% proc rd_chid {chid} { set msg [gets $chid] puts $msg } % set com [open com1: r+] % fconfigure $com -mode 9600,n,8,1 -blocking 0 -translation auto -buffering line % fileevent $com readable [list rd_chid $com]However, I was able to receive data by putting those last 3 lines into its own procedure...
% proc rd_chid {chid} { set msg [gets $chid] puts $msg } % proc open_com {} { global com set com [open com1: r+] fconfigure $com -mode 9600,n,8,1 -blocking 0 -translation auto -buffering line fileevent $com readable [list rd_chid $com] } % open_com # lots of data comes streaming :) % close $comjg
Tcl 8.4 greatly improved serial port control across platforms. Refer to the updated fconfigure documentation for more info.
To retrieve details on input/output errors--which are, in general, frequent, when working with serial lines--interrogate
set details [fconfigure $serial_handle -lasterror]8.3.4 introduced this capability.
How can I connect to a com port higher than 9? (I am using a terminal server, and its driver creates com ports upto 16 or so.) Would appreciate answer by mail - anner@flexlight-networks.comThanks25Aug2003 PS: You need to use the 'generic' name (I think it is actually the UNC path) of the com port. Use the file name \\.\com13 to open 'com13:' Mind you, windows wants to see those all those \ chars, so use [open \\\\.\\com13 r+]. I have not tested this myself... E_NO_ACCESS_TO_BIG_SERIAL_CARD. But it does work :)AMG: You can use {brace quoting} to eliminate the need for doubled \backslashes.20111014 tested with 8.5.9: open //./com13 definitely works (or \\\\.\\com13), shorter variants don't. Interesting detail: if you are using a tclkit app, you can open com5 etc only if you have the current directory NOT within tclkit VFS, but outside of this (com1...4 always open regardless current dir). But using the absolute path as proposed above, VFS or normal current directory does not matter.
The following code will enumerate the serial devices on a windows XP machine - including USB devices.
package require registry proc get_serial_ports { } { set serial_base "HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\SERIALCOMM" set values [ registry values $serial_base ] set result {} foreach valueName $values { lappend result [ registry get $serial_base $valueName ] } return $result }
Yep, the above works fine on XP. Try " return [lsort -dictionary $result]" to get the list sorted... -regardsZB 20111012 - yes, it works on my Win XP - but I had the problem, that id did list also the "virtual serial ports" left by Bluetooth device (not connected). Trying to open such serial port resulted in very long pause (almost a minute), before "open" gave up.
enumerate serial devices on win2k-win7(Jee Labs version [1])
# 2010-04-21 improved version, see http://talk.jeelabs.net/topic/208 # 2012-03-16 further improved, added detection for Brainboxes and ACPI # # List serial ports # # Identifies the following devices: # ftdi, acpi, usb, bbx (Brainbox) # # Resulting list: # <prefix>-<serial> COM<xy> ## proc RawListSerialPorts {} { set result {} set ccs {HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet} foreach {type prefix match} { Serenum ftdi {^FTDIBUS.*_6001.(\w+)} Serenum acpi {^ACPI.*(\w+)} usbser usb {^USB\B.*\B(.*)$} BbEnum20 bbx {^Ports\\BbUSer([0-9]*).*} } { # ignore registry access errors catch { set enum "$ccs\\Services\\$type\\Enum" set n [registry get $enum Count] for {set i 0} {$i < $n} {incr i} { set desc [registry get $enum $i] if {[regexp $match $desc - serial]} { set p [registry get "$ccs\\Enum\\$desc\\Device Parameters" PortName] # Log . {usb-$serial Port: $p\ Friendly: [registry get "$ccs\\Enum\\$desc" FriendlyName]} lappend result $prefix-$serial $p } } } } return $result }
Note that you most frequently see code something like this:
set serial [open "COM1:" "RDWR"] fconfigure $serial -mode 9600,n,8,1where fconfigure sets the baud rate, etc. of the serial port.ZB The above procedure didn't work at all on my Win XP.[PY] As for me, I use next snippet to obtain virtual COM ports:
# List all ports as FTDIBUS and USB. Returns list of {PortName, FriendlyName, Auto?} # where Auto is flag - port for HMC6343 or not proc ls_virt {args} { set res "" foreach {type vid} {FTDIBUS VID_* USB V[iI][dD]_*} { set k0 "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\$type" catch { ;# catch case where e.g. FTDIBUS is not found set k0ch [registry keys "$k0" $vid] foreach k1 $k0ch { set found [regexp -nocase $args $k1] set k1ch "" catch {set k1ch [registry keys "$k0\\$k1"]} foreach k2 $k1ch { set Class "" catch { ;# nested catch to prevent total loop break set Class [registry get "$k0\\$k1\\$k2" Class] if {$Class == "Ports"} { # only when Class is defined, the driver is truly installed set FriendlyName [registry get "$k0\\$k1\\$k2" FriendlyName] if {$found || [regexp -nocase $args $FriendlyName]} { set PortName [registry get "$k0\\$k1\\$k2\\Device Parameters" PortName] set Service [registry get "$k0\\$k1\\$k2" Service] lappend res [list $PortName $FriendlyName $Service] } } } } } } } return $res }RJM extended by scanning not only FTDI-based ports and case-tolerant VID/Vid string recognition as well as added robustness. Further, a result filter may be specified, used to filter according to FriendlyName substring or Pid&Vid keyThird item is a flag - is it our device (I'm looking for HMC6343 sensor, but it's possible to test instead of silabser any other driver/service type).
[_abc_] - 2012-01-27 14:56:35code to enumerate all serial ports, cross platform, tested to work well on various linuxes and windows xp and windows 7. Contributed by emiliano and tested by me on several machines.
package require platform namespace eval serial { variable platform [lindex [split [platform::generic] -] 0] } proc serial::listports {} { variable platform set result {} switch -- $platform { win32 { catch { package require registry set serial_base [join { HKEY_LOCAL_MACHINE HARDWARE DEVICEMAP SERIALCOMM} \\] set values [ registry values $serial_base ] foreach value $values { lappend result \\\\.\\[registry get $serial_base $value] } } } linux { set result [glob -nocomplain {/dev/ttyS[0-9]} {/dev/ttyUSB[0-9]} {/dev/ttyACM[0-9]}] } netbsd { set result [glob -nocomplain {/dev/tty0[0-9]} {/dev/ttyU[0-9]}] } openbsd { set result [glob -nocomplain {/dev/tty0[0-9]} {/dev/ttyU[0-9]}] } freebsd { # todo } default { # shouldn't happen } } return [lsort $result] }
aspenlogic 2014-04-30All of the scripts above worked to locate the names of my Windows 7 (64-bit) COM ports. However, a simple [open COM2: r+] always failed. On a hunch I tried running wish with Administrator privileges. After that, open worked just fine.
HE 2014-07-13: I had the task to show the currently existing devices connected via serial interfaces and show them with their friendly name. The solution I found is a combination of the above mentioned registry keys. It provides a list of list with two values (COM port and friendly name):
proc getSerialInterfaces {} { set coms {} set res {} set key "HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\SERIALCOMM" if {[catch { # The keys only available if the driver is loaded. foreach name [registry values $key] { set value [registry get $key $name] lappend coms $value } } fault]} { # return a empty list in case no serial interface is found return $res } set key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum foreach el [registry keys $key] { foreach el1 [registry keys $key\\$el] { catch { foreach el2 [registry keys $key\\$el\\$el1] { set port [registry get "$key\\$el\\$el1\\$el2\\Device Parameters" PortName] if {[lsearch $coms $port] < 0} { continue } set friendlyName [registry get "$key\\$el\\$el1\\$el2" FriendlyName] lappend res [list $port $friendlyName] } } } } return [lsort $res] }KL 2017-11-10 NOTE: This implementation does not work in WIN 10 can somebody provide a solution ??