]> rtime.felk.cvut.cz Git - linux-lin.git/commitdiff
Userspace LIN master: Provide state encapsulation to test kernel code.
authorPavel Pisa <pisa@cmp.felk.cvut.cz>
Fri, 25 Nov 2011 00:39:25 +0000 (01:39 +0100)
committerPavel Pisa <pisa@cmp.felk.cvut.cz>
Fri, 25 Nov 2011 00:39:25 +0000 (01:39 +0100)
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
misc/tty_lin_master/Makefile
misc/tty_lin_master/lin_common.c [new file with mode: 0644]
misc/tty_lin_master/lin_common.h [new file with mode: 0644]
misc/tty_lin_master/main.c

index 06443ed3dd6894018a8be73d0479857a7fc5a8fa..fa01dcf64c9d1394d21cdcd8ed2b50cea5143915 100644 (file)
@@ -1,2 +1,23 @@
-all: main.c
-       gcc main.c -lrt -std=gnu99 -Wall -pedantic -o main
+all: default
+
+CC = gcc
+CFLAGS = -std=gnu99 -Wall -pedantic -ggdb
+LDFLAGS = -lrt -ggdb
+
+.PHONY: default dep
+
+default: main
+
+main : main.o lin_common.o
+
+dep:
+       $(CC) $(CFLAGS) $(CPPFLAGS) -w -E -M *.c $(MORE_C_FILES) > depend
+
+depend:
+       @touch depend
+
+clean :
+       rm -f *.o *~ depend
+
+-include depend
+
diff --git a/misc/tty_lin_master/lin_common.c b/misc/tty_lin_master/lin_common.c
new file mode 100644 (file)
index 0000000..6fffafc
--- /dev/null
@@ -0,0 +1,51 @@
+#include <string.h>
+#include "lin_common.h"
+
+const unsigned char sllin_id_parity_table[64] = {
+        0x80,0xc0,0x40,0x00,0xc0,0x80,0x00,0x40,
+        0x00,0x40,0xc0,0x80,0x40,0x00,0x80,0xc0,
+        0x40,0x00,0x80,0xc0,0x00,0x40,0xc0,0x80,
+        0xc0,0x80,0x00,0x40,0x80,0xc0,0x40,0x00,
+        0x00,0x40,0xc0,0x80,0x40,0x00,0x80,0xc0,
+        0x80,0xc0,0x40,0x00,0xc0,0x80,0x00,0x40,
+        0xc0,0x80,0x00,0x40,0x80,0xc0,0x40,0x00,
+        0x40,0x00,0x80,0xc0,0x00,0x40,0xc0,0x80
+};
+
+
+int sllin_setup_msg(struct sllin *sl, int mode, int id,
+               unsigned char *data, int len)
+{
+       if (id > 0x3f)
+               return -1;
+
+       sl->rx_cnt = 0;
+       sl->tx_cnt = 0;
+       sl->rx_expect = 0;
+
+       sl->tx_buff[SLLIN_BUFF_BREAK] = 0;
+       sl->tx_buff[SLLIN_BUFF_SYNC]  = 0x55;
+       sl->tx_buff[SLLIN_BUFF_ID]    = id | sllin_id_parity_table[id];
+       sl->tx_lim = SLLIN_BUFF_DATA;
+
+       if ((data != NULL) && len) {
+               int i;
+               unsigned csum  = 0;
+
+               sl->tx_lim += len;
+               memcpy(sl->tx_buff + SLLIN_BUFF_DATA, data, len);
+               /* compute data parity there */
+               for (i = SLLIN_BUFF_DATA; i < sl->tx_lim; i++) {
+                       csum += sl->tx_buff[i];
+                       if (csum > 255)
+                               csum -= 255;
+               }
+
+               sl->tx_buff[sl->tx_lim++] = csum;
+       }
+       if (len != 0)
+               sl->rx_lim += len + 1;
+
+       return 0;
+}
+
diff --git a/misc/tty_lin_master/lin_common.h b/misc/tty_lin_master/lin_common.h
new file mode 100644 (file)
index 0000000..74cbe71
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef _LIN_COMMON_H
+#define _LIN_COMMON_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* maximum buffer len to store whole LIN message*/
+#define SLLIN_DATA_MAX  8
+#define SLLIN_BUFF_LEN (1 /*break*/ + 1 /*sync*/ + 1 /*ID*/ + \
+                         SLLIN_DATA_MAX + 1 /*checksum*/)
+#define SLLIN_BUFF_BREAK 0
+#define SLLIN_BUFF_SYNC         1
+#define SLLIN_BUFF_ID   2
+#define SLLIN_BUFF_DATA         3
+
+extern const unsigned char sllin_id_parity_table[64];
+
+struct sllin_tty;
+
+struct sllin {
+       /* Various fields. */
+       struct sllin_tty        *tty;           /* ptr to TTY structure      */
+
+       /* LIN message buffer and actual processed data counts */
+       unsigned char           rx_buff[SLLIN_BUFF_LEN]; /* LIN Rx buffer */
+       unsigned char           tx_buff[SLLIN_BUFF_LEN]; /* LIN Tx buffer */
+       int                     rx_expect;      /* expected number of Rx chars */
+       int                     rx_lim;         /* maximum Rx chars for ID  */
+       int                     rx_cnt;         /* message buffer Rx fill level  */
+       int                     tx_lim;         /* actual limit of bytes to Tx */
+       int                     tx_cnt;         /* number of already Tx bytes */
+       char                    lin_master;     /* node is a master node */
+       int                     lin_baud;       /* LIN baudrate */
+       int                     lin_break_baud; /* Baudrate used for break send */
+       int                     lin_state;      /* state */
+       int                     id_to_send;     /* there is ID to be sent */
+
+       unsigned long           flags;          /* Flag values/ mode etc     */
+#define SLF_INUSE              0               /* Channel in use            */
+#define SLF_ERROR              1               /* Parity, etc. error        */
+#define SLF_RXEVENT            2               /* Rx wake event             */
+#define SLF_TXEVENT            3               /* Tx wake event             */
+#define SLF_MSGEVENT           4               /* CAN message to sent       */
+};
+
+int sllin_setup_msg(struct sllin *sl, int mode, int id,
+               unsigned char *data, int len);
+
+
+#ifdef __cplusplus
+} /* extern "C"*/
+#endif
+
+
+#endif /*_LIN_COMMON_H*/
index 7da775f9e1825477ab3b009b8bf1605530cd060a..8d490c9cc8e0530b286f7be0de22845f56b9cd1b 100644 (file)
 #include <fcntl.h>
 #include <time.h> /* clock_nanosleep */
 #include <getopt.h>
