Professional Documents
Culture Documents
Fast Data Exchange With Canoe: 2015-08-07 Application Note An-And-1-119
Fast Data Exchange With Canoe: 2015-08-07 Application Note An-And-1-119
Fast Data Exchange With Canoe: 2015-08-07 Application Note An-And-1-119
Version 1.0
2015-08-07
Application Note AN-AND-1-119
Table of Contents
1
Copyright © 2015 - Vector Informatik GmbH
Contact Information: www.vector.com or +49-711-80 670-0
Fast Data Exchange with CANoe
1.0 Overview
1.1 Introduction
This application note is a step by step guide for setting up an easy FDX client application in C# .NET that
interfaces to CANoe via FDX. CANoe FDX (Fast Data eXchange) is a UDP-based protocol for simple, fast and
real-time exchange of data between CANoe and other systems via an Ethernet connection. This protocol grants
other systems both read and write access to CANoe system and environment variables, and bus signals. The other
system may be, for example, a HIL system on a test bench or a PC used to display CANoe data. For the remainder
of this document, the other system is referred to as the HIL system.
Before further explanation of FDX, some background on CANoe is necessary. CANoe is well-known for its network
simulation capabilities. Not only does CANoe have the ability to simulate multiple nodes in a network, it can also
simulate multiple networks of different bus architectures such as CAN, LIN, MOST, FlexRay and Ethernet. Imagine
a vehicle with multiple data networks consisting of the following networks: CAN for powertrain, LIN for body
electronics and lighting, MOST for entertainment and GPS navigation, and FlexRay for chassis. CANoe can be
used to model all of the network data and functions for these bus systems, either individually or simultaneously.
When network data and functions need to be evaluated and validated at the design, implementation, or production
stage, CANoe can act as a test tool as well as a network simulation tool in order to test the network data and
functions. A simple, fast and reliable data exchange method is needed for transferring large quantities of data into
and out of CANoe or for communicating with an existing HIL system. The solution is CANoe FDX.
Note: The HIL system may run on the same PC as CANoe or on a different PC connected via Ethernet.
2
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
</canoefdxdescription>
Note: The size of groupID 2 is 8, when it should be 5. CANoe will display a warning in the write window indicating
this: “16-0205 FDX: data size (5 bytes) given in incoming DataExchange command for group id 2 is smaller than
specified group size (8 bytes).” You can safely ignore this warning for the time being.
Note: The EasyFDX,cfg CANoe configuration already has FDX enabled and the appropriate
FDXDescription_Easy.xml file associated. Therefore, it is used as the example CANoe configuration for this
application note.
4
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
4.1 Structure
All FDX commands are triggered using functions accessed via buttons on the C# client’s user interface. The
supported functionality includes connecting and disconnecting from CANoe, starting and stopping measurement,
and sending and receiving data. Note that the data is static, but the CAPL and C# code could be easily modified to
change the data being exchanged (both transmitted and received).
5
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
TextBox in the “Receive Data” group. The data specified in the “Send Data” group will be sent upon pressing the
corresponding “Send Data” button.
5.0 Implementation
This chapter focuses on the actual client implementation. There are three main parts: connecting the UDP Socket,
sending data, and receiving data. These parts will be discussed in detail.
5.1 UdpClient
The UdpClient class from the Microsoft .NET Framework is an easy way of sending and receiving UDP datagrams.
All methods are executed in blocking synchronous mode. To establish a UdpClient connection, an IP address and
port must be defined.
First, create a new instance of UdpClient:
Next, declare an enumerated type that contains the different FDX commands to be sent:
Then, establish the connection to CANoe using a “Button Click” event procedure (btConnect_Click). The IP
address and port number will be used as arguments for the UdpClient method “Connect”. This procedure
establishes a remote host connection to CANoe.
7
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
8
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
Command Code
Every FDX command begins with a Command Code followed by the size of the command. The Command Code
determines what type of command is being used (e.g., CANoe measurement start, exchange of signals/variable
data, etc.).
Every CANoe installation includes a document which has a detailed description of the various FDX commands. For
more information, please see “<CANoe Installation Directory>\Doc\CANoe_FDX_Protocol_EN.pdf”.
// Assemble Header
writer.Write(SIGNATURE);
writer.Write(MajorVersion);
writer.Write(MinorVersion);
writer.Write(NumberOfCommands);
writer.Write(SequenceNumber);
writer.Write(Reserved);
// Add Command
writer.Write((UInt16)4); // Size of Command = Size field + Command
writer.Write((UInt16)FdxCommandE.Start);
9
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
// Send Data
_Client.Send(ms.ToArray(), (int)ms.Length);
writer.Close();
ms.Close();
}
The first step is to assemble the FDX packet. To do so, create a MemoryStream object and a BinaryWriter object
(these objects ease data assembly). Then, the datagram header is assembled. Next, the size of the command is
calculated. Finally, the start measurement command (4 bytes) is used.
Note: The FDX command size includes the command field, all consecutive data bytes associated to the command
and the command size field itself. The header is not included in the size calculation.
Command Size = command size-field’s size + command field’s size + associated data field’s size
Command Size = 2 bytes + 2 bytes + x bytes
Once the FDX packet is assembled, the next step is to transmit it by using the UdpClient “Send” method. Keep in
mind that the Send method is a blocking call (the function will return after all of the data has been sent).
Sending a Stop command code looks exactly the same as sending the Start command, with the exception of the
FDX command itself:
// Assemble Header
writer.Write(SIGNATURE);
writer.Write(MajorVersion);
writer.Write(MinorVersion);
writer.Write(NumberOfCommands);
writer.Write(SequenceNumber);
writer.Write(Reserved);
// Add Command
writer.Write((UInt16)4); // Size of Command = Size field + Command
writer.Write((UInt16)FdxCommandE.Stop);
// Send Data
_Client.Send(ms.ToArray(), (int)ms.Length);
10
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
writer.Close();
ms.Close();
}
The first step is to assemble the UDP datagram header using the same data from the previous commands. Next,
add the command to the stream. The size is calculated as follows:
- 2 bytes for the command size field
- 2 bytes for the command code field (indicating the DataExchange command)
- 2 bytes for the group ID to be sent
- 2 bytes for the actual data
- X bytes (size of the dataSize field) for the actual data size (will use 5 bytes for the C# example code)
So, in the C# example, the size of the datagram header is 13 bytes (2 + 2 + 2 + 2 + 5).
Next, the data must be assembled prior to being sent. Therefore, a byte array is created and all the data is added
to it. The example assumes the data has the following values:
- EngineSpeedEntry = 0x03E8 = 1000
- EngineStateSwitch = 0x01 = 1
- FlashLight = 0x01 = 1
- HeadLight = 0x01 = 1
Finally, once the complete UDP datagram has been assembled it can be sent using the UdpClient “Send”
command.
// Assemble Header
writer.Write(SIGNATURE);
writer.Write(MajorVersion);
writer.Write(MinorVersion);
11
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
writer.Write(NumberOfCommands);
writer.Write(SequenceNumber);
writer.Write(Reserved);
// Add Command
writer.Write((UInt16)13); // Size of Command (8+dataSize)
writer.Write((UInt16)FdxCommandE.DataExchange);
writer.Write(gIDwrite); // specify Group ID = 2
writer.Write((UInt16)5); // write data size (Size of DataGroup 2)
// set data
// EngineSpeedEntry = 0x03e8 = 1000
// EngineStateSwitch = 1
// FlashLight = 1
// HeadLight = 1
byte[] data = { 0xe8, 0x03, 0x01, 0x01, 0x01 };
// Send Data
_Client.Send(ms.ToArray(), (int)ms.Length);
ms.Close();
writer.Close();
}
5.3 Reception
Compared to sending a datagram, receiving a datagram is slightly more complex. Therefore, two “helper” functions
are introduced to assist in receiving FDX messages. These helper functions are not mandatory for FDX
communication and other methods may be employed as necessary.
return ms;
}
The second helper function is an overloaded version of the first function. This function uses a parameter to specify
a reception timeout (in milliseconds). The UdpClient assigns the input parameter to the ReceiveTimeout property,
which specifies the timeout time to receive the datagram. If no data is received prior to the timeout expiration, a
SocketException will be thrown by the UdpClient and the return value is “null”.
12
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
To keep the next example simple, only the DataRequest command will be shown. This example uses the
btReqData_Click event procedure:
// Assemble Header
writer.Write(SIGNATURE);
writer.Write(MajorVersion);
writer.Write(MinorVersion);
writer.Write(NumberOfCommands);
writer.Write(SequenceNumber);
writer.Write(Reserved);
13
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
// Add Command
writer.Write((UInt16)6); // Size of Command
writer.Write((UInt16)FdxCommandE.DataRequest);
writer.Write(gIDread); // specify Group ID
// Send Data
_Client.Send(ms.ToArray(), (int)ms.Length);
// get data
BinaryReader reader = new BinaryReader(ms);
tbRcvData.Text = "";
case FdxCommandE.Status:
// read current state of the measurement.
MeasurementState = reader.ReadByte();
reader.ReadBytes(3); // discard 3 unused bytes
TimeStamp = reader.ReadInt64(); // read time stamp
// Display TimeStamp
TimeSpan t = TimeSpan.FromTicks(TimeStamp / 100);
label2.Text = t.ToString();
break;
case FdxCommandE.DataError:
throw new ApplicationException("DataError CMD received.");
default:
reader.ReadBytes(size - 4); // discard data for this command
break;
}
}
ms.Close();
writer.Close();
14
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
reader.Close();
}
Note that the code is nearly the same as sending the Start Command. The code varies starting with the
_Client.Send(…) call.
Now, the newly introduced ReceiveDatagram() helper function is used. Take note that a 500ms timeout is used
due to the UdpClient’s receive functionality’s blocking nature. ReceiveDatagram() will return the data as a
MemoryStream, which is the input for a BinaryReader.
The BinaryReader eases parsing of the datagram. For this example, only the number of commands in the
datagram header is of interest. All other data fields will be discarded.
Following the datagram header, the data stream contains the different commands sent by CANoe. The expected
responses for DataRequest command are (1) a Status command and (2) a DataExchange command containing
the requested data. If CANoe encounters an error, a DataError command will be sent.
Since the number of commands is known, a “for” loop is used to handle the DataExchange, Status and DataError
commands. The DataExchange and Status commands will be decoded while the DataError Command will throw
an ApplicationException. The DataExchange command contains the requested data and the Status command
contains the current measurement state and a timestamp from CANoe.
Note: Please refer to the CANoe Help, if you have problems setting up these Modes.
CANoe | Extensions | VN8900 | Interactive Mode over USB | Interactive Mode over IP | Standalone Mode
15
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
8.0 Contacts
For a full list with all Vector locations and addresses worldwide, please visit http://vector.com/contact/.
16
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
9.0 Appendix
This Appendix contains the source files necessary to recreate the sample program discussed throughout this
document. Form1.cs implements all of the FDX functionality and Form1.Designer.cs creates the WindowsForm
(GUI).
9.1 Form1.cs
using System;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
using System.Text;
using System.Collections.Generic;
namespace EasyClientNet
{
public partial class Form1 : Form
{
// UDP Client for the communication
private UdpClient _Client;
public Form1()
{
InitializeComponent();
}
return ms;
}
18
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
// Assemble Header
writer.Write(SIGNATURE);
writer.Write(MajorVersion);
writer.Write(MinorVersion);
writer.Write(NumberOfCommands);
writer.Write(SequenceNumber);
writer.Write(Reserved);
// Add Command
writer.Write((UInt16)4); // Size of Command = Size field + Command
writer.Write((UInt16)FdxCommandE.Start);
// Send Data
_Client.Send(ms.ToArray(), (int)ms.Length);
writer.Close();
ms.Close();
}
// Assemble Header
writer.Write(SIGNATURE);
writer.Write(MajorVersion);
writer.Write(MinorVersion);
writer.Write(NumberOfCommands);
writer.Write(SequenceNumber);
writer.Write(Reserved);
// Add Command
writer.Write((UInt16)4); // Size of Command = Size field + Command
writer.Write((UInt16)FdxCommandE.Stop);
// Send Data
_Client.Send(ms.ToArray(), (int)ms.Length);
writer.Close();
ms.Close();
}
// Assemble Header
writer.Write(SIGNATURE);
writer.Write(MajorVersion);
writer.Write(MinorVersion);
writer.Write(NumberOfCommands);
writer.Write(SequenceNumber);
19
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
writer.Write(Reserved);
// Add Command
writer.Write((UInt16)6); // Size of Command
writer.Write((UInt16)FdxCommandE.DataRequest);
writer.Write(gIDread); // specify Group ID
// Send Data
_Client.Send(ms.ToArray(), (int)ms.Length);
// get data
BinaryReader reader = new BinaryReader(ms);
tbRcvData.Text = "";
case FdxCommandE.Status:
// read current state of the measurement.
MeasurementState = reader.ReadByte();
reader.ReadBytes(3); // discard 3 unused bytes
TimeStamp = reader.ReadInt64(); // read time stamp
// Display TimeStamp
TimeSpan t = TimeSpan.FromTicks(TimeStamp / 100);
label2.Text = t.ToString();
break;
case FdxCommandE.DataError:
throw new ApplicationException("DataError CMD received.");
default:
reader.ReadBytes(size - 4); // discard data for this command
break;
}
}
20
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
ms.Close();
writer.Close();
reader.Close();
}
// Assemble Header
writer.Write(SIGNATURE);
writer.Write(MajorVersion);
writer.Write(MinorVersion);
writer.Write(NumberOfCommands);
writer.Write(SequenceNumber);
writer.Write(Reserved);
// Add Command
writer.Write((UInt16)13); // Size of Command (8+dataSize)
writer.Write((UInt16)FdxCommandE.DataExchange);
writer.Write(gIDwrite); // specify Group ID = 2
writer.Write((UInt16)5); // write data size (Size of DataGroup 2)
// set data
// EngineSpeedEntry = 0x03e8 = 1000
// EngineStateSwitch = 1
// FlashLight = 1
// HeadLight = 1
byte[] data = { 0xe8, 0x03, 0x01, 0x01, 0x01 };
// Send Data
_Client.Send(ms.ToArray(), (int)ms.Length);
ms.Close();
writer.Close();
}
}
}
21
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
9.2 Form1.Designer.cs
namespace EasyClientNet
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise,
false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.btDisconnect = new System.Windows.Forms.Button();
this.btConnect = new System.Windows.Forms.Button();
this.btStartMeasure = new System.Windows.Forms.Button();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.tbRcvData = new System.Windows.Forms.TextBox();
this.btReqData = new System.Windows.Forms.Button();
this.groupBox4 = new System.Windows.Forms.GroupBox();
this.label1 = new System.Windows.Forms.Label();
this.btSendData = new System.Windows.Forms.Button();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.btStopMeasure = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.groupBox1.SuspendLayout();
this.groupBox3.SuspendLayout();
this.groupBox4.SuspendLayout();
this.groupBox2.SuspendLayout();
this.SuspendLayout();
//
// groupBox1
//
this.groupBox1.Controls.Add(this.btDisconnect);
this.groupBox1.Controls.Add(this.btConnect);
this.groupBox1.Location = new System.Drawing.Point(13, 13);
this.groupBox1.Name = "groupBox1";
22
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
23
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
24
Application Note AN-AND-1-119
Fast Data Exchange with CANoe
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(99, 25);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(0, 13);
this.label2.TabIndex = 2;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(253, 374);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox4);
this.Controls.Add(this.groupBox3);
this.Controls.Add(this.groupBox1);
this.Name = "Form1";
this.Text = "easyClient.Net";
this.groupBox1.ResumeLayout(false);
this.groupBox3.ResumeLayout(false);
this.groupBox3.PerformLayout();
this.groupBox4.ResumeLayout(false);
this.groupBox4.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.ResumeLayout(false);
#endregion
25
Application Note AN-AND-1-119