Exemple #1
0
    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)
Exemple #2
0
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()
Exemple #3
0
class NRF24:
    MAX_CHANNEL = 127
    MAX_PAYLOAD_SIZE = 32

    # PA Levels
    PA_MIN = 0
    PA_LOW = 1
    PA_HIGH = 2
    PA_MAX = 3
    PA_ERROR = 4

    # Bit rates
    BR_1MBPS = 0
    BR_2MBPS = 1
    BR_250KBPS = 2

    # CRC
    CRC_DISABLED = 0
    CRC_8 = 1
    CRC_16 = 2
    CRC_ENABLED = 3

    # Registers
    CONFIG = 0x00
    EN_AA = 0x01
    EN_RXADDR = 0x02
    SETUP_AW = 0x03
    SETUP_RETR = 0x04
    RF_CH = 0x05
    RF_SETUP = 0x06
    STATUS = 0x07
    OBSERVE_TX = 0x08
    CD = 0x09
    RX_ADDR_P0 = 0x0A
    RX_ADDR_P1 = 0x0B
    RX_ADDR_P2 = 0x0C
    RX_ADDR_P3 = 0x0D
    RX_ADDR_P4 = 0x0E
    RX_ADDR_P5 = 0x0F
    TX_ADDR = 0x10
    RX_PW_P0 = 0x11
    RX_PW_P1 = 0x12
    RX_PW_P2 = 0x13
    RX_PW_P3 = 0x14
    RX_PW_P4 = 0x15
    RX_PW_P5 = 0x16
    FIFO_STATUS = 0x17
    DYNPD = 0x1C
    FEATURE = 0x1D

    # Bit Mnemonics */
    MASK_RX_DR = 6
    MASK_TX_DS = 5
    MASK_MAX_RT = 4
    EN_CRC = 3
    CRCO = 2
    PWR_UP = 1
    PRIM_RX = 0
    ENAA_P5 = 5
    ENAA_P4 = 4
    ENAA_P3 = 3
    ENAA_P2 = 2
    ENAA_P1 = 1
    ENAA_P0 = 0
    ERX_P5 = 5
    ERX_P4 = 4
    ERX_P3 = 3
    ERX_P2 = 2
    ERX_P1 = 1
    ERX_P0 = 0
    AW = 0
    ARD = 4
    ARC = 0
    PLL_LOCK = 4
    RF_DR = 3
    RF_PWR = 6
    RX_DR = 6
    TX_DS = 5
    MAX_RT = 4
    RX_P_NO = 1
    TX_FULL = 0
    PLOS_CNT = 4
    ARC_CNT = 0
    TX_REUSE = 6
    FIFO_FULL = 5
    TX_EMPTY = 4
    RX_FULL = 1
    RX_EMPTY = 0
    DPL_P5 = 5
    DPL_P4 = 4
    DPL_P3 = 3
    DPL_P2 = 2
    DPL_P1 = 1
    DPL_P0 = 0
    EN_DPL = 2
    EN_ACK_PAY = 1
    EN_DYN_ACK = 0

    # Instruction Mnemonics
    R_REGISTER = 0x00
    W_REGISTER = 0x20
    REGISTER_MASK = 0x1F
    ACTIVATE = 0x50
    R_RX_PL_WID = 0x60
    R_RX_PAYLOAD = 0x61
    W_TX_PAYLOAD = 0xA0
    W_ACK_PAYLOAD = 0xA8
    FLUSH_TX = 0xE1
    FLUSH_RX = 0xE2
    REUSE_TX_PL = 0xE3
    NOP = 0xFF

    # Non-P omissions
    LNA_HCURR = 0x00

    # P model memory Map
    RPD = 0x09

    # P model bit Mnemonics
    RF_DR_LOW = 5
    RF_DR_HIGH = 3
    RF_PWR_LOW = 1
    RF_PWR_HIGH = 2

    # Signal Mnemonics
    LOW = 0
    HIGH = 1

    datarate_e_str_P = ["1MBPS", "2MBPS", "250KBPS"]
    model_e_str_P = ["nRF24L01", "nRF24l01+"]
    crclength_e_str_P = ["Disabled", "8 bits", "16 bits"]
    pa_dbm_e_str_P = ["PA_MIN", "PA_LOW", "PA_MED", "PA_HIGH"]
    child_pipe = [
        RX_ADDR_P0, RX_ADDR_P1, RX_ADDR_P2, RX_ADDR_P3, RX_ADDR_P4, RX_ADDR_P5
    ]

    child_payload_size = [
        RX_PW_P0, RX_PW_P1, RX_PW_P2, RX_PW_P3, RX_PW_P4, RX_PW_P5
    ]
    child_pipe_enable = [ERX_P0, ERX_P1, ERX_P2, ERX_P3, ERX_P4, ERX_P5]

    def __init__(self):
        self.ce_pin = "P9_15"
        self.irq_pin = "P9_16"
        self.channel = 76
        self.data_rate = NRF24.BR_1MBPS
        self.wide_band = False  # 2Mbs data rate in use?
        self.p_variant = False  # False for RF24L01 and true for RF24L01P
        self.payload_size = 5  #*< Fixed size of payloads
        self.ack_payload_available = False  #*< Whether there is an ack payload waiting
        self.dynamic_payloads_enabled = False  #*< Whether dynamic payloads are enabled.
        self.ack_payload_length = 5  #*< Dynamic size of pending ack payload.
        self.pipe0_reading_address = None  #*< Last address set on pipe 0 for reading.
        self.spidev = None

    def ce(self, level):
        if level == NRF24.HIGH:
            GPIO.output(self.ce_pin, GPIO.HIGH)
        else:
            GPIO.output(self.ce_pin, GPIO.LOW)
        return

    def irqWait(self, timeout=30000):
        # CHANGE: detect module name because wait_for_edge is not available in
        # other libraries
        if GPIO.__name__ != "Adafruit_BBIO.GPIO":
            return False

        # TODO: A race condition may occur here.
        if GPIO.input(
                self.irq_pin) == 0:  # Pin is already down. Packet is waiting?
            return True

        return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING, timeout) == 1

    def read_register(self, reg, blen=1):
        buf = [NRF24.R_REGISTER | (NRF24.REGISTER_MASK & reg)]
        for col in range(blen):
            buf.append(NRF24.NOP)

        resp = self.spidev.xfer2(buf)
        if blen == 1:
            return resp[1]

        return resp[1:blen + 1]

    def write_register(self, reg, value, length=-1):
        buf = [NRF24.W_REGISTER | (NRF24.REGISTER_MASK & reg)]
        if isinstance(value, (int, long)):
            if length < 0:
                length = 1

            length = min(4, length)
            for i in range(length):
                buf.insert(1, int(value & 0xff))
                value >>= 8

        elif isinstance(value, list):
            if length < 0:
                length = len(value)

            for i in range(min(len(value), length)):
                buf.append(int(value[len(value) - i - 1] & 0xff))
        else:
            raise Exception("Value must be int or list")

        return self.spidev.xfer2(buf)[0]

    def write_payload(self, buf):
        data_len = min(self.payload_size, len(buf))
        blank_len = 0
        if not self.dynamic_payloads_enabled:
            blank_len = self.payload_size - data_len

        txbuffer = [NRF24.W_TX_PAYLOAD]
        for n in buf:
            t = type(n)
            if t is str:
                txbuffer.append(ord(n))
            elif t is int:
                txbuffer.append(n)
            else:
                raise Exception("Only ints and chars are supported: Found " +
                                str(t))

        if blank_len != 0:
            blank = [0x00 for i in range(blank_len)]
            txbuffer.extend(blank)

        return self.spidev.xfer2(txbuffer)

    def read_payload(self, buf, buf_len=-1):
        if buf_len < 0:
            buf_len = self.payload_size
        data_len = min(self.payload_size, buf_len)
        blank_len = 0
        if not self.dynamic_payloads_enabled:
            blank_len = self.payload_size - data_len

        txbuffer = [NRF24.NOP for i in range(0, blank_len + data_len + 1)]
        txbuffer[0] = NRF24.R_RX_PAYLOAD

        payload = self.spidev.xfer2(txbuffer)
        del buf[:]
        buf.extend(payload[1:data_len + 1])
        return data_len

    def flush_rx(self):
        return self.spidev.xfer2([NRF24.FLUSH_RX])[0]

    def flush_tx(self):
        return self.spidev.xfer2([NRF24.FLUSH_TX])[0]

    def get_status(self):
        return self.spidev.xfer2([NRF24.NOP])[0]

    def print_status(self, status):
        status_str = "STATUS\t = 0x{0:02x} RX_DR={1:x} TX_DS={2:x} MAX_RT={3:x} RX_P_NO={4:x} TX_FULL={5:x}".format(
            status, 1 if status & _BV(NRF24.RX_DR) else 0,
            1 if status & _BV(NRF24.TX_DS) else 0,
            1 if status & _BV(NRF24.MAX_RT) else 0,
            ((status >> NRF24.RX_P_NO) & int("111", 2)),
            1 if status & _BV(NRF24.TX_FULL) else 0)

        print status_str

    def print_observe_tx(self, value):
        tx_str = "OBSERVE_TX=0x{0:02x}: POLS_CNT={2:x} ARC_CNT={2:x}\r\n".format(
            value, (value >> NRF24.PLOS_CNT) & int("1111", 2),
            (value >> NRF24.ARC_CNT) & int("1111", 2))
        print tx_str

    def print_byte_register(self, name, reg, qty=1):
        extra_tab = '\t' if len(name) < 8 else 0
        print "%s\t%c =" % (name, extra_tab),
        while qty > 0:
            print "0x%02x" % (self.read_register(reg)),
            qty -= 1
            reg += 1

        print ""

    def print_address_register(self, name, reg, qty=1):
        extra_tab = '\t' if len(name) < 8 else 0
        print "%s\t%c =" % (name, extra_tab),

        while qty > 0:
            qty -= 1
            buf = reversed(self.read_register(reg, 5))
            reg += 1
            sys.stdout.write(" 0x"),
            for i in buf:
                sys.stdout.write("%02x" % i)

        print ""

    def setChannel(self, channel):
        self.channel = min(max(0, channel), NRF24.MAX_CHANNEL)
        self.write_register(NRF24.RF_CH, self.channel)

    def getChannel(self):
        return self.read_register(NRF24.RF_CH)

    def setPayloadSize(self, size):
        self.payload_size = min(max(size, 1), NRF24.MAX_PAYLOAD_SIZE)

    def getPayloadSize(self):
        return self.payload_size

    def printDetails(self):
        self.print_status(self.get_status())
        self.print_address_register("RX_ADDR_P0-1", NRF24.RX_ADDR_P0, 2)
        self.print_byte_register("RX_ADDR_P2-5", NRF24.RX_ADDR_P2, 4)
        self.print_address_register("TX_ADDR", NRF24.TX_ADDR)

        self.print_byte_register("RX_PW_P0-6", NRF24.RX_PW_P0, 6)
        self.print_byte_register("EN_AA", NRF24.EN_AA)
        self.print_byte_register("EN_RXADDR", NRF24.EN_RXADDR)
        self.print_byte_register("RF_CH", NRF24.RF_CH)
        self.print_byte_register("RF_SETUP", NRF24.RF_SETUP)
        self.print_byte_register("CONFIG", NRF24.CONFIG)
        self.print_byte_register("DYNPD/FEATURE", NRF24.DYNPD, 2)

        #
        print "Data Rate\t = %s" % NRF24.datarate_e_str_P[self.getDataRate()]
        print "Model\t\t = %s" % NRF24.model_e_str_P[self.isPVariant()]
        print "CRC Length\t = %s" % NRF24.crclength_e_str_P[
            self.getCRCLength()]
        print "PA Power\t = %s" % NRF24.pa_dbm_e_str_P[self.getPALevel()]

    def begin(self, major, minor, ce_pin, irq_pin):
        # Initialize SPI bus
        self.spidev = SPI(major, minor)
        self.ce_pin = ce_pin
        self.irq_pin = irq_pin

        GPIO.setup(self.ce_pin, GPIO.OUT)
        GPIO.setup(self.irq_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

        time.sleep(5 / 1000000.0)

        # Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier
        # WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet
        # sizes must never be used. See documentation for a more complete explanation.
        self.write_register(NRF24.SETUP_RETR, (int('0100', 2) << NRF24.ARD) |
                            (int('1111', 2) << NRF24.ARC))

        # Restore our default PA level
        self.setPALevel(NRF24.PA_MAX)

        # Determine if this is a p or non-p RF24 module and then
        # reset our data rate back to default value. This works
        # because a non-P variant won't allow the data rate to
        # be set to 250Kbps.
        if self.setDataRate(NRF24.BR_250KBPS):
            self.p_variant = True

        # Then set the data rate to the slowest (and most reliable) speed supported by all
        # hardware.
        self.setDataRate(NRF24.BR_1MBPS)

        # Initialize CRC and request 2-byte (16bit) CRC
        self.setCRCLength(NRF24.CRC_16)

        # Disable dynamic payloads, to match dynamic_payloads_enabled setting
        self.write_register(NRF24.DYNPD, 0)

        # Reset current status
        # Notice reset and flush is the last thing we do
        self.write_register(
            NRF24.STATUS,
            _BV(NRF24.RX_DR) | _BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT))

        # Set up default configuration.  Callers can always change it later.
        # This channel should be universally safe and not bleed over into adjacent
        # spectrum.
        self.setChannel(self.channel)

        # Flush buffers
        self.flush_rx()
        self.flush_tx()

    def end(self):
        if self.spidev:
            self.spidev.close()
            self.spidev = None

    def startListening(self):
        self.write_register(
            NRF24.CONFIG,
            self.read_register(NRF24.CONFIG) | _BV(NRF24.PWR_UP)
            | _BV(NRF24.PRIM_RX))
        self.write_register(
            NRF24.STATUS,
            _BV(NRF24.RX_DR) | _BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT))

        # Restore the pipe0 address, if exists
        if self.pipe0_reading_address:
            self.write_register(self.RX_ADDR_P0, self.pipe0_reading_address, 5)

        # Go!
        self.ce(NRF24.HIGH)

        # wait for the radio to come up (130us actually only needed)
        time.sleep(130 / 1000000.0)

    def stopListening(self):
        self.ce(NRF24.LOW)
        self.flush_tx()
        self.flush_rx()

    def powerDown(self):
        self.write_register(
            NRF24.CONFIG,
            self.read_register(NRF24.CONFIG) & ~_BV(NRF24.PWR_UP))

    def powerUp(self):
        self.write_register(
            NRF24.CONFIG,
            self.read_register(NRF24.CONFIG) | _BV(NRF24.PWR_UP))
        time.sleep(150 / 1000000.0)

    def write(self, buf):
        # Begin the write
        self.startWrite(buf)

        timeout = self.getMaxTimeout()  #s to wait for timeout
        sent_at = time.time()

        while True:
            #status = self.read_register(NRF24.OBSERVE_TX, 1)
            status = self.get_status()
            if (status & (_BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT))) or (
                    time.time() - sent_at > timeout):
                break
            time.sleep(10 / 1000000.0)

        what = self.whatHappened()

        result = what['tx_ok']

        # Handle the ack packet
        if what['rx_ready']:
            self.ack_payload_length = self.getDynamicPayloadSize()

        return result

    def startWrite(self, buf):
        # Transmitter power-up
        self.write_register(
            NRF24.CONFIG,
            (self.read_register(NRF24.CONFIG) | _BV(NRF24.PWR_UP))
            & ~_BV(NRF24.PRIM_RX))

        # Send the payload
        self.write_payload(buf)

        # Allons!
        self.ce(NRF24.HIGH)
        time.sleep(10 / 1000000.0)
        self.ce(NRF24.LOW)

    def getDynamicPayloadSize(self):
        return self.spidev.xfer2([NRF24.R_RX_PL_WID, NRF24.NOP])[1]

    def available(self, pipe_num=None, irq_wait=False, irq_timeout=30000):
        if not pipe_num:
            pipe_num = []

        status = self.get_status()
        result = False

        # Sometimes the radio specifies that there is data in one pipe but
        # doesn't set the RX flag...
        if status & _BV(NRF24.RX_DR) or (status & 0b00001110 != 0b00001110):
            result = True
        else:
            if irq_wait:  # Will use IRQ wait
                if self.irqWait(irq_timeout):  # Do we have a packet?
                    status = self.get_status()  # Seems like we do!
                    if status & _BV(NRF24.RX_DR) or (status & 0b00001110 !=
                                                     0b00001110):
                        result = True

        if result:
            # If the caller wants the pipe number, include that
            if len(pipe_num) >= 1:
                pipe_num[0] = (status >> NRF24.RX_P_NO) & 0b00000111

                # Clear the status bit

                # ??? Should this REALLY be cleared now?  Or wait until we
                # actually READ the payload?
        self.write_register(NRF24.STATUS, _BV(NRF24.RX_DR))

        # Handle ack payload receipt
        if status & _BV(NRF24.TX_DS):
            self.write_register(NRF24.STATUS, _BV(NRF24.TX_DS))

        return result

    def read(self, buf, buf_len=-1):
        # Fetch the payload
        self.read_payload(buf, buf_len)

        # was this the last of the data available?
        return self.read_register(NRF24.FIFO_STATUS) & _BV(NRF24.RX_EMPTY)

    def whatHappened(self):
        # Read the status & reset the status in one easy call
        # Or is that such a good idea?
        status = self.write_register(
            NRF24.STATUS,
            _BV(NRF24.RX_DR) | _BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT))

        # Report to the user what happened
        tx_ok = status & _BV(NRF24.TX_DS)
        tx_fail = status & _BV(NRF24.MAX_RT)
        rx_ready = status & _BV(NRF24.RX_DR)
        return {'tx_ok': tx_ok, "tx_fail": tx_fail, "rx_ready": rx_ready}

    def openWritingPipe(self, value):
        # Note that the NRF24L01(+)
        # expects it LSB first.

        self.write_register(NRF24.RX_ADDR_P0, value, 5)
        self.write_register(NRF24.TX_ADDR, value, 5)

        max_payload_size = 32
        self.write_register(NRF24.RX_PW_P0,
                            min(self.payload_size, max_payload_size))

    def openReadingPipe(self, child, address):
        # If this is pipe 0, cache the address.  This is needed because
        # openWritingPipe() will overwrite the pipe 0 address, so
        # startListening() will have to restore it.
        if child == 0:
            self.pipe0_reading_address = address

        if child <= 6:
            # For pipes 2-5, only write the LSB
            if child < 2:
                self.write_register(NRF24.child_pipe[child], address, 5)
            else:
                self.write_register(NRF24.child_pipe[child], address, 1)

            self.write_register(NRF24.child_payload_size[child],
                                self.payload_size)

            # Note it would be more efficient to set all of the bits for all open
            # pipes at once.  However, I thought it would make the calling code
            # more simple to do it this way.
            self.write_register(
                NRF24.EN_RXADDR,
                self.read_register(NRF24.EN_RXADDR)
                | _BV(NRF24.child_pipe_enable[child]))

    def closeReadingPipe(self, pipe):
        self.write_register(
            NRF24.EN_RXADDR,
            self.read_register(EN_RXADDR)
            & ~_BV(NRF24.child_pipe_enable[pipe]))

    def toggle_features(self):
        buf = [NRF24.ACTIVATE, 0x73]
        self.spidev.xfer2(buf)

    def enableDynamicPayloads(self):
        # Enable dynamic payload throughout the system
        self.write_register(
            NRF24.FEATURE,
            self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_DPL))

        # If it didn't work, the features are not enabled
        if not self.read_register(NRF24.FEATURE):
            # So enable them and try again
            self.toggle_features()
            self.write_register(
                NRF24.FEATURE,
                self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_DPL))

        # Enable dynamic payload on all pipes

        # Not sure the use case of only having dynamic payload on certain
        # pipes, so the library does not support it.
        self.write_register(
            NRF24.DYNPD,
            self.read_register(NRF24.DYNPD) | _BV(NRF24.DPL_P5)
            | _BV(NRF24.DPL_P4) | _BV(NRF24.DPL_P3) | _BV(NRF24.DPL_P2)
            | _BV(NRF24.DPL_P1) | _BV(NRF24.DPL_P0))

        self.dynamic_payloads_enabled = True

    def enableAckPayload(self):
        # enable ack payload and dynamic payload features
        self.write_register(
            NRF24.FEATURE,
            self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_ACK_PAY)
            | _BV(NRF24.EN_DPL))

        # If it didn't work, the features are not enabled
        if not self.read_register(NRF24.FEATURE):
            # So enable them and try again
            self.toggle_features()
            self.write_register(
                NRF24.FEATURE,
                self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_ACK_PAY)
                | _BV(NRF24.EN_DPL))

        # Enable dynamic payload on pipes 0 & 1
        self.write_register(
            NRF24.DYNPD,
            self.read_register(NRF24.DYNPD) | _BV(NRF24.DPL_P1)
            | _BV(NRF24.DPL_P0))

    def writeAckPayload(self, pipe, buf, buf_len):
        txbuffer = [NRF24.W_ACK_PAYLOAD | (pipe & 0x7)]

        max_payload_size = 32
        data_len = min(buf_len, max_payload_size)
        txbuffer.extend(buf[0:data_len])

        self.spidev.xfer2(txbuffer)

    def isAckPayloadAvailable(self):
        result = self.ack_payload_available
        self.ack_payload_available = False
        return result

    def isPVariant(self):
        return self.p_variant

    def setAutoAck(self, enable):
        if enable:
            self.write_register(NRF24.EN_AA, int('111111', 2))
        else:
            self.write_register(NRF24.EN_AA, 0)

    def setAutoAckPipe(self, pipe, enable):
        if pipe <= 6:
            en_aa = self.read_register(NRF24.EN_AA)
            if enable:
                en_aa |= _BV(pipe)
            else:
                en_aa &= ~_BV(pipe)

            self.write_register(NRF24.EN_AA, en_aa)

    def testCarrier(self):
        return self.read_register(NRF24.CD) & 1

    def testRPD(self):
        return self.read_register(NRF24.RPD) & 1

    def setPALevel(self, level):
        setup = self.read_register(NRF24.RF_SETUP)
        setup &= ~(_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH))
        # switch uses RAM (evil!)
        if level == NRF24.PA_MAX:
            setup |= (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH))
        elif level == NRF24.PA_HIGH:
            setup |= _BV(NRF24.RF_PWR_HIGH)
        elif level == NRF24.PA_LOW:
            setup |= _BV(NRF24.RF_PWR_LOW)
        elif level == NRF24.PA_MIN:
            nop = 0
        elif level == NRF24.PA_ERROR:
            # On error, go to maximum PA
            setup |= (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH))

        self.write_register(NRF24.RF_SETUP, setup)

    def getPALevel(self):
        power = self.read_register(
            NRF24.RF_SETUP) & (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH))

        if power == (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH)):
            return NRF24.PA_MAX
        elif power == _BV(NRF24.RF_PWR_HIGH):
            return NRF24.PA_HIGH
        elif power == _BV(NRF24.RF_PWR_LOW):
            return NRF24.PA_LOW
        else:
            return NRF24.PA_MIN

    def setDataRate(self, speed):
        result = False
        setup = self.read_register(NRF24.RF_SETUP)

        # HIGH and LOW '00' is 1Mbs - our default
        self.wide_band = False
        setup &= ~(_BV(NRF24.RF_DR_LOW) | _BV(NRF24.RF_DR_HIGH))

        if speed == NRF24.BR_250KBPS:
            # Must set the RF_DR_LOW to 1 RF_DR_HIGH (used to be RF_DR) is already 0
            # Making it '10'.
            self.wide_band = False
            setup |= _BV(NRF24.RF_DR_LOW)
        else:
            # Set 2Mbs, RF_DR (RF_DR_HIGH) is set 1
            # Making it '01'
            if speed == NRF24.BR_2MBPS:
                self.wide_band = True
                setup |= _BV(NRF24.RF_DR_HIGH)
            else:
                # 1Mbs
                self.wide_band = False

        self.write_register(NRF24.RF_SETUP, setup)

        # Verify our result
        if self.read_register(NRF24.RF_SETUP) == setup:
            result = True
        else:
            self.wide_band = False
        return result

    def getDataRate(self):
        dr = self.read_register(
            NRF24.RF_SETUP) & (_BV(NRF24.RF_DR_LOW) | _BV(NRF24.RF_DR_HIGH))
        # Order matters in our case below
        if dr == _BV(NRF24.RF_DR_LOW):
            # '10' = 250KBPS
            return NRF24.BR_250KBPS
        elif dr == _BV(NRF24.RF_DR_HIGH):
            # '01' = 2MBPS
            return NRF24.BR_2MBPS
        else:
            # '00' = 1MBPS
            return NRF24.BR_1MBPS

    def setCRCLength(self, length):
        config = self.read_register(
            NRF24.CONFIG) & ~(_BV(NRF24.CRC_16) | _BV(NRF24.CRC_ENABLED))

        if length == NRF24.CRC_DISABLED:
            # Do nothing, we turned it off above.
            self.write_register(NRF24.CONFIG, config)
            return
        elif length == NRF24.CRC_8:
            config |= _BV(NRF24.CRC_ENABLED)
            config |= _BV(NRF24.CRC_8)
        else:
            config |= _BV(NRF24.CRC_ENABLED)
            config |= _BV(NRF24.CRC_16)

        self.write_register(NRF24.CONFIG, config)

    def getCRCLength(self):
        result = NRF24.CRC_DISABLED
        config = self.read_register(
            NRF24.CONFIG) & (_BV(NRF24.CRCO) | _BV(NRF24.EN_CRC))

        if config & _BV(NRF24.EN_CRC):
            if config & _BV(NRF24.CRCO):
                result = NRF24.CRC_16
            else:
                result = NRF24.CRC_8

        return result

    def disableCRC(self):
        disable = self.read_register(NRF24.CONFIG) & ~_BV(NRF24.EN_CRC)
        self.write_register(NRF24.CONFIG, disable)

    def setRetries(self, delay, count):
        self.write_register(NRF24.SETUP_RETR, (delay & 0xf) << NRF24.ARD |
                            (count & 0xf) << NRF24.ARC)

    def getRetries(self):
        return self.read_register(NRF24.SETUP_RETR)

    def getMaxTimeout(self):
        retries = self.getRetries()
        return ((250 + (250 * ((retries & 0xf0) >> 4))) *
                (retries & 0x0f)) / 1000000.0
