153 lines
3.6 KiB
Go
153 lines
3.6 KiB
Go
package bacnet
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
)
|
|
|
|
type ObjectID uint32
|
|
|
|
const (
|
|
OID_ANY ObjectID = 0x023fffff
|
|
)
|
|
|
|
type PropertyID byte
|
|
|
|
const (
|
|
PID_OID PropertyID = 75
|
|
PID_VENDOR_NUMBER PropertyID = 0x78
|
|
PID_VENDOR_NAME PropertyID = 0x79
|
|
PID_FIRMWARE_REVISION PropertyID = 0x2c
|
|
PID_APPLICATION_SOFTWARE_REVISION PropertyID = 0x0c
|
|
PID_OBJECT_NAME PropertyID = 0x4d
|
|
PID_MODEL_NAME PropertyID = 0x46
|
|
PID_DESCRIPTION PropertyID = 0x1c
|
|
PID_LOCATION PropertyID = 0x3a
|
|
)
|
|
|
|
type ReadProperty struct {
|
|
Object ObjectID `json:"object"`
|
|
Property PropertyID `json:"property"`
|
|
}
|
|
|
|
func (rp *ReadProperty) Marshal() ([]byte, error) {
|
|
buf := new(bytes.Buffer)
|
|
buf.WriteByte(0x0c)
|
|
if err := binary.Write(buf, binary.BigEndian, uint32(rp.Object)); err != nil {
|
|
return nil, err
|
|
}
|
|
buf.WriteByte(0x19)
|
|
buf.WriteByte(byte(rp.Property))
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
func (rp *ReadProperty) Unmarshal(b []byte) (leftovers []byte, err error) {
|
|
buf := bytes.NewBuffer(b)
|
|
leftovers = b
|
|
if oidContextTag, _ := buf.ReadByte(); oidContextTag != 0x0c {
|
|
return b, errInvalidPacket
|
|
}
|
|
var oid uint32
|
|
if err = binary.Read(buf, binary.BigEndian, &oid); err != nil {
|
|
return
|
|
}
|
|
rp.Object = ObjectID(oid)
|
|
if pidContextTag, _ := buf.ReadByte(); pidContextTag != 0x19 {
|
|
return b, errInvalidPacket
|
|
}
|
|
var pid byte
|
|
if pid, err = buf.ReadByte(); err != nil {
|
|
return
|
|
}
|
|
rp.Property = PropertyID(pid)
|
|
bytesRead := len(b) - buf.Len()
|
|
return b[bytesRead:], nil
|
|
}
|
|
|
|
func readInstanceNumber(b []byte) (leftovers []byte, instanceNumber uint32, err error) {
|
|
buf := bytes.NewBuffer(b)
|
|
leftovers = b
|
|
var openByte, appByte, closeByte byte
|
|
if openByte, err = buf.ReadByte(); openByte != 0x3e {
|
|
return
|
|
}
|
|
if appByte, err = buf.ReadByte(); appByte != 0xc4 {
|
|
return
|
|
}
|
|
if err = binary.Read(buf, binary.BigEndian, &instanceNumber); err != nil {
|
|
return
|
|
}
|
|
if closeByte, err = buf.ReadByte(); closeByte != 0x3f {
|
|
return
|
|
}
|
|
bytesRead := len(b) - buf.Len()
|
|
leftovers = b[bytesRead:]
|
|
instanceNumber &= 0x0003ffff
|
|
return
|
|
}
|
|
|
|
func readVendorID(b []byte) (leftovers []byte, vendorID uint16, err error) {
|
|
buf := bytes.NewBuffer(b)
|
|
leftovers = b
|
|
var openByte, appByte, closeByte byte
|
|
if openByte, err = buf.ReadByte(); openByte != 0x3e {
|
|
return
|
|
}
|
|
if appByte, err = buf.ReadByte(); appByte != 0x22 && appByte != 0x21 {
|
|
return
|
|
}
|
|
if appByte == 0x22 {
|
|
if err = binary.Read(buf, binary.BigEndian, &vendorID); err != nil {
|
|
return
|
|
}
|
|
} else {
|
|
var vendorIDByte byte
|
|
if err = binary.Read(buf, binary.BigEndian, &vendorIDByte); err != nil {
|
|
return
|
|
}
|
|
vendorID = uint16(vendorIDByte)
|
|
}
|
|
if closeByte, err = buf.ReadByte(); closeByte != 0x3f {
|
|
return
|
|
}
|
|
bytesRead := len(b) - buf.Len()
|
|
leftovers = b[bytesRead:]
|
|
return
|
|
}
|
|
|
|
func readStringProperty(b []byte) (leftovers []byte, value string, err error) {
|
|
buf := bytes.NewBuffer(b)
|
|
leftovers = b
|
|
var openByte, appByte, closeByte, lengthByte byte
|
|
if openByte, err = buf.ReadByte(); openByte != 0x3e {
|
|
return
|
|
}
|
|
if appByte, err = buf.ReadByte(); appByte&0xF8 != 0x70 {
|
|
return
|
|
}
|
|
lengthBits := appByte & 0x07
|
|
if lengthBits == 5 {
|
|
if lengthByte, err = buf.ReadByte(); err != nil {
|
|
return
|
|
}
|
|
} else {
|
|
lengthByte = lengthBits
|
|
}
|
|
propertyBytes := make([]byte, lengthByte)
|
|
var n int
|
|
if n, err = buf.Read(propertyBytes); err != nil {
|
|
return
|
|
}
|
|
if n != int(lengthByte) || lengthByte < 1 {
|
|
err = errBACNetPacketTooShort
|
|
return
|
|
}
|
|
value = string(propertyBytes[1:])
|
|
if closeByte, err = buf.ReadByte(); closeByte != 0x3f {
|
|
return
|
|
}
|
|
bytesRead := len(b) - buf.Len()
|
|
leftovers = b[bytesRead:]
|
|
return
|
|
}
|