From 6a5ef5f328e0eb83658e3b855b8c65a6bc10a030 Mon Sep 17 00:00:00 2001 From: c vw Date: Mon, 9 Jul 2018 11:21:27 +0200 Subject: [PATCH] Now behaves correctly if user switches mode during CAT CW transmission. --- old_protocol.c | 2 +- radio.c | 2 +- radio.h | 2 +- rigctl.c | 94 ++++++++++++++++++++++++++------------------------ transmitter.c | 43 +++++++++++++++-------- 5 files changed, 81 insertions(+), 62 deletions(-) diff --git a/old_protocol.c b/old_protocol.c index 4b944f5..3c26cae 100644 --- a/old_protocol.c +++ b/old_protocol.c @@ -507,7 +507,7 @@ static void process_ozy_input_buffer(unsigned char *buffer) { dot=(control_in[0]&0x04)==0x04; local_ptt=ptt; - if (dot || dash) external_cw_key_hit=1; + if (dot || dash) cw_key_hit=1; if(vfo[tx_vfo].mode==modeCWL || vfo[tx_vfo].mode==modeCWU) { local_ptt=ptt|dot|dash; } diff --git a/radio.c b/radio.c index 0b0c176..854f053 100644 --- a/radio.c +++ b/radio.c @@ -289,7 +289,7 @@ double vox_gain=10.0; double vox_hang=250.0; int vox=0; int local_cw_is_active=0; -int external_cw_key_hit=0; +int cw_key_hit=0; int diversity_enabled=0; double i_rotate[2]={1.0,1.0}; diff --git a/radio.h b/radio.h index c48f1db..b455aec 100644 --- a/radio.h +++ b/radio.h @@ -245,7 +245,7 @@ extern double vox_gain; extern double vox_hang; extern int vox; extern int local_cw_is_active; -extern int external_cw_key_hit; +extern int cw_key_hit; extern int diversity_enabled; extern double i_rotate[2]; diff --git a/rigctl.c b/rigctl.c index 42a7668..ec44ba4 100644 --- a/rigctl.c +++ b/rigctl.c @@ -303,7 +303,7 @@ static long dashlen; static int dotsamples; static int dashsamples; -extern int cw_key_up, cw_key_down; +extern int cw_key_up, cw_key_down, cw_not_ready; // // send_dash() send a "key-down" of a dashlen, followed by a "key-up" of a dotlen @@ -317,7 +317,7 @@ extern int cw_key_up, cw_key_down; // void send_dash() { int TimeToGo; - if (external_cw_key_hit) return; + if (cw_key_hit || cw_not_ready) return; for(;;) { TimeToGo=cw_key_up+cw_key_down; if (TimeToGo == 0) break; @@ -332,7 +332,7 @@ void send_dash() { void send_dot() { int TimeToGo; - if (external_cw_key_hit) return; + if (cw_key_hit || cw_not_ready) return; for(;;) { TimeToGo=cw_key_up+cw_key_down; if (TimeToGo == 0) break; @@ -347,7 +347,7 @@ void send_dot() { void send_space(int len) { int TimeToGo; - if (external_cw_key_hit) return; + if (cw_key_hit || cw_not_ready) return; for(;;) { TimeToGo=cw_key_up+cw_key_down; if (TimeToGo == 0) break; @@ -483,7 +483,7 @@ static gpointer rigctl_cw_thread(gpointer data) while (server_running) { // wait for cw_buf become filled with data // (periodically look every 100 msec) - external_cw_key_hit=0; + cw_key_hit=0; if (!cw_busy) { usleep(100000L); continue; @@ -506,37 +506,38 @@ static gpointer rigctl_cw_thread(gpointer data) usleep(100000L); } i=0; - while(((c=local_buf[i++]) != '\0') && !external_cw_key_hit && mox) { + while(((c=local_buf[i++]) != '\0') && !cw_key_hit && !cw_not_ready) { rigctl_send_cw_char(c); } - // - // Either an external CW key has been hit (one connected to the SDR board), - // or MOX has manually been switched. In this case swallow any pending - // or incoming KY messages for about 0.75 sec. We need this long time since - // hamlib waits 0.5 secs after receiving a "KY1" message before trying to - // send the next bunch (do PTT update immediately). - // - if (external_cw_key_hit || !mox) { + if (cw_key_hit || cw_not_ready) { + // + // CW transmission has been aborted, either due to manually + // removing MOX, changing the mode to non-CW, or because a CW key has been hit. + // Do not remove PTT if we abort CAT CW because a CW key has been hit. local_cw_is_active=0; g_idle_add(ext_cw_key ,(gpointer)0); // If an external CW key has been hit, we continue in TX mode // doing CW manually. Otherwise, switch PTT off. - if (!external_cw_key_hit) { + if (!cw_key_hit) { g_idle_add(ext_ptt_update ,(gpointer)0); } - for (i=0; i< 75; i++) { + // Stay for 1 sec swallowing incoming + // 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(10000L); + usleep(20000L); } - } - // If the next message is pending, continue - if (cw_busy) continue; - local_cw_is_active=0; - // In case of an abort of local CW, this has already been done. - // It is not too harmful to do it again. In case of "normal termination" - // of sending a CAT CW message, we have to do it here. - g_idle_add(ext_cw_key ,(gpointer)0); - if (!external_cw_key_hit) { + } else { + // + // 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; + local_cw_is_active=0; + g_idle_add(ext_cw_key ,(gpointer)0); g_idle_add(ext_ptt_update ,(gpointer)0); } } @@ -2151,34 +2152,37 @@ void parse_cmd ( char * cmd_input,int len,int client_sock) { else if((strcmp(cmd_str,"KY")==0) && (zzid_flag == 0)) { // DL1YCF: - // Hamlib produces errors if we keep begin busy here for - // seconds. Therefore we just copy the data to be handled - // by a separate thread. - // Note that this thread only makes a 0 --> 1 transition for cw_busy, - // and the CW thread only makes a 1 --> 0 transition + // Hamlib produces timeout errors if we are busy here for + // seconds. Therefore we just move the data into a buffer + // that is processed by a separate thread. + // Note that here we only makes a 0 --> 1 transition for cw_busy, + // and the CW thread only makes a 1 --> 0 transition, so we do not + // need a mutex and/or atomic updates here. // - // Note: for a "KY;" command, we have to return "KY0;" if we can - // accept new data (buffer space available) and "KY1;" if we cannot, + // Note: The "KY;" command is used to query if we are busy. We return: + // - if we can accept new data (buffer space available) : "KY0;" + // - if buffer is full: "KY1;" // if (len <= 2) { if (cw_busy) { - send_resp(client_sock,"KY1;"); // can store no more data + send_resp(client_sock,"KY1;"); } else { send_resp(client_sock,"KY0;"); } } else { - // So we have data. We have to init the CW setup because TUNE - // changes the WDSP side tone frequency. - g_idle_add(ext_cw_setup,NULL); // Initialize for external transmit - // We silently ignore buffer overruns. This does not happen with - // hamlib since I fixed it. Note further that the space immediately - // following "KY" is *not* part of the message. - // while cleaning up after hitting external CW key, just skip message - if (!cw_busy && len > 3 && !external_cw_key_hit) { + // - We silently ignore buffer overruns. This does not happen if + // "busy" is correctly queried. + // - Note further that the space immediately following "KY" is *not* + // part of the message. + if (!cw_busy && len > 3) { + // A CW text will be sent. We have to call cw_setup here because + // TUNE changes the WDSP side tone frequency, and in this case we have + // to re-adjust it. + g_idle_add(ext_cw_setup,NULL); // Initialize for external transmit // Copy data to buffer - strncpy(cw_buf, cmd_input+3, 30); - // Kenwood protocol allows for at most 28 characters, so - // this is pure paranoia + strncpy(cw_buf, cmd_input+3, 29); + // Kenwood protocol allows for at most 24 characters, so + // this seems pure paranoia -- but who knows? cw_buf[29]=0; cw_busy=1; } diff --git a/transmitter.c b/transmitter.c index 91f9eb0..3bd504f 100644 --- a/transmitter.c +++ b/transmitter.c @@ -62,11 +62,21 @@ static int filterHigh; static int waterfall_samples=0; static int waterfall_resample=8; + +// These three variables are global. Their use is: +// cw_key_up/cw_key_down: set number of samples for next key-down/key-up sequence +// Any of these variable will only be set from outside if +// both have value 0. +// cw_not_ready: set to 0 if transmitting in CW mode. This is used to +// abort pending CAT CW messages if MOX or MODE is switched +// manually. int cw_key_up = 0; int cw_key_down = 0; +int cw_not_ready=1; + // cw_shape_buffer will eventually be integrated into TRANSMITTER static int *cw_shape_buffer = NULL; -int cw_shape = 0; +static int cw_shape = 0; extern void cw_audio_write(double sample); @@ -814,7 +824,7 @@ static void full_tx_buffer(TRANSMITTER *tx) { qsample=qs>=0.0?(long)floor(qs*gain+0.5):(long)ceil(qs*gain-0.5); switch(protocol) { case ORIGINAL_PROTOCOL: - old_protocol_iq_samples_with_sidetone(isample,qsample,0); + old_protocol_iq_samples(isample,qsample); break; case NEW_PROTOCOL: new_protocol_iq_samples(isample,qsample); @@ -837,8 +847,11 @@ void add_mic_sample(TRANSMITTER *tx,short mic_sample) { mode=vfo[0].mode; } -// silence TX audio not transmitting, if tuning, or -// when doing CW +// +// silence TX audio if not transmitting, if tuning, or +// when doing CW. Note: CW side tone added later on by a +// separate mechanism. +// if (tune || !isTransmitting() || mode==modeCWL || mode==modeCWU) { mic_sample_double=0.0; @@ -846,13 +859,10 @@ void add_mic_sample(TRANSMITTER *tx,short mic_sample) { mic_sample_double=(double)mic_sample/32768.0; } -//This statement takes care that the cw shape buffer is -//automatically wiped if we are not doing local CW - - cw_shape_buffer[tx->samples]=0; - - if((mode==modeCWL || mode==modeCWU)) { - if (isTransmitting()) { +// +// shape CW pulses when doing CW and transmitting, else nullify them +// + if((mode==modeCWL || mode==modeCWU) && isTransmitting()) { // // RigCtl CW sets the variables cw_key_up and cw_key_down // to the number of samples for the next down/up sequence. @@ -862,6 +872,7 @@ void add_mic_sample(TRANSMITTER *tx,short mic_sample) { // heard way beside our frequency. The envelope goes up // and down linearly within 200 samples (4.16 msec) // + cw_not_ready=0; if (cw_key_down > 0 ) { if (cw_shape < 200) cw_shape++; cw_key_down--; @@ -875,14 +886,18 @@ void add_mic_sample(TRANSMITTER *tx,short mic_sample) { } cw_audio_write(0.00003937 * getNextSideToneSample() * cw_keyer_sidetone_volume * cw_shape); cw_shape_buffer[tx->samples]=cw_shape; - } else { + } else { // -// Have to reset pulse shaper since RigCtl may wait forever +// If no longer transmitting, or no longer doing CW: reset pulse shaper. +// This will also swallow any pending CW in rigtl CAT CW and wipe out the +// cw_shape buffer very quickly. In order to tell rigctl etc. that CW should be +// aborted, we also use the cw_not_ready flag. // + cw_not_ready=1; cw_key_up=0; cw_key_down=0; cw_shape=0; - } + cw_shape_buffer[tx->samples]=0; } tx->mic_input_buffer[tx->samples*2]=mic_sample_double; tx->mic_input_buffer[(tx->samples*2)+1]=0.0; //mic_sample_double; -- 2.45.2