def PullData(): print("pull data") spi = SPI(1, 0) spi.msh = 100000 spi.bpw = 8 spi.writebytes([0x30]) sleep(0.1) moistureVals = spi.readbytes(3) moisture = str(moistureVals[0]) + str(moistureVals[1]) + str(moistureVals[2]) spi.writebytes([0x31]) sleep(0.1) moistureVals1 = spi.readbytes(3) moisture1 = str(moistureVals1[0]) + str(moistureVals1[1]) + str(moistureVals1[2]) spi.writebytes([0x35]) sleep(0.1) lightVals = spi.readbytes(3) light = str(lightVals[0]) + str(lightVals[1]) + str(lightVals[2]) Data = [] Data.append(moisture) Data.append(moisture1) Data.append(light) spi.close() return Data
def __init__(self, bus): # Use Adafruit_BBIO.SPI to initialize the cap # and the spi bus configuration s = SPI(bus, self.__DEVICE) s.msh = self.__SPEED s.mode = self.__MODE s.close() # Use normal file for writing bytes dev = '/dev/spidev%s.%s' % (bus + 1, self.__DEVICE) self.spi = open(dev, 'wb') print 'Opened %s, Freq: %sHz' % (dev, self.__SPEED)
def __init__(self, bus): # Use Adafruit_BBIO.SPI to initialize the cap # and the spi bus configuration s = SPI(bus, self.__DEVICE) s.msh = self.__SPEED s.mode = self.__MODE s.close() # Use normal file for writing bytes dev = '/dev/spidev%s.%s' % (bus + 1, self.__DEVICE) self.spi = open(dev, 'wb') print 'Opened %s, Freq: %sHz' % (dev, self.__SPEED)
def getMoist_ch1(): #print("Reading Moisture CH 1") spi = SPI(1, 0) spi.msh = 100000 spi.bpw = 8 spi.writebytes([0x31]) sleep(0.01) moistureVals = spi.readbytes(3) moisture = str(moistureVals[0]) + str(moistureVals[1]) + str(moistureVals[2]) spi.close() return moisture
def getLight(): #print("Reading Light Data") spi = SPI(1, 0) spi.msh = 100000 spi.bpw = 8 spi.writebytes([0x35]) sleep(0.01) lightVals = spi.readbytes(3) light = str(lightVals[0]) + str(lightVals[1]) + str(lightVals[2]) spi.close() return light
def Watering(): print("watering") spi = SPI(1, 0) spi.msh = 100000 spi.bpw = 8 list = [] i=0 while i<50: spi.writebytes([0x31]) sleep(0.1) list.append(spi.readbytes(3)) print(list.pop()) ++i sleep(0.5) spi.close()
def stopWatering(): print("Stopping watering") session['watering_command_status'] = "OFF" # send the signal to arduino to stop watering spi = SPI(1, 0) spi.msh = 100000 spi.bpw = 8 # send the appropriate signal spi.writebytes([0x37]) # '7' print(spi.readbytes(1)) spi.close() return flask.redirect("/")
def startWatering(): print("Started watering...") session['watering_command_status'] = "ON" # send the signal to arduino to start watering spi = SPI(1, 0) spi.msh = 100000 spi.bpw = 8 # send the appropriate signal spi.writebytes([0x36]) # '6' print(spi.readbytes(1)) spi.close() return flask.redirect("/")
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
class DACRef: def __init__(self, maxClock=3300000): # using two's complement self.dacSend = "0001" self.max_raw_minus = -pow(2, 19) # maximal value that can be achieved self.max_raw_plus = int(0b01111111111111111111) self.actVal = 0 # actual value # SPI self.spi = SPI(1, 0) # choose SPI device self.spi.mode = 0b00 if maxClock > 1000: self.spi.msh = maxClock else: self.spi.msh = 3300000 print("Minumum clock speed is 10000, setting default 33Mhz") # Start values self.reset = 0 self.ldac = 0 # in the beggining the device is not ready(remember they are inverted) # P8 GPIO.setup("P8_17", GPIO.OUT) # LDAC GPIO.output("P8_17", self.ldac) GPIO.setup("P8_18", GPIO.OUT) # RESET GPIO.output("P8_18", self.reset) # GPIO.setup("P8_15", GPIO.OUT) #ext rsten # GPIO.setup("P8_14", GPIO.OUT) # PLL LOCK # GPIO.setup("P8_16", GPIO.OUT) # ext Ioupden # NOT USED # P9 (addresses) self.dacAddress = [0, 0, 0, 0, 0] # default GPIO.setup("P9_11", GPIO.OUT) # P1 GPIO.setup("P9_12", GPIO.OUT) # P2 GPIO.setup("P9_13", GPIO.OUT) # P3 GPIO.setup("P9_14", GPIO.OUT) # P4 GPIO.setup("P9_15", GPIO.OUT) # P0 def setDACAddress(self, list): self.dacAddress = list GPIO.setup("P9_15", self.dacAddress[0]) # P0 GPIO.setup("P9_11", self.dacAddress[1]) # P1 GPIO.setup("P9_12", self.dacAddress[2]) # P2 GPIO.setup("P9_13", self.dacAddress[3]) # P3 GPIO.setup("P9_14", self.dacAddress[4]) # P4 def chooseDAC(self, dacNum=0, board=0): if board == 0: p2 = 0 p3 = 0 p4 = 0 elif board == 1: p2 = 0 p3 = 0 p4 = 1 elif board == 2: p2 = 0 p3 = 1 p4 = 0 elif board == 3: p2 = 0 p3 = 1 p4 = 1 else: print("WRONG NUMBER, SETTING 0") p2 = 0 p3 = 0 p4 = 0 GPIO.output("P9_12", p2) GPIO.output("P9_13", p3) GPIO.output("P9_14", p4) if dacNum == 0: p0 = 0 p1 = 0 elif dacNum == 1: p0 = 0 p1 = 1 elif dacNum == 2: p0 = 1 p1 = 0 elif dacNum == 3: p0 = 1 p1 = 1 GPIO.output("P9_15", p0) GPIO.output("P9_11", p1) self.dacAddress = [p0, p1, p2, p3, p4] def setLDAC(self, ldac): self.ldac = ldac GPIO.output("P8_17", self.ldac) def resetDAC(self): self.reset = 1 GPIO.output("P8_18", self.reset) GPIO.output("P8_18", 0) # returns it back to 0 def setValueRaw(self, raw): if self.max_raw_plus >= int(raw) >= self.max_raw_minus: self.actVal = int(raw) print("Actual value is: " + str(self.actVal)) else: self.actVal = 0 # if we go out of range we get 0 print("Out of range[-1,1] or 0.") # print("Actual value is: " + str(self.actVal)) self.registerValue() def setValueNorm(self, norm): if 0 < norm <= 1: self.actVal = int(self.max_raw_plus * norm) print("Actual value is: " + str(self.actVal)) elif 0 > norm >= -1: self.actVal = int(-self.max_raw_minus * norm) # print("Actual value is: " + str(self.actVal)) else: self.actVal = 0 print("Out of range[-1,1] or 0.") # print("Actual value is: " + str(self.actVal)) self.registerValue() def setValHelp(self, address): val = input("Write the value from [-524288,524287]: ") if val <= self.max_raw_plus and val >= self.max_raw_minus: self.setDACAddress(address) self.setValueNorm(int(val)) else: print("Wrong number, doing nothing") return def initializeDAC(self): # we can always change the initialize and make it more flexible GPIO.output("P8_17", GPIO.HIGH) self.spi.writebytes([0b00100000, 0b00000000, 0b00100010]) GPIO.output("P8_17", GPIO.LOW) def registerValue(self): self.initializeDAC() if self.actVal != 0: temp = convertComplement_DAC(self.actVal, 20) string1 = self.dacSend + temp[0:4] string2 = temp[4:12] string3 = temp[12:] GPIO.output("P8_17", GPIO.HIGH) self.spi.writebytes([int(string1, 2), int(string2, 2), int(string3, 2)]) GPIO.output("P8_17", GPIO.LOW) else: self.resetDAC() def __del__(self): self.resetDAC() self.spi.close()
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()
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
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()
data.append(line) count += 1 elif count == 19: data.pop(0) break data.append(str(resultFinal))# + '\n') print data #print len(data) #data.pop(0) file.close() f = open('methane_test.txt' ,'w').close() #f = open('methane_test.txt','r+') #f.truncate() file = open('methane_test.txt', 'w') for number in data: print number #file.write("\n") file.write("%s" % number) #file.write("\n") ##################################### ##################################### #print data #print result[0] #"EYYYYY" #print result[1] file.close() #end while except KeyboardInterrupt: spi.close()
class DAC: def __init__(self): # create outer classes with ability to change inner parameters # using two's complement # CONSTS self.DAC_SEND = "0001" # value to be sending information to dac self.MAX_NEG = -pow(2, 19) # max neg value that can be achieved self.MAX_POS = int( 0b01111111111111111111) # max pos value that can be achieved self.MAX_CLOCK = 340000 # maximal clock value we can get in Hz self.MIN_CLOCK = 50000 # minimal clock value we can get in Hz self.IP = '192.168.0.20' self.PORT = 5555 self.act_val = 0 # actual value self.clock = self.MIN_CLOCK # begin with min value self.spi = SPI(1, 0) # spi for our communication self.spi.mode = 0b00 self.spi.msh = self.clock # Triggers for the DAC self.reset = False self.ldac = False GPIO.setup("P8_17", GPIO.OUT) # LDAC GPIO.setup("P8_18", GPIO.OUT) # RESET GPIO.output("P8_18", self.reset) GPIO.output("P8_17", self.ldac) # Address for which DAC self.dac_address = list() self.dac_address = [0, 0, 0, 0, 0] # default GPIO.setup("P9_15", GPIO.OUT) # P0 GPIO.setup("P9_11", GPIO.OUT) # P1 GPIO.setup("P9_12", GPIO.OUT) # P2 GPIO.setup("P9_13", GPIO.OUT) # P3 GPIO.setup("P9_14", GPIO.OUT) # P4 GPIO.output("P9_15", GPIO.LOW) # P0 GPIO.output("P9_11", GPIO.LOW) # P1 GPIO.output("P9_12", GPIO.LOW) # P2 GPIO.output("P9_13", GPIO.LOW) # P3 GPIO.output("P9_14", GPIO.LOW) # P4 self.initializeDAC() # server def reset_dac(self): GPIO.output("P8_18", 1) print('Reseting DAC') self.spi.close() self.spi = SPI(1, 0) GPIO.output("P8_18", 0) # returns it back to 0 def __del__(self): self.reset_dac() # reset voltage self.spi.close() # spi close def initializeDAC( self ): # we can always change the initialize and make it more flexible GPIO.output("P8_17", GPIO.HIGH) self.spi.writebytes([0b00100000, 0b00000000, 0b00100010]) GPIO.output("P8_17", GPIO.LOW) def registerValue(self): self.initializeDAC() if self.act_val != 0: temp = self.convertComplement_DAC(self.act_val, 20) string1 = self.DAC_SEND + temp[0:4] string2 = temp[4:12] string3 = temp[12:] GPIO.output("P8_17", GPIO.HIGH) self.spi.writebytes( [int(string1, 2), int(string2, 2), int(string3, 2)]) print('Sending to the DAC: ', string1 + string2 + string3) GPIO.output("P8_17", GPIO.LOW) else: self.reset_dac() return @staticmethod def convertComplement_DAC(value, width=20): # Return the binary representation of the input number as a string. # If width is not given it is assumed to be 20. If width is given, the two's complement of the number is # returned, with respect to that width. # In a two's-complement system negative numbers are represented by the two's # complement of the absolute value. This is the most common method of # representing signed integers on computers. A N-bit two's-complement # system can represent every integer in the range [-2^(N-1),2^(N-1)-1] def warning(widt, width_bin): # the function checks if the width is a good value for input number, if not (f.e smaller) returning # default 20 if widt != 20 and (widt <= 0 or width < width_bin): print("Bad width, returning default\n") return width_bin elif widt == 20 and widt < width_bin: return width_bin else: return widt if value > 0: binar = bin( int(value))[2:] # take binary representation of input value real_width = warning(width, len(binar)) # check width if real_width > len( binar): # add zeros if width is bigger that binary length for x1 in range(0, real_width - len(binar)): binar = "0" + binar return binar elif value == 0: # all zeros binar = "" for x2 in range(0, width): binar = "0" + binar elif value < 0: binar = bin( abs(int(value)) )[2:] # because of the minus sign at the beginning we take absolute value real_width = warning(width, len(binar)) if abs(value) == pow(2, real_width - 1): return binar if real_width > len( binar ): # with bigger length we have to add zeros at the beginning for x3 in range(0, real_width - len(binar)): binar = "0" + binar strin = "" # empty temporary string for x in range(0, real_width): if int(binar[x]) == 1: temp = 0 # negating for the 2's complement else: temp = 1 strin = strin + str(temp) temp_add = int(strin, 2) temp_add = temp_add + 1 binar = bin(temp_add)[2:] return binar
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()
print readID(flash_handler, flash3_cs) totalErase(flash_handler, flash1_cs) totalErase(flash_handler, flash2_cs) totalErase(flash_handler, flash3_cs) # #writeByte(flash_handler,0x00,33) # #writeByte(flash_handler,0x01,34) # erase4kbSector(flash_handler, 0) # f.write(datetime.datetime.now()) data1 = [i for i in range(100)] data2 = [2 * i for i in range(100)] data3 = [3 * i for i in range(100)] writeBytes(flash_handler, 0x000000, data1, flash1_cs) writeBytes(flash_handler, 0x000000, data2, flash2_cs) writeBytes(flash_handler, 0x000000, data3, flash3_cs) print readBytes(flash_handler, 0x00, 32, flash1_cs) print readBytes(flash_handler, 0x00, 32, flash2_cs) print readBytes(flash_handler, 0x00, 32, flash3_cs) erase4kbSector(flash_handler, 0, flash1_cs) erase4kbSector(flash_handler, 0, flash2_cs) erase4kbSector(flash_handler, 0, flash3_cs) print readBytes(flash_handler, 0x00, 32, flash1_cs) print readBytes(flash_handler, 0x00, 32, flash2_cs) print readBytes(flash_handler, 0x00, 32, flash3_cs) # #print readBytes(flash_handler, 0x00, 200) # erase4kbSector(flash_handler, 0) # data = [i for i in range(256)] # writeBytes(flash_handler, 0x000000, data) # print readBytes(flash_handler, 0x00, 1<<8) # erase4kbSector(flash_handler, 0) flash_handler.close()