はじめに
この記事は Elixir Advent Calendar 2024 の 12/23 の記事です。
Unity(C#) で ArtNet を送受信する内容を以前投稿し、GitHub にライブラリとして公開していますが、今回は同様の ArtNet パケットの Parse を Elixir でやってみようと思います。
ArtNet とは
以前書いた記事にも書いてますが、ArtNet とは舞台照明などの制御で使われているプロトコルの一つです。舞台照明の制御は RS-485 を基にした DMX512-A という規格で制御されているのが一般的です。
この DMX512-A は 1 本のケーブルで 512 チャンネルで、1チャンネルあたり 0~255(8bit) の値で制御することができます。
この DMX を Ethernet を介してやり取りできるようにしたものの一つが ArtNet です。
ArtNet は UDP 6454 番ポートが使われ、ArtNet の規格は以下のドキュメントに書かれています。
ArtNet の 1~8 バイト目はそのパケットが ArtNet のパケットかどうかを識別するための場所で、Art-Net\0
の固定値になっています。9~10 バイト目は OpCode(operation code) と呼ばれる値で、この値で ArtNet パケットの種類を識別します。
11 バイト目以降は OpCode によって内容が異なりますが、
OpCode が OpDmx(DMXパケット) の場合、11~12 バイト目はプロトコルバージョン、13 バイト目は シーケンス番号、15~16 バイト目には Universe 番号が入ります。
18 バイト目以降から DMX の値が順に入れられているのですが、16~17 バイト目には、18 バイト目以降の DMX の長さが格納されています。
実装
Elixir はバイナリに対してパターンマッチが可能です。
今回 OpCode が ArtDmx で、DMX のデータが 255 の値が 1 つだけが入ってる Universe 0 の ArtNet パケットを Parse してみます。
まずはじめに、ArtNet のパケットかどうかの判別は、パケットの先頭 8 バイト目が Art-Net\0
になっているかどうかで判別できます。
Elixir ではパターンマッチを使って、以下の様な感じで行えます。
packet = <<0x41, 0x72, 0x74, 0x2D, 0x4E, 0x65, 0x74, 0x00, 0x00, 0x50, 0x00, 0x0E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF>>
<<65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 1, 0, 0, 0, 0, 1, 255>>
case packet do
"Art-Net\0" <> _ -> true
_ -> false
end
結果: true
また、9~10 バイト目の OpCode(little endian) を文字列で以下のようにすることで取得できます。
今回は OpCode の値が分かりやすいように 16 進数の文字列に変換して返しています。
case packet do
"Art-Net\0" <> <<op_code::little-size(16)>> <> _rest -> {:ok, "0x" <> Integer.to_string(op_code, 16)}
_ -> :error
end
結果: {:ok, "0x5000"}
11~12 バイト目はプロトコルバージョンは 14 の固定値なので、ArtDmx のパケットを Parse するには以下の様になります。
case packet do
<<
"Art-Net\0"::binary,
0x5000::little-size(16),
14::size(16),
sequence::size(8),
physical::size(8),
sub_universe::size(8),
net::size(8),
length::size(16),
data::size(length)-bytes
>> ->
{:ok,
%{
sequence: sequence,
physical: physical,
sub_universe: sub_universe,
net: net,
length: length,
data: (for <<byte::size(8) <- data>>, do: byte)
}}
_ ->
:error
end
結果: {:ok,
%{
sequence: 0,
physical: 0,
sub_universe: 0,
net: 0,
length: 1,
data: [255]
}}
このように Elixir のパターンマッチを使うことで、ArtNet のパケットを簡単に Parse することができます。