rmspeers on GoodFETCCSPI fixing RF_autocrc and adding support to act like a TinyOS...
[goodfet] / client / GoodFETEM260.py
1 #!/usr/bin/env python
2 # GoodFET EM260 Radio Client
3
4 # (C) 2010 Travis Goodspeed <travis at radiantmachines.com>
5 #
6 # This code is being rewritten and refactored.  You've been warned!
7
8 # The EM260 is almost textbook SPI, except that the response cannot be
9 # read until after the nHOST_INT pin of the EM260 drops low and a dummy
10 # byte is read.  That is, the sequence will look like the following:
11
12 # Transmit Host->Slave Data
13 # while(nHOST_INT); //Sleep until ready.
14 # Recv Dummy Byte
15 # Recv Slave->Host Data
16
17 # The delay is mandatory.
18
19 import sys, time, string, cStringIO, struct, glob, serial, os;
20
21 from GoodFETSPI import GoodFETSPI;
22
23 class GoodFETEM260(GoodFETSPI):
24     EM260APP=0x01;
25     seq=0;
26     def EM260trans(self,data,retry=1):
27         """Exchange data by EM260 SPI. (Slightly nonstandard.)"""
28         
29         if retry==0:
30             #Retries exceeded.  Send a trivial command to clear error.
31             data=[0x0A,0xA7];
32         self.writecmd(0x01,0x82,len(data),data);
33         
34         
35         try:
36             reply=ord(self.data[0]);
37             if(reply==0x00):
38                 #print "Warning: EM260 rebooted.";
39                 return self.EM260trans(data,retry-1);
40             if(reply==0x02):
41                 #print "Error: Aborted Transaction.";
42                 return self.EM260trans(data,retry-1);
43             if(reply==0x03):
44                 print "Error: Missing Frame Terminator.";
45                 return self.data;
46             if(reply==0x04):
47                 print "Error: Reserved Error.  (Access denied?)";
48                 return self.data;
49         except:
50             print "Error in EM260trans.";
51         return self.data;
52     
53     def EZSPtrans(self,frame):
54         """Send an EZSP frame."""
55         data=self.EM260trans([0xFE,len(frame)+2,
56                               self.seq&0xFF,0x00,
57                               ]+frame+[
58                               0xA7]);
59         s="EZSP< ";
60         for foo in data:
61             s=s+"%02x " % ord(foo);
62         print s;
63         
64         if ord(data[0])!=0xFE:
65             print "EZSP error: 0x%02x" % ord(data[0]);
66         if ord(data[4])==0x58:
67             print "EZSP Invalid Command because 0x%02x" % ord(data[5]);
68             return data;
69         if frame[0]!=ord(data[4]):
70             print "EZSP warning: Command 0x%02x returned type 0x%02x." % (
71                 frame[0],ord(data[4]));
72         self.seq=self.seq+1;
73         return data;
74         
75     def peek8(self,adr):
76         """Read a byte from the given address.  Untested."""
77         
78         data=self.EZSPtrans([0x47,adr&0xFF,10]);
79         
80         return ord(data[6]);
81     def poke8(self,adr,val):
82         """Poke a value into RAM.  Untested"""
83         self.EZSPtrans([0x46,adr&0xFF,1,val&0xFF]);
84         return val;
85     def rand16(self):
86         """Read a random 16-bit word."""
87         
88         data=self.EZSPtrans([0x49]);
89         if data==None:
90             print "Insufficient random data.";
91             return 0;
92         return ord(data[6])+(ord(data[7])<<8);
93
94     def info(self):
95         """Read the info bytes."""
96         print "Ember EM26 Z-Stack SPI Module.";
97         version=self.EM260spiversion();
98         status=self.EM260spistatus();
99         print "Version: %i" % (version); 
100         print "Status:  %s" % (["dead","alive"][status]);
101         print ""
102         self.setVersion();
103         print "Node ID: %04x" % (self.getNodeID());
104         print "Connected to %2i neighbors." % self.neighborCount();
105     def EM260spiversion(self):
106         """Read the SPI version number from EM260."""
107         data=self.EM260trans([0x0A,0xA7]);        
108         version=ord(data[0]);
109         
110         if version==0x00:
111             return self.EM260spiversion();
112         if version==0x02:
113             return self.EM260spiversion();
114         if not version&0x80:
115             print "Version misread.";
116             return 0;
117         return version&0x7F;
118     
119     def EM260spistatus(self):
120         """Read the status bit."""
121         data=self.EM260trans([0x0B,0xA7]);
122         status=ord(data[0]);
123         
124         if status==0x00:
125             return self.EM260spistatus();
126         if status==0x02:
127             return self.EM260spistatus();
128         if not status&0x80 and status&0x40:
129             print "Status misread.";
130             return 0;
131         return status&1;
132     
133     #Everything after here is ZigBee.
134     
135     def getNodeID(self):
136         """Read the EZSP node id."""
137         
138         data=self.EZSPtrans([0x27]);
139         return ord(data[5])+(ord(data[6])<<8);
140     def neighborCount(self):
141         """Read the count of neighbors, used for iterating the neighbor table."""
142         
143         data=self.EZSPtrans([0x7A]);
144         return ord(data[5]);
145     def setRadioChannel(self,channel):
146         """Set the radio channel."""
147         
148         data=self.EZSPtrans([0x9A, channel&xFF]);
149         return ord(data[5]);
150     def setVersion(self,version=2):
151         """Set the requested EZSP protocol version."""
152         
153         data=self.EZSPtrans([0x00, version]);
154         newversion=ord(data[5]);
155         if version==newversion:
156             print "Version set."
157             print "Protocol %i, stack type %i, Stack Version 0x%02x%02x." % (
158                 newversion,
159                 ord(data[6]),
160                 ord(data[8]),
161                 ord(data[7]));
162         else:
163             self.setVersion(newversion);