質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

2回答

2808閲覧

C# シリアル通信で受信したデータを上位クラスに渡したい

Caffellattep

総合スコア12

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

1クリップ

投稿2018/06/25 08:13

編集2018/06/27 03:10

visualStudio2017 でシリアル通信で相手ポートに送信したデータの内容に依って、対応した受信データを受け取る処理を作っています。
(実際はRS232Cで複数接続したセンサに命令を送って返答を非同期で受け取るシステムのです。)
例えば10台センサがあるとして、10回命令を送信します。(測定値を送るというコマンドなど)
すると、10台分の結果を随時受け取り、変数にセットする仕組みです。
センサ側はCOMポートで接続しています。

受信はSerialPortのDataReceivedイベントを使っており、データを受け取る所は確認したのですが、この情報を
上位クラスが持っている変数にセットしたいのです。
送信データを10台文loopしているメソッドで受信データを受け取り、変数に値をセットするというのは可能なのでしょうか。

C#

1PressSerial.cs 2 3 // グループNo 4 public int GroupNo { private set; get; } 5 private Serial mSerial; 6 delegate void DisplayTextDelegate(); 7 8 public PressSerial(int group) 9 { 10 GroupNo = group; 11 12 mSerial = new Serial(SerialEventHandler); 13 14 } 15 16 /// シリアル通信クラス コンストラクタ 17 public PressSerial() 18 { 19 20 mSerial = new Serial(SerialEventHandler); 21 22 } 23 24 public async Task Hell_Async(int gno, int ch_su,List<PressSensInfo> psenList) 25 { 26 //psenListに10台文の情報が入っている 27 var timeout = TimeSpan.FromMilliseconds(1000); 28 for (int i = 0; i < ch_su; i++) 29 { 30 var rc = await Task.WhenAny( 31 Task.Run(async () => 32 {  33             // 送信コマンドの編集を行って送信 34 CreateSendCommand(psens.Channel);  35 })); 36 37 try 38 { 39 rc.Wait(timeout); 40 sensInfo.Add(new PressSerial(gno, i)); 41 } catch 42 { 43 44 } 45 } 46 } 47 public void CreateSendCommand(int ch) 48 { 49 50 byte[] Packet; 51…ここで送信データ文字列をbyte型に変換処理などを行っている 52 mSerial.SendBuff(Packet); 53 } 54 55 void SerialEventHandler(Serial.SerialEventArgs e) 56 { 57 switch (e.Event) 58 { 59 case Serial.SerialEventArgs.SERIALEVENT.SERIALEVENT_CONNECT: 60 break; 61 case Serial.SerialEventArgs.SERIALEVENT.SERIALEVENT_RECEIVE: 62 /// <summary> 63 /// 受信コマンド 64 /// </summary> 65 void CommandReceive() 66 { 67 68 string text = System.Text.Encoding.ASCII.GetString(e.ReceiveBody); 69 tmpReceivedByte = e.ReceiveBody; // ここに受信データ 70 71 72 } 73 DisplayTextDelegate d = new DisplayTextDelegate(CommandReceive); 74 d?.Invoke(); 75 76 break; 77 } 78 } 79

C#

1Serial.cs 2 public event SerialEventHandler SerialEvent;// Serialデリゲート 3 public delegate void SerialEventHandler(SerialEventArgs e);// イベントハンドラのデリゲート 4 5 public void SendBuff(byte[]sendBuffer) 6 { 7 byte[] rbuf = new byte[1]; 8 if (m_Serial.IsOpen == true) 9 { 10         // 1バイトずつ送信 11 for (int c = 0; c < sendBuffer.Length; c++) 12 { 13 rbuf[0] = sendBuffer[c]; 14 m_Serial.Write(rbuf, 0, rbuf.Length); 15 } 16 } 17 } 18 19 private void Serial_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) 20 { 21 byte tbyte = 0; 22 // 受信バッファから値を取得する 23 tbyte = (byte)m_Serial.BytesToRead; 24 25 byte[] rbuf = new byte[tbyte]; 26 27 m_Serial.Read(rbuf, 0, tbyte); 28 29 //受信イベント 30 ReceiveEvent(SerialEventArgs.SERIALEVENT.SERIALEVENT_RECEIVE, rbuf); 31 } 32 33 /// 受信デリゲート呼び出し処理 34 private void ReceiveEvent(SerialEventArgs.SERIALEVENT e, byte[] body) 35 { 36 //デリゲート呼び出し 37 SerialEvent?.Invoke(new SerialEventArgs(e, mNoticeId, body)); 38 } 39

