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