26

最終更新

それはずっと私たちのファームウェアでした。ある程度恥ずかしいことですが、前進できることをうれしく思います。Java の学習は別の日に延期できます。私の答えは以下です。

アップデート

だから私は多かれ少なかれこれをあきらめました。API にまで及ぶバグだと思いますが、その原因を究明するための時間もリソースもスキルセットもありません。Windowsが中指を立てるだけのハードウェアがいくつかあると思います。Eclipse をダウンロードし、Java に切り替えました。それが機能するかどうかを確認します。そうでない場合は、ここでまた会いましょう。しかし、私は絶対にこれを解決したいと思っているので、誰かがこれを深く掘り下げる時間や傾向がある場合は、あなたが思いついたものを見てみたい. もちろん、私は時々ここに戻ってきます。アラートが表示されるように、コメントで「@」を付けてください。


元の投稿

この問題に対処している人が他にも何人かいることは知っていますが、誰かが私を助けてくれることを望んでいました. COM ポートに接続しようとしていますが、次のserialport.Open()コマンドを使用しようとすると I/O 例外が発生します。

System.IO.IOException: The parameter is incorrect.

   at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
   at System.IO.Ports.InternalResources.WinIOError()
   at System.IO.Ports.SerialStream.InitializeDCB(Int32 baudRate, Parity parity, Int32 dataBits, StopBits stopBits, Boolean discardNull)
   at System.IO.Ports.SerialStream..ctor(String portName, Int32 baudRate, Parity parity, Int32 dataBits, StopBits stopBits, Int32 readTimeout, Int32 writeTimeout, Handshake handshake, Boolean dtrEnable, Boolean rtsEnable, Boolean discardNull, Byte parityReplace)
   at System.IO.Ports.SerialPort.Open()
   at *programtitlehere.cs*:line 90

COM ポートをエミュレートするために Stellaris LM4F232 を使用しています。Termite (端末プログラム) を使用して開いたり、アクセスしたり、良い結果を得ることができますが、Visual Studio を使用しようとすると接続すらできず、このエラーが発生します。今では、このエラーが何を意味するのかさえよくわかりません。他の場所で読み込もうとしても、まだ道に迷っています。

ここで何が起こっているのか誰か説明してもらえますか? もっと多くのコードを含めることができますが、正直なところ、それほど多くはありません。シリアル ポート デバイスのすべてのプロパティは正常であり、このデバイスでのみ発生しています (同じ詳細で問題なく MSP430 を使用できます)。

見たい人のために、私のコードを以下に示します(これは単なる「サンドボックス」であり、実際のプログラムではありませんが、症状は同じです):

try
{
    serialPort1.PortName = "COM5";
    serialPort1.Open();
    if (serialPort1.IsOpen == true)
    {
        textBox1.Text = "CONNECTED";
    }
    else
    {
        textBox1.Text = "NOT CONNECTED";
    }
}
catch (Exception ex)
{
    MessageBox.Show("Error: " + ex.ToString(), "ERROR");
}

その他の設定はプロパティ マネージャーで行います (唯一の違いは、ボーが 230400 に設定されていることです。他のすべての設定はデフォルトです)。これ (MSP430) を使用して COM4 を開くことができます。これは、すべての意図と目的において同一のデバイスです。COM5 は Termite で開くことができるので、接続が良好であることはわかっています)。いいえ、同時に開こうとしているわけではありません。さらに情報が必要な場合はお知らせください。さらに投稿できます。

編集:私はこれを理解しようとして3日目ですが、まだ運がありません。私が見る限り、まったく違いがないのに、なぜ自分のCOMポートではなくターミナルプログラムを介してこのCOMポートにアクセスできるのか、私にはよくわかりません。COMポートを「調べて」そのプロパティを確認できるプログラムはありますか(Windowsマネージャー以外に)?私はかなりイライラしており、これを理解するまでプロジェクトで立ち止まっているようなものです...

EDIT2: 明らかな回避策を見つけましたが、まだここで機能させるには至っていません。現在、いくつかの異なる I/O エラーが発生していますが、少なくともモーションです (進行中かどうかはわかりません)。また、これは .NET のバグであり、2.0 から存在していることもわかりました。私はまだ何か助けが欲しいのですが、私がそれを理解したら、私は戻って報告します. Zach のコード (上にリンクされている回避策) を以下に示します。

