update to threading of sniff on mainDisplay as well as added option to sniff in commu...
[goodfet] / client / GoodFETatmel128.py
1 # GoodFET client to interface zigduino/atmel128 radio
2 # forked by bx from code by neighbor Travis Goodspeed
3 from GoodFETAVR import GoodFETAVR
4 import sys, binascii, os, array, time, glob, struct
5
6 fmt = ("B", "<H", None, "<L")
7
8 class GoodFETatmel128rfa1(GoodFETAVR):
9     ATMELRADIOAPP = 0x53
10     def pyserInit(self, port, timeout, attemptlimit):
11         """Open the serial port"""
12         # Make timeout None to wait forever, 0 for non-blocking mode.
13         import serial;
14
15         if os.name=='nt' and sys.version.find('64 bit')!=-1:
16             print "WARNING: PySerial requires a 32-bit Python build in Windows.";
17
18         if port is None and os.environ.get("GOODFET")!=None:
19             glob_list = glob.glob(os.environ.get("GOODFET"));
20             if len(glob_list) > 0:
21                 port = glob_list[0];
22             else:
23                 port = os.environ.get("GOODFET");
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         if port is None:
33             glob_list = glob.glob("/dev/ttyU0");
34             if len(glob_list) > 0:
35                 port = glob_list[0];
36         if port is None and os.name=='nt':
37             from scanwin32 import winScan;
38             scan=winScan();
39             for order,comport,desc,hwid in sorted(scan.comports()):
40                 try:
41                     if hwid.index('FTDI')==0:
42                         port=comport;
43                         #print "Using FTDI port %s" % port
44                 except:
45                     #Do nothing.
46                     a=1;
47
48         baud=115200;
49         self.serialport = serial.Serial(
50             port,
51             baud,
52             parity = serial.PARITY_NONE,
53             timeout=timeout
54             )
55
56         self.verb=0;
57         self.data=""
58         attempts=0;
59         connected=0;
60
61         while connected==0:
62             while self.verb!=0x7F or self.data!="http://goodfet.sf.net/":
63                 if attemptlimit is not None and attempts >= attemptlimit:
64                     return
65                 elif attempts==2 and os.environ.get("board")!='telosb':
66                     print "See the GoodFET FAQ about missing info flash.";
67                     self.serialport.setTimeout(0.2);
68                     #Explicitly set RTS and DTR to halt board.
69                     self.serialport.setRTS(1);
70                     self.serialport.setDTR(1);
71                     #Drop DTR, which is !RST, low to begin the app.
72                     self.serialport.setDTR(0);
73
74                 attempts=attempts+1;
75                 self.readcmd(); #Read the first command.
76                 if self.verbose:
77                     print "Got %02x,%02x:'%s'" % (self.app,self.verb,self.data);
78
79             #Here we have a connection, but maybe not a good one.
80             #print "We have a connection."
81             for foo in range(1,30):
82                 time.sleep(1)
83                 if not self.monitorecho():
84                     connected = 0
85                     if self.verbose:
86                         print "Comm error on try %i." % (foo)
87                 else:
88                     connected = 1
89                     break
90         if self.verbose:
91             print "Connected after %02i attempts." % attempts;
92         self.serialport.setTimeout(12);
93
94
95     def writecmd(self, app, verb, count=0, data=[]):
96         """Write a command and some data to the GoodFET."""
97         self.serialport.write(chr(app));
98         self.serialport.write(chr(verb));
99
100         if count > 0:
101             if(isinstance(data,list)):
102                 old = data
103                 data = []
104                 for i in range(0,count):
105                     data += chr(old[i]);
106             outstr=''.join(data);
107
108         #little endian 16-bit length
109             count = len(outstr)
110             self.serialport.write(chr(count&0xFF));
111             self.serialport.write(chr(count>>8));
112             if self.verbose:
113                 print "Tx: ( 0x%02x, 0x%02x, %d )" % ( app, verb, count )
114                 print "sending: %s" %outstr.encode("hex")
115
116             self.serialport.write(outstr);
117         else: # count == 0
118             self.serialport.write("\x00")
119             self.serialport.write("\x00")
120
121         if not self.besilent:
122             out = self.readcmd()
123             #if out:
124             #    print "read: " + out
125             return out
126         else:
127             return []
128
129     def readcmd(self):
130         """Read a reply from the GoodFET."""
131         app = self.serialport.read(1)
132         if len(app) < 1:
133             self.app = 0
134             self.verb = 0
135             self.count = 0
136             self.data = ""
137             return
138
139         self.app=ord(app);
140         self.verb=ord(self.serialport.read(1));
141
142         self.count= ord(self.serialport.read(1)) + (ord(self.serialport.read(1))<<8)
143
144         if self.verbose:
145             print "Rx: ( 0x%02x, 0x%02x, %i )" % ( self.app, self.verb, self.count )
146
147         #Debugging string; print, but wait.
148         if self.app==0xFF:
149             if self.verb==0xFF:
150                 print "# DEBUG %s" % self.serialport.read(self.count)
151             elif self.verb==0xFE:
152                 print "# DEBUG 0x%x" % struct.unpack(fmt[self.count-1], self.serialport.read(self.count))[0]
153             elif self.verb==0xFD:
154                         #Do nothing, just wait so there's no timeout.
155                 print "# NOP.";
156             return ""
157         else:
158             self.data=self.serialport.read(self.count);
159             return self.data;
160
161     def RF_setchannel(self, chan):
162         if (chan < 11) or (chan > 26):
163             print "Channel out of range"
164         else:
165             self.poke(0x8, chan)
166
167     def peek(self,reg,bytes=-1):
168         """Read a Register. """
169         #Automatically calibrate the len.
170         if bytes==-1:
171             bytes=1;
172             #if reg==0x0a or reg==0x0b or reg==0x10: bytes=5;
173         data = [reg, 0, bytes%255, bytes>>8] + ([0]*bytes)
174         self.writecmd(self.ATMELRADIOAPP,0x02,len(data),data);
175         toret=0;
176         #print self.data.encode("hex")
177         if self.data:
178             #for i in range(0,bytes):
179             #    toret=toret|(ord(self.data[i+1])<<(8*i));
180             #return toret;
181             # right now only works with a byte of data
182             return ord(self.data)
183         else:
184             return -1
185
186     def poke(self,reg,val,bytes=-1):
187         """Write an Register."""
188         data=[reg, 0]
189
190         #Automatically calibrate the len.
191         if bytes==-1:
192             bytes=1;
193             #if reg==0x0a or reg==0x0b or reg==0x10: bytes=5;
194         for i in range(0,bytes):
195             data=data+[(val>>(8*i))&0xFF];
196
197         self.writecmd(self.ATMELRADIOAPP,0x03,len(data),data);
198         if self.peek(reg,bytes)!=val:
199             print "Warning, failed to set r%02x=%02x, got %02x." %(
200                 reg,
201                 val,
202                 self.peek(reg,bytes));
203
204         return;
205
206
207     def RF_setup(self):
208         self.writecmd(self.ATMELRADIOAPP, 0x10, 0, None)
209
210     def RF_rxpacket(self):
211         """Get a packet from the radio.  Returns None if none is waiting."""
212         #doto: check if packet has arrived, flush if not new
213         self.writecmd(self.ATMELRADIOAPP, 0x80, 0, None)
214         data=self.data;
215         self.packetlen = len(data)
216         if (self.packetlen > 0):
217             return data;
218         else:
219             return None
220
221     def RX_txpacket(self, payload):
222         self.writecmd(self.ATMELRADIOAPP, 0x81, len(payload)+1,chr(len(payload))+payload)