added new mcpCAN communication file to allow for easier testing and data storage.
[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 # This code is being rewritten and refactored.  You've been warned!
7 #
8
9 # The MCP2515 is a CAN Bus to SPI adapter from Microchip Technology,
10 # as used in the Goodthopter series of boards.  It requires a separate
11 # chip for voltage level conversion, such as the MCP2551.
12
13 import sys, time, string, cStringIO, struct, glob, os;
14
15 from GoodFETSPI import GoodFETSPI;
16
17 class GoodFETMCPCAN(GoodFETSPI):
18     """This class uses the regular SPI app to implement a CAN Bus
19     adapter on the Goodthopter10 hardware."""
20     MCPMODES=["Normal","Sleep","Loopback","Listen-only","Configuration",
21               "UNKNOWN","UNKNOWN","PowerUp"];
22     def MCPsetup(self):
23         """Sets up the ports."""
24         self.SPIsetup();
25         self.MCPreset(); #Reset the chip.
26         
27         # We're going to set some registers, so we must be in config
28         # mode.
29         self.MCPreqstatConfiguration();
30         
31         # If we don't enable promiscous mode, we'll miss a lot of
32         # packets.  It can be manually disabled later.
33         #self.poke8(0x60,0xFF); #TODO Does this have any unpleasant side effects?
34         self.poke8(0x60,0x66); #Wanted FF, but some bits are reserved.
35         
36         #Set the default rate.
37         self.MCPsetrate();
38     
39     #Array of supported rates.
40     MCPrates=[83.3, 100, 125,
41               250, 500, 1000];
42     
43     def MCPsetrate(self,rate=125):
44         """Sets the data rate in kHz."""
45         # Now we need to set the timing registers.  See chapter 5 of
46         # the MCP2515 datasheet to get some clue as to how this
47         # arithmetic of this works, as my comments here will likely be
48         # rambling, incoherent, and unchanged after I get the infernal
49         # thing working.
50         
51         # First, we must chose a Time Quanta (QT) which is used to
52         # define the durations of these segments.  Section 5.3
53         # suggests setting BRP<5:0> to 0x04 to get a TQ=500ns, as a 20
54         # MHz crystal gives a clock period of 50ns.  This way, for 125
55         # kHz communication, the bit time must be 16 TQ.
56         
57         # A bit consists of four parts:
58         # 1: SyncSeg             1 TQ
59         # 2: PropSeg             2 TQ
60         # 3: PhaseSeg1 (PS1)     7 TQ
61         # 4: PhaseSeg2 (PS2)     6 TQ
62         
63         # CNF1 with a prescaler of 4 and a SJW of 1 TQ.  SJW of 4
64         # might be more stable.
65         #self.poke8(0x2a,0x04);
66         
67         # CNF2 with a BLTMODE of 1, SAM of 0, PS1 of 7TQ, and PRSEG of 2TQ
68         #self.poke8(0x29,
69         #           0x80   |  # BTLMODE=1
70         #           (6<<3) |  # 6+1=7TQ for PHSEG1
71         #           (1)       # 1+1=2TQ for PRSEG
72         #           );
73         
74         #CNF3 with a PS2 length of 6TQ.
75         #self.poke8(0x28,
76         #           5      #5+1=6TQ
77         #           );
78         
79         
80         print "Setting rate of %i kHz." % rate;
81         
82         #These are the new examples.
83         if rate==125:
84             #125 kHz, 16 TQ, not quite as worked out above.
85             CNF1=0x04;
86             CNF2=0xB8;
87             CNF3=0x05;
88         elif rate==100:
89             #100 kHz, 20 TQ
90             CNF1=0x04;
91             CNF2=0xBA;
92             CNF3=0x07;
93         elif rate>83 and rate<83.5:
94             #83+1/3 kHz, 8 TQ
95             # 0.04% error from 83.30
96             CNF1=0x0E;
97             CNF2=0x90;
98             CNF3=0x02;
99         elif rate==250:
100             #256 kHz, 20 TQ
101             CNF1=0x01;
102             CNF2=0xBA;
103             CNF3=0x07;
104         elif rate==500:
105             #500 kHz, 20 TQ
106             CNF1=0x00;
107             CNF2=0xBA;
108             CNF3=0x07;
109         elif rate==1000:
110             #1,000 kHz, 10 TQ
111             CNF1=0x00;
112             CNF2=0xA0;
113             CNF3=0x02;
114             print "WARNING: Because of chip errata, this probably won't work."
115         else:
116             print "Given unsupported rate of %i kHz." % rate;
117             print "Defaulting to 125kHz.";
118             CNF1=0x04;
119             CNF2=0xB8;
120             CNF3=0x05;
121         self.poke8(0x2a,CNF1);
122         self.poke8(0x29,CNF2);
123         self.poke8(0x28,CNF3);
124         
125     def MCPreset(self):
126         """Reset the MCP2515 chip."""
127         self.SPItrans([0xC0]);
128     def MCPcanstat(self):
129         """Get the CAN Status."""
130         return self.peek8(0x0E);
131     def MCPreqstatNormal(self):
132         """Set the CAN state."""
133         state=0x0;
134         self.MCPbitmodify(0x0F,0xE0,(state<<5));
135     def MCPreqstatSleep(self):
136         """Set the CAN state."""
137         state=0x1;
138         self.MCPbitmodify(0x0F,0xE0,(state<<5));
139     def MCPreqstatLoopback(self):
140         """Set the CAN state."""
141         state=0x2;
142         self.MCPbitmodify(0x0F,0xE0,(state<<5));
143     def MCPreqstatListenOnly(self):
144         """Set the CAN state."""
145         state=0x3;
146         self.MCPbitmodify(0x0F,0xE0,(state<<5));
147     def MCPreqstatConfiguration(self):
148         """Set the CAN state."""
149         state=0x4;
150         self.MCPbitmodify(0x0F,0xE0,(state<<5));
151     
152     def MCPcanstatstr(self):
153         """Read the present status as a string."""
154         status=self.MCPcanstat();
155         opmod=(status&0xE0)>>5;
156         return self.MCPMODES[opmod];
157     def MCPrxstatus(self):
158         """Reads the RX Status by the SPI verb of the same name."""
159         data=self.SPItrans([0xB0,0x00]);
160         return ord(data[1]);
161
162     def MCPreadstatus(self):
163         """Reads the Read Status by the SPI verb of the same name."""
164         #See page 67 of the datasheet for the flag names.
165         data=self.SPItrans([0xA0,0x00]);
166         return ord(data[1]);
167
168     def MCPrts(self,TXB0=False,TXB1=False,TXB2=False):
169         """Requests to send one of the transmit buffers."""
170         flags=0;
171         if TXB0: flags=flags|1;
172         if TXB1: flags=flags|2;
173         if TXB2: flags=flags|4;
174         
175         if flags==0:
176             print "Warning: Requesting to send no buffer.";
177         
178         self.SPItrans([0x80|flags]);
179     def readrxbuffer(self,packbuf=0):
180         """Reads the RX buffer.  Might have old data."""
181         data=self.SPItrans([0x90|(packbuf<<2),
182                        0x00,0x00, #SID
183                        0x00,0x00, #EID
184                        0x00,      #DLC
185                        0x00, 0x00, 0x00, 0x00,
186                        0x00, 0x00, 0x00, 0x00
187                        ]);
188         return data[1:len(data)];
189     def writetxbuffer(self,packet,packbuf=0):
190         """Writes the transmit buffer."""
191         self.SPItrans([0x40|(packbuf<<1)]+packet);
192         
193     def rxpacket(self):
194         """Reads the next incoming packet from either buffer.
195         Returns None immediately if no packet is waiting."""
196         status=self.MCPrxstatus()&0xC0;
197         if status&0x40:
198             #Buffer 0 has higher priority.
199             return self.readrxbuffer(0);
200         elif status&0x80:
201             #Buffer 1 has lower priority.
202             return self.readrxbuffer(1);
203         else:
204             return None;
205     def txpacket(self,packet):
206         """Transmits a packet through one of the outbound buffers.
207         As usual, the packet should begin with SIDH.
208         For now, only TXB0 is supported."""
209         self.writetxbuffer(packet,0);
210         self.MCPrts(TXB0=True);
211     def packet2str(self,packet):
212         """Converts a packet from the internal format to a string."""
213         toprint="";
214         for bar in packet:
215             toprint=toprint+("%02x "%ord(bar))
216         return toprint;
217     def peek8(self,adr):
218         """Read a byte from the given address.  Untested."""
219         data=self.SPItrans([0x03,adr&0xFF,00]);
220         return ord(data[2]);
221     def MCPbitmodify(self,adr,mask,data):
222         """Writes a byte with a mask.  Doesn't work for many registers."""
223         data=self.SPItrans([0x05,adr&0xFF,mask&0xFF,data&0xFF]);
224         return ord(data[2]);
225     def poke8(self,adr,val):
226         """Poke a value into RAM.  Untested"""
227         self.SPItrans([0x02,adr&0xFF,val&0xFF]);
228         newval=self.peek8(adr);
229         if newval!=val:
230             print "Failed to poke %02x to %02x.  Got %02x." % (adr,val,newval);
231             print "Are you not in idle mode?";
232         return val;