Ejemplo n.º 1
0
def PullData():
    print("pull data")

    spi = SPI(1, 0)
    spi.msh = 100000
    spi.bpw = 8

    spi.writebytes([0x30])
    sleep(0.1)
    moistureVals = spi.readbytes(3)
    moisture = str(moistureVals[0]) + str(moistureVals[1]) + str(moistureVals[2])

    spi.writebytes([0x31])
    sleep(0.1)
    moistureVals1 = spi.readbytes(3)
    moisture1 = str(moistureVals1[0]) + str(moistureVals1[1]) + str(moistureVals1[2])

    spi.writebytes([0x35])
    sleep(0.1)
    lightVals = spi.readbytes(3)
    light = str(lightVals[0]) + str(lightVals[1]) + str(lightVals[2])

    Data = []
    Data.append(moisture)
    Data.append(moisture1)
    Data.append(light)

    spi.close()
    return Data
Ejemplo n.º 2
0
    def __init__(self, bus):
        # Use Adafruit_BBIO.SPI to initialize the cap
        # and the spi bus configuration
        s = SPI(bus, self.__DEVICE)
        s.msh = self.__SPEED
        s.mode = self.__MODE
        s.close()

        # Use normal file for writing bytes
        dev = '/dev/spidev%s.%s' % (bus + 1, self.__DEVICE)
        self.spi = open(dev, 'wb')
        print 'Opened %s, Freq: %sHz' % (dev, self.__SPEED)
Ejemplo n.º 3
0
	def __init__(self, bus):
		# Use Adafruit_BBIO.SPI to initialize the cap
		# and the spi bus configuration
		s = SPI(bus, self.__DEVICE)
		s.msh = self.__SPEED
		s.mode = self.__MODE
		s.close()

		# Use normal file for writing bytes
		dev = '/dev/spidev%s.%s' % (bus + 1, self.__DEVICE)
		self.spi = open(dev, 'wb')
		print 'Opened %s, Freq: %sHz' % (dev, self.__SPEED)
Ejemplo n.º 4
0
def getMoist_ch1():
    #print("Reading Moisture CH 1")

    spi = SPI(1, 0)
    spi.msh = 100000
    spi.bpw = 8

    spi.writebytes([0x31])
    sleep(0.01)
    moistureVals = spi.readbytes(3)
    moisture = str(moistureVals[0]) + str(moistureVals[1]) + str(moistureVals[2])

    spi.close()
    return moisture
Ejemplo n.º 5
0
def getLight():
    #print("Reading Light Data")

    spi = SPI(1, 0)
    spi.msh = 100000
    spi.bpw = 8

    spi.writebytes([0x35])
    sleep(0.01)
    lightVals = spi.readbytes(3)
    light = str(lightVals[0]) + str(lightVals[1]) + str(lightVals[2])

    spi.close()
    return light
Ejemplo n.º 6
0
def Watering():
    print("watering")

    spi = SPI(1, 0)
    spi.msh = 100000
    spi.bpw = 8

    list = []
    i=0
    while i<50:
        spi.writebytes([0x31])
        sleep(0.1)
        list.append(spi.readbytes(3))
        print(list.pop())
        ++i
        sleep(0.5)
    spi.close()
Ejemplo n.º 7
0
def stopWatering():
    print("Stopping watering")

    session['watering_command_status'] = "OFF"

    # send the signal to arduino to stop watering
    spi = SPI(1, 0)
    spi.msh = 100000
    spi.bpw = 8

    # send the appropriate signal
    spi.writebytes([0x37])  # '7'

    print(spi.readbytes(1))

    spi.close()

    return flask.redirect("/")
Ejemplo n.º 8
0
def startWatering():
    print("Started watering...")

    session['watering_command_status'] = "ON"

    # send the signal to arduino to start watering
    spi = SPI(1, 0)
    spi.msh = 100000
    spi.bpw = 8

    # send the appropriate signal
    spi.writebytes([0x36])  # '6'

    print(spi.readbytes(1))

    spi.close()

    return flask.redirect("/")
