changes on rtr sweep
[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         self.SPItrans([0x80|flags]);
231     
232     def writetxbuffer(self,packet,packbuf=0):
233         """Writes the transmit buffer."""
234         
235         self.SPItrans([0x40|(packbuf<<1)]+packet);
236
237     def simpleParse(self,packet):
238         dataPt = ord(packet[0]);
239         dataPt2 = ord(packet[1]);
240         # check if we have a standard frame, the msb of the second
241         # nibble will be 1. otherwise it is an extended rame
242         stdCheck = dataPt2 & 0x0f
243         if( stdCheck == 16 ):
244             #arb id is first byte + 3 msb of the 2nd byte
245             dataPt = dataPt<<3 | dataPt2>>5
246             print "Standard Packet \n Arb ID: "+("%d"%dataPt)
247         else:
248             #arb id is first byte + 3 msb + 2 lsb of 2nd byte +
249             # 3rd byte + 4th byte
250             dataPt = dataPt<<3 | dataPt2>>5
251             dataPt = dataPt<<2 | (dataPt2 & 0x03)
252             dataPt = dataPt<<8 | ord(packet[2])
253             dataPt = dataPt<<8 | ord(packet[3])
254             print "Extended Data Frame \n Arb ID: "+("%d"%dataPt)
255         
256         #find the dataLength
257         dataPt5 = packet[4]
258         dataLength = dataPt5 & 0x0e
259         print "Data Length: "+("%d"%dataLength)
260         # Print the data packet
261         print "Data:"
262         # Temporary, until correct packets are read
263         if( dataLength > 8 ):
264             dataLength = 8
265         toprint = self.pcket2str(packet[5:12])
266         print toprint
267         # For reading correct packets
268        # if (dataLength > 8 ):
269         #    print "Acceptable Length Exceeded"
270             # Data length value should never exceed 8
271        # else:
272        # toprint =  self.pcket2str(packet[5:(5+dataLength)])
273        # print toprint
274
275     def txpacket(self,packet):
276         """Transmits a packet through one of the outbound buffers.
277         As usual, the packet should begin with SIDH.
278         For now, only TXB0 is supported."""
279
280         self.writetxbuffer(packet,0);
281         self.MCPrts(TXB0=True);
282
283                 
284     ###############   UTILITY FUNCTIONS  #################
285             
286     def packet2str(self,packet):
287         """Converts a packet from the internal format to a string."""
288         toprint="";
289         for bar in packet:
290             toprint=toprint+("%02x "%ord(bar))
291         return toprint;
292     
293     
294     ## This code could be drastica
295     def packet2parsedstr(self,data):
296         dp1 = ord(data[0])
297         dp2 = ord(data[1])
298         dp5 = ord(data[4])
299         
300         #converts the CAN message to a string
301         msg="";
302         
303         
304         
305         #get the ide bit. allows us to check to see if we have an extended
306         #frame
307         ide = (dp2 & 0x0f)>>3
308         #we have an extended frame
309         if( ide != 0):
310             #get lower nibble, last 2 bits
311             eId = dp2 & 0x03
312             eId = eId<<8 | ord(data[2])
313             eId = eId<<8 | ord(data[3])
314             rtr = dp5>>6 & 0x01
315             eIDmsg = " eID: %06d" %(eId)
316             rtrmsg = " rtr: %d" % (rtr)
317     
318         else:
319             rtr = dp2>>4 & 0x01
320             eIDmsg = ""
321             rtrmsg = " rtr: %d"%(rtr)
322         
323         # Create the standard ID. from the message
324         sID = dp1<<3 | dp2>>5
325         length = dp5 & 0x0f
326         
327         #generate the data section
328         dbmsg = ""
329         for i in range(0,length):
330             idx = 5 + i
331             dbmsg += " %03d"%ord(data[idx])   
332         
333         msg = "sID: %04d"%sID
334         msg += eIDmsg + rtrmsg
335         msg += " length: %d"%(length)
336         msg +=  dbmsg 
337     
338         return msg
339         
340         
341     def peek8(self,adr):
342         """Read a byte from the given address.  Untested."""
343         data=self.SPItrans([0x03,adr&0xFF,00]);
344         return ord(data[2]);
345     def poke8(self,adr,val):
346         """Poke a value into RAM.  Untested"""
347         self.SPItrans([0x02,adr&0xFF,val&0xFF]);
348         newval=self.peek8(adr);
349         if newval!=val:
350             print "Failed to poke %02x to %02x.  Got %02x." % (adr,val,newval);
351             print "Are you not in idle mode?";
352         return val;
353     def MCPbitmodify(self,adr,mask,data):
354         """Writes a byte with a mask.  Doesn't work for many registers."""
355         data=self.SPItrans([0x05,adr&0xFF,mask&0xFF,data&0xFF]);
356         return ord(data[2]);
357
358 ############### DEBUG UTILITIES: STATUS MESSAGES ##############
359
360 #    def MCPrxstatusmessage(self):
361 #        """Returns string indicating status of RX buffers"""
362 #        status = self.MCPrxstatus();
363 #
364 #        if status < 64:
365 #            print "No RX message";
366 #        elif status < 128:
367 #            print "Message in RXB0";
368 #        elif status < 192:
369 #            print "Message in RXB1";
370 #        else:
371 #            print "Messages in both buffers";
372
373
374
375 # TXB0TRL = 0x30
376 # RXB0CTRL = 0x60
377 # CNF3/2/1 = 0x28, 29, 2a
378 # CANINTE = 0x2b
379 # CANINTF = 0x2c
380 # TXRTSCTRL = x0D
381
382
383