XCP_SIM
kvaser.c
1 /*
2  * BlueParrot XCP
3  *
4  * (C) 2007-2019 by Christoph Schueler <github.com/Christoph2,
5  * cpu12.gems@googlemail.com>
6  *
7  * All Rights Reserved
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  * s. FLOSS-EXCEPTION.txt
24  */
25 
27 #include "Xcp.h"
28 #include "Xcp_hw.h"
31 #include <stdio.h>
32 
33 #include "canlib.h"
34 
35 #if _MSC_VER
36 #pragma warning(disable : 4996)
37 #endif /* _MSC_VER */
38 
39 #define KV_MAX_DLC ((uint16_t)8) /* TODO: depends on classic or FD. */
40 
41 #if 0
42 static const uint8_t GET_SLAVE_ID_ECHO[] = {UINT8(0x58), UINT8(0x43), UINT8(0x50)};
43 static const uint8_t GET_SLAVE_ID_INVERSE_ECHO[] = {UINT8(0xA7), UINT8(0xBC), UINT8(0xAF)};
44 #endif
45 
46 typedef struct tagXcpTl_ConnectionType {
47  int virtualChannel;
48  int handle;
50 
51 extern Xcp_PduType Xcp_CtoIn;
52 extern Xcp_PduType Xcp_CtoOut;
53 
54 static XcpTl_ConnectionType XcpTl_Connection;
55 
56 static uint16_t XcpTl_SetDLC(uint16_t len);
57 static void XcpTl_SetCANFilter(void);
58 static void Kv_Notification(int hnd, void *context, unsigned int notifyEvent);
59 static bool XcpTl_MatchingAddress(uint32_t id0, uint32_t id1, uint16_t flag);
60 
61 void Kv_Error(const char *msg) { printf("ERROR[Kvaser]:: %s\n", msg); }
62 
63 void Kv_Info(const char *msg) { printf("INFO[Kvaser]:: %s\n", msg); }
64 
65 void Kv_Check(char *id, canStatus stat) {
66  char err_buf[128];
67  char msg_buf[128];
68 
69  if (stat != canOK) {
70  err_buf[0] = '\0';
71  canGetErrorText(stat, err_buf, sizeof(err_buf));
72  sprintf(msg_buf, "%s: failed, stat=%d (%s)\n", id, (int)stat, err_buf);
73  Kv_Error(msg_buf);
74  }
75 }
76 
77 static bool XcpTl_MatchingAddress(uint32_t id0, uint32_t id1, uint16_t flag) {
78  uint16_t ext0;
79  uint16_t ext1;
80  uint32_t identifier;
81 
82  ext0 = XCP_ON_CAN_IS_EXTENDED_IDENTIFIER(id0);
83  identifier = XCP_ON_CAN_STRIP_IDENTIFIER(id0);
84  ext1 = (flag == canMSG_EXT) ? 1 : 0;
85 
86  return (identifier == id1) && (ext0 == ext1);
87 }
88 
89 static void Kv_Notification(int hnd, void *context, unsigned int notifyEvent) {
90  canStatus stat;
91  long id;
92  static uint8_t msg[64];
93  unsigned int dlc;
94  unsigned int flag;
95  unsigned long time;
96  unsigned long status;
97  // char msg_buffer[128];
98 
99  stat = canReadStatus(hnd, &status);
100  Kv_Check("canReadStatus", stat);
101 
102  switch (notifyEvent) {
103  case canNOTIFY_TX:
104  // Kv_Info("CAN message sent\n");
105  break;
106  case canNOTIFY_RX:
107  // Kv_Info("CAN message received\n");
108  stat = canRead(hnd, &id, msg, &dlc, &flag, &time);
109  Kv_Check("canRead", stat);
110 #if XCP_ON_CAN_MAX_DLC_REQUIRED == XCP_ON
111  if (dlc != XCP_MAX_CTO) {
112  break;
113  }
114 #endif
115  if (dlc > 0) {
116  if (XcpTl_MatchingAddress(XCP_ON_CAN_INBOUND_IDENTIFIER, id, flag)) {
117  Xcp_CtoIn.len = dlc;
118  Xcp_CtoIn.data = msg + XCP_TRANSPORT_LAYER_BUFFER_OFFSET;
119  Xcp_DispatchCommand(&Xcp_CtoIn);
120  } else if (XcpTl_MatchingAddress(XCP_ON_CAN_BROADCAST_IDENTIFIER, id,
121  flag)) {
122  printf("BROADCAST request!!!\n");
123  }
124  }
125 #if 0
126 #define canMSG_MASK 0x00ff
127 #define canMSG_RTR 0x0001
128 #define canMSG_STD 0x0002
129 #define canMSG_EXT 0x0004
130 #define canMSG_WAKEUP 0x0008
131 #define canMSG_NERR 0x0010
132 #define canMSG_ERROR_FRAME 0x0020
133 #define canMSG_TXACK 0x0040
134 #define canMSG_TXRQ 0x0080
135 #endif
136  // printf("ID: %08x DLC: %d Flags: %08x Timer: %d\n", id, dlc, flag, time);
137  break;
138  case canNOTIFY_STATUS:
139  /* printf("CAN status %u\n", stat); */
140  break;
141  case canNOTIFY_ERROR:
142  Kv_Error("Error frame received");
143  break;
144  case canNOTIFY_BUSONOFF:
145  if (status & canSTAT_ERROR_PASSIVE) {
146  Kv_Info("Error-Passive");
147  } else if (status & canSTAT_BUS_OFF) {
148  Kv_Info("BusOff");
149  } else if (status & canSTAT_ERROR_WARNING) {
150  Kv_Info("Error-Warning");
151  } else if (status & canSTAT_ERROR_ACTIVE) {
153  } else {
154  printf("BusOn/BusOff %lu\n", status);
155  // ???
156  }
157  break;
158  default:
159  printf("Unknown event %d\n", notifyEvent);
160  break;
161  }
162 }
163 
164 void XcpTl_Init(void) {
165  canStatus stat;
166  uint32_t ts;
167  // int code;
168  // int ext;
169  int hnd;
170 
171  canInitializeLibrary();
172  hnd = canOpenChannel(
173  0, canOPEN_ACCEPT_VIRTUAL |
174  canOPEN_NO_INIT_ACCESS /* | canOPEN_ACCEPT_LARGE_DLC*/);
175  if (hnd < 0) {
176  Kv_Check("canOpenChannel", hnd);
177  exit(1);
178  }
179 
180  XcpTl_Connection.handle = hnd;
181 
182  stat = kvSetNotifyCallback(hnd, (kvCallback_t)&Kv_Notification, NULL,
183  canNOTIFY_RX | canNOTIFY_TX | canNOTIFY_ERROR |
184  canNOTIFY_STATUS | canNOTIFY_BUSONOFF);
185  Kv_Check("kvSetNotifyCallback", stat);
186 
187  stat =
188  canSetBusParams(hnd, XCP_ON_CAN_FREQ, XCP_ON_CAN_TSEG1, XCP_ON_CAN_TSEG2,
189  XCP_ON_CAN_SJW, XCP_ON_CAN_NOSAMP, 0);
190  Kv_Check("SetBusParams", stat);
191 
192  ts = 10; /* We are using 10µS timer resolution. */
193  stat = canIoCtl(hnd, canIOCTL_SET_TIMER_SCALE, &ts, 4);
194  Kv_Check("SET_TIME_SCALE", stat);
195 
196  XcpTl_SetCANFilter();
197 
198  canFlushReceiveQueue(hnd);
199  canFlushTransmitQueue(hnd);
200 
201  stat = canBusOn(hnd);
202  Kv_Check("canBusOn", stat);
203 }
204 
205 void XcpTl_DeInit(void) {
206  canStatus stat;
207 
208  Kv_Info("Going off bus and closing channel");
209  stat = canBusOff(XcpTl_Connection.handle);
210  Kv_Check("canBusOff", stat);
211  // stat = canClose(hnd);
212  // Kv_Check("canClose", stat);
213 }
214 
215 #if 0
216 int16_t XcpTl_FrameAvailable(uint32_t sec, uint32_t usec)
217 {
218  return 1;
219 }
220 #endif
221 
222 static uint16_t XcpTl_SetDLC(uint16_t len) {
223  static const uint16_t FD_DLCS[] = {12, 16, 20, 24, 32, 48, 64};
224  uint8_t idx;
225 
226  if (len <= 8) {
227  return len;
228  } else {
229  for (idx = 0; idx < sizeof(FD_DLCS); ++idx) {
230  if (len <= FD_DLCS[idx]) {
231  return FD_DLCS[idx];
232  }
233  }
234  }
235 }
236 
237 static void XcpTl_SetCANFilter(void) {
238  uint32_t i0;
239  uint32_t i1;
240  uint32_t filter;
241  uint32_t mask;
242  int ext;
243  int stat;
244 
245  i0 = XCP_ON_CAN_STRIP_IDENTIFIER(XCP_ON_CAN_INBOUND_IDENTIFIER);
246  i1 = XCP_ON_CAN_STRIP_IDENTIFIER(XCP_ON_CAN_BROADCAST_IDENTIFIER);
247 
248  filter = i0 & i1;
249  mask = (i0 | i1) ^ filter;
250 
251  if ((XCP_ON_CAN_IS_EXTENDED_IDENTIFIER(XCP_ON_CAN_INBOUND_IDENTIFIER)) ||
252  (XCP_ON_CAN_IS_EXTENDED_IDENTIFIER(XCP_ON_CAN_BROADCAST_IDENTIFIER))) {
253  ext = 1;
254  mask ^= 0x1fffffff;
255  } else {
256  ext = 0;
257  mask ^= 0x7ff;
258  }
259  stat = canSetAcceptanceFilter(XcpTl_Connection.handle, filter, mask, ext);
260  Kv_Check("canSetAcceptanceFilter", stat);
261 }
262 
263 void XcpTl_Send(uint8_t const *buf, uint16_t len) {
264  int stat;
265  int id;
266  int ext;
267  int flag;
268  char msg_buf[256];
269 
270  XCP_TL_ENTER_CRITICAL();
271  if (len > KV_MAX_DLC) {
272  sprintf(msg_buf, "XcpTl_Send -- at most %d bytes supported, got %d.\n",
273  KV_MAX_DLC, len);
274  Kv_Error((const char *)msg_buf);
275  return;
276  }
277 
278  id = XCP_ON_CAN_STRIP_IDENTIFIER(XCP_ON_CAN_OUTBOUND_IDENTIFIER);
279  ext = XCP_ON_CAN_IS_EXTENDED_IDENTIFIER(XCP_ON_CAN_OUTBOUND_IDENTIFIER);
280  flag = ext ? canMSG_EXT : canMSG_STD;
281  stat = canWrite(XcpTl_Connection.handle, id, (void *)buf, len, flag);
282  Kv_Check("canWrite", stat);
283  XCP_TL_LEAVE_CRITICAL();
284 }
285 
286 void XcpTl_MainFunction(void) {
287  Sleep(1);
288 #if 0
289  if (XcpTl_FrameAvailable(0, 1000) > 0) {
290  XcpTl_RxHandler();
291  }
292 #endif
293 }
294 
295 #if 0
296 void XcpTl_RxHandler(void)
297 {
298 
299 }
300 #endif
301 
302 void XcpTl_SaveConnection(void) {}
303 
304 void XcpTl_ReleaseConnection(void) {}
305 
306 void XcpTl_PostQuitMessage(void) {}
307 
308 bool XcpTl_VerifyConnection(void) { return XCP_TRUE; }
309 
310 void XcpTl_FeedReceiver(uint8_t octet) {}
311 
312 void XcpTl_TransportLayerCmd_Res(Xcp_PduType const *const pdu) {}
313 
314 void XcpTl_SetOptions(Xcp_OptionsType const *options) {
315  CopyMemory(&Xcp_Options, options, sizeof(Xcp_OptionsType));
316 }
317 
318 void XcpTl_PrintConnectionInformation(void) {
319  int stat;
320  int num;
321  char name[128];
322  bool ext;
323 
324  ext = XCP_ON_CAN_IS_EXTENDED_IDENTIFIER(XCP_ON_CAN_INBOUND_IDENTIFIER);
325  stat = canGetChannelData(XcpTl_Connection.handle,
326  canCHANNELDATA_CHAN_NO_ON_CARD, &num, sizeof(num));
327  Kv_Check("canGetChannelData", stat);
328  stat = canGetChannelData(XcpTl_Connection.handle,
329  canCHANNELDATA_DEVDESCR_ASCII, &name, sizeof(name));
330  Kv_Check("canGetChannelData", stat);
331  printf("\nXCPonCAN -- %s (channel %d), listening on 0x%X [%s]\n", name, num,
332  XCP_ON_CAN_STRIP_IDENTIFIER(XCP_ON_CAN_INBOUND_IDENTIFIER),
333  ext ? "EXT" : "STD");
334 }