Files
ecmc_plugin_socketcan/README.md
anderssandstrom 5409f8e7f7 Update README.md
2021-03-12 09:10:39 +01:00

7.0 KiB

e3-ecmc_plugin_socketcan

ESS Site-specific EPICS module : ecmcPlugin_socketcan

ScoketCAN

This module adds some CAN support to ecmc based on SocketCAN: https://en.wikipedia.org/wiki/SocketCAN

CANOpen

This module implements a few of the CANOpen functionalities (but it is far from a full CANOpen Implementation).

The current implemented features are:

  • Simple master:

    • Simple LSS

    • Heartbeat

    • Sync

  • Simple generic (slave) device

  • SDO segmented r/w

  • PDO r/w

These functionalities are configured through iocsh cmds:

  • ecmcCANOpenAddMaster

  • ecmcCANOpenAddDevice

  • ecmcCANOpenAddSDO

  • ecmcCANOpenAddPDO

ecmcCANOpenAddMaster

Issueing "ecmcCANOpenAddMaster -h" in the iocsh you will get the following help printout:

    ecmcCANOpenAddMaster -h
       Use ecmcCANOpenAddMaster(<name>, <node id>,....)
                 <name>                     : Name of master device.
                 <node id>                  : CANOpen node id of master.
                 <LSS sample time ms>       : Sample time for LSS.
                 <Sync sample time ms>      : Sample time for SYNC.
                 <Heartbeat sample time ms> : Sample time for Heartbeat.

Example to add a master with LSS, sync, heartbeat sample time of 1s:

ecmcCANOpenAddMaster("ecmcCANOpenMaster",0,1000,1000,1000)

Note:: You can only have one master in each ioc (one call to "ecmcCANOpenAddMaster").

ecmcCANOpenAddDevice

Issueing "ecmcCANOpenAddDevice -h" in the iocsh you will get the following help printout:

    ecmcCANOpenAddDevice -h
      Use ecmcCANOpenAddDevice(<name>, <node id>)
          <name>      : Name of device.
          <node id>   : CANOpen node id of device.

Example to add a device with node id 3:

ecmcCANOpenAddDevice("testDevice",3)

Note:: You can only use the below commands (ecmcCANOpenAddSDO and ecmcCANOpenAddODO) to nodes of an existing device or master.

ecmcCANOpenAddSDO

Issueing "ecmcCANOpenAddSDO -h" in the iocsh you will get the following help printout:

    ecmcCANOpenAddSDO -h
        ecmcCANOpenAddSDO( in the iocsh<name>, <node id>,.....)
         <name>            : Name of master device.
         <node id>         : CANOpen node id of device/master.
         <cob id tx>       : CANOpen cob id of Tx of slave SDO.
         <cob id rx>       : CANOpen cob id of Rx of slave SDO.
         <dir>             : Direction 1=write and 2=read.
         <ODIndex>         : OD index of SDO.
         <ODSubIndex>      : OD sub index of SDO.
         <ODSize>          : OS Siz
         <readSampleTimeMs>: Sample time for read in ms (write is always on demand).

A few examples:

# Example read SDO from device, will be cyclically read at an intervall of 7000ms:
ecmcCANOpenAddSDO("analogValues",3,0x583,0x603,2,0x2640,0x0,56,7000)
dbLoadRecords(ecmcPluginSocketCAN_SDO_input.template, "P=${ECMC_PREFIX},PORT=${ECMC_ASYN_PORT},ADDR=0,TIMEOUT=1,T_SMP_MS=${ECMC_SAMPLE_RATE_MS},TSE=${ECMC_TSE},NELM=${NELM=1},CH_ID=03,DEV_ID=3,suffix=AI03-Array,source=basicConfig,DTYP=asynInt8ArrayIn,FTVL=CHAR,NELM=7")

# Example write SDO to device, will be written on demand (when write data from epics):
ecmcCANOpenAddSDO("basicConfig",3,0x583,0x603,1,0x2690,0x1,7,0)
dbLoadRecords(ecmcPluginSocketCAN_SDO_output.template, "P=${ECMC_PREFIX},PORT=${ECMC_ASYN_PORT},ADDR=0,TIMEOUT=1,T_SMP_MS=${ECMC_SAMPLE_RATE_MS},TSE=${ECMC_TSE},NELM=${NELM=1},CH_ID=03,DEV_ID=3,suffix=BasicConfig,source=basicConfig,DTYP=asynInt8ArrayOut,FTVL=CHAR,NELM=7")

