|
|
package m9z
|
|
|
|
|
|
import (
|
|
|
"encoding/binary"
|
|
|
"fmt"
|
|
|
"github.com/towgo/towgo/errors/terror"
|
|
|
"math"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
type LgnLatData struct {
|
|
|
Lgn float64 // 经度
|
|
|
Lat float64 // 纬度
|
|
|
Loc *time.Location
|
|
|
}
|
|
|
|
|
|
// 经纬度参数
|
|
|
func LgnLatRead(deviceId string) (*LgnLatData, error) {
|
|
|
|
|
|
ll := new(LgnLatData)
|
|
|
cmd, err := ReadCmd(deviceId, lgnLat, "读取经纬度参数")
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
data := cmd.Data
|
|
|
lgn := float64(binary.LittleEndian.Uint32(data[0:4])) / 1000000
|
|
|
lat := float64(binary.LittleEndian.Uint32(data[4:8])) / 1000000
|
|
|
loc := float64(binary.LittleEndian.Uint32(data[8:len(data)])) / 1000000
|
|
|
ll.Lgn = lgn
|
|
|
ll.Lat = lat
|
|
|
timezone, err := FloatToTimezone(loc)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
ll.Loc = timezone
|
|
|
|
|
|
return ll, nil
|
|
|
}
|
|
|
func LgnLatWrite(deviceId string, data *LgnLatData) error {
|
|
|
// 将浮点型经纬度转换为字节编码(兼容原Read逻辑)
|
|
|
buf := make([]byte, 12)
|
|
|
|
|
|
// 1. 处理经度(4字节)
|
|
|
lgnInt := uint32(math.Round(data.Lgn * 1000000))
|
|
|
binary.LittleEndian.PutUint32(buf[0:4], lgnInt)
|
|
|
|
|
|
// 2. 处理纬度(4字节)
|
|
|
latInt := uint32(math.Round(data.Lat * 1000000))
|
|
|
binary.LittleEndian.PutUint32(buf[4:8], latInt)
|
|
|
|
|
|
// 3. 处理时区(4字节)
|
|
|
// 从time.Location解析出UTC偏移小时数(含小数)
|
|
|
offsetHours, err := getTimezoneOffset(data.Loc)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
offsetInt := uint32(math.Round(offsetHours * 1000000))
|
|
|
binary.LittleEndian.PutUint32(buf[8:12], offsetInt)
|
|
|
writeResp, err := WriteCmd(deviceId, lgnLat, buf, "写入经纬度参数")
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
if !writeResp.Success {
|
|
|
return terror.New("设置失败")
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// 从time.Location中解析UTC偏移小时数(支持正负)
|
|
|
func getTimezoneOffset(loc *time.Location) (float64, error) {
|
|
|
// 任取一个时间点计算偏移(固定时区偏移不会变化)
|
|
|
t := time.Date(2023, 1, 1, 0, 0, 0, 0, loc)
|
|
|
_, offsetSec := t.Zone()
|
|
|
|
|
|
// 转换为小时(含小数)
|
|
|
offsetHours := float64(offsetSec) / 3600.0
|
|
|
if offsetHours < -12 || offsetHours > 14 {
|
|
|
return 0, fmt.Errorf("invalid timezone offset: %f", offsetHours)
|
|
|
}
|
|
|
return offsetHours, nil
|
|
|
}
|
|
|
|
|
|
// FloatToTimezone 将float64时区值转换为 *time.Location
|
|
|
// 输入示例: 8.0 → UTC+8, -5.5 → UTC-5:30
|
|
|
func FloatToTimezone(offset float64) (*time.Location, error) {
|
|
|
// 验证范围 (-12.0 到 +14.0)
|
|
|
if offset < -12.0 || offset > 14.0 {
|
|
|
return nil, fmt.Errorf("时区偏移量超出有效范围 (-12.0 到 +14.0)")
|
|
|
}
|
|
|
|
|
|
// 分解小时和分钟
|
|
|
hours := int(math.Floor(offset))
|
|
|
minutes := int(math.Round((offset - float64(hours)) * 60))
|
|
|
|
|
|
// 处理负数情况
|
|
|
if offset < 0 {
|
|
|
minutes = -minutes
|
|
|
}
|
|
|
|
|
|
// 创建固定时区
|
|
|
name := fmt.Sprintf("UTC%+03d:%02d", hours, minutes)
|
|
|
return time.FixedZone(name, hours*3600+minutes*60), nil
|
|
|
}
|