]> git.rkrishnan.org Git - pihpsdr.git/commitdiff
Changes related to CW, and corrections throughout
authorc vw <dl1ycf@darc.de>
Thu, 18 Oct 2018 15:56:51 +0000 (17:56 +0200)
committerc vw <dl1ycf@darc.de>
Thu, 18 Oct 2018 15:56:51 +0000 (17:56 +0200)
configure.c
cw_menu.c
ext.c
gpio.c
gpio.h
iambic.c
property.c
radio.c
radio.h
rigctl.c

index dc512c48b6049e1522c9b1de9c8ddec8a77c6547..f8fbd93636eca092689cd40704d47ba5803d3343 100644 (file)
@@ -103,6 +103,7 @@ static GtkWidget *cws_label;
 static GtkWidget *cws;
 static GtkWidget *b_enable_cws;
 static GtkWidget *b_enable_cwlr;
+static GtkWidget *b_cw_active_low;
 #endif
 
 static gboolean save_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
@@ -152,6 +153,7 @@ static gboolean save_cb (GtkWidget *widget, GdkEventButton *event, gpointer data
     FUNCTION_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(function));
 #ifdef LOCALCW
     ENABLE_CW_BUTTONS=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_cwlr))?1:0;
+    CW_ACTIVE_LOW=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_cw_active_low))?1:0;
     CWL_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(cwl));
     CWR_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(cwr));
     ENABLE_GPIO_SIDETONE=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_cws))?1:0;
@@ -350,7 +352,7 @@ void configure_gpio(GtkWidget *parent) {
   gtk_widget_show(cwl);
   gtk_grid_attach(GTK_GRID(grid),cwl,4,y,1,1);
 
-  b_enable_cwlr=gtk_check_button_new_with_label("Enable CW buttons");
+  b_enable_cwlr=gtk_check_button_new_with_label("CWLR Enable");
   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_cwlr), ENABLE_CW_BUTTONS);
   gtk_widget_show(b_enable_cwlr);
   gtk_grid_attach(GTK_GRID(grid),b_enable_cwlr,5,y,1,1);
@@ -381,6 +383,11 @@ void configure_gpio(GtkWidget *parent) {
   gtk_spin_button_set_value (GTK_SPIN_BUTTON(cwr),CWR_BUTTON);
   gtk_widget_show(cwr);
   gtk_grid_attach(GTK_GRID(grid),cwr,4,y,1,1);
+
+  b_cw_active_low=gtk_check_button_new_with_label("CWLR active-low");
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_cw_active_low), CW_ACTIVE_LOW);
+  gtk_widget_show(b_cw_active_low);
+  gtk_grid_attach(GTK_GRID(grid),b_cw_active_low,5,y,1,1);
 #endif
 
   y++;
