def __init__(self, file_num): self.file_num = file_num interrupt = 157 tx_port = 138 rx_port = 139 spi.setup("/dev/spidev4.0") # setup the TR switch self.tx_ant = GeneralPurposeIO(tx_port, "out") self.tx_ant.write(0) self.rx_ant = GeneralPurposeIO(rx_port, "out") self.rx_ant.write(0) # setup irq line self.irq = GeneralPurposeIO(interrupt, "in") self.packet =[0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x78] self.rssi_data = [] self.packet_count = 0
def _init_io(self): interrupt = 157 tx_port = 138 rx_port = 139 spi.setup("/dev/spidev4.0") # setup the TR switch self.tx_ant = GeneralPurposeIO(tx_port, "out") self.tx_ant.write(0) self.rx_ant = GeneralPurposeIO(rx_port, "out") self.rx_ant.write(0) # setup irq line self.irq = GeneralPurposeIO(interrupt, "in")
def _init_io(self): """ Initialize I/O. This function initializes the radio I/O, including SPI, GPIO, and IRQ line. """ interrupt = 157 tx_port = 138 rx_port = 139 spi.setup("/dev/spidev4.0") # setup the TR switch self.tx_ant = GeneralPurposeIO(tx_port, "out") self.tx_ant.write(0) self.rx_ant = GeneralPurposeIO(rx_port, "out") self.rx_ant.write(0) # setup irq line self.irq = GeneralPurposeIO(interrupt, "in")
def __init__(self, file_num): self.file_num = file_num interrupt = 157 tx_port = 138 rx_port = 139 spi.setup("/dev/spidev4.0") # setup the TR switch self.tx_ant = GeneralPurposeIO(tx_port, "out") self.tx_ant.write(0) self.rx_ant = GeneralPurposeIO(rx_port, "out") self.rx_ant.write(0) # setup irq line self.irq = GeneralPurposeIO(interrupt, "in") self.packet = [ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x78 ] self.rssi_data = [] self.packet_count = 0
class RF(object): def __init__(self, file_num): self.file_num = file_num interrupt = 157 tx_port = 138 rx_port = 139 spi.setup("/dev/spidev4.0") # setup the TR switch self.tx_ant = GeneralPurposeIO(tx_port, "out") self.tx_ant.write(0) self.rx_ant = GeneralPurposeIO(rx_port, "out") self.rx_ant.write(0) # setup irq line self.irq = GeneralPurposeIO(interrupt, "in") self.packet =[0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x78] self.rssi_data = [] self.packet_count = 0 def setup_rf(self, fc, hbsel, fb): spi.write(0x07, 0x80) # reset all the registers spi.write(0x05, 0x00) # Disable interrupts in IntStatReg1 spi.write(0x06, 0x00) # Disable interrupts in IntStatReg2 spi.write(0x07, 0x01) # Set READY mode spi.write(0x09, 0x7F) # Cap = 12.5pF spi.write(0x0A, 0x05) # Clk output is 2MHz spi.write(0x0B, 0xF4) # GPIO0 is for RX data output spi.write(0x0C, 0xEF) # GPIO1 is TX/RX data CLK output spi.write(0x0D, 0x00) # GPIO2 for MCLK output spi.write(0x0E, 0x00) # GPIO port use default value spi.write(0x0F, 0x70) # NO ADC used spi.write(0x10, 0x00) # no ADC used spi.write(0x12, 0x00) # No temp sensor used spi.write(0x13, 0x00) # no temp sensor used spi.write(0x70, 0x0C) # No manchester code, no data whiting, data rate < 30Kbps spi.write(0x1C, 0x8A) # IF filter bandwidth spi.write(0x1D, 0x40) # AFC Loop spi.write(0x20, 0x60) # clock recovery spi.write(0x21, 0x01) # clock recovery spi.write(0x22, 0x55) # clock recovery spi.write(0x23, 0x55) # clock recovery spi.write(0x24, 0x02) # clock recovery timing spi.write(0x25, 0xAD) # clock recovery timing spi.write(0x2C, 0x40) spi.write(0x2D, 0x0A) spi.write(0x2E, 0x50) spi.write(0x6E, 0x20) # TX data rate 1 spi.write(0x6F, 0x00) # TX data rate 0 spi.write(0x30, 0x8C) # Data access control spi.write(0x32, 0xFF) # Header control spi.write(0x33, 0x42) # Header 3, 2, 1, 0 used for head length, # fixed packet length, synchronize word length 3, 2, spi.write(0x34, 64) # 64 nibble = 32 byte preamble spi.write(0x35, 0x20) # 0x35 need to detect 20bit preamble spi.write(0x36, 0x2D) # synchronize word spi.write(0x37, 0xD4) spi.write(0x38, 0x00) spi.write(0x39, 0x00) spi.write(0x3A, 0xff) # set tx header 3 spi.write(0x3B, 0xff) # set tx header 2 spi.write(0x3C, 0xff) # set tx header 1 spi.write(0x3D, 0xff) # set tx header 0 spi.write(0x3E, 17) # set packet length to 17 bytes spi.write(0x3F, 0xff) # set rx header spi.write(0x40, 0xff) spi.write(0x41, 0xff) spi.write(0x42, 0xff) spi.write(0x43, 0xFF) # check all bits spi.write(0x44, 0xFF) # Check all bits spi.write(0x45, 0xFF) # check all bits spi.write(0x46, 0xFF) # Check all bits spi.write(0x56, 0x01) # spi.write(0x6D, 0x04) # Tx power to max spi.write(0x6D, 0x07) # Tx power to max spi.write(0x79, 0x00) # no frequency hopping spi.write(0x7A, 0x00) # no frequency hopping spi.write(0x71, 0x22) # GFSK, fd[8]=0, no invert for TX/RX data, FIFO mode, txclk-->gpio spi.write(0x72, 0xc8) # Frequency deviation setting to 45K=72*625 spi.write(0x73, 0x00) # No frequency offset spi.write(0x74, 0x00) # No frequency offset val = 0x40 | hbsel << 5 | fb spi.write(0x75, val) # frequency set to 434MHz spi.write(0x76, fc >> 8) # frequency set to 434MHz spi.write(0x77, fc & 0xff) # frequency set to 434Mhz spi.write(0x5A, 0x7F) spi.write(0x59, 0x60) spi.write(0x58, 0x80) spi.write(0x6A, 0x0B) spi.write(0x68, 0x04) spi.write(0x1F, 0x03) # spi.write(0x07, 0x80) # reset all the registers # spi.write(0x05, 0x00) # Disable interrupts in IntStatReg1 # spi.write(0x06, 0x00) # Disable interrupts in IntStatReg2 # spi.write(0x07, 0x01) # Set READY mode # spi.write(0x09, 0x7F) # Cap = 12.5pF # spi.write(0x0A, 0x05) # Clk output is 2MHz # spi.write(0x0B, 0xF4) # GPIO0 is for RX data output # spi.write(0x0C, 0xEF) # GPIO1 is TX/RX data CLK output # spi.write(0x0D, 0x00) # GPIO2 for MCLK output # spi.write(0x0E, 0x00) # GPIO port use default value # spi.write(0x0F, 0x70) # NO ADC used # spi.write(0x10, 0x00) # no ADC used # spi.write(0x12, 0x00) # No temp sensor used # spi.write(0x13, 0x00) # no temp sensor used # spi.write(0x70, 0x20) # No manchester code, no data whiting, data rate < 30Kbps # spi.write(0x1C, 0x1D) # IF filter bandwidth # spi.write(0x1D, 0x40) # AFC Loop # spi.write(0x20, 0xA1) # clock recovery # spi.write(0x21, 0x20) # clock recovery # spi.write(0x22, 0x4E) # clock recovery # spi.write(0x23, 0xA5) # clock recovery # spi.write(0x24, 0x00) # clock recovery timing # spi.write(0x25, 0x0A) # clock recovery timing # spi.write(0x2C, 0x00) # spi.write(0x2D, 0x00) # spi.write(0x2E, 0x00) # spi.write(0x6E, 0x27) # TX data rate 1 # spi.write(0x6F, 0x52) # TX data rate 0 # spi.write(0x30, 0x8C) # Data access control # spi.write(0x32, 0xFF) # Header control # spi.write(0x33, 0x42) # Header 3, 2, 1, 0 used for head length, # # fixed packet length, synchronize word length 3, 2, # spi.write(0x34, 64) # 64 nibble = 32 byte preamble # spi.write(0x35, 0x20) # 0x35 need to detect 20bit preamble # spi.write(0x36, 0x2D) # synchronize word # spi.write(0x37, 0xD4) # spi.write(0x38, 0x00) # spi.write(0x39, 0x00) # spi.write(0x3A, 0xff) # set tx header 3 # spi.write(0x3B, 0xff) # set tx header 2 # spi.write(0x3C, 0xff) # set tx header 1 # spi.write(0x3D, 0xff) # set tx header 0 # spi.write(0x3E, 17) # set packet length to 17 bytes # spi.write(0x3F, 0xff) # set rx header # spi.write(0x40, 0xff) # spi.write(0x41, 0xff) # spi.write(0x42, 0xff) # spi.write(0x43, 0xFF) # check all bits # spi.write(0x44, 0xFF) # Check all bits # spi.write(0x45, 0xFF) # check all bits # spi.write(0x46, 0xFF) # Check all bits # spi.write(0x56, 0x01) # spi.write(0x6D, 0x07) # Tx power to max # spi.write(0x79, 0x00) # no frequency hopping # spi.write(0x7A, 0x00) # no frequency hopping # spi.write(0x71, 0x22) # GFSK, fd[8]=0, no invert for TX/RX data, FIFO mode, txclk-->gpio # spi.write(0x72, 0x48) # Frequency deviation setting to 45K=72*625 # spi.write(0x73, 0x00) # No frequency offset # spi.write(0x74, 0x00) # No frequency offset # val = 0x40 | hbsel << 5 | fb # spi.write(0x75, val) # frequency set to 434MHz # spi.write(0x76, fc >> 8) # frequency set to 434MHz # spi.write(0x77, fc & 0xff) # frequency set to 434Mhz # # spi.write(0x75, 0x53) # frequency set to 434MHz # # spi.write(0x76, 0x64) # frequency set to 434MHz # # spi.write(0x77, 0x00) # frequency set to 434Mhz # spi.write(0x5A, 0x7F) # spi.write(0x59, 0x40) # spi.write(0x58, 0x80) # spi.write(0x6A, 0x0B) # spi.write(0x68, 0x04) # spi.write(0x1F, 0x03) def clear_tx_fifo(self): spi.write(0x08, 0x01) spi.write(0x08, 0x00) def clear_rx_fifo(self): spi.write(0x08, 0x02) spi.write(0x08, 0x00) def clear_fifo(self): spi.write(0x08, 0x03) spi.write(0x08, 0x00) def clear_interrupt(self): i = spi.read(0x03) i = spi.read(0x04) def set_rx_fifo_almost_full_threshold(self, threshold): spi.write(0x7E, threshold) def set_tx_fifo_almost_full_threshold(self, threshold): pass def read_rx_fifo(self): return spi.read(0x7F) def set_rfm22_state(self, rfm22_state): if rfm22_state == 'tx': spi.write(0x07, 0x09) elif rfm22_state == 'rx': spi.write(0x07, 0x05) else: pass def set_rfm22_mode(self, mode): if mode == 'ready': spi.write(0x07, 0x01) elif mode == 'tune': spi.write(0x07, 0x03) else: pass def enable_interrupt(self, signal): reg_1 = spi.read(0x05) reg_2 = spi.read(0x06) if signal == 'valid_packet_received': spi.write(0x05, reg_1 | 0x02) else: print "error in enable_interrupt" def module_power_state(self): status = spi.read(0x02) power_state = status & 0x03 if power_state == 0x00: return 'idle' elif power_state == 0x01: return 'rx' elif power_state == 0x02: return 'tx' else: print "error in module_power_state" def receive(self): self.set_rfm22_mode('ready') # is there any particular order these should be in? self.set_rx_fifo_almost_full_threshold(17) self.tx_ant.write(0) self.rx_ant.write(1) self.clear_interrupt() self.clear_fifo() self.set_rfm22_state('rx') self.enable_interrupt('valid_packet_received') print "RSSI Threshold: ", '{0:d}'.format(spi.read(0x27)) print "RSSI Indicator: ", '{0:d}'.format(spi.read(0x26)) print "receiving packet..." while self.module_power_state() == 'rx': result = self.irq.read() rssi = '{0:d}'.format(spi.read(0x26)) self.rssi_data.append([time.time(), rssi]) # print "RSSI Indicator: ", rssi # print "interrupt: ", int(result) if ( int(result) == 0 ): rx_buffer = [] for i in range(17): rx_buffer.append(self.read_rx_fifo()) if ( rx_buffer == self.packet ): print "Packet Received" self.packet_count += 1 def _fsm(self, fsm_state): while True: if fsm_state == 'idle': pass elif fsm_state == 'tx': pass elif fsm_state == 'rx': fc, hbsel, fb = freq_utils.carrier_freq(434e6) self.setup_rf(fc, hbsel, fb) self.receive() if self.packet_count == 50: break else: state = 'rx' else: pass def run(self): self._fsm('rx') def shutdown(self): self.close_gpio() f = open("rssi_data_" + self.file_num + '.txt','w') for i in self.rssi_data: f.write(str(i) + "\n") f.close() def close_gpio(self): self.tx_ant.close() self.rx_ant.close() self.irq.close()
class RF(object): def __init__(self): self.rfm22 = RFM22() self.back_off = RandomBackOff() # self.rssi_threshold = 100 def _init_io(self): interrupt = 157 tx_port = 138 rx_port = 139 spi.setup("/dev/spidev4.0") # setup the TR switch self.tx_ant = GeneralPurposeIO(tx_port, "out") self.tx_ant.write(0) self.rx_ant = GeneralPurposeIO(rx_port, "out") self.rx_ant.write(0) # setup irq line self.irq = GeneralPurposeIO(interrupt, "in") def _kill_io(self): self.tx_ant.close() self.rx_ant.close() self.irq.close() def _init_rf(self): self.rfm22.reset_all_registers() self.rfm22.disable_interrupts() self.rfm22.default_rf22_setup() def _listen(self, freq): self.rfm22.set_frequency(freq) self.rfm22.disable_interrupts() self.rfm22.set_op_mode('ready') self.tx_ant.write(0) self.rx_ant.write(1) self.rfm22.clear_rx_fifo() self.rfm22.clear_interrupts() self.rfm22.set_op_mode('rx') time.sleep(0.01) # need a bit of time before we read rssi values rssi_level = float('{0:d}'.format(spi.read(0x26))) while (rssi_level >= 100): b = self.back_off.run() if (b == "continue"): continue else: # (b == "break") keep_looping = False break def _receive(self, freq): time_out = Timer(2.0) ack = [ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ] self.rfm22.set_frequency(freq) self.rfm22.disable_interrupts() self.rfm22.set_op_mode('ready') self.tx_ant.write(0) self.rx_ant.write(1) self.rfm22.clear_rx_fifo() self.rfm22.clear_interrupts() self.rfm22.set_rx_fifo_almost_full_threshold(17) self.rfm22.enable_interrupt('valid_packet_received') self.rfm22.set_op_mode('rx') print "waiting for ACK..." r = self.irq.read() time_out.start() while (int(r) == 1): if time_out.timer_event.isSet(): time_out.join() del (time_out) print "Time out exceeded" return else: r = self.irq.read() rx_buffer = [] for i in range(17): rx_buffer.append(spi.read(0x7F)) if (rx_buffer == ack): print "ACK Received" def _transmit(self, freq): data = [ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x78 ] self.rfm22.set_frequency(freq) self.rfm22.disable_interrupts() self.rfm22.set_op_mode('ready') self.rx_ant.write(0) self.tx_ant.write(1) self.rfm22.clear_tx_fifo() self.rfm22.load_tx_fifo(data) self.rfm22.enable_interrupt('packet_sent') self.rfm22.clear_interrupts() self.rfm22.set_op_mode('tx') r = self.irq.read() while (int(r) == 1): r = self.irq.read() print "packet sent" self.rx_ant.write(0) self.tx_ant.write(0) def run(self): pass def fsm(self): """ Primary control loop. This function is the finite state machine that controls the operation of the system. """ self._init_io() self._init_rf() state = "listen" f = 434e6 while True: if state == "listen": self._listen(f) state = "transmit" elif state == "transmit": self._transmit(f) state = "receive" elif state == "receive": self._receive(f) state = "listen" else: print "+++ Melon melon melon +++" state = "listen" def shutdown(self): self._kill_io()
class RadioAPI(object): """ Radio API. This class implements the functionality and provides the tools for making radio applications. """ def __init__(self): self.rfm22 = RadioBase() self.backoff = RandomBackOff() def _init_io(self): """ Initialize I/O. This function initializes the radio I/O, including SPI, GPIO, and IRQ line. """ interrupt = 157 tx_port = 138 rx_port = 139 spi.setup("/dev/spidev4.0") # setup the TR switch self.tx_ant = GeneralPurposeIO(tx_port, "out") self.tx_ant.write(0) self.rx_ant = GeneralPurposeIO(rx_port, "out") self.rx_ant.write(0) # setup irq line self.irq = GeneralPurposeIO(interrupt, "in") def _kill_io(self): """ Shutdown I/O. This function closes and ends the radio I/O including GPIO and IRQ line. """ self.tx_ant.close() self.rx_ant.close() self.irq.close() def _init_rf(self): """ Initialize RF. This function intitializes the RF parameters, resetting all RFM 22 registers, disabling all interrupts, and enabling a default configuration. """ self.rfm22.reset_all_registers() self.rfm22.disable_interrupts() self.rfm22.default_setup() def _tx_rx_switch(self, mode): """ Switch T/R mode. This function turns the transmit/receive switch to receive, transmit, or off. Parameters ---------- mode : str Mode for T/R switch operation, one of `tx`, `rx`, or `off`. Raises ------ KeyError if mode not in [`tx`, `rx`, `off`]. """ if mode not in ['tx', 'rx', 'off']: raise ValueError else: if mode == 'tx': self.rx_ant.write(0) self.tx_ant.write(1) elif mode == 'rx': self.tx_ant.write(0) self.rx_ant.write(1) elif mode == 'off': self.tx_ant.write(0) self.rx_ant.write(0) else: print "+++ Melon melon melon +++" def startup(self): """ General radio initialization. This helper function initializes the I/O and RF. """ self._init_io() self._init_rf() def shutdown(self): """ General radio cleanup. This helper function cleans up and shuts down any open processes. """ self._kill_io() def transmit(self, data, freq, DEBUG=True): """ Transmit data packet. This function takes data and loads it into the TX FIFO buffer for transmission over the air. Parameters ---------- data : list Input list of data to be transmitted, each element of which is 8 bits. Maximum list size is 64 elements. freq : float Operating (center) frequency for transmission. DEBUG : bool, optional Flag to turn on debug message printing . Raises ------ IndexError if length of `data` is greater than 64. """ if len(data) > 64: raise IndexError else: self.rfm22.set_op_mode('ready') self.rfm22.disable_interrupts() self.rfm22.clear_interrupts() self.rfm22.clear_tx_fifo() self.rfm22.set_frequency(freq) self.rfm22.load_tx_fifo(data) self._tx_rx_switch('tx') self.rfm22.enable_interrupt('packet_sent') self.rfm22.set_op_mode('tx') r = self.irq.read() while (int(r) == 1): r = self.irq.read() if DEBUG: print "packet sent" self._tx_rx_switch('off') def listen(self, freq, rssi_threshold=100, timeout=0.5, DEBUG=True): """ Listen before talk. This function implements listen-before-talk or carrier sense. RSSI is used to determine if the frequency of interest is busy. Timeout is used to interrupt the listening process, returning a value of `busy` to the parent (calling) function. Parameters ---------- freq : float Operating (center) frequency of interest. rssi_threshold : int, optional RSSI threshold for determining whether channel is clear. Default value is 100. This value is not a power value; for relationship between RSSI and power, see [RFM22]. timeout : float, optional Timeout value in seconds. DEBUG : bool, optional Flag to turn on debug message printing. Returns ------- out : str Frequency (channel) status, either `clear` or `busy`. References ---------- .. [RFM22] Figure 31, pg 64, RFM22 Data sheet. """ self.rfm22.set_op_mode('ready') self.rfm22.disable_interrupts() self.rfm22.clear_interrupts() self.rfm22.clear_rx_fifo() self.rfm22.set_frequency(freq) self._tx_rx_switch('rx') self.rfm22.set_op_mode('rx') time.sleep(0.01) # need a bit of time before we read rssi values rssi_level = float('{0:d}'.format(spi.read(0x26))) while (rssi_level >= 100): b = self.backoff.run() if (b == "continue"): rssi_level = float('{0:d}'.format(spi.read(0x26))) continue else: # (b == "break") self._tx_rx_switch('off') return 'busy' self._tx_rx_switch('off') return 'clear' def receive(self, freq, rx_fifo_threshold=17, timeout=None, DEBUG=True): """ Receive data. This function receives data and does more stuff. TODO: Add more here. If `timeout` is none, then there is no time limit on how long to wait to receive a packet. Parameters ---------- freq : float Operating (center) frequency of interest. rx_fifo_threshold : int, optional Value for RX Almost Full threshold. When the incoming RX data reaches the Almost Full Threshold an interrupt will be generated to the microcontroller via the nIRQ pin. The microcontroller will then need to read the data from the RX FIFO. timeout : float, optional Timeout value in seconds. Default value is 120. DEBUG : bool, optional Flag to turn on debug message printing. Returns ------- rx_buffer : list Received data, from RX FIFO buffer. """ self.rfm22.set_op_mode('ready') self.rfm22.disable_interrupts() self.rfm22.clear_interrupts() self.rfm22.clear_rx_fifo() self.rfm22.set_frequency(freq) self.rfm22.set_rx_fifo_almost_full_threshold(rx_fifo_threshold) self._tx_rx_switch('rx') self.rfm22.enable_interrupt('valid_packet_received') self.rfm22.set_op_mode('rx') if timeout == None: if DEBUG: print "waiting for packet..." r = self.irq.read() while (int(r) == 1): # interrupt is driven low when packet arrives r = self.irq.read() rx_buffer = [] for i in range(rx_fifo_threshold): rx_buffer.append(spi.read(0x7F)) return rx_buffer else: timer=Timer(timeout) timer.start() if DEBUG: print "waiting for packet..." r = self.irq.read() while (int(r) == 1): # interrupt is driven low when packet arrives if timer.flag.isSet(): timer.join() del(timer) if DEBUG: print "Time out exceeded" return [] else: r = self.irq.read() # timer.join() # this doesn't seem necessary, and it takes # a long time to execute BigO(1 sec) # del(timer) rx_buffer = [] for i in range(rx_fifo_threshold): rx_buffer.append(spi.read(0x7F)) return rx_buffer def configure_radio(self, power = 17, frequency = 434e6, data_rate = 4.8e3, modulation = "gfsk"): """ Configure radio. This function configures the radio for transmit and receive operation. Parameters ---------- power : int Output power in dBm, one of {8 | 11 | 14 | 17}. frequency : float Center frequency, this should be between 240.0e6 and 930.0e6. data_rate : float modulation : str Modulation type, one of {'unmodulated' | 'ook' | 'fsk' | 'gfsk'}. """ self.rfm22.set_output_power(power) self.rfm22.set_frequency(frequency) self.rfm22.set_data_rate(data_rate) self.rfm22.set_modulation(modulation)
class RadioAPI(object): """ Radio API. This class implements the functionality and provides the tools for making radio applications. """ def __init__(self): self.rfm22 = RadioBase() self.backoff = RandomBackOff() def _init_io(self): """ Initialize I/O. This function initializes the radio I/O, including SPI, GPIO, and IRQ line. """ interrupt = 157 tx_port = 138 rx_port = 139 spi.setup("/dev/spidev4.0") # setup the TR switch self.tx_ant = GeneralPurposeIO(tx_port, "out") self.tx_ant.write(0) self.rx_ant = GeneralPurposeIO(rx_port, "out") self.rx_ant.write(0) # setup irq line self.irq = GeneralPurposeIO(interrupt, "in") def _kill_io(self): """ Shutdown I/O. This function closes and ends the radio I/O including GPIO and IRQ line. """ self.tx_ant.close() self.rx_ant.close() self.irq.close() def _init_rf(self): """ Initialize RF. This function intitializes the RF parameters, resetting all RFM 22 registers, disabling all interrupts, and enabling a default configuration. """ self.rfm22.reset_all_registers() self.rfm22.disable_interrupts() self.rfm22.default_setup() def _tx_rx_switch(self, mode): """ Switch T/R mode. This function turns the transmit/receive switch to receive, transmit, or off. Parameters ---------- mode : str Mode for T/R switch operation, one of `tx`, `rx`, or `off`. Raises ------ KeyError if mode not in [`tx`, `rx`, `off`]. """ if mode not in ['tx', 'rx', 'off']: raise ValueError else: if mode == 'tx': self.rx_ant.write(0) self.tx_ant.write(1) elif mode == 'rx': self.tx_ant.write(0) self.rx_ant.write(1) elif mode == 'off': self.tx_ant.write(0) self.rx_ant.write(0) else: print "+++ Melon melon melon +++" def startup(self): """ General radio initialization. This helper function initializes the I/O and RF. """ self._init_io() self._init_rf() def shutdown(self): """ General radio cleanup. This helper function cleans up and shuts down any open processes. """ self._kill_io() def transmit(self, data, freq, DEBUG=True): """ Transmit data packet. This function takes data and loads it into the TX FIFO buffer for transmission over the air. Parameters ---------- data : list Input list of data to be transmitted, each element of which is 8 bits. Maximum list size is 64 elements. freq : float Operating (center) frequency for transmission. DEBUG : bool, optional Flag to turn on debug message printing . Raises ------ IndexError if length of `data` is greater than 64. """ if len(data) > 64: raise IndexError else: self.rfm22.set_op_mode('ready') self.rfm22.disable_interrupts() self.rfm22.clear_interrupts() self.rfm22.clear_tx_fifo() self.rfm22.set_frequency(freq) self.rfm22.load_tx_fifo(data) self._tx_rx_switch('tx') self.rfm22.enable_interrupt('packet_sent') self.rfm22.set_op_mode('tx') r = self.irq.read() while (int(r) == 1): r = self.irq.read() if DEBUG: print "packet sent" self._tx_rx_switch('off') def listen(self, freq, rssi_threshold=100, timeout=0.5, DEBUG=True): """ Listen before talk. This function implements listen-before-talk or carrier sense. RSSI is used to determine if the frequency of interest is busy. Timeout is used to interrupt the listening process, returning a value of `busy` to the parent (calling) function. Parameters ---------- freq : float Operating (center) frequency of interest. rssi_threshold : int, optional RSSI threshold for determining whether channel is clear. Default value is 100. This value is not a power value; for relationship between RSSI and power, see [RFM22]. timeout : float, optional Timeout value in seconds. DEBUG : bool, optional Flag to turn on debug message printing. Returns ------- out : str Frequency (channel) status, either `clear` or `busy`. References ---------- .. [RFM22] Figure 31, pg 64, RFM22 Data sheet. """ self.rfm22.set_op_mode('ready') self.rfm22.disable_interrupts() self.rfm22.clear_interrupts() self.rfm22.clear_rx_fifo() self.rfm22.set_frequency(freq) self._tx_rx_switch('rx') self.rfm22.set_op_mode('rx') time.sleep(0.01) # need a bit of time before we read rssi values rssi_level = float('{0:d}'.format(spi.read(0x26))) while (rssi_level >= 100): b = self.backoff.run() if (b == "continue"): rssi_level = float('{0:d}'.format(spi.read(0x26))) continue else: # (b == "break") self._tx_rx_switch('off') return 'busy' self._tx_rx_switch('off') return 'clear' def receive(self, freq, rx_fifo_threshold=17, timeout=None, DEBUG=True): """ Receive data. This function receives data and does more stuff. TODO: Add more here. If `timeout` is none, then there is no time limit on how long to wait to receive a packet. Parameters ---------- freq : float Operating (center) frequency of interest. rx_fifo_threshold : int, optional Value for RX Almost Full threshold. When the incoming RX data reaches the Almost Full Threshold an interrupt will be generated to the microcontroller via the nIRQ pin. The microcontroller will then need to read the data from the RX FIFO. timeout : float, optional Timeout value in seconds. Default value is 120. DEBUG : bool, optional Flag to turn on debug message printing. Returns ------- rx_buffer : list Received data, from RX FIFO buffer. """ self.rfm22.set_op_mode('ready') self.rfm22.disable_interrupts() self.rfm22.clear_interrupts() self.rfm22.clear_rx_fifo() self.rfm22.set_frequency(freq) self.rfm22.set_rx_fifo_almost_full_threshold(rx_fifo_threshold) self._tx_rx_switch('rx') self.rfm22.enable_interrupt('valid_packet_received') self.rfm22.set_op_mode('rx') if timeout == None: if DEBUG: print "waiting for packet..." r = self.irq.read() while (int(r) == 1): # interrupt is driven low when packet arrives r = self.irq.read() rx_buffer = [] for i in range(rx_fifo_threshold): rx_buffer.append(spi.read(0x7F)) return rx_buffer else: timer = Timer(timeout) timer.start() if DEBUG: print "waiting for packet..." r = self.irq.read() while (int(r) == 1): # interrupt is driven low when packet arrives if timer.flag.isSet(): timer.join() del (timer) if DEBUG: print "Time out exceeded" return [] else: r = self.irq.read() # timer.join() # this doesn't seem necessary, and it takes # a long time to execute BigO(1 sec) # del(timer) rx_buffer = [] for i in range(rx_fifo_threshold): rx_buffer.append(spi.read(0x7F)) return rx_buffer def configure_radio(self, power=17, frequency=434e6, data_rate=4.8e3, modulation="gfsk"): """ Configure radio. This function configures the radio for transmit and receive operation. Parameters ---------- power : int Output power in dBm, one of {8 | 11 | 14 | 17}. frequency : float Center frequency, this should be between 240.0e6 and 930.0e6. data_rate : float modulation : str Modulation type, one of {'unmodulated' | 'ook' | 'fsk' | 'gfsk'}. """ self.rfm22.set_output_power(power) self.rfm22.set_frequency(frequency) self.rfm22.set_data_rate(data_rate) self.rfm22.set_modulation(modulation)
class RF(object): def __init__(self): self.rfm22 = RFM22() self.back_off = RandomBackOff() # self.rssi_threshold = 100 def _init_io(self): interrupt = 157 tx_port = 138 rx_port = 139 spi.setup("/dev/spidev4.0") # setup the TR switch self.tx_ant = GeneralPurposeIO(tx_port, "out") self.tx_ant.write(0) self.rx_ant = GeneralPurposeIO(rx_port, "out") self.rx_ant.write(0) # setup irq line self.irq = GeneralPurposeIO(interrupt, "in") def _kill_io(self): self.tx_ant.close() self.rx_ant.close() self.irq.close() def _init_rf(self): self.rfm22.reset_all_registers() self.rfm22.disable_interrupts() self.rfm22.default_rf22_setup() def _listen(self, freq): self.rfm22.set_frequency(freq) self.rfm22.disable_interrupts() self.rfm22.set_op_mode('ready') self.tx_ant.write(0) self.rx_ant.write(1) self.rfm22.clear_rx_fifo() self.rfm22.clear_interrupts() self.rfm22.set_op_mode('rx') time.sleep(0.01) # need a bit of time before we read rssi values rssi_level = float('{0:d}'.format(spi.read(0x26))) while (rssi_level >= 100): b = self.back_off.run() if (b == "continue"): continue else: # (b == "break") keep_looping = False break def _receive(self, freq): time_out = Timer(2.0) ack = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] self.rfm22.set_frequency(freq) self.rfm22.disable_interrupts() self.rfm22.set_op_mode('ready') self.tx_ant.write(0) self.rx_ant.write(1) self.rfm22.clear_rx_fifo() self.rfm22.clear_interrupts() self.rfm22.set_rx_fifo_almost_full_threshold(17) self.rfm22.enable_interrupt('valid_packet_received') self.rfm22.set_op_mode('rx') print "waiting for ACK..." r = self.irq.read() time_out.start() while (int(r) == 1): if time_out.timer_event.isSet(): time_out.join() del(time_out) print "Time out exceeded" return else: r = self.irq.read() rx_buffer = [] for i in range(17): rx_buffer.append(spi.read(0x7F)) if (rx_buffer == ack): print "ACK Received" def _transmit(self, freq): data = [0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x78] self.rfm22.set_frequency(freq) self.rfm22.disable_interrupts() self.rfm22.set_op_mode('ready') self.rx_ant.write(0) self.tx_ant.write(1) self.rfm22.clear_tx_fifo() self.rfm22.load_tx_fifo(data) self.rfm22.enable_interrupt('packet_sent') self.rfm22.clear_interrupts() self.rfm22.set_op_mode('tx') r = self.irq.read() while (int(r) == 1): r = self.irq.read() print "packet sent" self.rx_ant.write(0) self.tx_ant.write(0) def run(self): pass def fsm(self): """ Primary control loop. This function is the finite state machine that controls the operation of the system. """ self._init_io() self._init_rf() state = "listen" f = 434e6 while True: if state == "listen": self._listen(f) state = "transmit" elif state == "transmit": self._transmit(f) state = "receive" elif state == "receive": self._receive(f) state = "listen" else: print "+++ Melon melon melon +++" state = "listen" def shutdown(self): self._kill_io()
class RF(object): def __init__(self, file_num): self.file_num = file_num interrupt = 157 tx_port = 138 rx_port = 139 spi.setup("/dev/spidev4.0") # setup the TR switch self.tx_ant = GeneralPurposeIO(tx_port, "out") self.tx_ant.write(0) self.rx_ant = GeneralPurposeIO(rx_port, "out") self.rx_ant.write(0) # setup irq line self.irq = GeneralPurposeIO(interrupt, "in") self.packet = [ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x78 ] self.rssi_data = [] self.packet_count = 0 def setup_rf(self, fc, hbsel, fb): spi.write(0x07, 0x80) # reset all the registers spi.write(0x05, 0x00) # Disable interrupts in IntStatReg1 spi.write(0x06, 0x00) # Disable interrupts in IntStatReg2 spi.write(0x07, 0x01) # Set READY mode spi.write(0x09, 0x7F) # Cap = 12.5pF spi.write(0x0A, 0x05) # Clk output is 2MHz spi.write(0x0B, 0xF4) # GPIO0 is for RX data output spi.write(0x0C, 0xEF) # GPIO1 is TX/RX data CLK output spi.write(0x0D, 0x00) # GPIO2 for MCLK output spi.write(0x0E, 0x00) # GPIO port use default value spi.write(0x0F, 0x70) # NO ADC used spi.write(0x10, 0x00) # no ADC used spi.write(0x12, 0x00) # No temp sensor used spi.write(0x13, 0x00) # no temp sensor used spi.write( 0x70, 0x0C) # No manchester code, no data whiting, data rate < 30Kbps spi.write(0x1C, 0x8A) # IF filter bandwidth spi.write(0x1D, 0x40) # AFC Loop spi.write(0x20, 0x60) # clock recovery spi.write(0x21, 0x01) # clock recovery spi.write(0x22, 0x55) # clock recovery spi.write(0x23, 0x55) # clock recovery spi.write(0x24, 0x02) # clock recovery timing spi.write(0x25, 0xAD) # clock recovery timing spi.write(0x2C, 0x40) spi.write(0x2D, 0x0A) spi.write(0x2E, 0x50) spi.write(0x6E, 0x20) # TX data rate 1 spi.write(0x6F, 0x00) # TX data rate 0 spi.write(0x30, 0x8C) # Data access control spi.write(0x32, 0xFF) # Header control spi.write(0x33, 0x42) # Header 3, 2, 1, 0 used for head length, # fixed packet length, synchronize word length 3, 2, spi.write(0x34, 64) # 64 nibble = 32 byte preamble spi.write(0x35, 0x20) # 0x35 need to detect 20bit preamble spi.write(0x36, 0x2D) # synchronize word spi.write(0x37, 0xD4) spi.write(0x38, 0x00) spi.write(0x39, 0x00) spi.write(0x3A, 0xff) # set tx header 3 spi.write(0x3B, 0xff) # set tx header 2 spi.write(0x3C, 0xff) # set tx header 1 spi.write(0x3D, 0xff) # set tx header 0 spi.write(0x3E, 17) # set packet length to 17 bytes spi.write(0x3F, 0xff) # set rx header spi.write(0x40, 0xff) spi.write(0x41, 0xff) spi.write(0x42, 0xff) spi.write(0x43, 0xFF) # check all bits spi.write(0x44, 0xFF) # Check all bits spi.write(0x45, 0xFF) # check all bits spi.write(0x46, 0xFF) # Check all bits spi.write(0x56, 0x01) # spi.write(0x6D, 0x04) # Tx power to max spi.write(0x6D, 0x07) # Tx power to max spi.write(0x79, 0x00) # no frequency hopping spi.write(0x7A, 0x00) # no frequency hopping spi.write( 0x71, 0x22 ) # GFSK, fd[8]=0, no invert for TX/RX data, FIFO mode, txclk-->gpio spi.write(0x72, 0xc8) # Frequency deviation setting to 45K=72*625 spi.write(0x73, 0x00) # No frequency offset spi.write(0x74, 0x00) # No frequency offset val = 0x40 | hbsel << 5 | fb spi.write(0x75, val) # frequency set to 434MHz spi.write(0x76, fc >> 8) # frequency set to 434MHz spi.write(0x77, fc & 0xff) # frequency set to 434Mhz spi.write(0x5A, 0x7F) spi.write(0x59, 0x60) spi.write(0x58, 0x80) spi.write(0x6A, 0x0B) spi.write(0x68, 0x04) spi.write(0x1F, 0x03) # spi.write(0x07, 0x80) # reset all the registers # spi.write(0x05, 0x00) # Disable interrupts in IntStatReg1 # spi.write(0x06, 0x00) # Disable interrupts in IntStatReg2 # spi.write(0x07, 0x01) # Set READY mode # spi.write(0x09, 0x7F) # Cap = 12.5pF # spi.write(0x0A, 0x05) # Clk output is 2MHz # spi.write(0x0B, 0xF4) # GPIO0 is for RX data output # spi.write(0x0C, 0xEF) # GPIO1 is TX/RX data CLK output # spi.write(0x0D, 0x00) # GPIO2 for MCLK output # spi.write(0x0E, 0x00) # GPIO port use default value # spi.write(0x0F, 0x70) # NO ADC used # spi.write(0x10, 0x00) # no ADC used # spi.write(0x12, 0x00) # No temp sensor used # spi.write(0x13, 0x00) # no temp sensor used # spi.write(0x70, 0x20) # No manchester code, no data whiting, data rate < 30Kbps # spi.write(0x1C, 0x1D) # IF filter bandwidth # spi.write(0x1D, 0x40) # AFC Loop # spi.write(0x20, 0xA1) # clock recovery # spi.write(0x21, 0x20) # clock recovery # spi.write(0x22, 0x4E) # clock recovery # spi.write(0x23, 0xA5) # clock recovery # spi.write(0x24, 0x00) # clock recovery timing # spi.write(0x25, 0x0A) # clock recovery timing # spi.write(0x2C, 0x00) # spi.write(0x2D, 0x00) # spi.write(0x2E, 0x00) # spi.write(0x6E, 0x27) # TX data rate 1 # spi.write(0x6F, 0x52) # TX data rate 0 # spi.write(0x30, 0x8C) # Data access control # spi.write(0x32, 0xFF) # Header control # spi.write(0x33, 0x42) # Header 3, 2, 1, 0 used for head length, # # fixed packet length, synchronize word length 3, 2, # spi.write(0x34, 64) # 64 nibble = 32 byte preamble # spi.write(0x35, 0x20) # 0x35 need to detect 20bit preamble # spi.write(0x36, 0x2D) # synchronize word # spi.write(0x37, 0xD4) # spi.write(0x38, 0x00) # spi.write(0x39, 0x00) # spi.write(0x3A, 0xff) # set tx header 3 # spi.write(0x3B, 0xff) # set tx header 2 # spi.write(0x3C, 0xff) # set tx header 1 # spi.write(0x3D, 0xff) # set tx header 0 # spi.write(0x3E, 17) # set packet length to 17 bytes # spi.write(0x3F, 0xff) # set rx header # spi.write(0x40, 0xff) # spi.write(0x41, 0xff) # spi.write(0x42, 0xff) # spi.write(0x43, 0xFF) # check all bits # spi.write(0x44, 0xFF) # Check all bits # spi.write(0x45, 0xFF) # check all bits # spi.write(0x46, 0xFF) # Check all bits # spi.write(0x56, 0x01) # spi.write(0x6D, 0x07) # Tx power to max # spi.write(0x79, 0x00) # no frequency hopping # spi.write(0x7A, 0x00) # no frequency hopping # spi.write(0x71, 0x22) # GFSK, fd[8]=0, no invert for TX/RX data, FIFO mode, txclk-->gpio # spi.write(0x72, 0x48) # Frequency deviation setting to 45K=72*625 # spi.write(0x73, 0x00) # No frequency offset # spi.write(0x74, 0x00) # No frequency offset # val = 0x40 | hbsel << 5 | fb # spi.write(0x75, val) # frequency set to 434MHz # spi.write(0x76, fc >> 8) # frequency set to 434MHz # spi.write(0x77, fc & 0xff) # frequency set to 434Mhz # # spi.write(0x75, 0x53) # frequency set to 434MHz # # spi.write(0x76, 0x64) # frequency set to 434MHz # # spi.write(0x77, 0x00) # frequency set to 434Mhz # spi.write(0x5A, 0x7F) # spi.write(0x59, 0x40) # spi.write(0x58, 0x80) # spi.write(0x6A, 0x0B) # spi.write(0x68, 0x04) # spi.write(0x1F, 0x03) def clear_tx_fifo(self): spi.write(0x08, 0x01) spi.write(0x08, 0x00) def clear_rx_fifo(self): spi.write(0x08, 0x02) spi.write(0x08, 0x00) def clear_fifo(self): spi.write(0x08, 0x03) spi.write(0x08, 0x00) def clear_interrupt(self): i = spi.read(0x03) i = spi.read(0x04) def set_rx_fifo_almost_full_threshold(self, threshold): spi.write(0x7E, threshold) def set_tx_fifo_almost_full_threshold(self, threshold): pass def read_rx_fifo(self): return spi.read(0x7F) def set_rfm22_state(self, rfm22_state): if rfm22_state == 'tx': spi.write(0x07, 0x09) elif rfm22_state == 'rx': spi.write(0x07, 0x05) else: pass def set_rfm22_mode(self, mode): if mode == 'ready': spi.write(0x07, 0x01) elif mode == 'tune': spi.write(0x07, 0x03) else: pass def enable_interrupt(self, signal): reg_1 = spi.read(0x05) reg_2 = spi.read(0x06) if signal == 'valid_packet_received': spi.write(0x05, reg_1 | 0x02) else: print "error in enable_interrupt" def module_power_state(self): status = spi.read(0x02) power_state = status & 0x03 if power_state == 0x00: return 'idle' elif power_state == 0x01: return 'rx' elif power_state == 0x02: return 'tx' else: print "error in module_power_state" def receive(self): self.set_rfm22_mode('ready') # is there any particular order these should be in? self.set_rx_fifo_almost_full_threshold(17) self.tx_ant.write(0) self.rx_ant.write(1) self.clear_interrupt() self.clear_fifo() self.set_rfm22_state('rx') self.enable_interrupt('valid_packet_received') print "RSSI Threshold: ", '{0:d}'.format(spi.read(0x27)) print "RSSI Indicator: ", '{0:d}'.format(spi.read(0x26)) print "receiving packet..." while self.module_power_state() == 'rx': result = self.irq.read() rssi = '{0:d}'.format(spi.read(0x26)) self.rssi_data.append([time.time(), rssi]) # print "RSSI Indicator: ", rssi # print "interrupt: ", int(result) if (int(result) == 0): rx_buffer = [] for i in range(17): rx_buffer.append(self.read_rx_fifo()) if (rx_buffer == self.packet): print "Packet Received" self.packet_count += 1 def _fsm(self, fsm_state): while True: if fsm_state == 'idle': pass elif fsm_state == 'tx': pass elif fsm_state == 'rx': fc, hbsel, fb = freq_utils.carrier_freq(434e6) self.setup_rf(fc, hbsel, fb) self.receive() if self.packet_count == 50: break else: state = 'rx' else: pass def run(self): self._fsm('rx') def shutdown(self): self.close_gpio() f = open("rssi_data_" + self.file_num + '.txt', 'w') for i in self.rssi_data: f.write(str(i) + "\n") f.close() def close_gpio(self): self.tx_ant.close() self.rx_ant.close() self.irq.close()