Skip to content

Instantly share code, notes, and snippets.

@dglaude
Last active January 10, 2023 17:01
Show Gist options
  • Save dglaude/c8634309c6bdfb29e33208b3f248d22b to your computer and use it in GitHub Desktop.
Save dglaude/c8634309c6bdfb29e33208b3f248d22b to your computer and use it in GitHub Desktop.
Circuit Python USB Host + Keyboard mirroring to USB and BLE
"""
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)
@dglaude
Copy link
Author

dglaude commented May 27, 2020

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment