trying out async device scan

This commit is contained in:
dekuNukem
2025-08-23 16:02:43 +01:00
parent 9370ecdd72
commit 1493b8b803
31 changed files with 291 additions and 188 deletions

View File

@@ -1,89 +0,0 @@
import os
import sys
import time
import RPi.GPIO as GPIO
from demo_opts import get_device
from luma.core.render import canvas
from PIL import ImageFont
OLED_WIDTH = 128
OLED_HEIGHT = 32
my_arg = ['--display', 'ssd1306', '--interface', 'spi', '--spi-port', '0', '--spi-device', '1', '--gpio-reset', '6', '--gpio-data-command', '5', '--width', str(OLED_WIDTH), '--height', str(OLED_HEIGHT), '--spi-bus-speed', '2000000']
oled_device = get_device(my_arg)
time.sleep(0.5)
oled_device = get_device(my_arg)
font_regular = ImageFont.truetype("ProggyTiny.ttf", 16)
font_medium = ImageFont.truetype("ChiKareGo2.ttf", 16)
font_large = ImageFont.truetype("ProggyTiny.ttf", 32)
max_char_per_line = {font_regular:21, font_medium:17, font_large:11}
width_per_char = {font_regular:6, font_medium:7, font_large:12}
def oled_print_centered(text, font, y, this_canvas):
text = text.strip()[:max_char_per_line[font]]
start_x = int((OLED_WIDTH - (len(text) * width_per_char[font]))/2)
if start_x < 0:
start_x = 0
this_canvas.text((start_x, y), text, font=font, fill="white")
class my_button(object):
def __init__(self, bcm_pin):
super(my_button, self).__init__()
self.pin_number = bcm_pin
GPIO.setup(self.pin_number, GPIO.IN, pull_up_down=GPIO.PUD_UP)
self.prev_state = GPIO.input(self.pin_number)
def is_pressed(self):
result = False
current_state = GPIO.input(self.pin_number)
if self.prev_state == 1 and current_state == 0:
result = True
self.prev_state = current_state
return result
PLUS_BUTTON_PIN = 27
MINUS_BUTTON_PIN = 19
ENTER_BUTTON_PIN = 22
SHUTDOWN_BUTTON_PIN = 21
PCARD_CS_PIN = 8
SLEEP_LED_PIN = 26
GPIO.setup(SLEEP_LED_PIN, GPIO.OUT)
GPIO.output(SLEEP_LED_PIN, GPIO.LOW)
GPIO.setup(PCARD_CS_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
plus_button = my_button(PLUS_BUTTON_PIN)
minus_button = my_button(MINUS_BUTTON_PIN)
enter_button = my_button(ENTER_BUTTON_PIN)
shutdown_button = my_button(SHUTDOWN_BUTTON_PIN)
loop_count = 0
def print_pattern():
global loop_count
loop_count = (loop_count + 1) % 2
oled_device = get_device(my_arg)
if loop_count:
GPIO.output(SLEEP_LED_PIN, GPIO.HIGH)
with canvas(oled_device) as draw:
draw.text((0, 0), "ABCDEFGHIJKLMNO", font=font_medium, fill="white")
draw.text((0, 15), "PQRSTUVWXYZ0123", font=font_medium, fill="white")
else:
GPIO.output(SLEEP_LED_PIN, GPIO.LOW)
with canvas(oled_device) as draw:
draw.text((0, 0), "===================", font=font_medium, fill="white")
draw.text((0, 15), "===================", font=font_medium, fill="white")
print_pattern()
while 1:
time.sleep(0.05)
if GPIO.input(PCARD_CS_PIN) == 0:
GPIO.output(SLEEP_LED_PIN, GPIO.LOW)
exit()
if plus_button.is_pressed() or \
minus_button.is_pressed() or \
enter_button.is_pressed() or \
shutdown_button.is_pressed():
print_pattern()

View File

@@ -1,122 +0,0 @@
import time
import os
import sys
import subprocess
from subprocess import Popen, PIPE
LINUX_EXIT_CODE_TIMEOUT = 124
def bt_setup():
rfkill_str = subprocess.getoutput("/usr/sbin/rfkill -n")
if 'bluetooth' not in rfkill_str:
return 1, "no BT receiver found"
os.system('/usr/sbin/rfkill unblock bluetooth')
time.sleep(0.1)
exit_code = os.system('timeout 1 bluetoothctl agent NoInputNoOutput')
if exit_code == LINUX_EXIT_CODE_TIMEOUT:
return 2, 'bluetoothctl stuck'
return 0, ''
def scan_bt_devices(timeout_sec = 5):
exit_code = os.system(f"timeout {timeout_sec} bluetoothctl --agent NoInputNoOutput scan on") >> 8
if exit_code != LINUX_EXIT_CODE_TIMEOUT:
return None, 'scan error'
device_str = subprocess.getoutput("bluetoothctl --agent NoInputNoOutput devices")
dev_list = []
for line in device_str.replace('\r', '').split('\n'):
if 'device' not in line.lower():
continue
line_split = line.split(' ', maxsplit=2)
# skip if device has no name
if len(line_split) < 3 or line_split[2].count('-') == 5:
continue
dev_list.append((line_split[1], line_split[2]))
if len(dev_list) == 0:
return None, 'Nothing was found'
return dev_list, ''
def delete_all_devices():
dev_set = set()
device_str = subprocess.getoutput(f"bluetoothctl --agent NoInputNoOutput devices")
device_str2 = subprocess.getoutput(f"bluetoothctl --agent NoInputNoOutput paired-devices")
for line in (device_str + '\n' + device_str2).replace('\r', '').split('\n'):
if 'device' not in line.lower():
continue
line_split = line.split(' ', maxsplit=2)
# skip if device has no name
if len(line_split) < 3 or line_split[2].count('-') == 5:
continue
dev_set.add((line_split[1], line_split[2]))
print('vvvvv')
print(device_str)
print(device_str2)
print(dev_set)
print('^^^^^')
for item in dev_set:
os.system(f'bluetoothctl --agent NoInputNoOutput block {item[0]}')
os.system(f'bluetoothctl --agent NoInputNoOutput remove {item[0]}')
os.system(f'bluetoothctl --agent NoInputNoOutput unblock {item[0]}')
print('done')
def pair_device(mac_addr):
is_ready = False
is_sent = False
fail_phrases = ['fail', 'error', 'not available', 'excep']
with Popen(["bluetoothctl", "--agent", "NoInputNoOutput"], stdout=PIPE, stdin=PIPE, bufsize=1,
universal_newlines=True, shell=True) as p:
for line in p.stdout:
print(line, end='')
line_lo = line.lower()
if 'registered' in line_lo:
is_ready = True
if is_ready is False:
continue
if '#' in line_lo and is_sent == False:
p.stdin.write(f'pair {mac_addr}\n')
is_sent = True
if 'successful' in line_lo:
p.stdin.write('exit\n')
return True, 'Success!'
for item in fail_phrases:
if item in line_lo:
p.stdin.write('exit\n')
return False, line
return False, "wtf"
# if len(sys.argv) > 1:
# print("deleting all devices..")
# delete_all_devices()
# else:
# print(pair_device('20:20:01:01:3C:0C'))
# [agent] PIN: 027004
# [agent] Enter passkey (number in 0-999999):
def get_paired_devices():
dev_set = set()
try:
device_str = subprocess.getoutput(f"timeout 5 bluetoothctl --agent NoInputNoOutput paired-devices")
for line in device_str.replace('\r', '').split('\n'):
if 'device' not in line.lower():
continue
line_split = line.split(' ', maxsplit=2)
# skip if device has no name
if len(line_split) < 3 or line_split[2].count('-') == 5:
continue
dev_set.add((line_split[1], line_split[2]))
except Exception as e:
print('get_paired_devices exception:', e)
return dev_set
print(get_paired_devices())
# for item in dev_set:
# os.system(f'bluetoothctl --agent NoInputNoOutput block {item[0]}')
# os.system(f'bluetoothctl --agent NoInputNoOutput remove {item[0]}')
# os.system(f'bluetoothctl --agent NoInputNoOutput unblock {item[0]}')
# print('done')

View File

@@ -1,36 +0,0 @@
import time
import sys
import RPi.GPIO as GPIO
PLUS_BUTTON_PIN = 27
MINUS_BUTTON_PIN = 19
ENTER_BUTTON_PIN = 22
SHUTDOWN_BUTTON_PIN = 21
GPIO.setmode(GPIO.BCM)
GPIO.setup(PLUS_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(PLUS_BUTTON_PIN, GPIO.FALLING, bouncetime=250)
GPIO.setup(MINUS_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(MINUS_BUTTON_PIN, GPIO.FALLING, bouncetime=250)
GPIO.setup(ENTER_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(ENTER_BUTTON_PIN, GPIO.FALLING, bouncetime=250)
GPIO.setup(SHUTDOWN_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(SHUTDOWN_BUTTON_PIN, GPIO.FALLING, bouncetime=250)
while 1:
time.sleep(0.1)
if GPIO.event_detected(PLUS_BUTTON_PIN):
print(time.time(), "PLUS_BUTTON pressed!")
if GPIO.event_detected(MINUS_BUTTON_PIN):
print(time.time(), "MINUS_BUTTON pressed!")
if GPIO.event_detected(ENTER_BUTTON_PIN):
print(time.time(), "ENTER_BUTTON pressed!")
if GPIO.event_detected(SHUTDOWN_BUTTON_PIN):
print(time.time(), "SHUTDOWN_BUTTON pressed!")

View File

@@ -1,79 +0,0 @@
I: Bus=0003 Vendor=05ac Product=0250 Version=0111
N: Name="Apple Inc. Apple Keyboard"
P: Phys=usb-3f980000.usb-1.3.2/input0
S: Sysfs=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3.2/1-1.3.2:1.0/0003:05AC:0250.0001/input/input0
U: Uniq=
H: Handlers=sysrq kbd leds event0
B: PROP=0
B: EV=120013
B: KEY=10000 0 0 0 0 0 0 1007b 1007 ff9f207a c14057ff ffbeffdf ffefffff ffffffff fffffffe
B: MSC=10
B: LED=1f
I: Bus=0003 Vendor=05ac Product=0250 Version=0111
N: Name="Apple Inc. Apple Keyboard"
P: Phys=usb-3f980000.usb-1.3.2/input1
S: Sysfs=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3.2/1-1.3.2:1.1/0003:05AC:0250.0002/input/input1
U: Uniq=
H: Handlers=kbd event1
B: PROP=0
B: EV=13
B: KEY=3a 0 e0000 0 0 0
B: MSC=10
I: Bus=0003 Vendor=17ef Product=6039 Version=0111
N: Name="Lenovo Laser Wireless Mouse"
P: Phys=usb-3f980000.usb-1.4/input0
S: Sysfs=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/0003:17EF:6039.0004/input/input3
U: Uniq=
H: Handlers=mouse0 event3
B: PROP=0
B: EV=1f
B: KEY=1f0000 0 0 0 0 0 0 0 0
B: REL=1943
B: ABS=100 0
B: MSC=10
I: Bus=0003 Vendor=0483 Product=d11c Version=0111
N: Name="dekuNukem duckyPad(2020) Keyboard"
P: Phys=usb-3f980000.usb-1.2/input0
S: Sysfs=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2:1.0/0003:0483:D11C.0006/input/input5
U: Uniq=DP20_774c6600
H: Handlers=sysrq kbd event2
B: PROP=0
B: EV=100013
B: KEY=7 ff800000 0 e0b0ffdf 1cfffff ffffffff fffffffe
B: MSC=10
I: Bus=0003 Vendor=0483 Product=d11c Version=0111
N: Name="dekuNukem duckyPad(2020) Consumer Control"
P: Phys=usb-3f980000.usb-1.2/input0
S: Sysfs=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2:1.0/0003:0483:D11C.0006/input/input6
U: Uniq=DP20_774c6600
H: Handlers=kbd event4
B: PROP=0
B: EV=13
B: KEY=7a 0 e0000 0 0 0
B: MSC=10
I: Bus=0003 Vendor=0483 Product=d11c Version=0111
N: Name="dekuNukem duckyPad(2020) Mouse"
P: Phys=usb-3f980000.usb-1.2/input0
S: Sysfs=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2:1.0/0003:0483:D11C.0006/input/input7
U: Uniq=DP20_774c6600
H: Handlers=mouse1 event5
B: PROP=0
B: EV=17
B: KEY=70000 0 0 0 0 0 0 0 0
B: REL=903
B: MSC=10
I: Bus=0003 Vendor=0483 Product=d11c Version=0111
N: Name="dekuNukem duckyPad(2020)"
P: Phys=usb-3f980000.usb-1.2/input0
S: Sysfs=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2:1.0/0003:0483:D11C.0006/input/input8
U: Uniq=DP20_774c6600
H: Handlers=event6
B: PROP=0
B: EV=9
B: ABS=100 0

View File

@@ -1,36 +0,0 @@
import time
import evdev
# sh sync.sh; ssh -t pi@192.168.1.56 "pkill python3;cd ~/usb4vc;python3 evdev_test.py"
# sh sync.sh; ssh -t pi@192.168.1.56 "pkill python3;cd ~/usb4vc;python3 usb4vc_main.py"
def get_input_devices():
result = []
available_devices = [evdev.InputDevice(path) for path in evdev.list_devices()]
for this_device in available_devices:
dev_dict = {
'path':this_device.path,
'name':this_device.name,
'axes_info':{},
'is_kb':False,
'is_mouse':False,
'is_gp':False,
}
cap_str = str(this_device.capabilities(verbose=True))
if 'BTN_LEFT' in cap_str and "EV_REL" in cap_str:
dev_dict['is_mouse'] = True
if 'KEY_ENTER' in cap_str and "KEY_Y" in cap_str:
dev_dict['is_kb'] = True
if 'EV_ABS' in cap_str and "BTN_SOUTH" in cap_str:
dev_dict['is_gp'] = True
try:
for item in this_device.capabilities()[EV_ABS]:
dev_dict['axes_info'][item[0]] = item[1]._asdict()
except Exception as e:
print('get_input_devices exception:', e)
result.append(dev_dict)
return result
start = time.time_ns()
get_input_devices()
print((time.time_ns() - start) / 1000000)

View File

@@ -1,108 +0,0 @@
import os
import sys
import time
import spidev
import RPi.GPIO as GPIO
PBOARD_RESET_PIN = 25
PBOARD_BOOT0_PIN = 12
SLAVE_REQ_PIN = 16
GPIO.setmode(GPIO.BCM)
GPIO.setup(PBOARD_RESET_PIN, GPIO.IN)
GPIO.setup(PBOARD_BOOT0_PIN, GPIO.IN)
GPIO.setup(SLAVE_REQ_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
is_dfu = False
def enter_dfu():
# RESET LOW: Enter reset
GPIO.setup(PBOARD_RESET_PIN, GPIO.OUT)
GPIO.output(PBOARD_RESET_PIN, GPIO.LOW)
time.sleep(0.05)
# BOOT0 HIGH: Boot into DFU mode
GPIO.setup(PBOARD_BOOT0_PIN, GPIO.OUT)
GPIO.output(PBOARD_BOOT0_PIN, GPIO.HIGH)
time.sleep(0.05)
# Release RESET, BOOT0 still HIGH, STM32 now in DFU mode
GPIO.setup(PBOARD_RESET_PIN, GPIO.IN)
time.sleep(1)
def exit_dfu():
# Release BOOT0
GPIO.setup(PBOARD_BOOT0_PIN, GPIO.IN)
# Activate RESET
GPIO.setup(PBOARD_RESET_PIN, GPIO.OUT)
GPIO.output(PBOARD_RESET_PIN, GPIO.LOW)
time.sleep(0.05)
# Release RESET, BOOT0 is LOW, STM32 boots in normal mode
GPIO.setup(PBOARD_RESET_PIN, GPIO.IN)
time.sleep(0.2)
def flash_firmware(fw_path):
for x in range(5):
print(f"----------------- {fw_path.split('/')[-1]} -----------------")
enter_dfu()
if is_dfu:
exit_code = os.system(f'sudo dfu-util --device ,0483:df11 -a 0 -D {fw_path}') >> 8
else:
exit_code = os.system(f'sudo stm32flash -w {fw_path} -a 0x3b /dev/i2c-1') >> 8
exit_dfu()
if exit_code != 0:
for x in range(5):
print("!!!!!!!!!!!!!!!!! TEST FLASH FAILED !!!!!!!!!!!!!!!!!")
exit()
if(len(sys.argv) < 3):
print (__file__ + ' payload_fw test_fw')
exit()
os.system("clear")
pcard_spi = spidev.SpiDev(0, 0)
pcard_spi.max_speed_hz = 2000000
payload_fw_path = sys.argv[1]
test_fw_path = sys.argv[2]
if '.dfu' in payload_fw_path.lower() or '.dfu' in test_fw_path.lower():
is_dfu = True
flash_firmware(test_fw_path)
req_result = []
for x in range(10):
req_result.append(GPIO.input(SLAVE_REQ_PIN))
time.sleep(0.1)
print(req_result)
if 0 not in req_result or 1 not in req_result or req_result.count(0) <= 3 or req_result.count(1) <= 3:
for x in range(5):
print("!!!!!!!!!!!!!!!!! SLAVE REQ ERROR !!!!!!!!!!!!!!!!!")
exit()
while 1:
if len(input("Press enter to continue\n")) == 0:
break;
flash_firmware(payload_fw_path)
SPI_MOSI_MAGIC = 0xde
SPI_MOSI_MSG_TYPE_INFO_REQUEST = 1
nop_spi_msg_template = [SPI_MOSI_MAGIC] + [0]*31
info_request_spi_msg_template = [SPI_MOSI_MAGIC, 0, SPI_MOSI_MSG_TYPE_INFO_REQUEST] + [0]*29
this_msg = list(info_request_spi_msg_template)
pcard_spi.xfer(this_msg)
time.sleep(0.1)
response = pcard_spi.xfer(list(nop_spi_msg_template))
time.sleep(0.1)
print(response)
if response[0] != 205:
for x in range(5):
print("!!!!!!!!!!!!!!!!! WRONG RESPONSE !!!!!!!!!!!!!!!!!")
else:
print("----------------- OK OK OK OK OK OK -----------------")
print("----------------- OK OK OK OK OK OK -----------------")

View File

@@ -1,12 +0,0 @@
import usb4vc_shared
default_map_dict = {}
for item in usb4vc_shared.gamepad_event_code_name_list:
this_name = item
this_value = usb4vc_shared.code_name_to_value_lookup.get(item)
if this_value is None:
continue
default_map_dict[this_name] = {'code':f'IBM_GGP_BTN_{(this_value[0]%4) + 1}'}
print(default_map_dict)

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,96 +0,0 @@
very useful video:
https://youtu.be/wdgULBpRoXk
search for PID ACK for data packet
from keypress to PID ACK on USB line: 10 to 20ms
catting /dev/input/event0 in bash: 490us
printing via python3: 1ms
script below:
fff = open("/dev/input/event0", "rb" )
while 1:
data = fff.read(24)
print(data)
using queue to despatch SPI on raspberry 3: 700 to 800us
on lichee 3.5ms
libevdev is SUPER SLOW! 20ms delay in parsing keyboard events. might write about it or do some more testing.
hand parse raw dev/input: 470us on pi3, 1ms on lichee
black PS2 extension cable both male:
purple clk
black data
brown GND
ps2 driver based on https://github.com/Harvie/ps2dev
no parity check for speed
raspberry pi gpio linux pin numbers is BCM pin number, check use `gpio readall`
in allwinner chips, linux gpio number = (position of letter in alphabet - 1) * 32 + pin number
PA3 = (1-1) * 32 + 3 = gpio3
PE3 = (5-1) * 32 + 3 = 128+3 = gpio131
echo 131 > /sys/class/gpio/export
echo in > /sys/class/gpio/gpio131/direction
cat /sys/class/gpio/gpio131/value
to see list of all interrupts
cat /proc/interrupts
change keyboard LED
sudo bash -c 'echo 1 > /sys/class/leds/input5\:\:capslock/brightness'
run script on launch:
https://raspberrypi-guide.github.io/programming/run-script-on-boot
sudo nano /etc/rc.local
cd /home/pi/usb4vc; sudo python3 usb4vc_main.py &
kill -SIGINT pid
ps2 mouse todo:
add remote mode data report
add scale/resolution change
test remote/wrap mode
supported protocols:
PS/2 Keyboard:
Scancode set 2
PS/2 Mouse:
generic id0
MS intellimouse id3
Serial Mouse:
Microsoft serial mouse (3 byte 1200bps 7n1)
rfkill returns nothing with no bluetooth on rpi 2
bluetoothctrl gets stuck if no bluetooth
check rfkill first, then put a timeout on first btctl command
bluetoothctl --agent NoInputNoOutput
scan on
trust <MAC-Address>
connect <MAC-Address>

View File

@@ -1,195 +0,0 @@
CODE_UNUSED, // KEY_RESERVED 0
0x8, // KEY_ESC 1
0x16, // KEY_1 2
0x1e, // KEY_2 3
0x26, // KEY_3 4
0x25, // KEY_4 5
0x2e, // KEY_5 6
0x36, // KEY_6 7
0x3d, // KEY_7 8
0x3e, // KEY_8 9
0x46, // KEY_9 10
0x45, // KEY_0 11
0x4e, // KEY_MINUS 12
0x55, // KEY_EQUAL 13
0x66, // KEY_BACKSPACE 14
0xd, // KEY_TAB 15
0x15, // KEY_Q 16
0x1d, // KEY_W 17
0x24, // KEY_E 18
0x2d, // KEY_R 19
0x2c, // KEY_T 20
0x35, // KEY_Y 21
0x3c, // KEY_U 22
0x43, // KEY_I 23
0x44, // KEY_O 24
0x4d, // KEY_P 25
0x54, // KEY_LEFTBRACE 26
0x5b, // KEY_RIGHTBRACE 27
0x5a, // KEY_ENTER 28
0x11, // KEY_LEFTCTRL 29
0x1c, // KEY_A 30
0x1b, // KEY_S 31
0x23, // KEY_D 32
0x2b, // KEY_F 33
0x34, // KEY_G 34
0x33, // KEY_H 35
0x3b, // KEY_J 36
0x42, // KEY_K 37
0x4b, // KEY_L 38
0x4c, // KEY_SEMICOLON 39
0x52, // KEY_APOSTROPHE 40
0xe, // KEY_GRAVE 41
0x12, // KEY_LEFTSHIFT 42
0x5c, // KEY_BACKSLASH 43
0x1a, // KEY_Z 44
0x22, // KEY_X 45
0x21, // KEY_C 46
0x2a, // KEY_V 47
0x32, // KEY_B 48
0x31, // KEY_N 49
0x3a, // KEY_M 50
0x41, // KEY_COMMA 51
0x49, // KEY_DOT 52
0x4a, // KEY_SLASH 53
0x59, // KEY_RIGHTSHIFT 54
0x7e, // KEY_KPASTERISK 55
0x19, // KEY_LEFTALT 56
0x29, // KEY_SPACE 57
0x14, // KEY_CAPSLOCK 58
0x7, // KEY_F1 59
0xf, // KEY_F2 60
0x17, // KEY_F3 61
0x1f, // KEY_F4 62
0x27, // KEY_F5 63
0x2f, // KEY_F6 64
0x37, // KEY_F7 65
0x3f, // KEY_F8 66
0x47, // KEY_F9 67
0x4f, // KEY_F10 68
0x76, // KEY_NUMLOCK 69
0x5f, // KEY_SCROLLLOCK 70
0x6c, // KEY_KP7 71
0x75, // KEY_KP8 72
0x7d, // KEY_KP9 73
0x4e, // KEY_KPMINUS 74
0x6b, // KEY_KP4 75
0x73, // KEY_KP5 76
0x74, // KEY_KP6 77
0x7c, // KEY_KPPLUS 78
0x69, // KEY_KP1 79
0x72, // KEY_KP2 80
0x7a, // KEY_KP3 81
0x70, // KEY_KP0 82
0x71, // KEY_KPDOT 83
CODE_UNUSED, // KEY_UNUSED 84
CODE_UNUSED, // KEY_ZENKAKUHANKAKU 85
0x13, // KEY_102ND 86
0x56, // KEY_F11 87
0x5e, // KEY_F12 88
CODE_UNUSED, // KEY_RO 89
CODE_UNUSED, // KEY_KATAKANA 90
CODE_UNUSED, // KEY_HIRAGANA 91
CODE_UNUSED, // KEY_HENKAN 92
CODE_UNUSED, // KEY_KATAKANAHIRAGANA 93
CODE_UNUSED, // KEY_MUHENKAN 94
CODE_UNUSED, // KEY_KPJPCOMMA 95
0x79, // KEY_KPENTER 96
0x58, // KEY_RIGHTCTRL 97
0x4a, // KEY_KPSLASH 98
0x57, // KEY_SYSRQ 99
0x39, // KEY_RIGHTALT 100
CODE_UNUSED, // KEY_LINEFEED 101
0x6e, // KEY_HOME 102
0x63, // KEY_UP 103
0x6f, // KEY_PAGEUP 104
0x61, // KEY_LEFT 105
0x6a, // KEY_RIGHT 106
0x65, // KEY_END 107
0x60, // KEY_DOWN 108
0x6d, // KEY_PAGEDOWN 109
0x67, // KEY_INSERT 110
0x64, // KEY_DELETE 111
CODE_UNUSED, // KEY_MACRO 112
CODE_UNUSED, // KEY_MUTE 113
CODE_UNUSED, // KEY_VOLUMEDOWN 114
CODE_UNUSED, // KEY_VOLUMEUP 115
CODE_UNUSED, // KEY_POWER 116
CODE_UNUSED, // KEY_KPEQUAL 117
CODE_UNUSED, // KEY_KPPLUSMINUS 118
0x62, // KEY_PAUSE 119
CODE_UNUSED, // KEY_SCALE 120
CODE_UNUSED, // KEY_KPCOMMA 121
CODE_UNUSED, // KEY_HANGEUL 122
CODE_UNUSED, // KEY_HANJA 123
CODE_UNUSED, // KEY_YEN 124
0x8b, // KEY_LEFTMETA 125
0x8c, // KEY_RIGHTMETA 126
0x8d, // KEY_COMPOSE 127
CODE_UNUSED, // KEY_STOP 128
CODE_UNUSED, // KEY_AGAIN 129
CODE_UNUSED, // KEY_PROPS 130
CODE_UNUSED, // KEY_UNDO 131
CODE_UNUSED, // KEY_FRONT 132
CODE_UNUSED, // KEY_COPY 133
CODE_UNUSED, // KEY_OPEN 134
CODE_UNUSED, // KEY_PASTE 135
CODE_UNUSED, // KEY_FIND 136
CODE_UNUSED, // KEY_CUT 137
CODE_UNUSED, // KEY_HELP 138
CODE_UNUSED, // KEY_MENU 139
CODE_UNUSED, // KEY_CALC 140
CODE_UNUSED, // KEY_SETUP 141
CODE_UNUSED, // KEY_SLEEP 142
CODE_UNUSED, // KEY_WAKEUP 143
CODE_UNUSED, // KEY_FILE 144
CODE_UNUSED, // KEY_SENDFILE 145
CODE_UNUSED, // KEY_DELETEFILE 146
CODE_UNUSED, // KEY_XFER 147
CODE_UNUSED, // KEY_PROG1 148
CODE_UNUSED, // KEY_PROG2 149
CODE_UNUSED, // KEY_WWW 150
CODE_UNUSED, // KEY_MSDOS 151
CODE_UNUSED, // KEY_COFFEE 152
CODE_UNUSED, // KEY_ROTATE_DISPLAY 153
CODE_UNUSED, // KEY_CYCLEWINDOWS 154
CODE_UNUSED, // KEY_MAIL 155
CODE_UNUSED, // KEY_BOOKMARKS 156
CODE_UNUSED, // KEY_COMPUTER 157
CODE_UNUSED, // KEY_BACK 158
CODE_UNUSED, // KEY_FORWARD 159
CODE_UNUSED, // KEY_CLOSECD 160
CODE_UNUSED, // KEY_EJECTCD 161
CODE_UNUSED, // KEY_EJECTCLOSECD 162
CODE_UNUSED, // KEY_NEXTSONG 163
CODE_UNUSED, // KEY_PLAYPAUSE 164
CODE_UNUSED, // KEY_PREVIOUSSONG 165
CODE_UNUSED, // KEY_STOPCD 166
CODE_UNUSED, // KEY_RECORD 167
CODE_UNUSED, // KEY_REWIND 168
CODE_UNUSED, // KEY_PHONE 169
CODE_UNUSED, // KEY_ISO 170
CODE_UNUSED, // KEY_CONFIG 171
CODE_UNUSED, // KEY_HOMEPAGE 172
CODE_UNUSED, // KEY_REFRESH 173
CODE_UNUSED, // KEY_EXIT 174
CODE_UNUSED, // KEY_MOVE 175
CODE_UNUSED, // KEY_EDIT 176
CODE_UNUSED, // KEY_SCROLLUP 177
CODE_UNUSED, // KEY_SCROLLDOWN 178
CODE_UNUSED, // KEY_KPLEFTPAREN 179
CODE_UNUSED, // KEY_KPRIGHTPAREN 180
CODE_UNUSED, // KEY_NEW 181
CODE_UNUSED, // KEY_REDO 182
0x08, // KEY_F13 183
0x10, // KEY_F14 184
0x18, // KEY_F15 185
0x20, // KEY_F16 186
0x28, // KEY_F17 187
0x30, // KEY_F18 188
0x38, // KEY_F19 189
0x40, // KEY_F20 190
0x48, // KEY_F21 191
0x50, // KEY_F22 192
0x57, // KEY_F23 193
0x5f, // KEY_F24 194

View File

@@ -1,213 +0,0 @@
CODE_UNUSED = 255
tttttt = [
(CODE_UNUSED, "KEY_RESERVED", 0),
(0x8, "KEY_ESC", 1),
(0x16, "KEY_1", 2),
(0x1e, "KEY_2", 3),
(0x26, "KEY_3", 4),
(0x25, "KEY_4", 5),
(0x2e, "KEY_5", 6),
(0x36, "KEY_6", 7),
(0x3d, "KEY_7", 8),
(0x3e, "KEY_8", 9),
(0x46, "KEY_9", 10),
(0x45, "KEY_0", 11),
(0x4e, "KEY_MINUS", 12),
(0x55, "KEY_EQUAL", 13),
(0x66, "KEY_BACKSPACE", 14),
(0xd, "KEY_TAB", 15),
(0x15, "KEY_Q", 16),
(0x1d, "KEY_W", 17),
(0x24, "KEY_E", 18),
(0x2d, "KEY_R", 19),
(0x2c, "KEY_T", 20),
(0x35, "KEY_Y", 21),
(0x3c, "KEY_U", 22),
(0x43, "KEY_I", 23),
(0x44, "KEY_O", 24),
(0x4d, "KEY_P", 25),
(0x54, "KEY_LEFTBRACE", 26),
(0x5b, "KEY_RIGHTBRACE", 27),
(0x5a, "KEY_ENTER", 28),
(0x11, "KEY_LEFTCTRL", 29),
(0x1c, "KEY_A", 30),
(0x1b, "KEY_S", 31),
(0x23, "KEY_D", 32),
(0x2b, "KEY_F", 33),
(0x34, "KEY_G", 34),
(0x33, "KEY_H", 35),
(0x3b, "KEY_J", 36),
(0x42, "KEY_K", 37),
(0x4b, "KEY_L", 38),
(0x4c, "KEY_SEMICOLON", 39),
(0x52, "KEY_APOSTROPHE", 40),
(0xe, "KEY_GRAVE", 41),
(0x12, "KEY_LEFTSHIFT", 42),
(0x5c, "KEY_BACKSLASH", 43),
(0x1a, "KEY_Z", 44),
(0x22, "KEY_X", 45),
(0x21, "KEY_C", 46),
(0x2a, "KEY_V", 47),
(0x32, "KEY_B", 48),
(0x31, "KEY_N", 49),
(0x3a, "KEY_M", 50),
(0x41, "KEY_COMMA", 51),
(0x49, "KEY_DOT", 52),
(0x4a, "KEY_SLASH", 53),
(0x59, "KEY_RIGHTSHIFT", 54),
(0x7e, "KEY_KPASTERISK", 55),
(0x19, "KEY_LEFTALT", 56),
(0x29, "KEY_SPACE", 57),
(0x14, "KEY_CAPSLOCK", 58),
(0x7, "KEY_F1", 59),
(0xf, "KEY_F2", 60),
(0x17, "KEY_F3", 61),
(0x1f, "KEY_F4", 62),
(0x27, "KEY_F5", 63),
(0x2f, "KEY_F6", 64),
(0x37, "KEY_F7", 65),
(0x3f, "KEY_F8", 66),
(0x47, "KEY_F9", 67),
(0x4f, "KEY_F10", 68),
(0x76, "KEY_NUMLOCK", 69),
(0x5f, "KEY_SCROLLLOCK", 70),
(0x6c, "KEY_KP7", 71),
(0x75, "KEY_KP8", 72),
(0x7d, "KEY_KP9", 73),
(0x4e, "KEY_KPMINUS", 74),
(0x6b, "KEY_KP4", 75),
(0x73, "KEY_KP5", 76),
(0x74, "KEY_KP6", 77),
(0x7c, "KEY_KPPLUS", 78),
(0x69, "KEY_KP1", 79),
(0x72, "KEY_KP2", 80),
(0x7a, "KEY_KP3", 81),
(0x70, "KEY_KP0", 82),
(0x71, "KEY_KPDOT", 83),
(CODE_UNUSED, "KEY_UNUSED", 84),
(CODE_UNUSED, "KEY_ZENKAKUHANKAKU", 85),
(0x13, "KEY_102ND", 86),
(0x56, "KEY_F11", 87),
(0x5e, "KEY_F12", 88),
(CODE_UNUSED, "KEY_RO", 89),
(CODE_UNUSED, "KEY_KATAKANA", 90),
(CODE_UNUSED, "KEY_HIRAGANA", 91),
(CODE_UNUSED, "KEY_HENKAN", 92),
(CODE_UNUSED, "KEY_KATAKANAHIRAGANA", 93),
(CODE_UNUSED, "KEY_MUHENKAN", 94),
(CODE_UNUSED, "KEY_KPJPCOMMA", 95),
(0x79, "KEY_KPENTER", 96),
(0x58, "KEY_RIGHTCTRL", 97),
(0x4a, "KEY_KPSLASH", 98),
(0x57, "KEY_SYSRQ", 99),
(0x39, "KEY_RIGHTALT", 100),
(CODE_UNUSED, "KEY_LINEFEED", 101),
(0x6e, "KEY_HOME", 102),
(0x63, "KEY_UP", 103),
(0x6f, "KEY_PAGEUP", 104),
(0x61, "KEY_LEFT", 105),
(0x6a, "KEY_RIGHT", 106),
(0x65, "KEY_END", 107),
(0x60, "KEY_DOWN", 108),
(0x6d, "KEY_PAGEDOWN", 109),
(0x67, "KEY_INSERT", 110),
(0x64, "KEY_DELETE", 111),
(CODE_UNUSED, "KEY_MACRO", 112),
(CODE_UNUSED, "KEY_MUTE", 113),
(CODE_UNUSED, "KEY_VOLUMEDOWN", 114),
(CODE_UNUSED, "KEY_VOLUMEUP", 115),
(CODE_UNUSED, "KEY_POWER", 116),
(CODE_UNUSED, "KEY_KPEQUAL", 117),
(CODE_UNUSED, "KEY_KPPLUSMINUS", 118),
(0x62, "KEY_PAUSE", 119),
(CODE_UNUSED, "KEY_SCALE", 120),
(CODE_UNUSED, "KEY_KPCOMMA", 121),
(CODE_UNUSED, "KEY_HANGEUL", 122),
(CODE_UNUSED, "KEY_HANJA", 123),
(CODE_UNUSED, "KEY_YEN", 124),
(0x8b, "KEY_LEFTMETA", 125),
(0x8c, "KEY_RIGHTMETA", 126),
(0x8d, "KEY_COMPOSE", 127),
(CODE_UNUSED, "KEY_STOP", 128),
(CODE_UNUSED, "KEY_AGAIN", 129),
(CODE_UNUSED, "KEY_PROPS", 130),
(CODE_UNUSED, "KEY_UNDO", 131),
(CODE_UNUSED, "KEY_FRONT", 132),
(CODE_UNUSED, "KEY_COPY", 133),
(CODE_UNUSED, "KEY_OPEN", 134),
(CODE_UNUSED, "KEY_PASTE", 135),
(CODE_UNUSED, "KEY_FIND", 136),
(CODE_UNUSED, "KEY_CUT", 137),
(CODE_UNUSED, "KEY_HELP", 138),
(CODE_UNUSED, "KEY_MENU", 139),
(CODE_UNUSED, "KEY_CALC", 140),
(CODE_UNUSED, "KEY_SETUP", 141),
(CODE_UNUSED, "KEY_SLEEP", 142),
(CODE_UNUSED, "KEY_WAKEUP", 143),
(CODE_UNUSED, "KEY_FILE", 144),
(CODE_UNUSED, "KEY_SENDFILE", 145),
(CODE_UNUSED, "KEY_DELETEFILE", 146),
(CODE_UNUSED, "KEY_XFER", 147),
(CODE_UNUSED, "KEY_PROG1", 148),
(CODE_UNUSED, "KEY_PROG2", 149),
(CODE_UNUSED, "KEY_WWW", 150),
(CODE_UNUSED, "KEY_MSDOS", 151),
(CODE_UNUSED, "KEY_COFFEE", 152),
(CODE_UNUSED, "KEY_ROTATE_DISPLAY", 153),
(CODE_UNUSED, "KEY_CYCLEWINDOWS", 154),
(CODE_UNUSED, "KEY_MAIL", 155),
(CODE_UNUSED, "KEY_BOOKMARKS", 156),
(CODE_UNUSED, "KEY_COMPUTER", 157),
(CODE_UNUSED, "KEY_BACK", 158),
(CODE_UNUSED, "KEY_FORWARD", 159),
(CODE_UNUSED, "KEY_CLOSECD", 160),
(CODE_UNUSED, "KEY_EJECTCD", 161),
(CODE_UNUSED, "KEY_EJECTCLOSECD", 162),
(CODE_UNUSED, "KEY_NEXTSONG", 163),
(CODE_UNUSED, "KEY_PLAYPAUSE", 164),
(CODE_UNUSED, "KEY_PREVIOUSSONG", 165),
(CODE_UNUSED, "KEY_STOPCD", 166),
(CODE_UNUSED, "KEY_RECORD", 167),
(CODE_UNUSED, "KEY_REWIND", 168),
(CODE_UNUSED, "KEY_PHONE", 169),
(CODE_UNUSED, "KEY_ISO", 170),
(CODE_UNUSED, "KEY_CONFIG", 171),
(CODE_UNUSED, "KEY_HOMEPAGE", 172),
(CODE_UNUSED, "KEY_REFRESH", 173),
(CODE_UNUSED, "KEY_EXIT", 174),
(CODE_UNUSED, "KEY_MOVE", 175),
(CODE_UNUSED, "KEY_EDIT", 176),
(CODE_UNUSED, "KEY_SCROLLUP", 177),
(CODE_UNUSED, "KEY_SCROLLDOWN", 178),
(CODE_UNUSED, "KEY_KPLEFTPAREN", 179),
(CODE_UNUSED, "KEY_KPRIGHTPAREN", 180),
(CODE_UNUSED, "KEY_NEW", 181),
(CODE_UNUSED, "KEY_REDO", 182),
(0x08, "KEY_F13", 183),
(0x10, "KEY_F14", 184),
(0x18, "KEY_F15", 185),
(0x20, "KEY_F16", 186),
(0x28, "KEY_F17", 187),
(0x30, "KEY_F18", 188),
(0x38, "KEY_F19", 189),
(0x40, "KEY_F20", 190),
(0x48, "KEY_F21", 191),
(0x50, "KEY_F22", 192),
(0x57, "KEY_F23", 193),
(0x5f, "KEY_F24", 194),
]
# (set3 scan code, key name, linux ev code)
sorted_list = sorted(tttttt, key=lambda x: x[0])
set3_dict = {}
for item in sorted_list:
set3_dict[item[0]] = item
for x in range(255):
if x in set3_dict:
print(f'SET3_KEY_STATE_TYPEMATIC, // ({x}, {hex(x)}), {set3_dict[x][1]}, ({set3_dict[x][2]}, {hex(set3_dict[x][2])})')
else:
print(f'SET3_KEY_STATE_TYPEMATIC, // ({x}, {hex(x)}), UNUSED')

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
for x in range(32):
print(hex(x), '', end='')

View File

@@ -1,67 +0,0 @@
import sys
import time
import spidev
import threading
is_on_raspberry_pi = False
with open('/etc/os-release') as os_version_file:
is_on_raspberry_pi = 'raspbian' in os_version_file.read().lower()
spi = None
if is_on_raspberry_pi:
spi = spidev.SpiDev(0, 0) # rasp
print("I'm on Raspberry Pi!")
else:
spi = spidev.SpiDev(1, 0) # lichee
print("I'm on custom board!")
spi.max_speed_hz = 2000000
fff = open(sys.argv[1], "rb" )
"""
https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/input-event-codes.h#L38
xbox gamepad:
EVENT TYPE: EV_ABS
dpad: ABS_HAT0X ABS_HAT1X
buttons: https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/input-event-codes.h#L385
sticks: ABS_X, ABS_Y, ABS_RX, ABS_RY
"""
EV_KEY = 0x01
EV_REL = 0x02
EV_ABS = 0x03
SPI_MSG_KEYBOARD_EVENT = 1
SPI_MSG_MOUSE_EVENT = 2
SPI_MSG_GAMEPAD_EVENT = 3
KEYBOARD_ID_PLACEHOLDER = 0
keyboard_spi_msg_header = [0xde, 0, SPI_MSG_KEYBOARD_EVENT, KEYBOARD_ID_PLACEHOLDER]
def keyboard_worker():
print("keyboard_thread started")
while 1:
data = list(fff.read(16)[8:])
if data[0] == EV_KEY:
spi.xfer(keyboard_spi_msg_header + data)
# print(data)
# print('----')
def mouse_worker():
print("mouse_thread started")
while 1:
time.sleep(0.2)
keyboard_thread = threading.Thread(target=keyboard_worker, daemon=True)
keyboard_thread.start()
mouse_thread = threading.Thread(target=mouse_worker, daemon=True)
mouse_thread.start()
while 1:
# print("main loop")
time.sleep(1)

View File

@@ -1,17 +0,0 @@
import select
gpio_path = "/sys/class/gpio/gpio131/value"
gpio_file = open(gpio_path, 'rb')
epoll = select.epoll()
epoll.register(gpio_file, select.EPOLLET)
while 1:
events = epoll.poll(timeout=0.2)
for df, event_type in events:
print(df, event_type)
print('here')
epoll.unregister(gpio_file)
gpio_file.close()

View File

@@ -1,10 +0,0 @@
import sys
import libevdev
fd = open(sys.argv[1], "rb" )
d = libevdev.Device(fd)
while True:
for e in d.events():
print(e)

View File

@@ -1,47 +0,0 @@
import sys
import time
import libevdev
import spidev
import threading
is_on_raspberry_pi = False
with open('/etc/os-release') as os_version_file:
is_on_raspberry_pi = 'raspbian' in os_version_file.read().lower()
spi = None
if is_on_raspberry_pi:
spi = spidev.SpiDev(0, 0) # rasp
print("I'm on Raspberry Pi!")
else:
spi = spidev.SpiDev(1, 0) # lichee
print("I'm on custom board!")
spi.max_speed_hz = 2000000
# fff = open("/dev/input/event1", "rb" )
fff = open(sys.argv[1], "rb" )
this_device = libevdev.Device(fff)
# this_device.disable(libevdev.EV_MSC)
def keyboard_worker():
print("keyboard_thread started")
while 1:
for e in this_device.events():
spi.xfer([0x5]*32)
print(e)
def mouse_worker():
print("mouse_thread started")
while 1:
time.sleep(0.2)
# print("sent")
keyboard_thread = threading.Thread(target=keyboard_worker, daemon=True)
keyboard_thread.start()
mouse_thread = threading.Thread(target=mouse_worker, daemon=True)
mouse_thread.start()
while 1:
# print("main loop")
time.sleep(1)

View File

@@ -1,16 +0,0 @@
import time
import sys
import RPi.GPIO as GPIO
BUTTON_GPIO = 16
def button_pressed_callback(channel):
print(time.time(), "Button pressed!")
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(BUTTON_GPIO, GPIO.FALLING, callback=button_pressed_callback, bouncetime=100)
while 1:
time.sleep(1)

View File

@@ -1,15 +0,0 @@
import time
import sys
import RPi.GPIO as GPIO
SLAVE_REQ_PIN = 16
GPIO.setmode(GPIO.BCM)
GPIO.setup(SLAVE_REQ_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(SLAVE_REQ_PIN, GPIO.FALLING, bouncetime=100)
while 1:
time.sleep(0.1)
if GPIO.event_detected(SLAVE_REQ_PIN):
print(time.time(), "Button pressed!")

View File

@@ -1,9 +0,0 @@
echo 131 > /sys/class/gpio/unexport
cat /proc/interrupts
echo 131 > /sys/class/gpio/export
echo in > /sys/class/gpio/gpio131/direction
echo rising > /sys/class/gpio/gpio131/edge
cat /proc/interrupts
# (letter in alfabet - 1) * 32 + number
# PE3: (5-1) * 32 + 3 = 131

View File

@@ -1,116 +0,0 @@
import os
import sys
import time
import spidev
import threading
is_on_raspberry_pi = False
with open('/etc/os-release') as os_version_file:
is_on_raspberry_pi = 'raspbian' in os_version_file.read().lower()
spi = None
if is_on_raspberry_pi:
spi = spidev.SpiDev(0, 0) # rasp
print("I'm on Raspberry Pi!")
os.system("echo 16 > /sys/class/gpio/export")
os.system("echo in > /sys/class/gpio/gpio16/direction")
print("GPIO init done")
else:
spi = spidev.SpiDev(1, 0) # lichee
print("I'm on custom board!")
spi.max_speed_hz = 2000000
keyboard_opened_device_dict = {}
mouse_opened_device_dict = {}
gamepad_opened_device_dict = {}
slave_ready_gpio_file = open("/sys/class/gpio/gpio16/value", 'rb')
"""
def send kb
def send mouse
def send js
read data first, if exception, skip it
"""
"""
https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/input-event-codes.h#L38
xbox gamepad:
EVENT TYPE: EV_ABS
dpad: ABS_HAT0X ABS_HAT1X
buttons: https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/input-event-codes.h#L385
sticks: ABS_X, ABS_Y, ABS_RX, ABS_RY
"""
EV_KEY = 0x01
EV_REL = 0x02
EV_ABS = 0x03
SPI_MSG_KEYBOARD_EVENT = 1
SPI_MSG_MOUSE_EVENT = 2
SPI_MSG_GAMEPAD_EVENT = 3
keyboard_spi_msg_header = [0xde, 0, SPI_MSG_KEYBOARD_EVENT, 0]
def raw_input_event_worker():
print("raw_input_event_parser_thread started")
to_delete = []
while 1:
for key in list(keyboard_opened_device_dict):
try:
data = keyboard_opened_device_dict[key][0].read(16)
except OSError:
keyboard_opened_device_dict[key][0].close()
del keyboard_opened_device_dict[key]
print("device disappeared:", key)
if data is None:
continue
data = list(data[8:])
if data[0] == EV_KEY:
to_transfer = keyboard_spi_msg_header + data + [0]*20
to_transfer[3] = keyboard_opened_device_dict[key][1]
spi.xfer(to_transfer)
print(time.time(), 'sent')
# print(key)
# print(to_transfer)
# print('----')
raw_input_event_parser_thread = threading.Thread(target=raw_input_event_worker, daemon=True)
raw_input_event_parser_thread.start()
input_device_path = '/dev/input/by-path/'
while 1:
try:
device_file_list = os.listdir(input_device_path)
except Exception as e:
print('list input device exception:', e)
time.sleep(0.75)
continue
mouse_list = [os.path.join(input_device_path, x) for x in device_file_list if 'event-mouse' in x]
keyboard_list = [os.path.join(input_device_path, x) for x in device_file_list if 'event-kbd' in x]
gamepad_list = [os.path.join(input_device_path, x) for x in device_file_list if 'event-joystick' in x]
# print(mouse_list)
# print(keyboard_list)
for item in keyboard_list:
if item not in keyboard_opened_device_dict:
try:
this_file = open(item, "rb")
os.set_blocking(this_file.fileno(), False)
kb_index = 0
try:
kb_index = sum([int(x) for x in item.split(':')[1].split('.')][:2])
except:
pass
keyboard_opened_device_dict[item] = (this_file, kb_index)
print("opened keyboard", keyboard_opened_device_dict[item][1], ':' , item)
except Exception as e:
print("keyboard open exception:", e)
continue
time.sleep(0.75)

View File

@@ -1,244 +0,0 @@
import os
import sys
import time
import select
import spidev
import threading
is_on_raspberry_pi = False
with open('/etc/os-release') as os_version_file:
is_on_raspberry_pi = 'raspbian' in os_version_file.read().lower()
spi = None
gpio_file = None
if is_on_raspberry_pi:
spi = spidev.SpiDev(0, 0) # rasp
print("I'm on Raspberry Pi!")
os.system("echo 16 > /sys/class/gpio/export")
os.system("echo in > /sys/class/gpio/gpio16/direction")
os.system("echo rising > /sys/class/gpio/gpio16/edge")
gpio_file = open("/sys/class/gpio/gpio16/value", 'rb')
print("GPIO init done")
else:
spi = spidev.SpiDev(0, 0) # lichee
print("I'm on custom board!")
print("DONT FORGET TO RUN gpio_setup.sh!")
gpio_file = open("/sys/class/gpio/gpio131/value", 'rb')
spi.max_speed_hz = 2000000
keyboard_opened_device_dict = {}
mouse_opened_device_dict = {}
gamepad_opened_device_dict = {}
epoll = select.epoll()
epoll.register(gpio_file, select.EPOLLET)
"""
def send kb
def send mouse
def send js
read data first, if exception, skip it
"""
"""
https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/input-event-codes.h#L38
xbox gamepad:
EVENT TYPE: EV_ABS
dpad: ABS_HAT0X ABS_HAT1X
buttons: https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/input-event-codes.h#L385
sticks: ABS_X, ABS_Y, ABS_RX, ABS_RY
"""
# https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
EV_SYN = 0
EV_KEY = 1
EV_REL = 2
EV_ABS = 3
SYN_REPORT = 0
REL_X = 0x00
REL_Y = 0x01
REL_WHEEL = 0x08
SPI_BUF_INDEX_MAGIC = 0
SPI_BUF_INDEX_SEQNUM = 1
SPI_BUF_INDEX_MSG_TYPE = 2
SPI_MOSI_MSG_KEYBOARD_EVENT = 1
SPI_MOSI_MSG_MOUSE_EVENT = 2
SPI_MOSI_MSG_GAMEPAD_EVENT = 3
SPI_MOSI_MSG_REQ_ACK = 4
SPI_MISO_MSG_INFO_REPLY = 0
SPI_MISO_MSG_KB_LED_REQ = 1
SPI_MOSI_MAGIC = 0xde
SPI_MISO_MAGIC = 0xcd
keyboard_spi_msg_header = [SPI_MOSI_MAGIC, 0, SPI_MOSI_MSG_KEYBOARD_EVENT, 0]
mouse_spi_msg_template = [SPI_MOSI_MAGIC, 0, SPI_MOSI_MSG_MOUSE_EVENT, 0] + [0]*28
def make_spi_msg_ack():
return [SPI_MOSI_MAGIC, 0, SPI_MOSI_MSG_REQ_ACK] + [0]*29
led_device_path = '/sys/class/leds'
def get_01(value):
if value:
return 1
return 0
def change_kb_led(ps2kb_led_byte):
led_file_list = os.listdir(led_device_path)
capslock_list = [os.path.join(led_device_path, x) for x in led_file_list if 'capslock' in x]
numlock_list = [os.path.join(led_device_path, x) for x in led_file_list if 'numlock' in x]
scrolllock_list = [os.path.join(led_device_path, x) for x in led_file_list if 'scrolllock' in x]
for item in scrolllock_list:
if is_on_raspberry_pi:
os.system(f"sudo bash -c 'echo {get_01(ps2kb_led_byte & 0x1)} > {os.path.join(item, 'brightness')}'")
else:
os.system(f"echo {get_01(ps2kb_led_byte & 0x1)} > {os.path.join(item, 'brightness')}")
for item in numlock_list:
if is_on_raspberry_pi:
os.system(f"sudo bash -c 'echo {get_01(ps2kb_led_byte & 0x2)} > {os.path.join(item, 'brightness')}'")
else:
os.system(f"echo {get_01(ps2kb_led_byte & 0x2)} > {os.path.join(item, 'brightness')}")
for item in capslock_list:
if is_on_raspberry_pi:
os.system(f"sudo bash -c 'echo {get_01(ps2kb_led_byte & 0x4)} > {os.path.join(item, 'brightness')}'")
else:
os.system(f"echo {get_01(ps2kb_led_byte & 0x4)} > {os.path.join(item, 'brightness')}")
def raw_input_event_worker():
mouse_spi_packet_dict = {}
mouse_button_state_list = [0] * 5
print("raw_input_event_parser_thread started")
while 1:
for key in list(keyboard_opened_device_dict):
try:
data = keyboard_opened_device_dict[key][0].read(16)
except OSError:
keyboard_opened_device_dict[key][0].close()
del keyboard_opened_device_dict[key]
print("keyboard disappeared:", key)
if data is None:
continue
data = list(data[8:])
if data[0] == EV_KEY:
to_transfer = keyboard_spi_msg_header + data + [0]*20
to_transfer[3] = keyboard_opened_device_dict[key][1]
spi.xfer(to_transfer)
for key in list(mouse_opened_device_dict):
try:
data = mouse_opened_device_dict[key][0].read(16)
except OSError:
mouse_opened_device_dict[key][0].close()
del mouse_opened_device_dict[key]
print("mouse disappeared:", key)
if data is None:
continue
data = list(data[8:])
# print(data)
if data[0] == EV_REL:
if data[2] == REL_X:
mouse_spi_packet_dict["x"] = data[4:6]
if data[2] == REL_Y:
mouse_spi_packet_dict["y"] = data[4:6]
if data[2] == REL_WHEEL:
mouse_spi_packet_dict["scroll"] = data[4:6]
if data[0] == EV_KEY:
mouse_button_state_list[data[2]-16] = data[4]
to_transfer = list(mouse_spi_msg_template)
to_transfer[10:13] = data[2:5]
to_transfer[13:18] = mouse_button_state_list[:]
to_transfer[3] = mouse_opened_device_dict[key][1]
spi.xfer(to_transfer)
if data[0] == EV_SYN and data[2] == SYN_REPORT and len(mouse_spi_packet_dict) > 0:
to_transfer = list(mouse_spi_msg_template)
if 'x' in mouse_spi_packet_dict:
to_transfer[4:6] = mouse_spi_packet_dict['x']
if 'y' in mouse_spi_packet_dict:
to_transfer[6:8] = mouse_spi_packet_dict['y']
if 'scroll' in mouse_spi_packet_dict:
to_transfer[8:10] = mouse_spi_packet_dict['scroll']
to_transfer[13:18] = mouse_button_state_list[:]
to_transfer[3] = mouse_opened_device_dict[key][1]
mouse_spi_packet_dict.clear()
spi.xfer(to_transfer)
events = epoll.poll(timeout=0)
for df, event_type in events:
if 0x8 & event_type:
slave_result = None
for x in range(2):
slave_result = spi.xfer(make_spi_msg_ack())
print(slave_result)
if slave_result[SPI_BUF_INDEX_MAGIC] == SPI_MISO_MAGIC and slave_result[SPI_BUF_INDEX_MSG_TYPE] == SPI_MISO_MSG_KB_LED_REQ:
change_kb_led(slave_result[3])
change_kb_led(slave_result[3])
raw_input_event_parser_thread = threading.Thread(target=raw_input_event_worker, daemon=True)
raw_input_event_parser_thread.start()
input_device_path = '/dev/input/by-path/'
while 1:
try:
device_file_list = os.listdir(input_device_path)
except Exception as e:
print('list input device exception:', e)
time.sleep(0.75)
continue
mouse_list = [os.path.join(input_device_path, x) for x in device_file_list if 'event-mouse' in x]
keyboard_list = [os.path.join(input_device_path, x) for x in device_file_list if 'event-kbd' in x]
gamepad_list = [os.path.join(input_device_path, x) for x in device_file_list if 'event-joystick' in x]
# print(mouse_list)
# print(keyboard_list)
for item in keyboard_list:
if item not in keyboard_opened_device_dict:
try:
this_file = open(item, "rb")
os.set_blocking(this_file.fileno(), False)
device_index = 0
try:
device_index = sum([int(x) for x in item.split(':')[1].split('.')][:2])
except:
pass
keyboard_opened_device_dict[item] = (this_file, device_index)
print("opened keyboard", keyboard_opened_device_dict[item][1], ':' , item)
except Exception as e:
print("keyboard open exception:", e)
continue
for item in mouse_list:
if item not in mouse_opened_device_dict:
try:
this_file = open(item, "rb")
os.set_blocking(this_file.fileno(), False)
device_index = 0
try:
device_index = sum([int(x) for x in item.split(':')[1].split('.')][:2])
except:
pass
mouse_opened_device_dict[item] = (this_file, device_index)
print("opened mouse", mouse_opened_device_dict[item][1], ':' , item)
except Exception as e:
print("mouse open exception:", e)
continue
time.sleep(0.75)

View File

@@ -1,29 +0,0 @@
import os
dev_path = '/proc/bus/input/devices'
if 'nt' in os.name:
dev_path = 'devices.txt'
dev_file = open(dev_path)
file_content = dev_file.readlines()
dev_file.close()
current_line_num = 0
max_lines = len(file_content)
while current_line_num < max_lines:
this_line = file_content[current_line_num]
if this_line.startswith('I: '):
print("-------- New block! --------")
while len(this_line) != 1:
current_line_num += 1
if current_line_num >= max_lines:
print("-------- EOF --------")
break
this_line = file_content[current_line_num]
print(this_line)
print("-------- Block end --------")
current_line_num += 1

View File

@@ -1,30 +0,0 @@
import sys
import spidev
import time
is_on_raspberry_pi = False
with open('/etc/os-release') as os_version_file:
is_on_raspberry_pi = 'raspbian' in os_version_file.read().lower()
spi = None
if is_on_raspberry_pi:
spi = spidev.SpiDev(0, 0) # rasp
print("I'm on Raspberry Pi!")
else:
spi = spidev.SpiDev(1, 0) # lichee
print("I'm on custom board!")
spi.max_speed_hz = 2000000
EV_SYN = 0
EV_KEY = 1
EV_REL = 2
EV_ABS = 3
fff = open(sys.argv[1], "rb" )
while 1:
data = list(fff.read(16))
print(data)

View File

@@ -1,53 +0,0 @@
# import sys
import time
import queue
import spidev
import threading
is_on_raspberry_pi = False
with open('/etc/os-release') as os_version_file:
is_on_raspberry_pi = 'raspbian' in os_version_file.read().lower()
spi = None
if is_on_raspberry_pi:
spi = spidev.SpiDev(0, 0) # rasp
print("I'm on Raspberry Pi!")
else:
spi = spidev.SpiDev(1, 0) # lichee
print("I'm on custom board!")
spi.max_speed_hz = 500000
MAX_SPI_QUEUE_SIZE = 32
spi_out_queue = queue.Queue(maxsize=MAX_SPI_QUEUE_SIZE)
# sys.setswitchinterval(0.005)
fff = open("/dev/input/event0", "rb" )
def keyboard_worker():
print("keyboard_thread started")
while 1:
data = fff.read(24)
data = list(data)
try:
spi_out_queue.put(data, block=False)
except Exception:
continue
def spi_worker():
print("spi_thread started")
while 1:
spi.xfer(spi_out_queue.get())
# print("sent")
keyboard_thread = threading.Thread(target=keyboard_worker, daemon=True)
keyboard_thread.start()
spi_thread = threading.Thread(target=spi_worker, daemon=True)
spi_thread.start()
while 1:
# print("main loop")
time.sleep(1)

View File

@@ -1,2 +0,0 @@
import sys
import time

View File

@@ -1,53 +0,0 @@
# https://luma-oled.readthedocs.io/en/latest/software.html
import os
import sys
import time
from demo_opts import get_device
from luma.core.render import canvas
from PIL import ImageFont
import json
OLED_WIDTH = 128
OLED_HEIGHT = 32
my_arg = ['--display', 'ssd1306', '--interface', 'spi', '--spi-port', '0', '--spi-device', '1', '--gpio-reset', '6', '--gpio-data-command', '5', '--width', str(OLED_WIDTH), '--height', str(OLED_HEIGHT), '--spi-bus-speed', '2000000']
oled_device = get_device(my_arg)
font_regular = ImageFont.truetype("ProggyTiny.ttf", 16)
font_medium = ImageFont.truetype("ChiKareGo2.ttf", 16)
font_large = ImageFont.truetype("ProggyTiny.ttf", 32)
max_char_per_line = {font_regular:21, font_medium:17, font_large:11}
width_per_char = {font_regular:6, font_medium:7, font_large:12}
def oled_print_centered(text, font, y, this_canvas):
text = text.strip()[:max_char_per_line[font]]
start_x = int((OLED_WIDTH - (len(text) * width_per_char[font]))/2)
if start_x < 0:
start_x = 0
this_canvas.text((start_x, y), text, font=font, fill="white")
curve_vertial_axis_x_pos = 80
curve_horizontal_axis_width = 32
linear_curve = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12, 13: 13, 14: 14, 15: 15, 16: 16, 17: 17, 18: 18, 19: 19, 20: 20, 21: 21, 22: 22, 23: 23, 24: 24, 25: 25, 26: 26, 27: 27, 28: 28, 29: 29, 30: 30, 31: 31, 32: 32, 33: 33, 34: 34, 35: 35, 36: 36, 37: 37, 38: 38, 39: 39, 40: 40, 41: 41, 42: 42, 43: 43, 44: 44, 45: 45, 46: 46, 47: 47, 48: 48, 49: 49, 50: 50, 51: 51, 52: 52, 53: 53, 54: 54, 55: 55, 56: 56, 57: 57, 58: 58, 59: 59, 60: 60, 61: 61, 62: 62, 63: 63, 64: 64, 65: 65, 66: 66, 67: 67, 68: 68, 69: 69, 70: 70, 71: 71, 72: 72, 73: 73, 74: 74, 75: 75, 76: 76, 77: 77, 78: 78, 79: 79, 80: 80, 81: 81, 82: 82, 83: 83, 84: 84, 85: 85, 86: 86, 87: 87, 88: 88, 89: 89, 90: 90, 91: 91, 92: 92, 93: 93, 94: 94, 95: 95, 96: 96, 97: 97, 98: 98, 99: 99, 100: 100, 101: 101, 102: 102, 103: 103, 104: 104, 105: 105, 106: 106, 107: 107, 108: 108, 109: 109, 110: 110, 111: 111, 112: 112, 113: 113, 114: 114, 115: 115, 116: 116, 117: 117, 118: 118, 119: 119, 120: 120, 121: 121, 122: 122, 123: 123, 124: 124, 125: 125, 126: 126, 127: 127}
mid_curve = {0: 1, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1, 9: 2, 10: 2, 11: 2, 12: 2, 13: 2, 14: 3, 15: 3, 16: 3, 17: 3, 18: 3, 19: 4, 20: 4, 21: 4, 22: 4, 23: 5, 24: 5, 25: 5, 26: 5, 27: 6, 28: 6, 29: 6, 30: 6, 31: 7, 32: 7, 33: 7, 34: 8, 35: 8, 36: 8, 37: 9, 38: 9, 39: 9, 40: 10, 41: 10, 42: 10, 43: 11, 44: 11, 45: 12, 46: 12, 47: 12, 48: 13, 49: 13, 50: 14, 51: 14, 52: 14, 53: 15, 54: 15, 55: 16, 56: 16, 57: 17, 58: 17, 59: 18, 60: 18, 61: 19, 62: 20, 63: 20, 64: 21, 65: 21, 66: 22, 67: 23, 68: 23, 69: 24, 70: 25, 71: 25, 72: 26, 73: 27, 74: 28, 75: 29, 76: 30, 77: 31, 78: 32, 79: 33, 80: 34, 81: 35, 82: 36, 83: 37, 84: 38, 85: 39, 86: 40, 87: 42, 88: 43, 89: 44, 90: 45, 91: 47, 92: 48, 93: 50, 94: 51, 95: 52, 96: 54, 97: 56, 98: 57, 99: 59, 100: 60, 101: 62, 102: 64, 103: 66, 104: 67, 105: 69, 106: 71, 107: 73, 108: 75, 109: 77, 110: 79, 111: 81, 112: 83, 113: 86, 114: 88, 115: 90, 116: 93, 117: 95, 118: 98, 119: 101, 120: 103, 121: 106, 122: 110, 123: 112, 124: 116, 125: 119, 126: 122, 127: 126}
curve3 = {0: 1, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1, 9: 1, 10: 1, 11: 1, 12: 1, 13: 1, 14: 1, 15: 1, 16: 1, 17: 1, 18: 2, 19: 2, 20: 2, 21: 2, 22: 2, 23: 2, 24: 2, 25: 2, 26: 2, 27: 3, 28: 3, 29: 3, 30: 3, 31: 3, 32: 3, 33: 4, 34: 4, 35: 4, 36: 4, 37: 4, 38: 5, 39: 5, 40: 5, 41: 5, 42: 5, 43: 6, 44: 6, 45: 6, 46: 6, 47: 7, 48: 7, 49: 7, 50: 8, 51: 8, 52: 8, 53: 8, 54: 9, 55: 9, 56: 10, 57: 10, 58: 10, 59: 11, 60: 11, 61: 11, 62: 12, 63: 12, 64: 13, 65: 13, 66: 14, 67: 14, 68: 15, 69: 15, 70: 16, 71: 16, 72: 17, 73: 17, 74: 18, 75: 19, 76: 19, 77: 20, 78: 21, 79: 22, 80: 23, 81: 23, 82: 24, 83: 25, 84: 26, 85: 27, 86: 29, 87: 30, 88: 31, 89: 32, 90: 33, 91: 34, 92: 36, 93: 37, 94: 38, 95: 40, 96: 41, 97: 43, 98: 44, 99: 46, 100: 48, 101: 49, 102: 51, 103: 53, 104: 55, 105: 57, 106: 59, 107: 61, 108: 63, 109: 65, 110: 67, 111: 69, 112: 72, 113: 74, 114: 77, 115: 79, 116: 82, 117: 85, 118: 88, 119: 92, 120: 94, 121: 99, 122: 101, 123: 105, 124: 110, 125: 114, 126: 118, 127: 126}
joystick_curve_list = [linear_curve, mid_curve, curve3]
with canvas(oled_device) as draw:
draw.text((0, 0), "Joystick", font=font_medium, fill="white")
draw.text((0, 15), "Curve", font=font_medium, fill="white")
draw.line((curve_vertial_axis_x_pos, 0, curve_vertial_axis_x_pos, curve_vertial_axis_x_pos), fill="white")
draw.line((curve_vertial_axis_x_pos, 31, curve_vertial_axis_x_pos+curve_horizontal_axis_width, 31), fill="white")
for xxx in range(curve_horizontal_axis_width):
dict_key = xxx*4
this_point_x = xxx + curve_vertial_axis_x_pos
this_point_y = OLED_HEIGHT - linear_curve[dict_key]//4 - 1
print(this_point_x, this_point_y)
draw.line((this_point_x,this_point_y,this_point_x,this_point_y), fill="white")
while 1:
time.sleep(1)

View File

@@ -1,96 +0,0 @@
import os
import sys
import time
import serial
import subprocess
import base64
import threading
import usb4vc_shared
# import usb4vc_usb_scan
# import usb4vc_ui
ser = None
try:
ser = serial.Serial('/dev/serial0', 115200)
except Exception as e:
print("SERIAL OPEN EXCEPTION:", e)
def uart_worker():
if ser is None:
return
while 1:
received = ser.readline().decode().replace('\r', '').replace('\n', '')
# print("I received:", received)
line_split = received.split(' ', maxsplit=2)
if len(line_split) < 2:
continue
magic = line_split[0]
cmd_type = line_split[1]
payload = line_split[-1]
if magic != 'U4':
continue
if cmd_type == "QUIT":
exit()
# read file
if cmd_type == 'RF':
file_path = line_split[-1].strip()
content = None
try:
with open(file_path, 'rb') as myfile:
content = myfile.read()
except Exception as e:
ser.write(f"U4 ERR {e}\n".encode('utf-8'))
continue
base64_bytes = base64.standard_b64encode(content)
base64_message = base64_bytes.decode('utf-8')
ser.write(f"U4 OK {base64_message}\n".encode('utf-8'))
# write file
if cmd_type == 'WF':
wf_args = payload.split(' ', maxsplit=2)
if len(wf_args) < 2:
ser.write("U4 ERR missing file content\n".encode('utf-8'))
continue
file_path = wf_args[0].strip()
base64_message = wf_args[1].strip()
try:
base64_bytes = base64.standard_b64decode(base64_message)
with open(file_path, 'wb') as myfile:
myfile.write(base64_bytes)
ser.write("U4 OK\n".encode('utf-8'))
except Exception as e:
ser.write(f"U4 ERR {e}\n".encode('utf-8'))
continue
# delete file
if cmd_type == 'DF':
file_path = line_split[-1].strip()
try:
os.remove(file_path)
except Exception as e:
ser.write(f"U4 ERR {e}\n".encode('utf-8'))
continue
ser.write("U4 OK\n".encode('utf-8'))
if cmd_type == 'SC':
try:
shell_result = subprocess.getoutput(payload).strip()
base64_bytes = base64.standard_b64encode(shell_result.encode('utf-8'))
base64_message = base64_bytes.decode('utf-8')
ser.write(f"U4 OK {base64_message}\n".encode('utf-8'))
except Exception as e:
ser.write(f"U4 ERR {e}\n".encode('utf-8'))
continue
if cmd_type == 'INFO':
try:
ser.write(f"U4 OK USB4VC RPi App v{usb4vc_shared.RPI_APP_VERSION_TUPLE[0]}.{usb4vc_shared.RPI_APP_VERSION_TUPLE[1]}.{usb4vc_shared.RPI_APP_VERSION_TUPLE[2]} dekuNukem 2022\n".encode('utf-8'))
except Exception as e:
ser.write(f"U4 ERR {e}\n".encode('utf-8'))
continue
uart_thread = threading.Thread(target=uart_worker, daemon=True)

View File

@@ -108,25 +108,116 @@ PID_GENERIC_GAMEPORT_GAMEPAD = 7
PID_BBC_MICRO_JOYSTICK = 14
PID_RAW_USB_GAMEPAD = 127
devices = [evdev.InputDevice(path) for path in evdev.list_devices()]
# devices = [evdev.InputDevice(path) for path in evdev.list_devices()]
for device in devices:
print(device.path, device.name, device.phys)
# for device in devices:
# print(device.path, device.name, device.phys)
# import asyncio, evdev
# mouse = evdev.InputDevice('/dev/input/event0')
# keybd = evdev.InputDevice('/dev/input/event6')
# mouse = evdev.InputDevice('/dev/input/event4')
# keybd = evdev.InputDevice('/dev/input/event1')
# async def print_events(device):
# async for event in device.async_read_loop():
# empty = list(keyboard_event_spi_msg_template)
# xfer_when_not_busy(empty)
# # empty = list(keyboard_event_spi_msg_template)
# # xfer_when_not_busy(empty)
# print(device.path, evdev.categorize(event), sep=': ')
# for device in mouse, keybd:
# asyncio.ensure_future(print_events(device))
# loop = asyncio.get_event_loop()
# loop.run_forever()
# loop.run_forever()
import asyncio
import evdev
from evdev import categorize
POLL_INTERVAL_SEC = 1.0 # how often we rescan for devices
async def read_device_events(path: str):
"""
Open a single device and print its events until it goes away
(or this task is cancelled).
"""
dev = None
try:
dev = evdev.InputDevice(path)
# Announce the device
print(f"[attach] {path} — name='{dev.name}' phys='{dev.phys}'")
# Async loop over input events
async for event in dev.async_read_loop():
# Skip non-value events if you want; here we show everything
print(f"!!!!!!!!!!!!!!! {path}: {categorize(event)}")
empty = list(keyboard_event_spi_msg_template)
xfer_when_not_busy(empty)
except (FileNotFoundError, OSError) as e:
# Common when the device is unplugged (e.g. [Errno 19] No such device)
print(f"[disconnect] {path}: {e}")
except asyncio.CancelledError:
# We were asked to stop (e.g. device disappeared or program exiting)
raise
finally:
if dev is not None:
try:
dev.close()
except Exception:
pass
ignored_hid_device_name = ['pwr_button', 'hdmi', 'motion']
def is_ignored_device(dev_path):
dev_name = evdev.InputDevice(dev_path).name.lower()
for item in ignored_hid_device_name:
if item.lower() in dev_name:
return True
return False
async def watch_all_devices():
"""
Periodically rescan /dev/input for devices, starting and stopping
per-device reader tasks as paths appear/disappear.
"""
tasks: dict[str, asyncio.Task] = {}
known_paths: set[str] = set()
while True:
try:
current_paths = set([x for x in evdev.list_devices() if is_ignored_device(x) is False])
except Exception as e:
# Very rare, but if listing fails, keep previous state and retry
print(f"[warn] list_devices failed: {e}")
current_paths = known_paths
# New devices -> start a reader task
for path in current_paths - known_paths:
tasks[path] = asyncio.create_task(read_device_events(path))
# Removed devices -> cancel the reader task (if still running)
for path in known_paths - current_paths:
print(f"[detach] {path}")
task = tasks.pop(path, None)
if task is not None and not task.done():
task.cancel()
known_paths = current_paths
await asyncio.sleep(POLL_INTERVAL_SEC)
async def main():
# Kick off the watcher; it will create per-device reader tasks
watcher = asyncio.create_task(watch_all_devices())
try:
await watcher
except asyncio.CancelledError:
pass
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\n[exit] keyboard interrupt")

View File

@@ -84,7 +84,7 @@ usb4vc_ui.ui_init()
usb4vc_ui.ui_thread.start()
usb4vc_usb_scan.usb_device_scan_thread.start()
usb4vc_usb_scan.raw_input_event_parser_thread.start()
# usb4vc_usb_scan.raw_input_event_parser_thread.start()
while 1:
time.sleep(2)

View File

@@ -35,8 +35,6 @@ GPIO.setup(PCARD_BUSY_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
pcard_spi = spidev.SpiDev(0, 0)
pcard_spi.max_speed_hz = 2000000
opened_device_dict = {}
led_device_path = '/sys/class/leds'
input_device_path = '/dev/input/by-path/'
@@ -741,137 +739,6 @@ def multiply_round_up_0(number, multi):
new_number = -1
return int(new_number)
USB_GAMEPAD_STICK_AXES_NAMES = ["ABS_X", "ABS_Y", "ABS_RX", "ABS_RY"]
gamepad_status_dict = {}
gamepad_hold_check_interval = 0.02
def raw_input_event_worker():
last_usb_event = 0
mouse_status_dict = {'x': [0, 0], 'y': [0, 0], 'scroll': 0, 'hscroll': 0, BTN_LEFT:0, BTN_RIGHT:0, BTN_MIDDLE:0, BTN_SIDE:0, BTN_EXTRA:0, BTN_FORWARD:0, BTN_BACK:0, BTN_TASK:0}
next_gamepad_hold_check = time.time() + gamepad_hold_check_interval
last_mouse_msg = []
last_gamepad_msg = None
last_mouse_button_msg = None
print("raw_input_event_worker started")
while 1:
now = time.time()
if now > next_gamepad_hold_check:
joystick_hold_update()
next_gamepad_hold_check = now + gamepad_hold_check_interval
# give other threads some breathing room if
# no USB input events
if now - last_usb_event > 1:
time.sleep(0.005)
for key in list(opened_device_dict):
this_device = opened_device_dict[key]
this_id = this_device['id']
try:
data = this_device['file'].read(16)
except OSError:
print("Device disappeared:", this_device['name'])
this_device['file'].close()
del opened_device_dict[key]
continue
if data is None:
continue
usb4vc_ui.my_oled.kick()
last_usb_event = now
if this_device['is_gp'] and this_id not in gamepad_status_dict:
gamepad_status_dict[this_id] = {}
data = list(data[8:])
event_code = data[3] * 256 + data[2]
# event is a key press
if data[0] == EV_KEY:
# keyboard keys
if 0x1 <= event_code <= 248 and event_code not in gamepad_buttons_as_kb_codes:
xfer_when_not_busy(make_keyboard_spi_packet(data, this_id))
# Mouse buttons
elif 0x110 <= event_code <= 0x117:
mouse_status_dict[event_code] = data[4]
next_gamepad_hold_check = now + gamepad_hold_check_interval
if data[4] != 2:
clear_mouse_movement(mouse_status_dict)
last_mouse_button_msg = make_mouse_spi_packet(mouse_status_dict, this_id)
xfer_when_not_busy(list(last_mouse_button_msg))
# Gamepad buttons
elif is_gamepad_button(event_code) or event_code in gamepad_buttons_as_kb_codes:
this_btn_status = data[4]
if this_btn_status != 0:
this_btn_status = 1
gamepad_status_dict[this_id][event_code] = this_btn_status
# event is relative axes AKA mouse
elif data[0] == EV_REL and event_code == REL_X:
rawx = int.from_bytes(data[4:6], byteorder='little', signed=True)
rawx = multiply_round_up_0(rawx, usb4vc_ui.get_mouse_sensitivity()) & 0xffff
mouse_status_dict["x"] = list(rawx.to_bytes(2, byteorder='little'))
elif data[0] == EV_REL and event_code == REL_Y:
rawy = int.from_bytes(data[4:6], byteorder='little', signed=True)
rawy = multiply_round_up_0(rawy, usb4vc_ui.get_mouse_sensitivity()) & 0xffff
mouse_status_dict["y"] = list(rawy.to_bytes(2, byteorder='little'))
elif data[0] == EV_REL and event_code == REL_WHEEL:
mouse_status_dict['scroll'] = data[4]
elif data[0] == EV_REL and event_code == REL_HWHEEL:
mouse_status_dict['hscroll'] = data[4]
# event is absolute axes AKA joystick
elif this_device['is_gp'] and data[0] == EV_ABS:
abs_value = int.from_bytes(data[4:8], byteorder='little', signed=True)
abs_value_midpoint127 = convert_to_8bit_midpoint127(abs_value, this_device['axes_info'], event_code)
gamepad_status_dict[this_id][event_code] = abs_value_midpoint127
# SYNC event
elif data[0] == EV_SYN and event_code == SYN_REPORT:
if this_device['is_mouse']:
this_mouse_msg = make_mouse_spi_packet(mouse_status_dict, this_id)
if this_mouse_msg == last_mouse_button_msg:
pass
# send spi mouse message if there is moment, or the button is not typematic
elif (max(this_mouse_msg[13:18]) != 2 or sum(this_mouse_msg[4:10]) != 0) and (this_mouse_msg[4:] != last_mouse_msg[4:] or sum(this_mouse_msg[4:]) != 0):
xfer_when_not_busy(list(this_mouse_msg))
next_gamepad_hold_check = now + gamepad_hold_check_interval
clear_mouse_movement(mouse_status_dict)
last_mouse_msg = list(this_mouse_msg)
if this_device['is_gp']:
for axis_name in USB_GAMEPAD_STICK_AXES_NAMES:
axis_code = code_name_to_value_lookup.get(axis_name)[0]
this_gp_dict = gamepad_status_dict[this_device['id']]
if axis_code in this_gp_dict and 127 - 10 <= this_gp_dict[axis_code] <= 127 + 10:
this_gp_dict[axis_code] = 127
gamepad_output = make_gamepad_spi_packet(gamepad_status_dict, this_device)
if gamepad_output != last_gamepad_msg:
# print(gamepad_output)
gp_to_transfer, kb_to_transfer, mouse_to_transfer = gamepad_output
xfer_when_not_busy(list(gp_to_transfer))
if kb_to_transfer is not None:
time.sleep(0.001)
xfer_when_not_busy(list(kb_to_transfer))
if mouse_to_transfer is not None:
time.sleep(0.001)
xfer_when_not_busy(list(mouse_to_transfer))
next_gamepad_hold_check = now + gamepad_hold_check_interval
last_gamepad_msg = gamepad_output
# ----------------- PBOARD INTERRUPT -----------------
if GPIO.event_detected(SLAVE_REQ_PIN):
# send out ACK to turn off P-Card interrupt
slave_result = xfer_when_not_busy(make_spi_msg_ack())
time.sleep(0.001)
# send another to shift response into RPi
slave_result = xfer_when_not_busy(make_spi_msg_ack())
print(int(time.time()), slave_result)
if slave_result[SPI_BUF_INDEX_MAGIC] == SPI_MISO_MAGIC and slave_result[SPI_BUF_INDEX_MSG_TYPE] == SPI_MISO_MSG_TYPE_KB_LED_REQUEST:
try:
change_kb_led(slave_result[3], slave_result[4], slave_result[5])
change_kb_led(slave_result[3], slave_result[4], slave_result[5])
except Exception as e:
print('exception change_kb_led:', e)
def check_is_gamepad(capability_dict):
keys_and_buttons = capability_dict.get(('EV_KEY', 1))
@@ -888,6 +755,12 @@ def check_is_gamepad(capability_dict):
return True
return False
def get_device_count():
mouse_count = 69
kb_count = 69
gp_count = 69
return (mouse_count, kb_count, gp_count)
def get_input_devices():
result = []
available_devices = [evdev.InputDevice(path) for path in evdev.list_devices()]
@@ -922,49 +795,16 @@ def get_input_devices():
result.append(dev_dict)
return result
def get_device_count():
mouse_count = 0
kb_count = 0
gp_count = 0
for key in opened_device_dict:
if opened_device_dict[key]['is_mouse']:
mouse_count += 1
elif opened_device_dict[key]['is_kb']:
kb_count += 1
elif opened_device_dict[key]['is_gp']:
gp_count += 1
return (mouse_count, kb_count, gp_count)
def usb_device_scan_worker():
print("usb_device_scan_worker started")
while 1:
time.sleep(0.75)
try:
device_list = get_input_devices()
except Exception as e:
print('exception get_input_devices:', e)
continue
if len(device_list) == 0:
print('No input devices found')
continue
wwwww = get_input_devices()
for item in wwwww:
print(item)
print("-----------------")
for item in device_list:
if item['path'] in opened_device_dict:
continue
try:
this_file = open(item['path'], "rb")
os.set_blocking(this_file.fileno(), False)
item['file'] = this_file
try:
item['id'] = int(item['path'][len(item['path'].rstrip('0123456789')):])
except:
item['id'] = 255
opened_device_dict[item['path']] = item
print("opened device:", hex(item['vendor_id']), hex(item['product_id']), item['name'])
except Exception as e:
print("exception Device open:", e, item)
raw_input_event_parser_thread = threading.Thread(target=raw_input_event_worker, daemon=True)
# raw_input_event_parser_thread = threading.Thread(target=raw_input_event_worker, daemon=True)
usb_device_scan_thread = threading.Thread(target=usb_device_scan_worker, daemon=True)
def get_pboard_info():