Project

General

Profile

Statistics
| Revision:

root / trunk / common / common.py @ 294

History | View | Annotate | Download (6.25 KB)

1
"""
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
import time
26
import re
27

    
28
keypadTimeout = 31 #in seconds
29

    
30
TT_ACK     = 'a'
31
TT_NACK    = 'n'
32
TT_TIMEOUT = 't'
33
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
TT_PING    = 'g'
37
TT_BOOT    = 'b'
38
TT_PROGRAM_MODE = 'p'
39
TT_RESET = 'r'
40
TT_PING = 'g'
41
TT_BAD = 0
42
TT_PROGM = 'p'
43
TT_PROGD = 'd'
44

    
45
#depricated
46
#TT_ON = 'o'
47

    
48
TT_MAX_RETRY = 3
49

    
50
MAX_PAYLOAD_LEN = 32
51

    
52
BAUD_RATE = 9600
53

    
54
# cardbox id
55
CARDBOX_ID = 2
56

    
57
#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
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
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
    print str(ord(msg[1])), str(ord(msg[2])),
84
    print msg[3],
85

    
86
    for c in msg[4:]:
87
        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
    #time.sleep(0.05) #TODO: do I still need this?
111

    
112
def sendTool(t):
113
    tn = t
114
    print "sending power to tool ID",tn
115
    sendMessage(tn, TT_GRANT, "")
116

    
117
def sendGrant():
118
    print "seding grant to cardbox (",CARDBOX_ID,")"
119
    sendMessage(CARDBOX_ID, TT_GRANT, "")
120

    
121
def sendDeny():
122
    print "seding deny to cardbox (",CARDBOX_ID,")"
123
    sendMessage(CARDBOX_ID, TT_DENY, "")
124

    
125
def sendAck(toolNum):
126
   print "seding ACK to",toolNum
127
   sendMessage(toolNum, TT_ACK, "")
128

    
129
def sendNack(toolNum):
130
   print "seding NACK to",toolNum
131
   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
        c = bus.read(1)
141
        #print "("+str(ord(c))+")"
142
        data += c
143

    
144
    plen = data[4]
145
    if plen > 0:
146
        bus.read(ord(plen))
147

    
148

    
149
#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
# Returns [src, dest, cmd, data]
158
def readMessage():
159
    global bus
160
    if bus == None:
161
        raise BusException
162

    
163
    start = bus.read(1)
164
    if start == '^':
165
        src = bus.read(1)
166
        # if src == chr(1): #reflection
167
        #     print "(reflection)"
168
        #     flushPacket('^' + src)
169
        #     return readMessage()
170

    
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
    else:
190
        if start == '':
191
            #print "ERROR: timeout on start delim"
192
            pass #TODO: do I need this printout for other (non-transaction reading) cases???
193
        else:
194
            print "ERROR: did not get start delimiter: "+str(ord(start))
195
        return None
196

    
197
# 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
def readTransaction():
208
    m = readMessageBlocking()
209
    if m != None:
210
        print "got a message:"
211
        [src, dest, cmd, data] = m
212
        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
        if src == CARDBOX_ID and cmd == TT_KC and len(data) >= 2:
220
            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

    
227
    # send nack if things didn't look right
228
    sendNack(CARDBOX_ID)
229
    return None
230

    
231

    
232
#returns [src, dest, command] or [] on error
233
# because of reflection, this will quietly ignore packets send by the server
234
def readTool():
235
    m = readMessage()
236
    if m == None:
237
        return None
238
    [src, dest, cmd, data] = m
239
    return [src, dest, cmd]
240

    
241
def checkAck(t):
242
    tn = t
243
    m = readTool()
244
    if m==None:
245
        print "timeout"
246
        return False
247
    [src,dest,cmd] = m
248
    return cmd == TT_ACK
249

    
250

    
251
def initBus(filename):
252
    global bus
253

    
254
    bus = serial.Serial(filename, BAUD_RATE, timeout = 1)
255
    bus.flushInput()
256
    print bus
257

    
258
    return True