/* * Written by Mark Spencer * Based on previous works, designs, and architectures conceived and * written by Jim Dixon . * * Copyright (C) 2001 Jim Dixon / Zapata Telephony. * Copyright (C) 2001-2008 Digium, Inc. * * All rights reserved. * * Primary Author: Mark Spencer * Radio Support by Jim Dixon */ /* * 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 #include #include #include #include #include #include #include #include #include #include #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; } 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; } int main(int argc, char *argv[]) { int fd; int res; int x; if (argc < 3) { fprintf(stderr, "Usage: fxstest \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 []- Send a sequence of dtmf tones (\"-\" denotes no tone)\n" " dtmfcid - create a dtmf cid spill without polarity reversal\n"); exit(1); } fd = channel_open(argv[1]); 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= 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; }