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.
191 lines
3.6 KiB
191 lines
3.6 KiB
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,
|
|
}
|