C#

1PressureSens.cs(ユーザーがアクセスする最上位クラス) 2 // シリアル通信クラス。要素はグループ数分。 3 private List<PressSerial> PressSerialList; 4 // センサ情報リスト 5 public List<PressSensInfo> PSensInfoList { private set; get; } 6 7 // コンストラクタ 8 public PressureSens() 9 { 10 PressSerialList = new List<PressSerial>(); 11 PSensInfoList = new List<PressSensInfo>(); 12 for (int i = 0; i < 3) // グループNo(接続したCOMポート数)が3台とする 13 { 14 PressSerialList.Add(new PressSerial(i); 15 } 16 } 17 18 // センサ情報、接続台数チェックなど。 19 public async Task<Boolean> Initialize() 20 { 21 Boolean ret = true; 22 23 // センサ応答チェック呼び出し 24 await Task.Run(async () => 25 { 26 // 実際はグループ毎に非同期で計測する。 27 28 int gno = 3; // グループNo(接続したCOMポート数) 29 int ch_su = 10; // 接続台数 30 for (int i = 0; i < gno; i++) 31 { 32 var rc = mPressSerial.Hell_Async(i, ch_su, PSensInfoList); 33 } 34 } 35 }); 36 return true; 37 } 38

C#

1 PressSensInfo.cs(センサデータ格納クラス) 2 /// 現在時刻(アラームやセンサ値など状態更新時の時刻) 3 public DateTime Time; 4 /// グループNo 5 public int GroupNo { private set; get; } 6 /// センサチャンネル 7 public int{ private set; get; } 8 /// グローバルID 9 /// </summary> 10 public int GlobalID { private set; get; } 11 /// センサ計測値 12 public Double Value = 0.0; 13 /// <summary> 14 /// センサ状態 15 /// </summary> 16 public int Status { private set; get; } = 0; // 0:待機 1:計測中 2:データエラー 3: …など 17 18 // センサデータクラスのコンストラクタ 19 public PressSensInfo (int group, int ch) 20 { 21 Status = 0; 22 Time = DateTime.Now; 23 GroupNo = group; 24 Channel = ch; 25 GlobalID = group * 100 + ch; 26 } 27

