Fixed more bugs.
authorJim Dixon <telesistant@hotmail.com>
Sat, 29 Jan 2005 07:31:17 +0000 (07:31 +0000)
committerJim Dixon <telesistant@hotmail.com>
Sat, 29 Jan 2005 07:31:17 +0000 (07:31 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4918 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_rpt.c

index fee56bb..040f8b0 100755 (executable)
@@ -3,11 +3,11 @@
  * Asterisk -- A telephony toolkit for Linux.
  *
  * Radio Repeater / Remote Base program 
- *  version 0.20 01/14/05
+ *  version 0.23 01/28/05
  * 
  * See http://www.zapatatelephony.org/app_rpt.html
  *
- * Copyright (C) 2002 - 2005, Jim Dixon, WB6NIL
+ * Copyright (C) 2002-2004, Jim Dixon, WB6NIL
  *
  * Jim Dixon, WB6NIL <jim@lambdatel.com>
  * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
@@ -80,6 +80,8 @@
 #define        DISC_TIME 10000  /* report disc after 10 seconds of no connect */
 #define        MAX_RETRIES 5
 
+#define        REDUNDANT_TX_TIME 2000
+
 #define        RETRY_TIMER_MS 5000
 
 #define        MAXREMSTR 15
@@ -107,7 +109,7 @@ enum {REM_OFF,REM_MONITOR,REM_TX};
 
 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
        CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME,
-       STATS_VERSION, IDTALKOVER, ARB_ALPHA};
+       STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE};
 
 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
 
@@ -131,6 +133,7 @@ enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM};
 #include <asterisk/config.h>
 #include <asterisk/say.h>
 #include <asterisk/localtime.h>
+#include <signal.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
@@ -150,7 +153,8 @@ enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM};
 #include <tonezone.h>
 #include <linux/zaptel.h>
 
-static  char *tdesc = "Radio Repeater / Remote Base  version 0.20  01/14/2005";
+static  char *tdesc = "Radio Repeater / Remote Base  version 0.23  01/28/2005";
+
 static char *app = "Rpt";
 
 static char *synopsis = "Radio Repeater/Remote Base Control System";
@@ -190,11 +194,14 @@ struct rpt_link
        char    lasttx;
        char    lastrx;
        char    connected;
+       char    hasconnected;
        char    outbound;
        char    disced;
+       char    killme;
        long    elaptime;
        long    disctime;
        long    retrytimer;
+       long    retxtimer;
        int     retries;
        struct ast_channel *chan;       
        struct ast_channel *pchan;      
@@ -272,6 +279,7 @@ static struct rpt
        int mustid;
        int politeid;
        int dtmfidx,rem_dtmfidx;
+       long    retxtimer;
        char mydtmf;
        int iobase;
        char exten[AST_MAX_EXTENSION];
@@ -282,6 +290,7 @@ static struct rpt
        char rxplon;
        char funcchar;
        char endchar;
+       char stopgen;
        int link_longestfunc;
        int longestfunc;
        int longestnode;        
@@ -792,6 +801,7 @@ struct tm localtm;
        if (!mychannel)
        {
                fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
+               ast_mutex_lock(&myrpt->lock);
                remque((struct qelem *)mytele);
                ast_mutex_unlock(&myrpt->lock);
                free(mytele);           
@@ -981,6 +991,11 @@ struct tm localtm;
                        if (!m)
                        {
                                ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
+                               ast_mutex_lock(&myrpt->lock);
+                               remque((struct qelem *)mytele);
+                               ast_mutex_unlock(&myrpt->lock);
+                               free(mytele);           
+                               ast_hangup(mychannel);
                                pthread_exit(NULL);
                        }
                        memcpy(m,l,sizeof(struct rpt_link));
@@ -1135,9 +1150,20 @@ struct tm localtm;
                        saycharstr(mychannel, mytele->param);
                imdone = 1;
                break;
+           case TEST_TONE:
+               imdone = 1;
+               myrpt->stopgen = 0;
+               if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
+                       break;
+               while(mychannel->generatordata && (!myrpt->stopgen)) {
+                       if (ast_safe_sleep(mychannel,1)) break;
+                       imdone = 1;
+                       }
+               break;
            default:
                break;
        }
