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])
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])
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 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 PullData(): print("pull data") spi = SPI(1, 0) spi.msh = 100000 spi.bpw = 8 spi.writebytes([0x30]) sleep(0.1) moistureVals = spi.readbytes(3) moisture = str(moistureVals[0]) + str(moistureVals[1]) + str(moistureVals[2]) spi.writebytes([0x31]) sleep(0.1) moistureVals1 = spi.readbytes(3) moisture1 = str(moistureVals1[0]) + str(moistureVals1[1]) + str(moistureVals1[2]) spi.writebytes([0x35]) sleep(0.1) lightVals = spi.readbytes(3) light = str(lightVals[0]) + str(lightVals[1]) + str(lightVals[2]) Data = [] Data.append(moisture) Data.append(moisture1) Data.append(light) spi.close() return Data
### 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) GPIO.cleanup()
class LED_LPD8806(object): # Constructor def __init__(self): self.spi = SPI(0,0) #/dev/spidev1.0 (be sure to run Python with su if 'no permission' self.spi.msh=1000000 #SPI clock set to 1MHz (slowed from 10MHz for better stability across setups) self.spi.bpw = 8 # bits per word self.spi.threewire = False # not half-duplex self.spi.lsbfirst = False # we want MSB first self.spi.mode = 0 # options are modes 0 through 3 self.spi.cshigh = False # we want chip select to be active low self.spi.open(0,0) # make it so time.sleep(0.05) def setup(self, led_pixels, debug=False): if (debug): print "Initializing LED strip" global pixels pixels = [[0x80 for x in range(3)] for y in range(led_pixels)] for i in range(led_pixels): pixels[i]=[0x00, 0x00, 0x00] # Define LED functions: # -------------------- # Update pixel display with a given delay time between pixel updates: def writestrip(self, delay): if (delay < 0): delay = 0 for i in range(len(pixels)): self.spi.writebytes([0x00, 0x00, 0x00]) #prepare write for i in range(len(pixels)): self.spi.writebytes(pixels[i]) #write colors to pixels time.sleep(delay) # Turn off all LEDs: def clearstrip(self): global pixels for i in range(len(pixels)): self.spi.writebytes([0x00, 0x00, 0x00]) #prepare write for i in range(len(pixels)): pixels[i] = [0x80, 0x80, 0x80] self.writestrip(0) # Set an individual pixel to a specific color (to display later): def setpixelcolor(self, n, g, r, b): global pixels if (n >= len(pixels)): return if (n < 0): return if (g > 0xFF): g = 0xFF if (g < 0x80): g = 0x80 if (r > 0xFF): r = 0xFF if (r < 0x80): r = 0x80 if (b > 0xFF): b = 0xFF if (b < 0x80): b = 0x80 pixels[n] = [g, r, b] # Update display with warmer colors (more red light) by a specified amount with a delay between pixels def warmstrip(self, warmth, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][1] + warmth) < 0x80): pixels[n][1] = 0x80 elif((pixels[n][2] + warmth) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1]+warmth self.writestrip(delay) # Update display with cooler colors (more blue) by a specified amount with a delay between each pixel def coolstrip(self, coolfactor, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][2] + coolfactor) < 0x80): pixels[n][2] = 0x80 elif((pixels[n][2] + coolfactor) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2]+coolfactor self.writestrip(delay) # Update display with greener colors by a specified amount with a set delay between each pixel def greenstrip(self, lushness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][0] + lushness) < 0x80): pixels[n][0] = 0x80 else: pixels[n][0] = pixels[n][0]+lushness self.writestrip(delay) # Update display with brighter (whiter) light by specified amount with a set delay between pixel updates def brightenstrip(self, brightness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][0] + brightness) < 0x80): pixels[n][0] = 0x80 elif((pixels[n][0] + brightness) > 0xFF): pixels[n][0] = 0xFF else: pixels[n][0] = pixels[n][0]+brightness if((pixels[n][1] + brightness) < 0x80): pixels[n][1] = 0x80 elif((pixels[n][1] + brightness) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1]+brightness if((pixels[n][2] + brightness) < 0x80): pixels[n][2] = 0x80 elif((pixels[n][2] + brightness) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2]+brightness self.writestrip(delay) # Darken display (less light) by specified amount with a set delay between pixel updates def dimstrip(self, dimness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if((pixels[n][0] - dimness) < 0x80): pixels[n][0] = 0x80 elif((pixels[n][0] - dimness) > 0xFF): pixels[n][0] = 0xFF else: pixels[n][0] = pixels[n][0]-dimness if((pixels[n][1] - dimness) < 0x80): pixels[n][1] = 0x80 elif((pixels[n][1] - dimness) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1]-dimness if((pixels[n][2] - dimness) < 0x80): pixels[n][2] = 0x80 elif((pixels[n][2] - dimness) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2]-dimness self.writestrip(delay)
class BStabBb: 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 get_max_dac_value(self): return self.maxDACvalue def adjust_b_field(self, freq_diff, corrFactor=1): [cDAC, fDAC] = self.calcNewDACvaluesFromFreqDiff(freq_diff, corrFactor) self.setStabiliserDACs(cDAC, fDAC) def setStabiliserDACs(self, cDacValue, fDacValue, verbose=False): """Update feedback DAC values""" self.set_DAC_values(CDAC=cDacValue,FDAC=fDacValue) dacValues = {'cDAC':cDacValue,'fDAC':fDacValue} pyon.store_file(self.fname, dacValues) #self.set_dataset("BField_stabiliser.cDAC", float(cDacValue), persist=True, broadcast=True) #self.set_dataset("BField_stabiliser.fDAC", float(fDacValue), persist=True, broadcast=True) #if verbose: # print("Update DACs {} {} --- Done.".format(int(cDacValue),int(fDacValue))) return dacValues def checkStabiliserOutput(self, volt_margin=3, verbose=False): """Read feedback shunt voltage via ssh connection""" shunt_ok = False shunt_voltage = self.read_voltage() if shunt_voltage > (10-volt_margin): shunt_ok_msg = "Too high!" elif shunt_voltage < volt_margin: shunt_ok_msg = "Too low!" else: shunt_ok = True shunt_ok_msg = "Fine." if verbose: print("Read ADC --- Shunt input voltage: {} --- {}".format(shunt_voltage, shunt_ok_msg)) # to do: raise Error when railing return shunt_ok def getSlopes(self): """Return conversion factors [cDAC_per_mG,fDAC_per_mG] """ """Use for scanning the magnetic field""" # fine DAC gain 1 # coarse DAC gain 200 mG_per_fDACvalue = self.mG_per_mVerr * self.mVDAC_per_DACvalue mG_per_cDACvalue = self.mG_per_mVerr * 200 * self.mVDAC_per_DACvalue return {'cDAC_per_mG': 1.0/mG_per_cDACvalue, 'fDAC_per_mG': 1.0/mG_per_fDACvalue} def calcNewDACvaluesFromFreqDiff(self, freq_diff, corrFactor=1): """Calculate new DAC values, based on the stretch qubit frequency difference to the setpoint""" # least significant bits in mV output fDAClsb = self.mVDAC_per_DACvalue # VERR = 200*cDAC + fDAC - 202*DIFF_SIG cDAClsb = 200 * fDAClsb VERR_diff = freq_diff / self.kHz_per_mVerr / 1e3 VERR_corr = VERR_diff * corrFactor if abs(VERR_corr) > 10*cDAClsb: change_cDAC = - int(round(VERR_corr / cDAClsb)) change_fDAC = 0 else: change_cDAC = 0 change_fDAC = - int(round(VERR_corr / fDAClsb)) try: oldDacValues = pyon.load_file(self.fname) #old_cDAC = self.get_dataset("BField_stabiliser.cDAC") #old_fDAC = self.get_dataset("BField_stabiliser.fDAC") except FileNotFoundError: print('Error: could not find file. Using default values') oldDacValues = {'cDAC':54710,'fDAC':33354} old_cDAC = oldDacValues['cDAC'] old_fDAC = oldDacValues['fDAC'] new_cDAC = old_cDAC + change_cDAC new_fDAC = old_fDAC + change_fDAC # when fDAC out of range, change coarse DAC if (new_fDAC > self.maxDACvalue or new_fDAC < 0): new_cDAC += (new_fDAC-30000)/200 new_fDAC = 30000 return [new_cDAC, new_fDAC] def set_DAC_values(self,CDAC=-1,FDAC=-1): ''' this is the external function to be called for setting the coarse and fine dac ''' if CDAC is not -1: self._set_coarse_dac(CDAC) if FDAC is not -1: self._set_fine_dac(FDAC) def read_voltage(self,verbose=0): ''' this is the external function to be called for reading out the ADC voltage ''' # for AD7477: # 2 bytes bytes = self._read_value(self.CS_ADC_PIN, 2) # most significant bit first num = bytes[0] * 256 + bytes[1] # 4 leading zeros, 2 trailing zeros num = num >> 2 # 5V reference, 10 bits AV = 5.0 * num / 1024 # G=0.33 for voltage divider between shunt and ADC # convert to feedback shunt input voltage FB_SHNT_IN_V = 3 * AV if verbose: print("byte response: %X %X"% (bytes[0], bytes[1])) print("num respose: %d" % (num)) print("ADC input voltage: %.2f" % (AV)) print("Feedback shunt input voltage: %.2f" % (FB_SHNT_IN_V)) return AV def test_set_pin(self,logicHigh=1,pin="P8_14"): ''' this is a test function to set a pin on the beaglebone to high or low ''' GPIO.setup(pin, GPIO.OUT) if logicHigh: GPIO.output(pin, GPIO.HIGH) else: GPIO.output(pin, GPIO.LOW) def _set_coarse_dac(self,value): self._set_dac_value(self.CS_FB_COARSE_PIN, value) def _set_fine_dac(self,value): self._set_dac_value(self.CS_FB_FINE_PIN, value) def _set_dac_value(self, cs_pin, value): GPIO.output(cs_pin, GPIO.LOW) value = self._check_dac_value(value) # check if value is in range MSByte = value >> 8 LSByte = value - (MSByte << 8) # write self.spi00.writebytes([MSByte,LSByte]) GPIO.output(cs_pin, GPIO.HIGH) def _check_dac_value(self,value): value = int(value) if value > 65535: value = 65535 if value < 0: value = 0 return value def _read_value(self,cs_pin, length): ''' internal read value of analogue voltage ''' GPIO.output(cs_pin, GPIO.LOW) bytes = self.spi00.readbytes(length) GPIO.output(cs_pin, GPIO.HIGH) return bytes def ping(self): return True
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
POWER SYSTEM: PWR_SYS = "P9_16" ''' #======================================================= # testing SPI #======================================================= while (1): # RST = 1 --> address # GPIO.output(RST, GPIO.HIGH) # time.sleep(0.001) # RST = 0 --> slaves # GPIO.output(RST, GPIO.LOW) # time.sleep(0.001) # send data through SPI spi1.writebytes([0x20, 0x03, 0x12]) spi0.writebytes([0x02, 0x30, 0x21]) # GPIO.output(PWR_SYS, GPIO.HIGH) # GPIO.output(RST, GPIO.HIGH) # GPIO.output(CLR, GPIO.HIGH) # GPIO.output(LDAC, GPIO.HIGH) # GPIO.output(CNV, GPIO.HIGH) # GPIO.output(PWR_SYS, GPIO.LOW) # GPIO.output(RST, GPIO.LOW) # GPIO.output(CLR, GPIO.LOW) # GPIO.output(LDAC, GPIO.LOW) # GPIO.output(CNV, GPIO.LOW)
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 # SCLK P9_22 clk
print "Board temp = ", boardTemp return tempAdc def readLevelsAvg(): crossSumm = 0.0 longSumm = 0.0 levelsAvg = (0.0), (0.0) averageCount = 10 for i in range(10): crossSumm += readCross() longSumm += readLong() levelsAvg[0] = crossSumm / averageCount levelsAvg[1] = longSumm / averageCount #levelsAvg = [crossSumm / averageCount], [longSumm / averageCount] return levelsAvg while (True): spi.writebytes([0x39]) # Update data time.sleep(.5) # crossData = readCross() # longData = readLong() # print "Cross\t", crossData, "\t\tLong\t", longData levelData = readLevelsAvg() print "Cross\t", levelData[0], "\t\tLong\t", levelData[1]
class Brightbar: #[brightness, blue, green, red] pixel_buffer = [POWER, 0, 0, 0] * LEDS_PER_PANEL * NUM_PANELS start_clock = None animation_time = 20000 def __init__(self): self.init_spi() #animation = GifAnimation('gifs/extracted/trippy_39_30x30') #animation = SparkleAnimation(None, SparkleAnimation.SPEED_SLOW, [POWER,255,255,255], 1000) #animation = SparkleAnimation(None, 2000, [POWER,255,255,255], 1000) #animation = LinesAnimation(None, 3000, [POWER,255,255,255], 0) animation = RainAnimation(None, .1, [POWER, 0.0, 200.0, 0.0]) self.animations = [ SparkleAnimation(None, 2000, [POWER, 255, 255, 255], 1000), LinesAnimation(None, 3000, [POWER, 255, 255, 255], 0), RainAnimation(None, .1, [POWER, 0.0, 200.0, 0.0]) ] self.render_thread = None def init_spi(self): logging.debug("Initializing spi...") self.spi = SPI(0, 0) #/dev/spidev1.0 # SPI Mode Clock Polarity (CPOL/CKP) Clock Phase (CPHA) Clock Edge (CKE/NCPHA) # 0 0 0 1 # 1 0 1 0 # 2 1 0 1 # 3 1 1 0 self.spi.mode = 0 self.spi.msh = SPI_CLOCK_RATE #this is clock speed setting self.spi.open(0, 0) def debug_frame(self, data): for y in range(PANEL_Y): line = str(y) + ": " for x in range(PANEL_X): offset = (y * PANEL_X + x) * 4 line += "|" + str(data[offset]) + "," + str( data[offset + 1]) + "," + str( data[offset + 2]) + "," + str(data[offset + 3]) print line #render a full frame def render(self): #logging.debug("buffer size: " + str(len(self.pixel_buffer)) + " start render: " + str(time.time())) start_time = time.time() #logging.debug(" start render: " + str(start_time)) #make a copy of the buffer to work on in case we need to switch the order of bytes #data = self.pixel_buffer[:] offset = 0 #the panels run in a snake S shape, so every other line needs to have bytes reversed if REVERSE_ALTERNATE_LINES: for i in range(0, PANEL_Y): if (i % 2) == 0: continue offset = i * PANEL_X * 4 line_length = PANEL_X * 4 line = data[offset:offset + line_length] reversed_line = [0] * line_length j = line_length - 4 #start one color from the end, and go backwards through the line while j >= 0: reversed_line[line_length - j - 4] = line[j] reversed_line[line_length - j - 3] = line[j + 1] reversed_line[line_length - j - 2] = line[j + 2] reversed_line[line_length - j - 1] = line[j + 3] j = j - 4 data[offset:offset + PANEL_X * 4] = reversed_line #self.write_apa102(data) #logging.debug("length of buffer: " + str(len(self.pixel_buffer))) #logging.debug(self.pixel_buffer) self.write_apa102(self.pixel_buffer) end_time = time.time() #logging.debug("end render: " + str(end_time) + " elapsed: " + str(end_time - start_time)) #import pdb #pdb.set_trace() def write_apa102(self, data): #start frame, 32 bits of zero self.spi.writebytes([0] * 4) #write RGB data #chunk the data out in 1024 byte blocks for i in range(0, len(data), 1024): length = len(data) if ((i + 1024) > length): #end = length - (i+1024 - length) chunk = data[i:] else: #end = i + 1024 chunk = data[i:i + 1024] self.spi.writebytes(chunk) #write footer. This is total numnber of LEDS / 2 bits of 1's num_dwords = LEDS_PER_PANEL * NUM_PANELS / 32 for i in range(num_dwords): self.spi.writebytes( [0xff, 0x00, 0x00, 0x00] ) #the datasheet calls for 1's here, but internet says 0s work better? the fast LED lib does both? def clear(self): self.pixel_buffer = [POWER, 0, 0, 0] * LEDS_PER_PANEL * NUM_PANELS def calculate_fps(self): now = time.time() delta = now - self.start_clock frame_time = delta / self.frame_count self.fps = 1 / frame_time logging.debug("elapsed seconds: " + str(delta) + " frame count: " + str(self.frame_count) + " current fps: " + str(self.fps)) def animate(self): if self.start_clock == None: self.frame_count = 0 self.start_clock = time.time() elapsed_time = time.time() - self.start_clock num_animations = int(round(elapsed_time / (self.animation_time / 1000))) current_animation = int(num_animations) % len(self.animations) #logging.debug("elapsed time: " + str(elapsed_time) + " num animations:" + str(num_animations) + " current animation:" + str(current_animation)) animation = self.animations[current_animation] frame = animation.get_next_frame() if frame == None: time.sleep(.001) return self.frame_count = self.frame_count + 1 if self.frame_count % 100 == 0: self.calculate_fps() line_length = animation.width * 4 for y in range(animation.height): frame_offset = y * line_length line = frame[frame_offset:frame_offset + line_length] buffer_offset = (( (int(animation.destination_y_offset) + y) * PANEL_X) + int(animation.destination_x_offset)) * 4 self.pixel_buffer[buffer_offset:buffer_offset + line_length] = line def render_loop(self): try: while 1: brightbar.animate() brightbar.render() except: print_exception(*sys.exc_info()) def start(self): if STARTUP_SEQUENCE: startup_sequence(self) if self.render_thread == None: self.render_thread = threading.Thread(name="RenderThread", target=self.render_loop) self.render_thread.start() def stop(self): self.render_thread.stop()
class 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
# write to RDAC spi.xfer(list(struct.unpack('BB', struct.pack('>H', 1 << 10 | 0)))) # read RDAC spi.xfer(list(struct.unpack('BB', struct.pack('>H', 0b10 << 10 | 0)))) # read Control register spi.xfer(list(struct.unpack('BB', struct.pack('>H', 0b111 << 10 | 0)))) spi.readbytes(2) for i in range(1024): spi.xfer(list(struct.unpack('BB', struct.pack('>H', 1 << 10 | i)))) time.sleep(.2) spi.writebytes([0x0,0x0]) spi.writebytes([0x18,0x02]) spi.writebytes([0x05,0x00]) spi.writebytes([0x08,0x0]) spi.writebytes([0x0,0x0]) spi.writebytes([0x0,0x0]) spi.writebytes([0x0,0x0]) spi.xfer([0x0,0x0]) spi.xfer([0x18,0x02]) spi.xfer([0x05,0x00]) spi.xfer([0x08,0x0]) spi.xfer([0x0,0x0]) class voltage_divider:
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 EPD(object): 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) def digital_write(self, pin, value): return GPIO.output(pin, value) def digital_read(self, pin): return GPIO.input(pin) def delay_ms(self, delaytime): time.sleep(delaytime / 1000.0) def send_command(self, command): self.digital_write(DC_PIN, GPIO.LOW) self.spi.writebytes([command]) def send_data(self, data): self.digital_write(DC_PIN, GPIO.HIGH) self.spi.writebytes([data]) def init(self): """ Preform the hardware initialization sequence """ # Interface initialization: GPIO.setwarnings(False) GPIO.setup(RST_PIN, GPIO.OUT) GPIO.setup(DC_PIN, GPIO.OUT) GPIO.setup(CS_PIN, GPIO.OUT) GPIO.setup(BUSY_PIN, GPIO.IN) self.spi.msh = 2000000 self.spi.mode = 0b00 # EPD hardware init # The specifics of how this works or what "power optimization" actually means # are unclear to me, so I'm leaving it as-is. self.reset() self.send_command(POWER_SETTING) self.send_data(0x03) # VDS_EN, VDG_EN self.send_data(0x00) # VCOM_HV, VGHL_LV[1], VGHL_LV[0] self.send_data(0x2b) # VDH self.send_data(0x2b) # VDL self.send_data(0x09) # VDHR self.send_command(BOOSTER_SOFT_START) self.send_data(0x07) self.send_data(0x07) self.send_data(0x17) # Power optimization self.send_command(0xF8) self.send_data(0x60) self.send_data(0xA5) # Power optimization self.send_command(0xF8) self.send_data(0x89) self.send_data(0xA5) # Power optimization self.send_command(0xF8) self.send_data(0x90) self.send_data(0x00) # Power optimization self.send_command(0xF8) self.send_data(0x93) self.send_data(0x2A) # Power optimization self.send_command(0xF8) self.send_data(0xA0) self.send_data(0xA5) # Power optimization self.send_command(0xF8) self.send_data(0xA1) self.send_data(0x00) # Power optimization self.send_command(0xF8) self.send_data(0x73) self.send_data(0x41) self.send_command(PARTIAL_DISPLAY_REFRESH) self.send_data(0x00) self.send_command(POWER_ON) self.wait_until_idle() self.send_command(PANEL_SETTING) self.send_data(0xAF) # KW-BF KWR-AF BWROTP 0f self.send_command(PLL_CONTROL) self.send_data(0x3A) # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ self.send_command(VCM_DC_SETTING_REGISTER) self.send_data(0x12) self.delay_ms(2) self.set_lut() # EPD hardware init end self._init_performed = True def wait_until_idle(self): """ Wait until screen is idle by polling the busy pin """ while(self.digital_read(BUSY_PIN) == 0): # 0: busy, 1: idle self.delay_ms(50) def reset(self): """ Module reset """ self.digital_write(RST_PIN, GPIO.LOW) self.delay_ms(200) self.digital_write(RST_PIN, GPIO.HIGH) self.delay_ms(200) def set_lut(self, fast=False): """ Set LUT for the controller. If `fast` is srt to True, quick update LUTs from Ben Krasnow will be used""" lut_to_use = LUT if not fast else QuickLUT # Quick LUTs courtsey of Ben Krasnow: # http://benkrasnow.blogspot.co.il/2017/10/fast-partial-refresh-on-42-e-paper.html # https://www.youtube.com/watch?v=MsbiO8EAsGw self.send_command(LUT_FOR_VCOM) # vcom for byte in lut_to_use.lut_vcom_dc: self.send_data(byte) self.send_command(LUT_WHITE_TO_WHITE) # ww -- for byte in lut_to_use.lut_ww: self.send_data(byte) self.send_command(LUT_BLACK_TO_WHITE) # bw r for byte in lut_to_use.lut_bw: self.send_data(byte) self.send_command(LUT_WHITE_TO_BLACK) # wb w for byte in lut_to_use.lut_wb: self.send_data(byte) self.send_command(LUT_BLACK_TO_BLACK) # bb b for byte in lut_to_use.lut_bb: self.send_data(byte) def _get_frame_buffer(self, image): """ Get a full frame buffer from a PIL Image object """ image_monocolor = image.convert('1') imwidth, imheight = image_monocolor.size if imwidth != self.width or imheight != self.height: raise ValueError('Image must be same dimensions as display \ ({0}x{1}).' .format(self.width, self.height)) return self._get_frame_buffer_for_size(image_monocolor, self.height, self.width) def _get_frame_buffer_for_size(self, image_monocolor, height, width): """ Get a frame buffer object from a PIL Image object assuming a specific size""" buf = [0x00] * (width * height // 8) pixels = image_monocolor.load() for y in range(height): for x in range(width): # Set the bits for the column of pixels at the current position if pixels[x, y] != 0: buf[(x + y * width) // 8] |= (0x80 >> (x % 8)) return buf def display_frame(self, image): """ Display a full frame, doing a full screen refresh """ if not self._init_performed: # Initialize the hardware if it wasn't already initialized self.init() self.set_lut() frame_buffer = self._get_frame_buffer(image) self.send_command(DATA_START_TRANSMISSION_1) self.delay_ms(2) for _ in range(0, self.width * self.height // 8): self.send_data(0xFF) self.delay_ms(2) self.send_command(DATA_START_TRANSMISSION_2) self.delay_ms(2) for i in range(0, self.width * self.height // 8): self.send_data(frame_buffer[i]) self.delay_ms(2) self.send_command(DISPLAY_REFRESH) self.wait_until_idle() self._last_frame = image.copy() self._partial_refresh_count = 0 # reset the partial refreshes counter def _send_partial_frame_dimensions(self, x, y, l, w): self.send_data(x >> 8) self.send_data(x & 0xf8) self.send_data(y >> 8) self.send_data(y & 0xff) self.send_data(w >> 8) self.send_data(w & 0xf8) self.send_data(l >> 8) self.send_data(l & 0xff) def display_partial_frame(self, image, x, y, h, w, fast=False): """ Display a partial frame, only refreshing the changed area. `image` is a Pillow Image object `x` and `y` are the top left coordinates `h` is the height of the area to update `w` is the width of the area to update. if `fast` is True, fast refresh lookup tables will be used. see `smart_update()` method documentation for details.""" if fast: self.set_lut(fast=True) self.delay_ms(2) # According to the spec, x and w have to be multiples of 8. # round them up and down accordingly to make sure they fit the requirement # adding a few more pixels to the refreshed area. # This is mandatory, otherwise the display might get corrupted until # the next valid update that touches the same area. x = _nearest_mult_of_8(x, False) w = _nearest_mult_of_8(w) self.send_command(PARTIAL_DATA_START_TRANSMISSION_1) self.delay_ms(2) self._send_partial_frame_dimensions(x, y, h, w) self.delay_ms(2) # Send the old values, as per spec old_image = self._last_frame.crop((x, y, x+w, y+h)) old_fb = self._get_frame_buffer_for_size(old_image, h, w) for i in range(0, w * h // 8): self.send_data(old_fb[i]) self.delay_ms(2) self.send_command(PARTIAL_DATA_START_TRANSMISSION_2) self.delay_ms(2) self._send_partial_frame_dimensions(x, y, h, w) # Send new data self._last_frame = image.copy() image = image.crop((x, y, x+w, y+h)) new_fb = self._get_frame_buffer_for_size(image, h, w) for i in range(0, w * h // 8): self.send_data(new_fb[i]) self.delay_ms(2) self.send_command(PARTIAL_DISPLAY_REFRESH) self.delay_ms(2) self._send_partial_frame_dimensions(x, y, h, w) self.wait_until_idle() if fast: self.set_lut() # restore LUT to normal mode self._partial_refresh_count += 1 def smart_update(self, image): """ Display a frame, automatically deciding which refresh method to use. If `fast_frefresh` is enabled, it would use optimized LUTs that shorten the refresh cycle, and don't do the full "inverse,black,white,black again, then draw" flush cycle. The fast refresh mode is much faster, but causes the image to apper gray instead of black, and can cause burn-in if it's overused. It's recommended to do a full flush "soon" after using the fast mode, to avoid degrading the panel. You can tweak `partial_refresh_limit` or """ if self._last_frame is None or self._partial_refresh_count == self.partial_refresh_limit: # Doing a full refresh when: # - No frame has been displayed in this run, do a full refresh # - The display has been partially refreshed more than LIMIT times # the last full refresh (to prevent burn-in) self.display_frame(image) else: # Partial update. Let's start by figuring out the bounding box # of the changed area difference = ImageChops.difference(self._last_frame, image) bbox = difference.getbbox() if bbox is not None: # the old picture and new picture are different, partial # update is needed. # Get the update area. x and w have to be multiples of 8 # as per the spec, so round down for x, and round up for w x = _nearest_mult_of_8(bbox[0], False) y = bbox[1] w = _nearest_mult_of_8(bbox[2] - x) if w > self.width: w = self.width h = bbox[3] - y if h > self.height: h = self.height # now let's figure out if fast mode is an option. # If the area was all white before - fast mode will be used. # otherwise, a slow refresh will be used (to avoid ghosting). # Since the image only has one color, meaning each pixel is either # 0 or 255, the following convinent one liner can be used fast = 0 not in self._last_frame.crop(bbox).getdata() and self.fast_refresh self.display_partial_frame(image, x, y, h, w, fast) def sleep(self): """Put the chip into a deep-sleep mode to save power. The deep sleep mode would return to standby by hardware reset. Use EPD.reset() to awaken and use EPD.init() to initialize. """ self.send_command(DEEP_SLEEP) self.delay_ms(2) self.send_data(0xa5) # deep sleep requires 0xa5 as a "check code" parameter
class LED_LPD8806(object): # Constructor def __init__(self): self.spi = SPI( 0, 0 ) #/dev/spidev1.0 (be sure to run Python with su if 'no permission' self.spi.msh = 1000000 #SPI clock set to 1MHz (slowed from 10MHz for better stability across setups) self.spi.bpw = 8 # bits per word self.spi.threewire = False # not half-duplex self.spi.lsbfirst = False # we want MSB first self.spi.mode = 0 # options are modes 0 through 3 self.spi.cshigh = False # we want chip select to be active low self.spi.open(0, 0) # make it so time.sleep(0.05) def setup(self, led_pixels, debug=False): if (debug): print "Initializing LED strip" global pixels pixels = [[0x80 for x in range(3)] for y in range(led_pixels)] for i in range(led_pixels): pixels[i] = [0x00, 0x00, 0x00] # Define LED functions: # -------------------- # Update pixel display with a given delay time between pixel updates: def writestrip(self, delay): if (delay < 0): delay = 0 for i in range(len(pixels)): self.spi.writebytes([0x00, 0x00, 0x00]) #prepare write for i in range(len(pixels)): self.spi.writebytes(pixels[i]) #write colors to pixels time.sleep(delay) # Turn off all LEDs: def clearstrip(self): global pixels for i in range(len(pixels)): self.spi.writebytes([0x00, 0x00, 0x00]) #prepare write for i in range(len(pixels)): pixels[i] = [0x80, 0x80, 0x80] self.writestrip(0) # Set an individual pixel to a specific color (to display later): def setpixelcolor(self, n, g, r, b): global pixels if (n >= len(pixels)): return if (n < 0): return if (g > 0xFF): g = 0xFF if (g < 0x80): g = 0x80 if (r > 0xFF): r = 0xFF if (r < 0x80): r = 0x80 if (b > 0xFF): b = 0xFF if (b < 0x80): b = 0x80 pixels[n] = [g, r, b] # Update display with warmer colors (more red light) by a specified amount with a delay between pixels def warmstrip(self, warmth, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if ((pixels[n][1] + warmth) < 0x80): pixels[n][1] = 0x80 elif ((pixels[n][2] + warmth) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1] + warmth self.writestrip(delay) # Update display with cooler colors (more blue) by a specified amount with a delay between each pixel def coolstrip(self, coolfactor, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if ((pixels[n][2] + coolfactor) < 0x80): pixels[n][2] = 0x80 elif ((pixels[n][2] + coolfactor) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2] + coolfactor self.writestrip(delay) # Update display with greener colors by a specified amount with a set delay between each pixel def greenstrip(self, lushness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if ((pixels[n][0] + lushness) < 0x80): pixels[n][0] = 0x80 else: pixels[n][0] = pixels[n][0] + lushness self.writestrip(delay) # Update display with brighter (whiter) light by specified amount with a set delay between pixel updates def brightenstrip(self, brightness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if ((pixels[n][0] + brightness) < 0x80): pixels[n][0] = 0x80 elif ((pixels[n][0] + brightness) > 0xFF): pixels[n][0] = 0xFF else: pixels[n][0] = pixels[n][0] + brightness if ((pixels[n][1] + brightness) < 0x80): pixels[n][1] = 0x80 elif ((pixels[n][1] + brightness) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1] + brightness if ((pixels[n][2] + brightness) < 0x80): pixels[n][2] = 0x80 elif ((pixels[n][2] + brightness) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2] + brightness self.writestrip(delay) # Darken display (less light) by specified amount with a set delay between pixel updates def dimstrip(self, dimness, delay): global pixels if (delay < 0): delay = 0 for n in range(len(pixels)): if ((pixels[n][0] - dimness) < 0x80): pixels[n][0] = 0x80 elif ((pixels[n][0] - dimness) > 0xFF): pixels[n][0] = 0xFF else: pixels[n][0] = pixels[n][0] - dimness if ((pixels[n][1] - dimness) < 0x80): pixels[n][1] = 0x80 elif ((pixels[n][1] - dimness) > 0xFF): pixels[n][1] = 0xFF else: pixels[n][1] = pixels[n][1] - dimness if ((pixels[n][2] - dimness) < 0x80): pixels[n][2] = 0x80 elif ((pixels[n][2] - dimness) > 0xFF): pixels[n][2] = 0xFF else: pixels[n][2] = pixels[n][2] - dimness self.writestrip(delay)
class Enrf24(): __bus = None __device = None __rf_status = 0 __rf_addr_width = 5 __lastirq = None __readpending = 0 __lastTXfailed = False __txbuf_len = 0 __txbuf = [] # Internal IRQ handling __ENRF24_IRQ_TX = 0x20 __ENRF24_IRQ_RX = 0x40 __ENRF24_IRQ_TXFAILED = 0x10 __ENRF24_IRQ_MASK = 0x70 __ENRF24_CFGMASK_IRQ = 0 def __init__(self, bus, device, cePin, csnPin, irqPin): self.__bus = bus self.__device = device self.cePin = cePin self.csnPin = csnPin self.irqPin = irqPin self.spi = SPI(self.__bus, self.__device) self.spi.msh = 10000 self.spi.bpw = 8 # bits/word self.spi.threewire = False self.spi.lsbfirst = False self.spi.mode = 0 self.spi.cshigh = False self.spi.open(0, 0) self.last_payload = "" def begin(self, datarate=1000000, channel=0): # Specify bitrate & channel GPIO.setup(self.cePin, GPIO.OUT) GPIO.output(self.cePin, GPIO.LOW) GPIO.setup(self.csnPin, GPIO.OUT) GPIO.output(self.csnPin, GPIO.HIGH) GPIO.setup(self.irqPin, GPIO.IN) # No pullups; the transceiver provides this! self.spi.writebytes([0x00 ]) # Strawman transfer, fixes USCI issue on G2553 #self.spi.writebytes([0xCF, 0x00]) # Is the transceiver present/alive? if (not self.__isAlive()): return False # Nothing more to do here... # Wait 100ms for module to initialize time.sleep(0.1) # Init certain registers self.__writeReg(RF24_CONFIG, 0x00) # Deep power-down, everything disabled self.__writeReg(RF24_EN_AA, 0x03) self.__writeReg(RF24_EN_RXADDR, 0x03) self.__writeReg(RF24_RF_SETUP, 0x00) self.__writeReg(RF24_STATUS, self.__ENRF24_IRQ_MASK) # Clear all IRQs self.__writeReg(RF24_DYNPD, 0x03) self.__writeReg(RF24_FEATURE, RF24_EN_DPL) # Dynamic payloads enabled by default # Set all parameters if (channel > 125): channel = 125 self.deepsleep() self.__issueCmd(RF24_FLUSH_TX) self.__issueCmd(RF24_FLUSH_RX) self.__readpending = 0 self.__irq_clear(self.__ENRF24_IRQ_MASK) self.setChannel(channel) self.setSpeed(datarate) self.setTXpower() self.setAutoAckParams() self.setAddressLength(self.__rf_addr_width) self.setCRC(True) # Default = CRC on, 8-bit return True def end(self): # Shut it off, clear the library's state self.__txbuf_len = 0 self.__rf_status = 0 self.__rf_addr_width = 5 if (not self.__isAlive()): return self.deepsleep() self.__issueCmd(RF24_FLUSH_TX) self.__issueCmd(RF24_FLUSH_RX) self.readpending = 0 self.__irq_clear(self.__ENRF24_IRQ_MASK) GPIO.output(self.cePin, GPIO.LOW) GPIO.output(self.csnPin, GPIO.HIGH) # I/O def available( self, checkIrq=False): # Check if incoming data is ready to be read #print(checkIrq and GPIO.input(self.irqPin) and self.__readpending == 0) if (checkIrq and GPIO.input(self.irqPin) and self.__readpending == 0): return False self.__maintenanceHook() if ((not self.__readReg(RF24_FIFO_STATUS)) & RF24_RX_EMPTY): return True if (self.__readpending): return True return False def read(self, maxlen=32): # Read contents of RX buffer up to buf = None plwidth = 0 res = "" self.__maintenanceHook() self.__readpending = 0 if ((self.__readReg(RF24_FIFO_STATUS) & RF24_RX_EMPTY) or maxlen < 1): return 0 plwidth = self.__readCmdPayload(RF24_R_RX_PL_WID, plwidth, 1, 1)[0] buf = self.__readCmdPayload(RF24_R_RX_PAYLOAD, buf, plwidth, maxlen) if (self.__irq_derivereason() and self.__ENRF24_IRQ_RX): self.__irq_clear(self.__ENRF24_IRQ_RX) for i in buf: res += chr(i) self.last_payload = res return res # 'maxlen' bytes, return final length. # 'inbuf' should be maxlen+1 since a # null '\0' is tacked onto the end. def getMessage(self): return self.last_payload def write(self, data): if (self.__txbuf_len == 32 ): # If we're trying to stuff an already-full buffer... self.flush() # Blocking OTA TX txbuf = [] data = list(data) for i in data: txbuf.append(ord(i)) self.__txbuf = txbuf self.__txbuf_len = len(txbuf) return 1 def flush(self): # Force transmission of TX ring buffer contents reg = None addrbuf = [] enaa = False origrx = False if (self.__txbuf_len == 0): return # Zero-length buffer? Nothing to send! reg = self.__readReg(RF24_FIFO_STATUS) if ( reg & BITS["BIT5"] ): # RF24_TX_FULL #define is BIT0, which is not the correct bit for FIFO_STATUS. # Seen this before with a user whose CE pin was messed up. self.__issueCmd(RF24_FLUSH_TX) self.__txbuf_len = 0 return # Should never happen, but nonetheless a precaution to take. self.__maintenanceHook() if (reg & RF24_TX_REUSE): # If somehow TX_REUSE is enabled, we need to flush the TX queue before loading our new payload. self.__issueCmd(RF24_FLUSH_TX) if (self.__readReg(RF24_EN_AA) & 0x01 and (self.__readReg(RF24_RF_SETUP) & 0x28) != 0x20): # AutoACK enabled, must write TX addr to RX pipe#0 # Note that 250Kbps doesn't support auto-ack, so we check RF24_RF_SETUP to verify that. enaa = True self.__readTXaddr(addrbuf) self.__writeRXaddrP0(addrbuf) reg = self.__readReg(RF24_CONFIG) if (not (reg & RF24_PWR_UP)): #digitalWrite(_cePin, HIGH); // Workaround for SI24R1 knockoff chips self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP) time.sleep(.05) # 5ms delay required for nRF24 oscillator start-up #digitalWrite(_cePin, LOW); if (reg & RF24_PRIM_RX): origrx = True GPIO.output(self.cePin, GPIO.LOW) self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP) self.__txbuf = self.__issueCmdPayload(RF24_W_TX_PAYLOAD, self.__txbuf) GPIO.output(self.cePin, GPIO.HIGH) time.sleep(0.1) GPIO.output(self.cePin, GPIO.LOW) self.__txbuf_len = 0 # Reset TX ring buffer while (GPIO.input(self.irqPin)): # Wait until IRQ fires pass # IRQ fired self.__maintenanceHook() # Handle/clear IRQ # Purge Pipe#0 address (set to module's power-up default) if (enaa): addrbuf = [0xE7, 0xE7, 0xE7, 0xE7, 0xE7] self.__writeRXaddrP0(addrbuf) # If we were in RX mode before writing, return back to RX mode. if (origrx): self.enableRX() def purge( self): # Ignore TX ring buffer contents, return ring pointer to 0. self.__txbuf_len = 0 # Power-state related stuff- def radioState( self ): # Evaluate current state of the transceiver (see ENRF24_STATE_* defines) if not self.__isAlive(): return ENRF24_STATE_NOTPRESENT counter = 15 reg = self.__readReg(RF24_CONFIG) if reg == 0: while reg == 0 and counter < 15: reg = self.__readReg(RF24_CONFIG) counter += 1 if (not (reg & RF24_PWR_UP)): return ENRF24_STATE_DEEPSLEEP # At this point it's either Standby-I, II or PRX. if (reg & RF24_PRIM_RX): if (GPIO.input(self.cePin)): return ENRF24_STATE_PRX # PRIM_RX=1 but CE=0 is a form of idle state. return ENRF24_STATE_IDLE # Check if TX queue is empty, if so it's idle, if not it's PTX. if (self.__readReg(RF24_FIFO_STATUS) & RF24_TX_EMPTY): return ENRF24_STATE_IDLE return ENRF24_STATE_PTX def printRadioState(self): status = self.radioState() sys.stdout.write("Enrf24 radio transceiver status: ") if status == ENRF24_STATE_NOTPRESENT: print("NO TRANSCEIVER PRESENT") elif status == ENRF24_STATE_DEEPSLEEP: print("DEEP SLEEP <1uA power consumption") elif status == ENRF24_STATE_IDLE: print("IDLE module powered up w/ oscillators running") elif status == ENRF24_STATE_PTX: print("Actively Transmitting") elif status == ENRF24_STATE_PRX: print("Receive Mode") else: print("UNKNOWN STATUS CODE") def printStatus(self): status = self.__readReg(RF24_STATUS) data_ready = str(hex(status & 0x40)) data_sent = str(hex(status & 0x20)) max_tx_retries = str(hex(status & 0x10)) if status & 0x0E == 0x0E: rx_pipe_no = "RX FIFO Empty" elif status & 0x02 == 0x02: rx_pipe_no = 1 elif status & 0x04 == 0x04: rx_pipe_no = 2 elif status & 0x06 == 0x06: rx_pipe_no = 3 elif status & 0x08 == 0x08: rx_pipe_no = 4 elif status & 0x0A == 0x0A: rx_pipe_no = 5 elif ~status & 0x0E: rx_pipe_no = 0 else: rx_pipe_no = "Error" rx_pipe_no = str(rx_pipe_no) tx_fifo_full = str(status & 0x01) status = str(hex(status)) sys.stdout.write("STATUS=") sys.stdout.write(status) sys.stdout.write("\tRX_DR=") sys.stdout.write(data_ready) sys.stdout.write(" TX_DS=") sys.stdout.write(data_sent) sys.stdout.write(" MAX_RT=") sys.stdout.write(max_tx_retries) sys.stdout.write(" RX_P_NO=") sys.stdout.write(rx_pipe_no) sys.stdout.write(" TX_FULL=") print(tx_fifo_full) print("") def printDetails(self): self.printStatus() buf = [] sys.stdout.write("RX_ADDR_P0=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P0, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P1=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P1, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P2=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P2, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P3=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P3, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P4=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P4, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") sys.stdout.write("RX_ADDR_P5=") buf = self.__readRegMultiLSB(RF24_RX_ADDR_P5, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") print("") sys.stdout.write("TX_ADDR=") buf = self.__readRegMultiLSB(RF24_TX_ADDR, buf, self.__rf_addr_width) for i in buf: sys.stdout.write(hex(i) + " ") print("") print("") sys.stdout.write("RX_PW_P0=") print(hex(self.__readReg(RF24_RX_PW_P0))) sys.stdout.write("RX_PW_P1=") print(hex(self.__readReg(RF24_RX_PW_P1))) sys.stdout.write("RX_PW_P2=") print(hex(self.__readReg(RF24_RX_PW_P2))) sys.stdout.write("RX_PW_P3=") print(hex(self.__readReg(RF24_RX_PW_P3))) sys.stdout.write("RX_PW_P4=") print(hex(self.__readReg(RF24_RX_PW_P4))) sys.stdout.write("RX_PW_P5=") print(hex(self.__readReg(RF24_RX_PW_P5))) print("") sys.stdout.write("EN_AA=") print(bin(self.__readReg(RF24_EN_AA))) sys.stdout.write("EN_RXADDR=") print(bin(self.__readReg(RF24_EN_RXADDR))) sys.stdout.write("RF_CH=") print(hex(self.__readReg(RF24_RF_CH))) sys.stdout.write("RF_SETUP=") print(bin(self.__readReg(RF24_RF_SETUP))) sys.stdout.write("CONFIG=") print(bin(self.__readReg(RF24_CONFIG))) sys.stdout.write("DYNPD=") print(bin(self.__readReg(RF24_DYNPD))) sys.stdout.write("FEATURE=") print(bin(self.__readReg(RF24_FEATURE))) print("") sys.stdout.write("Data Rate=") print(self.getSpeed()) sys.stdout.write("CRC Length=") print(self.getCRC()) sys.stdout.write("PA Power=") print(self.getTXpower()) def deepsleep(self): # Enter POWERDOWN mode, ~0.9uA power consumption reg = self.__readReg(RF24_CONFIG) if (reg & (RF24_PWR_UP | RF24_PRIM_RX)): self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg)) GPIO.output(self.cePin, GPIO.LOW) def enableRX(self): # Enter PRX mode (~14mA) reg = self.__readReg(RF24_CONFIG) self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP | RF24_PRIM_RX) self.__writeReg(RF24_RX_PW_P0, 0x20) self.__writeReg(RF24_RX_PW_P1, 0x20) GPIO.output(self.cePin, GPIO.HIGH) if ( not (reg & RF24_PWR_UP) ): # Powering up from deep-sleep requires 5ms oscillator start delay time.sleep(0.05) def disableRX(self): # Disable PRX mode (PRIM_RX bit in CONFIG register) # Note this won't necessarily push the transceiver into deep sleep, but rather # an idle standby mode where its internal oscillators are ready & running but # the RF transceiver PLL is disabled. ~26uA power consumption. GPIO.output(self.cePin, GPIO.LOW) reg = self.__readReg(RF24_CONFIG) if ( reg & RF24_PWR_UP ): # Keep us in standby-I if we're coming from RX mode, otherwise stay # in deep-sleep if we call this while already in PWR_UP=0 mode. self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP) else: self.__writeReg( RF24_CONFIG, self.__ENRF24_CFGMASK_IRQ | self.__ENRF24_CFGMASK_CRC(reg)) # Custom tweaks to RF parameters, packet parameters def autoAck(self, onoff=True ): # Enable/disable auto-acknowledgements (enabled by default) reg = self.__readReg(RF24_EN_AA) if (onoff): if (not (reg & 0x01) or not (reg & 0x02)): self.__writeReg(RF24_EN_AA, 0x03) else: if (reg & 0x03): self.__writeReg(RF24_EN_AA, 0x00) def setChannel(self, channel): if (channel > 125): channel = 125 self.__writeReg(RF24_RF_CH, channel) def setTXpower( self, dBm=0 ): # Only a few values supported by this (0, -6, -12, -18 dBm) reg = self.__readReg( RF24_RF_SETUP) & 0xF8 # preserve RF speed settings pwr = 0x06 if (dBm >= 7): pwr = 0x07 if (dBm < 0): pwr = 0x04 if (dBm < -6): pwr = 0x02 if (dBm < -12): pwr = 0x00 self.__writeReg(RF24_RF_SETUP, reg | pwr) def setSpeed(self, rfspeed): # Set 250000, 1000000, 2000000 speeds. reg = self.__readReg( RF24_RF_SETUP) & 0xD7 # preserve RF power settings spd = 0x01 if (rfspeed < 2000000): spd = 0x00 if (rfspeed < 1000000): spd = 0x04 self.__writeReg(RF24_RF_SETUP, reg | (spd << 3)) def setCRC(self, onoff, crc16bit=False): # Enable/disable CRC usage inside nRF24's # hardware packet engine, specify 8 or # 16-bit CRC. crcbits = 0 reg = self.__readReg( RF24_CONFIG) & 0xF3 # preserve IRQ mask, PWR_UP/PRIM_RX settings if (onoff): crcbits |= RF24_EN_CRC if (crc16bit): crcbits |= RF24_CRCO self.__writeReg(RF24_CONFIG, (reg | crcbits)) # Set AutoACK retry count, timeout params (0-15, 250-4000 respectively) def setAutoAckParams(self, autoretry_count=15, autoretry_timeout=2000): setup_retr = 0 setup_retr = autoretry_count & 0x0F autoretry_timeout -= 250 setup_retr |= ((autoretry_timeout / 250) & 0x0F) << 4 self.__writeReg(RF24_SETUP_RETR, setup_retr) # Protocol addressing -- receive, transmit addresses def setAddressLength(self, len): # Valid parameters = 3, 4 or 5. Defaults to 5. if (len < 3): len = 3 if (len > 5): len = 5 self.__writeReg(RF24_SETUP_AW, len - 2) self.__rf_addr_width = len def setRXaddress(self, rxaddr): # 3-5 byte RX address loaded into pipe#1 self.__writeRegMultiLSB(RF24_RX_ADDR_P1, rxaddr) def setTXaddress( self, txaddr): # 3-5 byte TX address loaded into TXaddr register self.__writeRegMultiLSB(RF24_TX_ADDR, txaddr) # Miscellaneous feature def rfSignalDetected( self ): # Read RPD register to determine if transceiver has presently detected an RF signal # of -64dBm or greater. Only works in PRX (enableRX()) mode. rpd = self.__readReg(RF24_RPD) return rpd # Query current parameters def getChannel(self): return self.__readReg(RF24_RF_CH) def getSpeed(self): reg = self.__readReg(RF24_RF_SETUP) & 0x28 if (reg == 0x00): return 1000000 elif (reg == 0x08): return 2000000 elif (reg == 0x20): return 250000 else: return 0 def getTXpower(self): reg = self.__readReg(RF24_RF_SETUP) & 0x07 if (reg & 0x01): return 7 # SI24R1-only +7dBm mode elif (reg == 0x02): return -12 elif (reg == 0x04): return -6 elif (reg == 0x06): return 0 else: return -18 def getAddressLength(self): return self.__rf_addr_width def getRXaddress(self): buf = [] buf = self.__readRegMultiLSB(RF24_RX_ADDR_P1, buf, self.__rf_addr_width) return buf def getTXaddress(self): buf = [] buf = self.__readRegMultiLSB(RF24_TX_ADDR, buf, rf_addr_width) return buf def getAutoAck(self): reg = self.__readReg(RF24_EN_AA) if (reg): return True else: return False def getCRC(self): reg = self.__readReg(RF24_CONFIG) & 0x0C if (reg == 0x08): return 8 elif (reg == 0x0C): return 16 else: return 0 def __readReg(self, addr): GPIO.output(self.csnPin, GPIO.LOW) result = self.spi.xfer2([(RF24_R_REGISTER | addr), RF24_NOP]) self.__rf_status = result[0] GPIO.output(self.csnPin, GPIO.HIGH) return result[1] def __readRegMultiLSB(self, addr, buf, length): txbuf = [(RF24_R_REGISTER | addr)] for i in range(length): txbuf.append(RF24_NOP) GPIO.output(self.csnPin, GPIO.LOW) buf = self.spi.xfer2(txbuf) self.__rf_status = buf[0] status = [] for i in range(1, len(buf) + 1): status.append(buf[-i]) status.pop() GPIO.output(self.csnPin, GPIO.HIGH) return status def __writeReg(self, addr, val): GPIO.output(self.csnPin, GPIO.LOW) res = self.spi.xfer2([(RF24_W_REGISTER | addr), val]) GPIO.output(self.csnPin, GPIO.HIGH) def __writeRegMultiLSB(self, addr, buf): txbuf = [(RF24_W_REGISTER | addr)] for i in range(1, len(buf) + 1): txbuf.append(buf[-i]) GPIO.output(self.csnPin, GPIO.LOW) status = self.spi.xfer2(txbuf) GPIO.output(self.csnPin, GPIO.HIGH) def __issueCmd(self, cmd): GPIO.output(self.csnPin, GPIO.LOW) self.spi.writebytes([cmd]) GPIO.output(self.csnPin, GPIO.HIGH) def __readCmdPayload(self, cmd, buf, length, maxlen): GPIO.output(self.csnPin, GPIO.LOW) messg = [] txbuf = [cmd] for i in range(maxlen): txbuf.append(RF24_NOP) buf = self.spi.xfer2( txbuf) # Beyond maxlen bytes, just discard the remaining data. self.__rf_status = buf[0] for i in range(1, length + 1): messg.append(buf[i]) GPIO.output(self.csnPin, GPIO.HIGH) return messg def __issueCmdPayload(self, cmd, buf): payload = [] payload.append(cmd) for i in buf: payload.append(i) GPIO.output(self.csnPin, GPIO.LOW) res = self.spi.xfer2(payload) GPIO.output(self.csnPin, GPIO.HIGH) def __irq_getreason(self): self.__lastirq = self.__readReg(RF24_STATUS) & self.__ENRF24_IRQ_MASK def __irq_derivereason( self ): # Get IRQ status from rf_status w/o querying module over SPI. self.__lastirq = self.__rf_status & self.__ENRF24_IRQ_MASK def __irq_clear(self, irq): self.__writeReg(RF24_STATUS, (irq & self.__ENRF24_IRQ_MASK)) def __isAlive(self): self.spi.writebytes([0x00]) aw = self.__readReg(RF24_SETUP_AW) return ((aw & 0xFC) == 0x00 and (aw & 0x03) != 0x00) def __readTXaddr(self, buf): self.__readRegMultiLSB(RF24_TX_ADDR, buf, self.__rf_addr_width) def __writeRXaddrP0(self, buf): self.__writeRegMultiLSB(RF24_RX_ADDR_P0, buf) def __maintenanceHook( self ): # Handles IRQs and purges RX queue when erroneous contents exist. i = 0 self.__irq_getreason() if (self.__lastirq & self.__ENRF24_IRQ_TXFAILED): self.__lastTXfailed = True self.__issueCmd(RF24_FLUSH_TX) self.__irq_clear(self.__ENRF24_IRQ_TXFAILED) if (self.__lastirq & self.__ENRF24_IRQ_TX): self.__lastTXfailed = False self.__irq_clear(self.__ENRF24_IRQ_TX) if (self.__lastirq & self.__ENRF24_IRQ_RX): if ((not self.__readReg(RF24_FIFO_STATUS)) & RF24_RX_FULL): # Don't feel it's necessary # to be notified of new # incoming packets if the RX # queue is full. self.__irq_clear(self.__ENRF24_IRQ_RX) # Check if RX payload is 0-byte or >32byte (erroneous conditions) # Also check if data was received on pipe#0, which we are ignoring. # The reason for this is pipe#0 is needed for receiving AutoACK acknowledgements, # its address gets reset to the module's default and we do not care about data # coming in to that address... i = self.__readCmdPayload(RF24_R_RX_PL_WID, i, 1, 1)[0] if (i == 0 or i > 32 or ((self.__rf_status & 0x0E) >> 1) == 0): # Zero-width RX payload is an error that happens a lot # with non-AutoAck, and must be cleared with FLUSH_RX. # Erroneous >32byte packets are a similar phenomenon. self.__issueCmd(RF24_FLUSH_RX) self.__irq_clear(self.__ENRF24_IRQ_RX) self.__readpending = 0 else: self.__readpending = 1 # Actual scavenging of RX queues is performed by user-directed use of read(). def __ENRF24_CFGMASK_CRC(self, a): return (a & (RF24_EN_CRC | RF24_CRCO))
class DAC: def __init__(self): # create outer classes with ability to change inner parameters # using two's complement # CONSTS self.DAC_SEND = "0001" # value to be sending information to dac self.MAX_NEG = -pow(2, 19) # max neg value that can be achieved self.MAX_POS = int( 0b01111111111111111111) # max pos value that can be achieved self.MAX_CLOCK = 340000 # maximal clock value we can get in Hz self.MIN_CLOCK = 50000 # minimal clock value we can get in Hz self.IP = '192.168.0.20' self.PORT = 5555 self.act_val = 0 # actual value self.clock = self.MIN_CLOCK # begin with min value self.spi = SPI(1, 0) # spi for our communication self.spi.mode = 0b00 self.spi.msh = self.clock # Triggers for the DAC self.reset = False self.ldac = False GPIO.setup("P8_17", GPIO.OUT) # LDAC GPIO.setup("P8_18", GPIO.OUT) # RESET GPIO.output("P8_18", self.reset) GPIO.output("P8_17", self.ldac) # Address for which DAC self.dac_address = list() self.dac_address = [0, 0, 0, 0, 0] # default GPIO.setup("P9_15", GPIO.OUT) # P0 GPIO.setup("P9_11", GPIO.OUT) # P1 GPIO.setup("P9_12", GPIO.OUT) # P2 GPIO.setup("P9_13", GPIO.OUT) # P3 GPIO.setup("P9_14", GPIO.OUT) # P4 GPIO.output("P9_15", GPIO.LOW) # P0 GPIO.output("P9_11", GPIO.LOW) # P1 GPIO.output("P9_12", GPIO.LOW) # P2 GPIO.output("P9_13", GPIO.LOW) # P3 GPIO.output("P9_14", GPIO.LOW) # P4 self.initializeDAC() # server def reset_dac(self): GPIO.output("P8_18", 1) print('Reseting DAC') self.spi.close() self.spi = SPI(1, 0) GPIO.output("P8_18", 0) # returns it back to 0 def __del__(self): self.reset_dac() # reset voltage self.spi.close() # spi close def initializeDAC( self ): # we can always change the initialize and make it more flexible GPIO.output("P8_17", GPIO.HIGH) self.spi.writebytes([0b00100000, 0b00000000, 0b00100010]) GPIO.output("P8_17", GPIO.LOW) def registerValue(self): self.initializeDAC() if self.act_val != 0: temp = self.convertComplement_DAC(self.act_val, 20) string1 = self.DAC_SEND + temp[0:4] string2 = temp[4:12] string3 = temp[12:] GPIO.output("P8_17", GPIO.HIGH) self.spi.writebytes( [int(string1, 2), int(string2, 2), int(string3, 2)]) print('Sending to the DAC: ', string1 + string2 + string3) GPIO.output("P8_17", GPIO.LOW) else: self.reset_dac() return @staticmethod def convertComplement_DAC(value, width=20): # Return the binary representation of the input number as a string. # If width is not given it is assumed to be 20. If width is given, the two's complement of the number is # returned, with respect to that width. # In a two's-complement system negative numbers are represented by the two's # complement of the absolute value. This is the most common method of # representing signed integers on computers. A N-bit two's-complement # system can represent every integer in the range [-2^(N-1),2^(N-1)-1] def warning(widt, width_bin): # the function checks if the width is a good value for input number, if not (f.e smaller) returning # default 20 if widt != 20 and (widt <= 0 or width < width_bin): print("Bad width, returning default\n") return width_bin elif widt == 20 and widt < width_bin: return width_bin else: return widt if value > 0: binar = bin( int(value))[2:] # take binary representation of input value real_width = warning(width, len(binar)) # check width if real_width > len( binar): # add zeros if width is bigger that binary length for x1 in range(0, real_width - len(binar)): binar = "0" + binar return binar elif value == 0: # all zeros binar = "" for x2 in range(0, width): binar = "0" + binar elif value < 0: binar = bin( abs(int(value)) )[2:] # because of the minus sign at the beginning we take absolute value real_width = warning(width, len(binar)) if abs(value) == pow(2, real_width - 1): return binar if real_width > len( binar ): # with bigger length we have to add zeros at the beginning for x3 in range(0, real_width - len(binar)): binar = "0" + binar strin = "" # empty temporary string for x in range(0, real_width): if int(binar[x]) == 1: temp = 0 # negating for the 2's complement else: temp = 1 strin = strin + str(temp) temp_add = int(strin, 2) temp_add = temp_add + 1 binar = bin(temp_add)[2:] return binar
class 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)
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 DACRef: def __init__(self, maxClock=3300000): # using two's complement self.dacSend = "0001" self.max_raw_minus = -pow(2, 19) # maximal value that can be achieved self.max_raw_plus = int(0b01111111111111111111) self.actVal = 0 # actual value # SPI self.spi = SPI(1, 0) # choose SPI device self.spi.mode = 0b00 if maxClock > 1000: self.spi.msh = maxClock else: self.spi.msh = 3300000 print("Minumum clock speed is 10000, setting default 33Mhz") # Start values self.reset = 0 self.ldac = 0 # in the beggining the device is not ready(remember they are inverted) # P8 GPIO.setup("P8_17", GPIO.OUT) # LDAC GPIO.output("P8_17", self.ldac) GPIO.setup("P8_18", GPIO.OUT) # RESET GPIO.output("P8_18", self.reset) # GPIO.setup("P8_15", GPIO.OUT) #ext rsten # GPIO.setup("P8_14", GPIO.OUT) # PLL LOCK # GPIO.setup("P8_16", GPIO.OUT) # ext Ioupden # NOT USED # P9 (addresses) self.dacAddress = [0, 0, 0, 0, 0] # default GPIO.setup("P9_11", GPIO.OUT) # P1 GPIO.setup("P9_12", GPIO.OUT) # P2 GPIO.setup("P9_13", GPIO.OUT) # P3 GPIO.setup("P9_14", GPIO.OUT) # P4 GPIO.setup("P9_15", GPIO.OUT) # P0 def setDACAddress(self, list): self.dacAddress = list GPIO.setup("P9_15", self.dacAddress[0]) # P0 GPIO.setup("P9_11", self.dacAddress[1]) # P1 GPIO.setup("P9_12", self.dacAddress[2]) # P2 GPIO.setup("P9_13", self.dacAddress[3]) # P3 GPIO.setup("P9_14", self.dacAddress[4]) # P4 def chooseDAC(self, dacNum=0, board=0): if board == 0: p2 = 0 p3 = 0 p4 = 0 elif board == 1: p2 = 0 p3 = 0 p4 = 1 elif board == 2: p2 = 0 p3 = 1 p4 = 0 elif board == 3: p2 = 0 p3 = 1 p4 = 1 else: print("WRONG NUMBER, SETTING 0") p2 = 0 p3 = 0 p4 = 0 GPIO.output("P9_12", p2) GPIO.output("P9_13", p3) GPIO.output("P9_14", p4) if dacNum == 0: p0 = 0 p1 = 0 elif dacNum == 1: p0 = 0 p1 = 1 elif dacNum == 2: p0 = 1 p1 = 0 elif dacNum == 3: p0 = 1 p1 = 1 GPIO.output("P9_15", p0) GPIO.output("P9_11", p1) self.dacAddress = [p0, p1, p2, p3, p4] def setLDAC(self, ldac): self.ldac = ldac GPIO.output("P8_17", self.ldac) def resetDAC(self): self.reset = 1 GPIO.output("P8_18", self.reset) GPIO.output("P8_18", 0) # returns it back to 0 def setValueRaw(self, raw): if self.max_raw_plus >= int(raw) >= self.max_raw_minus: self.actVal = int(raw) print("Actual value is: " + str(self.actVal)) else: self.actVal = 0 # if we go out of range we get 0 print("Out of range[-1,1] or 0.") # print("Actual value is: " + str(self.actVal)) self.registerValue() def setValueNorm(self, norm): if 0 < norm <= 1: self.actVal = int(self.max_raw_plus * norm) print("Actual value is: " + str(self.actVal)) elif 0 > norm >= -1: self.actVal = int(-self.max_raw_minus * norm) # print("Actual value is: " + str(self.actVal)) else: self.actVal = 0 print("Out of range[-1,1] or 0.") # print("Actual value is: " + str(self.actVal)) self.registerValue() def setValHelp(self, address): val = input("Write the value from [-524288,524287]: ") if val <= self.max_raw_plus and val >= self.max_raw_minus: self.setDACAddress(address) self.setValueNorm(int(val)) else: print("Wrong number, doing nothing") return def initializeDAC(self): # we can always change the initialize and make it more flexible GPIO.output("P8_17", GPIO.HIGH) self.spi.writebytes([0b00100000, 0b00000000, 0b00100010]) GPIO.output("P8_17", GPIO.LOW) def registerValue(self): self.initializeDAC() if self.actVal != 0: temp = convertComplement_DAC(self.actVal, 20) string1 = self.dacSend + temp[0:4] string2 = temp[4:12] string3 = temp[12:] GPIO.output("P8_17", GPIO.HIGH) self.spi.writebytes([int(string1, 2), int(string2, 2), int(string3, 2)]) GPIO.output("P8_17", GPIO.LOW) else: self.resetDAC() def __del__(self): self.resetDAC() self.spi.close()
controlReglAddress = 0x0D statusRegAddress = 0x0E trickleChargerRegAddress = 0x0F agingOffsetAddress = 0x10 temperatureMSBAddress = 0x11 temperatureLSBAddress = 0x12 seconds = 0x00 minutes = 0x00 hours = 0x00 dayOfWeek = 00000XXX dayOfMonth = 00NNXXXX monthCentury = 0x00 year = 0x00 control = 00011000 #Enable 1Hz or 00? status = 0x00 agingOffset = 0x00 temperatureMSB = 0x00 temperatureLSB = 0x00 SetHeatBeat = 0x00#For control register spi.writebytes([controlReglAddress, SetHeatBeat ])
class RFM69HCW(): def __init__(self, LED_STATE=default_LED_STATE, Fxosc=default_Fxosc, Fstep=default_Fstep, callsign=None, node_id=default_node_id, network_id=default_network_id, carrier_freq=default_carrier_freq, carrier_dev=default_carrier_dev, carrier_bitrate=default_bitrate): self._mode = OPMODE_SLEEP self.LED_STATE = LED_STATE self.Fxosc = Fxosc self.Fstep = Fstep self.callsign = callsign self.RFM_SPI = SPI(0, 0) self.RFM_SPI.msh = 5000000 self.carrier_freq = carrier_freq self.carrier_dev = carrier_dev self.bitrate = carrier_bitrate self.node_id = node_id self.network_id = network_id if self.callsign is None: raise NoCallSign("FCC Callsign not defined") self.ord_callsign = map(ord, list(self.callsign)) self._io_setup() GPIO.output(BLUE_LEDPIN, GPIO.LOW) self.reset_radio() return def _io_setup(self): GPIO.setup(BLUE_LEDPIN, GPIO.OUT) GPIO.setup(MODULE_EN, GPIO.OUT) GPIO.setup(MODULE_RST, GPIO.OUT) GPIO.setup(G0_PIN, GPIO.IN) GPIO.setup(G1_PIN, GPIO.OUT) GPIO.setup(G2_PIN, GPIO.OUT) # GPIO.add_event_detect(G0_PIN, GPIO.FALLING, callback=g0int) GPIO.add_event_detect(G0_PIN, GPIO.RISING, callback=g0int) def _check_register(self, addr, value): vals = self.RFM_SPI.xfer2([addr, 0x0]) if vals[1] != value: str = "addr: " + hex(addr) + "(" + inv_sx1231_reg[ addr] + ")" + " should be: " + hex(value) + " got: " + hex( vals[1]) raise CheckError(str) print "Reg{", hex(addr), "}(", inv_sx1231_reg[addr], ")\t\t=", hex( vals[1]) def write_register(self, reg, val, checkit=False): addr = reg reg = reg | 0x80 # print "reg is: ", bin(reg) # print "val is: " , bin(val) # RFM_SPI.writebytes([reg, val]) self.RFM_SPI.xfer2([reg, val]) if checkit == True: self._check_register(addr, val) return def read_register(self, reg): regval = self.RFM_SPI.xfer2([reg, 0x0]) return regval[1] def reset_radio(self): #self.blue_blink(2) GPIO.output(MODULE_EN, GPIO.HIGH) GPIO.output(MODULE_RST, GPIO.LOW) time.sleep(0.5) GPIO.output(MODULE_RST, GPIO.HIGH) time.sleep(0.5) GPIO.output(MODULE_RST, GPIO.LOW) time.sleep(0.5) def blue_invert(self): if (self.LED_STATE) == True: self.blue_off() else: self.blue_on() def blue_off(self): self.LED_STATE = False GPIO.output(BLUE_LEDPIN, GPIO.HIGH) return def blue_on(self): self.LED_STATE = True GPIO.output(BLUE_LEDPIN, GPIO.LOW) return def blue_blink(self, n=3): for num in range(0, n * 2): self.blue_invert() time.sleep(0.25) return def report_setup(self): print 'LED_STATE is:\t', self.LED_STATE print 'Fxosc is: \t', self.Fxosc print 'Fstep is: \t', self.Fstep print 'Callsign is: \t', self.callsign return # Facts: # Fxosc = 32Mhz # Fstep = 32e6/2^9 = 61.03515625 # Frf = int(carrier_hz/Fstep) def write_carrier_freq(self, carrier_hz=436500000): frf = int(carrier_hz / self.Fstep) # vals = RFM_SPI.xfer2([RegFrfMsb, 0x0, 0x0, 0x0]) # print "Pre: vals=\t", hex(vals[0]), "\t", hex(vals[1]), "\t", hex(vals[2]), "\t", hex(vals[3]) frfmsb = (frf >> 16) & 0xff frfmid = (frf >> 8) & 0xff frflsb = frf & 0xff wbuf = [(sx1231_reg["RegFrfMsb"] | 0x80), int(frfmsb), int(frfmid), int(frflsb)] self.RFM_SPI.writebytes(wbuf) vals = self.RFM_SPI.xfer2([sx1231_reg["RegFrfMsb"], 0x0, 0x0, 0x0]) # print "Post: vals=\t", hex(vals[0]), "\t", hex(vals[1]), "\t", hex(vals[2]), "\t", hex(vals[3]) return def set_freq_deviation(self, freq_dev_hz=20000): freqdev = int(freq_dev_hz / self.Fstep) wbuf = [(sx1231_reg["RegFdevMsb"] | 0x80), (int(freqdev >> 8) & 0x3f), int(freqdev & 0xff)] self.RFM_SPI.writebytes(wbuf) # print "fdev_msb:\t", # check_register(sx1231_reg["RegFdevMsb"], (int(freqdev>>8) & 0x3f)) # print "\nfdev_lsb:\t", # check_register(sx1231_reg["RegFdevLsb"], (int(freqdev & 0xff))) # print "\n" return def set_bitrate(self, bitrate_hz=1200): rate = int(self.Fxosc / bitrate_hz) wbuf = [(sx1231_reg["RegBitrateMsb"] | 0x80), (int(rate >> 8) & 0xff), int(rate & 0xff)] self.RFM_SPI.writebytes(wbuf) def set_sync_value(fourbytelist): wbuf = [(sx1231_reg["RegSyncValue1"] | 0x80)] + fourbytelist self.RFM_SPI.writebytes(wbuf) def set_preamble(twobytelist): wbuf = [(sx1231_reg["RegPreambleMsb"] | 0x80)] + twobytelist self.RFM_SPI.writebytes(wbuf) """ Experiment with automodes """ def config_packet(self, pa, node_id=0x33, network_id=0x77): # Begin with sequencer on, listen off, and in standby self.write_register(sx1231_reg["RegOpMode"], OPMODE_SEQUENCER_ON | OPMODE_LISTEN_OFF, True) self.set_mode(OPMODE_STANDBY) # Automodes - Finish Emptying fifo while in STBY self.write_register( sx1231_reg["RegAutoModes"], AUTOMODE_ENTER_CRC_OK | AUTOMODE_EXIT_FIFO_NOT_EMPTY | AUTOMODE_INTERM_STDBY, True) # Packet Mode, FSK, No Shaping self.write_register( sx1231_reg["RegDataModul"], DATAMODUL_Packet | DATAMODUL_FSK | DATAMODUL_NoShaping) self.write_carrier_freq(self.carrier_freq) self.set_freq_deviation(self.carrier_dev) self.set_bitrate(self.bitrate) # PA Output Power self.write_register(sx1231_reg["RegPaLevel"], PAOutputCfg( PA0, 0x1F)) # keep at PA0 until end of initialize # DIO Mappings g0_flag = False g1_flag = False g2_flag = False g3_flag = False g4_flag = False g5_flag = False # (DccFreq|RxBwMant|RxBwExp) Table 13 self.write_register(sx1231_reg["RegRxBw"], (010 << 5 | 0x10 << 3 | 100 << 0)) # 20.8kHz? # DIO_0 initialize to PAYLOAD ready in RX self.write_register( sx1231_reg["RegDioMapping1"], ((self.read_register(sx1231_reg["RegDioMapping1"]) & (~(0b11 << DIO_0_POS))) | DIO0_PAYLOADREADY << DIO_0_POS), True) # DIO_1 is RX TIMEOUT self.write_register( sx1231_reg["RegDioMapping1"], ((self.read_register(sx1231_reg["RegDioMapping1"]) & (~(0b11 << DIO_1_POS))) | DIO1_RX_TIMEOUT << DIO_1_POS), True) # DIO_4 is Clkout self.write_register(sx1231_reg["RegDioMapping2"], (DIO4_RXRDY << DIO_4_POS | DIO_CLK_DIV32), True) # Clear IRQFLAG and reset FIFO self.write_register(sx1231_reg["RegIrqFlags2"], IRQFLAGS2_FIFOOVERRUN) # RSSI Thresh self.write_register(sx1231_reg["RegRssiThresh"], 0xdc, True) # -220/2 = -110dBm? # Preamble length (0xaa..N) self.write_register(sx1231_reg["RegPreambleLsb"], 0xf, True) # Sync Config self.write_register( sx1231_reg["RegSyncConfig"], SYNCCFG_SYNC_ON | SYNCCFG_FILL_FIFO_INTR | SYNCCFG_SIZE_2, True) # Sync Word self.write_register(sx1231_reg["RegSyncValue1"], node_id, True) self.write_register(sx1231_reg["RegSyncValue2"], network_id, True) # Packet config 1 self.write_register( sx1231_reg["RegPacketConfig1"], PACKET1_FORMAT_FIXED | PACKET1_DCFREE_NONE | PACKET1_CRC_ON | PACKET1_CRCAUTOCLEAR_ON | PACKET1_ADDRESS_FILTERING_BOTH, True) # Payload Length self.write_register(sx1231_reg["RegPayloadLength"], default_Payload_bytes, True) # Node address: self.write_register(sx1231_reg["RegNodeAdrs"], self.node_id, True) self.write_register(sx1231_reg["RegBroadcastAdrs"], self.node_id + 1, True) # Fifothresh? Only for TX self.write_register(sx1231_reg["RegFifoThresh"], FIFOTHRESH_NOT_EMPTY | FIFOTHRESH_THRESHOLD_15, True) # Packet config 2 self.write_register(sx1231_reg["RegPacketConfig2"], PACKET2_AUTORX_RESTART_ON, True) # Magic numbers self.write_register( sx1231_reg["RegPaRamp"], 0b0011, True ) # 500uS close to 1/2400 bps ... see PacketConfig2 InterPacketRxDelay Must match the tx PA Ramp-down time # self.write_register(sx1231_reg["RegAfcCtrl"],0x40 | (0b1<<5) , True ) # AfcLowBetaOn - Manual misprint....bits 7-6 read as 0b01 not 0b00 self.write_register( sx1231_reg["RegAfcCtrl"], (0b1 << 5), True ) # AfcLowBetaOn - Manual misprint....bits 7-6 read as 0b01 not 0b00 self.write_register(sx1231_reg["RegTestDagc"], 0x20, True) # page 74 for AfcLowBetaOn=1 self.write_register(sx1231_reg["RegPaLevel"], pa) return def set_mode(self, mode): if (mode == self._mode): return if (mode == OPMODE_SLEEP): self.write_register( sx1231_reg["RegDioMapping1"], ((self.read_register(sx1231_reg["RegDioMapping1"]) & (~(0b11 << DIO_0_POS))) | DIO0_PAYLOADREADY << DIO_0_POS)) self.write_register( sx1231_reg["RegOpMode"], (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3) | OPMODE_SLEEP) self._mode = OPMODE_SLEEP elif (mode == OPMODE_STANDBY): self.write_register( sx1231_reg["RegDioMapping1"], ((self.read_register(sx1231_reg["RegDioMapping1"]) & (~(0b11 << DIO_0_POS))) | DIO0_PAYLOADREADY << DIO_0_POS)) self.write_register( sx1231_reg["RegOpMode"], (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3) | OPMODE_STANDBY) self._mode = OPMODE_STANDBY elif (mode == OPMODE_FS_SYNTH): self.write_register( sx1231_reg["RegOpMode"], (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3) | OPMODE_FS_SYNTH) self._mode = OPMODE_FS_SYNTH elif (mode == OPMODE_TX): self.write_register( sx1231_reg["RegDioMapping1"], ((self.read_register(sx1231_reg["RegDioMapping1"]) & (~(0b11 << DIO_0_POS))) | DIO0_PACKETSENT << DIO_0_POS)) self.write_register( sx1231_reg["RegOpMode"], (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3) | OPMODE_TX) self._mode = OPMODE_TX elif (mode == OPMODE_RX): self.write_register( sx1231_reg["RegDioMapping1"], ((self.read_register(sx1231_reg["RegDioMapping1"]) & (~(0b11 << DIO_0_POS))) | DIO0_PAYLOADREADY << DIO_0_POS)) self.write_register( sx1231_reg["RegOpMode"], (self.read_register(sx1231_reg["RegOpMode"]) & 0xe3) | OPMODE_RX) self._mode = OPMODE_RX else: raise ValueError('Unrecognized Mode') while ((self.read_register(sx1231_reg["RegIrqFlags1"]) & IRQFLAGS1_MODEREADY) == 0x00): pass return def RSSI(self): # write trigger self.write_register(sx1231_reg["RegRssiConfig"], 0b1) while ((self.read_register(sx1231_reg["RegRssiConfig"]) & RSSI_DONE) == 0x0): pass rssival = -self.read_register(sx1231_reg["RegRssiValue"]) rssival = rssival / 2 return rssival # call when g0flag goes true def read_fifo(self): global g0_flag self.standby() fifolist = self.RFM_SPI.readbytes(default_Payload_bytes + 1) #debugging # value = True # while value: # print "* "; # value = self.read_register(sx1231_reg["RegIrqFlags2"]) & IRQFLAGS2_PAYLOADREADY # garbage=self.RFM_SPI.readbytes(default_Payload_bytes+1) value = self.read_register( sx1231_reg["RegIrqFlags2"]) & IRQFLAGS2_PAYLOADREADY if value == 0: g0_flag = False return fifolist def standby(self): self.set_mode(OPMODE_STANDBY) return def receive(self): self.set_mode(OPMODE_RX) g0_flag = False return def send(self, bytelist): self.set_mode(OPMODE_STANDBY) if len(bytelist) > MAX_PACKET_LEN: raise ValueError('Max Packet Len Exceeded') #bytelist = [self.node_id+1]+[self.node_id] + bytelist # bytelist = [self.node_id] + [self.node_id+1] + bytelist # bytelist = [self.node_id] + bytelist bytelist = [self.node_id] + bytelist print "\tbytelist: ", bytelist wbuf = [(sx1231_reg["RegFifo"] | 0x80)] + bytelist self.RFM_SPI.writebytes(wbuf) start_time = time.time() self.set_mode(OPMODE_TX) # Read pin or register... # value = GPIO.input(G0_PIN) value = self.read_register( sx1231_reg["RegIrqFlags2"]) & IRQFLAGS2_PACKETSENT #print "Start send:\t", start_time while value == 0: # value = GPIO.input(G0_PIN) value = self.read_register( sx1231_reg["RegIrqFlags2"]) & IRQFLAGS2_PACKETSENT elapsed_time = time.time() - start_time if (elapsed_time > 10): break #print "Stop send:\t", elapsed_time self.set_mode(OPMODE_STANDBY) return def stop(self): return
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 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] self._unselect() return result def _writeReg(self, addr, 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.readRSSI() < 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.readRSSI() 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] ] while self._readReg(REG_SYNCVALUE1) != 0xaa: self._writeReg(REG_SYNCVALUE1, 0xaa) while self._readReg(REG_SYNCVALUE1) != 0x55: self._writeReg(REG_SYNCVALUE1, 0x55) 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