From bfca923f838b52048215f80af3f66afefac741bf Mon Sep 17 00:00:00 2001 From: blazSmehov Date: Tue, 6 Jan 2026 13:41:09 +0100 Subject: [PATCH] feat: dynamic decoder testbench --- cmd/decoder-parser-testbench/configs.json | 22 ++++ cmd/decoder-parser-testbench/main.go | 137 ++++++++++++++++++++++ internal/pkg/model/types.go | 3 + 3 files changed, 162 insertions(+) create mode 100644 cmd/decoder-parser-testbench/configs.json create mode 100644 cmd/decoder-parser-testbench/main.go diff --git a/cmd/decoder-parser-testbench/configs.json b/cmd/decoder-parser-testbench/configs.json new file mode 100644 index 0000000..4070ba1 --- /dev/null +++ b/cmd/decoder-parser-testbench/configs.json @@ -0,0 +1,22 @@ +[ + { + "name": "config1", + "min": 10, + "max": 15, + "pattern": ["0x02", "0x01", "0x06"], + "configs": { + "battery": {"offset": 3, "length": 1}, + "accX": {"offset": 4, "length": 2, "order": "bigendian"} + } + }, + { + "name": "config2", + "min": 10, + "max": 15, + "pattern": ["0x02", "0x01", "0x06"], + "configs": { + "battery": {"offset": 3, "length": 1}, + "accY": {"offset": 4, "length": 2, "order": "bigendian"} + } + } +] \ No newline at end of file diff --git a/cmd/decoder-parser-testbench/main.go b/cmd/decoder-parser-testbench/main.go new file mode 100644 index 0000000..0e32de5 --- /dev/null +++ b/cmd/decoder-parser-testbench/main.go @@ -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() +} diff --git a/internal/pkg/model/types.go b/internal/pkg/model/types.go index 9fbae9a..4897625 100644 --- a/internal/pkg/model/types.go +++ b/internal/pkg/model/types.go @@ -110,6 +110,9 @@ type BeaconEvent struct { Type string Battery uint32 Event int + AccX int16 + AccY int16 + AccZ int16 } type HTTPResult struct {