using System;
using System.IO;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;

namespace SerialPortTester
{
    public class SerialPortFixer : IDisposable
    {
        public static void Execute(string portName)
        {
            using (new SerialPortFixer(portName))
            {
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (m_Handle != null)
            {
                m_Handle.Close();
                m_Handle = null;
            }
        }

        #endregion

        #region Implementation

        private const int DcbFlagAbortOnError = 14;
        private const int CommStateRetries = 10;
        private SafeFileHandle m_Handle;

        private SerialPortFixer(string portName)
        {
            const int dwFlagsAndAttributes = 0x40000000;
            const int dwAccess = unchecked((int) 0xC0000000);

            if ((portName == null) || !portName.StartsWith("COM", StringComparison.OrdinalIgnoreCase))
            {
                throw new ArgumentException("Invalid Serial Port", "portName");
            }
            SafeFileHandle hFile = CreateFile(@"\\.\" + portName, dwAccess, 0, IntPtr.Zero, 3, dwFlagsAndAttributes,
                                              IntPtr.Zero);
            if (hFile.IsInvalid)
            {
                WinIoError();
            }
            try
            {
                int fileType = GetFileType(hFile);
                if ((fileType != 2) && (fileType != 0))
                {
                     throw new ArgumentException("Invalid Serial Port", "portName");
                }
                m_Handle = hFile;
                InitializeDcb();
            }
            catch
            {
                hFile.Close();
                m_Handle = null;
                throw;
            }
        }

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int FormatMessage(int dwFlags, HandleRef lpSource, int dwMessageId, int dwLanguageId,
                                                StringBuilder lpBuffer, int nSize, IntPtr arguments);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool GetCommState(SafeFileHandle hFile, ref Dcb lpDcb);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool SetCommState(SafeFileHandle hFile, ref Dcb lpDcb);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool ClearCommError(SafeFileHandle hFile, ref int lpErrors, ref Comstat lpStat);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
                                                        IntPtr securityAttrs, int dwCreationDisposition,
                                                        int dwFlagsAndAttributes, IntPtr hTemplateFile);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern int GetFileType(SafeFileHandle hFile);

        private void InitializeDcb()
        {
            Dcb dcb = new Dcb();
            GetCommStateNative(ref dcb);
            dcb.Flags &= ~(1u << DcbFlagAbortOnError);
            SetCommStateNative(ref dcb);
        }

        private static string GetMessage(int errorCode)
        {
            StringBuilder lpBuffer = new StringBuilder(0x200);
            if (
                FormatMessage(0x3200, new HandleRef(null, IntPtr.Zero), errorCode, 0, lpBuffer, lpBuffer.Capacity,
                              IntPtr.Zero) != 0)
            {
                return lpBuffer.ToString();
            }
            return "Unknown Error";
        }

        private static int MakeHrFromErrorCode(int errorCode)
        {
            return (int) (0x80070000 | (uint) errorCode);
        }

        private static void WinIoError()
        {
            int errorCode = Marshal.GetLastWin32Error();
            throw new IOException(GetMessage(errorCode), MakeHrFromErrorCode(errorCode));
        }

        private void GetCommStateNative(ref Dcb lpDcb)
        {
            int commErrors = 0;
            Comstat comStat = new Comstat();

            for (int i = 0; i < CommStateRetries; i++)
            {
                if (!ClearCommError(m_Handle, ref commErrors, ref comStat))
                {
                     WinIoError();
                }
                if (GetCommState(m_Handle, ref lpDcb))
                {
                     break;
                }
                if (i == CommStateRetries - 1)
                {
                     WinIoError();
                }
            }
        }

        private void SetCommStateNative(ref Dcb lpDcb)
        {
            int commErrors = 0;
            Comstat comStat = new Comstat();

            for (int i = 0; i < CommStateRetries; i++)
            {
                 if (!ClearCommError(m_Handle, ref commErrors, ref comStat))
                 {
                     WinIoError();
                 }
                 if (SetCommState(m_Handle, ref lpDcb))
                 {
                     break;
                 }
                 if (i == CommStateRetries - 1)
                 {
                     WinIoError();
                 }
            }
        }

        #region Nested type: COMSTAT

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

        #endregion

        #region Nested type: DCB

