Thu Jul 9 13:40:48 2009

Asterisk developer's documentation


app_rpt.c File Reference

Radio Repeater / Remote Base program version 0.48 06/13/06. More...

#include "asterisk.h"
#include <signal.h>
#include <search.h>
#include <sys/stat.h>
#include <dirent.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/io.h>
#include <math.h>
#include <dahdi/user.h>
#include <dahdi/tonezone.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/file.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/cli.h"
#include "asterisk/config.h"
#include "asterisk/say.h"
#include "asterisk/localtime.h"
#include "asterisk/app.h"

Go to the source code of this file.

Data Structures

struct  function_table_tag
struct  morse_bits
struct  rpt
struct  rpt_link
struct  rpt_lstat
struct  rpt_tele
struct  telem_defaults

Defines

#define ACTIONSIZE   32
#define DEFAULT_IOBASE   0x378
#define DELIMCHR   ','
#define DISC_TIME   10000
#define DTMF_TIMEOUT   3
#define ENDCHAR   '#'
#define FUNCCHAR   '*'
#define FUNCTDELAY   1500
#define FUNCTIONS   "functions"
#define GOSUB   "gosub"
#define GOSUBPTIME   500
#define GOSUBTIME   100
#define HANGTIME   5000
#define IDTIME   300000
#define MACRO   "macro"
#define MACROPTIME   500
#define MACROTIME   100
#define MAX_RETRIES   5
#define MAX_STAT_LINKS   32
#define MAXCONNECTTIME   5000
#define MAXDTMF   32
#define MAXGOSUB   2048
#define MAXMACRO   2048
#define MAXNODESTR   300
#define MAXPATCHCONTEXT   100
#define MAXPEERSTR   31
#define MAXREMSTR   15
#define MAXRPTS   20
#define MEMORY   "memory"
#define MORSE   "morse"
#define MSWAIT   200
#define NODES   "nodes"
#define POLITEID   30000
#define QUOTECHR   34
#define REDUNDANT_TX_TIME   2000
#define REM_SCANTIME   100
#define RETRY_TIMER_MS   5000
#define rpt_mutex_lock(x)   ast_mutex_lock(x)
#define rpt_mutex_unlock(x)   ast_mutex_unlock(x)
#define split_ctcss_freq(hertz, decimal, freq)   split_decimal(freq, hertz, decimal, 1)
#define split_freq(mhz, decimal, freq)   split_decimal(freq, mhz, decimal, 5)
#define TELEMETRY   "telemetry"
#define TELEPARAMSIZE   256
#define TOTIME   180000

Enumerations

