めのん@ひとりプログラミング同好会

このブログはすべてフィクションであり、実在の人物、団体とは一切関係ありません

sACNのData Packet

こんばんは、めのんです!

お昼の投稿ではsACNについてざっと調べた内容を書きました。

今夜の投稿(この投稿です)では、sACNのData Packetを組み立てて送受信が行えるところまでもっていきたかったんですが、なかなか時間が取れなかったのでとりあえずData Packetを組み立てるところまでコードを書きました。

まずは構造体の定義です。 ちょっと長いですけど掲載します。

typedef struct
{
  unsigned char PreambleSize[2];
  unsigned char PostAmbleSize[2];
  unsigned char ACNPacketIdentifier[12];
  unsigned char FlagsAndLength[2];
  unsigned char Vector[4];
  unsigned char CID[16];
} sACN_RootLayer;

typedef struct
{
  unsigned char FlagsAndLength[2];
  unsigned char Vector[4];
  unsigned char SourceName[64];
  unsigned char Priority;
  unsigned char SynchronizationAddress[2];
  unsigned char SequenceNumber;
  unsigned char Options;
  unsigned char Universe[2];
} sACN_FramingLayer;

typedef struct
{
  unsigned char ProtocolFlagsAndLength[2];
  unsigned char Vector;
  unsigned char AddressTypeAndDataType;
  unsigned char FirstPropertyAddress[2];
  unsigned char AddressIncrement[2];
  unsigned char PropertyValueCount[2];
  unsigned char PropertyValues[1 + 512];
} sACN_DMP_Layer;

typedef struct
{
  sACN_RootLayer    RootLayer;
  sACN_FramingLayer FramingLayer;
  sACN_DMP_Layer    DMP_Layer;
} sACN_DataPacket;

これについては規格の内容そのままです。

今度はこの構造体に値を詰め込む関数の定義です。 やはり長いですが、一通り掲載します(少しでも行数を少なくするためにコメントはほぼ入れていません)。

// とりあえずexampleそのまま
#define SENDERS_CID { \
    0xef, 0x07, 0xc8, 0xdd, 0x00, 0x64, 0x44, 0x01, 0xa3, \
    0xa2, 0x45, 0x9e, 0xf8, 0xe6, 0x14, 0x3e, \
  }

static const sACN_DataPacket DataPacket_template =
{
  {
    { 0x00, 0x01 },
    { 0x00, 0x00 },
    { 0x41, 0x53, 0x43, 0x2d, 0x45, 0x31,
      0x2e, 0x31, 0x37, 0x00, 0x00, 0x00 },
    { 0x72, 0x6e },
    { 0x00, 0x00, 0x00, 0x04 },
    SENDERS_CID,
  },
  {
    { 0x70, 0x0a },
    { 0x00, 0x00, 0x00, 0x02 },
    "menonfled",
    100,
  },
  {
    { 0x72, 0x0b },
    0x02,
    0xa1,
    { 0x00, 0x00 },
    { 0x00, 0x01 },
    { 0x02, 0x01 },
  },
};

sACN_DataPacket* sACN_make_DataPacket(
  sACN_DataPacket* packet,
  unsigned universe,
  unsigned char sequence,
  const void* data,
  size_t n)
{
  if (packet == NULL)
    return NULL;
  *packet = DataPacket_template;

  packet->FramingLayer.SequenceNumber = sequence;
  packet->FramingLayer.Universe[0] = (unsigned char)(universe >> 8);
  packet->FramingLayer.Universe[1] = (unsigned char)universe;

  memcpy(&packet->DMP_Layer.PropertyValues[1], data, n);

  return packet;
}

コードの内容の通りなんですが、少しだけ解説しておきます。

SENDERS_CIDマクロの内容なのですが、これはRoot LayerのCIDに格納すべき内容で送信者のユニークな識別子になります。 本来であればMACアドレスを使うなどしてユニークな値を作るべきなんでしょうが、今回はそこまで本格的なことをするつもりはないので、仕様書の例をそのまま使っています。

ほとんどのフィールドは決め打ちでいいので、送信のたびに変化する値を引数で渡す形でsACN_make_DataPacket関数で組み立てています。

このソースコードはCで書いたのですが、C++としてコンパイルしてもいいですし、あくまでCとしてコンパイルしてC++のプログラムとリンクしてもかまいません。

あとはUDPの送受信を行うだけで、ほとんどサンプルプログラム丸写しで大丈夫だと思います。 そういうのをここで引用するのは気が引けるので、次回はUDPの送受信はできたものとして、次の段階に進めればいいなと思います。

なんか今回は取ってつけたような感じになってしまいましたが、プログラムの進捗報告だとこんな感じにどうしてもなってしまいますね。 これからはもう少し読んで面白い内容にできるように頑張りたいと思います(できるかな💧)。

それでは!!