UWPでシリアル通信(QRコードリーダー)

CSharpTitleC#

現在QRコードを使った出荷確認アプリを開発しているのだが、どうにもUSB接続タイプのバーコードリーダーの読み取り速度が気に食わない。ある程度の文字数になるとどうしてもHIDモードのバーコードリーダーでは、入力に時間がかかってしまうので、もともと内蔵されているCOMモードでの接続にトライ。高速化が狙い。

スポンサーリンク

先に結果

UWPでのシリアル接続は、なんか微妙な感じがする。使い方が正しいかはよくわかってないけど。
ちなみにバーコードリーダーの読み取り速度は、爆速化する。入力ウェイトは体感できないくらい早くなる。初めからシリアル接続を採用するべきだった。

今回のアプリに使用したバーコードリーダー

無線タイプはCOM接続対応していないのかあまり見かけない。あってもUSB接続時のみみたいなのもあるので注意が必要。
初期状態はHIDモードになっているので付属の説明書の設定からCOMモードに切り替える。

シリアル接続

だいぶ前にWinFormsではシリアル接続を使ったことがあったがUWPになってからは初めて。

マニフェストの編集

よくある機能ならマニフェストの機能タブから追加できるのだがシリアルデバイスは無いようなので直接編集が必要になる。(マニフェスト開いて[F7])

<Capabilities>に下記を追加

<DeviceCapability Name="serialcommunication">
  <Device Id="any">
    <Function Type="name:serialPort"/>
  </Device>
</DeviceCapability>

コード作成

using に下記を追加する

using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;

ざっくりとコード全体。多分コピペでも動くはず。

public sealed partial class MainPage : Page
{
        SerialDevice QRCodeReader;
        DataReader dr;

        public MainPage()
        {
            this.InitializeComponent();
            SerialOpen();
        }

        string ReadBuffer = "";
        private async void ReadStanby()
        {
            try
            {
                //1文字ずつ読み取る
                uint bytesRead = await dr.LoadAsync(1);
                var str = dr.ReadString(bytesRead);
                //CRLFの処理はデバイスに依存する
                switch (str)
                {
                    //LFは無視
                    case "\n":
                        break;
                    //CRで完了
                    case "\r":
                        //読込完了の処理

                        //読取内容をリセット
                        ReadBuffer = string.Empty;
                        break;
                        //それ以外なら読取文字列に追加する
                    default:
                        ReadBuffer += str;
                        break;
                }
                //読取待機に戻る
                ReadStanby();
            }
            catch (Exception ex)
            {
                //接続切れなどの処理一応安全のために破棄しておく
                Console.Write(ex.Message);
                QRCodeReader.Dispose();
                dr.Dispose();
            }
        }

        private async void SerialOpen()
        {
            //接続されているシリアルデバイスのコレクションを取得
            DeviceInformationCollection serialDeviceInfos = await DeviceInformation.FindAllAsync(SerialDevice.GetDeviceSelector());

            foreach (DeviceInformation serialDeviceInfo in serialDeviceInfos)
            {
                try
                {
                    //シリアルデバイスなら接続処理開始
                    QRCodeReader = await SerialDevice.FromIdAsync(serialDeviceInfo.Id);
                    if (QRCodeReader != null)
                    {
                        dr = new DataReader(QRCodeReader.InputStream);
                        //読取待機
                        ReadStanby();
                        return;
                    }
                }
                catch (Exception)
                {
                    // Couldn't instantiate the device
                }

            }
        }

    }

参考サイト

SerialDevice Class (Windows.Devices.SerialCommunication) - Windows UWP applications
Represents a serial port. The object provides methods and properties that an app can use to find and interact with serials ports on the system.

これで接続さえできれば、いつでも受信可能状態。
読込完了の処理は受信文字のキャリッジリターンCRを受信して完了にしている。ラインフィードLFはスルーwこの辺の処理は相手のデバイスの通信方式次第なので臨機応変に対応する。

まとめ

もっとローレベルな制御方法かと思っていたのだが、全然違っていた。
SerialDeviceのプロパティで通信速度などの細かいところも設定できるのだが、今回の環境下では必要ないようでそのままのコード(初期値?)で動作した。場合によってはボーレートなどの設定は必要だと思う。
Formsに合ったようなイベントで受信かと思っていたので少々はまった。いまだに受信部分のコードが気に食わないがwなんで事前に受信する文字数を指定するのかいまいち理解できなかった。
ちょっと無理やりかもしれないが1文字ずつの処理でも問題なく動作してるので良しとする。
ただ、接続後の安定性はWinFormsよりイイような気もする。

今回の要件では入力しか使わなかったので出力に関しては不明。DataWriterでどうにかするらしい。

ちなみに出荷確認アプリは、イイ感じに動作している。かなり作業効率が上がったようで安心。

コメント

タイトルとURLをコピーしました