Added support for Yaesu FT-897 HF/VHF/UHF radio and other improvements
authorJim Dixon <telesistant@hotmail.com>
Mon, 22 Aug 2005 02:38:37 +0000 (02:38 +0000)
committerJim Dixon <telesistant@hotmail.com>
Mon, 22 Aug 2005 02:38:37 +0000 (02:38 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6346 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_rpt.c

index 57b43f5..1952b32 100755 (executable)
@@ -3,11 +3,11 @@
  * Asterisk -- A telephony toolkit for Linux.
  *
  * Radio Repeater / Remote Base program 
- *  version 0.27 07/09/05
+ *  version 0.28 08/21/05
  * 
  * See http://www.zapatatelephony.org/app_rpt.html
  *
- * Copyright (C) 2002-2004, Jim Dixon, WB6NIL
+ * Copyright (C) 2002-2005, Jim Dixon, WB6NIL
  *
  * Jim Dixon, WB6NIL <jim@lambdatel.com>
  * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
  *
  * remote cmds:
  *
- *  0 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
- *  1 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
- *  2 - Set Rx PL Tone HHH*D*
- *  3 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
- *  5 - Link Status
+ *  1 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
+ *  2 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
+ *  3 - Set Rx PL Tone HHH*D*
+ *  4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
+ *  5 - Link Status (long)
+ *  6 - Set operating mode M (FM, USB, LSB, AM, etc)
  *  100 - RX PL off (Default)
  *  101 - RX PL On
  *  102 - TX PL Off (Default)
  *  104 - Low Power
  *  105 - Med Power
  *  106 - Hi Power
+ *  107 - Bump Down 20 Hz
+ *  108 - Bump Down 100 Hz
+ *  109 - Bump Down 500 Hz
+ *  110 - Bump Up 20 Hz
+ *  111 - Bump Up 100 Hz
+ *  112 - Bump Up 500 Hz
+ *  113 - Scan Down Slow
+ *  114 - Scan Down Medium
+ *  115 - Scan Down Fast
+ *  116 - Scan Up Slow
+ *  117 - Scan Up Medium
+ *  118 - Scan Up Fast
+ *  119 - Transmit allowing auto-tune
+ *  140 - Link Status (brief)
  *
  *
 */
 
 #define TELEPARAMSIZE 32
 
+#define REM_SCANTIME 100
+
 
 enum {REM_OFF,REM_MONITOR,REM_TX};
 
@@ -120,6 +137,10 @@ enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT};
 
 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM};
 
+enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
+
+enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
+
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
@@ -159,7 +180,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/say.h"
 #include "asterisk/localtime.h"
 
-static  char *tdesc = "Radio Repeater / Remote Base  version 0.27  07/09/2005";
+static  char *tdesc = "Radio Repeater / Remote Base  version 0.28  08/21/2005";
 
 static char *app = "Rpt";
 
@@ -172,6 +193,8 @@ static int debug = 0;  /* Set this >0 for extra debug output */
 static int nrpts = 0;
 
 char *discstr = "!!DISCONNECT!!";
+static char *remote_rig_ft897="ft897";
+static char *remote_rig_rbi="rbi";
 
 struct ast_config *cfg;
 
@@ -283,7 +306,7 @@ static struct rpt
        struct rpt_tele tele;
        pthread_t rpt_call_thread,rpt_thread;
        time_t rem_dtmf_time,dtmf_time_rem;
-       int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx;
+       int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer;
        int mustid;
        int politeid;
        int dtmfidx,rem_dtmfidx;
@@ -296,6 +319,11 @@ static struct rpt
        char powerlevel;
        char txplon;
        char rxplon;
+       char remmode;
+       char tunerequest;
+       char hfscanmode;
+       int hfscanstatus;
+       char lastlinknode[MAXNODESTR];
        char funcchar;
        char endchar;
        char stopgen;
@@ -673,6 +701,19 @@ int        res;
        return res;
 }
 
+static int saynum(struct ast_channel *mychannel, int num)
+{
+       int res;
+       res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
+       if(!res)
+               res = ast_waitstream(mychannel, "");
+       else
+               ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
+       ast_stopstream(mychannel);
+       return res;
+}
+
+
 /* Retrieve an int from a config file */
                                                                                 
 static int retrieve_astcfgint(char *category, char *name, int min, int max, int defl)
@@ -867,7 +908,7 @@ static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
 static void *rpt_tele_thread(void *this)
 {
 ZT_CONFINFO ci;  /* conference info */
-int    res = 0,hastx,imdone = 0, unkeys_queued, x;
+int    res = 0,hastx,hasremote,imdone = 0, unkeys_queued, x;
 struct rpt_tele *mytele = (struct rpt_tele *)this;
 struct  rpt_tele *tlist;
 struct rpt *myrpt;
@@ -1018,14 +1059,17 @@ struct tm localtm;
                }
                        
                hastx = 0;
-               
+               hasremote = 0;          
                l = myrpt->links.next;
                if (l != &myrpt->links)
                {
                        ast_mutex_lock(&myrpt->lock);
                        while(l != &myrpt->links)
                        {
-                               if (l->mode) hastx++;
+                               if (l->mode) {
+                                       hastx++;
+                                       if (l->isremote) hasremote++;
+                               }
                                l = l->next;
                        }
                        ast_mutex_unlock(&myrpt->lock);
@@ -1052,6 +1096,31 @@ struct tm localtm;
                                ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);               
                }       
                        
