Armadilloフォーラム

バーコードリーダーの読み込みイベント

ry-hr

2018年5月15日 14時24分

お世話になっております。ry-hrです。

バーコードリーダーでの入力について質問があります。

Armadillo-440で動かしているアプリにて、
バーコードリーダーで読み込んだ値を取得しています。

---------------------------
#define DEVICE "/dev/tty0"

int fd= open(DEVICE,O_RDONLY);

if(FD_ISSET(fd, &fds))
{
 //読み込み処理
}
----------------------------

省略をしていますが、上記のようなロジックで実装していて、
バーコードリーダーで読み込み時に「読み込み処理」に入るのはいいのですが、
スイッチ(sw0)を押した場合にも処理に入ってしまいます。

何か原因や対策がわかる方いらっしゃいますでしょうか。
お手数おかけいたしますが、宜しくお願いいたします。

補足ですが、同じArmadillo上でスイッチのイベント(/dev/input/event0)を監視している別アプリケーションも動かしております。
こちらにはなるべく影響を与えないようにしたいと思っております。

コメント

中村です。

> if(FD_ISSET(fd, &fds))
> {
>  //読み込み処理
> }

のところで、FD_ISSET()のあとでselect()やってますか?
次のような感じです。

    FD_ISSET(fd, &fds);
    int r = select(fd + 1, &fds, NULL, NULL, NULL);
    if (r < 0) {
        // エラー処理
    } else if (r == 0) {
        // タイムアウト
        // -- select()の第5引数でタイムアウトを指定したとき
    } else {
        // ここでread()する
    }

--
なかむら

いつもご回答ありがとうございます。

selectは行っていたのですが、
詳細には、シリアルからのINPUTとバーコードからのINPUTを確認していたため、
少しことなるロジックにしておりました。
(selectの後に、シリアルとバーコードそれぞれのFD_ISSETを行う)

念のためバーコードからのINPUTのみを監視するように修正し、
提示していただいたよう変更しましたが、やはりスイッチ(sw0)を押したときにも反応してしまいます。

スイッチを押したときも「/dev/tty0」が立ってしまっているのでしょうか。

宜しくお願いいたします。

中村です。

すみません。大きな間違いを書いてました。
FD_ISSET()とFD_SET()の読み間違いです。

ry-hrさんの最初のコードを読み間違えて、さらに、
それに気づかずコピペという、情けない投稿になってました。
申し訳けありません。
(書いた後すぐに外出してしまい、訂正が遅れたこともお詫びします)

言い訳をさせていただくと。。。

>>    int fd= open(DEVICE,O_RDONLY);
>>    
>>    if(FD_ISSET(fd, &fds))
>>    {
>>     //読み込み処理
>>    }

と、open()の直後がFD_ISSET()になっていたためです。

修正したものを書いておきます。

     int fd= open(DEVICE,O_RDONLY);
 
     FD_SET(fd, &fds);
 
     int r = select(fd + 1, &fds, NULL, NULL, NULL);
     if (r < 0) {
         // エラー処理
     } else if (r == 0) {
         // タイムアウト
         // -- select()の第5引数でタイムアウトを指定したとき
     } else {
        // FD_SET()でfdしかセットしていないので、
        // FD_ISSET()は常に真になるはずだが...
        if (FD_ISSET(fd, &fds)) {
             // ここでread()する
        }
     }

こうなっていれば、open()したfdのデバイス("/dev/tty0")からの
入力だけになると思います。

>> 提示していただいたよう変更しましたが、やはりスイッチ(sw0)を押したときにも反応してしまいます。

「反応してしまう」というのは、スイッチを押しただけで
select()から戻ってきて、FD_ISSET()が真になってしまう、
ということでしょうか?

--
なかむら

中村です。

先ほどのサンプルコードに間違いがありました。
大事な処理が抜けてました。
FD_SET()の前のFD_ZERO()です。
FD_ZERO()しないとゴミを拾う可能性があります。
もしかしたらこれが原因ではないでしょうか?

もう一度、全体を書いておきます。

    int fd = open(DEVICE,O_RDONLY);
 
    FD_ZERO(&fds);
    FD_SET(fd, &fds);
 
    int r = select(fd + 1, &fds, NULL, NULL, NULL);
    if (r < 0) {
        // エラー処理
    } else if (r == 0) {
        // タイムアウト
        // -- select()の第5引数でタイムアウトを指定したとき
    } else {
       // FD_SET()でfdしかセットしていないので、
       // FD_ISSET()は常に真になるはずだが念のためチェック
       if (FD_ISSET(fd, &fds)) {
            // ここでread()する
       }
    }

