From c80807570af8b4e41bb7b250435e15a647130d4e Mon Sep 17 00:00:00 2001 From: WillForan Date: Fri, 10 May 2024 15:39:36 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7=20http=5Fttl:=20ar=5Feeg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- http_ttl.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++-- requirements.txt | 5 ++++ 2 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 requirements.txt diff --git a/http_ttl.py b/http_ttl.py index 1238421..18fc8a9 100755 --- a/http_ttl.py +++ b/http_ttl.py @@ -30,7 +30,7 @@ from tornado.httpserver import HTTPServer from tornado.web import RequestHandler, Application from tornado.ioloop import IOLoop -from pynput.keyboard import Controller, Key +from pynput.keyboard import Controller, Key, Listener import os import os.path @@ -154,6 +154,39 @@ async def watch(self): self.trigger("5 sec trigger") +class KeybaordListener(): + """ watch a real keyboard (cf. Cedrus, RTBox) + send ttl if approprate key pushed + left,right,up to ttl 2,3,4 matching cedrus (as of 20240510) + (1 reserved for photodiode) + """ + def __init__(self, hw, verbose=False): + self.hw = hw + self.verbose = verbose + self.keys_ttl = {'left': 2,'right': 3, 'up': 4} + self.keys = self.keys_ttl.keys() + + def parse_key(self, key): + "send key if key is in " + try: + k = key.char # single-char keys + except Exception as e: + print(e) + k = key.name + + if k in self.keys: + ttl = self.keys_ttl[k] + self.hw.send(ttl) + + if self.verbose: + print(f"[{datetime.datetime.now()}] {k}") + + async def watch(self): + "watch keypresses in background. forward key on to see if button should be pushed" + listener = Listener(on_press=self.parse_key) + listener.start() + + class Cedrus(): """ cedrus response box (RB-x40) top 3 right buttons are 5, 6, 7 (0-2 left, 3,4 thumb 5-7 right)""" @@ -320,6 +353,10 @@ def http_run(this_hardware): async def loeffeeg(verbose=False): + """settings for Luna Lab EEG in Loeffler building + uses Cedrus response box (+attached photodiode) + and TTL over LPT (biosemi) + """ hw = LPT(address=0xD010, verbose=verbose) kb = KB() rb = Cedrus(hw, kb) @@ -327,7 +364,24 @@ async def loeffeeg(verbose=False): await asyncio.create_task(rb.watch()) +async def ar_eeg(verbose=False): + """ + button pushes directly from they keyboard. + TTL over LPT (biosemi) + 20240510WF - init for LAF + """ + port = 0xCFE8 + hw = LPT(address=port, verbose=verbose) + rb = KeybaordListener(hw, verbose=verbose) + http_run(hw) + await asyncio.create_task(rb.watch()) + + async def seeg(verbose=False): + """ + sEEG at childrens hospital using USB 1208FS (binary TTL!) attached to grapevine + responses from RTBox with attached photodiode + """ hw = DAQ(verbose=verbose) kb = KB() rb = RTBox(hw, kb, verbose) @@ -392,7 +446,8 @@ async def fakeeeg(usekeyboard=False, verbose=False): def parser(args): import argparse p = argparse.ArgumentParser(description="Intercept http queries and watch ButtonBox/PhotoDiode") - p.add_argument('place', choices=["loeff", "seeg", "test_http", + p.add_argument('place', choices=["loeff", "seeg", "areeg", + "test_http", "test_rtbox", "test_DAQ", "test_cedrus", "test_lpt"], help='where (also how) to use button and ttl') @@ -408,6 +463,10 @@ def parser(args): asyncio.run(loeffeeg(verbose=args.verbose)) elif args.place == "seeg": asyncio.run(seeg(verbose=args.verbose)) + elif args.place == "areeg": + asyncio.run(ar_eeg(verbose=args.verbose)) + elif args.place == "seeg": + asyncio.run(seeg(verbose=args.verbose)) elif args.place == "test_http": asyncio.run(fakeeeg(args.usekeyboard, verbose=args.verbose)) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..014886a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +# 20240510 - psychopy cant run on newest python. using pyenv for +# pypy3.10-7.3.15 +# git+https://github.com/psychopy/psychopy +tornado +pynput