drivers/can_kvaser/can_kvaser.c
author Robert Lehmann <robert.lehmann@sitec-systems.de>
Tue, 28 Jul 2015 16:36:55 +0200
changeset 793 72e9e1064432
parent 631 08b6b903f84a
permissions -rw-r--r--
timers_unix: Fix termination problem of WaitReceiveTaskEnd

The function pthread_kill sends the Signal thread and to the own process.
If you use this construct than the application which calls uses the
canfestival api will terminate at the call of canClose. To avoid that
use pthread_cancel instead of pthread_kill. To use the pthread_cancel call
you need to set the cancel ability in the thread function. That means
you need to call pthread_setcancelstate and pthread_setcanceltype.
For the termination of the thread at any time it is important to set the
cancel type to PTHREAD_CANCEL_ASYNCHRONOUS.

/*
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;
}