parent
2010427000
commit
d82ad7e4b3
@ -0,0 +1,115 @@ |
|||||||
|
import serial |
||||||
|
import gex |
||||||
|
from gex import TinyFrame, PayloadParser |
||||||
|
|
||||||
|
class Client: |
||||||
|
""" GEX client """ |
||||||
|
|
||||||
|
def __init__(self, port='/dev/ttyACM0', timeout=0.3): |
||||||
|
""" Set up the client. timeout - timeout for waiting for a response. """ |
||||||
|
self.port = port |
||||||
|
self.serial = serial.Serial(port=port, timeout=timeout) |
||||||
|
self.tf = TinyFrame() |
||||||
|
self.tf.write = self._write |
||||||
|
|
||||||
|
# test connection |
||||||
|
resp = self.query_raw(type=gex.MSG_PING) |
||||||
|
print("GEX connected, version string: %s" % resp.data.decode('utf-8')) |
||||||
|
|
||||||
|
self.load_units() |
||||||
|
|
||||||
|
def load_units(self): |
||||||
|
""" Load a list of unit names and callsigns for look-up """ |
||||||
|
resp = self.query_raw(type=gex.MSG_LIST_UNITS) |
||||||
|
pp = PayloadParser(resp.data) |
||||||
|
count = pp.u8() |
||||||
|
|
||||||
|
self.unit_lu = {} |
||||||
|
|
||||||
|
for n in range(0,count): |
||||||
|
cs = pp.u8() |
||||||
|
name = pp.str() |
||||||
|
type = pp.str() |
||||||
|
|
||||||
|
print("- Found unit \"%s\" (type %s) @ callsign %d" % (name, type, cs)) |
||||||
|
self.unit_lu[name] = { |
||||||
|
'callsign': cs, |
||||||
|
'type': type, |
||||||
|
} |
||||||
|
|
||||||
|
def get_callsign(self, name, type = None): |
||||||
|
""" Find unit by name and type """ |
||||||
|
u = self.unit_lu[name] |
||||||
|
|
||||||
|
if type is not None: |
||||||
|
if u['type'] != type: |
||||||
|
raise Exception("Unit %s is not type %s (is %s)" % (name, type, u['type'])) |
||||||
|
|
||||||
|
return u['callsign'] |
||||||
|
|
||||||
|
def _write(self, data): |
||||||
|
""" Write bytes to the serial port """ |
||||||
|
self.serial.write(data) |
||||||
|
pass |
||||||
|
|
||||||
|
def poll(self, attempts=10): |
||||||
|
""" Read messages sent by GEX """ |
||||||
|
first = True |
||||||
|
while attempts > 0: |
||||||
|
rv = bytearray() |
||||||
|
|
||||||
|
# Blocking read with a timeout |
||||||
|
if first: |
||||||
|
rv.extend(self.serial.read(1)) |
||||||
|
first = False |
||||||
|
|
||||||
|
# Non-blocking read of the rest |
||||||
|
rv.extend(self.serial.read(self.serial.in_waiting)) |
||||||
|
|
||||||
|
if 0 == len(rv): |
||||||
|
# nothing was read |
||||||
|
if self.tf.ps == 'SOF': |
||||||
|
# TF is in base state, we're done |
||||||
|
return |
||||||
|
else: |
||||||
|
# Wait for TF to finish the frame |
||||||
|
attempts -= 1 |
||||||
|
first = True |
||||||
|
else: |
||||||
|
self.tf.accept(rv) |
||||||
|
|
||||||
|
def send(self, cs, cmd, id=None, pld=None, listener=None): |
||||||
|
""" Send a command to a unit """ |
||||||
|
if cs is None: |
||||||
|
return self.tf.query(type=cmd, id=id, pld=pld, listener=listener) |
||||||
|
|
||||||
|
if pld is None: |
||||||
|
pld = b'' |
||||||
|
|
||||||
|
buf = bytearray([cs, cmd]) |
||||||
|
buf.extend(pld) |
||||||
|
self.tf.query(type=gex.MSG_UNIT_REQUEST, id=id, pld=buf, listener=listener) |
||||||
|
|
||||||
|
def query(self, cs, cmd, id=None, pld=None): |
||||||
|
""" Query a unit """ |
||||||
|
|
||||||
|
self._theframe = None |
||||||
|
|
||||||
|
def lst(tf, frame): |
||||||
|
self._theframe = frame |
||||||
|
|
||||||
|
self.send(cs, cmd, id=id, pld=pld, listener=lst) |
||||||
|
self.poll() |
||||||
|
|
||||||
|
if self._theframe is None: |
||||||
|
raise Exception("No response to query") |
||||||
|
|
||||||
|
return self._theframe |
||||||
|
|
||||||
|
def query_raw(self, type, id=None, pld=None): |
||||||
|
""" Query GEX, without addressing a unit """ |
||||||
|
return self.query(cs=None, cmd=type, id=id, pld=pld) |
||||||
|
|
||||||
|
def send_raw(self, type, id=None, pld=None): |
||||||
|
""" Send to GEX, without addressing a unit """ |
||||||
|
return self.send(cs=None, cmd=type, id=id, pld=pld) |
@ -0,0 +1,16 @@ |
|||||||
|
from gex import Client |
||||||
|
|
||||||
|
class Unit: |
||||||
|
def __init__(self, client :Client, name :str, type :str): |
||||||
|
self.client = client |
||||||
|
self.unit_name = name |
||||||
|
self.unit_type = type |
||||||
|
self.callsign = client.get_callsign(name, type) |
||||||
|
|
||||||
|
def send(self, cmd, pld=None, id=None): |
||||||
|
""" Send a command to the unit """ |
||||||
|
self.client.send(cs=self.callsign, cmd=cmd, pld=pld, id=id) |
||||||
|
|
||||||
|
def query(self, cmd, pld=None, id=None): |
||||||
|
""" Query the unit. Returns TF_Msg """ |
||||||
|
self.client.query(cs=self.callsign, cmd=cmd, pld=pld, id=None) |
@ -0,0 +1,14 @@ |
|||||||
|
import gex |
||||||
|
|
||||||
|
class Pin(gex.Unit): |
||||||
|
def __init__(self, client, name): |
||||||
|
super().__init__(client, name, 'PIN') |
||||||
|
|
||||||
|
def off(self): |
||||||
|
self.send(0x00) |
||||||
|
|
||||||
|
def on(self): |
||||||
|
self.send(0x01) |
||||||
|
|
||||||
|
def toggle(self): |
||||||
|
self.send(0x02) |
Loading…
Reference in new issue