--
なかむら

お返事ありがとうございます。

ご提示していただいたとおりに実装しても、スイッチを押すと
select()から戻ってきて、FD_ISSET()が真になってしまいます。

意識的に設定を変更等はしてはいないのですが、
こちらは設定変更等で影響するようなことでしょうか?

また、ご回答を読んで、「FD_SET」あたりの動作を理解できたので、
解決策がない場合は以下のロジックにしたいと思いますが、なにか問題点はありそうでしょうか。

#define DEVICE "/dev/tty0"
#define SW_DEVICE "/dev/input/event0"    //スイッチのイベント
 
 
 int fd = open(DEVICE,O_RDONLY);
 int sw_fd = open(SW_DEVICE, O_RDONLY | O_NONBLOCK);
 
    FD_ZERO(&fds);
    FD_SET(fd, &fds);
    int maxfd=fd;
    FD_SET(sw_fd, &fds);
    if (sw_fd > maxfd)
    {
        maxfd=sw_fd;
    }
 
    int r = select(maxfd + 1, &fds, NULL, NULL, NULL);
    if (r < 0) {
        // エラー処理
    } else if (r == 0) {
        // タイムアウト
    } else {
       if (FD_ISSET(fd, &fds)) {
           if (FD_ISSET(sw_fd, &fds)==0) { //スイッチのイベントが発生していない時
            // ここでread()する
           }
       }
    }

OPENの方法は何が最適かは説明を読みながら後程考えたいと思います。

お手数おかけいたしますが、宜しくお願いいたします。

中村です。

> ご提示していただいたとおりに実装しても、スイッチを押すと
> select()から戻ってきて、FD_ISSET()が真になってしまいます。
>
> 意識的に設定を変更等はしてはいないのですが、
> こちらは設定変更等で影響するようなことでしょうか?

再現できる最小限のコードにして、
実際のソースコードを開示していただけますか?
こちらでも試してみたいと思います。
何度も中途半端な返答をして(間違いもあったり)、
ご迷惑をおかけしてますし。。。

> また、ご回答を読んで、「FD_SET」あたりの動作を理解できたので、
> 解決策がない場合は以下のロジックにしたいと思いますが、なにか問題点はありそうでしょうか。
>
> #define DEVICE "/dev/tty0"
> #define SW_DEVICE "/dev/input/event0" //スイッチのイベント
>
> int fd = open(DEVICE,O_RDONLY);
> int sw_fd = open(SW_DEVICE, O_RDONLY | O_NONBLOCK);

現状コードで何が原因で不具合が発生しているのかを調べたあと、
こちらを使うかどうか判断したのでもいいと思います。

ちなみに、Armadillo-440で"/dev/tty0"とのことですが、
これはどのインターフェースでしょうか?
すみません、いま出先で資料が手元に何もなく、
400シリーズのシリアルは長いこといじってないもので、
デバイスとtty名の関連を忘れてしまってます。

--
なかむら

中村です。

たびたび、すみません。

> ちなみに、Armadillo-440で"/dev/tty0"とのことですが、
> これはどのインターフェースでしょうか?

もう1つ、
>>> スイッチ(sw0)を押した場合にも処理に入ってしまいます。
と、これまで投稿で書かれていましたが、
これは本体のタクトスイッチ(440のマニュアルでは"SW1")でなく、
別のものでしょうか?

tty0とあわせて"sw0"の説明もお願いします。

--
なかむら

お忙しい中、ご回答ありがとうございます。

下記コードで実装しても同様の現象となります。

#include <stdio.h>
#include <fcntl.h>
 
#define DEVICE "/dev/tty0"
 
int main(int argc, char* argv[])
{
    int fd= open(DEVICE,O_RDONLY);
    if (fd==-1)
    {
        return -1;
    }
 
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(fd ,&fds);
    if(select(fd +1, &fds, NULL, NULL, NULL) < 0)
    {
        return -1;
    }
    else
    {
        if(FD_ISSET(fd, &fds))
        {
            printf("INPUT\r\n");
        }
    }
    close(keyin_fd);
    return 0;
}

> Armadillo-440で"/dev/tty0"とのことですが、
> これはどのインターフェースでしょうか?
これはどのような回答例がありますでしょうか。
まだ理解が浅く、回答の仕方がわからない状況です。

あと、「"/dev/tty0"」で取得している理由ですが、
USBのバーコードリーダーで読み込んだ値をどこから取得するかがわからず、
試しにtty0をオープンして値を取得したら拾えたという状況です。

