2010-08-18 21:49:24 +08:00
|
|
|
/*
|
|
|
|
* Written by Mark Spencer <markster@digium.com>
|
|
|
|
* Based on previous works, designs, and architectures conceived and
|
|
|
|
* written by Jim Dixon <jim@lambdatel.com>.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2001 Jim Dixon / Zapata Telephony.
|
|
|
|
* Copyright (C) 2001-2008 Digium, Inc.
|
|
|
|
*
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Primary Author: Mark Spencer <markster@digium.com>
|
|
|
|
* Radio Support by Jim Dixon <jim@lambdatel.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See http://www.asterisk.org for more information about
|
|
|
|
* the Asterisk project. Please do not directly contact
|
|
|
|
* any of the maintainers of this project for assistance;
|
|
|
|
* the project provides a web site, mailing lists and IRC
|
|
|
|
* channels for your use.
|
|
|
|
*
|
|
|
|
* This program is free software, distributed under the terms of
|
|
|
|
* the GNU General Public License Version 2 as published by the
|
|
|
|
* Free Software Foundation. See the LICENSE file included with
|
|
|
|
* this program for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/ioctl.h>
|
2013-05-09 23:34:20 +08:00
|
|
|
#include <sys/stat.h>
|
2010-08-18 21:49:24 +08:00
|
|
|
#include <dahdi/user.h>
|
|
|
|
#include <dahdi/wctdm_user.h>
|
|
|
|
|
|
|
|
#include "tonezone.h"
|
|
|
|
#include "dahdi_tools_version.h"
|
|
|
|
|
|
|
|
static int tones[] = {
|
|
|
|
DAHDI_TONE_DIALTONE,
|
|
|
|
DAHDI_TONE_BUSY,
|
|
|
|
DAHDI_TONE_RINGTONE,
|
|
|
|
DAHDI_TONE_CONGESTION,
|
|
|
|
DAHDI_TONE_DIALRECALL,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct dahdi_vmwi_info mwisend_setting; /*!< Which VMWI methods to use */
|
|
|
|
|
|
|
|
/* Use to translate a DTMF character to the value required by the dahdi call */
|
|
|
|
static int digit_to_dtmfindex(char digit)
|
|
|
|
{
|
|
|
|
if (isdigit(digit))
|
|
|
|
return DAHDI_TONE_DTMF_BASE + (digit - '0');
|
|
|
|
else if (digit >= 'A' && digit <= 'D')
|
|
|
|
return DAHDI_TONE_DTMF_A + (digit - 'A');
|
|
|
|
else if (digit >= 'a' && digit <= 'd')
|
|
|
|
return DAHDI_TONE_DTMF_A + (digit - 'a');
|
|
|
|
else if (digit == '*')
|
|
|
|
return DAHDI_TONE_DTMF_s;
|
|
|
|
else if (digit == '#')
|
|
|
|
return DAHDI_TONE_DTMF_p;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Place a channel into ringing mode */
|
|
|
|
static int dahdi_ring_phone(int fd)
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
int res;
|
|
|
|
/* Make sure our transmit state is on hook */
|
|
|
|
x = 0;
|
|
|
|
x = DAHDI_ONHOOK;
|
|
|
|
res = ioctl(fd, DAHDI_HOOK, &x);
|
|
|
|
do {
|
|
|
|
x = DAHDI_RING;
|
|
|
|
res = ioctl(fd, DAHDI_HOOK, &x);
|
|
|
|
if (res) {
|
|
|
|
switch (errno) {
|
|
|
|
case EBUSY:
|
|
|
|
case EINTR:
|
|
|
|
/* Wait just in case */
|
|
|
|
fprintf(stderr, "Ring phone is busy:%s\n", strerror(errno));
|
|
|
|
usleep(10000);
|
|
|
|
continue;
|
|
|
|
case EINPROGRESS:
|
|
|
|
fprintf(stderr, "Ring In Progress:%s\n", strerror(errno));
|
|
|
|
res = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "Couldn't ring the phone: %s\n", strerror(errno));
|
|
|
|
res = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Phone is ringing\n");
|
|
|
|
}
|
|
|
|
} while (res);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2013-05-09 23:34:20 +08:00
|
|
|
int channel_open(const char *name)
|
|
|
|
{
|
|
|
|
int channo, fd;
|
|
|
|
struct stat filestat;
|
|
|
|
const char *DEVICE = "/dev/dahdi/channel";
|
|
|
|
|
|
|
|
/* stat file, if character device, open it */
|
|
|
|
channo = strtoul(name, NULL, 10);
|
|
|
|
fd = stat(name, &filestat);
|
|
|
|
if (!fd && S_ISCHR(filestat.st_mode)) {
|
|
|
|
fd = open(name, O_RDWR, 0600);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror(name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* try out the dahdi_specify interface */
|
|
|
|
} else if (channo > 0) {
|
|
|
|
fd = open(DEVICE, O_RDWR, 0600);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror(DEVICE);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (ioctl(fd, DAHDI_SPECIFY, &channo) < 0) {
|
|
|
|
perror("DAHDI_SPECIFY ioctl failed");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* die */
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Specified channel is not a valid character "
|
|
|
|
"device or channel number");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2010-08-18 21:49:24 +08:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
int res;
|
|
|
|
int x;
|
|
|
|
if (argc < 3) {
|
|
|
|
fprintf(stderr, "Usage: fxstest <dahdi device> <cmd>\n"
|
|
|
|
" where cmd is one of:\n"
|
|
|
|
" stats - reports voltages\n"
|
|
|
|
" regdump - dumps ProSLIC registers\n"
|
|
|
|
" tones - plays a series of tones\n"
|
|
|
|
" polarity - tests polarity reversal\n"
|
|
|
|
" ring - rings phone\n"
|
|
|
|
" vmwi - toggles VMWI LED lamp\n"
|
|
|
|
" hvdc - toggles VMWI HV lamp\n"
|
|
|
|
" neon - toggles VMWI NEON lamp\n"
|
|
|
|
" dtmf <sequence> [<duration>]- Send a sequence of dtmf tones (\"-\" denotes no tone)\n"
|
|
|
|
" dtmfcid - create a dtmf cid spill without polarity reversal\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2013-05-09 23:34:20 +08:00
|
|
|
fd = channel_open(argv[1]);
|
2010-08-18 21:49:24 +08:00
|
|
|
if (fd < 0) {
|
|
|
|
fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !strcasecmp(argv[2], "neon") || !strcasecmp(argv[2], "vmwi") || !strcasecmp(argv[2], "hvdc")) {
|
|
|
|
fprintf(stderr, "Twiddling %s ...\n", argv[2]);
|
|
|
|
|
|
|
|
if ( !strcasecmp(argv[2], "vmwi") ) {
|
|
|
|
mwisend_setting.vmwi_type = DAHDI_VMWI_LREV;
|
|
|
|
} else if ( !strcasecmp(argv[2], "neon") ) {
|
|
|
|
mwisend_setting.vmwi_type = DAHDI_VMWI_HVAC;
|
|
|
|
} else if ( !strcasecmp(argv[2], "hvdc") ) {
|
|
|
|
mwisend_setting.vmwi_type = DAHDI_VMWI_HVDC;
|
|
|
|
}
|
|
|
|
res = ioctl(fd, DAHDI_VMWI_CONFIG, &mwisend_setting);
|
|
|
|
|
|
|
|
x = 1;
|
|
|
|
res = ioctl(fd, DAHDI_VMWI, &x);
|
|
|
|
if (res) {
|
|
|
|
fprintf(stderr, "Unable to set %s ...\n", argv[2]);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Set 1 Voice Message...\n");
|
|
|
|
|
|
|
|
sleep(5);
|
|
|
|
x = 2;
|
|
|
|
ioctl(fd, DAHDI_VMWI, &x);
|
|
|
|
fprintf(stderr, "Set 2 Voice Messages...\n");
|
|
|
|
|
|
|
|
sleep(5);
|
|
|
|
x = 0;
|
|
|
|
ioctl(fd, DAHDI_VMWI, &x);
|
|
|
|
fprintf(stderr, "Set No Voice messages...\n");
|
|
|
|
sleep(2);
|
|
|
|
mwisend_setting.vmwi_type = 0;
|
|
|
|
}
|
|
|
|
} else if (!strcasecmp(argv[2], "ring")) {
|
|
|
|
fprintf(stderr, "Ringing phone...\n");
|
|
|
|
x = DAHDI_RING;
|
|
|
|
res = ioctl(fd, DAHDI_HOOK, &x);
|
|
|
|
if (res) {
|
|
|
|
fprintf(stderr, "Unable to ring phone...\n");
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Phone is ringing...\n");
|
|
|
|
sleep(2);
|
|
|
|
}
|
|
|
|
} else if (!strcasecmp(argv[2], "polarity")) {
|
|
|
|
fprintf(stderr, "Twiddling polarity...\n");
|
|
|
|
/* Insure that the channel is in active mode */
|
|
|
|
x = DAHDI_RING;
|
|
|
|
res = ioctl(fd, DAHDI_HOOK, &x);
|
|
|
|
usleep(100000);
|
|
|
|
x = 0;
|
|
|
|
res = ioctl(fd, DAHDI_HOOK, &x);
|
|
|
|
|
|
|
|
x = 0;
|
|
|
|
res = ioctl(fd, DAHDI_SETPOLARITY, &x);
|
|
|
|
if (res) {
|
|
|
|
fprintf(stderr, "Unable to polarity...\n");
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Polarity is forward...\n");
|
|
|
|
sleep(2);
|
|
|
|
x = 1;
|
|
|
|
ioctl(fd, DAHDI_SETPOLARITY, &x);
|
|
|
|
fprintf(stderr, "Polarity is reversed...\n");
|
|
|
|
sleep(5);
|
|
|
|
x = 0;
|
|
|
|
ioctl(fd, DAHDI_SETPOLARITY, &x);
|
|
|
|
fprintf(stderr, "Polarity is forward...\n");
|
|
|
|
sleep(2);
|
|
|
|
}
|
|
|
|
} else if (!strcasecmp(argv[2], "tones")) {
|
|
|
|
int x = 0;
|
|
|
|
for (;;) {
|
|
|
|
res = tone_zone_play_tone(fd, tones[x]);
|
|
|
|
if (res)
|
|
|
|
fprintf(stderr, "Unable to play tone %d\n", tones[x]);
|
|
|
|
sleep(3);
|
|
|
|
x=(x+1) % (sizeof(tones) / sizeof(tones[0]));
|
|
|
|
}
|
|
|
|
} else if (!strcasecmp(argv[2], "stats")) {
|
|
|
|
struct wctdm_stats stats;
|
|
|
|
res = ioctl(fd, WCTDM_GET_STATS, &stats);
|
|
|
|
if (res) {
|
|
|
|
fprintf(stderr, "Unable to get stats on channel %s\n", argv[1]);
|
|
|
|
} else {
|
|
|
|
printf("TIP: %7.4f Volts\n", (float)stats.tipvolt / 1000.0);
|
|
|
|
printf("RING: %7.4f Volts\n", (float)stats.ringvolt / 1000.0);
|
|
|
|
printf("VBAT: %7.4f Volts\n", (float)stats.batvolt / 1000.0);
|
|
|
|
}
|
|
|
|
} else if (!strcasecmp(argv[2], "regdump")) {
|
|
|
|
struct wctdm_regs regs;
|
|
|
|
int numregs = NUM_REGS;
|
|
|
|
memset(®s, 0, sizeof(regs));
|
|
|
|
res = ioctl(fd, WCTDM_GET_REGS, ®s);
|
|
|
|
if (res) {
|
|
|
|
fprintf(stderr, "Unable to get registers on channel %s\n", argv[1]);
|
|
|
|
} else {
|
|
|
|
for (x=60;x<NUM_REGS;x++) {
|
|
|
|
if (regs.direct[x])
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (x == NUM_REGS)
|
|
|
|
numregs = 60;
|
|
|
|
printf("Direct registers: \n");
|
|
|
|
for (x=0;x<numregs;x++) {
|
|
|
|
printf("%3d. %02x ", x, regs.direct[x]);
|
|
|
|
if ((x % 8) == 7)
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
if (numregs == NUM_REGS) {
|
|
|
|
printf("\n\nIndirect registers: \n");
|
|
|
|
for (x=0;x<NUM_INDIRECT_REGS;x++) {
|
|
|
|
printf("%3d. %04x ", x, regs.indirect[x]);
|
|
|
|
if ((x % 6) == 5)
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
printf("\n\n");
|
|
|
|
}
|
|
|
|
} else if (!strcasecmp(argv[2], "setdirect") ||
|
|
|
|
!strcasecmp(argv[2], "setindirect")) {
|
|
|
|
struct wctdm_regop regop;
|
|
|
|
int val;
|
|
|
|
int reg;
|
|
|
|
if ((argc < 5) || (sscanf(argv[3], "%i", ®) != 1) ||
|
|
|
|
(sscanf(argv[4], "%i", &val) != 1)) {
|
|
|
|
fprintf(stderr, "Need a register and value...\n");
|
|
|
|
} else {
|
|
|
|
regop.reg = reg;
|
|
|
|
regop.val = val;
|
|
|
|
if (!strcasecmp(argv[2], "setindirect")) {
|
|
|
|
regop.indirect = 1;
|
|
|
|
} else {
|
|
|
|
regop.indirect = 0;
|
|
|
|
}
|
|
|
|
res = ioctl(fd, WCTDM_SET_REG, ®op);
|
|
|
|
if (res)
|
|
|
|
fprintf(stderr, "Unable to get registers on channel %s\n", argv[1]);
|
|
|
|
else
|
|
|
|
printf("Success.\n");
|
|
|
|
}
|
|
|
|
} else if (!strcasecmp(argv[2], "dtmf")) {
|
|
|
|
int duration = 50; /* default to 50 mS duration */
|
|
|
|
char * outstring = "";
|
|
|
|
int dtmftone;
|
|
|
|
|
|
|
|
if(argc < 4) { /* user supplied string */
|
|
|
|
fprintf(stderr, "You must specify a string of dtmf characters to send\n");
|
|
|
|
} else {
|
|
|
|
outstring = argv[3];
|
|
|
|
if(argc >= 5) {
|
|
|
|
sscanf(argv[4], "%30i", &duration);
|
|
|
|
}
|
|
|
|
printf("Going to send a set of DTMF tones >%s<\n", outstring);
|
|
|
|
printf("Using a duration of %d mS per tone\n", duration);
|
|
|
|
/* Flush any left remaining characs in the buffer and place the channel into on-hook transfer mode */
|
|
|
|
x = DAHDI_FLUSH_BOTH;
|
|
|
|
res = ioctl(fd, DAHDI_FLUSH, &x);
|
|
|
|
x = 500 + strlen(outstring) * duration;
|
|
|
|
ioctl(fd, DAHDI_ONHOOKTRANSFER, &x);
|
|
|
|
|
|
|
|
for (x = 0; '\0' != outstring[x]; x++) {
|
|
|
|
dtmftone = digit_to_dtmfindex(outstring[x]);
|
|
|
|
if (0 > dtmftone) {
|
|
|
|
dtmftone = -1;
|
|
|
|
}
|
|
|
|
res = tone_zone_play_tone(fd, dtmftone);
|
|
|
|
if (res) {
|
|
|
|
fprintf(stderr, "Unable to play DTMF tone %d (0x%x)\n", dtmftone, dtmftone);
|
|
|
|
}
|
|
|
|
usleep(duration * 1000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (!strcasecmp(argv[2], "dtmfcid")) {
|
|
|
|
char * outstring = "A5551212C"; /* Default string using A and C tones to bracket the number */
|
|
|
|
int dtmftone;
|
|
|
|
|
|
|
|
if(argc >= 4) { /* Use user supplied string */
|
|
|
|
outstring = argv[3];
|
|
|
|
}
|
|
|
|
printf("Going to send a set of DTMF tones >%s<\n", outstring);
|
|
|
|
/* Flush any left remaining characs in the buffer and place the channel into on-hook transfer mode */
|
|
|
|
x = DAHDI_FLUSH_BOTH;
|
|
|
|
res = ioctl(fd, DAHDI_FLUSH, &x);
|
|
|
|
x = 500 + strlen(outstring) * 100;
|
|
|
|
ioctl(fd, DAHDI_ONHOOKTRANSFER, &x);
|
|
|
|
|
|
|
|
/* Play the DTMF tones at a 50 mS on and 50 mS off rate which is standard for DTMF CID spills */
|
|
|
|
for (x = 0; '\0' != outstring[x]; x++) {
|
|
|
|
|
|
|
|
dtmftone = digit_to_dtmfindex(outstring[x]);
|
|
|
|
if (0 > dtmftone) {
|
|
|
|
dtmftone = -1;
|
|
|
|
}
|
|
|
|
res = tone_zone_play_tone(fd, dtmftone);
|
|
|
|
if (res) {
|
|
|
|
fprintf(stderr, "Unable to play DTMF tone %d (0x%x)\n", dtmftone, dtmftone);
|
|
|
|
}
|
|
|
|
usleep(50000);
|
|
|
|
tone_zone_play_tone(fd, -1);
|
|
|
|
usleep(50000);
|
|
|
|
}
|
|
|
|
/* Wait for 150 mS from end of last tone to initiating the ring */
|
|
|
|
usleep(100000);
|
|
|
|
dahdi_ring_phone(fd);
|
|
|
|
sleep(10);
|
|
|
|
printf("Ringing Done\n");
|
|
|
|
} else
|
|
|
|
fprintf(stderr, "Invalid command\n");
|
|
|
|
close(fd);
|
|
|
|
return 0;
|
|
|
|
}
|