IchigoJam 同士で通信ができる、簡易チャットプログラムを作ってみた。
※IchigoJamはjig.jpの登録商標です
プログラム
※1.4系以降専用
10 ' チャット
20 UART0:CLS:CLV:W=POS(3):H=POS(4):LOCATE0,H-2:FORI=1TOW:?CHR$(#91);:NEXT
30 LET[0],#B2B1,#3EC3:R=4:D=0:E=0:LOCATE0,H-1,1:?"アナタ:";:S=4:C=4:B=#900+W*H-W
40 K=INKEY():IF!KWAIT1:GOTO40
50 K=K&#FF:IFK<8D=K<<E+D:POKE#800+R,D:R=R+(R<W+1ANDE=6):E=(E+3)%9:D=D*!!E:GOTO40
60 IFK=22R=4:D=0:E=0:GOTO40
70 IFK=25COPY#900,#900+W,W*(H-3):COPYB-W*2,#840,W:COPYB-W*2,#800,R:R=4:D=0:E=0:GOTO40
80 IFK=28C=C-(C>4):GOTO160
90 IFK=29C=C+(C<S):GOTO160
100 IFK=18C=4:GOTO160
110 IFK=23C=S:GOTO160
120 IFK=8ANDC>4COPYB+C-1,B+C,S-C+1:C=C-1:S=S-1:GOTO160
130 IFK=127ANDC<SCOPYB+C,B+C+1,S-C:S=S-1:GOTO40
140 IFK=10ANDS>4UART9:?CHR$(22);:FORI=4TOS-1:V=PEEK(B+I):?CHR$(V&7,V/8&7,V>>6);:NEXT:?CHR$(25);:UART0:COPY#900,#900+W,W*(H-3):COPYB-W*2,#840,W:COPYB-W*2,B,S:COPYB+4,#840,W-4:S=4:C=4:GOTO160
150 IFK>31ANDK<>127ANDS+1<WCOPYB+S,B+S-1,C-S:POKEB+C,K:C=C+1:S=S+1
160 LOCATEC,H-1:GOTO40
2台の IchigoJam でこのプログラムをそれぞれ実行し、それぞれの RX をもう一方の TX に導線などで繋いで通信を行う。(GND 同士も接続する)
プログラムを実行していない時に TX と RX を接続すると、一方の IchigoJam が出力したメッセージを他方がコマンドとして実行しようとし、予期せぬ事象が発生する場合がある。
他方の IchigoJam への接続は、プログラムの実行中、もしくは実行直前に行うこと。
実行結果例
プロトコル
IchigoJam では、キーボードで入力した内容も、UART で受信した内容も、同じ INKEY() 関数で読み込むことになる。
そのため、何も工夫をせずに入力した内容をそのまま UART で送信してしまうと、読み込んだのか自分が入力したデータなのか、相手から送られてきたデータなのか、わからなくなってしまう。
そこで、今回は
IchigoJamの特殊キーコード表(特殊キャラクターコード表) by 表かんたん作成プログラム
を参考に、通常は入力しないはずであり、かつ特殊キーコードとして使用されていない 0~7、22、25 を相手へのデータの送信に使うことにした。
具体的には、入力されたメッセージを以下の形式で送信する。
- 22 (メッセージの開始を表す)
- 文字コードの下から 0~2 ビット目
- 文字コードの下から 3~5 ビット目
- 文字コードの下から 6~7 ビット目
- 2~4 を残りの文字の数だけ繰り返し
- 25 (メッセージの終了を表す)
メッセージを、メッセージの開始や終了を表すコードで挟むことで、もし通信がうまくいかずにあるメッセージの一部バイトが欠損しても、他のメッセージには影響を与えにくいようにすることを狙った。
プログラムの解説
初期化
10 ' チャット
20 UART0:CLS:CLV:W=POS(3):H=POS(4):LOCATE0,H-2:FORI=1TOW:?CHR$(#91);:NEXT
余計なデータを UART に送信しないようにする。
画面と変数領域をゼロクリアする。
画面の幅 W と高さ H を取得する。
発言ログを表示する部分と、編集中の発言を表示する部分を区切る線を描画する。
30 LET[0],#B2B1,#3EC3:R=4:D=0:E=0:LOCATE0,H-1,1:?"アナタ:";:S=4:C=4:B=#900+W*H-W
自分の発言の処理に用いる領域 (画面の最下行) のアドレスを変数 B に格納する。
相手の発言を格納する領域の前に、文字列「アイテ>」を置く。
自分の発言を格納する領域の前に、文字列「アナタ:」を置く。
カーソルの表示を有効化する。
以下の変数を初期化する。
-
R:相手から受信した文字を次に格納する位置 -
D:相手から受信中の文字 -
E:相手からの文字の受信状態 -
S:自分の発言の最後の文字の次の位置 -
C:自分の発言を編集するカーソルの位置
入力の読み取り
40 K=INKEY():IF!KWAIT1:GOTO40
INKEY() で入力を読み取る。
入力があるまで待機する。
相手の発言の受信
50 K=K&#FF:IFK<8D=K<<E+D:POKE#800+R,D:R=R+(R<W+1ANDE=6):E=(E+3)%9:D=D*!!E:GOTO40
0 の受信は #100 として表されるので、#FF とのビットANDをとって 0 に戻す。
受信したのが 0~7 の場合、以下を行う。
- 受信中の文字に、受信したビットを加える
- 受信中の文字を、受信したデータを保存する領域に書き込む
- 1文字完成して、かつ受信したデータが長すぎでない場合は、受信した文字を書き込む位置を進める
- 受信の状態 (次に受信するデータのビット位置) を進める
- 1文字完成した場合は、受信中の文字をクリアする
60 IFK=22R=4:D=0:E=0:GOTO40
22 (メッセージの開始を表す) を受信したら、発言の受信状態をリセットする。
70 IFK=25COPY#900,#900+W,W*(H-3):COPYB-W*2,#840,W:COPYB-W*2,#800,R:R=4:D=0:E=0:GOTO40
25 (メッセージの終了を表す) を受信したら、受信したメッセージを画面に反映する。
具体的には、以下を行う。
- 発言ログを1行上にスクロールする
- 発言ログの最下行をゼロクリアする
- 発言ログの最下行に、受信した発言と、その前に用意した
アイテ>をコピーする - 発言の受信状態をリセットする
自分の発言の編集と送信
80 IFK=28C=C-(C>4):GOTO160
90 IFK=29C=C+(C<S):GOTO160
100 IFK=18C=4:GOTO160
110 IFK=23C=S:GOTO160
左キー・右キー・Homeキー・Endキーによるカーソルの移動を行い、それをカーソルの表示に反映する。
120 IFK=8ANDC>4COPYB+C-1,B+C,S-C+1:C=C-1:S=S-1:GOTO160
BackSpaceキーの処理を行う。
具体的には、カーソルが左端以外にあるときのみ、以下を行う。
- カーソルの位置から最後までの発言内容を、1要素前にコピーする
- カーソルを1文字前に移動し、文字列の長さを1減らす
- カーソルの表示を更新する
130 IFK=127ANDC<SCOPYB+C,B+C+1,S-C:S=S-1:GOTO40
Deleteキーの処理を行う。
具体的には、カーソルが最後の文字の次以外にあるときのみ、以下を行う。
- カーソルの位置の次から最後までの発言内容を、1要素前にコピーする
- 文字列の長さを1減らす
この操作ではカーソルの位置は変わらないので、カーソルの表示の更新は行わず、すぐに次の入力の受け付けに移る。
140 IFK=10ANDS>4UART9:
?CHR$(22);:FORI=4TOS-1:V=PEEK(B+I):?CHR$(V&7,V/8&7,V>>6);:NEXT:?CHR$(25);:
UART0:COPY#900,#900+W,W*(H-3):COPYB-W*2,#840,W:COPYB-W*2,B,S:COPYB+4,#840,W-4:
S=4:C=4:GOTO160
発言が1文字以上ある状態でEnterキーが押されたら、発言を送信し、自らの発言ログに加える。
具体的には、以下を行う。
- UART のみに出力するモードにする
- 発言の開始を表す 22 を送信する
- 発言の内容を送信する
- 発言の終端を表す 25 を送信する
- 画面のみに出力するモードにする
- 発言ログを上に1行スクロールする
- 発言ログの最下行をゼロクリアする
- 発言ログに
アナタ:と発言内容をコピーする - 発言内容をゼロクリアする
- 発言内容の長さとカーソルの位置をリセットする
- カーソルの表示を更新する
150 IFK>31ANDK<>127ANDS+1<WCOPYB+S,B+S-1,C-S:POKEB+C,K:C=C+1:S=S+1
文字が入力された際、発言内容の長さが上限未満なら、それをカーソルの位置に挿入する。
具体的には、以下を行う。
- カーソルの位置から最後までの発言内容を、1要素後ろにコピーする
- カーソルの位置に入力された文字を置く
- カーソルを1文字後ろに移動し、文字列の長さを1増やす
- カーソルの表示を更新する
160 LOCATEC,H-1:GOTO40
カーソルの位置を画面に反映し、次の入力の受け付けに移る。
おわりに
最低限の機能を持ったチャットプログラムを作り、IchigoJam 2台の間で通信を行うことができた。
「アナタ」「アイテ」のかわりに自分の名前を設定できるようにし、3台以上で通信を行うことができるようにすると、より本格的になるだろう。