コード例 #1
0
def setup(i2c_bus=1, i2c_addr=0x20, bits=24, read_mode=False, invert=False):
    """Set up the IO expander devices."""
    global _I2C_ADDR
    global _BITS
    global _BUS
    global _PORT_VALUE
    global _READMODE
    global _INVERT
    _I2C_ADDR = i2c_addr
    _BITS = bits
    _READMODE = read_mode
    _INVERT = invert
    # Make 8-bits (can be 2- or 4-bits, but should always pack in a 8-bit msg)
    while bits % 8:
        bits += 1
    # Increase array size
    _PORT_VALUE = [0xFF] * int(bits / 8)
    # Set up I2C bus connectivity
    _BUS = SMBus(i2c_bus)
    # Write 1 to all pins to prepaire them for reading, or bring hardware in a defined state
    msg = i2c_msg.write(_I2C_ADDR, _PORT_VALUE)
    if _BUS:
        _BUS.i2c_rdwr(msg)
    else:
        raise ReferenceError(
            "I2C bus was not created, please check I2C address!")
    # If in read mode: do first hw read to have memory ready
    if read_mode:
        hw_to_memory()
コード例 #2
0
ファイル: Sensor1.py プロジェクト: bankaboy/TechnocratsIRC
class Sensor:
    def __init__(self):
        self.SENSOR_DEVICE_ADDRESS = 0x0d
        self.SENSOR_BYTES = 20
        self.I2C_MODE = 2
        self.bus = SMBus(self.I2C_MODE)
        self.msg = i2c_msg.read(self.SENSOR_DEVICE_ADDRESS, self.SENSOR_BYTES)
        self.sensorIndex = {
            'uv': [2],
            'temp': [4, 5],
            'pressure': [8, 9, 10, 11],
            'atmtemp': [8, 9, 10, 11],
            'humidity': [8, 9, 10, 11]
        }

    def parseMsg(self, msg):
        return [hex(i) for i in list(msg)]

    def getAllSensorValue(self):
        self.bus.i2c_rdwr(self.msg)
        return parseMsg(self.msg)

    def getSensorValue(self, sensor):
        sensorValues = self.getAllSensorValue()
        bytesRequired = []
        for i in self.sensorIndex[sensor]:
            bytesRequired.append(sensorValues[i])
        return bytesRequired
コード例 #3
0
class DSPI2C:
    def __init__(self, i2c_addr: int, i2c_bus: int = 1):
        self.i2c_addr = i2c_addr
        self.bus = SMBus(i2c_bus)

    def readReg(self,
                reg_addr: int,
                num_bytes: int = 1) -> Union[int, List[int]]:
        msg_wr = i2c_msg.write(self.i2c_addr, wordToBytes(reg_addr))
        msg_rd = i2c_msg.read(self.i2c_addr, num_bytes)
        self.bus.i2c_rdwr(msg_wr, msg_rd)
        rd_list = list(msg_rd)
        return rd_list[0] if len(rd_list) == 1 else rd_list

    def writeReg(self, reg_addr: int, data: Union[int, List[int]]) -> None:
        if isinstance(data, int):
            data = [data]
        wr_content = wordToBytes(reg_addr)
        wr_content.extend(data)
        msg_wr = i2c_msg.write(self.i2c_addr, wr_content)
        self.bus.i2c_rdwr(msg_wr)

    def showReg(self, reg_addr: int, length: int = 1) -> None:
        reg_values = self.readReg(reg_addr, length)
        for line in formatReg(reg_addr, reg_values):
            print(line)
コード例 #4
0
ファイル: sgp30.py プロジェクト: crHARPER/Pi_i2c_EnviroSens
    def get_version(self):
        info = 99999
        try:
            bus = SMBus(I2CBUS)
            bus.write_byte_data(self.I2Caddr, SGP30_MSB, SGP30_GET_VERSION)
            time.sleep(0.01)
            #resp = bus.read_i2c_block_data( self.I2Caddr, 0, 3 )
            read = i2c_msg.read(self.I2Caddr, 3)
            bus.i2c_rdwr(read)
            resp = list(read)
            bus.close()

            if (self.crc8(resp) == 0):
                print "sgp30.get_version() Feature Set Type: 0x%02x Version: 0x%02x" % (
                    resp[0], resp[1])

                info = (resp[0] << 8) | resp[1]

                #log Feature & Version Info
                f = open(self.FptrVer, "w")
                f.write("%d" % info)
                f.close()

        except:
            bus.close()
            print "spg30.get_version() failed"

        return info
コード例 #5
0
class HwRpiI2cHw(HwI2cHalMlx90632):
    support_buffer = False
    pass

    def __init__(self, channel=1):
        if isinstance(channel, str) and channel.startswith("I2C-"):
            channel = int(channel[4:])

        if channel == 1 and platform.machine().startswith('armv'):
            os.system('raspi-gpio set 2 a0')
            os.system('raspi-gpio set 3 a0')
        self.i2c = SMBus(channel)

    def connect(self):
        pass

    def disconnect(self):
        pass

    def i2c_read(self, i2c_addr, addr, count=1, unpack_format='H'):
        addr_msb = addr >> 8 & 0x00FF
        addr_lsb = addr & 0x00FF

        write = i2c_msg.write(i2c_addr, [addr_msb, addr_lsb])
        read = i2c_msg.read(i2c_addr, count * 2)
        self.i2c.i2c_rdwr(write, read)

        if unpack_format is None:
            return bytes(list(read))
        results = struct.unpack(">{}{}".format(count, unpack_format),
                                bytes(list(read)))
        if count == 1:
            return results[0]
        return results

    def i2c_write(self, i2c_addr, addr, data):
        cmd = []
        reg_msb = addr >> 8
        cmd.append(addr & 0x00FF)

        if type(data) is list:
            for d in data:
                cmd.append((d >> 8) & 0x00FF)
                cmd.append(d & 0x00FF)
        else:
            cmd.append((data >> 8) & 0x00FF)
            cmd.append(data & 0x00FF)
        # print(reg_msb, cmd)
        self.i2c.write_i2c_block_data(i2c_addr, reg_msb, cmd)

        if (addr & 0xFF00) == 0x2400:  # Wait after EEWRITE!
            time.sleep(0.010)  # 10ms

        return 0

    def get_hardware_id(self):
        return "Raspberry Pi I2C Hardware"
コード例 #6
0
    def task(self):

        co2_val = 99999

        try:

            bus = SMBus(I2CBUS)
            write = i2c_msg.write(self.I2Caddr, K30_MSG)
            bus.i2c_rdwr(write)
            time.sleep(0.02)
            read = i2c_msg.read(self.I2Caddr, 4)
            bus.i2c_rdwr(read)
            resp = list(read)
            bus.close()
            #print resp

            cs = resp[0] + resp[1] + resp[2]
            cs &= 0xff

            # check checksum
            if cs == resp[3]:
                co2_val = (resp[1] << 8) | resp[2]
                # sensor provides signed int
                if co2_val < 32767 and co2_val > 100:

                    # read of i2c co2 value passes muster
                    # include it in the rolling average
                    self.co2_buff[self.co2_ptr] = co2_val
                    self.co2_ptr += 1
                    if self.co2_ptr >= CO2_MAX:
                        self.co2_ptr = 0

                    co2_avg = 0
                    for i in range(CO2_MAX):
                        co2_avg += self.co2_buff[i]
                    co2_avg /= CO2_MAX

                    #print "CO2: %d" % co2_avg
                    f = open(self.FptrCO2, "w")
                    f.write("%d" % co2_avg)
                    f.close()

        except:
            bus.close()
            print "k30.task() failed"

        return co2_val
コード例 #7
0
ファイル: sgp30.py プロジェクト: crHARPER/Pi_i2c_EnviroSens
    def get_sid(self):
        sid = 99999
        try:
            info = [0xffff] * 3
            test = 0

            bus = SMBus(I2CBUS)
            bus.write_byte_data(self.I2Caddr, SGP30_SID_MSB, SGP30_SID_LSB)
            time.sleep(0.01)
            #resp = bus.read_i2c_block_data( self.I2Caddr, 0, 9 )
            read = i2c_msg.read(self.I2Caddr, 9)
            bus.i2c_rdwr(read)
            resp = list(read)
            bus.close()

            sid_1 = [resp[0], resp[1], resp[2]]
            sid_2 = [resp[3], resp[4], resp[5]]
            sid_3 = [resp[6], resp[7], resp[8]]

            if (self.crc8(sid_1) == 0):
                info[0] = (sid_1[0] << 8) | sid_1[1]
                test += 1

            if (self.crc8(sid_2) == 0):
                info[1] = (sid_2[0] << 8) | sid_2[1]
                test += 1

            if (self.crc8(sid_3) == 0):
                info[2] = (sid_3[0] << 8) | sid_3[1]
                test += 1

            if test == 3:
                sid = (info[0] << 32) | (info[1] << 16) | info[2]
                print "sgp30.get_sid(): 0x%012x" % (sid)

                #log Serial ID
                f = open(self.FptrSID, "w")
                f.write("%d" % sid)
                f.close()
            else:
                print "sgp30.get_sid(): CRC error"

        except:
            bus.close()
            print "sgp30.get_sid() failed"

        return sid
コード例 #8
0
def sendSlot(rooms):
    bus = SMBus(1)
    prev_lot = int(rooms[0]['slot']/22)
    i=0
    j=0
    while (i < len(rooms)):
        while (j < len(rooms)):
            r = rooms[j]
            j+=1
            lot = int(r['slot']/22)
            if lot > prev_lot:
                break
            bus.i2c_rdwr(i2c_msg.write(getAddress(lot), [r['slot'] % 22]))
            time.sleep(0.01)
            print(r['slot'], end=' ')
        prev_lot = lot
        i=j
        bus.i2c_rdwr(i2c_msg.write(getAddress(prev_lot), [255]))
        print('')
コード例 #9
0
class HwRpiI2cHw(HwI2cHalMlx90640):
    support_buffer = False
    pass

    def __init__(self, channel=1):
        if isinstance(channel, str) and channel.startswith("I2C-"):
            channel = int(channel[4:])

        if channel == 1 and platform.machine().startswith('armv'):
            os.system('raspi-gpio set 2 a0')
            os.system('raspi-gpio set 3 a0')
        self.i2c = SMBus(channel)

    def connect(self):
        pass

    def i2c_read(self, i2c_addr, addr, count=2):
        addr_msb = addr >> 8 & 0x00FF
        addr_lsb = addr & 0x00FF

        write = i2c_msg.write(i2c_addr, [addr_msb, addr_lsb])
        read = i2c_msg.read(i2c_addr, count)
        self.i2c.i2c_rdwr(write, read)
        return bytes(list(read)), 0

    def i2c_write(self, i2c_addr, addr, data):
        cmd = []
        reg_msb = addr >> 8
        cmd.append(addr & 0x00FF)

        for d in data:
            cmd.append(d)
        self.i2c.write_i2c_block_data(i2c_addr, reg_msb, cmd)
        return 0

    def get_hardware_id(self):
        return "Raspberry Pi I2C Hardware"
コード例 #10
0
ファイル: i2c-rdwr-test.py プロジェクト: squinard/mars-rover
def main():

    bus = SMBus(1)

    address = [0x10, 0x11]

    while True:
        for i in range(len(address)):
            message = 'j,' + str(round(random.uniform(-1, 1), 4)) + ',' + str(
                round(random.uniform(-1, 1), 4))
            print("[+]", message)
            message = list(message.encode('utf-8'))
            print("[+]", message)
            write = i2c_msg.write(address[i], message)
            read = i2c_msg.read(address[i], 16)
            print("[*] Issuing read/write")
            test = bus.i2c_rdwr(write, read)
        time.sleep(0.125)
コード例 #11
0
ファイル: MLX90640.py プロジェクト: yumamory/MLX90640-python
class MLX90640:
	
	def __init__(address=0x33):    #default 0x33
		self.address = address
		self.bus = SMBus(1)
		self.addr = address
		self.gain = self.getGain()
		self.VDD0 = 3.3
		self.DV = self.getVDD()		
		self.VDD = self.DV+self.VDD0
		self.Ta0 = 25
		self.Ta = self.getTa()
		self.emissivity = 1
		self.TGC = self.getTGC()
		self.chessNotIL = 1
		self.KsTa = self.getKsTa()
		self.KsTo1, self.KsTo2, self.KsTo3, self.KsTo4 = self.getKsTo()
		self.step, self.CT3, self.CT4 = self.getCorners()
		self.CT1 = 40
		self.CT2 = 0		
		self.alphaCorrR1 = 1/float(1+ self.KsTo1*(0-(-40)))
		self.alphaCorrR2 = 1
		self.alphaCorrR3 = 1 + self.KsTo2*(self.CT3-0)
		self.alphaCorrR4 = self.alphaCorrR3*(1+self.KsTo3*(self.CT4-self.CT3))
		
	def getRegs(self,reg,num):
		write = i2c_msg.write(self.addr,[reg>>8,reg&0xFF])
		read = i2c_msg.read(self.address,num)
		self.bus.i2c_rdwr(write, read)
		return list(read)
			
	def getRegf(self,reg):
		write = i2c_msg.write(self.addr,[reg>>8,reg&0xFF])
		read = i2c_msg.read(self.address,2)
		self.bus.i2c_rdwr(write, read)
		result = list(read)
		return (result[0]<<8)+result[1]

	def root4(self,num):
		return math.sqrt(math.sqrt(num))
		
	def getTGC(self):
		TGC = self.getRegf(0x243C) & 0x00FF
		if TGC > 127:
			TGC = TGC - 256
		
		return TGC
		
	def getVDD(self):
		Kvdd = (self.getRegf(0x2433) & 0xFF00)/256
		if Kvdd > 127:
			Kvdd = Kvdd -256
		Kvdd = Kvdd*32
		
		Vdd25 = self.getRegf(0x2433) & 0x00FF
		Vdd25 = (Vdd25-256)*32 - 8192
		
		RAM = self.getRegf(0x072A)
		if RAM > 32767:
			RAM = RAM - 65536

		DV = (RAM - Vdd25)/float(Kvdd)	
		
		return DV

	def getTa(self):
		KVptat = (self.getRegf(0x2432) & 0xFC00)/1024
		if KVptat > 31:
			KVptat = KVptat - 62
		
		KVptat = KVptat/4096.0
		
		KTptat = self.getRegf(0x2432) & 0x03FF
		if KTptat > 511:
			KTptat = KTptat - 1022
		
		KTptat = KTptat/8.0
		
		Vptat25 = self.getRegf(0x2431)
		if Vptat25 > 32767:
			Vptat25 = Vptat25 - 65536
		Vptat = self.getRegf(0x0720)
		if Vptat > 32767:
			Vptat = Vptat - 65536
		Vbe = self.getRegf(0x0700)
		if Vbe > 32767:
			Vbe = Vbe - 65536
		AlphaptatEE = (self.getRegf(0x2410) & 0xF000)/4096
		Alphaptat = (AlphaptatEE/4)+8
		Vptatart = (Vptat/float(Vptat * Alphaptat + Vbe))*262144
		
		Ta = ((Vptatart/float(1+KVptat*self.DV)-Vptat25)/float(KTptat))+self.Ta0
		return Ta

	def getGain(self):
		GAIN = self.getRegf(0x2430)
		if GAIN > 32767:
			GAIN = GAIN - 65536
		RAM = self.getRegf(0x070A)
		if RAM > 32767:
			RAM = RAM - 65536
		return GAIN/float(RAM)
				
	def pixnum(self,i,j):
		return (i-1)*32 + j

	def patternChess(self,i,j):
		pixnum = self.pixnum(i,j)
		a = (pixnum-1)/32
		b = int((pixnum-1)/32)/2
		return int(a) - int(b)*2
		
	def getKsTa(self):
		KsTaEE = (self.getRegf(0x243C) & 0xFF00) >> 256
		if KsTaEE > 127:
			KsTaEE = KsTaEE -256
		
		KsTa = KsTaEE/8192.0
		return KsTa
	
	def getKsTo(self):
		EE1 = self.getRegf(0x243D)
		EE2 = self.getRegf(0x243E)
		KsTo1 = EE1 & 0x00FF
		KsTo3 = EE2 & 0x00FF
		KsTo2 = (EE1 & 0xFF00) >> 8
		KsTo4 = (EE2 & 0xFF00) >> 8

		if KsTo1 > 127:
			KsTo1 = KsTo1 -256
		if KsTo2 > 127:
			KsTo2 = KsTo2 -256
		if KsTo3 > 127:
			KsTo3 = KsTo3 -256
		if KsTo4 > 127:
			KsTo4 = KsTo4 -256
		
		KsToScale = (self.getRegf(0x243F) & 0x000F)+8
		KsTo1 = KsTo1/float(pow(2,KsToScale))
		KsTo2 = KsTo2/float(pow(2,KsToScale))
		KsTo3 = KsTo3/float(pow(2,KsToScale))
		KsTo4 = KsTo4/float(pow(2,KsToScale))
		return KsTo1, KsTo2, KsTo3, KsTo4
		
	def getCorners(self):
		EE = self.getRegf(0x243F)
		step = ((EE & 0x3000)>>12)*10
		CT3 = ((EE & 0x00f0)>>4)*step
		CT4 = ((EE & 0x0f00)>>8)*(step+CT3)
		return step, CT3, CT4
		
	def getPixData(self,i,j):
		Offsetavg = self.getRegf(0x2411)
		if Offsetavg > 32676:
			Offsetavg = Offsetavg-65536

		scaleVal = self.getRegf(0x2410)
		OCCscaleRow = (scaleVal&0x0f00)/256
		OCCscaleCol = (scaleVal&0x00F0)/16
		OCCscaleRem = (scaleVal&0x000F)
		rowAdd = 0x2412 + ((i-1)/4)
		colAdd = 0x2418 + ((j-1)/4)
		rowMask = 0xF<<(4*((i-1)%4))
		colMask = 0xF<<(4*((j-1)%4))

		OffsetPixAdd = 0x243F+((i-1)*32)+j
		OffsetPixVal = self.getRegf(OffsetPixAdd)
		OffsetPix = (OffsetPixVal & 0xFC00)/1024
		if OffsetPix >31:
			OffsetPix = OffsetPix - 64

		OCCRow = (self.getRegf(rowAdd) & rowMask)>>(4*((i-1)%4))
		if OCCRow >7:
			OCCRow = OCCRow -16

		OCCCol = (self.getRegf(colAdd) & colMask)>>(4*((j-1)%4))
		if OCCCol > 7:
			OCCCol = OCCCol -16

		pixOffset = Offsetavg + OCCRow*pow(2,OCCscaleRow) + OCCCol*pow(2,OCCscaleCol) + OffsetPix*pow(2,OCCscaleRem)
		
		KtaEE = (OffsetPixVal & 0x000E)/2
		if KtaEE > 3:
			KtaEE = KtaEE - 7

		colEven = not (j%2)
		rowEven = not (i%2)
		rowOdd = not rowEven
		colOdd = not colEven
		KtaAvAddr = 0x2436 + (colEven)
		KtaAvMask = 0xFF00 >> (8*rowEven)
		
		KtaRC = (self.getRegf(KtaAvAddr) & KtaAvMask) >> 8* rowOdd
		if KtaRC > 127:
			KtaRC = KtaAvRC - 256
		
		KtaScale1 = ((self.getRegf(0x2438) & 0x00F0) >>4)+8
		KtaScale2 = (self.getRegf(0x2438) & 0x000F)

		Kta = (KtaRC+(KtaEE<<KtaScale2))/float(pow(2,KtaScale1))
		
		shiftNum = (rowOdd*4)+(colOdd*8)
		KvMask = 0x000F << shiftNum
		Kv = (self.getRegf(0x2434) & KvMask) >> shiftNum
		if Kv > 7:
			Kv = Kv-16
		
		KvScale = (self.getRegf(0x2438) & 0x0F00)>>8
		
		Kv = Kv/float(KvScale)
		
		RAMaddr = 0x400+((i-1)*32)+ j-1
		RAM = self.getRegf(RAMaddr)
		if RAM > 32767:
			RAM = RAM - 65536
		pixGain = RAM*self.gain
		pixOs = pixGain - pixOffset*(1+Kta*(self.Ta - self.Ta0)*(1+Kv*(self.VDD - self.VDD0)))
		return pixOs

	def getCompensatedPixData(self,i,j):
		pixOs = self.getPixData(i,j)
		Kgain = ((self.gain -1)/10)+1
		
		pixGainCPSP0 = self.getRegf(0x0708)		
		if pixGainCPSP0 > 32767:
			pixGainCPSP0 = pixGainCPSP0 - 65482
		
		pixGainCPSP1 = self.getRegf(0x0728)
		if pixGainCPSP1 > 32767:
			pixGainCPSP1 = pixGainCPSP1 - 65482
		
		pixGainCPSP0 = pixGainCPSP0*Kgain
		pixGainCPSP1 = pixGainCPSP1*Kgain
		
		OffCPSP0 = self.getRegf(0x243A) & 0x03FF
		if OffCPSP0 > 511:
			OffCPSP0 = OffCPSP0-1024
		
		OffCPSP1d = (self.getRegf(0x243A) &0xFC00)>>10
		if OffCPSP1d > 31:
			OffCPSP1d = OffCPSP1d-64
		
		OffCPSP1 = OffCPSP1d + OffCPSP0
		
		KvtaCPEEVal = self.getRegf(0x243B)
		KvtaScaleVal = self.getRegf(0x2438)
		
		KtaScale1 = ((KvtaScaleVal & 0x00F0)>>4)+8
		KvScale = (KvtaScaleVal & 0x0F00)>>8
		
		KtaCPEE = KvtaCPEEVal & 0x00FF
		if KtaCPEE > 127:
			KtaCPEE = KtaCPEE -256
		
		KvCPEE = (KvtaCPEEVal & 0xFF00)>>8
		
		KtaCP = KtaCPEE/float(pow(2,KtaScale1))
		KvCP = KvCPEE/float(pow(2,KvScale))
		
		b = (1+KtaCP*(self.Ta - self.Ta0))*(1+ KvCP*(self.VDD - self.VDD0))
		pixOSCPSP0 = pixGainCPSP0 - OffCPSP0*b
		pixOSCPSP1 = pixGainCPSP1 - OffCPSP1*b
		
		if self.chessNotIL:
			pattern = self.patternChess(i,j)
		else:
			pattern = self.patternChess(i,j)
		
		VIREmcomp = pixOs/self.emissivity
		VIRcomp = VIREmcomp - self.TGC*((1-pattern)*pixOSCPSP0 + pattern*pixOSCPSP1)
		###########TESTED TO HERE
		
		reg2439val = self.getRegf(0x2439)
		reg2420val = self.getRegf(0x2420)
		alphaScaleCP = ((reg2420val & 0xF000)>>12) + 27
		CPP1P0ratio = (reg2439val & 0xFC00)>>10
		if CPP1P0ratio >31:
			CPP1P0ratio = CPP1P0ratio -64
		
		alphaRef = self.getRegf(0x2421)
		alphaScale = ((reg2420val & 0xF000)>>12) + 30
		
		rowAdd = 0x2422 + ((i-1)/4)
		colAdd = 0x2428 + ((j-1)/4)
		rowMask = 0xF<<(4*((i-1)%4))
		colMask = 0xF<<(4*((j-1)%4))		

		ACCRow = (self.getRegf(rowAdd) & rowMask)>>(4*((i-1)%4))
		if ACCRow >7:
			ACCRow = ACCRow -16

		ACCCol = (self.getRegf(colAdd) & colMask)>>(4*((j-1)%4))
		if ACCCol > 7:
			ACCCol = ACCCol -16
		
		ACCScaleRow = (reg2420val & 0x0F00)>>8
		ACCScaleCol = (reg2420val & 0x00F0)>>4
		ACCScaleRem = (reg2420val & 0x000F)
		
		alphaPixel = (self.getRegf(0x241f+self.pixnum(i,j))&0x03f0)>>4
		
		alpha = (alphaRef+(ACCRow<<ACCScaleRow)+(ACCCol<<ACCScaleCol)+(alphaPixel<<ACCScaleRem))/float(pow(2,alphaScale))
		
		alphaCPSP0 = (reg2439val & 0x03ff)/float(pow(2,alphaScaleCP))
		alphaCPSP1 = alphaCPSP0*(1+CPP1P0ratio/128.0)
		alphacomp= alpha - self.TGC*((1-pattern)*alphaCPSP0 + pattern*alphaCPSP1)*(1+self.KsTa*(self.Ta-self.Ta0))

		Tak4 = pow(self.Ta + 273.15,4)
		Trk4 = pow(self.Ta-8 + 273.15,4)
		Tar = Trk4-(Trk4-Tak4)/self.emissivity
		Sx = self.KsTo2*self.root4(pow(alphacomp,3)*VIRcomp + pow(alphacomp,4)*Tar)
		return self.root4((VIRcomp/(alphacomp*(1-self.KsTo2*273.15)+Sx))+Tar) - 273.15
