Project

General

Profile

Statistics
| Revision:

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