Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add joypad HID master support #2214

Merged
merged 1 commit into from
Jun 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
# Features
* Adafruit TinyUSB Arduino (USB mouse, keyboard, flash drive, generic HID, CDC Serial, MIDI, WebUSB, others)
* Bluetooth on the PicoW (Classic and BLE) with Keyboard, Mouse, Joystick, and Virtual Serial
* Bluetooth Classic and BLE HID master mode (connect to BT keyboard or mouse)
* Bluetooth Classic and BLE HID master mode (connect to BT keyboard, mouse, or joystick)
* Generic Arduino USB Serial, Keyboard, Joystick, and Mouse emulation
* WiFi (Pico W, ESP32-based ESPHost, Atmel WINC1500)
* Ethernet (Wired W5500, W5100, ENC28J60)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,18 @@ void ckb(void *cbdata, int key) {
}


// Joystick can get reports of 4 analog axes, 1 d-pad bitfield, and up to 32 buttons
// Axes and hats that aren't reported by the pad are read as 0
void joy(void *cbdata, int x, int y, int z, int rz, uint8_t hat, uint32_t buttons) {
(void) cbdata;
const char *hats[16] = { "U", "UR", "R", "DR", "D", "DL", "L", "UL", "", "", "", "", "", "", "", "." };
Serial.printf("Joystick: (%4d, %4d) (%4d, %4d), Hat: %-2s, Buttons:", x, y, z, rz, hats[hat & 15]);
for (int i = 0; i < 32; i++) {
Serial.printf(" %c", (buttons & 1 << i) ? '*' : '.');
}
Serial.println();
}