+               if (hasremote && (!myrpt->cmdnode[0]))
+               {
+                       /* set for all to hear */
+                       ci.chan = 0;
+                       ci.confno = myrpt->conf;
+                       ci.confmode = ZT_CONF_CONFANN;
+                       /* first put the channel on the conference in announce mode */
+                       if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
+                       {
+                               ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
+                               ast_mutex_lock(&myrpt->lock);
+                               remque((struct qelem *)mytele);
+                               ast_mutex_unlock(&myrpt->lock);
+                               free(mytele);           
+                               ast_hangup(mychannel);
+                               pthread_exit(NULL);
+                       }
+                       if((ct = ast_variable_retrieve(cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
+                               ast_safe_sleep(mychannel,200);
+                               ct_copy = ast_strdupa(ct);
+                               res = telem_lookup(mychannel, myrpt->name, ct_copy);
+                               if(res)
+                                       ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);               
+                       }       
+               }
                imdone = 1;
                break;
            case REMDISC:
@@ -1579,11 +1648,12 @@ struct  rpt_link *l;
 * Internet linking function 
 */
 
-static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source)
+static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source)
 {
 
        char *val, *s, *s1, *tele;
        char tmp[300], deststr[300] = "",modechange = 0;
+       char digitbuf[MAXNODESTR];
        struct rpt_link *l;
        ZT_CONFINFO ci;  /* conference info */
 
@@ -1594,11 +1664,15 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
        if (!myrpt->enable)
                return DC_ERROR;
 
+       strncpy(digitbuf,digits,MAXNODESTR - 1);
+
        if(debug)
                printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
                
        switch(myatoi(param)){
                case 1: /* Link off */
+                       if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
+                               strcpy(digitbuf,myrpt->lastlinknode);
                        val = ast_variable_retrieve(cfg, NODES, digitbuf);
                        if (!val){
                                if(strlen(digitbuf) >= myrpt->longestnode)
@@ -1620,6 +1694,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                        if (l != &myrpt->links){ /* if found */
                                struct  ast_frame wf;
 
+                               strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
                                l->retries = MAX_RETRIES + 1;
                                l->disced = 1;
                                ast_mutex_unlock(&myrpt->lock);
@@ -1642,6 +1717,8 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                        ast_mutex_unlock(&myrpt->lock); 
                        return DC_COMPLETE;
                case 2: /* Link Monitor */
+                       if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
+                               strcpy(digitbuf,myrpt->lastlinknode);
                        val = ast_variable_retrieve(cfg, NODES, digitbuf);
                        if (!val){
                                if(strlen(digitbuf) >= myrpt->longestnode)
@@ -1677,6 +1754,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                                modechange = 1;
                        } else
                                ast_mutex_unlock(&myrpt->lock);
+                       strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
                        /* establish call in monitor mode */
                        l = malloc(sizeof(struct rpt_link));
                        if (!l){
@@ -1749,6 +1827,8 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                        rpt_telemetry(myrpt,COMPLETE,NULL);
                        return DC_COMPLETE;
                case 3: /* Link transceive */
+                       if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
+                               strcpy(digitbuf,myrpt->lastlinknode);
                        val = ast_variable_retrieve(cfg, NODES, digitbuf);
                        if (!val){
                                if(strlen(digitbuf) >= myrpt->longestnode)
@@ -1782,6 +1862,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                                modechange = 1;
                        } else
                                ast_mutex_unlock(&myrpt->lock);
+                       strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
                        /* establish call in tranceive mode */
                        l = malloc(sizeof(struct rpt_link));
                        if (!l){
@@ -1867,6 +1948,8 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                                rpt_telemetry(myrpt, REMALREADY, NULL);
                                return DC_COMPLETE;
                        }
+                       if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
+                               strcpy(digitbuf,myrpt->lastlinknode);
                        /* node must at least exist in list */
                        val = ast_variable_retrieve(cfg, NODES, digitbuf);
                        if (!val){
@@ -1876,6 +1959,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
                        
                        }
                        ast_mutex_lock(&myrpt->lock);
+                       strcpy(myrpt->lastlinknode,digitbuf);
                        strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
                        ast_mutex_unlock(&myrpt->lock);
                        rpt_telemetry(myrpt, REMGO, NULL);      
@@ -2032,891 +2116,1769 @@ static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int comm
 }
 
 /*
-* Remote base function
+* Collect digits one by one until something matches
 */
 
-static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source)
+static int collect_function_digits(struct rpt *myrpt, char *digits, int command_source)
 {
-       char *s,*s1,*s2,*val;
-       int i,j,k,l,res,offset,offsave;
-       char oc;
-       char tmp[20], freq[20] = "", savestr[20] = "";
-       struct ast_channel *mychannel;
-
-       if((!param) || (command_source != SOURCE_RMT))
-               return DC_ERROR;
-               
-       mychannel = myrpt->remchannel;
+       int i;
+       char *stringp,*action,*param,*functiondigits;
+       char function_table_name[30] = "";
+       char workstring[80];
        
+       struct ast_variable *vp;
        
-       switch(myatoi(param)){
+       if(debug)       
+               printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
+       
+       if (command_source == SOURCE_LNK)
+               strncpy(function_table_name, myrpt->link_functions, sizeof(function_table_name) - 1);
+       else
+               strncpy(function_table_name, myrpt->functions, sizeof(function_table_name) - 1);
+       vp = ast_variable_browse(cfg, function_table_name);
+       while(vp) {
+               if(!strncasecmp(vp->name, digits, strlen(vp->name)))
+                       break;
+               vp = vp->next;
+       }       
+       if(!vp) {
+               if(strlen(digits) >= ((command_source == SOURCE_LNK) ? 
+                   myrpt->link_longestfunc : myrpt->longestfunc)) /* Get out of function mode if longes func length reached */
+                       return DC_ERROR;
+               else
+                       return DC_INDETERMINATE;
+       }       
+       /* Found a match, retrieve value part and parse */
+       strncpy(workstring, vp->value, sizeof(workstring) - 1 );
+       stringp = workstring;
+       action = strsep(&stringp, ",");
+       param = stringp;
+       if(debug)
+               printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
+       /* Look up the action */
+       for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
+               if(!strncasecmp(action, function_table[i].action, strlen(action)))
+                       break;
+       }
+       if(debug)
+               printf("@@@@ table index i = %d\n",i);
+       if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
+               /* Error, action not in table */
+               return DC_ERROR;
+       }
+       if(function_table[i].function == NULL){
+               /* Error, function undefined */
+               if(debug)
+                       printf("@@@@ NULL for action: %s\n",action);
+               return DC_ERROR;
+       }
+       functiondigits = digits + strlen(vp->name);
+       return (*function_table[i].function)(myrpt, param, functiondigits, command_source);
+}
 
-               case 1:  /* retrieve memory */
-                       if(strlen(digitbuf) < 2) /* needs 2 digits */
-                               break;
-                       
-                       for(i = 0 ; i < 2 ; i++){
-                               if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
-                                       return DC_ERROR;
+
+static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
+       char *str)
+{
+char   tmp[300],cmd[300] = "",dest[300],src[300],c;
+int    seq, res;
+struct rpt_link *l;
+struct ast_frame wf;
+
+       wf.frametype = AST_FRAME_TEXT;
+       wf.subclass = 0;
+       wf.offset = 0;
+       wf.mallocd = 1;
+       wf.datalen = strlen(str) + 1;
+       wf.samples = 0;
+       /* put string in our buffer */
+       strncpy(tmp,str,sizeof(tmp) - 1);
+
+        if (!strcmp(tmp,discstr))
+        {
+                mylink->disced = 1;
+               mylink->retries = MAX_RETRIES + 1;
+                ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
+                return;
+        }
+       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);
+               return;
+       }
+       if (strcmp(cmd,"D"))
+       {
+               ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
+               return;
+       }
+       /* if not for me, redistribute to all links */
+       if (strcmp(dest,myrpt->name))
+       {
+               l = myrpt->links.next;
+               /* see if this is one in list */
+               while(l != &myrpt->links)
+               {
+                       /* dont send back from where it came */
+                       if ((l == mylink) || (!strcmp(l->name,mylink->name)))
+                       {
+                               l = l->next;
+                               continue;
                        }
-           
-                       val = ast_variable_retrieve(cfg, MEMORY, digitbuf);
-                       if (!val){
-                               if (ast_safe_sleep(mychannel,1000) == -1)
-                                       return DC_ERROR;
-                               sayfile(mychannel,"rpt/memory_notfound");
-                               return DC_COMPLETE;
-                       }                       
-                       strncpy(tmp,val,sizeof(tmp) - 1);
-                       s = strchr(tmp,',');
-                       if (!s)
-                               return DC_ERROR;
-                       *s++ = 0;
-                       s1 = strchr(s,',');
-                       if (!s1)
-                               return DC_ERROR;
-                       *s1++ = 0;
-                       strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
-                       strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
-                       myrpt->offset = REM_SIMPLEX;
-                       myrpt->powerlevel = REM_MEDPWR;
-                       myrpt->rxplon = 0;
-                       myrpt->txplon = 0;
-                       while(*s1)
+                       /* if it is, send it and we're done */
+                       if (!strcmp(l->name,dest))
                        {
-                               switch(*s1++){
-                               
-                                       case 'L':
-                                       case 'l':
-                                               myrpt->powerlevel = REM_LOWPWR;
-                                       break;
-                                       
-                                       case 'H':
-                                       case 'h':
-                                               myrpt->powerlevel = REM_HIPWR;
-                                       break;
-                                       
-                                       case 'M':
-                                       case 'm':
-                                               myrpt->powerlevel = REM_MEDPWR;
-                                               break;
-                                               
-                                       case '-':
-                                               myrpt->offset = REM_MINUS;
-                                               break;
-                                               
-                                       case '+':
-                                               myrpt->offset = REM_PLUS;
-                                               break;
-                                               
-                                       case 'S':
-                                       case 's':
-                                               myrpt->offset = REM_SIMPLEX;
-                                               break;
-                                               
-                                       case 'T':
-                                       case 't':
-                                               myrpt->txplon = 1;
-                                               break;
-                                               
-                                       case 'R':
-                                       case 'r':
-                                               myrpt->rxplon = 1;
-                                       break;
+                               /* send, but not to src */
+                               if (strcmp(l->name,src)) {
+                                       wf.data = strdup(str);
+                                       if (l->chan) ast_write(l->chan,&wf);
                                }
+                               return;
                        }
-               
-               
-                       if (setrbi(myrpt) == -1)
-                               return DC_ERROR;
-               
-               
-                       return DC_COMPLETE;     
-                       
-               case 2:  /* set freq + offset */
-          
-                       
-                       for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N+*N */
-                               if(digitbuf[i] == '*'){
-                                       j++;
-                                       continue;
-                               }
-                               if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
-                                       return DC_ERROR;
-                               else{
-                                       if(j == 0)
-                                               l++;
-                                       if(j == 1)
-                                               k++;
-                               }
+                       l = l->next;
+               }
+               l = myrpt->links.next;
+               /* otherwise, send it to all of em */
+               while(l != &myrpt->links)
+               {
+                       /* dont send back from where it came */
+                       if ((l == mylink) || (!strcmp(l->name,mylink->name)))
+                       {
+                               l = l->next;
+                               continue;
                        }
-               
-                       i = strlen(digitbuf) - 1;
-                       if((j > 2) || (l > 5) || (k > 3))
-                               return DC_ERROR; /* &$@^! */
-                       
-                       if((j < 2) || (digitbuf[i] == '*'))
-                               break; /* Not yet */
-                               
-                       strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
-                       
-                       s = tmp;
-                       s1 = strsep(&s, "*"); /* Pick off MHz */
-                       s2 = strsep(&s,"*"); /* Pick off KHz */
-                       oc = *s; /* Pick off offset */
-       
-                       
-                       switch(strlen(s2)){ /* Allow partial entry of khz digits for laziness support */
-                               case 1:
-                                       k = 100 * atoi(s2);
-                                       break;
-                               
-                               case 2:
-                                       k = 10 * atoi(s2);
-                                       break;
-                                       
-                               case 3:
-                                       if((s2[2] != '0')&&(s2[2] != '5'))
-                                               return DC_ERROR;
-                                       k = atoi(s2);
-                                       break;
-                                       
-                               default:
-                                       return DC_ERROR;
-                                       
+                       /* send, but not to src */
+                       if (strcmp(l->name,src)) {
+                               wf.data = strdup(str);
+                               if (l->chan) ast_write(l->chan,&wf);
                        }
-                               
-                                       
-                       
-                       snprintf(freq, sizeof(freq), "%s.%03d", s1, k);
-                       
-                       offset = REM_SIMPLEX;
-                       
-                       if (oc){
-                               switch(oc){
-
-                                       case '1':
-                                               offset = REM_MINUS;
-                                               break;
-                                               
-                                       case '2':
-                                               offset = REM_SIMPLEX;
-                                               break;
-                                               
-                                       case '3':
-                                               offset = REM_PLUS;
-                                               break;
-                                               
-                                       default:
-       
-                                               return DC_ERROR;
-                               } 
-                       } 
+                       l = l->next;
+               }
+               return;
+       }
+       ast_mutex_lock(&myrpt->lock);
+       if (myrpt->callmode == 1)
+       {
+               myrpt->exten[myrpt->cidx++] = c;
+               myrpt->exten[myrpt->cidx] = 0;
+               /* if this exists */
+               if (ast_exists_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
+               {
+                       myrpt->callmode = 2;
+                       rpt_telemetry(myrpt,PROC,NULL); 
+               }
+               /* if can continue, do so */
+               if (!ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL)) 
+               {
+                       /* call has failed, inform user */
+                       myrpt->callmode = 4;
+               }
+       }
+       if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
+       {
+               myrpt->mydtmf = c;
+       }
+       if (c == myrpt->funcchar)
+       {
+               myrpt->rem_dtmfidx = 0;
+               myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
+               time(&myrpt->rem_dtmf_time);
+               ast_mutex_unlock(&myrpt->lock);
+               return;
+       } 
+       else if ((c != myrpt->endchar) && (myrpt->rem_dtmfidx >= 0))
+       {
+               time(&myrpt->rem_dtmf_time);
+               if (myrpt->rem_dtmfidx < MAXDTMF)
+               {
+                       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
+                       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
                        
-                       offsave = myrpt->offset;
-                       strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
-                       strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
+                       ast_mutex_unlock(&myrpt->lock);
+                       strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
+                       res = collect_function_digits(myrpt, cmd, SOURCE_LNK);
+                       ast_mutex_lock(&myrpt->lock);
                        
-                       if(debug)
-                               printf("@@@@ Frequency entered: %s\n", myrpt->freq);
-
-                       strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
-                       myrpt->offset = offset;
-       
-                       if (setrbi(myrpt) == -1){
-                               myrpt->offset = offsave;
-                               strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
-                               return DC_ERROR;
-                       }
+                       switch(res){
 
-                       return DC_COMPLETE;
-               
-               case 3: /* set rx PL tone */
-                       
-                       for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
-                               if(digitbuf[i] == '*'){
-                                       j++;
-                                       continue;
-                               }
-                               if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
-                                       return DC_ERROR;
-                               else{
-                                       if(j)
-                                               l++;
-                                       else
-                                               k++;
-                               }
-                       }
-                       if((j > 1) || (k > 3) || (l > 1))
-                               return DC_ERROR; /* &$@^! */
-                       i = strlen(digitbuf) - 1;
-                       if((j != 1) || (k < 2)|| (l != 1))
-                               break; /* Not yet */
-                       if(debug)
-                               printf("PL digits entered %s\n", digitbuf);
-                       
-                       strncpy(tmp, digitbuf, sizeof(tmp) - 1);
-                       /* see if we have at least 1 */
-                       s = strchr(tmp,'*');
-                       if(s)
-                               *s = '.';
-                       strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
-                       strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
-                       
-                       if (setrbi(myrpt) == -1){
-                               strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
-                               return DC_ERROR;
-                       }
-               
-               
-                       return DC_COMPLETE;
-               
-               case 100: /* other stuff */
-               case 101: 
-               case 102: 
-               case 103: 
-               case 104: 
-               case 105: 
-               case 106: 
-                       switch(myatoi(param)){
-                               case 100: /* RX PL Off */
-                                       myrpt->rxplon = 0;
-                                       break;
-                                       
-                               case 101: /* RX PL On */
-                                       myrpt->rxplon = 1;
-                                       break;
-                                       
-                               case 102: /* TX PL Off */
-                                       myrpt->txplon = 0;
-                                       break;
-                                       
-                               case 103: /* TX PL On */
-                                       myrpt->txplon = 1;
-                                       break;
-                                       
-                               case 104: /* Low Power */
-                                       myrpt->powerlevel = REM_LOWPWR;
-                                       break;
-                                       
-                               case 105: /* Medium Power */
-                                       myrpt->powerlevel = REM_MEDPWR;
-                                       break;
-                                       
-                               case 106: /* Hi Power */
-                                       myrpt->powerlevel = REM_HIPWR;
-                                       break;
-                               default:
-                                       return DC_ERROR;
-                       }
-                       if (setrbi(myrpt) == -1) 
-                               return DC_ERROR;
-                       return DC_COMPLETE;
-               case 5: /* Status */
-                       myrpt->remotetx = 0;
-                       ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
-                       if (!myrpt->remoterx){
-                               ast_indicate(mychannel,AST_CONTROL_RADIO_KEY);
-                       }
-                       
-                       if (ast_safe_sleep(mychannel,1000) == -1)
-                                       return DC_ERROR;
-                       
-                       if ((sayfile(mychannel,"rpt/node") == -1) ||
-                       (saycharstr(mychannel,myrpt->name) == -1) ||
-                       (sayfile(mychannel,"rpt/frequency") == -1) ||
-                       (saycharstr(mychannel,myrpt->freq) == -1)){
-                       
-                               if (!myrpt->remoterx){
-               
-                                       ast_indicate(mychannel,AST_CONTROL_RADIO_UNKEY);
-                               }
-                               return DC_ERROR;
-                       }
-                       switch(myrpt->offset){
-       
-                               case REM_MINUS:
-                                       res = sayfile(mychannel,"rpt/minus");
+                               case DC_INDETERMINATE:
                                        break;
                                
-                               case REM_SIMPLEX:
-                                       res = sayfile(mychannel,"rpt/simplex");
+                               case DC_REQ_FLUSH:
+                                       myrpt->rem_dtmfidx = 0;
+                                       myrpt->rem_dtmfbuf[0] = 0;
                                        break;
-                                       
-                               case REM_PLUS:
-                                       res = sayfile(mychannel,"rpt/plus");
+                               
+                               
+                               case DC_COMPLETE:
+                                       myrpt->rem_dtmfbuf[0] = 0;
+                                       myrpt->rem_dtmfidx = -1;
+                                       myrpt->rem_dtmf_time = 0;
                                        break;
-                                       
+                               
+                               case DC_ERROR:
                                default:
-                                       return DC_ERROR;
-                       }
-                       if (res == -1){
-               
-                               if (!myrpt->remoterx){
-               
-                                       ast_indicate(mychannel,AST_CONTROL_RADIO_UNKEY);
-                               }
-                               return -1;
-                       }
-                       switch(myrpt->powerlevel){
-
-                               case REM_LOWPWR:
-                                       res = sayfile(mychannel,"rpt/lopwr") ;
-                                       break;
-                                       
-                               case REM_MEDPWR:
-                                       res = sayfile(mychannel,"rpt/medpwr");
-                                       break;
-                               case REM_HIPWR:
-                                       res = sayfile(mychannel,"rpt/hipwr"); 
+                                       myrpt->rem_dtmfbuf[0] = 0;
+                                       myrpt->rem_dtmfidx = -1;
+                                       myrpt->rem_dtmf_time = 0;
                                        break;
                        }
-                       if (res || (sayfile(mychannel,"rpt/rxpl") == -1) ||
-                               (sayfile(mychannel,"rpt/frequency") == -1) ||
-                               (saycharstr(mychannel,myrpt->rxpl) == -1) ||
-                               (sayfile(mychannel,"rpt/txpl") == -1) ||
-                               (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1) ||
-                               (sayfile(mychannel,"rpt/rxpl") == -1) ||
-                               (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1)){
-                               if (!myrpt->remoterx){
-                                       ast_indicate(mychannel,AST_CONTROL_RADIO_UNKEY);
-                               }
-                               return -1;
-                       }
-                       if (!myrpt->remoterx){
-                               ast_indicate(mychannel,AST_CONTROL_RADIO_UNKEY);
-                       }
-                       return DC_COMPLETE;
-                       
-               default:
-                       return DC_ERROR;
-       }
+               }
 
-       return DC_INDETERMINATE;
+       }
+       ast_mutex_unlock(&myrpt->lock);
+       return;
 }
 
-       
-/*
-* Collect digits one by one until something matches
-*/
+/* Doug Hall RBI-1 serial data definitions:
+ *
+ * Byte 0: Expansion external outputs 
+ * Byte 1: 
+ *     Bits 0-3 are BAND as follows:
+ *     Bits 4-5 are POWER bits as follows:
+ *             00 - Low Power
+ *             01 - Hi Power
+ *             02 - Med Power
+ *     Bits 6-7 are always set
+ * Byte 2:
+ *     Bits 0-3 MHZ in BCD format
+ *     Bits 4-5 are offset as follows:
+ *             00 - minus
+ *             01 - plus
+ *             02 - simplex
+ *             03 - minus minus (whatever that is)
+ *     Bit 6 is the 0/5 KHZ bit
+ *     Bit 7 is always set
+ * Byte 3:
+ *     Bits 0-3 are 10 KHZ in BCD format
+ *     Bits 4-7 are 100 KHZ in BCD format
+ * Byte 4: PL Tone code and encode/decode enable bits
+ *     Bits 0-5 are PL tone code (comspec binary codes)
+ *     Bit 6 is encode enable/disable
+ *     Bit 7 is decode enable/disable
+ */
 
-static int collect_function_digits(struct rpt *myrpt, char *digits, int command_source)
+/* take the frequency from the 10 mhz digits (and up) and convert it
+   to a band number */
+
+static int rbi_mhztoband(char *str)
 {
-       int i;
-       char *stringp,*action,*param,*functiondigits;
-       char function_table_name[30] = "";
-       char workstring[80];
-       
-       struct ast_variable *vp;
-       
-       if(debug)       
-               printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
-       
-       if (command_source == SOURCE_LNK)
-               strncpy(function_table_name, myrpt->link_functions, sizeof(function_table_name) - 1);
-       else
-               strncpy(function_table_name, myrpt->functions, sizeof(function_table_name) - 1);
-       vp = ast_variable_browse(cfg, function_table_name);
-       while(vp) {
-               if(!strncasecmp(vp->name, digits, strlen(vp->name)))
-                       break;
-               vp = vp->next;
-       }       
-       if(!vp) {
-               if(strlen(digits) >= ((command_source == SOURCE_LNK) ? 
-                   myrpt->link_longestfunc : myrpt->longestfunc)) /* Get out of function mode if longes func length reached */
-                       return DC_ERROR;
-               else
-                       return DC_INDETERMINATE;
-       }       
-       /* Found a match, retrieve value part and parse */
-       strncpy(workstring, vp->value, sizeof(workstring) - 1 );
-       stringp = workstring;
-       action = strsep(&stringp, ",");
-       param = stringp;
-       if(debug)
-               printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
-       /* Look up the action */
-       for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
-               if(!strncasecmp(action, function_table[i].action, strlen(action)))
-                       break;
-       }
-       if(debug)
-               printf("@@@@ table index i = %d\n",i);
-       if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
-               /* Error, action not in table */
-               return DC_ERROR;
-       }
-       if(function_table[i].function == NULL){
-               /* Error, function undefined */
-               if(debug)
-                       printf("@@@@ NULL for action: %s\n",action);
-               return DC_ERROR;
+int    i;
+
+       i = atoi(str) / 10; /* get the 10's of mhz */
+       switch(i)
+       {
+           case 2:
+               return 10;
+           case 5:
+               return 11;
+           case 14:
+               return 2;
+           case 22:
+               return 3;
+           case 44:
+               return 4;
+           case 124:
+               return 0;
+           case 125:
+               return 1;
+           case 126:
+               return 8;
+           case 127:
+               return 5;
+           case 128:
+               return 6;
+           case 129:
+               return 7;
+           default:
+               break;
        }
-       functiondigits = digits + strlen(vp->name);
-       return (*function_table[i].function)(myrpt, param, functiondigits, command_source);
+       return -1;
 }
 
