|
| 1 | +# Harucom OS マスタープラン |
| 2 | + |
| 3 | +## ゴール |
| 4 | + |
| 5 | +残り約2週間で以下の3機能を完成させ、Harucom OS を作品として仕上げる: |
| 6 | + |
| 7 | +1. **Ruby Shell (IRB)**: DVI テキストモード上で動作するインタラクティブ Ruby |
| 8 | +2. **テキストエディタ**: Ruby スクリプトを編集・保存できるエディタ |
| 9 | +3. **picorabbit**: プレゼンテーションツールを Harucom 上で動作させる |
| 10 | + |
| 11 | +## アーキテクチャ概要 |
| 12 | + |
| 13 | +I/O 経路は完全に分離する: |
| 14 | + |
| 15 | +- **デバッグ経路**: `printf()` -> `hal_write()` -> UART TX / `hal_getchar()` <- UART RX |
| 16 | +- **ユーザー経路**: IRB/Editor (Ruby) -> DVI::Text VRAM -> DVI 画面 / USB::Host.keyboard_* (Ruby) <- USB キーボード |
| 17 | + |
| 18 | +HAL は UART デバッグ I/O 専用として維持し、変更しない。 |
| 19 | + |
| 20 | +``` |
| 21 | +┌─────────────────────────────────────────────────────────┐ |
| 22 | +│ Ruby アプリケーション層 │ |
| 23 | +│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ |
| 24 | +│ │ IRB │ │ Editor │ │ picorabbit │ │ |
| 25 | +│ │ (Ruby) │ │ (Ruby) │ │ (Ruby) │ │ |
| 26 | +│ └────┬─────┘ └────┬─────┘ └────┬─────────────┘ │ |
| 27 | +│ │ │ │ │ |
| 28 | +│ ┌────┴──────────────┴──┐ ┌─────┴───────────────┐ │ |
| 29 | +│ │ Console (Ruby) │ │ DVI::Graphics (C) │ │ |
| 30 | +│ │ テキストモード UI │ │ グラフィックスモード │ │ |
| 31 | +│ └──┬──────────┬────────┘ └─────────────────────┘ │ |
| 32 | +│ │ │ │ |
| 33 | +│ │ 出力 │ 入力 │ |
| 34 | +│ v v │ |
| 35 | +├─────────────────────────────────────────────────────────┤ |
| 36 | +│ C 基盤層 │ |
| 37 | +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ |
| 38 | +│ │ DVI::Text │ │ USB::Host │ │ Sandbox │ │ |
| 39 | +│ │ VRAM API (C) │ │ keyboard (C) │ │ eval 隔離 │ │ |
| 40 | +│ └──────────────┘ └──────────────┘ └──────────────┘ │ |
| 41 | +│ ┌──────────────┐ ┌──────────────┐ │ |
| 42 | +│ │ Editor:: │ │ picoruby- │ │ |
| 43 | +│ │ Buffer │ │ require │ │ |
| 44 | +│ │ (PicoRuby) │ │ (PicoRuby) │ │ |
| 45 | +│ └──────────────┘ └──────────────┘ │ |
| 46 | +├─────────────────────────────────────────────────────────┤ |
| 47 | +│ HAL (UART デバッグ専用、変更なし) │ |
| 48 | +│ hal_write() -> UART TX hal_getchar() <- UART RX │ |
| 49 | +└─────────────────────────────────────────────────────────┘ |
| 50 | +``` |
| 51 | + |
| 52 | +## コンポーネント一覧 (Ruby/C の実装境界) |
| 53 | + |
| 54 | +### C で実装するもの |
| 55 | + |
| 56 | +| コンポーネント | 概要 | 新規/既存 | |
| 57 | +|---|---|---| |
| 58 | +| DVI::Text 追加 API | scroll_up, clear_range, get_attr, set_attr | 既存に追加 | |
| 59 | +| DVI::Graphics 描画追加 | draw_text (8x8), draw_line, draw_image | 既存に追加 | |
| 60 | +| Machine ポート | signal_self_manage, check_signal | 新規 | |
| 61 | + |
| 62 | +### Ruby で実装するもの |
| 63 | + |
| 64 | +| コンポーネント | 概要 | 新規/既存 | |
| 65 | +|---|---|---| |
| 66 | +| Keyboard | USB::Host API をラップした keycode->文字変換、キーリピート、修飾キー処理 | 新規 | |
| 67 | +| Console | DVI::Text を使ったテキスト UI 基盤 (カーソル管理、スクロール、行描画) | 新規 | |
| 68 | +| IRB | Console + Editor::Buffer + Sandbox による REPL | 新規 | |
| 69 | +| Editor | Console + Editor::Buffer による全画面エディタ | 新規 | |
| 70 | +| picorabbit | スライドロジック (DVI::Graphics API で再実装) | 移植 | |
| 71 | + |
| 72 | +### PicoRuby から再利用する部品 |
| 73 | + |
| 74 | +| 部品 | パス | 用途 | |
| 75 | +|---|---|---| |
| 76 | +| Editor::Buffer | `lib/picoruby/mrbgems/picoruby-editor/mrblib/buffer.rb` | テキストバッファ管理 (完全再利用、修正不要) | |
| 77 | +| Sandbox | `lib/picoruby/mrbgems/picoruby-sandbox/` | IRB の eval 隔離実行 (Machine ポート必要) | |
| 78 | +| picoruby-require | 既にビルド済み | ファイルベースの require/load | |
| 79 | +| mruby-task | 既にビルド済み | 協調マルチタスク | |
| 80 | + |
| 81 | +## マイルストーン |
| 82 | + |
| 83 | +### Milestone 1: キーボード入力 (Days 1-3) |
| 84 | + |
| 85 | +USB キーボードから文字入力を受け取れるようにする。全機能の入力基盤。Ruby で実装する。 |
| 86 | + |
| 87 | +**新規ファイル**: Ruby スクリプト (ファームウェア埋め込みまたは /flash 配置) |
| 88 | + |
| 89 | +**Keyboard クラス (Ruby)**: |
| 90 | +- `USB::Host.keyboard_keycodes` / `keyboard_modifier` をポーリング |
| 91 | +- HID keycode -> 文字変換ルックアップテーブル (初期実装は US レイアウト、テーブル差し替えで JIS 等に対応可能) |
| 92 | +- 前回レポートとの差分で新規キー押下を検出 |
| 93 | +- Shift: shifted テーブル使用 |
| 94 | +- Ctrl + 文字: ASCII 制御コード (Integer 1-26) として返す (Ctrl-C=3, Ctrl-D=4, Ctrl-S=19, Ctrl-Q=17) |
| 95 | +- 特殊キー: Editor::Buffer.put が受け付けるシンボルで返す (`:UP`, `:DOWN`, `:LEFT`, `:RIGHT`, `:HOME`, `:BSPACE`, `:TAB`, `:DELETE`) |
| 96 | +- ソフトウェアキーリピート (初期ディレイ 400ms, リピート 50ms) |
| 97 | +- `Keyboard#read_char` -> String (通常文字) / Symbol (特殊キー) / Integer (制御コード) / nil (入力なし) |
| 98 | + |
| 99 | +**戻り値の設計**: Editor::Buffer.put にそのまま渡せる形で統一する。 |
| 100 | +IRB/Editor のループは制御コード (Integer) を先にチェックし、残りを Buffer.put に渡す。 |
| 101 | + |
| 102 | +**HAL は変更しない**: hal_write / hal_getchar は UART デバッグ専用のまま維持。 |
| 103 | + |
| 104 | +**検証**: Ruby スクリプトで `Keyboard#read_char` を呼び出し、DVI::Text.put_string で文字が画面に表示されることを確認。 |
| 105 | + |
| 106 | +### Milestone 2: DVI テキスト API 拡張 (Days 2-4) |
| 107 | + |
| 108 | +IRB とエディタに必要なテキスト VRAM 操作を追加する。Milestone 1 と並行作業可能。 |
| 109 | + |
| 110 | +**実装内容**: |
| 111 | + |
| 112 | +C API 追加 (`mrbgems/picoruby-dvi/`): |
| 113 | +- `dvi_text_scroll_up(int lines, uint8_t fill_attr)` -- VRAM memmove + 末尾行クリア |
| 114 | +- `dvi_text_clear_range(int col, int row, int width, uint8_t attr)` -- 部分行クリア |
| 115 | +- `dvi_text_get_attr(int col, int row)` -- セル属性読み取り |
| 116 | +- `dvi_text_set_attr(int col, int row, uint8_t attr)` -- セル属性設定 |
| 117 | + |
| 118 | +Ruby バインディング追加: |
| 119 | +- `DVI::Text.scroll_up(lines, attr)` |
| 120 | +- `DVI::Text.clear_range(col, row, width, attr)` |
| 121 | +- `DVI::Text.clear_line(row, attr)` (既存 C API の Ruby 公開) |
| 122 | +- `DVI::Text.get_attr(col, row)` |
| 123 | +- `DVI::Text.set_attr(col, row, attr)` |
| 124 | + |
| 125 | +**変更ファイル**: |
| 126 | +- `mrbgems/picoruby-dvi/include/dvi.h` |
| 127 | +- `mrbgems/picoruby-dvi/ports/rp2350/dvi_output.c` |
| 128 | +- `mrbgems/picoruby-dvi/src/mruby/dvi.c` |
| 129 | + |
| 130 | +**検証**: Ruby スクリプトから scroll_up, clear_range 等を呼び出し、DVI 画面で正しく描画されることを確認。 |
| 131 | + |
| 132 | +### Milestone 3: ビルド統合 + Machine ポート (Days 4-5) |
| 133 | + |
| 134 | +Sandbox と Editor::Buffer をビルドに追加し、Machine モジュールのポートを実装する。 |
| 135 | + |
| 136 | +**ビルド設定変更** (`build_config/harucom-os-pico2.rb`): |
| 137 | +```ruby |
| 138 | +conf.gem core: 'picoruby-editor' # Editor::Buffer |
| 139 | +conf.gem core: 'picoruby-sandbox' # eval 隔離 |
| 140 | +conf.gem core: 'picoruby-machine' # シグナル管理 |
| 141 | +conf.gem core: 'picoruby-env' # Sandbox 依存 |
| 142 | +``` |
| 143 | + |
| 144 | +**Machine ポート実装**: |
| 145 | +- `Machine.signal_self_manage` / `Machine.check_signal` / `Machine.pop_signal_self_manage`: hal.c の sigint_status と統合 |
| 146 | +- `Machine.reboot`: `watchdog_reboot()` で実装 |
| 147 | + |
| 148 | +**picoruby-io-console は追加しない**: Keyboard は USB::Host API を直接使い、Sandbox は io-console に依存しないため不要。hal.c の `io_raw_q()` / `io_echo_q()` スタブはそのまま維持。 |
| 149 | + |
| 150 | +**変更ファイル**: |
| 151 | +- `build_config/harucom-os-pico2.rb` |
| 152 | +- `CMakeLists.txt` (ソース・インクルードパス追加) |
| 153 | + |
| 154 | +**検証**: `rake` がエラーなくビルド完了。 |
| 155 | + |
| 156 | +### Milestone 4-7: Console + IRB, エディタ, picorabbit, ポリッシュ (Days 5-14) |
| 157 | + |
| 158 | +Milestone 3 までが完了すれば基盤 (キーボード入力、DVI テキスト API、ビルド統合) が揃う。 |
| 159 | +Milestone 4 以降は直列に依存しており、実装しながら詳細を詰める。以下は現時点の方針。 |
| 160 | + |
| 161 | +--- |
| 162 | + |
| 163 | +#### Milestone 4: Console + IRB (Days 5-8) |
| 164 | + |
| 165 | +DVI テキストモード上で動作する IRB を実装する。プロジェクトのコア機能。 |
| 166 | + |
| 167 | +**Console クラス (Ruby, 新規)**: |
| 168 | +- DVI::Text API を直接使ったテキスト UI 基盤 |
| 169 | +- カーソル位置管理 (col, row) |
| 170 | +- 文字出力: put_char でカーソル位置に配置、カーソル前進、行末折り返し、画面末スクロール |
| 171 | +- 行クリア、画面クリア |
| 172 | +- カーソル描画 (属性反転トグル) |
| 173 | +- UTF-8 文字列出力 (DVI::Text.put_string に委譲) |
| 174 | + |
| 175 | +**IRB (Ruby, 新規)**: |
| 176 | +- Console + Editor::Buffer + Sandbox の組み合わせ |
| 177 | +- プロンプト表示 (`irb> `) |
| 178 | +- キー入力ループ: Keyboard#read_char -> Editor::Buffer.put |
| 179 | +- Enter 時: try-compile による複数行判定 (`begin; _ = (...); rescue => _; end; _`) |
| 180 | +- 実行: Sandbox.execute -> result.inspect で結果表示 |
| 181 | +- ヒストリ: 配列に保存、上下キーで切り替え |
| 182 | +- Ctrl-C: 実行中断 |
| 183 | + |
| 184 | +**ブートシーケンス変更** (`src/main.c`): |
| 185 | +```ruby |
| 186 | +# ファイルシステムマウント + USB host タスク (既存) |
| 187 | +# ... |
| 188 | +# IRB 起動 |
| 189 | +if VFS.exist?("/flash/main.rb") |
| 190 | + load "/flash/main.rb" |
| 191 | +else |
| 192 | + require 'irb' # /flash/irb.rb を load |
| 193 | +end |
| 194 | +``` |
| 195 | + |
| 196 | +IRB の Ruby コードは `/flash/irb.rb` として配置するか、ファームウェアに埋め込む。 |
| 197 | + |
| 198 | +**検証**: 起動後 IRB プロンプトが表示され、`1 + 1` -> `=> 2` が動作すること。 |
| 199 | + |
| 200 | +### Milestone 5: テキストエディタ (Days 8-11) |
| 201 | + |
| 202 | +IRB から呼び出せるテキストエディタを実装する。 |
| 203 | + |
| 204 | +**Editor (Ruby, 新規)**: |
| 205 | +- Console + Editor::Buffer による全画面エディタ |
| 206 | +- Editor::Buffer のダーティフラグで効率的な差分描画 |
| 207 | +- 基本操作: カーソル移動 (矢印、Home、End)、文字入力、バックスペース、デリート |
| 208 | +- 行操作: 行挿入 (Enter)、行削除 |
| 209 | +- ファイル操作: 保存 (Ctrl-S)、終了 (Ctrl-Q) |
| 210 | +- ステータスバー: ファイル名、行番号、変更フラグ |
| 211 | + |
| 212 | +**IRB からの起動**: |
| 213 | +```ruby |
| 214 | +irb> require 'editor' |
| 215 | +irb> Editor.new.open("/flash/hello.rb") |
| 216 | +``` |
| 217 | + |
| 218 | +**画面構成**: |
| 219 | +``` |
| 220 | +行 0: ステータスバー (ファイル名、行番号) |
| 221 | +行 1-35: テキスト編集領域 (35行) |
| 222 | +行 36: コマンドバー (Ctrl-S:Save Ctrl-Q:Quit) |
| 223 | +``` |
| 224 | + |
| 225 | +**検証**: エディタでファイルを開き、編集、保存、終了してIRBに戻れること。 |
| 226 | + |
| 227 | +### Milestone 6: picorabbit 移植 (Days 11-13) |
| 228 | + |
| 229 | +プレゼンテーションツールを Harucom 上で動作させる。 |
| 230 | + |
| 231 | +**DVI::Graphics 描画追加 (C)**: |
| 232 | +- `DVI::Graphics.draw_text(x, y, text, color)` -- 8x8 フォント (font8x8_basic) |
| 233 | +- `DVI::Graphics.draw_line(x0, y0, x1, y1, color)` -- Bresenham |
| 234 | +- `DVI::Graphics.draw_image(data, x, y, w, h)` -- 画像ブリット |
| 235 | +- `DVI::Graphics.draw_image_masked(data, mask, x, y, w, h)` -- 透過画像 |
| 236 | + |
| 237 | +**画像アセット**: picorabbit の `scripts/convert_image.rb` で変換、C ヘッダーとしてファームウェアに埋め込み |
| 238 | + |
| 239 | +**スライドロジック (Ruby)**: picorabbit の main_task.rb を 320x240 座標系に移植 |
| 240 | + |
| 241 | +**入力**: GPIO ボタンを USB キーボードに変更 (l=次, h=前, q=終了) |
| 242 | + |
| 243 | +**モード切り替え**: IRB -> `DVI.set_mode(DVI::GRAPHICS_MODE)` -> picorabbit -> `DVI.set_mode(DVI::TEXT_MODE)` -> IRB |
| 244 | + |
| 245 | +**検証**: IRB から picorabbit を起動し、スライド表示・切り替え・IRB 復帰が動作すること。 |
| 246 | + |
| 247 | +### Milestone 7: ポリッシュ (Days 13-14) |
| 248 | + |
| 249 | +- ブート画面 (Harucom OS バナー) |
| 250 | +- DVI 診断出力を UART のみに制限 |
| 251 | +- キーリピートのチューニング |
| 252 | +- 安定性テスト (長時間動作、メモリリーク確認) |
| 253 | +- flash 書き込み中の DVI ブランキング確認 (エディタ保存時) |
| 254 | + |
| 255 | +## 依存関係 |
| 256 | + |
| 257 | +``` |
| 258 | +Milestone 1 (Keyboard) ──┐ |
| 259 | + ├──> Milestone 3 (Build) ──> Milestone 4 (IRB) |
| 260 | +Milestone 2 (DVI API) ───┘ │ |
| 261 | + v |
| 262 | + Milestone 5 (Editor) |
| 263 | + │ |
| 264 | + v |
| 265 | + Milestone 6 (picorabbit) |
| 266 | + │ |
| 267 | + v |
| 268 | + Milestone 7 (Polish) |
| 269 | +``` |
| 270 | + |
| 271 | +## リスクと対策 |
| 272 | + |
| 273 | +| リスク | 影響 | 対策 | |
| 274 | +|---|---|---| |
| 275 | +| Machine ポートの複雑さ | 中: Sandbox が動かない | 最小実装から開始 (signal_self_manage のみ) | |
| 276 | +| picorabbit 解像度差 (640 vs 320) | 中: 表示品質 | 320x240 で再設計 (最も現実的) | |
| 277 | +| Editor::Buffer のビルド統合 | 低: 依存 gem の連鎖 | 最小限の gem セットで開始 | |
| 278 | +| SRAM 不足 (mrbgem 追加後) | 低: 現在 334KB 余裕 | サイズ監視、不要機能は除外 | |
| 279 | + |
| 280 | +## 設計方針メモ |
| 281 | + |
| 282 | +### Editor::Buffer を共通基盤とする設計 |
| 283 | + |
| 284 | +Editor::Buffer は I/O に依存しない純粋なデータモデル。 |
| 285 | +Harucom OS の IRB/Editor は Editor::Buffer の上に独自の I/O 層 (Console + Keyboard) を構築する。 |
| 286 | + |
| 287 | +``` |
| 288 | +Harucom: Console (DVI::Text) + Keyboard (USB::Host) -> Editor::Buffer |
| 289 | +R2P2: Editor::Line/Screen (ANSI + STDIN) -> Editor::Buffer |
| 290 | +``` |
| 291 | + |
| 292 | +この構造により、picoruby-vim のモード管理ロジック等を将来 Harucom に持ってくる際も、 |
| 293 | +Editor::Buffer への操作部分は再利用し、I/O 層だけ差し替えればよい。 |
| 294 | + |
| 295 | +### HAL の I/O 分離 |
| 296 | + |
| 297 | +HAL (hal_write / hal_getchar) は UART デバッグ専用として維持し、変更しない。 |
| 298 | +ユーザー向け I/O (画面表示、キーボード入力) は Ruby レイヤーで DVI::Text と USB::Host を直接使う。 |
0 commit comments