wvogel日記

自分用の技術備忘録が多めです.

Haskellでシリアル通信

友人と製作中の,電気刺激を使った展示品.
電気刺激装置自体は内部にPICを搭載していて,
オリジナル開発者の趣向から,
これまではPCからC++で書かれたソフトウェアを介して刺激を生成していた.

ただし,今回は電気刺激の部分以外のアルゴリズム開発を担当している友人がPythonを使っている背景があり,
Pythonから電気刺激装置を叩けるよう簡単なプログラムを組んだ.

で,ここからは私の趣向で,
前々からHaskellでシリアル通信を試したかったが手ごろな装置がなく放置されていた.
折角の機会なので,Haskellからも電気刺激が生成できるようにした.
使う機会はないだろうが.

ソースコードこちら
ようやくByteStringをまともに使った.

内容は簡単で,本当に,シリアル通信をしているだけである.

makeCommand :: Channel -> Current -> [Word8]
makeCommand ch i = map fromIntegral [comm1, comm2] where
	pole = if i >= 0 then 1 else 0
	comm1 = (shiftL ch 5) + (shiftL pole 4) + (shiftR i 8)
	comm2 = (2^8-1) .&. i

この関数で,2byteで構成されるコマンドを生成している.
Data.Bitsモジュールが非常に役に立った.
shiftR, shiftL, (.&.)関数で,Int型の値をそのまま
シフト演算,AND演算を簡単に実装できた.


シリアル通信の関数は主に次の二つ.

getGVS :: Port -> IO GVS
getGVS port =
    openSerial port defaultSerialSettings{ commSpeed = CS115200 }

sendCommand :: GVS -> Channel -> Current -> IO Int
sendCommand gvs ch i = send gvs . pack $ makeCommand ch i

これは,System.Hardware.SeralportモジュールとData.ByteStringのpack関数で簡単に実装できた.

基本はdefaultで用意されているシリアル通信のパラメータで良いが,
baudrateのみ値が違うので,値を書き換えている.

getGVS関数ではmakeCommand関数で生成したコマンドを
シリアルポートに送り込む処理をしているだけである.
ただ,ご存知の通り,ByteString型で送らなければいけないので,makeCommandで[0-255]に変換した値をInt -> Word8に変換したうえで,pack関数を用いてByteStringにしている.

こうすることで,各Bit情報を失わずにデータを送信できる.

受信する時には逆に,unpackすれば良い.

処理自体は簡単だったが,色々勉強になった.