mcu_ctrl_board.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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. return false
  69. }
  70. return true
  71. }
  72. // 释放掉MCU控制板
  73. func ModuleExit() {
  74. mcuCtrlBoard_ComExit()
  75. }
  76. // 通知MCU准备掉电
  77. func NotifyPwrWillOff() <-chan struct{} {
  78. if Board == nil || Board.PwrWillOffCh == nil {
  79. return nil
  80. }
  81. return Board.PwrWillOffCh
  82. }
  83. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  84. // 解析MCU发的数据
  85. func (d EnvData) parseFields() (tsVal uint32, tempVal int16, humVal uint16, illVal uint32, voltVal uint16) {
  86. tsVal = binary.LittleEndian.Uint32(d.Timestamp[:])
  87. tempVal = int16(binary.LittleEndian.Uint16(d.Temperature[:]))
  88. humVal = binary.LittleEndian.Uint16(d.Humidity[:])
  89. illVal = binary.LittleEndian.Uint32(d.Illuminance[:])
  90. voltVal = binary.LittleEndian.Uint16(d.Voltage[:])
  91. return
  92. }
  93. func (d EnvData) StringWithUnit() (ts, temp, hum, ill, volt string) {
  94. tsVal, tempVal, humVal, illVal, voltVal := d.parseFields()
  95. return fmt.Sprintf("%d", tsVal), fmt.Sprintf("%.1f°C", float32(tempVal)/10),
  96. fmt.Sprintf("%.1f%%RH", float32(humVal)/10), fmt.Sprintf("%dlux", illVal), fmt.Sprintf("%.1fV", float32(voltVal)/10)
  97. }
  98. func (d EnvData) StringWithoutUnit() (ts, temp, hum, ill, volt string) {
  99. tsVal, tempVal, humVal, illVal, voltVal := d.parseFields()
  100. return fmt.Sprintf("%d", tsVal), fmt.Sprintf("%.1f", float32(tempVal)/10),
  101. fmt.Sprintf("%.1f", float32(humVal)/10), fmt.Sprintf("%d", illVal), fmt.Sprintf("%.1f", float32(voltVal)/10)
  102. }
  103. func (d EnvData) LogString() string {
  104. ts, temp, hum, ill, volt := d.StringWithUnit()
  105. tsi, _ := strconv.ParseUint(ts, 10, 64)
  106. tss := time.Unix(int64(tsi), 0).Format("2006-01-02 15:04:05")
  107. return fmt.Sprintf("时间戳: %s(%s), 温度: %s, 湿度: %s, 光照: %s, 电压: %s", ts, tss, temp, hum, ill, volt)
  108. }
  109. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  110. // 导出Go函数给C用
  111. //export RTU_SendGrpEnvData
  112. func RTU_SendGrpEnvData(pGrpData *C.SensorEnvData, cnt C.int) C.int {
  113. if Board == nil || Board.EnvDataGrpCh == nil || pGrpData == nil || cnt <= 0 {
  114. return -1
  115. }
  116. // 1, 映射C内存为Go切片(不拷贝)
  117. length := int(cnt)
  118. cArray := unsafe.Slice(pGrpData, length)
  119. // 2, 将C数组内容拷贝到Go的切片
  120. dataGrp := make([]EnvData, length)
  121. for i := 0; i < length; i++ {
  122. dataGrp[i] = *(*EnvData)(unsafe.Pointer(&cArray[i]))
  123. }
  124. // 3, 非阻塞的写入进通道(生产者)
  125. select {
  126. case Board.EnvDataGrpCh <- dataGrp:
  127. default:
  128. olds := <-Board.EnvDataGrpCh // 弹出旧数据
  129. for index, old := range olds {
  130. baseapp.Logger.Warnf("GropEnvData 通道满, 丢弃一组老数据: [%02d]: %s!", index+1, old.LogString())
  131. }
  132. Board.EnvDataGrpCh <- dataGrp
  133. }
  134. return 0
  135. }
  136. //export RTU_SendOneEnvData
  137. func RTU_SendOneEnvData(pOneData *C.SensorEnvData) C.int {
  138. if Board == nil || Board.EnvDataOneCh == nil || pOneData == nil {
  139. return -1
  140. }
  141. // 1, 拷贝C内存到Go结构体(值拷贝)
  142. dataOne := *(*EnvData)(unsafe.Pointer(pOneData))
  143. // 2, 非阻塞的写入进通道(生产者)
  144. select {
  145. case Board.EnvDataOneCh <- dataOne:
  146. default:
  147. old := <-Board.EnvDataOneCh // 弹出旧数据
  148. baseapp.Logger.Warnf("OneEnvData 通道满, 丢弃一条老数据: %s!", old.LogString())
  149. Board.EnvDataOneCh <- dataOne
  150. }
  151. return 0
  152. }
  153. //export RTU_RequestTakePhoto
  154. func RTU_RequestTakePhoto() C.int {
  155. if Board == nil || Board.ReqTakePhoCh == nil {
  156. return -1
  157. }
  158. select {
  159. case Board.ReqTakePhoCh <- true:
  160. default:
  161. <-Board.ReqTakePhoCh // 弹出旧数据
  162. Board.ReqTakePhoCh <- true
  163. }
  164. return 0
  165. }
  166. //export RTU_LoadMCUParamsCfg
  167. func RTU_LoadMCUParamsCfg() C.int {
  168. if Board == nil {
  169. return -1
  170. }
  171. err := loadCfgParams()
  172. if err != nil {
  173. baseapp.Logger.Errorf("[%s] 加载MCU运行参数配置项失败: %v!!", MODULE_NAME, err)
  174. return -2
  175. }
  176. return 0
  177. }
  178. //export RTU_NotifyPwrWillOff
  179. func RTU_NotifyPwrWillOff() C.int {
  180. if Board == nil || Board.PwrWillOffCh == nil {
  181. return -1
  182. }
  183. close(Board.PwrWillOffCh)
  184. return 0
  185. }