├── 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 | 
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 |
--------------------------------------------------------------------------------