forked from mayeranalytics/pySX127x
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbeacon_on_MAC.py
More file actions
220 lines (170 loc) · 8.28 KB
/
beacon_on_MAC.py
File metadata and controls
220 lines (170 loc) · 8.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
#!/usr/bin/env python2.7
""" Beacon Class """
""" Thomas Verbeke - thomas.verbeke@vub.ac.be
Based on LoRaMAC
Send a LoRaMAC frame and open a window for receiving the ACK.
Retry after x seconds
Tested with Embed LoRa Module (SX1276 Semtech chip)
"""
import time
from math import ceil, floor
from time import sleep
from SX127x.LoRa import *
from LoRaMAC import LoRaMAC
BOARD.setup()
""" 868 ISM BANDS
BAND / DutyCycle / MaxPower / Channel Configuration Options / LoRaWAN use
============================================================================
h1.2 / 1% / 14 dBm / 15 x 125 or 10x 250 or 4x500 / 5X125 kHz
h1.4 / 1% / 14 dBm / 3x 125 or 1x250 or 1x 500** / 3X125 or 2x125 and 1x250 kHz
h1.5 / 0.1% / 14 dBm / 2x 125 or 1x250 / 1XFSK
h1.6 / 10% / 27 dBm / 1x 125 / Reception Window channel
h1.7 / 100% / 7 dBm / 1x 125 / not used
Band h1.6 is used as the BEACON channel or reception channel
Band h1.7 is used as last resort channel when device has used up all of its available duty cycle resources
** Modify Tx filter settings needed: done by writing "0xE1" in register 0x3D
"""
BAND0_868 = {'name': "RF_Band_868_h1.2" , 'dutyCycle' : 100, 'maxPower' : 14, 'maxTxTime' : 36000 } # 1% use, maxTxTime in ms
BAND1_868 = {'name': "RF_Band_868_h1.4" , 'dutyCycle' : 100, 'maxPower' : 14, 'maxTxTime' : 36000} # 1% use
BAND2_868 = {'name': "RF_Band_868_h1.5" , 'dutyCycle' : 10000, 'maxPower' : 14, 'maxTxTime' : 3600} # 0.1% use
BAND3_868 = {'name': "RF_Band_868_h1.6" , 'dutyCycle' : 10, 'maxPower' : 14, 'maxTxTime' : 360000} #mbed platform only connect high efficiency amp so TX power is limited at 14 dBm # 10% use
BAND4_868 = {'name': "RF_Band_868_h1.7" , 'dutyCycle' : 1, 'maxPower' : 7, 'maxTxTime' : 3600000} #100% use
bands_868 = {'BAND0' : BAND0_868, 'BAND1' : BAND1_868, 'BAND2' : BAND2_868, 'BAND3' : BAND3_868, 'BAND4' : BAND4_868}
#default channels in bands h1.6 and h1.7
channel_D1_868= {'name' : 'CH_D1_868_Def_BEACON' , 'freq' : 869.525, 'bw' : BW.BW_125, 'band' : BAND3_868} #Freq is center freq
channel_D2_868= {'name' : 'CH_D2_868_Def_ALWAYS_ON' , 'freq' : 869.850 , 'bw' : BW.BW_125, 'band' : BAND4_868} #Freq is center freq
"""
#Channel configurations
OPTION 1: High capacity : conf h1.2 to use 15x125 kHz and use h1.4 and h1.5 as the high speed channel
OPTION 2: High speed: 4x500 kHz channels in the h1.2 band and 3x125 kHz channels in h1.4 and 1x250 kHz channel in h1.5
OPTION 3: LoRaWAN avoidance mode: avoid h1.4 band and use h1.2 band from 865.1-566.9 (10x 125 kHz channels)
OPTION 4: Testing: 1x 125 kHz channel, 1x250 kHz channel and 1x500 kHz channel in both h1.2 and
"""
channel1_868 = {'name' : 'CH1_868_125' , 'freq' : 865.100 , 'bw' : BW.BW_125, 'band' : BAND0_868}
channel2_868 = {'name' : 'CH2_868_125' , 'freq' : 865.200 , 'bw' : BW.BW_250, 'band' : BAND0_868}
channel3_868 = {'name' : 'CH3_868_125' , 'freq' : 865.600 , 'bw' : BW.BW_500, 'band' : BAND0_868}
channel4_868 = {'name' : 'CH4_868_125' , 'freq' : 868.050 , 'bw' : BW.BW_125, 'band' : BAND1_868}
channel5_868 = {'name' : 'CH5_868_125' , 'freq' : 868.300 , 'bw' : BW.BW_250, 'band' : BAND1_868}
channel6_868 = {'name' : 'CH6_868_125' , 'freq' : 868.300 , 'bw' : BW.BW_500, 'band' : BAND1_868} #warning: to use this channel register "0xE1" must be written in register 0x3D
class Beacon(LoRaMAC):
def __init__(self, verbose=True):
super(Beacon, self).__init__(verbose)
""" General Settings for the SX127X """
""" Header ON/OFF (Implicit Mode) - Turning header off is called implicit mode
Payload length, coding rate, payload CRC must
be fixed at tx and rx side.
Options: [False: OFF, True:ON]
"""
#headerOff=False
self.transmission['headerOff'] = False
""" Bandwith
Options: [125 kHz | 250 kHz | 500 kHz]
"""
#bw=BW.BW_125
#self.transmission['bw'] = BW.BW_125
#no longer selection of bw but of communication channel
self.transmission['channel'] = channel_D2_868
""" Spreading factor / Data Rate
Options: [6:64 | 7:128 | 8:256 | 9:512 | 10:1024 | 11:2048 | 12:4096 chips]
"""
#sf=7
self.transmission['sf']=7
""" Code Rate
Options: [1:4/5, 2:4/6, 3:4/7, 4:4/8]
"""
#cr=CODING_RATE.CR4_5
self.transmission['cr']=CODING_RATE.CR4_5
""" Payload CRC ON/OFF
Options: [False: OFF, True:ON]
In implicit mode RxPayloadCrcOn should be set on both Tx and Rx
"""
#rx_crc_on=True
self.transmission['rx_crc_on']=True
""" Preamble length
Options: 6-65535 (Hardware adds 4 more symbols)
"""
#preambleLen=8
self.transmission['preambleLen']=8
""" Low Data Rate Optimization (Improves robustness of transmission; necessary at high spreading factors or if symbol duration higher than 16ms
Options: [True/False]
"""
#low_data_rate_optim=False
self.transmission['low_data_rate_optim']=False
#Update transceiver configuration
self.updateConfiguration()
#set_hop_channel (not available in HAL yet)
#set_hop_period
# DIO MAPPING
# 0x00 for RxDone (on DIO0) | 0x40 for TxDone (on DIO0)
# CadDone (on DIO3) | CadDone (on DIO3)
# 0x01 for RxDone (on DIO0) | 0x42 for TxDone (on DIO0)
# ValidHeader (on DIO3) | ValidHeader (on DIO3)
mapping = 0x01
self.spi.xfer([REG.LORA.DIO_MAPPING_1 | 0x80, mapping])[1]
self.get_dio_mapping() # update DIO mapping
def on_rx_done(self):
#prob good idea to use full buffer (for later)
#TODO check for bad crc
#we can also use a timeout functionality to stop listening after predetermined amount of time in order to save energy
#using RxTimeOut interrupt TimeOut = LoRaRxTimeout * Ts
print("\n(RxDone) Packet Received")
#print('num bytes payload', self.get_rx_nb_bytes())
payload = self.read_payload_noheader()
#print('Payload:', payload,map(hex, payload))
print('*** Payload: %s' % payload)
decoded_msg_str = ''.join(map(chr,payload)) # convert byte to string and join
print ('*** Decoded: %s' %decoded_msg_str)
if self.incoming['type'] == "ADMIN":
self.processADMIN_frame(payload)
elif self.incoming['type'] == "ACK":
self.processACK(payload)
#self.reset_ptr_rx()
def on_tx_done(self):
print("\n(TxDone) Packet send")
self.set_irq_flags(tx_done=1) #clear interrupt flag
#self.state['wf_ack']= True #set ACK state
print "state %s" % self.state['wf_ack']
self.timer = time.clock() #set timer
self.openReceiveWindow(100) #open receive window for ACK reception HOW LONG??
""" Interrupt Utility Functions """
def on_rx_timeout(self):
print("\n(RxTimeOut) Rx Timeout (No ACK detected in timeframe)")
self.set_irq_flags(rx_timeout=1) #clear interrupt flag
#self.state['wf_ack']= False #clear ACK state
self.set_mode(MODE.STDBY)
print("number of retries:%s" % self.retries)
if (self.retries < self.options['numRetries']):
self.retries += 1
self.writeFrame(self.lastFrame)
sleep(2)
else:
self.state['wf_ack']= False #clear ACK state
self.retries = 0
def start(self):
print "Assemble frame and (re)send every 5 seconds"
#frame = self.prepareFrame("BEACON",[0x50, 0x69, 0x6E, 0x67] )
#print self.channelList.index(channel_D1_868)
#print self.channelList.index(channel_D2_868)
#print self.channelList.index(channel1_868)
print channel1_868['name']
while True:
frame = self.send_MAC_AdminFrame(channel=channel1_868, sf=SF.SF_8, linkCheck=True)
while(self.state['wf_ack']!= False):
sleep(1)
sleep(8)
beacon = Beacon(verbose=False)
print(beacon)
assert(beacon.get_agc_auto_on() == 1)
try: input("Press enter to start...")
except: pass
try:
beacon.start()
except KeyboardInterrupt:
sys.stdout.flush()
print("")
sys.stderr.write("KeyboardInterrupt\n")
finally:
sys.stdout.flush()
beacon.set_mode(MODE.SLEEP)
print(beacon)
BOARD.teardown()