+#include "lin_common.h"
 
 #define LIN_HDR_SIZE           2
-#define LIN_PKT_MAX_SIZE       16 /* FIXME */
 
-int lin_baudrate = 19200;
-int lin_break_baud = 0;
+struct sllin_tty {
+       int tty_fd;
+       struct termios tattr_orig;
+       struct termios tattr;
+       struct serial_struct sattr;
+};
+
+struct sllin_tty sllin_tty_data;
+
+struct sllin sllin_data = {
+       .tty = &sllin_tty_data,
+};
 
-struct termios tattr_orig;
-struct termios tattr;
-struct serial_struct sattr;
 /* ------------------------------------------------------------------------ */
-static void reset_input_mode(int tty)
+static void tty_reset_mode(struct sllin_tty *tty)
 {
-       tcsetattr(tty, TCSANOW, &tattr_orig);
+       tcsetattr(tty->tty_fd, TCSANOW, &tty->tattr_orig);
 }
 
-static void set_uart_baudrate(int tty, int speed)
+static int tty_set_baudrate(struct sllin_tty *tty, int baudrate)
 {
        /* Set "non-standard" baudrate in serial_struct struct */
-       sattr.flags &= (~ASYNC_SPD_MASK);
-       sattr.flags |= (ASYNC_SPD_CUST);
-       sattr.custom_divisor = ((sattr.baud_base) / speed);
-       if (ioctl(tty, TIOCSSERIAL, &sattr) < 0)
+       tty->sattr.flags &= (~ASYNC_SPD_MASK);
+       tty->sattr.flags |= (ASYNC_SPD_CUST);
+       tty->sattr.custom_divisor = (tty->sattr.baud_base + baudrate / 2) / baudrate;
+       if (ioctl(tty->tty_fd, TIOCSSERIAL, &tty->sattr) < 0)
        {
-               perror("ioctl()");
+               perror("ioctl TIOCSSERIAL");
+               return -1;
        }
 
-//     cfsetispeed(&tattr, B38400);
-//     cfsetospeed(&tattr, B38400);
+//     cfsetispeed(&tty->tattr, B38400);
+//     cfsetospeed(&tty->tattr, B38400);
 //
-//     if (tcsetattr(tty, TCSANOW, &tattr) == -1)      
+//     if (tcsetattr(tty->tty_fd, TCSANOW, &tty->tattr) == -1) {
 //             perror("tcsetattr()");
+//             return -1;
+//     }
+
+       return 0;
 }
 
