Initial release
main.cpp
- Committer:
- masakjm
- Date:
- 2018-11-25
- Revision:
- 4:4fe5674bf409
- Parent:
- 3:b6e9850d3e76
- Child:
- 5:80cb8f9db01e
File content as of revision 4:4fe5674bf409:
//================================= // microbit_switch_if_3sw //================================= // BLE switch interface with 3 tact switches or 3 touch sensors 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 // 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 //--------------------------------- #define VERSION "3SW-181125" //#define NO_DEBUG #include "microbit_switch_if_3sw.h" #include "KeyValueInt.h" //--------------------------------- // Display //--------------------------------- MicroBitDisplay display; int state; // 状態遷移 char dispChar = 0; // LEDに表示する文字コード char dispCharLast = 0; // 最後に表示した文字コード bool turnOffMode = false; // LED非表示モードのフラグ /** ---------- * @brief 整数値をLEDに表示する * @param data 整数値 */ static void displayNumber(int data) { if (0<=data && data<=9) { // 1桁はスクロールしない display.print(data); } else { display.scroll(data); } } //--------------------------------- // Flash Memory //--------------------------------- /** ---------- * @brief キー名を指定して不揮発メモリから値を読み出す * @param key キー名 * @param init データが保存されていなかった時の初期値 * @return int 取得したデータ */ 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; } /** ---------- * @brief 不揮発メモリに値を書き込む * @param storage 不揮発メモリインスタンス * @param key キー名 * @param data 値 * @return int 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); /** ---------- * @brief 1つのパラメータの表示と変更 * @param storage 不揮発メモリインスタンス * @param para パラメータのキーと値の組 * @param change 変更する時 true * @return bool true : Success false : Failed */ static bool 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 true; } 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); } int ret = FlashPut(storage, para->key, para->value); if (ret) DEBUG("(strage)Error %d\r\n",ret); return (ret == MICROBIT_OK); } /** ---------- * @brief パラメータの表示と変更 * @param change true:変更する時 */ static bool paraSetting(bool change=false) { MicroBitStorage storage; kviKeyCode1.set(FlashGet(storage, kviKeyCode1.key, 1)); kviKeyCode2.set(FlashGet(storage, kviKeyCode2.key, 1)); if(!paraSettingOne(storage, &kviKeyCode1, change)) return false; return paraSettingOne(storage, &kviKeyCode2, change); } //--------------------------------- // BLE & HID //--------------------------------- BLE ble; KeyboardService *kbdServicePtr; BLE_MESSAGE bleMessage; /** ---------- * @brief BLE接続が切断された時のコールバック関数 */ static void onDisconnect(const Gap::DisconnectionCallbackParams_t *params) { DEBUG("(BLE)disconnected\r\n"); ble.gap().startAdvertising(); // restart advertising bleMessage = BLE_NO_MESSAGE; } /** ---------- * @brief BLE接続が接続された時のコールバック関数 */ static void onConnect(const Gap::ConnectionCallbackParams_t *params) { if(kbdServicePtr->isConnected()) { DEBUG("(BLE)connected\r\n"); ble.gap().stopAdvertising(); bleMessage = BLE_CONNECTED; } } /** ---------- * @brief パスキー入力を求められた時のコールバック関数 */ 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"); } /** ---------- * @brief セキュリティ設定完了時のコールバック関数 */ 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); bleMessage = BLE_PAIRING_SUCCESS; } else { // DEBUG("(BLE)Security failed %d\r\n", status); bleMessage = BLE_PAIRING_FAILED; } } /** ---------- * @brief セキュリティ初期化 * @para _ble BLEインスタンス */ static void initializeSecurity(BLE &_ble) { bool enableBonding = true; bool requireMITM = HID_SECURITY_REQUIRE_MITM; _ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback); _ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback); _ble.securityManager().init(enableBonding, requireMITM, HID_SECURITY_IOCAPS); } /** ---------- * @brief HOGP (HID Over GATT Profile) 初期化 * @para _ble BLEインスタンス */ 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); } /** ---------- * @brief 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); MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ALL); MicroBitPin P1(MICROBIT_ID_IO_P1, MICROBIT_PIN_P1, PIN_CAPABILITY_ALL); MicroBitPin P2(MICROBIT_ID_IO_P2, MICROBIT_PIN_P2, PIN_CAPABILITY_ALL); //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); /** ---------- * @brief キーコードを送信する * @para code 上位8bit:修飾キー 下位8bit:キーコード */ 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); } } } } /** ---------- * @brief ボタン保持時イベント * @para e イベント */ 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]); } } /** ---------- * @brief ボタン押下げ時イベント * @para e イベント */ 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); } } /** ---------- * @brief ボタン離し時イベント * @para e イベント */ 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_DESABLE_INPUT; wait(0.1); // ボタン状態の更新 bool bA = buttonA.isPressed(); bool bB = buttonB.isPressed(); if (bA && bB) { // ボタンABを押しながら起動 for(int i=0;i<3;i++) { 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); // Put the P0, P1 and P2 pins into touch sense mode. P0.isTouched(); P1.isTouched(); P2.isTouched(); //----- Setting if (paraSetting(state == STATE_SETTING)) dispChar =0; else dispChar ='e'; //----- BLE & HID state = STATE_DESABLE_INPUT; initialize_BLE_HID(); display.clear(); //----- Loop state = STATE_OPERATING; while (true) { ble.waitForEvent(); // BLEイベントを待つ if(bleMessage != BLE_NO_MESSAGE) { // BLEの状態を表示する dispChar = bleDispChar[bleMessage]; bleMessage = BLE_NO_MESSAGE; } 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; } }