etisserant@400: 
etisserant@400: /*
etisserant@400: Copyright (C): Giuseppe Massimo BERTANI
etisserant@400: gmbertani@users.sourceforge.net
etisserant@400: 
etisserant@400: 
etisserant@400: See COPYING file for copyrights details.
etisserant@400: 
etisserant@400: This library is free software; you can redistribute it and/or
etisserant@400: modify it under the terms of the GNU Lesser General Public
etisserant@400: License as published by the Free Software Foundation; either
etisserant@400: version 2.1 of the License, or (at your option) any later version.
etisserant@400: 
etisserant@400: This library is distributed in the hope that it will be useful,
etisserant@400: but WITHOUT ANY WARRANTY; without even the implied warranty of
etisserant@400: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
etisserant@400: Lesser General Public License for more details.
etisserant@400: 
etisserant@400: You should have received a copy of the GNU Lesser General Public
etisserant@400: License along with this library; if not, write to the Free Software
etisserant@400: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
etisserant@400: */
etisserant@400: 
etisserant@400: /**
etisserant@400:  * @file can_kvaser.c
etisserant@400:  * @author GMB
etisserant@400:  * @date 17/1/08
etisserant@400:  *
etisserant@400:  * This file is needed to interface Kvaser's CAN Leaf (USB-CAN adapter) 
etisserant@400:  * and probably others Kvaser's products compatible with Kvaser's CANLIB,
etisserant@400:  * to CANfestival open source CANopen stack.
etisserant@400:  *
etisserant@400:  * It was tested under Linux 2.6 with "Leaf Professional" and CANLIB 4.72 Beta (Oct 1,2007)
etisserant@400: */
etisserant@400: 
etisserant@400: #include <stdio.h>
etisserant@400: #include <string.h>
etisserant@400: #include <errno.h>
etisserant@400: #include <fcntl.h>
etisserant@400: #include <signal.h>
etisserant@400: #include <unistd.h>
etisserant@400: 
etisserant@400: /* includes Kvaser's CANLIB header */
etisserant@400: #include <canlib.h>
etisserant@400: 
etisserant@400: #include "can_driver.h"
etisserant@400:  
etisserant@400:     
etisserant@400: /**
etisserant@400:  * CAN_HANDLES must have value >=1 while CANLIB wants handles >= 0
etisserant@400:  * so fd0 needs to be decremented before use.
etisserant@400:  *
etisserant@400:  */ 
etisserant@400: UNS8 canReceive_driver(CAN_HANDLE fd0, Message *m)
etisserant@400: {
etisserant@400: canStatus retval = canOK;
etisserant@400: unsigned flags = 0;
etisserant@400: unsigned long timeStamp;
etisserant@400: 
etisserant@400:     fd0--;
etisserant@400: 
etisserant@400:     /* checking for input message (blocking) */
etisserant@400:     retval = canReadWait((int)fd0, (long*)&m->cob_id, &m->data, (unsigned*)&m->len, &flags, &timeStamp, -1);
etisserant@400:     if (retval != canOK)
etisserant@400:     {
etisserant@400:   	    fprintf(stderr, "canReceive_driver (Kvaser) : canReadWait() error, cob_id=%08X, len=%u, flags=%08X, returned value = %d\n", 
etisserant@400:                 m->cob_id, m->len, flags, retval);
etisserant@400:         canClose((int)fd0);
etisserant@400:         return retval;
etisserant@400:     }
etisserant@400: 
etisserant@400:     m->rtr = 0;
etisserant@400:     if (flags & canMSG_RTR)
etisserant@400:     {
etisserant@400:         m->rtr = 1;
etisserant@400:     }
etisserant@400: 
etisserant@400:     if (flags & canMSG_EXT)
etisserant@400:     {
etisserant@400:         /* TODO: is it correct to set this info in cob_id? */
etisserant@400:         m->cob_id |= 0x20000000;
etisserant@400:     }
etisserant@400:     
etisserant@400:     //fprintf(stderr, "canReceive_driver (Kvaser) : canReadWait() received packet, cob_id=%08X, len=%u, flags=%08X, timestamp=%d  returned value = %d\n", 
etisserant@400:     //       m->cob_id, m->len, flags, timeStamp, retval);
etisserant@400: 
etisserant@400:     return retval;
etisserant@400: }
etisserant@400: 
etisserant@400: /**
etisserant@400:  *
etisserant@400:  * CAN_HANDLES must have value >=1 while CANLIB wants handles >= 0
etisserant@400:  * so fd0 needs to be decremented before use.
etisserant@400:  *
etisserant@400:  */ 
etisserant@400: UNS8 canSend_driver(CAN_HANDLE fd0, Message *m)
etisserant@400: {
etisserant@400: canStatus retval = canOK;
etisserant@400: unsigned flags = 0;
etisserant@400: 
etisserant@400:     fd0--;
etisserant@400: 
etisserant@400:     flags |= canMSG_STD;
etisserant@400:     
etisserant@400:     if (m->cob_id & 0x20000000)
etisserant@400:     {
etisserant@400:         /* TODO: is it correct to desume this info from cob_id? */
etisserant@400:         flags |= canMSG_EXT;
etisserant@400:     }
etisserant@400: 
etisserant@400:     if (m->cob_id & 0x40000000)
etisserant@400:     {
etisserant@400:         flags |= canMSG_RTR;
etisserant@400:     }
etisserant@400: 
etisserant@400:     /*
etisserant@400:      * TODO: when should I set canMSG_ERROR_FRAME?
etisserant@400:      */ 
etisserant@400:     
etisserant@400:     retval = canWriteWait((int)fd0, m->cob_id, m->data, m->len, 10000, flags);
etisserant@400:     if (retval != canOK)
etisserant@400:     {
etisserant@400:   	    fprintf(stderr, "canSend_driver (Kvaser) :  canWriteWait() error, cob_id=%08X, len=%u, flags=%08X, returned value = %d\n", 
etisserant@400:                 m->cob_id, m->len, flags, retval);
etisserant@400:         canClose((int)fd0);
etisserant@400:         return retval;
etisserant@400:     }
etisserant@400:    
etisserant@400:     //fprintf(stderr, "canSend_driver (Kvaser) :  canWriteWait() send packet, cob_id=%08X, len=%u, flags=%08X, returned value = %d\n", 
etisserant@400:     //            m->cob_id, m->len, flags, retval);
etisserant@400:     return retval; 
etisserant@400: 
etisserant@400: }
etisserant@400: 
etisserant@400: 
etisserant@400: /**
etisserant@400:  * 
etisserant@400:  */ 
etisserant@400: int TranslateBaudRate(char* optarg)
etisserant@400: {
etisserant@400: 	if(!strcmp( optarg, "1M")) 
etisserant@400:         return BAUD_1M;
etisserant@400: 	if(!strcmp( optarg, "500K")) 
etisserant@400:         return BAUD_500K;
etisserant@400: 	if(!strcmp( optarg, "250K")) 
etisserant@400:         return BAUD_250K;
etisserant@400: 	if(!strcmp( optarg, "125K")) 
etisserant@400:         return BAUD_125K;
etisserant@400: 	if(!strcmp( optarg, "100K")) 
etisserant@400:         return BAUD_100K;
etisserant@400: 	if(!strcmp( optarg, "62K")) 
etisserant@400:         return BAUD_62K;
etisserant@400: 	if(!strcmp( optarg, "50K")) 
etisserant@400:         return BAUD_50K;
etisserant@400: 
etisserant@400: 	return 0;
etisserant@400: }
etisserant@400: 
etisserant@400: /**
etisserant@400:  * Channels and their descriptors are numbered starting from zero.
etisserant@400:  * So I need to increment by 1 the handle returned by CANLIB because
etisserant@400:  * CANfestival CAN_HANDLEs with value zero are considered NOT VALID. 
etisserant@400:  * 
etisserant@400:  * The baud rate could be given directly as bit/s
etisserant@400:  * or using one of the BAUD_* constants defined
etisserant@400:  * in canlib.h
etisserant@400:  */ 
etisserant@400: CAN_HANDLE canOpen_driver(s_BOARD *board)
etisserant@400: {
etisserant@400: int fd0 = -1;
etisserant@400: int channel, baud;
etisserant@400: canStatus retval = canOK;
etisserant@400: 
etisserant@400:     fd0--;
etisserant@400: 
etisserant@400:     sscanf(board->busname, "%d", &channel);  
etisserant@400: 
etisserant@400:     baud = TranslateBaudRate(board->baudrate);
etisserant@400: 
etisserant@400:     if (baud == 0)
etisserant@400:     {
etisserant@400:         sscanf(board->baudrate, "%d", &baud);
etisserant@400:     }
etisserant@400: 
etisserant@400:     fd0 = canOpenChannel(channel, canWANT_EXCLUSIVE|canWANT_EXTENDED);
etisserant@400:     if (fd0 < 0)
etisserant@400:     {
etisserant@400:   	    fprintf(stderr, "canOpen_driver (Kvaser) : error opening channel %d\n", channel);
etisserant@400:         return (CAN_HANDLE)(fd0+1);
etisserant@400:     }
etisserant@400:     canBusOff(fd0);
etisserant@400: 
etisserant@400:     /* values for tseg1, tseg2, sjw, noSamp and  syncmode
etisserant@400:      * come from canlib example "simplewrite.c". The doc
etisserant@400:      * says that default values will be taken if baud is one of
etisserant@400:      * the BAUD_* values
etisserant@400:      */ 
etisserant@400:     retval = canSetBusParams(fd0, baud, 4, 3, 1, 1, 0);
etisserant@400:     if (retval != canOK)
etisserant@400:     {
etisserant@400:   	    fprintf(stderr, "canOpen_driver (Kvaser) :  canSetBusParams() error, returned value = %d, baud=%d, \n", retval, baud);
etisserant@400:         canClose((int)fd0);
etisserant@400:         return (CAN_HANDLE)retval;
etisserant@400:     }
etisserant@400:     
etisserant@400:     canSetBusOutputControl(fd0, canDRIVER_NORMAL);
etisserant@400:     if (retval != canOK)
etisserant@400:     {
etisserant@400:   	    fprintf(stderr, "canOpen_driver (Kvaser) :  canSetBusOutputControl() error, returned value = %d\n", retval);
etisserant@400:         canClose((int)fd0);
etisserant@400:         return (CAN_HANDLE)retval;
etisserant@400:     }
etisserant@400: 
etisserant@400: 
etisserant@400: 
etisserant@400:     
etisserant@400:     retval = canBusOn(fd0);
etisserant@400:     if (retval != canOK)
etisserant@400:     {
etisserant@400:   	    fprintf(stderr, "canOpen_driver (Kvaser) :  canBusOn() error, returned value = %d\n", retval);
etisserant@400:         canClose((int)fd0);
etisserant@400:         return (CAN_HANDLE)retval;
etisserant@400:     }
etisserant@400:     
etisserant@400:     return (CAN_HANDLE)(fd0+1);
etisserant@400: 
etisserant@400: }
etisserant@400: 
etisserant@400: UNS8 canChangeBaudRate_driver( CAN_HANDLE fd0, char* baud)
etisserant@400: {
etisserant@400: int baudrate;
etisserant@400: canStatus retval = canOK;
etisserant@400: 
etisserant@400: 
etisserant@400:     baudrate = TranslateBaudRate(baud);
etisserant@400:     if (baudrate == 0)
etisserant@400:     {
etisserant@400:         sscanf(baud, "%d", &baudrate);
etisserant@400:     }
etisserant@400: 
etisserant@400: 
etisserant@400:     fprintf(stderr, "%x-> changing to baud rate %s[%d]\n", (int)fd0, baud, baudrate); 
etisserant@400:     
etisserant@400:     canBusOff((int)fd0);
etisserant@400: 
etisserant@400:     /* values for tseg1, tseg2, sjw, noSamp and  syncmode
etisserant@400:      * come from canlib example "simplewrite.c". The doc
etisserant@400:      * says that default values will be taken if baud is one of
etisserant@400:      * the BAUD_* values
etisserant@400:      */ 
etisserant@400:     retval = canSetBusParams((int)fd0, baudrate, 4, 3, 1, 1, 0);
etisserant@400:     if (retval != canOK)
etisserant@400:     {
etisserant@400:   	    fprintf(stderr, "canChangeBaudRate_driver (Kvaser) :  canSetBusParams() error, returned value = %d, baud=%d, \n", retval, baud);
etisserant@400:         canClose((int)fd0);
etisserant@400:         return (UNS8)retval;
etisserant@400:     }
etisserant@400:     
etisserant@400:     canSetBusOutputControl((int)fd0, canDRIVER_NORMAL);
etisserant@400:     if (retval != canOK)
etisserant@400:     {
etisserant@400:   	    fprintf(stderr, "canChangeBaudRate_driver (Kvaser) :  canSetBusOutputControl() error, returned value = %d\n", retval);
etisserant@400:         canClose((int)fd0);
etisserant@400:         return (UNS8)retval;
etisserant@400:     }
etisserant@400:     
etisserant@400:     retval = canBusOn((int)fd0);
etisserant@400:     if (retval != canOK)
etisserant@400:     {
etisserant@400:   	    fprintf(stderr, "canChangeBaudRate_driver (Kvaser) :  canBusOn() error, returned value = %d\n", retval);
etisserant@400:         canClose((int)fd0);
etisserant@400:         return (UNS8)retval;
etisserant@400:     }
etisserant@400: 
etisserant@400:     return 0;
etisserant@400: }
etisserant@400: 
etisserant@400: 
etisserant@400: /**
etisserant@400:  *
etisserant@400:  * CAN_HANDLES must have value >=1 while CANLIB wants handles >= 0
etisserant@400:  * so fd0 needs to be decremented before use.
etisserant@400:  */ 
etisserant@400: int canClose_driver(CAN_HANDLE fd0)
etisserant@400: {
etisserant@400: canStatus retval = canOK;
etisserant@400: 
etisserant@400:     fd0--;
etisserant@400:     
etisserant@400:     retval = canBusOff((int)fd0);
etisserant@400:     if (retval != canOK)
etisserant@400:     {
etisserant@400:   	    fprintf(stderr, "canClose_driver (Kvaser) :  canBusOff() error, returned value = %d\n", retval);
etisserant@400:         canClose((int)fd0);
etisserant@400:         return retval;
etisserant@400:     }
etisserant@400:     
etisserant@400:     retval = canClose((int)fd0);
etisserant@400:     if (retval != canOK)
etisserant@400:     {
etisserant@400:   	    fprintf(stderr, "canClose_driver (Kvaser) :  canClose() error, returned value = %d\n", retval);
etisserant@400:         return retval;
etisserant@400:     }
etisserant@400:     
etisserant@400:     return retval;
etisserant@400: }
etisserant@400: