-
-
Save dglaude/c8634309c6bdfb29e33208b3f248d22b to your computer and use it in GitHub Desktop.
""" | |
This example acts as a BLE HID keyboard to peer devices. | |
It get's keycode from UART RX. | |
Color indication: | |
* BLUE_LED is blinking when not connected and steady blue when connected | |
* NEOPIXEL alternate between RED / GREEN / BLUE every time a keycode is transmitted (up and down event) | |
""" | |
import time | |
import board | |
#from digitalio import DigitalInOut, Direction | |
import digitalio | |
import busio | |
import usb_hid | |
import adafruit_ble | |
from adafruit_ble.advertising import Advertisement | |
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement | |
from adafruit_ble.services.standard.hid import HIDService | |
from adafruit_ble.services.standard.device_info import DeviceInfoService | |
from adafruit_hid.keyboard import Keyboard | |
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS | |
from adafruit_hid.keycode import Keycode | |
import neopixel | |
# setup for LED to indicate BLE connection | |
blue_led = digitalio.DigitalInOut(board.BLUE_LED) | |
blue_led.direction = digitalio.Direction.OUTPUT | |
# Define the one NeoPixel on nRF52 | |
pixels = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.3, auto_write=True) | |
color_a = 255 | |
color_b = 0 | |
color_c = 0 | |
STX=0x02 | |
ETX=0x03 | |
uart = busio.UART(board.TX, board.RX, baudrate=115200) | |
hid = HIDService() | |
device_info = DeviceInfoService(software_revision=adafruit_ble.__version__, | |
manufacturer="Adafruit Industries") | |
advertisement = ProvideServicesAdvertisement(hid) | |
advertisement.appearance = 961 | |
scan_response = Advertisement() | |
scan_response.complete_name = "CircuitPython HID" | |
ble = adafruit_ble.BLERadio() | |
if not ble.connected: | |
print("advertising") | |
ble.start_advertising(advertisement, scan_response) | |
else: | |
print("already connected") | |
print(ble.connections) | |
keyboard = Keyboard(hid.devices) | |
keyboard_layout = KeyboardLayoutUS(keyboard) | |
while True: | |
while not ble.connected: | |
time.sleep(0.2) | |
blue_led.value = not blue_led.value | |
pixels.fill((0, 0, 0)) | |
print("Start typing:") | |
while ble.connected: | |
blue_led.value = True | |
data = uart.read(11) | |
if data is not None: | |
if (len(data) == 11) and (data[0] == STX) and (data[1] == 0x08) and (data[10] == ETX): | |
keyboard.report=bytearray(data[2:10]) | |
keyboard.send() | |
pixels.fill((color_a, color_b, color_c)) | |
color_a, color_b, color_c = (color_c, color_a, color_b) | |
print(data[2:10]) | |
elif len(data)>0: | |
# Scan for STX ... ETX to resync | |
print(data) | |
report = bytearray(11) | |
for i in range(0, len(data)): | |
if data[i] == STX: | |
report = data[i:len(data)] + uart.read(11-(len(data)-i)) | |
print(report) | |
if (len(report) == 11) and (report[0] == STX) and (report[1] == 0x08) and (report[10] == ETX): | |
keyboard.report=bytearray(report[2:10]) | |
keyboard.send() | |
ble.start_advertising(advertisement) |
""" | |
Demo: | |
A USB keyboard is connected (via USB OTG cable) to a Trinked M0. | |
Trinked run KBDADVUARTUSBH: Keyboard Advanced UART USB Host: | |
https://github.com/gdsports/usbhostcopro/tree/master/KBDADVUARTUSBH | |
The Trinked send it via UART TX to the UART RX of a nRF52840. | |
Every keyboard HID code is transmitted over USB and BLE simultaneously. | |
""" | |
import time | |
import board | |
from digitalio import DigitalInOut, Direction | |
import busio | |
import usb_hid | |
import adafruit_ble | |
from adafruit_ble.advertising import Advertisement | |
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement | |
from adafruit_ble.services.standard.hid import HIDService | |
from adafruit_ble.services.standard.device_info import DeviceInfoService | |
from adafruit_hid.keyboard import Keyboard | |
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS | |
from adafruit_hid.keycode import Keycode | |
STX=0x02 | |
ETX=0x03 | |
uart = busio.UART(board.TX, board.RX, baudrate=115200) | |
hid = HIDService() | |
device_info = DeviceInfoService(software_revision=adafruit_ble.__version__, | |
manufacturer="Adafruit Industries") | |
advertisement = ProvideServicesAdvertisement(hid) | |
advertisement.appearance = 961 | |
scan_response = Advertisement() | |
scan_response.complete_name = "CircuitPython HID" | |
ble = adafruit_ble.BLERadio() | |
if not ble.connected: | |
print("advertising") | |
ble.start_advertising(advertisement, scan_response) | |
else: | |
print("already connected") | |
print(ble.connections) | |
keyboard = Keyboard(hid.devices) | |
keyboard_layout = KeyboardLayoutUS(keyboard) | |
usb_keyboard = Keyboard(usb_hid.devices) | |
usb_keyboard_layout = KeyboardLayoutUS(usb_keyboard) | |
while True: | |
while not ble.connected: | |
pass | |
print("Start typing:") | |
while ble.connected: | |
data = uart.read(11) | |
if data is not None: | |
if (len(data) == 11) and (data[0] == STX) and (data[1] == 0x08) and (data[10] == ETX): | |
keyboard.report=bytearray(data[2:10]) | |
keyboard.send() | |
usb_keyboard.report=bytearray(data[2:10]) | |
usb_keyboard.send() | |
print(data[2:10]) | |
elif len(data)>0: | |
# Scan for STX ... ETX to resync | |
print(data) | |
report = bytearray(11) | |
for i in range(0, len(data)): | |
if data[i] == STX: | |
report = data[i:len(data)] + uart.read(11-(len(data)-i)) | |
print(report) | |
if (len(report) == 11) and (report[0] == STX) and (report[1] == 0x08) and (report[10] == ETX): | |
keyboard.report=bytearray(report[2:10]) | |
keyboard.send() | |
usb_keyboard.report=bytearray(report[2:10]) | |
usb_keyboard.send() | |
ble.start_advertising(advertisement) |
Hi @kmatch98,
Great, so that video recording is usefull to something.
Here is a link to Twitter that should show you the result and the FeatherWing I prototyped: https://twitter.com/DavidGlaude/status/1264590297654272002?s=20
I did nothing on the Arduino side, I just reused a pre-compiled image... so I have no clue what it does and how it does.
So right now, I just receive over serial the HID messsage that just need to be forwarded as is to another USB or to BLE.
Actually I never programmed in Arduino except for blinking an LED after an hour of installing the environement and installing library or other things. This is why I prefer to do Circuit Python.
Right now, there is no code or library behind this mini-project.
But I would like to "decode" the HID message and be able to manipulate it or take action depending on received key.
CircuitPython has code to send key, but not code to receive key.
Since stargirl (on Adafruit Discord Channel) is working on "Winterbloom Hostess Featherwing", I assume she will have code/library... so I am maybe not going to invest time in doing what she will be doing better.
Oh, your project is cyberDÛCK! That was a strong inspiration to trying again to get USB Keyboard input to work (I tried without success six month ago, but figured last week that it was my USB OTG cable that was not working).
And if I have all the required hardware, I may want to replicate what you have done.
I believe the ultimate goal would be to have something similar to IchigoJam (not the Raspberry Pi version, but the MCU version).
Or something like Pico8, but on physical hardware, not software your run on Win/Mac/Pi.
The ultimate all in one mini CircuitPython computer. Just like there were Forth and Lisp computer with all in one.
Yes, I almost wanted to ask DanH again if we could have BLE Keyboard input, even if it is just basic code to start with.
I would have put that in the weed section, but at the time of the meeting I was without a microphone and not in position to participate.
This would mean we can do with CircuitPython USB and BLE Keyboard input and output.
May I suggest you join CircuitPython Discord next week (Monday 01/06) and we raise this topic with DanH and other contributor.
Any other communication channel than this Gist is welcome too.
You have my Twitter account in a link above.
Thanks for the note. Somehow I missed your USB and UART work on your Twitter (sometimes I miss things by not checking very often) but glad that Scott referenced your work during the CIrcuitPython updates.
I’m actually the other way around, I have been learning Arduino for a couple of years and am just now trying to work with CIrcuitPython.
I’ll try to connect with the group call next week to support you on your request. Glad it’s not just me wanting BLE keyboard input. I submitted an issue but a nudge may help. I will let you lead the discussion and I will support where useful. I’m new to all this so I really prefer to lurk but will help where needed!
Added a BLE only version, that use the BLUE_LED and NEOPIXEL to indicate the status.
BLUE_LED blinking = not connected
BLUE_LED steady = connected
NEOPIXEL change color everytime a key is transmitted, both for up and down event
This can work standalone and the status is visible.
Just saw your project in the weekly CircuitPython video and had to inquire on a few things. I used the USB host running in Arduino but had to fight through some key conversions for the arrow keys etc. Do you know of an easy way to deal with special keys? My code is here.
Also, I’m really interested in getting BLE Keyboard input into an NRF52840. Any ideas on this? I raised an issue and danH said he didn’t have an example ready.
Cool projects. Can’t wait to see what things you will do with this.