Newer
Older
} else if (!strcmp(var->name, "nobusyout")) {
rpt_vars[n].p.nobusyout = ast_true(var->value);
} else if (!strcmp(var->name, "nodes")) {
ast_copy_string(rpt_vars[n].p.nodes, var->value, sizeof(rpt_vars[n].p.nodes));
Jim Dixon
committed
#ifdef __RPT_NOTCH
} else if (!strcmp(var->name, "rxnotch")) {
char *tmp = ast_strdupa(val);
Mark Michelson
committed
AST_STANDARD_APP_ARGS(strs, tmp);
strs.argc &= ~1; /* force an even number, rounded down */
if (strs.argc >= 2) {
for (j = 0; j < strs.argc; j += 2) {
rpt_mknotch(atof(strs.str[j]), atof(strs.str[j + 1]),
&rpt_vars[n].filters[j >> 1].gain,
&rpt_vars[n].filters[j >> 1].const0,
&rpt_vars[n].filters[j >> 1].const1,
&rpt_vars[n].filters[j >> 1].const2);
sprintf(rpt_vars[n].filters[j >> 1].desc, "%s Hz, BW = %s",
strs.str[j], strs.str[j + 1]);
}
}
#endif
Jim Dixon
committed
}
}
/* If these aren't specified, copy them from the functions property. */
if (ast_strlen_zero(rpt_vars[n].p.link_functions))
ast_copy_string(rpt_vars[n].p.link_functions, rpt_vars[n].p.functions, sizeof(rpt_vars[n].p.link_functions));
rpt_vars[n].longestnode = 0;
for (vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes); vp; vp = vp->next) {
if ((j = strlen(vp->name)) > rpt_vars[n].longestnode)
rpt_vars[n].longestnode = j;
Jim Dixon
committed
}
/*
* For this repeater, Determine the length of the longest function
*/
rpt_vars[n].longestfunc = 0;
for (vp = ast_variable_browse(cfg, rpt_vars[n].p.functions); vp; vp = vp->next) {
if ((j = strlen(vp->name)) > rpt_vars[n].longestfunc)
Jim Dixon
committed
rpt_vars[n].longestfunc = j;
}
Jim Dixon
committed
rpt_vars[n].link_longestfunc = 0;
for (vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions); vp; vp = vp->next) {
if ((j = strlen(vp->name)) > rpt_vars[n].link_longestfunc)
Jim Dixon
committed
rpt_vars[n].link_longestfunc = j;
}
Jim Dixon
committed
rpt_vars[n].phone_longestfunc = 0;
for (vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions); vp; vp = vp->next) {
if ((j = strlen(vp->name)) > rpt_vars[n].phone_longestfunc)
rpt_vars[n].phone_longestfunc = j;
Jim Dixon
committed
}
Jim Dixon
committed
rpt_vars[n].dphone_longestfunc = 0;
for (vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions); vp; vp = vp->next) {
if ((j = strlen(vp->name)) > rpt_vars[n].dphone_longestfunc)
rpt_vars[n].dphone_longestfunc = j;
Jim Dixon
committed
}
Jim Dixon
committed
rpt_vars[n].macro_longest = 1;
for (vp = ast_variable_browse(cfg, rpt_vars[n].p.macro); vp; vp = vp->next) {
if ((j = strlen(vp->name)) > rpt_vars[n].macro_longest)
Jim Dixon
committed
rpt_vars[n].macro_longest = j;
}
Steve Murphy
committed
rpt_vars[n].gosub_longest = 1;
for (vp = ast_variable_browse(cfg, rpt_vars[n].p.gosub); vp; vp = vp->next) {
if ((j = strlen(vp->name)) > rpt_vars[n].gosub_longest)
rpt_vars[n].gosub_longest = j;
}
Jim Dixon
committed
ast_mutex_unlock(&rpt_vars[n].lock);
}
/*
* Enable or disable debug output at a given level at the console
*/
static char *handle_cli_rpt_debug_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
int newlevel;
switch (cmd) {
case CLI_INIT:
e->command = "rpt debug level";
e->usage =
"Usage: rpt debug level {0-7}\n"
" Enables debug messages in app_rpt\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 4)
return CLI_SHOWUSAGE;
newlevel = myatoi(a->argv[3]);
if ((newlevel < 0) || (newlevel > 7))
return CLI_SHOWUSAGE;
if (newlevel)
ast_cli(a->fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
else
ast_cli(a->fd, "app_rpt Debugging disabled\n");
debug = newlevel;
return CLI_SUCCESS;
/*
* Dump rpt struct debugging onto console
*/
static char *handle_cli_rpt_dump(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
int i;
switch (cmd) {
case CLI_INIT:
e->command = "rpt dump";
e->usage =
"Usage: rpt dump <nodename>\n"
" Dumps struct debug info to log\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 3)
return CLI_SHOWUSAGE;
for (i = 0; i < nrpts; i++) {
if (!strcmp(a->argv[2], rpt_vars[i].name)) {
rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
ast_cli(a->fd, "app_rpt struct dump requested for node %s\n", a->argv[2]);
return CLI_SUCCESS;
}
}
return CLI_FAILURE;
}
Jim Dixon
committed
/*
* Dump statistics onto console
*/
static char *handle_cli_rpt_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Jim Dixon
committed
{
int i, j;
Jim Dixon
committed
int dailytxtime, dailykerchunks;
int totalkerchunks, dailykeyups, totalkeyups, timeouts;
int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
long long totaltxtime;
struct rpt_link *l;
Jim Dixon
committed
char *listoflinks[MAX_STAT_LINKS];
char *lastnodewhichkeyedusup, *lastdtmfcommand;
char *tot_state, *ider_state, *patch_state;
char *reverse_patch_state, *enable_state, *input_signal, *called_number;
struct rpt *myrpt;
static char *not_applicable = "N/A";
switch (cmd) {
case CLI_INIT:
e->command = "rpt stats";
e->usage =
"Usage: rpt stats <nodename>\n"
" Dumps node statistics to console\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 3)
return CLI_SHOWUSAGE;
Jim Dixon
committed
for (i = 0 ; i <= MAX_STAT_LINKS; i++)
Jim Dixon
committed
listoflinks[i] = NULL;
tot_state = ider_state =
patch_state = reverse_patch_state =
input_signal = called_number =
lastdtmfcommand = not_applicable;
for (i = 0; i < nrpts; i++) {
if (!strcmp(a->argv[2], rpt_vars[i].name)) {
Jim Dixon
committed
/* Make a copy of all stat variables while locked */
myrpt = &rpt_vars[i];
rpt_mutex_lock(&myrpt->lock); /* LOCK */
dailytxtime = myrpt->dailytxtime;
totaltxtime = myrpt->totaltxtime;
dailykeyups = myrpt->dailykeyups;
totalkeyups = myrpt->totalkeyups;
dailykerchunks = myrpt->dailykerchunks;
totalkerchunks = myrpt->totalkerchunks;
dailyexecdcommands = myrpt->dailyexecdcommands;
totalexecdcommands = myrpt->totalexecdcommands;
timeouts = myrpt->timeouts;
/* Traverse the list of connected nodes */
reverse_patch_state = "DOWN";
j = 0;
l = myrpt->links.next;
while (l != &myrpt->links) {
if (l->name[0] == '0') { /* Skip '0' nodes */
Jim Dixon
committed
reverse_patch_state = "UP";
l = l->next;
continue;
}
listoflinks[j] = ast_strdupa(l->name);
if (listoflinks[j])
Jim Dixon
committed
j++;
l = l->next;
}
lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);
if ((!lastnodewhichkeyedusup) || (ast_strlen_zero(lastnodewhichkeyedusup)))
Jim Dixon
committed
lastnodewhichkeyedusup = not_applicable;
if (myrpt->keyed)
Jim Dixon
committed
input_signal = "YES";
else
input_signal = "NO";
if (myrpt->enable)
Jim Dixon
committed
enable_state = "YES";
else
enable_state = "NO";
if (!myrpt->totimer)
Jim Dixon
committed
tot_state = "TIMED OUT!";
else if (myrpt->totimer != myrpt->p.totime)
Jim Dixon
committed
tot_state = "ARMED";
else
tot_state = "RESET";
if (myrpt->tailid)
Jim Dixon
committed
ider_state = "QUEUED IN TAIL";
else if (myrpt->mustid)
Jim Dixon
committed
ider_state = "QUEUED FOR CLEANUP";
else
ider_state = "CLEAN";
switch (myrpt->callmode) {
case 1:
patch_state = "DIALING";
break;
case 2:
patch_state = "CONNECTING";
break;
case 3:
patch_state = "UP";
break;
case 4:
patch_state = "CALL FAILED";
break;
default:
patch_state = "DOWN";
Jim Dixon
committed
}
if (!ast_strlen_zero(myrpt->exten))
Jim Dixon
committed
called_number = ast_strdupa(myrpt->exten);
if (!ast_strlen_zero(myrpt->lastdtmfcommand))
Jim Dixon
committed
lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
ast_cli(a->fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
ast_cli(a->fd, "Signal on input..................................: %s\n", input_signal);
ast_cli(a->fd, "Transmitter enabled..............................: %s\n", enable_state);
ast_cli(a->fd, "Time out timer state.............................: %s\n", tot_state);
ast_cli(a->fd, "Time outs since system initialization............: %d\n", timeouts);
ast_cli(a->fd, "Identifier state.................................: %s\n", ider_state);
ast_cli(a->fd, "Kerchunks today..................................: %d\n", dailykerchunks);
ast_cli(a->fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
ast_cli(a->fd, "Keyups today.....................................: %d\n", dailykeyups);
ast_cli(a->fd, "Keyups since system initialization...............: %d\n", totalkeyups);
ast_cli(a->fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
ast_cli(a->fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
ast_cli(a->fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
Jim Dixon
committed
hours = dailytxtime / 3600000;
Jim Dixon
committed
dailytxtime %= 3600000;
minutes = dailytxtime / 60000;
Jim Dixon
committed
dailytxtime %= 60000;
seconds = dailytxtime / 1000;
Jim Dixon
committed
dailytxtime %= 1000;
ast_cli(a->fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
Jim Dixon
committed
hours, minutes, seconds, dailytxtime);
hours = (int) totaltxtime / 3600000;
Jim Dixon
committed
totaltxtime %= 3600000;
minutes = (int) totaltxtime / 60000;
Jim Dixon
committed
totaltxtime %= 60000;
seconds = (int) totaltxtime / 1000;
Jim Dixon
committed
totaltxtime %= 1000;
ast_cli(a->fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
Jim Dixon
committed
hours, minutes, seconds, (int) totaltxtime);
ast_cli(a->fd, "Nodes currently connected to us..................: ");
for (j = 0;; j++) {
if (!listoflinks[j]) {
if (!j) {
ast_cli(a->fd, "<NONE>");
Jim Dixon
committed
}
break;
}
ast_cli(a->fd, "%s", listoflinks[j]);
if (j % 4 == 3) {
ast_cli(a->fd, "\n");
ast_cli(a->fd, " : ");
} else {
if (listoflinks[j + 1])
ast_cli(a->fd, ", ");
Jim Dixon
committed
}
}
ast_cli(a->fd, "\n");
Jim Dixon
committed
ast_cli(a->fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
ast_cli(a->fd, "Autopatch state..................................: %s\n", patch_state);
ast_cli(a->fd, "Autopatch called number..........................: %s\n", called_number);
ast_cli(a->fd, "Reverse patch/IAXRPT connected...................: %s\n\n", reverse_patch_state);
Jim Dixon
committed
return CLI_SUCCESS;
Jim Dixon
committed
}
}
return CLI_FAILURE;
Jim Dixon
committed
}
/*
* Link stats function
*/
static char *handle_cli_rpt_lstats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Jim Dixon
committed
{
int i, j;
Jim Dixon
committed
struct rpt *myrpt;
struct rpt_link *l;
Jim Dixon
committed
struct rpt_lstat s_head;
switch (cmd) {
case CLI_INIT:
e->command = "rpt lstats";
e->usage =
"Usage: rpt lstats <nodename>\n"
" Dumps link statistics to console\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 3)
return CLI_SHOWUSAGE;
Jim Dixon
committed
s = NULL;
s_head.next = &s_head;
s_head.prev = &s_head;
for (i = 0; i < nrpts; i++) {
if (!strcmp(a->argv[2], rpt_vars[i].name)) {
Jim Dixon
committed
/* Make a copy of all stat variables while locked */
myrpt = &rpt_vars[i];
rpt_mutex_lock(&myrpt->lock); /* LOCK */
/* Traverse the list of connected nodes */
j = 0;
l = myrpt->links.next;
while (l != &myrpt->links) {
if (l->name[0] == '0') { /* Skip '0' nodes */
Jim Dixon
committed
l = l->next;
continue;
}
Tilghman Lesher
committed
if ((s = ast_calloc(1, sizeof(*s))) == NULL) {
Jim Dixon
committed
ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
return CLI_FAILURE;
Jim Dixon
committed
}
ast_copy_string(s->name, l->name, MAXREMSTR);
Jim Dixon
committed
pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
s->mode = l->mode;
s->outbound = l->outbound;
s->reconnects = l->reconnects;
s->connecttime = l->connecttime;
insque((struct qelem *) s, (struct qelem *) s_head.next);
l = l->next;
}
rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
ast_cli(a->fd, "NODE PEER RECONNECTS DIRECTION CONNECT TIME\n");
ast_cli(a->fd, "---- ---- ---------- --------- ------------\n");
Jim Dixon
committed
for (s = s_head.next; s != &s_head; s = s->next) {
Jim Dixon
committed
int hours, minutes, seconds;
long long connecttime = s->connecttime;
char conntime[31];
hours = (int) connecttime/3600000;
connecttime %= 3600000;
minutes = (int) connecttime/60000;
connecttime %= 60000;
seconds = (int) connecttime/1000;
connecttime %= 1000;
snprintf(conntime, sizeof(conntime), "%02d:%02d:%02d.%d",
Jim Dixon
committed
hours, minutes, seconds, (int) connecttime);
ast_cli(a->fd, "%-10s%-20s%-12d%-11s%-30s\n",
Jim Dixon
committed
s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime);
}
/* destroy our local link queue */
s = s_head.next;
while (s != &s_head) {
Jim Dixon
committed
t = s;
s = s->next;
remque((struct qelem *)t);
ast_free(t);
Jim Dixon
committed
}
return CLI_SUCCESS;
Jim Dixon
committed
}
}
return CLI_FAILURE;
Jim Dixon
committed
}
/*
* reload vars
*/
static char *handle_cli_rpt_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Jim Dixon
committed
{
int n;
Jim Dixon
committed
switch (cmd) {
case CLI_INIT:
e->command = "rpt reload";
e->usage =
"Usage: rpt reload\n"
" Reloads app_rpt running config parameters\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc > 2)
return CLI_SHOWUSAGE;
Jim Dixon
committed
for (n = 0; n < nrpts; n++)
rpt_vars[n].reload = 1;
Jim Dixon
committed
return CLI_SUCCESS;
Jim Dixon
committed
}
/*
* restart app_rpt
*/
static char *handle_cli_rpt_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Jim Dixon
committed
{
int i;
Jim Dixon
committed
switch (cmd) {
case CLI_INIT:
e->command = "rpt restart";
e->usage =
"Usage: rpt restart\n"
" Restarts app_rpt\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc > 2)
return CLI_SHOWUSAGE;
for (i = 0; i < nrpts; i++) {
if (rpt_vars[i].rxchannel)
ast_softhangup(rpt_vars[i].rxchannel, AST_SOFTHANGUP_DEV);
Jim Dixon
committed
}
return CLI_SUCCESS;
Jim Dixon
committed
}
static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
{
int res;
if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
return res;
while (chan->generatordata) {
if (ast_safe_sleep(chan, 1))
return -1;
return 0;
}
static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
{
return play_tone_pair(chan, freq, 0, duration, amplitude);
}
static int play_silence(struct ast_channel *chan, int duration)
{
return play_tone_pair(chan, 0, 0, duration, 0);
}
Tilghman Lesher
committed
static int send_morse(struct ast_channel *chan, const char *string, int speed, int freq, int amplitude)
{
static struct morse_bits mbits[] = {
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
{0, 0}, /* SPACE */
{0, 0},
{6, 18},/* " */
{0, 0},
{7, 72},/* $ */
{0, 0},
{0, 0},
{6, 30},/* ' */
{5, 13},/* ( */
{6, 29},/* ) */
{0, 0},
{5, 10},/* + */
{6, 51},/* , */
{6, 33},/* - */
{6, 42},/* . */
{5, 9}, /* / */
{5, 31},/* 0 */
{5, 30},/* 1 */
{5, 28},/* 2 */
{5, 24},/* 3 */
{5, 16},/* 4 */
{5, 0}, /* 5 */
{5, 1}, /* 6 */
{5, 3}, /* 7 */
{5, 7}, /* 8 */
{5, 15},/* 9 */
{6, 7}, /* : */
{6, 21},/* ; */
{0, 0},
{5, 33},/* = */
{0, 0},
{6, 12},/* ? */
{0, 0},
{2, 2}, /* A */
{4, 1}, /* B */
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
{4, 5}, /* C */
{3, 1}, /* D */
{1, 0}, /* E */
{4, 4}, /* F */
{3, 3}, /* G */
{4, 0}, /* H */
{2, 0}, /* I */
{4, 14},/* J */
{3, 5}, /* K */
{4, 2}, /* L */
{2, 3}, /* M */
{2, 1}, /* N */
{3, 7}, /* O */
{4, 6}, /* P */
{4, 11},/* Q */
{3, 2}, /* R */
{3, 0}, /* S */
{1, 1}, /* T */
{3, 4}, /* U */
{4, 8}, /* V */
{3, 6}, /* W */
{4, 9}, /* X */
{4, 13},/* Y */
{4, 3} /* Z */
};
int dottime;
int dashtime;
int intralettertime;
int interlettertime;
int interwordtime;
int len, ddcomb;
int res;
int c;
res = 0;
/* Approximate the dot time from the speed arg. */
dottime = 900 / speed;
/* Establish timing relationships */
dashtime = 3 * dottime;
intralettertime = dottime;
interlettertime = dottime * 4 ;
interwordtime = dottime * 7;
for (; (*string) && (!res); string++) {
c = *string;
/* Convert lower case to upper case */
if ((c >= 'a') && (c <= 'z'))
c -= 0x20;
/* Can't deal with any char code greater than Z, skip it */
if (c > 'Z')
continue;
/* If space char, wait the inter word time */
if (c == ' ') {
if (!res)
res = play_silence(chan, interwordtime);
continue;
}
/* Subtract out control char offset to match our table */
c -= 0x20;
/* Get the character data */
len = mbits[c].len;
ddcomb = mbits[c].ddcomb;
/* Send the character */
for (; len ; len--) {
if (!res)
res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
if (!res)
res = play_silence(chan, intralettertime);
ddcomb >>= 1;
}
/* Wait the interletter time */
if (!res)
res = play_silence(chan, interlettertime - intralettertime);
}
/* Wait for all the frames to be sent */
if (!res)
res = ast_waitstream(chan, "");
ast_stopstream(chan);
/*
* Wait for the zaptel driver to physically write the tone blocks to the hardware
*/
for (i = 0; i < 20 ; i++) {
flags = ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT;
res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
if (flags & ZT_IOMUX_WRITEEMPTY)
if ( ast_safe_sleep(chan, 50)) {
res = -1;
break;
}
}
return res;
}
Tilghman Lesher
committed
static int send_tone_telemetry(struct ast_channel *chan, const char *tonestring)
{
char *stringp;
char *tonesubset;
int f1, f2;
int duration;
int amplitude;
int res;
res = 0;
stringp = ast_strdupa(tonestring);
for (;tonestring;) {
tonesubset = strsep(&stringp, ")");
if (!tonesubset)
break;
if (sscanf(tonesubset, "(%d,%d,%d,%d", &f1, &f2, &duration, &litude) != 4)
break;
res = play_tone_pair(chan, f1, f2, duration, amplitude);
if (res)
break;
}
if (!res)
res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
if (!res)
res = ast_waitstream(chan, "");
ast_stopstream(chan);
/*
* Wait for the zaptel driver to physically write the tone blocks to the hardware
*/
for (i = 0; i < 20 ; i++) {
flags = ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT;
res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
if (flags & ZT_IOMUX_WRITEEMPTY)
if (ast_safe_sleep(chan, 50)) {
return res;
}
Tilghman Lesher
committed
static int sayfile(struct ast_channel *mychannel, const char *fname)
int res;
res = ast_streamfile(mychannel, fname, mychannel->language);
if (!res)
res = ast_waitstream(mychannel, "");
else
ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
ast_stopstream(mychannel);
return res;
}
static int saycharstr(struct ast_channel *mychannel, char *str)
int res;
res = ast_say_character_str(mychannel, str, NULL, mychannel->language);
if (!res)
res = ast_waitstream(mychannel, "");
else
ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
ast_stopstream(mychannel);
return res;
}
static int saynum(struct ast_channel *mychannel, int num)
{
int res;
res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
if (!res)
res = ast_waitstream(mychannel, "");
else
ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
ast_stopstream(mychannel);
return res;
}
static int saydigits(struct ast_channel *mychannel, int num)
{
int res;
res = ast_say_digits(mychannel, num, NULL, mychannel->language);
if (!res)
res = ast_waitstream(mychannel, "");
else
ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
ast_stopstream(mychannel);
return res;
}
static int telem_any(struct rpt *myrpt, struct ast_channel *chan, const char *entry)
{
int res;
char c;
static int morsespeed;
static int morsefreq;
static int morseampl;
static int morseidfreq = 0;
static int morseidampl;
static char mcat[] = MORSE;
res = 0;
if (!morseidfreq) { /* Get the morse parameters if not already loaded */
Jim Dixon
committed
morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
Jim Dixon
committed
morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330);
}
/* Is it a file, or a tone sequence? */
if (entry[0] == '|') {
c = entry[1];
if ((c >= 'a') && (c <= 'z'))
c -= 0x20;
switch (c) {
case 'I': /* Morse ID */
res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
break;
case 'M': /* Morse Message */
res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
break;
case 'T': /* Tone sequence */
res = send_tone_telemetry(chan, entry + 2);
break;
default:
res = -1;
}
} else
res = sayfile(chan, entry); /* File */
return res;
}
/*
* This function looks up a telemetry name in the config file, and does a telemetry response as configured.
*
* 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
*/
static int telem_lookup(struct rpt *myrpt, struct ast_channel *chan, const char *node, const char *name)
{
int res = 0;
int i;
const char *entry = NULL;
Tilghman Lesher
committed
const char *telemetry;
/* Retrieve the section name for telemetry from the node section */
if ((telemetry = ast_variable_retrieve(myrpt->cfg, node, TELEMETRY)))
entry = ast_variable_retrieve(myrpt->cfg, telemetry, name);
Jim Dixon
committed
/* Try to look up the telemetry name */
if (!entry) {
/* Telemetry name wasn't found in the config file, use the default */
for (i = 0; i < sizeof(tele_defs) / sizeof(struct telem_defaults); i++) {
if (!strcasecmp(tele_defs[i].name, name))
entry = tele_defs[i].value;
}
}
if (entry) {
if (!ast_strlen_zero(entry))
telem_any(myrpt, chan, entry);
} else {
res = -1;
}
return res;
}
/*
* Retrieve a wait interval
*/
static int get_wait_interval(struct rpt *myrpt, int type)
{
int interval = 1000;
const char *wait_times = ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
switch (type) {
case DLY_TELEM:
if (wait_times)
interval = retrieve_astcfgint(myrpt, wait_times, "telemwait", 500, 5000, 1000);
break;
case DLY_ID:
if (wait_times)
interval = retrieve_astcfgint(myrpt, wait_times, "idwait", 250, 5000, 500);
else
interval = 500;
break;
case DLY_UNKEY:
if (wait_times)
interval = retrieve_astcfgint(myrpt, wait_times, "unkeywait", 500, 5000, 1000);
break;
case DLY_CALLTERM:
if (wait_times)
interval = retrieve_astcfgint(myrpt, wait_times, "calltermwait", 500, 5000, 1500);
break;
default:
return 0;
}
/*
* Wait a configurable interval of time
*/
static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
{
int interval;
Jim Dixon
committed
interval = get_wait_interval(myrpt, type);
if (debug)
ast_log(LOG_NOTICE, " Delay interval = %d\n", interval);
if (interval)
if (debug)
ast_log(LOG_NOTICE, "Delay complete\n");
return;
}
static void *rpt_tele_thread(void *this)
ZT_CONFINFO ci; /* conference info */
int res = 0, haslink, hastx, hasremote, imdone = 0, unkeys_queued, x;
struct rpt_tele *mytele = (struct rpt_tele *)this;
struct rpt_tele *tlist;
struct rpt *myrpt;
struct rpt_link *l, *m, linkbase;
struct ast_channel *mychannel;
Tilghman Lesher
committed
const char *p, *ct;
struct timeval tv;
Tilghman Lesher
committed
struct ast_tm localtm;
#ifdef APP_RPT_LOCK_DEBUG
struct lockthread *t;
#endif
/* get a pointer to myrpt */
myrpt = mytele->rpt;
/* Snag copies of a few key myrpt variables */
rpt_mutex_lock(&myrpt->lock);
rpt_mutex_unlock(&myrpt->lock);
mychannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
if (!mychannel) {
ast_log(LOG_WARNING, "rpt: unable to obtain pseudo channel\n");
rpt_mutex_lock(&myrpt->lock);
remque((struct qelem *)mytele);
ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode); /*@@@@@@@@@@@*/
rpt_mutex_unlock(&myrpt->lock);
ast_free(mytele);
rpt_mutex_lock(&myrpt->lock);
mytele->chan = mychannel; /* Save a copy of the channel so we can access it externally if need be */
rpt_mutex_unlock(&myrpt->lock);
/* make a conference for the tx */
ci.chan = 0;
/* If there's an ID queued, or tail message queued, */
/* only connect the ID audio to the local tx conference so */
/* linked systems can't hear it */
ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) ||
(mytele->mode == TAILMSG)) ?
myrpt->txconf : myrpt->conf);
ci.confmode = ZT_CONF_CONFANN;
/* first put the channel on the conference in announce mode */
if (ioctl(mychannel->fds[0], ZT_SETCONF, &ci) == -1) {
ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
rpt_mutex_lock(&myrpt->lock);
remque((struct qelem *)mytele);
rpt_mutex_unlock(&myrpt->lock);
ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode); /*@@@@@@@@@@@*/
ast_free(mytele);
ast_hangup(mychannel);
pthread_exit(NULL);
}
ast_stopstream(mychannel);
switch (mytele->mode) {
case ID:
case ID1:
Jim Dixon
committed
/* wait a bit */
wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM, mychannel);
res = telem_any(myrpt, mychannel, myrpt->p.ident);
imdone=1;
break;
case TAILMSG:
res = ast_streamfile(mychannel, myrpt->p.tailmsg.msgs[myrpt->tailmessagen], mychannel->language);
break;
case IDTALKOVER:
p = ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
if (p)
res = telem_any(myrpt, mychannel, p);
imdone = 1;
break;
case PROC:
/* wait a little bit longer */
wait_interval(myrpt, DLY_TELEM, mychannel);
Jim Dixon
committed
res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
if (res < 0) { /* Then default message */
Jim Dixon
committed
res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
}
break;
case TERM:
/* wait a little bit longer */
wait_interval(myrpt, DLY_CALLTERM, mychannel);
Jim Dixon
committed
res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
if (res < 0) { /* Then default message */
Jim Dixon
committed
res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
}
break;
case COMPLETE:
/* wait a little bit */
wait_interval(myrpt, DLY_TELEM, mychannel);
res = telem_lookup(myrpt, mychannel, myrpt->name, "functcomplete");
break;
case MACRO_NOTFOUND: