Mercurial > templog
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() |