You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

105 lines
2.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package m9z
import (
"encoding/binary"
"fmt"
"github.com/gogf/gf/v2/errors/gerror"
"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 gerror.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
}