No.1202
C言語の共用体(union)ですが、教科書やら動画を見ますと「あまり使い道が無い」的な解説が多いような気がします。
されど、今回のArt-Net系の装置では便利です。Art-Net のポート番号 0x1936(6454) の受信値をとりあえず突っ込むだけで要素毎に取り出すことも出来るからです。例えば ArtDMX は530バイトのパケットですが、受信値を uint8_t[530] (または unsigned char[530]) の配列として保存するだけで ArtDMX の構造体としても扱えます。パディングに注意は必要ですが、便利に使えると思うのです。ID、OpCode、ProVer をまとめて評価するのに先頭12バイトを uint8_t[12] としておいて memcmp で判別することも出来ます。AertDMX と別種の Art-Net パケットもシームレスに扱えそうです。
天才を超越した神たちが何故 union を作ったのかを考えるとワクワクします。
とまぁ、最近C言語の理解が進んで一人笑いが止まらないアホの戯言でした。
オレメモです。
gccで構造体のパディングを回避する書き方。struct に続いて「__attribute__((__packed__))」を入れるそうな。gcc独特の書式らしいので、コンパイラに合わせた書式を使ってください。
typedef struct __attribute__((__packed__)) {
uint8_t ID[8];
uint8_t OpCode[2];
uint8_t ProVerHi;
uint8_t ProVerLow;
uint8_t Sequence;
uint8_t Physical;
uint8_t SubUni;
uint8_t Net;
uint8_t LengthHi;
uint8_t Length;
uint8_t Data[512];
} ad_t;
ad_t ad_data;
ArtDMXを保存する構造体はこんな感じに書けばよいのでしょう。たぶん。
この型を sizeof で見て530バイトならヨシです。
ついでに共用体の定義(案)です。
// Art-Netの受信値を収める構造体
typedef struct __attribute__((__packed__)) {
uint8_t resv[530];
} an_t;
// ArtDMXを取り出す構造体
typedef struct __attribute__((__packed__)) {
uint8_t ID[8];
uint8_t OpCode[2];
uint8_t ProVerHi;
uint8_t ProVerLow;
uint8_t Sequence;
uint8_t Physical;
uint8_t SubUni;
uint8_t Net;
uint8_t LengthHi;
uint8_t Length;
uint8_t Data[512];
} ad_t;
// Art-Netの受信値を保存する共用体ループバッファ
union {
an_t an_resv;
ad_t ad_data;
} an_stack[8192];
こういうことでいいのかな?
共用体の書き方はまだよくわかってないのですけど。
共用体の配列を作って Art-Net のポートで受信したパケットを延々と保存します。8191番まで記録したら0に折り返すループバッファです。
8192個あれば44fps、8センダー、各16ユニバースで最短でも1.45秒分の保存が出来るハズです。十進数で8192なのは2進数(16進数)でキリの良い数値のため折り返し評価が少ない処理で出来るからです。十進数8192は16進数0x2000でキリがよく処理しやすいのです。このあたりはアセンブリ言語だけでPICマイコンと会話をしてきた者にとって自然な着想です。10進数は人が日常的に使い慣れているだけで特筆するほど合理的な数体系ではありませんし、今どきのコンピュータ(論理回路)に合わせた方が便利です。
ヘッダーチェックは当該の配列要素(例えば an_stack[1024] )を示すポインタからmemcmpで12バイトをチェックすれば済みますので共用体には定義しません。
ArtDMX以外のパケットにも使えるチェック方法です。
#C言語
されど、今回のArt-Net系の装置では便利です。Art-Net のポート番号 0x1936(6454) の受信値をとりあえず突っ込むだけで要素毎に取り出すことも出来るからです。例えば ArtDMX は530バイトのパケットですが、受信値を uint8_t[530] (または unsigned char[530]) の配列として保存するだけで ArtDMX の構造体としても扱えます。パディングに注意は必要ですが、便利に使えると思うのです。ID、OpCode、ProVer をまとめて評価するのに先頭12バイトを uint8_t[12] としておいて memcmp で判別することも出来ます。AertDMX と別種の Art-Net パケットもシームレスに扱えそうです。
天才を超越した神たちが何故 union を作ったのかを考えるとワクワクします。
とまぁ、最近C言語の理解が進んで一人笑いが止まらないアホの戯言でした。
オレメモです。
gccで構造体のパディングを回避する書き方。struct に続いて「__attribute__((__packed__))」を入れるそうな。gcc独特の書式らしいので、コンパイラに合わせた書式を使ってください。
typedef struct __attribute__((__packed__)) {
uint8_t ID[8];
uint8_t OpCode[2];
uint8_t ProVerHi;
uint8_t ProVerLow;
uint8_t Sequence;
uint8_t Physical;
uint8_t SubUni;
uint8_t Net;
uint8_t LengthHi;
uint8_t Length;
uint8_t Data[512];
} ad_t;
ad_t ad_data;
ArtDMXを保存する構造体はこんな感じに書けばよいのでしょう。たぶん。
この型を sizeof で見て530バイトならヨシです。
ついでに共用体の定義(案)です。
// Art-Netの受信値を収める構造体
typedef struct __attribute__((__packed__)) {
uint8_t resv[530];
} an_t;
// ArtDMXを取り出す構造体
typedef struct __attribute__((__packed__)) {
uint8_t ID[8];
uint8_t OpCode[2];
uint8_t ProVerHi;
uint8_t ProVerLow;
uint8_t Sequence;
uint8_t Physical;
uint8_t SubUni;
uint8_t Net;
uint8_t LengthHi;
uint8_t Length;
uint8_t Data[512];
} ad_t;
// Art-Netの受信値を保存する共用体ループバッファ
union {
an_t an_resv;
ad_t ad_data;
} an_stack[8192];
こういうことでいいのかな?
共用体の書き方はまだよくわかってないのですけど。
共用体の配列を作って Art-Net のポートで受信したパケットを延々と保存します。8191番まで記録したら0に折り返すループバッファです。
8192個あれば44fps、8センダー、各16ユニバースで最短でも1.45秒分の保存が出来るハズです。十進数で8192なのは2進数(16進数)でキリの良い数値のため折り返し評価が少ない処理で出来るからです。十進数8192は16進数0x2000でキリがよく処理しやすいのです。このあたりはアセンブリ言語だけでPICマイコンと会話をしてきた者にとって自然な着想です。10進数は人が日常的に使い慣れているだけで特筆するほど合理的な数体系ではありませんし、今どきのコンピュータ(論理回路)に合わせた方が便利です。
ヘッダーチェックは当該の配列要素(例えば an_stack[1024] )を示すポインタからmemcmpで12バイトをチェックすれば済みますので共用体には定義しません。
ArtDMX以外のパケットにも使えるチェック方法です。
#C言語