@Ledington

Как сделать сканирование COM-портов и добавление в ComboBox?

Добрый день!
Я на самом начале своего пути в программирование на данном языке, поэтому могу задавать довольно простые вопросы для некоторых.
Есть задачка простая вроде как, просканировать COM-порты на компе. Прямых как таковых нет, есть COM-порт подключенный через USB-переходник. В диспетчере отображается как USB-SERIAL CH340 (COM3).
Надо проверить свободен он или нет, ну и живой ли, и добавить в ComboBox.
Почитал разные форумы и пришел к такому коду:

using System;
using System.IO;
using System.IO.Ports;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace COM_test_2
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        private void connect ()
        {
            string[] ports = SerialPort.GetPortNames();
            SerialPort[] serialPort = new SerialPort[ports.Length];
            foreach (string port in ports)
            {
                int i = Array.IndexOf(ports, port);
                //serialPort[i] = new SerialPort();
                serialPort[i].PortName = port;
                serialPort[i].BaudRate = 9600;
                serialPort[i].Open();

                serialPort[i].DataReceived += serialPort_DataReceived;
                comboBox.Items.Add(port);
            }
        }

        private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            SerialPort serialPort1 = sender as SerialPort;
            byte[] data = new byte[serialPort1.BytesToRead]; 
            Stream portStream = serialPort1.BaseStream;
            portStream.Read(data, 0, data.Length);
        }
    }
}


Код не вызывает каких либо ошибок при компиляции, запускается, но в ComboBox ничего нет.
Что не так? Как увидеть COM3 в ComboBox?
  • Вопрос задан
  • 1192 просмотра
Пригласить эксперта
Ответы на вопрос 5
a_volkov1987
@a_volkov1987
Инженер-схемотехник
Я не настоящий программист, но делал так и все работает:

При загрузке формы вычитываем список портов и пихаем их в комбобокс
private void Main_Load(object sender, EventArgs e)
        {
            var portNames = SerialPort.GetPortNames();
            portSelectorComboBox.Items.AddRange(portNames);
        }


Выбранный в комбобоксе элемент кидаем в переменную

private void portSelectorComboBox_TextChanged(object sender, EventArgs e)
        {
            _portName = portSelectorComboBox.SelectedItem.ToString();
        }


По нажатию кнопки OpenButton пытаемся соединиться

private void portOpenButton_Click(object sender, EventArgs e)
        {
            try
            {
                port = new SerialPort(_portName, 115200, Parity.None, 8, StopBits.Two);
                port.ReceivedBytesThreshold = 1;
                port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
                port.Open();
                portStatusText.Text = "Ok, port open";
            }
            catch (Exception)
            {
                portStatusText.Text = "Error";
                MessageBox.Show("неправильно выбран порт, попробуйте еще раз");
            }
        }


Ну и реализуем чтение того что пришло

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

        }
Ответ написан
@cicatrix
было бы большой ошибкой думать
В своё время делал перечисление последовательных портов так, но не уверен, что это есть хорошо.
Тоже интересно было бы узнать, можно ли сделать поэлегантнее:
using System.Management;

public static Dictionary<string, ManagementBaseObject> EnumerateComPorts()
{
    Dictionary<string, ManagementBaseObject> result = new Dictionary<string, ManagementBaseObject>();
    string[] ports = SerialPort.GetPortNames();
    foreach (string port in ports)
    {
        using (var entitySearcher = new ManagementObjectSearcher(
            "root\\CIMV2", $"SELECT * FROM Win32_PnPEntity WHERE Caption LIKE '%{port}%'"))
        {
            var matchingEntity = entitySearcher.Get().Cast<ManagementBaseObject>().FirstOrDefault();
            if (null != matchingEntity)
            {
                result.Add(port, matchingEntity);
            }
        } // using
    } // foreach
    return result;
} // EnumerateComPorts


Далее, уже сделал Listener на нужный порт и ждал данные:
public RS232Listener(string portname)
        {
            m_queue = new Queue<string>();
            try
            {
                if (null != m_port)
                {
                    m_port.Close();
                    m_port.Dispose();
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
                m_port = new SerialPort(portname, 9600, Parity.None, 8, StopBits.One);
                m_port.DataReceived += this.M_port_DataReceived;
                m_port.ErrorReceived += this.M_port_ErrorReceived;
                m_port.Open();
            } // try
            catch(Exception ex)
            {
                Logger.LogError("RS232Listener constructor", ex.Message, ex);
                ErrorMessage = ex.Message;
                ErrorState = true;
            }
        } // RS232Listener constructor
Ответ написан
@d-stream
Готовые решения - не подаю, но...
Последовательно перебирать 256 com портов, да еще и получая в 99% случаев отлупы - штука долгая
но это видимо единственный вариант надежного определения всех портов
я бы делал в отдельных потоках (фоне) попытки их открыть и по успеху маркировал как потенциально доступные
это по крайней мере позволит не завесить UI на минуты... ну и в общем случае если "плюнуть" сразу 256 параллельных проверок - то окончания результата можно дождаться в 30 сек.
Ответ написан
Комментировать
gdt
@gdt
Программист
Вот здесь https://stackoverflow.com/a/1394301/1828989 перечислены все самые популярные способы обнаружения портов, выбирайте по вкусу :)
Ответ написан
Комментировать
@lonelymyp
Хочу вылезти из минуса по карме.
Насколько я помню, попытка открытия неподключенного порта может вешать ПО, поэтому стоит сразу же убивать поток если нет мгновенного результата, не дожидаясь таймаута.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы