Listado de puertos serie (COM) en Windows?

Estoy buscando una forma sólida de enumerar los puertos serie (COM) disponibles en una máquina con Windows. Hay una 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 progtwig 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 siempre 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?

Edición: por cierto, aquí hay una implementación simple 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 

Varias opciones están disponibles:

  1. Llame a QueryDosDevice con un lpDeviceName NULL para enumerar todos los dispositivos DOS. Luego, use CreateFile y GetCommConfig con cada nombre de dispositivo para 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 los progtwigs C / C ++ .

Hay una conversación sobre el grupo de noticias win32 y un proyecto de CodeProject, er.

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 ++ a EnumSerialPorts y al ver la función GetDefaultCommConfig() . Parecía el método más simple usando ANSI C simple y una sola llamada de API para cada puerto COM posible.

 #include  #include  #include  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  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 poner en marcha 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 pip install pypiwin32 WMI .

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) 

Salida

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

Supongo que su puerto serie es una especie de Plug ‘n Play, así que esto 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()