def run(self): #Only need to execute one of the following lines: #spi = SPI(bus, device) #/dev/spidev<bus>.<device> spi = SPI(0, 0) #/dev/spidev1.0 spi.msh = 2000000 # SPI clock set to 2000 kHz spi.bpw = 8 # bits/word spi.threewire = False spi.lsbfirst = False spi.mode = 1 spi.cshigh = False # chip select (active low) spi.open(0, 0) print("spi... msh=" + str(spi.msh)) gchannel = 0 buf0 = (7 << 3) | ((gchannel & 0x0f) >> 1) #(7<<3) for auto-2 mode buf1 = (gchannel & 0x01) << 7 buf1 = buf1 | 0x40 #select 5v i/p range while (self.running): ret = spi.xfer2([buf0, buf1]) print("0x%x 0x%x" % (ret[0], ret[1])) chanl = (ret[0] & 0xf0) >> 4 adcval = ((ret[0] & 0x0f) << 4) + ((ret[1] & 0xf0) >> 4) print(" -> chanl=%d adcval=0x%x" % (chanl, adcval)) time.sleep(1)
def ini_levels(): check_ok = 0 update_data = 0x39 # spi.set_clock_hz(1000000) # spi.set_mode(0) # spi.set_bit_order(SPI.MSBFIRST) SPI_PORT = 0 SPI_DEVICE = 0 # SPI setup spi = SPI(0, 0) #/dev/spidev1.0 spi.msh = 100000 # SPI clock set to 100 kHz spi.bpw = 8 # bits/word spi.threewire = False spi.lsbfirst = False spi.mode = 0 spi.cshigh = False # ADS1248 chip select (active low) # spi.open(0,0) spi.open(SPI_PORT, SPI_DEVICE) print "SPI port ", SPI_PORT, " ", SPI_DEVICE, " open"
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()
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()
import time pause = 0.1 chipSelect = "P9_12" GPIO.setup(chipSelect, GPIO.OUT) GPIO.output(chipSelect, GPIO.HIGH) sclk = "P9_11" GPIO.setup(sclk, GPIO.IN) spi = SPI(0, 0) spi.mode = 0 spi.msh = 500000 spi.open(0, 0) # global count # count = 0; # # def callback_function_print(input_pin): # count = count + 1 # print "Input on pin", input_pin # # GPIO.add_event_detect(sclk, GPIO.BOTH, callback=callback_function_print) def spi_write(num): print "Writing " + num + "..." GPIO.output(chipSelect, GPIO.LOW) print str(spi.xfer2([int(num)]))
#OM SPI TE ENABLEN #config-pin P9.20 spi #en da me alle pins 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)
class Brightbar: #[brightness, blue, green, red] pixel_buffer = [POWER, 0, 0, 0] * LEDS_PER_PANEL * NUM_PANELS start_clock = None animation_time = 20000 def __init__(self): self.init_spi() #animation = GifAnimation('gifs/extracted/trippy_39_30x30') #animation = SparkleAnimation(None, SparkleAnimation.SPEED_SLOW, [POWER,255,255,255], 1000) #animation = SparkleAnimation(None, 2000, [POWER,255,255,255], 1000) #animation = LinesAnimation(None, 3000, [POWER,255,255,255], 0) animation = RainAnimation(None, .1, [POWER, 0.0, 200.0, 0.0]) self.animations = [ SparkleAnimation(None, 2000, [POWER, 255, 255, 255], 1000), LinesAnimation(None, 3000, [POWER, 255, 255, 255], 0), RainAnimation(None, .1, [POWER, 0.0, 200.0, 0.0]) ] self.render_thread = None def init_spi(self): logging.debug("Initializing spi...") self.spi = SPI(0, 0) #/dev/spidev1.0 # SPI Mode Clock Polarity (CPOL/CKP) Clock Phase (CPHA) Clock Edge (CKE/NCPHA) # 0 0 0 1 # 1 0 1 0 # 2 1 0 1 # 3 1 1 0 self.spi.mode = 0 self.spi.msh = SPI_CLOCK_RATE #this is clock speed setting self.spi.open(0, 0) def debug_frame(self, data): for y in range(PANEL_Y): line = str(y) + ": " for x in range(PANEL_X): offset = (y * PANEL_X + x) * 4 line += "|" + str(data[offset]) + "," + str( data[offset + 1]) + "," + str( data[offset + 2]) + "," + str(data[offset + 3]) print line #render a full frame def render(self): #logging.debug("buffer size: " + str(len(self.pixel_buffer)) + " start render: " + str(time.time())) start_time = time.time() #logging.debug(" start render: " + str(start_time)) #make a copy of the buffer to work on in case we need to switch the order of bytes #data = self.pixel_buffer[:] offset = 0 #the panels run in a snake S shape, so every other line needs to have bytes reversed if REVERSE_ALTERNATE_LINES: for i in range(0, PANEL_Y): if (i % 2) == 0: continue offset = i * PANEL_X * 4 line_length = PANEL_X * 4 line = data[offset:offset + line_length] reversed_line = [0] * line_length j = line_length - 4 #start one color from the end, and go backwards through the line while j >= 0: reversed_line[line_length - j - 4] = line[j] reversed_line[line_length - j - 3] = line[j + 1] reversed_line[line_length - j - 2] = line[j + 2] reversed_line[line_length - j - 1] = line[j + 3] j = j - 4 data[offset:offset + PANEL_X * 4] = reversed_line #self.write_apa102(data) #logging.debug("length of buffer: " + str(len(self.pixel_buffer))) #logging.debug(self.pixel_buffer) self.write_apa102(self.pixel_buffer) end_time = time.time() #logging.debug("end render: " + str(end_time) + " elapsed: " + str(end_time - start_time)) #import pdb #pdb.set_trace() def write_apa102(self, data): #start frame, 32 bits of zero self.spi.writebytes([0] * 4) #write RGB data #chunk the data out in 1024 byte blocks for i in range(0, len(data), 1024): length = len(data) if ((i + 1024) > length): #end = length - (i+1024 - length) chunk = data[i:] else: #end = i + 1024 chunk = data[i:i + 1024] self.spi.writebytes(chunk) #write footer. This is total numnber of LEDS / 2 bits of 1's num_dwords = LEDS_PER_PANEL * NUM_PANELS / 32 for i in range(num_dwords): self.spi.writebytes( [0xff, 0x00, 0x00, 0x00] ) #the datasheet calls for 1's here, but internet says 0s work better? the fast LED lib does both? def clear(self): self.pixel_buffer = [POWER, 0, 0, 0] * LEDS_PER_PANEL * NUM_PANELS def calculate_fps(self): now = time.time() delta = now - self.start_clock frame_time = delta / self.frame_count self.fps = 1 / frame_time logging.debug("elapsed seconds: " + str(delta) + " frame count: " + str(self.frame_count) + " current fps: " + str(self.fps)) def animate(self): if self.start_clock == None: self.frame_count = 0 self.start_clock = time.time() elapsed_time = time.time() - self.start_clock num_animations = int(round(elapsed_time / (self.animation_time / 1000))) current_animation = int(num_animations) % len(self.animations) #logging.debug("elapsed time: " + str(elapsed_time) + " num animations:" + str(num_animations) + " current animation:" + str(current_animation)) animation = self.animations[current_animation] frame = animation.get_next_frame() if frame == None: time.sleep(.001) return self.frame_count = self.frame_count + 1 if self.frame_count % 100 == 0: self.calculate_fps() line_length = animation.width * 4 for y in range(animation.height): frame_offset = y * line_length line = frame[frame_offset:frame_offset + line_length] buffer_offset = (( (int(animation.destination_y_offset) + y) * PANEL_X) + int(animation.destination_x_offset)) * 4 self.pixel_buffer[buffer_offset:buffer_offset + line_length] = line def render_loop(self): try: while 1: brightbar.animate() brightbar.render() except: print_exception(*sys.exc_info()) def start(self): if STARTUP_SEQUENCE: startup_sequence(self) if self.render_thread == None: self.render_thread = threading.Thread(name="RenderThread", target=self.render_loop) self.render_thread.start() def stop(self): self.render_thread.stop()
class Enrf24(): __bus = None __device = None __rf_status = 0 __rf_addr_width = 5 __lastirq = None __readpending = 0 __lastTXfailed = False __txbuf_len = 0 __txbuf = [] # Internal IRQ handling __ENRF24_IRQ_TX = 0x20 __ENRF24_IRQ_RX = 0x40 __ENRF24_IRQ_TXFAILED = 0x10 __ENRF24_IRQ_MASK = 0x70 __ENRF24_CFGMASK_IRQ = 0 def __init__(self, bus, device, cePin, csnPin, irqPin): self.__bus = bus self.__device = device self.cePin = cePin self.csnPin = csnPin self.irqPin = irqPin self.spi = SPI(self.__bus, self.__device) self.spi.msh = 10000 self.spi.bpw = 8 # bits/word self.spi.threewire = False self.spi.lsbfirst = False self.spi.mode = 0 self.spi.cshigh = False self.spi.open(0, 0) self.last_payload = "" def begin(self, datarate=1000000, channel=0): # Specify bitrate & channel GPIO.setup(self.cePin, GPIO.OUT) GPIO.output(self.cePin, GPIO.LOW) GPIO.setup(self.csnPin, GPIO.OUT) GPIO.output(self.csnPin, GPIO.HIGH) GPIO.setup(self.irqPin, GPIO.IN) # No pullups; the transceiver provides this! self.spi.writebytes([0x00 ]) # Strawman transfer, fixes USCI issue on G2553 #self.spi.writebytes([0xCF, 0x00]) # Is the transceiver present/alive? if (not self.__isAlive()): return False # Nothing more to do here... # Wait 100ms for module to initialize time.sleep(0.1) # Init certain registers self.__writeReg(RF24_CONFIG, 0x00) # Deep power-down, everything disabled self.__writeReg(RF24_EN_AA, 0x03) self.__writeReg(RF24_EN_RXADDR, 0x03) self.__writeReg(RF24_RF_SETUP, 0x00) self.__writeReg(RF24_STATUS, self.__ENRF24_IRQ_MASK) # Clear all IRQs self.__writeReg(RF24_DYNPD, 0x03) self.__writeReg(RF24_FEATURE, RF24_EN_DPL) # Dynamic payloads enabled by default # Set all parameters if (channel > 125): channel = 125 self.deepsleep() self.__issueCmd(RF24_FLUSH_TX) self.__issueCmd(RF24_FLUSH_RX) self.__readpending = 0 self.__irq_clear(self.__ENRF24_IRQ_MASK) self.setChannel(channel) self.setSpeed(datarate) self.setTXpower() self.setAutoAckParams() self.setAddressLength(self.__rf_addr_width) self.setCRC(True) # Default = CRC on, 8-bit return True def end(self): # Shut it off, clear the library's state self.__txbuf_len = 0 self.__rf_status = 0 self.__rf_addr_width = 5 if (not self.__isAlive()): return self.deepsleep() self.__issueCmd(RF24_FLUSH_TX) self.__issueCmd(RF24_FLUSH_RX) self.readpending = 0 self.__irq_clear(self.__ENRF24_IRQ_MASK) GPIO.output(self.cePin, GPIO.LOW) GPIO.output(self.csnPin, GPIO.HIGH) # I/O def available( self, checkIrq=False): # Check if incoming data is ready to be read #print(checkIrq and GPIO.input(self.irqPin) and self.__readpending == 0) if (checkIrq and GPIO.input(self.irqPin) and self.__readpending == 0): return False self.__maintenanceHook() if ((not self.__readReg(RF24_FIFO_STATUS)) & RF24_RX_EMPTY): return True if (self.__readpending): return True return False def read(self, maxlen=32): # Read contents of RX buffer up to buf = None plwidth = 0 res = "" self.__maintenanceHook() self.__readpending = 0 if ((self.__readReg(RF24_FIFO_STATUS) & RF24_RX_EMPTY) or maxlen < 1): return 0 plwidth = self.__readCmdPayload(RF24_R_RX_PL_WID, plwidth, 1, 1)[0] buf = self.__readCmdPayload(RF24_R_RX_PAYLOAD, buf, plwidth, maxlen) if (self.__irq_derivereason() and self.__ENRF24_IRQ_RX): self.__irq_clear(self.__ENRF24_IRQ_RX) for i in buf: res += chr(i) self.last_payload = res return res # 'maxlen' bytes, return final length. # 'inbuf' should be maxlen+1 since a # null '\0' is tacked onto the end. def getMessage(self): return self.last_payload def write(self, data): if (self.__txbuf_len == 32 ): # If we're trying to stuff an already-full buffer... self.flush() # Blocking OTA TX txbuf = [] data = list(data) for i in data: txbuf.append(ord(i)) self.__txbuf = txbuf self.__txbuf_len = len(txbuf) return 1 def flush(self): # Force transmission of TX ring buffer contents reg = None addrbuf = [] enaa = False origrx = False if (self.__txbuf_len == 0): return # Zero-length buffer? Nothing to send! reg = self.__readReg(RF24_FIFO_STATUS) if ( reg & BITS["BIT5"] ): # RF24_TX_FULL #define is BIT0, which is not the correct bit for FIFO_STATUS. # Seen this before with a user whose CE pin was messed up. self.__issueCmd(RF24_FLUSH_TX) self.__txbuf_len = 0 return # Should never happen, but nonetheless a precaution to take. self.__maintenanceHook() if (reg & RF24_TX_REUSE): # If somehow TX_REUSE is enabled, we need to flush the TX queue before loading our new payload. self.__issueCmd(RF24_FLUSH_TX) if (self.__readReg(RF24_EN_AA) & 0x01 and (self.__readReg(RF24_RF_SETUP) & 0x28) != 0x20): # AutoACK enabled, must write TX addr to RX pipe#0 # Note that 250Kbps doesn't support auto-ack, so we check RF24_RF_SETUP to verify that. enaa = True self.__readTXaddr(addrbuf) self.__writeRXaddrP0(addrbuf) reg = self.__readReg(RF24_CONFIG) if (not (reg & RF24_PWR_UP)): #digitalWrite(_cePin, HIGH); // Workaround for SI24R1 knockoff chips self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP) time.sleep(.05) # 5ms delay required for nRF24 oscillator start-up #digitalWrite(_cePin, LOW); if (reg & RF24_PRIM_RX): origrx = True GPIO.output(self.cePin, GPIO.LOW) self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP) self.__txbuf = self.__issueCmdPayload(RF24_W_TX_PAYLOAD, self.__txbuf) GPIO.output(self.cePin, GPIO.HIGH) time.sleep(0.1) GPIO.output(self.cePin, GPIO.LOW) self.__txbuf_len = 0 # Reset TX ring buffer while (GPIO.input(self.irqPin)): # Wait until IRQ fires pass # IRQ fired self.__maintenanceHook() # Handle/clear IRQ # Purge Pipe#0 address (set to module's power-up default) if (enaa): addrbuf = [0xE7, 0xE7, 0xE7, 0xE7, 0xE7] self.__writeRXaddrP0(addrbuf) # If we were in RX mode before writing, return back to RX mode. if (origrx): self.enableRX() def purge( self): # Ignore TX ring buffer contents, return ring pointer to 0. self.__txbuf_len = 0 # Power-state related stuff- def radioState( self ): # Evaluate current state of the transceiver (see ENRF24_STATE_* defines) if not self.__isAlive(): return ENRF24_STATE_NOTPRESENT counter = 15 reg = self.__readReg(RF24_CONFIG) if reg == 0: while reg == 0 and counter < 15: reg = self.__readReg(RF24_CONFIG) counter += 1 if (not (reg & RF24_PWR_UP)): return ENRF24_STATE_DEEPSLEEP # At this point it's either Standby-I, II or PRX. if (reg & RF24_PRIM_RX): if (GPIO.input(self.cePin)): return ENRF24_STATE_PRX # PRIM_RX=1 but CE=0 is a form of idle state. return ENRF24_STATE_IDLE # Check if TX queue is empty, if so it's idle, if not it's PTX. if (self.__readReg(RF24_FIFO_STATUS) & RF24_TX_EMPTY): return ENRF24_STATE_IDLE return ENRF24_STATE_PTX def printRadioState(self): status = self.radioState() sys.stdout.write("Enrf24 radio transceiver status: ") if status == ENRF24_STATE_NOTPRESENT: print("NO TRANSCEIVER PRESENT") elif status == ENRF24_STATE_DEEPSLEEP: print("DEEP SLEEP <1uA power consumption") elif status == ENRF24_STATE_IDLE: print("IDLE module powered up w/ oscillators running") elif status == ENRF24_STATE_PTX: print("Actively Transmitting") elif status == ENRF24_STATE_PRX: print("Receive Mode") else: print("UNKNOWN STATUS CODE") def printStatus(self): status = self.__readReg(RF24_STATUS) data_ready = str(hex(status & 0x40)) data_sent = str(hex(status & 0x20)) max_tx_retries = str(hex(status & 0x10)) if status & 0x0E == 0x0E: rx_pipe_no = "RX FIFO Empty" elif status & 0x02 == 0x02: rx_pipe_no = 1 elif status & 0x04 == 0x04: rx_pipe_no = 2 elif status & 0x06 == 0x06: rx_pipe_no = 3 elif status & 0x08 == 0x08: rx_pipe_no = 4 elif status & 0x0A == 0x0A: rx_pipe_no = 5 elif ~status & 0x0E: rx_pipe_no = 0 else: rx_pipe_no = "Error" rx_pipe_no = str(rx_pipe_no) tx_fifo_full = str(status & 0x01) status = str(hex(status)) sys.stdout.write("STATUS=") sys.stdout.write(status) sys.stdout.write("\tRX_DR=") sys.stdout.write(data_ready) sys.stdout.write(" TX_DS=") sys.stdout.write(data_sent) sys.stdout.write(" MAX_RT=") sys.stdout.write(max_tx_retries) sys.stdout.write(" RX_P_NO=") sys.stdout.write(rx_pipe_no) sys.stdout.write(" TX_FULL=") print(tx_fifo_full) print("") def printDetails(self): self.printStatus() buf = [] sys.stdout.write("RX_ADDR_P0=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P0, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P1=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P1, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P2=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P2, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P3=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P3, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P4=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P4, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P5=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P5, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") print("") sys.stdout.write("TX_ADDR=") buf = self.__readRegMultiLSB(RF24_TX_ADDR, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") print("") sys.stdout.write("RX_PW_P0=") print(hex(self.__readReg(RF24_RX_PW_P0))) sys.stdout.write("RX_PW_P1=") print(hex(self.__readReg(RF24_RX_PW_P1))) sys.stdout.write("RX_PW_P2=") print(hex(self.__readReg(RF24_RX_PW_P2))) sys.stdout.write("RX_PW_P3=") print(hex(self.__readReg(RF24_RX_PW_P3))) sys.stdout.write("RX_PW_P4=") print(hex(self.__readReg(RF24_RX_PW_P4))) sys.stdout.write("RX_PW_P5=") print(hex(self.__readReg(RF24_RX_PW_P5))) print("") sys.stdout.write("EN_AA=") print(bin(self.__readReg(RF24_EN_AA))) sys.stdout.write("EN_RXADDR=") print(bin(self.__readReg(RF24_EN_RXADDR))) sys.stdout.write("RF_CH=") print(hex(self.__readReg(RF24_RF_CH))) sys.stdout.write("RF_SETUP=") print(bin(self.__readReg(RF24_RF_SETUP))) sys.stdout.write("CONFIG=") print(bin(self.__readReg(RF24_CONFIG))) sys.stdout.write("DYNPD=") print(bin(self.__readReg(RF24_DYNPD))) sys.stdout.write("FEATURE=") print(bin(self.__readReg(RF24_FEATURE))) print("") sys.stdout.write("Data Rate=") print(self.getSpeed()) sys.stdout.write("CRC Length=") print(self.getCRC()) sys.stdout.write("PA Power=") print(self.getTXpower()) def deepsleep(self): # Enter POWERDOWN mode, ~0.9uA power consumption reg = self.__readReg(RF24_CONFIG) if (reg & (RF24_PWR_UP | RF24_PRIM_RX)): self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg)) GPIO.output(self.cePin, GPIO.LOW) def enableRX(self): # Enter PRX mode (~14mA) reg = self.__readReg(RF24_CONFIG) self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP | RF24_PRIM_RX) self.__writeReg(RF24_RX_PW_P0, 0x20) self.__writeReg(RF24_RX_PW_P1, 0x20) GPIO.output(self.cePin, GPIO.HIGH) if ( not (reg & RF24_PWR_UP) ): # Powering up from deep-sleep requires 5ms oscillator start delay time.sleep(0.05) def disableRX(self): # Disable PRX mode (PRIM_RX bit in CONFIG register) # Note this won't necessarily push the transceiver into deep sleep, but rather # an idle standby mode where its internal oscillators are ready & running but # the RF transceiver PLL is disabled. ~26uA power consumption. GPIO.output(self.cePin, GPIO.LOW) reg = self.__readReg(RF24_CONFIG) if ( reg & RF24_PWR_UP ): # Keep us in standby-I if we're coming from RX mode, otherwise stay # in deep-sleep if we call this while already in PWR_UP=0 mode. self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP) else: self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg)) # Custom tweaks to RF parameters, packet parameters def autoAck(self, onoff=True ): # Enable/disable auto-acknowledgements (enabled by default) reg = self.__readReg(RF24_EN_AA) if (onoff): if (not (reg & 0x01) or not (reg & 0x02)): self.__writeReg(RF24_EN_AA, 0x03) else: if (reg & 0x03): self.__writeReg(RF24_EN_AA, 0x00) def setChannel(self, channel): if (channel > 125): channel = 125 self.__writeReg(RF24_RF_CH, channel) def setTXpower( self, dBm=0 ): # Only a few values supported by this (0, -6, -12, -18 dBm) reg = self.__readReg( RF24_RF_SETUP) & 0xF8 # preserve RF speed settings pwr = 0x06 if (dBm >= 7): pwr = 0x07 if (dBm < 0): pwr = 0x04 if (dBm < -6): pwr = 0x02 if (dBm < -12): pwr = 0x00 self.__writeReg(RF24_RF_SETUP, reg | pwr) def setSpeed(self, rfspeed): # Set 250000, 1000000, 2000000 speeds. reg = self.__readReg( RF24_RF_SETUP) & 0xD7 # preserve RF power settings spd = 0x01 if (rfspeed < 2000000): spd = 0x00 if (rfspeed < 1000000): spd = 0x04 self.__writeReg(RF24_RF_SETUP, reg | (spd << 3)) def setCRC(self, onoff, crc16bit=False): # Enable/disable CRC usage inside nRF24's # hardware packet engine, specify 8 or # 16-bit CRC. crcbits = 0 reg = self.__readReg( RF24_CONFIG) & 0xF3 # preserve IRQ mask, PWR_UP/PRIM_RX settings if (onoff): crcbits |= RF24_EN_CRC if (crc16bit): crcbits |= RF24_CRCO self.__writeReg(RF24_CONFIG, (reg | crcbits)) # Set AutoACK retry count, timeout params (0-15, 250-4000 respectively) def setAutoAckParams(self, autoretry_count=15, autoretry_timeout=2000): setup_retr = 0 setup_retr = autoretry_count & 0x0F autoretry_timeout -= 250 setup_retr |= ((autoretry_timeout / 250) & 0x0F) << 4 self.__writeReg(RF24_SETUP_RETR, setup_retr) # Protocol addressing -- receive, transmit addresses def setAddressLength(self, len): # Valid parameters = 3, 4 or 5. Defaults to 5. if (len < 3): len = 3 if (len > 5): len = 5 self.__writeReg(RF24_SETUP_AW, len - 2) self.__rf_addr_width = len def setRXaddress(self, rxaddr): # 3-5 byte RX address loaded into pipe#1 self.__writeRegMultiLSB(RF24_RX_ADDR_P1, rxaddr) def setTXaddress( self, txaddr): # 3-5 byte TX address loaded into TXaddr register self.__writeRegMultiLSB(RF24_TX_ADDR, txaddr) # Miscellaneous feature def rfSignalDetected( self ): # Read RPD register to determine if transceiver has presently detected an RF signal # of -64dBm or greater. Only works in PRX (enableRX()) mode. rpd = self.__readReg(RF24_RPD) return rpd # Query current parameters def getChannel(self): return self.__readReg(RF24_RF_CH) def getSpeed(self): reg = self.__readReg(RF24_RF_SETUP) & 0x28 if (reg == 0x00): return 1000000 elif (reg == 0x08): return 2000000 elif (reg == 0x20): return 250000 else: return 0 def getTXpower(self): reg = self.__readReg(RF24_RF_SETUP) & 0x07 if (reg & 0x01): return 7 # SI24R1-only +7dBm mode elif (reg == 0x02): return -12 elif (reg == 0x04): return -6 elif (reg == 0x06): return 0 else: return -18 def getAddressLength(self): return self.__rf_addr_width def getRXaddress(self): buf = [] buf = self.__readRegMultiLSB(RF24_RX_ADDR_P1, buf, self.__rf_addr_width) return buf def getTXaddress(self): buf = [] buf = self.__readRegMultiLSB(RF24_TX_ADDR, buf, rf_addr_width) return buf def getAutoAck(self): reg = self.__readReg(RF24_EN_AA) if (reg): return True else: return False def getCRC(self): reg = self.__readReg(RF24_CONFIG) & 0x0C if (reg == 0x08): return 8 elif (reg == 0x0C): return 16 else: return 0 def __readReg(self, addr): GPIO.output(self.csnPin, GPIO.LOW) result = self.spi.xfer2([(RF24_R_REGISTER | addr), RF24_NOP]) self.__rf_status = result[0] GPIO.output(self.csnPin, GPIO.HIGH) return result[1] def __readRegMultiLSB(self, addr, buf, length): txbuf = [(RF24_R_REGISTER | addr)] for i in range(length): txbuf.append(RF24_NOP) GPIO.output(self.csnPin, GPIO.LOW) buf = self.spi.xfer2(txbuf) self.__rf_status = buf[0] status = [] for i in range(1, len(buf) + 1): status.append(buf[-i]) status.pop() GPIO.output(self.csnPin, GPIO.HIGH) return status def __writeReg(self, addr, val): GPIO.output(self.csnPin, GPIO.LOW) res = self.spi.xfer2([(RF24_W_REGISTER | addr), val]) GPIO.output(self.csnPin, GPIO.HIGH) def __writeRegMultiLSB(self, addr, buf): txbuf = [(RF24_W_REGISTER | addr)] for i in range(1, len(buf) + 1): txbuf.append(buf[-i]) GPIO.output(self.csnPin, GPIO.LOW) status = self.spi.xfer2(txbuf) GPIO.output(self.csnPin, GPIO.HIGH) def __issueCmd(self, cmd): GPIO.output(self.csnPin, GPIO.LOW) self.spi.writebytes([cmd]) GPIO.output(self.csnPin, GPIO.HIGH) def __readCmdPayload(self, cmd, buf, length, maxlen): GPIO.output(self.csnPin, GPIO.LOW) messg = [] txbuf = [cmd] for i in range(maxlen): txbuf.append(RF24_NOP) buf = self.spi.xfer2( txbuf) # Beyond maxlen bytes, just discard the remaining data. self.__rf_status = buf[0] for i in range(1, length + 1): messg.append(buf[i]) GPIO.output(self.csnPin, GPIO.HIGH) return messg def __issueCmdPayload(self, cmd, buf): payload = [] payload.append(cmd) for i in buf: payload.append(i) GPIO.output(self.csnPin, GPIO.LOW) res = self.spi.xfer2(payload) GPIO.output(self.csnPin, GPIO.HIGH) def __irq_getreason(self): self.__lastirq = self.__readReg(RF24_STATUS) & self.__ENRF24_IRQ_MASK def __irq_derivereason( self ): # Get IRQ status from rf_status w/o querying module over SPI. self.__lastirq = self.__rf_status & self.__ENRF24_IRQ_MASK def __irq_clear(self, irq): self.__writeReg(RF24_STATUS, (irq & self.__ENRF24_IRQ_MASK)) def __isAlive(self): self.spi.writebytes([0x00]) aw = self.__readReg(RF24_SETUP_AW) return ((aw & 0xFC) == 0x00 and (aw & 0x03) != 0x00) def __readTXaddr(self, buf): self.__readRegMultiLSB(RF24_TX_ADDR, buf, self.__rf_addr_width) def __writeRXaddrP0(self, buf): self.__writeRegMultiLSB(RF24_RX_ADDR_P0, buf) def __maintenanceHook( self ): # Handles IRQs and purges RX queue when erroneous contents exist. i = 0 self.__irq_getreason() if (self.__lastirq & self.__ENRF24_IRQ_TXFAILED): self.__lastTXfailed = True self.__issueCmd(RF24_FLUSH_TX) self.__irq_clear(self.__ENRF24_IRQ_TXFAILED) if (self.__lastirq & self.__ENRF24_IRQ_TX): self.__lastTXfailed = False self.__irq_clear(self.__ENRF24_IRQ_TX) if (self.__lastirq & self.__ENRF24_IRQ_RX): if ((not self.__readReg(RF24_FIFO_STATUS)) & RF24_RX_FULL): # Don't feel it's necessary # to be notified of new # incoming packets if the RX # queue is full. self.__irq_clear(self.__ENRF24_IRQ_RX) # Check if RX payload is 0-byte or >32byte (erroneous conditions) # Also check if data was received on pipe#0, which we are ignoring. # The reason for this is pipe#0 is needed for receiving AutoACK acknowledgements, # its address gets reset to the module's default and we do not care about data # coming in to that address... i = self.__readCmdPayload(RF24_R_RX_PL_WID, i, 1, 1)[0] if (i == 0 or i > 32 or ((self.__rf_status & 0x0E) >> 1) == 0): # Zero-width RX payload is an error that happens a lot # with non-AutoAck, and must be cleared with FLUSH_RX. # Erroneous >32byte packets are a similar phenomenon. self.__issueCmd(RF24_FLUSH_RX) self.__irq_clear(self.__ENRF24_IRQ_RX) self.__readpending = 0 else: self.__readpending = 1 # Actual scavenging of RX queues is performed by user-directed use of read(). def __ENRF24_CFGMASK_CRC(self, a): return (a & (RF24_EN_CRC | RF24_CRCO))
class NRF24: MAX_CHANNEL = 127 MAX_PAYLOAD_SIZE = 32 # PA Levels PA_MIN = 0x00 PA_LOW = 0x01 PA_HIGH = 0x02 PA_MAX = 0x03 PA_ERROR = 0x04 # Bit rates BR_1MBPS = 0 BR_2MBPS = 1 BR_250KBPS = 2 # CRC CRC_DISABLED = 0x0 CRC_8 = 0x02 CRC_16 = 0x04 CRC_ENABLED = 0x08 EN_CRC = 0x08 CRCO = 0x04 # Registers CONFIG = 0x00 EN_AA = 0x01 EN_RXADDR = 0x02 SETUP_AW = 0x03 SETUP_RETR = 0x04 RF_CH = 0x05 RF_SETUP = 0x06 STATUS = 0x07 OBSERVE_TX = 0x08 RPD = 0x09 RX_ADDR_P0 = 0x0A RX_ADDR_P1 = 0x0B RX_ADDR_P2 = 0x0C RX_ADDR_P3 = 0x0D RX_ADDR_P4 = 0x0E RX_ADDR_P5 = 0x0F TX_ADDR = 0x10 RX_PW_P0 = 0x11 RX_PW_P1 = 0x12 RX_PW_P2 = 0x13 RX_PW_P3 = 0x14 RX_PW_P4 = 0x15 RX_PW_P5 = 0x16 FIFO_STATUS = 0x17 DYNPD = 0x1C FEATURE = 0x1D # Bit Mnemonics */ MASK_RX_DR = 0x40 MASK_TX_DS = 0x20 MASK_MAX_RT = 0x10 PWR_UP = 0x02 PRIM_RX = 0x01 PLL_LOCK = 0x10 RX_DR = 0x40 TX_DS = 0x20 MAX_RT = 0x10 TX_FULL = 0x01 EN_DPL = 0x04 EN_ACK_PAY = 0x02 EN_DYN_ACK = 0x01 # Shift counts ARD = 4 ARC = 0 PLOS_CNT = 4 ARC_CNT = 0 RX_P_NO = 1 TX_REUSE = 6 FIFO_FULL = 5 TX_EMPTY = 4 RX_FULL = 1 RX_EMPTY = 0 DPL_P5 = 5 DPL_P4 = 4 DPL_P3 = 3 DPL_P2 = 2 DPL_P1 = 1 DPL_P0 = 0 #Masks RX_P_NO_MASK = 0x0E # Instruction Mnemonics R_REGISTER = 0x00 W_REGISTER = 0x20 REGISTER_MASK = 0x1F ACTIVATE = 0x50 R_RX_PL_WID = 0x60 R_RX_PAYLOAD = 0x61 W_TX_PAYLOAD = 0xA0 W_ACK_PAYLOAD = 0xA8 FLUSH_TX = 0xE1 FLUSH_RX = 0xE2 REUSE_TX_PL = 0xE3 NOP = 0xFF # Non-P omissions LNA_HCURR = 0x01 LNA_ON = 1 LNA_OFF = 0 # P model bit Mnemonics RF_DR_LOW = 0x20 RF_DR_HIGH = 0x08 RF_PWR_LOW = 0x02 RF_PWR_HIGH = 0x04 datarate_e_str_P = ["1MBPS", "2MBPS", "250KBPS"] model_e_str_P = ["nRF24L01", "nRF24l01+"] crclength_e_str_P = ["Disabled", "", "8 bits", "", "16 bits"] pa_dbm_e_str_P = ["PA_MIN", "PA_LOW", "PA_HIGH", "PA_MAX"] @staticmethod def print_single_status_line(name, value): print("{0:<16}= {1}".format(name, value)) @staticmethod def _to_8b_list(data): """Convert an arbitray iteratable or single int to a list of ints where each int is smaller than 256.""" if isinstance(data, str): data = [ord(x) for x in data] elif isinstance(data, (int, long)): data = [data] else: data = [int(x) for x in data] #for byte in data: # if byte < 0 or byte > 255: # raise RuntimeError("Value %d is larger than 8 bits" % byte) return data def __init__(self, major=None, minor=None, ce_pin=None, irq_pin=None): self.ce_pin = "P9_15" self.irq_pin = "P9_16" self.channel = 76 self.data_rate = NRF24.BR_1MBPS self.data_rate_bits = 1000 self.p_variant = False # False for RF24L01 and true for RF24L01P self.payload_size = 5 # *< Fixed size of payloads self.ack_payload_available = False # *< Whether there is an ack payload waiting self.dynamic_payloads_enabled = False # *< Whether dynamic payloads are enabled. self.ack_payload_length = 5 # *< Dynamic size of pending ack payload. self.pipe0_reading_address = None # *< Last address set on pipe 0 for reading. self.spidev = None self.last_error = 0 self.crc_length = 0 self.auto_ack = 0x3F self.address_length = 5 # If all parameters are available, lets start the radio! if major is not None and minor is not None and irq_pin is not None: self.begin(major, minor, ce_pin, irq_pin) def begin(self, major, minor, ce_pin, irq_pin): # Initialize SPI bus if ADAFRUID_BBIO_SPI: self.spidev = SPI(major, minor) self.spidev.bpw = 8 try: self.spidev.msh = 10000000 # Maximum supported by NRF24L01+ except IOError: pass # Hardware does not support this speed else: self.spidev = spidev.SpiDev() self.spidev.open(major, minor) self.spidev.bits_per_word = 8 try: self.spidev.max_speed_hz = 10000000 # Maximum supported by NRF24L01+ except IOError: pass # Hardware does not support this speed self.spidev.cshigh = False self.spidev.mode = 0 self.spidev.loop = False self.spidev.lsbfirst = False self.spidev.threewire = False self.ce_pin = ce_pin self.irq_pin = irq_pin if self.ce_pin is not None: GPIO.setup(self.ce_pin, GPIO.OUT) GPIO.setup(self.irq_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) time.sleep(5 / 1000000.0) # Reset radio configuration self.reset() # Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier # WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet # sizes must never be used. See documentation for a more complete explanation. self.setRetries(int('0101', 2), 15) # Restore our default PA level self.setPALevel(NRF24.PA_MAX) # Determine if this is a p or non-p RF24 module and then # reset our data rate back to default value. This works # because a non-P variant won't allow the data rate to # be set to 250Kbps. if self.setDataRate(NRF24.BR_250KBPS): self.p_variant = True # Then set the data rate to the slowest (and most reliable) speed supported by all # hardware. self.setDataRate(NRF24.BR_1MBPS) # Initialize CRC and request 2-byte (16bit) CRC self.setCRCLength(NRF24.CRC_16) # Disable dynamic payloads, to match dynamic_payloads_enabled setting self.write_register(NRF24.DYNPD, 0) # Reset current status # Notice reset and flush is the last thing we do self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) # Set up default configuration. Callers can always change it later. # This channel should be universally safe and not bleed over into adjacent # spectrum. self.setChannel(self.channel) self.setRetries(15, 15) # Flush buffers self.flush_rx() self.flush_tx() self.clear_irq_flags() def end(self): if self.spidev: self.spidev.close() self.spidev = None def startListening(self): self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP | NRF24.PRIM_RX) self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) self.flush_tx() self.flush_rx() self.clear_irq_flags() # Restore the pipe0 address, if exists if self.pipe0_reading_address: self.write_register(self.RX_ADDR_P0, self.pipe0_reading_address) # Go! self.ce(1) def ce(self, level, pulse=0): # CE Pin is optional if self.ce_pin is not None: GPIO.output(self.ce_pin, level) if pulse > 0: time.sleep(pulse) GPIO.output(self.ce_pin, 1 - level) def irqWait(self, timeout=30000): # TODO: A race condition may occur here. => wait for level? if GPIO.input(self.irq_pin) == 0: # Pin is already down. Packet is waiting? return True try: return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING, timeout) == 1 except TypeError: # Timeout parameter not supported return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING) == 1 except AttributeError: raise RuntimeError("GPIO lib does not support wait_for_edge()") def read_register(self, reg, length=1): buf = [NRF24.R_REGISTER | (NRF24.REGISTER_MASK & reg)] buf += [NRF24.NOP] * max(1, length) resp = self.spidev.xfer2(buf) if length == 1: return resp[1] return resp[1:] def write_register(self, reg, value): """ Write register value """ buf = [NRF24.W_REGISTER | (NRF24.REGISTER_MASK & reg)] buf += self._to_8b_list(value) self.spidev.xfer2(buf) def write_payload(self, buf): """ Writes data to the payload register, automatically padding it to match the required length. Returns the number of bytes actually written. """ buf = self._to_8b_list(buf) if self.dynamic_payloads_enabled: if len(buf) > self.MAX_PAYLOAD_SIZE: raise RuntimeError("Dynamic payload is larger than the " + "maximum size.") blank_len = 0 else: if len(buf) > self.payload_size: raise RuntimeError("Payload is larger than the fixed payload" + "size (%d vs. %d bytes)" % (len(buf), self.payload_size)) blank_len = self.payload_size - len(buf) txbuffer = [NRF24.W_TX_PAYLOAD] + buf + ([0x00] * blank_len) self.spidev.xfer2(txbuffer) return len(txbuffer) - 1 def read_payload(self, buf, buf_len=-1): """ Reads data from the payload register and sets the DR bit of the STATUS register. """ if buf_len < 0: buf_len = self.payload_size if not self.dynamic_payloads_enabled: data_len = min(self.payload_size, buf_len) blank_len = self.payload_size - data_len else: data_len = self.getDynamicPayloadSize() blank_len = 0 txbuffer = [NRF24.R_RX_PAYLOAD] + [NRF24.NOP] * (blank_len + data_len + 1) payload = self.spidev.xfer2(txbuffer) del buf[:] buf += payload[1:data_len + 1] self.write_register(NRF24.STATUS, NRF24.RX_DR) return data_len def flush_rx(self): return self.spidev.xfer2([NRF24.FLUSH_RX])[0] def flush_tx(self): return self.spidev.xfer2([NRF24.FLUSH_TX])[0] def get_status(self): return self.spidev.xfer2([NRF24.NOP])[0] def 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()
from Adafruit_BBIO.SPI import SPI spi = SPI(0,0) spi.open(0,0) #spi.msh = 100000 spi.bpw = 8 #spi.mode = b00 try: #while True: # set CS bit high, choose first channel to read from #channel = 0; #adc = spi.xfer([1,8,0]) #data = ((adc[1]&3) << 8) + adc[2] channelSelect = 0xC0 channelSelect |= 0x18 channelSelect <<= 3 fsr = spi.xfer2([channelSelect, 0x00, 0x00]) #result = spi.readbytes(2) #result2 = spi.readbytes(1) resultFinal = 0x0000 resultFinal = 0x0300 & (resultFinal | (fsr[1] << 8 )) resultFinal |= ( ( 0x00FF & fsr[2]) ) #print (8 + channel ) << 4 #print resultFinal ################################### #################################### resultFinal = 1 #temp
class LED_LPD8806(object): # Constructor def __init__(self): self.spi = SPI( 0, 0 ) #/dev/spidev1.0 (be sure to run Python with su if 'no permission' self.spi.msh = 1000000 #SPI clock set to 1MHz (slowed from 10MHz for better stability across setups) self.spi.bpw = 8 # bits per word self.spi.threewire = False # not half-duplex self.spi.lsbfirst = False # we want MSB first self.spi.mode = 0 # options are modes 0 through 3 self.spi.cshigh = False # we want chip select to be active low self.spi.open(0, 0) # make it so time.sleep(0.05) def setup(self, led_pixels, debug=False): if (debug): print "Initializing LED strip" global pixels pixels = [[0x80 for x in range(3)] for y in range(led_pixels)] for i in range(led_pixels): pixels[i] = [0x00, 0x00, 0x00] # Define LED functions: # -------------------- # Update pixel display with a given delay time between pixel updates: def writestrip(self, delay): if (delay < 0): delay = 0 for i in range(len(pixels)): self.spi.writebytes([0x00, 0x00, 0x00]) #prepare write for i in range(len(pixels)): self.spi.writebytes(pixels[i]) #write colors to pixels time.sleep(delay) # Turn off all LEDs: def clearstrip(self): global pixels for i in range(len(pixels)): self.spi.writebytes([0x00, 0x00, 0x00]) #prepare write for i in range(len(pixels)): pixels[i] = [0x80, 0x80, 0x80] self.writestrip(0) # Set an individual pixel to a specific color (to display later): def setpixelcolor(self, n, g, r, b): global pixels if (n >= len(pixels)): return if (n < 0): return if (g > 0xFF): g = 0xFF if (g < 0x80): g = 0x80 if (r > 0xFF): r = 0xFF if (r < 0x80): r = 0x80 if (b > 0xFF): b = 0xFF if (b < 0x80): b = 0x80 pixels[n] = [g, r, b] # Update display with warmer colors (more red light) by a specified amount with a delay between pixels def warmstrip(self, warmth, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if ((pixels[n][1] + warmth) < 0x80): pixels[n][1] = 0x80 elif ((pixels[n][2] + warmth) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1] + warmth self.writestrip(delay) # Update display with cooler colors (more blue) by a specified amount with a delay between each pixel def coolstrip(self, coolfactor, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if ((pixels[n][2] + coolfactor) < 0x80): pixels[n][2] = 0x80 elif ((pixels[n][2] + coolfactor) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2] + coolfactor self.writestrip(delay) # Update display with greener colors by a specified amount with a set delay between each pixel def greenstrip(self, lushness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if ((pixels[n][0] + lushness) < 0x80): pixels[n][0] = 0x80 else: pixels[n][0] = pixels[n][0] + lushness self.writestrip(delay) # Update display with brighter (whiter) light by specified amount with a set delay between pixel updates def brightenstrip(self, brightness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if ((pixels[n][0] + brightness) < 0x80): pixels[n][0] = 0x80 elif ((pixels[n][0] + brightness) > 0xFF): pixels[n][0] = 0xFF else: pixels[n][0] = pixels[n][0] + brightness if ((pixels[n][1] + brightness) < 0x80): pixels[n][1] = 0x80 elif ((pixels[n][1] + brightness) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1] + brightness if ((pixels[n][2] + brightness) < 0x80): pixels[n][2] = 0x80 elif ((pixels[n][2] + brightness) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2] + brightness self.writestrip(delay) # Darken display (less light) by specified amount with a set delay between pixel updates def dimstrip(self, dimness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if ((pixels[n][0] - dimness) < 0x80): pixels[n][0] = 0x80 elif ((pixels[n][0] - dimness) > 0xFF): pixels[n][0] = 0xFF else: pixels[n][0] = pixels[n][0] - dimness if ((pixels[n][1] - dimness) < 0x80): pixels[n][1] = 0x80 elif ((pixels[n][1] - dimness) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1] - dimness if ((pixels[n][2] - dimness) < 0x80): pixels[n][2] = 0x80 elif ((pixels[n][2] - dimness) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2] - dimness self.writestrip(delay)
class LED_LPD8806(object): # Constructor def __init__(self): self.spi = SPI(0,0) #/dev/spidev1.0 (be sure to run Python with su if 'no permission' self.spi.msh=1000000 #SPI clock set to 1MHz (slowed from 10MHz for better stability across setups) self.spi.bpw = 8 # bits per word self.spi.threewire = False # not half-duplex self.spi.lsbfirst = False # we want MSB first self.spi.mode = 0 # options are modes 0 through 3 self.spi.cshigh = False # we want chip select to be active low self.spi.open(0,0) # make it so time.sleep(0.05) def setup(self, led_pixels, debug=False): if (debug): print "Initializing LED strip" global pixels pixels = [[0x80 for x in range(3)] for y in range(led_pixels)] for i in range(led_pixels): pixels[i]=[0x00, 0x00, 0x00] # Define LED functions: # -------------------- # Update pixel display with a given delay time between pixel updates: def writestrip(self, delay): if (delay < 0): delay = 0 for i in range(len(pixels)): self.spi.writebytes([0x00, 0x00, 0x00]) #prepare write for i in range(len(pixels)): self.spi.writebytes(pixels[i]) #write colors to pixels time.sleep(delay) # Turn off all LEDs: def clearstrip(self): global pixels for i in range(len(pixels)): self.spi.writebytes([0x00, 0x00, 0x00]) #prepare write for i in range(len(pixels)): pixels[i] = [0x80, 0x80, 0x80] self.writestrip(0) # Set an individual pixel to a specific color (to display later): def setpixelcolor(self, n, g, r, b): global pixels if (n >= len(pixels)): return if (n < 0): return if (g > 0xFF): g = 0xFF if (g < 0x80): g = 0x80 if (r > 0xFF): r = 0xFF if (r < 0x80): r = 0x80 if (b > 0xFF): b = 0xFF if (b < 0x80): b = 0x80 pixels[n] = [g, r, b] # Update display with warmer colors (more red light) by a specified amount with a delay between pixels def warmstrip(self, warmth, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][1] + warmth) < 0x80): pixels[n][1] = 0x80 elif((pixels[n][2] + warmth) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1]+warmth self.writestrip(delay) # Update display with cooler colors (more blue) by a specified amount with a delay between each pixel def coolstrip(self, coolfactor, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][2] + coolfactor) < 0x80): pixels[n][2] = 0x80 elif((pixels[n][2] + coolfactor) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2]+coolfactor self.writestrip(delay) # Update display with greener colors by a specified amount with a set delay between each pixel def greenstrip(self, lushness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][0] + lushness) < 0x80): pixels[n][0] = 0x80 else: pixels[n][0] = pixels[n][0]+lushness self.writestrip(delay) # Update display with brighter (whiter) light by specified amount with a set delay between pixel updates def brightenstrip(self, brightness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][0] + brightness) < 0x80): pixels[n][0] = 0x80 elif((pixels[n][0] + brightness) > 0xFF): pixels[n][0] = 0xFF else: pixels[n][0] = pixels[n][0]+brightness if((pixels[n][1] + brightness) < 0x80): pixels[n][1] = 0x80 elif((pixels[n][1] + brightness) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1]+brightness if((pixels[n][2] + brightness) < 0x80): pixels[n][2] = 0x80 elif((pixels[n][2] + brightness) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2]+brightness self.writestrip(delay) # Darken display (less light) by specified amount with a set delay between pixel updates def dimstrip(self, dimness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][0] - dimness) < 0x80): pixels[n][0] = 0x80 elif((pixels[n][0] - dimness) > 0xFF): pixels[n][0] = 0xFF else: pixels[n][0] = pixels[n][0]-dimness if((pixels[n][1] - dimness) < 0x80): pixels[n][1] = 0x80 elif((pixels[n][1] - dimness) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1]-dimness if((pixels[n][2] - dimness) < 0x80): pixels[n][2] = 0x80 elif((pixels[n][2] - dimness) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2]-dimness self.writestrip(delay)
from Adafruit_BBIO.SPI import SPI spi = SPI(1,0) spi.mode=2 spi.msh=200000 spi.open(1,0) print spi.readbytes(4) #print spi.xfer2([32, 11, 110, 22, 220]) spi.close()