コード例 #12
0
class ADS1x15(object):
    """Base functionality for ADS1x15 analog to digital converters."""
    def __init__(self,
                 address=_ADS1X15_DEFAULT_ADDRESS,
                 gain=1,
                 data_rate=None,
                 mode=Mode.SINGLE):
        self._last_pin_read = None
        self.buf = bytearray(3)
        self._data_rate = self._gain = self._mode = None
        self.gain = gain
        self.data_rate = self._data_rate_default(
        ) if data_rate is None else data_rate
        self.mode = mode
        self.address = address
        # -----Open I2C interface:
        # self.bus = SMBus(0)  # Rev 1 Pi uses 0
        self.bus = SMBus(1)  # Rev 2 Pi uses 1

    @property
    def data_rate(self):
        """The data rate for ADC conversion in samples per second."""
        return self._data_rate

    @data_rate.setter
    def data_rate(self, rate):
        possible_rates = self.rates
        if rate not in possible_rates:
            raise ValueError(
                "Data rate must be one of: {}".format(possible_rates))
        self._data_rate = rate

    @property
    def rates(self):
        """Possible data rate settings."""
        raise NotImplementedError('Subclass must implement rates property.')

    @property
    def rate_config(self):
        """Rate configuration masks."""
        raise NotImplementedError(
            'Subclass must implement rate_config property.')

    @property
    def gain(self):
        """The ADC gain."""
        return self._gain

    @gain.setter
    def gain(self, gain):
        possible_gains = self.gains
        if gain not in possible_gains:
            raise ValueError("Gain must be one of: {}".format(possible_gains))
        self._gain = gain

    @property
    def gains(self):
        """Possible gain settings."""
        g = list(_ADS1X15_CONFIG_GAIN.keys())
        g.sort()
        return g

    @property
    def mode(self):
        """The ADC conversion mode."""
        return self._mode

    @mode.setter
    def mode(self, mode):
        if mode != Mode.CONTINUOUS and mode != Mode.SINGLE:
            raise ValueError("Unsupported mode.")
        self._mode = mode

    def read(self, pin, is_differential=False):
        """I2C Interface for ADS1x15-based ADCs reads.

        params:
            :param pin: individual or differential pin.
            :param bool is_differential: single-ended or differential read.
        """
        pin = pin if is_differential else pin + 0x04
        return self._read(pin)

    def _data_rate_default(self):
        """Retrieve the default data rate for this ADC (in samples per second).
        Should be implemented by subclasses.
        """
        raise NotImplementedError(
            'Subclasses must implement _data_rate_default!')

    def _conversion_value(self, raw_adc):
        """Subclasses should override this function that takes the 16 raw ADC
        values of a conversion result and returns a signed integer value.
        """
        raise NotImplementedError(
            'Subclass must implement _conversion_value function!')

    def _read(self, pin):
        """Perform an ADC read. Returns the signed integer result of the read."""
        if self.mode == Mode.CONTINUOUS and self._last_pin_read == pin:
            return self._conversion_value(self.get_last_result(True))
        else:
            self._last_pin_read = pin
            config = _ADS1X15_CONFIG_OS_SINGLE
            config |= (pin & 0x07) << _ADS1X15_CONFIG_MUX_OFFSET
            config |= _ADS1X15_CONFIG_GAIN[self.gain]
            config |= self.mode
            config |= self.rate_config[self.data_rate]
            config |= _ADS1X15_CONFIG_COMP_QUE_DISABLE
            self._write_register(_ADS1X15_POINTER_CONFIG, config)

            if self.mode == Mode.SINGLE:
                while not self._conversion_complete():
                    pass

            return self._conversion_value(self.get_last_result(False))

    def _conversion_complete(self):
        """Return status of ADC conversion."""
        # OS is bit 15
        # OS = 0: Device is currently performing a conversion
        # OS = 1: Device is not currently performing a conversion
        return self._read_register(_ADS1X15_POINTER_CONFIG) & 0x8000

    def get_last_result(self, fast=False):
        """Read the last conversion result when in continuous conversion mode.
        Will return a signed integer value. If fast is True, the register
        pointer is not updated as part of the read. This reduces I2C traffic
        and increases possible read rate.
        """
        return self._read_register(_ADS1X15_POINTER_CONVERSION, fast)

    def _write_register(self, reg, value):
        """Write 16 bit value to register."""
        self.buf[0] = reg
        self.buf[1] = (value >> 8) & 0xFF
        self.buf[2] = value & 0xFF
        # Write some bytes to address
        msg = i2c_msg.write(self.address,
                            [self.buf[0], self.buf[1], self.buf[2]])
        self.bus.i2c_rdwr(msg)

    def _read_register(self, reg, fast=False):
        """Read 16 bit register value. If fast is True, the pointer register
        is not updated.
        """
        if fast:
            self.buf = self.bus.read_i2c_block_data(
                80, 0, 2)  # read 16 bit (2 byte of data)
        else:
            write = i2c_msg.write(self.address, [reg])
            read = i2c_msg.read(self.address, 2)
            self.bus.i2c_rdwr(write, read)
            return ord(read.buf[0]) << 8 | ord(read.buf[1])
コード例 #13
0
ファイル: sps30.py プロジェクト: iquincoces/sps30
class SPS30():
    SPS_ADDR = 0x69

    START_MEAS   = [0x00, 0x10]
    STOP_MEAS    = [0x01, 0x04]
    R_DATA_RDY   = [0x02, 0x02]
    R_VALUES     = [0x03, 0x00]
    RW_AUTO_CLN  = [0x80, 0x04]
    START_CLN    = [0x56, 0x07]
    R_ARTICLE_CD = [0xD0, 0x25]
    R_SERIAL_NUM = [0xD0, 0x33]
    RESET        = [0xD3, 0x04]

    NO_ERROR = 1
    ARTICLE_CODE_ERROR = -1
    SERIAL_NUMBER_ERROR = -2
    AUTO_CLN_INTERVAL_ERROR = -3
    DATA_READY_FLAG_ERROR = -4
    MEASURED_VALUES_ERROR = -5

    dict_values = {"pm1p0"  : None,
                   "pm2p5"  : None,
                   "pm4p0"  : None,
                   "pm10p0" : None,
                   "nc0p5"  : None,
                   "nc1p0"  : None,
                   "nc2p5"  : None,
                   "nc4p0"  : None,
                   "nc10p0" : None,
                   "typical": None}

    def __init__(self, port):
        self.bus = SMBus(port)

    def read_article_code(self):
        result = []
        article_code = []

        write = i2c_msg.write(self.SPS_ADDR, self.R_ARTICLE_CD)
        self.bus.i2c_rdwr(write)

        read = i2c_msg.read(self.SPS_ADDR, 48)
        self.bus.i2c_rdwr(read)

        for i in range(read.len):
            result.append(bytes_to_int(read.buf[i]))

        if checkCRC(result):
            for i in range (2, len(result), 3):
                article_code.append(chr(result[i-2]))
                article_code.append(chr(result[i-1]))
            return str("".join(article_code))
        else:
            return self.ARTICLE_CODE_ERROR

    def read_device_serial(self):
        result = []
        device_serial = []

        write = i2c_msg.write(self.SPS_ADDR, self.R_SERIAL_NUM)
        self.bus.i2c_rdwr(write)

        read = i2c_msg.read(self.SPS_ADDR, 48)
        self.bus.i2c_rdwr(read)

        for i in range(read.len):
            result.append(bytes_to_int(read.buf[i]))

        if checkCRC(result):
            for i in range(2, len(result), 3):
                device_serial.append(chr(result[i-2]))
                device_serial.append(chr(result[i-1]))
            return str("".join(device_serial))
        else:
            return self.SERIAL_NUMBER_ERROR

    def read_auto_cleaning_interval(self):
        result = []

        write = i2c_msg.write(self.SPS_ADDR, self.RW_AUTO_CLN)
        self.bus.i2c_rdwr(write)

        read = i2c_msg.read(self.SPS_ADDR, 6)
        self.bus.i2c_rdwr(read)

        for i in range(read.len):
            result.append(bytes_to_int(read.buf[i]))

        if checkCRC(result):
            result = result[0] * pow(2, 24) + result[1] * pow(2, 16) + result[3] * pow(2, 8) + result[4]
            return result
        else:
            return self.AUTO_CLN_INTERVAL_ERROR

    def set_auto_cleaning_interval(self, seconds):
        self.RW_AUTO_CLN.append((seconds >> 24) & 0xFF)
        self.RW_AUTO_CLN.append((seconds >> 16) & 0xFF)

        self.RW_AUTO_CLN.append(calculateCRC(self.RW_AUTO_CLN[2:4]))

        self.RW_AUTO_CLN.append((seconds >> 8) & 0xFF)
        self.RW_AUTO_CLN.append(seconds & 0xFF)

        self.RW_AUTO_CLN.append(calculateCRC(self.RW_AUTO_CLN[5:7]))

        write = i2c_msg.write(self.SPS_ADDR, self.RW_AUTO_CLN)
        self.bus.i2c_rdwr(write)

    def start_fan_cleaning(self):
        write = i2c_msg.write(self.SPS_ADDR, self.START_CLN)
        self.bus.i2c_rdwr(write)

    def start_measurement(self):
        self.START_MEAS.append(0x03)
        self.START_MEAS.append(0x00)

        crc = calculateCRC(self.START_MEAS[2:4])
        self.START_MEAS.append(crc)

        write = i2c_msg.write(self.SPS_ADDR, self.START_MEAS)
        self.bus.i2c_rdwr(write)

    def stop_measurement(self):
        write = i2c_msg.write(self.SPS_ADDR, self.STOP_MEAS)
        self.bus.i2c_rdwr(write)

    def read_data_ready_flag(self):
        result = []

        write = i2c_msg.write(self.SPS_ADDR, self.R_DATA_RDY)
        self.bus.i2c_rdwr(write)

        read = i2c_msg.read(self.SPS_ADDR, 3)
        self.bus.i2c_rdwr(read)

        for i in range(read.len):
            result.append(bytes_to_int(read.buf[i]))

        if checkCRC(result):
            return result[1]
        else:
            return self.DATA_READY_FLAG_ERROR

    def read_measured_values(self):
        result = []

        write = i2c_msg.write(self.SPS_ADDR, self.R_VALUES)
        self.bus.i2c_rdwr(write)

        read = i2c_msg.read(self.SPS_ADDR, 60)
        self.bus.i2c_rdwr(read)

        for i in range(read.len):
            result.append(bytes_to_int(read.buf[i]))

        if checkCRC(result):
            self.parse_sensor_values(result)
            return self.NO_ERROR
        else:
            return self.MEASURED_VALUES_ERROR

    def device_reset(self):
        write = i2c_msg.write(self.SPS_ADDR, self.RESET)
        self.bus.i2c_rdwr(write)
        sleep(1)

    def parse_sensor_values(self, input):
        index = 0
        pm_list = []
        for i in range (4, len(input), 6):
            value = input[i] + input[i-1] * pow(2, 8) +input[i-3] * pow(2, 16) + input[i-4] * pow(2, 24)
            pm_list.append(value)

        for i in self.dict_values.keys():
            self.dict_values[i] = convertPMValues(pm_list[index])
            index += 1
コード例 #14
0
    def task(self):

        temp  = 99999
        humid = 99999
        tdew  = 99999
        
        status = 0
        
        try:
            bus = SMBus(I2CBUS)
            bus.write_byte( self.I2Caddr, HTU21D_READ_TEMP_NOHOLD )
            time.sleep(0.05)
            read = i2c_msg.read( self.I2Caddr, 3 )
            bus.i2c_rdwr(read)
            resp = list(read)

            if ( self.crc8(resp) == 0 ):
                status += 1
                # data sheet 15/21 Temperature Conversion
                t = (resp[0] << 8) | (resp[1] & HTU21D_STATUS_LSBMASK)
                temp = ((175.72 * t) / 65536.0) - 46.86 

                self.temp_buff[self.temp_ptr] = temp
                self.temp_ptr += 1
                if self.temp_ptr >= HTU21D_MAX:
                    self.temp_ptr = 0

                # runs first pass only
                if self.init_buff :
                    for i in range(HTU21D_MAX):
                        self.temp_buff[i] = temp
                # need to init humid_buff[] too
                # so don't clear self.init_buff flag here
            
                avg_temp = 0
                for i in range(HTU21D_MAX):
                    avg_temp += self.temp_buff[i]
                avg_temp /= HTU21D_MAX_FLOAT

                f = open(self.FptrTC,"w")
                f.write("%3.1f" % avg_temp)
                f.close()
                
            bus.write_byte( self.I2Caddr, HTU21D_READ_HUM_NOHOLD )
            time.sleep(0.05)
            read = i2c_msg.read( self.I2Caddr, 3 )
            bus.i2c_rdwr(read)
            resp = list(read)
            bus.close()

            if( self.crc8( resp ) == 0 ):
                status += 1
                # data sheet 15/21 Relative Humidity
                h = (resp[0] << 8) | (resp[1] & HTU21D_STATUS_LSBMASK)
                humid = ((125.0 * h) / 65536.0) - 6.0 
            
                # limit for out of range values
                # per data sheet page 15/21
                if humid < 0.0 :
                    humid = 0.0
                if humid > 100.0:
                    humid = 100.0
                
                # RH compensation per datasheet page: 4/12    
                # JUN 28, 2018 changed to avg_temp
                rh = humid + ( 25.0 - avg_temp) * -0.15    

                self.humid_buff[self.humid_ptr] = rh
                self.humid_ptr += 1
                if self.humid_ptr >= HTU21D_MAX:
                    self.humid_ptr = 0
            
                # runs first pass only
                if self.init_buff :
                    for i in range(HTU21D_MAX):
                        self.humid_buff[i] = rh
                        self.init_buff = 0
           
                avg_humid = 0
                for i in range(HTU21D_MAX):
                    avg_humid += self.humid_buff[i]
                avg_humid /= HTU21D_MAX_FLOAT

                f = open(self.FptrRH,"w")
                f.write("%3.1f" % avg_humid)
                f.close()
    
            # with both valid temperature and RH 
            # calculate the dew point and absolute humidity using average values
            if status > 1:
            
                # Calculate dew point
            
                # because log of zero is not possible
                if avg_humid < 0.1:
                    avg_humid = 0.1
                A = 8.1332
                B = 1762.39
                C = 235.66
                # data sheet page 16/21 Partial Pressure & Dew Point  
                pp = 10**( A - ( B / ( avg_temp + C )))            
                tdew = -(( B / ( log10( avg_humid * pp / 100.0) - A )) + C ) 
            
                f = open(self.FptrTD,"w")
                f.write("%3.1f" % tdew)
                f.close()

                # Calculate absolute humidity in grams/M^3
                e = 2.71828
                a = 13.2473
                b = e**((17.67 * avg_temp)/(avg_temp + 243.5))
                c = 273.15 + avg_temp
                ah = a * b * avg_humid / c
            
                f = open(self.FptrAH,"w")
                f.write("%3.1f" % ah)
                f.close()

            #print "htu21d.task() T: %3.1f RH: %3.1f Tdew: %3.1f AH: %3.1f" %  ( avg_temp, avg_humid, tdew, ah )
        
        except:
            bus.close()
            print "htu21d.task() failed"
            
        # returning average values
        return [ temp, humid, tdew ]        
