root / trunk / common / common.py @ 300
History | View | Annotate | Download (6.26 KB)
1 | 222 | bneuman | """
|
---|---|---|---|
2 | This file is part of Tooltron.
|
||
3 |
|
||
4 | Tooltron is free software: you can redistribute it and/or modify
|
||
5 | it under the terms of the Lesser GNU General Public License as published by
|
||
6 | the Free Software Foundation, either version 3 of the License, or
|
||
7 | (at your option) any later version.
|
||
8 |
|
||
9 | Tooltron is distributed in the hope that it will be useful,
|
||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
12 | Lesser GNU General Public License for more details.
|
||
13 | You should have received a copy of the Lesser GNU General Public License
|
||
14 | along with Tooltron. If not, see <http://www.gnu.org/licenses/>.
|
||
15 |
|
||
16 | Copyright 2009 Bradford Neuman <bneuman@andrew.cmu.edu>
|
||
17 |
|
||
18 | """
|
||
19 | |||
20 | ####
|
||
21 | # This file contains common code for both manualTron and the real tooltron server
|
||
22 | |||
23 | import serial |
||
24 | import sys |
||
25 | 244 | bneuman | import time |
26 | 283 | bneuman | import re |
27 | 222 | bneuman | |
28 | 250 | bneuman | keypadTimeout = 31 #in seconds |
29 | 222 | bneuman | |
30 | TT_ACK = 'a'
|
||
31 | TT_NACK = 'n'
|
||
32 | TT_TIMEOUT = 't'
|
||
33 | 282 | bneuman | TT_KC = 'x' # A transaction containing a key and a card number |
34 | TT_GRANT = 'q' # Tool access granted |
||
35 | TT_DENY = 'f' # Tool access denied |
||
36 | 222 | bneuman | TT_PING = 'g'
|
37 | 224 | bneuman | TT_BOOT = 'b'
|
38 | TT_PROGRAM_MODE = 'p'
|
||
39 | TT_RESET = 'r'
|
||
40 | TT_PING = 'g'
|
||
41 | TT_BAD = 0
|
||
42 | 225 | bneuman | TT_PROGM = 'p'
|
43 | TT_PROGD = 'd'
|
||
44 | 222 | bneuman | |
45 | 286 | bneuman | #depricated
|
46 | 294 | rc99 | #TT_ON = 'o'
|
47 | 286 | bneuman | |
48 | 243 | bneuman | TT_MAX_RETRY = 3
|
49 | 225 | bneuman | |
50 | 222 | bneuman | MAX_PAYLOAD_LEN = 32
|
51 | |||
52 | BAUD_RATE = 9600
|
||
53 | |||
54 | 282 | bneuman | # cardbox id
|
55 | CARDBOX_ID = 2
|
||
56 | |||
57 | 222 | bneuman | #fails until a warning is sent
|
58 | MAX_TOOL_FAILS = 5
|
||
59 | |||
60 | bus = None
|
||
61 | |||
62 | class BusException(Exception): |
||
63 | def __str__(self): |
||
64 | return "Bus Not Init'd" |
||
65 | |||
66 | 236 | bneuman | class TimeoutException(Exception): |
67 | def __init__(self, val): |
||
68 | Exception.__init__(self) |
||
69 | self.str = val
|
||
70 | |||
71 | def __str__(self): |
||
72 | return "TimeoutException: " + self.str |
||
73 | |||
74 | 222 | bneuman | def printMsg(msg): |
75 | if len(msg) < 5: |
||
76 | print "ERROR: trying to print message thats too small!" |
||
77 | return
|
||
78 | if msg[0] == '^': |
||
79 | print '^', |
||
80 | else:
|
||
81 | print str(ord(msg[0])) |
||
82 | |||
83 | 283 | bneuman | print str(ord(msg[1])), str(ord(msg[2])), |
84 | print msg[3], |
||
85 | |||
86 | for c in msg[4:]: |
||
87 | 222 | bneuman | print str(ord(c)), |
88 | |||
89 | print
|
||
90 | |||
91 | |||
92 | #tn is an actual tool number
|
||
93 | # ^ <src> <dest> <cmd> <plen> <payload> <crc>
|
||
94 | def sendMessage(tn, cmd, msg): |
||
95 | global bus
|
||
96 | if bus == None: |
||
97 | raise BusException
|
||
98 | if len(msg) > MAX_PAYLOAD_LEN: |
||
99 | print "ERROR: message too long! max size is " + str(MAX_PAYLOAD_LEN) |
||
100 | else:
|
||
101 | body = chr(1) + chr(tn) + cmd + chr(len(msg)) + msg |
||
102 | crc = 0
|
||
103 | for c in body: |
||
104 | crc = crc ^ ord(c)
|
||
105 | msg = '^' + body + chr(crc) |
||
106 | print "sending packet to tool",tn |
||
107 | printMsg(msg) |
||
108 | bus.write(msg) |
||
109 | |||
110 | 283 | bneuman | #time.sleep(0.05) #TODO: do I still need this?
|
111 | |||
112 | 222 | bneuman | def sendTool(t): |
113 | tn = t |
||
114 | 244 | bneuman | print "sending power to tool ID",tn |
115 | 294 | rc99 | sendMessage(tn, TT_GRANT, "")
|
116 | 222 | bneuman | |
117 | 282 | bneuman | def sendGrant(): |
118 | 283 | bneuman | print "seding grant to cardbox (",CARDBOX_ID,")" |
119 | 282 | bneuman | sendMessage(CARDBOX_ID, TT_GRANT, "")
|
120 | 222 | bneuman | |
121 | 282 | bneuman | def sendDeny(): |
122 | 283 | bneuman | print "seding deny to cardbox (",CARDBOX_ID,")" |
123 | 282 | bneuman | sendMessage(CARDBOX_ID, TT_DENY, "")
|
124 | 243 | bneuman | |
125 | 222 | bneuman | def sendAck(toolNum): |
126 | print "seding ACK to",toolNum |
||
127 | sendMessage(toolNum, TT_ACK, "")
|
||
128 | |||
129 | def sendNack(toolNum): |
||
130 | 241 | bneuman | print "seding NACK to",toolNum |
131 | 222 | bneuman | sendMessage(toolNum, TT_NACK, "")
|
132 | |||
133 | # This function eats the rest of the packet where data is what we have so far
|
||
134 | def flushPacket(data): |
||
135 | global bus
|
||
136 | if bus == None: |
||
137 | raise BusException
|
||
138 | |||
139 | while len(data) < 6: |
||
140 | 224 | bneuman | c = bus.read(1)
|
141 | 225 | bneuman | #print "("+str(ord(c))+")"
|
142 | 224 | bneuman | data += c |
143 | 222 | bneuman | |
144 | plen = data[4]
|
||
145 | if plen > 0: |
||
146 | bus.read(ord(plen))
|
||
147 | |||
148 | |||
149 | 224 | bneuman | #reads until a timeout
|
150 | def readInf(): |
||
151 | c = ' '
|
||
152 | while c != '': |
||
153 | c = bus.read(1)
|
||
154 | if c != '': |
||
155 | print "<" + str(ord(c)) + ">" |
||
156 | |||
157 | 222 | bneuman | # Returns [src, dest, cmd, data]
|
158 | def readMessage(): |
||
159 | global bus
|
||
160 | if bus == None: |
||
161 | raise BusException
|
||
162 | |||
163 | 224 | bneuman | start = bus.read(1)
|
164 | if start == '^': |
||
165 | 222 | bneuman | src = bus.read(1)
|
166 | 294 | rc99 | # if src == chr(1): #reflection
|
167 | # print "(reflection)"
|
||
168 | # flushPacket('^' + src)
|
||
169 | # return readMessage()
|
||
170 | 222 | bneuman | |
171 | dest = bus.read(1)
|
||
172 | cmd = bus.read(1)
|
||
173 | plen = bus.read(1)
|
||
174 | data = bus.read(ord(plen))
|
||
175 | x = bus.read(1)
|
||
176 | |||
177 | print "got packet" |
||
178 | printMsg('^' + src + dest + cmd + plen + data + x)
|
||
179 | |||
180 | crc = ord(src) ^ ord(dest) ^ ord(cmd) ^ ord(plen) |
||
181 | for d in data: |
||
182 | crc ^= ord(d)
|
||
183 | |||
184 | if crc == ord(x): |
||
185 | return [src, dest, cmd, data]
|
||
186 | else:
|
||
187 | print "xor fail. got", str(ord(x)), "should have been got",crc |
||
188 | return None |
||
189 | 224 | bneuman | else:
|
190 | if start == '': |
||
191 | 283 | bneuman | #print "ERROR: timeout on start delim"
|
192 | pass #TODO: do I need this printout for other (non-transaction reading) cases??? |
||
193 | 224 | bneuman | else:
|
194 | print "ERROR: did not get start delimiter: "+str(ord(start)) |
||
195 | return None |
||
196 | 222 | bneuman | |
197 | 283 | bneuman | # This function keeps trying to read the message until it gets something
|
198 | def readMessageBlocking(): |
||
199 | print "blocking on read" |
||
200 | m = None
|
||
201 | while m == None: |
||
202 | m = readMessage(); |
||
203 | |||
204 | return m
|
||
205 | |||
206 | #returns [key, cardnum] pair
|
||
207 | 282 | bneuman | def readTransaction(): |
208 | 283 | bneuman | m = readMessageBlocking() |
209 | 282 | bneuman | if m != None: |
210 | 283 | bneuman | print "got a message:" |
211 | 282 | bneuman | [src, dest, cmd, data] = m |
212 | 283 | bneuman | src = ord(src)
|
213 | dest = ord(dest)
|
||
214 | print "src:", src, " (should be:",CARDBOX_ID,")" |
||
215 | print "dest:", dest |
||
216 | print "cmd:", cmd, " (should be:",TT_KC,")" |
||
217 | print "len(data)", len(data) |
||
218 | print "data:", data |
||
219 | 282 | bneuman | if src == CARDBOX_ID and cmd == TT_KC and len(data) >= 2: |
220 | 283 | bneuman | print "looks like a transaction" |
221 | card = re.search('%([0-9]*)=.*', data[1:]) |
||
222 | if card != None: |
||
223 | print "got a card number!" |
||
224 | sendAck(CARDBOX_ID) |
||
225 | return [data[0], card.group(1)] #return the key and parsed out cardnum |
||
226 | 222 | bneuman | |
227 | 283 | bneuman | # send nack if things didn't look right
|
228 | sendNack(CARDBOX_ID) |
||
229 | return None |
||
230 | 243 | bneuman | |
231 | 283 | bneuman | |
232 | 222 | bneuman | #returns [src, dest, command] or [] on error
|
233 | # because of reflection, this will quietly ignore packets send by the server
|
||
234 | def readTool(): |
||
235 | 224 | bneuman | m = readMessage() |
236 | if m == None: |
||
237 | return None |
||
238 | [src, dest, cmd, data] = m |
||
239 | return [src, dest, cmd]
|
||
240 | 222 | bneuman | |
241 | def checkAck(t): |
||
242 | tn = t |
||
243 | m = readTool() |
||
244 | 224 | bneuman | if m==None: |
245 | print "timeout" |
||
246 | 222 | bneuman | return False |
247 | 224 | bneuman | [src,dest,cmd] = m |
248 | return cmd == TT_ACK
|
||
249 | 222 | bneuman | |
250 | |||
251 | 300 | bneuman | def initBus(filename, timeout=1): |
252 | 222 | bneuman | global bus
|
253 | |||
254 | 300 | bneuman | bus = serial.Serial(filename, BAUD_RATE, timeout=timeout) |
255 | 222 | bneuman | bus.flushInput() |
256 | print bus
|
||
257 | |||
258 | return True |