-static void set_input_mode(int tty)
+static int tty_set_mode(struct sllin_tty *tty, int baudrate)
 {
-       /* Flush input and output queues. */
-       if (tcflush(tty, TCIOFLUSH) != 0) {
-               perror("tcflush");
-               exit(EXIT_FAILURE);
+       if(!isatty(tty->tty_fd)) {
+               fprintf(stderr, "Not a terminal.\n");
+               return -1;
        }
 
-       if(!isatty(tty)) {
-               fprintf(stderr, "Not a terminal.\n");
-               exit(EXIT_FAILURE);
+       /* Flush input and output queues. */
+       if (tcflush(tty->tty_fd, TCIOFLUSH) != 0) {
+               perror("tcflush");
+               return -1;;
        }
 
        /* Save settings for later restoring */
-       tcgetattr(tty, &tattr_orig);
+       tcgetattr(tty->tty_fd, &tty->tattr_orig);
 
        /* Save settings into global variables for later use */
-       tcgetattr(tty, &tattr);
-       if (ioctl(tty, TIOCGSERIAL, &sattr) < 0)
-               perror("ioctl()");
+       if (tcgetattr(tty->tty_fd, &tty->tattr) < 0)
+               perror("tcgetattr");
+
+       if (ioctl(tty->tty_fd, TIOCGSERIAL, &tty->sattr) < 0)
+               perror("ioctl TIOCGSERIAL");
 
        /* Set RAW mode */
 #if 0
-       tattr.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
+       tty->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;
+       tty->tattr.c_oflag &= ~OPOST;
+       tty->tattr.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+       tty->tattr.c_cflag &= ~(CSIZE | PARENB);
+       tty->tattr.c_cflag |= CS8;
 
-       tattr.c_cc[VMIN] = 1;
-       tattr.c_cc[VTIME] = 0;
+       tty->tattr.c_cc[VMIN] = 1;
+       tty->tattr.c_cc[VTIME] = 0;
 #else
        /* 8 data bits                  */
        /* Enable receiver              */
        /* Ignore CD (local connection) */
-       tattr.c_cflag = CS8 | CREAD | CLOCAL;
-       tattr.c_iflag = 0;
-       tattr.c_oflag = NL0 | CR0 | TAB0 | BS0 | VT0 | FF0;
-       tattr.c_lflag = 0;
-
-       tattr.c_cc[VINTR]    = '\0';
-       tattr.c_cc[VQUIT]    = '\0';
-       tattr.c_cc[VERASE]   = '\0';
-       tattr.c_cc[VKILL]    = '\0';
-       tattr.c_cc[VEOF]     = '\0';
-       tattr.c_cc[VTIME]    = '\0';
-       tattr.c_cc[VMIN]     = 1;
-       tattr.c_cc[VSWTC]    = '\0';
-       tattr.c_cc[VSTART]   = '\0';
-       tattr.c_cc[VSTOP]    = '\0';
-       tattr.c_cc[VSUSP]    = '\0';
-       tattr.c_cc[VEOL]     = '\0';
-       tattr.c_cc[VREPRINT] = '\0';
-       tattr.c_cc[VDISCARD] = '\0';
-       tattr.c_cc[VWERASE]  = '\0';
-       tattr.c_cc[VLNEXT]   = '\0';
-       tattr.c_cc[VEOL2]    = '\0';
+       tty->tattr.c_cflag = CS8 | CREAD | CLOCAL;
+       tty->tattr.c_iflag = 0;
+       tty->tattr.c_oflag = NL0 | CR0 | TAB0 | BS0 | VT0 | FF0;
+       tty->tattr.c_lflag = 0;
+
+       tty->tattr.c_cc[VINTR]    = '\0';
+       tty->tattr.c_cc[VQUIT]    = '\0';
+       tty->tattr.c_cc[VERASE]   = '\0';
+       tty->tattr.c_cc[VKILL]    = '\0';
+       tty->tattr.c_cc[VEOF]     = '\0';
+       tty->tattr.c_cc[VTIME]    = '\0';
+       tty->tattr.c_cc[VMIN]     = 1;
+       tty->tattr.c_cc[VSWTC]    = '\0';
+       tty->tattr.c_cc[VSTART]   = '\0';
+       tty->tattr.c_cc[VSTOP]    = '\0';
+       tty->tattr.c_cc[VSUSP]    = '\0';
+       tty->tattr.c_cc[VEOL]     = '\0';
+       tty->tattr.c_cc[VREPRINT] = '\0';
+       tty->tattr.c_cc[VDISCARD] = '\0';
+       tty->tattr.c_cc[VWERASE]  = '\0';
+       tty->tattr.c_cc[VLNEXT]   = '\0';
+       tty->tattr.c_cc[VEOL2]    = '\0';
 #endif
 
        /* Set TX, RX speed to 38400 -- this value allows
           to use custom speed in struct struct_serial */
-       cfsetispeed(&tattr, B38400);
-       cfsetospeed(&tattr, B38400);
+       cfsetispeed(&tty->tattr, B38400);
+       cfsetospeed(&tty->tattr, B38400);
 
-       if (tcsetattr(tty, TCSANOW, &tattr) == -1)      
+       if (tcsetattr(tty->tty_fd, TCSANOW, &tty->tattr) == -1) {
                perror("tcsetattr()");
+               return -1;
+       }
 
        /* Set real speed */
-       set_uart_baudrate(tty, lin_baudrate);
+       tty_set_baudrate(tty, baudrate);
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+int sllin_open(struct sllin *sl, const char *dev_fname, int baudrate)
+{
+       int fd;
+
+       sl->lin_baud = baudrate;
 
        /* Calculate baudrate for sending LIN break */
-       lin_break_baud = ((lin_baudrate * 2) / 3);
+       sl->lin_break_baud = (sl->lin_baud * 2) / 3;
+
+       fd = open(dev_fname, O_RDWR);
+       if (fd < 0) {
+               perror("open()");
+               return -1;
+       }
+       sl->tty->tty_fd = fd;
+
+       return tty_set_mode(sl->tty, sl->lin_baud);
 }
 
+int sllin_close(struct sllin *sl)
+{
+       tty_reset_mode(sl->tty);
+       close(sl->tty->tty_fd);
+       return 0;
+}
 
-int send_header(int tty)
+int send_header(struct sllin *sl, int lin_id)
 {
        int buff[3];
+
        buff[0] = 0x00; /* Fake break */
        buff[1] = 0x55; /* Sync byte */
-       buff[2] = 0xC1; /* LIN ID: 1 */
+
+       lin_id &= 0x3f;
+       lin_id |= sllin_id_parity_table[lin_id];
+       buff[2] = lin_id; /* LIN ID: 1 */
 
        printf("send_header() invoked\n");
-       tcflush(tty, TCIOFLUSH);
+       tcflush(sl->tty->tty_fd, TCIOFLUSH);
 
        /* Decrease speed to send BREAK
           (simulated with 0x00 data frame) */
-       set_uart_baudrate(tty, lin_break_baud);
+       tty_set_baudrate(sl->tty, sl->lin_break_baud);
 
        printf("Write break\n");
-       write(tty, &buff[0], 1); /* Write "break" */
+       write(sl->tty->tty_fd, &buff[0], 1); /* Write "break" */
 #if 0
-       read(tty, &buff[0], 1);
+       read(sl->tty->tty_fd, &buff[0], 1);
        printf("Break read\n");
 #else
        {
                struct timespec sleep_time;
                sleep_time.tv_sec = 0;
-               sleep_time.tv_nsec = ((1000000000ll * 11) / lin_break_baud);
+               sleep_time.tv_nsec = ((1000000000ll * 11) / sl->lin_break_baud);
                clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep_time, NULL);
        }
 #endif
 
        /* Restore "normal" speed */
-       set_uart_baudrate(tty, lin_baudrate);
+       tty_set_baudrate(sl->tty, sl->lin_baud);
 
-       write(tty, &buff[1], 1); /* Sync Byte Field */
-       write(tty, &buff[2], 1); /* PID -- Protected Identifier Field */
+       write(sl->tty->tty_fd, &buff[1], 1); /* Sync Byte Field */
+       write(sl->tty->tty_fd, &buff[2], 1); /* PID -- Protected Identifier Field */
        return 0;
 }
 
-int read_header(int tty)
+int read_header(struct sllin *sl)
 {
        int p0, p1; /* Parity bits */
        int par_rec; /* Parity received as a part of a packet */
@@ -171,14 +217,14 @@ int read_header(int tty)
        memset(buff, '\0', sizeof(buff));
 
        while (1) {
-               received = read(tty, &buff[0], 1);
+               received = read(sl->tty->tty_fd, &buff[0], 1);
                if (received == -1)
                        perror("read()");
                
                if (buff[0] != 0x55) /* Sync byte field */
                        continue;
 
-               received = read(tty, &buff[1], 1);
+               received = read(sl->tty->tty_fd, &buff[1], 1);
                if (received == -1)
                        perror("read()");
                else
@@ -203,6 +249,31 @@ int read_header(int tty)
        return 0;
 }
 
+int parse_arr(unsigned char *buff, const char *str, int len_max)
+{
+       char *p;
+       int len = 0;
+
+       do {
+               if (len >= len_max)
+                       return -1;
+               
+               *buff = strtol(str, &p, 0);
+               if(str == p)
+                       return -1;
+
+               str = p;
+
+               len++;
+               buff++;
+       } while (*(str++) == ',');
+
+       if (*(--str) != '\0')
+               return -1;
+
+       return len;
+}
+
 static void usage(void)
 {
        printf("Usage: lin_master <parameters>\n\n");
@@ -218,6 +289,8 @@ static void usage(void)
 
 int main(int argc, char* argv[])
 {
+       struct sllin *sl = &sllin_data;
+
        static struct option long_opts[] = {
                {"device"  , 1, 0, 'd'},
                {"baud"    , 1, 0, 'B'},
@@ -227,23 +300,41 @@ int main(int argc, char* argv[])
                {0, 0, 0, 0}
        };
        int opt;
-       char dev[32] = {'\0'};
-       int tty;
+       char *dev_fname = "";
+       int lin_baudrate = 19200;
+       int lin_id = 1;
+       int resp_len = 0;
+       unsigned char resp_data[SLLIN_DATA_MAX + 1];
+       char *p;
 
        while ((opt = getopt_long(argc, argv, "d:B:i:r:h", &long_opts[0], NULL)) != EOF) {
                switch (opt) {
                        case 'd':
-                               strncpy((char*)&dev, optarg, 32);
+                               dev_fname = optarg;
                                break;
 
                        case 'B':
-                               lin_baudrate = atoi(optarg);
+                               lin_baudrate = strtol(optarg, &p, 10);
+                               if ((p == optarg) || ((*p != '\0') && (*p != ' '))) {
+                                       fprintf(stderr, "Baudrate format error\n");
+                                       exit(EXIT_FAILURE);
+                               }
                                break;
 
                        case 'i':
+                               lin_id = strtol(optarg, &p, 0);
+                               if ((p == optarg) || ((*p != '\0') && (*p != ' '))) {
+                                       fprintf(stderr, "LIN ID format error\n");
+                                       exit(EXIT_FAILURE);
+                               }
                                break;
 
                        case 'r':
+                               resp_len = parse_arr(resp_data, optarg, SLLIN_DATA_MAX);
+                               if (resp_len < 0) {
+                                       fprintf(stderr, "Response data format error\n");
+                                       exit(EXIT_FAILURE);
+                               }
                                break;
 
                        case 'h':
@@ -261,36 +352,32 @@ int main(int argc, char* argv[])
        }
 
        /* Device name was not set by user */
-       if (strlen(dev) == 0) {
+       if (strlen(dev_fname) == 0) {
                usage();
                exit(EXIT_FAILURE);
        }
 
        /* ----------------------------------- */
-       tty = open(dev, O_RDWR);
-       if (tty < 0) {
-               perror("open()");
-               return -4;
+       if (sllin_open(sl, dev_fname, lin_baudrate) < 0) {
+               fprintf (stderr, "sllin_open open failed\n");
+               exit(EXIT_FAILURE);
        }
 
        fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
        printf("Press enter to terminate.\n\n");
 
-       /* Configure UART */
-       set_input_mode(tty);
 
        while(1) {
                char c;
 
-               send_header(tty);
+               send_header(sl, lin_id);
                sleep(1);
 
                if (read(fileno(stdin), &c, 1) > 0)
                        break;
        }
 
-       reset_input_mode(tty);
-       close(tty);
+       sllin_close(sl);
 
        return EXIT_SUCCESS;
 }