コード例 #15
0
class TrackBall():
    def __init__(self, address=I2C_ADDRESS, i2c_bus=1, interrupt_pin=None, timeout=5):
        self._i2c_address = address
        self._i2c_bus = SMBus(i2c_bus)
        self._interrupt_pin = interrupt_pin
        self._timeout = timeout

        chip_id = struct.unpack("<H", bytearray(self.i2c_rdwr([REG_CHIP_ID_L], 2)))[0]
        if chip_id != CHIP_ID:
            raise RuntimeError("Invalid chip ID: 0x{:04X}, expected 0x{:04X}".format(chip_id, CHIP_ID))

        if self._interrupt_pin is not None:
            GPIO.setwarnings(False)
            GPIO.setmode(GPIO.BCM)
            GPIO.setup(self._interrupt_pin, GPIO.IN, pull_up_down=GPIO.PUD_OFF)

        self.enable_interrupt()

    def change_address(self, new_address):
        """Write a new I2C address into flash."""
        self.i2c_rdwr([REG_I2C_ADDR, new_address & 0xff])
        self._wait_for_flash()

    def _wait_for_flash(self):
        t_start = time.time()
        while self.get_interrupt():
            if time.time() - t_start > self._timeout:
                raise RuntimeError("Timed out waiting for interrupt!")
            time.sleep(0.001)

        t_start = time.time()
        while not self.get_interrupt():
            if time.time() - t_start > self._timeout:
                raise RuntimeError("Timed out waiting for interrupt!")
            time.sleep(0.001)

    def enable_interrupt(self, interrupt=True):
        """Enable/disable GPIO interrupt pin."""
        value = self.i2c_rdwr([REG_INT], 1)[0]
        value = value & ~MSK_INT_OUT_EN
        if interrupt:
            value = value | MSK_INT_OUT_EN

        self.i2c_rdwr([REG_INT, value])

    def i2c_rdwr(self, data, length=0):
        """Write and optionally read I2C data."""
        msg_w = i2c_msg.write(self._i2c_address, data)
        self._i2c_bus.i2c_rdwr(msg_w)

        if length > 0:
            time.sleep(0.02)
            msg_r = i2c_msg.read(self._i2c_address, length)
            self._i2c_bus.i2c_rdwr(msg_r)
            return list(msg_r)

        return []

    def get_interrupt(self):
        """Get the trackball interrupt status."""
        if self._interrupt_pin is not None:
            return GPIO.input(self._interrupt_pin) == 0
        else:
            value = self.i2c_rdwr([REG_INT], 1)[0]
            return value & MSK_INT_TRIGGERED

    def set_rgbw(self, r, g, b, w):
        """Set all LED brightness as RGBW."""
        self.i2c_rdwr([REG_LED_RED, r, g, b, w])

    def set_red(self, value):
        """Set brightness of trackball red LED."""
        self.i2c_rdwr([REG_LED_RED, value & 0xff])

    def set_green(self, value):
        """Set brightness of trackball green LED."""
        self.i2c_rdwr([REG_LED_GRN, value & 0xff])

    def set_blue(self, value):
        """Set brightness of trackball blue LED."""
        self.i2c_rdwr([REG_LED_BLU, value & 0xff])

    def set_white(self, value):
        """Set brightness of trackball white LED."""
        self.i2c_rdwr([REG_LED_WHT, value & 0xff])

    def read(self):
        """Read up, down, left, right and switch data from trackball."""
        left, right, up, down, switch = self.i2c_rdwr([REG_LEFT], 5)
        switch, switch_state = switch & ~MSK_SWITCH_STATE, (switch & MSK_SWITCH_STATE) > 0
        return up, down, left, right, switch, switch_state
コード例 #16
0
class LifeTester:
    # Todo: what if two instances are created with the same address?

    def __init__(self, addr):
        self.addr = addr
        self.bus = SMBus(I2C_BUS)

    def reset(self):
        """Resets both lifetester channels"""
        self._send_command(WRITE_CMD_REG)
        self._send_command(RESET_CH_A)
        self._poll_ready_state()
        self._send_command(WRITE_CMD_REG)
        self._send_command(RESET_CH_B)
        self._poll_ready_state()

    def set_params(self, new_params):
        """Sets the measurement parameters"""
        # note that polling doesn't work in this case
        self._send_command(WRITE_CMD_REG)
        self._send_command(WRITE_PARAMS)
        self._write_block_data(self._parse_bytes_from_params(new_params))

    def get_params(self):
        """Gets the current measurement parameters"""
        self._send_command(WRITE_CMD_REG)
        self._poll_ready_state()
        self._send_command(READ_PARAMS)
        self._poll_ready_state()
        params_bytes = self._read_block_data(PARAMS_PACKET_SIZE)
        return self._parse_params_from_bytes(params_bytes)

    def get_error_code(self):
        """get the error code from the command register"""
        cmd = self._read_command_reg()
        return (cmd >> ERR_OFFSET) & ERR_MASK

    def get_data(self):
        """Reads and returns data from channel A and B"""
        self._send_command(WRITE_CMD_REG)
        self._poll_ready_state()
        self._send_command(READ_CH_A_DATA)
        self._poll_ready_state()
        data_block_a = self._read_block_data(DATA_PACKET_SIZE)
        packet_a = self._parse_data(data_block_a)
        self._send_command(WRITE_CMD_REG)
        self._poll_ready_state()
        self._send_command(READ_CH_B_DATA)
        self._poll_ready_state()
        data_block_b = self._read_block_data(DATA_PACKET_SIZE)
        packet_b = self._parse_data(data_block_b)
        return self._parse_measurement(packet_a, packet_b)

    def _bytes_to_int(self, b):
        return int.from_bytes(b, byteorder='little', signed=False)

    def _dequeue(self, l, n):
        # pops a list, l, of length n from another list
        return [l.pop(0) for e in range(n)]

    def _parse_data(self, b):
        # Todo: catch empty list exception - assert len(b)?
        tmp = [
            self._bytes_to_int(self._dequeue(b, field))
            for field in list(num_bytes)
        ]
        return DataPacket._make(tmp)

    def _parse_params_from_bytes(self, b):
        # Todo: catch empty list exception - assert len(b)?
        tmp = [
            self._bytes_to_int(self._dequeue(b, BYTES_PER_PARAM))
            for p in ParamsPacket._fields
        ]
        return ParamsPacket._make(tmp)

    def _parse_bytes_from_params(self, params):
        msb = lambda x: x >> (8 & 0xFF)
        lsb = lambda x: x & 0xFF
        return [f(p) for p in params for f in [lsb, msb]]

    def _send_command(self, cmd):
        sleep(POLL_DELAY)
        self.bus.write_byte_data(self.addr, cmd, 0)

    def _read_byte(self):
        return self.bus.read_byte_data(self.addr, 0)

    def _read_block_data(self, num_bytes):
        msg = i2c_msg.read(self.addr, num_bytes)
        self.bus.i2c_rdwr(msg)
        return list(msg)

    def _write_block_data(self, data):
        msg = i2c_msg.write(self.addr, data)
        self.bus.i2c_rdwr(msg)

    def _read_command_reg(self):
        self._send_command(READ_CMD_REG)
        return self._read_byte()

    def _is_ready(self):
        cmd_reg = self._read_command_reg()
        mask = 1 << RDY_OFFSET
        return (bool)(cmd_reg & mask)

    def _poll_ready_state(self):
        while not self._is_ready():
            sleep(POLL_DELAY)

    def _convert_to_temp(self, reg):
        # Turn 16 bit wide register to temperature float
        return int(reg >> 3) * TEMP_CONVERSION

    def _parse_error_code(self, byte):
        if byte < len(ERROR_CODES):
            return ERROR_CODES[byte]
        else:
            return 'unkown'

    def _parse_measurement(self, a, b):
        measurement = Measurement(time=a.time,
                                  v_a=a.voltage * DAC_CONVERSION,
                                  i_a=a.current * ADC_CONVERSION,
                                  v_b=b.voltage * DAC_CONVERSION,
                                  i_b=b.voltage * ADC_CONVERSION,
                                  temperature=self._convert_to_temp(
                                      a.temperature),
                                  light_intensity=a.light_intensity,
                                  error_a=self._parse_error_code(a.error_code),
                                  error_b=self._parse_error_code(b.error_code))
        return measurement
