Lazarus

Programming => Networking and Web Programming => Topic started by: rampinia on January 28, 2018, 10:20:35 am

Title: CAN-BUS SocketCAN
Post by: rampinia on January 28, 2018, 10:20:35 am
Hello to all

does anyone did programming socket in the class PF_CAN for accessing CAN-BUS in Linux?
On the wiki side I have seen there are not current constant declaration for such network protocoll.

If the pfsocket and others call are just wrapper for standard BSD socket call I think it is enaugh to declare the constant just porting from the standard linux header.

Any info?

Thanks
Title: Re: CAN-BUS SockectCAN
Post by: marcov on January 28, 2018, 10:43:14 am
Yes, the sockets unit are just wrappers. Best is if somebody finds the constants, tests it, and then submits a patch.
Title: Re: CAN-BUS SockectCAN
Post by: rampinia on January 28, 2018, 06:30:27 pm
Yes

got PF_CAN = 29 and CAN_RAW = 1 from sys/if.h

already run some tests with PF_CAN = 29 and CAN_RAW = 1 and it works.

I'm working a minimal porting from C header.
Title: Re: CAN-BUS SockectCAN
Post by: RM on March 11, 2019, 08:50:21 am
Hello at all, i am new here...

I try to establish a CAN connection on the raspberry pi (stretch), using free pascal.
I successfully created a raw socket with PF_CAN=29 and CAN_RAW=1.
And now i have to bind the socket to the hardware address, but i don't know how?

Code: Pascal  [Select][+][-]
  1. class procedure TSysBus.OpenSocket;
  2. var
  3.   s:Tsocket;
  4.   sa:TSockAddr;
  5. begin
  6.      s:=fpsocket(29, SOCK_RAW, 1);
  7.      sa.sa_family:=29;
  8.      sa.sa_data[0]:=???;
  9.      fpbind(s,@sa,SizeOf(sa));
  10.      FpClose(s);
  11. end;
  12.  

Can somebody give me an example, how i have to go on?
Thanks
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on August 21, 2020, 05:00:22 am
Anyone been able to create the equivalent of a simple the socketCAN utilities  candump using Lazarus
Code: Text  [Select][+][-]
  1. debian@ebb:~$ sudo /sbin/ip link set can1 up type can bitrate 250000
  2. debian@ebb:~$ candump can1
  3.   can1  721   [1]  05
  4.   can1  1A1   [8]  20 00 FF 0F A8 FD A8 FD
  5.  

No one answered RM and rampinia didn't post any other solutions.

Code: Pascal  [Select][+][-]
  1. procedure TSocketForm.Button1Click(Sender: TObject);
  2. var
  3.     i : integer;
  4. begin
  5.   // open socket
  6.   socket_result := fpsocket(PF_CAN, SOCK_RAW, CAN_RAW);
  7.   if (socket_result < 0) then begin
  8.         // perror("socket");
  9.     Edit1.text := 'Error #' + IntToStr(socket_result) + ' creating socket';
  10.   end
  11.   else begin
  12.     SAddr.sin_family := PF_CAN;
  13.     if fpconnect(socket_result, @SAddr, 0) = -1 then begin
  14.       Edit1.text := 'Socket can''t connect: ' + strerror(socketerror);
  15.     end;
  16.   end;
  17. end;
  18.  

The error is 'Operation not supported on Endpoint'

The C language candump doesn't use fpconnect() and the 'connect()' is deprecated and doesn't work either.  So although this is the document for fpconnect it uses deprecated functions rather than fpconnect().

https://www.freepascal.org/docs-html/current/rtl/sockets/fpconnect.html (https://www.freepascal.org/docs-html/current/rtl/sockets/fpconnect.html)

Plus it's more targeted at internet protocol sockets.

Ideas?

Title: Re: CAN-BUS SockectCAN
Post by: trev on August 21, 2020, 05:17:22 am
What about this (http://www.cananalyser.co.uk/index.html). The Windows/Linux SDK for Delphi is free.
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on August 23, 2020, 09:55:24 am
What about this (http://www.cananalyser.co.uk/index.html). The Windows/Linux SDK for Delphi is free.
Unfortunately from what I can see it doesn't address socketcan.

What I've found out so far is that socketcan and the utilities like candump work with the USB based CANUSB from Lawicel along with the internal BeagleBone Black CAN device and on a Pi, an SPI based MCP2515.

Further research shows that as simple as including 'can' in python programs brings in support for either the BBB or Pi. 

This is what I want to see for Lazarus.  I'd like to be able to plug in any device that has socketCAN support and have the application compile on that platform, or cross compile for that platform and just plain work.

What I've discovered is that this doesn't work for Lazarus yet.   So I need to find out where the sockets source code lives for the Pi and the Beagle and figure out why the fpconnect() returns an error.  Clearly it's broken or not properly documented.
Title: Re: CAN-BUS SockectCAN
Post by: Laksen on August 23, 2020, 11:10:19 am
Why are you calling connect and not bind?
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on October 22, 2020, 06:10:48 am
I think I have some time to dive back into this project. 
Why are you calling connect and not bind?
Even if I call bind (or fpbind) the issue is that the sockets code seems to be oriented towards ip and port numbers. 
Referencing this document
http://www.linuxhowtos.org/C_C++/socket.htm
I believe the socketCAN has to address the unix domain via the Linux File system. 
Recall my example from a previous post.
Code: Pascal  [Select][+][-]
  1.    
  2.     debian@ebb:~$ sudo /sbin/ip link set can1 up type can bitrate 250000
  3.     debian@ebb:~$ candump can1
  4.       can1  721   [1]  05
  5.       can1  1A1   [8]  20 00 FF 0F A8 FD A8 FD
  6.  
The can1 is the device which in the above example is a USB based CAN dongle.  On a Pi I can just as easily specify the SPI based MCP2515 CAN device in place of the USB device. 

For example from this tutorial
https://www.raspberrypi.org/forums/viewtopic.php?t=141052
Code: Pascal  [Select][+][-]
  1. pi@piv2:~ $ ls /sys/bus/spi/devices/spi0.0/net/
  2. can0
  3.  
  4. pi@piv2:~ $ sudo ip link set can0 up type can bitrate 125000
  5.  
  6. pi@piv2:~ $ sudo ifconfig
  7. can0   Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
  8.           UP RUNNING NOARP  MTU:16  Metric:1
  9.           RX packets:0 errors:0 dropped:0 overruns:0 frame:0
  10.           TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
  11.           collisions:0 txqueuelen:10
  12.           RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
  13.  

So from the OS perspective the fact that one device is USB based and can be plugged into a WIN-PC MAC or Linux system while the other one is SPI based on the Pi the access via Linux is the same.

And the C Program candump.c creates identical output regardless of the hardware type.  (BTW, it's the same with the embedded inside the processor CAN device in a BeagleBone Black).

Code: Pascal  [Select][+][-]
  1. pi@piv2:~ $ candump can0
  2.   can0  001   [8]  11 22 33 44 55 66 77 88
  3.   can0  00003456   [8]  EF FE DD AD CB 67 98 AA
  4.  

Now in the C world, candump.c or cansend.c can be used as a template for a customized program to do whatever...  One might cut and paste parts into their application.    That's because the sockets library in C handles the parameters PF_CAN and SOCK_RAW, CAN_RAW.

The FPC sockets does not.  And yes I can define those but tunnel down into sockets.pp and and the system's ...sockh.inc we don't have a PF_CAN.  And without a PF_CAN and AF_CAN in the socket()  the connection aborts because it doesn't know what to do with it.

In order to cut and paste more of the code I'll have to continue this in another message from the Pi3 so I can post the Lazarus program I've used to discover this but I don't think the FPC code will matter at this point.

Search for candump.c and we find in
https://github.com/linux-can/can-utils/blob/master/candump.c

Code: Text  [Select][+][-]
  1. s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW);

Later we bind to the socket
Code: C  [Select][+][-]
  1. if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  2.                         perror("bind");
  3.                         return 1;
  4.                 }
  5.  

Eventually after all the CAN_FD and filter handling we end up
Code: C  [Select][+][-]
  1. nbytes = recvmsg(s[i], &msg, 0);

So in general I get the feeling that to add socketCAN support to FPC will require a fairly extensive modification of the base sockets library.  Is there any interest in this?  Who's allowed to change it. 

The project I started in Lazarus works fine with the USB based CAN dongle by treating it as a serial port which generates strings of characters representing the messages.  But I can't access the CAN devices built into the BeagleBone nor the Pi which is a cakewalk with Python or C.  And I'd like to be able to demonstrate CAN bus access from a USB dongle or the embedded hardware. 

What's the next step?
Title: Re: CAN-BUS SockectCAN
Post by: avra on October 22, 2020, 09:41:43 am
So in general I get the feeling that to add socketCAN support to FPC will require a fairly extensive modification of the base sockets library.
PF_CAN is just a number. In linux sources you can find it defined as AF_CAN, which is defined as 29. So why don't you try that first?

You could also take a look at https://github.com/linux-can/socketcand if you wish to access CAN via CAN-ETH gateway daemon. You can install https://github.com/dschanoeh/Kayak as a handy GUI application that can access SocketCAN (and serial slcan through it) using socketcand.

Instead of using real slcan device as you do, maybe it would be easier if you use vcan instead and simulate CAN traffic for testing purposes. Once you get everything working you can then switch to a real device. If you wish I can give you several simple scripts to bring up VCAN environment, generate CAN traffic, and use SocketCAN directly or through socketcand and Kayak.

EDIT: I see now that you are looking at sources of candump. It will be much easier if you use simpler example from here:
https://www.beyondlogic.org/example-c-socketcan-code/
Title: Re: CAN-BUS SockectCAN
Post by: MarkMLl on October 22, 2020, 09:44:51 am
I believe the socketCAN has to address the unix domain via the Linux File system. 

Presumably you mean unix domain *socket* here. If so I agree that it's normally accessed via the filesystem, but otherwise the API is fairly similar to an inet datagram socket.


Code: [Select]
      if fpSelect(maxHandle + 1, @readSet, nil, nil, nil) >= 0 then begin

(* A message received on the inet domain socket must have a recognisable sender *)
(* since it might be needed for authentication purposes. A unix domain socket   *)
(* can be assumed to be protected by local permissions and capabilities.        *)

        if (UnixDomainSocket() >= 0) and (fpFD_ISSET(UnixDomainSocket(), readSet) = 1) then
          dispatchMessage(UnixDomainSocket(), false);
        if (InetDomainSocket() >= 0) and (fpFD_ISSET(InetDomainSocket(), readSet) = 1) then
          dispatchMessage(InetDomainSocket(), true)
      end

...

begin // dispatchMessage(), invoked as above, 2nd param is hasFrom
  FillByte(recvBuffer, SizeOf(recvBuffer), 0);
  if hasFrom then begin                 (* Inet domain socket                   *)
    FillByte(sa, SizeOf(sa), 0);
    saLength := SizeOf(sa);
    messageLength := fpRecvFrom(socket, @recvBuffer, SizeOf(recvBuffer), 0, @sa, @saLength)
  end else begin                        (* Unix domain socket                   *)
    saLength := -1;
    messageLength := fpRecv(socket, @recvBuffer, SizeOf(recvBuffer), 0)
  end;

(* There is no provision here for concatenated or fragmented messages, which we *)
(* of course shouldn't see since it's a datagram socket. Elsewhere, we try to   *)
(* work out the MTU by looking at padded backbone messages.                     *)

...

(* The result of this may be subsequently retrieved using UnixDomainSocket().
  If a .pid file indicates that an existing socket was created by an instance
  of this program that no longer exists then delete it. Create a fresh Unix
  Domain socket and save the handle, on failure save an error code. Both success
  and failure are silent.
*)
procedure CreateUnixDomainSocket(socketName: string);

var
  oldPid: longInt= -1;
  pidName: string;
  pidFile: text;
  uid: TUid;
  gid: TGid;

begin
  if socketName[1] = '~' then begin
    Delete(socketName, 1, 1);
    socketName := UserHome() + socketName
  end;
  pidName := socketName + '.pid';
  if FileExists(pidName) then
    try
      Write(StdErr, 'Opening old PID file... ');
      Assign(pidFile, pidName);
      Reset(pidFile);
      try
        Read(pidFile, oldPid);
        WriteLn(StdErr, 'OK, ' + IntToStr(oldPid))
      finally
        Close(pidFile)
      end
    except
      WriteLn(StdErr, 'failed');
      oldPid := -1
    end;

(* If we have managed to read a process ID file then check whether the relevant *)
(* process (an older instance of this program) still exists. If it does then we *)
(* shouldn't be trying to run this program, if it does not and a unix domain    *)
(* socket exists then try to delete it.                                         *)

  if (oldPid >= 0) and FileExists('/proc/' + IntToStr(oldPid)) then begin
    WriteLn(StdErr, 'WatchP0x already running, terminating.');
    Halt(9)
  end;
  if oldPid >= 0 then begin
    WriteLn(StdErr, 'Process ', oldPid, ' is not running');
    try
      if FileExists(socketName) then begin
        Write(StdErr, 'Deleting old unix domain socket ', socketName, '... ');
        DeleteFile(socketName);
        if not FileExists(socketName) then
          WriteLn(StdErr, 'OK')
        else
          WriteLn(StdErr, 'ineffective (critical error)')
      end else
        WriteLn(StdErr, 'No old socket')
    except
      WriteLn(StdErr, 'failed');
      unixDomainSocketHandle := -Abs(ErrNo) (* Probably ESysEACCESS             *)
    end
  end;

(* Delete old PID file since it might be owned by a different user.             *)

  if FileExists(pidName) then begin
    Write(StdErr, 'Deleting old PID file... ');
    try
        DeleteFile(pidName);
        if not FileExists(pidName) then
          WriteLn(StdErr, 'OK')
        else
          WriteLn(StdErr, 'ineffective (critical error)')
    except
      WriteLn(StdErr, 'failed');
      unixDomainSocketHandle := -Abs(ErrNo) (* Probably ESysEACCESS             *)
    end
  end;

(* Create a new PID file.                                                       *)

  try
    Write(StdErr, 'Creating new PID file... ');
    Assign(pidFile, pidName);
    Rewrite(pidFile);
    try
      WriteLn(pidFile, IntToStr(GetProcessID()));
      WriteLn(StdErr, 'OK, ', GetProcessID())
    finally
      Close(pidFile)
    end
  except
    WriteLn(StdErr, 'failed (critical error)');
    unixDomainSocketHandle := -Abs(ErrNo) (* Probably ESysEACCESS               *)
  end;

(* Create the socket. Note that there is no suitable fpBind() for this.         *)

  Write(StdErr, 'Creating new unix domain socket... ');
  unixDomainSocketHandle := fpSocket(AF_UNIX, SOCK_DGRAM, 0);
  if Bind(unixDomainSocketHandle, socketName) then
    WriteLn(StdErr, 'OK')
  else begin
    WriteLn(StdErr, 'failed (continuing)');
    unixDomainSocketHandle := -Abs(ErrNo) (* Probably ESysEACCESS               *)
  end;

(* Change socket owner and group to be the same as the executable, on the       *)
(* assumption that this is the user that will be executing all programs.        *)

// TODO : Bad assumption if setuid.

  Write(StdErr, 'Changing socket''s ownership... ');
  getOwner(ParamStr(0), uid, gid);
  if fpChown(socketName, uid, gid) = 0 then
    WriteLn(StdErr, 'OK')
  else begin
    WriteLn(StdErr, 'failed (continuing)');
//    unixDomainSocketHandle := -Abs(ErrNo) (* Probably ESysEACCESS             *)
  end;

(* Set the socket to be writable by its owner (i.e. any cooperating program)    *)
(* and readable by its group (this program). I don't think very much of doing   *)
(* this but the computer on which this is running can be assumed to be          *)
(* physically secure leaving the major risk being that somebody unauthorised    *)
(* logs into it and runs one of this suite of programs.                         *)

  Write(StdErr, 'Relaxing socket''s read/write permissions... ');
  if fpChMod(socketName, &766) = 0 then
    WriteLn(StdErr, 'OK')
  else begin
    WriteLn(StdErr, 'failed (continuing), might need CAP_DAC_OVERRIDE,CAP_NET_BIND_SERVICE,CAP_NET_RAW=p+e');
    unixDomainSocketHandle := -Abs(ErrNo) (* Probably ESysEACCESS               *)
  end

(* Since we're about to reliquish admin capabilities we won't be able to delete *)
(* the socket at program termination.                                           *)

end { CreateUnixDomainSocket } ;


(* The result of this may be subsequently retrieved using InetDomainSocket().
  Assume that any existing socket was deleted when its owner terminated. Create
  a fresh Inet Domain socket and save the handle, on failure save an error code.
  Both success and failure are silent.
*)
procedure CreateInetDomainSocket(port: integer);

var
  sockAddr: TSockAddr;

begin
  Write(StdErr, 'Creating new Internet domain socket (UDP, port ', port, ')... ');
  inetDomainSocketHandle := fpSocket(PF_INET, SOCK_DGRAM, 0);
  try
    sockAddr.sin_family:= AF_INET;
    sockAddr.sin_port:= hToNS(port);
    sockAddr.sin_addr.s_addr:= 0;
    FillChar(sockAddr.sin_zero[0], SIZEOF(sockAddr.sin_zero), #0);
    if fpBind(inetDomainSocketHandle, @sockAddr, SIZEOF(sockAddr)) = 0 then
      WriteLn(StdErr, 'OK')
    else begin
      WriteLn(StdErr, 'failed, might need CAP_DAC_OVERRIDE,CAP_NET_BIND_SERVICE,CAP_NET_RAW=p+e');
      inetDomainSocketHandle := -Abs(ErrNo)
    end
  except
    WriteLn(StdErr, 'failed, might need CAP_DAC_OVERRIDE,CAP_NET_BIND_SERVICE,CAP_NET_RAW=p+e');
    inetDomainSocketHandle := -Abs(ErrNo)
  end

(* Assume that this will be deleted automatically at program termination.       *)

end { CreateInetDomainSocket } ;

Quote
Recall my example from a previous post.

Code: Pascal  [Select][+][-]
  1.    
  2.     debian@ebb:~$ sudo /sbin/ip link set can1 up type can bitrate 250000
  3.     debian@ebb:~$ candump can1
  4.       can1  721   [1]  05
  5.       can1  1A1   [8]  20 00 FF 0F A8 FD A8 FD
  6.  

...

So in general I get the feeling that to add socketCAN support to FPC will require a fairly extensive modification of the base sockets library.  Is there any interest in this?  Who's allowed to change it. 

Noting that you seem to have demonstrated that the "plug-in" nature of the Linux network stack functionality is working properly... are you saying that this is purely an FPC issue rather than a kernel one? At that point I'd expect that a patch via Mantis would be appropriate, particularly since this appears to move FPC and possibly Lazarus into an area that it's not previously supported.

MarkMLl
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on October 22, 2020, 10:07:36 am

Noting that you seem to have demonstrated that the "plug-in" nature of the Linux network stack functionality is working properly... are you saying that this is purely an FPC issue rather than a kernel one? At that point I'd expect that a patch via Mantis would be appropriate, particularly since this appears to move FPC and possibly Lazarus into an area that it's not previously supported.

MarkMLl


Yes for both the BeagleBone and Pi and as I understand pretty well all Linux systems the socketCAN capability works well.  As the attached screen shot generated by the return result from the socket call with PF_CAN as the parameter shows.  PF_CAN doesn't exist so of course it fails.  The PF_CAN with a value of 29 doesn't exist in the definitions for socket.pp or whatever code is ultimately executed.  And the PF can is required so the system knows where to go for the data during a read.

Code: Pascal  [Select][+][-]
  1. const
  2.   PF_CAN = 29;
  3.   CAN_RAW = 1;
  4.  

Trouble is, GitHub and the associated read me files are so convoluted that I have no idea where to even start much less what to compile (if at all) to be able to duplicate the operation of the C programs.    I could make the changes but I don't know where to start.

Here's the example.  I realize bind should probably be used but it doesn't make it past the socket call.
Code: Pascal  [Select][+][-]
  1. unit socketunit;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Sockets, errors;
  9.  
  10. const
  11.   PF_CAN = 29;
  12.   CAN_RAW = 1;
  13.  
  14. type
  15.  
  16.   { TSocketForm }
  17.  
  18.   TSocketForm = class(TForm)
  19.     Button1: TButton;
  20.     Edit1: TEdit;
  21.     procedure Button1Click(Sender: TObject);
  22.   private
  23.  
  24.   public
  25.     socket_result : LongInt;
  26.     SAddr : TInetSockAddr;
  27.     Slen : TSockLen;
  28.     sin, sout : text;
  29.  
  30.   end;
  31.  
  32. var
  33.   SocketForm: TSocketForm;
  34.  
  35. implementation
  36.  
  37. {$R *.lfm}
  38.  
  39. { TSocketForm }
  40.  
  41. procedure TSocketForm.Button1Click(Sender: TObject);
  42. var
  43.     i : integer;
  44. begin
  45.   // open socket
  46.   socket_result := fpsocket(PF_CAN, SOCK_RAW, CAN_RAW);
  47.   if (socket_result < 0) then begin
  48.         // perror("socket");
  49.     Edit1.text := 'Error #' + IntToStr(socket_result) + ' creating socket';
  50.   end
  51.   else begin
  52.     SAddr.sin_family := PF_CAN;
  53.     SAddr.xpad := 'can0';
  54.     if fpconnect(socket_result, @SAddr, 0) = -1 then begin
  55.       Edit1.text := 'Socket can''t connect: ' + strerror(socketerror);
  56.     end;
  57.   end;
  58. end;
  59.  
  60. end.
  61.  
Title: Re: CAN-BUS SockectCAN
Post by: MarkMLl on October 22, 2020, 10:45:46 am
At the very least I suggest getting a bug report in  suggesting that FPC's definition of PF_INET (and possibly AF_INET?) should be accompanied by one for PF_CAN. However I think that you'd need to make sure that you could provide (links to) the appropriate numeric values for different OSes, since I don't think the numeric values can be relied upon to be constant... you're basically telling the OS how to populate an internal table.

MarkMLl
Title: Re: CAN-BUS SockectCAN
Post by: avra on October 22, 2020, 11:15:23 am
Here's the example.  I realize bind should probably be used but it doesn't make it past the socket call.
Because you are trying to use "SAddr : TInetSockAddr;" (C sockaddr) with SocketCAN, while you need to use C sockaddr_can. CAN C headers have not yet been translated to FPC. You will at least need sockaddr_can, ifreq and can_frame structures. You can find ifreq structure in \fpcsrc\packages\libc\src\nifh.inc, but the rest only in /usr/src/linux-source-5.8/include/uapi/linux/can.h and /usr/src/linux-source-5.8/include/uapi/linux/can/ (raw.h, bcm.h, error.h ...) waiting for translation.

Btw.1 You do not need CAN_FD for slcan devices since none of them implements faster CAN_FD yet (although CAN_FD is backwards compatible with slow CAN).
Btw.2 Did you read my previous message? I still think that socketcand path would be easier for you...
Title: Re: CAN-BUS SockectCAN
Post by: tetrastes on October 22, 2020, 12:39:40 pm
Code: Pascal  [Select][+][-]
  1.     if fpconnect(socket_result, @SAddr, 0) = -1 then begin
  2.  

Why the third parameter of fpconnect is zero?
Title: Re: CAN-BUS SockectCAN
Post by: MarkMLl on October 22, 2020, 01:29:16 pm
Code: Pascal  [Select][+][-]
  1.     if fpconnect(socket_result, @SAddr, 0) = -1 then begin
  2.  

Why the third parameter of fpconnect is zero?

Well spotted ;-)

For that matter, I have a lot of trouble tying https://www.freepascal.org/docs-html/rtl/sockets/fpconnect.html to anything remotely relevant.

MarkMLl
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on October 22, 2020, 07:06:19 pm
So in general I get the feeling that to add socketCAN support to FPC will require a fairly extensive modification of the base sockets library.
PF_CAN is just a number. In linux sources you can find it defined as AF_CAN, which is defined as 29. So why don't you try that first?

EDIT: I see now that you are looking at sources of candump. It will be much easier if you use simpler example from here:
https://www.beyondlogic.org/example-c-socketcan-code/

True.  And in my example I assigned 29 to PF_CAN.  The beyondlogic example in C translated to pascal still suffers from the same issue that it's not handled in the socket library.  Thank you for that link.  It does simplify the code.  The candump.c has become more complicated with CAN_FD support which I'm not interested in looking at right now.  Especially since it's not supported by the MCP2515 and the BeagleBone internal CAN device nor many of the other existing CANopen modules out there.

I don't really want to add what appears to be an extra layer with TCP if I don't have to.  I'll download and compile socketcand to see if it fits in with what I want to do.

BTW, under winsock2.pp 29 is allocated to
Code: Pascal  [Select][+][-]
  1.   AF_TCNPROCESS   = 29;
  2.   AF_TCNMESSAGE   = 30;
  3.   AF_ICLFXBM      = 31;
  4.  
  5.   AF_MAX          = 32;
  6.  

My goal is to make something that runs on Windows, Pi and BeagleBones and other small modules running Linux.  Even LinuxCNC.  Not that concerned about Linux Desktop PCs.  The PC doesn't have the SPI or embedded CAN device so the CANUSB from Lawicel (or equivalent module with identical protocol) is what I'm currently targeting.

Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on October 22, 2020, 07:08:55 pm
Code: Pascal  [Select][+][-]
  1.     if fpconnect(socket_result, @SAddr, 0) = -1 then begin
  2.  

Why the third parameter of fpconnect is zero?

Well spotted ;-)

For that matter, I have a lot of trouble tying https://www.freepascal.org/docs-html/rtl/sockets/fpconnect.html to anything remotely relevant.

MarkMLl
Because I never got past the socket call and had not used bind which is what should be used.  Wasn't even worried about fpconnect or the Saddr once I dove down into the socket library and saw that AF_CAN  or PF_CAN equal to 29 was not supported which essentially means the socketCAN library working in C or Python also won't work.
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on October 22, 2020, 07:25:05 pm
Code: Pascal  [Select][+][-]
  1.     if fpconnect(socket_result, @SAddr, 0) = -1 then begin
  2.  

Why the third parameter of fpconnect is zero?
Awe Crap!  That's what I get for leaving a project for 2 months and then jumping back in not remembering where I stopped.  In fact both you and Mark are correct that I'm using fpconnect incorrectly.
My mistake is that I though I didn't make it past the socket call which I do and returns 11 and not a value < 0. 

OK.  Some steps backwards and then I'll report what I've discovered.  Sheesh. Newbie type mistake...
Title: Re: CAN-BUS SockectCAN
Post by: avra on February 22, 2021, 03:41:43 pm
For a start, I would like to update fpc's linux kernel header translations with missing AF_CAN, PF_CAN and some other constants.

Needed kernel header is at
Quote
/usr/src/linux-headers-5.10.0-0.bpo.3-common/include/linux/socket.h
and I want to update file
Quote
fpcsrc/packages/rtl-extra/src/linux/unxsockh.inc

Should I also update
Quote
fpcsrc/packages/rtl-extra/src/android/unxsockh.inc
as well?

I only intend to test linux...
Title: Re: CAN-BUS SockectCAN
Post by: MarkMLl on February 22, 2021, 03:56:43 pm
For a start, I would like to update fpc's linux kernel header translations with missing AF_CAN, PF_CAN and some other constants.
...
I only intend to test linux...

Noting that the AF_ and PF_ constants are used by user and/or kernel code to express an interest in a particular protocol facet, and that there aren't helpers to extend enumerations and subranges, I think that as a matter of policy they're worth getting into header files etc. as soon as they are standardised by the IETF or whoever's authoritative.

MarkMLl
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on February 23, 2021, 03:44:16 am
For now this project is on hold for while I catch up on a few others.  I'm working on a project that uses the TI TMS320F28379D and the CAN bus and Quadrature encoder interface.  Also not quite finished a CNC mill conversion.  https://youtu.be/I6lvnYhlez4 (https://youtu.be/I6lvnYhlez4)
When I get a few of these other projects out of the way I'll come back to Lazarus and see about the sockets and socketCAN.
Title: Re: CAN-BUS SockectCAN
Post by: avra on February 23, 2021, 08:19:58 am
For a start, I would like to update fpc's linux kernel header translations with missing AF_CAN, PF_CAN and some other constants.
...
I only intend to test linux...

Noting that the AF_ and PF_ constants are used by user and/or kernel code to express an interest in a particular protocol facet, and that there aren't helpers to extend enumerations and subranges, I think that as a matter of policy they're worth getting into header files etc. as soon as they are standardised by the IETF or whoever's authoritative.
Those constants are only a start. I searched FPC files for them, and found where they are and what should be updated. I need a little guiding since it is not simple 1:1 header translation and there is a split into several files - probably because of cross platforming. Only when this work is finished, can and j1939 can build on them.

As for the standardization... well, I don't know what to say. Try to search in sources for AF_BLUETOOTH and you will see that in some operating systems it is defined as 31 and in some as 36. It seams to be OS dependent and not tied to some standard...
Title: Re: CAN-BUS SockectCAN
Post by: MarkMLl on February 23, 2021, 08:33:04 am
As for the standardization... well, I don't know what to say. Try to search in sources for AF_BLUETOOTH and you will see that in some operating systems it is defined as 31 and in some as 36. It seams to be OS dependent and not tied to some standard...

Hmmm. Another of those things like the data returned by a stat() call, where OSes varied and Linux tried to follow the dominant OS on each platform.

I obviously knew that the numerical value of AF_ and PF_ couldn't be trusted to be the same, but I'd assumed that ultimately they were traceable to IETF or similar... I was obviously wrong.

MarkMLl
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on February 23, 2021, 08:41:44 am
The issue isn't only the AF_CAN and PF_CAN.  The lower levels need to deal with the socketCAN infrastructure.  The best way to do this is to research what happens with AF_CAN and PF_CAN in sockets.c.  The socketCAN interface has been usable in Linux now for almost 10 years.  In fact the newest code I was looking at now also supports CANFD which is an enhancement to the original CAN protocol that supports larger messages at higher data rates for the data part.

Even if CANFD was not supported initially I suspect the best thing to do is to port the socketCAN section from the C code to the pascal side.  Then rewrite, again without the CANFD support, the command line applications that are written in C like candump.

The candump application is clever enough to know the difference between a Lawicel CANUSB dongle and say the SPI based Pi MCP2515 or the Beagle embledded CAN device.  In both cases those devices show up as files that can be opened.

To do most of this one doesn't have to actually know much about CAN, although it's useful, but mostly about how Linux handles devices that are files and how the socket communications deals with them.  It's on my do list.
John


Title: Re: CAN-BUS SockectCAN
Post by: avra on February 23, 2021, 02:48:05 pm
The issue isn't only the AF_CAN and PF_CAN...
That's why I said that updating socket wrapper with new constants is just a first step. Next step would be CAN through SocketCAN (not via socketcand daemon which already allows us to connect to CAN using ethernet), and after that SAE J1939 which is a layer on top of CAN. That's what I'm after. CAN FD is not in my focus, but I will probably add it, too.

Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on February 23, 2021, 06:23:51 pm
The issue isn't only the AF_CAN and PF_CAN...
That's why I said that updating socket wrapper with new constants is just a first step. Next step would be CAN through SocketCAN (not via socketcand daemon which already allows us to connect to CAN using ethernet), and after that SAE J1939 which is a layer on top of CAN. That's what I'm after. CAN FD is not in my focus, but I will probably add it, too.
My focus will be CANopen with a monitor program that runs equally well on PCs with Windows, LinuxCNC, Pi and Beagles.  But I've worked with all sorts of CAN protocols..
http://www.autoartisans.com/rings/9S12-Controller.jpg (http://www.autoartisans.com/rings/9S12-Controller.jpg)  This M9S12 has 5 CAN channels and I've used it on one project that had a proprietary protocol on one channel, CANopen on two more actiing as bridge and two J1939, one to servo motors and one to the vehicle for engine RPM and transmission status.   Software on the PC to interface to this was done with Delphi to the USB port
This module here http://www.autoartisans.com/CAN/STU-2.jpg (http://www.autoartisans.com/CAN/STU-2.jpg) runs a PiZeroW and includes a PIC32 for the high speed CAN buffering and then SPI.  C software with pipes etc. to log CAN messages from an electric vehicle into Pi Linux.  I had to use C for that.  Would have been nice to be able to use Lazarus.
Both those projects are for clients so I can't disclose details.  But there are lots of other projects on the go that will be published for playing with CAN and Pi or BBB.

Title: Re: CAN-BUS SockectCAN
Post by: avra on March 02, 2021, 01:55:42 pm
CAN constants have been added to FPC 48867:
https://svn.freepascal.org/svn/fpc/trunk/packages/rtl-extra/src/linux/unxsockh.inc

Also other stuff not related to CAN has been added from .../include/linux/socket.h in Linux 5.10 headers.

Proceeding further steps...
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on March 02, 2021, 06:25:31 pm
Awesome.  You've probably already seen this but for convenience here's the link:
https://www.beyondlogic.org/example-c-socketcan-code (https://www.beyondlogic.org/example-c-socketcan-code)

I guess for example one would take the C code and create a Lazarus command line version of candump called pcandump to avoid mixing things up.  But it needs that sockets.pp (I think that was the file) modified to understand the AF_CAN and PF_CAN constants.

https://elinux.org/Can-utils (https://elinux.org/Can-utils)

The above link is to an example which has a link to the source which has a link to the doc.
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 03, 2021, 09:54:10 am
Awesome.  You've probably already seen this but for convenience here's the link:
https://www.beyondlogic.org/example-c-socketcan-code (https://www.beyondlogic.org/example-c-socketcan-code)
That is the link I gave in my first reply to this topic.  ;)

I guess for example one would take the C code and create a Lazarus command line version of candump called pcandump to avoid mixing things up.
My initial goal would be to make pascal versions of cantransmit, canreceive and canfilter from https://github.com/craigpeacock/CAN-Examples. Then I would probably move to J1939.

But it needs that sockets.pp (I think that was the file) modified to understand the AF_CAN and PF_CAN constants.
Already done. With latest trunk you simply include sockets and those constants are available.

https://elinux.org/Can-utils (https://elinux.org/Can-utils)
The above link is to an example which has a link to the source which has a link to the doc.
I am familiar with that, too. I am the author of https://github.com/linux-can/can-utils/blob/master/can-j1939-install-kernel-module.md  :D
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on March 03, 2021, 07:11:19 pm
https://elinux.org/Can-utils (https://elinux.org/Can-utils)
The above link is to an example which has a link to the source which has a link to the doc.

I am familiar with that, too. I am the author of https://github.com/linux-can/can-utils/blob/master/can-j1939-install-kernel-module.md  :D

Nice write-up on the install of can-J1939.  I like the fact that you explain how to fix it when it goes wrong.  So many people leave that out of their description. :)
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 04, 2021, 12:05:38 pm
Nice write-up on the install of can-J1939.  I like the fact that you explain how to fix it when it goes wrong.  So many people leave that out of their description. :)
Thanks, you're very kind. I'm glad you like it.  :)
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 08, 2021, 11:12:04 am
Here is Linux SocketCAN wrapper. Not a full one yet, but enough to be able to compile 1:1 pascal version of https://github.com/craigpeacock/CAN-Examples/blob/master/cantransmit.c.