+       myrpt->stopgen = 0;
        if (!imdone)
        {
                if (!res) 
@@ -1197,7 +1223,7 @@ static void *rpt_call(void *this)
 ZT_CONFINFO ci;  /* conference info */
 struct rpt *myrpt = (struct rpt *)this;
 int    res;
-struct ast_frame *f,wf;
+struct ast_frame wf;
 int stopped,congstarted;
 struct ast_channel *mychannel,*genchannel;
 
@@ -1284,7 +1310,7 @@ struct ast_channel *mychannel,*genchannel;
                        /* start congestion tone */
                        tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
                }
-               res = ast_waitfor(mychannel, MSWAIT);
+               res = ast_safe_sleep(mychannel, MSWAIT);
                if (res < 0)
                {
                        ast_hangup(mychannel);
@@ -1294,29 +1320,6 @@ struct ast_channel *mychannel,*genchannel;
                        ast_mutex_unlock(&myrpt->lock);
                        pthread_exit(NULL);
                }
-               if (res == 0) continue;
-               f = ast_read(mychannel);
-               if (f == NULL) 
-               {
-                       ast_hangup(mychannel);
-                       ast_hangup(genchannel);
-                       ast_mutex_lock(&myrpt->lock);
-                       myrpt->callmode = 0;
-                       ast_mutex_unlock(&myrpt->lock);
-                       pthread_exit(NULL);                     
-               }
-               if ((f->frametype == AST_FRAME_CONTROL) &&
-                   (f->subclass == AST_CONTROL_HANGUP))
-               {
-                       ast_frfree(f);
-                       ast_hangup(mychannel);
-                       ast_hangup(genchannel);
-                       ast_mutex_lock(&myrpt->lock);
-                       myrpt->callmode = 0;
-                       ast_mutex_unlock(&myrpt->lock);
-                       pthread_exit(NULL);                     
-               }
-               ast_frfree(f);
        }
        /* stop any tone generation */
        tone_zone_play_tone(mychannel->fds[0],-1);
@@ -1393,11 +1396,7 @@ struct ast_channel *mychannel,*genchannel;
                        myrpt->mydtmf = 0;
                }
                ast_mutex_unlock(&myrpt->lock);
-               if (ast_safe_sleep(mychannel,25)) 
-               {
-                       ast_mutex_unlock(&myrpt->lock);
-                       break;
-               }
+               usleep(MSWAIT * 1000);
                ast_mutex_lock(&myrpt->lock);
        }
        ast_mutex_unlock(&myrpt->lock);
@@ -1455,7 +1454,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
 {
 
        char *val, *s, *s1, *tele;
-       char tmp[300], deststr[300] = "";
+       char tmp[300], deststr[300] = "",modechange = 0;
        struct rpt_link *l;
        ZT_CONFINFO ci;  /* conference info */
 
@@ -1542,14 +1541,18 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                                        return DC_COMPLETE;
                                        
                                }
+                               ast_mutex_unlock(&myrpt->lock);
                                if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
-                       }
-                       ast_mutex_unlock(&myrpt->lock);
+                               l->retries = MAX_RETRIES + 1;
+                               l->disced = 2;
+                               modechange = 1;
+                       } else
+                               ast_mutex_unlock(&myrpt->lock);
                        /* establish call in monitor mode */
                        l = malloc(sizeof(struct rpt_link));
                        if (!l){
                                ast_log(LOG_WARNING, "Unable to malloc\n");
-                               pthread_exit(NULL);
+                               return DC_ERROR;
                        }
                        /* zero the silly thing */
                        memset((char *)l,0,sizeof(struct rpt_link));
@@ -1557,12 +1560,13 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                        tele = strchr(deststr,'/');
                        if (!tele){
                                fprintf(stderr,"link2:Dial number (%s) must be in format tech/number\n",deststr);
-                               pthread_exit(NULL);
+                               return DC_ERROR;
                        }
                        *tele++ = 0;
                        l->isremote = (s && ast_true(s));
                        strncpy(l->name, digitbuf, MAXNODESTR - 1);
                        l->chan = ast_request(deststr,AST_FORMAT_SLINEAR,tele,NULL);
+                       if (modechange) l->connected = 1;
                        if (l->chan){
                                ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
                                ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
@@ -1590,7 +1594,9 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                        l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
                        if (!l->pchan){
                                fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
-                               pthread_exit(NULL);
+                               ast_hangup(l->chan);
+                               free(l);
+                               return DC_ERROR;
                        }
                        ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
                        ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
@@ -1602,7 +1608,10 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                        if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
                        {
                                ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
-                               pthread_exit(NULL);
+                               ast_hangup(l->chan);
+                               ast_hangup(l->pchan);
+                               free(l);
+                               return DC_ERROR;
                        }
                        ast_mutex_lock(&myrpt->lock);
                        /* insert at end of queue */
@@ -1637,14 +1646,18 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                                        rpt_telemetry(myrpt, REMALREADY, NULL);
                                        return DC_COMPLETE;
                                }
