jbr May 2, 2010
The Delta Tau PMAC (programmable multi axis controller) is a high end programmable motion controller for machine tools and robotics. I have been programming PMACs for about 10 years. Usually I access them from C, but recently I've had occasion to connect directly from Tcl.
Here is a simple library that I wrote up last week to make this possible. You'll need TCP and recv.
You'll also need to review the PMAC Ethernet protocol documentation, this library is a pretty direct mapping of the available commands. The only "fancy" usage here is pmac:command which provides a command reply pair and pmac:mapmem which reads a memory buffer from the pmac and immediately calls binary scan to map the data buffer into Tcl variables that need to be fully qualified names.
I think that this code provides a very concise example of interacting with a binary protocol in Tcl.
enjoy,
set Host2PMAC 0x40 set PMAC2Host 0xC0 set PMAC_SENDLINE 0xB0 set PMAC_GETLINE 0xB1 set PMAC_FLUSH 0xB3 set PMAC_GETMEM 0xB4 set PMAC_SETMEM 0xB5 set PMAC_READY 0xC2 set PMAC_GETBUFFER 0xC5 set PMAC_WRITEBUFFER 0xC6 proc pmac:connect { pmac } { set sock [socket $pmac 1025] fconfigure $sock -encoding binary return $sock } proc pmac:flush { sock } { pmac:packet $sock $::Host2PMAC $::PMAC_FLUSH read $sock 1 } proc pmac:wait { sock } { set x 0 while { 1 } { pmac:packet $sock $::PMAC2Host $::PMAC_READY 0 2 binary scan [read $sock 2] c x if { $x } { break } after 10 } } proc pmac:getbuf { sock } { pmac:packet $sock $::PMAC2Host $::PMAC_GETBUFFER 0 1400 recv $sock } proc pmac:command { sock data } { pmac:packet $sock $::Host2PMAC $::PMAC_SENDLINE 0 [string length $data] $data binary scan [read $sock 1] c reply pmac:wait $sock string map { \r " " } [string range [pmac:getbuf $sock] 0 end-2] } proc pmac:wbuff { sock data here } { pmac:packet $sock $::Host2PMAC $::PMAC_WRITEBUFFER 0 [string length $data] $data binary scan [read $sock 4] scc line code error if { $error == 0x80 } { error "pmac:write : error $code at line [expr $here + $line]" } } proc pmac:write { sock Data } { set data {} set Here 0 set here 0 foreach line [split $Data \n] { if { [string length $data] + [string length $line] + 1 > 1000 } { pmac:wbuff $sock $data $Here incr Here $here set data {} set here 0 } append data $line "\0" } pmac:wbuff $sock $data $Here } proc pmac:setmem { sock start length } { pmac:packet $sock $::Host2PMAC $::PMAC_SETMEM $start $offset $data } proc pmac:packet { sock type requ { offset 0 } { size 0 } { data {} } } { puts -nonewline $sock [binary format ccSSS $type $requ $offset 0 $size] puts -nonewline $sock $data flush $sock } proc pmac:getmem { sock start length } { pmac:packet $sock $::PMAC2Host $::PMAC_GETMEM $start $length recv $sock } proc pmac:mapmem { sock start length scan vars } { set block [pmac:getmem $sock $start $length] binary scan $block $scan {*}$vars] }