It compiles, however something is wrong since with pascal version during runtime binding:

Code: Pascal  [Select][+][-]
  1.     if fpbind(s, @addr, sizeof(addr)) < 0 then

I get socket error 88 (ESysENOTSOCK - Socket operation on non-socket).

C version of cantransmit example binds without problems and sends good data to canreceive, and I can also see with other sniffing tools that SocketCAN messaging is working.

Could someone please take a closer look at this "Socket operation on non-socket" problem?

Code: Pascal  [Select][+][-]
  1. program cantransmit;
  2.  
  3. {$mode delphi} {$H+}
  4.  
  5. uses
  6.   cthreads, classes, sysutils, sockets, unixtype, baseunix, can;
  7.  
  8. procedure PError(const S : string);
  9. begin
  10.   WriteLn(S, ', SocketError = ', SocketError);
  11. end;
  12.  
  13. var
  14.   s:     cint = 0;
  15.   addr:  sockaddr_can;
  16.   ifr:   ifreq;
  17.   frame: can_frame;
  18. begin
  19.   try
  20.     Writeln('CAN Sockets Demo');
  21.     if fpsocket(PF_CAN, SOCK_RAW, CAN_RAW) < 0 then
  22.     begin
  23.       perror('Socket');
  24.       Exit;
  25.     end;
  26.  
  27.     ifr.ifr_name := 'vcan0' ;
  28.     fpioctl(s, SIOCGIFINDEX, @ifr);
  29.  
  30.     memset(@addr, 0, sizeof(addr));
  31.     addr.can_family := AF_CAN;
  32.     addr.can_ifindex := ifr.ifr_ifindex;
  33.  
  34.     if fpbind(s, @addr, sizeof(addr)) < 0 then
  35.     //if fpbind(s, Psockaddr(@addr), sizeof(addr)) < 0 then
  36.     begin
  37.       perror('Bind');
  38.       Exit;
  39.     end;
  40.  
  41.     frame.can_id   := $555;
  42.     frame.can_dlc  := 5;
  43.     frame.datatext := 'Hello'; // datatext field is a variant record of chars overlaying data field
  44.  
  45.     if fpwrite(s, frame, sizeof(can_frame)) <> sizeof(can_frame) then
  46.     begin
  47.       perror('Write');
  48.       Exit;
  49.     end;
  50.  
  51.     if fpclose(s) < 0 then
  52.     begin
  53.       perror('Close');
  54.       Exit;
  55.     end;
  56.  
  57.   except
  58.     on e:Exception do
  59.       WriteLn(e.Message);
  60.   end;
  61. end.
  62.  

Code: C  [Select][+][-]
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5.  
  6. #include <net/if.h>
  7. #include <sys/ioctl.h>
  8. #include <sys/socket.h>
  9.  
  10. #include <linux/can.h>
  11. #include <linux/can/raw.h>
  12.  
  13. int main(int argc, char **argv)
  14. {
  15.         int s;
  16.         struct sockaddr_can addr;
  17.         struct ifreq ifr;
  18.         struct can_frame frame;
  19.  
  20.         printf("CAN Sockets Demo\r\n");
  21.  
  22.         if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
  23.                 perror("Socket");
  24.                 return 1;
  25.         }
  26.  
  27.         strcpy(ifr.ifr_name, "vcan0" );
  28.         ioctl(s, SIOCGIFINDEX, &ifr);
  29.  
  30.         memset(&addr, 0, sizeof(addr));
  31.         addr.can_family = AF_CAN;
  32.         addr.can_ifindex = ifr.ifr_ifindex;
  33.  
  34.         if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  35.                 perror("Bind");
  36.                 return 1;
  37.         }
  38.  
  39.         frame.can_id = 0x555;
  40.         frame.can_dlc = 5;
  41.         sprintf(frame.data, "Hello");
  42.  
  43.         if (write(s, &frame, sizeof(struct can_frame)) != sizeof(struct can_frame)) {
  44.                 perror("Write");
  45.                 return 1;
  46.         }
  47.  
  48.         if (close(s) < 0) {
  49.                 perror("Close");
  50.                 return 1;
  51.         }
  52.  
  53.         return 0;
  54. }

As you can see in code, I am using virtual vcan0 which you can create yourself if you follow instructions from https://www.elinux.org/Bringing_CAN_interface_up.

If needed sniffing tools can be found at https://www.elinux.org/Can-utils.

p.s. You need either trunk FPC, or you need to define missing CAN constants yourself as explained earlier in this thread.

UPDATE: The problem remains even when doing one of these:
Code: Pascal  [Select][+][-]
  1.     memset(@ifr, 0, sizeof(ifr));
Code: Pascal  [Select][+][-]
  1.     ifr.ifr_name := 'vcan0' + #0;
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 08, 2021, 12:15:12 pm
It looks like the problem is in fpioctl() call since this modified code:
Code: Pascal  [Select][+][-]
  1.     strcopy(ifr.ifr_name, 'vcan0');
  2.     WriteLn('before fpioctl: ifr.ifr_ifindex = ', ifr.ifr_ifindex);
  3.     if fpioctl(s, SIOCGIFINDEX, @ifr) < 0 then // SIOCGIFINDEX = $8933;
  4.     begin
  5.       WriteLn('after fpioctl: ifr.ifr_ifindex = ', ifr.ifr_ifindex);
  6.       WriteLn('fpGetErrno = ', fpGetErrno);
  7.       perror('IOctl');
  8.       Exit;
  9.     end;
