-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlib.c
339 lines (272 loc) · 9.06 KB
/
lib.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <time.h>
#include <sys/socket.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <linux/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/can/error.h>
#include "keyTime.h"
#define CANID_DELIM '#'
#define DATA_SEPERATOR '.'
/*
* timer function is responsible for getting a time values
* @param timer_val - take a long variable and sets the time equal to it
*/
void timer(long *timer_val) {
struct timespec tp;
clock_gettime(CLOCK_REALTIME, &tp);
*timer_val = tp.tv_sec * 1000000000 + tp.tv_nsec;
}
/*
* createSocket function creates a socket on the CAN bus network
* so we're able to send and receive messages from it.
* @param interface - A string value naming the interface where you want to create the socket.
*/
int createSocket(char *interface) {
int s;
struct sockaddr_can addr;
struct ifreq ifr;
const char *ifname = interface;
if((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
perror("Error while opening socket");
return -1;
}
strcpy(ifr.ifr_name, ifname);
ioctl(s, SIOCGIFINDEX, &ifr);
bzero(&addr,sizeof(struct sockaddr_can)); //zero out the struct
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
// setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("Error in socket bind");
return -2;
}
return s;
}
/*
* From can-utils, lib.h file.
* Returns the decimal value of a given ASCII hex character.
*
* While 0..9, a..f, A..F are valid ASCII hex characters.
* On invalid characters the value 16 is returned for error handling.
*/
unsigned char asc2nibble(char c) {
if ((c >= '0') && (c <= '9'))
return c - '0';
if ((c >= 'A') && (c <= 'F'))
return c - 'A' + 10;
if ((c >= 'a') && (c <= 'f'))
return c - 'a' + 10;
return 16; /* error */
}
/*
* From can-utils, lib.h file.
*
* Transfers a valid ASCII string decribing a CAN frame into struct canfd_frame.
*
* CAN 2.0 frames
* - string layout <can_id>#{R{len}|data}
* - {data} has 0 to 8 hex-values that can (optionally) be separated by '.'
* - {len} can take values from 0 to 8 and can be omitted if zero
* - return value on successful parsing: CAN_MTU
*
* CAN FD frames
* - string layout <can_id>##<flags>{data}
* - <flags> a single ASCII Hex value (0 .. F) which defines canfd_frame.flags
* - {data} has 0 to 64 hex-values that can (optionally) be separated by '.'
* - return value on successful parsing: CANFD_MTU
*
* Return value on detected problems: 0
*
* <can_id> can have 3 (standard frame format) or 8 (extended frame format)
* hexadecimal chars
*
*
* Examples:
*
* 123# -> standard CAN-Id = 0x123, len = 0
* 12345678# -> extended CAN-Id = 0x12345678, len = 0
* 123#R -> standard CAN-Id = 0x123, len = 0, RTR-frame
* 123#R0 -> standard CAN-Id = 0x123, len = 0, RTR-frame
* 123#R7 -> standard CAN-Id = 0x123, len = 7, RTR-frame
* 7A1#r -> standard CAN-Id = 0x7A1, len = 0, RTR-frame
*
* 123#00 -> standard CAN-Id = 0x123, len = 1, data[0] = 0x00
* 123#1122334455667788 -> standard CAN-Id = 0x123, len = 8
* 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, len = 8
* 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, len = 8
* 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
*
* 123##0112233 -> CAN FD frame standard CAN-Id = 0x123, flags = 0, len = 3
* 123##1112233 -> CAN FD frame, flags = CANFD_BRS, len = 3
* 123##2112233 -> CAN FD frame, flags = CANFD_ESI, len = 3
* 123##3 -> CAN FD frame, flags = (CANFD_ESI | CANFD_BRS), len = 0
* ^^
* CAN FD extension to handle the canfd_frame.flags content
*
* Simple facts on this compact ASCII CAN frame representation:
*
* - 3 digits: standard frame format
* - 8 digits: extendend frame format OR error frame
* - 8 digits with CAN_ERR_FLAG (0x2000000) set: error frame
* - an error frame is never a RTR frame
* - CAN FD frames do not have a RTR bit
*/
int parseFrame(char *cs, struct canfd_frame *cf) {
/* documentation see lib.h */
int i, idx, dlen, len;
int maxdlen = CAN_MAX_DLEN;
int ret = CAN_MTU;
unsigned char tmp;
len = strlen(cs);
// printf("'%s' len %d\n", cs, len);
memset(cf, 0, sizeof(*cf)); /* init CAN FD frame, e.g. LEN = 0 */
if (len < 4)
return 0;
if (cs[3] == CANID_DELIM) { /* 3 digits */
idx = 4;
for (i=0; i<3; i++){
if ((tmp = asc2nibble(cs[i])) > 0x0F)
return 0;
cf->can_id |= (tmp << (2-i)*4);
}
} else if (cs[8] == CANID_DELIM) { /* 8 digits */
idx = 9;
for (i=0; i<8; i++){
if ((tmp = asc2nibble(cs[i])) > 0x0F)
return 0;
cf->can_id |= (tmp << (7-i)*4);
}
if (!(cf->can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe? */
cf->can_id |= CAN_EFF_FLAG; /* then it is an extended frame */
} else
return 0;
if((cs[idx] == 'R') || (cs[idx] == 'r')){ /* RTR frame */
cf->can_id |= CAN_RTR_FLAG;
/* check for optional DLC value for CAN 2.0B frames */
if(cs[++idx] && (tmp = asc2nibble(cs[idx])) <= CAN_MAX_DLC)
cf->len = tmp;
return ret;
}
if (cs[idx] == CANID_DELIM) { /* CAN FD frame escape char '##' */
maxdlen = CANFD_MAX_DLEN;
ret = CANFD_MTU;
/* CAN FD frame <canid>##<flags><data>* */
if ((tmp = asc2nibble(cs[idx+1])) > 0x0F)
return 0;
cf->flags = tmp;
idx += 2;
}
for (i=0, dlen=0; i < maxdlen; i++){
if(cs[idx] == DATA_SEPERATOR) /* skip (optional) separator */
idx++;
if(idx >= len) /* end of string => end of data */
break;
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
return 0;
cf->data[i] = (tmp << 4);
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
return 0;
cf->data[i] |= tmp;
dlen++;
}
cf->len = dlen;
return ret;
}
/*
* sendMsg function is made to send a message to the CAN network
* @param ptr - a void pointer used to accept structs of data
*/
void *sendMsg(void *ptr) {
struct canInfoStruct *sendStruct = ptr;
char *sID = sendStruct->sendIDinStruct;
int s = sendStruct->sock;
int reqMTU; // Maximum transfer unit
struct canfd_frame frame; // Pack data into this frame
// Parse the CAN data and check it's the right length
reqMTU = parseFrame(sID, &frame);
if(!reqMTU) {
fprintf(stderr, "Bad CAN format.\n");
return (void *)1;
}
// Write the data to the frame and send
write(s, &frame, reqMTU);
// Once the data has been sent start the timer
timer(sendStruct->beginTime);
// Print out the information
printf("\n=============" "\x1b[32m" "SENT" "\x1b[0m" "============");
printf("\n%X - [%d] - %02X %02X %02X %02X %02X %02X %02X %02X", frame.can_id & 0x1fffffffu, frame.len, // 29 bit CAN ID
frame.data[0], frame.data[1], frame.data[2], frame.data[3],
frame.data[4], frame.data[5], frame.data[6], frame.data[7]);
if((frame.data[0] == 0x02) && (frame.data[1] == 0x10))
printf(" - PUTTING INTO PROGMODE");
if((frame.data[0] == 0x02) && (frame.data[1] == 0x27))
printf(" - REQUEST A SEED");
if(frame.data[0] == 0x06)
printf(" - KEY SENT");
if(frame.data[1] == 0x11)
printf(" - RESET MODE\n\n");
return 0;
}
/*
* receiveMsg function is made to receive a message from the CAN network
* @param ptr - a void pointer used to accept structs of data
*/
void *receiveMsg(void *ptr) {
struct canInfoStruct *receiveStruct = ptr;
int rID = receiveStruct->receiveIDinStruct;
int s = receiveStruct->sock;
struct can_frame frame;
// TODO: Better alternative
int loop = 1;
// While looping read in CAN frames, if it matches a certain ID is an option aswell
while(loop) {
// If there is a packet. If the bit mask adds up. If it's not a 'wait, I'm entering prog mode' from the ECU.
if(read(s, &frame, sizeof(struct can_frame)) > 0 && (frame.can_id & 0x1fffffffu) == rID) {
printf("\n===========" "\x1b[32m" "RECEIVED" "\x1b[0m" "==========");
printf("\n%X - [%d] - %02X %02X %02X %02X %02X %02X %02X %02X", frame.can_id & 0x1fffffffu, frame.can_dlc, // 29 bit CAN ID
frame.data[0], frame.data[1], frame.data[2], frame.data[3],
frame.data[4], frame.data[5], frame.data[6], frame.data[7]);
// If we have received a seed
if((frame.data[0] == 0x06) && (frame.data[1] == 0x67) && (frame.data[2] == 0x01)) {
// Add data to struct
receiveStruct->cdata[0] = frame.data[0];
receiveStruct->cdata[1] = frame.data[1];
receiveStruct->cdata[2] = frame.data[2];
receiveStruct->cdata[3] = frame.data[3];
receiveStruct->cdata[4] = frame.data[4];
receiveStruct->cdata[5] = frame.data[5];
receiveStruct->cdata[6] = frame.data[6];
receiveStruct->cdata[7] = frame.data[7];
printf(" - SEED RECEIVED");
return 0;
}
// If we have entered prog mode
if(frame.data[1] == 0x50) {
printf(" - NOW IN PROGMODE");
receiveStruct->cdata[1] = frame.data[1];
return 0;
}
// Expected response from ECU after we send a key
if(frame.data[2] == 0x27)
printf(" - ERROR RESPONSE");
// Expected response once the ECU has been rest
if(frame.data[1] == 0x51) {
printf(" - SUCCESS RESET");
receiveStruct->cdata[1] = frame.data[1];
}
// Stop the timer
timer(receiveStruct->endTime);
loop = 0;
}
}
return 0;
}