bridge.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // Author: NiuJiuRu
  2. // Email: niujiuru@qq.com
  3. // Date: 2025-11-20
  4. package mcu_ctrl_board
  5. /*
  6. #include "mcu_ctrl_board.h"
  7. */
  8. import "C"
  9. import (
  10. "encoding/json"
  11. "fmt"
  12. "sync"
  13. "time"
  14. "unsafe"
  15. "hnyfkj.com.cn/rtu/linux/baseapp"
  16. "hnyfkj.com.cn/rtu/linux/netmgrd"
  17. "hnyfkj.com.cn/rtu/linux/utils/jsonrpc2"
  18. )
  19. // 打开与MCU控制板的串口通讯
  20. func mcuCtrlBoard_ComInit() (int, error) {
  21. ret := int(C.MCBComInit())
  22. if ret != 0 {
  23. return ret, fmt.Errorf("an error occurred while calling the C.MCBComInit function(%d)", ret)
  24. }
  25. return 0, nil
  26. }
  27. // 关闭与MCU控制板的串口通讯
  28. func mcuCtrlBoard_ComExit() error {
  29. ret := int(C.MCBComExit())
  30. if ret != 0 {
  31. return fmt.Errorf("an error occurred while calling the C.MCBComExit function(%d)", ret)
  32. }
  33. return nil
  34. }
  35. // 主动的发送指令给MCU控制板
  36. func mcuCtrlBoard_SendCmd(cmd string) error {
  37. cstr := C.CString(cmd)
  38. defer C.free(unsafe.Pointer(cstr))
  39. ret := int(C.MCBComSendCmd(cstr))
  40. if ret != 0 {
  41. return fmt.Errorf("an error occurred while calling the C.MCBComSendCmd function(%d)", ret)
  42. }
  43. return nil
  44. }
  45. // 判断输入字符串是请求/应答
  46. func detectJsonRole(jsonStr string) string {
  47. var obj map[string]json.RawMessage
  48. if json.Unmarshal([]byte(jsonStr), &obj) != nil {
  49. return "invalid"
  50. }
  51. switch {
  52. case obj["method"] != nil:
  53. return "request"
  54. case obj["result"] != nil || obj["error"] != nil:
  55. return "response"
  56. default:
  57. return "unknown"
  58. }
  59. }
  60. //export RTU_JsonMsgProcCb
  61. func RTU_JsonMsgProcCb(jsonStr *C.char) *C.char {
  62. s := C.GoString(jsonStr)
  63. role := detectJsonRole(s)
  64. var w *jsonrpc2.Response
  65. wret := func() *C.char {
  66. b, err := w.String()
  67. if err != nil {
  68. return C.CString(fmt.Sprintf("an error occurred while calling the String() method of jsonrpc2.Response: %v", err))
  69. }
  70. return C.CString(b)
  71. }
  72. if role == "response" {
  73. err := Board.handleResponse(s)
  74. if err != nil {
  75. baseapp.Logger.Errorf("[%s] 解析数据板发送的命令应答时发生错误: %v", MODULE_NAME, err)
  76. }
  77. return nil
  78. }
  79. if role != "request" {
  80. w = jsonrpc2.BuildError(nil, jsonrpc2.ErrInvalidRequest, "")
  81. return wret()
  82. }
  83. r, err := jsonrpc2.ParseRequest(s)
  84. call := func(f func(*jsonrpc2.Request) (*jsonrpc2.Response, error)) *jsonrpc2.Response {
  85. w, e := f(r)
  86. if e != nil { // 调用本地RPC处理函数时发生错误
  87. return jsonrpc2.BuildError(r, jsonrpc2.ErrInternal, "")
  88. }
  89. return w
  90. }
  91. if err != nil {
  92. w = jsonrpc2.BuildError(nil, jsonrpc2.ErrParse, "")
  93. } else {
  94. switch r.Method {
  95. // 控制板查询数据板状态
  96. case "get_rtu_status":
  97. w = call(Board.getRTUStatus)
  98. // 控制板发送传感器数据
  99. case "send_sensor_data":
  100. w = call(Board.sendSensorData)
  101. // 控制板请求数据板拍照
  102. case "take_photo":
  103. w = call(Board.takePhoto)
  104. // 控制板发送预掉电通知
  105. case "power_down":
  106. w = call(Board.powerDown)
  107. default:
  108. w = jsonrpc2.BuildError(r, jsonrpc2.ErrMethodNotFound, "")
  109. }
  110. }
  111. return wret()
  112. }
  113. // 控制板查询数据板状态
  114. func (b *MCUCtrlBoard) getRTUStatus(r *jsonrpc2.Request) (*jsonrpc2.Response, error) {
  115. netst := "offline"
  116. if netmgrd.IsInetAvailable() {
  117. netst = "online"
  118. }
  119. systm := ""
  120. if netmgrd.IsSyncedNtpTime() {
  121. now := time.Now()
  122. systm = now.Format("2006-01-02 15:04:05")
  123. }
  124. wrkst := "idle"
  125. if GlobalWorkState.Get() != Idle {
  126. wrkst = "busy"
  127. }
  128. wjson := fmt.Sprintf(`{"netst":"%s","systm":"%s","wrkst":"%s"}`, netst, systm, wrkst)
  129. return jsonrpc2.BuildResult(r, wjson)
  130. }
  131. // 控制板发送传感器数据
  132. func (board *MCUCtrlBoard) sendSensorData(r *jsonrpc2.Request) (*jsonrpc2.Response, error) {
  133. GlobalWorkState.Add(SensorDataReceiving)
  134. defer GlobalWorkState.Remove(SensorDataReceiving)
  135. var dataOne EnvSensorData
  136. if err := json.Unmarshal([]byte(r.Params), &dataOne); err != nil {
  137. return jsonrpc2.BuildError(r, jsonrpc2.ErrInvalidParams, ""), nil
  138. }
  139. select {
  140. case board.OneEnvDataCh <- &dataOne:
  141. default:
  142. old := <-board.OneEnvDataCh // 弹出旧数据
  143. baseapp.Logger.Warnf("OneEnvData 通道满, 丢弃一条老数据: %s!", old.String())
  144. board.OneEnvDataCh <- &dataOne
  145. }
  146. return jsonrpc2.BuildResult(r, "success")
  147. }
  148. // 控制板请求数据板拍照
  149. func (board *MCUCtrlBoard) takePhoto(r *jsonrpc2.Request) (*jsonrpc2.Response, error) {
  150. select {
  151. case board.ReqTakePhoCh <- true:
  152. default:
  153. <-board.ReqTakePhoCh // 弹出旧数据
  154. board.ReqTakePhoCh <- true
  155. }
  156. return jsonrpc2.BuildResult(r, "success")
  157. }
  158. // 控制板发送预掉电通知
  159. func (board *MCUCtrlBoard) powerDown(r *jsonrpc2.Request) (*jsonrpc2.Response, error) {
  160. netst := "offline"
  161. if netmgrd.IsInetAvailable() {
  162. netst = "online"
  163. }
  164. systm := ""
  165. if netmgrd.IsSyncedNtpTime() {
  166. now := time.Now()
  167. systm = now.Format("2006-01-02 15:04:05")
  168. }
  169. wrkst := "idle"
  170. if GlobalWorkState.Get() != Idle {
  171. wrkst = "busy"
  172. } else {
  173. close(board.PwrWillOffCh)
  174. }
  175. wjson := fmt.Sprintf(`{"netst":"%s","systm":"%s","wrkst":"%s"}`, netst, systm, wrkst)
  176. return jsonrpc2.BuildResult(r, wjson)
  177. }
  178. var pendingRequests sync.Map // 存储所有待处理的请求ID和对应的应答通道
  179. // 发送请求, 并等待应答
  180. func (board *MCUCtrlBoard) SendRequest(req *jsonrpc2.Request, timeout int /*单位: ms*/) (*jsonrpc2.Response, error) {
  181. if req == nil || req.ID == nil {
  182. return nil, fmt.Errorf("invalid request or request ID")
  183. }
  184. id := *req.ID
  185. ch := make(chan *jsonrpc2.Response, 1)
  186. pendingRequests.Store(id, ch)
  187. defer pendingRequests.Delete(id)
  188. jsonStr, err := req.String()
  189. if err != nil {
  190. return nil, err
  191. }
  192. err = mcuCtrlBoard_SendCmd(jsonStr)
  193. if err != nil {
  194. return nil, err
  195. }
  196. timer := time.NewTimer(time.Duration(timeout) * time.Millisecond)
  197. defer timer.Stop()
  198. select {
  199. case resp := <-ch:
  200. return resp, nil
  201. case <-timer.C:
  202. return nil, fmt.Errorf("request %v timed out after %d ms", id, timeout)
  203. }
  204. }
  205. // 处理控制板返回的请求
  206. func (board *MCUCtrlBoard) handleResponse(jsonStr string) error {
  207. w, err := jsonrpc2.ParseResponse(jsonStr)
  208. if err != nil {
  209. return fmt.Errorf("an error occurred while parsing JSON-RPC response: %v", err)
  210. }
  211. if w.ID == nil {
  212. return nil
  213. }
  214. id := *w.ID
  215. v, ok := pendingRequests.Load(id)
  216. if !ok {
  217. return fmt.Errorf("orphan response id=%d, no pending request", id)
  218. }
  219. ch, ok := v.(chan *jsonrpc2.Response)
  220. if !ok {
  221. return fmt.Errorf("invalid response channel for id=%d", id)
  222. }
  223. select {
  224. case ch <- w:
  225. return nil
  226. default:
  227. return fmt.Errorf("response dropped for id=%d, channel not receiving", id)
  228. }
  229. }