mcu_ctrl_board.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. package mcu_ctrl_board
  2. /*
  3. #include "mcu_ctrl_board.h"
  4. */
  5. import "C"
  6. import (
  7. "encoding/binary"
  8. "fmt"
  9. "strconv"
  10. "sync"
  11. "time"
  12. "unsafe"
  13. "hnyfkj.com.cn/rtu/bxs-sy/baseapp"
  14. )
  15. const (
  16. MODULE_NAME = "MCUCtrlBoard"
  17. )
  18. var (
  19. Board *MCUCtrlBoard
  20. once sync.Once
  21. )
  22. // 采集的环境数据
  23. type SensorEnvData struct { // 小端序
  24. Timestamp [4]byte // 时间戳(秒, 存在"​​2038-01-19 03:14:07 UTC​​"溢出风险)
  25. Temperature [2]byte // 温度(0.1°C)
  26. Humidity [2]byte // 湿度(0.1%RH)
  27. Illuminance [4]byte // 光照(lux)
  28. Voltage [2]byte // 电压(0.1V)
  29. }
  30. type EnvData = SensorEnvData
  31. // MCU 控制板对象
  32. type MCUCtrlBoard struct {
  33. EnvDataOneCh chan EnvData // 单条环境数据
  34. EnvDataGrpCh chan []EnvData // 一组环境数据
  35. ReqTakePhoCh chan bool // 请求开始拍照
  36. PwrWillOffCh chan struct{} // 通知即将掉电
  37. }
  38. // 初始化MCU控制板
  39. func ModuleInit() bool {
  40. once.Do(func() { // 只允许创建单一实例
  41. Board = &MCUCtrlBoard{
  42. EnvDataOneCh: make(chan EnvData, 1),
  43. EnvDataGrpCh: make(chan []EnvData, 1),
  44. ReqTakePhoCh: make(chan bool, 1),
  45. PwrWillOffCh: make(chan struct{}),
  46. }
  47. })
  48. err := loadCfgParams()
  49. if err != nil {
  50. baseapp.Logger.Errorf("[%s] 加载MCU运行参数配置项失败: %v!!", MODULE_NAME, err)
  51. return false
  52. }
  53. var ret int
  54. for range 5 {
  55. if baseapp.IsExit1() {
  56. return false
  57. }
  58. ret, err = mcuCtrlBoard_ComInit()
  59. if ret == -1 {
  60. time.Sleep(1 * time.Second)
  61. continue
  62. } else {
  63. break
  64. }
  65. }
  66. if err != nil {
  67. baseapp.Logger.Errorf("[%s] 初始化与MCU控制板通信失败: %v!!", MODULE_NAME, err)
  68. }
  69. return true
  70. }
  71. // 释放掉MCU控制板
  72. func ModuleExit() {
  73. mcuCtrlBoard_ComExit()
  74. }
  75. // 通知MCU准备掉电
  76. func NotifyPwrWillOff() <-chan struct{} {
  77. if Board == nil || Board.PwrWillOffCh == nil {
  78. return nil
  79. }
  80. return Board.PwrWillOffCh
  81. }
  82. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  83. // 解析MCU发的数据
  84. func (d EnvData) parseFields() (tsVal uint32, tempVal int16, humVal uint16, illVal uint32, voltVal uint16) {
  85. tsVal = binary.LittleEndian.Uint32(d.Timestamp[:])
  86. tempVal = int16(binary.LittleEndian.Uint16(d.Temperature[:]))
  87. humVal = binary.LittleEndian.Uint16(d.Humidity[:])
  88. illVal = binary.LittleEndian.Uint32(d.Illuminance[:])
  89. voltVal = binary.LittleEndian.Uint16(d.Voltage[:])
  90. return
  91. }
  92. func (d EnvData) StringWithUnit() (ts, temp, hum, ill, volt string) {
  93. tsVal, tempVal, humVal, illVal, voltVal := d.parseFields()
  94. return fmt.Sprintf("%d", tsVal), fmt.Sprintf("%.1f°C", float32(tempVal)/10),
  95. fmt.Sprintf("%.1f%%RH", float32(humVal)/10), fmt.Sprintf("%dlux", illVal), fmt.Sprintf("%.1fV", float32(voltVal)/10)
  96. }
  97. func (d EnvData) StringWithoutUnit() (ts, temp, hum, ill, volt string) {
  98. tsVal, tempVal, humVal, illVal, voltVal := d.parseFields()
  99. return fmt.Sprintf("%d", tsVal), fmt.Sprintf("%.1f", float32(tempVal)/10),
  100. fmt.Sprintf("%.1f", float32(humVal)/10), fmt.Sprintf("%d", illVal), fmt.Sprintf("%.1f", float32(voltVal)/10)
  101. }
  102. func (d EnvData) LogString() string {
  103. ts, temp, hum, ill, volt := d.StringWithUnit()
  104. tsi, _ := strconv.ParseUint(ts, 10, 64)
  105. tss := time.Unix(int64(tsi), 0).Format("2006-01-02 15:04:05")
  106. return fmt.Sprintf("时间戳: %s(%s), 温度: %s, 湿度: %s, 光照: %s, 电压: %s", ts, tss, temp, hum, ill, volt)
  107. }
  108. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  109. // 导出Go函数给C用
  110. //export RTU_SendGrpEnvData
  111. func RTU_SendGrpEnvData(pGrpData *C.SensorEnvData, cnt C.int) C.int {
  112. if Board == nil || Board.EnvDataGrpCh == nil || pGrpData == nil || cnt <= 0 {
  113. return -1
  114. }
  115. // 1, 映射C内存为Go切片(不拷贝)
  116. length := int(cnt)
  117. cArray := unsafe.Slice(pGrpData, length)
  118. // 2, 将C数组内容拷贝到Go的切片
  119. dataGrp := make([]EnvData, length)
  120. for i := 0; i < length; i++ {
  121. dataGrp[i] = *(*EnvData)(unsafe.Pointer(&cArray[i]))
  122. }
  123. // 3, 非阻塞的写入进通道(生产者)
  124. select {
  125. case Board.EnvDataGrpCh <- dataGrp:
  126. default:
  127. olds := <-Board.EnvDataGrpCh // 弹出旧数据
  128. for index, old := range olds {
  129. baseapp.Logger.Warnf("GropEnvData 通道满, 丢弃一组老数据: [%02d]: %s!", index+1, old.LogString())
  130. }
  131. Board.EnvDataGrpCh <- dataGrp
  132. }
  133. return 0
  134. }
  135. //export RTU_SendOneEnvData
  136. func RTU_SendOneEnvData(pOneData *C.SensorEnvData) C.int {
  137. if Board == nil || Board.EnvDataOneCh == nil || pOneData == nil {
  138. return -1
  139. }
  140. // 1, 拷贝C内存到Go结构体(值拷贝)
  141. dataOne := *(*EnvData)(unsafe.Pointer(pOneData))
  142. // 2, 非阻塞的写入进通道(生产者)
  143. select {
  144. case Board.EnvDataOneCh <- dataOne:
  145. default:
  146. old := <-Board.EnvDataOneCh // 弹出旧数据
  147. baseapp.Logger.Warnf("OneEnvData 通道满, 丢弃一条老数据: %s!", old.LogString())
  148. Board.EnvDataOneCh <- dataOne
  149. }
  150. return 0
  151. }
  152. //export RTU_RequestTakePhoto
  153. func RTU_RequestTakePhoto() C.int {
  154. if Board == nil || Board.ReqTakePhoCh == nil {
  155. return -1
  156. }
  157. select {
  158. case Board.ReqTakePhoCh <- true:
  159. default:
  160. <-Board.ReqTakePhoCh // 弹出旧数据
  161. Board.ReqTakePhoCh <- true
  162. }
  163. return 0
  164. }
  165. //export RTU_LoadMCUParamsCfg
  166. func RTU_LoadMCUParamsCfg() C.int {
  167. if Board == nil {
  168. return -1
  169. }
  170. err := loadCfgParams()
  171. if err != nil {
  172. baseapp.Logger.Errorf("[%s] 加载MCU运行参数配置项失败: %v!!", MODULE_NAME, err)
  173. return -2
  174. }
  175. return 0
  176. }
  177. //export RTU_NotifyPwrWillOff
  178. func RTU_NotifyPwrWillOff() C.int {
  179. if Board == nil || Board.PwrWillOffCh == nil {
  180. return -1
  181. }
  182. close(Board.PwrWillOffCh)
  183. return 0
  184. }