コード例 #17
0
class UpbeatLabs_MCP39F521(object):
    """Class for communicating with an MCP39F521 device like Dr. Wattson using the 
    python smbus library."""
    class Error_code(Enum):
        SUCCESS = 0
        ERROR_INCORRECT_HEADER = 1
        ERROR_CHECKSUM_FAIL = 2
        ERROR_UNEXPECTED_RESPONSE = 3
        ERROR_INSUFFICIENT_ARRAY_SIZE = 4
        ERROR_CHECKSUM_MISMATCH = 5
        ERROR_SET_VALUE_MISMATCH = 6
        ERROR_VALUE_OUT_OF_BOUNDS = 7

    class Event_config(Enum):
        EVENT_OVERCUR_TST = 0
        EVENT_OVERPOW_TST = 1
        EVENT_VSAG_TST = 2
        EVENT_VSUR_TST = 3
        EVENT_OVERCUR_LA = 4
        EVENT_OVERPOW_LA = 5
        EVENT_VSAG_LA = 6
        EVENT_VSUR_LA = 7
        EVENT_VSAG_CL = 8
        EVENT_VSUR_CL = 9
        EVENT_OVERPOW_CL = 10
        EVENT_OVERCUR_CL = 11
        EVENT_MANUAL = 14
        EVENT_VSAG_PIN = 16
        EVENT_VSURGE_PIN = 17
        EVENT_OVERCUR_PIN = 18
        EVENT_OVERPOW_PIN = 19

    class System_status(Enum):
        SYSTEM_VSAG = 0
        SYSTEM_VSURGE = 1
        SYSTEM_OVERCUR = 2
        SYSTEM_OVERPOW = 3
        SYSTEM_SIGN_PA = 4
        SYSTEM_SIGN_PR = 5
        SYSTEM_EVENT = 10

    class calibration_config(Enum):
        CALIBRATION_CONFIG_4A = 0
        CALIBRATION_CONFIG_10A = 1  # 30 ohm burden resistor x2
        CALIBRATION_CONFIG_15A = 2  # 20 ohm burden resistor x2

    class __Response_code(Enum):
        RESPONSE_ACK = 0x06
        RESPONSE_NAK = 0x15
        RESPONSE_CSFAIL = 0x51

    class __Command_code(Enum):
        COMMAND_REGISTER_READ_N_BYTES = 0x4e
        COMMAND_REGISTER_WRITE_N_BYTES = 0x4d
        COMMAND_SET_ADDRESS_POINTER = 0x41
        COMMAND_SAVE_TO_FLASH = 0x53
        COMMAND_PAGE_READ_EEPROM = 0x42
        COMMAND_PAGE_WRITE_EEPROM = 0x50
        COMMAND_BULK_ERASE_EEPROM = 0x4f
        COMMAND_AUTO_CALIBRATE_GAIN = 0x5a
        COMMAND_AUTO_CALIBRATE_REACTIVE_GAIN = 0x7a
        COMMAND_AUTO_CALIBRATE_FREQUENCY = 0x76

    ## There is a bug in current MCP39F511/521 where energy accumulation
    ## values are off if the energy accumulation interval is
    ## anything but 2. This applies the workaround for that problem.
    ## To be removed for chips that have the issue fixed.
    ## XXX : TODO

    def __init__(self, address=MCP39F521_I2CADDR, busnum=DEFAULT_BUSNUM):
        """Create an instance of the MCP39F521 device at the specified address on the
           specified I2C bus number."""
        self._address = address
        self._bus = SMBus(busnum)
        self._logger = logging.getLogger(
            'DrWattson.UpbeatLabs_MCP39F521.Bus.{0}.Address.{1:#0X}'.format(
                busnum, address))
        self._energy_accum_correction_factor = 1
        (retVal, enabled) = self.isEnergyAccumulationEnabled()
        if (retVal == self.Error_code.SUCCESS.value and enabled):
            (retVal,
             accumIntervalReg) = self.readAccumulationIntervalRegister()
            self._energy_accum_correction_factor = (accumIntervalReg - 2)

    ## Get energy related data from the module
    ##
    ## Parameters:
    ## UpbeatLabs_MCP39F521_Data (output) - Metering data
    ##

    def readEnergyData(self):
        (retVal, buf) = self.__registerReadNBytes(0x00, 0x02, 28)
        data = UpbeatLabs_MCP39F521_Data()

        if (retVal == self.Error_code.SUCCESS.value):
            data.systemStatus = (buf[3] << 8 | buf[2])
            data.systemVersion = (buf[5] << 8 | buf[4])
            data.voltageRMS = (buf[7] << 8 | buf[6]) / 10.0
            data.lineFrequency = (buf[9] << 8 | buf[8]) / 1000.0
            data.analogInputVoltage = (buf[11] << 8 | buf[10]) / 1023.0 * 3.3

            pfRaw = buf[13] << 8 | buf[12]
            f = ((pfRaw & 0x8000) >> 15) * -1.0

            for ch in range(14, 3, -1):
                f += ((pfRaw & (1 << ch)) >> ch) * 1.0 / (1 << (15 - ch))

            data.powerFactor = f

            data.currentRMS = (buf[17] << 24 | buf[16] << 16 | buf[15] << 8
                               | buf[14]) / 10000.0
            data.activePower = (buf[21] << 24 | buf[20] << 16 | buf[19] << 8
                                | buf[18]) / 100.0
            data.reactivePower = (buf[25] << 24 | buf[24] << 16 | buf[23] << 8
                                  | buf[22]) / 100.0
            data.apparentPower = (buf[29] << 24 | buf[28] << 16 | buf[27] << 8
                                  | buf[26]) / 100.0

        return (retVal, data)

    ## Get energy accumulator data from the module
    ##
    ## Parameters:
    ## UpbeatLabs_MCP39F521_AccumData (output) - accumulator data for energy
    ## Notes:
    ## On Arduino cannot read more than 32 bytes on I2C
    ## Let's just stick to that limit!
    ## Splitting out activeEnergyImport, activeEnergyExport and
    ## reactiveEnergyImport, reactiveEnergyExport into two calls
    ## as the total is 32+3 = 35 bytes otherwise.

    def readEnergyAccumData(self):
        (retVal, buf) = self.__registerReadNBytes(0x00, 0x1e, 16)
        data = UpbeatLabs_MCP39F521_AccumData()

        if (retVal == self.Error_code.SUCCESS.value):
            if (self._energy_accum_correction_factor == -1):
                data.activeEnergyImport = (
                    ((buf[9]) << 56 | (buf[8]) << 48 | (buf[7]) << 40 |
                     (buf[6]) << 32 | (buf[5]) << 24 | (buf[4]) << 16 |
                     (buf[3]) << 8 | buf[2]) / 2) / 1000.0
                data.activeEnergyExport = (
                    ((buf[17]) << 56 | (buf[16]) << 48 | (buf[15]) << 40 |
                     (buf[14]) << 32 | (buf[13]) << 24 | (buf[12]) << 16 |
                     (buf[11]) << 8 | buf[10]) / 2) / 1000.0
            else:
                data.activeEnergyImport = (
                    ((buf[9]) << 56 | (buf[8]) << 48 | (buf[7]) << 40 |
                     (buf[6]) << 32 | (buf[5]) << 24 | (buf[4]) << 16 |
                     (buf[3]) << 8 | buf[2]) *
                    (1 << self._energy_accum_correction_factor)) / 1000.0
                data.activeEnergyExport = (
                    ((buf[17]) << 56 | (buf[16]) << 48 | (buf[15]) << 40 |
                     (buf[14]) << 32 | (buf[13]) << 24 | (buf[12]) << 16 |
                     (buf[11]) << 8 | buf[10]) *
                    (1 << self._energy_accum_correction_factor)) / 1000.0

        time.sleep(0.05)
        (retVal, buf) = self.__registerReadNBytes(0x00, 0x2e, 16)

        if (retVal == self.Error_code.SUCCESS.value):
            if (self._energy_accum_correction_factor == -1):
                data.reactiveEnergyImport = (
                    ((buf[9]) << 56 | (buf[8]) << 48 | (buf[7]) << 40 |
                     (buf[6]) << 32 | (buf[5]) << 24 | (buf[4]) << 16 |
                     (buf[3]) << 8 | buf[2]) / 2) / 1000.0
                data.reactiveEnergyExport = (
                    ((buf[17]) << 56 | (buf[16]) << 48 | (buf[15]) << 40 |
                     (buf[14]) << 32 | (buf[13]) << 24 | (buf[12]) << 16 |
                     (buf[11]) << 8 | buf[10]) / 2) / 1000.0
            else:
                data.reactiveEnergyImport = (
                    ((buf[9]) << 56 | (buf[8]) << 48 | (buf[7]) << 40 |
                     (buf[6]) << 32 | (buf[5]) << 24 | (buf[4]) << 16 |
                     (buf[3]) << 8 | buf[2]) *
                    (1 << self._energy_accum_correction_factor)) / 1000.0
                data.reactiveEnergyExport = (
                    ((buf[17]) << 56 | (buf[16]) << 48 | (buf[15]) << 40 |
                     (buf[14]) << 32 | (buf[13]) << 24 | (buf[12]) << 16 |
                     (buf[11]) << 8 | buf[10]) *
                    (1 << self._energy_accum_correction_factor)) / 1000.0

        return (retVal, data)

    # Event control methods

    ## Reads the event configuration and returns the 32-bit bit map.
    ## Use the event_config enum to read bits of interest, without
    ## worrying about the bit position and structure of the
    ## event config register
    ##
    ## For example, bitRead(eventConfigRegisterValue, EVENT_VSAG_PIN)
    ## to see if event notification for VSAG events is turned on

    def readEventConfigRegister(self):
        (retVal, buf) = self.__registerReadNBytes(0x00, 0x7e, 4)
        configRegister = 0
        if (retVal == self.Error_code.SUCCESS.value):
            configRegister = buf[5] << 24 | buf[4] << 16 | buf[3] << 8 | buf[2]

        return (retVal, configRegister)

    ## Set the event configuration register to the appropriate value
    ##
    ## First, read the existing register value. Then, set (or clear) appropriate
    ## bits using the event_config enum for assitance. Lastly, set the
    ## new value back in the register.
    ##
    ## For example, bitSet(eventConfigRegisterValue, EVENT_VSAG_PIN)
    ## to turn on the event notification for VSAG events
    ## or bitClear(eventConfigRegisterValue, EVENT_VSAG_PIN)

    def setEventConfigurationRegister(self, value):
        byteArray = []
        byteArray.append(value & 0xFF)
        byteArray.append((value >> 8) & 0xFF)
        byteArray.append((value >> 16) & 0xFF)
        byteArray.append((value >> 24) & 0xFF)

        retVal = self.__registerWriteNBytes(0x00, 0x7e, 4, byteArray)
        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        (retVal, readArray) = self.__registerReadNBytes(0x00, 0x7e, 4)

        if (retVal == self.Error_code.SUCCESS.value):
            readValue = readArray[5] << 24 | readArray[4] << 16 | readArray[
                3] << 8 | readArray[2]

        if (readValue != value):
            return self.Error_code.ERROR_SET_VALUE_MISMATCH.value

        return self.Error_code.SUCCESS.value

    ## Read the event flag limits that have been set for the various events.
    ## For example, the voltage sag limit sets the voltage value below which
    ## the VSAG event is triggered
    ##
    ## See UpbeatLabs_MCP39F521_EventFlagLimits for more information about
    ## various limits

    def readEventFlagLimitRegisters(self):
        (retVal, buf) = self.__registerReadNBytes(0x00, 0xA0, 12)
        data = UpbeatLabs_MCP39F521_EventFlagLimits()

        if (retVal == self.Error_code.SUCCESS.value):
            data.voltageSagLimit = (buf[3] << 8 | buf[2])
            data.voltageSurgeLimit = (buf[5] << 8 | buf[4])
            data.overCurrentLimit = (buf[9] << 24 | buf[8] << 16 | buf[7] << 8
                                     | buf[6])
            data.overPowerLimit = (buf[13] << 24 | buf[12] << 16 | buf[11] << 8
                                   | buf[10])

        return (retVal, data)

    ## Write the event flag limits for the various events.
    ## For example, the voltage sag limit sets the voltage value below which
    ## the VSAG event is triggered
    ##
    ## See UpbeatLabs_MCP39F521_EventFlagLimits for more information about
    ## various limits

    def writeEventFlagLimitRegisters(self, input):
        byteArray = []
        byteArray.append(input.voltageSagLimit & 0xFF)
        byteArray.append((input.voltageSagLimit >> 8) & 0xFF)

        byteArray.append(input.voltageSurgeLimit & 0xFF)
        byteArray.append((input.voltageSurgeLimit >> 8) & 0xFF)

        byteArray.append(input.overCurrentLimit & 0xFF)
        byteArray.append((input.overCurrentLimit >> 8) & 0xFF)
        byteArray.append((input.overCurrentLimit >> 16) & 0xFF)
        byteArray.append((input.overCurrentLimit >> 24) & 0xFF)

        byteArray.append(input.overPowerLimit & 0xFF)
        byteArray.append((input.overPowerLimit >> 8) & 0xFF)
        byteArray.append((input.overPowerLimit >> 16) & 0xFF)
        byteArray.append((input.overPowerLimit >> 24) & 0xFF)

        retVal = self.__registerWriteNBytes(0x00, 0xA0, 12, byteArray)

        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        (retVal, eventFlagLimitsData) = self.readEventFlagLimitRegisters()
        if (retVal == self.Error_code.SUCCESS.value):
            ## Verify read values with input values
            if (eventFlagLimitsData.voltageSagLimit != input.voltageSagLimit
                    or eventFlagLimitsData.voltageSurgeLimit !=
                    input.voltageSurgeLimit
                    or eventFlagLimitsData.overCurrentLimit !=
                    input.overCurrentLimit
                    or eventFlagLimitsData.overPowerLimit !=
                    input.overPowerLimit):
                return self.Error_code.ERROR_SET_VALUE_MISMATCH.value

        return retVal

    # EEPROM methods

    ## Bulk erase all pages of the EEPROM memory

    def bulkEraseEEPROM(self):
        return self.__issueAckNackCommand(
            self.__Command_code.COMMAND_BULK_ERASE_EEPROM.value)

    def pageReadEEPROM(self, pageNum):
        """Implementation of pageReadEEPROM """
        data = [
            0xa5, 0x05, self.__Command_code.COMMAND_PAGE_READ_EEPROM.value,
            pageNum
        ]
        checksum = 0
        for x in data:
            checksum += x
        data.append(checksum % 256)

        write = i2c_msg.write(self._address, data)
        self._bus.i2c_rdwr(write)

        time.sleep(0.05)

        ##
        ## Read the specified length of data - ACK, Num Bytes, EEPROM Page Data, Checksum
        ## -> 1 + 1 + 16 + 1 = 19 bytes of data
        ##
        read = i2c_msg.read(self._address, 19)
        self._bus.i2c_rdwr(read)

        buf = []
        buf.extend(read)

        return (self.__checkHeaderAndChecksum(16, buf), buf[2:-1])

    def pageWriteEEPROM(self, pageNum, byteArray):
        """Implementation of pageWriteEEPROM """
        if (len(byteArray) != 16):
            return self.Error_code.ERROR_INSUFFICIENT_ARRAY_SIZE.value

        data = [
            0xa5, 21, self.__Command_code.COMMAND_PAGE_WRITE_EEPROM.value,
            pageNum
        ]

        # Data here...
        data.extend(byteArray)

        checksum = 0
        for x in data:
            checksum += x
        data.append(checksum % 256)

        write = i2c_msg.write(self._address, data)
        self._bus.i2c_rdwr(write)

        time.sleep(0.05)

        header = self._bus.read_byte(self._address)
        self._logger.debug(header)

        return self.__checkHeader(header)

    # Energy Accumulation methods

    ## This method is used to turn on/off energy accumulation.
    ## When it is turned on, the data read from the module
    ## in UpbeatLabs_MCP39F521_AccumData represents the
    ## accumulated energy data over the no load threshold
    ## (defaults to 1w). Therefore any energy over 1w
    ## gets accumulated over time.

    ## There is a bug in current MCP39F511/521 where energy accumulation
    ## values are off if the energy accumulation interval is
    ## anything but 2. This applies the workaround for that problem.
    ## To be removed for chips that have the issue fixed.

    def enableEnergyAccumulation(self, enable):
        ## First, note the accumulation interval. If it is anything
        ## other than the default (2), note the correction
        ## factor that has to be applied to the energy
        ## accumulation.
        (retVal, accumIntervalReg) = self.readAccumulationIntervalRegister()

        self._energy_accum_correction_factor = (accumIntervalReg - 2)

        byteArray = [enable, 0]

        ## write register
        retVal = self.__registerWriteNBytes(0x00, 0xDC, 2, byteArray)

        return retVal

    def isEnergyAccumulationEnabled(self):
        (retVal, readArray) = self.__registerReadNBytes(0x00, 0xDC, 5)
        enabled = False
        if (retVal == self.Error_code.SUCCESS.value):
            enabled = readArray[2]

        return (retVal, enabled)

    # <----   End Energy Accumulation methods

    # START --- WARNING!!! WARNING!!! WARNING!!!
    # Advanced methods for calibration, etc
    # WARNING!!!! Use with extreme caution! These can render your Dr. Wattson
    # uncalibrated. Only use if you know what you are doing!

    ## Read the contents of the calibration registers
    ## Results returned in UpbeatLabs_MCP39F521_CalibrationData object

    def readCalibrationRegisters(self):
        (retVal, buf) = self.__registerReadNBytes(0x00, 0x5e, 28)
        data = UpbeatLabs_MCP39F521_CalibrationData()

        if (retVal == self.Error_code.SUCCESS.value):
            data.calibrationRegisterDelimiter = (buf[3] << 8 | buf[2])
            data.gainCurrentRMS = (buf[5] << 8 | buf[4])
            data.gainVoltageRMS = (buf[7] << 8 | buf[6])
            data.gainActivePower = (buf[9] << 8 | buf[8])
            data.gainReactivePower = (buf[11] << 8 | buf[10])
            data.offsetCurrentRMS = (buf[15] << 24 | buf[14] << 16
                                     | buf[13] << 8 | buf[12])
            data.offsetActivePower = (buf[19] << 24 | buf[18] << 16
                                      | buf[17] << 8 | buf[16])
            data.offsetReactivePower = (buf[23] << 24 | buf[22] << 16
                                        | buf[21] << 8 | buf[20])
            data.dcOffsetCurrent = (buf[25] << 8 | buf[24])
            data.phaseCompensation = (buf[27] << 8 | buf[26])
            data.apparentPowerDivisor = (buf[29] << 8 | buf[28])

        return (retVal, data)

    ## This method writes the current, voltage, active power and reactive power gains directly to
    ## the MCP39F521 registers. Use this if you know what the appropriate gains are to be for
    ## your particular metering range and design. Typically, these are not to be changed unless
    ## you are performing your own calibration, and even so, it is better to use the
    ## auto-calibration methods instead. This is one big gun to shoot yourself, be warned!

    def writeGains(self, gainCurrentRMS, gainVoltageRMS, gainActivePower,
                   gainReactivePower):

        byteArray = []
        byteArray.append(gainCurrentRMS & 0xFF)
        byteArray.append((gainCurrentRMS >> 8) & 0xFF)

        byteArray.append(gainVoltageRMS & 0xFF)
        byteArray.append((gainVoltageRMS >> 8) & 0xFF)

        byteArray.append(gainActivePower & 0xFF)
        byteArray.append((gainActivePower >> 8) & 0xFF)

        byteArray.append(gainReactivePower & 0xFF)
        byteArray.append((gainReactivePower >> 8) & 0xFF)

        retVal = self.__registerWriteNBytes(0x00, 0x60, 8, byteArray)

        return retVal

    ## Read the system config register, which is a 32-bit bit map.
    ## The system config register is used to set setting like
    ## PGA gains for current and voltage channels, etc
    ## You will typically not be changing these unless you are
    ## performing a calibration.

    def readSystemConfigRegister(self):
        (retVal, buf) = self.__registerReadNBytes(0x00, 0x7a, 4)
        value = 0
        if (retVal == self.Error_code.SUCCESS.value):
            value = buf[5] << 24 | buf[4] << 16 | buf[3] << 8 | buf[2]
        return (retVal, value)

    ## Set the system config register, which is a 32-bit bit map.
    ## The system config register is used to set setting like
    ## PGA gains for current and voltage channels, etc
    ## You will typically not be changing these unless you are
    ## performing a calibration. Do not use unless you know what
    ## you are doing! This is one big gun to shoot yourself, be warned!

    def setSystemConfigurationRegister(self, value):
        retVal = 0
        byteArray = [0] * 4
        byteArray[0] = value & 0xFF
        byteArray[1] = (value >> 8) & 0xFF
        byteArray[2] = (value >> 16) & 0xFF
        byteArray[3] = (value >> 24) & 0xFF
        # print byteArray

        retVal = self.__registerWriteNBytes(0x00, 0x7a, 4, byteArray)
        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        time.sleep(0.05)

        (retVal, readArray) = self.__registerReadNBytes(0x00, 0x7a, 4)
        readValue = ((readArray[5]) << 24 | (readArray[4]) << 16 |
                     (readArray[3]) << 8 | readArray[2])

        if (readValue != value):
            return self.Error_code.ERROR_SET_VALUE_MISMATCH.value
        return self.Error_code.SUCCESS.value

    ## Read the accumlation interval register, which represents N in 2^N
    ## number of line cycles to be used for a single computation.
    ## You will not be modifying this unless you are performing a
    ## calibration.

    def readAccumulationIntervalRegister(self):
        (retVal, buf) = self.__registerReadNBytes(0x00, 0x9e, 2)
        value = 0
        if (retVal == self.Error_code.SUCCESS.value):
            value = buf[3] << 8 | buf[2]
        return (retVal, value)

    ## Set the accumlation interval register, which represents N in 2^N
    ## number of line cycles to be used for a single computation.
    ## You will not be modifying this unless you are performing a
    ## calibration. Use with caution!!

    def setAccumulationIntervalRegister(self, value):
        retVal = 0
        byteArray = [0] * 2
        byteArray[0] = value & 0xFF
        byteArray[1] = (value >> 8) & 0xFF

        retVal = self.__registerWriteNBytes(0x00, 0x9e, 2, byteArray)
        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        time.sleep(0.05)

        (retVal, readArray) = self.__registerReadNBytes(0x00, 0x9e, 2)
        readValue = ((readArray[3]) << 8 | readArray[2])

        if (readValue != value):
            return self.Error_code.ERROR_SET_VALUE_MISMATCH.value
        return self.Error_code.SUCCESS.value

    ## Read the design config registers into the UpbeatLabs_MCP39F521_DesignConfigData struct.
    ## See class for more details. These are used to set the appropriate calibration values for
    ## calibrating your module.

    def readDesignConfigurationRegisters(self):
        (retVal, buf) = self.__registerReadNBytes(0x00, 0x82, 20)
        data = UpbeatLabs_MCP39F521_DesignConfigData()

        if (retVal == self.Error_code.SUCCESS.value):
            data.rangeVoltage = buf[2]
            data.rangeCurrent = buf[3]
            data.rangePower = buf[4]
            data.rangeUnimplemented = buf[5]
            data.calibrationCurrent = (buf[9] << 24 | buf[8] << 16
                                       | buf[7] << 8 | buf[6])
            data.calibrationVoltage = ((buf[11] << 8) | buf[10])
            data.calibrationPowerActive = (buf[15] << 24 | buf[14] << 16
                                           | buf[13] << 8 | buf[12])
            data.calibrationPowerReactive = (buf[19] << 24 | buf[18] << 16
                                             | buf[17] << 8 | buf[16])
            data.lineFrequencyRef = ((buf[21] << 8) | buf[20])

        return (retVal, data)

    ## Write the design config registers. See UpbeatLabs_MCP39F521_DesignConfigData
    ## struct for more details. These are used to set the appropriate calibration values for
    ## calibrating your module. Use this method only if you know what you are doing!
    ## This is one big gun to shoot yourself, be warned!

    def writeDesignConfigRegisters(self, data):
        byteArray = [] * 20
        ## range
        byteArray[0] = data.rangeVoltage
        byteArray[1] = data.rangeCurrent
        byteArray[2] = data.rangePower
        byteArray[3] = data.rangeUnimplemented

        ## calibration current
        byteArray[4] = data.calibrationCurrent & 0xFF
        byteArray[5] = (data.calibrationCurrent >> 8) & 0xFF
        byteArray[6] = (data.calibrationCurrent >> 16) & 0xFF
        byteArray[7] = (data.calibrationCurrent >> 24) & 0xFF

        ## calibration voltage
        byteArray[8] = data.calibrationVoltage & 0xFF
        byteArray[9] = (data.calibrationVoltage >> 8) & 0xFF

        ## calibration power active
        byteArray[10] = data.calibrationPowerActive & 0xFF
        byteArray[11] = (data.calibrationPowerActive >> 8) & 0xFF
        byteArray[12] = (data.calibrationPowerActive >> 16) & 0xFF
        byteArray[13] = (data.calibrationPowerActive >> 24) & 0xFF

        ## calibration power reactive
        byteArray[14] = data.calibrationPowerReactive & 0xFF
        byteArray[15] = (data.calibrationPowerReactive >> 8) & 0xFF
        byteArray[16] = (data.calibrationPowerReactive >> 16) & 0xFF
        byteArray[17] = (data.calibrationPowerReactive >> 24) & 0xFF

        ## line frequency ref
        byteArray[18] = data.lineFrequencyRef & 0xFF
        byteArray[19] = (data.lineFrequencyRef >> 8) & 0xFF

        retVal = self.__registerWriteNBytes(0x00, 0x82, 20, byteArray)
        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        time.sleep(0.05)

        ## Read the values to verify write

        (retVal, designConfigData) = self.readDesignConfigurationRegisters()

        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        ## Verify read values with input values
        if (designConfigData.rangeVoltage != data.rangeVoltage
                or designConfigData.rangeCurrent != data.rangeCurrent
                or designConfigData.rangePower != data.rangePower or
                designConfigData.calibrationCurrent != data.calibrationCurrent
                or
                designConfigData.calibrationVoltage != data.calibrationVoltage
                or designConfigData.calibrationPowerActive !=
                data.calibrationPowerActive
                or designConfigData.calibrationPowerReactive !=
                data.calibrationPowerReactive
                or designConfigData.lineFrequencyRef != data.lineFrequencyRef):
            return self.Error_code.ERROR_SET_VALUE_MISMATCH.value

        return self.Error_code.SUCCESS.value

    ## Write the phase compensation register. This will not be required unless
    ## you are manually writing calibration values yourself. Use with caution!

    def writePhaseCompensation(self, phaseCompensation):

        byteArray = [] * 2
        ## Calibrating phase
        byteArray[0] = phaseCompensation
        byteArray[1] = 0

        retVal = self.__registerWriteNBytes(0x00, 0x76, 2, byteArray)

        return retVal

    ## Read and set the ambient reference temperature when
    ## calibrating. This is used during calibration as one
    ## of the steps. Use with caution!

    def readAndSetTemperature(self):
        (retVal, byteArray) = __registerReadNBytes(0x00, 0x0a, 2)

        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        bytesWrite = [] * 2
        bytesWrite[0] = byteArray[2]
        bytesWrite[1] = byteArray[3]

        retVal = self.__registerWriteNBytes(0x00, 0xcc, 2, bytesWrite)

        return retVal

    ## Invoke the "autoCalibrate Gain" command. Prior to this,
    ## other requisite steps need to be taken like setting
    ## the design config registers with the appropriate
    ## calibration values. Use only if you know what you are
    ## doing! This is one big gun to shoot yourself, be warned!

    def autoCalibrateGain(self):
        return self.__issueAckNackCommand(
            self.__Command_code.COMMAND_AUTO_CALIBRATE_GAIN.value)

    ## Invoke the "autoCalibrate Reactive Gain" command. Prior to this,
    ## other requisite steps need to be taken like setting
    ## the design config registers with the appropriate
    ## calibration values, and auto calibrating gain.
    ## Use only if you know what you are doing!
    ## This is one big gun to shoot yourself, be warned!

    def autoCalibrateReactiveGain(self):
        return self.__issueAckNackCommand(
            self.__Command_code.COMMAND_AUTO_CALIBRATE_REACTIVE_GAIN.value)

    ## Invoke the "autoCalibrate Line Frequency" command. Prior to this,
    ## other requisite calibration steps need to be taken like setting
    ## the appropriate design config registers.
    ## Use only if you know what you are doing!
    ## This is one big gun to shoot yourself, be warned!

    def autoCalibrateFrequency(self):
        return self.__issueAckNackCommand(
            self.__Command_code.COMMAND_AUTO_CALIBRATE_FREQUENCY.value)

    ## This method is used to calibrate the phase compensation
    ## when calibrating the module, as one of the steps during
    ## system calibration. Use only if you know what you are doing!
    ## This is one big gun to shoot yourself, be warned!

    def calibratePhase(self, pfExp):
        (retVal, byteArray) = self.__registerReadNBytes(0x00, 0x0c, 2)

        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        pfRaw = buf[13] << 8 | buf[12]
        f = ((pfRaw & 0x8000) >> 15) * -1.0

        for ch in range(14, 3, -1):
            f += ((pfRaw & (1 << ch)) >> ch) * 1.0 / (1 << (15 - ch))

        pfMeasured = f

        angleMeasured = acos(pfMeasured)
        angleExp = acos(pfExp)
        angleMeasuredDeg = angleMeasured * 180.0 / 3.14159
        angleExpDeg = angleExp * 180.0 / 3.14159

        phi = (angleMeasuredDeg - angleExpDeg) * 40.0

        (retVal, byteArray) = self.__registerReadNBytes(0x00, 0x76, 2)

        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        # phase compensation is stored as an 8-bit 2's complement number
        # (in a 16 bit register)
        pcRaw = byteArray[2]
        if pcRaw > 127:
            pcRaw = pcRaw - 256
        phaseComp = pcRaw

        phaseCompNew = phaseComp + phi

        # New value has to be between 127 and -128 and has to be converted
        # back to an 8 bit integer for transmission
        if (phaseCompNew > 127 or phaseCompNew < -128):
            retVal = self.Error_code.ERROR_VALUE_OUT_OF_BOUNDS.value
        else:
            ## Calibrating phase
            bytes = [0] * 2
            # converting back to 8 bit unsigned integer representation of
            # two's complement value
            bytes[0] = phaseCompNew if (phaseCompNew >= 0) else (256 +
                                                                 phaseCompNew)
            bytes[1] = 0

            retVal = self.__registerWriteNBytes(0x00, 0x76, 2, bytes)

        return retVal

    ## This method saves the contents of all calibration
    ## and configuration registers to flash. Use with caution!

    def saveToFlash(self):
        return self.__issueAckNackCommand(
            self.__Command_code.COMMAND_SAVE_TO_FLASH.value)

    # This will revert the MCP39F521 to its factory settings and
    # remove any calibration data. Use with extreme caution!!!!

    def factoryReset(self):
        byteArray = [0] * 2
        byteArray[0] = 0xa5
        byteArray[1] = 0xa5

        retVal = self.__registerWriteNBytes(0x00, 0x5e, 2, byteArray)

        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        retVal = self.saveToFlash()

        return retVal

    ## This method will reset the calibration values to Dr. Wattson

    def resetCalibration(self,
                         cc=calibration_config.CALIBRATION_CONFIG_4A.value):
        global calibConfig
        retVal = self.Error_code.SUCCESS.value

        retVal = self.setSystemConfigurationRegister(
            calibConfig[cc].systemConfig)  # Channel 1 Gain 4, Channel 0 Gain 1
        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        retVal = self.setAccumulationIntervalRegister(
            calibConfig[cc].accumInt)  # Accumulation interval 5
        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        ## We need to apply correction factor where accumulation interval is not 2;
        if (calibConfig[cc].accumInt > 2):
            self._energy_accum_correction_factor = (calibConfig[cc].accumInt -
                                                    2)

        retVal = self.writeDesignConfigRegisters(
            calibConfig[cc].designConfigData)
        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        retVal = self.writeGains(calibConfig[cc].gainCurrentRMS,
                                 calibConfig[cc].gainVoltageRMS,
                                 calibConfig[cc].gainActivePower,
                                 calibConfig[cc].gainReactivePower)
        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        retVal = self.writePhaseCompensation(calibConfig[cc].phaseCompensation)
        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        retVal = self.saveToFlash()
        if (retVal != self.Error_code.SUCCESS.value):
            return retVal

        return self.Error_code.SUCCESS.value

    # END --- WARNING!!! WARNING!!! WARNING!!!

    ## Bit manipulation convenience methods

    # Check to see if the kth bit is set in value n
    # (where k starts with 0 for the least significant bit
    def bitRead(self, n, k):
        return n & (1 << k)

    # Set the kth bit in value n
    # (where k starts with 0 for the least significant bit
    def bitSet(self, n, k):
        return n | (1 << k)

    # Clear the kth bit in value n
    # (where k starts with 0 for the least significant bit
    def bitClear(self, n, k):
        return n ^ (1 << k)

    ## Private methods ---

    ## Read the contents of the registers starting with the starting address,
    ## up to the number of bytes specified.

    def __registerReadNBytes(self, addressHigh, addressLow, numBytesToRead):
        """Implementation of RegisterReadNBytes """
        data = [
            0xa5, 0x08, self.__Command_code.COMMAND_SET_ADDRESS_POINTER.value,
            addressHigh, addressLow,
            self.__Command_code.COMMAND_REGISTER_READ_N_BYTES.value,
            numBytesToRead
        ]
        checksum = 0
        for x in data:
            checksum += x
        # Add checksum at the end
        data.append(checksum % 256)

        write = i2c_msg.write(self._address, data)
        self._bus.i2c_rdwr(write)

        time.sleep(0.05)

        read = i2c_msg.read(self._address, numBytesToRead + 3)
        self._bus.i2c_rdwr(read)

        buf = []
        buf.extend(read)
        # print buf

        return (self.__checkHeaderAndChecksum(numBytesToRead, buf), buf)

    ## Write to the registers, starting from the starting address the number of bytes
    ## specified in the byteArray

    def __registerWriteNBytes(self, addressHigh, addressLow, numBytes,
                              byteArray):
        """Implementation of registerWriteNBytes """
        data = [
            0xa5, numBytes + 8,
            self.__Command_code.COMMAND_SET_ADDRESS_POINTER.value, addressHigh,
            addressLow,
            self.__Command_code.COMMAND_REGISTER_WRITE_N_BYTES.value, numBytes
        ]
        ## data here
        data.extend(byteArray)
        # print data

        ## compute and fill checksum as last element
        checksum = 0
        for x in data:
            checksum += x
        data.append(checksum % 256)

        write = i2c_msg.write(self._address, data)
        self._bus.i2c_rdwr(write)

        time.sleep(0.05)

        header = self._bus.read_byte(self._address)
        self._logger.debug(header)

        return self.__checkHeader(header)

    ## Some commands are issued and just return an ACK (or NAK)
    ## This method factors out those types of commands
    ## and takes in as argument the specified command to issue.

    def __issueAckNackCommand(self, command):
        """Implementation of issueAckNackCommand """
        # header, numBytes, command
        data = [0xa5, 0x04, command]
        checksum = 0
        for x in data:
            checksum += x
        # Add checksum at the end
        data.append(checksum % 256)

        write = i2c_msg.write(self._address, data)
        self._bus.i2c_rdwr(write)

        time.sleep(0.05)

        ## Read the ack
        header = self._bus.read_byte(self._address)
        self._logger.debug(header)

        return self.__checkHeader(header)

    ## Convenience method to check the header and the checksum for the returned data.
    ## If all is good, this method should return SUCCESS

    def __checkHeaderAndChecksum(self, numBytesToRead, byteArray):
        """Implementation of checkHeaderAndChecksum """
        checksumTotal = 0
        header = byteArray[0]
        dataLen = byteArray[1]
        checksum = byteArray[numBytesToRead + 3 - 1]

        for i in range(0, numBytesToRead + 3 - 1):
            checksumTotal += byteArray[i]

        calculatedChecksum = checksumTotal % 256
        error = self.Error_code.SUCCESS.value

        error = self.__checkHeader(header)

        if (calculatedChecksum != checksum):
            error = self.Error_code.ERROR_CHECKSUM_MISMATCH.value

        return error

    ## Convenience method to check the header of the response.
    ## If all is good, this will return SUCCESS

    def __checkHeader(self, header):
        """Implementation of checkHeader """
        error = self.Error_code.SUCCESS.value
        if (header != self.__Response_code.RESPONSE_ACK.value):
            error = self.Error_code.ERROR_INCORRECT_HEADER.value

        if (header == self.__Response_code.RESPONSE_CSFAIL.value):
            error = self.Error_code.ERROR_CHECKSUM_FAIL.value

        return error
