| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- package mcu_ctrl_board
- /*
- #include "mcu_ctrl_board.h"
- */
- import "C"
- import (
- "encoding/binary"
- "fmt"
- "strconv"
- "sync"
- "time"
- "unsafe"
- "hnyfkj.com.cn/rtu/bxs-sy/baseapp"
- )
- const (
- MODULE_NAME = "MCUCtrlBoard"
- )
- var (
- Board *MCUCtrlBoard
- once sync.Once
- )
- // 采集的环境数据
- type SensorEnvData struct { // 小端序
- Timestamp [4]byte // 时间戳(秒, 存在"2038-01-19 03:14:07 UTC"溢出风险)
- Temperature [2]byte // 温度(0.1°C)
- Humidity [2]byte // 湿度(0.1%RH)
- Illuminance [4]byte // 光照(lux)
- Voltage [2]byte // 电压(0.1V)
- }
- type EnvData = SensorEnvData
- // MCU 控制板对象
- type MCUCtrlBoard struct {
- EnvDataOneCh chan EnvData // 单条环境数据
- EnvDataGrpCh chan []EnvData // 一组环境数据
- ReqTakePhoCh chan bool // 请求开始拍照
- PwrWillOffCh chan struct{} // 通知即将掉电
- }
- // 初始化MCU控制板
- func ModuleInit() bool {
- once.Do(func() { // 只允许创建单一实例
- Board = &MCUCtrlBoard{
- EnvDataOneCh: make(chan EnvData, 1),
- EnvDataGrpCh: make(chan []EnvData, 1),
- ReqTakePhoCh: make(chan bool, 1),
- PwrWillOffCh: make(chan struct{}),
- }
- })
- err := loadCfgParams()
- if err != nil {
- baseapp.Logger.Errorf("[%s] 加载MCU运行参数配置项失败: %v!!", MODULE_NAME, err)
- return false
- }
- var ret int
- for range 5 {
- if baseapp.IsExit1() {
- return false
- }
- ret, err = mcuCtrlBoard_ComInit()
- if ret == -1 {
- time.Sleep(1 * time.Second)
- continue
- } else {
- break
- }
- }
- if err != nil {
- baseapp.Logger.Errorf("[%s] 初始化与MCU控制板通信失败: %v!!", MODULE_NAME, err)
- return false
- }
- return true
- }
- // 释放掉MCU控制板
- func ModuleExit() {
- mcuCtrlBoard_ComExit()
- }
- // 通知MCU准备掉电
- func NotifyPwrWillOff() <-chan struct{} {
- if Board == nil || Board.PwrWillOffCh == nil {
- return nil
- }
- return Board.PwrWillOffCh
- }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // 解析MCU发的数据
- func (d EnvData) parseFields() (tsVal uint32, tempVal int16, humVal uint16, illVal uint32, voltVal uint16) {
- tsVal = binary.LittleEndian.Uint32(d.Timestamp[:])
- tempVal = int16(binary.LittleEndian.Uint16(d.Temperature[:]))
- humVal = binary.LittleEndian.Uint16(d.Humidity[:])
- illVal = binary.LittleEndian.Uint32(d.Illuminance[:])
- voltVal = binary.LittleEndian.Uint16(d.Voltage[:])
- return
- }
- func (d EnvData) StringWithUnit() (ts, temp, hum, ill, volt string) {
- tsVal, tempVal, humVal, illVal, voltVal := d.parseFields()
- return fmt.Sprintf("%d", tsVal), fmt.Sprintf("%.1f°C", float32(tempVal)/10),
- fmt.Sprintf("%.1f%%RH", float32(humVal)/10), fmt.Sprintf("%dlux", illVal), fmt.Sprintf("%.1fV", float32(voltVal)/10)
- }
- func (d EnvData) StringWithoutUnit() (ts, temp, hum, ill, volt string) {
- tsVal, tempVal, humVal, illVal, voltVal := d.parseFields()
- return fmt.Sprintf("%d", tsVal), fmt.Sprintf("%.1f", float32(tempVal)/10),
- fmt.Sprintf("%.1f", float32(humVal)/10), fmt.Sprintf("%d", illVal), fmt.Sprintf("%.1f", float32(voltVal)/10)
- }
- func (d EnvData) LogString() string {
- ts, temp, hum, ill, volt := d.StringWithUnit()
- tsi, _ := strconv.ParseUint(ts, 10, 64)
- tss := time.Unix(int64(tsi), 0).Format("2006-01-02 15:04:05")
- return fmt.Sprintf("时间戳: %s(%s), 温度: %s, 湿度: %s, 光照: %s, 电压: %s", ts, tss, temp, hum, ill, volt)
- }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // 导出Go函数给C用
- //export RTU_SendGrpEnvData
- func RTU_SendGrpEnvData(pGrpData *C.SensorEnvData, cnt C.int) C.int {
- if Board == nil || Board.EnvDataGrpCh == nil || pGrpData == nil || cnt <= 0 {
- return -1
- }
- // 1, 映射C内存为Go切片(不拷贝)
- length := int(cnt)
- cArray := unsafe.Slice(pGrpData, length)
- // 2, 将C数组内容拷贝到Go的切片
- dataGrp := make([]EnvData, length)
- for i := 0; i < length; i++ {
- dataGrp[i] = *(*EnvData)(unsafe.Pointer(&cArray[i]))
- }
- // 3, 非阻塞的写入进通道(生产者)
- select {
- case Board.EnvDataGrpCh <- dataGrp:
- default:
- olds := <-Board.EnvDataGrpCh // 弹出旧数据
- for index, old := range olds {
- baseapp.Logger.Warnf("GropEnvData 通道满, 丢弃一组老数据: [%02d]: %s!", index+1, old.LogString())
- }
- Board.EnvDataGrpCh <- dataGrp
- }
- return 0
- }
- //export RTU_SendOneEnvData
- func RTU_SendOneEnvData(pOneData *C.SensorEnvData) C.int {
- if Board == nil || Board.EnvDataOneCh == nil || pOneData == nil {
- return -1
- }
- // 1, 拷贝C内存到Go结构体(值拷贝)
- dataOne := *(*EnvData)(unsafe.Pointer(pOneData))
- // 2, 非阻塞的写入进通道(生产者)
- select {
- case Board.EnvDataOneCh <- dataOne:
- default:
- old := <-Board.EnvDataOneCh // 弹出旧数据
- baseapp.Logger.Warnf("OneEnvData 通道满, 丢弃一条老数据: %s!", old.LogString())
- Board.EnvDataOneCh <- dataOne
- }
- return 0
- }
- //export RTU_RequestTakePhoto
- func RTU_RequestTakePhoto() C.int {
- if Board == nil || Board.ReqTakePhoCh == nil {
- return -1
- }
- select {
- case Board.ReqTakePhoCh <- true:
- default:
- <-Board.ReqTakePhoCh // 弹出旧数据
- Board.ReqTakePhoCh <- true
- }
- return 0
- }
- //export RTU_LoadMCUParamsCfg
- func RTU_LoadMCUParamsCfg() C.int {
- if Board == nil {
- return -1
- }
- err := loadCfgParams()
- if err != nil {
- baseapp.Logger.Errorf("[%s] 加载MCU运行参数配置项失败: %v!!", MODULE_NAME, err)
- return -2
- }
- return 0
- }
- //export RTU_NotifyPwrWillOff
- func RTU_NotifyPwrWillOff() C.int {
- if Board == nil || Board.PwrWillOffCh == nil {
- return -1
- }
- close(Board.PwrWillOffCh)
- return 0
- }
|