enum  { REM_OFF, REM_MONITOR, REM_TX }
enum  {
  ID, PROC, TERM, COMPLETE,
  UNKEY, REMDISC, REMALREADY, REMNOTFOUND,
  REMGO, CONNECTED, CONNFAIL, STATUS,
  TIMEOUT, ID1, STATS_TIME, STATS_VERSION,
  IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
  TAILMSG, MACRO_NOTFOUND, GOSUB_NOTFOUND, MACRO_BUSY,
  GOSUB_BUSY, LASTNODEKEY
}
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_DOKEY
}
enum  {
  SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE,
  SOURCE_DPHONE
}
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
}

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int attempt_reconnect (struct rpt *myrpt, struct rpt_link *l)
static int check_freq (struct rpt *myrpt, int m, int d, int *defmode)
static int check_freq_ft897 (int m, int d, int *defmode)
static int check_freq_rbi (int m, int d, int *defmode)
static int closerem (struct rpt *myrpt)
static int closerem_ft897 (struct rpt *myrpt)
static int collect_function_digits (struct rpt *myrpt, char *digits, int command_source, struct rpt_link *mylink)
static void do_scheduler (struct rpt *myrpt)
static int function_autopatchdn (struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
static int function_autopatchup (struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
static int function_cop (struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
static int function_gosub (struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
static int function_ilink (struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
static int function_macro (struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
static int function_remote (struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
static int function_status (struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
static int get_wait_interval (struct rpt *myrpt, int type)
static char * handle_cli_rpt_debug_level (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_rpt_dump (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_rpt_lstats (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_rpt_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_rpt_restart (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_rpt_stats (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void handle_link_data (struct rpt *myrpt, struct rpt_link *mylink, char *str)
static void handle_link_phone_dtmf (struct rpt *myrpt, struct rpt_link *mylink, char c)
static int handle_remote_data (struct rpt *myrpt, char *str)
static int handle_remote_dtmf_digit (struct rpt *myrpt, char c, char *keyed, int phonemode)
static int handle_remote_phone_dtmf (struct rpt *myrpt, char c, char *keyed, int phonemode)
static int load_module (void)
static void load_rpt_vars (int n, int init)
static void local_dtmf_helper (struct rpt *myrpt, char c)
static int matchkeyword (char *string, char **param, char *keywords[])
static int multimode_bump_freq (struct rpt *myrpt, int interval)
static int multimode_bump_freq_ft897 (struct rpt *myrpt, int interval)
static int multimode_capable (struct rpt *myrpt)
static int myatoi (const char *str)
static int play_silence (struct ast_channel *chan, int duration)
static int play_tone (struct ast_channel *chan, int freq, int duration, int amplitude)
static int play_tone_pair (struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
static void queue_id (struct rpt *myrpt)
static int rbi_mhztoband (char *str)
static void rbi_out (struct rpt *myrpt, unsigned char *data)
static void rbi_out_parallel (struct rpt *myrpt, unsigned char *data)
static int rbi_pltocode (char *str)
static int reload (void)
static int retrieve_astcfgint (struct rpt *myrpt, const char *category, const char *name, int min, int max, int defl)
static int rmt_saycharstr (struct rpt *myrpt, struct ast_channel *chan, int delay, char *charstr)
static int rmt_sayfile (struct rpt *myrpt, struct ast_channel *chan, int delay, char *filename)
static int rmt_telem_finish (struct rpt *myrpt, struct ast_channel *chan)
static int rmt_telem_start (struct rpt *myrpt, struct ast_channel *chan, int delay)
static void * rpt (void *this)
static void * rpt_call (void *this)
static int rpt_exec (struct ast_channel *chan, void *data)
static void * rpt_master (void *config)
static void * rpt_tele_thread (void *this)
static void rpt_telemetry (struct rpt *myrpt, int mode, void *data)
static int saycharstr (struct ast_channel *mychannel, char *str)
static int saydigits (struct ast_channel *mychannel, int num)
static int sayfile (struct ast_channel *mychannel, const char *fname)
static int saynum (struct ast_channel *mychannel, int num)
static void send_link_dtmf (struct rpt *myrpt, char c)
static int send_morse (struct ast_channel *chan, const char *string, int speed, int freq, int amplitude)
static int send_tone_telemetry (struct ast_channel *chan, const char *tonestring)
static int serial_remote_io (struct rpt *myrpt, unsigned char *txbuf, int txbytes, char *rxbuf, int rxmaxbytes, int asciiflag)
static int service_scan (struct rpt *myrpt)
static int set_ctcss_freq_ft897 (struct rpt *myrpt, char *txtone, char *rxtone)
static int set_ctcss_mode_ft897 (struct rpt *myrpt, char txplon, char rxplon)
static int set_freq_ft897 (struct rpt *myrpt, char *newfreq)
static int set_ft897 (struct rpt *myrpt)
static int set_mode_ft897 (struct rpt *myrpt, char newmode)
static int set_offset_ft897 (struct rpt *myrpt, char offset)
static int setrbi (struct rpt *myrpt)
static int setrem (struct rpt *myrpt)
static int simple_command_ft897 (struct rpt *myrpt, char command)
static char * skipchars (char *string, char *charlist)
static int split_decimal (char *input, int *ints, int *decs, int places)
static void stop_scan (struct rpt *myrpt, int flag)
static int telem_any (struct rpt *myrpt, struct ast_channel *chan, const char *entry)
static int telem_lookup (struct rpt *myrpt, struct ast_channel *chan, const char *node, const char *name)
static int unload_module (void)
static void wait_interval (struct rpt *myrpt, int type, struct ast_channel *chan)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Radio Repeater / Remote Base" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, }
static char * app = "Rpt"
static const struct ast_module_infoast_module_info = &__mod_info
static struct ast_cli_entry cli_rpt []
static int debug = 0
static char * descrip
char * discstr = "!!DISCONNECT!!"
static struct function_table_tag function_table []
static int nrpts = 0
static char * remote_rig_ft897 = "ft897"
static char * remote_rig_rbi = "rbi"
static pthread_t rpt_master_thread
static struct rpt rpt_vars [MAXRPTS]
static char * synopsis = "Radio Repeater/Remote Base Control System"
static struct telem_defaults tele_defs []
static unsigned int vmajor = 0
static unsigned int vminor = 47


Detailed Description

Radio Repeater / Remote Base program version 0.48 06/13/06.

Author:
Jim Dixon, WB6NIL <jim@lambdatel.com>
Note:
Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
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 2 - Give Time of Day 3 - Give software Version

cop (control operator) cmds:

1 - System warm boot 2 - System enable 3 - System disable 4 - Test Tone On 5 - Dump System Variables on Console (debug) 6 - PTT (phone mode only)

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

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)

'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

Definition in file app_rpt.c.


Define Documentation

#define ACTIONSIZE   32

Definition at line 178 of file app_rpt.c.

#define DEFAULT_IOBASE   0x378

Definition at line 170 of file app_rpt.c.

Referenced by load_rpt_vars().

#define DELIMCHR   ','

Definition at line 157 of file app_rpt.c.

#define DISC_TIME   10000

Definition at line 147 of file app_rpt.c.

Referenced by rpt().

#define DTMF_TIMEOUT   3

Definition at line 141 of file app_rpt.c.

Referenced by handle_remote_dtmf_digit(), and rpt().

#define ENDCHAR   '#'

Definition at line 168 of file app_rpt.c.

Referenced by load_rpt_vars().

#define FUNCCHAR   '*'

Definition at line 167 of file app_rpt.c.

Referenced by load_rpt_vars().

#define FUNCTDELAY   1500

Definition at line 297 of file app_rpt.c.

#define FUNCTIONS   "functions"

Definition at line 164 of file app_rpt.c.

Referenced by load_rpt_vars().

#define GOSUB   "gosub"

Definition at line 163 of file app_rpt.c.

Referenced by load_rpt_vars().

#define GOSUBPTIME   500

Definition at line 140 of file app_rpt.c.

Referenced by rpt().

#define GOSUBTIME   100

Definition at line 138 of file app_rpt.c.

Referenced by function_gosub(), and rpt().

#define HANGTIME   5000

Definition at line 291 of file app_rpt.c.

Referenced by load_rpt_vars().

#define IDTIME   300000

Definition at line 293 of file app_rpt.c.

Referenced by load_rpt_vars().

#define MACRO   "macro"

Definition at line 162 of file app_rpt.c.

Referenced by load_rpt_vars().

#define MACROPTIME   500

Definition at line 139 of file app_rpt.c.

Referenced by rpt().

#define MACROTIME   100

Definition at line 137 of file app_rpt.c.

Referenced by function_macro(), and rpt().

#define MAX_RETRIES   5

Definition at line 148 of file app_rpt.c.

Referenced by function_ilink(), handle_link_data(), and rpt().

#define MAX_STAT_LINKS   32

Definition at line 295 of file app_rpt.c.

Referenced by handle_cli_rpt_stats().

#define MAXCONNECTTIME   5000

Definition at line 172 of file app_rpt.c.

Referenced by rpt().

#define MAXDTMF   32

Definition at line 134 of file app_rpt.c.

Referenced by handle_link_data(), handle_link_phone_dtmf(), handle_remote_dtmf_digit(), and local_dtmf_helper().

#define MAXGOSUB   2048

Definition at line 136 of file app_rpt.c.

#define MAXMACRO   2048

Definition at line 135 of file app_rpt.c.

#define MAXNODESTR   300

Definition at line 174 of file app_rpt.c.

Referenced by function_ilink().

#define MAXPATCHCONTEXT   100

Definition at line 176 of file app_rpt.c.

#define MAXPEERSTR   31

Definition at line 154 of file app_rpt.c.

Referenced by handle_cli_rpt_lstats().

#define MAXREMSTR   15

Definition at line 155 of file app_rpt.c.

Referenced by handle_cli_rpt_lstats(), multimode_bump_freq_ft897(), and setrbi().

#define MAXRPTS   20

Definition at line 294 of file app_rpt.c.

#define MEMORY   "memory"

Definition at line 161 of file app_rpt.c.

Referenced by load_rpt_vars().

#define MORSE   "morse"

Definition at line 166 of file app_rpt.c.

Referenced by telem_any().

#define MSWAIT   200

Definition at line 290 of file app_rpt.c.

Referenced by rpt(), and rpt_call().

#define NODES   "nodes"

Definition at line 160 of file app_rpt.c.

Referenced by load_rpt_vars().

#define POLITEID   30000

Definition at line 296 of file app_rpt.c.

Referenced by load_rpt_vars().

#define QUOTECHR   34

Definition at line 158 of file app_rpt.c.

#define REDUNDANT_TX_TIME   2000

Definition at line 150 of file app_rpt.c.

Referenced by rpt().

#define REM_SCANTIME   100

Definition at line 182 of file app_rpt.c.

Referenced by function_remote().

#define RETRY_TIMER_MS   5000

Definition at line 152 of file app_rpt.c.

Referenced by rpt().

#define rpt_mutex_lock (  )     ast_mutex_lock(x)

Definition at line 678 of file app_rpt.c.

Referenced by attempt_reconnect(), function_autopatchdn(), function_gosub(), function_ilink(), function_macro(), handle_cli_rpt_lstats(), handle_cli_rpt_stats(), handle_link_data(), handle_link_phone_dtmf(), local_dtmf_helper(), queue_id(), rpt(), rpt_call(), rpt_tele_thread(), and rpt_telemetry().

#define rpt_mutex_unlock (  )     ast_mutex_unlock(x)

Definition at line 679 of file app_rpt.c.

Referenced by attempt_reconnect(), function_autopatchdn(), function_gosub(), function_ilink(), function_macro(), handle_cli_rpt_lstats(), handle_link_data(), handle_link_phone_dtmf(), local_dtmf_helper(), queue_id(), rpt(), rpt_call(), rpt_tele_thread(), and rpt_telemetry().

#define split_ctcss_freq ( hertz,
decimal,
freq   )     split_decimal(freq, hertz, decimal, 1)

Definition at line 4125 of file app_rpt.c.

Referenced by set_ctcss_freq_ft897().

#define split_freq ( mhz,
decimal,
freq   )     split_decimal(freq, mhz, decimal, 5)

Definition at line 4119 of file app_rpt.c.

Referenced by function_remote(), multimode_bump_freq_ft897(), service_scan(), and set_freq_ft897().

#define TELEMETRY   "telemetry"

Definition at line 165 of file app_rpt.c.

Referenced by telem_lookup().

#define TELEPARAMSIZE   256

Definition at line 180 of file app_rpt.c.

#define TOTIME   180000

Definition at line 292 of file app_rpt.c.

Referenced by load_rpt_vars().


Enumeration Type Documentation

anonymous enum

Enumerator:
REM_OFF 
REM_MONITOR 
REM_TX 

Definition at line 185 of file app_rpt.c.

anonymous enum

Enumerator:
ID 
PROC 
TERM 
COMPLETE 
UNKEY 
REMDISC 
REMALREADY 
REMNOTFOUND 
REMGO 
CONNECTED 
CONNFAIL 
STATUS 
TIMEOUT 
ID1 
STATS_TIME 
STATS_VERSION 
IDTALKOVER 
ARB_ALPHA 
TEST_TONE 
REV_PATCH 
TAILMSG 
MACRO_NOTFOUND 
GOSUB_NOTFOUND 
MACRO_BUSY 
GOSUB_BUSY 
LASTNODEKEY 

Definition at line 187 of file app_rpt.c.

anonymous enum

Enumerator:
REM_SIMPLEX 
REM_MINUS 
REM_PLUS 

Definition at line 192 of file app_rpt.c.

anonymous enum

Enumerator:
REM_LOWPWR 
REM_MEDPWR 
REM_HIPWR 

Definition at line 194 of file app_rpt.c.

anonymous enum

Enumerator:
DC_INDETERMINATE 
DC_REQ_FLUSH 
DC_ERROR 
DC_COMPLETE 
DC_DOKEY 

Definition at line 196 of file app_rpt.c.

anonymous enum

Enumerator:
SOURCE_RPT 
SOURCE_LNK 
SOURCE_RMT 
SOURCE_PHONE 
SOURCE_DPHONE 

Definition at line 198 of file app_rpt.c.

anonymous enum

Enumerator:
DLY_TELEM 
DLY_ID 
DLY_UNKEY 
DLY_CALLTERM 

Definition at line 200 of file app_rpt.c.

anonymous enum

Enumerator:
REM_MODE_FM 
REM_MODE_USB 
REM_MODE_LSB 
REM_MODE_AM 

Definition at line 202 of file app_rpt.c.

anonymous enum

Enumerator:
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 

Definition at line 204 of file app_rpt.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 7478 of file app_rpt.c.

static void __unreg_module ( void   )  [static]

Definition at line 7478 of file app_rpt.c.

static int attempt_reconnect ( struct rpt myrpt,
struct rpt_link l 
) [static]

Definition at line 5428 of file app_rpt.c.

References AST_APP_ARG, ast_call(), AST_DECLARE_APP_ARGS, AST_FORMAT_SLINEAR, ast_free, ast_log(), ast_request(), ast_set_read_format(), ast_set_write_format(), AST_STANDARD_APP_ARGS, ast_strdup, ast_strdupa, ast_variable_retrieve(), ast_verb, rpt::cfg, rpt::links, rpt::lock, LOG_ERROR, LOG_NOTICE, rpt::name, rpt_link::name, rpt_link::next, rpt::nodes, rpt::p, rpt_mutex_lock, rpt_mutex_unlock, and s.

Referenced by rpt().

05429 {
05430    const char *val;
05431    char *s, *tele;
05432    char deststr[300] = "";
05433    AST_DECLARE_APP_ARGS(args,
05434       AST_APP_ARG(channel);
05435       AST_APP_ARG(extra);
05436    );
05437 
05438    val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, l->name);
05439    if (!val) {
05440       ast_log(LOG_ERROR, "attempt_reconnect: cannot find node %s\n", l->name);
05441       return -1;
05442    }
05443 
05444    rpt_mutex_lock(&myrpt->lock);
05445    /* remove from queue */
05446    remque((struct qelem *) l);
05447    rpt_mutex_unlock(&myrpt->lock);
05448    s = ast_strdupa(val);
05449    AST_STANDARD_APP_ARGS(args, s);
05450 
05451    /* XXX This section doesn't make any sense.  Why not just use args.channel? XXX */
05452    snprintf(deststr, sizeof(deststr), "IAX2/%s", args.channel);
05453    tele = strchr(deststr, '/');
05454    if (!tele) {
05455       ast_log(LOG_ERROR, "attempt_reconnect:Dial number (%s) must be in format tech/number\n", deststr);
05456       return -1;
05457    }
05458    *tele++ = 0;
05459    l->elaptime = 0;
05460    l->connecttime = 0;
05461    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele, NULL);
05462    if (l->chan) {
05463       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
05464       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
05465       l->chan->whentohangup = 0;
05466       l->chan->appl = "Apprpt";
05467       l->chan->data = "(Remote Rx)";
05468       ast_verb(3, "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
05469             deststr, tele, l->chan->name);
05470       if (l->chan->cid.cid_num)
05471          ast_free(l->chan->cid.cid_num);
05472       l->chan->cid.cid_num = ast_strdup(myrpt->name);
05473       ast_call(l->chan, tele, 999); 
05474 
05475    } else {
05476       ast_verb(3, "Unable to place call to %s/%s on %s\n",
05477             deststr, tele, l->chan->name);
05478       return -1;
05479    }
05480    rpt_mutex_lock(&myrpt->lock);
05481    /* put back in queue */
05482    insque((struct qelem *)l, (struct qelem *)myrpt->links.next);
05483    rpt_mutex_unlock(&myrpt->lock);
05484    ast_log(LOG_NOTICE, "Reconnect Attempt to %s in process\n", l->name);
05485    return 0;
05486 }

static int check_freq ( struct rpt myrpt,
int  m,
int  d,
int *  defmode 
) [static]

Definition at line 4459 of file app_rpt.c.

References check_freq_ft897(), check_freq_rbi(), and rpt::remote.

Referenced by function_remote().

04460 {
04461    if (!strcmp(myrpt->remote, remote_rig_ft897))
04462       return check_freq_ft897(m, d, defmode);
04463    else if (!strcmp(myrpt->remote, remote_rig_rbi))
04464       return check_freq_rbi(m, d, defmode);
04465    else
04466       return -1;
04467 }

static int check_freq_ft897 ( int  m,
int  d,
int *  defmode 
) [static]

Definition at line 4134 of file app_rpt.c.

References REM_MODE_FM, REM_MODE_LSB, and REM_MODE_USB.

Referenced by check_freq(), and multimode_bump_freq_ft897().

04135 {
04136    int dflmd = REM_MODE_FM;
04137 
04138    if (m == 1) { /* 160 meters */
04139       dflmd =  REM_MODE_LSB; 
04140       if (d < 80001)
04141          return -1;
04142    } else if (m == 3) { /* 80 meters */
04143       dflmd = REM_MODE_LSB;
04144       if (d < 75001)
04145          return -1;
04146    } else if (m == 7) { /* 40 meters */
04147       dflmd = REM_MODE_LSB;
04148       if ((d < 15001) || (d > 29999))
04149          return -1;
04150    } else if (m == 14) { /* 20 meters */
04151       dflmd = REM_MODE_USB;
04152       if ((d < 15001) || (d > 34999))
04153          return -1;
04154    } else if (m == 18) { /* 17 meters */
04155       dflmd = REM_MODE_USB;
04156       if ((d < 11001) || (d > 16797))
04157          return -1;
04158    } else if (m == 21) { /* 15 meters */
04159       dflmd = REM_MODE_USB;
04160       if ((d < 20001) || (d > 44999))
04161          return -1;
04162    } else if (m == 24) { /* 12 meters */
04163       dflmd = REM_MODE_USB;
04164       if ((d < 93001) || (d > 98999))
04165          return -1;
04166    } else if (m == 28) { /* 10 meters */
04167       dflmd = REM_MODE_USB;
04168       if (d < 30001)
04169          return -1;
04170    } else if (m == 29) { 
04171       if (d >= 51000)
04172          dflmd = REM_MODE_FM;
04173       else
04174          dflmd = REM_MODE_USB;
04175       if (d > 69999)
04176          return -1;
04177    } else if (m == 50) { /* 6 meters */
04178       if (d < 10100)
04179          return -1;
04180       if (d >= 30000)
04181          dflmd = REM_MODE_FM;
04182       else
04183          dflmd = REM_MODE_USB;
04184    } else if ((m >= 51) && ( m < 54)) {
04185       dflmd = REM_MODE_FM;
04186    } else if (m == 144) { /* 2 meters */
04187       if (d < 10100)
04188          return -1;
04189       if (d >= 30000)
04190          dflmd = REM_MODE_FM;
04191       else
04192          dflmd = REM_MODE_USB;
04193    } else if ((m >= 145) && (m < 148)) {
04194       dflmd = REM_MODE_FM;
04195    } else if ((m >= 430) && (m < 450)) { /* 70 centimeters */
04196       if (m  < 438)
04197          dflmd = REM_MODE_USB;
04198       else
04199          dflmd = REM_MODE_FM;
04200       ;
04201    } else
04202       return -1;
04203 
04204    if (defmode)
04205       *defmode = dflmd;
04206 
04207    return 0;
04208 }

static int check_freq_rbi ( int  m,
int  d,
int *  defmode 
) [static]

Definition at line 4073 of file app_rpt.c.

References REM_MODE_FM.

Referenced by check_freq().

04074 {
04075    int dflmd = REM_MODE_FM;
04076 
04077    if (m == 50) { /* 6 meters */
04078       if (d < 10100)
04079          return -1;
04080    } else if ((m >= 51) && ( m < 54)) {
04081       /* nada */
04082    } else if (m == 144) { /* 2 meters */
04083       if (d < 10100)
04084          return -1;
04085    } else if ((m >= 145) && (m < 148)) {
04086       /* nada */
04087    } else if ((m >= 222) && (m < 225)) { /* 1.25 meters */
04088       /* nada */
04089    } else if ((m >= 430) && (m < 450)) { /* 70 centimeters */
04090       /* nada */
04091    } else if ((m >= 1240) && (m < 1300)) { /* 23 centimeters */
04092       /* nada */
04093    } else
04094       return -1;
04095    
04096    if (defmode)
04097       *defmode = dflmd; 
04098 
04099    return 0;
04100 }

static int closerem ( struct rpt myrpt  )  [static]

Definition at line 4446 of file app_rpt.c.

References closerem_ft897(), and rpt::remote.

04447 {
04448    return 0; /* XXX BROKEN!! */
04449    if (!strcmp(myrpt->remote, remote_rig_ft897))
04450       return closerem_ft897(myrpt);
04451    else
04452       return 0;
04453 }

static int closerem_ft897 ( struct rpt myrpt  )  [static]

Definition at line 4388 of file app_rpt.c.

References simple_command_ft897().

Referenced by closerem().

04389 {
04390    simple_command_ft897(myrpt, 0x88); /* PTT off */
04391    return 0;
04392 }  

static int collect_function_digits ( struct rpt myrpt,
char *  digits,
int  command_source,
struct rpt_link mylink 
) [static]

Definition at line 3411 of file app_rpt.c.

References function_table_tag::action, AST_APP_ARG, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strdupa, ast_variable_browse(), rpt::cfg, DC_ERROR, DC_INDETERMINATE, rpt::dphone_functions, rpt::dphone_longestfunc, function_table, rpt::functions, rpt::link_functions, rpt::link_longestfunc, rpt::longestfunc, ast_variable::name, ast_variable::next, rpt::p, rpt::phone_functions, rpt::phone_longestfunc, S_OR, SOURCE_DPHONE, SOURCE_LNK, SOURCE_PHONE, and ast_variable::value.

Referenced by handle_link_data(), handle_link_phone_dtmf(), handle_remote_dtmf_digit(), and local_dtmf_helper().

03412 {
03413    int i;
03414    char *stringp, *functiondigits;
03415    char function_table_name[30] = "";
03416    struct ast_variable *vp;
03417    AST_DECLARE_APP_ARGS(args,
03418       AST_APP_ARG(action);
03419       AST_APP_ARG(param);
03420    );
03421    
03422    ast_debug(1, "@@@@ Digits collected: %s, source: %d\n", digits, command_source);
03423    
03424    if (command_source == SOURCE_DPHONE) {
03425       if (!myrpt->p.dphone_functions)
03426          return DC_INDETERMINATE;
03427       ast_copy_string(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name));
03428    } else if (command_source == SOURCE_PHONE) {
03429       if (!myrpt->p.phone_functions)
03430          return DC_INDETERMINATE;
03431       ast_copy_string(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name));
03432    } else if (command_source == SOURCE_LNK)
03433       ast_copy_string(function_table_name, myrpt->p.link_functions, sizeof(function_table_name));
03434    else
03435       ast_copy_string(function_table_name, myrpt->p.functions, sizeof(function_table_name));
03436 
03437    for (vp = ast_variable_browse(myrpt->cfg, function_table_name); vp; vp = vp->next) {
03438       if (!strncasecmp(vp->name, digits, strlen(vp->name)))
03439          break;
03440    }  
03441    if (!vp) {
03442       int n;
03443 
03444       n = myrpt->longestfunc;
03445       if (command_source == SOURCE_LNK)
03446          n = myrpt->link_longestfunc;
03447       else if (command_source == SOURCE_PHONE)
03448          n = myrpt->phone_longestfunc;
03449       else if (command_source == SOURCE_DPHONE)
03450          n = myrpt->dphone_longestfunc;
03451 
03452       if (strlen(digits) >= n)
03453          return DC_ERROR;
03454       else
03455          return DC_INDETERMINATE;
03456    }
03457 
03458    /* Found a match, retrieve value part and parse */
03459    stringp = ast_strdupa(vp->value);
03460    AST_STANDARD_APP_ARGS(args, stringp);
03461 
03462    ast_debug(1, "@@@@ action: %s, param = %s\n", args.action, S_OR(args.param, "(null)"));
03463    /* Look up the action */
03464    for (i = 0; i < (sizeof(function_table) / sizeof(struct function_table_tag)); i++) {
03465       if (!strncasecmp(args.action, function_table[i].action, strlen(args.action)))
03466          break;
03467    }
03468    ast_debug(1, "@@@@ table index i = %d\n", i);
03469    if (i == (sizeof(function_table) / sizeof(struct function_table_tag))) {
03470       /* Error, action not in table */
03471       return DC_ERROR;
03472    }
03473    if (function_table[i].function == NULL) {
03474       /* Error, function undefined */
03475       ast_debug(1, "@@@@ NULL for action: %s\n", args.action);
03476       return DC_ERROR;
03477    }
03478    functiondigits = digits + strlen(vp->name);
03479    return (*function_table[i].function)(myrpt, args.param, functiondigits, command_source, mylink);
03480 }

static void do_scheduler ( struct rpt myrpt  )  [static]

Definition at line 5624 of file app_rpt.c.

References ast_localtime(), ast_log(), rpt::curtv, rpt::dailyexecdcommands, rpt::dailykerchunks, rpt::dailykeyups, rpt::dailytxtime, LOG_NOTICE, ast_tm::tm_hour, ast_tm::tm_min, and ast_tm::tm_sec.

Referenced by rpt().

05625 {
05626    int res;
05627    struct ast_tm tmnow;
05628 
05629    memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
05630    
05631    if ( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
05632       ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
05633 
05634    /* Try to get close to a 1 second resolution */
05635    
05636    if (myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
05637       return;
05638 
05639    ast_localtime(&myrpt->curtv, &tmnow, NULL);
05640 
05641    /* If midnight, then reset all daily statistics */
05642    
05643    if ((tmnow.tm_hour == 0) && (tmnow.tm_min == 0) && (tmnow.tm_sec == 0)) {
05644       myrpt->dailykeyups = 0;
05645       myrpt->dailytxtime = 0;
05646       myrpt->dailykerchunks = 0;
05647       myrpt->dailyexecdcommands = 0;
05648    }
05649 }

static int function_autopatchdn ( struct rpt myrpt,
char *  param,
char *  digitbuf,
int  command_source,
struct rpt_link mylink 
) [static]

Definition at line 3226 of file app_rpt.c.

References ast_debug, rpt::callmode, DC_COMPLETE, DC_ERROR, rpt::enable, rpt::lock, rpt_mutex_lock, rpt_mutex_unlock, rpt_telemetry(), and TERM.

03227 {
03228    if (!myrpt->enable)
03229       return DC_ERROR;
03230    
03231    ast_debug(1, "@@@@ Autopatch down\n");
03232       
03233    rpt_mutex_lock(&myrpt->lock);
03234    
03235    if (!myrpt->callmode) {
03236       rpt_mutex_unlock(&myrpt->lock);
03237       return DC_COMPLETE;
03238    }
03239    
03240    myrpt->callmode = 0;
03241    rpt_mutex_unlock(&myrpt->lock);
03242    rpt_telemetry(myrpt, TERM, NULL);
03243    return DC_COMPLETE;
03244 }

static int function_autopatchup ( struct rpt myrpt,
char *  param,
char *  digitbuf,
int  command_source,
struct rpt_link mylink 
) [static]

Definition at line 3142 of file app_rpt.c.

References AST_APP_ARG, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strdupa, rpt::callmode, DC_ERROR, rpt::enable, matchkeyword(), rpt::ourcontext, rpt::p, rpt::patchcontext, rpt::patchdialtime, rpt::patchfarenddisconnect, rpt::patchnoct, rpt::patchquiet, and skipchars().

03143 {
03144    int i, index;
03145    char *value = NULL;
03146    AST_DECLARE_APP_ARGS(params,
03147       AST_APP_ARG(list)[20];
03148    );
03149 
03150    static char *keywords[] = {
03151    "context",
03152    "dialtime",
03153    "farenddisconnect",
03154    "noct",
03155    "quiet",
03156    NULL
03157    };
03158       
03159    if (!myrpt->enable)
03160       return DC_ERROR;
03161 
03162    ast_debug(1, "@@@@ Autopatch up\n");
03163 
03164    if (!myrpt->callmode) {
03165       /* Set defaults */
03166       myrpt->patchnoct = 0;
03167       myrpt->patchdialtime = 0;
03168       myrpt->patchfarenddisconnect = 0;
03169       myrpt->patchquiet = 0;
03170       ast_copy_string(myrpt->patchcontext, myrpt->p.ourcontext, sizeof(myrpt->patchcontext));
03171 
03172       if (param) {
03173          /* Process parameter list */
03174          char *tmp = ast_strdupa(param);
03175          AST_STANDARD_APP_ARGS(params, tmp);
03176          for (i = 0; i < params.argc; i++) {
03177             index = matchkeyword(params.list[i], &value, keywords);
03178             if (value)
03179                value = skipchars(value, "= ");
03180             switch (index) {
03181             case 1: /* context */
03182                ast_copy_string(myrpt->patchcontext, value, sizeof(myrpt->patchcontext)) ;
03183                break;
03184             case 2: /* dialtime */
03185                myrpt->patchdialtime = atoi(value);
03186                break;
03187             case 3: /* farenddisconnect */
03188                myrpt->patchfarenddisconnect = atoi(value);
03189                break;
03190             case 4:  /* noct */
03191                myrpt->patchnoct = atoi(value);
03192                break;
03193             case 5: /* quiet */
03194                myrpt->patchquiet = atoi(value);
03195                break;
03196             default:
03197                break;
03198             }
03199          }
03200       }
03201    }
03202                
03203    rpt_mutex_lock(&myrpt->lock);
03204 
03205    /* if on call, force * into current audio stream */
03206    
03207    if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) {
03208       myrpt->mydtmf = myrpt->p.funcchar;
03209    }
03210    if (myrpt->callmode) {
03211       rpt_mutex_unlock(&myrpt->lock);
03212       return DC_COMPLETE;
03213    }
03214    myrpt->callmode = 1;
03215    myrpt->cidx = 0;
03216    myrpt->exten[myrpt->cidx] = 0;
03217    rpt_mutex_unlock(&myrpt->lock);
03218    ast_pthread_create_detached(&myrpt->rpt_call_thread, NULL, rpt_call, (void *) myrpt);
03219    return DC_COMPLETE;
03220 }

static int function_cop ( struct rpt myrpt,
char *  param,
char *  digitbuf,
int  command_source,
struct rpt_link mylink 
) [static]

Definition at line 3377 of file app_rpt.c.

References ARB_ALPHA, ast_cli_command(), DC_COMPLETE, DC_DOKEY, DC_ERROR, DC_INDETERMINATE, rpt::disgorgetime, rpt::enable, myatoi(), rpt_telemetry(), SOURCE_PHONE, and TEST_TONE.

03378 {
03379    if (!param)
03380       return DC_ERROR;
03381    
03382    switch(myatoi(param)) {
03383    case 1: /* System reset */
03384       ast_cli_command(STDERR_FILENO, "restart now"); /* A little less drastic than what was previously here. */
03385       return DC_COMPLETE;
03386    case 2:
03387       myrpt->enable = 1;
03388       rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
03389       return DC_COMPLETE;
03390    case 3:
03391       myrpt->enable = 0;
03392       return DC_COMPLETE;
03393    case 4: /* test tone on */
03394       rpt_telemetry(myrpt, TEST_TONE, NULL);
03395       return DC_COMPLETE;
03396    case 5: /* Disgorge variables to log for debug purposes */
03397       myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
03398       return DC_COMPLETE;
03399    case 6: /* Simulate COR being activated (phone only) */
03400       if (command_source != SOURCE_PHONE)
03401          return DC_INDETERMINATE;
03402       return DC_DOKEY;  
03403    }  
03404    return DC_INDETERMINATE;
03405 }

static int function_gosub ( struct rpt myrpt,
char *  param,
char *  digitbuf,
int  command_source,
struct rpt_link mylink 
) [static]

Definition at line 3329 of file app_rpt.c.

References ast_log(), ast_strlen_zero(), ast_variable_retrieve(), rpt::cfg, DC_COMPLETE, DC_ERROR, DC_INDETERMINATE, rpt::enable, rpt::gosub, GOSUB_BUSY, GOSUB_NOTFOUND, rpt::gosubbuf, GOSUBTIME, rpt::gosubtimer, rpt::lock, LOG_DEBUG, rpt::p, rpt::remchannel, rpt::remote, rpt_mutex_lock, rpt_mutex_unlock, rpt_telemetry(), and rpt::startupgosub.

03330 {
03331 
03332    const char *val;
03333    int   i;
03334    struct ast_channel *mychannel;
03335 
03336    if ((!myrpt->remote) && (!myrpt->enable))
03337       return DC_ERROR;
03338 
03339    if (debug) 
03340       ast_log(LOG_DEBUG, "@@@@ gosub param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
03341    
03342    mychannel = myrpt->remchannel;
03343 
03344    if (ast_strlen_zero(digitbuf)) /* needs 1 digit */
03345       return DC_INDETERMINATE;
03346          
03347    for (i = 0; i < digitbuf[i]; i++) {
03348       if ((digitbuf[i] < '0') || (digitbuf[i] > '9'))
03349          return DC_ERROR;
03350    }
03351    
03352    if (*digitbuf == '0')
03353       val = myrpt->p.startupgosub;
03354    else
03355       val = ast_variable_retrieve(myrpt->cfg, myrpt->p.gosub, digitbuf);
03356    /* param was 1 for local buf */
03357    if (!val) {
03358       rpt_telemetry(myrpt, GOSUB_NOTFOUND, NULL);
03359       return DC_COMPLETE;
03360    }        
03361    rpt_mutex_lock(&myrpt->lock);
03362    if ((sizeof(myrpt->gosubbuf) - strlen(myrpt->gosubbuf)) < strlen(val)) {
03363       rpt_mutex_unlock(&myrpt->lock);
03364       rpt_telemetry(myrpt, GOSUB_BUSY, NULL);
03365       return DC_ERROR;
03366    }
03367    myrpt->gosubtimer = GOSUBTIME;
03368    strncat(myrpt->gosubbuf, val, sizeof(myrpt->gosubbuf) - strlen(myrpt->gosubbuf) - 1);
03369    rpt_mutex_unlock(&myrpt->lock);
03370    return DC_COMPLETE;  
03371 }

static int function_ilink ( struct rpt myrpt,
char *  param,
char *  digitbuf,
int  command_source,
struct rpt_link mylink 
) [static]

Definition at line 2800 of file app_rpt.c.

References AST_APP_ARG, ast_call(), ast_calloc, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_FORMAT_SLINEAR, AST_FRAME_TEXT, ast_free, ast_hangup(), ast_log(), ast_request(), ast_safe_sleep(), ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_DEV, AST_STANDARD_APP_ARGS, ast_strdup, ast_strdupa, ast_true(), ast_variable_retrieve(), ast_verb, ast_write(), rpt::cfg, rpt_link::chan, rpt::cmdnode, COMPLETE, rpt::conf, CONNFAIL, ast_frame::data, ast_frame::datalen, DC_COMPLETE, DC_ERROR, DC_INDETERMINATE, rpt_link::disced, rpt::enable, ast_frame::frametype, rpt::lastlinknode, LASTNODEKEY, rpt::links, rpt::lock, LOG_ERROR, LOG_WARNING, rpt::longestnode, ast_frame::mallocd, MAX_RETRIES, MAXNODESTR, rpt_link::mode, myatoi(), rpt::name, rpt_link::name, rpt_link::next, rpt::nodes, ast_frame::offset, rpt::p, rpt_link::reconnects, REMALREADY, REMGO, rpt_link::retries, rpt_mutex_lock, rpt_mutex_unlock, rpt_telemetry(), s, S_OR, ast_frame::samples, SOURCE_DPHONE, SOURCE_PHONE, SOURCE_RPT, STATUS, and ast_frame::subclass.

02801 {
02802    const char *val;
02803    char *s, *tele;
02804    char deststr[300] = "", modechange = 0;
02805    char digitbuf[MAXNODESTR];
02806    struct rpt_link *l;
02807    int reconnects = 0;
02808    struct dahdi_confinfo ci;  /* conference info */
02809    AST_DECLARE_APP_ARGS(args,
02810       AST_APP_ARG(s1);
02811       AST_APP_ARG(s2); /* XXX Never used.  Scratch? XXX */
02812    );
02813 
02814    if (!param)
02815       return DC_ERROR;
02816 
02817    if (!myrpt->enable)
02818       return DC_ERROR;
02819 
02820    ast_copy_string(digitbuf, digits, sizeof(digitbuf));
02821    ast_debug(1, "@@@@ ilink param = %s, digitbuf = %s\n", S_OR(param, "(null)"), digitbuf);
02822 
02823    switch (myatoi(param)) {
02824    case 1: /* Link off */
02825       if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
02826          strcpy(digitbuf, myrpt->lastlinknode);
02827       val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
02828       if (!val) {
02829          if (strlen(digitbuf) >= myrpt->longestnode)
02830             return DC_ERROR;
02831          break;
02832       }
02833       rpt_mutex_lock(&myrpt->lock);
02834       l = myrpt->links.next;
02835       /* try to find this one in queue */
02836       while (l != &myrpt->links) {
02837          if (l->name[0] == '0') {
02838             l = l->next;
02839             continue;
02840          }
02841          /* if found matching string */
02842          if (!strcmp(l->name, digitbuf))
02843             break;
02844          l = l->next;
02845       }
02846       if (l != &myrpt->links) { /* if found */
02847          struct ast_frame wf;
02848          ast_copy_string(myrpt->lastlinknode, digitbuf, MAXNODESTR);
02849          l->retries = MAX_RETRIES + 1;
02850          l->disced = 1;
02851          rpt_mutex_unlock(&myrpt->lock);
02852          wf.frametype = AST_FRAME_TEXT;
02853          wf.subclass = 0;
02854          wf.offset = 0;
02855          wf.mallocd = 1;
02856          wf.datalen = strlen(discstr) + 1;
02857          wf.samples = 0;
02858          wf.data = ast_strdup(discstr);
02859          if (l->chan) {
02860             ast_write(l->chan, &wf);
02861             if (ast_safe_sleep(l->chan, 250) == -1)
02862                return DC_ERROR;
02863             ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
02864          }
02865          rpt_telemetry(myrpt, COMPLETE, NULL);
02866          return DC_COMPLETE;
02867       }
02868       rpt_mutex_unlock(&myrpt->lock);  
02869       return DC_COMPLETE;
02870    case 2: /* Link Monitor */
02871       if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
02872          strcpy(digitbuf, myrpt->lastlinknode);
02873       val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
02874       if (!val) {
02875          if (strlen(digitbuf) >= myrpt->longestnode)
02876             return DC_ERROR;
02877          break;
02878       }
02879       s = ast_strdupa(val);
02880       AST_STANDARD_APP_ARGS(args, s);
02881       rpt_mutex_lock(&myrpt->lock);
02882       l = myrpt->links.next;
02883       /* try to find this one in queue */
02884       while (l != &myrpt->links) {
02885          if (l->name[0] == '0') {
02886             l = l->next;
02887             continue;
02888          }
02889          /* if found matching string */
02890          if (!strcmp(l->name, digitbuf))
02891             break;
02892          l = l->next;
02893       }
02894       /* if found */
02895       if (l != &myrpt->links) {
02896          /* if already in this mode, just ignore */
02897          if ((!l->mode) || (!l->chan)) {
02898             rpt_mutex_unlock(&myrpt->lock);
02899             rpt_telemetry(myrpt, REMALREADY, NULL);
02900             return DC_COMPLETE;
02901          }
02902          reconnects = l->reconnects;
02903          rpt_mutex_unlock(&myrpt->lock);
02904          if (l->chan)
02905             ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
02906          l->retries = MAX_RETRIES + 1;
02907          l->disced = 2;
02908          modechange = 1;
02909       } else
02910          rpt_mutex_unlock(&myrpt->lock);
02911       ast_copy_string(myrpt->lastlinknode, digitbuf, MAXNODESTR);
02912       /* establish call in monitor mode */
02913       l = ast_calloc(1, sizeof(*l));
02914       if (!l) {
02915          ast_log(LOG_WARNING, "Unable to malloc\n");
02916          return DC_ERROR;
02917       }
02918       snprintf(deststr, sizeof(deststr), "IAX2/%s", args.s1);
02919       tele = strchr(deststr, '/');
02920       if (!tele) {
02921          ast_log(LOG_ERROR, "link2:Dial number (%s) must be in format tech/number\n", deststr);
02922          return DC_ERROR;
02923       }
02924       *tele++ = 0;
02925       l->isremote = (s && ast_true(s));
02926       ast_copy_string(l->name, digitbuf, MAXNODESTR);
02927       l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele, NULL);
02928       if (modechange)
02929          l->connected = 1;
02930       if (l->chan) {
02931          ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
02932          ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
02933          l->chan->whentohangup = 0;
02934          l->chan->appl = "Apprpt";
02935          l->chan->data = "(Remote Rx)";
02936          ast_verb(3, "rpt (remote) initiating call to %s/%s on %s\n",
02937                deststr, tele, l->chan->name);
02938          if (l->chan->cid.cid_num)
02939             ast_free(l->chan->cid.cid_num);
02940          l->chan->cid.cid_num = ast_strdup(myrpt->name);
02941          ast_call(l->chan, tele, 0);
02942       } else {
02943          rpt_telemetry(myrpt, CONNFAIL, l);
02944          ast_free(l);
02945          ast_verb(3, "Unable to place call to %s/%s on %s\n",
02946                deststr, tele, l->chan->name);
02947          return DC_ERROR;
02948       }
02949       /* allocate a pseudo-channel thru asterisk */
02950       l->pchan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
02951       if (!l->pchan) {
02952          ast_log(LOG_ERROR, "rpt:Sorry unable to obtain pseudo channel\n");
02953          ast_hangup(l->chan);
02954          ast_free(l);
02955          return DC_ERROR;
02956       }
02957       ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
02958       ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
02959       /* make a conference for the pseudo-one */
02960       ci.chan = 0;
02961       ci.confno = myrpt->conf;
02962       ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
02963       /* first put the channel on the conference in proper mode */
02964       if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1) {
02965          ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02966          ast_hangup(l->chan);
02967          ast_hangup(l->pchan);
02968          ast_free(l);
02969          return DC_ERROR;
02970       }
02971       rpt_mutex_lock(&myrpt->lock);
02972       l->reconnects = reconnects;
02973       /* insert at end of queue */
02974       insque((struct qelem *)l, (struct qelem *)myrpt->links.next);
02975       rpt_mutex_unlock(&myrpt->lock);
02976       rpt_telemetry(myrpt, COMPLETE, NULL);
02977       return DC_COMPLETE;
02978    case 3: /* Link transceive */
02979       if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
02980          strcpy(digitbuf, myrpt->lastlinknode);
02981       val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
02982       if (!val) {
02983          if (strlen(digitbuf) >= myrpt->longestnode)
02984             return DC_ERROR;
02985          break;
02986       }
02987       s = ast_strdupa(val);
02988       AST_STANDARD_APP_ARGS(args, s);
02989       rpt_mutex_lock(&myrpt->lock);
02990       l = myrpt->links.next;
02991       /* try to find this one in queue */
02992       while (l != &myrpt->links) {
02993          if (l->name[0] == '0') {
02994             l = l->next;
02995             continue;
02996          }
02997          /* if found matching string */
02998          if (!strcmp(l->name, digitbuf))
02999             break;
03000          l = l->next;
03001       }
03002       /* if found */
03003       if (l != &myrpt->links) { 
03004          /* if already in this mode, just ignore */
03005          if ((l->mode) || (!l->chan)) {
03006             rpt_mutex_unlock(&myrpt->lock);
03007             rpt_telemetry(myrpt, REMALREADY, NULL);
03008             return DC_COMPLETE;
03009          }
03010          reconnects = l->reconnects;
03011          rpt_mutex_unlock(&myrpt->lock);
03012          if (l->chan)
03013             ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
03014          l->retries = MAX_RETRIES + 1;
03015          l->disced = 2;
03016          modechange = 1;
03017       } else
03018          rpt_mutex_unlock(&myrpt->lock);
03019       ast_copy_string(myrpt->lastlinknode, digitbuf, MAXNODESTR);
03020       /* establish call in tranceive mode */
03021       l = ast_calloc(1, sizeof(*l));
03022       if (!l) {
03023          ast_log(LOG_WARNING, "Unable to malloc\n");
03024          return DC_ERROR;
03025       }
03026       l->mode = 1;
03027       l->outbound = 1;
03028       ast_copy_string(l->name, digitbuf, MAXNODESTR);
03029       l->isremote = (s && ast_true(s));
03030       if (modechange)
03031          l->connected = 1;
03032       snprintf(deststr, sizeof(deststr), "IAX2/%s", args.s1);
03033       tele = strchr(deststr, '/');
03034       if (!tele) {
03035          ast_log(LOG_ERROR, "link3:Dial number (%s) must be in format tech/number\n", deststr);
03036          ast_free(l);
03037          return DC_ERROR;
03038       }
03039       *tele++ = 0;
03040       l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele, NULL);
03041       if (l->chan) {
03042          ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
03043          ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
03044          l->chan->whentohangup = 0;
03045          l->chan->appl = "Apprpt";
03046          l->chan->data = "(Remote Rx)";
03047          ast_verb(3, "rpt (remote) initiating call to %s/%s on %s\n",
03048                deststr, tele, l->chan->name);
03049          if (l->chan->cid.cid_num)
03050             ast_free(l->chan->cid.cid_num);
03051          l->chan->cid.cid_num = ast_strdup(myrpt->name);
03052          ast_call(l->chan, tele, 999);
03053       } else {
03054          rpt_telemetry(myrpt, CONNFAIL, l);
03055          ast_free(l);
03056          ast_verb(3, "Unable to place call to %s/%s on %s\n",
03057                deststr, tele, l->chan->name);
03058          return DC_ERROR;
03059       }
03060       /* allocate a pseudo-channel thru asterisk */
03061       l->pchan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
03062       if (!l->pchan) {
03063          ast_log(LOG_ERROR, "rpt:Sorry unable to obtain pseudo channel\n");
03064          ast_hangup(l->chan);
03065          ast_free(l);
03066          return DC_ERROR;
03067       }
03068       ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
03069       ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
03070       /* make a conference for the tx */
03071       ci.chan = 0;
03072       ci.confno = myrpt->conf;
03073       ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
03074       /* first put the channel on the conference in proper mode */
03075       if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1) {
03076          ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
03077          ast_hangup(l->chan);
03078          ast_hangup(l->pchan);
03079          ast_free(l);
03080          return DC_ERROR;
03081       }
03082       rpt_mutex_lock(&myrpt->lock);
03083       l->reconnects = reconnects;
03084       /* insert at end of queue */
03085       insque((struct qelem *)l, (struct qelem *)myrpt->links.next);
03086       rpt_mutex_unlock(&myrpt->lock);
03087       rpt_telemetry(myrpt, COMPLETE, NULL);
03088       return DC_COMPLETE;
03089    case 4: /* Enter Command Mode */
03090       /* if doesnt allow link cmd, or no links active, return */
03091       if (((command_source != SOURCE_RPT) &&
03092           (command_source != SOURCE_PHONE) &&
03093           (command_source != SOURCE_DPHONE)) ||
03094          (myrpt->links.next == &myrpt->links))
03095          return DC_COMPLETE;
03096       /* if already in cmd mode, or selected self, fughetabahtit */
03097       if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))) {
03098          rpt_telemetry(myrpt, REMALREADY, NULL);
03099          return DC_COMPLETE;
03100       }
03101       if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
03102          strcpy(digitbuf, myrpt->lastlinknode);
03103       /* node must at least exist in list */
03104       val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
03105       if (!val) {
03106          if (strlen(digitbuf) >= myrpt->longestnode)
03107             return DC_ERROR;
03108          break;
03109       }
03110       rpt_mutex_lock(&myrpt->lock);
03111       strcpy(myrpt->lastlinknode, digitbuf);
03112       ast_copy_string(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode));
03113       rpt_mutex_unlock(&myrpt->lock);
03114       rpt_telemetry(myrpt, REMGO, NULL);  
03115       return DC_COMPLETE;
03116    case 5: /* Status */
03117       rpt_telemetry(myrpt, STATUS, NULL);
03118       return DC_COMPLETE;
03119    case 6: /* All Links Off */
03120       l = myrpt->links.next;
03121       while (l != &myrpt->links) { /* This code is broke and needs to be changed to work with the reconnect kludge */
03122          if (l->chan)
03123             ast_softhangup(l->chan, AST_SOFTHANGUP_DEV); /* Hang 'em up */
03124          l = l->next;
03125       }
03126       rpt_telemetry(myrpt, COMPLETE, NULL);
03127       break;
03128    case 7: /* Identify last node which keyed us up */
03129       rpt_telemetry(myrpt, LASTNODEKEY, NULL);
03130       break;
03131    default:
03132       return DC_ERROR;
03133    }
03134 
03135    return DC_INDETERMINATE;
03136 }

static int function_macro ( struct rpt myrpt,
char *  param,
char *  digitbuf,
int  command_source,
struct rpt_link mylink 
) [static]

Definition at line 3282 of file app_rpt.c.

References ast_debug, ast_strlen_zero(), ast_variable_retrieve(), rpt::cfg, DC_COMPLETE, DC_ERROR, DC_INDETERMINATE, rpt::enable, rpt::lock, rpt::macro, MACRO_BUSY, MACRO_NOTFOUND, rpt::macrobuf, MACROTIME, rpt::macrotimer, rpt::p, rpt::remchannel, rpt::remote, rpt_mutex_lock, rpt_mutex_unlock, rpt_telemetry(), and rpt::startupmacro.

03283 {
03284 
03285    const char *val;
03286    int   i;
03287    struct ast_channel *mychannel;
03288 
03289    if ((!myrpt->remote) && (!myrpt->enable))
03290       return DC_ERROR;
03291 
03292    ast_debug(1, "@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
03293    
03294    mychannel = myrpt->remchannel;
03295 
03296    if (ast_strlen_zero(digitbuf)) /* needs 1 digit */
03297       return DC_INDETERMINATE;
03298          
03299    for (i = 0; i < digitbuf[i]; i++) {
03300       if ((digitbuf[i] < '0') || (digitbuf[i] > '9'))
03301          return DC_ERROR;
03302    }
03303    
03304    if (*digitbuf == '0')
03305       val = myrpt->p.startupmacro;
03306    else
03307       val = ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
03308    /* param was 1 for local buf */
03309    if (!val) {
03310       rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
03311       return DC_COMPLETE;
03312    }        
03313    rpt_mutex_lock(&myrpt->lock);
03314    if ((sizeof(myrpt->macrobuf) - strlen(myrpt->macrobuf)) < strlen(val)) {
03315       rpt_mutex_unlock(&myrpt->lock);
03316       rpt_telemetry(myrpt, MACRO_BUSY, NULL);
03317       return DC_ERROR;
03318    }
03319    myrpt->macrotimer = MACROTIME;
03320    strncat(myrpt->macrobuf, val, sizeof(myrpt->macrobuf) - strlen(myrpt->macrobuf) - 1);
03321    rpt_mutex_unlock(&myrpt->lock);
03322    return DC_COMPLETE;  
03323 }

static int function_remote ( struct rpt myrpt,
char *  param,
char *  digitbuf,
int  command_source,
struct rpt_link mylink 
) [static]

Definition at line 4632 of file app_rpt.c.

References AST_APP_ARG, AST_CONTROL_RADIO_KEY, AST_CONTROL_RADIO_UNKEY, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_indicate(), AST_NONSTANDARD_APP_ARGS, ast_safe_sleep(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_variable_retrieve(), rpt::cfg, check_freq(), DC_COMPLETE, DC_ERROR, DC_INDETERMINATE, rpt::freq, HF_SCAN_DOWN_FAST, HF_SCAN_DOWN_QUICK, HF_SCAN_DOWN_SLOW, HF_SCAN_UP_FAST, HF_SCAN_UP_QUICK, HF_SCAN_UP_SLOW, rpt::hfscanmode, rpt::memory, multimode_bump_freq(), multimode_capable(), myatoi(), rpt::name, rpt::offset, rpt::p, rpt::powerlevel, REM_HIPWR, REM_LOWPWR, REM_MEDPWR, REM_MINUS, REM_MODE_AM, REM_MODE_FM, REM_MODE_LSB, REM_MODE_USB, REM_PLUS, REM_SCANTIME, REM_SIMPLEX, rpt::remchannel, rpt::remmode, rpt::remoterx, rpt::remotetx, rmt_saycharstr(), rmt_sayfile(), rmt_telem_finish(), rmt_telem_start(), rpt::rxpl, rpt::rxplon, s, saycharstr(), saydigits(), sayfile(), saynum(), rpt::scantimer, setrem(), SOURCE_LNK, SOURCE_RPT, split_freq, rpt::tunerequest, rpt::txchannel, rpt::txpl, and rpt::txplon.

04633 {
04634    char *s, *modestr;
04635    const char *val;
04636    int i, j, ht, k, l, ls2, res, offset, offsave, modesave, defmode = 0;
04637    char multimode = 0;
04638    char oc;
04639    char tmp[20], freq[20] = "", savestr[20] = "";
04640    int mhz = 0, decimals = 0;
04641    struct ast_channel *mychannel;
04642    AST_DECLARE_APP_ARGS(args1,
04643       AST_APP_ARG(freq);
04644       AST_APP_ARG(xpl);
04645       AST_APP_ARG(mode);
04646    );
04647    AST_DECLARE_APP_ARGS(args,
04648       AST_APP_ARG(s1);
04649       AST_APP_ARG(s2);
04650    );
04651 
04652    if ((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
04653       return DC_ERROR;
04654       
04655    multimode = multimode_capable(myrpt);
04656    mychannel = myrpt->remchannel;
04657 
04658    switch (myatoi(param)) {
04659    case 1:  /* retrieve memory */
04660       if (strlen(digitbuf) < 2) /* needs 2 digits */
04661          break;
04662          
04663       for (i = 0 ; i < 2 ; i++) {
04664          if ((digitbuf[i] < '0') || (digitbuf[i] > '9'))
04665             return DC_ERROR;
04666       }
04667 
04668       val = ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, digitbuf);
04669       if (!val) {
04670          if (ast_safe_sleep(mychannel, 1000) == -1)
04671             return DC_ERROR;
04672          sayfile(mychannel, "rpt/memory_notfound");
04673          return DC_COMPLETE;
04674       }
04675       s = ast_strdupa(val);
04676       AST_STANDARD_APP_ARGS(args1, s);
04677       if (args1.argc < 3)
04678          return DC_ERROR;
04679       ast_copy_string(myrpt->freq, args1.freq, sizeof(myrpt->freq));
04680       ast_copy_string(myrpt->rxpl, args1.xpl, sizeof(myrpt->rxpl));
04681       ast_copy_string(myrpt->txpl, args1.xpl, sizeof(myrpt->rxpl));
04682       myrpt->remmode = REM_MODE_FM;
04683       myrpt->offset = REM_SIMPLEX;
04684       myrpt->powerlevel = REM_MEDPWR;
04685       myrpt->txplon = myrpt->rxplon = 0;
04686       modestr = args1.mode;
04687       while (*modestr) {
04688          switch (*modestr++) {
04689          case 'A':
04690          case 'a':
04691             strcpy(myrpt->rxpl, "100.0");
04692             strcpy(myrpt->txpl, "100.0");
04693             myrpt->remmode = REM_MODE_AM; 
04694             break;
04695 
04696          case 'B':
04697          case 'b':
04698             strcpy(myrpt->rxpl, "100.0");
04699             strcpy(myrpt->txpl, "100.0");
04700             myrpt->remmode = REM_MODE_LSB;
04701             break;
04702 
04703          case 'F':
04704             myrpt->remmode = REM_MODE_FM;
04705             break;
04706 
04707          case 'L':
04708          case 'l':
04709             myrpt->powerlevel = REM_LOWPWR;
04710             break;               
04711          case 'H':
04712          case 'h':
04713             myrpt->powerlevel = REM_HIPWR;
04714             break;
04715 
04716          case 'M':
04717          case 'm':
04718             myrpt->powerlevel = REM_MEDPWR;
04719             break;
04720 
04721          case '-':
04722             myrpt->offset = REM_MINUS;
04723             break;
04724 
04725          case '+':
04726             myrpt->offset = REM_PLUS;
04727             break;
04728 
04729          case 'S':
04730          case 's':
04731             myrpt->offset = REM_SIMPLEX;
04732             break;
04733 
04734          case 'T':
04735          case 't':
04736             myrpt->txplon = 1;
04737             break;
04738 
04739          case 'R':
04740          case 'r':
04741             myrpt->rxplon = 1;
04742             break;
04743 
04744          case 'U':
04745          case 'u':
04746             strcpy(myrpt->rxpl, "100.0");
04747             strcpy(myrpt->txpl, "100.0");
04748             myrpt->remmode = REM_MODE_USB;
04749             break;
04750          }
04751       }
04752 
04753       if (setrem(myrpt) == -1)
04754          return DC_ERROR;
04755 
04756       return DC_COMPLETE;  
04757 
04758    case 2:  /* set freq and offset */
04759       for (i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++) { /* look for M+*K+*O or M+*H+* depending on mode */
04760          if (digitbuf[i] == '*') {
04761             j++;
04762             continue;
04763          }
04764          if ((digitbuf[i] < '0') || (digitbuf[i] > '9'))
04765             goto invalid_freq;
04766          else {
04767             if (j == 0)
04768                l++; /* # of digits before first * */
04769             if (j == 1)
04770                k++; /* # of digits after first * */
04771          }
04772       }
04773 
04774       i = strlen(digitbuf) - 1;
04775       if (multimode) {
04776          if ((j > 2) || (l > 3) || (k > 6))
04777             goto invalid_freq; /* &^@#! */
04778       } else {
04779          if ((j > 2) || (l > 4) || (k > 3))
04780             goto invalid_freq; /* &^@#! */
04781       }
04782 
04783       /* Wait for M+*K+* */
04784 
04785       if (j < 2)
04786          break; /* Not yet */
04787 
04788       /* We have a frequency */
04789 
04790       s = ast_strdupa(digitbuf);
04791       AST_NONSTANDARD_APP_ARGS(args, s, '*');
04792       ls2 = strlen(args.s2);  
04793 
04794       switch (ls2) { /* Allow partial entry of khz and hz digits for laziness support */
04795       case 1:
04796          ht = 0;
04797          k = 100 * atoi(args.s2);
04798          break;
04799       case 2:
04800          ht = 0;
04801          k = 10 * atoi(args.s2);
04802          break;
04803       case 3:
04804          if (!multimode) {
04805             if ((args.s2[2] != '0') && (args.s2[2] != '5'))
04806                goto invalid_freq;
04807          }
04808          ht = 0;
04809          k = atoi(args.s2);
04810             break;
04811       case 4:
04812          k = atoi(args.s2) / 10;
04813          ht = 10 * (atoi(args.s2 + (ls2 - 1)));
04814          break;
04815       case 5:
04816          k = atoi(args.s2) / 100;
04817          ht = (atoi(args.s2 + (ls2 - 2)));
04818          break;
04819       default:
04820          goto invalid_freq;
04821       }
04822 
04823       /* Check frequency for validity and establish a default mode */
04824          
04825       snprintf(freq, sizeof(freq), "%s.%03d%02d", args.s1, k, ht);
04826       ast_debug(1, "New frequency: %s\n", freq);      
04827    
04828       split_freq(&mhz, &decimals, freq);
04829 
04830       if (check_freq(myrpt, mhz, decimals, &defmode)) /* Check to see if frequency entered is legit */
04831          goto invalid_freq;
04832 
04833       if ((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
04834          break; /* Not yet */
04835 
04836       offset = REM_SIMPLEX; /* Assume simplex */
04837 
04838       if (defmode == REM_MODE_FM) {
04839          oc = *s; /* Pick off offset */
04840          if (oc) {
04841             switch (oc) {
04842             case '1':
04843                offset = REM_MINUS;
04844                break;
04845             case '2':
04846                offset = REM_SIMPLEX;
04847                break;
04848             case '3':
04849                offset = REM_PLUS;
04850                break;
04851             default:
04852                goto invalid_freq;
04853             } 
04854          } 
04855       }  
04856       offsave = myrpt->offset;
04857       modesave = myrpt->remmode;
04858       ast_copy_string(savestr, myrpt->freq, sizeof(savestr));
04859       ast_copy_string(myrpt->freq, freq, sizeof(myrpt->freq));
04860       myrpt->offset = offset;
04861       myrpt->remmode = defmode;
04862 
04863       if (setrem(myrpt) == -1) {
04864          myrpt->offset = offsave;
04865          myrpt->remmode = modesave;
04866          ast_copy_string(myrpt->freq, savestr, sizeof(myrpt->freq));
04867          goto invalid_freq;
04868       }
04869 
04870       return DC_COMPLETE;
04871 
04872 invalid_freq:
04873       rmt_sayfile(myrpt, mychannel, 1000, "rpt/invalid-freq");
04874 
04875       return DC_ERROR; 
04876       
04877    case 3: /* set rx PL tone */
04878          
04879       for (i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++) { /* look for N+*N */
04880          if (digitbuf[i] == '*') {
04881             j++;
04882             continue;
04883          }
04884          if ((digitbuf[i] < '0') || (digitbuf[i] > '9'))
04885             return DC_ERROR;
04886          else {
04887             if (j)
04888                l++;
04889             else
04890                k++;
04891          }
04892       }
04893       if ((j > 1) || (k > 3) || (l > 1))
04894          return DC_ERROR; /* &$@^! */
04895       i = strlen(digitbuf) - 1;
04896       if ((j != 1) || (k < 2)|| (l != 1))
04897          break; /* Not yet */
04898       ast_debug(1, "PL digits entered %s\n", digitbuf);
04899       
04900       ast_copy_string(tmp, digitbuf, sizeof(tmp));
04901       /* see if we have at least 1 */
04902       s = strchr(tmp, '*');
04903       if (s)
04904          *s = '.';
04905       ast_copy_string(savestr, myrpt->rxpl, sizeof(savestr));
04906       ast_copy_string(myrpt->rxpl, tmp, sizeof(myrpt->rxpl));
04907 
04908       if (setrem(myrpt) == -1) {
04909          ast_copy_string(myrpt->rxpl, savestr, sizeof(myrpt->rxpl));
04910          return DC_ERROR;
04911       }
04912 
04913       return DC_COMPLETE;
04914    case 4: /* set tx PL tone */
04915       for (i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++) { /* look for N+*N */
04916          if (digitbuf[i] == '*') {
04917             j++;
04918             continue;
04919          }
04920          if ((digitbuf[i] < '0') || (digitbuf[i] > '9'))
04921             return DC_ERROR;
04922          else {
04923             if (j)
04924                l++;
04925             else
04926                k++;
04927          }
04928       }
04929       if ((j > 1) || (k > 3) || (l > 1))
04930          return DC_ERROR; /* &$@^! */
04931       i = strlen(digitbuf) - 1;
04932       if ((j != 1) || (k < 2)|| (l != 1))
04933          break; /* Not yet */
04934       ast_debug(1, "PL digits entered %s\n", digitbuf);
04935 
04936       ast_copy_string(tmp, digitbuf, sizeof(tmp));
04937       /* see if we have at least 1 */
04938       s = strchr(tmp, '*');
04939       if (s)
04940          *s = '.';
04941       ast_copy_string(savestr, myrpt->txpl, sizeof(savestr));
04942       ast_copy_string(myrpt->txpl, tmp, sizeof(myrpt->txpl));
04943          
04944       if (setrem(myrpt) == -1) {
04945          ast_copy_string(myrpt->txpl, savestr, sizeof(myrpt->txpl));
04946          return DC_ERROR;
04947       }
04948 
04949       return DC_COMPLETE;
04950 
04951    case 6: /* MODE (FM,USB,LSB,AM) */
04952       if (strlen(digitbuf) < 1)
04953          break;
04954 
04955       if (!multimode)
04956          return DC_ERROR; /* Multimode radios only */
04957 
04958       switch (*digitbuf) {
04959       case '1':
04960          split_freq(&mhz, &decimals, myrpt->freq); 
04961          if (mhz < 29) /* No FM allowed below 29MHz! */
04962             return DC_ERROR;
04963          myrpt->remmode = REM_MODE_FM;
04964          res = rmt_saycharstr(myrpt, mychannel, 1000, "FM");
04965          break;
04966 
04967       case '2':
04968          myrpt->remmode = REM_MODE_USB;
04969          res = rmt_saycharstr(myrpt, mychannel, 1000, "USB");
04970          break;   
04971 
04972       case '3':
04973          myrpt->remmode = REM_MODE_LSB;
04974          res = rmt_saycharstr(myrpt, mychannel, 1000, "LSB");
04975          break;
04976 
04977       case '4':
04978          myrpt->remmode = REM_MODE_AM;
04979          res = rmt_saycharstr(myrpt, mychannel, 1000, "AM");
04980          break;
04981 
04982       default:
04983          return DC_ERROR;
04984       }
04985       if (res)
04986          return DC_ERROR;
04987 
04988       if (setrem(myrpt))
04989          return DC_ERROR;
04990       return DC_COMPLETE;
04991 
04992    case 100: /* other stuff */
04993    case 101:
04994    case 102:
04995    case 103:
04996    case 104:
04997    case 105:
04998    case 106:
04999       res = rmt_telem_start(myrpt, mychannel, 1000);
05000       switch (myatoi(param)) { /* Quick commands requiring a setrem call */
05001       case 100: /* RX PL Off */
05002          myrpt->rxplon = 0;
05003          if (!res)
05004             res = sayfile(mychannel, "rpt/rxpl");
05005          if (!res)
05006             sayfile(mychannel, "rpt/off");
05007          break;
05008 
05009       case 101: /* RX PL On */
05010          myrpt->rxplon = 1;
05011          if (!res)
05012             res = sayfile(mychannel, "rpt/rxpl");
05013          if (!res)
05014             sayfile(mychannel, "rpt/on");
05015          break;
05016 
05017       case 102: /* TX PL Off */
05018          myrpt->txplon = 0;
05019          if (!res)
05020             res = sayfile(mychannel, "rpt/txpl");
05021          if (!res)
05022             sayfile(mychannel, "rpt/off");
05023          break;
05024 
05025       case 103: /* TX PL On */
05026          myrpt->txplon = 1;
05027          if (!res)
05028             res = sayfile(mychannel, "rpt/txpl");
05029          if (!res)
05030             sayfile(mychannel, "rpt/on");
05031          break;
05032 
05033       case 104: /* Low Power */
05034          myrpt->powerlevel = REM_LOWPWR;
05035          if (!res)
05036             res = sayfile(mychannel, "rpt/lopwr");
05037          break;
05038 
05039       case 105: /* Medium Power */
05040          myrpt->powerlevel = REM_MEDPWR;
05041          if (!res)
05042             res = sayfile(mychannel, "rpt/medpwr");
05043          break;
05044 
05045       case 106: /* Hi Power */
05046          myrpt->powerlevel = REM_HIPWR;
05047          if (!res)
05048             res = sayfile(mychannel, "rpt/hipwr");
05049          break;
05050 
05051       default:
05052          if (!res)
05053             rmt_telem_finish(myrpt, mychannel);
05054          return DC_ERROR;
05055       }
05056       if (!res)
05057          res = rmt_telem_finish(myrpt, mychannel);
05058       if (res)
05059          return DC_ERROR;
05060 
05061       if (setrem(myrpt) == -1) 
05062          return DC_ERROR;
05063       return DC_COMPLETE;
05064 
05065    case 107: /* Bump down 20Hz */
05066       multimode_bump_freq(myrpt, -20);
05067       return DC_COMPLETE;
05068 
05069    case 108: /* Bump down 100Hz */
05070       multimode_bump_freq(myrpt, -100);
05071       return DC_COMPLETE;
05072 
05073    case 109: /* Bump down 500Hz */
05074       multimode_bump_freq(myrpt, -500);
05075       return DC_COMPLETE;
05076 
05077    case 110: /* Bump up 20Hz */
05078       multimode_bump_freq(myrpt, 20);
05079       return DC_COMPLETE;
05080             
05081    case 111: /* Bump up 100Hz */
05082       multimode_bump_freq(myrpt, 100);
05083       return DC_COMPLETE;
05084 
05085    case 112: /* Bump up 500Hz */
05086       multimode_bump_freq(myrpt, 500);
05087       return DC_COMPLETE;
05088 
05089    case 113:
05090    case 114:
05091    case 115:
05092    case 116:
05093    case 117:
05094    case 118:
05095       myrpt->remotetx = 0;
05096       ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
05097       if (!myrpt->remoterx)
05098          ast_indicate(mychannel, AST_CONTROL_RADIO_KEY);
05099       if (ast_safe_sleep(mychannel, 1000) == -1)
05100             return DC_ERROR;
05101 
05102       switch (myatoi(param)) {
05103       case 113: /* Scan down slow */
05104          res = sayfile(mychannel, "rpt/down");
05105          if (!res)
05106             res = sayfile(mychannel, "rpt/slow");
05107          if (!res) {
05108             myrpt->scantimer = REM_SCANTIME;
05109             myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
05110          }
05111          break;
05112 
05113       case 114: /* Scan down quick */
05114          res = sayfile(mychannel, "rpt/down");
05115          if (!res)
05116             res = sayfile(mychannel, "rpt/quick");
05117          if (!res) {
05118             myrpt->scantimer = REM_SCANTIME;
05119             myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
05120          }
05121          break;
05122 
05123       case 115: /* Scan down fast */
05124          res = sayfile(mychannel, "rpt/down");
05125          if (!res)
05126             res = sayfile(mychannel, "rpt/fast");
05127          if (!res) {
05128             myrpt->scantimer = REM_SCANTIME;
05129             myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
05130          }
05131          break;
05132 
05133       case 116: /* Scan up slow */
05134          res = sayfile(mychannel, "rpt/up");
05135          if (!res)
05136             res = sayfile(mychannel, "rpt/slow");
05137          if (!res) {
05138             myrpt->scantimer = REM_SCANTIME;
05139             myrpt->hfscanmode = HF_SCAN_UP_SLOW;
05140          }
05141          break;
05142 
05143       case 117: /* Scan up quick */
05144          res = sayfile(mychannel, "rpt/up");
05145          if (!res)
05146             res = sayfile(mychannel, "rpt/quick");
05147          if (!res) {
05148             myrpt->scantimer = REM_SCANTIME;
05149             myrpt->hfscanmode = HF_SCAN_UP_QUICK;
05150          }
05151          break;
05152 
05153       case 118: /* Scan up fast */
05154          res = sayfile(mychannel, "rpt/up");
05155          if (!res)
05156             res = sayfile(mychannel, "rpt/fast");
05157          if (!res) {
05158             myrpt->scantimer = REM_SCANTIME;
05159             myrpt->hfscanmode = HF_SCAN_UP_FAST;
05160          }
05161          break;
05162       }
05163       rmt_telem_finish(myrpt, mychannel);
05164       return DC_COMPLETE;
05165 
05166 
05167    case 119: /* Tune Request */
05168       myrpt->tunerequest = 1;
05169       return DC_COMPLETE;
05170 
05171    case 5: /* Long Status */
05172    case 140: /* Short Status */
05173       res = rmt_telem_start(myrpt, mychannel, 1000);
05174 
05175       res = sayfile(mychannel, "rpt/node");
05176       if (!res)
05177          res = saycharstr(mychannel, myrpt->name);
05178       if (!res)
05179          res = sayfile(mychannel, "rpt/frequency");
05180       if (!res)
05181          res = split_freq(&mhz, &decimals, myrpt->freq);
05182       if (!res) {
05183          if (mhz < 100)
05184             res = saynum(mychannel, mhz);
05185          else
05186             res = saydigits(mychannel, mhz);
05187       }
05188       if (!res)
05189          res = sayfile(mychannel, "letters/dot");
05190       if (!res)
05191          res = saydigits(mychannel, decimals);
05192 
05193       if (res) {  
05194          rmt_telem_finish(myrpt, mychannel);
05195          return DC_ERROR;
05196       }
05197       if (myrpt->remmode == REM_MODE_FM) { /* Mode FM? */
05198          switch (myrpt->offset) {
05199          case REM_MINUS:
05200             res = sayfile(mychannel, "rpt/minus");
05201             break;
05202 
05203          case REM_SIMPLEX:
05204             res = sayfile(mychannel, "rpt/simplex");
05205             break;
05206 
05207          case REM_PLUS:
05208             res = sayfile(mychannel, "rpt/plus");
05209             break;
05210 
05211          default:
05212             return DC_ERROR;
05213 
05214          }
05215       } else { /* Must be USB, LSB, or AM */
05216          switch (myrpt->remmode) {
05217          case REM_MODE_USB:
05218             res = saycharstr(mychannel, "USB");
05219             break;
05220          case REM_MODE_LSB:
05221             res = saycharstr(mychannel, "LSB");
05222             break;
05223          case REM_MODE_AM:
05224             res = saycharstr(mychannel, "AM");
05225             break;
05226          default:
05227             return DC_ERROR;
05228          }
05229       }
05230 
05231       if (res == -1) {
05232          rmt_telem_finish(myrpt, mychannel);
05233          return DC_ERROR;
05234       }
05235 
05236       if (myatoi(param) == 140) { /* Short status? */
05237          if (!res)
05238             res = rmt_telem_finish(myrpt, mychannel);
05239          if (res)
05240             return DC_ERROR;
05241          return DC_COMPLETE;
05242       }
05243 
05244       switch (myrpt->powerlevel) {
05245       case REM_LOWPWR:
05246          res = sayfile(mychannel, "rpt/lopwr") ;
05247          break;
05248       case REM_MEDPWR:
05249          res = sayfile(mychannel, "rpt/medpwr");
05250          break;
05251       case REM_HIPWR:
05252          res = sayfile(mychannel, "rpt/hipwr"); 
05253          break;
05254       }
05255       if (res || (sayfile(mychannel, "rpt/rxpl") == -1) ||
05256          (sayfile(mychannel, "rpt/frequency") == -1) ||
05257          (saycharstr(mychannel, myrpt->rxpl) == -1) ||
05258          (sayfile(mychannel, "rpt/txpl") == -1) ||
05259          (sayfile(mychannel, "rpt/frequency") == -1) ||
05260          (saycharstr(mychannel, myrpt->txpl) == -1) ||
05261          (sayfile(mychannel, "rpt/txpl") == -1) ||
05262          (sayfile(mychannel, ((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1) ||
05263          (sayfile(mychannel, "rpt/rxpl") == -1) ||
05264          (sayfile(mychannel, ((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1))
05265          {
05266          rmt_telem_finish(myrpt, mychannel);
05267          return DC_ERROR;
05268       }
05269       if (!res)
05270          res = rmt_telem_finish(myrpt, mychannel);
05271       if (res)
05272          return DC_ERROR;
05273 
05274       return DC_COMPLETE;
05275    default:
05276       return DC_ERROR;
05277    }
05278 
05279    return DC_INDETERMINATE;
05280 }

static int function_status ( struct rpt myrpt,
char *  param,
char *  digitbuf,
int  command_source,
struct rpt_link mylink 
) [static]

Definition at line 3250 of file app_rpt.c.

References ast_debug, DC_COMPLETE, DC_ERROR, DC_INDETERMINATE, rpt::enable, ID1, myatoi(), rpt_telemetry(), STATS_TIME, and STATS_VERSION.

03251 {
03252 
03253    if (!param)
03254       return DC_ERROR;
03255 
03256    if (!myrpt->enable)
03257       return DC_ERROR;
03258 
03259    ast_debug(1, "@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
03260    
03261    switch (myatoi(param)) {
03262    case 1: /* System ID */
03263       rpt_telemetry(myrpt, ID1, NULL);
03264       return DC_COMPLETE;
03265    case 2: /* System Time */
03266       rpt_telemetry(myrpt, STATS_TIME, NULL);
03267       return DC_COMPLETE;
03268    case 3: /* app_rpt.c version */
03269       rpt_telemetry(myrpt, STATS_VERSION, NULL);
03270    default:
03271       return DC_ERROR;
03272    }
03273 
03274    /* Never reached */
03275    return DC_INDETERMINATE;
03276 }

static int get_wait_interval ( struct rpt myrpt,
int  type 
) [static]

Definition at line 1843 of file app_rpt.c.

References ast_variable_retrieve(), rpt::cfg, DLY_CALLTERM, DLY_ID, DLY_TELEM, DLY_UNKEY, rpt::name, and retrieve_astcfgint().

Referenced by rpt_tele_thread(), and wait_interval().

01844 {
01845    int interval = 1000;
01846    const char *wait_times = ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
01847 
01848    switch (type) {
01849    case DLY_TELEM:
01850       if (wait_times)
01851          interval = retrieve_astcfgint(myrpt, wait_times, "telemwait", 500, 5000, 1000);
01852       break;
01853    case DLY_ID:
01854       if (wait_times)
01855          interval = retrieve_astcfgint(myrpt, wait_times, "idwait", 250, 5000, 500);
01856       else
01857          interval = 500;
01858       break;
01859    case DLY_UNKEY:
01860       if (wait_times)
01861          interval = retrieve_astcfgint(myrpt, wait_times, "unkeywait", 500, 5000, 1000);
01862       break;
01863    case DLY_CALLTERM:
01864       if (wait_times)
01865          interval = retrieve_astcfgint(myrpt, wait_times, "calltermwait", 500, 5000, 1500);
01866       break;
01867    default:
01868       return 0;
01869    }
01870    return interval;
01871 }

static char * handle_cli_rpt_debug_level ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1075 of file app_rpt.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, myatoi(), and ast_cli_entry::usage.

01076 {
01077    int newlevel;
01078 
01079    switch (cmd) {
01080    case CLI_INIT:
01081       e->command = "rpt debug level";
01082       e->usage =
01083          "Usage: rpt debug level {0-7}\n"
01084          "       Enables debug messages in app_rpt\n";
01085       return NULL;
01086    case CLI_GENERATE:
01087       return NULL;
01088    }
01089    if (a->argc != e->args)
01090       return CLI_SHOWUSAGE;
01091    newlevel = myatoi(a->argv[3]);
01092    if ((newlevel < 0) || (newlevel > 7))
01093       return CLI_SHOWUSAGE;
01094    if (newlevel)
01095       ast_cli(a->fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
01096    else
01097       ast_cli(a->fd, "app_rpt Debugging disabled\n");
01098 
01099    debug = newlevel;
01100 
01101    return CLI_SUCCESS;
01102 }

static char * handle_cli_rpt_dump ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1107 of file app_rpt.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, rpt::disgorgetime, ast_cli_args::fd, rpt::name, rpt_vars, and ast_cli_entry::usage.

01108 {
01109    int i;
01110 
01111    switch (cmd) {
01112    case CLI_INIT:
01113       e->command = "rpt dump";
01114       e->usage =
01115          "Usage: rpt dump <nodename>\n"
01116          "       Dumps struct debug info to log\n";
01117       return NULL;
01118    case CLI_GENERATE:
01119       return NULL;
01120    }
01121 
01122    if (a->argc != 3)
01123       return CLI_SHOWUSAGE;
01124 
01125    for (i = 0; i < nrpts; i++) {
01126       if (!strcmp(a->argv[2], rpt_vars[i].name)) {
01127          rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
01128          ast_cli(a->fd, "app_rpt struct dump requested for node %s\n", a->argv[2]);
01129          return CLI_SUCCESS;
01130       }
01131    }
01132    return CLI_FAILURE;
01133 }

static char * handle_cli_rpt_lstats ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1327 of file app_rpt.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_calloc, ast_copy_string(), ast_log(), rpt_link::chan, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, rpt_link::connecttime, rpt::links, rpt::lock, LOG_ERROR, MAXPEERSTR, MAXREMSTR, rpt_link::mode, rpt_link::name, rpt::name, rpt_link::next, rpt_lstat::next, rpt_link::outbound, pbx_substitute_variables_helper(), rpt_lstat::prev, rpt_link::reconnects, rpt_mutex_lock, rpt_mutex_unlock, rpt_vars, s, and ast_cli_entry::usage.

01328 {
01329    int i, j;
01330    struct rpt *myrpt;
01331    struct rpt_link *l;
01332    struct rpt_lstat *s, *t;
01333    struct rpt_lstat s_head;
01334 
01335    switch (cmd) {
01336    case CLI_INIT:
01337       e->command = "rpt lstats";
01338       e->usage =
01339          "Usage: rpt lstats <nodename>\n"
01340          "       Dumps link statistics to console\n";
01341       return NULL;
01342    case CLI_GENERATE:
01343       return NULL;
01344    }
01345 
01346    if (a->argc != 3)
01347       return CLI_SHOWUSAGE;
01348 
01349    s = NULL;
01350    s_head.next = &s_head;
01351    s_head.prev = &s_head;
01352 
01353    for (i = 0; i < nrpts; i++) {
01354       if (!strcmp(a->argv[2], rpt_vars[i].name)) {
01355          /* Make a copy of all stat variables while locked */
01356          myrpt = &rpt_vars[i];
01357          rpt_mutex_lock(&myrpt->lock); /* LOCK */
01358          /* Traverse the list of connected nodes */
01359          j = 0;
01360          l = myrpt->links.next;
01361          while (l != &myrpt->links) {
01362             if (l->name[0] == '0') { /* Skip '0' nodes */
01363                l = l->next;
01364                continue;
01365             }
01366             if ((s = ast_calloc(1, sizeof(*s))) == NULL) {
01367                ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
01368                rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
01369                return CLI_FAILURE;
01370             }
01371             ast_copy_string(s->name, l->name, MAXREMSTR);
01372             pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
01373             s->mode = l->mode;
01374             s->outbound = l->outbound;
01375             s->reconnects = l->reconnects;
01376             s->connecttime = l->connecttime;
01377             insque((struct qelem *) s, (struct qelem *) s_head.next);
01378             l = l->next;
01379          }
01380          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
01381          ast_cli(a->fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME\n");
01382          ast_cli(a->fd, "----      ----                ----------  ---------  ------------\n");
01383 
01384          for (s = s_head.next; s != &s_head; s = s->next) {
01385             int hours, minutes, seconds;
01386             long long connecttime = s->connecttime;
01387             char conntime[31];
01388             hours = (int) connecttime/3600000;
01389             connecttime %= 3600000;
01390             minutes = (int) connecttime/60000;
01391             connecttime %= 60000;
01392             seconds = (int)  connecttime/1000;
01393             connecttime %= 1000;
01394             snprintf(conntime, sizeof(conntime), "%02d:%02d:%02d.%d",
01395                hours, minutes, seconds, (int) connecttime);
01396             ast_cli(a->fd, "%-10s%-20s%-12d%-11s%-30s\n",
01397                s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime);
01398          }  
01399          /* destroy our local link queue */
01400          s = s_head.next;
01401          while (s != &s_head) {
01402             t = s;
01403             s = s->next;
01404             remque((struct qelem *)t);
01405             ast_free(t);
01406          }        
01407          return CLI_SUCCESS;
01408       }
01409    }
01410 
01411    return CLI_FAILURE;
01412 }

static char * handle_cli_rpt_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1417 of file app_rpt.c.

References ast_cli_args::argc, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, reload, rpt_vars, and ast_cli_entry::usage.

01418 {
01419    int   n;
01420 
01421    switch (cmd) {
01422    case CLI_INIT:
01423       e->command = "rpt reload";
01424       e->usage =
01425          "Usage: rpt reload\n"
01426          "       Reloads app_rpt running config parameters\n";
01427       return NULL;
01428    case CLI_GENERATE:
01429       return NULL;
01430    }
01431 
01432    if (a->argc > 2)
01433       return CLI_SHOWUSAGE;
01434 
01435    for (n = 0; n < nrpts; n++)
01436       rpt_vars[n].reload = 1;
01437 
01438    return CLI_SUCCESS;
01439 }

static char * handle_cli_rpt_restart ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1444 of file app_rpt.c.

References ast_cli_args::argc, ast_softhangup(), AST_SOFTHANGUP_DEV, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, rpt_vars, and ast_cli_entry::usage.

01445 {
01446    int   i;
01447 
01448    switch (cmd) {
01449    case CLI_INIT:
01450       e->command = "rpt restart";
01451       e->usage =
01452          "Usage: rpt restart\n"
01453          "       Restarts app_rpt\n";
01454       return NULL;
01455    case CLI_GENERATE:
01456       return NULL;
01457    }
01458 
01459    if (a->argc > 2)
01460       return CLI_SHOWUSAGE;
01461    for (i = 0; i < nrpts; i++) {
01462       if (rpt_vars[i].rxchannel)
01463          ast_softhangup(rpt_vars[i].rxchannel, AST_SOFTHANGUP_DEV);
01464    }
01465    return CLI_SUCCESS;
01466 }

static char * handle_cli_rpt_stats ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1138 of file app_rpt.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_strdupa, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, rpt::dailyexecdcommands, rpt::dailykerchunks, rpt::dailykeyups, rpt::dailytxtime, rpt::links, rpt::lock, MAX_STAT_LINKS, rpt_link::name, rpt::name, rpt_link::next, rpt_mutex_lock, rpt_vars, rpt::timeouts, rpt::totalexecdcommands, rpt::totalkerchunks, rpt::totalkeyups, rpt::totaltxtime, and ast_cli_entry::usage.

01139 {
01140    int i, j;
01141    int dailytxtime, dailykerchunks;
01142    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
01143    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
01144    long long totaltxtime;
01145    struct rpt_link *l;
01146    char *listoflinks[MAX_STAT_LINKS];  
01147    char *lastnodewhichkeyedusup, *lastdtmfcommand;
01148    char *tot_state, *ider_state, *patch_state;
01149    char *reverse_patch_state, *enable_state, *input_signal, *called_number;
01150    struct rpt *myrpt;
01151 
01152    static char *not_applicable = "N/A";
01153 
01154    switch (cmd) {
01155    case CLI_INIT:
01156       e->command = "rpt stats";
01157       e->usage =
01158          "Usage: rpt stats <nodename>\n"
01159          "       Dumps node statistics to console\n";
01160       return NULL;
01161    case CLI_GENERATE:
01162       return NULL;
01163    }
01164 
01165    if (a->argc != 3)
01166       return CLI_SHOWUSAGE;
01167 
01168    for (i = 0 ; i <= MAX_STAT_LINKS; i++)
01169       listoflinks[i] = NULL;
01170 
01171    tot_state = ider_state = 
01172    patch_state = reverse_patch_state = 
01173    input_signal = called_number = 
01174    lastdtmfcommand = not_applicable;
01175 
01176    for (i = 0; i < nrpts; i++) {
01177       if (!strcmp(a->argv[2], rpt_vars[i].name)) {
01178          /* Make a copy of all stat variables while locked */
01179          myrpt = &rpt_vars[i];
01180          rpt_mutex_lock(&myrpt->lock); /* LOCK */
01181 
01182          dailytxtime = myrpt->dailytxtime;
01183          totaltxtime = myrpt->totaltxtime;
01184          dailykeyups = myrpt->dailykeyups;
01185          totalkeyups = myrpt->totalkeyups;
01186          dailykerchunks = myrpt->dailykerchunks;
01187          totalkerchunks = myrpt->totalkerchunks;
01188          dailyexecdcommands = myrpt->dailyexecdcommands;
01189          totalexecdcommands = myrpt->totalexecdcommands;
01190          timeouts = myrpt->timeouts;
01191 
01192          /* Traverse the list of connected nodes */
01193          reverse_patch_state = "DOWN";
01194          j = 0;
01195          l = myrpt->links.next;
01196          while (l != &myrpt->links) {
01197             if (l->name[0] == '0') { /* Skip '0' nodes */
01198                reverse_patch_state = "UP";
01199                l = l->next;
01200                continue;
01201             }
01202             listoflinks[j] = ast_strdupa(l->name);
01203             if (listoflinks[j])
01204                j++;
01205             l = l->next;
01206          }
01207 
01208          lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);       
01209          if ((!lastnodewhichkeyedusup) || (ast_strlen_zero(lastnodewhichkeyedusup)))
01210             lastnodewhichkeyedusup = not_applicable;
01211 
01212          if (myrpt->keyed)
01213             input_signal = "YES";
01214          else
01215             input_signal = "NO";
01216 
01217          if (myrpt->enable)
01218             enable_state = "YES";
01219          else
01220             enable_state = "NO";
01221 
01222          if (!myrpt->totimer)
01223             tot_state = "TIMED OUT!";
01224          else if (myrpt->totimer != myrpt->p.totime)
01225             tot_state = "ARMED";
01226          else
01227             tot_state = "RESET";
01228 
01229          if (myrpt->tailid)
01230             ider_state = "QUEUED IN TAIL";
01231          else if (myrpt->mustid)
01232             ider_state = "QUEUED FOR CLEANUP";
01233          else
01234             ider_state = "CLEAN";
01235 
01236          switch (myrpt->callmode) {
01237          case 1:
01238             patch_state = "DIALING";
01239             break;
01240          case 2:
01241             patch_state = "CONNECTING";
01242             break;
01243          case 3:
01244             patch_state = "UP";
01245             break;
01246          case 4:
01247             patch_state = "CALL FAILED";
01248             break;
01249          default:
01250             patch_state = "DOWN";
01251          }
01252 
01253          if (!ast_strlen_zero(myrpt->exten))
01254             called_number = ast_strdupa(myrpt->exten);
01255 
01256          if (!ast_strlen_zero(myrpt->lastdtmfcommand))
01257             lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
01258 
01259          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
01260 
01261          ast_cli(a->fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
01262          ast_cli(a->fd, "Signal on input..................................: %s\n", input_signal);
01263          ast_cli(a->fd, "Transmitter enabled..............................: %s\n", enable_state);
01264          ast_cli(a->fd, "Time out timer state.............................: %s\n", tot_state);
01265          ast_cli(a->fd, "Time outs since system initialization............: %d\n", timeouts);
01266          ast_cli(a->fd, "Identifier state.................................: %s\n", ider_state);
01267          ast_cli(a->fd, "Kerchunks today..................................: %d\n", dailykerchunks);
01268          ast_cli(a->fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
01269          ast_cli(a->fd, "Keyups today.....................................: %d\n", dailykeyups);
01270          ast_cli(a->fd, "Keyups since system initialization...............: %d\n", totalkeyups);
01271          ast_cli(a->fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
01272          ast_cli(a->fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
01273          ast_cli(a->fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
01274 
01275          hours = dailytxtime / 3600000;
01276          dailytxtime %= 3600000;
01277          minutes = dailytxtime / 60000;
01278          dailytxtime %= 60000;
01279          seconds = dailytxtime / 1000;
01280          dailytxtime %= 1000;
01281 
01282          ast_cli(a->fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
01283             hours, minutes, seconds, dailytxtime);
01284 
01285          hours = (int) totaltxtime / 3600000;
01286          totaltxtime %= 3600000;
01287          minutes = (int) totaltxtime / 60000;
01288          totaltxtime %= 60000;
01289          seconds = (int)  totaltxtime / 1000;
01290          totaltxtime %= 1000;
01291 
01292          ast_cli(a->fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
01293              hours, minutes, seconds, (int) totaltxtime);
01294          ast_cli(a->fd, "Nodes currently connected to us..................: ");
01295          for (j = 0;; j++) {
01296             if (!listoflinks[j]) {
01297                if (!j) {
01298                   ast_cli(a->fd, "<NONE>");
01299                }
01300                break;
01301             }
01302             ast_cli(a->fd, "%s", listoflinks[j]);
01303             if (j % 4 == 3) {
01304                ast_cli(a->fd, "\n");
01305                ast_cli(a->fd, "                                                 : ");
01306             } else {
01307                if (listoflinks[j + 1])
01308                   ast_cli(a->fd, ", ");
01309             }
01310          }
01311          ast_cli(a->fd, "\n");
01312 
01313          ast_cli(a->fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
01314          ast_cli(a->fd, "Autopatch state..................................: %s\n", patch_state);
01315          ast_cli(a->fd, "Autopatch called number..........................: %s\n", called_number);
01316          ast_cli(a->fd, "Reverse patch/IAXRPT connected...................: %s\n\n", reverse_patch_state);
01317 
01318          return CLI_SUCCESS;
01319       }
01320    }
01321    return CLI_FAILURE;
01322 }

static void handle_link_data ( struct rpt myrpt,
struct rpt_link mylink,
char *  str 
) [static]

Definition at line 3483 of file app_rpt.c.

References ast_canmatch_extension(), ast_copy_string(), ast_exists_extension(), AST_FRAME_TEXT, ast_log(), ast_softhangup(), AST_SOFTHANGUP_DEV, ast_strdup, ast_write(), rpt::callmode, rpt_link::chan, rpt::cidx, collect_function_digits(), rpt::dailyexecdcommands, ast_frame::data, ast_frame::datalen, DC_COMPLETE, DC_ERROR, DC_INDETERMINATE, DC_REQ_FLUSH, rpt_link::disced, rpt::endchar, rpt::exten, ast_frame::frametype, rpt::funcchar, rpt::lastdtmfcommand, rpt::links, rpt::lock, LOG_WARNING, ast_frame::mallocd, MAX_RETRIES, MAXDTMF, rpt::mydtmf, rpt_link::name, rpt::name, rpt_link::next, ast_frame::offset, rpt::p, rpt::patchcontext, rpt::patchquiet, rpt::pchannel, PROC, rpt::rem_dtmf_time, rpt::rem_dtmfbuf, rpt::rem_dtmfidx, rpt_link::retries, rpt_mutex_lock, rpt_mutex_unlock, rpt_telemetry(), ast_frame::samples, seq, SOURCE_LNK, rpt::stopgen, ast_frame::subclass, and rpt::totalexecdcommands.

Referenced by rpt().

03484 {
03485    char cmd[300] = "", dest[300], src[300], c;
03486    int   seq, res;
03487    struct rpt_link *l;
03488    struct ast_frame wf;
03489 
03490    wf.frametype = AST_FRAME_TEXT;
03491    wf.subclass = 0;
03492    wf.offset = 0;
03493    wf.mallocd = 1;
03494    wf.datalen = strlen(str) + 1;
03495    wf.samples = 0;
03496    if (!strcmp(str, discstr)) {
03497       mylink->disced = 1;
03498       mylink->retries = MAX_RETRIES + 1;
03499       ast_softhangup(mylink->chan, AST_SOFTHANGUP_DEV);
03500       return;
03501    }
03502    if (sscanf(str, "%s %s %s %d %c", cmd, dest, src, &seq, &c) != 5) {
03503       ast_log(LOG_WARNING, "Unable to parse link string %s\n", str);
03504       return;
03505    }
03506    if (strcmp(cmd, "D")) {
03507       ast_log(LOG_WARNING, "Unable to parse link string %s\n", str);
03508       return;
03509    }
03510 
03511    if (dest[0] == '0') {
03512       strcpy(dest, myrpt->name);
03513    }
03514 
03515    /* if not for me, redistribute to all links */
03516    if (strcmp(dest, myrpt->name)) {
03517       l = myrpt->links.next;
03518       /* see if this is one in list */
03519       while (l != &myrpt->links) {
03520          if (l->name[0] == '0') {
03521             l = l->next;
03522             continue;
03523          }
03524          /* dont send back from where it came */
03525          if ((l == mylink) || (!strcmp(l->name, mylink->name))) {
03526             l = l->next;
03527             continue;
03528          }
03529          /* if it is, send it and we're done */
03530          if (!strcmp(l->name, dest)) {
03531             /* send, but not to src */
03532             if (strcmp(l->name, src)) {
03533                wf.data = ast_strdup(str);
03534                if (l->chan)
03535                   ast_write(l->chan, &wf);
03536             }
03537             return;
03538          }
03539          l = l->next;
03540       }
03541       l = myrpt->links.next;
03542       /* otherwise, send it to all of em */
03543       while (l != &myrpt->links) {
03544          if (l->name[0] == '0') {
03545             l = l->next;
03546             continue;
03547          }
03548          /* dont send back from where it came */
03549          if ((l == mylink) || (!strcmp(l->name, mylink->name))) {
03550             l = l->next;
03551             continue;
03552          }
03553          /* send, but not to src */
03554          if (strcmp(l->name, src)) {
03555             wf.data = ast_strdup(str);
03556             if (l->chan)
03557                ast_write(l->chan, &wf);
03558          }
03559          l = l->next;
03560       }
03561       return;
03562    }
03563    rpt_mutex_lock(&myrpt->lock);
03564    if (c == myrpt->p.endchar)
03565       myrpt->stopgen = 1;
03566    if (myrpt->callmode == 1) {
03567       myrpt->exten[myrpt->cidx++] = c;
03568       myrpt->exten[myrpt->cidx] = 0;
03569       /* if this exists */
03570       if (ast_exists_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
03571          myrpt->callmode = 2;
03572          if (!myrpt->patchquiet) {
03573             rpt_mutex_unlock(&myrpt->lock);
03574             rpt_telemetry(myrpt, PROC, NULL); 
03575             rpt_mutex_lock(&myrpt->lock);
03576          }
03577       }
03578       /* if can continue, do so */
03579       if (!ast_canmatch_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
03580          /* call has failed, inform user */
03581          myrpt->callmode = 4;
03582       }
03583    }
03584    if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) {
03585       myrpt->mydtmf = c;
03586    }
03587    if (c == myrpt->p.funcchar) {
03588       myrpt->rem_dtmfidx = 0;
03589       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
03590       time(&myrpt->rem_dtmf_time);
03591       rpt_mutex_unlock(&myrpt->lock);
03592       return;
03593    } else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0)) {
03594       time(&myrpt->rem_dtmf_time);
03595       if (myrpt->rem_dtmfidx < MAXDTMF) {
03596          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
03597          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
03598          
03599          rpt_mutex_unlock(&myrpt->lock);
03600          ast_copy_string(cmd, myrpt->rem_dtmfbuf, sizeof(cmd));
03601          res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
03602          rpt_mutex_lock(&myrpt->lock);
03603          
03604          switch (res) {
03605          case DC_INDETERMINATE:
03606             break;
03607          case DC_REQ_FLUSH:
03608             myrpt->rem_dtmfidx = 0;
03609             myrpt->rem_dtmfbuf[0] = 0;
03610             break;
03611          case DC_COMPLETE:
03612             myrpt->totalexecdcommands++;
03613             myrpt->dailyexecdcommands++;
03614             ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF);
03615             myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
03616             myrpt->rem_dtmfbuf[0] = 0;
03617             myrpt->rem_dtmfidx = -1;
03618             myrpt->rem_dtmf_time = 0;
03619             break;
03620          case DC_ERROR:
03621          default:
03622             myrpt->rem_dtmfbuf[0] = 0;
03623             myrpt->rem_dtmfidx = -1;
03624             myrpt->rem_dtmf_time = 0;
03625             break;
03626          }
03627       }
03628 
03629    }
03630    rpt_mutex_unlock(&myrpt->lock);
03631    return;
03632 }

static void handle_link_phone_dtmf ( struct rpt myrpt,
struct rpt_link mylink,
char  c 
) [static]

Definition at line 3634 of file app_rpt.c.

References ast_canmatch_extension(), ast_copy_string(), ast_exists_extension(), rpt::callmode, rpt::cidx, rpt::cmdnode, collect_function_digits(), COMPLETE, rpt::dailyexecdcommands, DC_COMPLETE, DC_DOKEY, DC_ERROR, DC_INDETERMINATE, DC_REQ_FLUSH, rpt::dtmfbuf, rpt::dtmfidx, rpt::endchar, rpt::exten, rpt::funcchar, rpt::lastdtmfcommand, rpt_link::lastrx, rpt::lock, MAXDTMF, rpt::mydtmf, rpt::p, rpt::patchcontext, rpt::patchquiet, rpt::pchannel, rpt_link::phonemode, PROC, rpt::rem_dtmf_time, rpt::rem_dtmfbuf, rpt::rem_dtmfidx, rpt_mutex_lock, rpt_mutex_unlock, rpt_telemetry(), send_link_dtmf(), SOURCE_DPHONE, SOURCE_LNK, SOURCE_PHONE, rpt::stopgen, and rpt::totalexecdcommands.

Referenced by rpt().

03635 {
03636    char cmd[300];
03637    int   res;
03638 
03639    rpt_mutex_lock(&myrpt->lock);
03640    if (c == myrpt->p.endchar) {
03641       if (mylink->lastrx) {
03642          mylink->lastrx = 0;
03643          rpt_mutex_unlock(&myrpt->lock);
03644          return;
03645       }
03646       myrpt->stopgen = 1;
03647       if (myrpt->cmdnode[0]) {
03648          myrpt->cmdnode[0] = 0;
03649          myrpt->dtmfidx = -1;
03650          myrpt->dtmfbuf[0] = 0;
03651          rpt_mutex_unlock(&myrpt->lock);
03652          rpt_telemetry(myrpt, COMPLETE, NULL);
03653          return;
03654       }
03655    }
03656    if (myrpt->cmdnode[0]) {
03657       rpt_mutex_unlock(&myrpt->lock);
03658       send_link_dtmf(myrpt, c);
03659       return;
03660    }
03661    if (myrpt->callmode == 1) {
03662       myrpt->exten[myrpt->cidx++] = c;
03663       myrpt->exten[myrpt->cidx] = 0;
03664       /* if this exists */
03665       if (ast_exists_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
03666          myrpt->callmode = 2;
03667          if (!myrpt->patchquiet) {
03668             rpt_mutex_unlock(&myrpt->lock);
03669             rpt_telemetry(myrpt, PROC, NULL); 
03670             rpt_mutex_lock(&myrpt->lock);
03671          }
03672       }
03673       /* if can continue, do so */
03674       if (!ast_canmatch_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
03675          /* call has failed, inform user */
03676          myrpt->callmode = 4;
03677       }
03678    }
03679    if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) {
03680       myrpt->mydtmf = c;
03681    }
03682    if (c == myrpt->p.funcchar) {
03683       myrpt->rem_dtmfidx = 0;
03684       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
03685       time(&myrpt->rem_dtmf_time);
03686       rpt_mutex_unlock(&myrpt->lock);
03687       return;
03688    } else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0)) {
03689       time(&myrpt->rem_dtmf_time);
03690       if (myrpt->rem_dtmfidx < MAXDTMF) {
03691          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
03692          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
03693          
03694          rpt_mutex_unlock(&myrpt->lock);
03695          ast_copy_string(cmd, myrpt->rem_dtmfbuf, sizeof(cmd));
03696          switch(mylink->phonemode) {
03697           case 1:
03698             res = collect_function_digits(myrpt, cmd, 
03699                SOURCE_PHONE, mylink);
03700             break;
03701           case 2:
03702             res = collect_function_digits(myrpt, cmd, 
03703                SOURCE_DPHONE, mylink);
03704             break;
03705           default:
03706             res = collect_function_digits(myrpt, cmd, 
03707                SOURCE_LNK, mylink);
03708             break;
03709          }
03710 
03711          rpt_mutex_lock(&myrpt->lock);
03712 
03713          switch(res) {
03714          case DC_INDETERMINATE:
03715             break;
03716          case DC_DOKEY:
03717             mylink->lastrx = 1;
03718             break;
03719          case DC_REQ_FLUSH:
03720             myrpt->rem_dtmfidx = 0;
03721             myrpt->rem_dtmfbuf[0] = 0;
03722             break;
03723          case DC_COMPLETE:
03724             myrpt->totalexecdcommands++;
03725             myrpt->dailyexecdcommands++;
03726             ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF);
03727             myrpt->rem_dtmfbuf[0] = 0;
03728             myrpt->rem_dtmfidx = -1;
03729             myrpt->rem_dtmf_time = 0;
03730             break;
03731          case DC_ERROR:
03732          default:
03733             myrpt->rem_dtmfbuf[0] = 0;
03734             myrpt->rem_dtmfidx = -1;
03735             myrpt->rem_dtmf_time = 0;
03736             break;
03737          }
03738       }
03739 
03740    }
03741    rpt_mutex_unlock(&myrpt->lock);
03742    return;
03743 }

static int handle_remote_data ( struct rpt myrpt,
char *  str 
) [static]

Definition at line 5371 of file app_rpt.c.

References AST_CONTROL_RADIO_KEY, AST_CONTROL_RADIO_UNKEY, ast_indicate(), ast_log(), ast_safe_sleep(), handle_remote_dtmf_digit(), LOG_WARNING, rpt::name, rpt::remchannel, rpt::remoterx, rpt::remotetx, rmt_telem_finish(), seq, telem_lookup(), and rpt::txchannel.

05372 {
05373    char cmd[300], dest[300], src[300], c;
05374    int   seq, res;
05375 
05376    if (!strcmp(str, discstr))
05377       return 0;
05378    if (sscanf(str, "%s %s %s %d %c", cmd, dest, src, &seq, &c) != 5) {
05379       ast_log(LOG_WARNING, "Unable to parse link string %s\n", str);
05380       return 0;
05381    }
05382    if (strcmp(cmd, "D")) {
05383       ast_log(LOG_WARNING, "Unable to parse link string %s\n", str);
05384       return 0;
05385    }
05386    /* if not for me, ignore */
05387    if (strcmp(dest, myrpt->name))
05388       return 0;
05389    res = handle_remote_dtmf_digit(myrpt, c, NULL, 0);
05390    if (res != 1)
05391       return res;
05392    myrpt->remotetx = 0;
05393    ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
05394    if (!myrpt->remoterx) {
05395       ast_indicate(myrpt->remchannel, AST_CONTROL_RADIO_KEY);
05396    }
05397    if (ast_safe_sleep(myrpt->remchannel, 1000) == -1)
05398       return -1;
05399    res = telem_lookup(myrpt, myrpt->remchannel, myrpt->name, "functcomplete");
05400    rmt_telem_finish(myrpt, myrpt->remchannel);
05401    return res;
05402 }

static int handle_remote_dtmf_digit ( struct rpt myrpt,
char  c,
char *  keyed,
int  phonemode 
) [static]

Definition at line 5282 of file app_rpt.c.

References ast_copy_string(), collect_function_digits(), rpt::dailyexecdcommands, DC_COMPLETE, DC_DOKEY, DC_ERROR, DC_INDETERMINATE, DC_REQ_FLUSH, rpt::dtmf_time_rem, DTMF_TIMEOUT, rpt::dtmfbuf, rpt::dtmfidx, rpt::funcchar, rpt::hfscanmode, rpt::lastdtmfcommand, MAXDTMF, rpt::p, SOURCE_DPHONE, SOURCE_PHONE, SOURCE_RMT, stop_scan(), and rpt::totalexecdcommands.

Referenced by handle_remote_data(), and handle_remote_phone_dtmf().

05283 {
05284    time_t now;
05285    int   ret, res = 0, src;
05286 
05287    /* Stop scan mode if in scan mode */
05288    if (myrpt->hfscanmode) {
05289       stop_scan(myrpt, 0);
05290       return 0;
05291    }
05292 
05293    time(&now);
05294    /* if timed-out */
05295    if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now) {
05296       myrpt->dtmfidx = -1;
05297       myrpt->dtmfbuf[0] = 0;
05298       myrpt->dtmf_time_rem = 0;
05299    }
05300    /* if decode not active */
05301    if (myrpt->dtmfidx == -1) {
05302       /* if not lead-in digit, dont worry */
05303       if (c != myrpt->p.funcchar)
05304          return 0;
05305       myrpt->dtmfidx = 0;
05306       myrpt->dtmfbuf[0] = 0;
05307       myrpt->dtmf_time_rem = now;
05308       return 0;
05309    }
05310    /* if too many in buffer, start over */
05311    if (myrpt->dtmfidx >= MAXDTMF) {
05312       myrpt->dtmfidx = 0;
05313       myrpt->dtmfbuf[0] = 0;
05314       myrpt->dtmf_time_rem = now;
05315    }
05316    if (c == myrpt->p.funcchar) {
05317       /* if star at beginning, or 2 together, erase buffer */
05318       if ((myrpt->dtmfidx < 1) || (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar)) {
05319          myrpt->dtmfidx = 0;
05320          myrpt->dtmfbuf[0] = 0;
05321          myrpt->dtmf_time_rem = now;
05322          return 0;
05323       }
05324    }
05325    myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
05326    myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
05327    myrpt->dtmf_time_rem = now;
05328    
05329    
05330    src = SOURCE_RMT;
05331    if (phonemode > 1)
05332       src = SOURCE_DPHONE;
05333    else if (phonemode)
05334       src = SOURCE_PHONE;
05335    ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
05336    
05337    switch(ret) {
05338    case DC_INDETERMINATE:
05339       res = 0;
05340       break;
05341    case DC_DOKEY:
05342       if (keyed)
05343          *keyed = 1;
05344       res = 0;
05345       break;
05346    case DC_REQ_FLUSH:
05347       myrpt->dtmfidx = 0;
05348       myrpt->dtmfbuf[0] = 0;
05349       res = 0;
05350       break;
05351    case DC_COMPLETE:
05352       myrpt->totalexecdcommands++;
05353       myrpt->dailyexecdcommands++;
05354       ast_copy_string(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF);
05355       myrpt->dtmfbuf[0] = 0;
05356       myrpt->dtmfidx = -1;
05357       myrpt->dtmf_time_rem = 0;
05358       res = 1;
05359       break;
05360    case DC_ERROR:
05361    default:
05362       myrpt->dtmfbuf[0] = 0;
05363       myrpt->dtmfidx = -1;
05364       myrpt->dtmf_time_rem = 0;
05365       res = 0;
05366    }
05367 
05368    return res;
05369 }

static int handle_remote_phone_dtmf ( struct rpt myrpt,
char  c,
char *  keyed,
int  phonemode 
) [static]

Definition at line 5404 of file app_rpt.c.

References AST_CONTROL_RADIO_KEY, AST_CONTROL_RADIO_UNKEY, ast_indicate(), ast_safe_sleep(), DC_INDETERMINATE, rpt::endchar, handle_remote_dtmf_digit(), rpt::name, rpt::p, rpt::remchannel, rpt::remoterx, rpt::remotetx, rmt_telem_finish(), telem_lookup(), and rpt::txchannel.

05405 {
05406    int   res;
05407 
05408    if (keyed && *keyed && (c == myrpt->p.endchar)) {
05409       *keyed = 0;
05410       return DC_INDETERMINATE;
05411    }
05412 
05413    res = handle_remote_dtmf_digit(myrpt, c, keyed, phonemode);
05414    if (res != 1)
05415       return res;
05416    myrpt->remotetx = 0;
05417    ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
05418    if (!myrpt->remoterx) {
05419       ast_indicate(myrpt->remchannel, AST_CONTROL_RADIO_KEY);
05420    }
05421    if (ast_safe_sleep(myrpt->remchannel, 1000) == -1)
05422       return -1;
05423    res = telem_lookup(myrpt, myrpt->remchannel, myrpt->name, "functcomplete");
05424    rmt_telem_finish(myrpt, myrpt->remchannel);
05425    return res;
05426 }

static int load_module ( void   )  [static]

Definition at line 7449 of file app_rpt.c.

References ast_cli_register_multiple(), ast_config_load, ast_log(), AST_MODULE_LOAD_DECLINE, ast_pthread_create, ast_register_application, cli_rpt, CONFIG_FLAG_NOCACHE, LOG_WARNING, rpt_exec(), and rpt_master().

07450 {
07451    struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07452    struct ast_config *cfg = ast_config_load("rpt.conf", config_flags);
07453    if (!cfg) {
07454       ast_log(LOG_WARNING, "No such configuration file rpt.conf\n");
07455       return AST_MODULE_LOAD_DECLINE;
07456    }
07457    ast_pthread_create(&rpt_master_thread, NULL, rpt_master, cfg);
07458 
07459    /* Register cli extensions */
07460    ast_cli_register_multiple(cli_rpt, sizeof(cli_rpt) / sizeof(struct ast_cli_entry));
07461 
07462    return ast_register_application(app, rpt_exec, synopsis, descrip);
07463 }

static void load_rpt_vars ( int  n,
int  init 
) [static]

Definition at line 862 of file app_rpt.c.

References AST_APP_ARG, ast_config_destroy(), ast_config_load, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_free, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, ast_variable_browse(), ast_verb, rpt::cfg, CONFIG_FLAG_NOCACHE, DEFAULT_IOBASE, rpt::duplex, ENDCHAR, rpt::endchar, FUNCCHAR, rpt::funcchar, FUNCTIONS, rpt::functions, GOSUB, rpt::gosub, HANGTIME, rpt::hangtime, IDTIME, rpt::idtime, rpt::iobase, lock, LOG_NOTICE, MACRO, rpt::macro, MEMORY, rpt::memory, rpt::name, name, NODES, rpt::nodes, rpt::ourcallerid, rpt::ourcontext, rpt::p, POLITEID, rpt::politeid, rpt_vars, rpt::simple, str, rpt::tailmsgbuf, TOTIME, rpt::totime, typeof(), and var.

Referenced by rpt(), and rpt_master().

00863 {
00864    int   j;
00865    struct ast_variable *vp, *var;
00866    struct ast_config *cfg;
00867    struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
00868 #ifdef   __RPT_NOTCH
00869    AST_DECLARE_APP_ARGS(strs,
00870       AST_APP_ARG(str)[100];
00871    );
00872 #endif
00873 
00874    ast_verb(3, "%s config for repeater %s\n",
00875          (init) ? "Loading initial" : "Re-Loading", rpt_vars[n].name);
00876    ast_mutex_lock(&rpt_vars[n].lock);
00877    if (rpt_vars[n].cfg)
00878       ast_config_destroy(rpt_vars[n].cfg);
00879    cfg = ast_config_load("rpt.conf", config_flags);
00880    if (!cfg) {
00881       ast_mutex_unlock(&rpt_vars[n].lock);
00882       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
00883       pthread_exit(NULL);
00884    }
00885    rpt_vars[n].cfg = cfg;
00886    /* Free previously malloc'ed buffer */
00887    if (!init && rpt_vars[n].p.tailmsgbuf)
00888       ast_free(rpt_vars[n].p.tailmsgbuf);
00889    memset(&rpt_vars[n].p, 0, sizeof(rpt_vars[n].p));
00890    if (init) {
00891       /* clear all the fields in the structure after 'p' */
00892       memset(&rpt_vars[n].p + sizeof(rpt_vars[0].p), 0, sizeof(rpt_vars[0]) - sizeof(rpt_vars[0].p) - offsetof(typeof(rpt_vars[0]), p));
00893       rpt_vars[n].tele.next = &rpt_vars[n].tele;
00894       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
00895       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
00896       rpt_vars[n].tailmessagen = 0;
00897    }
00898 #ifdef   __RPT_NOTCH
00899    /* zot out filters stuff */
00900    memset(&rpt_vars[n].filters, 0, sizeof(rpt_vars[n].filters));
00901 #endif
00902 
00903    /* Defaults */
00904    ast_copy_string(rpt_vars[n].p.ourcontext, rpt_vars[n].name, sizeof(rpt_vars[n].p.ourcontext));
00905    rpt_vars[n].p.hangtime = HANGTIME;
00906    rpt_vars[n].p.totime = TOTIME;
00907    rpt_vars[n].p.duplex = 2;
00908    rpt_vars[n].p.idtime = IDTIME;
00909    rpt_vars[n].p.politeid = POLITEID;
00910    ast_copy_string(rpt_vars[n].p.memory, MEMORY, sizeof(rpt_vars[n].p.memory));
00911    ast_copy_string(rpt_vars[n].p.macro, MACRO, sizeof(rpt_vars[n].p.macro));
00912    ast_copy_string(rpt_vars[n].p.gosub, GOSUB, sizeof(rpt_vars[n].p.gosub));
00913    rpt_vars[n].p.iobase = DEFAULT_IOBASE;
00914    ast_copy_string(rpt_vars[n].p.functions, FUNCTIONS, sizeof(rpt_vars[n].p.functions));
00915    rpt_vars[n].p.simple = 1;
00916    rpt_vars[n].p.funcchar = FUNCCHAR;
00917    rpt_vars[n].p.endchar = ENDCHAR;
00918    ast_copy_string(rpt_vars[n].p.nodes, NODES, sizeof(rpt_vars[n].p.nodes));
00919 
00920    for (var = ast_variable_browse(cfg, rpt_vars[n].name); var; var = var->next) {
00921       if (!strcmp(var->name, "context")) {
00922          ast_copy_string(rpt_vars[n].p.ourcontext, var->value, sizeof(rpt_vars[n].p.ourcontext));
00923       } else if (!strcmp(var->name, "callerid")) {
00924          ast_copy_string(rpt_vars[n].p.ourcallerid, var->value, sizeof(rpt_vars[n].p.ourcallerid));
00925       } else if (!strcmp(var->name, "accountcode")) {
00926          ast_copy_string(rpt_vars[n].p.acctcode, var->value, sizeof(rpt_vars[n].p.acctcode));
00927       } else if (!strcmp(var->name, "idrecording")) {
00928          ast_copy_string(rpt_vars[n].p.ident, var->value, sizeof(rpt_vars[n].p.ident));
00929       } else if (!strcmp(var->name, "hangtime")) {
00930          rpt_vars[n].p.hangtime = atoi(var->value);
00931       } else if (!strcmp(var->name, "totime")) {
00932          rpt_vars[n].p.totime = atoi(var->value);
00933       } else if (!strcmp(var->name, "tailmessagetime")) {
00934          rpt_vars[n].p.tailmessagetime = atoi(var->value);
00935          if (rpt_vars[n].p.tailmessagetime < 0)
00936             rpt_vars[n].p.tailmessagetime = 0;
00937          else if (rpt_vars[n].p.tailmessagetime > 2400000)
00938             rpt_vars[n].p.tailmessagetime = 2400000;
00939       } else if (!strcmp(var->name, "tailsquashedtime")) {
00940          rpt_vars[n].p.tailsquashedtime = atoi(var->value);
00941          if (rpt_vars[n].p.tailsquashedtime < 0)
00942             rpt_vars[n].p.tailsquashedtime = 0;
00943          else if (rpt_vars[n].p.tailsquashedtime > 2400000)
00944             rpt_vars[n].p.tailsquashedtime = 2400000;
00945       } else if (!strcmp(var->name, "duplex")) {
00946          rpt_vars[n].p.duplex = atoi(var->value);
00947          if (rpt_vars[n].p.duplex < 0)
00948             rpt_vars[n].p.duplex = 0;
00949          else if (rpt_vars[n].p.duplex > 4)
00950             rpt_vars[n].p.duplex = 4;
00951       } else if (!strcmp(var->name, "idtime")) {
00952          rpt_vars[n].p.idtime = atoi(var->value);
00953          if (rpt_vars[n].p.idtime < 60000)
00954             rpt_vars[n].p.idtime = 60000;
00955          else if (rpt_vars[n].p.idtime > 2400000)
00956             rpt_vars[n].p.idtime = 2400000;
00957       } else if (!strcmp(var->name, "politeid")) {
00958          rpt_vars[n].p.politeid = atoi(var->value);
00959          if (rpt_vars[n].p.politeid < 30000)
00960             rpt_vars[n].p.politeid = 30000;
00961          else if (rpt_vars[n].p.politeid > 300000)
00962             rpt_vars[n].p.politeid = 300000;
00963       } else if (!strcmp(var->name, "tonezone")) {
00964          ast_copy_string(rpt_vars[n].p.tonezone, var->value, sizeof(rpt_vars[n].p.tonezone));
00965       } else if (!strcmp(var->name, "tailmessagelist")) {
00966          rpt_vars[n].p.tailmsgbuf = ast_strdup(var->value);
00967          AST_STANDARD_APP_ARGS(rpt_vars[n].p.tailmsg, rpt_vars[n].p.tailmsgbuf);
00968       } else if (!strcmp(var->name, "memory")) {
00969          ast_copy_string(rpt_vars[n].p.memory, var->value, sizeof(rpt_vars[n].p.memory));
00970       } else if (!strcmp(var->name, "macro")) {
00971          ast_copy_string(rpt_vars[n].p.macro, var->value, sizeof(rpt_vars[n].p.macro));
00972       } else if (!strcmp(var->name, "gosub")) {
00973          ast_copy_string(rpt_vars[n].p.gosub, var->value, sizeof(rpt_vars[n].p.gosub));
00974       } else if (!strcmp(var->name, "startup_macro")) {
00975          ast_copy_string(rpt_vars[n].p.startupmacro, var->value, sizeof(rpt_vars[n].p.startupmacro));
00976       } else if (!strcmp(var->name, "startup_gosub")) {
00977          ast_copy_string(rpt_vars[n].p.startupgosub, var->value, sizeof(rpt_vars[n].p.startupgosub));
00978       } else if (!strcmp(var->name, "iobase")) {
00979          /* do not use atoi() here, we need to be able to have
00980             the input specified in hex or decimal so we use
00981             sscanf with a %i */
00982          if (sscanf(var->value, "%i", &rpt_vars[n].p.iobase) != 1)
00983             rpt_vars[n].p.iobase = DEFAULT_IOBASE;
00984       } else if (!strcmp(var->name, "functions")) {
00985          rpt_vars[n].p.simple = 0;
00986          ast_copy_string(rpt_vars[n].p.functions, var->value, sizeof(rpt_vars[n].p.functions));
00987       } else if (!strcmp(var->name, "link_functions")) {
00988          ast_copy_string(rpt_vars[n].p.link_functions, var->value, sizeof(rpt_vars[n].p.link_functions));
00989       } else if (!strcmp(var->name, "phone_functions")) {
00990          ast_copy_string(rpt_vars[n].p.phone_functions, var->value, sizeof(rpt_vars[n].p.phone_functions));
00991       } else if (!strcmp(var->name, "dphone_functions")) {
00992          ast_copy_string(rpt_vars[n].p.dphone_functions, var->value, sizeof(rpt_vars[n].p.dphone_functions));
00993       } else if (!strcmp(var->name, "funcchar")) {
00994          rpt_vars[n].p.funcchar = *var->value;
00995       } else if (!strcmp(var->name, "endchar")) {
00996          rpt_vars[n].p.endchar = *var->value;
00997       } else if (!strcmp(var->name, "nobusyout")) {
00998          rpt_vars[n].p.nobusyout = ast_true(var->value);
00999       } else if (!strcmp(var->name, "nodes")) {
01000          ast_copy_string(rpt_vars[n].p.nodes, var->value, sizeof(rpt_vars[n].p.nodes));
01001 #ifdef   __RPT_NOTCH
01002       } else if (!strcmp(var->name, "rxnotch")) {
01003          char *tmp = ast_strdupa(val);
01004          AST_STANDARD_APP_ARGS(strs, tmp);
01005          strs.argc &= ~1; /* force an even number, rounded down */
01006          if (strs.argc >= 2) {
01007             for (j = 0; j < strs.argc; j += 2) {
01008                rpt_mknotch(atof(strs.str[j]), atof(strs.str[j + 1]),
01009                   &rpt_vars[n].filters[j >> 1].gain,
01010                   &rpt_vars[n].filters[j >> 1].const0,
01011                   &rpt_vars[n].filters[j >> 1].const1,
01012                   &rpt_vars[n].filters[j >> 1].const2);
01013                sprintf(rpt_vars[n].filters[j >> 1].desc, "%s Hz, BW = %s",
01014                   strs.str[j], strs.str[j + 1]);
01015             }
01016          }
01017 #endif
01018       }
01019    }
01020 
01021    /* If these aren't specified, copy them from the functions property. */
01022    if (ast_strlen_zero(rpt_vars[n].p.link_functions))
01023       ast_copy_string(rpt_vars[n].p.link_functions, rpt_vars[n].p.functions, sizeof(rpt_vars[n].p.link_functions));
01024 
01025    rpt_vars[n].longestnode = 0;
01026    for (vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes); vp; vp = vp->next) {
01027       if ((j = strlen(vp->name)) > rpt_vars[n].longestnode)
01028          rpt_vars[n].longestnode = j;
01029    }
01030 
01031    /*
01032    * For this repeater, Determine the length of the longest function 
01033    */
01034    rpt_vars[n].longestfunc = 0;
01035    for (vp = ast_variable_browse(cfg, rpt_vars[n].p.functions); vp; vp = vp->next) {
01036       if ((j = strlen(vp->name)) > rpt_vars[n].longestfunc)
01037          rpt_vars[n].longestfunc = j;
01038    }
01039 
01040    rpt_vars[n].link_longestfunc = 0;
01041    for (vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions); vp; vp = vp->next) {
01042       if ((j = strlen(vp->name)) > rpt_vars[n].link_longestfunc)
01043          rpt_vars[n].link_longestfunc = j;
01044    }
01045 
01046    rpt_vars[n].phone_longestfunc = 0;
01047    for (vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions); vp; vp = vp->next) {
01048       if ((j = strlen(vp->name)) > rpt_vars[n].phone_longestfunc)
01049          rpt_vars[n].phone_longestfunc = j;
01050    }
01051 
01052    rpt_vars[n].dphone_longestfunc = 0;
01053    for (vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions); vp; vp = vp->next) {
01054       if ((j = strlen(vp->name)) > rpt_vars[n].dphone_longestfunc)
01055          rpt_vars[n].dphone_longestfunc = j;
01056    }
01057 
01058    rpt_vars[n].macro_longest = 1;
01059    for (vp = ast_variable_browse(cfg, rpt_vars[n].p.macro); vp; vp = vp->next) {
01060       if ((j = strlen(vp->name)) > rpt_vars[n].macro_longest)
01061          rpt_vars[n].macro_longest = j;
01062    }
01063 
01064    rpt_vars[n].gosub_longest = 1;
01065    for (vp = ast_variable_browse(cfg, rpt_vars[n].p.gosub); vp; vp = vp->next) {
01066       if ((j = strlen(vp->name)) > rpt_vars[n].gosub_longest)
01067          rpt_vars[n].gosub_longest = j;
01068    }
01069    ast_mutex_unlock(&rpt_vars[n].lock);
01070 }

static void local_dtmf_helper ( struct rpt myrpt,
char  c 
) [static]

Definition at line 5489 of file app_rpt.c.

References ast_canmatch_extension(), ast_copy_string(), ast_exists_extension(), ast_pthread_create_detached, rpt::callmode, rpt::cidx, rpt::cmdnode, collect_function_digits(), COMPLETE, rpt::dailyexecdcommands, DC_COMPLETE, DC_ERROR, DC_INDETERMINATE, DC_REQ_FLUSH, rpt::dtmf_time, rpt::dtmfbuf, rpt::dtmfidx, rpt::endchar, rpt::exten, rpt::funcchar, rpt::lastdtmfcommand, rpt::lock, MAXDTMF, rpt::mydtmf, rpt::ourcontext, rpt::p, rpt::patchcontext, rpt::patchdialtime, rpt::patchfarenddisconnect, rpt::patchnoct, rpt::patchquiet, rpt::pchannel, PROC, rpt_call(), rpt::rpt_call_thread, rpt_mutex_lock, rpt_mutex_unlock, rpt_telemetry(), send_link_dtmf(), rpt::simple, SOURCE_RPT, rpt::stopgen, TERM, and rpt::totalexecdcommands.

Referenced by rpt().

05490 {
05491    int   res;
05492    char cmd[MAXDTMF+1] = "";
05493 
05494    if (c == myrpt->p.endchar) {
05495    /* if in simple mode, kill autopatch */
05496       if (myrpt->p.simple && myrpt->callmode) {
05497          rpt_mutex_lock(&myrpt->lock);
05498          myrpt->callmode = 0;
05499          rpt_mutex_unlock(&myrpt->lock);
05500          rpt_telemetry(myrpt, TERM, NULL);
05501          return;
05502       }
05503       rpt_mutex_lock(&myrpt->lock);
05504       myrpt->stopgen = 1;
05505       if (myrpt->cmdnode[0]) {
05506          myrpt->cmdnode[0] = 0;
05507          myrpt->dtmfidx = -1;
05508          myrpt->dtmfbuf[0] = 0;
05509          rpt_mutex_unlock(&myrpt->lock);
05510          rpt_telemetry(myrpt, COMPLETE, NULL);
05511       } else
05512          rpt_mutex_unlock(&myrpt->lock);
05513       return;
05514    }
05515    rpt_mutex_lock(&myrpt->lock);
05516    if (myrpt->cmdnode[0]) {
05517       rpt_mutex_unlock(&myrpt->lock);
05518       send_link_dtmf(myrpt, c);
05519       return;
05520    }
05521    if (!myrpt->p.simple) {
05522       if (c == myrpt->p.funcchar) {
05523          myrpt->dtmfidx = 0;
05524          myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
05525          rpt_mutex_unlock(&myrpt->lock);
05526          time(&myrpt->dtmf_time);
05527          return;
05528       } else if ((c != myrpt->p.endchar) && (myrpt->dtmfidx >= 0)) {
05529          time(&myrpt->dtmf_time);
05530 
05531          if (myrpt->dtmfidx < MAXDTMF) {
05532             myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
05533             myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
05534 
05535             ast_copy_string(cmd, myrpt->dtmfbuf, sizeof(cmd));
05536 
05537             rpt_mutex_unlock(&myrpt->lock);
05538             res = collect_function_digits(myrpt, cmd, SOURCE_RPT, NULL);
05539             rpt_mutex_lock(&myrpt->lock);
05540             switch(res) {
05541             case DC_INDETERMINATE:
05542                break;
05543             case DC_REQ_FLUSH:
05544                myrpt->dtmfidx = 0;
05545                myrpt->dtmfbuf[0] = 0;
05546                break;
05547             case DC_COMPLETE:
05548                myrpt->totalexecdcommands++;
05549                myrpt->dailyexecdcommands++;
05550                ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF);
05551                myrpt->dtmfbuf[0] = 0;
05552                myrpt->dtmfidx = -1;
05553                myrpt->dtmf_time = 0;
05554                break;
05555 
05556             case DC_ERROR:
05557             default:
05558                myrpt->dtmfbuf[0] = 0;
05559                myrpt->dtmfidx = -1;
05560                myrpt->dtmf_time = 0;
05561                break;
05562             }
05563             if (res != DC_INDETERMINATE) {
05564                rpt_mutex_unlock(&myrpt->lock);
05565                return;
05566             }
05567          } 
05568       }
05569    } else /* if simple */ {
05570       if ((!myrpt->callmode) && (c == myrpt->p.funcchar)) {
05571          myrpt->callmode = 1;
05572          myrpt->patchnoct = 0;
05573          myrpt->patchquiet = 0;
05574          myrpt->patchfarenddisconnect = 0;
05575          myrpt->patchdialtime = 0;
05576          ast_copy_string(myrpt->patchcontext, myrpt->p.ourcontext, sizeof(myrpt->patchcontext));
05577          myrpt->cidx = 0;
05578          myrpt->exten[myrpt->cidx] = 0;
05579          rpt_mutex_unlock(&myrpt->lock);
05580          ast_pthread_create_detached(&myrpt->rpt_call_thread, NULL, rpt_call, (void *)myrpt);
05581          return;
05582       }
05583    }
05584    if (myrpt->callmode == 1) {
05585       myrpt->exten[myrpt->cidx++] = c;
05586       myrpt->exten[myrpt->cidx] = 0;
05587       /* if this exists */
05588       if (ast_exists_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
05589          myrpt->callmode = 2;
05590          rpt_mutex_unlock(&myrpt->lock);
05591          if (!myrpt->patchquiet)
05592             rpt_telemetry(myrpt, PROC, NULL); 
05593          return;
05594       }
05595       /* if can continue, do so */
05596       if (!ast_canmatch_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
05597          /* call has failed, inform user */
05598          myrpt->callmode = 4;
05599       }
05600       rpt_mutex_unlock(&myrpt->lock);
05601       return;
05602    }
05603    if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) {
05604       myrpt->mydtmf = c;
05605    }
05606    rpt_mutex_unlock(&myrpt->lock);
05607    return;
05608 }

static int matchkeyword ( char *  string,
char **  param,
char *  keywords[] 
) [static]

Definition at line 764 of file app_rpt.c.

Referenced by function_autopatchup().

00765 {
00766    int   i, ls;
00767    for (i = 0; keywords[i]; i++) {
00768       ls = strlen(keywords[i]);
00769       if (!ls) {
00770          *param = NULL;
00771          return 0;
00772       }
00773       if (!strncmp(string, keywords[i], ls)) {
00774          if (param)
00775             *param = string + ls;
00776          return i + 1; 
00777       }
00778    }
00779    param = NULL;
00780    return 0;
00781 }

static int multimode_bump_freq ( struct rpt myrpt,
int  interval 
) [static]

Definition at line 4484 of file app_rpt.c.

References multimode_bump_freq_ft897(), and rpt::remote.

Referenced by function_remote(), and service_scan().

04485 {
04486    if (!strcmp(myrpt->remote, remote_rig_ft897))
04487       return multimode_bump_freq_ft897(myrpt, interval);
04488    else
04489       return -1;
04490 }

static int multimode_bump_freq_ft897 ( struct rpt myrpt,
int  interval 
) [static]

Definition at line 4400 of file app_rpt.c.

References ast_debug, check_freq_ft897(), rpt::freq, MAXREMSTR, set_freq_ft897(), and split_freq.

Referenced by multimode_bump_freq().

04401 {
04402    int m, d;
04403 
04404    ast_debug(1, "Before bump: %s\n", myrpt->freq);
04405 
04406    if (split_freq(&m, &d, myrpt->freq))
04407       return -1;
04408    
04409    d += (interval / 10); /* 10Hz resolution */
04410    if (d < 0) {
04411       m--;
04412       d += 100000;
04413    } else if (d >= 100000) {
04414       m++;
04415       d -= 100000;
04416    }
04417 
04418    if (check_freq_ft897(m, d, NULL)) {
04419       ast_debug(1, "Bump freq invalid\n");
04420       return -1;
04421    }
04422 
04423    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
04424    ast_debug(1, "After bump: %s\n", myrpt->freq);
04425 
04426    return set_freq_ft897(myrpt, myrpt->freq);   
04427 }

static int multimode_capable ( struct rpt myrpt  )  [static]

Definition at line 4473 of file app_rpt.c.

References rpt::remote.

Referenced by function_remote().

04474 {
04475    if (!strcmp(myrpt->remote, remote_rig_ft897))
04476       return 1;
04477    return 0;
04478 }  

static int myatoi ( const char *  str  )  [static]

Definition at line 806 of file app_rpt.c.

Referenced by function_cop(), function_ilink(), function_remote(), function_status(), handle_cli_rpt_debug_level(), and retrieve_astcfgint().

00807 {
00808    int   ret;
00809 
00810    if (str == NULL)
00811       return -1;
00812    /* leave this %i alone, non-base-10 input is useful here */
00813    if (sscanf(str, "%i", &ret) != 1)
00814       return -1;
00815    return ret;
00816 }

static int play_silence ( struct ast_channel chan,
int  duration 
) [static]

Definition at line 1488 of file app_rpt.c.

References chan, and play_tone_pair().

Referenced by send_morse().

01489 {
01490    return play_tone_pair(chan, 0, 0, duration, 0);
01491 }

static int play_tone ( struct ast_channel chan,
int  freq,
int  duration,
int  amplitude 
) [static]

Definition at line 1483 of file app_rpt.c.

References chan, and play_tone_pair().

Referenced by send_morse().

01484 {
01485    return play_tone_pair(chan, freq, 0, duration, amplitude);
01486 }

static int play_tone_pair ( struct ast_channel chan,
int  f1,
int  f2,
int  duration,
int  amplitude 
) [static]

Definition at line 1468 of file app_rpt.c.

References ast_safe_sleep(), ast_tonepair_start(), chan, and ast_channel::generatordata.

Referenced by play_silence(), play_tone(), and send_tone_telemetry().

01469 {
01470    int res;
01471 
01472    if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
01473       return res;
01474 
01475    while (chan->generatordata) {
01476       if (ast_safe_sleep(chan, 1))
01477          return -1;
01478    }
01479 
01480    return 0;
01481 }

static void queue_id ( struct rpt myrpt  )  [static]

Definition at line 5613 of file app_rpt.c.

References ID, rpt::idtime, rpt::idtimer, rpt::lock, rpt::mustid, rpt::p, rpt_mutex_lock, rpt_mutex_unlock, rpt_telemetry(), and rpt::tailid.

Referenced by rpt().

05614 {
05615    myrpt->mustid = myrpt->tailid = 0;
05616    myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
05617    rpt_mutex_unlock(&myrpt->lock);
05618    rpt_telemetry(myrpt, ID, NULL);
05619    rpt_mutex_lock(&myrpt->lock);
05620 }

static int rbi_mhztoband ( char *  str  )  [static]

Definition at line 3776 of file app_rpt.c.

Referenced by setrbi().

03777 {
03778    int   i;
03779 
03780    i = atoi(str) / 10; /* get the 10's of mhz */
03781    switch (i) {
03782    case 2:
03783       return 10;
03784    case 5:
03785       return 11;
03786    case 14:
03787       return 2;
03788    case 22:
03789       return 3;
03790    case 44:
03791       return 4;
03792    case 124:
03793       return 0;
03794    case 125:
03795       return 1;
03796    case 126:
03797       return 8;
03798    case 127:
03799       return 5;
03800    case 128:
03801       return 6;
03802    case 129:
03803       return 7;
03804    default:
03805       break;
03806    }
03807    return -1;
03808 }

static void rbi_out ( struct rpt myrpt,
unsigned char *  data 
) [static]

Definition at line 3928 of file app_rpt.c.

References ast_log(), ast_channel::fds, LOG_WARNING, ast_channel::name, rbi_out_parallel(), and rpt::rxchannel.

Referenced by setrbi().

03929 {
03930    struct dahdi_radio_param r = { 0, };
03931 
03932    r.radpar = DAHDI_RADPAR_REMMODE;
03933    r.data = DAHDI_RADPAR_REM_RBI1;
03934    /* if setparam ioctl fails, its probably not a pciradio card */
03935    if (ioctl(myrpt->rxchannel->fds[0], DAHDI_RADIO_SETPARAM, &r) == -1) {
03936       rbi_out_parallel(myrpt, data);
03937       return;
03938    }
03939    r.radpar = DAHDI_RADPAR_REMCOMMAND;
03940    memcpy(&r.data, data, 5);
03941    if (ioctl(myrpt->rxchannel->fds[0], DAHDI_RADIO_SETPARAM, &r) == -1) {
03942       ast_log(LOG_WARNING, "Cannot send RBI command for channel %s\n", myrpt->rxchannel->name);
03943       return;
03944    }
03945 }

static void rbi_out_parallel ( struct rpt myrpt,
unsigned char *  data 
) [static]

Definition at line 3906 of file app_rpt.c.

References rpt::iobase, and rpt::p.

Referenced by rbi_out().

03907 {
03908    int i, j;
03909    unsigned char od, d;
03910 
03911    for (i = 0; i < 5; i++) {
03912       od = *data++; 
03913       for (j = 0; j < 8; j++) {
03914          d = od & 1;
03915          outb(d, myrpt->p.iobase);
03916          usleep(15);
03917          od >>= 1;
03918          outb(d | 2, myrpt->p.iobase);
03919          usleep(30);
03920          outb(d, myrpt->p.iobase);
03921          usleep(10);
03922       }
03923    }
03924    /* >= 50 us */
03925    usleep(50);
03926 }

static int rbi_pltocode ( char *  str  )  [static]

Definition at line 3811 of file app_rpt.c.

References s.

Referenced by setrbi().

03812 {
03813    int i;
03814    char *s;
03815 
03816    s = strchr(str, '.');
03817    i = 0;
03818    if (s)
03819       i = atoi(s + 1);
03820    i += atoi(str) * 10;
03821    switch(i) {
03822    case 670:
03823       return 0;
03824    case 719:
03825       return 1;
03826    case 744:
03827       return 2;
03828    case 770:
03829       return 3;
03830    case 797:
03831       return 4;
03832    case 825:
03833       return 5;
03834    case 854:
03835       return 6;
03836    case 885:
03837       return 7;
03838    case 915:
03839       return 8;
03840    case 948:
03841       return 9;
03842    case 974:
03843       return 10;
03844    case 1000:
03845       return 11;
03846    case 1035:
03847       return 12;
03848    case 1072:
03849       return 13;
03850    case 1109:
03851       return 14;
03852    case 1148:
03853       return 15;
03854    case 1188:
03855       return 16;
03856    case 1230:
03857       return 17;
03858    case 1273:
03859       return 18;
03860    case 1318:
03861       return 19;
03862    case 1365:
03863       return 20;
03864    case 1413:
03865       return 21;
03866    case 1462:
03867       return 22;
03868    case 1514:
03869       return 23;
03870    case 1567:
03871       return 24;
03872    case 1622:
03873       return 25;
03874    case 1679:
03875       return 26;
03876    case 1738:
03877       return 27;
03878    case 1799:
03879       return 28;
03880    case 1862:
03881       return 29;
03882    case 1928:
03883       return 30;
03884    case 2035:
03885       return 31;
03886    case 2107:
03887       return 32;
03888    case 2181:
03889       return 33;
03890    case 2257:
03891       return 34;
03892    case 2336:
03893       return 35;
03894    case 2418:
03895       return 36;
03896    case 2503:
03897       return 37;
03898    }
03899    return -1;
03900 }

static int reload ( void   )  [static]

Definition at line 7465 of file app_rpt.c.

References reload, and rpt_vars.

07466 {
07467    int n;
07468 
07469    for (n = 0; n < nrpts; n++)
07470       rpt_vars[n].reload = 1;
07471    return(0);
07472 }

static int retrieve_astcfgint ( struct rpt myrpt,
const char *  category,
const char *  name,
int  min,
int  max,
int  defl 
) [static]

Definition at line 845 of file app_rpt.c.

References ast_variable_retrieve(), rpt::cfg, myatoi(), and var.

Referenced by get_wait_interval(), and telem_any().

00846 {
00847    const char *var = ast_variable_retrieve(myrpt->cfg, category, name);
00848    int ret;
00849 
00850    if (var) {
00851       ret = myatoi(var);
00852       if (ret < min)
00853          ret = min;
00854       else if (ret > max)
00855          ret = max;
00856    } else
00857       ret = defl;
00858    return ret;
00859 }

static int rmt_saycharstr ( struct rpt myrpt,
struct ast_channel chan,
int  delay,
char *  charstr 
) [static]

Definition at line 4614 of file app_rpt.c.

References chan, rmt_telem_finish(), rmt_telem_start(), and saycharstr().

Referenced by function_remote().

04615 {
04616    int res;
04617 
04618    res = rmt_telem_start(myrpt, chan, delay);
04619 
04620    if (!res)
04621       res = saycharstr(chan, charstr);
04622    
04623    if (!res)
04624       res = rmt_telem_finish(myrpt, chan);
04625    return res;
04626 }

static int rmt_sayfile ( struct rpt myrpt,
struct ast_channel chan,
int  delay,
char *  filename 
) [static]

Definition at line 4600 of file app_rpt.c.

References chan, rmt_telem_finish(), rmt_telem_start(), and sayfile().

Referenced by function_remote().

04601 {
04602    int res;
04603 
04604    res = rmt_telem_start(myrpt, chan, delay);
04605 
04606    if (!res)
04607       res = sayfile(chan, filename);
04608    
04609    if (!res)
04610       res = rmt_telem_finish(myrpt, chan);
04611    return res;
04612 }

static int rmt_telem_finish ( struct rpt myrpt,
struct ast_channel chan 
) [static]

Definition at line 4582 of file app_rpt.c.

References AST_CONTROL_RADIO_UNKEY, ast_indicate(), ast_channel::fds, rpt::remchannel, rpt::remoterx, and rpt::txchannel.

Referenced by function_remote(), handle_remote_data(), handle_remote_phone_dtmf(), rmt_saycharstr(), and rmt_sayfile().

04583 {
04584    struct dahdi_params par;
04585 
04586    if (ioctl(myrpt->txchannel->fds[0], DAHDI_GET_PARAMS, &par) == -1) {
04587       return -1;
04588 
04589    }
04590    if (!par.rxisoffhook) {
04591       ast_indicate(myrpt->remchannel, AST_CONTROL_RADIO_UNKEY);
04592       myrpt->remoterx = 0;
04593    } else {
04594       myrpt->remoterx = 1;
04595    }
04596    return 0;
04597 }

static int rmt_telem_start ( struct rpt myrpt,
struct ast_channel chan,
int  delay 
) [static]

Definition at line 4570 of file app_rpt.c.

References AST_CONTROL_RADIO_KEY, AST_CONTROL_RADIO_UNKEY, ast_indicate(), ast_safe_sleep(), chan, rpt::remoterx, rpt::remotetx, and rpt::txchannel.

Referenced by function_remote(), rmt_saycharstr(), and rmt_sayfile().

04571 {
04572    myrpt->remotetx = 0;
04573    ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
04574    if (!myrpt->remoterx)
04575       ast_indicate(chan, AST_CONTROL_RADIO_KEY);
04576    if (ast_safe_sleep(chan, delay) == -1)
04577          return -1;
04578    return 0;
04579 }

static void* rpt ( void *  this  )  [static]

Definition at line 5653 of file app_rpt.c.

References ast_channel::_state, ast_channel::appl, ast_call(), ast_channel_setoption(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_HANGUP, AST_CONTROL_RADIO_KEY, AST_CONTROL_RADIO_UNKEY, ast_copy_string(), ast_debug, AST_FORMAT_SLINEAR, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, AST_FRAME_VOICE, ast_free, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), AST_OPTION_RELAXDTMF, AST_OPTION_TONE_VERIFY, AST_PTHREADT_STOP, ast_read(), ast_request(), ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_DEV, AST_STATE_BUSY, AST_STATE_UP, ast_variable_retrieve(), ast_verb, ast_waitfor_n(), ast_write(), attempt_reconnect(), rpt::callmode, rpt::cfg, rpt_link::chan, rpt_tele::chan, rpt::cmdnode, rpt::conf, CONNECTED, rpt_link::connected, rpt_link::connecttime, CONNFAIL, rpt::dailyexecdcommands, rpt::dailykerchunks, rpt::dailykeyups, rpt::dailytxtime, ast_channel::data, DISC_TIME, rpt_link::disced, rpt_link::disctime, rpt::disgorgetime, do_scheduler(), rpt::dtmf_time, DTMF_TIMEOUT, rpt::dtmfbuf, rpt::dtmfidx, rpt::duplex, rpt_link::elaptime, rpt::enable, rpt::exten, rpt::exttx, f, ast_channel::fds, rpt::gosubbuf, GOSUBPTIME, GOSUBTIME, rpt::gosubtimer, handle_link_data(), handle_link_phone_dtmf(), rpt::hangtime, rpt_link::hasconnected, ID, IDTALKOVER, rpt::idtimer, rpt_link::isremote, rpt::keyed, rpt_link::killme, rpt::lastdtmfcommand, rpt::lastnodewhichkeyedusup, rpt_link::lastrx, rpt_link::lasttx, rpt::links, load_rpt_vars(), local_dtmf_helper(), rpt::localtx, rpt::lock, LOG_ERROR, LOG_NOTICE, LOG_WARNING, rpt::macrobuf, MACROPTIME, MACROTIME, rpt::macrotimer, MAX_RETRIES, MAXCONNECTTIME, rpt_link::mode, rpt_tele::mode, MSWAIT, rpt::mustid, rpt_link::name, rpt::name, ast_channel::name, rpt_link::next, rpt_tele::next, rpt_link::outbound, rpt::p, rpt_link::pchan, rpt::pchannel, rpt::politeid, rpt_link::prev, queue_id(), rpt_link::reconnects, REDUNDANT_TX_TIME, rpt::reload, rpt::rem_dtmf_time, rpt::rem_dtmfbuf, rpt::rem_dtmfidx, REMDISC, rpt_link::retries, RETRY_TIMER_MS, rpt_link::retrytimer, rpt_link::retxtimer, rpt::retxtimer, rpt_mutex_lock, rpt_mutex_unlock, rpt_telemetry(), rpt::rpt_thread, rpt_vars, rpt::rxchanname, rpt::rxchannel, rpt::skedtimer, rpt::startupgosub, rpt::startupmacro, rpt::tailevent, rpt::tailid, rpt::tailmessagetime, rpt::tailmsg, TAILMSG, rpt::tailtimer, rpt::tele, TIMEOUT, rpt::timeouts, rpt::tmsgtimer, rpt::tonotify, rpt::totalexecdcommands, rpt::totalkerchunks, rpt::totalkeyups, rpt::totaltxtime, rpt::totime, rpt::totimer, rpt::tounkeyed, rpt::txchanname, rpt::txchannel, rpt::txconf, rpt::txpchannel, UNKEY, and ast_channel::whentohangup.

05654 {
05655    struct rpt *myrpt = (struct rpt *)this;
05656    char *tele, c;
05657    const char *idtalkover;
05658    int ms = MSWAIT, i, lasttx=0, val, remrx=0, identqueued, othertelemqueued, tailmessagequeued, ctqueued;
05659    struct ast_channel *who;
05660    struct dahdi_confinfo ci;  /* conference info */
05661    time_t t;
05662    struct rpt_link *l, *m;
05663    struct rpt_tele *telem;
05664    char tmpstr[300];
05665 
05666    rpt_mutex_lock(&myrpt->lock);
05667 
05668    telem = myrpt->tele.next;
05669    while (telem != &myrpt->tele) {
05670       ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV);
05671       telem = telem->next;
05672    }
05673    rpt_mutex_unlock(&myrpt->lock);
05674    /* find our index, and load the vars initially */
05675    for (i = 0; i < nrpts; i++) {
05676       if (&rpt_vars[i] == myrpt) {
05677          load_rpt_vars(i, 0);
05678          break;
05679       }
05680    }
05681    rpt_mutex_lock(&myrpt->lock);
05682    ast_copy_string(tmpstr, myrpt->rxchanname, sizeof(tmpstr));
05683    tele = strchr(tmpstr, '/');
05684    if (!tele) {
05685       ast_log(LOG_ERROR, "rpt:Rxchannel Dial number (%s) must be in format tech/number\n", myrpt->rxchanname);
05686       rpt_mutex_unlock(&myrpt->lock);
05687       myrpt->rpt_thread = AST_PTHREADT_STOP;
05688       pthread_exit(NULL);
05689    }
05690    *tele++ = 0;
05691    myrpt->rxchannel = ast_request(tmpstr, AST_FORMAT_SLINEAR, tele, NULL);
05692    if (myrpt->rxchannel) {
05693       if (myrpt->rxchannel->_state == AST_STATE_BUSY) {
05694          ast_log(LOG_ERROR, "rpt:Sorry unable to obtain Rx channel\n");
05695          rpt_mutex_unlock(&myrpt->lock);
05696          ast_hangup(myrpt->rxchannel);
05697          myrpt->rpt_thread = AST_PTHREADT_STOP;
05698          pthread_exit(NULL);
05699       }
05700       ast_set_read_format(myrpt->rxchannel, AST_FORMAT_SLINEAR);
05701       ast_set_write_format(myrpt->rxchannel, AST_FORMAT_SLINEAR);
05702       myrpt->rxchannel->whentohangup = 0;
05703       myrpt->rxchannel->appl = "Apprpt";
05704       myrpt->rxchannel->data = "(Repeater Rx)";
05705       ast_verb(3, "rpt (Rx) initiating call to %s/%s on %s\n",
05706             tmpstr, tele, myrpt->rxchannel->name);
05707       ast_call(myrpt->rxchannel, tele, 999);
05708       if (myrpt->rxchannel->_state != AST_STATE_UP) {
05709          rpt_mutex_unlock(&myrpt->lock);
05710          ast_hangup(myrpt->rxchannel);
05711          myrpt->rpt_thread = AST_PTHREADT_STOP;
05712          pthread_exit(NULL);
05713       }
05714    } else {
05715       ast_log(LOG_ERROR, "rpt:Sorry unable to obtain Rx channel\n");
05716       rpt_mutex_unlock(&myrpt->lock);
05717       myrpt->rpt_thread = AST_PTHREADT_STOP;
05718       pthread_exit(NULL);
05719    }
05720    if (myrpt->txchanname) {
05721       ast_copy_string(tmpstr, myrpt->txchanname, sizeof(tmpstr));
05722       tele = strchr(tmpstr, '/');
05723       if (!tele) {
05724          ast_log(LOG_ERROR, "rpt:Txchannel Dial number (%s) must be in format tech/number\n", myrpt->txchanname);
05725          rpt_mutex_unlock(&myrpt->lock);
05726          ast_hangup(myrpt->rxchannel);
05727          myrpt->rpt_thread = AST_PTHREADT_STOP;
05728          pthread_exit(NULL);
05729       }
05730       *tele++ = 0;
05731       myrpt->txchannel = ast_request(tmpstr, AST_FORMAT_SLINEAR, tele, NULL);
05732       if (myrpt->txchannel) {
05733          if (myrpt->txchannel->_state == AST_STATE_BUSY) {
05734             ast_log(LOG_ERROR, "rpt:Sorry unable to obtain Tx channel\n");
05735             rpt_mutex_unlock(&myrpt->lock);
05736             ast_hangup(myrpt->txchannel);
05737             ast_hangup(myrpt->rxchannel);
05738             myrpt->rpt_thread = AST_PTHREADT_STOP;
05739             pthread_exit(NULL);
05740          }        
05741          ast_set_read_format(myrpt->txchannel, AST_FORMAT_SLINEAR);
05742          ast_set_write_format(myrpt->txchannel, AST_FORMAT_SLINEAR);
05743          myrpt->txchannel->whentohangup = 0;
05744          myrpt->txchannel->appl = "Apprpt";
05745          myrpt->txchannel->data = "(Repeater Tx)";
05746          ast_verb(3, "rpt (Tx) initiating call to %s/%s on %s\n",
05747                tmpstr, tele, myrpt->txchannel->name);
05748          ast_call(myrpt->txchannel, tele, 999);
05749          if (myrpt->rxchannel->_state != AST_STATE_UP) {
05750             rpt_mutex_unlock(&myrpt->lock);
05751             ast_hangup(myrpt->rxchannel);
05752             ast_hangup(myrpt->txchannel);
05753             myrpt->rpt_thread = AST_PTHREADT_STOP;
05754             pthread_exit(NULL);
05755          }
05756       } else {
05757          ast_log(LOG_ERROR, "rpt:Sorry unable to obtain Tx channel\n");
05758          rpt_mutex_unlock(&myrpt->lock);
05759          ast_hangup(myrpt->rxchannel);
05760          myrpt->rpt_thread = AST_PTHREADT_STOP;
05761          pthread_exit(NULL);
05762       }
05763    } else {
05764       myrpt->txchannel = myrpt->rxchannel;
05765    }
05766    ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_KEY);
05767    ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
05768    /* allocate a pseudo-channel thru asterisk */
05769    myrpt->pchannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
05770    if (!myrpt->pchannel) {
05771       ast_log(LOG_ERROR, "rpt:Sorry unable to obtain pseudo channel\n");
05772       rpt_mutex_unlock(&myrpt->lock);
05773       if (myrpt->txchannel != myrpt->rxchannel) 
05774          ast_hangup(myrpt->txchannel);
05775       ast_hangup(myrpt->rxchannel);
05776       myrpt->rpt_thread = AST_PTHREADT_STOP;
05777       pthread_exit(NULL);
05778    }
05779    /* make a conference for the tx */
05780    ci.chan = 0;
05781    ci.confno = -1; /* make a new conf */
05782    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER;
05783    /* first put the channel on the conference in proper mode */
05784    if (ioctl(myrpt->txchannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
05785       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05786       rpt_mutex_unlock(&myrpt->lock);
05787       ast_hangup(myrpt->pchannel);
05788       if (myrpt->txchannel != myrpt->rxchannel) 
05789          ast_hangup(myrpt->txchannel);
05790       ast_hangup(myrpt->rxchannel);
05791       myrpt->rpt_thread = AST_PTHREADT_STOP;
05792       pthread_exit(NULL);
05793    }
05794    /* save tx conference number */
05795    myrpt->txconf = ci.confno;
05796    /* make a conference for the pseudo */
05797    ci.chan = 0;
05798    ci.confno = -1; /* make a new conf */
05799    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
05800       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
05801    /* first put the channel on the conference in announce mode */
05802    if (ioctl(myrpt->pchannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
05803       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05804       rpt_mutex_unlock(&myrpt->lock);
05805       ast_hangup(myrpt->pchannel);
05806       if (myrpt->txchannel != myrpt->rxchannel) 
05807          ast_hangup(myrpt->txchannel);
05808       ast_hangup(myrpt->rxchannel);
05809       myrpt->rpt_thread = AST_PTHREADT_STOP;
05810       pthread_exit(NULL);
05811    }
05812    /* save pseudo channel conference number */
05813    myrpt->conf = ci.confno;
05814    /* allocate a pseudo-channel thru asterisk */
05815    myrpt->txpchannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
05816    if (!myrpt->txpchannel) {
05817       ast_log(LOG_ERROR, "rpt:Sorry unable to obtain pseudo channel\n");
05818       rpt_mutex_unlock(&myrpt->lock);
05819       ast_hangup(myrpt->pchannel);
05820       if (myrpt->txchannel != myrpt->rxchannel) 
05821          ast_hangup(myrpt->txchannel);
05822       ast_hangup(myrpt->rxchannel);
05823       myrpt->rpt_thread = AST_PTHREADT_STOP;
05824       pthread_exit(NULL);
05825    }
05826    /* make a conference for the tx */
05827    ci.chan = 0;
05828    ci.confno = myrpt->txconf;
05829    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER ;
05830    /* first put the channel on the conference in proper mode */
05831    if (ioctl(myrpt->txpchannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
05832       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05833       rpt_mutex_unlock(&myrpt->lock);
05834       ast_hangup(myrpt->txpchannel);
05835       ast_hangup(myrpt->pchannel);
05836       if (myrpt->txchannel != myrpt->rxchannel) 
05837          ast_hangup(myrpt->txchannel);
05838       ast_hangup(myrpt->rxchannel);
05839       myrpt->rpt_thread = AST_PTHREADT_STOP;
05840       pthread_exit(NULL);
05841    }
05842    /* Now, the idea here is to copy from the physical rx channel buffer
05843       into the pseudo tx buffer, and from the pseudo rx buffer into the 
05844       tx channel buffer */
05845    myrpt->links.next = &myrpt->links;
05846    myrpt->links.prev = &myrpt->links;
05847    myrpt->tailtimer = 0;
05848    myrpt->totimer = 0;
05849    myrpt->tmsgtimer = myrpt->p.tailmessagetime;
05850    myrpt->idtimer = myrpt->p.politeid;
05851    myrpt->mustid = myrpt->tailid = 0;
05852    myrpt->callmode = 0;
05853    myrpt->tounkeyed = 0;
05854    myrpt->tonotify = 0;
05855    myrpt->retxtimer = 0;
05856    myrpt->skedtimer = 0;
05857    myrpt->tailevent = 0;
05858    lasttx = 0;
05859    myrpt->keyed = 0;
05860    idtalkover = ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
05861    myrpt->dtmfidx = -1;
05862    myrpt->dtmfbuf[0] = 0;
05863    myrpt->rem_dtmfidx = -1;
05864    myrpt->rem_dtmfbuf[0] = 0;
05865    myrpt->dtmf_time = 0;
05866    myrpt->rem_dtmf_time = 0;
05867    myrpt->enable = 1;
05868    myrpt->disgorgetime = 0;
05869    myrpt->lastnodewhichkeyedusup[0] = '\0';
05870    myrpt->dailytxtime = 0;
05871    myrpt->totaltxtime = 0;
05872    myrpt->dailykeyups = 0;
05873    myrpt->totalkeyups = 0;
05874    myrpt->dailykerchunks = 0;
05875    myrpt->totalkerchunks = 0;
05876    myrpt->dailyexecdcommands = 0;
05877    myrpt->totalexecdcommands = 0;
05878    myrpt->timeouts = 0;
05879    myrpt->exten[0] = '\0';
05880    myrpt->lastdtmfcommand[0] = '\0';
05881    if (myrpt->p.startupmacro) {
05882       snprintf(myrpt->macrobuf, sizeof(myrpt->macrobuf), "PPPP%s", myrpt->p.startupmacro);
05883    }
05884    if (myrpt->p.startupgosub) {
05885       snprintf(myrpt->gosubbuf, sizeof(myrpt->gosubbuf), "PPPP%s", myrpt->p.startupgosub);
05886    }
05887    rpt_mutex_unlock(&myrpt->lock);
05888    val = 0;
05889    ast_channel_setoption(myrpt->rxchannel, AST_OPTION_TONE_VERIFY, &val, sizeof(char), 0);
05890    val = 1;
05891    ast_channel_setoption(myrpt->rxchannel, AST_OPTION_RELAXDTMF, &val, sizeof(char), 0);
05892    while (ms >= 0) {
05893       struct ast_frame *f;
05894       struct ast_channel *cs[300];
05895       int totx=0, elap=0, n, toexit = 0;
05896 
05897       /* DEBUG Dump */
05898       if ((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)) {
05899          struct rpt_link *zl;
05900          struct rpt_tele *zt;
05901 
05902          myrpt->disgorgetime = 0;
05903          ast_log(LOG_NOTICE, "********** Variable Dump Start (app_rpt) **********\n");
05904          ast_log(LOG_NOTICE, "totx = %d\n", totx);
05905          ast_log(LOG_NOTICE, "remrx = %d\n", remrx);
05906          ast_log(LOG_NOTICE, "lasttx = %d\n", lasttx);
05907          ast_log(LOG_NOTICE, "elap = %d\n", elap);
05908          ast_log(LOG_NOTICE, "toexit = %d\n", toexit);
05909 
05910          ast_log(LOG_NOTICE, "myrpt->keyed = %d\n", myrpt->keyed);
05911          ast_log(LOG_NOTICE, "myrpt->localtx = %d\n", myrpt->localtx);
05912          ast_log(LOG_NOTICE, "myrpt->callmode = %d\n", myrpt->callmode);
05913          ast_log(LOG_NOTICE, "myrpt->enable = %d\n", myrpt->enable);
05914          ast_log(LOG_NOTICE, "myrpt->mustid = %d\n", myrpt->mustid);
05915          ast_log(LOG_NOTICE, "myrpt->tounkeyed = %d\n", myrpt->tounkeyed);
05916          ast_log(LOG_NOTICE, "myrpt->tonotify = %d\n", myrpt->tonotify);
05917          ast_log(LOG_NOTICE, "myrpt->retxtimer = %ld\n", myrpt->retxtimer);
05918          ast_log(LOG_NOTICE, "myrpt->totimer = %d\n", myrpt->totimer);
05919          ast_log(LOG_NOTICE, "myrpt->tailtimer = %d\n", myrpt->tailtimer);
05920          ast_log(LOG_NOTICE, "myrpt->tailevent = %d\n", myrpt->tailevent);
05921 
05922          zl = myrpt->links.next;
05923          while (zl != &myrpt->links) {
05924             ast_log(LOG_NOTICE, "*** Link Name: %s ***\n", zl->name);
05925             ast_log(LOG_NOTICE, "        link->lasttx %d\n", zl->lasttx);
05926             ast_log(LOG_NOTICE, "        link->lastrx %d\n", zl->lastrx);
05927             ast_log(LOG_NOTICE, "        link->connected %d\n", zl->connected);
05928             ast_log(LOG_NOTICE, "        link->hasconnected %d\n", zl->hasconnected);
05929             ast_log(LOG_NOTICE, "        link->outbound %d\n", zl->outbound);
05930             ast_log(LOG_NOTICE, "        link->disced %d\n", zl->disced);
05931             ast_log(LOG_NOTICE, "        link->killme %d\n", zl->killme);
05932             ast_log(LOG_NOTICE, "        link->disctime %ld\n", zl->disctime);
05933             ast_log(LOG_NOTICE, "        link->retrytimer %ld\n", zl->retrytimer);
05934             ast_log(LOG_NOTICE, "        link->retries = %d\n", zl->retries);
05935             ast_log(LOG_NOTICE, "        link->reconnects = %d\n", zl->reconnects);
05936             zl = zl->next;
05937          }
05938 
05939          zt = myrpt->tele.next;
05940          if (zt != &myrpt->tele)
05941             ast_log(LOG_NOTICE, "*** Telemetry Queue ***\n");
05942          while (zt != &myrpt->tele) {
05943             ast_log(LOG_NOTICE, "        Telemetry mode: %d\n", zt->mode);
05944             zt = zt->next;
05945          }
05946          ast_log(LOG_NOTICE, "******* Variable Dump End (app_rpt) *******\n");
05947       }  
05948 
05949       if (myrpt->reload) {
05950          struct rpt_tele *telem;
05951 
05952          rpt_mutex_lock(&myrpt->lock);
05953          telem = myrpt->tele.next;
05954          while (telem != &myrpt->tele) {
05955             ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV);
05956             telem = telem->next;
05957          }
05958          myrpt->reload = 0;
05959          rpt_mutex_unlock(&myrpt->lock);
05960          usleep(10000);
05961          /* find our index, and load the vars */
05962          for (i = 0; i < nrpts; i++) {
05963             if (&rpt_vars[i] == myrpt) {
05964                load_rpt_vars(i, 0);
05965                break;
05966             }
05967          }
05968       }
05969 
05970       rpt_mutex_lock(&myrpt->lock);
05971       if (ast_check_hangup(myrpt->rxchannel)) break;
05972       if (ast_check_hangup(myrpt->txchannel)) break;
05973       if (ast_check_hangup(myrpt->pchannel)) break;
05974       if (ast_check_hangup(myrpt->txpchannel)) break;
05975 
05976       /* Update local tx with keyed if not parsing a command */
05977       myrpt->localtx = myrpt->keyed && (myrpt->dtmfidx == -1) && (!myrpt->cmdnode[0]);
05978       /* If someone's connected, and they're transmitting from their end to us, set remrx true */
05979       l = myrpt->links.next;
05980       remrx = 0;
05981       while (l != &myrpt->links) {
05982          if (l->lastrx) {
05983             remrx = 1;
05984             if (l->name[0] != '0') /* Ignore '0' nodes */
05985                strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
05986          }
05987          l = l->next;
05988       }
05989       /* Create a "must_id" flag for the cleanup ID */      
05990       myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
05991       /* Build a fresh totx from myrpt->keyed and autopatch activated */
05992       totx = myrpt->callmode;
05993       /* If full duplex, add local tx to totx */
05994       if (myrpt->p.duplex > 1) totx = totx || myrpt->localtx;
05995       /* Traverse the telemetry list to see what's queued */
05996       identqueued = 0;
05997       othertelemqueued = 0;
05998       tailmessagequeued = 0;
05999       ctqueued = 0;
06000       telem = myrpt->tele.next;
06001       while (telem != &myrpt->tele) {
06002          if ((telem->mode == ID) || (telem->mode == IDTALKOVER)) {
06003             identqueued = 1; /* Identification telemetry */
06004          } else if (telem->mode == TAILMSG) {
06005             tailmessagequeued = 1; /* Tail message telemetry */
06006          } else {
06007             if (telem->mode != UNKEY)
06008                othertelemqueued = 1;  /* Other telemetry */
06009             else
06010                ctqueued = 1; /* Courtesy tone telemetry */
06011          }
06012          telem = telem->next;
06013       }
06014    
06015       /* Add in any "other" telemetry, if 3/4 or full duplex */
06016       if (myrpt->p.duplex > 0)
06017          totx = totx || othertelemqueued;
06018       /* Update external (to links) transmitter PTT state with everything but ID, CT, and tailmessage telemetry */
06019       myrpt->exttx = totx;
06020       /* If half or 3/4 duplex, add localtx to external link tx */
06021       if (myrpt->p.duplex < 2)
06022          myrpt->exttx = myrpt->exttx || myrpt->localtx;
06023       /* Add in ID telemetry to local transmitter */
06024       totx = totx || remrx;
06025       /* If 3/4 or full duplex, add in ident and CT telemetry */
06026       if (myrpt->p.duplex > 0)
06027          totx = totx || identqueued || ctqueued;
06028       /* Reset time out timer variables if there is no activity */
06029       if (!totx) {
06030          myrpt->totimer = myrpt->p.totime;
06031          myrpt->tounkeyed = 0;
06032          myrpt->tonotify = 0;
06033       } else
06034          myrpt->tailtimer = myrpt->p.hangtime; /* Initialize tail timer */
06035       /* Disable the local transmitter if we are timed out */
06036       totx = totx && myrpt->totimer;
06037       /* if timed-out and not said already, say it */
06038       if ((!myrpt->totimer) && (!myrpt->tonotify)) {
06039          myrpt->tonotify = 1;
06040          myrpt->timeouts++;
06041          rpt_mutex_unlock(&myrpt->lock);
06042          rpt_telemetry(myrpt, TIMEOUT, NULL);
06043          rpt_mutex_lock(&myrpt->lock);
06044       }
06045 
06046       /* If unkey and re-key, reset time out timer */
06047       if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed)) {
06048          myrpt->tounkeyed = 1;
06049       }
06050       if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed) {
06051          myrpt->totimer = myrpt->p.totime;
06052          myrpt->tounkeyed = 0;
06053          myrpt->tonotify = 0;
06054          rpt_mutex_unlock(&myrpt->lock);
06055          continue;
06056       }
06057       /* if timed-out and in circuit busy after call */
06058       if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4)) {
06059          myrpt->callmode = 0;
06060       }
06061       /* get rid of tail if timed out */
06062       if (!myrpt->totimer)
06063          myrpt->tailtimer = 0;
06064       /* if not timed-out, add in tail */
06065       if (myrpt->totimer)
06066          totx = totx || myrpt->tailtimer;
06067       /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
06068       /* If tail message, kill the message if someone keys up over it */ 
06069       if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
06070          int hasid = 0, hastalkover = 0;
06071 
06072          telem = myrpt->tele.next;
06073          while (telem != &myrpt->tele) {
06074             if (telem->mode == ID) {
06075                if (telem->chan)
06076                   ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
06077                hasid = 1;
06078             }
06079             if (telem->mode == TAILMSG) {
06080                if (telem->chan)
06081                   ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
06082             }
06083             if (telem->mode == IDTALKOVER)
06084                hastalkover = 1;
06085             telem = telem->next;
06086          }
06087          rpt_mutex_unlock(&myrpt->lock);
06088          if (hasid && (!hastalkover))
06089             rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
06090          rpt_mutex_lock(&myrpt->lock);
06091       }
06092       /* Try to be polite */
06093       /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
06094       /* If within 30 seconds of the time to ID, try do it in the tail */
06095       /* else if at ID time limit, do it right over the top of them */
06096       /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
06097       if (myrpt->mustid && (!myrpt->idtimer))
06098          queue_id(myrpt);
06099 
06100       if ((totx && (!myrpt->exttx) &&
06101           (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) {
06102          myrpt->tailid = 1;
06103       }
06104 
06105       /* If tail timer expires, then check for tail messages */
06106 
06107       if (myrpt->tailevent) {
06108          myrpt->tailevent = 0;
06109          if (myrpt->tailid) {
06110             totx = 1;
06111             queue_id(myrpt);
06112          }
06113          else if ((myrpt->p.tailmsg.msgs[0]) &&
06114             (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)) {
06115                totx = 1;
06116                myrpt->tmsgtimer = myrpt->p.tailmessagetime; 
06117                rpt_mutex_unlock(&myrpt->lock);
06118                rpt_telemetry(myrpt, TAILMSG, NULL);
06119                rpt_mutex_lock(&myrpt->lock);
06120          }  
06121       }
06122 
06123       /* Main TX control */
06124 
06125       /* let telemetry transmit anyway (regardless of timeout) */
06126       if (myrpt->p.duplex > 0)
06127          totx = totx || (myrpt->tele.next != &myrpt->tele);
06128       if (totx && (!lasttx)) {
06129          lasttx = 1;
06130          myrpt->dailykeyups++;
06131          myrpt->totalkeyups++;
06132          rpt_mutex_unlock(&myrpt->lock);
06133          ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_KEY);
06134          rpt_mutex_lock(&myrpt->lock);
06135       }
06136       totx = totx && myrpt->enable;
06137       if ((!totx) && lasttx) {
06138          lasttx = 0;
06139          rpt_mutex_unlock(&myrpt->lock);
06140          ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
06141          rpt_mutex_lock(&myrpt->lock);
06142       }
06143       time(&t);
06144       /* if DTMF timeout */
06145       if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t)) {
06146          myrpt->dtmfidx = -1;
06147          myrpt->dtmfbuf[0] = 0;
06148       }        
06149       /* if remote DTMF timeout */
06150       if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t)) {
06151          myrpt->rem_dtmfidx = -1;
06152          myrpt->rem_dtmfbuf[0] = 0;
06153       }  
06154 
06155       /* Reconnect */
06156    
06157       l = myrpt->links.next;
06158       while (l != &myrpt->links) {
06159          if (l->killme) {
06160             /* remove from queue */
06161             remque((struct qelem *) l);
06162             if (!strcmp(myrpt->cmdnode, l->name))
06163                myrpt->cmdnode[0] = 0;
06164             rpt_mutex_unlock(&myrpt->lock);
06165             /* hang-up on call to device */
06166             if (l->chan)
06167                ast_hangup(l->chan);
06168             ast_hangup(l->pchan);
06169             ast_free(l);
06170             rpt_mutex_lock(&myrpt->lock);
06171             /* re-start link traversal */
06172             l = myrpt->links.next;
06173             continue;
06174          }
06175          l = l->next;
06176       }
06177       n = 0;
06178       cs[n++] = myrpt->rxchannel;
06179       cs[n++] = myrpt->pchannel;
06180       cs[n++] = myrpt->txpchannel;
06181       if (myrpt->txchannel != myrpt->rxchannel)
06182          cs[n++] = myrpt->txchannel;
06183       l = myrpt->links.next;
06184       while (l != &myrpt->links) {
06185          if ((!l->killme) && (!l->disctime) && l->chan) {
06186             cs[n++] = l->chan;
06187             cs[n++] = l->pchan;
06188          }
06189          l = l->next;
06190       }
06191       rpt_mutex_unlock(&myrpt->lock);
06192       ms = MSWAIT;
06193       who = ast_waitfor_n(cs, n, &ms);
06194       if (who == NULL)
06195          ms = 0;
06196       elap = MSWAIT - ms;
06197       rpt_mutex_lock(&myrpt->lock);
06198       l = myrpt->links.next;
06199       while (l != &myrpt->links) {
06200          if (!l->lasttx) {
06201             if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME) {
06202                l->retxtimer = 0;
06203                if (l->chan)
06204                   ast_indicate(l->chan, AST_CONTROL_RADIO_UNKEY);
06205             }
06206          } else
06207             l->retxtimer = 0;
06208          if (l->disctime) { /* Disconnect timer active on a channel ? */
06209             l->disctime -= elap;
06210             if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
06211                l->disctime = 0; /* Yep */
06212          }
06213 
06214          if (l->retrytimer) {
06215             l->retrytimer -= elap;
06216             if (l->retrytimer < 0)
06217                l->retrytimer = 0;
06218          }
06219 
06220          /* Tally connect time */
06221          l->connecttime += elap;
06222 
06223          /* ignore non-timing channels */
06224          if (l->elaptime < 0) {
06225             l = l->next;
06226             continue;
06227          }
06228          l->elaptime += elap;
06229          /* if connection has taken too long */
06230          if ((l->elaptime > MAXCONNECTTIME) && 
06231             ((!l->chan) || (l->chan->_state != AST_STATE_UP))) {
06232             l->elaptime = 0;
06233             rpt_mutex_unlock(&myrpt->lock);
06234             if (l->chan)
06235                ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
06236             rpt_mutex_lock(&myrpt->lock);
06237             break;
06238          }
06239          if ((!l->chan) && (!l->retrytimer) && l->outbound && 
06240             (l->retries++ < MAX_RETRIES) && (l->hasconnected)) {
06241             if (l->chan)
06242                ast_hangup(l->chan);
06243             rpt_mutex_unlock(&myrpt->lock);
06244             if ((l->name[0] != '0') && (!l->isremote)) {
06245                l->retrytimer = MAX_RETRIES + 1;
06246             } else {
06247                if (attempt_reconnect(myrpt, l) == -1) {
06248                   l->retrytimer = RETRY_TIMER_MS;
06249                }
06250             }
06251             rpt_mutex_lock(&myrpt->lock);
06252             break;
06253          }
06254          if ((!l->chan) && (!l->retrytimer) && l->outbound && (l->retries >= MAX_RETRIES)) {
06255             /* remove from queue */
06256             remque((struct qelem *) l);
06257             if (!strcmp(myrpt->cmdnode, l->name))
06258                myrpt->cmdnode[0] = 0;
06259             rpt_mutex_unlock(&myrpt->lock);
06260             if (l->name[0] != '0') {
06261                if (!l->hasconnected)
06262                   rpt_telemetry(myrpt, CONNFAIL, l);
06263                else
06264                   rpt_telemetry(myrpt, REMDISC, l);
06265             }
06266             /* hang-up on call to device */
06267             ast_hangup(l->pchan);
06268             ast_free(l);
06269             rpt_mutex_lock(&myrpt->lock);
06270             break;
06271          }
06272          if ((!l->chan) && (!l->disctime) && (!l->outbound)) {
06273             /* remove from queue */
06274             remque((struct qelem *) l);
06275             if (!strcmp(myrpt->cmdnode, l->name))
06276                myrpt->cmdnode[0] = 0;
06277             rpt_mutex_unlock(&myrpt->lock);
06278             if (l->name[0] != '0') {
06279                rpt_telemetry(myrpt, REMDISC, l);
06280             }
06281             /* hang-up on call to device */
06282             ast_hangup(l->pchan);
06283             ast_free(l);
06284             rpt_mutex_lock(&myrpt->lock);
06285             break;
06286          }
06287          l = l->next;
06288       }
06289       if (totx) {
06290          myrpt->dailytxtime += elap;
06291          myrpt->totaltxtime += elap;
06292       }
06293       i = myrpt->tailtimer;
06294       if (myrpt->tailtimer)
06295          myrpt->tailtimer -= elap;
06296       if (myrpt->tailtimer < 0)
06297          myrpt->tailtimer = 0;
06298       if ((i) && (myrpt->tailtimer == 0))
06299          myrpt->tailevent = 1;
06300       if (myrpt->totimer)
06301          myrpt->totimer -= elap;
06302       if (myrpt->totimer < 0)
06303          myrpt->totimer = 0;
06304       if (myrpt->idtimer)
06305          myrpt->idtimer -= elap;
06306       if (myrpt->idtimer < 0)
06307          myrpt->idtimer = 0;
06308       if (myrpt->tmsgtimer)
06309          myrpt->tmsgtimer -= elap;
06310       if (myrpt->tmsgtimer < 0)
06311          myrpt->tmsgtimer = 0;
06312       /* do macro timers */
06313       if (myrpt->macrotimer)
06314          myrpt->macrotimer -= elap;
06315       if (myrpt->macrotimer < 0)
06316          myrpt->macrotimer = 0;
06317       /* do gosub timers */
06318       if (myrpt->gosubtimer)
06319          myrpt->gosubtimer -= elap;
06320       if (myrpt->gosubtimer < 0)
06321          myrpt->gosubtimer = 0;
06322       /* Execute scheduler appx. every 2 tenths of a second */
06323       if (myrpt->skedtimer <= 0) {
06324          myrpt->skedtimer = 200;
06325          do_scheduler(myrpt);
06326       } else
06327          myrpt->skedtimer -= elap;
06328       if (!ms) {
06329          rpt_mutex_unlock(&myrpt->lock);
06330          continue;
06331       }
06332       c = myrpt->macrobuf[0];
06333       if (c && (!myrpt->macrotimer)) {
06334          myrpt->macrotimer = MACROTIME;
06335          memmove(myrpt->macrobuf, myrpt->macrobuf + 1, sizeof(myrpt->macrobuf) - 1);
06336          if ((c == 'p') || (c == 'P'))
06337             myrpt->macrotimer = MACROPTIME;
06338          rpt_mutex_unlock(&myrpt->lock);
06339          local_dtmf_helper(myrpt, c);
06340       } else
06341          rpt_mutex_unlock(&myrpt->lock);
06342       c = myrpt->gosubbuf[0];
06343       if (c && (!myrpt->gosubtimer)) {
06344          myrpt->gosubtimer = GOSUBTIME;
06345          memmove(myrpt->gosubbuf, myrpt->gosubbuf + 1, sizeof(myrpt->gosubbuf) - 1);
06346          if ((c == 'p') || (c == 'P'))
06347             myrpt->gosubtimer = GOSUBPTIME;
06348          rpt_mutex_unlock(&myrpt->lock);
06349          local_dtmf_helper(myrpt, c);
06350       } else
06351          rpt_mutex_unlock(&myrpt->lock);
06352       if (who == myrpt->rxchannel) { /* if it was a read from rx */
06353          f = ast_read(myrpt->rxchannel);
06354          if (!f) {
06355             ast_debug(1, "@@@@ rpt:Hung Up\n");
06356             break;
06357          }
06358          if (f->frametype == AST_FRAME_VOICE) {
06359 #ifdef   _MDC_DECODE_H_
06360             unsigned char ubuf[2560];
06361             short *sp;
06362             int n;
06363 #endif
06364 
06365             if (!myrpt->localtx) {
06366                memset(f->data, 0, f->datalen);
06367             }
06368 
06369 #ifdef   _MDC_DECODE_H_
06370             sp = (short *) f->data;
06371             /* convert block to unsigned char */
06372             for (n = 0; n < f->datalen / 2; n++) {
06373                ubuf[n] = (*sp++ >> 8) + 128;
06374             }
06375             n = mdc_decoder_process_samples(myrpt->mdc, ubuf, f->datalen / 2);
06376             if (n == 1) {
06377                unsigned char op, arg;
06378                unsigned short unitID;
06379 
06380                mdc_decoder_get_packet(myrpt->mdc, &op, &arg, &unitID);
06381                if (debug > 2) {
06382                   ast_log(LOG_NOTICE, "Got (single-length) packet:\n");
06383                   ast_log(LOG_NOTICE, "op: %02x, arg: %02x, UnitID: %04x\n", op & 255, arg & 255, unitID);
06384                }
06385                if ((op == 1) && (arg == 0)) {
06386                   myrpt->lastunit = unitID;
06387                }
06388             }
06389             if ((debug > 2) && (i == 2)) {
06390                unsigned char op, arg, ex1, ex2, ex3, ex4;
06391                unsigned short unitID;
06392 
06393                mdc_decoder_get_double_packet(myrpt->mdc, &op, &arg, &unitID, &ex1, &ex2, &ex3, &ex4);
06394                ast_log(LOG_NOTICE, "Got (double-length) packet:\n");
06395                ast_log(LOG_NOTICE, "op: %02x, arg: %02x, UnitID: %04x\n", op & 255, arg & 255, unitID);
06396                ast_log(LOG_NOTICE, "ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
06397                   ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
06398             }
06399 #endif
06400 #ifdef   __RPT_NOTCH
06401             /* apply inbound filters, if any */
06402             rpt_filter(myrpt, f->data, f->datalen / 2);
06403 #endif
06404             ast_write(myrpt->pchannel, f);
06405          } else if (f->frametype == AST_FRAME_DTMF) {
06406             c = (char) f->subclass; /* get DTMF char */
06407             ast_frfree(f);
06408             if (!myrpt->keyed)
06409                continue;
06410             local_dtmf_helper(myrpt, c);
06411             continue;
06412          } else if (f->frametype == AST_FRAME_CONTROL) {
06413             if (f->subclass == AST_CONTROL_HANGUP) {
06414                ast_debug(1, "@@@@ rpt:Hung Up\n");
06415                ast_frfree(f);
06416                break;
06417             }
06418             /* if RX key */
06419             if (f->subclass == AST_CONTROL_RADIO_KEY) {
06420                if ((!lasttx) || (myrpt->p.duplex > 1)) {
06421                   ast_debug(8, "@@@@ rx key\n");
06422                   myrpt->keyed = 1;
06423                }
06424             }
06425             /* if RX un-key */
06426             if (f->subclass == AST_CONTROL_RADIO_UNKEY) {
06427                if ((!lasttx) || (myrpt->p.duplex > 1)) {
06428                   ast_debug(8, "@@@@ rx un-key\n");
06429                   if (myrpt->keyed) {
06430                      rpt_telemetry(myrpt, UNKEY, NULL);
06431                   }
06432                   myrpt->keyed = 0;
06433                }
06434             }
06435          }
06436          ast_frfree(f);
06437          continue;
06438       }
06439       if (who == myrpt->pchannel) { /* if it was a read from pseudo */
06440          f = ast_read(myrpt->pchannel);
06441          if (!f) {
06442             ast_debug(1, "@@@@ rpt:Hung Up\n");
06443             break;
06444          }
06445          if (f->frametype == AST_FRAME_VOICE) {
06446             ast_write(myrpt->txpchannel, f);
06447          }
06448          if (f->frametype == AST_FRAME_CONTROL) {
06449             if (f->subclass == AST_CONTROL_HANGUP) {
06450                ast_debug(1, "@@@@ rpt:Hung Up\n");
06451                ast_frfree(f);
06452                break;
06453             }
06454          }
06455          ast_frfree(f);
06456          continue;
06457       }
06458       if (who == myrpt->txchannel) { /* if it was a read from tx */
06459          f = ast_read(myrpt->txchannel);
06460          if (!f) {
06461             ast_debug(1, "@@@@ rpt:Hung Up\n");
06462             break;
06463          }
06464          if (f->frametype == AST_FRAME_CONTROL) {
06465             if (f->subclass == AST_CONTROL_HANGUP) {
06466                ast_debug(1, "@@@@ rpt:Hung Up\n");
06467                ast_frfree(f);
06468                break;
06469             }
06470          }
06471          ast_frfree(f);
06472          continue;
06473       }
06474       toexit = 0;
06475       rpt_mutex_lock(&myrpt->lock);
06476       l = myrpt->links.next;
06477       while (l != &myrpt->links) {
06478          if (l->disctime) {
06479             l = l->next;
06480             continue;
06481          }
06482          if (who == l->chan) { /* if it was a read from rx */
06483             remrx = 0;
06484             /* see if any other links are receiving */
06485             m = myrpt->links.next;
06486             while (m != &myrpt->links) {
06487                /* if not us, count it */
06488                if ((m != l) && (m->lastrx))
06489                   remrx = 1;
06490                m = m->next;
06491             }
06492             rpt_mutex_unlock(&myrpt->lock);
06493             totx = (((l->isremote) ? myrpt->localtx : 
06494                myrpt->exttx) || remrx) && l->mode;
06495             if (l->chan && (l->lasttx != totx)) {
06496                if (totx) {
06497                   ast_indicate(l->chan, AST_CONTROL_RADIO_KEY);
06498                } else {
06499                   ast_indicate(l->chan, AST_CONTROL_RADIO_UNKEY);
06500                }
06501             }
06502             l->lasttx = totx;
06503             f = ast_read(l->chan);
06504             if (!f) {
06505                if ((!l->disced) && (!l->outbound)) {
06506                   if ((l->name[0] == '0') || l->isremote)
06507                      l->disctime = 1;
06508                   else
06509                      l->disctime = DISC_TIME;
06510                   rpt_mutex_lock(&myrpt->lock);
06511                   ast_hangup(l->chan);
06512                   l->chan = 0;
06513                   break;
06514                }
06515 
06516                if (l->retrytimer) {
06517                   rpt_mutex_lock(&myrpt->lock);
06518                   break; 
06519                }
06520                if (l->outbound && (l->retries++ < MAX_RETRIES) && (l->hasconnected)) {
06521                   rpt_mutex_lock(&myrpt->lock);
06522                   ast_hangup(l->chan);
06523                   l->chan = 0;
06524                   rpt_mutex_unlock(&myrpt->lock);
06525                   if (attempt_reconnect(myrpt, l) == -1) {
06526                      l->retrytimer = RETRY_TIMER_MS;
06527                   }
06528                   rpt_mutex_lock(&myrpt->lock);
06529                   break;
06530                }
06531                rpt_mutex_lock(&myrpt->lock);
06532                /* remove from queue */
06533                remque((struct qelem *) l);
06534                if (!strcmp(myrpt->cmdnode, l->name))
06535                   myrpt->cmdnode[0] = 0;
06536                rpt_mutex_unlock(&myrpt->lock);
06537                if (!l->hasconnected)
06538                   rpt_telemetry(myrpt, CONNFAIL, l);
06539                else if (l->disced != 2)
06540                   rpt_telemetry(myrpt, REMDISC, l);
06541                /* hang-up on call to device */
06542                ast_hangup(l->chan);
06543                ast_hangup(l->pchan);
06544                ast_free(l);
06545                rpt_mutex_lock(&myrpt->lock);
06546                break;
06547             }
06548             if (f->frametype == AST_FRAME_VOICE) {
06549                if (!l->lastrx) {
06550                   memset(f->data, 0, f->datalen);
06551                }
06552                ast_write(l->pchan, f);
06553             }
06554             if (f->frametype == AST_FRAME_TEXT) {
06555                handle_link_data(myrpt, l, f->data);
06556             }
06557             if (f->frametype == AST_FRAME_DTMF) {
06558                handle_link_phone_dtmf(myrpt, l, f->subclass);
06559             }
06560             if (f->frametype == AST_FRAME_CONTROL) {
06561                if (f->subclass == AST_CONTROL_ANSWER) {
06562                   char lconnected = l->connected;
06563                   l->connected = 1;
06564                   l->hasconnected = 1;
06565                   l->elaptime = -1;
06566                   l->retries = 0;
06567                   if (!lconnected) 
06568                      rpt_telemetry(myrpt, CONNECTED, l);
06569                   else
06570                      l->reconnects++;
06571                }
06572                /* if RX key */
06573                if (f->subclass == AST_CONTROL_RADIO_KEY) {
06574                   ast_debug(8, "@@@@ rx key\n");
06575                   l->lastrx = 1;
06576                }
06577                /* if RX un-key */
06578                if (f->subclass == AST_CONTROL_RADIO_UNKEY) {
06579                   ast_debug(8, "@@@@ rx un-key\n");
06580                   l->lastrx = 0;
06581                }
06582                if (f->subclass == AST_CONTROL_HANGUP) {
06583                   ast_frfree(f);
06584                   if ((!l->outbound) && (!l->disced)) {
06585                      if ((l->name[0] == '0') || l->isremote)
06586                         l->disctime = 1;
06587                      else
06588                         l->disctime = DISC_TIME;
06589                      rpt_mutex_lock(&myrpt->lock);
06590                      ast_hangup(l->chan);
06591                      l->chan = 0;
06592                      break;
06593                   }
06594                   if (l->retrytimer) {
06595                      rpt_mutex_lock(&myrpt->lock);
06596                      break;
06597                   }
06598                   if (l->outbound && (l->retries++ < MAX_RETRIES) && (l->hasconnected)) {
06599                      rpt_mutex_lock(&myrpt->lock);
06600                      ast_hangup(l->chan);
06601                      l->chan = 0;
06602                      rpt_mutex_unlock(&myrpt->lock);
06603                      if (attempt_reconnect(myrpt, l) == -1) {
06604                         l->retrytimer = RETRY_TIMER_MS;
06605                      }
06606                      rpt_mutex_lock(&myrpt->lock);
06607                      break;
06608                   }
06609                   rpt_mutex_lock(&myrpt->lock);
06610                   /* remove from queue */
06611                   remque((struct qelem *) l);
06612                   if (!strcmp(myrpt->cmdnode, l->name))
06613                      myrpt->cmdnode[0] = 0;
06614                   rpt_mutex_unlock(&myrpt->lock);
06615                   if (!l->hasconnected)
06616                      rpt_telemetry(myrpt, CONNFAIL, l);
06617                   else if (l->disced != 2)
06618                      rpt_telemetry(myrpt, REMDISC, l);
06619                   /* hang-up on call to device */
06620                   ast_hangup(l->chan);
06621                   ast_hangup(l->pchan);
06622                   ast_free(l);
06623                   rpt_mutex_lock(&myrpt->lock);
06624                   break;
06625                }
06626             }
06627             ast_frfree(f);
06628             rpt_mutex_lock(&myrpt->lock);
06629             break;
06630          }
06631          if (who == l->pchan) {
06632             rpt_mutex_unlock(&myrpt->lock);
06633             f = ast_read(l->pchan);
06634             if (!f) {
06635                ast_debug(1, "@@@@ rpt:Hung Up\n");
06636                toexit = 1;
06637                rpt_mutex_lock(&myrpt->lock);
06638                break;
06639             }
06640             if (f->frametype == AST_FRAME_VOICE) {
06641                if (l->chan)
06642                   ast_write(l->chan, f);
06643             }
06644             if (f->frametype == AST_FRAME_CONTROL) {
06645                if (f->subclass == AST_CONTROL_HANGUP) {
06646                   ast_debug(1, "@@@@ rpt:Hung Up\n");
06647                   ast_frfree(f);
06648                   toexit = 1;
06649                   rpt_mutex_lock(&myrpt->lock);
06650                   break;
06651                }
06652             }
06653             ast_frfree(f);
06654             rpt_mutex_lock(&myrpt->lock);
06655             break;
06656          }
06657          l = l->next;
06658       }
06659       rpt_mutex_unlock(&myrpt->lock);
06660       if (toexit)
06661          break;
06662       if (who == myrpt->txpchannel) { /* if it was a read from remote tx */
06663          f = ast_read(myrpt->txpchannel);
06664          if (!f) {
06665             ast_debug(1, "@@@@ rpt:Hung Up\n");
06666             break;
06667          }
06668          if (f->frametype == AST_FRAME_CONTROL) {
06669             if (f->subclass == AST_CONTROL_HANGUP) {
06670                ast_debug(1, "@@@@ rpt:Hung Up\n");
06671                ast_frfree(f);
06672                break;
06673             }
06674          }
06675          ast_frfree(f);
06676          continue;
06677       }
06678    }
06679    usleep(100000);
06680    ast_hangup(myrpt->pchannel);
06681    ast_hangup(myrpt->txpchannel);
06682    if (myrpt->txchannel != myrpt->rxchannel)
06683       ast_hangup(myrpt->txchannel);
06684    ast_hangup(myrpt->rxchannel);
06685    rpt_mutex_lock(&myrpt->lock);
06686    l = myrpt->links.next;
06687    while (l != &myrpt->links) {
06688       struct rpt_link *ll = l;
06689       /* remove from queue */
06690       remque((struct qelem *) l);
06691       /* hang-up on call to device */
06692       if (l->chan)
06693          ast_hangup(l->chan);
06694       ast_hangup(l->pchan);
06695       l = l->next;
06696       ast_free(ll);
06697    }
06698    rpt_mutex_unlock(&myrpt->lock);
06699    ast_debug(1, "@@@@ rpt:Hung up channel\n");
06700    myrpt->rpt_thread = AST_PTHREADT_STOP;
06701    pthread_exit(NULL); 
06702    return NULL;
06703 }