コード例 #18
0
ファイル: __init__.py プロジェクト: weijentu/sgp30-python
class SGP30:
    def __init__(self, i2c_dev=None, i2c_msg=None, i2c_addr=SGP30_I2C_ADDR):
        """Mapping table of SGP30 commands.

        Friendly-name, followed by 16-bit command,
        then the number of parameter and response words.

        Each word is two bytes followed by a third CRC
        checksum byte. So a response length of 2 would
        result in the transmission of 6 bytes total.
        """
        self.commands = {
            'init_air_quality': (0x2003, 0, 0),
            'measure_air_quality': (0x2008, 0, 2),
            'get_baseline': (0x2015, 0, 2),
            'set_baseline': (0x201e, 2, 0),
            'set_humidity': (0x2061, 1, 0),
            # 'measure_test': (0x2032, 0, 1),  # Production verification only
            'get_feature_set_version': (0x202f, 0, 1),
            'measure_raw_signals': (0x2050, 0, 2),
            'get_serial_id': (0x3682, 0, 3)
        }

        self._i2c_addr = i2c_addr
        self._i2c_dev = i2c_dev
        self._i2c_msg = i2c_msg
        if self._i2c_dev is None:
            from smbus2 import SMBus, i2c_msg
            self._i2c_msg = i2c_msg
            self._i2c_dev = SMBus(1)

    def command(self, command_name, parameters=None):
        if parameters is None:
            parameters = []
        parameters = list(parameters)
        cmd, param_len, response_len = self.commands[command_name]
        if len(parameters) != param_len:
            raise ValueError("{} requires {} parameters. {} supplied!".format(
                command_name, param_len, len(parameters)))

        parameters_out = [cmd]

        for i in range(len(parameters)):
            parameters_out.append(parameters[i])
            parameters_out.append(self.calculate_crc(parameters[i]))

        data_out = struct.pack('>H' + ('HB' * param_len), *parameters_out)

        msg_w = self._i2c_msg.write(self._i2c_addr, data_out)
        self._i2c_dev.i2c_rdwr(msg_w)
        time.sleep(0.025)  # Suitable for all commands except 'measure_test'

        if response_len > 0:
            # Each parameter is a word (2 bytes) followed by a CRC (1 byte)
            msg_r = self._i2c_msg.read(self._i2c_addr, response_len * 3)
            self._i2c_dev.i2c_rdwr(msg_r)

            buf = msg_r.buf[0:response_len * 3]

            response = struct.unpack('>' + ('HB' * response_len), buf)

            verified = []
            for i in range(response_len):
                offset = i * 2
                value, crc = response[offset:offset + 2]
                if crc != self.calculate_crc(value):
                    raise RuntimeError(
                        "Invalid CRC in response from SGP30: {:02x} != {:02x}",
                        crc, self.calculate_crc(value), buf)
                verified.append(value)
            return verified

    def calculate_crc(self, data):
        """Calculate an 8-bit CRC from a 16-bit word

        Defined in section 6.6 of the SGP30 datasheet.

        Polynominal: 0x31 (x8 + x5 + x4 + x1)
        Initialization: 0xFF
        Reflect input/output: False
        Final XOR: 0x00

        """
        crc = 0xff  # Initialization value
        # calculates 8-Bit checksum with given polynomial
        for byte in [(data & 0xff00) >> 8, data & 0x00ff]:
            crc ^= byte
            for _ in range(8):
                if crc & 0x80:
                    crc = (crc << 1) ^ 0x31  # XOR with polynominal
                else:
                    crc <<= 1
        return crc & 0xff

    def get_unique_id(self):
        result = self.command('get_serial_id')
        return result[0] << 32 | result[1] << 16 | result[0]

    def get_feature_set_version(self):
        result = self.command('get_feature_set_version')[0]
        return (result & 0xf000) >> 12, result & 0x00ff

    def start_measurement(self, run_while_waiting=None):
        """Start air quality measurement on the SGP30.

        The first 15 readings are discarded so this command will block for 15s.

        :param run_while_waiting: Function to call for every discarded reading.

        """
        self.command('init_air_quality')
        testsamples = 0
        while True:
            # Discard the initialisation readings as per page 8/15 of the datasheet
            eco2, tvoc = self.command('measure_air_quality')
            # The first 15 readings should return as 400, 0 so abort when they change
            # Break after 20 test samples to avoid a potential infinite loop
            if eco2 != 400 or tvoc != 0 or testsamples >= 20:
                break
            if callable(run_while_waiting):
                run_while_waiting()
            time.sleep(1.0)
            testsamples += 1

    def get_air_quality(self):
        """Get an air quality measurement.

        Returns an instance of SGP30Reading with the properties equivalent_co2 and total_voc.

        This should be called at 1s intervals to ensure the dynamic baseline compensation on the SGP30 operates correctly.

        """
        eco2, tvoc = self.command('measure_air_quality')
        return SGP30Reading(eco2, tvoc)

    def get_baseline(self):
        """Get the current baseline setting.

        Returns an instance of SGP30Reading with the properties equivalent_co2 and total_voc.

        """
        eco2, tvoc = self.command('get_baseline')
        return SGP30Reading(eco2, tvoc)

    def set_baseline(self, eco2, tvoc):
        self.command('set_baseline', [tvoc, eco2])

    def __del__(self):
        self._i2c_dev.close()
コード例 #19
0
ファイル: rob-comm-test.py プロジェクト: llfl/Pi-puck
ROB_ADDR = 0x1F
ACTUATORS_SIZE = 20
SENSORS_SIZE = 47

try:
    bus = SMBus(I2C_CHANNEL)
except:
    sys.exit(1)

actuators_data = bytearray([0] * ACTUATORS_SIZE)
sensors_data = bytearray([0] * SENSORS_SIZE)
actuators_data[4] = 3

try:
    write = i2c_msg.write(ROB_ADDR, actuators_data)
    read = i2c_msg.read(ROB_ADDR, SENSORS_SIZE)
    bus.i2c_rdwr(write, read)
    sensors_data = list(read)
    #print(str(len(sensors_data)))
    #print(sensors_data)
except:
    sys.exit(1)

if len(sensors_data) < 0:
    sys.exit(1)

#print("sel = " + str(sensors_data[24]))
if (sensors_data[40] & 0x0F) != 10:
    sys.exit(2)

sys.exit(0)
コード例 #20
0
ファイル: __init__.py プロジェクト: dgatwood/ioe-c
class IOE():
    def __init__(self,
                 i2c_addr=I2C_ADDR,
                 interrupt_timeout=1.0,
                 interrupt_pin=None,
                 gpio=None,
                 skip_chip_id_check=False):
        self._i2c_addr = i2c_addr
        self._i2c_dev = SMBus(1)
        self._debug = False
        self._vref = 3.3
        self._timeout = interrupt_timeout
        self._interrupt_pin = interrupt_pin
        self._gpio = gpio
        self._encoder_offset = [0, 0, 0, 0]
        self._encoder_last = [0, 0, 0, 0]

        if self._interrupt_pin is not None:
            if self._gpio is None:
                import RPi.GPIO as GPIO
                self._gpio = GPIO
            self._gpio.setwarnings(False)
            self._gpio.setmode(GPIO.BCM)
            self._gpio.setup(self._interrupt_pin,
                             GPIO.IN,
                             pull_up_down=GPIO.PUD_OFF)
            self.enable_interrupt_out()

        self._pins = [
            PWM_PIN(1, 5, 5, REG_PIOCON1),
            PWM_PIN(1, 0, 2, REG_PIOCON0),
            PWM_PIN(1, 2, 0, REG_PIOCON0),
            PWM_PIN(1, 4, 1, REG_PIOCON0),
            PWM_PIN(0, 0, 3, REG_PIOCON0),
            PWM_PIN(0, 1, 4, REG_PIOCON0),
            ADC_OR_PWM_PIN(1, 1, 7, 1, REG_PIOCON0),
            ADC_OR_PWM_PIN(0, 3, 6, 5, REG_PIOCON0),
            ADC_OR_PWM_PIN(0, 4, 5, 3, REG_PIOCON1),
            ADC_PIN(3, 0, 1),
            ADC_PIN(0, 6, 3),
            ADC_OR_PWM_PIN(0, 5, 4, 2, REG_PIOCON1),
            ADC_PIN(0, 7, 2),
            ADC_PIN(1, 7, 0)
        ]

        if not skip_chip_id_check:
            chip_id = (self.i2c_read8(REG_CHIP_ID_H) <<
                       8) | self.i2c_read8(REG_CHIP_ID_L)
            if chip_id != CHIP_ID:
                raise RuntimeError(
                    "Chip ID invalid: {:04x} expected: {:04x}.".format(
                        chip_id, CHIP_ID))

    def i2c_read8(self, reg):
        """Read a single (8bit) register from the device."""
        msg_w = i2c_msg.write(self._i2c_addr, [reg])
        msg_r = i2c_msg.read(self._i2c_addr, 1)
        self._i2c_dev.i2c_rdwr(msg_w, msg_r)

        return list(msg_r)[0]

    def i2c_write8(self, reg, value):
        """Write a single (8bit) register to the device."""
        msg_w = i2c_msg.write(self._i2c_addr, [reg, value])
        self._i2c_dev.i2c_rdwr(msg_w)

    def setup_rotary_encoder(self,
                             channel,
                             pin_a,
                             pin_b,
                             pin_c=None,
                             count_microsteps=False):
        """Set up a rotary encoder."""
        channel -= 1
        self.set_mode(pin_a, PIN_MODE_PU, schmitt_trigger=True)
        self.set_mode(pin_b, PIN_MODE_PU, schmitt_trigger=True)
        if pin_c is not None:
            self.set_mode(pin_c, PIN_MODE_OD)
            self.output(pin_c, 0)

        self.i2c_write8(
            [REG_ENC_1_CFG, REG_ENC_2_CFG, REG_ENC_3_CFG,
             REG_ENC_4_CFG][channel], pin_a | (pin_b << 4))
        self.change_bit(REG_ENC_EN, channel * 2 + 1, count_microsteps)
        self.set_bit(REG_ENC_EN, channel * 2)

    def read_rotary_encoder(self, channel):
        """Read the step count from a rotary encoder."""
        channel -= 1
        last = self._encoder_last[channel]
        reg = [
            REG_ENC_1_COUNT, REG_ENC_2_COUNT, REG_ENC_3_COUNT, REG_ENC_4_COUNT
        ][channel]
        value = self.i2c_read8(reg)

        if value & 0b10000000:
            value -= 256

        if last > 64 and value < -64:
            self._encoder_offset[channel] += 256
        if last < -64 and value > 64:
            self._encoder_offset[channel] -= 256

        self._encoder_last[channel] = value

        return self._encoder_offset[channel] + value

    def set_bits(self, reg, bits):
        """Set the specified bits (using a mask) in a register."""
        if reg in BIT_ADDRESSED_REGS:
            for bit in range(8):
                if bits & (1 << bit):
                    self.i2c_write8(reg, 0b1000 | (bit & 0b111))
        else:
            value = self.i2c_read8(reg)
            time.sleep(0.001)
            self.i2c_write8(reg, value | bits)

    def set_bit(self, reg, bit):
        """Set the specified bit (nth position from right) in a register."""
        self.set_bits(reg, (1 << bit))

    def clr_bits(self, reg, bits):
        """Clear the specified bits (using a mask) in a register."""
        if reg in BIT_ADDRESSED_REGS:
            for bit in range(8):
                if bits & (1 << bit):
                    self.i2c_write8(reg, 0b0000 | (bit & 0b111))
        else:
            value = self.i2c_read8(reg)
            time.sleep(0.001)
            self.i2c_write8(reg, value & ~bits)

    def clr_bit(self, reg, bit):
        """Clear the specified bit (nth position from right) in a register."""
        self.clr_bits(reg, (1 << bit))

    def get_bit(self, reg, bit):
        """Returns the specified bit (nth position from right) from a register."""
        return self.i2c_read8(reg) & (1 << bit)

    def change_bit(self, reg, bit, state):
        """Toggle one register bit on/off."""
        if state:
            self.set_bit(reg, bit)
        else:
            self.clr_bit(reg, bit)

    def enable_interrupt_out(self, pin_swap=False):
        """Enable the IOE interrupts."""
        self.set_bit(REG_INT, BIT_INT_OUT_EN)
        self.change_bit(REG_INT, BIT_INT_PIN_SWAP, pin_swap)

    def disable_interrupt_out(self):
        """Disable the IOE interrupt output."""
        self.clr_bit(REG_INT, BIT_INT_OUT_EN)

    def get_interrupt(self):
        """Get the IOE interrupt state."""
        if self._interrupt_pin is not None:
            return self._gpio.input(self._interrupt_pin) == 0
        else:
            return self.get_bit(REG_INT, BIT_INT_TRIGD)

    def clear_interrupt(self):
        """Clear the interrupt flag."""
        self.clr_bit(REG_INT, BIT_INT_TRIGD)

    def set_pin_interrupt(self, pin, enabled):
        """Enable/disable the input interrupt on a specific pin.

        :param pin: Pin from 1-14
        :param enabled: True/False for enabled/disabled

        """
        if pin < 1 or pin > len(self._pins):
            raise ValueError("Pin should be in range 1-14.")

        io_pin = self._pins[pin - 1]

        self.change_bit(io_pin.reg_int_mask_p, io_pin.pin, enabled)

    def on_interrupt(self, callback):
        """Attach an event handler to be run on interrupt.

        :param callback: Callback function to run: callback(pin)

        """
        if self._interrupt_pin is not None:
            self._gpio.add_event_detect(self._interrupt_pin,
                                        self._gpio.FALLING,
                                        callback=callback,
                                        bouncetime=1)

    def _wait_for_flash(self):
        """Wait for the IOE to finish writing non-volatile memory."""
        t_start = time.time()
        while self.get_interrupt():
            if time.time() - t_start > self._timeout:
                raise RuntimeError("Timed out waiting for interrupt!")
            time.sleep(0.001)

        t_start = time.time()
        while not self.get_interrupt():
            if time.time() - t_start > self._timeout:
                raise RuntimeError("Timed out waiting for interrupt!")
            time.sleep(0.001)

    def set_i2c_addr(self, i2c_addr):
        """Set the IOE i2c address."""
        self.set_bit(REG_CTRL, 4)
        self.i2c_write8(REG_ADDR, i2c_addr)
        self._i2c_addr = i2c_addr
        time.sleep(0.25)  # TODO Handle addr change IOError better
        # self._wait_for_flash()
        self.clr_bit(REG_CTRL, 4)

    def set_adc_vref(self, vref):
        """Set the ADC voltage reference."""
        self._vref = vref

    def get_adc_vref(self):
        """Get the ADC voltage reference."""
        return self._vref

    def get_chip_id(self):
        """Get the IOE chip ID."""
        return (
            self.i2c_read8(REG_CHIP_ID_H) << 8) | self.i2c_read8(REG_CHIP_ID_L)

    def _pwm_load(self):
        # Load new period and duty registers into buffer
        t_start = time.time()
        self.set_bit(REG_PWMCON0, 6)  # Set the "LOAD" bit of PWMCON0
        while self.get_bit(REG_PWMCON0, 6):
            time.sleep(0.001)  # Wait for "LOAD" to complete
            if time.time() - t_start >= self._timeout:
                raise RuntimeError("Timed out waiting for PWM load!")

    def set_pwm_control(self, divider):
        """Set PWM settings.

        PWM is driven by the 24MHz FSYS clock by default.

        :param divider: Clock divider, one of 1, 2, 4, 8, 16, 32, 64 or 128

        """
        try:
            pwmdiv2 = {
                1: 0b000,
                2: 0b001,
                4: 0b010,
                8: 0b011,
                16: 0b100,
                32: 0b101,
                64: 0b110,
                128: 0b111
            }[divider]
        except KeyError:
            raise ValueError("A clock divider of {}".format(divider))

        # TODO: This currently sets GP, PWMTYP and FBINEN to 0
        # It might be desirable to make these available to the user
        # GP - Group mode enable (changes first three pairs of pAM to PWM01H and PWM01L)
        # PWMTYP - PWM type select: 0 edge-aligned, 1 center-aligned
        # FBINEN - Fault-break input enable

        self.i2c_write8(REG_PWMCON1, pwmdiv2)

    def set_pwm_period(self, value):
        """Set the PWM period.

        The period is the point at which the PWM counter is reset to zero.

        The PWM clock runs at FSYS with a divider of 1/1.

        Also specifies the maximum value that can be set in the PWM duty cycle.

        """
        value &= 0xffff
        self.i2c_write8(REG_PWMPL, value & 0xff)
        self.i2c_write8(REG_PWMPH, value >> 8)

        self._pwm_load()

    def get_mode(self, pin):
        """Get the current mode of a pin."""
        return self._pins[pin - 1].mode

    def set_mode(self, pin, mode, schmitt_trigger=False, invert=False):
        """Set a pin output mode.

        :param mode: one of the supplied IN, OUT, PWM or ADC constants

        """
        if pin < 1 or pin > len(self._pins):
            raise ValueError("Pin should be in range 1-14.")

        io_pin = self._pins[pin - 1]
        if io_pin.mode == mode:
            return

        gpio_mode = mode & 0b11
        io_mode = (mode >> 2) & 0b11
        initial_state = mode >> 4

        if io_mode != PIN_MODE_IO and mode not in io_pin.type:
            raise ValueError("Pin {} does not support {}!".format(
                pin, MODE_NAMES[io_mode]))

        io_pin.mode = mode
        if self._debug:
            print("Setting pin {pin} to mode {mode} {name}, state: {state}".
                  format(pin=pin,
                         mode=MODE_NAMES[io_mode],
                         name=GPIO_NAMES[gpio_mode],
                         state=STATE_NAMES[initial_state]))

        if mode == PIN_MODE_PWM:
            self.set_bit(io_pin.reg_iopwm, io_pin.pwm_channel)
            self.change_bit(REG_PNP, io_pin.pwm_channel, invert)
            self.set_bit(REG_PWMCON0, 7)  # Set PWMRUN bit

        else:
            if PIN_MODE_PWM in io_pin.type:
                self.clr_bit(io_pin.reg_iopwm, io_pin.pwm_channel)

        pm1 = self.i2c_read8(io_pin.reg_m1)
        pm2 = self.i2c_read8(io_pin.reg_m2)

        # Clear the pm1 and pm2 bits
        pm1 &= 255 - (1 << io_pin.pin)
        pm2 &= 255 - (1 << io_pin.pin)

        # Set the new pm1 and pm2 bits according to our gpio_mode
        pm1 |= (gpio_mode >> 1) << io_pin.pin
        pm2 |= (gpio_mode & 0b1) << io_pin.pin

        self.i2c_write8(io_pin.reg_m1, pm1)
        self.i2c_write8(io_pin.reg_m2, pm2)

        # Set up Schmitt trigger mode on inputs
        if mode in [PIN_MODE_PU, PIN_MODE_IN]:
            self.change_bit(io_pin.reg_ps, io_pin.pin, schmitt_trigger)

        # 5th bit of mode encodes default output pin state
        self.i2c_write8(io_pin.reg_p, (initial_state << 3) | io_pin.pin)

    def input(self, pin, adc_timeout=1):
        """Read the IO pin state.

        Returns a 12-bit ADC reading if the pin is in ADC mode
        Returns True/False if the pin is in any other input mode
        Returns None if the pin is in PWM mode

        :param adc_timeout: Timeout (in seconds) for an ADC read (default 1.0)

        """
        if pin < 1 or pin > len(self._pins):
            raise ValueError("Pin should be in range 1-14.")

        io_pin = self._pins[pin - 1]

        if io_pin.mode == PIN_MODE_ADC:
            if self._debug:
                print("Reading ADC from pin {}".format(pin))
                print("ADC channel {}".format(io_pin.adc_channel))
            self.clr_bits(REG_ADCCON0, 0x0f)
            self.set_bits(REG_ADCCON0, io_pin.adc_channel)
            self.i2c_write8(REG_AINDIDS, 0)
            self.set_bit(REG_AINDIDS, io_pin.adc_channel)
            self.set_bit(REG_ADCCON1, 0)

            self.clr_bit(REG_ADCCON0,
                         7)  # ADCF - Clear the conversion complete flag
            self.set_bit(REG_ADCCON0,
                         6)  # ADCS - Set the ADC conversion start flag

            # Wait for the ADCF conversion complete flag to be set
            t_start = time.time()
            while not self.get_bit(REG_ADCCON0, 7):
                time.sleep(0.01)
                if time.time() - t_start >= adc_timeout:
                    raise RuntimeError("Timeout waiting for ADC conversion!")

            hi = self.i2c_read8(REG_ADCRH)
            lo = self.i2c_read8(REG_ADCRL)
            return ((hi << 4) | lo) / 4095.0 * self._vref

        else:
            if self._debug:
                print("Reading IO from pin {}".format(pin))
            pv = self.get_bit(io_pin.reg_p, io_pin.pin)

            return HIGH if pv else LOW

    def output(self, pin, value):
        """Write an IO pin state or PWM duty cycle.

        :param value: Either True/False for OUT, or a number between 0 and PWM period for PWM.

        """
        if pin < 1 or pin > len(self._pins):
            raise ValueError("Pin should be in range 1-14.")

        io_pin = self._pins[pin - 1]

        if io_pin.mode == PIN_MODE_PWM:
            if self._debug:
                print("Outputting PWM to pin: {pin}".format(pin=pin))
            self.i2c_write8(io_pin.reg_pwml, value & 0xff)
            self.i2c_write8(io_pin.reg_pwmh, value >> 8)
            self._pwm_load()

        else:
            if value == LOW:
                if self._debug:
                    print("Outputting LOW to pin: {pin}".format(pin=pin,
                                                                value=value))
                self.clr_bit(io_pin.reg_p, io_pin.pin)
            elif value == HIGH:
                if self._debug:
                    print("Outputting HIGH to pin: {pin}".format(pin=pin,
                                                                 value=value))
                self.set_bit(io_pin.reg_p, io_pin.pin)
