BLE switch interface with GROVE joystic for micro:bit http://mahoro-ba.net/e2073.html
main.cpp@11:8e0b379efcb3, 2019-02-22 (annotated)
- Committer:
- masakjm
- Date:
- Fri Feb 22 21:17:13 2019 +0000
- Revision:
- 11:8e0b379efcb3
- Parent:
- 7:e2779d2fef9c
- Child:
- 12:7fb193872bec
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
masakjm | 0:28fb3e9ef81a | 1 | //================================= |
masakjm | 7:e2779d2fef9c | 2 | // microbit_switch_if_joy |
masakjm | 0:28fb3e9ef81a | 3 | //================================= |
masakjm | 7:e2779d2fef9c | 4 | // BLE switch interface with GROVE joystic for micro:bit |
masakjm | 0:28fb3e9ef81a | 5 | // It is intended for use with ios devices. |
masakjm | 0:28fb3e9ef81a | 6 | // |
masakjm | 7:e2779d2fef9c | 7 | // The MIT License (MIT) Copyright (c) 2019 Masatomo Kojima |
masakjm | 0:28fb3e9ef81a | 8 | // |
masakjm | 0:28fb3e9ef81a | 9 | // LED message |
masakjm | 6:bd39b12d4ac8 | 10 | // S key code setting P1,P2 |
masakjm | 6:bd39b12d4ac8 | 11 | // T key code setting P0 |
masakjm | 0:28fb3e9ef81a | 12 | // C Conected |
masakjm | 0:28fb3e9ef81a | 13 | // P success Pearing |
masakjm | 0:28fb3e9ef81a | 14 | // F Fail pearing |
masakjm | 0:28fb3e9ef81a | 15 | // E Error at sending data by ble |
masakjm | 0:28fb3e9ef81a | 16 | // e Error at writting data to flash memory |
masakjm | 0:28fb3e9ef81a | 17 | // I Error by Incorrect cording |
masakjm | 7:e2779d2fef9c | 18 | // G GROVE sensor connect error |
masakjm | 0:28fb3e9ef81a | 19 | //--------------------------------- |
masakjm | 0:28fb3e9ef81a | 20 | |
masakjm | 7:e2779d2fef9c | 21 | #define VERSION "JOY-190218" |
masakjm | 7:e2779d2fef9c | 22 | #define NO_DEBUG |
masakjm | 0:28fb3e9ef81a | 23 | |
masakjm | 7:e2779d2fef9c | 24 | #include "microbit_switch_if_joy.h" |
masakjm | 0:28fb3e9ef81a | 25 | #include "KeyValueInt.h" |
masakjm | 0:28fb3e9ef81a | 26 | |
masakjm | 0:28fb3e9ef81a | 27 | //--------------------------------- |
masakjm | 0:28fb3e9ef81a | 28 | // Display |
masakjm | 0:28fb3e9ef81a | 29 | //--------------------------------- |
masakjm | 0:28fb3e9ef81a | 30 | MicroBitDisplay display; |
masakjm | 7:e2779d2fef9c | 31 | int State; // 状態遷移 |
masakjm | 7:e2779d2fef9c | 32 | char DispChar = 0; // LEDに表示する文字コード |
masakjm | 7:e2779d2fef9c | 33 | char DispCharLast = 0; // 最後に表示した文字コード |
masakjm | 7:e2779d2fef9c | 34 | bool TurnOffMode = false; // LED非表示モードのフラグ |
masakjm | 0:28fb3e9ef81a | 35 | |
masakjm | 7:e2779d2fef9c | 36 | //--------------------------------- |
masakjm | 7:e2779d2fef9c | 37 | // GROVE Joystick |
masakjm | 7:e2779d2fef9c | 38 | //--------------------------------- |
masakjm | 7:e2779d2fef9c | 39 | |
masakjm | 7:e2779d2fef9c | 40 | AnalogIn AnalogP1(MICROBIT_PIN_P1); |
masakjm | 7:e2779d2fef9c | 41 | AnalogIn AnalogP2(MICROBIT_PIN_P2); |
masakjm | 7:e2779d2fef9c | 42 | |
masakjm | 3:b6e9850d3e76 | 43 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 44 | * @brief 整数値をLEDに表示する |
masakjm | 3:b6e9850d3e76 | 45 | * @param data 整数値 |
masakjm | 3:b6e9850d3e76 | 46 | */ |
masakjm | 0:28fb3e9ef81a | 47 | static void displayNumber(int data) |
masakjm | 0:28fb3e9ef81a | 48 | { |
masakjm | 0:28fb3e9ef81a | 49 | if (0<=data && data<=9) { // 1桁はスクロールしない |
masakjm | 0:28fb3e9ef81a | 50 | display.print(data); |
masakjm | 0:28fb3e9ef81a | 51 | } else { |
masakjm | 0:28fb3e9ef81a | 52 | display.scroll(data); |
masakjm | 0:28fb3e9ef81a | 53 | } |
masakjm | 0:28fb3e9ef81a | 54 | } |
masakjm | 0:28fb3e9ef81a | 55 | |
masakjm | 0:28fb3e9ef81a | 56 | //--------------------------------- |
masakjm | 0:28fb3e9ef81a | 57 | // Flash Memory |
masakjm | 0:28fb3e9ef81a | 58 | //--------------------------------- |
masakjm | 3:b6e9850d3e76 | 59 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 60 | * @brief キー名を指定して不揮発メモリから値を読み出す |
masakjm | 3:b6e9850d3e76 | 61 | * @param key キー名 |
masakjm | 3:b6e9850d3e76 | 62 | * @param init データが保存されていなかった時の初期値 |
masakjm | 3:b6e9850d3e76 | 63 | * @return int 取得したデータ |
masakjm | 3:b6e9850d3e76 | 64 | */ |
masakjm | 0:28fb3e9ef81a | 65 | static int FlashGet(MicroBitStorage storage, const char* key, int init=0) |
masakjm | 0:28fb3e9ef81a | 66 | { |
masakjm | 0:28fb3e9ef81a | 67 | KeyValuePair* kvp = storage.get(key); |
masakjm | 0:28fb3e9ef81a | 68 | if(kvp != NULL) { |
masakjm | 0:28fb3e9ef81a | 69 | int data; |
masakjm | 0:28fb3e9ef81a | 70 | memcpy(&data, kvp->value, sizeof(int)); |
masakjm | 0:28fb3e9ef81a | 71 | DEBUG("== FlashGet exist %s = %d\r\n", key, data); |
masakjm | 0:28fb3e9ef81a | 72 | return data; |
masakjm | 0:28fb3e9ef81a | 73 | } |
masakjm | 0:28fb3e9ef81a | 74 | return init; |
masakjm | 0:28fb3e9ef81a | 75 | } |
masakjm | 0:28fb3e9ef81a | 76 | |
masakjm | 3:b6e9850d3e76 | 77 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 78 | * @brief 不揮発メモリに値を書き込む |
masakjm | 3:b6e9850d3e76 | 79 | * @param storage 不揮発メモリインスタンス |
masakjm | 3:b6e9850d3e76 | 80 | * @param key キー名 |
masakjm | 3:b6e9850d3e76 | 81 | * @param data 値 |
masakjm | 3:b6e9850d3e76 | 82 | * @return int MICROBIT_OK = 0 |
masakjm | 3:b6e9850d3e76 | 83 | * MICROBIT_INVALID_PARAMETER = -1001, |
masakjm | 3:b6e9850d3e76 | 84 | * MICROBIT_NO_RESOURCES = -1005, |
masakjm | 3:b6e9850d3e76 | 85 | */ |
masakjm | 0:28fb3e9ef81a | 86 | static int FlashPut(MicroBitStorage storage, const char* key, int data) |
masakjm | 0:28fb3e9ef81a | 87 | { |
masakjm | 0:28fb3e9ef81a | 88 | int ret = storage.put(key, (uint8_t *)&data, sizeof(int)); |
masakjm | 0:28fb3e9ef81a | 89 | DEBUG("== FlashPut %s %d %d\r\n", key, data, ret); |
masakjm | 0:28fb3e9ef81a | 90 | return ret; |
masakjm | 0:28fb3e9ef81a | 91 | } |
masakjm | 0:28fb3e9ef81a | 92 | |
masakjm | 0:28fb3e9ef81a | 93 | //--------------------------------- |
masakjm | 0:28fb3e9ef81a | 94 | // Setting |
masakjm | 0:28fb3e9ef81a | 95 | //--------------------------------- |
masakjm | 0:28fb3e9ef81a | 96 | bool setting_inc; // 設定値を増加 |
masakjm | 0:28fb3e9ef81a | 97 | bool setting_enter; // 設定値を入力 |
masakjm | 0:28fb3e9ef81a | 98 | bool setting_next; // 次の設定値に移動 |
masakjm | 0:28fb3e9ef81a | 99 | |
masakjm | 0:28fb3e9ef81a | 100 | KeyValueInt kviKeyCode1("keycode1",'S', 1, 1, NUM_GROUP1, true); |
masakjm | 0:28fb3e9ef81a | 101 | |
masakjm | 3:b6e9850d3e76 | 102 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 103 | * @brief 1つのパラメータの表示と変更 |
masakjm | 3:b6e9850d3e76 | 104 | * @param storage 不揮発メモリインスタンス |
masakjm | 3:b6e9850d3e76 | 105 | * @param para パラメータのキーと値の組 |
masakjm | 3:b6e9850d3e76 | 106 | * @param change 変更する時 true |
masakjm | 3:b6e9850d3e76 | 107 | * @return bool true : Success false : Failed |
masakjm | 3:b6e9850d3e76 | 108 | */ |
masakjm | 3:b6e9850d3e76 | 109 | static bool paraSettingOne(MicroBitStorage storage, KeyValueInt* para, bool change) |
masakjm | 0:28fb3e9ef81a | 110 | { |
masakjm | 0:28fb3e9ef81a | 111 | display.print(para->disp); // 識別文字をLED表示 |
masakjm | 0:28fb3e9ef81a | 112 | wait(SETTING_DISPLAY_WAIT); |
masakjm | 0:28fb3e9ef81a | 113 | displayNumber(para->value); // 値をLED表示 |
masakjm | 0:28fb3e9ef81a | 114 | if (!change) { |
masakjm | 0:28fb3e9ef81a | 115 | wait(SETTING_DISPLAY_WAIT); |
masakjm | 3:b6e9850d3e76 | 116 | return true; |
masakjm | 0:28fb3e9ef81a | 117 | } |
masakjm | 0:28fb3e9ef81a | 118 | |
masakjm | 0:28fb3e9ef81a | 119 | DEBUG("== paraSetting\r\n"); |
masakjm | 0:28fb3e9ef81a | 120 | setting_inc = false; |
masakjm | 0:28fb3e9ef81a | 121 | setting_next = setting_enter = false; |
masakjm | 0:28fb3e9ef81a | 122 | while( ! setting_next) { // Bボタンが離されるまで |
masakjm | 0:28fb3e9ef81a | 123 | if (setting_inc) { // Aボタンが押されたら |
masakjm | 0:28fb3e9ef81a | 124 | setting_inc = false; |
masakjm | 0:28fb3e9ef81a | 125 | para->inc(); |
masakjm | 0:28fb3e9ef81a | 126 | displayNumber(para->value); |
masakjm | 0:28fb3e9ef81a | 127 | } |
masakjm | 0:28fb3e9ef81a | 128 | wait(0.2); |
masakjm | 0:28fb3e9ef81a | 129 | } |
masakjm | 3:b6e9850d3e76 | 130 | int ret = FlashPut(storage, para->key, para->value); |
masakjm | 3:b6e9850d3e76 | 131 | if (ret) DEBUG("(strage)Error %d\r\n",ret); |
masakjm | 3:b6e9850d3e76 | 132 | return (ret == MICROBIT_OK); |
masakjm | 0:28fb3e9ef81a | 133 | } |
masakjm | 0:28fb3e9ef81a | 134 | |
masakjm | 3:b6e9850d3e76 | 135 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 136 | * @brief パラメータの表示と変更 |
masakjm | 3:b6e9850d3e76 | 137 | * @param change true:変更する時 |
masakjm | 3:b6e9850d3e76 | 138 | */ |
masakjm | 3:b6e9850d3e76 | 139 | static bool paraSetting(bool change=false) |
masakjm | 0:28fb3e9ef81a | 140 | { |
masakjm | 0:28fb3e9ef81a | 141 | MicroBitStorage storage; |
masakjm | 0:28fb3e9ef81a | 142 | |
masakjm | 0:28fb3e9ef81a | 143 | kviKeyCode1.set(FlashGet(storage, kviKeyCode1.key, 1)); |
masakjm | 7:e2779d2fef9c | 144 | return paraSettingOne(storage, &kviKeyCode1, change); |
masakjm | 0:28fb3e9ef81a | 145 | } |
masakjm | 0:28fb3e9ef81a | 146 | //--------------------------------- |
masakjm | 0:28fb3e9ef81a | 147 | // BLE & HID |
masakjm | 0:28fb3e9ef81a | 148 | //--------------------------------- |
masakjm | 0:28fb3e9ef81a | 149 | BLE ble; |
masakjm | 0:28fb3e9ef81a | 150 | KeyboardService *kbdServicePtr; |
masakjm | 3:b6e9850d3e76 | 151 | BLE_MESSAGE bleMessage; |
masakjm | 0:28fb3e9ef81a | 152 | |
masakjm | 3:b6e9850d3e76 | 153 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 154 | * @brief BLE接続が切断された時のコールバック関数 |
masakjm | 3:b6e9850d3e76 | 155 | */ |
masakjm | 0:28fb3e9ef81a | 156 | static void onDisconnect(const Gap::DisconnectionCallbackParams_t *params) |
masakjm | 0:28fb3e9ef81a | 157 | { |
masakjm | 0:28fb3e9ef81a | 158 | DEBUG("(BLE)disconnected\r\n"); |
masakjm | 0:28fb3e9ef81a | 159 | ble.gap().startAdvertising(); // restart advertising |
masakjm | 3:b6e9850d3e76 | 160 | bleMessage = BLE_NO_MESSAGE; |
masakjm | 0:28fb3e9ef81a | 161 | } |
masakjm | 0:28fb3e9ef81a | 162 | |
masakjm | 3:b6e9850d3e76 | 163 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 164 | * @brief BLE接続が接続された時のコールバック関数 |
masakjm | 3:b6e9850d3e76 | 165 | */ |
masakjm | 0:28fb3e9ef81a | 166 | static void onConnect(const Gap::ConnectionCallbackParams_t *params) |
masakjm | 0:28fb3e9ef81a | 167 | { |
masakjm | 0:28fb3e9ef81a | 168 | if(kbdServicePtr->isConnected()) { |
masakjm | 0:28fb3e9ef81a | 169 | DEBUG("(BLE)connected\r\n"); |
masakjm | 3:b6e9850d3e76 | 170 | ble.gap().stopAdvertising(); |
masakjm | 3:b6e9850d3e76 | 171 | bleMessage = BLE_CONNECTED; |
masakjm | 0:28fb3e9ef81a | 172 | } |
masakjm | 0:28fb3e9ef81a | 173 | } |
masakjm | 0:28fb3e9ef81a | 174 | |
masakjm | 3:b6e9850d3e76 | 175 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 176 | * @brief パスキー入力を求められた時のコールバック関数 |
masakjm | 3:b6e9850d3e76 | 177 | */ |
masakjm | 0:28fb3e9ef81a | 178 | static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey) |
masakjm | 0:28fb3e9ef81a | 179 | { |
masakjm | 0:28fb3e9ef81a | 180 | printf("(BLE)Input passKey: "); |
masakjm | 0:28fb3e9ef81a | 181 | for (unsigned i = 0; i < Gap::ADDR_LEN; i++) { |
masakjm | 0:28fb3e9ef81a | 182 | printf("%c", passkey[i]); |
masakjm | 0:28fb3e9ef81a | 183 | } |
masakjm | 0:28fb3e9ef81a | 184 | printf("\r\n"); |
masakjm | 0:28fb3e9ef81a | 185 | } |
masakjm | 0:28fb3e9ef81a | 186 | |
masakjm | 3:b6e9850d3e76 | 187 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 188 | * @brief セキュリティ設定完了時のコールバック関数 |
masakjm | 3:b6e9850d3e76 | 189 | */ |
masakjm | 0:28fb3e9ef81a | 190 | static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status) |
masakjm | 0:28fb3e9ef81a | 191 | { |
masakjm | 0:28fb3e9ef81a | 192 | if (status == SecurityManager::SEC_STATUS_SUCCESS) { |
masakjm | 0:28fb3e9ef81a | 193 | // DEBUG("(BLE)Security success %d\r\n", status); |
masakjm | 3:b6e9850d3e76 | 194 | bleMessage = BLE_PAIRING_SUCCESS; |
masakjm | 0:28fb3e9ef81a | 195 | |
masakjm | 0:28fb3e9ef81a | 196 | } else { |
masakjm | 0:28fb3e9ef81a | 197 | // DEBUG("(BLE)Security failed %d\r\n", status); |
masakjm | 3:b6e9850d3e76 | 198 | bleMessage = BLE_PAIRING_FAILED; |
masakjm | 0:28fb3e9ef81a | 199 | } |
masakjm | 0:28fb3e9ef81a | 200 | } |
masakjm | 0:28fb3e9ef81a | 201 | |
masakjm | 3:b6e9850d3e76 | 202 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 203 | * @brief セキュリティ初期化 |
masakjm | 3:b6e9850d3e76 | 204 | * @para _ble BLEインスタンス |
masakjm | 3:b6e9850d3e76 | 205 | */ |
masakjm | 3:b6e9850d3e76 | 206 | static void initializeSecurity(BLE &_ble) |
masakjm | 0:28fb3e9ef81a | 207 | { |
masakjm | 0:28fb3e9ef81a | 208 | bool enableBonding = true; |
masakjm | 0:28fb3e9ef81a | 209 | bool requireMITM = HID_SECURITY_REQUIRE_MITM; |
masakjm | 0:28fb3e9ef81a | 210 | |
masakjm | 3:b6e9850d3e76 | 211 | _ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback); |
masakjm | 3:b6e9850d3e76 | 212 | _ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback); |
masakjm | 0:28fb3e9ef81a | 213 | |
masakjm | 3:b6e9850d3e76 | 214 | _ble.securityManager().init(enableBonding, requireMITM, HID_SECURITY_IOCAPS); |
masakjm | 0:28fb3e9ef81a | 215 | } |
masakjm | 0:28fb3e9ef81a | 216 | |
masakjm | 3:b6e9850d3e76 | 217 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 218 | * @brief HOGP (HID Over GATT Profile) 初期化 |
masakjm | 3:b6e9850d3e76 | 219 | * @para _ble BLEインスタンス |
masakjm | 3:b6e9850d3e76 | 220 | */ |
masakjm | 3:b6e9850d3e76 | 221 | static void initializeHOGP(BLE &_ble) |
masakjm | 0:28fb3e9ef81a | 222 | { |
masakjm | 0:28fb3e9ef81a | 223 | static const uint16_t uuid16_list[] = {GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE, |
masakjm | 0:28fb3e9ef81a | 224 | GattService::UUID_DEVICE_INFORMATION_SERVICE, |
masakjm | 0:28fb3e9ef81a | 225 | GattService::UUID_BATTERY_SERVICE |
masakjm | 0:28fb3e9ef81a | 226 | }; |
masakjm | 0:28fb3e9ef81a | 227 | |
masakjm | 0:28fb3e9ef81a | 228 | PnPID_t pnpID; |
masakjm | 0:28fb3e9ef81a | 229 | pnpID.vendorID_source = 0x2; // from the USB Implementer's Forum |
masakjm | 0:28fb3e9ef81a | 230 | pnpID.vendorID = 0x0D28; // NXP |
masakjm | 0:28fb3e9ef81a | 231 | pnpID.productID = 0x0204; // CMSIS-DAP (well, it's a keyboard but oh well) |
masakjm | 0:28fb3e9ef81a | 232 | pnpID.productVersion = 0x0100; // v1.0 |
masakjm | 3:b6e9850d3e76 | 233 | HIDDeviceInformationService deviceInfo(_ble, "ARM", "m1", "abc", "def", "ghi", "jkl", &pnpID); |
masakjm | 0:28fb3e9ef81a | 234 | |
masakjm | 3:b6e9850d3e76 | 235 | BatteryService batteryInfo(_ble, 80); |
masakjm | 0:28fb3e9ef81a | 236 | |
masakjm | 3:b6e9850d3e76 | 237 | _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | |
masakjm | 0:28fb3e9ef81a | 238 | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
masakjm | 3:b6e9850d3e76 | 239 | _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, |
masakjm | 0:28fb3e9ef81a | 240 | (uint8_t *)uuid16_list, sizeof(uuid16_list)); |
masakjm | 0:28fb3e9ef81a | 241 | |
masakjm | 0:28fb3e9ef81a | 242 | // see 5.1.2: HID over GATT Specification (pg. 25) |
masakjm | 3:b6e9850d3e76 | 243 | _ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
masakjm | 0:28fb3e9ef81a | 244 | // 30ms to 50ms is recommended (5.1.2) |
masakjm | 3:b6e9850d3e76 | 245 | _ble.gap().setAdvertisingInterval(50); |
masakjm | 0:28fb3e9ef81a | 246 | } |
masakjm | 0:28fb3e9ef81a | 247 | |
masakjm | 3:b6e9850d3e76 | 248 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 249 | * @brief BLE接続のHID(human interface device) の初期化 |
masakjm | 3:b6e9850d3e76 | 250 | */ |
masakjm | 0:28fb3e9ef81a | 251 | static void initialize_BLE_HID() |
masakjm | 0:28fb3e9ef81a | 252 | { |
masakjm | 0:28fb3e9ef81a | 253 | static const char SHORT_DEVICE_NAME[] = "micro:bit"; |
masakjm | 0:28fb3e9ef81a | 254 | static char DeviceName[20]; |
masakjm | 0:28fb3e9ef81a | 255 | |
masakjm | 0:28fb3e9ef81a | 256 | int id = microbit_serial_number()& 0xfff; // シリアル番号の下12桁を4桁の10進で表示 |
masakjm | 0:28fb3e9ef81a | 257 | sprintf(DeviceName, "micro:bit %04d", id); |
masakjm | 0:28fb3e9ef81a | 258 | DEBUG("(BLE)id %s\r\n", DeviceName); |
masakjm | 0:28fb3e9ef81a | 259 | |
masakjm | 0:28fb3e9ef81a | 260 | // DEBUG("(BLE)initialising ble\r\n"); |
masakjm | 0:28fb3e9ef81a | 261 | ble.init(); |
masakjm | 0:28fb3e9ef81a | 262 | |
masakjm | 0:28fb3e9ef81a | 263 | ble.gap().onDisconnection(onDisconnect); |
masakjm | 0:28fb3e9ef81a | 264 | ble.gap().onConnection(onConnect); |
masakjm | 0:28fb3e9ef81a | 265 | |
masakjm | 0:28fb3e9ef81a | 266 | initializeSecurity(ble); |
masakjm | 0:28fb3e9ef81a | 267 | |
masakjm | 0:28fb3e9ef81a | 268 | DEBUG("(BLE)adding hid service\r\n"); |
masakjm | 0:28fb3e9ef81a | 269 | KeyboardService kbdService(ble); |
masakjm | 0:28fb3e9ef81a | 270 | kbdServicePtr = &kbdService; |
masakjm | 0:28fb3e9ef81a | 271 | |
masakjm | 0:28fb3e9ef81a | 272 | DEBUG("(BLE)adding device info and battery service\r\n"); |
masakjm | 0:28fb3e9ef81a | 273 | initializeHOGP(ble); |
masakjm | 0:28fb3e9ef81a | 274 | |
masakjm | 0:28fb3e9ef81a | 275 | DEBUG("(BLE)setting up gap\r\n"); |
masakjm | 0:28fb3e9ef81a | 276 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::KEYBOARD); |
masakjm | 0:28fb3e9ef81a | 277 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, |
masakjm | 0:28fb3e9ef81a | 278 | (uint8_t *)DeviceName, sizeof(DeviceName)); |
masakjm | 0:28fb3e9ef81a | 279 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, |
masakjm | 0:28fb3e9ef81a | 280 | (uint8_t *)SHORT_DEVICE_NAME, sizeof(SHORT_DEVICE_NAME)); |
masakjm | 0:28fb3e9ef81a | 281 | ble.gap().setDeviceName((const uint8_t *)DeviceName); |
masakjm | 0:28fb3e9ef81a | 282 | |
masakjm | 0:28fb3e9ef81a | 283 | DEBUG("(BLE)advertising\r\n"); |
masakjm | 0:28fb3e9ef81a | 284 | ble.gap().startAdvertising(); |
masakjm | 0:28fb3e9ef81a | 285 | } |
masakjm | 0:28fb3e9ef81a | 286 | |
masakjm | 0:28fb3e9ef81a | 287 | //--------------------------------- |
masakjm | 0:28fb3e9ef81a | 288 | // Button |
masakjm | 0:28fb3e9ef81a | 289 | //--------------------------------- |
masakjm | 0:28fb3e9ef81a | 290 | MicroBitMessageBus bus; |
masakjm | 0:28fb3e9ef81a | 291 | MicroBitButton buttonA(MICROBIT_PIN_BUTTON_A, MICROBIT_ID_BUTTON_A); |
masakjm | 0:28fb3e9ef81a | 292 | MicroBitButton buttonB(MICROBIT_PIN_BUTTON_B, MICROBIT_ID_BUTTON_B); |
masakjm | 4:4fe5674bf409 | 293 | MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ALL); |
masakjm | 0:28fb3e9ef81a | 294 | |
masakjm | 3:b6e9850d3e76 | 295 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 296 | * @brief キーコードを送信する |
masakjm | 3:b6e9850d3e76 | 297 | * @para code 上位8bit:修飾キー 下位8bit:キーコード |
masakjm | 3:b6e9850d3e76 | 298 | */ |
masakjm | 1:3b9ae1dbcdcf | 299 | static void sendKeyCode(int code) { |
masakjm | 1:3b9ae1dbcdcf | 300 | if (code) { |
masakjm | 1:3b9ae1dbcdcf | 301 | uint8_t key = code & 0xff; |
masakjm | 1:3b9ae1dbcdcf | 302 | uint8_t modif = code >> 8; |
masakjm | 1:3b9ae1dbcdcf | 303 | |
masakjm | 1:3b9ae1dbcdcf | 304 | if (key > KEYMAP_SIZE ) { |
masakjm | 7:e2779d2fef9c | 305 | DispChar ='I'; // キーコード設定間違い |
masakjm | 1:3b9ae1dbcdcf | 306 | } else { |
masakjm | 1:3b9ae1dbcdcf | 307 | ble_error_t ret = kbdServicePtr->keyDownCode(key, modif); |
masakjm | 7:e2779d2fef9c | 308 | DEBUG(" code=%d modif=%d\r\n",key , modif); |
masakjm | 1:3b9ae1dbcdcf | 309 | if (ret) { |
masakjm | 7:e2779d2fef9c | 310 | DispChar ='E'; |
masakjm | 7:e2779d2fef9c | 311 | DispCharLast =0; // E が続く時に表示 |
masakjm | 1:3b9ae1dbcdcf | 312 | DEBUG("(BLE)Error %d\r\n",ret); |
masakjm | 1:3b9ae1dbcdcf | 313 | } |
masakjm | 1:3b9ae1dbcdcf | 314 | } |
masakjm | 1:3b9ae1dbcdcf | 315 | } |
masakjm | 1:3b9ae1dbcdcf | 316 | } |
masakjm | 3:b6e9850d3e76 | 317 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 318 | * @brief ボタン保持時イベント |
masakjm | 3:b6e9850d3e76 | 319 | * @para e イベント |
masakjm | 3:b6e9850d3e76 | 320 | */ |
masakjm | 1:3b9ae1dbcdcf | 321 | static void onButtonHold(MicroBitEvent e) |
masakjm | 1:3b9ae1dbcdcf | 322 | { |
masakjm | 1:3b9ae1dbcdcf | 323 | if ((e.source == MICROBIT_ID_BUTTON_A && buttonB.isPressed()) || |
masakjm | 1:3b9ae1dbcdcf | 324 | (e.source == MICROBIT_ID_BUTTON_B && buttonA.isPressed()) ) { |
masakjm | 7:e2779d2fef9c | 325 | DispChar = 'H'; |
masakjm | 1:3b9ae1dbcdcf | 326 | sendKeyCode(keyCodeGroup0[2]); |
masakjm | 1:3b9ae1dbcdcf | 327 | } |
masakjm | 1:3b9ae1dbcdcf | 328 | } |
masakjm | 1:3b9ae1dbcdcf | 329 | |
masakjm | 3:b6e9850d3e76 | 330 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 331 | * @brief ボタン押下げ時イベント |
masakjm | 3:b6e9850d3e76 | 332 | * @para e イベント |
masakjm | 3:b6e9850d3e76 | 333 | */ |
masakjm | 0:28fb3e9ef81a | 334 | static void onButtonDown(MicroBitEvent e) |
masakjm | 0:28fb3e9ef81a | 335 | { |
masakjm | 7:e2779d2fef9c | 336 | // DEBUG(" Button Down %d State=%d\r\n", e.source, State); |
masakjm | 0:28fb3e9ef81a | 337 | |
masakjm | 7:e2779d2fef9c | 338 | switch (State) { |
masakjm | 0:28fb3e9ef81a | 339 | case STATE_SETTING : |
masakjm | 0:28fb3e9ef81a | 340 | switch(e.source) { |
masakjm | 0:28fb3e9ef81a | 341 | case MICROBIT_ID_BUTTON_A : |
masakjm | 0:28fb3e9ef81a | 342 | setting_inc = true; |
masakjm | 0:28fb3e9ef81a | 343 | break; |
masakjm | 0:28fb3e9ef81a | 344 | case MICROBIT_ID_BUTTON_B : |
masakjm | 0:28fb3e9ef81a | 345 | setting_enter = true; |
masakjm | 0:28fb3e9ef81a | 346 | break; |
masakjm | 0:28fb3e9ef81a | 347 | } |
masakjm | 0:28fb3e9ef81a | 348 | break; |
masakjm | 0:28fb3e9ef81a | 349 | case STATE_OPERATING : |
masakjm | 1:3b9ae1dbcdcf | 350 | int code = 0; |
masakjm | 0:28fb3e9ef81a | 351 | switch(e.source) { |
masakjm | 0:28fb3e9ef81a | 352 | case MICROBIT_ID_BUTTON_A : |
masakjm | 7:e2779d2fef9c | 353 | DispChar = 'A'; |
masakjm | 0:28fb3e9ef81a | 354 | code = keyCodeGroup0[0]; |
masakjm | 0:28fb3e9ef81a | 355 | break; |
masakjm | 0:28fb3e9ef81a | 356 | case MICROBIT_ID_BUTTON_B : |
masakjm | 7:e2779d2fef9c | 357 | DispChar = 'B'; |
masakjm | 0:28fb3e9ef81a | 358 | code = keyCodeGroup0[1]; |
masakjm | 0:28fb3e9ef81a | 359 | break; |
masakjm | 0:28fb3e9ef81a | 360 | case MICROBIT_ID_IO_P0 : |
masakjm | 7:e2779d2fef9c | 361 | DispChar = '0'; |
masakjm | 7:e2779d2fef9c | 362 | code = keyCodeGroup1[kviKeyCode1.value-1][JOY_CENTER_PRESS]; |
masakjm | 0:28fb3e9ef81a | 363 | break; |
masakjm | 0:28fb3e9ef81a | 364 | } |
masakjm | 7:e2779d2fef9c | 365 | if (code != 0 )sendKeyCode(code); |
masakjm | 0:28fb3e9ef81a | 366 | } |
masakjm | 0:28fb3e9ef81a | 367 | } |
masakjm | 0:28fb3e9ef81a | 368 | |
masakjm | 3:b6e9850d3e76 | 369 | /** ---------- |
masakjm | 3:b6e9850d3e76 | 370 | * @brief ボタン離し時イベント |
masakjm | 3:b6e9850d3e76 | 371 | * @para e イベント |
masakjm | 3:b6e9850d3e76 | 372 | */ |
masakjm | 0:28fb3e9ef81a | 373 | static void onButtonUp(MicroBitEvent e) |
masakjm | 0:28fb3e9ef81a | 374 | { |
masakjm | 0:28fb3e9ef81a | 375 | // DEBUG(" Button up %d\r\n", e.source); |
masakjm | 7:e2779d2fef9c | 376 | switch (State) { |
masakjm | 0:28fb3e9ef81a | 377 | case STATE_SETTING : |
masakjm | 0:28fb3e9ef81a | 378 | if(setting_enter) setting_next = true; // 決定ボタンを離したら次へ |
masakjm | 0:28fb3e9ef81a | 379 | break; |
masakjm | 0:28fb3e9ef81a | 380 | case STATE_OPERATING : |
masakjm | 7:e2779d2fef9c | 381 | DispChar = 0; |
masakjm | 0:28fb3e9ef81a | 382 | ble_error_t ret = kbdServicePtr->keyUpCode(); |
masakjm | 0:28fb3e9ef81a | 383 | if (ret) { |
masakjm | 7:e2779d2fef9c | 384 | DispChar ='E'; |
masakjm | 7:e2779d2fef9c | 385 | DispCharLast =0; // E が続く時に表示 |
masakjm | 0:28fb3e9ef81a | 386 | } |
masakjm | 0:28fb3e9ef81a | 387 | } |
masakjm | 0:28fb3e9ef81a | 388 | } |
masakjm | 0:28fb3e9ef81a | 389 | |
masakjm | 7:e2779d2fef9c | 390 | |
masakjm | 7:e2779d2fef9c | 391 | /** ---------- |
masakjm | 7:e2779d2fef9c | 392 | * @brief ジョイスティックの接続をチェックする |
masakjm | 7:e2779d2fef9c | 393 | * @return false:接続エラー |
masakjm | 7:e2779d2fef9c | 394 | */ |
masakjm | 7:e2779d2fef9c | 395 | static bool checkJoy() |
masakjm | 7:e2779d2fef9c | 396 | { |
masakjm | 7:e2779d2fef9c | 397 | float joyX = AnalogP1.read(); |
masakjm | 7:e2779d2fef9c | 398 | float joyY = AnalogP2.read(); |
masakjm | 7:e2779d2fef9c | 399 | |
masakjm | 7:e2779d2fef9c | 400 | if (joyX < JOY_ERR_THRE) return false; |
masakjm | 7:e2779d2fef9c | 401 | if (joyY < JOY_ERR_THRE) return false; |
masakjm | 7:e2779d2fef9c | 402 | |
masakjm | 7:e2779d2fef9c | 403 | return true; |
masakjm | 7:e2779d2fef9c | 404 | } |
masakjm | 7:e2779d2fef9c | 405 | |
masakjm | 7:e2779d2fef9c | 406 | /** ---------- |
masakjm | 7:e2779d2fef9c | 407 | * @brief ジョイスティックの状態を返す |
masakjm | 7:e2779d2fef9c | 408 | * @return JOY_STATUS |
masakjm | 7:e2779d2fef9c | 409 | */ |
masakjm | 7:e2779d2fef9c | 410 | static JOY_STATUS readJoyStatus(JOY_STATUS last) |
masakjm | 7:e2779d2fef9c | 411 | { |
masakjm | 7:e2779d2fef9c | 412 | JOY_STATUS js = JOY_NEUTRAL; |
masakjm | 7:e2779d2fef9c | 413 | |
masakjm | 7:e2779d2fef9c | 414 | float joyX = AnalogP1.read(); |
masakjm | 7:e2779d2fef9c | 415 | float joyY = AnalogP2.read(); |
masakjm | 7:e2779d2fef9c | 416 | |
masakjm | 7:e2779d2fef9c | 417 | if (joyX > JOY_CENTER_THRE) js = JOY_CENTER_PRESS; |
masakjm | 7:e2779d2fef9c | 418 | else { |
masakjm | 7:e2779d2fef9c | 419 | if (joyX < JOY_LOW_THRE) js = JOY_XLOW_PRESS; |
masakjm | 7:e2779d2fef9c | 420 | if (joyX > JOY_HIGH_THRE) js = JOY_XHIGH_PRESS; |
masakjm | 7:e2779d2fef9c | 421 | if (joyY < JOY_LOW_THRE) js = JOY_YLOW_PRESS; |
masakjm | 7:e2779d2fef9c | 422 | if (joyY > JOY_HIGH_THRE) js = JOY_YHIGH_PRESS; |
masakjm | 7:e2779d2fef9c | 423 | } |
masakjm | 7:e2779d2fef9c | 424 | |
masakjm | 7:e2779d2fef9c | 425 | // DEBUG("%d, %f, %f\r\n", js, joyX, joyY); |
masakjm | 7:e2779d2fef9c | 426 | return js; |
masakjm | 7:e2779d2fef9c | 427 | } |
masakjm | 7:e2779d2fef9c | 428 | |
masakjm | 7:e2779d2fef9c | 429 | static void joyAction(JOY_STATUS last, JOY_STATUS now) |
masakjm | 7:e2779d2fef9c | 430 | { |
masakjm | 7:e2779d2fef9c | 431 | int code = 0; |
masakjm | 7:e2779d2fef9c | 432 | // DEBUG("%d, %d\r\n", now, last); |
masakjm | 7:e2779d2fef9c | 433 | |
masakjm | 7:e2779d2fef9c | 434 | if( now != last){ |
masakjm | 7:e2779d2fef9c | 435 | if(now == JOY_NEUTRAL) { |
masakjm | 7:e2779d2fef9c | 436 | DispChar = 0; |
masakjm | 7:e2779d2fef9c | 437 | ble_error_t ret = kbdServicePtr->keyUpCode(); |
masakjm | 7:e2779d2fef9c | 438 | if (ret) { |
masakjm | 7:e2779d2fef9c | 439 | DispChar ='E'; |
masakjm | 7:e2779d2fef9c | 440 | DispCharLast =0; // E が続く時に表示 |
masakjm | 7:e2779d2fef9c | 441 | } |
masakjm | 7:e2779d2fef9c | 442 | } else { |
masakjm | 7:e2779d2fef9c | 443 | DispChar = '0' + now; |
masakjm | 7:e2779d2fef9c | 444 | code = keyCodeGroup1[kviKeyCode1.value-1][now]; |
masakjm | 7:e2779d2fef9c | 445 | } |
masakjm | 7:e2779d2fef9c | 446 | if (code != 0 )sendKeyCode(code); |
masakjm | 7:e2779d2fef9c | 447 | } |
masakjm | 7:e2779d2fef9c | 448 | } |
masakjm | 0:28fb3e9ef81a | 449 | //--------------------------------- |
masakjm | 0:28fb3e9ef81a | 450 | // Main |
masakjm | 0:28fb3e9ef81a | 451 | //--------------------------------- |
masakjm | 0:28fb3e9ef81a | 452 | int main() |
masakjm | 0:28fb3e9ef81a | 453 | { |
masakjm | 7:e2779d2fef9c | 454 | State = STATE_DESABLE_INPUT; |
masakjm | 0:28fb3e9ef81a | 455 | |
masakjm | 0:28fb3e9ef81a | 456 | wait(0.1); // ボタン状態の更新 |
masakjm | 0:28fb3e9ef81a | 457 | bool bA = buttonA.isPressed(); |
masakjm | 0:28fb3e9ef81a | 458 | bool bB = buttonB.isPressed(); |
masakjm | 0:28fb3e9ef81a | 459 | |
masakjm | 0:28fb3e9ef81a | 460 | if (bA && bB) { // ボタンABを押しながら起動 |
masakjm | 7:e2779d2fef9c | 461 | for(int i=0;i<2;i++) { |
masakjm | 0:28fb3e9ef81a | 462 | display.scroll(VERSION); |
masakjm | 0:28fb3e9ef81a | 463 | wait(0.5); |
masakjm | 0:28fb3e9ef81a | 464 | } |
masakjm | 0:28fb3e9ef81a | 465 | } else if(bA) // ボタンAを押しながら起動 |
masakjm | 7:e2779d2fef9c | 466 | State = STATE_SETTING; |
masakjm | 0:28fb3e9ef81a | 467 | |
masakjm | 0:28fb3e9ef81a | 468 | //----- Display |
masakjm | 0:28fb3e9ef81a | 469 | display.setDisplayMode(DISPLAY_MODE_BLACK_AND_WHITE); |
masakjm | 0:28fb3e9ef81a | 470 | display.clear(); |
masakjm | 0:28fb3e9ef81a | 471 | Timer dispTime; // 連続表示タイマー |
masakjm | 0:28fb3e9ef81a | 472 | dispTime.start(); |
masakjm | 0:28fb3e9ef81a | 473 | |
masakjm | 0:28fb3e9ef81a | 474 | //----- Button |
masakjm | 0:28fb3e9ef81a | 475 | bus.listen(MICROBIT_ID_ANY, MICROBIT_BUTTON_EVT_DOWN, onButtonDown); |
masakjm | 0:28fb3e9ef81a | 476 | bus.listen(MICROBIT_ID_ANY, MICROBIT_BUTTON_EVT_UP, onButtonUp); |
masakjm | 1:3b9ae1dbcdcf | 477 | bus.listen(MICROBIT_ID_ANY, MICROBIT_BUTTON_EVT_HOLD, onButtonHold); |
masakjm | 0:28fb3e9ef81a | 478 | |
masakjm | 7:e2779d2fef9c | 479 | |
masakjm | 7:e2779d2fef9c | 480 | //----- Button |
masakjm | 7:e2779d2fef9c | 481 | bus.listen(MICROBIT_ID_ANY, MICROBIT_BUTTON_EVT_DOWN, onButtonDown); |
masakjm | 7:e2779d2fef9c | 482 | bus.listen(MICROBIT_ID_ANY, MICROBIT_BUTTON_EVT_UP, onButtonUp); |
masakjm | 7:e2779d2fef9c | 483 | bus.listen(MICROBIT_ID_ANY, MICROBIT_BUTTON_EVT_HOLD, onButtonHold); |
masakjm | 7:e2779d2fef9c | 484 | |
masakjm | 7:e2779d2fef9c | 485 | // Put the P0 pins into touch sense mode. |
masakjm | 4:4fe5674bf409 | 486 | P0.isTouched(); |
masakjm | 4:4fe5674bf409 | 487 | |
masakjm | 7:e2779d2fef9c | 488 | //----- Joystick |
masakjm | 7:e2779d2fef9c | 489 | JOY_STATUS joyStatus; |
masakjm | 7:e2779d2fef9c | 490 | JOY_STATUS joyStatusLast = JOY_NEUTRAL; |
masakjm | 7:e2779d2fef9c | 491 | while (!checkJoy()) { |
masakjm | 7:e2779d2fef9c | 492 | DispChar ='G'; |
masakjm | 7:e2779d2fef9c | 493 | display.printChar(DispChar ); |
masakjm | 7:e2779d2fef9c | 494 | wait(1); |
masakjm | 7:e2779d2fef9c | 495 | } |
masakjm | 7:e2779d2fef9c | 496 | |
masakjm | 0:28fb3e9ef81a | 497 | //----- Setting |
masakjm | 7:e2779d2fef9c | 498 | if (paraSetting(State == STATE_SETTING)) DispChar =0; |
masakjm | 7:e2779d2fef9c | 499 | else DispChar ='e'; |
masakjm | 0:28fb3e9ef81a | 500 | |
masakjm | 0:28fb3e9ef81a | 501 | //----- BLE & HID |
masakjm | 7:e2779d2fef9c | 502 | State = STATE_DESABLE_INPUT; |
masakjm | 0:28fb3e9ef81a | 503 | initialize_BLE_HID(); |
masakjm | 0:28fb3e9ef81a | 504 | display.clear(); |
masakjm | 0:28fb3e9ef81a | 505 | |
masakjm | 0:28fb3e9ef81a | 506 | //----- Loop |
masakjm | 7:e2779d2fef9c | 507 | State = STATE_OPERATING; |
masakjm | 0:28fb3e9ef81a | 508 | while (true) { |
masakjm | 0:28fb3e9ef81a | 509 | ble.waitForEvent(); // BLEイベントを待つ |
masakjm | 0:28fb3e9ef81a | 510 | |
masakjm | 7:e2779d2fef9c | 511 | joyStatus = readJoyStatus(joyStatusLast); // Joystick の状態を読む |
masakjm | 7:e2779d2fef9c | 512 | joyAction(joyStatusLast, joyStatus); |
masakjm | 7:e2779d2fef9c | 513 | joyStatusLast = joyStatus; |
masakjm | 7:e2779d2fef9c | 514 | |
masakjm | 3:b6e9850d3e76 | 515 | if(bleMessage != BLE_NO_MESSAGE) { // BLEの状態を表示する |
masakjm | 7:e2779d2fef9c | 516 | DispChar = bleDispChar[bleMessage]; |
masakjm | 3:b6e9850d3e76 | 517 | bleMessage = BLE_NO_MESSAGE; |
masakjm | 3:b6e9850d3e76 | 518 | } |
masakjm | 3:b6e9850d3e76 | 519 | |
masakjm | 7:e2779d2fef9c | 520 | if (DispChar != DispCharLast) { // 表示文字が変更 |
masakjm | 7:e2779d2fef9c | 521 | TurnOffMode = false; |
masakjm | 0:28fb3e9ef81a | 522 | dispTime.reset(); |
masakjm | 0:28fb3e9ef81a | 523 | display.enable(); |
masakjm | 7:e2779d2fef9c | 524 | if (DispChar ) display.printChar(DispChar ); |
masakjm | 0:28fb3e9ef81a | 525 | else display.clear(); |
masakjm | 0:28fb3e9ef81a | 526 | } |
masakjm | 7:e2779d2fef9c | 527 | if (!TurnOffMode) { |
masakjm | 0:28fb3e9ef81a | 528 | if (dispTime.read() > TIME_TURN_OFF) { // 長時間表示 |
masakjm | 7:e2779d2fef9c | 529 | TurnOffMode = true; |
masakjm | 0:28fb3e9ef81a | 530 | display.disable(); |
masakjm | 0:28fb3e9ef81a | 531 | } |
masakjm | 0:28fb3e9ef81a | 532 | } |
masakjm | 7:e2779d2fef9c | 533 | |
masakjm | 7:e2779d2fef9c | 534 | DispCharLast = DispChar ; |
masakjm | 0:28fb3e9ef81a | 535 | } |
masakjm | 0:28fb3e9ef81a | 536 | } |