www.pudn.com > canbus4linux.rar > DOCUMENTATION



                     D O C U M E N T A T I O N

            C A N B U S 4 L I N U X   V E R S I O N   0 . 3


Copyright 2001 by Juergen Eder 


No liability for the contents of this document can be accepted. Use the concepts, 
examples and other content at your own risk. 

All copyrights are held by their respective owners, unless specifically noted otherwise. 
Use of a term in this document should not be regarded as affecting the validity of
any trademark or service mark. 

The file elektor_canpar.o is a driver for the can card from 
"Elektor magazine june, 2000". 
Homepage: http://www.elektor.de

The file can200par.o is a driver for the can card from CAN200 Project (it's also a card for the
parallelport)
Homepage: http://private.addcom.de/horo/can200/index.html

The file cantronik.o is a driver for the can card from cantronik.com

The canbus4linux driver is completely new written and use no part from
Elektor or CAN200 project!

****************************************************************************
Installation:
see file: INSTALL

****************************************************************************
Licence:
see file: COPYING

****************************************************************************
Features:
- interrupt driven
- should work with kernel 2.2.16 or newer
  (tested with 2.6.6)
- support CAN200 card and elektor CAN card (both for the parallelport)
  other cards can easily added with mini driver
- support CAN 2.0A and 2.0B (PeliCAN) of SJA1000 chip
- support /proc filesystem (/proc/canbus/...)
- parameters can be controlled by: IOCTL's and /proc filesystem
- read and write are implemented
  => example: echo "1234 0 12 34 55" > /dev/can0
     send a can message with:
       can id = 0x1234 
       rtr = 0
       data bytes = 0x12 0x34 0x55
  => cat /dev/can0
     shows the can messages
