Configuring of another devices should be implemented more easily.
CC=gcc
-CFLAGS=-std=gnu99 -Wall -pedantic $(XMLCFLAGS) $(DEBUG)
-XMLCFLAGS=`xml2-config --cflags` `xml2-config --libs`
+CFLAGS=-std=gnu99 -Wall -pedantic $(DEBUG) `xml2-config --cflags`
+LIBS=`xml2-config --libs`
DEBUG=-ggdb
-all: pcan_lin_config
+objects = linc_parse_xml.o pcl_config.o lin_config.o
-pcan_lin_config: pcan_lin_config.c
- $(CC) $< $(CFLAGS) -o $@
+lin_config: $(objects)
+ $(CC) $(objects) $(LIBS) -o lin_config
+
+%.o : %.c
+ $(CC) $(CFLAGS) $(LIBS) -c $< -o $@
+
+.PHONY: clean
+clean:
+ rm *.o
--- /dev/null
+/*
+ * PCAN-LIN, RS-232 to CAN/LIN converter control application
+ *
+ * This program is free software; you can distribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of
+ * the License.
+ *
+ * Copyright: (c) 2012 Czech Technical University in Prague
+ * Authors: Rostislav Lisovy <lisovy@gmail.cz>
+ */
+
+/*
+ Used prefixes explanation:
+ pcl_ -- PCAN-LIN (hw) related functions
+ sll_ -- sllin (tty lin implementation) related functions
+ linc_ -- LIN config general functions
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <termios.h>
+#include <stdint.h>
+#include <assert.h>
+#include "linc_parse_xml.h"
+#include "pcl_config.h"
+#include "lin_config.h"
+
+
+void linc_explain(int argc, char *argv[])
+{
+ fprintf(stderr, "Usage: %s [OPTIONS] <SERIAL_INTERFACE>\n", argv[0]);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "'pcan_lin_config' Is used for configuring PEAK PCAN-LIN device.\n");
+ fprintf(stderr, " When invoked without any OPTIONS, it configures PCAN-LIN device\n");
+ fprintf(stderr, " with configuration obtained from '"PCL_DEFAULT_CONFIG"' file (if it exists).\n");
+ fprintf(stderr, " The PCAN-LIN module enables CAN, LIN and serial participants to communicate.\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -r Execute only Reset of a device\n");
+ fprintf(stderr, " -f Flash the active configuration\n");
+ fprintf(stderr, " -c <FILE> Path to XML configuration file\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Examples:\n");
+ fprintf(stderr, " %s /dev/ttyS0 (Configure the device with the configuration from '"PCL_DEFAULT_CONFIG"')\n",
+ argv[0]);
+ fprintf(stderr, " %s -r /dev/ttyS0 (Reset the device)\n", argv[0]);
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ int opt;
+ int flags = 0;
+ char *filename = NULL;
+
+ while ((opt = getopt(argc, argv, "rfc:")) != -1) {
+ switch (opt) {
+ case 'r':
+ flags |= RESET_DEVICE_fl;
+ break;
+ case 'f':
+ flags |= FLASH_CONF_fl;
+ break;
+ case 'c':
+ filename = optarg;
+ break;
+ default:
+ linc_explain(argc, argv);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* Expected argument after options */
+ if (optind >= argc) {
+ linc_explain(argc, argv);
+ exit(EXIT_FAILURE);
+ }
+
+ linc_lin_state.dev = strdup(argv[optind]);
+
+ ret = linc_parse_configuration(filename, &linc_lin_state);
+ if (!ret)
+ printf("Configuration file %s parsed correctly\n", filename);
+
+ pcl_config(&linc_lin_state, flags);
+
+ return EXIT_SUCCESS;
+}
--- /dev/null
+#ifndef _LIN_CONFIG_H_
+#define _LIN_CONFIG_H_
+
+#define FLASH_CONF_fl (1 << 0)
+#define RESET_DEVICE_fl (1 << 1)
+
+#define MAX_LIN_ID 0x3F
+#define PCL_DEFAULT_CONFIG "config.pclin"
+
+struct linc_scheduler_entry {
+ int lin_id;
+ int interval_ms;
+};
+
+/* Index in this array = LIN ID */
+struct linc_frame_entry {
+ int status; /* 1 = active; 0 = unactive */
+ int data_len;
+ char data[8];
+};
+
+struct linc_lin_state {
+ int is_active;
+ int baudrate;
+ int master_status;
+ int bus_termination;
+
+ struct linc_frame_entry frame_entry[MAX_LIN_ID];
+ struct linc_scheduler_entry scheduler_entry[100]; // FIXME max value
+ int scheduler_entries_cnt;
+
+ char *dev;
+};
+struct linc_lin_state linc_lin_state;
+
+
+#endif /* _LIN_CONFIG_H_ */
--- /dev/null
+#include <libxml/parser.h>
+#include <assert.h>
+#include <string.h>
+#include "lin_config.h"
+
+static inline int linc_xml_get_prop_int(xmlNodePtr cur, const xmlChar* str)
+{
+ int val;
+ xmlChar *attr;
+
+ attr = xmlGetProp(cur, str);
+ if (!attr)
+ assert(0);
+
+ val = atoi((const char *)attr); // FIXME error handling
+ xmlFree(attr);
+
+ return val;
+}
+
+static inline int linc_xml_get_element_int(xmlDocPtr doc, xmlNodePtr cur)
+{
+ xmlChar *key;
+ int val;
+
+ key = xmlNodeListGetString(doc, cur->children, 1);
+ if (!key)
+ assert(0);
+
+ val = atoi((const char *)key); // FIXME error handling etc.
+ xmlFree(key);
+
+ return val;
+}
+
+void linc_parse_scheduler_entries(struct linc_lin_state *linc_lin_state, xmlDocPtr doc, xmlNodePtr cur)
+{
+ cur = cur->children;
+ while (cur) {
+ if (!xmlStrcmp(cur->name, (const xmlChar *)"Entry")) {
+ int linid;
+ int interval;
+ linid = linc_xml_get_element_int(doc, cur);
+ interval = linc_xml_get_prop_int(cur, (const xmlChar *)"Time");
+
+ linc_lin_state->scheduler_entry[linc_lin_state->scheduler_entries_cnt].lin_id = linid;
+ linc_lin_state->scheduler_entry[linc_lin_state->scheduler_entries_cnt].interval_ms = interval;
+ linc_lin_state->scheduler_entries_cnt++;
+
+ //printf("Time = %d Entry = %d\n", interval, linid);
+ }
+ cur = cur->next;
+ }
+}
+
+void linc_parse_frame_configuration(struct linc_lin_state *linc_lin_state, xmlDocPtr doc, xmlNodePtr cur)
+{
+ xmlNodePtr tmp_node;
+ int val;
+
+ cur = cur->children;
+ while (cur) {
+ if (!xmlStrcmp(cur->name, (const xmlChar *)"Frame")) {
+ tmp_node = cur->children;
+ /* We are able to write into the main Configuration array after
+ parsing of all necessary elements (especially LIN ID) -- store
+ parsed elements in this temporary entry -- copy the entry afterwards */
+ struct linc_frame_entry tmp_fr_entry;
+ int linid = -1;
+
+ while (tmp_node) {
+ if (!xmlStrcmp(tmp_node->name, (const xmlChar *)"ID")) {
+ val = linc_xml_get_element_int(doc, tmp_node);
+ linid = val;
+ //printf("ID = %d\n", val);
+ }
+ if (!xmlStrcmp(tmp_node->name, (const xmlChar *)"Length")) {
+ val = linc_xml_get_element_int(doc, tmp_node);
+ tmp_fr_entry.data_len = val;
+ //printf("Length = %d\n", val);
+ }
+ if (!xmlStrcmp(tmp_node->name, (const xmlChar *)"Active")) {
+ val = linc_xml_get_element_int(doc, tmp_node);
+ tmp_fr_entry.status = val;
+ //printf("Active = %d\n", val);
+ }
+ if (!xmlStrcmp(tmp_node->name, (const xmlChar *)"Data")) {
+ int indx = 0;
+ xmlNodePtr tmp_node2;
+ tmp_node2 = tmp_node->children;
+ while (tmp_node2) {
+ if (!xmlStrcmp(tmp_node2->name, (const xmlChar *)"Byte")) {
+ // Byte indexing in XML file is wrong
+ //indx = linc_xml_get_prop_int(tmp_node2,
+ // (const xmlChar *)"Index");
+ val = linc_xml_get_element_int(doc, tmp_node2);
+ //printf("Data = %d\n", val);
+ snprintf((char *)&tmp_fr_entry.data[indx], 1, "%i", val);
+ indx++;
+ }
+ tmp_node2 = tmp_node2->next;
+ }
+ }
+ tmp_node = tmp_node->next;
+ }
+
+ if (linid >= 0) {
+ memcpy(&linc_lin_state->frame_entry[linid], &tmp_fr_entry,
+ sizeof(struct linc_frame_entry));
+ }
+ }
+ cur = cur->next;
+ }
+}
+
+int linc_parse_configuration(char *filename, struct linc_lin_state *linc_lin_state)
+{
+ xmlDocPtr doc;
+ xmlNodePtr cur_node;
+
+ if (!filename)
+ filename = PCL_DEFAULT_CONFIG;
+
+ xmlKeepBlanksDefault(1);
+ doc = xmlParseFile(filename);
+ if (doc == NULL)
+ return -1;
+
+ cur_node = xmlDocGetRootElement(doc);
+ if (cur_node == NULL) {
+ fprintf(stderr, "Configuration file %s is empty\n", filename);
+ xmlFreeDoc(doc);
+ return -1;
+ }
+
+ /* Check for Root element */
+ if (xmlStrcmp(cur_node->name, (const xmlChar *)"PCLIN_PROFILE"))
+ goto exit_failure;
+
+ /* Check for LIN element */
+ cur_node = cur_node->children;
+ while (cur_node) {
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"LIN"))
+ break;
+
+ cur_node = cur_node->next;
+ }
+
+ if (!cur_node)
+ goto exit_failure;
+
+ /* Process LIN configuration */
+ cur_node = cur_node->children;
+ while (cur_node) {
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Active")) {
+ linc_lin_state->is_active = linc_xml_get_element_int(doc, cur_node);
+ }
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Baudrate")) {
+ linc_lin_state->baudrate = linc_xml_get_element_int(doc, cur_node);
+ }
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Master_Status")) {
+ linc_lin_state->master_status = linc_xml_get_element_int(doc, cur_node);
+ }
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Bus_Termination")) {
+ linc_lin_state->bus_termination = linc_xml_get_element_int(doc, cur_node);
+ }
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Scheduler_Entries")) {
+ linc_parse_scheduler_entries(linc_lin_state, doc, cur_node);
+ }
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Frame_Configuration")) {
+ linc_parse_frame_configuration(linc_lin_state, doc, cur_node);
+ }
+
+ cur_node = cur_node->next;
+ }
+
+ xmlFreeDoc(doc);
+ return 0;
+
+exit_failure:
+ fprintf(stderr, "Invalid configuration file\n");
+ xmlFreeDoc(doc);
+ return -1;
+}
+
--- /dev/null
+#ifndef _LINC_PARSE_H_
+#define _LINC_PARSE_H_
+
+#include "lin_config.h"
+
+int linc_parse_configuration(char *filename, struct linc_lin_state *linc_lin_state);
+
+#endif /* _LINC_PARSE_H_ */
+++ /dev/null
-/*
- * PCAN-LIN, RS-232 to CAN/LIN converter control application
- *
- * This program is free software; you can distribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2 of
- * the License.
- *
- * Copyright: (c) 2012 Czech Technical University in Prague
- * Authors: Rostislav Lisovy <lisovy@gmail.cz>
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <termios.h>
-#include <stdint.h>
-#include <assert.h>
-#include <libxml/parser.h>
-
-#define true 1
-#define false 0
-
-#define MAX_LIN_ID 0x3F
-#define PCL_ACTIVE 1
-#define PCL_UNACTIVE 0
-#define PCL_DEFAULT_CONFIG "config.pclin"
-
-#define PCL_PKT_MAX_SIZE 16
-#define PCL_HEADERS_SIZE 2 /* There are 2 bytes of headers */
-#define PCL_CHECKSUM_SIZE 1
-#define PCL_STX_SIZE 1
-#define PCL_PACKET_OVERHEAD (PCL_HEADERS_SIZE + PCL_CHECKSUM_SIZE)
-
-#define PCL_STX 0x2
-
-#define PCL_SEQ_NO_ofs 4
-#define PCL_SEQ_FRLEN_ofs 0
-#define PCL_CTRL_TIFACE_ofs 6
-#define PCL_CTRL_COMC_ofs 0
-
-#define PCL_SEQ_FRLEN_msk 0xF
-
-#define PCL_PACKET_LIN_IFACE 0x2
-#define PCL_PACKET_MODULE_IFACE 0x3
-
-/* Logical representation of a packet sent to PCAN-LIN converter via RS232 */
-typedef struct {
- uint8_t stx; /* Start transmission; Always set to 0x2 */
- uint8_t seq_no; /* Sequence number */
- uint8_t seq_frlen; /* Frame length */
- uint8_t ctrl_tiface;/* Target interface */
- uint8_t ctrl_comc; /* Command code */
- uint8_t parms[8]; /* Parameters; Number of parameters depends
- on the frame length */
- uint8_t chks; /* Checksum; Bitwise XOR of all bytes except STX */
-} pcl_packet_t;
-
-struct pcl_scheduler_entry {
- int lin_id;
- int interval_ms;
-};
-
-/* Index in this array = LIN ID */
-struct pcl_frame_entry {
- int status; /* 1 = active; 0 = unactive */
- int data_len;
- char data[8];
-};
-
-struct pcl_lin_state {
- int is_active;
- int baudrate;
- int master_status;
- int bus_termination;
-};
-
-struct pcl_lin_state pcl_lin_state;
-struct pcl_frame_entry pcl_frame_entry[MAX_LIN_ID];
-struct pcl_scheduler_entry pcl_scheduler_entry[100]; // FIXME max value
-int pcl_scheduler_entries_cnt;
-
-struct termios term_attr;
-/* ------------------------------------------------------------------------ */
-
-/* Transform 'logic' representation of a frame to exact byte sequence */
-int pcl_serialize(pcl_packet_t *pkt, uint8_t *pkt_raw)
-{
- int i;
- uint8_t checksum = 0;
-
- pkt_raw[0] = pkt->stx;
- pkt_raw[1] = (pkt->seq_no << PCL_SEQ_NO_ofs) |
- (pkt->seq_frlen << PCL_SEQ_FRLEN_ofs);
- pkt_raw[2] = (pkt->ctrl_tiface << PCL_CTRL_TIFACE_ofs) |
- (pkt->ctrl_comc << PCL_CTRL_COMC_ofs);
-
- for (i = 0; i < pkt->seq_frlen; i++) {
- pkt_raw[3+i] = pkt->parms[i];
- }
-
- /* Calculate XOR checksum; Skip STX */
- for (i = 1; i <= pkt->seq_frlen + PCL_HEADERS_SIZE; i++) {
- checksum ^= pkt_raw[i];
- }
- pkt_raw[i] = checksum;
-
- printf("Snd: [STX] [SEQ] [PRM] [...] \n ");
- for (i = 0; i < pkt->seq_frlen + PCL_PACKET_OVERHEAD + 1; i++)
- printf("0x%02X ", pkt_raw[i]);
- printf("\n");
-
- return pkt->seq_frlen + 4; /* real packet size */
-}
-
-int pcl_send_frame(int tty, pcl_packet_t *pkt)
-{
- int pkt_size;
- int to_send;
- int sent;
- uint8_t pkt_buff[PCL_PKT_MAX_SIZE];
-
- pkt_size = pcl_serialize(pkt, (uint8_t *) &pkt_buff);
- to_send = pkt_size;
- sent = 0;
-
- while (to_send > 0) {
- sent = write(tty, pkt_buff+sent, to_send);
- to_send -= sent;
- }
-
- memset(pkt, '\0', sizeof(pcl_packet_t));
- return 0;
-}
-
-int pcl_read_reset_response(int tty)
-{
- char c;
- int ret;
- int i = 0;
- char str_match[] = {'G', 'm', 'b', 'H'};
-
- do {
- ret = read(tty, &c, 1);
- if (ret == -1)
- perror("read()");
-
- printf("%c", c);
-
- if ((c == str_match[i]) && (i == 3))
- i = -1; /* We are done -- Stop the loop*/
- else if (c == str_match[i])
- i++; /* Match found -- Go to the next letter */
- else
- i = 0; /* Start from beginning */
-
- } while (i != -1);
-
- printf("\n\n");
-
- return 0;
-}
-
-int pcl_read_response(int tty)
-{
- int i;
- int received = 0;
- int to_read = 0;
- int data_length = 0;
- uint8_t buff[PCL_PKT_MAX_SIZE];
- //memset(buff, '\0', sizeof(buff));
-
- /* Read 2 bytes of header */
- received = read(tty, &buff[0], 1); /* Read STX */
- if (received == -1)
- perror("read()");
-
- if (buff[0] == 0x2) { /* STX ok */
- received = read(tty, &buff[1], 1); /* Read SEQ */
- if (received == -1)
- perror("read()");
- } else {
- return 1;
- }
-
- data_length = (buff[1] & PCL_SEQ_FRLEN_msk);
- to_read = data_length + 1; /* +chksm */
- while (to_read > 0) {
- received = read(tty, &buff[2], to_read);
- to_read -= received;
- }
-
- printf("Rcv: [STX] [SEQ] [PRM] [CHK]\n"); // FIXME add spaces before "CHKS" when
- //more than 1 byte received in params
- printf(" 0x%02X 0x%02X", buff[0], buff[1]);
- for (i = 0; i < data_length; i++) {
- printf(" 0x%02X", buff[i + 2]);
- }
- printf(" 0x%02X\n\n", buff[i]);
-
- return 0;
-}
-
-void pcl_insert_scheduler_entries(int tty)
-{
- pcl_packet_t pkt;
- int i;
-
- /* Insert scheduler entry */
- for (i = 0; i < (sizeof(pcl_scheduler_entry)/sizeof(struct pcl_scheduler_entry)); i++) {
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = 0x3;
- pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
- pkt.ctrl_comc = 0x28;
- pkt.parms[0] = (pcl_scheduler_entry[i].interval_ms) & 0xFF;
- pkt.parms[1] = (pcl_scheduler_entry[i].interval_ms >> 8) & 0xFF;
- pkt.parms[2] = pcl_scheduler_entry[i].lin_id; /* LIN ID */
-
- pcl_send_frame(tty, &pkt);
- pcl_read_response(tty);
- }
-
-}
-
-void pcl_set_slave_id_and_data_configuration(int tty)
-{
- pcl_packet_t pkt;
- int i;
-
- /* Set Slave ID + Data Configuration */
- for (i = 0; i < 0x3F; i++) {
- int len;
-
- if (pcl_frame_entry[i].status == PCL_ACTIVE) {
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = pcl_frame_entry[i].data_len + 2;
- pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
- pkt.ctrl_comc = 0x29;
- pkt.parms[0] = pcl_frame_entry[i].status; /* Field Status */
- pkt.parms[1] = i; /* LIN ID */
- pkt.parms[2] = pcl_frame_entry[i].data[0]; /* Data */
- pkt.parms[3] = pcl_frame_entry[i].data[1]; /* Data */
- pkt.parms[4] = pcl_frame_entry[i].data[2]; /* Data */
- pkt.parms[5] = pcl_frame_entry[i].data[3]; /* Data */
- pkt.parms[6] = pcl_frame_entry[i].data[4]; /* Data */
- pkt.parms[7] = pcl_frame_entry[i].data[5]; /* Data */
- pkt.parms[8] = pcl_frame_entry[i].data[6]; /* Data */
- pkt.parms[9] = pcl_frame_entry[i].data[7]; /* Data */
-
- } else {
- if (i < 0x20)
- len = 4;
- else if (i < 0x30)
- len = 6;
- else
- len = 8;
-
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = len;
- pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
- pkt.ctrl_comc = 0x29;
- pkt.parms[0] = 0x00; /* Field Status -- unactive */
- pkt.parms[1] = i; /* LIN ID */
- }
-
- pcl_send_frame(tty, &pkt);
- pcl_read_response(tty);
- }
-}
-
-void pcl_flash_config(int tty)
-{
- pcl_packet_t pkt;
-
- /* Flash Current Configuration */
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = 0x0;
- pkt.ctrl_tiface = PCL_PACKET_MODULE_IFACE;
- pkt.ctrl_comc = 0x3;
-
- pcl_send_frame(tty, &pkt);
- pcl_read_response(tty);
-}
-
-void pcl_reset_device(int tty)
-{
- pcl_packet_t pkt;
-
- /* Reset module */
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = 0x0;
- pkt.ctrl_tiface = PCL_PACKET_MODULE_IFACE;
- pkt.ctrl_comc = 0x4;
-
- pcl_send_frame(tty, &pkt);
- pcl_read_reset_response(tty);
-}
-
-int pcl_lin_init(int tty)
-{
- pcl_packet_t pkt;
-#if 0
- /* Initialization according to current parameters */
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = 0x0;
- pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
- pkt.ctrl_comc = 0x0;
-
- pcl_send_frame(tty, &pkt);
- pcl_read_response(tty);
-#endif
-
- /* Reset module */
- pcl_reset_device(tty);
-
- /* Erase Master Scheduler List */
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = 0x0;
- pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
- pkt.ctrl_comc = 0x33;
-
- pcl_send_frame(tty, &pkt);
- pcl_read_response(tty);
-
- /* Set Activation Status */
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = 0x1;
- pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
- pkt.ctrl_comc = 0x1E;
- pkt.parms[0] = pcl_lin_state.is_active;
-
- pcl_send_frame(tty, &pkt);
- pcl_read_response(tty);
-
- /* Set bitrate */
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = 0x2;
- pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
- pkt.ctrl_comc = 0x1F;
- pkt.parms[0] = 0x00;
- pkt.parms[1] = 0x4B; /* 19200 kBit/s */
-
- pcl_send_frame(tty, &pkt);
- pcl_read_response(tty);
-
- /* Set Forward Mask */
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = 0x1;
- pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
- pkt.ctrl_comc = 0x20;
- pkt.parms[0] = 0x00;
-
- pcl_send_frame(tty, &pkt);
- pcl_read_response(tty);
-
- /* Set Filter Mask */
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = 0x1;
- pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
- pkt.ctrl_comc = 0x21;
- pkt.parms[0] = 0xFF;
-
- pcl_send_frame(tty, &pkt);
- pcl_read_response(tty);
-
- /* Set Filter Code */
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = 0x1;
- pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
- pkt.ctrl_comc = 0x21;
- pkt.parms[0] = 0x00;
-
- pcl_send_frame(tty, &pkt);
- pcl_read_response(tty);
-
- /* Set Message Transmission Timeouts */
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = 0x8;
- pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
- pkt.ctrl_comc = 0x26;
- pkt.parms[0] = 0xA0;
- pkt.parms[1] = 0x0F;
- pkt.parms[2] = 0x09;
- pkt.parms[3] = 0x00;
- pkt.parms[4] = 0x06;
- pkt.parms[5] = 0x00;
- pkt.parms[6] = 0x05;
- pkt.parms[7] = 0x00;
-
- pcl_send_frame(tty, &pkt);
- pcl_read_response(tty);
-
- /* Set Message Retries */
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = 0x1;
- pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
- pkt.ctrl_comc = 0x27;
- pkt.parms[0] = 0x0;
-
- pcl_send_frame(tty, &pkt);
- pcl_read_response(tty);
-
- /* Set Slave ID + Data configuration */
- pcl_set_slave_id_and_data_configuration(tty);
-
- /* Insert scheduler entry */
- pcl_insert_scheduler_entries(tty);
-
- /* Set master status: Active */
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = 0x1;
- pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
- pkt.ctrl_comc = 0x24;
- pkt.parms[0] = pcl_lin_state.master_status;
-
- pcl_send_frame(tty, &pkt);
- pcl_read_response(tty);
-
- /* Set LIN bus termination */
- pkt.stx = PCL_STX;
- pkt.seq_no = 0x0;
- pkt.seq_frlen = 0x1;
- pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
- pkt.ctrl_comc = 0x25;
- pkt.parms[0] = pcl_lin_state.bus_termination;
- /* Should have the same value as "Set master status" */
-
- pcl_send_frame(tty, &pkt);
- pcl_read_response(tty);
-
- return 0;
-}
-
-static void pcl_reset_input_mode(int tty)
-{
- tcsetattr(tty, TCSANOW, &term_attr);
-}
-
-static void pcl_set_input_mode(int tty)
-{
- int status;
- struct termios tattr;
-
- /* Flush input and output queues. */
- if (tcflush(tty, TCIOFLUSH) != 0) {
- perror("tcflush");
- exit(EXIT_FAILURE);
- }
-
- /* Fetch the current terminal parameters. */
- if (!isatty(tty)) {
- fprintf(stderr, "Not a terminal.\n");
- exit(EXIT_FAILURE);
- }
-
- /* Save settings for later restoring */
- tcgetattr(tty, &term_attr);
-
- /* RAW mode */
- tcgetattr(tty, &tattr);
- tattr.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
- | INLCR | IGNCR | ICRNL | IXON);
- tattr.c_oflag &= ~OPOST;
- tattr.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
- tattr.c_cflag &= ~(CSIZE | PARENB);
- tattr.c_cflag |= CS8;
-
- tattr.c_cc[VMIN] = 1;
- tattr.c_cc[VTIME] = 0;
-
- /* Set TX, RX speed */
- cfsetispeed(&tattr, B38400);
- cfsetospeed(&tattr, B38400);
-
- status = tcsetattr(tty, TCSANOW, &tattr);
- if (status == -1)
- perror("tcsetattr()");
-
-}
-
-/****** XML PARSING ******/
-
-static inline int pcl_xml_get_prop_int(xmlNodePtr cur, const xmlChar* str)
-{
- int val;
- xmlChar *attr;
-
- attr = xmlGetProp(cur, str);
- if (!attr)
- assert(0);
-
- val = atoi((const char *)attr); // FIXME error handling
- xmlFree(attr);
-
- return val;
-}
-
-static inline int pcl_xml_get_element_int(xmlDocPtr doc, xmlNodePtr cur)
-{
- xmlChar *key;
- int val;
-
- key = xmlNodeListGetString(doc, cur->children, 1);
- if (!key)
- assert(0);
-
- val = atoi((const char *)key); // FIXME error handling etc.
- xmlFree(key);
-
- return val;
-}
-
-void pcl_parse_scheduler_entries(xmlDocPtr doc, xmlNodePtr cur)
-{
- cur = cur->children;
- while (cur) {
- if (!xmlStrcmp(cur->name, (const xmlChar *)"Entry")) {
- int linid;
- int interval;
- linid = pcl_xml_get_element_int(doc, cur);
- interval = pcl_xml_get_prop_int(cur, (const xmlChar *)"Time");
-
- pcl_scheduler_entry[pcl_scheduler_entries_cnt].lin_id = linid;
- pcl_scheduler_entry[pcl_scheduler_entries_cnt].interval_ms = interval;
- pcl_scheduler_entries_cnt++;
-
- //printf("Time = %d Entry = %d\n", interval, linid);
- }
- cur = cur->next;
- }
-}
-
-void pcl_parse_frame_configuration(xmlDocPtr doc, xmlNodePtr cur)
-{
- xmlNodePtr tmp_node;
- int val;
-
- cur = cur->children;
- while (cur) {
- if (!xmlStrcmp(cur->name, (const xmlChar *)"Frame")) {
- tmp_node = cur->children;
- /* We are able to write into the main Configuration array after
- parsing of all necessary elements (especially LIN ID) -- store
- parsed elements in this temporary entry -- copy the entry afterwards */
- struct pcl_frame_entry tmp_fr_entry;
- int linid = -1;
-
- while (tmp_node) {
- if (!xmlStrcmp(tmp_node->name, (const xmlChar *)"ID")) {
- val = pcl_xml_get_element_int(doc, tmp_node);
- linid = val;
- //printf("ID = %d\n", val);
- }
- if (!xmlStrcmp(tmp_node->name, (const xmlChar *)"Length")) {
- val = pcl_xml_get_element_int(doc, tmp_node);
- tmp_fr_entry.data_len = val;
- //printf("Length = %d\n", val);
- }
- if (!xmlStrcmp(tmp_node->name, (const xmlChar *)"Active")) {
- val = pcl_xml_get_element_int(doc, tmp_node);
- tmp_fr_entry.status = val;
- //printf("Active = %d\n", val);
- }
- if (!xmlStrcmp(tmp_node->name, (const xmlChar *)"Data")) {
- int indx = 0;
- xmlNodePtr tmp_node2;
- tmp_node2 = tmp_node->children;
- while (tmp_node2) {
- if (!xmlStrcmp(tmp_node2->name, (const xmlChar *)"Byte")) {
- // Byte indexing in XML file is wrong
- //indx = pcl_xml_get_prop_int(tmp_node2,
- // (const xmlChar *)"Index");
- val = pcl_xml_get_element_int(doc, tmp_node2);
- //printf("Data = %d\n", val);
- snprintf((char *)&tmp_fr_entry.data[indx], 1, "%i", val);
- indx++;
- }
- tmp_node2 = tmp_node2->next;
- }
- }
- tmp_node = tmp_node->next;
- }
-
- if (linid >= 0) {
- memcpy(&pcl_frame_entry[linid], &tmp_fr_entry,
- sizeof(struct pcl_frame_entry));
- }
- }
- cur = cur->next;
- }
-}
-
-int pcl_parse_configuration(char *filename)
-{
- xmlDocPtr doc;
- xmlNodePtr cur_node;
-
- if (!filename)
- filename = PCL_DEFAULT_CONFIG;
-
- xmlKeepBlanksDefault(1);
- doc = xmlParseFile(filename);
- if (doc == NULL)
- return -1;
-
- cur_node = xmlDocGetRootElement(doc);
- if (cur_node == NULL) {
- fprintf(stderr, "Configuration file %s is empty\n", filename);
- xmlFreeDoc(doc);
- return -1;
- }
-
- /* Check for Root element */
- if (xmlStrcmp(cur_node->name, (const xmlChar *)"PCLIN_PROFILE"))
- goto exit_failure;
-
- /* Check for LIN element */
- cur_node = cur_node->children;
- while (cur_node) {
- if (!xmlStrcmp(cur_node->name, (const xmlChar *)"LIN"))
- break;
-
- cur_node = cur_node->next;
- }
-
- if (!cur_node)
- goto exit_failure;
-
- /* Process LIN configuration */
- cur_node = cur_node->children;
- while (cur_node) {
- if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Active")) {
- pcl_lin_state.is_active = pcl_xml_get_element_int(doc, cur_node);
- }
- if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Baudrate")) {
- pcl_lin_state.baudrate = pcl_xml_get_element_int(doc, cur_node);
- }
- if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Master_Status")) {
- pcl_lin_state.master_status = pcl_xml_get_element_int(doc, cur_node);
- }
- if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Bus_Termination")) {
- pcl_lin_state.bus_termination = pcl_xml_get_element_int(doc, cur_node);
- }
- if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Scheduler_Entries")) {
- pcl_parse_scheduler_entries(doc, cur_node);
- }
- if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Frame_Configuration")) {
- pcl_parse_frame_configuration(doc, cur_node);
- }
-
- cur_node = cur_node->next;
- }
-
- xmlFreeDoc(doc);
- return 0;
-
-exit_failure:
- fprintf(stderr, "Invalid configuration file\n");
- xmlFreeDoc(doc);
- return -1;
-}
-
-void pcl_explain(int argc, char *argv[])
-{
- fprintf(stderr, "Usage: %s [OPTIONS] <SERIAL_INTERFACE>\n", argv[0]);
- fprintf(stderr, "\n");
- fprintf(stderr, "'pcan_lin_config' Is used for configuring PEAK PCAN-LIN device.\n");
- fprintf(stderr, " When invoked without any OPTIONS, it configures PCAN-LIN device\n");
- fprintf(stderr, " with configuration obtained from '"PCL_DEFAULT_CONFIG"' file (if it exists).\n");
- fprintf(stderr, " The PCAN-LIN module enables CAN, LIN and serial participants to communicate.\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Options:\n");
- fprintf(stderr, " -r Execute only Reset of a device\n");
- fprintf(stderr, " -f Flash the active configuration\n");
- fprintf(stderr, " -c <FILE> Path to XML configuration file\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Examples:\n");
- fprintf(stderr, " %s /dev/ttyS0 (Configure the device with the configuration from '"PCL_DEFAULT_CONFIG"')\n",
- argv[0]);
- fprintf(stderr, " %s -r /dev/ttyS0 (Reset the device)\n", argv[0]);
-}
-
-int main(int argc, char *argv[])
-{
- char dev[32]; // FIXME
- int ret;
- int tty;
- int opt;
- int pcl_reset_device_fl = false;
- int pcl_flash_config_fl = false;
- char *filename = NULL;
-
- while ((opt = getopt(argc, argv, "rfc:")) != -1) {
- switch (opt) {
- case 'r':
- pcl_reset_device_fl = true;
- break;
- case 'f':
- pcl_flash_config_fl = true;
- break;
- case 'c':
- filename = optarg;
- break;
- default:
- pcl_explain(argc, argv);
- exit(EXIT_FAILURE);
- }
- }
-
- /* Expected argument after options */
- if (optind >= argc) {
- pcl_explain(argc, argv);
- exit(EXIT_FAILURE);
- }
-
- strncpy((char *) &dev, argv[optind], 32);
- tty = open(dev, O_RDWR);
- if (tty < 0) {
- perror("open()");
- return -4;
- }
-
- ret = pcl_parse_configuration(filename);
- if (!ret)
- printf("Configuration file %s parsed correctly\n", filename);
-
- /* Configure UART */
- pcl_set_input_mode(tty);
-
- if (pcl_reset_device_fl) {
- pcl_reset_device(tty);
- goto exit;
- }
-
- pcl_lin_init(tty);
-
- if (pcl_flash_config_fl) {
- pcl_flash_config(tty);
- pcl_reset_device(tty);
- }
-
-exit:
- pcl_reset_input_mode(tty);
- close(tty);
-
- return EXIT_SUCCESS;
-}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <termios.h>
+#include <stdint.h>
+#include <assert.h>
+#include "pcl_config.h"
+#include "lin_config.h"
+
+struct termios term_attr;
+
+static void pcl_reset_input_mode(int tty)
+{
+ tcsetattr(tty, TCSANOW, &term_attr);
+}
+
+static void pcl_set_input_mode(int tty)
+{
+ int status;
+ struct termios tattr;
+
+ /* Flush input and output queues. */
+ if (tcflush(tty, TCIOFLUSH) != 0) {
+ perror("tcflush");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Fetch the current terminal parameters. */
+ if (!isatty(tty)) {
+ fprintf(stderr, "Not a terminal.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Save settings for later restoring */
+ tcgetattr(tty, &term_attr);
+
+ /* RAW mode */
+ tcgetattr(tty, &tattr);
+ tattr.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
+ | INLCR | IGNCR | ICRNL | IXON);
+ tattr.c_oflag &= ~OPOST;
+ tattr.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ tattr.c_cflag &= ~(CSIZE | PARENB);
+ tattr.c_cflag |= CS8;
+
+ tattr.c_cc[VMIN] = 1;
+ tattr.c_cc[VTIME] = 0;
+
+ /* Set TX, RX speed */
+ cfsetispeed(&tattr, B38400);
+ cfsetospeed(&tattr, B38400);
+
+ status = tcsetattr(tty, TCSANOW, &tattr);
+ if (status == -1)
+ perror("tcsetattr()");
+}
+
+/* Transform 'logic' representation of a frame to exact byte sequence */
+int pcl_serialize(pcl_packet_t *pkt, uint8_t *pkt_raw)
+{
+ int i;
+ uint8_t checksum = 0;
+
+ pkt_raw[0] = pkt->stx;
+ pkt_raw[1] = (pkt->seq_no << PCL_SEQ_NO_ofs) |
+ (pkt->seq_frlen << PCL_SEQ_FRLEN_ofs);
+ pkt_raw[2] = (pkt->ctrl_tiface << PCL_CTRL_TIFACE_ofs) |
+ (pkt->ctrl_comc << PCL_CTRL_COMC_ofs);
+
+ for (i = 0; i < pkt->seq_frlen; i++) {
+ pkt_raw[3+i] = pkt->parms[i];
+ }
+
+ /* Calculate XOR checksum; Skip STX */
+ for (i = 1; i <= pkt->seq_frlen + PCL_HEADERS_SIZE; i++) {
+ checksum ^= pkt_raw[i];
+ }
+ pkt_raw[i] = checksum;
+
+ printf("Snd: [STX] [SEQ] [PRM] [...] \n ");
+ for (i = 0; i < pkt->seq_frlen + PCL_PACKET_OVERHEAD + 1; i++)
+ printf("0x%02X ", pkt_raw[i]);
+ printf("\n");
+
+ return pkt->seq_frlen + 4; /* real packet size */
+}
+
+int pcl_send_frame(int tty, pcl_packet_t *pkt)
+{
+ int pkt_size;
+ int to_send;
+ int sent;
+ uint8_t pkt_buff[PCL_PKT_MAX_SIZE];
+
+ pkt_size = pcl_serialize(pkt, (uint8_t *) &pkt_buff);
+ to_send = pkt_size;
+ sent = 0;
+
+ while (to_send > 0) {
+ sent = write(tty, pkt_buff+sent, to_send);
+ to_send -= sent;
+ }
+
+ memset(pkt, '\0', sizeof(pcl_packet_t));
+ return 0;
+}
+
+int pcl_read_reset_response(int tty)
+{
+ char c;
+ int ret;
+ int i = 0;
+ char str_match[] = {'G', 'm', 'b', 'H'};
+
+ do {
+ ret = read(tty, &c, 1);
+ if (ret == -1)
+ perror("read()");
+
+ printf("%c", c);
+
+ if ((c == str_match[i]) && (i == 3))
+ i = -1; /* We are done -- Stop the loop*/
+ else if (c == str_match[i])
+ i++; /* Match found -- Go to the next letter */
+ else
+ i = 0; /* Start from beginning */
+
+ } while (i != -1);
+
+ printf("\n\n");
+
+ return 0;
+}
+
+int pcl_read_response(int tty)
+{
+ int i;
+ int received = 0;
+ int to_read = 0;
+ int data_length = 0;
+ uint8_t buff[PCL_PKT_MAX_SIZE];
+ //memset(buff, '\0', sizeof(buff));
+
+ /* Read 2 bytes of header */
+ received = read(tty, &buff[0], 1); /* Read STX */
+ if (received == -1)
+ perror("read()");
+
+ if (buff[0] == 0x2) { /* STX ok */
+ received = read(tty, &buff[1], 1); /* Read SEQ */
+ if (received == -1)
+ perror("read()");
+ } else {
+ return 1;
+ }
+
+ data_length = (buff[1] & PCL_SEQ_FRLEN_msk);
+ to_read = data_length + 1; /* +chksm */
+ while (to_read > 0) {
+ received = read(tty, &buff[2], to_read);
+ to_read -= received;
+ }
+
+ printf("Rcv: [STX] [SEQ] [PRM] [CHK]\n"); // FIXME add spaces before "CHKS" when
+ //more than 1 byte received in params
+ printf(" 0x%02X 0x%02X", buff[0], buff[1]);
+ for (i = 0; i < data_length; i++) {
+ printf(" 0x%02X", buff[i + 2]);
+ }
+ printf(" 0x%02X\n\n", buff[i]);
+
+ return 0;
+}
+
+void pcl_insert_scheduler_entries(int tty, struct linc_lin_state *linc_lin_state)
+{
+ pcl_packet_t pkt;
+ int i;
+
+ /* Insert scheduler entry */
+ for (i = 0; i < (sizeof(linc_lin_state->scheduler_entry)/sizeof(struct linc_scheduler_entry)); i++) {
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = 0x3;
+ pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
+ pkt.ctrl_comc = 0x28;
+ pkt.parms[0] = (linc_lin_state->scheduler_entry[i].interval_ms) & 0xFF;
+ pkt.parms[1] = (linc_lin_state->scheduler_entry[i].interval_ms >> 8) & 0xFF;
+ pkt.parms[2] = linc_lin_state->scheduler_entry[i].lin_id; /* LIN ID */
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_response(tty);
+ }
+
+}
+
+void pcl_set_slave_id_and_data_configuration(int tty, struct linc_lin_state *linc_lin_state)
+{
+ pcl_packet_t pkt;
+ int i;
+
+ /* Set Slave ID + Data Configuration */
+ for (i = 0; i < 0x3F; i++) {
+ int len;
+
+ if (linc_lin_state->frame_entry[i].status == PCL_ACTIVE) {
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = linc_lin_state->frame_entry[i].data_len + 2;
+ pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
+ pkt.ctrl_comc = 0x29;
+ pkt.parms[0] = linc_lin_state->frame_entry[i].status; /* Field Status */
+ pkt.parms[1] = i; /* LIN ID */
+ pkt.parms[2] = linc_lin_state->frame_entry[i].data[0]; /* Data */
+ pkt.parms[3] = linc_lin_state->frame_entry[i].data[1]; /* Data */
+ pkt.parms[4] = linc_lin_state->frame_entry[i].data[2]; /* Data */
+ pkt.parms[5] = linc_lin_state->frame_entry[i].data[3]; /* Data */
+ pkt.parms[6] = linc_lin_state->frame_entry[i].data[4]; /* Data */
+ pkt.parms[7] = linc_lin_state->frame_entry[i].data[5]; /* Data */
+ pkt.parms[8] = linc_lin_state->frame_entry[i].data[6]; /* Data */
+ pkt.parms[9] = linc_lin_state->frame_entry[i].data[7]; /* Data */
+
+ } else {
+ if (i < 0x20)
+ len = 4;
+ else if (i < 0x30)
+ len = 6;
+ else
+ len = 8;
+
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = len;
+ pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
+ pkt.ctrl_comc = 0x29;
+ pkt.parms[0] = 0x00; /* Field Status -- unactive */
+ pkt.parms[1] = i; /* LIN ID */
+ }
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_response(tty);
+ }
+}
+
+void pcl_flash_config(int tty)
+{
+ pcl_packet_t pkt;
+
+ /* Flash Current Configuration */
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = 0x0;
+ pkt.ctrl_tiface = PCL_PACKET_MODULE_IFACE;
+ pkt.ctrl_comc = 0x3;
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_response(tty);
+}
+
+void pcl_reset_device(int tty)
+{
+ pcl_packet_t pkt;
+
+ /* Reset module */
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = 0x0;
+ pkt.ctrl_tiface = PCL_PACKET_MODULE_IFACE;
+ pkt.ctrl_comc = 0x4;
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_reset_response(tty);
+}
+
+int pcl_lin_init(int tty, struct linc_lin_state *linc_lin_state)
+{
+ pcl_packet_t pkt;
+#if 0
+ /* Initialization according to current parameters */
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = 0x0;
+ pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
+ pkt.ctrl_comc = 0x0;
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_response(tty);
+#endif
+
+ /* Reset module */
+ pcl_reset_device(tty);
+
+ /* Erase Master Scheduler List */
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = 0x0;
+ pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
+ pkt.ctrl_comc = 0x33;
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_response(tty);
+
+ /* Set Activation Status */
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = 0x1;
+ pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
+ pkt.ctrl_comc = 0x1E;
+ pkt.parms[0] = linc_lin_state->is_active;
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_response(tty);
+
+ /* Set bitrate */
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = 0x2;
+ pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
+ pkt.ctrl_comc = 0x1F;
+ pkt.parms[0] = 0x00;
+ pkt.parms[1] = 0x4B; /* 19200 kBit/s */
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_response(tty);
+
+ /* Set Forward Mask */
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = 0x1;
+ pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
+ pkt.ctrl_comc = 0x20;
+ pkt.parms[0] = 0x00;
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_response(tty);
+
+ /* Set Filter Mask */
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = 0x1;
+ pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
+ pkt.ctrl_comc = 0x21;
+ pkt.parms[0] = 0xFF;
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_response(tty);
+
+ /* Set Filter Code */
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = 0x1;
+ pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
+ pkt.ctrl_comc = 0x21;
+ pkt.parms[0] = 0x00;
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_response(tty);
+
+ /* Set Message Transmission Timeouts */
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = 0x8;
+ pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
+ pkt.ctrl_comc = 0x26;
+ pkt.parms[0] = 0xA0;
+ pkt.parms[1] = 0x0F;
+ pkt.parms[2] = 0x09;
+ pkt.parms[3] = 0x00;
+ pkt.parms[4] = 0x06;
+ pkt.parms[5] = 0x00;
+ pkt.parms[6] = 0x05;
+ pkt.parms[7] = 0x00;
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_response(tty);
+
+ /* Set Message Retries */
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = 0x1;
+ pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
+ pkt.ctrl_comc = 0x27;
+ pkt.parms[0] = 0x0;
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_response(tty);
+
+ /* Set Slave ID + Data configuration */
+ pcl_set_slave_id_and_data_configuration(tty, linc_lin_state);
+
+ /* Insert scheduler entry */
+ pcl_insert_scheduler_entries(tty, linc_lin_state);
+
+ /* Set master status: Active */
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = 0x1;
+ pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
+ pkt.ctrl_comc = 0x24;
+ pkt.parms[0] = linc_lin_state->master_status;
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_response(tty);
+
+ /* Set LIN bus termination */
+ pkt.stx = PCL_STX;
+ pkt.seq_no = 0x0;
+ pkt.seq_frlen = 0x1;
+ pkt.ctrl_tiface = PCL_PACKET_LIN_IFACE;
+ pkt.ctrl_comc = 0x25;
+ pkt.parms[0] = linc_lin_state->bus_termination;
+ /* Should have the same value as "Set master status" */
+
+ pcl_send_frame(tty, &pkt);
+ pcl_read_response(tty);
+
+ return 0;
+}
+
+int pcl_config(struct linc_lin_state *linc_lin_state, unsigned int flags)
+{
+ int tty;
+
+ tty = open(linc_lin_state->dev, O_RDWR);
+ if (tty < 0) {
+ perror("open()");
+ return -4;
+ }
+ /* Configure UART */
+ pcl_set_input_mode(tty);
+
+
+ if (flags & RESET_DEVICE_fl) {
+ pcl_reset_device(tty);
+ return 0;
+ }
+
+ pcl_lin_init(tty, linc_lin_state);
+
+ if (flags & FLASH_CONF_fl) {
+ pcl_flash_config(tty);
+ pcl_reset_device(tty);
+ }
+
+ pcl_reset_input_mode(tty);
+ close(tty);
+
+ return 0;
+}
+
+
--- /dev/null
+#ifndef _PCL_CONFIG_H_
+#define _PCL_CONFIG_H_
+
+#include <inttypes.h>
+#include "lin_config.h"
+
+#define PCL_ACTIVE 1
+#define PCL_UNACTIVE 0
+
+#define PCL_PKT_MAX_SIZE 16
+#define PCL_HEADERS_SIZE 2 /* There are 2 bytes of headers */
+#define PCL_CHECKSUM_SIZE 1
+#define PCL_STX_SIZE 1
+#define PCL_PACKET_OVERHEAD (PCL_HEADERS_SIZE + PCL_CHECKSUM_SIZE)
+
+#define PCL_STX 0x2
+
+#define PCL_SEQ_NO_ofs 4
+#define PCL_SEQ_FRLEN_ofs 0
+#define PCL_CTRL_TIFACE_ofs 6
+#define PCL_CTRL_COMC_ofs 0
+
+#define PCL_SEQ_FRLEN_msk 0xF
+
+#define PCL_PACKET_LIN_IFACE 0x2
+#define PCL_PACKET_MODULE_IFACE 0x3
+
+/* Logical representation of a packet sent to PCAN-LIN converter via RS232 */
+typedef struct {
+ uint8_t stx; /* Start transmission; Always set to 0x2 */
+ uint8_t seq_no; /* Sequence number */
+ uint8_t seq_frlen; /* Frame length */
+ uint8_t ctrl_tiface;/* Target interface */
+ uint8_t ctrl_comc; /* Command code */
+ uint8_t parms[8]; /* Parameters; Number of parameters depends
+ on the frame length */
+ uint8_t chks; /* Checksum; Bitwise XOR of all bytes except STX */
+} pcl_packet_t;
+
+int pcl_config(struct linc_lin_state *linc_lin_state, unsigned int flags);
+
+#endif /* _PCL_CONFIG_H_ */