+                               ast_mutex_unlock(&myrpt->lock);
                                if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
-                       } 
-                       ast_mutex_unlock(&myrpt->lock);
+                               l->retries = MAX_RETRIES + 1;
+                               l->disced = 2;
+                               modechange = 1;
+                       } else
+                               ast_mutex_unlock(&myrpt->lock);
                        /* establish call in tranceive mode */
                        l = malloc(sizeof(struct rpt_link));
                        if (!l){
                                ast_log(LOG_WARNING, "Unable to malloc\n");
-                               pthread_exit(NULL);
+                               return(DC_ERROR);
                        }
                        /* zero the silly thing */
                        memset((char *)l,0,sizeof(struct rpt_link));
@@ -1652,11 +1665,13 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                        l->outbound = 1;
                        strncpy(l->name, digitbuf, MAXNODESTR - 1);
                        l->isremote = (s && ast_true(s));
+                       if (modechange) l->connected = 1;
                        snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
                        tele = strchr(deststr, '/');
                        if (!tele){
                                fprintf(stderr,"link3:Dial number (%s) must be in format tech/number\n",deststr);
-                               pthread_exit(NULL);
+                               free(l);
+                               return DC_ERROR;
                        }
                        *tele++ = 0;
                        l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
@@ -1686,7 +1701,9 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                        l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
                        if (!l->pchan){
                                fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
-                               pthread_exit(NULL);
+                               ast_hangup(l->chan);
+                               free(l);
+                               return DC_ERROR;
                        }
                        ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
                        ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
@@ -1698,7 +1715,10 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                        if (ioctl(l->pchan->fds[0], ZT_SETCONF, &ci) == -1)
                        {
                                ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
-                               pthread_exit(NULL);
+                               ast_hangup(l->chan);
+                               ast_hangup(l->pchan);
+                               free(l);
+                               return DC_ERROR;
                        }
                        ast_mutex_lock(&myrpt->lock);
                        /* insert at end of queue */
@@ -1776,7 +1796,6 @@ static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf,
        
        if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
                myrpt->mydtmf = myrpt->funcchar;
-               ast_mutex_unlock(&myrpt->lock);
        }
        if (myrpt->callmode){
                ast_mutex_unlock(&myrpt->lock);
@@ -1872,6 +1891,10 @@ static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int comm
                        myrpt->enable = 0;
                        return DC_COMPLETE;
                        
+               case 4: /* test tone on */
+                       rpt_telemetry(myrpt, TEST_TONE, NULL);
+                       return DC_COMPLETE;
+
        }       
        return DC_INDETERMINATE;
 }
@@ -2064,8 +2087,7 @@ static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int c
                        
                        if(debug)
                                printf("@@@@ Frequency entered: %s\n", myrpt->freq);
-       
-                       
+
                        strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
                        myrpt->offset = offset;
        
@@ -2320,6 +2342,7 @@ struct    ast_frame wf;
        wf.samples = 0;
        /* put string in our buffer */
        strncpy(tmp,str,sizeof(tmp) - 1);
+
         if (!strcmp(tmp,discstr))
         {
                 mylink->disced = 1;
@@ -2390,7 +2413,7 @@ struct    ast_frame wf;
                if (ast_exists_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
                {
                        myrpt->callmode = 2;
-                       rpt_telemetry(myrpt,PROC,NULL);
+                       rpt_telemetry(myrpt,PROC,NULL); 
                }
                /* if can continue, do so */
                if (!ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL)) 
@@ -2425,7 +2448,7 @@ struct    ast_frame wf;
                        ast_mutex_lock(&myrpt->lock);
                        
                        switch(res){
-                       
+
                                case DC_INDETERMINATE:
                                        break;
                                
@@ -2845,6 +2868,7 @@ int       seq,res;
 
        /* put string in our buffer */
        strncpy(tmp,str,sizeof(tmp) - 1);
+       if (!strcmp(tmp,discstr)) return 0;
        if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
        {
                ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
@@ -2886,15 +2910,17 @@ static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
                fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
                return -1;
        }
+       ast_mutex_lock(&myrpt->lock);
+       /* remove from queue */
+       remque((struct qelem *) l);
+       ast_mutex_unlock(&myrpt->lock);
        strncpy(tmp,val,sizeof(tmp) - 1);
        s = tmp;
        s1 = strsep(&s,",");
-       ast_mutex_lock(&myrpt->lock);
        snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
        tele = strchr(deststr, '/');
        if (!tele) {
                fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
-               ast_mutex_unlock(&myrpt->lock);
                return -1;
        }
        *tele++ = 0;
@@ -2919,9 +2945,11 @@ static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
                if (option_verbose > 2)
                        ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
                                deststr,tele,l->chan->name);
-               ast_mutex_unlock(&myrpt->lock);
                return -1;
        }
