package artnet import ( "encoding/binary" "errors" "slices" ) type ArtPollReply struct { IPAddress [4]uint8 Port uint16 VersInfo uint16 NetSwitch uint8 SubSwitch uint8 Oem uint16 UbeaVersion uint8 Status1 uint8 EstaMan uint16 PortName [18]uint8 LongName [64]uint8 NodeReport [64]uint8 NumPorts uint16 PortTypes [4]uint8 GoodInput [4]uint8 GoodOutputA [4]uint8 SwIn [4]uint8 SwOut [4]uint8 AcnPriority uint8 SwMacro uint8 SwRemote uint8 spare1 uint8 spare2 uint8 spare3 uint8 Style uint8 MAC [6]uint8 // TODO(jwetzell): support extended poll fields BindIp [4]uint8 BindIndex uint8 Status2 uint8 GoodOutputB [4]uint8 Status3 uint8 DefaultRespUID uint64 User uint16 RefreshRate uint8 BackgroundQueuePolicy uint8 filler [10]uint8 } func (ap *ArtPollReply) GetOpCode() uint16 { return OpPollReply } func (ap *ArtPollReply) UnmarshalBinary(data []byte) error { if len(data) < 207 { return errors.New("ArtPollReply packet must be at least 207 bytes long") } if !slices.Equal(ArtNetID[:], data[0:8]) { return errors.New("ID does not match Art-Net ID") } opCode := binary.LittleEndian.Uint16(data[8:10]) if opCode != OpPollReply { return errors.New("packet does not have the correct OpCode for an ArtPollReply packet") } ap.IPAddress[0] = data[10] ap.IPAddress[1] = data[11] ap.IPAddress[2] = data[12] ap.IPAddress[3] = data[13] ap.Port = binary.LittleEndian.Uint16(data[14:16]) ap.VersInfo = binary.BigEndian.Uint16(data[16:18]) ap.NetSwitch = data[18] ap.SubSwitch = data[19] ap.Oem = binary.BigEndian.Uint16(data[20:22]) ap.UbeaVersion = data[22] ap.Status1 = data[23] ap.EstaMan = binary.LittleEndian.Uint16(data[24:26]) copy(ap.PortName[:], data[26:44]) copy(ap.LongName[:], data[44:108]) copy(ap.NodeReport[:], data[108:172]) ap.NumPorts = binary.BigEndian.Uint16(data[172:174]) copy(ap.PortTypes[:], data[174:178]) copy(ap.GoodInput[:], data[178:182]) copy(ap.GoodOutputA[:], data[182:186]) copy(ap.SwIn[:], data[186:190]) copy(ap.SwOut[:], data[190:194]) ap.AcnPriority = data[194] ap.SwMacro = data[195] ap.SwRemote = data[196] ap.spare1 = data[197] ap.spare2 = data[198] ap.spare3 = data[199] ap.Style = data[200] copy(ap.MAC[:], data[201:207]) return nil } func (ap *ArtPollReply) MarshalBinary() ([]byte, error) { if ap.DefaultRespUID > 0xFFFFFFFFFFFF { return nil, errors.New("DefaultRespUID must not be greater than 281474976710655") } data := make([]byte, 8+230) copy(data[0:8], ArtNetID[:]) binary.LittleEndian.PutUint16(data[8:10], OpPollReply) data[10] = ap.IPAddress[0] data[11] = ap.IPAddress[1] data[12] = ap.IPAddress[2] data[13] = ap.IPAddress[3] binary.LittleEndian.PutUint16(data[14:16], ap.Port) binary.BigEndian.PutUint16(data[16:18], ap.VersInfo) data[18] = ap.NetSwitch data[19] = ap.SubSwitch binary.BigEndian.PutUint16(data[20:22], ap.Oem) data[22] = ap.UbeaVersion data[23] = ap.Status1 binary.LittleEndian.PutUint16(data[24:26], ap.EstaMan) copy(data[26:44], ap.PortName[:]) copy(data[44:108], ap.LongName[:]) copy(data[108:172], ap.NodeReport[:]) binary.BigEndian.PutUint16(data[172:174], ap.NumPorts) copy(data[174:178], ap.PortTypes[:]) copy(data[178:182], ap.GoodInput[:]) copy(data[182:186], ap.GoodOutputA[:]) copy(data[186:190], ap.SwIn[:]) copy(data[190:194], ap.SwOut[:]) data[194] = ap.AcnPriority data[195] = ap.SwMacro data[196] = ap.SwRemote data[197] = ap.spare1 data[198] = ap.spare2 data[199] = ap.spare3 data[200] = ap.Style copy(data[201:207], ap.MAC[:]) copy(data[207:211], ap.BindIp[:]) data[211] = ap.BindIndex data[212] = ap.Status2 copy(data[213:217], ap.GoodOutputB[:]) data[217] = ap.Status3 // DefaultRespUID is a 48-bit value, so we need to make sure we only write the lower 6 bytes data[218] = uint8(ap.DefaultRespUID >> 40) data[219] = uint8(ap.DefaultRespUID >> 32) data[220] = uint8(ap.DefaultRespUID >> 24) data[221] = uint8(ap.DefaultRespUID >> 16) data[222] = uint8(ap.DefaultRespUID >> 8) data[223] = uint8(ap.DefaultRespUID) binary.BigEndian.PutUint16(data[224:226], ap.User) data[226] = ap.RefreshRate data[227] = ap.BackgroundQueuePolicy copy(data[228:], ap.filler[:]) return data, nil }