|
- package utils
-
- import (
- "encoding/binary"
- "fmt"
-
- "github.com/AFASystems/presence/internal/pkg/model"
- )
-
- // ParseADFast efficiently parses Advertising Data structures
- // Returns slice of [startIndex, endIndex] pairs for each AD structure
- func ParseADFast(b []byte) [][2]int {
- var res [][2]int
- i := 0
-
- for i < len(b) {
- l := int(b[i])
- if l == 0 || i+1+l > len(b) {
- break
- }
-
- res = append(res, [2]int{i, i + 1 + l})
-
- i += 1 + l
- }
-
- return res
- }
-
- // RemoveFlagBytes removes Bluetooth advertising flag bytes if present
- // Some beacons include flag bytes as the first AD structure
- func RemoveFlagBytes(b []byte) []byte {
- if len(b) > 1 && b[1] == 0x01 {
- l := int(b[0])
- if 1+l <= len(b) {
- return b[1+l:]
- }
- }
- return b
- }
-
- // Generate event based on the Beacon type
- func LoopADStructures(b []byte, i [][2]int, id string) model.BeaconEvent {
- be := model.BeaconEvent{}
- for _, r := range i {
- ad := b[r[0]:r[1]]
- if !isValidADStructure(ad) {
- break
- }
- if checkIngics(ad) {
- be = parseIngicsState(ad)
- be.ID = id
- be.Name = id
- break
- } else if checkEddystoneTLM(ad) {
- be = parseEddystoneState(ad)
- be.ID = id
- be.Name = id
- break
- } else if checkMinewB7(ad) {
- fmt.Println("Minew B7 vendor format")
- break
- }
- }
-
- return be
- }
-
- // IsValidADStructure validates if an AD structure is well-formed
- func isValidADStructure(data []byte) bool {
- if len(data) < 2 {
- return false
- }
-
- length := int(data[0])
- return length > 0 && int(length)+1 <= len(data)
- }
-
- func checkIngics(ad []byte) bool {
- if len(ad) >= 6 &&
- ad[1] == 0xFF &&
- ad[2] == 0x59 &&
- ad[3] == 0x00 &&
- ad[4] == 0x80 &&
- ad[5] == 0xBC {
- return true
- }
-
- return false
- }
-
- func parseIngicsState(ad []byte) model.BeaconEvent {
- return model.BeaconEvent{
- Battery: uint32(binary.LittleEndian.Uint16(ad[6:8])),
- Event: int(ad[8]),
- Type: "Ingics",
- }
- }
-
- func checkEddystoneTLM(ad []byte) bool {
- if len(ad) >= 4 &&
- ad[1] == 0x16 &&
- ad[2] == 0xAA &&
- ad[3] == 0xFE &&
- ad[4] == 0x20 {
- return true
- }
-
- return false
- }
-
- func parseEddystoneState(ad []byte) model.BeaconEvent {
- return model.BeaconEvent{
- Battery: uint32(binary.BigEndian.Uint16(ad[6:8])),
- Type: "Eddystone",
- }
- }
-
- // I dont think this is always true, but for testing is ok
- func checkMinewB7(ad []byte) bool {
- if len(ad) >= 4 &&
- ad[1] == 0x16 &&
- ad[2] == 0xE1 &&
- ad[3] == 0xFF {
- return true
- }
-
- return false
- }
|