static void* rpt_call ( void *  this  )  [static]

Definition at line 2526 of file app_rpt.c.

References accountcode, rpt::acctcode, ast_callerid_parse(), ast_channel_undefer_dtmf(), ast_copy_string(), AST_FORMAT_SLINEAR, AST_FRAME_DTMF, ast_free, ast_hangup(), ast_log(), ast_pbx_start(), ast_request(), ast_safe_sleep(), ast_softhangup(), AST_SOFTHANGUP_DEV, ast_strdup, ast_string_field_set, ast_write(), rpt::callmode, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, rpt::cidx, rpt::conf, ast_channel::context, ast_frame::data, ast_frame::datalen, rpt::duplex, rpt::exten, ast_channel::exten, ast_channel::fds, ast_frame::frametype, rpt::lock, LOG_ERROR, LOG_WARNING, ast_frame::mallocd, MSWAIT, rpt::mydtmf, name, ast_frame::offset, rpt::ourcallerid, rpt::p, rpt::patchcontext, rpt::patchdialtime, rpt::patchfarenddisconnect, rpt::patchquiet, ast_channel::pbx, rpt::pchannel, ast_channel::priority, rpt_mutex_lock, rpt_mutex_unlock, rpt_telemetry(), ast_frame::samples, ast_frame::subclass, TERM, and rpt::tonezone.

