2 # GoodFET MCP2515 CAN Bus Client
4 # (C) 2012 Travis Goodspeed <travis at radiantmachines.com>
7 # Currently being updated by Siege Technology's ENGS89 team
8 # Primary contact: Theodore Sumers <ted.sumers at gmail.com>
10 # 10.4/41.6/83.3 kHz sniffing
12 # debugs on TX and RX packet
13 # int-based state change reqs for preserving state
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.
20 import sys, time, string, cStringIO, struct, glob, os;
22 from GoodFETSPI import GoodFETSPI;
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"];
31 """Sets up the ports."""
33 self.MCPreset(); #Reset the chip.
34 # We're going to set some registers, so we must be in config
36 self.MCPreqstatConfiguration();
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.
43 #Array of supported rates.
44 MCPrates=[10.4, 41.6, 83.3, 100, 125, 250, 500, 1000];
47 """Reset the MCP2515 chip."""
48 self.SPItrans([0xC0]);
51 ################ SETTING BAUD RATE ################
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.
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();
69 if rate>41 and rate<42:
70 # NOT CHECKED: based on kvaser website.
71 # Sets baud rate for 41.6 kbps
75 elif rate>10 and rate<11:
76 # NOT CHECKED: based on kvaser website.
77 # Sets baud rate for 10.4 kbps
82 #125 kHz, 16 TQ, not quite as worked out above.
91 elif rate>83 and rate<83.5:
93 # 0.04% error from 83.30
112 print "WARNING: Because of chip errata, this probably won't work."
114 print "Given unsupported rate of %i kHz." % rate;
115 print "Defaulting to 125kHz.";
119 self.poke8(0x2a,CNF1);
120 self.poke8(0x29,CNF2);
121 self.poke8(0x28,CNF3);
123 # and now return to whatever state we were in before
124 self.MCPreqstat(oldstatus);
125 #print "Reverted to %s." % self.MCPcanstatstr();
128 ################# STATE MANAGEMENT ##################
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;
142 def MCPreqstat(self, state):
143 """Set the CAN state."""
145 self.MCPreqstatNormal();
147 self.MCPreqstatSleep();
149 self.MCPreqstatLoopback();
151 self.MCPreqstatListenOnly();
153 self.MCPreqstatConfiguration();
155 print "Invalid state entered; defaulting to Listen-Only"
156 self.MCPreqstatListenOnly();
157 def MCPreqstatNormal(self):
158 """Set the CAN state."""
160 self.MCPbitmodify(0x0F,0xE0,(state<<5));
161 def MCPreqstatSleep(self):
162 """Set the CAN state."""
164 self.MCPbitmodify(0x0F,0xE0,(state<<5));
165 def MCPreqstatLoopback(self):
166 """Set the CAN state."""
168 self.MCPbitmodify(0x0F,0xE0,(state<<5));
169 def MCPreqstatListenOnly(self):
170 """Set the CAN state."""
172 self.MCPbitmodify(0x0F,0xE0,(state<<5));
173 def MCPreqstatConfiguration(self):
174 """Set the CAN state."""
176 self.MCPbitmodify(0x0F,0xE0,(state<<5));
178 #################### RX MANAGEMENT #####################
180 def MCPrxstatus(self):
181 """Reads the RX Status by the SPI verb of the same name."""
182 data=self.SPItrans([0xB0,0x00]);
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]);
191 def readrxbuffer(self,packbuf=0):
192 """Reads the RX buffer. Might have old data."""
193 data=self.SPItrans([0x90|(packbuf<<2),
197 0x00, 0x00, 0x00, 0x00,
198 0x00, 0x00, 0x00, 0x00
201 return data[1:len(data)];
203 def fastrxpacket(self):
204 return self.readrxbuffer(0);
207 """Reads the next incoming packet from either buffer.
208 Returns None immediately if no packet is waiting."""
209 status=self.MCPrxstatus()&0xC0;
211 #Buffer 0 has higher priority.
212 return self.readrxbuffer(0);
214 #Buffer 1 has lower priority.
215 return self.readrxbuffer(1);
219 ################# TX MANAGEMENT ##################
221 def MCPrts(self,TXB0=False,TXB1=False,TXB2=False):
222 """Requests to send one of the transmit buffers."""
224 if TXB0: flags=flags|1;
225 if TXB1: flags=flags|2;
226 if TXB2: flags=flags|4;
229 print "Warning: Requesting to send no buffer.";
230 self.SPItrans([0x80|flags]);
232 def writetxbuffer(self,packet,packbuf=0):
233 """Writes the transmit buffer."""
235 self.SPItrans([0x40|(packbuf<<1)]+packet);
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)
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)
258 dataLength = dataPt5 & 0x0e
259 print "Data Length: "+("%d"%dataLength)
260 # Print the data packet
262 # Temporary, until correct packets are read
263 if( dataLength > 8 ):
265 toprint = self.pcket2str(packet[5:12])
267 # For reading correct packets
268 # if (dataLength > 8 ):
269 # print "Acceptable Length Exceeded"
270 # Data length value should never exceed 8
272 # toprint = self.pcket2str(packet[5:(5+dataLength)])
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."""
280 self.writetxbuffer(packet,0);
281 self.MCPrts(TXB0=True);
284 ############### UTILITY FUNCTIONS #################
286 def packet2str(self,packet):
287 """Converts a packet from the internal format to a string."""
290 toprint=toprint+("%02x "%ord(bar))
294 ## This code could be drastica
295 def packet2parsed(self,data):
301 #get the ide bit. allows us to check to see if we have an extended
303 packet['ide'] = (dp2 & 0x0f)>>3
304 #we have an extended frame
305 if( packet['ide'] != 0):
306 #get lower nibble, last 2 bits
308 eId = eId<<8 | ord(data[2])
309 eId = eId<<8 | ord(data[3])
311 packet['eID'] = " eID: %06d" %(eId)
312 packet['rtr'] = " rtr: %d" % (rtr)
315 packet['rtr'] = dp2>>4 & 0x01
318 # Create the standard ID. from the message
319 packet['sID'] = dp1<<3 | dp2>>5
320 packet['length'] = dp5 & 0x0f
322 #generate the data section
323 for i in range(0,packet['length']):
326 packet[dbidx] = data[idx]
333 """Read a byte from the given address. Untested."""
334 data=self.SPItrans([0x03,adr&0xFF,00]);
336 def poke8(self,adr,val):
337 """Poke a value into RAM. Untested"""
338 self.SPItrans([0x02,adr&0xFF,val&0xFF]);
339 newval=self.peek8(adr);
341 print "Failed to poke %02x to %02x. Got %02x." % (adr,val,newval);
342 print "Are you not in idle mode?";
344 def MCPbitmodify(self,adr,mask,data):
345 """Writes a byte with a mask. Doesn't work for many registers."""
346 data=self.SPItrans([0x05,adr&0xFF,mask&0xFF,data&0xFF]);
349 ############### DEBUG UTILITIES: STATUS MESSAGES ##############
351 # def MCPrxstatusmessage(self):
352 # """Returns string indicating status of RX buffers"""
353 # status = self.MCPrxstatus();
356 # print "No RX message";
358 # print "Message in RXB0";
360 # print "Message in RXB1";
362 # print "Messages in both buffers";
368 # CNF3/2/1 = 0x28, 29, 2a