ハイハイスクールアドベンチャー_raspberry_pico_lcd版
差分
このページの2つのバージョン間の差分を表示します。
| 両方とも前のリビジョン前のリビジョン次のリビジョン | 前のリビジョン | ||
| ハイハイスクールアドベンチャー_raspberry_pico_lcd版 [2025/04/14 01:17] – [USBキーボード] araki | ハイハイスクールアドベンチャー_raspberry_pico_lcd版 [2025/09/18 01:33] (現在) – [ハイハイスクールアドベンチャー Raspberry Pico + LCD版] araki | ||
|---|---|---|---|
| 行 1: | 行 1: | ||
| ====== ハイハイスクールアドベンチャー Raspberry Pico + LCD版 ====== | ====== ハイハイスクールアドベンチャー Raspberry Pico + LCD版 ====== | ||
| + | ===== あらすじ ===== | ||
| + | |||
| + | 2019年((まさかこのゲームが2019年を超えて生き残っているとは思っていなかっただろう。))神奈山県立ハイ高等学校は 地盤が弱く校舎の老朽化も進んだため、 とうとう廃校にする以外方法がなく なってしまった。 | ||
| + | |||
| + | ところで大変な情報を手に入れた。 それは、 | ||
| + | |||
| + | 「ハイ高校にATOMIC BOMBが仕掛けられている。」 | ||
| + | |||
| + | と、いうものだ。 どうやらハイ高が廃校になった時、 気が狂った理科の先生がATOMIC BOMBを 学校のどこかに仕掛けてしまったらしい。 | ||
| + | |||
| + | お願いだ。我が母校のコナゴナになった 姿を見たくはない。 早くATOMIC BOMBを取り除いてくれ……!! | ||
| + | |||
| + | 行動は英語で、“< | ||
| + | |||
| + | それでは Good Luck!!!………… | ||
| ===== 概要 ===== | ===== 概要 ===== | ||
| 行 10: | 行 25: | ||
| 現状、[[https:// | 現状、[[https:// | ||
| + | 追記: [[https:// | ||
| + | また、BLEキーボードもPico 1W/Pico 2Wで利用できるようになっています。 | ||
| ===== あれこれ ===== | ===== あれこれ ===== | ||
| 行 40: | 行 57: | ||
| まあ、描画はされていたけれど、バックライトが真っ暗で何も見えていなかっただけというのが実際だったわけです。 | まあ、描画はされていたけれど、バックライトが真っ暗で何も見えていなかっただけというのが実際だったわけです。 | ||
| - | < | + | < |
| namespace lgfx | namespace lgfx | ||
| { | { | ||
| 行 73: | 行 90: | ||
| </ | </ | ||
| - | < | + | < |
| namespace lgfx | namespace lgfx | ||
| { | { | ||
| 行 112: | 行 129: | ||
| SDカードのCSピンは SD.begin(22, | SDカードのCSピンは SD.begin(22, | ||
| + | === SPI上でSDとLCDが競合している場合 === | ||
| + | |||
| + | Pico Res-Touch LCD 2.8(3.5も同様)はSDカードインターフェイスとLCDインターフェイスをSPI1上に置いているため、両社は競合しています。 | ||
| + | |||
| + | このため。 | ||
| + | CSピンでバスの譲り合い((奪い合い? | ||
| + | |||
| + | そもそも LovyanGFX も SDカードインターフェイスも競合を想定しているので、CSピンを正しくアサインしてやればうまく動くのですが、リセット後に不安定化する場合がままあります。 | ||
| + | |||
| + | 集合知に問うと、最初に両方のCSピンをOFFにしてやればいいという情報が出てきました。 | ||
| + | |||
| + | <code cpp> | ||
| + | pinMode(9, OUTPUT); | ||
| + | pinMode(22, OUTPUT); // SD CS | ||
| + | digitalWrite(9, | ||
| + | digitalWrite(22, | ||
| + | </ | ||
| + | |||
| + | このコードを入れた後はとりあえずリセット後におかしな読込みとなることはなくなったように思います。 | ||
| + | |||
| + | ==== Pico Res-Touch LCD 3.5 ==== | ||
| + | |||
| + | Pico Res-Touch LCD 2.8と同じピンアサインを持つSPI液晶 + SDカードモジュールなのですが、画面が3.5インチ 320x480と大型化した関係で、コントローラが ILI9488 に変更されています。 | ||
| + | |||
| + | これはPicoCalcのものと同じなので、ピンと解像度((PicoCalcは 320x320))だけ変更してやれば動くだろうと思ったら、まったく表示が来なくて、3時間ほど試行錯誤をすることに。 | ||
| + | |||
| + | 結論から言うと、16bit カラーモードで初期化してやらないといけないのでした。 | ||
| + | |||
| + | <code cpp> | ||
| + | auto cfg = _panel_instance.config(); | ||
| + | ... | ||
| + | cfg.dlen_16bit = true; | ||
| + | </ | ||
| + | |||
| + | 要はカラーモードがあってなかったので書き込んでも表示が来なかったというわけです。 | ||
| + | ((おそらくデフォルトでは24か32ビットカラーになっているんだと思います。)) | ||
| + | |||
| + | なお、書き込み40000000 読み出し 2000000で駆動させています。 | ||
| + | これより速くすると動きが怪しい感じになったので多分やめた方がいいでしょう。 | ||
| + | 正直表示は速くはありません。 | ||
| + | |||
| + | 画面サイズが320x480なので、ハイハイスクールアドベンチャーでは縦長で使うことにしました。 | ||
| ==== USBキーボード ==== | ==== USBキーボード ==== | ||
| 行 126: | 行 185: | ||
| === 間違ったWEAK宣言の呪縛 === | === 間違ったWEAK宣言の呪縛 === | ||
| - | コンパイラというかリンカーへの指示として、WEAKシンボルというのが太鼓の昔から存在しています。 | + | コンパイラというかリンカーへの指示として、WEAKシンボルというのが太古の昔から存在しています。 |
| 何かというと、そのシンボルはリンク時に他にWEAKではない同名のシンボルがあればそれで置き換えるというものです。 | 何かというと、そのシンボルはリンク時に他にWEAKではない同名のシンボルがあればそれで置き換えるというものです。 | ||
| 普通同じシンボルが別々に実体をもっていたらリンク時に重複エラーになるんですが、WEAKがついていれば、それが起きません。 | 普通同じシンボルが別々に実体をもっていたらリンク時に重複エラーになるんですが、WEAKがついていれば、それが起きません。 | ||
| 行 153: | 行 212: | ||
| ちょっとWeb界隈を漁ると、同じ現象で困っている人もいらっしゃる。 | ちょっとWeb界隈を漁ると、同じ現象で困っている人もいらっしゃる。 | ||
| - | で、さらに調べていったら、**ヘッダファイルの中でコールバックのテンプレート宣言に_ _attribute( (weak) )_ _つけてる**じゃありませんか! | + | で、さらに調べていったら、**ヘッダファイルの中でコールバックのテンプレート宣言に**<code cpp> |
| ダメ、絶対! | ダメ、絶対! | ||
| WEAK属性は実装の方にだけつけて宣言につけちゃダメ! | WEAK属性は実装の方にだけつけて宣言につけちゃダメ! | ||
| 行 233: | 行 292: | ||
| されどこれだけ。 | されどこれだけ。 | ||
| + | === キーマッピング === | ||
| + | |||
| + | 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キーボード ==== | ||
| 行 240: | 行 309: | ||
| 線がのたくりまわるのは好きではないので、最初にこっちを実装しようとしたのですが、サンプル見ても、Web界隈で調べても、例によってマイコンをBLEセントラルとして使っている事例は少ないんですよね。 | 線がのたくりまわるのは好きではないので、最初にこっちを実装しようとしたのですが、サンプル見ても、Web界隈で調べても、例によってマイコンをBLEセントラルとして使っている事例は少ないんですよね。 | ||
| - | 実は未だ動いてないので、コードは同梱していませんが、とりあえず、色々実験はしているので、ここまでで得た知見を。 | + | <del>実は未だ動いてないので、コードは同梱していませんが、とりあえず、色々実験はしているので、ここまでで得た知見を。</ |
| + | 無事に動くに至りましたので、そこまでに得た知見をまとめておきます。 | ||
| === ビルド === | === ビルド === | ||
| 行 286: | 行 356: | ||
| わたしの手元にあるバッファローの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ごとにわけないといけないんだと思いますが、一括で動いているのでよしとします。)) | ||
| + | なお、このBLEキーボードのくだりについては再編集して[[bleキーボードをつなごう_btstack編]]にまとめました | ||
ハイハイスクールアドベンチャー_raspberry_pico_lcd版.1744593436.txt.gz · 最終更新: by araki
