|
|
|
@@ -0,0 +1,137 @@ |
|
|
|
package main |
|
|
|
|
|
|
|
import ( |
|
|
|
"bytes" |
|
|
|
"encoding/binary" |
|
|
|
"encoding/json" |
|
|
|
"fmt" |
|
|
|
"io" |
|
|
|
"os" |
|
|
|
"sync" |
|
|
|
|
|
|
|
"github.com/AFASystems/presence/internal/pkg/model" |
|
|
|
) |
|
|
|
|
|
|
|
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 { |
|
|
|
return len(ad) >= c.Min && len(ad) <= c.Max && bytes.HasPrefix(ad, c.GetPatternBytes()) |
|
|
|
}, |
|
|
|
configs: c.Configs, |
|
|
|
} |
|
|
|
|
|
|
|
p.parserList = append(p.parserList, b) |
|
|
|
} |
|
|
|
|
|
|
|
func (b *beaconParser) Parse(ad []byte) (model.BeaconEvent, bool) { |
|
|
|
flag := false |
|
|
|
event := model.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 |
|
|
|
} |
|
|
|
|
|
|
|
func main() { |
|
|
|
parserRegistry := parserRegistry{ |
|
|
|
parserList: make([]beaconParser, 0), |
|
|
|
} |
|
|
|
seq := []byte{0x02, 0x01, 0x06, 0x64, 0x01, 0xF4, 0x00, 0x0A, 0xFF, 0x05} |
|
|
|
|
|
|
|
jsonFile, err := os.Open("configs.json") |
|
|
|
if err != nil { |
|
|
|
fmt.Println(err) |
|
|
|
} |
|
|
|
|
|
|
|
fmt.Println("succesfully opened json file") |
|
|
|
|
|
|
|
b, _ := io.ReadAll(jsonFile) |
|
|
|
var configs []config |
|
|
|
json.Unmarshal(b, &configs) |
|
|
|
for _, config := range configs { |
|
|
|
parserRegistry.Register(config.Name, config) |
|
|
|
} |
|
|
|
|
|
|
|
for _, parser := range parserRegistry.parserList { |
|
|
|
if parser.canParse(seq) { |
|
|
|
event, ok := parser.Parse(seq) |
|
|
|
if ok { |
|
|
|
fmt.Printf("Device: %s | Battery: %d%% | AccX: %d | AccY: %d | AccZ: %d\n", event.Type, event.Battery, event.AccX, event.AccY, event.AccZ) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fmt.Printf("configs: %+v\n", configs) |
|
|
|
jsonFile.Close() |
|
|
|
} |