Referenced by local_dtmf_helper().

02527 {
02528    struct dahdi_confinfo ci;  /* conference info */
02529    struct rpt *myrpt = (struct rpt *)this;
02530    int   res;
02531    struct ast_frame wf;
02532    int stopped, congstarted, dialtimer, lastcidx, aborted;
02533    struct ast_channel *mychannel, *genchannel;
02534 
02535    myrpt->mydtmf = 0;
02536    /* allocate a pseudo-channel thru asterisk */
02537    mychannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
02538    if (!mychannel) {
02539       ast_log(LOG_ERROR, "rpt: unable to obtain pseudo channel\n");
02540       pthread_exit(NULL);
02541    }
02542    ci.chan = 0;
02543    ci.confno = myrpt->conf; /* use the pseudo conference */
02544    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
02545       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
02546    /* first put the channel on the conference */
02547    if (ioctl(mychannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
02548       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02549       ast_hangup(mychannel);
02550       myrpt->callmode = 0;
02551       pthread_exit(NULL);
02552    }
02553    /* allocate a pseudo-channel thru asterisk */
02554    genchannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
02555    if (!genchannel) {
02556       ast_log(LOG_ERROR, "rpt: unable to obtain pseudo channel\n");
02557       ast_hangup(mychannel);
02558       pthread_exit(NULL);
02559    }
02560    ci.chan = 0;
02561    ci.confno = myrpt->conf;
02562    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
02563       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
02564    /* first put the channel on the conference */
02565    if (ioctl(genchannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
02566       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02567       ast_hangup(mychannel);
02568       ast_hangup(genchannel);
02569       myrpt->callmode = 0;
02570       pthread_exit(NULL);
02571    }
02572    if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0], myrpt->p.tonezone) == -1)) {
02573       ast_log(LOG_WARNING, "Unable to set tone zone %s\n", myrpt->p.tonezone);
02574       ast_hangup(mychannel);
02575       ast_hangup(genchannel);
02576       myrpt->callmode = 0;
02577       pthread_exit(NULL);
02578    }
02579    if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0], myrpt->p.tonezone) == -1)) {
02580       ast_log(LOG_WARNING, "Unable to set tone zone %s\n", myrpt->p.tonezone);
02581       ast_hangup(mychannel);
02582       ast_hangup(genchannel);
02583       myrpt->callmode = 0;
02584       pthread_exit(NULL);
02585    }
02586    /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
02587    if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0], DAHDI_TONE_DIALTONE) < 0)) {
02588       ast_log(LOG_WARNING, "Cannot start dialtone\n");
02589       ast_hangup(mychannel);
02590       ast_hangup(genchannel);
02591       myrpt->callmode = 0;
02592       pthread_exit(NULL);
02593    }
02594    stopped = 0;
02595    congstarted = 0;
02596    dialtimer = 0;
02597    lastcidx = 0;
02598    aborted = 0;
02599 
02600    while ((myrpt->callmode == 1) || (myrpt->callmode == 4)) {
02601       if ((myrpt->patchdialtime) && (myrpt->callmode == 1) && (myrpt->cidx != lastcidx)) {
02602          dialtimer = 0;
02603          lastcidx = myrpt->cidx;
02604       }     
02605 
02606       if ((myrpt->patchdialtime) && (dialtimer >= myrpt->patchdialtime)) { 
02607          rpt_mutex_lock(&myrpt->lock);
02608          aborted = 1;
02609          myrpt->callmode = 0;
02610          rpt_mutex_unlock(&myrpt->lock);
02611          break;
02612       }
02613    
02614       if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0)) {
02615          stopped = 1;
02616          /* stop dial tone */
02617          tone_zone_play_tone(mychannel->fds[0], -1);
02618       }
02619       if (myrpt->callmode == 4) {
02620          if (!congstarted) {
02621             congstarted = 1;
02622             /* start congestion tone */
02623             tone_zone_play_tone(mychannel->fds[0], DAHDI_TONE_CONGESTION);
02624          }
02625       }
02626       res = ast_safe_sleep(mychannel, MSWAIT);
02627       if (res < 0) {
02628          ast_hangup(mychannel);
02629          ast_hangup(genchannel);
02630          rpt_mutex_lock(&myrpt->lock);
02631          myrpt->callmode = 0;
02632          rpt_mutex_unlock(&myrpt->lock);
02633          pthread_exit(NULL);
02634       }
02635       dialtimer += MSWAIT;
02636    }
02637    /* stop any tone generation */
02638    tone_zone_play_tone(mychannel->fds[0], -1);
02639    /* end if done */
02640    if (!myrpt->callmode) {
02641       ast_hangup(mychannel);
02642       ast_hangup(genchannel);
02643       rpt_mutex_lock(&myrpt->lock);
02644       myrpt->callmode = 0;
02645       rpt_mutex_unlock(&myrpt->lock);
02646       if ((!myrpt->patchquiet) && aborted)
02647          rpt_telemetry(myrpt, TERM, NULL);
02648       pthread_exit(NULL);        
02649    }
02650 
02651    if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid) {
02652       char *name, *loc, *instr;
02653       instr = ast_strdup(myrpt->p.ourcallerid);
02654       if (instr) {
02655          ast_callerid_parse(instr, &name, &loc);
02656          if (loc) {
02657             if (mychannel->cid.cid_num)
02658                ast_free(mychannel->cid.cid_num);
02659             mychannel->cid.cid_num = ast_strdup(loc);
02660          }
02661          if (name) {
02662             if (mychannel->cid.cid_name)
02663                ast_free(mychannel->cid.cid_name);
02664             mychannel->cid.cid_name = ast_strdup(name);
02665          }
02666          ast_free(instr);
02667       }
02668    }
02669 
02670    ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten));
02671    ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context));
02672    
02673    if (myrpt->p.acctcode)
02674       ast_string_field_set(mychannel, accountcode, myrpt->p.acctcode);
02675    mychannel->priority = 1;
02676    ast_channel_undefer_dtmf(mychannel);
02677    if (ast_pbx_start(mychannel) < 0) {
02678       ast_log(LOG_WARNING, "Unable to start PBX!!\n");
02679       ast_hangup(mychannel);
02680       ast_hangup(genchannel);
02681       rpt_mutex_lock(&myrpt->lock);
02682       myrpt->callmode = 0;
02683       rpt_mutex_unlock(&myrpt->lock);
02684       pthread_exit(NULL);
02685    }
02686    usleep(10000);
02687    rpt_mutex_lock(&myrpt->lock);
02688    myrpt->callmode = 3;
02689    /* set appropriate conference for the pseudo */
02690    ci.chan = 0;
02691    ci.confno = myrpt->conf;
02692    ci.confmode = (myrpt->p.duplex == 2) ? DAHDI_CONF_CONFANNMON :
02693       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
02694    /* first put the channel on the conference in announce mode */
02695    if (ioctl(myrpt->pchannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
02696       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02697       ast_hangup(mychannel);
02698       ast_hangup(genchannel);
02699       myrpt->callmode = 0;
02700       pthread_exit(NULL);
02701    }
02702    while (myrpt->callmode) {
02703       if ((!mychannel->pbx) && (myrpt->callmode != 4)) {
02704          if (myrpt->patchfarenddisconnect) { /* If patch is setup for far end disconnect */
02705             myrpt->callmode = 0;
02706             if (!myrpt->patchquiet) {
02707                rpt_mutex_unlock(&myrpt->lock);
02708                rpt_telemetry(myrpt, TERM, NULL);
02709                rpt_mutex_lock(&myrpt->lock);
02710             }
02711          } else { /* Send congestion until patch is downed by command */
02712             myrpt->callmode = 4;
02713             rpt_mutex_unlock(&myrpt->lock);
02714             /* start congestion tone */
02715             tone_zone_play_tone(genchannel->fds[0], DAHDI_TONE_CONGESTION);
02716             rpt_mutex_lock(&myrpt->lock);
02717          }
02718       }
02719       if (myrpt->mydtmf) {
02720          wf.frametype = AST_FRAME_DTMF;
02721          wf.subclass = myrpt->mydtmf;
02722          wf.offset = 0;
02723          wf.mallocd = 0;
02724          wf.data = NULL;
02725          wf.datalen = 0;
02726          wf.samples = 0;
02727          rpt_mutex_unlock(&myrpt->lock);
02728          ast_write(genchannel, &wf); 
02729          rpt_mutex_lock(&myrpt->lock);
02730          myrpt->mydtmf = 0;
02731       }
02732       rpt_mutex_unlock(&myrpt->lock);
02733       usleep(MSWAIT * 1000);
02734       rpt_mutex_lock(&myrpt->lock);
02735    }
02736    rpt_mutex_unlock(&myrpt->lock);
02737    tone_zone_play_tone(genchannel->fds[0], -1);
02738    if (mychannel->pbx)
02739       ast_softhangup(mychannel, AST_SOFTHANGUP_DEV);
02740    ast_hangup(genchannel);
02741    rpt_mutex_lock(&myrpt->lock);
02742    myrpt->callmode = 0;
02743    rpt_mutex_unlock(&myrpt->lock);
02744    /* set appropriate conference for the pseudo */
02745    ci.chan = 0;
02746    ci.confno = myrpt->conf;
02747    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
02748       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
02749    /* first put the channel on the conference in announce mode */
02750    if (ioctl(myrpt->pchannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
02751       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02752    }
02753    pthread_exit(NULL);
02754 }

static int rpt_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 6809 of file app_rpt.c.

References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), f, LOG_WARNING, rpt::name, and rpt_vars.

