]> rtime.felk.cvut.cz Git - linux-lin.git/blob - lin_config/src/pcan_lin_config.c
pcanlin: Passing of XML configuration file path through program parameter
[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 #include <assert.h>
21 #include <libxml/parser.h>
22
23 #define true                                    1
24 #define false                                   0
25
26 #define MAX_LIN_ID                              0x3F
27 #define PCL_ACTIVE                              1
28 #define PCL_UNACTIVE                            0
29 #define PCL_DEFAULT_CONFIG                      "config.pclin"
30
31 #define PCL_PKT_MAX_SIZE                        16
32 #define PCL_HEADERS_SIZE                        2 /* There are 2 bytes of headers */
33 #define PCL_CHECKSUM_SIZE                       1
34 #define PCL_STX_SIZE                            1
35 #define PCL_PACKET_OVERHEAD                     (PCL_HEADERS_SIZE + PCL_CHECKSUM_SIZE)
36
37 #define PCL_STX                                 0x2
38
39 #define PCL_SEQ_NO_ofs                          4
40 #define PCL_SEQ_FRLEN_ofs                       0
41 #define PCL_CTRL_TIFACE_ofs                     6
42 #define PCL_CTRL_COMC_ofs                       0
43
44 #define PCL_SEQ_FRLEN_msk                       0xF
45
46 #define PCL_PACKET_LIN_IFACE                    0x2
47 #define PCL_PACKET_MODULE_IFACE                 0x3
48
49 /* Logical representation of a packet sent to PCAN-LIN converter via RS232 */
50 typedef struct {
51         uint8_t stx;        /* Start transmission; Always set to 0x2 */
52         uint8_t seq_no;     /* Sequence number */
53         uint8_t seq_frlen;  /* Frame length */
54         uint8_t ctrl_tiface;/* Target interface */
55         uint8_t ctrl_comc;  /* Command code */
56         uint8_t parms[8];   /* Parameters; Number of parameters depends
57                                 on the frame length */
58         uint8_t chks;       /* Checksum; Bitwise XOR of all bytes except STX */
59 } pcl_packet_t;
60
61 struct pcl_scheduler_entry {
62         int lin_id;
63         int interval_ms;
64 };
65
66 /* Index in this array = LIN ID */
67 struct pcl_frame_entry {
68         int status; /* 1 = active; 0 = unactive */
69         int data_len;
70         char data[8];
71 };
72
73 struct pcl_lin_state {
74         int is_active;
75         int baudrate;
76         int master_status;
77         int bus_termination;
78 };
79
80 struct pcl_lin_state pcl_lin_state;
81 struct pcl_frame_entry pcl_frame_entry[MAX_LIN_ID];
82 struct pcl_scheduler_entry pcl_scheduler_entry[100]; // FIXME max value
83 int pcl_scheduler_entries_cnt;
84
85 struct termios term_attr;
86 /* ------------------------------------------------------------------------ */
87
88 /* Transform 'logic' representation of a frame to exact byte sequence */
89 int pcl_serialize(pcl_packet_t *pkt, uint8_t *pkt_raw)
90 {
91         int i;
92         uint8_t checksum = 0;
93
94         pkt_raw[0] = pkt->stx;
95         pkt_raw[1] = (pkt->seq_no << PCL_SEQ_NO_ofs) |
96                         (pkt->seq_frlen << PCL_SEQ_FRLEN_ofs);
97         pkt_raw[2] = (pkt->ctrl_tiface << PCL_CTRL_TIFACE_ofs) |
98                         (pkt->ctrl_comc << PCL_CTRL_COMC_ofs);
99
100         for (i = 0; i < pkt->seq_frlen; i++) {
101                 pkt_raw[3+i] = pkt->parms[i];
102         }
103
104         /* Calculate XOR checksum; Skip STX */
105         for (i = 1; i <= pkt->seq_frlen + PCL_HEADERS_SIZE; i++) {
106                 checksum ^= pkt_raw[i];
107         }
108         pkt_raw[i] = checksum;
109
110         printf("Snd: [STX] [SEQ] [PRM] [...] \n      ");
111         for (i = 0; i < pkt->seq_frlen + PCL_PACKET_OVERHEAD + 1; i++)
112                 printf("0x%02X  ", pkt_raw[i]);
113         printf("\n");
114
115         return pkt->seq_frlen + 4; /* real packet size */
116 }
117
118 int pcl_send_frame(int tty, pcl_packet_t *pkt)
119 {
120         int pkt_size;
121         int to_send;
122         int sent;
123         uint8_t pkt_buff[PCL_PKT_MAX_SIZE];
124
125         pkt_size = pcl_serialize(pkt, (uint8_t *) &pkt_buff);
126         to_send = pkt_size;
127         sent = 0;
128
129         while (to_send > 0) {
130                 sent = write(tty, pkt_buff+sent, to_send);
131                 to_send -= sent;
132         }
133
134         memset(pkt, '\0', sizeof(pcl_packet_t));
135         return 0;
136 }
137
138 int pcl_read_reset_response(int tty)
139 {
140         char c;
141         int ret;
142         int i = 0;
143         char str_match[] = {'G', 'm', 'b', 'H'};
144
145         do {
146                 ret = read(tty, &c, 1);
147                 if (ret == -1)
148                         perror("read()");
149
150                 printf("%c", c);
151
152                 if ((c == str_match[i]) && (i == 3))
153                         i = -1; /* We are done -- Stop the loop*/
154                 else if (c == str_match[i])
155                         i++; /* Match found -- Go to the next letter */
156                 else
157                         i = 0; /* Start from beginning */
158
159         } while (i != -1);
160
161         printf("\n\n");
162
163         return 0;
164 }
165
166 int pcl_read_response(int tty)
167 {
168         int i;
169         int received = 0;
170         int to_read = 0;
171         int data_length = 0;
172         uint8_t buff[PCL_PKT_MAX_SIZE];
173         //memset(buff, '\0', sizeof(buff));
174
175         /* Read 2 bytes of header */
176         received = read(tty, &buff[0], 1); /* Read STX */
177         if (received == -1)
178                 perror("read()");
179
180         if (buff[0] == 0x2) { /* STX ok */
181                 received = read(tty, &buff[1], 1); /* Read SEQ */
182                 if (received == -1)
183                         perror("read()");
184         } else {
185                 return 1;
186         }
187
188         data_length = (buff[1] & PCL_SEQ_FRLEN_msk);
189         to_read = data_length + 1; /* +chksm */
190         while (to_read > 0) {
191                 received = read(tty, &buff[2], to_read);
192                 to_read -= received;
193         }
194
195         printf("Rcv: [STX] [SEQ] [PRM] [CHK]\n"); // FIXME add spaces before "CHKS" when
196                                                         //more than 1 byte received in params
197         printf("      0x%02X  0x%02X", buff[0], buff[1]);
198         for (i = 0; i < data_length; i++) {
199                 printf("  0x%02X", buff[i + 2]);
200         }
201         printf("  0x%02X\n\n", buff[i]);
202
203         return 0;
204 }
205
206 void pcl_insert_scheduler_entries(int tty)
207 {
208         pcl_packet_t pkt;
209         int i;
210
211         /* Insert scheduler entry */
212         for (i = 0; i < (sizeof(pcl_scheduler_entry)/sizeof(struct pcl_scheduler_entry)); i++) {
213                 pkt.stx = PCL_STX;
214                 pkt.seq_no = 0x0;
215                 pkt.seq_frlen = 0x3;
216                 pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
217                 pkt.ctrl_comc = 0x28;
218                 pkt.parms[0] = (pcl_scheduler_entry[i].interval_ms) & 0xFF;
219                 pkt.parms[1] = (pcl_scheduler_entry[i].interval_ms >> 8) & 0xFF;
220                 pkt.parms[2] = pcl_scheduler_entry[i].lin_id; /* LIN ID */
221
222                 pcl_send_frame(tty, &pkt);
223                 pcl_read_response(tty);
224         }
225
226 }
227
228 void pcl_set_slave_id_and_data_configuration(int tty)
229 {
230         pcl_packet_t pkt;
231         int i;
232
233         /* Set Slave ID + Data Configuration */
234         for (i = 0; i < 0x3F; i++) {
235                 int len;
236
237                 if (pcl_frame_entry[i].status == PCL_ACTIVE) {
238                         pkt.stx = PCL_STX;
239                         pkt.seq_no = 0x0;
240                         pkt.seq_frlen = pcl_frame_entry[i].data_len + 2;
241                         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
242                         pkt.ctrl_comc = 0x29;
243                         pkt.parms[0] = pcl_frame_entry[i].status; /* Field Status */
244                         pkt.parms[1] = i; /* LIN ID */
245                         pkt.parms[2] = pcl_frame_entry[i].data[0]; /* Data */
246                         pkt.parms[3] = pcl_frame_entry[i].data[1]; /* Data */
247                         pkt.parms[4] = pcl_frame_entry[i].data[2]; /* Data */
248                         pkt.parms[5] = pcl_frame_entry[i].data[3]; /* Data */
249                         pkt.parms[6] = pcl_frame_entry[i].data[4]; /* Data */
250                         pkt.parms[7] = pcl_frame_entry[i].data[5]; /* Data */
251                         pkt.parms[8] = pcl_frame_entry[i].data[6]; /* Data */
252                         pkt.parms[9] = pcl_frame_entry[i].data[7]; /* Data */
253
254                 } else {
255                         if (i < 0x20)
256                                 len = 4;
257                         else if (i < 0x30)
258                                 len = 6;
259                         else
260                                 len = 8;
261
262                         pkt.stx = PCL_STX;
263                         pkt.seq_no = 0x0;
264                         pkt.seq_frlen = len;
265                         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
266                         pkt.ctrl_comc = 0x29;
267                         pkt.parms[0] = 0x00; /* Field Status -- unactive */
268                         pkt.parms[1] = i; /* LIN ID */
269                 }
270
271                 pcl_send_frame(tty, &pkt);
272                 pcl_read_response(tty);
273         }
274 }
275
276 void pcl_flash_config(int tty)
277 {
278         pcl_packet_t pkt;
279
280         /* Flash Current Configuration */
281         pkt.stx = PCL_STX;
282         pkt.seq_no = 0x0;
283         pkt.seq_frlen = 0x0;
284         pkt.ctrl_tiface = PCL_PACKET_MODULE_IFACE;
285         pkt.ctrl_comc = 0x3;
286
287         pcl_send_frame(tty, &pkt);
288         pcl_read_response(tty);
289 }
290
291 void pcl_reset_device(int tty)
292 {
293         pcl_packet_t pkt;
294
295         /* Reset module */
296         pkt.stx = PCL_STX;
297         pkt.seq_no = 0x0;
298         pkt.seq_frlen = 0x0;
299         pkt.ctrl_tiface = PCL_PACKET_MODULE_IFACE;
300         pkt.ctrl_comc = 0x4;
301
302         pcl_send_frame(tty, &pkt);
303         pcl_read_reset_response(tty);
304 }
305
306 int pcl_lin_init(int tty)
307 {
308         pcl_packet_t pkt;
309 #if 0
310         /* Initialization according to current parameters */
311         pkt.stx = PCL_STX;
312         pkt.seq_no = 0x0;
313         pkt.seq_frlen = 0x0;
314         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
315         pkt.ctrl_comc = 0x0;
316
317         pcl_send_frame(tty, &pkt);
318         pcl_read_response(tty);
319 #endif
320
321         /* Reset module */
322         pcl_reset_device(tty);
323
324         /* Erase Master Scheduler List */
325         pkt.stx = PCL_STX;
326         pkt.seq_no = 0x0;
327         pkt.seq_frlen = 0x0;
328         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
329         pkt.ctrl_comc = 0x33;
330
331         pcl_send_frame(tty, &pkt);
332         pcl_read_response(tty);
333
334         /* Set Activation Status */
335         pkt.stx = PCL_STX;
336         pkt.seq_no = 0x0;
337         pkt.seq_frlen = 0x1;
338         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
339         pkt.ctrl_comc = 0x1E;
340         pkt.parms[0] = pcl_lin_state.is_active;
341
342         pcl_send_frame(tty, &pkt);
343         pcl_read_response(tty);
344
345         /* Set bitrate */
346         pkt.stx = PCL_STX;
347         pkt.seq_no = 0x0;
348         pkt.seq_frlen = 0x2;
349         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
350         pkt.ctrl_comc = 0x1F;
351         pkt.parms[0] = 0x00;
352         pkt.parms[1] = 0x4B; /* 19200 kBit/s */
353
354         pcl_send_frame(tty, &pkt);
355         pcl_read_response(tty);
356
357         /* Set Forward Mask */
358         pkt.stx = PCL_STX;
359         pkt.seq_no = 0x0;
360         pkt.seq_frlen = 0x1;
361         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
362         pkt.ctrl_comc = 0x20;
363         pkt.parms[0] = 0x00;
364
365         pcl_send_frame(tty, &pkt);
366         pcl_read_response(tty);
367
368         /* Set Filter Mask */
369         pkt.stx = PCL_STX;
370         pkt.seq_no = 0x0;
371         pkt.seq_frlen = 0x1;
372         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
373         pkt.ctrl_comc = 0x21;
374         pkt.parms[0] = 0xFF;
375
376         pcl_send_frame(tty, &pkt);
377         pcl_read_response(tty);
378
379         /* Set Filter Code */
380         pkt.stx = PCL_STX;
381         pkt.seq_no = 0x0;
382         pkt.seq_frlen = 0x1;
383         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
384         pkt.ctrl_comc = 0x21;
385         pkt.parms[0] = 0x00;
386
387         pcl_send_frame(tty, &pkt);
388         pcl_read_response(tty);
389
390         /* Set Message Transmission Timeouts */
391         pkt.stx = PCL_STX;
392         pkt.seq_no = 0x0;
393         pkt.seq_frlen = 0x8;
394         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
395         pkt.ctrl_comc = 0x26;
396         pkt.parms[0] = 0xA0;
397         pkt.parms[1] = 0x0F;
398         pkt.parms[2] = 0x09;
399         pkt.parms[3] = 0x00;
400         pkt.parms[4] = 0x06;
401         pkt.parms[5] = 0x00;
402         pkt.parms[6] = 0x05;
403         pkt.parms[7] = 0x00;
404
405         pcl_send_frame(tty, &pkt);
406         pcl_read_response(tty);
407
408         /* Set Message Retries */
409         pkt.stx = PCL_STX;
410         pkt.seq_no = 0x0;
411         pkt.seq_frlen = 0x1;
412         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
413         pkt.ctrl_comc = 0x27;
414         pkt.parms[0] = 0x0;
415
416         pcl_send_frame(tty, &pkt);
417         pcl_read_response(tty);
418
419         /* Set Slave ID + Data configuration */
420         pcl_set_slave_id_and_data_configuration(tty);
421
422         /* Insert scheduler entry */
423         pcl_insert_scheduler_entries(tty);
424
425         /* Set master status: Active */
426         pkt.stx = PCL_STX;
427         pkt.seq_no = 0x0;
428         pkt.seq_frlen = 0x1;
429         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
430         pkt.ctrl_comc = 0x24;
431         pkt.parms[0] = pcl_lin_state.master_status;
432
433         pcl_send_frame(tty, &pkt);
434         pcl_read_response(tty);
435
436         /* Set LIN bus termination */
437         pkt.stx = PCL_STX;
438         pkt.seq_no = 0x0;
439         pkt.seq_frlen = 0x1;
440         pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
441         pkt.ctrl_comc = 0x25;
442         pkt.parms[0] = pcl_lin_state.bus_termination;
443         /* Should have the same value as "Set master status" */
444
445         pcl_send_frame(tty, &pkt);
446         pcl_read_response(tty);
447
448         return 0;
449 }
450
451 static void pcl_reset_input_mode(int tty)
452 {
453         tcsetattr(tty, TCSANOW, &term_attr);
454 }
455
456 static void pcl_set_input_mode(int tty)
457 {
458         int status;
459         struct termios tattr;
460
461         /* Flush input and output queues. */
462         if (tcflush(tty, TCIOFLUSH) != 0) {
463                 perror("tcflush");
464                 exit(EXIT_FAILURE);
465         }
466
467         /* Fetch the current terminal parameters. */
468         if (!isatty(tty)) {
469                 fprintf(stderr, "Not a terminal.\n");
470                 exit(EXIT_FAILURE);
471         }
472
473         /* Save settings for later restoring */
474         tcgetattr(tty, &term_attr);
475
476         /* RAW mode */
477         tcgetattr(tty, &tattr);
478         tattr.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
479                                 | INLCR | IGNCR | ICRNL | IXON);
480         tattr.c_oflag &= ~OPOST;
481         tattr.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
482         tattr.c_cflag &= ~(CSIZE | PARENB);
483         tattr.c_cflag |= CS8;
484
485         tattr.c_cc[VMIN] = 1;
486         tattr.c_cc[VTIME] = 0;
487
488         /* Set TX, RX speed */
489         cfsetispeed(&tattr, B38400);
490         cfsetospeed(&tattr, B38400);
491
492         status = tcsetattr(tty, TCSANOW, &tattr);
493         if (status == -1)
494                 perror("tcsetattr()");
495
496 }
497
498 /****** XML PARSING ******/
499
500 static inline int pcl_xml_get_prop_int(xmlNodePtr cur, const xmlChar* str)
501 {
502         int val;
503         xmlChar *attr;
504
505         attr = xmlGetProp(cur, str);
506         if (!attr)
507                 assert(0);
508
509         val = atoi((const char *)attr); // FIXME error handling
510         xmlFree(attr);
511
512         return val;
513 }
514
515 static inline int pcl_xml_get_element_int(xmlDocPtr doc, xmlNodePtr cur)
516 {
517         xmlChar *key;
518         int val;
519
520         key = xmlNodeListGetString(doc, cur->children, 1);
521         if (!key)
522                 assert(0);
523
524         val = atoi((const char *)key); // FIXME error handling etc.
525         xmlFree(key);
526
527         return val;
528 }
529
530 void pcl_parse_scheduler_entries(xmlDocPtr doc, xmlNodePtr cur)
531 {
532         cur = cur->children;
533         while (cur) {
534                 if (!xmlStrcmp(cur->name, (const xmlChar *)"Entry")) {
535                         int linid;
536                         int interval;
537                         linid = pcl_xml_get_element_int(doc, cur);
538                         interval = pcl_xml_get_prop_int(cur, (const xmlChar *)"Time");
539
540                         pcl_scheduler_entry[pcl_scheduler_entries_cnt].lin_id = linid;
541                         pcl_scheduler_entry[pcl_scheduler_entries_cnt].interval_ms = interval;
542                         pcl_scheduler_entries_cnt++;
543
544                         //printf("Time = %d Entry = %d\n", interval, linid);
545                 }
546                 cur = cur->next;
547         }
548 }
549
550 void pcl_parse_frame_configuration(xmlDocPtr doc, xmlNodePtr cur)
551 {
552         xmlNodePtr tmp_node;
553         int val;
554
555         cur = cur->children;
556         while (cur) {
557                 if (!xmlStrcmp(cur->name, (const xmlChar *)"Frame")) {
558                         tmp_node = cur->children;
559                         /* We are able to write into the main Configuration array after
560                         parsing of all necessary elements (especially LIN ID) -- store
561                         parsed elements in this temporary entry -- copy the entry afterwards */
562                         struct pcl_frame_entry tmp_fr_entry;
563                         int linid = -1;
564
565                         while (tmp_node) {
566                                 if (!xmlStrcmp(tmp_node->name, (const xmlChar *)"ID")) {
567                                         val = pcl_xml_get_element_int(doc, tmp_node);
568                                         linid = val;
569                                         //printf("ID = %d\n", val);
570                                 }
571                                 if (!xmlStrcmp(tmp_node->name, (const xmlChar *)"Length")) {
572                                         val = pcl_xml_get_element_int(doc, tmp_node);
573                                         tmp_fr_entry.data_len = val;
574                                         //printf("Length = %d\n", val);
575                                 }
576                                 if (!xmlStrcmp(tmp_node->name, (const xmlChar *)"Active")) {
577                                         val = pcl_xml_get_element_int(doc, tmp_node);
578                                         tmp_fr_entry.status = val;
579                                         //printf("Active = %d\n", val);
580                                 }
581                                 if (!xmlStrcmp(tmp_node->name, (const xmlChar *)"Data")) {
582                                         int indx = 0;
583                                         xmlNodePtr tmp_node2;
584                                         tmp_node2 = tmp_node->children;
585                                         while (tmp_node2) {
586                                                 if (!xmlStrcmp(tmp_node2->name, (const xmlChar *)"Byte")) {
587                                                         // Byte indexing in XML file is wrong
588                                                         //indx = pcl_xml_get_prop_int(tmp_node2,
589                                                         //      (const xmlChar *)"Index");
590                                                         val = pcl_xml_get_element_int(doc, tmp_node2);
591                                                         //printf("Data = %d\n", val);
592                                                         snprintf((char *)&tmp_fr_entry.data[indx], 1, "%i", val);
593                                                         indx++;
594                                                 }
595                                                 tmp_node2 = tmp_node2->next;
596                                         }
597                                 }
598                                 tmp_node = tmp_node->next;
599                         }
600
601                         if (linid >= 0) {
602                                 memcpy(&pcl_frame_entry[linid], &tmp_fr_entry,
603                                         sizeof(struct pcl_frame_entry));
604                         }
605                 }
606                 cur = cur->next;
607         }
608 }
609
610 int pcl_parse_configuration(char *filename)
611 {
612         xmlDocPtr doc;
613         xmlNodePtr cur_node;
614
615         if (!filename)
616                 filename = PCL_DEFAULT_CONFIG;
617
618         xmlKeepBlanksDefault(1);
619         doc = xmlParseFile(filename);
620         if (doc == NULL)
621                 return -1;
622
623         cur_node = xmlDocGetRootElement(doc);
624         if (cur_node == NULL) {
625                 fprintf(stderr, "Configuration file %s is empty\n", filename);
626                 xmlFreeDoc(doc);
627                 return -1;
628         }
629
630         /* Check for Root element */
631         if (xmlStrcmp(cur_node->name, (const xmlChar *)"PCLIN_PROFILE"))
632                 goto exit_failure;
633
634         /* Check for LIN element */
635         cur_node = cur_node->children;
636         while (cur_node) {
637                 if (!xmlStrcmp(cur_node->name, (const xmlChar *)"LIN"))
638                         break;
639
640                 cur_node = cur_node->next;
641         }
642
643         if (!cur_node)
644                 goto exit_failure;
645
646         /* Process LIN configuration */
647         cur_node = cur_node->children;
648         while (cur_node) {
649                 if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Active")) {
650                         pcl_lin_state.is_active = pcl_xml_get_element_int(doc, cur_node);
651                 }
652                 if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Baudrate")) {
653                         pcl_lin_state.baudrate = pcl_xml_get_element_int(doc, cur_node);
654                 }
655                 if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Master_Status")) {
656                         pcl_lin_state.master_status = pcl_xml_get_element_int(doc, cur_node);
657                 }
658                 if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Bus_Termination")) {
659                         pcl_lin_state.bus_termination = pcl_xml_get_element_int(doc, cur_node);
660                 }
661                 if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Scheduler_Entries")) {
662                         pcl_parse_scheduler_entries(doc, cur_node);
663                 }
664                 if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Frame_Configuration")) {
665                         pcl_parse_frame_configuration(doc, cur_node);
666                 }
667
668                 cur_node = cur_node->next;
669         }
670
671         xmlFreeDoc(doc);
672         return 0;
673
674 exit_failure:
675         fprintf(stderr, "Invalid configuration file\n");
676         xmlFreeDoc(doc);
677         return -1;
678 }
679
680 void pcl_explain(int argc, char *argv[])
681 {
682         fprintf(stderr, "Usage: %s [OPTIONS] <SERIAL_INTERFACE>\n", argv[0]);
683         fprintf(stderr, "\n");
684         fprintf(stderr, "'pcan_lin_config' Is used for configuring PEAK PCAN-LIN device.\n");
685         fprintf(stderr, "  When invoked without any OPTIONS, it configures PCAN-LIN device\n");
686         fprintf(stderr, "  with configuration obtained from '"PCL_DEFAULT_CONFIG"' file (if it exists).\n");
687         fprintf(stderr, "  The PCAN-LIN module enables CAN, LIN and serial participants to communicate.\n");
688         fprintf(stderr, "\n");
689         fprintf(stderr, "Options:\n");
690         fprintf(stderr, " -r          Execute only Reset of a device\n");
691         fprintf(stderr, " -f          Flash the active configuration\n");
692         fprintf(stderr, " -c <FILE>   Path to XML configuration file\n");
693         fprintf(stderr, "\n");
694         fprintf(stderr, "Examples:\n");
695         fprintf(stderr, " %s /dev/ttyS0      (Configure the device with the configuration from '"PCL_DEFAULT_CONFIG"')\n",
696                 argv[0]);
697         fprintf(stderr, " %s -r /dev/ttyS0   (Reset the device)\n", argv[0]);
698 }
699
700 int main(int argc, char *argv[])
701 {
702         char dev[32]; // FIXME
703         int ret;
704         int tty;
705         int opt;
706         int pcl_reset_device_fl = false;
707         int pcl_flash_config_fl = false;
708         char *filename = NULL;
709
710         while ((opt = getopt(argc, argv, "rfc:")) != -1) {
711                 switch (opt) {
712                 case 'r':
713                         pcl_reset_device_fl = true;
714                         break;
715                 case 'f':
716                         pcl_flash_config_fl = true;
717                         break;
718                 case 'c':
719                         filename = optarg;
720                         break;
721                 default:
722                         pcl_explain(argc, argv);
723                         exit(EXIT_FAILURE);
724                 }
725         }
726
727         /* Expected argument after options */
728         if (optind >= argc) {
729                 pcl_explain(argc, argv);
730                 exit(EXIT_FAILURE);
731         }
732
733         strncpy((char *) &dev, argv[optind], 32);
734         tty = open(dev, O_RDWR);
735         if (tty < 0) {
736                 perror("open()");
737                 return -4;
738         }
739
740         ret = pcl_parse_configuration(filename);
741         if (!ret)
742                 printf("Configuration file %s parsed correctly\n", filename);
743
744         /* Configure UART */
745         pcl_set_input_mode(tty);
746
747         if (pcl_reset_device_fl) {
748                 pcl_reset_device(tty);
749                 goto exit;
750         }
751
752         pcl_lin_init(tty);
753
754         if (pcl_flash_config_fl) {
755                 pcl_flash_config(tty);
756                 pcl_reset_device(tty);
757         }
758
759 exit:
760         pcl_reset_input_mode(tty);
761         close(tty);
762
763         return EXIT_SUCCESS;
764 }