exits with fpGetErrno = 25 and I can see that ifr.ifr_ifindex = 0 which tells me that vcan0 was not found at all,

while this modified part of C code:
Code: C  [Select][+][-]
  1.   strcpy(ifr.ifr_name, "vcan0" );
  2.   int i;
  3.   i = ioctl(s, SIOCGIFINDEX, &ifr);
  4.   if (i < 0){
  5.     perror("ioctl");
  6.     return 1;
  7.   };
  8.   printf("ioctl() = %d\n", i);
  9.   printf("ifr.ifr_ifindex = %d\n", ifr.ifr_ifindex);  
works well with ioctl() = 0 and ifr.ifr_ifindex = 3 which tells me that vcan0 was found properly.

So, is this a bug related to fpioctl() ???

UPDATE: No, it was not a bug in fpioctl(). Silly me, I forgot to get a handle in the first place.  :-[

I will provide working cantransmit a little later...
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 08, 2021, 02:44:19 pm
Here is a fully working SocketCAN transmit demo. First ever with FreePascal.  8-)

Code: Pascal  [Select][+][-]
  1. program cantransmit;
  2.  
  3. {$mode delphi} {$H+}
  4.  
  5. uses
  6.   cthreads, classes, sysutils, sockets, unixtype, baseunix, can;
  7.  
  8. procedure PError(const S : string);
  9. begin
  10.   WriteLn(S, ', SocketError = ', SocketError);
  11. end;
  12.  
  13. var
  14.   s:     cint = 0;
  15.   addr:  sockaddr_can;
  16.   ifr:   ifreq;
  17.   frame: can_frame;
  18. begin
  19.   try
  20.     Writeln('CAN Sockets Transmit Demo');
  21.     s := fpsocket(PF_CAN, SOCK_RAW, CAN_RAW);
  22.     if s < 0 then
  23.     begin
  24.       perror('Socket');
  25.       Exit;
  26.     end;
  27.  
  28.     strcopy(ifr.ifr_name, 'vcan0'); // ifr.ifr_name := 'vcan0' + #0;
  29.  
  30.     if fpioctl(s, SIOCGIFINDEX, @ifr) < 0 then
  31.     begin
  32.       perror('IOctl');
  33.       Exit;
  34.     end;
  35.  
  36.     memset(@addr, 0, sizeof(addr));
  37.     addr.can_family := AF_CAN;
  38.     addr.can_ifindex := ifr.ifr_ifindex;
  39.  
  40.     if fpbind(s, @addr, sizeof(addr)) < 0 then // equals to: if fpbind(s, Psockaddr(@addr), sizeof(addr)) < 0 then
  41.     begin
  42.       perror('Bind');
  43.       Exit;
  44.     end;
  45.  
  46.     frame.can_id   := $555;
  47.     frame.can_dlc  := 5;
  48.     frame.datatext := 'Hello'; // datatext field is a variant record of chars overlaying data field
  49.  
  50.     if fpwrite(s, frame, sizeof(can_frame)) <> sizeof(can_frame) then
  51.     begin
  52.       perror('Write');
  53.       Exit;
  54.     end;
  55.  
  56.     if fpclose(s) < 0 then
  57.     begin
  58.       perror('Close');
  59.       Exit;
  60.     end;
  61.  
  62.   except
  63.     on e:Exception do
  64.       WriteLn(e.Message);
  65.   end;
  66. end.
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 08, 2021, 03:34:55 pm
Also fully working SocketCAN receive demo. Enjoy!  :D

Code: Pascal  [Select][+][-]
  1. program canreceive;
  2.  
  3. {$mode delphi} {$H+}
  4.  
  5. uses
  6.   cthreads, classes, sysutils, sockets, unixtype, baseunix, can;
  7.  
  8. procedure PError(const S : string);
  9. begin
  10.   WriteLn(S, ', SocketError = ', SocketError);
  11. end;
  12.  
  13. var
  14.   s, i, nbytes: cint;
  15.   addr:  sockaddr_can;
  16.   ifr:   ifreq;
  17.   frame: can_frame;
  18. begin
  19.   try
  20.     Writeln('CAN Sockets Receive  Demo');
  21.     s := fpsocket(PF_CAN, SOCK_RAW, CAN_RAW);
  22.     if s < 0 then
  23.     begin
  24.       perror('Socket');
  25.       Exit;
  26.     end;
  27.  
  28.     strcopy(ifr.ifr_name, 'vcan0'); // ifr.ifr_name := 'vcan0' + #0;
  29.  
  30.     if fpioctl(s, SIOCGIFINDEX, @ifr) < 0 then
  31.     begin
  32.       perror('IOctl');
  33.       Exit;
  34.     end;
  35.  
  36.     memset(@addr, 0, sizeof(addr));
  37.     addr.can_family := AF_CAN;
  38.     addr.can_ifindex := ifr.ifr_ifindex;
  39.  
  40.     if fpbind(s, @addr, sizeof(addr)) < 0 then // equals to: if fpbind(s, Psockaddr(@addr), sizeof(addr)) < 0 then
  41.     begin
  42.       perror('Bind');
  43.       Exit;
  44.     end;
  45.  
  46.     nbytes := fpread(s, frame, sizeof(can_frame));
  47.     if nbytes < 0 then begin
  48.       perror('Read');
  49.       Exit;
  50.     end;
  51.  
  52.     Write(format('0x%03X [%d] ', [frame.can_id, frame.can_dlc]));
  53.     for i := 0 to frame.can_dlc - 1 do
  54.       Write(Format('%02X ', [frame.data[i]]));
  55.     WriteLn('');
  56.  
  57.     if fpclose(s) < 0 then
  58.     begin
  59.       perror('Close');
  60.       Exit;
  61.     end;
  62.  
  63.   except
  64.     on e:Exception do
  65.       WriteLn(e.Message);
  66.   end;
  67. end.
  68.  
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 09, 2021, 01:48:34 pm
SocketCAN filter demo:  :-X

Code: Pascal  [Select][+][-]
  1. program canfilter;
  2.  
  3. {$mode delphi} {$H+}
  4.  
  5. uses
  6.   cthreads, classes, sysutils, sockets, unixtype, baseunix, can, can.raw;
  7.  
  8. procedure PError(const S : string);
  9. begin
  10.   WriteLn(S, ', SocketError = ', SocketError);
  11. end;
  12.  
  13. var
  14.   s, i, nbytes: cint;
  15.   addr:         sockaddr_can;
  16.   ifr:          ifreq;
  17.   frame:        can_frame;
  18.   rfilter:      array[0..1] of can_filter;
  19. begin
  20.   try
  21.     Writeln('CAN Sockets Filter Demo');
  22.     s := fpsocket(PF_CAN, SOCK_RAW, CAN_RAW);
  23.     if s < 0 then
  24.     begin
  25.       perror('Socket');
  26.       Exit;
  27.     end;
  28.  
  29.     strcopy(ifr.ifr_name, 'vcan0'); // ifr.ifr_name := 'vcan0' + #0;
  30.     if fpioctl(s, SIOCGIFINDEX, @ifr) < 0 then
  31.     begin
  32.       perror('IOctl');
  33.       Exit;
  34.     end;
  35.  
  36.     memset(@addr, 0, sizeof(addr));
  37.     addr.can_family  := AF_CAN;
  38.     addr.can_ifindex := ifr.ifr_ifindex;
  39.  
  40.     if fpbind(s, @addr, sizeof(addr)) < 0 then // if fpbind(s, Psockaddr(@addr), sizeof(addr)) < 0 then
  41.     begin
  42.       perror('Bind');
  43.       Exit;
  44.     end;
  45.  
  46.     rfilter[0].can_id   := $550; // 1st CAN ID
  47.     rfilter[0].can_mask := $7F0; // 1st CAN MASK matches all frames with identifiers from $550 to $55F
  48.     rfilter[1].can_id   := $200; // 2nd CAN ID
  49.     rfilter[1].can_mask := $7FF; // 2nd CAN MASK matches only frames with identifier equal to $200 and nothing else
  50.  
  51.     fpsetsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, @rfilter, sizeof(rfilter));
  52.  
  53.     nbytes := fpread(s, frame, sizeof(can_frame));
  54.     if nbytes < 0 then begin
  55.       perror('Read');
  56.       Exit;
  57.     end;
  58.  
  59.     Write(format('0x%03X [%d] ', [frame.can_id, frame.can_dlc]));
  60.     for i := 0 to frame.can_dlc - 1 do
  61.       Write(Format('%02X ', [frame.data[i]]));
  62.     WriteLn('');
  63.  
  64.     if fpclose(s) < 0 then
  65.     begin
  66.       perror('Close');
  67.       Exit;
  68.     end;
  69.  
  70.   except
  71.     on e:Exception do
  72.       WriteLn(e.Message);
  73.   end;
  74. end.
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 11, 2021, 09:53:02 am
Finished conversion of all linux CAN headers (can, can.bcm, can.error, can.gw, can.isotp, can.j1939, can.netlink, can.raw and can.vxcan). I will see if I can shape it a little bit more, add some more demos, and prepare a patch for bug tracker. Demos for can and can.raw are already given, so I will probably add can.bcm and can.j1939 demos. If anyone is interested to contribute some other demos send me a PM and I will provide all header translations.

I guess that CAN support should be shaped as a FP package. That way it shall work out of the box with FP, as it already does with Python and C.

I should have done this a long time ago. Python and C are fine but there is no fun in that.  8-) :D 8-)
Title: Re: CAN-BUS SockectCAN
Post by: ThomasK on March 11, 2021, 03:01:32 pm
Hi, can you tell me where I can finde the required can and can.raw units you use in your solutions (Send ,receive, filter)?

Thanks and Best Regards,

Thomas
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 11, 2021, 03:11:35 pm
Hi, can you tell me where I can finde the required can and can.raw units you use in your solutions (Send ,receive, filter)?
Translated headers can be found in cantransmit.zip attached to message: https://forum.lazarus.freepascal.org/index.php/topic,39858.msg396883.html#msg396883. In just few days there have been almost 200 downloads.  8-) Since I have updated them a little, I have attached latest version of demos and all translated headers to this message.

Thanks and Best Regards
You're most welcome.   :D
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 11, 2021, 03:12:31 pm
@jcdammeyer: CAN FD receive and transmit demos are here.  It was not trivial to find info of what exactly to change when compared to legacy CAN but it works now. 8-)

Code: Pascal  [Select][+][-]
  1. //////////////////////////////////////////////////////////////////////////////////
  2. //                                                                              //
  3. //  This is a SocketCAN demo converted from C to Pascal by Zeljko Avramovic.    //
  4. //  Original code has GNU General Public License v3.0 and can be found at       //
  5. //  https://github.com/craigpeacock/CAN-Examples                                //
  6. //                                                                              //
  7. //  Virtual CAN adapter vcan0 is hard coded and you can bring it up like this:  //
  8. //  sudo modprobe vcan                                                          //
  9. //  sudo ip link add dev vcan0 type vcan                                        //
  10. //  sudo ip link set vcan0 mtu 72            # needed for CAN FD                //
  11. //  sudo ip link set vcan0 up                                                   //
  12. //                                                                              //
  13. //////////////////////////////////////////////////////////////////////////////////
  14.  
  15. program canfdtransmit;
  16.  
  17. {$mode delphi} {$H+}
  18.  
  19. uses
  20.   cthreads, classes, sysutils, sockets, baseunix, can, can.raw;
  21.  
  22. procedure perror(const S : string);
  23. begin
  24.   WriteLn(S, ', SocketError = ', SocketError);
  25. end;
  26.  
  27. var
  28.   s, err: cint;
  29.   addr:   sockaddr_can;
  30.   ifr:    ifreq;
  31.   frame:  canfd_frame;
  32. begin
  33.   try
  34.     Writeln('CAN FD Sockets Transmit Demo');
  35.     s := fpsocket(PF_CAN, SOCK_RAW, CAN_RAW);
  36.     if s < 0 then
  37.     begin
  38.       if s = ESysENOPROTOOPT then
  39.         Writeln('CAN_RAW_FD_FRAMES socket option is not supported. Your kernel is probably too old.');
  40.       perror('Socket');
  41.       Exit;
  42.     end;
  43.  
  44.     strcopy(ifr.ifr_name, 'vcan0');
  45.     if fpioctl(s, SIOCGIFINDEX, @ifr) < 0 then
  46.     begin
  47.       perror('IOctl');
  48.       Exit;
  49.     end;
  50.  
  51.     memset(@addr, 0, sizeof(addr));
  52.     addr.can_family  := AF_CAN;
  53.     addr.can_ifindex := ifr.ifr_ifindex;
  54.  
  55.     if fpbind(s, @addr, sizeof(addr)) < 0 then
  56.     begin
  57.       perror('Bind');
  58.       Exit;
  59.     end;
  60.  
  61.     frame.can_id := $444;    // CAN FD message ID
  62.     frame.len    := 20;      // payload length will be 20 bytes
  63.     frame.data   := [$01, $02, $03, $04, $05, $06, $07, $08, $09, $0A, $0B, $0C, $0D, $0E, $0F, $10,
  64.                      $11, $12, $13, $14, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
  65.                      $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
  66.                      $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00];
  67.                      // 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
  68.     {
  69.     frame.data[0]  := $01; // alternative for the above
  70.     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
  71.     frame.data[2]  := $03;
  72.     frame.data[3]  := $04;
  73.     frame.data[4]  := $05;
  74.     frame.data[5]  := $06;
  75.     frame.data[6]  := $07;
  76.     frame.data[7]  := $08;
  77.     frame.data[8]  := $09;
  78.     frame.data[9]  := $0A;
  79.     frame.data[10] := $0B;
  80.     frame.data[11] := $0C;
  81.     frame.data[12] := $0D;
  82.     frame.data[13] := $0E;
  83.     frame.data[14] := $0F;
  84.     frame.data[15] := $10;
  85.     frame.data[16] := $11;
  86.     frame.data[17] := $12;
  87.     frame.data[18] := $13;
  88.     frame.data[19] := $14;
  89.     }
  90.  
  91.     err := fpsetsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, @ENABLE_CAN_OPTION, sizeof(ENABLE_CAN_OPTION));
  92.     if err <> 0 then
  93.     begin
  94.       if err = ESysENOPROTOOPT then
  95.         WriteLn('CAN FD Protocol not available. Try newer kernel');
  96.       perror('SetSockopt');
  97.       Exit;
  98.     end;
  99.  
  100.     if fpwrite(s, frame, sizeof(canfd_frame)) <> sizeof(canfd_frame) then
  101.     begin
  102.       perror('Write');
  103.       Exit;
  104.     end;
  105.  
  106.     if fpclose(s) < 0 then
  107.     begin
  108.       perror('Close');
  109.       Exit;
  110.     end;
  111.  
  112.   except
  113.     on e:Exception do
  114.       WriteLn(e.Message);
  115.   end;
  116. end.

Code: Pascal  [Select][+][-]
  1. //////////////////////////////////////////////////////////////////////////////////
  2. //                                                                              //
  3. //  This is a SocketCAN demo converted from C to Pascal by Zeljko Avramovic.    //
  4. //  Original code has GNU General Public License v3.0 and can be found at       //
  5. //  https://github.com/craigpeacock/CAN-Examples                                //
  6. //                                                                              //
  7. //  Virtual CAN adapter vcan0 is hard coded and you can bring it up like this:  //
  8. //  sudo modprobe vcan                                                          //
  9. //  sudo ip link add dev vcan0 type vcan                                        //
  10. //  sudo ip link set vcan0 mtu 72            # needed for CAN FD                //
  11. //  sudo ip link set vcan0 up                                                   //
  12. //                                                                              //
  13. //////////////////////////////////////////////////////////////////////////////////
  14.  
  15. program canfdreceive;
  16.  
  17. {$mode delphi} {$H+}
  18.  
  19. uses
  20.   cthreads, classes, sysutils, sockets, unixtype, baseunix, can, can.raw;
  21.  
  22. procedure perror(const S : string);
  23. begin
  24.   WriteLn(S, ', SocketError = ', SocketError);
  25. end;
  26.  
  27. var
  28.   s, i, nbytes, err: cint;
  29.   addr:              sockaddr_can;
  30.   ifr:               ifreq;
  31.   frame:             canfd_frame;
  32. begin
  33.   try
  34.     Writeln('CAN FD Sockets Receive Demo');
  35.     s := fpsocket(PF_CAN, SOCK_RAW, CAN_RAW);
  36.     if s < 0 then
  37.     begin
  38.       perror('Socket');
  39.       Exit;
  40.     end;
  41.  
  42.     strcopy(ifr.ifr_name, 'vcan0'); // ifr.ifr_name := 'vcan0' + #0;
  43.     if fpioctl(s, SIOCGIFINDEX, @ifr) < 0 then
  44.     begin
  45.       perror('IOctl');
  46.       Exit;
  47.     end;
  48.  
  49.     memset(@addr, 0, sizeof(addr));
  50.     addr.can_family  := AF_CAN;
  51.     addr.can_ifindex := ifr.ifr_ifindex;
  52.  
  53.     if fpbind(s, @addr, sizeof(addr)) < 0 then
  54.     begin
  55.       perror('Bind');
  56.       Exit;
  57.     end;
  58.  
  59.     err := fpsetsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, @ENABLE_CAN_OPTION, sizeof(ENABLE_CAN_OPTION));
  60.     if err <> 0 then
  61.     begin
  62.       if err = ESysENOPROTOOPT then
  63.         WriteLn('CAN FD Protocol not available. Try newer kernel');
  64.       perror('SetSockopt');
  65.       Exit;
  66.     end;
  67.  
  68.     nbytes := fpread(s, frame, sizeof(canfd_frame));
  69.     if nbytes < 0 then
  70.     begin
  71.       perror('Read');
  72.       Exit;
  73.     end;
  74.     if nbytes < sizeof(can_frame) then // paranoid check
  75.     begin
  76.       perror('Read: Incomplete CAN frame');
  77.       Exit;
  78.     end;
  79.  
  80.     if nbytes = CANFD_MTU then
  81.       WriteLn('CAN FD frame received with length ', IntToStr(frame.len))
  82.     else if nbytes = CAN_MTU then
  83.       WriteLn('CAN legacy frame received with length ', IntToStr(frame.len))
  84.     else
  85.       WriteLn('Invalid CAN(FD) frame received');
  86.  
  87.     Write(format('0x%03X [%d] ', [frame.can_id, frame.len]));
  88.     for i := 0 to frame.len - 1 do
  89.       Write(Format('%02.2X ', [frame.data[i]]));
  90.     WriteLn('');
  91.  
  92.     if fpclose(s) < 0 then
  93.     begin
  94.       perror('Close');
  95.       Exit;
  96.     end;
  97.  
  98.   except
  99.     on e:Exception do
  100.       WriteLn(e.Message);
  101.   end;
  102. end.
Title: Re: CAN-BUS SockectCAN
Post by: ThomasK on March 11, 2021, 03:26:32 pm

You're most welcome.   :D

Thanks a lot. I recently started progamming Pascal again. I started in 1977 on a Siemens 4004/151 with punch cards.....
My first application runs on a Pi.
Title: Re: CAN-BUS SockectCAN
Post by: Fred vS on March 11, 2021, 03:33:57 pm
@Avra: Wonderful! (like always with you  ;))

Many thanks.

Fre;D
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 11, 2021, 03:41:30 pm
@Avra: Wonderful! (like always with you  ;))

Many thanks.
You're very kind and you're most welcome.   :)

You can test canfdreceive either with provided canfdtransmit, or you can use can-utils like this:

for legacy CAN:
Quote
cansend vcan0 456#DEADBEEF

for CAN FD:
Quote
cansend vcan0 123##1112233445566778899AABBCC

for CAN XL:
Quote
Just kidding  :D :D :D. CAN XL is in testing phase and linux is not ready for it yet. But according to specification it should be compatible to CAN FD so we do not have to worry for now...
Title: Re: CAN-BUS SockectCAN
Post by: sstvmaster on March 11, 2021, 05:08:33 pm
@Avra: Many thanks.

