Initial release
main.cpp
- Committer:
- masakjm
- Date:
- 2018-09-17
- Revision:
- 1:3b9ae1dbcdcf
- Parent:
- 0:28fb3e9ef81a
- Child:
- 3:b6e9850d3e76
File content as of revision 1:3b9ae1dbcdcf:
//================================= // microbit_switch_if_3sw //================================= // BLE switch interface with 3 tact switches for micro:bit // It is intended for use with ios devices. // // The MIT License (MIT) Copyright (c) 2018 Masatomo Kojima // // LED message // S key code setting sw1,2 // T key code setting sw3 // W Waiting // C Conected // P success Pearing // F Fail pearing // E Error at sending data by ble // e Error at writting data to flash memory // I Error by Incorrect cording // // Please refer to the following site. (Japanese only) // http://mahoro-ba.net/e2036.html // http://mahoro-ba.net/e2038.html // // I refer to information written on the following sites. // (1)https://os.mbed.com/teams/microbit/code/microbit_presenter/ // Licensed under the Apache License, Version 2.0 // // (2)https://lancaster-university.github.io/microbit-docs/ // The MIT License (MIT) // Copyright (c) 2016 British Broadcasting Corporation. // //--------------------------------- #define VERSION "3SW-180917" //#define NO_DEBUG #include "microbit_switch_if.h" #include "KeyValueInt.h" //--------------------------------- // Display //--------------------------------- MicroBitDisplay display; int state; // 状態遷移 char dispChar = 0; // LEDに表示する文字コード char dispCharLast = 0; // 最後に表示した文字コード bool turnOffMode = false; // LED非表示モードのフラグ //----- 数値の表示 static void displayNumber(int data) { if (0<=data && data<=9) { // 1桁はスクロールしない display.print(data); } else { display.scroll(data); } } //--------------------------------- // Flash Memory //--------------------------------- //----- 不揮発メモリの読み出し static int FlashGet(MicroBitStorage storage, const char* key, int init=0) { KeyValuePair* kvp = storage.get(key); if(kvp != NULL) { int data; memcpy(&data, kvp->value, sizeof(int)); DEBUG("== FlashGet exist %s = %d\r\n", key, data); return data; } return init; } //----- 不揮発メモリの書き込み // MICROBIT_OK = 0 // MICROBIT_INVALID_PARAMETER = -1001, // MICROBIT_NO_RESOURCES = -1005, static int FlashPut(MicroBitStorage storage, const char* key, int data) { int ret = storage.put(key, (uint8_t *)&data, sizeof(int)); DEBUG("== FlashPut %s %d %d\r\n", key, data, ret); return ret; } //--------------------------------- // Setting //--------------------------------- bool setting_inc; // 設定値を増加 bool setting_enter; // 設定値を入力 bool setting_next; // 次の設定値に移動 KeyValueInt kviKeyCode1("keycode1",'S', 1, 1, NUM_GROUP1, true); KeyValueInt kviKeyCode2("keycode2",'T', 1, 1, NUM_GROUP2, true); //----- パラメータ設定 static int paraSettingOne(MicroBitStorage storage, KeyValueInt* para, bool change) { display.print(para->disp); // 識別文字をLED表示 wait(SETTING_DISPLAY_WAIT); displayNumber(para->value); // 値をLED表示 if (!change) { wait(SETTING_DISPLAY_WAIT); return 0; } DEBUG("== paraSetting\r\n"); setting_inc = false; setting_next = setting_enter = false; while( ! setting_next) { // Bボタンが離されるまで if (setting_inc) { // Aボタンが押されたら setting_inc = false; para->inc(); displayNumber(para->value); } wait(0.2); } if (FlashPut(storage, para->key, para->value)) { dispChar = 'e'; return -1; } else { dispChar = 0; return 0; } } static void paraSetting(bool change) { MicroBitStorage storage; kviKeyCode1.set(FlashGet(storage, kviKeyCode1.key, 1)); kviKeyCode2.set(FlashGet(storage, kviKeyCode2.key, 1)); int err = paraSettingOne(storage, &kviKeyCode1, change); if (err) return; paraSettingOne(storage, &kviKeyCode2, change); } //--------------------------------- // BLE & HID //--------------------------------- BLE ble; KeyboardService *kbdServicePtr; //----- BLE接続が切断された static void onDisconnect(const Gap::DisconnectionCallbackParams_t *params) { DEBUG("(BLE)disconnected\r\n"); ble.gap().startAdvertising(); // restart advertising dispChar = 0; } //----- BLE接続された static void onConnect(const Gap::ConnectionCallbackParams_t *params) { if(kbdServicePtr->isConnected()) { DEBUG("(BLE)connected\r\n"); dispChar = 'C'; } } //----- BLE接続待ち状態 static void waiting() { if (!kbdServicePtr->isConnected()) { dispChar ='W'; } } //----- パスキー表示 static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey) { printf("(BLE)Input passKey: "); for (unsigned i = 0; i < Gap::ADDR_LEN; i++) { printf("%c", passkey[i]); } printf("\r\n"); } //----- セキュリティ設定完了 static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status) { if (status == SecurityManager::SEC_STATUS_SUCCESS) { // DEBUG("(BLE)Security success %d\r\n", status); dispChar = 'P'; } else { // DEBUG("(BLE)Security failed %d\r\n", status); dispChar = 'F'; } } //----- セキュリティ初期設定 static void securitySetupInitiatedCallback(Gap::Handle_t, bool allowBonding, bool requireMITM, SecurityManager::SecurityIOCapabilities_t iocaps) { DEBUG("(BLE)Security setup initiated\r\n"); } //----- セキュリティ初期設定 static void initializeSecurity(BLE &ble) { bool enableBonding = true; bool requireMITM = HID_SECURITY_REQUIRE_MITM; ble.securityManager().onSecuritySetupInitiated(securitySetupInitiatedCallback); ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback); ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback); ble.securityManager().init(enableBonding, requireMITM, HID_SECURITY_IOCAPS); } //----- HOGP (HID Over GATT Profile) 初期化 static void initializeHOGP(BLE &ble) { static const uint16_t uuid16_list[] = {GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE, GattService::UUID_DEVICE_INFORMATION_SERVICE, GattService::UUID_BATTERY_SERVICE }; PnPID_t pnpID; pnpID.vendorID_source = 0x2; // from the USB Implementer's Forum pnpID.vendorID = 0x0D28; // NXP pnpID.productID = 0x0204; // CMSIS-DAP (well, it's a keyboard but oh well) pnpID.productVersion = 0x0100; // v1.0 HIDDeviceInformationService deviceInfo(ble, "ARM", "m1", "abc", "def", "ghi", "jkl", &pnpID); BatteryService batteryInfo(ble, 80); ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); // see 5.1.2: HID over GATT Specification (pg. 25) ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); // 30ms to 50ms is recommended (5.1.2) ble.gap().setAdvertisingInterval(50); } //----- BLE接続のHID(human interface device) の初期化 static void initialize_BLE_HID() { static const char SHORT_DEVICE_NAME[] = "micro:bit"; static char DeviceName[20]; int id = microbit_serial_number()& 0xfff; // シリアル番号の下12桁を4桁の10進で表示 sprintf(DeviceName, "micro:bit %04d", id); DEBUG("(BLE)id %s\r\n", DeviceName); // DEBUG("(BLE)initialising ble\r\n"); ble.init(); ble.gap().onDisconnection(onDisconnect); ble.gap().onConnection(onConnect); initializeSecurity(ble); DEBUG("(BLE)adding hid service\r\n"); KeyboardService kbdService(ble); kbdServicePtr = &kbdService; DEBUG("(BLE)adding device info and battery service\r\n"); initializeHOGP(ble); DEBUG("(BLE)setting up gap\r\n"); ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::KEYBOARD); ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DeviceName, sizeof(DeviceName)); ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, (uint8_t *)SHORT_DEVICE_NAME, sizeof(SHORT_DEVICE_NAME)); ble.gap().setDeviceName((const uint8_t *)DeviceName); DEBUG("(BLE)advertising\r\n"); ble.gap().startAdvertising(); } //--------------------------------- // Button //--------------------------------- MicroBitMessageBus bus; MicroBitButton buttonA(MICROBIT_PIN_BUTTON_A, MICROBIT_ID_BUTTON_A); MicroBitButton buttonB(MICROBIT_PIN_BUTTON_B, MICROBIT_ID_BUTTON_B); MicroBitButton button0(MICROBIT_PIN_P0, MICROBIT_ID_IO_P0, MICROBIT_BUTTON_ALL_EVENTS, PullUp); MicroBitButton button1(MICROBIT_PIN_P1, MICROBIT_ID_IO_P1, MICROBIT_BUTTON_ALL_EVENTS, PullUp); MicroBitButton button2(MICROBIT_PIN_P2, MICROBIT_ID_IO_P2, MICROBIT_BUTTON_ALL_EVENTS, PullUp); static void sendKeyCode(int code) { if (code) { uint8_t key = code & 0xff; uint8_t modif = code >> 8; if (key > KEYMAP_SIZE ) { dispChar ='I'; // キーコード設定間違い } else { ble_error_t ret = kbdServicePtr->keyDownCode(key, modif); // DEBUG(" code=%d modif=%d\r\n",key , modif); if (ret) { dispChar ='E'; dispCharLast =0; // E が続く時に表示 DEBUG("(BLE)Error %d\r\n",ret); } } } } //----- ボタン保持時イベント static void onButtonHold(MicroBitEvent e) { if ((e.source == MICROBIT_ID_BUTTON_A && buttonB.isPressed()) || (e.source == MICROBIT_ID_BUTTON_B && buttonA.isPressed()) ) { dispChar = 'H'; sendKeyCode(keyCodeGroup0[2]); } } //----- ボタン押下げ時イベント static void onButtonDown(MicroBitEvent e) { // DEBUG(" Button Down %d state=%d\r\n", e.source, state); switch (state) { case STATE_SETTING : switch(e.source) { case MICROBIT_ID_BUTTON_A : setting_inc = true; break; case MICROBIT_ID_BUTTON_B : setting_enter = true; break; } break; case STATE_OPERATING : int code = 0; switch(e.source) { case MICROBIT_ID_BUTTON_A : dispChar = 'A'; code = keyCodeGroup0[0]; break; case MICROBIT_ID_BUTTON_B : dispChar = 'B'; code = keyCodeGroup0[1]; break; case MICROBIT_ID_IO_P0 : dispChar = '1'; code = keyCodeGroup1[kviKeyCode1.value-1][0]; break; case MICROBIT_ID_IO_P1 : dispChar = '2'; code = keyCodeGroup1[kviKeyCode1.value-1][1]; break; case MICROBIT_ID_IO_P2 : dispChar = '3'; code = keyCodeGroup2[kviKeyCode2.value-1]; break; } sendKeyCode(code); } } //----- ボタン離し時イベント static void onButtonUp(MicroBitEvent e) { // DEBUG(" Button up %d\r\n", e.source); switch (state) { case STATE_SETTING : if(setting_enter) setting_next = true; // 決定ボタンを離したら次へ break; case STATE_OPERATING : dispChar = 0; ble_error_t ret = kbdServicePtr->keyUpCode(); if (ret) { dispChar ='E'; dispCharLast =0; // E が続く時に表示 } } } //--------------------------------- // Main //--------------------------------- int main() { state = STATE_NORMAL; wait(0.1); // ボタン状態の更新 bool bA = buttonA.isPressed(); bool bB = buttonB.isPressed(); if (bA && bB) { // ボタンABを押しながら起動 while(1) { display.scroll(VERSION); wait(0.5); } } else if(bA) // ボタンAを押しながら起動 state = STATE_SETTING; //----- Display display.setDisplayMode(DISPLAY_MODE_BLACK_AND_WHITE); display.clear(); Timer dispTime; // 連続表示タイマー dispTime.start(); //----- Button bus.listen(MICROBIT_ID_ANY, MICROBIT_BUTTON_EVT_DOWN, onButtonDown); bus.listen(MICROBIT_ID_ANY, MICROBIT_BUTTON_EVT_UP, onButtonUp); bus.listen(MICROBIT_ID_ANY, MICROBIT_BUTTON_EVT_HOLD, onButtonHold); //----- Setting paraSetting(state == STATE_SETTING); state = STATE_OPERATING; //----- BLE & HID Ticker heartbeat; heartbeat.attach(waiting, 1); // 1秒毎に関数waiting を呼び出す initialize_BLE_HID(); display.clear(); //----- Loop while (true) { ble.waitForEvent(); // BLEイベントを待つ if (dispChar != dispCharLast) { // 表示文字が変更 turnOffMode = false; dispTime.reset(); display.enable(); if (dispChar) display.printChar(dispChar); else display.clear(); } if (!turnOffMode) { if (dispTime.read() > TIME_TURN_OFF) { // 長時間表示 turnOffMode = true; display.disable(); } } dispCharLast = dispChar; } }