mcu_ctrl_board.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #include "mcu_ctrl_board.h"
  2. #include "../../rtu_linux_modules/swapi/subjects/serial/serial.h"
  3. #include "lwjson/lwjson.h"
  4. // 模块名称
  5. static const char MODULE_NAME[] = "MCUCtrlBoard";
  6. // 定义与单片机进行通讯的结构体, 同时定义结构体对象
  7. typedef struct
  8. {
  9. void *h;
  10. lwjson_stream_parser_t parser;
  11. unsigned long jsonStartTick; // JSON数据包开始接收时的单调计时基准, 用于超时判断
  12. } SMCBCom;
  13. static SMCBCom s_myCom = { 0 };
  14. // 声明Go中处理串口请求并返回应答结果的函数(供C调用)
  15. extern char *RTU_JsonMsgProcCb(const char *jsonStr);
  16. // 接收处理来自MCU控制板的数据报文帧, 串口-数据回调
  17. static int comio_data_recv_proc(unsigned long wParam/*传递打开的串口句柄*/, unsigned long lParam/*保留暂未使用*/)
  18. {
  19. SMCBCom *pComIO = &s_myCom; void *pSerial = pComIO->h;
  20. const unsigned char *pRecvBuf = serial_get_recv_buffer(pSerial); int nRecvBytes = serial_get_recv_buffer_bytes(pSerial);
  21. const char *log_prefix = serial_get_log_prefix(pSerial); lwjsonr_t ret;
  22. ret = lwjson_stream_parse(&pComIO->parser, pRecvBuf[nRecvBytes - 1]); // 把串口数据逐字节的喂给解析器去解析
  23. switch(ret)
  24. {
  25. case lwjsonERRJSON: // 1, 无效的字符
  26. case lwjsonSTREAMWAITFIRSTCHAR: // 2, 等待首字符
  27. serial_printf_recv_buffer(pSerial, LEVEL_TRACE);
  28. sw_log_warn("[%s] %s discarding invalid JSON byte: 0x%02X(buffer length: %d)!", MODULE_NAME, log_prefix, pRecvBuf[0], nRecvBytes);
  29. serial_clear_recv_buffer(pSerial);
  30. break;
  31. case lwjsonSTREAMINPROG: // 3, 正在解析中
  32. if(0 == pComIO->jsonStartTick) xgettickcount(&pComIO->jsonStartTick);
  33. break;
  34. case lwjsonSTREAMDONE: // 4, 解析已完成
  35. sw_log_debug("[%s] %s received a request(%d bytes): %s", MODULE_NAME, log_prefix, nRecvBytes, pRecvBuf);
  36. char *pResponse = RTU_JsonMsgProcCb((const char *)pRecvBuf);
  37. if(pResponse)
  38. {
  39. int nRspBytes = strlen(pResponse);
  40. int sendBytes = serial_send_data(pSerial, (const unsigned char *)pResponse, nRspBytes);
  41. if(sendBytes == nRspBytes) sw_log_debug("[%s] %s sent a response(%d bytes): %s", MODULE_NAME, log_prefix, nRspBytes, pResponse);
  42. else sw_log_error("[%s] %s failed to send a response(%d bytes, ret=%d): %s!!", MODULE_NAME, log_prefix, nRspBytes, sendBytes, pResponse);
  43. free(pResponse); // 释放Go侧C.CString()分配的堆内存
  44. }
  45. pComIO->jsonStartTick = 0; serial_clear_recv_buffer(pSerial); lwjson_stream_reset(&pComIO->parser);
  46. break;
  47. case lwjsonERRMEM: // 5, 嵌套的太深("LWJSON_CFG_STREAM_STACK_SIZE")
  48. sw_log_error("[%s] %s parser stack overflow (ERRMEM), resetting parser!", MODULE_NAME, log_prefix);
  49. pComIO->jsonStartTick = 0; serial_clear_recv_buffer(pSerial); lwjson_stream_reset(&pComIO->parser);
  50. break;
  51. default: // 流式解析时, 其它的返回值, 都不应该出现
  52. sw_log_fatal("[%s] %s internal error, lwjson_stream_parse() returned: %d, data receive thread will exit!!!", MODULE_NAME, log_prefix, ret);
  53. return -1;
  54. }
  55. return 1;
  56. }
  57. // 接收处理来自MCU控制板的数据报文帧, 串口-空闲回调
  58. static int comio_data_idle_proc(unsigned long wParam/*传递打开的串口句柄*/, unsigned long lParam/*保留暂未使用*/)
  59. {
  60. SMCBCom *pComIO = &s_myCom; void *pSerial = pComIO->h;
  61. const unsigned char *pRecvBuf = serial_get_recv_buffer(pSerial); int nRecvBytes = serial_get_recv_buffer_bytes(pSerial);
  62. const char *log_prefix = serial_get_log_prefix(pSerial); unsigned long nowTick;
  63. xgettickcount(&nowTick);
  64. if(pComIO->jsonStartTick > 0 && (nowTick - pComIO->jsonStartTick) > 50/*空闲超时单位: ms*/)
  65. {
  66. sw_log_warn("[%s] %s timeout occurred while receiving a request(%d bytes): %s!", MODULE_NAME, log_prefix, nRecvBytes, pRecvBuf);
  67. pComIO->jsonStartTick = 0; serial_clear_recv_buffer(pSerial); lwjson_stream_reset(&pComIO->parser);
  68. }
  69. return 1;
  70. }
  71. // 打开与MCU控制板的串口通讯, 返回: 0成功, <0时失败
  72. int MCBComInit()
  73. {
  74. lwjson_stream_init(&s_myCom.parser, NULL);
  75. const char *serialName = "/dev/ttymxc2"; int baudrate = 115200;
  76. const char *parityCheck = "none"; // 无校检
  77. s_myCom.h = serial_open(serialName, baudrate, parityCheck, \
  78. comio_data_recv_proc, comio_data_idle_proc, NULL);
  79. if(!s_myCom.h)
  80. {
  81. sw_log_error("[%s] failed to open the \"%s:%d(%s parity)\" device!!", \
  82. MODULE_NAME, serialName, baudrate, parityCheck);
  83. MCBComExit(); return -1;
  84. }
  85. return 0;
  86. }
  87. // 关闭与MCU控制板的串口通讯, 返回: 0成功, <0时失败
  88. int MCBComExit()
  89. {
  90. if(s_myCom.h) serial_close(s_myCom.h, WAITTHRD_SAFEEXIT_TIMEOUT);
  91. memset(&s_myCom, 0, sizeof(s_myCom));
  92. return 0;
  93. }
  94. // 主动的发送指令给MCU控制板, 返回: 0成功, <0时失败
  95. int MCBComSendCmd(const char *cmd)
  96. {
  97. if(!s_myCom.h || !cmd) return -1;
  98. int nBytes = strlen(cmd);
  99. int ret = serial_send_data(s_myCom.h, (const unsigned char *)cmd, nBytes);
  100. if(ret != nBytes)
  101. {
  102. sw_log_error("[%s] failed to send a request(%d bytes, ret=%d): %s!!", MODULE_NAME, ret, nBytes, cmd);
  103. return -2;
  104. }
  105. sw_log_debug("[%s] sent a request(%d bytes): %s", MODULE_NAME, nBytes, cmd);
  106. return 0;
  107. }