]> rtime.felk.cvut.cz Git - linux-lin.git/blob - misc/tty_lin_master/main.c
faa01cebd707a5642a0203fe526f8fce9d6493bd
[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
18 #define LIN_HDR_SIZE            2
19 #define LIN_PKT_MAX_SIZE        16 /* FIXME */
20
21 const int lin_baudrate = 19200;
22 int lin_break_baud = 0;
23
24 struct termios tattr_orig;
25 struct termios tattr;
26 struct serial_struct sattr;
27 /* ------------------------------------------------------------------------ */
28 static void reset_input_mode(int tty)
29 {
30         tcsetattr(tty, TCSANOW, &tattr_orig);
31 }
32
33 static void set_uart_baudrate(int tty, int speed)
34 {
35         /* Set "non-standard" baudrate in serial_struct struct */
36         sattr.flags &= (~ASYNC_SPD_MASK);
37         sattr.flags |= (ASYNC_SPD_CUST);
38         sattr.custom_divisor = ((sattr.baud_base) / speed);
39         if (ioctl(tty, TIOCSSERIAL, &sattr) < 0)
40         {
41                 perror("ioctl()");
42         }
43
44 //      cfsetispeed(&tattr, B38400);
45 //      cfsetospeed(&tattr, B38400);
46 //
47 //      if (tcsetattr(tty, TCSANOW, &tattr) == -1)      
48 //              perror("tcsetattr()");
49 }
50
51 static void set_input_mode(int tty)
52 {
53         /* Flush input and output queues. */
54         if (tcflush(tty, TCIOFLUSH) != 0) {
55                 perror("tcflush");
56                 exit(EXIT_FAILURE);
57         }
58
59         if(!isatty(tty)) {
60                 fprintf(stderr, "Not a terminal.\n");
61                 exit(EXIT_FAILURE);
62         }
63
64         /* Save settings for later restoring */
65         tcgetattr(tty, &tattr_orig);
66
67         /* Save settings into global variables for later use */
68         tcgetattr(tty, &tattr);
69         if (ioctl(tty, TIOCGSERIAL, &sattr) < 0)
70                 perror("ioctl()");
71
72         /* Set RAW mode */
73 #if 0
74         tattr.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
75                                 | INLCR | IGNCR | ICRNL | IXON);
76         tattr.c_oflag &= ~OPOST;
77         tattr.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
78         tattr.c_cflag &= ~(CSIZE | PARENB);
79         tattr.c_cflag |= CS8;
80
81         tattr.c_cc[VMIN] = 1;
82         tattr.c_cc[VTIME] = 0;
83 #else
84         /* 8 data bits                  */
85         /* Enable receiver              */
86         /* Ignore CD (local connection) */
87         tattr.c_cflag = CS8 | CREAD | CLOCAL;
88         tattr.c_iflag = 0;
89         tattr.c_oflag = NL0 | CR0 | TAB0 | BS0 | VT0 | FF0;
90         tattr.c_lflag = 0;
91
92         tattr.c_cc[VINTR]    = '\0';
93         tattr.c_cc[VQUIT]    = '\0';
94         tattr.c_cc[VERASE]   = '\0';
95         tattr.c_cc[VKILL]    = '\0';
96         tattr.c_cc[VEOF]     = '\0';
97         tattr.c_cc[VTIME]    = '\0';
98         tattr.c_cc[VMIN]     = 1;
99         tattr.c_cc[VSWTC]    = '\0';
100         tattr.c_cc[VSTART]   = '\0';
101         tattr.c_cc[VSTOP]    = '\0';
102         tattr.c_cc[VSUSP]    = '\0';
103         tattr.c_cc[VEOL]     = '\0';
104         tattr.c_cc[VREPRINT] = '\0';
105         tattr.c_cc[VDISCARD] = '\0';
106         tattr.c_cc[VWERASE]  = '\0';
107         tattr.c_cc[VLNEXT]   = '\0';
108         tattr.c_cc[VEOL2]    = '\0';
109 #endif
110
111         /* Set TX, RX speed to 38400 -- this value allows
112            to use custom speed in struct struct_serial */
113         cfsetispeed(&tattr, B38400);
114         cfsetospeed(&tattr, B38400);
115
116         if (tcsetattr(tty, TCSANOW, &tattr) == -1)      
117                 perror("tcsetattr()");
118
119         /* Set real speed */
120         set_uart_baudrate(tty, lin_baudrate);
121
122         /* Calculate baudrate for sending LIN break */
123         lin_break_baud = ((lin_baudrate * 2) / 3);
124 }
125
126
127 int send_header(int tty)
128 {
129         int buff[3];
130         buff[0] = 0x00; /* Fake break */
131         buff[1] = 0x55; /* Sync byte */
132         buff[2] = 0xC1; /* LIN ID: 1 */
133
134         printf("send_header() invoked\n");
135         tcflush(tty, TCIOFLUSH);
136
137         /* Decrease speed to send BREAK
138            (simulated with 0x00 data frame) */
139         set_uart_baudrate(tty, lin_break_baud);
140
141         printf("Write break\n");
142         write(tty, &buff[0], 1); /* Write "break" */
143 #if 0
144         read(tty, &buff[0], 1);
145         printf("Break read\n");
146 #else
147         {
148                 struct timespec sleep_time;
149                 sleep_time.tv_sec = 0;
150                 sleep_time.tv_nsec = ((1000000000ll * 11) / lin_break_baud);
151                 clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep_time, NULL);
152         }
153 #endif
154
155         /* Restore "normal" speed */
156         set_uart_baudrate(tty, lin_baudrate);
157
158         write(tty, &buff[1], 1); /* Sync Byte Field */
159         write(tty, &buff[2], 1); /* PID -- Protected Identifier Field */
160         return 0;
161 }
162
163 int read_header(int tty)
164 {
165         int p0, p1; /* Parity bits */
166         int par_rec; /* Parity received as a part of a packet */
167         int par_calc; /* Calculated parity */
168         int received = 0;
169         uint8_t buff[LIN_HDR_SIZE];
170         memset(buff, '\0', sizeof(buff));
171
172         while (1) {
173                 received = read(tty, &buff[0], 1);
174                 if (received == -1)
175                         perror("read()");
176                 
177                 if (buff[0] != 0x55) /* Sync byte field */
178                         continue;
179
180                 received = read(tty, &buff[1], 1);
181                 if (received == -1)
182                         perror("read()");
183                 else
184                         break;
185         }
186
187         p0 = (buff[1] ^ (buff[1] >> 1) ^ (buff[1] >> 2) ^ (buff[1] >> 4)) & 0x1;
188         p1 = ~(((buff[1] >> 1) ^ (buff[1] >> 3) ^ (buff[1] >> 4) ^ (buff[1] >> 5))) & 0x1;
189
190         printf("%02X ", buff[0]);
191         printf("%02X ", buff[1]);
192
193         par_rec = (buff[1] & 0xc0) >> 6;
194         par_calc = p0 | (p1 << 1);
195         printf("| LIN id: %02X ", buff[1] & 0x3f);
196         //printf("| par_rec: %X; par_calc: %X ", par_rec, par_calc);
197         if (par_rec == par_calc)
198                 printf("| parity OK");
199         
200         printf("\n");
201
202         return 0;
203 }
204
205
206 int main(int argc, char* argv[])
207 {
208         char dev[32];
209         int tty;
210
211         if (argc < 2) {
212                 fprintf(stderr, "Device is missing\n");
213                 fprintf(stderr, "Usage: %s DEVICE\n", argv[0]);
214                 return -3;
215         }
216
217         strncpy((char*)&dev, argv[1], 32);
218         tty = open(dev, O_RDWR);
219         if (tty < 0) {
220                 perror("open()");
221                 return -4;
222         }
223
224         fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
225         printf("Press enter to terminate.\n\n");
226
227         /* Configure UART */
228         set_input_mode(tty);
229
230         while(1) {
231                 char c;
232
233                 send_header(tty);
234                 sleep(1);
235
236                 if (read(fileno(stdin), &c, 1) > 0)
237                         break;
238         }
239
240         reset_input_mode(tty);
241         close(tty);
242
243         return EXIT_SUCCESS;
244 }