2 * UART-LIN master implementation
12 #include <sys/ioctl.h>
13 #include <linux/serial.h> /* struct struct_serial */
16 #include <time.h> /* clock_nanosleep */
19 #define LIN_HDR_SIZE 2
20 #define LIN_PKT_MAX_SIZE 16 /* FIXME */
22 int lin_baudrate = 19200;
23 int lin_break_baud = 0;
25 struct termios tattr_orig;
27 struct serial_struct sattr;
28 /* ------------------------------------------------------------------------ */
29 static void reset_input_mode(int tty)
31 tcsetattr(tty, TCSANOW, &tattr_orig);
34 static void set_uart_baudrate(int tty, int speed)
36 /* Set "non-standard" baudrate in serial_struct struct */
37 sattr.flags &= (~ASYNC_SPD_MASK);
38 sattr.flags |= (ASYNC_SPD_CUST);
39 sattr.custom_divisor = ((sattr.baud_base) / speed);
40 if (ioctl(tty, TIOCSSERIAL, &sattr) < 0)
45 // cfsetispeed(&tattr, B38400);
46 // cfsetospeed(&tattr, B38400);
48 // if (tcsetattr(tty, TCSANOW, &tattr) == -1)
49 // perror("tcsetattr()");
52 static void set_input_mode(int tty)
54 /* Flush input and output queues. */
55 if (tcflush(tty, TCIOFLUSH) != 0) {
61 fprintf(stderr, "Not a terminal.\n");
65 /* Save settings for later restoring */
66 tcgetattr(tty, &tattr_orig);
68 /* Save settings into global variables for later use */
69 tcgetattr(tty, &tattr);
70 if (ioctl(tty, TIOCGSERIAL, &sattr) < 0)
75 tattr.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
76 | INLCR | IGNCR | ICRNL | IXON);
77 tattr.c_oflag &= ~OPOST;
78 tattr.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
79 tattr.c_cflag &= ~(CSIZE | PARENB);
83 tattr.c_cc[VTIME] = 0;
87 /* Ignore CD (local connection) */
88 tattr.c_cflag = CS8 | CREAD | CLOCAL;
90 tattr.c_oflag = NL0 | CR0 | TAB0 | BS0 | VT0 | FF0;
93 tattr.c_cc[VINTR] = '\0';
94 tattr.c_cc[VQUIT] = '\0';
95 tattr.c_cc[VERASE] = '\0';
96 tattr.c_cc[VKILL] = '\0';
97 tattr.c_cc[VEOF] = '\0';
98 tattr.c_cc[VTIME] = '\0';
100 tattr.c_cc[VSWTC] = '\0';
101 tattr.c_cc[VSTART] = '\0';
102 tattr.c_cc[VSTOP] = '\0';
103 tattr.c_cc[VSUSP] = '\0';
104 tattr.c_cc[VEOL] = '\0';
105 tattr.c_cc[VREPRINT] = '\0';
106 tattr.c_cc[VDISCARD] = '\0';
107 tattr.c_cc[VWERASE] = '\0';
108 tattr.c_cc[VLNEXT] = '\0';
109 tattr.c_cc[VEOL2] = '\0';
112 /* Set TX, RX speed to 38400 -- this value allows
113 to use custom speed in struct struct_serial */
114 cfsetispeed(&tattr, B38400);
115 cfsetospeed(&tattr, B38400);
117 if (tcsetattr(tty, TCSANOW, &tattr) == -1)
118 perror("tcsetattr()");
121 set_uart_baudrate(tty, lin_baudrate);
123 /* Calculate baudrate for sending LIN break */
124 lin_break_baud = ((lin_baudrate * 2) / 3);
128 int send_header(int tty)
131 buff[0] = 0x00; /* Fake break */
132 buff[1] = 0x55; /* Sync byte */
133 buff[2] = 0xC1; /* LIN ID: 1 */
135 printf("send_header() invoked\n");
136 tcflush(tty, TCIOFLUSH);
138 /* Decrease speed to send BREAK
139 (simulated with 0x00 data frame) */
140 set_uart_baudrate(tty, lin_break_baud);
142 printf("Write break\n");
143 write(tty, &buff[0], 1); /* Write "break" */
145 read(tty, &buff[0], 1);
146 printf("Break read\n");
149 struct timespec sleep_time;
150 sleep_time.tv_sec = 0;
151 sleep_time.tv_nsec = ((1000000000ll * 11) / lin_break_baud);
152 clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep_time, NULL);
156 /* Restore "normal" speed */
157 set_uart_baudrate(tty, lin_baudrate);
159 write(tty, &buff[1], 1); /* Sync Byte Field */
160 write(tty, &buff[2], 1); /* PID -- Protected Identifier Field */
164 int read_header(int tty)
166 int p0, p1; /* Parity bits */
167 int par_rec; /* Parity received as a part of a packet */
168 int par_calc; /* Calculated parity */
170 uint8_t buff[LIN_HDR_SIZE];
171 memset(buff, '\0', sizeof(buff));
174 received = read(tty, &buff[0], 1);
178 if (buff[0] != 0x55) /* Sync byte field */
181 received = read(tty, &buff[1], 1);
188 p0 = (buff[1] ^ (buff[1] >> 1) ^ (buff[1] >> 2) ^ (buff[1] >> 4)) & 0x1;
189 p1 = ~(((buff[1] >> 1) ^ (buff[1] >> 3) ^ (buff[1] >> 4) ^ (buff[1] >> 5))) & 0x1;
191 printf("%02X ", buff[0]);
192 printf("%02X ", buff[1]);
194 par_rec = (buff[1] & 0xc0) >> 6;
195 par_calc = p0 | (p1 << 1);
196 printf("| LIN id: %02X ", buff[1] & 0x3f);
197 //printf("| par_rec: %X; par_calc: %X ", par_rec, par_calc);
198 if (par_rec == par_calc)
199 printf("| parity OK");
206 static void usage(void)
208 printf("Usage: lin_master <parameters>\n\n");
209 printf("Mandatory parameters:\n");
210 printf(" -d, --device <device> Device name, e.g. /dev/ttyS0\n\n");
211 printf("Optional parameters:\n");
212 printf(" -B, --baud <baud> LIN bus baudrate. Default value is 19200.\n");
213 printf(" Recommendet values are 2400, 9600, 19200\n");
214 printf(" -i, --id <num> LIN frame ID\n");
215 printf(" -r, --response <num> Values of data fields sent from slave task\n");
216 printf(" -h, --help Help, i.e. this screen\n");
219 int main(int argc, char* argv[])
221 static struct option long_opts[] = {
222 {"device" , 1, 0, 'd'},
223 {"baud" , 1, 0, 'B'},
225 {"response", 1, 0, 'r'},
226 {"help" , 0, 0, 'h'},
230 char dev[32] = {'\0'};
233 while ((opt = getopt_long(argc, argv, "d:B:i:r:h", &long_opts[0], NULL)) != EOF) {
236 strncpy((char*)&dev, optarg, 32);
240 lin_baudrate = atoi(optarg);
252 exit(opt == 'h' ? 0 : 1);
259 //fprintf(stderr, "Expected argument after options\n");
263 /* Device name was not set by user */
264 if (strlen(dev) == 0) {
269 /* ----------------------------------- */
270 tty = open(dev, O_RDWR);
276 fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
277 printf("Press enter to terminate.\n\n");
288 if (read(fileno(stdin), &c, 1) > 0)
292 reset_input_mode(tty);