いとうです。相変わらず思わしくありませんが、試したことのレポートです。

From: Kouichi Hirabayashi <k...@mogami.com>
Subject: [FreeBSD-users-jp 94055] Re: umodem で PICC18F2550 にアクセスすると不安定
Date: Thu, 15 Nov 2012 22:37:46 +0900

> 相手のデバイスがコマンド(BARH\r\n)を読めていないか、
> コマンド/レスポンスがちぐはぐになっているような気が
> します。相手側のデータを読み出す方法があるとよいの
> ですが、それが非現実的でないとしたら、select() を使
> わすに、
> 
>   open();     // LF 終端の canonincal 入力
>   sleep();    // 1, 2 秒とか長めにして
>   write();    // コマンド
>   read();

やってみましたが、状況は変わりませんでした。

> を試して、それでもためなら、open() でデリミタ(LF)で
> なく 1 バイト単位の入力を指定して、バイト単位で読ん
> で見ると何かわかるかもしれません。

いただいたアドバイスを反映したつもりで、末尾のようなコードを試してみま
した。

- raw モードにして、1Byte ずつ sleep()しながら write()し、read()も
  1Byte ずつ読むようにした。
- read()の前の select()を復活させて、気圧計側が待ちに入っているようなら
  再送するようにした…つもりだが、うまくいっていない模様。

というのが気をつけたところです。

結果は
-----
# ./test11
i = 0
  j = 0
    BARH
      :
    (略)
      :
i = 9
  j = 0
    BARH
    calling select()  back from select(), n = 1
calling read()   c = '1'(0x31)  calling read()   c = '0'(0x30)  calling read()  
 c = '0'(0x30)  calling read()   c = '4'(0x34)  calling read()   c = '.'(0x2e)  
calling read()   c = '5'(0x35)  calling read()   c = 'h'(0x68)  calling read()  
 c = 'P'(0x50)  calling read()   c = 'a'(0x61)  calling read()   c = '.'(0x0d)  
calling read()   c = '.'(0x0a)  calling read()   c = '>'(0x3e)
rmesg: 1004.5hPa
>
i = 10
  j = 0
    BARH
    calling select()  back from select(), n = 0
  j = 1
    BARH
    calling select()  back from select(), n = 0
  j = 2
    BARH
    calling select()  back from select(), n = 0
  j = 3
    BARH
    calling select()  back from select(), n = 0
  retry limit of write() exceeded.
-----
と、read()の手前の select()がタイムアウトして、さらに close()が帰って来
ません。

$ ps alxwwp 98979
  UID   PID  PPID CPU PRI NI   VSZ   RSS MWCHAN STAT  TT       TIME COMMAND
    0 98979 91357   0  44  0  5832  1052 ttyout I+     1    0:00.00 ./test11

と、今度は ttyout でブロックされています。

なお、0x0a の次の'>'は、気圧計のコマンドラインのプロンプトです。
-----
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>

#define PAUSE   2
#define MAX_RETRY       3

main()
{
        int     i,
                j,
                k,
                fd;
        size_t  tlen;
        ssize_t n;
        char    *tmesg,
                c,
                *p,
                rmesg[16];
        fd_set  fds;
        struct termios  tios;
        struct timeval  timeout;

        for (i = 0; ; i++) {
                printf("i = %d\n", i);
                if ( (fd = open("/dev/cuaU0", O_RDWR) ) < 0) {
                        err(1, "open()");
                }
                sleep(PAUSE);
                if (ioctl(fd, TIOCEXCL) < 0) {
                        err(1, "ioctl(TIOCEXCL)");
                }
                if (tcflush(fd, TCOFLUSH) < 0) {
                        err(1, "tcflush(TCOFLUSH)");
                }
                if (tcflush(fd, TCIFLUSH) < 0) {
                        err(1, "tcflush(TCIFLUSH)");
                }
                if (tcgetattr(fd, &tios) < 0) {
                        err(1, "tcgetattr()");
                }
                tios.c_cc[VMIN] = 0;
                tios.c_cc[VTIME] = 100;
                tios.c_cflag |= (CREAD | CLOCAL);
                tios.c_iflag &= ~(IXON | IXOFF | IMAXBEL);
                tios.c_lflag &= ~(ECHO | ECHONL);
                cfmakeraw(&tios);
                if (tcsetattr(fd, TCSADRAIN, &tios) < 0) {
                        err(1, "tcsetattr()");
                }
                timeout.tv_sec = 1;
                timeout.tv_usec = 0;
                tmesg = "BARH\r\n";
                tlen = strlen(tmesg);
                p = rmesg;
                j = 0;
                do {
                        printf("  j = %d\n    ", j);
                        for (k = 0; k < tlen; k++) {
                                sleep(PAUSE);
                                if (write(fd, &tmesg[k], 1) < 0) {
                                        err(1, "write()");
                                }
                                putchar(tmesg[k] );
                                fflush(stdout);
                        }
                        FD_ZERO(&fds);
                        FD_SET(fd, &fds);
                        printf("    calling select()");
                        fflush(stdout);
                        if ( (n = select(fd + 1, &fds, NULL, NULL,
                                        &timeout) ) < 0) {
                                err(1, "select() for read()");
                        }
                        printf("  back from select(), n = %d\n", n);
                } while ( (n == 0) && j++ < MAX_RETRY);
                if (!n) {
                        printf("  retry limit of write() exceeded.\n");
                        close(fd);
                        printf("  back from close()\n");
                        sleep(PAUSE);
                        exit(1);
                }
                j = 0;
                while ( (j < MAX_RETRY) && (p - rmesg < sizeof(rmesg) ) ) {
                        printf("calling read()  ");
                        fflush(stdout);
                        if ( (n = read(fd, &c, 1) ) < 0) {
                                err(1, "read()");
                                close(fd);
                                sleep(PAUSE);
                                exit(1);
                        }
                        if (n) {
                                printf(" c = '%c'(0x%02x)  ",
                                        isprint(c)? c:'.', c);
                        } else {
                                printf(" n = 0  ");
                        }
                        fflush(stdout);
                        if (c) {
                                *p++ = c;
                        } else {
                                j++;
                        }
                        if (c == '>') {
                                goto DONE;
                        }
                }
                printf("retry limit of read() exceeded\n");
                close(fd);
                sleep(PAUSE);
                exit(1);
DONE:
                *p = '\0';
                printf("\nrmesg: %s\n", rmesg);
                close(fd);
                sleep(PAUSE);
        }
}
-----
kkdlabs.jp, featuring Koh-ichi Ito as just another DNS freak in town.

メールによる返信