root / trunk / swipe / dustmite.py @ 131
History | View | Annotate | Download (5.31 KB)
1 |
#!/usr/bin/python
|
---|---|
2 |
|
3 |
################################################################################
|
4 |
## dustmite.py is the main tooltron server
|
5 |
# It connects to the civicrm database of mysql and sends commands to
|
6 |
# the cardbox and tools. It must be connected over usb to the card
|
7 |
# reader, and the two arguments specify the devices to use for the
|
8 |
# serial communication to the card and tool boxes.
|
9 |
#
|
10 |
# This script requires the modules seen below, which may not be
|
11 |
# present by default
|
12 |
#
|
13 |
# Because of a problem with card scans buffering in stdio, there is a
|
14 |
# seperate thread which stores the last swiped id. To cleanly exit the
|
15 |
# program type C-d
|
16 |
#
|
17 |
# email bradneuman@gmail.com if you have any questions
|
18 |
################################################################################
|
19 |
|
20 |
|
21 |
import re |
22 |
import sys |
23 |
import serial |
24 |
import MySQLdb |
25 |
import getpass |
26 |
|
27 |
|
28 |
#tools for messages are these + 1 but in decimal, not ascii
|
29 |
#the values are lists of numbers which get appended to the acl
|
30 |
tools = { |
31 |
'Bandsaw':['2','8'], |
32 |
'DrillPress':['1','9'], |
33 |
'Mill':['4'], |
34 |
'Lathe':['5'], |
35 |
'ChopMiterSaw':['3'] |
36 |
} |
37 |
|
38 |
|
39 |
|
40 |
TT_GET_KEY = 'k'
|
41 |
TT_ACK = 'a'
|
42 |
TT_NACK = 'n'
|
43 |
TT_TO = 'f'
|
44 |
TT_TIMEOUT = 't'
|
45 |
|
46 |
BAUD_RATE = 9600
|
47 |
|
48 |
#################################################
|
49 |
#this code spawns a thread which always puts the last card id in the
|
50 |
#lastid variable.
|
51 |
#################################################
|
52 |
import threading |
53 |
import time |
54 |
|
55 |
lastid = None
|
56 |
idready = False
|
57 |
|
58 |
cv = threading.Condition() |
59 |
|
60 |
class idThread ( threading.Thread ): |
61 |
|
62 |
def run ( self ): |
63 |
global lastid
|
64 |
global idready
|
65 |
|
66 |
try:
|
67 |
while True: |
68 |
l = raw_input()
|
69 |
cv.acquire() |
70 |
id = re.search('%([0-9]*)=.*', l)
|
71 |
if id != None: |
72 |
lastid = id
|
73 |
print "!!! setting idready" |
74 |
idready = True
|
75 |
cv.notify() |
76 |
cv.release() |
77 |
|
78 |
except EOFError: |
79 |
cv.acquire() |
80 |
idready = True
|
81 |
lastid=None
|
82 |
cv.notify() |
83 |
cv.release() |
84 |
#end thread
|
85 |
###############################################
|
86 |
|
87 |
def get_last_id(): |
88 |
global idready
|
89 |
global lastid
|
90 |
|
91 |
got = None
|
92 |
|
93 |
print ">>> locking for last_id" |
94 |
|
95 |
cv.acquire() |
96 |
while not idready: |
97 |
print ">>> wait" |
98 |
cv.wait() |
99 |
|
100 |
print ">>> idready set" |
101 |
|
102 |
got = lastid |
103 |
idready = False
|
104 |
cv.release() |
105 |
print ">>> done" |
106 |
|
107 |
return got
|
108 |
|
109 |
def clear_id(): |
110 |
global idready
|
111 |
global lastid
|
112 |
|
113 |
print "=== locking to clear idready flag" |
114 |
cv.acquire() |
115 |
idready = False
|
116 |
lastid = None
|
117 |
cv.release() |
118 |
print "=== done" |
119 |
|
120 |
return
|
121 |
|
122 |
|
123 |
|
124 |
if len(sys.argv) < 3: |
125 |
print "usage: dustmite.py /path/to/keypad/device /path/to/tool/bus/device" |
126 |
|
127 |
else:
|
128 |
|
129 |
|
130 |
pw = getpass.getpass("mysql password: ")
|
131 |
db = MySQLdb.connect(host="roboclub8.frc.ri.cmu.edu", user="tooltron", passwd=pw, db="civicrm") |
132 |
print "connected, now accepting input" |
133 |
|
134 |
#start the id scan thread AFTER the getpass prompt
|
135 |
idThread().start() |
136 |
|
137 |
|
138 |
cursor = db.cursor() |
139 |
|
140 |
qry = "SELECT tools_6 FROM civicrm_value_roboclub_info_2 WHERE card_number_1 = "
|
141 |
|
142 |
keypad = serial.Serial(sys.argv[1], BAUD_RATE, timeout = 30) |
143 |
keypad.flushInput() |
144 |
print keypad
|
145 |
|
146 |
bus = serial.Serial(sys.argv[2], BAUD_RATE, timeout = 15) |
147 |
bus.flushInput() |
148 |
print bus
|
149 |
|
150 |
# ^ <src> <dest> <data>
|
151 |
def sendTool(t): |
152 |
tn = int(t) + 1 |
153 |
msg = '^' + chr(1) + chr(tn) + 'O' + chr(1 ^ tn ^ ord('O')) |
154 |
|
155 |
bus.write(msg) |
156 |
return
|
157 |
|
158 |
#returns [src, data] or [] on error
|
159 |
def readTool(): |
160 |
ret = [0,0,0] |
161 |
|
162 |
if bus.read(1) == '^': |
163 |
ret[0] = bus.read(1) |
164 |
ret[1] = bus.read(1) |
165 |
ret[2] = bus.read(1) |
166 |
x = bus.read(1)
|
167 |
|
168 |
print "got packet",ret |
169 |
|
170 |
if chr(ord(ret[0]) ^ ord(ret[1]) ^ ord(ret[2])) == x: |
171 |
return ret
|
172 |
else:
|
173 |
print "xor fail. got", x, "should have been got",(ord(ret[0]) ^ ord(ret[1]) ^ ord(ret[2])) |
174 |
|
175 |
return []
|
176 |
|
177 |
def checkAck(t): |
178 |
tn = int(t) + 1 |
179 |
m = readTool() |
180 |
|
181 |
if m== []:
|
182 |
return False |
183 |
|
184 |
|
185 |
return m[0] == chr(tn) and m[1] == chr(1) and m[2] == 'A' |
186 |
|
187 |
|
188 |
while True: |
189 |
|
190 |
id = get_last_id() |
191 |
|
192 |
if id != None: |
193 |
print "\n-----------\nid# ", id.group(1) |
194 |
|
195 |
|
196 |
print "sending key request" |
197 |
keypad.write(TT_GET_KEY) |
198 |
|
199 |
cursor.execute(qry + id.group(1)) |
200 |
|
201 |
result = cursor.fetchall() |
202 |
|
203 |
acl = [] |
204 |
|
205 |
for r in result: |
206 |
tls = r[0].split("\x01") |
207 |
for t in tls: |
208 |
if t != '': |
209 |
try:
|
210 |
acl.extendy (tools[t]) |
211 |
except KeyError: |
212 |
#this doesn't really matter
|
213 |
pass
|
214 |
|
215 |
print "user has access to:", acl |
216 |
|
217 |
resp = keypad.read(1)
|
218 |
|
219 |
print "request:",resp |
220 |
|
221 |
|
222 |
if acl.count(resp) > 0: |
223 |
keypad.write(TT_ACK) |
224 |
sendTool(resp) |
225 |
print "ACCESS GRANTED" |
226 |
if checkAck(resp):
|
227 |
print "ACK" |
228 |
else:
|
229 |
print "NO ACK!!!!" |
230 |
|
231 |
else:
|
232 |
keypad.write(TT_NACK) |
233 |
print "ACCESS DENIED!!" |
234 |
|
235 |
else:
|
236 |
break
|
237 |
|
238 |
clear_id() |