fork download
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdint.h>
  4. #include <signal.h>
  5. #include <fcntl.h>
  6. #include <unistd.h>
  7. #include <termios.h>
  8. #include <errno.h>
  9.  
  10. #define ARGU_FILENAME_OFFSET 1
  11. #define PROPER_ARGU_CNT 2
  12. #define BAUDRATE 115200
  13. #define STOP_BIT 1
  14. #define DATA_LEN 8
  15. #define IS_PARITY 0
  16. #define BUFFER_SIZE 512
  17. #define LEN_OFFSET 1
  18. #define PID_OFFSET 2
  19. #define DATA_OFFSET 3
  20. #define CHECKSUM_OFFSET 4
  21. #define HEADER 0x23
  22. #define LEN 0x02 // len + PID actually
  23. #define PID 0x01
  24.  
  25. #define DEBUG
  26.  
  27. volatile sig_atomic_t sig_flag = 0;
  28. uint8_t buffer[BUFFER_SIZE] = {0};
  29.  
  30. int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300,};
  31.  
  32. int name_arr[] = {115200, 38400, 19200, 9600, 4800, 2400, 1200, 300,};
  33.  
  34. typedef enum {
  35. FILE_ERR = -5,
  36. ARGUS_ERR,
  37. SERIAL_SET_ERR,
  38. INDEX_ERR
  39. } err_type;
  40.  
  41. void quit_program_cb(int sig)
  42. {
  43. sig_flag = 1;
  44. }
  45.  
  46. int open_serial(char* dev)
  47. {
  48. return open(dev, O_RDWR);
  49. }
  50.  
  51. int set_speed(int fd, int speed)
  52. {
  53. int i;
  54. int status;
  55. struct termios Opt;
  56. tcgetattr(fd, &Opt);
  57.  
  58. for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {
  59. if (speed == name_arr[i]) {
  60. tcflush(fd, TCIOFLUSH);
  61. cfsetispeed(&Opt, speed_arr[i]);
  62. cfsetospeed(&Opt, speed_arr[i]);
  63. status = tcsetattr(fd, TCSANOW, &Opt);
  64.  
  65. if (status != 0) {
  66. perror("tcsetattr fd1a");
  67. return SERIAL_SET_ERR;
  68. }
  69.  
  70. return 0;
  71. }
  72. tcflush(fd,TCIOFLUSH);
  73. }
  74.  
  75. return SERIAL_SET_ERR;
  76. }
  77.  
  78. int set_Parity(int fd,int databits,int stopbits,int parity)
  79. {
  80.  
  81. struct termios options;
  82.  
  83. if ( tcgetattr( fd,&options) != 0) {
  84. perror("Setting serial error");
  85. return SERIAL_SET_ERR;
  86. }
  87.  
  88. options.c_cflag &= ~CSIZE;
  89.  
  90. switch (databits) {
  91. case 7:
  92. options.c_cflag |= CS7;
  93. break;
  94. case 8:
  95. options.c_cflag |= CS8;
  96. break;
  97. default:
  98. fprintf(stderr,"Unsupported data size\n");
  99. return SERIAL_SET_ERR;
  100. }
  101.  
  102. switch (parity) {
  103. case 'n':
  104. case 'N':
  105. options.c_cflag &= ~PARENB; /* Clear parity enable */
  106. options.c_iflag &= ~INPCK; /* Enable parity checking */
  107. break;
  108. case 'o':
  109. case 'O':
  110. options.c_cflag |= (PARODD | PARENB);
  111. options.c_iflag |= INPCK;
  112. break;
  113. case 'e':
  114. case 'E':
  115. options.c_cflag |= PARENB; /* Enable parity */
  116. options.c_cflag &= ~PARODD;
  117. options.c_iflag |= INPCK; /* Disnable parity checking */
  118. break;
  119. case 'S':
  120. case 's':
  121. options.c_cflag &= ~PARENB;
  122. options.c_cflag &= ~CSTOPB;
  123. break;
  124. default:
  125. fprintf(stderr,"Unsupported parity\n");
  126. return SERIAL_SET_ERR;
  127. }
  128.  
  129. switch (stopbits) {
  130. case 1:
  131. options.c_cflag &= ~CSTOPB;
  132. break;
  133. case 2:
  134. options.c_cflag |= CSTOPB;
  135. break;
  136. default:
  137. fprintf(stderr,"Unsupported stop bits\n");
  138. return SERIAL_SET_ERR;
  139. }
  140.  
  141. /* Set input parity option */
  142. if (parity != 'n')
  143. options.c_iflag |= INPCK;
  144.  
  145. options.c_cc[VTIME] = 150; // 15 seconds
  146.  
  147. options.c_cc[VMIN] = 0;
  148.  
  149. tcflush(fd,TCIFLUSH); /* Update the options and do it *NOW* */
  150.  
  151. if (tcsetattr(fd,TCSANOW,&options) != 0) {
  152. perror("Setting serial error");
  153. return SERIAL_SET_ERR;
  154.  
  155. }
  156.  
  157. return 0;
  158. }
  159.  
  160. int serial_conf(int fd)
  161. {
  162. if (set_speed(fd, BAUDRATE) == SERIAL_SET_ERR)
  163. return SERIAL_SET_ERR;
  164. if (set_Parity(fd, DATA_LEN, STOP_BIT, (IS_PARITY ? 'Y' : 'N')) == SERIAL_SET_ERR)
  165. return SERIAL_SET_ERR;
  166.  
  167. return 0;
  168. }
  169.  
  170. int16_t find_speed_data_pattern(uint16_t size)
  171. {
  172. #ifdef DEBUG
  173. return buffer[2];
  174. #endif
  175. uint16_t base = 0, correctness = 0;
  176.  
  177. size -= 1; // for safe traverse the array
  178.  
  179. while (base < size) {
  180. if ((size - base) < 5) // no pattern matched at the end of the buffer
  181. return INDEX_ERR;
  182. if (buffer[base] == HEADER) { // header matched
  183. varifying: correctness++;
  184. switch (correctness) {
  185. case 1:
  186. if (buffer[base + LEN_OFFSET] == LEN)
  187. goto varifying; // LEN matched
  188. else
  189. goto start_over;
  190. case 2:
  191. if (buffer[base + PID_OFFSET] == PID)
  192. goto varifying; // PID matched
  193. else
  194. goto start_over;
  195. case 3:
  196. if (buffer[base + CHECKSUM_OFFSET] \
  197. == ((PID + buffer[DATA_OFFSET]) % 0xff))
  198. return buffer[base + DATA_OFFSET]; // pass, return speed_data
  199. else
  200. goto start_over;
  201. }
  202. }
  203. else {
  204. start_over: correctness = 0;
  205. base++;
  206. }
  207. }
  208. return INDEX_ERR;
  209. }
  210.  
  211. int main(int argc, char** argv)
  212. {
  213. if (argc != PROPER_ARGU_CNT) {
  214. puts("Too many or too few arguments!");
  215. puts("Should be `./executable {FILENAME}`, whereas should have 2 args.");
  216. exit(ARGUS_ERR);
  217. }
  218.  
  219. int fd_serial;
  220.  
  221. fd_serial = open_serial(*(argv + ARGU_FILENAME_OFFSET));
  222.  
  223. if (fd_serial == -1) {
  224. puts("Device not exist or currently not available!");
  225. puts("Do you forget to execute the program with `sudo` ?");
  226. exit(FILE_ERR);
  227. }
  228.  
  229. if (serial_conf(fd_serial) == SERIAL_SET_ERR) {
  230. puts("Serial port configuration failed!");
  231. exit(SERIAL_SET_ERR);
  232. }
  233.  
  234. signal(SIGINT, quit_program_cb);
  235.  
  236. uint32_t recv_cnt;
  237. int16_t speed_data;
  238.  
  239. while ((recv_cnt = read(fd_serial, buffer, BUFFER_SIZE)) > 0) {
  240. speed_data = find_speed_data_pattern(recv_cnt);
  241. speed_data == INDEX_ERR ? puts("No valid data."): printf("%d km/h\n", speed_data);
  242.  
  243. sleep(1);
  244. /* ctrl+c, program ending handler */
  245. if (sig_flag) {
  246. printf("\nExit status: %d\n", close(fd_serial));
  247. puts("Terminated by user.");
  248. exit(0);
  249. }
  250. }
  251.  
  252. puts("Unexpected error occured!");
  253. exit(-1);
  254. }
  255.  
Runtime error #stdin #stdout 0s 9432KB
stdin
Standard input is empty
stdout
Too many or too few arguments!
Should be `./executable {FILENAME}`, whereas should have 2 args.