DOBON.NET DOBON.NETプログラミング掲示板過去ログ

シリアル通信で連続で読みたくない時の処理について

環境/言語:[Windows 7/Vista VS2010 C# Winアプリ]
分類:[.NET]

お世話になります。

シリアル通信でデータを読むさい、DataReceivedを使用しないで読み込むことを考えています。

理由は、後述。そこでタイマー呼び出しで下記を実行しClearCommErrorでバイト数を数えて読み込みをしたいのですが、機器から送って何バイトからデータがあるのに0を返します。
下記のどこが悪いのか指摘していただけと助かります。よろしくお願いします。

xxxxx.cs
Microsoft.Win32.SafeHandles.SafeFileHandle hFile = MySerialClass.CreateFile(/*@"\\.\" +*/ SerialCounter1.sPortName, dwAccess, 0, IntPtr.Zero, 3, dwFlagsAndAttributes, IntPtr.Zero);

MySerialClass.Comstat comStat = new MySerialClass.Comstat();
int commErrors = 0;

MySerialClass.ClearCommError(hFile, ref commErrors, ref comStat);
if (comStat.cbInQue > 0)
{
Counter1_DataReceived();
return;
}


MySerialClass.cs
public partial class MySerialClass : Component
{
:
:

#region Nested type: COMSTAT

[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct Comstat
{
public readonly uint Flags;
public readonly uint cbInQue;
public readonly uint cbOutQue;
}

#endregion

[System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
public static extern bool ClearCommError(Microsoft.Win32.SafeHandles.SafeFileHandle hFile, ref int lpErrors, ref Comstat lpStat);
[System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
public static extern Microsoft.Win32.SafeHandles.SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
IntPtr securityAttrs, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);


標準のDataReceivedを使いたくない理由:
検査機器(病院などで検査するもの)から出力されるデータを1件単位で正しいかどうか判断してそのデータをを保存処理したりするので、後述のデータが溜まります。
その際、このハンドラは、データが来ると次々何のためらいもなくデータを処理します。
現在の流れでは、来たデータがそのまま更新されるので、処理者が知らないうちに上書きしてしまいます。
そこで、苦肉の策としてタイマー処理で・・・となったわけです。
何かいい方法があれば、教えていただけると助かります。
2013/08/08(Thu) 02:40:05 編集(投稿者)

機器の仕様が解らない為、正確な方法を提示することができませんが
APIを使ったりタイマーを使わなくても、SerialPortクラスで十分に
受信機能を作れますヨ!

非同期受信ルーチンで、バッファにどんどん読み込ませて、別スレッド
で、バッファに読み込まれた情報から必要な部分のみを抜き出して処理
を行うとか・・・

懸念されているDataReceivedですべて処理をする必要は無いのです。

通信で受信されるデータ(テキスト?バイナリ?)で、デリミタがある
ならば、ReadToを使ってデリミタまでのデータを一括で読み込めますの
で、読み込んだのちにそれをどうするのか判断してやればよい。

以上。参考まで
オショウさん、お世話になります。

> 非同期受信ルーチンで、バッファにどんどん読み込ませて、別スレッド
> で、バッファに読み込まれた情報から必要な部分のみを抜き出して処理
> を行うとか・・・
バッファにためて別スレッドで・・・・って実際どのような形になるのでしょうか?
出力する機器は、2種類あって1つのフォーマットは、131バイト、他は、2つのレコードを順次出力191+255バイトいずれも下記のようにデリミタ相当の文字があります。後者の機器のデータ1、2も識別の文字(先頭から3、4バイト目)が含まれているので区別できます。
 バッファにどんどん溜めるとか、溜まったデータを自動表示させたいのですが、可能になりますか?できればDataReceivedを使用しないサンプルなどご存知ではないでしょうか?


> 通信で受信されるデータ(テキスト?バイナリ?)で、デリミタがある
> ならば、ReadToを使ってデリミタまでのデータを一括で読み込めますの
送られてくる文字列は、テキストで先頭がSTX(02h)終わりがETX(03h)になっています。

よろしくお願いします。
> 送られてくる文字列は、テキストで先頭がSTX(02h)終わりがETX(03h)になっています。

  SerialPortクラスを使って・・・

  後先になりますが・・・
  sz = devSerial.ReadTo(ETX)

  としてやれば、ETXを受信した時点で、受信したデータが文字列として
  sz に代入されます。

  2台あるとのことですが・・・
  RS-232C は、1対1の通信しかできませんので、シリアルポートが2個
  必要で、各々接続した機器と通信することになります。ので、4バイト
  目が何であるかを見分ける必要は無いでしょう。ポートをオープンする
  時点ですでに固定化していますので。

> バッファにためて別スレッドで・・・・って実際どのような形になるのでしょうか?

  そんな難しいのとでしょうか・・・
  たとえば、ArrayList でため込む変数を各々の機器用に用意して、受信
  した際に.Addしていけばよい話。

  別スレッドにするのか否かはプログラムの構造をどうするのか・・・
  バッファを用意しなくても、処理が行えないくらい、頻繁に受信イベント
  が発生するなら、バッファを用意してもそのうち処理が追いつかなくなっ
  て破たんしてしまうかと。

  ETXまでのデータを受信する間隔が、秒以上空いていれば、OnReceive で
  そのまま処理しても問題ないかと。

  別スレッドで受信と処理を分離するならば、排他制御は必要でしょう。


Private Const ETX As String = Chr(&H3)
Private al As ArrayList

Private Sub devSerial_DataReceived(sender As Object, e As System.IO.Ports.SerialDataReceivedEventArgs) Handles devSerial.DataReceived

Dim dev As SerialPort
Dim sz As String

dev = DirectCast(sender, SerialPort)

If e.EventType = SerialData.Chars Then
sz = dev.ReadTo(ETX)
If sz <> String.Empty Then
System.Threading.Monitor.Enter(al)
al.Add(sz)
System.Threading.Monitor.Exit(al)
End If
End If

End Sub

以上。参考まで
オショウさん、ご丁寧にありがとうございます。


> System.Threading.Monitor.Enter(al)
> al.Add(sz)
> System.Threading.Monitor.Exit(al)
スレッドになれていないので、わかりにくい文ですが、これを参考にさせていただき取り込まれたデータを取得するテストをしてみたいと思います。

今、手元に機器がないので、また質問させてください。よろしくお願いします。

DOBON.NET | プログラミング道 | プログラミング掲示板