2 * PCAN-LIN, RS-232 to CAN/LIN converter control application
12 #include <sys/ioctl.h>
13 #include <linux/serial.h> /* struct struct_serial */
16 #include <time.h> /* clock_nanosleep */
18 #define LIN_HDR_SIZE 2
19 #define LIN_PKT_MAX_SIZE 16 /* FIXME */
21 int lin_baudrate = B19200;
22 int lin_break_baud = 0;
24 struct termios tattr_orig;
26 struct serial_struct sattr;
27 /* ------------------------------------------------------------------------ */
28 static void reset_input_mode(int tty)
30 tcsetattr(tty, TCSANOW, &tattr_orig);
33 static void set_input_mode(int tty, speed_t speed)
37 /* Flush input and output queues. */
38 if (tcflush(tty, TCIOFLUSH) != 0) {
43 /* Fetch the current terminal parameters. */
45 fprintf(stderr, "Not a terminal.\n");
49 /* Save settings for later restoring */
50 tcgetattr(tty, &tattr_orig);
51 if (ioctl(tty, TIOCGSERIAL, &sattr) < 0) {
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;
64 /* Sets hardware control flags: */
67 /* Ignore CD (local connection) */
68 tattr.c_cflag = CS8 | CREAD | CLOCAL;
70 tattr.c_oflag = NL0 | CR0 | TAB0 | BS0 | VT0 | FF0;
73 // tattr.c_cc[VMIN] = 1;
74 // tattr.c_cc[VTIME] = 0;
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';
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';
94 /* Set TX, RX speed */
95 cfsetispeed(&tattr, speed);
96 cfsetospeed(&tattr, speed);
98 status = tcsetattr(tty, TCSANOW, &tattr);
100 perror("tcsetattr()");
102 /* Baudrate for sending LIN break */
103 //lin_break_baud = ((lin_baudrate * 2) / 3);
104 lin_break_baud = 12800;
108 int send_header(int tty)
111 buff[0] = 0x00; /* Sync byte */
112 buff[1] = 0x55; /* Sync byte */
113 buff[2] = 0xC1; /* LIN ID: 1 */
115 printf("send_header() invoked\n");
116 tcflush(tty, TCIOFLUSH);
118 /* Decrease speed to send BREAK
119 * (simulated with 0x00 data frame) */
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)
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()");
137 printf("Write break\n");
138 write(tty, &buff[0], 1); /* Write "break" */
140 read(tty, &buff[0], 1);
141 printf("Break read\n");
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);
151 sattr.flags &= (~ASYNC_SPD_CUST);
152 sattr.flags |= (ASYNC_SPD_MASK);
153 if (ioctl(tty, TIOCSSERIAL, &sattr) < 0)
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()");
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 */
173 int read_header(int tty)
175 int p0, p1; /* Parity bits */
176 int par_rec; /* Parity received as a part of a packet */
177 int par_calc; /* Calculated parity */
179 uint8_t buff[LIN_HDR_SIZE];
180 memset(buff, '\0', sizeof(buff));
183 received = read(tty, &buff[0], 1);
187 if (buff[0] != 0x55) /* Sync byte field */
190 received = read(tty, &buff[1], 1);
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;
200 printf("%02X ", buff[0]);
201 printf("%02X ", buff[1]);
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");
216 int main(int argc, char* argv[])
222 fprintf(stderr, "Device is missing\n");
223 fprintf(stderr, "Usage: %s DEVICE\n", argv[0]);
227 strncpy((char*)&dev, argv[1], 32);
228 tty = open(dev, O_RDWR);
234 fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
235 printf("Press enter to terminate.\n\n");
238 set_input_mode(tty, lin_baudrate);
246 if (read(fileno(stdin), &c, 1) > 0)
250 reset_input_mode(tty);