92434


ご存じの方、ご教示頂きたくお願いいたします。

現在、C# で `SerialPort` クラスを使用してモデムテスターを開発しています。

`System.IO.Ports.Handshake.RequestToSend` を使用せずに RTS/CTS を手動で制御する方法はありますか?

データ送受信の流れは以下の通りです。

  0. シリアルポートを開きます。
  1. RTS を ON にします。
  2. CTS の ON を待ちます。
  3. CTS が ON になったら、バイトデータを送信します。
  4. データ送信が完了したら RTS を OFF します。
  5. 相手側からのデータ受信を待ちます。
  6. 相手側からのデータを受信します。

上記 1. ～ 6. を繰り返します。

上記の 1. ～ 2. と 4. を実現するため `SerialPort` クラスのプロパティは

  * `SerialPort.RtsEnable` → `true`: RTS ON, `false`: RTS OFF
  * `SerialPort.CtsHolding` → `true`: CTS ON, `false`: CTS OFF

と考えています。

試しに、RTS信号の出力がCTS信号に入力されるようにRS232Cケーブルを配線してみました。  
この RS232C ケーブルを使って以下のコードで検証しましたが、`SerialPort.CtsHolding` が `true`
にならずタイムアウトしてしまいます。

`SerialPort.RtsEnable` を `true` に設定しても、RTS は ON(Hight) にはならないのでしょうか?  
(Win32API を使用するしかないのでしょうか...)

[code]

    public class SerialCommunicationTester : System.IDisposable
    {
        private System.IO.Ports.SerialPort _serialPort = null;
    
        // 0. Open SerialPort.
        public bool Open(
            string portName,
            int baudRate,
            int dataBits,
            System.IO.Ports.Parity parity,
            System.IO.Ports.StopBits stopBits,
            int readTimeout,
            int writeTimeout,
        ) {
            _serialPort.PortName = portName;
            _serialPort.BaudRate = baudRate;
            _serialPort.DataBits = dataBits;
            _serialPort.Parity = parity;
            _serialPort.StopBits = stopBits;
            _serialPort.Handshake = Handshake.None;
            _serialPort.ReadTimeout = readTimeout;
            _serialPort.WriteTimeout = writeTimeout;
    
            try {
                _serialPort.Open();
            } catch (Exception ex) {
                Console.WriteLine("SerialPort#Open Failed...{0}", ex);
            }
    
            return _serialPort.IsOpen;
        }
    
        // 1. Set to RTS "High" and 2. Wait for CTS to go "High".
        public bool RtsCtsFlowCtrl(uint timeout) {
    
            if (!_serialPort.IsOpen) return false;
    
            bool result = true;
            // 1. Set to RTS "High"
            _serialPort.RtsEnable = true;
            Stopwatch sw = new Stopwatch();
            sw.Start();
            // 2. Wait for CTS to go "High".
            while (true) {
                Thread.Sleep(0);
                if (_serialPort.CtsHolding) break;
                if (0 < timeout && timeout <= sw.ElapsedMilliseconds) {
                    result = false;
                    break;
                }
            }
            sw.Stop();
            return result;
        }
    
        // 4. Set to RTS "Low"
        public void RtsOff() {
            if (_serialPort.IsOpen) _serialPort.RtsEnable = false;
        }
    }
    
[/code]


CC BY-SA 4.0
2022-11-25T10:16:48.270
92426
2022-11-28T09:51:46.360
2022-11-25T23:19:42.140
4236
55588
question
c# シリアル通信
C# SerialPort クラスを使用して RTS/CTS を手動で制御する方法


.NETのソースコードを読む限り、期待通りの動作をしています。つまり、

[`SerialPort.RtsEnable`プロパティは最終的に](https://github.com/dotnet/runtime/blob/v7.0.0/src/libraries/System.IO.Ports/src/System/IO/Ports/SerialStream.Windows.cs#L419)

[code]

    EscapeCommFunction(_handle, <SerialPort.RtsEnableの値> ? SETRTS : CLRRTS);
    
[/code]

が呼ばれますし、[`SerialPort.CtsHolding`プロパティ](https://github.com/dotnet/runtime/blob/v7.0.0/src/libraries/System.IO.Ports/src/System/IO/Ports/SerialStream.Windows.cs#L501-L511)は

[code]

    <GetCommModemStatus()の結果> & MS_CTS_ON
    
[/code]

を指しています。

* * *

> SerialPort.CtsHolding が true にならずタイムアウトしてしまいます。

は原因が別のところにあるかもしれません。例えば、タイムアウトを **1秒** に設定したが、

>
[code]

>     if (0 < timeout && timeout <= sw.ElapsedMilliseconds) {
>  
[/code]

の比較により **1ミリ秒** でタイムアウト判定されてしまった、なども考えられます。

ちなみに.NETではこのような時間単位の誤りを防ぐために [`TimeSpan`型](https://learn.microsoft.com/ja-
jp/dotnet/api/system.timespan?view=net-7.0)が用意されています。
`TimeSpan.FromSeconds(1)` や `TimeSpan.FromMilliseconds(1)` という記述が可能です。


CC BY-SA 4.0
2022-11-25T23:31:29.957
92434
2022-11-25T23:31:29.957
4236
92426
answer


@kunif 様、@sayuri 様  
お忙しいところコメント、および、回答を頂き有難う御座います。

本日、投稿時と同一状態で再度動作確認を行いましたところ、  
RTS High → CTS Higt を確認できました。

何故、投稿時に期待した動作とならなかったのか明確な原因は不明ですが、  
・デバッグ開始/停止の繰り返しによる影響  
・他処理の不具合による影響  
等々であったのではないかと推察されます。


CC BY-SA 4.0
2022-11-28T09:51:46.360
92480
2022-11-28T09:51:46.360
55588
92426
answer