Referenced by load_module().

06810 {
06811    int res = -1, i, rem_totx, n, phone_mode = 0;
06812    char *tmp, keyed = 0;
06813    char *options = NULL, *tele, c;
06814    struct rpt *myrpt;
06815    struct ast_frame *f;
06816    struct ast_channel *who;
06817    struct ast_channel *cs[20];
06818    struct rpt_link *l;
06819    struct dahdi_confinfo ci;  /* conference info */
06820    struct dahdi_params par;
06821    int ms, elap;
06822    AST_DECLARE_APP_ARGS(args,
06823       AST_APP_ARG(node);
06824       AST_APP_ARG(options);
06825    );
06826 
06827    if (ast_strlen_zero(data)) {
06828       ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
06829       return -1;
06830    }
06831    tmp = ast_strdupa((char *)data);
06832    AST_STANDARD_APP_ARGS(args, tmp);
06833    myrpt = NULL;
06834    /* see if we can find our specified one */
06835    for (i = 0; i < nrpts; i++) {
06836       /* if name matches, assign it and exit loop */
06837       if (!strcmp(args.node, rpt_vars[i].name)) {
06838          myrpt = &rpt_vars[i];
06839          break;
06840       }
06841    }
06842    if (myrpt == NULL) {
06843       ast_log(LOG_WARNING, "Cannot find specified system node %s\n", args.node);
06844       return -1;
06845    }
06846 
06847    /* if not phone access, must be an IAX connection */
06848    if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R'))) {
06849       phone_mode = 1;
06850       if (*options == 'D')
06851          phone_mode = 2;
06852       ast_set_callerid(chan, "0", "app_rpt user", "0");
06853    } else {
06854       if (strncmp(chan->name, "IAX2", 4)) {
06855          ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
06856          return -1;
06857       }
06858    }
06859    if (*args.options == 'R') {
06860       /* Parts of this section taken from app_parkandannounce */
06861       int m, lot, timeout = 0;
06862       char tmp[256];
06863       char *s;
06864       AST_DECLARE_APP_ARGS(optionarg,
06865          AST_APP_ARG(template);
06866          AST_APP_ARG(timeout);
06867          AST_APP_ARG(return_context);
06868       );
06869 
06870       rpt_mutex_lock(&myrpt->lock);
06871       m = myrpt->callmode;
06872       rpt_mutex_unlock(&myrpt->lock);
06873 
06874       if ((!myrpt->p.nobusyout) && m) {
06875          if (chan->_state != AST_STATE_UP) {
06876             ast_indicate(chan, AST_CONTROL_BUSY);
06877          }
06878          while (ast_safe_sleep(chan, 10000) != -1) {
06879             /* This used to be a busy loop.  It's probably better to yield the processor here. */
06880             usleep(1);
06881          }
06882          return -1;
06883       }
06884 
06885       if (chan->_state != AST_STATE_UP) {
06886          ast_answer(chan);
06887       }
06888 
06889       s = ast_strdupa(options);
06890       AST_STANDARD_APP_ARGS(optionarg, s);
06891       if (optionarg.argc == 0 || ast_strlen_zero(optionarg.template)) {
06892          ast_log(LOG_WARNING, "An announce template must be defined\n");
06893          return -1;
06894       } 
06895   
06896       if (optionarg.argc >= 2) {
06897          timeout = atoi(optionarg.timeout) * 1000;
06898       }
06899    
06900       if (!ast_strlen_zero(optionarg.return_context)) {
06901          if (ast_parseable_goto(chan, optionarg.return_context)) {
06902             ast_verb(3, "Warning: Return Context Invalid, call will return to default|s\n");
06903          }
06904       }
06905 
06906       /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
06907       before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
06908 
06909       ast_masq_park_call(chan, NULL, timeout, &lot);
06910       ast_verb(3, "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, optionarg.return_context);
06911 
06912       snprintf(tmp, sizeof(tmp), "%d,%s", lot, optionarg.template + 1);
06913       rpt_telemetry(myrpt, REV_PATCH, tmp);
06914 
06915       return 0;
06916    }
06917 
06918    if (!options) {
06919       struct ast_hostent ahp;
06920       struct hostent *hp;
06921       struct in_addr ia;
06922       char hisip[100], nodeip[100];
06923       const char *val;
06924       char *s, *s1, *s2;
06925 
06926       /* look at callerid to see what node this comes from */
06927       if (!chan->cid.cid_num) { /* if doesn't have caller id */
06928          ast_log(LOG_WARNING, "Doesn't have callerid on %s\n", args.node);
06929          return -1;
06930       }
06931 
06932       /* get his IP from IAX2 module */
06933       pbx_substitute_variables_helper(chan, "${IAXPEER(CURRENTCHANNEL)}", hisip, sizeof(hisip) - 1);
06934       if (ast_strlen_zero(hisip)) {
06935          ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
06936          return -1;
06937       }
06938       
06939       if (!strcmp(myrpt->name, chan->cid.cid_num)) {
06940          ast_log(LOG_WARNING, "Trying to link to self!!\n");
06941          return -1;
06942       }
06943 
06944       if (*(chan->cid.cid_num) < '1') {
06945          ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n", chan->cid.cid_num);
06946          return -1;
06947       }
06948 
06949       /* look for his reported node string */
06950       val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, chan->cid.cid_num);
06951       if (!val) {
06952          ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n", chan->cid.cid_num);
06953          return -1;
06954       }
06955       ast_copy_string(tmp, val, sizeof(tmp));
06956       s = tmp;
06957       s1 = strsep(&s, ",");
06958       s2 = strsep(&s, ",");
06959       if (!s2) {
06960          ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n", chan->cid.cid_num);
06961          return -1;
06962       }
06963       if (strcmp(s2, "NONE")) {
06964          hp = ast_gethostbyname(s2, &ahp);
06965          if (!hp) {
06966             ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n", chan->cid.cid_num, s2);
06967             return -1;
06968          }
06969          memcpy(&ia, hp->h_addr, sizeof(in_addr_t));
06970          ast_copy_string(nodeip, ast_inet_ntoa(ia), sizeof(nodeip));
06971          if (strcmp(hisip, nodeip)) {
06972             char *s3 = strchr(s1, '@');
06973             if (s3)
06974                s1 = s3 + 1;
06975             s3 = strchr(s1, '/');
06976             if (s3)
06977                *s3 = 0;
06978             hp = ast_gethostbyname(s1, &ahp);
06979             if (!hp) {
06980                ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n", chan->cid.cid_num, s1);
06981                return -1;
06982             }
06983             memcpy(&ia, hp->h_addr, sizeof(in_addr_t));
06984             ast_copy_string(nodeip, ast_inet_ntoa(ia), sizeof(nodeip));
06985             if (strcmp(hisip, nodeip)) {
06986                ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n", chan->cid.cid_num, nodeip, hisip);
06987                return -1;
06988             }
06989          }
06990       }
06991    }
06992 
06993    /* if is not a remote */
06994    if (!myrpt->remote) {
06995       int reconnects = 0;
06996 
06997       /* look at callerid to see what node this comes from */
06998       if (!chan->cid.cid_num) { /* if doesn't have caller id */
06999          ast_log(LOG_WARNING, "Doesnt have callerid on %s\n", args.node);
07000          return -1;
07001       }
07002 
07003       if (!strcmp(myrpt->name, chan->cid.cid_num)) {
07004          ast_log(LOG_WARNING, "Trying to link to self!!\n");
07005          return -1;
07006       }
07007       rpt_mutex_lock(&myrpt->lock);
07008       l = myrpt->links.next;
07009       /* try to find this one in queue */
07010       while (l != &myrpt->links) {
07011          if (l->name[0] == '0') {
07012             l = l->next;
07013             continue;
07014          }
07015          /* if found matching string */
07016          if (!strcmp(l->name, chan->cid.cid_num))
07017             break;
07018          l = l->next;
07019       }
07020       /* if found */
07021       if (l != &myrpt->links) {
07022          l->killme = 1;
07023          l->retries = MAX_RETRIES + 1;
07024          l->disced = 2;
07025          reconnects = l->reconnects;
07026          reconnects++;
07027          rpt_mutex_unlock(&myrpt->lock);
07028          usleep(500000);   
07029       } else 
07030          rpt_mutex_unlock(&myrpt->lock);
07031       /* establish call in tranceive mode */
07032       l = ast_calloc(1, sizeof(*l));
07033       if (!l) {
07034          ast_log(LOG_WARNING, "Unable to malloc\n");
07035          pthread_exit(NULL);
07036       }
07037       l->mode = 1;
07038       ast_copy_string(l->name, chan->cid.cid_num, sizeof(l->name));
07039       l->isremote = 0;
07040       l->chan = chan;
07041       l->connected = 1;
07042       l->hasconnected = 1;
07043       l->reconnects = reconnects;
07044       l->phonemode = phone_mode;
07045       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
07046       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
07047       /* allocate a pseudo-channel thru asterisk */
07048       l->pchan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
07049       if (!l->pchan) {
07050          ast_log(LOG_ERROR, "rpt:Sorry unable to obtain pseudo channel\n");
07051          pthread_exit(NULL);
07052       }
07053       ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
07054       ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
07055       /* make a conference for the tx */
07056       ci.chan = 0;
07057       ci.confno = myrpt->conf;
07058       ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
07059       /* first put the channel on the conference in proper mode */
07060       if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1) {
07061          ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
07062          pthread_exit(NULL);
07063       }
07064       rpt_mutex_lock(&myrpt->lock);
07065       if (phone_mode > 1)
07066          l->lastrx = 1;
07067       /* insert at end of queue */
07068       insque((struct qelem *)l, (struct qelem *)myrpt->links.next);
07069       rpt_mutex_unlock(&myrpt->lock);
07070       if (chan->_state != AST_STATE_UP) {
07071          ast_answer(chan);
07072       }
07073       return 0;
07074    }
07075    rpt_mutex_lock(&myrpt->lock);
07076    /* if remote, error if anyone else already linked */
07077    if (myrpt->remoteon) {
07078       rpt_mutex_unlock(&myrpt->lock);
07079       usleep(500000);
07080       if (myrpt->remoteon) {
07081          ast_log(LOG_WARNING, "Trying to use busy link on %s\n", args.node);
07082          return -1;
07083       }     
07084       rpt_mutex_lock(&myrpt->lock);
07085    }
07086    myrpt->remoteon = 1;
07087    if (ioperm(myrpt->p.iobase, 1, 1) == -1) {
07088       rpt_mutex_unlock(&myrpt->lock);
07089       ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n", myrpt->p.iobase);
07090       return -1;
07091    }
07092    rpt_mutex_unlock(&myrpt->lock);
07093    /* find our index, and load the vars initially */
07094    for (i = 0; i < nrpts; i++) {
07095       if (&rpt_vars[i] == myrpt) {
07096          load_rpt_vars(i, 0);
07097          break;
07098       }
07099    }
07100    rpt_mutex_lock(&myrpt->lock);
07101    tele = strchr(myrpt->rxchanname, '/');
07102    if (!tele) {
07103       ast_log(LOG_ERROR, "rpt:Dial number must be in format tech/number\n");
07104       rpt_mutex_unlock(&myrpt->lock);
07105       pthread_exit(NULL);
07106    }
07107    *tele++ = 0;
07108    myrpt->rxchannel = ast_request(myrpt->rxchanname, AST_FORMAT_SLINEAR, tele, NULL);
07109    if (myrpt->rxchannel) {
07110       ast_set_read_format(myrpt->rxchannel, AST_FORMAT_SLINEAR);
07111       ast_set_write_format(myrpt->rxchannel, AST_FORMAT_SLINEAR);
07112       myrpt->rxchannel->whentohangup = 0;
07113       myrpt->rxchannel->appl = "Apprpt";
07114       myrpt->rxchannel->data = "(Link Rx)";
07115       ast_verb(3, "rpt (Rx) initiating call to %s/%s on %s\n",
07116             myrpt->rxchanname, tele, myrpt->rxchannel->name);
07117       rpt_mutex_unlock(&myrpt->lock);
07118       ast_call(myrpt->rxchannel, tele, 999);
07119       rpt_mutex_lock(&myrpt->lock);
07120    } else {
07121       ast_log(LOG_ERROR, "rpt:Sorry unable to obtain Rx channel\n");
07122       rpt_mutex_unlock(&myrpt->lock);
07123       pthread_exit(NULL);
07124    }
07125    *--tele = '/';
07126    if (myrpt->txchanname) {
07127       tele = strchr(myrpt->txchanname, '/');
07128       if (!tele) {
07129          ast_log(LOG_ERROR, "rpt:Dial number must be in format tech/number\n");
07130          rpt_mutex_unlock(&myrpt->lock);
07131          ast_hangup(myrpt->rxchannel);
07132          pthread_exit(NULL);
07133       }
07134       *tele++ = 0;
07135       myrpt->txchannel = ast_request(myrpt->txchanname, AST_FORMAT_SLINEAR, tele, NULL);
07136       if (myrpt->txchannel) {
07137          ast_set_read_format(myrpt->txchannel, AST_FORMAT_SLINEAR);
07138          ast_set_write_format(myrpt->txchannel, AST_FORMAT_SLINEAR);
07139          myrpt->txchannel->whentohangup = 0;
07140          myrpt->txchannel->appl = "Apprpt";
07141          myrpt->txchannel->data = "(Link Tx)";
07142          ast_verb(3, "rpt (Tx) initiating call to %s/%s on %s\n",
07143                myrpt->txchanname, tele, myrpt->txchannel->name);
07144          rpt_mutex_unlock(&myrpt->lock);
07145          ast_call(myrpt->txchannel, tele, 999);
07146          rpt_mutex_lock(&myrpt->lock);
07147       } else {
07148          ast_log(LOG_ERROR, "rpt:Sorry unable to obtain Tx channel\n");
07149          rpt_mutex_unlock(&myrpt->lock);
07150          ast_hangup(myrpt->rxchannel);
07151          pthread_exit(NULL);
07152       }
07153       *--tele = '/';
07154    } else {
07155       myrpt->txchannel = myrpt->rxchannel;
07156    }
07157    myrpt->remoterx = 0;
07158    myrpt->remotetx = 0;
07159    myrpt->retxtimer = 0;
07160    myrpt->remoteon = 1;
07161    myrpt->dtmfidx = -1;
07162    myrpt->dtmfbuf[0] = 0;
07163    myrpt->dtmf_time_rem = 0;
07164    myrpt->hfscanmode = 0;
07165    myrpt->hfscanstatus = 0;
07166    if (myrpt->p.startupmacro) {
07167       myrpt->remchannel = chan; /* Save copy of channel */
07168       snprintf(myrpt->macrobuf, sizeof(myrpt->macrobuf), "PPPP%s", myrpt->p.startupmacro);
07169    }
07170    if (myrpt->p.startupgosub) {
07171       myrpt->remchannel = chan; /* Save copy of channel */
07172       snprintf(myrpt->gosubbuf, sizeof(myrpt->gosubbuf), "PPPP%s", myrpt->p.startupgosub);
07173    }
07174    myrpt->reload = 0;
07175    rpt_mutex_unlock(&myrpt->lock);
07176    setrem(myrpt); 
07177    ast_set_write_format(chan, AST_FORMAT_SLINEAR);
07178    ast_set_read_format(chan, AST_FORMAT_SLINEAR);
07179    /* if we are on 2w loop and are a remote, turn EC on */
07180    if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel)) {
07181       i = 128;
07182       ioctl(myrpt->rxchannel->fds[0], DAHDI_ECHOCANCEL, &i);
07183    }
07184    if (chan->_state != AST_STATE_UP) {
07185       ast_answer(chan);
07186    }
07187 
07188    if (ioctl(myrpt->txchannel->fds[0], DAHDI_GET_PARAMS, &par) != -1) {
07189       if (par.rxisoffhook) {
07190          ast_indicate(chan, AST_CONTROL_RADIO_KEY);
07191          myrpt->remoterx = 1;
07192       }
07193    }
07194    n = 0;
07195    cs[n++] = chan;
07196    cs[n++] = myrpt->rxchannel;
07197    if (myrpt->rxchannel != myrpt->txchannel)
07198       cs[n++] = myrpt->txchannel;
07199    for (;;) {
07200       if (ast_check_hangup(chan))
07201          break;
07202       if (ast_check_hangup(myrpt->rxchannel))
07203          break;
07204       if (myrpt->reload) {
07205          myrpt->reload = 0;
07206          rpt_mutex_unlock(&myrpt->lock);
07207          /* find our index, and load the vars */
07208          for (i = 0; i < nrpts; i++) {
07209             if (&rpt_vars[i] == myrpt) {
07210                load_rpt_vars(i, 0);
07211                break;
07212             }
07213          }
07214          rpt_mutex_lock(&myrpt->lock);
07215       }
07216       ms = MSWAIT;
07217       who = ast_waitfor_n(cs, n, &ms);
07218       if (who == NULL)
07219          ms = 0;
07220       elap = MSWAIT - ms;
07221       if (myrpt->macrotimer)
07222          myrpt->macrotimer -= elap;
07223       if (myrpt->macrotimer < 0)
07224          myrpt->macrotimer = 0;
07225       if (myrpt->gosubtimer)
07226          myrpt->gosubtimer -= elap;
07227       if (myrpt->gosubtimer < 0)
07228          myrpt->gosubtimer = 0;
07229       rpt_mutex_unlock(&myrpt->lock);
07230       if (!ms)
07231          continue;
07232       rem_totx = keyed;
07233       
07234       
07235       if ((!myrpt->remoterx) && (!myrpt->remotetx)) {
07236          if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME) {
07237             myrpt->retxtimer = 0;
07238             ast_indicate(chan, AST_CONTROL_RADIO_UNKEY);
07239          }
07240       } else
07241          myrpt->retxtimer = 0;
07242       if (rem_totx && (!myrpt->remotetx)) { /* Remote base radio TX key */
07243          myrpt->remotetx = 1;
07244          ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_KEY);
07245       }
07246       if ((!rem_totx) && myrpt->remotetx) { /* Remote base radio TX unkey */
07247          myrpt->remotetx = 0;
07248          ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
07249       }
07250 
07251       if (myrpt->tunerequest && (!strcmp(myrpt->remote, remote_rig_ft897))) { /* ft-897 specific for now... */
07252          myrpt->tunerequest = 0;
07253          set_mode_ft897(myrpt, REM_MODE_AM);
07254          simple_command_ft897(myrpt, 8);
07255          myrpt->remotetx = 0;
07256          ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
07257          if (!myrpt->remoterx)
07258             ast_indicate(chan, AST_CONTROL_RADIO_KEY);
07259          if (play_tone(chan, 800, 6000, 8192) == -1)
07260             break;
07261 
07262          rmt_telem_finish(myrpt, chan);
07263          set_mode_ft897(myrpt, 0x88);
07264          setrem(myrpt);
07265       }
07266    
07267       if (myrpt->hfscanmode) {
07268          myrpt->scantimer -= elap;
07269          if (myrpt->scantimer <= 0) {
07270             myrpt->scantimer = REM_SCANTIME;
07271             service_scan(myrpt);
07272          }
07273       }
07274       if (who == chan) { /* if it was a read from incoming */
07275          f = ast_read(chan);
07276          if (!f) {
07277             ast_debug(1, "@@@@ link:Hung Up\n");
07278             break;
07279          }
07280          if (f->frametype == AST_FRAME_VOICE) {
07281             /* if not transmitting, zero-out audio */
07282             if (!myrpt->remotetx)
07283                memset(f->data, 0, f->datalen);
07284             ast_write(myrpt->txchannel, f);
07285          }
07286          if (f->frametype == AST_FRAME_DTMF) {
07287             myrpt->remchannel = chan; /* Save copy of channel */
07288             if (handle_remote_phone_dtmf(myrpt, f->subclass, &keyed, phone_mode) == -1) {
07289                ast_debug(1, "@@@@ rpt:Hung Up\n");
07290                ast_frfree(f);
07291                break;
07292             }
07293          }
07294          if (f->frametype == AST_FRAME_TEXT) {
07295             myrpt->remchannel = chan; /* Save copy of channel */
07296             if (handle_remote_data(myrpt, f->data) == -1) {
07297                ast_debug(1, "@@@@ rpt:Hung Up\n");
07298                ast_frfree(f);
07299                break;
07300             }
07301          }
07302          if (f->frametype == AST_FRAME_CONTROL) {
07303             if (f->subclass == AST_CONTROL_HANGUP) {
07304                ast_debug(1, "@@@@ rpt:Hung Up\n");
07305                ast_frfree(f);
07306                break;
07307             }
07308             /* if RX key */
07309             if (f->subclass == AST_CONTROL_RADIO_KEY) {
07310                ast_debug(8, "@@@@ rx key\n");
07311                keyed = 1;
07312             }
07313             /* if RX un-key */
07314             if (f->subclass == AST_CONTROL_RADIO_UNKEY) {
07315                ast_debug(8, "@@@@ rx un-key\n");
07316                keyed = 0;
07317             }
07318          }
07319          if (myrpt->hfscanstatus) {
07320             myrpt->remchannel = chan; /* Save copy of channel */
07321             myrpt->remotetx = 0;
07322             ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
07323             if (!myrpt->remoterx) {
07324                ast_indicate(myrpt->remchannel, AST_CONTROL_RADIO_KEY);
07325             }
07326             if (myrpt->hfscanstatus < 0) {
07327                if (myrpt->hfscanstatus == -1) {
07328                   if (ast_safe_sleep(myrpt->remchannel, 1000) == -1)
07329                      break;
07330                }
07331                sayfile(myrpt->remchannel, "rpt/stop");
07332             } else {
07333                saynum(myrpt->remchannel, myrpt->hfscanstatus );
07334             }  
07335             rmt_telem_finish(myrpt, myrpt->remchannel);
07336             myrpt->hfscanstatus = 0;
07337          }
07338          ast_frfree(f);
07339          rpt_mutex_lock(&myrpt->lock);
07340          c = myrpt->macrobuf[0];
07341          if (c && (!myrpt->macrotimer)) {
07342             myrpt->macrotimer = MACROTIME;
07343             memmove(myrpt->macrobuf, myrpt->macrobuf + 1, sizeof(myrpt->macrobuf) - 1);
07344             if ((c == 'p') || (c == 'P'))
07345                myrpt->macrotimer = MACROPTIME;
07346             rpt_mutex_unlock(&myrpt->lock);
07347             if (handle_remote_dtmf_digit(myrpt, c, &keyed, 0) == -1)
07348                break;
07349             continue;
07350          }
07351          c = myrpt->gosubbuf[0];
07352          if (c && (!myrpt->gosubtimer)) {
07353             myrpt->gosubtimer = GOSUBTIME;
07354             memmove(myrpt->gosubbuf, myrpt->gosubbuf + 1, sizeof(myrpt->gosubbuf) - 1);
07355             if ((c == 'p') || (c == 'P'))
07356                myrpt->gosubtimer = GOSUBPTIME;
07357             rpt_mutex_unlock(&myrpt->lock);
07358             if (handle_remote_dtmf_digit(myrpt, c, &keyed, 0) == -1)
07359                break;
07360             continue;
07361          } 
07362          rpt_mutex_unlock(&myrpt->lock);
07363          continue;
07364       }
07365       if (who == myrpt->rxchannel) { /* if it was a read from radio */
07366          f = ast_read(myrpt->rxchannel);
07367          if (!f) {
07368             ast_debug(1, "@@@@ link:Hung Up\n");
07369             break;
07370          }
07371          if (f->frametype == AST_FRAME_VOICE) {
07372             if ((myrpt->remote) && (myrpt->remotetx))
07373                memset(f->data, 0, f->datalen);
07374              ast_write(chan, f);
07375          } else if (f->frametype == AST_FRAME_CONTROL) {
07376             if (f->subclass == AST_CONTROL_HANGUP) {
07377                ast_debug(1, "@@@@ rpt:Hung Up\n");
07378                ast_frfree(f);
07379                break;
07380             }
07381             /* if RX key */
07382             if (f->subclass == AST_CONTROL_RADIO_KEY) {
07383                ast_debug(8, "@@@@ remote rx key\n");
07384                if (!myrpt->remotetx) {
07385                   ast_indicate(chan, AST_CONTROL_RADIO_KEY);
07386                   myrpt->remoterx = 1;
07387                }
07388             }
07389             /* if RX un-key */
07390             if (f->subclass == AST_CONTROL_RADIO_UNKEY) {
07391                ast_debug(8, "@@@@ remote rx un-key\n");
07392                if (!myrpt->remotetx) {
07393                   ast_indicate(chan, AST_CONTROL_RADIO_UNKEY);
07394                   myrpt->remoterx = 0;
07395                }
07396             }
07397          }
07398          ast_frfree(f);
07399          continue;
07400       }
07401       if ((myrpt->rxchannel != myrpt->txchannel) && (who == myrpt->txchannel)) {
07402          /* do this cuz you have to */
07403          f = ast_read(myrpt->txchannel);
07404          if (!f) {
07405             ast_debug(1, "@@@@ link:Hung Up\n");
07406             break;
07407          }
07408          if (f->frametype == AST_FRAME_CONTROL) {
07409             if (f->subclass == AST_CONTROL_HANGUP) {
07410                ast_debug(1, "@@@@ rpt:Hung Up\n");
07411                ast_frfree(f);
07412                break;
07413             }
07414          }
07415          ast_frfree(f);
07416          continue;
07417       }
07418 
07419    }
07420    rpt_mutex_lock(&myrpt->lock);
07421    if (myrpt->rxchannel != myrpt->txchannel)
07422       ast_hangup(myrpt->txchannel);
07423    ast_hangup(myrpt->rxchannel);
07424    myrpt->hfscanmode = 0;
07425    myrpt->hfscanstatus = 0;
07426    myrpt->remoteon = 0;
07427    rpt_mutex_unlock(&myrpt->lock);
07428    closerem(myrpt);
07429    return res;
07430 }

