switch to pi pico code
This commit is contained in:
parent
95e26968f7
commit
d630d4c08e
28
README.md
28
README.md
|
@ -1,27 +1,5 @@
|
||||||
# Button Buddy
|
## Button Buddy
|
||||||
|
|
||||||
## Goal
|
This is the code I run on my 3x3 macro-pad. The main reason I built it is to provide mouse click buttons next to my [Ploopy Nano](https://ploopy.co/nano-trackball/). I use the [maddie](https://github.com/qmk/qmk_firmware/tree/e7931289918221081cbe2a7ea5df27a5d86324db/keyboards/ploopyco/trackball_nano/keymaps/maddie) keymap which includes code that turns the Ploopy into a scroll wheel when num-lock is toggled twice in 25ms so a couple of the buttons are mapped to that (one hold-to-scroll button and a toggle scroll-mode button).
|
||||||
|
|
||||||
A hand-wired macro-pad using a Raspberry Pi Zero, cherry-style switches, and a 3D printed case.
|
I 3D-printed the macropad using [this model](https://www.thingiverse.com/thing:4816077), used some left over Kailh midnight jade switches left over from other keyboard projects, hand-wired to a Raspberry Pi Pico. The switches are wired to GPIO pins 0 through 8 with 0-2 across the top row, 3-5 across the middle row, and 6-8 across the bottom.
|
||||||
|
|
||||||
## Why?
|
|
||||||
|
|
||||||
I've got a spare Pi Zero, a bunch of spare kailh box jade switches and keycaps, and a 3D printer, and I want a little macropad that I can use for (among other things) mouse buttons next to my Ploopy Nano.
|
|
||||||
|
|
||||||
## How?
|
|
||||||
|
|
||||||
Case and switch plate will be rendered using OpenSCAD, probably 2 rows of 3 (right, left, middle click, a scroll-mode toggle, and two extra buttons maybe for copy/paste macros or whatever else I decide is more useful).
|
|
||||||
|
|
||||||
The Pi Zero will be programmed with gpiozero I guess? That's the part I'm least familiar with.
|
|
||||||
|
|
||||||
## Concerns
|
|
||||||
|
|
||||||
The lamest things are than my Pi Zero is the model with no built-in storage, so it'll have to use one of my spare SD cards too. It's wi-fi though so maybe it can serve a dual purpose as a controller for the macropad as well as some kind of server. Or maybe if I get super ambitious I can throw a LiPo in there and make the whole thing wireless, sending its events to some kind of daemon on my computer. Probably not. I dunno. Since it's a Zero and not a Pico or some other microcontroller it's going to have to boot up every time the power is interrupted which takes a minute, which is kind of lame, but I'll be using it on my desktop machine which also has to boot up so that's NBD.
|
|
||||||
|
|
||||||
## Resources
|
|
||||||
|
|
||||||
- [Turn Your Raspberry Pi Zero into a USB Keyboard (HID)](https://randomnerdtutorials.com/raspberry-pi-zero-usb-keyboard-hid/)
|
|
||||||
- [USB Keyboard Emulation with the Raspberry Pi Zero](https://www.makerhacks.com/usb-keyboard-emulation-with-the-raspberry-pi-zero/)
|
|
||||||
- [Getting started with gpiozero](https://dronebotworkshop.com/raspberry-pi-gpio/)
|
|
||||||
|
|
||||||
![Rasberry Pi Zero Pinout Diagram](https://tutorials-raspberrypi.de/wp-content/uploads/Raspbery-Pi-GPIO-Pin-Belegung.png)
|
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
import time
|
||||||
|
import board
|
||||||
|
from digitalio import DigitalInOut, Direction, Pull
|
||||||
|
import usb_hid
|
||||||
|
from adafruit_hid.keyboard import Keyboard
|
||||||
|
from adafruit_hid.keycode import Keycode
|
||||||
|
from adafruit_hid.mouse import Mouse
|
||||||
|
from adafruit_hid.consumer_control import ConsumerControl
|
||||||
|
|
||||||
|
led = DigitalInOut(board.LED)
|
||||||
|
led.direction = Direction.OUTPUT
|
||||||
|
led.value = True
|
||||||
|
|
||||||
|
kbd = Keyboard(usb_hid.devices)
|
||||||
|
mse = Mouse(usb_hid.devices)
|
||||||
|
ctl = ConsumerControl(usb_hid.devices)
|
||||||
|
|
||||||
|
pins = [
|
||||||
|
board.GP0, # 0 1 2
|
||||||
|
board.GP1, # 3 4 5
|
||||||
|
board.GP2, # 6 7 8
|
||||||
|
board.GP3,
|
||||||
|
board.GP4,
|
||||||
|
board.GP5,
|
||||||
|
board.GP6,
|
||||||
|
board.GP7,
|
||||||
|
board.GP8,
|
||||||
|
]
|
||||||
|
|
||||||
|
# toggles scroll mode in ploopy nano using maddie layout
|
||||||
|
def toggle_scroll():
|
||||||
|
kbd.press(Keycode.KEYPAD_NUMLOCK)
|
||||||
|
kbd.release(Keycode.KEYPAD_NUMLOCK)
|
||||||
|
kbd.press(Keycode.KEYPAD_NUMLOCK)
|
||||||
|
kbd.release(Keycode.KEYPAD_NUMLOCK)
|
||||||
|
|
||||||
|
def press(key):
|
||||||
|
if key == 0:
|
||||||
|
kbd.press(Keycode.F13)
|
||||||
|
elif key == 1:
|
||||||
|
kbd.press(Keycode.F14)
|
||||||
|
elif key == 2:
|
||||||
|
mse.press(Mouse.MIDDLE_BUTTON)
|
||||||
|
elif key == 3:
|
||||||
|
ctl.send(0x224) # back
|
||||||
|
elif key == 4:
|
||||||
|
ctl.send(0x225) # back
|
||||||
|
elif key == 5:
|
||||||
|
mse.press(Mouse.RIGHT_BUTTON)
|
||||||
|
elif key == 6: # sticky scroll mode
|
||||||
|
toggle_scroll()
|
||||||
|
elif key == 7: # press and hold scroll mode
|
||||||
|
toggle_scroll()
|
||||||
|
elif key == 8:
|
||||||
|
mse.press(Mouse.LEFT_BUTTON)
|
||||||
|
|
||||||
|
def release(key):
|
||||||
|
if key == 0:
|
||||||
|
kbd.release(Keycode.F13)
|
||||||
|
elif key == 1:
|
||||||
|
kbd.release(Keycode.F14)
|
||||||
|
elif key == 2:
|
||||||
|
mse.release(Mouse.MIDDLE_BUTTON)
|
||||||
|
elif key == 5:
|
||||||
|
mse.release(Mouse.RIGHT_BUTTON)
|
||||||
|
elif key == 7:
|
||||||
|
toggle_scroll()
|
||||||
|
elif key == 8:
|
||||||
|
mse.release(Mouse.LEFT_BUTTON)
|
||||||
|
|
||||||
|
switches = [0, 1, 2, 3, 4, 5, 6, 7, 8]
|
||||||
|
|
||||||
|
for i in range(9):
|
||||||
|
switches[i] = DigitalInOut(pins[i])
|
||||||
|
switches[i].direction = Direction.INPUT
|
||||||
|
switches[i].pull = Pull.UP
|
||||||
|
|
||||||
|
switch_state = [0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
|
||||||
|
while True:
|
||||||
|
for button in range(9):
|
||||||
|
if switch_state[button] == 0:
|
||||||
|
if not switches[button].value:
|
||||||
|
try:
|
||||||
|
press(button)
|
||||||
|
except ValueError: # deals w six key limit
|
||||||
|
pass
|
||||||
|
switch_state[button] = 1
|
||||||
|
|
||||||
|
if switch_state[button] == 1:
|
||||||
|
if switches[button].value:
|
||||||
|
try:
|
||||||
|
release(button)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
switch_state[button] = 0
|
||||||
|
|
||||||
|
time.sleep(0.01) # debounce
|
|
@ -1,32 +0,0 @@
|
||||||
# 2022-03-06 Initial HID Test
|
|
||||||
|
|
||||||
Found a _really_ old 16gb SD card and loaded Raspbian up on it, then followed a guide to enable wifi and ssh on it before throwing it in the Pi Zero and plugging it in. After a few minutes I was able to ssh in.
|
|
||||||
|
|
||||||
I followed a guide to enable it as a HID device, which involves adding this to `/boot/config.txt`:
|
|
||||||
|
|
||||||
```
|
|
||||||
dtoverlay=dwc2
|
|
||||||
```
|
|
||||||
|
|
||||||
And adding this to `/etc/modules`:
|
|
||||||
|
|
||||||
```
|
|
||||||
dwc2
|
|
||||||
libcomposite
|
|
||||||
```
|
|
||||||
|
|
||||||
Then I created the `/raspi_config/hid_usb` script that's in this repo at `/usr/bin/hid_usb` and updated `/etc/rc.local` to execute it at boot time.
|
|
||||||
|
|
||||||
After a reboot, the Pi showed up as a usb device when running `lsusb` on the computer it's plugged into:
|
|
||||||
|
|
||||||
```
|
|
||||||
Bus 005 Device 008: ID 1d6b:0104 Linux Foundation Multifunction Composite Gadget
|
|
||||||
```
|
|
||||||
|
|
||||||
I created the `/test_scripts/test1.py` script on the Pi and ran it as root, then used a paperclip to alternately connect GPIO 26 and GPIO 16 with ground, and observed it printing characters on the host computer. 26 printed `a` over and over until I broke the connection, and 16 printed `B`. Success!
|
|
||||||
|
|
||||||
Looking at the pin-out, there are enough GPIO inputs to support well over 6 or 9 buttons directly hand-wired, so I think that's all I need to do. I guess I'd connect one pin on each keyboard switch to ground (maybe all chained together to the same ground pin?) then the other pin from each to a distinct GPIO pin on the Pi.
|
|
||||||
|
|
||||||
To further test this theory I got a second paper clip and awkwardly connected both GPIO 26 and 16 to the same ground pin simultaneously and observed `aBaBaBaB` being output on the host computer. Looking good!
|
|
||||||
|
|
||||||
Done messing with the Pi today. Going to mess with OpenSCAD a bit, having just learned about it and worked through a few steps of the introductory tutorial I still have a ways to go before I'll feel comfortable designing the switch plate and case for this thing.
|
|
|
@ -1,27 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
cd /sys/kernel/config/usb_gadget
|
|
||||||
mkdir -p usb_hid
|
|
||||||
cd usb_hid
|
|
||||||
echo 0x1d6b > idVendor # Linux Foundation
|
|
||||||
echo 0x0104 > idProduct # Multifunction Composite Gadget
|
|
||||||
echo 0x0100 > bcdDevice # v1.0.0
|
|
||||||
echo 0x0200 > bcdUSB # USB2
|
|
||||||
mkdir -p strings/0x409
|
|
||||||
echo "fedcba9876543210" > strings/0x409/serialnumber
|
|
||||||
echo "Rudis Muiznieks" > strings/0x409/manufacturer
|
|
||||||
echo "Button Buddy" > strings/0x409/product
|
|
||||||
mkdir -p configs/c.1/strings/0x409
|
|
||||||
echo "Config 1: ECM network" > configs/c.1/strings/0x409/configuration
|
|
||||||
echo 250 > configs/c.1/MaxPower
|
|
||||||
|
|
||||||
# functions
|
|
||||||
mkdir -p functions/hid.usb0
|
|
||||||
echo 1 > functions/hid.usb0/protocol
|
|
||||||
echo 1 > functions/hid.usb0/subclass
|
|
||||||
echo 8 > functions/hid.usb0/report_length
|
|
||||||
echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.usb0/report_desc
|
|
||||||
ln -s functions/hid.usb0 configs/c.1
|
|
||||||
# end functions
|
|
||||||
|
|
||||||
ls /sys/class/udc > UDC
|
|
|
@ -1,21 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
import time
|
|
||||||
import RPi.GPIO as GPIO
|
|
||||||
|
|
||||||
GPIO.setmode(GPIO.BCM)
|
|
||||||
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
|
||||||
GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
|
||||||
|
|
||||||
NULL_CHAR = chr(0)
|
|
||||||
|
|
||||||
def write_report(report):
|
|
||||||
with open('/dev/hidg0', 'rb+') as fd:
|
|
||||||
fd.write(report.encode())
|
|
||||||
|
|
||||||
while True:
|
|
||||||
if not(GPIO.input(26)): # 26 = a
|
|
||||||
write_report(NULL_CHAR*2+chr(4)+NULL_CHAR*5)
|
|
||||||
write_report(NULL_CHAR*8)
|
|
||||||
if not(GPIO.input(16)): # 16 = b
|
|
||||||
write_report(chr(32)+NULL_CHAR+chr(5)+NULL_CHAR*5)
|
|
||||||
write_report(NULL_CHAR*8)
|
|
Loading…
Reference in New Issue