added parsing abilities to sniff as well as improvements to the simpleGUI
[goodfet] / client / GoodFETMCPCAN.py
1 #!/usr/bin/env python
2 # GoodFET MCP2515 CAN Bus Client
3
4 # (C) 2012 Travis Goodspeed <travis at radiantmachines.com>
5 #
6 # WORKING COPY
7 # Currently being updated by Siege Technology's ENGS89 team
8 # Primary contact: Theodore Sumers <ted.sumers at gmail.com>
9 # ADDED FUNCTIONALITY:
10 #   10.4/41.6/83.3 kHz sniffing
11 #   setbitrate
12 #   debugs on TX and RX packet
13 #   int-based state change reqs for preserving state
14 #
15
16 # The MCP2515 is a CAN Bus to SPI adapter from Microchip Technology,
17 # as used in the Goodthopter series of boards.  It requires a separate
18 # chip for voltage level conversion, such as the MCP2551.
19
20 import sys, time, string, cStringIO, struct, glob, os;
21
22 from GoodFETSPI import GoodFETSPI;
23
24 class GoodFETMCPCAN(GoodFETSPI):
25     """This class uses the regular SPI app to implement a CAN Bus
26     adapter on the Goodthopter10 hardware."""
27     MCPMODES=["Normal","Sleep","Loopback","Listen-only","Configuration",
28               "UNKNOWN","UNKNOWN","PowerUp"];
29     
30     def MCPsetup(self):
31         """Sets up the ports."""
32         self.SPIsetup();
33         self.MCPreset(); #Reset the chip.
34         # We're going to set some registers, so we must be in config
35         # mode.
36         self.MCPreqstatConfiguration();
37         
38         # If we don't enable promiscous mode, we'll miss a lot of
39         # packets.  It can be manually disabled later.
40         #self.poke8(0x60,0xFF); #TODO Does this have any unpleasant side effects?
41         self.poke8(0x60,0x66); #Wanted FF, but some bits are reserved.
42
43     #Array of supported rates.
44     MCPrates=[10.4, 41.6, 83.3, 100, 125, 250, 500, 1000];
45     
46     def MCPreset(self):
47         """Reset the MCP2515 chip."""
48         self.SPItrans([0xC0]);
49     
50       
51     ################    SETTING BAUD RATE   ################
52     
53     
54     def MCPsetrate(self,rate=125):
55         """Sets the data rate in kHz."""
56         # Now we need to set the timing registers.  See chapter 5 of
57         # the MCP2515 datasheet to get some clue as to how this
58         # arithmetic of this works.
59
60         
61         #STORE the prior status
62         oldstatus=self.MCPcanstatint();
63         print "Setting rate of %i kHz." % rate;
64         #print "Current state is %s." % self.MCPcanstatstr();
65         self.MCPreqstatConfiguration();
66         # print "Switched to %s state." % self.MCPcanstatstr();
67         
68         
69         if rate>41 and rate<42:
70             # NOT CHECKED: based on kvaser website.
71             # Sets baud rate for 41.6 kbps
72             CNF1=0x8e;
73             CNF2=0xa3;
74             CNF3=0x05;
75         elif rate>10 and rate<11:
76             # NOT CHECKED: based on kvaser website.
77             # Sets baud rate for 10.4 kbps
78             CNF1=0xbb;
79             CNF2=0xa3;
80             CNF3=0x05;  
81         elif rate==125:
82             #125 kHz, 16 TQ, not quite as worked out above.
83             CNF1=0x04;
84             CNF2=0xB8;
85             CNF3=0x05;
86         elif rate==100:
87             #100 kHz, 20 TQ
88             CNF1=0x04;
89             CNF2=0xBA;
90             CNF3=0x07;
91         elif rate>83 and rate<83.5:
92             #83+1/3 kHz, 8 TQ
93             # 0.04% error from 83.30
94             CNF1=0x0E;
95             CNF2=0x90;
96             CNF3=0x02;
97         elif rate==250:
98             #256 kHz, 20 TQ
99             CNF1=0x01;
100             CNF2=0xBA;
101             CNF3=0x07;
102         elif rate==500:
103             #500 kHz, 20 TQ
104             CNF1=0x00;
105             CNF2=0xBA;
106             CNF3=0x07;
107         elif rate==1000:
108             #1,000 kHz, 10 TQ
109             CNF1=0x00;
110             CNF2=0xA0;
111             CNF3=0x02;
112             print "WARNING: Because of chip errata, this probably won't work."
113         else:
114             print "Given unsupported rate of %i kHz." % rate;
115             print "Defaulting to 125kHz.";
116             CNF1=0x04;
117             CNF2=0xB8;
118             CNF3=0x05;
119         self.poke8(0x2a,CNF1);
120         self.poke8(0x29,CNF2);
121         self.poke8(0x28,CNF3);
122
123         # and now return to whatever state we were in before
124         self.MCPreqstat(oldstatus);
125         #print "Reverted to %s." % self.MCPcanstatstr();
126
127     
128     #################   STATE MANAGEMENT   ##################
129
130     def MCPcanstat(self):
131         """Get the CAN Status."""
132         return self.peek8(0x0E);
133     def MCPcanstatstr(self):
134         """Read the present status as a string."""
135         opmod=self.MCPcanstatint();
136         return self.MCPMODES[opmod];
137     def MCPcanstatint(self):
138         """Read present status as an int."""
139         return self.MCPcanstat()>>5;
140
141             
142     def MCPreqstat(self, state):
143         """Set the CAN state."""
144         if state==0:
145             self.MCPreqstatNormal();
146         elif state==1:
147             self.MCPreqstatSleep();
148         elif state==2:
149             self.MCPreqstatLoopback();
150         elif state==3:
151             self.MCPreqstatListenOnly();
152         elif state==4:
153             self.MCPreqstatConfiguration();
154         else:
155             print "Invalid state entered; defaulting to Listen-Only"
156             self.MCPreqstatListenOnly();
157     def MCPreqstatNormal(self):
158         """Set the CAN state."""
159         state=0x0;
160         self.MCPbitmodify(0x0F,0xE0,(state<<5));
161     def MCPreqstatSleep(self):
162         """Set the CAN state."""
163         state=0x1;
164         self.MCPbitmodify(0x0F,0xE0,(state<<5));
165     def MCPreqstatLoopback(self):
166         """Set the CAN state."""
167         state=0x2;
168         self.MCPbitmodify(0x0F,0xE0,(state<<5));
169     def MCPreqstatListenOnly(self):
170         """Set the CAN state."""
171         state=0x3;
172         self.MCPbitmodify(0x0F,0xE0,(state<<5));
173     def MCPreqstatConfiguration(self):
174         """Set the CAN state."""
175         state=0x4;
176         self.MCPbitmodify(0x0F,0xE0,(state<<5));
177     
178     ####################     RX MANAGEMENT     #####################
179     
180     def MCPrxstatus(self):
181         """Reads the RX Status by the SPI verb of the same name."""
182         data=self.SPItrans([0xB0,0x00]);
183         return ord(data[1]);
184
185     def MCPreadstatus(self):
186         """Reads the Read Status by the SPI verb of the same name."""
187         #See page 69 of the datasheet for the flag names.
188         data=self.SPItrans([0xA0,0x00]);
189         return ord(data[1]);
190             
191     def readrxbuffer(self,packbuf=0):
192         """Reads the RX buffer.  Might have old data."""
193         data=self.SPItrans([0x90|(packbuf<<2),
194                             0x00,0x00, #SID
195                             0x00,0x00, #EID
196                             0x00,      #DLC
197                             0x00, 0x00, 0x00, 0x00,
198                             0x00, 0x00, 0x00, 0x00
199                             ]);
200         
201         return data[1:len(data)];
202     
203     def fastrxpacket(self):
204         return self.readrxbuffer(0);
205     
206     def rxpacket(self):
207         """Reads the next incoming packet from either buffer.
208             Returns None immediately if no packet is waiting."""
209         status=self.MCPrxstatus()&0xC0;
210         if status&0x40:
211             #Buffer 0 has higher priority.
212             return self.readrxbuffer(0);
213         elif status&0x80:
214             #Buffer 1 has lower priority.
215             return self.readrxbuffer(1);
216         else:
217             return None;
218
219     #################      TX MANAGEMENT    ##################
220             
221     def MCPrts(self,TXB0=False,TXB1=False,TXB2=False):
222         """Requests to send one of the transmit buffers."""
223         flags=0;
224         if TXB0: flags=flags|1;
225         if TXB1: flags=flags|2;
226         if TXB2: flags=flags|4;
227         
228         if flags==0:
229             print "Warning: Requesting to send no buffer.";
230         if self.MCPcanstat()>>5!=0:
231             print "Warning: currently in %s mode. NOT in normal mode! May not transmit." %self.MCPcanstatstr();
232         self.SPItrans([0x80|flags]);
233     
234     def writetxbuffer(self,packet,packbuf=0):
235         """Writes the transmit buffer."""
236         
237         self.SPItrans([0x40|(packbuf<<1)]+packet);
238         #READ BACK BUFFER 0 to check what we're about to send out
239         data=self.SPItrans([0x03, 0x31,                        
240                             0x00,0x00, #SID
241                             0x00,0x00, #EID
242                             0x00,      #DLC
243                             0x00, 0x00, 0x00, 0x00,
244                             0x00, 0x00, 0x00, 0x00
245                             ]);
246         print "about to transmit:" + self.packet2str(data[2:len(data)]);
247         
248     def txpacket(self,packet):
249         """Transmits a packet through one of the outbound buffers.
250         As usual, the packet should begin with SIDH.
251         For now, only TXB0 is supported."""
252
253         self.writetxbuffer(packet,0);
254
255         #self.SPItrans([0x81]);
256         self.MCPrts(TXB0=True);
257
258                 
259     ###############   UTILITY FUNCTIONS  #################
260             
261     def packet2str(self,packet):
262         """Converts a packet from the internal format to a string."""
263         toprint="";
264         for bar in packet:
265             toprint=toprint+("%02x "%ord(bar))
266         return toprint;
267     
268     def packet2parsed(self,packet):
269         dp1 = ord(data[0])
270         dp2 = ord(data[1])
271         dp5 = ord(data[4])
272         
273         #converts the CAN message to a string
274         msg="";
275         for bar in data:
276             msg=msg+("%02x"%bar)
277         
278         packet = {'msg':msg}
279         
280         #get the ide bit. allows us to check to see if we have an extended
281         #frame
282         packet['ide'] = (dp2 & 0x0f)>>3
283         #we have an extended frame
284         if( packet['ide'] != 0):
285             #get lower nibble, last 2 bits
286             eId = dp2 & 0x03
287             eId = eId<<8 | ord(data[2])
288             packet['eID'] = eId<<8 | ord(data[3])
289             packet['rtr'] = dp5>>6 & 0x01
290     
291         else:
292             packet['rtr'] = dp2>>4 & 0x01
293         
294         #error check, 2nd msb of the lower nibble of byte 2 should be 0
295         if( (dp2 & 0x04) == 4 ):
296             packet['error'] = 1
297         #error check an always 0 bit
298         if( (dp5 & 0xf0) == 240):
299             packet['error'] = 1
300         
301         # Create the standard ID. from the message
302         packet['sID'] = dp1<<3 | dp2>>5
303         
304  
305         length = dp5 & 0x0f
306         packet['length'] = length
307         
308         if( length > 8):
309             packet['error'] = 1
310         
311         #generate the data section
312         for i in range(0,length):
313             idx = 5+i
314             dbidx = 'db%d' % i
315             packet[dbidx] = data[idx]   
316         return packet
317         
318         
319         
320     def peek8(self,adr):
321         """Read a byte from the given address.  Untested."""
322         data=self.SPItrans([0x03,adr&0xFF,00]);
323         return ord(data[2]);
324     def poke8(self,adr,val):
325         """Poke a value into RAM.  Untested"""
326         self.SPItrans([0x02,adr&0xFF,val&0xFF]);
327         newval=self.peek8(adr);
328         if newval!=val:
329             print "Failed to poke %02x to %02x.  Got %02x." % (adr,val,newval);
330             print "Are you not in idle mode?";
331         return val;
332     def MCPbitmodify(self,adr,mask,data):
333         """Writes a byte with a mask.  Doesn't work for many registers."""
334         data=self.SPItrans([0x05,adr&0xFF,mask&0xFF,data&0xFF]);
335         return ord(data[2]);
336
337 ############### DEBUG UTILITIES: STATUS MESSAGES ##############
338
339 #    def MCPrxstatusmessage(self):
340 #        """Returns string indicating status of RX buffers"""
341 #        status = self.MCPrxstatus();
342 #
343 #        if status < 64:
344 #            print "No RX message";
345 #        elif status < 128:
346 #            print "Message in RXB0";
347 #        elif status < 192:
348 #            print "Message in RXB1";
349 #        else:
350 #            print "Messages in both buffers";
351
352
353
354 # TXB0TRL = 0x30
355 # RXB0CTRL = 0x60
356 # CNF3/2/1 = 0x28, 29, 2a
357 # CANINTE = 0x2b
358 # CANINTF = 0x2c
359 # TXRTSCTRL = x0D
360
361
362