static void* rpt_master ( void *  config  )  [static]

Definition at line 6706 of file app_rpt.c.

References ast_category_browse(), ast_cli_command(), ast_config_destroy(), ast_copy_string(), ast_log(), ast_mutex_init(), ast_pthread_create_detached, AST_PTHREADT_NULL, AST_PTHREADT_STOP, ast_strdup, ast_variable_retrieve(), rpt::cfg, rpt::ident, rpt::lastthreadrestarttime, load_rpt_vars(), lock, LOG_ERROR, LOG_NOTICE, LOG_WARNING, name, rpt::name, rpt_tele::next, rpt::offset, rpt::powerlevel, rpt_tele::prev, REM_MEDPWR, REM_MODE_FM, REM_SIMPLEX, rpt::remmode, rpt::remote, rpt::rpt_thread, rpt_vars, rpt::rxchanname, rpt::tailmessagen, rpt::tele, rpt::threadrestarts, and rpt::txchanname.

Referenced by load_module().

06707 {
06708    int   i, n;
06709    struct ast_config *cfg;
06710    char *this;
06711    const char *val;
06712 
06713    /* go thru all the specified repeaters */
06714    this = NULL;
06715    n = 0;
06716    rpt_vars[n].cfg = config;
06717    cfg = rpt_vars[n].cfg;
06718    if (!cfg) {
06719       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
06720       pthread_exit(NULL);
06721    }
06722    while ((this = ast_category_browse(cfg, this)) != NULL) {
06723       for (i = 0; i < strlen(this); i++) {
06724          if ((this[i] < '0') || (this[i] > '9'))
06725             break;
06726       }
06727       if (i != strlen(this))
06728          continue; /* Not a node defn */
06729       memset(&rpt_vars[n], 0, sizeof(rpt_vars[n]));
06730       rpt_vars[n].name = ast_strdup(this);
06731       val = ast_variable_retrieve(cfg, this, "rxchannel");
06732       if (val)
06733          rpt_vars[n].rxchanname = ast_strdup(val);
06734       val = ast_variable_retrieve(cfg, this, "txchannel");
06735       if (val)
06736          rpt_vars[n].txchanname = ast_strdup(val);
06737       val = ast_variable_retrieve(cfg, this, "remote");
06738       if (val)
06739          rpt_vars[n].remote = ast_strdup(val);
06740       ast_mutex_init(&rpt_vars[n].lock);
06741       rpt_vars[n].tele.next = &rpt_vars[n].tele;
06742       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
06743       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
06744       rpt_vars[n].tailmessagen = 0;
06745 #ifdef   _MDC_DECODE_H_
06746       rpt_vars[n].mdc = mdc_decoder_new(8000);
06747 #endif
06748       n++;
06749    }
06750    nrpts = n;
06751    ast_config_destroy(cfg);
06752 
06753    /* start em all */
06754    for (i = 0; i < n; i++) {
06755       load_rpt_vars(i, 1);
06756 
06757       /* if is a remote, dont start one for it */
06758       if (rpt_vars[i].remote) {
06759          ast_copy_string(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq));
06760          ast_copy_string(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl));
06761          ast_copy_string(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl));
06762          rpt_vars[i].remmode = REM_MODE_FM;
06763          rpt_vars[i].offset = REM_SIMPLEX;
06764          rpt_vars[i].powerlevel = REM_MEDPWR;
06765          continue;
06766       }
06767       if (!rpt_vars[i].p.ident) {
06768          ast_log(LOG_WARNING, "Did not specify ident for node %s\n", rpt_vars[i].name);
06769          ast_config_destroy(cfg);
06770          pthread_exit(NULL);
06771       }
06772       ast_pthread_create_detached(&rpt_vars[i].rpt_thread, NULL, rpt, (void *) &rpt_vars[i]);
06773    }
06774    usleep(500000);
06775    for (;;) {
06776       /* Now monitor each thread, and restart it if necessary */
06777       for (i = 0; i < n; i++) { 
06778          int rv;
06779          if (rpt_vars[i].remote)
06780             continue;
06781          if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP) 
06782             rv = -1;
06783          else
06784             rv = pthread_kill(rpt_vars[i].rpt_thread, 0);
06785          if (rv) {
06786             if (time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15) {
06787                if (rpt_vars[i].threadrestarts >= 5) {
06788                   ast_log(LOG_ERROR, "Continual RPT thread restarts, killing Asterisk\n");
06789                   ast_cli_command(STDERR_FILENO, "restart now");
06790                } else {
06791                   ast_log(LOG_NOTICE, "RPT thread restarted on %s\n", rpt_vars[i].name);
06792                   rpt_vars[i].threadrestarts++;
06793                }
06794             } else
06795                rpt_vars[i].threadrestarts = 0;
06796 
06797             rpt_vars[i].lastthreadrestarttime = time(NULL);
06798             ast_pthread_create_detached(&rpt_vars[i].rpt_thread, NULL, rpt, (void *) &rpt_vars[i]);
06799             ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
06800          }
06801 
06802       }
06803       sleep(2);
06804    }
06805    ast_config_destroy(cfg);
06806    pthread_exit(NULL);
06807 }