-
-static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
-       char *str)
+/* take a PL frequency and turn it into a code */
+static int rbi_pltocode(char *str)
 {
-char   tmp[300],cmd[300] = "",dest[300],src[300],c;
-int    seq, res;
-struct rpt_link *l;
-struct ast_frame wf;
-
-       wf.frametype = AST_FRAME_TEXT;
-       wf.subclass = 0;
-       wf.offset = 0;
-       wf.mallocd = 1;
-       wf.datalen = strlen(str) + 1;
-       wf.samples = 0;
-       /* put string in our buffer */
-       strncpy(tmp,str,sizeof(tmp) - 1);
+int i;
+char *s;
 
-        if (!strcmp(tmp,discstr))
-        {
-                mylink->disced = 1;
-               mylink->retries = MAX_RETRIES + 1;
-                ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
-                return;
-        }
-       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);
-               return;
-       }
-       if (strcmp(cmd,"D"))
+       s = strchr(str,'.');
+       i = 0;
+       if (s) i = atoi(s + 1);
+       i += atoi(str) * 10;
+       switch(i)
        {
-               ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
-               return;
+           case 670:
+               return 0;
+           case 719:
+               return 1;
+           case 744:
+               return 2;
+           case 770:
+               return 3;
+           case 797:
+               return 4;
+           case 825:
+               return 5;
+           case 854:
+               return 6;
+           case 885:
+               return 7;
+           case 915:
+               return 8;
+           case 948:
+               return 9;
+           case 974:
+               return 10;
+           case 1000:
+               return 11;
+           case 1035:
+               return 12;
+           case 1072:
+               return 13;
+           case 1109:
+               return 14;
+           case 1148:
+               return 15;
+           case 1188:
+               return 16;
+           case 1230:
+               return 17;
+           case 1273:
+               return 18;
+           case 1318:
+               return 19;
+           case 1365:
+               return 20;
+           case 1413:
+               return 21;
+           case 1462:
+               return 22;
+           case 1514:
+               return 23;
+           case 1567:
+               return 24;
+           case 1622:
+               return 25;
+           case 1679:
+               return 26;
+           case 1738:
+               return 27;
+           case 1799:
+               return 28;
+           case 1862:
+               return 29;
+           case 1928:
+               return 30;
+           case 2035:
+               return 31;
+           case 2107:
+               return 32;
+           case 2181:
+               return 33;
+           case 2257:
+               return 34;
+           case 2336:
+               return 35;
+           case 2418:
+               return 36;
+           case 2503:
+               return 37;
        }
