13,000
回編集
351行目: | 351行目: | ||
== その他のシリアル通信の機能 == | == その他のシリアル通信の機能 == | ||
==== 送信 ==== | |||
以下の例では、バッファリング、再接続機能を使用して、非同期でデータを送信している。<br> | |||
これにより、大量のデータを扱う場合や不安定な接続環境での使用に適している。<br> | |||
<br> | |||
* バッファリング | |||
*: ConcurrentQueue<string>を使用して、送信データをバッファリングする。 | |||
*: また、バッファの最大サイズを制限して、オーバーフローを防ぐ。 | |||
* 再接続機能 | |||
*: 接続が失敗した場合に複数回試行する。 | |||
*: また、接続状態を監視して、切断された場合に再接続を試みる。 | |||
* 非同期処理 | |||
*: バッファリングされたデータを非同期に送信する。 | |||
<br> | |||
バッファリング機能により、一時的な接続問題や送信の遅延がある場合でもデータ損失のリスクを軽減する。<br> | |||
<br> | |||
<syntaxhighlight lang="c#"> | |||
using System; | |||
using System.Text; | |||
using System.IO.Ports; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
using System.Collections.Concurrent; | |||
class AdvancedAsyncSender | |||
{ | |||
private static SerialPort _serialPort; | |||
private static ConcurrentQueue<string> _sendBuffer = new ConcurrentQueue<string>(); | |||
private static int _maxBufferSize = 100; // 送信バッファの最大サイズ | |||
private static int _reconnectAttempts = 5; // 再接続の試行回数 | |||
private static int _reconnectDelay = 5000; // 再接続の待機時間 (ミリ秒) | |||
static async Task Main(string[] args) | |||
{ | |||
string portName = "/dev/ttyS0"; // ポート名を適切に設定 | |||
int baudRate = 9600; // ボーレート 9600[bps] | |||
Parity parity = Parity.None; // パリティ無し | |||
int dataBits = 8; // データ長は8ビット | |||
StopBits stopBits = StopBits.One; // ストップビットは1ビット | |||
try | |||
{ | |||
_serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits); | |||
_serialPort.Handshake = Handshake.None; // フロー制御の設定 | |||
_serialPort.ReadTimeout = 500; // 読み取りタイムアウトの設定 (ミリ秒) | |||
_serialPort.WriteTimeout = 500; // 書き込みタイムアウトの設定 (ミリ秒) | |||
await ConnectWithRetry(); | |||
Console.WriteLine("シリアルポートをオープン"); | |||
Console.WriteLine("終了するには 'exit' と入力"); | |||
using (var cts = new CancellationTokenSource()) | |||
{ | |||
var sendTask = SendDataAsync(cts.Token); | |||
var monitorTask = MonitorConnectionAsync(cts.Token); | |||
while (true) | |||
{ | |||
Console.Write("送信するメッセージを入力: "); | |||
string message = Console.ReadLine(); | |||
if (message.ToLower() == "exit") | |||
{ | |||
cts.Cancel(); | |||
break; | |||
} | |||
if (_sendBuffer.Count < _maxBufferSize) | |||
{ | |||
_sendBuffer.Enqueue(message); | |||
} | |||
else | |||
{ | |||
Console.WriteLine("警告: 送信バッファのオーバーフローが発生 (データを破棄)"); | |||
} | |||
} | |||
await Task.WhenAll(sendTask, monitorTask); | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
Console.WriteLine($"エラーが発生: {ex.Message}"); | |||
} | |||
finally | |||
{ | |||
_serialPort?.Close(); | |||
} | |||
} | |||
private static async Task ConnectWithRetry() | |||
{ | |||
for (int i = 0; i < _reconnectAttempts; i++) | |||
{ | |||
try | |||
{ | |||
_serialPort.Open(); | |||
return; | |||
} | |||
catch (Exception ex) | |||
{ | |||
Console.WriteLine($"接続試行 {i + 1} 失敗: {ex.Message}"); | |||
if (i < _reconnectAttempts - 1) | |||
{ | |||
await Task.Delay(_reconnectDelay); | |||
} | |||
} | |||
} | |||
throw new Exception("接続に失敗しました。"); | |||
} | |||
private static async Task SendDataAsync(CancellationToken cancellationToken) | |||
{ | |||
while (!cancellationToken.IsCancellationRequested) | |||
{ | |||
if (_sendBuffer.TryDequeue(out string message)) | |||
{ | |||
try | |||
{ | |||
byte[] buffer = Encoding.UTF8.GetBytes(message + Environment.NewLine); | |||
await _serialPort.BaseStream.WriteAsync(buffer, 0, buffer.Length, cancellationToken); | |||
await _serialPort.BaseStream.FlushAsync(cancellationToken); | |||
Console.WriteLine("メッセージが非同期で送信完了"); | |||
} | |||
catch (Exception ex) | |||
{ | |||
Console.WriteLine($"送信中にエラーが発生: {ex.Message}"); | |||
_sendBuffer.Enqueue(message); // 送信失敗したメッセージを再度キューに追加 | |||
} | |||
} | |||
else | |||
{ | |||
await Task.Delay(100, cancellationToken); // バッファが空の場合は100[ミリ秒]待機 | |||
} | |||
} | |||
} | |||
private static async Task MonitorConnectionAsync(CancellationToken cancellationToken) | |||
{ | |||
while (!cancellationToken.IsCancellationRequested) | |||
{ | |||
if (!_serialPort.IsOpen) | |||
{ | |||
Console.WriteLine("接続が切断されたので再接続を試行..."); | |||
await ConnectWithRetry(); | |||
Console.WriteLine("再接続に成功"); | |||
} | |||
await Task.Delay(1000, cancellationToken); // 1秒ごとに接続状態をチェック | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== 受信 ==== | ==== 受信 ==== | ||
以下の例では、バッファリング、再接続機能、イベントベースの受信を行っている。<br> | 以下の例では、バッファリング、再接続機能、イベントベースの受信を行っている。<br> | ||
502行目: | 656行目: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br><br> | <br><br> | ||