PressSerialクラスのHell_Asyncメソッド内でList配列のセンサ情報をloopでID情報などを送信して、センサ側からの応答を[受け取り、同じ配列データの変数に受信内容をセットするようにしたいのですが、DataReceivedイベントから、デリゲード呼び出しでPressSerialクラスのSerialEventHandler内で受信データを拾うことはできたのですが、この値をどうやってList<PressSensInfo>内にセットすれば良いか、
SerialEventHandlerから上位のメソッドにコールバックする方法が分かりません。

上に[書いたメソッドは直接関係ないところは省略しています。
どうか、宜しくお願いいします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

●全体的な構造に関して
考え方として、Serial_DataReceivedを使わない方法が良いと思いました。

 例えば下記のような方法になります。
https://tomosoft.jp/design/?p=11200

 PressSerial.csのHell_Async内の下記が完了すると、COMポートへの送信完了になるため、

var rc = await Task.WhenAny( Task.Run(async () => {               // 送信コマンドの編集を行って送信 CreateSendCommand(psens.Channel);  }));

 その次に部分(tryの部分)に、下記サイトのbtnconnect_Clickのawait Task.Run(() => readserial());に相当する部分を追加変更すればよいのではないでしょうか?
https://tomosoft.jp/design/?p=11200

●PressSerial.csのSerialのインスタンスについて
現在、インスタンスはmSerialの1つしか存在しないように見えました。
10個シリアルポートが存在し、並列に個別に送信・受信するのであるならば
10個のインスタンスが必要なはずですが、どうなっているんだろうと疑問に思いました。

投稿2018/06/26 08:42

kikukiku

総合スコア514

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Caffellattep

2018/06/27 03:00

ご回答ありがとうございます。返答が遅れてしまい申し訳ありません。 上記の方法で、PressSerial.Hell_Async内で受信することが出来ました。ありがとうございます。 > ●PressSerial.csのSerialのインスタンスについて > 現在、インスタンスはmSerialの1つしか存在しないように見えました。 > 10個シリアルポートが存在し、並列に個別に送信・受信するのであるならば > 10個のインスタンスが必要なはずですが、どうなっているんだろうと疑問に思いました。 ご指摘ありがとうございます。実はPressureSens.csのコンストラクタでシリアルポート数分インスタンスを生成しています(省略していました)
guest

0

いろいろ方法がありますが、上位クラスでList<PressSensInfo>のプロパティを作り、下位クラスから値を設定していけばいいのでは。
で、どうやって設定するのか、というのはPressSensInfoクラスが示されてないために詳しいことは言えませんが、

list.Add(new PressSensInfo(受信結果));

という形になると思われます

投稿2018/06/25 14:29

y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Caffellattep

2018/06/25 21:00

ご回答ありがとうございます。情報が足りなかった為、ユーザがアクセスする最上位クラス(PresserSenseクラス)とセンサ情報を格納用のPressSensInfo.csを追加しました。 実際は、複数のCOMポートにそれぞれ複数のセンサがぶら下がっている状態です。 ユーザがPresserSenseのHell_Asyncメソッドを呼び出して、センサに接続されているか、測定値を求めたりなど色々と命令を送信します。センサからの応答を非同期で受け取るという流れです。 非同期処理やら、通信処理がごちゃごちゃになってどうやって複数のセンサの応答を受け取り(又は、応答が無い時はタイムアウトエラー)センサ情報格納リストにセットしていけばよいかわかりません。 現状の作りでは、PressSerialのSerialEventHandlerで受信データを受け取り処理を行っていますが、本当はHell_Asyncで受け取りたいです。sensInfo.Add(new PressSensInfo(グループno, チャンネル));の形で設定するので、受信データがどのグループNoでチャンネルのを聞いたのかが分からくなるので。 分かりにくい説明ですみません。
y_waiwai

2018/06/25 22:34

グループNoとチャンネルとコマンド種別、受信結果で構成されるクラスを作って、そのリストを親クラスのプロパティとして設定し、下位クラスから追加していく、でいいかと思いますが、なにか問題はあるでしょうか
Caffellattep

2018/06/26 00:03

>下位クラスから追加していく すみません。この場合の下位クラスとはどこになるのでしょうか。今はPressSerialクラスのHell_Asyncメソッドで追加しようとしています。
y_waiwai

2018/06/26 00:20

PressSerial.cs のクラスにPressureSens.cs のインスタンスを持たせるようにしとけば、そこからPSensInfoListにアクセスできるでしょ
Caffellattep

2018/06/26 06:22 編集

重ね重ねすみません。 >PressSerial.cs のクラスにPressureSens.cs のインスタンスを持たせる PressSerial.cs のクラス内でPressureSens.cs のインスタンスを渡してみました。 PressSens = new PressureSens();  データ受信のコールバックで PrSens.PSensInfoList.Add(new PressSensInfo(グループno, チャンネル)); をすると、データが追加されました。このやり方で良かったのでしょうか。 只、グループNoが判断できない為また試行錯誤中です
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問