procedure TFormCanFDtest.RunCanFDExamplePlease;
var
I : integer; // INT32
N : integer; // INT32
R : integer; // INT32
TX : integer; // INT32
RX : integer; // INT32
numCh : integer; // INT32
MyChNames : array of string; //
TX_MyHnd : canHandle; // canHandle = integer = INT32
RX_MyHnd : canHandle; // canHandle = integer = INT32
BUF : TByteBUF0064; // Array 64 bytes of 8bit char
MyStringBuf: TByteBUF1024; // Array 1024 bytes of 8bit char
id : Longint; // Warning LONGINT is 32b or 64b depending of
// target platform. check if using iOS or LINUX!
dlc : Cardinal; // UINT32
Flag : Cardinal; // UINT32
HelpFlag : THelpFlag absolute Flag; // UINT32, HelpFlag share adress with Flag
myTime : Cardinal; // UINT32
begin
I := sizeof(id);
dummy(I);
begin
case MyApp of
canCL:
begin
Memo.Lines.Add('Hello! Starting TestCanLIB_STD. Using CLASSIC CAN')
end;
canFD:
begin
Memo.Lines.Add('Hello! Starting TestCanLIB_STD. Using FD CAN');
end;
end;
/// *********************************************************
/// Section one, INITIALIZATION
/// *********************************************************
// Open CanLib.DLL
canInitializeLibrary;
// No errorchecking here, will be done later when opening channel...
// Find out how many channels(interfaces) we can use
R := canGetNumberOfChannels(numCh);
if MyErrorCheck(Memo, R, 'canGetNumberOfChannels') then
begin
exit;
end;
Memo.Lines.Add('Found ' + numCh.ToString + ' channels');
setlength(MyChNames, numCh);
for I := Low(MyChNames) to High(MyChNames) do
begin
canGetChannelData(I, canCHANNELDATA_DEVDESCR_ASCII, MyStringBuf, sizeof(MyStringBuf));
canGetChannelData(I, canCHANNELDATA_CHAN_NO_ON_CARD, N, sizeof(N));
MyChNames[I] := (I+1).ToString+' '+string(MyStringBuf)+' ' + (N+1).ToString;
Memo.Lines.Add('Found channel: ' + MyChNames[I]);
end;
// Check that the selected channels exist
if MyErrorCheck(Memo, TX_MySelCh, RX_MySelCh, 1, numCh, 'numCh') then
begin
exit;
end;
Memo.Lines.Add('Selected TX:' + MyChNames[TX_MySelCh - 1]);
Memo.Lines.Add('Selected RX:' + MyChNames[RX_MySelCh - 1]);
// Next step is to open the Channels
// Please check the FLAGs!
// CAN FD needs different settings!
case MyApp of
canCL: // Classic CAN communication
begin
TX_MyHnd := canOpenChannel(TX_MySelCh - 1, canOPEN_ACCEPT_VIRTUAL);
RX_MyHnd := canOpenChannel(RX_MySelCh - 1, canOPEN_ACCEPT_VIRTUAL);
if MyErrorCheck(Memo, TX_MyHnd, RX_MyHnd, 'canOpenChannel') then
begin
exit;
end;
end;
canFD: // CAN FD communication
begin
TX_MyHnd:=canOpenChannel(TX_MySelCh-1, canOPEN_ACCEPT_VIRTUAL OR canOPEN_CAN_FD);
RX_MyHnd:=canOpenChannel(RX_MySelCh-1, canOPEN_ACCEPT_VIRTUAL OR canOPEN_CAN_FD);
if MyErrorCheck(Memo, TX_MyHnd, RX_MyHnd, 'canOpenChannel FD') then
begin
exit
end;
end;
end;
/// *****************************************************************************
///
/// Now is a good time to enable messages, but we do not need it in this example
/// canSetNotify(MyHnd, Self.Handle, $FFFFFFFF);
///
/// *****************************************************************************
case MyApp of
canCL: // Classic CAN communication
begin
TX := canSetBusParams(TX_MyHnd, canBITRATE_500K, 0, 0, 0, 0, 0);
RX := canSetBusParams(RX_MyHnd, canBITRATE_500K, 0, 0, 0, 0, 0);
if MyErrorCheck(Memo, TX, RX, 'canSetBusParams') then
begin
exit
end;
end;
canFD: // CAN FD communication
begin
TX := canSetBusParams(TX_MyHnd, canFD_BITRATE_500K_80P, 0, 0, 0, 0, 0);
RX := canSetBusParams(RX_MyHnd, canFD_BITRATE_500K_80P, 0, 0, 0, 0, 0);
if MyErrorCheck(Memo, TX, RX, 'canSetBusParams') then
begin
exit
end;
TX := canSetBusParamsFD(TX_MyHnd, canFD_BITRATE_1M_80P, 0, 0, 0);
RX := canSetBusParamsFD(RX_MyHnd, canFD_BITRATE_1M_80P, 0, 0, 0);
if MyErrorCheck(Memo, TX, RX, 'canSetBusParamsFD') then
begin
exit
end;
end;
end;
// Turn BUS on
TX := canBusOn(TX_MyHnd);
RX := canBusOn(RX_MyHnd);
if MyErrorCheck(Memo, TX, RX, 'canBusOn') then
begin
exit
end;
// Remove all pending transmissions, might not be needed
TX := canFlushTransmitQueue(TX_MyHnd);
RX := canFlushTransmitQueue(RX_MyHnd);
if MyErrorCheck(Memo, TX, RX, 'canFlushTransmitQueue') then
begin
exit
end;
sleep(250); // Take a short nap...
// Remove all pending transmissions, do we really wanna do this in a sharp application?
// Might remove wanted frames.
TX := canFlushReceiveQueue(TX_MyHnd);
RX := canFlushReceiveQueue(RX_MyHnd);
if MyErrorCheck(Memo, TX, RX, 'canFlushReceiveQueue') then
begin
exit
end;
// CAN is open for traffic
Memo.Lines.Add('CAN open, waiting');
/// *********************************************************
/// Section two, Sending
/// *********************************************************
// Create one frame and transmit
// Transmitting from TX_MySelCh
case MyApp of
canCL: // Classic CAN communication
begin
BUF := 'Hello!';
id := 111;
dlc := 8;
/// For Classic CAN dlc can be at most 8, unless canOPEN_ACCEPT_LARGE_DLC is used.
/// CanWrite can only transfer max 8 bytes, regardless of dlc
/// In this example BUF is 64 bytes wide, but only 8 bytes can be sent.
Flag := canMSG_STD;
R := canWrite(TX_MyHnd, id, @BUF, dlc, Flag);
if MyErrorCheck(Memo, R, 'canWrite') then
begin
exit
end;
Memo.Lines.Add('TX ID:'+id.ToString+' dlc:'+dlc.ToString+' B :'+MyConvert(BUF, dlc));
end;
canFD: // CAN FD communication
begin
BUF := 'Hello World!';
id := 222;
dlc := 16;
// for CAN FD dlc CAN be one of the following 0-8, 12, 16, 20, 24, 32, 48, 64
Flag := canMSG_STD OR canFDMSG_FDF OR canFDMSG_BRS;
R := canWrite(TX_MyHnd, id, @BUF, dlc, Flag);
if MyErrorCheck(Memo, R, 'canWrite (FD)') then
begin
exit
end;
Memo.Lines.Add('TX ID:' + id.ToString + ' dlc:' + dlc.ToString + ' bytes :' +
MyConvert(BUF, dlc));
end;
end;
/// *********************************************************
/// Section three, Recieving
/// *********************************************************
// Now if we are lucky, some bytes have arrived to RX
BUF := '';
I := 0;
repeat
inc(I);
sleep(100);
// Always use 64 byte wide buffer to avoid errors!!!
dlc := 4;
Flag := 0;
R := canRead(RX_MyHnd, id, @BUF, dlc, Flag, myTime);
/// WARNING, make sure that BUF is mminimum 64 bytes wide!
Memo.Lines.Add('Read attemp no ' + I.ToString + ' Result :' + R.ToString);
until (I >= 5) OR (R = canOK);
case R of
canOK:
begin
dummy(id, BUF, dlc, Flag, HelpFlag.canMSG_Flag, myTime);
// Examine the Flag(HelpFlag) and do someting...
if MycanMSG_RTR in HelpFlag.canMSG_Flag then
Memo.Lines.Add('RX Flag: <MycanMSG_RTR>');
if MycanMSG_STD in HelpFlag.canMSG_Flag then
Memo.Lines.Add('RX Flag: <MycanMSG_STD>');
if MycanMSG_EXT in HelpFlag.canMSG_Flag then
Memo.Lines.Add('RX Flag: <MycanMSG_EXT>');
if MycanMSG_ERROR_FRAME in HelpFlag.canMSG_Flag then
Memo.Lines.Add('RX Flag: <MycanMSG_ERROR_FRAME>');
if MycanFDMSG_FDF in HelpFlag.canMSG_Flag then
Memo.Lines.Add('RX Flag: <MycanFDMSG_FDF>');
if MycanFDMSG_BRS in HelpFlag.canMSG_Flag then
Memo.Lines.Add('RX Flag: <MycanFDMSG_BRS>');
Memo.Lines.Add('RX ID:' + id.ToString + ' dlc:' + dlc.ToString + ' bytes :' +
MyConvert(BUF, dlc));
end;
canERR_NOMSG:
begin
Memo.Lines.Add('Ooops, no data????');
end;
else
begin
Memo.Lines.Add('Some error happened, check! ' + R.ToString);
end;
end;
/// *********************************************************
/// Section three, Finalizing
/// *********************************************************
// We are done
Memo.Lines.Add('DONE, start the cleanup process');
TX := canBusOff(TX_MyHnd);
RX := canBusOff(RX_MyHnd);
if MyErrorCheck(Memo, TX, RX, 'canBusOff') then
begin
exit
end;
TX := canClose(TX_MyHnd);
RX := canClose(RX_MyHnd);
if MyErrorCheck(Memo, TX, RX, 'canClose') then
begin
exit
end;
Memo.Lines.Add('If you can read this, everything worked!');
end;
end;