From: Jim Dixon Date: Mon, 22 Aug 2005 02:38:37 +0000 (+0000) Subject: Added support for Yaesu FT-897 HF/VHF/UHF radio and other improvements X-Git-Tag: 1.2.0-beta1~79 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6b2ff5db906344a09232b7d399c8a2c3157d4a97;p=thirdparty%2Fasterisk.git Added support for Yaesu FT-897 HF/VHF/UHF radio and other improvements git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6346 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/apps/app_rpt.c b/apps/app_rpt.c index 57b43f5523..1952b322aa 100755 --- a/apps/app_rpt.c +++ b/apps/app_rpt.c @@ -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 * Serious contributions by Steve RoDgers, WA6ZFT @@ -47,11 +47,12 @@ * * 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) @@ -59,6 +60,20 @@ * 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) * * */ @@ -104,6 +119,8 @@ #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; }