-       /* if not for me, redistribute to all links */
-       if (strcmp(dest,myrpt->name))
-       {
-               l = myrpt->links.next;
-               /* see if this is one in list */
-               while(l != &myrpt->links)
-               {
-                       /* dont send back from where it came */
-                       if ((l == mylink) || (!strcmp(l->name,mylink->name)))
+       return -1;
+}
+
+/*
+* Shift out a formatted serial bit stream
+*/
+
+static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
+    {
+    int i,j;
+    unsigned char od,d;
+    static volatile long long delayvar;
+
+    for(i = 0 ; i < 5 ; i++){
+        od = *data++; 
+        for(j = 0 ; j < 8 ; j++){
+            d = od & 1;
+            outb(d,myrpt->iobase);
+           /* >= 15 us */
+           for(delayvar = 1; delayvar < 15000; delayvar++); 
+            od >>= 1;
+            outb(d | 2,myrpt->iobase);
+           /* >= 30 us */
+           for(delayvar = 1; delayvar < 30000; delayvar++); 
+            outb(d,myrpt->iobase);
+           /* >= 10 us */
+           for(delayvar = 1; delayvar < 10000; delayvar++); 
+            }
+        }
+       /* >= 50 us */
+        for(delayvar = 1; delayvar < 50000; delayvar++); 
+    }
+
+static void rbi_out(struct rpt *myrpt,unsigned char *data)
+{
+struct zt_radio_param r;
+
+       memset(&r,0,sizeof(struct zt_radio_param));
+       r.radpar = ZT_RADPAR_REMMODE;
+       r.data = ZT_RADPAR_REM_RBI1;
+       /* if setparam ioctl fails, its probably not a pciradio card */
+       if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
+       {
+               rbi_out_parallel(myrpt,data);
+               return;
+       }
+       r.radpar = ZT_RADPAR_REMCOMMAND;
+       memcpy(&r.data,data,5);
+       if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
+       {
+               ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->rxchannel->name);
+               return;
+       }
+}
+
+static int serial_remote_io(struct rpt *myrpt, char *txbuf, int txbytes, char *rxbuf,
+        int rxmaxbytes, int asciiflag)
+{
+       int i;
+       struct zt_radio_param prm;
+
+       if(debug){
+               printf("String output was: ");
+               for(i = 0; i < txbytes; i++)
+                       printf("%02X ", (unsigned char ) txbuf[i]);
+               printf("\n");
+       }
+
+        prm.radpar = ZT_RADPAR_REMMODE;
+        if (asciiflag)  prm.data = ZT_RADPAR_REM_SERIAL_ASCII;
+        else prm.data = ZT_RADPAR_REM_SERIAL;
+       if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
+        prm.radpar = ZT_RADPAR_REMCOMMAND;
+        prm.data = rxmaxbytes;
+        memcpy(prm.buf,txbuf,txbytes);
+        prm.index = txbytes;
+       if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
+        if (rxbuf)
+        {
+                *rxbuf = 0;
+                memcpy(rxbuf,prm.buf,prm.index);
+        }
+        return(prm.index);
+}
+
+static int setrbi(struct rpt *myrpt)
+{
+char tmp[MAXREMSTR] = "",rbicmd[5],*s;
+int    band,txoffset = 0,txpower = 0,txpl;
+
+       /* must be a remote system */
+       if (!myrpt->remote) return(0);
+       /* must have rbi hardware */
+       if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
+       strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
+       s = strchr(tmp,'.');
+       /* if no decimal, is invalid */
+       
+       if (s == NULL){
+               if(debug)
+                       printf("@@@@ Frequency needs a decimal\n");
+               return -1;
+       }
+       
+       *s++ = 0;
+       if (strlen(tmp) < 2){
+               if(debug)
+                       printf("@@@@ Bad MHz digits: %s\n", tmp);
+               return -1;
+       }
+        
+       if (strlen(s) < 3){
+               if(debug)
+                       printf("@@@@ Bad KHz digits: %s\n", s);
+               return -1;
+       }
+
+       if ((s[2] != '0') && (s[2] != '5')){
+               if(debug)
+                       printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
+               return -1;
+       }
+        
+       band = rbi_mhztoband(tmp);
+       if (band == -1){
+               if(debug)
+                       printf("@@@@ Bad Band: %s\n", tmp);
+               return -1;
+       }
+       
+       txpl = rbi_pltocode(myrpt->txpl);
+       
+       if (txpl == -1){
+               if(debug)
+                       printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
+               return -1;
+       }
+
+       
+       switch(myrpt->offset)
+       {
+           case REM_MINUS:
+               txoffset = 0;
+               break;
+           case REM_PLUS:
+               txoffset = 0x10;
+               break;
+           case REM_SIMPLEX:
+               txoffset = 0x20;
+               break;
+       }
+       switch(myrpt->powerlevel)
+       {
+           case REM_LOWPWR:
+               txpower = 0;
+               break;
+           case REM_MEDPWR:
+               txpower = 0x20;
+               break;
+           case REM_HIPWR:
+               txpower = 0x10;
+               break;
+       }
+       rbicmd[0] = 0;
+       rbicmd[1] = band | txpower | 0xc0;
+       rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
+       if (s[2] == '5') rbicmd[2] |= 0x40;
+       rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
+       rbicmd[4] = txpl;
+       if (myrpt->txplon) rbicmd[4] |= 0x40;
+       if (myrpt->rxplon) rbicmd[4] |= 0x80;
+       rbi_out(myrpt,rbicmd);
+       return 0;
+}
+
+
+/* Check for valid rbi frequency */
+/* Hard coded limits now, configurable later, maybe? */
+
+static int check_freq_rbi(int m, int d)
+{
+       if(m == 50){ /* 6 meters */
+               if(d < 10100)
+                       return -1;
+       }
+       else if((m >= 51) && ( m < 54)){
+                ;
+       }
+       else if(m == 144){ /* 2 meters */
+               if(d < 10100)
+                       return -1;
+       }
+       else if((m >= 145) && (m < 148)){
+               ;
+       }
+       else if((m >= 222) && (m < 225)){ /* 1.25 meters */
+               ;
+       }
+       else if((m >= 430) && (m < 450)){ /* 70 centimeters */
+               ;
+       }
+       else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
+               ;
+       }
+       else
+               return -1;
+       return 0;
+}
+
+/*
+* Split frequency into mhz and decimals
+*/
+static int split_freq(char *mhz, char *decimals, char *freq)
+{
+       char freq_copy[MAXREMSTR];
+       char *decp;
+
+       decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
+       if(decp){
+               *decp++ = 0;
+               strncpy(mhz, freq_copy, MAXREMSTR);
+               strcpy(decimals, "00000");
+               strncpy(decimals, decp, strlen(decp));
+               decimals[5] = 0;
+               return 0;
+       }
+       else
+               return -1;
+
+}
+       
+/*
+* FT-897 I/O handlers
+*/
+
+/* Check to see that the frequency is valid */
+/* Hard coded limits now, configurable later, maybe? */
+
+
+static int check_freq_ft897(int m, int d)
+{
+
+       if(m == 1){ /* 160 meters */
+               if(d < 80001)
+                       return -1;
+       }
+       else if(m == 3){ /* 80 meters */
+               if(d < 75001)
+                       return -1;
+       }
+       else if(m == 7){ /* 40 meters */
+               if((d < 71501) || (d > 72999))
+                       return -1;
+       }
+       else if(m == 14){ /* 20 meters */
+               if((d < 15001) || (d > 34999))
+                       return -1;
+       }
+       else if(m == 18){ /* 17 meters */
+               if((d < 11001) || (d > 11679))
+                       return -1;
+       }
+       else if(m == 21){ /* 15 meters */
+               if((d < 20001) || (d > 44999))
+                       return -1;
+       }
+       else if(m == 24){ /* 12 meters */
+               if((d < 93001) || (d > 98999))
+                       return -1;
+       }
+       else if(m == 28){ /* 10 meters */
+               if(d < 30001)
+                       return -1;
+       }
+       else if(m == 29){ 
+               if(d > 69999)
+                       return -1;
+       }
+       else if(m == 50){ /* 6 meters */
+               if(d < 10100)
+                       return -1;
+       }
+       else if((m >= 51) && ( m < 54)){
+               ;
+       }
+       else if(m == 144){ /* 2 meters */
+               if(d < 10100)
+                       return -1;
+       }
+       else if((m >= 145) && (m < 148)){
+               ;
+       }
+       else if((m >= 430) && (m < 450)){ /* 70 centimeters */
+               ;
+       }
+       else
+               return -1;
+       return 0;
+}
+
+/*
+* Set a new frequency for the FT897
+*/
+
+static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
+{
+       char mhz[MAXREMSTR];
+       char decimals[MAXREMSTR];
+       unsigned char cmdstr[5];
+       int fd,m,d;
+
+       fd = 0;
+       if(debug) 
+               printf("New frequency: %s\n",newfreq);
+
+       if(split_freq(mhz, decimals, newfreq))
+               return -1; 
+
+       m = atoi(mhz);
+       d = atoi(decimals);
+
+       /* The FT-897 likes packed BCD frequencies */
+
+       cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10);                  /* 100MHz 10Mhz */
+       cmdstr[1] = ((m % 10) << 4) + (d / 10000);                      /* 1MHz 100KHz */
+       cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100);      /* 10KHz 1KHz */
+       cmdstr[3] = (((d % 100)/10) << 4) + (d % 10);                   /* 100Hz 10Hz */
+       cmdstr[4] = 0x01;                                               /* command */
+
+       return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
+
+}
+
+/* ft-897 simple commands */
+
+static int simple_command_ft897(struct rpt *myrpt, char command)
+{
+       unsigned char cmdstr[5];
+       
+       memset(cmdstr, 0, 5);
+
+       cmdstr[4] = command;    
+
+       return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
+
+}
+
+/* ft-897 offset */
+
+static int set_offset_ft897(struct rpt *myrpt, char offset)
+{
+       unsigned char cmdstr[5];
+       
+       memset(cmdstr, 0, 5);
+
+       switch(offset){
+               case    REM_SIMPLEX:
+                       cmdstr[0] = 0x89;
+                       break;
+
+               case    REM_MINUS:
+                       cmdstr[0] = 0x09;
+                       break;
+               
+               case    REM_PLUS:
+                       cmdstr[0] = 0x49;
+                       break;  
+
+               default:
+                       return -1;
+       }
+
+       cmdstr[4] = 0x09;       
+
+       return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
+}
+
+/* ft-897 mode */
+
+static int set_mode_ft897(struct rpt *myrpt, char newmode)
+{
+       unsigned char cmdstr[5];
+       
+       memset(cmdstr, 0, 5);
+       
+       switch(newmode){
+               case    REM_MODE_FM:
+                       cmdstr[0] = 0x08;
+                       break;
+
+               case    REM_MODE_USB:
+                       cmdstr[0] = 0x01;
+                       break;
+
+               case    REM_MODE_LSB:
+                       cmdstr[0] = 0x00;
+                       break;
+
+               case    REM_MODE_AM:
+                       cmdstr[0] = 0x04;
+                       break;
+               
+               default:
+                       return -1;
+       }
+       cmdstr[4] = 0x07;       
+
+       return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
+}
+
+/* Set tone encode and decode modes */
+
+static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
+{
+       unsigned char cmdstr[5];
+       
+       memset(cmdstr, 0, 5);
+       
+       if(rxplon && txplon)
+               cmdstr[0] = 0x2A; /* Encode and Decode */
+       else if (!rxplon && txplon)
+               cmdstr[0] = 0x4A; /* Encode only */
+       else if (rxplon && !txplon)
+               cmdstr[0] = 0x3A; /* Encode only */
+       else
+               cmdstr[0] = 0x8A; /* OFF */
+
+       cmdstr[4] = 0x0A;       
+
+       return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
+}
+
+
+/* Set transmit and receive ctcss tone frequencies */
+
+static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
+{
+       unsigned char cmdstr[5];
+       char hertz[MAXREMSTR],decimals[MAXREMSTR];
+       int h,d;        
+
+
+       memset(cmdstr, 0, 5);
+
+       if(split_freq(hertz, decimals, txtone))
+               return -1; 
+
+       h = atoi(hertz);
+       d = atoi(decimals);
+       
+       cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
+       cmdstr[1] = ((h % 10) << 4) + (d % 10);
+       
+       if(rxtone){
+       
+               if(split_freq(hertz, decimals, rxtone))
+                       return -1; 
+
+               h = atoi(hertz);
+               d = atoi(decimals);
+       
+               cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
+               cmdstr[3] = ((h % 10) << 4) + (d % 10);
+       }
+       cmdstr[4] = 0x0B;       
+
+       return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
+}      
+
+
+
+static int set_ft897(struct rpt *myrpt)
+{
+       int res;
+       
+       if(debug)
+               printf("@@@@ lock on\n");
+
+       res = simple_command_ft897(myrpt, 0x00);                                /* LOCK on */   
+
+       if(debug)
+               printf("@@@@ ptt off\n");
+
+       if(!res)
+               res = simple_command_ft897(myrpt, 0x88);                /* PTT off */
+
+       if(debug)
+               printf("Modulation mode\n");
+
+       if(!res)
+               res = set_mode_ft897(myrpt, myrpt->remmode);            /* Modulation mode */
+
+       if(debug)
+               printf("Split off\n");
+
+       if(!res)
+               simple_command_ft897(myrpt, 0x82);                      /* Split off */
+
+       if(debug)
+               printf("Frequency\n");
+
+       if(!res)
+               res = set_freq_ft897(myrpt, myrpt->freq);               /* Frequency */
+       if((myrpt->remmode == REM_MODE_FM)){
+               if(debug)
+                       printf("Offset\n");
+               if(!res)
+                       res = set_offset_ft897(myrpt, myrpt->offset);   /* Offset if FM */
+               if((!res)&&(myrpt->rxplon || myrpt->txplon)){
+                       if(debug)
+                               printf("CTCSS tone freqs.\n");
+                       res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
+               }
+               if(!res){
+                       if(debug)
+                               printf("CTCSS mode\n");
+                       res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
+               }
+       }
+       if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
+               if(debug)
+                       printf("Clarifier off\n");
+               simple_command_ft897(myrpt, 0x85);                      /* Clarifier off if LSB or USB */
+       }
+       return res;
+}
+
+static int closerem_ft897(struct rpt *myrpt)
+{
+       simple_command_ft897(myrpt, 0x88); /* PTT off */
+       return 0;
+}      
+
+/*
+* Bump frequency up or down by a small amount 
+* Return 0 if the new frequnecy is valid, or -1 if invalid
+* Interval is in Hz, resolution is 10Hz 
+*/
+
+static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
+{
+       int m,d;
+       char mhz[MAXREMSTR], decimals[MAXREMSTR];
+
+       if(debug)
+               printf("Before bump: %s\n", myrpt->freq);
+
+       if(split_freq(mhz, decimals, myrpt->freq))
+               return -1;
+       
+       m = atoi(mhz);
+       d = atoi(decimals);
+
+       d += (interval / 10); /* 10Hz resolution */
+       if(d < 0){
+               m--;
+               d += 100000;
+       }
+       else if(d >= 100000){
+               m++;
+               d -= 100000;
+       }
+
+       if(check_freq_ft897(m, d)){
+               if(debug)
+                       printf("Bump freq invalid\n");
+               return -1;
+       }
+
+       snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
+
+       if(debug)
+               printf("After bump: %s\n", myrpt->freq);
+
+       return set_freq_ft897(myrpt, myrpt->freq);      
+}
+
+
+
+/*
+* Dispatch to correct I/O handler 
+*/
+
+static int setrem(struct rpt *myrpt)
+{
+       if(!strcmp(myrpt->remote, remote_rig_ft897))
+               return set_ft897(myrpt);
+       else if(!strcmp(myrpt->remote, remote_rig_rbi))
+               return setrbi(myrpt);
+       else
+               return -1;
+}
+
+static int closerem(struct rpt *myrpt)
+{
+       if(!strcmp(myrpt->remote, remote_rig_ft897))
+               return closerem_ft897(myrpt);
+       else
+               return 0;
+}
+
+/*
+* Dispatch to correct frequency checker
+*/
+
+static int check_freq(struct rpt *myrpt, int m, int d)
+{
+       if(!strcmp(myrpt->remote, remote_rig_ft897))
+               return check_freq_ft897(m, d);
+       else if(!strcmp(myrpt->remote, remote_rig_rbi))
+               return check_freq_rbi(m, d);
+       else
+               return -1;
+}
+
+/*
+* Return 1 if rig is multimode capable
+*/
+
+static int multimode_capable(struct rpt *myrpt)
+{
+       if(!strcmp(myrpt->remote, remote_rig_ft897))
+               return 1;
+       return 0;
+}      
+
+/*
+* Dispatch to correct frequency bumping function
+*/
+
+static int multimode_bump_freq(struct rpt *myrpt, int interval)
+{
+       if(!strcmp(myrpt->remote, remote_rig_ft897))
+               return multimode_bump_freq_ft897(myrpt, interval);
+       else
+               return -1;
+}
+
+
+/*
+* Queue announcment that scan has been stopped 
+*/
+
+static void stop_scan(struct rpt *myrpt, int flag)
+{
+       myrpt->hfscanmode = 0;
+       myrpt->hfscanstatus = ((flag) ? -2 : -1);
+}
+
+/*
+* This is called periodically when in scan mode
+*/
+
+
+static int service_scan(struct rpt *myrpt)
+{
+       int res, interval;
+       char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
+
+       switch(myrpt->hfscanmode){
+
+               case HF_SCAN_DOWN_SLOW:
+                       interval = -10; /* 100Hz /sec */
+                       break;
+
+               case HF_SCAN_DOWN_QUICK:
+                       interval = -50; /* 500Hz /sec */
+                       break;
+
+               case HF_SCAN_DOWN_FAST:
+                       interval = -200; /* 2KHz /sec */
+                       break;
+
+               case HF_SCAN_UP_SLOW:
+                       interval = 10; /* 100Hz /sec */
+                       break;
+
+               case HF_SCAN_UP_QUICK:
+                       interval = 50; /* 500 Hz/sec */
+                       break;
+
+               case HF_SCAN_UP_FAST:
+                       interval = 200; /* 2KHz /sec */
+                       break;
+
+               default:
+                       myrpt->hfscanmode = 0; /* Huh? */
+                       return -1;
+       }
+
+       res = split_freq(mhz, decimals, myrpt->freq);
+               
+       if(!res){
+               k100 =decimals[0];
+               k10 = decimals[1];
+               res = multimode_bump_freq(myrpt, interval);
+       }
+
+       if(!res)
+               res = split_freq(mhz, decimals, myrpt->freq);
+
+
+       if(res){
+               stop_scan(myrpt,1);
+               return -1;
+       }
+
+       /* Announce 10KHz boundaries */
+       if(k10 != decimals[1]){
+               int myhund = (interval < 0) ? k100 : decimals[0];
+               int myten = (interval < 0) ? k10 : decimals[1];
+               myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
+       }
+       return res;
+
+}
+
+
+
+/*
+* Remote base function
+*/
+
+static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source)
+{
+       char *s,*s1,*s2,*val;
+       int i,j,ht,k,l,ls2,m,d,res,offset,offsave;
+       char multimode = 0;
+       char oc;
+       char tmp[20], freq[20] = "", savestr[20] = "";
+       char mhz[MAXREMSTR], decimals[MAXREMSTR];
+       struct ast_channel *mychannel;
+
+       if((!param) || (command_source != SOURCE_RMT))
+               return DC_ERROR;
+               
+
+       multimode = multimode_capable(myrpt);
+
+       mychannel = myrpt->remchannel;
+       
+       
+       switch(myatoi(param)){
+
+               case 1:  /* retrieve memory */
+                       if(strlen(digitbuf) < 2) /* needs 2 digits */
+                               break;
+                       
+                       for(i = 0 ; i < 2 ; i++){
+                               if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
+                                       return DC_ERROR;
+                       }
+           
+                       val = ast_variable_retrieve(cfg, MEMORY, digitbuf);
+                       if (!val){
+                               if (ast_safe_sleep(mychannel,1000) == -1)
+                                       return DC_ERROR;
+                               sayfile(mychannel,"rpt/memory_notfound");
+                               return DC_COMPLETE;
+                       }                       
+                       strncpy(tmp,val,sizeof(tmp) - 1);
+                       s = strchr(tmp,',');
+                       if (!s)
+                               return DC_ERROR;
+                       *s++ = 0;
+                       s1 = strchr(s,',');
+                       if (!s1)
+                               return DC_ERROR;
+                       *s1++ = 0;
+                       strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
+                       strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
+                       strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
+                       myrpt->remmode = REM_MODE_FM;
+                       myrpt->offset = REM_SIMPLEX;
+                       myrpt->powerlevel = REM_MEDPWR;
+                       myrpt->txplon = myrpt->rxplon = 0;
+                       while(*s1)
                        {
-                               l = l->next;
-                               continue;
+                               switch(*s1++){
+                                       case 'A':
+                                       case 'a':
+                                               strcpy(myrpt->rxpl, "100.0");
+                                               strcpy(myrpt->txpl, "100.0");
+                                               myrpt->remmode = REM_MODE_AM;   
+                                               break;
+                                       
+                                       case 'B':
+                                       case 'b':
+                                               strcpy(myrpt->rxpl, "100.0");
+                                               strcpy(myrpt->txpl, "100.0");
+                                               myrpt->remmode = REM_MODE_LSB;
+                                               break;
+                       
+                                       case 'F':
+                                               myrpt->remmode = REM_MODE_FM;
+                                               break;
+
+                                       case 'L':
+                                       case 'l':
+                                               myrpt->powerlevel = REM_LOWPWR;
+                                               break;                                  
+                                       case 'H':
+                                       case 'h':
+                                               myrpt->powerlevel = REM_HIPWR;
+                                               break;
+                                       
+                                       case 'M':
+                                       case 'm':
+                                               myrpt->powerlevel = REM_MEDPWR;
+                                               break;
+                                               
+                                       case '-':
+                                               myrpt->offset = REM_MINUS;
+                                               break;
+                                               
+                                       case '+':
+                                               myrpt->offset = REM_PLUS;
+                                               break;
+                                               
+                                       case 'S':
+                                       case 's':
+                                               myrpt->offset = REM_SIMPLEX;
+                                               break;
+                                               
+                                       case 'T':
+                                       case 't':
+                                               myrpt->txplon = 1;
+                                               break;
+                                               
+                                       case 'R':
+                                       case 'r':
+                                               myrpt->rxplon = 1;
+                                               break;
+
+                                       case 'U':
+                                       case 'u':
+                                               strcpy(myrpt->rxpl, "100.0");
+                                               strcpy(myrpt->txpl, "100.0");
+                                               myrpt->remmode = REM_MODE_USB;
+                                               break;
+                               }
                        }
-                       /* if it is, send it and we're done */
-                       if (!strcmp(l->name,dest))
-                       {
-                               /* send, but not to src */
-                               if (strcmp(l->name,src)) {
-                                       wf.data = strdup(str);
-                                       if (l->chan) ast_write(l->chan,&wf);
+               
+               
+                       if (setrem(myrpt) == -1)
+                               return DC_ERROR;
+               
+               
+                       return DC_COMPLETE;     
+                       
+               case 2:  /* set freq and offset */
+          
+                       
+                       for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N+*N or N+*N+* depending on mode */
+                               if(digitbuf[i] == '*'){
+                                       j++;
+                                       continue;
+                               }
+                               if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
+                                       return DC_ERROR;
+                               else{
+                                       if(j == 0)
+                                               l++; /* # of digits before first * */
+                                       if(j == 1)
+                                               k++; /* # of digits after first * */
                                }
-                               return;
                        }
-                       l = l->next;
-               }
-               l = myrpt->links.next;
-               /* otherwise, send it to all of em */
-               while(l != &myrpt->links)
-               {
-                       /* dont send back from where it came */
-                       if ((l == mylink) || (!strcmp(l->name,mylink->name)))
-                       {
-                               l = l->next;
-                               continue;
+               
+                       i = strlen(digitbuf) - 1;
+                       if(multimode){
+                               if((j > 2) || (l > 3) || (k > 6))
+                                       return DC_ERROR; /* &^@#! */
+                       }
+                       else{
+                               if((j > 2) || (l > 4) || (k > 3))
+                                       return DC_ERROR; /* &^@#! */
                        }
-                       /* send, but not to src */
-                       if (strcmp(l->name,src)) {
-                               wf.data = strdup(str);
-                               if (l->chan) ast_write(l->chan,&wf);
+
+                       /* For FM modulation mode, we require M+*K+*O, for other modulation modes M+*K+* will suffice */
+
+                       if((j < 2) || ((myrpt->remmode == REM_MODE_FM) && (digitbuf[i] == '*')))
+                               break; /* Not yet */
+
+                       strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
+                       
+                       s = tmp;
+                       s1 = strsep(&s, "*"); /* Pick off MHz */
+                       s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
+                       oc = *s; /* Pick off offset */
+                       ls2 = strlen(s2);       
+
+                       
+                       switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
+                               case 1:
+                                       ht = 0;
+                                       k = 100 * atoi(s2);
+                                       break;
+                               
+                               case 2:
+                                       ht = 0;
+                                       k = 10 * atoi(s2);
+                                       break;
+                                       
+                               case 3:
+                                       if(!multimode){
+                                               if((s2[2] != '0')&&(s2[2] != '5'))
+                                                       return DC_ERROR;
+                                       }
+                                       ht = 0;
+                                       k = atoi(s2);
+                                               break;
+                               case 4:
+                                       k = atoi(s2)/10;
+                                       ht = 10 * (atoi(s2+(ls2-1)));
+                                       break;
+
+                               case 5:
+                                       k = atoi(s2)/100;
+                                       ht = (atoi(s2+(ls2-2)));
+                                       break;
+                                       
+                               default:
+                                       return DC_ERROR;
+                                       
                        }
-                       l = l->next;
-               }
-               return;
-       }
-       ast_mutex_lock(&myrpt->lock);
-       if (myrpt->callmode == 1)
-       {
-               myrpt->exten[myrpt->cidx++] = c;
-               myrpt->exten[myrpt->cidx] = 0;
-               /* if this exists */
-               if (ast_exists_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
-               {
-                       myrpt->callmode = 2;
-                       rpt_telemetry(myrpt,PROC,NULL); 
-               }
-               /* if can continue, do so */
-               if (!ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL)) 
-               {
-                       /* call has failed, inform user */
-                       myrpt->callmode = 4;
-               }
-       }
-       if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
-       {
-               myrpt->mydtmf = c;
-       }
-       if (c == myrpt->funcchar)
-       {
-               myrpt->rem_dtmfidx = 0;
-               myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
-               time(&myrpt->rem_dtmf_time);
-               ast_mutex_unlock(&myrpt->lock);
-               return;
-       } 
-       else if ((c != myrpt->endchar) && (myrpt->rem_dtmfidx >= 0))
-       {
-               time(&myrpt->rem_dtmf_time);
-               if (myrpt->rem_dtmfidx < MAXDTMF)
-               {
-                       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
-                       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
+                               
+
                        
-                       ast_mutex_unlock(&myrpt->lock);
-                       strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
-                       res = collect_function_digits(myrpt, cmd, SOURCE_LNK);
-                       ast_mutex_lock(&myrpt->lock);
+                       snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
+                       if(debug)
+                               printf("New frequency: %s\n", freq);            
+       
+                       split_freq(mhz, decimals, freq);
+                       m = atoi(mhz);
+                       d = atoi(decimals);
+
+                        if(check_freq(myrpt, m, d)) /* Check to see if frequency entered is legit */
+                                return DC_ERROR;
+
+                       if((myrpt->remmode == REM_MODE_FM) && (m < 29)) /* FM not allowed below 29 MHZ */
+                               return DC_ERROR;
+
+                       offset = REM_SIMPLEX;
                        
-                       switch(res){
+                       if (oc){
+                               switch(oc){
+                                       case '1':
+                                               offset = REM_MINUS;
+                                               break;
+                                               
+                                       case '2':
+                                       case 0:
+                                               offset = REM_SIMPLEX;
+                                               break;
+                                               
+                                       case '3':
+                                               offset = REM_PLUS;
+                                               break;
+                                               
+                                       default:
+       
+                                               return DC_ERROR;
+                               } 
+                       } 
+                       
+                       offsave = myrpt->offset;
+                       strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
+                       strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
+                       
+                       myrpt->offset = offset;
+       
+                       if (setrem(myrpt) == -1){
+                               myrpt->offset = offsave;
+                               strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
+                               return DC_ERROR;
+                       }
+
+                       return DC_COMPLETE;
+               
+               case 3: /* set tx PL tone */
+                       
+                       for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
+                               if(digitbuf[i] == '*'){
+                                       j++;
+                                       continue;
+                               }
+                               if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
+                                       return DC_ERROR;
+                               else{
+                                       if(j)
+                                               l++;
+                                       else
+                                               k++;
+                               }
+                       }
+                       if((j > 1) || (k > 3) || (l > 1))
+                               return DC_ERROR; /* &$@^! */
+                       i = strlen(digitbuf) - 1;
+                       if((j != 1) || (k < 2)|| (l != 1))
+                               break; /* Not yet */
+                       if(debug)
+                               printf("PL digits entered %s\n", digitbuf);
+                       
+                       strncpy(tmp, digitbuf, sizeof(tmp) - 1);
+                       /* see if we have at least 1 */
+                       s = strchr(tmp,'*');
+                       if(s)
+                               *s = '.';
+                       strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
+                       strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
+                       
+                       if (setrem(myrpt) == -1){
+                               strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
+                               return DC_ERROR;
+                       }
+               
+               
+                       return DC_COMPLETE;
+               
+               case 4: /* set rx PL tone */
+                       
+                       for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
+                               if(digitbuf[i] == '*'){
+                                       j++;
+                                       continue;
+                               }
+                               if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
+                                       return DC_ERROR;
+                               else{
+                                       if(j)
+                                               l++;
+                                       else
+                                               k++;
+                               }
+                       }
+                       if((j > 1) || (k > 3) || (l > 1))
+                               return DC_ERROR; /* &$@^! */
+                       i = strlen(digitbuf) - 1;
+                       if((j != 1) || (k < 2)|| (l != 1))
+                               break; /* Not yet */
+                       if(debug)
+                               printf("PL digits entered %s\n", digitbuf);
+                       
+                       strncpy(tmp, digitbuf, sizeof(tmp) - 1);
+                       /* see if we have at least 1 */
+                       s = strchr(tmp,'*');
+                       if(s)
+                               *s = '.';
+                       strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
+                       strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
+                       
+                       if (setrem(myrpt) == -1){
+                               strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
+                               return DC_ERROR;
+                       }
+               
+               
+                       return DC_COMPLETE;
+               
 
-                               case DC_INDETERMINATE:
+               case 6: /* MODE (FM,USB,LSB,AM) */
+                       if(strlen(digitbuf) < 1)
+                               break;
+
+                       if(!multimode)
+                               return DC_ERROR; /* Multimode radios only */
+
+                       switch(*digitbuf){
+                               case '1':
+                                       split_freq(mhz, decimals, myrpt->freq); 
+                                       m=atoi(mhz);
+                                       if(m < 29) /* No FM allowed below 29MHz! */
+                                               return DC_ERROR;
+                                       myrpt->remmode = REM_MODE_FM;
                                        break;
-                               
-                               case DC_REQ_FLUSH:
-                                       myrpt->rem_dtmfidx = 0;
-                                       myrpt->rem_dtmfbuf[0] = 0;
+
+                               case '2':
+                                       myrpt->remmode = REM_MODE_USB;
                                        break;
-                               
-                               
-                               case DC_COMPLETE:
-                                       myrpt->rem_dtmfbuf[0] = 0;
-                                       myrpt->rem_dtmfidx = -1;
-                                       myrpt->rem_dtmf_time = 0;
+
+                               case '3':
+                                       myrpt->remmode = REM_MODE_LSB;
                                        break;
                                
-                               case DC_ERROR:
+                               case '4':
+                                       myrpt->remmode = REM_MODE_AM;
+                                       break;
+               
                                default:
-                                       myrpt->rem_dtmfbuf[0] = 0;
-                                       myrpt->rem_dtmfidx = -1;
-                                       myrpt->rem_dtmf_time = 0;
+                                       return DC_ERROR;
+                       }
+
+                       if(setrem(myrpt))
+                               return DC_ERROR;
+                       return DC_COMPLETE;
+
+               case 100: /* other stuff */
+               case 101: 
+               case 102: 
+               case 103: 
+               case 104: 
+               case 105: 
+               case 106:
+                       switch(myatoi(param)){ /* Quick commands requiring a setrem call */
+                               case 100: /* RX PL Off */
+                                       myrpt->rxplon = 0;
+                                       break;
+                                       
+                               case 101: /* RX PL On */
+                                       myrpt->rxplon = 1;
+                                       break;
+                                       
+                               case 102: /* TX PL Off */
+                                       myrpt->txplon = 0;
+                                       break;
+                                       
+                               case 103: /* TX PL On */
+                                       myrpt->txplon = 1;
+                                       break;
+                                       
+                               case 104: /* Low Power */
+                                       myrpt->powerlevel = REM_LOWPWR;
+                                       break;
+                                       
+                               case 105: /* Medium Power */
+                                       myrpt->powerlevel = REM_MEDPWR;
+                                       break;
+                                       
+                               case 106: /* Hi Power */
+                                       myrpt->powerlevel = REM_HIPWR;
                                        break;
+                       
+                               default:
+                                       return DC_ERROR;
                        }
-               }
 
-       }
-       ast_mutex_unlock(&myrpt->lock);
-       return;
-}
+                       if (setrem(myrpt) == -1) 
+                               return DC_ERROR;
+                       return DC_COMPLETE;
 
