The plugin contains 3 files. all are listed below.
hakocan.h
<sxh c; title:hakocan.h>
/ \file hakocan.h
* \ingroup hwmodule
* \brief Hardware abstraction layer for HAKO Tractor can-bus control
*
* This liberary inplements the hardware abstraction layer
* for communicating using CAN-BUS on the KU-Life
* HAKO Automated tractor
*
* Communication is adjusted directly for the instruction-set
* on the HAKO ECU and is based on the HAKO implemention
* project by Anders Reeske Nilsen and Asbjørn Mejnertsen in 2006
*
* \author Nils A. Andersen & Anders Billesø Beck, DTU
* $Rev: 1570 $
* $Date: 2011-07-02 06:52:23 +0200 (Sat, 02 Jul 2011) $
*
*/
#ifndef HAKOCAN_H
#define HAKOCAN_H
extern int initXML(char *);
extern int periodic(int);
extern ”C” int terminate (void) ; No shutdown function
#define RPMCMD 0x200
#define CURVATURECMD 0x141
#define STEERINGREPORTREQ 0x408
#define STEERINGREPORT 0x409
#define CVTCONTROLCMD 0x080
#define STEERINGANGLECMD 0x142
#define HITCHCMD 0x090
#define CVTACK 0x750
#define STEERINGANGLEACK 0x75A
#define STEERINGACK 0x758
#define HORNCMD 0x610
#define HORNACK 0x740
#endif
</sxh>
hakocan.c
<sxh c; title:hakocan.c>
/ \file hakocan.c
* \ingroup hwmodule
* \brief Hardware abstraction layer for HAKO Tractor can-bus control
*
* This liberary inplements the hardware abstraction layer
* for communicating using CAN-BUS on the KU-Life
* HAKO Automated tractor
*
* Communication is adjusted directly for the instruction-set
* on the HAKO ECU and is based on the HAKO implemention
* project by Anders Reeske Nilsen and Asbjørn Mejnertsen in 2006
*
* \author Nils A. Andersen & Anders Billesø Beck, DTU
* $Rev: 1570 $
* $Date: 2011-07-02 06:52:23 +0200 (Sat, 02 Jul 2011) $
*
*/
/
* Copyright 2008 DTU-Elektro, Automation and Control
* Programmers: Nils A. Andersen
* Anders Billesø Beck, DTU
* anders.beck@get2net.dk
*
*/
/ Library version */
#define HAKOCANVERSION “1.1030”
/ Version control information */
#define REVISION “$Rev: 1570 $:”
#define DATE “$Date: 2011-07-02 06:52:23 +0200 (Sat, 02 Jul 2011) $:”
//
#include <sched.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <linux/serial.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <expat.h>
CAN-Driver definitions, placed in include folder
#include <rhd.h>
#include <database.h>
#include <globalfunc.h>
#include “canmsg.h”
#include “hakocan.h”
/ Global variables */
/Index pointers for the variable database
int iSteeringangleref,
iSteeringangle,iSpeedref,iEnginespeedref,iNavigationmoderef,icurvatureref,icurvature,
iNavigationmode,iOdopulses,iOdopulses1,iEnginespeed,iHakostate0,
iHakostate1,iHakostate2,iHakostate3,
iliftinggearpos,ipowertakeoffspeed,iliftinggearstateref,ipowertakeoffstateref,ihitchposref,icvtack,isteeringack,
ig01,ig02,iptor,iauxr,ifll,iflr,ihlght,irlght,ihorn,ihornack,iswitchack;
PThread definitions
pthread_t canrx_thread, canrx_thread1;
pthread_attr_t attr;
/Number of CAN-messages to be send to CAN-bus in every cycle
#define CANTXBUFSIZE 4
/Number of CAN-messages to be received from the CAN-bus in every cycle
#define CANRXBUFSIZE 3
#define DFLTENGSP 50
#define BLOCK_MAX 200
Creation of communication buffers
/Receive buffer for CAN-messages
struct canmsg_t canrxbuf[CANRXBUFSIZE];
/Transmit buffer for CAN-messages
struct canmsg_t cantxbuf[CANTXBUFSIZE];
/CAN port pointer
int can_dev,can_dev1;
/CAN port device identification string
char canDevString[64];
char canDevString1[64];
/Flag to indicate if HakoCan is running or not
static volatile int hakocanRunning = -1;
Function prototypes
int initHakocan(void);
void *canrx_task(void *);
void *canrx_task1(void *);
/ \brief Initialization of the CAN-bus and all rx/tx buffers
*
* All buffers are initilized and database variables are created.
* Finally, the RX Thread is spawned
*
*/
int initHakocan(void)
{
struct canmsg_t msg;
int ret;
union {float a;char b[4];}conv;
Open CAN port
can_dev=open(canDevString,O_RDWR);
if (can_dev<0) {
fprintf(stderr," HakoCan: Error CAN-BUS on %s\n",canDevString);
return -1;
}
if (canDevString1[0]!=0){
can_dev1=open(canDevString1,O_RDWR);
if (can_dev1<0) {
fprintf(stderr," HakoCan: Error CAN-BUS on %s\n",canDevString1);
return -1;
}
else{
printf(" HakoCan: Ports %s and %s open\n",canDevString,canDevString1) ;
}
}
//Create CAN RX Thread
pthread_attr_init(&attr);
pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (pthread_create(&canrx_thread, &attr, canrx_task, 0)) {
perror(" HakoCan: failed");
return -1;
}
if (can_dev1){
pthread_attr_init(&attr);
pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (pthread_create(&canrx_thread1, &attr, canrx_task1, 0)) {
perror(" HakoCan1: failed");
return -1;
}
}
//Create database variables (if everyting works)
iSpeedref=createVariable('w',1,"speedref");
iSteeringangleref = createVariable('w',1,"steeringangleref");
icurvatureref = createVariable('w',1,"curvatureref");
iEnginespeedref = createVariable('w',1,"enginespeedref");
ihitchposref = createVariable('w',1,"hitchposref");
iNavigationmoderef = createVariable('w',1,"hakomanual");
iliftinggearstateref = createVariable('w',1,"liftinggearstateref");
ipowertakeoffstateref = createVariable('w',1,"powertakeoffstateref");
ig01 = createVariable('w',1,"g01");
ig02 = createVariable('w',1,"g02");
iptor = createVariable('w',1,"ptor");
iauxr = createVariable('w',1,"auxr");
ifll = createVariable('w',1,"fll");
iflr = createVariable('w',1,"flr");
ihlght = createVariable('w',1,"hlght");
irlght = createVariable('w',1,"rlght");
ihorn = createVariable('w',1,"horn");
iNavigationmode = createVariable('r',1,"hakonavigationmode");
iSteeringangle = createVariable('r',1,"hakosteeringangle");
icurvature = createVariable('r',1,"curvature");
iOdopulses= createVariable('r',1,"hakoodopulses");
iEnginespeed= createVariable('r',1,"enginespeed");
iHakostate0= createVariable('r',1,"hakostate0");
iHakostate1= createVariable('r',1,"hakostate1");
iHakostate2= createVariable('r',1,"hakostate2");
iHakostate3= createVariable('r',1,"hakostate3");
iliftinggearpos= createVariable('r',1,"liftinggearpos");
ipowertakeoffspeed= createVariable('r',1,"powertakeoffspeed");
ihornack= createVariable('r',1,"hornack");
iswitchack=createVariable('r',1,"switchack");
icvtack=createVariable('r',1,"cvtack");
isteeringack=createVariable('r',1,"steringack");
if (can_dev1){
iOdopulses1= createVariable('r',1,"hakoodopulses1");
printf("hakoodopuses1 created\n");
}
return 1;
}
/ \brief Entry-point for Can-Bus RX Thread
*
* Responsible for reading and parsing all CAN-Bus messages
*
*/
void *canrx_task(void *not_used){
fprintf(stderr, “ HakoCan: Canrx_task running (1030)\n”);
Lock memory - No more allocations
if (mlockall(MCL_CURRENT | MCL_FUTURE))
{
perror(“mlockall”);
exit(-1);
}
/* use real-time (fixed priority) scheduler
* set priority to one less than the maximum
*/
struct sched_param param;
param.sched_priority = sched_get_priority_max(SCHED_RR) - 1;
if (sched_setscheduler(0, SCHED_RR, ¶m)) {
perror(“setscheduler”);
pthread_exit(NULL);
};
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
fprintf(stderr, “signal: can't ignore SIGPIPE.\n”);
Wait to make sure variables are created
while (hakocanRunning < 0) usleep(100000);
while (hakocanRunning) {
int ret, tmp;
struct canmsg_t msg;
union {
short s;
char b[2];
}conv;
receive one CAN message
ret=secureRead(can_dev, &msg, sizeof(struct canmsg_t));
if (ret<0) {
fprintf(stderr,“Error receiving message on CAN-bus\n”);
hakocanRunning = -1; Shutdown!
} else {
Parse input packages
switch(msg.id) {
case 0x105:{
conv.b[0]=msg.data[0];
conv.b[1]=msg.data[1];
setVariable(iSteeringangle, 0, -conv.s);
conv.b[0]=msg.data[2];
conv.b[1]=msg.data[3];
tmp=conv.s;
if 1) ||
2) ||
3)) {
info→skip = info→depth;
return;
} else if (info→depth == 3) info→found = 1;
} else return;
Branch to parse the elements of the XML file.
if (!strcmp(“hakocan”,el)) {
for(i = 0; attr[i]; i+=2) if 4) {
info→enable = 1;
}
if (!info→enable) {
printf(“ HakoCan: Use of HakoCan disabled in configuration\n”);
info→skip = info→depth;
}
} else if (strcmp(“controlcan”,el) == 0) {
Check for the correct depth for this tag
if(info→depth != 4) {
printf(“Error: Wrong depth for the %s tag\n”,el);
}
for(i = 0; attr[i]; i+=2) {
if (strcmp(“port”,attr[i]) == 0) strncpy(canDevString,attr[i+1],63);
if (strcmp(“port1”,attr[i]) == 0) strncpy(canDevString1,attr[i+1],63);
}
printf(“ HakoCan: Using Control CAN-port %s %s\n”,canDevString,canDevString1);
}
}
/Handle XML End tags
void XMLCALL
hakocanEndTag(void *data, const char *el)
{
parseInfo *info = (parseInfo *) data;
info→depth–;
if (info→depth < info→skip) info→skip = 0;
}
</sxh>
canmsg.h
<sxh c; title:canmsg.h>
/ /file canmsg.h
* canmsg.h - common kernel-space and user-space CAN message structure
* Linux CAN-bus device driver.
* Written by Pavel Pisa - OCERA team member
* email:pisa@cmp.felk.cvut.cz
* This software is released under the GPL-License.
* Version lincan-0.3 17 Jun 2004
*/
#ifndef _CANMSG_T_H
#define _CANMSG_T_H
#ifdef KERNEL
#include <linux/time.h>
#include <linux/types.h>
#else /* KERNEL */
#include <sys/time.h>
#include <sys/types.h>
#endif /* KERNEL */
#ifdef cplusplus
extern “C” {
#endif
/*
* CAN_MSG_VERSION_2 enables new canmsg_t layout compatible with
* can4linux project from http://www.port.de/
*
*/
#define CAN_MSG_VERSION_2
/* Number of data bytes in one CAN message */
#define CAN_MSG_LENGTH 8
#ifdef CAN_MSG_VERSION_2
typedef struct timeval canmsg_tstamp_t ;
typedef unsigned long canmsg_id_t;
/
* struct canmsg_t - structure representing CAN message
* @flags: message flags
* %MSG_RTR .. message is Remote Transmission Request,
* %MSG_EXT .. message with extended ID,
* %MSG_OVR .. indication of queue overflow condition,
* %MSG_LOCAL .. message originates from this node.
* @cob: communication object number (not used)
* @id: ID of CAN message
* @timestamp: not used
* @length: length of used data
* @data: data bytes buffer
*
* Header: canmsg.h
*/
struct canmsg_t {
int flags;
int cob;
canmsg_id_t id;
canmsg_tstamp_t timestamp;
unsigned short length;
unsigned char data[CAN_MSG_LENGTH];
};
#else /*CAN_MSG_VERSION_2*/
#ifndef PACKED
#define PACKED attribute5)
#endif
/* Old, deprecated version of canmsg_t structure */
struct canmsg_t {
short flags;
int cob;
canmsg_id_t id;
unsigned long timestamp;
unsigned int length;
unsigned char data[CAN_MSG_LENGTH];
} PACKED;
#endif /*CAN_MSG_VERSION_2*/
typedef struct canmsg_t canmsg_t;
/
* struct canfilt_t - structure for acceptance filter setup
* @flags: message flags
* %MSG_RTR .. message is Remote Transmission Request,
* %MSG_EXT .. message with extended ID,
* %MSG_OVR .. indication of queue overflow condition,
* %MSG_LOCAL .. message originates from this node.
* there are corresponding mask bits
* %MSG_RTR_MASK, %MSG_EXT_MASK, %MSG_LOCAL_MASK.
* %MSG_PROCESSLOCAL enables local messages processing in the
* combination with global setting
* @queid: CAN queue identification in the case of the multiple
* queues per one user (open instance)
* @cob: communication object number (not used)
* @id: selected required value of cared ID id bits
* @mask: select bits significand for the comparation;
* 1 .. take care about corresponding ID bit, 0 .. don't care
*
* Header: canmsg.h
*/
struct canfilt_t {
int flags;
int queid;
int cob;
canmsg_id_t id;
canmsg_id_t mask;
};
typedef struct canfilt_t canfilt_t;
/* Definitions to use for canmsg_t and canfilt_t flags */
#define MSG_RTR (1«0)
#define MSG_OVR (1«1)
#define MSG_EXT (1«2)
#define MSG_LOCAL (1«3)
/* If you change above lines, check canque_filtid2internal function */
/* Additional definitions used for canfilt_t only */
#define MSG_FILT_MASK_SHIFT 8
#define MSG_RTR_MASK (MSG_RTR«MSG_FILT_MASK_SHIFT)
#define MSG_EXT_MASK (MSG_EXT«MSG_FILT_MASK_SHIFT)
#define MSG_LOCAL_MASK (MSG_LOCAL«MSG_FILT_MASK_SHIFT)
#define MSG_PROCESSLOCAL (MSG_OVR«MSG_FILT_MASK_SHIFT)
/* Can message ID mask */
#define MSG_ID_MASK ((1l«29)-1)
#ifdef cplusplus
} /* extern “C”*/
#endif
#endif /*_CANMSG_T_H*/
</sxh>