def __init__(self, LED_STATE=default_LED_STATE, Fxosc=default_Fxosc, Fstep=default_Fstep, callsign=None, node_id=default_node_id, network_id=default_network_id, carrier_freq=default_carrier_freq, carrier_dev=default_carrier_dev, carrier_bitrate=default_bitrate): self._mode = OPMODE_SLEEP self.LED_STATE = LED_STATE self.Fxosc = Fxosc self.Fstep = Fstep self.callsign = callsign self.RFM_SPI = SPI(0, 0) self.RFM_SPI.msh = 5000000 self.carrier_freq = carrier_freq self.carrier_dev = carrier_dev self.bitrate = carrier_bitrate self.node_id = node_id self.network_id = network_id if self.callsign is None: raise NoCallSign("FCC Callsign not defined") self.ord_callsign = map(ord, list(self.callsign)) self._io_setup() GPIO.output(BLUE_LEDPIN, GPIO.LOW) self.reset_radio() return
class DAC(): """ This class uses an actual DAC """ def __init__(self, channel): """ Channel is the pwm output is on (0..15) """ self.channel = channel self.offset = 0.0 if 'SPI' in globals(): # init the SPI for the DAC try: self.spi2_0 = SPI(0, 0) except IOError: self.spi2_0 = SPI(1, 0) self.spi2_0.bpw = 8 self.spi2_0.mode = 1 else: logging.warning("Unable to set up SPI") self.spi2_0 = None def set_voltage(self, voltage): logging.debug("Setting voltage to "+str(voltage)) if self.spi2_0 is None: logging.debug("SPI2_0 missing") return v_ref = 3.3 # Voltage reference on the DAC dacval = int((voltage * 256.0) / v_ref) byte1 = ((dacval & 0xF0) >> 4) | (self.channel << 4) byte2 = (dacval & 0x0F) << 4 self.spi2_0.writebytes([byte1, byte2]) # Update all channels self.spi2_0.writebytes([0xA0, 0xFF])
class DAC(): """ This class uses an actual DAC """ def __init__(self, channel): """ Channel is the pwm output is on (0..15) """ self.channel = channel self.offset = 0.0 if 'SPI' in globals(): # init the SPI for the DAC self.spi2_0 = SPI(2, 0) self.spi2_0.bpw = 8 self.spi2_0.mode = 1 else: logging.warning("Unable to set up SPI") self.spi2_0 = None def set_voltage(self, voltage): logging.debug("Setting voltage to " + str(voltage)) if self.spi2_0 is None: logging.debug("SPI2_0 missing") return v_ref = 3.3 # Voltage reference on the DAC dacval = int((voltage * 256.0) / v_ref) byte1 = ((dacval & 0xF0) >> 4) | (self.channel << 4) byte2 = (dacval & 0x0F) << 4 self.spi2_0.writebytes([byte1, byte2]) # Update all channels self.spi2_0.writebytes([0xA0, 0xFF])
def __init__(self, length, missing): # the important piece of this for reuse is setting up the interface # the rest sets up the strip of leds for what we intend to do with them self.interface = SPI(0, 1) self.full_length = length self.missing_leds = missing self.outbuff = [[128, 128, 128]] * length self.reset_buffer([128, 128, 128])
def __init__(self): self.val = None self.tempList = [] self.spi = SPI(0, 0) self.spi.msh = 1000000 GPIO.setup(CS_PIN, GPIO.OUT) GPIO.output(CS_PIN, GPIO.HIGH) self.inter = Interpolate(x, y)
def __init__(self, channel): """ Channel is the pwm output is on (0..15) """ self.channel = channel self.offset = 0.0 if 'SPI' in globals(): # init the SPI for the DAC self.spi2_0 = SPI(2, 0) self.spi2_0.bpw = 8 self.spi2_0.mode = 1 else: logging.warning("Unable to set up SPI") self.spi2_0 = None
def __init__(self, bus): # Use Adafruit_BBIO.SPI to initialize the cap # and the spi bus configuration s = SPI(bus, self.__DEVICE) s.msh = self.__SPEED s.mode = self.__MODE s.close() # Use normal file for writing bytes dev = '/dev/spidev%s.%s' % (bus + 1, self.__DEVICE) self.spi = open(dev, 'wb') print 'Opened %s, Freq: %sHz' % (dev, self.__SPEED)
def __init__(self): self.spi = SPI( 0, 0 ) #/dev/spidev1.0 (be sure to run Python with su if 'no permission' self.spi.msh = 1000000 #SPI clock set to 1MHz (slowed from 10MHz for better stability across setups) self.spi.bpw = 8 # bits per word self.spi.threewire = False # not half-duplex self.spi.lsbfirst = False # we want MSB first self.spi.mode = 0 # options are modes 0 through 3 self.spi.cshigh = False # we want chip select to be active low self.spi.open(0, 0) # make it so time.sleep(0.05)
def factory(bus=0, device=0, dev="rpi"): if dev == "rpi": import spidev s = spidev.SpiDev() s.open(0, 0) return s elif dev == "bbb": from Adafruit_BBIO.SPI import SPI bus = 1 s = SPI(bus, device) s.mode = 0 return s
def init_spi(self): logging.debug("Initializing spi...") self.spi = SPI(0, 0) #/dev/spidev1.0 # SPI Mode Clock Polarity (CPOL/CKP) Clock Phase (CPHA) Clock Edge (CKE/NCPHA) # 0 0 0 1 # 1 0 1 0 # 2 1 0 1 # 3 1 1 0 self.spi.mode = 0 self.spi.msh = SPI_CLOCK_RATE #this is clock speed setting self.spi.open(0, 0)
def __init__(self, unix_socket_path, *args, **kwargs): self.unix_socket_path = unix_socket_path self.connection = None self.welcome_socket = None spi = SPI(0, 0) spi.msh = 2000000 spi.mode = 1 self.chs = [0, 1, 2, 3] self.ADC0 = ADC("P9_24", spi) self.ADC1 = ADC("P9_26", spi) self.ADC2 = ADC("P9_28", spi) self.ADC3 = ADC("P9_30", spi)
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 __init__(self, channel): """ Channel is the pwm output is on (0..15) """ self.channel = channel self.offset = 0.0 if 'SPI' in globals(): # init the SPI for the DAC try: self.spi2_0 = SPI(0, 0) except IOError: self.spi2_0 = SPI(1, 0) self.spi2_0.bpw = 8 self.spi2_0.mode = 1 else: logging.warning("Unable to set up SPI") self.spi2_0 = None
def __init__(self, bus, device, cePin, csnPin, irqPin): self.__bus = bus self.__device = device self.cePin = cePin self.csnPin = csnPin self.irqPin = irqPin self.spi = SPI(self.__bus, self.__device) self.spi.msh = 10000 self.spi.bpw = 8 # bits/word self.spi.threewire = False self.spi.lsbfirst = False self.spi.mode = 0 self.spi.cshigh = False self.spi.open(0, 0) self.last_payload = ""
def __init__(self, coarsePin="P9_15", finePin="P9_16", readPin="P9_14", clockRate=100000): self.CS_FB_COARSE_PIN = coarsePin self.CS_FB_FINE_PIN = finePin self.CS_ADC_PIN = readPin self.FB_CLK_RATE = clockRate GPIO.setup(self.CS_FB_COARSE_PIN, GPIO.OUT) GPIO.setup(self.CS_FB_FINE_PIN, GPIO.OUT) GPIO.setup(self.CS_ADC_PIN, GPIO.OUT) self.spi00 = SPI(0,0) self.spi00.msh = self.FB_CLK_RATE self.fname = "dacValues.pyon" self.maxDACvalue = (1<<16)-1 # Ca43 self.kHz_per_mG = -2.45 # measured self.mG_per_mA = 146 / 56.64 # (sensor+DiffAmp) equivalent : 6.06ohm # Verr: voltage of error signal self.mA_per_mVerr = 1 / 6.06 self.mG_per_mVerr = self.mG_per_mA * self.mA_per_mVerr self.kHz_per_mVerr = self.kHz_per_mG * self.mG_per_mVerr # maximum DAC output: 2.048V self.mVDAC_per_DACvalue = 2.048e3 / self.maxDACvalue # estimates for the slope qubit_freq'(DACvalue) # fine DAC gain 1 # coarse DAC gain 200 self.kHz_per_fDACvalue_est = self.kHz_per_mG * self.mG_per_mVerr * self.mVDAC_per_DACvalue self.kHz_per_cDACvalue_est = self.kHz_per_mG * self.mG_per_mVerr * 200 * self.mVDAC_per_DACvalue
def setup_spi(self): #This is for BB Black self.spi = SPI(self.spi_bus, self.spi_client) self.spi.msh = self.spi_freq self.spi.mode = self.spi_mode self.bpw = self.spi_bits_per_word self.spi.cshigh = self.spi_cshigh
def __init__(self, spi = SPI(0,0), gpio_nrst = 'P9_23', gpio_dc = 'P9_24', gpio_nled = 'P9_25'): self.gpio_nrst = gpio_nrst self.gpio_dc = gpio_dc self.gpio_nled = gpio_nled self.spi = spi self.spi.msh = 4000000 self.spi.mode = 0b00 self.spi.bpw = 8 self.spi.lsbfirst = False self.spi.threewire = False self.spi.cshigh = False GPIO.setup(self.gpio_nrst, GPIO.OUT, initial = GPIO.LOW) sleep(0.1) # workaround until library waits for permissions GPIO.setup(self.gpio_nrst, GPIO.OUT, initial = GPIO.LOW) GPIO.output(self.gpio_nrst, GPIO.LOW) # Reset. GPIO.setup(self.gpio_dc, GPIO.OUT, initial = GPIO.LOW) sleep(0.1) GPIO.setup(self.gpio_dc, GPIO.OUT, initial = GPIO.LOW) GPIO.output(self.gpio_dc, GPIO.LOW) # Command. if self.gpio_nled: GPIO.setup(self.gpio_nled, GPIO.OUT, initial = GPIO.HIGH) sleep(0.1) GPIO.setup(self.gpio_nled, GPIO.OUT, initial = GPIO.HIGH) GPIO.output(self.gpio_nled, GPIO.HIGH) # Off. self.reset()
def __init__(self, isRFM69HW=True, interruptPin=DIO0_PIN, csPin=NSS_PIN): self._isRFM69HW = isRFM69HW self._interruptPin = interruptPin self._csPin = csPin self.SPI = SPI(SPI_BUS, SPI_CS) self.SPI.bpw = 8 self.SPI.mode = 0 self.SPI.msh = SPI_CLK_SPEED self.SPI.lsbfirst = False GPIO.setup(self._interruptPin, GPIO.IN) self.lastIrqLevel = GPIO.input(self._interruptPin) GPIO.setup(self._csPin, GPIO.OUT) GPIO.output(self._csPin, GPIO.HIGH) self.start_time = datetime.datetime.now()
def __init__(self, length, missing): # the important piece of this for reuse is setting up the interface # the rest sets up the strip of leds for what we intend to do with them self.interface = SPI(0,1) self.full_length = length self.missing_leds = missing self.outbuff = [[128, 128, 128]] * length self.reset_buffer([128, 128, 128])
def getLight(): #print("Reading Light Data") spi = SPI(1, 0) spi.msh = 100000 spi.bpw = 8 spi.writebytes([0x35]) sleep(0.01) lightVals = spi.readbytes(3) light = str(lightVals[0]) + str(lightVals[1]) + str(lightVals[2]) spi.close() return light
def getMoist_ch1(): #print("Reading Moisture CH 1") spi = SPI(1, 0) spi.msh = 100000 spi.bpw = 8 spi.writebytes([0x31]) sleep(0.01) moistureVals = spi.readbytes(3) moisture = str(moistureVals[0]) + str(moistureVals[1]) + str(moistureVals[2]) spi.close() return moisture
def __init__(self, partial_refresh_limit=32, fast_refresh=True): """ Initialize the EPD class. `partial_refresh_limit` - number of partial refreshes before a full refrersh is forced `fast_frefresh` - enable or disable the fast refresh mode, see smart_update() method documentation for details""" self.width = EPD_WIDTH """ Display width, in pixels """ self.height = EPD_HEIGHT """ Display height, in pixels """ self.fast_refresh = fast_refresh """ enable or disable the fast refresh mode """ self.partial_refresh_limit = partial_refresh_limit """ number of partial refreshes before a full refrersh is forced """ self._last_frame = None self._partial_refresh_count = 0 self._init_performed = False self.spi = SPI(1, 0)
class PT100(Sensor): def __init__(self): self.val = None self.tempList = [] self.spi = SPI(0, 0) self.spi.msh = 1000000 GPIO.setup(CS_PIN, GPIO.OUT) GPIO.output(CS_PIN, GPIO.HIGH) self.inter = Interpolate(x, y) def spi_read(self): GPIO.output(CS_PIN, GPIO.LOW) self.spi.xfer([REG_CONF, CNF_ONESHOT]) GPIO.output(CS_PIN, GPIO.HIGH) time.sleep(0.1) GPIO.output(CS_PIN, GPIO.LOW) self.spi.xfer([REG_LSB]) lsb = self.spi.readbytes(1) GPIO.output(CS_PIN, GPIO.HIGH) GPIO.output(CS_PIN, GPIO.LOW) self.spi.xfer([REG_MSB]) msb = self.spi.readbytes(1) GPIO.output(CS_PIN, GPIO.HIGH) err = (False, True)[lsb[0] & 1] adc = (msb[0] << 8 | lsb[0]) >> 1 return (err, adc) def update(self): value = 0 err = False for i in range(10): err, adc = self.spi_read() if err: break value = value + adc if err: #self.val=None return value = value / 10. res = (value / 2**15 * 400) self.tempList.append(self.inter(res)) if len(self.tempList) > 5: del self.tempList[0] tSum = 0 for t in self.tempList: tSum = tSum + t self.val = tSum / len(self.tempList)
def __init__(self): self.spi = SPI(0,0) #/dev/spidev1.0 (be sure to run Python with su if 'no permission' self.spi.msh=1000000 #SPI clock set to 1MHz (slowed from 10MHz for better stability across setups) self.spi.bpw = 8 # bits per word self.spi.threewire = False # not half-duplex self.spi.lsbfirst = False # we want MSB first self.spi.mode = 0 # options are modes 0 through 3 self.spi.cshigh = False # we want chip select to be active low self.spi.open(0,0) # make it so time.sleep(0.05)
def __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()
def Watering(): print("watering") spi = SPI(1, 0) spi.msh = 100000 spi.bpw = 8 list = [] i=0 while i<50: spi.writebytes([0x31]) sleep(0.1) list.append(spi.readbytes(3)) print(list.pop()) ++i sleep(0.5) spi.close()
def 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("/")
def stopWatering(): print("Stopping watering") session['watering_command_status'] = "OFF" # send the signal to arduino to stop watering spi = SPI(1, 0) spi.msh = 100000 spi.bpw = 8 # send the appropriate signal spi.writebytes([0x37]) # '7' print(spi.readbytes(1)) spi.close() return flask.redirect("/")
def __init__(self, bus, device): super(MAX7221, self).__init__(8, 8) SPI(bus, device).mode = 0 self.spi_bus = SPI(bus, device) self.buf = [0, 0, 0, 0, 0, 0, 0, 0] self.OP_NOP = 0x0 self.OP_DIG0 = 0x1 self.OP_DIG1 = 0x2 self.OP_DIG2 = 0x3 self.OP_DIG3 = 0x4 self.OP_DIG4 = 0x5 self.OP_DIG5 = 0x6 self.OP_DIG6 = 0x7 self.OP_DIG7 = 0x8 self.OP_DECODEMODE = 0x9 self.OP_INTENSITY = 0xA self.OP_SCANLIMIT = 0xB self.OP_SHUTDOWN = 0xC self.OP_DISPLAYTEST = 0xF self.init()
def ini_levels(): check_ok = 0 update_data = 0x39 # spi.set_clock_hz(1000000) # spi.set_mode(0) # spi.set_bit_order(SPI.MSBFIRST) SPI_PORT = 0 SPI_DEVICE = 0 # SPI setup spi = SPI(0, 0) #/dev/spidev1.0 spi.msh = 100000 # SPI clock set to 100 kHz spi.bpw = 8 # bits/word spi.threewire = False spi.lsbfirst = False spi.mode = 0 spi.cshigh = False # ADS1248 chip select (active low) # spi.open(0,0) spi.open(SPI_PORT, SPI_DEVICE) print "SPI port ", SPI_PORT, " ", SPI_DEVICE, " open"
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 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()
class LED_LPD8806(object): # Constructor def __init__(self): self.spi = SPI(0,0) #/dev/spidev1.0 (be sure to run Python with su if 'no permission' self.spi.msh=1000000 #SPI clock set to 1MHz (slowed from 10MHz for better stability across setups) self.spi.bpw = 8 # bits per word self.spi.threewire = False # not half-duplex self.spi.lsbfirst = False # we want MSB first self.spi.mode = 0 # options are modes 0 through 3 self.spi.cshigh = False # we want chip select to be active low self.spi.open(0,0) # make it so time.sleep(0.05) def setup(self, led_pixels, debug=False): if (debug): print "Initializing LED strip" global pixels pixels = [[0x80 for x in range(3)] for y in range(led_pixels)] for i in range(led_pixels): pixels[i]=[0x00, 0x00, 0x00] # Define LED functions: # -------------------- # Update pixel display with a given delay time between pixel updates: def writestrip(self, delay): if (delay < 0): delay = 0 for i in range(len(pixels)): self.spi.writebytes([0x00, 0x00, 0x00]) #prepare write for i in range(len(pixels)): self.spi.writebytes(pixels[i]) #write colors to pixels time.sleep(delay) # Turn off all LEDs: def clearstrip(self): global pixels for i in range(len(pixels)): self.spi.writebytes([0x00, 0x00, 0x00]) #prepare write for i in range(len(pixels)): pixels[i] = [0x80, 0x80, 0x80] self.writestrip(0) # Set an individual pixel to a specific color (to display later): def setpixelcolor(self, n, g, r, b): global pixels if (n >= len(pixels)): return if (n < 0): return if (g > 0xFF): g = 0xFF if (g < 0x80): g = 0x80 if (r > 0xFF): r = 0xFF if (r < 0x80): r = 0x80 if (b > 0xFF): b = 0xFF if (b < 0x80): b = 0x80 pixels[n] = [g, r, b] # Update display with warmer colors (more red light) by a specified amount with a delay between pixels def warmstrip(self, warmth, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][1] + warmth) < 0x80): pixels[n][1] = 0x80 elif((pixels[n][2] + warmth) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1]+warmth self.writestrip(delay) # Update display with cooler colors (more blue) by a specified amount with a delay between each pixel def coolstrip(self, coolfactor, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][2] + coolfactor) < 0x80): pixels[n][2] = 0x80 elif((pixels[n][2] + coolfactor) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2]+coolfactor self.writestrip(delay) # Update display with greener colors by a specified amount with a set delay between each pixel def greenstrip(self, lushness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][0] + lushness) < 0x80): pixels[n][0] = 0x80 else: pixels[n][0] = pixels[n][0]+lushness self.writestrip(delay) # Update display with brighter (whiter) light by specified amount with a set delay between pixel updates def brightenstrip(self, brightness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][0] + brightness) < 0x80): pixels[n][0] = 0x80 elif((pixels[n][0] + brightness) > 0xFF): pixels[n][0] = 0xFF else: pixels[n][0] = pixels[n][0]+brightness if((pixels[n][1] + brightness) < 0x80): pixels[n][1] = 0x80 elif((pixels[n][1] + brightness) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1]+brightness if((pixels[n][2] + brightness) < 0x80): pixels[n][2] = 0x80 elif((pixels[n][2] + brightness) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2]+brightness self.writestrip(delay) # Darken display (less light) by specified amount with a set delay between pixel updates def dimstrip(self, dimness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][0] - dimness) < 0x80): pixels[n][0] = 0x80 elif((pixels[n][0] - dimness) > 0xFF): pixels[n][0] = 0xFF else: pixels[n][0] = pixels[n][0]-dimness if((pixels[n][1] - dimness) < 0x80): pixels[n][1] = 0x80 elif((pixels[n][1] - dimness) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1]-dimness if((pixels[n][2] - dimness) < 0x80): pixels[n][2] = 0x80 elif((pixels[n][2] - dimness) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2]-dimness self.writestrip(delay)
def ADCinit(): RegWrite(ADS1248.MUX0, 0b00000001); # MUX0: Pos. input: AIN0, Neg. input: AIN1 (Burnout current source off) RegWrite(ADS1248.MUX1, 0b00100000); # MUX1: REF0, normal operation RegWrite(ADS1248.SYS0, 0b00000000); # SYS0: PGA Gain = 1, 5 SPS RegWrite(ADS1248.IDAC0,0b00000000); # IDAC0: off RegWrite(ADS1248.IDAC1,0b11001100); # IDAC1: n.c. RegWrite(ADS1248.VBIAS,0b00000000); # VBIAS: BIAS voltage disabled RegWrite(ADS1248.OFC0, 0b00000000); # OFC0: 0 => reset offset calibration RegWrite(ADS1248.OFC1, 0b00000000); # OFC1: 0 => reset offset calibration RegWrite(ADS1248.OFC2, 0b00000000); # OFC2: 0 => reset offset calibration RegWrite(ADS1248.GPIOCFG, 0b00000000); # GPIOCFG: all used as analog inputs RegWrite(ADS1248.GPIODIR, 0b00000000); # GPIODIR: - RegWrite(ADS1248.GPIODAT, 0b00000000); # GPIODAT: - spi = SPI(0,0) #/dev/spidev1.0 spi.msh=10000 # SPI clock set to 100 kHz spi.bpw = 8 # bits/word spi.threewire = False spi.lsbfirst = False spi.mode = 1 spi.cshigh = False # ADS1248 chip select (active low) spi.open(0,0) GPIO.setup("P9_14", GPIO.OUT) # drive START high to start conversion GPIO.setup(ADS1248.STARTPIN, GPIO.OUT) GPIO.output(ADS1248.STARTPIN,GPIO.HIGH)
""" import logging spi = None # Load SPI module try: from Adafruit_BBIO.SPI import SPI except ImportError: pass if 'SPI' in globals(): # Init the SPI for the serial to parallel try: spi = SPI(1, 1) except: pass spi.bpw = 8 spi.mode = 0 else: logging.warning("Unable to set up SPI") spi = None class ShiftRegister(object): registers = list() @staticmethod def commit(): """ Send the values to the serial to parallel chips """
from Adafruit_BBIO.SPI import SPI spi = SPI(1,0) spi.mode=2 spi.msh=200000 spi.open(1,0) print spi.readbytes(4) #print spi.xfer2([32, 11, 110, 22, 220]) spi.close()
from Adafruit_BBIO.SPI import SPI spi = SPI(1,0) spi.mode=2 spi.msh=2000000 spi.open(1,0) print spi.xfer2([32, 11, 110, 22, 220]) spi.close()
import Adafruit_BBIO.GPIO as GPIO from Adafruit_BBIO.SPI import SPI # from ADS126x_constants import * spi = SPI(0, 0) # class ADS126x(): START_PIN = "P9_23" RSTN_PIN = "P9_24" DRDY_PIN = "P9_26" GPIO.setup(RSTN_PIN, GPIO.OUT, pull_up_down=GPIO.PUD_UP) GPIO.output(RSTN_PIN, GPIO.HIGH) GPIO.setup(START_PIN, GPIO.OUT, pull_up_down=GPIO.PUD_DOWN) GPIO.output(START_PIN, GPIO.LOW) GPIO.setup(DRDY_PIN, GPIO.IN) R0 = 100.0 A = 3.9083e-3 B = -5.775e-7 C = -4.183e-12 def R2C(R): if R >= 100.0: return (-R0*A +(R0**2 * A**2 - 4 * R0 * B * (R0 - R))**0.5)\
from Adafruit_BBIO.SPI import SPI spi = SPI(0,0) spi.open(0,0) #spi.msh = 100000 spi.bpw = 8 #spi.mode = b00 try: #while True: # set CS bit high, choose first channel to read from #channel = 0; #adc = spi.xfer([1,8,0]) #data = ((adc[1]&3) << 8) + adc[2] channelSelect = 0xC0 channelSelect |= 0x18 channelSelect <<= 3 fsr = spi.xfer2([channelSelect, 0x00, 0x00]) #result = spi.readbytes(2) #result2 = spi.readbytes(1) resultFinal = 0x0000 resultFinal = 0x0300 & (resultFinal | (fsr[1] << 8 )) resultFinal |= ( ( 0x00FF & fsr[2]) ) #print (8 + channel ) << 4 #print resultFinal ################################### #################################### resultFinal = 1 #temp
class NRF24: # Some limits MAX_CHANNEL = 127 MAX_PAYLOAD_SIZE = 32 # PA Levels PA_MIN = 0x00 PA_LOW = 0x01 PA_HIGH = 0x02 PA_MAX = 0x03 PA_ERROR = 0x04 # Bit rates BR_1MBPS = 0 BR_2MBPS = 1 BR_250KBPS = 2 # CRC CRC_DISABLED = 0 CRC_8 = 1 CRC_16 = 2 # Registers CONFIG = 0x00 EN_AA = 0x01 EN_RXADDR = 0x02 SETUP_AW = 0x03 SETUP_RETR = 0x04 RF_CH = 0x05 RF_SETUP = 0x06 STATUS = 0x07 OBSERVE_TX = 0x08 RPD = 0x09 # CD on Non-P version RX_ADDR_P0 = 0x0A RX_ADDR_P1 = 0x0B RX_ADDR_P2 = 0x0C RX_ADDR_P3 = 0x0D RX_ADDR_P4 = 0x0E RX_ADDR_P5 = 0x0F TX_ADDR = 0x10 RX_PW_P0 = 0x11 RX_PW_P1 = 0x12 RX_PW_P2 = 0x13 RX_PW_P3 = 0x14 RX_PW_P4 = 0x15 RX_PW_P5 = 0x16 FIFO_STATUS = 0x17 DYNPD = 0x1C FEATURE = 0x1D # Bit Mask Mnemonics - CONFIG register MASK_RX_DR = 0x40 MASK_TX_DS = 0x20 MASK_MAX_RT = 0x10 EN_CRC = 0x08 CRCO = 0x04 PWR_UP = 0x02 PRIM_RX = 0x01 # Bit Mask Mnemonics - STATUS register RX_DR = 0x40 TX_DS = 0x20 MAX_RT = 0x10 TX_FULL = 0x01 RX_P_NO_MASK = 0x0E # isolate pipe number # Bit Mask Mnemonics - FIFO_STATUS register TX_REUSE = 0x40 TXFIFO_FULL = 0x20 TXFIFO_EMPTY = 0x10 RXFIFO_FULL = 0x02 RXFIFO_EMPTY = 0x01 # Bit Mask Mnemonics - DYNPD register DPL_P5 = 0x20 DPL_P4 = 0x10 DPL_P3 = 0x08 DPL_P2 = 0x04 DPL_P1 = 0x02 DPL_P0 = 0x01 # Bit Mask Mnemonics - FEATURE register EN_DPL = 0x04 EN_ACK_PAY = 0x02 EN_DYN_ACK = 0x01 # Shift counts ARD = 4 ARC = 0 PLOS_CNT = 4 ARC_CNT = 0 RX_P_NO = 1 # Instruction Mnemonics R_REGISTER = 0x00 W_REGISTER = 0x20 REGISTER_MASK = 0x1F ACTIVATE = 0x50 R_RX_PL_WID = 0x60 R_RX_PAYLOAD = 0x61 W_TX_PAYLOAD = 0xA0 W_ACK_PAYLOAD = 0xA8 FLUSH_TX = 0xE1 FLUSH_RX = 0xE2 REUSE_TX_PL = 0xE3 NOP = 0xFF # Non-P omissions LNA_HCURR = 0x01 LNA_ON = 1 LNA_OFF = 0 # P model Mask Mnemonics RF_DR_LOW = 0x20 RF_DR_HIGH = 0x08 RF_PWR_LOW = 0x02 RF_PWR_HIGH = 0x04 datarate_e_str_P = ["1MBPS", "2MBPS", "250KBPS"] model_e_str_P = ["nRF24L01", "nRF24l01+"] crclength_e_str_P = ["Disabled", "8 bits", "16 bits"] pa_dbm_e_str_P = ["PA_MIN", "PA_LOW", "PA_HIGH", "PA_MAX"] @staticmethod def print_single_status_line(name, value): """Prints name = value""" print("{0:<16}= {1}".format(name, value)) @staticmethod def _to_8b_list(data): """Convert an arbitray iteratable or single int to a list of ints where each int is smaller than 256.""" if isinstance(data, str): data = [ord(x) & 0xFF for x in data] elif isinstance(data, (int, long)): data = [data & 0xFF] else: data = [int(x) & 0xFF for x in data] return data def __init__(self, major=None, minor=None, ce_pin=None, irq_pin=None): """Construtor. major and minor selects SPI port, ce_pin is optional GPIO pin number for CE signal irq_pin is optional GPIO pin number for IRQ signal""" # defaults and miscelaneous initialization self.payload_size = 32 # *< Fixed size of payloads self.ack_payload_available = False # *< Whether there is an ack payload waiting self.dynamic_payloads_enabled = False # *< Whether dynamic payloads are enabled. self.ack_payload_length = 5 # *< Dynamic size of pending ack payload. self.pipe0_reading_address = None # *< Last address set on pipe 0 for reading. self.spidev = None self.last_error = 0 self.auto_ack = 0 self.address_length = 5 # If all parameters are available, lets start the radio! if major is not None and minor is not None and irq_pin is not None: self.begin(major, minor, ce_pin, irq_pin) def begin(self, major, minor, ce_pin, irq_pin): """Radio initialization, must be called before anything else. major and minor selects SPI port, ce_pin is GPIO pin number for CE signal irq_pin is optional GPIO pin number for IRQ signal""" # Initialize SPI bus if ADAFRUID_BBIO_SPI: self.spidev = SPI(major, minor) self.spidev.bpw = 8 try: self.spidev.msh = 10000000 # Maximum supported by NRF24L01+ except IOError: pass # Hardware does not support this speed else: self.spidev = spidev.SpiDev() self.spidev.open(major, minor) self.spidev.bits_per_word = 8 try: self.spidev.max_speed_hz = 10000000 # Maximum supported by NRF24L01+ except IOError: pass # Hardware does not support this speed self.spidev.cshigh = False self.spidev.mode = 0 self.spidev.loop = False self.spidev.lsbfirst = False self.spidev.threewire = False # Save pin numbers self.ce_pin = ce_pin self.irq_pin = irq_pin # If CE pin is not used, CE signal must be always high if self.ce_pin is not None: GPIO.setup(self.ce_pin, GPIO.OUT) # IRQ pin is optional if self.irq_pin is not None: GPIO.setup(self.irq_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) time.sleep(5 / 1000000.0) # Reset radio registers self.reset() # Restore our default PA level self.setPALevel(NRF24.PA_MAX) # Determine if this is a p or non-p RF24 module and then # reset our data rate back to default value. This works # because a non-P variant won't allow the data rate to # be set to 250Kbps. self.p_variant = False # False for RF24L01 and true for RF24L01P if self.setDataRate(NRF24.BR_250KBPS): self.p_variant = True # Then set the data rate to the slowest (and most reliable) speed supported by all # hardware. self.setDataRate(NRF24.BR_1MBPS) # Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier # WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet # sizes must never be used. See documentation for a more complete explanation. # This must be done after setDataRate() self.setRetries(int('0101', 2), 15) # Line bellow will set maximum (4ms) delay #self.setRetries(15, 15) # Initialize CRC and request 2-byte (16bit) CRC self.setCRCLength(NRF24.CRC_16) # Disable dynamic payloads, to match dynamic_payloads_enabled setting self.write_register(NRF24.DYNPD, 0) # Set up default configuration. Callers can always change it later. # This channel should be universally safe and not bleed over into adjacent # spectrum. self.channel = 76 self.setChannel(self.channel) # Powers up the radio, this can take up to 4.5ms # when CE is low radio will be in standby and will initiate # reception or transmission very shortly after CE is raised # If CE pin is not used, will Power up only on startListening and stopListening if self.ce_pin is not None: self.powerUp() # Reset current status # Notice reset and flush is the last thing we do self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) # Flush buffers self.flush_rx() self.flush_tx() self.clear_irq_flags() def end(self): """ End use of the radio """ self.ce(0) if self.spidev: self.powerDown() self.spidev.close() self.spidev = None def startListening(self): """ Set radio for reception Use openReadingPipe to set up reception pipes before listening """ self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP | NRF24.PRIM_RX) self.flush_tx() self.flush_rx() self.clear_irq_flags() # Restore the pipe0 address, if exists if self.pipe0_reading_address: self.write_register(self.RX_ADDR_P0, self.pipe0_reading_address) # Go! self.ce(1) # wait for the radio to come up if self.ce_pin is None: time.sleep(45 / 10000.0) # 4.5 ms else: time.sleep(130 / 1000000.0) # 130us def ce(self, level, pulse=0): """ Controls CE pin """ # CE Pin is optional (but highly recommended) if self.ce_pin is not None: GPIO.output(self.ce_pin, level) if pulse > 0: time.sleep(pulse) GPIO.output(self.ce_pin, 1 - level) def irqWait(self, timeout=30000): """ Wait for IRQ pin LOW, timeout in miliseconds """ if self.irq_pin is None: return True # TODO: A race condition may occur here. => wait for level? if GPIO.input(self.irq_pin) == 0: # Pin is already down. Packet is waiting? return True try: return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING, timeout) == 1 except TypeError: # Timeout parameter not supported return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING) == 1 except AttributeError: raise RuntimeError("GPIO lib does not support wait_for_edge()") def read_register(self, reg, length=1): """ Read one or more registers """ buf = [NRF24.R_REGISTER | (NRF24.REGISTER_MASK & reg)] buf += [NRF24.NOP] * max(1, length) resp = self.spidev.xfer2(buf) if length == 1: return resp[1] return resp[1:] def write_register(self, reg, value): """ Write register value """ buf = [NRF24.W_REGISTER | (NRF24.REGISTER_MASK & reg)] buf += self._to_8b_list(value) self.spidev.xfer2(buf) def write_payload(self, buf): """ Writes data to the payload register, automatically padding it to match the required length. Returns the number of bytes actually written. """ buf = self._to_8b_list(buf) if self.dynamic_payloads_enabled: if len(buf) > self.MAX_PAYLOAD_SIZE: raise RuntimeError("Dynamic payload is larger than the " + "maximum size.") blank_len = 0 else: if len(buf) > self.payload_size: raise RuntimeError("Payload is larger than the fixed payload" + "size (%d vs. %d bytes)" % (len(buf), self.payload_size)) blank_len = self.payload_size - len(buf) txbuffer = [NRF24.W_TX_PAYLOAD] + buf + ([0x00] * blank_len) self.spidev.xfer2(txbuffer) return len(txbuffer) - 1 def read_payload(self, buf, buf_len=-1): """ Reads data from the payload register and clears the DR bit of the STATUS register. """ if buf_len < 0: buf_len = self.payload_size if not self.dynamic_payloads_enabled: data_len = min(self.payload_size, buf_len) blank_len = self.payload_size - data_len else: data_len = self.getDynamicPayloadSize() blank_len = 0 txbuffer = [NRF24.R_RX_PAYLOAD] + [NRF24.NOP] * (blank_len + data_len) payload = self.spidev.xfer2(txbuffer) del buf[:] buf += payload[1:data_len + 1] self.write_register(NRF24.STATUS, NRF24.RX_DR) return data_len def flush_rx(self): """ Flush RX buffer, return status """ return self.spidev.xfer2([NRF24.FLUSH_RX])[0] def flush_tx(self): """ Flush TX buffer, return status """ return self.spidev.xfer2([NRF24.FLUSH_TX])[0] def get_status(self): """ Read status register """ return self.spidev.xfer2([NRF24.NOP])[0] def print_status(self, status): """ Print decoded status """ status_str = "0x{0:02x} RX_DR={1:x} TX_DS={2:x} MAX_RT={3:x} RX_P_NO={4:x} TX_FULL={5:x}".format( status, 1 if status & NRF24.RX_DR else 0, 1 if status & NRF24.TX_DS else 0, 1 if status & NRF24.MAX_RT else 0, ((status >> NRF24.RX_P_NO) & int("111", 2)), 1 if status & NRF24.TX_FULL else 0) self.print_single_status_line("STATUS", status_str) def print_observe_tx(self, value): """ Print decoded observe_tx register: lost packets (accumulated) and retransmited packets (last tx) """ tx_str = "OBSERVE_TX=0x{0:02x}: POLS_CNT={2:x} ARC_CNT={2:x}\r\n".format( value, (value >> NRF24.PLOS_CNT) & int("1111", 2), (value >> NRF24.ARC_CNT) & int("1111", 2)) self.print_single_status_line("OBSERVE_TX", tx_str) def print_byte_register(self, name, reg, qty=1): """ Print byte registers """ registers = ["0x{:0>2x}".format(self.read_register(reg+r)) for r in range(0, qty)] self.print_single_status_line(name, " ".join(registers)) def print_address_register(self, name, reg, qty=1): """ Print address register (LSB to MSB) """ address_registers = ["0x{0:>02x}{1:>02x}{2:>02x}{3:>02x}{4:>02x}".format( *self.read_register(reg+r, 5)) for r in range(qty)] self.print_single_status_line(name, " ".join(address_registers)) def setChannel(self, channel): """ Set radio channel (0 to MAX_CHANNEL) """ if channel < 0 or channel > self.MAX_CHANNEL: raise RuntimeError("Channel number out of range") self.channel = channel self.write_register(NRF24.RF_CH, channel) def getChannel(self): """ Read channel register """ return self.read_register(NRF24.RF_CH) def setPayloadSize(self, size): """ Set payload size """ self.payload_size = min(max(size, 1), NRF24.MAX_PAYLOAD_SIZE) def getPayloadSize(self): """ Get payload size """ return self.payload_size def printDetails(self): """ Prints register values and other information """ self.print_status(self.get_status()) self.print_address_register("RX_ADDR_P0-1", NRF24.RX_ADDR_P0, 2) self.print_byte_register("RX_ADDR_P2-5", NRF24.RX_ADDR_P2, 4) self.print_address_register("TX_ADDR", NRF24.TX_ADDR) self.print_byte_register("RX_PW_P0-6", NRF24.RX_PW_P0, 6) self.print_byte_register("EN_AA", NRF24.EN_AA) self.print_byte_register("EN_RXADDR", NRF24.EN_RXADDR) self.print_byte_register("RF_CH", NRF24.RF_CH) self.print_byte_register("RF_SETUP", NRF24.RF_SETUP) self.print_byte_register("SETUP_AW", NRF24.SETUP_AW) self.print_byte_register("OBSERVE_TX", NRF24.OBSERVE_TX) self.print_byte_register("CONFIG", NRF24.CONFIG) self.print_byte_register("FIFO_STATUS", NRF24.FIFO_STATUS) self.print_byte_register("DYNPD", NRF24.DYNPD) self.print_byte_register("FEATURE", NRF24.FEATURE) self.print_single_status_line("Data Rate", NRF24.datarate_e_str_P[self.getDataRate()]) self.print_single_status_line("Model", NRF24.model_e_str_P[self.isPVariant()]) self.print_single_status_line("CRC Length", NRF24.crclength_e_str_P[self.getCRCLength()]) self.print_single_status_line("PA Power", NRF24.pa_dbm_e_str_P[self.getPALevel()]) def stopListening(self): """ Stop listenning and set up transmission """ self.ce(0) self.flush_tx() self.flush_rx() self.clear_irq_flags() # Enable TX self.write_register(NRF24.CONFIG, (self.read_register(NRF24.CONFIG) | NRF24.PWR_UP) & ~NRF24.PRIM_RX) # Enable pipe 0 for auto-ack self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | 1) # wait for the radio to come up if self.ce_pin is None: time.sleep(45 / 10000.0) # 4.5 ms else: time.sleep(130 / 1000000.0) # 130us def powerDown(self): """ Power down radio """ self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) & ~ NRF24.PWR_UP) def powerUp(self): """ Power up radio """ self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP) time.sleep(4.5e-3) def write(self, buf): """ Sends buf and wait for end of transmission and acknowledgement call stopListenning and openWritingPipe before sending buf can be a single int or a container of char or int """ self.last_error = None length = self.write_payload(buf) self.ce(1) sent_at = monotonic() packet_time = ((1 + length + self.crc_length + self.address_length) * 8 + 9)/(self.data_rate_bits * 1000.) if self.auto_ack != 0: packet_time *= 2 if self.retries != 0 and self.auto_ack != 0: timeout = sent_at + (packet_time + self.delay)*self.retries else: timeout = sent_at + packet_time * 2 # 2 is empiric while monotonic() < timeout: time.sleep(packet_time) status = self.get_status() if status & NRF24.TX_DS: self.ce(0) return True if status & NRF24.MAX_RT: self.last_error = 'MAX_RT' self.ce(0) break self.ce(0) if self.last_error is None: self.last_error = 'TIMEOUT' self.flush_tx() # Avoid leaving the payload in tx fifo return False def startFastWrite(self, buf): """ Starts sending of buf but do not wait for end of transmission. CE is left high.""" self.write_payload(buf) self.ce(1) def startWrite(self, buf): """ Starts sending of buf but do not wait for end of transmission. CE is pulsed.""" self.write_payload(buf) self.ce(1, 10e-6) # Pulse CE to start tranmission def getDynamicPayloadSize(self): """ Reads the size of received payload when using dynamic payloads """ return self.spidev.xfer2([NRF24.R_RX_PL_WID, NRF24.NOP])[1] def available(self, pipe_num=None, irq_wait=False, irq_timeout=30000): """ Tests if there is a reception available pipe_num should be None or a list. If not None, it will receive information on pipes with available data. if irq_wait is True, will wait for IRQ line to change from HIGH to LOW irq_timeout is the timeout for this wait, in miliseconds """ status = self.get_status() result = False # Sometimes the radio specifies that there is data in one pipe but # doesn't set the RX flag... if status & NRF24.RX_DR or (status & NRF24.RX_P_NO_MASK != NRF24.RX_P_NO_MASK): result = True else: if irq_wait: # Will use IRQ wait if self.irqWait(irq_timeout): # Do we have a packet? status = self.get_status() # Seems like we do! if status & NRF24.RX_DR or (status & NRF24.RX_P_NO_MASK != NRF24.RX_P_NO_MASK): result = True if pipe_num is not None: del pipe_num[:] if result: pipe_num.append((status & NRF24.RX_P_NO_MASK) >> NRF24.RX_P_NO) # Handle ack payload receipt if status & NRF24.TX_DS: self.write_register(NRF24.STATUS, NRF24.TX_DS) return result def read(self, buf, buf_len=-1): """ Read payload from received packet. Returns != 0 if there are more packets in the FIFO. """ # Fetch the payload self.read_payload(buf, buf_len) # was this the last of the data available? return self.read_register(NRF24.FIFO_STATUS) & NRF24.RXFIFO_EMPTY def clear_irq_flags(self): """ Clear flags in status register. """ self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) def whatHappened(self): """ Read the status & reset the status in one easy call Returns a dictionary informing tx_ok, tx_fail and rx_ready """ status = self.spidev.xfer2(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT)[0] # Report to the user what happened tx_ok = status & NRF24.TX_DS tx_fail = status & NRF24.MAX_RT rx_ready = status & NRF24.RX_DR return {'tx_ok': tx_ok, "tx_fail": tx_fail, "rx_ready": rx_ready} def openWritingPipe(self, address): """ Sets tx address address is the address in transmited packet (2 to 5 bytes), LSB to MSB """ self.write_register(NRF24.RX_ADDR_P0, address) self.write_register(NRF24.TX_ADDR, address) if not self.dynamic_payloads_enabled: self.write_register(NRF24.RX_PW_P0, self.payload_size) def openReadingPipe(self, pipe, address): """ Sets rx address for a pipe and enables it for recieving pipe should be 0 to 5 address is the address for pipe 0 or 1, 2 to 5 bytes LSB to MSB for pipes 2 to 5, 1 byte (LSB, MSB cames from pipe 1) """ if pipe >= 6: raise RuntimeError("Invalid pipe number") if (pipe >= 2 and len(address) > 1) or len(address) > 5: raise RuntimeError("Invalid adress length") # If this is pipe 0, cache the address. This is needed because # openWritingPipe() will overwrite the pipe 0 address, so # startListening() will have to restore it. if pipe == 0: self.pipe0_reading_address = address self.write_register(NRF24.RX_ADDR_P0 + pipe, address) if not self.dynamic_payloads_enabled: self.write_register(NRF24.RX_PW_P0 + pipe, self.payload_size) # Note it would be more efficient to set all of the bits for all open # pipes at once. However, I thought it would make the calling code # more simple to do it this way. self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | (1 << pipe)) def closeReadingPipe(self, pipe): """ Disabe a receiving pipe """ self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) & ~(1 << pipe)) def toggle_features(self): """ Enable DUNPD and FEATURE registers on non P variant """ buf = [NRF24.ACTIVATE, 0x73] self.spidev.xfer2(buf) def enableDynamicPayloads(self): """ Enables dynamic size payloads """ # First try writing to the features self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_DPL) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_DPL) # Enable dynamic payload on all pipes # Not sure the use case of only having dynamic payload on certain # pipes, so the library does not support it. self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | 0b00111111) self.dynamic_payloads_enabled = True def enableAckPayload(self): """ Enable ack payload and dynamic payload features """ # First try writing to the features self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_ACK_PAY | NRF24.EN_DPL) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_ACK_PAY | NRF24.EN_DPL) # Enable dynamic payload on pipes 0 & 1 self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | NRF24.DPL_P1 | NRF24.DPL_P0) def writeAckPayload(self, pipe, buf, buf_len): """ Write payload for acknowledgement """ txbuffer = [NRF24.W_ACK_PAYLOAD | (pipe & 0x7)] max_payload_size = 32 data_len = min(buf_len, max_payload_size) txbuffer.extend(buf[0:data_len]) self.spidev.xfer2(txbuffer) def isAckPayloadAvailable(self): """ Check if there is a payload in a acknowledgement. Note: this will clear the ack payload flag. """ result = self.ack_payload_available self.ack_payload_available = False return result def isPVariant(self): """ Returns true if nRF24L01+, False if nRF24L01 """ return self.p_variant def setAutoAck(self, enable): """ Enable or disable auto acknoledge for all pipes """ if enable: self.write_register(NRF24.EN_AA, 0x3F) self.auto_ack = 0x3f if self.self.getCRCLength() == NFR24.CRC_DISABLED: self.setCRCLength(NRF24.CRC_8) # Enhanced Shockburst requires at least 1 byte CRC else: self.auto_ack = 0 self.write_register(NRF24.EN_AA, 0) def setAutoAckPipe(self, pipe, enable): """ Enable or disable auto acknoledge for an specific pipe """ if pipe <= 6: en_aa = self.read_register(NRF24.EN_AA) if enable: if self.self.getCRCLength() == NFR24.CRC_DISABLED: self.setCRCLength(NRF24.CRC_8) # Enhanced Shockburst requires at least 1 byte CRC en_aa |= 1 << pipe self.auto_ack |= 1 << pipe else: en_aa &= ~1 << pipe self.auto_ack &= ~1 << pipe self.write_register(NRF24.EN_AA, en_aa) def setAddressWidth(self, width): """ Set address width (2 to 5 bytes) """ if width >= 2 and width <= 5: self.write_register(NRF24.SETUP_AW, width - 2) self.address_width = width def testCarrier(self): """ Tests if there is a radio signal at current channel. """ return self.read_register(NRF24.RPD) & 1 def setPALevel(self, level): """ Set transmission level """ setup = self.read_register(NRF24.RF_SETUP) setup &= ~(NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH) if level == NRF24.PA_MAX: setup |= NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH elif level == NRF24.PA_HIGH: setup |= NRF24.RF_PWR_HIGH elif level == NRF24.PA_LOW: setup |= NRF24.RF_PWR_LOW elif level == NRF24.PA_MIN: pass elif level == NRF24.PA_ERROR: # On error, go to maximum PA setup |= NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH self.write_register(NRF24.RF_SETUP, setup) def getPALevel(self): """ Inform current transmission level """ power = self.read_register(NRF24.RF_SETUP) & (NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH) if power == (NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH): return NRF24.PA_MAX elif power == NRF24.RF_PWR_HIGH: return NRF24.PA_HIGH elif power == NRF24.RF_PWR_LOW: return NRF24.PA_LOW else: return NRF24.PA_MIN def setDataRate(self, speed): """ Set data rate. returns True if success. """ setup = self.read_register(NRF24.RF_SETUP) setup &= ~(NRF24.RF_DR_LOW | NRF24.RF_DR_HIGH) if speed == NRF24.BR_250KBPS: # Must set the RF_DR_LOW to 1 RF_DR_HIGH (used to be RF_DR) is already 0 # Making it '10'. self.data_rate_bits = 250 self.data_rate = NRF24.BR_250KBPS setup |= NRF24.RF_DR_LOW elif speed == NRF24.BR_2MBPS: # Set 2Mbs, RF_DR (RF_DR_HIGH) is set 1 # Making it '01' self.data_rate_bits = 2000 self.data_rate = NRF24.BR_2MBPS setup |= NRF24.RF_DR_HIGH else: # 1Mbs self.data_rate_bits = 1000 self.data_rate = NRF24.BR_1MBPS self.write_register(NRF24.RF_SETUP, setup) # Verify our result return self.read_register(NRF24.RF_SETUP) == setup def getDataRate(self): """ Inform current data rate """ dr = self.read_register(NRF24.RF_SETUP) & (NRF24.RF_DR_LOW | NRF24.RF_DR_HIGH) # Order matters in our case below if dr == NRF24.RF_DR_LOW: # '10' = 250KBPS return NRF24.BR_250KBPS elif dr == NRF24.RF_DR_HIGH: # '01' = 2MBPS return NRF24.BR_2MBPS else: # '00' = 1MBPS return NRF24.BR_1MBPS def setCRCLength(self, length): """ Set CRC length length = CRC_DISABLED, CRC_8 or CRC_16 """ config = self.read_register(NRF24.CONFIG) & ~(NRF24.EN_CRC | NRF24.CRCO) if length == NRF24.CRC_DISABLED: self.crc_length = 0 elif length == NRF24.CRC_8: config |= NRF24.EN_CRC self.crc_length = 1 else: config |= NRF24.EN_CRC config |= NRF24.CRCO self.crc_length = 2 self.write_register(NRF24.CONFIG, config) def getCRCLength(self): """ Get CRC length returns CRC_DISABLED, CRC_8 or CRC_16 """ result = NRF24.CRC_DISABLED config = self.read_register(NRF24.CONFIG) & (NRF24.CRCO | NRF24.EN_CRC) if config & NRF24.EN_CRC: if config & NRF24.CRCO: result = NRF24.CRC_16 else: result = NRF24.CRC_8 return result def disableCRC(self): """ Disable CRC """ disable = self.read_register(NRF24.CONFIG) & ~NRF24.EN_CRC self.write_register(NRF24.CONFIG, disable) def setRetries(self, delay, count): """ Set timeout and number of retries delay (timeout) 0-15 as per datasheet count 0-15 max number of retries (0=disable retries)""" self.write_register(NRF24.SETUP_RETR, (delay & 0xf) << NRF24.ARD | (count & 0xf) << NRF24.ARC) self.delay = delay * 0.000250 self.retries = count self.max_timeout = (self.payload_size / float(self.data_rate_bits) + self.delay) * self.retries self.timeout = (self.payload_size / float(self.data_rate_bits) + self.delay) def getRetries(self): """ Return current retry configuration. """ return self.read_register(NRF24.SETUP_RETR) def getMaxTimeout(self): """ Return current maximum timeout (no ack after all retries). """ return self.max_timeout def getTimeout(self): """ Return current timeout for one transmission. """ return self.timeout def reset(self): """ Make sure the NRF is in the same state as after power up to avoid problems resulting from left over configuration from other programs.""" self.ce(0) reset_values = {0: 0x08, 1: 0x3F, 2: 0x03, 3: 0x03, 4: 0x03, 5: 0x02, 6: 0x0e, 0x0a: [0xe7, 0xe7, 0xe7, 0xe7, 0xe7], 0x0b: [0xc2, 0xc2, 0xc2, 0xc2, 0xc2], 0x0c: 0xc3, 0x0d: 0xc4, 0x0e: 0xc5, 0x0f: 0xc6, 0x10: [0xe7, 0xe7, 0xe7, 0xe7, 0xe7], 0x11: 0, 0x12: 0, 0x13: 0, 0x14: 0, 0x15: 0, 0x16: 0, 0x1c: 0, 0x1d: 0} for reg, value in reset_values.items(): self.write_register(reg, value) self.flush_rx() self.flush_tx()
class ltc1858: def __init__(self, spi_bus = 0, spi_client = 0, spi_freq = 1000000, spi_mode = 0b00, RD = "P9_12"): #define pins self.logger = logging.getLogger('LTC1858') self.logger.setLevel(logging.WARNING) self.spi_bus = spi_bus self.spi_client = spi_client self.spi_freq = spi_freq #1Mhz is plenty self.spi_mode = spi_mode """We actually send 16 bits but the SPI protocol is a bit screwy It's just easier currently to send two 8 bit words as protocol is broken""" self.spi_bits_per_word = 8 self.spi_cshigh = False #Need the RD set to low to get data - Could do something #more fancy with this later self.RD = RD self.data_in = BitArray(14) self.vrange = {"+-5V" : 0b00, "+5V" : 0b10, "+-10V" : 0b01, "+10V" : 0b11} #Create a chan dict as not standard binary self.chans = {0 : 0b000, 1 : 0b100, 2 : 0b001, 3 : 0b101, 4 : 0b010, 5 : 0b110, 6 : 0b011, 7 : 0b111} self.adc_reg = {"Monitor" : False, "Range" : "+5V", "V" : 0, "Command" : 0} #Bitstring is terribly slow so for a register #read we use a preconstructed bitstring rather #Than create every time self.chip_reg = [] for i in xrange(8): self.chip_reg.append(self.adc_reg.copy()) self.single_ended = 0b1 self.setup_chip() self.setup_spi() def setup_spi(self): #This is for BB Black self.spi = SPI(self.spi_bus, self.spi_client) self.spi.msh = self.spi_freq self.spi.mode = self.spi_mode self.bpw = self.spi_bits_per_word self.spi.cshigh = self.spi_cshigh def setup_chip(self): #Just need to setup RD and make sure it is low GPIO.setup(self.RD, GPIO.OUT) GPIO.output(self.RD, False) def set_reg(self,adc,monitor,adc_range): self.chip_reg[adc]["Monitor"] = monitor self.chip_reg[adc]["Range"] = adc_range self.chip_reg[adc]["Command"] = self.construct_word(adc,adc_range) def construct_word(self, chan_no, vrange): t_word = BitArray(8) t_word[0] = self.single_ended t_word[1:4] = self.chans[chan_no] t_word[4:6] = self.vrange[vrange] #Ignore nap and sleep return t_word def single_read(self, chan_no, v_range): #Need to set command and then read back so #two words - Just send the same word twice #self.send_data(self.construct_word(chan_no, v_range)) data_out = self.send_data(self.construct_word(chan_no, v_range)) data_conv = self.convert_to_v(data_out, v_range) return data_conv def register_read(self): #This does one pass at reading all dac inputs for i in xrange(8): if self.chip_reg[i]["Monitor"] is True: data_out = self.send_data(self.chip_reg[i]["Command"]) vv = self.convert_to_v(data_out, self.chip_reg[i]["Range"]) self.chip_reg[i]["V"] = vv def send_data(self,data): self.spi.writebytes([data.uint,0x00]) #Send data then zeros as per DS #at 1MHz we don't care if it's duplex read a,b = self.spi.readbytes(2) self.data_in[0:8] = a self.data_in[8:] = (b >> 2) return self.data_in def convert_to_v(self,num, v_range): if v_range == "+5V": return 5.0*num.uint/2**14 elif v_range == "+10V": return 10.0*num.uint/2**14 elif v_range == "+-5V": return num.int*5.0/2**13 elif v_range == "+-10V": return num.int*10.0/2**13 else: return -69
class NRF24: MAX_CHANNEL = 127 MAX_PAYLOAD_SIZE = 32 # PA Levels PA_MIN = 0x00 PA_LOW = 0x01 PA_HIGH = 0x02 PA_MAX = 0x03 PA_ERROR = 0x04 # Bit rates BR_1MBPS = 0 BR_2MBPS = 1 BR_250KBPS = 2 # CRC CRC_DISABLED = 0x0 CRC_8 = 0x02 CRC_16 = 0x04 CRC_ENABLED = 0x08 EN_CRC = 0x08 CRCO = 0x04 # Registers CONFIG = 0x00 EN_AA = 0x01 EN_RXADDR = 0x02 SETUP_AW = 0x03 SETUP_RETR = 0x04 RF_CH = 0x05 RF_SETUP = 0x06 STATUS = 0x07 OBSERVE_TX = 0x08 RPD = 0x09 RX_ADDR_P0 = 0x0A RX_ADDR_P1 = 0x0B RX_ADDR_P2 = 0x0C RX_ADDR_P3 = 0x0D RX_ADDR_P4 = 0x0E RX_ADDR_P5 = 0x0F TX_ADDR = 0x10 RX_PW_P0 = 0x11 RX_PW_P1 = 0x12 RX_PW_P2 = 0x13 RX_PW_P3 = 0x14 RX_PW_P4 = 0x15 RX_PW_P5 = 0x16 FIFO_STATUS = 0x17 DYNPD = 0x1C FEATURE = 0x1D # Bit Mnemonics */ MASK_RX_DR = 0x40 MASK_TX_DS = 0x20 MASK_MAX_RT = 0x10 PWR_UP = 0x02 PRIM_RX = 0x01 PLL_LOCK = 0x10 RX_DR = 0x40 TX_DS = 0x20 MAX_RT = 0x10 TX_FULL = 0x01 EN_DPL = 0x04 EN_ACK_PAY = 0x02 EN_DYN_ACK = 0x01 # Shift counts ARD = 4 ARC = 0 PLOS_CNT = 4 ARC_CNT = 0 RX_P_NO = 1 TX_REUSE = 6 FIFO_FULL = 5 TX_EMPTY = 4 RX_FULL = 1 RX_EMPTY = 0 DPL_P5 = 5 DPL_P4 = 4 DPL_P3 = 3 DPL_P2 = 2 DPL_P1 = 1 DPL_P0 = 0 #Masks RX_P_NO_MASK = 0x0E # Instruction Mnemonics R_REGISTER = 0x00 W_REGISTER = 0x20 REGISTER_MASK = 0x1F ACTIVATE = 0x50 R_RX_PL_WID = 0x60 R_RX_PAYLOAD = 0x61 W_TX_PAYLOAD = 0xA0 W_ACK_PAYLOAD = 0xA8 FLUSH_TX = 0xE1 FLUSH_RX = 0xE2 REUSE_TX_PL = 0xE3 NOP = 0xFF # Non-P omissions LNA_HCURR = 0x01 LNA_ON = 1 LNA_OFF = 0 # P model bit Mnemonics RF_DR_LOW = 0x20 RF_DR_HIGH = 0x08 RF_PWR_LOW = 0x02 RF_PWR_HIGH = 0x04 datarate_e_str_P = ["1MBPS", "2MBPS", "250KBPS"] model_e_str_P = ["nRF24L01", "nRF24l01+"] crclength_e_str_P = ["Disabled", "", "8 bits", "", "16 bits"] pa_dbm_e_str_P = ["PA_MIN", "PA_LOW", "PA_HIGH", "PA_MAX"] @staticmethod def print_single_status_line(name, value): print("{0:<16}= {1}".format(name, value)) @staticmethod def _to_8b_list(data): """Convert an arbitray iteratable or single int to a list of ints where each int is smaller than 256.""" if isinstance(data, str): data = [ord(x) for x in data] elif isinstance(data, (int, long)): data = [data] else: data = [int(x) for x in data] #for byte in data: # if byte < 0 or byte > 255: # raise RuntimeError("Value %d is larger than 8 bits" % byte) return data def __init__(self, major=None, minor=None, ce_pin=None, irq_pin=None): self.ce_pin = "P9_15" self.irq_pin = "P9_16" self.channel = 76 self.data_rate = NRF24.BR_1MBPS self.data_rate_bits = 1000 self.p_variant = False # False for RF24L01 and true for RF24L01P self.payload_size = 5 # *< Fixed size of payloads self.ack_payload_available = False # *< Whether there is an ack payload waiting self.dynamic_payloads_enabled = False # *< Whether dynamic payloads are enabled. self.ack_payload_length = 5 # *< Dynamic size of pending ack payload. self.pipe0_reading_address = None # *< Last address set on pipe 0 for reading. self.spidev = None self.last_error = 0 self.crc_length = 0 self.auto_ack = 0x3F self.address_length = 5 # If all parameters are available, lets start the radio! if major is not None and minor is not None and irq_pin is not None: self.begin(major, minor, ce_pin, irq_pin) def begin(self, major, minor, ce_pin, irq_pin): # Initialize SPI bus if ADAFRUID_BBIO_SPI: self.spidev = SPI(major, minor) self.spidev.bpw = 8 try: self.spidev.msh = 10000000 # Maximum supported by NRF24L01+ except IOError: pass # Hardware does not support this speed else: self.spidev = spidev.SpiDev() self.spidev.open(major, minor) self.spidev.bits_per_word = 8 try: self.spidev.max_speed_hz = 10000000 # Maximum supported by NRF24L01+ except IOError: pass # Hardware does not support this speed self.spidev.cshigh = False self.spidev.mode = 0 self.spidev.loop = False self.spidev.lsbfirst = False self.spidev.threewire = False self.ce_pin = ce_pin self.irq_pin = irq_pin if self.ce_pin is not None: GPIO.setup(self.ce_pin, GPIO.OUT) GPIO.setup(self.irq_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) time.sleep(5 / 1000000.0) # Reset radio configuration self.reset() # Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier # WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet # sizes must never be used. See documentation for a more complete explanation. self.setRetries(int('0101', 2), 15) # Restore our default PA level self.setPALevel(NRF24.PA_MAX) # Determine if this is a p or non-p RF24 module and then # reset our data rate back to default value. This works # because a non-P variant won't allow the data rate to # be set to 250Kbps. if self.setDataRate(NRF24.BR_250KBPS): self.p_variant = True # Then set the data rate to the slowest (and most reliable) speed supported by all # hardware. self.setDataRate(NRF24.BR_1MBPS) # Initialize CRC and request 2-byte (16bit) CRC self.setCRCLength(NRF24.CRC_16) # Disable dynamic payloads, to match dynamic_payloads_enabled setting self.write_register(NRF24.DYNPD, 0) # Reset current status # Notice reset and flush is the last thing we do self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) # Set up default configuration. Callers can always change it later. # This channel should be universally safe and not bleed over into adjacent # spectrum. self.setChannel(self.channel) self.setRetries(15, 15) # Flush buffers self.flush_rx() self.flush_tx() self.clear_irq_flags() def end(self): if self.spidev: self.spidev.close() self.spidev = None def startListening(self): self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP | NRF24.PRIM_RX) self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) self.flush_tx() self.flush_rx() self.clear_irq_flags() # Restore the pipe0 address, if exists if self.pipe0_reading_address: self.write_register(self.RX_ADDR_P0, self.pipe0_reading_address) # Go! self.ce(1) def ce(self, level, pulse=0): # CE Pin is optional if self.ce_pin is not None: GPIO.output(self.ce_pin, level) if pulse > 0: time.sleep(pulse) GPIO.output(self.ce_pin, 1 - level) def irqWait(self, timeout=30000): # TODO: A race condition may occur here. => wait for level? if GPIO.input(self.irq_pin) == 0: # Pin is already down. Packet is waiting? return True try: return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING, timeout) == 1 except TypeError: # Timeout parameter not supported return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING) == 1 except AttributeError: raise RuntimeError("GPIO lib does not support wait_for_edge()") def read_register(self, reg, length=1): buf = [NRF24.R_REGISTER | (NRF24.REGISTER_MASK & reg)] buf += [NRF24.NOP] * max(1, length) resp = self.spidev.xfer2(buf) if length == 1: return resp[1] return resp[1:] def write_register(self, reg, value): """ Write register value """ buf = [NRF24.W_REGISTER | (NRF24.REGISTER_MASK & reg)] buf += self._to_8b_list(value) self.spidev.xfer2(buf) def write_payload(self, buf): """ Writes data to the payload register, automatically padding it to match the required length. Returns the number of bytes actually written. """ buf = self._to_8b_list(buf) if self.dynamic_payloads_enabled: if len(buf) > self.MAX_PAYLOAD_SIZE: raise RuntimeError("Dynamic payload is larger than the " + "maximum size.") blank_len = 0 else: if len(buf) > self.payload_size: raise RuntimeError("Payload is larger than the fixed payload" + "size (%d vs. %d bytes)" % (len(buf), self.payload_size)) blank_len = self.payload_size - len(buf) txbuffer = [NRF24.W_TX_PAYLOAD] + buf + ([0x00] * blank_len) self.spidev.xfer2(txbuffer) return len(txbuffer) - 1 def read_payload(self, buf, buf_len=-1): """ Reads data from the payload register and sets the DR bit of the STATUS register. """ if buf_len < 0: buf_len = self.payload_size if not self.dynamic_payloads_enabled: data_len = min(self.payload_size, buf_len) blank_len = self.payload_size - data_len else: data_len = self.getDynamicPayloadSize() blank_len = 0 txbuffer = [NRF24.R_RX_PAYLOAD] + [NRF24.NOP] * (blank_len + data_len + 1) payload = self.spidev.xfer2(txbuffer) del buf[:] buf += payload[1:data_len + 1] self.write_register(NRF24.STATUS, NRF24.RX_DR) return data_len def flush_rx(self): return self.spidev.xfer2([NRF24.FLUSH_RX])[0] def flush_tx(self): return self.spidev.xfer2([NRF24.FLUSH_TX])[0] def get_status(self): return self.spidev.xfer2([NRF24.NOP])[0] def get_status_str(self, status): status_str = "STATUS\t = 0x{0:02x} RX_DR={1:x} TX_DS={2:x} MAX_RT={3:x} RX_P_NO={4:x} TX_FULL={5:x}".format( status, 1 if status & NRF24.RX_DR else 0, 1 if status & NRF24.TX_DS else 0, 1 if status & NRF24.MAX_RT else 0, ((status >> NRF24.RX_P_NO) & int("111", 2)), 1 if status & NRF24.TX_FULL else 0) return status_str def print_status(self, status): print self.get_status_str(status) def get_observe_tx_str(self, value): tx_str = "OBSERVE_TX=0x{0:02x}: POLS_CNT={2:x} ARC_CNT={2:x}\r\n".format( value, (value >> NRF24.PLOS_CNT) & int("1111",2), (value >> NRF24.ARC_CNT) & int("1111",2) ) return tx_str def print_observe_tx(self, value): print self.get_observe_tx_str(value) def get_byte_register_str(self, name, reg, qty=1): extra_tab = '\t' if len(name) < 8 else 0 byte_str= "%s\t%c =" % (name, extra_tab) while qty > 0: byte_str+= " 0x%02x" % (self.read_register(reg)) qty -= 1 reg += 1 return byte_str def print_byte_register(self, name, reg, qty=1): print self.get_address_register_str(name, reg, qty) def get_address_register_str(self, name, reg, qty=1): extra_tab = '\t' if len(name) < 8 else 0 addr_str = "%s\t%c =" % (name, extra_tab) while qty > 0: qty -= 1 buf = reversed(self.read_register(reg, 5)) reg += 1 addr_str+=" 0x" for i in buf: addr_str+="%02x" % i return addr_str def print_address_register(self, name, reg, qty=1): print self.get_address_register_str(name, reg, qty) self.print_single_status_line(name, " ".join(address_registers)) def setChannel(self, channel): if channel < 0 or channel > self.MAX_CHANNEL: raise RuntimeError("Channel number out of range") self.channel = channel self.write_register(NRF24.RF_CH, channel) def getChannel(self): return self.read_register(NRF24.RF_CH) def setPayloadSize(self, size): self.payload_size = min(max(size, 1), NRF24.MAX_PAYLOAD_SIZE) def getPayloadSize(self): return self.payload_size def getDetails(self): return "\n".join([self.get_status_str(self.get_status()), self.get_address_register_str("RX_ADDR_P0-1", NRF24.RX_ADDR_P0, 2), self.get_byte_register_str("RX_ADDR_P2-5", NRF24.RX_ADDR_P2, 4), self.get_address_register_str("TX_ADDR", NRF24.TX_ADDR), self.get_byte_register_str("RX_PW_P0-6", NRF24.RX_PW_P0, 6), self.get_byte_register_str("EN_AA", NRF24.EN_AA), self.get_byte_register_str("EN_RXADDR", NRF24.EN_RXADDR), self.get_byte_register_str("RF_CH", NRF24.RF_CH), self.get_byte_register_str("RF_SETUP", NRF24.RF_SETUP), self.get_byte_register_str("CONFIG", NRF24.CONFIG), self.get_byte_register_str("DYNPD/FEATURE", NRF24.DYNPD, 2), "Data Rate\t = %s" % NRF24.datarate_e_str_P[self.getDataRate()], "Model\t\t = %s" % NRF24.model_e_str_P[self.isPVariant()], "CRC Length\t = %s" % NRF24.crclength_e_str_P[self.getCRCLength()], "PA Power\t = %s" % NRF24.pa_dbm_e_str_P[self.getPALevel()]]) def printDetails(self): print self.getDetails() def stopListening(self): self.ce(0) self.flush_tx() self.flush_rx() self.clear_irq_flags() # Enable TX self.write_register(NRF24.CONFIG, (self.read_register(NRF24.CONFIG) | NRF24.PWR_UP) & ~NRF24.PRIM_RX) # Enable pipe 0 for auto-ack self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | 1) def powerDown(self): self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) & ~ NRF24.PWR_UP) def powerUp(self): self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP) time.sleep(150e-6) def write(self, buf): self.last_error = None length = self.write_payload(buf) self.ce(1) sent_at = monotonic() packet_time = ((1 + length + self.crc_length + self.address_length) * 8 + 9)/(self.data_rate_bits * 1000.) if self.auto_ack != 0: packet_time *= 2 if self.retries != 0 and self.auto_ack != 0: timeout = sent_at + (packet_time + self.delay)*self.retries else: timeout = sent_at + packet_time * 2 # 2 is empiric #while NRF24.TX_DS & self.get_status() == 0: # pass #print monotonic() - sent_at #print packet_time while monotonic() < timeout: time.sleep(packet_time) status = self.get_status() if status & NRF24.TX_DS: self.ce(0) return True if status & NRF24.MAX_RT: self.last_error = 'MAX_RT' self.ce(0) break self.ce(0) if self.last_error is None: self.last_error = 'TIMEOUT' self.flush_tx() # Avoid leaving the payload in tx fifo return False def startFastWrite(self, buf): """ Do not wait for CE HIGH->LOW """ # Send the payload self.write_payload(buf) self.ce(1) def startWrite(self, buf): # Send the payload self.write_payload(buf) # Allons! self.ce(1, 10e-6) def getDynamicPayloadSize(self): return self.spidev.xfer2([NRF24.R_RX_PL_WID, NRF24.NOP])[1] def available(self, pipe_num=None, irq_wait=False, irq_timeout=30000): status = self.get_status() result = False # Sometimes the radio specifies that there is data in one pipe but # doesn't set the RX flag... if status & NRF24.RX_DR or (status & NRF24.RX_P_NO_MASK != NRF24.RX_P_NO_MASK): result = True else: if irq_wait: # Will use IRQ wait if self.irqWait(irq_timeout): # Do we have a packet? status = self.get_status() # Seems like we do! if status & NRF24.RX_DR or (status & NRF24.RX_P_NO_MASK != NRF24.RX_P_NO_MASK): result = True # read status once again see Note on page 52 or 56 in product specification 1.0 # Note: The 3 bit pipe information in the STATUS register is updated during the IRQ pin high to low #transition. The pipe information is unreliable if the STATUS register is read during an IRQ pin #high to low transition. status = self.get_status() del pipe_num[:] if result and pipe_num is not None: pipe_num.append((status & NRF24.RX_P_NO_MASK) >> NRF24.RX_P_NO) # Handle ack payload receipt if status & NRF24.TX_DS: self.write_register(NRF24.STATUS, NRF24.TX_DS) return result def read(self, buf, buf_len=-1): # Fetch the payload self.read_payload(buf, buf_len) # was this the last of the data available? return self.read_register(NRF24.FIFO_STATUS & NRF24.RX_EMPTY) def clear_irq_flags(self): self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) def whatHappened(self): # Read the status & reset the status in one easy call # Or is that such a good idea? self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) status = self.get_status() self.clear_irq_flags() # Report to the user what happened tx_ok = status & NRF24.TX_DS tx_fail = status & NRF24.MAX_RT rx_ready = status & NRF24.RX_DR return {'tx_ok': tx_ok, "tx_fail": tx_fail, "rx_ready": rx_ready} def openWritingPipe(self, value): # Note that the NRF24L01(+) # expects it LSB first. self.write_register(NRF24.RX_ADDR_P0, value) self.write_register(NRF24.TX_ADDR, value) if not self.dynamic_payloads_enabled: self.write_register(NRF24.RX_PW_P0, self.payload_size) def openReadingPipe(self, pipe, address): # If this is pipe 0, cache the address. This is needed because # openWritingPipe() will overwrite the pipe 0 address, so # startListening() will have to restore it. if pipe >= 6: raise RuntimeError("Invalid pipe number") if (pipe >= 2 and len(address) > 1) or len(address) > 5: raise RuntimeError("Invalid adress length") if pipe == 0: self.pipe0_reading_address = address self.write_register(NRF24.RX_ADDR_P0 + pipe, address) if not self.dynamic_payloads_enabled: self.write_register(NRF24.RX_PW_P0 + pipe, self.payload_size) # Note it would be more efficient to set all of the bits for all open # pipes at once. However, I thought it would make the calling code # more simple to do it this way. self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | (1 << pipe)) def closeReadingPipe(self, pipe): self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) & ~(1 << pipe)) def toggle_features(self): buf = [NRF24.ACTIVATE, 0x73] self.spidev.xfer2(buf) def enableDynamicPayloads(self): # Enable dynamic payload throughout the system self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_DPL) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_DPL) # Enable dynamic payload on all pipes # Not sure the use case of only having dynamic payload on certain # pipes, so the library does not support it. self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | 0b00111111) self.dynamic_payloads_enabled = True def enableAckPayload(self): # enable ack payload and dynamic payload features self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_ACK_PAY | NRF24.EN_DPL) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_ACK_PAY | NRF24.EN_DPL) # Enable dynamic payload on pipes 0 & 1 self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | NRF24.DPL_P1 | NRF24.DPL_P0) def writeAckPayload(self, pipe, buf, buf_len): txbuffer = [NRF24.W_ACK_PAYLOAD | (pipe & 0x7)] max_payload_size = 32 data_len = min(buf_len, max_payload_size) txbuffer.extend(buf[0:data_len]) self.spidev.xfer2(txbuffer) def isAckPayloadAvailable(self): result = self.ack_payload_available self.ack_payload_available = False return result def isPVariant(self): return self.p_variant def setAutoAck(self, enable): if enable: self.write_register(NRF24.EN_AA, 0x3F) self.auto_ack = 0x3f if self.crc_length == 0: self.setCRCLength(NRF24.CRC_8) # Enhanced Shockburst requires at least 1 byte CRC else: self.auto_ack = 0 self.write_register(NRF24.EN_AA, 0) def setAutoAckPipe(self, pipe, enable): if pipe <= 6: en_aa = self.read_register(NRF24.EN_AA) if enable: self.setCRCLength(NRF24.CRC_8) # Enhanced Shockburst requires at least 1 byte CRC en_aa |= 1 << pipe self.auto_ack |= 1 << pipe else: en_aa &= ~1 << pipe self.auto_ack &= ~1 << pipe self.write_register(NRF24.EN_AA, en_aa) def setAddressWidth(self, width): if width >= 2 and width <= 5: self.write_register(NRF24.SETUP_AW, width - 2) self.address_width = width def testCarrier(self): return self.read_register(NRF24.RPD) & 1 def setPALevel(self, level): setup = self.read_register(NRF24.RF_SETUP) setup &= ~(NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH) if level == NRF24.PA_MAX: setup |= NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH elif level == NRF24.PA_HIGH: setup |= NRF24.RF_PWR_HIGH elif level == NRF24.PA_LOW: setup |= NRF24.RF_PWR_LOW elif level == NRF24.PA_MIN: pass elif level == NRF24.PA_ERROR: # On error, go to maximum PA setup |= NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH self.write_register(NRF24.RF_SETUP, setup) def getPALevel(self): power = self.read_register(NRF24.RF_SETUP) & (NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH) if power == (NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH): return NRF24.PA_MAX elif power == NRF24.RF_PWR_HIGH: return NRF24.PA_HIGH elif power == NRF24.RF_PWR_LOW: return NRF24.PA_LOW else: return NRF24.PA_MIN def setDataRate(self, speed): setup = self.read_register(NRF24.RF_SETUP) setup &= ~(NRF24.RF_DR_LOW | NRF24.RF_DR_HIGH) if speed == NRF24.BR_250KBPS: # Must set the RF_DR_LOW to 1 RF_DR_HIGH (used to be RF_DR) is already 0 # Making it '10'. self.data_rate_bits = 250 self.data_rate = NRF24.BR_250KBPS setup |= NRF24.RF_DR_LOW elif speed == NRF24.BR_2MBPS: # Set 2Mbs, RF_DR (RF_DR_HIGH) is set 1 # Making it '01' self.data_rate_bits = 2000 self.data_rate = NRF24.BR_2MBPS setup |= NRF24.RF_DR_HIGH else: # 1Mbs self.data_rate_bits = 1000 self.data_rate = NRF24.BR_1MBPS self.write_register(NRF24.RF_SETUP, setup) # Verify our result return self.read_register(NRF24.RF_SETUP) == setup def getDataRate(self): dr = self.read_register(NRF24.RF_SETUP) & (NRF24.RF_DR_LOW | NRF24.RF_DR_HIGH) # Order matters in our case below if dr == NRF24.RF_DR_LOW: # '10' = 250KBPS return NRF24.BR_250KBPS elif dr == NRF24.RF_DR_HIGH: # '01' = 2MBPS return NRF24.BR_2MBPS else: # '00' = 1MBPS return NRF24.BR_1MBPS def setCRCLength(self, length): config = self.read_register(NRF24.CONFIG) & ~(NRF24.EN_CRC | NRF24.CRCO) if length == NRF24.CRC_DISABLED: self.crc_length = 0 elif length == NRF24.CRC_8: config |= NRF24.EN_CRC config &= ~NRF24.CRCO self.crc_length = 1 else: config |= NRF24.EN_CRC config |= NRF24.CRCO self.crc_length = 2 self.write_register(NRF24.CONFIG, config) def getCRCLength(self): result = NRF24.CRC_DISABLED config = self.read_register(NRF24.CONFIG) & (NRF24.CRCO | NRF24.EN_CRC) if config & NRF24.EN_CRC: if config & NRF24.CRCO: result = NRF24.CRC_16 else: result = NRF24.CRC_8 return result def disableCRC(self): disable = self.read_register(NRF24.CONFIG) & ~NRF24.EN_CRC self.write_register(NRF24.CONFIG, disable) def setRetries(self, delay, count): self.write_register(NRF24.SETUP_RETR, (delay & 0xf) << NRF24.ARD | (count & 0xf) << NRF24.ARC) self.delay = delay * 0.000250 self.retries = count self.max_timeout = (self.payload_size / float(self.data_rate_bits) + self.delay) * self.retries self.timeout = (self.payload_size / float(self.data_rate_bits) + self.delay) def getRetries(self): return self.read_register(NRF24.SETUP_RETR) def getMaxTimeout(self): return self.max_timeout def getTimeout(self): return self.timeout def reset(self): """ Make sure the NRF is in the same state as after power up to avoid problems resulting from left over configuration from other programs.""" self.ce(0) reset_values = {0: 0x08, 1: 0x3F, 2: 0x02, 3: 0x03, 4: 0x03, 5: 0x02, 6: 0x06, 0x0a: [0xe7, 0xe7, 0xe7, 0xe7, 0xe7], 0x0b: [0xc2, 0xc2, 0xc2, 0xc2, 0xc2], 0x0c: 0xc3, 0x0d: 0xc4, 0x0e: 0xc5, 0x0f: 0xc6, 0x10: [0xe7, 0xe7, 0xe7, 0xe7, 0xe7], 0x11: 0, 0x12: 0, 0x13: 0, 0x14: 0, 0x15: 0, 0x16: 0, 0x1c: 0, 0x1d: 0} for reg, value in reset_values.items(): self.write_register(reg, value) self.flush_rx() self.flush_tx()
class NRF24: MAX_CHANNEL = 127 MAX_PAYLOAD_SIZE = 32 # PA Levels PA_MIN = 0x00 PA_LOW = 0x01 PA_HIGH = 0x02 PA_MAX = 0x03 PA_ERROR = 0x04 # Bit rates BR_1MBPS = 0 BR_2MBPS = 1 BR_250KBPS = 2 # CRC CRC_DISABLED = 0x0 CRC_8 = 0x02 CRC_16 = 0x04 CRC_ENABLED = 0x08 EN_CRC = 0x08 CRCO = 0x04 # Registers CONFIG = 0x00 EN_AA = 0x01 EN_RXADDR = 0x02 SETUP_AW = 0x03 SETUP_RETR = 0x04 RF_CH = 0x05 RF_SETUP = 0x06 STATUS = 0x07 OBSERVE_TX = 0x08 RPD = 0x09 RX_ADDR_P0 = 0x0A RX_ADDR_P1 = 0x0B RX_ADDR_P2 = 0x0C RX_ADDR_P3 = 0x0D RX_ADDR_P4 = 0x0E RX_ADDR_P5 = 0x0F TX_ADDR = 0x10 RX_PW_P0 = 0x11 RX_PW_P1 = 0x12 RX_PW_P2 = 0x13 RX_PW_P3 = 0x14 RX_PW_P4 = 0x15 RX_PW_P5 = 0x16 FIFO_STATUS = 0x17 DYNPD = 0x1C FEATURE = 0x1D # Bit Mnemonics */ MASK_RX_DR = 0x40 MASK_TX_DS = 0x20 MASK_MAX_RT = 0x10 PWR_UP = 0x02 PRIM_RX = 0x01 PLL_LOCK = 0x10 RX_DR = 0x40 TX_DS = 0x20 MAX_RT = 0x10 TX_FULL = 0x01 EN_DPL = 0x04 EN_ACK_PAY = 0x02 EN_DYN_ACK = 0x01 # Shift counts ARD = 4 ARC = 0 PLOS_CNT = 4 ARC_CNT = 0 RX_P_NO = 1 TX_REUSE = 6 FIFO_FULL = 5 TX_EMPTY = 4 RX_FULL = 1 RX_EMPTY = 0 DPL_P5 = 5 DPL_P4 = 4 DPL_P3 = 3 DPL_P2 = 2 DPL_P1 = 1 DPL_P0 = 0 #Masks RX_P_NO_MASK = 0x0E # Instruction Mnemonics R_REGISTER = 0x00 W_REGISTER = 0x20 REGISTER_MASK = 0x1F ACTIVATE = 0x50 R_RX_PL_WID = 0x60 R_RX_PAYLOAD = 0x61 W_TX_PAYLOAD = 0xA0 W_ACK_PAYLOAD = 0xA8 FLUSH_TX = 0xE1 FLUSH_RX = 0xE2 REUSE_TX_PL = 0xE3 NOP = 0xFF # Non-P omissions LNA_HCURR = 0x01 LNA_ON = 1 LNA_OFF = 0 # P model bit Mnemonics RF_DR_LOW = 0x20 RF_DR_HIGH = 0x08 RF_PWR_LOW = 0x02 RF_PWR_HIGH = 0x04 datarate_e_str_P = ["1MBPS", "2MBPS", "250KBPS"] model_e_str_P = ["nRF24L01", "nRF24l01+"] crclength_e_str_P = ["Disabled", "", "8 bits", "", "16 bits"] pa_dbm_e_str_P = ["PA_MIN", "PA_LOW", "PA_HIGH", "PA_MAX"] @staticmethod def print_single_status_line(name, value): print("{0:<16}= {1}".format(name, value)) @staticmethod def _to_8b_list(data): """Convert an arbitray iteratable or single int to a list of ints where each int is smaller than 256.""" if isinstance(data, str): data = [ord(x) for x in data] elif isinstance(data, (int, long)): data = [data] else: data = [int(x) for x in data] #for byte in data: # if byte < 0 or byte > 255: # raise RuntimeError("Value %d is larger than 8 bits" % byte) return data def __init__(self, major=None, minor=None, ce_pin=None, irq_pin=None): self.ce_pin = "P9_15" self.irq_pin = "P9_16" self.channel = 76 self.data_rate = NRF24.BR_1MBPS self.data_rate_bits = 1000 self.p_variant = False # False for RF24L01 and true for RF24L01P self.payload_size = 5 # *< Fixed size of payloads self.ack_payload_available = False # *< Whether there is an ack payload waiting self.dynamic_payloads_enabled = False # *< Whether dynamic payloads are enabled. self.ack_payload_length = 5 # *< Dynamic size of pending ack payload. self.pipe0_reading_address = None # *< Last address set on pipe 0 for reading. self.spidev = None self.last_error = 0 self.crc_length = 0 self.auto_ack = 0x3F self.address_length = 5 # If all parameters are available, lets start the radio! if major is not None and minor is not None and irq_pin is not None: self.begin(major, minor, ce_pin, irq_pin) def begin(self, major, minor, ce_pin, irq_pin): # Initialize SPI bus if ADAFRUID_BBIO_SPI: self.spidev = SPI(major, minor) self.spidev.bpw = 8 try: self.spidev.msh = 10000000 # Maximum supported by NRF24L01+ except IOError: pass # Hardware does not support this speed else: self.spidev = spidev.SpiDev() self.spidev.open(major, minor) self.spidev.bits_per_word = 8 try: self.spidev.max_speed_hz = 10000000 # Maximum supported by NRF24L01+ except IOError: pass # Hardware does not support this speed self.spidev.cshigh = False self.spidev.mode = 0 self.spidev.loop = False self.spidev.lsbfirst = False self.spidev.threewire = False self.ce_pin = ce_pin self.irq_pin = irq_pin if self.ce_pin is not None: GPIO.setup(self.ce_pin, GPIO.OUT) GPIO.setup(self.irq_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) time.sleep(5 / 1000000.0) # Reset radio configuration self.reset() # Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier # WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet # sizes must never be used. See documentation for a more complete explanation. self.setRetries(int('0101', 2), 15) # Restore our default PA level self.setPALevel(NRF24.PA_MAX) # Determine if this is a p or non-p RF24 module and then # reset our data rate back to default value. This works # because a non-P variant won't allow the data rate to # be set to 250Kbps. if self.setDataRate(NRF24.BR_250KBPS): self.p_variant = True # Then set the data rate to the slowest (and most reliable) speed supported by all # hardware. self.setDataRate(NRF24.BR_1MBPS) # Initialize CRC and request 2-byte (16bit) CRC self.setCRCLength(NRF24.CRC_16) # Disable dynamic payloads, to match dynamic_payloads_enabled setting self.write_register(NRF24.DYNPD, 0) # Reset current status # Notice reset and flush is the last thing we do self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) # Set up default configuration. Callers can always change it later. # This channel should be universally safe and not bleed over into adjacent # spectrum. self.setChannel(self.channel) self.setRetries(15, 15) # Flush buffers self.flush_rx() self.flush_tx() self.clear_irq_flags() def end(self): if self.spidev: self.spidev.close() self.spidev = None def startListening(self): self.write_register( NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP | NRF24.PRIM_RX) self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) self.flush_tx() self.flush_rx() self.clear_irq_flags() # Restore the pipe0 address, if exists if self.pipe0_reading_address: self.write_register(self.RX_ADDR_P0, self.pipe0_reading_address) # Go! self.ce(1) def ce(self, level, pulse=0): # CE Pin is optional if self.ce_pin is not None: GPIO.output(self.ce_pin, level) if pulse > 0: time.sleep(pulse) GPIO.output(self.ce_pin, 1 - level) def irqWait(self, timeout=30000): # TODO: A race condition may occur here. => wait for level? if GPIO.input( self.irq_pin) == 0: # Pin is already down. Packet is waiting? return True try: return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING, timeout) == 1 except TypeError: # Timeout parameter not supported return GPIO.wait_for_edge(self.irq_pin, GPIO.FALLING) == 1 except AttributeError: raise RuntimeError("GPIO lib does not support wait_for_edge()") def read_register(self, reg, length=1): buf = [NRF24.R_REGISTER | (NRF24.REGISTER_MASK & reg)] buf += [NRF24.NOP] * max(1, length) resp = self.spidev.xfer2(buf) if length == 1: return resp[1] return resp[1:] def write_register(self, reg, value): """ Write register value """ buf = [NRF24.W_REGISTER | (NRF24.REGISTER_MASK & reg)] buf += self._to_8b_list(value) self.spidev.xfer2(buf) def write_payload(self, buf): """ Writes data to the payload register, automatically padding it to match the required length. Returns the number of bytes actually written. """ buf = self._to_8b_list(buf) if self.dynamic_payloads_enabled: if len(buf) > self.MAX_PAYLOAD_SIZE: raise RuntimeError("Dynamic payload is larger than the " + "maximum size.") blank_len = 0 else: if len(buf) > self.payload_size: raise RuntimeError("Payload is larger than the fixed payload" + "size (%d vs. %d bytes)" % (len(buf), self.payload_size)) blank_len = self.payload_size - len(buf) txbuffer = [NRF24.W_TX_PAYLOAD] + buf + ([0x00] * blank_len) self.spidev.xfer2(txbuffer) return len(txbuffer) - 1 def read_payload(self, buf, buf_len=-1): """ Reads data from the payload register and sets the DR bit of the STATUS register. """ if buf_len < 0: buf_len = self.payload_size if not self.dynamic_payloads_enabled: data_len = min(self.payload_size, buf_len) blank_len = self.payload_size - data_len else: data_len = self.getDynamicPayloadSize() blank_len = 0 txbuffer = [NRF24.R_RX_PAYLOAD ] + [NRF24.NOP] * (blank_len + data_len + 1) payload = self.spidev.xfer2(txbuffer) del buf[:] buf += payload[1:data_len + 1] self.write_register(NRF24.STATUS, NRF24.RX_DR) return data_len def flush_rx(self): return self.spidev.xfer2([NRF24.FLUSH_RX])[0] def flush_tx(self): return self.spidev.xfer2([NRF24.FLUSH_TX])[0] def get_status(self): return self.spidev.xfer2([NRF24.NOP])[0] def print_status(self, status): status_str = "0x{0:02x} RX_DR={1:x} TX_DS={2:x} MAX_RT={3:x} RX_P_NO={4:x} TX_FULL={5:x}".format( status, 1 if status & NRF24.RX_DR else 0, 1 if status & NRF24.TX_DS else 0, 1 if status & NRF24.MAX_RT else 0, ((status >> NRF24.RX_P_NO) & int("111", 2)), 1 if status & NRF24.TX_FULL else 0) self.print_single_status_line("STATUS", status_str) def print_observe_tx(self, value): tx_str = "OBSERVE_TX=0x{0:02x}: POLS_CNT={2:x} ARC_CNT={2:x}\r\n".format( value, (value >> NRF24.PLOS_CNT) & int("1111", 2), (value >> NRF24.ARC_CNT) & int("1111", 2)) self.print_single_status_line("OBSERVE_TX", tx_str) def print_byte_register(self, name, reg, qty=1): registers = [ "0x{:0>2x}".format(self.read_register(reg + r)) for r in range(0, qty) ] self.print_single_status_line(name, " ".join(registers)) def print_address_register(self, name, reg, qty=1): address_registers = [ "0x{0:>02x}{1:>02x}{2:>02x}{3:>02x}{4:>02x}".format( *self.read_register(reg + r, 5)) for r in range(qty) ] self.print_single_status_line(name, " ".join(address_registers)) def setChannel(self, channel): if channel < 0 or channel > self.MAX_CHANNEL: raise RuntimeError("Channel number out of range") self.channel = channel self.write_register(NRF24.RF_CH, channel) def getChannel(self): return self.read_register(NRF24.RF_CH) def setPayloadSize(self, size): self.payload_size = min(max(size, 1), NRF24.MAX_PAYLOAD_SIZE) def getPayloadSize(self): return self.payload_size def printDetails(self): self.print_status(self.get_status()) self.print_address_register("RX_ADDR_P0-1", NRF24.RX_ADDR_P0, 2) self.print_byte_register("RX_ADDR_P2-5", NRF24.RX_ADDR_P2, 4) self.print_address_register("TX_ADDR", NRF24.TX_ADDR) self.print_byte_register("RX_PW_P0-6", NRF24.RX_PW_P0, 6) self.print_byte_register("EN_AA", NRF24.EN_AA) self.print_byte_register("EN_RXADDR", NRF24.EN_RXADDR) self.print_byte_register("RF_CH", NRF24.RF_CH) self.print_byte_register("RF_SETUP", NRF24.RF_SETUP) self.print_byte_register("SETUP_AW", NRF24.SETUP_AW) self.print_byte_register("OBSERVE_TX", NRF24.OBSERVE_TX) self.print_byte_register("CONFIG", NRF24.CONFIG) self.print_byte_register("FIFO_STATUS", NRF24.FIFO_STATUS) self.print_byte_register("DYNPD", NRF24.DYNPD) self.print_byte_register("FEATURE", NRF24.FEATURE) self.print_single_status_line( "Data Rate", NRF24.datarate_e_str_P[self.getDataRate()]) self.print_single_status_line("Model", NRF24.model_e_str_P[self.isPVariant()]) self.print_single_status_line( "CRC Length", NRF24.crclength_e_str_P[self.getCRCLength()]) self.print_single_status_line("PA Power", NRF24.pa_dbm_e_str_P[self.getPALevel()]) def stopListening(self): self.ce(0) self.flush_tx() self.flush_rx() self.clear_irq_flags() # Enable TX self.write_register(NRF24.CONFIG, (self.read_register(NRF24.CONFIG) | NRF24.PWR_UP) & ~NRF24.PRIM_RX) # Enable pipe 0 for auto-ack self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | 1) def powerDown(self): self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) & ~NRF24.PWR_UP) def powerUp(self): self.write_register(NRF24.CONFIG, self.read_register(NRF24.CONFIG) | NRF24.PWR_UP) time.sleep(150e-6) def write(self, buf): self.last_error = None length = self.write_payload(buf) self.ce(1) sent_at = monotonic() packet_time = ( (1 + length + self.crc_length + self.address_length) * 8 + 9) / (self.data_rate_bits * 1000.) if self.auto_ack != 0: packet_time *= 2 if self.retries != 0 and self.auto_ack != 0: timeout = sent_at + (packet_time + self.delay) * self.retries else: timeout = sent_at + packet_time * 2 # 2 is empiric #while NRF24.TX_DS & self.get_status() == 0: # pass #print monotonic() - sent_at #print packet_time while monotonic() < timeout: time.sleep(packet_time) status = self.get_status() if status & NRF24.TX_DS: self.ce(0) return True if status & NRF24.MAX_RT: self.last_error = 'MAX_RT' self.ce(0) break self.ce(0) if self.last_error is None: self.last_error = 'TIMEOUT' self.flush_tx() # Avoid leaving the payload in tx fifo return False def startFastWrite(self, buf): """ Do not wait for CE HIGH->LOW """ # Send the payload self.write_payload(buf) self.ce(1) def startWrite(self, buf): # Send the payload self.write_payload(buf) # Allons! self.ce(1, 10e-6) def getDynamicPayloadSize(self): return self.spidev.xfer2([NRF24.R_RX_PL_WID, NRF24.NOP])[1] def available(self, pipe_num=None, irq_wait=False, irq_timeout=30000): status = self.get_status() result = False # Sometimes the radio specifies that there is data in one pipe but # doesn't set the RX flag... if status & NRF24.RX_DR or (status & NRF24.RX_P_NO_MASK != NRF24.RX_P_NO_MASK): result = True else: if irq_wait: # Will use IRQ wait if self.irqWait(irq_timeout): # Do we have a packet? status = self.get_status() # Seems like we do! if status & NRF24.RX_DR or (status & NRF24.RX_P_NO_MASK != NRF24.RX_P_NO_MASK): result = True if result and pipe_num is not None: del pipe_num[:] pipe_num.append((status & NRF24.RX_P_NO_MASK) >> NRF24.RX_P_NO) # Handle ack payload receipt if status & NRF24.TX_DS: self.write_register(NRF24.STATUS, NRF24.TX_DS) return result def read(self, buf, buf_len=-1): # Fetch the payload self.read_payload(buf, buf_len) # was this the last of the data available? return self.read_register(NRF24.FIFO_STATUS & NRF24.RX_EMPTY) def clear_irq_flags(self): self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) def whatHappened(self): # Read the status & reset the status in one easy call # Or is that such a good idea? self.write_register(NRF24.STATUS, NRF24.RX_DR | NRF24.TX_DS | NRF24.MAX_RT) status = self.get_status() self.clear_irq_flags() # Report to the user what happened tx_ok = status & NRF24.TX_DS tx_fail = status & NRF24.MAX_RT rx_ready = status & NRF24.RX_DR return {'tx_ok': tx_ok, "tx_fail": tx_fail, "rx_ready": rx_ready} def openWritingPipe(self, value): # Note that the NRF24L01(+) # expects it LSB first. self.write_register(NRF24.RX_ADDR_P0, value) self.write_register(NRF24.TX_ADDR, value) if not self.dynamic_payloads_enabled: self.write_register(NRF24.RX_PW_P0, self.payload_size) def openReadingPipe(self, pipe, address): # If this is pipe 0, cache the address. This is needed because # openWritingPipe() will overwrite the pipe 0 address, so # startListening() will have to restore it. if pipe >= 6: raise RuntimeError("Invalid pipe number") if (pipe >= 2 and len(address) > 1) or len(address) > 5: raise RuntimeError("Invalid adress length") if pipe == 0: self.pipe0_reading_address = address self.write_register(NRF24.RX_ADDR_P0 + pipe, address) if not self.dynamic_payloads_enabled: self.write_register(NRF24.RX_PW_P0 + pipe, self.payload_size) # Note it would be more efficient to set all of the bits for all open # pipes at once. However, I thought it would make the calling code # more simple to do it this way. self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) | (1 << pipe)) def closeReadingPipe(self, pipe): self.write_register(NRF24.EN_RXADDR, self.read_register(NRF24.EN_RXADDR) & ~(1 << pipe)) def toggle_features(self): buf = [NRF24.ACTIVATE, 0x73] self.spidev.xfer2(buf) def enableDynamicPayloads(self): # Enable dynamic payload throughout the system self.write_register(NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_DPL) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register( NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_DPL) # Enable dynamic payload on all pipes # Not sure the use case of only having dynamic payload on certain # pipes, so the library does not support it. self.write_register(NRF24.DYNPD, self.read_register(NRF24.DYNPD) | 0b00111111) self.dynamic_payloads_enabled = True def enableAckPayload(self): # enable ack payload and dynamic payload features self.write_register( NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_ACK_PAY | NRF24.EN_DPL) # If it didn't work, the features are not enabled if not self.read_register(NRF24.FEATURE): # So enable them and try again self.toggle_features() self.write_register( NRF24.FEATURE, self.read_register(NRF24.FEATURE) | NRF24.EN_ACK_PAY | NRF24.EN_DPL) # Enable dynamic payload on pipes 0 & 1 self.write_register( NRF24.DYNPD, self.read_register(NRF24.DYNPD) | NRF24.DPL_P1 | NRF24.DPL_P0) def writeAckPayload(self, pipe, buf, buf_len): txbuffer = [NRF24.W_ACK_PAYLOAD | (pipe & 0x7)] max_payload_size = 32 data_len = min(buf_len, max_payload_size) txbuffer.extend(buf[0:data_len]) self.spidev.xfer2(txbuffer) def isAckPayloadAvailable(self): result = self.ack_payload_available self.ack_payload_available = False return result def isPVariant(self): return self.p_variant def setAutoAck(self, enable): if enable: self.write_register(NRF24.EN_AA, 0x3F) self.auto_ack = 0x3f if self.crc_length == 0: self.setCRCLength( NRF24.CRC_8 ) # Enhanced Shockburst requires at least 1 byte CRC else: self.auto_ack = 0 self.write_register(NRF24.EN_AA, 0) def setAutoAckPipe(self, pipe, enable): if pipe <= 6: en_aa = self.read_register(NRF24.EN_AA) if enable: self.setCRCLength( NRF24.CRC_8 ) # Enhanced Shockburst requires at least 1 byte CRC en_aa |= 1 << pipe self.auto_ack |= 1 << pipe else: en_aa &= ~1 << pipe self.auto_ack &= ~1 << pipe self.write_register(NRF24.EN_AA, en_aa) def setAddressWidth(self, width): if width >= 2 and width <= 5: self.write_register(NRF24.SETUP_AW, width - 2) self.address_width = width def testCarrier(self): return self.read_register(NRF24.RPD) & 1 def setPALevel(self, level): setup = self.read_register(NRF24.RF_SETUP) setup &= ~(NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH) if level == NRF24.PA_MAX: setup |= NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH elif level == NRF24.PA_HIGH: setup |= NRF24.RF_PWR_HIGH elif level == NRF24.PA_LOW: setup |= NRF24.RF_PWR_LOW elif level == NRF24.PA_MIN: pass elif level == NRF24.PA_ERROR: # On error, go to maximum PA setup |= NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH self.write_register(NRF24.RF_SETUP, setup) def getPALevel(self): power = self.read_register( NRF24.RF_SETUP) & (NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH) if power == (NRF24.RF_PWR_LOW | NRF24.RF_PWR_HIGH): return NRF24.PA_MAX elif power == NRF24.RF_PWR_HIGH: return NRF24.PA_HIGH elif power == NRF24.RF_PWR_LOW: return NRF24.PA_LOW else: return NRF24.PA_MIN def setDataRate(self, speed): setup = self.read_register(NRF24.RF_SETUP) setup &= ~(NRF24.RF_DR_LOW | NRF24.RF_DR_HIGH) if speed == NRF24.BR_250KBPS: # Must set the RF_DR_LOW to 1 RF_DR_HIGH (used to be RF_DR) is already 0 # Making it '10'. self.data_rate_bits = 250 self.data_rate = NRF24.BR_250KBPS setup |= NRF24.RF_DR_LOW elif speed == NRF24.BR_2MBPS: # Set 2Mbs, RF_DR (RF_DR_HIGH) is set 1 # Making it '01' self.data_rate_bits = 2000 self.data_rate = NRF24.BR_2MBPS setup |= NRF24.RF_DR_HIGH else: # 1Mbs self.data_rate_bits = 1000 self.data_rate = NRF24.BR_1MBPS self.write_register(NRF24.RF_SETUP, setup) # Verify our result return self.read_register(NRF24.RF_SETUP) == setup def getDataRate(self): dr = self.read_register( NRF24.RF_SETUP) & (NRF24.RF_DR_LOW | NRF24.RF_DR_HIGH) # Order matters in our case below if dr == NRF24.RF_DR_LOW: # '10' = 250KBPS return NRF24.BR_250KBPS elif dr == NRF24.RF_DR_HIGH: # '01' = 2MBPS return NRF24.BR_2MBPS else: # '00' = 1MBPS return NRF24.BR_1MBPS def setCRCLength(self, length): config = self.read_register( NRF24.CONFIG) & ~(NRF24.EN_CRC | NRF24.CRCO) if length == NRF24.CRC_DISABLED: self.crc_length = 0 elif length == NRF24.CRC_8: config |= NRF24.EN_CRC config &= ~NRF24.CRCO self.crc_length = 1 else: config |= NRF24.EN_CRC config |= NRF24.CRCO self.crc_length = 2 self.write_register(NRF24.CONFIG, config) def getCRCLength(self): result = NRF24.CRC_DISABLED config = self.read_register(NRF24.CONFIG) & (NRF24.CRCO | NRF24.EN_CRC) if config & NRF24.EN_CRC: if config & NRF24.CRCO: result = NRF24.CRC_16 else: result = NRF24.CRC_8 return result def disableCRC(self): disable = self.read_register(NRF24.CONFIG) & ~NRF24.EN_CRC self.write_register(NRF24.CONFIG, disable) def setRetries(self, delay, count): self.write_register(NRF24.SETUP_RETR, (delay & 0xf) << NRF24.ARD | (count & 0xf) << NRF24.ARC) self.delay = delay * 0.000250 self.retries = count self.max_timeout = (self.payload_size / float(self.data_rate_bits) + self.delay) * self.retries self.timeout = (self.payload_size / float(self.data_rate_bits) + self.delay) def getRetries(self): return self.read_register(NRF24.SETUP_RETR) def getMaxTimeout(self): return self.max_timeout def getTimeout(self): return self.timeout def reset(self): """ Make sure the NRF is in the same state as after power up to avoid problems resulting from left over configuration from other programs.""" self.ce(0) reset_values = { 0: 0x08, 1: 0x3F, 2: 0x02, 3: 0x03, 4: 0x03, 5: 0x02, 6: 0x06, 0x0a: [0xe7, 0xe7, 0xe7, 0xe7, 0xe7], 0x0b: [0xc2, 0xc2, 0xc2, 0xc2, 0xc2], 0x0c: 0xc3, 0x0d: 0xc4, 0x0e: 0xc5, 0x0f: 0xc6, 0x10: [0xe7, 0xe7, 0xe7, 0xe7, 0xe7], 0x11: 0, 0x12: 0, 0x13: 0, 0x14: 0, 0x15: 0, 0x16: 0, 0x1c: 0, 0x1d: 0 } for reg, value in reset_values.items(): self.write_register(reg, value) self.flush_rx() self.flush_tx()
class MAX7221(Display.Display): def __init__(self, bus, device): super(MAX7221, self).__init__(8, 8) SPI(bus, device).mode = 0 self.spi_bus = SPI(bus, device) self.buf = [0, 0, 0, 0, 0, 0, 0, 0] self.OP_NOP = 0x0 self.OP_DIG0 = 0x1 self.OP_DIG1 = 0x2 self.OP_DIG2 = 0x3 self.OP_DIG3 = 0x4 self.OP_DIG4 = 0x5 self.OP_DIG5 = 0x6 self.OP_DIG6 = 0x7 self.OP_DIG7 = 0x8 self.OP_DECODEMODE = 0x9 self.OP_INTENSITY = 0xA self.OP_SCANLIMIT = 0xB self.OP_SHUTDOWN = 0xC self.OP_DISPLAYTEST = 0xF self.init() def rotate(self, x, n): return (x << n) | (x >> (8 - n)) def init(self): self.write_command(self.OP_DISPLAYTEST, 0x0) self.write_command(self.OP_SCANLIMIT, 0x7) self.write_command(self.OP_DECODEMODE, 0x0) self.shutdown(False) self.update_display() def shutdown(self, off): if off: off = 0 else: off = 1 self.write_command(self.OP_SHUTDOWN, off) def write_spi(self, reg, data): self.spi_bus.writebytes([reg, data]) def write_command(self, command, arg): self.write_spi(command, arg) def write_display(self, buffer): for col in range(0, len(buffer)): self.write_spi(col + 0x1, buffer[col]) def update_display(self): self.write_display(self.buf) def draw_pixel(self, x, y, color): if color == 1: self.buf[y] = self.buf[y] | (1 << x) elif color == 0: self.buf[y] = self.buf[y] & ~(1 << x) self.update_display() def draw_fast_hline(self, x, y, w, color): self.write_spi(0x1 + y, (0xFF >> (8 - w)) << x)
#!/usr/bin/env python2 # -*- coding: utf-8 -*- ### New Python Template File ### H27 Mar 16 import os, sys import time import Adafruit_BBIO.GPIO as GPIO from Adafruit_BBIO.SPI import SPI GPIO.setup("P9_12",GPIO.OUT) GPIO.output("P9_12",GPIO.HIGH) print("GPIO >> HIGH") spi_in = SPI(0, 0) spi_out = SPI(0, 1) spi_out.msh = 500000 while True: GPIO.output("P9_12",GPIO.LOW) print("GPIO >> LOW") spi_out.writebytes([0b00001111]) print("write >> num") print spi_in.readbytes(1) GPIO.output("P9_12",GPIO.HIGH) print("GPIO >> HIGH") time.sleep(1)
#!/usr/bin/python from Adafruit_BBIO.SPI import SPI from time import sleep spi = SPI(0,0) spi.bpw = 12 spi.msh = 100000 spi.lsbfirst = False spi.mode = 0 spi.open tlc5947_count = 2 tlc5947_channels = 24 # buffer = [0x000] * 48 buffer = [0x000] * (tlc5947_count * tlc5947_channels) #spi.writebytes(buffer) #print buffer spi.writebytes(buffer) #sleep(1) spi.close # CS_0 P9_17 lat # DO P9_21 din # DI P9_18 n/c
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 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()
#!/usr/bin/python from Adafruit_BBIO.SPI import SPI spi = SPI(0,0) spi.lsbfirst=False spi.msh=1000000 spi.cshigh=False spi.xfer2([0x36]) spi.cshigh=True for reg in range(0x0,0x3d+1,1): spi.cshigh=False send = [ reg+0xc0 , 0x0 ] recv = spi.xfer2(send) spi.cshigh=True print reg,recv patable=9*[0] patable[0]=0x3e+0xc0 spi.cshigh=False dd = spi.xfer2(patable) spi.cshigh=True print 0x3e,dd rxfifo=65*[0] rxfifo[0]=0x3f+0xc0
value[12]).split('x')[1] + ":" + hex(value[11]).split('x')[1] #print(address) rssi = value[17] - 256 #print(rssi) if rssi > -70: if value[28] == 128: print("%s, 1, %d") % (address, rssi) if value[28] == 129: print("%s, 2, %d") % (address, rssi) if value[28] == 130: print("%s, 3, %d") % (address, rssi) if value[28] == 131: print("%s, 4, %d") % (address, rssi) bt = SPI(0, 0) bt.mode = 1 bt.msh = 1000000 #reset the module GPIO.output("P9_12", GPIO.LOW) time.sleep(0.1) GPIO.output("P9_12", GPIO.HIGH) # initialize bt module k = 0 while k < 100: #print("Sending init message") bt.xfer2([ 0x00, 0xFE, 0x2A, 0x01, 0x00, 0xFE, 0x26, 0x02, 0x0A, 0x00, 0x00, 0x00,
#!/usr/bin/env python # -*- coding: utf-8 -*- import time from Adafruit_BBIO.SPI import SPI spi_in = SPI(0, 0) spi_out = SPI(0, 1) while True: try: print spi_in.readbytes(1) time.sleep(0.03) except KeyboardInterrupt: Break
from Adafruit_BBIO.SPI import SPI import time import numpy as np import scipy as sp import peakutils spi = SPI(0, 0) spi.mode = 1 spi.bpw = 8 spi.msh = 8000000 def put_in_reset(): print "\nput in reset" print spi.xfer2([int("16", 16), int("2F", 16), int("01", 16)]) def read_this_fifo(this, that): #print "\nread this fifo" #print "sent: 08", this, that, " 00. Got:" resp = spi.xfer2( [int("08", 16), int(str(this), 16), int(str(that), 16), int("00", 16)]) print resp return resp def put_out_reset(): print "\nput out reset"
class ledstrip: def __init__(self, length, missing): # the important piece of this for reuse is setting up the interface # the rest sets up the strip of leds for what we intend to do with them self.interface = SPI(0,1) self.full_length = length self.missing_leds = missing self.outbuff = [[128, 128, 128]] * length self.reset_buffer([128, 128, 128]) def reset_buffer(self, color): for i in range(0, len(self.outbuff), 1): self.outbuff[i] = color def write(self): # this guy here, plus a small amount of init code elsewhere, # is all we really need to make the led strips work. The rest is just # for ease of use. self.interface.writebytes([0] * (int(self.full_length / 32) + 1) + [0]) for i in range(0, len(self.outbuff), 1): if not i in self.missing_leds: self.interface.writebytes(self.outbuff[i]) def twocolorfade(self, bcolor, tcolor, length): outcolor = [] totalshift = [0, 0, 0] for i in range(0, 3, 1): totalshift[i] = tcolor[i] - bcolor[i] for i in range(0, length, 1): outcolor.append([]) for j in range(0, 3, 1): outcolor[i].append(bcolor[j] + (int(totalshift[j] / float(length) * i))) return outcolor def movingtwocolor(self, bcols, tcols, strip_length, gradient_width, delay): bfade = self.twocolorfade(bcols[0], bcols[1], gradient_width) for frame in bfade: seg1 = self.twocolorfade(frame, tcols[0], strip_length) seg2 = [] + seg1 seg2.reverse() self.outbuff = seg1 + seg2 + seg1 self.write() time.sleep(delay) bfade = self.twocolorfade(tcols[0], tcols[1], gradient_width) for frame in bfade: seg1 = self.twocolorfade(bcols[1], frame, strip_length) seg2 = [] + seg1 seg2.reverse() self.outbuff = seg1 + seg2 + seg1 self.write() time.sleep(delay) bfade = self.twocolorfade(tcols[1], tcols[0], gradient_width) for frame in bfade: seg1 = self.twocolorfade(bcols[1], frame, strip_length) seg2 = [] + seg1 seg2.reverse() self.outbuff = seg1 + seg2 + seg1 self.write() time.sleep(delay) bfade = self.twocolorfade(bcols[1], bcols[0], gradient_width) for frame in bfade: seg1 = self.twocolorfade(frame, tcols[0], strip_length) seg2 = [] + seg1 seg2.reverse() self.outbuff = seg1 + seg2 + seg1 self.write() time.sleep(delay) def run_sequence(self, fcol, bcol, length, delay, sequence, step, loops, timechange): # with run_sequence, we can do pretty much anything, # provided we can set up the sequence properly # long list of parameters gives us what we need to make that happen # fcol : foreground color (the color value for the leds in sequence) # bcol : background color (the color value for the leds not in sequence) # length : number of leds still active trailing the "current" one in sequence # delay : time between steps in sequence # sequence : a list (processed in the order provided) of leds to activate # step : number of leds in sequence to skip per step (useful for moving a whole group at once) # loops : number of times to iterate through the sequence completely # timechange : somewhat handy but not wholly necessary per loop multiplier for delay variable # can be used to increase or decrease timestep over several loops without re-running sequence pos = 0 loops = loops - 1 firstrun = True self.reset_buffer(bcol) while pos < len(sequence): self.reset_buffer(bcol) for tail in range(0, length, 1): if pos - tail >= 0 or not firstrun: self.outbuff[sequence[pos - tail]] = fcol if pos < len(sequence): if pos == len(sequence) - 1 and loops: pos = 0 firstrun = False loops = loops - 1 delay = delay * timechange elif pos == len(sequence) - 1 and length: length = length - 1 else: pos = pos + step time.sleep(delay) self.write() self.reset_buffer(bcol) self.write()
class RFM69(BaseRadio): DATA = [] DATALEN = 0 SENDERID = 0 TARGETID = 0 PAYLOADLEN = 0 ACK_REQUESTED = False ACK_RECEIVED = False RSSI = 0 _mode = 0 _interruptPin = DIO0_PIN _csPin = NSS_PIN _address = 0 _promiscuousMode = False _powerLevel = 31 _isRFM69HW = True def __init__(self, isRFM69HW=True, interruptPin=DIO0_PIN, csPin=NSS_PIN): self._isRFM69HW = isRFM69HW self._interruptPin = interruptPin self._csPin = csPin self.SPI = SPI(SPI_BUS, SPI_CS) self.SPI.bpw = 8 self.SPI.mode = 0 self.SPI.msh = SPI_CLK_SPEED self.SPI.lsbfirst = False GPIO.setup(self._interruptPin, GPIO.IN) self.lastIrqLevel = GPIO.input(self._interruptPin) GPIO.setup(self._csPin, GPIO.OUT) GPIO.output(self._csPin, GPIO.HIGH) self.start_time = datetime.datetime.now() # Convention I want to stick to is a single underscore to indicate "private" methods. # I'm grouping all the private stuff up at the beginning. def _millis(self): delta = datetime.datetime.now() - self.start_time return delta.total_seconds() * 1000 def _readReg(self, addr): self._select() self.SPI.writebytes([addr & 0x7F]) result = self.SPI.readbytes(1)[0] # print "readReg {} = {}". format(hex(addr), hex(result)) self._unselect() return result def _writeReg(self, addr, value): # print "writeReg, Address {}:{}". format(hex(addr), hex(value)) self._select() self.SPI.writebytes([addr | 0x80, value]) self._unselect() # Select the transceiver def _select(self): GPIO.output(self._csPin, GPIO.LOW) # Unselect the transceiver chip def _unselect(self): GPIO.output(self._csPin, GPIO.HIGH) def _setMode(self, newMode): if newMode == RF69_MODE_TX: self._writeReg(REG_OPMODE, (self._readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_TRANSMITTER) if self._isRFM69HW: self.setHighPowerRegs(True) elif newMode == RF69_MODE_RX: self._writeReg(REG_OPMODE, (self._readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_RECEIVER) if self._isRFM69HW: self.setHighPowerRegs(False) elif newMode == RF69_MODE_SYNTH: self._writeReg(REG_OPMODE, (self._readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SYNTHESIZER) elif newMode == RF69_MODE_STANDBY: self._writeReg(REG_OPMODE, (self._readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_STANDBY) elif newMode == RF69_MODE_SLEEP: self._writeReg(REG_OPMODE, (self._readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SLEEP) # we are using packet mode, so this check is not really needed # but waiting for mode ready is necessary when going from sleep because the FIFO may not # be immediately available from previous mode while (self._mode == RF69_MODE_SLEEP and (self._readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00): # Wait for ModeReady pass self._mode = newMode def _canSend(self): #if signal stronger than -100dBm is detected assume channel activity if (self._mode == RF69_MODE_RX and self.PAYLOADLEN == 0 and self.getRSSI() < CSMA_LIMIT): self._setMode(RF69_MODE_STANDBY) return True return False def _sendFrame(self, toAddress, buffer, bufferSize, requestACK=False, sendACK=False): self._setMode(RF69_MODE_STANDBY) #turn off receiver to prevent reception while filling fifo while ((self._readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00): pass # Wait for ModeReady self._writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00) # DIO0 is "Packet Sent" if bufferSize > RF69_MAX_DATA_LEN: bufferSize = RF69_MAX_DATA_LEN #write to FIFO self._select() self.SPI.writebytes([REG_FIFO | 0x80, bufferSize + 3, toAddress, self._address]) #control byte if (sendACK): self.SPI.writebytes([0x80]) elif (requestACK): self.SPI.writebytes([0x40]) else: self.SPI.writebytes([0x00]) bufferBytes = [] for i in range(0, bufferSize): self.SPI.writebytes([ord(buffer[i])]) self._unselect() # no need to wait for transmit mode to be ready since its handled by the radio self._setMode(RF69_MODE_TX) txStart = self._millis() # wait for DIO0 to turn HIGH signalling transmission finish while (GPIO.input(self._interruptPin) == 0 and self._millis()-txStart < RF69_TX_LIMIT_MS): pass self._setMode(RF69_MODE_STANDBY) def _interruptHandler(self): if (self._mode == RF69_MODE_RX and (self._readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY)): self._setMode(RF69_MODE_STANDBY) self._select() self.SPI.writebytes([REG_FIFO & 0x7f]) self.PAYLOADLEN = self.SPI.readbytes(1)[0] self.PAYLOADLEN = 66 if self.PAYLOADLEN > 66 else self.PAYLOADLEN self.TARGETID = self.SPI.readbytes(1)[0] # match this node's address, or broadcast address or anything in promiscuous mode # address situation could receive packets that are malformed and don't fit this libraries extra fields if(not(self._promiscuousMode or self.TARGETID==self._address or self.TARGETID==RF69_BROADCAST_ADDR) or self.PAYLOADLEN < 3): self.PAYLOADLEN = 0 self._unselect() self._receiveBegin() return self.DATALEN = self.PAYLOADLEN - 3 self.SENDERID = self.SPI.readbytes(1)[0] CTLbyte = self.SPI.readbytes(1)[0] self.ACK_RECEIVED = CTLbyte & 0x80 #extract ACK-requested flag self.ACK_REQUESTED = CTLbyte & 0x40 #extract ACK-received flag self.DATA = self.SPI.readbytes(self.DATALEN) self._unselect() self._setMode(RF69_MODE_RX) self.RSSI = self.getRSSI() def _noInterrupts(self): pass def _interrupts(self): pass def _receiveBegin(self): self.DATALEN = 0 self.SENDERID = 0 self.TARGETID = 0 self.PAYLOADLEN = 0 self.ACK_REQUESTED = 0 self.ACK_RECEIVED = 0 self.RSSI = 0 if (self._readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY): # avoid RX deadlocks self._writeReg(REG_PACKETCONFIG2, (self._readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART) #set DIO0 to "PAYLOADREADY" in receive mode self._writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01) self._setMode(RF69_MODE_RX) def initialize(self, freqBand, nodeId, networkID): self._address = nodeId config = [ [ REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY ], [ REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00 ], #no shaping [ REG_BITRATEMSB, RF_BITRATEMSB_55555], #default:4.8 KBPS [ REG_BITRATELSB, RF_BITRATELSB_55555], [ REG_FDEVMSB, RF_FDEVMSB_50000], #default:5khz, (FDEV + BitRate/2 <= 500Khz) [ REG_FDEVLSB, RF_FDEVLSB_50000], [ REG_FRFMSB, RF_FRFMSB_315 if freqBand == RF69_315MHZ else (RF_FRFMSB_433 if freqBand == RF69_433MHZ else (RF_FRFMSB_868 if freqBand == RF69_868MHZ else RF_FRFMSB_915)) ], [ REG_FRFMID, RF_FRFMID_315 if freqBand == RF69_315MHZ else (RF_FRFMID_433 if freqBand == RF69_433MHZ else (RF_FRFMID_868 if freqBand == RF69_868MHZ else RF_FRFMID_915)) ], [ REG_FRFLSB, RF_FRFLSB_315 if freqBand == RF69_315MHZ else (RF_FRFLSB_433 if freqBand == RF69_433MHZ else (RF_FRFLSB_868 if freqBand == RF69_868MHZ else RF_FRFLSB_915)) ], # looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm # +17dBm and +20dBm are possible on RFM69HW # +13dBm formula: Pout=-18+OutputPower (with PA0 or PA1**) # +17dBm formula: Pout=-14+OutputPower (with PA1 and PA2)** # +20dBm formula: Pout=-11+OutputPower (with PA1 and PA2)** and high power PA settings (section 3.3.7 in datasheet) #[ REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | RF_PALEVEL_OUTPUTPOWER_11111], #[ REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95 ], #over current protection (default is 95mA) # RXBW defaults are [ REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_5] (RxBw: 10.4khz) [ REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2 ], #(BitRate < 2 * RxBw) # for BR-19200: #* 0x19 */ [ REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 ], [ REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01 ], #DIO0 is the only IRQ we're using [ REG_RSSITHRESH, 220 ], #must be set to dBm = (-Sensitivity / 2) - default is 0xE4=228 so -114dBm #[ REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE ] # default 3 preamble bytes 0xAAAAAA [ REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0 ], [ REG_SYNCVALUE1, 0x2D ], #attempt to make this compatible with sync1 byte of RFM12B lib [ REG_SYNCVALUE2, networkID ], #NETWORK ID [ REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF ], [ REG_PAYLOADLENGTH, 66 ], #in variable length mode: the max frame size, not used in TX #[ REG_NODEADRS, nodeID ], #turned off because we're not using address filtering [ REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE ], #TX on FIFO not empty [ REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_2BITS | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF ], #RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) # for BR-19200: #* 0x3d */ [ REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF ], #RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) #[ REG_TESTDAGC, RF_DAGC_CONTINUOUS ], # run DAGC continuously in RX mode [ REG_TESTDAGC, RF_DAGC_IMPROVED_LOWBETA0 ], # run DAGC continuously in RX mode, recommended default for AfcLowBetaOn=0 [255, 0] ] print "writing REG_SYNCVALUE1" while self._readReg(REG_SYNCVALUE1) != 0xaa: self._writeReg(REG_SYNCVALUE1, 0xaa) while self._readReg(REG_SYNCVALUE1) != 0x55: self._writeReg(REG_SYNCVALUE1, 0x55) print "done writing REG_SYNCVALUE1" for chunk in config: self._writeReg(chunk[0], chunk[1]) self.setEncryptionKey(None) self.setHighPower(self._isRFM69HW) self._setMode(RF69_MODE_STANDBY) # wait for mode ready while (self._readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00: pass self._interrupts() def sleep(self): self._setMode(RF69_MODE_SLEEP) def setAddress(self, addr): self._address = addr self._writeReg(REG_NODEADRS, self._address) def setNetwork(self, networkID): self._writeReg(REG_SYNCVALUE2, networkID) # set output power: 0=min, 31=max # this results in a "weaker" transmitted signal, and directly results in a lower RSSI at the receiver def setPowerLevel(self, powerLevel): self._powerLevel = powerLevel self._writeReg(REG_PALEVEL, (_readReg(REG_PALEVEL) & 0xE0) | (self._powerLevel if self._powerLevel < 31 else 31)) def send(self, toAddress, buffer, bufferSize, requestACK): self._writeReg(REG_PACKETCONFIG2, (self._readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART) # avoid RX deadlocks now = self._millis() while (not self._canSend() and self._millis()-now < RF69_CSMA_LIMIT_MS): self.receiveDone() self._sendFrame(toAddress, buffer, bufferSize, requestACK, False) # to increase the chance of getting a packet across, call this function instead of send # and it handles all the ACK requesting/retrying for you :) # The only twist is that you have to manually listen to ACK requests on the other side and send back the ACKs # The reason for the semi-automaton is that the lib is ingterrupt driven and # requires user action to read the received data and decide what to do with it # replies usually take only 5-8ms at 50kbps@915Mhz def sendWithRetry(self, toAddress, buffer, bufferSize, retries=2, retryWaitTime=40): for i in range(0, retries): self.send(toAddress, buffer, bufferSize, True) sentTime = self._millis() while self._millis()-sentTime<retryWaitTime: if self.ACKReceived(toAddress): return True return False # Should be polled immediately after sending a packet with ACK request def ACKReceived(self, fromNodeID): if self.receiveDone(): return (self.SENDERID == fromNodeID or fromNodeID == RF69_BROADCAST_ADDR) and self.ACK_RECEIVED return False #check whether an ACK was requested in the last received packet (non-broadcasted packet) def ACKRequested(self): return self.ACK_REQUESTED and (self.TARGETID != RF69_BROADCAST_ADDR) # Should be called immediately after reception in case sender wants ACK def sendACK(self, buffer="", bufferSize=0): sender = self.SENDERID _RSSI = self.RSSI #save payload received RSSI value self._writeReg(REG_PACKETCONFIG2, (self._readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART) # avoid RX deadlocks now = self._millis() while (not self._canSend() and self._millis()-now < RF69_CSMA_LIMIT_MS): self.receiveDone() self._sendFrame(sender, buffer, bufferSize, False, True) self.RSSI = _RSSI #restore payload RSSI def receiveDone(self): self._noInterrupts() #re-enabled in _unselect() via _setMode() or via _receiveBegin() if GPIO.input(self._interruptPin): self._interruptHandler() if (self._mode == RF69_MODE_RX and self.PAYLOADLEN > 0): self._setMode(RF69_MODE_STANDBY) #enables interrupts return True elif (self._mode == RF69_MODE_RX): #already in RX no payload yet self._interrupts() #explicitly re-enable interrupts return False self._receiveBegin() return False # To enable encryption: radio.encrypt("ABCDEFGHIJKLMNOP") # To disable encryption: radio.encrypt(null) # KEY HAS TO BE 16 bytes !!! def setEncryptionKey(self, key): if key is not None: if len(key) != 16: raise Exception("Key must be exactly 16 bytes!") self._setMode(RF69_MODE_STANDBY) if (key is not None): keyBytes = [] self._select() self.SPI.writebytes([REG_AESKEY1 | 0x80]) for i in range(0,16): keyBytes.append(ord(key[i])) self.SPI.writebytes(keyBytes) self._unselect() self._writeReg(REG_PACKETCONFIG2, (self._readReg(REG_PACKETCONFIG2) & 0xFE) | (0 if key is None else 1)) # The following methods are not required by BaseRadio. # They depend too heavily on the specific radio hardware and would not get any benefit from being part of the # BaseRadio class. def getRSSI(self, forceTrigger=False): rssi = 0 if (forceTrigger): # RSSI trigger not needed if DAGC is in continuous mode self._writeReg(REG_RSSICONFIG, RF_RSSI_START) while ((self._readReg(REG_RSSICONFIG) & RF_RSSI_DONE) == 0x00): pass # Wait for RSSI_Ready rssi = -self._readReg(REG_RSSIVALUE) rssi >>= 1 return rssi # ON = disable filtering to capture all frames on network # OFF = enable node+broadcast filtering to capture only frames sent to this/broadcast address def setPromiscuous(self, onOff): self._promiscuousMode = onOff def setHighPower(self, onOff): self._isRFM69HW = onOff self._writeReg(REG_OCP, RF_OCP_OFF if self._isRFM69HW else RF_OCP_ON) if (self._isRFM69HW): # enable P1 & P2 amplifier stages self._writeReg(REG_PALEVEL, (self._readReg(REG_PALEVEL) & 0x1F) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON) else: # enable P0 only self._writeReg(REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | self.powerLevel) def setHighPowerRegs(self, onOff): self._writeReg(REG_TESTPA1, 0x5D if onOff else 0x55) self._writeReg(REG_TESTPA2, 0x7C if onOff else 0x70) def readAllRegs(self): print "Register, Address, Value" print "REG_FIFO, 0x00, {}".format(hex(self._readReg(REG_FIFO))) print "REG_OPMODE, 0x01, {}".format(hex(self._readReg(REG_OPMODE))) print "REG_DATAMODUL, 0x02, {}".format(hex(self._readReg(REG_DATAMODUL))) print "REG_BITRATEMSB, 0x03, {}".format(hex(self._readReg(REG_BITRATEMSB))) print "REG_BITRATELSB, 0x04, {}".format(hex(self._readReg(REG_BITRATELSB))) print "REG_FDEVMSB, 0x05, {}".format(hex(self._readReg(REG_FDEVMSB))) print "REG_FDEVLSB, 0x06, {}".format(hex(self._readReg(REG_FDEVLSB))) print "REG_FRFMSB, 0x07, {}".format(hex(self._readReg(REG_FRFMSB))) print "REG_FRFMID, 0x08, {}".format(hex(self._readReg(REG_FRFMID))) print "REG_FRFLSB, 0x09, {}".format(hex(self._readReg(REG_FRFLSB))) print "REG_OSC1, 0x0A, {}".format(hex(self._readReg(REG_OSC1))) print "REG_AFCCTRL, 0x0B, {}".format(hex(self._readReg(REG_AFCCTRL))) print "REG_LOWBAT, 0x0C, {}".format(hex(self._readReg(REG_LOWBAT))) print "REG_LISTEN1, 0x0D, {}".format(hex(self._readReg(REG_LISTEN1))) print "REG_LISTEN2, 0x0E, {}".format(hex(self._readReg(REG_LISTEN2))) print "REG_LISTEN3, 0x0F, {}".format(hex(self._readReg(REG_LISTEN3))) print "REG_VERSION, 0x10, {}".format(hex(self._readReg(REG_VERSION))) print "REG_PALEVEL, 0x11, {}".format(hex(self._readReg(REG_PALEVEL))) print "REG_PARAMP, 0x12, {}".format(hex(self._readReg(REG_PARAMP))) print "REG_OCP, 0x13, {}".format(hex(self._readReg(REG_OCP))) print "REG_AGCREF, 0x14, {}".format(hex(self._readReg(REG_AGCREF))) print "REG_AGCTHRESH1, 0x15, {}".format(hex(self._readReg(REG_AGCTHRESH1))) print "REG_AGCTHRESH2, 0x16, {}".format(hex(self._readReg(REG_AGCTHRESH2))) print "REG_AGCTHRESH3, 0x17, {}".format(hex(self._readReg(REG_AGCTHRESH3))) print "REG_LNA, 0x18, {}".format(hex(self._readReg(REG_LNA))) print "REG_RXBW, 0x19, {}".format(hex(self._readReg(REG_RXBW))) print "REG_AFCBW, 0x1A, {}".format(hex(self._readReg(REG_AFCBW))) print "REG_OOKPEAK, 0x1B, {}".format(hex(self._readReg(REG_OOKPEAK))) print "REG_OOKAVG, 0x1C, {}".format(hex(self._readReg(REG_OOKAVG))) print "REG_OOKFIX, 0x1D, {}".format(hex(self._readReg(REG_OOKFIX))) print "REG_AFCFEI, 0x1E, {}".format(hex(self._readReg(REG_AFCFEI))) print "REG_AFCMSB, 0x1F, {}".format(hex(self._readReg(REG_AFCMSB))) print "REG_AFCLSB, 0x20, {}".format(hex(self._readReg(REG_AFCLSB))) print "REG_FEIMSB, 0x21, {}".format(hex(self._readReg(REG_FEIMSB))) print "REG_FEILSB, 0x22, {}".format(hex(self._readReg(REG_FEILSB))) print "REG_RSSICONFIG, 0x23, {}".format(hex(self._readReg(REG_RSSICONFIG))) print "REG_RSSIVALUE, 0x24, {}".format(hex(self._readReg(REG_RSSIVALUE))) print "REG_DIOMAPPING1, 0x25, {}".format(hex(self._readReg(REG_DIOMAPPING1))) print "REG_DIOMAPPING2, 0x26, {}".format(hex(self._readReg(REG_DIOMAPPING2))) print "REG_IRQFLAGS1, 0x27, {}".format(hex(self._readReg(REG_IRQFLAGS1))) print "REG_IRQFLAGS2, 0x28, {}".format(hex(self._readReg(REG_IRQFLAGS2))) print "REG_RSSITHRESH, 0x29, {}".format(hex(self._readReg(REG_RSSITHRESH))) print "REG_RXTIMEOUT1, 0x2A, {}".format(hex(self._readReg(REG_RXTIMEOUT1))) print "REG_RXTIMEOUT2, 0x2B, {}".format(hex(self._readReg(REG_RXTIMEOUT2))) print "REG_PREAMBLEMSB, 0x2C, {}".format(hex(self._readReg(REG_PREAMBLEMSB))) print "REG_PREAMBLELSB, 0x2D, {}".format(hex(self._readReg(REG_PREAMBLELSB))) print "REG_SYNCCONFIG, 0x2E, {}".format(hex(self._readReg(REG_SYNCCONFIG))) print "REG_SYNCVALUE1, 0x2F, {}".format(hex(self._readReg(REG_SYNCVALUE1))) print "REG_SYNCVALUE2, 0x30, {}".format(hex(self._readReg(REG_SYNCVALUE2))) print "REG_SYNCVALUE3, 0x31, {}".format(hex(self._readReg(REG_SYNCVALUE3))) print "REG_SYNCVALUE4, 0x32, {}".format(hex(self._readReg(REG_SYNCVALUE4))) print "REG_SYNCVALUE5, 0x33, {}".format(hex(self._readReg(REG_SYNCVALUE5))) print "REG_SYNCVALUE6, 0x34, {}".format(hex(self._readReg(REG_SYNCVALUE6))) print "REG_SYNCVALUE7, 0x35, {}".format(hex(self._readReg(REG_SYNCVALUE7))) print "REG_SYNCVALUE8, 0x36, {}".format(hex(self._readReg(REG_SYNCVALUE8))) print "REG_PACKETCONFIG1, 0x37, {}".format(hex(self._readReg(REG_PACKETCONFIG1))) print "REG_PAYLOADLENGTH, 0x38, {}".format(hex(self._readReg(REG_PAYLOADLENGTH))) print "REG_NODEADRS, 0x39, {}".format(hex(self._readReg(REG_NODEADRS))) print "REG_BROADCASTADRS, 0x3A, {}".format(hex(self._readReg(REG_BROADCASTADRS))) print "REG_AUTOMODES, 0x3B, {}".format(hex(self._readReg(REG_AUTOMODES))) print "REG_FIFOTHRESH, 0x3C, {}".format(hex(self._readReg(REG_FIFOTHRESH))) print "REG_PACKETCONFIG2, 0x3D, {}".format(hex(self._readReg(REG_PACKETCONFIG2))) print "REG_AESKEY1, 0x3E, {}".format(hex(self._readReg(REG_AESKEY1))) print "REG_AESKEY2, 0x3F, {}".format(hex(self._readReg(REG_AESKEY2))) print "REG_AESKEY3, 0x40, {}".format(hex(self._readReg(REG_AESKEY3))) print "REG_AESKEY4, 0x41, {}".format(hex(self._readReg(REG_AESKEY4))) print "REG_AESKEY5, 0x42, {}".format(hex(self._readReg(REG_AESKEY5))) print "REG_AESKEY6, 0x43, {}".format(hex(self._readReg(REG_AESKEY6))) print "REG_AESKEY7, 0x44, {}".format(hex(self._readReg(REG_AESKEY7))) print "REG_AESKEY8, 0x45, {}".format(hex(self._readReg(REG_AESKEY8))) print "REG_AESKEY9, 0x46, {}".format(hex(self._readReg(REG_AESKEY9))) print "REG_AESKEY10, 0x47, {}".format(hex(self._readReg(REG_AESKEY10))) print "REG_AESKEY11, 0x48, {}".format(hex(self._readReg(REG_AESKEY11))) print "REG_AESKEY12, 0x49, {}".format(hex(self._readReg(REG_AESKEY12))) print "REG_AESKEY13, 0x4A, {}".format(hex(self._readReg(REG_AESKEY13))) print "REG_AESKEY14, 0x4B, {}".format(hex(self._readReg(REG_AESKEY14))) print "REG_AESKEY15, 0x4C, {}".format(hex(self._readReg(REG_AESKEY15))) print "REG_AESKEY16, 0x4D, {}".format(hex(self._readReg(REG_AESKEY16))) print "REG_TEMP1, 0x4E, {}".format(hex(self._readReg(REG_TEMP1))) print "REG_TEMP2, 0x4F, {}".format(hex(self._readReg(REG_TEMP2))) if self._isRFM69HW: print "REG_TESTPA1, 0x5A, {}".format(hex(self._readReg(REG_TESTPA1))) print "REG_TESTPA2, 0x5C, {}".format(hex(self._readReg(REG_TESTPA2))) print "REG_TESTDAGC, 0x6F, {}".format(hex(self._readReg(REG_TESTDAGC))) # returns centigrade def readTemperature(self, calFactor): self._setMode(RF69_MODE_STANDBY) self._writeReg(REG_TEMP1, RF_TEMP1_MEAS_START) while ((self._readReg(REG_TEMP1) & RF_TEMP1_MEAS_RUNNING)): pass #'complement'corrects the slope, rising temp = rising val # COURSE_TEMP_COEF puts reading in the ballpark, user can add additional correction return ~self._readReg(REG_TEMP2) + COURSE_TEMP_COEF + calFactor def rcCalibration(self): _writeReg(REG_OSC1, RF_OSC1_RCCAL_START) while ((_readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00): pass
import time from Adafruit_BBIO.SPI import SPI spi_in = SPI(0,0) spi_out = SPI(0,1) while True: try: spi_out.writebytes([0x50]) print spi_in.readbytes(2) time.sleep(0.02) except KeyboardInterrupt: break
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