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
}
