MCP2515 can now loopback packets!
[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         #Loopback mode for testing.
28         self.MCPreqstatConfiguration();
29     def MCPreset(self):
30         """Reset the MCP2515 chip."""
31         self.SPItrans([0xC0]);
32     def MCPcanstat(self):
33         """Get the CAN Status."""
34         return self.peek8(0x0E);
35     def MCPreqstatNormal(self):
36         """Set the CAN state."""
37         state=0x0;
38         self.MCPbitmodify(0x0F,0xE0,(state<<5));
39     def MCPreqstatSleep(self):
40         """Set the CAN state."""
41         state=0x1;
42         self.MCPbitmodify(0x0F,0xE0,(state<<5));
43     def MCPreqstatLoopback(self):
44         """Set the CAN state."""
45         state=0x2;
46         self.MCPbitmodify(0x0F,0xE0,(state<<5));
47     def MCPreqstatListenOnly(self):
48         """Set the CAN state."""
49         state=0x3;
50         self.MCPbitmodify(0x0F,0xE0,(state<<5));
51     def MCPreqstatConfiguration(self):
52         """Set the CAN state."""
53         state=0x4;
54         self.MCPbitmodify(0x0F,0xE0,(state<<5));
55     
56     def MCPcanstatstr(self):
57         """Read the present status as a string."""
58         status=self.MCPcanstat();
59         opmod=(status&0xE0)>>5;
60         return self.MCPMODES[opmod];
61     def MCPrxstatus(self):
62         """Reads the RX Status by the SPI verb of the same name."""
63         data=self.SPItrans([0xB0,0x00]);
64         return ord(data[1]);
65
66     def MCPreadstatus(self):
67         """Reads the Read Status by the SPI verb of the same name."""
68         #See page 67 of the datasheet for the flag names.
69         data=self.SPItrans([0xA0,0x00]);
70         return ord(data[1]);
71
72     def MCPrts(self,TXB0=False,TXB1=False,TXB2=False):
73         """Requests to send one of the transmit buffers."""
74         flags=0;
75         if TXB0: flags=flags|1;
76         if TXB1: flags=flags|2;
77         if TXB2: flags=flags|4;
78         
79         if flags==0:
80             print "Warning: Requesting to send no buffer.";
81         
82         self.SPItrans([0x80|flags]);
83     def readrxbuffer(self,packbuf=0):
84         """Reads the RX buffer.  Might have old data."""
85         data=self.SPItrans([0x90|(packbuf<<2),
86                        0x00,0x00, #SID
87                        0x00,0x00, #EID
88                        0x00,      #DLC
89                        0x00, 0x00, 0x00, 0x00,
90                        0x00, 0x00, 0x00, 0x00
91                        ]);
92         return data[1:len(data)];
93     def writetxbuffer(self,packet,packbuf=0):
94         """Writes the transmit buffer."""
95         self.SPItrans([0x40|(packbuf<<1)]+packet);
96         
97     def rxpacket(self):
98         """Reads the next incoming packet from either buffer.
99         Returns None immediately if no packet is waiting."""
100         status=self.MCPrxstatus()&0xC0;
101         if status&0x40:
102             #Buffer 0 has higher priority.
103             return self.readrxbuffer(0);
104         elif status&0x80:
105             #Buffer 1 has lower priority.
106             return self.readrxbuffer(1);
107         else:
108             return None;
109     def txpacket(self,packet):
110         """Transmits a packet through one of the outbound buffers.
111         As usual, the packet should begin with SIDH.
112         For now, only TXB0 is supported."""
113         self.writetxbuffer(packet,0);
114         self.MCPrts(TXB0=True);
115     def packet2str(self,packet):
116         """Converts a packet from the internal format to a string."""
117         toprint="";
118         for bar in packet:
119             toprint=toprint+("%02x "%ord(bar))
120         return toprint;
121     def peek8(self,adr):
122         """Read a byte from the given address.  Untested."""
123         data=self.SPItrans([0x03,adr&0xFF,00]);
124         return ord(data[2]);
125     def MCPbitmodify(self,adr,mask,data):
126         """Writes a byte with a mask.  Doesn't work for many registers."""
127         data=self.SPItrans([0x05,adr&0xFF,mask&0xFF,data&0xFF]);
128         return ord(data[2]);
129     def poke8(self,adr,val):
130         """Poke a value into RAM.  Untested"""
131         self.SPItrans([0x02,adr&0xFF,val&0xFF]);
132         return val;