        [StructLayout(LayoutKind.Sequential)]
        private struct Dcb
        {
            public readonly uint DCBlength;
            public readonly uint BaudRate;
            public uint Flags;
            public readonly ushort wReserved;
            public readonly ushort XonLim;
            public readonly ushort XoffLim;
            public readonly byte ByteSize;
            public readonly byte Parity;
            public readonly byte StopBits;
            public readonly byte XonChar;
            public readonly byte XoffChar;
            public readonly byte ErrorChar;
            public readonly byte EofChar;
            public readonly byte EvtChar;
            public readonly ushort wReserved1;
        }

        #endregion

        #endregion
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            SerialPortFixer.Execute("COM1");
            using (SerialPort port = new SerialPort("COM1"))
            {
                port.Write("test");
            }
        }
    }
}

EDIT3: 6 日目: 私はまだこれに取り組んでいます。水の配給は少ないですが、それでも頑張っています。助けは確実に間近に迫っているに違いないと感じています。この日誌を見つけた人は誰でも私の遺体をカナダに持ち帰り、ニコールを見つけてください。私が彼女を愛していると彼女に伝えてください。

しかし、真剣に、何がこの問題を引き起こしているのかわかりません。純粋に組み込み側にあるのだろうかと思います。おそらく、USB On-The-Go (OTG) であるか、デバイスがホストにもなることができるためです。誰かがその問題に遭遇しましたか? ただし、Termite (参加したばかりの視聴者向けの端末プログラム) を使用できる理由については説明していません。私は、a) 動作し、b) a) を参照できるオープン ソース ターミナル プログラムを見つけようとしています。いつものように、2006 年にさかのぼってこの問題が発生したと思われるフォーラムを無数に見つけたので、ここで問題を発見したら報告します。

EDIT4:与えられたアドバイスに従って、ポート監視ソフトウェアアプリケーションをダウンロードしました(Eltima Serial Port Monitorを入手しました)、ボーの問題のように見えます:

Eltima からのスクリーン キャプチャ

しかし、奇妙なことに、どのボーを設定しても失敗します。また、誰かがアップ/ダウンの意味を説明できますか? ググってみましたが、キーワードが一般的すぎます。いつものように、私は変更を報告し続けます。

また、記録のために、115200 ボー (Termite と同じ) で Eltima を使用して接続できます。残念ながら、これは Visual Studio では機能しません。

EDIT5: 私たちの筋書きは意外なひねりを加えています。シロアリが問題の COM ポートに接続したときに何が起こるかを監視していて、BLAM! シロアリは私のプログラムとまったく同じエラーをスローしますが、無視します。天才ですね。ずさんですが、うまくいきます。ここで、IOExceptions を無視する方法を学ぶ必要があります。判明したらまた報告します。

EDIT6:ボーレートの問題であることが判明しましたが、さらに深くなります。Eltima Serial Port Monitoring ソフトウェアを使用していますが、非常に直感的で使いやすいです。私はそれをお勧めします。調査の結果、この例外を無視することはできず、.NET のライブラリを使用してシリアル ポートに接続できないことがわかりました。

そのため、Win32 API をさらに深く掘り下げ、独自の API を作成する必要があります。これに触れているページをいくつか見つけましたが、正直なところ、このようなことはこれまでに行ったことがありません。この問題に苦しんでいる人が多すぎます。

まったく同じ症状が見られるフォーラムや Web サイトをかなり見つけましたが、「ああ、.NET は最悪だ」と言う以外に実際に多くのことを行った人は誰もいません。私は完全な静的ライブラリ クラスを作成し、自分の Web サイト、ここ、およびその他の場所で公開する予定です。うまくいけば、.NET が気付くでしょう (このバグは 2.0 から存在しています)。

4

5 に答える 5

8

これはシリアルポートドライバから来ています。設定の1つに不満があります。ボーレートが適切な候補であるため、ドライバーは最大115200までしか許可しない傾向があります。ただし、これが専用のCANバス製品である場合、これは制限ではありません。

これに取り組む最善の方法は、SysinternalsのPortmonユーティリティを使用することです。ドライバーに何が送信されているかを確認できます。最初に終了するためにそれを観察します。それがあなたの既知のベースラインです。次に、プログラムによって送信された初期化コマンドがPortMonに表示されるように、Termiteのコマンドと一致するまで、SerialPortプロパティをいじくり回します。順序ではなく、値のみ。それでもうまくいかない場合は、駐車場に持っていき、車で数回戻し、別のブランドを購入します。


