ハイハイスクールアドベンチャー_raspberry_pico_lcd版
差分
このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン前のリビジョン次のリビジョン | 前のリビジョン | ||
ハイハイスクールアドベンチャー_raspberry_pico_lcd版 [2025/04/14 01:17] – [Pico-ResTouch-LCD-2.8] araki | ハイハイスクールアドベンチャー_raspberry_pico_lcd版 [2025/04/17 01:04] (現在) – [BLEキーボード] araki | ||
---|---|---|---|
行 126: | 行 126: | ||
=== 間違ったWEAK宣言の呪縛 === | === 間違ったWEAK宣言の呪縛 === | ||
- | コンパイラというかリンカーへの指示として、WEAKシンボルというのが太鼓の昔から存在しています。 | + | コンパイラというかリンカーへの指示として、WEAKシンボルというのが太古の昔から存在しています。 |
何かというと、そのシンボルはリンク時に他にWEAKではない同名のシンボルがあればそれで置き換えるというものです。 | 何かというと、そのシンボルはリンク時に他にWEAKではない同名のシンボルがあればそれで置き換えるというものです。 | ||
普通同じシンボルが別々に実体をもっていたらリンク時に重複エラーになるんですが、WEAKがついていれば、それが起きません。 | 普通同じシンボルが別々に実体をもっていたらリンク時に重複エラーになるんですが、WEAKがついていれば、それが起きません。 | ||
行 233: | 行 233: | ||
されどこれだけ。 | されどこれだけ。 | ||
+ | === キーマッピング === | ||
+ | |||
+ | US配列のキーボードがターゲットなのは、Keyboard.cpp内の keycode2asciiという配列がそうなっているからです。 | ||
+ | HID_KEYCODE_TO_ASCIIというTinyUSB由来のマッピングを横着して使っているのでこうなっています。 | ||
+ | |||
+ | これを、JISキーボードにあうように直せばJISキーボードでも使えます。 | ||
+ | |||
+ | <code cpp> | ||
+ | static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII }; | ||
+ | </ | ||
==== BLEキーボード ==== | ==== BLEキーボード ==== | ||
行 286: | 行 296: | ||
わたしの手元にあるバッファローのBLEキーボードとM5 CardputerのおまけでついてくるBLEキーボードだけがセキュア接続でなくてもつながるキーボードなので、つまりは、大体の場合セキュアじゃないとダメなのです。((ちなみにCardputerのそれはセキュアでは接続できません。バッファローはセキュアでもOK)) | わたしの手元にあるバッファローのBLEキーボードとM5 CardputerのおまけでついてくるBLEキーボードだけがセキュア接続でなくてもつながるキーボードなので、つまりは、大体の場合セキュアじゃないとダメなのです。((ちなみにCardputerのそれはセキュアでは接続できません。バッファローはセキュアでもOK)) | ||
- | さて、世間には、実は Pico W + btstack | + | とりあえず、ボンディングは行わないで単純にコネクションだけをセキュアにできればいいので、そのように設定をします。 |
+ | <code cpp> | ||
+ | sm_init(); | ||
+ | sm_set_request_security(true); | ||
+ | sm_set_io_capabilities(IO_CAPABILITY_NO_INPUT_NO_OUTPUT); | ||
+ | sm_set_authentication_requirements(SM_AUTHREQ_SECURE_CONNECTION); | ||
+ | sm_set_encryption_key_size_range(7, | ||
- | まあ、セキュアじゃなくてもつながるキーボードなら多分つながるのでそれでよしとするというのもありでしょうけれど、なんかあとちょっとの工夫で動くんじゃないかっていう気がするので、あきらめがつきません。 | + | sm_event_callback_registration.callback = & |
+ | sm_add_event_handler(& | ||
+ | </ | ||
+ | |||
+ | IO_CAPABILITY_NO_INPUT_NO_OUTPUTとSM_AUtHREQ_SECURE_CONNECTIONのみがセットされている場合、Just in Workでの接続が行われるようです。なので、sm_event_handler側でそれを処理すればいいようです。 | ||
+ | |||
+ | <code cpp> | ||
+ | static void | ||
+ | sm_event_handler(uint8_t packet_type, | ||
+ | if (packet_type != HCI_EVENT_PACKET) return; | ||
+ | |||
+ | switch (hci_event_packet_get_type(packet)) | ||
+ | { | ||
+ | case SM_EVENT_JUST_WORKS_REQUEST: | ||
+ | { | ||
+ | // Just Works Confirmを自動的に承認 | ||
+ | bd_addr_t addr; | ||
+ | sm_event_just_works_request_get_address(packet, | ||
+ | Serial.printf(" | ||
+ | sm_just_works_confirm(sm_event_just_works_request_get_handle(packet)); | ||
+ | break; | ||
+ | } | ||
+ | case SM_EVENT_PAIRING_STARTED: | ||
+ | Serial.println(" | ||
+ | break; | ||
+ | case SM_EVENT_PAIRING_COMPLETE: | ||
+ | { | ||
+ | uint8_t status = sm_event_pairing_complete_get_status(packet); | ||
+ | if (status == ERROR_CODE_SUCCESS) | ||
+ | { | ||
+ | Serial.println(" | ||
+ | hci_con_handle_t connection_handle = sm_event_pairing_complete_get_handle(packet); | ||
+ | uint16_t hids_cid; | ||
+ | イスに接続 | ||
+ | gatt_client_discover_primary_services_by_uuid16(& | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | Serial.printf(" | ||
+ | } | ||
+ | break; | ||
+ | } | ||
+ | case SM_EVENT_PASSKEY_DISPLAY_NUMBER: | ||
+ | // パスキー表示が必要な場合の処理 (今回は No Input No Output | ||
+ | display.printf(" | ||
+ | break; | ||
+ | case SM_EVENT_REENCRYPTION_STARTED: | ||
+ | { | ||
+ | // 再暗号化が開始された場合の処理 | ||
+ | bd_addr_t addr; | ||
+ | sm_event_reencryption_started_get_address(packet, | ||
+ | uint8_t addr_type = sm_event_reencryption_started_get_addr_type(packet); | ||
+ | Serial.printf(" | ||
+ | break; | ||
+ | } | ||
+ | case SM_EVENT_REENCRYPTION_COMPLETE: | ||
+ | { | ||
+ | // 再暗号化が完了した場合の処理 | ||
+ | uint8_t status = sm_event_reencryption_complete_get_status(packet); | ||
+ | if(status == ERROR_CODE_SUCCESS) { | ||
+ | Serial.println(" | ||
+ | } else { | ||
+ | Serial.printf(" | ||
+ | } | ||
+ | break; | ||
+ | } | ||
+ | default: | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | あとは接続時にセキュア接続を要求するだけです。 | ||
+ | |||
+ | <code cpp> | ||
+ | case HCI_EVENT_LE_META: | ||
+ | if (hci_event_le_meta_get_subevent_code(packet) == HCI_SUBEVENT_LE_CONNECTION_COMPLETE) | ||
+ | { | ||
+ | // 暗号化を有効化 | ||
+ | hci_con_handle_t connection_handle = gap_subevent_le_connection_complete_get_connection_handle(packet); | ||
+ | gap_request_security_level(connection_handle, | ||
+ | sm_request_pairing(connection_handle); | ||
+ | // | ||
+ | Serial.printf(" | ||
+ | } | ||
+ | break; | ||
+ | </ | ||
- | 識者の見解を待ちます! | + | これでコネクションはセキュアになりました。 |
+ | < | ||
+ | ble/ | ||
+ | ついに、文字が拾えるようになりました。 | ||
+ | まだ、テスト用のコードなので、これを整理して、こちらに組み込まないといけないのですが、長かった。 | ||
+ | ポイントは、Notificationを受け取りたいCharacteristicに対して、ディスクリプタを検索してCCCDを見つけたら、Notifyを送信するように要求する((0x0001 -- little endian なら {0x01, 0x00}を送信する。))のと、最後に gatt_client_listen_for_charcteristic_value_updates()でGATT_EVENT_NOTIFICATIONを受け取るようにすることの両方。 | ||
+ | 更に gatt_client_listen_for_characteristic_value_updates()のcharacteristicにはnullptrを渡して一括でやる方がいいということですかね。((サンプルに従って notification_listenerを一つだけ作っているので、個別の characteristicに対してやりたいなら、多分これもcharacteristicごとにわけないといけないんだと思いますが、一括で動いているのでよしとします。)) | ||
ハイハイスクールアドベンチャー_raspberry_pico_lcd版.1744593469.txt.gz · 最終更新: 2025/04/14 01:17 by araki