package lifx import ( "encoding/binary" "fmt" "git.aiterp.net/lucifer/new-server/internal/lerrors" "log" "net" ) func createPacket() Packet { p := make(Packet, 36) p.Reset() return p } type Packet []byte func (p *Packet) Reset() { p.ensureHeader() copy(*p, blankHeader) } func (p *Packet) Size() int { return int(binary.LittleEndian.Uint16((*p)[0:2])) } func (p *Packet) Protocol() int { return int(binary.LittleEndian.Uint16((*p)[2:3]) & 0b00001111_11111111) } func (p *Packet) SetTagged(v bool) { if v { (*p)[3] |= uint8(0b00100000) } else { (*p)[3] &= ^uint8(0b00100000) } } func (p *Packet) Source() uint32 { return binary.LittleEndian.Uint32((*p)[4:8]) } func (p *Packet) Target() net.HardwareAddr { return net.HardwareAddr((*p)[8:14]) } func (p *Packet) SetSource(v uint32) { binary.LittleEndian.PutUint32((*p)[4:8], v) } func (p *Packet) CopyTargetFrom(other Packet) { copy((*p)[8:14], other[8:14]) } func (p *Packet) SetTarget(v string) error { addr, err := net.ParseMAC(v) if err != nil { return err } if len(addr) != 6 { return lerrors.ErrInvalidAddress } copy((*p)[8:], addr) return nil } func (p *Packet) SetResRequired(v bool) { if v { (*p)[22] |= uint8(0b00000001) } else { (*p)[22] &= ^uint8(0b00000001) } } func (p *Packet) SetAckRequired(v bool) { if v { (*p)[22] |= uint8(0b00000010) } else { (*p)[22] &= ^uint8(0b00000010) } } func (p *Packet) Sequence() uint8 { return (*p)[23] } func (p *Packet) SetSequence(v uint8) { (*p)[23] = v } func (p *Packet) PacketType() uint16 { return binary.LittleEndian.Uint16((*p)[32:34]) } func (p *Packet) SetRawPayload(packetType uint16, data []byte) { p.ensureSize(36 + len(data)) copy((*p)[36:], data) binary.LittleEndian.PutUint16(*p, uint16(36+len(data))) binary.LittleEndian.PutUint16((*p)[32:34], packetType) } func (p *Packet) Payload() (res Payload, err error) { switch p.PacketType() { case 2: res = &GetService{} case 3: res = &StateService{} err = res.Decode((*p)[36:]) case 14: res = &GetHostFirmware{} case 15: res = &StateHostFirmware{} err = res.Decode((*p)[36:]) case 32: res = &GetVersion{} case 33: res = &StateVersion{} err = res.Decode((*p)[36:]) case 45: res = &Acknowledgement{} case 101: res = &GetColor{} case 102: res = &SetColor{} err = res.Decode((*p)[36:]) case 107: res = &LightState{} err = res.Decode((*p)[36:]) case 117: res = &SetLightPower{} err = res.Decode((*p)[36:]) default: err = lerrors.ErrUnrecognizedPacketType } if err != nil { res = nil } if res != nil && res.PacketType() != p.PacketType() { log.Println("BUG Incorrect packet type used in Packet.Payload") log.Println("BUG Payload Type:", p.PacketType()) log.Println("BUG Panic Packet Type:", res.PacketType()) log.Println("BUG Panic Payload:", res.String()) } return } func (p *Packet) SetPayload(payload Payload) { ackRequired, resRequired := payload.Flags() p.SetRawPayload(payload.PacketType(), payload.Encode()) p.SetAckRequired(ackRequired) p.SetResRequired(resRequired) } func (p *Packet) ensureHeader() { p.ensureSize(36) } func (p *Packet) ensureSize(size int) { if len(*p) < size { newData := make([]byte, size) copy(newData, *p) *p = newData } } type Payload interface { fmt.Stringer Decode(data []byte) error Encode() []byte PacketType() uint16 Flags() (ackRequired bool, resRequired bool) } var blankHeader = []byte{ 0x24, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }