Newer
Older
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
rpt_vars[n].p.idtime = 2400000;
} else if (!strcmp(var->name, "politeid")) {
rpt_vars[n].p.politeid = atoi(var->value);
if (rpt_vars[n].p.politeid < 30000)
rpt_vars[n].p.politeid = 30000;
else if (rpt_vars[n].p.politeid > 300000)
rpt_vars[n].p.politeid = 300000;
} else if (!strcmp(var->name, "tonezone")) {
ast_copy_string(rpt_vars[n].p.tonezone, var->value, sizeof(rpt_vars[n].p.tonezone));
} else if (!strcmp(var->name, "tailmessagelist")) {
rpt_vars[n].p.tailmsgbuf = ast_strdup(var->value);
AST_NONSTANDARD_APP_ARGS(rpt_vars[n].p.tailmsg, rpt_vars[n].p.tailmsgbuf, ',');
} else if (!strcmp(var->name, "memory")) {
ast_copy_string(rpt_vars[n].p.memory, var->value, sizeof(rpt_vars[n].p.memory));
} else if (!strcmp(var->name, "macro")) {
ast_copy_string(rpt_vars[n].p.macro, var->value, sizeof(rpt_vars[n].p.macro));
} else if (!strcmp(var->name, "startup_macro")) {
ast_copy_string(rpt_vars[n].p.startupmacro, var->value, sizeof(rpt_vars[n].p.startupmacro));
} else if (!strcmp(var->name, "iobase")) {
/* do not use atoi() here, we need to be able to have
the input specified in hex or decimal so we use
sscanf with a %i */
if (sscanf(var->value, "%i", &rpt_vars[n].p.iobase) != 1)
rpt_vars[n].p.iobase = DEFAULT_IOBASE;
} else if (!strcmp(var->name, "functions")) {
rpt_vars[n].p.simple = 0;
ast_copy_string(rpt_vars[n].p.functions, var->value, sizeof(rpt_vars[n].p.functions));
} else if (!strcmp(var->name, "link_functions")) {
ast_copy_string(rpt_vars[n].p.link_functions, var->value, sizeof(rpt_vars[n].p.link_functions));
} else if (!strcmp(var->name, "phone_functions")) {
ast_copy_string(rpt_vars[n].p.phone_functions, var->value, sizeof(rpt_vars[n].p.phone_functions));
} else if (!strcmp(var->name, "dphone_functions")) {
ast_copy_string(rpt_vars[n].p.dphone_functions, var->value, sizeof(rpt_vars[n].p.dphone_functions));
} else if (!strcmp(var->name, "funcchar")) {
rpt_vars[n].p.funcchar = *var->value;
} else if (!strcmp(var->name, "endchar")) {
rpt_vars[n].p.endchar = *var->value;
} 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);
AST_NONSTANDARD_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;
}
ast_mutex_unlock(&rpt_vars[n].lock);
}
/*
* Enable or disable debug output at a given level at the console
*/
static int rpt_do_debug(int fd, int argc, char *argv[])
{
int newlevel;
if (argc != 4)
return RESULT_SHOWUSAGE;
newlevel = myatoi(argv[3]);
if ((newlevel < 0) || (newlevel > 7))
return RESULT_SHOWUSAGE;
if (newlevel)
ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
else
ast_cli(fd, "app_rpt Debugging disabled\n");
debug = newlevel;
return RESULT_SUCCESS;
/*
* Dump rpt struct debugging onto console
*/
static int rpt_do_dump(int fd, int argc, char *argv[])
{
int i;
if (argc != 3)
return RESULT_SHOWUSAGE;
for (i = 0; i < nrpts; i++) {
if (!strcmp(argv[2], rpt_vars[i].name)) {
rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
return RESULT_SUCCESS;
}
}
return RESULT_FAILURE;
}
Jim Dixon
committed
/*
* Dump statistics onto console
*/
static int rpt_do_stats(int fd, int argc, char *argv[])
{
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";
if (argc != 3)
Jim Dixon
committed
return RESULT_SHOWUSAGE;
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(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(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
ast_cli(fd, "Transmitter enabled..............................: %s\n", enable_state);
ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
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(fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
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(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
hours, minutes, seconds, (int) totaltxtime);
ast_cli(fd, "Nodes currently connected to us..................: ");
for (j = 0;; j++) {
if (!listoflinks[j]) {
if (!j) {
ast_cli(fd, "<NONE>");
Jim Dixon
committed
}
break;
}
ast_cli(fd, "%s", listoflinks[j]);
if (j % 4 == 3) {
Jim Dixon
committed
ast_cli(fd, "\n");
ast_cli(fd, " : ");
} else {
if (listoflinks[j + 1])
Jim Dixon
committed
ast_cli(fd, ", ");
}
}
ast_cli(fd, "\n");
Jim Dixon
committed
ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
ast_cli(fd, "Autopatch called number..........................: %s\n", called_number);
ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n\n", reverse_patch_state);
return RESULT_SUCCESS;
Jim Dixon
committed
}
}
return RESULT_FAILURE;
}
/*
* Link stats function
*/
static int rpt_do_lstats(int fd, int argc, char *argv[])
{
int i, j;
Jim Dixon
committed
struct rpt *myrpt;
struct rpt_link *l;
struct rpt_lstat *s,*t;
struct rpt_lstat s_head;
if (argc != 3)
Jim Dixon
committed
return RESULT_SHOWUSAGE;
s = NULL;
s_head.next = &s_head;
s_head.prev = &s_head;
for (i = 0; i < nrpts; i++) {
if (!strcmp(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;
}
if ((s = (struct rpt_lstat *) ast_calloc(1, sizeof(struct rpt_lstat))) == NULL) {
Jim Dixon
committed
ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
return RESULT_FAILURE;
}
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(fd, "NODE PEER RECONNECTS DIRECTION CONNECT TIME\n");
ast_cli(fd, "---- ---- ---------- --------- ------------\n");
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(fd, "%-10s%-20s%-12d%-11s%-30s\n",
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 RESULT_SUCCESS;
}
}
return RESULT_FAILURE;
}
/*
* reload vars
*/
static int rpt_do_reload(int fd, int argc, char *argv[])
{
int n;
Jim Dixon
committed
if (argc > 2)
return RESULT_SHOWUSAGE;
Jim Dixon
committed
for (n = 0; n < nrpts; n++)
rpt_vars[n].reload = 1;
Jim Dixon
committed
return RESULT_FAILURE;
}
/*
* restart app_rpt
*/
static int rpt_do_restart(int fd, int argc, char *argv[])
{
int i;
Jim Dixon
committed
if (argc > 2)
return RESULT_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 RESULT_FAILURE;
}
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[] = {
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
{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 */
1500
1501
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
{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 releationships */
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)
ast_safe_sleep(chan,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;
time_t t;
struct 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:
/* wait a little bit */
wait_interval(myrpt, DLY_TELEM, mychannel);
res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
break;
case MACRO_BUSY:
/* wait a little bit */
wait_interval(myrpt, DLY_TELEM, mychannel);
res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
break;
case UNKEY:
if (myrpt->patchnoct && myrpt->callmode) { /* If no CT during patch configured, then don't send one */
Jim Dixon
committed
imdone = 1;
break;
}
/*
* Reset the Unkey to CT timer
*/
x = get_wait_interval(myrpt, DLY_UNKEY);
rpt_mutex_lock(&myrpt->lock);
myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
rpt_mutex_unlock(&myrpt->lock);
/*
* If there's one already queued, don't do another
*/
tlist = myrpt->tele.next;
unkeys_queued = 0;
if (tlist != &myrpt->tele) {
rpt_mutex_lock(&myrpt->lock);
while (tlist != &myrpt->tele) {
if (tlist->mode == UNKEY)
unkeys_queued++;
tlist = tlist->next;
}
rpt_mutex_unlock(&myrpt->lock);
}
if (unkeys_queued > 1) {
imdone = 1;