+       ast_mutex_lock(&myrpt->lock);
+       /* put back in queue queue */
+       insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
        ast_mutex_unlock(&myrpt->lock);
        return 0;
 }
@@ -2996,6 +3024,7 @@ char cmd[MAXDTMF+1] = "";
                {
                        fprintf(stderr,"rpt:Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
                        ast_mutex_unlock(&myrpt->lock);
+                       ast_hangup(myrpt->rxchannel);
                        myrpt->rpt_thread = AST_PTHREADT_STOP;
                        pthread_exit(NULL);
                }
@@ -3133,6 +3162,7 @@ char cmd[MAXDTMF+1] = "";
        myrpt->callmode = 0;
        myrpt->tounkeyed = 0;
        myrpt->tonotify = 0;
+       myrpt->retxtimer = 0;
        lasttx = 0;
        keyed = 0;
        idtalkover = ast_variable_retrieve(cfg, myrpt->name, "idtalkover");
@@ -3154,11 +3184,11 @@ char cmd[MAXDTMF+1] = "";
                struct ast_channel *cs[300];
                int totx,elap,n,toexit;
 
+               ast_mutex_lock(&myrpt->lock);
                if (ast_check_hangup(myrpt->rxchannel)) break;
                if (ast_check_hangup(myrpt->txchannel)) break;
                if (ast_check_hangup(myrpt->pchannel)) break;
                if (ast_check_hangup(myrpt->txpchannel)) break;
-               ast_mutex_lock(&myrpt->lock);
                myrpt->localtx = keyed && (myrpt->dtmfidx == -1) && (!myrpt->cmdnode[0]);
                
                /* If someone's connected, and they're transmitting from their end to us, set remrx true */
@@ -3219,7 +3249,9 @@ char cmd[MAXDTMF+1] = "";
                if ((!myrpt->totimer) && (!myrpt->tonotify))
                {
                        myrpt->tonotify = 1;
+                       ast_mutex_unlock(&myrpt->lock);
                        rpt_telemetry(myrpt,TIMEOUT,NULL);
+                       ast_mutex_lock(&myrpt->lock);
                }
                /* if wants to transmit and in phone call, but timed out, 
                        reset time-out timer if keyed */
@@ -3305,6 +3337,27 @@ char cmd[MAXDTMF+1] = "";
                        myrpt->rem_dtmfidx = -1;
                        myrpt->rem_dtmfbuf[0] = 0;
                }                       
+               l = myrpt->links.next;
+               while(l != &myrpt->links)
+               {
+                       if (l->killme)
+                       {
+                               /* remove from queue */
+                               remque((struct qelem *) l);
+                               if (!strcmp(myrpt->cmdnode,l->name))
+                                       myrpt->cmdnode[0] = 0;
+                               ast_mutex_unlock(&myrpt->lock);
+                               /* hang-up on call to device */
+                               if (l->chan) ast_hangup(l->chan);
+                               ast_hangup(l->pchan);
+                               free(l);
+                               ast_mutex_lock(&myrpt->lock);
+                               /* re-start link traversal */
+                               l = myrpt->links.next;
+                               continue;
+                       }
+                       l = l->next;
+               }
                n = 0;
                cs[n++] = myrpt->rxchannel;
                cs[n++] = myrpt->pchannel;
