From 8a91cc0d7470cdade8c04fbf5b8090fcc6ebde18 Mon Sep 17 00:00:00 2001 From: jaseg Date: Mon, 24 Mar 2014 22:58:29 +0100 Subject: [PATCH] Added the Ampel and fixed an python lib escape handling bug --- configs/mainhall.json | 113 ++++++++++++++++++++++++++++++++++++++++++++ pylibcerebrum/ganglion.py | 7 ++- pylibcerebrum/serial_mux.py | 4 +- tools/trafotron.py | 57 ++++++++++++++++++++-- 4 files changed, 172 insertions(+), 9 deletions(-) create mode 100644 configs/mainhall.json diff --git a/configs/mainhall.json b/configs/mainhall.json new file mode 100644 index 0000000..a29b948 --- /dev/null +++ b/configs/mainhall.json @@ -0,0 +1,113 @@ +{ + "type": "avr", + "version": 23, + "url": "http://jaseg.github.com/cerebrum", + "members": { + "ampelrot": { + "type": "simple-io", + "port": "C", + "mode": "output", + "state": "low", + "pin": 0 + }, + "ampelgrün": { + "type": "simple-io", + "port": "C", + "mode": "output", + "state": "low", + "pin": 1 + }, + "ampelgelb": { + "type": "simple-io", + "port": "C", + "mode": "output", + "state": "low", + "pin": 2 + }, + "analog3": { + "type": "simple-io", + "port": "C", + "pin": 3 + }, + "analog4": { + "type": "simple-io", + "port": "C", + "pin": 4 + }, + "analog5": { + "type": "simple-io", + "port": "C", + "pin": 5 + }, + "digital0": { + "type": "simple-io", + "port": "D", + "pin": 0 + }, + "digital1": { + "type": "simple-io", + "port": "D", + "pin": 1 + }, + "digital2": { + "type": "simple-io", + "port": "D", + "pin": 2 + }, + "digital3": { + "type": "simple-io", + "port": "D", + "pin": 3 + }, + "digital4": { + "type": "simple-io", + "port": "D", + "pin": 4 + }, + "digital5": { + "type": "simple-io", + "port": "D", + "pin": 5 + }, + "digital6": { + "type": "simple-io", + "port": "D", + "pin": 6 + }, + "digital7": { + "type": "simple-io", + "port": "D", + "pin": 7 + }, + "digital8": { + "type": "simple-io", + "port": "B", + "pin": 0 + }, + "digital9": { + "type": "simple-io", + "port": "B", + "pin": 1 + }, + "digital10": { + "type": "simple-io", + "port": "B", + "pin": 2 + }, + "digital11": { + "type": "simple-io", + "port": "B", + "pin": 3 + }, + "digital12": { + "type": "simple-io", + "port": "B", + "pin": 4 + }, + "digital13": { + "type": "simple-io", + "port": "B", + "pin": 5 + } + } +} diff --git a/pylibcerebrum/ganglion.py b/pylibcerebrum/ganglion.py index 599cffa..123a415 100644 --- a/pylibcerebrum/ganglion.py +++ b/pylibcerebrum/ganglion.py @@ -17,6 +17,8 @@ import serial from pylibcerebrum.NotifyList import NotifyList from pylibcerebrum.timeout_exception import TimeoutException +escape = lambda s: s.replace(b'\\', b'\\\\') + """Call RPC functions on serially connected devices over the Cerebrum protocol.""" class Ganglion(object): @@ -74,7 +76,7 @@ class Ganglion(object): def _read_config(self): """Fetch the device configuration descriptor from the device.""" with self._ser as s: - s.write(b'\\#' + struct.pack(">H", self.node_id) + b'\x00\x00\x00\x00') + s.write(b'\\#' + escape(struct.pack(">H", self.node_id)) + b'\x00\x00\x00\x00') (clen,) = struct.unpack(">H", s.read(2)) cbytes = s.read(clen) #decide whether cbytes contains lzma or json depending on the first byte (which is used as a magic here) @@ -86,11 +88,12 @@ class Ganglion(object): def _callfunc(self, fid, argsfmt, args, retfmt): """Call a function on the device by id, directly passing argument/return format parameters.""" # Make a list out of the arguments if they are none + #print('calling function No. {}, args({}) {}, returning {}'.format(fid, argsfmt, args, retfmt)) if not (isinstance(args, tuple) or isinstance(args, list)): args = [args] with self._ser as s: # Send the encoded data - cmd = b'\\#' + struct.pack(">HHH", self.node_id, fid, struct.calcsize(argsfmt)) + struct.pack(argsfmt, *args) + cmd = b'\\#' + escape(struct.pack(">HHH", self.node_id, fid, struct.calcsize(argsfmt)) + struct.pack(argsfmt, *args)) s.write(cmd) # payload length (clen,) = struct.unpack(">H", s.read(2)) diff --git a/pylibcerebrum/serial_mux.py b/pylibcerebrum/serial_mux.py index 07260c0..2d4c140 100644 --- a/pylibcerebrum/serial_mux.py +++ b/pylibcerebrum/serial_mux.py @@ -2,7 +2,7 @@ import serial import threading import struct -from pylibcerebrum.ganglion import Ganglion +from pylibcerebrum.ganglion import Ganglion, escape from pylibcerebrum.timeout_exception import TimeoutException MAC_LEN = 64 @@ -42,7 +42,7 @@ class SerialMux(object): def _send_probe(self, mac, mask, next_address): #print('Discovery: mac', mac, 'mask', mask) with self.ser as s: - s.write(b'\\#\xFF\xFF' + struct.pack('>HHQ', next_address, mask, mac)) + s.write(b'\\#\xFF\xFF' + escape(struct.pack('>HHQ', next_address, mask, mac))) timeout_tmp = s.timeout s.timeout = 0.05 try: diff --git a/tools/trafotron.py b/tools/trafotron.py index 527a319..8af6106 100755 --- a/tools/trafotron.py +++ b/tools/trafotron.py @@ -5,6 +5,7 @@ from threading import Thread import copy import json import requests +from http.server import HTTPServer, BaseHTTPRequestHandler from pylibcerebrum.serial_mux import SerialMux CBEAM = 'http://10.0.1.27:4254/rpc/' @@ -31,11 +32,26 @@ for io in [g.digital3, g.digital5, g.digital6, g.digital9, g.digital10, g.digita io.pwm_enabled = 1 print('starting event loop') +oldre, oldge, oldgn = None,None,None +def ampel(re,ge,gn): + global oldre, oldge, oldgn + if re and ge and gn: + gn = False + # Ensure no more than two lights are on at the same time, even for very short periods of time + if oldre != re: + g.ampelrot.state = re + if oldge != ge: + g.ampelgelb.state = ge + if oldgn != gn: + g.ampelgrün.state = gn + oldre,oldge,oldgn = re,ge,gn + #HACK ctrl-c ctrl-p -ed from barstatus.py barstatus = 'closed' +ampelstate = ((0,0,0), (0,0,0)) lastchange = time.time() - 180 def animate(): - global barstatus, lastchange + global barstatus, lastchange, ampelstate while True: lookup = barstatus if time.time() - lastchange < 180: @@ -52,12 +68,14 @@ def animate(): 'closed': ((128, 128, 128), (255, 4, 4)), 'lastcall': ((10, 255, 10), (255, 255, 10))}.get(lookup) (g.digital3.pwm, g.digital5.pwm, g.digital6.pwm), (g.digital9.pwm, g.digital10.pwm, g.digital11.pwm) = l1, r1 + ampel(*ampelstate[0]) time.sleep(0.33) (g.digital3.pwm, g.digital5.pwm, g.digital6.pwm), (g.digital9.pwm, g.digital10.pwm, g.digital11.pwm) = l2, r2 + ampel(*ampelstate[1]) time.sleep(0.66) animator = Thread(target=animate) -animator.daemon = False +animator.daemon = True animator.start() @@ -65,6 +83,38 @@ def sendstate(value): print('SENDING', value) requests.post(CBEAM, data=json.dumps({'method': 'trafotron', 'params': [value], 'id': 0})) +class AmpelHandler(BaseHTTPRequestHandler): + def do_POST(self): + global ampelstate + self.send_response(200) + self.end_headers() + postlen = int(self.headers['Content-Length']) + postdata = str(self.rfile.read(postlen), 'utf-8') + data = json.loads(postdata) + method = data.get('method') + if method == 'ampel': + p = data.get('params') + if type(p[0]) is list: + (r1,y1,g1),(r2,y2,g2) = p + r1,y1,g1 = bool(r1), bool(y1), bool(g1) + r2,y2,g2 = bool(r2), bool(y2), bool(g2) + ampelstate = ((r1,y1,g1),(r2,y2,g2)) + elif type(p[0]) is int and len(p) == 1: + a,b = (bool(p[0]&32), bool(p[0]&16), bool(p[0]&8)), (bool(p[0]&4), bool(p[0]&2), bool(p[0]&1)) + ampelstate = a,b + else: + r,y,g = p + r,y,g = bool(r), bool(y), bool(g) + ampelstate = (r,y,g), (r,y,g) + +HOST, PORT = '', 1337 +server = HTTPServer((HOST, PORT), AmpelHandler) +t = Thread(target=server.serve_forever) +t.daemon = True +t.start() + +time.sleep(2) + # Enable pull-up on Arduino analog pin 4 g.analog4.state = 1 oldval = -2*SEND_THRESHOLD @@ -72,9 +122,6 @@ oldbarstate = None newbarstate = None while True: val = sum([ g.analog5.analog for i in range(AVG_SAMPLES)])/AVG_SAMPLES - if abs(val-oldval) > SEND_THRESHOLD: - oldval = val - sendstate(int(val)) if g.analog4.state: newbarstate = 'closed' else: -- 2.11.4.GIT