ecmcCANOpenAddPDO

Issueing "ecmcCANOpenAddPDO -h" in the iocsh you will get the following help printout:

    ecmcCANOpenAddPDO -h
      Use "ecmcCANOpenAddPDO(<name>, <node id>
          <name>            : Name of master device.
          <node id>         : CANOpen node id of device/master.
          <cob id>          : CANOpen cob id of PDO.
          <dir>             : Direction 1=write and 2=read.
          <ODSize>          : Size of PDO (max 8 bytes).
          <readTimeoutMs>   : Readtimeout in ms.
          <writeCycleMs>    : Cycle time for write (if <= 0 then only write on change).

An example:

# Read PDO, if not recived pdo within 10s the PDO object will go into error state:
ecmcCANOpenAddPDO("status",3,0x183,2,8,10000,0)
dbLoadRecords(ecmcPluginSocketCAN_PDO_input.template, "P=${ECMC_PREFIX},PORT=${ECMC_ASYN_PORT},ADDR=0,TIMEOUT=1,T_SMP_MS=${ECMC_SAMPLE_RATE_MS},TSE=${ECMC_TSE},NELM=${NELM=1},CH_ID=03,DEV_ID=3,suffix=PDO01-Array,source=status,NELM=8")

Plugin

Plugin report printout:

Plugin info: 
  Index                = 0
  Name                 = ecmcPlugin_socketcan
  Description          = SocketCAN plugin for use with ecmc.
  Option description   = 
    DBG_PRINT=<1/0>    : Enables/disables printouts from plugin, default = disabled (=0).
    IF=<if name>         : Sets can interface (example: can0, vcan0..).
    CONNECT=<1/0>        : Auto connect to if at startup, default = autoconnect (=1).

  Filename             = /home/dev/epics/base-7.0.4/require/3.4.0/siteMods/ecmc_plugin_socketcan/master/lib/linux-x86_64/libecmc_plugin_socketcan.so
  Config string        = IF=vcan0;DBG_PRINT=1;
  Version              = 2
  Interface version    = 65536 (ecmc = 65536)
     max plc funcs     = 64
     max plc func args = 10
     max plc consts    = 64
  Construct func       = @0x7fb36b81d310
  Enter realtime func  = @0x7fb36b81d220
  Exit realtime func   = @0x7fb36b81d230
  Realtime func        = @0x7fb36b81d270
  Destruct func        = @0x7fb36b81d240
  dlhandle             = @0xa45a50
  Plc functions:
    funcs[00]:
      Name       = "can_connect();"
      Desc       = double can_connect() : Connect to can interface (from config str).
      Arg count  = 0
      func       = @0x7fb36b81d280
    funcs[01]:
      Name       = "can_connected();"
      Desc       = double can_connected() : Connected to can interface.
      Arg count  = 0
      func       = @0x7fb36b81d2a0
    funcs[02]:
      Name       = "can_add_write(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);"
      Desc       = double can_add_write(canId,len,data0..data7) : Add write frame to can interface output buffer.
      Arg count  = 10
      func       = @0x7fb36b81d2e0
    funcs[03]:
      Name       = "can_last_writes_error();"
      Desc       = double can_last_writes_error() : get error from last writes.
      Arg count  = 0
      func       = @0x7fb36b81d2c0
  Plc constants:

Testing

You can use a virtual can, vcan network for testing:

Prerequirements

Install can utils:

   $ git clone https://github.com/linux-can/can-utils
   $ cd can-utils
   $ make
   $ make install

vccn setup

Start virt can 0 (vcan0) and candump:

  $ sudo modprobe vcan
  $ sudo ip link add dev vcan0 type vcan
  $ sudo ip link set up vcan0
  $ candump vcan0

candump will start to printout the raw can meassages on vcan0 network.

Other intressting things

In future it could be an option to use one of these repos for the CANOpen support:

  1. https://github.com/CANopenNode/CANopenNode
  2. https://github.com/CANopenNode/CANopenSocket
  3. https://github.com/marel-keytech/openCANopen