ユーザ用ツール

サイト用ツール


bleキーボードをつなごう_btstack編

差分

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

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
bleキーボードをつなごう_btstack編 [2025/04/22 02:05] arakibleキーボードをつなごう_btstack編 [2025/04/22 06:13] (現在) – [前提] araki
行 26: 行 26:
 言語は C++を使用する。 言語は C++を使用する。
  
 +なお、この文書やプログラムの作成に当たっては[[https://vanhunteradams.com/Pico/BLE/GATT_Client.html|Building a Bluetooth GATT Client on the Pi Pico W]]および[[https://github.com/bluekitchen/btstack/tree/501e6d2b86e6c92bfb9c390bcf55709938e25ac1|btstack-1.6.2]]のサンプルプログラムを参考にした。
 +
 +また、Copilot、Gemini、およびLM Studio上の Gemma3 12BなどAIによる支援も利用した。
 +
 +完全なコードは[[https://github.com/wildtree/HHSAdvPico.git|ハイハイスクールアドベンチャー PicoCalc版]]に含まれている。
 ===== 処理の流れ ===== ===== 処理の流れ =====
  
行 707: 行 712:
 } }
 </code> </code>
-==== Notificationの処理準備 ==== 
  
 ==== Notification handler ==== ==== Notification handler ====
  
 +ほぼ蛇足であるが、Notification handlerについても少しだけ記しておく。
 +Notificationについては、キーボードからの入力は 0x0040 のハンドルで渡されるようである。
 +メディアキーなどの特殊キーはさらに別のハンドルとなるがここでは割愛する。
 +
 +ほとんどのキーボードの場合はデータ長は 8bytes で先頭が modifierで、1byteのパディングがあって、6bytesのキーコードがわたされる。
 +
 +但し、バッファローのキーボードで11bytes (modifier + 10bytesのキーコード)というものがあったのでどちらでも扱えるようにデザインしてある。
 +
 +キーコードについては、キーボードごとに違いはないので、キーコードを文字にマッピングしてやって、keybuf というキューにデータを登録している。
 +
 +キーの状態に変化がないと Notificationは来ない。
 +キーが押しっぱなしでは状態が変化したわけではないので、押しっぱなしの通知は来ない。
 +通知がなければ、押しっぱなしとみることで、キーリピートやゲームでのキー処理にも対応できるが、ここではそのあたりの処理はしない。
 +
 +キーを押し続けているときに新しくキーが押されたらその分が新しく押されたキーコードとして渡されるが、その時、押しっぱなしになっているキーも渡されるので、差分を見なければ、新しく押されたキーを見つけることができない。
 +
 +そのため前回渡されたキーバッファの内容を保存している。
 +
 +押しっぱなしのキーが離されたときにも、通知が来るが、この時他に押しっぱなしのキーがあればそれも渡されるため、同様に、新しく押されたキーがあるかどうか、離されただけなのか、というチェックを前回のデータと比較して行う。
 +
 +キーボードについては概ねこのような処理を行っている。
 +
 +
 +<code cpp>
 +typedef union {
 +  struct __attribute__((__packed__))
 +  {
 +      uint8_t modifiers;
 +      uint8_t keys[10];
 +  } k1;
 +  struct __attribute__((__packed__))
 +  {
 +      uint8_t modifiers;
 +      uint8_t reserved;
 +      uint8_t keys[6];
 +      uint8_t padding[3];
 +  } k2;
 +  uint8_t raw[11];
 +} keyboard_t;
 +
 +static keyboard_t keyboardReport;
 +static std::queue<uint8_t> keybuf;
 +static const int MAX_KEYCODE = 96;
 +const uint8_t keymap[][MAX_KEYCODE] = {
 +  {    0,   0,   0,   0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
 +     'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
 +     '3', '4', '5', '6', '7', '8', '9', '0',  13,  27,   8,   9, ' ', '-', '=', '[',
 +     ']','\\',   0, ';','\'', '`', ',', '.', '/',   0,   0,   0,   0,   0,   0,   0,
 +       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 127,   0,   0,   0,
 +       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
 +  },
 +  {
 +       0,   0,   0,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,
 +      13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,   0,   0,
 +       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
 +       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
 +       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
 +       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
 +  },
 +  {
 +       0,   0,   0,   0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
 +     'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@',
 +     '#', '$', '%', '^', '&', '*', '(', ')',  13,  27,   8,   9, ' ', '_', '+', '{',
 +     '}', '|',   0, ':', '"', '~', '<', '>', '?',   0,   0,   0,   0,   0,   0,   0,
 +       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 127,   0,   0,   0,
 +       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
 +  },
 +};
 +// 通知を受け取るハンドラ
 +static void 
 +notification_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 GATT_EVENT_NOTIFICATION:
 +      {
 +        // 通知を受信した場合の処理
 +        uint16_t attribute_handle = gatt_event_notification_get_handle(packet);
 +        uint16_t value_length = gatt_event_notification_get_value_length(packet);
 +        const uint8_t *value = gatt_event_notification_get_value(packet);
 +        uint16_t value_handle = gatt_event_notification_get_value_handle(packet);
 +        uint16_t service_id = gatt_event_notification_get_service_id(packet);
 +        if (attribute_handle == 0x0040)
 +        {
 +          if (value_length == 0) return; // データがない場合は無視
 +          if (value_length == 8 || value_length == 11)
 +          {
 +            keyboard_t *newKeyReport = (keyboard_t*)value;
 +            int buflen = 6;
 +            uint8_t *buf = keyboardReport.k2.keys;
 +            uint8_t *input = newKeyReport->k2.keys;
 +            uint8_t mod = newKeyReport->k2.modifiers;
 +            if (value_length == 11)
 +            {
 +              buflen = 10;
 +              buf = keyboardReport.k1.keys;
 +              input = newKeyReport->k1.keys;
 +              mod = newKeyReport->k1.modifiers;     
 +            }
 +            for (int i = 0 ; i < buflen ; i++)
 +            {
 +              uint8_t c = input[i];
 +              if (c == 0) continue;
 +              if (mod == 3) mod = 1;
 +              uint8_t ch = keymap[mod][c];
 +              if (ch == 0) continue;
 +              if (memchr(buf, c, buflen) == NULL) keybuf.push(ch);
 +            }
 +            memcpy(&keyboardReport, value, value_length);
 +          }
 +        }
 +      }
 +      break;
 +    default:
 +      break;
 +  }
 +}
 +</code>
  
  
bleキーボードをつなごう_btstack編.1745287557.txt.gz · 最終更新: by araki