コード例 #21
0
class VL53L1X:
    """VL53L1X ToF."""
    def __init__(self,
                 i2c_bus=1,
                 i2c_address=0x29,
                 tca9548a_num=255,
                 tca9548a_addr=0):
        """Initialize the VL53L1X ToF Sensor from ST"""
        self._i2c_bus = i2c_bus
        self.i2c_address = i2c_address
        self._tca9548a_num = tca9548a_num
        self._tca9548a_addr = tca9548a_addr
        self._i2c = SMBus(1)
        self._dev = None
        # Resgiter Address
        self.ADDR_UNIT_ID_HIGH = 0x16  # Serial number high byte
        self.ADDR_UNIT_ID_LOW = 0x17  # Serial number low byte
        self.ADDR_I2C_ID_HIGH = 0x18  # Write serial number high byte for I2C address unlock
        self.ADDR_I2C_ID_LOW = 0x19  # Write serial number low byte for I2C address unlock
        self.ADDR_I2C_SEC_ADDR = 0x8a  # Write new I2C address after unlock

    def open(self):
        self._i2c.open(bus=self._i2c_bus)
        self._configure_i2c_library_functions()
        self._dev = _TOF_LIBRARY.initialise(self.i2c_address)

    def close(self):
        self._i2c.close()
        self._dev = None

    def _configure_i2c_library_functions(self):
        # I2C bus read callback for low level library.
        def _i2c_read(address, reg, data_p, length):
            ret_val = 0

            msg_w = i2c_msg.write(address, [reg >> 8, reg & 0xff])
            msg_r = i2c_msg.read(address, length)

            self._i2c.i2c_rdwr(msg_w, msg_r)

            if ret_val == 0:
                for index in range(length):
                    data_p[index] = ord(msg_r.buf[index])

            return ret_val

        # I2C bus write callback for low level library.
        def _i2c_write(address, reg, data_p, length):
            ret_val = 0
            data = []

            for index in range(length):
                data.append(data_p[index])

            msg_w = i2c_msg.write(address, [reg >> 8, reg & 0xff] + data)

            self._i2c.i2c_rdwr(msg_w)

            return ret_val

        # Pass i2c read/write function pointers to VL53L1X library.
        self._i2c_read_func = _I2C_READ_FUNC(_i2c_read)
        self._i2c_write_func = _I2C_WRITE_FUNC(_i2c_write)
        _TOF_LIBRARY.VL53L1_set_i2c(self._i2c_read_func, self._i2c_write_func)

    def start_ranging(self, mode=VL53L1xDistanceMode.LONG):
        """Start VL53L1X ToF Sensor Ranging"""
        _TOF_LIBRARY.startRanging(self._dev, mode)

    def stop_ranging(self):
        """Stop VL53L1X ToF Sensor Ranging"""
        _TOF_LIBRARY.stopRanging(self._dev)

    def get_distance(self):
        """Get distance from VL53L1X ToF Sensor"""
        return _TOF_LIBRARY.getDistance(self._dev)

    # This function included to show how to access the ST library directly
    # from python instead of through the simplified interface
    def get_timing(self):
        budget = c_uint(0)
        budget_p = pointer(budget)
        status = _TOF_LIBRARY.VL53L1_GetMeasurementTimingBudgetMicroSeconds(
            self._dev, budget_p)
        if status == 0:
            return budget.value + 1000
        else:
            return 0

    def change_address(self, new_address):
        _TOF_LIBRARY.setDeviceAddress(self._dev, new_address)
コード例 #22
0
ファイル: VL53L1X.py プロジェクト: NagyAttila/vl53l1x-python
class VL53L1X:
    """VL53L1X ToF."""
    def __init__(self, i2c_bus=1):
        """Initialize the VL53L1X ToF Sensor from ST"""
        self._i2c_bus = i2c_bus
        self._i2c = SMBus(1)
        self._default_dev = None
        self._dev_list = None

        # Resgiter Address
        self.ADDR_UNIT_ID_HIGH = 0x16  # Serial number high byte
        self.ADDR_UNIT_ID_LOW = 0x17  # Serial number low byte
        self.ADDR_I2C_ID_HIGH = 0x18  # Write serial number high byte for I2C address unlock
        self.ADDR_I2C_ID_LOW = 0x19  # Write serial number low byte for I2C address unlock
        self.ADDR_I2C_SEC_ADDR = 0x8a  # Write new I2C address after unlock

    def open(self):
        self._i2c.open(bus=self._i2c_bus)
        self._configure_i2c_library_functions()
        self._default_dev = _TOF_LIBRARY.initialise()
        self._dev_list = dict()

    def add_sensor(self, sensor_id, address):
        self._dev_list[sensor_id] = _TOF_LIBRARY.copy_dev(self._default_dev)
        _TOF_LIBRARY.init_dev(self._dev_list[sensor_id], c_uint8(address))

    def close(self):
        self._i2c.close()
        self._default_dev = None
        self._dev_list = None

    def _configure_i2c_library_functions(self):
        # I2C bus read callback for low level library.
        def _i2c_read(address, reg, data_p, length):
            ret_val = 0

            msg_w = i2c_msg.write(address, [reg >> 8, reg & 0xff])
            msg_r = i2c_msg.read(address, length)

            # print("R: a: %x\tr:%d" % (address,reg))
            try:
                self._i2c.i2c_rdwr(msg_w, msg_r)
            except:
                print("Cannot read on 0x%x I2C bus, reg: %d" % (address, reg))

            if ret_val == 0:
                for index in range(length):
                    data_p[index] = ord(msg_r.buf[index])

            return ret_val

        # I2C bus write callback for low level library.
        def _i2c_write(address, reg, data_p, length):
            ret_val = 0
            data = []

            for index in range(length):
                data.append(data_p[index])

            msg_w = i2c_msg.write(address, [reg >> 8, reg & 0xff] + data)
            # print("W: a: %x\tr:%d" % (address,reg))

            try:
                self._i2c.i2c_rdwr(msg_w)
            except:
                print("Cannot write on 0x%x I2C bus, reg: %d" % (address, reg))

            return ret_val

        # Pass i2c read/write function pointers to VL53L1X library.
        self._i2c_read_func = _I2C_READ_FUNC(_i2c_read)
        self._i2c_write_func = _I2C_WRITE_FUNC(_i2c_write)
        _TOF_LIBRARY.VL53L1_set_i2c(self._i2c_read_func, self._i2c_write_func)

    def start_ranging(self, sensor_id, mode=VL53L1xDistanceMode.LONG):
        """Start VL53L1X ToF Sensor Ranging"""
        dev = self._dev_list[sensor_id]
        _TOF_LIBRARY.startRanging(dev, mode)

    def stop_ranging(self, sensor_id):
        """Stop VL53L1X ToF Sensor Ranging"""
        dev = self._dev_list[sensor_id]
        _TOF_LIBRARY.stopRanging(dev)

    def get_distance(self, sensor_id):
        dev = self._dev_list[sensor_id]
        return _TOF_LIBRARY.getDistance(dev)

    def get_address(self, sensor_id):
        dev = self._dev_list[sensor_id]
        return _TOF_LIBRARY.get_address(dev)

    def change_address(self, sensor_id, new_address):
        dev = self._dev_list[sensor_id]
        _TOF_LIBRARY.setDeviceAddress(dev, new_address)
コード例 #23
0
ファイル: AntennaDeployer.py プロジェクト: TJREVERB/pfs
class AntennaDeployer(Device):
    BUS_NUMBER = 1
    PRIMARY_ADDRESS = 0x31
    SECONDARY_ADDRESS = 0x32
    EXPECTED_BYTES = {
        AntennaDeployerCommand.SYSTEM_RESET: 0,
        AntennaDeployerCommand.WATCHDOG_RESET: 0,

        AntennaDeployerCommand.ARM_ANTS: 0,
        AntennaDeployerCommand.DISARM_ANTS: 0,

        AntennaDeployerCommand.DEPLOY_1: 0,
        AntennaDeployerCommand.DEPLOY_2: 0,
        AntennaDeployerCommand.DEPLOY_3: 0,
        AntennaDeployerCommand.DEPLOY_4: 0,

        AntennaDeployerCommand.AUTO_DEPLOY: 0,
        AntennaDeployerCommand.CANCEL_DEPLOY: 0,

        AntennaDeployerCommand.DEPLOY_1_OVERRIDE: 0,
        AntennaDeployerCommand.DEPLOY_2_OVERRIDE: 0,
        AntennaDeployerCommand.DEPLOY_3_OVERRIDE: 0,
        AntennaDeployerCommand.DEPLOY_4_OVERRIDE: 0,

        AntennaDeployerCommand.GET_TEMP: 2,
        AntennaDeployerCommand.GET_STATUS: 2,

        AntennaDeployerCommand.GET_COUNT_1: 1,
        AntennaDeployerCommand.GET_COUNT_2: 1,
        AntennaDeployerCommand.GET_COUNT_3: 1,
        AntennaDeployerCommand.GET_COUNT_4: 1,

        AntennaDeployerCommand.GET_UPTIME_1: 2,
        AntennaDeployerCommand.GET_UPTIME_2: 2,
        AntennaDeployerCommand.GET_UPTIME_3: 2,
        AntennaDeployerCommand.GET_UPTIME_4: 2,
    }

    def __init__(self):
        super().__init__("AntennaDeployer")
        self.bus = SMBus()

    def write(self, command: AntennaDeployerCommand, parameter: int) -> bool or None:
        """
        Wrapper for SMBus write word data
        :param command: (AntennaDeployerCommand) The antenna deployer command to run
        :param parameter: (int) The parameter to pass in to the command (usually 0x00)
        :return: (bool or None) success
        """
        if type(command) != AntennaDeployerCommand:
            return

        try:
            self.bus.open(self.BUS_NUMBER)
            self.bus.write_word_data(self.PRIMARY_ADDRESS, command.value, parameter)
            self.bus.close()
        except:
            return False

        return True

    def read(self, command: AntennaDeployerCommand) -> bytes or None:
        """
        Wrapper for SMBus to read from AntennaDeployer
        :param command: (AntennaDeployerCommand) The antenna deployer command to run
        :return: (ctypes.LP_c_char, bool) buffer, success
        """
        if type(command) != AntennaDeployerCommand:
            return

        success = self.write(command, 0x00)
        if not success:
            return None, False

        time.sleep(0.5)
        try:
            i2c_obj = i2c_msg.read(self.PRIMARY_ADDRESS, self.EXPECTED_BYTES[command])
            self.bus.open(self.BUS_NUMBER)
            self.bus.i2c_rdwr(i2c_obj)
            self.bus.close()
            return i2c_obj.buf, True
        except:
            return None, False

    def functional(self):
        """
        :return: (bool) i2c file opened by SMBus
        """
        return self.bus.fd is not None

    def reset(self):
        """
        Resets the Microcontroller on the ISIS Antenna Deployer
        :return: (bool) no error
        """
        try:
            self.bus.open(self.BUS_NUMBER)
            self.write(AntennaDeployerCommand.SYSTEM_RESET, 0x00)
            self.bus.close()
            return True
        except:
            return False

    def disable(self):
        """
        Disarms the ISIS Antenna Deployer
        """
        try:
            self.bus.open(self.BUS_NUMBER)
            self.write(AntennaDeployerCommand.DISARM_ANTS, 0x00)
            self.bus.close()
            return True
        except:
            return False

    def enable(self):
        """
        Arms the ISIS Antenna Deployer
        """
        try:
            self.bus.open(self.BUS_NUMBER)
            self.write(AntennaDeployerCommand.ARM_ANTS, 0x00)
            self.bus.close()
            return True
        except:
            return False
コード例 #24
0
class SMBus2(I2C):
    """Wrapper for smbus2 library extends :class:`I2C`
    
    Args:
        bus (int): The i2c bus of the raspberry pi. The pi has two buses.
    """
    def __init__(self, bus):
        """Constructor"""

        self.bus = bus
        if SMBus is None:
            raise ImportError("failed to import smbus2")
        self._smbus = SMBus(bus)

    def read(self, address, register, byte_num=1):
        """Read using the smbus protocol.

        Args:
            address: The address of the spi slave
            register: The register's address.
            byte_num: How many bytes to read from the device. Max 32

        Returns:
            A list with byte_num elements.
        """

        byte_num = min(byte_num, 32)
        if byte_num > 1:
            data = self._smbus.read_i2c_block_data(address, register, byte_num)
        else:
            data = self._smbus.read_byte_data(address, register)

        return data

    def write(self, address, register, data):
        """Write using the smbus protocol.

        Args:
            address: The address of the spi slave
            register: The address of the register inside the slave.
            data: A list or a single byte, if it is a list max length 32 bytes.
                It is error prone so write less and make consecutive calls.
        """

        write_func = self._smbus.write_i2c_block_data\
            if isinstance(data, list) else self._smbus.write_byte_data

        write_func(address, register, data)

    def write_i2c(self, address, register, data):
        """Write using the i2c protocol

        Args:
            address: The address of the spi slave
            register: The address of the register inside the slave.
            data: A list or a single byte, if it is a list max length 32 bytes.
        """
        data = data if isinstance(data, list) else [data]
        msg = i2c_msg.write(address, [register] + data)
        self._smbus.i2c_rdwr(msg)

    def read_i2c(self, address, byte_num):
        """Read using the i2c protocol.

        Args:
            address: The address of the spi slave
            byte_num: How many bytes to read from the device. Max 32

        Returns:
            A list with byte_num elements.
        """

        read = i2c_msg.read(address, byte_num)
        self._smbus.i2c_rdwr(read)
        res = [ord(read.buf[i]) for i in range(byte_num)]

        return res

    def read_write(self, address, register, data, byte_num):
        """Combined read and write command using the i2c protocol.
        
        Args:
            address: The address of the spi slave
            register: The address of the register inside the slave.
            data: A list or a single byte, if it is a list max length 32 bytes.
            byte_num: How many bytes to read from the device. Max 32

        Returns:
            A list with byte_num elements.
        """

        data = data if isinstance(data, list) else [data]
        write = i2c_msg.write(address, [register] + data)
        read = i2c_msg.read(address, byte_num)

        self._smbus.i2c_rdwr(write, read)
        res = [ord(read.buf[i]) for i in range(byte_num)]

        return res

    def close(self):
        self._smbus.close()

    def _set_bus(self, bus):
        self._bus = bus

    def _get_bus(self):
        return self._bus
コード例 #25
0
class I2CBus(I2CInterface):
    """An I2C bus implementation for the Raspberry Pi.

    Derived from the SMBus2 library by 'kplindegaard' at
    https://github.com/kplindegaard/smbus2.
    """
    def __init__(self, board_rev=board_revision.REV1):
        """Initialize a new instance of I2CBus.

        :param int board_rev: The board revision.
        """
        I2CInterface.__init__(self)
        self.__busID = 1
        if board_rev == board_revision.REV1:
            self.__busID = 0

        self.__isOpen = False
        self.__bus = None

    @property
    def is_open(self):
        """Get a value indicating whether the connection is open.

        :returns: True if the connection is open.
        :rtype: bool
        """
        return self.__isOpen

    def open(self):
        """Open a connection to the I2C bus.

        :raises: raspy.object_disposed_exception.ObjectDisposedException if
        this instance has been disposed.

        :raises: raspy.io.io_exception.IOException if unable to open the
        bus connection.
        """
        if self.is_disposed:
            raise ObjectDisposedException("I2CBus")

        if self.__isOpen:
            return

        try:
            self.__bus = SMBus(self.__busID)
        except OSError or IOError:
            msg = "Error opening bus '" + str(self.__busID) + "'."
            raise IOException(msg)

        if self.__bus.fd is None:
            msg = "Error opening bus '" + str(self.__busID) + "'."
            raise IOException(msg)

        self.__isOpen = True

    def close(self):
        """Close the bus connection."""
        if self.is_disposed:
            return

        if self.__isOpen:
            if self.__bus is not None:
                self.__bus.close()
            self.__isOpen = False
            self.__bus = None

    def dispose(self):
        """Dispose of all the managed resources used by this instance."""
        if self.is_disposed:
            return

        self.close()
        self.__busID = None
        I2CInterface.dispose(self)

    def write_bytes(self, address, buf):
        """Write a list of bytes to the specified device address.

        Currently, RPi drivers do not allow writing more than 3 bytes at a
        time. As such, if any list of greater than 3 bytes is provided, an
        exception is thrown.

        :param int address: The address of the target device.
        :param list buf: A list of bytes to write to the bus.
        :raises: raspy.object_disposed_exception.ObjectDisposedException if
        this instance has been disposed.

        :raises: raspy.invalid_operation_exception.InvalidOperationException if
        a connection to the I2C bus has not yet been opened.

        :raises: raspy.illegal_argument_exception.IllegalArgumentException if
        the buffer contains more than 3 bytes or if the specified buffer
        parameter is not a list.

        :raises: raspy.io.io_exception.IOException if an error occurs while
        writing the buffer contents to the I2C bus or if only a partial
        write succeeds.
        """
        if self.is_disposed:
            raise ObjectDisposedException("I2CBus")

        if not self.__isOpen:
            raise InvalidOperationException("No open connection to write to.")

        if isinstance(buf, list):
            if len(buf) > 3:
                # TODO we only do this to keep parity with the JS and C#
                # ports. They each have their own underlying native
                # implementations. SMBus2 itself is capable of writing
                # much more than 3 bytes. We should change this as soon
                # as we can get the other ports to support more.
                msg = "Cannot write more than 3 bytes at a time."
                raise IllegalArgumentException(msg)
        else:
            msg = "The specified buf param value is not a list."
            raise IllegalArgumentException(msg)

        try:
            trans = i2c_msg.write(address, buf)
            self.__bus.i2c_rdwr(trans)
        except OSError or IOError:
            msg = "Error writing to address '" + str(address)
            msg += "': I2C transaction failed."
            raise IOException(msg)

    def write_byte(self, address, byt):
        """Write a single byte to the specified device address.

        :param int address: The address of the target device.
        :param int byt: The byte value to write.
        :raises: raspy.object_disposed_exception.ObjectDisposedException if
        this instance has been disposed.

        :raises: raspy.invalid_operation_exception.InvalidOperationException if
        a connection to the I2C bus has not yet been opened.

        :raises: raspy.io.io_exception.IOException if an error occurs while
        writing the buffer contents to the I2C bus or if only a partial
        write succeeds.
        """
        buf = list()
        buf[0] = byt
        self.write_bytes(address, buf)

    def write_command(self, address, command, data1=None, data2=None):
        """Write a command with data to the specified device address.

        :param int address: The address of the target device.
        :param int command: The command to send to the device.
        :param int data1: The data to send as the first parameter (optional).
        :param int data2: The data to send as the second parameter (optional).
        :raises: raspy.object_disposed_exception.ObjectDisposedException if
        this instance has been disposed.

        :raises: raspy.invalid_operation_exception.InvalidOperationException if
        a connection to the I2C bus has not yet been opened.

        :raises: raspy.io.io_exception.IOException if an error occurs while
        writing the buffer contents to the I2C bus or if only a partial
        write succeeds.
        """
        buf = list()
        buf[0] = command

        if data1:
            buf[1] = data1

        if data1 and data2:
            buf[1] = data1
            buf[2] = data2

        self.write_bytes(address, buf)

    def write_command_byte(self, address, command, data):
        """Write a command with data to the specified device address.

        :param int address: The address of the target device.
        :param int command: The command to send to the device.
        :param int data: The data to send with the command.
        :raises: raspy.object_disposed_exception.ObjectDisposedException if
        this instance has been disposed.

        :raises: raspy.invalid_operation_exception.InvalidOperationException if
        a connection to the I2C bus has not yet been opened.

        :raises: raspy.io.io_exception.IOException if an error occurs while
        writing the buffer contents to the I2C bus or if only a partial
        write succeeds.
        """
        buf = list()
        buf[0] = command
        buf[1] = data & 0xff
        buf[2] = data >> 8
        self.write_bytes(address, buf)

    def read_bytes(self, address, count):
        """Read bytes from the device at the specified address.

        :param int address: The address of the device to read from.
        :param int count: The number of bytes to read.
        :returns: The bytes read.
        :rtype: list
        :raises: raspy.object_disposed_exception.ObjectDisposedException if
        this instance has been disposed.

        :raises: raspy.invalid_operation_exception.InvalidOperationException if
        a connection to the I2C bus has not yet been opened.

        :raises: raspy.io.io_exception.IOException if an error occurs while
        writing the buffer contents to the I2C bus or if only a partial
        write succeeds.
        """
        if self.is_disposed:
            return

        if not self.__isOpen:
            raise InvalidOperationException("No open connection to read from.")

        buf = []
        msg = "Error reading from address '" + str(address)
        msg += "': I2C transaction failed."
        try:
            trans = i2c_msg.read(address, count)
            self.__bus.i2c_rdwr(trans)
            buf = list(trans)
        except OSError or IOError:
            raise IOException(msg)

        if len(buf) <= 0:
            raise IOException(msg)

        return buf

    def read(self, address):
        """Read a single byte from the device at the specified address.

        :param int address: The address of the device to read from.
        :returns: The byte read.
        :rtype: int
        :raises: raspy.object_disposed_exception.ObjectDisposedException if
        this instance has been disposed.

        :raises: raspy.invalid_operation_exception.InvalidOperationException if
        a connection to the I2C bus has not yet been opened.

        :raises: raspy.io.io_exception.IOException if an error occurs while
        writing the buffer contents to the I2C bus or if only a partial
        write succeeds.
        """
        result = self.read_bytes(address, 1)
        return result[0]