#!/usr/bin/python

from Adafruit_BBIO.SPI import SPI

spi = SPI(0,0)

spi.lsbfirst=False
spi.msh=1000000

spi.cshigh=False
spi.xfer2([0x36])
spi.cshigh=True

for reg in range(0x0,0x3d+1,1):
 spi.cshigh=False
 send = [ reg+0xc0 , 0x0 ]
 recv = spi.xfer2(send)
 spi.cshigh=True
 print reg,recv

patable=9*[0]
patable[0]=0x3e+0xc0

spi.cshigh=False
dd = spi.xfer2(patable)
spi.cshigh=True
print 0x3e,dd

rxfifo=65*[0]
rxfifo[0]=0x3f+0xc0
Exemple #5
0
from Adafruit_BBIO.SPI import SPI

import Adafruit_BBIO.GPIO as GPIO
import time

spi = SPI(0, 0)  #4 busses, this is bus 0
spi.msh = 10000  #Frequency
spi.bpw = 8  #bits per word
spi.cshigh = False  #true means you select the chip, depends on the chip, here low means active, normally Low for IMU
spi.threewire = False  #if it is true, you just read, otherwise you also send commands
spi.lsbfirst = False  #Least significant bit first (left)
spi.open(0, 0)  #open

#GPIO.setup("P8_11",GPIO.OUT)
#GPIO.output("P8_11",GPIO.HIGH)

try:
    while True:
        res = spi.xfer2([0xFFFF, 0xFFFF])  #deliver two bytes

        res1 = spi.readbytes(2)  #Read 2 bytes
        angle = (res1[0] << 8) | res1[1]  #merge leftbyte and rightbyte
        angle1 = angle & 0x3FFF  #move the first two bits
        angle2 = float(angle1) / 16363 * 360
        print("data is")
        print(angle2)
        time.sleep(.25)
except KeyboardInterrupt:
    spi.close()
Exemple #6
0
from Adafruit_BBIO.SPI import SPI

# From Adafruit Learning System:
# https://learn.adafruit.com/setting-up-io-python-library-on-beaglebone-black/spi
#spi = SPI(bus, device) #/dev/spidev<bus>.<device>
#spi = SPI(0,0)	#/dev/spidev1.0
#spi = SPI(0,1)	#/dev/spidev1.1
#spi = SPI(1,0)	#/dev/spidev2.0
#spi = SPI(1,1)	#/dev/spidev2.1

