田舎の組み込みプログラマーがわざわざ趣味でも色々開発してみようとあがく様を綴るブログです。
DMM.makeのクリエイターズマーケットに出品しています。
ターミナルから指示してみる ― 2018年05月15日
せっかくシリアルの送受信ができるようになったので、ターミナルからコマンドを入力して何かをやらせてみたいですね。
なので、ここまでの流れでLチカをターミナルから実行してみることにしました。
イメージとしてはこんな感じです。
文字列を扱うのは面倒なのでコマンドは1文字とし、リターンキーで実行します。
"S"コマンドは数値を入力すると点滅時間の設定となり、コマンドのみでは現在の設定値を返すようにします。
そのため、LED_CONTROLには_GETアクションを追加しました。
そんなところで
いきなりソースです。
;==========================================================
PART$ TINY_TOKENIZER
;----------------------------------------------------------
ENUM$_SET 0
ENUM TYPE_CHAR
ENUM TYPE_NUM
ENUM TYPE_SPACE
ENUM TYPE_ENTER
ENUM TYPE_BS
ENUM TYPE_ESCAPE
C_BUFF_SIZE .equ 10
c_type: .blkb 1
c_index: .blkb 1
c_buff: .blkb C_BUFF_SIZE
;==========================================================
; コンディション定義
CONDITION$_DEFINE C_NANIKA ; [何か入ってる]
; ステータス定義
STATE$_DEFINE TKN_NULL ; 何もない
STATE$_DEFINE TKN_NUM ; 数値<[何か入ってる]
STATE$_DEFINE TKN_CHAR ; 文字<[何か入ってる]
;-----------------------------------
; 何もない
;-----------------------------------
STATE$ TKN_NULL, 0
; エントリー処理
[ c_index ] = 0
_PUT
if [ c_type ] == TYPE_CHAR
TRANS TKN_CHAR
elif [ c_type ] == TYPE_NUM
TRANS TKN_NUM
endif
_GO
; ヘラルドさんに実行を通達(命令が伝わっているかどうかは知らない)
PROC$_CALL HERALD$_GO
_BACK
; ヘラルドさんに後退を伝える(後退できるかどうかは知らない)
PROC$_CALL HERALD$_BACK
_ESCAPE
; ヘラルドさんに撤退を伝える(撤退できるかどうかは知らない)
PROC$_CALL HERALD$_ESCAPE
_END
;=======================================
;[何か入ってる]
;=======================================
CONDITION$ C_NANIKA
_GO
PROC$_CALL HERALD$_VALUE ; ヘラルドさんにトークンを与える
PROC$_CALL HERALD$_GO ; ヘラルドさんに実行を通達
TRANS TKN_NULL
_BACK ; BS 入力
[ c_index ] = -- [ c_index ]
if Z ; 何もなくなった
TRANS TKN_NULL
endif
_VALUE ; トークン抽出
PROC$_CALL HERALD$_VALUE ; ヘラルドさんにトークンを与える
TRANS TKN_NULL
_ESCAPE
TRANS TKN_NULL
_END
;-----------------------------------
; 数値<[何か入ってる]
;-----------------------------------
STATE$ TKN_NUM, C_NANIKA
_PUT
if [ c_type ] == TYPE_CHAR
REDIRECT _ESCAPE ; 俺はいらない
endif
_END
;-----------------------------------
; 文字<[何か入ってる]
;-----------------------------------
STATE$ TKN_CHAR, C_NANIKA
; 俺は知らない
_END
_PUT
; キャラクタータイプ判定
[ c_type ] = TYPE_ESCAPE
R0L = [ PARAMETER ].b
if R0L <= 'z'
; コードの大きい方から判定
if R0L >= 'a' ; 小文字
R0L = R0L - 20h ; →大文字
[ c_type ] = TYPE_CHAR
elif R0L > 'Z' ; Z より後ろ
; エスケープ扱い
elif R0L >= 'A' ; 大文字
[ c_type ] = TYPE_CHAR
elif R0L > '9' ; 9 より後ろ
; エスケープ扱い
elif R0L >= '0' ; 数字
[ c_type ] = TYPE_NUM
elif R0L == ' ' || R0L == 0ah || R0L == 09h ; SPC, LF, TAB
[ c_type ] = TYPE_SPACE
elif R0L == 0dh ; CR
[ c_type ] = TYPE_ENTER
elif R0L == 08h ; BS
[ c_type ] = TYPE_BS
endif
endif
; キャラクタータイプに応じて処理を指示
if [ c_type ] == TYPE_NUM || [ c_type ] == TYPE_CHAR
if [ c_index ] < C_BUFF_SIZE
mov.b c_index, A0
[ c_buff[A0]] = R0L
[ c_index ] = ++ [ c_index ]
THROW ; _PUT
else ; バッファオーバー
REDIRECT _ESCAPE
endif
elif [ c_type ] == TYPE_ENTER
REDIRECT _GO
elif [ c_type ] == TYPE_BS
REDIRECT _BACK
elif [ c_type ] == TYPE_SPACE
REDIRECT _VALUE
else
REDIRECT _ESCAPE
endif
;----------------------------------------------------------
_END
;==========================================================
;==========================================================
PART$ HERALD
;----------------------------------------------------------
;==========================================================
; コンディション定義
CONDITION$_DEFINE C_WAIT_PARAM ;[パラメータ待ち]
CONDITION$_DEFINE C_READY ;[準備完了]
; ステータス定義
STATE$_DEFINE H_WAIT ; 待機<[]
STATE$_DEFINE H_B_CYCLE ; 点滅周期<[パラメータ待ち]
STATE$_DEFINE H_ON_READY ; 点灯準備<[準備完了]
STATE$_DEFINE H_OFF_READY ; 消灯準備<[準備完了]
STATE$_DEFINE H_BLINK_READY ; 点滅準備<[準備完了]
STATE$_DEFINE H_B_CYCLE_READY ; 点滅周期<[準備完了]
;-----------------------------------
; 待機<[]
;-----------------------------------
STATE$ H_WAIT, 0
_VALUE ; トークン
R0L = [ c_buff ]
if R0L == 'O' ; LED 点灯指令
TRANS H_ON_READY ; 点灯準備<[準備完了]
elif R0L == 'F' ; LED 消灯指令
TRANS H_OFF_READY ; 消灯準備<[準備完了]
elif R0L == 'B' ; LED 点滅指令
TRANS H_BLINK_READY ; 点滅準備<[準備完了]
elif R0L == 'S' ; LED 点滅時間 設定/返答
TRANS H_B_CYCLE ; 点滅周期<[パラメータ待ち]
else
RET$_FALSE
endif
_END
;=======================================
;[パラメータ待ち]
;=======================================
CONDITION$ C_WAIT_PARAM
_BACK ; 後退
TRANS H_WAIT
_ESCAPE ; 撤退
TRANS H_WAIT
_END
;-----------------------------------
; 点滅周期<[パラメータ待ち]]
;-----------------------------------
STATE$ H_B_CYCLE, C_WAIT_PARAM
_VALUE ; パラメータ来た
CHAR2VAL$_CALC c_buff, [c_index].b ; 数値文字列→数値
TRANS H_B_CYCLE_READY
_GO ; パラメータなし
PROC$_CALL LED_CONTROL$_GET ; 現在の設定値→R0
VAL2CHAR$_UW R0 ; 符号なしでキャラクター変換
VAL2CHAR$_GET R0L ; 変換したキャラクターを順次受け取る
for R0L != -1
PROC$_CALL$_B S0T$_PUT, R0L ; シリアルにキャラクターを送る
VAL2CHAR$_GET R0L ; 変換したキャラクターを順次受け取る
next
PROC$_CALL$_B S0T$_PUT, 0dh ; [CR]
TRANS H_WAIT
_END
;=======================================
;[準備完了]
;=======================================
CONDITION$ C_READY
_VALUE ; もうパラメーターはいらない
TRANS H_WAIT
_BACK ; 後退
TRANS H_WAIT
_ESCAPE ; 撤退
TRANS H_WAIT
_END
;-----------------------------------
; 点灯準備<[準備完了]
;-----------------------------------
STATE$ H_ON_READY, C_READY
_GO
PROC$_CALL LED_CONTROL$_ON
TRANS H_WAIT
_END
;-----------------------------------
; 消灯準備<[準備完了]
;-----------------------------------
STATE$ H_OFF_READY, C_READY
_GO
PROC$_CALL LED_CONTROL$_OFF
TRANS H_WAIT
_END
;-----------------------------------
; 点滅準備<[準備完了]
;-----------------------------------
STATE$ H_BLINK_READY, C_READY
_GO
PROC$_CALL LED_CONTROL$_UNIQUE
TRANS H_WAIT
_END
;-----------------------------------
; 点滅周期<[準備完了]
;-----------------------------------
STATE$ H_B_CYCLE_READY, C_READY
_GO
CHAR2VAL$_GET$_W R0 ; パラメータの数値取得
PROC$_CALL$_W LED_CONTROL$_SET, R0
TRANS H_WAIT
_END
;----------------------------------------------------------
_END
;==========================================================
イメージでは解析器は1つにしていましたが、実際には2段階になっていて、この辺りは字句解析→構文解析のお約束ですね、多分。
呼び出し部分のソースは掲載していませんが、シリアルで受信した文字をTINY_TOKENIZERに_PUTすることで動作します。
TINY_TOKENIZERはパート部分でキャラクタータイプの判定だけを行い、文字か数字ならバッファに入れて、あとはアクティブステートに投げます。
その際、キャラクタータイプによって後に続く処理が限定されるので、処理をリダイレクトします。
例えば[CR]が来た場合は何かを実行することになりますので、アクティブステートに対して_GOを投げるといった具合です。
区切りとなる文字が入るとトークンが確定しますので、後処理であるHERALDに投げます。
変数渡しなのがちょっとアレですが、アセンブラですのでご容赦ください。
HERALDは受け取ったトークンが有効なコマンドなら対応する状態に遷移します。
で、受け取った指示とその時の状態によってやることが変わるわけで、状態遷移処理の真骨頂と言えると思います。
そしてお約束の
デバッガ画面です。
今回はソースコード量に比べて説明がアッサリ過ぎますが、この辺で。
コメント
トラックバック
このエントリのトラックバックURL: http://trident.asablo.jp/blog/2018/05/15/8851364/tb
コメントをどうぞ
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※投稿には管理者が設定した質問に答える必要があります。