コード例 #26
0
class TrillLib:

    def __init__(self, bus, tt, addr): # tt - trill type string addr - I2C address
        self.dataBuffer = [0] * kRawLength
        self.rawData = [0] * kNumChannelsMax
        self.bus = SMBus(bus)
        if addr >= 128 : return # so calling program will can and find a valid address
        
        # been given a validate I2C address and trill type - now check they match
        if tt in trillTypes :
            self.typeNumber = trillTypes.index(tt)
        else :
            raise BaseException("Error - " + tt +" is not a valid Trill type")
            return        
        if not (addr >= trillAddress[self.typeNumber][0] and addr <= trillAddress[self.typeNumber][1]) :
            raise BaseException("Error - " + hex(addr) +" is not a Trill type " + tt + " address")
            return
        self.addr = addr
        self.tt = tt
        
        self.modeNumber = 0
        self.max_touch_1D_or_2D = kMaxTouchNum1D
        # trill size [pos, posH, size] at index of trillTypes 
        self.deviceSize = trillSize[self.typeNumber]
        if tt == "craft" : self.setMode("DIFF")
        else: self.setMode("CENTROID") # default mode for all other types
        if self.setScanSettings(0, 12) : raise BaseException("Error - unable to set scan settings")        
        if self.updateBaseLine() : raise BaseException("Error - unable to set base line")      
        if self.prepareForDataRead() : raise BaseException("Error - unable to prepare for data read")
        # test read to see if we can access the device
        self.identify()
        self.typeNumber = self.device_type_
        tt = trillTypes[self.typeNumber]
        
    def getTypeNumber(self): # get the Trill type number of this instance 
        return self.typeNumber
    
    def getDeviceFromName(self, name): # get the Trill type string of this instance 
        if name in trillTypes : 
            return trillTypes.index(name)
        else:
            return "Invalid device name "
    
    def getNameFromMode(self, mode): # get the current Trill mode number 
        if mode < 0 or mode > 3: return "Invalid mode number"
        return modeTypes[mode]
    
    def getMode(self):    # get the current Trill mode name
        return modeTypes[self.modeNumber]
    
    def identify(self): # check that the address we have is that of a Trill device
        self.device_type_ = 0
        block = [kCommandIdentify]
        if self.txI2C(kOffsetCommand, block) : # set in the identity mode
            raise BaseException("Device not found for identify command")
        else:
            self.prepairedForDataRead_ = False
            time.sleep(commandSleepTime)
            self.rxI2C(kOffsetCommand, 4) # ignore first reading
            bytesRead = self.rxI2C(kOffsetCommand, 4)
            if bytesRead[1] == 0 : # assume the device did not respond
                return -1
            self.device_type_ = bytesRead[1] 
            self.firmware_version_ = bytesRead[2]
    
    def updateRescale(self): # refresh scale factors
        scale = 1 << (16 - self.numBits)
        #scale += 0.1 ; scale -= 0.1
        self.posRescale = 1.0 / self.deviceSize[0]
        self.posHRescale = 1.0 / self.deviceSize[1]
        self.sizeRescale = scale / self.deviceSize[2]
        self.rawRescale = 1.0 / (1 << self.numBits)

    def printDetails(self): # print details of this device and this library to the console
        print("Device type",trillTypes[self.typeNumber])
        print("At I2C address:-", str(hex(self.addr)))
        print("Running in mode:-", modeTypes[self.modeNumber])
        print("Device size:-", self.deviceSize)
        print("Device version number", self.firmware_version_)
        print("Python library version 1.0")
    
    def setMode(self, modeToSet): # set the current working mode from a mode number
        if modeToSet in modeTypes :
            self.modeNumber = modeTypes.index(modeToSet)
            block = [kCommandMode, self.modeNumber]            
            if self.txI2C(kOffsetCommand, block) : raise BaseException("Device not found setting mode")
            else: self.prepairedForDataRead_ = False ; time.sleep(commandSleepTime)
        else:
            raise BaseException("Error - mode" + modeToSet + "is not a valid mode")
    
    def setScanSettings(self, speed, num_bits): # parameters of auto scan
        if speed > 3 : speed = 3
        if num_bits < 9 : num_bits = 9
        if num_bits > 16 : num_bits = 16
        block = [kCommandScanSettings, speed, num_bits]
        if self.txI2C(kOffsetCommand, block) : raise BaseException("Device not found setting Scan")
        else:
            self.prepairedForDataRead_ = False
            self.numBits = num_bits
            self.updateRescale()
            time.sleep(commandSleepTime)       
    
    def setPrescaler(self, prescaler): # set the register of the I2C device
        block = [kCommandPrescaler, prescaler]
        if self.txI2C(kOffsetCommand, block) : raise BaseException("Device not found setting Prescaler")
        else: self.prepairedForDataRead_ = False ; time.sleep(commandSleepTime)
    
    def setNoiseThreshold(self, threshold): # ignore readings lower than this
        threshold = threshold * (1 << self.numBits)
        if threshold > 255 : threshold = 255
        thByte = int(threshold + 0.5)
        block = [kCommandNoiseThreshold, thByte]
        if self.txI2C(kOffsetCommand, block) : raise BaseException("Device not found setting noise threshold")
        else: self.prepairedForDataRead_ = False ; time.sleep(commandSleepTime)
    
    def setIDACValue(self, value): # A/D converter settings
        block = [kCommandIdac, value]
        if self.txI2C(kOffsetCommand, block) : raise BaseException("Device not found setting IDAC value")
        else: self.prepairedForDataRead_ = False ; time.sleep(commandSleepTime)

    def setMinimumTouchSize(self, minSize): # minimum size of touch considered valid
        maxMinSize = (1 << 16) - 1
        if(maxMinSize > minSize / self.sizeRescale): minSize = maxMinSize # clip to max value we can send
        else: size = minSize / self.sizeRescale        
        block[kCommandMinimumSize, size >> 8, size & 0xFF]
        if self.txI2C(kOffsetCommand, block) : raise BaseException("Device not found setting minimum touch size")
        else: self.prepairedForDataRead_ = False ; time.sleep(commandSleepTime)
        return 0

    def setAutoScanInterval(self, interval): # set the auto scan speed
        block = [kCommandAutoScanInterval, int(interval >> 8), int(interval & 0xFF)]
        if self.txI2C(kOffsetCommand, block) : raise BaseException("Device not found setting Auto Scan Interval")
        else: self.prepairedForDataRead_ = False ; time.sleep(commandSleepTime)
                          
    def updateBaseLine(self): # set the base line all readings have these values subtracted in the DIFF mode
        block = [kCommandBaselineUpdate]
        if self.txI2C(kOffsetCommand, block) : raise BaseException("Device not found setting base line")
        else: self.prepairedForDataRead_ = False ; time.sleep(commandSleepTime)
        return 0
    
    def prepareForDataRead(self): # set up the registers of the Trill device for a data reading
        if not self.prepairedForDataRead_ :
            self.bus.write_byte(self.addr, kOffsetData) # send one byte
            self.prepairedForDataRead_ = True
            time.sleep(commandSleepTime)
            return 0
        
    def readI2C(self) : # for compatibility with the C library
        self.readTrill()
        
    def readTrill(self) : # read the Trill device and process it according to the current mode
        self.prepareForDataRead()
        bytesToRead = kCentroidLengthDefault
        self.num_touches_ = 0
        if("CENTROID" == modeTypes[self.modeNumber]) :
            if self.tt == 'square' or self.tt == 'hex' :
                    bytesToRead = kCentroidLength2D;
            if self.tt == 'ring' :
                    bytesToRead = kCentroidLengthRing;
        else :
            bytesToRead = kRawLength   
        msg = i2c_msg.read(self.addr, bytesToRead)
        self.bus.i2c_rdwr(msg)
        self.dataBuffer = list(msg)
        if len(self.dataBuffer) != bytesToRead :
            print("only got", len(self.dataBuffer), "when asked for", bytesToRead) 
            return 1        
        
        if "CENTROID" != modeTypes[self.modeNumber] :
                for i in range (0, self.getNumChannels()) :
                    self.rawData[i] = (((self.dataBuffer[2 * i] << 8) + self.dataBuffer[2 * i + 1]) & 0x0FFF) * self.rawRescale
        else:   
            locations = 0
            #Look for 1st instance of 0xFFFF (no touch) in the buffer
            for locations in range(0,  self.max_touch_1D_or_2D + 1) :
                    if self.dataBuffer[2 * locations] == 0xFF and self.dataBuffer[2 * locations + 1] == 0xFF :
                        break
            self.num_touches_ = locations
            if self.tt == "square" or self.tt == 'hex' :
                # Look for the number of horizontal touches in 2D sliders
                # which might be different from number of vertical touches
                self.topHalf = bytesToRead // 2
                for locations in range(0,  self.max_touch_1D_or_2D) :
                    if self.dataBuffer[2 * locations + self.topHalf] == 0xFF and self.dataBuffer[2 * locations + self.topHalf + 1] == 0xFF :
                        break
                self.num_touches_ |= locations << 4 # pack into the top four bits
        return 0
    
    def is1D(self): # is this device a one dimensional device?
        if modeTypes[self.modeNumber] != "CENTROID" : return False
        if self.tt == 'bar' or self.tt == 'ring' or self.tt == 'craft' :
            return True;
        else :
            return False;
        
    def is2D(self): # is this device a two dimensional device?
        if self.tt == 'square' or self.tt == 'hex' :
            return True
        else:
            return False;
        
    def getNumTouches(self): # how many touches (vertical) are being detected?
            if modeTypes[self.modeNumber] != "CENTROID" : return 0
            # Lower 4 bits hold number of 1-axis or vertical touches
            return (self.num_touches_ & 0x0F)

    def getNumHorizontalTouches(self): # how many Horizontal touches are being detected?
        if modeTypes[self.modeNumber] != "CENTROID" or (self.tt != 'square' and self.tt != 'hex') :
            return 0
        return (self.num_touches_  >> 4)

    def touchLocation(self, touch_num): # where is the touch returns a value 0.0 to 1.0
        if modeTypes[self.modeNumber] != "CENTROID" : return -1
        if touch_num >= self.max_touch_1D_or_2D : return -1
        location = self.dataBuffer[2 * touch_num] << 8
        location |= self.dataBuffer[2 * touch_num + 1]
        return location * self.posRescale

    def getButtonValue(self, button_num): # Get the value of the capacitive "button" channels on the device
        if modeTypes[self.modeNumber] != "CENTROID" : return -1
        if button_num > 1 : return -1
        if self.tt != "ring" : return -1
        return ((self.dataBuffer[4 * self.max_touch_1D_or_2D + 2* button_num] << 8) +
                   self.dataBuffer[4 * self.max_touch_1D_or_2D + 2* button_num + 1] & 0xFFF) *self.rawRescale
           
    def touchSize(self, touch_num): # the size of the touch, if the touch exists, or 0 otherwise
        if modeTypes[self.modeNumber] != "CENTROID" : return -1
        if touch_num >= self.max_touch_1D_or_2D : return -1
        size = self.dataBuffer[2 * touch_num + 2* self.max_touch_1D_or_2D] * 256 
        size += self.dataBuffer[2 * touch_num + 2* self.max_touch_1D_or_2D + 1]
        return size * self.sizeRescale
         
    def touchHorizontalLocation(self, touch_num): # Get the location of a touch on the horizontal axis of the device.
        if(modeTypes[self.modeNumber] != "CENTROID" or (self.tt != 'square' and  self.tt != 'hex')):
            return -1
        if(touch_num >= self.max_touch_1D_or_2D):
            return -1
        location = self.dataBuffer[2 * touch_num + self.topHalf] << 8 | self.dataBuffer[2 * touch_num + self.topHalf+1]
        place = location * self.posHRescale
        if place >1.0 : place = 1.0
        return place
    
    def touchHorizontalSize(self, touch_num) : # get the size of the touch, if the touch exists, or 0 otherwise. 
        if(modeTypes[self.modeNumber] != "CENTROID"  or (self.tt != 'square' and  self.tt != 'hex')):
            return -1
        if(touch_num >=  self.max_touch_1D_or_2D):
            return -1;
        size = self.dataBuffer[2*touch_num + 6* self.max_touch_1D_or_2D] * 256
        size += self.dataBuffer[2*touch_num + 6* self.max_touch_1D_or_2D + 1]
        return size * self.sizeRescale;

    def compoundTouch(self, LOCATION, SIZE, TOUCHES) :
        favg = 0.0
        totalSize = 0.0
        numTouches = TOUCHES
        for i in range(0,  numTouches) :
            avg += LOCATION(i) * SIZE(i)
            totalSize += SIZE(i)
        if(numTouches) :
            avg = avg / totalSize;
        return avg

    def compoundTouchLocation(self): # Get the vertical location of the compound touch on the device.
        self.compoundTouch(touchLocation, touchSize, self.getNumTouches())

    def compoundTouchHorizontalLocation(self): # Get the horizontal location of the compound touch on the device.
        self.compoundTouch(touchHorizontalLocation, touchHorizontalSize, self.getNumHorizontalTouches())

    def compoundTouchSize(self): # Get the size of the compound touch on the device.
        size = 0.0
        for i in range(0, self.getNumTouches()): size += touchSize[i]        
        return size

    def getNumChannels(self): # Get the number of capacitive channels on this device
        if self.tt == 'bar': return kNumChannelsBar
        elif self.tt == 'ring':return kNumChannelsRing
        else: return kNumChannelsMax        
    
    ### I2C calls ###
        
    def rxI2C(self, reg, number):
        r = self.bus.read_i2c_block_data(self.addr, reg, number)
        return r
    
    def testForI2CDevice(self, addr, reg, value):
        device = True
        try :
            self.bus.read_i2c_block_data(addr, reg, value)
        except :
            device = False
        return device    
    
    def txI2C(self, reg, data):
        error = False
        try :
            self.bus.write_i2c_block_data(self.addr, reg, data)
        except :
            error = True
        return error # error indication      
コード例 #27
0
import RPi.GPIO as GPIO
import time
from smbus2 import SMBus
import ic_msg

i = 0
start = 0
maxLoops = 40
bus = SMBus(1)

keepGoing = True
while keepGoing:
    msg = i2c_msg.write(80, [65, 66, 67, 68])
    bus.i2c_rdwr(msg)

    print("writing!  " + str(i))
    i = i + 1
    if (i > maxLoops):
        keepGoing = False
    time.sleep(0.05)

#Exit gracefully?

