Archive: 2014/06/16

fplug_for_linux

先日導入したgoto2048/fplug_for_linux

F-PLUG
F-PLUG

ゴミデータっぽい値が採れたりしたので改修にトライしていたが、シリアル通信のパラメータやリトライ手順など地道にプロトコル実装を固める事で、1週間以上連続で安定して(ペアリングも解除されずに)計測できる事を確認した。

ポイントとしては

  • RTS/CTSによるフロー制御
  • Rawモード送信
  • 非カノニカル受信
  • 応答が無い場合は要求を再送信
で、最終版のfpstatusは以下の通り。
#include
#include
#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; cnt printf( "%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("%s:%d; write()=%d,errno=%d\n", __FILE__, __LINE__, ret, errno);
#endif
switch ( errno ){
case ENOTCONN :
tmspec.tv_nsec = 500 * 1000 * 1000;
nanosleep(&tmspec, NULL);
break;
}
}
if ( ret <= 0 )
break;

for (j = 0;j < MSG_RETRY_MAX && !(ret = read(fd, res_buf, bufsiz)); j++ ) {
tmspec.tv_sec = 0;
tmspec.tv_nsec = (j+1) * 100 * 1000 * 1000;
nanosleep(&tmspec, NULL);
}
if ( ret <= 0 ){
#ifdef DEBUG
printf("%s:%d; read()=%d,errno=%d\n", __FILE__, __LINE__, ret, errno);
#endif
continue;
}

dump_message( "read:", res_buf, ret );
if (4 < ret && !memcmp(req_buf, res_buf, 4)){ // TID match
#ifdef DEBUG
printf("%s:%d; read()=%d\n", __FILE__, __LINE__, ret);
#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, "x");
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);
}