4 proc debug {m} { puts "DEBUG $m" }
6 proc log {m} { puts "LOG $m" }
12 proc find-devices {} {
13 global errorCode errorInfo devices
14 set base /sys/class/tty
15 foreach candidate [glob -nocomplain -directory $base -tails ttyACM*] {
16 debug "candidate $candidate"
17 if {[catch { file link $base/$candidate/device } ltarget]} {
18 debug " readlink failed [lrange $errorCode 0 1]"
19 switch -glob $errorCode {
20 {POSIX EINVAL *} continue
21 {POSIX ENOENT *} continue
22 default { error "$ltarget \[$errorCode] $errorInfo $errorCode" }
25 if {![regexp {^(.*)\.(\d+)$} $ltarget dummy dbase interf]} {
26 debug " readlink bad target $ltarget"
29 debug " approved $dbase $interf $candidate"
30 lappend devs($dbase) [list $interf $candidate]
32 set howmany [array size devs]
34 experror "no appropriate device(s) found"
37 experror "several appropriate device(s) found [array names $devs]"
40 foreach dev [lsort -index 0 -integer $devs([lindex [array names devs] 0])] {
41 lappend devices [lindex $dev 1]
45 proc reopen-our-device {} {
48 set dchan [open /dev/[lindex $devices 1] r+]
49 fconfigure $dchan -blocking no -buffering line -translation {crlf cr}
50 read $dchan; # flush input
54 set result [read $dchan]
55 if {![regexp -line {^OK$} $result]} { experror "got [logquote $result]" }
56 fileevent $dchan readable dchan-readable
59 proc devfailure {emsg} {
60 global errorCode errorInfo dchan
61 switch -glob $errorCode {
62 {POSIX *} - EXPECTED {
63 log "device failure: $emsg"
66 log "unexpected device failure: $emsg"
67 foreach l [split $errorInfo "\n"] {
72 if {[info exists dchan]} {
73 catch { close $dchan }
78 proc try-open-our-device {} {
86 sendout-async *TTYATMUX "*TTYATMUXDEVS [join $devices ,]"
87 sendout-async *TTYATMUX "*TTYATMUXOPEN"
90 proc dchan-readable {args} {
100 if {![eof $dchan]} return
101 set errorCode EXPECTED
109 proc async-notif-or-resp-varies {async_values asid l} {
110 set ll [llength [split $l ,]]
111 if {$ll == $async_values} {
113 } elseif {$ll == $async_values+1} {
116 bad-data $l "async-notif-or-resp-varies $ll"
120 proc async-notif-or-resp-fixed {asid l} {
121 global current_command_asid
122 if {![string compare $asid $current_command_asid]} {
129 proc async-notif-creg {asid l} {
130 set ll [llength [split $l ,]]
134 async-notif {+CREG} 2 2 $l
135 async-notif {+CREG} 1 1 [lindex [split $l ,] 0]
139 async-notif {+CREG} 1 2 $l
142 bad-data $l "async-notif-creg $ll"
147 proc async-control-max0 {c l allows} {
148 async-control-core $c $l $allows {
153 if {$tw} { set wanted 1 }
156 foreach allow $allows { lappend $send [lindex $allow 0] }
157 sync-subcommand $c "$cmd=[join $send ,]" async-updated-ok $c
161 proc async-control-cmer {c l allows} {
162 async-control-core $c $l $allows {
165 set mode 0; set ind 0
166 manyset $ca($c) mode keyp disp ind bfr
167 if {$mode==3 && $ind} { set send 3,0,0,1 }
169 sync-subcommand $c "$cmd=$send" async-updated-ok $c
173 proc async-updated-ok
175 proc async-control-core {c l allows ubody_init ubody_perclient ubody_finish} {
178 if {[regexp {^(AT[^=?])\?$} dummy cmd]} {
179 sync-subcommand $c $cmd async-massage-result-subs $c $cmd
180 } elseif {[regexp {^(AT[^=?])=\?$} dummy cmd]} {
181 sync-subcommand $c $cmd async-massage-result-support $c $cmd $allows
182 } elseif {[regexp {^(AT[^=?])=([0-9,]+)$} dummy cmd values]} {
183 set values [split $values ,]
184 if {[llength $values] > [llength $allows]} {
185 bad-command "too many values"
188 while {[llength $values] < [llength $allows]} {
191 foreach val $values allow $allows {
192 if {[lsearch -exact $allow $val]<0} {
193 bad-command "$val not in allowed $allow ($allows)"
197 uplevel 1 [list upvar #0 client_async/$cmd ca]
198 upvar #0 client_async/$cmd ca
200 uplevel 1 $ubody_init
202 foreach uc [array names clients] {
203 uplevel 1 $ubody_perclient
205 uplevel 1 $ubody_finish
207 bad-command "unknown async control syntax"
211 proc set-client-echo {c yn} {
213 set client_echo($c) 0
214 client-command-complete $c OK
217 proc process-client-command {c nl} {
219 {^AT\+CREG\b} { async-control-max0 $c $l {{0 1 2}} }
220 {^AT\+CGREG\b} { async-control-max0 $c $l {{0 1 2}} }
221 {^AT\*ERINFO\b} { async-control-max0 $c $l {{0 1}} }
222 {^AT\+CGEREP\b} { async-control-max0 $c $l {{0 1 2} 0} }
223 {^AT\+CMER\b} { async-control-cmer $c $l {{0 3} 0 0 {0 1} 0} }
224 {^ATE0$} { set-client-echo $c 0 }
225 {^ATE1$} { set-client-echo $c 1 }
228 proc dchan-line {l} {
231 {\+CREG:} { async-notif-creg +CREG $l }
232 {\+CGREG:} { async-notif-creg +CGREG $l }
233 {\*ERINFO:} { async-notif-or-resp-fixed *ERINFO $l }
234 {\+CGEV:} { async-notif +CGEREP $l }
236 {\+CIEV:} { async-notif +CIEV $l }
239 if {[info exists cclient