- support poll and fsync
- support fasync
- time stamp in all events
- a virtual CAN bus is simulated, if several applications uses the same CAN channel
  => example: 2 applications (x and y) open /dev/can0
     -> application x send a message (and get the "transmission event)
     -> application y get the receive message, because of the "virtual bus structure"
  => it's possible to turn off virtualization


       ---------------                  |<------ virtual CAN bus
       |             |   send data      |
       |    App x    |---->------>----->|
       |             |                  |
       ---------------                  |
                                        |
       ---------------                  |
       |             |   get data       |
       |    App y    |<-----<--------<--|
       |             |                  |
       ---------------                  |
                                        |
                                        |
                                 ---------------
                                 |  Hardware   |
                                 ---------------
                                        |
                                        |<------- real CAN bus
                                        |

- the two drivers for the ELEKTOR CAN CARD and the CAN200 CAN CARD use
  the parport driver
- the chipset driver (SJA1000.O) calculates the BTR registers



****************************************************************************
Description:
Actually the driver has three layers:

Layer 1: elektor_canpar.o and/or can200par.o
This layer implements the hardware access to the chip registers. This layer 
is specific for every hardware.

Layer 2: SJA1000.O
It's the chipset layer and implements all features of the SJA1000
from Philips. This driver "translates" the order's from layer 3
to chip registers. For example layer 3 want 125000 baud. Layer 2 calculates 
the BTR0 and BTR1 register and set this register with layer 1.

Layer 3: canbuscore.o
It's a core driver between the hardware driver and the application. 
This layer implements all features: read/write, ioctl's, ...


---------------------------------------------
|                APPLICATION                |
---------------------------------------------
                      |
---------------------------------------------
|                CANBUSCORE.O               |
---------------------------------------------
       |                      |
---------------  ------------------------------
|  SJA1000.O  |  |    |      chipset driver or hardware driver
---------------  ------------------------------
        |                     |
     ------------------       -------------------
     |                |             |           |
-------------  ---------------  ---------  ---------
| ELEKTOR.O |  | CAN200PAR.O |  |  |  |  |  ....
-------------  ---------------  ---------  ---------


****************************************************************************
Accessing CAN bus with scripts:
If a CAN driver is installed and started, it will create a directory:
/proc/canbus
and sub directories as many devices are available:
/proc/canbus/0
/proc/canbus/1
/proc/canbus/2
/proc/canbus/3
/proc/canbus/...

In "/proc/canbus/devices" you get the number of installed devices, for 
example 1 sub directory if you have only LPT1 and installed only elektor_canpar.o 
(or only can200par.o).

In the sub directories (./0, ./1, ...) you get information from every CAN channel. Some 
information are write only and some are read only:
- ./baudrate (read/write: one line with decimal integer value)
- ./busload (read: busload in percentage  => not implemented yet)
- ./filter (read/write: one line with 2 values hexadecimal acceptance filter)
- ./format (read/write: one line with 1 value integer: 0=default, 1=11 bit, 2=29 bit)
- ./lost (read: lost messages while receiving)
- ./mode (read/write: one line with 1 value integer: 0=CAN 2.0A   1=CAN 2.0B PeliCAN)
- ./receive (XXX: TODO)
- ./standby (read/write: one line with 1 value integer: 0=active  1=standby)
- ./transmit (write: one line with a CAN message, all values hexadecimal:   [])
- ./virtualize (read/write: one line with 1 value integer: 0=virtualize off   1=virtualize on)
- ./information (read: information about the CAN channel)


****************************************************************************
Access with scripts:
To set all values, you can use the /proc filesystem and the echo command:
Examples:

Baudrate:   echo 500000 > /proc/canbus/0/baudrate
Filter  :   echo "ffffffff ffffffff" > /proc/canbus/0/filter
Transmit:   echo "1234 0 11 22 33 44 55 66 77 88" > /proc/canbus/0/transmit

To receive CAN messages, you can use the "cat" command:
cat /dev/can0

If some data will received, you get a line shown below:

received  1010852408:682453  00000111   0  0  [n data bytes]  0
    |              |            |       |  |        |         |---- lost messages
    |              |            |       |  |        |-------------- n data bytes (max. 8)
    |              |            |       |  |----------------------- dlc (data length code = number of received bytes)
    |              |            |       |-------------------------- rtr (remote transmission request bit)
    |              |            |---------------------------------- CAN id
    |              |----------------------------------------------- 64 bit system time
    |-------------------------------------------------------------- meaning of this event

Of course you can write CAN messages into a simple text file and 'copy' this
file to the CAN device:
content of simple.txt:
1234 0 11 22 33 44 55 66 77 88
0188 0 11 22

(Very important is the linefeed, don't forget a linefeed at the last line!)

Copying:
cp simple.txt /dev/can0

All messages in the text file will be sent over CAN bus.



If you use scripting, it's better to turn off virtualization:
echo 0 > /proc/canbus/0/virtualize
                                                    

****************************************************************************
Accessing CAN bus using read/write and /proc - filesystem:
First open the CAN driver (for example /dev/can0). After that you
can read or write values into /proc - filesystem (see also above "Accessing CAN bus with scripts").

Example: Write one message
FILE *canbus;
canbus = fopen("/dev/can0","w");
if(canbus)
{
     fprintf(canbus,"1234 0 11 22 33 44 55 66 77 88\n");  // the \n is important !!
     fclose(canbus);
}

Example: Read one message
FILE *canbus;
canbus = fopen("/dev/can0","r");
if(canbus)
{
     char buffer[100];
     fgets(buffer,sizeof(buffer),canbus);
     printf(buffer);
     fclose(canbus);
}

Example: Set baudrate
FILE *canbus;
canbus = fopen("/proc/canbus/0/baudrate","w");
if(canbus)
{
     fprintf(canbus,"500000");
     fclose(canbus);
}

All other /proc/canbus parameters are described in "Accessing CAN bus with scripts".


****************************************************************************
Accessing CAN bus using ioctl: (recommended method)


In C or C++ programs, the header file "canbus4linux.h" can be used.

----------------------------------------------------------------------------
Open and close a CAN device with read/write access:

    int file;

    file = open("/dev/can0",O_RDWR);
    if(file == -1)
    {
        printf("can't open canbus4linux device\n");
    }
    else
    {
        // Because of following 2 lines, a signal is generated on every event 
        // (receiving, transmitting, errors, warnings,...)
        fcntl(file,F_SETOWN,getpid());
        fcntl(file,F_SETFL, FASYNC | fcntl(file,F_GETFL));
    }

Later close the CAN device:
    if(file != -1)
    {
        close(file);
    }

----------------------------------------------------------------------------
Determine CAN driver properties:

    struct canbus_properties properties;
    ioctl(file, CANBUS4LINUX_READ_PROPERTIES, &properties);



    The properties are:
    version           Version number of canbus4linux
    device_name[]     A string with the channel name, this string can displayed for 
	                  user information
    min               Minimal supported baudrate
    max               Maximal supported baudrate
    commands[]        An array with supported commands of this CAN channel, all known commands
	                  of canbus4linux are:
	                     CANBUS_CMD_ENTER_STANDBY,
	                     CANBUS_CMD_LEAVE_STANDBY,
	                     CANBUS_CMD_ABORT_TRANSMISSION,
	                     CANBUS_CMD_CLEAR_OVERRUN,
	                     CANBUS_CMD_SELF_RECEPTION_REQUEST,
	                     CANBUS_CMD_LISTEN_ON,
	                     CANBUS_CMD_LISTEN_OFF,
	                     CANBUS_CMD_VIRTUALIZE_ON,
	                     CANBUS_CMD_VIRTUALIZE_OFF,
    number_commands   Number of valid entries in "commands[]"
    baudrates[]       (Optional) An array with supported baudrates of this CAN channel
    number_baudrates  Number of valid entries in "baudrates[]"
    chipset_flags     Bit field, which describes some features of the CAN channel:
	                     CANBUS_CFS_CAN_2_0_A     channel support CAN 2.0 A (Basic CAN)
	                     CANBUS_CFS_CAN_2_0_B     channel support CAN 2.0 B
	                     CANBUS_CFS_EXT_FRAME     channel support extended frame format (only used if 
	                                              supports CAN 2.0 B too)
	                     CANBUS_CFS_POLLING       channel is not(!) interrupt driven, all
	                                              data must get with polling method
    number_registers  Number of supported registers


    Note:
    CANBUS_CFS_POLLING is not implemented yet
    number_registers is not implemented yet

----------------------------------------------------------------------------
Init CAN channel:

To init the CAN channel, this function is used:
    ioctl(file, CANBUS4LINUX_INIT, 0);

----------------------------------------------------------------------------
Read/Write acceptance filter:

Read acceptance filter
    struct canbus_acceptance_filter filter;
    ioctl(file, CANBUS4LINUX_READ_ACCEPTANCE_FILTER, &filter);

Write acceptance filter:
    struct canbus_acceptance_filter filter;
    filter.code = .....;
    filter.mask = .....;
    ioctl(file, CANBUS4LINUX_WRITE_ACCEPTANCE_FILTER, &filter);

----------------------------------------------------------------------------
Read/Write baudrate:

Read baudrate (baudrate is calculated by driver):
    baudrate = ioctl(file, CANBUS4LINUX_GET_BAUDRATE, 0);

Write baudrate (baudrate is calculated by driver):
    ioctl(file, CANBUS4LINUX_SET_BAUDRATE, );

Read baudrate (baudrate is a constant):
    index = ioctl(file, CANBUS4LINUX_GET_BAUDRATE_BY_CONSTANT, 0);

Write baudrate (baudrate is a constant):
    ioctl(file, CANBUS4LINUX_SET_BAUDRATE_BY_CONSTANT, );

----------------------------------------------------------------------------
Set CAN mode (2.0A or 2.0B)

Set to CAN 2.0 A:
    ioctl(file, CANBUS4LINUX_SET_CAN_MODE, CANBUS_FORMAT_CAN_2_0_A);

Set to CAN 2.0 B:
    ioctl(file, CANBUS4LINUX_SET_CAN_MODE, CANBUS_FORMAT_CAN_2_0_B);

----------------------------------------------------------------------------
Set default frame format:

Set frame format in dependency of CAN mode. If CAN 2.0A is selected the
frame format is always 11 bit (standard frame format). If CAN 2.0B
the frame format can be 11 bit (CANBUS_TRANS_FMT_STD) or 29 bit (CANBUS_TRANS_FMT_EXT). 

Set to standard frames:
    ioctl(file, CANBUS4LINUX_SET_DEFAULT_FRAME_FORMAT, CANBUS_TRANS_FMT_STD);

Set to extended frames:
    ioctl(file, CANBUS4LINUX_SET_DEFAULT_FRAME_FORMAT, CANBUS_TRANS_FMT_EXT);

----------------------------------------------------------------------------
Hardware test:

Test if the hardware is installed. This is useful for external CAN devices, e.g for 
the parallel port or for USB or other ports.

    if (ioctl(file, CANBUS4LINUX_TEST_DEVICE, 0) > 0)
    {
    	// CAN device is installed
    }
    else
    {
    	// CAN device is not installed or an error ocured (return value < 0)
    }

----------------------------------------------------------------------------
Read time:

With every event you get an absolute time stamp from the can driver. Also the actually time
can be read with this function. 

    struct canbus_time time;
    ioctl(file, CANBUS4LINUX_READ_TIME, &time);

The time is a 64 bit value, with a resolution of 1 microsecond.

    struct canbus_time
    {
        unsigned long low;
        unsigned long high;
    };

If relative timings are needed, it must be calculated in the application, for example:

    ....
    time1 = read time with above function
    ...
    ...
    time2 = event from driver
    difference = time2 - time1
    time1 = time2
    ...
    ...
    time2 = event from driver
    difference = time2 - time1
    ...
    ...
    etc.
    

----------------------------------------------------------------------------
Transmit a CAN message:

To transmit a message, this call is used. In CAN 2.0B mode the CAN id format
can be specified in entry: "fmt" in the canbus_transmit_data structure.
If this entry is 0, the default (set by: CANBUS4LINUX_SET_DEFAULT_FRAME_FORMAT)
is used. In mode CAN 2.0A always standard frame format is used.

Example:
	struct canbus_transmit_data data;
	data.fmt = 0;
	data.identifier = 0x1234
	data.rtr = 0;
	data.dlc = 8;
	data.msg[0] = 0x11;
	data.msg[1] = 0x22;
	data.msg[2] = 0x33;
	data.msg[3] = 0x44;
	data.msg[4] = 0x55;
	data.msg[5] = 0x66;
	data.msg[6] = 0x77;
	data.msg[7] = 0x88;
	ioctl(file, CANBUS4LINUX_WRITE_TRANSMIT_DATA, &data);

canbus_transmit_data structure:
    fmt           Format of the transmitted CAN id
                     CANBUS_TRANS_FMT_DEFAULT  use default format set by
                                               ioctl(CANBUS4LINUX_SET_DEFAULT_FRAME_FORMAT)
                     CANBUS_TRANS_FMT_STD      force standard frame format
                     CANBUS_TRANS_FMT_EXT      force extended frame format (only useful
                                               in CAN 2.0B mode)
    identifier    CAN identifier 11 or 29 bit
    rtr           0=data frame   1=remote transmission frame
    dlc           data length code = number of valid entries in msg[]
    msg[]         data bytes, maximal 8 bytes msg[0]...msg[7]

----------------------------------------------------------------------------
Event processing:

The driver can send signals to the application. For example if following
lines are pass through after opening the CAN driver:
    fcntl(file,F_SETOWN,getpid());
    fcntl(file,F_SETFL, FASYNC | fcntl(file,F_GETFL));

To receive a signal in the application you need further code as shown here:

void SignalFromDriver(int signum)
{
    struct canbus_event data;

    while(1)
    {
        if (ioctl(file, CANBUS4LINUX_READ_EVENT_DATA, &data) <= 0)
        {
            break;
        }
        // interpret event:
        switch(data.event)
        {
        case CANBUS_EVENT_RECEIVED:
            // do something...
            break;
        case CANBUS_EVENT_TRANSMITTED:
            // do something...
            break;
        case CANBUS_EVENT_BUS_ERROR:
            // do something...
            break;
        case CANBUS_EVENT_WARNING:
            // do something...
            break;
        case CANBUS_EVENT_LEAVING_STANDBY:
            // do something...
            break;
        case CANBUS_EVENT_ARBITRATION_LOST:
            // do something...
            break;
        case CANBUS_EVENT_OVERRUN:
            // do something...
            break;
        case CANBUS_EVENT_PASSIVE:
            // do something...
            break;
        case CANBUS_EVENT_ENTERING_STANDBY:
            // do something...
            break;
        case CANBUS_EVENT_DEVICE_CHANGED:
            // do something...
            break;
		}
	}
	return;
}


void Init()
{
     // open CAN device and other initialization's
     file = open("/dev/can0",O_RDWR);
     if(file == -1)
     {
        printf("can't open canbus4linux device\n");
        return;
     }
     else
     {
        // Because of the next 2 lines, a signal is generated on every event 
        // (receiving, transmitting, errors, warnings,...)
        fcntl(file,F_SETOWN,getpid());
        fcntl(file,F_SETFL, FASYNC | fcntl(file,F_GETFL));
     }
     // now CAN device is ready to create signals
     
     // install signal handler
   	 struct sigaction sa;
	 memset(&sa,0,sizeof(sa));
	 sa.sa_handler = Refresh;
	 sa.sa_flags = SA_RESTART;
	 sigaction(SIGIO,&sa,0);
}

All events are buffered in driver and at least one signal will be sent to the
application. In the application all events are get with CANBUS4LINUX_READ_EVENT_DATA.


****************************************************************************
Implementing a layer 1 driver:

Layer 1 driver (described in above model with SJA1000) need functions to:
- open and close the CAN channel
- 2 functions (read/write) for chip access with Reset-Bit=0
- 2 functions (read/write) for chip access with Reset-Bit=1
- a function to register a callback function from layer 2 for hardware interrupts
- a function to free the callback from layer 2
- if the driver have set CANBUS_CFS_POLLING, a callback function will not registered
  (this feature is not implemented yet!)

Also the layer 2 (sja1000.o) need some information about the hardware and the layer 1
driver:
- bCanChipsetFlags         With the following flags you specify the
                           features of the hardware:
                           CANBUS_CFS_CAN_2_0_A    Chipset support CAN 2.0 A
                           CANBUS_CFS_CAN_2_0_B    Chipset support CAN 2.0 B
                           CANBUS_CFS_EXT_FRAME    Chipset support extended frame format 
                                                   This feature is used only if CANBUS_CFS_CAN_2_0_B 
                                                   is set
                           CANBUS_CFS_POLLING      Chipset driver supports only polling
                                                   (not implemented yet)

                           For a 82C200 chip the bits: 
                           CANBUS_CFS_2_0_B and CANBUS_CFS_EXT_FRAME
                           are never set.                           
- chipset_frequency        Frequency of crystal (mostly 24MHz or 16 MHz, CAN200 project use 8MHz)
                           This information is needed to calculate the baudrate
- output_control_register  The setting of this register in the SJA1000 chip. This information
                           is needed to initialize the sja1000 chip.


To register the driver at layer 2, a structure (sja_1000_access) must be filled out:
 
     struct sja1000_access
     {
          sja1000_openCanDevice        pOpenCanDevice;
          sja1000_closeCanDevice       pCloseCanDevice;
          sja1000_writeToRegister      pWriteToRegister;
          sja1000_writeToRegisterRR    pWriteToRegisterRR;
          sja1000_readFromRegister     pReadFromRegister;
          sja1000_readFromRegisterRR   pReadFromRegisterRR;
          sja1000_registerIsr          pRegisterIsr;
          sja1000_unregisterIsr        pUnregisterIsr;
          int                          bCanChipsetFlags;  // show Flags: CANBUS_CSF_...
          int                          chipset_frequency;
          unsigned char                output_control_register;
     };

The first parameter in every function is a pointer to a user structure of the layer 1 driver. 
In this structure every driver can save settings and/or variables. Example:

       ---------------------  registering ->
       |                   |-------------------- sja1000_register_device("name", , ...);
       | Layer 1  driver   |                                 |
       |                   |                                 |
       |                   |<---------------------------------
       |          ---------|       call functions; example: openCanDevice();
       |          |  var.  |                                   
       |          |        |
       ---------------------

       var. = user structure of every driver

While registering a layer 1 driver with "sja1000_register_device()", the pointer of this user structure
will be saved in the next layer 2 and will used in every function call.

int openCanDevice(void *pSpecificPar);
    Parameter: pointer to user structure
    Return:    standard return values (0 = OK)

    This function is called to open the can channel. In this function you can claim hardware
    resources. Don't initialize the CAN hardware in this function!

int closeCanDevice(void *pSpecificPar);
    Parameter: pointer to user structure
    Return:    standard return values (0 = OK)

    This function is called to close the can channel. In this function you can free hardware
    resources.

void writeToRegister(void *pSpecificPar, unsigned char adr, unsigned char value);
    Parameter: pointer to user structure
               sja1000 register addresse (0...127)
               value to write 

    This function is called to write data into sja1000. While access, the Reset-Bit should 
    set to 0.

void writeToRegisterRR(void *pSpecificPar, unsigned char adr, unsigned char value);
    Parameter: pointer to user structure
               sja1000 register addresse (0...127)
               value to write 

    This function is called to write data into sja1000. While access, the Reset-Bit should 
    set to 1.

unsigned char readFromRegister(void *pSpecificPar, unsigned char adr);
    Parameter: pointer to user structure
               sja1000 register addresse (0...127)
    Return:    value of sja1000 register

    This function is called to read data from sja1000. While access, the Reset-Bit should 
    set to 0.

unsigned char readFromRegisterRR(void *pSpecificPar, unsigned char adr);
    Parameter: pointer to user structure
               sja1000 register addresse (0...127)
    Return:    value of sja1000 register

    This function is called to read data from sja1000. While access, the Reset-Bit should 
    set to 1.


****************************************************************************