Search code examples
serial-porttclexpectpermission-deniedreconnect

Cannot reconnect to serial port that was previously opened in the same TCL script


I have been working towards automating hardware testing using TCL, where the hardware is connected to a serial port. The current script can connect to the serial port the first time through, and disconnect at the end. However, it cannot reconnect to the serial port again unless the application is closed and reopened. The code to connect to the serial port is:

    if { [catch {spawn -open [open $port r+] } results] } {
        puts $results
        puts "Could not connect to port.\n"
        return -1 }

with the successful return statement being return $spawn_id

The code that is supposed to close the connection to the serial port is:

if {[catch {close -i $handle} results]} {
    puts "$results"
    puts "Failed to Close Session $handle\n\r"
    return -1 }

#waits for handle to be properly closed
exp_wait

where $handle is the spawn_id returned by the open procedure.

I wrote a short test script to demonstrate how I am trying to use this:

source console.tcl

puts "available COM ports are: [console::availableSerial]" 

set handle [console::openSession COM6 BARE>]

if {[catch {console::closeSession $handle} results]} {
    puts $results }


if {[catch {console::openSession COM6 BARE>} results]} {
    puts $results }

where 'console::' is the namespace of the open and close procedures in question

I have tried playing around with some of the fconfigure parameters, such as enabling and disabling blocking, but to no avail.

The error message displayed by TCL is `couldn't open serial "COM6": permission denied' , suggesting the port is not being closed properly. The book 'Exploring Expect' does not have much information specific to this, so I was hoping someone here would be able to provide some insight into what I am doing wrong. I am using 32-bit ActiveState ActiveTCL 8.6.3.1 and my shell is Tclsh36

Any feedback will be appreciated. Thanks.


Solution

  • The problem here stems from using proc to deal with a spawned connection. If a connection is spawned in a procedure (call it foo1), than another procedure (call if foo2) cannot immediately interact with it. For this to work, the spawn_id must be returned from foo1 and passed in as a parameter to foo2. This does not only affect sending information to the spawned connection, but also receiving information from that connection.

    In my case, I called close -i $handle, which was correct, but then simply called exp_wait. the exp_wait was not called using the spawn_id passed in, so was not waiting for the correct response.

    The fix was to simply replace exp_wait with exp_wait -i $handle