@@ -3313,7 +3366,7 @@ char cmd[MAXDTMF+1] = "";
                l = myrpt->links.next;
                while(l != &myrpt->links)
                {
-                       if ((!l->disctime) && l->chan)
+                       if ((!l->killme) && (!l->disctime) && l->chan)
                        {
                                cs[n++] = l->chan;
                                cs[n++] = l->pchan;
@@ -3329,6 +3382,14 @@ char cmd[MAXDTMF+1] = "";
                l = myrpt->links.next;
                while(l != &myrpt->links)
                {
+                       if (!l->lasttx)
+                       {
+                               if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
+                               {
+                                       l->retxtimer = 0;
+                                       if (l->chan) ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
+                               }
+                       } else l->retxtimer = 0;
 #ifdef RECONNECT_KLUDGE
                        if (l->disctime && l->chan)
                        {
@@ -3368,7 +3429,7 @@ char cmd[MAXDTMF+1] = "";
                        }
 #ifdef RECONNECT_KLUDGE
                        if ((!l->chan) && (!l->retrytimer) && l->outbound && 
-                               (l->retries++ < MAX_RETRIES))
+                               (l->retries++ < MAX_RETRIES) && (l->hasconnected))
                        {
                                if (l->chan) ast_hangup(l->chan);
                                ast_mutex_unlock(&myrpt->lock);
@@ -3377,6 +3438,7 @@ char cmd[MAXDTMF+1] = "";
                                        l->retrytimer = RETRY_TIMER_MS;
                                }
                                ast_mutex_lock(&myrpt->lock);
+                               break;
                        }
                        if ((!l->chan) && (!l->retrytimer) && l->outbound &&
                                (l->retries >= MAX_RETRIES))
@@ -3386,10 +3448,13 @@ char cmd[MAXDTMF+1] = "";
                                if (!strcmp(myrpt->cmdnode,l->name))
                                        myrpt->cmdnode[0] = 0;
                                ast_mutex_unlock(&myrpt->lock);
-                               rpt_telemetry(myrpt,REMDISC,l);
+                               if (!l->hasconnected)
+                                       rpt_telemetry(myrpt,CONNFAIL,l);
+                               else rpt_telemetry(myrpt,REMDISC,l);
                                /* hang-up on call to device */
                                ast_hangup(l->pchan);
                                free(l);
+                                ast_mutex_lock(&myrpt->lock);
                                break;
                        }
                         if ((!l->chan) && (!l->disctime) && (!l->outbound))
@@ -3403,6 +3468,7 @@ char cmd[MAXDTMF+1] = "";
                                 /* hang-up on call to device */
                                 ast_hangup(l->pchan);
                                 free(l);
+                                ast_mutex_lock(&myrpt->lock);
                                 break;
                         }
 #endif
@@ -3441,11 +3507,14 @@ char cmd[MAXDTMF+1] = "";
                                        /* if in simple mode, kill autopatch */
                                        if (myrpt->simple && myrpt->callmode)
                                        {
+                                               ast_mutex_lock(&myrpt->lock);
                                                myrpt->callmode = 0;
+                                               ast_mutex_unlock(&myrpt->lock);
                                                rpt_telemetry(myrpt,TERM,NULL);
                                                continue;
                                        }
                                        ast_mutex_lock(&myrpt->lock);
+                                       myrpt->stopgen = 1;
                                        if (myrpt->cmdnode[0])
                                        {
                                                myrpt->cmdnode[0] = 0;
@@ -3456,8 +3525,10 @@ char cmd[MAXDTMF+1] = "";
                                        } else ast_mutex_unlock(&myrpt->lock);
                                        continue;
                                }
+                               ast_mutex_lock(&myrpt->lock);
                                if (myrpt->cmdnode[0])
                                {
+                                       ast_mutex_unlock(&myrpt->lock);
                                        send_link_dtmf(myrpt,c);
                                        continue;
                                }
@@ -3467,23 +3538,25 @@ char cmd[MAXDTMF+1] = "";
                                        {
                                                myrpt->dtmfidx = 0;
                                                myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
+                                               ast_mutex_unlock(&myrpt->lock);
                                                time(&dtmf_time);
                                                continue;
                                        } 
                                        else if ((c != myrpt->endchar) && (myrpt->dtmfidx >= 0))
                                        {
                                                time(&dtmf_time);
+                                               
                                                if (myrpt->dtmfidx < MAXDTMF)
                                                {
                                                        myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
                                                        myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
                                                        
                                                        strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1);
-                                                       ast_mutex_unlock(&myrpt->lock);
                                                        
+                                                       ast_mutex_unlock(&myrpt->lock);
                                                        res = collect_function_digits(myrpt, cmd, SOURCE_RPT);
-
                                                        ast_mutex_lock(&myrpt->lock);
+
                                                        switch(res){
                        
                                                                case DC_INDETERMINATE:
@@ -3508,19 +3581,21 @@ char cmd[MAXDTMF+1] = "";
                                                                        dtmf_time = 0;
                                                                        break;
                                                        }
-                                                       ast_mutex_unlock(&myrpt->lock);
-                                                       if(res != DC_INDETERMINATE)     
+                                                       if(res != DC_INDETERMINATE) {
+                                                               ast_mutex_unlock(&myrpt->lock);
                                                                continue;
-                                               }
+                                                       }
+                                               } 
                                        }
                                }
