BLE switch interface with GROVE joystic for micro:bit http://mahoro-ba.net/e2073.html
Embed:
(wiki syntax)
Show/hide line numbers
main.cpp
00001 //================================= 00002 // microbit_switch_if_joy 00003 //================================= 00004 // BLE switch interface with GROVE joystic for micro:bit 00005 // It is intended for use with ios devices. 00006 // 00007 // The MIT License (MIT) Copyright (c) 2019 Masatomo Kojima 00008 // 00009 // LED message 00010 // S key code setting 00011 // C Conected 00012 // P success Pearing 00013 // F Fail pearing 00014 // E Error at sending data by ble 00015 // e Error at writting data to flash memory 00016 // I Error by Incorrect cording 00017 // G GROVE sensor connect error 00018 //--------------------------------- 00019 00020 #define VERSION "JOY-190330" 00021 //#define NO_DEBUG 00022 00023 #include "microbit_switch_if_joy.h" 00024 #include "KeyValueInt.h" 00025 00026 //--------------------------------- 00027 // Display 00028 //--------------------------------- 00029 MicroBitDisplay display; 00030 int State; // 状態遷移 00031 char DispChar = 0; // LEDに表示する文字コード 00032 char DispCharLast = 0; // 最後に表示した文字コード 00033 bool TurnOffMode = false; // LED非表示モードのフラグ 00034 00035 //--------------------------------- 00036 // GROVE Joystick 00037 //--------------------------------- 00038 00039 AnalogIn AnalogP1(MICROBIT_PIN_P1); 00040 AnalogIn AnalogP2(MICROBIT_PIN_P2); 00041 00042 /** ---------- 00043 * @brief 整数値をLEDに表示する 00044 * @param data 整数値 00045 */ 00046 static void displayNumber(int data) 00047 { 00048 if (0<=data && data<=9) { // 1桁はスクロールしない 00049 display.print(data); 00050 } else { 00051 display.scroll(data); 00052 } 00053 } 00054 00055 //--------------------------------- 00056 // Flash Memory 00057 //--------------------------------- 00058 /** ---------- 00059 * @brief キー名を指定して不揮発メモリから値を読み出す 00060 * @param key キー名 00061 * @param init データが保存されていなかった時の初期値 00062 * @return int 取得したデータ 00063 */ 00064 static int FlashGet(MicroBitStorage storage, const char* key, int init=0) 00065 { 00066 KeyValuePair* kvp = storage.get(key); 00067 if(kvp != NULL) { 00068 int data; 00069 memcpy(&data, kvp->value, sizeof(int)); 00070 DEBUG("== FlashGet exist %s = %d\r\n", key, data); 00071 return data; 00072 } 00073 return init; 00074 } 00075 00076 /** ---------- 00077 * @brief 不揮発メモリに値を書き込む 00078 * @param storage 不揮発メモリインスタンス 00079 * @param key キー名 00080 * @param data 値 00081 * @return int MICROBIT_OK = 0 00082 * MICROBIT_INVALID_PARAMETER = -1001, 00083 * MICROBIT_NO_RESOURCES = -1005, 00084 */ 00085 static int FlashPut(MicroBitStorage storage, const char* key, int data) 00086 { 00087 int ret = storage.put(key, (uint8_t *)&data, sizeof(int)); 00088 DEBUG("== FlashPut %s %d %d\r\n", key, data, ret); 00089 return ret; 00090 } 00091 00092 //--------------------------------- 00093 // Setting 00094 //--------------------------------- 00095 bool setting_inc; // 設定値を増加 00096 bool setting_enter; // 設定値を入力 00097 bool setting_next; // 次の設定値に移動 00098 00099 KeyValueInt kviKeyCode1("keycode1",'S', 1, 1, NUM_GROUP1, true); 00100 00101 /** ---------- 00102 * @brief 1つのパラメータの表示と変更 00103 * @param storage 不揮発メモリインスタンス 00104 * @param para パラメータのキーと値の組 00105 * @param change 変更する時 true 00106 * @return bool true : Success false : Failed 00107 */ 00108 static bool paraSettingOne(MicroBitStorage storage, KeyValueInt* para, bool change) 00109 { 00110 display.print(para->disp); // 識別文字をLED表示 00111 wait(SETTING_DISPLAY_WAIT); 00112 displayNumber(para->value); // 値をLED表示 00113 if (!change) { 00114 wait(SETTING_DISPLAY_WAIT); 00115 return true; 00116 } 00117 00118 DEBUG("== paraSetting\r\n"); 00119 setting_inc = false; 00120 setting_next = setting_enter = false; 00121 while( ! setting_next) { // Bボタンが離されるまで 00122 if (setting_inc) { // Aボタンが押されたら 00123 setting_inc = false; 00124 para->inc(); 00125 displayNumber(para->value); 00126 } 00127 wait(0.2); 00128 } 00129 int ret = FlashPut(storage, para->key, para->value); 00130 if (ret) DEBUG("(strage)Error %d\r\n",ret); 00131 return (ret == MICROBIT_OK); 00132 } 00133 00134 /** ---------- 00135 * @brief パラメータの表示と変更 00136 * @param change true:変更する時 00137 */ 00138 static bool paraSetting(bool change=false) 00139 { 00140 MicroBitStorage storage; 00141 00142 kviKeyCode1.set(FlashGet(storage, kviKeyCode1.key, 1)); 00143 return paraSettingOne(storage, &kviKeyCode1, change); 00144 } 00145 //--------------------------------- 00146 // BLE & HID 00147 //--------------------------------- 00148 BLE ble; 00149 KeyboardService *kbdServicePtr; 00150 BLE_MESSAGE bleMessage; 00151 00152 /** ---------- 00153 * @brief BLE接続が切断された時のコールバック関数 00154 */ 00155 static void onDisconnect(const Gap::DisconnectionCallbackParams_t *params) 00156 { 00157 DEBUG("(BLE)disconnected\r\n"); 00158 ble.gap().startAdvertising(); // restart advertising 00159 bleMessage = BLE_NO_MESSAGE; 00160 } 00161 00162 /** ---------- 00163 * @brief BLE接続が接続された時のコールバック関数 00164 */ 00165 static void onConnect(const Gap::ConnectionCallbackParams_t *params) 00166 { 00167 if(kbdServicePtr->isConnected()) { 00168 DEBUG("(BLE)connected\r\n"); 00169 ble.gap().stopAdvertising(); 00170 bleMessage = BLE_CONNECTED; 00171 } 00172 } 00173 00174 /** ---------- 00175 * @brief パスキー入力を求められた時のコールバック関数 00176 */ 00177 static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey) 00178 { 00179 printf("(BLE)Input passKey: "); 00180 for (unsigned i = 0; i < Gap::ADDR_LEN; i++) { 00181 printf("%c", passkey[i]); 00182 } 00183 printf("\r\n"); 00184 } 00185 00186 /** ---------- 00187 * @brief セキュリティ設定完了時のコールバック関数 00188 */ 00189 static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status) 00190 { 00191 if (status == SecurityManager::SEC_STATUS_SUCCESS) { 00192 // DEBUG("(BLE)Security success %d\r\n", status); 00193 bleMessage = BLE_PAIRING_SUCCESS; 00194 00195 } else { 00196 // DEBUG("(BLE)Security failed %d\r\n", status); 00197 bleMessage = BLE_PAIRING_FAILED; 00198 } 00199 } 00200 00201 /** ---------- 00202 * @brief セキュリティ初期化 00203 * @para _ble BLEインスタンス 00204 */ 00205 static void initializeSecurity(BLE &_ble) 00206 { 00207 bool enableBonding = true; 00208 bool requireMITM = HID_SECURITY_REQUIRE_MITM; 00209 00210 _ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback); 00211 _ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback); 00212 00213 _ble.securityManager().init(enableBonding, requireMITM, HID_SECURITY_IOCAPS); 00214 } 00215 00216 /** ---------- 00217 * @brief HOGP (HID Over GATT Profile) 初期化 00218 * @para _ble BLEインスタンス 00219 */ 00220 static void initializeHOGP(BLE &_ble) 00221 { 00222 static const uint16_t uuid16_list[] = {GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE, 00223 GattService::UUID_DEVICE_INFORMATION_SERVICE, 00224 GattService::UUID_BATTERY_SERVICE 00225 }; 00226 00227 PnPID_t pnpID; 00228 pnpID.vendorID_source = 0x2; // from the USB Implementer's Forum 00229 pnpID.vendorID = 0x0D28; // NXP 00230 pnpID.productID = 0x0204; // CMSIS-DAP (well, it's a keyboard but oh well) 00231 pnpID.productVersion = 0x0100; // v1.0 00232 HIDDeviceInformationService deviceInfo(_ble, "ARM", "m1", "abc", "def", "ghi", "jkl", &pnpID); 00233 00234 BatteryService batteryInfo(_ble, 80); 00235 00236 _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | 00237 GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 00238 _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, 00239 (uint8_t *)uuid16_list, sizeof(uuid16_list)); 00240 00241 // see 5.1.2: HID over GATT Specification (pg. 25) 00242 _ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 00243 // 30ms to 50ms is recommended (5.1.2) 00244 _ble.gap().setAdvertisingInterval(50); 00245 } 00246 00247 /** ---------- 00248 * @brief BLE接続のHID(human interface device) の初期化 00249 */ 00250 static void initialize_BLE_HID() 00251 { 00252 static const char SHORT_DEVICE_NAME[] = "micro:bit"; 00253 static char DeviceName[20]; 00254 00255 int id = microbit_serial_number()& 0xfff; // シリアル番号の下12桁を4桁の10進で表示 00256 sprintf(DeviceName, "micro:bit %04d", id); 00257 DEBUG("(BLE)id %s\r\n", DeviceName); 00258 00259 // DEBUG("(BLE)initialising ble\r\n"); 00260 ble.init(); 00261 00262 ble.gap().onDisconnection(onDisconnect); 00263 ble.gap().onConnection(onConnect); 00264 00265 initializeSecurity(ble); 00266 00267 DEBUG("(BLE)adding hid service\r\n"); 00268 KeyboardService kbdService(ble); 00269 kbdServicePtr = &kbdService; 00270 00271 DEBUG("(BLE)adding device info and battery service\r\n"); 00272 initializeHOGP(ble); 00273 00274 DEBUG("(BLE)setting up gap\r\n"); 00275 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::KEYBOARD); 00276 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, 00277 (uint8_t *)DeviceName, sizeof(DeviceName)); 00278 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, 00279 (uint8_t *)SHORT_DEVICE_NAME, sizeof(SHORT_DEVICE_NAME)); 00280 ble.gap().setDeviceName((const uint8_t *)DeviceName); 00281 00282 DEBUG("(BLE)advertising\r\n"); 00283 ble.gap().startAdvertising(); 00284 } 00285 00286 //--------------------------------- 00287 // Button 00288 //--------------------------------- 00289 MicroBitMessageBus bus; 00290 MicroBitButton buttonA(MICROBIT_PIN_BUTTON_A, MICROBIT_ID_BUTTON_A); 00291 MicroBitButton buttonB(MICROBIT_PIN_BUTTON_B, MICROBIT_ID_BUTTON_B); 00292 //MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ALL); 00293 MicroBitButton P0(MICROBIT_PIN_P0, MICROBIT_ID_IO_P0, MICROBIT_BUTTON_ALL_EVENTS, PullUp); 00294 00295 /** ---------- 00296 * @brief キーコードを送信する 00297 * @para code 上位8bit:修飾キー 下位8bit:キーコード 00298 */ 00299 static void sendKeyCode(int code) { 00300 if (code) { 00301 uint8_t key = code & 0xff; 00302 uint8_t modif = code >> 8; 00303 00304 if (key > KEYMAP_SIZE ) { 00305 DispChar ='I'; // キーコード設定間違い 00306 } else { 00307 ble_error_t ret = kbdServicePtr->keyDownCode(key, modif); 00308 // DEBUG(" code=%d modif=%d\r\n",key , modif); 00309 if (ret) { 00310 DispChar ='E'; 00311 DispCharLast =0; // E が続く時に表示 00312 DEBUG("(BLE)Error %d\r\n",ret); 00313 } 00314 } 00315 } 00316 } 00317 /** ---------- 00318 * @brief ボタン保持時イベント 00319 * @para e イベント 00320 */ 00321 static void onButtonHold(MicroBitEvent e) 00322 { 00323 if ((e.source == MICROBIT_ID_BUTTON_A && buttonB.isPressed()) || 00324 (e.source == MICROBIT_ID_BUTTON_B && buttonA.isPressed()) ) { 00325 DispChar = 'H'; 00326 sendKeyCode(keyCodeGroup0[2]); 00327 } 00328 } 00329 00330 /** ---------- 00331 * @brief ボタン押下げ時イベント 00332 * @para e イベント 00333 */ 00334 static void onButtonDown(MicroBitEvent e) 00335 { 00336 // DEBUG(" Button Down %d State=%d\r\n", e.source, State); 00337 00338 switch (State) { 00339 case STATE_SETTING : 00340 switch(e.source) { 00341 case MICROBIT_ID_BUTTON_A : 00342 setting_inc = true; 00343 break; 00344 case MICROBIT_ID_BUTTON_B : 00345 setting_enter = true; 00346 break; 00347 } 00348 break; 00349 case STATE_OPERATING : 00350 int code = 0; 00351 switch(e.source) { 00352 case MICROBIT_ID_BUTTON_A : 00353 DispChar = 'A'; 00354 code = keyCodeGroup0[0]; 00355 break; 00356 case MICROBIT_ID_BUTTON_B : 00357 DispChar = 'B'; 00358 code = keyCodeGroup0[1]; 00359 break; 00360 case MICROBIT_ID_IO_P0 : 00361 DispChar = '0'; 00362 code = keyCodeGroup1[kviKeyCode1.value-1][JOY_CENTER_PRESS]; 00363 break; 00364 } 00365 if (code != 0 )sendKeyCode(code); 00366 } 00367 } 00368 00369 /** ---------- 00370 * @brief ボタン離し時イベント 00371 * @para e イベント 00372 */ 00373 static void onButtonUp(MicroBitEvent e) 00374 { 00375 // DEBUG(" Button up %d\r\n", e.source); 00376 switch (State) { 00377 case STATE_SETTING : 00378 if(setting_enter) setting_next = true; // 決定ボタンを離したら次へ 00379 break; 00380 case STATE_OPERATING : 00381 DispChar = 0; 00382 ble_error_t ret = kbdServicePtr->keyUpCode(); 00383 if (ret) { 00384 DispChar ='E'; 00385 DispCharLast =0; // E が続く時に表示 00386 } 00387 } 00388 } 00389 00390 00391 /** ---------- 00392 * @brief ジョイスティックの接続をチェックする 00393 * @return false:接続エラー 00394 */ 00395 static bool checkJoy() 00396 { 00397 float joyX = AnalogP1.read(); 00398 float joyY = AnalogP2.read(); 00399 00400 if (joyX < JOY_ERR_THRE) return false; 00401 if (joyY < JOY_ERR_THRE) return false; 00402 00403 return true; 00404 } 00405 00406 /** ---------- 00407 * @brief ジョイスティックの状態を返す 00408 * @return JOY_STATUS 00409 */ 00410 static JOY_STATUS readJoyStatus(JOY_STATUS last) 00411 { 00412 JOY_STATUS js = JOY_NEUTRAL; 00413 00414 float joyX = AnalogP1.read(); 00415 float joyY = AnalogP2.read(); 00416 00417 if (joyX > JOY_CENTER_THRE) js = JOY_CENTER_PRESS; 00418 else { 00419 if (joyX < JOY_LOW_THRE) js = JOY_XLOW_PRESS; 00420 if (joyX > JOY_HIGH_THRE) js = JOY_XHIGH_PRESS; 00421 if (joyY < JOY_LOW_THRE) js = JOY_YLOW_PRESS; 00422 if (joyY > JOY_HIGH_THRE) js = JOY_YHIGH_PRESS; 00423 } 00424 00425 // DEBUG("%d, %f, %f\r\n", js, joyX, joyY); 00426 return js; 00427 } 00428 00429 static void joyAction(JOY_STATUS last, JOY_STATUS now) 00430 { 00431 int code = 0; 00432 // DEBUG("%d, %d\r\n", now, last); 00433 00434 if( now != last){ 00435 if(now == JOY_NEUTRAL) { 00436 DispChar = 0; 00437 ble_error_t ret = kbdServicePtr->keyUpCode(); 00438 if (ret) { 00439 DispChar ='E'; 00440 DispCharLast =0; // E が続く時に表示 00441 } 00442 } else { 00443 DispChar = '0' + now; 00444 code = keyCodeGroup1[kviKeyCode1.value-1][now]; 00445 } 00446 if (code != 0 )sendKeyCode(code); 00447 } 00448 } 00449 //--------------------------------- 00450 // Main 00451 //--------------------------------- 00452 int main() 00453 { 00454 State = STATE_DESABLE_INPUT; 00455 00456 wait(0.1); // ボタン状態の更新 00457 bool bA = buttonA.isPressed(); 00458 bool bB = buttonB.isPressed(); 00459 00460 if (bA && bB) { // ボタンABを押しながら起動 00461 for(int i=0;i<2;i++) { 00462 display.scroll(VERSION); 00463 wait(0.5); 00464 } 00465 } else if(bA) // ボタンAを押しながら起動 00466 State = STATE_SETTING; 00467 00468 //----- Display 00469 display.setDisplayMode(DISPLAY_MODE_BLACK_AND_WHITE); 00470 display.clear(); 00471 Timer dispTime; // 連続表示タイマー 00472 dispTime.start(); 00473 00474 //----- Button 00475 bus.listen(MICROBIT_ID_ANY, MICROBIT_BUTTON_EVT_DOWN, onButtonDown); 00476 bus.listen(MICROBIT_ID_ANY, MICROBIT_BUTTON_EVT_UP, onButtonUp); 00477 bus.listen(MICROBIT_ID_ANY, MICROBIT_BUTTON_EVT_HOLD, onButtonHold); 00478 00479 // Put the P0 pins into touch sense mode. 00480 // P0.isTouched(); 00481 00482 //----- Joystick 00483 JOY_STATUS joyStatus; 00484 JOY_STATUS joyStatusLast = JOY_NEUTRAL; 00485 while (!checkJoy()) { 00486 DispChar ='G'; 00487 display.printChar(DispChar ); 00488 wait(1); 00489 } 00490 00491 //----- Setting 00492 if (paraSetting(State == STATE_SETTING)) DispChar =0; 00493 else DispChar ='e'; 00494 00495 //----- BLE & HID 00496 State = STATE_DESABLE_INPUT; 00497 initialize_BLE_HID(); 00498 display.clear(); 00499 00500 //----- Loop 00501 State = STATE_OPERATING; 00502 while (true) { 00503 wait(0.15); 00504 ble.waitForEvent(); // BLEイベントを待つ 00505 00506 joyStatus = readJoyStatus(joyStatusLast); // Joystick の状態を読む 00507 joyAction(joyStatusLast, joyStatus); 00508 joyStatusLast = joyStatus; 00509 00510 if(bleMessage != BLE_NO_MESSAGE) { // BLEの状態を表示する 00511 DispChar = bleDispChar[bleMessage]; 00512 bleMessage = BLE_NO_MESSAGE; 00513 } 00514 00515 if (DispChar != DispCharLast) { // 表示文字が変更 00516 TurnOffMode = false; 00517 dispTime.reset(); 00518 display.enable(); 00519 if (DispChar ) display.printChar(DispChar ); 00520 else display.clear(); 00521 } 00522 if (!TurnOffMode) { 00523 if (dispTime.read() > TIME_TURN_OFF) { // 長時間表示 00524 TurnOffMode = true; 00525 display.disable(); 00526 } 00527 } 00528 00529 DispCharLast = DispChar ; 00530 } 00531 }
Generated on Tue Jul 12 2022 19:55:32 by 1.7.2