Ejemplo n.º 9
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()
Ejemplo n.º 10
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
Ejemplo n.º 11
0
class DACRef:

    def __init__(self, maxClock=3300000):
        # using two's complement
        self.dacSend = "0001"
        self.max_raw_minus = -pow(2, 19)  # maximal value that can be achieved
        self.max_raw_plus = int(0b01111111111111111111)
        self.actVal = 0  # actual value
        # SPI
        self.spi = SPI(1, 0)  # choose SPI device
        self.spi.mode = 0b00
        if maxClock > 1000:
            self.spi.msh = maxClock
        else:
            self.spi.msh = 3300000
            print("Minumum clock speed is 10000, setting default 33Mhz")
        # Start values
        self.reset = 0
        self.ldac = 0  # in the beggining the device is not ready(remember they are inverted)

        # P8
        GPIO.setup("P8_17", GPIO.OUT)  # LDAC
        GPIO.output("P8_17", self.ldac)
        GPIO.setup("P8_18", GPIO.OUT)  # RESET
        GPIO.output("P8_18", self.reset)

        # GPIO.setup("P8_15", GPIO.OUT) #ext rsten
        # GPIO.setup("P8_14", GPIO.OUT) # PLL LOCK
        # GPIO.setup("P8_16", GPIO.OUT) # ext Ioupden
        # NOT USED

        # P9 (addresses)
        self.dacAddress = [0, 0, 0, 0, 0]  # default
        GPIO.setup("P9_11", GPIO.OUT)  # P1
        GPIO.setup("P9_12", GPIO.OUT)  # P2
        GPIO.setup("P9_13", GPIO.OUT)  # P3
        GPIO.setup("P9_14", GPIO.OUT)  # P4
        GPIO.setup("P9_15", GPIO.OUT)  # P0

    def setDACAddress(self, list):
        self.dacAddress = list
        GPIO.setup("P9_15", self.dacAddress[0])  # P0
        GPIO.setup("P9_11", self.dacAddress[1])  # P1
        GPIO.setup("P9_12", self.dacAddress[2])  # P2
        GPIO.setup("P9_13", self.dacAddress[3])  # P3
        GPIO.setup("P9_14", self.dacAddress[4])  # P4

    def chooseDAC(self, dacNum=0, board=0):

        if board == 0:
            p2 = 0
            p3 = 0
            p4 = 0
        elif board == 1:
            p2 = 0
            p3 = 0
            p4 = 1
        elif board == 2:
            p2 = 0
            p3 = 1
            p4 = 0
        elif board == 3:
            p2 = 0
            p3 = 1
            p4 = 1
        else:
            print("WRONG NUMBER, SETTING 0")
            p2 = 0
            p3 = 0
            p4 = 0

        GPIO.output("P9_12", p2)
        GPIO.output("P9_13", p3)
        GPIO.output("P9_14", p4)

        if dacNum == 0:
            p0 = 0
            p1 = 0
        elif dacNum == 1:
            p0 = 0
            p1 = 1
        elif dacNum == 2:
            p0 = 1
            p1 = 0
        elif dacNum == 3:
            p0 = 1
            p1 = 1
        GPIO.output("P9_15", p0)
        GPIO.output("P9_11", p1)
        self.dacAddress = [p0, p1, p2, p3, p4]

    def setLDAC(self, ldac):
        self.ldac = ldac
        GPIO.output("P8_17", self.ldac)

    def resetDAC(self):
        self.reset = 1
        GPIO.output("P8_18", self.reset)
        GPIO.output("P8_18", 0)  # returns it back to 0

    def setValueRaw(self, raw):
        if self.max_raw_plus >= int(raw) >= self.max_raw_minus:
            self.actVal = int(raw)
            print("Actual value is: " + str(self.actVal))
        else:
            self.actVal = 0  # if we go out of range we get 0
            print("Out of range[-1,1] or 0.")
           # print("Actual value is: " + str(self.actVal))
        self.registerValue()

    def setValueNorm(self, norm):
        if 0 < norm <= 1:
            self.actVal = int(self.max_raw_plus * norm)
            print("Actual value is: " + str(self.actVal))
        elif 0 > norm >= -1:
            self.actVal = int(-self.max_raw_minus * norm)
           # print("Actual value is: " + str(self.actVal))
        else:
            self.actVal = 0
            print("Out of range[-1,1] or 0.")
           # print("Actual value is: " + str(self.actVal))
        self.registerValue()

    def setValHelp(self, address):
        val = input("Write the value from [-524288,524287]: ")
        if val <= self.max_raw_plus and val >= self.max_raw_minus:
            self.setDACAddress(address)
            self.setValueNorm(int(val))
        else:
            print("Wrong number, doing nothing")
            return

    def initializeDAC(self):  # we can always change the initialize and make it more flexible
        GPIO.output("P8_17", GPIO.HIGH)
        self.spi.writebytes([0b00100000, 0b00000000, 0b00100010])
        GPIO.output("P8_17", GPIO.LOW)

    def registerValue(self):

        self.initializeDAC()
        if self.actVal != 0:
            temp = convertComplement_DAC(self.actVal, 20)
            string1 = self.dacSend + temp[0:4]
            string2 = temp[4:12]
            string3 = temp[12:]
            GPIO.output("P8_17", GPIO.HIGH)
            self.spi.writebytes([int(string1, 2), int(string2, 2), int(string3, 2)])
            GPIO.output("P8_17", GPIO.LOW)
        else:
            self.resetDAC()

    def __del__(self):
        self.resetDAC()
        self.spi.close()