static void* rpt_tele_thread ( void *  this  )  [static]

Definition at line 1893 of file app_rpt.c.

References ARB_ALPHA, AST_FORMAT_SLINEAR, ast_free, ast_hangup(), ast_localtime(), ast_log(), ast_malloc, ast_mutex_lock(), ast_mutex_unlock(), ast_request(), ast_safe_sleep(), ast_say_character_str(), ast_say_digits(), ast_say_number(), ast_say_time, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_tonepair_start(), ast_tvnow(), ast_variable_retrieve(), ast_waitstream(), rpt::callmode, rpt::cfg, rpt_tele::chan, rpt::cmdnode, COMPLETE, rpt::conf, CONNECTED, rpt_link::connected, CONNFAIL, rpt::dailykerchunks, DLY_CALLTERM, DLY_ID, DLY_TELEM, DLY_UNKEY, ast_channel::fds, get_wait_interval(), GOSUB_BUSY, GOSUB_NOTFOUND, ID, ID1, rpt::ident, IDTALKOVER, rpt_link::isremote, rpt::keyed, ast_channel::language, LASTNODEKEY, rpt::lastnodewhichkeyedusup, rpt::links, rpt::lock, LOG_NOTICE, LOG_WARNING, MACRO_BUSY, MACRO_NOTFOUND, rpt_link::mode, rpt_tele::mode, rpt_tele::mylink, ast_channel::name, rpt_link::name, rpt::name, rpt_link::next, rpt_tele::next, rpt::p, rpt_tele::param, rpt::patchnoct, rpt_link::prev, PROC, REMALREADY, REMDISC, REMGO, REMNOTFOUND, REV_PATCH, rpt_tele::rpt, rpt_mutex_lock, rpt_mutex_unlock, saycharstr(), sayfile(), STATS_TIME, STATS_VERSION, STATUS, rpt::stopgen, strsep(), rpt::tailmessagen, rpt::tailmsg, TAILMSG, rpt::tailsquashedtime, rpt::tele, telem_any(), telem_lookup(), TERM, TEST_TONE, TIMEOUT, ast_tm::tm_hour, rpt::tmsgtimer, rpt::totalkerchunks, rpt::txconf, UNKEY, rpt::unkeytocttimer, and wait_interval().

Referenced by rpt_telemetry().

