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 checkMinewDeviceInfo(ad) { be = parseMinewDeviceInfo(ad) be.ID = id be.Name = id break } else if checkMinewAccData(ad) { 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", } } // Minew Battery level func checkMinewDeviceInfo(ad []byte) bool { if len(ad) >= 4 && len(ad) != 19 && ad[1] == 0x16 && ad[2] == 0xE1 && ad[3] == 0xFF { fmt.Println("Minew device info") return true } return false } func parseMinewDeviceInfo(ad []byte) model.BeaconEvent { fmt.Printf("ad: %x\n", ad) return model.BeaconEvent{ Battery: uint32(ad[6]), Type: "Minew B7", } } func checkMinewAccData(ad []byte) bool { if len(ad) == 19 && ad[1] == 0x16 && ad[2] == 0xE1 && ad[3] == 0xFF { fmt.Println("Minew Acc data") return true } return false } // func parseMinewAccData(ad []byte) model.BeaconEvent { // }