-/* Doug Hall RBI-1 serial data definitions:
- *
- * Byte 0: Expansion external outputs 
- * Byte 1: 
- *     Bits 0-3 are BAND as follows:
- *     Bits 4-5 are POWER bits as follows:
- *             00 - Low Power
- *             01 - Hi Power
- *             02 - Med Power
- *     Bits 6-7 are always set
- * Byte 2:
- *     Bits 0-3 MHZ in BCD format
- *     Bits 4-5 are offset as follows:
- *             00 - minus
- *             01 - plus
- *             02 - simplex
- *             03 - minus minus (whatever that is)
- *     Bit 6 is the 0/5 KHZ bit
- *     Bit 7 is always set
- * Byte 3:
- *     Bits 0-3 are 10 KHZ in BCD format
- *     Bits 4-7 are 100 KHZ in BCD format
- * Byte 4: PL Tone code and encode/decode enable bits
- *     Bits 0-5 are PL tone code (comspec binary codes)
- *     Bit 6 is encode enable/disable
- *     Bit 7 is decode enable/disable
- */
+               case 107: /* Bump down 20Hz */
+                       multimode_bump_freq(myrpt, -20);
+                       return DC_COMPLETE;
 
-/* take the frequency from the 10 mhz digits (and up) and convert it
-   to a band number */
+               case 108: /* Bump down 100Hz */
+                       multimode_bump_freq(myrpt, -100);
+                       return DC_COMPLETE;
 
