def run(self): #Only need to execute one of the following lines: #spi = SPI(bus, device) #/dev/spidev<bus>.<device> spi = SPI(0, 0) #/dev/spidev1.0 spi.msh = 2000000 # SPI clock set to 2000 kHz spi.bpw = 8 # bits/word spi.threewire = False spi.lsbfirst = False spi.mode = 1 spi.cshigh = False # chip select (active low) spi.open(0, 0) print("spi... msh=" + str(spi.msh)) gchannel = 0 buf0 = (7 << 3) | ((gchannel & 0x0f) >> 1) #(7<<3) for auto-2 mode buf1 = (gchannel & 0x01) << 7 buf1 = buf1 | 0x40 #select 5v i/p range while (self.running): ret = spi.xfer2([buf0, buf1]) print("0x%x 0x%x" % (ret[0], ret[1])) chanl = (ret[0] & 0xf0) >> 4 adcval = ((ret[0] & 0x0f) << 4) + ((ret[1] & 0xf0) >> 4) print(" -> chanl=%d adcval=0x%x" % (chanl, adcval)) time.sleep(1)
class NRF24: # Some limits MAX_CHANNEL = 127 MAX_PAYLOAD_SIZE = 32 # PA Levels PA_MIN = 0x00 PA_LOW = 0x01 PA_HIGH = 0x02 PA_MAX = 0x03 PA_ERROR = 0x04 # Bit rates BR_1MBPS = 0 BR_2MBPS = 1 BR_250KBPS = 2 # CRC CRC_DISABLED = 0 CRC_8 = 1 CRC_16 = 2 # Registers CONFIG = 0x00 EN_AA = 0x01 EN_RXADDR = 0x02 SETUP_AW = 0x03 SETUP_RETR = 0x04 RF_CH = 0x05 RF_SETUP = 0x06 STATUS = 0x07 OBSERVE_TX = 0x08 RPD = 0x09 # CD on Non-P version RX_ADDR_P0 = 0x0A RX_ADDR_P1 = 0x0B RX_ADDR_P2 = 0x0C RX_ADDR_P3 = 0x0D RX_ADDR_P4 = 0x0E RX_ADDR_P5 = 0x0F TX_ADDR = 0x10 RX_PW_P0 = 0x11 RX_PW_P1 = 0x12 RX_PW_P2 = 0x13 RX_PW_P3 = 0x14 RX_PW_P4 = 0x15 RX_PW_P5 = 0x16 FIFO_STATUS = 0x17 DYNPD = 0x1C FEATURE = 0x1D # Bit Mask Mnemonics - CONFIG register MASK_RX_DR = 0x40 MASK_TX_DS = 0x20 MASK_MAX_RT = 0x10 EN_CRC = 0x08 CRCO = 0x04 PWR_UP = 0x02 PRIM_RX = 0x01 # Bit Mask Mnemonics - STATUS register RX_DR = 0x40 TX_DS = 0x20 MAX_RT = 0x10 TX_FULL = 0x01 RX_P_NO_MASK = 0x0E # isolate pipe number # Bit Mask Mnemonics - FIFO_STATUS register TX_REUSE = 0x40 TXFIFO_FULL = 0x20 TXFIFO_EMPTY = 0x10 RXFIFO_FULL = 0x02 RXFIFO_EMPTY = 0x01 # Bit Mask Mnemonics - DYNPD register DPL_P5 = 0x20 DPL_P4 = 0x10 DPL_P3 = 0x08 DPL_P2 = 0x04 DPL_P1 = 0x02 DPL_P0 = 0x01 # Bit Mask Mnemonics - FEATURE register EN_DPL = 0x04 EN_ACK_PAY = 0x02 EN_DYN_ACK = 0x01 # Shift counts ARD = 4 ARC = 0 PLOS_CNT = 4 ARC_CNT = 0 RX_P_NO = 1 # Instruction Mnemonics R_REGISTER = 0x00 W_REGISTER = 0x20 REGISTER_MASK = 0x1F ACTIVATE = 0x50 R_RX_PL_WID = 0x60 R_RX_PAYLOAD = 0x61 W_TX_PAYLOAD = 0xA0 W_ACK_PAYLOAD = 0xA8 FLUSH_TX = 0xE1 FLUSH_RX = 0xE2 REUSE_TX_PL = 0xE3 NOP = 0xFF # Non-P omissions LNA_HCURR = 0x01 LNA_ON = 1 LNA_OFF = 0 # P model Mask Mnemonics RF_DR_LOW = 0x20 RF_DR_HIGH = 0x08 RF_PWR_LOW = 0x02 RF_PWR_HIGH = 0x04 datarate_e_str_P = ["1MBPS", "2MBPS", "250KBPS"] model_e_str_P = ["nRF24L01", "nRF24l01+"] crclength_e_str_P = ["Disabled", "8 bits", "16 bits"] pa_dbm_e_str_P = ["PA_MIN", "PA_LOW", "PA_HIGH", "PA_MAX"] @staticmethod def print_single_status_line(name, value): """Prints name = value""" print("{0:<16}= {1}".format(name, value)) @staticmethod def _to_8b_list(data): """Convert an arbitray iteratable or single int to a list of ints where each int is smaller than 256.""" if isinstance(data, str): data = [ord(x) & 0xFF for x in data] elif isinstance(data, (int, long)): data = [data & 0xFF] else: data = [int(x) & 0xFF for x in data] return data def __init__(self, major=None, minor=None, ce_pin=None, irq_pin=None): """Construtor. major and minor selects SPI port, ce_pin is optional GPIO pin number for CE signal irq_pin is optional GPIO pin number for IRQ signal""" # defaults and miscelaneous initialization self.payload_size = 32 # *< Fixed size of payloads self.ack_payload_available = False # *< Whether there is an ack payload waiting self.dynamic_payloads_enabled = False # *< Whether dynamic payloads are enabled. self.ack_payload_length = 5 # *< Dynamic size of pending ack payload. self.pipe0_reading_address = None # *< Last address set on pipe 0 for reading. self.spidev = None self.last_error = 0 self.auto_ack = 0 self.address_length = 5 # If all parameters are available, lets start the radio! if major is not None and minor is not None and irq_pin is not None: self.begin(major, minor, ce_pin, irq_pin) def begin(self, major, minor, ce_pin, irq_pin): """Radio initialization, must be called before anything else. major and minor selects SPI port, ce_pin is GPIO pin number for CE signal irq_pin is optional GPIO pin number for IRQ signal""" # Initialize SPI bus if ADAFRUID_BBIO_SPI: self.spidev = SPI(major, minor) self.spidev.bpw = 8 try: self.spidev.msh = 10000000 # Maximum supported by NRF24L01+ except IOError: pass # Hardware does not support this speed else: self.spidev = spidev.SpiDev() self.spidev.open(major, minor) self.spidev.bits_per_word = 8 try: self.spidev.max_speed_hz = 10000000 # Maximum supported by NRF24L01+ except IOError: pass # Hardware does not support this speed self.spidev.cshigh = False self.spidev.mode = 0 self.spidev.loop = False self.spidev.lsbfirst = False self.spidev.threewire = False # Save pin numbers self.ce_pin = ce_pin self.irq_pin = irq_pin # If CE pin is not used, CE signal must be always high if self.ce_pin is not None: GPIO.setup(self.ce_pin, GPIO.OUT) # IRQ pin is optional if self.irq_pin is not None: GPIO.setup(self.irq_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) time.sleep(5 / 1000000.0) # Reset radio registers self.reset() # Restore our default PA level self.setPALevel(NRF24.PA_MAX) # Determine if this is a p or non-p RF24 module and then # reset our data rate back to default value. This works # because a non-P variant won't allow the data rate to # be set to 250Kbps. self.p_variant = False # False for RF24L01 and true for RF24L01P if self.setDataRate(NRF24.BR_250KBPS): self.p_variant = True # Then set the data rate to the slowest (and most reliable) speed supported by all # hardware. self.setDataRate(NRF24.BR_1MBPS) # Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier # WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet # sizes must never be used. See documentation for a more complete explanation. # This must be done after setDataRate() self.setRetries(int('0101', 2), 15) # Line bellow will set maximum (4ms) delay #self.setRetries(15, 15) # Initialize CRC and request 2-byte (16bit) CRC self.setCRCLength(NRF24.CRC_16) # Disable dynamic payloads, to match dynamic_payloads_enabled setting self.write_register(NRF24.DYNPD, 0) # Set up default configuration. Callers can always change it later. # This channel should be universally safe and not bleed over into adjacent # spectrum. self.channel = 76 self.setChannel(self.channel) # Powers up the radio, this can take up to 4.5ms # when CE is low radio will be in standby and will initiate # reception or transmission very shortly after CE is raised # If CE pin is not used, will Power up only on startListening and stopListening if self.ce_pin is not None: self.powerUp() # Reset current status # Notice reset and flush is the last thing we do self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) # Flush buffers self.flush_rx() self.flush_tx() self.clear_irq_flags() def end(self): """ End use of the radio """ self.ce(0) if self.spidev: self.powerDown() self.spidev.close() self.spidev = None def startListening(self): """ Set radio for reception Use openReadingPipe to set up reception pipes before listening """ self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP | NRF24.PRIM_RX) self.flush_tx() self.flush_rx() self.clear_irq_flags() # Restore the pipe0 address, if exists if self.pipe0_reading_address: self.write_register(self.RX_ADDR_P0, self.pipe0_reading_address) # Go! self.ce(1) # wait for the radio to come up if self.ce_pin is None: time.sleep(45 / 10000.0) # 4.5 ms else: time.sleep(130 / 1000000.0) # 130us def ce(self, level, pulse=0): """ Controls CE pin """ # CE Pin is optional (but highly recommended) if self.ce_pin is not None: GPIO.output(self.ce_pin, level) if pulse > 0: time.sleep(pulse) GPIO.output(self.ce_pin, 1 - level) def irqWait(self, timeout=30000): """ Wait for IRQ pin LOW, timeout in miliseconds """ if self.irq_pin is None: return True # TODO: A race condition may occur here. => wait for level? if GPIO.input(self.irq_pin) == 0: # Pin is already down. Packet is waiting? return True try: return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING, timeout) == 1 except TypeError: # Timeout parameter not supported return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING) == 1 except AttributeError: raise RuntimeError("GPIO lib does not support wait_for_edge()") def read_register(self, reg, length=1): """ Read one or more registers """ buf = [NRF24.R_REGISTER | (NRF24.REGISTER_MASK & reg)] buf += [NRF24.NOP] * max(1, length) resp = self.spidev.xfer2(buf) if length == 1: return resp[1] return resp[1:] def write_register(self, reg, value): """ Write register value """ buf = [NRF24.W_REGISTER | (NRF24.REGISTER_MASK & reg)] buf += self._to_8b_list(value) self.spidev.xfer2(buf) def write_payload(self, buf): """ Writes data to the payload register, automatically padding it to match the required length. Returns the number of bytes actually written. """ buf = self._to_8b_list(buf) if self.dynamic_payloads_enabled: if len(buf) > self.MAX_PAYLOAD_SIZE: raise RuntimeError("Dynamic payload is larger than the " + "maximum size.") blank_len = 0 else: if len(buf) > self.payload_size: raise RuntimeError("Payload is larger than the fixed payload" + "size (%d vs. %d bytes)" % (len(buf), self.payload_size)) blank_len = self.payload_size - len(buf) txbuffer = [NRF24.W_TX_PAYLOAD] + buf + ([0x00] * blank_len) self.spidev.xfer2(txbuffer) return len(txbuffer) - 1 def read_payload(self, buf, buf_len=-1): """ Reads data from the payload register and clears the DR bit of the STATUS register. """ if buf_len < 0: buf_len = self.payload_size if not self.dynamic_payloads_enabled: data_len = min(self.payload_size, buf_len) blank_len = self.payload_size - data_len else: data_len = self.getDynamicPayloadSize() blank_len = 0 txbuffer = [NRF24.R_RX_PAYLOAD] + [NRF24.NOP] * (blank_len + data_len) payload = self.spidev.xfer2(txbuffer) del buf[:] buf += payload[1:data_len + 1] self.write_register(NRF24.STATUS, NRF24.RX_DR) return data_len def flush_rx(self): """ Flush RX buffer, return status """ return self.spidev.xfer2([NRF24.FLUSH_RX])[0] def flush_tx(self): """ Flush TX buffer, return status """ return self.spidev.xfer2([NRF24.FLUSH_TX])[0] def get_status(self): """ Read status register """ return self.spidev.xfer2([NRF24.NOP])[0] def print_status(self, status): """ Print decoded status """ status_str = "0x{0:02x} RX_DR={1:x} TX_DS={2:x} MAX_RT={3:x} RX_P_NO={4:x} TX_FULL={5:x}".format( status, 1 if status & NRF24.RX_DR else 0, 1 if status & NRF24.TX_DS else 0, 1 if status & NRF24.MAX_RT else 0, ((status >> NRF24.RX_P_NO) & int("111", 2)), 1 if status & NRF24.TX_FULL else 0) self.print_single_status_line("STATUS", status_str) def print_observe_tx(self, value): """ Print decoded observe_tx register: lost packets (accumulated) and retransmited packets (last tx) """ tx_str = "OBSERVE_TX=0x{0:02x}: POLS_CNT={2:x} ARC_CNT={2:x}\r\n".format( value, (value >> NRF24.PLOS_CNT) & int("1111", 2), (value >> NRF24.ARC_CNT) & int("1111", 2)) self.print_single_status_line("OBSERVE_TX", tx_str) def print_byte_register(self, name, reg, qty=1): """ Print byte registers """ registers = ["0x{:0>2x}".format(self.read_register(reg+r)) for r in range(0, qty)] self.print_single_status_line(name, " ".join(registers)) def print_address_register(self, name, reg, qty=1): """ Print address register (LSB to MSB) """ address_registers = ["0x{0:>02x}{1:>02x}{2:>02x}{3:>02x}{4:>02x}".format( *self.read_register(reg+r, 5)) for r in range(qty)] self.print_single_status_line(name, " ".join(address_registers)) def setChannel(self, channel): """ Set radio channel (0 to MAX_CHANNEL) """ if channel < 0 or channel > self.MAX_CHANNEL: raise RuntimeError("Channel number out of range") self.channel = channel self.write_register(NRF24.RF_CH, channel) def getChannel(self): """ Read channel register """ return self.read_register(NRF24.RF_CH) def setPayloadSize(self, size): """ Set payload size """ self.payload_size = min(max(size, 1), NRF24.MAX_PAYLOAD_SIZE) def getPayloadSize(self): """ Get payload size """ return self.payload_size def printDetails(self): """ Prints register values and other information """ self.print_status(self.get_status()) self.print_address_register("RX_ADDR_P0-1", NRF24.RX_ADDR_P0, 2) self.print_byte_register("RX_ADDR_P2-5", NRF24.RX_ADDR_P2, 4) self.print_address_register("TX_ADDR", NRF24.TX_ADDR) self.print_byte_register("RX_PW_P0-6", NRF24.RX_PW_P0, 6) self.print_byte_register("EN_AA", NRF24.EN_AA) self.print_byte_register("EN_RXADDR", NRF24.EN_RXADDR) self.print_byte_register("RF_CH", NRF24.RF_CH) self.print_byte_register("RF_SETUP", NRF24.RF_SETUP) self.print_byte_register("SETUP_AW", NRF24.SETUP_AW) self.print_byte_register("OBSERVE_TX", NRF24.OBSERVE_TX) self.print_byte_register("CONFIG", NRF24.CONFIG) self.print_byte_register("FIFO_STATUS", NRF24.FIFO_STATUS) self.print_byte_register("DYNPD", NRF24.DYNPD) self.print_byte_register("FEATURE", NRF24.FEATURE) self.print_single_status_line("Data Rate", NRF24.datarate_e_str_P[self.getDataRate()]) self.print_single_status_line("Model", NRF24.model_e_str_P[self.isPVariant()]) self.print_single_status_line("CRC Length", NRF24.crclength_e_str_P[self.getCRCLength()]) self.print_single_status_line("PA Power", NRF24.pa_dbm_e_str_P[self.getPALevel()]) def stopListening(self): """ Stop listenning and set up transmission """ self.ce(0) self.flush_tx() self.flush_rx() self.clear_irq_flags() # Enable TX self.write_register(NRF24.CONFIG, (self.read_register(NRF24.CONFIG) | NRF24.PWR_UP) & ~NRF24.PRIM_RX) # Enable pipe 0 for auto-ack self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | 1) # wait for the radio to come up if self.ce_pin is None: time.sleep(45 / 10000.0) # 4.5 ms else: time.sleep(130 / 1000000.0) # 130us def powerDown(self): """ Power down radio """ self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) & ~ NRF24.PWR_UP) def powerUp(self): """ Power up radio """ self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP) time.sleep(4.5e-3) def write(self, buf): """ Sends buf and wait for end of transmission and acknowledgement call stopListenning and openWritingPipe before sending buf can be a single int or a container of char or int """ self.last_error = None length = self.write_payload(buf) self.ce(1) sent_at = monotonic() packet_time = ((1 + length + self.crc_length + self.address_length) * 8 + 9)/(self.data_rate_bits * 1000.) if self.auto_ack != 0: packet_time *= 2 if self.retries != 0 and self.auto_ack != 0: timeout = sent_at + (packet_time + self.delay)*self.retries else: timeout = sent_at + packet_time * 2 # 2 is empiric while monotonic() < timeout: time.sleep(packet_time) status = self.get_status() if status & NRF24.TX_DS: self.ce(0) return True if status & NRF24.MAX_RT: self.last_error = 'MAX_RT' self.ce(0) break self.ce(0) if self.last_error is None: self.last_error = 'TIMEOUT' self.flush_tx() # Avoid leaving the payload in tx fifo return False def startFastWrite(self, buf): """ Starts sending of buf but do not wait for end of transmission. CE is left high.""" self.write_payload(buf) self.ce(1) def startWrite(self, buf): """ Starts sending of buf but do not wait for end of transmission. CE is pulsed.""" self.write_payload(buf) self.ce(1, 10e-6) # Pulse CE to start tranmission def getDynamicPayloadSize(self): """ Reads the size of received payload when using dynamic payloads """ return self.spidev.xfer2([NRF24.R_RX_PL_WID, NRF24.NOP])[1] def available(self, pipe_num=None, irq_wait=False, irq_timeout=30000): """ Tests if there is a reception available pipe_num should be None or a list. If not None, it will receive information on pipes with available data. if irq_wait is True, will wait for IRQ line to change from HIGH to LOW irq_timeout is the timeout for this wait, in miliseconds """ status = self.get_status() result = False # Sometimes the radio specifies that there is data in one pipe but # doesn't set the RX flag... if status & NRF24.RX_DR or (status & NRF24.RX_P_NO_MASK != NRF24.RX_P_NO_MASK): result = True else: if irq_wait: # Will use IRQ wait if self.irqWait(irq_timeout): # Do we have a packet? status = self.get_status() # Seems like we do! if status & NRF24.RX_DR or (status & NRF24.RX_P_NO_MASK != NRF24.RX_P_NO_MASK): result = True if pipe_num is not None: del pipe_num[:] if result: pipe_num.append((status & NRF24.RX_P_NO_MASK) >> NRF24.RX_P_NO) # Handle ack payload receipt if status & NRF24.TX_DS: self.write_register(NRF24.STATUS, NRF24.TX_DS) return result def read(self, buf, buf_len=-1): """ Read payload from received packet. Returns != 0 if there are more packets in the FIFO. """ # Fetch the payload self.read_payload(buf, buf_len) # was this the last of the data available? return self.read_register(NRF24.FIFO_STATUS) & NRF24.RXFIFO_EMPTY def clear_irq_flags(self): """ Clear flags in status register. """ self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) def whatHappened(self): """ Read the status & reset the status in one easy call Returns a dictionary informing tx_ok, tx_fail and rx_ready """ status = self.spidev.xfer2(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT)[0] # Report to the user what happened tx_ok = status & NRF24.TX_DS tx_fail = status & NRF24.MAX_RT rx_ready = status & NRF24.RX_DR return {'tx_ok': tx_ok, "tx_fail": tx_fail, "rx_ready": rx_ready} def openWritingPipe(self, address): """ Sets tx address address is the address in transmited packet (2 to 5 bytes), LSB to MSB """ self.write_register(NRF24.RX_ADDR_P0, address) self.write_register(NRF24.TX_ADDR, address) if not self.dynamic_payloads_enabled: self.write_register(NRF24.RX_PW_P0, self.payload_size) def openReadingPipe(self, pipe, address): """ Sets rx address for a pipe and enables it for recieving pipe should be 0 to 5 address is the address for pipe 0 or 1, 2 to 5 bytes LSB to MSB for pipes 2 to 5, 1 byte (LSB, MSB cames from pipe 1) """ if pipe >= 6: raise RuntimeError("Invalid pipe number") if (pipe >= 2 and len(address) > 1) or len(address) > 5: raise RuntimeError("Invalid adress length") # If this is pipe 0, cache the address. This is needed because # openWritingPipe() will overwrite the pipe 0 address, so # startListening() will have to restore it. if pipe == 0: self.pipe0_reading_address = address self.write_register(NRF24.RX_ADDR_P0 + pipe, address) if not self.dynamic_payloads_enabled: self.write_register(NRF24.RX_PW_P0 + pipe, self.payload_size) # Note it would be more efficient to set all of the bits for all open # pipes at once. However, I thought it would make the calling code # more simple to do it this way. self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | (1 << pipe)) def closeReadingPipe(self, pipe): """ Disabe a receiving pipe """ self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) & ~(1 << pipe)) def toggle_features(self): """ Enable DUNPD and FEATURE registers on non P variant """ buf = [NRF24.ACTIVATE, 0x73] self.spidev.xfer2(buf) def enableDynamicPayloads(self): """ Enables dynamic size payloads """ # First try writing to the features self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_DPL) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_DPL) # Enable dynamic payload on all pipes # Not sure the use case of only having dynamic payload on certain # pipes, so the library does not support it. self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | 0b00111111) self.dynamic_payloads_enabled = True def enableAckPayload(self): """ Enable ack payload and dynamic payload features """ # First try writing to the features self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_ACK_PAY | NRF24.EN_DPL) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_ACK_PAY | NRF24.EN_DPL) # Enable dynamic payload on pipes 0 & 1 self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | NRF24.DPL_P1 | NRF24.DPL_P0) def writeAckPayload(self, pipe, buf, buf_len): """ Write payload for acknowledgement """ txbuffer = [NRF24.W_ACK_PAYLOAD | (pipe & 0x7)] max_payload_size = 32 data_len = min(buf_len, max_payload_size) txbuffer.extend(buf[0:data_len]) self.spidev.xfer2(txbuffer) def isAckPayloadAvailable(self): """ Check if there is a payload in a acknowledgement. Note: this will clear the ack payload flag. """ result = self.ack_payload_available self.ack_payload_available = False return result def isPVariant(self): """ Returns true if nRF24L01+, False if nRF24L01 """ return self.p_variant def setAutoAck(self, enable): """ Enable or disable auto acknoledge for all pipes """ if enable: self.write_register(NRF24.EN_AA, 0x3F) self.auto_ack = 0x3f if self.self.getCRCLength() == NFR24.CRC_DISABLED: self.setCRCLength(NRF24.CRC_8) # Enhanced Shockburst requires at least 1 byte CRC else: self.auto_ack = 0 self.write_register(NRF24.EN_AA, 0) def setAutoAckPipe(self, pipe, enable): """ Enable or disable auto acknoledge for an specific pipe """ if pipe <= 6: en_aa = self.read_register(NRF24.EN_AA) if enable: if self.self.getCRCLength() == NFR24.CRC_DISABLED: self.setCRCLength(NRF24.CRC_8) # Enhanced Shockburst requires at least 1 byte CRC en_aa |= 1 << pipe self.auto_ack |= 1 << pipe else: en_aa &= ~1 << pipe self.auto_ack &= ~1 << pipe self.write_register(NRF24.EN_AA, en_aa) def setAddressWidth(self, width): """ Set address width (2 to 5 bytes) """ if width >= 2 and width <= 5: self.write_register(NRF24.SETUP_AW, width - 2) self.address_width = width def testCarrier(self): """ Tests if there is a radio signal at current channel. """ return self.read_register(NRF24.RPD) & 1 def setPALevel(self, level): """ Set transmission level """ setup = self.read_register(NRF24.RF_SETUP) setup &= ~(NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH) if level == NRF24.PA_MAX: setup |= NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH elif level == NRF24.PA_HIGH: setup |= NRF24.RF_PWR_HIGH elif level == NRF24.PA_LOW: setup |= NRF24.RF_PWR_LOW elif level == NRF24.PA_MIN: pass elif level == NRF24.PA_ERROR: # On error, go to maximum PA setup |= NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH self.write_register(NRF24.RF_SETUP, setup) def getPALevel(self): """ Inform current transmission level """ power = self.read_register(NRF24.RF_SETUP) & (NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH) if power == (NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH): return NRF24.PA_MAX elif power == NRF24.RF_PWR_HIGH: return NRF24.PA_HIGH elif power == NRF24.RF_PWR_LOW: return NRF24.PA_LOW else: return NRF24.PA_MIN def setDataRate(self, speed): """ Set data rate. returns True if success. """ setup = self.read_register(NRF24.RF_SETUP) setup &= ~(NRF24.RF_DR_LOW | NRF24.RF_DR_HIGH) if speed == NRF24.BR_250KBPS: # Must set the RF_DR_LOW to 1 RF_DR_HIGH (used to be RF_DR) is already 0 # Making it '10'. self.data_rate_bits = 250 self.data_rate = NRF24.BR_250KBPS setup |= NRF24.RF_DR_LOW elif speed == NRF24.BR_2MBPS: # Set 2Mbs, RF_DR (RF_DR_HIGH) is set 1 # Making it '01' self.data_rate_bits = 2000 self.data_rate = NRF24.BR_2MBPS setup |= NRF24.RF_DR_HIGH else: # 1Mbs self.data_rate_bits = 1000 self.data_rate = NRF24.BR_1MBPS self.write_register(NRF24.RF_SETUP, setup) # Verify our result return self.read_register(NRF24.RF_SETUP) == setup def getDataRate(self): """ Inform current data rate """ dr = self.read_register(NRF24.RF_SETUP) & (NRF24.RF_DR_LOW | NRF24.RF_DR_HIGH) # Order matters in our case below if dr == NRF24.RF_DR_LOW: # '10' = 250KBPS return NRF24.BR_250KBPS elif dr == NRF24.RF_DR_HIGH: # '01' = 2MBPS return NRF24.BR_2MBPS else: # '00' = 1MBPS return NRF24.BR_1MBPS def setCRCLength(self, length): """ Set CRC length length = CRC_DISABLED, CRC_8 or CRC_16 """ config = self.read_register(NRF24.CONFIG) & ~(NRF24.EN_CRC | NRF24.CRCO) if length == NRF24.CRC_DISABLED: self.crc_length = 0 elif length == NRF24.CRC_8: config |= NRF24.EN_CRC self.crc_length = 1 else: config |= NRF24.EN_CRC config |= NRF24.CRCO self.crc_length = 2 self.write_register(NRF24.CONFIG, config) def getCRCLength(self): """ Get CRC length returns CRC_DISABLED, CRC_8 or CRC_16 """ result = NRF24.CRC_DISABLED config = self.read_register(NRF24.CONFIG) & (NRF24.CRCO | NRF24.EN_CRC) if config & NRF24.EN_CRC: if config & NRF24.CRCO: result = NRF24.CRC_16 else: result = NRF24.CRC_8 return result def disableCRC(self): """ Disable CRC """ disable = self.read_register(NRF24.CONFIG) & ~NRF24.EN_CRC self.write_register(NRF24.CONFIG, disable) def setRetries(self, delay, count): """ Set timeout and number of retries delay (timeout) 0-15 as per datasheet count 0-15 max number of retries (0=disable retries)""" self.write_register(NRF24.SETUP_RETR, (delay & 0xf) << NRF24.ARD | (count & 0xf) << NRF24.ARC) self.delay = delay * 0.000250 self.retries = count self.max_timeout = (self.payload_size / float(self.data_rate_bits) + self.delay) * self.retries self.timeout = (self.payload_size / float(self.data_rate_bits) + self.delay) def getRetries(self): """ Return current retry configuration. """ return self.read_register(NRF24.SETUP_RETR) def getMaxTimeout(self): """ Return current maximum timeout (no ack after all retries). """ return self.max_timeout def getTimeout(self): """ Return current timeout for one transmission. """ return self.timeout def reset(self): """ Make sure the NRF is in the same state as after power up to avoid problems resulting from left over configuration from other programs.""" self.ce(0) reset_values = {0: 0x08, 1: 0x3F, 2: 0x03, 3: 0x03, 4: 0x03, 5: 0x02, 6: 0x0e, 0x0a: [0xe7, 0xe7, 0xe7, 0xe7, 0xe7], 0x0b: [0xc2, 0xc2, 0xc2, 0xc2, 0xc2], 0x0c: 0xc3, 0x0d: 0xc4, 0x0e: 0xc5, 0x0f: 0xc6, 0x10: [0xe7, 0xe7, 0xe7, 0xe7, 0xe7], 0x11: 0, 0x12: 0, 0x13: 0, 0x14: 0, 0x15: 0, 0x16: 0, 0x1c: 0, 0x1d: 0} for reg, value in reset_values.items(): self.write_register(reg, value) self.flush_rx() self.flush_tx()
class NRF24: MAX_CHANNEL = 127 MAX_PAYLOAD_SIZE = 32 # PA Levels PA_MIN = 0 PA_LOW = 1 PA_HIGH = 2 PA_MAX = 3 PA_ERROR = 4 # Bit rates BR_1MBPS = 0 BR_2MBPS = 1 BR_250KBPS = 2 # CRC CRC_DISABLED = 0 CRC_8 = 1 CRC_16 = 2 CRC_ENABLED = 3 # Registers CONFIG = 0x00 EN_AA = 0x01 EN_RXADDR = 0x02 SETUP_AW = 0x03 SETUP_RETR = 0x04 RF_CH = 0x05 RF_SETUP = 0x06 STATUS = 0x07 OBSERVE_TX = 0x08 CD = 0x09 RX_ADDR_P0 = 0x0A RX_ADDR_P1 = 0x0B RX_ADDR_P2 = 0x0C RX_ADDR_P3 = 0x0D RX_ADDR_P4 = 0x0E RX_ADDR_P5 = 0x0F TX_ADDR = 0x10 RX_PW_P0 = 0x11 RX_PW_P1 = 0x12 RX_PW_P2 = 0x13 RX_PW_P3 = 0x14 RX_PW_P4 = 0x15 RX_PW_P5 = 0x16 FIFO_STATUS = 0x17 DYNPD = 0x1C FEATURE = 0x1D # Bit Mnemonics */ MASK_RX_DR = 6 MASK_TX_DS = 5 MASK_MAX_RT = 4 EN_CRC = 3 CRCO = 2 PWR_UP = 1 PRIM_RX = 0 ENAA_P5 = 5 ENAA_P4 = 4 ENAA_P3 = 3 ENAA_P2 = 2 ENAA_P1 = 1 ENAA_P0 = 0 ERX_P5 = 5 ERX_P4 = 4 ERX_P3 = 3 ERX_P2 = 2 ERX_P1 = 1 ERX_P0 = 0 AW = 0 ARD = 4 ARC = 0 PLL_LOCK = 4 RF_DR = 3 RF_PWR = 6 RX_DR = 6 TX_DS = 5 MAX_RT = 4 RX_P_NO = 1 TX_FULL = 0 PLOS_CNT = 4 ARC_CNT = 0 TX_REUSE = 6 FIFO_FULL = 5 TX_EMPTY = 4 RX_FULL = 1 RX_EMPTY = 0 DPL_P5 = 5 DPL_P4 = 4 DPL_P3 = 3 DPL_P2 = 2 DPL_P1 = 1 DPL_P0 = 0 EN_DPL = 2 EN_ACK_PAY = 1 EN_DYN_ACK = 0 # Instruction Mnemonics R_REGISTER = 0x00 W_REGISTER = 0x20 REGISTER_MASK = 0x1F ACTIVATE = 0x50 R_RX_PL_WID = 0x60 R_RX_PAYLOAD = 0x61 W_TX_PAYLOAD = 0xA0 W_ACK_PAYLOAD = 0xA8 FLUSH_TX = 0xE1 FLUSH_RX = 0xE2 REUSE_TX_PL = 0xE3 NOP = 0xFF # Non-P omissions LNA_HCURR = 0x00 # P model memory Map RPD = 0x09 # P model bit Mnemonics RF_DR_LOW = 5 RF_DR_HIGH = 3 RF_PWR_LOW = 1 RF_PWR_HIGH = 2 # Signal Mnemonics LOW = 0 HIGH = 1 datarate_e_str_P = ["1MBPS", "2MBPS", "250KBPS"] model_e_str_P = ["nRF24L01", "nRF24l01+"] crclength_e_str_P = ["Disabled", "8 bits", "16 bits"] pa_dbm_e_str_P = ["PA_MIN", "PA_LOW", "PA_MED", "PA_HIGH"] child_pipe = [ RX_ADDR_P0, RX_ADDR_P1, RX_ADDR_P2, RX_ADDR_P3, RX_ADDR_P4, RX_ADDR_P5 ] child_payload_size = [ RX_PW_P0, RX_PW_P1, RX_PW_P2, RX_PW_P3, RX_PW_P4, RX_PW_P5 ] child_pipe_enable = [ERX_P0, ERX_P1, ERX_P2, ERX_P3, ERX_P4, ERX_P5] def __init__(self): self.ce_pin = "P9_15" self.irq_pin = "P9_16" self.channel = 76 self.data_rate = NRF24.BR_1MBPS self.wide_band = False # 2Mbs data rate in use? self.p_variant = False # False for RF24L01 and true for RF24L01P self.payload_size = 5 #*< Fixed size of payloads self.ack_payload_available = False #*< Whether there is an ack payload waiting self.dynamic_payloads_enabled = False #*< Whether dynamic payloads are enabled. self.ack_payload_length = 5 #*< Dynamic size of pending ack payload. self.pipe0_reading_address = None #*< Last address set on pipe 0 for reading. self.spidev = None def ce(self, level): if level == NRF24.HIGH: GPIO.output(self.ce_pin, GPIO.HIGH) else: GPIO.output(self.ce_pin, GPIO.LOW) return def irqWait(self, timeout=30000): # CHANGE: detect module name because wait_for_edge is not available in # other libraries if GPIO.__name__ != "Adafruit_BBIO.GPIO": return False # TODO: A race condition may occur here. if GPIO.input( self.irq_pin) == 0: # Pin is already down. Packet is waiting? return True return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING, timeout) == 1 def read_register(self, reg, blen=1): buf = [NRF24.R_REGISTER | (NRF24.REGISTER_MASK & reg)] for col in range(blen): buf.append(NRF24.NOP) resp = self.spidev.xfer2(buf) if blen == 1: return resp[1] return resp[1:blen + 1] def write_register(self, reg, value, length=-1): buf = [NRF24.W_REGISTER | (NRF24.REGISTER_MASK & reg)] if isinstance(value, (int, long)): if length < 0: length = 1 length = min(4, length) for i in range(length): buf.insert(1, int(value & 0xff)) value >>= 8 elif isinstance(value, list): if length < 0: length = len(value) for i in range(min(len(value), length)): buf.append(int(value[len(value) - i - 1] & 0xff)) else: raise Exception("Value must be int or list") return self.spidev.xfer2(buf)[0] def write_payload(self, buf): data_len = min(self.payload_size, len(buf)) blank_len = 0 if not self.dynamic_payloads_enabled: blank_len = self.payload_size - data_len txbuffer = [NRF24.W_TX_PAYLOAD] for n in buf: t = type(n) if t is str: txbuffer.append(ord(n)) elif t is int: txbuffer.append(n) else: raise Exception("Only ints and chars are supported: Found " + str(t)) if blank_len != 0: blank = [0x00 for i in range(blank_len)] txbuffer.extend(blank) return self.spidev.xfer2(txbuffer) def read_payload(self, buf, buf_len=-1): if buf_len < 0: buf_len = self.payload_size data_len = min(self.payload_size, buf_len) blank_len = 0 if not self.dynamic_payloads_enabled: blank_len = self.payload_size - data_len txbuffer = [NRF24.NOP for i in range(0, blank_len + data_len + 1)] txbuffer[0] = NRF24.R_RX_PAYLOAD payload = self.spidev.xfer2(txbuffer) del buf[:] buf.extend(payload[1:data_len + 1]) return data_len def flush_rx(self): return self.spidev.xfer2([NRF24.FLUSH_RX])[0] def flush_tx(self): return self.spidev.xfer2([NRF24.FLUSH_TX])[0] def get_status(self): return self.spidev.xfer2([NRF24.NOP])[0] def print_status(self, status): status_str = "STATUS\t = 0x{0:02x} RX_DR={1:x} TX_DS={2:x} MAX_RT={3:x} RX_P_NO={4:x} TX_FULL={5:x}".format( status, 1 if status & _BV(NRF24.RX_DR) else 0, 1 if status & _BV(NRF24.TX_DS) else 0, 1 if status & _BV(NRF24.MAX_RT) else 0, ((status >> NRF24.RX_P_NO) & int("111", 2)), 1 if status & _BV(NRF24.TX_FULL) else 0) print status_str def print_observe_tx(self, value): tx_str = "OBSERVE_TX=0x{0:02x}: POLS_CNT={2:x} ARC_CNT={2:x}\r\n".format( value, (value >> NRF24.PLOS_CNT) & int("1111", 2), (value >> NRF24.ARC_CNT) & int("1111", 2)) print tx_str def print_byte_register(self, name, reg, qty=1): extra_tab = '\t' if len(name) < 8 else 0 print "%s\t%c =" % (name, extra_tab), while qty > 0: print "0x%02x" % (self.read_register(reg)), qty -= 1 reg += 1 print "" def print_address_register(self, name, reg, qty=1): extra_tab = '\t' if len(name) < 8 else 0 print "%s\t%c =" % (name, extra_tab), while qty > 0: qty -= 1 buf = reversed(self.read_register(reg, 5)) reg += 1 sys.stdout.write(" 0x"), for i in buf: sys.stdout.write("%02x" % i) print "" def setChannel(self, channel): self.channel = min(max(0, channel), NRF24.MAX_CHANNEL) self.write_register(NRF24.RF_CH, self.channel) def getChannel(self): return self.read_register(NRF24.RF_CH) def setPayloadSize(self, size): self.payload_size = min(max(size, 1), NRF24.MAX_PAYLOAD_SIZE) def getPayloadSize(self): return self.payload_size def printDetails(self): self.print_status(self.get_status()) self.print_address_register("RX_ADDR_P0-1", NRF24.RX_ADDR_P0, 2) self.print_byte_register("RX_ADDR_P2-5", NRF24.RX_ADDR_P2, 4) self.print_address_register("TX_ADDR", NRF24.TX_ADDR) self.print_byte_register("RX_PW_P0-6", NRF24.RX_PW_P0, 6) self.print_byte_register("EN_AA", NRF24.EN_AA) self.print_byte_register("EN_RXADDR", NRF24.EN_RXADDR) self.print_byte_register("RF_CH", NRF24.RF_CH) self.print_byte_register("RF_SETUP", NRF24.RF_SETUP) self.print_byte_register("CONFIG", NRF24.CONFIG) self.print_byte_register("DYNPD/FEATURE", NRF24.DYNPD, 2) # print "Data Rate\t = %s" % NRF24.datarate_e_str_P[self.getDataRate()] print "Model\t\t = %s" % NRF24.model_e_str_P[self.isPVariant()] print "CRC Length\t = %s" % NRF24.crclength_e_str_P[ self.getCRCLength()] print "PA Power\t = %s" % NRF24.pa_dbm_e_str_P[self.getPALevel()] def begin(self, major, minor, ce_pin, irq_pin): # Initialize SPI bus self.spidev = SPI(major, minor) self.ce_pin = ce_pin self.irq_pin = irq_pin GPIO.setup(self.ce_pin, GPIO.OUT) GPIO.setup(self.irq_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) time.sleep(5 / 1000000.0) # Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier # WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet # sizes must never be used. See documentation for a more complete explanation. self.write_register(NRF24.SETUP_RETR, (int('0100', 2) << NRF24.ARD) | (int('1111', 2) << NRF24.ARC)) # Restore our default PA level self.setPALevel(NRF24.PA_MAX) # Determine if this is a p or non-p RF24 module and then # reset our data rate back to default value. This works # because a non-P variant won't allow the data rate to # be set to 250Kbps. if self.setDataRate(NRF24.BR_250KBPS): self.p_variant = True # Then set the data rate to the slowest (and most reliable) speed supported by all # hardware. self.setDataRate(NRF24.BR_1MBPS) # Initialize CRC and request 2-byte (16bit) CRC self.setCRCLength(NRF24.CRC_16) # Disable dynamic payloads, to match dynamic_payloads_enabled setting self.write_register(NRF24.DYNPD, 0) # Reset current status # Notice reset and flush is the last thing we do self.write_register( NRF24.STATUS, _BV(NRF24.RX_DR) | _BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT)) # Set up default configuration. Callers can always change it later. # This channel should be universally safe and not bleed over into adjacent # spectrum. self.setChannel(self.channel) # Flush buffers self.flush_rx() self.flush_tx() def end(self): if self.spidev: self.spidev.close() self.spidev = None def startListening(self): self.write_register( NRF24.CONFIG, self.read_register(NRF24.CONFIG) | _BV(NRF24.PWR_UP) | _BV(NRF24.PRIM_RX)) self.write_register( NRF24.STATUS, _BV(NRF24.RX_DR) | _BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT)) # Restore the pipe0 address, if exists if self.pipe0_reading_address: self.write_register(self.RX_ADDR_P0, self.pipe0_reading_address, 5) # Go! self.ce(NRF24.HIGH) # wait for the radio to come up (130us actually only needed) time.sleep(130 / 1000000.0) def stopListening(self): self.ce(NRF24.LOW) self.flush_tx() self.flush_rx() def powerDown(self): self.write_register( NRF24.CONFIG, self.read_register(NRF24.CONFIG) & ~_BV(NRF24.PWR_UP)) def powerUp(self): self.write_register( NRF24.CONFIG, self.read_register(NRF24.CONFIG) | _BV(NRF24.PWR_UP)) time.sleep(150 / 1000000.0) def write(self, buf): # Begin the write self.startWrite(buf) timeout = self.getMaxTimeout() #s to wait for timeout sent_at = time.time() while True: #status = self.read_register(NRF24.OBSERVE_TX, 1) status = self.get_status() if (status & (_BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT))) or ( time.time() - sent_at > timeout): break time.sleep(10 / 1000000.0) what = self.whatHappened() result = what['tx_ok'] # Handle the ack packet if what['rx_ready']: self.ack_payload_length = self.getDynamicPayloadSize() return result def startWrite(self, buf): # Transmitter power-up self.write_register( NRF24.CONFIG, (self.read_register(NRF24.CONFIG) | _BV(NRF24.PWR_UP)) & ~_BV(NRF24.PRIM_RX)) # Send the payload self.write_payload(buf) # Allons! self.ce(NRF24.HIGH) time.sleep(10 / 1000000.0) self.ce(NRF24.LOW) def getDynamicPayloadSize(self): return self.spidev.xfer2([NRF24.R_RX_PL_WID, NRF24.NOP])[1] def available(self, pipe_num=None, irq_wait=False, irq_timeout=30000): if not pipe_num: pipe_num = [] status = self.get_status() result = False # Sometimes the radio specifies that there is data in one pipe but # doesn't set the RX flag... if status & _BV(NRF24.RX_DR) or (status & 0b00001110 != 0b00001110): result = True else: if irq_wait: # Will use IRQ wait if self.irqWait(irq_timeout): # Do we have a packet? status = self.get_status() # Seems like we do! if status & _BV(NRF24.RX_DR) or (status & 0b00001110 != 0b00001110): result = True if result: # If the caller wants the pipe number, include that if len(pipe_num) >= 1: pipe_num[0] = (status >> NRF24.RX_P_NO) & 0b00000111 # Clear the status bit # ??? Should this REALLY be cleared now? Or wait until we # actually READ the payload? self.write_register(NRF24.STATUS, _BV(NRF24.RX_DR)) # Handle ack payload receipt if status & _BV(NRF24.TX_DS): self.write_register(NRF24.STATUS, _BV(NRF24.TX_DS)) return result def read(self, buf, buf_len=-1): # Fetch the payload self.read_payload(buf, buf_len) # was this the last of the data available? return self.read_register(NRF24.FIFO_STATUS) & _BV(NRF24.RX_EMPTY) def whatHappened(self): # Read the status & reset the status in one easy call # Or is that such a good idea? status = self.write_register( NRF24.STATUS, _BV(NRF24.RX_DR) | _BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT)) # Report to the user what happened tx_ok = status & _BV(NRF24.TX_DS) tx_fail = status & _BV(NRF24.MAX_RT) rx_ready = status & _BV(NRF24.RX_DR) return {'tx_ok': tx_ok, "tx_fail": tx_fail, "rx_ready": rx_ready} def openWritingPipe(self, value): # Note that the NRF24L01(+) # expects it LSB first. self.write_register(NRF24.RX_ADDR_P0, value, 5) self.write_register(NRF24.TX_ADDR, value, 5) max_payload_size = 32 self.write_register(NRF24.RX_PW_P0, min(self.payload_size, max_payload_size)) def openReadingPipe(self, child, address): # If this is pipe 0, cache the address. This is needed because # openWritingPipe() will overwrite the pipe 0 address, so # startListening() will have to restore it. if child == 0: self.pipe0_reading_address = address if child <= 6: # For pipes 2-5, only write the LSB if child < 2: self.write_register(NRF24.child_pipe[child], address, 5) else: self.write_register(NRF24.child_pipe[child], address, 1) self.write_register(NRF24.child_payload_size[child], self.payload_size) # Note it would be more efficient to set all of the bits for all open # pipes at once. However, I thought it would make the calling code # more simple to do it this way. self.write_register( NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | _BV(NRF24.child_pipe_enable[child])) def closeReadingPipe(self, pipe): self.write_register( NRF24.EN_RXADDR, self.read_register(EN_RXADDR) & ~_BV(NRF24.child_pipe_enable[pipe])) def toggle_features(self): buf = [NRF24.ACTIVATE, 0x73] self.spidev.xfer2(buf) def enableDynamicPayloads(self): # Enable dynamic payload throughout the system self.write_register( NRF24.FEATURE, self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_DPL)) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register( NRF24.FEATURE, self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_DPL)) # Enable dynamic payload on all pipes # Not sure the use case of only having dynamic payload on certain # pipes, so the library does not support it. self.write_register( NRF24.DYNPD, self.read_register(NRF24.DYNPD) | _BV(NRF24.DPL_P5) | _BV(NRF24.DPL_P4) | _BV(NRF24.DPL_P3) | _BV(NRF24.DPL_P2) | _BV(NRF24.DPL_P1) | _BV(NRF24.DPL_P0)) self.dynamic_payloads_enabled = True def enableAckPayload(self): # enable ack payload and dynamic payload features self.write_register( NRF24.FEATURE, self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_ACK_PAY) | _BV(NRF24.EN_DPL)) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register( NRF24.FEATURE, self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_ACK_PAY) | _BV(NRF24.EN_DPL)) # Enable dynamic payload on pipes 0 & 1 self.write_register( NRF24.DYNPD, self.read_register(NRF24.DYNPD) | _BV(NRF24.DPL_P1) | _BV(NRF24.DPL_P0)) def writeAckPayload(self, pipe, buf, buf_len): txbuffer = [NRF24.W_ACK_PAYLOAD | (pipe & 0x7)] max_payload_size = 32 data_len = min(buf_len, max_payload_size) txbuffer.extend(buf[0:data_len]) self.spidev.xfer2(txbuffer) def isAckPayloadAvailable(self): result = self.ack_payload_available self.ack_payload_available = False return result def isPVariant(self): return self.p_variant def setAutoAck(self, enable): if enable: self.write_register(NRF24.EN_AA, int('111111', 2)) else: self.write_register(NRF24.EN_AA, 0) def setAutoAckPipe(self, pipe, enable): if pipe <= 6: en_aa = self.read_register(NRF24.EN_AA) if enable: en_aa |= _BV(pipe) else: en_aa &= ~_BV(pipe) self.write_register(NRF24.EN_AA, en_aa) def testCarrier(self): return self.read_register(NRF24.CD) & 1 def testRPD(self): return self.read_register(NRF24.RPD) & 1 def setPALevel(self, level): setup = self.read_register(NRF24.RF_SETUP) setup &= ~(_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH)) # switch uses RAM (evil!) if level == NRF24.PA_MAX: setup |= (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH)) elif level == NRF24.PA_HIGH: setup |= _BV(NRF24.RF_PWR_HIGH) elif level == NRF24.PA_LOW: setup |= _BV(NRF24.RF_PWR_LOW) elif level == NRF24.PA_MIN: nop = 0 elif level == NRF24.PA_ERROR: # On error, go to maximum PA setup |= (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH)) self.write_register(NRF24.RF_SETUP, setup) def getPALevel(self): power = self.read_register( NRF24.RF_SETUP) & (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH)) if power == (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH)): return NRF24.PA_MAX elif power == _BV(NRF24.RF_PWR_HIGH): return NRF24.PA_HIGH elif power == _BV(NRF24.RF_PWR_LOW): return NRF24.PA_LOW else: return NRF24.PA_MIN def setDataRate(self, speed): result = False setup = self.read_register(NRF24.RF_SETUP) # HIGH and LOW '00' is 1Mbs - our default self.wide_band = False setup &= ~(_BV(NRF24.RF_DR_LOW) | _BV(NRF24.RF_DR_HIGH)) if speed == NRF24.BR_250KBPS: # Must set the RF_DR_LOW to 1 RF_DR_HIGH (used to be RF_DR) is already 0 # Making it '10'. self.wide_band = False setup |= _BV(NRF24.RF_DR_LOW) else: # Set 2Mbs, RF_DR (RF_DR_HIGH) is set 1 # Making it '01' if speed == NRF24.BR_2MBPS: self.wide_band = True setup |= _BV(NRF24.RF_DR_HIGH) else: # 1Mbs self.wide_band = False self.write_register(NRF24.RF_SETUP, setup) # Verify our result if self.read_register(NRF24.RF_SETUP) == setup: result = True else: self.wide_band = False return result def getDataRate(self): dr = self.read_register( NRF24.RF_SETUP) & (_BV(NRF24.RF_DR_LOW) | _BV(NRF24.RF_DR_HIGH)) # Order matters in our case below if dr == _BV(NRF24.RF_DR_LOW): # '10' = 250KBPS return NRF24.BR_250KBPS elif dr == _BV(NRF24.RF_DR_HIGH): # '01' = 2MBPS return NRF24.BR_2MBPS else: # '00' = 1MBPS return NRF24.BR_1MBPS def setCRCLength(self, length): config = self.read_register( NRF24.CONFIG) & ~(_BV(NRF24.CRC_16) | _BV(NRF24.CRC_ENABLED)) if length == NRF24.CRC_DISABLED: # Do nothing, we turned it off above. self.write_register(NRF24.CONFIG, config) return elif length == NRF24.CRC_8: config |= _BV(NRF24.CRC_ENABLED) config |= _BV(NRF24.CRC_8) else: config |= _BV(NRF24.CRC_ENABLED) config |= _BV(NRF24.CRC_16) self.write_register(NRF24.CONFIG, config) def getCRCLength(self): result = NRF24.CRC_DISABLED config = self.read_register( NRF24.CONFIG) & (_BV(NRF24.CRCO) | _BV(NRF24.EN_CRC)) if config & _BV(NRF24.EN_CRC): if config & _BV(NRF24.CRCO): result = NRF24.CRC_16 else: result = NRF24.CRC_8 return result def disableCRC(self): disable = self.read_register(NRF24.CONFIG) & ~_BV(NRF24.EN_CRC) self.write_register(NRF24.CONFIG, disable) def setRetries(self, delay, count): self.write_register(NRF24.SETUP_RETR, (delay & 0xf) << NRF24.ARD | (count & 0xf) << NRF24.ARC) def getRetries(self): return self.read_register(NRF24.SETUP_RETR) def getMaxTimeout(self): retries = self.getRetries() return ((250 + (250 * ((retries & 0xf0) >> 4))) * (retries & 0x0f)) / 1000000.0
#!/usr/bin/python from Adafruit_BBIO.SPI import SPI spi = SPI(0,0) spi.lsbfirst=False spi.msh=1000000 spi.cshigh=False spi.xfer2([0x36]) spi.cshigh=True for reg in range(0x0,0x3d+1,1): spi.cshigh=False send = [ reg+0xc0 , 0x0 ] recv = spi.xfer2(send) spi.cshigh=True print reg,recv patable=9*[0] patable[0]=0x3e+0xc0 spi.cshigh=False dd = spi.xfer2(patable) spi.cshigh=True print 0x3e,dd rxfifo=65*[0] rxfifo[0]=0x3f+0xc0
from Adafruit_BBIO.SPI import SPI import Adafruit_BBIO.GPIO as GPIO import time spi = SPI(0, 0) #4 busses, this is bus 0 spi.msh = 10000 #Frequency spi.bpw = 8 #bits per word spi.cshigh = False #true means you select the chip, depends on the chip, here low means active, normally Low for IMU spi.threewire = False #if it is true, you just read, otherwise you also send commands spi.lsbfirst = False #Least significant bit first (left) spi.open(0, 0) #open #GPIO.setup("P8_11",GPIO.OUT) #GPIO.output("P8_11",GPIO.HIGH) try: while True: res = spi.xfer2([0xFFFF, 0xFFFF]) #deliver two bytes res1 = spi.readbytes(2) #Read 2 bytes angle = (res1[0] << 8) | res1[1] #merge leftbyte and rightbyte angle1 = angle & 0x3FFF #move the first two bits angle2 = float(angle1) / 16363 * 360 print("data is") print(angle2) time.sleep(.25) except KeyboardInterrupt: spi.close()
from Adafruit_BBIO.SPI import SPI # From Adafruit Learning System: # https://learn.adafruit.com/setting-up-io-python-library-on-beaglebone-black/spi #spi = SPI(bus, device) #/dev/spidev<bus>.<device> #spi = SPI(0,0) #/dev/spidev1.0 #spi = SPI(0,1) #/dev/spidev1.1 #spi = SPI(1,0) #/dev/spidev2.0 #spi = SPI(1,1) #/dev/spidev2.1 spi = SPI(0, 0) print spi.xfer2([32, 11, 110, 22, 220]) spi.close()
class NRF24: MAX_CHANNEL = 127 MAX_PAYLOAD_SIZE = 32 # PA Levels PA_MIN = 0 PA_LOW = 1 PA_HIGH = 2 PA_MAX = 3 PA_ERROR = 4 # Bit rates BR_1MBPS = 0 BR_2MBPS = 1 BR_250KBPS = 2 # CRC CRC_DISABLED = 0 CRC_8 = 1 CRC_16 = 2 CRC_ENABLED = 3 # Registers CONFIG = 0x00 EN_AA = 0x01 EN_RXADDR = 0x02 SETUP_AW = 0x03 SETUP_RETR = 0x04 RF_CH = 0x05 RF_SETUP = 0x06 STATUS = 0x07 OBSERVE_TX = 0x08 CD = 0x09 RX_ADDR_P0 = 0x0A RX_ADDR_P1 = 0x0B RX_ADDR_P2 = 0x0C RX_ADDR_P3 = 0x0D RX_ADDR_P4 = 0x0E RX_ADDR_P5 = 0x0F TX_ADDR = 0x10 RX_PW_P0 = 0x11 RX_PW_P1 = 0x12 RX_PW_P2 = 0x13 RX_PW_P3 = 0x14 RX_PW_P4 = 0x15 RX_PW_P5 = 0x16 FIFO_STATUS = 0x17 DYNPD = 0x1C FEATURE = 0x1D # Bit Mnemonics */ MASK_RX_DR = 6 MASK_TX_DS = 5 MASK_MAX_RT = 4 EN_CRC = 3 CRCO = 2 PWR_UP = 1 PRIM_RX = 0 ENAA_P5 = 5 ENAA_P4 = 4 ENAA_P3 = 3 ENAA_P2 = 2 ENAA_P1 = 1 ENAA_P0 = 0 ERX_P5 = 5 ERX_P4 = 4 ERX_P3 = 3 ERX_P2 = 2 ERX_P1 = 1 ERX_P0 = 0 AW = 0 ARD = 4 ARC = 0 PLL_LOCK = 4 RF_DR = 3 RF_PWR = 6 RX_DR = 6 TX_DS = 5 MAX_RT = 4 RX_P_NO = 1 TX_FULL = 0 PLOS_CNT = 4 ARC_CNT = 0 TX_REUSE = 6 FIFO_FULL = 5 TX_EMPTY = 4 RX_FULL = 1 RX_EMPTY = 0 DPL_P5 = 5 DPL_P4 = 4 DPL_P3 = 3 DPL_P2 = 2 DPL_P1 = 1 DPL_P0 = 0 EN_DPL = 2 EN_ACK_PAY = 1 EN_DYN_ACK = 0 # Instruction Mnemonics R_REGISTER = 0x00 W_REGISTER = 0x20 REGISTER_MASK = 0x1F ACTIVATE = 0x50 R_RX_PL_WID = 0x60 R_RX_PAYLOAD = 0x61 W_TX_PAYLOAD = 0xA0 W_ACK_PAYLOAD = 0xA8 FLUSH_TX = 0xE1 FLUSH_RX = 0xE2 REUSE_TX_PL = 0xE3 NOP = 0xFF # Non-P omissions LNA_HCURR = 0x00 # P model memory Map RPD = 0x09 # P model bit Mnemonics RF_DR_LOW = 5 RF_DR_HIGH = 3 RF_PWR_LOW = 1 RF_PWR_HIGH = 2 # Signal Mnemonics LOW = 0 HIGH = 1 datarate_e_str_P = ["1MBPS", "2MBPS", "250KBPS"] model_e_str_P = ["nRF24L01", "nRF24l01+"] crclength_e_str_P = ["Disabled", "8 bits", "16 bits"] pa_dbm_e_str_P = ["PA_MIN", "PA_LOW", "PA_MED", "PA_HIGH"] child_pipe = [RX_ADDR_P0, RX_ADDR_P1, RX_ADDR_P2, RX_ADDR_P3, RX_ADDR_P4, RX_ADDR_P5] child_payload_size = [RX_PW_P0, RX_PW_P1, RX_PW_P2, RX_PW_P3, RX_PW_P4, RX_PW_P5] child_pipe_enable = [ERX_P0, ERX_P1, ERX_P2, ERX_P3, ERX_P4, ERX_P5] def __init__(self): self.ce_pin = "P9_15" self.irq_pin = "P9_16" self.channel = 76 self.data_rate = NRF24.BR_1MBPS self.wide_band = False # 2Mbs data rate in use? self.p_variant = False # False for RF24L01 and true for RF24L01P self.payload_size = 5 #*< Fixed size of payloads self.ack_payload_available = False #*< Whether there is an ack payload waiting self.dynamic_payloads_enabled = False #*< Whether dynamic payloads are enabled. self.ack_payload_length = 5 #*< Dynamic size of pending ack payload. self.pipe0_reading_address = None #*< Last address set on pipe 0 for reading. self.spidev = None def ce(self, level): if level == NRF24.HIGH: GPIO.output(self.ce_pin, GPIO.HIGH) else: GPIO.output(self.ce_pin, GPIO.LOW) return def irqWait(self, timeout = 30000): # CHANGE: detect module name because wait_for_edge is not available in # other libraries if GPIO.__name__ != "Adafruit_BBIO.GPIO": return False # TODO: A race condition may occur here. if GPIO.input(self.irq_pin) == 0: # Pin is already down. Packet is waiting? return True return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING, timeout) == 1 def read_register(self, reg, blen=1): buf = [NRF24.R_REGISTER | ( NRF24.REGISTER_MASK & reg )] for col in range(blen): buf.append(NRF24.NOP) resp = self.spidev.xfer2(buf) if blen == 1: return resp[1] return resp[1:blen + 1] def write_register(self, reg, value, length=-1): buf = [NRF24.W_REGISTER | ( NRF24.REGISTER_MASK & reg )] if isinstance(value, (int, long)): if length < 0: length = 1 length = min(4, length) for i in range(length): buf.insert(1, int(value & 0xff)) value >>= 8 elif isinstance(value, list): if length < 0: length = len(value) for i in range(min(len(value), length)): buf.append(int(value[len(value) - i - 1] & 0xff)) else: raise Exception("Value must be int or list") return self.spidev.xfer2(buf)[0] def write_payload(self, buf): data_len = min(self.payload_size, len(buf)) blank_len = 0 if not self.dynamic_payloads_enabled: blank_len = self.payload_size - data_len txbuffer = [NRF24.W_TX_PAYLOAD] for n in buf: t = type(n) if t is str: txbuffer.append(ord(n)) elif t is int: txbuffer.append(n) else: raise Exception("Only ints and chars are supported: Found " + str(t)) if blank_len != 0: blank = [0x00 for i in range(blank_len)] txbuffer.extend(blank) return self.spidev.xfer2(txbuffer) def read_payload(self, buf, buf_len=-1): if buf_len < 0: buf_len = self.payload_size data_len = min(self.payload_size, buf_len) blank_len = 0 if not self.dynamic_payloads_enabled: blank_len = self.payload_size - data_len txbuffer = [NRF24.NOP for i in range(0, blank_len + data_len + 1)] txbuffer[0] = NRF24.R_RX_PAYLOAD payload = self.spidev.xfer2(txbuffer) del buf[:] buf.extend(payload[1:data_len + 1]) return data_len def flush_rx(self): return self.spidev.xfer2([NRF24.FLUSH_RX])[0] def flush_tx(self): return self.spidev.xfer2([NRF24.FLUSH_TX])[0] def get_status(self): return self.spidev.xfer2([NRF24.NOP])[0] def print_status(self, status): status_str = "STATUS\t = 0x{0:02x} RX_DR={1:x} TX_DS={2:x} MAX_RT={3:x} RX_P_NO={4:x} TX_FULL={5:x}".format( status, 1 if status & _BV(NRF24.RX_DR) else 0, 1 if status & _BV(NRF24.TX_DS) else 0, 1 if status & _BV(NRF24.MAX_RT) else 0, ((status >> NRF24.RX_P_NO) & int("111", 2)), 1 if status & _BV(NRF24.TX_FULL) else 0) print status_str def print_observe_tx(self, value): tx_str = "OBSERVE_TX=0x{0:02x}: POLS_CNT={2:x} ARC_CNT={2:x}\r\n".format( value, (value >> NRF24.PLOS_CNT) & int("1111",2), (value >> NRF24.ARC_CNT) & int("1111",2) ) print tx_str def print_byte_register(self, name, reg, qty=1): extra_tab = '\t' if len(name) < 8 else 0 print "%s\t%c =" % (name, extra_tab), while qty > 0: print "0x%02x" % (self.read_register(reg)), qty -= 1 reg += 1 print "" def print_address_register(self, name, reg, qty=1): extra_tab = '\t' if len(name) < 8 else 0 print "%s\t%c =" % (name, extra_tab), while qty > 0: qty -= 1 buf = reversed(self.read_register(reg, 5)) reg += 1 sys.stdout.write(" 0x"), for i in buf: sys.stdout.write("%02x" % i) print "" def setChannel(self, channel): self.channel = min(max(0, channel), NRF24.MAX_CHANNEL) self.write_register(NRF24.RF_CH, self.channel) def getChannel(self): return self.read_register(NRF24.RF_CH) def setPayloadSize(self, size): self.payload_size = min(max(size, 1), NRF24.MAX_PAYLOAD_SIZE) def getPayloadSize(self): return self.payload_size def printDetails(self): self.print_status(self.get_status()) self.print_address_register("RX_ADDR_P0-1", NRF24.RX_ADDR_P0, 2) self.print_byte_register("RX_ADDR_P2-5", NRF24.RX_ADDR_P2, 4) self.print_address_register("TX_ADDR", NRF24.TX_ADDR) self.print_byte_register("RX_PW_P0-6", NRF24.RX_PW_P0, 6) self.print_byte_register("EN_AA", NRF24.EN_AA) self.print_byte_register("EN_RXADDR", NRF24.EN_RXADDR) self.print_byte_register("RF_CH", NRF24.RF_CH) self.print_byte_register("RF_SETUP", NRF24.RF_SETUP) self.print_byte_register("CONFIG", NRF24.CONFIG) self.print_byte_register("DYNPD/FEATURE", NRF24.DYNPD, 2) # print "Data Rate\t = %s" % NRF24.datarate_e_str_P[self.getDataRate()] print "Model\t\t = %s" % NRF24.model_e_str_P[self.isPVariant()] print "CRC Length\t = %s" % NRF24.crclength_e_str_P[self.getCRCLength()] print "PA Power\t = %s" % NRF24.pa_dbm_e_str_P[self.getPALevel()] def begin(self, major, minor, ce_pin, irq_pin): # Initialize SPI bus self.spidev = SPI(major, minor) self.ce_pin = ce_pin self.irq_pin = irq_pin GPIO.setup(self.ce_pin, GPIO.OUT) GPIO.setup(self.irq_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) time.sleep(5 / 1000000.0) # Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier # WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet # sizes must never be used. See documentation for a more complete explanation. self.write_register(NRF24.SETUP_RETR, (int('0100', 2) << NRF24.ARD) | (int('1111', 2) << NRF24.ARC)) # Restore our default PA level self.setPALevel(NRF24.PA_MAX) # Determine if this is a p or non-p RF24 module and then # reset our data rate back to default value. This works # because a non-P variant won't allow the data rate to # be set to 250Kbps. if self.setDataRate(NRF24.BR_250KBPS): self.p_variant = True # Then set the data rate to the slowest (and most reliable) speed supported by all # hardware. self.setDataRate(NRF24.BR_1MBPS) # Initialize CRC and request 2-byte (16bit) CRC self.setCRCLength(NRF24.CRC_16) # Disable dynamic payloads, to match dynamic_payloads_enabled setting self.write_register(NRF24.DYNPD, 0) # Reset current status # Notice reset and flush is the last thing we do self.write_register(NRF24.STATUS, _BV(NRF24.RX_DR) | _BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT)) # Set up default configuration. Callers can always change it later. # This channel should be universally safe and not bleed over into adjacent # spectrum. self.setChannel(self.channel) # Flush buffers self.flush_rx() self.flush_tx() def end(self): if self.spidev: self.spidev.close() self.spidev = None def startListening(self): self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | _BV(NRF24.PWR_UP) | _BV(NRF24.PRIM_RX)) self.write_register(NRF24.STATUS, _BV(NRF24.RX_DR) | _BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT)) # Restore the pipe0 address, if exists if self.pipe0_reading_address: self.write_register(self.RX_ADDR_P0, self.pipe0_reading_address, 5) # Go! self.ce(NRF24.HIGH) # wait for the radio to come up (130us actually only needed) time.sleep(130 / 1000000.0) def stopListening(self): self.ce(NRF24.LOW) self.flush_tx() self.flush_rx() def powerDown(self): self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) & ~_BV(NRF24.PWR_UP)) def powerUp(self): self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | _BV(NRF24.PWR_UP)) time.sleep(150 / 1000000.0) def write(self, buf): # Begin the write self.startWrite(buf) timeout = self.getMaxTimeout() #s to wait for timeout sent_at = time.time() while True: #status = self.read_register(NRF24.OBSERVE_TX, 1) status = self.get_status() if (status & (_BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT))) or (time.time() - sent_at > timeout ): break time.sleep(10 / 1000000.0) what = self.whatHappened() result = what['tx_ok'] # Handle the ack packet if what['rx_ready']: self.ack_payload_length = self.getDynamicPayloadSize() return result def startWrite(self, buf): # Transmitter power-up self.write_register(NRF24.CONFIG, (self.read_register(NRF24.CONFIG) | _BV(NRF24.PWR_UP) ) & ~_BV(NRF24.PRIM_RX)) # Send the payload self.write_payload(buf) # Allons! self.ce(NRF24.HIGH) time.sleep(10 / 1000000.0) self.ce(NRF24.LOW) def getDynamicPayloadSize(self): return self.spidev.xfer2([NRF24.R_RX_PL_WID, NRF24.NOP])[1] def available(self, pipe_num=None, irq_wait=False, irq_timeout=30000): if not pipe_num: pipe_num = [] status = self.get_status() result = False # Sometimes the radio specifies that there is data in one pipe but # doesn't set the RX flag... if status & _BV(NRF24.RX_DR) or (status & 0b00001110 != 0b00001110): result = True else: if irq_wait: # Will use IRQ wait if self.irqWait(irq_timeout): # Do we have a packet? status = self.get_status() # Seems like we do! if status & _BV(NRF24.RX_DR) or (status & 0b00001110 != 0b00001110): result = True if result: # If the caller wants the pipe number, include that if len(pipe_num) >= 1: pipe_num[0] = ( status >> NRF24.RX_P_NO ) & 0b00000111 # Clear the status bit # ??? Should this REALLY be cleared now? Or wait until we # actually READ the payload? self.write_register(NRF24.STATUS, _BV(NRF24.RX_DR)) # Handle ack payload receipt if status & _BV(NRF24.TX_DS): self.write_register(NRF24.STATUS, _BV(NRF24.TX_DS)) return result def read(self, buf, buf_len=-1): # Fetch the payload self.read_payload(buf, buf_len) # was this the last of the data available? return self.read_register(NRF24.FIFO_STATUS) & _BV(NRF24.RX_EMPTY) def whatHappened(self): # Read the status & reset the status in one easy call # Or is that such a good idea? status = self.write_register(NRF24.STATUS, _BV(NRF24.RX_DR) | _BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT)) # Report to the user what happened tx_ok = status & _BV(NRF24.TX_DS) tx_fail = status & _BV(NRF24.MAX_RT) rx_ready = status & _BV(NRF24.RX_DR) return {'tx_ok': tx_ok, "tx_fail": tx_fail, "rx_ready": rx_ready} def openWritingPipe(self, value): # Note that the NRF24L01(+) # expects it LSB first. self.write_register(NRF24.RX_ADDR_P0, value, 5) self.write_register(NRF24.TX_ADDR, value, 5) max_payload_size = 32 self.write_register(NRF24.RX_PW_P0, min(self.payload_size, max_payload_size)) def openReadingPipe(self, child, address): # If this is pipe 0, cache the address. This is needed because # openWritingPipe() will overwrite the pipe 0 address, so # startListening() will have to restore it. if child == 0: self.pipe0_reading_address = address if child <= 6: # For pipes 2-5, only write the LSB if child < 2: self.write_register(NRF24.child_pipe[child], address, 5) else: self.write_register(NRF24.child_pipe[child], address, 1) self.write_register(NRF24.child_payload_size[child], self.payload_size) # Note it would be more efficient to set all of the bits for all open # pipes at once. However, I thought it would make the calling code # more simple to do it this way. self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | _BV(NRF24.child_pipe_enable[child])) def closeReadingPipe(self, pipe): self.write_register(NRF24.EN_RXADDR, self.read_register(EN_RXADDR) & ~_BV(NRF24.child_pipe_enable[pipe])) def toggle_features(self): buf = [NRF24.ACTIVATE, 0x73] self.spidev.xfer2(buf) def enableDynamicPayloads(self): # Enable dynamic payload throughout the system self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_DPL)) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_DPL)) # Enable dynamic payload on all pipes # Not sure the use case of only having dynamic payload on certain # pipes, so the library does not support it. self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | _BV(NRF24.DPL_P5) | _BV(NRF24.DPL_P4) | _BV( NRF24.DPL_P3) | _BV(NRF24.DPL_P2) | _BV(NRF24.DPL_P1) | _BV(NRF24.DPL_P0)) self.dynamic_payloads_enabled = True def enableAckPayload(self): # enable ack payload and dynamic payload features self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_ACK_PAY) | _BV(NRF24.EN_DPL)) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_ACK_PAY) | _BV(NRF24.EN_DPL)) # Enable dynamic payload on pipes 0 & 1 self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | _BV(NRF24.DPL_P1) | _BV(NRF24.DPL_P0)) def writeAckPayload(self, pipe, buf, buf_len): txbuffer = [NRF24.W_ACK_PAYLOAD | ( pipe & 0x7 )] max_payload_size = 32 data_len = min(buf_len, max_payload_size) txbuffer.extend(buf[0:data_len]) self.spidev.xfer2(txbuffer) def isAckPayloadAvailable(self): result = self.ack_payload_available self.ack_payload_available = False return result def isPVariant(self): return self.p_variant def setAutoAck(self, enable): if enable: self.write_register(NRF24.EN_AA, int('111111',2)) else: self.write_register(NRF24.EN_AA, 0) def setAutoAckPipe(self, pipe, enable): if pipe <= 6: en_aa = self.read_register(NRF24.EN_AA) if enable: en_aa |= _BV(pipe) else: en_aa &= ~_BV(pipe) self.write_register(NRF24.EN_AA, en_aa) def testCarrier(self): return self.read_register(NRF24.CD) & 1 def testRPD(self): return self.read_register(NRF24.RPD) & 1 def setPALevel(self, level): setup = self.read_register(NRF24.RF_SETUP) setup &= ~( _BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH)) # switch uses RAM (evil!) if level == NRF24.PA_MAX: setup |= (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH)) elif level == NRF24.PA_HIGH: setup |= _BV(NRF24.RF_PWR_HIGH) elif level == NRF24.PA_LOW: setup |= _BV(NRF24.RF_PWR_LOW) elif level == NRF24.PA_MIN: nop = 0 elif level == NRF24.PA_ERROR: # On error, go to maximum PA setup |= (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH)) self.write_register(NRF24.RF_SETUP, setup) def getPALevel(self): power = self.read_register(NRF24.RF_SETUP) & (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH)) if power == (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH)): return NRF24.PA_MAX elif power == _BV(NRF24.RF_PWR_HIGH): return NRF24.PA_HIGH elif power == _BV(NRF24.RF_PWR_LOW): return NRF24.PA_LOW else: return NRF24.PA_MIN def setDataRate(self, speed): result = False setup = self.read_register(NRF24.RF_SETUP) # HIGH and LOW '00' is 1Mbs - our default self.wide_band = False setup &= ~(_BV(NRF24.RF_DR_LOW) | _BV(NRF24.RF_DR_HIGH)) if speed == NRF24.BR_250KBPS: # Must set the RF_DR_LOW to 1 RF_DR_HIGH (used to be RF_DR) is already 0 # Making it '10'. self.wide_band = False setup |= _BV(NRF24.RF_DR_LOW) else: # Set 2Mbs, RF_DR (RF_DR_HIGH) is set 1 # Making it '01' if speed == NRF24.BR_2MBPS: self.wide_band = True setup |= _BV(NRF24.RF_DR_HIGH) else: # 1Mbs self.wide_band = False self.write_register(NRF24.RF_SETUP, setup) # Verify our result if self.read_register(NRF24.RF_SETUP) == setup: result = True else: self.wide_band = False return result def getDataRate(self): dr = self.read_register(NRF24.RF_SETUP) & (_BV(NRF24.RF_DR_LOW) | _BV(NRF24.RF_DR_HIGH)) # Order matters in our case below if dr == _BV(NRF24.RF_DR_LOW): # '10' = 250KBPS return NRF24.BR_250KBPS elif dr == _BV(NRF24.RF_DR_HIGH): # '01' = 2MBPS return NRF24.BR_2MBPS else: # '00' = 1MBPS return NRF24.BR_1MBPS def setCRCLength(self, length): config = self.read_register(NRF24.CONFIG) & ~( _BV(NRF24.CRC_16) | _BV(NRF24.CRC_ENABLED)) if length == NRF24.CRC_DISABLED: # Do nothing, we turned it off above. self.write_register(NRF24.CONFIG, config) return elif length == NRF24.CRC_8: config |= _BV(NRF24.CRC_ENABLED) config |= _BV(NRF24.CRC_8) else: config |= _BV(NRF24.CRC_ENABLED) config |= _BV(NRF24.CRC_16) self.write_register(NRF24.CONFIG, config) def getCRCLength(self): result = NRF24.CRC_DISABLED config = self.read_register(NRF24.CONFIG) & ( _BV(NRF24.CRCO) | _BV(NRF24.EN_CRC)) if config & _BV(NRF24.EN_CRC): if config & _BV(NRF24.CRCO): result = NRF24.CRC_16 else: result = NRF24.CRC_8 return result def disableCRC(self): disable = self.read_register(NRF24.CONFIG) & ~_BV(NRF24.EN_CRC) self.write_register(NRF24.CONFIG, disable) def setRetries(self, delay, count): self.write_register(NRF24.SETUP_RETR, (delay & 0xf) << NRF24.ARD | (count & 0xf) << NRF24.ARC) def getRetries(self): return self.read_register(NRF24.SETUP_RETR) def getMaxTimeout(self): retries = self.getRetries() return ((250+(250*((retries& 0xf0)>>4 ))) * (retries & 0x0f)) / 1000000.0
from Adafruit_BBIO.SPI import SPI command = sys.argv[1] WALK = 1 WALK_BACK = 31 STOP = 15 TURNL = 3 TURNR = 7 spi = SPI(0,0) spi.msh = 57600 spi.bpw = 8 #for debugging with keyboard input #command = raw_input(); spi.xfer2([getCommandCode(command)]) spi.close() def getCommandCode(command): if command == 'walk': print("Walk!") return WALK elif command == 'back': print('Reverse') return WALK_BACK elif command == 'stop': print('Stop!') return STOP elif command == 'left': print('Turn Left') return TURNL
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ simple test for SPI adafruit-BBIO. https://learn.adafruit.com/setting-up-io-python-library-on-beaglebone-black/spi """ from Adafruit_BBIO.SPI import SPI #spi = SPI(bus, device) #/dev/spidev<bus>.<device> # /dev/spidev0.0 spi = SPI(1, 0) print(spi.xfer2([32, 11, 110, 22, 220])) spi.close() print("Hello BBIO SPI!")
spi.open(0,0) #spi.msh = 100000 spi.bpw = 8 #spi.mode = b00 try: #while True: # set CS bit high, choose first channel to read from #channel = 0; #adc = spi.xfer([1,8,0]) #data = ((adc[1]&3) << 8) + adc[2] channelSelect = 0xC0 channelSelect |= 0x18 channelSelect <<= 3 fsr = spi.xfer2([channelSelect, 0x00, 0x00]) #result = spi.readbytes(2) #result2 = spi.readbytes(1) resultFinal = 0x0000 resultFinal = 0x0300 & (resultFinal | (fsr[1] << 8 )) resultFinal |= ( ( 0x00FF & fsr[2]) ) #print (8 + channel ) << 4 #print resultFinal ################################### #################################### resultFinal = 1 #temp file = open('methane_test.txt', 'r') data = [] #data.append(str(resultFinal) + '\n')
class NRF24: MAX_CHANNEL = 127 MAX_PAYLOAD_SIZE = 32 # PA Levels PA_MIN = 0x00 PA_LOW = 0x01 PA_HIGH = 0x02 PA_MAX = 0x03 PA_ERROR = 0x04 # Bit rates BR_1MBPS = 0 BR_2MBPS = 1 BR_250KBPS = 2 # CRC CRC_DISABLED = 0x0 CRC_8 = 0x02 CRC_16 = 0x04 CRC_ENABLED = 0x08 EN_CRC = 0x08 CRCO = 0x04 # Registers CONFIG = 0x00 EN_AA = 0x01 EN_RXADDR = 0x02 SETUP_AW = 0x03 SETUP_RETR = 0x04 RF_CH = 0x05 RF_SETUP = 0x06 STATUS = 0x07 OBSERVE_TX = 0x08 RPD = 0x09 RX_ADDR_P0 = 0x0A RX_ADDR_P1 = 0x0B RX_ADDR_P2 = 0x0C RX_ADDR_P3 = 0x0D RX_ADDR_P4 = 0x0E RX_ADDR_P5 = 0x0F TX_ADDR = 0x10 RX_PW_P0 = 0x11 RX_PW_P1 = 0x12 RX_PW_P2 = 0x13 RX_PW_P3 = 0x14 RX_PW_P4 = 0x15 RX_PW_P5 = 0x16 FIFO_STATUS = 0x17 DYNPD = 0x1C FEATURE = 0x1D # Bit Mnemonics */ MASK_RX_DR = 0x40 MASK_TX_DS = 0x20 MASK_MAX_RT = 0x10 PWR_UP = 0x02 PRIM_RX = 0x01 PLL_LOCK = 0x10 RX_DR = 0x40 TX_DS = 0x20 MAX_RT = 0x10 TX_FULL = 0x01 EN_DPL = 0x04 EN_ACK_PAY = 0x02 EN_DYN_ACK = 0x01 # Shift counts ARD = 4 ARC = 0 PLOS_CNT = 4 ARC_CNT = 0 RX_P_NO = 1 TX_REUSE = 6 FIFO_FULL = 5 TX_EMPTY = 4 RX_FULL = 1 RX_EMPTY = 0 DPL_P5 = 5 DPL_P4 = 4 DPL_P3 = 3 DPL_P2 = 2 DPL_P1 = 1 DPL_P0 = 0 #Masks RX_P_NO_MASK = 0x0E # Instruction Mnemonics R_REGISTER = 0x00 W_REGISTER = 0x20 REGISTER_MASK = 0x1F ACTIVATE = 0x50 R_RX_PL_WID = 0x60 R_RX_PAYLOAD = 0x61 W_TX_PAYLOAD = 0xA0 W_ACK_PAYLOAD = 0xA8 FLUSH_TX = 0xE1 FLUSH_RX = 0xE2 REUSE_TX_PL = 0xE3 NOP = 0xFF # Non-P omissions LNA_HCURR = 0x01 LNA_ON = 1 LNA_OFF = 0 # P model bit Mnemonics RF_DR_LOW = 0x20 RF_DR_HIGH = 0x08 RF_PWR_LOW = 0x02 RF_PWR_HIGH = 0x04 datarate_e_str_P = ["1MBPS", "2MBPS", "250KBPS"] model_e_str_P = ["nRF24L01", "nRF24l01+"] crclength_e_str_P = ["Disabled", "", "8 bits", "", "16 bits"] pa_dbm_e_str_P = ["PA_MIN", "PA_LOW", "PA_HIGH", "PA_MAX"] @staticmethod def print_single_status_line(name, value): print("{0:<16}= {1}".format(name, value)) @staticmethod def _to_8b_list(data): """Convert an arbitray iteratable or single int to a list of ints where each int is smaller than 256.""" if isinstance(data, str): data = [ord(x) for x in data] elif isinstance(data, (int, long)): data = [data] else: data = [int(x) for x in data] #for byte in data: # if byte < 0 or byte > 255: # raise RuntimeError("Value %d is larger than 8 bits" % byte) return data def __init__(self, major=None, minor=None, ce_pin=None, irq_pin=None): self.ce_pin = "P9_15" self.irq_pin = "P9_16" self.channel = 76 self.data_rate = NRF24.BR_1MBPS self.data_rate_bits = 1000 self.p_variant = False # False for RF24L01 and true for RF24L01P self.payload_size = 5 # *< Fixed size of payloads self.ack_payload_available = False # *< Whether there is an ack payload waiting self.dynamic_payloads_enabled = False # *< Whether dynamic payloads are enabled. self.ack_payload_length = 5 # *< Dynamic size of pending ack payload. self.pipe0_reading_address = None # *< Last address set on pipe 0 for reading. self.spidev = None self.last_error = 0 self.crc_length = 0 self.auto_ack = 0x3F self.address_length = 5 # If all parameters are available, lets start the radio! if major is not None and minor is not None and irq_pin is not None: self.begin(major, minor, ce_pin, irq_pin) def begin(self, major, minor, ce_pin, irq_pin): # Initialize SPI bus if ADAFRUID_BBIO_SPI: self.spidev = SPI(major, minor) self.spidev.bpw = 8 try: self.spidev.msh = 10000000 # Maximum supported by NRF24L01+ except IOError: pass # Hardware does not support this speed else: self.spidev = spidev.SpiDev() self.spidev.open(major, minor) self.spidev.bits_per_word = 8 try: self.spidev.max_speed_hz = 10000000 # Maximum supported by NRF24L01+ except IOError: pass # Hardware does not support this speed self.spidev.cshigh = False self.spidev.mode = 0 self.spidev.loop = False self.spidev.lsbfirst = False self.spidev.threewire = False self.ce_pin = ce_pin self.irq_pin = irq_pin if self.ce_pin is not None: GPIO.setup(self.ce_pin, GPIO.OUT) GPIO.setup(self.irq_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) time.sleep(5 / 1000000.0) # Reset radio configuration self.reset() # Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier # WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet # sizes must never be used. See documentation for a more complete explanation. self.setRetries(int('0101', 2), 15) # Restore our default PA level self.setPALevel(NRF24.PA_MAX) # Determine if this is a p or non-p RF24 module and then # reset our data rate back to default value. This works # because a non-P variant won't allow the data rate to # be set to 250Kbps. if self.setDataRate(NRF24.BR_250KBPS): self.p_variant = True # Then set the data rate to the slowest (and most reliable) speed supported by all # hardware. self.setDataRate(NRF24.BR_1MBPS) # Initialize CRC and request 2-byte (16bit) CRC self.setCRCLength(NRF24.CRC_16) # Disable dynamic payloads, to match dynamic_payloads_enabled setting self.write_register(NRF24.DYNPD, 0) # Reset current status # Notice reset and flush is the last thing we do self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) # Set up default configuration. Callers can always change it later. # This channel should be universally safe and not bleed over into adjacent # spectrum. self.setChannel(self.channel) self.setRetries(15, 15) # Flush buffers self.flush_rx() self.flush_tx() self.clear_irq_flags() def end(self): if self.spidev: self.spidev.close() self.spidev = None def startListening(self): self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP | NRF24.PRIM_RX) self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) self.flush_tx() self.flush_rx() self.clear_irq_flags() # Restore the pipe0 address, if exists if self.pipe0_reading_address: self.write_register(self.RX_ADDR_P0, self.pipe0_reading_address) # Go! self.ce(1) def ce(self, level, pulse=0): # CE Pin is optional if self.ce_pin is not None: GPIO.output(self.ce_pin, level) if pulse > 0: time.sleep(pulse) GPIO.output(self.ce_pin, 1 - level) def irqWait(self, timeout=30000): # TODO: A race condition may occur here. => wait for level? if GPIO.input(self.irq_pin) == 0: # Pin is already down. Packet is waiting? return True try: return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING, timeout) == 1 except TypeError: # Timeout parameter not supported return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING) == 1 except AttributeError: raise RuntimeError("GPIO lib does not support wait_for_edge()") def read_register(self, reg, length=1): buf = [NRF24.R_REGISTER | (NRF24.REGISTER_MASK & reg)] buf += [NRF24.NOP] * max(1, length) resp = self.spidev.xfer2(buf) if length == 1: return resp[1] return resp[1:] def write_register(self, reg, value): """ Write register value """ buf = [NRF24.W_REGISTER | (NRF24.REGISTER_MASK & reg)] buf += self._to_8b_list(value) self.spidev.xfer2(buf) def write_payload(self, buf): """ Writes data to the payload register, automatically padding it to match the required length. Returns the number of bytes actually written. """ buf = self._to_8b_list(buf) if self.dynamic_payloads_enabled: if len(buf) > self.MAX_PAYLOAD_SIZE: raise RuntimeError("Dynamic payload is larger than the " + "maximum size.") blank_len = 0 else: if len(buf) > self.payload_size: raise RuntimeError("Payload is larger than the fixed payload" + "size (%d vs. %d bytes)" % (len(buf), self.payload_size)) blank_len = self.payload_size - len(buf) txbuffer = [NRF24.W_TX_PAYLOAD] + buf + ([0x00] * blank_len) self.spidev.xfer2(txbuffer) return len(txbuffer) - 1 def read_payload(self, buf, buf_len=-1): """ Reads data from the payload register and sets the DR bit of the STATUS register. """ if buf_len < 0: buf_len = self.payload_size if not self.dynamic_payloads_enabled: data_len = min(self.payload_size, buf_len) blank_len = self.payload_size - data_len else: data_len = self.getDynamicPayloadSize() blank_len = 0 txbuffer = [NRF24.R_RX_PAYLOAD] + [NRF24.NOP] * (blank_len + data_len + 1) payload = self.spidev.xfer2(txbuffer) del buf[:] buf += payload[1:data_len + 1] self.write_register(NRF24.STATUS, NRF24.RX_DR) return data_len def flush_rx(self): return self.spidev.xfer2([NRF24.FLUSH_RX])[0] def flush_tx(self): return self.spidev.xfer2([NRF24.FLUSH_TX])[0] def get_status(self): return self.spidev.xfer2([NRF24.NOP])[0] def get_status_str(self, status): status_str = "STATUS\t = 0x{0:02x} RX_DR={1:x} TX_DS={2:x} MAX_RT={3:x} RX_P_NO={4:x} TX_FULL={5:x}".format( status, 1 if status & NRF24.RX_DR else 0, 1 if status & NRF24.TX_DS else 0, 1 if status & NRF24.MAX_RT else 0, ((status >> NRF24.RX_P_NO) & int("111", 2)), 1 if status & NRF24.TX_FULL else 0) return status_str def print_status(self, status): print self.get_status_str(status) def get_observe_tx_str(self, value): tx_str = "OBSERVE_TX=0x{0:02x}: POLS_CNT={2:x} ARC_CNT={2:x}\r\n".format( value, (value >> NRF24.PLOS_CNT) & int("1111",2), (value >> NRF24.ARC_CNT) & int("1111",2) ) return tx_str def print_observe_tx(self, value): print self.get_observe_tx_str(value) def get_byte_register_str(self, name, reg, qty=1): extra_tab = '\t' if len(name) < 8 else 0 byte_str= "%s\t%c =" % (name, extra_tab) while qty > 0: byte_str+= " 0x%02x" % (self.read_register(reg)) qty -= 1 reg += 1 return byte_str def print_byte_register(self, name, reg, qty=1): print self.get_address_register_str(name, reg, qty) def get_address_register_str(self, name, reg, qty=1): extra_tab = '\t' if len(name) < 8 else 0 addr_str = "%s\t%c =" % (name, extra_tab) while qty > 0: qty -= 1 buf = reversed(self.read_register(reg, 5)) reg += 1 addr_str+=" 0x" for i in buf: addr_str+="%02x" % i return addr_str def print_address_register(self, name, reg, qty=1): print self.get_address_register_str(name, reg, qty) self.print_single_status_line(name, " ".join(address_registers)) def setChannel(self, channel): if channel < 0 or channel > self.MAX_CHANNEL: raise RuntimeError("Channel number out of range") self.channel = channel self.write_register(NRF24.RF_CH, channel) def getChannel(self): return self.read_register(NRF24.RF_CH) def setPayloadSize(self, size): self.payload_size = min(max(size, 1), NRF24.MAX_PAYLOAD_SIZE) def getPayloadSize(self): return self.payload_size def getDetails(self): return "\n".join([self.get_status_str(self.get_status()), self.get_address_register_str("RX_ADDR_P0-1", NRF24.RX_ADDR_P0, 2), self.get_byte_register_str("RX_ADDR_P2-5", NRF24.RX_ADDR_P2, 4), self.get_address_register_str("TX_ADDR", NRF24.TX_ADDR), self.get_byte_register_str("RX_PW_P0-6", NRF24.RX_PW_P0, 6), self.get_byte_register_str("EN_AA", NRF24.EN_AA), self.get_byte_register_str("EN_RXADDR", NRF24.EN_RXADDR), self.get_byte_register_str("RF_CH", NRF24.RF_CH), self.get_byte_register_str("RF_SETUP", NRF24.RF_SETUP), self.get_byte_register_str("CONFIG", NRF24.CONFIG), self.get_byte_register_str("DYNPD/FEATURE", NRF24.DYNPD, 2), "Data Rate\t = %s" % NRF24.datarate_e_str_P[self.getDataRate()], "Model\t\t = %s" % NRF24.model_e_str_P[self.isPVariant()], "CRC Length\t = %s" % NRF24.crclength_e_str_P[self.getCRCLength()], "PA Power\t = %s" % NRF24.pa_dbm_e_str_P[self.getPALevel()]]) def printDetails(self): print self.getDetails() def stopListening(self): self.ce(0) self.flush_tx() self.flush_rx() self.clear_irq_flags() # Enable TX self.write_register(NRF24.CONFIG, (self.read_register(NRF24.CONFIG) | NRF24.PWR_UP) & ~NRF24.PRIM_RX) # Enable pipe 0 for auto-ack self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | 1) def powerDown(self): self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) & ~ NRF24.PWR_UP) def powerUp(self): self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP) time.sleep(150e-6) def write(self, buf): self.last_error = None length = self.write_payload(buf) self.ce(1) sent_at = monotonic() packet_time = ((1 + length + self.crc_length + self.address_length) * 8 + 9)/(self.data_rate_bits * 1000.) if self.auto_ack != 0: packet_time *= 2 if self.retries != 0 and self.auto_ack != 0: timeout = sent_at + (packet_time + self.delay)*self.retries else: timeout = sent_at + packet_time * 2 # 2 is empiric #while NRF24.TX_DS & self.get_status() == 0: # pass #print monotonic() - sent_at #print packet_time while monotonic() < timeout: time.sleep(packet_time) status = self.get_status() if status & NRF24.TX_DS: self.ce(0) return True if status & NRF24.MAX_RT: self.last_error = 'MAX_RT' self.ce(0) break self.ce(0) if self.last_error is None: self.last_error = 'TIMEOUT' self.flush_tx() # Avoid leaving the payload in tx fifo return False def startFastWrite(self, buf): """ Do not wait for CE HIGH->LOW """ # Send the payload self.write_payload(buf) self.ce(1) def startWrite(self, buf): # Send the payload self.write_payload(buf) # Allons! self.ce(1, 10e-6) def getDynamicPayloadSize(self): return self.spidev.xfer2([NRF24.R_RX_PL_WID, NRF24.NOP])[1] def available(self, pipe_num=None, irq_wait=False, irq_timeout=30000): status = self.get_status() result = False # Sometimes the radio specifies that there is data in one pipe but # doesn't set the RX flag... if status & NRF24.RX_DR or (status & NRF24.RX_P_NO_MASK != NRF24.RX_P_NO_MASK): result = True else: if irq_wait: # Will use IRQ wait if self.irqWait(irq_timeout): # Do we have a packet? status = self.get_status() # Seems like we do! if status & NRF24.RX_DR or (status & NRF24.RX_P_NO_MASK != NRF24.RX_P_NO_MASK): result = True # read status once again see Note on page 52 or 56 in product specification 1.0 # Note: The 3 bit pipe information in the STATUS register is updated during the IRQ pin high to low #transition. The pipe information is unreliable if the STATUS register is read during an IRQ pin #high to low transition. status = self.get_status() del pipe_num[:] if result and pipe_num is not None: pipe_num.append((status & NRF24.RX_P_NO_MASK) >> NRF24.RX_P_NO) # Handle ack payload receipt if status & NRF24.TX_DS: self.write_register(NRF24.STATUS, NRF24.TX_DS) return result def read(self, buf, buf_len=-1): # Fetch the payload self.read_payload(buf, buf_len) # was this the last of the data available? return self.read_register(NRF24.FIFO_STATUS & NRF24.RX_EMPTY) def clear_irq_flags(self): self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) def whatHappened(self): # Read the status & reset the status in one easy call # Or is that such a good idea? self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) status = self.get_status() self.clear_irq_flags() # Report to the user what happened tx_ok = status & NRF24.TX_DS tx_fail = status & NRF24.MAX_RT rx_ready = status & NRF24.RX_DR return {'tx_ok': tx_ok, "tx_fail": tx_fail, "rx_ready": rx_ready} def openWritingPipe(self, value): # Note that the NRF24L01(+) # expects it LSB first. self.write_register(NRF24.RX_ADDR_P0, value) self.write_register(NRF24.TX_ADDR, value) if not self.dynamic_payloads_enabled: self.write_register(NRF24.RX_PW_P0, self.payload_size) def openReadingPipe(self, pipe, address): # If this is pipe 0, cache the address. This is needed because # openWritingPipe() will overwrite the pipe 0 address, so # startListening() will have to restore it. if pipe >= 6: raise RuntimeError("Invalid pipe number") if (pipe >= 2 and len(address) > 1) or len(address) > 5: raise RuntimeError("Invalid adress length") if pipe == 0: self.pipe0_reading_address = address self.write_register(NRF24.RX_ADDR_P0 + pipe, address) if not self.dynamic_payloads_enabled: self.write_register(NRF24.RX_PW_P0 + pipe, self.payload_size) # Note it would be more efficient to set all of the bits for all open # pipes at once. However, I thought it would make the calling code # more simple to do it this way. self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | (1 << pipe)) def closeReadingPipe(self, pipe): self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) & ~(1 << pipe)) def toggle_features(self): buf = [NRF24.ACTIVATE, 0x73] self.spidev.xfer2(buf) def enableDynamicPayloads(self): # Enable dynamic payload throughout the system self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_DPL) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_DPL) # Enable dynamic payload on all pipes # Not sure the use case of only having dynamic payload on certain # pipes, so the library does not support it. self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | 0b00111111) self.dynamic_payloads_enabled = True def enableAckPayload(self): # enable ack payload and dynamic payload features self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_ACK_PAY | NRF24.EN_DPL) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_ACK_PAY | NRF24.EN_DPL) # Enable dynamic payload on pipes 0 & 1 self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | NRF24.DPL_P1 | NRF24.DPL_P0) def writeAckPayload(self, pipe, buf, buf_len): txbuffer = [NRF24.W_ACK_PAYLOAD | (pipe & 0x7)] max_payload_size = 32 data_len = min(buf_len, max_payload_size) txbuffer.extend(buf[0:data_len]) self.spidev.xfer2(txbuffer) def isAckPayloadAvailable(self): result = self.ack_payload_available self.ack_payload_available = False return result def isPVariant(self): return self.p_variant def setAutoAck(self, enable): if enable: self.write_register(NRF24.EN_AA, 0x3F) self.auto_ack = 0x3f if self.crc_length == 0: self.setCRCLength(NRF24.CRC_8) # Enhanced Shockburst requires at least 1 byte CRC else: self.auto_ack = 0 self.write_register(NRF24.EN_AA, 0) def setAutoAckPipe(self, pipe, enable): if pipe <= 6: en_aa = self.read_register(NRF24.EN_AA) if enable: self.setCRCLength(NRF24.CRC_8) # Enhanced Shockburst requires at least 1 byte CRC en_aa |= 1 << pipe self.auto_ack |= 1 << pipe else: en_aa &= ~1 << pipe self.auto_ack &= ~1 << pipe self.write_register(NRF24.EN_AA, en_aa) def setAddressWidth(self, width): if width >= 2 and width <= 5: self.write_register(NRF24.SETUP_AW, width - 2) self.address_width = width def testCarrier(self): return self.read_register(NRF24.RPD) & 1 def setPALevel(self, level): setup = self.read_register(NRF24.RF_SETUP) setup &= ~(NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH) if level == NRF24.PA_MAX: setup |= NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH elif level == NRF24.PA_HIGH: setup |= NRF24.RF_PWR_HIGH elif level == NRF24.PA_LOW: setup |= NRF24.RF_PWR_LOW elif level == NRF24.PA_MIN: pass elif level == NRF24.PA_ERROR: # On error, go to maximum PA setup |= NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH self.write_register(NRF24.RF_SETUP, setup) def getPALevel(self): power = self.read_register(NRF24.RF_SETUP) & (NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH) if power == (NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH): return NRF24.PA_MAX elif power == NRF24.RF_PWR_HIGH: return NRF24.PA_HIGH elif power == NRF24.RF_PWR_LOW: return NRF24.PA_LOW else: return NRF24.PA_MIN def setDataRate(self, speed): setup = self.read_register(NRF24.RF_SETUP) setup &= ~(NRF24.RF_DR_LOW | NRF24.RF_DR_HIGH) if speed == NRF24.BR_250KBPS: # Must set the RF_DR_LOW to 1 RF_DR_HIGH (used to be RF_DR) is already 0 # Making it '10'. self.data_rate_bits = 250 self.data_rate = NRF24.BR_250KBPS setup |= NRF24.RF_DR_LOW elif speed == NRF24.BR_2MBPS: # Set 2Mbs, RF_DR (RF_DR_HIGH) is set 1 # Making it '01' self.data_rate_bits = 2000 self.data_rate = NRF24.BR_2MBPS setup |= NRF24.RF_DR_HIGH else: # 1Mbs self.data_rate_bits = 1000 self.data_rate = NRF24.BR_1MBPS self.write_register(NRF24.RF_SETUP, setup) # Verify our result return self.read_register(NRF24.RF_SETUP) == setup def getDataRate(self): dr = self.read_register(NRF24.RF_SETUP) & (NRF24.RF_DR_LOW | NRF24.RF_DR_HIGH) # Order matters in our case below if dr == NRF24.RF_DR_LOW: # '10' = 250KBPS return NRF24.BR_250KBPS elif dr == NRF24.RF_DR_HIGH: # '01' = 2MBPS return NRF24.BR_2MBPS else: # '00' = 1MBPS return NRF24.BR_1MBPS def setCRCLength(self, length): config = self.read_register(NRF24.CONFIG) & ~(NRF24.EN_CRC | NRF24.CRCO) if length == NRF24.CRC_DISABLED: self.crc_length = 0 elif length == NRF24.CRC_8: config |= NRF24.EN_CRC config &= ~NRF24.CRCO self.crc_length = 1 else: config |= NRF24.EN_CRC config |= NRF24.CRCO self.crc_length = 2 self.write_register(NRF24.CONFIG, config) def getCRCLength(self): result = NRF24.CRC_DISABLED config = self.read_register(NRF24.CONFIG) & (NRF24.CRCO | NRF24.EN_CRC) if config & NRF24.EN_CRC: if config & NRF24.CRCO: result = NRF24.CRC_16 else: result = NRF24.CRC_8 return result def disableCRC(self): disable = self.read_register(NRF24.CONFIG) & ~NRF24.EN_CRC self.write_register(NRF24.CONFIG, disable) def setRetries(self, delay, count): self.write_register(NRF24.SETUP_RETR, (delay & 0xf) << NRF24.ARD | (count & 0xf) << NRF24.ARC) self.delay = delay * 0.000250 self.retries = count self.max_timeout = (self.payload_size / float(self.data_rate_bits) + self.delay) * self.retries self.timeout = (self.payload_size / float(self.data_rate_bits) + self.delay) def getRetries(self): return self.read_register(NRF24.SETUP_RETR) def getMaxTimeout(self): return self.max_timeout def getTimeout(self): return self.timeout def reset(self): """ Make sure the NRF is in the same state as after power up to avoid problems resulting from left over configuration from other programs.""" self.ce(0) reset_values = {0: 0x08, 1: 0x3F, 2: 0x02, 3: 0x03, 4: 0x03, 5: 0x02, 6: 0x06, 0x0a: [0xe7, 0xe7, 0xe7, 0xe7, 0xe7], 0x0b: [0xc2, 0xc2, 0xc2, 0xc2, 0xc2], 0x0c: 0xc3, 0x0d: 0xc4, 0x0e: 0xc5, 0x0f: 0xc6, 0x10: [0xe7, 0xe7, 0xe7, 0xe7, 0xe7], 0x11: 0, 0x12: 0, 0x13: 0, 0x14: 0, 0x15: 0, 0x16: 0, 0x1c: 0, 0x1d: 0} for reg, value in reset_values.items(): self.write_register(reg, value) self.flush_rx() self.flush_tx()
class RFM69HCW(): def __init__(self, LED_STATE=default_LED_STATE, Fxosc=default_Fxosc, Fstep=default_Fstep, callsign=None, node_id=default_node_id, network_id=default_network_id, carrier_freq=default_carrier_freq, carrier_dev=default_carrier_dev, carrier_bitrate=default_bitrate): self._mode = OPMODE_SLEEP self.LED_STATE = LED_STATE self.Fxosc = Fxosc self.Fstep = Fstep self.callsign = callsign self.RFM_SPI = SPI(0, 0) self.RFM_SPI.msh = 5000000 self.carrier_freq = carrier_freq self.carrier_dev = carrier_dev self.bitrate = carrier_bitrate self.node_id = node_id self.network_id = network_id if self.callsign is None: raise NoCallSign("FCC Callsign not defined") self.ord_callsign = map(ord, list(self.callsign)) self._io_setup() GPIO.output(BLUE_LEDPIN, GPIO.LOW) self.reset_radio() return def _io_setup(self): GPIO.setup(BLUE_LEDPIN, GPIO.OUT) GPIO.setup(MODULE_EN, GPIO.OUT) GPIO.setup(MODULE_RST, GPIO.OUT) GPIO.setup(G0_PIN, GPIO.IN) GPIO.setup(G1_PIN, GPIO.OUT) GPIO.setup(G2_PIN, GPIO.OUT) # GPIO.add_event_detect(G0_PIN, GPIO.FALLING, callback=g0int) GPIO.add_event_detect(G0_PIN, GPIO.RISING, callback=g0int) def _check_register(self, addr, value): vals = self.RFM_SPI.xfer2([addr, 0x0]) if vals[1] != value: str = "addr: " + hex(addr) + "(" + inv_sx1231_reg[ addr] + ")" + " should be: " + hex(value) + " got: " + hex( vals[1]) raise CheckError(str) print "Reg{", hex(addr), "}(", inv_sx1231_reg[addr], ")\t\t=", hex( vals[1]) def write_register(self, reg, val, checkit=False): addr = reg reg = reg | 0x80 # print "reg is: ", bin(reg) # print "val is: " , bin(val) # RFM_SPI.writebytes([reg, val]) self.RFM_SPI.xfer2([reg, val]) if checkit == True: self._check_register(addr, val) return def read_register(self, reg): regval = self.RFM_SPI.xfer2([reg, 0x0]) return regval[1] def reset_radio(self): #self.blue_blink(2) GPIO.output(MODULE_EN, GPIO.HIGH) GPIO.output(MODULE_RST, GPIO.LOW) time.sleep(0.5) GPIO.output(MODULE_RST, GPIO.HIGH) time.sleep(0.5) GPIO.output(MODULE_RST, GPIO.LOW) time.sleep(0.5) def blue_invert(self): if (self.LED_STATE) == True: self.blue_off() else: self.blue_on() def blue_off(self): self.LED_STATE = False GPIO.output(BLUE_LEDPIN, GPIO.HIGH) return def blue_on(self): self.LED_STATE = True GPIO.output(BLUE_LEDPIN, GPIO.LOW) return def blue_blink(self, n=3): for num in range(0, n * 2): self.blue_invert() time.sleep(0.25) return def report_setup(self): print 'LED_STATE is:\t', self.LED_STATE print 'Fxosc is: \t', self.Fxosc print 'Fstep is: \t', self.Fstep print 'Callsign is: \t', self.callsign return # Facts: # Fxosc = 32Mhz # Fstep = 32e6/2^9 = 61.03515625 # Frf = int(carrier_hz/Fstep) def write_carrier_freq(self, carrier_hz=436500000): frf = int(carrier_hz / self.Fstep) # vals = RFM_SPI.xfer2([RegFrfMsb, 0x0, 0x0, 0x0]) # print "Pre: vals=\t", hex(vals[0]), "\t", hex(vals[1]), "\t", hex(vals[2]), "\t", hex(vals[3]) frfmsb = (frf >> 16) & 0xff frfmid = (frf >> 8) & 0xff frflsb = frf & 0xff wbuf = [(sx1231_reg["RegFrfMsb"] | 0x80), int(frfmsb), int(frfmid), int(frflsb)] self.RFM_SPI.writebytes(wbuf) vals = self.RFM_SPI.xfer2([sx1231_reg["RegFrfMsb"], 0x0, 0x0, 0x0]) # print "Post: vals=\t", hex(vals[0]), "\t", hex(vals[1]), "\t", hex(vals[2]), "\t", hex(vals[3]) return def set_freq_deviation(self, freq_dev_hz=20000): freqdev = int(freq_dev_hz / self.Fstep) wbuf = [(sx1231_reg["RegFdevMsb"] | 0x80), (int(freqdev >> 8) & 0x3f), int(freqdev & 0xff)] self.RFM_SPI.writebytes(wbuf) # print "fdev_msb:\t", # check_register(sx1231_reg["RegFdevMsb"], (int(freqdev>>8) & 0x3f)) # print "\nfdev_lsb:\t", # check_register(sx1231_reg["RegFdevLsb"], (int(freqdev & 0xff))) # print "\n" return def set_bitrate(self, bitrate_hz=1200): rate = int(self.Fxosc / bitrate_hz) wbuf = [(sx1231_reg["RegBitrateMsb"] | 0x80), (int(rate >> 8) & 0xff), int(rate & 0xff)] self.RFM_SPI.writebytes(wbuf) def set_sync_value(fourbytelist): wbuf = [(sx1231_reg["RegSyncValue1"] | 0x80)] + fourbytelist self.RFM_SPI.writebytes(wbuf) def set_preamble(twobytelist): wbuf = [(sx1231_reg["RegPreambleMsb"] | 0x80)] + twobytelist self.RFM_SPI.writebytes(wbuf) """ Experiment with automodes """ def config_packet(self, pa, node_id=0x33, network_id=0x77): # Begin with sequencer on, listen off, and in standby self.write_register(sx1231_reg["RegOpMode"], OPMODE_SEQUENCER_ON | OPMODE_LISTEN_OFF, True) self.set_mode(OPMODE_STANDBY) # Automodes - Finish Emptying fifo while in STBY self.write_register( sx1231_reg["RegAutoModes"], AUTOMODE_ENTER_CRC_OK | AUTOMODE_EXIT_FIFO_NOT_EMPTY | AUTOMODE_INTERM_STDBY, True) # Packet Mode, FSK, No Shaping self.write_register( sx1231_reg["RegDataModul"], DATAMODUL_Packet | DATAMODUL_FSK | DATAMODUL_NoShaping) self.write_carrier_freq(self.carrier_freq) self.set_freq_deviation(self.carrier_dev) self.set_bitrate(self.bitrate) # PA Output Power self.write_register(sx1231_reg["RegPaLevel"], PAOutputCfg( PA0, 0x1F)) # keep at PA0 until end of initialize # DIO Mappings g0_flag = False g1_flag = False g2_flag = False g3_flag = False g4_flag = False g5_flag = False # (DccFreq|RxBwMant|RxBwExp) Table 13 self.write_register(sx1231_reg["RegRxBw"], (010 << 5 | 0x10 << 3 | 100 << 0)) # 20.8kHz? # DIO_0 initialize to PAYLOAD ready in RX self.write_register( sx1231_reg["RegDioMapping1"], ((self.read_register(sx1231_reg["RegDioMapping1"]) & (~(0b11 << DIO_0_POS))) | DIO0_PAYLOADREADY << DIO_0_POS), True) # DIO_1 is RX TIMEOUT self.write_register( sx1231_reg["RegDioMapping1"], ((self.read_register(sx1231_reg["RegDioMapping1"]) & (~(0b11 << DIO_1_POS))) | DIO1_RX_TIMEOUT << DIO_1_POS), True) # DIO_4 is Clkout self.write_register(sx1231_reg["RegDioMapping2"], (DIO4_RXRDY << DIO_4_POS | DIO_CLK_DIV32), True) # Clear IRQFLAG and reset FIFO self.write_register(sx1231_reg["RegIrqFlags2"], IRQFLAGS2_FIFOOVERRUN) # RSSI Thresh self.write_register(sx1231_reg["RegRssiThresh"], 0xdc, True) # -220/2 = -110dBm? # Preamble length (0xaa..N) self.write_register(sx1231_reg["RegPreambleLsb"], 0xf, True) # Sync Config self.write_register( sx1231_reg["RegSyncConfig"], SYNCCFG_SYNC_ON | SYNCCFG_FILL_FIFO_INTR | SYNCCFG_SIZE_2, True) # Sync Word self.write_register(sx1231_reg["RegSyncValue1"], node_id, True) self.write_register(sx1231_reg["RegSyncValue2"], network_id, True) # Packet config 1 self.write_register( sx1231_reg["RegPacketConfig1"], PACKET1_FORMAT_FIXED | PACKET1_DCFREE_NONE | PACKET1_CRC_ON | PACKET1_CRCAUTOCLEAR_ON | PACKET1_ADDRESS_FILTERING_BOTH, True) # Payload Length self.write_register(sx1231_reg["RegPayloadLength"], default_Payload_bytes, True) # Node address: self.write_register(sx1231_reg["RegNodeAdrs"], self.node_id, True) self.write_register(sx1231_reg["RegBroadcastAdrs"], self.node_id + 1, True) # Fifothresh? Only for TX self.write_register(sx1231_reg["RegFifoThresh"], FIFOTHRESH_NOT_EMPTY | FIFOTHRESH_THRESHOLD_15, True) # Packet config 2 self.write_register(sx1231_reg["RegPacketConfig2"], PACKET2_AUTORX_RESTART_ON, True) # Magic numbers self.write_register( sx1231_reg["RegPaRamp"], 0b0011, True ) # 500uS close to 1/2400 bps ... see PacketConfig2 InterPacketRxDelay Must match the tx PA Ramp-down time # self.write_register(sx1231_reg["RegAfcCtrl"],0x40 | (0b1<<5) , True ) # AfcLowBetaOn - Manual misprint....bits 7-6 read as 0b01 not 0b00 self.write_register( sx1231_reg["RegAfcCtrl"], (0b1 << 5), True ) # AfcLowBetaOn - Manual misprint....bits 7-6 read as 0b01 not 0b00 self.write_register(sx1231_reg["RegTestDagc"], 0x20, True) # page 74 for AfcLowBetaOn=1 self.write_register(sx1231_reg["RegPaLevel"], pa) return def set_mode(self, mode): if (mode == self._mode): return if (mode == OPMODE_SLEEP): self.write_register( sx1231_reg["RegDioMapping1"], ((self.read_register(sx1231_reg["RegDioMapping1"]) & (~(0b11 << DIO_0_POS))) | DIO0_PAYLOADREADY << DIO_0_POS)) self.write_register( sx1231_reg["RegOpMode"], (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3) | OPMODE_SLEEP) self._mode = OPMODE_SLEEP elif (mode == OPMODE_STANDBY): self.write_register( sx1231_reg["RegDioMapping1"], ((self.read_register(sx1231_reg["RegDioMapping1"]) & (~(0b11 << DIO_0_POS))) | DIO0_PAYLOADREADY << DIO_0_POS)) self.write_register( sx1231_reg["RegOpMode"], (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3) | OPMODE_STANDBY) self._mode = OPMODE_STANDBY elif (mode == OPMODE_FS_SYNTH): self.write_register( sx1231_reg["RegOpMode"], (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3) | OPMODE_FS_SYNTH) self._mode = OPMODE_FS_SYNTH elif (mode == OPMODE_TX): self.write_register( sx1231_reg["RegDioMapping1"], ((self.read_register(sx1231_reg["RegDioMapping1"]) & (~(0b11 << DIO_0_POS))) | DIO0_PACKETSENT << DIO_0_POS)) self.write_register( sx1231_reg["RegOpMode"], (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3) | OPMODE_TX) self._mode = OPMODE_TX elif (mode == OPMODE_RX): self.write_register( sx1231_reg["RegDioMapping1"], ((self.read_register(sx1231_reg["RegDioMapping1"]) & (~(0b11 << DIO_0_POS))) | DIO0_PAYLOADREADY << DIO_0_POS)) self.write_register( sx1231_reg["RegOpMode"], (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3) | OPMODE_RX) self._mode = OPMODE_RX else: raise ValueError('Unrecognized Mode') while ((self.read_register(sx1231_reg["RegIrqFlags1"]) & IRQFLAGS1_MODEREADY) == 0x00): pass return def RSSI(self): # write trigger self.write_register(sx1231_reg["RegRssiConfig"], 0b1) while ((self.read_register(sx1231_reg["RegRssiConfig"]) & RSSI_DONE) == 0x0): pass rssival = -self.read_register(sx1231_reg["RegRssiValue"]) rssival = rssival / 2 return rssival # call when g0flag goes true def read_fifo(self): global g0_flag self.standby() fifolist = self.RFM_SPI.readbytes(default_Payload_bytes + 1) #debugging # value = True # while value: # print "* "; # value = self.read_register(sx1231_reg["RegIrqFlags2"]) & IRQFLAGS2_PAYLOADREADY # garbage=self.RFM_SPI.readbytes(default_Payload_bytes+1) value = self.read_register( sx1231_reg["RegIrqFlags2"]) & IRQFLAGS2_PAYLOADREADY if value == 0: g0_flag = False return fifolist def standby(self): self.set_mode(OPMODE_STANDBY) return def receive(self): self.set_mode(OPMODE_RX) g0_flag = False return def send(self, bytelist): self.set_mode(OPMODE_STANDBY) if len(bytelist) > MAX_PACKET_LEN: raise ValueError('Max Packet Len Exceeded') #bytelist = [self.node_id+1]+[self.node_id] + bytelist # bytelist = [self.node_id] + [self.node_id+1] + bytelist # bytelist = [self.node_id] + bytelist bytelist = [self.node_id] + bytelist print "\tbytelist: ", bytelist wbuf = [(sx1231_reg["RegFifo"] | 0x80)] + bytelist self.RFM_SPI.writebytes(wbuf) start_time = time.time() self.set_mode(OPMODE_TX) # Read pin or register... # value = GPIO.input(G0_PIN) value = self.read_register( sx1231_reg["RegIrqFlags2"]) & IRQFLAGS2_PACKETSENT #print "Start send:\t", start_time while value == 0: # value = GPIO.input(G0_PIN) value = self.read_register( sx1231_reg["RegIrqFlags2"]) & IRQFLAGS2_PACKETSENT elapsed_time = time.time() - start_time if (elapsed_time > 10): break #print "Stop send:\t", elapsed_time self.set_mode(OPMODE_STANDBY) return def stop(self): return
print("%s, 1, %d") % (address, rssi) if value[28] == 129: print("%s, 2, %d") % (address, rssi) if value[28] == 130: print("%s, 3, %d") % (address, rssi) if value[28] == 131: print("%s, 4, %d") % (address, rssi) bt = SPI(0, 0) bt.mode = 1 bt.msh = 1000000 k=0 while k<100: bt.xfer2([ 0x00, 0x00, 0xFE, 0x07, 0x01, 0x04, 0xFE, 0x03, 0x03, 0x00, 0x00, 0xFC]) i=0; while i<35: if GPIO.input("P9_15") != 1: value = bt.readbytes(12) if value[1] == 0xFE and value[6] == 127 and value[7] == 6: print("scanner started") i=50 k=100 time.sleep(0.001) i = i + 1 k = k +1 end_cond = 1 while end_cond:
from Adafruit_BBIO.SPI import SPI spi = SPI(1,0) spi.mode=2 spi.msh=2000000 spi.open(1,0) print spi.xfer2([32, 11, 110, 22, 220]) spi.close()
bt.mode = 1 bt.msh = 1000000 #reset the module GPIO.output("P9_12", GPIO.LOW) time.sleep(0.1) GPIO.output("P9_12", GPIO.HIGH) # initialize bt module k = 0 while k < 100: #print("Sending init message") bt.xfer2([ 0x00, 0xFE, 0x2A, 0x01, 0x00, 0xFE, 0x26, 0x02, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFA ]) i = 0 while i < 30: if GPIO.input("P9_15") != 1: value = bt.readbytes(12) if value[1] == 0xFE and value[6] == 0 and value[7] == 6: #print("Init Success") #print(value) i = 50 k = 100 time.sleep(0.001) i = i + 1 k = k + 1 k = 0
class Enrf24(): __bus = None __device = None __rf_status = 0 __rf_addr_width = 5 __lastirq = None __readpending = 0 __lastTXfailed = False __txbuf_len = 0 __txbuf = [] # Internal IRQ handling __ENRF24_IRQ_TX = 0x20 __ENRF24_IRQ_RX = 0x40 __ENRF24_IRQ_TXFAILED = 0x10 __ENRF24_IRQ_MASK = 0x70 __ENRF24_CFGMASK_IRQ = 0 def __init__(self, bus, device, cePin, csnPin, irqPin): self.__bus = bus self.__device = device self.cePin = cePin self.csnPin = csnPin self.irqPin = irqPin self.spi = SPI(self.__bus, self.__device) self.spi.msh = 10000 self.spi.bpw = 8 # bits/word self.spi.threewire = False self.spi.lsbfirst = False self.spi.mode = 0 self.spi.cshigh = False self.spi.open(0, 0) self.last_payload = "" def begin(self, datarate=1000000, channel=0): # Specify bitrate & channel GPIO.setup(self.cePin, GPIO.OUT) GPIO.output(self.cePin, GPIO.LOW) GPIO.setup(self.csnPin, GPIO.OUT) GPIO.output(self.csnPin, GPIO.HIGH) GPIO.setup(self.irqPin, GPIO.IN) # No pullups; the transceiver provides this! self.spi.writebytes([0x00 ]) # Strawman transfer, fixes USCI issue on G2553 #self.spi.writebytes([0xCF, 0x00]) # Is the transceiver present/alive? if (not self.__isAlive()): return False # Nothing more to do here... # Wait 100ms for module to initialize time.sleep(0.1) # Init certain registers self.__writeReg(RF24_CONFIG, 0x00) # Deep power-down, everything disabled self.__writeReg(RF24_EN_AA, 0x03) self.__writeReg(RF24_EN_RXADDR, 0x03) self.__writeReg(RF24_RF_SETUP, 0x00) self.__writeReg(RF24_STATUS, self.__ENRF24_IRQ_MASK) # Clear all IRQs self.__writeReg(RF24_DYNPD, 0x03) self.__writeReg(RF24_FEATURE, RF24_EN_DPL) # Dynamic payloads enabled by default # Set all parameters if (channel > 125): channel = 125 self.deepsleep() self.__issueCmd(RF24_FLUSH_TX) self.__issueCmd(RF24_FLUSH_RX) self.__readpending = 0 self.__irq_clear(self.__ENRF24_IRQ_MASK) self.setChannel(channel) self.setSpeed(datarate) self.setTXpower() self.setAutoAckParams() self.setAddressLength(self.__rf_addr_width) self.setCRC(True) # Default = CRC on, 8-bit return True def end(self): # Shut it off, clear the library's state self.__txbuf_len = 0 self.__rf_status = 0 self.__rf_addr_width = 5 if (not self.__isAlive()): return self.deepsleep() self.__issueCmd(RF24_FLUSH_TX) self.__issueCmd(RF24_FLUSH_RX) self.readpending = 0 self.__irq_clear(self.__ENRF24_IRQ_MASK) GPIO.output(self.cePin, GPIO.LOW) GPIO.output(self.csnPin, GPIO.HIGH) # I/O def available( self, checkIrq=False): # Check if incoming data is ready to be read #print(checkIrq and GPIO.input(self.irqPin) and self.__readpending == 0) if (checkIrq and GPIO.input(self.irqPin) and self.__readpending == 0): return False self.__maintenanceHook() if ((not self.__readReg(RF24_FIFO_STATUS)) & RF24_RX_EMPTY): return True if (self.__readpending): return True return False def read(self, maxlen=32): # Read contents of RX buffer up to buf = None plwidth = 0 res = "" self.__maintenanceHook() self.__readpending = 0 if ((self.__readReg(RF24_FIFO_STATUS) & RF24_RX_EMPTY) or maxlen < 1): return 0 plwidth = self.__readCmdPayload(RF24_R_RX_PL_WID, plwidth, 1, 1)[0] buf = self.__readCmdPayload(RF24_R_RX_PAYLOAD, buf, plwidth, maxlen) if (self.__irq_derivereason() and self.__ENRF24_IRQ_RX): self.__irq_clear(self.__ENRF24_IRQ_RX) for i in buf: res += chr(i) self.last_payload = res return res # 'maxlen' bytes, return final length. # 'inbuf' should be maxlen+1 since a # null '\0' is tacked onto the end. def getMessage(self): return self.last_payload def write(self, data): if (self.__txbuf_len == 32 ): # If we're trying to stuff an already-full buffer... self.flush() # Blocking OTA TX txbuf = [] data = list(data) for i in data: txbuf.append(ord(i)) self.__txbuf = txbuf self.__txbuf_len = len(txbuf) return 1 def flush(self): # Force transmission of TX ring buffer contents reg = None addrbuf = [] enaa = False origrx = False if (self.__txbuf_len == 0): return # Zero-length buffer? Nothing to send! reg = self.__readReg(RF24_FIFO_STATUS) if ( reg & BITS["BIT5"] ): # RF24_TX_FULL #define is BIT0, which is not the correct bit for FIFO_STATUS. # Seen this before with a user whose CE pin was messed up. self.__issueCmd(RF24_FLUSH_TX) self.__txbuf_len = 0 return # Should never happen, but nonetheless a precaution to take. self.__maintenanceHook() if (reg & RF24_TX_REUSE): # If somehow TX_REUSE is enabled, we need to flush the TX queue before loading our new payload. self.__issueCmd(RF24_FLUSH_TX) if (self.__readReg(RF24_EN_AA) & 0x01 and (self.__readReg(RF24_RF_SETUP) & 0x28) != 0x20): # AutoACK enabled, must write TX addr to RX pipe#0 # Note that 250Kbps doesn't support auto-ack, so we check RF24_RF_SETUP to verify that. enaa = True self.__readTXaddr(addrbuf) self.__writeRXaddrP0(addrbuf) reg = self.__readReg(RF24_CONFIG) if (not (reg & RF24_PWR_UP)): #digitalWrite(_cePin, HIGH); // Workaround for SI24R1 knockoff chips self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP) time.sleep(.05) # 5ms delay required for nRF24 oscillator start-up #digitalWrite(_cePin, LOW); if (reg & RF24_PRIM_RX): origrx = True GPIO.output(self.cePin, GPIO.LOW) self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP) self.__txbuf = self.__issueCmdPayload(RF24_W_TX_PAYLOAD, self.__txbuf) GPIO.output(self.cePin, GPIO.HIGH) time.sleep(0.1) GPIO.output(self.cePin, GPIO.LOW) self.__txbuf_len = 0 # Reset TX ring buffer while (GPIO.input(self.irqPin)): # Wait until IRQ fires pass # IRQ fired self.__maintenanceHook() # Handle/clear IRQ # Purge Pipe#0 address (set to module's power-up default) if (enaa): addrbuf = [0xE7, 0xE7, 0xE7, 0xE7, 0xE7] self.__writeRXaddrP0(addrbuf) # If we were in RX mode before writing, return back to RX mode. if (origrx): self.enableRX() def purge( self): # Ignore TX ring buffer contents, return ring pointer to 0. self.__txbuf_len = 0 # Power-state related stuff- def radioState( self ): # Evaluate current state of the transceiver (see ENRF24_STATE_* defines) if not self.__isAlive(): return ENRF24_STATE_NOTPRESENT counter = 15 reg = self.__readReg(RF24_CONFIG) if reg == 0: while reg == 0 and counter < 15: reg = self.__readReg(RF24_CONFIG) counter += 1 if (not (reg & RF24_PWR_UP)): return ENRF24_STATE_DEEPSLEEP # At this point it's either Standby-I, II or PRX. if (reg & RF24_PRIM_RX): if (GPIO.input(self.cePin)): return ENRF24_STATE_PRX # PRIM_RX=1 but CE=0 is a form of idle state. return ENRF24_STATE_IDLE # Check if TX queue is empty, if so it's idle, if not it's PTX. if (self.__readReg(RF24_FIFO_STATUS) & RF24_TX_EMPTY): return ENRF24_STATE_IDLE return ENRF24_STATE_PTX def printRadioState(self): status = self.radioState() sys.stdout.write("Enrf24 radio transceiver status: ") if status == ENRF24_STATE_NOTPRESENT: print("NO TRANSCEIVER PRESENT") elif status == ENRF24_STATE_DEEPSLEEP: print("DEEP SLEEP <1uA power consumption") elif status == ENRF24_STATE_IDLE: print("IDLE module powered up w/ oscillators running") elif status == ENRF24_STATE_PTX: print("Actively Transmitting") elif status == ENRF24_STATE_PRX: print("Receive Mode") else: print("UNKNOWN STATUS CODE") def printStatus(self): status = self.__readReg(RF24_STATUS) data_ready = str(hex(status & 0x40)) data_sent = str(hex(status & 0x20)) max_tx_retries = str(hex(status & 0x10)) if status & 0x0E == 0x0E: rx_pipe_no = "RX FIFO Empty" elif status & 0x02 == 0x02: rx_pipe_no = 1 elif status & 0x04 == 0x04: rx_pipe_no = 2 elif status & 0x06 == 0x06: rx_pipe_no = 3 elif status & 0x08 == 0x08: rx_pipe_no = 4 elif status & 0x0A == 0x0A: rx_pipe_no = 5 elif ~status & 0x0E: rx_pipe_no = 0 else: rx_pipe_no = "Error" rx_pipe_no = str(rx_pipe_no) tx_fifo_full = str(status & 0x01) status = str(hex(status)) sys.stdout.write("STATUS=") sys.stdout.write(status) sys.stdout.write("\tRX_DR=") sys.stdout.write(data_ready) sys.stdout.write(" TX_DS=") sys.stdout.write(data_sent) sys.stdout.write(" MAX_RT=") sys.stdout.write(max_tx_retries) sys.stdout.write(" RX_P_NO=") sys.stdout.write(rx_pipe_no) sys.stdout.write(" TX_FULL=") print(tx_fifo_full) print("") def printDetails(self): self.printStatus() buf = [] sys.stdout.write("RX_ADDR_P0=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P0, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P1=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P1, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P2=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P2, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P3=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P3, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P4=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P4, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P5=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P5, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") print("") sys.stdout.write("TX_ADDR=") buf = self.__readRegMultiLSB(RF24_TX_ADDR, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") print("") sys.stdout.write("RX_PW_P0=") print(hex(self.__readReg(RF24_RX_PW_P0))) sys.stdout.write("RX_PW_P1=") print(hex(self.__readReg(RF24_RX_PW_P1))) sys.stdout.write("RX_PW_P2=") print(hex(self.__readReg(RF24_RX_PW_P2))) sys.stdout.write("RX_PW_P3=") print(hex(self.__readReg(RF24_RX_PW_P3))) sys.stdout.write("RX_PW_P4=") print(hex(self.__readReg(RF24_RX_PW_P4))) sys.stdout.write("RX_PW_P5=") print(hex(self.__readReg(RF24_RX_PW_P5))) print("") sys.stdout.write("EN_AA=") print(bin(self.__readReg(RF24_EN_AA))) sys.stdout.write("EN_RXADDR=") print(bin(self.__readReg(RF24_EN_RXADDR))) sys.stdout.write("RF_CH=") print(hex(self.__readReg(RF24_RF_CH))) sys.stdout.write("RF_SETUP=") print(bin(self.__readReg(RF24_RF_SETUP))) sys.stdout.write("CONFIG=") print(bin(self.__readReg(RF24_CONFIG))) sys.stdout.write("DYNPD=") print(bin(self.__readReg(RF24_DYNPD))) sys.stdout.write("FEATURE=") print(bin(self.__readReg(RF24_FEATURE))) print("") sys.stdout.write("Data Rate=") print(self.getSpeed()) sys.stdout.write("CRC Length=") print(self.getCRC()) sys.stdout.write("PA Power=") print(self.getTXpower()) def deepsleep(self): # Enter POWERDOWN mode, ~0.9uA power consumption reg = self.__readReg(RF24_CONFIG) if (reg & (RF24_PWR_UP | RF24_PRIM_RX)): self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg)) GPIO.output(self.cePin, GPIO.LOW) def enableRX(self): # Enter PRX mode (~14mA) reg = self.__readReg(RF24_CONFIG) self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP | RF24_PRIM_RX) self.__writeReg(RF24_RX_PW_P0, 0x20) self.__writeReg(RF24_RX_PW_P1, 0x20) GPIO.output(self.cePin, GPIO.HIGH) if ( not (reg & RF24_PWR_UP) ): # Powering up from deep-sleep requires 5ms oscillator start delay time.sleep(0.05) def disableRX(self): # Disable PRX mode (PRIM_RX bit in CONFIG register) # Note this won't necessarily push the transceiver into deep sleep, but rather # an idle standby mode where its internal oscillators are ready & running but # the RF transceiver PLL is disabled. ~26uA power consumption. GPIO.output(self.cePin, GPIO.LOW) reg = self.__readReg(RF24_CONFIG) if ( reg & RF24_PWR_UP ): # Keep us in standby-I if we're coming from RX mode, otherwise stay # in deep-sleep if we call this while already in PWR_UP=0 mode. self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP) else: self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg)) # Custom tweaks to RF parameters, packet parameters def autoAck(self, onoff=True ): # Enable/disable auto-acknowledgements (enabled by default) reg = self.__readReg(RF24_EN_AA) if (onoff): if (not (reg & 0x01) or not (reg & 0x02)): self.__writeReg(RF24_EN_AA, 0x03) else: if (reg & 0x03): self.__writeReg(RF24_EN_AA, 0x00) def setChannel(self, channel): if (channel > 125): channel = 125 self.__writeReg(RF24_RF_CH, channel) def setTXpower( self, dBm=0 ): # Only a few values supported by this (0, -6, -12, -18 dBm) reg = self.__readReg( RF24_RF_SETUP) & 0xF8 # preserve RF speed settings pwr = 0x06 if (dBm >= 7): pwr = 0x07 if (dBm < 0): pwr = 0x04 if (dBm < -6): pwr = 0x02 if (dBm < -12): pwr = 0x00 self.__writeReg(RF24_RF_SETUP, reg | pwr) def setSpeed(self, rfspeed): # Set 250000, 1000000, 2000000 speeds. reg = self.__readReg( RF24_RF_SETUP) & 0xD7 # preserve RF power settings spd = 0x01 if (rfspeed < 2000000): spd = 0x00 if (rfspeed < 1000000): spd = 0x04 self.__writeReg(RF24_RF_SETUP, reg | (spd << 3)) def setCRC(self, onoff, crc16bit=False): # Enable/disable CRC usage inside nRF24's # hardware packet engine, specify 8 or # 16-bit CRC. crcbits = 0 reg = self.__readReg( RF24_CONFIG) & 0xF3 # preserve IRQ mask, PWR_UP/PRIM_RX settings if (onoff): crcbits |= RF24_EN_CRC if (crc16bit): crcbits |= RF24_CRCO self.__writeReg(RF24_CONFIG, (reg | crcbits)) # Set AutoACK retry count, timeout params (0-15, 250-4000 respectively) def setAutoAckParams(self, autoretry_count=15, autoretry_timeout=2000): setup_retr = 0 setup_retr = autoretry_count & 0x0F autoretry_timeout -= 250 setup_retr |= ((autoretry_timeout / 250) & 0x0F) << 4 self.__writeReg(RF24_SETUP_RETR, setup_retr) # Protocol addressing -- receive, transmit addresses def setAddressLength(self, len): # Valid parameters = 3, 4 or 5. Defaults to 5. if (len < 3): len = 3 if (len > 5): len = 5 self.__writeReg(RF24_SETUP_AW, len - 2) self.__rf_addr_width = len def setRXaddress(self, rxaddr): # 3-5 byte RX address loaded into pipe#1 self.__writeRegMultiLSB(RF24_RX_ADDR_P1, rxaddr) def setTXaddress( self, txaddr): # 3-5 byte TX address loaded into TXaddr register self.__writeRegMultiLSB(RF24_TX_ADDR, txaddr) # Miscellaneous feature def rfSignalDetected( self ): # Read RPD register to determine if transceiver has presently detected an RF signal # of -64dBm or greater. Only works in PRX (enableRX()) mode. rpd = self.__readReg(RF24_RPD) return rpd # Query current parameters def getChannel(self): return self.__readReg(RF24_RF_CH) def getSpeed(self): reg = self.__readReg(RF24_RF_SETUP) & 0x28 if (reg == 0x00): return 1000000 elif (reg == 0x08): return 2000000 elif (reg == 0x20): return 250000 else: return 0 def getTXpower(self): reg = self.__readReg(RF24_RF_SETUP) & 0x07 if (reg & 0x01): return 7 # SI24R1-only +7dBm mode elif (reg == 0x02): return -12 elif (reg == 0x04): return -6 elif (reg == 0x06): return 0 else: return -18 def getAddressLength(self): return self.__rf_addr_width def getRXaddress(self): buf = [] buf = self.__readRegMultiLSB(RF24_RX_ADDR_P1, buf, self.__rf_addr_width) return buf def getTXaddress(self): buf = [] buf = self.__readRegMultiLSB(RF24_TX_ADDR, buf, rf_addr_width) return buf def getAutoAck(self): reg = self.__readReg(RF24_EN_AA) if (reg): return True else: return False def getCRC(self): reg = self.__readReg(RF24_CONFIG) & 0x0C if (reg == 0x08): return 8 elif (reg == 0x0C): return 16 else: return 0 def __readReg(self, addr): GPIO.output(self.csnPin, GPIO.LOW) result = self.spi.xfer2([(RF24_R_REGISTER | addr), RF24_NOP]) self.__rf_status = result[0] GPIO.output(self.csnPin, GPIO.HIGH) return result[1] def __readRegMultiLSB(self, addr, buf, length): txbuf = [(RF24_R_REGISTER | addr)] for i in range(length): txbuf.append(RF24_NOP) GPIO.output(self.csnPin, GPIO.LOW) buf = self.spi.xfer2(txbuf) self.__rf_status = buf[0] status = [] for i in range(1, len(buf) + 1): status.append(buf[-i]) status.pop() GPIO.output(self.csnPin, GPIO.HIGH) return status def __writeReg(self, addr, val): GPIO.output(self.csnPin, GPIO.LOW) res = self.spi.xfer2([(RF24_W_REGISTER | addr), val]) GPIO.output(self.csnPin, GPIO.HIGH) def __writeRegMultiLSB(self, addr, buf): txbuf = [(RF24_W_REGISTER | addr)] for i in range(1, len(buf) + 1): txbuf.append(buf[-i]) GPIO.output(self.csnPin, GPIO.LOW) status = self.spi.xfer2(txbuf) GPIO.output(self.csnPin, GPIO.HIGH) def __issueCmd(self, cmd): GPIO.output(self.csnPin, GPIO.LOW) self.spi.writebytes([cmd]) GPIO.output(self.csnPin, GPIO.HIGH) def __readCmdPayload(self, cmd, buf, length, maxlen): GPIO.output(self.csnPin, GPIO.LOW) messg = [] txbuf = [cmd] for i in range(maxlen): txbuf.append(RF24_NOP) buf = self.spi.xfer2( txbuf) # Beyond maxlen bytes, just discard the remaining data. self.__rf_status = buf[0] for i in range(1, length + 1): messg.append(buf[i]) GPIO.output(self.csnPin, GPIO.HIGH) return messg def __issueCmdPayload(self, cmd, buf): payload = [] payload.append(cmd) for i in buf: payload.append(i) GPIO.output(self.csnPin, GPIO.LOW) res = self.spi.xfer2(payload) GPIO.output(self.csnPin, GPIO.HIGH) def __irq_getreason(self): self.__lastirq = self.__readReg(RF24_STATUS) & self.__ENRF24_IRQ_MASK def __irq_derivereason( self ): # Get IRQ status from rf_status w/o querying module over SPI. self.__lastirq = self.__rf_status & self.__ENRF24_IRQ_MASK def __irq_clear(self, irq): self.__writeReg(RF24_STATUS, (irq & self.__ENRF24_IRQ_MASK)) def __isAlive(self): self.spi.writebytes([0x00]) aw = self.__readReg(RF24_SETUP_AW) return ((aw & 0xFC) == 0x00 and (aw & 0x03) != 0x00) def __readTXaddr(self, buf): self.__readRegMultiLSB(RF24_TX_ADDR, buf, self.__rf_addr_width) def __writeRXaddrP0(self, buf): self.__writeRegMultiLSB(RF24_RX_ADDR_P0, buf) def __maintenanceHook( self ): # Handles IRQs and purges RX queue when erroneous contents exist. i = 0 self.__irq_getreason() if (self.__lastirq & self.__ENRF24_IRQ_TXFAILED): self.__lastTXfailed = True self.__issueCmd(RF24_FLUSH_TX) self.__irq_clear(self.__ENRF24_IRQ_TXFAILED) if (self.__lastirq & self.__ENRF24_IRQ_TX): self.__lastTXfailed = False self.__irq_clear(self.__ENRF24_IRQ_TX) if (self.__lastirq & self.__ENRF24_IRQ_RX): if ((not self.__readReg(RF24_FIFO_STATUS)) & RF24_RX_FULL): # Don't feel it's necessary # to be notified of new # incoming packets if the RX # queue is full. self.__irq_clear(self.__ENRF24_IRQ_RX) # Check if RX payload is 0-byte or >32byte (erroneous conditions) # Also check if data was received on pipe#0, which we are ignoring. # The reason for this is pipe#0 is needed for receiving AutoACK acknowledgements, # its address gets reset to the module's default and we do not care about data # coming in to that address... i = self.__readCmdPayload(RF24_R_RX_PL_WID, i, 1, 1)[0] if (i == 0 or i > 32 or ((self.__rf_status & 0x0E) >> 1) == 0): # Zero-width RX payload is an error that happens a lot # with non-AutoAck, and must be cleared with FLUSH_RX. # Erroneous >32byte packets are a similar phenomenon. self.__issueCmd(RF24_FLUSH_RX) self.__irq_clear(self.__ENRF24_IRQ_RX) self.__readpending = 0 else: self.__readpending = 1 # Actual scavenging of RX queues is performed by user-directed use of read(). def __ENRF24_CFGMASK_CRC(self, a): return (a & (RF24_EN_CRC | RF24_CRCO))
class NRF24: MAX_CHANNEL = 127 MAX_PAYLOAD_SIZE = 32 # PA Levels PA_MIN = 0x00 PA_LOW = 0x01 PA_HIGH = 0x02 PA_MAX = 0x03 PA_ERROR = 0x04 # Bit rates BR_1MBPS = 0 BR_2MBPS = 1 BR_250KBPS = 2 # CRC CRC_DISABLED = 0x0 CRC_8 = 0x02 CRC_16 = 0x04 CRC_ENABLED = 0x08 EN_CRC = 0x08 CRCO = 0x04 # Registers CONFIG = 0x00 EN_AA = 0x01 EN_RXADDR = 0x02 SETUP_AW = 0x03 SETUP_RETR = 0x04 RF_CH = 0x05 RF_SETUP = 0x06 STATUS = 0x07 OBSERVE_TX = 0x08 RPD = 0x09 RX_ADDR_P0 = 0x0A RX_ADDR_P1 = 0x0B RX_ADDR_P2 = 0x0C RX_ADDR_P3 = 0x0D RX_ADDR_P4 = 0x0E RX_ADDR_P5 = 0x0F TX_ADDR = 0x10 RX_PW_P0 = 0x11 RX_PW_P1 = 0x12 RX_PW_P2 = 0x13 RX_PW_P3 = 0x14 RX_PW_P4 = 0x15 RX_PW_P5 = 0x16 FIFO_STATUS = 0x17 DYNPD = 0x1C FEATURE = 0x1D # Bit Mnemonics */ MASK_RX_DR = 0x40 MASK_TX_DS = 0x20 MASK_MAX_RT = 0x10 PWR_UP = 0x02 PRIM_RX = 0x01 PLL_LOCK = 0x10 RX_DR = 0x40 TX_DS = 0x20 MAX_RT = 0x10 TX_FULL = 0x01 EN_DPL = 0x04 EN_ACK_PAY = 0x02 EN_DYN_ACK = 0x01 # Shift counts ARD = 4 ARC = 0 PLOS_CNT = 4 ARC_CNT = 0 RX_P_NO = 1 TX_REUSE = 6 FIFO_FULL = 5 TX_EMPTY = 4 RX_FULL = 1 RX_EMPTY = 0 DPL_P5 = 5 DPL_P4 = 4 DPL_P3 = 3 DPL_P2 = 2 DPL_P1 = 1 DPL_P0 = 0 #Masks RX_P_NO_MASK = 0x0E # Instruction Mnemonics R_REGISTER = 0x00 W_REGISTER = 0x20 REGISTER_MASK = 0x1F ACTIVATE = 0x50 R_RX_PL_WID = 0x60 R_RX_PAYLOAD = 0x61 W_TX_PAYLOAD = 0xA0 W_ACK_PAYLOAD = 0xA8 FLUSH_TX = 0xE1 FLUSH_RX = 0xE2 REUSE_TX_PL = 0xE3 NOP = 0xFF # Non-P omissions LNA_HCURR = 0x01 LNA_ON = 1 LNA_OFF = 0 # P model bit Mnemonics RF_DR_LOW = 0x20 RF_DR_HIGH = 0x08 RF_PWR_LOW = 0x02 RF_PWR_HIGH = 0x04 datarate_e_str_P = ["1MBPS", "2MBPS", "250KBPS"] model_e_str_P = ["nRF24L01", "nRF24l01+"] crclength_e_str_P = ["Disabled", "", "8 bits", "", "16 bits"] pa_dbm_e_str_P = ["PA_MIN", "PA_LOW", "PA_HIGH", "PA_MAX"] @staticmethod def print_single_status_line(name, value): print("{0:<16}= {1}".format(name, value)) @staticmethod def _to_8b_list(data): """Convert an arbitray iteratable or single int to a list of ints where each int is smaller than 256.""" if isinstance(data, str): data = [ord(x) for x in data] elif isinstance(data, (int, long)): data = [data] else: data = [int(x) for x in data] #for byte in data: # if byte < 0 or byte > 255: # raise RuntimeError("Value %d is larger than 8 bits" % byte) return data def __init__(self, major=None, minor=None, ce_pin=None, irq_pin=None): self.ce_pin = "P9_15" self.irq_pin = "P9_16" self.channel = 76 self.data_rate = NRF24.BR_1MBPS self.data_rate_bits = 1000 self.p_variant = False # False for RF24L01 and true for RF24L01P self.payload_size = 5 # *< Fixed size of payloads self.ack_payload_available = False # *< Whether there is an ack payload waiting self.dynamic_payloads_enabled = False # *< Whether dynamic payloads are enabled. self.ack_payload_length = 5 # *< Dynamic size of pending ack payload. self.pipe0_reading_address = None # *< Last address set on pipe 0 for reading. self.spidev = None self.last_error = 0 self.crc_length = 0 self.auto_ack = 0x3F self.address_length = 5 # If all parameters are available, lets start the radio! if major is not None and minor is not None and irq_pin is not None: self.begin(major, minor, ce_pin, irq_pin) def begin(self, major, minor, ce_pin, irq_pin): # Initialize SPI bus if ADAFRUID_BBIO_SPI: self.spidev = SPI(major, minor) self.spidev.bpw = 8 try: self.spidev.msh = 10000000 # Maximum supported by NRF24L01+ except IOError: pass # Hardware does not support this speed else: self.spidev = spidev.SpiDev() self.spidev.open(major, minor) self.spidev.bits_per_word = 8 try: self.spidev.max_speed_hz = 10000000 # Maximum supported by NRF24L01+ except IOError: pass # Hardware does not support this speed self.spidev.cshigh = False self.spidev.mode = 0 self.spidev.loop = False self.spidev.lsbfirst = False self.spidev.threewire = False self.ce_pin = ce_pin self.irq_pin = irq_pin if self.ce_pin is not None: GPIO.setup(self.ce_pin, GPIO.OUT) GPIO.setup(self.irq_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) time.sleep(5 / 1000000.0) # Reset radio configuration self.reset() # Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier # WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet # sizes must never be used. See documentation for a more complete explanation. self.setRetries(int('0101', 2), 15) # Restore our default PA level self.setPALevel(NRF24.PA_MAX) # Determine if this is a p or non-p RF24 module and then # reset our data rate back to default value. This works # because a non-P variant won't allow the data rate to # be set to 250Kbps. if self.setDataRate(NRF24.BR_250KBPS): self.p_variant = True # Then set the data rate to the slowest (and most reliable) speed supported by all # hardware. self.setDataRate(NRF24.BR_1MBPS) # Initialize CRC and request 2-byte (16bit) CRC self.setCRCLength(NRF24.CRC_16) # Disable dynamic payloads, to match dynamic_payloads_enabled setting self.write_register(NRF24.DYNPD, 0) # Reset current status # Notice reset and flush is the last thing we do self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) # Set up default configuration. Callers can always change it later. # This channel should be universally safe and not bleed over into adjacent # spectrum. self.setChannel(self.channel) self.setRetries(15, 15) # Flush buffers self.flush_rx() self.flush_tx() self.clear_irq_flags() def end(self): if self.spidev: self.spidev.close() self.spidev = None def startListening(self): self.write_register( NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP | NRF24.PRIM_RX) self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) self.flush_tx() self.flush_rx() self.clear_irq_flags() # Restore the pipe0 address, if exists if self.pipe0_reading_address: self.write_register(self.RX_ADDR_P0, self.pipe0_reading_address) # Go! self.ce(1) def ce(self, level, pulse=0): # CE Pin is optional if self.ce_pin is not None: GPIO.output(self.ce_pin, level) if pulse > 0: time.sleep(pulse) GPIO.output(self.ce_pin, 1 - level) def irqWait(self, timeout=30000): # TODO: A race condition may occur here. => wait for level? if GPIO.input( self.irq_pin) == 0: # Pin is already down. Packet is waiting? return True try: return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING, timeout) == 1 except TypeError: # Timeout parameter not supported return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING) == 1 except AttributeError: raise RuntimeError("GPIO lib does not support wait_for_edge()") def read_register(self, reg, length=1): buf = [NRF24.R_REGISTER | (NRF24.REGISTER_MASK & reg)] buf += [NRF24.NOP] * max(1, length) resp = self.spidev.xfer2(buf) if length == 1: return resp[1] return resp[1:] def write_register(self, reg, value): """ Write register value """ buf = [NRF24.W_REGISTER | (NRF24.REGISTER_MASK & reg)] buf += self._to_8b_list(value) self.spidev.xfer2(buf) def write_payload(self, buf): """ Writes data to the payload register, automatically padding it to match the required length. Returns the number of bytes actually written. """ buf = self._to_8b_list(buf) if self.dynamic_payloads_enabled: if len(buf) > self.MAX_PAYLOAD_SIZE: raise RuntimeError("Dynamic payload is larger than the " + "maximum size.") blank_len = 0 else: if len(buf) > self.payload_size: raise RuntimeError("Payload is larger than the fixed payload" + "size (%d vs. %d bytes)" % (len(buf), self.payload_size)) blank_len = self.payload_size - len(buf) txbuffer = [NRF24.W_TX_PAYLOAD] + buf + ([0x00] * blank_len) self.spidev.xfer2(txbuffer) return len(txbuffer) - 1 def read_payload(self, buf, buf_len=-1): """ Reads data from the payload register and sets the DR bit of the STATUS register. """ if buf_len < 0: buf_len = self.payload_size if not self.dynamic_payloads_enabled: data_len = min(self.payload_size, buf_len) blank_len = self.payload_size - data_len else: data_len = self.getDynamicPayloadSize() blank_len = 0 txbuffer = [NRF24.R_RX_PAYLOAD ] + [NRF24.NOP] * (blank_len + data_len + 1) payload = self.spidev.xfer2(txbuffer) del buf[:] buf += payload[1:data_len + 1] self.write_register(NRF24.STATUS, NRF24.RX_DR) return data_len def flush_rx(self): return self.spidev.xfer2([NRF24.FLUSH_RX])[0] def flush_tx(self): return self.spidev.xfer2([NRF24.FLUSH_TX])[0] def get_status(self): return self.spidev.xfer2([NRF24.NOP])[0] def print_status(self, status): status_str = "0x{0:02x} RX_DR={1:x} TX_DS={2:x} MAX_RT={3:x} RX_P_NO={4:x} TX_FULL={5:x}".format( status, 1 if status & NRF24.RX_DR else 0, 1 if status & NRF24.TX_DS else 0, 1 if status & NRF24.MAX_RT else 0, ((status >> NRF24.RX_P_NO) & int("111", 2)), 1 if status & NRF24.TX_FULL else 0) self.print_single_status_line("STATUS", status_str) def print_observe_tx(self, value): tx_str = "OBSERVE_TX=0x{0:02x}: POLS_CNT={2:x} ARC_CNT={2:x}\r\n".format( value, (value >> NRF24.PLOS_CNT) & int("1111", 2), (value >> NRF24.ARC_CNT) & int("1111", 2)) self.print_single_status_line("OBSERVE_TX", tx_str) def print_byte_register(self, name, reg, qty=1): registers = [ "0x{:0>2x}".format(self.read_register(reg + r)) for r in range(0, qty) ] self.print_single_status_line(name, " ".join(registers)) def print_address_register(self, name, reg, qty=1): address_registers = [ "0x{0:>02x}{1:>02x}{2:>02x}{3:>02x}{4:>02x}".format( *self.read_register(reg + r, 5)) for r in range(qty) ] self.print_single_status_line(name, " ".join(address_registers)) def setChannel(self, channel): if channel < 0 or channel > self.MAX_CHANNEL: raise RuntimeError("Channel number out of range") self.channel = channel self.write_register(NRF24.RF_CH, channel) def getChannel(self): return self.read_register(NRF24.RF_CH) def setPayloadSize(self, size): self.payload_size = min(max(size, 1), NRF24.MAX_PAYLOAD_SIZE) def getPayloadSize(self): return self.payload_size def printDetails(self): self.print_status(self.get_status()) self.print_address_register("RX_ADDR_P0-1", NRF24.RX_ADDR_P0, 2) self.print_byte_register("RX_ADDR_P2-5", NRF24.RX_ADDR_P2, 4) self.print_address_register("TX_ADDR", NRF24.TX_ADDR) self.print_byte_register("RX_PW_P0-6", NRF24.RX_PW_P0, 6) self.print_byte_register("EN_AA", NRF24.EN_AA) self.print_byte_register("EN_RXADDR", NRF24.EN_RXADDR) self.print_byte_register("RF_CH", NRF24.RF_CH) self.print_byte_register("RF_SETUP", NRF24.RF_SETUP) self.print_byte_register("SETUP_AW", NRF24.SETUP_AW) self.print_byte_register("OBSERVE_TX", NRF24.OBSERVE_TX) self.print_byte_register("CONFIG", NRF24.CONFIG) self.print_byte_register("FIFO_STATUS", NRF24.FIFO_STATUS) self.print_byte_register("DYNPD", NRF24.DYNPD) self.print_byte_register("FEATURE", NRF24.FEATURE) self.print_single_status_line( "Data Rate", NRF24.datarate_e_str_P[self.getDataRate()]) self.print_single_status_line("Model", NRF24.model_e_str_P[self.isPVariant()]) self.print_single_status_line( "CRC Length", NRF24.crclength_e_str_P[self.getCRCLength()]) self.print_single_status_line("PA Power", NRF24.pa_dbm_e_str_P[self.getPALevel()]) def stopListening(self): self.ce(0) self.flush_tx() self.flush_rx() self.clear_irq_flags() # Enable TX self.write_register(NRF24.CONFIG, (self.read_register(NRF24.CONFIG) | NRF24.PWR_UP) & ~NRF24.PRIM_RX) # Enable pipe 0 for auto-ack self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | 1) def powerDown(self): self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) & ~NRF24.PWR_UP) def powerUp(self): self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP) time.sleep(150e-6) def write(self, buf): self.last_error = None length = self.write_payload(buf) self.ce(1) sent_at = monotonic() packet_time = ( (1 + length + self.crc_length + self.address_length) * 8 + 9) / (self.data_rate_bits * 1000.) if self.auto_ack != 0: packet_time *= 2 if self.retries != 0 and self.auto_ack != 0: timeout = sent_at + (packet_time + self.delay) * self.retries else: timeout = sent_at + packet_time * 2 # 2 is empiric #while NRF24.TX_DS & self.get_status() == 0: # pass #print monotonic() - sent_at #print packet_time while monotonic() < timeout: time.sleep(packet_time) status = self.get_status() if status & NRF24.TX_DS: self.ce(0) return True if status & NRF24.MAX_RT: self.last_error = 'MAX_RT' self.ce(0) break self.ce(0) if self.last_error is None: self.last_error = 'TIMEOUT' self.flush_tx() # Avoid leaving the payload in tx fifo return False def startFastWrite(self, buf): """ Do not wait for CE HIGH->LOW """ # Send the payload self.write_payload(buf) self.ce(1) def startWrite(self, buf): # Send the payload self.write_payload(buf) # Allons! self.ce(1, 10e-6) def getDynamicPayloadSize(self): return self.spidev.xfer2([NRF24.R_RX_PL_WID, NRF24.NOP])[1] def available(self, pipe_num=None, irq_wait=False, irq_timeout=30000): status = self.get_status() result = False # Sometimes the radio specifies that there is data in one pipe but # doesn't set the RX flag... if status & NRF24.RX_DR or (status & NRF24.RX_P_NO_MASK != NRF24.RX_P_NO_MASK): result = True else: if irq_wait: # Will use IRQ wait if self.irqWait(irq_timeout): # Do we have a packet? status = self.get_status() # Seems like we do! if status & NRF24.RX_DR or (status & NRF24.RX_P_NO_MASK != NRF24.RX_P_NO_MASK): result = True if result and pipe_num is not None: del pipe_num[:] pipe_num.append((status & NRF24.RX_P_NO_MASK) >> NRF24.RX_P_NO) # Handle ack payload receipt if status & NRF24.TX_DS: self.write_register(NRF24.STATUS, NRF24.TX_DS) return result def read(self, buf, buf_len=-1): # Fetch the payload self.read_payload(buf, buf_len) # was this the last of the data available? return self.read_register(NRF24.FIFO_STATUS & NRF24.RX_EMPTY) def clear_irq_flags(self): self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) def whatHappened(self): # Read the status & reset the status in one easy call # Or is that such a good idea? self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) status = self.get_status() self.clear_irq_flags() # Report to the user what happened tx_ok = status & NRF24.TX_DS tx_fail = status & NRF24.MAX_RT rx_ready = status & NRF24.RX_DR return {'tx_ok': tx_ok, "tx_fail": tx_fail, "rx_ready": rx_ready} def openWritingPipe(self, value): # Note that the NRF24L01(+) # expects it LSB first. self.write_register(NRF24.RX_ADDR_P0, value) self.write_register(NRF24.TX_ADDR, value) if not self.dynamic_payloads_enabled: self.write_register(NRF24.RX_PW_P0, self.payload_size) def openReadingPipe(self, pipe, address): # If this is pipe 0, cache the address. This is needed because # openWritingPipe() will overwrite the pipe 0 address, so # startListening() will have to restore it. if pipe >= 6: raise RuntimeError("Invalid pipe number") if (pipe >= 2 and len(address) > 1) or len(address) > 5: raise RuntimeError("Invalid adress length") if pipe == 0: self.pipe0_reading_address = address self.write_register(NRF24.RX_ADDR_P0 + pipe, address) if not self.dynamic_payloads_enabled: self.write_register(NRF24.RX_PW_P0 + pipe, self.payload_size) # Note it would be more efficient to set all of the bits for all open # pipes at once. However, I thought it would make the calling code # more simple to do it this way. self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | (1 << pipe)) def closeReadingPipe(self, pipe): self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) & ~(1 << pipe)) def toggle_features(self): buf = [NRF24.ACTIVATE, 0x73] self.spidev.xfer2(buf) def enableDynamicPayloads(self): # Enable dynamic payload throughout the system self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_DPL) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register( NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_DPL) # Enable dynamic payload on all pipes # Not sure the use case of only having dynamic payload on certain # pipes, so the library does not support it. self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | 0b00111111) self.dynamic_payloads_enabled = True def enableAckPayload(self): # enable ack payload and dynamic payload features self.write_register( NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_ACK_PAY | NRF24.EN_DPL) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register( NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_ACK_PAY | NRF24.EN_DPL) # Enable dynamic payload on pipes 0 & 1 self.write_register( NRF24.DYNPD, self.read_register(NRF24.DYNPD) | NRF24.DPL_P1 | NRF24.DPL_P0) def writeAckPayload(self, pipe, buf, buf_len): txbuffer = [NRF24.W_ACK_PAYLOAD | (pipe & 0x7)] max_payload_size = 32 data_len = min(buf_len, max_payload_size) txbuffer.extend(buf[0:data_len]) self.spidev.xfer2(txbuffer) def isAckPayloadAvailable(self): result = self.ack_payload_available self.ack_payload_available = False return result def isPVariant(self): return self.p_variant def setAutoAck(self, enable): if enable: self.write_register(NRF24.EN_AA, 0x3F) self.auto_ack = 0x3f if self.crc_length == 0: self.setCRCLength( NRF24.CRC_8 ) # Enhanced Shockburst requires at least 1 byte CRC else: self.auto_ack = 0 self.write_register(NRF24.EN_AA, 0) def setAutoAckPipe(self, pipe, enable): if pipe <= 6: en_aa = self.read_register(NRF24.EN_AA) if enable: self.setCRCLength( NRF24.CRC_8 ) # Enhanced Shockburst requires at least 1 byte CRC en_aa |= 1 << pipe self.auto_ack |= 1 << pipe else: en_aa &= ~1 << pipe self.auto_ack &= ~1 << pipe self.write_register(NRF24.EN_AA, en_aa) def setAddressWidth(self, width): if width >= 2 and width <= 5: self.write_register(NRF24.SETUP_AW, width - 2) self.address_width = width def testCarrier(self): return self.read_register(NRF24.RPD) & 1 def setPALevel(self, level): setup = self.read_register(NRF24.RF_SETUP) setup &= ~(NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH) if level == NRF24.PA_MAX: setup |= NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH elif level == NRF24.PA_HIGH: setup |= NRF24.RF_PWR_HIGH elif level == NRF24.PA_LOW: setup |= NRF24.RF_PWR_LOW elif level == NRF24.PA_MIN: pass elif level == NRF24.PA_ERROR: # On error, go to maximum PA setup |= NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH self.write_register(NRF24.RF_SETUP, setup) def getPALevel(self): power = self.read_register( NRF24.RF_SETUP) & (NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH) if power == (NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH): return NRF24.PA_MAX elif power == NRF24.RF_PWR_HIGH: return NRF24.PA_HIGH elif power == NRF24.RF_PWR_LOW: return NRF24.PA_LOW else: return NRF24.PA_MIN def setDataRate(self, speed): setup = self.read_register(NRF24.RF_SETUP) setup &= ~(NRF24.RF_DR_LOW | NRF24.RF_DR_HIGH) if speed == NRF24.BR_250KBPS: # Must set the RF_DR_LOW to 1 RF_DR_HIGH (used to be RF_DR) is already 0 # Making it '10'. self.data_rate_bits = 250 self.data_rate = NRF24.BR_250KBPS setup |= NRF24.RF_DR_LOW elif speed == NRF24.BR_2MBPS: # Set 2Mbs, RF_DR (RF_DR_HIGH) is set 1 # Making it '01' self.data_rate_bits = 2000 self.data_rate = NRF24.BR_2MBPS setup |= NRF24.RF_DR_HIGH else: # 1Mbs self.data_rate_bits = 1000 self.data_rate = NRF24.BR_1MBPS self.write_register(NRF24.RF_SETUP, setup) # Verify our result return self.read_register(NRF24.RF_SETUP) == setup def getDataRate(self): dr = self.read_register( NRF24.RF_SETUP) & (NRF24.RF_DR_LOW | NRF24.RF_DR_HIGH) # Order matters in our case below if dr == NRF24.RF_DR_LOW: # '10' = 250KBPS return NRF24.BR_250KBPS elif dr == NRF24.RF_DR_HIGH: # '01' = 2MBPS return NRF24.BR_2MBPS else: # '00' = 1MBPS return NRF24.BR_1MBPS def setCRCLength(self, length): config = self.read_register( NRF24.CONFIG) & ~(NRF24.EN_CRC | NRF24.CRCO) if length == NRF24.CRC_DISABLED: self.crc_length = 0 elif length == NRF24.CRC_8: config |= NRF24.EN_CRC config &= ~NRF24.CRCO self.crc_length = 1 else: config |= NRF24.EN_CRC config |= NRF24.CRCO self.crc_length = 2 self.write_register(NRF24.CONFIG, config) def getCRCLength(self): result = NRF24.CRC_DISABLED config = self.read_register(NRF24.CONFIG) & (NRF24.CRCO | NRF24.EN_CRC) if config & NRF24.EN_CRC: if config & NRF24.CRCO: result = NRF24.CRC_16 else: result = NRF24.CRC_8 return result def disableCRC(self): disable = self.read_register(NRF24.CONFIG) & ~NRF24.EN_CRC self.write_register(NRF24.CONFIG, disable) def setRetries(self, delay, count): self.write_register(NRF24.SETUP_RETR, (delay & 0xf) << NRF24.ARD | (count & 0xf) << NRF24.ARC) self.delay = delay * 0.000250 self.retries = count self.max_timeout = (self.payload_size / float(self.data_rate_bits) + self.delay) * self.retries self.timeout = (self.payload_size / float(self.data_rate_bits) + self.delay) def getRetries(self): return self.read_register(NRF24.SETUP_RETR) def getMaxTimeout(self): return self.max_timeout def getTimeout(self): return self.timeout def reset(self): """ Make sure the NRF is in the same state as after power up to avoid problems resulting from left over configuration from other programs.""" self.ce(0) reset_values = { 0: 0x08, 1: 0x3F, 2: 0x02, 3: 0x03, 4: 0x03, 5: 0x02, 6: 0x06, 0x0a: [0xe7, 0xe7, 0xe7, 0xe7, 0xe7], 0x0b: [0xc2, 0xc2, 0xc2, 0xc2, 0xc2], 0x0c: 0xc3, 0x0d: 0xc4, 0x0e: 0xc5, 0x0f: 0xc6, 0x10: [0xe7, 0xe7, 0xe7, 0xe7, 0xe7], 0x11: 0, 0x12: 0, 0x13: 0, 0x14: 0, 0x15: 0, 0x16: 0, 0x1c: 0, 0x1d: 0 } for reg, value in reset_values.items(): self.write_register(reg, value) self.flush_rx() self.flush_tx()
GPIO.output(ADC_RUN_PIN, GPIO.HIGH) time.sleep(0.5) GPIO.output(ADC_RUN_PIN, GPIO.LOW) time.sleep(0.5) GPIO.output(ADC_RUN_PIN, GPIO.HIGH) GPIO.output(ADC_RESET_PIN, GPIO.HIGH) # ADC powered up now, wait a second before starting SPI transfers time.sleep(1) # SPI Adafruit library: https://github.com/adafruit/adafruit-beaglebone-io-python/blob/master/docs/SPI.rst #print(spi.xfer2([(0b10000000 | 0x11), 0x00])) # read register 0x11 run(['config-pin', 'P9.18', 'spi']) # can't have MOSI high during power up, so now configure as SPI spi = SPI(0, 0) #print(spi.xfer2([(0b00000000 | 0x11), 0b01110100])) # write register 0x11 low power mode (8kHz), internal reference on print(spi.xfer2([(0b00000000 | 0x11), 0b01110100])) # write register 0x11 high power mode (16kHz), internal reference on print(spi.xfer2([(0b00000000 | 0x15), 0b01000000])) # write register 0x15, internal reference # To compile firmware, use the command: pasm -b -V3 HWL_ping.pasm pruss = Icss( "/dev/uio/pruss/module" ) pruss.initialize() core = pruss.core1 # CORE 1!!!! # load program with open('HWL_ping.bin', 'rb') as f: core.iram.write( f.read() ) NUM_SAMPLES = 5000 class Shmem( ctypes.Structure ):