diff --git a/Makefile b/Makefile index b6469d32f9953c8ca2e8f07fffd193a64f8cf6a0..e52a71a1fe311fc5385bba142d04daa57cf3f1df 100755 --- a/Makefile +++ b/Makefile @@ -57,6 +57,10 @@ DEBUG=-g #-pg # You can still use the old libpri if you do "cvs update -D "08/03/03" in libpri source code OPTIONS += -DNEW_PRI_HANGUP +# If you are running a radio application, define RADIO_RELAX so that the DTMF +# will be received more reliably +#OPTIONS += -DRADIO_RELAX + # Optional debugging parameters DEBUG_THREADS = #-DDEBUG_THREADS #-DDO_CRASH diff --git a/apps/Makefile b/apps/Makefile index e10209ec79776544320b9b205745e718bb011d64..a51f5a03647bf5ec831ef9df2b6fbad4086622f7 100755 --- a/apps/Makefile +++ b/apps/Makefile @@ -35,9 +35,9 @@ endif #APPS+=app_sql_postgres.so #APPS+=app_sql_odbc.so +#APPS+=app_rpt.so APPS+=$(shell if [ -f /usr/include/linux/zaptel.h ]; then echo "app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so" ; fi) -#APPS+=$(shell if [ -f /usr/include/zap.h ]; then echo "app_rpt.so" ; fi) CFLAGS+=-fPIC @@ -64,12 +64,6 @@ install: all for x in $(APPS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(MODULES_DIR) ; done rm -f $(DESTDIR)$(MODULES_DIR)/app_datetime.so -app_todd.o: app_todd.c - gcc -pipe -O6 -g -Iinclude -I../include -D_REENTRANT -march=i586 -DDO_CRASH -c -o app_todd.o app_todd.c - -app_todd.so: app_todd.o - $(CC) $(SOLINK) -o $@ $< -L/usr/local/ssl/lib -lssl -lcrypto - app_voicemail.so : app_voicemail.o ifeq ($(USE_MYSQL_VM_INTERFACE),1) $(CC) $(SOLINK) -o $@ $(MLFLAGS) $< -L/usr/lib/mysql -lmysqlclient -lz diff --git a/apps/app_rpt.c b/apps/app_rpt.c index c99a06ae61e78041e129774b3cc1dce3afef3a29..9325d39bae5faf72a257b22ba5464090b20ef3c7 100755 --- a/apps/app_rpt.c +++ b/apps/app_rpt.c @@ -2,17 +2,40 @@ * * Asterisk -- A telephony toolkit for Linux. * - * Radio Repeater program + * Radio Repeater / Remote Base program + * version 0.2 5/30/04 * - * Copyright (C) 2002, Jim Dixon + * Copyright (C) 2002-2004, Jim Dixon * * Jim Dixon <jim@lambdatel.com> * * This program is free software, distributed under the terms of * the GNU General Public License * + * Repeater / Remote Functions: + * "Simple" Mode: * - autopatch access, # - autopatch hangup + * Normal mode: + * *0 - autopatch access + * *1 - remote base off + * *2 - remote base monitor + * *3 - remote base tranceive + * *8 - force ID + * *9 - system reset + * + * To send an asterisk (*) while dialing or talking on phone, + * use the autopatch acess code. */ +/* number of digits for function after *. Must be at least 1 */ +#define FUNCTION_LEN 1 + +/* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */ + +#define MAXDTMF 10 +#define DTMF_TIMEOUT 3 + +enum {REM_OFF,REM_MONITOR,REM_TX}; + #include <asterisk/lock.h> #include <asterisk/file.h> #include <asterisk/logger.h> @@ -40,7 +63,7 @@ #include <tonezone.h> #include <linux/zaptel.h> -static char *tdesc = "Radio Repeater"; +static char *tdesc = "Radio Repeater / Remote Base version 0.2 05/30/2004"; static int debug = 0; STANDARD_LOCAL_USER; LOCAL_USER_DECL; @@ -58,17 +81,25 @@ static struct rpt char *name; char *rxchanname; char *txchanname; + char *rem_rxchanname; + char *rem_txchanname; char *ourcontext; char *ourcallerid; char *acctcode; char *idrecording; + char *tonezone; int hangtime; int totime; int idtime; - struct ast_channel *rxchannel,*txchannel,*pchannel; + char remoterx; + char remotetx; + char remotemode; + char simple; + struct ast_channel *rxchannel,*txchannel,*rem_rxchannel; + struct ast_channel *rem_txchannel,*pchannel; int tailtimer,totimer,idtimer,txconf,pconf,callmode,cidx; pthread_t rpt_id_thread,rpt_term_thread,rpt_proc_thread,rpt_call_thread; - char mydtmf,iding,terming; + char mydtmf,iding,terming,teleing,comping,procing; char exten[AST_MAX_EXTENSION]; } rpt_vars[MAXRPTS]; @@ -130,7 +161,7 @@ struct ast_channel *mychannel; } /* make a conference for the tx */ ci.chan = 0; - ci.confno = myrpt->pconf; /* use the tx conference */ + ci.confno = myrpt->txconf; /* use the tx conference */ ci.confmode = ZT_CONF_CONFANN; /* first put the channel on the conference in announce mode */ if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1) @@ -138,7 +169,7 @@ struct ast_channel *mychannel; ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); pthread_exit(NULL); } - myrpt->terming = 1; + myrpt->procing = 1; ast_stopstream(mychannel); res = ast_streamfile(mychannel, "callproceeding", mychannel->language); if (!res) @@ -147,7 +178,7 @@ struct ast_channel *mychannel; ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name); res = 0; } - myrpt->terming = 0; + myrpt->procing = 0; ast_stopstream(mychannel); ast_hangup(mychannel); pthread_exit(NULL); @@ -171,7 +202,7 @@ struct ast_channel *mychannel; } /* make a conference for the tx */ ci.chan = 0; - ci.confno = myrpt->pconf; /* use the tx conference */ + ci.confno = myrpt->txconf; /* use the tx conference */ ci.confmode = ZT_CONF_CONFANN; /* first put the channel on the conference in announce mode */ if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1) @@ -194,6 +225,89 @@ struct ast_channel *mychannel; pthread_exit(NULL); } +static void *rpt_complete(void *this) +{ +ZT_CONFINFO ci; /* conference info */ +int res; +struct rpt *myrpt = (struct rpt *)this; +struct ast_channel *mychannel; + + /* wait a little bit */ + usleep(1000000); + /* allocate a pseudo-channel thru asterisk */ + mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo"); + if (!mychannel) + { + fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n"); + pthread_exit(NULL); + } + /* make a conference for the tx */ + ci.chan = 0; + ci.confno = myrpt->txconf; /* use the tx conference */ + 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"); + pthread_exit(NULL); + } + myrpt->comping = 1; + ast_stopstream(mychannel); + res = ast_streamfile(mychannel, "functioncomplete", mychannel->language); + if (!res) + res = ast_waitstream(mychannel, ""); + else { + ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name); + res = 0; + } + myrpt->comping = 0; + ast_stopstream(mychannel); + ast_hangup(mychannel); + pthread_exit(NULL); +} + +static void *rpt_remote_telemetry(void *this) +{ +ZT_CONFINFO ci; /* conference info */ +int res; +struct rpt *myrpt = (struct rpt *)this; +struct ast_channel *mychannel; + + /* wait a little bit */ + usleep(1000000); + /* allocate a pseudo-channel thru asterisk */ + mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo"); + if (!mychannel) + { + fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n"); + pthread_exit(NULL); + } + /* make a conference for the tx */ + ci.chan = 0; + ci.confno = myrpt->txconf; /* use the tx conference */ + 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"); + pthread_exit(NULL); + } + myrpt->teleing = 1; + ast_stopstream(mychannel); + res = ast_streamfile(mychannel, + ((myrpt->remotemode == REM_MONITOR) ? "remote_monitor" : "remote_tx"), + mychannel->language); + if (!res) + res = ast_waitstream(mychannel, ""); + else { + ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name); + res = 0; + } + myrpt->teleing = 0; + ast_hangup(mychannel); + pthread_exit(NULL); +} + static void *rpt_call(void *this) { ZT_CONFINFO ci; /* conference info */ @@ -244,6 +358,22 @@ struct ast_channel *mychannel,*genchannel; myrpt->callmode = 0; pthread_exit(NULL); } + if (myrpt->tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->tonezone) == -1)) + { + ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone); + ast_hangup(mychannel); + ast_hangup(genchannel); + myrpt->callmode = 0; + pthread_exit(NULL); + } + if (myrpt->tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->tonezone) == -1)) + { + ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone); + ast_hangup(mychannel); + ast_hangup(genchannel); + myrpt->callmode = 0; + pthread_exit(NULL); + } /* start dialtone */ if (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0) { @@ -358,14 +488,104 @@ struct ast_channel *mychannel,*genchannel; pthread_exit(NULL); } +static void process_dtmf(char *cmd,struct rpt *myrpt) +{ +pthread_attr_t attr; +ZT_CONFINFO ci; /* conference info */ + + switch(atoi(cmd)) + { + case 0: /* autopatch on / send asterisk (*) */ + /* if on call, force * into current audio stream */ + if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) + { + myrpt->mydtmf = '*'; + break; + } + if (myrpt->callmode) return; + myrpt->callmode = 1; + myrpt->cidx = 0; + myrpt->exten[myrpt->cidx] = 0; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt); + return; + case 9: /* master reset */ + myrpt->callmode = 0; + /* fall thru intentionally */ + case 1: /* remote base off */ + if (myrpt->rem_rxchannel == NULL) return; + myrpt->remotemode = REM_OFF; + ci.chan = 0; + ci.confno = 0; + ci.confmode = 0; + /* Take off conf */ + if (ioctl(myrpt->rem_rxchannel->fds[0],ZT_SETCONF,&ci) == -1) + { + ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); + pthread_exit(NULL); + } + /* Take off conf */ + if (ioctl(myrpt->rem_txchannel->fds[0],ZT_SETCONF,&ci) == -1) + { + ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); + pthread_exit(NULL); + } + break; + case 2: /* remote base monitor */ + if (myrpt->rem_rxchannel == NULL) return; + myrpt->remotemode = REM_MONITOR; + if (myrpt->remoterx && (!myrpt->remotetx)) + { + ci.chan = 0; + ci.confno = myrpt->pconf; + ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER; + /* Put on conf */ + if (ioctl(myrpt->rem_rxchannel->fds[0],ZT_SETCONF,&ci) == -1) + { + ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); + pthread_exit(NULL); + } + } + break; + case 3: /* remote base tranceieve */ + if (myrpt->rem_rxchannel == NULL) return; + myrpt->remotemode = REM_TX; + if (myrpt->remoterx && (!myrpt->remotetx)) + { + ci.chan = 0; + ci.confno = myrpt->pconf; + ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER; + /* Put on conf */ + if (ioctl(myrpt->rem_rxchannel->fds[0],ZT_SETCONF,&ci) == -1) + { + ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); + pthread_exit(NULL); + } + } + break; + case 8: /* force ID */ + myrpt->idtimer = 0; + return; + default: + return; + } + /* send function complete */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&myrpt->rpt_call_thread,&attr,rpt_complete,(void *)myrpt); +} + /* single thread with one file (request) to dial */ static void *rpt(void *this) { struct rpt *myrpt = (struct rpt *)this; char *tele; -int ms = MSWAIT,lasttx,keyed,val; +int ms = MSWAIT,lasttx,keyed,val,dtmfidx; +char dtmfbuf[MAXDTMF]; struct ast_channel *who; ZT_CONFINFO ci; /* conference info */ +time_t dtmf_time,t; pthread_attr_t attr; tele = strchr(myrpt->rxchanname,'/'); @@ -390,7 +610,7 @@ pthread_attr_t attr; } else { - fprintf(stderr,"rpt:Sorry unable to obtain channel\n"); + fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n"); pthread_exit(NULL); } if (myrpt->txchanname) @@ -417,7 +637,7 @@ pthread_attr_t attr; } else { - fprintf(stderr,"rpt:Sorry unable to obtain channel\n"); + fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n"); pthread_exit(NULL); } } @@ -425,6 +645,70 @@ pthread_attr_t attr; { myrpt->txchannel = myrpt->rxchannel; } + myrpt->rem_rxchannel = NULL; + myrpt->rem_txchannel = NULL; + myrpt->remoterx = 0; + myrpt->remotemode = REM_OFF; + if (myrpt->rem_rxchanname) + { + tele = strchr(myrpt->rem_rxchanname,'/'); + if (!tele) + { + fprintf(stderr,"rpt:Dial number must be in format tech/number\n"); + pthread_exit(NULL); + } + *tele++ = 0; + myrpt->rem_rxchannel = ast_request(myrpt->rem_rxchanname,AST_FORMAT_SLINEAR,tele); + if (myrpt->rem_rxchannel) + { + ast_set_read_format(myrpt->rem_rxchannel,AST_FORMAT_SLINEAR); + ast_set_write_format(myrpt->rem_rxchannel,AST_FORMAT_SLINEAR); + myrpt->rem_rxchannel->whentohangup = 0; + myrpt->rem_rxchannel->appl = "Apprpt"; + myrpt->rem_rxchannel->data = "(Repeater/Remote Rx)"; + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "rpt (RemoteRx) initiating call to %s/%s on %s\n", + myrpt->rem_rxchanname,tele,myrpt->rem_rxchannel->name); + ast_call(myrpt->rem_rxchannel,tele,999); + } + else + { + fprintf(stderr,"rpt:Sorry unable to obtain RemoteRx channel\n"); + pthread_exit(NULL); + } + if (myrpt->rem_txchanname) /* if in remote base mode */ + { + tele = strchr(myrpt->rem_txchanname,'/'); + if (!tele) + { + fprintf(stderr,"rpt:Dial number must be in format tech/number\n"); + pthread_exit(NULL); + } + *tele++ = 0; + myrpt->rem_txchannel = ast_request(myrpt->rem_txchanname,AST_FORMAT_SLINEAR,tele); + if (myrpt->rem_txchannel) + { + ast_set_read_format(myrpt->rem_txchannel,AST_FORMAT_SLINEAR); + ast_set_write_format(myrpt->rem_txchannel,AST_FORMAT_SLINEAR); + myrpt->rem_txchannel->whentohangup = 0; + myrpt->rem_txchannel->appl = "Apprpt"; + myrpt->rem_txchannel->data = "(Repeater/Remote Tx)"; + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "rpt (RemoteTx) initiating call to %s/%s on %s\n", + myrpt->rem_txchanname,tele,myrpt->rem_txchannel->name); + ast_call(myrpt->rem_txchannel,tele,999); + } + else + { + fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n"); + pthread_exit(NULL); + } + } + else + { + myrpt->rem_txchannel = myrpt->rem_rxchannel; + } + } /* allocate a pseudo-channel thru asterisk */ myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo"); if (!myrpt->pchannel) @@ -463,19 +747,39 @@ pthread_attr_t attr; myrpt->totimer = 0; myrpt->idtimer = 0; lasttx = 0; + myrpt->remotetx = 0; keyed = 0; myrpt->callmode = 0; + dtmfidx = -1; + dtmfbuf[0] = 0; + dtmf_time = 0; val = 0; ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0); val = 1; ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0); + if (myrpt->rem_rxchannel) + { + val = 0; + ast_channel_setoption(myrpt->rem_rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0); + val = 1; + ast_channel_setoption(myrpt->rem_rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0); + } while (ms >= 0) { struct ast_frame *f; - struct ast_channel *cs[3]; - int totx,elap; + struct ast_channel *cs[5]; + int totx,rem_totx,elap,n; - totx = (keyed || myrpt->callmode || myrpt->iding || myrpt->terming); + if (ast_check_hangup(myrpt->rxchannel)) break; + if (ast_check_hangup(myrpt->txchannel)) break; + if (myrpt->rem_rxchannel) + { + if (ast_check_hangup(myrpt->rem_rxchannel)) break; + if (ast_check_hangup(myrpt->rem_txchannel)) break; + } + totx = (keyed || myrpt->callmode || myrpt->iding || myrpt->terming + || ((myrpt->remotemode != REM_OFF) && myrpt->remoterx) || + myrpt->teleing || myrpt->comping || myrpt->procing); if (!totx) myrpt->totimer = myrpt->totime; else myrpt->tailtimer = myrpt->hangtime; totx = (totx || myrpt->tailtimer) && myrpt->totimer; @@ -486,6 +790,11 @@ pthread_attr_t attr; myrpt->totimer = myrpt->totime; continue; } + /* if timed-out and in circuit busy after call */ + if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4)) + { + myrpt->callmode = 0; + } if (totx && (!myrpt->idtimer)) { myrpt->idtimer = myrpt->idtime; @@ -503,12 +812,75 @@ pthread_attr_t attr; lasttx = 0; ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY); } - - cs[0] = myrpt->rxchannel; - cs[1] = myrpt->pchannel; - cs[2] = myrpt->txchannel; + rem_totx = ((keyed && (myrpt->remotemode == REM_TX)) && myrpt->totimer); + if (rem_totx && (!myrpt->remotetx)) + { + myrpt->remotetx = 1; + ci.chan = 0; + ci.confno = 0; + ci.confmode = 0; + /* Take off conf */ + if (ioctl(myrpt->rem_rxchannel->fds[0],ZT_SETCONF,&ci) == -1) + { + ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); + pthread_exit(NULL); + } + ast_indicate(myrpt->rem_txchannel,AST_CONTROL_RADIO_KEY); + ci.chan = 0; + ci.confno = myrpt->txconf; + ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER; + /* Put the channel on the conference in listener mode */ + if (ioctl(myrpt->rem_txchannel->fds[0],ZT_SETCONF,&ci) == -1) + { + ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); + pthread_exit(NULL); + } + } + if ((!rem_totx) && myrpt->remotetx) + { + myrpt->remotetx = 0; + ast_indicate(myrpt->rem_txchannel,AST_CONTROL_RADIO_UNKEY); + ci.chan = 0; + ci.confno = 0; + ci.confmode = 0; + /* Take off conf */ + if (ioctl(myrpt->rem_txchannel->fds[0],ZT_SETCONF,&ci) == -1) + { + ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); + pthread_exit(NULL); + } + if (myrpt->remotemode != REM_OFF) + { + ci.chan = 0; + ci.confno = myrpt->pconf; + ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER; + /* Put on conf */ + if (ioctl(myrpt->rem_rxchannel->fds[0],ZT_SETCONF,&ci) == -1) + { + ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); + pthread_exit(NULL); + } + } + } + time(&t); + /* if DTMF timeout */ + if ((dtmfidx >= 0) && ((dtmf_time + DTMF_TIMEOUT) < t)) + { + dtmfidx = -1; + dtmfbuf[0] = 0; + } + n = 0; + cs[n++] = myrpt->rxchannel; + cs[n++] = myrpt->pchannel; + if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel; + if (myrpt->rem_rxchannel) + { + cs[n++] = myrpt->rem_rxchannel; + if (myrpt->rem_txchannel != myrpt->rem_rxchannel) + cs[n++] = myrpt->rem_txchannel; + } ms = MSWAIT; - who = ast_waitfor_n(cs,3,&ms); + who = ast_waitfor_n(cs,n,&ms); if (who == NULL) ms = 0; elap = MSWAIT - ms; if (myrpt->tailtimer) myrpt->tailtimer -= elap; @@ -535,15 +907,44 @@ pthread_attr_t attr; char c; c = (char) f->subclass; /* get DTMF char */ - if ((!myrpt->callmode) && (c == '*')) + if (!myrpt->simple) { - myrpt->callmode = 1; - myrpt->cidx = 0; - myrpt->exten[myrpt->cidx] = 0; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt); - continue; + if (c == '*') + { + dtmfidx = 0; + dtmfbuf[dtmfidx] = 0; + time(&dtmf_time); + continue; + } + else if ((c != '#') && (dtmfidx >= 0)) + { + time(&dtmf_time); + if (dtmfidx < MAXDTMF) + { + dtmfbuf[dtmfidx++] = c; + dtmfbuf[dtmfidx] = 0; + } + if (dtmfidx == FUNCTION_LEN) + { + process_dtmf(dtmfbuf,myrpt); + dtmfbuf[0] = 0; + dtmfidx = -1; + continue; + } + } + } + else + { + if ((!myrpt->callmode) && (c == '*')) + { + myrpt->callmode = 1; + myrpt->cidx = 0; + myrpt->exten[myrpt->cidx] = 0; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt); + continue; + } } if (myrpt->callmode && (c == '#')) { @@ -595,9 +996,16 @@ pthread_attr_t attr; { if (debug) printf("@@@@ rx un-key\n"); keyed = 0; + if (myrpt->remotemode != REM_OFF) + { + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&myrpt->rpt_proc_thread,&attr,rpt_remote_telemetry,(void *) myrpt); + } } } ast_frfree(f); + continue; } if (who == myrpt->pchannel) /* if it was a read from pseudo */ { @@ -610,6 +1018,8 @@ pthread_attr_t attr; if (f->frametype == AST_FRAME_VOICE) { ast_write(myrpt->txchannel,f); + if (myrpt->remotemode == REM_TX) + ast_write(myrpt->rem_txchannel,f); } if (f->frametype == AST_FRAME_CONTROL) { @@ -621,6 +1031,7 @@ pthread_attr_t attr; } } ast_frfree(f); + continue; } if (who == myrpt->txchannel) /* if it was a read from tx */ { @@ -640,12 +1051,95 @@ pthread_attr_t attr; } } ast_frfree(f); + continue; + } + if (who == myrpt->rem_rxchannel) /* if it was a read from rx */ + { + f = ast_read(myrpt->rem_rxchannel); + if (!f) + { + if (debug) printf("@@@@ rpt:Hung Up\n"); + break; + } + if (f->frametype == AST_FRAME_CONTROL) + { + if (f->subclass == AST_CONTROL_HANGUP) + { + if (debug) printf("@@@@ rpt:Hung Up\n"); + ast_frfree(f); + break; + } + /* if RX key */ + if (f->subclass == AST_CONTROL_RADIO_KEY) + { + if (debug) printf("@@@@ remote rx key\n"); + if (!myrpt->remotetx) + { + myrpt->remoterx = 1; + ci.chan = 0; + ci.confno = myrpt->pconf; + ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER; + /* Put on conf */ + if (ioctl(myrpt->rem_rxchannel->fds[0],ZT_SETCONF,&ci) == -1) + { + ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); + pthread_exit(NULL); + } + } + } + /* if RX un-key */ + if (f->subclass == AST_CONTROL_RADIO_UNKEY) + { + if (debug) printf("@@@@ remote rx un-key\n"); + if (!myrpt->remotetx) + { + myrpt->remoterx = 0; + ci.chan = 0; + ci.confno = 0; + ci.confmode = 0; + /* Take off conf */ + if (ioctl(myrpt->rem_rxchannel->fds[0],ZT_SETCONF,&ci) == -1) + { + ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); + pthread_exit(NULL); + } + } + } + } + ast_frfree(f); + continue; + } + if (who == myrpt->rem_txchannel) /* if it was a read from remote tx */ + { + f = ast_read(myrpt->rem_txchannel); + if (!f) + { + if (debug) printf("@@@@ rpt:Hung Up\n"); + break; + } + if (f->frametype == AST_FRAME_CONTROL) + { + if (f->subclass == AST_CONTROL_HANGUP) + { + if (debug) printf("@@@@ rpt:Hung Up\n"); + ast_frfree(f); + break; + } + } + ast_frfree(f); + continue; } } ast_hangup(myrpt->pchannel); ast_hangup(myrpt->rxchannel); - ast_hangup(myrpt->txchannel); + if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel); + if (myrpt->rem_rxchannel) + { + ast_hangup(myrpt->rem_rxchannel); + if (myrpt->rem_txchannel != myrpt->rem_rxchannel) + ast_hangup(myrpt->rem_txchannel); + } if (debug) printf("@@@@ rpt:Hung up channel\n"); pthread_exit(NULL); return NULL; @@ -675,6 +1169,8 @@ int i,n; rpt_vars[n].name = this; rpt_vars[n].rxchanname = ast_variable_retrieve(cfg,this,"rxchannel"); rpt_vars[n].txchanname = ast_variable_retrieve(cfg,this,"txchannel"); + rpt_vars[n].rem_rxchanname = ast_variable_retrieve(cfg,this,"remote_rxchannel"); + rpt_vars[n].rem_txchanname = ast_variable_retrieve(cfg,this,"remote_txchannel"); rpt_vars[n].ourcontext = ast_variable_retrieve(cfg,this,"context"); if (!rpt_vars[n].ourcontext) rpt_vars[n].ourcontext = this; rpt_vars[n].ourcallerid = ast_variable_retrieve(cfg,this,"callerid"); @@ -689,6 +1185,10 @@ int i,n; val = ast_variable_retrieve(cfg,this,"idtime"); if (val) rpt_vars[n].idtime = atoi(val); else rpt_vars[n].idtime = IDTIME; + val = ast_variable_retrieve(cfg,this,"simple"); + if (val) rpt_vars[n].simple = ast_true(val); + else rpt_vars[n].simple = 0; + rpt_vars[n].tonezone = ast_variable_retrieve(cfg,this,"tonezone"); n++; } ast_log(LOG_DEBUG, "Total of %d repeaters configured.\n",n); diff --git a/channels/chan_zap.c b/channels/chan_zap.c index 79584d23622e8dc06633d341277fc4aec28ae3c0..956c39b93548b0b30f7672c91f86bb760a6417eb 100755 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -5676,11 +5676,15 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio) p.debouncetime = cur_debounce; } - res = ioctl(tmp->subs[SUB_REAL].zfd, ZT_SET_PARAMS, &p); - if (res < 0) { - ast_log(LOG_ERROR, "Unable to set parameters\n"); - free(tmp); - return NULL; + /* dont set parms on a pseudo-channel */ + if (tmp->subs[SUB_REAL].zfd >= 0) + { + res = ioctl(tmp->subs[SUB_REAL].zfd, ZT_SET_PARAMS, &p); + if (res < 0) { + ast_log(LOG_ERROR, "Unable to set parameters\n"); + free(tmp); + return NULL; + } } #if 1 if (!here && (tmp->subs[SUB_REAL].zfd > -1)) { diff --git a/configs/rpt.conf.sample b/configs/rpt.conf.sample index c9704092b3021961aa1c063325c8ccde89eb3b45..546a61deeee21ff7725968138e4a9d9657dfead2 100755 --- a/configs/rpt.conf.sample +++ b/configs/rpt.conf.sample @@ -1,4 +1,4 @@ -; Radio Repeater configuration file (for use with app_rpt) +; Radio Repeater / Remote Base configuration file (for use with app_rpt) ; ;[oakhurst] ; Name of First Repeater @@ -7,8 +7,14 @@ ; Note: if you use a unified interface (tx/rx on one channel), only ; specify the rxchannel and the txchannel will be assumed from the rxchannel ;txchannel = Zap/2 ; Tx audio/signalling channel +;remote_rxchannel = Zap/3 ; Remote Base Rx audio/signalling channel +; Note: if you use a unified interface (tx/rx on one channel), only +; specify the remote_rxchannel and the remote_txchannel will be assumed from the rxchannel +;remote_txchannel = Zap/4 ; Remote Base Tx audio/signalling channel +;tonezone = us ; use US tones +;simple = no ; Not in "simple" mode ;context = default ; dialing context for phone -;callerid = "WB6NIL Repeater" <(818) 325-2757> ; Callerid for phone calls +;callerid = "WB6NIL Repeater" <(559) 692-1234> ; Callerid for phone calls ;idrecording = wb6nil ; id recording ;accountcode=RADIO ; account code (optional) ;hangtime=1000 ; squelch tail hang time (in ms) (optional) diff --git a/dsp.c b/dsp.c index 774875212f50be7a659e9961d5cfebb088f147d9..fa66318eddb0e1d71623d2cc70a674110848b5e8 100755 --- a/dsp.c +++ b/dsp.c @@ -123,7 +123,11 @@ static struct progress { #define FAX_THRESHOLD 8.0e7 #define FAX_2ND_HARMONIC 2.0 /* 4dB */ #define DTMF_NORMAL_TWIST 6.3 /* 8dB */ +#ifdef RADIO_RELAX +#define DTMF_REVERSE_TWIST ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 6.5 : 2.5) /* 4dB normal */ +#else #define DTMF_REVERSE_TWIST ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 4.0 : 2.5) /* 4dB normal */ +#endif #define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */ #define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */ #define DTMF_2ND_HARMONIC_ROW ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 1.7 : 2.5) /* 4dB normal */