-static int rbi_mhztoband(char *str)
-{
-int    i;
+               case 109: /* Bump down 500Hz */
+                       multimode_bump_freq(myrpt, -500);
+                       return DC_COMPLETE;
 
-       i = atoi(str) / 10; /* get the 10's of mhz */
-       switch(i)
-       {
-           case 2:
-               return 10;
-           case 5:
-               return 11;
-           case 14:
-               return 2;
-           case 22:
-               return 3;
-           case 44:
-               return 4;
-           case 124:
-               return 0;
-           case 125:
-               return 1;
-           case 126:
-               return 8;
-           case 127:
-               return 5;
-           case 128:
-               return 6;
-           case 129:
-               return 7;
-           default:
-               break;
-       }
-       return -1;
-}
+               case 110: /* Bump up 20Hz */
+                       multimode_bump_freq(myrpt, 20);
+                       return DC_COMPLETE;
+                               
+               case 111: /* Bump up 100Hz */
+                       multimode_bump_freq(myrpt, 100);
+                       return DC_COMPLETE;
 
-/* take a PL frequency and turn it into a code */
-static int rbi_pltocode(char *str)
-{
-int i;
-char *s;
+               case 112: /* Bump up 500Hz */
+                       multimode_bump_freq(myrpt, 500);
+                       return DC_COMPLETE;
 
-       s = strchr(str,'.');
-       i = 0;
-       if (s) i = atoi(s + 1);
-       i += atoi(str) * 10;
-       switch(i)
-       {
-           case 670:
-               return 0;
-           case 719:
-               return 1;
-           case 744:
-               return 2;
-           case 770:
-               return 3;
-           case 797:
-               return 4;
-           case 825:
-               return 5;
-           case 854:
-               return 6;
-           case 885:
-               return 7;
-           case 915:
-               return 8;
-           case 948:
-               return 9;
-           case 974:
-               return 10;
-           case 1000:
-               return 11;
-           case 1035:
-               return 12;
-           case 1072:
-               return 13;
-           case 1109:
-               return 14;
-           case 1148:
-               return 15;
-           case 1188:
-               return 16;
-           case 1230:
-               return 17;
-           case 1273:
-               return 18;
-           case 1318:
-               return 19;
-           case 1365:
-               return 20;
-           case 1413:
-               return 21;
-           case 1462:
-               return 22;
-           case 1514:
-               return 23;
-           case 1567:
-               return 24;
-           case 1622:
-               return 25;
-           case 1679:
-               return 26;
-           case 1738:
-               return 27;
-           case 1799:
-               return 28;
-           case 1862:
-               return 29;
-           case 1928:
-               return 30;
-           case 2035:
-               return 31;
-           case 2107:
-               return 32;
-           case 2181:
-               return 33;
-           case 2257:
-               return 34;
-           case 2336:
-               return 35;
-           case 2418:
-               return 36;
-           case 2503:
-               return 37;
-       }
-       return -1;
-}
 
