# 2025q1 Homework3 (kxo) contributed by < `h0w726` > :::danger 注意細節! ::: ## 鍵盤事件處理 #### 連續觀看多場 「電腦 vs. 電腦」的對弈 > commit [367ac7d](https://github.com/sysprog21/kxo/commit/367ac7d738f3a879dc09d2661c4500a276951720) 執行原來的程式時,第一次按下 Ctrl-Q 可以正常退出。但是想要繼續執行時,棋盤會卡住不動,且按下 Ctrl-P 或 Ctrl-Q 都沒有反應,需要重新掛載模組,於是查看 `/sys/class/kxo/kxo/kxo_state` 發現,剛開始載入模組時,內容為 **1 1 0^@**,對應到 `main.c` 的 `kxo_attr` 結構。 ```c struct kxo_attr { char display; char resume; char end; rwlock_t lock; }; ``` 第一次執行按下 Ctrl-P 及 Ctrl-Q 後, `/sys/class/kxo/kxo/kxo_state` 內容變為 **0 1 1^@**,也就是說 end 的狀態被啟用,需要在 `release` 後將其重置為 0。這時發現再次執行 `sudo ./xo-user` 時連棋盤都沒有顯示,一樣查看 `/sys/class/kxo/kxo/kxo_state` 的內容為 **0 1 0^@** ,原來是 display 的狀態沒有啟用,使用 `sudo dmesg |grep -i kxo` 觀察,發現模組還有在運行。於是在 open 將 display 先設為 1 確保每次執行都可以正常顯示棋盤。 #### 修正按下 Ctrl-Q 顯示的訊息有亂碼的情況 > commit [fcd6c2f](https://github.com/h0w726/kxo/commit/fcd6c2f54e455f2d4d5f0bebe9ec2b9d1a221480) 按下 Ctrl-Q 暫停棋盤後,可以見到顯示的訊息如下 ``` O| | | ------- O| |X|O ------- X|X|X| ------- |O| | ------- B�Stopping the kernel space tic-tac-toe game... ``` 有亂碼的原因為在字串最後沒有以 null terminator(`'\0'`)結尾,造成未定義行為。 ## 使畫面呈現的部分全部在使用者層級 > commit [161e3a6](https://github.com/h0w726/kxo/commit/161e3a603f63ea39fc4c1d1c13a1d5d74b4089ee) 原來的程式畫出棋盤的步驟如下: 1. 以 Timer 模擬中斷,每次中斷都會下一步棋 2. 核心透過 tasklet 將下棋以及畫棋盤的 work 排入 workqueue 3. AI1 或 AI2 將下棋結果 `'O'` 或 `'X'` 存入 `table` 4. 每下一步棋 `drawboard_work_func` 都會將整個棋盤存入 `kfifo_buffer` 5. 當使用者層級使用 `read` 時 , 對應到核心的 `kxo_read` 將 `kfifo_buffer` 存入 `xo-user.c` 中的 `display_buf` 6. 透過 `printf("%s", display_buf);` 印出棋盤 原本核心是傳遞整個棋盤到使用者層級畫出,我的想法是核心只傳遞 `table` 也就是 `'O'` 或 `'X'` ,將畫出棋盤的工作在使用者層級完成,其實就是將 `draw_board` 搬至使用者層級。 原來的程式是傳遞整個棋盤也就是 `DRAWBUFFER_SIZE` 個 bytes 為 66 個 bytes,改為只傳遞 `table` 只需要 棋盤的大小 4*4 = 16 個 bytes :::danger 降低傳輸的成本,並提供對應的編碼和數學分析 ::: ### 進一步編碼以降低傳輸成本 想法是將棋盤的三種狀態 `'O'` `'X'` `' '` 進行編碼,一個棋格只需要 2 bits 即可表示狀態,由於有16個棋格,運用 [bit field](https://hackmd.io/@sysprog/c-bitfield#C-%E8%AA%9E%E8%A8%80%E7%9A%84-bit-field) 的概念,剛好能以一個 `unsigned int` 表示全部棋格的狀態。 另外觀察 `'O'` `'X'` `' '` 的 ASCII 值 || `'O'` | `'X'` | `' '` | |--------| -------- | -------- | -------- | |十進位| 79 | 88 | 32 | |二進位| 01001111 | 01011000 | 00100000 | 發現第三第四位剛好可以運用作為編碼,`'O'` 為 00 `'X'` 為 01 `' '` 為 10