package model import ( "bytes" "encoding/binary" "fmt" "sync" ) type ParserConfig struct { Length int `json:"length"` Offset int `json:"offset"` Order string `json:"order"` } type BeaconParser struct { Name string CanParse func([]byte) bool configs map[string]ParserConfig } type ParserRegistry struct { ParserList []BeaconParser rw sync.RWMutex } type Config struct { Name string `json:"name"` Min int `json:"min"` Max int `json:"max"` Pattern []string `json:"pattern"` Configs map[string]ParserConfig `json:"configs"` } func (pc ParserConfig) GetOrder() binary.ByteOrder { if pc.Order == "bigendian" { return binary.BigEndian } return binary.LittleEndian } func (p *ParserRegistry) Register(name string, c Config) { p.rw.Lock() defer p.rw.Unlock() b := BeaconParser{ Name: name, CanParse: func(ad []byte) bool { if len(ad) < 2 { return false } return len(ad) >= c.Min && len(ad) <= c.Max && bytes.HasPrefix(ad[1:], c.GetPatternBytes()) }, configs: c.Configs, } fmt.Printf("registered beacon parser: %+v\n", b) p.ParserList = append(p.ParserList, b) } func (b *BeaconParser) Parse(ad []byte) (BeaconEvent, bool) { flag := false event := BeaconEvent{Type: b.Name} if cfg, ok := b.configs["battery"]; ok { event.Battery = uint32(b.extract(ad, cfg)) flag = true } if cfg, ok := b.configs["accX"]; ok { event.AccX = int16(b.extract(ad, cfg)) flag = true } if cfg, ok := b.configs["accY"]; ok { event.AccY = int16(b.extract(ad, cfg)) flag = true } if cfg, ok := b.configs["accZ"]; ok { event.AccZ = int16(b.extract(ad, cfg)) flag = true } return event, flag } func (b *BeaconParser) extract(ad []byte, pc ParserConfig) uint16 { if len(ad) < pc.Offset+pc.Length { return 0 } data := ad[pc.Offset : pc.Offset+pc.Length] if pc.Length == 1 { return uint16(data[0]) } return pc.GetOrder().Uint16(data) } func (c Config) GetPatternBytes() []byte { res := make([]byte, len(c.Pattern)) for i, s := range c.Pattern { fmt.Sscanf(s, "0x%02x", &res[i]) } return res }