27
27
28
28
import time
29
29
from random import randint
30
- from micropython import const
30
+
31
31
import adafruit_bus_device .spi_device
32
+ from micropython import const
33
+
32
34
from adafruit_tinylora .adafruit_tinylora_encryption import AES
33
35
36
+ try : # typing
37
+ from types import TracebackType
38
+ from typing import Optional , Type , Union
39
+
40
+ import busio
41
+ import digitalio
42
+ from typing_extensions import Self # Python <3.11
43
+ from typing_extensions import Annotated , TypeAlias
44
+
45
+ # type aliases
46
+ bytearray2 : TypeAlias = Annotated [bytearray , 2 ]
47
+ bytearray4 : TypeAlias = Annotated [bytearray , 4 ]
48
+ bytearray16 : TypeAlias = Annotated [bytearray , 16 ]
49
+
50
+ registeraddress : TypeAlias = Union [const , int ]
51
+ except ImportError :
52
+ pass
53
+
54
+
34
55
__version__ = "0.0.0+auto.0"
35
56
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_TinyLoRa.git"
36
57
70
91
class TTN :
71
92
"""TTN Class"""
72
93
73
- def __init__ (self , dev_address , net_key , app_key , country = "US" ):
94
+ def __init__ (
95
+ self ,
96
+ dev_address : bytearray4 ,
97
+ net_key : bytearray16 ,
98
+ app_key : bytearray16 ,
99
+ country : str = "US" ,
100
+ ):
74
101
"""Interface for TheThingsNetwork
75
102
:param bytearray dev_address: TTN Device Address.
76
103
:param bytearray net_key: TTN Network Key.
@@ -83,22 +110,22 @@ def __init__(self, dev_address, net_key, app_key, country="US"):
83
110
self .region = country
84
111
85
112
@property
86
- def country (self ):
113
+ def country (self ) -> str :
87
114
"""Returns the TTN Frequency Country."""
88
115
return self .region
89
116
90
117
@property
91
- def device_address (self ):
118
+ def device_address (self ) -> bytearray4 :
92
119
"""Returns the TTN Device Address."""
93
120
return self .dev_addr
94
121
95
122
@property
96
- def application_key (self ):
123
+ def application_key (self ) -> bytearray16 :
97
124
"""Returns the TTN Application Key."""
98
125
return self .app_key
99
126
100
127
@property
101
- def network_key (self ):
128
+ def network_key (self ) -> bytearray16 :
102
129
"""Returns the TTN Network Key."""
103
130
return self .net_key
104
131
@@ -108,10 +135,18 @@ class TinyLoRa:
108
135
"""TinyLoRa Interface"""
109
136
110
137
# SPI Write Buffer
111
- _BUFFER = bytearray (2 )
138
+ _BUFFER : bytearray2 = bytearray (2 )
112
139
113
140
# pylint: disable=too-many-arguments,invalid-name
114
- def __init__ (self , spi , cs , irq , rst , ttn_config , channel = None ):
141
+ def __init__ (
142
+ self ,
143
+ spi : busio .SPI ,
144
+ cs : digitalio .DigitalInOut ,
145
+ irq : digitalio .DigitalInOut ,
146
+ rst : digitalio .DigitalInOut ,
147
+ ttn_config : digitalio .DigitalInOut ,
148
+ channel : Optional [int ] = None ,
149
+ ):
115
150
"""Interface for a HopeRF RFM95/6/7/8(w) radio module. Sets module up for sending to
116
151
The Things Network.
117
152
@@ -141,13 +176,13 @@ def __init__(self, spi, cs, irq, rst, ttn_config, channel=None):
141
176
if self ._version != 18 :
142
177
raise TypeError ("Can not detect LoRa Module. Please check wiring!" )
143
178
# Set Frequency registers
144
- self ._rfm_msb = None
145
- self ._rfm_mid = None
146
- self ._rfm_lsb = None
179
+ self ._rfm_msb : Optional [ registeraddress ] = None
180
+ self ._rfm_mid : Optional [ registeraddress ] = None
181
+ self ._rfm_lsb : Optional [ registeraddress ] = None
147
182
# Set datarate registers
148
- self ._sf = None
149
- self ._bw = None
150
- self ._modemcfg = None
183
+ self ._sf : Optional [ registeraddress ] = None
184
+ self ._bw : Optional [ registeraddress ] = None
185
+ self ._modemcfg : Optional [ registeraddress ] = None
151
186
self .set_datarate ("SF7BW125" )
152
187
# Set regional frequency plan
153
188
# pylint: disable=import-outside-toplevel
@@ -201,13 +236,18 @@ def __init__(self, spi, cs, irq, rst, ttn_config, channel=None):
201
236
# Give the lora object ttn configuration
202
237
self ._ttn_config = ttn_config
203
238
204
- def __enter__ (self ):
239
+ def __enter__ (self ) -> Self :
205
240
return self
206
241
207
- def __exit__ (self , exception_type , exception_value , traceback ):
242
+ def __exit__ (
243
+ self ,
244
+ exception_type : Optional [Type [type ]],
245
+ exception_value : Optional [BaseException ],
246
+ traceback : Optional [TracebackType ],
247
+ ) -> None :
208
248
self .deinit ()
209
249
210
- def deinit (self ):
250
+ def deinit (self ) -> None :
211
251
"""Deinitializes the TinyLoRa object properties and pins."""
212
252
self ._irq = None
213
253
self ._rst = None
@@ -220,7 +260,9 @@ def deinit(self):
220
260
self ._bw = None
221
261
self ._modemcfg = None
222
262
223
- def send_data (self , data , data_length , frame_counter , timeout = 2 ):
263
+ def send_data (
264
+ self , data : bytearray , data_length : int , frame_counter : int , timeout : int = 2
265
+ ) -> None :
224
266
"""Function to assemble and send data
225
267
:param data: data to send
226
268
:param data_length: length of data to send
@@ -258,15 +300,17 @@ def send_data(self, data, data_length, frame_counter, timeout=2):
258
300
# recalculate packet length
259
301
lora_pkt_len += data_length
260
302
# Calculate MIC
261
- mic = bytearray (4 )
303
+ mic : bytearray4 = bytearray (4 )
262
304
mic = aes .calculate_mic (lora_pkt , lora_pkt_len , mic )
263
305
# load mic in package
264
306
lora_pkt [lora_pkt_len : lora_pkt_len + 4 ] = mic [0 :4 ]
265
307
# recalculate packet length (add MIC length)
266
308
lora_pkt_len += 4
267
309
self .send_packet (lora_pkt , lora_pkt_len , timeout )
268
310
269
- def send_packet (self , lora_packet , packet_length , timeout ):
311
+ def send_packet (
312
+ self , lora_packet : bytearray , packet_length : int , timeout : int
313
+ ) -> None :
270
314
"""Sends a LoRa packet using the RFM Module
271
315
:param bytearray lora_packet: assembled LoRa packet from send_data
272
316
:param int packet_length: length of LoRa packet to send
@@ -312,10 +356,11 @@ def send_packet(self, lora_packet, packet_length, timeout):
312
356
if timed_out :
313
357
raise RuntimeError ("Timeout during packet send" )
314
358
315
- def set_datarate (self , datarate ) :
359
+ def set_datarate (self , datarate : str ) -> None :
316
360
"""Sets the RFM Datarate
317
361
:param datarate: Bandwidth and Frequency Plan
318
362
"""
363
+ # TODO: Convert these to enum
319
364
data_rates = {
320
365
"SF7BW125" : (0x74 , 0x72 , 0x04 ),
321
366
"SF7BW250" : (0x74 , 0x82 , 0x04 ),
@@ -330,13 +375,15 @@ def set_datarate(self, datarate):
330
375
except KeyError as err :
331
376
raise KeyError ("Invalid or Unsupported Datarate." ) from err
332
377
333
- def set_channel (self , channel ) :
378
+ def set_channel (self , channel : int ) -> None :
334
379
"""Sets the RFM Channel (if single-channel)
335
380
:param int channel: Transmit Channel (0 through 7).
336
381
"""
337
382
self ._rfm_msb , self ._rfm_mid , self ._rfm_lsb = self ._frequencies [channel ]
338
383
339
- def _read_into (self , address , buf , length = None ):
384
+ def _read_into (
385
+ self , address : registeraddress , buf : bytearray2 , length : Optional [int ] = None
386
+ ) -> None :
340
387
"""Read a number of bytes from the specified address into the
341
388
provided buffer. If length is not specified (default) the entire buffer
342
389
will be filled.
@@ -353,14 +400,14 @@ def _read_into(self, address, buf, length=None):
353
400
device .write (self ._BUFFER , end = 1 )
354
401
device .readinto (buf , end = length )
355
402
356
- def _read_u8 (self , address ) :
403
+ def _read_u8 (self , address : registeraddress ) -> int :
357
404
"""Read a single byte from the provided address and return it.
358
405
:param bytearray address: Register Address.
359
406
"""
360
407
self ._read_into (address , self ._BUFFER , length = 1 )
361
408
return self ._BUFFER [0 ]
362
409
363
- def _write_u8 (self , address , val ) :
410
+ def _write_u8 (self , address : registeraddress , val : int ) -> None :
364
411
"""Writes to the RFM register given an address and data.
365
412
:param bytearray address: Register Address.
366
413
:param val: Data to write.
0 commit comments