Wouldn't it be better to upload your work to Bitbucket, Github, ..., and make an own repo for that?

Rgr Maik
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 12, 2021, 07:53:40 am
@Avra: Many thanks.
You're most welcome. I'm glad it's of use to others.  :P

Wouldn't it be better to upload your work to Bitbucket, Github, ..., and make an own repo for that?
This is just a temporary public playground. My final goal is to make SocketCAN header translations and demos integral part of FreePascal, so that CAN works out of the box without downloading anything additional. Like Python and C already have.

So far my development and testing is on Debian x86-64 via vcan, using can-utils and Kayak. I will probably also test it on Manjaro x86-64. While I do intend to test it with real hardware on Raspbery Pi and PocketBeagle in the future, I would appreciate any testing feedback I can get now. Especially on 32 and 64 bit ARM - even with just vcan.
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 15, 2021, 02:43:27 pm
Here is SocketCAN BCM cyclic demo where you let kernel take care of sending interval. Enjoy!  :D

Code: Pascal  [Select][+][-]
  1. //////////////////////////////////////////////////////////////////////////////////
  2. //                                                                              //
  3. //  This is a SocketCAN BCM cyclic demo created by Zeljko Avramovic             //
  4. //  FPC modified LGPL licence: https://wiki.freepascal.org/FPC_modified_LGPL    //
  5. //                                                                              //
  6. //  Virtual CAN adapter vcan0 is hard coded and you can bring it up like this:  //
  7. //  sudo modprobe vcan                                                          //
  8. //  sudo ip link add dev vcan0 type vcan                                        //
  9. //  sudo ip link set vcan0 mtu 72            # needed for CAN FD                //
  10. //  sudo ip link set vcan0 up                                                   //
  11. //                                                                              //
  12. //////////////////////////////////////////////////////////////////////////////////
  13.  
  14. program cancyclic;
  15.  
  16. {$mode delphi} {$H+}
  17.  
  18. uses
  19.   cthreads, classes, sysutils, sockets, baseunix, crt, can, can.bcm;
  20.  
  21. type
  22.   bcm_msg = record
  23.     head: bcm_msg_head_without_frames; // we shall use more then 1 frame so bcm_msg_head is not enough
  24.     frame: array[0..2] of can_frame;   // and we add here space for our 3 frames
  25.   end;
  26.  
  27. procedure perror(const S : string);
  28. begin
  29.   WriteLn(S, ', SocketError = ', SocketError);
  30. end;
  31.  
  32. var
  33.   s, i: cint;
  34.   addr: sockaddr_can;
  35.   ifr:  ifreq;
  36.   msg:  bcm_msg;
  37. begin
  38.   try
  39.     Writeln('CAN Sockets BCM Cyclic Demo');
  40.     s := fpsocket(PF_CAN, SOCK_DGRAM, CAN_BCM);
  41.     if s < 0 then
  42.     begin
  43.       perror('Socket');
  44.       Exit;
  45.     end;
  46.  
  47.     strcopy(ifr.ifr_name, 'vcan0'); // ifr.ifr_name := 'vcan0' + #0;
  48.     if fpioctl(s, SIOCGIFINDEX, @ifr) < 0 then
  49.     begin
  50.       perror('IOctl');
  51.       Exit;
  52.     end;
  53.  
  54.     memset(@addr, 0, sizeof(addr));
  55.     addr.can_family  := AF_CAN;
  56.     addr.can_ifindex := ifr.ifr_ifindex;
  57.  
  58.     if fpconnect(s, @addr, sizeof(addr)) < 0 then
  59.     begin
  60.       perror('Connect');
  61.       Exit;
  62.     end;
  63.  
  64.     msg.head.opcode        := TX_SETUP;
  65.     msg.head.can_id        := $567; // if TX_CP_CAN_ID flag is set then all messages shall have this CAN ID
  66.     msg.head.flags         := SETTIMER OR STARTTIMER OR TX_ANNOUNCE {OR TX_CP_CAN_ID} {OR TX_RESET_MULTI_IDX};
  67.     msg.head.nframes       := 3;
  68.     msg.head.count         := 0; // single interval (use only ival2)
  69.     msg.head.ival1.tv_sec  := 0;
  70.     msg.head.ival1.tv_usec := 0;
  71.     msg.head.ival2.tv_sec  := 0;
  72.     msg.head.ival2.tv_usec := 250000; // 250 ms interval between CAN messages
  73.     msg.frame[0].can_id    := $550; // not used if TX_CP_CAN_ID falg is set
  74.     msg.frame[0].can_dlc   := 2;
  75.     msg.frame[0].data      := [$01,$02,$03,$04,$05,$06,$07,$08];
  76.     msg.frame[1].can_id    := $551; // not used if TX_CP_CAN_ID falg is set
  77.     msg.frame[1].can_dlc   := 4;
  78.     msg.frame[1].data      := [$11,$12,$13,$14,$15,$16,$17,$18];
  79.     msg.frame[2].can_id    := $552; // not used if TX_CP_CAN_ID falg is set
  80.     msg.frame[2].can_dlc   := 8;
  81.     msg.frame[2].data      := [$21,$22,$23,$24,$25,$26,$27,$28];
  82.  
  83.     if fpwrite(s, msg, sizeof(msg)) <> sizeof(msg) then
  84.     begin
  85.       perror('Write');
  86.       Exit;
  87.     end;
  88.  
  89.     repeat
  90.       WriteLn('Press any key to stop...');
  91.       msg.frame[2].DataByte[0] := msg.frame[2].DataByte[0] + 1;
  92.       for i := 0 to msg.frame[2].can_dlc - 1 do
  93.         Write(Format('%02.2X ', [msg.frame[2].data[i]]));
  94.       WriteLn('');
  95.       WriteLn('');
  96.       fpwrite(s, msg, sizeof(msg)); // comment out this line if you do not want to publish changed frame[2]
  97.       Delay(2000); // loop every 2 seconds
  98.     until KeyPressed;
  99.  
  100.     if fpclose(s) < 0 then
  101.     begin
  102.       perror('Close');
  103.       Exit;
  104.     end;
  105.  
  106.   except
  107.     on e:Exception do
  108.       WriteLn(e.Message);
  109.   end;
  110. end.
  111.  
Title: Re: CAN-BUS SockectCAN
Post by: radek on March 16, 2021, 01:01:29 am
Hi,
I apologize in advance for my English, I am also interested in the implementation of CAN for Lazarus.

I wonder what the performance difference will be if I use:
1) This solution via SocketCAN
2) Direct control of IC MCP2518 via SPI bus using Lazarus
3) Direct control of IC MCP2518 via USB using IC MCP2210 (USB to SPI driver) libusb

I'm interested because I want the application to work under both Windows and Linux. When I use MCP2210 and MCP2518, I can control the CAN driver via SPI directly in Windows and Linux. If I use SocketCAN, then I have to implement another solution for Windows.
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 16, 2021, 08:35:47 am
I am also interested in the implementation of CAN for Lazarus.
Nice to hear  ;)

I wonder what the performance difference will be if I use:
1) This solution via SocketCAN
2) Direct control of IC MCP2518 via SPI bus using Lazarus
3) Direct control of IC MCP2518 via USB using IC MCP2210 (USB to SPI driver) libusb
Any modern PC or SBC CPU is capable of handling CAN without problems. Bottleneck is communication channel. In case of Lawicel/SLCAN/CAN232 it is serial communication - if you use classic AVR ATMEGA328 based Arduino it is 115200 (STM32 or ESP32 based ones may use speeds higher then that so they do not have that problem), you don't use filters and want to see all of high speed CAN traffic then expect to miss frames here and there. Using MCP2518 direct via SPI on Raspberry Pi or PocketBeagle for CAN and CAN FD is solid and comfortable. I haven't used MCP2518 over MCP2210 but I guess that might also skip frames. SocketCAN is just a Berkeley sockets abstraction layer over any Linux CAN hardware, and you use it the same with both SPI MCP2518 and Lawicel/SLCAN/CAN232 (there is no driver for MCP2518 over MCP2210). So, performance does not suffer if you use SocketCAN.

I'm interested because I want the application to work under both Windows and Linux. When I use MCP2210 and MCP2518, I can control the CAN driver via SPI directly in Windows and Linux. If I use SocketCAN, then I have to implement another solution for Windows.
Well, you said it all. Since you want your app to be used on both Windows and Linux, unfortunately you need to give up SocketCAN (unless someone implements it under Windows). Your best bet would be to use some STM32 or ESP32 Lawicel/SLCAN/CAN232 using higher serial speeds, which would probably avoid frame dropping unless you use it on a very, very high traffic 1Mbit CAN.

Also take a look at this discussion: https://forum.lazarus.freepascal.org/index.php/topic,51477.msg377993.html#msg377993
Title: Re: CAN-BUS SockectCAN
Post by: radek on March 16, 2021, 12:19:30 pm
Just to add, the MCP2210 is a High Speed USB HID driver for the SPI bus with speeds from 1500bps to 12Mbps, so there will be no bottleneck. The only problem is that I need to constantly read the 64 byte register to see if the MCP2518 has received any data, this may cause some CPU usage.
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 16, 2021, 02:08:42 pm
Just to add, the MCP2210 is a High Speed USB HID driver for the SPI bus with speeds from 1500bps to 12Mbps, so there will be no bottleneck. The only problem is that I need to constantly read the 64 byte register to see if the MCP2518 has received any data, this may cause some CPU usage.
It doesn't matter how fast you set it's SPI to talk to CAN chip. It seams to use USB HID, which is limited to 1000 messages per second where each message can have up to 64 bytes. You do the math. Ah yes, and while you are transferring data over USB you can not get new CAN messages.

https://github.com/daniel-santos/mcp2210-linux/issues/11
Title: Re: CAN-BUS SockectCAN
Post by: joelucsd on March 23, 2021, 10:23:02 pm
Thank you for the work to get the CANsocket working.  I pulled in the files from can.zip and it worked.  I am using an older version of FPC on the raspberry Pi.  The example worked.  I used that code as a template for my Lazarus project.

I needed an Extended ID.  Will look at that tomorrow.  Might just need to set the extended ID manually before stuffing the value into the frame field.

Regards,
Joel
Title: Re: CAN-BUS SockectCAN
Post by: avra on March 25, 2021, 08:28:09 am
Thank you for the work to get the CANsocket working.
You're most welcome.  ;)

I pulled in the files from can.zip and it worked.  I am using an older version of FPC on the raspberry Pi.  The example worked.  I used that code as a template for my Lazarus project.
Thank you for the report. I didn't catch time to test on Pi and PocketBeagle yet, so I'm glad to hear it works on Pi. Just for info, could you tell me what CAN hardware did you use during testing?

I needed an Extended ID.  Will look at that tomorrow.  Might just need to set the extended ID manually before stuffing the value into the frame field.
So far I have attached enough for 1:1 translation of various C examples you can find on the net. Right now I am working on bit packed overlays which would allow easy access to individual bits, and some higher level helper methods. After that I will probably add SAE J1939 (for trucks, buses, tractors, boats and heavy machinery) where Extended ID is used, and at the end provide a FPC patch so that we can all use SocketCAN out of the box.
Title: Re: CAN-BUS SocketCAN
Post by: joelucsd on March 25, 2021, 06:00:16 pm
I am running on a Raspberry Pi 4.
Raspbian GNU/Linux 10
FPC version is: 3.0.4+dfsg-22+rpi1
Lazarus: 2.0.0+dfsg-2   2019-03-01
I am using a USB to CAN adapter from www.inno-maker.com.  It is a nice cheap solution.
http://wiki.inno-maker.com/display/HOMEPAGE/usb2can
I got mine through Amazon
You do have to enable it with a couple of commands:
'sudo ip link set can0 type can bitrate 250000'
'sudo ifconfig can0 up'

