Подтвердить что ты не робот

Ошибка исключения IO при использовании serialport.open()

ЗАКЛЮЧИТЕЛЬНОЕ ОБНОВЛЕНИЕ Это была наша прошивка все время. Смущаю до некоторой степени, но я счастлив, что мы можем двигаться вперед, и я могу учить изучение Java еще на один день. Мой ответ ниже.

UPDATE Поэтому я более или менее отказался от этого. Я думаю, что это ошибка, которая сводится к API, но у меня нет ни времени, ни ресурсов, ни навыков, чтобы добраться до сути. Я думаю, что существует некоторое аппаратное обеспечение, которому Windows просто дает средний палец. Я загрузил Eclipse, переключился на Java и попытаюсь посмотреть, работает ли это. Если нет, ты увидишь меня здесь. Тем не менее, я был бы очень рад решить эту проблему, и если у кого есть время или желание углубиться в это, я бы с удовольствием посмотрел, что вы придумали. Очевидно, я буду периодически проверять это время. Пожалуйста, убедитесь, что вы "@" меня в своих комментариях, поэтому меня предупреждают.


ОРИГИНАЛЬНАЯ ПОЧТА

Я знаю, что есть несколько других людей, которые занимаются этой проблемой, но я надеялся, что кто-то сможет мне помочь. Я пытаюсь подключиться к COM-порту, но я получаю исключение IO, когда пытаюсь использовать команду serialport.Open():

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

Я использую Stellaris LM4F232 для эмуляции COM-порта. Я могу открыть, получить доступ и получить хорошие результаты с помощью Termite (терминальной программы), но всякий раз, когда я пытаюсь работать с Visual Studio, он даже не подключается, и я получаю эту ошибку. Теперь я даже не знаю, что означает эта ошибка, и я, несмотря на попытки читать в другом месте, все еще чувствую себя потерянным.

Может кто-нибудь объяснить мне, что здесь происходит, и, может быть, я начну пытаться понять это? Я могу добавить больше кода, но, честно говоря, там не так много; все свойства устройства serialport являются нормальными, и это происходит только с этим устройством (я могу использовать 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, все остальные по умолчанию). Я могу открыть COM4 с этим (MSP430), который для всех целей и задач является идентичным устройством. Я могу открыть COM5 с Termite, поэтому я знаю, что соединение хорошее). И нет, я не пытаюсь открыть их одновременно. Если вам нужна дополнительная информация, дайте мне знать, и я могу опубликовать больше.

Спасибо!

EDIT: я на третий день пытаюсь понять это и до сих пор не повезло. Я не понимаю, почему я могу получить доступ к этому COM через терминальную программу, а не по своему усмотрению, когда я вижу, что нет абсолютно никакой разницы. Кто-нибудь знает о программе, которая может "исследовать" COM-порт, чтобы увидеть его свойства (помимо диспетчера Windows, я имею в виду)? Я становлюсь довольно расстроенным и вроде как стоять в моем проекте, пока не узнаю об этом...

EDIT2: Я нашел очевидное обходное решение, но мне еще нужно заставить его работать здесь. Теперь я получаю несколько разных ошибок ввода-вывода, но по крайней мере это движение (не уверен, что это прогресс). Я также узнал, что это ошибка .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-to-go, или потому, что устройство также может быть хостом. Кто-нибудь сталкивался с этой проблемой? Это не объясняет, почему я могу использовать Termite (терминальная программа, для тех, кто просто присоединяется к нам). Я пытался найти терминальную программу с открытым исходным кодом, которая: а) работает и б) видит а). Как обычно, я отчитаю, если я открою здесь эту проблему, так как теперь я нашел бесчисленные форумы, на которых звучит эта проблема, относящаяся к 2006 году.

EDIT4: Так, в соответствии с приведенным советом, я загрузил приложение для мониторинга портов (я получил Eltima Serial Port Monitor), и он выглядит как проблема с бодом:

Screen capture from Eltima

но, как ни странно, какой бы бод я ни устанавливал, он все еще терпит неудачу. А также может кто-нибудь объяснить, что означает "вверх-вниз"? Я пробовал искать его, но ключевые слова слишком общие. Как обычно, я буду сообщать о любых изменениях.

Кроме того, для записи я могу подключиться с помощью Eltima при бодах 115200 (так же, как Termite). К сожалению, это не работает в Visual Studio.

EDIT5: Наш сюжет имеет неожиданное завихрение. Я отслеживал, что происходит, когда Termite подключается к рассматриваемому COM-порту и BLAM! Термиты выдают ту же ошибку, что и моя программа, но игнорируют ее. Гений, да? Sloppy, но он работает. Теперь мне нужно научиться игнорировать IOExceptions. Я отчитаю, когда выясню, как это сделать.

