2025年6月 この範囲を時系列順で読む この範囲をファイルに出力する
しばらく前に書いた Art-Net を扱うコードです。
今だったらこうするのにってところは多いですが、これをたたき台にしようかなと。
表示の都合で一部の文字を全角にしています。コピペしてお使いになる際はご注意ください。オレオレライブラリーやオレオレヘッダーが必要なのでこのソースだけでは動きませんけど、要点の参考になれば幸いかと。
/* --------------
Art-Net Engine
ae_main.c
-------------- */
// 汎用ライブラリをインクルード
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/shm.h>
//#include <netinet/in.h>
//#include <sys/ipc.h>
// 自作ライブラリをインクルード
#include "ae_main.h"
#include "std_inkey.h"
#include "std_dump.h"
// Main
int main( int argc, char *argv〔〕 ) {
// 汎用変数
// int i ;
// int ret = 0 ;
// 共有メモリ変数
ae_sharemem_t *ae_sharemem ;
int ae_sharememsize = sizeof( ae_sharemem_t ) ;
int ae_sharememID ;
//【開発用】共有メモリ領域の確保 上位モジュールが出来たらそちらで作る
ae_sharememID = shmget( IPC_PRIVATE, ae_sharememsize, SHM_R|SHM_W ) ;
// 共有メモリ定義
ae_sharemem = shmat( ae_sharememID, 0, SHM_R|SHM_W ) ;
// nsec時変数
struct timespec now ; // 現在POSIX時を得る構造体
unsigned long long int start_nsec ; // 処理開始nsec時を保存
//【開発用】処理時間変数
unsigned long long int lap_nsec ; // 処理終了nsec時
static unsigned long long int max_nsec = 0 ; // 経過したnsecの最大値
// Art-Net 受信変数
int an_rx ; // 受信socket番号
struct sockaddr_in an_rx_addr ; // 受信先指定構造体
int an_rx_length ; // recvfromで得たデータ長
char an_rx_nic〔〕 = { "eth0" } ; // 受信NICの名称
char an_rx_buf〔 ADMX_BUF_SIZE 〕 ; // 受信バッファ ArtDMXの最大バイト長で設定
socklen_t an_rx_sin_size = ADMX_BUF_SIZE ; // recvfromに渡す受信バッファサイズ
struct sockaddr_in an_rx_from_addr ; // 送信元情報の構造体
artdmx_t artdmx_rx ; // 受信したArtDMXを保存する構造体
// Art-Net 送信変数
int an_tx ; // 送信socket番号
struct sockaddr_in an_tx_addr ; // 送信先指定構造体
char an_tx_nic〔〕 = { "eth1" } ; // 受信NICの名称
int yes = 1 ; // 送信をブロードキャストに設定する際のフラグ変数
artdmx_t artdmx_tx〔 ADMX_TX_UNIVRESES 〕 ; // 送信するArtDMXを保存する構造体配列
char an_tx_buf〔 ADMX_BUF_SIZE 〕 ; // 送信バッファ Art-DMXの最大バイト長で設定
int an_tx_count = 0 ; // 送信ユニバースカウンタ
unsigned long long int an_tx_nsec = 0 ; // 送信nsec時を保存
float an_tx_fps = 29.97 ; // 送信フレームレート
unsigned int an_tx_interval =
( unsigned int )( 1e9 / ADMX_TX_UNIVRESES / an_tx_fps ) ;
// Art-Netの受信ソケットを作成
an_rx = socket( AF_INET, SOCK_DGRAM, 0 ) ; // 受信ソケットのインスタンスを作成
setsockopt( an_rx, SOL_SOCKET, SO_BINDTODEVICE, // 受信NICを指定する
&an_rx_nic, sizeof( an_rx_nic ) );
an_rx_addr.sin_family = AF_INET ; // 受信をUDPに設定
an_rx_addr.sin_port = htons( AN_PORT ) ; // 受信ポート番号を設定
an_rx_addr.sin_addr.s_addr = INADDR_ANY ; // 送信元アドレスを無指定にする
bind( an_rx, ( struct sockaddr * ) &an_rx_addr, // 上記をインスタンスに設定する
sizeof( an_rx_addr ) ) ;
// Art-Netの送信ソケットを作成
an_tx = socket( AF_INET, SOCK_DGRAM, 0 ) ; // 送信ソケットのインスタンスを作成
an_tx_addr.sin_family = AF_INET ; // 送信をUDPに設定
an_tx_addr.sin_port = htons( AN_PORT ) ; // 送信ポート番号を設定
an_tx_addr.sin_addr.s_addr = inet_addr( "255.255.255.255" ) ; // 送信先アドレスを無指定にする
setsockopt( an_tx, SOL_SOCKET, SO_BINDTODEVICE, // 送信NICを指定する
&an_tx_nic, sizeof( an_tx_nic ) ) ;
setsockopt( an_tx, SOL_SOCKET, SO_BROADCAST, // 送信をブロードキャストに設定
( char * )&yes, sizeof( yes ) ) ;
// std_inkey 用変数
int key_code_length = 0 ;
int key_code_length_st = 0 ;
char key_code〔 32 〕 = { 0x00 } ;
char key_code_st〔 32 〕 = { 0x00 } ;
// std_inkey を開始
set_inkey( SET ) ;
// ***** Art-Netの受送信と表示 *****
printf( "\e〔2J\e〔?25l" ) ; // 画面を消去 カーソル非表示 \e〔?25l カーソル非表示
while( strcmp( key_code, _KEY_F12 ) != 0 ) {
// ------ 開始nsec時を取得 ------
clock_gettime( CLOCK_REALTIME, &now ) ; // 現在POSIX時間値取得
start_nsec = ( unsigned long long int )now.tv_sec * 1e9 // unsigned long long int型(8バイト長int)変数に
+ now.tv_nsec ; // 取得値をひとまとめにする(nsec)
// --------- キー入力 ----------
key_code_length = get_inkey( key_code ) ; // キー入力を取得
if( strcmp( key_code, "\x20" ) == 0 ) max_nsec = 0 ; //【開発用】キー入力が〔SP〕なら実行時間計測の最大値をクリア
if( key_code_length > 0 ) { // キー入力を別関数に渡すためのスタック
key_code_length_st = key_code_length ;
memcpy( key_code_st, key_code, sizeof( key_code ) ) ;
}
// --------- 受 信 -----------
memset( an_rx_buf, 0, ADMX_BUF_SIZE ) ; // 受信バッファのクリア
an_rx_length = recvfrom( an_rx, an_rx_buf, ADMX_BUF_SIZE, MSG_DONTWAIT, // an_rx_from_addrには送信元情報が入る
( struct sockaddr * )&an_rx_from_addr, &an_rx_sin_size ) ;
// 受信がある場合
if( an_rx_length > 0 ) { // an_rx_lengthは受信値のバイト長
// 送信元IPアドレスとポートを抽出し、構造体artdmx_rxに保存
inet_ntop( AF_INET, &an_rx_from_addr.sin_addr, // 受信データから送信元IPアドレスを抽出保存
artdmx_rx.senderip, sizeof( artdmx_rx.senderip ) ) ;
strcpy( artdmx_rx.senderip, inet_ntoa( an_rx_from_addr.sin_addr ) ) ;
artdmx_rx.senderport = ntohs( an_rx_from_addr.sin_port ) ; // 受信データから送信元ポートを抽出保存
artdmx_rx.recv_nsec = start_nsec ; // 受信日時を保存
// 受信したArtDMXをデコード
if( artdmx_decode( an_rx_buf, &artdmx_rx ) >= 0 ) // ArtDMXなら送信スタックに保存
memcpy( &artdmx_tx〔 artdmx_rx.universe 〕, // ArtDMX以外なら読み飛ばし
&artdmx_rx, sizeof( artdmx_t ) ) ;
//【開発用】終了nsec時を取得
clock_gettime( CLOCK_REALTIME, &now ) ; // 現在POSIX時間値取得
lap_nsec = ( unsigned long long int )now.tv_sec * 1e9 // unsigned long long int型(8バイト長int)変数に
+ now.tv_nsec - start_nsec ; // 取得値をひとまとめにする(nsec)
if( max_nsec < lap_nsec ) max_nsec = lap_nsec ; // ここまでの最大処理時間を得る
}
// --------- 送 信 -----------
else if( start_nsec - an_tx_nsec > ( unsigned int )( an_tx_interval ) ) {
artdmx_encode( an_tx_buf, &artdmx_tx〔 an_tx_count 〕 ) ; // 送信データをエンコード
sendto( an_tx, an_tx_buf, ADMX_BUF_SIZE, MSG_DONTWAIT, // 送信実行
( struct sockaddr * )&an_tx_addr, sizeof( an_tx_addr ) ) ;
/*
//【開発用】終了nsec時を取得
clock_gettime( CLOCK_REALTIME, &now ) ; // 現在POSIX時間値取得
lap_nsec = ( unsigned long long int )now.tv_sec * 1e9 // unsigned long long int型(8バイト長int)変数に
+ now.tv_nsec - start_nsec ; // 取得値をひとまとめにする(nsec)
if( max_nsec < lap_nsec ) max_nsec = lap_nsec ; // ここまでの最大処理時間を得る
*/
//【開発用】受信データの表示
artdmx_check_disp( &artdmx_tx〔 an_tx_count 〕, // 送信データの仮表示
key_code_st, &key_code_length_st, &lap_nsec, &max_nsec ) ;
// 送信事後処理
an_tx_nsec = start_nsec ; // 送信インターバル・次回用のnsec取得
if( ++an_tx_count > 7 ) an_tx_count = 0 ; // 送信ルートカウンタインクリメント
}
// 待ち時間 無駄にループしても処理負荷が増えるだけなので少しお休み
usleep( 1 ) ;
}
// --------- 終 了 ----------
set_inkey( RESET ) ; // std_inkeyを終了
close( an_rx ) ; // 受信ソケットをクローズ
close( an_tx ) ; // 送信ソケットをクローズ
printf( "\e〔?25h\e〔0m\n" ) ; // コンソール画面を戻す \e〔?25h カーソルの表示
shmdt( ae_sharemem ) ; // 共有メモリの切り離し
//【開発用】上位モジュールが出来たらそちらで処理する
shmctl( ae_sharememID, IPC_RMID, 0) ; // 共有メモリ領域開放
return 0 ;
}
// ArtDMXのデコード関数
int artdmx_decode( char *an_rx_buf, artdmx_t *artdmx_rx ) {
int i ;
char int_st〔 sizeof( int ) 〕 ;
// IDを抽出
for( i = 0; i < 8; i++ ) { // bufの先頭から8バイト
artdmx_rx->id〔 i 〕 = an_rx_buf〔 i 〕 ;
}
// OpCodeを抽出
int_st〔 0 〕 = an_rx_buf〔 8 〕 ;
int_st〔 1 〕 = an_rx_buf〔 9 〕 ;
int_st〔 2 〕 = 0x00 ;
int_st〔 3 〕 = 0x00 ;
artdmx_rx->opcode = *( ( int * )&int_st〔 0 〕) ;
if( ! (strcmp( artdmx_rx->id, "Art-Net" ) == 0 // ArtDMXかチェックし、そうでなければエラーを返して終了
&& artdmx_rx->opcode == 0x5000 ) ) {
return -1 ;
}
// ProVerを抽出
int_st〔 0 〕 = an_rx_buf〔 11 〕 ;
int_st〔 1 〕 = an_rx_buf〔 10 〕 ;
int_st〔 2 〕 = 0x00 ;
int_st〔 3 〕 = 0x00 ;
artdmx_rx->prover = *( ( int * )&int_st〔 0 〕) ;
// Sequenceを抽出
artdmx_rx->sequence = an_rx_buf〔 12 〕 ;
// Physicalを抽出
artdmx_rx->physical = an_rx_buf〔 13 〕 ;
// Universeを抽出
artdmx_rx->subnet = an_rx_buf〔 14 〕 / 0x10 ;
artdmx_rx->universe = an_rx_buf〔 14 〕 % 0x10 ;
artdmx_rx->net = an_rx_buf〔 15 〕 ;
// Lengthを抽出
int_st〔 0 〕 = an_rx_buf〔 17 〕 ;
int_st〔 1 〕 = an_rx_buf〔 16 〕 ;
int_st〔 2 〕 = 0x00 ;
int_st〔 3 〕 = 0x00 ;
artdmx_rx->length = *( ( int * )&int_st〔0〕) ;
// Dataを抽出
for( i = 0; i < artdmx_rx->length; i++ ) {
artdmx_rx->data〔 i 〕 = an_rx_buf〔 i + 18 〕 ;
}
if( artdmx_rx->length < 512 ) {
for( i = artdmx_rx->length; i < 512; i++ ) {
artdmx_rx->data〔 i 〕 = 0x00 ;
}
}
return 0 ;
}
// ArtDMXのエンコード関数
int artdmx_encode( char *an_tx_buf, artdmx_t *artdmx_tx ) {
int i ;
// IDを設定
for( i = 0; i < 8; i++ ) {
an_tx_buf〔 i 〕 = artdmx_tx->id〔 i 〕 ;
}
// OpCodeを設定
an_tx_buf〔 8 〕 = (char)( artdmx_tx->opcode % 0x100 ) ;
an_tx_buf〔 9 〕 = (char)( artdmx_tx->opcode / 0x100 ) ;
// ProVerを設定
an_tx_buf〔 10 〕 = (char)( artdmx_tx->prover / 0x100 ) ;
an_tx_buf〔 11 〕 = (char)( artdmx_tx->prover % 0x100 ) ;
// Sequenceを設定
an_tx_buf〔 12 〕 = (char) artdmx_tx->sequence ;
// Physicalを設定
an_tx_buf〔 13 〕 = (char) artdmx_tx->physical ;
// SubUniを設定
an_tx_buf〔 14 〕 = (char)( artdmx_tx->subnet * 0x100 + artdmx_tx->universe ) ;
// Netを設定
an_tx_buf〔 15 〕 = (char)artdmx_tx->net ;
// Lengthを設定
an_tx_buf〔 16 〕 = (char)( artdmx_tx->length / 0x100 ) ;
an_tx_buf〔 17 〕 = (char)( artdmx_tx->length % 0x100 ) ;
// Dataを設定
memcpy( an_tx_buf + 18, artdmx_tx->data, 512 ) ;
return 0 ;
}
// ArtDMXのチェック用画面表示
int artdmx_check_disp( artdmx_t *artdmx, char *key_code_st, int *key_code_length_st,
unsigned long long int *val1, unsigned long long int *val2 ) {
// 汎用変数
//int i ;
// タイムカウント変数
struct timespec now ; // 現在POSIX時を得る構造体
unsigned long long int now_nsec ; // 現在nsecを保存
static unsigned long long int prev_nsec = 0 ; // 過去nsecを保存
// データ管理用
static artdmx_t artdmx_disp ;
// std_dump 用変数
static int first_line = 0 ; // 表示開始行数
// 表示制御変数
struct winsize ws ;
static int col = 20 ;
static int row = 100 ;
static int net = 0 ;
static int subnet = 0 ;
static int universe = 0 ;
// カーソルキー入力
if( *key_code_length_st > 0 ) {
if( strcmp( key_code_st, _KEY_RIGHT ) == 0 ) {
if( ++universe > 7 ) universe = 7 ;
}
if( strcmp( key_code_st, _KEY_LEFT ) == 0 ) {
if( --universe < 0 ) universe = 0 ;
}
if( strcmp( key_code_st, _KEY_UP ) == 0 ) {
first_line-- ;
}
if( strcmp( key_code_st, _KEY_DOWN ) == 0 ) {
first_line++ ;
}
*key_code_length_st = 0 ;
}
// 対象ユニバースのデータをスタック
if( ( artdmx->net == net ) && ( artdmx->subnet == subnet ) && ( artdmx->universe == universe ) ) {
memcpy( &artdmx_disp, artdmx, sizeof( artdmx_t ) ) ;
}
// タイムカウント
clock_gettime( CLOCK_REALTIME, &now ) ; // 現在POSIX時間値取得
now_nsec = ( unsigned long long int )now.tv_sec * 1e9 // unsigned long long int型(8バイト長int)変数に
+ now.tv_nsec ; // 取得値をひとまとめにする(nsec)
if( now_nsec - prev_nsec < 5e7) return -1 ; // 経過時間が不足なら何もせずリターン
prev_nsec = now_nsec ; // 過去nsecを現在値としておく
// 画面のテキスト表示サイズを取得
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) ; // 画面サイズを取得 幅=ws.ws_col 高=ws.ws_row
if( row + 4 > ws.ws_row ) row = ws.ws_row - 4 ; // dumpの行数制限
// artdmxを表示
printf( "\e〔0;0H" ) ; // カーソルを左上に
printf( "Sender: %s:%d", artdmx_disp.senderip, artdmx_disp.senderport ) ;
printf( "\e〔28GID: %s", artdmx_disp.id ) ;
printf( "\e〔41GOpCode: 0x%04X", artdmx_disp.opcode ) ;
printf( "\e〔57GProVer: 0x%04X", artdmx_disp.prover ) ;
printf( "\e〔0K\nSequence: 0x%04X", artdmx_disp.sequence ) ;
printf( "\e〔19GPhysical: 0x%04X", artdmx_disp.physical ) ;
printf( "\e〔37GLength: %d", artdmx_disp.length ) ;
printf( "\e〔50G< Net:%d SubNet:%d Universe:%d >\e〔0K\n", artdmx_disp.net, artdmx_disp.subnet, artdmx_disp.universe ) ;
dump_print( artdmx_disp.data, artdmx_disp.length, col, row, &first_line, 0 ) ;
printf( "%8lld /%8lld nsec", *val1, *val2 ) ;
//fflush( stdout ) ;
// 終了
return 0 ;
}
#[Art-Net] #C言語
今だったらこうするのにってところは多いですが、これをたたき台にしようかなと。
表示の都合で一部の文字を全角にしています。コピペしてお使いになる際はご注意ください。オレオレライブラリーやオレオレヘッダーが必要なのでこのソースだけでは動きませんけど、要点の参考になれば幸いかと。
/* --------------
Art-Net Engine
ae_main.c
-------------- */
// 汎用ライブラリをインクルード
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/shm.h>
//#include <netinet/in.h>
//#include <sys/ipc.h>
// 自作ライブラリをインクルード
#include "ae_main.h"
#include "std_inkey.h"
#include "std_dump.h"
// Main
int main( int argc, char *argv〔〕 ) {
// 汎用変数
// int i ;
// int ret = 0 ;
// 共有メモリ変数
ae_sharemem_t *ae_sharemem ;
int ae_sharememsize = sizeof( ae_sharemem_t ) ;
int ae_sharememID ;
//【開発用】共有メモリ領域の確保 上位モジュールが出来たらそちらで作る
ae_sharememID = shmget( IPC_PRIVATE, ae_sharememsize, SHM_R|SHM_W ) ;
// 共有メモリ定義
ae_sharemem = shmat( ae_sharememID, 0, SHM_R|SHM_W ) ;
// nsec時変数
struct timespec now ; // 現在POSIX時を得る構造体
unsigned long long int start_nsec ; // 処理開始nsec時を保存
//【開発用】処理時間変数
unsigned long long int lap_nsec ; // 処理終了nsec時
static unsigned long long int max_nsec = 0 ; // 経過したnsecの最大値
// Art-Net 受信変数
int an_rx ; // 受信socket番号
struct sockaddr_in an_rx_addr ; // 受信先指定構造体
int an_rx_length ; // recvfromで得たデータ長
char an_rx_nic〔〕 = { "eth0" } ; // 受信NICの名称
char an_rx_buf〔 ADMX_BUF_SIZE 〕 ; // 受信バッファ ArtDMXの最大バイト長で設定
socklen_t an_rx_sin_size = ADMX_BUF_SIZE ; // recvfromに渡す受信バッファサイズ
struct sockaddr_in an_rx_from_addr ; // 送信元情報の構造体
artdmx_t artdmx_rx ; // 受信したArtDMXを保存する構造体
// Art-Net 送信変数
int an_tx ; // 送信socket番号
struct sockaddr_in an_tx_addr ; // 送信先指定構造体
char an_tx_nic〔〕 = { "eth1" } ; // 受信NICの名称
int yes = 1 ; // 送信をブロードキャストに設定する際のフラグ変数
artdmx_t artdmx_tx〔 ADMX_TX_UNIVRESES 〕 ; // 送信するArtDMXを保存する構造体配列
char an_tx_buf〔 ADMX_BUF_SIZE 〕 ; // 送信バッファ Art-DMXの最大バイト長で設定
int an_tx_count = 0 ; // 送信ユニバースカウンタ
unsigned long long int an_tx_nsec = 0 ; // 送信nsec時を保存
float an_tx_fps = 29.97 ; // 送信フレームレート
unsigned int an_tx_interval =
( unsigned int )( 1e9 / ADMX_TX_UNIVRESES / an_tx_fps ) ;
// Art-Netの受信ソケットを作成
an_rx = socket( AF_INET, SOCK_DGRAM, 0 ) ; // 受信ソケットのインスタンスを作成
setsockopt( an_rx, SOL_SOCKET, SO_BINDTODEVICE, // 受信NICを指定する
&an_rx_nic, sizeof( an_rx_nic ) );
an_rx_addr.sin_family = AF_INET ; // 受信をUDPに設定
an_rx_addr.sin_port = htons( AN_PORT ) ; // 受信ポート番号を設定
an_rx_addr.sin_addr.s_addr = INADDR_ANY ; // 送信元アドレスを無指定にする
bind( an_rx, ( struct sockaddr * ) &an_rx_addr, // 上記をインスタンスに設定する
sizeof( an_rx_addr ) ) ;
// Art-Netの送信ソケットを作成
an_tx = socket( AF_INET, SOCK_DGRAM, 0 ) ; // 送信ソケットのインスタンスを作成
an_tx_addr.sin_family = AF_INET ; // 送信をUDPに設定
an_tx_addr.sin_port = htons( AN_PORT ) ; // 送信ポート番号を設定
an_tx_addr.sin_addr.s_addr = inet_addr( "255.255.255.255" ) ; // 送信先アドレスを無指定にする
setsockopt( an_tx, SOL_SOCKET, SO_BINDTODEVICE, // 送信NICを指定する
&an_tx_nic, sizeof( an_tx_nic ) ) ;
setsockopt( an_tx, SOL_SOCKET, SO_BROADCAST, // 送信をブロードキャストに設定
( char * )&yes, sizeof( yes ) ) ;
// std_inkey 用変数
int key_code_length = 0 ;
int key_code_length_st = 0 ;
char key_code〔 32 〕 = { 0x00 } ;
char key_code_st〔 32 〕 = { 0x00 } ;
// std_inkey を開始
set_inkey( SET ) ;
// ***** Art-Netの受送信と表示 *****
printf( "\e〔2J\e〔?25l" ) ; // 画面を消去 カーソル非表示 \e〔?25l カーソル非表示
while( strcmp( key_code, _KEY_F12 ) != 0 ) {
// ------ 開始nsec時を取得 ------
clock_gettime( CLOCK_REALTIME, &now ) ; // 現在POSIX時間値取得
start_nsec = ( unsigned long long int )now.tv_sec * 1e9 // unsigned long long int型(8バイト長int)変数に
+ now.tv_nsec ; // 取得値をひとまとめにする(nsec)
// --------- キー入力 ----------
key_code_length = get_inkey( key_code ) ; // キー入力を取得
if( strcmp( key_code, "\x20" ) == 0 ) max_nsec = 0 ; //【開発用】キー入力が〔SP〕なら実行時間計測の最大値をクリア
if( key_code_length > 0 ) { // キー入力を別関数に渡すためのスタック
key_code_length_st = key_code_length ;
memcpy( key_code_st, key_code, sizeof( key_code ) ) ;
}
// --------- 受 信 -----------
memset( an_rx_buf, 0, ADMX_BUF_SIZE ) ; // 受信バッファのクリア
an_rx_length = recvfrom( an_rx, an_rx_buf, ADMX_BUF_SIZE, MSG_DONTWAIT, // an_rx_from_addrには送信元情報が入る
( struct sockaddr * )&an_rx_from_addr, &an_rx_sin_size ) ;
// 受信がある場合
if( an_rx_length > 0 ) { // an_rx_lengthは受信値のバイト長
// 送信元IPアドレスとポートを抽出し、構造体artdmx_rxに保存
inet_ntop( AF_INET, &an_rx_from_addr.sin_addr, // 受信データから送信元IPアドレスを抽出保存
artdmx_rx.senderip, sizeof( artdmx_rx.senderip ) ) ;
strcpy( artdmx_rx.senderip, inet_ntoa( an_rx_from_addr.sin_addr ) ) ;
artdmx_rx.senderport = ntohs( an_rx_from_addr.sin_port ) ; // 受信データから送信元ポートを抽出保存
artdmx_rx.recv_nsec = start_nsec ; // 受信日時を保存
// 受信したArtDMXをデコード
if( artdmx_decode( an_rx_buf, &artdmx_rx ) >= 0 ) // ArtDMXなら送信スタックに保存
memcpy( &artdmx_tx〔 artdmx_rx.universe 〕, // ArtDMX以外なら読み飛ばし
&artdmx_rx, sizeof( artdmx_t ) ) ;
//【開発用】終了nsec時を取得
clock_gettime( CLOCK_REALTIME, &now ) ; // 現在POSIX時間値取得
lap_nsec = ( unsigned long long int )now.tv_sec * 1e9 // unsigned long long int型(8バイト長int)変数に
+ now.tv_nsec - start_nsec ; // 取得値をひとまとめにする(nsec)
if( max_nsec < lap_nsec ) max_nsec = lap_nsec ; // ここまでの最大処理時間を得る
}
// --------- 送 信 -----------
else if( start_nsec - an_tx_nsec > ( unsigned int )( an_tx_interval ) ) {
artdmx_encode( an_tx_buf, &artdmx_tx〔 an_tx_count 〕 ) ; // 送信データをエンコード
sendto( an_tx, an_tx_buf, ADMX_BUF_SIZE, MSG_DONTWAIT, // 送信実行
( struct sockaddr * )&an_tx_addr, sizeof( an_tx_addr ) ) ;
/*
//【開発用】終了nsec時を取得
clock_gettime( CLOCK_REALTIME, &now ) ; // 現在POSIX時間値取得
lap_nsec = ( unsigned long long int )now.tv_sec * 1e9 // unsigned long long int型(8バイト長int)変数に
+ now.tv_nsec - start_nsec ; // 取得値をひとまとめにする(nsec)
if( max_nsec < lap_nsec ) max_nsec = lap_nsec ; // ここまでの最大処理時間を得る
*/
//【開発用】受信データの表示
artdmx_check_disp( &artdmx_tx〔 an_tx_count 〕, // 送信データの仮表示
key_code_st, &key_code_length_st, &lap_nsec, &max_nsec ) ;
// 送信事後処理
an_tx_nsec = start_nsec ; // 送信インターバル・次回用のnsec取得
if( ++an_tx_count > 7 ) an_tx_count = 0 ; // 送信ルートカウンタインクリメント
}
// 待ち時間 無駄にループしても処理負荷が増えるだけなので少しお休み
usleep( 1 ) ;
}
// --------- 終 了 ----------
set_inkey( RESET ) ; // std_inkeyを終了
close( an_rx ) ; // 受信ソケットをクローズ
close( an_tx ) ; // 送信ソケットをクローズ
printf( "\e〔?25h\e〔0m\n" ) ; // コンソール画面を戻す \e〔?25h カーソルの表示
shmdt( ae_sharemem ) ; // 共有メモリの切り離し
//【開発用】上位モジュールが出来たらそちらで処理する
shmctl( ae_sharememID, IPC_RMID, 0) ; // 共有メモリ領域開放
return 0 ;
}
// ArtDMXのデコード関数
int artdmx_decode( char *an_rx_buf, artdmx_t *artdmx_rx ) {
int i ;
char int_st〔 sizeof( int ) 〕 ;
// IDを抽出
for( i = 0; i < 8; i++ ) { // bufの先頭から8バイト
artdmx_rx->id〔 i 〕 = an_rx_buf〔 i 〕 ;
}
// OpCodeを抽出
int_st〔 0 〕 = an_rx_buf〔 8 〕 ;
int_st〔 1 〕 = an_rx_buf〔 9 〕 ;
int_st〔 2 〕 = 0x00 ;
int_st〔 3 〕 = 0x00 ;
artdmx_rx->opcode = *( ( int * )&int_st〔 0 〕) ;
if( ! (strcmp( artdmx_rx->id, "Art-Net" ) == 0 // ArtDMXかチェックし、そうでなければエラーを返して終了
&& artdmx_rx->opcode == 0x5000 ) ) {
return -1 ;
}
// ProVerを抽出
int_st〔 0 〕 = an_rx_buf〔 11 〕 ;
int_st〔 1 〕 = an_rx_buf〔 10 〕 ;
int_st〔 2 〕 = 0x00 ;
int_st〔 3 〕 = 0x00 ;
artdmx_rx->prover = *( ( int * )&int_st〔 0 〕) ;
// Sequenceを抽出
artdmx_rx->sequence = an_rx_buf〔 12 〕 ;
// Physicalを抽出
artdmx_rx->physical = an_rx_buf〔 13 〕 ;
// Universeを抽出
artdmx_rx->subnet = an_rx_buf〔 14 〕 / 0x10 ;
artdmx_rx->universe = an_rx_buf〔 14 〕 % 0x10 ;
artdmx_rx->net = an_rx_buf〔 15 〕 ;
// Lengthを抽出
int_st〔 0 〕 = an_rx_buf〔 17 〕 ;
int_st〔 1 〕 = an_rx_buf〔 16 〕 ;
int_st〔 2 〕 = 0x00 ;
int_st〔 3 〕 = 0x00 ;
artdmx_rx->length = *( ( int * )&int_st〔0〕) ;
// Dataを抽出
for( i = 0; i < artdmx_rx->length; i++ ) {
artdmx_rx->data〔 i 〕 = an_rx_buf〔 i + 18 〕 ;
}
if( artdmx_rx->length < 512 ) {
for( i = artdmx_rx->length; i < 512; i++ ) {
artdmx_rx->data〔 i 〕 = 0x00 ;
}
}
return 0 ;
}
// ArtDMXのエンコード関数
int artdmx_encode( char *an_tx_buf, artdmx_t *artdmx_tx ) {
int i ;
// IDを設定
for( i = 0; i < 8; i++ ) {
an_tx_buf〔 i 〕 = artdmx_tx->id〔 i 〕 ;
}
// OpCodeを設定
an_tx_buf〔 8 〕 = (char)( artdmx_tx->opcode % 0x100 ) ;
an_tx_buf〔 9 〕 = (char)( artdmx_tx->opcode / 0x100 ) ;
// ProVerを設定
an_tx_buf〔 10 〕 = (char)( artdmx_tx->prover / 0x100 ) ;
an_tx_buf〔 11 〕 = (char)( artdmx_tx->prover % 0x100 ) ;
// Sequenceを設定
an_tx_buf〔 12 〕 = (char) artdmx_tx->sequence ;
// Physicalを設定
an_tx_buf〔 13 〕 = (char) artdmx_tx->physical ;
// SubUniを設定
an_tx_buf〔 14 〕 = (char)( artdmx_tx->subnet * 0x100 + artdmx_tx->universe ) ;
// Netを設定
an_tx_buf〔 15 〕 = (char)artdmx_tx->net ;
// Lengthを設定
an_tx_buf〔 16 〕 = (char)( artdmx_tx->length / 0x100 ) ;
an_tx_buf〔 17 〕 = (char)( artdmx_tx->length % 0x100 ) ;
// Dataを設定
memcpy( an_tx_buf + 18, artdmx_tx->data, 512 ) ;
return 0 ;
}
// ArtDMXのチェック用画面表示
int artdmx_check_disp( artdmx_t *artdmx, char *key_code_st, int *key_code_length_st,
unsigned long long int *val1, unsigned long long int *val2 ) {
// 汎用変数
//int i ;
// タイムカウント変数
struct timespec now ; // 現在POSIX時を得る構造体
unsigned long long int now_nsec ; // 現在nsecを保存
static unsigned long long int prev_nsec = 0 ; // 過去nsecを保存
// データ管理用
static artdmx_t artdmx_disp ;
// std_dump 用変数
static int first_line = 0 ; // 表示開始行数
// 表示制御変数
struct winsize ws ;
static int col = 20 ;
static int row = 100 ;
static int net = 0 ;
static int subnet = 0 ;
static int universe = 0 ;
// カーソルキー入力
if( *key_code_length_st > 0 ) {
if( strcmp( key_code_st, _KEY_RIGHT ) == 0 ) {
if( ++universe > 7 ) universe = 7 ;
}
if( strcmp( key_code_st, _KEY_LEFT ) == 0 ) {
if( --universe < 0 ) universe = 0 ;
}
if( strcmp( key_code_st, _KEY_UP ) == 0 ) {
first_line-- ;
}
if( strcmp( key_code_st, _KEY_DOWN ) == 0 ) {
first_line++ ;
}
*key_code_length_st = 0 ;
}
// 対象ユニバースのデータをスタック
if( ( artdmx->net == net ) && ( artdmx->subnet == subnet ) && ( artdmx->universe == universe ) ) {
memcpy( &artdmx_disp, artdmx, sizeof( artdmx_t ) ) ;
}
// タイムカウント
clock_gettime( CLOCK_REALTIME, &now ) ; // 現在POSIX時間値取得
now_nsec = ( unsigned long long int )now.tv_sec * 1e9 // unsigned long long int型(8バイト長int)変数に
+ now.tv_nsec ; // 取得値をひとまとめにする(nsec)
if( now_nsec - prev_nsec < 5e7) return -1 ; // 経過時間が不足なら何もせずリターン
prev_nsec = now_nsec ; // 過去nsecを現在値としておく
// 画面のテキスト表示サイズを取得
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) ; // 画面サイズを取得 幅=ws.ws_col 高=ws.ws_row
if( row + 4 > ws.ws_row ) row = ws.ws_row - 4 ; // dumpの行数制限
// artdmxを表示
printf( "\e〔0;0H" ) ; // カーソルを左上に
printf( "Sender: %s:%d", artdmx_disp.senderip, artdmx_disp.senderport ) ;
printf( "\e〔28GID: %s", artdmx_disp.id ) ;
printf( "\e〔41GOpCode: 0x%04X", artdmx_disp.opcode ) ;
printf( "\e〔57GProVer: 0x%04X", artdmx_disp.prover ) ;
printf( "\e〔0K\nSequence: 0x%04X", artdmx_disp.sequence ) ;
printf( "\e〔19GPhysical: 0x%04X", artdmx_disp.physical ) ;
printf( "\e〔37GLength: %d", artdmx_disp.length ) ;
printf( "\e〔50G< Net:%d SubNet:%d Universe:%d >\e〔0K\n", artdmx_disp.net, artdmx_disp.subnet, artdmx_disp.universe ) ;
dump_print( artdmx_disp.data, artdmx_disp.length, col, row, &first_line, 0 ) ;
printf( "%8lld /%8lld nsec", *val1, *val2 ) ;
//fflush( stdout ) ;
// 終了
return 0 ;
}
#[Art-Net] #C言語
TaitanやETCでは正常なのにMA系の卓からの出力を正常に受信出来ないノードがあります。MAの卓は値が変化している最中は30fpsくらいですが、値の変化が無いと10fps位に落ちるのでコレが原因かなと妄想しています。DoctorMXでの計測ですが、レガシーDMXだけでなくArt-Netもしかりです。
原因は定かではありませんが繋がらないのは困ります。ArtNetPatchではどうしましょう。
fpsを一定にすることは外さないとして、ArtNetPatchの処理フェーズにも関係しそうな気がしてます。
#[Art-Net]
原因は定かではありませんが繋がらないのは困ります。ArtNetPatchではどうしましょう。
fpsを一定にすることは外さないとして、ArtNetPatchの処理フェーズにも関係しそうな気がしてます。
#[Art-Net]
ArtNetPatch は一時スタックに格納した後にどう処理するかが課題です。
一定以上の処理速度を確保しなければなりません。DMX512 は最大44fps ですので1フェーズあたり23msec.以下で動かす必要があります。4卓、各8ユニバースと想定するなら、受信1パケットあたりの総処理時間を710usec.以下にしなければなりません。RaspberryPi でも一時スタックに格納するまでの所要時間は150usec.くらいかと予想しますが、全体の処理が納まるかは感覚として微妙です。
Delay の扱いをどうするが鍵です。Delay を構成するには FIFO と呼ばれるループ型のスタックを使いますが、Art-Net を受信する度に FIFO に持って行くか、一旦一時スタックに留めて一定間隔で FIFO に持って行くか悩んでいます。前者ならソースコードは簡単ですがパケットの受信時刻を評価する回数が多く重くなり、後者ならソースコードが複雑になりますがスタックポインタの現在値からの単純なオフセットで処理出来るので軽くなります。簡単で重いか、複雑で軽いか、この両者の良し悪しは簡単には決められません。
後工程を考えずに前工程を決めてしまうと難儀することがあるので、工程全体をある程度イメージしてから進めなければなりません。
#[Art-Net]
一定以上の処理速度を確保しなければなりません。DMX512 は最大44fps ですので1フェーズあたり23msec.以下で動かす必要があります。4卓、各8ユニバースと想定するなら、受信1パケットあたりの総処理時間を710usec.以下にしなければなりません。RaspberryPi でも一時スタックに格納するまでの所要時間は150usec.くらいかと予想しますが、全体の処理が納まるかは感覚として微妙です。
Delay の扱いをどうするが鍵です。Delay を構成するには FIFO と呼ばれるループ型のスタックを使いますが、Art-Net を受信する度に FIFO に持って行くか、一旦一時スタックに留めて一定間隔で FIFO に持って行くか悩んでいます。前者ならソースコードは簡単ですがパケットの受信時刻を評価する回数が多く重くなり、後者ならソースコードが複雑になりますがスタックポインタの現在値からの単純なオフセットで処理出来るので軽くなります。簡単で重いか、複雑で軽いか、この両者の良し悪しは簡単には決められません。
後工程を考えずに前工程を決めてしまうと難儀することがあるので、工程全体をある程度イメージしてから進めなければなりません。
#[Art-Net]
ArtNetPatch は受信データを得るところまで考えてみました。
卓が1枚でユニバースも指定ならシンプルですが、有効なすべての卓とすべてのユニバースを得たいので少し複雑になりそうです。
構成の概略はこんな感じ。
Art-Net
↓
[Art-Net受信] UDP/IP、ポート番号0x1936のブロードキャストを受信。
↓
[IPアドレス、受信時刻、パケットを取得]
↓
[Art-Netフィルタ] パケットのIDを見てArt-Netパケットか判断。そうでないなら破棄しBreak。
↓
[Art-Net送信機リストに登録] IPアドレスをキーワードに送信機をリストに登録。
↓
[OpCodeフィルタ] Art-NetパケットのOpCodeで振り分け。とりあえずはArtDmxだけ扱い、その他なら破棄しBreak。
↓
[ArtDmxデコーダ] ArtDmxを変換し構造体に保存
↓
Loop
さらに別プロセスに送信機リストとArtDmxを表示する画面も作り、共有メモリとセマフォの機能を習得します。
#[Art-Net]
卓が1枚でユニバースも指定ならシンプルですが、有効なすべての卓とすべてのユニバースを得たいので少し複雑になりそうです。
構成の概略はこんな感じ。
Art-Net
↓
[Art-Net受信] UDP/IP、ポート番号0x1936のブロードキャストを受信。
↓
[IPアドレス、受信時刻、パケットを取得]
↓
[Art-Netフィルタ] パケットのIDを見てArt-Netパケットか判断。そうでないなら破棄しBreak。
↓
[Art-Net送信機リストに登録] IPアドレスをキーワードに送信機をリストに登録。
↓
[OpCodeフィルタ] Art-NetパケットのOpCodeで振り分け。とりあえずはArtDmxだけ扱い、その他なら破棄しBreak。
↓
[ArtDmxデコーダ] ArtDmxを変換し構造体に保存
↓
Loop
さらに別プロセスに送信機リストとArtDmxを表示する画面も作り、共有メモリとセマフォの機能を習得します。
#[Art-Net]
急ぎの用件が無かったので台車を仕上げました。仕掛品が邪魔だったからです。
しかし、気が付くと昼飯を除き約10時間ほど作業を続けてしまい体がヤバイ・・・。
半世紀以上使ってきた体ですからもうちっと労わらんとイカンですね。
ただ、こういう作業をした後のお風呂は妙に気持ちいい(笑
#器具の製作
しかし、気が付くと昼飯を除き約10時間ほど作業を続けてしまい体がヤバイ・・・。
半世紀以上使ってきた体ですからもうちっと労わらんとイカンですね。
ただ、こういう作業をした後のお風呂は妙に気持ちいい(笑
#器具の製作
2025年5月 この範囲を時系列順で読む この範囲をファイルに出力する
アタマがヒマな時にArtNetPatch の処理構成を考えています。
今日は現地照明の卓番でしたから時間はありました。居なきゃいけない、トラブル無ければやることない、もちろん寝てもいけない。こんな置きダヌキは妄想にふけるに限ります。
今のところ、Art-Net に流れているデータを表示するモニターから作ってみようかと。必要になるテクニックのほとんどを使うことになるので習作になりますし処理負荷が見えます。卓を何枚相手に出来るか、何ユニバース相手に出来るかの検討材料になります。
RaspberryPi-CM4 を母体に使う予定ですが、高性能を求めるのではなく RaspberryPi で作れる範囲の最高スペックを形にすることが課題です。昨年の試作では RaspberryPi4で卓3枚、入力合計12ユニバース、出力4ユニバースくらいならいけそうでした。ミキサーとしても使えるプロファイルカーブ・ディレイ付きのパッチマシンが欲しいワケですが、自分の仕事ではこの規模で御の字です。RaspberryPi を使う理由は安くて小さくて電気喰わなくて PIC などのマイコンと協調しやすいからです。PCレベルのマザーボードにSPIやI2Cが付いていればそれでもいいのですけど、それが期待できる工業用のマザーボードは一般のPCマザーボードに比べてお高いのです。
RaspberryPi上のDebianベースで作っておけば、ほぼそのまま工業用マザーボードに持って行ける期待感があります。Windowsベースでは難しいことですが、Debian(Linux)ベースでの製作はメリットが多いのです。
#[Art-net]
今日は現地照明の卓番でしたから時間はありました。居なきゃいけない、トラブル無ければやることない、もちろん寝てもいけない。こんな置きダヌキは妄想にふけるに限ります。
今のところ、Art-Net に流れているデータを表示するモニターから作ってみようかと。必要になるテクニックのほとんどを使うことになるので習作になりますし処理負荷が見えます。卓を何枚相手に出来るか、何ユニバース相手に出来るかの検討材料になります。
RaspberryPi-CM4 を母体に使う予定ですが、高性能を求めるのではなく RaspberryPi で作れる範囲の最高スペックを形にすることが課題です。昨年の試作では RaspberryPi4で卓3枚、入力合計12ユニバース、出力4ユニバースくらいならいけそうでした。ミキサーとしても使えるプロファイルカーブ・ディレイ付きのパッチマシンが欲しいワケですが、自分の仕事ではこの規模で御の字です。RaspberryPi を使う理由は安くて小さくて電気喰わなくて PIC などのマイコンと協調しやすいからです。PCレベルのマザーボードにSPIやI2Cが付いていればそれでもいいのですけど、それが期待できる工業用のマザーボードは一般のPCマザーボードに比べてお高いのです。
RaspberryPi上のDebianベースで作っておけば、ほぼそのまま工業用マザーボードに持って行ける期待感があります。Windowsベースでは難しいことですが、Debian(Linux)ベースでの製作はメリットが多いのです。
#[Art-net]
電装工芸の本体ページを見たら昨日のアクセス数が564でした。これまでは多くても100前後でしたので驚いた。自分で言うのもナンですが誰が見てんだ?
#雑記
#雑記
この後しばらく日程が緩いので、仕掛かり品の台車とDMX切替機の仕上げをする予定です。
DMX切替機はフェスなどで複数の調光卓を使う際に卓を選択する装置です。DMX1ユニバースの製品なので複数ユニバース使う場合に複数を1台の選択スイッチに連動する機能とHOLD機能の追加です。
HOLDは自分が未熟だったのもありますが、2kBのメモリを持ったPIC16を安価に入手出来る様になってようやく作れるようになったのです。DMXの512バイトのスタックは不整合を防止するには2面必要ですが、PIC16系のメモリは最近まで1024バイトが頭打ちだったので手が止まっていました。こんなPICマイコンが200円以下で買えるのですから良い時代になったものです。
あとは、出来ることならArt-Netパッチの製作も進めたいですね・・・。パッチ、プロファイルカーブ、ディレイが主題ですが、RaspberryPiでもC言語でプログラムすれば8ユニバースくらい扱えそうです。DMXミックスやアクティブにするArt-Netの入力経路の選択機能も入れる予定なので対象調光卓の選択も可能です。私の感覚で全てのことが出来るパッチマシンが目標です。こんなのを1万円程度で買えるRaspberryPi上で動かしたらメーカーさんに嫌がられそうですが、カスタマーサポートをしきれないので自社使用と理解してくれる同業者にしか売るつもりはありません。カスタマーサポートがどんだけ大変で面倒かを体験するとどんだけ便利で間違いなく売れるモノを作っても自分で使う範囲に留めたくなるのです。50万円の粗利があっても100万円分の手間がかかっては損得以前に心が折れます。
みなさん、メーカーさんや販売店さんに過剰な要求をしてませんか?お客さま、購買者は神様ではありません。三波春夫先生の聴衆に対するリップサービスであって、売る側が買う側に忖度する常識論・責任論ではありません。適正な対価も払わんで文句を言うだけならクレーマーであってお客ぢゃありません。持ちつ持たれつの同格の気持ちをどうかお忘れになりませんように。。。
#器具の製作
DMX切替機はフェスなどで複数の調光卓を使う際に卓を選択する装置です。DMX1ユニバースの製品なので複数ユニバース使う場合に複数を1台の選択スイッチに連動する機能とHOLD機能の追加です。
HOLDは自分が未熟だったのもありますが、2kBのメモリを持ったPIC16を安価に入手出来る様になってようやく作れるようになったのです。DMXの512バイトのスタックは不整合を防止するには2面必要ですが、PIC16系のメモリは最近まで1024バイトが頭打ちだったので手が止まっていました。こんなPICマイコンが200円以下で買えるのですから良い時代になったものです。
あとは、出来ることならArt-Netパッチの製作も進めたいですね・・・。パッチ、プロファイルカーブ、ディレイが主題ですが、RaspberryPiでもC言語でプログラムすれば8ユニバースくらい扱えそうです。DMXミックスやアクティブにするArt-Netの入力経路の選択機能も入れる予定なので対象調光卓の選択も可能です。私の感覚で全てのことが出来るパッチマシンが目標です。こんなのを1万円程度で買えるRaspberryPi上で動かしたらメーカーさんに嫌がられそうですが、カスタマーサポートをしきれないので自社使用と理解してくれる同業者にしか売るつもりはありません。カスタマーサポートがどんだけ大変で面倒かを体験するとどんだけ便利で間違いなく売れるモノを作っても自分で使う範囲に留めたくなるのです。50万円の粗利があっても100万円分の手間がかかっては損得以前に心が折れます。
みなさん、メーカーさんや販売店さんに過剰な要求をしてませんか?お客さま、購買者は神様ではありません。三波春夫先生の聴衆に対するリップサービスであって、売る側が買う側に忖度する常識論・責任論ではありません。適正な対価も払わんで文句を言うだけならクレーマーであってお客ぢゃありません。持ちつ持たれつの同格の気持ちをどうかお忘れになりませんように。。。
#器具の製作
修理した Antari F1-FAZER を小ぶりな野外フェスで使っています。風には負けますが、煙量はアホかと思うくらい。
まだ確信の段階ではありませんが、使用の度に洗浄液を通すのは効果がありそうです。
#器具の修理
まだ確信の段階ではありませんが、使用の度に洗浄液を通すのは効果がありそうです。
#器具の修理
先日ヒーター(発煙器)を新品に交換した Antari F1-FAZER を昨日の現場で使ったところ2台のウチ1台がオーバーヒートの警告。
煙は出ませんので念のため持ってきていた予備機に交換して現場としては事なきを得ましたが、明けての今日稼働させても再現せず。「ボク、昨日もバッチリ働いたもん♪」って顔で煙を吐きます。なんか腹立つ。
温度センサからの電圧を受ける基板の端子が怪しいように感じたので稼働テストする前に挿し直しをしましたが、端子の接触具合いで奇妙なヒステリンスでも起きていたのでしょうか。温度センサーの熱電帯は微弱な電圧・電流しか出しませんから端子の接触が悪いと誤認するのかもしれません。ヒステリンスの様な障害があれば温度が一定以上になった途端に検知電圧が上がる可能性はあります。
動いてくれればそれでいいのですが、ヒーター(発煙器)を交換した後5時間くらい稼働テストをしていますので、なぜ警告が出たのかスッキリしません。
日を改めて長時間稼働させてみましょう。
追記
オーバーヒートの警告が出た Antari F1-FAZER の稼働テストを続けていますが警告は出ません。アホかってくらい煙が出ています。あまりの煙にお隣の自動車修理工場のご主人が火事ぢゃないよね!?と心配していらっしゃったくらい(笑
コロナ以降、劇場の空調の排気が強くなっている傾向があり、コンセプトなら太刀打ちできますが、水性スモークマシンは残留が弱くて1台では負けることがありますので2台焚きを基本にしています。1台が動かなくなっても残りの1台があれば薄くともビームは出ますので相互バックアップの意味もあります。
要の部品を交換したとはいえ、一度壊れた器具を完全回復させるのは難しいですね。こういうのは倉庫でのテストでは正常でも現場ではおかしくなる内弁慶さんかな!?。
お塩とお神酒で簡易なお祓いをすると治るのかもしれません。機材が動くかの最後は神頼み運頼みですから・・・
追記の2
機材修理の最後は神頼みです。しめ縄の作り方と祝詞を研究しましょうか・・・
故障した道具には濁ったナニかがまとわりつく気配を感じます。故障部位の健全化が必須だとしても、そこには悪戯好きの何某が居ると感じるのです。
機械のことを勉強すればするほど、修理の経験を積めば積むほど、付喪神の存在を当たり前に感じます。
舞台は人の想いが集まるところですから、そこで使う道具は付喪神が憑きやすいのかもしれません。
感謝と労わりを以って機材たちと向き合いたいものです。
日本の舞台は引き籠りの天照大御神を天岩戸から引っ張り出したアマノ・ウズメのストリップ公演が記録に残る最初でしょう。性的アプローチや酔っぱらったオッサンたちのバカ騒ぎの是非はともかく、その石舞台と天岩戸が最初の舞台機構と言ってもいい。神々が使ったものですからそこに魂が宿っても不思議はありません。そこまで高貴でなくとも、人の想いが集まるところで使ったモノには何かが宿るものだと思ったりしてます。
#器具の修理
煙は出ませんので念のため持ってきていた予備機に交換して現場としては事なきを得ましたが、明けての今日稼働させても再現せず。「ボク、昨日もバッチリ働いたもん♪」って顔で煙を吐きます。なんか腹立つ。
温度センサからの電圧を受ける基板の端子が怪しいように感じたので稼働テストする前に挿し直しをしましたが、端子の接触具合いで奇妙なヒステリンスでも起きていたのでしょうか。温度センサーの熱電帯は微弱な電圧・電流しか出しませんから端子の接触が悪いと誤認するのかもしれません。ヒステリンスの様な障害があれば温度が一定以上になった途端に検知電圧が上がる可能性はあります。
動いてくれればそれでいいのですが、ヒーター(発煙器)を交換した後5時間くらい稼働テストをしていますので、なぜ警告が出たのかスッキリしません。
日を改めて長時間稼働させてみましょう。
追記
オーバーヒートの警告が出た Antari F1-FAZER の稼働テストを続けていますが警告は出ません。アホかってくらい煙が出ています。あまりの煙にお隣の自動車修理工場のご主人が火事ぢゃないよね!?と心配していらっしゃったくらい(笑
コロナ以降、劇場の空調の排気が強くなっている傾向があり、コンセプトなら太刀打ちできますが、水性スモークマシンは残留が弱くて1台では負けることがありますので2台焚きを基本にしています。1台が動かなくなっても残りの1台があれば薄くともビームは出ますので相互バックアップの意味もあります。
要の部品を交換したとはいえ、一度壊れた器具を完全回復させるのは難しいですね。こういうのは倉庫でのテストでは正常でも現場ではおかしくなる内弁慶さんかな!?。
お塩とお神酒で簡易なお祓いをすると治るのかもしれません。機材が動くかの最後は神頼み運頼みですから・・・
追記の2
機材修理の最後は神頼みです。しめ縄の作り方と祝詞を研究しましょうか・・・
故障した道具には濁ったナニかがまとわりつく気配を感じます。故障部位の健全化が必須だとしても、そこには悪戯好きの何某が居ると感じるのです。
機械のことを勉強すればするほど、修理の経験を積めば積むほど、付喪神の存在を当たり前に感じます。
舞台は人の想いが集まるところですから、そこで使う道具は付喪神が憑きやすいのかもしれません。
感謝と労わりを以って機材たちと向き合いたいものです。
日本の舞台は引き籠りの天照大御神を天岩戸から引っ張り出したアマノ・ウズメのストリップ公演が記録に残る最初でしょう。性的アプローチや酔っぱらったオッサンたちのバカ騒ぎの是非はともかく、その石舞台と天岩戸が最初の舞台機構と言ってもいい。神々が使ったものですからそこに魂が宿っても不思議はありません。そこまで高貴でなくとも、人の想いが集まるところで使ったモノには何かが宿るものだと思ったりしてます。
#器具の修理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132