print "Done!"
コード例 #28
0
class PowerSupply(object):
    def __init__(self,i2cbus=0,address=7):  #address 0..7 reflecting the i2c address select bits on the PSU edge connector
        self.i2c = SMBus(i2cbus)    # 0 = /dev/i2c-0 (port I2C0), 1 = /dev/i2c-1 (port I2C1)
        self.address=0x58+address
        self.EEaddress=0x50+address

        self.numReg=0x58/2
        self.lastReg=[0 for n in range(self.numReg)]
        self.minReg=[0xffff for n in range(self.numReg)]
        self.maxReg=[0 for n in range(self.numReg)]
        

    #not very interesting - read the 24c02 eeprom (you can write it too)
    def readEEPROM(self):
        pos=0
        data=""
        while pos<256: #fixme
            data+=self.i2c.read_i2c_block_data(self.EEaddress,pos,32)
            pos+=32
        print "%s" % (" ".join([ "%02x" % ord(d) for d in data]) )

    def readVar(self,address,writeInts,readCount):
        #https://github.com/kplindegaard/smbus2  'dual i2c_rdrw'
        write = i2c_msg.write(address, writeInts)
        if readCount:
            read = i2c_msg.read(address,readCount)
        m=self.i2c.i2c_rdwr(write, read)
        return [chr(n) for n in list(read)]

    def writeVar(self,address,bytes):
        asInts=[ord(d) for d in bytes]
        self.i2c.write_i2c_block_data(address,asInts[0],asInts[1:])
        
    #the most useful
    def readDPS1200(self,reg,count):
        cs=reg+(self.address<<1)
        regCS=((0xff-cs)+1)&0xff  #this is the 'secret sauce' - if you don't add the checksum byte when reading a register the PSU will play dumb
        #checksum is [ i2c_address, reg_address, checksum ] where checksum is as above.
        writeInts=[reg,regCS]   #send register # plus checksum
        #this should write [address,register,checksum] and then read two bytes (send address+read bit, read lsb,read msb)
        #note this device doesn't require you to use a "repeated start" I2C condition - you can just do start/write/stop;start/read/stop
        return self.readVar(self.address,writeInts,count)
    
    #  Writable registers/cmds:
    # Nothing very interesting discovered so far; you can control the fan speed. Not yet discovered how to turn 
    # the 12v output on/off in software.
    #
    # Random notes below:
    #
    #"interesting" write cmds;
    #0x35  (if msb+lsb==0 clear c4+c5)
    #
    #0x3b - checks bit 5 of lsb of write data, if set does (stuff), if bit 6 set does (other stuff), low 5 bits
    #stored @ 0xc8 (read with 0x3a)  
    #        b0..2= 1=(see 0x344); sets 'fan_related' to 9000
    #               2=(see 0x190a) sets 'surprise_more_flags bit 6'
    #        b3= 
    #        b4=
    #        b5=
    #        b6=
    #
    #..cmds that write to ram..
    #0x31 - if data=0 sets i2c_flags1 2 & 7 (0x2d8) = resets total_watts and uptime_secs
    #0x33 - if data=0 resets MaxInputWatts
    #0x35 - if data=0 resets MaxInputCurrent
    #0x37 - if data=0 resets MaxRecordedCurrent
    #0x3b - sets yet_more_flags:5, checks write data lsb:5
    #0x3d - something like set min fan speed
    #0x40  (writes 0xe5) 
    #0x41  (writes 0xd4)   <<d4= fan speed control - write 0x4000 to 0x40 = full speed fan (sets 'surprise_mnore_flags:5)')
    #0x45  sets some voltage threshold if written  (sets a4:1)
    #0x47  sets some other threshhold when written (sets a4:2) -
    #0x49  sets a4:3
    #0x4b  sets a4:4
    #50/51  (writes 0xee/ef) - default is 3200 
    #52/53 (0xa5/6) - some temp threshold 
    #54/55 (0xa7/8)  (sets some_major_flags:5) - eeprom related
    #56/57 (0xa9/a)  (a9 is EEPROM read address with cmd 57)


    def writeDPS1200(self,reg,value):
        valLSB=value&0xff
        valMSB=value>>8
        cs=(self.address<<1)+reg+valLSB+valMSB
        regCS=((0xff-cs)+1)&0xff
        #the checksum is the 'secret sauce'
        writeInts=[reg,valLSB,valMSB,regCS]  #write these 4 bytes to i2c
        bytes="".join([chr(n) for n in writeInts])
        return self.writeVar(self.address, bytes) 
        
    def testWrite(self):
        value=0
        #try fuzzing things to see if we can find power on/off.. (not yet) 0x40 controls fan speed (bitfield)
        #for n in [0x35,0x3b,0x40,0x50,0x52,0x54,0x56]:
        for n in [0x35,0x3b,0x50,0x52,0x54,0x56]:
        #for n in [0x40]:
            for b in range(16):
                value=(1<<b)-1
                print "%02x : %04x" % (n,value)
                self.writeDPS1200(n,value)
                time.sleep(0.5)

    #Readable registers - some of these are slightly guessed - comments welcome if you figure something new out or have a correction.
    REGS={
        #note when looking at PIC disasm table; "lookup_ram_to_read_for_cmd", below numbers are <<1
        #the second arg is the scale factor
        0x01:["FLAGS",0],           #not sure but includes e.g. "power good"
        0x04:["INPUT_VOLTAGE",32.0], #e.g. 120 (volts)
        0x05:["AMPS_IN",128.0],
        0x06:["WATTS_IN",2.0],
        0x07:["OUTPUT_VOLTAGE",254.5], #pretty sure this is right; unclear why scale is /254.5 not /256 but it's wrong - can't see how they'd not be measuring this to high precision
        0x08:["AMPS_OUT",128.0],  #rather inaccurate at low output <10A (reads under) - appears to have internal load for stability so always reads about 1.5 even open circuit
        0x09:["WATTS_OUT",2.0],
        0x0d:["TEMP1_INTAKE_FARENHEIT",32.0],   # this is a guess - may be C or F but F looks more right
        0x0e:["TEMP2_INTERNAL_FARENHEIT",32.0], 
        0x0f:["FAN_SPEED_RPM",1], #total guess at scale but this is def fan speed it may be counting ticks from the fan sensor which seem to be typically 2 ticks/revolution
        0x1a:["?flags",0],                      #unknown (from disassembly)
        0x1b:["?voltage",1],                    #unknown (from disassembly)
        (0x2c>>1):["WATT_SECONDS_IN",-4.0], #this is a special case; uses two consecutive regs to make a 32-bit value (the minus scale factor is a flag for that)
        (0x30>>1):["ON_SECONDS",2.0],
        (0x32>>1):["PEAK_WATTS_IN",2.0],
        (0x34>>1):["MIN_AMPS_IN",128.0],
        (0x36>>1):["PEAK_AMPS_OUT",128.0],
        (0x3A>>1):["COOL_FLAGS1",0],             #unknown (from disassembly)
        (0x3c>>1):["COOL_FLAGS2",0],             #unknown (from disassembly)
        (0x40>>1):["FAN_TARGET_RPM",1],          #unknown (from disassembly)
        (0x44>>1):["VOLTAGE_THRESHOLD_1",1],    #unknown (from disassembly)
        (0x46>>1):["VOLTAGE_THRESHOLD_2",1],    #unknown (from disassembly)
        (0x50>>1):["MAYBE_UNDERVOLTAGE_THRESH",32.0],    #unknown (from disassembly)
        (0x52>>1):["MAYBE_OVERVOLTAGE_THRESH",32.0],    #unknown (from disassembly)
        #reading 0x57 reads internal EEPROM space in CPU (just logging info, e.g. hours in use)
        }

    def readDPS1200Register(self,reg):
        data=self.readDPS1200(reg<<1,3)  #if low bit set returns zeros (so use even # cmds)
        #check checksum (why not)
        replyCS=0
        for d in data:
            replyCS+=ord(d)
        replyCS=((0xff-replyCS)+1)&0xff  #check reply checksum (not really reqd)
        if replyCS!=0:
            raise Exception("Read error")
        data=data[:-1]
        value=ord(data[0]) | ord(data[1])<<8
        return value


    def read(self):
        for n in range(self.numReg):
            try:
                value=self.readDPS1200Register(n)
                self.minReg[n]=min(self.minReg[n],value)
                self.maxReg[n]=max(self.maxReg[n],value)
                name=""
                if n in self.REGS:
                    name,scale=self.REGS[n]
                    if scale<0:
                        scale=-scale
                        value+=self.readDPS1200Register(n+1)<<16
                else:
                    scale=1
                print "%02x\t%04x\t" % (n<<1,value ),
                if scale:
                    print "%d\t%d\t%d\t(%d)\t%.3f\t%s" % (value,self.minReg[n],self.maxReg[n],self.maxReg[n]-self.minReg[n],value/scale,name )
                else:
                    print "%s\t%s" % (bin(value),name)
            except Exception,ex:
                print "r %02x er %s" % (n,ex)
        return
        addr=self.address
コード例 #29
0
class Robot(object):
    MODE_SIMULATION = 0
    MODE_CROSS_COMPILATION = 1
    MODE_REMOTE_CONTROL = 2

    def __init__(self):
        self.time = 0
        self.tof = VL53L0X.VL53L0X(i2c_bus=4, i2c_address=0x29)
        self.tof.open()
        self.tof.start_ranging(VL53L0X.Vl53l0xAccuracyMode.BETTER)
        self.bus = SMBus(I2C_CHANNEL)
        self.busFT903 = SMBus(FT903_I2C_CHANNEL)
        self.devices = {}
        self.previousTime = None
        self.customData = ''
        for name in DistanceSensor.groundNames + DistanceSensor.proximityNames:
            self.devices[name] = DistanceSensor(name)
        for name in LightSensor.names:
            self.devices[name] = LightSensor(name)
        for name in PositionSensor.names:
            self.devices[name] = PositionSensor(name)
        for name in Motor.names:
            self.devices[name] = Motor(name)
        for name in LED.names:
            self.devices[name] = LED(name)
        for name in Accelerometer.names:
            self.devices[name] = Accelerometer(name)
        for name in Gyro.names:
            self.devices[name] = Gyro(name)
        self.devices['tof'] = DistanceSensor('tof')
        print('Starting controller.')

    def step(self, duration, blocking=False):
        if blocking:
            now = time.time()
            if self.previousTime is not None:
                diff = now - (self.previousTime + 0.001 * duration)
                if diff < 0:
                    time.sleep(-diff)
                    self.time += 0.001 * duration
                else:
                    self.time += diff + 0.001 * duration
            else:
                self.time += 0.001 * duration
            self.previousTime = time.time()

        self.devices['tof'].value = self.tof.get_distance() / 1000.0

        actuatorsData = []
        # left motor
        # 0.00628 = (2 * pi) / encoder_resolution
        leftSpeed = int(self.devices['left wheel motor'].getVelocity() /
                        0.0068)
        actuatorsData.append(leftSpeed & 0xFF)
        actuatorsData.append((leftSpeed >> 8) & 0xFF)
        # right motor
        rightSpeed = int(self.devices['right wheel motor'].getVelocity() /
                         0.0068)
        actuatorsData.append(rightSpeed & 0xFF)
        actuatorsData.append((rightSpeed >> 8) & 0xFF)
        # speaker sound
        actuatorsData.append(0)
        # LED1, LED3, LED5, LED7 on/off flag
        actuatorsData.append((self.devices['led0'].value & 0x1)
                             | (self.devices['led2'].value & 0x2)
                             | (self.devices['led4'].value & 0x4)
                             | (self.devices['led6'].value & 0x8))
        # LED2 R/G/B
        actuatorsData.append(
            int(((self.devices['led1'].value >> 16) & 0xFF) / 2.55))
        actuatorsData.append(
            int(((self.devices['led1'].value >> 8) & 0xFF) / 2.55))
        actuatorsData.append(int((self.devices['led1'].value & 0xFF) / 2.55))
        # LED4 R/G/B
        actuatorsData.append(
            int(((self.devices['led3'].value >> 16) & 0xFF) / 2.55))
        actuatorsData.append(
            int(((self.devices['led3'].value >> 8) & 0xFF) / 2.55))
        actuatorsData.append(int((self.devices['led3'].value & 0xFF) / 2.55))
        # LED6 R/G/B
        actuatorsData.append(
            int(((self.devices['led5'].value >> 16) & 0xFF) / 2.55))
        actuatorsData.append(
            int(((self.devices['led5'].value >> 8) & 0xFF) / 2.55))
        actuatorsData.append(int((self.devices['led5'].value & 0xFF) / 2.55))
        # LED8 R/G/B
        actuatorsData.append(
            int(((self.devices['led7'].value >> 16) & 0xFF) / 2.55))
        actuatorsData.append(
            int(((self.devices['led7'].value >> 8) & 0xFF) / 2.55))
        actuatorsData.append(int((self.devices['led7'].value & 0xFF) / 2.55))
        # Settings
        actuatorsData.append(0)
        # Checksum
        checksum = 0
        for data in actuatorsData:
            checksum ^= data

        actuatorsData.append(checksum)
        if len(actuatorsData) != ACTUATORS_SIZE:
            sys.exit('Wrond actuator data size.')
        # communication with i2c bus with main board address
        write = i2c_msg.write(MAIN_ADDR, actuatorsData)
        read = i2c_msg.read(MAIN_ADDR, SENSORS_SIZE)
        try:
            self.bus.i2c_rdwr(write, read)
        except:
            return
        sensorsData = list(read)

        checksum = 0
        for data in sensorsData:
            checksum ^= checksum ^ data
        if sensorsData[SENSORS_SIZE - 1] != checksum:
            print('Wrogn receiving checksum')
            return

        if len(sensorsData) != SENSORS_SIZE:
            sys.exit('Wrond actuator data size.')
        # Read and assign DistanceSensor values
        for i in range(8):
            self.devices[DistanceSensor.proximityNames[i]].value = (
                sensorsData[i * 2] & 0x00FF) | (
                    (sensorsData[i * 2 + 1] << 8) & 0xFF00)
        # Read and assign LightSensor values
        for i in range(8):
            self.devices[LightSensor.names[i]].value = sensorsData[
                i * 2 + 16] + (sensorsData[i * 2 + 17] << 8)
        # Read and assign PositionSensor values
        for i in range(2):
            val = (sensorsData[i * 2 + 41] & 0x00FF) | (
                (sensorsData[i * 2 + 42] << 8) & 0xFF00)

            # Pythonic way to get signed 16bit integers :O
            if val > 2**15:
                val -= 2**16

            # 159.23 = encoder_resolution/ (2 * pi)
            self.devices[PositionSensor.names[i]].value = val / 159.23

        # communication with the pi-puck extension FT903 address
        mapping = [2, 1, 0]
        for i in range(3):
            ledName = 'pi-puck led %d' % i
            if self.devices[ledName].changed:
                ledValue = (
                    (0x01 if
                     ((self.devices[ledName].value >> 16) & 0xFF) > 0 else 0) |
                    (0x02 if
                     ((self.devices[ledName].value >> 8) & 0xFF) > 0 else 0) |
                    (0x04 if (self.devices[ledName].value & 0xFF) > 0 else 0))
                self.busFT903.write_byte_data(FT903_ADDR, mapping[i], ledValue)
                self.devices[ledName].changed = False
        # communication with i2c bus with ground sensors board address
        groundSensorsEnabled = False
        for name in DistanceSensor.groundNames:
            if self.devices[name].getSamplingPeriod() > 0:
                groundSensorsEnabled = True
                break
        if groundSensorsEnabled:
            read = i2c_msg.read(GROUND_ADDR, GROUND_SENSORS_SIZE)
            try:
                self.bus.i2c_rdwr(read)
            except:
                return
            groundData = list(read)
            for i in range(3):
                self.devices[DistanceSensor.groundNames[i]].value = (
                    groundData[i * 2] << 8) + groundData[i * 2 + 1]
        # communication with the i2c bus with the extension board address
        # if self.devices['accelerometer'].getSamplingPeriod() > 0 or self.devices['gyro'].getSamplingPeriod() > 0:
        # imuRead = i2c_msg.read(IMU_ADDR, IMU_SIZE)
        # self.bus.i2c_rdwr(imuRead)
        # imuData = list(imuRead)
        # if len(imuData) != IMU_SIZE:
        #     sys.exit('Wrond IMU data size.')
        # print(imuData)

    def getAccelerometer(self, name):
        if name in self.devices and isinstance(self.devices[name],
                                               Accelerometer):
            return self.devices[name]
        print('No Accelerometer device named "%s"\n' % name)
        return None

    def getDistanceSensor(self, name):
        if name in self.devices and isinstance(self.devices[name],
                                               DistanceSensor):
            return self.devices[name]
        print('No DistanceSensor device named "%s"\n' % name)
        return None

    def getLED(self, name):
        if name in self.devices and isinstance(self.devices[name], LED):
            return self.devices[name]
        print('No LED device named "%s"\n' % name)
        return None

    def getLightSensor(self, name):
        if name in self.devices and isinstance(self.devices[name],
                                               LightSensor):
            return self.devices[name]
        print('No LightSensor device named "%s"\n' % name)
        return None

    def getMotor(self, name):
        if name in self.devices and isinstance(self.devices[name], Motor):
            return self.devices[name]
        print('No Motor device named "%s"\n' % name)
        return None

    def getPositionSensor(self, name):
        if name in self.devices and isinstance(self.devices[name],
                                               PositionSensor):
            return self.devices[name]
        print('No PositionSensor device named "%s"\n' % name)
        return None

    def getName(self):
        return 'e-puck'

    def getTime(self):
        return self.time

    def getSupervisor(self):
        return False

    def getSynchronization(self):
        return False

    def getBasicTimeStep(self):
        return 32

    def getNumberOfDevices(self):
        return len(self.devices)

    def getDeviceByIndex(self, index):
        return self.devices[index]

    def getMode(self):
        return Robot.MODE_CROSS_COMPILATION

    def getCustomData(self):
        return self.customData

    def setCustomData(self, data):
        self.customData = data
コード例 #30
0
class VL53L1X:
    """VL53L1X ToF."""
    def __init__(self,
                 i2c_bus=1,
                 i2c_address=0x29,
                 tca9548a_num=255,
                 tca9548a_addr=0):
        """Initialize the VL53L1X ToF Sensor from ST"""
        self._i2c_bus = i2c_bus
        self.i2c_address = i2c_address
        self._tca9548a_num = tca9548a_num
        self._tca9548a_addr = tca9548a_addr

        self._i2c = SMBus(i2c_bus)
        try:
            if tca9548a_num == 255:
                self._i2c.read_byte_data(self.i2c_address, 0x00)
        except IOError:
            raise RuntimeError("VL53L1X not found on adddress: {:02x}".format(
                self.i2c_address))

        self._dev = None
        # Register Address
        self.ADDR_UNIT_ID_HIGH = 0x16  # Serial number high byte
        self.ADDR_UNIT_ID_LOW = 0x17  # Serial number low byte
        self.ADDR_I2C_ID_HIGH = 0x18  # Write serial number high byte for I2C address unlock
        self.ADDR_I2C_ID_LOW = 0x19  # Write serial number low byte for I2C address unlock
        self.ADDR_I2C_SEC_ADDR = 0x8a  # Write new I2C address after unlock

    def open(self, reset=False):
        self._i2c.open(bus=self._i2c_bus)
        self._configure_i2c_library_functions()
        self._dev = _TOF_LIBRARY.initialise(self.i2c_address,
                                            self._tca9548a_num,
                                            self._tca9548a_addr, reset)

    def close(self):
        self._i2c.close()
        self._dev = None

    def _configure_i2c_library_functions(self):
        # I2C bus read callback for low level library.
        def _i2c_read(address, reg, data_p, length):
            ret_val = 0

            msg_w = i2c_msg.write(address, [reg >> 8, reg & 0xff])
            msg_r = i2c_msg.read(address, length)

            self._i2c.i2c_rdwr(msg_w, msg_r)

            if ret_val == 0:
                for index in range(length):
                    data_p[index] = ord(msg_r.buf[index])

            return ret_val

        # I2C bus write callback for low level library.
        def _i2c_write(address, reg, data_p, length):
            ret_val = 0
            data = []

            for index in range(length):
                data.append(data_p[index])

            msg_w = i2c_msg.write(address, [reg >> 8, reg & 0xff] + data)

            self._i2c.i2c_rdwr(msg_w)

            return ret_val

        # I2C bus write callback for low level library.
        def _i2c_multi(address, reg):
            ret_val = 0

            # Write to the multiplexer
            self._i2c.write_byte(address, reg)

            return ret_val

        # Pass i2c read/write function pointers to VL53L1X library.
        self._i2c_multi_func = _I2C_MULTI_FUNC(_i2c_multi)
        self._i2c_read_func = _I2C_READ_FUNC(_i2c_read)
        self._i2c_write_func = _I2C_WRITE_FUNC(_i2c_write)
        _TOF_LIBRARY.VL53L1_set_i2c(self._i2c_multi_func, self._i2c_read_func,
                                    self._i2c_write_func)

    def start_ranging(self, mode=VL53L1xDistanceMode.LONG):
        """Start VL53L1X ToF Sensor Ranging"""
        _TOF_LIBRARY.startRanging(self._dev, mode)

    def set_distance_mode(self, mode):
        """Set distance mode

        :param mode: One of 1 = Short, 2 = Medium or 3 = Long

        """
        _TOF_LIBRARY.setDistanceMode(self._dev, mode)

    def stop_ranging(self):
        """Stop VL53L1X ToF Sensor Ranging"""
        _TOF_LIBRARY.stopRanging(self._dev)

    def get_distance(self):
        """Get distance from VL53L1X ToF Sensor"""
        return _TOF_LIBRARY.getDistance(self._dev)

    def set_timing(self, timing_budget, inter_measurement_period):
        """Set the timing budget and inter measurement period.

        A higher timing budget results in greater measurement accuracy,
        but also a higher power consumption.

        The inter measurement period must be >= the timing budget, otherwise
        it will be double the expected value.

        :param timing_budget: Timing budget in microseconds
        :param inter_measurement_period: Inter Measurement Period in milliseconds

        """
        if (inter_measurement_period * 1000) < timing_budget:
            raise ValueError(
                "The Inter Measurement Period must be >= Timing Budget")

        self.set_timing_budget(timing_budget)
        self.set_inter_measurement_period(inter_measurement_period)

    def set_timing_budget(self, timing_budget):
        """Set the timing budget in microseocnds"""
        _TOF_LIBRARY.setMeasurementTimingBudgetMicroSeconds(
            self._dev, timing_budget)

    def set_inter_measurement_period(self, period):
        """Set the inter-measurement period in milliseconds"""
        _TOF_LIBRARY.setInterMeasurementPeriodMilliSeconds(self._dev, period)

    # This function included to show how to access the ST library directly
    # from python instead of through the simplified interface
    def get_timing(self):
        budget = c_uint(0)
        budget_p = pointer(budget)
        status = _TOF_LIBRARY.VL53L1_GetMeasurementTimingBudgetMicroSeconds(
            self._dev, budget_p)
        if status == 0:
            return budget.value + 1000
        else:
            return 0

    def change_address(self, new_address):
        status = _TOF_LIBRARY.setDeviceAddress(self._dev, new_address)
        if status == 0:
            self.i2c_address = new_address
        else:
            raise RuntimeError(
                "change_address failed with code: {}".format(status))
        return True

    def get_RangingMeasurementData(self):
        '''
        Returns the full RangingMeasurementData structure.
        (it ignores the fields that are not implemented according to en.DM00474730.pdf)
        '''
        contents = _getRangingMeasurementData(self._dev).contents
        return {
            'StreamCount': contents.StreamCount,
            'SignalRateRtnMegaCps': contents.SignalRateRtnMegaCps / 65536,
            'AmbientRateRtnMegaCps': contents.AmbientRateRtnMegaCps / 65536,
            'EffectiveSpadRtnCount': contents.EffectiveSpadRtnCount / 256,
            'SigmaMilliMeter': contents.SigmaMilliMeter / 65536,
            'RangeMilliMeter': contents.RangeMilliMeter,
            'RangeStatus': contents.RangeStatus
        }