-                               else
+                               else /* if simple */
                                {
                                        if ((!myrpt->callmode) && (c == myrpt->funcchar))
                                        {
                                                myrpt->callmode = 1;
                                                myrpt->cidx = 0;
                                                myrpt->exten[myrpt->cidx] = 0;
+                                               ast_mutex_unlock(&myrpt->lock);
                                                pthread_attr_init(&attr);
                                                pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
                                                ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
@@ -3535,18 +3610,24 @@ char cmd[MAXDTMF+1] = "";
                                        if (ast_exists_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
                                        {
                                                myrpt->callmode = 2;
-                                               rpt_telemetry(myrpt,PROC,NULL);
+                                               ast_mutex_unlock(&myrpt->lock);
+                                               rpt_telemetry(myrpt,PROC,NULL); 
+                                               continue;
                                        }
                                        /* if can continue, do so */
-                                       if (ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL)) continue;
-                                       /* call has failed, inform user */
-                                       myrpt->callmode = 4;
+                                       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
+                                       {
+                                               /* call has failed, inform user */
+                                               myrpt->callmode = 4;
+                                       }
+                                       ast_mutex_unlock(&myrpt->lock);
                                        continue;
                                }
                                if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
                                {
                                        myrpt->mydtmf = f->subclass;
                                }
+                               ast_mutex_unlock(&myrpt->lock);
                                continue;
                        }                                               
                        else if (f->frametype == AST_FRAME_CONTROL)
@@ -3567,10 +3648,10 @@ char cmd[MAXDTMF+1] = "";
                                if (f->subclass == AST_CONTROL_RADIO_UNKEY)
                                {
                                        if (debug) printf("@@@@ rx un-key\n");
-                                       if(keyed)
+                                       if(keyed) {
                                                rpt_telemetry(myrpt,UNKEY,NULL);
+                                       }
                                        keyed = 0;
-
                                }
                        }
                        ast_frfree(f);
@@ -3621,6 +3702,7 @@ char cmd[MAXDTMF+1] = "";
                        continue;
                }
                toexit = 0;
