#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <errno.h>
#define ARGU_FILENAME_OFFSET 1
#define PROPER_ARGU_CNT 2
#define BAUDRATE 115200
#define STOP_BIT 1
#define DATA_LEN 8
#define IS_PARITY 0
#define BUFFER_SIZE 512
#define LEN_OFFSET 1
#define PID_OFFSET 2
#define DATA_OFFSET 3
#define CHECKSUM_OFFSET 4
#define HEADER 0x23
#define LEN 0x02 // len + PID actually
#define PID 0x01
#define DEBUG
volatile sig_atomic_t sig_flag = 0;
uint8_t buffer[BUFFER_SIZE] = {0};
int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300,};
int name_arr[] = {115200, 38400, 19200, 9600, 4800, 2400, 1200, 300,};
typedef enum {
FILE_ERR = -5,
ARGUS_ERR,
SERIAL_SET_ERR,
INDEX_ERR
} err_type;
void quit_program_cb(int sig)
{
sig_flag = 1;
}
int open_serial(char* dev)
{
return open(dev, O_RDWR);
}
int set_speed(int fd, int speed)
{
int i;
int status;
struct termios Opt;
tcgetattr(fd, &Opt);
for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {
if (speed == name_arr[i]) {
tcflush(fd, TCIOFLUSH);
cfsetispeed(&Opt, speed_arr[i]);
cfsetospeed(&Opt, speed_arr[i]);
status = tcsetattr(fd, TCSANOW, &Opt);
if (status != 0) {
return SERIAL_SET_ERR;
}
return 0;
}
tcflush(fd,TCIOFLUSH);
}
return SERIAL_SET_ERR;
}
int set_Parity(int fd,int databits,int stopbits,int parity)
{
struct termios options;
if ( tcgetattr( fd,&options) != 0) {
perror("Setting serial error"); return SERIAL_SET_ERR;
}
options.c_cflag &= ~CSIZE;
switch (databits) {
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
fprintf(stderr
,"Unsupported data size\n"); return SERIAL_SET_ERR;
}
switch (parity) {
case 'n':
case 'N':
options.c_cflag &= ~PARENB; /* Clear parity enable */
options.c_iflag &= ~INPCK; /* Enable parity checking */
break;
case 'o':
case 'O':
options.c_cflag |= (PARODD | PARENB);
options.c_iflag |= INPCK;
break;
case 'e':
case 'E':
options.c_cflag |= PARENB; /* Enable parity */
options.c_cflag &= ~PARODD;
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'S':
case 's':
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
break;
default:
fprintf(stderr
,"Unsupported parity\n"); return SERIAL_SET_ERR;
}
switch (stopbits) {
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
fprintf(stderr
,"Unsupported stop bits\n"); return SERIAL_SET_ERR;
}
/* Set input parity option */
if (parity != 'n')
options.c_iflag |= INPCK;
options.c_cc[VTIME] = 150; // 15 seconds
options.c_cc[VMIN] = 0;
tcflush(fd,TCIFLUSH); /* Update the options and do it *NOW* */
if (tcsetattr(fd,TCSANOW,&options) != 0) {
perror("Setting serial error"); return SERIAL_SET_ERR;
}
return 0;
}
int serial_conf(int fd)
{
if (set_speed(fd, BAUDRATE) == SERIAL_SET_ERR)
return SERIAL_SET_ERR;
if (set_Parity(fd, DATA_LEN, STOP_BIT, (IS_PARITY ? 'Y' : 'N')) == SERIAL_SET_ERR)
return SERIAL_SET_ERR;
return 0;
}
int16_t find_speed_data_pattern(uint16_t size)
{
#ifdef DEBUG
return buffer[2];
#endif
uint16_t base = 0, correctness = 0;
size -= 1; // for safe traverse the array
while (base < size) {
if ((size - base) < 5) // no pattern matched at the end of the buffer
return INDEX_ERR;
if (buffer[base] == HEADER) { // header matched
varifying: correctness++;
switch (correctness) {
case 1:
if (buffer[base + LEN_OFFSET] == LEN)
goto varifying; // LEN matched
else
goto start_over;
case 2:
if (buffer[base + PID_OFFSET] == PID)
goto varifying; // PID matched
else
goto start_over;
case 3:
if (buffer[base + CHECKSUM_OFFSET] \
== ((PID + buffer[DATA_OFFSET]) % 0xff))
return buffer[base + DATA_OFFSET]; // pass, return speed_data
else
goto start_over;
}
}
else {
start_over: correctness = 0;
base++;
}
}
return INDEX_ERR;
}
int main(int argc, char** argv)
{
if (argc != PROPER_ARGU_CNT) {
puts("Too many or too few arguments!"); puts("Should be `./executable {FILENAME}`, whereas should have 2 args."); }
int fd_serial;
fd_serial = open_serial(*(argv + ARGU_FILENAME_OFFSET));
if (fd_serial == -1) {
puts("Device not exist or currently not available!"); puts("Do you forget to execute the program with `sudo` ?"); }
if (serial_conf(fd_serial) == SERIAL_SET_ERR) {
puts("Serial port configuration failed!"); }
signal(SIGINT, quit_program_cb);
uint32_t recv_cnt;
int16_t speed_data;
while ((recv_cnt = read(fd_serial, buffer, BUFFER_SIZE)) > 0) {
speed_data = find_speed_data_pattern(recv_cnt);
speed_data
== INDEX_ERR
? puts("No valid data."): printf("%d km/h\n", speed_data
);
sleep(1);
/* ctrl+c, program ending handler */
if (sig_flag) {
printf("\nExit status: %d\n", close
(fd_serial
)); puts("Terminated by user."); }
}
puts("Unexpected error occured!"); }
I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgPHN0ZGludC5oPgojaW5jbHVkZSA8c2lnbmFsLmg+CiNpbmNsdWRlIDxmY250bC5oPgojaW5jbHVkZSA8dW5pc3RkLmg+CiNpbmNsdWRlIDx0ZXJtaW9zLmg+CiNpbmNsdWRlIDxlcnJuby5oPgoKI2RlZmluZSBBUkdVX0ZJTEVOQU1FX09GRlNFVCAxCiNkZWZpbmUgUFJPUEVSX0FSR1VfQ05UIDIKI2RlZmluZSBCQVVEUkFURSAxMTUyMDAKI2RlZmluZSBTVE9QX0JJVCAxCiNkZWZpbmUgREFUQV9MRU4gOAojZGVmaW5lIElTX1BBUklUWSAwCiNkZWZpbmUgQlVGRkVSX1NJWkUgNTEyCiNkZWZpbmUgTEVOX09GRlNFVCAxCiNkZWZpbmUgUElEX09GRlNFVCAyCiNkZWZpbmUgREFUQV9PRkZTRVQgMwojZGVmaW5lIENIRUNLU1VNX09GRlNFVCA0CiNkZWZpbmUgSEVBREVSIDB4MjMKI2RlZmluZSBMRU4gMHgwMiAvLyBsZW4gKyBQSUQgYWN0dWFsbHkKI2RlZmluZSBQSUQgMHgwMQoKI2RlZmluZSBERUJVRwoKdm9sYXRpbGUgc2lnX2F0b21pY190IHNpZ19mbGFnID0gMDsKdWludDhfdCBidWZmZXJbQlVGRkVSX1NJWkVdID0gezB9OwoKaW50IHNwZWVkX2FycltdID0ge0IxMTUyMDAsIEIzODQwMCwgQjE5MjAwLCBCOTYwMCwgQjQ4MDAsIEIyNDAwLCBCMTIwMCwgQjMwMCx9OwoKaW50IG5hbWVfYXJyW10gPSB7MTE1MjAwLCAzODQwMCwgMTkyMDAsIDk2MDAsIDQ4MDAsIDI0MDAsIDEyMDAsIDMwMCx9OwoKdHlwZWRlZiBlbnVtIHsKCUZJTEVfRVJSID0gLTUsCglBUkdVU19FUlIsCglTRVJJQUxfU0VUX0VSUiwKCUlOREVYX0VSUgp9IGVycl90eXBlOwoKdm9pZCBxdWl0X3Byb2dyYW1fY2IoaW50IHNpZykgCnsKCXNpZ19mbGFnID0gMTsKfQoKaW50IG9wZW5fc2VyaWFsKGNoYXIqIGRldikKewoJcmV0dXJuIG9wZW4oZGV2LCBPX1JEV1IpOwp9CgppbnQgc2V0X3NwZWVkKGludCBmZCwgaW50IHNwZWVkKQp7CglpbnQgaTsKCWludCBzdGF0dXM7CglzdHJ1Y3QgdGVybWlvcyBPcHQ7Cgl0Y2dldGF0dHIoZmQsICZPcHQpOwoKICAJZm9yICggaT0gMDsgaSA8IHNpemVvZihzcGVlZF9hcnIpIC8gc2l6ZW9mKGludCk7IGkrKykgewoJCWlmIChzcGVlZCA9PSBuYW1lX2FycltpXSkgewoJCQl0Y2ZsdXNoKGZkLCBUQ0lPRkxVU0gpOwoJCQljZnNldGlzcGVlZCgmT3B0LCBzcGVlZF9hcnJbaV0pOwoJCQljZnNldG9zcGVlZCgmT3B0LCBzcGVlZF9hcnJbaV0pOwoJICAgICAgICAJc3RhdHVzID0gdGNzZXRhdHRyKGZkLCBUQ1NBTk9XLCAmT3B0KTsKCgkJICAgICAgaWYgKHN0YXR1cyAhPSAwKSB7CgkJICAgICAgICAJcGVycm9yKCJ0Y3NldGF0dHIgZmQxYSIpOwoJCQkJcmV0dXJuIFNFUklBTF9TRVRfRVJSOwoJCQl9CgoJICAgICAgICAJcmV0dXJuIDA7CiAgICAgICAgCX0KCQl0Y2ZsdXNoKGZkLFRDSU9GTFVTSCk7Cgl9CgkKCXJldHVybiBTRVJJQUxfU0VUX0VSUjsKfQoKaW50IHNldF9QYXJpdHkoaW50IGZkLGludCBkYXRhYml0cyxpbnQgc3RvcGJpdHMsaW50IHBhcml0eSkKewoKICAgICAgc3RydWN0IHRlcm1pb3Mgb3B0aW9uczsKCiAgICAgIGlmICAoIHRjZ2V0YXR0ciggZmQsJm9wdGlvbnMpICAhPSAgMCkgewogICAgICAgICAgICBwZXJyb3IoIlNldHRpbmcgc2VyaWFsIGVycm9yIik7CiAgICAgICAgICAgIHJldHVybiBTRVJJQUxfU0VUX0VSUjsKICAgICAgfQoKICAgICAgb3B0aW9ucy5jX2NmbGFnICY9IH5DU0laRTsKCiAgICAgIHN3aXRjaCAoZGF0YWJpdHMpIHsKICAgICAgICAgICAgY2FzZSA3OgogICAgICAgICAgICAgICAgICBvcHRpb25zLmNfY2ZsYWcgfD0gQ1M3OwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSA4OgogICAgICAgICAgICAgICAgICBvcHRpb25zLmNfY2ZsYWcgfD0gQ1M4OwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICAgICAgZnByaW50ZihzdGRlcnIsIlVuc3VwcG9ydGVkIGRhdGEgc2l6ZVxuIik7CiAgICAgICAgICAgICAgICAgIHJldHVybiBTRVJJQUxfU0VUX0VSUjsKICAgICAgfQoKICAgICAgc3dpdGNoIChwYXJpdHkpIHsKICAgICAgICAgICAgY2FzZSAnbic6CiAgICAgICAgICAgIGNhc2UgJ04nOgogICAgICAgICAgICAgICAgICBvcHRpb25zLmNfY2ZsYWcgJj0gflBBUkVOQjsgICAvKiBDbGVhciBwYXJpdHkgZW5hYmxlICovCiAgICAgICAgICAgICAgICAgIG9wdGlvbnMuY19pZmxhZyAmPSB+SU5QQ0s7ICAgICAvKiBFbmFibGUgcGFyaXR5IGNoZWNraW5nICovCiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICBjYXNlICdvJzoKICAgICAgICAgICAgY2FzZSAnTyc6CiAgICAgICAgICAgICAgICAgIG9wdGlvbnMuY19jZmxhZyB8PSAoUEFST0REIHwgUEFSRU5CKTsKICAgICAgICAgICAgICAgICAgb3B0aW9ucy5jX2lmbGFnIHw9IElOUENLOwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSAnZSc6CiAgICAgICAgICAgIGNhc2UgJ0UnOgogICAgICAgICAgICAgICAgICBvcHRpb25zLmNfY2ZsYWcgfD0gUEFSRU5COyAgICAgLyogRW5hYmxlIHBhcml0eSAqLwogICAgICAgICAgICAgICAgICBvcHRpb25zLmNfY2ZsYWcgJj0gflBBUk9ERDsKICAgICAgICAgICAgICAgICAgb3B0aW9ucy5jX2lmbGFnIHw9IElOUENLOyAgICAgICAvKiBEaXNuYWJsZSBwYXJpdHkgY2hlY2tpbmcgKi8KICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgJ1MnOgogICAgICAgICAgICBjYXNlICdzJzoKICAgICAgICAgICAgICAgICAgb3B0aW9ucy5jX2NmbGFnICY9IH5QQVJFTkI7CiAgICAgICAgICAgICAgICAgIG9wdGlvbnMuY19jZmxhZyAmPSB+Q1NUT1BCOwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICAgICAgZnByaW50ZihzdGRlcnIsIlVuc3VwcG9ydGVkIHBhcml0eVxuIik7CiAgICAgICAgICAgICAgICAgIHJldHVybiBTRVJJQUxfU0VUX0VSUjsKICAgICAgfQoKICAgICAgc3dpdGNoIChzdG9wYml0cykgewogICAgICAgICAgICBjYXNlIDE6CiAgICAgICAgICAgICAgICAgIG9wdGlvbnMuY19jZmxhZyAmPSB+Q1NUT1BCOwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSAyOgogICAgICAgICAgICAgICAgICBvcHRpb25zLmNfY2ZsYWcgfD0gQ1NUT1BCOwogICAgICAgICAgICAJICBicmVhazsKICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICAgICAgZnByaW50ZihzdGRlcnIsIlVuc3VwcG9ydGVkIHN0b3AgYml0c1xuIik7CiAgICAgICAgICAgICAgICAgIHJldHVybiBTRVJJQUxfU0VUX0VSUjsKICAgICAgfQoKICAgICAgLyogU2V0IGlucHV0IHBhcml0eSBvcHRpb24gKi8KICAgICAgaWYgKHBhcml0eSAhPSAnbicpCiAgICAgICAgICAgIG9wdGlvbnMuY19pZmxhZyB8PSBJTlBDSzsKCiAgICAgIG9wdGlvbnMuY19jY1tWVElNRV0gPSAxNTA7IC8vIDE1IHNlY29uZHMKCiAgICAgIG9wdGlvbnMuY19jY1tWTUlOXSA9IDA7CgogICAgICB0Y2ZsdXNoKGZkLFRDSUZMVVNIKTsgLyogVXBkYXRlIHRoZSBvcHRpb25zIGFuZCBkbyBpdCAqTk9XKiAqLwoKICAgICAgaWYgKHRjc2V0YXR0cihmZCxUQ1NBTk9XLCZvcHRpb25zKSAhPSAwKSB7CiAgICAgICAgICAgIHBlcnJvcigiU2V0dGluZyBzZXJpYWwgZXJyb3IiKTsKICAgICAgICAgICAgcmV0dXJuIFNFUklBTF9TRVRfRVJSOwoKICAgICAgfQoKICAgICAgcmV0dXJuIDA7CiB9CgppbnQgc2VyaWFsX2NvbmYoaW50IGZkKQp7CglpZiAoc2V0X3NwZWVkKGZkLCBCQVVEUkFURSkgPT0gU0VSSUFMX1NFVF9FUlIpCiAgICAgICAgICAgIHJldHVybiBTRVJJQUxfU0VUX0VSUjsKCWlmIChzZXRfUGFyaXR5KGZkLCBEQVRBX0xFTiwgU1RPUF9CSVQsIChJU19QQVJJVFkgPyAnWScgOiAnTicpKSA9PSBTRVJJQUxfU0VUX0VSUikKICAgICAgICAgICAgcmV0dXJuIFNFUklBTF9TRVRfRVJSOwoKICAgICAgcmV0dXJuIDA7Cn0KCmludDE2X3QgZmluZF9zcGVlZF9kYXRhX3BhdHRlcm4odWludDE2X3Qgc2l6ZSkKewojaWZkZWYgREVCVUcKCXJldHVybiBidWZmZXJbMl07CiNlbmRpZgoJdWludDE2X3QgYmFzZSA9IDAsIGNvcnJlY3RuZXNzID0gMDsKCQoJc2l6ZSAtPSAxOyAvLyBmb3Igc2FmZSB0cmF2ZXJzZSB0aGUgYXJyYXkKCgl3aGlsZSAoYmFzZSA8IHNpemUpIHsKCQlpZiAoKHNpemUgLSBiYXNlKSA8IDUpIC8vIG5vIHBhdHRlcm4gbWF0Y2hlZCBhdCB0aGUgZW5kIG9mIHRoZSBidWZmZXIKCQkJcmV0dXJuIElOREVYX0VSUjsKCQlpZiAoYnVmZmVyW2Jhc2VdID09IEhFQURFUikgeyAvLyBoZWFkZXIgbWF0Y2hlZAp2YXJpZnlpbmc6CQljb3JyZWN0bmVzcysrOwoJCQlzd2l0Y2ggKGNvcnJlY3RuZXNzKSB7CgkJCQljYXNlIDE6CgkJCQkJaWYgKGJ1ZmZlcltiYXNlICsgTEVOX09GRlNFVF0gPT0gTEVOKQoJCQkJCQlnb3RvIHZhcmlmeWluZzsgLy8gTEVOIG1hdGNoZWQKCQkJCQllbHNlCgkJCQkJCWdvdG8gc3RhcnRfb3ZlcjsKCQkJCWNhc2UgMjoKCQkJCQlpZiAoYnVmZmVyW2Jhc2UgKyBQSURfT0ZGU0VUXSA9PSBQSUQpCgkJCQkJCWdvdG8gdmFyaWZ5aW5nOyAvLyBQSUQgbWF0Y2hlZAoJCQkJCWVsc2UKCQkJCQkJZ290byBzdGFydF9vdmVyOwoJCQkJY2FzZSAzOgoJCQkJCWlmIChidWZmZXJbYmFzZSArIENIRUNLU1VNX09GRlNFVF0gXAoJCQkJCT09ICgoUElEICsgYnVmZmVyW0RBVEFfT0ZGU0VUXSkgJSAweGZmKSkKCQkJCQkJcmV0dXJuIGJ1ZmZlcltiYXNlICsgREFUQV9PRkZTRVRdOyAvLyBwYXNzLCByZXR1cm4gc3BlZWRfZGF0YQoJCQkJCWVsc2UKCQkJCQkJZ290byBzdGFydF9vdmVyOwoJCQl9CgkJfQoJCWVsc2UgewpzdGFydF9vdmVyOgkJY29ycmVjdG5lc3MgPSAwOwoJCQliYXNlKys7CgkJfQoJfQoJcmV0dXJuIElOREVYX0VSUjsKfQoKaW50IG1haW4oaW50IGFyZ2MsIGNoYXIqKiBhcmd2KQp7CglpZiAoYXJnYyAhPSBQUk9QRVJfQVJHVV9DTlQpIHsKCQlwdXRzKCJUb28gbWFueSBvciB0b28gZmV3IGFyZ3VtZW50cyEiKTsKCQlwdXRzKCJTaG91bGQgYmUgYC4vZXhlY3V0YWJsZSB7RklMRU5BTUV9YCwgd2hlcmVhcyBzaG91bGQgaGF2ZSAyIGFyZ3MuIik7CgkJZXhpdChBUkdVU19FUlIpOwoJfQoKCWludCBmZF9zZXJpYWw7CgoJZmRfc2VyaWFsID0gb3Blbl9zZXJpYWwoKihhcmd2ICsgQVJHVV9GSUxFTkFNRV9PRkZTRVQpKTsKICAgICAgCglpZiAoZmRfc2VyaWFsID09IC0xKSB7CgkJcHV0cygiRGV2aWNlIG5vdCBleGlzdCBvciBjdXJyZW50bHkgbm90IGF2YWlsYWJsZSEiKTsKCQlwdXRzKCJEbyB5b3UgZm9yZ2V0IHRvIGV4ZWN1dGUgdGhlIHByb2dyYW0gd2l0aCBgc3Vkb2AgPyIpOwoJCWV4aXQoRklMRV9FUlIpOwoJfQoKCWlmIChzZXJpYWxfY29uZihmZF9zZXJpYWwpID09IFNFUklBTF9TRVRfRVJSKSB7CgkJcHV0cygiU2VyaWFsIHBvcnQgY29uZmlndXJhdGlvbiBmYWlsZWQhIik7CgkJZXhpdChTRVJJQUxfU0VUX0VSUik7Cgl9CgoJc2lnbmFsKFNJR0lOVCwgcXVpdF9wcm9ncmFtX2NiKTsKCQoJdWludDMyX3QgcmVjdl9jbnQ7CglpbnQxNl90IHNwZWVkX2RhdGE7CgoJd2hpbGUgKChyZWN2X2NudCA9IHJlYWQoZmRfc2VyaWFsLCBidWZmZXIsIEJVRkZFUl9TSVpFKSkgPiAwKSB7CgkJc3BlZWRfZGF0YSA9IGZpbmRfc3BlZWRfZGF0YV9wYXR0ZXJuKHJlY3ZfY250KTsKCQlzcGVlZF9kYXRhID09IElOREVYX0VSUiA/IHB1dHMoIk5vIHZhbGlkIGRhdGEuIik6IHByaW50ZigiJWQga20vaFxuIiwgc3BlZWRfZGF0YSk7CgkKCQlzbGVlcCgxKTsKCQkvKiBjdHJsK2MsIHByb2dyYW0gZW5kaW5nIGhhbmRsZXIgKi8KCQlpZiAoc2lnX2ZsYWcpIHsKCQkJcHJpbnRmKCJcbkV4aXQgc3RhdHVzOiAlZFxuIiwgY2xvc2UoZmRfc2VyaWFsKSk7CgkJCXB1dHMoIlRlcm1pbmF0ZWQgYnkgdXNlci4iKTsKCQkJZXhpdCgwKTsKCQl9Cgl9CgoJcHV0cygiVW5leHBlY3RlZCBlcnJvciBvY2N1cmVkISIpOwoJZXhpdCgtMSk7Cn0K