Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

160 linhas
2.9 KiB

  1. package utils
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "github.com/AFASystems/presence/internal/pkg/model"
  6. )
  7. // ParseADFast efficiently parses Advertising Data structures
  8. // Returns slice of [startIndex, endIndex] pairs for each AD structure
  9. func ParseADFast(b []byte) [][2]int {
  10. var res [][2]int
  11. i := 0
  12. for i < len(b) {
  13. l := int(b[i])
  14. if l == 0 || i+1+l > len(b) {
  15. break
  16. }
  17. res = append(res, [2]int{i, i + 1 + l})
  18. i += 1 + l
  19. }
  20. return res
  21. }
  22. // RemoveFlagBytes removes Bluetooth advertising flag bytes if present
  23. // Some beacons include flag bytes as the first AD structure
  24. func RemoveFlagBytes(b []byte) []byte {
  25. if len(b) > 1 && b[1] == 0x01 {
  26. l := int(b[0])
  27. if 1+l <= len(b) {
  28. return b[1+l:]
  29. }
  30. }
  31. return b
  32. }
  33. // Generate event based on the Beacon type
  34. func LoopADStructures(b []byte, i [][2]int, id string) model.BeaconEvent {
  35. be := model.BeaconEvent{}
  36. for _, r := range i {
  37. ad := b[r[0]:r[1]]
  38. if !isValidADStructure(ad) {
  39. break
  40. }
  41. if checkIngics(ad) {
  42. be = parseIngicsState(ad)
  43. be.ID = id
  44. be.Name = id
  45. break
  46. } else if checkEddystoneTLM(ad) {
  47. be = parseEddystoneState(ad)
  48. be.ID = id
  49. be.Name = id
  50. break
  51. } else if checkMinewDeviceInfo(ad) {
  52. be = parseMinewDeviceInfo(ad)
  53. be.ID = id
  54. be.Name = id
  55. break
  56. } else if checkMinewAccData(ad) {
  57. break
  58. }
  59. }
  60. return be
  61. }
  62. // IsValidADStructure validates if an AD structure is well-formed
  63. func isValidADStructure(data []byte) bool {
  64. if len(data) < 2 {
  65. return false
  66. }
  67. length := int(data[0])
  68. return length > 0 && int(length)+1 <= len(data)
  69. }
  70. func checkIngics(ad []byte) bool {
  71. if len(ad) >= 6 &&
  72. ad[1] == 0xFF &&
  73. ad[2] == 0x59 &&
  74. ad[3] == 0x00 &&
  75. ad[4] == 0x80 &&
  76. ad[5] == 0xBC {
  77. return true
  78. }
  79. return false
  80. }
  81. func parseIngicsState(ad []byte) model.BeaconEvent {
  82. return model.BeaconEvent{
  83. Battery: uint32(binary.LittleEndian.Uint16(ad[6:8])),
  84. Event: int(ad[8]),
  85. Type: "Ingics",
  86. }
  87. }
  88. func checkEddystoneTLM(ad []byte) bool {
  89. if len(ad) >= 4 &&
  90. ad[1] == 0x16 &&
  91. ad[2] == 0xAA &&
  92. ad[3] == 0xFE &&
  93. ad[4] == 0x20 {
  94. return true
  95. }
  96. return false
  97. }
  98. func parseEddystoneState(ad []byte) model.BeaconEvent {
  99. return model.BeaconEvent{
  100. Battery: uint32(binary.BigEndian.Uint16(ad[6:8])),
  101. Type: "Eddystone",
  102. }
  103. }
  104. // Minew Battery level
  105. func checkMinewDeviceInfo(ad []byte) bool {
  106. if len(ad) >= 4 &&
  107. len(ad) != 19 &&
  108. ad[1] == 0x16 &&
  109. ad[2] == 0xE1 &&
  110. ad[3] == 0xFF {
  111. fmt.Println("Minew device info")
  112. return true
  113. }
  114. return false
  115. }
  116. func parseMinewDeviceInfo(ad []byte) model.BeaconEvent {
  117. fmt.Printf("ad: %x\n", ad)
  118. return model.BeaconEvent{
  119. Battery: uint32(ad[6]),
  120. Type: "Minew B7",
  121. }
  122. }
  123. func checkMinewAccData(ad []byte) bool {
  124. if len(ad) == 19 &&
  125. ad[1] == 0x16 &&
  126. ad[2] == 0xE1 &&
  127. ad[3] == 0xFF {
  128. fmt.Println("Minew Acc data")
  129. return true
  130. }
  131. return false
  132. }
  133. // func parseMinewAccData(ad []byte) model.BeaconEvent {
  134. // }