]> rtime.felk.cvut.cz Git - linux-lin.git/commitdiff
Merge /home/pi/repo/lin/pcan_lin_config/submodule/linux-lin
authorPavel Pisa <pisa@cmp.felk.cvut.cz>
Fri, 20 Jul 2012 13:07:22 +0000 (15:07 +0200)
committerPavel Pisa <pisa@cmp.felk.cvut.cz>
Fri, 20 Jul 2012 13:07:22 +0000 (15:07 +0200)
lin_config/examples/master_slave.pclin [new file with mode: 0644]
lin_config/src/Makefile [new file with mode: 0644]
lin_config/src/lin_config.c [new file with mode: 0644]
lin_config/src/lin_config.h [new file with mode: 0644]
lin_config/src/linc_parse_xml.c [new file with mode: 0644]
lin_config/src/linc_parse_xml.h [new file with mode: 0644]
lin_config/src/pcl_config.c [new file with mode: 0644]
lin_config/src/pcl_config.h [new file with mode: 0644]
lin_config/src/run.sh [new file with mode: 0755]
lin_config/src/sllin_config.c [new file with mode: 0644]

diff --git a/lin_config/examples/master_slave.pclin b/lin_config/examples/master_slave.pclin
new file mode 100644 (file)
index 0000000..573e067
Binary files /dev/null and b/lin_config/examples/master_slave.pclin differ
diff --git a/lin_config/src/Makefile b/lin_config/src/Makefile
new file mode 100644 (file)
index 0000000..db50031
--- /dev/null
@@ -0,0 +1,17 @@
+CC=gcc
+CFLAGS=-std=gnu99 -Wall -pedantic $(DEBUG) `xml2-config --cflags` -I$(INCLUDE)
+LIBS=`xml2-config --libs`
+INCLUDE=../../linux_lin_git/sllin
+DEBUG=-ggdb
+
+objects = linc_parse_xml.o pcl_config.o sllin_config.o lin_config.o
+
+lin_config: $(objects)
+       $(CC) $(objects) $(LIBS) -o lin_config
+
+%.o : %.c %.h
+       $(CC) $(CFLAGS) $(LIBS) -c $< -o $@
+
+.PHONY: clean
+clean:
+       rm *.o
diff --git a/lin_config/src/lin_config.c b/lin_config/src/lin_config.c
new file mode 100644 (file)
index 0000000..a42d3e8
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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 "sllin_config.h"
+#include "lin_config.h"
+
+#include "linux/lin_bus.h"
+
+struct linc_lin_state linc_lin_state;
+
+
+void linc_explain(int argc, char *argv[])
+{
+// FIXME what is default behaviour
+// Write a warning about not using a rs232--usb converter for sllin
+       fprintf(stderr, "Usage: %s [OPTIONS] <SERIAL_INTERFACE>\n", argv[0]);
+       fprintf(stderr, "\n");
+       fprintf(stderr, "'lin_config' is used for configuring sllin -- " \
+               "simple LIN device implemented\n" \
+               "  as a TTY line discipline for arbitrary UART interface.\n" \
+               "  This program is able to configure PCAN-LIN (RS232 configurable " \
+               "LIN node) as well.\n" \
+               "  When invoked without any OPTIONS, it configures PCAN-LIN device\n" \
+               "  with configuration obtained from '"PCL_DEFAULT_CONFIG"' " \
+               "file (if it exists).\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "SERIAL_INTERFACE is in format CLASS:PATH\n");
+       fprintf(stderr, "  CLASS defines the device class -- it is either " \
+               "'sllin' or 'pcanlin'\n");
+       fprintf(stderr, "  PATH is path to the serial interface, e.g /dev/ttyS0\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "General options:\n");
+       fprintf(stderr, " -c <FILE>   Path to XML configuration file in PCLIN format\n");
+       fprintf(stderr, " -r          Execute only Reset of a device\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "PCAN-LIN specific options:\n");
+       fprintf(stderr, " -f          Store the active configuration into internal " \
+               "flash memory\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Sllin specific options:\n");
+       fprintf(stderr, " -a          Attach sllin TTY line discipline to " \
+               "particular SERIAL_INTERFACE\n");
+       fprintf(stderr, " -d          Detach sllin TTY line discipline from " \
+               "particular SERIAL_INTERFACE\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Examples:\n");
+       fprintf(stderr, " %s sllin:/dev/ttyS0        (Configure the device with the " \
+               "configuration from '"PCL_DEFAULT_CONFIG"')\n", argv[0]);
+       fprintf(stderr, " %s -r pcanlin:/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:ad")) != -1) {
+               switch (opt) {
+               case 'r':
+                       flags |= RESET_DEVICE_fl;
+                       break;
+               case 'f':
+                       flags |= FLASH_CONF_fl;
+                       break;
+               case 'c':
+                       filename = optarg;
+                       break;
+               case 'a':
+                       flags |= SLLIN_ATTACH_fl;
+                       break;
+               case 'd':
+                       flags |= SLLIN_DETACH_fl;
+                       break;
+               default:
+                       linc_explain(argc, argv);
+                       return 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);
+
+       linc_lin_state.flags = flags;
+       //ret = pcl_config(&linc_lin_state);
+       ret = sllin_config(&linc_lin_state);
+
+       if (ret < 0)
+               return EXIT_FAILURE;
+       if (ret == LIN_EXIT_OK) {
+
+               return EXIT_SUCCESS;
+       }
+
+       printf("Running in background ...\n");
+       ret = daemon(0, 0);
+       if (ret < 0) {
+               perror("daemon()");
+               return EXIT_FAILURE;
+       }
+
+       // FIXME free() linc_lin_state?
+       /* Sleep to keep the line discipline active. */
+       pause();
+
+       return EXIT_SUCCESS;
+}
diff --git a/lin_config/src/lin_config.h b/lin_config/src/lin_config.h
new file mode 100644 (file)
index 0000000..6d4ea1b
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _LIN_CONFIG_H_
+#define _LIN_CONFIG_H_
+
+#define LIN_EXIT_OK                            1
+
+/* Flags passed to configuration functions */
+#define FLASH_CONF_fl                          (1 << 0)
+#define RESET_DEVICE_fl                                (1 << 1)
+#define SLLIN_ATTACH_fl                                (1 << 2)
+#define SLLIN_DETACH_fl                                (1 << 3)
+
+#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;          /* Is LIN device active */
+       int baudrate;           /* LIN baudrate */
+       int master_status;      /* LIN node type -- Master or Slave */
+       int bus_termination;    /* LIN bus termination in device -- Master or Slave */
+
+       /* Subscriber/publisher table entries */
+       struct linc_frame_entry frame_entry[MAX_LIN_ID + 1];
+       /* Scheduler table entries */
+       // FIXME max value
+       struct linc_scheduler_entry scheduler_entry[100];
+       int scheduler_entries_cnt; /* No. of configured scheduler entries */
+
+       char *dev;              /* Path to LIN device to be configured */
+       int flags;              /* Flags passed to configuration function
+                               of particular device */
+};
+
+#endif /* _LIN_CONFIG_H_ */
diff --git a/lin_config/src/linc_parse_xml.c b/lin_config/src/linc_parse_xml.c
new file mode 100644 (file)
index 0000000..160ef84
--- /dev/null
@@ -0,0 +1,186 @@
+#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 Lin ID = %d Entry no. = %d\n",
+                       //      interval, linid, linc_lin_state->scheduler_entries_cnt-1);
+               }
+               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 && linid <= MAX_LIN_ID) {
+                               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;
+}
+
diff --git a/lin_config/src/linc_parse_xml.h b/lin_config/src/linc_parse_xml.h
new file mode 100644 (file)
index 0000000..09efa16
--- /dev/null
@@ -0,0 +1,8 @@
+#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_ */
diff --git a/lin_config/src/pcl_config.c b/lin_config/src/pcl_config.c
new file mode 100644 (file)
index 0000000..1b313e8
--- /dev/null
@@ -0,0 +1,456 @@
+#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 == 1) { /* Is 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] = linc_lin_state->baudrate & 0xFF;
+       pkt.parms[1] = (linc_lin_state->baudrate >> 8) & 0xFF;
+
+       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)
+{
+       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 (linc_lin_state->flags & RESET_DEVICE_fl) {
+               pcl_reset_device(tty);
+                       return 0;
+       }
+
+       pcl_lin_init(tty, linc_lin_state);
+
+       if (linc_lin_state->flags & FLASH_CONF_fl) {
+               pcl_flash_config(tty);
+               pcl_reset_device(tty);
+       }
+
+       // FIXME add warning on unrecognized flags
+       //if (flags & (RESET_DEVICE_fl | FLASH_CONF_fl))
+
+       pcl_reset_input_mode(tty);
+       close(tty);
+
+       return LIN_EXIT_OK;
+}
+
diff --git a/lin_config/src/pcl_config.h b/lin_config/src/pcl_config.h
new file mode 100644 (file)
index 0000000..061bb8d
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _PCL_CONFIG_H_
+#define _PCL_CONFIG_H_
+
+#include <inttypes.h>
+#include "lin_config.h"
+
+#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);
+
+#endif /* _PCL_CONFIG_H_ */
diff --git a/lin_config/src/run.sh b/lin_config/src/run.sh
new file mode 100755 (executable)
index 0000000..8bf1477
--- /dev/null
@@ -0,0 +1,6 @@
+#/bin/bash
+
+killall lin_config
+ip link set sllin0 down
+./lin_config /dev/ttyS0 -c ../example_config/master_slave.pclin -a
+ip link set sllin0 up
diff --git a/lin_config/src/sllin_config.c b/lin_config/src/sllin_config.c
new file mode 100644 (file)
index 0000000..ffb02f5
--- /dev/null
@@ -0,0 +1,218 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <linux/can.h>
+#include <linux/can/bcm.h>
+
+#include "lin_config.h"
+#include "linux/lin_bus.h"
+
+#define SLLIN_LDISC                                    25
+struct bcm_msg {
+       struct bcm_msg_head msg_head;
+       struct can_frame frame;
+};
+
+struct sllin_connection {
+       int bcm_sock; // FIXME is necessary??
+       int can_sock;
+       char iface[IFNAMSIZ+1];
+};
+
+void sllin_ms_to_timeval(int ms, struct timeval *tv)
+{
+       tv->tv_sec = (int) ms/1000;
+       tv->tv_usec = (ms % 1000) * 1000;
+}
+
+int sllin_cache_config(struct linc_lin_state *linc_lin_state,
+                       struct sllin_connection *sllin_connection)
+{
+       int i;
+       struct ifreq ifr;
+       struct sockaddr_can addr;
+       struct can_frame frame;
+       int s;
+       int ret;
+
+       /* Create the socket */
+       s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
+       if (s < 0) {
+               perror("socket()");
+               return -1;
+       }
+
+       /* Locate the interface you wish to use */
+       strcpy(ifr.ifr_name, sllin_connection->iface);
+       ioctl(s, SIOCGIFINDEX, &ifr); /* ifr.ifr_ifindex gets filled
+                                      * with that device's index */
+
+       /* Select that CAN interface, and bind the socket to it. */
+       addr.can_family = AF_CAN;
+       addr.can_ifindex = ifr.ifr_ifindex;
+       ret = bind(s, (struct sockaddr*)&addr, sizeof(addr));
+       if (ret < 0) {
+               perror("bind()");
+               return -1;
+       }
+
+       for (i = 0; i < 0x3F; i++) {
+               if (linc_lin_state->frame_entry[i].status == 1) { /* Is active */
+                       frame.can_dlc = linc_lin_state->frame_entry[i].data_len;
+                       frame.can_id = i; /* LIN ID */
+                       frame.data[0] = linc_lin_state->frame_entry[i].data[0]; /* Data */
+                       frame.data[1] = linc_lin_state->frame_entry[i].data[1]; /* Data */
+                       frame.data[2] = linc_lin_state->frame_entry[i].data[2]; /* Data */
+                       frame.data[3] = linc_lin_state->frame_entry[i].data[3]; /* Data */
+                       frame.data[4] = linc_lin_state->frame_entry[i].data[4]; /* Data */
+                       frame.data[5] = linc_lin_state->frame_entry[i].data[5]; /* Data */
+                       frame.data[6] = linc_lin_state->frame_entry[i].data[6]; /* Data */
+                       frame.data[7] = linc_lin_state->frame_entry[i].data[7]; /* Data */
+
+                       frame.can_id |= LIN_CTRL_FRAME | LIN_CACHE_RESPONSE;
+                       ret = write(s, &frame, sizeof(frame));
+                       printf("configuring frame cache; ret = %d\n", ret);
+                       //if (ret ...)
+                       //read_response(tty);
+               }
+       }
+
+       close(s);
+       return 0;
+}
+
+int sllin_bcm_config(struct linc_lin_state *linc_lin_state,
+                       struct sllin_connection *sllin_connection)
+{
+       struct sockaddr_can caddr;
+       struct ifreq ifr;
+       struct bcm_msg msg;
+       int s;
+       int ret;
+       int i;
+
+       s = socket(PF_CAN, SOCK_DGRAM, CAN_BCM);
+       if (s < 0) {
+               perror("socket(): bcmsocket");
+               return -1;
+       }
+
+       strcpy(ifr.ifr_name, sllin_connection->iface);
+       ioctl(s, SIOCGIFINDEX, &ifr);
+
+       memset(&caddr, 0, sizeof(caddr));
+       caddr.can_family = AF_CAN;
+       caddr.can_ifindex = ifr.ifr_ifindex;
+
+//     ret = bind(s, (struct sockaddr*)&caddr, sizeof(caddr));
+//     if (ret < 0) {
+//             perror("bind()");
+//             return -1;
+//     }
+//
+//     sllin_connection->bcm_sock = s;
+
+       ret = connect(s, (struct sockaddr *)&caddr, sizeof(caddr));
+       if (ret < 0) {
+               perror("connect()");
+               return -1;
+       }
+
+       for (i = 0; i < linc_lin_state->scheduler_entries_cnt; i++) {
+               struct timeval time;
+               memset(&msg, 0, sizeof(msg));
+
+               msg.msg_head.nframes = 1;
+               msg.msg_head.opcode = TX_SETUP;
+               msg.msg_head.flags |= SETTIMER | STARTTIMER;
+               sllin_ms_to_timeval(
+                       linc_lin_state->scheduler_entry[i].interval_ms, &time);
+               msg.msg_head.ival2.tv_sec = time.tv_sec;
+               msg.msg_head.ival2.tv_usec = time.tv_usec;
+               msg.msg_head.can_id = (
+                       linc_lin_state->scheduler_entry[i].lin_id | CAN_RTR_FLAG);
+               msg.frame.can_dlc = 0;
+               msg.frame.can_id = msg.msg_head.can_id;
+
+               //printf("tv_sec = %i, tv_usec = %i\n", time.tv_sec, time.tv_usec);
+
+               sendto(s, &msg, sizeof(msg), 0,
+                       (struct sockaddr*)&caddr, sizeof(caddr));
+               //read_response(s); // FIXME
+       }
+
+       /* Do not close "s" to make BCM configuration running */
+
+       printf("Configuration finished\n");
+       return 0;
+}
+
+int sllin_config(struct linc_lin_state *linc_lin_state)
+{
+       int tty;
+       int ldisc = SLLIN_LDISC;
+       int ret;
+       struct sllin_connection sllin_connection;
+
+       tty = open(linc_lin_state->dev, O_WRONLY | O_NOCTTY);
+       if (tty < 0) {
+               perror("open()");
+               return -1;
+       }
+
+       /* Set sllin line discipline on given tty */
+       if (linc_lin_state->flags & SLLIN_ATTACH_fl) {
+               ret = ioctl(tty, TIOCSETD, &ldisc);
+               if (ret < 0) {
+                       perror("ioctl TIOCSETD");
+                       return -1;
+               }
+
+               /* Retrieve the name of the created CAN netdevice */
+               ret = ioctl(tty, SIOCGIFNAME, sllin_connection.iface);
+               if (ret < 0) {
+                       perror("ioctl SIOCGIFNAME");
+                       return -1;
+               }
+
+               printf("Attached tty %s to netdevice %s\n",
+                       linc_lin_state->dev, sllin_connection.iface);
+       }
+
+       if (linc_lin_state->flags & SLLIN_DETACH_fl) {
+               ldisc = N_TTY;
+               ret = ioctl(tty, TIOCSETD, &ldisc);
+               if (ret < 0) {
+                       perror("ioctl");
+                       return -1;
+               }
+
+               printf("Detached sllin line discipline from %s\n",
+                       linc_lin_state->dev);
+
+               close(tty);
+               return LIN_EXIT_OK;
+       }
+
+       ret = sllin_bcm_config(linc_lin_state, &sllin_connection);
+       if (ret < 0)
+               return ret;
+
+       ret = sllin_cache_config(linc_lin_state, &sllin_connection);
+
+       /* !!! Do not close "tty" to enable newly
+          configured tty line discipline */
+
+       return ret;
+}
+