2015-07-27 00:35:07 +00:00
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
2015-07-27 01:17:23 +00:00
// Copyright (C) 2011, 2012, 2015 John Langner, WB2OSZ
2015-07-27 00:35:07 +00:00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
/*------------------------------------------------------------------
*
* Module : rdq . c
*
* Purpose : Retry later decode queue for frames with bad FCS .
*
* Description :
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2016-07-03 22:09:34 +00:00
# include "direwolf.h"
2015-07-27 00:35:07 +00:00
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
# include <assert.h>
# include <string.h>
# include "ax25_pad.h"
# include "textcolor.h"
# include "audio.h"
# include "rdq.h"
# include "dedupe.h"
2015-07-27 01:17:23 +00:00
static rrbb_t queue_head = NULL ; /* Head of linked list for queue. */
2015-07-27 01:05:48 +00:00
static int rdq_len = 0 ;
# define RDQ_UNDERRUN_THRESHOLD 30 /* A warning will be emitted if there are still this number of packets to decode in the queue and we try to add another one */
2015-07-27 00:35:07 +00:00
2015-07-27 01:17:23 +00:00
static dw_mutex_t rdq_mutex ; /* Critical section for updating queues. */
# if __WIN32__
2015-07-27 00:35:07 +00:00
static HANDLE wake_up_event ; /* Notify try decode again thread when queue not empty. */
# else
static pthread_cond_t wake_up_cond ; /* Notify try decode again thread when queue not empty. */
2015-07-27 01:17:23 +00:00
static dw_mutex_t wake_up_mutex ; /* Required by cond_wait. */
2015-07-27 00:35:07 +00:00
# endif
/*-------------------------------------------------------------------
*
* Name : rdq_init
*
* Purpose : Initialize the receive decode again queue .
*
* Inputs : None . Only single queue for all channels .
*
* Outputs :
*
* Description : Initialize the queue to be empty and set up other
* mechanisms for sharing it between different threads .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void rdq_init ( void )
{
//int c, p;
# if __WIN32__
# else
int err ;
# endif
# if DEBUG
text_color_set ( DW_COLOR_DEBUG ) ;
dw_printf ( " rdq_init ( ) \n " ) ;
dw_printf ( " rdq_init: pthread_mutex_init... \n " ) ;
# endif
2015-07-27 01:17:23 +00:00
dw_mutex_init ( & rdq_mutex ) ;
2015-07-27 00:35:07 +00:00
# if __WIN32__
# else
2015-07-27 01:17:23 +00:00
dw_mutex_init ( & wake_up_mutex ) ;
2015-07-27 00:35:07 +00:00
# endif
# if DEBUG
text_color_set ( DW_COLOR_DEBUG ) ;
dw_printf ( " rdq_init: pthread_cond_init... \n " ) ;
# endif
# if __WIN32__
wake_up_event = CreateEvent ( NULL , 0 , 0 , NULL ) ;
if ( wake_up_event = = NULL ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " rdq_init: pthread_cond_init: can't create decode wake up event " ) ;
exit ( 1 ) ;
}
# else
err = pthread_cond_init ( & wake_up_cond , NULL ) ;
# if DEBUG
text_color_set ( DW_COLOR_DEBUG ) ;
dw_printf ( " rdq_init: pthread_cond_init returns %d \n " , err ) ;
# endif
if ( err ! = 0 ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " rdq_init: pthread_cond_init err=%d " , err ) ;
perror ( " " ) ;
exit ( 1 ) ;
}
# endif
} /* end rdq_init */
/*-------------------------------------------------------------------
*
* Name : rdq_append
*
* Purpose : Add a packet to the end of the queue .
*
* Inputs : pp - Address of raw received bit buffer .
* Caller should NOT make any references to
* it after this point because it could
* be deleted at any time .
*
* Outputs :
*
* Description : Add buffer to end of linked list .
* Signal the decode thread if the queue was formerly empty .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void rdq_append ( rrbb_t rrbb )
{
//int was_empty;
rrbb_t plast ;
rrbb_t pnext ;
# ifndef __WIN32__
int err ;
# endif
# if DEBUG
text_color_set ( DW_COLOR_DEBUG ) ;
dw_printf ( " rdq_append (rrbb=%p) \n " , rrbb ) ;
dw_printf ( " rdq_append: enter critical section \n " ) ;
# endif
2015-07-27 01:17:23 +00:00
dw_mutex_lock ( & rdq_mutex ) ;
2015-07-27 00:35:07 +00:00
//was_empty = 1;
//if (queue_head != NULL) {
//was_empty = 0;
//}
if ( queue_head = = NULL ) {
queue_head = rrbb ;
}
else {
plast = queue_head ;
while ( ( pnext = rrbb_get_nextp ( plast ) ) ! = NULL ) {
plast = pnext ;
}
rrbb_set_nextp ( plast , rrbb ) ;
}
2015-07-27 01:05:48 +00:00
rdq_len + + ;
if ( rdq_len > RDQ_UNDERRUN_THRESHOLD ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " Too many packets to decode (%d) in the queue, decrease the FIX_BITS value \n " , rdq_len ) ;
}
2015-07-27 00:35:07 +00:00
2015-07-27 01:17:23 +00:00
dw_mutex_unlock ( & rdq_mutex ) ;
2015-07-27 00:35:07 +00:00
# if DEBUG
text_color_set ( DW_COLOR_DEBUG ) ;
dw_printf ( " rdq_append: left critical section \n " ) ;
dw_printf ( " rdq_append (): about to wake up retry decode thread. \n " ) ;
# endif
# if __WIN32__
SetEvent ( wake_up_event ) ;
# else
2015-07-27 01:17:23 +00:00
dw_mutex_lock ( & wake_up_mutex ) ;
2015-07-27 00:35:07 +00:00
err = pthread_cond_signal ( & wake_up_cond ) ;
if ( err ! = 0 ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " rdq_append: pthread_cond_signal err=%d " , err ) ;
perror ( " " ) ;
exit ( 1 ) ;
}
2015-07-27 01:17:23 +00:00
dw_mutex_unlock ( & wake_up_mutex ) ;
2015-07-27 00:35:07 +00:00
# endif
}
/*-------------------------------------------------------------------
*
* Name : rdq_wait_while_empty
*
* Purpose : Sleep while the queue is empty rather than
* polling periodically .
*
* Inputs : None .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void rdq_wait_while_empty ( void )
{
int is_empty ;
# ifndef __WIN32__
int err ;
# endif
# if DEBUG
text_color_set ( DW_COLOR_DEBUG ) ;
dw_printf ( " rdq_wait_while_empty () : enter critical section \n " ) ;
# endif
2015-07-27 01:17:23 +00:00
dw_mutex_lock ( & rdq_mutex ) ;
2015-07-27 00:35:07 +00:00
# if DEBUG
//text_color_set(DW_COLOR_DEBUG);
//dw_printf ("rdq_wait_while_empty (): after pthread_mutex_lock\n");
# endif
is_empty = 1 ;
if ( queue_head ! = NULL )
is_empty = 0 ;
2015-07-27 01:17:23 +00:00
dw_mutex_unlock ( & rdq_mutex ) ;
2015-07-27 00:35:07 +00:00
# if DEBUG
text_color_set ( DW_COLOR_DEBUG ) ;
dw_printf ( " rdq_wait_while_empty () : left critical section \n " ) ;
# endif
# if DEBUG
text_color_set ( DW_COLOR_DEBUG ) ;
dw_printf ( " rdq_wait_while_empty (): is_empty = %d \n " , is_empty ) ;
# endif
if ( is_empty ) {
# if DEBUG
text_color_set ( DW_COLOR_DEBUG ) ;
dw_printf ( " rdq_wait_while_empty (): SLEEP - about to call cond wait \n " ) ;
# endif
# if __WIN32__
WaitForSingleObject ( wake_up_event , INFINITE ) ;
# if DEBUG
text_color_set ( DW_COLOR_DEBUG ) ;
dw_printf ( " rdq_wait_while_empty (): returned from wait \n " ) ;
# endif
# else
2015-07-27 01:17:23 +00:00
dw_mutex_lock ( & wake_up_mutex ) ;
2015-07-27 00:35:07 +00:00
err = pthread_cond_wait ( & wake_up_cond , & wake_up_mutex ) ;
# if DEBUG
text_color_set ( DW_COLOR_DEBUG ) ;
dw_printf ( " rdq_wait_while_empty (): WOKE UP - returned from cond wait, err = %d \n " , err ) ;
# endif
if ( err ! = 0 ) {
text_color_set ( DW_COLOR_ERROR ) ;
dw_printf ( " rdq_wait_while_empty: pthread_cond_wait err=%d " , err ) ;
perror ( " " ) ;
exit ( 1 ) ;
}
2015-07-27 01:17:23 +00:00
dw_mutex_unlock ( & wake_up_mutex ) ;
2015-07-27 00:35:07 +00:00
# endif
}
# if DEBUG
text_color_set ( DW_COLOR_DEBUG ) ;
2015-07-27 01:05:48 +00:00
dw_printf ( " rdq_wait_while_empty () returns (%d buffers remaining) \n " , rdq_len ) ;
2015-07-27 00:35:07 +00:00
# endif
}
/*-------------------------------------------------------------------
*
* Name : rdq_remove
*
* Purpose : Remove raw bit buffer from the head of the queue .
*
* Inputs : none
*
* Returns : Pointer to rrbb object .
* Caller should destroy it with rrbb_delete when finished with it .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
rrbb_t rdq_remove ( void )
{
rrbb_t result_p ;
# ifndef __WIN32__
int err ;
# endif
# if DEBUG
text_color_set ( DW_COLOR_DEBUG ) ;
dw_printf ( " rdq_remove() enter critical section \n " ) ;
# endif
2015-07-27 01:17:23 +00:00
dw_mutex_lock ( & rdq_mutex ) ;
2015-07-27 01:05:48 +00:00
rdq_len - - ;
# if DEBUG
dw_printf ( " -rdq_len: %d \n " , rdq_len ) ;
# endif
2015-07-27 00:35:07 +00:00
if ( queue_head = = NULL ) {
result_p = NULL ;
}
else {
result_p = queue_head ;
queue_head = rrbb_get_nextp ( result_p ) ;
rrbb_set_nextp ( result_p , NULL ) ;
}
2015-07-27 01:17:23 +00:00
dw_mutex_unlock ( & rdq_mutex ) ;
2015-07-27 00:35:07 +00:00
# if DEBUG
text_color_set ( DW_COLOR_DEBUG ) ;
dw_printf ( " rdq_remove() leave critical section, returns %p \n " , result_p ) ;
# endif
return ( result_p ) ;
}
/* end rdq.c */