ユーザ用ツール

サイト用ツール


ハイハイスクールアドベンチャー_raspberry_pico_lcd版

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
ハイハイスクールアドベンチャー_raspberry_pico_lcd版 [2025/04/14 02:01] – [USBキーボード] arakiハイハイスクールアドベンチャー_raspberry_pico_lcd版 [2025/05/12 07:15] (現在) araki
行 10: 行 10:
  
 現状、[[https://www.waveshare.com/wiki/Pico-ResTouch-LCD-2.8|Pico-ResTouch-LCD-2.8]]に、OTGアダプタをかませたUSBキーボード((US配列))をサポートしています。 現状、[[https://www.waveshare.com/wiki/Pico-ResTouch-LCD-2.8|Pico-ResTouch-LCD-2.8]]に、OTGアダプタをかませたUSBキーボード((US配列))をサポートしています。
 +追記: [[https://www.waveshare.com/wiki/Pico-ResTouch-LCD-3.5|Pico-ResTouch-LCD-3.5]]もサポートしました。
 +また、BLEキーボードもPico 1W/Pico 2Wで利用できるようになっています。
  
 ===== あれこれ ===== ===== あれこれ =====
行 112: 行 114:
 SDカードのCSピンは SD.begin(22,SPI1)のように、SDインターフェイスの開始時に渡せばいいので、setCS()は呼ばないようにしてください。 SDカードのCSピンは SD.begin(22,SPI1)のように、SDインターフェイスの開始時に渡せばいいので、setCS()は呼ばないようにしてください。
  
 +=== 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);  // LCD CS
 +  pinMode(22, OUTPUT); // SD CS
 +  digitalWrite(9, HIGH); // OFF
 +  digitalWrite(22, HIGH); // OFF
 +</code>
 +
 +このコードを入れた後はとりあえずリセット後におかしな読込みとなることはなくなったように思います。
 +
 +==== 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;
 +</code>
 +
 +要はカラーモードがあってなかったので書き込んでも表示が来なかったというわけです。
 +((おそらくデフォルトでは24か32ビットカラーになっているんだと思います。))
 +
 +なお、書き込み40000000 読み出し 2000000で駆動させています。
 +これより速くすると動きが怪しい感じになったので多分やめた方がいいでしょう。
 +正直表示は速くはありません。
 +
 +画面サイズが320x480なので、ハイハイスクールアドベンチャーでは縦長で使うことにしました。
 ==== USBキーボード ==== ==== USBキーボード ====
  
行 153: 行 197:
 ちょっとWeb界隈を漁ると、同じ現象で困っている人もいらっしゃる。 ちょっとWeb界隈を漁ると、同じ現象で困っている人もいらっしゃる。
  
-で、さらに調べていったら、**ヘッダファイルの中でコールバックのテンプレート宣言に_ _attribute( (weak) )_ _つけてる**じゃありませんか!+で、さらに調べていったら、**ヘッダファイルの中でコールバックのテンプレート宣言に**<code cpp>__attribute__((weak))</code>**つけてる**じゃありませんか!
 ダメ、絶対! ダメ、絶対!
 WEAK属性は実装の方にだけつけて宣言につけちゃダメ! WEAK属性は実装の方にだけつけて宣言につけちゃダメ!
行 250: 行 294:
 線がのたくりまわるのは好きではないので、最初にこっちを実装しようとしたのですが、サンプル見ても、Web界隈で調べても、例によってマイコンをBLEセントラルとして使っている事例は少ないんですよね。 線がのたくりまわるのは好きではないので、最初にこっちを実装しようとしたのですが、サンプル見ても、Web界隈で調べても、例によってマイコンをBLEセントラルとして使っている事例は少ないんですよね。
  
-実は未だ動いてないので、コードは同梱していませんが、とりあえず、色々実験はしているので、ここまでで得た知見を。+<del>実は未だ動いてないので、コードは同梱していませんが、とりあえず、色々実験はしているので、ここまでで得た知見を。</del> 
 +無事に動くに至りましたので、そこまでに得た知見をまとめておきます
  
 === ビルド === === ビルド ===
行 296: 行 341:
 わたしの手元にあるバッファローのBLEキーボードとM5 CardputerのおまけでついてくるBLEキーボードだけがセキュア接続でなくてもつながるキーボードなので、つまりは、大体の場合セキュアじゃないとダメなのです。((ちなみにCardputerのそれはセキュアでは接続できません。バッファローはセキュアでもOK)) わたしの手元にあるバッファローのBLEキーボードとM5 CardputerのおまけでついてくるBLEキーボードだけがセキュア接続でなくてもつながるキーボードなので、つまりは、大体の場合セキュアじゃないとダメなのです。((ちなみにCardputerのそれはセキュアでは接続できません。バッファローはセキュアでもOK))
  
-さて世間に、実は Pico W + btstack でセキュア接続をして BLE Centralとして動作させてるという事例があまりないよう、AIもいろいろ教えてくれるんでが、簡単にいうと、セキュア接続要求がstate=8で失敗して先へ進めないが現状です。+とりあえずボンディング行わない単純にコネクションだけをセキュアにできればいいので、そのように設定を。 
 +<code cpp> 
 +  sm_init();                        // セキュリティマネージャの初期化 
 +  sm_set_request_security(true);    // セキュリティ要求を有効化 
 +  sm_set_io_capabilities(IO_CAPABILITY_NO_INPUT_NO_OUTPUT); // IOキャパビリティ設定 
 +  sm_set_authentication_requirements(SM_AUTHREQ_SECURE_CONNECTION); // 認証要件を設定 
 +  sm_set_encryption_key_size_range(7, 16); // 暗号化キーサイズ範囲を設定
  
-まあ、セキュアじゃなくてもつながるキーボードなら多分つながるのでそれでよしとするというのもありでしょうけれど、なんかあとちょっとの工夫で動くんじゃないかっていう気がするので、あきらめがつきません。+  sm_event_callback_registration.callback = &sm_event_handler; 
 +  sm_add_event_handler(&sm_event_callback_registration); 
 +</code>
  
-識者見解待ちま+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, uint16_t channel, uint8_t *packet, uint16_t size) { 
 +  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, addr); // アドレスを取得 
 +        Serial.printf("Just works request from %s\n", bd_addr_to_str(addr)); 
 +        sm_just_works_confirm(sm_event_just_works_request_get_handle(packet)); 
 +        break; 
 +      } 
 +    case SM_EVENT_PAIRING_STARTED: 
 +      Serial.println("Pairing started."); 
 +      break; 
 +    case SM_EVENT_PAIRING_COMPLETE:  
 +    { 
 +      uint8_t status = sm_event_pairing_complete_get_status(packet); 
 +      if (status == ERROR_CODE_SUCCESS)  
 +      { 
 +        Serial.println("Pairing complete. Connection is now secure."); 
 +        hci_con_handle_t connection_handle = sm_event_pairing_complete_get_handle(packet); 
 +        uint16_t hids_cid; 
 +イスに接続 
 +        gatt_client_discover_primary_services_by_uuid16(&handle_gatt_client_event, connection_handle, HID_SERVICE_UUID);  // GATT event handler 
 +      }  
 +      else  
 +      { 
 +        Serial.printf("Pairing failed with status %u.\n", status); 
 +      } 
 +      break; 
 +    } 
 +    case SM_EVENT_PASSKEY_DISPLAY_NUMBER: 
 +      // パスキー表示が必要な場合の処理 (今回は No Input No Output なので基本的には発生しない) 
 +      display.printf("Passkey: %06u\n", sm_event_passkey_display_number_get_passkey(packet)); 
 +      break; 
 +    case SM_EVENT_REENCRYPTION_STARTED: 
 +      { 
 +        // 再暗号化が開始された場合の処理 
 +        bd_addr_t addr; 
 +        sm_event_reencryption_started_get_address(packet, addr); // アドレスを取得 
 +        uint8_t addr_type = sm_event_reencryption_started_get_addr_type(packet); 
 +        Serial.printf("Re-encryption started for address: %s (%d)\n", bd_addr_to_str(addr), addr_type); 
 +        break; 
 +      } 
 +    case SM_EVENT_REENCRYPTION_COMPLETE: 
 +      { 
 +        // 再暗号化が完了した場合の処理 
 +        uint8_t status = sm_event_reencryption_complete_get_status(packet); 
 +        if(status == ERROR_CODE_SUCCESS) { 
 +          Serial.println("Re-encryption successful."); 
 +        } else { 
 +          Serial.printf("Re-encryption failed.(%d)\n", status); 
 +        } 
 +        break; 
 +      } 
 +    default: 
 +      break; 
 +  } 
 +
 +</code> 
 + 
 +あとは接続時にセキュア接続を要求するだけです。 
 + 
 +<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, LEVEL_2); 
 +        sm_request_pairing(connection_handle); 
 +        //gatt_client_discover_primary_services_by_uuid16(&handle_gatt_client_event, connection_handle, HID_SERVICE_UUID);  // GATT event handler 
 +        Serial.printf("Connected to HID device: %s (%08x)\n", bd_addr_to_str(keyboard_address), connection_handle); 
 +      } 
 +      break; 
 +</code>
  
 +これでコネクションはセキュアになりました。
  
 +<del>ただ、まだキーボードから通知が拾えていません。
 +ble/hids_client.c というのがあるので、これを使えば簡単かもしれませんが、サンプルが見当たらないので、ソースを読みながら手探りで調査しています。</del>
  
 +ついに、文字が拾えるようになりました。
 +<del>まだ、テスト用のコードなので、これを整理して、こちらに組み込まないといけないのですが、長かった。</del>
  
 +ポイントは、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版.1744596087.txt.gz · 最終更新: by araki