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