dahdi_span_types: hush warning of missing attribute
[dahdi/tools.git] / fxstest.c
1 /*
2  * Written by Mark Spencer <markster@digium.com>
3  * Based on previous works, designs, and architectures conceived and
4  * written by Jim Dixon <jim@lambdatel.com>.
5  *
6  * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
7  * Copyright (C) 2001-2008 Digium, Inc.
8  *
9  * All rights reserved.
10  *
11  * Primary Author: Mark Spencer <markster@digium.com>
12  * Radio Support by Jim Dixon <jim@lambdatel.com>
13  */
14
15 /*
16  * See http://www.asterisk.org for more information about
17  * the Asterisk project. Please do not directly contact
18  * any of the maintainers of this project for assistance;
19  * the project provides a web site, mailing lists and IRC
20  * channels for your use.
21  *
22  * This program is free software, distributed under the terms of
23  * the GNU General Public License Version 2 as published by the
24  * Free Software Foundation. See the LICENSE file included with
25  * this program for more details.
26  */
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <sys/ioctl.h>
36 #include <sys/stat.h>
37 #include <dahdi/user.h>
38 #include <dahdi/wctdm_user.h>
39
40 #include "tonezone.h"
41 #include "dahdi_tools_version.h"
42
43 static int tones[] = {
44         DAHDI_TONE_DIALTONE,
45         DAHDI_TONE_BUSY,
46         DAHDI_TONE_RINGTONE,
47         DAHDI_TONE_CONGESTION,
48         DAHDI_TONE_DIALRECALL,
49 };
50
51 struct dahdi_vmwi_info mwisend_setting; /*!< Which VMWI methods to use */
52
53 /* Use to translate a DTMF character to the value required by the dahdi call */
54 static int digit_to_dtmfindex(char digit)
55 {
56         if (isdigit(digit))
57                 return DAHDI_TONE_DTMF_BASE + (digit - '0');
58         else if (digit >= 'A' && digit <= 'D')
59                 return DAHDI_TONE_DTMF_A + (digit - 'A');
60         else if (digit >= 'a' && digit <= 'd')
61                 return DAHDI_TONE_DTMF_A + (digit - 'a');
62         else if (digit == '*')
63                 return DAHDI_TONE_DTMF_s;
64         else if (digit == '#')
65                 return DAHDI_TONE_DTMF_p;
66         else
67                 return -1;
68 }
69
70 /* Place a channel into ringing mode */
71 static int dahdi_ring_phone(int fd)
72 {
73         int x;
74         int res;
75         /* Make sure our transmit state is on hook */
76         x = 0;
77         x = DAHDI_ONHOOK;
78         res = ioctl(fd, DAHDI_HOOK, &x);
79         do {
80                 x = DAHDI_RING;
81                 res = ioctl(fd, DAHDI_HOOK, &x);
82                 if (res) {
83                         switch (errno) {
84                                 case EBUSY:
85                                 case EINTR:
86                                         /* Wait just in case */
87                                         fprintf(stderr, "Ring phone is busy:%s\n", strerror(errno));
88                                         usleep(10000);
89                                         continue;
90                                 case EINPROGRESS:
91                                         fprintf(stderr, "Ring In Progress:%s\n", strerror(errno));
92                                         res = 0;
93                                         break;
94                                 default:
95                                         fprintf(stderr, "Couldn't ring the phone: %s\n", strerror(errno));
96                                         res = 0;
97                         }
98                 } else {
99                         fprintf(stderr, "Phone is ringing\n");
100                 }
101         } while (res);
102         return res;
103 }
104
105 int channel_open(const char *name)
106 {
107         int     channo, fd;
108         struct  stat filestat;
109         const char *DEVICE = "/dev/dahdi/channel";
110
111         /* stat file, if character device, open it */
112         channo = strtoul(name, NULL, 10);
113         fd = stat(name, &filestat);
114         if (!fd && S_ISCHR(filestat.st_mode)) {
115                 fd = open(name, O_RDWR, 0600);
116                 if (fd < 0) {
117                         perror(name);
118                         return -1;
119                 }
120         /* try out the dahdi_specify interface */
121         } else if (channo > 0) {
122                 fd = open(DEVICE, O_RDWR, 0600);
123                 if (fd < 0) {
124                         perror(DEVICE);
125                         return -1;
126                 }
127                 if (ioctl(fd, DAHDI_SPECIFY, &channo) < 0) {
128                         perror("DAHDI_SPECIFY ioctl failed");
129                         return -1;
130                 }
131         /* die */
132         } else {
133                 fprintf(stderr, "Specified channel is not a valid character "
134                         "device or channel number");
135                 return -1;
136         }
137         return fd;
138 }
139
140 int main(int argc, char *argv[])
141 {
142         int fd;
143         int res;
144         int x;
145         if (argc < 3) {
146                 fprintf(stderr, "Usage: fxstest <dahdi device> <cmd>\n"
147                        "       where cmd is one of:\n"
148                        "       stats - reports voltages\n"
149                        "       regdump - dumps ProSLIC registers\n"
150                        "       tones - plays a series of tones\n"
151                        "       polarity - tests polarity reversal\n"
152                        "       ring - rings phone\n"
153                        "       vmwi - toggles VMWI LED lamp\n"
154                        "       hvdc - toggles VMWI HV lamp\n"
155                        "       neon - toggles VMWI NEON lamp\n"
156                        "       dtmf <sequence> [<duration>]- Send a sequence of dtmf tones (\"-\" denotes no tone)\n"
157                        "       dtmfcid - create a dtmf cid spill without polarity reversal\n");
158                 exit(1);
159         }
160         fd = channel_open(argv[1]);
161         if (fd < 0) {
162                 fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno));
163                 exit(1);
164         }
165         
166         if ( !strcasecmp(argv[2], "neon") || !strcasecmp(argv[2], "vmwi") || !strcasecmp(argv[2], "hvdc")) {
167                 fprintf(stderr, "Twiddling %s ...\n", argv[2]);
168
169                 if ( !strcasecmp(argv[2], "vmwi") ) {
170                         mwisend_setting.vmwi_type = DAHDI_VMWI_LREV;
171                 } else if ( !strcasecmp(argv[2], "neon") ) {
172                         mwisend_setting.vmwi_type = DAHDI_VMWI_HVAC;
173                 } else if ( !strcasecmp(argv[2], "hvdc") ) {
174                         mwisend_setting.vmwi_type = DAHDI_VMWI_HVDC;
175                 }
176                 res = ioctl(fd, DAHDI_VMWI_CONFIG, &mwisend_setting);
177
178                 x = 1;
179                 res = ioctl(fd, DAHDI_VMWI, &x);
180                 if (res) {
181                         fprintf(stderr, "Unable to set %s ...\n", argv[2]);
182                 } else {
183                         fprintf(stderr, "Set 1 Voice Message...\n");
184
185                         sleep(5);
186                         x = 2;
187                         ioctl(fd, DAHDI_VMWI, &x);
188                         fprintf(stderr, "Set 2 Voice Messages...\n");
189
190                         sleep(5);
191                         x = 0;
192                         ioctl(fd, DAHDI_VMWI, &x);
193                         fprintf(stderr, "Set No Voice messages...\n");
194                         sleep(2);
195                         mwisend_setting.vmwi_type = 0;
196                 }
197         } else if (!strcasecmp(argv[2], "ring")) {
198                 fprintf(stderr, "Ringing phone...\n");
199                 x = DAHDI_RING;
200                 res = ioctl(fd, DAHDI_HOOK, &x);
201                 if (res) {
202                         fprintf(stderr, "Unable to ring phone...\n");
203                 } else {
204                         fprintf(stderr, "Phone is ringing...\n");
205                         sleep(2);
206                 }
207         } else if (!strcasecmp(argv[2], "polarity")) {
208                 fprintf(stderr, "Twiddling polarity...\n");
209                 /* Insure that the channel is in active mode */
210                 x = DAHDI_RING;
211                 res = ioctl(fd, DAHDI_HOOK, &x);
212                 usleep(100000);
213                 x = 0;
214                 res = ioctl(fd, DAHDI_HOOK, &x);
215
216                 x = 0;
217                 res = ioctl(fd, DAHDI_SETPOLARITY, &x);
218                 if (res) {
219                         fprintf(stderr, "Unable to polarity...\n");
220                 } else {
221                         fprintf(stderr, "Polarity is forward...\n");
222                         sleep(2);
223                         x = 1;
224                         ioctl(fd, DAHDI_SETPOLARITY, &x);
225                         fprintf(stderr, "Polarity is reversed...\n");
226                         sleep(5);
227                         x = 0;
228                         ioctl(fd, DAHDI_SETPOLARITY, &x);
229                         fprintf(stderr, "Polarity is forward...\n");
230                         sleep(2);
231                 }
232         } else if (!strcasecmp(argv[2], "tones")) {
233                 int x = 0;
234                 for (;;) {
235                         res = tone_zone_play_tone(fd, tones[x]);
236                         if (res)
237                                 fprintf(stderr, "Unable to play tone %d\n", tones[x]);
238                         sleep(3);
239                         x=(x+1) % (sizeof(tones) / sizeof(tones[0]));
240                 }
241         } else if (!strcasecmp(argv[2], "stats")) {
242                 struct wctdm_stats stats;
243                 res = ioctl(fd, WCTDM_GET_STATS, &stats);
244                 if (res) {
245                         fprintf(stderr, "Unable to get stats on channel %s\n", argv[1]);
246                 } else {
247                         printf("TIP: %7.4f Volts\n", (float)stats.tipvolt / 1000.0);
248                         printf("RING: %7.4f Volts\n", (float)stats.ringvolt / 1000.0);
249                         printf("VBAT: %7.4f Volts\n", (float)stats.batvolt / 1000.0);
250                 }
251         } else if (!strcasecmp(argv[2], "regdump")) {
252                 struct wctdm_regs regs;
253                 int numregs = NUM_REGS;
254                 memset(&regs, 0, sizeof(regs));
255                 res = ioctl(fd, WCTDM_GET_REGS, &regs);
256                 if (res) {
257                         fprintf(stderr, "Unable to get registers on channel %s\n", argv[1]);
258                 } else {
259                         for (x=60;x<NUM_REGS;x++) {
260                                 if (regs.direct[x])
261                                         break;
262                         }
263                         if (x == NUM_REGS) 
264                                 numregs = 60;
265                         printf("Direct registers: \n");
266                         for (x=0;x<numregs;x++) {
267                                 printf("%3d. %02x  ", x, regs.direct[x]);
268                                 if ((x % 8) == 7)
269                                         printf("\n");
270                         }
271                         if (numregs == NUM_REGS) {
272                                 printf("\n\nIndirect registers: \n");
273                                 for (x=0;x<NUM_INDIRECT_REGS;x++) {
274                                         printf("%3d. %04x  ", x, regs.indirect[x]);
275                                         if ((x % 6) == 5)
276                                                 printf("\n");
277                                 }
278                         }
279                         printf("\n\n");
280                 }
281         } else if (!strcasecmp(argv[2], "setdirect") ||
282                                 !strcasecmp(argv[2], "setindirect")) {
283                 struct wctdm_regop regop;
284                 int val;
285                 int reg;
286                 if ((argc < 5) || (sscanf(argv[3], "%i", &reg) != 1) ||
287                         (sscanf(argv[4], "%i", &val) != 1)) {
288                         fprintf(stderr, "Need a register and value...\n");
289                 } else {
290                         regop.reg = reg;
291                         regop.val = val;
292                         if (!strcasecmp(argv[2], "setindirect")) {
293                                 regop.indirect = 1;
294                         } else {
295                                 regop.indirect = 0;
296                         }
297                         res = ioctl(fd, WCTDM_SET_REG, &regop);
298                         if (res) 
299                                 fprintf(stderr, "Unable to get registers on channel %s\n", argv[1]);
300                         else
301                                 printf("Success.\n");
302                 }
303         } else if (!strcasecmp(argv[2], "dtmf")) {
304                 int duration = 50;  /* default to 50 mS duration */
305                 char * outstring = "";
306                 int dtmftone;
307
308                 if(argc < 4) {  /* user supplied string */
309                         fprintf(stderr, "You must specify a string of dtmf characters to send\n");
310                 } else {
311                         outstring = argv[3];
312                         if(argc >= 5) {
313                                 sscanf(argv[4], "%30i", &duration);
314                         }
315                         printf("Going to send a set of DTMF tones >%s<\n", outstring);
316                         printf("Using a duration of %d mS per tone\n", duration);
317                                         /* Flush any left remaining characs in the buffer and place the channel into on-hook transfer mode */
318                         x = DAHDI_FLUSH_BOTH;
319                         res = ioctl(fd, DAHDI_FLUSH, &x);
320                         x = 500 + strlen(outstring) * duration;
321                         ioctl(fd, DAHDI_ONHOOKTRANSFER, &x);
322
323                         for (x = 0; '\0' != outstring[x]; x++) {
324                                 dtmftone = digit_to_dtmfindex(outstring[x]);
325                                 if (0 > dtmftone) {
326                                         dtmftone = -1;
327                                 }
328                                 res = tone_zone_play_tone(fd, dtmftone);
329                                 if (res) {
330                                         fprintf(stderr, "Unable to play DTMF tone %d (0x%x)\n", dtmftone, dtmftone);
331                                 }
332                                 usleep(duration * 1000);
333                         }
334                 }
335         } else if (!strcasecmp(argv[2], "dtmfcid")) {
336                 char * outstring = "A5551212C";  /* Default string using A and C tones to bracket the number */
337                 int dtmftone;
338                 
339                 if(argc >= 4) { /* Use user supplied string */
340                         outstring = argv[3];
341                 }
342                 printf("Going to send a set of DTMF tones >%s<\n", outstring);
343                 /* Flush any left remaining characs in the buffer and place the channel into on-hook transfer mode */
344                 x = DAHDI_FLUSH_BOTH;
345                 res = ioctl(fd, DAHDI_FLUSH, &x);
346                 x = 500 + strlen(outstring) * 100;
347                 ioctl(fd, DAHDI_ONHOOKTRANSFER, &x);
348
349                 /* Play the DTMF tones at a 50 mS on and 50 mS off rate which is standard for DTMF CID spills */
350                 for (x = 0; '\0' != outstring[x]; x++) {
351
352                         dtmftone = digit_to_dtmfindex(outstring[x]);
353                         if (0 > dtmftone) {
354                                 dtmftone = -1;
355                         }
356                         res = tone_zone_play_tone(fd, dtmftone);
357                         if (res) {
358                                 fprintf(stderr, "Unable to play DTMF tone %d (0x%x)\n", dtmftone, dtmftone);
359                         }
360                         usleep(50000);
361                         tone_zone_play_tone(fd, -1);
362                         usleep(50000);
363                 }
364                 /* Wait for 150 mS from end of last tone to initiating the ring */
365                 usleep(100000);
366                 dahdi_ring_phone(fd);
367                 sleep(10);
368                 printf("Ringing Done\n");
369         } else
370                 fprintf(stderr, "Invalid command\n");
371         close(fd);
372         return 0;
373 }