EDIT6: Итак, как выясняется, это проблема скорости в бодах, но она идет глубже. Я использую программное обеспечение для мониторинга последовательного порта Eltima, и он очень интуитивно понятен и прост в использовании. Я бы рекомендовал его. После некоторых исследований я узнал, что вы не можете игнорировать это исключение и все еще подключаться к последовательному порту с использованием библиотеки .NET. Поэтому я должен углубиться в API Win32 и написать свой собственный. Я нашел несколько страниц, которые касаются этого, но, честно говоря, я никогда не делал ничего подобного раньше, так что может быть какое-то время, пока я не отчитаюсь, но я обязательно это рассмотрю и вернусь к каждому. Есть слишком много людей, которые страдают от этой проблемы. Я нашел довольно много форумов и веб-сайтов, где я могу видеть те же самые симптомы, но никто на самом деле ничего не сделал, кроме того, сказал: "Да,.NET сосет". Я планирую писать полный статический класс библиотеки, а затем публиковать либо на своем веб-сайте, и здесь, и где бы я мог. Надеемся, что .NET заметит (эта ошибка существует с версии 2.0). Я отчитаю, когда это будет сделано!

EDIT7: Это намного сложнее, чем я думал.

EDIT8: Я не знаю, если кто-то следит за этим или нет, но я хотел сказать, что я все еще нахожусь, но я выхожу из города на неделю в командировке. Я все еще рад услышать предложения и альтернативные идеи, хотя!

4b9b3361

Ответ 1

Итак, наша захватывающая история подходит к концу. Это была прошивка все время (т.е. Код на встроенном устройстве). Мы изменили несколько функций и, по существу, ткнулись, нарезали, добавили и полностью очистили код и вуаля, код работает. Этот рисунок подводит итог. Проклятие прошивки!

Однако ошибка, описанная в моем (длинном) вопросе, по-прежнему сохраняется для многих людей, и я знаю, что есть много людей, которые все еще имеют ее. Все, что я могу сказать, это удача и четырехкратная проверка вашей прошивки (по-видимому, тройная проверка этого недостаточно в наши дни).

Ответ 2

Это происходит от драйвера последовательного порта, он недоволен одним из параметров. Поскольку скорость передачи данных является хорошим кандидатом, драйверы имеют тенденцию допускать только до 115200. Хотя это не должно быть ограничением, если это выделенный продукт шины CAN.

Лучший способ справиться с этим - с помощью утилиты SysInternals PortMon, вы можете видеть, что отправляется драйверу. Соблюдайте его сначала для завершения, чтобы ваша базовая линия была известна на рабочем месте. Затем перебирайте свойства SerialPort до тех пор, пока команды инициализации, как вы видите их в PortMon, не отправили вашей программой, не соответствуют термитам. Просто значения, а не порядок. Если это не закончится, то возьмите его на автостоянку и верните его с помощью своего автомобиля несколько раз и купите другой бренд.


Обновление: это, безусловно, похоже на проблему с бодрой скоростью. Это проблема в .NET, она не будет игнорировать код возврата ошибки драйвера, как это делают программы эмулятора терминала. Фактическое значение не должно иметь значения, поскольку вы разговариваете с эмулированным последовательным портом. Тем не менее, существует проблема с частотой шины CAN, ставки меняются, и мне не ясно, как они обсуждаются. Это, как правило, с DIP-переключателями в прежние дни, вполне возможно, что драйвер хочет, чтобы вы указали скорость через настройку скорости передачи. Там должно быть что-то об этом на коробке или в руководстве. Типичные скорости - 40, 250 или 500 Кбит/с. Производитель, конечно же, знал бы, позвоните им.

Ответ 3

Я сталкиваюсь с аналогичной проблемой, о которой сообщалось в этом потоке, но мне удалось решить эту проблему!

Я использую STM32F2xx для VCP!

И действительно, это моя проблема с прошивкой, я забыл включить параметры последовательного порта в свой обратный вызов USB!

Процесс подключения последовательного порта с ПК и прошивки:

  • Когда ПК открывает связь по последовательному порту, ПК отправит некоторую команду в "конечную точку конфигурации"
  • В прошивке у него будет обратный вызов, и прошивка предоставит всю информацию USB (они называют его дескриптором USB).
  • Информация о USB - это конфигурация каждой конечной точки (например: латентность, передача данных, тип USB - высокая скорость или низкая скорость).
  • Как только прошивка завершит отправку всей информации, ПК подтвердит и USB-связь будет успешно открыта.
  • Затем ПК отправит команду для получения настроек последовательного порта из прошивки
  • Параметры последовательного порта: скорость передачи данных, четность данных, длина бит
  • В прошивке он должен ответить на настройки последовательного порта на ПК (Моя ошибка происходит здесь, я не отвечаю на любые настройки последовательного порта на ПК)
  • В случае успеха ПК запустит связь по последовательному порту!
  • Если это не удастся, ПК даст открытую ошибку последовательного порта (но, обратите внимание, что эта ошибка иногда обходит)

В коде прошивки 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;
        }:
....

Ответ 4

Я столкнулся с той же ситуацией. Я пытаюсь подключить последовательную связь к моему 3G USB Dongle (Huawei E303F) на /dev/ttyUSB 0. Я использую моно в Raspbian (малина-pi2). В моей разработке ПК и macOS моя программа работает нормально. Но когда я развертываю его в Raspbian, я получил ошибку IOException Broken Pipe на Serial.Open().

Я потратил три дня на отладку и попробовал все возможные решения. Наконец, я обнаружил, что мне нужно установить...

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

Перед вызовами .Open(). Надеюсь, это поможет другим людям, которые сталкиваются с такими же проблемами, как и мои.