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