]> rtime.felk.cvut.cz Git - linux-lin.git/blob - misc/tty_lin_master/main.c
Basic argument parsing made by getopt_long.
[linux-lin.git] / misc / tty_lin_master / main.c
1 /*
2  * UART-LIN master implementation
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <string.h>
10 #include <termios.h>
11 #include <stdint.h>
12 #include <sys/ioctl.h>
13 #include <linux/serial.h> /* struct struct_serial */
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <time.h> /* clock_nanosleep */
17 #include <getopt.h>
18
19 #define LIN_HDR_SIZE            2
20 #define LIN_PKT_MAX_SIZE        16 /* FIXME */
21
22 int lin_baudrate = 19200;
23 int lin_break_baud = 0;
24
25 struct termios tattr_orig;
26 struct termios tattr;
27 struct serial_struct sattr;
28 /* ------------------------------------------------------------------------ */
29 static void reset_input_mode(int tty)
30 {
31         tcsetattr(tty, TCSANOW, &tattr_orig);
32 }
33
34 static void set_uart_baudrate(int tty, int speed)
35 {
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)
41         {
42                 perror("ioctl()");
43         }
44
45 //      cfsetispeed(&tattr, B38400);
46 //      cfsetospeed(&tattr, B38400);
47 //
48 //      if (tcsetattr(tty, TCSANOW, &tattr) == -1)      
49 //              perror("tcsetattr()");
50 }
51
52 static void set_input_mode(int tty)
53 {
54         /* Flush input and output queues. */
55         if (tcflush(tty, TCIOFLUSH) != 0) {
56                 perror("tcflush");
57                 exit(EXIT_FAILURE);
58         }
59
60         if(!isatty(tty)) {
61                 fprintf(stderr, "Not a terminal.\n");
62                 exit(EXIT_FAILURE);
63         }
64
65         /* Save settings for later restoring */
66         tcgetattr(tty, &tattr_orig);
67
68         /* Save settings into global variables for later use */
69         tcgetattr(tty, &tattr);
70         if (ioctl(tty, TIOCGSERIAL, &sattr) < 0)
71                 perror("ioctl()");
72
73         /* Set RAW mode */
74 #if 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);
80         tattr.c_cflag |= CS8;
81
82         tattr.c_cc[VMIN] = 1;
83         tattr.c_cc[VTIME] = 0;
84 #else
85         /* 8 data bits                  */
86         /* Enable receiver              */
87         /* Ignore CD (local connection) */
88         tattr.c_cflag = CS8 | CREAD | CLOCAL;
89         tattr.c_iflag = 0;
90         tattr.c_oflag = NL0 | CR0 | TAB0 | BS0 | VT0 | FF0;
91         tattr.c_lflag = 0;
92
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';
99         tattr.c_cc[VMIN]     = 1;
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';
110 #endif
111
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);
116
117         if (tcsetattr(tty, TCSANOW, &tattr) == -1)      
118                 perror("tcsetattr()");
119
120         /* Set real speed */
121         set_uart_baudrate(tty, lin_baudrate);
122
123         /* Calculate baudrate for sending LIN break */
124         lin_break_baud = ((lin_baudrate * 2) / 3);
125 }
126
127
128 int send_header(int tty)
129 {
130         int buff[3];
131         buff[0] = 0x00; /* Fake break */
132         buff[1] = 0x55; /* Sync byte */
133         buff[2] = 0xC1; /* LIN ID: 1 */
134
135         printf("send_header() invoked\n");
136         tcflush(tty, TCIOFLUSH);
137
138         /* Decrease speed to send BREAK
139            (simulated with 0x00 data frame) */
140         set_uart_baudrate(tty, lin_break_baud);
141
142         printf("Write break\n");
143         write(tty, &buff[0], 1); /* Write "break" */
144 #if 0
145         read(tty, &buff[0], 1);
146         printf("Break read\n");
147 #else
148         {
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);
153         }
154 #endif
155
156         /* Restore "normal" speed */
157         set_uart_baudrate(tty, lin_baudrate);
158
159         write(tty, &buff[1], 1); /* Sync Byte Field */
160         write(tty, &buff[2], 1); /* PID -- Protected Identifier Field */
161         return 0;
162 }
163
164 int read_header(int tty)
165 {
166         int p0, p1; /* Parity bits */
167         int par_rec; /* Parity received as a part of a packet */
168         int par_calc; /* Calculated parity */
169         int received = 0;
170         uint8_t buff[LIN_HDR_SIZE];
171         memset(buff, '\0', sizeof(buff));
172
173         while (1) {
174                 received = read(tty, &buff[0], 1);
175                 if (received == -1)
176                         perror("read()");
177                 
178                 if (buff[0] != 0x55) /* Sync byte field */
179                         continue;
180
181                 received = read(tty, &buff[1], 1);
182                 if (received == -1)
183                         perror("read()");
184                 else
185                         break;
186         }
187
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;
190
191         printf("%02X ", buff[0]);
192         printf("%02X ", buff[1]);
193
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");
200         
201         printf("\n");
202
203         return 0;
204 }
205
206 static void usage(void)
207 {
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");
217 }
218
219 int main(int argc, char* argv[])
220 {
221         static struct option long_opts[] = {
222                 {"device"  , 1, 0, 'd'},
223                 {"baud"    , 1, 0, 'B'},
224                 {"id"      , 1, 0, 'i'},
225                 {"response", 1, 0, 'r'},
226                 {"help"    , 0, 0, 'h'},
227                 {0, 0, 0, 0}
228         };
229         int opt;
230         char dev[32] = {'\0'};
231         int tty;
232
233         while ((opt = getopt_long(argc, argv, "d:B:i:r:h", &long_opts[0], NULL)) != EOF) {
234                 switch (opt) {
235                         case 'd':
236                                 strncpy((char*)&dev, optarg, 32);
237                                 break;
238
239                         case 'B':
240                                 lin_baudrate = atoi(optarg);
241                                 break;
242
243                         case 'i':
244                                 break;
245
246                         case 'r':
247                                 break;
248
249                         case 'h':
250                         default:
251                                 usage();
252                                 exit(opt == 'h' ? 0 : 1);
253                                 break;
254                 }
255         }
256
257         if (optind < argc) {
258                 usage();
259                 //fprintf(stderr, "Expected argument after options\n");
260                 exit(EXIT_FAILURE);
261         }
262
263         /* Device name was not set by user */
264         if (strlen(dev) == 0) {
265                 usage();
266                 exit(EXIT_FAILURE);
267         }
268
269         /* ----------------------------------- */
270         tty = open(dev, O_RDWR);
271         if (tty < 0) {
272                 perror("open()");
273                 return -4;
274         }
275
276         fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
277         printf("Press enter to terminate.\n\n");
278
279         /* Configure UART */
280         set_input_mode(tty);
281
282         while(1) {
283                 char c;
284
285                 send_header(tty);
286                 sleep(1);
287
288                 if (read(fileno(stdin), &c, 1) > 0)
289                         break;
290         }
291
292         reset_input_mode(tty);
293         close(tty);
294
295         return EXIT_SUCCESS;
296 }