Ejemplo n.º 12
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()
Ejemplo n.º 13
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
Ejemplo n.º 14
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()
Ejemplo n.º 15
0
			data.append(line)
			count += 1
		elif count == 19:
			data.pop(0)
			break
	data.append(str(resultFinal))# + '\n')
	print data
	#print len(data)
	#data.pop(0)
	file.close()
	f = open('methane_test.txt' ,'w').close()
	#f = open('methane_test.txt','r+')
	#f.truncate()
	file = open('methane_test.txt', 'w')
	for number in data:
		print number
		#file.write("\n")
		file.write("%s" % number)
		#file.write("\n")
	#####################################
	#####################################

        #print data
        #print result[0] #"EYYYYY"
        #print result[1]
	file.close()
#end while

except KeyboardInterrupt:
        spi.close()
Ejemplo n.º 16
0
class DAC:
    def __init__(self):
        # create outer classes with ability to change inner parameters

        # using two's complement
        # CONSTS
        self.DAC_SEND = "0001"  # value to be sending information to dac
        self.MAX_NEG = -pow(2, 19)  # max neg value that can be achieved
        self.MAX_POS = int(
            0b01111111111111111111)  # max pos value that can be achieved
        self.MAX_CLOCK = 340000  # maximal clock value we can get in Hz
        self.MIN_CLOCK = 50000  # minimal clock value we can get in Hz
        self.IP = '192.168.0.20'
        self.PORT = 5555

        self.act_val = 0  # actual value
        self.clock = self.MIN_CLOCK  # begin with min value

        self.spi = SPI(1, 0)  # spi for our communication
        self.spi.mode = 0b00
        self.spi.msh = self.clock

        # Triggers for the DAC
        self.reset = False
        self.ldac = False
        GPIO.setup("P8_17", GPIO.OUT)  # LDAC
        GPIO.setup("P8_18", GPIO.OUT)  # RESET
        GPIO.output("P8_18", self.reset)
        GPIO.output("P8_17", self.ldac)

        # Address for which DAC
        self.dac_address = list()
        self.dac_address = [0, 0, 0, 0, 0]  # default
        GPIO.setup("P9_15", GPIO.OUT)  # P0
        GPIO.setup("P9_11", GPIO.OUT)  # P1
        GPIO.setup("P9_12", GPIO.OUT)  # P2
        GPIO.setup("P9_13", GPIO.OUT)  # P3
        GPIO.setup("P9_14", GPIO.OUT)  # P4
        GPIO.output("P9_15", GPIO.LOW)  # P0
        GPIO.output("P9_11", GPIO.LOW)  # P1
        GPIO.output("P9_12", GPIO.LOW)  # P2
        GPIO.output("P9_13", GPIO.LOW)  # P3
        GPIO.output("P9_14", GPIO.LOW)  # P4
        self.initializeDAC()
        # server

    def reset_dac(self):
        GPIO.output("P8_18", 1)
        print('Reseting DAC')
        self.spi.close()
        self.spi = SPI(1, 0)
        GPIO.output("P8_18", 0)  # returns it back to 0

    def __del__(self):
        self.reset_dac()  # reset voltage
        self.spi.close()  # spi close

    def initializeDAC(
            self
    ):  # we can always change the initialize and make it more flexible
        GPIO.output("P8_17", GPIO.HIGH)
        self.spi.writebytes([0b00100000, 0b00000000, 0b00100010])
        GPIO.output("P8_17", GPIO.LOW)

    def registerValue(self):
        self.initializeDAC()
        if self.act_val != 0:
            temp = self.convertComplement_DAC(self.act_val, 20)
            string1 = self.DAC_SEND + temp[0:4]
            string2 = temp[4:12]
            string3 = temp[12:]
            GPIO.output("P8_17", GPIO.HIGH)
            self.spi.writebytes(
                [int(string1, 2),
                 int(string2, 2),
                 int(string3, 2)])
            print('Sending to the DAC: ', string1 + string2 + string3)
            GPIO.output("P8_17", GPIO.LOW)
        else:
            self.reset_dac()
            return

    @staticmethod
    def convertComplement_DAC(value, width=20):
        #        Return the binary representation of the input number as a string.
        #        If width is not given it is assumed to be 20. If width is given, the two's complement of the number is
        #        returned, with respect to that width.
        #        In a two's-complement system negative numbers are represented by the two's
        #        complement of the absolute value. This is the most common method of
        #        representing signed integers on computers. A N-bit two's-complement
        #        system can represent every integer in the range [-2^(N-1),2^(N-1)-1]

        def warning(widt, width_bin):

            # the function checks if the width is a good value for input number, if not (f.e smaller) returning
            # default 20

            if widt != 20 and (widt <= 0 or width < width_bin):
                print("Bad width, returning default\n")
                return width_bin
            elif widt == 20 and widt < width_bin:
                return width_bin
            else:
                return widt

        if value > 0:
            binar = bin(
                int(value))[2:]  # take binary representation of input value
            real_width = warning(width, len(binar))  # check width
            if real_width > len(
                    binar):  # add zeros if width is bigger that binary length
                for x1 in range(0, real_width - len(binar)):
                    binar = "0" + binar
            return binar

        elif value == 0:  # all zeros
            binar = ""
            for x2 in range(0, width):
                binar = "0" + binar

        elif value < 0:
            binar = bin(
                abs(int(value))
            )[2:]  # because of the minus sign at the beginning we take absolute value
            real_width = warning(width, len(binar))
            if abs(value) == pow(2, real_width - 1):
                return binar
            if real_width > len(
                    binar
            ):  # with bigger length we have to add zeros at the beginning
                for x3 in range(0, real_width - len(binar)):
                    binar = "0" + binar
            strin = ""  # empty temporary string
            for x in range(0, real_width):
                if int(binar[x]) == 1:
                    temp = 0  # negating for the 2's complement
                else:
                    temp = 1
                strin = strin + str(temp)
            temp_add = int(strin, 2)
            temp_add = temp_add + 1
            binar = bin(temp_add)[2:]
            return binar