spi = SPI(0, 0)
print spi.xfer2([32, 11, 110, 22, 220])
spi.close()
Exemple #7
0
class NRF24:
    MAX_CHANNEL = 127
    MAX_PAYLOAD_SIZE = 32

    # PA Levels
    PA_MIN = 0
    PA_LOW = 1
    PA_HIGH = 2
    PA_MAX = 3
    PA_ERROR = 4

    # Bit rates
    BR_1MBPS = 0
    BR_2MBPS = 1
    BR_250KBPS = 2

    # CRC
    CRC_DISABLED = 0
    CRC_8 = 1
    CRC_16 = 2
    CRC_ENABLED = 3

    # Registers
    CONFIG = 0x00
    EN_AA = 0x01
    EN_RXADDR = 0x02
    SETUP_AW = 0x03
    SETUP_RETR = 0x04
    RF_CH = 0x05
    RF_SETUP = 0x06
    STATUS = 0x07
    OBSERVE_TX = 0x08
    CD = 0x09
    RX_ADDR_P0 = 0x0A
    RX_ADDR_P1 = 0x0B
    RX_ADDR_P2 = 0x0C
    RX_ADDR_P3 = 0x0D
    RX_ADDR_P4 = 0x0E
    RX_ADDR_P5 = 0x0F
    TX_ADDR = 0x10
    RX_PW_P0 = 0x11
    RX_PW_P1 = 0x12
    RX_PW_P2 = 0x13
    RX_PW_P3 = 0x14
    RX_PW_P4 = 0x15
    RX_PW_P5 = 0x16
    FIFO_STATUS = 0x17
    DYNPD = 0x1C
    FEATURE = 0x1D


    # Bit Mnemonics */
    MASK_RX_DR = 6
    MASK_TX_DS = 5
    MASK_MAX_RT = 4
    EN_CRC = 3
    CRCO = 2
    PWR_UP = 1
    PRIM_RX = 0
    ENAA_P5 = 5
    ENAA_P4 = 4
    ENAA_P3 = 3
    ENAA_P2 = 2
    ENAA_P1 = 1
    ENAA_P0 = 0
    ERX_P5 = 5
    ERX_P4 = 4
    ERX_P3 = 3
    ERX_P2 = 2
    ERX_P1 = 1
    ERX_P0 = 0
    AW = 0
    ARD = 4
    ARC = 0
    PLL_LOCK = 4
    RF_DR = 3
    RF_PWR = 6
    RX_DR = 6
    TX_DS = 5
    MAX_RT = 4
    RX_P_NO = 1
    TX_FULL = 0
    PLOS_CNT = 4
    ARC_CNT = 0
    TX_REUSE = 6
    FIFO_FULL = 5
    TX_EMPTY = 4
    RX_FULL = 1
    RX_EMPTY = 0
    DPL_P5 = 5
    DPL_P4 = 4
    DPL_P3 = 3
    DPL_P2 = 2
    DPL_P1 = 1
    DPL_P0 = 0
    EN_DPL = 2
    EN_ACK_PAY = 1
    EN_DYN_ACK = 0

    # Instruction Mnemonics
    R_REGISTER = 0x00
    W_REGISTER = 0x20
    REGISTER_MASK = 0x1F
    ACTIVATE = 0x50
    R_RX_PL_WID = 0x60
    R_RX_PAYLOAD = 0x61
    W_TX_PAYLOAD = 0xA0
    W_ACK_PAYLOAD = 0xA8
    FLUSH_TX = 0xE1
    FLUSH_RX = 0xE2
    REUSE_TX_PL = 0xE3
    NOP = 0xFF


    # Non-P omissions
    LNA_HCURR = 0x00

    # P model memory Map
    RPD = 0x09

    # P model bit Mnemonics
    RF_DR_LOW = 5
    RF_DR_HIGH = 3
    RF_PWR_LOW = 1
    RF_PWR_HIGH = 2

    # Signal Mnemonics
    LOW = 0
    HIGH = 1

    datarate_e_str_P = ["1MBPS", "2MBPS", "250KBPS"]
    model_e_str_P = ["nRF24L01", "nRF24l01+"]
    crclength_e_str_P = ["Disabled", "8 bits", "16 bits"]
    pa_dbm_e_str_P = ["PA_MIN", "PA_LOW", "PA_MED", "PA_HIGH"]
    child_pipe = [RX_ADDR_P0, RX_ADDR_P1, RX_ADDR_P2, RX_ADDR_P3, RX_ADDR_P4, RX_ADDR_P5]

    child_payload_size = [RX_PW_P0, RX_PW_P1, RX_PW_P2, RX_PW_P3, RX_PW_P4, RX_PW_P5]
    child_pipe_enable = [ERX_P0, ERX_P1, ERX_P2, ERX_P3, ERX_P4, ERX_P5]

    def __init__(self):
        self.ce_pin = "P9_15"
        self.irq_pin = "P9_16"
        self.channel = 76
        self.data_rate = NRF24.BR_1MBPS
        self.wide_band = False # 2Mbs data rate in use?
        self.p_variant = False # False for RF24L01 and true for RF24L01P
        self.payload_size = 5 #*< Fixed size of payloads
        self.ack_payload_available = False #*< Whether there is an ack payload waiting
        self.dynamic_payloads_enabled = False #*< Whether dynamic payloads are enabled.
        self.ack_payload_length = 5 #*< Dynamic size of pending ack payload.
        self.pipe0_reading_address = None #*< Last address set on pipe 0 for reading.
        self.spidev = None

    def ce(self, level):
        if level == NRF24.HIGH:
            GPIO.output(self.ce_pin, GPIO.HIGH)
        else:
            GPIO.output(self.ce_pin, GPIO.LOW)
        return

    def irqWait(self, timeout = 30000):
        # CHANGE: detect module name because wait_for_edge is not available in
        # other libraries
        if GPIO.__name__ != "Adafruit_BBIO.GPIO":
            return False

        # TODO: A race condition may occur here.
        if GPIO.input(self.irq_pin) == 0: # Pin is already down. Packet is waiting?
            return True

        return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING, timeout) == 1

    def read_register(self, reg, blen=1):
        buf = [NRF24.R_REGISTER | ( NRF24.REGISTER_MASK & reg )]
        for col in range(blen):
            buf.append(NRF24.NOP)

        resp = self.spidev.xfer2(buf)
        if blen == 1:
            return resp[1]

        return resp[1:blen + 1]

    def write_register(self, reg, value, length=-1):
        buf = [NRF24.W_REGISTER | ( NRF24.REGISTER_MASK & reg )]
        if isinstance(value, (int, long)):
            if length < 0:
                length = 1

            length = min(4, length)
            for i in range(length):
                buf.insert(1, int(value & 0xff))
                value >>= 8

        elif isinstance(value, list):
            if length < 0:
                length = len(value)

            for i in range(min(len(value), length)):
                buf.append(int(value[len(value) - i - 1] & 0xff))
        else:
            raise Exception("Value must be int or list")

        return self.spidev.xfer2(buf)[0]


    def write_payload(self, buf):
        data_len = min(self.payload_size, len(buf))
        blank_len = 0
        if not self.dynamic_payloads_enabled:
            blank_len = self.payload_size - data_len

        txbuffer = [NRF24.W_TX_PAYLOAD]
        for n in buf:
            t = type(n)
            if t is str:
                txbuffer.append(ord(n))
            elif t is int:
                txbuffer.append(n)
            else:
                raise Exception("Only ints and chars are supported: Found " + str(t))

        if blank_len != 0:
            blank = [0x00 for i in range(blank_len)]
            txbuffer.extend(blank)

        return self.spidev.xfer2(txbuffer)

    def read_payload(self, buf, buf_len=-1):
        if buf_len < 0:
            buf_len = self.payload_size
        data_len = min(self.payload_size, buf_len)
        blank_len = 0
        if not self.dynamic_payloads_enabled:
            blank_len = self.payload_size - data_len

        txbuffer = [NRF24.NOP for i in range(0, blank_len + data_len + 1)]
        txbuffer[0] = NRF24.R_RX_PAYLOAD

        payload = self.spidev.xfer2(txbuffer)
        del buf[:]
        buf.extend(payload[1:data_len + 1])
        return data_len

    def flush_rx(self):
        return self.spidev.xfer2([NRF24.FLUSH_RX])[0]

    def flush_tx(self):
        return self.spidev.xfer2([NRF24.FLUSH_TX])[0]

    def get_status(self):
        return self.spidev.xfer2([NRF24.NOP])[0]

    def print_status(self, status):
        status_str = "STATUS\t = 0x{0:02x} RX_DR={1:x} TX_DS={2:x} MAX_RT={3:x} RX_P_NO={4:x} TX_FULL={5:x}".format(
            status,
            1 if status & _BV(NRF24.RX_DR) else 0,
            1 if status & _BV(NRF24.TX_DS) else 0,
            1 if status & _BV(NRF24.MAX_RT) else 0,
            ((status >> NRF24.RX_P_NO) & int("111", 2)),
            1 if status & _BV(NRF24.TX_FULL) else 0)

        print status_str

    def print_observe_tx(self, value):
        tx_str = "OBSERVE_TX=0x{0:02x}: POLS_CNT={2:x} ARC_CNT={2:x}\r\n".format(
            value,
            (value >> NRF24.PLOS_CNT) & int("1111",2),
            (value >> NRF24.ARC_CNT)  & int("1111",2)
            )
        print tx_str

    def print_byte_register(self, name, reg, qty=1):
        extra_tab = '\t' if len(name) < 8 else 0
        print "%s\t%c =" % (name, extra_tab),
        while qty > 0:
            print "0x%02x" % (self.read_register(reg)),
            qty -= 1
            reg += 1

        print ""

    def print_address_register(self, name, reg, qty=1):
        extra_tab = '\t' if len(name) < 8 else 0
        print "%s\t%c =" % (name, extra_tab),

        while qty > 0:
            qty -= 1
            buf = reversed(self.read_register(reg, 5))
            reg += 1
            sys.stdout.write(" 0x"),
            for i in buf:
                sys.stdout.write("%02x" % i)

        print ""


    def setChannel(self, channel):
        self.channel = min(max(0, channel), NRF24.MAX_CHANNEL)
        self.write_register(NRF24.RF_CH, self.channel)

    def getChannel(self):
        return self.read_register(NRF24.RF_CH)

    def setPayloadSize(self, size):
        self.payload_size = min(max(size, 1), NRF24.MAX_PAYLOAD_SIZE)

    def getPayloadSize(self):
        return self.payload_size

    def printDetails(self):
        self.print_status(self.get_status())
        self.print_address_register("RX_ADDR_P0-1", NRF24.RX_ADDR_P0, 2)
        self.print_byte_register("RX_ADDR_P2-5", NRF24.RX_ADDR_P2, 4)
        self.print_address_register("TX_ADDR", NRF24.TX_ADDR)

        self.print_byte_register("RX_PW_P0-6", NRF24.RX_PW_P0, 6)
        self.print_byte_register("EN_AA", NRF24.EN_AA)
        self.print_byte_register("EN_RXADDR", NRF24.EN_RXADDR)
        self.print_byte_register("RF_CH", NRF24.RF_CH)
        self.print_byte_register("RF_SETUP", NRF24.RF_SETUP)
        self.print_byte_register("CONFIG", NRF24.CONFIG)
        self.print_byte_register("DYNPD/FEATURE", NRF24.DYNPD, 2)

        #
        print "Data Rate\t = %s" % NRF24.datarate_e_str_P[self.getDataRate()]
        print "Model\t\t = %s" % NRF24.model_e_str_P[self.isPVariant()]
        print "CRC Length\t = %s" % NRF24.crclength_e_str_P[self.getCRCLength()]
        print "PA Power\t = %s" % NRF24.pa_dbm_e_str_P[self.getPALevel()]

    def begin(self, major, minor, ce_pin, irq_pin):
        # Initialize SPI bus
        self.spidev = SPI(major, minor) 
        self.ce_pin = ce_pin
        self.irq_pin = irq_pin

        GPIO.setup(self.ce_pin, GPIO.OUT)
        GPIO.setup(self.irq_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

        time.sleep(5 / 1000000.0)

        # Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier
        # WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet
        # sizes must never be used. See documentation for a more complete explanation.
        self.write_register(NRF24.SETUP_RETR, (int('0100', 2) << NRF24.ARD) | (int('1111', 2) << NRF24.ARC))

        # Restore our default PA level
        self.setPALevel(NRF24.PA_MAX)

        # Determine if this is a p or non-p RF24 module and then
        # reset our data rate back to default value. This works
        # because a non-P variant won't allow the data rate to
        # be set to 250Kbps.
        if self.setDataRate(NRF24.BR_250KBPS):
            self.p_variant = True

        # Then set the data rate to the slowest (and most reliable) speed supported by all
        # hardware.
        self.setDataRate(NRF24.BR_1MBPS)

        # Initialize CRC and request 2-byte (16bit) CRC
        self.setCRCLength(NRF24.CRC_16)

        # Disable dynamic payloads, to match dynamic_payloads_enabled setting
        self.write_register(NRF24.DYNPD, 0)

        # Reset current status
        # Notice reset and flush is the last thing we do
        self.write_register(NRF24.STATUS, _BV(NRF24.RX_DR) | _BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT))

        # Set up default configuration.  Callers can always change it later.
        # This channel should be universally safe and not bleed over into adjacent
        # spectrum.
        self.setChannel(self.channel)

        # Flush buffers
        self.flush_rx()
        self.flush_tx()

    def end(self):
        if self.spidev:
            self.spidev.close()
            self.spidev = None

    def startListening(self):
        self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | _BV(NRF24.PWR_UP) | _BV(NRF24.PRIM_RX))
        self.write_register(NRF24.STATUS, _BV(NRF24.RX_DR) | _BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT))

        # Restore the pipe0 address, if exists
        if self.pipe0_reading_address:
            self.write_register(self.RX_ADDR_P0, self.pipe0_reading_address, 5)

        # Go!
        self.ce(NRF24.HIGH)

        # wait for the radio to come up (130us actually only needed)
        time.sleep(130 / 1000000.0)

    def stopListening(self):
        self.ce(NRF24.LOW)
        self.flush_tx()
        self.flush_rx()

    def powerDown(self):
        self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) & ~_BV(NRF24.PWR_UP))

    def powerUp(self):
        self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | _BV(NRF24.PWR_UP))
        time.sleep(150 / 1000000.0)

    def write(self, buf):
        # Begin the write
        self.startWrite(buf)

        timeout = self.getMaxTimeout() #s to wait for timeout
        sent_at = time.time()

        while True:
            #status = self.read_register(NRF24.OBSERVE_TX, 1)
            status = self.get_status()
            if (status & (_BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT))) or (time.time() - sent_at > timeout ):
                break
            time.sleep(10 / 1000000.0)

        what = self.whatHappened()

        result = what['tx_ok']

        # Handle the ack packet
        if what['rx_ready']:
            self.ack_payload_length = self.getDynamicPayloadSize()

        return result

    def startWrite(self, buf):
        # Transmitter power-up
        self.write_register(NRF24.CONFIG, (self.read_register(NRF24.CONFIG) | _BV(NRF24.PWR_UP) ) & ~_BV(NRF24.PRIM_RX))

        # Send the payload
        self.write_payload(buf)

        # Allons!
        self.ce(NRF24.HIGH)
        time.sleep(10 / 1000000.0)
        self.ce(NRF24.LOW)

    def getDynamicPayloadSize(self):
        return self.spidev.xfer2([NRF24.R_RX_PL_WID, NRF24.NOP])[1]

    def available(self, pipe_num=None, irq_wait=False, irq_timeout=30000):
        if not pipe_num:
            pipe_num = []

        status = self.get_status()
        result = False

        # Sometimes the radio specifies that there is data in one pipe but
        # doesn't set the RX flag...
        if status & _BV(NRF24.RX_DR) or (status & 0b00001110 != 0b00001110):
            result = True
        else:
            if irq_wait: # Will use IRQ wait
                if self.irqWait(irq_timeout): # Do we have a packet?
                    status = self.get_status() # Seems like we do!
                    if status & _BV(NRF24.RX_DR) or (status & 0b00001110 != 0b00001110):
                        result = True 

        if result:
            # If the caller wants the pipe number, include that
            if len(pipe_num) >= 1:
                pipe_num[0] = ( status >> NRF24.RX_P_NO ) & 0b00000111

                # Clear the status bit

                # ??? Should this REALLY be cleared now?  Or wait until we
                # actually READ the payload?
        self.write_register(NRF24.STATUS, _BV(NRF24.RX_DR))

        # Handle ack payload receipt
        if status & _BV(NRF24.TX_DS):
            self.write_register(NRF24.STATUS, _BV(NRF24.TX_DS))

        return result

    def read(self, buf, buf_len=-1):
        # Fetch the payload
        self.read_payload(buf, buf_len)

        # was this the last of the data available?
        return self.read_register(NRF24.FIFO_STATUS) & _BV(NRF24.RX_EMPTY)

    def whatHappened(self):
        # Read the status & reset the status in one easy call
        # Or is that such a good idea?
        status = self.write_register(NRF24.STATUS, _BV(NRF24.RX_DR) | _BV(NRF24.TX_DS) | _BV(NRF24.MAX_RT))

        # Report to the user what happened
        tx_ok = status & _BV(NRF24.TX_DS)
        tx_fail = status & _BV(NRF24.MAX_RT)
        rx_ready = status & _BV(NRF24.RX_DR)
        return {'tx_ok': tx_ok, "tx_fail": tx_fail, "rx_ready": rx_ready}

    def openWritingPipe(self, value):
        # Note that the NRF24L01(+)
        # expects it LSB first.

        self.write_register(NRF24.RX_ADDR_P0, value, 5)
        self.write_register(NRF24.TX_ADDR, value, 5)

        max_payload_size = 32
        self.write_register(NRF24.RX_PW_P0, min(self.payload_size, max_payload_size))

    def openReadingPipe(self, child, address):
        # If this is pipe 0, cache the address.  This is needed because
        # openWritingPipe() will overwrite the pipe 0 address, so
        # startListening() will have to restore it.
        if child == 0:
            self.pipe0_reading_address = address

        if child <= 6:
            # For pipes 2-5, only write the LSB
            if child < 2:
                self.write_register(NRF24.child_pipe[child], address, 5)
            else:
                self.write_register(NRF24.child_pipe[child], address, 1)

            self.write_register(NRF24.child_payload_size[child], self.payload_size)

            # Note it would be more efficient to set all of the bits for all open
            # pipes at once.  However, I thought it would make the calling code
            # more simple to do it this way.
            self.write_register(NRF24.EN_RXADDR,
                                self.read_register(NRF24.EN_RXADDR) | _BV(NRF24.child_pipe_enable[child]))


    def closeReadingPipe(self, pipe):
        self.write_register(NRF24.EN_RXADDR,
            self.read_register(EN_RXADDR) & ~_BV(NRF24.child_pipe_enable[pipe]))


    def toggle_features(self):
        buf = [NRF24.ACTIVATE, 0x73]
        self.spidev.xfer2(buf)

    def enableDynamicPayloads(self):
        # Enable dynamic payload throughout the system
        self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_DPL))

        # If it didn't work, the features are not enabled
        if not self.read_register(NRF24.FEATURE):
            # So enable them and try again
            self.toggle_features()
            self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_DPL))

        # Enable dynamic payload on all pipes

        # Not sure the use case of only having dynamic payload on certain
        # pipes, so the library does not support it.
        self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | _BV(NRF24.DPL_P5) | _BV(NRF24.DPL_P4) | _BV(
            NRF24.DPL_P3) | _BV(NRF24.DPL_P2) | _BV(NRF24.DPL_P1) | _BV(NRF24.DPL_P0))

        self.dynamic_payloads_enabled = True


    def enableAckPayload(self):
        # enable ack payload and dynamic payload features
        self.write_register(NRF24.FEATURE,
                            self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_ACK_PAY) | _BV(NRF24.EN_DPL))

        # If it didn't work, the features are not enabled
        if not self.read_register(NRF24.FEATURE):
            # So enable them and try again
            self.toggle_features()
            self.write_register(NRF24.FEATURE,
                                self.read_register(NRF24.FEATURE) | _BV(NRF24.EN_ACK_PAY) | _BV(NRF24.EN_DPL))

        # Enable dynamic payload on pipes 0 & 1
        self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | _BV(NRF24.DPL_P1) | _BV(NRF24.DPL_P0))

    def writeAckPayload(self, pipe, buf, buf_len):
        txbuffer = [NRF24.W_ACK_PAYLOAD | ( pipe & 0x7 )]

        max_payload_size = 32
        data_len = min(buf_len, max_payload_size)
        txbuffer.extend(buf[0:data_len])

        self.spidev.xfer2(txbuffer)

    def isAckPayloadAvailable(self):
        result = self.ack_payload_available
        self.ack_payload_available = False
        return result

    def isPVariant(self):
        return self.p_variant

    def setAutoAck(self, enable):
        if enable:
            self.write_register(NRF24.EN_AA, int('111111',2))
        else:
            self.write_register(NRF24.EN_AA, 0)

    def setAutoAckPipe(self, pipe, enable):
        if pipe <= 6:
            en_aa = self.read_register(NRF24.EN_AA)
            if enable:
                en_aa |= _BV(pipe)
            else:
                en_aa &= ~_BV(pipe)

            self.write_register(NRF24.EN_AA, en_aa)

    def testCarrier(self):
        return self.read_register(NRF24.CD) & 1

    def testRPD(self):
        return self.read_register(NRF24.RPD) & 1

    def setPALevel(self, level):
        setup = self.read_register(NRF24.RF_SETUP)
        setup &= ~( _BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH))
        # switch uses RAM (evil!)
        if level == NRF24.PA_MAX:
            setup |= (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH))
        elif level == NRF24.PA_HIGH:
            setup |= _BV(NRF24.RF_PWR_HIGH)
        elif level == NRF24.PA_LOW:
            setup |= _BV(NRF24.RF_PWR_LOW)
        elif level == NRF24.PA_MIN:
            nop = 0
        elif level == NRF24.PA_ERROR:
            # On error, go to maximum PA
            setup |= (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH))

        self.write_register(NRF24.RF_SETUP, setup)


    def getPALevel(self):
        power = self.read_register(NRF24.RF_SETUP) & (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH))

        if power == (_BV(NRF24.RF_PWR_LOW) | _BV(NRF24.RF_PWR_HIGH)):
            return NRF24.PA_MAX
        elif power == _BV(NRF24.RF_PWR_HIGH):
            return NRF24.PA_HIGH
        elif power == _BV(NRF24.RF_PWR_LOW):
            return NRF24.PA_LOW
        else:
            return NRF24.PA_MIN

    def setDataRate(self, speed):
        result = False
        setup = self.read_register(NRF24.RF_SETUP)

        # HIGH and LOW '00' is 1Mbs - our default
        self.wide_band = False
        setup &= ~(_BV(NRF24.RF_DR_LOW) | _BV(NRF24.RF_DR_HIGH))

        if speed == NRF24.BR_250KBPS:
            # Must set the RF_DR_LOW to 1 RF_DR_HIGH (used to be RF_DR) is already 0
            # Making it '10'.
            self.wide_band = False
            setup |= _BV(NRF24.RF_DR_LOW)
        else:
            # Set 2Mbs, RF_DR (RF_DR_HIGH) is set 1
            # Making it '01'
            if speed == NRF24.BR_2MBPS:
                self.wide_band = True
                setup |= _BV(NRF24.RF_DR_HIGH)
            else:
                # 1Mbs
                self.wide_band = False

        self.write_register(NRF24.RF_SETUP, setup)

        # Verify our result
        if self.read_register(NRF24.RF_SETUP) == setup:
            result = True
        else:
            self.wide_band = False
        return result

    def getDataRate(self):
        dr = self.read_register(NRF24.RF_SETUP) & (_BV(NRF24.RF_DR_LOW) | _BV(NRF24.RF_DR_HIGH))
        # Order matters in our case below
        if dr == _BV(NRF24.RF_DR_LOW):
            # '10' = 250KBPS
            return NRF24.BR_250KBPS
        elif dr == _BV(NRF24.RF_DR_HIGH):
            # '01' = 2MBPS
            return NRF24.BR_2MBPS
        else:
            # '00' = 1MBPS
            return NRF24.BR_1MBPS


    def setCRCLength(self, length):
        config = self.read_register(NRF24.CONFIG) & ~( _BV(NRF24.CRC_16) | _BV(NRF24.CRC_ENABLED))

        if length == NRF24.CRC_DISABLED:
            # Do nothing, we turned it off above.
            self.write_register(NRF24.CONFIG, config)
            return
        elif length == NRF24.CRC_8:
            config |= _BV(NRF24.CRC_ENABLED)
            config |= _BV(NRF24.CRC_8)
        else:
            config |= _BV(NRF24.CRC_ENABLED)
            config |= _BV(NRF24.CRC_16)

        self.write_register(NRF24.CONFIG, config)

    def getCRCLength(self):
        result = NRF24.CRC_DISABLED
        config = self.read_register(NRF24.CONFIG) & ( _BV(NRF24.CRCO) | _BV(NRF24.EN_CRC))

        if config & _BV(NRF24.EN_CRC):
            if config & _BV(NRF24.CRCO):
                result = NRF24.CRC_16
            else:
                result = NRF24.CRC_8

        return result

    def disableCRC(self):
        disable = self.read_register(NRF24.CONFIG) & ~_BV(NRF24.EN_CRC)
        self.write_register(NRF24.CONFIG, disable)

    def setRetries(self, delay, count):
        self.write_register(NRF24.SETUP_RETR, (delay & 0xf) << NRF24.ARD | (count & 0xf) << NRF24.ARC)


    def getRetries(self):
        return self.read_register(NRF24.SETUP_RETR)

    def getMaxTimeout(self):
        retries = self.getRetries()
        return ((250+(250*((retries& 0xf0)>>4 ))) * (retries & 0x0f)) / 1000000.0
