cf01c85cd341d9a13bb677208f4cba5a157c89c8
[goodfet] / client / GoodFET.py
1 #!/usr/bin/env python
2 # GoodFET Client Library
3
4 # (C) 2009 Travis Goodspeed <travis at radiantmachines.com>
5 #
6 # This code is being rewritten and refactored.  You've been warned!
7
8 import sys, time, string, cStringIO, struct, glob, serial, os;
9
10
11 class GoodFET:
12     """GoodFET Client Library"""
13     def __init__(self, *args, **kargs):
14         self.data=[0];
15     def timeout(self):
16         print "timeout\n";
17     def serInit(self, port=None):
18         """Open the serial port"""
19         
20         if port is None and os.environ.get("GOODFET")!=None:
21             glob_list = glob.glob(os.environ.get("GOODFET"));
22             if len(glob_list) > 0:
23                 port = glob_list[0];
24         if port is None:
25             glob_list = glob.glob("/dev/tty.usbserial*");
26             if len(glob_list) > 0:
27                 port = glob_list[0];
28         if port is None:
29             glob_list = glob.glob("/dev/ttyUSB*");
30             if len(glob_list) > 0:
31                 port = glob_list[0];
32         
33         self.serialport = serial.Serial(
34             port,
35             #9600,
36             115200,
37             parity = serial.PARITY_NONE
38             )
39         #Drop DTR, which is !RST, low to begin the app.
40         self.serialport.setDTR(0);
41         self.serialport.flushInput()
42         self.serialport.flushOutput()
43         
44         #Read and handle the initial command.
45         #time.sleep(1);
46         self.readcmd(); #Read the first command.
47         if(self.verb!=0x7F):
48             print "Verb %02x is wrong.  Incorrect firmware?" % self.verb;
49         #print "Connected."
50     def writecmd(self, app, verb, count=0, data=[], blocks=1):
51         """Write a command and some data to the GoodFET."""
52         self.serialport.write(chr(app));
53         self.serialport.write(chr(verb));
54         self.serialport.write(chr(count));
55         #print "count=%02x, len(data)=%04x" % (count,len(data));
56         if count!=0:
57             for d in data:
58                 self.serialport.write(chr(d));
59         
60         self.readcmd(blocks);  #Uncomment this later, to ensure a response.
61     def readcmd(self,blocks=1):
62         """Read a reply from the GoodFET."""
63         self.app=ord(self.serialport.read(1));
64         self.verb=ord(self.serialport.read(1));
65         self.count=ord(self.serialport.read(1));
66         self.data=self.serialport.read(self.count*blocks);
67         #print "READ %02x %02x %02x " % (self.app, self.verb, self.count);
68         return self.data;
69         
70     #Monitor stuff
71     def out(self,byte):
72         """Write a byte to P5OUT."""
73         self.writecmd(0,0xA1,1,[byte]);
74     def dir(self,byte):
75         """Write a byte to P5DIR."""
76         self.writecmd(0,0xA0,1,[byte]);
77     def peekbyte(self,address):
78         """Read a byte of memory from the monitor."""
79         self.data=[address&0xff,address>>8];
80         self.writecmd(0,0x02,2,self.data);
81         #self.readcmd();
82         return ord(self.data[0]);
83     def peekword(self,address):
84         """Read a word of memory from the monitor."""
85         return self.peekbyte(address)+(self.peekbyte(address+1)<<8);
86     def pokebyte(self,address,value):
87         """Set a byte of memory by the monitor."""
88         self.data=[address&0xff,address>>8,value];
89         self.writecmd(0,0x03,3,self.data);
90         return ord(self.data[0]);
91     def dumpmem(self,begin,end):
92         i=begin;
93         while i<end:
94             print "%04x %04x" % (i, self.peekword(i));
95             i+=2;
96     def monitor_ram_pattern(self):
97         """Overwrite all of RAM with 0xBEEF."""
98         self.writecmd(0,0x90,0,self.data);
99         return;
100     def monitor_ram_depth(self):
101         """Determine how many bytes of RAM are unused by looking for 0xBEEF.."""
102         self.writecmd(0,0x91,0,self.data);
103         return ord(self.data[0])+(ord(self.data[1])<<8);
104     
105     #Baud rates.
106     baudrates=[115200, 
107                9600,
108                19200,
109                38400,
110                57600,
111                115200];
112     def setBaud(self,baud):
113         """Change the baud rate.  TODO fix this."""
114         rates=self.baudrates;
115         self.data=[baud];
116         print "Changing FET baud."
117         self.serialport.write(chr(0x00));
118         self.serialport.write(chr(0x80));
119         self.serialport.write(chr(1));
120         self.serialport.write(chr(baud));
121         
122         print "Changed host baud."
123         self.serialport.setBaudrate(rates[baud]);
124         time.sleep(1);
125         self.serialport.flushInput()
126         self.serialport.flushOutput()
127         
128         print "Baud is now %i." % rates[baud];
129         return;
130     def readbyte(self):
131         return ord(self.serialport.read(1));
132     def findbaud(self):
133         for r in self.baudrates:
134             print "\nTrying %i" % r;
135             self.serialport.setBaudrate(r);
136             #time.sleep(1);
137             self.serialport.flushInput()
138             self.serialport.flushOutput()
139             
140             for i in range(1,10):
141                 self.readbyte();
142             
143             print "Read %02x %02x %02x %02x" % (
144                 self.readbyte(),self.readbyte(),self.readbyte(),self.readbyte());
145     def monitortest(self):
146         """Self-test several functions through the monitor."""
147         print "Performing monitor self-test.";
148         
149         if self.peekword(0x0c00)!=0x0c04 and self.peekword(0x0c00)!=0x0c06:
150             print "ERROR Fetched wrong value from 0x0c04.";
151         self.pokebyte(0x0021,0); #Drop LED
152         if self.peekbyte(0x0021)!=0:
153             print "ERROR, P1OUT not cleared.";
154         self.pokebyte(0x0021,1); #Light LED
155         
156         print "Self-test complete.";
157     
158     
159
160     def I2Csetup(self):
161         """Move the FET into the I2C application."""
162         self.writecmd(0x02,0x10,0,self.data); #SPI/SETUP
163     def I2Cstart(self):
164         """Start an I2C transaction."""
165         self.writecmd(0x02,0x20,0,self.data); #SPI/SETUP
166     def I2Cstop(self):
167         """Stop an I2C transaction."""
168         self.writecmd(0x02,0x21,0,self.data); #SPI/SETUP
169     def I2Cread(self,len=1):
170         """Read len bytes by I2C."""
171         self.writecmd(0x02,0x00,1,[len]); #SPI/SETUP
172         return self.data;
173     def I2Cwrite(self,bytes):
174         """Write bytes by I2C."""
175         self.writecmd(0x02,0x01,len(bytes),bytes); #SPI/SETUP
176         return ord(self.data[0]);
177 class GoodFETCC(GoodFET):
178     """A GoodFET variant for use with Chipcon 8051 Zigbe SoC."""
179     def CChaltcpu(self):
180         """Halt the CPU."""
181         self.writecmd(0x30,0x86,0,self.data);
182     def CCreleasecpu(self):
183         """Resume the CPU."""
184         self.writecmd(0x30,0x87,0,self.data);
185     def CCtest(self):
186         self.CCreleasecpu();
187         self.CChaltcpu();
188         #print "Status: %s" % self.CCstatusstr();
189         
190         #Grab ident three times, should be equal.
191         ident1=self.CCident();
192         ident2=self.CCident();
193         ident3=self.CCident();
194         if(ident1!=ident2 or ident2!=ident3):
195             print "Error, repeated ident attempts unequal."
196             print "%04x, %04x, %04x" % (ident1, ident2, ident3);
197         
198         #Single step, printing PC.
199         print "Tracing execution at startup."
200         for i in range(1,15):
201             pc=self.CCgetPC();
202             byte=self.CCpeekcodebyte(i);
203             #print "PC=%04x, %02x" % (pc, byte);
204             self.CCstep_instr();
205         
206         print "Verifying that debugging a NOP doesn't affect the PC."
207         for i in range(1,15):
208             pc=self.CCgetPC();
209             self.CCdebuginstr([0x00]);
210             if(pc!=self.CCgetPC()):
211                 print "ERROR: PC changed during CCdebuginstr([NOP])!";
212         
213         
214         #print "Status: %s." % self.CCstatusstr();
215         #Exit debugger
216         self.CCstop();
217         print "Done.";
218
219     def CCsetup(self):
220         """Move the FET into the CC2430/CC2530 application."""
221         #print "Initializing Chipcon.";
222         self.writecmd(0x30,0x10,0,self.data);
223     def CCrd_config(self):
224         """Read the config register of a Chipcon."""
225         self.writecmd(0x30,0x82,0,self.data);
226         return ord(self.data[0]);
227     def CCwr_config(self,config):
228         """Write the config register of a Chipcon."""
229         self.writecmd(0x30,0x81,1,[config&0xFF]);
230     
231     CCversions={0x0100:"CC1110",
232                 0x8500:"CC2430",
233                 0x8900:"CC2431",
234                 0x8100:"CC2510",
235                 0x9100:"CC2511",
236                 0xFF00:"CCmissing"};
237     def CCidentstr(self):
238         ident=self.CCident();
239         chip=self.CCversions.get(ident&0xFF00);
240         return "%s/r%02x" % (chip, ident&0xFF); 
241     def CCident(self):
242         """Get a chipcon's ID."""
243         self.writecmd(0x30,0x8B,0,None);
244         chip=ord(self.data[0]);
245         rev=ord(self.data[1]);
246         return (chip<<8)+rev;
247     def CCgetPC(self):
248         """Get a chipcon's PC."""
249         self.writecmd(0x30,0x83,0,None);
250         hi=ord(self.data[0]);
251         lo=ord(self.data[1]);
252         return (hi<<8)+lo;
253     def CCdebuginstr(self,instr):
254         self.writecmd(0x30,0x88,len(instr),instr);
255         return ord(self.data[0]);
256     def CCpeekcodebyte(self,adr):
257         """Read the contents of code memory at an address."""
258         self.data=[adr&0xff, (adr&0xff00)>>8];
259         self.writecmd(0x30,0x90,2,self.data);
260         return ord(self.data[0]);
261     def CCpeekdatabyte(self,adr):
262         """Read the contents of data memory at an address."""
263         self.data=[adr&0xff, (adr&0xff00)>>8];
264         self.writecmd(0x30,0x91, 2, self.data);
265         return ord(self.data[0]);
266     def CCpokedatabyte(self,adr,val):
267         """Write a byte to data memory."""
268         self.data=[adr&0xff, (adr&0xff00)>>8, val];
269         self.writecmd(0x30, 0x92, 3, self.data);
270         return ord(self.data[0]);
271     def CCchiperase(self):
272         """Erase all of the target's memory."""
273         self.writecmd(0x30,0x80,0,None);
274     def CCstatus(self):
275         """Check the status."""
276         self.writecmd(0x30,0x84,0,None);
277         return ord(self.data[0])
278     CCstatusbits={0x80 : "erased",
279                   0x40 : "pcon_idle",
280                   0x20 : "halted",
281                   0x10 : "pm0",
282                   0x08 : "halted",
283                   0x04 : "locked",
284                   0x02 : "oscstable",
285                   0x01 : "overflow"};
286     def CCstatusstr(self):
287         """Check the status as a string."""
288         status=self.CCstatus();
289         str="";
290         i=1;
291         while i<0x100:
292             if(status&i):
293                 str="%s %s" %(self.CCstatusbits[i],str);
294             i*=2;
295         return str;
296     def CCstart(self):
297         """Start debugging."""
298         self.writecmd(0x30,0x20,0,self.data);
299         ident=self.CCidentstr();
300         print "Target identifies as %s." % ident;
301         #print "Status: %s." % self.CCstatusstr();
302         self.CCreleasecpu();
303         self.CChaltcpu();
304         #print "Status: %s." % self.CCstatusstr();
305         
306     def CCstop(self):
307         """Stop debugging."""
308         self.writecmd(0x30,0x21,0,self.data);
309     def CCstep_instr(self):
310         """Step one instruction."""
311         self.writecmd(0x30,0x89,0,self.data);
312