-/*
-* Shift out a formatted serial bit stream
-*/
+               case 113:
+               case 114:
+               case 115:
+               case 116:
+               case 117:
+               case 118:
+                       myrpt->remotetx = 0;
+                       ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
+                       if (!myrpt->remoterx)
+                               ast_indicate(mychannel,AST_CONTROL_RADIO_KEY);
+                       if (ast_safe_sleep(mychannel,1000) == -1)
+                                       return DC_ERROR;
+               
+                       switch(myatoi(param)){
+
+                               case 113: /* Scan down slow */
+                                       res = sayfile(mychannel,"rpt/down");
+                                       if(!res)
+                                               res = sayfile(mychannel, "rpt/slow");
+                                       if(!res){
+                                               myrpt->scantimer = REM_SCANTIME;
+                                               myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
+                                       }
+                                       break;
+
+                               case 114: /* Scan down quick */
+                                       res = sayfile(mychannel,"rpt/down");
+                                       if(!res)
+                                               res = sayfile(mychannel, "rpt/quick");
+                                       if(!res){
+                                               myrpt->scantimer = REM_SCANTIME;
+                                               myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
+                                       }
+                                       break;
+
+                               case 115: /* Scan down fast */
+                                       res = sayfile(mychannel,"rpt/down");
+                                       if(!res)
+                                               res = sayfile(mychannel, "rpt/fast");
+                                       if(!res){
+                                               myrpt->scantimer = REM_SCANTIME;
+                                               myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
+                                       }
+                                       break;
+
+                               case 116: /* Scan up slow */
+                                       res = sayfile(mychannel,"rpt/up");
+                                       if(!res)
+                                               res = sayfile(mychannel, "rpt/slow");
+                                       if(!res){
+                                               myrpt->scantimer = REM_SCANTIME;
+                                               myrpt->hfscanmode = HF_SCAN_UP_SLOW;
+                                       }
+                                       break;
 
-static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
-    {
-    int i,j;
-    unsigned char od,d;
-    static volatile long long delayvar;
+                               case 117: /* Scan up quick */
+                                       res = sayfile(mychannel,"rpt/up");
+                                       if(!res)
+                                               res = sayfile(mychannel, "rpt/quick");
+                                       if(!res){
+                                               myrpt->scantimer = REM_SCANTIME;
+                                               myrpt->hfscanmode = HF_SCAN_UP_QUICK;
+                                       }
+                                       break;
 
-    for(i = 0 ; i < 5 ; i++){
-        od = *data++; 
-        for(j = 0 ; j < 8 ; j++){
-            d = od & 1;
-            outb(d,myrpt->iobase);
-           /* >= 15 us */
-           for(delayvar = 1; delayvar < 15000; delayvar++); 
-            od >>= 1;
-            outb(d | 2,myrpt->iobase);
-           /* >= 30 us */
-           for(delayvar = 1; delayvar < 30000; delayvar++); 
-            outb(d,myrpt->iobase);
-           /* >= 10 us */
-           for(delayvar = 1; delayvar < 10000; delayvar++); 
-            }
-        }
-       /* >= 50 us */
-        for(delayvar = 1; delayvar < 50000; delayvar++); 
-    }
+                               case 118: /* Scan up fast */
+                                       res = sayfile(mychannel,"rpt/up");
+                                       if(!res)
+                                               res = sayfile(mychannel, "rpt/fast");
+                                       if(!res){
+                                               myrpt->scantimer = REM_SCANTIME;
+                                               myrpt->hfscanmode = HF_SCAN_UP_FAST;
+                                       }
+                                       break;
+                       }
+                       if (!myrpt->remoterx){
+                               ast_indicate(mychannel,AST_CONTROL_RADIO_UNKEY);
+                       }
+                       return DC_COMPLETE;
 
-static void rbi_out(struct rpt *myrpt,unsigned char *data)
-{
-struct zt_radio_param r;
 
-       memset(&r,0,sizeof(struct zt_radio_param));
-       r.radpar = ZT_RADPAR_REMMODE;
-       r.data = ZT_RADPAR_REM_RBI1;
-       /* if setparam ioctl fails, its probably not a pciradio card */
-       if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
-       {
-               rbi_out_parallel(myrpt,data);
-               return;
-       }
-       r.radpar = ZT_RADPAR_REMCOMMAND;
-       memcpy(&r.data,data,5);
-       if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
-       {
-               ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->rxchannel->name);
-               return;
-       }
-}
+               case 119: /* Tune Request */
+                       myrpt->tunerequest = 1;
+                       return DC_COMPLETE;
 
