bridge.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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. if w == nil {
  67. return nil
  68. }
  69. b, err := w.String()
  70. if err != nil {
  71. return C.CString(fmt.Sprintf("an error occurred while calling the String() method of jsonrpc2.Response: %v", err))
  72. }
  73. return C.CString(b)
  74. }
  75. if role == "response" {
  76. err := Board.handleResponse(s)
  77. if err != nil {
  78. baseapp.Logger.Errorf("[%s] 解析数据板返回的命令应答时发生错误: %v", MODULE_NAME, err)
  79. }
  80. return nil
  81. }
  82. if role != "request" {
  83. w = jsonrpc2.BuildError(nil, jsonrpc2.ErrInvalidRequest, "")
  84. return wret()
  85. }
  86. r, err := jsonrpc2.ParseRequest(s)
  87. call := func(f func(*jsonrpc2.Request) (*jsonrpc2.Response, error)) *jsonrpc2.Response {
  88. w, e := f(r)
  89. if e != nil { // 调用本地RPC处理函数时发生错误
  90. return jsonrpc2.BuildError(r, jsonrpc2.ErrInternal, "")
  91. }
  92. return w
  93. }
  94. if err != nil {
  95. w = jsonrpc2.BuildError(nil, jsonrpc2.ErrParse, "")
  96. } else {
  97. switch r.Method {
  98. // 控制板查询数据板状态
  99. case "get_rtu_status":
  100. w = call(Board.getRTUStatus)
  101. // 控制板发送传感器数据
  102. case "send_sensor_data":
  103. w = call(Board.sendSensorData)
  104. // 控制板请求数据板拍照
  105. case "take_photo":
  106. w = call(Board.takePhoto)
  107. // 控制板发送预掉电通知
  108. case "power_down":
  109. w = call(Board.powerDown)
  110. default:
  111. w = jsonrpc2.BuildError(r, jsonrpc2.ErrMethodNotFound, "")
  112. }
  113. }
  114. return wret()
  115. }
  116. // 控制板查询数据板状态
  117. func (b *MCUCtrlBoard) getRTUStatus(r *jsonrpc2.Request) (*jsonrpc2.Response, error) {
  118. netst := "offline"
  119. if netmgrd.IsInetAvailable() {
  120. netst = "online"
  121. }
  122. systm := ""
  123. if netmgrd.IsSyncedNtpTime() {
  124. now := time.Now()
  125. systm = now.Format("2006-01-02 15:04:05")
  126. }
  127. wrkst := "idle"
  128. if GlobalWorkState.Get() != Idle {
  129. wrkst = "busy"
  130. }
  131. wjson := fmt.Sprintf(`{"netst":"%s","systm":"%s","wrkst":"%s"}`, netst, systm, wrkst)
  132. return jsonrpc2.BuildResult(r, wjson)
  133. }
  134. // 控制板发送传感器数据
  135. func (board *MCUCtrlBoard) sendSensorData(r *jsonrpc2.Request) (*jsonrpc2.Response, error) {
  136. GlobalWorkState.Add(SensorDataReceiving)
  137. defer GlobalWorkState.Remove(SensorDataReceiving)
  138. var dataOne EnvSensorData
  139. if err := json.Unmarshal([]byte(r.Params), &dataOne); err != nil {
  140. return jsonrpc2.BuildError(r, jsonrpc2.ErrInvalidParams, ""), nil
  141. }
  142. select {
  143. case board.OneEnvDataCh <- &dataOne:
  144. default:
  145. old := <-board.OneEnvDataCh // 弹出旧数据
  146. baseapp.Logger.Warnf("OneEnvData 通道满, 丢弃一条老数据: %s!", old.String())
  147. board.OneEnvDataCh <- &dataOne
  148. }
  149. return jsonrpc2.BuildResult(r, "success")
  150. }
  151. // 控制板请求数据板拍照
  152. func (board *MCUCtrlBoard) takePhoto(r *jsonrpc2.Request) (*jsonrpc2.Response, error) {
  153. select {
  154. case board.ReqTakePhoCh <- true:
  155. default:
  156. <-board.ReqTakePhoCh // 弹出旧数据
  157. board.ReqTakePhoCh <- true
  158. }
  159. return jsonrpc2.BuildResult(r, "success")
  160. }
  161. // 控制板发送预掉电通知
  162. func (board *MCUCtrlBoard) powerDown(r *jsonrpc2.Request) (*jsonrpc2.Response, error) {
  163. netst := "offline"
  164. if netmgrd.IsInetAvailable() {
  165. netst = "online"
  166. }
  167. systm := ""
  168. if netmgrd.IsSyncedNtpTime() {
  169. now := time.Now()
  170. systm = now.Format("2006-01-02 15:04:05")
  171. }
  172. wrkst := "idle"
  173. if GlobalWorkState.Get() != Idle {
  174. wrkst = "busy"
  175. } else {
  176. close(board.PwrWillOffCh)
  177. }
  178. wjson := fmt.Sprintf(`{"netst":"%s","systm":"%s","wrkst":"%s"}`, netst, systm, wrkst)
  179. return jsonrpc2.BuildResult(r, wjson)
  180. }
  181. var pendingRequests sync.Map // 存储所有待处理的请求ID和对应的应答通道
  182. // 发送请求, 并等待应答
  183. func (board *MCUCtrlBoard) sendRequest(req *jsonrpc2.Request, timeout int /*单位: ms*/) (*jsonrpc2.Response, error) {
  184. if req == nil || req.ID == nil {
  185. return nil, fmt.Errorf("invalid request or request ID")
  186. }
  187. id := *req.ID
  188. ch := make(chan *jsonrpc2.Response, 1)
  189. pendingRequests.Store(id, ch)
  190. defer pendingRequests.Delete(id)
  191. jsonStr, err := req.String()
  192. if err != nil {
  193. return nil, err
  194. }
  195. err = mcuCtrlBoard_SendCmd(jsonStr)
  196. if err != nil {
  197. return nil, err
  198. }
  199. timer := time.NewTimer(time.Duration(timeout) * time.Millisecond)
  200. defer timer.Stop()
  201. select {
  202. case resp := <-ch:
  203. return resp, nil
  204. case <-timer.C:
  205. return nil, fmt.Errorf("request %v timed out after %d ms", id, timeout)
  206. }
  207. }
  208. // 处理控制板返回的请求
  209. func (board *MCUCtrlBoard) handleResponse(jsonStr string) error {
  210. w, err := jsonrpc2.ParseResponse(jsonStr)
  211. if err != nil {
  212. return fmt.Errorf("an error occurred while parsing JSON-RPC response: %v", err)
  213. }
  214. if w.ID == nil {
  215. return nil
  216. }
  217. id := *w.ID
  218. v, ok := pendingRequests.Load(id)
  219. if !ok {
  220. return fmt.Errorf("orphan response id=%d, no pending request", id)
  221. }
  222. ch, ok := v.(chan *jsonrpc2.Response)
  223. if !ok {
  224. return fmt.Errorf("invalid response channel for id=%d", id)
  225. }
  226. select {
  227. case ch <- w:
  228. return nil
  229. default:
  230. return fmt.Errorf("response dropped for id=%d, channel not receiving", id)
  231. }
  232. }