+               ast_mutex_lock(&myrpt->lock);
                l = myrpt->links.next;
                while(l != &myrpt->links)
                {
@@ -3631,7 +3713,6 @@ char cmd[MAXDTMF+1] = "";
                        }
                        if (who == l->chan) /* if it was a read from rx */
                        {
-                               ast_mutex_lock(&myrpt->lock);
                                remrx = 0;
                                /* see if any other links are receiving */
                                m = myrpt->links.next;
@@ -3644,7 +3725,7 @@ char cmd[MAXDTMF+1] = "";
                                ast_mutex_unlock(&myrpt->lock);
                                totx = (((l->isremote) ? myrpt->localtx : 
                                        myrpt->exttx) || remrx) && l->mode;
-                               if (l->lasttx != totx)
+                               if (l->chan && (l->lasttx != totx))
                                {
                                        if (totx)
                                        {
@@ -3665,21 +3746,26 @@ char cmd[MAXDTMF+1] = "";
                                                l->disctime = DISC_TIME;
                                                ast_mutex_lock(&myrpt->lock);
                                                ast_hangup(l->chan);
-                                               ast_mutex_unlock(&myrpt->lock);
                                                l->chan = 0;
                                                break;
                                        }
 
-                                       if (l->retrytimer) break; 
-                                       if (l->outbound && (l->retries++ < MAX_RETRIES))
+                                       if (l->retrytimer) 
+                                       {
+                                               ast_mutex_lock(&myrpt->lock);
+                                               break; 
+                                       }
+                                       if (l->outbound && (l->retries++ < MAX_RETRIES) && (l->hasconnected))
                                        {
                                                ast_mutex_lock(&myrpt->lock);
                                                ast_hangup(l->chan);
+                                               l->chan = 0;
                                                ast_mutex_unlock(&myrpt->lock);
                                                if (attempt_reconnect(myrpt,l) == -1)
                                                {
                                                        l->retrytimer = RETRY_TIMER_MS;
                                                }
+                                               ast_mutex_lock(&myrpt->lock);
                                                break;
                                        }
 #endif
@@ -3689,11 +3775,14 @@ char cmd[MAXDTMF+1] = "";
                                        if (!strcmp(myrpt->cmdnode,l->name))
                                                myrpt->cmdnode[0] = 0;
                                        ast_mutex_unlock(&myrpt->lock);
-                                       rpt_telemetry(myrpt,REMDISC,l);
+                                       if (!l->hasconnected)
+                                               rpt_telemetry(myrpt,CONNFAIL,l);
+                                       else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
                                        /* hang-up on call to device */
                                        ast_hangup(l->chan);
                                        ast_hangup(l->pchan);
                                        free(l);
+                                       ast_mutex_lock(&myrpt->lock);
                                        break;
                                }
                                if (f->frametype == AST_FRAME_VOICE)
@@ -3710,6 +3799,7 @@ char cmd[MAXDTMF+1] = "";
                                        {
                                                char lconnected = l->connected;
                                                l->connected = 1;
+                                               l->hasconnected = 1;
                                                l->elaptime = -1;
                                                l->retries = 0;
                                                if (!lconnected) rpt_telemetry(myrpt,CONNECTED,l);
@@ -3735,21 +3825,25 @@ char cmd[MAXDTMF+1] = "";
                                                        l->disctime = DISC_TIME;
                                                        ast_mutex_lock(&myrpt->lock);
                                                        ast_hangup(l->chan);
-                                                       ast_mutex_unlock(&myrpt->lock);
                                                        l->chan = 0;
                                                        break;
                                                }
-
-                                               if (l->retrytimer) break;
-                                               if (l->outbound && (l->retries++ < MAX_RETRIES))
+                                               if (l->retrytimer) 
+                                               {
+                                                       ast_mutex_lock(&myrpt->lock);
+                                                       break;
+                                               }
+                                               if (l->outbound && (l->retries++ < MAX_RETRIES) && (l->hasconnected))
                                                {
                                                        ast_mutex_lock(&myrpt->lock);
                                                        ast_hangup(l->chan);
+                                                       l->chan = 0;
                                                        ast_mutex_unlock(&myrpt->lock);
                                                        if (attempt_reconnect(myrpt,l) == -1)
                                                        {
                                                                l->retrytimer = RETRY_TIMER_MS;
                                                        }
+                                                       ast_mutex_lock(&myrpt->lock);
                                                        break;
                                                }
 #endif
@@ -3759,29 +3853,35 @@ char cmd[MAXDTMF+1] = "";
                                                if (!strcmp(myrpt->cmdnode,l->name))
                                                        myrpt->cmdnode[0] = 0;
                                                ast_mutex_unlock(&myrpt->lock);
-                                               rpt_telemetry(myrpt,REMDISC,l);
+                                               if (!l->hasconnected)
+                                                       rpt_telemetry(myrpt,CONNFAIL,l);
+                                               else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
                                                /* hang-up on call to device */
                                                ast_hangup(l->chan);
                                                ast_hangup(l->pchan);
                                                free(l);
+                                               ast_mutex_lock(&myrpt->lock);
                                                break;
                                        }
                                }
                                ast_frfree(f);
+                               ast_mutex_lock(&myrpt->lock);
                                break;
                        }
                        if (who == l->pchan) 
                        {
+                               ast_mutex_unlock(&myrpt->lock);
                                f = ast_read(l->pchan);
                                if (!f)
                                {
                                        if (debug) printf("@@@@ rpt:Hung Up\n");
                                        toexit = 1;
+                                       ast_mutex_lock(&myrpt->lock);
                                        break;
                                }
                                if (f->frametype == AST_FRAME_VOICE)
                                {
-                                       ast_write(l->chan,f);
+                                       if (l->chan) ast_write(l->chan,f);
                                }
                                if (f->frametype == AST_FRAME_CONTROL)
                                {
@@ -3790,14 +3890,17 @@ char cmd[MAXDTMF+1] = "";
                                                if (debug) printf("@@@@ rpt:Hung Up\n");
                                                ast_frfree(f);
                                                toexit = 1;
+                                               ast_mutex_lock(&myrpt->lock);
                                                break;
                                        }
                                }
                                ast_frfree(f);
+                               ast_mutex_lock(&myrpt->lock);
                                break;
                        }
                        l = l->next;
                }
+               ast_mutex_unlock(&myrpt->lock);
                if (toexit) break;
                if (who == myrpt->txpchannel) /* if it was a read from remote tx */
                {
@@ -3820,11 +3923,12 @@ char cmd[MAXDTMF+1] = "";
                        continue;
                }
        }
