class I2C(_Bus,NET): "Class representing a I2C bus, locally or over TCP/IP. Use an Instance of this class as the bus parameter for any board" Devices = {} DeviceList= {} class Device(): """class respresening a device connected to the bus, instances are created automatically""" def __init__(self,address,InUseBy=None,Bus = None,Ident=''): """address = int (0x00-0xFF), address of this device Ident = The Identification of the device for scan matching, default:'' InUseBy = If an Instance of a device-class is created, InUseBy points to that Instance""" self.Ident = Ident self.InUseBy = InUseBy VersionStrip =Ident.split(' ')[0].lower() if Ident !='' and VersionStrip in I2C.DeviceList: self.InUseBy = I2C.DeviceList[VersionStrip](Bus,address) else: self.Type=None if self.InUseBy!=None: self.InUseBy.Ident=VersionStrip def __init__(self,device=0,Port=None,Server=None): """ @param device The I2C bus to use e.g. /dev/i2c-0, /dev/i2c-1 etc. @param Port Default=None if set to an Integer this will be the TCP/IP port to listen on. @param Server Default=None if set to a string e.g. '192.168.200.137' the bus listening on that address/port combination will be connected to. @todo Ckeck for Raspberry Pi, and its version in /Proc/CPUInfo """ self.Port = Port self.Server=Server if self.Server != None: # TCP Client mode self.NetInit() self.Transaction=self._NetTransaction else: try: self.I2cBus = SMBus(device) except : print 'Need python-smbus for I2C bus to work' print '' print 'To install: sudo apt-get install python-smbus' return None if self.Port != None: #TCP Server Mode self.ServerThread = threading.Thread(target=self.ListenerTread) self.ServerThread.start() def Close(self): self.I2cBus.close() def Transaction(self, OutBuffer,read=0): if read!=0: try: return 0,' '+''.join([chr(m) for m in self.I2cBus.read_i2c_block_data((ord(OutBuffer[0])>>1),ord(OutBuffer[1]))]) except IOError: return 0," " else: self.I2cBus.write_i2c_block_data(ord(OutBuffer[0])>>1 ,ord(OutBuffer[1]), [ord(m) for m in OutBuffer[2:]]) return 0,None # # TODO: change Transaction to _Bus.Read_String # def scan(self,Display=None,line=0): for i in range(0x00,0xFF,0x02): ret, buf = self.Transaction(chr(i)+chr(Ident),0x20) Identification ="" for c in buf[2:]: if ord(c)==0: break if ord(c) in range(32,127): Identification +=c if Identification != "": if i in self.Devices: self.Devices[i].Ident=Identification else: self.Devices[i]=I2C.Device(i,Ident=Identification,Bus=self) if Display!=None: ProgressBar(i,minval=0, maxval=0xFF , Display = Display, y=line) sleep(.05) def AddDevice(self,Address, InUseBy): self.Devices[Address]=I2C.Device(Address,InUseBy=InUseBy,Bus=self)
def get_status(): """ Get the humidity, tempetature, led and garage door status by calling the arduino by I2C Obtenez l'humidité, la température, l'état des leds et de la porte de garage en appelant l'arduino par I2C """ bus = SMBus(1) i2c_data1 = bus.read_i2c_block_data(ARDUINO1_I2C_ADDRESS,0) humidity, temperature = struct.unpack("ff", struct.pack("B"*8,*i2c_data1[0:8])) leds = i2c_data1[8:13] i2c_data2 = bus.read_i2c_block_data(ARDUINO2_I2C_ADDRESS,0) garage_door = i2c_data2[0] bus.close() global last_door_status # Display door status on LCD - Affiche le status de la porte sur le LCD if garage_door == 1 and last_door_status == False: display_message("Garage","Open") last_door_status = True elif garage_door == 0 and last_door_status == True: display_message("Garage","Closed") last_door_status = False response = {"humidity" : humidity, "temperature" : temperature, "leds" : leds, "garageDoor" : garage_door} return jsonify(response)
def main(): db = QSqlDatabase.addDatabase("QSQLITE") db.setDatabaseName("HtrTest.db") if not db.open(): result = QMessageBox.warning( None, 'HtrTest', "Database Error: %s" % db.lastError().text()) print(result) sys.exit(1) # create IO object io = GPIO_config.io() pid = PID() # create i2c smbus object i2c_bus = SMBus( 1) # 0 = /dev/i2c-0 (port I2C0), 1 = /dev/i2c-1 (port I2C1) # create MCP9600 T/C readout object tc = MCP9600(db, i2c_bus) cid = tc.mcp9600_read_id() print("chip id = %x" % cid) qApp = QtWidgets.QApplication(sys.argv) aw = ApplicationWindow(db, tc, io, pid) aw.setWindowTitle("%s" % progname) aw.show() sys.exit(qApp.exec_()) i2c_bus.close()
def set_baseline(self, hi, lo): msg = [hi, lo] bus = SMBus(I2CBUS) resp = bus.write_i2c_block_data(self.I2Caddr, CCS8_REG_BASELINE, msg) bus.close() return
def getAngle(self): bus = SMBus(self.busnum) #return self.bus.read_i2c_block_data(self.address, AS5048B_registers["ANGLMSB_REG"], 8) - self.angle_zero val = (bus.read_i2c_block_data(self.address, AS5048B_registers["ANGLMSB_REG"], 2)) bus.close() return val
def set_comp(self, t, h): # don't know if a value of 0.0% RH is allowed # so make minimun RH 0.01% if h < 0.1: h = 0.01 if t < -25.0: t = -25.0 rh = h * 2.0 rh_i = int(rh // 1) rh_i &= 0xff #rh_d = int( (rh % 1) * 256 ) # per CC-803-AN rev 6, AMS writes zero to fractional byte rh_d = 0x00 # per datasheet 25 degree offset th = (t + 25) * 2.0 th_i = int(th // 1) th_i &= 0xff #th_d = int( (th % 1) * 256 ) # per CC-803-AN tev 6, AMS writes zero to fractional byte th_d = 0x00 msg = [rh_i, rh_d, th_i, th_d] print "ccs811.set_comp() set T: %.1f RH: %.1f" % (t, h) print "ccs811.set_comp() regs. 0x%02x 0x%02x 0x%02x 0x%02x" % ( th_i, th_d, rh_i, rh_d) bus = SMBus(I2CBUS) bus.write_i2c_block_data(self.I2Caddr, CCS811_REG_ENV_DATA, msg) bus.close() return
def _set_regs(self, register, value): bus = SMBus(I2CBUS) if isinstance(value, int): bus.write_byte_data(self.i2c_addr, register, value) else: bus.write_i2c_block_data(self.i2c_addr, register, value) bus.close()
def __init__(self, addr): self.address = addr bus = SMBus(1) self.VOUT_MODE = bus.read_byte_data(self.address, 0x20) bus.close() voutN = self.VOUT_MODE & 0b00011111 self.VOUT_N = self.twos_comp(voutN, 5) print("DRQ1250 succesfully connected to PMBus... \n")
class AK8975: def __init__(self, i2c_bus, i2c_addr): self._bus = SMBus(i2c_bus) self._dev_addr = i2c_addr self.xCoeff = self._bus.read_byte_data(self._dev_addr, REG_ASAX) self.yCoeff = self._bus.read_byte_data(self._dev_addr, REG_ASAY) self.zCoeff = self._bus.read_byte_data(self._dev_addr, REG_ASAZ) self._bus.write_byte_data(self._dev_addr, REG_CNTL, CNTL_PWRDWN) self.offsets = [0.] * 3 self.scale = [1.] * 3 self.last_sin = 0. self.last_cos = 0.0 self.lock_counter = 100 def setOffset(self, offsets): self.offsets = offsets def setScale(self, scale): self.scale = scale def close(self): self._bus.close() def read_gauss(self): self._bus.write_byte_data(self._dev_addr, REG_CNTL, CNTL_MEASURE) while (self._bus.read_byte_data(self._dev_addr, REG_ST1) & ST1_DRDY) == 0: time.sleep(0.001) data = self._bus.read_i2c_block_data(self._dev_addr, REG_HXL, 6) data = bytes(data) fields = struct.unpack('hhh', data) x = self.adjustValue(fields[0], self.xCoeff) y = self.adjustValue(fields[1], self.yCoeff) z = self.adjustValue(fields[2], self.zCoeff) return (x, y, z) def read_heading(self): x, y, z = self.read_gauss() x = (x - self.offsets[0]) * self.scale[0] y = (y - self.offsets[1]) * self.scale[1] z = (z - self.offsets[2]) * self.scale[2] #heading = 90+ (math.atan2(y, x) * 180./math.pi) #heading = heading + 90.0 #robot compass not north aligned heading = math.atan2(y, x) self.last_sin = ALPHA * self.last_sin + (1 - ALPHA) * math.sin(heading) self.last_cos = ALPHA * self.last_cos + (1 - ALPHA) * math.cos(heading) heading = math.atan2(self.last_sin, self.last_cos) * 180. / math.pi heading = heading + 180 if self.lock_counter == 0: return heading else: self.lock_counter = self.lock_counter - 1 return None def adjustValue(self, value, adj): # apply the proper compensation to value. This equation is taken # from the AK8975 datasheet, section 8.3.11 return (value * ((((adj - 128.0) * 0.5) / 128.0) + 1.0))
def getPowerOut(self, fromDRQ): if (fromDRQ == True): bus = SMBus(1) self.powerOut = self.decodePMBus( bus.read_word_data(self.address, 0x96)) bus.close() else: self.powerOut = self.voltageOut * self.current return self.powerOut
def _get_regs(self, register, length): bus = SMBus(I2CBUS) if length == 1: resp = bus.read_byte_data(self.i2c_addr, register) else: resp = bus.read_i2c_block_data(self.i2c_addr, register, length) bus.close() return resp
def get_baseline(self): # Looks like on power up, the CCS811 keeps # adjusting its baseline possibly bacause # the calculated tVOC value is negitive. # In effect the chip is auto zeroing itself. bus = SMBus(I2CBUS) resp = bus.read_i2c_block_data(self.I2Caddr, CCS811_REG_BASELINE, 2) bus.close() bl = (resp[0] << 8) | resp[1] #print "Baseline: 0x%04x" % bl return bl
class MPU6050: def __init__(self, address_mpu): self.address_mpu = address_mpu self.i2c = SMBus() self.setup() def setup(self): # open bus 1 print('open bus 1') self.i2c.open(1) # sensor uit sleep modus halen print('sensor uit sleep modus halen') self.i2c.write_byte_data(self.address_mpu, 0x6B, 1) # instellen gyroscoop print('gyroscoop instellen') self.i2c.write_byte_data(self.address_mpu, 0x1B, 0x00) def read_data(self): # data inlezen raw_data = self.i2c.read_i2c_block_data(self.address_mpu, 0x43, 6) # gyro x_waarde_gyro = self.registerwaarden_omzetten(raw_data[0], raw_data[1]) y_waarde_gyro = self.registerwaarden_omzetten(raw_data[2], raw_data[3]) z_waarde_gyro = self.registerwaarden_omzetten(raw_data[4], raw_data[5]) x_waarde_gyro_in_graden, y_waarde_gyro_in_graden, z_waarde_gyro_in_graden = self.omzetten_graden_per_seconde( x_waarde_gyro, y_waarde_gyro, z_waarde_gyro) return x_waarde_gyro_in_graden, y_waarde_gyro_in_graden, z_waarde_gyro_in_graden @staticmethod def registerwaarden_omzetten(msb, lsb): msb = msb << 8 if bin(msb)[2] == '1': msb = msb - 2**16 waarde = msb | lsb waarde = waarde / 340 + 36.53 return waarde @staticmethod def omzetten_graden_per_seconde(x_waarde, y_waarde, z_waarde): rot_x = x_waarde / 131 rot_y = y_waarde / 131 rot_z = z_waarde / 131 return rot_x, rot_y, rot_z def opkuisen(self): self.i2c.close()
def get_status(command, value): status = "" bus = SMBus(i2cBusAddr) BytesToSend = convert_string_to_bytes(value) bus.write_i2c_block_data(arduinoSlaveAddress, ord(command), BytesToSend) time.sleep(0.001) for i in range (0, 11): statusChr = chr(bus.read_byte(arduinoSlaveAddress)) if statusChr != ";": status += statusChr else: break bus.close() return status
class VL53LOX: def __init__(self, address): self.address = address self.i2c = SMBus() self.setup() def setup(self): self.i2c.open(1) def read_data(self): self.i2c.write_byte(self.address, 0) value = self.i2c.read_byte(self.address) return value def close(self): self.i2c.close()
def setUVLimit(self, uvLimit): if (uvLimit > 32): uvWarnLimit = float(uvLimit) + 2 uvFaultLimit = float(uvLimit) else: uvWarnLimit = 34.0 uvFaultLimit = 32.0 bus = SMBus(1) #bus.write_byte_data(self.address, 0x10, int(0b00000000)) bus.write_word_data(self.address, 0x59, int(uvFaultLimit)) #This causes an error bus.write_word_data( self.address, 0x58, int(uvWarnLimit) ) #The error shows up here or if this is commented out it shows up on under the getTempurature method bus.close()
def run(self): while True: bus = SMBus(1) i2c_data1 = bus.read_i2c_block_data(ARDUINO1_I2C_ADDRESS,0) humidity, temperature = struct.unpack("ff", struct.pack("B"*8,*i2c_data1[0:8])) bus.close() data = {"timestamp" : str(datetime.now()), "humidity" : humidity, "temperature" : temperature} with open("dataHistory.json","a+") as f: f.write(json.dumps(data) + "\n") self.elements.append(data) if len(self.elements) > self.number_elements: self.elements.pop(0) time.sleep(self.interval)
def kill(self, bf): bus = SMBus(1) range_sensor = LidarLiteV3(bus) range_sensor.begin(0, 0x62) dest = range_sensor.get_distance(False, 0x62) print "#########################Distance: {}############################".format( dest) if dest < 160: print "Killing" laser = Laser() laser.trigger(1) time.sleep( 2 ) #MAKE SURE THE switch_off gets called!! either by timeout or manually calling switch_off() print("Laser test done") bus.close() time.sleep(5) im, balloon_list = bf.find_balloons() if len(balloon_list) > 0: return False return True return False
class i2c_interface: def __init__(self, address=0x3c): """ :param address: i2c address of ssd1306 """ self.bus = SMBus(self.bus_id()) self.address = address def __del__(self): self.close_i2c() def close_i2c(self): self.bus.close() def bus_id(self): """ :return: Returns SMBUS id of Raspberry Pi """ revision = [ lines[12:-1] for lines in open('/proc/cpuinfo', 'r').readlines() if "Revision" in lines[:8] ] revision = (revision + ['0000'])[0] return 1 if int(revision, 16) >= 4 else 0 def i2c_read(self, register=0): data = self.bus.read_byte_data(self.address, register) return data def i2c_write(self, register=DISPLAY_START_LINE, data=0): # Write a byte to address, register self.bus.write_byte_data(self.address, register, data) def i2c_write_block(self, register=DISPLAY_START_LINE, data=None): if data is None: data = [40] self.bus.write_i2c_block_data(self.address, register, data)
def detect_device(): for busNum in range(20): if not os.path.exists('/dev/i2c-' + str(busNum)): if busNum == 20 - 1: print("device not found.") return -1 continue bus = SMBus(busNum) print("Bus #{} open. Searching...".format(busNum)) response = bus.read_byte(addr) if response >= 0: #print("On bus {} a device {} found with response of {}".format(busNum, hex(dev_addr), hex(response))) if bus.read_byte_data(addr, 0x00) == 2: M = bus.read_byte(addr) m = bus.read_byte(addr) print( "Bus:{} Addr:{} Reg:0x00 query returns {}.{}.\nPossible AsRock AURA device with FW nu50_{}.{} detected." .format(busNum, hex(addr), M, m, M, m)) if M != 1 and m != 10: print( "This FW is NOT supported, yet. Try with your own risk!" ) return bus bus.close()
def zero_magnitude(self): bus = SMBus(self.busnum) self.magnitude_zero = bus.read_i2c_block_data(self.address, AS5048B_registers["MAGNMSB_REG"], 8) bus.close()
class LinuxI2cBus: """A Linux I²C device, which is itself an I²C bus. Should not be instantiated directly; use `LinuxI2c.find_devices` instead. This type mimics the `smbus.SMBus` read/write/close APIs. However, `open` does not take any parameters, and not all APIs are available. """ # note: this is not a liquidctl BaseBus, as that would cause # find_liquidctl_devices to try to directly instantiate it def __init__(self, i2c_dev): self._i2c_dev = i2c_dev self._smbus = None try: assert i2c_dev.name.startswith('i2c-') self._number = int(i2c_dev.name[4:]) except: raise ValueError(f'cannot infer bus number') def find_devices(self, drivers, **kwargs): """Probe drivers and find compatible devices in this bus.""" for drv in drivers: yield from drv.probe(self, **kwargs) def open(self): """Open the I²C bus.""" if not self._smbus: try: self._smbus = SMBus(self._number) except FileNotFoundError: if Path('/sys/class/i2c-dev').exists(): raise raise OSError('kernel module i2c-dev not loaded') from None def read_byte(self, address): """Read a single byte from a device.""" value = self._smbus.read_byte(address) _LOGGER.debug('read byte @ 0x%02x: 0x%02x', address, value) return value def read_byte_data(self, address, register): """Read a single byte from a designated register.""" value = self._smbus.read_byte_data(address, register) _LOGGER.debug('read byte data @ 0x%02x:0x%02x: 0x%02x', address, register, value) return value def read_word_data(self, address, register): """Read a single 2-byte word from a given register.""" value = self._smbus.read_word_data(address, register) _LOGGER.debug('read word data @ 0x%02x:0x%02x: 0x%04x', address, register, value) return value def read_block_data(self, address, register): """Read a block of up to 32 bytes from a given register.""" data = self._smbus.read_block_data(address, register) _LOGGER.debug('read block data @ 0x%02x:0x%02x: %r', address, register, LazyHexRepr(data)) return data def write_byte(self, address, value): """Write a single byte to a device.""" _LOGGER.debug('writing byte @ 0x%02x: 0x%02x', address, value) return self._smbus.write_byte(address, value) def write_byte_data(self, address, register, value): """Write a single byte to a designated register.""" _LOGGER.debug('writing byte data @ 0x%02x:0x%02x: 0x%02x', address, register, value) return self._smbus.write_byte_data(address, register, value) def write_word_data(self, address, register, value): """Write a single 2-byte word to a designated register.""" _LOGGER.debug('writing word data @ 0x%02x:0x%02x: 0x%04x', address, register, value) return self._smbus.write_word_data(address, register, value) def write_block_data(self, address, register, data): """Write a block of byte data to a given register.""" _LOGGER.debug('writing block data @ 0x%02x:0x%02x: %r', address, register, LazyHexRepr(data)) return self._smbus.write_block_data(address, register, data) def close(self): """Close the I²C connection.""" if self._smbus: self._smbus.close() self._smbus = None def load_eeprom(self, address): """Return EEPROM name and data in `address`, or None if N/A.""" # uses kernel facilities to avoid directly reading from the EEPROM # or managing its pages, also avoiding the need for unsafe=smbus dev = f'{self._number}-{address:04x}' try: name = self._i2c_dev.joinpath(dev, 'name').read_text().strip() eeprom = self._i2c_dev.joinpath(dev, 'eeprom').read_bytes() return LinuxEeprom(name, eeprom) except Exception as err: return None @property def name(self): return self._i2c_dev.name @property def description(self): return self._try_sysfs_read('name') @property def parent_vendor(self): return self._try_sysfs_read_hex('device/vendor') @property def parent_device(self): return self._try_sysfs_read_hex('device/device') @property def parent_subsystem_vendor(self): return self._try_sysfs_read_hex('device/subsystem_vendor') @property def parent_subsystem_device(self): return self._try_sysfs_read_hex('device/subsystem_device') @property def parent_driver(self): try: return Path( os.readlink(self._i2c_dev.joinpath('device/driver'))).name except FileNotFoundError: return None def __str__(self): if self.description: return f'{self.name}: {self.description}' return self.name def __repr__(self): def hexid(maybe): if maybe is not None: return f'{maybe:#06x}' return 'None' return f'{self.__class__.__name__}: name: {self.name!r}, ' \ f'description: {self.description!r}, ' \ f'parent_vendor: {hexid(self.parent_vendor)}, ' \ f'parent_device: {hexid(self.parent_device)}, ' \ f'parent_subsystem_vendor: {hexid(self.parent_subsystem_vendor)}, ' \ f'parent_subsystem_device: {hexid(self.parent_subsystem_device)}, ' \ f'parent_driver: {self.parent_driver!r}' def _try_sysfs_read(self, *sub, default=None): try: return self._i2c_dev.joinpath(*sub).read_text().rstrip() except FileNotFoundError: return default def _try_sysfs_read_hex(self, *sub, default=None): try: return int(self._i2c_dev.joinpath(*sub).read_text(), base=16) except FileNotFoundError: return default
def main(): # Read arguments parser = argparse.ArgumentParser(description='Change SuperMicro X8 Fan Control.') parser.add_argument('-m', '--mode', type=str, choices=['smart', 'cruise'], help='Set the fan mode: smart or cruise. smart: to use Smart Fan mode. cruise: to use Thermal Cruise mode.') parser.add_argument('-p', '--pwm', type=str, help='Set Fan Duty (in percentage).') parser.add_argument('-t', '--temp', type=str, help='Set Temperature (in Celsius) associated to pwm.') parser.add_argument('-H', '--hystersis', type=int, help='Set Hystersis value in degree (0-15)') args = parser.parse_args() # Open SMBus try: bus = SMBus(0) except: print("Failed to open i2c bus (/dev/i2d-0). Make sure i2c-dev module is loaded.") return #Check if we have the right device. try: vendor = w83795_read(bus, 0xfd) chipid = w83795_read(bus, 0xfe) #debug("vendor %s, chipid %s" % (vendor, chipid)) if vendor != NUVOTON_VENDOR_ID or chipid != CHIP_ID: print("unexpected vendor %s, chipid %s" % (vendor, chipid)) return # Check if Smarts Fan Control is enabled if args.mode == 'smart': # Check arguments if not args.pwm or not args.temp: print('pwm and temp are required') return pwm = args.pwm.split(',') temp = args.temp.split(',') if len(pwm) != len(temp): print("pwm and temp must have the same number of values") return # Change Smart Fan Control value for i in range(0,7): p = pwm[i] if i < len(pwm) else pwm[-1] tt = temp[i] if i < len(temp) else temp[-1] print("Set Smart Fan Control %s%% - %sC" % (p, tt)) for t in TEMPS: w83795_write(bus, W83795_REG_SFIV_DCPWM(t)[i], from_perc(p)) w83795_write(bus, W83795_REG_SFIV_TEMP(t)[i], from_degree(tt)) # Change Minimum PWM for f in FANS: w83795_write(bus, W83795_REG_FONV(f), from_perc(pwm[0])) # Change critical Temp for t in TEMPS: w83795_write(bus, W83795_REG_CTFS(t), from_degree(temp[-1])) # Set Smart Fan Control Mode T6FC - T1FC w83795_write(bus, W83795_REG_FCMS1, 0x0) w83795_write(bus, W83795_REG_FCMS2, 0x3f) elif args.mode == 'cruise': # Check arguments if not args.temp: print('temp is required') return temp = int(args.temp) print("Set Thermal Cruise %sC" % (temp,)) for t in TEMPS: w83795_write(bus, W83795_TTTI(t), from_degree(temp)) # Change critical Temp for t in TEMPS: w83795_write(bus, W83795_REG_CTFS(t), from_degree(80)) # Set Thermal Cruise Mode. w83795_write(bus, W83795_REG_FCMS1, 0x0) w83795_write(bus, W83795_REG_FCMS2, 0x0) # Set hystersis if args.hystersis: ht = max(min(args.hystersis,15),0) print("Set hystersis %sC" % ht) # Change Smart Fan Control value for t in range(0,6): w83795_write(bus, W83795_REG_HT(t), ht) if args.mode or args.pwm or args.temp or args.hystersis: return # Check if Smarts Fan Control is enabled fcms1 = w83795_read(bus, W83795_REG_FCMS1) fcms2 = w83795_read(bus, W83795_REG_FCMS2) & 0xff # Default to show all data. for t in TEMPS: print("Temp%s to Fan mapping Relationships (T%sFMR)" % (t+1, t+1)) tfmr = w83795_read(bus, W83795_REG_TFMR(t)) fans= [i+1 for i in FANS if tfmr & (0x1<<i)] print(' '.join(['Fan%s' % i for i in fans])) print("Smart Fan Control Table (SFIV)") temp = w83795_read(bus, W83795_REG_SFIV_TEMP(t)) print(''.join([("%sC" % to_degree(v)).rjust(6) for v in temp])) dcpwm = w83795_read(bus, W83795_REG_SFIV_DCPWM(t)) print(''.join([("%s%%" % to_perc(v)).rjust(6) for v in dcpwm])) ttti = w83795_read(bus, W83795_TTTI(t)) print("Thermal Cruise (TTTI): %sC" % (ttti,)) ctfs = w83795_read(bus, W83795_REG_CTFS(t)) print("Critical Temperature (T%sCTFS): %sC" % (t, to_degree(ctfs))) ht = w83795_read(bus, W83795_REG_HT(t)) & 0b1111 print("Hysteresis (HT%s): %sC" % (t, ht)) tmp = w83795_read(bus, W83795_REG_TEMP_READ[t]) print("Current Temperature (TEMP%s): %sC" % (t, to_degree(tmp),)) print('---') for f in FANS: fonv = w83795_read(bus, W83795_REG_FONV(f)) print("Fan%s Output Nonstop Value (F%sONV): %s%%" % (f+1, f+1, to_perc(fonv))) #for f in range(0,6): # w83795_write(bus, W83795_REG_FONV(f), 50) #w83795_write(bus, W83795_REG_SFIV_DCPWM(0)[0], 50) #w83795_write(bus, W83795_REG_SFIV_TEMP(0)[0], 85) #w83795_write(bus, W83795_REG_SFIV_TEMP(1)[0], 85) finally: bus.close()
def zero_angle(self): bus = SMBus(self.busnum) self.angle_zero = bus.read_i2c_block_data(self.address, AS5048B_registers["ANGLMSB_REG"], 8) bus.close()
class DeviceConnection(object): def __init__(self, mode='uart_usb', address=I2C_ADDRESS, port=UART_PORT, bus=I2C_BUS): """Initialize UART or I2C connection to slave microcontroller""" self._mode = mode self.address = address self.port = port if mode == 'uart_usb': self._con = serial.Serial( port=self.port, baudrate=UART_BAUDRATE, bytesize=serial.EIGHTBITS, stopbits=serial.STOPBITS_ONE, parity=serial.PARITY_NONE, rtscts=False, dsrdtr=False, timeout=UART_TIMEOUT_MS / 1000, write_timeout=5, ) else: self._con = SMBus(bus) time.sleep(1) def disconnect(self): """Disconnect UART or I2C connection""" self._con.close() def get_register(self, register_address, format_bytes=False): """Get single register from slave microcontroller""" if format_bytes: return self.get_registers(register_address, register_len=1, format_bytes=format_bytes) else: return self.get_registers(register_address, register_len=1, format_bytes=format_bytes)[0] def get_registers(self, register_address, register_len=1, format_bytes=False): """Get multiple registers from slave microcontroller""" if COMM_DEBUG: print("request register '%02x' len '%i'" % (register_address, register_len * 2)) if self._mode == 'uart_usb': self._con.write(b'R%02x%02x\n' % (register_address, register_len * 2)) response = self._con.read_until( terminator=serial.LF).decode('ascii').strip() if COMM_DEBUG: print("raw response '%s'" % response) if not response.startswith('ACK'): raise Exception("response error") response = response.split('ACK')[1] registers = [] if not format_bytes: registers = [ int(response[i:i + 4], 16) for i in range(0, len(response), 4) ] else: registers = [ int(response[i:i + 2], 16) for i in range(0, len(response), 2) ] if COMM_DEBUG: print("decoded response '%s'" % registers) return registers else: response = self._con.read_i2c_block_data(self.address, register_address, register_len * 2) if COMM_DEBUG: print("raw response '%s'" % response) registers = [] for i in range(0, register_len * 2, 2): registers.append((response[i] << 8) + response[i + 1]) if COMM_DEBUG: print("decoded response '%s'" % registers) return registers def set_register(self, register_address, register_value): """Set single register on slave microcontroller""" return self.set_registers(register_address, [register_value]) def set_registers(self, register_address, register_values, format_bytes=False): """Set multiple registers on slave microcontroller""" if self._mode == 'uart_usb': out_str = "" if format_bytes: for register_value in register_values: out_str += str("%02x" % register_value) else: for register_value in register_values: out_str += str("%04x" % register_value) if COMM_DEBUG: print("set registers raw '%02x - %s'" % (register_address, out_str)) self._con.write(b'W%02x%s\n' % (register_address, out_str.encode('ascii'))) response = self._con.read_until( terminator=serial.LF).decode('ascii').strip() if COMM_DEBUG: print("raw response '%s'" % response) if not response.startswith('ACK'): raise Exception("response error") return response else: out_bytes = [] if format_bytes: out_bytes = register_values else: for register_value in register_values: out_bytes.extend([(register_value & 0xFF00) >> 8, (register_value & 0x00FF)]) if COMM_DEBUG: print("set registers raw '%02x - %s'" % (register_address, out_bytes)) self._con.write_i2c_block_data(self.address, register_address, out_bytes)
print "PLL Select: (0: RF or 1: VCO)" vco = raw_input() user.vco = bool(int(vco)) print bcolors.WARNING + "Loading PLL" + bcolors.ENDC pll = si5338POST(0x70, user.vco, bus, VCOREGS, PINS["INTERRUPT"], GPIO) time.sleep(0.5) if pll.check(): print bcolors.FAIL + "Exiting..." + bcolors.ENDC exit() else: print bcolors.OKGREEN + "PLL Ready" + bcolors.ENDC bus.close() print "Enable Test Signal: (0: Disable or 1: Enable)" testSignal = raw_input() print "Select SCROD: (A or B)" scrod = raw_input() print "Input bunchMarkerA: (0 - 5280)" bma = raw_input() print "Input bunchMarkerB: (0 - 5280)" bmb = raw_input() print bin(int(bma)) print bin(int(bmb)) user.testSignal = bool(int(testSignal)) user.scrod = scrod
class Monster(): """Monster class. Should only be used with a context manager! All GPIOs are BCM GPIO numbers. """ I2C_BUS_NUM = 0 SERVO_I2C_ADDR = 0xa SERVO_CMD_OPEN = 1 SERVO_CMD_CLOSE = 2 SERVO_CMD_TWITCH = 3 DISTANCE_UPDATE_SECONDS = .2 def __init__(self, solenoid_gpio_num=17, echo_trigger_gpio_num=24, echo_gpio_num=25): self._gpios = { 'solenoid': solenoid_gpio_num, 'echo_trigger': echo_trigger_gpio_num, 'echo': echo_gpio_num, } self._rangefinder_settled = False self._distance_lock = threading.Lock() self._distance = 999999999 def __enter__(self): PWM.set_loglevel(PWM.LOG_LEVEL_ERRORS) GPIO.setup(self._gpios['solenoid'], GPIO.OUT) GPIO.setup(self._gpios['echo_trigger'], GPIO.OUT) GPIO.setup(self._gpios['echo'], GPIO.IN) self._i2c_bus = SMBus() self._i2c_bus.open(Monster.I2C_BUS_NUM) self.close_door() return self def __exit__(self, exc_type, exc_value, traceback): self._cm_active = False self._i2c_bus.close() GPIO.cleanup() def activate_solenoid(self): GPIO.output(self._gpios['solenoid'], True) def deactivate_solenoid(self): GPIO.output(self._gpios['solenoid'], False) def fire_ball(self, active_time=.3): """Activate the solenoid for `active_time' seconds.""" self.activate_solenoid() time.sleep(active_time) self.deactivate_solenoid() def i2c_write(self, cmd, max_iters): for i in range(max_iters): try: self._i2c_bus.write_byte(Monster.SERVO_I2C_ADDR, cmd) return except IOError: time.sleep(.5) pass print "I2C Contention! Couldn't send command:", cmd def close_door(self): self.i2c_write(Monster.SERVO_CMD_CLOSE, 10) def open_door(self): self.i2c_write(Monster.SERVO_CMD_OPEN, 10) def twitch_door(self): self.i2c_write(Monster.SERVO_CMD_TWITCH, 10) def toggle_door(self, time_open=.8): self.open_door() time.sleep(time_open) self.close_door() def ball_and_door(self): self.twitch_door() time.sleep(1) self.fire_ball() time.sleep(1) self.fire_ball() # based on http://www.modmypi.com/blog/hc-sr04-ultrasonic-range-sensor-on-the-raspberry-pi def measure_distance(self): """Returns the distance (in meters) to the object being looked at. Probably should only happen in a thread due to all the sleeping """ if not self._rangefinder_settled: # let the sensor settle GPIO.output(self._gpios['echo_trigger'], False) time.sleep(2) self._rangefinder_settled = True # 10 us pulse GPIO.output(self._gpios['echo_trigger'], True) time.sleep(0.00001) GPIO.output(self._gpios['echo_trigger'], False) # interrupt might be better? pulse_start = time.time() cnt = 0 while not GPIO.input(self._gpios['echo']): pulse_start = time.time() # maybe pass would be better? might actually more cpu though... cnt += 1 if cnt > 20000: return 999999999 # we got a pulse, measure it's width by polling until it goes low # again. cnt = 0 pulse_end = time.time() while GPIO.input(self._gpios['echo']): pulse_end = time.time() cnt += 1 if cnt > 20000: return 999999999 pulse_duration = pulse_end - pulse_start sound_mps = 343.0 # speed of sound: 343 m/s distance = sound_mps * pulse_duration # and the pulse width is actually the time it takes to get to the # object *and back*, so we need to divide by two to get just the # distance: distance /= 2.0 # Because the datasheet says: # # we suggest to use over 60ms measurement cycle, in order to # prevent trigger signal to the echo signal. # # We'll use 80ms to be safe time.sleep(.08) return distance def print_distance(self): print 'Distance: ', self.measure_distance(), ' meters' def monitor_distance(self, iters=10): iters = int(iters) # we pass strings from the command line below... for i in xrange(iters): self.print_distance() sys.stdin.flush() def set_distance(self, distance): with self._distance_lock: self._distance = distance def get_distance(self): with self._distance_lock: return self._distance def watch_distance(self): while self._keep_watching: distance = self.measure_distance() self.set_distance(distance) time.sleep(Monster.DISTANCE_UPDATE_SECONDS) print 'done watching distance' def monster_loop(self, trigger_threshold_meters=1.0, come_closer_meters=2.0): loop_sound('background.mp3') self._keep_watching = True dist_thread = threading.Thread(target=self.watch_distance) dist_thread.start() try: last_come_closer = 0 distances = [0, 0, 0] # simple moving average... while True: distances.insert(0, self.get_distance()) distances.pop() distance = sum(distances) / 3.0 print 'distances, distance:', distances, distance if distance < come_closer_meters and \ distance > trigger_threshold_meters and \ time.time() - last_come_closer > 12: print 'come closer...' play_sound('come-closer.mp3') last_come_closer = time.time() elif distance < trigger_threshold_meters: play_sound('vocal-leave-now-happy-halloween.mp3') time.sleep(1) print 'FIRE!' self.ball_and_door() time.sleep(10) time.sleep(.3) except KeyboardInterrupt: print "Interrupt received. Exiting loop." except SystemExit: print "Exiting loop." self._keep_watching = False print 'waiting for threads to exit...' dist_thread.join() print "ok, we're outta here" def sayhi(self, sleep_s=0.5, reps=5): for i in xrange(reps): self.open_door() time.sleep(sleep_s) self.close_door() time.sleep(sleep_s)
class PM2: '''Handle display''' # Translation value from String to Display digits = { '': 0, '1': 96, '2': 167, '3': 227, '4': 106, '5': 203, '6': 207, '7': 224, '8': 239, '9': 235, '0': 237 } buffer = [0 for i in xrange(20)] # Buffer for device RAM def __init__(self, defaultBus=PI_DEFAULT_BUS, defaultAddr=PM2_DEFAULT_ADDRESS): self.bus = SMBus(defaultBus) self.busNum = defaultBus self.defaultAddr = defaultAddr self.bus.close() self.bus.open(self.busNum) self.bus.write_byte(self.defaultAddr, PM2_MODE_SET) self.clear() self.set_mode('normal') self.top_right('00') self.middle('000') self.top_left('0000') self.bottom_left('0000') def write_bit(self, addr, position, value): '''write one bit to buffer @addr : buffer address -> int @position : bit position -> int @value : bit value -> boolean ''' mask = ~(1 << position) value = value << position self.buffer[addr] = (self.buffer[addr] & mask) | value def write_digit(self, addr, value): '''write single/multiple digit(s) to buffer @addr : buffer address -> int @value : single/mutiple digit -> string ''' i = addr for x in reversed(value): intVal = self.digits[x] mask = 1 << 4 # Preserve DP bit self.buffer[i] = (self.buffer[i] & mask) | intVal i += 1 def set_mode(self, mode): '''Toggle between different possible mode : -normal -cal/hr -watts -heart rate ''' if (mode == 'normal'): """Time, /500m, Distance""" self.set_segment_colon_top_left(False) self.set_segment_colon_top_right(True) self.set_segment_dp_top(False) self.set_segment_time_top(True) self.set_segment_meters_top(False) self.set_segment_spm_top(True) self.set_segment_int_top(False) self.set_segment_1_middle(False) self.set_segment_colon_middle(True) self.set_segment_500m_middle(True) self.set_segment_calhr_middle(False) self.set_segment_watts_middle(False) self.set_segment_rest_time_middle(False) self.set_segment_int_middle(False) self.set_segment_colon_bottom_left(False) self.set_segment_colon_bottom_right(False) self.set_segment_dp_bottom(False) self.set_segment_ave_bottom(False) self.set_segment_500m_bottom(False) self.set_segment_watts_bottom(False) self.set_segment_split_bottom(False) self.set_segment_cal_bottom(False) self.set_segment_proj_bottom(False) self.set_segment_time_bottom(False) self.set_segment_meters_bottom(True) self.set_segment_dragfactor_bottom(False) elif (mode == 'watts'): """Time, Watts, Distance""" self.set_segment_colon_top_left(False) self.set_segment_colon_top_right(True) self.set_segment_dp_top(False) self.set_segment_time_top(True) self.set_segment_meters_top(False) self.set_segment_spm_top(True) self.set_segment_int_top(False) self.set_segment_1_middle(False) self.set_segment_colon_middle(False) self.set_segment_500m_middle(False) self.set_segment_calhr_middle(False) self.set_segment_watts_middle(True) self.set_segment_rest_time_middle(False) self.set_segment_int_middle(False) self.set_segment_colon_bottom_left(False) self.set_segment_colon_bottom_right(False) self.set_segment_dp_bottom(False) self.set_segment_ave_bottom(True) self.set_segment_500m_bottom(False) self.set_segment_watts_bottom(True) self.set_segment_split_bottom(False) self.set_segment_cal_bottom(False) self.set_segment_proj_bottom(False) self.set_segment_time_bottom(False) self.set_segment_meters_bottom(False) self.set_segment_dragfactor_bottom(False) elif (mode == 'heart rate'): self.set_segment_colon_middle(isHeartRate) def set_segment_colon_top_left(self, enabled): '''Set first : segment at the top from the left''' self.write_bit(13, 5, enabled) def set_segment_colon_top_right(self, enabled): '''Set 2nd : segment at the top from the left''' self.write_bit(18, 1, enabled) def set_segment_int_top(self, enabled): '''Set INT segment in the top right corner''' self.write_bit(19, 0, enabled) def set_segment_spm_top(self, enabled): '''Set SPM segment in the top right corner''' self.write_bit(14, 4, enabled) def set_segment_meters_top(self, enabled): '''Set METERS segment in at the top''' self.write_bit(19, 4, enabled) def set_segment_time_top(self, enabled): '''Set TIME segment in at the top''' self.write_bit(0, 4, enabled) def set_segment_dp_top(self, enabled): '''Set DP segment (decimal point) in at the top''' self.write_bit(1, 4, enabled) def set_segment_calhr_middle(self, enabled): '''Set CAL/HR segment in the middle''' self.write_bit(19, 7, enabled) def set_segment_500m_middle(self, enabled): '''Set /500M segment in the middle''' self.write_bit(19, 5, enabled) def set_segment_int_middle(self, enabled): '''Set INT segment in the middle''' self.write_bit(19, 2, enabled) def set_segment_watts_middle(self, enabled): '''Set WATTS segment in the middle''' self.write_bit(19, 6, enabled) def set_segment_colon_middle(self, enabled): '''Set : segment in the middle''' self.write_bit(19, 1, enabled) def set_segment_1_middle(self, enabled): '''Set '1' segment in the middle''' self.write_bit(13, 6, enabled) def set_segment_rest_time_middle(self, enabled): '''Set REST TIME segment in the middle''' self.write_bit(10, 4, enabled) def set_segment_ave_bottom(self, enabled): '''Set AVE segment in the bottom''' self.write_bit(13, 7, enabled) def set_segment_500m_bottom(self, enabled): '''Set /500M segment in the bottom''' self.write_bit(13, 4, enabled) def set_segment_watts_bottom(self, enabled): '''Set WATTS segment in the bottom''' self.write_bit(12, 4, enabled) def set_segment_split_bottom(self, enabled): '''Set SPLIT segment in the bottom''' self.write_bit(11, 4, enabled) def set_segment_cal_bottom(self, enabled): '''Set CAL segment in the bottom''' self.write_bit(9, 4, enabled) def set_segment_proj_bottom(self, enabled): '''Set PROJ segment in the bottom''' self.write_bit(8, 4, enabled) def set_segment_dp_bottom(self, enabled): '''Set DP segment (decimal point) in the bottom''' self.write_bit(6, 4, enabled) def set_segment_time_bottom(self, enabled): '''Set TIME segment in the bottom''' self.write_bit(7, 4, enabled) def set_segment_meters_bottom(self, enabled): '''Set METERS segment in the bottom''' self.write_bit(13, 0, enabled) def set_segment_dragfactor_bottom(self, enabled): '''Set DRAG FACTOR segment in the bottom''' self.write_bit(18, 0, enabled) def set_segment_heartrate_bottom(self, enabled): '''Set HEART RATE segment in the bottom''' self.write_bit(17, 4, enabled) def set_segment_colon_bottom_left(self, enabled): '''Set 1st : segment at the bottom from the left''' self.write_bit(18, 5, enabled) def set_segment_colon_bottom_right(self, enabled): '''Set 2nd : segment at the bottom from the left''' self.write_bit(13, 1, enabled) def top_right(self, value): '''Display value to the top rigth corner of the screen''' startAddr = 14 if (int(value) <= 99): self.write_digit(startAddr, value) self.refresh() return True else: return False def middle(self, value): '''Display value to the middle of the screen''' startAddr = 10 if (int(value) <= 999): self.write_digit(startAddr, value) self.refresh() return True elif (int(value) > 999 & int(value) <= 1999): self.set_segment_middle_1(True) self.write_digit(startAddr, value) self.refresh() else: return False def bottom_right(self, value): '''Display value to the bottom right corner of the screen''' startAddr = 17 if (int(value) <= 399): self.write_digit(startAddr, value) self.refrsh() return True else: return False def top_left(self, value): '''Display value to the top left corner of the screen''' startAddr = 0 if (int(value) <= 99999): self.write_digit(startAddr, value) self.refresh() return True else: return False def bottom_left(self, value): '''Display value to the bottom left corner of the screen''' startAddr = 5 if (int(value) <= 99999): self.write_digit(startAddr, value) self.refresh() return True else: return False def refresh(self): '''Push buffer content to device RAM at once for display''' # Do nothing special execpt avoiding an I2C communication error self.bus.write_byte(self.defaultAddr, 0b01100000) self.bus.write_i2c_block_data(self.defaultAddr, 0, self.buffer) # Do nothing special execpt avoiding an I2C communication error self.bus.write_byte(self.defaultAddr, 0b01100000) def clear(self): '''Clear screen''' self.buffer = [0 for x in xrange(20)] self.refresh() def display_all(self): '''Display all possible character on the screen''' self.buffer = [255 for x in xrange(20)] self.refresh() def loop(self): self.bus.write_byte_data(self.defaultAddr, 0, 255) for x in range(2, 40, 2): self.bus.write_byte_data(self.defaultAddr, x - 2, 0) self.bus.write_byte_data(self.defaultAddr, x, 255) sleep(1) if (x > 36): self.bus.write_byte(self.defaultAddr, 0b01100000)
def _readBytePMBus(self, cmd, pecByte=True): bus = SMBus(self.busID) bus.pec = pecByte data = bus.read_byte_data(self.address, cmd) bus.close() return data
def sigint_handle(signal_recieved, frame): running = False signal(SIGINT, sigint_handle) # Create I2C bus bus = SMBus(1) INIT_SIGNAL = 0x01 #init signal fori2c while (running): # NOTE: May need to move [D040] <= 0x06 inside the loop here, but I don't think you do sleep(SENSOR_MEASUREMENT_WAIT_TIME) # Tell the sensor we want to read the flow value [D051/D052] => Read Compensated Flow value answer = bus.read_word_data(PRESSURE_SENSOR_ADDRESS, INIT_SIGNAL) #bit shift to get the full value answer = float((((answer & 0x00FF) << 8) + ((answer & 0xFF00) >> 8))) pressure = (answer - SENSOR_COUNT_MIN) * ( SENSOR_PRESSURE_MAX - SENSOR_PRESSURE_MIN) / ( SENSOR_COUNT_MAX - SENSOR_COUNT_MIN) + SENSOR_PRESSURE_MIN # Output for the user print(f"Sensor Reading {pressure:.3f} psi" + " " * 20, end='\r') print("Exiting program...") bus.close()
def _writeBytePMBus(self, cmd, byte, pecByte=True): bus = SMBus(self.busID) bus.pec = pecByte bus.write_byte_data(self.address, cmd, byte) bus.close()
def _writeWordPMBus(self, cmd, word, pecByte=True): bus = SMBus(self.busID) bus.pec = pecByte bus.write_word_data(self.address, cmd, word) bus.close()
def getCurrent(self): bus = SMBus(1) self.current = self._decodePMBus(self._readWordPMBus(0x8C)) bus.close() return self.current
class BerryIMUClient(object): """Client for using the BerryIMU from Python. Settings can be applied by sending in a dict at initialisation. The following keys and corresponding valid values govern the settings, where values in <> denotes default values. Accelerometer: * 'data_rate' [0, 3.125, 6.25, 12.5, 25, 50, 100, <200>, 400, 800, 1600] * 'continuous_update': [True, <False>], * 'enabled_x': [<True>, False], * 'enabled_y': [<True>, False], * 'enabled_z': [<True>, False], * 'anti_alias': [<773>, 194, 362, 50], * 'full_scale': [2, 4, 6, <8>, 16], * 'self_test': [<0>, 1, -1, 'X'] Gyroscope: * 'data_rate' [95, <190>, 380, 760] * 'bandwidth_level': [<0>, 1, 2, 3], * 'powerdown_mode': [True, <False>], * 'enabled_x': [<True>, False], * 'enabled_y': [<True>, False], * 'enabled_z': [<True>, False], * 'continuous_update': [True, <False>], * 'little_endian': [True, <False>], * 'full_scale': [245, <500>, 2000], * 'self_test': [<0>, 1, -1] Magnetometer: * 'data_rate' [3.125, 6.25, 12.5, 25, <50>, 100] * 'full_scale': [2, 4, 8, <12>], * 'sensor_mode': [<0>, 1, -1] * 'lowpower_mode': [True, <False>], * 'high_resolution': [<True>, False], * 'enabled_temp': [<True>, False] Read more about these settings in the `LSM9DS0 data sheet <http://ozzmaker.com/wp-content/uploads/2014/12/LSM9DS0.pdf>`_. For the barometric pressure sensor BMP180, docstring will be written. `BMP180 data sheet <http://ozzmaker.com/wp-content/uploads/2015/01/BMP180-DS000-09.pdf>`_ """ def __init__(self, bus=1, settings=None): """Constructor for BerryIMUClient""" self._bus = None self._calibration_object = BerryIMUCalibration() # Init time settings. self._bus_no = bus self._acc_setup = self._create_accelerometer_settings_dict( settings.get('accelerometer', {}) if settings is not None else {}) self._gyro_setup = self._create_gyroscope_settings_dict( settings.get('gyroscope', {}) if settings is not None else {}) self._mag_setup = self._create_magnetometer_settings_dict( settings.get('magnetometer', {}) if settings is not None else {}) # BMP180 calibration values. self.__ac1 = None self.__ac2 = None self.__ac3 = None self.__ac4 = None self.__ac5 = None self.__ac6 = None self.__b1 = None self.__b2 = None self.__mb = None self.__mc = None self.__md = None @property def bus(self): if self._bus is not None: return self._bus else: self.open() return self.bus @property def calibration_object(self): return self._calibration_object @calibration_object.setter def calibration_object(self, new_calibration): # TODO: Check if calibration and current client share vital settings such as full scales. self._calibration_object = new_calibration def open(self): try: self._bus = SMBus(self._bus_no) except IOError as e: if str(e) == '2': raise PyBerryIMUError("/dev/i2c-{0} not found. (IOError 2)".format(self._bus_no)) elif str(e) == '5': raise PyBerryIMUError("I2C Input/Output error. (IOError 5)".format(self._bus_no)) elif str(e) == '13': raise PyBerryIMUError("Permission to read and/or write to " "/dev/i2c-{0} missing. (IOError 13)".format(self._bus_no)) else: raise PyBerryIMUError('Unhandled IOError: {0}'.format(e)) except Exception as e: raise PyBerryIMUError('Unhandled {0}: {1}'.format(type(e), e)) else: self._init_accelerometer() self._init_gyroscope() self._init_magnetometer() self._init_barometric_pressure_sensor() def close(self): if self._bus is not None: try: self._bus.close() except Exception as e: # TODO: Test what errors can occur and handle these better. print("Exception at closing of i2c bus: {0}".format(e)) def __enter__(self): self.open() return self def __exit__(self, exc_type, exc_val, exc_tb): self.close() # Initialisation methods def _create_accelerometer_settings_dict(self, setup_dict): return { 'data_rate': setup_dict.get('data_rate', 200), 'continuous_update': setup_dict.get('continuous_update', False), 'enabled_z': setup_dict.get('enabled_z', True), 'enabled_y': setup_dict.get('enabled_y', True), 'enabled_x': setup_dict.get('enabled_x', True), 'anti_alias': setup_dict.get('anti_alias', 773), 'full_scale': setup_dict.get('full_scale', 8), 'self_test': setup_dict.get('self_test', 0) } def _init_accelerometer(self): """Initialize the accelerometer according to the settings document sent in.""" # TODO: Better init handling! reg1_value = ( LSM9DS0.get_accelerometer_data_rate_bits(self._acc_setup.get('data_rate')) + ('0' if self._acc_setup.get('continuous_update') else '1') + ('1' if self._acc_setup.get('enabled_z') else '0') + ('1' if self._acc_setup.get('enabled_y') else '0') + ('1' if self._acc_setup.get('enabled_x') else '0') ) # Write data rate, enabled axes and block data update. self._write(LSM9DS0.ACC_ADDRESS, LSM9DS0.CTRL_REG1_XM, int(reg1_value, 2)) reg2_value = ( LSM9DS0.get_accelerometer_anti_alias_filter_bits(self._acc_setup.get('anti_alias')) + LSM9DS0.get_accelerometer_full_scale_bits(self._acc_setup.get('full_scale')) + LSM9DS0.get_accelerometer_self_test_bits(self._acc_setup.get('self_test')) + '0' # SPI Serial Interface Mode selection ) # Write anti-alias filter bandwidth, acceleration full scale and self-test mode. self._write(LSM9DS0.ACC_ADDRESS, LSM9DS0.CTRL_REG2_XM, int(reg2_value, 2)) def _create_gyroscope_settings_dict(self, setup_dict): return { 'data_rate': setup_dict.get('data_rate', 190), 'bandwidth_level': setup_dict.get('bandwidth_level', 0), 'powerdown_mode': setup_dict.get('powerdown_mode', False), 'enabled_z': setup_dict.get('enabled_z', True), 'enabled_y': setup_dict.get('enabled_y', True), 'enabled_x': setup_dict.get('enabled_x', True), 'continuous_update': setup_dict.get('continuous_update', False), 'little_endian': setup_dict.get('little_endian', False), 'full_scale': setup_dict.get('full_scale', 500), 'self_test': setup_dict.get('self_test', 0) } def _init_gyroscope(self): """Initialize the gyroscope according to the settings document sent in.""" # TODO: Better init handling! reg1_value = ( LSM9DS0.get_gyroscope_data_rate_bits(self._gyro_setup.get('data_rate')) + LSM9DS0.get_gyroscope_bandwidth_bits(self._gyro_setup.get('bandwidth_level')) + ('0' if self._gyro_setup.get('powerdown_mode') else '1') + ('1' if self._gyro_setup.get('enabled_z') else '0') + ('1' if self._gyro_setup.get('enabled_y') else '0') + ('1' if self._gyro_setup.get('enabled_x') else '0') ) self._write(LSM9DS0.GYR_ADDRESS, LSM9DS0.CTRL_REG1_G, int(reg1_value, 2)) # TODO: Add setup for high-pass filter, LSM9DS0.CTRL_REG2_G and LSM9DS0.CTRL_REG5_G reg4_value = ( ('0' if self._gyro_setup.get('continuous_update') else '1') + ('1' if self._gyro_setup.get('little_endian') else '0') + LSM9DS0.get_gyroscope_full_scale_bits(self._gyro_setup.get('full_scale')) + '0' + # Unused bit. LSM9DS0.get_gyroscope_self_test_bits(self._gyro_setup.get('self_test')) + '0' # SPI Serial Interface Mode selection ) self._write(LSM9DS0.GYR_ADDRESS, LSM9DS0.CTRL_REG4_G, int(reg4_value, 2)) def _create_magnetometer_settings_dict(self, setup_dict): return { 'enabled_temp': setup_dict.get('enabled_temp', True), 'data_rate': setup_dict.get('data_rate', 50), 'full_scale': setup_dict.get('full_scale', 12), 'sensor_mode': setup_dict.get('sensor_mode', 0), 'lowpower_mode': setup_dict.get('lowpower_mode', False), 'high_resolution': setup_dict.get('high_resolution', True) } def _init_magnetometer(self): """Initialize the magnetometer according to the settings document sent in.""" reg5_value = ( ('1' if self._mag_setup.get('enabled_temp') else '0') + ('11' if self._mag_setup.get('high_resolution') else '00') + LSM9DS0.get_magnetometer_data_rate_bits(self._mag_setup.get('data_rate')) + '00' # Latch interrupts disabled right. ) self._write(LSM9DS0.MAG_ADDRESS, LSM9DS0.CTRL_REG5_XM, int(reg5_value, 2)) reg6_value = ( '0' + # Unused bits LSM9DS0.get_magnetometer_full_scale_bits(self._mag_setup.get('full_scale')) + '00000' # Unused bits ) self._write(LSM9DS0.MAG_ADDRESS, LSM9DS0.CTRL_REG6_XM, int(reg6_value, 2)) reg7_value = ( '00' + # Accelerometer high-pass filter disabled. '0' + # Filtered acceleration data selection bypassed. '00' + # Unused bits ('1' if self._mag_setup.get('lowpower_mode') else '0') + LSM9DS0.get_magnetometer_sensor_mode_bits(self._mag_setup.get('sensor_mode')) ) self._write(LSM9DS0.MAG_ADDRESS, LSM9DS0.CTRL_REG7_XM, int(reg7_value, 2)) def _init_barometric_pressure_sensor(self): """Initialize the Barometric Pressure Sensor.""" self._set_bmp180_calibration_values() # TODO: Better init handling! self.__OVERSAMPLING = 3 # 0..3 def get_settings(self): settings = { 'accelerometer': { 'reg1': "{0:08b}".format(self.bus.read_byte_data(LSM9DS0.ACC_ADDRESS, LSM9DS0.CTRL_REG1_XM)), 'reg2': "{0:08b}".format(self.bus.read_byte_data(LSM9DS0.ACC_ADDRESS, LSM9DS0.CTRL_REG2_XM)), }, 'gyroscope': { 'reg1': "{0:08b}".format(self.bus.read_byte_data(LSM9DS0.GYR_ADDRESS, LSM9DS0.CTRL_REG1_G)), 'reg4': "{0:08b}".format(self.bus.read_byte_data(LSM9DS0.GYR_ADDRESS, LSM9DS0.CTRL_REG4_G)), }, 'magnetometer': { 'reg5': "{0:08b}".format(self.bus.read_byte_data(LSM9DS0.MAG_ADDRESS, LSM9DS0.CTRL_REG5_XM)), 'reg6': "{0:08b}".format(self.bus.read_byte_data(LSM9DS0.MAG_ADDRESS, LSM9DS0.CTRL_REG6_XM)), 'reg7': "{0:08b}".format(self.bus.read_byte_data(LSM9DS0.MAG_ADDRESS, LSM9DS0.CTRL_REG7_XM)), } } settings['accelerometer'].update(self._acc_setup) settings['gyroscope'].update(self._gyro_setup) settings['magnetometer'].update(self._mag_setup) return settings # BMP180 specific methods. def get_bmp180_chip_id_and_version(self): """Gets Chip ID and version for the BMP180 sensor. :return: Chip ID and Version number :rtype: tuple """ return self.bus.read_i2c_block_data(BMP180.ADDRESS, BMP180.CHIP_ID_REG, 2) def _set_bmp180_calibration_values(self): """Read, parse and store calibration EEPROM data to attributes.""" bmp180_calibration = self.bus.read_i2c_block_data(BMP180.ADDRESS, BMP180.CALIB_DATA_REG, 22) vals = [msb + lsb for msb, lsb in zip(map(lambda x: x << 8, bmp180_calibration[::2]), bmp180_calibration[1::2])] for i in [0, 1, 2, 6, 7, 8, 9, 10]: if vals[i] > 2 ** 15 - 1: vals[i] -= 2 ** 16 self.__ac1 = vals[0] self.__ac2 = vals[1] self.__ac3 = vals[2] self.__ac4 = vals[3] self.__ac5 = vals[4] self.__ac6 = vals[5] self.__b1 = vals[6] self.__b2 = vals[7] self.__mb = vals[8] self.__mc = vals[9] self.__md = vals[10] # Methods for writing to BerryIMU. def _write(self, address, register, value): self.bus.write_byte_data(address, register, value) return -1 # Methods for reading from BerryIMU. def _read(self, address, register_low_bit, register_high_bit): value = (self.bus.read_byte_data(address, register_low_bit) | (self.bus.read_byte_data(address, register_high_bit) << 8)) return value if value < 32768 else value - 65536 @property def timestamp(self): """Timestamp right now Epoch time. :return: Epoch timestamp :rtype: float """ # TODO: Make timezone independent... return time.time() def read_accelerometer(self): """Method for reading values from the accelerometer. :return: The X, Y, and Z values of the accelerometer. :rtype: tuple """ return self.calibration_object.transform_accelerometer_values( (self._read(LSM9DS0.ACC_ADDRESS, LSM9DS0.OUT_X_L_A, LSM9DS0.OUT_X_H_A), self._read(LSM9DS0.ACC_ADDRESS, LSM9DS0.OUT_Y_L_A, LSM9DS0.OUT_Y_H_A), self._read(LSM9DS0.ACC_ADDRESS, LSM9DS0.OUT_Z_L_A, LSM9DS0.OUT_Z_H_A))) def read_gyroscope(self): """Method for reading values from the gyroscope. :return: The X, Y, and Z values of the gyroscope. :rtype: tuple """ return self.calibration_object.transform_gyroscope_values( (self._read(LSM9DS0.GYR_ADDRESS, LSM9DS0.OUT_X_L_G, LSM9DS0.OUT_X_H_G), self._read(LSM9DS0.GYR_ADDRESS, LSM9DS0.OUT_Y_L_G, LSM9DS0.OUT_Y_H_G), self._read(LSM9DS0.GYR_ADDRESS, LSM9DS0.OUT_Z_L_G, LSM9DS0.OUT_Z_H_G))) def read_magnetometer(self): """Method for reading values from the magnetometer. :return: The X, Y, and Z values of the magnetometer. :rtype: tuple """ return self.calibration_object.transform_magnetometer_values( (self._read(LSM9DS0.MAG_ADDRESS, LSM9DS0.OUT_X_L_M, LSM9DS0.OUT_X_H_M), self._read(LSM9DS0.MAG_ADDRESS, LSM9DS0.OUT_Y_L_M, LSM9DS0.OUT_Y_H_M), self._read(LSM9DS0.MAG_ADDRESS, LSM9DS0.OUT_Z_L_M, LSM9DS0.OUT_Z_H_M))) def read_temperature_LSM9DS0(self): """Method for reading temperature values from the LSM9DS0 chip. Temperature value is stored as a 12-bit, right justified value, hence the bit mask on the high bit. :return: Temperature value. :rtype: int """ value = (self.bus.read_byte_data(LSM9DS0.MAG_ADDRESS, LSM9DS0.OUT_TEMP_L_XM) | ( (self.bus.read_byte_data(LSM9DS0.MAG_ADDRESS, LSM9DS0.OUT_TEMP_H_XM) & 0b00001111) << 8)) value = value if value < 2048 else value - 4096 # Convert to degrees Celsius according to data sheet specs: 8 LSB/deg C return value / 8 def read_temperature(self): """Method for reading temperature values from the barometric pressure sensor. Reference for reading to temperature calculations: `BMP180 reference sheet <http://ozzmaker.com/wp-content/uploads/2015/01/BMP180-DS000-09.pdf>`_ :return: The temperature value. :rtype: int """ self._write(BMP180.ADDRESS, BMP180.WRITE_REG, 0x2E) time.sleep(0.005) msb, lsb = self.bus.read_i2c_block_data(BMP180.ADDRESS, BMP180.READ_REG, 2) ut = (msb << 8) + lsb x1 = ((ut - self.__ac6) * self.__ac5) >> 15 x2 = (self.__mc << 11) // (x1 + self.__md) b5 = x1 + x2 t = (b5 + 8) >> 4 return t / 10.0 def read_pressure(self): """Method for reading pressure value from the barometric pressure sensor. Reference for reading to pressure calculations: `BMP180 reference sheet <http://ozzmaker.com/wp-content/uploads/2015/01/BMP180-DS000-09.pdf>`_ :return: The pressure value. :rtype: int """ self._write(BMP180.ADDRESS, BMP180.WRITE_REG, 0x2E) time.sleep(0.005) msb, lsb = self.bus.read_i2c_block_data(BMP180.ADDRESS, BMP180.READ_REG, 2) ut = (msb << 8) + lsb self._write(BMP180.ADDRESS, BMP180.WRITE_REG, 0x34 + (self.__OVERSAMPLING << 6)) time.sleep(0.04) msb, lsb, xsb = self.bus.read_i2c_block_data(BMP180.ADDRESS, BMP180.READ_REG, 3) up = ((msb << 16) + (lsb << 8) + xsb) >> (8 - self.__OVERSAMPLING) x1 = ((ut - self.__ac6) * self.__ac5) >> 15 x2 = (self.__mc << 11) // (x1 + self.__md) b5 = x1 + x2 b6 = b5 - 4000 b62 = b6 * b6 >> 12 x1 = (self.__b2 * b62) >> 11 x2 = self.__ac2 * b6 >> 11 x3 = x1 + x2 b3 = (((self.__ac1 * 4 + x3) << self.__OVERSAMPLING) + 2) >> 2 x1 = self.__ac3 * b6 >> 13 x2 = (self.__b1 * b62) >> 16 x3 = ((x1 + x2) + 2) >> 2 b4 = (self.__ac4 * (x3 + 32768)) >> 15 b7 = (up - b3) * (50000 >> self.__OVERSAMPLING) p = (b7 * 2) // b4 x1 = (p >> 8) * (p >> 8) x1 = (x1 * 3038) >> 16 x2 = (-7357 * p) >> 16 p += (x1 + x2 + 3791) >> 4 return p / 100.0
class Lcd: # Modes MODE_4BIT = 0x00 MODE_8BIT = 0x10 # Commands FUNCTION_SET = 0x20 DISPLAY = 0x08 CLEAR = 0x01 ENTRY_MODE = 0x04 # Function set LINES_1 = 0x00 LINES_2 = 0x08 FONT_5x8 = 0x00 FONT_5x10 = 0x04 # Display DISPLAY_ON = 0x04 DISPLAY_OFF = 0x00 CURSOR_ON = 0x02 CURSOR_OFF = 0x00 BLINK_ON = 0x01 BLINK_OFF = 0x00 # Entry mode ENTRY_RIGHT = 0x00 ENTRY_LEFT = 0x02 ENTRY_SHIFT_INCREMENT = 0x01 ENTRY_SHIFT_DECREMENT = 0x00 # Data modes COMMAND = 0 # Enable bit ENABLE = 0b00000100 # Backlight BACKLIGHT_OFF = 0x00 BACKLIGHT_ON = 0x08 # Timing MS_5 = 0.005 MS_60 = 0.06 US_160 = 0.00016 CLEAR_TIME = 2 # Constructor def __init__(self, address = 0x27, bus = 1, lines = 2, font = 0): self.address = address self.bus = bus self.lines = self.LINES_1 if lines < 2 else self.LINES_2 self.mode = self.MODE_8BIT self.font = font self.backlight_state = self.BACKLIGHT_OFF print 'Addess: %s' % hex(self.address) print 'Lines: %s' % hex(self.lines) print 'Font: %s' % hex(self.font) print 'Bus: %s' % self.bus print 'Backlight state: %s' % hex(self.backlight_state) self.open() self.__initialize() # Open bus def open(self): print 'Open bus connection to %s' % self.bus self.bus = SMBus(self.bus) # Close bus def close(self): print 'Close bus connection' self.bus.close() # Run the command def command(self, command): print 'Running command %s' % hex(command) self.__send(command, self.COMMAND) # Clear def clear(self): print 'Clearing' self.command(self.CLEAR) time.sleep(self.CLEAR_TIME) # Turn backlight on def backlight_on(self): print 'Turn backlight on' self.backlight_state = self.BACKLIGHT_ON self.command(self.BACKLIGHT_ON) # Initialize LCD in 4 bit mode. We are in 8 bit mode until we # switch to 4 bit mode def __initialize(self): print 'Initializing LCD' # In 8 bit mode self.__send(0x3) time.sleep(self.MS_5) self.__send(0x3) time.sleep(self.US_160) self.__send(0x3) time.sleep(self.US_160) self.__send(0x2) # This enables 4 bit mode time.sleep(self.US_160) # We are now in 4 bit mode print '4 bit mode enabled' self.mode = self.MODE_4BIT # Function set self.__send(self.FUNCTION_SET | self.mode | self.lines | self.font) time.sleep(self.MS_60) print 'Function set' # Turn display on with no cursor or blinking self.__configure_display(self.DISPLAY_ON | self.CURSOR_OFF | self.BLINK_OFF) # Clear display self.clear() # Set default text direction self.__configure_entry_mode(self.ENTRY_LEFT | self.ENTRY_SHIFT_DECREMENT) # Backlight on self.backlight_on() # Configure display def __configure_display(self, flags): print 'Configuring display' print 'Flags: %s' % self.__to_byte(flags) self.__send(self.DISPLAY | flags) # Configure entry mode def __configure_entry_mode(self, flags): print 'Configuring entry mode' print 'Flags: %s' % self.__to_byte(flags) self.__send(self.ENTRY_MODE | flags) # Send data to LCD def __send(self, data, mode = 0): print 'Sending data: %s' % hex(data) print 'Byte: %s' % self.__to_byte(data) if (self.mode == self.MODE_8BIT): print 'In 8 bit mode' self.__write_4(mode | (data & 0x0F)) else: print 'In 4 bit mode' self.__write_4(mode | (data >> 4)) self.__write_4(mode | (data & 0x0F)) # Write 4 bits def __write_4(self, data): data = data | self.backlight_state print 'Writing 4 bits: %s' % self.__to_nibble(data) self.__pulse_enable(data) # Pulse enable def __pulse_enable(self, data): print 'Pulsing enable' data = data | self.ENABLE print 'ENABLE: %s' % self.__to_nibble(data) self.__i2c_write_byte(data) data = data & ~self.ENABLE print 'DISABLE: %s' % self.__to_nibble(data) self.__i2c_write_byte(data) # I2C write byte def __i2c_write_byte(self, data): print 'Writing %s to bus' % self.__to_byte(data) # Convert to 4 bit string def __to_nibble(self, val): return bin(val)[2:].zfill(4) # Convert to 8 bit string def __to_byte(self, val): return bin(val)[2:].zfill(8)