3b4a63afcef6401ecfe0b68ecece76dcddb0e60b
[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 rxpacket(self):
204         """Reads the next incoming packet from either buffer.
205             Returns None immediately if no packet is waiting."""
206         status=self.MCPrxstatus()&0xC0;
207         if status&0x40:
208             #Buffer 0 has higher priority.
209             return self.readrxbuffer(0);
210         elif status&0x80:
211             #Buffer 1 has lower priority.
212             return self.readrxbuffer(1);
213         else:
214             return None;
215
216     #################      TX MANAGEMENT    ##################
217             
218     def MCPrts(self,TXB0=False,TXB1=False,TXB2=False):
219         """Requests to send one of the transmit buffers."""
220         flags=0;
221         if TXB0: flags=flags|1;
222         if TXB1: flags=flags|2;
223         if TXB2: flags=flags|4;
224         
225         if flags==0:
226             print "Warning: Requesting to send no buffer.";
227         if self.MCPcanstat()>>5!=0:
228             print "Warning: currently in %s mode. NOT in normal mode! May not transmit." %self.MCPcanstatstr();
229         self.SPItrans([0x80|flags]);
230     
231     def writetxbuffer(self,packet,packbuf=0):
232         """Writes the transmit buffer."""
233         
234         self.SPItrans([0x40|(packbuf<<1)]+packet);
235         #READ BACK BUFFER 0 to check what we're about to send out
236         data=self.SPItrans([0x03, 0x31,                        
237                             0x00,0x00, #SID
238                             0x00,0x00, #EID
239                             0x00,      #DLC
240                             0x00, 0x00, 0x00, 0x00,
241                             0x00, 0x00, 0x00, 0x00
242                             ]);
243         print "about to transmit:" + self.packet2str(data[2:len(data)]);
244         
245     def txpacket(self,packet):
246         """Transmits a packet through one of the outbound buffers.
247         As usual, the packet should begin with SIDH.
248         For now, only TXB0 is supported."""
249
250         self.writetxbuffer(packet,0);
251
252         #self.SPItrans([0x81]);
253         self.MCPrts(TXB0=True);
254
255                 
256     ###############   UTILITY FUNCTIONS  #################
257             
258     def packet2str(self,packet):
259         """Converts a packet from the internal format to a string."""
260         toprint="";
261         for bar in packet:
262             toprint=toprint+("%02x "%ord(bar))
263         return toprint;
264     def peek8(self,adr):
265         """Read a byte from the given address.  Untested."""
266         data=self.SPItrans([0x03,adr&0xFF,00]);
267         return ord(data[2]);
268     def poke8(self,adr,val):
269         """Poke a value into RAM.  Untested"""
270         self.SPItrans([0x02,adr&0xFF,val&0xFF]);
271         newval=self.peek8(adr);
272         if newval!=val:
273             print "Failed to poke %02x to %02x.  Got %02x." % (adr,val,newval);
274             print "Are you not in idle mode?";
275         return val;
276     def MCPbitmodify(self,adr,mask,data):
277         """Writes a byte with a mask.  Doesn't work for many registers."""
278         data=self.SPItrans([0x05,adr&0xFF,mask&0xFF,data&0xFF]);
279         return ord(data[2]);
280
281 ############### DEBUG UTILITIES: STATUS MESSAGES ##############
282
283 #    def MCPrxstatusmessage(self):
284 #        """Returns string indicating status of RX buffers"""
285 #        status = self.MCPrxstatus();
286 #
287 #        if status < 64:
288 #            print "No RX message";
289 #        elif status < 128:
290 #            print "Message in RXB0";
291 #        elif status < 192:
292 #            print "Message in RXB1";
293 #        else:
294 #            print "Messages in both buffers";
295
296
297
298 # TXB0TRL = 0x30
299 # RXB0CTRL = 0x60
300 # CNF3/2/1 = 0x28, 29, 2a
301 # CANINTE = 0x2b
302 # CANINTF = 0x2c
303 # TXRTSCTRL = x0D
304
305
306