更新:それは確かにボーレートの問題のように見えます。これは.NETの問題です。ターミナルエミュレータプログラムのように、ドライバのエラーリターンコードを無視することはありません。エミュレートされたシリアルポートと通信しているため、実際の値は重要ではありません。ただし、CANバス速度に問題がある可能性があります。料金は変動し、どのように交渉されるかは私にはわかりません。これは昔はDIPスイッチで行われる傾向があり、ドライバーがボーレート設定で速度を指定するように求めている可能性があります。箱やマニュアルに何かあるはずです。通常の速度は40、250、または500 kbit/sです​​。メーカーは確かに知っているでしょう。彼らに電話をしてください。

于 2013-02-15T01:29:47.330 に答える
5

私は同じ状況に遭遇しました。/dev/ttyUSB0 にある 3G USB ドングル (Huawei E303F) にシリアル通信を接続しようとしています。RaspbianRaspberry Pi 2 )でMonoを使用しています。私の開発用 PC と macOS では、私のプログラムは問題なく動作します。しかし、Raspbian にデプロイすると、Serial.Open() でIOException Broken Pipeエラーが発生しました。

デバッグに 3 日かかり、考えられるすべての解決策を試しました。最後に、設定する必要があることがわかりました...

serialPort.DtrEnable = true;
serialPort.RtsEnable = true;

.Open() を呼び出す前に。

于 2017-01-08T14:34:12.690 に答える
5

このスレッドで報告されているのと同様の問題に直面しましたが、問題を解決することができました!

VCP に STM32F2xx を使用しています。

そして実際、それは私のファームウェアの問題でした。USB コールバックにシリアル ポート設定を含めるのを忘れていました。

PC とファームウェアからシリアル ポートを接続するプロセス:

  1. PC がシリアル ポート通信を開くと、PC は何らかのコマンドを「構成エンドポイント」に送信します。
  2. ファームウェアでは、コールバックがあり、ファームウェアはすべての USB 情報を提供します (USB 記述子と呼ばれます)。
  3. USB 情報は、各エンドポイントの構成です (たとえば、遅延、データ サイズの送信、および USB の種類 - 高速または低速)
  4. ファームウェアがすべての情報の送信を完了すると、PC が確認し、USB 通信が正常に開かれます。
  5. 次に、PC はコマンドを送信して、ファームウェアからシリアル ポート設定を取得します。
  6. シリアル ポートの設定は、ボーレート、データ パリティ、およびビット長です。
  7. ファームウェアでは、シリアルポートの設定を PC に返信する必要があります (私の間違いはここで発生します。シリアルポートの設定を PC に送信していません) 。
  8. 成功すると、PC はシリアル ポート通信を開始します。
  9. 失敗した場合、PC はオープン シリアル ポート エラーを返します (ただし、このエラーはバイパスされる場合があることに注意してください)。

STM32 ファームウェア コード:

static int8_t CDC_Control_FS (uint8_t cmd, uint8_t* pbuf, uint16_t length)
{
    switch (cmd) {
       case CDC_GET_LINE_CODING:
        {
            // I was missing this part
            uint32_t baudrate = 9600;
            pbuf[0] = (uint8_t)(baudrate);
            pbuf[1] = (uint8_t)(baudrate >> 8);
            pbuf[2] = (uint8_t)(baudrate >> 16);
            pbuf[3] = (uint8_t)(baudrate >> 24);
            pbuf[4] = 0;
            pbuf[5] = 0;
            pbuf[6] = 8;
            break;
        }:
....
于 2014-11-14T08:10:53.980 に答える
2

そして、私たちのスリリングな物語は終わりを迎えます。それはずっとファームウェアでした(つまり、組み込みデバイスのコード)。いくつかの関数を変更し、基本的にコードを突っ込み、切り刻み、追加し、完全にクリーンアップしました。コードは機能しています。この写真はそれをかなりうまくまとめています。ファームウェアを呪う!!

しかし、私の(長い)質問で説明されているバグはまだ多くの人に残っており、まだそれを持っている人がたくさんいることを私は知っています。私が言えるのは、幸運とファームウェアの4倍のチェックです(最近は3倍のチェックでは不十分なようです)。

于 2013-03-19T19:36:57.407 に答える