-       ast_mutex_lock(&myrpt->lock);
+       usleep(100000);
        ast_hangup(myrpt->pchannel);
        ast_hangup(myrpt->txpchannel);
        if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
        ast_hangup(myrpt->rxchannel);
+       ast_mutex_lock(&myrpt->lock);
        l = myrpt->links.next;
        while(l != &myrpt->links)
        {
@@ -3845,7 +3949,6 @@ char cmd[MAXDTMF+1] = "";
 }
 
 
-
 static void *rpt_master(void *ignore)
 {
 char *this,*val;
@@ -3856,7 +3959,7 @@ pthread_attr_t attr;
        /* start with blank config */
        memset(&rpt_vars,0,sizeof(rpt_vars));
 
-       cfg = ast_config_load("rpt.conf");
+       cfg = ast_load("rpt.conf");
        if (!cfg) {
                ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
                pthread_exit(NULL);
@@ -3971,7 +4074,7 @@ pthread_attr_t attr;
                /* if is a remote, dont start one for it */
                if (rpt_vars[i].remote)
                {
-                       strncpy(rpt_vars[i].freq, "146.460", sizeof(rpt_vars[i].freq) - 1);
+                       strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
                        strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
                        rpt_vars[i].offset = REM_SIMPLEX;
                        rpt_vars[i].powerlevel = REM_MEDPWR;
@@ -4082,20 +4185,9 @@ static int rpt_exec(struct ast_channel *chan, void *data)
                /* if found */
                if (l != &myrpt->links) 
                {
-                        l->disctime = DISC_TIME;
-                        if (l->chan)
-                        {
-                                ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
-                                l->chan = 0;
-                        }
-                        else
-                        {
-                                remque((struct qelem *) l);
-                                if (!strcmp(myrpt->cmdnode,l->name))
-                                        myrpt->cmdnode[0] = 0;
-                                ast_hangup(l->pchan);
-                                free(l);
-                        }
+                       l->killme = 1;
+                       l->retries = MAX_RETRIES + 1;
+                       l->disced = 2;
                         ast_mutex_unlock(&myrpt->lock);
                        usleep(500000); 
                } else 
@@ -4114,6 +4206,7 @@ static int rpt_exec(struct ast_channel *chan, void *data)
                l->isremote = 0;
                l->chan = chan;
                l->connected = 1;
+               l->hasconnected = 1;
                ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
                ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
                /* allocate a pseudo-channel thru asterisk */
@@ -4150,12 +4243,12 @@ static int rpt_exec(struct ast_channel *chan, void *data)
        {
                ast_mutex_unlock(&myrpt->lock);
                usleep(500000);
-               ast_mutex_lock(&myrpt->lock);
                if (myrpt->remoteon)
                {
                        ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
                        return -1;
                }               
+               ast_mutex_lock(&myrpt->lock);
        }
        myrpt->remoteon = 1;
        if (ioperm(myrpt->iobase,1,1) == -1)
@@ -4202,6 +4295,7 @@ static int rpt_exec(struct ast_channel *chan, void *data)
                {
                        fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
                        ast_mutex_unlock(&myrpt->lock);
+                       ast_hangup(myrpt->rxchannel);
                        pthread_exit(NULL);
                }
                *tele++ = 0;
@@ -4224,6 +4318,7 @@ static int rpt_exec(struct ast_channel *chan, void *data)
                {
                        fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
                        ast_mutex_unlock(&myrpt->lock);
+                       ast_hangup(myrpt->rxchannel);
                        pthread_exit(NULL);
                }
                *--tele = '/';
@@ -4234,6 +4329,7 @@ static int rpt_exec(struct ast_channel *chan, void *data)
        }
        myrpt->remoterx = 0;
        myrpt->remotetx = 0;
+       myrpt->retxtimer = 0;
        myrpt->remoteon = 1;
        myrpt->dtmfidx = -1;
        myrpt->dtmfbuf[0] = 0;
@@ -4268,6 +4364,14 @@ static int rpt_exec(struct ast_channel *chan, void *data)
                rem_totx = keyed;
                
                
+               if ((!myrpt->remoterx) && (!myrpt->remotetx))
+               {
+                       if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
+                       {
+                               myrpt->retxtimer = 0;
+                               ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
+                       }
+               } else myrpt->retxtimer = 0;
                if (rem_totx && (!myrpt->remotetx)) /* Remote base radio TX key */
                {
                        myrpt->remotetx = 1;
@@ -4440,3 +4544,4 @@ char *key()
 {
        return ASTERISK_GPL_KEY;
 }
+