fplug_for_linux
先日導入したgoto2048/fplug_for_linux。
![]() |
| F-PLUG |
温度(Temperature)の応答メッセージが1バイト短い問題は、ひとまずデータの最後から2バイトに注目するように改修したのだが、やはり「1バイト短い」だけではなく別種別の応答が返ってくる事例もあってゴミデータっぽい値となっている事がわかった。
そういうわけで定石通り「SEOJクラスコード」が期待と違ったらリトライするようにしようかと思ったのだが、そこで温度(Temperature)の応答メッセージで「SEOJクラスコード」が漏れる問題に再び行く手を阻まれた。
もしかして、TIDが使われていない(常時ゼロ)のが問題なのではないか?というのも気になったので、カウントアップするTIDを載せてみたものの結果は変わらず。しかし、「SEOJクラスコード」が無くても「TIDがある」事で各情報の要求と応答メッセージが紐付けできるようになるので、fpstatusを下のように改修してみた。
#include受信メッセージが期待する種別の応答でない場合は新しいTIDをアサインして要求からリトライする。5回送信しても期待する種別の応答が得られなかった場合、取得値は"--"となる。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "fplug.h"
#undef DEBUG
#define ENOTCONN_RETRY_MAX 10
#define MSG_RETRY_MAX 5
#define FPLUG_EXEC(fd,msg,buf) fplug_exec((fd),(msg),sizeof((msg)),(buf),sizeof((buf)))
typedef unsigned char uchar;
static uint16_t tid = 0x0001;
void hunt_tid(uchar *buf)
{
*(uint16_t *)&buf[2] = tid++;
}
typedef uchar uchar;
static void dump_message( char *mes, uchar *buf, int size )
{
#ifdef DEBUG
int cnt;
printf( "%s", mes );
for ( cnt=0; cntprintf( "%02X,", buf[cnt] );
}
printf( "\n" );
#endif
return;
}
int fplug_exec(int fd, uchar *req_msg, size_t req_len, uchar *res_buf, size_t bufsiz)
{
struct timespec tmspec = { 0, 1000 * 1000 };
int ret, i, j;
uchar req_buf[BUFSIZ];
memcpy(req_buf, req_msg, req_len);
for (i = 0;i < MSG_RETRY_MAX; i++ ) {
hunt_tid(req_buf);
dump_message( "Command:", req_buf, req_len);
for (ret = j = 0;j < ENOTCONN_RETRY_MAX; j++ ) {
ret = write(fd, req_buf, req_len);
if ( ret == req_len )
break;
#ifdef DEBUG
printf("write()=%d,errno=%d\n", ret, errno);
#endif
switch ( errno ){
case ENOTCONN :
tmspec.tv_nsec = 500 * 1000 * 1000;
nanosleep(&tmspec, NULL);
break;
}
}
if ( ret <= 0 )
break;
tmspec.tv_sec = 0;
tmspec.tv_nsec = 250 * 1000 * 1000;
nanosleep(&tmspec, NULL);
ret = read(fd, res_buf, bufsiz);
if ( ret <= 0 )
continue;
dump_message( "read:", res_buf, ret );
if (4 < ret && !memcmp(req_buf, res_buf, 4)){ // TID match
#ifdef DEBUG
printf("read()=%d,errno=%d\n", ret, errno);
#endif
return ret;
}
}
return -1;
}
int fplug_main( int fd, int mode )
{
int cmd;
int cnt;
int ret;
int i=0;
uchar buf[BUFSIZ];
uchar *szMode, szResult[BUFSIZ];
time_t timer;
struct tm *t;
strcpy(szResult, "--");
szMode = szResult;
switch(mode) {
case 'h':
szMode = "FP_HUMID";
for ( i = 0; i < MSG_RETRY_MAX && 0 < (ret = FPLUG_EXEC(fd, Humid, buf)); i++ ){
uint16_t a = *(uint16_t *)&buf[ret-2];
if ( 100 < a )
continue;
sprintf(szResult, "%d", a );
break;
}
break;
case 'i':
szMode = "FP_ILLUM";
for ( i = 0; i < MSG_RETRY_MAX && 0 < (ret = FPLUG_EXEC(fd, Illum, buf)); i++ ){
uint16_t a = *(uint16_t *)&buf[ret-2];
if ( 0xFFFD < a )
continue;
sprintf(szResult, "%d", a );
break;
}
break;
case 't':
szMode = "FP_TEMP";
for ( i = 0; i < MSG_RETRY_MAX && 0 < (ret = FPLUG_EXEC(fd, Temp, buf)); i++ ){
int16_t a = *(int16_t *)&buf[ret-2];
if ( a < -100 || 500 < a )
continue;
sprintf(szResult, "%.1f", (float)a / 10);
break;
}
break;
case 'w':
szMode = "FP_WATT";
for ( i = 0; i < MSG_RETRY_MAX && 0 < (ret = FPLUG_EXEC(fd, RWatt, buf)); i++ ){
int16_t a = *(int16_t *)&buf[ret-2];
if ( 2000 < a )
continue;
sprintf(szResult, "%.1f", (float)a / 10);
break;
}
break;
default:
szMode = "FP_unknown";
break;
}
printf( "%s=%s;", szMode, szResult);
}
int main(int argc, char *argv[])
{
int fd;
struct termios oldtio, newtio;
char *cmd;
if ( argc == 1 ) {
printf("Usage: fpstatus