I did get extended addressing to work.  Like I suggested, I just had to set bit 31 to select it before writing the ID into the frame structure.  Then it came out on the bus.  The Python library has an additional parameter in the call to say it is the 29 bit version of the ID.  Setting the bit manually before works fine.  You just need to know to do it.  (And I don't like the Python syntax.  So would rather use Pascal or C)
Title: Re: CAN-BUS SocketCAN
Post by: avra on March 26, 2021, 10:18:54 am
I am running on a Raspberry Pi 4.
Raspbian GNU/Linux 10
FPC version is: 3.0.4+dfsg-22+rpi1
Lazarus: 2.0.0+dfsg-2   2019-03-01
I am using a USB to CAN adapter from www.inno-maker.com.
Thanks for the report. I guess with 3.0.4 you had to manually add missing CAN constants.

You do have to enable it with a couple of commands:
'sudo ip link set can0 type can bitrate 250000'
'sudo ifconfig can0 up'
That's pretty standard for a CAN device that kernel can recognize.

I did get extended addressing to work.  Like I suggested, I just had to set bit 31 to select it before writing the ID into the frame structure.
I know. That's why I said "I am working on bit packed overlays which would allow easy access to individual bits".  ;)
Title: Re: CAN-BUS SocketCAN
Post by: avra on March 31, 2021, 11:14:03 am
I have implemented high level CAN access in can.hl unit. So, if you do your own code from scratch it is recommended to use this unit. Old low level C-like access will stay for easier future upgrades, and you will probably use it only when you want 1:1 translation of some C example from the net. In the attachment you will find new CAN examples hlcancyclic, hlcanfdreceive, hlcanfdtransmit, hlcanfilter, hlcanreceive and hlcantransmit. These are all "high level" versions of previous examples using can.hl unit (if you can give "high level" name to pascalish renaming, bit packed overlays and some helpers).

I hope you will find CAN usage more pleasant now.

@joelucsd: Take a look at hlcanfdtransmit which uses extended 29-bit CAN ID addressing now. It is as simple as this:
Code: Pascal  [Select][+][-]
  1.     CanFDFrame.ID.Value := $444444; // CAN FD message extended ID
  2.     CanFDFrame.ID.EFF   := true;    // confirm that we have 29-bit CAN ID

Talk is cheap. Here is what CAN code looks like now:
Code: Pascal  [Select][+][-]
  1. program hlcanfdtransmit; // higher level pascalized version of canfdtransmit demo
  2.  
  3. {$mode delphi} {$H+}
  4.  
  5. uses
  6.   cthreads, sysutils, sockets, baseunix, can, can.hl, can.raw;
  7.  
  8. procedure perror(const S : string);
  9. begin
  10.   WriteLn(S, ', SocketError = ', SocketError);
  11. end;
  12.  
  13. var
  14.   Err:          integer;
  15.   CanHandle:    TCanHandle;
  16.   CanAddr:      TCanSockAddr;
  17.   CanInterface: TCanIfreq;
  18.   CanFDFrame:   TCanFDFrame;
  19. begin
  20.   try
  21.     Writeln('CAN FD Sockets Transmit Demo');
  22.     CanHandle := CanSocket(SOCK_RAW, CAN_RAW);
  23.     if CanHandle < 0 then
  24.     begin
  25.       perror('Socket');
  26.       Exit;
  27.     end;
  28.  
  29.     CanInterface.Name := 'vcan0' + #0;
  30.     if CanIOCtl(CanHandle, SIOCGIFINDEX, CanInterface) < 0 then
  31.     begin
  32.       perror('IOctl');
  33.       Exit;
  34.     end;
  35.  
  36.     CanAddr.Clear;
  37.     CanAddr.CanFamily  := AF_CAN;
  38.     CanAddr.CanIfIndex := CanInterface.IfIndex;
  39.  
  40.     if CanBind(CanHandle, CanAddr) < 0 then
  41.     begin
  42.       perror('Bind');
  43.       Exit;
  44.     end;
  45.  
  46.     CanFDFrame.ID.Value := $444444; // CAN FD message extended ID
  47.     CanFDFrame.ID.EFF   := true;    // confirm that we have 29-bit CAN ID
  48.     CanFDFrame.Len      := 20;      // payload length will be 20 bytes
  49.     CanFDFrame.Data     := [$01, $02, $03, $04, $05, $06, $07, $08, $09, $0A, $0B, $0C, $0D, $0E, $0F, $10,
  50.                             $11, $12, $13, $14, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
  51.                             $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
  52.                             $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00];
  53.                             // shows as '0x444444 [40] 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14' in canfdreceive
  54.     {
  55.     CanFDFrame.Data[0]  := $01; // alternative for the above
  56.     CanFDFrame.Data[1]  := $02; // shows as '0x444444 [40] 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14' in canfdreceive
  57.     CanFDFrame.Data[2]  := $03;
  58.     CanFDFrame.Data[3]  := $04;
  59.     CanFDFrame.Data[4]  := $05;
  60.     CanFDFrame.Data[5]  := $06;
  61.     CanFDFrame.Data[6]  := $07;
  62.     CanFDFrame.Data[7]  := $08;
  63.     CanFDFrame.Data[8]  := $09;
  64.     CanFDFrame.Data[9]  := $0A;
  65.     CanFDFrame.Data[10] := $0B;
  66.     CanFDFrame.Data[11] := $0C;
  67.     CanFDFrame.Data[12] := $0D;
  68.     CanFDFrame.Data[13] := $0E;
  69.     CanFDFrame.Data[14] := $0F;
  70.     CanFDFrame.Data[15] := $10;
  71.     CanFDFrame.Data[16] := $11;
  72.     CanFDFrame.Data[17] := $12;
  73.     CanFDFrame.Data[18] := $13;
  74.     CanFDFrame.Data[19] := $14;
  75.     }
  76.  
  77.     Err := CanSetSockOpt(CanHandle, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, ENABLE_CAN_OPTION, SizeOf(ENABLE_CAN_OPTION));
  78.     if Err <> 0 then
  79.     begin
  80.       if Err = ESysENOPROTOOPT then
  81.         WriteLn('CAN FD Protocol not available. Try newer kernel');
  82.       perror('SetSockopt');
  83.       Exit;
  84.     end;
  85.  
  86.     if CanWrite(CanHandle, CanFDFrame) <> SizeOf(CanFDFrame) then
  87.     begin
  88.       perror('Write');
  89.       Exit;
  90.     end;
  91.  
  92.     if CanClose(CanHandle) < 0 then
  93.     begin
  94.       perror('Close');
  95.       Exit;
  96.     end;
  97.  
  98.   except
  99.     on e: Exception do
  100.       WriteLn(e.Message);
  101.   end;
  102. end.
  103.  

Code: Pascal  [Select][+][-]
  1. program hlcanfdreceive; // higher level pascalized version of canfdreceive demo
  2.  
  3. {$mode delphi} {$H+}
  4.  
  5. uses
  6.   cthreads, sysutils, sockets, baseunix, can, can.hl, can.raw;
  7.  
  8. procedure perror(const S : string);
  9. begin
  10.   WriteLn(S, ', SocketError = ', SocketError);
  11. end;
  12.  
  13. var
  14.   i, BytesNo:   byte;
  15.   Err:          integer;
  16.   CanHandle:    TCanHandle;
  17.   CanAddr:      TCanSockAddr;
  18.   CanInterface: TCanIfreq;
  19.   CanFDFrame:   TCanFDFrame;
  20. begin
  21.   try
  22.     Writeln('CAN FD Sockets Receive Demo');
  23.     CanHandle := CanSocket(SOCK_RAW, CAN_RAW);
  24.     if CanHandle < 0 then
  25.     begin
  26.       perror('Socket');
  27.       Exit;
  28.     end;
  29.  
  30.     CanInterface.Name := 'vcan0' + #0;
  31.     if CanIOCtl(CanHandle, SIOCGIFINDEX, CanInterface) < 0 then
  32.     begin
  33.       perror('IOctl');
  34.       Exit;
  35.     end;
  36.  
  37.     CanAddr.Clear;
  38.     CanAddr.CanFamily  := AF_CAN;
  39.     CanAddr.CanIfIndex := CanInterface.IfIndex;
  40.  
  41.     if CanBind(CanHandle, CanAddr) < 0 then
  42.     begin
  43.       perror('Bind');
  44.       Exit;
  45.     end;
  46.  
  47.     Err := CanSetSockOpt(CanHandle, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, ENABLE_CAN_OPTION, SizeOf(ENABLE_CAN_OPTION));
  48.     if Err <> 0 then
  49.     begin
  50.       if Err = ESysENOPROTOOPT then
  51.         WriteLn('CAN FD Protocol not available. Try newer kernel.');
  52.       perror('SetSockopt');
  53.       Exit;
  54.     end;
  55.  
  56.     BytesNo := CanRead(CanHandle, CanFDFrame);
  57.     if BytesNo < 0 then
  58.     begin
  59.       perror('Read');
  60.       Exit;
  61.     end;
  62.  
  63.     if BytesNo = CANFD_MTU then    // test CAN FD with 'cansend vcan0 123##1223344556677889900'
  64.       WriteLn('CAN FD frame received with length ', IntToStr(CanFDFrame.Len))
  65.     else if BytesNo = CAN_MTU then // test legacy CAN with 'cansend vcan0 456#DEADBEEF'
  66.       WriteLn('CAN legacy frame received with length ', IntToStr(CanFDFrame.Len))
  67.     else
  68.       WriteLn('Invalid CAN(FD) frame received');
  69.  
  70.     Write(format('0x%03X [%d] ', [CanFDFrame.ID.Value, CanFDFrame.Len]));
  71.     for i := 0 to CanFDFrame.Len - 1 do
  72.       Write(Format('%02.2X ', [CanFDFrame.Data[i]]));
  73.     WriteLn('');
  74.  
  75.     if CanClose(CanHandle) < 0 then
  76.     begin
  77.       perror('Close');
  78.       Exit;
  79.     end;
  80.  
  81.   except
  82.     on e: Exception do
  83.       WriteLn(e.Message);
  84.   end;
  85. end.
  86.  

Hopefully, J1939 examples are next.

Remember, this is all still a playground and things may change until I include SocketCAN support into FP trunk.
Title: Re: CAN-BUS SocketCAN
Post by: avra on April 16, 2021, 02:20:52 pm
I've been thinking about creating some unique CAN tools. There are so many tools for sniffing, dumping and hacking your car CAN communication, but very few touch showing CAN error message details. The ones which do, show just a few selected messages, and there is none that shows all CAN error messages with their finest details in human readable form. So, I have created hlcanerrdump. Quite a unique tool created with FreePascal. Enjoy!

Code: Pascal  [Select][+][-]
  1. ////////////////////////////////////////////////////////////////////////////////////////////////////
  2. //                                                                                                //
  3. //  hlcanerrdump utility to display SocketCAN error messages, by Zeljko Avramovic (c) 2021        //
  4. //                                                                                                //
  5. //  Dual license:                                                                                 //
  6. //  1. FPC modified LGPL (chosen for compatibility with FreePascal and Lazarus)                   //
  7. //  2. BSD3              (chosen for compatibility with everything else)                          //
  8. //                                                                                                //
  9. //  Virtual CAN adapter vcan0 is hard coded and you can bring it up like this:                    //
  10. //  sudo modprobe vcan                                                                            //
  11. //  sudo ip link add dev vcan0 type vcan                                                          //
  12. //  sudo ip link set vcan0 mtu 72              # needed for CAN FD                                //
  13. //  sudo ip link set vcan0 up                                                                     //
  14. //                                                                                                //
  15. //  To simulate error messages use hlcanerrsim utility like this:                                 //
  16. //  ./hlcanerrsim LostArbitrationBit=09 TX BusOff Data7=AA Data6=BB                               //
  17. //                                                                                                //
  18. //  That should show in hlcanerrdump utility as:                                                  //
  19. //  0x04A [8] 16 00 80 00 00 00 BB AA  ERR=LostArbitrationBit09,BusOff,Prot(Type(TX),Loc(Unspec)) //
  20. //                                                                                                //
  21. //  Alternatively, you could use candump from can-utils to check error messages like this:        //
  22. //  candump -s -c -c -x -a any,0~0,#FFFFFFFF                                                      //
  23. //                                                                                                //
  24. ////////////////////////////////////////////////////////////////////////////////////////////////////
  25.  
  26. program hlcanerrdump; // dump CAN error messages
  27.  
  28. {$mode delphi} {$H+}
  29.  
  30. uses
  31.   classes, sysutils, strutils, sockets, baseunix, can, can.hl, can.raw, can.error, crt;
  32.  
  33. procedure perror(const S : string);
  34. begin
  35.   WriteLn(S, ', SocketError = ', SocketError);
  36. end;
  37.  
  38. var
  39.   i, BytesNo:   integer;
  40.   CanHandle:    TCanHandle;
  41.   CanAddress:   TCanSockAddress;
  42.   CanInterface: TCanIFreq;
  43.   CanFrame:     TCanFrame;
  44.   CanMask:      TCanErrMask;
  45.   CanFilter:    TCanFilter;
  46.   SockOpt:      cint;
  47.   ErrFlagStr:   string;
  48.   Errors:       TStringList;
  49. begin
  50.   try
  51.     try
  52.       WriteLn('CAN Sockets Error Messages Dump. Waiting for errors...');
  53.       Errors    := TStringList.Create;
  54.       CanHandle := CanSocket(SOCK_RAW, CAN_RAW);
  55.       if CanHandle < 0 then
  56.       begin
  57.         perror('Socket');
  58.         Exit;
  59.       end;
  60.  
  61.       CanInterface.Name := 'vcan0';
  62.       if CanIOCtl(CanHandle, SIOCGIFINDEX, CanInterface) < 0 then
  63.       begin
  64.         perror('IOctl');
  65.         Exit;
  66.       end;
  67.  
  68.       CanAddress.Clear;
  69.       CanAddress.CanFamily  := AF_CAN;
  70.       CanAddress.CanIfIndex := CanInterface.IfIndex;
  71.  
  72.       if CanBind(CanHandle, CanAddress) < 0 then
  73.       begin
  74.         perror('Bind');
  75.         Exit;
  76.       end;
  77.  
  78.       CanFilter.ID.InverseFilter              := true; // no normal CAN frames
  79.       CanFilter.Mask.Full                     := 0;    // inverting nothing gives us everything
  80.       // CanFilter.Mask.Error.LostArbitration := true; // you might want to exclude arbitration errors
  81.       CanSetSockOpt(CanHandle, SOL_CAN_RAW, CAN_RAW_FILTER, CanFilter, SizeOf(CanFilter));
  82.  
  83.       CanMask.ERR := true;                // only error frames
  84.       CanSetSockOpt(CanHandle, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, CanMask, SizeOf(CanMask));
  85.  
  86.       SockOpt := CanFcntl(CanHandle, F_GETFL);                        // get socket options
  87.       if SockOpt < 0 then
  88.       begin
  89.         perror('CanFcntl: Error = ' + CanGetErrNo.ToString);
  90.         Exit;
  91.       end;
  92.  
  93.       if CanFcntl(CanHandle, F_SETFL, SockOpt or O_NONBLOCK) < 0 then // set nonblock socket (to be able to exit after key press)
  94.       begin
  95.         perror('NonBlock: Error = ' + CanGetErrNo.ToString);
  96.         Exit;
  97.       end;
  98.  
  99.       repeat
  100.         BytesNo := CanRead(CanHandle, CanFrame);
  101.         if BytesNo = SizeOf(CanFrame) then
  102.         begin
  103.           Write(Format(IfThen(CanFrame.ID.EFF, '0x%08.8X [%d] ', '     0x%03.3X [%d] '), [CanFrame.ID.Value, CanFrame.DLC])); // extended or standard frame
  104.           for i := 0 to CanFrame.DLC - 1 do
  105.             Write(Format('%02.2X ', [CanFrame.Data[i]]));
  106.  
  107.           Errors.Clear;
  108.           if CanFrame.ID.Mask.Error.TxTimeout       then Errors.Add('TxTimeout');
  109.           if CanFrame.ID.Mask.Error.LostArbitration then Errors.Add('LostArbitrationBit' + Format('%.*d', [2, CanFrame.DataError.LostArbitration.BitNumber]));
  110.           if CanFrame.ID.Mask.Error.NoAck           then Errors.Add('NoAck');
  111.           if CanFrame.ID.Mask.Error.BusOff          then Errors.Add('BusOff');
  112.           if CanFrame.ID.Mask.Error.BusError        then Errors.Add('BusError');
  113.           if CanFrame.ID.Mask.Error.Restarted       then Errors.Add('Restarted');
  114.           if CanFrame.ID.Mask.Error.Controller      then
  115.           begin
  116.             ErrFlagStr := '';
  117.             if CanFrame.DataError.Controller.OverflowRX then ErrFlagStr := ErrFlagStr + 'OverflowRX,';
  118.             if CanFrame.DataError.Controller.OverflowTX then ErrFlagStr := ErrFlagStr + 'OverflowTX,';
  119.             if CanFrame.DataError.Controller.WarningRX  then ErrFlagStr := ErrFlagStr + 'WarningRX,';
  120.             if CanFrame.DataError.Controller.WarningTX  then ErrFlagStr := ErrFlagStr + 'WarningTX,';
  121.             if CanFrame.DataError.Controller.PassiveRX  then ErrFlagStr := ErrFlagStr + 'PassiveRX,';
  122.             if CanFrame.DataError.Controller.PassiveTX  then ErrFlagStr := ErrFlagStr + 'PassiveTX,';
  123.             if CanFrame.DataError.Controller.Active     then ErrFlagStr := ErrFlagStr + 'Active';
  124.             if ErrFlagStr.EndsWith(',') then SetLength(ErrFlagStr, ErrFlagStr.Length - 1);
  125.             Errors.Add('Ctrl(' + ErrFlagStr + ')');
  126.           end;
  127.           if CanFrame.ID.Mask.Error.Protocol        then
  128.           begin
  129.             ErrFlagStr := 'Type(';
  130.             if CanFrame.DataError.Protocol.Category.SingleBit          then ErrFlagStr := ErrFlagStr + 'SingleBit,';
  131.             if CanFrame.DataError.Protocol.Category.FrameFormat        then ErrFlagStr := ErrFlagStr + 'FrameFormat,';
  132.             if CanFrame.DataError.Protocol.Category.BitStuffing        then ErrFlagStr := ErrFlagStr + 'BitStuffing,';
  133.             if CanFrame.DataError.Protocol.Category.Bit0               then ErrFlagStr := ErrFlagStr + 'Bit0,';
  134.             if CanFrame.DataError.Protocol.Category.Bit1               then ErrFlagStr := ErrFlagStr + 'Bit1,';
  135.             if CanFrame.DataError.Protocol.Category.BusOverload        then ErrFlagStr := ErrFlagStr + 'BusOverload,';
  136.             if CanFrame.DataError.Protocol.Category.ActiveAnnouncement then ErrFlagStr := ErrFlagStr + 'ActiveAnnouncement,';
  137.             if CanFrame.DataError.Protocol.Category.TX                 then ErrFlagStr := ErrFlagStr + 'TX';
  138.             if ErrFlagStr.EndsWith(',') then SetLength(ErrFlagStr, ErrFlagStr.Length - 1);
  139.             ErrFlagStr := ErrFlagStr + '),Loc(';
  140.             case CanFrame.DataError.Protocol.Location of
  141.               CAN_ERR_PROT_LOC_UNSPEC:     ErrFlagStr := ErrFlagStr + 'Unspec';  // zero
  142.               CAN_ERR_PROT_LOC_SOF:        ErrFlagStr := ErrFlagStr + 'SOF';     // start of frame
  143.               CAN_ERR_PROT_LOC_ID28_21:    ErrFlagStr := ErrFlagStr + 'ID28_21'; // ID bits 28 - 21 (SFF: 10 - 3)
  144.               CAN_ERR_PROT_LOC_ID20_18:    ErrFlagStr := ErrFlagStr + 'ID20_18'; // ID bits 20 - 18 (SFF: 2 - 0 )
  145.               CAN_ERR_PROT_LOC_SRTR:       ErrFlagStr := ErrFlagStr + 'SRTR';    // substitute RTR (SFF: RTR)
  146.               CAN_ERR_PROT_LOC_IDE:        ErrFlagStr := ErrFlagStr + 'IDE';     // identifier extension
  147.               CAN_ERR_PROT_LOC_ID17_13:    ErrFlagStr := ErrFlagStr + 'ID17_13'; // ID bits 17-13
  148.               CAN_ERR_PROT_LOC_ID12_05:    ErrFlagStr := ErrFlagStr + 'ID12_05'; // ID bits 12-5
  149.               CAN_ERR_PROT_LOC_ID04_00:    ErrFlagStr := ErrFlagStr + 'ID04_00'; // ID bits 4-0
  150.               CAN_ERR_PROT_LOC_RTR:        ErrFlagStr := ErrFlagStr + 'RTR';     // RTR
  151.               CAN_ERR_PROT_LOC_RES1:       ErrFlagStr := ErrFlagStr + 'RES1';    // reserved bit 1
  152.               CAN_ERR_PROT_LOC_RES0:       ErrFlagStr := ErrFlagStr + 'RES0';    // reserved bit 0
  153.               CAN_ERR_PROT_LOC_DLC:        ErrFlagStr := ErrFlagStr + 'DLC';     // data length code
  154.               CAN_ERR_PROT_LOC_DATA:       ErrFlagStr := ErrFlagStr + 'DATA';    // data section
  155.               CAN_ERR_PROT_LOC_CRC_SEQ:    ErrFlagStr := ErrFlagStr + 'CRC_SEQ'; // CRC sequence
  156.               CAN_ERR_PROT_LOC_CRC_DEL:    ErrFlagStr := ErrFlagStr + 'CRC_DEL'; // CRC delimiter
  157.               CAN_ERR_PROT_LOC_ACK:        ErrFlagStr := ErrFlagStr + 'ACK';     // ACK slot
  158.               CAN_ERR_PROT_LOC_ACK_DEL:    ErrFlagStr := ErrFlagStr + 'ACK_DEL'; // ACK delimiter
  159.               CAN_ERR_PROT_LOC_EOF:        ErrFlagStr := ErrFlagStr + 'EOF';     // end of frame
  160.               CAN_ERR_PROT_LOC_INTERM:     ErrFlagStr := ErrFlagStr + 'INTERM';  // intermission
  161.             otherwise
  162.               ErrFlagStr := ErrFlagStr + 'Unknown';   // protocol location not recognized
  163.             end;
  164.             Errors.Add('Prot(' + ErrFlagStr + '))');
  165.           end;
  166.           if CanFrame.ID.Mask.Error.Transceiver then
  167.           begin
  168.             ErrFlagStr := '';
  169.             case CanFrame.DataError.Transceiver of
  170.               CAN_ERR_TRX_UNSPEC:              ErrFlagStr := ErrFlagStr + 'Unspec';            // $00, 0000 0000
  171.               CAN_ERR_TRX_CANH_NO_WIRE:        ErrFlagStr := ErrFlagStr + 'CanHiNoWire';       // $04, 0000 0100
  172.               CAN_ERR_TRX_CANH_SHORT_TO_BAT:   ErrFlagStr := ErrFlagStr + 'CanHiShortToBAT';   // $05, 0000 0101
  173.               CAN_ERR_TRX_CANH_SHORT_TO_VCC:   ErrFlagStr := ErrFlagStr + 'CanHiShortToVCC';   // $06, 0000 0110
  174.               CAN_ERR_TRX_CANH_SHORT_TO_GND:   ErrFlagStr := ErrFlagStr + 'CanHiShortToGND';   // $07, 0000 0111
  175.               CAN_ERR_TRX_CANL_NO_WIRE:        ErrFlagStr := ErrFlagStr + 'CanLoNoWire';       // $40, 0100 0000
  176.               CAN_ERR_TRX_CANL_SHORT_TO_BAT:   ErrFlagStr := ErrFlagStr + 'CanLoShortToBAT';   // $50, 0101 0000
  177.               CAN_ERR_TRX_CANL_SHORT_TO_VCC:   ErrFlagStr := ErrFlagStr + 'CanLoShortToVCC';   // $60, 0110 0000
  178.               CAN_ERR_TRX_CANL_SHORT_TO_GND:   ErrFlagStr := ErrFlagStr + 'CanLoShortToGND';   // $70, 0111 0000
  179.               CAN_ERR_TRX_CANL_SHORT_TO_CANH:  ErrFlagStr := ErrFlagStr + 'CanLoShortToCanHi'; // $80, 1000 0000
  180.             otherwise
  181.               ErrFlagStr := ErrFlagStr + 'Unknown'; // transceiver error not recognized
  182.             end;
  183.             Errors.Add('Trans(' + ErrFlagStr + ')');
  184.           end;
  185.  
  186.           if Errors.Count > 0 then
  187.             Write(' ERR=');
  188.  
  189.           for i := 0 to Errors.Count - 1 do
  190.           begin
  191.             Write(Errors.Strings[i]);
  192.             if i <> (Errors.Count - 1) then
  193.               Write(',');
  194.           end;
  195.           WriteLn('');
  196.         end;
  197.         Sleep(5);
  198.       until KeyPressed;
  199.  
  200.       if CanClose(CanHandle) < 0 then
  201.       begin
  202.         perror('Close');
  203.         Exit;
  204.       end;
  205.     except
  206.       on e: Exception do
  207.         WriteLn(e.Message);
  208.     end;
  209.   finally
  210.     Errors.Free;
  211.   end;
  212. end.
  213.  

Beta version attached here is tied to vcan0. Before I put it into FPC trunk I will make it accept CAN interface as a parameter.
Title: Re: CAN-BUS SocketCAN
Post by: avra on April 16, 2021, 02:29:25 pm
I have searched all the net and I could not find a single open source tool for simulating CAN error messages. None. Zero. So, I have created hlcanerrsim. A unique tool created with FreePascal. Enjoy!

UPDATE: Source exceeds single message limit, so you can find it in can.zip archive in previous message.
Title: Re: CAN-BUS SocketCAN
Post by: avra on April 28, 2021, 10:33:07 am
hlcanerrdump now accepts CAN interface as first parameter and CAN filter for error messages as further parameters. Especially useful example is to use IgnoreNoAck parameter for filtering NoAck messages.
Code: [Select]
avra@vm-debian:/mnt/e/can$ ./hlcanerrdump
CAN Sockets Error Messages Dump

Usage: hlcanerrdump <CAN interface> [options]

CAN interface:                   ( CAN interface is case sensitive )
    can1                         ( or can2, can3 or virtual ones like vcan0, vcan1...

Options:                         ( options are not case sensitive )
                                 ( ERROR CLASS (MASK) IN CAN ID: )
    IgnoreTxTimeout              ( filter TX timeout by netdevice driver error messages )
    IgnoreLostArbitration        ( filter lost arbitration error messages )
    IgnoreController             ( filter controller problem error messages )
    IgnoreProtocol               ( filter protocol error messages )
    IgnoreTransceiver            ( filter transceiver status error messages )
    IgnoreNoAck                  ( filter no ACK on transmission error messages )
    IgnoreBusOff                 ( filter bus off error messages )
    IgnoreBusError               ( filter bus error messages )
    IgnoreRestarted              ( filter controller restarted messages )
                                 ( DEBUG HELPERS: )
    ShowFilterAndMaskBits        ( display all filtering bits )

Examples:

    ./hlcanerrdump can1
    ( dump all CAN error messages from CAN interface can1 )

    ./hlcanerrdump vcan0 IgnoreNoAck IgnoreBusOff
    ( dump all CAN error messages from virtual CAN interface vcan0 except NoACk and BusOff)

hlcanerrsim now accepts CAN interface as first parameter. It still accepts error message types as parameters for forming simulated error messages.
Code: [Select]
avra@vm-debian:/mnt/e/can$ ./hlcanerrsim
CAN Sockets Error Messages Simulator

Usage: hlcanerrsim <CAN interface> [options]

CAN interface:                   ( CAN interface is case sensitive )
    can1                         ( or can2, can3 or virtual ones like vcan0, vcan1...

Options:                         ( options are not case sensitive )
                                 ( ERROR CLASS (MASK) IN CAN ID: )
    TxTimeout                    ( TX timeout by netdevice driver )
    NoAck                        ( received no ACK on transmission )
    BusOff                       ( bus off )
    BusError                     ( bus error, may flood! )
    Restarted                    ( controller restarted )
                                 ( ARBITRATIONLOST IN CAN ID + BIT NUMBER IN DATA[0]: )
    LostArbitrationBit=<00..29>  ( decimal bit number in bitstream )
                                 ( CONTROLLER IN CAN ID + ERROR STATUS IN DATA[1]: )
    OverflowRX                   ( RX buffer overflow )
    OverflowTX                   ( TX buffer overflow )
    WarningRX                    ( reached warning level for RX errors )
    WarningTX                    ( reached warning level for TX errors )
    PassiveRX                    ( reached error passive status RX, errors > 127 )
    PassiveTX                    ( reached error passive status TX, errors > 127 )
    Active                       ( recovered to error active state )
                                 ( PROTOCOL ERROR IN CAN ID + TYPE IN DATA[2]: )
    SingleBit                    ( single bit error )
    FrameFormat                  ( frame format error )
    BitStuffing                  ( bit stuffing error )
    Bit0                         ( unable to send dominant bit )
    Bit1                         ( unable to send recessive bit )
    BusOverload                  ( bus overload )
    ActiveAnnouncement           ( active error announcement )
    TX                           ( error occurred on transmission )
                                 ( PROTOCOL ERROR IN CAN ID + LOCATION IN DATA[3]: )
    SOF                          ( start of frame )
    ID28_21                      ( ID bits 21..28, SFF: 3..10 )
    ID20_18                      ( ID bits 18..20, SFF: 0..2 )
    SRTR                         ( substitute RTR, SFF: RTR )
    IDE                          ( identifier extension )
    ID17_13                      ( ID bits 13..17 )
    ID12_05                      ( ID bits 5..12 )
    ID04_00                      ( ID bits 0..4 )
    RTR                          ( RTR )
    RES1                         ( reserved bit 1 )
    RES0                         ( reserved bit 0 )
    DLC                          ( data length code )
    DATA                         ( data section )
    CRC_SEQ                      ( CRC sequence )
    CRC_DEL                      ( CRC delimiter )
    ACK                          ( ACK slot )
    ACK_DEL                      ( ACK delimiter )
    EOF                          ( end of frame )
    INTERM                       ( intermission )
                                 ( TRANSCEIVER ERROR IN CAN ID + STATUS IN DATA[4]: )
                                 ( CANH CANL )
    TransUnspec                  ( 0000 0000 )
    CanHiNoWire                  ( 0000 0100 )
    CanHiShortToBAT              ( 0000 0101 )
    CanHiShortToVCC              ( 0000 0110 )
    CanHiShortToGND              ( 0000 0111 )
    CanLoNoWire                  ( 0100 0000 )
    CanLoShortToBAT              ( 0101 0000 )
    CanLoShortToVCC              ( 0110 0000 )
    CanLoShortToGND              ( 0111 0000 )
    CanLoShortToCanHi            ( 1000 0000 )
                                 ( CUSTOM BYTE TO DATA[0..7]: )
    Data<0..7>=<00..FF>          ( write hex number to one of 8 payload bytes )

Examples:

    ./hlcanerrsim can1 LostArbitrationBit=09 TX BusOff Data7=AA Data6=BB
    ( can1: 9th arb. bit lost, transmission, bus off, controller specific info in Data[6] and Data[7] )

    ./hlcanerrsim vcan0 NoAck TxTimeout Active
    ( vcan0: received no ACK on transmission, driver timeout, protocol type active error announcement )

    ./hlcanerrsim vcan0 BusError CanHiNoWire Restarted INTERM
    ( vcan0: bus error, lost CANH wiring, controller restarted, protocol location intermission )
Title: Re: CAN-BUS SocketCAN
Post by: ThomasK on May 15, 2021, 02:40:45 pm
Hello Avra,

is there already a way to perform the actions which the 'ip' command does in pascal?

like "sudo ip link set can0 type can bitrate 125000 sample-point 0.875"
and "sudo ip link set can0 up"
and "sudo ip link set can0 down"?

I got the Inno-Maker CAN RS485 HAT to work with my test gear from PEAK and don't want to do work which is already done.....

Cheers,

Thomas
Title: Re: CAN-BUS SocketCAN
Post by: avra on May 16, 2021, 02:35:31 am
is there already a way to perform the actions which the 'ip' command does in pascal?

like "sudo ip link set can0 type can bitrate 125000 sample-point 0.875"
and "sudo ip link set can0 up"
and "sudo ip link set can0 down"?
Calling ip command from your pascal application and parsing the output would be the simplest solution. If you are not satisfied with that, you would have to use NETLINK sockets, since that is what ip command uses. Alternatively, you could use libsocketcan (a wrapper around netlink sockets for CAN) or libnl, but you would need to make your own wrapper.

https://lalten.github.io/libsocketcan/Documentation/html/group__extern.html#gaa01e52bcb6f4b873da7ce32cab38332d
https://github.com/jmore-reachtech/can-utils/blob/master/src/canconfig.c
https://www.infradead.org/~tgr/libnl/doc/api/group__can.html#gab6de57cdb6c42d48df432636e266700b
Title: Re: CAN-BUS SocketCAN
Post by: ThomasK on May 16, 2021, 10:45:20 am
Thanks.

Well, it seems that due to the 'C' in CAN most code is written in C >:(
Title: Re: CAN-BUS SocketCAN wrapper for libsocketcan
Post by: ThomasK on May 16, 2021, 03:03:41 pm
Hi,

I installed the library and am trying to call it.
Code: Pascal  [Select][+][-]
  1. unit LibSockCAN;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. //lib/arm-linux-gnueabihf/libsocketcan.so
  8. //libsocketcan.h
  9.  
  10. {$linklib c}
  11. {$linklib libsocketcan}
  12.  
  13. //function can_do_restart                   : longint; cdecl; external;
  14. function can_do_stop(const pchar)           : longint; cdecl; external;
  15. function can_do_start(const pchar)          : longint; cdecl; external;
  16. //function can_set_bitrate                  : longint; cdecl; external;
  17. //function can_set_bitrate_samplepoint      : longint; cdecl; external;
  18.  
  19. //uses
  20.  
  21. implementation
  22.  
  23.  
  24. end.
  25.  

The call is done as reaction to a Button:

Code: Pascal  [Select][+][-]
  1.  
  2. procedure TForm1.B_StartCan0Click(Sender: TObject);
  3. var
  4.   ifr_name : PChar;
  5.   myresult : integer;
  6. begin
  7.   ifr_name:= 'can0';
  8.   myresult:=can_do_start(ifr_name);
  9.   Label_StartResult.caption:=InttoStr(myresult);
  10. end;

No errors during compilation, but return code is -1.
Where is my error?

btw. the CAN-UTILS and the ip commands work
Title: Re: CAN-BUS SocketCAN
Post by: avra on May 16, 2021, 03:32:39 pm
Thanks.
You're welcome.  :)

it seems that due to the 'C' in CAN most code is written in C >:(
Well, Linux kernel 2.6.25 with first SocketCAN implementation was donated by Volkswagen in 2008, so besides much wider user base C also has about 13 years advantage - although we already have some unique and pretty useful error dump and error simulation tools. With FreePascal wrapper all SocketCAN code can be easily transferred with almost 1:1 translation. Just take a look at demos which do not start with hl prefix in their name. They are in Pascal but they look almost identical to their C roots. If you take a look at canconfig.c that I mentioned in previous post, you will see that besides SocketCAN (that is already part of the kernel) only libsocketcan is used additionally. So, if you create a libsocketcan wrapper then it should not be too hard to do an almost 1:1 translation, or extract just parts which you need for CAN setup in code. If that is too much, then you can always run ip command in a process and parse the output.

According to my free time, plan is to support J1939 (trucks, buses, heavy machinery, marine, military and agriculture), OBD-II (cars) and DBC file parsing (for automatic conversion of CAN messages to human readable form). If in the mean time I get some CANopen (plc, industrial automation, embedded) freelance work then I might consider supporting CANopen as well. For now, there is no plan to support libsocketcan.

UPDATE:

No errors during compilation, but return code is -1.
Where is my error?
I am not familiar with internals of libsocketcan so I can not tell. If I had to guess then I would first try to replace
Code: Pascal  [Select][+][-]
  1. ifr_name:= 'can0';
with
Code: Pascal  [Select][+][-]
  1. ifr_name:= 'can0' + #0;
If that doesn't work, then I would try to create the most simplest code in C which does the job, and then try to convert that to FreePascal with already mentioned 1:1 conversion method. That would eliminate a lot of unknowns of what works and what doesn't.

Ah, yes... You should also try to start your app as root, and check if can0 is not already started.
Title: Re: CAN-BUS SocketCAN
Post by: ThomasK on May 16, 2021, 04:25:03 pm
Adding the #0 to the devince name changed nothing.

Title: Re: CAN-BUS SocketCAN
Post by: dseligo on May 16, 2021, 11:40:48 pm
According to my free time, plan is to support J1939 (trucks, buses, heavy machinery, marine, military and agriculture), OBD-II (cars) and DBC file parsing (for automatic conversion of CAN messages to human readable form). If in the mean time I get some CANopen (plc, industrial automation, embedded) freelance work then I might consider supporting CANopen as well. For now, there is no plan to support libsocketcan.

What device(s) do you use to interface with CAN bus?
Title: Re: CAN-BUS SocketCAN
Post by: avra on May 17, 2021, 12:44:51 am
What device(s) do you use to interface with CAN bus?
Pi, PocketBeagle and Arduino (AVR, STM32, ESP32)
Title: Re: CAN-BUS SocketCAN
Post by: dseligo on May 17, 2021, 02:54:14 pm
What device(s) do you use to interface with CAN bus?
Pi, PocketBeagle and Arduino (AVR, STM32, ESP32)

Does Arduino (AVR) has to be some specific type (e.g. AT90CAN128) or any will do?
What do you use between 'controller' and CAN bus?
Title: Re: CAN-BUS SocketCAN
Post by: Blade on May 17, 2021, 03:23:15 pm
This thread mentions C to Pascal translation several times.  I'm wondering if this is not also an opportunity to test out some of the automatic C to Pascal or C to Delphi translators.  Probably wouldn't be as good as being done manually by someone very fluent in both, but perhaps the automatic software could be useful in various cases.
Title: Re: CAN-BUS SocketCAN
Post by: avra on May 18, 2021, 12:58:09 am
What device(s) do you use to interface with CAN bus?
Pi, PocketBeagle and Arduino (AVR, STM32, ESP32)

Does Arduino (AVR) has to be some specific type (e.g. AT90CAN128) or any will do?
What do you use between 'controller' and CAN bus?

You can use some CAN based AVR as AT90CAN128 with just a TJA1050 or similar CAN transceiver, but it is more common to use simpler AVR (like ATMEGA328P) with MCP2515 and some CAN transceiver chip as MCP is much better supported. Using MCP2515 also means that besides using CAN directly from AVR, you can also use it from Linux as Lawicel/SLCAN based CAN gateway for SocketCAN with something like this: https://github.com/latonita/arduino-canbus-monitor, https://github.com/autowp/can-usb or https://github.com/mintynet/nano-can. You are limited with serial to USB chip speed on your Arduino so with speeds of 500kbps and higher expect dropped frames (and even with 250kbps if your CAN bus load is high). Although MCP2515 is the most supported CAN 2.0B chip on the planet, if you need CAN FD then it will not be enough and you will have to use MCP2518 and similar with a proper lib.

Although ESP32 is much more capable then standard AVRs, there is also a serial to USB chip so there is the same speed limit. It has internal CAN so there are libs which do not need MCP2515 to implement Lawicel/SLCAN which can be used from Linux SocketCAN. I have seen versions which use Bluetooth instead of serial to USB, but I have never tested them (https://github.com/michey/esp32_can and https://github.com/mintynet/esp32-slcan). There are also versions which support CAN FD and create a WiFi UDP tunnel to Linux SocketCAN via cannelloni protocol (https://github.com/PhilippFux/ESP32_CAN_Interface and https://github.com/epozzobon/lasagne), but I haven't tested them either.

STM32 has many microcontrollers (like STM32F103C8T6 BluePill for example) which support CAN out of the box and do not need MCP2515. They also have USB but unfortunately USB and CAN can not work at the same time, so some serial to USB must also be used. Look at https://github.com/kolyandex/CAN-to-USB-lawicel-for-stm32, https://github.com/GBert/misc/tree/master/stm32-slcan, https://github.com/geier99/STM32-CAN_CubeMX_Tests, https://github.com/darauble/lawicel-slcan, http://randomport.com/pages/usb-to-can.html and https://ucandevices.github.io.

Most of the mentioned devices can be used as very cheap Lawicel/SLCAN compatible protocol CAN gateways for Linux SocketCAN, but I personally do not use them for that. I use them as embedded devices when Linux SBC is an overkill or when long booting can not be tolerated. What is good about such Lawicel/SLCAN protocol compatible devices is that there is a lot of software for Windows that can use them, so that will be your CAN path if you are not a Linux fan. However, Linux SocketCAN path is much more powerful and standardized so unlike with Windows various software can work together using data simultaneously from the same CAN adapter.

Raspberry Pi needs a HAT with MCP2515/2517/2518. PocketBeagle and BeagleBone can also use MCP, but if you do not need CAN FD then built in CAN with some transceiver will be enough. There is no speed limit or dropped frames problem with Linux boards, so you can use SocketCAN at it's full glory.

SocketCAN also supports virtual CAN channels so you can play and learn even if you have no CAN adapter at all.

For a simple introduction to CAN, CAN FD, OBD-II, CANopen and J1939 take a look at these links:
https://www.csselectronics.com/screen/page/simple-intro-to-can-bus
https://www.csselectronics.com/screen/page/can-fd-flexible-data-rate-intro
https://www.csselectronics.com/screen/page/simple-intro-obd2-explained
https://www.csselectronics.com/screen/page/simple-intro-j1939-explained
https://www.csselectronics.com/screen/page/canopen-tutorial-simple-intro

Here is also a little old but still relevant Car Hacker's Handbook:
http://www.opengarages.org/handbook/

This thread mentions C to Pascal translation several times.  I'm wondering if this is not also an opportunity to test out some of the automatic C to Pascal or C to Delphi translators.  Probably wouldn't be as good as being done manually by someone very fluent in both, but perhaps the automatic software could be useful in various cases.
I use these all the time. They are good, but not perfect and I usually have to combine them. They can save you a lot of time, but can not save you from manual work completelly.
https://forum.lazarus.freepascal.org/index.php/topic,12763.msg66330.html#msg66330
https://forum.lazarus.freepascal.org/index.php/topic,53389.msg395085.html#msg395085
https://wiki.freepascal.org/C_to_Pascal
Title: Re: CAN-BUS SocketCAN
Post by: dseligo on May 18, 2021, 04:38:36 am
Thanks  :D

I will need some time to process this  :)
Title: Re: CAN-BUS SocketCAN
Post by: ThomasK on May 19, 2021, 01:24:21 pm
For now, there is no plan to support libsocketcan.

I see.

Anyway for my point of view it is better if an application takes care itself of all relevant initialisation and parameterisation tasks.
At least I am used to that working with an automation system for automotive test beds. Customers always complained to if they need more than one program to get an interface working.

I also found a fork of can-utils containing canconfig.c with a more recent date than 2009. 8). I will try to get short snippets to work, as you proposed and migrate then.

I tested my short app by starting it with admin rights, it failed too. Didn't find the file, it said in the console.
Title: Re: CAN-BUS SocketCAN
Post by: ThomasK on May 30, 2021, 10:07:21 pm
Have you intentions to implement this:

Code: C  [Select][+][-]
  1. num_events = epoll_wait(fd_epoll, events_pending, currmax, timeout_ms);
  2.                 if (num_events == -1) {
  3.                         if (errno != EINTR)
  4.                                 running = 0;
  5.                         continue;
  6.                 }
  7.  

This would allow a read process not to wait until data is available.

I found that in the recent can-utils.
Title: Re: CAN-BUS SocketCAN
Post by: avra on May 31, 2021, 01:30:08 am
I found that in the recent can-utils.
Not everything is related to CAN. If you take a look at candump.c from can-utils you will see that it includes sys/epoll.h which is a standard linux header for which there is a man page https://linux.die.net/man/2/epoll_wait. As such, you could also search your fpc directory and find that translation for epoll_wait can already be found in your existing \fpcsrc\rtl\linux\linux.pp, so you already have everything needed.

You need to improve your source search fu a little, if you want the source to be with you.  :D ;) :D
Title: Re: CAN-BUS SocketCAN
Post by: ThomasK on May 31, 2021, 02:46:54 pm
I know that this is not only CAN related.
But this code snippet is from the latest https://github.com/linux-can/can-utils (https://github.com/linux-can/can-utils) candump.c.

I try to get this to work.
Title: Re: CAN-BUS SocketCAN
Post by: ThomasK on June 03, 2021, 01:20:16 pm
@avra, I have put yor sent & transmit code together with the epoll routines from the latest candump.c into a GUI app for Lazarus.

It works principally, I can send, receive, see that there is data after calling epoll_wait.

But the num_events is always either 0 or 1 even if more than 1 message was sent to the port.
Code: Pascal  [Select][+][-]
  1. unit mainunit;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, sockets, baseunix, can, linux;
  9.  
  10. type
  11.  
  12.   { TFCANTest }
  13.  
  14.   TFCANTest = class(TForm)
  15.     bInitcan0: TButton;
  16.     bSendData: TButton;
  17.     bReceiveData: TButton;
  18.     BClosecan0: TButton;
  19.     bEpollCreate: TButton;
  20.     bEpollQuery: TButton;
  21.     mLog: TMemo;
  22.     mLogTest: TMemo;
  23.     STnum_events: TStaticText;
  24.     STevents_pending: TStaticText;
  25.     StaticText3: TStaticText;
  26.     StaticText4: TStaticText;
  27.     procedure BClosecan0Click(Sender: TObject);
  28.     procedure bEpollCreateClick(Sender: TObject);
  29.     procedure bEpollQueryClick(Sender: TObject);
  30.     procedure bInitcan0Click(Sender: TObject);
  31.     procedure bReceiveDataClick(Sender: TObject);
  32.     procedure bSendDataClick(Sender: TObject);
  33.     procedure FormCreate(Sender: TObject);
  34.  
  35.   private
  36.     procedure Addmessages(mess2show: string);
  37.  
  38.   public
  39.  
  40.   end;
  41.  
  42.  
  43. const
  44.   AF_CAN = 29;
  45.   PF_CAN = 29;
  46.   CANDevice ='can0';
  47. type
  48. if_info = record
  49.   s            : integer;
  50.   cmdlinename  : ^byte;
  51.   dropcnt,
  52.   last_dropcnt : uint32;
  53. end;
  54. {
  55. type
  56.   EPoll_Data = record
  57.     case integer of
  58.       0: (ptr: pointer);
  59.       1: (fd: cint);
  60.       2: (u32: cuint);
  61.       3: (u64: cuint64);
  62.   end;
  63.   TEPoll_Data =  Epoll_Data;
  64.   PEPoll_Data = ^Epoll_Data;
  65.   EPoll_Event = record
  66.     Events: cuint32;
  67.     Data  : TEpoll_Data;
  68.   end;
  69.  
  70.   TEPoll_Event =  Epoll_Event;
  71.   PEpoll_Event = ^Epoll_Event;
  72. }
  73. var
  74.   FCANTest       : TFCANTest;
  75.   sock_info      : if_info;
  76.   events_pending : EPoll_Event;
  77.   event_setup    : EPoll_Event;
  78.   Pevent_Setup   : PEPoll_Event;
  79.   PPoll_Event    : PEPoll_Event;
  80.   fd_epoll,
  81.   num_events,
  82.   currmax        : integer;
  83.   s:     cint;
  84.   addr:  sockaddr_can;
  85.   ifr:   ifreq;
  86.   frame: can_frame;
  87.   timeout_ms : integer; //* default to no timeout */
  88.  
  89. implementation
  90.  
  91. {$R *.lfm}
  92.  
  93. { TFCANTest }
  94. procedure TFCANTest.Addmessages(mess2show: string);
  95. begin
  96.   mLogtest.Lines.BeginUpdate;
  97.   mLogtest.Lines.Add(mess2show);
  98.   mLogtest.Lines.EndUpdate;
  99.   mLogtest.SelStart := Length(mLogtest.Lines.Text)-1;
  100.   mLogtest.SelLength:=0;
  101. end;
  102.  
  103. procedure TFCANTest.FormCreate(Sender: TObject);
  104. begin
  105.   currmax            :=16;                                                       // number of CAN devices
  106.   event_setup.events :=EPOLLIN;
  107.   Pevent_Setup       :=@(event_setup);
  108.   PPoll_event        :=@(events_pending);
  109.   timeout_ms         :=10;
  110.   bInitcan0.caption  :=bInitcan0.caption + ' ' + CANDevice;
  111.   bClosecan0.caption  :=bclosecan0.caption + ' ' + CANDevice;
  112. end;
  113.  
  114. procedure TFCANTest.bInitcan0Click(Sender: TObject);
  115. var
  116.   perror : string;
  117. begin
  118.   s := fpsocket(PF_CAN, SOCK_RAW, CAN_RAW);
  119.   if s < 0 then
  120.   begin
  121.     perror:='socket creation error';
  122.     mLog.Lines.Add(perror);
  123.     Addmessages(perror);
  124.     Exit;
  125.   end else begin
  126.      mLog.Lines.Add('Socket: '+inttostr(s));
  127.      Addmessages('Socket: '+inttostr(s));
  128.   end;
  129.   strcopy(ifr.ifr_name, CANDevice);
  130.   if fpioctl(s, SIOCGIFINDEX, @ifr) < 0 then
  131.   begin
  132.     perror:='error IOctl';
  133.     mLog.Lines.Add(perror);
  134.     Addmessages(perror);
  135.     Exit;
  136.   end;
  137.   memset(@addr, 0, sizeof(addr));
  138.   addr.can_family  := AF_CAN;
  139.   addr.can_ifindex := ifr.ifr_ifindex;
  140.   if fpbind(s, @addr, sizeof(addr)) < 0 then // if fpbind(s, Psockaddr(@addr), sizeof(addr)) < 0 then
  141.   begin
  142.     perror:='error bind';
  143.     mLog.Lines.Add(perror);
  144.     Addmessages(perror);
  145.     Exit;
  146.   end;
  147. end;
  148.  
  149. procedure TFCANTest.bReceiveDataClick(Sender: TObject);
  150. var
  151.   nbytes,
  152.   i      : integer;
  153.   perror : string;
  154. begin
  155.     nbytes := fpread(s, frame, sizeof(can_frame));
  156.     if nbytes < 0 then
  157.     begin
  158.       perror:='Error during Read';
  159.       mLog.Lines.Add(perror);
  160.       Addmessages(perror);
  161.       Exit;
  162.     end;
  163.     if nbytes < sizeof(can_frame) then // paranoid check
  164.     begin
  165.       perror:='Read: Incomplete CAN frame';
  166.       mLog.Lines.Add(perror);
  167.       Addmessages(perror);
  168.       Exit;
  169.     end;
  170.     Perror:=Format('0x%03X [%d] ', [frame.can_id and CAN_SFF_MASK, frame.can_dlc]);
  171.     for i := 0 to frame.can_dlc - 1 do
  172.       Perror:=Perror + Format('%02.2X ', [frame.data[i]]);
  173.     mLog.Lines.Add(perror);
  174.     Addmessages(perror);
  175. end;
  176.  
  177. procedure TFCANTest.bSendDataClick(Sender: TObject);
  178. var
  179.   perror : string;
  180.   psizef : integer;
  181. begin
  182.   frame.can_id   := $020;    // CAN message ID
  183.   frame.can_dlc  := 8;       // payload length will be 8 bytes
  184.   frame.data[0]  := $10;
  185.   frame.data[1]  := $11;
  186.   frame.data[2]  := $12;
  187.   frame.data[3]  := $13;
  188.   frame.data[4]  := $14;
  189.   frame.data[5]  := $15;
  190.   frame.data[6]  := $16;
  191.   frame.data[7]  := $17;
  192.  
  193. psizef:= fpwrite(s, frame, sizeof(can_frame));
  194. if psizef <> sizeof(can_frame) then
  195.   begin
  196.     perror:='error write ' + InttoStr(psizef);
  197.     mLog.Lines.Add(perror);
  198.     Addmessages(perror);
  199.     Exit;
  200.   end else begin
  201.     mLog.Lines.Add(InttoStr(psizef) + ' bytes written');
  202.     Addmessages(InttoStr(psizef) + ' bytes written');
  203.   end;
  204. end;
  205.  
  206. procedure TFCANTest.BClosecan0Click(Sender: TObject);
  207. var
  208.   perror : string;
  209. begin
  210.   if fpclose(s) < 0 then
  211.     begin
  212.       perror:='error close socket ';
  213.       mLog.Lines.Add(perror);
  214.       Addmessages(perror);
  215.       Exit;
  216.     end;
  217.   if fpclose(fd_epoll) < 0 then
  218.     begin
  219.       perror:='error close epoll ';
  220.       mLog.Lines.Add(perror);
  221.       Addmessages(perror);
  222.       Exit;
  223.     end;
  224. end;
  225.  
  226. procedure TFCANTest.bEpollCreateClick(Sender: TObject);
  227. var
  228.   pepollerr : integer;
  229. begin
  230.   fd_epoll := epoll_create(1);
  231.   if fd_epoll < 0 then begin
  232.     mLog.Lines.Add('epoll create error');
  233.     Addmessages('epoll create error');
  234.     Exit;
  235.   end;
  236.   pepollerr:= epoll_ctl(fd_epoll, EPOLL_CTL_ADD, s, pevent_setup);
  237.   if pepollerr< 0 then begin
  238.     mLog.Lines.Add(IntTostr(pepollerr)+ ' epoll add to socket error');
  239.     Addmessages(IntTostr(pepollerr)+ ' epoll add to socket error');
  240.     Exit;
  241.   end;
  242. end;
  243.  
  244. procedure TFCANTest.bEpollQueryClick(Sender: TObject);
  245. begin
  246.   num_events := epoll_wait(fd_epoll, PPoll_event, currmax, timeout_ms);
  247.   STnum_events.caption:= IntToStr(num_events);
  248.   STevents_pending.caption:=IntToStr(PPoll_event^.Events);
  249. end;
  250.  
  251.  
  252. end.
  253.  

This would be sufficient, because it can prevent that the read routine gets stuck if there is nothing to read.

But the candump repeats the reads as often as num_events.... may be not, because when it is fast enough it sees only one telegram.
Title: Re: CAN-BUS SocketCAN
Post by: ThomasK on June 04, 2021, 01:23:17 pm
update.

ip commands added

{$i can.ioctl.inc}
{$i can.if.inc}
{$i can.sockios.inc}   included in zip.

epoll_wait delivers a '1' if the file descriptor has an EPOLLIN event. After all data is read, this returns to 0.

btw. runs on a Raspberry Pi 4 with inno maker dual RS485 and CAN Module, both isolated.
Other CAN device is attached to a W10 laptop. (Peak USB)
Maybe I try to get the USB-CAN running with a virtual machine on the laptop.
Title: Re: CAN-BUS SocketCAN
Post by: avra on June 05, 2021, 05:19:46 pm
But the num_events is always either 0 or 1 even if more than 1 message was sent to the port.
I am in the middle of industrial plant commissioning, so I will not be able to take a look at this before next week.
Title: Re: CAN-BUS SocketCAN
Post by: ThomasK on June 06, 2021, 08:48:10 am
I am in the middle of industrial plant commissioning, so I will not be able to take a look at this before next week.

Thanks.
But I think the num_events as result of epoll_wait is not increased with number of events per input, but with number of inputs having an event.

If only one input is polled it can simply be seen as „true“ for having data to read, if the only event type is EPOLLIN.
Title: Re: CAN-BUS SocketCAN
Post by: ThomasK on June 08, 2021, 10:19:01 am
I converted the LibSocketCAN library into a Pascal Unit.

beside the 'set' functions, which require root rights, the 'get' functions work as normal user.

Code: Pascal  [Select][+][-]
  1. unit LibSockCAN;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. //lib/arm-linux-gnueabihf/libsocketcan.so
  8. //libsocketcan.h
  9. uses can.netlink, ctypes,
  10.  
  11. if_linkpart;   // a short version of the linux/if_link.h
  12.  
  13. {$linklib c}
  14. {$linklib libsocketcan}
  15. type
  16.  pdword   = ^dword;
  17.  p_mybt   = ^can_bittiming;
  18.  p_mycm   = ^can_ctrlmode;
  19.  p_myclk  = ^can_clock;
  20.  p_mybtc  = ^can_bittiming_const;
  21.  p_mybcs  = ^can_berr_counter;
  22.  p_mycds  = ^can_device_stats;
  23.  p_myrls  = ^rtnl_link_stats64;  //defined in if_linkpart derived from <linux/if_link.h>  
  24.  rx_packets = qword;
  25.  
  26.  
  27. //These functions work only with root rights
  28.  
  29. function can_do_restart(myifname : ansistring) : longint; cdecl; external;
  30. function can_set_restart_ms(myifname : ansistring; restart_ms : dword) : longint; cdecl; external;
  31. function can_do_stop(myifname : ansistring) : longint; cdecl; external;
  32. function can_do_start(myifname : ansistring) : longint; cdecl; external;
  33. function can_set_bitrate(myifname : ansistring; bitrate : dword) : longint; cdecl; external;
  34. function can_set_bitrate_samplepoint(myifname : ansistring; bitrate, samplepoint : dword) : longint; cdecl; external;
  35. function can_set_bittiming(myifname : ansistring; mybt : p_mybt) : longint; cdecl; external;
  36. function can_set_ctrlmode(myifname : ansistring; mycm : p_mycm ) : longint; cdecl; external;
  37.  
  38. //These functions work with user rights
  39.  
  40. function can_get_restart_ms(myifname : ansistring; myrms : pdword)  :longint; cdecl; external;
  41. function can_get_bittiming(myifname : ansistring; mybt : p_mybt ) : longint; cdecl; external;
  42. function can_get_ctrlmode(myifname : ansistring; mycm : p_mycm) :longint; cdecl; external;
  43. function can_get_state(myifname : ansistring; mystate : pdword): longint; cdecl; external;
  44. function can_get_clock(myifname : ansistring; myclock : p_myclk) :longint; cdecl; external;
  45. function can_get_bittiming_const(myifname : ansistring; mybtc : p_mybtc) :longint; cdecl; external;
  46. function can_get_berr_counter(myifname : ansistring; mybcs : p_mybcs):longint; cdecl; external;
  47. function can_get_device_stats(myifname : ansistring; mycds : p_mycds):longint; cdecl; external;
  48. function can_get_link_stats(myifname : ansistring; myrls : p_myrls):longint; cdecl; external;
  49.  
  50.  
  51. implementation
  52.  
  53.  
  54. end.
  55.  


I have tested all the 'get' and from the 'set' the ones I would need.

Doing that, was easier than using ip commands and parsing the text returns for the desired value.
Title: Re: CAN-BUS SocketCAN
Post by: avra on June 09, 2021, 01:51:33 pm
But the num_events is always either 0 or 1 even if more than 1 message was sent to the port.
Based on a quick look, it seams to me that instead of a single PEPoll_event you should try to create an array of PEPoll_event, pass number of elements to epoll_create(), and pass PEPoll_event array to epoll_wait(). Exactly аs in C demo that you can find at https://linux.die.net/man/7/epoll. I know that epoll_create() with kernels newer then 2.6.8 should not care for size parameter (as long as it's positive), but C demo thinks that it does matter so you should probably listen to it (at least until you make it work).

I converted the LibSocketCAN library into a Pascal Unit.
Very nice and thank you! If you agree to put the same license as in my CAN wrapper and demos, then I can add your wrapper also - if you add some simple console demo (of course, it will be clear who is the author of which file). What I would probably do is rename LibSockCAN.pas to can.lib.pas, and rename if_linkpart.pas (which is missing, btw) to can.if.linkpart.inc and include it from can.lib unit. What do you think?
Title: Re: CAN-BUS SocketCAN
Post by: ThomasK on June 09, 2021, 02:50:44 pm
(at least until you make it work).
I actually don't care how many events occur, because the epoll is fixed to the event EPOLLIN. As long as the query returns '1' there is data to read, if
 it is '0' then not.

Very nice and thank you! If you agree to put the same license as in my CAN wrapper and demos, then I can add your wrapper also - if you add some simple console demo (of course, it will be clear who is the author of which file).
I can rework the whole stuff, no problem

Is really a console application required? A GUI exists, which I left out of the .zip due to its size and in case of a console app I would have to do a cmd parser......

What I would probably do is rename LibSockCAN.pas to can.lib.pas, and rename if_linkpart.pas (which is missing, btw) to can.if.linkpart.inc and include it from can.lib unit. What do you think?

I can do the renaming, the licensing stuff and and check if all is available, no problem. 

I am working on another topic : https://forum.lazarus.freepascal.org/index.php/topic,54944.msg408418.html#msg408418 (https://forum.lazarus.freepascal.org/index.php/topic,54944.msg408418.html#msg408418)
and want to solve that too.
Pic of the GUI attached.
Title: Re: CAN-BUS SocketCAN
Post by: avra on June 09, 2021, 06:45:30 pm
Is really a console application required? A GUI exists, which I left out of the .zip due to its size and in case of a console app I would have to do a cmd parser......
Although you can find basic cmd parsers in hlcanerrdump and hlcanerrsim, there is really no need to go that far. Just fix interface name and other needed parameters in code and that shall be fine. GUI advanced demos are nice, but SocketCAN package will be part of FPC and there is a good chance that it will run on a headless SBC without Lazarus, so simple console demos are more important.

What I would probably do is rename LibSockCAN.pas to can.lib.pas, and rename if_linkpart.pas (which is missing, btw) to can.if.linkpart.inc and include it from can.lib unit. What do you think?
I can do the renaming, the licensing stuff and and check if all is available, no problem.
Thanks! It would be great if you could use license templates from my demos and wrappers.

I am working on another topic : https://forum.lazarus.freepascal.org/index.php/topic,54944.msg408418.html#msg408418 (https://forum.lazarus.freepascal.org/index.php/topic,54944.msg408418.html#msg408418)
and want to solve that too.
Pic of the GUI attached.
Nice. I wrote a solution proposal there.
Title: Re: CAN-BUS SocketCAN
Post by: ThomasK on June 10, 2021, 11:17:37 am
Hello Avra,

I have reworked the library and included the definition for

Code: Pascal  [Select][+][-]
  1. rtnl_link_stats64  =   record

in can.lib.pas library itself, like in libsocketcan.h. Explanations of this data type can be found for example here https://github.com/torvalds/linux/blob/master/include/uapi/linux/if_link.h (https://github.com/torvalds/linux/blob/master/include/uapi/linux/if_link.h).

I updated the license disclaimer of the original libsocketcan.h and added it to the library.
Besides the can.lib.pas, only can.netlink.pas is required to use libsocketcan.

A demo GUI application for Lazarus is included, it does not exercise all functions with all parameters set, but the use becomes clear.
If you want to use "set" commands it must be started with root rights, otherwise they fail.

Feel free to use the lib.can.pas together with your code.

rgds, Thomas
Title: Re: CAN-BUS SocketCAN
Post by: avra on June 10, 2021, 03:31:01 pm
Thanks Thomas, very nice! I will take a look as soon as I get some free time.
Title: Re: CAN-BUS SocketCAN
Post by: avra on July 01, 2021, 03:45:27 pm
@Thomas: I have made small changes needed for your LibSocketCAN wrapper and demo to fit the rest of the project. Please review and comment if needed.

@Everyone: I am also thinking about making a high level pascal like interface to avoid ugly c naming in LibSocketCAN, like I already did for SocketCAN. However, I do not know if I should add it to can.hl.pas where the rest of the high level stuff is, or to a separate unit? I am in doubt since LibSocketCAN wrapper in can.lib.pas has {$linklib libsocketcan} which is a dependency that needs installation (from source or package manager), and I don't want to force that dependency to all SocketCAN users. Is lib dependency forced on everyone as soon as we include lib with $linklib, or we need to call something from that lib first? I do not know this so I ask if someone else knows?
Title: Re: CAN-BUS SocketCAN
Post by: ThomasK on July 28, 2021, 10:48:34 am
@Avra,

sorry for the late reply, I changed job so my days are very busy....

I will review the new demo and come back.

About integration of LibSocketCAN into can.hl my two cents are keep it as an tool on top, because  it is not always needed but a grip to do some diagnostics.

Chers!
Title: Re: CAN-BUS SocketCAN
Post by: avra on July 28, 2021, 12:43:16 pm
sorry for the late reply, I changed job so my days are very busy....

I will review the new demo and come back.
Take your time. No rush.

About integration of LibSocketCAN into can.hl my two cents are keep it as an tool on top, because it is not always needed but a grip to do some diagnostics.
Your wrapper will stay as can.lib unit, and future pascalish thin wrapper will be a separate can.lib.hl unit. That way we will still be able to easily convert C demos when needed, while having more eye pleasing pascalish named access as with the rest of the high level CAN.

I wish you well on your new job!
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on September 24, 2021, 10:04:17 am
@jcdammeyer: CAN FD receive and transmit demos are here.  It was not trivial to find info of what exactly to change when compared to legacy CAN but it works now. 8-)

Oh my gosh.  I've finally finished a fairly large work-work project this summer and was thinking about getting back to this and I must have missed an email that the thread had been updated. 
Wow! 

Time for me to dig back into this since it's part of a larger project on CANopen Lite I'd like to do with Lazarus.

In fact I'm using one of my dsPIC modules with very simple CANopen messaging from LinuxCNC to run a power drawbar.  The LinuxCNC code is python interfaced with the AXIS user interface but the connection is via the Lawicel CANUSB dongle and serial port commands. 

I'll go through the entire thread and do some testing as soon as I finish a CNC conversion to new AC Servos.  I really do want to get back to this.
John
Title: Re: CAN-BUS SockectCAN
Post by: avra on September 24, 2021, 12:24:45 pm
Oh my gosh.  I've finally finished a fairly large work-work project this summer and was thinking about getting back to this and I must have missed an email that the thread had been updated. 
Wow!
I'm glad you like the progress.  :D ;) :D

I'm waiting for my bithelpers (actually new name as agreed with devs is syshelpers) FPC patch to become fully accepted (direct bit/nibble/byte/word/dword array like access already works in trunk as can be seen at https://gitlab.com/freepascal.org/fpc/source/-/issues/39268), and then I will need to write syshelpers documentation. After that gets completed, plan is to polish SocketCAN a little more and make an official FPC patch so it can be used out of the box. Good news for you is that Lawicel works with SocketCAN. Bad news is that while J1939 base support exists (demos not included yet), CANopen support is not comming any time soon. Right now I need plain CAN and J1939 for some of my freelance work so that's in focus, but since I do CAN a lot it is possible that at some moment I will deal with CANopen, too. No promisses and no schedule, but tiny possibility is there. If you need CANopen now, then you will have to implement it on your own. Patches are welcome.
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on September 24, 2021, 07:30:21 pm
I'm glad you like the progress.  :D ;) :D
If you need CANopen now, then you will have to implement it on your own. Patches are welcome.
The problem with CANopen is it's huge and for 99% of the projects (IMHO) doesn't need to be.  For example, a big deal is made over the support of the configuration files.  Useful for the non-programmer mechanical engineer or installer but for someone who writes in Delphi or Lazarus not so much.  Building up the object dictionary (OD) to show the size of variables pointless and just takes up a lot of code/data space.  Creating a be all end all installation would be nice but also overkill and hard to understand and maintain.

So I'm proposing a CANopen Lite.  That can deal with COTS (Commercial Off The Shelf) devices but might require a bit of programming to interface with.  To start with I've started with a simple monitoring program that at the moment uses the CANUSB.  So far this software has run on WIN-PC, BeagleBone and Pi. 

To migrate to socketCAN it will need a level of abstraction built in so we can open a device like the internal processor built in CAN on a BeagleBone or a Pi3 HAT that uses the MCP2515 SPI to CAN device and of course the socketCAN version of CANUSB.  I have two HATs for the Pi, a cape for the Beagle and lots of CANUSB plus a few expensive commercial USB dongles.

I will of course make the entire program open source. 
Title: Re: CAN-BUS SockectCAN
Post by: avra on September 25, 2021, 01:02:20 am
To migrate to socketCAN it will need a level of abstraction built in so we can open a device like the internal processor built in CAN on a BeagleBone or a Pi3 HAT that uses the MCP2515 SPI to CAN device and of course the socketCAN version of CANUSB.
Step-by-step guide on using Lawicel CANUSB via SocketCAN: https://pascal-walter.blogspot.com/2015/08/installing-lawicel-canusb-on-linux.html
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on September 25, 2021, 01:10:02 am
To migrate to socketCAN it will need a level of abstraction built in so we can open a device like the internal processor built in CAN on a BeagleBone or a Pi3 HAT that uses the MCP2515 SPI to CAN device and of course the socketCAN version of CANUSB.
Step-by-step guide on using Lawicel CANUSB via SocketCAN: https://pascal-walter.blogspot.com/2015/08/installing-lawicel-canusb-on-linux.html

Yes.  Thank you.  That's not an issue.  I've dumped CAN packets from working systems using socketCAN with the CANUSB on the PI3/4.  But that's using the C language command line programs.   

A couple of years ago now I had to record Hydrogen powered vehicle CAN messages from ignition key on and the Pi wasn't capable of booting in under 14 seconds.   So instead I put together a small PIC32 with CAN module that logged/timestamped all CAN messages along with GPS information and sent them up via SPI to the PiZero once it was awake. On the Pi they were saved in files and another application would grab them and put them on the cloud for the engineers to use for diagnostics.

Really looking forward to playing with your socketCAN stuff.
John

Title: Re: CAN-BUS SockectCAN
Post by: avra on September 25, 2021, 11:02:03 am
I've dumped CAN packets from working systems using socketCAN with the CANUSB on the PI3/4.  But that's using the C language command line programs.
As you progress through pascal SocketCAN demos, you will see that low level units will help when you want to convert C examples from the net since it will mostly be 1:1 translation as far as SocketCAN part is concerned. Once you get a feeling, you will quickly advance to more natural pascalish high level unit.

Really looking forward to playing with your socketCAN stuff.
I wish you as much fun as I have!  :D
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on September 26, 2021, 05:49:40 am
I wish you as much fun as I have!  :D
Not quite yet.
Under Lazarus I can create a console project, add this
writeln('Hello World from my Console Application');
 in the appropriate spot and then either run it from the IDE or from the console with that output.

Opening the canreceive project from the can.zip file compiles but doesn't generate an executable on the Beaglebone as shown in the attached screen shot.

Code: Pascal  [Select][+][-]
  1.     s := fpsocket(PF_CAN, SOCK_RAW, CAN_RAW);
And the BBB sockets.pp doesn't have PF_CAN so the can.zip file by itself isn't enough to compile and test. 

ie. if I add this along with the perror function it complains about the missing PF_CAN
Code: Pascal  [Select][+][-]
  1.     s := fpsocket(PF_CAN, SOCK_RAW, CAN_RAW);
  2.     if s < 0 then
  3.     begin
  4.       perror('Socket');
  5.       Exit;
  6.     end;
  7.  

Would you be able to create a canreceive.zip with a console application who's sole purpose is to open say slcan0 and just dump out messages like your canreceive.  For example the 3 attachments show that the CANUSB on /dev/ttyUSB0 can be accessed as a serial port via the CANopenLite application but can also be configured as slcan0 as shown in the other photo working with the socketCAN candump application.

So my hardware works.  Now the software.

Title: Re: CAN-BUS SockectCAN
Post by: avra on September 26, 2021, 05:00:21 pm
BBB sockets.pp doesn't have PF_CAN
As mentioned at https://forum.lazarus.freepascal.org/index.php/topic,39858.msg396135.html#msg396135 you need newer FPC so getting trunk would be a good idea. If that is not for you, then instead you could simply define missing constants PF_CAN and AF_CAN as 29 somewhere in your code. After that, it would be good to create vcan0 virtual adapter and go through demos since they should all work out of the box.

Would you be able to create a canreceive.zip with a console application who's sole purpose is to open say slcan0 and just dump out messages like your canreceive.
Once you have demos working with vcan0, making them work with slcan0 should be trivial. For example, in canreceive.lpr or hlcanreceive.lpr, all you need is to replace 'vcan0' with 'slcan0' at one place in code (as shown in your 3rd attachment).
Title: Re: CAN-BUS SockectCAN
Post by: jcdammeyer on September 26, 2021, 07:22:11 pm
BBB sockets.pp doesn't have PF_CAN
As mentioned at https://forum.lazarus.freepascal.org/index.php/topic,39858.msg396135.html#msg396135 you need newer FPC so getting trunk would be a good idea. If that is not for you, then instead you could simply define missing constants PF_CAN and AF_CAN as 29 somewhere in your code. After that, it would be good to create vcan0 virtual adapter and go through demos since they should all work out of the box.
Sadly this link doesn't work anymore which is why I posted the question.
Quote
CAN constants have been added to FPC 48867:
https://svn.freepascal.org/svn/fpc/trunk/packages/rtl-extra/src/linux/unxsockh.inc
In fact I can't even access https://svn.freepasccal.org

Title: Re: CAN-BUS SockectCAN
Post by: dsiders on September 26, 2021, 08:07:10 pm
Quote
CAN constants have been added to FPC 48867:
https://svn.freepascal.org/svn/fpc/trunk/packages/rtl-extra/src/linux/unxsockh.inc
In fact I can't even access https://svn.freepasccal.org

You have two issues:

The URL was https://svn.freepascal.org and not https://svn.freepasccal.org.

They moved to GitLab a few months back and the svn server no longer exists. There is a GitHub SVN mirror at: https://github.com/fpc/FPCSource, but the vcs of record is git located at: https://gitlab.com/freepascal.org/fpc/source.
Title: Re: CAN-BUS SocketCAN
Post by: jcdammeyer on September 26, 2021, 08:45:45 pm
Incorrect spelling.  Sorry about that.  If possible then the link way back should be edited to point to the correct location.

What I did is add the PF_CAN and AF_CAN definitions into my code.  I also did put them into unxsockh.inc but it didn't have any effect.  Perhaps there's another copy being used instead.

Here's the results of the code below where I cut and pasted the canreceive.lpr section:
Code: [Select]
debian@ebb:~/lazarus/AvraCAN$ ./ConsoleApplication
Hello World from Console Application
CAN Sockets Receive Demo Rev 0.01
fpsocket call
fpioctl call
fpbind call
fpread call
Standard CAN frame received with length 1
0x718 [1] 05
debian@ebb:~/lazarus/AvraCAN$

Code: Pascal  [Select][+][-]
  1. program ConsoleApplication;
  2.  
  3. {$mode delphi}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}{$IFDEF UseCThreads}
  7.   cthreads,
  8.   {$ENDIF}{$ENDIF}
  9.   Classes, SysUtils, CustApp,
  10.   { you can add units after this }
  11.   sockets, baseunix, can;
  12.  
  13. const
  14.          PF_CAN = 29;
  15.          AF_CAN = 29;
  16.  
  17. type
  18.  
  19.   { TMyApplication }
  20.  
  21.   TMyApplication = class(TCustomApplication)
  22.   protected
  23.     procedure DoRun; override;
  24.   public
  25.     constructor Create(TheOwner: TComponent); override;
  26.     destructor Destroy; override;
  27.     procedure WriteHelp; virtual;
  28.     procedure perror(const S : string);
  29.     procedure MyApplicationMain;
  30.   end;
  31.  
  32. { TMyApplication }
  33. procedure TMyApplication.perror(const S : string);
  34. begin
  35.   WriteLn(S, ', SocketError = ', SocketError);
  36. end;
  37.  
  38.  
  39. procedure TMyApplication.MyApplicationMain;
  40. var
  41.   s, i, nbytes, err: cint;
  42.   addr:              sockaddr_can;
  43.   ifr:               ifreq;
  44.   frame:             canfd_frame;
  45. begin
  46.   Writeln('Hello World from Console Application');
  47.   WriteLn('CAN Sockets Receive Demo Rev 0.01');
  48.   writeln('fpsocket call');
  49.   s := fpsocket(PF_CAN, SOCK_RAW, CAN_RAW);
  50.   if s < 0 then
  51.   begin
  52.     perror('Socket');
  53.     Exit;
  54.   end;
  55.  
  56.   writeln('fpioctl call');
  57.   strcopy(ifr.ifr_name, 'slcan0'); // ifr.ifr_name := 'vcan0' + #0;
  58.   if fpioctl(s, SIOCGIFINDEX, @ifr) < 0 then
  59.   begin
  60.     perror('IOctl');
  61.     Exit;
  62.   end;
  63.  
  64.   writeln('fpbind call');
  65.   memset(@addr, 0, sizeof(addr));
  66.   addr.can_family  := AF_CAN;
  67.   addr.can_ifindex := ifr.ifr_ifindex;
  68.  
  69.   if fpbind(s, @addr, sizeof(addr)) < 0 then
  70.   begin
  71.     perror('Bind');
  72.     Exit;
  73.   end;
  74.  
  75.   writeln('fpread call');
  76.   nbytes := fpread(s, frame, sizeof(frame));
  77.   if nbytes < 0 then
  78.   begin
  79.     perror('Read');
  80.     Exit;
  81.   end;
  82.  
  83.   if nbytes = CANFD_MTU then    // test CAN FD with 'cansend vcan0 123##1223344556677889900'
  84.     WriteLn('CAN FD frame received with length ', IntToStr(frame.len))
  85.   else if nbytes = CAN_MTU then // test legacy CAN with 'cansend vcan0 456#DEADBEEF'
  86.     WriteLn('Standard CAN frame received with length ', IntToStr(frame.len))
  87.   else
  88.     WriteLn('Invalid CAN(FD) frame received');
  89.  
  90.   Write(Format('0x%03X [%d] ', [frame.can_id and CAN_EFF_MASK, frame.len]));
  91.   for i := 0 to frame.len - 1 do
  92.     Write(Format('%02.2X ', [frame.data[i]]));
  93.   WriteLn('');
  94.  
  95.   if fpclose(s) < 0 then
  96.   begin
  97.     perror('Close');
  98.     Exit;
  99.   end;
  100.  
  101. end;
  102.  
  103. procedure TMyApplication.DoRun;
  104. var
  105.   ErrorMsg: String;
  106. begin
  107.   // quick check parameters
  108.   ErrorMsg:=CheckOptions('h', 'help');
  109.   if ErrorMsg<>'' then begin
  110.     ShowException(Exception.Create(ErrorMsg));
  111.     Terminate;
  112.     Exit;
  113.   end;
  114.  
  115.   // parse parameters
  116.   if HasOption('h', 'help') then begin
  117.     WriteHelp;
  118.     Terminate;
  119.     Exit;
  120.   end;
  121.  
  122.   { add your program here }
  123.   MyApplicationMain;
  124.  
  125.   // stop program loop
  126.   Terminate;
  127. end;
  128.  
  129. constructor TMyApplication.Create(TheOwner: TComponent);
  130. begin
  131.   inherited Create(TheOwner);
  132.   StopOnException:=True;
  133. end;
  134.  
  135. destructor TMyApplication.Destroy;
  136. begin
  137.   inherited Destroy;
  138. end;
  139.  
  140. procedure TMyApplication.WriteHelp;
  141. begin
  142.   { add your help code here }
  143.   writeln('Usage: ', ExeName, ' -h');
  144. end;
  145.  
  146. var
  147.   Application: TMyApplication;
  148. begin
  149.   Application:=TMyApplication.Create(nil);
  150.   Application.Title:='My Application';
  151.   Application.Run;
  152.   Application.Free;
  153. end.
  154.  
  155.  

No idea why canreceive.lpr won't compile into an executable.
Title: Re: CAN-BUS SocketCAN
Post by: jcdammeyer on September 26, 2021, 10:32:19 pm
I've updated the program and formatted it to match the socketCAN candump program.  Only does standard IDs, no Extended ID or CANFD.  CANFD likely won't happen as I have absolutely no CANFD units here and no desire to actually use it.  99.9% of everything I have in stock in drivers, devices, dongles are all non-CANFD.

Quote
debian@ebb:~/lazarus/AvraCAN$ ./ConsoleApplication
CAN Sockets Receive Demo Rev 0.1 Build 5
slcan0  298   [7]  00 00 00 00 01 00 00
slcan0  718   [1]  05
slcan0  298   [7]  00 00 00 00 01 00 00
slcan0  298   [7]  00 00 00 00 01 00 00
slcan0  718   [1]  05
slcan0  298   [7]  00 00 00 00 01 00 00
slcan0  298   [7]  00 00 00 00 01 00 00
slcan0  718   [1]  05
slcan0  298   [7]  00 00 00 00 01 00 00
slcan0  298   [7]  00 00 00 00 01 00 00
slcan0  718   [1]  05
debian@ebb:~/lazarus/AvraCAN$

And here's the updated console application.  I'll hang a module on that generates Extended 29 bit ID messages and add support for that to match candump.  I'll also add a command line parameter that allows defining which CAN device is to be used.  Since this test is on a Beagle I'll put the CAN cape on it, verify with the socketCAN candump that it works and then test it with the Lazarus program.

Code: Pascal  [Select][+][-]
  1. program ConsoleApplication;
  2.  
  3. {$mode delphi}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}{$IFDEF UseCThreads}
  7.   cthreads,
  8.   {$ENDIF}{$ENDIF}
  9.   Classes, SysUtils, CustApp,
  10.   { you can add units after this }
  11.   crt,  { for the keypressed function }
  12.   sockets, baseunix, can;  { for socketCAN support }
  13.  
  14. const
  15.          PF_CAN = 29;  // Not defined in libraries yet.
  16.          AF_CAN = 29;
  17.  
  18. type
  19.  
  20.   { TMyApplication }
  21.  
  22.   TMyApplication = class(TCustomApplication)
  23.   protected
  24.     procedure DoRun; override;
  25.   public
  26.     constructor Create(TheOwner: TComponent); override;
  27.     destructor Destroy; override;
  28.     procedure WriteHelp; virtual;
  29.     procedure perror(const S : string);
  30.     procedure MyApplicationMain;
  31.   end;
  32.  
  33. { TMyApplication }
  34. procedure TMyApplication.perror(const S : string);
  35. begin
  36.   WriteLn(S, ', SocketError = ', SocketError);
  37. end;
  38.  
  39.  
  40. procedure TMyApplication.MyApplicationMain;
  41. var
  42.   s, i, nbytes, err: cint;
  43.   addr:              sockaddr_can;
  44.   ifr:               ifreq;
  45.   frame:             canfd_frame;
  46.  
  47. begin
  48. //  Writeln('Hello World from Console Application');
  49.   WriteLn('CAN Sockets Receive Demo Rev 0.1 Build 5');
  50. //  writeln('fpsocket call');
  51.   s := fpsocket(PF_CAN, SOCK_RAW, CAN_RAW);
  52.   if s < 0 then
  53.   begin
  54.     perror('Socket');
  55.     Exit;
  56.   end;
  57.  
  58. //  writeln('fpioctl call');
  59.   strcopy(ifr.ifr_name, 'slcan0'); // ifr.ifr_name := 'vcan0' + #0;
  60.   if fpioctl(s, SIOCGIFINDEX, @ifr) < 0 then
  61.   begin
  62.     perror('IOctl');
  63.     Exit;
  64.   end;
  65.  
  66. //  writeln('fpbind call');
  67.   memset(@addr, 0, sizeof(addr));
  68.   addr.can_family  := AF_CAN;
  69.   addr.can_ifindex := ifr.ifr_ifindex;
  70.  
  71.   if fpbind(s, @addr, sizeof(addr)) < 0 then
  72.   begin
  73.     perror('Bind');
  74.     Exit;
  75.   end;
  76.  
  77.   while (not keypressed) do begin
  78.     //  writeln('fpread call');
  79.       nbytes := fpread(s, frame, sizeof(frame));
  80.       if nbytes < 0 then
  81.       begin
  82.         perror('Read');
  83.         Exit;
  84.       end;
  85.  
  86.       if nbytes = CANFD_MTU then    // test CAN FD with 'cansend vcan0 123##1223344556677889900'
  87.         WriteLn('CAN FD frame received with length ', IntToStr(frame.len))
  88.       else if nbytes = CAN_MTU then // test Standard CAN with 'cansend vcan0 456#DEADBEEF'
  89.     //    WriteLn('Standard CAN frame received with length ', IntToStr(frame.len))
  90.           write(ifr.ifr_name, '  ')
  91.       else
  92.         WriteLn('Invalid CAN(FD) frame received');
  93.  
  94.       Write(Format('%03X   [%d]  ', [frame.can_id and CAN_EFF_MASK, frame.len]));
  95.       for i := 0 to frame.len - 1 do
  96.         Write(Format('%02.2X ', [frame.data[i]]));
  97.       WriteLn('');
  98.   end;
  99.  
  100.   if fpclose(s) < 0 then
  101.   begin
  102.     perror('Close');
  103.     Exit;
  104.   end;
  105.  
  106. end;
  107.  
  108. procedure TMyApplication.DoRun;
  109. var
  110.   ErrorMsg: String;
  111. begin
  112.   // quick check parameters
  113.   ErrorMsg:=CheckOptions('h', 'help');
  114.   if ErrorMsg<>'' then begin
  115.     ShowException(Exception.Create(ErrorMsg));
  116.     Terminate;
  117.     Exit;
  118.   end;
  119.  
  120.   // parse parameters
  121.   if HasOption('h', 'help') then begin
  122.     WriteHelp;
  123.     Terminate;
  124.     Exit;
  125.   end;
  126.  
  127.   { add your program here }
  128.   MyApplicationMain;
  129.  
  130.   // stop program loop
  131.   Terminate;
  132. end;
  133.  
  134. constructor TMyApplication.Create(TheOwner: TComponent);
  135. begin
  136.   inherited Create(TheOwner);
  137.   StopOnException:=True;
  138. end;
  139.  
  140. destructor TMyApplication.Destroy;
  141. begin
  142.   inherited Destroy;
  143. end;
  144.  
  145. procedure TMyApplication.WriteHelp;
  146. begin
  147.   { add your help code here }
  148.   writeln('Usage: ', ExeName, ' -h');
  149. end;
  150.  
  151. var
  152.   Application: TMyApplication;
  153. begin
  154.   Application:=TMyApplication.Create(nil);
  155.   Application.Title:='My Application';
  156.   Application.Run;
  157.   Application.Free;
  158. end.
  159.  
  160.  

