I2C_sniffer.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 import time
00004 
00005 import pigpio
00006 
00007 class sniffer:
00008    """
00009    A class to passively monitor activity on an I2C bus.  This should
00010    work for an I2C bus running at 100kbps or less.  You are unlikely
00011    to get any usable results for a bus running any faster.
00012    """
00013 
00014    def __init__(self, pi, SCL, SDA, set_as_inputs=True):
00015       """
00016       Instantiate with the Pi and the gpios for the I2C clock
00017       and data lines.
00018 
00019       If you are monitoring one of the Raspberry Pi buses you
00020       must set set_as_inputs to False so that they remain in
00021       I2C mode.
00022 
00023       The pigpio daemon should have been started with a higher
00024       than default sample rate.
00025 
00026       For an I2C bus rate of 100Kbps sudo pigpiod -s 2 should work.
00027 
00028       A message is printed for each I2C transaction formatted with
00029       "[" for the START
00030       "XX" two hex characters for each data byte
00031       "+" if the data is ACKd, "-" if the data is NACKd
00032       "]" for the STOP
00033 
00034       E.g. Reading the X, Y, Z values from an ADXL345 gives:
00035 
00036       [A6+32+]
00037       [A7+01+FF+F2+FF+06+00-]
00038       """
00039 
00040       self.pi = pi
00041       self.gSCL = SCL
00042       self.gSDA = SDA
00043 
00044       self.FALLING = 0
00045       self.RISING = 1
00046       self.STEADY = 2
00047 
00048       self.in_data = False
00049       self.byte = 0
00050       self.bit = 0
00051       self.oldSCL = 1
00052       self.oldSDA = 1
00053 
00054       self.transact = ""
00055 
00056       if set_as_inputs:
00057          self.pi.set_mode(SCL, pigpio.INPUT)
00058          self.pi.set_mode(SDA, pigpio.INPUT)
00059 
00060       self.cbA = self.pi.callback(SCL, pigpio.EITHER_EDGE, self._cb)
00061       self.cbB = self.pi.callback(SDA, pigpio.EITHER_EDGE, self._cb)
00062 
00063    def _parse(self, SCL, SDA):
00064       """
00065       Accumulate all the data between START and STOP conditions
00066       into a string and output when STOP is detected.
00067       """
00068 
00069       if SCL != self.oldSCL:
00070          self.oldSCL = SCL
00071          if SCL:
00072             xSCL = self.RISING
00073          else:
00074             xSCL = self.FALLING
00075       else:
00076             xSCL = self.STEADY
00077 
00078       if SDA != self.oldSDA:
00079          self.oldSDA = SDA
00080          if SDA:
00081             xSDA = self.RISING
00082          else:
00083             xSDA = self.FALLING
00084       else:
00085             xSDA = self.STEADY
00086 
00087       if xSCL == self.RISING:
00088          if self.in_data:
00089             if self.bit < 8:
00090                self.byte = (self.byte << 1) | SDA
00091                self.bit += 1
00092             else:
00093                self.transact += '{:02X}'.format(self.byte)
00094                if SDA:
00095                   self.transact += '-'
00096                else:
00097                   self.transact += '+'
00098                self.bit = 0
00099                self.byte = 0
00100 
00101       elif xSCL == self.STEADY:
00102 
00103          if xSDA == self.RISING:
00104             if SCL:
00105                self.in_data = False
00106                self.byte = 0
00107                self.bit = 0
00108                self.transact += ']' # STOP
00109                print (self.transact)
00110                self.transact = ""
00111 
00112          if xSDA == self.FALLING:
00113             if SCL:
00114                self.in_data = True
00115                self.byte = 0
00116                self.bit = 0
00117                self.transact += '[' # START
00118 
00119    def _cb(self, gpio, level, tick):
00120       """
00121       Check which line has altered state (ignoring watchdogs) and
00122       call the parser with the new state.
00123       """
00124       SCL = self.oldSCL
00125       SDA = self.oldSDA
00126 
00127       if gpio == self.gSCL:
00128          if level == 0:
00129             SCL = 0
00130          elif level == 1:
00131             SCL = 1
00132 
00133       if gpio == self.gSDA:
00134          if level == 0:
00135             SDA = 0
00136          elif level == 1:
00137             SDA = 1
00138 
00139       self._parse(SCL, SDA)
00140 
00141    def cancel(self):
00142       """Cancel the I2C callbacks."""
00143       self.cbA.cancel()
00144       self.cbB.cancel()
00145 
00146 if __name__ == "__main__":
00147 
00148    import time
00149 
00150    import pigpio
00151 
00152    import I2C_sniffer
00153 
00154    pi = pigpio.pi()
00155 
00156    s = I2C_sniffer.sniffer(pi, 1, 0, False) # leave gpios 1/0 in I2C mode
00157 
00158    time.sleep(60000)
00159 
00160    s.cancel()
00161 
00162    pi.stop()
00163 


cob_hand_bridge
Author(s): Mathias Lüdtke
autogenerated on Thu Jun 6 2019 20:43:57