[svn-commits] jdixon: branch jdixon/chan_usbradio-1.4 r138259 - in /team/jdixon/chan_usbrad...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Aug 15 17:40:13 CDT 2008


Author: jdixon
Date: Fri Aug 15 17:40:12 2008
New Revision: 138259

URL: http://svn.digium.com/view/asterisk?view=rev&rev=138259
Log:
Development versions of app_rpt.c and chan_locloop.c

Added:
    team/jdixon/chan_usbradio-1.4/dev-1.0/
    team/jdixon/chan_usbradio-1.4/dev-1.0/apps/
    team/jdixon/chan_usbradio-1.4/dev-1.0/apps/app_rpt.c   (with props)
    team/jdixon/chan_usbradio-1.4/dev-1.0/channels/
    team/jdixon/chan_usbradio-1.4/dev-1.0/channels/chan_locloop.c   (with props)

Added: team/jdixon/chan_usbradio-1.4/dev-1.0/apps/app_rpt.c
URL: http://svn.digium.com/view/asterisk/team/jdixon/chan_usbradio-1.4/dev-1.0/apps/app_rpt.c?view=auto&rev=138259
==============================================================================
--- team/jdixon/chan_usbradio-1.4/dev-1.0/apps/app_rpt.c (added)
+++ team/jdixon/chan_usbradio-1.4/dev-1.0/apps/app_rpt.c Fri Aug 15 17:40:12 2008
@@ -1,0 +1,15136 @@
+/* #define	NEW_ASTERISK */
+/* #define OLD_ASTERISK */
+/* #define	APP_RPT_LOCK_DEBUG */
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2002-2008, Jim Dixon, WB6NIL
+ *
+ * Jim Dixon, WB6NIL <jim at lambdatel.com>
+ * Serious contributions by Steve RoDgers, WA6ZFT <hwstar at rodgers.sdcoxmail.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+/*! \file
+ *
+ * \brief Radio Repeater / Remote Base program 
+ *  version 0.904 (1.0-dev4) 8/6/08 
+ * 
+ * \author Jim Dixon, WB6NIL <jim at lambdatel.com>
+ *
+ * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar at rodgers.sdcoxmail.com>
+ * \note Steven Henke, W9SH, <w9sh at arrl.net> added a few features here and there.
+ *
+ * See http://www.zapatatelephony.org/app_rpt.html
+ *
+ *
+ * Repeater / Remote Functions:
+ * "Simple" Mode:  * - autopatch access, # - autopatch hangup
+ * Normal mode:
+ * See the function list in rpt.conf (autopatchup, autopatchdn)
+ * autopatchup can optionally take comma delimited setting=value pairs:
+ *  
+ *
+ * context=string		:	Override default context with "string"
+ * dialtime=ms			:	Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
+ * farenddisconnect=1		:	Automatically disconnect when called party hangs up
+ * noct=1			:	Don't send repeater courtesy tone during autopatch calls
+ * quiet=1			:	Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
+ *
+ *
+ * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
+ *
+ *  To send an asterisk (*) while dialing or talking on phone,
+ *  use the autopatch acess code.
+ *
+ *
+ * status cmds:
+ *
+ *  1 - Force ID (global)
+ *  2 - Give Time of Day (global)
+ *  3 - Give software Version (global)
+ *  11 - Force ID (local only)
+ *  12 - Give Time of Day (local only)
+ *
+ * cop (control operator) cmds:
+ *
+ *  1 - System warm boot
+ *  2 - System enable
+ *  3 - System disable
+ *  4 - Test Tone On/Off
+ *  5 - Dump System Variables on Console (debug)
+ *  6 - PTT (phone mode only)
+ *  7 - Time out timer enable
+ *  8 - Time out timer disable
+ *  9 - Autopatch enable
+ *  10 - Autopatch disable
+ *  11 - Link enable
+ *  12 - Link disable
+ *  13 - Query System State
+ *  14 - Change System State
+ *  15 - Scheduler Enable
+ *  16 - Scheduler Disable
+ *  17 - User functions (time, id, etc) enable
+ *  18 - User functions (time, id, etc) disable
+ *  19 - Select alternate hang timer
+ *  20 - Select standard hang timer 
+ *  21 - Enable Parrot Mode
+ *  22 - Disable Parrot Mode
+ *  23 - Birdbath (Current Parrot Cleanup/Flush)
+ *  24 - Flush all telemetry
+ *  25 - Query last node un-keyed
+ *  26 - Query all nodes keyed/unkeyed
+ *  30 - Recall Memory Setting in Attached Xcvr
+ *  31 - Channel Selector for Parallel Programmed Xcvr
+ *  32 - Touchtone pad test: command + Digit string + # to playback all digits pressed
+ *
+ * ilink cmds:
+ *
+ *  1 - Disconnect specified link
+ *  2 - Connect specified link -- monitor only
+ *  3 - Connect specified link -- tranceive
+ *  4 - Enter command mode on specified link
+ *  5 - System status
+ *  6 - Disconnect all links
+ *  11 - Disconnect a previously permanently connected link
+ *  12 - Permanently connect specified link -- monitor only
+ *  13 - Permanently connect specified link -- tranceive
+ *  15 - Full system status (all nodes)
+ *  16 - Reconnect links disconnected with "disconnect all links"
+ *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
+ *
+ * remote cmds:
+ *
+ *  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)
+ *  103 - TX PL On
+ *  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)
+ *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
+ *
+ * playback cmds:
+ *  specify the name of the file to be played (for example, 25=rpt/foo)
+ *
+ *
+ * 'duplex' modes:  (defaults to duplex=2)
+ *
+ * 0 - Only remote links key Tx and no main repeat audio.
+ * 1 - Everything other then main Rx keys Tx, no main repeat audio.
+ * 2 - Normal mode
+ * 3 - Normal except no main repeat audio.
+ * 4 - Normal except no main repeat audio during autopatch only
+ *
+*/
+
+/*** MODULEINFO
+	<depend>zaptel</depend>
+	<defaultenabled>yes</defaultenabled>
+ ***/
+
+/* Un-comment the following to include support for MDC-1200 digital tone
+   signalling protocol (using KA6SQG's GPL'ed implementation) */
+/* #include "mdc_decode.c" */
+
+/* Un-comment the following to include support for notch filters in the
+   rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
+/* #include "rpt_notch.c" */
+
+/* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
+
+#ifdef OLD_ASTERISK
+#define ast_free free
+#define ast_malloc malloc
+#define ast_strdup strdup
+#endif
+
+
+#define	MAXDTMF 32
+#define	MAXMACRO 2048
+#define	MAXLINKLIST 512
+#define	LINKLISTTIME 10000
+#define	LINKLISTSHORTTIME 200
+#define	LINKPOSTTIME 30000
+#define	LINKPOSTSHORTTIME 200
+#define	KEYPOSTTIME 30000
+#define	KEYPOSTSHORTTIME 200
+#define	MACROTIME 100
+#define	MACROPTIME 500
+#define	DTMF_TIMEOUT 3
+#define	KENWOOD_RETRIES 5
+#define	TOPKEYN 32
+#define	TOPKEYWAIT 3
+#define	TOPKEYMAXSTR 30
+
+#define	AUTHTELLTIME 7000
+#define	AUTHTXTIME 1000
+#define	AUTHLOGOUTTIME 25000
+
+#ifdef	__RPT_NOTCH
+#define	MAXFILTERS 10
+#endif
+
+#define	DISC_TIME 10000  /* report disc after 10 seconds of no connect */
+#define	MAX_RETRIES 5
+#define	MAX_RETRIES_PERM 1000000000
+
+#define	REDUNDANT_TX_TIME 2000
+
+#define	RETRY_TIMER_MS 5000
+
+#define	PATCH_DIALPLAN_TIMEOUT 1500
+
+#ifdef OLD_ASTERISK
+#define	START_DELAY 10
+#else
+#define	START_DELAY 2
+#endif
+
+#define	RPT_LOCKOUT_SECS 10
+
+#define MAXPEERSTR 31
+#define	MAXREMSTR 15
+
+#define	DELIMCHR ','
+#define	QUOTECHR 34
+
+#define	MONITOR_DISK_BLOCKS_PER_MINUTE 38
+
+#define	DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
+#define	DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
+#define	DEFAULT_REMOTE_TIMEOUT (60 * 60)
+#define	DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
+#define	DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
+
+#define	NODES "nodes"
+#define	EXTNODES "extnodes"
+#define MEMORY "memory"
+#define MACRO "macro"
+#define	FUNCTIONS "functions"
+#define TELEMETRY "telemetry"
+#define MORSE "morse"
+#define	TONEMACRO "tonemacro"
+#define	FUNCCHAR '*'
+#define	ENDCHAR '#'
+#define	EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
+#define	NODENAMES "rpt/nodenames"
+#define	PARROTFILE "/tmp/parrot_%s_%u"
+
+#define	PARROTTIME 1000
+
+#define	DEFAULT_IOBASE 0x378
+
+#define	DEFAULT_CIV_ADDR 0x58
+
+#define	MAXCONNECTTIME 5000
+
+#define MAXNODESTR 300
+
+#define MAXNODELEN 16
+
+#define MAXIDENTLEN 32
+
+#define MAXPATCHCONTEXT 100
+
+#define ACTIONSIZE 32
+
+#define TELEPARAMSIZE 256
+
+#define REM_SCANTIME 100
+
+#define	DTMF_LOCAL_TIME 250
+#define	DTMF_LOCAL_STARTTIME 500
+
+#define	IC706_PL_MEMORY_OFFSET 50
+
+#define	VOX_ON_DEBOUNCE_COUNT 3
+#define	VOX_OFF_DEBOUNCE_COUNT 20
+#define	VOX_MAX_THRESHOLD 10000.0
+#define	VOX_MIN_THRESHOLD 3000.0
+#define	VOX_TIMEOUT_MS 5000
+#define	VOX_RECOVER_MS 500
+#define	SIMPLEX_PATCH_DELAY 25
+#define	SIMPLEX_PHONE_DELAY 25
+
+#define	STATPOST_PROGRAM "/usr/bin/wget,-q,--output-document=/dev/null,--no-check-certificate"
+
+#define	ALLOW_LOCAL_CHANNELS
+
+enum {REM_OFF,REM_MONITOR,REM_TX};
+
+enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
+	CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME, PLAYBACK,
+	STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
+	TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
+	MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
+	REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE, TOPKEY,
+	TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX, PARROT,
+	STATS_TIME_LOCAL};
+
+
+enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
+
+enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
+
+enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
+
+enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE, SOURCE_ALT};
+
+enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY, DLY_PARROT};
+
+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$")
+
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <search.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/io.h>
+#include <sys/vfs.h>
+#include <math.h>
+#ifdef OLD_ASTERISK
+#include <linux/zaptel.h>
+//#include <tonezone.h>
+#else
+#include <zaptel/zaptel.h>
+//#include <zaptel/tonezone.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "asterisk/utils.h"
+#include "asterisk/lock.h"
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/callerid.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/translate.h"
+#include "asterisk/features.h"
+#include "asterisk/options.h"
+#include "asterisk/cli.h"
+#include "asterisk/config.h"
+#include "asterisk/say.h"
+#include "asterisk/localtime.h"
+#include "asterisk/cdr.h"
+#include "asterisk/options.h"
+#include "asterisk/manager.h"
+#include "asterisk/indications.h"
+#include <termios.h>
+
+#ifdef	NEW_ASTERISK
+struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
+#endif
+
+
+/* Start a tone-list going */
+int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
+/*! Stop the tones from playing */
+void ast_playtones_stop(struct ast_channel *chan);
+
+static  char *tdesc = "Radio Repeater / Remote Base  version 0.904  8/6/2008";
+
+static char *app = "Rpt";
+
+static char *synopsis = "Radio Repeater/Remote Base Control System";
+
+static char *descrip = 
+"  Rpt(nodename[|options][|M][|*]):  \n"
+"    Radio Remote Link or Remote Base Link Endpoint Process.\n"
+"\n"
+"    Not specifying an option puts it in normal endpoint mode (where source\n"
+"    IP and nodename are verified).\n"
+"\n"
+"    Options are as follows:\n"
+"\n"
+"        X - Normal endpoint mode WITHOUT security check. Only specify\n"
+"            this if you have checked security already (like with an IAX2\n"
+"            user/password or something).\n"
+"\n"
+"        Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
+"            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
+"            specified by the 'announce-string') is played on radio system.\n"
+"            Users of radio system can access autopatch, dial specified\n"
+"            code, and pick up call. Announce-string is list of names of\n"
+"            recordings, or \"PARKED\" to substitute code for un-parking,\n"
+"            or \"NODE\" to substitute node number.\n"
+"\n"
+"        P - Phone Control mode. This allows a regular phone user to have\n"
+"            full control and audio access to the radio system. For the\n"
+"            user to have DTMF control, the 'phone_functions' parameter\n"
+"            must be specified for the node in 'rpt.conf'. An additional\n"
+"            function (cop,6) must be listed so that PTT control is available.\n"
+"\n"
+"        D - Dumb Phone Control mode. This allows a regular phone user to\n"
+"            have full control and audio access to the radio system. In this\n"
+"            mode, the PTT is activated for the entire length of the call.\n"
+"            For the user to have DTMF control (not generally recomended in\n"
+"            this mode), the 'dphone_functions' parameter must be specified\n"
+"            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
+"            available to the phone user.\n"
+"\n"
+"        S - Simplex Dumb Phone Control mode. This allows a regular phone user\n"
+"            audio-only access to the radio system. In this mode, the\n"
+"            transmitter is toggled on and off when the phone user presses the\n"
+"            funcchar (*) key on the telephone set. In addition, the transmitter\n"
+"            will turn off if the endchar (#) key is pressed. When a user first\n"
+"            calls in, the transmitter will be off, and the user can listen for\n"
+"            radio traffic. When the user wants to transmit, they press the *\n" 
+"            key, start talking, then press the * key again or the # key to turn\n"
+"            the transmitter off.  No other functions can be executed by the\n"
+"            user on the phone when this mode is selected. Note: If your\n"
+"            radio system is full-duplex, we recommend using either P or D\n"
+"            modes as they provide more flexibility.\n"
+"\n"
+"        q - Query Status. Sets channel variables and returns + 101 in plan.\n"
+"\n"
+"        M - Memory Channel Steer as MXX where XX is the memory channel number.\n"
+"\n"
+"        * - Alt Macro to execute (e.g. *7 for status)\n"
+"\n";
+;
+
+static int debug = 0;  /* Set this >0 for extra debug output */
+static int nrpts = 0;
+
+static char remdtmfstr[] = "0123456789*#ABCD";
+
+enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
+
+int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
+
+#define NRPTSTAT 7
+
+struct rpt_chan_stat
+{
+	struct timeval last;
+	long long total;
+	unsigned long count;
+	unsigned long largest;
+	struct timeval largest_time;
+};
+
+char *discstr = "!!DISCONNECT!!";
+char *newkeystr = "!NEWKEY!";
+static char *remote_rig_ft897="ft897";
+static char *remote_rig_rbi="rbi";
+static char *remote_rig_kenwood="kenwood";
+static char *remote_rig_tm271="tm271";
+static char *remote_rig_ic706="ic706";
+static char *remote_rig_rtx150="rtx150";
+static char *remote_rig_rtx450="rtx450";
+static char *remote_rig_ppp16="ppp16";	  		// parallel port programmable 16 channels
+
+#define ISRIG_RTX(x) ((!strcmp(x,remote_rig_rtx150)) || (!strcmp(x,remote_rig_rtx450)))
+#define	IS_XPMR(x) (!strncasecmp(x->rxchanname,"rad",3))
+
+#ifdef	OLD_ASTERISK
+STANDARD_LOCAL_USER;
+LOCAL_USER_DECL;
+#endif
+
+#define	MSWAIT 200
+#define	HANGTIME 5000
+#define	TOTIME 180000
+#define	IDTIME 300000
+#define	MAXRPTS 20
+#define MAX_STAT_LINKS 32
+#define POLITEID 30000
+#define FUNCTDELAY 1500
+
+#define	MAXXLAT 20
+#define	MAXXLATTIME 3
+
+#define MAX_SYSSTATES 10
+
+#define	RPT_MIXER_BLOCKSIZE 160
+#define	RPT_MIXER_MODE_TRANSMIT 1
+#define	RPT_MIXER_MODE_SUBOUT 2
+#define	RPT_MIXER_MODE_RECEIVE 4
+#define	MIXER_LIMIT 32000
+
+struct rpt_mixer {
+	short cursum[RPT_MIXER_BLOCKSIZE];
+	short lastsum[RPT_MIXER_BLOCKSIZE];
+} ;
+
+struct rpt_mixer_sample {
+	short cursample[RPT_MIXER_BLOCKSIZE];
+	short lastsample[RPT_MIXER_BLOCKSIZE];
+} ;
+
+struct rpt_rxtelem {
+	struct rpt_rxtelem *qe_forw;
+	struct rpt_rxtelem *qe_back;
+	struct ast_channel *chan;
+	char cmode;
+} ;
+
+struct vox {
+	float	speech_energy;
+	float	noise_energy;
+	int	enacount;
+	char	voxena;
+	char	lastvox;
+	int	offdebcnt;
+	int	ondebcnt;
+} ;
+
+#define	mymax(x,y) ((x > y) ? x : y)
+#define	mymin(x,y) ((x < y) ? x : y)
+
+struct rpt_topkey
+{
+char	node[TOPKEYMAXSTR];
+int	timesince;
+int	keyed;
+} ;
+
+struct rpt_xlat
+{
+char	funccharseq[MAXXLAT];
+char	endcharseq[MAXXLAT];
+char	passchars[MAXXLAT];
+int	funcindex;
+int	endindex;
+time_t	lastone;
+} ;
+
+static time_t	starttime = 0;
+
+static  pthread_t rpt_master_thread;
+
+struct rpt;
+
+struct rpt_link
+{
+	struct rpt_link *next;
+	struct rpt_link *prev;
+	struct rpt_mixer_sample conf_sample;
+	char	mode;			/* 1 if in tx mode */
+        char    ready;
+	char	isremote;
+	char	phonemode;
+	char	phonevox;		/* vox the phone */
+	char	name[MAXNODESTR];	/* identifier (routing) string */
+	char	lasttx;
+	char	lasttx1;
+	char	lastrx;
+	char	lastrealrx;
+	char	lastrx1;
+	char	connected;
+	char	hasconnected;
+	char	perma;
+	char	thisconnected;
+	char	outbound;
+	char	disced;
+	char	killme;
+	long	elaptime;
+	long	disctime;
+	long 	retrytimer;
+	long	retxtimer;
+	long	rerxtimer;
+	int	retries;
+	int	max_retries;
+	int	reconnects;
+	long long connecttime;
+	struct ast_channel *chan;
+	char	linklist[MAXLINKLIST];
+	time_t	linklistreceived;
+	long	linklisttimer;
+	int	dtmfed;
+	int linkunkeytocttimer;
+	struct timeval lastlinktv;
+	struct	ast_frame *lastf1,*lastf2;
+	struct	rpt_chan_stat chan_stat[NRPTSTAT];
+	struct vox vox;
+	char wasvox;
+	int voxtotimer;
+	char voxtostate;
+	char newkey;
+#ifdef OLD_ASTERISK
+        AST_LIST_HEAD(, ast_frame) linq;
+#else
+	AST_LIST_HEAD_NOLOCK(, ast_frame) linq;
+#endif
+#ifdef OLD_ASTERISK
+        AST_LIST_HEAD(, ast_frame) rxq;
+#else
+	AST_LIST_HEAD_NOLOCK(, ast_frame) rxq;
+#endif
+} ;
+
+struct rpt_lstat
+{
+	struct	rpt_lstat *next;
+	struct	rpt_lstat *prev;
+	char	peer[MAXPEERSTR];
+	char	name[MAXNODESTR];
+	char	mode;
+	char	outbound;
+	char	reconnects;
+	char	thisconnected;
+	long long	connecttime;
+	struct	rpt_chan_stat chan_stat[NRPTSTAT];
+} ;
+
+struct rpt_tele
+{
+	struct rpt_tele *next;
+	struct rpt_tele *prev;
+	struct rpt *rpt;
+	struct ast_channel *chan;
+	int	mode;
+	struct rpt_link mylink;
+	char param[TELEPARAMSIZE];
+	int	submode;
+	unsigned int parrot;
+	pthread_t threadid;
+	unsigned long uid;
+	char cmode;
+	struct ast_channel *rchan;
+	struct rpt_rxtelem *rxtelem;
+} ;
+
+struct function_table_tag
+{
+	char action[ACTIONSIZE];
+	int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
+		int command_source, struct rpt_link *mylink);
+} ;
+
+/* Used to store the morse code patterns */
+
+struct morse_bits
+{		  
+	int len;
+	int ddcomb;
+} ;
+
+struct telem_defaults
+{
+	char name[20];
+	char value[80];
+} ;
+
+
+struct sysstate
+{
+	char txdisable;
+	char totdisable;
+	char linkfundisable;
+	char autopatchdisable;
+	char schedulerdisable;
+	char userfundisable;
+	char alternatetail;
+};
+
+/* rpt cmd support */
+#define CMD_DEPTH 1
+#define CMD_STATE_IDLE 0
+#define CMD_STATE_BUSY 1
+#define CMD_STATE_READY 2
+#define CMD_STATE_EXECUTING 3
+
+struct rpt_cmd_struct
+{
+    int state;
+    int functionNumber;
+    char param[MAXDTMF];
+    char digits[MAXDTMF];
+    int command_source;
+};
+
+static struct rpt
+{
+	ast_mutex_t lock;
+	ast_mutex_t remlock;
+	ast_mutex_t statpost_lock;
+	struct ast_config *cfg;
+	char reload;
+	char xlink;		 							// cross link state of a share repeater/remote radio
+	char firstone;
+        char ready;
+	unsigned int statpost_seqno;
+
+	char *name;
+	char *rxchanname;
+	char *txchanname;
+	char remote;
+	char *remoterig;
+	struct	rpt_chan_stat chan_stat[NRPTSTAT];
+	unsigned int scram;
+
+	struct {
+		char *ourcontext;
+		char *ourcallerid;
+		char *acctcode;
+		char *ident;
+		char *tonezone;
+		char simple;
+		char *functions;
+		char *link_functions;
+		char *phone_functions;
+		char *dphone_functions;
+		char *alt_functions;
+		char *nodes;
+		char *extnodes;
+		char *extnodefile;
+		int hangtime;
+		int althangtime;
+		int totime;
+		int idtime;
+		int tailmessagetime;
+		int tailsquashedtime;
+		int duplex;
+		int politeid;
+		char *tailmessages[500];
+		int tailmessagemax;
+		char	*memory;
+		char	*macro;
+		char	*tonemacro;
+		char	*startupmacro;
+		int iobase;
+		char *ioport;
+		char funcchar;
+		char endchar;
+		char nobusyout;
+		char notelemtx;
+		char propagate_dtmf;
+		char propagate_phonedtmf;
+		char linktolink;
+		unsigned char civaddr;
+		struct rpt_xlat inxlat;
+		struct rpt_xlat outxlat;
+		char *archivedir;
+		int authlevel;
+		char *csstanzaname;
+		char *skedstanzaname;
+		char *txlimitsstanzaname;
+		long monminblocks;
+		int remoteinacttimeout;
+		int remotetimeout;
+		int remotetimeoutwarning;
+		int remotetimeoutwarningfreq;
+		int sysstate_cur;
+		struct sysstate s[MAX_SYSSTATES];
+		char parrotmode;
+		int parrottime;
+		char *rptnode;
+		char remote_mars;
+		int voxtimeout_ms;
+		int voxrecover_ms;
+		int simplexpatchdelay;
+		int simplexphonedelay;
+		char *statpost_program;
+		char *statpost_url;
+	} p;
+	struct rpt_link links;
+	int unkeytocttimer;
+	time_t lastkeyedtime;
+	time_t lasttxkeyedtime;
+	char keyed;
+	char txkeyed;
+	char exttx;
+	char localtx;
+	char remoterx;
+	char remotetx;
+	char remoteon;
+	char remtxfreqok;
+	char tounkeyed;
+	char tonotify;
+	char dtmfbuf[MAXDTMF];
+	char macrobuf[MAXMACRO];
+	char rem_dtmfbuf[MAXDTMF];
+	char lastdtmfcommand[MAXDTMF];
+	char cmdnode[50];
+	char nowchan;						// channel now
+	char waschan;						// channel selected initially or by command
+	char bargechan;						// barge in channel
+	char macropatch;					// autopatch via tonemacro state
+	char parrotstate;
+	int  parrottimer;
+	unsigned int parrotcnt;
+	struct ast_channel *rxchannel,*txchannel,*pchannel,*timingchannel;
+	struct ast_channel *remchannel;
+	struct ast_frame *lastf1,*lastf2;
+	struct rpt_tele tele;
+	struct rpt_rxtelem rxtele;
+	struct timeval lasttv,curtv;
+	pthread_t rpt_call_thread,rpt_thread;
+	time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
+	int calldigittimer;
+	struct rpt_mixer conf;
+	struct rpt_mixer txconf;
+	int tailtimer,totimer,idtimer,callmode,cidx,scantimer,tmsgtimer,skedtimer;
+	int mustid,tailid;
+	int tailevent;
+	int telemrefcount;
+	int dtmfidx,rem_dtmfidx;
+	int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
+	int totalexecdcommands, dailyexecdcommands;
+	long	retxtimer;
+	long	rerxtimer;
+	long long totaltxtime;
+	char mydtmf;
+	char exten[AST_MAX_EXTENSION];
+	char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
+	char offset;
+	char powerlevel;
+	char txplon;
+	char rxplon;
+	char remmode;
+	char tunerequest;
+	char hfscanmode;
+	int hfscanstatus;
+	char hfscanstop;
+	char lastlinknode[MAXNODESTR];
+	char savednodes[MAXNODESTR];
+	int stopgen;
+	char patchfarenddisconnect;
+	char patchnoct;
+	char patchquiet;
+	char patchcontext[MAXPATCHCONTEXT];
+	int patchdialtime;
+	int macro_longest;
+	int phone_longestfunc;
+	int alt_longestfunc;
+	int dphone_longestfunc;
+	int link_longestfunc;
+	int longestfunc;
+	int longestnode;
+	int threadrestarts;		
+	int tailmessagen;
+	time_t disgorgetime;
+	time_t lastthreadrestarttime;
+	long	macrotimer;
+	char	lastnodewhichkeyedusup[MAXNODESTR];
+	int	dtmf_local_timer;
+	char	dtmf_local_str[100];
+	char	loginuser[50];
+	char	loginlevel[10];
+	long	authtelltimer;
+	long	authtimer;
+	int iofd;
+	time_t start_time,last_activity_time;
+	char	lasttone[32];
+	struct rpt_tele *active_telem;
+	struct 	rpt_topkey topkey[TOPKEYN];
+	int topkeystate;
+	time_t topkeytime;
+	int topkeylong;
+	struct vox vox;
+	char wasvox;
+	int voxtotimer;
+	char voxtostate;
+	int linkposttimer;			
+	int keyposttimer;			
+	char newkey;
+	char inpadtest;
+	struct rpt_mixer_sample pconf_sample;
+	unsigned long uid;
+	char iszap;
+	char myfirsttx;
+	short pcq[RPT_MIXER_BLOCKSIZE];
+	char pcqflag;
+#ifdef OLD_ASTERISK
+        AST_LIST_HEAD(, ast_frame) inq;
+#else
+	AST_LIST_HEAD_NOLOCK(, ast_frame) inq;
+#endif
+#ifdef OLD_ASTERISK
+	AST_LIST_HEAD(, ast_frame) txq;
+#else
+	AST_LIST_HEAD_NOLOCK(, ast_frame) txq;
+#endif
+	char txrealkeyed;
+#ifdef	__RPT_NOTCH
+	struct rptfilter
+	{
+		char	desc[100];
+		float	x0;
+		float	x1;
+		float	x2;
+		float	y0;
+		float	y1;
+		float	y2;
+		float	gain;
+		float	const0;
+		float	const1;
+		float	const2;
+	} filters[MAXFILTERS];
+#endif
+#ifdef	_MDC_DECODE_H_
+	mdc_decoder_t *mdc;
+	unsigned short lastunit;
+#endif
+	struct rpt_cmd_struct cmdAction;
+} rpt_vars[MAXRPTS];	
+
+struct nodelog {
+struct nodelog *next;
+struct nodelog *prev;
+time_t	timestamp;
+char archivedir[MAXNODESTR];
+char str[MAXNODESTR * 2];
+} nodelog;
+
+static int service_scan(struct rpt *myrpt);
+static int set_mode_ft897(struct rpt *myrpt, char newmode);
+static int set_mode_ic706(struct rpt *myrpt, char newmode);
+static int simple_command_ft897(struct rpt *myrpt, char command);
+static int setrem(struct rpt *myrpt);
+static int setrtx_check(struct rpt *myrpt);
+static int channel_revert(struct rpt *myrpt);
+static int channel_steer(struct rpt *myrpt, char *data);
+
+AST_MUTEX_DEFINE_STATIC(nodeloglock);
+
+AST_MUTEX_DEFINE_STATIC(nodelookuplock);
+
+#ifdef	APP_RPT_LOCK_DEBUG
+
+#warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
+
+#define	MAXLOCKTHREAD 100
+
+#define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
+#define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
+
+struct lockthread
+{
+	pthread_t id;
+	int lockcount;
+	int lastlock;
+	int lastunlock;
+} lockthreads[MAXLOCKTHREAD];
+
+
+struct by_lightning
+{
+	int line;
+	struct timeval tv;
+	struct rpt *rpt;
+	struct lockthread lockthread;
+} lock_ring[32];
+
+int lock_ring_index = 0;
+
+AST_MUTEX_DEFINE_STATIC(locklock);
+
+static struct lockthread *get_lockthread(pthread_t id)
+{
+int	i;
+
+	for(i = 0; i < MAXLOCKTHREAD; i++)
+	{
+		if (lockthreads[i].id == id) return(&lockthreads[i]);
+	}
+	return(NULL);
+}
+
+static struct lockthread *put_lockthread(pthread_t id)
+{
+int	i;
+
+	for(i = 0; i < MAXLOCKTHREAD; i++)
+	{
+		if (lockthreads[i].id == id)
+			return(&lockthreads[i]);
+	}
+	for(i = 0; i < MAXLOCKTHREAD; i++)
+	{
+		if (!lockthreads[i].id)
+		{
+			lockthreads[i].lockcount = 0;
+			lockthreads[i].lastlock = 0;
+			lockthreads[i].lastunlock = 0;
+			lockthreads[i].id = id;
+			return(&lockthreads[i]);
+		}
+	}
+	return(NULL);
+}
+
+
+static void rpt_mutex_spew(void)
+{
+	struct by_lightning lock_ring_copy[32];
+	int lock_ring_index_copy;
+	int i,j;
+	long long diff;
+	char a[100];
+	struct timeval lasttv;
+
+	ast_mutex_lock(&locklock);
+	memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
+	lock_ring_index_copy = lock_ring_index;
+	ast_mutex_unlock(&locklock);
+
+	lasttv.tv_sec = lasttv.tv_usec = 0;
+	for(i = 0 ; i < 32 ; i++)
+	{
+		j = (i + lock_ring_index_copy) % 32;
+		strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
+			localtime(&lock_ring_copy[j].tv.tv_sec));
+		diff = 0;
+		if(lasttv.tv_sec)
+		{
+			diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
+				* 1000000;
+			diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
+		}
+		lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
+		lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
+		if (!lock_ring_copy[j].tv.tv_sec) continue;
+		if (lock_ring_copy[j].line < 0)
+		{
+			ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
+				i - 31,-lock_ring_copy[j].line,lock_ring_copy[j].rpt->name,(int) lock_ring_copy[j].lockthread.id,diff,a,(int)lock_ring_copy[j].tv.tv_usec);
+		}
+		else
+		{
+			ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
+				i - 31,lock_ring_copy[j].line,lock_ring_copy[j].rpt->name,(int) lock_ring_copy[j].lockthread.id,diff,a,(int)lock_ring_copy[j].tv.tv_usec);
+		}
+	}
+}
+
+
+static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
+{
+struct lockthread *t;
+pthread_t id;
+
+	id = pthread_self();
+	ast_mutex_lock(&locklock);
+	t = put_lockthread(id);
+	if (!t)
+	{
+		ast_mutex_unlock(&locklock);
+		return;
+	}
+	if (t->lockcount)
+	{
+		int lastline = t->lastlock;
+		ast_mutex_unlock(&locklock);
+		ast_log(LOG_NOTICE,"rpt_mutex_lock: Double lock request line %d node %s pid %x, last lock was line %d\n",line,myrpt->name,(int) t->id,lastline);
+		rpt_mutex_spew();
+		return;
+	}
+	t->lastlock = line;
+	t->lockcount = 1;
+	gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
+	lock_ring[lock_ring_index].rpt = myrpt;
+	memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
+	lock_ring[lock_ring_index++].line = line;
+	if(lock_ring_index == 32)
+		lock_ring_index = 0;
+	ast_mutex_unlock(&locklock);
+	ast_mutex_lock(lockp);
+}
+
+
+static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
+{
+struct lockthread *t;
+pthread_t id;
+
+	id = pthread_self();
+	ast_mutex_lock(&locklock);
+	t = put_lockthread(id);
+	if (!t)
+	{
+		ast_mutex_unlock(&locklock);
+		return;
+	}
+	if (!t->lockcount)
+	{
+		int lastline = t->lastunlock;
+		ast_mutex_unlock(&locklock);
+		ast_log(LOG_NOTICE,"rpt_mutex_lock: Double un-lock request line %d node %s pid %x, last un-lock was line %d\n",line,myrpt->name,(int) t->id,lastline);
+		rpt_mutex_spew();
+		return;
+	}
+	t->lastunlock = line;
+	t->lockcount = 0;
+	gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
+	lock_ring[lock_ring_index].rpt = myrpt;
+	memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
+	lock_ring[lock_ring_index++].line = -line;
+	if(lock_ring_index == 32)
+		lock_ring_index = 0;
+	ast_mutex_unlock(&locklock);
+	ast_mutex_unlock(lockp);
+}
+
+#else  /* APP_RPT_LOCK_DEBUG */
+
+#define rpt_mutex_lock(x) ast_mutex_lock(x)
+#define rpt_mutex_unlock(x) ast_mutex_unlock(x)
+
+#endif  /* APP_RPT_LOCK_DEBUG */
+
+/* node logging function */
+static void donodelog(struct rpt *myrpt,char *str)
+{
+struct nodelog *nodep;
+char	datestr[100];
+
+	if (!myrpt->p.archivedir) return;
+	nodep = (struct nodelog *)ast_malloc(sizeof(struct nodelog));
+	if (nodep == NULL)
+	{
+		ast_log(LOG_ERROR,"Cannot get memory for node log");
+		return;
+	}
+	time(&nodep->timestamp);
+	strncpy(nodep->archivedir,myrpt->p.archivedir,
+		sizeof(nodep->archivedir) - 1);
+	strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
+		localtime(&nodep->timestamp));
+	snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
+		myrpt->name,datestr,str);
+	ast_mutex_lock(&nodeloglock);
+	insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
+	ast_mutex_unlock(&nodeloglock);
+}
+
+static void rpt_mixer_reset(struct rpt_mixer *r)
+{
+	memset(r,0,sizeof(struct rpt_mixer));
+	return;
+}
+
+static void rpt_mixer_next(struct rpt_mixer *r)
+{
+int	i;
+
+	for(i = 0; i < RPT_MIXER_BLOCKSIZE; i++)
+	{
+		r->lastsum[i] = r->cursum[i];
+		r->cursum[i] = 0;
+	}
+	return;
+}
+
+static void rpt_mixer_next_sample(struct rpt_mixer_sample *rs)
+{
+int	i;
+
+	for(i = 0; i < RPT_MIXER_BLOCKSIZE; i++)
+	{
+		rs->lastsample[i] = rs->cursample[i];
+		rs->cursample[i] = 0;
+	}
+	return;
+}
+
+static void rpt_mixer_put(struct rpt_mixer *r,short *buf,
+	struct rpt_mixer_sample *rs)
+{
+int	i;
+long	retval;
+
+	for(i = 0; i < RPT_MIXER_BLOCKSIZE; i++)
+	{
+		if (rs) rs->cursample[i] = buf[i];
+		retval = r->cursum[i];
+		retval += buf[i];
+		if (retval < -MIXER_LIMIT) retval = -MIXER_LIMIT;
+		if (retval > MIXER_LIMIT) retval = MIXER_LIMIT;
+		r->cursum[i] = (short) retval;
+	}
+	return;
+}
+
+static void rpt_mixer_get(struct rpt_mixer *r,short *buf,
+	struct rpt_mixer_sample *rs)
+{
+long	retval;
+int	i;
+
+	for(i = 0; i < RPT_MIXER_BLOCKSIZE; i++)
+	{
+		retval = r->lastsum[i];
+		if (rs) retval -= rs->lastsample[i];
+		if (retval < -MIXER_LIMIT) retval = -MIXER_LIMIT;
+		if (retval > MIXER_LIMIT) retval = MIXER_LIMIT;
+		buf[i] = (short) retval;
+	}
+	return;
+
+}
+ 
+static void rpt_mixer_voyeur(struct rpt_mixer *src,struct rpt_mixer *dst)
+{
+int	i;
+long	retval;
+
+	for(i = 0; i < RPT_MIXER_BLOCKSIZE; i++)
+	{
+		retval = src->cursum[i];
+		retval += dst->cursum[i];
+		if (retval < -MIXER_LIMIT) retval = -MIXER_LIMIT;
+		if (retval > MIXER_LIMIT) retval = MIXER_LIMIT;
+		dst->cursum[i] = retval;
+	}
+}
+
+static void rpt_do_mix(void)
+{
+	int	n,x;
+	struct ast_frame fr;
+	char	buf[(RPT_MIXER_BLOCKSIZE * sizeof(short)) + 
+		    AST_FRIENDLY_OFFSET + 10],remrx,totx,remnomute;
+	struct timeval now;
+	struct rpt_link *l,*m;
+	struct ast_frame *f1;
+	
+	for(n = 0; n < nrpts; n++)
+	{
+		if (!rpt_vars[n].ready) continue;
+#ifdef	APP_RPT_LOCK_DEBUG 
+		_rpt_mutex_lock(&rpt_vars[n].lock,&rpt_vars[n],__LINE__);
+#else
+		rpt_mutex_lock(&rpt_vars[n].lock);
+#endif
+		if (rpt_vars[n].keyed)
+		{
+			x = 0;
+			AST_LIST_TRAVERSE(&rpt_vars[n].inq, f1,frame_list) x++;
+			if (x > 1)
+			{
+				f1 = AST_LIST_REMOVE_HEAD(&rpt_vars[n].inq,
+					frame_list);
+				rpt_mixer_put(&rpt_vars[n].conf,f1->data,NULL);
+				ast_frfree(f1);
+			} 
+		}
+		else
+		{
+			while(!AST_LIST_EMPTY(&rpt_vars[n].inq))
+			{
+				f1 = AST_LIST_REMOVE_HEAD(&rpt_vars[n].inq,
+					frame_list);
+				ast_frfree(f1);
+			}
+		}
+		if ((!rpt_vars[n].remote) && rpt_vars[n].pcqflag)
+		{
+			rpt_mixer_put(&rpt_vars[n].conf,
+				rpt_vars[n].pcq,&rpt_vars[n].pconf_sample);
+			rpt_vars[n].pcqflag = 0;
+		}
+	        /* go thru all links */
+	        if ((!rpt_vars[n].remote) && (rpt_vars[n].links.next != &rpt_vars[n].links))
+	            for(l = rpt_vars[n].links.next; l != &rpt_vars[n].links; l = l->next)
+	            {
+        	        if (!l->chan) continue;
+			if (!l->ready) continue;
+			x = 0;
+			AST_LIST_TRAVERSE(&l->linq, f1,frame_list) x++;
+			if (l->lastrx)
+			{
+				x = 0;
+				AST_LIST_TRAVERSE(&l->linq, f1,frame_list) x++;
+				if (x > 1)
+				{
+					f1 = AST_LIST_REMOVE_HEAD(&l->linq,frame_list);
+					rpt_mixer_put(&rpt_vars[n].conf,f1->data,&l->conf_sample);
+					ast_frfree(f1);
+				}
+			}
+			else
+			{
+				while(!AST_LIST_EMPTY(&l->linq))
+				{
+					f1 = AST_LIST_REMOVE_HEAD(&l->linq,frame_list);
+					ast_frfree(f1);
+				}
+			}
+		    }
+	        rpt_mixer_voyeur(&rpt_vars[n].conf,&rpt_vars[n].txconf);
+	        rpt_mixer_next(&rpt_vars[n].conf);				
+	        rpt_mixer_next(&rpt_vars[n].txconf);				
+#ifdef	APP_RPT_LOCK_DEBUG 
+		_rpt_mutex_unlock(&rpt_vars[n].lock,&rpt_vars[n],__LINE__);
+#else
+		rpt_mutex_unlock(&rpt_vars[n].lock);
+#endif
+	}
+	fr.datalen = RPT_MIXER_BLOCKSIZE * sizeof(short);
+	fr.samples = fr.datalen / 2;
+	fr.frametype = AST_FRAME_VOICE;
+	fr.subclass = AST_FORMAT_SLINEAR;
+	fr.data =  buf + AST_FRIENDLY_OFFSET;
+	fr.src = "rpt_domix()";
+	fr.offset = AST_FRIENDLY_OFFSET;
+	fr.mallocd=0;
+	fr.delivery.tv_sec = 0;
+	fr.delivery.tv_usec = 0;
+
+	for(n = 0; n < nrpts; n++)
+	{
+		if (!rpt_vars[n].ready) continue;
+#ifdef	APP_RPT_LOCK_DEBUG 
+		_rpt_mutex_lock(&rpt_vars[n].lock,&rpt_vars[n],__LINE__);
+#else
+		rpt_mutex_lock(&rpt_vars[n].lock);
+#endif
+	        /* go thru all links */
+	        if ((!rpt_vars[n].remote) && (rpt_vars[n].links.next != &rpt_vars[n].links))
+	            for(l = rpt_vars[n].links.next; l != &rpt_vars[n].links; l = l->next)
+	            {
+	                if (!l || !l->chan) continue;
+			if (!l->ready) continue;
+        	        rpt_mixer_next_sample(&l->conf_sample);
+	            }
+	        rpt_mixer_get(&rpt_vars[n].txconf,fr.data,NULL);
+		if ((!rpt_vars[n].remote) && (rpt_vars[n].p.duplex < 2))
+		{
+			if (rpt_vars[n].txrealkeyed) 
+			{
+				if ((!rpt_vars[n].myfirsttx) && rpt_vars[n].callmode)
+				{
+					x = 0;
+					AST_LIST_TRAVERSE(&rpt_vars[n].txq, f1,frame_list) x++;
+					for(;x < rpt_vars[n].p.simplexpatchdelay; x++)
+					{
+						f1 = ast_frdup(&fr);
+						memset(f1->data,0,f1->datalen);
+						AST_LIST_INSERT_TAIL(&rpt_vars[n].txq,f1,frame_list);
+					}
+					rpt_vars[n].myfirsttx = 1;
+				}
+				f1 = ast_frdup(&fr);
+				AST_LIST_INSERT_TAIL(&rpt_vars[n].txq,f1,frame_list);
+			} else rpt_vars[n].myfirsttx = 0;
+			x = 0;
+			AST_LIST_TRAVERSE(&rpt_vars[n].txq, f1,frame_list) x++;
+			if (!x)
+			{
+				memset(fr.data,0,fr.datalen);
+			}
+			else
+			{
+				f1 = AST_LIST_REMOVE_HEAD(&rpt_vars[n].txq,
+					frame_list);
+				ast_write(rpt_vars[n].txchannel,f1);
+				ast_frfree(f1);
+			}
+		}
+		else
+		{
+			if (!rpt_vars[n].remote)
+			{
+				ast_write(rpt_vars[n].txchannel,&fr);
+			}
+			else
+			{
+				ast_write(rpt_vars[n].remchannel,&fr);
+			}
+			while((f1 = AST_LIST_REMOVE_HEAD(&rpt_vars[n].txq,
+				frame_list))) ast_frfree(f1);
+		}
+		if ((!rpt_vars[n].remote) && (rpt_vars[n].pchannel && rpt_vars[n].callmode))
+		{
+			rpt_mixer_next_sample(&rpt_vars[n].pconf_sample);
+		        rpt_mixer_get(&rpt_vars[n].conf,fr.data,
+				&rpt_vars[n].pconf_sample);
+		        ast_write(rpt_vars[n].pchannel,&fr);
+		}			
+	        /* go thru all links */
+	        if ((!rpt_vars[n].remote) && (rpt_vars[n].links.next != &rpt_vars[n].links))
+	            for(l = rpt_vars[n].links.next; l != &rpt_vars[n].links; l = l->next)
+	            {
+        	        if (!l->chan) continue;
+			if (!l->ready) continue;
+	                rpt_mixer_get(&rpt_vars[n].conf,fr.data,
+                              &l->conf_sample);
+	                ast_write(l->chan,&fr);
+	            }
+#ifdef	APP_RPT_LOCK_DEBUG 
+		_rpt_mutex_unlock(&rpt_vars[n].lock,&rpt_vars[n],__LINE__);
+#else
+		rpt_mutex_unlock(&rpt_vars[n].lock);
+#endif
+	}
+	for(n = 0; n < nrpts; n++)
+	{
+		if (!rpt_vars[n].ready) continue;
+		if (rpt_vars[n].remote) continue;
+#ifdef	APP_RPT_LOCK_DEBUG 
+		_rpt_mutex_lock(&rpt_vars[n].lock,&rpt_vars[n],__LINE__);
+#else
+		rpt_mutex_lock(&rpt_vars[n].lock);
+#endif
+	        /* go thru all links */
+	        if (rpt_vars[n].links.next != &rpt_vars[n].links)
+	            for(l = rpt_vars[n].links.next; l != &rpt_vars[n].links; l = l->next)
+		{
+			remrx = 0;
+			/* see if any other links are receiving */
+			m = rpt_vars[n].links.next;
+			while(m != &rpt_vars[n].links)
+			{
+				/* if not us, count it */
+				if ((m != l) && (m->lastrx)) remrx = 1;
+				m = m->next;
+			}
+			now = ast_tvnow();
+			if ((!l->lastlinktv.tv_sec) ||
+				(ast_tvdiff_ms(now,l->lastlinktv) >= 19))
+			{
+				l->lastlinktv = now;
+				remnomute = rpt_vars[n].localtx && 
+				    (!(rpt_vars[n].cmdnode[0] || 
+					(rpt_vars[n].dtmfidx > -1)));
+				totx = (((l->isremote) ? (remnomute) : 
+					rpt_vars[n].exttx) || remrx) && l->mode;
+				if (l->phonemode == 0 && l->chan && (l->lasttx != totx))
+				{
+					if (totx)
+					{
+						ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
+					}
+					else
+					{
+						ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
+					}
+					if (rpt_vars[n].p.archivedir)
+					{
+						char str[100];
+
+						if (totx)
+							sprintf(str,"TXKEY,%s",l->name);
+						else

[... 14135 lines stripped ...]



More information about the svn-commits mailing list