787
|
1 |
/*
|
|
2 |
This file is part of CanFestival, a library implementing CanOpen Stack.
|
|
3 |
|
|
4 |
Copyright (C): Edouard TISSERANT and Francis DUPIN
|
|
5 |
|
|
6 |
See COPYING file for copyrights details.
|
|
7 |
|
|
8 |
This library is free software; you can redistribute it and/or
|
|
9 |
modify it under the terms of the GNU Lesser General Public
|
|
10 |
License as published by the Free Software Foundation; either
|
|
11 |
version 2.1 of the License, or (at your option) any later version.
|
|
12 |
|
|
13 |
This library is distributed in the hope that it will be useful,
|
|
14 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
16 |
Lesser General Public License for more details.
|
|
17 |
|
|
18 |
You should have received a copy of the GNU Lesser General Public
|
|
19 |
License along with this library; if not, write to the Free Software
|
|
20 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
21 |
*/
|
|
22 |
|
|
23 |
|
|
24 |
/*
|
|
25 |
Wrapper Layer for CANFestival to interact with IXXAT VCI V3.X.X Drivers (vcisdk.lib)
|
|
26 |
Provides external references for win32 library see win32.c (CanFestival-3)
|
|
27 |
|
|
28 |
http://www.ixxat.com/download_vci_v3_en.html
|
|
29 |
|
|
30 |
Currently the VCI CAN driver for Windows supports the following IXXAT interfaces:
|
|
31 |
|
|
32 |
PC-I 04/PCI
|
|
33 |
iPC-I 320/PCI II
|
|
34 |
iPC-I 165/PCI
|
|
35 |
iPC-I XC16/PCI
|
|
36 |
iPC-I XC16/PMC
|
|
37 |
iPC-I XC16/PCIe
|
|
38 |
USB-to-CAN compact
|
|
39 |
USB-to-CAN II
|
|
40 |
CAN-IB100/PCIe
|
|
41 |
CAN-IB200/PCIe
|
|
42 |
CAN-IB120/PCIe Mini
|
|
43 |
CAN-IB130/PCIe 104
|
|
44 |
CAN-IB230/PCIe 104
|
|
45 |
CAN@net II/VCI
|
|
46 |
CANblue II
|
|
47 |
FR-IB100/PCIe (only in combination with VCI V2.20)
|
|
48 |
tinCAN 161
|
|
49 |
|
|
50 |
*/
|
|
51 |
|
|
52 |
|
|
53 |
/*************************************************************************
|
|
54 |
**
|
|
55 |
**************************************************************************
|
|
56 |
**
|
|
57 |
** File: can_ixxat_win32.c
|
|
58 |
** Summary: Wrapper to encapsulate handling of VCI3
|
|
59 |
** Include vcisdk.lib
|
|
60 |
**
|
|
61 |
**************************************************************************
|
|
62 |
**************************************************************************
|
|
63 |
**
|
|
64 |
** Functions: canOpen_driver
|
|
65 |
** canReceive_driver
|
|
66 |
** TimerProc1
|
|
67 |
** canClose_driver
|
|
68 |
** canSend_drive
|
|
69 |
**
|
|
70 |
**/
|
|
71 |
|
|
72 |
#include <stdio.h>
|
|
73 |
#include "can_driver.h"
|
|
74 |
#include "def.h"
|
|
75 |
#include "winuser.h"
|
|
76 |
|
|
77 |
// Include a path to the following header files provided with VCI V3.X.X
|
|
78 |
// ...sdk/Microsoft_VisualC/inc
|
|
79 |
#include "vcinpl.h"
|
|
80 |
#include "VCI3.h"
|
|
81 |
#include "vcitype.h"
|
|
82 |
#include "vciguid.h"
|
|
83 |
#include "vcierr.h"
|
|
84 |
|
|
85 |
|
|
86 |
|
|
87 |
/************************************************************************
|
|
88 |
** bus status polling cycle milliseconds
|
|
89 |
*************************************************************************/
|
|
90 |
#define STATUS_POLLING_CYCLE 1000
|
|
91 |
|
|
92 |
/*************************************************************************
|
|
93 |
** function prototypes
|
|
94 |
*************************************************************************/
|
|
95 |
void CALLBACK TimerProc1(void* lpParametar, BOOL TimerOrWaitFired );
|
|
96 |
void Display_Error(HRESULT hResult);
|
|
97 |
|
|
98 |
|
|
99 |
/*************************************************************************
|
|
100 |
** static variables
|
|
101 |
*************************************************************************/
|
|
102 |
static HANDLE hDevice; // device handle
|
|
103 |
static LONG lCtrlNo; // controller number
|
|
104 |
static HANDLE hCanCtl; // controller handle
|
|
105 |
static HANDLE hCanChn; // channel handle
|
|
106 |
static LONG lMustQuit = 0; // quit flag for the receive thread
|
|
107 |
static HANDLE hTimerHandle; // timer handle
|
|
108 |
|
|
109 |
/*************************************************************************
|
|
110 |
** datatypes
|
|
111 |
*************************************************************************/
|
|
112 |
|
|
113 |
struct sLook_up_table
|
|
114 |
{
|
|
115 |
char baud_rate[20];
|
|
116 |
UINT8 bt0;
|
|
117 |
UINT8 bt1;
|
|
118 |
};
|
|
119 |
|
|
120 |
struct sInterface_lookup_table
|
|
121 |
{
|
|
122 |
char board_num[10];
|
|
123 |
UINT8 num;
|
|
124 |
};
|
|
125 |
|
|
126 |
/*************************************************************************
|
|
127 |
**
|
|
128 |
** Function : canOpen_driver
|
|
129 |
**
|
|
130 |
** Description : Initializes the Control and Message Channels
|
|
131 |
** Parameters : s_BOARD *board - pointer to board information
|
|
132 |
** Returnvalue : (CAN_HANDLE)board - handle for CAN controller
|
|
133 |
**
|
|
134 |
*************************************************************************/
|
|
135 |
CAN_HANDLE __stdcall canOpen_driver(s_BOARD *board)
|
|
136 |
{
|
|
137 |
HANDLE hEnumerator; // enumerator handle
|
|
138 |
VCIDEVICEINFO VCIDeviceInfo; // device info
|
|
139 |
HRESULT hResult;
|
|
140 |
int index, boardNum;
|
|
141 |
BOOL bResult;
|
|
142 |
|
|
143 |
struct sLook_up_table sBitRate_lookup[9] = {
|
|
144 |
{"10K",0x31,0x1C},
|
|
145 |
{"20K",0x18,0x1C},
|
|
146 |
{"50K",0x09,0x1C},
|
|
147 |
{"100K",0x04,0x1C},
|
|
148 |
{"125K",0x03,0x1C},
|
|
149 |
{"250K",0x01,0x1C},
|
|
150 |
{"500K",0x00,0x1C},
|
|
151 |
{"800K",0x00,0x16},
|
|
152 |
{"1M",0x00,0x14}};
|
|
153 |
|
|
154 |
struct sInterface_lookup_table sInterfaceList[4]={
|
|
155 |
{"vcan0",0},
|
|
156 |
{"vcan1",1},
|
|
157 |
{"vcan2",2},
|
|
158 |
{"vcan3",3}};
|
|
159 |
|
|
160 |
for (boardNum =0 ; boardNum<4;boardNum++) // determine canline selected
|
|
161 |
{
|
|
162 |
if (strcmp(sInterfaceList[boardNum].board_num,board->busname )==0)
|
|
163 |
break;
|
|
164 |
}
|
|
165 |
|
|
166 |
for (index = 0; index < 10; ++index) // determine baudrate
|
|
167 |
{
|
|
168 |
if (strcmp(sBitRate_lookup[index].baud_rate,board->baudrate)==0)
|
|
169 |
break;
|
|
170 |
}
|
|
171 |
|
|
172 |
if (index == 9)
|
|
173 |
{
|
|
174 |
MSG_ERR_DRV("IXXAT::open: The given baudrate %S is invalid.", baud_rate);
|
|
175 |
return NULL ;
|
|
176 |
}
|
|
177 |
|
|
178 |
|
|
179 |
/*
|
|
180 |
** The following can be used when the client has multiple CAN interfaces to slect from, and does not wish to use the
|
|
181 |
** selection dialog box
|
|
182 |
/*
|
|
183 |
|
|
184 |
/*
|
|
185 |
hResult= vciEnumDeviceOpen(&hEnumerator);
|
|
186 |
// This loop will increment the index of the device list and returns the decription of the CAN line chose by user
|
|
187 |
if (hResult== VCI_OK)
|
|
188 |
{
|
|
189 |
for (index1=0; index1 <= sInterfaceList[boardNum].num; index1++){
|
|
190 |
hResult=vciEnumDeviceNext(hEnumerator, &VCIDeviceInfo);
|
|
191 |
}
|
|
192 |
}
|
|
193 |
printf("Device Selected: %s %s\n",VCIDeviceInfo.Manufacturer, VCIDeviceInfo.Description);
|
|
194 |
if (hResult== VCI_OK)
|
|
195 |
hResult=vciEnumDeviceClose(hEnumerator);
|
|
196 |
|
|
197 |
if (hResult== VCI_OK)
|
|
198 |
hResult= vciDeviceOpen(&VCIDeviceInfo.VciObjectId, &hDevice);
|
|
199 |
*/
|
|
200 |
|
|
201 |
|
|
202 |
|
|
203 |
/*
|
|
204 |
** Display Interface Selection Dialog Box
|
|
205 |
*/
|
|
206 |
hResult= vciDeviceOpenDlg(0, &hDevice);
|
|
207 |
|
|
208 |
/*
|
|
209 |
** Establish and activate the message Channel
|
|
210 |
*/
|
|
211 |
if (hResult== VCI_OK)
|
|
212 |
hResult= canChannelOpen(hDevice, 0, TRUE, &hCanChn);
|
|
213 |
// Select Rx fifo size, Rx threshold, Tx fifo size, Tx threshold
|
|
214 |
if (hResult== VCI_OK)
|
|
215 |
hResult=canChannelInitialize( hCanChn, 1024, 1,128,1);
|
|
216 |
|
|
217 |
if (hResult== VCI_OK)
|
|
218 |
hResult=canChannelActivate(hCanChn, TRUE);
|
|
219 |
|
|
220 |
|
|
221 |
/*
|
|
222 |
** Establish and Activate the Contol Channel
|
|
223 |
*/
|
|
224 |
if (hResult== VCI_OK)
|
|
225 |
hResult=canControlOpen(hDevice, 0, &hCanCtl);
|
|
226 |
|
|
227 |
// Select 11 or 29 bit IDs, Select operating mode
|
|
228 |
if (hResult== VCI_OK)
|
|
229 |
hResult=canControlInitialize( hCanCtl, CAN_OPMODE_STANDARD | CAN_OPMODE_ERRFRAME, sBitRate_lookup[index].bt0, sBitRate_lookup[index].bt1 );
|
|
230 |
|
|
231 |
|
|
232 |
// With VCI it is possible to filter IDs, See VCI V3 manual. The following will accept all IDs
|
|
233 |
if (hResult== VCI_OK)
|
|
234 |
hResult= canControlSetAccFilter( hCanCtl, FALSE, CAN_ACC_CODE_ALL, CAN_ACC_MASK_ALL);
|
|
235 |
|
|
236 |
if (hResult== VCI_OK)
|
|
237 |
hResult=canControlStart(hCanCtl, TRUE);
|
|
238 |
|
|
239 |
if (hResult!=VCI_OK)
|
|
240 |
{
|
|
241 |
Display_Error(hResult);
|
|
242 |
return NULL;
|
|
243 |
}
|
|
244 |
|
|
245 |
|
|
246 |
/*
|
|
247 |
** Create timer to poll bus status
|
|
248 |
*/
|
|
249 |
bResult= CreateTimerQueueTimer(
|
|
250 |
& hTimerHandle,
|
|
251 |
NULL,
|
|
252 |
TimerProc1, // Callback function
|
|
253 |
NULL,
|
|
254 |
0,
|
|
255 |
STATUS_POLLING_CYCLE,
|
|
256 |
WT_EXECUTEINIOTHREAD
|
|
257 |
);
|
|
258 |
|
|
259 |
return (CAN_HANDLE)board;
|
|
260 |
}
|
|
261 |
|
|
262 |
|
|
263 |
/*************************************************************************
|
|
264 |
**
|
|
265 |
** Function : canReceive_driver
|
|
266 |
**
|
|
267 |
** Description : Transfers RX messages to Festival application
|
|
268 |
** Parameters : CAN_HANDLE inst - handle for CAN controller
|
|
269 |
Message *m - pointer to Message struct
|
|
270 |
** Returnvalue : hResult - VCI_OK if success
|
|
271 |
**
|
|
272 |
*************************************************************************/
|
|
273 |
UNS8 __stdcall canReceive_driver(CAN_HANDLE inst, Message *m)
|
|
274 |
{
|
|
275 |
HRESULT hResult;
|
|
276 |
CANMSG rCanMsg;
|
|
277 |
//Read message from the receive buffer
|
|
278 |
hResult=canChannelReadMessage( hCanChn, INFINITE, &rCanMsg );
|
|
279 |
if (hResult !=VCI_OK )
|
|
280 |
return 1;
|
|
281 |
|
|
282 |
m->cob_id = rCanMsg.dwMsgId;
|
|
283 |
m->len = rCanMsg.uMsgInfo.Bits.dlc;
|
|
284 |
m->rtr = rCanMsg.uMsgInfo.Bits.rtr;
|
|
285 |
if (m->rtr == NOT_A_REQUEST)
|
|
286 |
memcpy(m->data, rCanMsg.abData , m->len);
|
|
287 |
return (UNS8)hResult;
|
|
288 |
}
|
|
289 |
|
|
290 |
/*************************************************************************
|
|
291 |
**
|
|
292 |
** Function : canSend_driver
|
|
293 |
**
|
|
294 |
** Description : Transfers RX messages to Interface
|
|
295 |
** Parameters : CAN_HANDLE inst - handle for CAN controller
|
|
296 |
** Message *m - pointer to Message struct
|
|
297 |
** Returnvalue : hResult - VCI_OK if success
|
|
298 |
**
|
|
299 |
*************************************************************************/
|
|
300 |
UNS8 __stdcall canSend_driver(CAN_HANDLE inst, Message const *m)
|
|
301 |
{
|
|
302 |
HRESULT hResult;
|
|
303 |
CANMSG sCanMsg;
|
|
304 |
|
|
305 |
sCanMsg.uMsgInfo.Bytes.bType = CAN_MSGTYPE_DATA;
|
|
306 |
sCanMsg.uMsgInfo.Bytes.bFlags = CAN_MAKE_MSGFLAGS(8,0,0,0,0);
|
|
307 |
sCanMsg.uMsgInfo.Bits.srr = 0;
|
|
308 |
sCanMsg.dwTime = 0;
|
|
309 |
sCanMsg.dwMsgId = m->cob_id ;
|
|
310 |
memcpy(sCanMsg.abData,m->data, m->len);
|
|
311 |
sCanMsg.uMsgInfo.Bits.dlc = m->len;
|
|
312 |
sCanMsg.uMsgInfo.Bits.rtr=m->rtr;
|
|
313 |
|
|
314 |
// write the CAN message into the transmit FIFO without waiting for transmission
|
|
315 |
hResult = canChannelPostMessage(hCanChn, &sCanMsg);
|
|
316 |
|
|
317 |
return (UNS8)hResult;
|
|
318 |
}
|
|
319 |
|
|
320 |
|
|
321 |
|
|
322 |
|
|
323 |
/*************************************************************************
|
|
324 |
**
|
|
325 |
** Function : canClose_driver
|
|
326 |
**
|
|
327 |
** Description : Close the message and control channel
|
|
328 |
** Parameters : CAN_HANDLE inst - handle for CAN controller
|
|
329 |
** Returnvalue :
|
|
330 |
**
|
|
331 |
*************************************************************************/
|
|
332 |
int __stdcall canClose_driver(CAN_HANDLE inst)
|
|
333 |
{
|
|
334 |
printf("CAN close \n");
|
|
335 |
canControlReset(hCanCtl);
|
|
336 |
canChannelClose(hCanChn);
|
|
337 |
canControlClose(hCanCtl);
|
|
338 |
vciDeviceClose(hDevice);
|
|
339 |
DeleteTimerQueueTimer(NULL,hTimerHandle,NULL);
|
|
340 |
return 1;
|
|
341 |
}
|
|
342 |
|
|
343 |
|
|
344 |
/*************************************************************************
|
|
345 |
**
|
|
346 |
** Function : canChangeBaudRate_driver
|
|
347 |
**
|
|
348 |
** Description : Changes the Baudrate of the interface (not supported)
|
|
349 |
** Parameters :
|
|
350 |
** Returnvalue :
|
|
351 |
**
|
|
352 |
*************************************************************************/
|
|
353 |
UNS8 __stdcall canChangeBaudRate_driver( CAN_HANDLE fd, char* baud)
|
|
354 |
{
|
|
355 |
//printf("canChangeBaudRate not yet supported by this driver\n");
|
|
356 |
return 0;
|
|
357 |
}
|
|
358 |
|
|
359 |
|
|
360 |
/*************************************************************************
|
|
361 |
**
|
|
362 |
** Function : TimerProc1
|
|
363 |
**
|
|
364 |
** Description : Basic Polling of the the canline status,
|
|
365 |
** print debug message for buffer overflow, and BUSOFF condition
|
|
366 |
** Parameters : void* lpParametar, BOOL TimerOrWaitFired
|
|
367 |
** Returnvalue : none
|
|
368 |
**
|
|
369 |
*************************************************************************/
|
|
370 |
void CALLBACK TimerProc1(void* lpParametar, BOOL TimerOrWaitFired )
|
|
371 |
{
|
|
372 |
HRESULT hResult;
|
|
373 |
CANLINESTATUS canStatus;
|
|
374 |
|
|
375 |
|
|
376 |
/* Establish CAN controller status */
|
|
377 |
hResult = canControlGetStatus ( hCanCtl, &canStatus);
|
|
378 |
if (hResult!=VCI_OK)
|
|
379 |
printf("Error did not read CAN STATUS\n");
|
|
380 |
switch ( canStatus.dwStatus)
|
|
381 |
{
|
|
382 |
case CAN_STATUS_OVRRUN:
|
|
383 |
printf("Overrun of the recieve buffer\n");
|
|
384 |
break;
|
|
385 |
case CAN_STATUS_ERRLIM:
|
|
386 |
printf("Overrun of the CAN controller error counter \n");
|
|
387 |
break;
|
|
388 |
case CAN_STATUS_BUSOFF:
|
|
389 |
printf("CAN status: BUSOFF");
|
|
390 |
break;
|
|
391 |
case CAN_STATUS_ININIT:
|
|
392 |
break;
|
|
393 |
case (CAN_STATUS_BUSOFF)+(CAN_STATUS_ININIT):
|
|
394 |
printf("CAN status: BUSOFF\n");
|
|
395 |
|
|
396 |
/*
|
|
397 |
** Bus off recovery should come after a software reset, and 128*11 recessive bits.
|
|
398 |
** This can only happen when an Error-Active node sends an active error flag,
|
|
399 |
** and other nodes respond with Error Echo Flag
|
|
400 |
*/
|
|
401 |
break;
|
|
402 |
default:
|
|
403 |
break;
|
|
404 |
}
|
|
405 |
};
|
|
406 |
|
|
407 |
|
|
408 |
/*************************************************************************
|
|
409 |
**
|
|
410 |
** Function : Display_Error
|
|
411 |
**
|
|
412 |
** Description : Display the CANline Error
|
|
413 |
** Parameters : HANDLE hResult
|
|
414 |
** Returnvalue : none
|
|
415 |
**
|
|
416 |
*************************************************************************/
|
|
417 |
void Display_Error(HRESULT hResult )
|
|
418 |
{
|
|
419 |
char szError[VCI_MAX_ERRSTRLEN];
|
|
420 |
if (hResult != NO_ERROR)
|
|
421 |
{
|
|
422 |
if (hResult == -1)
|
|
423 |
hResult = GetLastError();
|
|
424 |
szError[0] = 0;
|
|
425 |
vciFormatError(hResult, szError, sizeof(szError));
|
|
426 |
printf("Error Establishing CAN channel, Error Code: %s\n",szError);
|
|
427 |
}
|
|
428 |
} |