Skip to content

Commit

Permalink
Converted keyer-control to the Tcl version, started the keyer_decode …
Browse files Browse the repository at this point in the history
…replacement in Tcl.
  • Loading branch information
recri committed Jan 4, 2012
1 parent 0610ea3 commit be2694d
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 482 deletions.
108 changes: 51 additions & 57 deletions bin/keyer-control
Expand Up @@ -4,20 +4,23 @@
lappend auto_path [file join [file dirname [info script]] .. lib] lappend auto_path [file join [file dirname [info script]] .. lib]


package require Tk package require Tk
package require keyer
package require sdrkit


## ##
## parameters and operating data ## parameters and operating data
## ##
array set data { array set data {
ascii 1 ascii 1
iambic 1 iambic 1



#ascii_tone-verbose 5
ascii_tone-freq 700 ascii_tone-freq 700
ascii_tone-gain -30 ascii_tone-gain -30
ascii_tone-rise 5 ascii_tone-rise 5
ascii_tone-fall 5 ascii_tone-fall 5


#ascii-verbose 5
ascii-wpm 15 ascii-wpm 15
ascii-word 50 ascii-word 50
ascii-dah 3 ascii-dah 3
Expand All @@ -28,11 +31,13 @@ array set data {
ascii-chan 1 ascii-chan 1
ascii-note 0 ascii-note 0


#iambic_tone-verbose 5
iambic_tone-freq 750 iambic_tone-freq 750
iambic_tone-gain -30 iambic_tone-gain -30
iambic_tone-rise 5 iambic_tone-rise 5
iambic_tone-fall 5 iambic_tone-fall 5


iambic-verbose 5
iambic-wpm 15 iambic-wpm 15
iambic-word 50 iambic-word 50
iambic-dah 3 iambic-dah 3
Expand All @@ -53,44 +58,32 @@ array set data {
## ##
proc plug-exists {client} { proc plug-exists {client} {
global plug global plug
return [info exists plug($client-fp)] return [info exists plug($client)]
} }


proc plug-open {program client {server default}} { proc plug-open {command client {server default}} {
global plug global plug
global data global data
set bindir [file dirname [info script]] set args {}
set plug($client-binary) [file join $bindir $program]
# test for file exists
set plug($client-out-file) "/tmp/keyer-control-[pid]-$client.out"
set args [list |$plug($client-binary) --server $server --client $client]
foreach name [array names data $client-*] { foreach name [array names data $client-*] {
set val $data($name) set val $data($name)
set name [string range $name [expr {1+[string length $client]}] end] set name [string range $name [expr {1+[string length $client]}] end]
lappend args "--$name" $val lappend args "-$name" $val
} }
lappend args {>&} $plug($client-out-file) eval [concat [list $command $client -server $server] $args]
set command [join $args] set plug($client) $client
set plug($client-fp) [open $command w]
fconfigure $plug($client-fp) -buffering line
set plug($client-out-fp) [open "$plug($client-out-file)" r]
fconfigure $plug($client-out-fp) -blocking 0 -buffering line
# fileevent $plug($client-out-fp) readable "plug-readable $client"
lappend plug(clients) $client lappend plug(clients) $client
} }


proc plug-close {client} { proc plug-close {client} {
global plug global plug
if {[plug-exists $client]} { if {[plug-exists $client]} {
#puts stderr "plug-close $client"
close $plug($client-fp)
close $plug($client-out-fp)
file delete $plug($client-out-file)
foreach name [array names plug $client-*] { foreach name [array names plug $client-*] {
unset plug($name) unset plug($name)
} }
set i [lsearch -exact $plug(clients) $client] set i [lsearch -exact $plug(clients) $client]
set plug(clients) [lreplace $plug(clients) $i $i] set plug(clients) [lreplace $plug(clients) $i $i]
rename $plug(client) {}
} else { } else {
puts stderr "non-existent client $client in plug-close" puts stderr "non-existent client $client in plug-close"
} }
Expand All @@ -106,7 +99,9 @@ proc plug-close-all {} {
proc plug-puts {client opt value} { proc plug-puts {client opt value} {
global plug global plug
if {[plug-exists $client]} { if {[plug-exists $client]} {
puts $plug($client-fp) "<$opt$value>" #puts "$plug($client) config -$opt $value"
$plug($client) config -$opt $value
#puts "$plug($client) cget -$opt -> [$plug($client) cget -$opt]"
} else { } else {
puts stderr "non-existent client $client in plug-puts" puts stderr "non-existent client $client in plug-puts"
} }
Expand All @@ -115,28 +110,15 @@ proc plug-puts {client opt value} {
proc plug-puts-text {client text} { proc plug-puts-text {client text} {
global plug global plug
if {[plug-exists $client]} { if {[plug-exists $client]} {
puts $plug($client-fp) $text $plug($client) puts $text
} else { } else {
puts stderr "non-existent client $client in plug-puts-text" puts stderr "non-existent client $client in plug-puts-text"
} }
} }


proc plug-readable {client} {
global plug
# puts "plug-readable $client"
if {[gets $plug($client-out-fp) line] < 0} {
if {[eof $plug($client-out-fp)]} {
# don't close, they're files that will grow
# plug-close $client
}
return;
}
lappend plug($client-input) $line
}

proc plug-read {client} { proc plug-read {client} {
global plug global plug
return [read $plug($client-out-fp)] return [$plug($client) gets]
} }


# #
Expand All @@ -146,45 +128,56 @@ proc plug-init {} {
global data global data
# start jack # start jack
# look for zombie helpers? # look for zombie helpers?
foreach line [split [string trim [exec jack_lsp]] \n] { set ports [sdrkit::jack list-ports]
switch -glob $line { foreach port [dict keys $ports] {
ascii:* - foreach conn [dict get $ports $port connections] {
iambic:* - switch -glob $line {
ascii_tone:* - ascii:* -
iambic_tone:* { iambic:* -
error "the [lindex [split $line :] 0] client is still running" ascii_tone:* -
iambic_tone:* {
error "the [lindex [split $line :] 0] client is still running"
}
}
}
switch -glob $port {
system:midi_capture_* {
set midi_capture $port
} }
} }
} }
# make helpers # make helpers
set connects {} set connects {}
if {$data(ascii)} { if {$data(ascii)} {
plug-open keyer_ascii ascii plug-open keyer::ascii ascii
plug-open keyer_tone ascii_tone plug-open keyer::tone ascii_tone
lappend connects {jack_connect ascii:midi_out ascii_tone:midi_in} lappend connects {sdrkit::jack connect ascii:midi_out ascii_tone:midi_in}
lappend connects {jack_connect ascii_tone:out_i system:playback_1} lappend connects {sdrkit::jack connect ascii_tone:out_i system:playback_1}
lappend connects {jack_connect ascii_tone:out_q system:playback_2} lappend connects {sdrkit::jack connect ascii_tone:out_q system:playback_2}
} }
if {$data(iambic)} { if {$data(iambic)} {
plug-open keyer_iambic iambic if { ! [info exists midi_capture]} {
# plug-open keyer_iambic2 iambic error "no midi_capture port for keyer connection"
plug-open keyer_tone iambic_tone }
lappend connects {jack_connect system:midi_capture_1 iambic:midi_in} # plug-open keyer::iambic iambic
lappend connects {jack_connect iambic:midi_out iambic_tone:midi_in} plug-open keyer::iambic iambic
lappend connects {jack_connect iambic_tone:out_i system:playback_1} plug-open keyer::tone iambic_tone
lappend connects {jack_connect iambic_tone:out_q system:playback_2} lappend connects [list sdrkit::jack connect $midi_capture iambic:midi_in]
lappend connects {sdrkit::jack connect iambic:midi_out iambic_tone:midi_in}
lappend connects {sdrkit::jack connect iambic_tone:out_i system:playback_1}
lappend connects {sdrkit::jack connect iambic_tone:out_q system:playback_2}
} }
# these names may need to change around # these names may need to change around
after 500 after 500
set retry {} set retry {}
foreach cmd $connects { foreach cmd $connects {
if {[catch "exec $cmd" error]} { if {[catch "eval $cmd" error]} {
puts "$cmd: yielded $error" puts "$cmd: yielded $error"
lappend retry $cmd lappend retry $cmd
} }
} }
foreach cmd $retry { foreach cmd $retry {
if {[catch "exec $cmd" error]} { if {[catch "eval $cmd" error]} {
puts "$cmd: failed again, yielded $error" puts "$cmd: failed again, yielded $error"
} }
} }
Expand Down Expand Up @@ -388,6 +381,7 @@ proc main {argv} {
--ascii-freq { set data(ascii_tone-freq) $value } --ascii-freq { set data(ascii_tone-freq) $value }
--ascii-gain { set data(ascii_tone-gain) $value } --ascii-gain { set data(ascii_tone-gain) $value }
--iambic { set data(iambic) $value } --iambic { set data(iambic) $value }
--iambicpp { set data(iambicpp) $value }
--iambic-wpm { set data(iambic-wpm) $value } --iambic-wpm { set data(iambic-wpm) $value }
--iambic-freq { set data(iambic_tone-freq) $value } --iambic-freq { set data(iambic_tone-freq) $value }
--iambic-gain { set data(iambic_tone-gain) $value } --iambic-gain { set data(iambic_tone-gain) $value }
Expand Down
37 changes: 37 additions & 0 deletions bin/keyer_decode2
@@ -0,0 +1,37 @@
#!/usr/bin/tclsh
# -*- mode: Tcl; tab-width: 8; -*-

lappend auto_path [file join [file dirname [info script]] .. lib]

package require keyer

array set data {
-server default
-client decode
-chan 1
-note 0
}

foreach {option value} $argv {
switch -- $option {
--server -
--client -
--chan -
--note {
set data([string range $option 1 end]) $value
}
default {
error "unrecognized option: $option"
}
}
}

keyer::decode decode {*}[array get data]

fconfigure stdout -buffering none
while {1} {
set line [decode gets]
if {[string length $line]} {
puts -nonewline $line
}
}
Binary file added images/keyer-7.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/keyer-8.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 7 additions & 15 deletions keyers/Makefile
Expand Up @@ -11,8 +11,8 @@ LIBUSB_LIBS=$(shell pkg-config --libs libusb-1.0)


LIBDIR=../lib/keyers LIBDIR=../lib/keyers


ALL=../bin/keyer_tone ../bin/keyer_ascii ../bin/keyer_iambic ../bin/keyer_decode ../bin/keyer_iambicpp ALL=../bin/keyer_tone ../bin/keyer_ascii ../bin/keyer_iambic ../bin/keyer_decode
ALL2=$(LIBDIR)/keyer_tone.so $(LIBDIR)/keyer_ascii.so $(LIBDIR)/keyer_iambic.so $(LIBDIR)/keyer_decode.so $(LIBDIR)/keyer_iambicpp.so ALL2=$(LIBDIR)/keyer_tone.so $(LIBDIR)/keyer_ascii.so $(LIBDIR)/keyer_iambic.so $(LIBDIR)/keyer_decode.so


all:: $(ALL) $(ALL2) all:: $(ALL) $(ALL2)
cd $(LIBDIR) && make all cd $(LIBDIR) && make all
Expand All @@ -35,31 +35,23 @@ clean::
mkdir -p ../bin mkdir -p ../bin
cc -o ../bin/keyer_ascii $(CFLAGS) -DAS_BIN keyer_ascii.c $(JACK_LIBS) -lm cc -o ../bin/keyer_ascii $(CFLAGS) -DAS_BIN keyer_ascii.c $(JACK_LIBS) -lm


../bin/keyer_iambic: keyer_iambic.c framework.h options.h timing.h midi.h ../bin/keyer_iambic: keyer_iambic.cc framework.h options.h timing.h midi.h
mkdir -p ../bin mkdir -p ../bin
cc -o ../bin/keyer_iambic $(CFLAGS) -DAS_BIN keyer_iambic.c $(JACK_LIBS) -lm g++ -o ../bin/keyer_iambic $(CPPFLAGS) -DAS_BIN keyer_iambic.cc $(JACK_LIBS) -lm

../bin/keyer_iambicpp: keyer_iambicpp.cc Iambic.hh framework.h options.h timing.h midi.h
mkdir -p ../bin
g++ -o ../bin/keyer_iambicpp $(CPPFLAGS) -DAS_BIN keyer_iambicpp.cc $(JACK_LIBS) -lm


$(LIBDIR)/keyer_tone.so: keyer_tone.c framework.h options.h timing.h $(LIBDIR)/keyer_tone.so: keyer_tone.c framework.h options.h timing.h
mkdir -p $(LIBDIR) mkdir -p $(LIBDIR)
cc -o $(LIBDIR)/keyer_tone.so -shared -fPIC -DAS_TCL $(CFLAGS) keyer_tone.c $(JACK_LIBS) $(LIBS) -lm cc -o $(LIBDIR)/keyer_tone.so -shared -fPIC -DAS_TCL $(CFLAGS) keyer_tone.c $(JACK_LIBS) $(LIBS) -lm


$(LIBDIR)/keyer_decode.so: keyer_decode.c framework.h options.h $(LIBDIR)/keyer_decode.so: keyer_decode.c framework.h options.h ring_buffer.h
mkdir -p $(LIBDIR) mkdir -p $(LIBDIR)
cc -o $(LIBDIR)/keyer_decode.so $(CFLAGS) -shared -fPIC -DAS_TCL keyer_decode.c $(JACK_LIBS) $(LIBS) -lm cc -o $(LIBDIR)/keyer_decode.so $(CFLAGS) -shared -fPIC -DAS_TCL keyer_decode.c $(JACK_LIBS) $(LIBS) -lm


$(LIBDIR)/keyer_ascii.so: keyer_ascii.c framework.h options.h timing.h midi.h $(LIBDIR)/keyer_ascii.so: keyer_ascii.c framework.h options.h timing.h midi.h
mkdir -p $(LIBDIR) mkdir -p $(LIBDIR)
cc -o $(LIBDIR)/keyer_ascii.so $(CFLAGS) -shared -fPIC -DAS_TCL keyer_ascii.c $(JACK_LIBS) $(LIBS) -lm cc -o $(LIBDIR)/keyer_ascii.so $(CFLAGS) -shared -fPIC -DAS_TCL keyer_ascii.c $(JACK_LIBS) $(LIBS) -lm


$(LIBDIR)/keyer_iambic.so: keyer_iambic.c framework.h options.h timing.h midi.h $(LIBDIR)/keyer_iambic.so: keyer_iambic.cc framework.h options.h timing.h midi.h
mkdir -p $(LIBDIR)
cc -o $(LIBDIR)/keyer_iambic.so $(CFLAGS) -shared -fPIC -DAS_TCL keyer_iambic.c $(JACK_LIBS) $(LIBS) -lm

$(LIBDIR)/keyer_iambicpp.so: keyer_iambicpp.cc Iambic.hh framework.h options.h timing.h midi.h
mkdir -p $(LIBDIR) mkdir -p $(LIBDIR)
g++ -o $(LIBDIR)/keyer_iambicpp.so $(CPPFLAGS) -shared -fPIC -DAS_TCL keyer_iambicpp.cc $(JACK_LIBS) $(LIBS) -lm g++ -o $(LIBDIR)/keyer_iambic.so $(CPPFLAGS) -shared -fPIC -DAS_TCL keyer_iambic.cc $(JACK_LIBS) $(LIBS) -lm


21 changes: 19 additions & 2 deletions keyers/keyer_decode.c
Expand Up @@ -23,6 +23,7 @@
#include "framework.h" #include "framework.h"
#include "options.h" #include "options.h"
#include "midi.h" #include "midi.h"
#include "ring_buffer.h"


typedef struct { typedef struct {
unsigned last_frame; /* frame of last event */ unsigned last_frame; /* frame of last event */
Expand All @@ -38,7 +39,10 @@ typedef struct {
framework_t fw; framework_t fw;
decode_t decode; decode_t decode;
unsigned frame; unsigned frame;
/* Tcl needs a ring buffer to store decoded elements */ #define _SIZE 512
unsigned rptr;
unsigned wptr;
char buff[_SIZE];
} _t; } _t;


/* /*
Expand Down Expand Up @@ -128,7 +132,12 @@ static void _decode(_t *dp, unsigned count, unsigned char *p) {
fprintf(stdout, "%s", out); fflush(stdout); fprintf(stdout, "%s", out); fflush(stdout);
#endif #endif
#if AS_TCL #if AS_TCL

if (buffer_writeable(dp->wptr, dp->rptr, _SIZE)) {
if (*out != 0)
dp->buff[buffer_index(dp->wptr++, _SIZE)] = *out;
} else {
fprintf(stderr, "keyer_decode: buffer overflow writing \"%s\"\n", out);
}
#endif #endif
} else if (dp->fw.opts.verbose > 3) } else if (dp->fw.opts.verbose > 3)
fprintf(stderr, "discarded midi chan=0x%x note=0x%x != mychan=0x%x mynote=0x%x\n", channel, note, dp->fw.opts.chan, dp->fw.opts.note); fprintf(stderr, "discarded midi chan=0x%x note=0x%x != mychan=0x%x mynote=0x%x\n", channel, note, dp->fw.opts.chan, dp->fw.opts.note);
Expand Down Expand Up @@ -193,6 +202,14 @@ int main(int narg, char **args) {
static int _command(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj* const *objv) { static int _command(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj* const *objv) {
if (argc == 2 && strcmp(Tcl_GetString(objv[1]), "gets") == 0) { if (argc == 2 && strcmp(Tcl_GetString(objv[1]), "gets") == 0) {
// return the current decoded string // return the current decoded string
_t *dp = (_t *)clientData;
unsigned n = buffer_items_available_to_read(dp->wptr, dp->rptr, _SIZE);
char buff[512];
if (n > 512)
n = 512;
for (int i = 0; i < n; i += 1)
buff[i] = dp->buff[buffer_index(dp->rptr++, _SIZE)];
Tcl_SetObjResult(interp, Tcl_NewStringObj(buff, n));
return TCL_OK; return TCL_OK;
} }
if (framework_command(clientData, interp, argc, objv) != TCL_OK) if (framework_command(clientData, interp, argc, objv) != TCL_OK)
Expand Down

0 comments on commit be2694d

Please sign in to comment.