Send timeout is set to 10 ms. Without timeout PLC can be blocked by CAN driver: if CAN bus is not connected to controller CAN driver never returns and therfore PLC application halts. This is a temporary solution.
/*
This file is part of CanFestival, a library implementing CanOpen Stack.
Copyright (C): Edouard TISSERANT and Francis DUPIN
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
*/
/*
Wrapper Layer for CANFestival to interact with IXXAT VCI V3.X.X Drivers (vcisdk.lib)
Provides external references for win32 library see win32.c (CanFestival-3)
http://www.ixxat.com/download_vci_v3_en.html
Currently the VCI CAN driver for Windows supports the following IXXAT interfaces:
PC-I 04/PCI
iPC-I 320/PCI II
iPC-I 165/PCI
iPC-I XC16/PCI
iPC-I XC16/PMC
iPC-I XC16/PCIe
USB-to-CAN compact
USB-to-CAN II
CAN-IB100/PCIe
CAN-IB200/PCIe
CAN-IB120/PCIe Mini
CAN-IB130/PCIe 104
CAN-IB230/PCIe 104
CAN@net II/VCI
CANblue II
FR-IB100/PCIe (only in combination with VCI V2.20)
tinCAN 161
*/
/*************************************************************************
**
**************************************************************************
**
** File: can_ixxat_win32.c
** Summary: Wrapper to encapsulate handling of VCI3
** Include vcisdk.lib
**
**************************************************************************
**************************************************************************
**
** Functions: canOpen_driver
** canReceive_driver
** TimerProc1
** canClose_driver
** canSend_drive
**
**/
#include <stdio.h>
#include "can_driver.h"
#include "def.h"
#include "winuser.h"
// Include a path to the following header files provided with VCI V3.X.X
// ...sdk/Microsoft_VisualC/inc
#include "vcinpl.h"
#include "VCI3.h"
#include "vcitype.h"
#include "vciguid.h"
#include "vcierr.h"
/************************************************************************
** bus status polling cycle milliseconds
*************************************************************************/
#define STATUS_POLLING_CYCLE 1000
/*************************************************************************
** function prototypes
*************************************************************************/
void CALLBACK TimerProc1(void* lpParametar, BOOL TimerOrWaitFired );
void Display_Error(HRESULT hResult);
/*************************************************************************
** static variables
*************************************************************************/
static HANDLE hDevice; // device handle
static LONG lCtrlNo; // controller number
static HANDLE hCanCtl; // controller handle
static HANDLE hCanChn; // channel handle
static LONG lMustQuit = 0; // quit flag for the receive thread
static HANDLE hTimerHandle; // timer handle
/*************************************************************************
** datatypes
*************************************************************************/
struct sLook_up_table
{
char baud_rate[20];
UINT8 bt0;
UINT8 bt1;
};
struct sInterface_lookup_table
{
char board_num[10];
UINT8 num;
};
/*************************************************************************
**
** Function : canOpen_driver
**
** Description : Initializes the Control and Message Channels
** Parameters : s_BOARD *board - pointer to board information
** Returnvalue : (CAN_HANDLE)board - handle for CAN controller
**
*************************************************************************/
CAN_HANDLE __stdcall canOpen_driver(s_BOARD *board)
{
HANDLE hEnumerator; // enumerator handle
VCIDEVICEINFO VCIDeviceInfo; // device info
HRESULT hResult;
int index, boardNum;
BOOL bResult;
struct sLook_up_table sBitRate_lookup[9] = {
{"10K",0x31,0x1C},
{"20K",0x18,0x1C},
{"50K",0x09,0x1C},
{"100K",0x04,0x1C},
{"125K",0x03,0x1C},
{"250K",0x01,0x1C},
{"500K",0x00,0x1C},
{"800K",0x00,0x16},
{"1M",0x00,0x14}};
struct sInterface_lookup_table sInterfaceList[4]={
{"vcan0",0},
{"vcan1",1},
{"vcan2",2},
{"vcan3",3}};
for (boardNum =0 ; boardNum<4;boardNum++) // determine canline selected
{
if (strcmp(sInterfaceList[boardNum].board_num,board->busname )==0)
break;
}
for (index = 0; index < 10; ++index) // determine baudrate
{
if (strcmp(sBitRate_lookup[index].baud_rate,board->baudrate)==0)
break;
}
if (index == 9)
{
MSG_ERR_DRV("IXXAT::open: The given baudrate %S is invalid.", baud_rate);
return NULL ;
}
/*
** The following can be used when the client has multiple CAN interfaces to slect from, and does not wish to use the
** selection dialog box
/*
/*
hResult= vciEnumDeviceOpen(&hEnumerator);
// This loop will increment the index of the device list and returns the decription of the CAN line chose by user
if (hResult== VCI_OK)
{
for (index1=0; index1 <= sInterfaceList[boardNum].num; index1++){
hResult=vciEnumDeviceNext(hEnumerator, &VCIDeviceInfo);
}
}
printf("Device Selected: %s %s\n",VCIDeviceInfo.Manufacturer, VCIDeviceInfo.Description);
if (hResult== VCI_OK)
hResult=vciEnumDeviceClose(hEnumerator);
if (hResult== VCI_OK)
hResult= vciDeviceOpen(&VCIDeviceInfo.VciObjectId, &hDevice);
*/
/*
** Display Interface Selection Dialog Box
*/
hResult= vciDeviceOpenDlg(0, &hDevice);
/*
** Establish and activate the message Channel
*/
if (hResult== VCI_OK)
hResult= canChannelOpen(hDevice, 0, TRUE, &hCanChn);
// Select Rx fifo size, Rx threshold, Tx fifo size, Tx threshold
if (hResult== VCI_OK)
hResult=canChannelInitialize( hCanChn, 1024, 1,128,1);
if (hResult== VCI_OK)
hResult=canChannelActivate(hCanChn, TRUE);
/*
** Establish and Activate the Contol Channel
*/
if (hResult== VCI_OK)
hResult=canControlOpen(hDevice, 0, &hCanCtl);
// Select 11 or 29 bit IDs, Select operating mode
if (hResult== VCI_OK)
hResult=canControlInitialize( hCanCtl, CAN_OPMODE_STANDARD | CAN_OPMODE_ERRFRAME, sBitRate_lookup[index].bt0, sBitRate_lookup[index].bt1 );
// With VCI it is possible to filter IDs, See VCI V3 manual. The following will accept all IDs
if (hResult== VCI_OK)
hResult= canControlSetAccFilter( hCanCtl, FALSE, CAN_ACC_CODE_ALL, CAN_ACC_MASK_ALL);
if (hResult== VCI_OK)
hResult=canControlStart(hCanCtl, TRUE);
if (hResult!=VCI_OK)
{
Display_Error(hResult);
return NULL;
}
/*
** Create timer to poll bus status
*/
bResult= CreateTimerQueueTimer(
& hTimerHandle,
NULL,
TimerProc1, // Callback function
NULL,
0,
STATUS_POLLING_CYCLE,
WT_EXECUTEINIOTHREAD
);
return (CAN_HANDLE)board;
}
/*************************************************************************
**
** Function : canReceive_driver
**
** Description : Transfers RX messages to Festival application
** Parameters : CAN_HANDLE inst - handle for CAN controller
Message *m - pointer to Message struct
** Returnvalue : hResult - VCI_OK if success
**
*************************************************************************/
UNS8 __stdcall canReceive_driver(CAN_HANDLE inst, Message *m)
{
HRESULT hResult;
CANMSG rCanMsg;
//Read message from the receive buffer
hResult=canChannelReadMessage( hCanChn, INFINITE, &rCanMsg );
if (hResult !=VCI_OK )
return 1;
m->cob_id = rCanMsg.dwMsgId;
m->len = rCanMsg.uMsgInfo.Bits.dlc;
m->rtr = rCanMsg.uMsgInfo.Bits.rtr;
if (m->rtr == NOT_A_REQUEST)
memcpy(m->data, rCanMsg.abData , m->len);
return (UNS8)hResult;
}
/*************************************************************************
**
** Function : canSend_driver
**
** Description : Transfers RX messages to Interface
** Parameters : CAN_HANDLE inst - handle for CAN controller
** Message *m - pointer to Message struct
** Returnvalue : hResult - VCI_OK if success
**
*************************************************************************/
UNS8 __stdcall canSend_driver(CAN_HANDLE inst, Message const *m)
{
HRESULT hResult;
CANMSG sCanMsg;
sCanMsg.uMsgInfo.Bytes.bType = CAN_MSGTYPE_DATA;
sCanMsg.uMsgInfo.Bytes.bFlags = CAN_MAKE_MSGFLAGS(8,0,0,0,0);
sCanMsg.uMsgInfo.Bits.srr = 0;
sCanMsg.dwTime = 0;
sCanMsg.dwMsgId = m->cob_id ;
memcpy(sCanMsg.abData,m->data, m->len);
sCanMsg.uMsgInfo.Bits.dlc = m->len;
sCanMsg.uMsgInfo.Bits.rtr=m->rtr;
// write the CAN message into the transmit FIFO without waiting for transmission
hResult = canChannelPostMessage(hCanChn, &sCanMsg);
return (UNS8)hResult;
}
/*************************************************************************
**
** Function : canClose_driver
**
** Description : Close the message and control channel
** Parameters : CAN_HANDLE inst - handle for CAN controller
** Returnvalue :
**
*************************************************************************/
int __stdcall canClose_driver(CAN_HANDLE inst)
{
printf("CAN close \n");
canControlReset(hCanCtl);
canChannelClose(hCanChn);
canControlClose(hCanCtl);
vciDeviceClose(hDevice);
DeleteTimerQueueTimer(NULL,hTimerHandle,NULL);
return 1;
}
/*************************************************************************
**
** Function : canChangeBaudRate_driver
**
** Description : Changes the Baudrate of the interface (not supported)
** Parameters :
** Returnvalue :
**
*************************************************************************/
UNS8 __stdcall canChangeBaudRate_driver( CAN_HANDLE fd, char* baud)
{
//printf("canChangeBaudRate not yet supported by this driver\n");
return 0;
}
/*************************************************************************
**
** Function : TimerProc1
**
** Description : Basic Polling of the the canline status,
** print debug message for buffer overflow, and BUSOFF condition
** Parameters : void* lpParametar, BOOL TimerOrWaitFired
** Returnvalue : none
**
*************************************************************************/
void CALLBACK TimerProc1(void* lpParametar, BOOL TimerOrWaitFired )
{
HRESULT hResult;
CANLINESTATUS canStatus;
/* Establish CAN controller status */
hResult = canControlGetStatus ( hCanCtl, &canStatus);
if (hResult!=VCI_OK)
printf("Error did not read CAN STATUS\n");
switch ( canStatus.dwStatus)
{
case CAN_STATUS_OVRRUN:
printf("Overrun of the recieve buffer\n");
break;
case CAN_STATUS_ERRLIM:
printf("Overrun of the CAN controller error counter \n");
break;
case CAN_STATUS_BUSOFF:
printf("CAN status: BUSOFF");
break;
case CAN_STATUS_ININIT:
break;
case (CAN_STATUS_BUSOFF)+(CAN_STATUS_ININIT):
printf("CAN status: BUSOFF\n");
/*
** Bus off recovery should come after a software reset, and 128*11 recessive bits.
** This can only happen when an Error-Active node sends an active error flag,
** and other nodes respond with Error Echo Flag
*/
break;
default:
break;
}
};
/*************************************************************************
**
** Function : Display_Error
**
** Description : Display the CANline Error
** Parameters : HANDLE hResult
** Returnvalue : none
**
*************************************************************************/
void Display_Error(HRESULT hResult )
{
char szError[VCI_MAX_ERRSTRLEN];
if (hResult != NO_ERROR)
{
if (hResult == -1)
hResult = GetLastError();
szError[0] = 0;
vciFormatError(hResult, szError, sizeof(szError));
printf("Error Establishing CAN channel, Error Code: %s\n",szError);
}
}