そのため、「"/dev/tty0"」からの取得が良くないのかもしれません。

> これは本体のタクトスイッチ(440のマニュアルでは"SW1")でなく、
失礼いたしました。そのスイッチです。「sw1」でした。

情報出しが遅れてしまい申し訳ありませんが、
宜しくお願いいたします。

中村です。

> 下記コードで実装しても同様の現象となります。

ありがとうございます。
今すぐに・・・というわけにはいかず、
何か試せるのは今日の夜以降になってしまいます。
ご了承ください。

> あと、「"/dev/tty0"」で取得している理由ですが、
> USBのバーコードリーダーで読み込んだ値をどこから取得するかがわからず、
> 試しにtty0をオープンして値を取得したら拾えたという状況です。

USB接続ですね。
/dev/ttyUSB0のようなものはありませんか?
Armadillo-440のUSBポートにそのバーコードリーダーを接続したとき、
コンソールにどのようなメッセージが出ますか?
バーコードリーダーのUSBの素性(型番やVID/PID)などが
わかるといいのですが・・・

> そのため、「"/dev/tty0"」からの取得が良くないのかもしれません。

その可能性がありそうです。

> > これは本体のタクトスイッチ(440のマニュアルでは"SW1")でなく、
> 失礼いたしました。そのスイッチです。「sw1」でした。

了解しました。

> 情報出しが遅れてしまい申し訳ありませんが、

もう1つ、
カーネルは3.14でしょうか?
それとも古い2.6.26でしょうか?

--
なかむら

質問者のry-hrです

> 何か試せるのは今日の夜以降になってしまいます。
いつもありがとうございます。
急ぎではありませんので、お手すきの際に可能でしたら、宜しくお願いいたします。

>/dev/ttyUSB0のようなものはありませんか?
こちらはありませんでした。

バーコードリーダーを接続したときのメッセージは

usb 1-1: new low speed USB device using fsl-ehci and address 2
usb 1-1: configuration #1 chosen from 1 choice
input: CANMAX Installed Successfully as /devices/platform/fsl-ehci.0/usb1/1-1/1-1:1.0/input/input2
input: USB HID v1.10 Keyboard [CANMAX Installed Successfully] on usb-fsl-ehci.0-1

となります。

cat /proc/bus/usb/devices

T:  Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0
D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=0d6c ProdID=0200 Rev= 2.50
S:  Manufacturer=CANMAX
S:  Product=Installed Successfully
C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=01 Driver=usbhid
E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=10ms

現在試しているバーコードリーダーの情報は上記になります。

また、カーネルは「2.6.26」になります。

宜しくお願いいたします。

中村です。

> バーコードリーダーを接続したときのメッセージは
>

> usb 1-1: new low speed USB device using fsl-ehci and address 2
> usb 1-1: configuration #1 chosen from 1 choice
> input: CANMAX Installed Successfully as /devices/platform/fsl-ehci.0/usb1/1-1/1-1:1.0/input/input2
> input: USB HID v1.10 Keyboard [CANMAX Installed Successfully] on usb-fsl-ehci.0-1
> 

これ、USBキーボードとして認識されてませんか?
/dev/input/event1とか/dev/input/event2とか。

USBキーボードになっていると、起動時から接続されていた場合には
SW1の/dev/input/event0の番号が変わってしまっているかもしれません。
https://manual.atmark-techno.com/armadillo-4x0/armadillo-400_series_sof…

evtest /dev/input/event0
evtest /dev/input/event1
evtest /dev/input/event2
などやると、どうなりますか?

> また、カーネルは「2.6.26」になります。

カーネル3.14での解説になりますが、
この記事なども参考に。
https://users.atmark-techno.com/blog/615/2884

--
なかむら

お返事ありがとうございます。

/dev/input/event2
として認識されていました。
(起動時に接続していると「event1」)

ご提示いただいた参考のURLのサンプルソースのようにして読み込みを行えました。
sw1 の event0 には影響がないため、
あとはバーコードリーダー接続時(event1 or event2)のルールで対応できそうです。

ありがとうございました。

中村です。

> /dev/input/event2
> として認識されていました。

最初の質問を読んだときに「バーコードリーダーからの入力」という
ご説明からすぐに「USBキーボードに見えるのでは?」と気づいていれば、
もう少し早く解決できていたかもしれないところ、
違った方向へ話をもっていってしまい、申し訳ありませんでした。

遠回りになってしまいましたが、解決できてよかったです。

--
なかむら