01894 {
01895    struct dahdi_confinfo ci;  /* conference info */
01896    int   res = 0, haslink, hastx, hasremote, imdone = 0, unkeys_queued, x;
01897    struct rpt_tele *mytele = (struct rpt_tele *)this;
01898    struct rpt_tele *tlist;
01899    struct rpt *myrpt;
01900    struct rpt_link *l, *m, linkbase;
01901    struct ast_channel *mychannel;
01902    const char *p, *ct;
01903    struct timeval tv;
01904    struct ast_tm localtm;
01905 #ifdef  APP_RPT_LOCK_DEBUG
01906    struct lockthread *t;
01907 #endif
01908 
01909    /* get a pointer to myrpt */
01910    myrpt = mytele->rpt;
01911 
01912    /* Snag copies of a few key myrpt variables */
01913    rpt_mutex_lock(&myrpt->lock);
01914    rpt_mutex_unlock(&myrpt->lock);
01915    
01916    /* allocate a pseudo-channel thru asterisk */
01917    mychannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
01918    if (!mychannel) {
01919       ast_log(LOG_WARNING, "rpt: unable to obtain pseudo channel\n");
01920       rpt_mutex_lock(&myrpt->lock);
01921       remque((struct qelem *)mytele);
01922       ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode); /*@@@@@@@@@@@*/
01923       rpt_mutex_unlock(&myrpt->lock);
01924       ast_free(mytele);
01925       pthread_exit(NULL);
01926    }
01927    rpt_mutex_lock(&myrpt->lock);
01928    mytele->chan = mychannel; /* Save a copy of the channel so we can access it externally if need be */
01929    rpt_mutex_unlock(&myrpt->lock);
01930    
01931    /* make a conference for the tx */
01932    ci.chan = 0;
01933    /* If there's an ID queued, or tail message queued, */
01934    /* only connect the ID audio to the local tx conference so */
01935    /* linked systems can't hear it */
01936    ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
01937       (mytele->mode == TAILMSG)) ?
01938          myrpt->txconf : myrpt->conf);
01939    ci.confmode = DAHDI_CONF_CONFANN;
01940    /* first put the channel on the conference in announce mode */
01941    if (ioctl(mychannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
01942       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
01943       rpt_mutex_lock(&myrpt->lock);
01944       remque((struct qelem *)mytele);
01945       rpt_mutex_unlock(&myrpt->lock);
01946       ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode); /*@@@@@@@@@@@*/
01947       ast_free(mytele);
01948       ast_hangup(mychannel);
01949       pthread_exit(NULL);
01950    }
01951    ast_stopstream(mychannel);
01952    switch (mytele->mode) {
01953    case ID:
01954    case ID1:
01955       /* wait a bit */
01956       wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM, mychannel);
01957       res = telem_any(myrpt, mychannel, myrpt->p.ident); 
01958       imdone=1;   
01959       break;
01960       
01961    case TAILMSG:
01962       res = ast_streamfile(mychannel, myrpt->p.tailmsg.msgs[myrpt->tailmessagen], mychannel->language); 
01963       break;
01964       
01965    case IDTALKOVER:
01966       p = ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
01967       if (p)
01968          res = telem_any(myrpt, mychannel, p); 
01969       imdone = 1; 
01970       break;
01971    case PROC:
01972       /* wait a little bit longer */
01973       wait_interval(myrpt, DLY_TELEM, mychannel);
01974       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
01975       if (res < 0) { /* Then default message */
01976          res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
01977       }
01978       break;
01979    case TERM:
01980       /* wait a little bit longer */
01981       wait_interval(myrpt, DLY_CALLTERM, mychannel);
01982       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
01983       if (res < 0) { /* Then default message */
01984          res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
01985       }
01986       break;
01987    case COMPLETE:
01988       /* wait a little bit */
01989       wait_interval(myrpt, DLY_TELEM, mychannel);
01990       res = telem_lookup(myrpt, mychannel, myrpt->name, "functcomplete");
01991       break;
01992    case MACRO_NOTFOUND:
01993       /* wait a little bit */
01994       wait_interval(myrpt, DLY_TELEM, mychannel);
01995       res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
01996       break;
01997    case GOSUB_NOTFOUND:
01998       /* wait a little bit */
01999       wait_interval(myrpt, DLY_TELEM, mychannel);
02000       res = ast_streamfile(mychannel, "rpt/gosub_notfound", mychannel->language);
02001       break;
02002    case MACRO_BUSY:
02003       /* wait a little bit */
02004       wait_interval(myrpt, DLY_TELEM, mychannel);
02005       res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
02006       break;
02007    case GOSUB_BUSY:
02008       /* wait a little bit */
02009       wait_interval(myrpt, DLY_TELEM, mychannel);
02010       res = ast_streamfile(mychannel, "rpt/gosub_busy", mychannel->language);
02011       break;
02012    case UNKEY:
02013       if (myrpt->patchnoct && myrpt->callmode) { /* If no CT during patch configured, then don't send one */
02014          imdone = 1;
02015          break;
02016       }
02017          
02018       /*
02019       * Reset the Unkey to CT timer
02020       */
02021 
02022       x = get_wait_interval(myrpt, DLY_UNKEY);
02023       rpt_mutex_lock(&myrpt->lock);
02024       myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
02025       rpt_mutex_unlock(&myrpt->lock);
02026 
02027       /*
02028       * If there's one already queued, don't do another
02029       */
02030 
02031       tlist = myrpt->tele.next;
02032       unkeys_queued = 0;
02033       if (tlist != &myrpt->tele) {
02034          rpt_mutex_lock(&myrpt->lock);
02035          while (tlist != &myrpt->tele) {
02036             if (tlist->mode == UNKEY)
02037                unkeys_queued++;
02038             tlist = tlist->next;
02039          }
02040          rpt_mutex_unlock(&myrpt->lock);
02041       }
02042       if (unkeys_queued > 1) {
02043          imdone = 1;
02044          break;
02045       }
02046 
02047       /* Wait for the telemetry timer to expire */
02048       /* Periodically check the timer since it can be re-initialized above */
02049       while (myrpt->unkeytocttimer) {
02050          int ctint;
02051          if (myrpt->unkeytocttimer > 100)
02052             ctint = 100;
02053          else
02054             ctint = myrpt->unkeytocttimer;
02055          ast_safe_sleep(mychannel, ctint);
02056          rpt_mutex_lock(&myrpt->lock);
02057          if (myrpt->unkeytocttimer < ctint)
02058             myrpt->unkeytocttimer = 0;
02059          else
02060             myrpt->unkeytocttimer -= ctint;
02061          rpt_mutex_unlock(&myrpt->lock);
02062       }
02063    
02064       /*
02065       * Now, the carrier on the rptr rx should be gone. 
02066       * If it re-appeared, then forget about sending the CT
02067       */
02068       if (myrpt->keyed) {
02069          imdone = 1;
02070          break;
02071       }
02072       
02073       rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
02074       myrpt->dailykerchunks++;
02075       myrpt->totalkerchunks++;
02076       rpt_mutex_unlock(&myrpt->lock);
02077    
02078       haslink = 0;
02079       hastx = 0;
02080       hasremote = 0;    
02081       l = myrpt->links.next;
02082       if (l != &myrpt->links) {
02083          rpt_mutex_lock(&myrpt->lock);
02084          while (l != &myrpt->links) {
02085             if (l->name[0] == '0') {
02086                l = l->next;
02087                continue;
02088             }
02089             haslink = 1;
02090             if (l->mode) {
02091                hastx++;
02092                if (l->isremote)
02093                   hasremote++;
02094             }
02095             l = l->next;
02096          }
02097          rpt_mutex_unlock(&myrpt->lock);
02098       }
02099       if (haslink) {
02100          res = telem_lookup(myrpt, mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
02101          if (res)
02102             ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
02103 
02104          /* if in remote cmd mode, indicate it */
02105          if (myrpt->cmdnode[0]) {
02106             ast_safe_sleep(mychannel, 200);
02107             res = telem_lookup(myrpt, mychannel, myrpt->name, "cmdmode");
02108             if (res)
02109                ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
02110             ast_stopstream(mychannel);
02111          }
02112       } else if ((ct = ast_variable_retrieve(myrpt->cfg, myrpt->name, "unlinkedct"))) { /* Unlinked Courtesy Tone */
02113          res = telem_lookup(myrpt, mychannel, myrpt->name, ct);
02114          if (res)
02115             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
02116       }  
02117       if (hasremote && (!myrpt->cmdnode[0])) {
02118          /* set for all to hear */
02119          ci.chan = 0;
02120          ci.confno = myrpt->conf;
02121          ci.confmode = DAHDI_CONF_CONFANN;
02122          /* first put the channel on the conference in announce mode */
02123          if (ioctl(mychannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
02124             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02125             rpt_mutex_lock(&myrpt->lock);
02126             remque((struct qelem *)mytele);
02127             rpt_mutex_unlock(&myrpt->lock);
02128             ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode); /*@@@@@@@@@@@*/
02129             ast_free(mytele);
02130             ast_hangup(mychannel);
02131             pthread_exit(NULL);
02132          }
02133          if ((ct = ast_variable_retrieve(myrpt->cfg, myrpt->name, "remotect"))) { /* Unlinked Courtesy Tone */
02134             ast_safe_sleep(mychannel, 200);
02135             res = telem_lookup(myrpt, mychannel, myrpt->name, ct);
02136             if (res)
02137                ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
02138          }  
02139       }
02140 #ifdef   _MDC_DECODE_H_
02141       if (myrpt->lastunit) {
02142          char mystr[10];
02143 
02144          ast_safe_sleep(mychannel, 200);
02145          /* set for all to hear */
02146          ci.chan = 0;
02147          ci.confno = myrpt->txconf;
02148          ci.confmode = DAHDI_CONF_CONFANN;
02149          /* first put the channel on the conference in announce mode */
02150          if (ioctl(mychannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
02151             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02152             rpt_mutex_lock(&myrpt->lock);
02153             remque((struct qelem *)mytele);
02154             rpt_mutex_unlock(&myrpt->lock);
02155             ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode); /*@@@@@@@@@@@*/
02156             ast_free(mytele);    
02157             ast_hangup(mychannel);
02158             pthread_exit(NULL);
02159          }
02160          snprintf(mystr, sizeof(mystr), "%04x", myrpt->lastunit);
02161          myrpt->lastunit = 0;
02162          ast_say_character_str(mychannel, mystr, NULL, mychannel->language);
02163          break;
02164       }
02165 #endif
02166       imdone = 1;
02167       break;
02168    case REMDISC:
02169       /* wait a little bit */
02170       wait_interval(myrpt, DLY_TELEM, mychannel);
02171       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02172       if (!res) 
02173          res = ast_waitstream(mychannel, "");
02174       else
02175           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02176       ast_stopstream(mychannel);
02177       ast_say_character_str(mychannel, mytele->mylink.name, NULL, mychannel->language);
02178       res = ast_streamfile(mychannel, ((mytele->mylink.connected) ? 
02179          "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
02180       break;
02181    case REMALREADY:
02182       /* wait a little bit */
02183       wait_interval(myrpt, DLY_TELEM, mychannel);
02184       res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
02185       break;
02186    case REMNOTFOUND:
02187       /* wait a little bit */
02188       wait_interval(myrpt, DLY_TELEM, mychannel);
02189       res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
02190       break;
02191    case REMGO:
02192       /* wait a little bit */
02193       wait_interval(myrpt, DLY_TELEM, mychannel);
02194       res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
02195       break;
02196    case CONNECTED:
02197       /* wait a little bit */
02198       wait_interval(myrpt, DLY_TELEM,  mychannel);
02199       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02200       if (!res) 
02201          res = ast_waitstream(mychannel, "");
02202       else
02203           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02204       ast_stopstream(mychannel);
02205       ast_say_character_str(mychannel, mytele->mylink.name, NULL, mychannel->language);
02206       res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
02207       break;
02208    case CONNFAIL:
02209       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02210       if (!res) 
02211          res = ast_waitstream(mychannel, "");
02212       else
02213           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02214       ast_stopstream(mychannel);
02215       ast_say_character_str(mychannel, mytele->mylink.name, NULL, mychannel->language);
02216       res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
02217       break;
02218    case STATUS:
02219       /* wait a little bit */
02220       wait_interval(myrpt, DLY_TELEM, mychannel);
02221       hastx = 0;
02222       linkbase.next = &linkbase;
02223       linkbase.prev = &linkbase;
02224       rpt_mutex_lock(&myrpt->lock);
02225       /* make our own list of links */
02226       l = myrpt->links.next;
02227       while (l != &myrpt->links) {
02228          if (l->name[0] == '0') {
02229             l = l->next;
02230             continue;
02231          }
02232          m = ast_malloc(sizeof(*m));
02233          if (!m) {
02234             ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
02235             remque((struct qelem *)mytele);
02236             rpt_mutex_unlock(&myrpt->lock);
02237             ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode); /*@@@@@@@@@@@*/
02238             ast_free(mytele);
02239             ast_hangup(mychannel);
02240             pthread_exit(NULL);
02241          }
02242          memcpy(m, l, sizeof(struct rpt_link));
02243          m->next = m->prev = NULL;
02244          insque((struct qelem *)m, (struct qelem *)linkbase.next);
02245          l = l->next;
02246       }
02247       rpt_mutex_unlock(&myrpt->lock);
02248       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02249       if (!res)
02250          res = ast_waitstream(mychannel, "");
02251       else
02252           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02253       ast_stopstream(mychannel);
02254       ast_say_character_str(mychannel, myrpt->name, NULL, mychannel->language);
02255       if (!res) 
02256          res = ast_waitstream(mychannel, "");
02257       else
02258           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02259       ast_stopstream(mychannel);
02260       if (myrpt->callmode) {
02261          hastx = 1;
02262          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
02263          if (!res)
02264             res = ast_waitstream(mychannel, "");
02265          else
02266              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02267          ast_stopstream(mychannel);
02268       }
02269       l = linkbase.next;
02270       while (l != &linkbase) {
02271          hastx = 1;
02272          res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02273          if (!res) 
02274             res = ast_waitstream(mychannel, "");
02275          else
02276             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02277          ast_stopstream(mychannel);
02278          ast_say_character_str(mychannel, l->name, NULL, mychannel->language);
02279          if (!res) 
02280             res = ast_waitstream(mychannel, "");
02281          else
02282              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02283          ast_stopstream(mychannel);
02284          res = ast_streamfile(mychannel, ((l->mode) ? 
02285             "rpt/tranceive" : "rpt/monitor"), mychannel->language);
02286          if (!res) 
02287             res = ast_waitstream(mychannel, "");
02288          else
02289             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02290          ast_stopstream(mychannel);
02291          l = l->next;
02292       }        
02293       if (!hastx) {
02294          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
02295          if (!res) 
02296             res = ast_waitstream(mychannel, "");
02297          else
02298              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02299          ast_stopstream(mychannel);
02300       }
02301       /* destroy our local link queue */
02302       l = linkbase.next;
02303       while (l != &linkbase) {
02304          m = l;
02305          l = l->next;
02306          remque((struct qelem *)m);
02307          ast_free(m);
02308       }        
02309       imdone = 1;
02310       break;
02311 
02312    case LASTNODEKEY: /* Identify last node which keyed us up */
02313       rpt_mutex_lock(&myrpt->lock);
02314       if (myrpt->lastnodewhichkeyedusup)
02315          p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
02316       else
02317          p = NULL;
02318       rpt_mutex_unlock(&myrpt->lock);
02319       if (!p) {
02320          imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
02321          break;
02322       }
02323       wait_interval(myrpt, DLY_TELEM, mychannel);
02324       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02325       if (!res) 
02326          res = ast_waitstream(mychannel, "");
02327       else
02328           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02329       ast_stopstream(mychannel);
02330       ast_say_character_str(mychannel, p, NULL, mychannel->language);
02331       if (!res) 
02332          res = ast_waitstream(mychannel, "");
02333       else
02334          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02335       ast_stopstream(mychannel);
02336       imdone = 1;
02337       break;      
02338 
02339    case TIMEOUT:
02340       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02341       if (!res) 
02342          res = ast_waitstream(mychannel, "");
02343       else
02344           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02345       ast_stopstream(mychannel);
02346       ast_say_character_str(mychannel, myrpt->name, NULL, mychannel->language);
02347       res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
02348       break;
02349       
02350    case STATS_TIME:
02351       wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
02352       tv = ast_tvnow();
02353       ast_localtime(&tv, &localtm, NULL);
02354       /* Say the phase of the day is before the time */
02355       if ((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
02356          p = "rpt/goodmorning";
02357       else if ((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
02358          p = "rpt/goodafternoon";
02359       else
02360          p = "rpt/goodevening";
02361       if (sayfile(mychannel, p) == -1) {
02362          imdone = 1;
02363          break;
02364       }
02365       /* Say the time is ... */     
02366       if (sayfile(mychannel, "rpt/thetimeis") == -1) {
02367          imdone = 1;
02368          break;
02369       }
02370       /* Say the time */            
02371       res = ast_say_time(mychannel, tv.tv_sec, "", mychannel->language);
02372       if (!res) 
02373          res = ast_waitstream(mychannel, "");
02374       ast_stopstream(mychannel);    
02375       imdone = 1;
02376          break;
02377    case STATS_VERSION:
02378       wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
02379       /* Say "version" */
02380       if (sayfile(mychannel, "rpt/version") == -1) {
02381          imdone = 1;
02382          break;
02383       }
02384       if (!res) /* Say "X" */
02385          ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
02386       if (!res) 
02387          res = ast_waitstream(mychannel, "");
02388       ast_stopstream(mychannel); 
02389       if (saycharstr(mychannel, ".") == -1) {
02390          imdone = 1;
02391          break;
02392       }
02393       if (!res) /* Say "Y" */
02394          ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
02395       if (!res) {
02396          res = ast_waitstream(mychannel, "");
02397          ast_stopstream(mychannel);
02398       } else
02399           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02400       imdone = 1;
02401       break;
02402    case ARB_ALPHA:
02403       wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
02404       if (mytele->param)
02405          saycharstr(mychannel, mytele->param);
02406       imdone = 1;
02407       break;
02408    case REV_PATCH:
02409       wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
02410       if (mytele->param) {
02411          /* Parts of this section taken from app_parkandannounce */
02412          char *tpl_working, *tpl_current;
02413          char *tmp[100], *myparm;
02414          int looptemp=0, i = 0, dres = 0;
02415 
02416          tpl_working = ast_strdupa(mytele->param);
02417          myparm = strsep(&tpl_working, ",");
02418          tpl_current = strsep(&tpl_working, ":");
02419 
02420          while (tpl_current && looptemp < sizeof(tmp)) {
02421             tmp[looptemp] = tpl_current;
02422             looptemp++;
02423             tpl_current = strsep(&tpl_working, ":");
02424          }
02425 
02426          for (i = 0; i < looptemp; i++) {
02427             if (!strcmp(tmp[i], "PARKED")) {
02428                ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
02429             } else if (!strcmp(tmp[i], "NODE")) {
02430                ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
02431             } else {
02432                dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
02433                if (!dres) {
02434                   dres = ast_waitstream(mychannel, "");
02435                } else {
02436                   ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
02437                   dres = 0;
02438                }
02439             }
02440          }
02441       }
02442       imdone = 1;
02443       break;
02444    case TEST_TONE:
02445       imdone = 1;
02446       myrpt->stopgen = 0;
02447       if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
02448          break;
02449       while (mychannel->generatordata && (!myrpt->stopgen)) {
02450          if (ast_safe_sleep(mychannel, 1)) break;
02451          imdone = 1;
02452       }
02453       break;
02454    default:
02455       break;
02456    }
02457 
02458    myrpt->stopgen = 0;
02459    if (!imdone) {
02460       if (!res) 
02461          res = ast_waitstream(mychannel, "");
02462       else {
02463          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02464          res = 0;
02465       }
02466    }
02467    ast_stopstream(mychannel);
02468    rpt_mutex_lock(&myrpt->lock);
02469    if (mytele->mode == TAILMSG) {
02470       if (!res) {
02471          myrpt->tailmessagen++;
02472          if (myrpt->tailmessagen >= myrpt->p.tailmsg.argc)
02473             myrpt->tailmessagen = 0;
02474       } else {
02475          myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
02476       }
02477    }
02478    remque((struct qelem *)mytele);
02479    rpt_mutex_unlock(&myrpt->lock);
02480    ast_free(mytele);    
02481    ast_hangup(mychannel);
02482 #ifdef  APP_RPT_LOCK_DEBUG
02483    sleep(5);
02484    ast_mutex_lock(&locklock);
02485    t = get_lockthread(pthread_self());
02486    if (t)
02487       memset(t, 0, sizeof(struct lockthread));
02488    ast_mutex_unlock(&locklock);
02489 #endif
02490    pthread_exit(NULL);
02491 }

static void rpt_telemetry ( struct rpt myrpt,
int  mode,
void *  data 
) [static]

Definition at line 2493 of file app_rpt.c.

References ARB_ALPHA, ast_calloc, ast_copy_string(), ast_log(), ast_pthread_create_detached, CONNECTED, CONNFAIL, rpt::lock, LOG_WARNING, rpt_tele::next, REMDISC, REV_PATCH, rpt_mutex_lock, rpt_mutex_unlock, rpt_tele_thread(), and rpt::tele.

Referenced by function_autopatchdn(), function_cop(), function_gosub(), function_ilink(), function_macro(), function_status(), handle_link_data(), handle_link_phone_dtmf(), local_dtmf_helper(), queue_id(), rpt(), and rpt_call().

02494 {
02495    struct rpt_tele *tele;
02496    struct rpt_link *mylink = (struct rpt_link *) data;
02497    int res;
02498 
02499    tele = ast_calloc(1, sizeof(*tele));
02500    if (!tele) {
02501       ast_log(LOG_WARNING, "Unable to allocate memory\n");
02502       pthread_exit(NULL);
02503    }
02504    tele->rpt = myrpt;
02505    tele->mode = mode;
02506    rpt_mutex_lock(&myrpt->lock);
02507    if ((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED)) {
02508       if (mylink) {
02509          memcpy(&tele->mylink, mylink, sizeof(struct rpt_link));
02510       }
02511    } else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
02512       ast_copy_string(tele->param, (char *) data, sizeof(tele->param));
02513    }
02514    insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
02515    rpt_mutex_unlock(&myrpt->lock);
02516    res = ast_pthread_create_detached(&tele->threadid, NULL, rpt_tele_thread, (void *) tele);
02517    if (res != 0) {
02518       rpt_mutex_lock(&myrpt->lock);
02519       remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
02520       rpt_mutex_unlock(&myrpt->lock);  
02521       ast_log(LOG_WARNING, "Could not create telemetry thread: %s\n", strerror(res));
02522    }
02523    return;
02524 }

static int saycharstr ( struct ast_channel mychannel,
char *  str 
) [static]

Definition at line 1719 of file app_rpt.c.

References ast_log(), ast_say_character_str(), ast_stopstream(), ast_waitstream(), ast_channel::language, LOG_WARNING, and ast_channel::name.

Referenced by function_remote(), rmt_saycharstr(), and rpt_tele_thread().

01720 {
01721    int   res;
01722 
01723    res = ast_say_character_str(mychannel, str, NULL, mychannel->language);
01724    if (!res) 
01725       res = ast_waitstream(mychannel, "");
01726    else
01727        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
01728    ast_stopstream(mychannel);
01729    return res;
01730 }

static int saydigits ( struct ast_channel mychannel,
int  num 
) [static]

Definition at line 1744 of file app_rpt.c.

References ast_log(), ast_say_digits(), ast_stopstream(), ast_waitstream(), ast_channel::language, LOG_WARNING, and ast_channel::name.

Referenced by function_remote().

01745 {
01746    int res;
01747    res = ast_say_digits(mychannel, num, NULL, mychannel->language);
01748    if (!res)
01749       res = ast_waitstream(mychannel, "");
01750    else
01751       ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
01752    ast_stopstream(mychannel);
01753    return res;
01754 }

static int sayfile ( struct ast_channel mychannel,
const char *  fname 
) [static]

Definition at line 1706 of file app_rpt.c.

References ast_log(), ast_stopstream(), ast_streamfile(), ast_waitstream(), ast_channel::language, LOG_WARNING, and ast_channel::name.

Referenced by function_remote(), rmt_sayfile(), rpt_tele_thread(), and telem_any().

01707 {
01708    int   res;
01709 
01710    res = ast_streamfile(mychannel, fname, mychannel->language);
01711    if (!res) 
01712       res = ast_waitstream(mychannel, "");
01713    else
01714        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
01715    ast_stopstream(mychannel);
01716    return res;
01717 }

static int saynum ( struct ast_channel mychannel,
int  num 
) [static]

Definition at line 1732 of file app_rpt.c.

References ast_log(), ast_say_number(), ast_stopstream(), ast_waitstream(), ast_channel::language, LOG_WARNING, and ast_channel::name.

Referenced by function_remote().

01733 {
01734    int res;
01735    res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
01736    if (!res)
01737       res = ast_waitstream(mychannel, "");
01738    else
01739       ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
01740    ast_stopstream(mychannel);
01741    return res;
01742 }

static void send_link_dtmf ( struct rpt myrpt,
char  c 
) [static]

Definition at line 2756 of file app_rpt.c.

References AST_FRAME_TEXT, ast_strdup, ast_write(), rpt_link::chan, rpt::cmdnode, ast_frame::data, ast_frame::datalen, rpt::dtmfidx, ast_frame::frametype, rpt::links, ast_frame::mallocd, rpt_link::name, rpt::name, rpt_link::next, ast_frame::offset, ast_frame::samples, str, and ast_frame::subclass.

Referenced by handle_link_phone_dtmf(), and local_dtmf_helper().

02757 {
02758    char str[300];
02759    struct ast_frame wf;
02760    struct rpt_link *l;
02761 
02762    snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
02763    wf.frametype = AST_FRAME_TEXT;
02764    wf.subclass = 0;
02765    wf.offset = 0;
02766    wf.mallocd = 1;
02767    wf.datalen = strlen(str) + 1;
02768    wf.samples = 0;
02769    l = myrpt->links.next;
02770    /* first, see if our dude is there */
02771    while (l != &myrpt->links) {
02772       if (l->name[0] == '0') {
02773          l = l->next;
02774          continue;
02775       }
02776       /* if we found it, write it and were done */
02777       if (!strcmp(l->name, myrpt->cmdnode)) {
02778          wf.data = ast_strdup(str);
02779          if (l->chan)
02780             ast_write(l->chan, &wf);
02781          return;
02782       }
02783       l = l->next;
02784    }
02785    l = myrpt->links.next;
02786    /* if not, give it to everyone */
02787    while (l != &myrpt->links) {
02788       wf.data = ast_strdup(str);
02789       if (l->chan)
02790          ast_write(l->chan, &wf);
02791       l = l->next;
02792    }
02793    return;
02794 }

static int send_morse ( struct ast_channel chan,
const char *  string,
int  speed,
int  freq,
int  amplitude 
) [static]

Definition at line 1494 of file app_rpt.c.

References ast_safe_sleep(), ast_stopstream(), ast_waitstream(), chan, morse_bits::ddcomb, ast_channel::fds, morse_bits::len, play_silence(), and play_tone().

Referenced by telem_any().

01495 {
01496 
01497    static struct morse_bits mbits[] = {
01498       {0, 0}, /* SPACE */
01499       {0, 0}, 
01500       {6, 18},/* " */
01501       {0, 0},
01502       {7, 72},/* $ */
01503       {0, 0},
01504       {0, 0},
01505       {6, 30},/* ' */
01506       {5, 13},/* ( */
01507       {6, 29},/* ) */
01508       {0, 0},
01509       {5, 10},/* + */
01510       {6, 51},/* , */
01511       {6, 33},/* - */
01512       {6, 42},/* . */
01513       {5, 9}, /* / */
01514       {5, 31},/* 0 */
01515       {5, 30},/* 1 */
01516       {5, 28},/* 2 */
01517       {5, 24},/* 3 */
01518       {5, 16},/* 4 */
01519       {5, 0}, /* 5 */
01520       {5, 1}, /* 6 */
01521       {5, 3}, /* 7 */
01522       {5, 7}, /* 8 */
01523       {5, 15},/* 9 */
01524       {6, 7}, /* : */
01525       {6, 21},/* ; */
01526       {0, 0},
01527       {5, 33},/* = */
01528       {0, 0},
01529       {6, 12},/* ? */
01530       {0, 0},
01531       {2, 2}, /* A */
01532       {4, 1}, /* B */
01533       {4, 5}, /* C */
01534       {3, 1}, /* D */
01535       {1, 0}, /* E */
01536       {4, 4}, /* F */
01537       {3, 3}, /* G */
01538       {4, 0}, /* H */
01539       {2, 0}, /* I */
01540       {4, 14},/* J */
01541       {3, 5}, /* K */
01542       {4, 2}, /* L */
01543       {2, 3}, /* M */
01544       {2, 1}, /* N */
01545       {3, 7}, /* O */
01546       {4, 6}, /* P */
01547       {4, 11},/* Q */
01548       {3, 2}, /* R */
01549       {3, 0}, /* S */
01550       {1, 1}, /* T */
01551       {3, 4}, /* U */
01552       {4, 8}, /* V */
01553       {3, 6}, /* W */
01554       {4, 9}, /* X */
01555       {4, 13},/* Y */
01556       {4, 3}  /* Z */
01557    };
01558 
01559    int dottime;
01560    int dashtime;
01561    int intralettertime;
01562    int interlettertime;
01563    int interwordtime;
01564    int len, ddcomb;
01565    int res;
01566    int c;
01567    int i;
01568    int flags;
01569          
01570    res = 0;
01571    
01572    /* Approximate the dot time from the speed arg. */
01573    
01574    dottime = 900 / speed;
01575    
01576    /* Establish timing relationships */
01577    
01578    dashtime = 3 * dottime;
01579    intralettertime = dottime;
01580    interlettertime = dottime * 4 ;
01581    interwordtime = dottime * 7;
01582    
01583    for (; (*string) && (!res); string++) {
01584    
01585       c = *string;
01586       
01587       /* Convert lower case to upper case */
01588       
01589       if ((c >= 'a') && (c <= 'z'))
01590          c -= 0x20;
01591       
01592       /* Can't deal with any char code greater than Z, skip it */
01593       
01594       if (c  > 'Z')
01595          continue;
01596       
01597       /* If space char, wait the inter word time */
01598                
01599       if (c == ' ') {
01600          if (!res)
01601             res = play_silence(chan, interwordtime);
01602          continue;
01603       }
01604       
01605       /* Subtract out control char offset to match our table */
01606       
01607       c -= 0x20;
01608       
01609       /* Get the character data */
01610       
01611       len = mbits[c].len;
01612       ddcomb = mbits[c].ddcomb;
01613       
01614       /* Send the character */
01615       
01616       for (; len ; len--) {
01617          if (!res)
01618             res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
01619          if (!res)
01620             res = play_silence(chan, intralettertime);
01621          ddcomb >>= 1;
01622       }
01623       
01624       /* Wait the interletter time */
01625       
01626       if (!res)
01627          res = play_silence(chan, interlettertime - intralettertime);
01628    }
01629    
01630    /* Wait for all the frames to be sent */
01631    
01632    if (!res) 
01633       res = ast_waitstream(chan, "");
01634    ast_stopstream(chan);
01635    
01636    /*
01637    * Wait for the dahdi driver to physically write the tone blocks to the hardware
01638    */
01639 
01640    for (i = 0; i < 20 ; i++) {
01641       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
01642       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
01643       if (flags & DAHDI_IOMUX_WRITEEMPTY)
01644          break;
01645       if ( ast_safe_sleep(chan, 50)) {
01646          res = -1;
01647          break;
01648       }
01649    }
01650 
01651    
01652    return res;
01653 }

static int send_tone_telemetry ( struct ast_channel chan,
const char *  tonestring 
) [static]

Definition at line 1655 of file app_rpt.c.

References ast_safe_sleep(), ast_stopstream(), ast_strdupa, ast_waitstream(), chan, ast_channel::fds, play_tone_pair(), and strsep().

Referenced by telem_any().

01656 {
01657    char *stringp;
01658    char *tonesubset;
01659    int f1, f2;
01660    int duration;
01661    int amplitude;
01662    int res;
01663    int i;
01664    int flags;
01665    
01666    res = 0;
01667    
01668    stringp = ast_strdupa(tonestring);
01669 
01670    for (;tonestring;) {
01671       tonesubset = strsep(&stringp, ")");
01672       if (!tonesubset)
01673          break;
01674       if (sscanf(tonesubset, "(%d,%d,%d,%d", &f1, &f2, &duration, &amplitude) != 4)
01675          break;
01676       res = play_tone_pair(chan, f1, f2, duration, amplitude);
01677       if (res)
01678          break;
01679    }
01680    if (!res)
01681       res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
01682    
01683    if (!res) 
01684       res = ast_waitstream(chan, "");
01685    ast_stopstream(chan);
01686 
01687    /*
01688    * Wait for the dahdi driver to physically write the tone blocks to the hardware
01689    */
01690 
01691    for (i = 0; i < 20 ; i++) {
01692       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
01693       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
01694       if (flags & DAHDI_IOMUX_WRITEEMPTY)
01695          break;
01696       if (ast_safe_sleep(chan, 50)) {
01697          res = -1;
01698          break;
01699       }
01700    }
01701       
01702    return res;
01703 }

static int serial_remote_io ( struct rpt myrpt,
unsigned char *  txbuf,
int  txbytes,
char *  rxbuf,
int  rxmaxbytes,
int  asciiflag 
) [static]

Definition at line 3947 of file app_rpt.c.

References ast_copy_string(), ast_debug, ast_channel::fds, and rpt::rxchannel.

Referenced by set_ctcss_freq_ft897(), set_ctcss_mode_ft897(), set_freq_ft897(), set_mode_ft897(), set_offset_ft897(), and simple_command_ft897().

03948 {
03949    int i;
03950    struct dahdi_radio_param prm;
03951 
03952    char *buf = alloca(30 + txbytes * 3);
03953    int len;
03954    ast_copy_string(buf, "String output was: ", 30 + txbytes * 3);
03955    len = strlen(buf);
03956    for (i = 0; i < txbytes; i++)
03957       len += snprintf(buf + len, 30 + txbytes * 3 - len, "%02X ", (unsigned char) txbuf[i]);
03958    strcat(buf + len, "\n");
03959    ast_debug(1, "%s", buf);
03960 
03961    prm.radpar = DAHDI_RADPAR_REMMODE;
03962    if (asciiflag)
03963       prm.data = DAHDI_RADPAR_REM_SERIAL_ASCII;
03964    else
03965       prm.data = DAHDI_RADPAR_REM_SERIAL;
03966    if (ioctl(myrpt->rxchannel->fds[0], DAHDI_RADIO_SETPARAM, &prm) == -1)
03967       return -1;
03968    prm.radpar = DAHDI_RADPAR_REMCOMMAND;
03969    prm.data = rxmaxbytes;
03970    memcpy(prm.buf, txbuf, txbytes);
03971    prm.index = txbytes;
03972    if (ioctl(myrpt->rxchannel->fds[0], DAHDI_RADIO_SETPARAM, &prm) == -1)
03973       return -1;
03974    if (rxbuf) {
03975       *rxbuf = 0;
03976       memcpy(rxbuf, prm.buf, prm.index);
03977    }
03978    return(prm.index);
03979 }

static int service_scan ( struct rpt myrpt  )  [static]

Definition at line 4507 of file app_rpt.c.

References rpt::freq, HF_SCAN_DOWN_FAST, HF_SCAN_DOWN_QUICK, HF_SCAN_DOWN_SLOW, HF_SCAN_UP_FAST, HF_SCAN_UP_QUICK, HF_SCAN_UP_SLOW, rpt::hfscanmode, rpt::hfscanstatus, multimode_bump_freq(), split_freq, and stop_scan().

04508 {
04509    int res, interval, mhz, decimals;
04510    char k10=0, k100=0;
04511 
04512    switch (myrpt->hfscanmode) {
04513 
04514    case HF_SCAN_DOWN_SLOW:
04515       interval = -10; /* 100Hz /sec */
04516       break;
04517 
04518    case HF_SCAN_DOWN_QUICK:
04519       interval = -50; /* 500Hz /sec */
04520       break;
04521 
04522    case HF_SCAN_DOWN_FAST:
04523       interval = -200; /* 2KHz /sec */
04524       break;
04525 
04526    case HF_SCAN_UP_SLOW:
04527       interval = 10; /* 100Hz /sec */
04528       break;
04529 
04530    case HF_SCAN_UP_QUICK:
04531       interval = 50; /* 500 Hz/sec */
04532       break;
04533 
04534    case HF_SCAN_UP_FAST:
04535       interval = 200; /* 2KHz /sec */
04536       break;
04537 
04538    default:
04539       myrpt->hfscanmode = 0; /* Huh? */
04540       return -1;
04541    }
04542 
04543    res = split_freq(&mhz, &decimals, myrpt->freq);
04544       
04545    if (!res) {
04546       k100 = decimals / 10000;
04547       k10 = (decimals / 1000) % 10;
04548       res = multimode_bump_freq(myrpt, interval);
04549    }
04550 
04551    if (!res)
04552       res = split_freq(&mhz, &decimals, myrpt->freq);
04553 
04554    if (res) {
04555       stop_scan(myrpt, 1);
04556       return -1;
04557    }
04558 
04559    /* Announce 10KHz boundaries */
04560    if (k10 != (decimals / 1000) % 10) {
04561       int myhund = (interval < 0) ? k100 : decimals / 10000;
04562       int myten = (interval < 0) ? k10 : (decimals / 1000) % 10;
04563       myrpt->hfscanstatus = (myten == 0) ? (myhund) * 100 : (myten) * 10;
04564    }
04565    return res;
04566 
04567 }

static int set_ctcss_freq_ft897 ( struct rpt myrpt,
char *  txtone,
char *  rxtone 
) [static]

Definition at line 4317 of file app_rpt.c.

References serial_remote_io(), and split_ctcss_freq.

Referenced by set_ft897().

04318 {
04319    unsigned char cmdstr[5] = { 0, 0, 0, 0, 0x0B };
04320    int hertz, decimal;
04321 
04322    if (split_ctcss_freq(&hertz, &decimal, txtone))
04323       return -1; 
04324 
04325    cmdstr[0] = ((hertz / 100) << 4) + (hertz % 100) / 10;
04326    cmdstr[1] = ((hertz % 10) << 4) + (decimal % 10);
04327    
04328    if (rxtone) {
04329       if (split_ctcss_freq(&hertz, &decimal, rxtone))
04330          return -1; 
04331 
04332       cmdstr[2] = ((hertz / 100) << 4) + (hertz % 100)/ 10;
04333       cmdstr[3] = ((hertz % 10) << 4) + (decimal % 10);
04334    }
04335 
04336    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04337 }  

static int set_ctcss_mode_ft897 ( struct rpt myrpt,
char  txplon,
char  rxplon 
) [static]

Definition at line 4298 of file app_rpt.c.

References serial_remote_io().

Referenced by set_ft897().

04299 {
04300    unsigned char cmdstr[5] = { 0, 0, 0, 0, 0x0A };
04301 
04302    if (rxplon && txplon)
04303       cmdstr[0] = 0x2A; /* Encode and Decode */
04304    else if (!rxplon && txplon)
04305       cmdstr[0] = 0x4A; /* Encode only */
04306    else if (rxplon && !txplon)
04307       cmdstr[0] = 0x3A; /* Encode only */
04308    else
04309       cmdstr[0] = 0x8A; /* OFF */
04310 
04311    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04312 }

static int set_freq_ft897 ( struct rpt myrpt,
char *  newfreq 
) [static]

Definition at line 4214 of file app_rpt.c.

References ast_debug, serial_remote_io(), and split_freq.

Referenced by multimode_bump_freq_ft897(), and set_ft897().

04215 {
04216    unsigned char cmdstr[5];
04217    int fd, m, d;
04218 
04219    fd = 0;
04220    ast_debug(1, "New frequency: %s\n", newfreq);
04221 
04222    if (split_freq(&m, &d, newfreq))
04223       return -1; 
04224 
04225    /* The FT-897 likes packed BCD frequencies */
04226 
04227    cmdstr[0] = ((m / 100) << 4) + ((m % 100) / 10);              /* 100MHz 10Mhz */
04228    cmdstr[1] = ((m % 10) << 4) + (d / 10000);                    /* 1MHz 100KHz */
04229    cmdstr[2] = (((d % 10000) / 1000) << 4) + ((d % 1000) / 100); /* 10KHz 1KHz */
04230    cmdstr[3] = (((d % 100) / 10) << 4) + (d % 10);               /* 100Hz 10Hz */
04231    cmdstr[4] = 0x01;                                             /* command */
04232 
04233    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04234 }

static int set_ft897 ( struct rpt myrpt  )  [static]

Definition at line 4341 of file app_rpt.c.

References ast_debug, REM_MODE_FM, REM_MODE_LSB, REM_MODE_USB, rpt::remmode, set_ctcss_freq_ft897(), set_ctcss_mode_ft897(), set_freq_ft897(), set_mode_ft897(), set_offset_ft897(), and simple_command_ft897().

Referenced by setrem().

04342 {
04343    int res;
04344    
04345    ast_debug(1, "@@@@ lock on\n");
04346 
04347    res = simple_command_ft897(myrpt, 0x00);           /* LOCK on */  
04348 
04349    ast_debug(1, "@@@@ ptt off\n");
04350 
04351    if (!res)
04352       res = simple_command_ft897(myrpt, 0x88);     /* PTT off */
04353 
04354    ast_debug(1, "Modulation mode\n");
04355 
04356    if (!res)
04357       res = set_mode_ft897(myrpt, myrpt->remmode);    /* Modulation mode */
04358 
04359    ast_debug(1, "Split off\n");
04360 
04361    if (!res)
04362       simple_command_ft897(myrpt, 0x82);        /* Split off */
04363 
04364    ast_debug(1, "Frequency\n");
04365 
04366    if (!res)
04367       res = set_freq_ft897(myrpt, myrpt->freq);    /* Frequency */
04368    if ((myrpt->remmode == REM_MODE_FM)) {
04369       ast_debug(1, "Offset\n");
04370       if (!res)
04371          res = set_offset_ft897(myrpt, myrpt->offset);   /* Offset if FM */
04372       if ((!res)&&(myrpt->rxplon || myrpt->txplon)) {
04373          ast_debug(1, "CTCSS tone freqs.\n");
04374          res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
04375       }
04376       if (!res) {
04377          ast_debug(1, "CTCSS mode\n");
04378          res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
04379       }
04380    }
04381    if ((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)) {
04382       ast_debug(1, "Clarifier off\n");
04383       simple_command_ft897(myrpt, 0x85);        /* Clarifier off if LSB or USB */
04384    }
04385    return res;
04386 }

static int set_mode_ft897 ( struct rpt myrpt,
char  newmode 
) [static]

Definition at line 4272 of file app_rpt.c.

References REM_MODE_AM, REM_MODE_FM, REM_MODE_LSB, REM_MODE_USB, and serial_remote_io().

Referenced by set_ft897().

04273 {
04274    unsigned char cmdstr[5] = { 0, 0, 0, 0, 0x07 };
04275 
04276    switch (newmode) {
04277    case REM_MODE_FM:
04278       cmdstr[0] = 0x08;
04279       break;
04280    case REM_MODE_USB:
04281       cmdstr[0] = 0x01;
04282       break;
04283    case REM_MODE_LSB:
04284       cmdstr[0] = 0x00;
04285       break;
04286    case REM_MODE_AM:
04287       cmdstr[0] = 0x04;
04288       break;
04289    default:
04290       return -1;
04291    }
04292 
04293    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04294 }

static int set_offset_ft897 ( struct rpt myrpt,
char  offset 
) [static]

Definition at line 4247 of file app_rpt.c.

References REM_MINUS, REM_PLUS, REM_SIMPLEX, and serial_remote_io().

Referenced by set_ft897().

04248 {
04249    unsigned char cmdstr[5] = "";
04250 
04251    switch (offset) {
04252    case REM_SIMPLEX:
04253       cmdstr[0] = 0x89;
04254       break;
04255    case REM_MINUS:
04256       cmdstr[0] = 0x09;
04257       break;
04258    case REM_PLUS:
04259       cmdstr[0] = 0x49;
04260       break;   
04261    default:
04262       return -1;
04263    }
04264 
04265    cmdstr[4] = 0x09; 
04266 
04267    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04268 }

static int setrbi ( struct rpt myrpt  )  [static]

Definition at line 3981 of file app_rpt.c.

References ast_copy_string(), ast_debug, rpt::freq, MAXREMSTR, rpt::offset, rpt::powerlevel, rbi_mhztoband(), rbi_out(), rbi_pltocode(), REM_HIPWR, REM_LOWPWR, REM_MEDPWR, REM_MINUS, REM_PLUS, REM_SIMPLEX, rpt::remote, rpt::rxplon, s, rpt::txpl, and rpt::txplon.

Referenced by setrem().

03982 {
03983    char tmp[MAXREMSTR] = "", *s;
03984    unsigned char rbicmd[5];
03985    int   band, txoffset = 0, txpower = 0, txpl;
03986 
03987    /* must be a remote system */
03988    if (!myrpt->remote)
03989       return(0);
03990    /* must have rbi hardware */
03991    if (strncmp(myrpt->remote, remote_rig_rbi, 3))
03992       return(0);
03993    ast_copy_string(tmp, myrpt->freq, sizeof(tmp));
03994    s = strchr(tmp, '.');
03995    /* if no decimal, is invalid */
03996    
03997    if (s == NULL) {
03998       ast_debug(1, "@@@@ Frequency needs a decimal\n");
03999       return -1;
04000    }
04001    
04002    *s++ = 0;
04003    if (strlen(tmp) < 2) {
04004       ast_debug(1, "@@@@ Bad MHz digits: %s\n", tmp);
04005       return -1;
04006    }
04007     
04008    if (strlen(s) < 3) {
04009       ast_debug(1, "@@@@ Bad KHz digits: %s\n", s);
04010       return -1;
04011    }
04012 
04013    if ((s[2] != '0') && (s[2] != '5')) {
04014       ast_debug(1, "@@@@ KHz must end in 0 or 5: %c\n", s[2]);
04015       return -1;
04016    }
04017     
04018    band = rbi_mhztoband(tmp);
04019    if (band == -1) {
04020       ast_debug(1, "@@@@ Bad Band: %s\n", tmp);
04021       return -1;
04022    }
04023    
04024    txpl = rbi_pltocode(myrpt->txpl);
04025    
04026    if (txpl == -1) {
04027       ast_debug(1, "@@@@ Bad TX PL: %s\n", myrpt->txpl);
04028       return -1;
04029    }
04030 
04031    
04032    switch (myrpt->offset) {
04033    case REM_MINUS:
04034       txoffset = 0;
04035       break;
04036    case REM_PLUS:
04037       txoffset = 0x10;
04038       break;
04039    case REM_SIMPLEX:
04040       txoffset = 0x20;
04041       break;
04042    }
04043    switch(myrpt->powerlevel) {
04044    case REM_LOWPWR:
04045       txpower = 0;
04046       break;
04047    case REM_MEDPWR:
04048       txpower = 0x20;
04049       break;
04050    case REM_HIPWR:
04051       txpower = 0x10;
04052       break;
04053    }
04054    rbicmd[0] = 0;
04055    rbicmd[1] = band | txpower | 0xc0;
04056    rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
04057    if (s[2] == '5')
04058       rbicmd[2] |= 0x40;
04059    rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
04060    rbicmd[4] = txpl;
04061    if (myrpt->txplon)
04062       rbicmd[4] |= 0x40;
04063    if (myrpt->rxplon)
04064       rbicmd[4] |= 0x80;
04065    rbi_out(myrpt, rbicmd);
04066    return 0;
04067 }

static int setrem ( struct rpt myrpt  )  [static]

Definition at line 4435 of file app_rpt.c.

References rpt::remote, set_ft897(), and setrbi().

Referenced by function_remote().

04436 {
04437    return 0; /* XXX BROKEN!! */
04438    if (!strcmp(myrpt->remote, remote_rig_ft897))
04439       return set_ft897(myrpt);
04440    else if (!strcmp(myrpt->remote, remote_rig_rbi))
04441       return setrbi(myrpt);
04442    else
04443       return -1;
04444 }

static int simple_command_ft897 ( struct rpt myrpt,
char  command 
) [static]

Definition at line 4238 of file app_rpt.c.

References serial_remote_io().

Referenced by closerem_ft897(), and set_ft897().

04239 {
04240    unsigned char cmdstr[5] = { 0, 0, 0, 0, command };
04241 
04242    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04243 }

static char* skipchars ( char *  string,
char *  charlist 
) [static]

Definition at line 788 of file app_rpt.c.

Referenced by function_autopatchup().

00789 {
00790    int i;   
00791    while (*string) {
00792       for (i = 0; charlist[i] ; i++) {
00793          if (*string == charlist[i]) {
00794             string++;
00795             break;
00796          }
00797       }
00798       if (!charlist[i])
00799          return string;
00800    }
00801    return string;
00802 }  

static int split_decimal ( char *  input,
int *  ints,
int *  decs,
int  places 
) [static]

Definition at line 4102 of file app_rpt.c.

04103 {
04104    double input2 = 0.0;
04105    long long modifier = (long long)pow(10.0, (double)places);
04106    if (sscanf(input, "%lf", &input2) == 1) {
04107       long long input3 = input2 * modifier;
04108       *ints = input3 / modifier;
04109       *decs = input3 % modifier;
04110       return 0;
04111    } else
04112       return -1;
04113 }

static void stop_scan ( struct rpt myrpt,
int  flag 
) [static]

Definition at line 4497 of file app_rpt.c.

References rpt::hfscanmode, and rpt::hfscanstatus.

Referenced by handle_remote_dtmf_digit(), and service_scan().

04498 {
04499    myrpt->hfscanmode = 0;
04500    myrpt->hfscanstatus = ((flag) ? -2 : -1);
04501 }

static int telem_any ( struct rpt myrpt,
struct ast_channel chan,
const char *  entry 
) [static]

Definition at line 1757 of file app_rpt.c.

References chan, MORSE, retrieve_astcfgint(), sayfile(), send_morse(), and send_tone_telemetry().

Referenced by rpt_tele_thread(), and telem_lookup().

01758 {
01759    int res;
01760    char c;
01761    
01762    static int morsespeed;
01763    static int morsefreq;
01764    static int morseampl;
01765    static int morseidfreq = 0;
01766    static int morseidampl;
01767    static char mcat[] = MORSE;
01768    
01769    res = 0;
01770    
01771    if (!morseidfreq) { /* Get the morse parameters if not already loaded */
01772       morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
01773       morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
01774       morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
01775       morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
01776       morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330); 
01777    }
01778    
01779    /* Is it a file, or a tone sequence? */
01780          
01781    if (entry[0] == '|') {
01782       c = entry[1];
01783       if ((c >= 'a') && (c <= 'z'))
01784          c -= 0x20;
01785    
01786       switch (c) {
01787       case 'I': /* Morse ID */
01788          res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
01789          break;
01790       case 'M': /* Morse Message */
01791          res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
01792          break;
01793       case 'T': /* Tone sequence */
01794          res = send_tone_telemetry(chan, entry + 2);
01795          break;
01796       default:
01797          res = -1;
01798       }
01799    } else
01800       res = sayfile(chan, entry); /* File */
01801    return res;
01802 }

static int telem_lookup ( struct rpt myrpt,
struct ast_channel chan,
const char *  node,
const char *  name 
) [static]

Definition at line 1810 of file app_rpt.c.

References ast_strlen_zero(), ast_variable_retrieve(), rpt::cfg, chan, tele_defs, telem_any(), and TELEMETRY.

Referenced by handle_remote_data(), handle_remote_phone_dtmf(), and rpt_tele_thread().

01811 {
01812    int res = 0;
01813    int i;
01814    const char *entry = NULL;
01815    const char *telemetry;
01816 
01817    /* Retrieve the section name for telemetry from the node section */
01818    if ((telemetry = ast_variable_retrieve(myrpt->cfg, node, TELEMETRY)))
01819       entry = ast_variable_retrieve(myrpt->cfg, telemetry, name);
01820 
01821    /* Try to look up the telemetry name */   
01822 
01823    if (!entry) {
01824       /* Telemetry name wasn't found in the config file, use the default */
01825       for (i = 0; i < sizeof(tele_defs) / sizeof(struct telem_defaults); i++) {
01826          if (!strcasecmp(tele_defs[i].name, name))
01827             entry = tele_defs[i].value;
01828       }
01829    }
01830    if (entry) {   
01831       if (!ast_strlen_zero(entry))
01832          telem_any(myrpt, chan, entry);
01833    } else {
01834       res = -1;
01835    }
01836    return res;
01837 }

static int unload_module ( void   )  [static]

Definition at line 7432 of file app_rpt.c.

References ast_cli_unregister_multiple(), ast_mutex_destroy(), ast_unregister_application(), cli_rpt, lock, name, rpt::nodes, and rpt_vars.

07433 {
07434    int i;
07435 
07436    for (i = 0; i < nrpts; i++) {
07437       if (!strcmp(rpt_vars[i].name, rpt_vars[i].p.nodes))
07438          continue;
07439       ast_mutex_destroy(&rpt_vars[i].lock);
07440    }
07441    i = ast_unregister_application(app);
07442 
07443    /* Unregister cli extensions */
07444    ast_cli_unregister_multiple(cli_rpt, sizeof(cli_rpt) / sizeof(struct ast_cli_entry));
07445 
07446    return i;
07447 }

static void wait_interval ( struct rpt myrpt,
int  type,
struct ast_channel chan 
) [static]

Definition at line 1879 of file app_rpt.c.

References ast_log(), ast_safe_sleep(), chan, get_wait_interval(), and LOG_NOTICE.

Referenced by rpt_tele_thread().

01880 {
01881    int interval;
01882    interval = get_wait_interval(myrpt, type);
01883    if (debug)
01884       ast_log(LOG_NOTICE, " Delay interval = %d\n", interval);
01885    if (interval)
01886       ast_safe_sleep(chan, interval);
01887    if (debug)
01888       ast_log(LOG_NOTICE, "Delay complete\n");
01889    return;
01890 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Radio Repeater / Remote Base" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 7478 of file app_rpt.c.

char* app = "Rpt" [static]

Definition at line 241 of file app_rpt.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 7478 of file app_rpt.c.

struct ast_cli_entry cli_rpt[] [static]

Definition at line 695 of file app_rpt.c.

Referenced by load_module(), and unload_module().

int debug = 0 [static]

Definition at line 283 of file app_rpt.c.

Referenced by add_sdp(), aji_load_config(), check_peer_ok(), check_user_ok(), handle_incoming(), handle_pri_show_debug(), handle_verbose(), process_sdp(), and set_destination().

char* descrip [static]

Definition at line 245 of file app_rpt.c.

char* discstr = "!!DISCONNECT!!"

Definition at line 286 of file app_rpt.c.

struct function_table_tag function_table[] [static]

Definition at line 748 of file app_rpt.c.

Referenced by collect_function_digits().

int nrpts = 0 [static]

Definition at line 284 of file app_rpt.c.

char* remote_rig_ft897 = "ft897" [static]

Definition at line 287 of file app_rpt.c.

char* remote_rig_rbi = "rbi" [static]

Definition at line 288 of file app_rpt.c.

pthread_t rpt_master_thread [static]

Definition at line 299 of file app_rpt.c.

struct rpt rpt_vars[MAXRPTS] [static]

Referenced by handle_cli_rpt_dump(), handle_cli_rpt_lstats(), handle_cli_rpt_reload(), handle_cli_rpt_restart(), handle_cli_rpt_stats(), load_rpt_vars(), reload(), rpt(), rpt_exec(), rpt_master(), and unload_module().

char* synopsis = "Radio Repeater/Remote Base Control System" [static]

Definition at line 243 of file app_rpt.c.

struct telem_defaults tele_defs[] [static]

Definition at line 709 of file app_rpt.c.

Referenced by telem_lookup().

unsigned int vmajor = 0 [static]

Definition at line 280 of file app_rpt.c.

unsigned int vminor = 47 [static]

Definition at line 281 of file app_rpt.c.


Generated on Thu Jul 9 13:40:49 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7