]> rtime.felk.cvut.cz Git - linux-lin.git/blob - lin_config/src/pcan_lin_config.c
pcanlin: Initial commit.
[linux-lin.git] / lin_config / src / pcan_lin_config.c
1 /*
2  * PCAN-LIN, RS-232 to CAN/LIN converter control application
3  *
4  *   This program is free software; you can distribute it and/or
5  *   modify it under the terms of the GNU General Public License
6  *   as published by the Free Software Foundation; version 2 of
7  *   the License.
8  *
9  * Copyright:  (c) 2012 Czech Technical University in Prague
10  * Authors:    Rostislav Lisovy <lisovy@gmail.cz>
11  */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <string.h>
18 #include <termios.h>
19 #include <stdint.h>
20
21 #define true                                    1
22 #define false                                   0
23
24 #define PCL_PKT_MAX_SIZE                        16
25 #define PCL_HEADERS_SIZE                        2 /* There are 2 bytes of headers */
26 #define PCL_CHECKSUM_SIZE                       1
27 #define PCL_STX_SIZE                            1
28 #define PCL_PACKET_OVERHEAD                     (PCL_HEADERS_SIZE + PCL_CHECKSUM_SIZE)
29
30 /* Logical representation of a packet sent to PCAN-LIN converter via RS232 */
31 typedef struct {
32         uint8_t stx;        /* Start transmission; Always set to 0x2 */
33         uint8_t seq_no;     /* Sequence number */
34         uint8_t seq_frlen;  /* Frame length */
35         uint8_t ctrl_tiface;/* Target interface */
36         uint8_t ctrl_comc;  /* Command code */
37         uint8_t parms[8];   /* Parameters; Number of parameters depends
38                                 on the frame length */
39         uint8_t chks;       /* Checksum; Bitwise XOR of all bytes except STX */
40 } pcl_packet_t;
41
42 #define PCL_STX                                 0x2
43
44 #define PCL_SEQ_NO_ofs                          4
45 #define PCL_SEQ_FRLEN_ofs                       0
46 #define PCL_CTRL_TIFACE_ofs                     6
47 #define PCL_CTRL_COMC_ofs                       0
48
49 #define PCL_SEQ_FRLEN_msk                       0xF
50
51 #define PCL_PACKET_LIN_IFACE                    0x2
52 #define PCL_PACKET_MODULE_IFACE                 0x3
53
54 struct termios term_attr;
55
56 struct pcl_scheduler_entry_t {
57         int lin_id;
58         int interval_ms;
59 } pcl_scheduler_entry[] = {
60 //      {0x3F, 500},
61 //      {0x2A, 500},
62         {1, 500},
63         {2, 500},
64         {4, 500},
65         {8, 500},
66         {16, 500}
67 };
68
69 #define PCL_ACTIVE                              1
70 #define PCL_UNACTIVE                            0
71 /* Excerpt from the PCAN-LIN documentation:
72
73         The length of the data depends on the slave ID. If the used frame
74         length is the default, the length to be used can be found using
75         the following table:
76                 ID Range        |    Data Length
77                 ----------------+---------------
78                 0x00 to 0x1F    |    2 Bytes
79                 0x20 to 0x2F    |    4 Bytes
80                 0x30 to 0x3F    |    8 Bytes
81
82         If the frame length of the used LIN ID was configured with another
83         length, than that length must be used;
84 */
85
86 /* Index in this array = LIN ID */
87 struct pcl_publish_entry_t {
88         int status; /* 1 = active; 0 = unactive */
89         int data_len;
90         unsigned char data[8];
91 } pcl_publish_entry[] = {
92         [0x0] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
93         [0x1] = { PCL_ACTIVE, 2, {0xff, 0xff} },
94         [0x2] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
95         [0x3] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
96         [0x4] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
97         [0x5] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
98         [0x6] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
99         [0x7] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
100         [0x8] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
101         [0x9] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
102         [0xa] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
103         [0xb] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
104         [0xc] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
105         [0xd] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
106         [0xe] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
107         [0xf] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
108         [0x10] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
109         [0x11] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
110         [0x12] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
111         [0x13] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
112         [0x14] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
113         [0x15] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
114         [0x16] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
115         [0x17] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
116         [0x18] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
117         [0x19] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
118         [0x1a] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
119         [0x1b] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
120         [0x1c] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
121         [0x1d] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
122         [0x1e] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
123         [0x1f] = { PCL_UNACTIVE, 2, {0xff, 0xff} },
124
125         [0x20] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
126         [0x21] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
127         [0x22] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
128         [0x23] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
129         [0x24] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
130         [0x25] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
131         [0x26] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
132         [0x27] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
133         [0x28] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
134         [0x29] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
135         [0x2a] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
136         [0x2b] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
137         [0x2c] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
138         [0x2d] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
139         [0x2e] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
140         [0x2f] = { PCL_UNACTIVE, 4, {0xff, 0xff, 0xff, 0xff} },
141
142         [0x30] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
143         [0x31] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
144         [0x32] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
145         [0x33] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
146         [0x34] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
147         [0x35] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
148         [0x36] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
149         [0x37] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
150         [0x38] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
151         [0x39] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
152         [0x3a] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
153         [0x3b] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
154         [0x3c] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
155         [0x3d] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
156         [0x3e] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
157         [0x3f] = { PCL_UNACTIVE, 6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
158 };
159
160 int pcl_slave_only_fl = false;
161 /* ------------------------------------------------------------------------ */
162
163 /* Transform 'logic' representation of a frame to exact byte sequence */
164 int pcl_serialize(pcl_packet_t *pkt, uint8_t *pkt_raw)
165 {
166         int i;
167         uint8_t checksum = 0;
168
169         pkt_raw[0] = pkt->stx;
170         pkt_raw[1] = (pkt->seq_no << PCL_SEQ_NO_ofs) |
171                         (pkt->seq_frlen << PCL_SEQ_FRLEN_ofs);
172         pkt_raw[2] = (pkt->ctrl_tiface << PCL_CTRL_TIFACE_ofs) |
173                         (pkt->ctrl_comc << PCL_CTRL_COMC_ofs);
174
175         for (i = 0; i < pkt->seq_frlen; i++) {
176                 pkt_raw[3+i] = pkt->parms[i];
177         }
178
179         /* Calculate XOR checksum; Skip STX */
180         for (i = 1; i <= pkt->seq_frlen + PCL_HEADERS_SIZE; i++) {
181                 checksum ^= pkt_raw[i];
182         }
183         pkt_raw[i] = checksum;
184
185         printf("Snd: [STX] [SEQ] [PRM] [...] \n      ");
186         for (i = 0; i < pkt->seq_frlen + PCL_PACKET_OVERHEAD + 1; i++)
187                 printf("0x%02X  ", pkt_raw[i]);
188         printf("\n");
189
190         return pkt->seq_frlen + 4; /* real packet size */
191 }
192
193 int pcl_send_frame(int tty, pcl_packet_t *pkt)
194 {
195         int pkt_size;
196         int to_send;
197         int sent;
198         uint8_t pkt_buff[PCL_PKT_MAX_SIZE];
199
200         pkt_size = pcl_serialize(pkt, (uint8_t *) &pkt_buff);
201         to_send = pkt_size;
202         sent = 0;
203
204         while (to_send > 0) {
205                 sent = write(tty, pkt_buff+sent, to_send);
206                 to_send -= sent;
207         }
208
209         memset(pkt, '\0', sizeof(pcl_packet_t));
210         return 0;
211 }
212
213 int pcl_read_reset_response(int tty)
214 {
215         char c;
216         int ret;
217         int i = 0;
218         char str_match[] = {'G', 'm', 'b', 'H'};
219
220         do {
221                 ret = read(tty, &c, 1);
222                 if (ret == -1)
223                         perror("read()");
224
225                 printf("%c", c);
226
227                 if ((c == str_match[i]) && (i == 3))
228                         i = -1; /* We are done -- Stop the loop*/
229                 else if (c == str_match[i])
230                         i++; /* Match found -- Go to the next letter */
231                 else
232                         i = 0; /* Start from beginning */
233
234         } while (i != -1);
235
236         printf("\n\n");
237
238         return 0;
239 }
240
241 int pcl_read_response(int tty)
242 {
243         int i;
244         int received = 0;
245         int to_read = 0;
246         int data_length = 0;
247         uint8_t buff[PCL_PKT_MAX_SIZE];
248         //memset(buff, '\0', sizeof(buff));
249
250         /* Read 2 bytes of header */
251         received = read(tty, &buff[0], 1); /* Read STX */
252         if (received == -1)
253                 perror("read()");
254
255         if (buff[0] == 0x2) { /* STX ok */
256                 received = read(tty, &buff[1], 1); /* Read SEQ */
257                 if (received == -1)
258                         perror("read()");
259         } else {
260                 return 1;
261         }
262
263         data_length = (buff[1] & PCL_SEQ_FRLEN_msk);
264         to_read = data_length + 1; /* +chksm */
265         while (to_read > 0) {
266                 received = read(tty, &buff[2], to_read);
267                 to_read -= received;
268         }
269
270         printf("Rcv: [STX] [SEQ] [PRM] [CHK]\n"); // FIXME add spaces before "CHKS" when
271                                                         //more than 1 byte received in params
272         printf("      0x%02X  0x%02X", buff[0], buff[1]);
273         for (i = 0; i < data_length; i++) {
274                 printf("  0x%02X", buff[i + 2]);
275         }
276         printf("  0x%02X\n\n", buff[i]);
277
278         return 0;
279 }
280
281 void pcl_insert_scheduler_entries(int tty)
282 {
283         pcl_packet_t pkt;
284         int i;
285
286         /* Insert scheduler entry */
287         for (i = 0; i < (sizeof(pcl_scheduler_entry)/sizeof(struct pcl_scheduler_entry_t)); i++) {
288                 pkt.stx = PCL_STX;
289                 pkt.seq_no = 0x0;
290                 pkt.seq_frlen = 0x3;
291                 pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
292                 pkt.ctrl_comc = 0x28;
293                 pkt.parms[0] = (pcl_scheduler_entry[i].interval_ms) & 0xFF;
294                 pkt.parms[1] = (pcl_scheduler_entry[i].interval_ms >> 8) & 0xFF;
295                 pkt.parms[2] = pcl_scheduler_entry[i].lin_id; /* LIN ID */
296
297                 pcl_send_frame(tty, &pkt);
298                 pcl_read_response(tty);
299         }
300
301 }
302
303 void pcl_set_slave_id_and_data_configuration(int tty)
304 {
305         pcl_packet_t pkt;
306         int i;
307
308         /* Set Slave ID + Data Configuration */
309         for (i = 0; i < 0x3F; i++) {
310                 int len;
311
312                 if (pcl_publish_entry[i].status == PCL_ACTIVE) {
313                         pkt.stx = PCL_STX;
314                         pkt.seq_no = 0x0;
315                         pkt.seq_frlen = pcl_publish_entry[i].data_len + 2;
316                         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
317                         pkt.ctrl_comc = 0x29;
318                         pkt.parms[0] = pcl_publish_entry[i].status; /* Field Status */
319                         pkt.parms[1] = i; /* LIN ID */
320                         pkt.parms[2] = pcl_publish_entry[i].data[0]; /* Data */
321                         pkt.parms[3] = pcl_publish_entry[i].data[1]; /* Data */
322                         pkt.parms[4] = pcl_publish_entry[i].data[2]; /* Data */
323                         pkt.parms[5] = pcl_publish_entry[i].data[3]; /* Data */
324                         pkt.parms[6] = pcl_publish_entry[i].data[4]; /* Data */
325                         pkt.parms[7] = pcl_publish_entry[i].data[5]; /* Data */
326                         pkt.parms[8] = pcl_publish_entry[i].data[6]; /* Data */
327                         pkt.parms[9] = pcl_publish_entry[i].data[7]; /* Data */
328
329                 } else {
330                         if (i < 0x20)
331                                 len = 4;
332                         else if (i < 0x30)
333                                 len = 6;
334                         else
335                                 len = 8;
336
337                         pkt.stx = PCL_STX;
338                         pkt.seq_no = 0x0;
339                         pkt.seq_frlen = len;
340                         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
341                         pkt.ctrl_comc = 0x29;
342                         pkt.parms[0] = 0x00; /* Field Status -- unactive */
343                         pkt.parms[1] = i; /* LIN ID */
344                 }
345
346                 pcl_send_frame(tty, &pkt);
347                 pcl_read_response(tty);
348         }
349 }
350
351 void pcl_flash_config(int tty)
352 {
353         pcl_packet_t pkt;
354
355         /* Flash Current Configuration */
356         pkt.stx = PCL_STX;
357         pkt.seq_no = 0x0;
358         pkt.seq_frlen = 0x0;
359         pkt.ctrl_tiface = PCL_PACKET_MODULE_IFACE;
360         pkt.ctrl_comc = 0x3;
361
362         pcl_send_frame(tty, &pkt);
363         pcl_read_response(tty);
364 }
365
366 void pcl_reset_device(int tty)
367 {
368         pcl_packet_t pkt;
369
370         /* Reset module */
371         pkt.stx = PCL_STX;
372         pkt.seq_no = 0x0;
373         pkt.seq_frlen = 0x0;
374         pkt.ctrl_tiface = PCL_PACKET_MODULE_IFACE;
375         pkt.ctrl_comc = 0x4;
376
377         pcl_send_frame(tty, &pkt);
378         pcl_read_reset_response(tty);
379 }
380
381 int pcl_lin_init(int tty)
382 {
383         pcl_packet_t pkt;
384 #if 0
385         /* Initialization according to current parameters */
386         pkt.stx = PCL_STX;
387         pkt.seq_no = 0x0;
388         pkt.seq_frlen = 0x0;
389         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
390         pkt.ctrl_comc = 0x0;
391
392         pcl_send_frame(tty, &pkt);
393         pcl_read_response(tty);
394 #endif
395
396         /* Reset module */
397         pcl_reset_device(tty);
398
399         /* Erase Master Scheduler List */
400         pkt.stx = PCL_STX;
401         pkt.seq_no = 0x0;
402         pkt.seq_frlen = 0x0;
403         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
404         pkt.ctrl_comc = 0x33;
405
406         pcl_send_frame(tty, &pkt);
407         pcl_read_response(tty);
408
409         /* Set Activation Status */
410         pkt.stx = PCL_STX;
411         pkt.seq_no = 0x0;
412         pkt.seq_frlen = 0x1;
413         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
414         pkt.ctrl_comc = 0x1E;
415         pkt.parms[0] = 0x01;
416
417         pcl_send_frame(tty, &pkt);
418         pcl_read_response(tty);
419
420         /* Set bitrate */
421         pkt.stx = PCL_STX;
422         pkt.seq_no = 0x0;
423         pkt.seq_frlen = 0x2;
424         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
425         pkt.ctrl_comc = 0x1F;
426         pkt.parms[0] = 0x00;
427         pkt.parms[1] = 0x4B; /* 19200 kBit/s */
428
429         pcl_send_frame(tty, &pkt);
430         pcl_read_response(tty);
431
432         /* Set Forward Mask */
433         pkt.stx = PCL_STX;
434         pkt.seq_no = 0x0;
435         pkt.seq_frlen = 0x1;
436         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
437         pkt.ctrl_comc = 0x20;
438         pkt.parms[0] = 0x00;
439
440         pcl_send_frame(tty, &pkt);
441         pcl_read_response(tty);
442
443         /* Set Filter Mask */
444         pkt.stx = PCL_STX;
445         pkt.seq_no = 0x0;
446         pkt.seq_frlen = 0x1;
447         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
448         pkt.ctrl_comc = 0x21;
449         pkt.parms[0] = 0xFF;
450
451         pcl_send_frame(tty, &pkt);
452         pcl_read_response(tty);
453
454         /* Set Filter Code */
455         pkt.stx = PCL_STX;
456         pkt.seq_no = 0x0;
457         pkt.seq_frlen = 0x1;
458         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
459         pkt.ctrl_comc = 0x21;
460         pkt.parms[0] = 0x00;
461
462         pcl_send_frame(tty, &pkt);
463         pcl_read_response(tty);
464
465         /* Set Message Transmission Timeouts */
466         pkt.stx = PCL_STX;
467         pkt.seq_no = 0x0;
468         pkt.seq_frlen = 0x8;
469         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
470         pkt.ctrl_comc = 0x26;
471         pkt.parms[0] = 0xA0;
472         pkt.parms[1] = 0x0F;
473         pkt.parms[2] = 0x09;
474         pkt.parms[3] = 0x00;
475         pkt.parms[4] = 0x06;
476         pkt.parms[5] = 0x00;
477         pkt.parms[6] = 0x05;
478         pkt.parms[7] = 0x00;
479
480         pcl_send_frame(tty, &pkt);
481         pcl_read_response(tty);
482
483         /* Set Message Retries */
484         pkt.stx = PCL_STX;
485         pkt.seq_no = 0x0;
486         pkt.seq_frlen = 0x1;
487         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
488         pkt.ctrl_comc = 0x27;
489         pkt.parms[0] = 0x0;
490
491         pcl_send_frame(tty, &pkt);
492         pcl_read_response(tty);
493
494         /* Set Slave ID + Data configuration */
495         pcl_set_slave_id_and_data_configuration(tty);
496
497         /* Insert scheduler entry */
498         pcl_insert_scheduler_entries(tty);
499
500         /* Set master status: Active */
501         pkt.stx = PCL_STX;
502         pkt.seq_no = 0x0;
503         pkt.seq_frlen = 0x1;
504         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
505         pkt.ctrl_comc = 0x24;
506         pkt.parms[0] = (pcl_slave_only_fl) ? 0x0 : 0x1;
507
508         pcl_send_frame(tty, &pkt);
509         pcl_read_response(tty);
510
511         /* Set LIN bus termination */
512         pkt.stx = PCL_STX;
513         pkt.seq_no = 0x0;
514         pkt.seq_frlen = 0x1;
515         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
516         pkt.ctrl_comc = 0x25;
517         pkt.parms[0] = (pcl_slave_only_fl) ? 0x0 : 0x1;
518         /* Should have the same value as "Set master status" */
519
520         pcl_send_frame(tty, &pkt);
521         pcl_read_response(tty);
522
523         return 0;
524 }
525
526 static void pcl_reset_input_mode(int tty)
527 {
528         tcsetattr(tty, TCSANOW, &term_attr);
529 }
530
531 static void pcl_set_input_mode(int tty)
532 {
533         int status;
534         struct termios tattr;
535
536         /* Flush input and output queues. */
537         if (tcflush(tty, TCIOFLUSH) != 0) {
538                 perror("tcflush");
539                 exit(EXIT_FAILURE);
540         }
541
542         /* Fetch the current terminal parameters. */
543         if (!isatty(tty)) {
544                 fprintf(stderr, "Not a terminal.\n");
545                 exit(EXIT_FAILURE);
546         }
547
548         /* Save settings for later restoring */
549         tcgetattr(tty, &term_attr);
550
551         /* RAW mode */
552         tcgetattr(tty, &tattr);
553         tattr.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
554                                 | INLCR | IGNCR | ICRNL | IXON);
555         tattr.c_oflag &= ~OPOST;
556         tattr.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
557         tattr.c_cflag &= ~(CSIZE | PARENB);
558         tattr.c_cflag |= CS8;
559
560         tattr.c_cc[VMIN] = 1;
561         tattr.c_cc[VTIME] = 0;
562
563         /* Set TX, RX speed */
564         cfsetispeed(&tattr, B38400);
565         cfsetospeed(&tattr, B38400);
566
567         status = tcsetattr(tty, TCSANOW, &tattr);
568         if (status == -1)
569                 perror("tcsetattr()");
570
571 }
572
573 void pcl_explain(int argc, char *argv[])
574 {
575         fprintf(stderr, "Usage: %s [OPTIONS] <SERIAL_INTERFACE>\n", argv[0]);
576         fprintf(stderr, "\n");
577         fprintf(stderr, "'pcan_lin_config' Is used for configuring PEAK PCAN-LIN device.\n");
578         fprintf(stderr, "  When invoked without any OPTIONS, it configures PCAN-LIN device\n");
579         fprintf(stderr, "  with default configuration from the program.\n");
580         fprintf(stderr, "  The PCAN-LIN module enables CAN, LIN and serial participants to communicate.\n");
581         fprintf(stderr, "\n");
582         fprintf(stderr, "Options:\n");
583         fprintf(stderr, " -r         Execute only Reset of a device\n");
584         fprintf(stderr, " -f         Flash the active configuration\n");
585         fprintf(stderr, " -s         Activate only LIN Slave node in the device\n");
586         fprintf(stderr, "\n");
587         fprintf(stderr, "Examples:\n");
588         fprintf(stderr, " %s /dev/ttyS0      (Configure the device with the default configuration)\n", argv[0]);
589         fprintf(stderr, " %s -r /dev/ttyS0   (Reset the device)\n", argv[0]);
590 }
591
592 int main(int argc, char *argv[])
593 {
594         char dev[32]; // FIXME
595         int tty;
596         int opt;
597         int pcl_reset_device_fl = false;
598         int pcl_flash_config_fl = false;
599
600         while ((opt = getopt(argc, argv, "rfs")) != -1) {
601                 switch (opt) {
602                 case 'r':
603                         pcl_reset_device_fl = true;
604                         break;
605                 case 'f':
606                         pcl_flash_config_fl = true;
607                         break;
608                 case 's':
609                         pcl_slave_only_fl = true;
610                         break;
611                 default:
612                         pcl_explain(argc, argv);
613                         exit(EXIT_FAILURE);
614                 }
615         }
616
617         /* Expected argument after options */
618         if (optind >= argc) {
619                 pcl_explain(argc, argv);
620                 exit(EXIT_FAILURE);
621         }
622
623         strncpy((char *) &dev, argv[optind], 32);
624         tty = open(dev, O_RDWR);
625         if (tty < 0) {
626                 perror("open()");
627                 return -4;
628         }
629
630         /* Configure UART */
631         pcl_set_input_mode(tty);
632
633         if (pcl_reset_device_fl) {
634                 pcl_reset_device(tty);
635                 goto exit;
636         }
637
638         pcl_lin_init(tty);
639
640         if (pcl_flash_config_fl) {
641                 pcl_flash_config(tty);
642                 pcl_reset_device(tty);
643         }
644
645 exit:
646         pcl_reset_input_mode(tty);
647         close(tty);
648
649         return EXIT_SUCCESS;
650 }