comparison old/server/ts.py @ 511:cf52d5817709

merge
author Matt Johnston <matt@ucc.asn.au>
date Thu, 26 Jun 2014 23:03:32 +0800
parents 95043860e437
children
comparison
equal deleted inserted replaced
505:ad846b9bdd10 511:cf52d5817709
1 #!/usr/bin/env python2.7
2
3 # time that the bluetooth takes to get going?
4 EXTRA_WAKEUP = -3
5
6 FETCH_TRIES = 3
7
8 # avoid turning off the bluetooth etc.
9 TESTING = False
10
11 import sys
12 # for wrt
13 sys.path.append('/root/python')
14 import httplib
15 import time
16 import traceback
17 import binascii
18 import hmac
19 import zlib
20 import urllib
21 import urllib2
22 import logging
23 import socket
24
25 L = logging.info
26 W = logging.warning
27 E = logging.error
28
29 import config
30
31 from utils import monotonic_time, retry, readline, crc16
32 import utils
33
34 import bluetooth
35
36 def get_socket(addr):
37 s = bluetooth.BluetoothSocket( bluetooth.RFCOMM )
38 L("connecting")
39 s.connect((addr, 1))
40 s.setblocking(False)
41 s.settimeout(1)
42
43 return s
44
45
46 def flush(sock):
47 ret = []
48 while True:
49 l = readline(sock)
50 if l:
51 ret.append(l)
52 else:
53 break
54 return ret
55
56 def encode_extra(extra_lines):
57 return ['extra%d=%s' % (n, l.strip()) for (n,l) in enumerate(extra_lines)]
58
59 @retry()
60 def fetch(sock):
61 extra_lines = flush(sock)
62 sock.send("fetch\n")
63
64 crc = 0
65
66 lines = []
67 l = readline(sock)
68 if not l:
69 return None
70
71 if l != 'START\n':
72 W("Bad expected START line '%s'\n" % l.rstrip('\n'))
73 extra_lines.append(l)
74 return encode_extra(extra_lines)
75 crc = crc16(l, crc)
76
77 while True:
78 l = readline(sock)
79
80 crc = crc16(l, crc)
81
82 if l == 'END\n':
83 break
84
85 lines.append(l.rstrip('\n'))
86
87 lines += encode_extra(extra_lines)
88
89 for d in lines:
90 L("Received: %s" % d)
91
92 l = readline(sock)
93 recv_crc = None
94 try:
95 k, v = l.rstrip('\n').split('=')
96 if k == 'CRC':
97 recv_crc = int(v)
98 if recv_crc < 0 or recv_crc > 0xffff:
99 recv_crc = None
100 except ValueError:
101 pass
102
103 if recv_crc is None:
104 W("Bad expected CRC line '%s'\n" % l.rstrip('\n'))
105 return None
106
107 if recv_crc != crc:
108 W("Bad CRC: calculated 0x%x vs received 0x%x\n" % (crc, recv_crc))
109 return None
110
111 return lines
112
113 @retry()
114 def turn_off(sock):
115 if TESTING:
116 return 99
117 L("Sending btoff")
118 flush(sock)
119 sock.send("btoff\n");
120 # read newline
121 l = readline(sock)
122 if not l:
123 W("Bad response to btoff")
124 return None
125
126 if not l.startswith('next_wake'):
127 W("Bad response to btoff '%s'" % l)
128 return None
129 L("Next wake line %s" % l)
130
131 toks = dict(v.split('=') for v in l.split(','))
132
133 rem = int(toks['rem'])
134 tick_secs = int(toks['tick_secs'])
135 tick_wake = int(toks['tick_wake']) + 1
136 next_wake = int(toks['next_wake'])
137
138 rem_secs = float(rem) / tick_wake * tick_secs
139
140 next_wake_secs = next_wake - rem_secs
141 L("next_wake_secs %f\n", next_wake_secs)
142 return next_wake_secs
143
144 @retry()
145 def clear_meas(sock):
146 flush(sock)
147 sock.send("clear\n");
148 l = readline(sock)
149 if l and l.rstrip() == 'cleared':
150 return True
151
152 E("Bad response to clear '%s'" % str(l))
153 return False
154
155 def send_results(lines):
156 enc_lines = binascii.b2a_base64(zlib.compress('\n'.join(lines)))
157 mac = hmac.new(config.HMAC_KEY, enc_lines).hexdigest()
158
159 url_data = urllib.urlencode( {'lines': enc_lines, 'hmac': mac} )
160 con = urllib2.urlopen(config.UPDATE_URL, url_data)
161 result = con.read(100)
162 if result == 'OK':
163 return True
164 else:
165 W("Bad result '%s'" % result)
166 return False
167
168 def do_comms(sock):
169 L("do_comms")
170 d = None
171 # serial could be unreliable, try a few times
172 d = fetch(sock)
173 if not d:
174 return
175
176 res = send_results(d)
177 if not res:
178 return
179
180 clear_meas(sock)
181
182 next_wake = 600
183 #next_wake = turn_off(sock)
184 #sock.close()
185 return next_wake
186
187 testcount = 0
188
189 def sleep_for(secs):
190 until = monotonic_time() + secs
191 while True:
192 length = until - monotonic_time()
193 if length <= 0:
194 return
195 time.sleep(length)
196
197 def setup_logging():
198 logging.basicConfig(format='%(asctime)s %(message)s',
199 datefmt='%m/%d/%Y %I:%M:%S %p',
200 level=logging.INFO)
201
202 def get_net_socket(host, port):
203 s = socket.create_connection((host, port))
204 s.setblocking(False)
205 s.settimeout(1)
206 return s
207
208 def main():
209 setup_logging()
210
211 L("Running templog rfcomm server")
212
213 if '--daemon' in sys.argv:
214 utils.cheap_daemon()
215
216 next_wake_time = 0
217
218 while True:
219 sock = None
220 try:
221 sock = get_net_socket(config.SERIAL_HOST, config.SERIAL_PORT)
222 except Exception, e:
223 #logging.exception("Error connecting")
224 pass
225
226 if not sock:
227 sleep_for(config.SLEEP_TIME)
228 continue
229
230 while True:
231 try:
232 do_comms(sock)
233 sleep_for(config.SLEEP_TIME)
234 except Exception, e:
235 logging.exception("Error in do_comms")
236 break
237
238 if __name__ == '__main__':
239 main()