13,000
回編集
(→受信) |
(→受信) |
||
306行目: | 306行目: | ||
Console.WriteLine($"受信中にエラーが発生: {ex.Message}"); | Console.WriteLine($"受信中にエラーが発生: {ex.Message}"); | ||
} | } | ||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
== その他のシリアル通信の機能 == | |||
以下の例では、バッファリング、再接続機能、イベントベースの受信を行っている。<br> | |||
これにより、大量のデータを扱う場合や不安定な接続環境での使用に適している。<br> | |||
<br> | |||
* バッファリング | |||
*: ConcurrentQueue<byte[]>を使用して、受信データをバッファリングする。 | |||
*: また、バッファの最大サイズを制限して、オーバーフローを防ぐ。 | |||
* 再接続機能 | |||
*: 接続が失敗した場合に複数回試行する。 | |||
*: また、接続状態を監視して、切断された場合に再接続を試みる。 | |||
* イベントベースの受信 | |||
*: SerialPort_DataReceivedイベントハンドラを使用して、データ受信時の処理を行う。 | |||
* 非同期処理 | |||
*: バッファリングされたデータを非同期に処理する。 | |||
<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 AdvancedAsyncReceiver | |||
{ | |||
private static SerialPort _serialPort; | |||
private static ConcurrentQueue<byte[]> _dataBuffer = new ConcurrentQueue<byte[]>(); | |||
private static int _maxBufferSize = 10; // 受信バッファの最大サイズ | |||
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; // 書き込みタイムアウトの設定 (ミリ秒) | |||
_serialPort.DataReceived += SerialPort_DataReceived; // イベントハンドラの登録 | |||
await ConnectWithRetry(); | |||
Console.WriteLine("シリアルポートをオープン"); | |||
Console.WriteLine("終了するには [Ctrl] + [C]キーを押下"); | |||
using (var cts = new CancellationTokenSource()) | |||
{ | |||
Console.CancelKeyPress += (s, e) => | |||
{ | |||
e.Cancel = true; | |||
cts.Cancel(); | |||
}; | |||
await Task.WhenAll( | |||
ProcessBufferedDataAsync(cts.Token), | |||
MonitorConnectionAsync(cts.Token) | |||
); | |||
} | |||
} | |||
catch (OperationCanceledException) | |||
{ | |||
Console.WriteLine("エラー: 受信が中断"); | |||
} | |||
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 void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) | |||
{ | |||
int bytesToRead = _serialPort.BytesToRead; | |||
byte[] buffer = new byte[bytesToRead]; | |||
_serialPort.Read(buffer, 0, bytesToRead); | |||
if (_dataBuffer.Count < _maxBufferSize) | |||
{ | |||
_dataBuffer.Enqueue(buffer); | |||
} | |||
else | |||
{ | |||
Console.WriteLine("警告: バッファオーバーフロー"); | |||
Console.WriteLine("データが破棄されました"); | |||
} | |||
} | |||
private static async Task ProcessBufferedDataAsync(CancellationToken cancellationToken) | |||
{ | |||
while (!cancellationToken.IsCancellationRequested) | |||
{ | |||
if (_dataBuffer.TryDequeue(out byte[] data)) | |||
{ | |||
string receivedData = Encoding.UTF8.GetString(data); | |||
Console.WriteLine($"受信したデータ: {receivedData.Trim()}"); | |||
} | |||
else | |||
{ | |||
await Task.Delay(100, cancellationToken); // バッファが空の場合は、100[mS]待機 | |||
} | |||
} | |||
} | |||
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[秒]ごとに接続状態を確認 | |||
} | } | ||
} | } |