@@ -490,56 +497,9 @@ void configure_gpio(GtkWidget *parent) {
 
   gtk_container_add(GTK_CONTAINER(content),grid);
 
-/*
-  GtkWidget *close_button=gtk_dialog_add_button(GTK_DIALOG(dialog),"Save",GTK_RESPONSE_OK);
-  //gtk_widget_override_font(close_button, pango_font_description_from_string("Arial 20"));
-*/
   gtk_widget_show_all(dialog);
   int result=gtk_dialog_run(GTK_DIALOG(dialog));
 
-/*
-  ENABLE_VFO_ENCODER=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_vfo_encoder))?1:0;
-  VFO_ENCODER_A=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(vfo_a));
-  VFO_ENCODER_B=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(vfo_b));
-  ENABLE_VFO_PULLUP=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_vfo_pullup))?1:0;
-  ENABLE_E1_ENCODER=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_E1_encoder))?1:0;
-  E1_ENCODER_A=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E1_a));
-  E1_ENCODER_B=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E1_b));
-  ENABLE_E1_PULLUP=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_E1_pullup))?1:0;
-  ENABLE_E2_ENCODER=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_E2_encoder))?1:0;
-  E2_ENCODER_A=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E2_a));
-  E2_ENCODER_B=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E2_b));
-  ENABLE_E2_PULLUP=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_E2_pullup))?1:0;
-  ENABLE_E3_ENCODER=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_S6_encoder))?1:0;
-  E3_ENCODER_A=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(S6_a));
-  E3_ENCODER_B=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(S6_b));
-  ENABLE_E3_PULLUP=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_S6_pullup))?1:0;
-  ENABLE_S1_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_S1))?1:0;
-  S1_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(S1));
-  ENABLE_S2_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_S2))?1:0;
-  S2_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(S2));
-  ENABLE_S3_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_S3))?1:0;
-  S3_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(S3));
-  ENABLE_S4_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_S4))?1:0;
-  S4_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(S4));
-  ENABLE_S5_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_S5))?1:0;
-  S5_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(S5));
-  ENABLE_S6_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_S6))?1:0;
-  S6_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(S6));
-  ENABLE_MOX_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_mox))?1:0;
-  MOX_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(mox));
-  ENABLE_FUNCTION_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_function))?1:0;
-  FUNCTION_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(function));
-#ifdef LOCALCW
-  CWL_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(cwl));
-  CWR_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(cwr));
-#endif
-*/
-
-  gtk_widget_destroy(dialog);
-
-//  gpio_save_state();
-
 }
 #endif
 
index c2a57387313fc9ca6be8512177d85381d654b1b3..0b43f0aa72dd54c91a348ffc7ee1db0e4ac96d99 100644 (file)
--- a/cw_menu.c
+++ b/cw_menu.c
@@ -63,11 +63,6 @@ static void cw_keyer_internal_cb(GtkWidget *widget, gpointer data) {
   cw_changed();
 }
 
