serial_linux.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /*************************************************
  2. Copyright (c) 2019
  3. All rights reserved.
  4. File name: dlt645_port.c
  5. Description: DLT645 移植&使用例程文件
  6. History:
  7. 1. Version:
  8. Date: 2019-09-19
  9. Author: wangjunjie
  10. Modify:
  11. *************************************************/
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <fcntl.h>
  17. #include "dlt645_private.h"
  18. #include <unistd.h>
  19. #include <termios.h>
  20. #include "serial_linux.h"
  21. //DL/T 645硬件拓展结构体
  22. typedef struct
  23. {
  24. int fd;
  25. uint8_t is_rs485;
  26. struct termios old_tios;
  27. } serial_port_t;
  28. static int serial_select(dlt645_t *ctx)
  29. {
  30. int s_rc;
  31. fd_set rfds;
  32. struct timeval tv;
  33. serial_port_t *port = ctx->port_data;
  34. FD_ZERO(&rfds);
  35. FD_SET(port->fd, &rfds);
  36. tv.tv_sec = ctx->response_timeout / 1000;
  37. tv.tv_usec = (ctx->response_timeout % 1000) * 1000;
  38. s_rc = select(port->fd + 1, &rfds, NULL, NULL, &tv);
  39. if (s_rc < 0)
  40. {
  41. return -1;
  42. }
  43. else
  44. {
  45. return s_rc;
  46. }
  47. }
  48. /**
  49. * Name: serial_linux_hw_read
  50. * Brief: dlt645 硬件层接收数据
  51. * Input:
  52. * @ctx: 645运行环境
  53. * @msg: 接收数据存放地址
  54. * @len: 数据最大接收长度
  55. * Output: 读取数据的长度 -1:error 0:timeout
  56. */
  57. static int serial_linux_hw_read(dlt645_t *ctx, uint8_t *msg, uint16_t len)
  58. {
  59. //实际接收长度
  60. int rc = 0;
  61. int length_to_read = 1, msg_length = 0;
  62. serial_port_t *port = ctx->port_data;
  63. _step_t step;
  64. step = _STEP_START;
  65. while (length_to_read != 0)
  66. {
  67. rc = serial_select(ctx);
  68. if (rc < 0)
  69. {
  70. printf("select error on fd %d\r\n", port->fd);
  71. return -1;
  72. }
  73. else if (rc == 0)
  74. {
  75. printf("select timeout on fd %d\r\n", port->fd);
  76. return 0;
  77. }
  78. rc = read(port->fd, msg + msg_length, length_to_read);
  79. if (rc < 0)
  80. {
  81. printf("read error on fd %d\r\n", port->fd);
  82. return -1;
  83. }
  84. //更新已收到的数据长度以及待接收的数据长度
  85. msg_length += rc;
  86. length_to_read -= rc;
  87. if (length_to_read == 0)
  88. {
  89. switch (step)
  90. {
  91. case _STEP_START:
  92. if (msg[0] == DLT645_START_CODE)
  93. {
  94. length_to_read = 9;
  95. step = _STEP_META;
  96. }
  97. break;
  98. case _STEP_META:
  99. length_to_read = msg[DLT645_LEN_POS];
  100. step = _STEP_DATA;
  101. break;
  102. case _STEP_DATA:
  103. length_to_read = 2;
  104. step = _STEP_END;
  105. break;
  106. case _STEP_END:
  107. if (msg[msg_length - 1] != DLT645_STOP_CODE)
  108. {
  109. printf("dlt645 frame error,no stop code\r\n");
  110. return -1;
  111. }
  112. break;
  113. default:
  114. break;
  115. }
  116. }
  117. }
  118. return msg_length;
  119. }
  120. /**
  121. * Name: serial_linux_hw_write
  122. * Brief: dlt645 硬件层发送数据
  123. * Input:
  124. * @ctx: 645运行环境
  125. * @buf: 待发送数据
  126. * @len: 发送长度
  127. * Output: 实际发送的字节数,错误返回-1
  128. */
  129. static int serial_linux_hw_write(dlt645_t *ctx, uint8_t *buf, uint16_t len)
  130. {
  131. serial_port_t *port = ctx->port_data;
  132. int write_len = 0;
  133. write_len = write(port->fd, buf, len);
  134. return write_len;
  135. }
  136. static void _port_close(serial_port_t *port)
  137. {
  138. if (port)
  139. {
  140. tcsetattr(port->fd, TCSANOW, &port->old_tios);
  141. if (port->fd)
  142. {
  143. if (close(port->fd) == 0)
  144. {
  145. printf("close fd:%d success\r\n", port->fd);
  146. }
  147. else
  148. {
  149. printf("close fd:%d failed\r\n", port->fd);
  150. }
  151. }
  152. }
  153. }
  154. static void serial_linux_hw_close(dlt645_t *ctx)
  155. {
  156. if (ctx == NULL)
  157. {
  158. return;
  159. }
  160. if (ctx->port_data)
  161. {
  162. _port_close(ctx->port_data);
  163. free(ctx->port_data);
  164. ctx->port_data = NULL;
  165. }
  166. free(ctx);
  167. ctx = NULL;
  168. }
  169. const dlt645_backend_t serial_linux_backend = {
  170. serial_linux_hw_close,
  171. serial_linux_hw_write,
  172. serial_linux_hw_read};
  173. /**
  174. * Name: serial_linux_port_init
  175. * Brief: 硬件层初始化
  176. * Input: None
  177. * Output: None
  178. */
  179. static int serial_linux_port_init(dlt645_t *ctx, void *param)
  180. {
  181. serial_linux_param_t *port_param = param;
  182. if (ctx == NULL)
  183. {
  184. printf("no ctx available\r\n");
  185. return -1;
  186. }
  187. serial_port_t *port = dlt645_malloc(sizeof(serial_port_t));
  188. if (port == NULL)
  189. {
  190. printf("no memory for serial_port_t\r\n");
  191. return -1;
  192. }
  193. memset(port, 0, sizeof(serial_port_t));
  194. //串口初始化
  195. port->fd = open(port_param->device_name, O_RDWR | O_NOCTTY);
  196. if (port->fd < 0)
  197. {
  198. printf("cannot open device %s \r\n", port_param->device_name);
  199. dlt645_free(port);
  200. return -1;
  201. }
  202. else
  203. {
  204. struct termios opt;
  205. int baudrate = 0;
  206. tcgetattr(port->fd, &port->old_tios);
  207. memset(&opt, 0, sizeof(struct termios));
  208. //清空串口接收缓冲区
  209. tcflush(port->fd, TCIOFLUSH);
  210. // 设置串口输出波特率
  211. switch (port_param->baud)
  212. {
  213. case SERIAL_B1200:
  214. baudrate = B1200;
  215. break;
  216. case SERIAL_B2400:
  217. baudrate = B2400;
  218. break;
  219. case SERIAL_B4800:
  220. baudrate = B4800;
  221. break;
  222. case SERIAL_B9600:
  223. baudrate = B9600;
  224. break;
  225. case SERIAL_B19200:
  226. baudrate = B19200;
  227. break;
  228. case SERIAL_B38400:
  229. baudrate = B38400;
  230. break;
  231. case SERIAL_B57600:
  232. baudrate = B57600;
  233. break;
  234. case SERIAL_B115200:
  235. baudrate = B115200;
  236. break;
  237. default:
  238. printf("unknown baud rate :%d, use default 9600\r\n", port_param->baud);
  239. baudrate = B9600;
  240. break;
  241. }
  242. if ((cfsetospeed(&opt, baudrate) < 0) ||
  243. (cfsetispeed(&opt, baudrate) < 0))
  244. {
  245. close(port->fd);
  246. dlt645_free(port);
  247. return -1;
  248. }
  249. //设置数据位数
  250. opt.c_cflag &= ~CSIZE;
  251. switch (port_param->data_bits)
  252. {
  253. case DATA_BITS_5:
  254. opt.c_cflag |= CS5;
  255. break;
  256. case DATA_BITS_6:
  257. opt.c_cflag |= CS6;
  258. break;
  259. case DATA_BITS_7:
  260. opt.c_cflag |= CS7;
  261. break;
  262. case DATA_BITS_8:
  263. default:
  264. opt.c_cflag |= CS8;
  265. break;
  266. }
  267. //校验位
  268. switch (port_param->parity)
  269. {
  270. case PARITY_NONE:
  271. opt.c_cflag &= ~PARENB;
  272. opt.c_iflag &= ~INPCK;
  273. break;
  274. case PARITY_EVEN:
  275. opt.c_cflag |= PARENB;
  276. opt.c_cflag &= ~PARODD;
  277. opt.c_iflag |= INPCK;
  278. break;
  279. case PARITY_ODD:
  280. opt.c_cflag |= PARENB;
  281. opt.c_cflag |= PARODD;
  282. opt.c_iflag |= INPCK;
  283. break;
  284. default:
  285. break;
  286. }
  287. //设置停止位
  288. if (port_param->stop_bits == STOP_BITS_1)
  289. {
  290. opt.c_cflag &= ~CSTOPB;
  291. }
  292. else
  293. {
  294. opt.c_cflag |= CSTOPB;
  295. }
  296. /* Software flow control is disabled */
  297. opt.c_iflag &= ~(IXON | IXOFF | IXANY);
  298. /* Raw ouput */
  299. opt.c_oflag &= ~OPOST;
  300. opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  301. printf("Device %s on fd %d is set to 9600bps,8N1\n", port_param->device_name, port->fd);
  302. //更新配置
  303. if (tcsetattr(port->fd, TCSANOW, &opt) < 0)
  304. {
  305. close(port->fd);
  306. dlt645_free(port);
  307. return -1;
  308. }
  309. }
  310. ctx->port_data = port;
  311. return 0;
  312. }
  313. dlt645_t *dlt645_new_serial_linux(serial_linux_param_t *params)
  314. {
  315. //create dlt645 context
  316. dlt645_t *ctx = malloc(sizeof(dlt645_t));
  317. if (ctx == NULL)
  318. {
  319. printf("no memory for dlt645 ctx,malloc failed\r\n");
  320. return NULL;
  321. }
  322. //set default params
  323. dlt645_ctx_init_default(ctx);
  324. //set backend
  325. dlt645_set_backend(ctx, &serial_linux_backend);
  326. //hardware init
  327. if (serial_linux_port_init(ctx, params) < 0)
  328. {
  329. free(ctx);
  330. return NULL;
  331. }
  332. return ctx;
  333. }