158 lines
3.8 KiB
Python
158 lines
3.8 KiB
Python
from random import randint
|
|
from threading import Lock
|
|
from _thread import start_new_thread
|
|
from os.path import exists
|
|
from asyncio import sleep
|
|
from ctypes import cdll
|
|
|
|
from utils import is_wallaby
|
|
|
|
from highway import log as logging
|
|
|
|
|
|
|
|
ANALOG = 1
|
|
DIGITAL = 2
|
|
NAMED_MODES = {ANALOG : "analog", DIGITAL : "digital"}
|
|
REVERSE_NAMED_MODES = {v : k for k, v in NAMED_MODES.items()}
|
|
MODES = tuple(NAMED_MODES.keys())
|
|
|
|
CONFIG_PATH = "fl0w.cfg"
|
|
IS_WALLABY = is_wallaby()
|
|
LIB_WALLABY = "/usr/lib/libwallaby.so"
|
|
|
|
READOUT_TEMPLATE = {
|
|
ANALOG : [],
|
|
DIGITAL : []
|
|
}
|
|
|
|
def valid_port(port, mode):
|
|
if mode == ANALOG:
|
|
return port >= 0 and port <= 5
|
|
elif mode == DIGITAL:
|
|
return port >= 0 and port <= 9
|
|
return False
|
|
|
|
class SensorReadout:
|
|
def __init__(self, poll_rate=0.2):
|
|
self.poll_rate = poll_rate
|
|
|
|
self.handler_lock = Lock()
|
|
self.handlers = {}
|
|
|
|
self.running = True
|
|
|
|
self.readout_required = READOUT_TEMPLATE.copy()
|
|
|
|
# Wallaby library avaliable?
|
|
if not exists(LIB_WALLABY):
|
|
logging.warning("Wallaby library unavaliable.")
|
|
self.get_sensor_value = self.__get_random_value
|
|
else:
|
|
self.wallaby_library = cdll.LoadLibrary(LIB_WALLABY)
|
|
self.get_sensor_value = self.__get_sensor_value
|
|
|
|
|
|
async def run(self):
|
|
while self.running:
|
|
current_values = {
|
|
ANALOG : {},
|
|
DIGITAL : {}
|
|
}
|
|
|
|
for mode in MODES:
|
|
for port in self.readout_required[mode]:
|
|
current_values[mode][port] = self.get_sensor_value(port, mode)
|
|
|
|
self.handler_lock.acquire()
|
|
for handler in self.handlers:
|
|
readouts = 0
|
|
|
|
response = {ANALOG : {}, DIGITAL : {}}
|
|
|
|
for mode in MODES:
|
|
for port in self.handlers[handler][mode]:
|
|
response[mode][port] = current_values[mode][port]
|
|
readouts += 1
|
|
if readouts != 0:
|
|
await handler.send(response, "sensor_stream")
|
|
self.handler_lock.release()
|
|
|
|
await sleep(self.poll_rate)
|
|
|
|
|
|
def stop(self):
|
|
self.running = False
|
|
|
|
|
|
def subscribe(self, port, mode, handler):
|
|
if port not in self.readout_required[mode]:
|
|
self.readout_required[mode].append(port)
|
|
if not handler in self.handlers:
|
|
self.handler_lock.acquire()
|
|
self.handlers[handler] = READOUT_TEMPLATE.copy()
|
|
self.handler_lock.release()
|
|
|
|
self.handler_lock.acquire()
|
|
self.handlers[handler][mode].append(port)
|
|
self.handler_lock.release()
|
|
|
|
|
|
def unsubscribe(self, port, mode, handler):
|
|
if handler in self.handlers:
|
|
if port in self.handlers[handler][mode]:
|
|
self.handler_lock.acquire()
|
|
|
|
del self.handlers[handler][mode][ \
|
|
self.handlers[handler][mode].index(port)]
|
|
|
|
self.handler_lock.release()
|
|
self.determine_required_readouts()
|
|
|
|
|
|
def determine_required_readouts(self):
|
|
readout_required = READOUT_TEMPLATE.copy()
|
|
|
|
self.handler_lock.acquire()
|
|
for handler in self.handlers:
|
|
for mode in MODES:
|
|
for port in self.handlers[handler][mode]:
|
|
if not port in readout_required[mode]:
|
|
readout_required[mode].append(port)
|
|
self.handler_lock.release()
|
|
self.readout_required = readout_required
|
|
|
|
|
|
async def unsubscribe_all(self, handler):
|
|
successful = False
|
|
if handler in self.handlers:
|
|
self.handler_lock.acquire()
|
|
del self.handlers[handler]
|
|
self.handler_lock.release()
|
|
successful = True
|
|
self.determine_required_readouts()
|
|
await handler.send(successful, "sensor_unsubscribe")
|
|
|
|
|
|
def handler_disconnected(self, handler):
|
|
if handler in self.handlers:
|
|
self.handler_lock.acquire()
|
|
del self.handlers[handler]
|
|
self.handler_lock.release()
|
|
self.determine_required_readouts()
|
|
|
|
|
|
def __get_sensor_value(self, port, mode):
|
|
if mode == SensorReadout.ANALOG:
|
|
return self.wallaby_library.analog(port)
|
|
elif mode == SensorReadout.DIGITAL:
|
|
return self.wallaby_library.digital(port)
|
|
|
|
|
|
def __get_random_value(self, port, mode):
|
|
if mode == ANALOG:
|
|
return randint(0, 4095)
|
|
elif mode == DIGITAL:
|
|
return randint(0, 1)
|
|
|
|
|