-static void cw_active_level_cb(GtkWidget *widget, gpointer data) {
-  cw_active_level=cw_active_level==1?0:1;
-  cw_changed();
-}
-
 static void cw_keyer_speed_value_changed_cb(GtkWidget *widget, gpointer data) {
   cw_keyer_speed=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
   cw_changed();
@@ -245,13 +240,6 @@ void cw_menu(GtkWidget *parent) {
   gtk_widget_show(cw_keyer_internal_b);
   gtk_grid_attach(GTK_GRID(grid),cw_keyer_internal_b,0,10,1,1);
   g_signal_connect(cw_keyer_internal_b,"toggled",G_CALLBACK(cw_keyer_internal_cb),NULL);
-
-  GtkWidget *cw_active_level_b=gtk_check_button_new_with_label("CW Local Active_Low");
-  //gtk_widget_override_font(cw_active_level_b, pango_font_description_from_string("Arial 18"));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cw_active_level_b), cw_active_level==0);
-  gtk_widget_show(cw_active_level_b);
-  gtk_grid_attach(GTK_GRID(grid),cw_active_level_b,1,10,1,1);
-  g_signal_connect(cw_active_level_b,"toggled",G_CALLBACK(cw_active_level_cb),NULL);
 #endif
 
   gtk_container_add(GTK_CONTAINER(content),grid);
diff --git a/ext.c b/ext.c
index d49947a89c6cf28eead43d62245a9eefa465f457..6550d12a6e6cc23090d7874986cef445c704aaa0 100644 (file)
--- a/ext.c
+++ b/ext.c
 
 // The following calls functions can be called usig g_idle_add
 
-// DL1YCF: added interface for mode change, to be used by rigctl
-//         (MD command)
 int ext_vfo_mode_changed(void * data)
 {
-  vfo_mode_changed((int) (long) data);
+  int mode=(uintptr_t) data;
+  vfo_mode_changed(mode);
   return 0;
 }
 
@@ -52,9 +51,6 @@ int ext_discovery(void *data) {
 int ext_set_frequency(void *data) {
   setFrequency(*(long long *)data);
   free(data);
-  // DL1YCF added return statement
-  // this one is CRITICAL to avoid free() being called 
-  // repeatedly on the same pointer
   return 0;
 }
 
@@ -141,20 +137,6 @@ int ext_radio_change_sample_rate(void *data) {
   return 0;
 }
 
-// DL1YCF: because of the new CW algorithm,
-//         this function is no longer used
-int ext_cw_setup() {
-  radio_cw_setup();
-  return 0;
-}
-
-// DL1YCF: because of the new CW algorithm,
-//         this function is no longer used
-int ext_cw_key(void *data) {
-  radio_cw_key((uintptr_t)data);
-  return 0;
-}
-
 int ext_update_squelch(void *data) {
   set_squelch(active_receiver);
   return 0;
@@ -167,7 +149,8 @@ int ext_sliders_update(void *data) {
 
 #ifdef PURESIGNAL
 int ext_tx_set_ps(void *data) {
-  tx_set_ps(transmitter,(uintptr_t)data);
+  int state=(uintptr_t) data;
+  tx_set_ps(transmitter, state);
   return 0;
 }
 #endif
diff --git a/gpio.c b/gpio.c
index 422a4a9ee6a7e3d658b62a94f2bf953f0999f21b..5828b8ff830ee475174f990d5a6494dbc1745144 100644 (file)
--- a/gpio.c
+++ b/gpio.c
@@ -155,6 +155,7 @@ int CWR_BUTTON=15;
 int SIDETONE_GPIO=8;
 int ENABLE_GPIO_SIDETONE=0;
 int ENABLE_CW_BUTTONS=1;
+int CW_ACTIVE_LOW=1;
 #endif
 
 static volatile int vfoEncoderPos;
@@ -850,6 +851,8 @@ void gpio_restore_state() {
 #ifdef LOCALCW         
  value=getProperty("ENABLE_CW_BUTTONS");               
  if(value) ENABLE_CW_BUTTONS=atoi(value);              
+ value=getProperty("CW_ACTIVE_LOW");           
+ if(value) CW_ACTIVE_LOW=atoi(value);          
  value=getProperty("CWL_BUTTON");              
  if(value) CWL_BUTTON=atoi(value);             
  value=getProperty("CWR_BUTTON");              
@@ -956,6 +959,8 @@ void gpio_save_state() {
 #ifdef LOCALCW         
  sprintf(value,"%d",ENABLE_CW_BUTTONS);                
  setProperty("ENABLE_CW_BUTTONS",value);               
+ sprintf(value,"%d",CW_ACTIVE_LOW);            
+ setProperty("CW_ACTIVE_LOW",value);           
  sprintf(value,"%d",CWL_BUTTON);               
  setProperty("CWL_BUTTON",value);              
  sprintf(value,"%d",CWR_BUTTON);               
@@ -988,12 +993,9 @@ fprintf(stderr,"setup_encoder_pin: pin=%d updown=%d\n",pin,up_down);
 
 #ifdef LOCALCW
 
-// Note we cannot use debouncing, as after the first interrupt,
-// we might read the wrong level. So we process all interrupts
-// to the keyer.
-// The only way to do proper debouncing is to record the wall-clock time
-// of the last state change of each of the two buttons, and
-// disable further state changes for a short time (5 msec)
+//
+// We generate interrupts only on falling edge
+//
 
 static void setup_cw_pin(int pin, void(*pAlert)(void)) {
    fprintf(stderr,"setup_cw_pin: pin=%d \n",pin);
@@ -1008,7 +1010,8 @@ static void cwAlert_left() {
     if (cw_keyer_internal != 0) return; // as quickly as possible
     level=digitalRead(CWL_BUTTON);
     //fprintf(stderr,"cwl button : level=%d \n",level);
-    keyer_event(CWL_BUTTON, cw_active_level == 0 ? level : (level==0));
+    //the second parameter of keyer_event ("state") is TRUE on key-down
+    keyer_event(CWL_BUTTON, CW_ACTIVE_LOW ? (level==0) : level);
 }
 
 static void cwAlert_right() {
@@ -1016,9 +1019,21 @@ static void cwAlert_right() {
     if (cw_keyer_internal != 0) return; // as quickly as possible
     level=digitalRead(CWR_BUTTON);
     //fprintf(stderr,"cwr button : level=%d \n",level);
-     keyer_event(CWR_BUTTON, cw_active_level == 0 ? level : (level==0));
+     keyer_event(CWR_BUTTON, CW_ACTIVE_LOW ? (level==0) : level);
 }
 
+//
+// Two functions added, might be useful somewhere
+//
+int gpio_left_cw_key() {
+  int val=digitalRead(CWL_BUTTON);
+  return CW_ACTIVE_LOW? (val==0) : val;
+}
+
+int gpio_right_cw_key() {
+  int val=digitalRead(CWR_BUTTON);
+  return CW_ACTIVE_LOW? (val==0) : val;
+}
 #endif
 
 int gpio_init() {
diff --git a/gpio.h b/gpio.h
index 9563bb65a4dd23b79885bc51e936c6a4f4b01ef1..1075d5d35adb23ff4ca3abc000f6bf250fa2c8df 100644 (file)
--- a/gpio.h
+++ b/gpio.h
@@ -86,7 +86,10 @@ extern int CWR_BUTTON;
 extern int SIDETONE_GPIO;
 extern int ENABLE_GPIO_SIDETONE;
 extern int ENABLE_CW_BUTTONS;
+extern int CW_ACTIVE_LOW;
 void gpio_sidetone(int freq);
+int  gpio_left_cw_key();
+int  gpio_right_cw_key();
 #endif
 
 void gpio_restore_state();
index f36f594194d81f58fad138546350975464375fe5..83868497bc205f6103642c06b263a30e406e595c 100644 (file)
--- a/iambic.c
+++ b/iambic.c
@@ -154,9 +154,7 @@ void keyer_update() {
 }
 
 #ifdef GPIO
-void keyer_event(int gpio, int level) {
-    int state = (level == 0);
-
+void keyer_event(int gpio, int state) {
     if (state) {
         // This is for aborting CAT CW messages if the key is hit.
        cw_key_hit = 1;
@@ -164,7 +162,7 @@ void keyer_event(int gpio, int level) {
        // PTT has been engaged manually
         if (running && !cwvox && !mox) {
           g_idle_add(ext_mox_update, (gpointer)(long) 1);
-           cwvox=(int) vox_hang;
+           cwvox=(int) cw_breakin;
        }
     }
     if (gpio == CWL_BUTTON)
@@ -224,7 +222,7 @@ fprintf(stderr,"keyer_thread  state running= %d\n", running);
        // If MOX still hanging, continue spinnning/checking and decrement cwvox
 
         while (key_state != EXITLOOP || cwvox > 0) {
-          if (cwvox > 0 && key_state != EXITLOOP && key_state != CHECK) cwvox=(int) vox_hang;
+          if (cwvox > 0 && key_state != EXITLOOP && key_state != CHECK) cwvox=(int) cw_breakin;
          switch (key_state) {
            case EXITLOOP:
                if (cwvox >0) cwvox--;
index 110a60029ca43250dc3996192841cbb896158e3a..e6bc40d88a7fc37617e6782971a52bd6f0fe2553 100644 (file)
@@ -79,6 +79,9 @@ void saveProperties(char* filename) {
     FILE* f=fopen(filename,"w+");
     char line[512];
     char version[32];
+
+    fprintf(stderr,"saveProperties: %s\n",filename);
+
     if(!f) {
         fprintf(stderr,"can't open %s\n",filename);
         return;
diff --git a/radio.c b/radio.c
index 3bf10ec5aaa3121211d3592df2e883add2e331a8..c9bb32c00fcafcf0d8f40877951539f165a4f4ba 100644 (file)
--- a/radio.c
+++ b/radio.c
@@ -217,7 +217,6 @@ int cw_keyer_ptt_delay=20; // 0-255ms
 int cw_keyer_hang_time=300; // ms
 int cw_keyer_sidetone_frequency=400; // Hz
 int cw_breakin=1; // 0=disabled 1=enabled
-int cw_active_level=1; // 0=active_low 1=active_high
 
 int vfo_encoder_divisor=15;
 
@@ -1170,8 +1169,6 @@ fprintf(stderr,"radioRestoreState: %s\n",property_path);
     value=getProperty("cw_keyer_internal");
     if(value) cw_keyer_internal=atoi(value);
 #endif
-    value=getProperty("cw_active_level");
-    if(value) cw_active_level=atoi(value);
     value=getProperty("cw_keyer_sidetone_volume");
     if(value) cw_keyer_sidetone_volume=atoi(value);
     value=getProperty("cw_keyer_ptt_delay");
@@ -1373,8 +1370,6 @@ void radioSaveState() {
     setProperty("cw_keyer_spacing",value);
     sprintf(value,"%d",cw_keyer_internal);
     setProperty("cw_keyer_internal",value);
-    sprintf(value,"%d",cw_active_level);
-    setProperty("cw_active_level",value);
     sprintf(value,"%d",cw_keyer_sidetone_volume);
     setProperty("cw_keyer_sidetone_volume",value);
     sprintf(value,"%d",cw_keyer_ptt_delay);
diff --git a/radio.h b/radio.h
index 94215346d869d3f1664d769aa1addf68abaca558..943ed24e6008bcfc80c68abac92456e86a4ebf7d 100644 (file)
--- a/radio.h
+++ b/radio.h
@@ -171,7 +171,6 @@ extern int cw_keyer_ptt_delay;
 extern int cw_keyer_hang_time;
 extern int cw_keyer_sidetone_frequency;
 extern int cw_breakin;
-extern int cw_active_level;
 
 extern int vfo_encoder_divisor;
 
index 268c9928256b00e3508f06c0bf136488104c491d..b285bcb1bc83158b876c0d809aa2618df7e05711 100644 (file)
--- a/rigctl.c
+++ b/rigctl.c
@@ -361,7 +361,6 @@ void send_space(int len) {
 
 void rigctl_send_cw_char(char cw_char) {
     char pattern[9],*ptr;
-    static char last_cw_char=0;
     strcpy(pattern,"");
     ptr = &pattern[0];
     switch (cw_char) {
@@ -427,19 +426,31 @@ void rigctl_send_cw_char(char cw_char) {
        case '7': strcpy(pattern,"--...");break;
        case '8': strcpy(pattern,"---..");break;
        case '9': strcpy(pattern,"----.");break;
-       case '.': strcpy(pattern,".-.-.-");break;
-       case '/': strcpy(pattern,"-..-.");break;
-       case ',': strcpy(pattern,"--..--");break;
-       case '!': strcpy(pattern,"-.-.--");break;
-       case ')': strcpy(pattern,"-.--.-");break;
-       case '(': strcpy(pattern,"-.--.-");break;
+//
+//     DL1YCF:
+//     There were some signs I considered wrong, other
+//     signs missing. Therefore I put the signs here
+//     from ITU Recommendation M.1677-1 (2009)
+//     in the order given there.
+//
+       case '.':  strcpy(pattern,".-.-.-"); break;
+       case ',':  strcpy(pattern,"--..--"); break;
+       case ':':  strcpy(pattern,"---..");  break;
+       case '?':  strcpy(pattern,"..--.."); break;
+       case '\'': strcpy(pattern,".----."); break;
+       case '-':  strcpy(pattern,"-....-"); break;
+       case '/':  strcpy(pattern,"-..-.");  break;
+       case '(':  strcpy(pattern,"-.--.");  break;
+       case ')':  strcpy(pattern,"-.--.-"); break;
+       case '"':  strcpy(pattern,".-..-."); break;
+       case '=':  strcpy(pattern,"-...-");  break;
+       case '+':  strcpy(pattern,".-.-.");  break;
+       case '@':  strcpy(pattern,".--.-."); break;
+//
+//     Often used, but not ITU: Ampersand for "wait"
+//
        case '&': strcpy(pattern,".-...");break;
-       case ':': strcpy(pattern,"---..");break;
-       case '+': strcpy(pattern,".-.-.");break;
-       case '-': strcpy(pattern,"-....-");break;
-       case '_': strcpy(pattern,".--.-.");break;
-       case '@': strcpy(pattern,"..--.-");break;
-       default:  strcpy(pattern," ");
+       default:  strcpy(pattern,"");
     }
      
     while(*ptr != '\0') {
@@ -451,19 +462,20 @@ void rigctl_send_cw_char(char cw_char) {
        }
        ptr++;
     }
-    // The last character sent already has one dotlen included.
-    // Therefore, if the character was a "space", we need an additional
-    // inter-word  pause of 6 dotlen, else we need a inter-character
-    // pause of 2 dotlens.
-    // Note that two or more adjacent space characters result in a 
-    // single inter-word distance. This also gets rid of trailing
-    // spaces in the KY command.
+
+    // The last element (dash or dot) sent already has one dotlen space appended.
+    // If the current character is another "printable" sign, we need an additional
+    // pause of 2 dotlens to form the inter-character spacing of 3 dotlens.
+    // However if the current character is a "space" we must produce an inter-word
+    // spacing (7 dotlens) and therefore need 6 additional dotlens
+    // We need no longer take care of a sequence of spaces since adjacent spaces
+    // are now filtered out while filling the CW character (ring-) buffer.
+
     if (cw_char == ' ') {
-      if (last_cw_char != ' ') send_space(6);
+      send_space(6);  // produce inter-word space of 7 dotlens
     } else {
-      send_space(2);
+      send_space(2);  // produce inter-character space of 3 dotlens
     }
-    last_cw_char=cw_char;
 }
 
 //
@@ -476,23 +488,52 @@ void rigctl_send_cw_char(char cw_char) {
 // sending each word with a separate KY command
 // produces perfectly readable CW.
 //
+// UPDATE: we maintain a ring buffer such that
+//         the contents of several KY commands
+//         can be buffered
+//
 static gpointer rigctl_cw_thread(gpointer data)
 { 
   int i;
   char c;
-  char local_buf[30];
+  char last_char=0;
+  char ring_buf[130];
+  char *write_buf=ring_buf;
+  char *read_buf =ring_buf;
+  char *p;
+  int  num_buf=0;
   
   while (server_running) {
     // wait for cw_buf become filled with data
     // (periodically look every 100 msec)
-    cw_key_hit=0;
-    if (!cw_busy) {
+    if (!cw_busy && num_buf ==0) {
+      cw_key_hit=0;
       usleep(100000L);
       continue;
     }
-    strncpy(local_buf, cw_buf, 30);
-    cw_busy=0; // mark buffer free again
+
+    // if new data available and space in buffer, copy it
+    // If there are several adjacent spaces, take only the first one.
+    // This also swallows the "tails" of the KY commands which
+    // (according to Kenwood) have to be padded with spaces up
+    // to the maximum length (24)
+
+    if (cw_busy && num_buf < 100) {
+      p=cw_buf;
+      while ((c=*p++)) {
+        if (last_char == ' ' && c == ' ') continue;
+        *write_buf++ = c;
+        last_char=c;
+        num_buf++;
+        if (write_buf - ring_buf == 128) write_buf=ring_buf;  // wrap around
+      }
+      cw_busy=0; // mark buffer free again
+    }
+
     // these values may have changed, so recompute them here
+    // This means that we can change the speed (KS command) while
+    // the buffer is being sent
+
     dotlen = 1200000L/(long)cw_keyer_speed;
     dashlen = (dotlen * 3 * cw_keyer_weight) / 50L;
     dotsamples = 57600 / cw_keyer_speed;
@@ -506,7 +547,7 @@ static gpointer rigctl_cw_thread(gpointer data)
        // forever here, so allow at most 500 msec
        i=10;
         while (!mox && (i--) > 0) usleep(50000L);
-       // still no MOX? --> silently discard CW message and give up
+       // still no MOX? --> silently discard CW character and give up
        if (!mox) {
            CAT_cw_is_active=0;
            continue;
@@ -516,10 +557,6 @@ static gpointer rigctl_cw_thread(gpointer data)
         usleep(100000L);
     }
     // At this point, mox==1 and CAT_cw_active == 1
-    i=0;
-    while(((c=local_buf[i++]) != '\0') && !cw_key_hit && !cw_not_ready) {
-        rigctl_send_cw_char(c);
-    }
     if (cw_key_hit || cw_not_ready) {
        //
        // CW transmission has been aborted, either due to manually
@@ -535,19 +572,27 @@ static gpointer rigctl_cw_thread(gpointer data)
        // CAT CW commands. We need this long time since
        // hamlib waits 0.5 secs after receiving a "KY1" message before trying to
        // send the next bunch
-       for (i=0; i< 50; i++) {
-         cw_busy=0;      // mark buffer free
-         usleep(20000L);
-       }
+       cw_busy=-1;      // mark buffer purge situation
+       usleep(1000000L);
+       cw_busy=0;
+       write_buf=read_buf=ring_buf;
+       num_buf=0;
     } else {
+      rigctl_send_cw_char(*read_buf++);
+      if (read_buf - ring_buf == 128) read_buf=ring_buf; // wrap around
+      num_buf--;
       //
-      // CAT CW message has been sent.
-      // If the next message is pending, continue.
-      // Otherwise remove PTT and wait for next CAT
-      // CW command.
-      if (cw_busy) continue;
+      // Character has been sent.
+      // If there are more to send, or the next message is pending, continue.
+      // Otherwise remove PTT and wait for next CAT CW command.
+      if (cw_busy || num_buf > 0) continue;
       CAT_cw_is_active=0;
       g_idle_add(ext_ptt_update ,(gpointer)0);
+      // wait up to 500 msec for MOX having gone
+      // otherwise there might be a race condition when sending
+      // the next character really soon
+      i=10;
+      while (mox && (i--) > 0) usleep(50000L);
     }
   }
   // We arrive here if the rigctl server shuts down.
@@ -556,6 +601,7 @@ static gpointer rigctl_cw_thread(gpointer data)
   // of a transmission
   rigctl_cw_thread_id = NULL;
   cw_busy=0;
+  CAT_cw_is_active=0;
   g_idle_add(ext_ptt_update ,(gpointer)0);
   return NULL;
 }
@@ -2170,8 +2216,11 @@ void parse_cmd ( char * cmd_input,int len,int client_sock) {
                                        //  - if we can accept new data (buffer space available) : "KY0;"
                                        //  - if buffer is full: "KY1;"
                                        //
+                                       // Note: cw_buse == -1 indicates a "purge KY" situation, where
+                                       //       all KY commands are accepted and data is discared silently
+                                       //       In this case cw_busy is left untouched here.
                                         if (len <= 2) {
-                                           if (cw_busy) {
+                                           if (cw_busy == 1) {
                                                send_resp(client_sock,"KY1;");
                                            } else {
                                                send_resp(client_sock,"KY0;");
@@ -2181,7 +2230,7 @@ void parse_cmd ( char * cmd_input,int len,int client_sock) {
                                            //   "busy" is correctly queried.
                                            // - Note further that the space immediately following "KY" is *not*
                                            //   part of the message.
-                                           if (!cw_busy && len > 3) {
+                                           if ((cw_busy==0)  && (len > 3)) {
                                                // A CW text will be sent. Copy incoming data to buffer
                                                strncpy(cw_buf, cmd_input+3, 29);
                                                // Kenwood protocol allows for at most 24 characters, so
@@ -2189,6 +2238,7 @@ void parse_cmd ( char * cmd_input,int len,int client_sock) {
                                                cw_buf[29]=0;
                                                cw_busy=1;
                                            }
+                                           // cwbusy == -1 or empty text: do nothing
                                        }  
                                    }
         else if(strcmp(cmd_str,"LK")==0)  {