Pregunta

Estoy buscando una forma sólida de enumerar los puertos serie (COM) disponibles en una máquina con Windows. Hay esta publicación sobre el uso de WMI , pero me gustaría algo menos específico de .NET - Quiero obtener la lista de puertos en un programa Python o C ++, sin .NET.

Actualmente, conozco otros dos enfoques:

  1. Leyendo la información en la clave de registro HARDWARE \\ DEVICEMAP \\ SERIALCOMM . Esto parece una gran opción, pero ¿es robusto ? No puedo encontrar una garantía en línea o en MSDN de que esta celda de registro tenga la lista completa de puertos disponibles.

  2. Intente llamar a CreateFile en COMN con N un número de 1 a algo. Esto no es lo suficientemente bueno, porque algunos puertos COM no se denominan COMN. Por ejemplo, algunos puertos COM virtuales creados se denominan CSNA0, CSNB0, etc., por lo que no confiaría en este método.

¿Algún otro método / idea / experiencia para compartir?

Editar: por cierto, aquí hay una implementación sencilla de Python para leer los nombres de puertos del registro:

import _winreg as winreg
import itertools


def enumerate_serial_ports():
    """ Uses the Win32 registry to return a iterator of serial 
        (COM) ports existing on this computer.


    """
    path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
    try:
        key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
    except WindowsError:
        raise IterationError

    for i in itertools.count():
        try:
            val = winreg.EnumValue(key, i)
            yield (str(val[1]), str(val[0]))
        except EnvironmentError:
            break
¿Fue útil?

Solución

Hay varias opciones disponibles:

  1. Llame a QueryDosDevice con una NULL lpDeviceName para enumerar todos los dispositivos DOS. Luego use CreateFile y GetCommConfig con cada nombre de dispositivo en diríjase a averiguar si se trata de un puerto serie.

  2. Llame a SetupDiGetClassDevs con un ClassGuid de GUID_DEVINTERFACE_COMPORT.

  3. WMI también está disponible para C / C ++ programas .

Hay una conversación en el win32 newsgroup y un CodeProject, er, proyecto .

Otros consejos

Usando pySerial con Python:

import serial.tools.list_ports


ports = list(serial.tools.list_ports.comports())
for p in ports:
    print p

El proyecto PySerial proporciona un par de soluciones .

Acabo de crear lo siguiente, basado en la lectura a través de la fuente de C ++ en EnumSerialPorts y al ver el función GetDefaultCommConfig () . Parecía el método más simple utilizando ANSI C simple y una única llamada a la API para cada puerto COM posible.

#include <stdio.h>
#include <windows.h>
#include <winbase.h>

BOOL COM_exists( int port)
{
    char buffer[7];
    COMMCONFIG CommConfig;
    DWORD size;

    if (! (1 <= port && port <= 255))
    {
        return FALSE;
    }

    snprintf( buffer, sizeof buffer, "COM%d", port);
    size = sizeof CommConfig;

    // COM port exists if GetDefaultCommConfig returns TRUE
    // or changes <size> to indicate COMMCONFIG buffer too small.
    return (GetDefaultCommConfig( buffer, &CommConfig, &size)
                                                    || size > sizeof CommConfig);
}

int main()
{
    int i;

    for (i = 1; i < 256; ++i)
    {
        if (COM_exists( i))
        {
            printf( "COM%d exists\n", i);
        }
    }

    return 0;
}

Esto definitivamente es bastante tarde, ¡pero me resultó útil!

http: / /eli.thegreenplace.net/2009/07/31/listing-all-serial-ports-on-windows-with-python/

Particularmente este ejemplo:

import re

def full_port_name(portname):
    """ Given a port-name (of the form COM7,
        COM12, CNCA0, etc.) returns a full
        name suitable for opening with the
        Serial class.
    """
    m = re.match('^COM(\d+), portname)
    if m and int(m.group(1)) < 10:
    return portname
return '\\\\.\\' + portname

Hay un ejemplo en la distribución de pyserial ahora que hace esto llamado scanwin32.py

http://pyserial.sourcearchive.com/documentation/2.5/scanwin32_8py_source.html

Creo que WMI es el camino a seguir, ya que es bastante fácil de usar y tiene un código mínimo. Le ahorra tener que excavar dentro del registro y le da alguna garantía de que funcionará para situaciones más generales en el futuro.

Puede instalar todo lo necesario con pip install pypiwin32 WMI y funciona de manera inmediata.

Código

import wmi

query = "SELECT * FROM Win32_PnPEntity WHERE Name LIKE '%(COM%)'"
coms  = wmi.WMI().query(query)

for com in coms:
    print(com.Name)

Output

Communications Port (COM1)
mbed Serial Port (COM3)
mbed Serial Port (COM5)

Supongo que su puerto serie es una especie de Plug 'n Play, por lo que debería funcionar bien. Por alguna razón, Win32_SerialPort no funciona para todos los puertos.

Hoy en día hay una sola línea de Powershell para eso.

[System.IO.Ports.SerialPort]::GetPortNames()
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top