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
//
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;
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;
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;
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;
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);
}
}
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;
}
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);
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);
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;
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.
// 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--;
}
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;