//////////////////////////////////////////////////////////////////////////////////
// //
// This is a SocketCAN demo converted from C to Pascal by Zeljko Avramovic. //
// Original code has GNU General Public License v3.0 and can be found at //
// https://github.com/craigpeacock/CAN-Examples //
// //
// Virtual CAN adapter vcan0 is hard coded and you can bring it up like this: //
// sudo modprobe vcan //
// sudo ip link add dev vcan0 type vcan //
// sudo ip link set vcan0 mtu 72 # needed for CAN FD //
// sudo ip link set vcan0 up //
// //
//////////////////////////////////////////////////////////////////////////////////
program canfdtransmit;
{$mode delphi} {$H+}
uses
cthreads, classes, sysutils, sockets, baseunix, can, can.raw;
procedure perror(const S : string);
begin
WriteLn(S, ', SocketError = ', SocketError);
end;
var
s, err: cint;
addr: sockaddr_can;
ifr: ifreq;
frame: canfd_frame;
begin
try
Writeln('CAN FD Sockets Transmit Demo');
s := fpsocket(PF_CAN, SOCK_RAW, CAN_RAW);
if s < 0 then
begin
if s = ESysENOPROTOOPT then
Writeln('CAN_RAW_FD_FRAMES socket option is not supported. Your kernel is probably too old.');
perror('Socket');
Exit;
end;
strcopy(ifr.ifr_name, 'vcan0');
if fpioctl(s, SIOCGIFINDEX, @ifr) < 0 then
begin
perror('IOctl');
Exit;
end;
memset(@addr, 0, sizeof(addr));
addr.can_family := AF_CAN;
addr.can_ifindex := ifr.ifr_ifindex;
if fpbind(s, @addr, sizeof(addr)) < 0 then
begin
perror('Bind');
Exit;
end;
frame.can_id := $444; // CAN FD message ID
frame.len := 20; // payload length will be 20 bytes
frame.data := [$01, $02, $03, $04, $05, $06, $07, $08, $09, $0A, $0B, $0C, $0D, $0E, $0F, $10,
$11, $12, $13, $14, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00];
// shows as '0x444 [40] 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14' in canfdreceive
{
frame.data[0] := $01; // alternative for the above
frame.data[1] := $02; // shows as '0x444 [40] 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14' in canfdreceive
frame.data[2] := $03;
frame.data[3] := $04;
frame.data[4] := $05;
frame.data[5] := $06;
frame.data[6] := $07;
frame.data[7] := $08;
frame.data[8] := $09;
frame.data[9] := $0A;
frame.data[10] := $0B;
frame.data[11] := $0C;
frame.data[12] := $0D;
frame.data[13] := $0E;
frame.data[14] := $0F;
frame.data[15] := $10;
frame.data[16] := $11;
frame.data[17] := $12;
frame.data[18] := $13;
frame.data[19] := $14;
}
err := fpsetsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, @ENABLE_CAN_OPTION, sizeof(ENABLE_CAN_OPTION));
if err <> 0 then
begin
if err = ESysENOPROTOOPT then
WriteLn('CAN FD Protocol not available. Try newer kernel');
perror('SetSockopt');
Exit;
end;
if fpwrite(s, frame, sizeof(canfd_frame)) <> sizeof(canfd_frame) then
begin
perror('Write');
Exit;
end;
if fpclose(s) < 0 then
begin
perror('Close');
Exit;
end;
except
on e:Exception do
WriteLn(e.Message);
end;
end.