void setup() {
Serial.begin();
delay(3000);
Expand Down Expand Up @@ -190,9 +202,11 @@ void setup() {
hid.onConsumerKeyDown(ckb, (void *)true);
hid.onConsumerKeyUp(ckb, (void *)false);

hid.onJoypad(joy);

hid.begin();

hid.connectKeyboard();
hid.connectAny();
// or hid.connectMouse();
}

Expand All @@ -204,6 +218,6 @@ void loop() {
hid.disconnect();
hid.clearPairing();
Serial.printf("Restarting HID master, put your device in pairing mode now.\n");
hid.connectKeyboard();
hid.connectAny();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,18 @@ void ckb(void *cbdata, int key) {
Serial.printf("Consumer: %02x %s\n", key, state ? "DOWN" : "UP");
}

// Joystick can get reports of 4 analog axes, 1 d-pad bitfield, and up to 32 buttons
// Axes and hats that aren't reported by the pad are read as 0
void joy(void *cbdata, int x, int y, int z, int rz, uint8_t hat, uint32_t buttons) {
(void) cbdata;
const char *hats[16] = { "U", "UR", "R", "DR", "D", "DL", "L", "UL", "", "", "", "", "", "", "", "." };
Serial.printf("Joystick: (%4d, %4d) (%4d, %4d), Hat: %-2s, Buttons:", x, y, z, rz, hats[hat & 15]);
for (int i = 0; i < 32; i++) {
Serial.printf(" %c", (buttons & 1 << i) ? '*' : '.');
}
Serial.println();
}


void setup() {
Serial.begin();
Expand Down Expand Up @@ -190,10 +202,11 @@ void setup() {
hid.onConsumerKeyDown(ckb, (void *)true);
hid.onConsumerKeyUp(ckb, (void *)false);

hid.onJoypad(joy);

hid.begin(true);

hid.connectBLE(); //Keyboard();
// or hid.connectMouse();
hid.connectBLE();
}

void loop() {
Expand All @@ -204,6 +217,6 @@ void loop() {
hid.disconnect();
hid.clearPairing();
Serial.printf("Restarting HID master, put your device in pairing mode now.\n");
hid.connectBLE(); //Keyboard();
hid.connectBLE();
}
}
3 changes: 3 additions & 0 deletions libraries/BluetoothHIDMaster/keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ scanAsyncResult KEYWORD2

connectKeyboard KEYWORD2
connectMouse KEYWORD2
connectJoypad KEYWORD2
connectAny KEYWORD2

hidConnected KEYWORD2
onMouseMove KEYWORD2
Expand All @@ -29,6 +31,7 @@ onKeyDown KEYWORD2
onKeyUp KEYWORD2
onConsumerKeyDown KEYWORD2
onConsumerKeyUp KEYWORD2
onJoypad KEYWORD2

# BTDeviceInfo
deviceClass KEYWORD2
Expand Down
37 changes: 32 additions & 5 deletions libraries/BluetoothHIDMaster/src/BluetoothHIDMaster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,11 @@ void BluetoothHIDMaster::onConsumerKeyUp(void (*cb)(void *, int), void *cbData)
_consumerKeyUpData = cbData;
}

void BluetoothHIDMaster::onJoypad(void (*cb)(void *, int, int, int, int, uint8_t, uint32_t), void *cbData) {
_joypadCB = cb;
_joypadData = cbData;
}

std::list<BTDeviceInfo> BluetoothHIDMaster::scan(uint32_t mask, int scanTimeSec, bool async) {
return _hci.scan(mask, scanTimeSec, async);
}
Expand Down Expand Up @@ -252,6 +257,14 @@ bool BluetoothHIDMaster::connectMouse() {
return connectCOD(0x2580);
}

bool BluetoothHIDMaster::connectJoypad() {
return connectCOD(0x2508);
}

bool BluetoothHIDMaster::connectAny() {
return connectCOD(0x2500);
}

bool BluetoothHIDMaster::disconnect() {
BluetoothLock b;
if (!_running || !connected()) {
Expand Down Expand Up @@ -287,17 +300,21 @@ void BluetoothHIDMaster::hid_host_handle_interrupt_report(btstack_hid_parser_t *
int new_keys_count = 0;

uint16_t new_consumer_key = 0;
uint8_t newMB = 0;
uint32_t newMB = 0;
bool noMB = false;

bool updCons = false;
bool updKey = false;
bool updMB = false;
bool updJoy = false;

bool updMouse = false;
int dx = 0;
int dy = 0;
int dz = 0;
int rz = 0;
int dwheel = 0;
uint8_t hat = 0;

while (btstack_hid_parser_has_more(parser)) {
uint16_t usage_page;
Expand All @@ -306,19 +323,26 @@ void BluetoothHIDMaster::hid_host_handle_interrupt_report(btstack_hid_parser_t *
btstack_hid_parser_get_field(parser, &usage_page, &usage, &value);
if (usage_page == 0x01) {
updMouse = true;
updJoy = true;
if (usage == 0x30) {
dx = value;
} else if (usage == 0x31) {
dy = value;
} else if (usage == 0x32) {
dz = value;
} else if (usage == 0x35) {
rz = value;
} else if (usage == 0x38) {
dwheel = value;
} else if (usage == 0x39) {
hat = value & 0xff;
}
} else if (usage_page == 0x09) {
updMB = true;
if (usage == 0) {
noMB = true;
}
if (!noMB && value && (usage > 0) && (usage < 9)) {
if (!noMB && value && (usage > 0)) {
newMB |= 1 << (usage - 1);
}

Expand Down Expand Up @@ -386,13 +410,13 @@ void BluetoothHIDMaster::hid_host_handle_interrupt_report(btstack_hid_parser_t *
if (updCons) {
last_consumer_key = new_consumer_key;
}
if (updMB) {
if (updMB && _mouseButtonCB) {
if (lastMB != newMB) {
for (int i = 0; i < 8; i++) {
int mask = 1 << i;
if ((lastMB & mask) && !(newMB & mask) && _mouseButtonCB) {
if ((lastMB & mask) && !(newMB & mask)) {
_mouseButtonCB(_mouseButtonData, i, false);
} else if (!(lastMB & mask) && (newMB & mask) && _mouseButtonCB) {
} else if (!(lastMB & mask) && (newMB & mask)) {
_mouseButtonCB(_mouseButtonData, i, true);
}
}
Expand All @@ -403,6 +427,9 @@ void BluetoothHIDMaster::hid_host_handle_interrupt_report(btstack_hid_parser_t *
if (updMouse && _mouseMoveCB) {
_mouseMoveCB(_mouseMoveData, dx, dy, dwheel);
}
if (updJoy && _joypadCB) {
_joypadCB(_joypadData, dx, dy, dz, rz, hat, newMB);
}
}


Expand Down
8 changes: 8 additions & 0 deletions libraries/BluetoothHIDMaster/src/BluetoothHIDMaster.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class BluetoothHIDMaster {

static const uint32_t keyboard_cod = 0x2540;
static const uint32_t mouse_cod = 0x2540;
static const uint32_t joypad_cod = 0x2508;
static const uint32_t any_cod = 0;
std::list<BTDeviceInfo> scan(uint32_t mask, int scanTimeSec = 5, bool async = false);
bool scanAsyncDone();
Expand All @@ -86,6 +87,8 @@ class BluetoothHIDMaster {
bool connect(const uint8_t *addr);
bool connectKeyboard();
bool connectMouse();
bool connectJoypad();
bool connectAny();

bool connectBLE(const uint8_t *addr, int addrType);
bool connectBLE();
Expand All @@ -99,6 +102,7 @@ class BluetoothHIDMaster {
void onKeyUp(void (*)(void *, int), void *cbData = nullptr);
void onConsumerKeyDown(void (*)(void *, int), void *cbData = nullptr);
void onConsumerKeyUp(void (*)(void *, int), void *cbData = nullptr);
void onJoypad(void (*)(void *, int, int, int, int, uint8_t, uint32_t), void *cbData = nullptr);

private:
bool _ble = false;
Expand Down Expand Up @@ -131,6 +135,10 @@ class BluetoothHIDMaster {
void (*_consumerKeyUpCB)(void *, int) = nullptr;
void *_consumerKeyUpData;

void (*_joypadCB)(void *, int, int, int, int, uint8_t, uint32_t) = nullptr;
void *_joypadData;


btstack_packet_callback_registration_t _sm_event_callback_registration;
void sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
Expand Down