John
Title: Re: CAN-BUS SocketCAN
Post by: jcdammeyer on September 26, 2021, 10:47:28 pm
Oh and the messages you see are generated by the module in the photo.  The buttons enable an air cylinder and butterfly impact wrench to act as a power drawbar and are displayed on the Pi4 LinuxCNC display.  The Mist Coolant has been turned on so the 0x44 represents that output command and in the high nibble the output status.   You can see the bits in the PDO message changing as I press the button and the drawbar state machine is activated with one other output also switched ON.  The Pi4 LinuxCNC talks to the CAN bus via another Lawicel CANUSB. 

Quote
CAN Sockets Receive Demo Rev 0.1 Build 5
slcan0  298   [7]  00 44 00 00 01 00 00
slcan0  718   [1]  05
slcan0  298   [7]  00 44 00 00 01 00 00
slcan0  298   [7]  00 44 00 00 01 00 00
slcan0  718   [1]  05
slcan0  298   [7]  00 44 00 00 01 00 00
slcan0  298   [7]  00 44 00 00 01 00 00
slcan0  718   [1]  05
slcan0  298   [7]  00 44 00 00 01 00 00
slcan0  298   [7]  00 44 00 00 01 00 00
slcan0  298   [7]  02 44 00 00 01 00 02
slcan0  298   [7]  00 66 00 00 06 00 00
slcan0  718   [1]  05
slcan0  298   [7]  00 66 00 00 06 00 00
slcan0  298   [7]  00 66 00 00 06 00 00
slcan0  718   [1]  05
slcan0  298   [7]  00 66 00 00 06 00 00
slcan0  298   [7]  00 66 00 00 06 00 00
slcan0  718   [1]  05
slcan0  298   [7]  00 44 00 00 01 00 00
slcan0  298   [7]  00 44 00 00 01 00 00
slcan0  718   [1]  05

It's not yet mounted on the machine.  I only just learned about postings from avra on this.  For some reason I missed the email that things were being done.  Been a busy summer.  And yes.  Now I'm having fun again. ;D
Titl