summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDevaev Maxim <[email protected]>2018-06-28 18:58:52 +0300
committerDevaev Maxim <[email protected]>2018-06-28 18:58:52 +0300
commit54430fed3151701a4e975485c17b786dfcb20d42 (patch)
treeaa3fbb2986402e8097f9d442504ca98889341c12
parent65bee96fefbcce8d0730f112f0a1e73fab099a35 (diff)
ps/2 keyboard prototype
-rw-r--r--kvmd/kvmd.yaml2
-rw-r--r--kvmd/kvmd/__init__.py8
-rw-r--r--kvmd/kvmd/atx.py4
-rw-r--r--kvmd/kvmd/gpio.py4
-rw-r--r--kvmd/kvmd/ps2.py63
-rw-r--r--kvmd/kvmd/server.py14
-rw-r--r--kvmd/kvmd/streamer.py4
7 files changed, 92 insertions, 7 deletions
diff --git a/kvmd/kvmd.yaml b/kvmd/kvmd.yaml
index 56bb93d8..78ef5e07 100644
--- a/kvmd/kvmd.yaml
+++ b/kvmd/kvmd.yaml
@@ -8,7 +8,7 @@ kvmd:
pinout:
clock: 17
data: 4
- delay: 0.0002
+ pulse: 0.0002
atx:
leds:
diff --git a/kvmd/kvmd/__init__.py b/kvmd/kvmd/__init__.py
index 03088dcb..a1eca26b 100644
--- a/kvmd/kvmd/__init__.py
+++ b/kvmd/kvmd/__init__.py
@@ -5,6 +5,7 @@ from .application import init
from .atx import Atx
from .streamer import Streamer
+from .ps2 import Ps2Keyboard
from .server import Server
from . import gpio
@@ -33,9 +34,16 @@ def main() -> None:
loop=loop,
)
+ keyboard = Ps2Keyboard(
+ clock=config["keyboard"]["pinout"]["clock"],
+ data=config["keyboard"]["pinout"]["data"],
+ pulse=config["keyboard"]["pulse"],
+ )
+
Server(
atx=atx,
streamer=streamer,
+ keyboard=keyboard,
heartbeat=config["server"]["heartbeat"],
atx_leds_poll=config["atx"]["leds"]["poll"],
video_shutdown_delay=config["video"]["shutdown_delay"],
diff --git a/kvmd/kvmd/atx.py b/kvmd/kvmd/atx.py
index a8c29cb0..839f33ce 100644
--- a/kvmd/kvmd/atx.py
+++ b/kvmd/kvmd/atx.py
@@ -24,8 +24,8 @@ class Atx:
self.__power_led = gpio.set_input(power_led)
self.__hdd_led = gpio.set_input(hdd_led)
- self.__power_switch = gpio.set_output_zeroed(power_switch)
- self.__reset_switch = gpio.set_output_zeroed(reset_switch)
+ self.__power_switch = gpio.set_output(power_switch)
+ self.__reset_switch = gpio.set_output(reset_switch)
self.__click_delay = click_delay
self.__long_click_delay = long_click_delay
diff --git a/kvmd/kvmd/gpio.py b/kvmd/kvmd/gpio.py
index a5197e75..a7bdb45c 100644
--- a/kvmd/kvmd/gpio.py
+++ b/kvmd/kvmd/gpio.py
@@ -21,8 +21,8 @@ def bcm() -> Generator[None, None, None]:
_logger.info("GPIO cleaned")
-def set_output_zeroed(pin: int) -> int:
- GPIO.setup(pin, GPIO.OUT)
+def set_output(pin: int, initial: bool=False) -> int:
+ GPIO.setup(pin, GPIO.OUT, initial=initial)
GPIO.output(pin, False)
return pin
diff --git a/kvmd/kvmd/ps2.py b/kvmd/kvmd/ps2.py
new file mode 100644
index 00000000..7ba646b4
--- /dev/null
+++ b/kvmd/kvmd/ps2.py
@@ -0,0 +1,63 @@
+import multiprocessing
+import multiprocessing.queues
+import queue
+import logging
+import time
+
+from . import gpio
+
+
+# =====
+_logger = logging.getLogger(__name__)
+
+
+class Ps2Keyboard(multiprocessing.Process):
+ def __init__(self, clock: int, data: int, pulse: float) -> None:
+ super().__init__(daemon=True)
+
+ self.__clock = gpio.set_output(clock, initial=True)
+ self.__data = gpio.set_output(data, initial=True)
+ self.__pulse = pulse
+
+ self.__queue: multiprocessing.queues.Queue = multiprocessing.Queue()
+ self.__event = multiprocessing.Event()
+
+ def start(self) -> None:
+ _logger.info("Starting keyboard daemon ...")
+ super().start()
+
+ def stop(self) -> None:
+ _logger.info("Stopping keyboard daemon ...")
+ self.__event.set()
+ self.join()
+
+ def send_byte(self, code: int) -> None:
+ self.__queue.put(code)
+
+ def run(self) -> None:
+ try:
+ while not self.__event.is_set():
+ try:
+ code = self.__queue.get(timeout=0.1)
+ except queue.Empty:
+ pass
+ else:
+ self.__send_byte(code)
+ except Exception:
+ _logger.exception("Unhandled exception")
+ raise
+
+ def __send_byte(self, code: int) -> None:
+ code_bits = list(map(bool, bin(code)[2:].zfill(8)))
+ code_bits.reverse()
+ message = [False] + code_bits + [(not sum(code_bits) % 2), True]
+ for bit in message:
+ self.__send_bit(bit)
+
+ def __send_bit(self, bit: bool) -> None:
+ gpio.write(self.__clock, True)
+ gpio.write(self.__data, bool(bit))
+ time.sleep(self.__pulse)
+ gpio.write(self.__clock, False)
+ time.sleep(self.__pulse)
+ gpio.write(self.__clock, True)
diff --git a/kvmd/kvmd/server.py b/kvmd/kvmd/server.py
index 3216d3fd..3233a7ec 100644
--- a/kvmd/kvmd/server.py
+++ b/kvmd/kvmd/server.py
@@ -13,6 +13,7 @@ import aiohttp
from .atx import Atx
from .streamer import Streamer
+from .ps2 import Ps2Keyboard
# =====
@@ -36,6 +37,7 @@ class Server: # pylint: disable=too-many-instance-attributes
self,
atx: Atx,
streamer: Streamer,
+ keyboard: Ps2Keyboard,
heartbeat: float,
atx_leds_poll: float,
video_shutdown_delay: float,
@@ -45,6 +47,7 @@ class Server: # pylint: disable=too-many-instance-attributes
self.__atx = atx
self.__streamer = streamer
self.__heartbeat = heartbeat
+ self.__keyboard = keyboard
self.__video_shutdown_delay = video_shutdown_delay
self.__atx_leds_poll = atx_leds_poll
self.__loop = loop
@@ -55,6 +58,8 @@ class Server: # pylint: disable=too-many-instance-attributes
self.__system_tasks: List[asyncio.Task] = []
def run(self, host: str, port: int) -> None:
+ self.__keyboard.start()
+
app = aiohttp.web.Application(loop=self.__loop)
app.router.add_get("/", self.__root_handler)
app.router.add_get("/ws", self.__ws_handler)
@@ -62,6 +67,7 @@ class Server: # pylint: disable=too-many-instance-attributes
app.on_cleanup.append(self.__on_cleanup)
self.__system_tasks.extend([
+ self.__loop.create_task(self.__monitor_keyboard()),
self.__loop.create_task(self.__stream_controller()),
self.__loop.create_task(self.__poll_dead_sockets()),
self.__loop.create_task(self.__poll_atx_leds()),
@@ -101,10 +107,18 @@ class Server: # pylint: disable=too-many-instance-attributes
await self.__remove_socket(ws)
async def __on_cleanup(self, _: aiohttp.web.Application) -> None:
+ if self.__keyboard.is_alive():
+ self.__keyboard.stop()
if self.__streamer.is_running():
await self.__streamer.stop()
@_system_task
+ async def __monitor_keyboard(self) -> None:
+ while self.__keyboard.is_alive():
+ await asyncio.sleep(0.1)
+ raise RuntimeError("Keyboard dead")
+
+ @_system_task
async def __stream_controller(self) -> None:
prev = 0
shutdown_at = 0.0
diff --git a/kvmd/kvmd/streamer.py b/kvmd/kvmd/streamer.py
index 8581e4ee..8a34de02 100644
--- a/kvmd/kvmd/streamer.py
+++ b/kvmd/kvmd/streamer.py
@@ -22,8 +22,8 @@ class Streamer: # pylint: disable=too-many-instance-attributes
loop: asyncio.AbstractEventLoop,
) -> None:
- self.__cap_power = gpio.set_output_zeroed(cap_power)
- self.__vga_power = gpio.set_output_zeroed(vga_power)
+ self.__cap_power = gpio.set_output(cap_power)
+ self.__vga_power = gpio.set_output(vga_power)
self.__sync_delay = sync_delay
self.__cmd = (