Ejemplo n.º 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()
Ejemplo n.º 18
0
    print readID(flash_handler, flash3_cs)
    totalErase(flash_handler, flash1_cs)
    totalErase(flash_handler, flash2_cs)
    totalErase(flash_handler, flash3_cs)
    #    #writeByte(flash_handler,0x00,33)
    #    #writeByte(flash_handler,0x01,34)
    #    erase4kbSector(flash_handler, 0)
    #    f.write(datetime.datetime.now())
    data1 = [i for i in range(100)]
    data2 = [2 * i for i in range(100)]
    data3 = [3 * i for i in range(100)]
    writeBytes(flash_handler, 0x000000, data1, flash1_cs)
    writeBytes(flash_handler, 0x000000, data2, flash2_cs)
    writeBytes(flash_handler, 0x000000, data3, flash3_cs)
    print readBytes(flash_handler, 0x00, 32, flash1_cs)
    print readBytes(flash_handler, 0x00, 32, flash2_cs)
    print readBytes(flash_handler, 0x00, 32, flash3_cs)
    erase4kbSector(flash_handler, 0, flash1_cs)
    erase4kbSector(flash_handler, 0, flash2_cs)
    erase4kbSector(flash_handler, 0, flash3_cs)
    print readBytes(flash_handler, 0x00, 32, flash1_cs)
    print readBytes(flash_handler, 0x00, 32, flash2_cs)
    print readBytes(flash_handler, 0x00, 32, flash3_cs)
    #    #print readBytes(flash_handler, 0x00, 200)
    #    erase4kbSector(flash_handler, 0)
    #    data = [i for i in range(256)]
    #    writeBytes(flash_handler, 0x000000, data)
    #    print readBytes(flash_handler, 0x00, 1<<8)
    #    erase4kbSector(flash_handler, 0)
    flash_handler.close()