I2C_sniffer.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 import time
4 
5 import pigpio
6 
7 class sniffer:
8  """
9  A class to passively monitor activity on an I2C bus. This should
10  work for an I2C bus running at 100kbps or less. You are unlikely
11  to get any usable results for a bus running any faster.
12  """
13 
14  def __init__(self, pi, SCL, SDA, set_as_inputs=True):
15  """
16  Instantiate with the Pi and the gpios for the I2C clock
17  and data lines.
18 
19  If you are monitoring one of the Raspberry Pi buses you
20  must set set_as_inputs to False so that they remain in
21  I2C mode.
22 
23  The pigpio daemon should have been started with a higher
24  than default sample rate.
25 
26  For an I2C bus rate of 100Kbps sudo pigpiod -s 2 should work.
27 
28  A message is printed for each I2C transaction formatted with
29  "[" for the START
30  "XX" two hex characters for each data byte
31  "+" if the data is ACKd, "-" if the data is NACKd
32  "]" for the STOP
33 
34  E.g. Reading the X, Y, Z values from an ADXL345 gives:
35 
36  [A6+32+]
37  [A7+01+FF+F2+FF+06+00-]
38  """
39 
40  self.pi = pi
41  self.gSCL = SCL
42  self.gSDA = SDA
43 
44  self.FALLING = 0
45  self.RISING = 1
46  self.STEADY = 2
47 
48  self.in_data = False
49  self.byte = 0
50  self.bit = 0
51  self.oldSCL = 1
52  self.oldSDA = 1
53 
54  self.transact = ""
55 
56  if set_as_inputs:
57  self.pi.set_mode(SCL, pigpio.INPUT)
58  self.pi.set_mode(SDA, pigpio.INPUT)
59 
60  self.cbA = self.pi.callback(SCL, pigpio.EITHER_EDGE, self._cb)
61  self.cbB = self.pi.callback(SDA, pigpio.EITHER_EDGE, self._cb)
62 
63  def _parse(self, SCL, SDA):
64  """
65  Accumulate all the data between START and STOP conditions
66  into a string and output when STOP is detected.
67  """
68 
69  if SCL != self.oldSCL:
70  self.oldSCL = SCL
71  if SCL:
72  xSCL = self.RISING
73  else:
74  xSCL = self.FALLING
75  else:
76  xSCL = self.STEADY
77 
78  if SDA != self.oldSDA:
79  self.oldSDA = SDA
80  if SDA:
81  xSDA = self.RISING
82  else:
83  xSDA = self.FALLING
84  else:
85  xSDA = self.STEADY
86 
87  if xSCL == self.RISING:
88  if self.in_data:
89  if self.bit < 8:
90  self.byte = (self.byte << 1) | SDA
91  self.bit += 1
92  else:
93  self.transact += '{:02X}'.format(self.byte)
94  if SDA:
95  self.transact += '-'
96  else:
97  self.transact += '+'
98  self.bit = 0
99  self.byte = 0
100 
101  elif xSCL == self.STEADY:
102 
103  if xSDA == self.RISING:
104  if SCL:
105  self.in_data = False
106  self.byte = 0
107  self.bit = 0
108  self.transact += ']' # STOP
109  print (self.transact)
110  self.transact = ""
111 
112  if xSDA == self.FALLING:
113  if SCL:
114  self.in_data = True
115  self.byte = 0
116  self.bit = 0
117  self.transact += '[' # START
118 
119  def _cb(self, gpio, level, tick):
120  """
121  Check which line has altered state (ignoring watchdogs) and
122  call the parser with the new state.
123  """
124  SCL = self.oldSCL
125  SDA = self.oldSDA
126 
127  if gpio == self.gSCL:
128  if level == 0:
129  SCL = 0
130  elif level == 1:
131  SCL = 1
132 
133  if gpio == self.gSDA:
134  if level == 0:
135  SDA = 0
136  elif level == 1:
137  SDA = 1
138 
139  self._parse(SCL, SDA)
140 
141  def cancel(self):
142  """Cancel the I2C callbacks."""
143  self.cbA.cancel()
144  self.cbB.cancel()
145 
146 if __name__ == "__main__":
147 
148  import time
149 
150  import pigpio
151 
152  import I2C_sniffer
153 
154  pi = pigpio.pi()
155 
156  s = I2C_sniffer.sniffer(pi, 1, 0, False) # leave gpios 1/0 in I2C mode
157 
158  time.sleep(60000)
159 
160  s.cancel()
161 
162  pi.stop()
163 
def _parse(self, SCL, SDA)
Definition: I2C_sniffer.py:63
def __init__(self, pi, SCL, SDA, set_as_inputs=True)
Definition: I2C_sniffer.py:14
def _cb(self, gpio, level, tick)
Definition: I2C_sniffer.py:119


cob_hand_bridge
Author(s): Mathias Lüdtke
autogenerated on Tue Oct 20 2020 03:35:57