|
42 | 42 | import time
|
43 | 43 | import struct
|
44 | 44 | import random
|
| 45 | +from micropython import const |
45 | 46 | from adafruit_ble import BLERadio
|
46 |
| -from adafruit_ble.advertising.adafruit import AdafruitRadio |
| 47 | +from adafruit_ble.advertising import Advertisement, LazyObjectField |
| 48 | +from adafruit_ble.advertising.standard import ManufacturerData, ManufacturerDataField |
47 | 49 |
|
48 | 50 |
|
49 | 51 | __version__ = "0.0.0-auto.0"
|
|
56 | 58 | #: Amount of time to advertise a message (in seconds).
|
57 | 59 | AD_DURATION = 0.5
|
58 | 60 |
|
| 61 | +_MANUFACTURING_DATA_ADT = const(0xff) |
| 62 | +_ADAFRUIT_COMPANY_ID = const(0x0822) |
| 63 | +_RADIO_DATA_ID = const(0x0001) # TODO: check this isn't already taken. |
| 64 | + |
| 65 | +class _RadioAdvertisement(Advertisement): |
| 66 | + """Broadcast arbitrary bytes as a radio message.""" |
| 67 | + prefix = struct.pack("<BBH", |
| 68 | + 0x3, |
| 69 | + 0xff, |
| 70 | + _ADAFRUIT_COMPANY_ID) |
| 71 | + manufacturer_data = LazyObjectField(ManufacturerData, |
| 72 | + "manufacturer_data", |
| 73 | + advertising_data_type=_MANUFACTURING_DATA_ADT, |
| 74 | + company_id=_ADAFRUIT_COMPANY_ID, |
| 75 | + key_encoding="<H") |
| 76 | + |
| 77 | + @classmethod |
| 78 | + def matches(cls, entry): |
| 79 | + if len(entry.advertisement_bytes) < 6: |
| 80 | + return False |
| 81 | + # Check the key position within the manufacturer data. We already know |
| 82 | + # prefix matches so we don't need to check it twice. |
| 83 | + return struct.unpack_from("<H", entry.advertisement_bytes, 5)[0] == _RADIO_DATA_ID |
| 84 | + |
| 85 | + @property |
| 86 | + def msg(self): |
| 87 | + if _RADIO_DATA_ID not in self.manufacturer_data.data: |
| 88 | + return b"" |
| 89 | + return self.manufacturer_data.data[_RADIO_DATA_ID] |
| 90 | + |
| 91 | + @msg.setter |
| 92 | + def msg(self, value): |
| 93 | + self.manufacturer_data.data[_RADIO_DATA_ID] = value |
59 | 94 |
|
60 | 95 | class Radio:
|
61 | 96 | """
|
@@ -111,18 +146,11 @@ def send_bytes(self, message):
|
111 | 146 | raise ValueError(
|
112 | 147 | "Message too long (max length = {})".format(MAX_LENGTH)
|
113 | 148 | )
|
114 |
| - advertisement = AdafruitRadio() |
115 |
| - # Channel byte. |
116 |
| - chan = struct.pack("<B", self._channel) |
117 |
| - # "Unique" id byte (to avoid duplication when receiving messages in |
118 |
| - # an AD_DURATION timeframe). |
119 |
| - uid = struct.pack("<B", self.uid) |
120 |
| - # Increment (and reset if needed) the uid. |
121 |
| - self.uid += 1 |
122 |
| - if self.uid > 255: |
123 |
| - self.uid = 0 |
| 149 | + advertisement = _RadioAdvertisement() |
124 | 150 | # Concatenate the bytes that make up the advertised message.
|
125 |
| - advertisement.msg = chan + uid + message |
| 151 | + advertisement.msg = struct.pack("<BB", self._channel, self.uid) + message |
| 152 | + |
| 153 | + self.uid = (self.uid + 1) % 255 |
126 | 154 | # Advertise (block) for AD_DURATION period of time.
|
127 | 155 | self.ble.start_advertising(advertisement)
|
128 | 156 | time.sleep(AD_DURATION)
|
@@ -158,7 +186,7 @@ def receive_full(self):
|
158 | 186 | """
|
159 | 187 | try:
|
160 | 188 | for entry in self.ble.start_scan(
|
161 |
| - AdafruitRadio, minimum_rssi=-255, timeout=1, extended=True |
| 189 | + _RadioAdvertisement, minimum_rssi=-255, timeout=1, extended=True |
162 | 190 | ):
|
163 | 191 | # Extract channel and unique message ID bytes.
|
164 | 192 | chan, uid = struct.unpack("<BB", entry.msg[:2])
|
|
0 commit comments