// CCS811からのデータ取得プログラムは、下記を参照。 // // CCS811 Air Quality Sensor demo program // Copyright (c) 2017 Larry Bank // email: bitbank@pobox.com // Project started 11/5/2017 // // 上記ライブラリを元に、30秒おきにデータ取得部し // 保存しておいた値を TCP/10007 で取得できるように // プログラムを作成。 // // 動作確認 // $ ccs811 センサー値を随時出力動作 // $ ccs811 -d (daemon化) // データ取得 // $ /usr/bin/nc localhost 10007 // 432 10 eCO2,TVOC 値 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ccs811.h" #define DEBUG int i2c_channel = 1 ; int ccs811_i2c_addr = 0x5A ; int ccs811_listen_port = 10007 ; int ccs811_interval_sec = 30 ; volatile int ccs811_eCO2 = 0 ; volatile int ccs811_TVOC = 0 ; pthread_mutex_t ccs811_mutex ; int flag_daemon = 0 ; int flag_echoback = 0 ; // CCS811 の測定スレッド int ccs811_setup() { // Check which I2C channel you're using // Raspberry Pi's usually use channel 1 // Other ARM boards tend to use channel 0 pthread_mutex_init( &ccs811_mutex , NULL ) ; if ( ccs811Init( i2c_channel , ccs811_i2c_addr ) != 0 ) { if ( !flag_daemon ) printf( "ccs811Init fail\n" ) ; return 1 ; // problem - quit } sleep( 1 ) ; // wait for data to settle for first read return 0 ; } void* ccs811_main() { for( ;; ) { int eco2 , tvoc ; if ( ccs811ReadValues( &eco2 , &tvoc ) ) { #if defined( DEBUG ) if ( !flag_daemon ) printf( "eCO2=%d , TVOC=%d\n" , eco2 , tvoc ) ; #endif // 参照側と排他処理 pthread_mutex_lock( &ccs811_mutex ) ; ccs811_eCO2 = eco2 ; ccs811_TVOC = tvoc ; pthread_mutex_unlock( &ccs811_mutex ) ; } else { #if defined( DEBUG ) if ( !flag_daemon ) printf( "ccs811ReadValues fail\n" ) ; #endif } sleep( ccs811_interval_sec ) ; // every 10 seconds } } int thread_main() { pthread_t thread ; int ret ; int listen_socket ; int sock_optval = 1 ; struct sockaddr_in sock_in ; if ( ccs811_setup() ) { if ( !flag_daemon ) printf( "pthread_create fail\n" ) ; exit( 1 ) ; } // ccs811_main をスレッドで起動 if ( (ret = pthread_create( &thread , NULL , ccs811_main , NULL )) != 0 ) { if ( !flag_daemon ) printf( "pthread_create fail\n" ) ; exit( 1 ) ; } // スレッド終了を待たない if ( (ret = pthread_detach( thread )) != 0 ) { if ( !flag_daemon ) printf( "pthread_detach fail\n" ) ; exit( 1 ) ; } // ソケットを割り当てる if ( (listen_socket = socket( PF_INET , SOCK_STREAM , 0 )) < 0 ) { if ( !flag_daemon ) printf( "socket fail\n" ) ; exit( 1 ) ; } // ソケットのオプション設定 if ( setsockopt( listen_socket , SOL_SOCKET , SO_REUSEADDR , &sock_optval , sizeof( sock_optval ) ) < 0 ) { if ( !flag_daemon ) printf( "setsockopt fail\n" ) ; exit( 1 ) ; } // ソケットの入力設定 sock_in.sin_family = AF_INET ; sock_in.sin_port = htons( ccs811_listen_port ) ; sock_in.sin_addr.s_addr = htonl( INADDR_ANY ) ; // バインドする if ( bind( listen_socket , (struct sockaddr*)&sock_in , sizeof( sock_in )) < 0 ) { if ( !flag_daemon ) printf( "bind fail\n" ) ; exit( 1 ) ; } // ソケットへの接続待ち if ( listen( listen_socket , SOMAXCONN ) < 0 ) { if ( !flag_daemon ) printf( "listen fail\n" ) ; exit( 1 ) ; } // 接続相手からの受信ループ for( ;; ) { struct hostent* remote_host ; struct sockaddr_in peer_sock_in ; int connected_socket ; socklen_t len ; char buff[ 1024 ] ; char* p ; len = sizeof( peer_sock_in ) ; if ( (connected_socket = accept( listen_socket , (struct sockaddr*)&peer_sock_in , &len )) < 0 ) { if ( !flag_daemon ) printf( "accept fail\n" ) ; exit( 1 ) ; } remote_host = gethostbyaddr( (char*)&peer_sock_in.sin_addr.s_addr , sizeof( peer_sock_in.sin_addr ) , AF_INET ) ; if ( remote_host == NULL ) { if ( !flag_daemon ) printf( "gethostbyname fail\n" ) ; exit( 1 ) ; } #if defined( DEBUG ) if ( !flag_daemon ) printf( "remote: %s %s port %d\n" , remote_host->h_name , inet_ntoa( peer_sock_in.sin_addr ) , ntohs( peer_sock_in.sin_port ) ) ; #endif if ( flag_echoback ) { // 1行入力 p = buff ; while( p < buff + sizeof( buff ) - 1 ) { int ret ; if ( (ret = read( connected_socket , p , 1 )) < 0 ) { if ( !flag_daemon ) printf( "connection read fail\n" ) ; exit( 1 ) ; } else if ( ret == 0 || *p == '\n' ) { break ; } } *p = '\0' ; if ( !flag_daemon ) printf( "receive %s\n" , buff ) ; } // データ書き込み側と排他処理 pthread_mutex_lock( &ccs811_mutex ) ; if ( flag_echoback ) { if ( strncasecmp( buff , "eco2" , 4 ) == 0 ) { sprintf( buff , "%d\n" , ccs811_eCO2 ) ; } else if ( strncasecmp( buff , "tvoc" , 4 ) == 0 ) { sprintf( buff , "%d\n" , ccs811_TVOC ) ; } else { sprintf( buff , "%d %d\n" , ccs811_eCO2 , ccs811_TVOC ) ; } } else { sprintf( buff , "%d %d\n" , ccs811_eCO2 , ccs811_TVOC ) ; } pthread_mutex_unlock( &ccs811_mutex ) ; // 通信相手に返信 write( connected_socket , buff , strlen( buff ) ) ; #if defined( DEBUG ) if ( !flag_daemon ) puts( buff ) ; #endif if ( !flag_daemon ) printf( "Connection closed\n" ) ; if ( close( connected_socket ) < 0 ) { if ( !flag_daemon ) printf( "connection close failed\n" ) ; exit( 1 ) ; } } if ( close( listen_socket ) < 0 ) { if ( !flag_daemon ) printf( "listen close fail\n" ) ; exit( 1 ) ; } } char* proc_name = NULL ; int main( int argc , char* argv[] ) { // プロセス名保存 proc_name = argv[0] ; argc-- , argv++ ; while( argc > 0 ) { if ( argc >= 2 && strcmp( argv[ 0 ] , "-c" ) == 0 ) { // i2cチャネル argc-- , argv++ ; i2c_channel = strtol( argv[0] , NULL , 0 ) ; argc-- , argv++ ; } else if ( argc >= 2 && strcmp( argv[ 0 ] , "-a" ) == 0 ) { // i2cアドレス argc-- , argv++ ; ccs811_i2c_addr = strtol( argv[0] , NULL , 0 ) ; argc-- , argv++ ; } else if ( argc >= 2 && strcmp( argv[ 0 ] , "-p" ) == 0 ) { // ポート番号 argc-- , argv++ ; ccs811_listen_port = strtol( argv[0] , NULL , 0 ) ; argc-- , argv++ ; } else if ( argc >= 2 && strcmp( argv[ 0 ] , "-i" ) == 0 ) { // サンプリング間隔 argc-- , argv++ ; ccs811_interval_sec = strtol( argv[0] , NULL , 0 ) ; argc-- , argv++ ; if ( ccs811_interval_sec <= 0 || ccs811_interval_sec > 3600 ) { printf( "ccs811: interval 1..3600\n" ) ; exit( 1 ) ; } } else if ( argc >= 1 && strcmp( argv[ 0 ] , "-d" ) == 0 ) { argc-- , argv++ ; flag_daemon = 1 ; } else if ( argc >= 1 && strcmp( argv[ 0 ] , "-e" ) == 0 ) { argc-- , argv++ ; flag_echoback = 1 ; } else { printf( "Unknown option %s\n" , argv[0] ) ; exit( 1 ) ; } } // オプションでデーモン化したうえで、thread_main() を呼出す。 if ( flag_daemon ) { if ( daemon( 0 , 0 ) == 0 ) { thread_main() ; } else { printf( "Error at daemon()\n" ) ; } } else { thread_main() ; } return 0 ; } /// Local Variables: /// /// mode: c /// /// End: ///