11
11
import machine
12
12
import time
13
13
import _thread
14
+ import struct
14
15
15
16
16
- class Def :
17
+ class LoRaE220JPUnit :
17
18
# Baud Rate Values
18
- BAUD_1200 = 0b000
19
- BAUD_2400 = 0b001
20
- BAUD_4800 = 0b010
21
- BAUD_9600 = 0b011
22
- BAUD_19200 = 0b100
23
- BAUD_38400 = 0b101
24
- BAUD_57600 = 0b110
25
- BAUD_115200 = 0b111
19
+ BAUD_1200 = 0b0000_0000
20
+ BAUD_2400 = 0b0010_0000
21
+ BAUD_4800 = 0b0100_0000
22
+ BAUD_9600 = 0b0110_0000
23
+ BAUD_19200 = 0b1000_0000
24
+ BAUD_38400 = 0b1010_0000
25
+ BAUD_57600 = 0b1100_0000
26
+ BAUD_115200 = 0b1110_0000
26
27
27
28
# Data Rate Values
28
- BW125K_SF5 = 0b00000
29
- BW125K_SF6 = 0b00100
30
- BW125K_SF7 = 0b01000
31
- BW125K_SF8 = 0b01100
32
- BW125K_SF9 = 0b10000
33
- BW250K_SF5 = 0b00001
34
- BW250K_SF6 = 0b00101
35
- BW250K_SF7 = 0b01001
36
- BW250K_SF8 = 0b01101
37
- BW250K_SF9 = 0b10001
38
- BW250K_SF10 = 0b10101
39
- BW500K_SF5 = 0b00010
40
- BW500K_SF6 = 0b00110
41
- BW500K_SF7 = 0b01010
42
- BW500K_SF8 = 0b01110
43
- BW500K_SF9 = 0b10010
44
- BW500K_SF10 = 0b10110
45
- BW500K_SF11 = 0b11010
29
+ BW125K_SF5 = 0b0000_0000
30
+ BW125K_SF6 = 0b0000_0100
31
+ BW125K_SF7 = 0b0000_1000
32
+ BW125K_SF8 = 0b0000_1100
33
+ BW125K_SF9 = 0b0001_0000
34
+ BW250K_SF5 = 0b0000_0001
35
+ BW250K_SF6 = 0b0000_0101
36
+ BW250K_SF7 = 0b0000_1001
37
+ BW250K_SF8 = 0b0000_1101
38
+ BW250K_SF9 = 0b0001_0001
39
+ BW250K_SF10 = 0b0001_0101
40
+ BW500K_SF5 = 0b0000_0010
41
+ BW500K_SF6 = 0b0000_0110
42
+ BW500K_SF7 = 0b0000_1010
43
+ BW500K_SF8 = 0b0000_1110
44
+ BW500K_SF9 = 0b0001_0010
45
+ BW500K_SF10 = 0b0001_0110
46
+ BW500K_SF11 = 0b0001_1010
46
47
47
48
# Subpacket Size Values
48
- SUBPACKET_200_BYTE = 0b00
49
- SUBPACKET_128_BYTE = 0b01
50
- SUBPACKET_64_BYTE = 0b10
51
- SUBPACKET_32_BYTE = 0b11
49
+ SUBPACKET_200_BYTE = 0b0000_0000
50
+ SUBPACKET_128_BYTE = 0b0100_0000
51
+ SUBPACKET_64_BYTE = 0b1000_0000
52
+ SUBPACKET_32_BYTE = 0b1100_0000
52
53
53
54
# RSSI Ambient Noise Flag Values
54
- RSSI_AMBIENT_NOISE_ENABLE = 0b1
55
- RSSI_AMBIENT_NOISE_DISABLE = 0b0
55
+ RSSI_AMBIENT_NOISE_ENABLE = 0b0010_0000
56
+ RSSI_AMBIENT_NOISE_DISABLE = 0b0000_0000
56
57
57
58
# Transmitting Power Values
58
- TX_POWER_13dBm = 0b01
59
- TX_POWER_7dBm = 0b10
60
- TX_POWER_0dBm = 0b11
59
+ TX_POWER_13dBm = 0b0000_0000
60
+ TX_POWER_12dBm = 0b0000_0001
61
+ TX_POWER_7dBm = 0b0000_0010
62
+ TX_POWER_0dBm = 0b0000_0011
61
63
62
64
# RSSI Byte Flag Values
63
- RSSI_BYTE_ENABLE = 0b1
64
- RSSI_BYTE_DISABLE = 0b0
65
+ RSSI_BYTE_ENABLE = 0b1000_0000
66
+ RSSI_BYTE_DISABLE = 0b0000_0000
65
67
66
68
# Transmission Method Type Values
67
- UART_TT_MODE = 0b0
68
- UART_P2P_MODE = 0b1
69
+ UART_TT_MODE = 0b0000_0000
70
+ UART_P2P_MODE = 0b0100_0000
69
71
70
72
# LBT Flag Values
71
- LBT_ENABLE = 0b1
72
- LBT_DISABLE = 0b0
73
+ # LBT_ENABLE = 0b0001_0000
74
+ # LBT_DISABLE = 0b0000_0000
73
75
74
76
# WOR Cycle Values
75
- WOR_500MS = 0b000
76
- WOR_1000MS = 0b001
77
- WOR_1500MS = 0b010
78
- WOR_2000MS = 0b011
79
-
77
+ WOR_500MS = 0b0000_0000
78
+ WOR_1000MS = 0b0000_0001
79
+ WOR_1500MS = 0b0000_0010
80
+ WOR_2000MS = 0b0000_0011
81
+ WOR_2500MS = 0b0000_0100
82
+ WOR_3000MS = 0b0000_0101
80
83
81
- class LoRaE220JPUnit :
82
84
def __init__ (self , port , port_id = 1 ) -> None :
83
85
# print('Port: ', port)
84
86
self .uart = machine .UART (port_id , tx = port [1 ], rx = port [0 ])
85
87
self .uart .init (9600 , bits = 0 , parity = None , stop = 1 , rxbuf = 1024 )
86
88
self .recv_running = False
87
89
self .receive_callback = None
90
+ self ._TXD_BUFFER = bytearray (200 )
91
+ self ._RXD_BUFFER = bytearray (200 )
92
+ self .max_len = 200
93
+ self .rssi_byte_flag = self .RSSI_BYTE_DISABLE
88
94
89
- def _conf_range (self , target , min , max ):
95
+ def _conf_range (self , target , min , max ) -> bool :
90
96
return min <= target <= max
91
97
92
98
def setup (
93
99
self ,
94
100
own_address = 0 ,
95
101
own_channel = 0 ,
96
102
encryption_key = 0x2333 ,
97
- air_data_rate = Def . BW125K_SF9 ,
98
- subpacket_size = Def . SUBPACKET_200_BYTE ,
99
- rssi_ambient_noise_flag = Def . RSSI_AMBIENT_NOISE_ENABLE ,
100
- transmitting_power = Def . TX_POWER_13dBm ,
101
- rssi_byte_flag = Def . RSSI_BYTE_ENABLE ,
102
- transmission_method_type = Def . UART_P2P_MODE ,
103
- lbt_flag = Def . LBT_DISABLE ,
104
- wor_cycle = Def . WOR_2000MS ,
105
- ):
103
+ air_data_rate = 0b0000_0010 , # BW500K_SF5
104
+ subpacket_size = 0b0000_0000 , # SUBPACKET_200_BYTE
105
+ rssi_ambient_noise_flag = 0b0000_0000 , # RSSI_AMBIENT_NOISE_DISABLE
106
+ transmitting_power = 0b0000_0000 , # TX_POWER_13dBm
107
+ rssi_byte_flag = 0b0000_0000 , # RSSI_BYTE_DISABLE
108
+ transmission_method_type = 0b0000_0000 , # UART_TT_MODE
109
+ lbt_flag = 0b0000_0000 , # LBT_DISABLE
110
+ wor_cycle = 0b0000_0011 , # WOR_2000MS
111
+ ) -> bool :
106
112
if not self ._conf_range (own_channel , 0 , 30 ):
107
113
return False
108
114
109
- self .subpacket_size = subpacket_size
110
- self .max_len = 0
111
- if self .subpacket_size == Def .SUBPACKET_128_BYTE :
115
+ if subpacket_size == self .SUBPACKET_128_BYTE :
112
116
self .max_len = 128
113
- elif self . subpacket_size == Def .SUBPACKET_64_BYTE :
117
+ elif subpacket_size == self .SUBPACKET_64_BYTE :
114
118
self .max_len = 64
115
- elif self . subpacket_size == Def .SUBPACKET_32_BYTE :
119
+ elif subpacket_size == self .SUBPACKET_32_BYTE :
116
120
self .max_len = 32
117
121
else :
118
122
self .max_len = 200
119
123
120
- command = [ 0xC0 , 0x00 , 0x08 ]
121
- ADDH = own_address >> 8
122
- ADDL = own_address & 0xFF
123
- command . extend ([ ADDH , ADDL ] )
124
+ # Configuration
125
+ struct . pack_into ( ">B" , self . _TXD_BUFFER , 0 , 0xC0 )
126
+ struct . pack_into ( ">B" , self . _TXD_BUFFER , 1 , 0x00 )
127
+ struct . pack_into ( ">B" , self . _TXD_BUFFER , 2 , 0x08 )
124
128
125
- REG0 = ( Def . BAUD_9600 << 5 ) | air_data_rate
126
- command . append ( REG0 )
129
+ # Register Address 00H, 01H
130
+ struct . pack_into ( ">H" , self . _TXD_BUFFER , 3 , own_address )
127
131
128
- REG1 = (subpacket_size << 6 ) | (rssi_ambient_noise_flag << 5 ) | transmitting_power
129
- command .append (REG1 )
132
+ # Register Address 02H
133
+ REG0 = self .BAUD_9600 | air_data_rate
134
+ struct .pack_into (">B" , self ._TXD_BUFFER , 5 , REG0 )
130
135
131
- command .append (own_channel )
136
+ # Register Address 03H
137
+ REG1 = subpacket_size | rssi_ambient_noise_flag | transmitting_power
138
+ struct .pack_into (">B" , self ._TXD_BUFFER , 6 , REG1 )
132
139
133
- REG3 = (
134
- (rssi_byte_flag << 7 ) | (transmission_method_type << 6 ) | (lbt_flag << 4 ) | wor_cycle
135
- )
136
- command .append (REG3 )
140
+ # Register Address 04H
141
+ struct .pack_into (">B" , self ._TXD_BUFFER , 7 , own_channel )
137
142
138
- CRYPT_H = encryption_key >> 8
139
- CRYPT_L = encryption_key & 0xFF
140
- command .extend ([CRYPT_H , CRYPT_L ])
143
+ # Register Address 05H
144
+ self .rssi_byte_flag = rssi_byte_flag
145
+ REG3 = self .rssi_byte_flag | transmission_method_type | wor_cycle
146
+ struct .pack_into (">B" , self ._TXD_BUFFER , 8 , REG3 )
141
147
142
- self .uart .write (bytes (command ))
148
+ # Register Address 06H, 07H
149
+ struct .pack_into (">H" , self ._TXD_BUFFER , 9 , encryption_key )
143
150
151
+ command = memoryview (self ._TXD_BUFFER [0 :11 ])
152
+ self .uart .write (command )
144
153
time .sleep_ms (100 ) # wait for response
145
154
146
155
response = []
@@ -154,68 +163,73 @@ def setup(
154
163
return False
155
164
return True
156
165
157
- def _recvCallback (self ):
166
+ def _recv_task (self ) -> None :
158
167
response = bytes ()
159
168
rssi = 0
160
169
_ = self .uart .read ()
161
170
while self .recv_running :
162
- if self .uart .any ():
163
- response += self .uart .read ()
164
- elif len (response ) > 0 :
165
- time .sleep_ms (10 )
166
- if not self .uart .any ():
167
- rssi = int (response [- 1 ]) - 256
168
- self .receive_callback (response [:- 1 ], rssi )
169
- response = bytes ()
171
+ response , rssi = self .receive ()
172
+ if len (response ):
173
+ self .receive_callback (response , rssi )
170
174
time .sleep_ms (10 )
171
175
172
- def receiveNoneBlock (self , receive_callback ) :
176
+ def receive_none_block (self , receive_callback : function ) -> None :
173
177
if not self .recv_running :
174
178
self .recv_running = True
175
179
self .receive_callback = receive_callback
176
- _thread .start_new_thread (self ._recvCallback , ())
180
+ # FIXME: Threads cannot be automatically destroyed when the
181
+ # application is interrupted.
182
+ _thread .start_new_thread (self ._recv_task , ())
183
+
184
+ def receiveNoneBlock (self , receive_callback : function ) -> None :
185
+ return self .receive_none_block (receive_callback )
177
186
178
- def stopReceive (self ):
187
+ def stop_receive (self ) -> None :
179
188
self .recv_running = False
180
189
time .sleep_ms (50 )
181
190
self .receive_callback = None
182
191
183
- def receive (self , timeout = 1000 ):
192
+ def stopReceive (self ) -> None :
193
+ return self .stop_receive ()
194
+
195
+ def receive (self , timeout = 1000 ) -> tuple [bytes , int ]:
184
196
start = time .ticks_ms ()
197
+ read_length = 0
185
198
response = bytes ()
186
- rssi = 0
199
+ rssi = 1
187
200
while True :
188
201
if time .ticks_ms () - start > timeout :
189
202
break
190
203
191
204
if self .uart .any ():
192
- response += self .uart .read ()
193
-
194
- elif len (response ) > 0 :
205
+ read_length += self .uart .readinto (self ._RXD_BUFFER )
206
+ elif read_length > 0 :
195
207
time .sleep_ms (10 )
196
208
if not self .uart .any ():
197
- rssi = int (response [- 1 ]) - 256
209
+ RXD_BUFFER = memoryview (self ._RXD_BUFFER [0 :read_length ])
210
+ if self .rssi_byte_flag == self .RSSI_BYTE_ENABLE :
211
+ response , rssi = struct .unpack_from (
212
+ "<%dsB" % (read_length - 1 ), RXD_BUFFER
213
+ )
214
+ rssi = rssi - 256
215
+ else :
216
+ response = struct .unpack_from ("<%ds" % read_length , RXD_BUFFER )
198
217
break
199
218
time .sleep_ms (10 )
200
- return response [:- 1 ], rssi
201
-
202
- def send (self , target_address , target_channel , send_data ):
203
- if type (send_data ) is str :
204
- send_data = send_data .encode ("utf-8" )
205
-
206
- if type (send_data ) is list :
207
- send_data = bytearray (send_data )
219
+ return response , rssi
208
220
221
+ def send (self , target_address : int , target_channel : int , send_data : bytes | str ) -> bool :
209
222
if len (send_data ) > self .max_len : # Adjust based on allowed packet size
210
223
print ("ERROR: Length of send_data over %d bytes." % self .max_len )
211
224
return False
212
225
213
- target_address_H = target_address >> 8
214
- target_address_L = target_address & 0xFF
215
-
216
- frame = bytearray ([target_address_H , target_address_L , target_channel ])
217
- frame .extend (send_data )
218
-
219
- self .uart .write (frame )
226
+ FRAME = memoryview (self ._TXD_BUFFER [0 : 3 + len (send_data )])
227
+ struct .pack_into (">HB" , FRAME , 0 , target_address , target_channel )
228
+ if type (send_data ) is str :
229
+ struct .pack_into ("%ds" % len (send_data ), FRAME , 3 , send_data )
230
+ else :
231
+ for i in range (len (send_data )):
232
+ FRAME [3 + i ] = send_data [i ]
233
+ self .uart .write (FRAME )
220
234
221
235
return True
0 commit comments