YANO's digital garage

Copyright ©YANO All rights reserved. https://www.bravotouring.com/~yano/

Last-modified: 2024-04-08 (月)


[一語一絵/IT系]

fplug_for_linux / 2014-05-28 (水)

先日導入した[External]goto2048/fplug_for_linux

F-PLUG
F-PLUG

温度(Temperature)の応答メッセージが1バイト短い問題は、ひとまずデータの最後から2バイトに注目するように改修したのだが、やはり「1バイト短い」だけではなく別種別の応答が返ってくる事例もあってゴミデータっぽい値となっている事がわかった。

そういうわけで定石通り「SEOJクラスコード」が期待と違ったらリトライするようにしようかと思ったのだが、そこで温度(Temperature)の応答メッセージで「SEOJクラスコード」が漏れる問題に再び行く手を阻まれた。

もしかして、TIDが使われていない(常時ゼロ)のが問題なのではないか?というのも気になったので、カウントアップするTIDを載せてみたものの結果は変わらず。しかし、「SEOJクラスコード」が無くても「TIDがある」事で各情報の要求と応答メッセージが紐付けできるようになるので、fpstatusを下のように改修してみた。

#include <stdint.h>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <time.h>
#include <string.h>

#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<size; 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("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 <option>\n");
        return(0);
    }
    if ( *argv[1] == '-' ) argv[1]++;

    fd = open(SERIAL_PORT, O_RDWR);
    if ( fd < 0 ){
        perror("open(/dev/rfcomm0)");
        return 0;
    }

    tcgetattr( fd, &oldtio );
    newtio = oldtio;
    newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
    tcsetattr(fd, TCSANOW, &newtio);

    for ( cmd = argv[1]; cmd && *cmd; cmd++ )
        fplug_main(fd, *cmd);

    printf( "\n");

    tcsetattr(fd, TCSANOW, &oldtio);
    close(fd);

    return 0;
}
受信メッセージが期待する種別の応答でない場合は新しいTIDをアサインして要求からリトライする。5回送信しても期待する種別の応答が得られなかった場合、取得値は"--"となる。

【29日追記】今朝ほどログチェックしたところ深夜0時過ぎから欠測している事がわかった。bluetooth serviceを再起動して復旧したかに思えたが、1時間ほどで再び応答が無くなり、F-PLUGを見たところペアリングも解除されて初期状態になっている事に気が付いた。再ペアリングにトライするものの、何度やっても成功せず断念。

改めてコンセントを抜き差しした後、最終確認なWindows 7でもペアリングできなかったのでいよいよ故障で確定かと思い始めたが、念のためと[External]動作確認済みBluetooth® USBアダプター一覧にある中から発注しておいた[External]iBUFFALO Bluetooth USBアダプター 3.0+EDR対応 class2 ブラック BSHSBD04BKが届いていたので、PLANEXのBT-MicroEDR2から差し替えみてみたところあっさりペアリングに成功した。

[External]Bluetoothのバージョン違いに起因する可能性もあるが、最初はペアリングできていたので単なる実装ズレのような印象だ。[External]動作確認済みBluetooth® USBアダプター一覧には

Bluetooth® USBアダプターをご利用の際には、各社付属のBluetooth®ドライバーはインストールせずに、OS(Windows)標準のドライバーをご利用ください。
OS標準のドライバーをご利用にならないと、パソコンとF-PLUGがうまくペアリングできません。
と書いてあるので「Linux標準」ではダメかにゃ?と心配したのだが、Ubuntu 14.04(Trusty Tahr)ML110G7でも再ペアリングできたので、これで通信が安定してくれる事を期待したい。

【参照】
●富士通ビー・エス・シー http://www.bsc.fujitsu.com/
F-PLUG(エフプラグ)
F-PLUGの注意事項 : 動作確認済みBluetooth® USBアダプター一覧
F-PLUG メッセージ一覧
●株式会社バッファロー BUFFALO http://buffalo.jp/
Bluetooth®3.0+EDR対応 USBアダプター(class2)
●Amazon.co.jp https://www.amazon.co.jp/
富士通BSC F-PLUG115 電力・温度・湿度・照度測定機能つきプラグ ホワイト BSCESFP0103 4,900円
iBUFFALO Bluetooth USBアダプター 3.0+EDR対応 class2 ブラック BSHSBD04BK 906円1,625円