package nvcs import ( "bytes" "encoding/binary" "encoding/hex" "encoding/json" "fmt" "io/ioutil" "net" "time" "gat1400Exchange/config" "gat1400Exchange/pkg/logger" "gat1400Exchange/rfid" "github.com/google/uuid" "golang.org/x/text/encoding/simplifiedchinese" "golang.org/x/text/transform" ) type a1SetFloorFrame struct { Header [16]byte // Fixed 16-byte header Command byte // 1 byte command MAC [6]byte // 6 bytes MAC address DataLength uint16 // 2 bytes data length Data []byte // Data area, length defined by DataLength Checksum uint16 // 2 bytes CRC16 checksum } // Convert frame to byte slice func (f *a1SetFloorFrame) toBytes(includeChecksum bool) []byte { buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, f.Header) binary.Write(buf, binary.LittleEndian, f.Command) binary.Write(buf, binary.LittleEndian, f.MAC) binary.Write(buf, binary.LittleEndian, f.DataLength) buf.Write(f.Data) if includeChecksum { binary.Write(buf, binary.LittleEndian, f.Checksum) } return buf.Bytes() } type a1ElevatorStatus struct { TotalFloors int `json:"TotalFloors"` Floor int `json:"Floor"` FloorName string `json:"FloorName"` RunDir int `json:"RunDir"` Speed string `json:"Speed"` } type a1Elevator struct { Name string `json:"Name"` IP string `json:"IP"` Status a1ElevatorStatus `json:"Status"` Alarm []interface{} `json:"Alarm"` // You might want to define a specific type for alarms } type a1ElevatorData struct { Elevator []a1Elevator `json:"Elevator"` } var gRunningCorrectTaskId string func a1CorrectFloor() { if gRunningCorrectTaskId != "" || config.RFIDConf.EPC == "" { return } taskId := uuid.New().String() gRunningCorrectTaskId = taskId rfidReader := rfid.NewReader(config.RFIDConf.DevName, 115200, 5) defer rfidReader.CloseSerial() err := rfidReader.OpenSerial() if err != nil { logger.Error(err.Error()) return } isFind, err := rfidReader.ScanSpecificEPC(config.RFIDConf.EPC, 5) if isFind && gRunningCorrectTaskId == taskId { frame := newA1SetFloorFrame(config.NVCSConf.Mac, config.RFIDConf.Position) address := "192.168.10.253:50000" err := a1SendFrame(frame, address) if err != nil { logger.Warn(err.Error()) } else { logger.Debug("The floor has been calibrated.") } } } func calculateCRC16(data []byte) uint16 { var crc16 uint16 = 0xFFFF for i := 0; i < len(data); i++ { crc16 ^= uint16(data[i]) for j := 0; j < 8; j++ { if crc16&0x0001 != 0 { crc16 >>= 1 crc16 ^= 0xA001 } else { crc16 >>= 1 } } } return crc16 } // Create a new frame based on provided data func newA1SetFloorFrame(macAddr string, floor uint8) *a1SetFloorFrame { b, err := hex.DecodeString(macAddr) if err != nil { return nil } if len(b) != 6 { return nil } var mac [6]byte copy(mac[:], b) //b, err = hex.DecodeString(floor) frame := &a1SetFloorFrame{ Header: [16]byte{0x45, 0x4c, 0x45, 0x56, 0x41, 0x54, 0x4f, 0x52, 0x2d, 0x53, 0x45, 0x4e, 0x53, 0x4f, 0x52, 0x00}, Command: 0x0c, MAC: mac, DataLength: 1, Data: []byte{floor}, } frame.Checksum = calculateCRC16(frame.toBytes(false)) // Calculate CRC without including the checksum itself return frame } func a1SendFrame(frame *a1SetFloorFrame, address string) error { conn, err := net.Dial("udp", address) if err != nil { return err } defer conn.Close() // Send frame _, err = conn.Write(frame.toBytes(true)) return err } // 对接网络视频字符叠加器,接收udp发送的楼层信息, 更新device地址 func a1UDPServer() { // 指定监听的端口 port := config.ServeConf.Port // 创建一个UDP地址 address, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%s", port)) if err != nil { logger.Error("Error resolving address:", err) return } // 创建一个UDP连接 conn, err := net.ListenUDP("udp", address) if err != nil { logger.Error("Error listening:", err) return } defer conn.Close() logger.Info("UDP server listening on port %s...", port) // 无限循环等待接收数据 for { // 创建一个缓冲区来存储接收的数据 buffer := make([]byte, 256) // 从连接中读取数据 numBytes, clientAddr, err := conn.ReadFromUDP(buffer) if err != nil { logger.Warn("Error reading from UDP connection:%s", err.Error()) continue } // 设备上传的中文数据为GBK编码, 转换为utf8 decoder := simplifiedchinese.GBK.NewDecoder() reader := transform.NewReader(bytes.NewReader(buffer[:numBytes]), decoder) decodedBytes, err := ioutil.ReadAll(reader) var data a1ElevatorData err = json.Unmarshal(decodedBytes, &data) if err != nil { logger.Warn("ElevatorData unmarshal error:%s", err.Error()) continue } logger.Debug("Received %d bytes from %s, %+v", numBytes, clientAddr, data) if len(data.Elevator) == 0 { continue } elevator := data.Elevator[0] // 程序部署在设备端, 字符叠加器上报的名称允许为空. 在云端, 名称必须与摄像机相同 if elevator.Name == "" { elevator.Name = "1" } var runState = ElevatorRunData{ Device: elevator.Name, Timestamp: time.Now().Unix(), Floor: elevator.Status.FloorName, RunState: elevator.Status.RunDir, } // correct floor when elevator stopped. //if elevator.Status.RunDir == 0 { // go A1CorrectFloor() //} else { // RunningCorrectTaskId = "" //} queue.put(runState) } }