-static int setrbi(struct rpt *myrpt)
-{
-char tmp[MAXREMSTR] = "",rbicmd[5],*s;
-int    band,txoffset = 0,txpower = 0,rxpl;
+               case 5: /* Long Status */
+               case 140: /* Short Status */
+                       myrpt->remotetx = 0;
+                       ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
+                       if (!myrpt->remoterx){
+                               ast_indicate(mychannel,AST_CONTROL_RADIO_KEY);
+                       }
+                       
+                       if (ast_safe_sleep(mychannel,1000) == -1)
+                                       return DC_ERROR;
 
-       /* must be a remote system */
-       if (!myrpt->remote) return(0);
-       /* must have rbi hardware */
-       if (strncmp(myrpt->remote,"rbi",3)) return(0);
-       strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
-       s = strchr(tmp,'.');
-       /* if no decimal, is invalid */
-       
-       if (s == NULL){
-               if(debug)
-                       printf("@@@@ Frequency needs a decimal\n");
-               return -1;
-       }
-       
-       *s++ = 0;
-       if (strlen(tmp) < 2){
-               if(debug)
-                       printf("@@@@ Bad MHz digits: %s\n", tmp);
-               return -1;
-       }
-        
-       if (strlen(s) < 3){
-               if(debug)
-                       printf("@@@@ Bad KHz digits: %s\n", s);
-               return -1;
-       }
 
-       if ((s[2] != '0') && (s[2] != '5')){
-               if(debug)
-                       printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
-               return -1;
-       }
-        
-       band = rbi_mhztoband(tmp);
-       if (band == -1){
-               if(debug)
-                       printf("@@@@ Bad Band: %s\n", tmp);
-               return -1;
-       }
-       
-       rxpl = rbi_pltocode(myrpt->rxpl);
+                       res = sayfile(mychannel,"rpt/node");
+                       if(!res)
+                               res = saycharstr(mychannel, myrpt->name);
+                       if(!res)
+                               res = sayfile(mychannel,"rpt/frequency");
+                       if(!res)
+                               res = split_freq(mhz, decimals, myrpt->freq);
+                       if(!res){
+                               m = atoi(mhz);
+                               if(m < 100)
+                                       res = saynum(mychannel, m);
+                               else
+                                       res = saycharstr(mychannel, mhz);
+                       }
+                       if(!res)
+                               res = sayfile(mychannel, "letters/dot");
+                       if(!res)
+                               res = saycharstr(mychannel, decimals);
+               
+                       if(res){        
+                               if (!myrpt->remoterx){
+               
+                                       ast_indicate(mychannel,AST_CONTROL_RADIO_UNKEY);
+                               }
+                               return DC_ERROR;
+                       }
+                       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
+                               switch(myrpt->offset){
        
-       if (rxpl == -1){
-               if(debug)
-                       printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
-               return -1;
-       }
+                                       case REM_MINUS:
+                                               res = sayfile(mychannel,"rpt/minus");
+                                               break;
+                               
+                                       case REM_SIMPLEX:
+                                               res = sayfile(mychannel,"rpt/simplex");
+                                               break;
+                                       
+                                       case REM_PLUS:
+                                               res = sayfile(mychannel,"rpt/plus");
+                                               break;
+                                       
+                                       default:
+                                               return DC_ERROR;
 
-       
-       switch(myrpt->offset)
-       {
-           case REM_MINUS:
-               txoffset = 0;
-               break;
-           case REM_PLUS:
-               txoffset = 0x10;
-               break;
-           case REM_SIMPLEX:
-               txoffset = 0x20;
-               break;
-       }
-       switch(myrpt->powerlevel)
-       {
-           case REM_LOWPWR:
-               txpower = 0;
-               break;
-           case REM_MEDPWR:
-               txpower = 0x20;
-               break;
-           case REM_HIPWR:
-               txpower = 0x10;
-               break;
-       }
-       rbicmd[0] = 0;
-       rbicmd[1] = band | txpower | 0xc0;
-       rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
-       if (s[2] == '5') rbicmd[2] |= 0x40;
-       rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
-       rbicmd[4] = rxpl;
-       if (myrpt->txplon) rbicmd[4] |= 0x40;
-       if (myrpt->rxplon) rbicmd[4] |= 0x80;
-       rbi_out(myrpt,rbicmd);
-       return 0;
-}
+                               }
+                       }
+                       else{ /* Must be USB, LSB, or AM */
+                               switch(myrpt->remmode){
+
+                                       case REM_MODE_USB:
+                                               res = saycharstr(mychannel, "USB");
+                                               break;
+
+                                       case REM_MODE_LSB:
+                                               res = saycharstr(mychannel, "LSB");
+                                               break;
+
+                                       case REM_MODE_AM:
+                                               res = saycharstr(mychannel, "AM");
+                                               break;
+
+
+                                       default:
+                                               return DC_ERROR;
+                               }
+                       }
+
+                       if (res == -1){
+               
+                               if (!myrpt->remoterx){
+               
+                                       ast_indicate(mychannel,AST_CONTROL_RADIO_UNKEY);
+                               }
+                               return DC_ERROR;
+                       }
+
+                       if(myatoi(param) == 140) /* Short status? */
+                               return DC_COMPLETE;
 
 
+                       switch(myrpt->powerlevel){
+
+                               case REM_LOWPWR:
+                                       res = sayfile(mychannel,"rpt/lopwr") ;
+                                       break;
+                                       
+                               case REM_MEDPWR:
+                                       res = sayfile(mychannel,"rpt/medpwr");
+                                       break;
+                               case REM_HIPWR:
+                                       res = sayfile(mychannel,"rpt/hipwr"); 
+                                       break;
+                       }
+                       if (res || (sayfile(mychannel,"rpt/rxpl") == -1) ||
+                               (sayfile(mychannel,"rpt/frequency") == -1) ||
+                               (saycharstr(mychannel,myrpt->rxpl) == -1) ||
+                               (sayfile(mychannel,"rpt/txpl") == -1) ||
+                               (sayfile(mychannel,"rpt/frequency") == -1) ||
+                               (saycharstr(mychannel,myrpt->txpl) == -1) ||
+                               (sayfile(mychannel,"rpt/txpl") == -1) ||
+                               (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1) ||
+                               (sayfile(mychannel,"rpt/rxpl") == -1) ||
+                               (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1)){
+                               if (!myrpt->remoterx){
+                                       ast_indicate(mychannel,AST_CONTROL_RADIO_UNKEY);
+                               }
+                               return DC_ERROR;
+                       }
+                       if (!myrpt->remoterx){
+                               ast_indicate(mychannel,AST_CONTROL_RADIO_UNKEY);
+                       }
+                       return DC_COMPLETE;
+                       
+               default:
+                       return DC_ERROR;
+       }
+
+       return DC_INDETERMINATE;
+}
 
 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c)
 {
 time_t now;
 int    ret,res = 0;
 
+       /* Stop scan mode if in scan mode */
+       if(myrpt->hfscanmode){
+               stop_scan(myrpt,0);
+               return 0;
+       }
+
        time(&now);
        /* if timed-out */
        if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
@@ -4273,6 +5235,9 @@ pthread_attr_t attr;
                {
                        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);
+
+                       strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
+                       rpt_vars[i].remmode = REM_MODE_FM;
                        rpt_vars[i].offset = REM_SIMPLEX;
                        rpt_vars[i].powerlevel = REM_MEDPWR;
                        continue;
@@ -4548,8 +5513,10 @@ static int rpt_exec(struct ast_channel *chan, void *data)
        myrpt->dtmfidx = -1;
        myrpt->dtmfbuf[0] = 0;
        myrpt->dtmf_time_rem = 0;
+       myrpt->hfscanmode = 0;
+       myrpt->hfscanstatus = 0;
        ast_mutex_unlock(&myrpt->lock);
-       setrbi(myrpt);
+       setrem(myrpt); 
        ast_set_write_format(chan, AST_FORMAT_SLINEAR);
        ast_set_read_format(chan, AST_FORMAT_SLINEAR);
        /* if we are on 2w loop and are a remote, turn EC on */
@@ -4566,7 +5533,7 @@ static int rpt_exec(struct ast_channel *chan, void *data)
        cs[n++] = myrpt->rxchannel;
        if (myrpt->rxchannel != myrpt->txchannel)
                cs[n++] = myrpt->txchannel;
-       for(;;)
+       for(;;) 
        {
                if (ast_check_hangup(chan)) break;
                if (ast_check_hangup(myrpt->rxchannel)) break;
@@ -4596,6 +5563,35 @@ static int rpt_exec(struct ast_channel *chan, void *data)
                        myrpt->remotetx = 0;
                        ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
                }
+
+               if(myrpt->tunerequest && (!strcmp(myrpt->remote, remote_rig_ft897))){ /* ft-897 specific for now... */
+                       myrpt->tunerequest = 0;
+                       set_mode_ft897(myrpt, REM_MODE_AM);
+                       simple_command_ft897(myrpt, 8);
+                       myrpt->remotetx = 0;
+                       ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
+                       if (!myrpt->remoterx)
+                               ast_indicate(chan, AST_CONTROL_RADIO_KEY);
+                       if(play_tone(chan, 800, 6000, 8192) == -1)
+                               break;
+                       if(myrpt->remoterx == 0)
+                               ast_indicate(chan, AST_CONTROL_RADIO_UNKEY);
+                       set_mode_ft897(myrpt, 0x88);
+                       setrem(myrpt);
+               }
+                               
+                       
+                       
+       
+               if (myrpt->hfscanmode){
+                       myrpt->scantimer -= elap;
+                       if(myrpt->scantimer <= 0){
+                               myrpt->scantimer = REM_SCANTIME;
+                               service_scan(myrpt);
+                       }
+               }
+
+
                if (who == chan) /* if it was a read from incomming */
                {
                        f = ast_read(chan);
@@ -4611,7 +5607,7 @@ static int rpt_exec(struct ast_channel *chan, void *data)
                                        memset(f->data,0,f->datalen);
                                ast_write(myrpt->txchannel,f);
                        }
-                       else if (f->frametype == AST_FRAME_TEXT)
+                       if (f->frametype == AST_FRAME_TEXT)
                        {
                                myrpt->remchannel = chan; /* Save copy of channel */
                                if (handle_remote_data(myrpt,f->data) == -1)
@@ -4621,7 +5617,7 @@ static int rpt_exec(struct ast_channel *chan, void *data)
                                        break;
                                }
                        }
-                       else if (f->frametype == AST_FRAME_CONTROL)
+                       if (f->frametype == AST_FRAME_CONTROL)
                        {
                                if (f->subclass == AST_CONTROL_HANGUP)
                                {
@@ -4642,6 +5638,30 @@ static int rpt_exec(struct ast_channel *chan, void *data)
                                        keyed = 0;
                                }
                        }
+                       if (myrpt->hfscanstatus){
+                               myrpt->remchannel = chan; /* Save copy of channel */
+                               myrpt->remotetx = 0;
+                               ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
+                               if (!myrpt->remoterx)
+                               {
+                                       ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_KEY);
+                               }
+                               if(myrpt->hfscanstatus < 0) {
+                                       if (myrpt->hfscanstatus == -1) {
+                                               if (ast_safe_sleep(myrpt->remchannel,1000) == -1) break;
+                                       }
+                                       sayfile(myrpt->remchannel, "rpt/stop");
+                               }
+                               else
+                               {
+                                       saynum(myrpt->remchannel, myrpt->hfscanstatus );
+                               }       
+                               if (!myrpt->remoterx)
+                               {
+                                       ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_UNKEY);
+                               }
+                               myrpt->hfscanstatus = 0;
+                       }
                        ast_frfree(f);
                        continue;
                }
@@ -4717,8 +5737,11 @@ static int rpt_exec(struct ast_channel *chan, void *data)
        ast_mutex_lock(&myrpt->lock);
        if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
        ast_hangup(myrpt->rxchannel);
+       myrpt->hfscanmode = 0;
+       myrpt->hfscanstatus = 0;
        myrpt->remoteon = 0;
        ast_mutex_unlock(&myrpt->lock);
+       closerem(myrpt);
        LOCAL_USER_REMOVE(u);
        return res;
 }