mirror of https://github.com/wb2osz/direwolf.git
Issue 132 continued. If a client app tried to send connected data when
the transmitter was already on, the packet would get stuck in the outgoing data queue.
This commit is contained in:
parent
4ecaf478cf
commit
220e7dd1c4
65
ax25_link.c
65
ax25_link.c
|
@ -156,6 +156,8 @@
|
||||||
* Implemented Multi Selective Reject.
|
* Implemented Multi Selective Reject.
|
||||||
* More efficient generation of SREJ frames.
|
* More efficient generation of SREJ frames.
|
||||||
* Reduced number of duplicate I frames sent for both REJ and SREJ cases.
|
* Reduced number of duplicate I frames sent for both REJ and SREJ cases.
|
||||||
|
* Avoided unnecessary RR when I frame could take care of the ack.
|
||||||
|
* (This led to issue 132 where outgoing data sometimes got stuck in the queue.)
|
||||||
*
|
*
|
||||||
*------------------------------------------------------------------*/
|
*------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -591,8 +593,6 @@ static int AX25MODULO(int n, int m, const char *file, const char *func, int line
|
||||||
|
|
||||||
static void dl_data_indication (ax25_dlsm_t *S, int pid, char *data, int len);
|
static void dl_data_indication (ax25_dlsm_t *S, int pid, char *data, int len);
|
||||||
|
|
||||||
static void lm_seize_confirm (ax25_dlsm_t *S);
|
|
||||||
|
|
||||||
static void i_frame (ax25_dlsm_t *S, cmdres_t cr, int p, int nr, int ns, int pid, char *info_ptr, int info_len);
|
static void i_frame (ax25_dlsm_t *S, cmdres_t cr, int p, int nr, int ns, int pid, char *info_ptr, int info_len);
|
||||||
static void i_frame_continued (ax25_dlsm_t *S, int p, int ns, int pid, char *info_ptr, int info_len);
|
static void i_frame_continued (ax25_dlsm_t *S, int p, int ns, int pid, char *info_ptr, int info_len);
|
||||||
static int is_ns_in_window (ax25_dlsm_t *S, int ns);
|
static int is_ns_in_window (ax25_dlsm_t *S, int ns);
|
||||||
|
@ -1801,8 +1801,6 @@ static void dl_data_indication (ax25_dlsm_t *S, int pid, char *data, int len)
|
||||||
*
|
*
|
||||||
* Description: We need to pause the timers when the channel is busy.
|
* Description: We need to pause the timers when the channel is busy.
|
||||||
*
|
*
|
||||||
* Signal lm_seize_confirm when we have started to transmit.
|
|
||||||
*
|
|
||||||
*------------------------------------------------------------------------------*/
|
*------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
static int dcd_status[MAX_CHANS];
|
static int dcd_status[MAX_CHANS];
|
||||||
|
@ -1859,14 +1857,6 @@ void lm_channel_busy (dlq_item_t *E)
|
||||||
S->radio_channel_busy = 1;
|
S->radio_channel_busy = 1;
|
||||||
PAUSE_T1;
|
PAUSE_T1;
|
||||||
PAUSE_TM201;
|
PAUSE_TM201;
|
||||||
|
|
||||||
// Did channel become busy due to PTT turning on?
|
|
||||||
|
|
||||||
if ( E->activity == OCTYPE_PTT && E->status == 1) {
|
|
||||||
|
|
||||||
lm_seize_confirm (S); // C4.2. "This primitive indicates, to the Data-link State
|
|
||||||
// machine, that the transmission opportunity has arrived."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if ( ! busy && S->radio_channel_busy) {
|
else if ( ! busy && S->radio_channel_busy) {
|
||||||
S->radio_channel_busy = 0;
|
S->radio_channel_busy = 0;
|
||||||
|
@ -1901,32 +1891,43 @@ void lm_channel_busy (dlq_item_t *E)
|
||||||
*
|
*
|
||||||
*------------------------------------------------------------------------------*/
|
*------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
static void lm_seize_confirm (ax25_dlsm_t *S)
|
void lm_seize_confirm (dlq_item_t *E)
|
||||||
{
|
{
|
||||||
|
|
||||||
switch (S->state) {
|
assert (E->chan >= 0 && E->chan < MAX_CHANS);
|
||||||
|
|
||||||
case state_0_disconnected:
|
ax25_dlsm_t *S;
|
||||||
case state_1_awaiting_connection:
|
|
||||||
case state_2_awaiting_release:
|
|
||||||
case state_5_awaiting_v22_connection:
|
|
||||||
|
|
||||||
break;
|
for (S = list_head; S != NULL; S = S->next) {
|
||||||
|
|
||||||
case state_3_connected:
|
if (E->chan == S->chan) {
|
||||||
case state_4_timer_recovery:
|
|
||||||
|
|
||||||
// v1.5 change in strategy.
|
|
||||||
// New I frames, not sent yet, are delayed until after processing anything in the received transmission.
|
|
||||||
// Previously we started sending new frames, from the client app, as soon as they arrived.
|
|
||||||
// Now, we first take care of those in progress before throwing more into the mix.
|
|
||||||
|
|
||||||
i_frame_pop_off_queue(S);
|
switch (S->state) {
|
||||||
|
|
||||||
if (S->acknowledge_pending) {
|
case state_0_disconnected:
|
||||||
S->acknowledge_pending = 0;
|
case state_1_awaiting_connection:
|
||||||
enquiry_response (S, frame_not_AX25, 0);
|
case state_2_awaiting_release:
|
||||||
}
|
case state_5_awaiting_v22_connection:
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case state_3_connected:
|
||||||
|
case state_4_timer_recovery:
|
||||||
|
|
||||||
|
// v1.5 change in strategy.
|
||||||
|
// New I frames, not sent yet, are delayed until after processing anything in the received transmission.
|
||||||
|
// Previously we started sending new frames, from the client app, as soon as they arrived.
|
||||||
|
// Now, we first take care of those in progress before throwing more into the mix.
|
||||||
|
|
||||||
|
i_frame_pop_off_queue(S);
|
||||||
|
|
||||||
|
// Need an RR if we didn't have I frame send the necessary ack.
|
||||||
|
|
||||||
|
if (S->acknowledge_pending) {
|
||||||
|
S->acknowledge_pending = 0;
|
||||||
|
enquiry_response (S, frame_not_AX25, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Implementation difference: The flow chart for state 3 has LM-RELEASE Request here.
|
// Implementation difference: The flow chart for state 3 has LM-RELEASE Request here.
|
||||||
// I don't think I need it because the transmitter will turn off
|
// I don't think I need it because the transmitter will turn off
|
||||||
|
@ -1935,7 +1936,9 @@ static void lm_seize_confirm (ax25_dlsm_t *S)
|
||||||
// Erratum: The original spec had LM-SEIZE request here, for state 4, which didn't seem right.
|
// Erratum: The original spec had LM-SEIZE request here, for state 4, which didn't seem right.
|
||||||
// The 2006 revision has LM-RELEASE Request so states 3 & 4 are the same.
|
// The 2006 revision has LM-RELEASE Request so states 3 & 4 are the same.
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* lm_seize_confirm */
|
} /* lm_seize_confirm */
|
||||||
|
|
|
@ -52,6 +52,8 @@ void ax25_link_init (struct misc_config_s *pconfig);
|
||||||
// These functions must be called on a single thread, one at a time.
|
// These functions must be called on a single thread, one at a time.
|
||||||
// The Data Link Queue (DLQ) is used to serialize events from multiple sources.
|
// The Data Link Queue (DLQ) is used to serialize events from multiple sources.
|
||||||
|
|
||||||
|
// Maybe the dispatch switch should be moved to ax25_link.c so they can all
|
||||||
|
// be made static and they can't be called from the wrong place accidentally.
|
||||||
|
|
||||||
void dl_connect_request (dlq_item_t *E);
|
void dl_connect_request (dlq_item_t *E);
|
||||||
|
|
||||||
|
@ -68,6 +70,8 @@ void dl_client_cleanup (dlq_item_t *E);
|
||||||
|
|
||||||
void lm_data_indication (dlq_item_t *E);
|
void lm_data_indication (dlq_item_t *E);
|
||||||
|
|
||||||
|
void lm_seize_confirm (dlq_item_t *E);
|
||||||
|
|
||||||
void lm_channel_busy (dlq_item_t *E);
|
void lm_channel_busy (dlq_item_t *E);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -262,7 +262,7 @@ int main (int argc, char *argv[])
|
||||||
|
|
||||||
text_color_init(t_opt);
|
text_color_init(t_opt);
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("Dire Wolf version %d.%d (%s) Beta Test 3\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
|
dw_printf ("Dire Wolf version %d.%d (%s) Beta Test 4\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
|
||||||
//dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "C", __DATE__);
|
//dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "C", __DATE__);
|
||||||
//dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION);
|
//dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION);
|
||||||
|
|
||||||
|
|
47
dlq.c
47
dlq.c
|
@ -767,6 +767,53 @@ void dlq_channel_busy (int chan, int activity, int status)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: dlq_seize_confirm
|
||||||
|
*
|
||||||
|
* Purpose: Inform data link state machine that the transmitter is on.
|
||||||
|
* This is in reponse to lm_seize_request.
|
||||||
|
*
|
||||||
|
* Inputs: chan - Radio channel number.
|
||||||
|
*
|
||||||
|
* Outputs: Request is appended to queue for processing by
|
||||||
|
* the data link state machine.
|
||||||
|
*
|
||||||
|
* Description: When removed from the data link state machine queue, this
|
||||||
|
* becomes lm_seize_confirm.
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void dlq_seize_confirm (int chan)
|
||||||
|
{
|
||||||
|
struct dlq_item_s *pnew;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dlq_seize_confirm (chan=%d)\n", chan);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Allocate a new queue item. */
|
||||||
|
|
||||||
|
pnew = (struct dlq_item_s *) calloc (sizeof(struct dlq_item_s), 1);
|
||||||
|
s_new_count++;
|
||||||
|
|
||||||
|
pnew->type = DLQ_SEIZE_CONFIRM;
|
||||||
|
pnew->chan = chan;
|
||||||
|
|
||||||
|
/* Put it into queue. */
|
||||||
|
|
||||||
|
append_to_queue (pnew);
|
||||||
|
|
||||||
|
|
||||||
|
} /* end dlq_seize_confirm */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
/*-------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Name: dlq_client_cleanup
|
* Name: dlq_client_cleanup
|
||||||
|
|
4
dlq.h
4
dlq.h
|
@ -35,7 +35,7 @@ typedef struct cdata_s {
|
||||||
|
|
||||||
/* Types of things that can be in queue. */
|
/* Types of things that can be in queue. */
|
||||||
|
|
||||||
typedef enum dlq_type_e {DLQ_REC_FRAME, DLQ_CONNECT_REQUEST, DLQ_DISCONNECT_REQUEST, DLQ_XMIT_DATA_REQUEST, DLQ_REGISTER_CALLSIGN, DLQ_UNREGISTER_CALLSIGN, DLQ_CHANNEL_BUSY, DLQ_CLIENT_CLEANUP} dlq_type_t;
|
typedef enum dlq_type_e {DLQ_REC_FRAME, DLQ_CONNECT_REQUEST, DLQ_DISCONNECT_REQUEST, DLQ_XMIT_DATA_REQUEST, DLQ_REGISTER_CALLSIGN, DLQ_UNREGISTER_CALLSIGN, DLQ_CHANNEL_BUSY, DLQ_SEIZE_CONFIRM, DLQ_CLIENT_CLEANUP} dlq_type_t;
|
||||||
|
|
||||||
|
|
||||||
/* A queue item. */
|
/* A queue item. */
|
||||||
|
@ -116,6 +116,8 @@ void dlq_unregister_callsign (char addr[AX25_MAX_ADDR_LEN], int chan, int client
|
||||||
|
|
||||||
void dlq_channel_busy (int chan, int activity, int status);
|
void dlq_channel_busy (int chan, int activity, int status);
|
||||||
|
|
||||||
|
void dlq_seize_confirm (int chan);
|
||||||
|
|
||||||
void dlq_client_cleanup (int client);
|
void dlq_client_cleanup (int client);
|
||||||
|
|
||||||
|
|
||||||
|
|
5
recv.c
5
recv.c
|
@ -378,6 +378,11 @@ void recv_process (void)
|
||||||
lm_channel_busy (pitem);
|
lm_channel_busy (pitem);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DLQ_SEIZE_CONFIRM:
|
||||||
|
|
||||||
|
lm_seize_confirm (pitem);
|
||||||
|
break;
|
||||||
|
|
||||||
case DLQ_CLIENT_CLEANUP:
|
case DLQ_CLIENT_CLEANUP:
|
||||||
|
|
||||||
dl_client_cleanup (pitem);
|
dl_client_cleanup (pitem);
|
||||||
|
|
65
xmit.c
65
xmit.c
|
@ -74,6 +74,7 @@
|
||||||
#include "morse.h"
|
#include "morse.h"
|
||||||
#include "dtmf.h"
|
#include "dtmf.h"
|
||||||
#include "xid.h"
|
#include "xid.h"
|
||||||
|
#include "dlq.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,8 +105,8 @@ static int xmit_txtail[MAX_CHANS]; /* Amount of time to keep transmitting after
|
||||||
static int xmit_fulldup[MAX_CHANS]; /* Full duplex if non-zero. */
|
static int xmit_fulldup[MAX_CHANS]; /* Full duplex if non-zero. */
|
||||||
|
|
||||||
static int xmit_bits_per_sec[MAX_CHANS]; /* Data transmission rate. */
|
static int xmit_bits_per_sec[MAX_CHANS]; /* Data transmission rate. */
|
||||||
/* Often called baud rate which is equivalent in */
|
/* Often called baud rate which is equivalent for */
|
||||||
/* this case but could be different with other */
|
/* 1200 & 9600 cases but could be different with other */
|
||||||
/* modulation techniques. */
|
/* modulation techniques. */
|
||||||
|
|
||||||
static int g_debug_xmit_packet; /* print packet in hexadecimal form for debugging. */
|
static int g_debug_xmit_packet; /* print packet in hexadecimal form for debugging. */
|
||||||
|
@ -114,11 +115,42 @@ static int g_debug_xmit_packet; /* print packet in hexadecimal form for debuggi
|
||||||
// TODO: When this was first written, bits/sec was same as baud.
|
// TODO: When this was first written, bits/sec was same as baud.
|
||||||
// Need to revisit this for PSK modes where they are not the same.
|
// Need to revisit this for PSK modes where they are not the same.
|
||||||
|
|
||||||
|
#if 0 // Added during 1.5 beta test
|
||||||
|
|
||||||
|
static int BITS_TO_MS (int b, int ch) {
|
||||||
|
|
||||||
|
int bits_per_symbol;
|
||||||
|
|
||||||
|
switch (save_audio_config_p->achan[ch].modem_type) {
|
||||||
|
case MODEM_QPSK: bits_per_symbol = 2; break;
|
||||||
|
case MODEM_8PSK: bits_per_symbol = 3; break;
|
||||||
|
case default: bits_per_symbol = 1; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( (b * 1000) / (xmit_bits_per_sec[(ch)] * bits_per_symbol) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int MS_TO_BITS (int ms, int ch) {
|
||||||
|
|
||||||
|
int bits_per_symbol;
|
||||||
|
|
||||||
|
switch (save_audio_config_p->achan[ch].modem_type) {
|
||||||
|
case MODEM_QPSK: bits_per_symbol = 2; break;
|
||||||
|
case MODEM_8PSK: bits_per_symbol = 3; break;
|
||||||
|
case default: bits_per_symbol = 1; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( (ms * xmit_bits_per_sec[(ch)] * bits_per_symbol) / 1000 ); TODO...
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // OK for 1200, 9600 but wrong for PSK
|
||||||
|
|
||||||
#define BITS_TO_MS(b,ch) (((b)*1000)/xmit_bits_per_sec[(ch)])
|
#define BITS_TO_MS(b,ch) (((b)*1000)/xmit_bits_per_sec[(ch)])
|
||||||
|
|
||||||
#define MS_TO_BITS(ms,ch) (((ms)*xmit_bits_per_sec[(ch)])/1000)
|
#define MS_TO_BITS(ms,ch) (((ms)*xmit_bits_per_sec[(ch)])/1000)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MAXX(a,b) (((a)>(b)) ? (a) : (b))
|
#define MAXX(a,b) (((a)>(b)) ? (a) : (b))
|
||||||
|
|
||||||
|
|
||||||
|
@ -723,6 +755,12 @@ static void xmit_ax25_frames (int chan, int prio, packet_t pp, int max_bundle)
|
||||||
#endif
|
#endif
|
||||||
ptt_set (OCTYPE_PTT, chan, 1);
|
ptt_set (OCTYPE_PTT, chan, 1);
|
||||||
|
|
||||||
|
|
||||||
|
// Inform data link state machine that we are now transmitting.
|
||||||
|
|
||||||
|
dlq_seize_confirm (chan); // C4.2. "This primitive indicates, to the Data-link State
|
||||||
|
// machine, that the transmission opportunity has arrived."
|
||||||
|
|
||||||
pre_flags = MS_TO_BITS(xmit_txdelay[chan] * 10, chan) / 8;
|
pre_flags = MS_TO_BITS(xmit_txdelay[chan] * 10, chan) / 8;
|
||||||
num_bits = hdlc_send_flags (chan, pre_flags, 0);
|
num_bits = hdlc_send_flags (chan, pre_flags, 0);
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -730,6 +768,11 @@ static void xmit_ax25_frames (int chan, int prio, packet_t pp, int max_bundle)
|
||||||
dw_printf ("xmit_thread: txdelay=%d [*10], pre_flags=%d, num_bits=%d\n", xmit_txdelay[chan], pre_flags, num_bits);
|
dw_printf ("xmit_thread: txdelay=%d [*10], pre_flags=%d, num_bits=%d\n", xmit_txdelay[chan], pre_flags, num_bits);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
SLEEP_MS (10); // Give data link state machine a chance to
|
||||||
|
// to stuff more frames into the transmit queue,
|
||||||
|
// in response to dlq_seize_confirm, so
|
||||||
|
// we don't run off the end too soon.
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Transmit the frame.
|
* Transmit the frame.
|
||||||
|
@ -913,6 +956,24 @@ static int send_one_frame (int c, int p, packet_t pp)
|
||||||
|
|
||||||
|
|
||||||
if (ax25_is_null_frame(pp)) {
|
if (ax25_is_null_frame(pp)) {
|
||||||
|
|
||||||
|
// Issue 132 - We could end up in a situation where:
|
||||||
|
// Transmitter is already on.
|
||||||
|
// Application wants to send a frame.
|
||||||
|
// dl_seize_request turns into this null frame.
|
||||||
|
// It was being ignored here so the data got stuck in the queue.
|
||||||
|
// I think the solution is to send back a seize confirm here.
|
||||||
|
// It shouldn't hurt if we send it redundantly.
|
||||||
|
// Added for 1.5 beta test 4.
|
||||||
|
|
||||||
|
dlq_seize_confirm (c); // C4.2. "This primitive indicates, to the Data-link State
|
||||||
|
// machine, that the transmission opportunity has arrived."
|
||||||
|
|
||||||
|
SLEEP_MS (10); // Give data link state machine a chance to
|
||||||
|
// to stuff more frames into the transmit queue,
|
||||||
|
// in response to dlq_seize_confirm, so
|
||||||
|
// we don't run off the end too soon.
|
||||||
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue