Werner Johansson
2005-Sep-03  08:05 UTC
[Asterisk-Users] Current status on _outgoing_ Swedish/Dutch DTMF CLIP for TDM400 FXS interfaces?
Hi all,
I have been looking at the code for both the zaptel driver (wctdm.c/wcfxs.c) 
and the asterisk channel driver (chan_zap.c) trying to figure out how much 
of this that has been implemented. So far I can see that the current stable 
1.0.9.1 zaptel driver don't have the SETPOLARITY ioctl that would be 
required to properly signal the Swedish/Dutch CLIP, but the 1.2 beta1 has 
this support..
Moving forward from that I then look at the 1.2 beta1 chan_zap code, but 
nothing's in there could possibly give us any DTMF tones. I have seen some 
bugs being posted and closed (particulary this one: 
http://bugs.digium.com/view.php?id=3866). After a bit of experimenting with 
that code and the fxstest.c code supplied with zaptel I have something that 
actually reverses the polarity of the idle line, waits, sends the digits, 
waits again and reverses polarity back to normal - this results in fully 
working CallerID using my stand-alone CID display and a Gigaset4010 DECT 
phone which unfortunately doesn't understand FSK CLIP/CNIP. I have also 
checked the signal with my scope and it looks just like my landline CLIP 
procedure (and working equally well.. :))
The code is provided at the end of this mail. After browsing the 1.2beta1 
release I also downloaded the latest bleeding edge cvs and verified that 
these parts of the code looked exactly like 1.2beta1.
There are a few questions I have though:
Why do I have to continuously set the ProSLIC register 64 to 6 (active 
reverse transmission) to get the tones onto the line if I'm onhook? Only 
doing it once just after reverse polarity ioctl doesn't do the trick... The 
idea with SETPOLARITY in addition with going OFFHOOK with ZT_HOOK should be 
the same, right? It works if I take the phone offhook though, then I can 
hear the tones even without having to force the register to 6. Next question 
would be if there's a better way to know that the "dialing" is
complete,
especially if this is to be embedded into the chan_zap code, it would be 
nice to have a cleaner solution?
Is this something for the dev list as well, I guess there's some interest in
getting this to work in the stock Asterisk code, even though we're not that 
many people requiring this as it seems..? Should I reopen the bug?
I'm thankful for any input in this matter..
Regards,
Werner
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "zaptel.h"
#include "tonezone.h"
#include "wctdm.h"
static int tones[] = {
        ZT_TONE_DIALTONE,
        ZT_TONE_BUSY,
        ZT_TONE_RINGTONE,
        ZT_TONE_CONGESTION,
        ZT_TONE_DIALRECALL,
};
int main(int argc, char *argv[])
{
        ZT_DIAL_OPERATION dop;
        struct wctdm_regop regop;
        struct zt_dialparams dps;
        int fd,ctlfd,toneduration;
        int res;
        int x;
        if (argc < 3) {
                fprintf(stderr, "Usage: fxstest <zap 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");
                exit(1);
        }
// Code added by wj@xnk.nu to set the default tone length to shorten the 
time it takes to transmit DTMF CLIP
//  25ms is enough for me but according to specs 40 _should_ be understood 
as a valid digit, YMMV.
        ctlfd = open("/dev/zap/ctl", O_RDWR);
        if (ctlfd == -1) {
                fprintf(stderr,"Couldn't open zapctl!\n");
        }
        toneduration = 40;
        if (toneduration > -1) {
                dps.dtmf_tonelen = dps.mfv1_tonelen = toneduration;
                res = ioctl(ctlfd, ZT_SET_DIALPARAMS, &dps);
                if (res < 0) {
                        fprintf(stderr,"Couldn't dialparms!\n");
                }
        }
        close(ctlfd);
// End of code added - wj@xnk.nu
        fd = open(argv[1], O_RDWR);
        if (fd < 0) {
                fprintf(stderr, "Unable to open %s: %s\n", argv[1], 
strerror(errno));
                exit(1);
        }
        if (!strcasecmp(argv[2], "ring")) {
                fprintf(stderr, "Ringing phone...\n");
                x = ZT_RING;
                res = ioctl(fd, ZT_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")) {
// Code modified by wj@xnk.nu to not only reverse polarity but also send an 
example DTMF CLIP
                fprintf(stderr, "Sending DTMF CLIP...\n");
                x = 1;
                res=ioctl(fd, ZT_SETPOLARITY, &x);
                if (res) {
                        fprintf(stderr, "Unable to set reverse 
polarity...\n");
                }
                x = ZT_OFFHOOK;
                res=ioctl(fd, ZT_HOOK, &x);
                if (res) {
                        fprintf(stderr, "Unable to go offhook...\n");
                }
                fprintf(stderr, "Polarity should be reversed
now...\n");
                dop.op = ZT_DIAL_OP_REPLACE;
//              if (ast->cid.cid_num) {
                        snprintf(dop.dialstr, sizeof(dop.dialstr), 
"TwD1234567890CC");
//              } else {
//                      snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), 
"TB00Cw");
//              }
                if (ioctl(fd, ZT_DIAL, &dop)) {
                        x = ZT_ONHOOK;
                        ioctl(fd, ZT_HOOK, &x);
                        fprintf(stderr, "Bad status from DIAL!\n");
                }
                fprintf(stderr, "Waiting for dial completion...\n");
                x=1;
                while(x!=0) {
                        // This sets the line in reverse mode with audio 
transmission!
                        regop.reg=64;
                        regop.val=6;
                        res = ioctl(fd, WCTDM_SET_REG, ®op);
                        ioctl(fd,ZT_DIALING,&x);
                }
                dop.dialstr[0] = '\0';
                // Go back to reverse mode without audio transmission
                regop.reg=64;
                regop.val=5;
                res = ioctl(fd, WCTDM_SET_REG, ®op);
                x = 0;
                res=ioctl(fd, ZT_SETPOLARITY, &x);
                if (res) {
                        fprintf(stderr, "Unable to set normal 
polarity...\n");
                }
                fprintf(stderr, "Polarity should be forward...\n");
                // After this normal ringing can commence
// End of modified polarity example - wj@xnk.nu
        } else if (!strcasecmp(argv[2], "tones")) {
                int x = 0;
                x = ZT_OFFHOOK;
                res = ioctl(fd, ZT_HOOK, &x);
                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;
                                regop.val &= 0xff;
                        } 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
                fprintf(stderr, "Invalid command\n");
        close(fd);
        return 0;
}
Josef Seger
2005-Nov-19  11:31 UTC
[Asterisk-Users] Current status on _outgoing_ Swedish/Dutch DTMF CLIP for TDM400 FXS interfaces?
Hi,
There is a significant number of persons who requires this function (FXS
CallerID for TDM400, Swidish style DTMF tones after polarityreversal and before
the first ringtone).
Is there anyone who has more information about this issus? Mabye there is a
working beta
of this for Asterisk 1.2?
Best Regards
  Josef Seger
-----Original Message-----
From: asterisk-users-bounces@lists.digium.com
[mailto:asterisk-users-bounces@lists.digium.com] On Behalf Of Werner Johansson
Sent: den 3 september 2005 17:05
To: asterisk-users@lists.digium.com
Subject: [Asterisk-Users] Current status on _outgoing_ Swedish/Dutch DTMF CLIP
for TDM400 FXS interfaces?
Hi all,
I have been looking at the code for both the zaptel driver (wctdm.c/wcfxs.c) and
the asterisk channel driver (chan_zap.c) trying to figure out how much of this
that has been implemented. So far I can see that the current stable
1.0.9.1 zaptel driver don't have the SETPOLARITY ioctl that would be
required to properly signal the Swedish/Dutch CLIP, but the 1.2 beta1 has this
support..
Moving forward from that I then look at the 1.2 beta1 chan_zap code, but
nothing's in there could possibly give us any DTMF tones. I have seen some
bugs being posted and closed (particulary this one:
http://bugs.digium.com/view.php?id=3866). After a bit of experimenting with that
code and the fxstest.c code supplied with zaptel I have something that actually
reverses the polarity of the idle line, waits, sends the digits, waits again and
reverses polarity back to normal - this results in fully working CallerID using
my stand-alone CID display and a Gigaset4010 DECT phone which unfortunately
doesn't understand FSK CLIP/CNIP. I have also checked the signal with my
scope and it looks just like my landline CLIP procedure (and working equally
well.. :))
The code is provided at the end of this mail. After browsing the 1.2beta1
release I also downloaded the latest bleeding edge cvs and verified that these
parts of the code looked exactly like 1.2beta1.
There are a few questions I have though:
Why do I have to continuously set the ProSLIC register 64 to 6 (active reverse
transmission) to get the tones onto the line if I'm onhook? Only doing it
once just after reverse polarity ioctl doesn't do the trick... The idea with
SETPOLARITY in addition with going OFFHOOK with ZT_HOOK should be the same,
right? It works if I take the phone offhook though, then I can hear the tones
even without having to force the register to 6. Next question would be if
there's a better way to know that the "dialing" is complete,
especially if this is to be embedded into the chan_zap code, it would be nice to
have a cleaner solution?
Is this something for the dev list as well, I guess there's some interest in
getting this to work in the stock Asterisk code, even though we're not that
many people requiring this as it seems..? Should I reopen the bug?
I'm thankful for any input in this matter..
Regards,
Werner
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "zaptel.h"
#include "tonezone.h"
#include "wctdm.h"
static int tones[] = {
        ZT_TONE_DIALTONE,
        ZT_TONE_BUSY,
        ZT_TONE_RINGTONE,
        ZT_TONE_CONGESTION,
        ZT_TONE_DIALRECALL,
};
int main(int argc, char *argv[])
{
        ZT_DIAL_OPERATION dop;
        struct wctdm_regop regop;
        struct zt_dialparams dps;
        int fd,ctlfd,toneduration;
        int res;
        int x;
        if (argc < 3) {
                fprintf(stderr, "Usage: fxstest <zap 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");
                exit(1);
        }
// Code added by wj@xnk.nu to set the default tone length to shorten the time it
takes to transmit DTMF CLIP //  25ms is enough for me but according to specs 40
_should_ be understood as a valid digit, YMMV.
        ctlfd = open("/dev/zap/ctl", O_RDWR);
        if (ctlfd == -1) {
                fprintf(stderr,"Couldn't open zapctl!\n");
        }
        toneduration = 40;
        if (toneduration > -1) {
                dps.dtmf_tonelen = dps.mfv1_tonelen = toneduration;
                res = ioctl(ctlfd, ZT_SET_DIALPARAMS, &dps);
                if (res < 0) {
                        fprintf(stderr,"Couldn't dialparms!\n");
                }
        }
        close(ctlfd);
// End of code added - wj@xnk.nu
        fd = open(argv[1], O_RDWR);
        if (fd < 0) {
                fprintf(stderr, "Unable to open %s: %s\n", argv[1],
strerror(errno));
                exit(1);
        }
        if (!strcasecmp(argv[2], "ring")) {
                fprintf(stderr, "Ringing phone...\n");
                x = ZT_RING;
                res = ioctl(fd, ZT_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")) { // Code
modified by wj@xnk.nu to not only reverse polarity but also send an example DTMF
CLIP
                fprintf(stderr, "Sending DTMF CLIP...\n");
                x = 1;
                res=ioctl(fd, ZT_SETPOLARITY, &x);
                if (res) {
                        fprintf(stderr, "Unable to set reverse
polarity...\n");
                }
                x = ZT_OFFHOOK;
                res=ioctl(fd, ZT_HOOK, &x);
                if (res) {
                        fprintf(stderr, "Unable to go offhook...\n");
                }
                fprintf(stderr, "Polarity should be reversed
now...\n");
                dop.op = ZT_DIAL_OP_REPLACE;
//              if (ast->cid.cid_num) {
                        snprintf(dop.dialstr, sizeof(dop.dialstr),
"TwD1234567890CC");
//              } else {
//                      snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), 
"TB00Cw");
//              }
                if (ioctl(fd, ZT_DIAL, &dop)) {
                        x = ZT_ONHOOK;
                        ioctl(fd, ZT_HOOK, &x);
                        fprintf(stderr, "Bad status from DIAL!\n");
                }
                fprintf(stderr, "Waiting for dial completion...\n");
                x=1;
                while(x!=0) {
                        // This sets the line in reverse mode with audio
transmission!
                        regop.reg=64;
                        regop.val=6;
                        res = ioctl(fd, WCTDM_SET_REG, ®op);
                        ioctl(fd,ZT_DIALING,&x);
                }
                dop.dialstr[0] = '\0';
                // Go back to reverse mode without audio transmission
                regop.reg=64;
                regop.val=5;
                res = ioctl(fd, WCTDM_SET_REG, ®op);
                x = 0;
                res=ioctl(fd, ZT_SETPOLARITY, &x);
                if (res) {
                        fprintf(stderr, "Unable to set normal
polarity...\n");
                }
                fprintf(stderr, "Polarity should be forward...\n");
                // After this normal ringing can commence // End of modified
polarity example - wj@xnk.nu
        } else if (!strcasecmp(argv[2], "tones")) {
                int x = 0;
                x = ZT_OFFHOOK;
                res = ioctl(fd, ZT_HOOK, &x);
                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;
                                regop.val &= 0xff;
                        } 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
                fprintf(stderr, "Invalid command\n");
        close(fd);
        return 0;
}
_______________________________________________
--Bandwidth and Colocation sponsored by Easynews.com --
Asterisk-Users mailing list
Asterisk-Users@lists.digium.com
http://lists.digium.com/mailman/listinfo/asterisk-users
To UNSUBSCRIBE or update options visit:
   http://lists.digium.com/mailman/listinfo/asterisk-users
Maybe Matching Threads
- [AMDGPU] AMDGPUAsmParser fails to parse several instructions
- [LLVMdev] Expected behavior of eliminateFrameIndex() on dbg_value machine instructions
- [LLVMdev] Expected behavior of eliminateFrameIndex() on dbg_value machine instructions
- [LLVMdev] Expected behavior of eliminateFrameIndex() on dbg_value machine instructions
- Remus blktap2 issue