├── demo.jpg ├── README.md └── Nano_33_Gamepad.ino /demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitbank2/Nano_33_Gamepad/HEAD/demo.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Nano 33 Gamepad
2 | Project started 10/26/2019
3 | Copyright (c) 2019 BitBank Software, Inc.
4 | Written by Larry Bank
5 | bitbank@pobox.com
6 |
7 | ![Nano 33 Gamepad](/demo.jpg?raw=true "Nano 33 Gamepad") 8 |
9 | The purpose of this code is to use BLE HID gamepads with the Arduino Nano 33 BLE. 10 | The Nano 33 BLE libraries don't include any HID support, so this code is 11 | very rudamentary and instead of properly parsing the HID reports, it makes 12 | assumptions to work with 2 popular devices (ACGAM R1 and MINI PLUS). 13 | There is a #define switch to send the output to either the serial monitor 14 | or a 128x64 SSD1306 OLED display. The code was written to learn about HID 15 | over GATT and how difficult it would be to implement a minimal HID host 16 | using the Nano 33 BLE board. 17 |
18 | 19 | -------------------------------------------------------------------------------- /Nano_33_Gamepad.ino: -------------------------------------------------------------------------------- 1 | // 2 | // Sample sketch to connect a BLE HID Gamepad to the Arduino Nano 33 BLE 3 | // This code doesn't implement a full HID report parser and instead 4 | // supports only the 2 most popular devices I could find (ACGAM R1 and MINI PLUS) 5 | // 6 | // Copyright (c) 2019 BitBank Software, Inc. 7 | // written by Larry Bank (bitbank@pobox.com) 8 | // project started 10/26/2019 9 | // 10 | 11 | #include 12 | 13 | void ProcessHIDReport(uint8_t *ucData, int iLen); 14 | void ShowMsg(char *msg, int iLine); 15 | 16 | // 17 | // Define this to display results on a 128x64 OLED 18 | // otherwise output will be sent to the serial monitor 19 | #define USE_OLED 20 | 21 | #ifdef USE_OLED 22 | #include 23 | #endif 24 | 25 | enum { 26 | CONTROLLER_ACGAM_R1 = 0, 27 | CONTROLLER_MINIPLUS, 28 | CONTROLLER_UNKNOWN 29 | }; 30 | 31 | char *szACGAM = (char *)"ACGAM R1 "; 32 | char *szMINIPLUS = (char *)"MINI PLUS"; 33 | static int iControllerType; 34 | volatile static int bConnected, bChanged; 35 | 36 | // Current button state 37 | // The first 8 bits are for the (up to 8) push buttons 38 | static uint16_t u16Buttons; 39 | // bits to define the direction pad since it's not analog 40 | #define BUTTON_LEFT 0x100 41 | #define BUTTON_RIGHT 0x200 42 | #define BUTTON_UP 0x400 43 | #define BUTTON_DOWN 0x800 44 | 45 | // Graphics for the controller real time display 46 | const uint8_t ucArrow[] PROGMEM = { 47 | 0x01,0x80,0x02,0x40,0x04,0x20,0x08,0x10,0x10,0x08,0x20,0x04,0x40,0x02,0x80,0x01, 48 | 0x80,0x01,0xfc,0x3f,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x07,0xe0 49 | }; 50 | 51 | const uint8_t ucFilledArrow[] PROGMEM = { 52 | 0x01,0x80,0x03,0xc0,0x07,0xe0,0x0f,0xf0,0x1f,0xf8,0x3f,0xfc,0x7f,0xfe,0xff,0xff, 53 | 0xff,0xff,0xff,0xff,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0 54 | }; 55 | 56 | const uint8_t ucSquare[] PROGMEM = { 57 | 0x00,0x00,0x00,0x00,0x3f,0xfc,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04, 58 | 0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x3f,0xfc,0x00,0x00,0x00,0x00 59 | }; 60 | 61 | const uint8_t ucFilledSquare[] PROGMEM = { 62 | 0x00,0x00,0x00,0x00,0x3f,0xfc,0x3f,0xfc,0x3f,0xfc,0x3f,0xfc,0x3f,0xfc,0x3f,0xfc, 63 | 0x3f,0xfc,0x3f,0xfc,0x3f,0xfc,0x3f,0xfc,0x3f,0xfc,0x3f,0xfc,0x00,0x00,0x00,0x00 64 | }; 65 | 66 | void setup() 67 | { 68 | #ifdef USE_OLED 69 | oledInit(OLED_128x64, 0,0, -1, -1, 400000L); 70 | oledFill(0, 1); 71 | #else 72 | Serial.begin(115200); 73 | while (!Serial); 74 | #endif 75 | 76 | ShowMsg("Scanning for BLE ctrl", 0); 77 | 78 | // begin initialization 79 | if (!BLE.begin()) 80 | { 81 | ShowMsg("starting BLE failed!", 0); 82 | while (1); 83 | } 84 | // start scanning for peripheral 85 | BLE.scan(); 86 | 87 | u16Buttons = 0; 88 | } /* setup() */ 89 | 90 | void loop() 91 | { 92 | char szTemp[64]; 93 | 94 | bConnected = 0; 95 | // check if a peripheral has been discovered 96 | BLEDevice peripheral = BLE.available(); 97 | 98 | if (peripheral) { 99 | // discovered a peripheral, print out address, local name, and advertised service 100 | sprintf(szTemp, "Found %s", peripheral.address().c_str()); 101 | ShowMsg(szTemp,1); 102 | sprintf(szTemp, "%s - %s", peripheral.localName().c_str(), peripheral.advertisedServiceUuid().c_str()); 103 | ShowMsg(szTemp, 2); 104 | 105 | 106 | // Compare it to known controllers 107 | iControllerType = CONTROLLER_UNKNOWN; 108 | if (strcmp(peripheral.localName().c_str(), szACGAM) == 0) 109 | iControllerType = CONTROLLER_ACGAM_R1; 110 | else if (strcmp(peripheral.localName().c_str(), szMINIPLUS) == 0) 111 | iControllerType = CONTROLLER_MINIPLUS; 112 | 113 | // Check if the peripheral is a HID device 114 | if (peripheral.advertisedServiceUuid() == "1812" && iControllerType != CONTROLLER_UNKNOWN) { 115 | // stop scanning 116 | BLE.stopScan(); 117 | 118 | monitorActions(peripheral); 119 | 120 | // peripheral disconnected, start scanning again 121 | BLE.scan(); 122 | } 123 | } 124 | } /* loop() */ 125 | 126 | // 127 | // Callback which handles HID report updates 128 | // 129 | void HIDReportWritten(BLEDevice central, BLECharacteristic characteristic) 130 | { 131 | int iLen, i; 132 | uint8_t ucTemp[128]; 133 | 134 | // central wrote new HID report info 135 | iLen = characteristic.readValue(ucTemp, sizeof(ucTemp)); 136 | ProcessHIDReport(ucTemp, iLen); 137 | } /* HIDReportWritten() */ 138 | void monitorActions(BLEDevice peripheral) { 139 | 140 | char ucTemp[128]; 141 | int i, iLen, iCount; 142 | //BLECharacteristic hidRep[16]; 143 | BLEService hidService; 144 | //int ihidCount = 0; 145 | 146 | // connect to the peripheral 147 | ShowMsg("Connecting...", 4); 148 | if (peripheral.connect()) { 149 | ShowMsg("Connected", 5); 150 | } else { 151 | ShowMsg("Failed to connect!", 5); 152 | return; 153 | } 154 | 155 | // discover peripheral attributes 156 | // Serial.println("Discovering service 0x1812 ..."); 157 | if (peripheral.discoverService("1812")) { 158 | ShowMsg("0x1812 discovered", 6); 159 | } else { 160 | ShowMsg("0x1812 disc failed", 6); 161 | peripheral.disconnect(); 162 | 163 | while (1); 164 | return; 165 | } 166 | 167 | hidService = peripheral.service("1812"); // get the HID service 168 | 169 | // Serial.print("characteristic count = "); Serial.println(hidService.characteristicCount(), DEC); 170 | 171 | iCount = hidService.characteristicCount(); 172 | for (i=0; i= 16) ? FONT_SMALL : FONT_NORMAL; 343 | oledWriteString(0,0,iLine,msg, iFont, 0, 1); 344 | #else 345 | Serial.println(msg); 346 | #endif 347 | } /* ShowMsg() */ 348 | --------------------------------------------------------------------------------