# -*- coding: utf-8 -*- import sys def read_until(f, term, encoding): data = [] c = f.read(1) while c != term: data.append(c) c = f.read(1) data = ''.join(data) if sys.version_info.major == 2: data = data.decode(encoding) return data def to_binary(body, param, sep=' '): assert body.isupper() assert len(body) == 4 assert len(param) <= 128 return '%1' + body + sep + param + '\r' def parse_response(f, encoding, data=''): if len(data) < 7: data += read(f, 2 + 4 + 1 - len(data), encoding) header = data[0] assert header == '%' version = data[1] # only class 1 is currently defined assert version == '1' body = data[2:6] # commands are case-insensitive, but let's turn them upper case anyway # this will avoid the rest of our code from making this mistake # FIXME: AFAIR this takes the current locale into consideration, it shouldn't. body = body.upper() sep = data[6] assert sep == '=' param = read_until(f, '\r', encoding) return (body, param) # python 3 socket makefile is already unicode in text mode, i do the same on # python 2 if sys.version_info.major == 2: def read(f, n, encoding): return f.read(n).decode(encoding) else: def read(f, n, encoding): return f.read(n) ERRORS = { 'ERR1': 'undefined command', 'ERR2': 'out of parameter', 'ERR3': 'unavailable time', 'ERR4': 'projector failure', } def send_command(f, req_body, req_param, encoding): data = to_binary(req_body, req_param) f.write(data) f.flush() resp_body, resp_param = parse_response(f, encoding) assert resp_body == req_body if resp_param in ERRORS: return False, ERRORS[resp_param] return True, resp_param