Exemple #8
0
from Adafruit_BBIO.SPI import SPI

command = sys.argv[1]

WALK = 1
WALK_BACK = 31
STOP = 15
TURNL = 3
TURNR = 7

spi = SPI(0,0) 
spi.msh = 57600
spi.bpw = 8
#for debugging with keyboard input
#command = raw_input();
spi.xfer2([getCommandCode(command)])
spi.close() 

def getCommandCode(command):
      if command == 'walk':
    print("Walk!")
    return WALK
  elif command == 'back':
    print('Reverse')
    return WALK_BACK
  elif command == 'stop':
    print('Stop!')
    return STOP
  elif command == 'left': 
    print('Turn Left')
    return TURNL
Exemple #9
0
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
    simple test for SPI adafruit-BBIO.

    https://learn.adafruit.com/setting-up-io-python-library-on-beaglebone-black/spi
"""

from Adafruit_BBIO.SPI import SPI
#spi = SPI(bus, device) #/dev/spidev<bus>.<device>

# /dev/spidev0.0
spi = SPI(1, 0)
print(spi.xfer2([32, 11, 110, 22, 220]))
spi.close()

print("Hello BBIO SPI!")
spi.open(0,0)
#spi.msh = 100000
spi.bpw = 8
#spi.mode = b00
try:
#while True:
        # set CS bit high, choose first channel to read from

        #channel = 0;
        #adc = spi.xfer([1,8,0])
        #data = ((adc[1]&3) << 8) + adc[2]

        channelSelect = 0xC0
        channelSelect |= 0x18
        channelSelect <<= 3
        fsr = spi.xfer2([channelSelect, 0x00, 0x00])
        #result = spi.readbytes(2)
        #result2 = spi.readbytes(1)

        resultFinal = 0x0000
        resultFinal = 0x0300 & (resultFinal | (fsr[1] << 8 ))
        resultFinal |= ( ( 0x00FF  & fsr[2]) )
        #print (8 + channel ) << 4
        #print resultFinal

	###################################
	####################################
	resultFinal = 1 #temp
	file = open('methane_test.txt', 'r')
	data = []
	#data.append(str(resultFinal) + '\n')
Exemple #11
0
class NRF24:
    MAX_CHANNEL = 127
    MAX_PAYLOAD_SIZE = 32

    # PA Levels
    PA_MIN = 0x00
    PA_LOW = 0x01
    PA_HIGH = 0x02
    PA_MAX = 0x03
    PA_ERROR = 0x04

    # Bit rates
    BR_1MBPS = 0
    BR_2MBPS = 1
    BR_250KBPS = 2

    # CRC
    CRC_DISABLED = 0x0
    CRC_8 = 0x02
    CRC_16 = 0x04
    CRC_ENABLED = 0x08

    EN_CRC = 0x08
    CRCO = 0x04

    # Registers
    CONFIG = 0x00
    EN_AA = 0x01
    EN_RXADDR = 0x02
    SETUP_AW = 0x03
    SETUP_RETR = 0x04
    RF_CH = 0x05
    RF_SETUP = 0x06
    STATUS = 0x07
    OBSERVE_TX = 0x08
    RPD = 0x09
    RX_ADDR_P0 = 0x0A
    RX_ADDR_P1 = 0x0B
    RX_ADDR_P2 = 0x0C
    RX_ADDR_P3 = 0x0D
    RX_ADDR_P4 = 0x0E
    RX_ADDR_P5 = 0x0F
    TX_ADDR = 0x10
    RX_PW_P0 = 0x11
    RX_PW_P1 = 0x12
    RX_PW_P2 = 0x13
    RX_PW_P3 = 0x14
    RX_PW_P4 = 0x15
    RX_PW_P5 = 0x16
    FIFO_STATUS = 0x17
    DYNPD = 0x1C
    FEATURE = 0x1D

    # Bit Mnemonics */
    MASK_RX_DR = 0x40
    MASK_TX_DS = 0x20
    MASK_MAX_RT = 0x10

    PWR_UP = 0x02
    PRIM_RX = 0x01
    PLL_LOCK = 0x10
    RX_DR = 0x40
    TX_DS = 0x20
    MAX_RT = 0x10
    TX_FULL = 0x01

    EN_DPL = 0x04
    EN_ACK_PAY = 0x02
    EN_DYN_ACK = 0x01

    # Shift counts
    ARD = 4
    ARC = 0
    PLOS_CNT = 4
    ARC_CNT = 0
    RX_P_NO = 1

    TX_REUSE = 6
    FIFO_FULL = 5
    TX_EMPTY = 4
    RX_FULL = 1
    RX_EMPTY = 0

    DPL_P5 = 5
    DPL_P4 = 4
    DPL_P3 = 3
    DPL_P2 = 2
    DPL_P1 = 1
    DPL_P0 = 0

    #Masks
    RX_P_NO_MASK = 0x0E

    # Instruction Mnemonics
    R_REGISTER = 0x00
    W_REGISTER = 0x20
    REGISTER_MASK = 0x1F
    ACTIVATE = 0x50
    R_RX_PL_WID = 0x60
    R_RX_PAYLOAD = 0x61
    W_TX_PAYLOAD = 0xA0
    W_ACK_PAYLOAD = 0xA8
    FLUSH_TX = 0xE1
    FLUSH_RX = 0xE2
    REUSE_TX_PL = 0xE3
    NOP = 0xFF

    # Non-P omissions
    LNA_HCURR = 0x01
    LNA_ON = 1
    LNA_OFF = 0

    # P model bit Mnemonics
    RF_DR_LOW = 0x20
    RF_DR_HIGH = 0x08
    RF_PWR_LOW = 0x02
    RF_PWR_HIGH = 0x04

    datarate_e_str_P = ["1MBPS", "2MBPS", "250KBPS"]
    model_e_str_P = ["nRF24L01", "nRF24l01+"]
    crclength_e_str_P = ["Disabled", "", "8 bits", "", "16 bits"]
    pa_dbm_e_str_P = ["PA_MIN", "PA_LOW", "PA_HIGH", "PA_MAX"]

    @staticmethod
    def print_single_status_line(name, value):
        print("{0:<16}= {1}".format(name, value))

    @staticmethod
    def _to_8b_list(data):
        """Convert an arbitray iteratable or single int to a list of ints
            where each int is smaller than 256."""
        if isinstance(data, str):
            data = [ord(x) for x in data]
        elif isinstance(data, (int, long)):
            data = [data]
        else:
            data = [int(x) for x in data]

        #for byte in data:
        #    if byte < 0 or byte > 255:
        #        raise RuntimeError("Value %d is larger than 8 bits" % byte)
        return data

    def __init__(self, major=None, minor=None, ce_pin=None, irq_pin=None):
        self.ce_pin = "P9_15"
        self.irq_pin = "P9_16"
        self.channel = 76
        self.data_rate = NRF24.BR_1MBPS
        self.data_rate_bits = 1000
        self.p_variant = False  # False for RF24L01 and true for RF24L01P
        self.payload_size = 5  # *< Fixed size of payloads
        self.ack_payload_available = False  # *< Whether there is an ack payload waiting
        self.dynamic_payloads_enabled = False  # *< Whether dynamic payloads are enabled.
        self.ack_payload_length = 5  # *< Dynamic size of pending ack payload.
        self.pipe0_reading_address = None  # *< Last address set on pipe 0 for reading.
        self.spidev = None
        self.last_error = 0
        self.crc_length = 0
        self.auto_ack = 0x3F
        self.address_length = 5

        # If all parameters are available, lets start the radio!
        if major is not None and minor is not None and irq_pin is not None:
            self.begin(major, minor, ce_pin, irq_pin)

    def begin(self, major, minor, ce_pin, irq_pin):
        # Initialize SPI bus

        if ADAFRUID_BBIO_SPI:
            self.spidev = SPI(major, minor)
            self.spidev.bpw = 8
            try:
                self.spidev.msh = 10000000  # Maximum supported by NRF24L01+
            except IOError:
                pass  # Hardware does not support this speed
        else:
            self.spidev = spidev.SpiDev()
            self.spidev.open(major, minor)

            self.spidev.bits_per_word = 8

            try:
                self.spidev.max_speed_hz = 10000000  # Maximum supported by NRF24L01+
            except IOError:
                pass  # Hardware does not support this speed

        self.spidev.cshigh = False
        self.spidev.mode = 0
        self.spidev.loop = False
        self.spidev.lsbfirst = False
        self.spidev.threewire = False

        self.ce_pin = ce_pin
        self.irq_pin = irq_pin

        if self.ce_pin is not None:
            GPIO.setup(self.ce_pin, GPIO.OUT)

        GPIO.setup(self.irq_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

        time.sleep(5 / 1000000.0)

        # Reset radio configuration
        self.reset()

        # Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier
        # WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet
        # sizes must never be used. See documentation for a more complete explanation.
        self.setRetries(int('0101', 2), 15)

        # Restore our default PA level
        self.setPALevel(NRF24.PA_MAX)

        # Determine if this is a p or non-p RF24 module and then
        # reset our data rate back to default value. This works
        # because a non-P variant won't allow the data rate to
        # be set to 250Kbps.
        if self.setDataRate(NRF24.BR_250KBPS):
            self.p_variant = True

        # Then set the data rate to the slowest (and most reliable) speed supported by all
        # hardware.
        self.setDataRate(NRF24.BR_1MBPS)

        # Initialize CRC and request 2-byte (16bit) CRC
        self.setCRCLength(NRF24.CRC_16)

        # Disable dynamic payloads, to match dynamic_payloads_enabled setting
        self.write_register(NRF24.DYNPD, 0)

        # Reset current status
        # Notice reset and flush is the last thing we do
        self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT)

        # Set up default configuration.  Callers can always change it later.
        # This channel should be universally safe and not bleed over into adjacent
        # spectrum.
        self.setChannel(self.channel)

        self.setRetries(15, 15)

        # Flush buffers
        self.flush_rx()
        self.flush_tx()
        self.clear_irq_flags()

    def end(self):
        if self.spidev:
            self.spidev.close()
            self.spidev = None

    def startListening(self):
        self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP | NRF24.PRIM_RX)
        self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT)

        self.flush_tx()
        self.flush_rx()
        self.clear_irq_flags()

        # Restore the pipe0 address, if exists
        if self.pipe0_reading_address:
            self.write_register(self.RX_ADDR_P0, self.pipe0_reading_address)

        # Go!
        self.ce(1)

    def ce(self, level, pulse=0):
        # CE Pin is optional
        if self.ce_pin is not None:
            GPIO.output(self.ce_pin, level)
            if pulse > 0:
                time.sleep(pulse)
                GPIO.output(self.ce_pin, 1 - level)

    def irqWait(self, timeout=30000):
        # TODO: A race condition may occur here. => wait for level?
        if GPIO.input(self.irq_pin) == 0:  # Pin is already down. Packet is waiting?
            return True

        try:
            return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING, timeout) == 1
        except TypeError:  # Timeout parameter not supported
            return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING) == 1
        except AttributeError:
            raise RuntimeError("GPIO lib does not support wait_for_edge()")

    def read_register(self, reg, length=1):
        buf = [NRF24.R_REGISTER | (NRF24.REGISTER_MASK & reg)]
        buf += [NRF24.NOP] * max(1, length)

        resp = self.spidev.xfer2(buf)
        if length == 1:
            return resp[1]

        return resp[1:]

    def write_register(self, reg, value):
        """ Write register value """
        buf = [NRF24.W_REGISTER | (NRF24.REGISTER_MASK & reg)]
        buf += self._to_8b_list(value)
        self.spidev.xfer2(buf)

    def write_payload(self, buf):
        """ Writes data to the payload register, automatically padding it
            to match the required length. Returns the number of bytes
            actually written. """

        buf = self._to_8b_list(buf)
        if self.dynamic_payloads_enabled:
            if len(buf) > self.MAX_PAYLOAD_SIZE:
                raise RuntimeError("Dynamic payload is larger than the " +
                                   "maximum size.")
            blank_len = 0
        else:
            if len(buf) > self.payload_size:
                raise RuntimeError("Payload is larger than the fixed payload" +
                                   "size (%d vs. %d bytes)" % (len(buf), self.payload_size))
            blank_len = self.payload_size - len(buf)

        txbuffer = [NRF24.W_TX_PAYLOAD] + buf + ([0x00] * blank_len)
        self.spidev.xfer2(txbuffer)
        return len(txbuffer) - 1

    def read_payload(self, buf, buf_len=-1):
        """ Reads data from the payload register and sets the
            DR bit of the STATUS register. """

        if buf_len < 0:
            buf_len = self.payload_size

        if not self.dynamic_payloads_enabled:
            data_len = min(self.payload_size, buf_len)
            blank_len = self.payload_size - data_len
        else:
            data_len = self.getDynamicPayloadSize()
            blank_len = 0

        txbuffer = [NRF24.R_RX_PAYLOAD] + [NRF24.NOP] * (blank_len + data_len + 1)

        payload = self.spidev.xfer2(txbuffer)
        del buf[:]
        buf += payload[1:data_len + 1]

        self.write_register(NRF24.STATUS, NRF24.RX_DR)

        return data_len

    def flush_rx(self):
        return self.spidev.xfer2([NRF24.FLUSH_RX])[0]

    def flush_tx(self):
        return self.spidev.xfer2([NRF24.FLUSH_TX])[0]

    def get_status(self):
        return self.spidev.xfer2([NRF24.NOP])[0]

    def get_status_str(self, status):
        status_str = "STATUS\t = 0x{0:02x} RX_DR={1:x} TX_DS={2:x} MAX_RT={3:x} RX_P_NO={4:x} TX_FULL={5:x}".format(
            status,
            1 if status & NRF24.RX_DR else 0,
            1 if status & NRF24.TX_DS else 0,
            1 if status & NRF24.MAX_RT else 0,
            ((status >> NRF24.RX_P_NO) & int("111", 2)),
            1 if status & NRF24.TX_FULL else 0)
        return status_str

        
    def print_status(self, status):
        print self.get_status_str(status)
        
    def get_observe_tx_str(self, value):
        tx_str = "OBSERVE_TX=0x{0:02x}: POLS_CNT={2:x} ARC_CNT={2:x}\r\n".format(
            value,
            (value >> NRF24.PLOS_CNT) & int("1111",2),
            (value >> NRF24.ARC_CNT)  & int("1111",2)
            )
        return tx_str

    def print_observe_tx(self, value):
        print self.get_observe_tx_str(value)

    def get_byte_register_str(self, name, reg, qty=1):
        extra_tab = '\t' if len(name) < 8 else 0
        byte_str= "%s\t%c =" % (name, extra_tab)
        while qty > 0:
            byte_str+= " 0x%02x" % (self.read_register(reg))
            qty -= 1
            reg += 1
        return byte_str
        

    def print_byte_register(self, name, reg, qty=1):
        print self.get_address_register_str(name, reg, qty)

    def get_address_register_str(self, name, reg, qty=1):
        extra_tab = '\t' if len(name) < 8 else 0
        addr_str = "%s\t%c =" % (name, extra_tab)

        while qty > 0:
            qty -= 1
            buf = reversed(self.read_register(reg, 5))
            reg += 1
            addr_str+=" 0x"
            for i in buf:
                addr_str+="%02x" % i
        return addr_str
    
    def print_address_register(self, name, reg, qty=1):
        print self.get_address_register_str(name, reg, qty)

        self.print_single_status_line(name, " ".join(address_registers))

    def setChannel(self, channel):
        if channel < 0 or channel > self.MAX_CHANNEL:
            raise RuntimeError("Channel number out of range")
        self.channel = channel
        self.write_register(NRF24.RF_CH, channel)

    def getChannel(self):
        return self.read_register(NRF24.RF_CH)

    def setPayloadSize(self, size):
        self.payload_size = min(max(size, 1), NRF24.MAX_PAYLOAD_SIZE)

    def getPayloadSize(self):
        return self.payload_size

    def getDetails(self):
        return  "\n".join([self.get_status_str(self.get_status()),
            self.get_address_register_str("RX_ADDR_P0-1", NRF24.RX_ADDR_P0, 2),
            self.get_byte_register_str("RX_ADDR_P2-5", NRF24.RX_ADDR_P2, 4),
            self.get_address_register_str("TX_ADDR", NRF24.TX_ADDR),
            self.get_byte_register_str("RX_PW_P0-6", NRF24.RX_PW_P0, 6),
            self.get_byte_register_str("EN_AA", NRF24.EN_AA),
            self.get_byte_register_str("EN_RXADDR", NRF24.EN_RXADDR),
            self.get_byte_register_str("RF_CH", NRF24.RF_CH),
            self.get_byte_register_str("RF_SETUP", NRF24.RF_SETUP),
            self.get_byte_register_str("CONFIG", NRF24.CONFIG),
            self.get_byte_register_str("DYNPD/FEATURE", NRF24.DYNPD, 2),
            "Data Rate\t = %s" % NRF24.datarate_e_str_P[self.getDataRate()],
            "Model\t\t = %s" % NRF24.model_e_str_P[self.isPVariant()],
            "CRC Length\t = %s" % NRF24.crclength_e_str_P[self.getCRCLength()],
            "PA Power\t = %s" % NRF24.pa_dbm_e_str_P[self.getPALevel()]])


    def printDetails(self):
        print self.getDetails()

    def stopListening(self):
        self.ce(0)
        self.flush_tx()
        self.flush_rx()
        self.clear_irq_flags()

        # Enable TX
        self.write_register(NRF24.CONFIG,
                            (self.read_register(NRF24.CONFIG) | NRF24.PWR_UP) & ~NRF24.PRIM_RX)

        # Enable pipe 0 for auto-ack
        self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | 1)

    def powerDown(self):
        self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) & ~ NRF24.PWR_UP)

    def powerUp(self):
        self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP)
        time.sleep(150e-6)

    def write(self, buf):
        self.last_error = None
        length = self.write_payload(buf)
        self.ce(1)

        sent_at = monotonic()
        packet_time = ((1 + length + self.crc_length + self.address_length) * 8 + 9)/(self.data_rate_bits * 1000.)

        if self.auto_ack != 0:
            packet_time *= 2

        if self.retries != 0 and self.auto_ack != 0:
            timeout = sent_at + (packet_time + self.delay)*self.retries
        else:
            timeout = sent_at + packet_time * 2  # 2 is empiric

        #while NRF24.TX_DS &  self.get_status() == 0:
        #    pass

        #print monotonic() - sent_at
        #print packet_time

        while monotonic() < timeout:
            time.sleep(packet_time)
            status = self.get_status()
            if status & NRF24.TX_DS:
                self.ce(0)
                return True

            if status & NRF24.MAX_RT:
                self.last_error = 'MAX_RT'
                self.ce(0)
                break

        self.ce(0)
        if self.last_error is None:
            self.last_error = 'TIMEOUT'

        self.flush_tx()  # Avoid leaving the payload in tx fifo
        return False

    def startFastWrite(self, buf):
        """
            Do not wait for CE HIGH->LOW
        """
        # Send the payload
        self.write_payload(buf)

        self.ce(1)

    def startWrite(self, buf):
        # Send the payload
        self.write_payload(buf)

        # Allons!
        self.ce(1, 10e-6)

    def getDynamicPayloadSize(self):
        return self.spidev.xfer2([NRF24.R_RX_PL_WID, NRF24.NOP])[1]

    def available(self, pipe_num=None, irq_wait=False, irq_timeout=30000):
        status = self.get_status()
        result = False

        # Sometimes the radio specifies that there is data in one pipe but
        # doesn't set the RX flag...
        if status & NRF24.RX_DR or (status & NRF24.RX_P_NO_MASK != NRF24.RX_P_NO_MASK):
            result = True
        else:
            if irq_wait:  # Will use IRQ wait
                if self.irqWait(irq_timeout):  # Do we have a packet?
                    status = self.get_status()  # Seems like we do!
                    if status & NRF24.RX_DR or (status & NRF24.RX_P_NO_MASK != NRF24.RX_P_NO_MASK):
                        result = True
        # read status once again see Note on page 52 or 56 in product specification 1.0
        # Note: The 3 bit pipe information in the STATUS register is updated during the IRQ pin high to low
        #transition. The pipe information is unreliable if the STATUS register is read during an IRQ pin
        #high to low transition.
        status = self.get_status()
        del pipe_num[:]
        if result and pipe_num is not None:
            pipe_num.append((status & NRF24.RX_P_NO_MASK) >> NRF24.RX_P_NO)

        # Handle ack payload receipt
        if status & NRF24.TX_DS:
            self.write_register(NRF24.STATUS, NRF24.TX_DS)

        return result

    def read(self, buf, buf_len=-1):
        # Fetch the payload
        self.read_payload(buf, buf_len)

        # was this the last of the data available?
        return self.read_register(NRF24.FIFO_STATUS & NRF24.RX_EMPTY)

    def clear_irq_flags(self):
        self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT)

    def whatHappened(self):
        # Read the status & reset the status in one easy call
        # Or is that such a good idea?
        self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT)

        status = self.get_status()
        self.clear_irq_flags()

        # Report to the user what happened
        tx_ok = status & NRF24.TX_DS
        tx_fail = status & NRF24.MAX_RT
        rx_ready = status & NRF24.RX_DR
        return {'tx_ok': tx_ok, "tx_fail": tx_fail, "rx_ready": rx_ready}

    def openWritingPipe(self, value):
        # Note that the NRF24L01(+)
        # expects it LSB first.

        self.write_register(NRF24.RX_ADDR_P0, value)
        self.write_register(NRF24.TX_ADDR, value)
        if not self.dynamic_payloads_enabled:
            self.write_register(NRF24.RX_PW_P0, self.payload_size)

    def openReadingPipe(self, pipe, address):
        # If this is pipe 0, cache the address.  This is needed because
        # openWritingPipe() will overwrite the pipe 0 address, so
        # startListening() will have to restore it.
        if pipe >= 6:
            raise RuntimeError("Invalid pipe number")
        if (pipe >= 2 and len(address) > 1) or len(address) > 5:
            raise RuntimeError("Invalid adress length")

        if pipe == 0:
            self.pipe0_reading_address = address

        self.write_register(NRF24.RX_ADDR_P0 + pipe, address)
        if not self.dynamic_payloads_enabled:
            self.write_register(NRF24.RX_PW_P0 + pipe, self.payload_size)

        # Note it would be more efficient to set all of the bits for all open
        # pipes at once.  However, I thought it would make the calling code
        # more simple to do it this way.
        self.write_register(NRF24.EN_RXADDR,
                            self.read_register(NRF24.EN_RXADDR) | (1 << pipe))

    def closeReadingPipe(self, pipe):
        self.write_register(NRF24.EN_RXADDR,
                            self.read_register(NRF24.EN_RXADDR) & ~(1 << pipe))

    def toggle_features(self):
        buf = [NRF24.ACTIVATE, 0x73]
        self.spidev.xfer2(buf)

    def enableDynamicPayloads(self):
        # Enable dynamic payload throughout the system
        self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_DPL)

        # If it didn't work, the features are not enabled
        if not self.read_register(NRF24.FEATURE):
            # So enable them and try again
            self.toggle_features()
            self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_DPL)

        # Enable dynamic payload on all pipes

        # Not sure the use case of only having dynamic payload on certain
        # pipes, so the library does not support it.
        self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | 0b00111111)

        self.dynamic_payloads_enabled = True

    def enableAckPayload(self):
        # enable ack payload and dynamic payload features
        self.write_register(NRF24.FEATURE,
                            self.read_register(NRF24.FEATURE) | NRF24.EN_ACK_PAY | NRF24.EN_DPL)

        # If it didn't work, the features are not enabled
        if not self.read_register(NRF24.FEATURE):
            # So enable them and try again
            self.toggle_features()
            self.write_register(NRF24.FEATURE,
                                self.read_register(NRF24.FEATURE) | NRF24.EN_ACK_PAY | NRF24.EN_DPL)

        # Enable dynamic payload on pipes 0 & 1
        self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | NRF24.DPL_P1 | NRF24.DPL_P0)

    def writeAckPayload(self, pipe, buf, buf_len):
        txbuffer = [NRF24.W_ACK_PAYLOAD | (pipe & 0x7)]

        max_payload_size = 32
        data_len = min(buf_len, max_payload_size)
        txbuffer.extend(buf[0:data_len])

        self.spidev.xfer2(txbuffer)

    def isAckPayloadAvailable(self):
        result = self.ack_payload_available
        self.ack_payload_available = False
        return result

    def isPVariant(self):
        return self.p_variant

    def setAutoAck(self, enable):
        if enable:
            self.write_register(NRF24.EN_AA, 0x3F)
            self.auto_ack = 0x3f
            if self.crc_length == 0:
                self.setCRCLength(NRF24.CRC_8)  # Enhanced Shockburst requires at least 1 byte CRC
        else:
            self.auto_ack = 0
            self.write_register(NRF24.EN_AA, 0)

    def setAutoAckPipe(self, pipe, enable):
        if pipe <= 6:
            en_aa = self.read_register(NRF24.EN_AA)
            if enable:
                self.setCRCLength(NRF24.CRC_8)  # Enhanced Shockburst requires at least 1 byte CRC
                en_aa |= 1 << pipe
                self.auto_ack |= 1 << pipe
            else:
                en_aa &= ~1 << pipe
                self.auto_ack &= ~1 << pipe

            self.write_register(NRF24.EN_AA, en_aa)

    def setAddressWidth(self, width):
        if width >= 2 and width <= 5:
            self.write_register(NRF24.SETUP_AW, width - 2)
            self.address_width = width

    def testCarrier(self):
        return self.read_register(NRF24.RPD) & 1

    def setPALevel(self, level):
        setup = self.read_register(NRF24.RF_SETUP)
        setup &= ~(NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH)

        if level == NRF24.PA_MAX:
            setup |= NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH
        elif level == NRF24.PA_HIGH:
            setup |= NRF24.RF_PWR_HIGH
        elif level == NRF24.PA_LOW:
            setup |= NRF24.RF_PWR_LOW
        elif level == NRF24.PA_MIN:
            pass
        elif level == NRF24.PA_ERROR:
            # On error, go to maximum PA
            setup |= NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH

        self.write_register(NRF24.RF_SETUP, setup)

    def getPALevel(self):
        power = self.read_register(NRF24.RF_SETUP) & (NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH)
        if power == (NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH):
            return NRF24.PA_MAX
        elif power == NRF24.RF_PWR_HIGH:
            return NRF24.PA_HIGH
        elif power == NRF24.RF_PWR_LOW:
            return NRF24.PA_LOW
        else:
            return NRF24.PA_MIN

    def setDataRate(self, speed):
        setup = self.read_register(NRF24.RF_SETUP)
        setup &= ~(NRF24.RF_DR_LOW | NRF24.RF_DR_HIGH)

        if speed == NRF24.BR_250KBPS:
            # Must set the RF_DR_LOW to 1 RF_DR_HIGH (used to be RF_DR) is already 0
            # Making it '10'.
            self.data_rate_bits = 250
            self.data_rate = NRF24.BR_250KBPS
            setup |= NRF24.RF_DR_LOW
        elif speed == NRF24.BR_2MBPS:
            # Set 2Mbs, RF_DR (RF_DR_HIGH) is set 1
            # Making it '01'
            self.data_rate_bits = 2000
            self.data_rate = NRF24.BR_2MBPS
            setup |= NRF24.RF_DR_HIGH
        else:
            # 1Mbs
            self.data_rate_bits = 1000
            self.data_rate = NRF24.BR_1MBPS

        self.write_register(NRF24.RF_SETUP, setup)

        # Verify our result
        return self.read_register(NRF24.RF_SETUP) == setup

    def getDataRate(self):
        dr = self.read_register(NRF24.RF_SETUP) & (NRF24.RF_DR_LOW | NRF24.RF_DR_HIGH)
        # Order matters in our case below
        if dr == NRF24.RF_DR_LOW:
            # '10' = 250KBPS
            return NRF24.BR_250KBPS
        elif dr == NRF24.RF_DR_HIGH:
            # '01' = 2MBPS
            return NRF24.BR_2MBPS
        else:
            # '00' = 1MBPS
            return NRF24.BR_1MBPS

    def setCRCLength(self, length):
        config = self.read_register(NRF24.CONFIG) & ~(NRF24.EN_CRC | NRF24.CRCO)

        if length == NRF24.CRC_DISABLED:
            self.crc_length = 0
        elif length == NRF24.CRC_8:
            config |= NRF24.EN_CRC
            config &= ~NRF24.CRCO
            self.crc_length = 1
        else:
            config |= NRF24.EN_CRC
            config |= NRF24.CRCO
            self.crc_length = 2

        self.write_register(NRF24.CONFIG, config)

    def getCRCLength(self):
        result = NRF24.CRC_DISABLED
        config = self.read_register(NRF24.CONFIG) & (NRF24.CRCO | NRF24.EN_CRC)

        if config & NRF24.EN_CRC:
            if config & NRF24.CRCO:
                result = NRF24.CRC_16
            else:
                result = NRF24.CRC_8

        return result

    def disableCRC(self):
        disable = self.read_register(NRF24.CONFIG) & ~NRF24.EN_CRC
        self.write_register(NRF24.CONFIG, disable)

    def setRetries(self, delay, count):
        self.write_register(NRF24.SETUP_RETR, (delay & 0xf) << NRF24.ARD | (count & 0xf) << NRF24.ARC)
        self.delay = delay * 0.000250
        self.retries = count
        self.max_timeout = (self.payload_size / float(self.data_rate_bits) + self.delay) * self.retries
        self.timeout = (self.payload_size / float(self.data_rate_bits) + self.delay)

    def getRetries(self):
        return self.read_register(NRF24.SETUP_RETR)

    def getMaxTimeout(self):
        return self.max_timeout

    def getTimeout(self):
        return self.timeout

    def reset(self):
        """ Make sure the NRF is in the same state as after power up
            to avoid problems resulting from left over configuration
            from other programs."""
        self.ce(0)
        reset_values = {0: 0x08, 1: 0x3F, 2: 0x02, 3: 0x03, 4: 0x03, 5: 0x02, 6: 0x06,
                        0x0a: [0xe7, 0xe7, 0xe7, 0xe7, 0xe7],
                        0x0b: [0xc2, 0xc2, 0xc2, 0xc2, 0xc2],
                        0x0c: 0xc3, 0x0d: 0xc4, 0x0e: 0xc5, 0x0f: 0xc6,
                        0x10: [0xe7, 0xe7, 0xe7, 0xe7, 0xe7],
                        0x11: 0, 0x12: 0, 0x13: 0, 0x14: 0, 0x15: 0, 0x16: 0,
                        0x1c: 0, 0x1d: 0}
        for reg, value in reset_values.items():
            self.write_register(reg, value)

        self.flush_rx()
        self.flush_tx()
Exemple #12
0
class RFM69HCW():
    def __init__(self,
                 LED_STATE=default_LED_STATE,
                 Fxosc=default_Fxosc,
                 Fstep=default_Fstep,
                 callsign=None,
                 node_id=default_node_id,
                 network_id=default_network_id,
                 carrier_freq=default_carrier_freq,
                 carrier_dev=default_carrier_dev,
                 carrier_bitrate=default_bitrate):
        self._mode = OPMODE_SLEEP
        self.LED_STATE = LED_STATE
        self.Fxosc = Fxosc
        self.Fstep = Fstep
        self.callsign = callsign
        self.RFM_SPI = SPI(0, 0)
        self.RFM_SPI.msh = 5000000
        self.carrier_freq = carrier_freq
        self.carrier_dev = carrier_dev
        self.bitrate = carrier_bitrate
        self.node_id = node_id
        self.network_id = network_id

        if self.callsign is None:
            raise NoCallSign("FCC Callsign not defined")
        self.ord_callsign = map(ord, list(self.callsign))
        self._io_setup()
        GPIO.output(BLUE_LEDPIN, GPIO.LOW)
        self.reset_radio()
        return

    def _io_setup(self):
        GPIO.setup(BLUE_LEDPIN, GPIO.OUT)
        GPIO.setup(MODULE_EN, GPIO.OUT)
        GPIO.setup(MODULE_RST, GPIO.OUT)
        GPIO.setup(G0_PIN, GPIO.IN)
        GPIO.setup(G1_PIN, GPIO.OUT)
        GPIO.setup(G2_PIN, GPIO.OUT)
        # GPIO.add_event_detect(G0_PIN, GPIO.FALLING, callback=g0int)
        GPIO.add_event_detect(G0_PIN, GPIO.RISING, callback=g0int)

    def _check_register(self, addr, value):
        vals = self.RFM_SPI.xfer2([addr, 0x0])
        if vals[1] != value:
            str = "addr: " + hex(addr) + "(" + inv_sx1231_reg[
                addr] + ")" + " should be: " + hex(value) + " got: " + hex(
                    vals[1])
            raise CheckError(str)
        print "Reg{", hex(addr), "}(", inv_sx1231_reg[addr], ")\t\t=", hex(
            vals[1])

    def write_register(self, reg, val, checkit=False):
        addr = reg
        reg = reg | 0x80
        # print "reg is: ", bin(reg)
        # print "val is: " , bin(val)
        # RFM_SPI.writebytes([reg, val])
        self.RFM_SPI.xfer2([reg, val])
        if checkit == True:
            self._check_register(addr, val)
        return

    def read_register(self, reg):
        regval = self.RFM_SPI.xfer2([reg, 0x0])
        return regval[1]

    def reset_radio(self):
        #self.blue_blink(2)
        GPIO.output(MODULE_EN, GPIO.HIGH)
        GPIO.output(MODULE_RST, GPIO.LOW)
        time.sleep(0.5)
        GPIO.output(MODULE_RST, GPIO.HIGH)
        time.sleep(0.5)
        GPIO.output(MODULE_RST, GPIO.LOW)
        time.sleep(0.5)

    def blue_invert(self):
        if (self.LED_STATE) == True:
            self.blue_off()
        else:
            self.blue_on()

    def blue_off(self):
        self.LED_STATE = False
        GPIO.output(BLUE_LEDPIN, GPIO.HIGH)
        return

    def blue_on(self):
        self.LED_STATE = True
        GPIO.output(BLUE_LEDPIN, GPIO.LOW)
        return

    def blue_blink(self, n=3):
        for num in range(0, n * 2):
            self.blue_invert()
            time.sleep(0.25)
        return

    def report_setup(self):
        print 'LED_STATE is:\t', self.LED_STATE
        print 'Fxosc is:    \t', self.Fxosc
        print 'Fstep is:    \t', self.Fstep
        print 'Callsign is: \t', self.callsign
        return

    # Facts:
    #   Fxosc = 32Mhz
    #   Fstep = 32e6/2^9  =  61.03515625
    #   Frf   = int(carrier_hz/Fstep)
    def write_carrier_freq(self, carrier_hz=436500000):
        frf = int(carrier_hz / self.Fstep)

        # vals = RFM_SPI.xfer2([RegFrfMsb, 0x0, 0x0, 0x0])
        # print "Pre: vals=\t", hex(vals[0]), "\t", hex(vals[1]), "\t", hex(vals[2]), "\t", hex(vals[3])

        frfmsb = (frf >> 16) & 0xff
        frfmid = (frf >> 8) & 0xff
        frflsb = frf & 0xff

        wbuf = [(sx1231_reg["RegFrfMsb"] | 0x80),
                int(frfmsb),
                int(frfmid),
                int(frflsb)]
        self.RFM_SPI.writebytes(wbuf)

        vals = self.RFM_SPI.xfer2([sx1231_reg["RegFrfMsb"], 0x0, 0x0, 0x0])
        # print "Post: vals=\t", hex(vals[0]), "\t", hex(vals[1]), "\t", hex(vals[2]), "\t", hex(vals[3])
        return

    def set_freq_deviation(self, freq_dev_hz=20000):
        freqdev = int(freq_dev_hz / self.Fstep)

        wbuf = [(sx1231_reg["RegFdevMsb"] | 0x80), (int(freqdev >> 8) & 0x3f),
                int(freqdev & 0xff)]
        self.RFM_SPI.writebytes(wbuf)
        # print "fdev_msb:\t",
        # check_register(sx1231_reg["RegFdevMsb"], (int(freqdev>>8) & 0x3f))
        # print "\nfdev_lsb:\t",
        # check_register(sx1231_reg["RegFdevLsb"], (int(freqdev & 0xff)))
        # print "\n"
        return

    def set_bitrate(self, bitrate_hz=1200):
        rate = int(self.Fxosc / bitrate_hz)

        wbuf = [(sx1231_reg["RegBitrateMsb"] | 0x80), (int(rate >> 8) & 0xff),
                int(rate & 0xff)]
        self.RFM_SPI.writebytes(wbuf)

    def set_sync_value(fourbytelist):
        wbuf = [(sx1231_reg["RegSyncValue1"] | 0x80)] + fourbytelist
        self.RFM_SPI.writebytes(wbuf)

    def set_preamble(twobytelist):
        wbuf = [(sx1231_reg["RegPreambleMsb"] | 0x80)] + twobytelist
        self.RFM_SPI.writebytes(wbuf)

    """
    Experiment with automodes 
    """

    def config_packet(self, pa, node_id=0x33, network_id=0x77):
        # Begin with sequencer on, listen off, and in standby
        self.write_register(sx1231_reg["RegOpMode"],
                            OPMODE_SEQUENCER_ON | OPMODE_LISTEN_OFF, True)
        self.set_mode(OPMODE_STANDBY)

        # Automodes - Finish Emptying fifo while in STBY
        self.write_register(
            sx1231_reg["RegAutoModes"], AUTOMODE_ENTER_CRC_OK
            | AUTOMODE_EXIT_FIFO_NOT_EMPTY | AUTOMODE_INTERM_STDBY, True)

        # Packet Mode, FSK, No Shaping
        self.write_register(
            sx1231_reg["RegDataModul"],
            DATAMODUL_Packet | DATAMODUL_FSK | DATAMODUL_NoShaping)

        self.write_carrier_freq(self.carrier_freq)
        self.set_freq_deviation(self.carrier_dev)
        self.set_bitrate(self.bitrate)

        # PA Output Power
        self.write_register(sx1231_reg["RegPaLevel"], PAOutputCfg(
            PA0, 0x1F))  # keep at PA0 until end of initialize

        # DIO Mappings
        g0_flag = False
        g1_flag = False
        g2_flag = False
        g3_flag = False
        g4_flag = False
        g5_flag = False
        #  (DccFreq|RxBwMant|RxBwExp) Table 13
        self.write_register(sx1231_reg["RegRxBw"],
                            (010 << 5 | 0x10 << 3 | 100 << 0))  # 20.8kHz?

        # DIO_0 initialize to PAYLOAD ready in RX
        self.write_register(
            sx1231_reg["RegDioMapping1"],
            ((self.read_register(sx1231_reg["RegDioMapping1"]) &
              (~(0b11 << DIO_0_POS))) | DIO0_PAYLOADREADY << DIO_0_POS), True)
        # DIO_1 is RX TIMEOUT
        self.write_register(
            sx1231_reg["RegDioMapping1"],
            ((self.read_register(sx1231_reg["RegDioMapping1"]) &
              (~(0b11 << DIO_1_POS))) | DIO1_RX_TIMEOUT << DIO_1_POS), True)

        # DIO_4 is Clkout
        self.write_register(sx1231_reg["RegDioMapping2"],
                            (DIO4_RXRDY << DIO_4_POS | DIO_CLK_DIV32), True)

        # Clear IRQFLAG and reset FIFO
        self.write_register(sx1231_reg["RegIrqFlags2"], IRQFLAGS2_FIFOOVERRUN)

        # RSSI Thresh
        self.write_register(sx1231_reg["RegRssiThresh"], 0xdc,
                            True)  # -220/2 = -110dBm?

        # Preamble length (0xaa..N)
        self.write_register(sx1231_reg["RegPreambleLsb"], 0xf, True)

        # Sync Config
        self.write_register(
            sx1231_reg["RegSyncConfig"],
            SYNCCFG_SYNC_ON | SYNCCFG_FILL_FIFO_INTR | SYNCCFG_SIZE_2, True)

        # Sync Word
        self.write_register(sx1231_reg["RegSyncValue1"], node_id, True)
        self.write_register(sx1231_reg["RegSyncValue2"], network_id, True)

        # Packet config 1
        self.write_register(
            sx1231_reg["RegPacketConfig1"], PACKET1_FORMAT_FIXED
            | PACKET1_DCFREE_NONE
            | PACKET1_CRC_ON
            | PACKET1_CRCAUTOCLEAR_ON
            | PACKET1_ADDRESS_FILTERING_BOTH, True)

        # Payload Length
        self.write_register(sx1231_reg["RegPayloadLength"],
                            default_Payload_bytes, True)

        # Node address:
        self.write_register(sx1231_reg["RegNodeAdrs"], self.node_id, True)
        self.write_register(sx1231_reg["RegBroadcastAdrs"], self.node_id + 1,
                            True)

        # Fifothresh? Only for TX
        self.write_register(sx1231_reg["RegFifoThresh"],
                            FIFOTHRESH_NOT_EMPTY | FIFOTHRESH_THRESHOLD_15,
                            True)

        # Packet config 2
        self.write_register(sx1231_reg["RegPacketConfig2"],
                            PACKET2_AUTORX_RESTART_ON, True)

        # Magic numbers
        self.write_register(
            sx1231_reg["RegPaRamp"], 0b0011, True
        )  # 500uS   close to 1/2400 bps ... see PacketConfig2 InterPacketRxDelay Must match the tx PA Ramp-down time
        # self.write_register(sx1231_reg["RegAfcCtrl"],0x40 | (0b1<<5) , True ) # AfcLowBetaOn  - Manual misprint....bits 7-6 read as 0b01  not 0b00
        self.write_register(
            sx1231_reg["RegAfcCtrl"], (0b1 << 5), True
        )  # AfcLowBetaOn  - Manual misprint....bits 7-6 read as 0b01  not 0b00
        self.write_register(sx1231_reg["RegTestDagc"], 0x20,
                            True)  # page 74 for AfcLowBetaOn=1
        self.write_register(sx1231_reg["RegPaLevel"], pa)
        return

    def set_mode(self, mode):
        if (mode == self._mode):
            return

        if (mode == OPMODE_SLEEP):
            self.write_register(
                sx1231_reg["RegDioMapping1"],
                ((self.read_register(sx1231_reg["RegDioMapping1"]) &
                  (~(0b11 << DIO_0_POS))) | DIO0_PAYLOADREADY << DIO_0_POS))
            self.write_register(
                sx1231_reg["RegOpMode"],
                (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3)
                | OPMODE_SLEEP)
            self._mode = OPMODE_SLEEP
        elif (mode == OPMODE_STANDBY):
            self.write_register(
                sx1231_reg["RegDioMapping1"],
                ((self.read_register(sx1231_reg["RegDioMapping1"]) &
                  (~(0b11 << DIO_0_POS))) | DIO0_PAYLOADREADY << DIO_0_POS))
            self.write_register(
                sx1231_reg["RegOpMode"],
                (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3)
                | OPMODE_STANDBY)
            self._mode = OPMODE_STANDBY
        elif (mode == OPMODE_FS_SYNTH):
            self.write_register(
                sx1231_reg["RegOpMode"],
                (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3)
                | OPMODE_FS_SYNTH)
            self._mode = OPMODE_FS_SYNTH
        elif (mode == OPMODE_TX):
            self.write_register(
                sx1231_reg["RegDioMapping1"],
                ((self.read_register(sx1231_reg["RegDioMapping1"]) &
                  (~(0b11 << DIO_0_POS))) | DIO0_PACKETSENT << DIO_0_POS))
            self.write_register(
                sx1231_reg["RegOpMode"],
                (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3)
                | OPMODE_TX)
            self._mode = OPMODE_TX
        elif (mode == OPMODE_RX):
            self.write_register(
                sx1231_reg["RegDioMapping1"],
                ((self.read_register(sx1231_reg["RegDioMapping1"]) &
                  (~(0b11 << DIO_0_POS))) | DIO0_PAYLOADREADY << DIO_0_POS))
            self.write_register(
                sx1231_reg["RegOpMode"],
                (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3)
                | OPMODE_RX)
            self._mode = OPMODE_RX
        else:
            raise ValueError('Unrecognized Mode')

        while ((self.read_register(sx1231_reg["RegIrqFlags1"])
                & IRQFLAGS1_MODEREADY) == 0x00):
            pass
        return

    def RSSI(self):
        # write trigger
        self.write_register(sx1231_reg["RegRssiConfig"], 0b1)
        while ((self.read_register(sx1231_reg["RegRssiConfig"])
                & RSSI_DONE) == 0x0):
            pass
        rssival = -self.read_register(sx1231_reg["RegRssiValue"])
        rssival = rssival / 2
        return rssival

    # call when g0flag goes true
    def read_fifo(self):
        global g0_flag
        self.standby()
        fifolist = self.RFM_SPI.readbytes(default_Payload_bytes + 1)

        #debugging
        # value = True
        # while value:
        # print "* ";
        # value = self.read_register(sx1231_reg["RegIrqFlags2"]) & IRQFLAGS2_PAYLOADREADY
        # garbage=self.RFM_SPI.readbytes(default_Payload_bytes+1)

        value = self.read_register(
            sx1231_reg["RegIrqFlags2"]) & IRQFLAGS2_PAYLOADREADY
        if value == 0:
            g0_flag = False
        return fifolist

    def standby(self):
        self.set_mode(OPMODE_STANDBY)
        return

    def receive(self):
        self.set_mode(OPMODE_RX)

        g0_flag = False
        return

    def send(self, bytelist):
        self.set_mode(OPMODE_STANDBY)
        if len(bytelist) > MAX_PACKET_LEN:
            raise ValueError('Max Packet Len Exceeded')

        #bytelist  = [self.node_id+1]+[self.node_id] + bytelist
        # bytelist  = [self.node_id] + [self.node_id+1] + bytelist
        # bytelist  = [self.node_id] + bytelist
        bytelist = [self.node_id] + bytelist
        print "\tbytelist: ", bytelist
        wbuf = [(sx1231_reg["RegFifo"] | 0x80)] + bytelist

        self.RFM_SPI.writebytes(wbuf)
        start_time = time.time()
        self.set_mode(OPMODE_TX)

        # Read pin or register...
        # value = GPIO.input(G0_PIN)
        value = self.read_register(
            sx1231_reg["RegIrqFlags2"]) & IRQFLAGS2_PACKETSENT
        #print "Start send:\t", start_time
        while value == 0:
            # value = GPIO.input(G0_PIN)
            value = self.read_register(
                sx1231_reg["RegIrqFlags2"]) & IRQFLAGS2_PACKETSENT
            elapsed_time = time.time() - start_time
            if (elapsed_time > 10):
                break

        #print "Stop send:\t", elapsed_time
        self.set_mode(OPMODE_STANDBY)
        return

    def stop(self):
        return
			print("%s, 1, %d") % (address, rssi)
		if value[28] == 129:
			print("%s, 2, %d") % (address, rssi)
		if value[28] == 130:
			print("%s, 3, %d") % (address, rssi)
		if value[28] == 131:
			print("%s, 4, %d") % (address, rssi)


bt = SPI(0, 0)
bt.mode = 1
bt.msh = 1000000

k=0
while k<100:
        bt.xfer2([ 0x00, 0x00, 0xFE, 0x07, 0x01, 0x04, 0xFE, 0x03,
        0x03, 0x00, 0x00, 0xFC])
        i=0;
	while i<35:
                if GPIO.input("P9_15") != 1:
                        value = bt.readbytes(12)
                        if value[1] == 0xFE and value[6] == 127 and value[7] == 6:
                                print("scanner started")
				i=50
                                k=100
                time.sleep(0.001)
                i = i + 1
	k = k +1


end_cond = 1
while end_cond:
from Adafruit_BBIO.SPI import SPI 

spi = SPI(1,0) 
spi.mode=2 

spi.msh=2000000 
spi.open(1,0) 

print spi.xfer2([32, 11, 110, 22, 220]) 
spi.close() 
Exemple #15
0
bt.mode = 1
bt.msh = 1000000

#reset the module

GPIO.output("P9_12", GPIO.LOW)
time.sleep(0.1)
GPIO.output("P9_12", GPIO.HIGH)

# initialize bt module
k = 0
while k < 100:
    #print("Sending init message")
    bt.xfer2([
        0x00, 0xFE, 0x2A, 0x01, 0x00, 0xFE, 0x26, 0x02, 0x0A, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFA
    ])
    i = 0
    while i < 30:
        if GPIO.input("P9_15") != 1:
            value = bt.readbytes(12)
            if value[1] == 0xFE and value[6] == 0 and value[7] == 6:
                #print("Init Success")
                #print(value)
                i = 50
                k = 100
        time.sleep(0.001)
        i = i + 1
    k = k + 1
k = 0
Exemple #16
0
class Enrf24():
    __bus = None
    __device = None

    __rf_status = 0
    __rf_addr_width = 5
    __lastirq = None
    __readpending = 0
    __lastTXfailed = False
    __txbuf_len = 0
    __txbuf = []

    # Internal IRQ handling
    __ENRF24_IRQ_TX = 0x20
    __ENRF24_IRQ_RX = 0x40
    __ENRF24_IRQ_TXFAILED = 0x10
    __ENRF24_IRQ_MASK = 0x70

    __ENRF24_CFGMASK_IRQ = 0

    def __init__(self, bus, device, cePin, csnPin, irqPin):
        self.__bus = bus
        self.__device = device
        self.cePin = cePin
        self.csnPin = csnPin
        self.irqPin = irqPin
        self.spi = SPI(self.__bus, self.__device)
        self.spi.msh = 10000
        self.spi.bpw = 8  # bits/word
        self.spi.threewire = False
        self.spi.lsbfirst = False
        self.spi.mode = 0
        self.spi.cshigh = False
        self.spi.open(0, 0)
        self.last_payload = ""

    def begin(self, datarate=1000000, channel=0):  # Specify bitrate & channel
        GPIO.setup(self.cePin, GPIO.OUT)
        GPIO.output(self.cePin, GPIO.LOW)
        GPIO.setup(self.csnPin, GPIO.OUT)
        GPIO.output(self.csnPin, GPIO.HIGH)
        GPIO.setup(self.irqPin,
                   GPIO.IN)  # No pullups; the transceiver provides this!
        self.spi.writebytes([0x00
                             ])  # Strawman transfer, fixes USCI issue on G2553
        #self.spi.writebytes([0xCF, 0x00])

        # Is the transceiver present/alive?
        if (not self.__isAlive()):
            return False  # Nothing more to do here...

        # Wait 100ms for module to initialize
        time.sleep(0.1)

        # Init certain registers
        self.__writeReg(RF24_CONFIG,
                        0x00)  # Deep power-down, everything disabled
        self.__writeReg(RF24_EN_AA, 0x03)
        self.__writeReg(RF24_EN_RXADDR, 0x03)
        self.__writeReg(RF24_RF_SETUP, 0x00)
        self.__writeReg(RF24_STATUS, self.__ENRF24_IRQ_MASK)  # Clear all IRQs
        self.__writeReg(RF24_DYNPD, 0x03)
        self.__writeReg(RF24_FEATURE,
                        RF24_EN_DPL)  # Dynamic payloads enabled by default

        # Set all parameters
        if (channel > 125):
            channel = 125

        self.deepsleep()
        self.__issueCmd(RF24_FLUSH_TX)
        self.__issueCmd(RF24_FLUSH_RX)
        self.__readpending = 0
        self.__irq_clear(self.__ENRF24_IRQ_MASK)
        self.setChannel(channel)
        self.setSpeed(datarate)
        self.setTXpower()
        self.setAutoAckParams()
        self.setAddressLength(self.__rf_addr_width)
        self.setCRC(True)  # Default = CRC on, 8-bit
        return True

    def end(self):  # Shut it off, clear the library's state
        self.__txbuf_len = 0
        self.__rf_status = 0
        self.__rf_addr_width = 5

        if (not self.__isAlive()):
            return

        self.deepsleep()
        self.__issueCmd(RF24_FLUSH_TX)
        self.__issueCmd(RF24_FLUSH_RX)
        self.readpending = 0
        self.__irq_clear(self.__ENRF24_IRQ_MASK)
        GPIO.output(self.cePin, GPIO.LOW)
        GPIO.output(self.csnPin, GPIO.HIGH)

    # I/O
    def available(
            self,
            checkIrq=False):  # Check if incoming data is ready to be read
        #print(checkIrq and GPIO.input(self.irqPin) and self.__readpending == 0)
        if (checkIrq and GPIO.input(self.irqPin) and self.__readpending == 0):
            return False
        self.__maintenanceHook()
        if ((not self.__readReg(RF24_FIFO_STATUS)) & RF24_RX_EMPTY):
            return True

        if (self.__readpending):
            return True

        return False

    def read(self, maxlen=32):  # Read contents of RX buffer up to
        buf = None
        plwidth = 0
        res = ""

        self.__maintenanceHook()
        self.__readpending = 0
        if ((self.__readReg(RF24_FIFO_STATUS) & RF24_RX_EMPTY) or maxlen < 1):
            return 0

        plwidth = self.__readCmdPayload(RF24_R_RX_PL_WID, plwidth, 1, 1)[0]
        buf = self.__readCmdPayload(RF24_R_RX_PAYLOAD, buf, plwidth, maxlen)
        if (self.__irq_derivereason() and self.__ENRF24_IRQ_RX):
            self.__irq_clear(self.__ENRF24_IRQ_RX)

        for i in buf:
            res += chr(i)

        self.last_payload = res
        return res  # 'maxlen' bytes, return final length.
        # 'inbuf' should be maxlen+1 since a
        # null '\0' is tacked onto the end.

    def getMessage(self):
        return self.last_payload

    def write(self, data):
        if (self.__txbuf_len == 32
            ):  # If we're trying to stuff an already-full buffer...
            self.flush()  # Blocking OTA TX

        txbuf = []
        data = list(data)
        for i in data:
            txbuf.append(ord(i))
        self.__txbuf = txbuf
        self.__txbuf_len = len(txbuf)

        return 1

    def flush(self):  # Force transmission of TX ring buffer contents
        reg = None
        addrbuf = []
        enaa = False
        origrx = False

        if (self.__txbuf_len == 0):
            return  # Zero-length buffer?  Nothing to send!

        reg = self.__readReg(RF24_FIFO_STATUS)
        if (
                reg & BITS["BIT5"]
        ):  # RF24_TX_FULL #define is BIT0, which is not the correct bit for FIFO_STATUS.
            # Seen this before with a user whose CE pin was messed up.
            self.__issueCmd(RF24_FLUSH_TX)
            self.__txbuf_len = 0
            return  # Should never happen, but nonetheless a precaution to take.

        self.__maintenanceHook()

        if (reg & RF24_TX_REUSE):
            # If somehow TX_REUSE is enabled, we need to flush the TX queue before loading our new payload.
            self.__issueCmd(RF24_FLUSH_TX)

        if (self.__readReg(RF24_EN_AA) & 0x01
                and (self.__readReg(RF24_RF_SETUP) & 0x28) != 0x20):
            # AutoACK enabled, must write TX addr to RX pipe#0
            # Note that 250Kbps doesn't support auto-ack, so we check RF24_RF_SETUP to verify that.
            enaa = True
            self.__readTXaddr(addrbuf)
            self.__writeRXaddrP0(addrbuf)

        reg = self.__readReg(RF24_CONFIG)
        if (not (reg & RF24_PWR_UP)):
            #digitalWrite(_cePin, HIGH);  // Workaround for SI24R1 knockoff chips
            self.__writeReg(
                RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ
                | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP)
            time.sleep(.05)  # 5ms delay required for nRF24 oscillator start-up
            #digitalWrite(_cePin, LOW);

        if (reg & RF24_PRIM_RX):
            origrx = True
            GPIO.output(self.cePin, GPIO.LOW)
            self.__writeReg(
                RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ
                | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP)

        self.__txbuf = self.__issueCmdPayload(RF24_W_TX_PAYLOAD, self.__txbuf)
        GPIO.output(self.cePin, GPIO.HIGH)
        time.sleep(0.1)
        GPIO.output(self.cePin, GPIO.LOW)

        self.__txbuf_len = 0  # Reset TX ring buffer

        while (GPIO.input(self.irqPin)):  # Wait until IRQ fires
            pass

        # IRQ fired
        self.__maintenanceHook()  # Handle/clear IRQ

        # Purge Pipe#0 address (set to module's power-up default)
        if (enaa):
            addrbuf = [0xE7, 0xE7, 0xE7, 0xE7, 0xE7]
            self.__writeRXaddrP0(addrbuf)

        # If we were in RX mode before writing, return back to RX mode.
        if (origrx):
            self.enableRX()

    def purge(
            self):  # Ignore TX ring buffer contents, return ring pointer to 0.
        self.__txbuf_len = 0

    # Power-state related stuff-
    def radioState(
        self
    ):  # Evaluate current state of the transceiver (see ENRF24_STATE_* defines)
        if not self.__isAlive():
            return ENRF24_STATE_NOTPRESENT

        counter = 15
        reg = self.__readReg(RF24_CONFIG)
        if reg == 0:
            while reg == 0 and counter < 15:
                reg = self.__readReg(RF24_CONFIG)
                counter += 1

        if (not (reg & RF24_PWR_UP)):
            return ENRF24_STATE_DEEPSLEEP

        # At this point it's either Standby-I, II or PRX.
        if (reg & RF24_PRIM_RX):
            if (GPIO.input(self.cePin)):
                return ENRF24_STATE_PRX
            # PRIM_RX=1 but CE=0 is a form of idle state.
            return ENRF24_STATE_IDLE

        # Check if TX queue is empty, if so it's idle, if not it's PTX.
        if (self.__readReg(RF24_FIFO_STATUS) & RF24_TX_EMPTY):
            return ENRF24_STATE_IDLE
        return ENRF24_STATE_PTX

    def printRadioState(self):
        status = self.radioState()
        sys.stdout.write("Enrf24 radio transceiver status: ")
        if status == ENRF24_STATE_NOTPRESENT:
            print("NO TRANSCEIVER PRESENT")

        elif status == ENRF24_STATE_DEEPSLEEP:
            print("DEEP SLEEP <1uA power consumption")

        elif status == ENRF24_STATE_IDLE:
            print("IDLE module powered up w/ oscillators running")

        elif status == ENRF24_STATE_PTX:
            print("Actively Transmitting")

        elif status == ENRF24_STATE_PRX:
            print("Receive Mode")

        else:
            print("UNKNOWN STATUS CODE")

    def printStatus(self):
        status = self.__readReg(RF24_STATUS)
        data_ready = str(hex(status & 0x40))
        data_sent = str(hex(status & 0x20))
        max_tx_retries = str(hex(status & 0x10))

        if status & 0x0E == 0x0E:
            rx_pipe_no = "RX FIFO Empty"
        elif status & 0x02 == 0x02:
            rx_pipe_no = 1
        elif status & 0x04 == 0x04:
            rx_pipe_no = 2
        elif status & 0x06 == 0x06:
            rx_pipe_no = 3
        elif status & 0x08 == 0x08:
            rx_pipe_no = 4
        elif status & 0x0A == 0x0A:
            rx_pipe_no = 5
        elif ~status & 0x0E:
            rx_pipe_no = 0
        else:
            rx_pipe_no = "Error"

        rx_pipe_no = str(rx_pipe_no)
        tx_fifo_full = str(status & 0x01)

        status = str(hex(status))

        sys.stdout.write("STATUS=")
        sys.stdout.write(status)
        sys.stdout.write("\tRX_DR=")
        sys.stdout.write(data_ready)
        sys.stdout.write(" TX_DS=")
        sys.stdout.write(data_sent)
        sys.stdout.write(" MAX_RT=")
        sys.stdout.write(max_tx_retries)
        sys.stdout.write(" RX_P_NO=")
        sys.stdout.write(rx_pipe_no)
        sys.stdout.write(" TX_FULL=")
        print(tx_fifo_full)
        print("")

    def printDetails(self):
        self.printStatus()

        buf = []
        sys.stdout.write("RX_ADDR_P0=")
        buf = self.__readRegMultiLSB(RF24_RX_ADDR_P0, buf,
                                     self.__rf_addr_width)
        for i in buf:
            sys.stdout.write(hex(i) + " ")
        print("")
        sys.stdout.write("RX_ADDR_P1=")
        buf = self.__readRegMultiLSB(RF24_RX_ADDR_P1, buf,
                                     self.__rf_addr_width)
        for i in buf:
            sys.stdout.write(hex(i) + " ")
        print("")
        sys.stdout.write("RX_ADDR_P2=")
        buf = self.__readRegMultiLSB(RF24_RX_ADDR_P2, buf,
                                     self.__rf_addr_width)
        for i in buf:
            sys.stdout.write(hex(i) + " ")
        print("")
        sys.stdout.write("RX_ADDR_P3=")
        buf = self.__readRegMultiLSB(RF24_RX_ADDR_P3, buf,
                                     self.__rf_addr_width)
        for i in buf:
            sys.stdout.write(hex(i) + " ")
        print("")
        sys.stdout.write("RX_ADDR_P4=")
        buf = self.__readRegMultiLSB(RF24_RX_ADDR_P4, buf,
                                     self.__rf_addr_width)
        for i in buf:
            sys.stdout.write(hex(i) + " ")
        print("")
        sys.stdout.write("RX_ADDR_P5=")
        buf = self.__readRegMultiLSB(RF24_RX_ADDR_P5, buf,
                                     self.__rf_addr_width)
        for i in buf:
            sys.stdout.write(hex(i) + " ")
        print("")
        print("")

        sys.stdout.write("TX_ADDR=")
        buf = self.__readRegMultiLSB(RF24_TX_ADDR, buf, self.__rf_addr_width)
        for i in buf:
            sys.stdout.write(hex(i) + " ")
        print("")
        print("")

        sys.stdout.write("RX_PW_P0=")
        print(hex(self.__readReg(RF24_RX_PW_P0)))

        sys.stdout.write("RX_PW_P1=")
        print(hex(self.__readReg(RF24_RX_PW_P1)))

        sys.stdout.write("RX_PW_P2=")
        print(hex(self.__readReg(RF24_RX_PW_P2)))

        sys.stdout.write("RX_PW_P3=")
        print(hex(self.__readReg(RF24_RX_PW_P3)))

        sys.stdout.write("RX_PW_P4=")
        print(hex(self.__readReg(RF24_RX_PW_P4)))

        sys.stdout.write("RX_PW_P5=")
        print(hex(self.__readReg(RF24_RX_PW_P5)))
        print("")

        sys.stdout.write("EN_AA=")
        print(bin(self.__readReg(RF24_EN_AA)))

        sys.stdout.write("EN_RXADDR=")
        print(bin(self.__readReg(RF24_EN_RXADDR)))

        sys.stdout.write("RF_CH=")
        print(hex(self.__readReg(RF24_RF_CH)))

        sys.stdout.write("RF_SETUP=")
        print(bin(self.__readReg(RF24_RF_SETUP)))

        sys.stdout.write("CONFIG=")
        print(bin(self.__readReg(RF24_CONFIG)))

        sys.stdout.write("DYNPD=")
        print(bin(self.__readReg(RF24_DYNPD)))

        sys.stdout.write("FEATURE=")
        print(bin(self.__readReg(RF24_FEATURE)))
        print("")

        sys.stdout.write("Data Rate=")
        print(self.getSpeed())

        sys.stdout.write("CRC Length=")
        print(self.getCRC())

        sys.stdout.write("PA Power=")
        print(self.getTXpower())

    def deepsleep(self):  # Enter POWERDOWN mode, ~0.9uA power consumption
        reg = self.__readReg(RF24_CONFIG)
        if (reg & (RF24_PWR_UP | RF24_PRIM_RX)):
            self.__writeReg(
                RF24_CONFIG,
                self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg))

        GPIO.output(self.cePin, GPIO.LOW)

    def enableRX(self):  # Enter PRX mode (~14mA)
        reg = self.__readReg(RF24_CONFIG)
        self.__writeReg(
            RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ
            | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP | RF24_PRIM_RX)
        self.__writeReg(RF24_RX_PW_P0, 0x20)
        self.__writeReg(RF24_RX_PW_P1, 0x20)
        GPIO.output(self.cePin, GPIO.HIGH)

        if (
                not (reg & RF24_PWR_UP)
        ):  # Powering up from deep-sleep requires 5ms oscillator start delay
            time.sleep(0.05)

    def disableRX(self):  # Disable PRX mode (PRIM_RX bit in CONFIG register)
        # Note this won't necessarily push the transceiver into deep sleep, but rather
        # an idle standby mode where its internal oscillators are ready & running but
        # the RF transceiver PLL is disabled.  ~26uA power consumption.
        GPIO.output(self.cePin, GPIO.LOW)

        reg = self.__readReg(RF24_CONFIG)
        if (
                reg & RF24_PWR_UP
        ):  # Keep us in standby-I if we're coming from RX mode, otherwise stay
            # in deep-sleep if we call this while already in PWR_UP=0 mode.

            self.__writeReg(
                RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ
                | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP)
        else:
            self.__writeReg(
                RF24_CONFIG,
                self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg))

    # Custom tweaks to RF parameters, packet parameters
    def autoAck(self,
                onoff=True
                ):  # Enable/disable auto-acknowledgements (enabled by default)
        reg = self.__readReg(RF24_EN_AA)
        if (onoff):
            if (not (reg & 0x01) or not (reg & 0x02)):
                self.__writeReg(RF24_EN_AA, 0x03)

        else:
            if (reg & 0x03):
                self.__writeReg(RF24_EN_AA, 0x00)

    def setChannel(self, channel):
        if (channel > 125):
            channel = 125
        self.__writeReg(RF24_RF_CH, channel)

    def setTXpower(
            self,
            dBm=0
    ):  # Only a few values supported by this (0, -6, -12, -18 dBm)
        reg = self.__readReg(
            RF24_RF_SETUP) & 0xF8  # preserve RF speed settings
        pwr = 0x06
        if (dBm >= 7):
            pwr = 0x07
        if (dBm < 0):
            pwr = 0x04
        if (dBm < -6):
            pwr = 0x02
        if (dBm < -12):
            pwr = 0x00
        self.__writeReg(RF24_RF_SETUP, reg | pwr)

    def setSpeed(self, rfspeed):  # Set 250000, 1000000, 2000000 speeds.
        reg = self.__readReg(
            RF24_RF_SETUP) & 0xD7  # preserve RF power settings
        spd = 0x01
        if (rfspeed < 2000000):
            spd = 0x00
        if (rfspeed < 1000000):
            spd = 0x04
        self.__writeReg(RF24_RF_SETUP, reg | (spd << 3))

    def setCRC(self,
               onoff,
               crc16bit=False):  # Enable/disable CRC usage inside nRF24's
        # hardware packet engine, specify 8 or
        # 16-bit CRC.
        crcbits = 0

        reg = self.__readReg(
            RF24_CONFIG) & 0xF3  # preserve IRQ mask, PWR_UP/PRIM_RX settings
        if (onoff):
            crcbits |= RF24_EN_CRC
        if (crc16bit):
            crcbits |= RF24_CRCO
        self.__writeReg(RF24_CONFIG, (reg | crcbits))

    # Set AutoACK retry count, timeout params (0-15, 250-4000 respectively)
    def setAutoAckParams(self, autoretry_count=15, autoretry_timeout=2000):
        setup_retr = 0

        setup_retr = autoretry_count & 0x0F
        autoretry_timeout -= 250
        setup_retr |= ((autoretry_timeout / 250) & 0x0F) << 4
        self.__writeReg(RF24_SETUP_RETR, setup_retr)

    # Protocol addressing -- receive, transmit addresses
    def setAddressLength(self,
                         len):  # Valid parameters = 3, 4 or 5.  Defaults to 5.
        if (len < 3):
            len = 3
        if (len > 5):
            len = 5

        self.__writeReg(RF24_SETUP_AW, len - 2)
        self.__rf_addr_width = len

    def setRXaddress(self, rxaddr):  # 3-5 byte RX address loaded into pipe#1
        self.__writeRegMultiLSB(RF24_RX_ADDR_P1, rxaddr)

    def setTXaddress(
            self, txaddr):  # 3-5 byte TX address loaded into TXaddr register
        self.__writeRegMultiLSB(RF24_TX_ADDR, txaddr)

    # Miscellaneous feature
    def rfSignalDetected(
        self
    ):  # Read RPD register to determine if transceiver has presently detected an RF signal
        # of -64dBm or greater.  Only works in PRX (enableRX()) mode.
        rpd = self.__readReg(RF24_RPD)
        return rpd

    # Query current parameters
    def getChannel(self):
        return self.__readReg(RF24_RF_CH)

    def getSpeed(self):
        reg = self.__readReg(RF24_RF_SETUP) & 0x28

        if (reg == 0x00):
            return 1000000
        elif (reg == 0x08):
            return 2000000
        elif (reg == 0x20):
            return 250000
        else:
            return 0

    def getTXpower(self):
        reg = self.__readReg(RF24_RF_SETUP) & 0x07

        if (reg & 0x01):
            return 7  # SI24R1-only +7dBm mode
        elif (reg == 0x02):
            return -12
        elif (reg == 0x04):
            return -6
        elif (reg == 0x06):
            return 0
        else:
            return -18

    def getAddressLength(self):
        return self.__rf_addr_width

    def getRXaddress(self):
        buf = []
        buf = self.__readRegMultiLSB(RF24_RX_ADDR_P1, buf,
                                     self.__rf_addr_width)
        return buf

    def getTXaddress(self):
        buf = []
        buf = self.__readRegMultiLSB(RF24_TX_ADDR, buf, rf_addr_width)
        return buf

    def getAutoAck(self):
        reg = self.__readReg(RF24_EN_AA)

        if (reg):
            return True
        else:
            return False

    def getCRC(self):
        reg = self.__readReg(RF24_CONFIG) & 0x0C

        if (reg == 0x08):
            return 8
        elif (reg == 0x0C):
            return 16
        else:
            return 0

    def __readReg(self, addr):
        GPIO.output(self.csnPin, GPIO.LOW)
        result = self.spi.xfer2([(RF24_R_REGISTER | addr), RF24_NOP])
        self.__rf_status = result[0]
        GPIO.output(self.csnPin, GPIO.HIGH)
        return result[1]

    def __readRegMultiLSB(self, addr, buf, length):
        txbuf = [(RF24_R_REGISTER | addr)]
        for i in range(length):
            txbuf.append(RF24_NOP)
        GPIO.output(self.csnPin, GPIO.LOW)
        buf = self.spi.xfer2(txbuf)
        self.__rf_status = buf[0]
        status = []
        for i in range(1, len(buf) + 1):
            status.append(buf[-i])
        status.pop()
        GPIO.output(self.csnPin, GPIO.HIGH)
        return status

    def __writeReg(self, addr, val):
        GPIO.output(self.csnPin, GPIO.LOW)
        res = self.spi.xfer2([(RF24_W_REGISTER | addr), val])
        GPIO.output(self.csnPin, GPIO.HIGH)

    def __writeRegMultiLSB(self, addr, buf):
        txbuf = [(RF24_W_REGISTER | addr)]
        for i in range(1, len(buf) + 1):
            txbuf.append(buf[-i])
        GPIO.output(self.csnPin, GPIO.LOW)
        status = self.spi.xfer2(txbuf)
        GPIO.output(self.csnPin, GPIO.HIGH)

    def __issueCmd(self, cmd):
        GPIO.output(self.csnPin, GPIO.LOW)
        self.spi.writebytes([cmd])
        GPIO.output(self.csnPin, GPIO.HIGH)

    def __readCmdPayload(self, cmd, buf, length, maxlen):
        GPIO.output(self.csnPin, GPIO.LOW)
        messg = []
        txbuf = [cmd]
        for i in range(maxlen):
            txbuf.append(RF24_NOP)
        buf = self.spi.xfer2(
            txbuf)  # Beyond maxlen bytes, just discard the remaining data.
        self.__rf_status = buf[0]
        for i in range(1, length + 1):
            messg.append(buf[i])
        GPIO.output(self.csnPin, GPIO.HIGH)
        return messg

    def __issueCmdPayload(self, cmd, buf):
        payload = []
        payload.append(cmd)
        for i in buf:
            payload.append(i)
        GPIO.output(self.csnPin, GPIO.LOW)
        res = self.spi.xfer2(payload)
        GPIO.output(self.csnPin, GPIO.HIGH)

    def __irq_getreason(self):
        self.__lastirq = self.__readReg(RF24_STATUS) & self.__ENRF24_IRQ_MASK

    def __irq_derivereason(
            self
    ):  # Get IRQ status from rf_status w/o querying module over SPI.
        self.__lastirq = self.__rf_status & self.__ENRF24_IRQ_MASK

    def __irq_clear(self, irq):
        self.__writeReg(RF24_STATUS, (irq & self.__ENRF24_IRQ_MASK))

    def __isAlive(self):
        self.spi.writebytes([0x00])
        aw = self.__readReg(RF24_SETUP_AW)
        return ((aw & 0xFC) == 0x00 and (aw & 0x03) != 0x00)

    def __readTXaddr(self, buf):
        self.__readRegMultiLSB(RF24_TX_ADDR, buf, self.__rf_addr_width)

    def __writeRXaddrP0(self, buf):
        self.__writeRegMultiLSB(RF24_RX_ADDR_P0, buf)

    def __maintenanceHook(
        self
    ):  # Handles IRQs and purges RX queue when erroneous contents exist.
        i = 0

        self.__irq_getreason()

        if (self.__lastirq & self.__ENRF24_IRQ_TXFAILED):
            self.__lastTXfailed = True
            self.__issueCmd(RF24_FLUSH_TX)
            self.__irq_clear(self.__ENRF24_IRQ_TXFAILED)

        if (self.__lastirq & self.__ENRF24_IRQ_TX):
            self.__lastTXfailed = False
            self.__irq_clear(self.__ENRF24_IRQ_TX)

        if (self.__lastirq & self.__ENRF24_IRQ_RX):
            if ((not self.__readReg(RF24_FIFO_STATUS))
                    & RF24_RX_FULL):  # Don't feel it's necessary
                # to be notified of new
                # incoming packets if the RX
                # queue is full.
                self.__irq_clear(self.__ENRF24_IRQ_RX)

        # Check if RX payload is 0-byte or >32byte (erroneous conditions)
        # Also check if data was received on pipe#0, which we are ignoring.
        # The reason for this is pipe#0 is needed for receiving AutoACK acknowledgements,
        # its address gets reset to the module's default and we do not care about data
        # coming in to that address...

            i = self.__readCmdPayload(RF24_R_RX_PL_WID, i, 1, 1)[0]

            if (i == 0 or i > 32 or ((self.__rf_status & 0x0E) >> 1) == 0):
                # Zero-width RX payload is an error that happens a lot
                # with non-AutoAck, and must be cleared with FLUSH_RX.
                # Erroneous >32byte packets are a similar phenomenon.
                self.__issueCmd(RF24_FLUSH_RX)
                self.__irq_clear(self.__ENRF24_IRQ_RX)
                self.__readpending = 0
            else:
                self.__readpending = 1

            # Actual scavenging of RX queues is performed by user-directed use of read().

    def __ENRF24_CFGMASK_CRC(self, a):
        return (a & (RF24_EN_CRC | RF24_CRCO))
Exemple #17
0
class NRF24:
    MAX_CHANNEL = 127
    MAX_PAYLOAD_SIZE = 32

    # PA Levels
    PA_MIN = 0x00
    PA_LOW = 0x01
    PA_HIGH = 0x02
    PA_MAX = 0x03
    PA_ERROR = 0x04

    # Bit rates
    BR_1MBPS = 0
    BR_2MBPS = 1
    BR_250KBPS = 2

    # CRC
    CRC_DISABLED = 0x0
    CRC_8 = 0x02
    CRC_16 = 0x04
    CRC_ENABLED = 0x08

    EN_CRC = 0x08
    CRCO = 0x04

    # Registers
    CONFIG = 0x00
    EN_AA = 0x01
    EN_RXADDR = 0x02
    SETUP_AW = 0x03
    SETUP_RETR = 0x04
    RF_CH = 0x05
    RF_SETUP = 0x06
    STATUS = 0x07
    OBSERVE_TX = 0x08
    RPD = 0x09
    RX_ADDR_P0 = 0x0A
    RX_ADDR_P1 = 0x0B
    RX_ADDR_P2 = 0x0C
    RX_ADDR_P3 = 0x0D
    RX_ADDR_P4 = 0x0E
    RX_ADDR_P5 = 0x0F
    TX_ADDR = 0x10
    RX_PW_P0 = 0x11
    RX_PW_P1 = 0x12
    RX_PW_P2 = 0x13
    RX_PW_P3 = 0x14
    RX_PW_P4 = 0x15
    RX_PW_P5 = 0x16
    FIFO_STATUS = 0x17
    DYNPD = 0x1C
    FEATURE = 0x1D

    # Bit Mnemonics */
    MASK_RX_DR = 0x40
    MASK_TX_DS = 0x20
    MASK_MAX_RT = 0x10

    PWR_UP = 0x02
    PRIM_RX = 0x01
    PLL_LOCK = 0x10
    RX_DR = 0x40
    TX_DS = 0x20
    MAX_RT = 0x10
    TX_FULL = 0x01

    EN_DPL = 0x04
    EN_ACK_PAY = 0x02
    EN_DYN_ACK = 0x01

    # Shift counts
    ARD = 4
    ARC = 0
    PLOS_CNT = 4
    ARC_CNT = 0
    RX_P_NO = 1

    TX_REUSE = 6
    FIFO_FULL = 5
    TX_EMPTY = 4
    RX_FULL = 1
    RX_EMPTY = 0

    DPL_P5 = 5
    DPL_P4 = 4
    DPL_P3 = 3
    DPL_P2 = 2
    DPL_P1 = 1
    DPL_P0 = 0

    #Masks
    RX_P_NO_MASK = 0x0E

    # Instruction Mnemonics
    R_REGISTER = 0x00
    W_REGISTER = 0x20
    REGISTER_MASK = 0x1F
    ACTIVATE = 0x50
    R_RX_PL_WID = 0x60
    R_RX_PAYLOAD = 0x61
    W_TX_PAYLOAD = 0xA0
    W_ACK_PAYLOAD = 0xA8
    FLUSH_TX = 0xE1
    FLUSH_RX = 0xE2
    REUSE_TX_PL = 0xE3
    NOP = 0xFF

    # Non-P omissions
    LNA_HCURR = 0x01
    LNA_ON = 1
    LNA_OFF = 0

    # P model bit Mnemonics
    RF_DR_LOW = 0x20
    RF_DR_HIGH = 0x08
    RF_PWR_LOW = 0x02
    RF_PWR_HIGH = 0x04

    datarate_e_str_P = ["1MBPS", "2MBPS", "250KBPS"]
    model_e_str_P = ["nRF24L01", "nRF24l01+"]
    crclength_e_str_P = ["Disabled", "", "8 bits", "", "16 bits"]
    pa_dbm_e_str_P = ["PA_MIN", "PA_LOW", "PA_HIGH", "PA_MAX"]

    @staticmethod
    def print_single_status_line(name, value):
        print("{0:<16}= {1}".format(name, value))

    @staticmethod
    def _to_8b_list(data):
        """Convert an arbitray iteratable or single int to a list of ints
            where each int is smaller than 256."""
        if isinstance(data, str):
            data = [ord(x) for x in data]
        elif isinstance(data, (int, long)):
            data = [data]
        else:
            data = [int(x) for x in data]

        #for byte in data:
        #    if byte < 0 or byte > 255:
        #        raise RuntimeError("Value %d is larger than 8 bits" % byte)
        return data

    def __init__(self, major=None, minor=None, ce_pin=None, irq_pin=None):
        self.ce_pin = "P9_15"
        self.irq_pin = "P9_16"
        self.channel = 76
        self.data_rate = NRF24.BR_1MBPS
        self.data_rate_bits = 1000
        self.p_variant = False  # False for RF24L01 and true for RF24L01P
        self.payload_size = 5  # *< Fixed size of payloads
        self.ack_payload_available = False  # *< Whether there is an ack payload waiting
        self.dynamic_payloads_enabled = False  # *< Whether dynamic payloads are enabled.
        self.ack_payload_length = 5  # *< Dynamic size of pending ack payload.
        self.pipe0_reading_address = None  # *< Last address set on pipe 0 for reading.
        self.spidev = None
        self.last_error = 0
        self.crc_length = 0
        self.auto_ack = 0x3F
        self.address_length = 5

        # If all parameters are available, lets start the radio!
        if major is not None and minor is not None and irq_pin is not None:
            self.begin(major, minor, ce_pin, irq_pin)

    def begin(self, major, minor, ce_pin, irq_pin):
        # Initialize SPI bus

        if ADAFRUID_BBIO_SPI:
            self.spidev = SPI(major, minor)
            self.spidev.bpw = 8
            try:
                self.spidev.msh = 10000000  # Maximum supported by NRF24L01+
            except IOError:
                pass  # Hardware does not support this speed
        else:
            self.spidev = spidev.SpiDev()
            self.spidev.open(major, minor)

            self.spidev.bits_per_word = 8

            try:
                self.spidev.max_speed_hz = 10000000  # Maximum supported by NRF24L01+
            except IOError:
                pass  # Hardware does not support this speed

        self.spidev.cshigh = False
        self.spidev.mode = 0
        self.spidev.loop = False
        self.spidev.lsbfirst = False
        self.spidev.threewire = False

        self.ce_pin = ce_pin
        self.irq_pin = irq_pin

        if self.ce_pin is not None:
            GPIO.setup(self.ce_pin, GPIO.OUT)

        GPIO.setup(self.irq_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

        time.sleep(5 / 1000000.0)

        # Reset radio configuration
        self.reset()

        # Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier
        # WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet
        # sizes must never be used. See documentation for a more complete explanation.
        self.setRetries(int('0101', 2), 15)

        # Restore our default PA level
        self.setPALevel(NRF24.PA_MAX)

        # Determine if this is a p or non-p RF24 module and then
        # reset our data rate back to default value. This works
        # because a non-P variant won't allow the data rate to
        # be set to 250Kbps.
        if self.setDataRate(NRF24.BR_250KBPS):
            self.p_variant = True

        # Then set the data rate to the slowest (and most reliable) speed supported by all
        # hardware.
        self.setDataRate(NRF24.BR_1MBPS)

        # Initialize CRC and request 2-byte (16bit) CRC
        self.setCRCLength(NRF24.CRC_16)

        # Disable dynamic payloads, to match dynamic_payloads_enabled setting
        self.write_register(NRF24.DYNPD, 0)

        # Reset current status
        # Notice reset and flush is the last thing we do
        self.write_register(NRF24.STATUS,
                            NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT)

        # Set up default configuration.  Callers can always change it later.
        # This channel should be universally safe and not bleed over into adjacent
        # spectrum.
        self.setChannel(self.channel)

        self.setRetries(15, 15)

        # Flush buffers
        self.flush_rx()
        self.flush_tx()
        self.clear_irq_flags()

    def end(self):
        if self.spidev:
            self.spidev.close()
            self.spidev = None

    def startListening(self):
        self.write_register(
            NRF24.CONFIG,
            self.read_register(NRF24.CONFIG) | NRF24.PWR_UP | NRF24.PRIM_RX)
        self.write_register(NRF24.STATUS,
                            NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT)

        self.flush_tx()
        self.flush_rx()
        self.clear_irq_flags()

        # Restore the pipe0 address, if exists
        if self.pipe0_reading_address:
            self.write_register(self.RX_ADDR_P0, self.pipe0_reading_address)

        # Go!
        self.ce(1)

    def ce(self, level, pulse=0):
        # CE Pin is optional
        if self.ce_pin is not None:
            GPIO.output(self.ce_pin, level)
            if pulse > 0:
                time.sleep(pulse)
                GPIO.output(self.ce_pin, 1 - level)

    def irqWait(self, timeout=30000):
        # TODO: A race condition may occur here. => wait for level?
        if GPIO.input(
                self.irq_pin) == 0:  # Pin is already down. Packet is waiting?
            return True

        try:
            return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING, timeout) == 1
        except TypeError:  # Timeout parameter not supported
            return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING) == 1
        except AttributeError:
            raise RuntimeError("GPIO lib does not support wait_for_edge()")

    def read_register(self, reg, length=1):
        buf = [NRF24.R_REGISTER | (NRF24.REGISTER_MASK & reg)]
        buf += [NRF24.NOP] * max(1, length)

        resp = self.spidev.xfer2(buf)
        if length == 1:
            return resp[1]

        return resp[1:]

    def write_register(self, reg, value):
        """ Write register value """
        buf = [NRF24.W_REGISTER | (NRF24.REGISTER_MASK & reg)]
        buf += self._to_8b_list(value)
        self.spidev.xfer2(buf)

    def write_payload(self, buf):
        """ Writes data to the payload register, automatically padding it
            to match the required length. Returns the number of bytes
            actually written. """

        buf = self._to_8b_list(buf)
        if self.dynamic_payloads_enabled:
            if len(buf) > self.MAX_PAYLOAD_SIZE:
                raise RuntimeError("Dynamic payload is larger than the " +
                                   "maximum size.")
            blank_len = 0
        else:
            if len(buf) > self.payload_size:
                raise RuntimeError("Payload is larger than the fixed payload" +
                                   "size (%d vs. %d bytes)" %
                                   (len(buf), self.payload_size))
            blank_len = self.payload_size - len(buf)

        txbuffer = [NRF24.W_TX_PAYLOAD] + buf + ([0x00] * blank_len)
        self.spidev.xfer2(txbuffer)
        return len(txbuffer) - 1

    def read_payload(self, buf, buf_len=-1):
        """ Reads data from the payload register and sets the
            DR bit of the STATUS register. """

        if buf_len < 0:
            buf_len = self.payload_size

        if not self.dynamic_payloads_enabled:
            data_len = min(self.payload_size, buf_len)
            blank_len = self.payload_size - data_len
        else:
            data_len = self.getDynamicPayloadSize()
            blank_len = 0

        txbuffer = [NRF24.R_RX_PAYLOAD
                    ] + [NRF24.NOP] * (blank_len + data_len + 1)

        payload = self.spidev.xfer2(txbuffer)
        del buf[:]
        buf += payload[1:data_len + 1]

        self.write_register(NRF24.STATUS, NRF24.RX_DR)

        return data_len

    def flush_rx(self):
        return self.spidev.xfer2([NRF24.FLUSH_RX])[0]

    def flush_tx(self):
        return self.spidev.xfer2([NRF24.FLUSH_TX])[0]

    def get_status(self):
        return self.spidev.xfer2([NRF24.NOP])[0]

    def 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()
Exemple #18
0
GPIO.output(ADC_RUN_PIN, GPIO.HIGH)

time.sleep(0.5)
GPIO.output(ADC_RUN_PIN, GPIO.LOW)
time.sleep(0.5)
GPIO.output(ADC_RUN_PIN, GPIO.HIGH)
GPIO.output(ADC_RESET_PIN, GPIO.HIGH)   # ADC powered up now, wait a second before starting SPI transfers
time.sleep(1) 

# SPI Adafruit library: https://github.com/adafruit/adafruit-beaglebone-io-python/blob/master/docs/SPI.rst
#print(spi.xfer2([(0b10000000 | 0x11), 0x00])) # read register 0x11
run(['config-pin',  'P9.18', 'spi']) # can't have MOSI high during power up, so now configure as SPI
spi = SPI(0, 0)

#print(spi.xfer2([(0b00000000 | 0x11), 0b01110100])) # write register 0x11 low power mode (8kHz), internal reference on 
print(spi.xfer2([(0b00000000 | 0x11), 0b01110100])) # write register 0x11 high power mode (16kHz), internal reference on 
print(spi.xfer2([(0b00000000 | 0x15), 0b01000000])) # write register 0x15, internal reference

# To compile firmware, use the command: pasm -b -V3 HWL_ping.pasm
pruss = Icss( "/dev/uio/pruss/module" )
pruss.initialize()

core = pruss.core1 # CORE 1!!!!

# load program
with open('HWL_ping.bin', 'rb') as f:
    core.iram.write( f.read() )

NUM_SAMPLES = 5000

class Shmem( ctypes.Structure ):