summaryrefslogtreecommitdiff
path: root/zaptel.c
diff options
context:
space:
mode:
Diffstat (limited to 'zaptel.c')
-rwxr-xr-xzaptel.c162
1 files changed, 157 insertions, 5 deletions
diff --git a/zaptel.c b/zaptel.c
index 1fdfa62..e8ba8d1 100755
--- a/zaptel.c
+++ b/zaptel.c
@@ -299,7 +299,7 @@ static rwlock_t chan_lock = RW_LOCK_UNLOCKED;
static struct zt_zone *tone_zones[ZT_TONE_ZONE_MAX];
-#define NUM_SIGS 8
+#define NUM_SIGS 9
static inline void rotate_sums(void)
@@ -326,7 +326,8 @@ static unsigned int in_sig[NUM_SIGS][2] = {
{ ZT_SIG_FXSKS,ZT_BBIT | ZT_BBIT | ((ZT_ABIT | ZT_BBIT) << 8)},
{ ZT_SIG_FXOLS,0 | (ZT_ABIT << 8)},
{ ZT_SIG_FXOGS,ZT_BBIT | ((ZT_ABIT | ZT_BBIT) << 8)},
- { ZT_SIG_FXOKS,0 | (ZT_ABIT << 8)}
+ { ZT_SIG_FXOKS,0 | (ZT_ABIT << 8)},
+ { ZT_SIG_SF, 0}
} ;
/* must have span to begin with */
@@ -376,6 +377,8 @@ static char *sigstr(int sig)
return "Slave";
case ZT_SIG_CAS:
return "CAS";
+ case ZT_SIG_SF:
+ return "SF (ToneOnly)";
case ZT_SIG_NONE:
default:
return "Unconfigured";
@@ -1556,6 +1559,21 @@ static int zt_chan_release(struct inode *inode, struct file *file)
return 0;
}
+static void set_txtone(struct zt_chan *ss,int fac, int init_v2, int init_v3)
+{
+ if (fac == 0)
+ {
+ ss->v2_1 = 0;
+ ss->v3_1 = 0;
+ return;
+ }
+ ss->txtone = fac;
+ ss->v1_1 = 0;
+ ss->v2_1 = init_v2;
+ ss->v3_1 = init_v3;
+ return;
+}
+
static void zt_rbs_sethook(struct zt_chan *chan, int txsig, int txstate, int timeout)
{
static int outs[NUM_SIGS][5] = {
@@ -1577,7 +1595,11 @@ who cares what the sig bits are as long as they are stable */
{ ZT_SIG_FXOGS, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT,
ZT_BBIT | ZT_DBIT, 0, 0 }, /* FXO Groundstart */
{ ZT_SIG_FXOKS, ZT_BBIT | ZT_DBIT, ZT_BBIT | ZT_DBIT, 0,
- ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT } /* FXO Kewlstart */
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT }, /* FXO Kewlstart */
+ { ZT_SIG_SF, ZT_BBIT | ZT_CBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT,
+ ZT_BBIT | ZT_CBIT | ZT_DBIT }, /* no signalling */
} ;
int x;
@@ -1598,6 +1620,25 @@ who cares what the sig bits are as long as they are stable */
}
chan->txstate = txstate;
+ /* if tone signalling */
+ if (chan->sig == ZT_SIG_SF)
+ {
+ chan->txhooksig = txsig;
+ if (chan->txtone) /* if set to make tone for tx */
+ {
+ if ((txsig && !(chan->toneflags & ZT_REVERSE_TXTONE)) ||
+ ((!txsig) && (chan->toneflags & ZT_REVERSE_TXTONE)))
+ {
+ set_txtone(chan,chan->txtone,chan->tx_v2,chan->tx_v3);
+ }
+ else
+ {
+ set_txtone(chan,0,0,0);
+ }
+ }
+ chan->otimer = timeout * 8; /* Otimer is timer in samples */
+ return;
+ }
if (chan->span->hooksig) {
chan->txhooksig = txsig;
chan->span->hooksig(chan, txsig);
@@ -2488,6 +2529,7 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
int i,j;
struct zt_lineconfig lc;
struct zt_chanconfig ch;
+ struct zt_sfconfig sf;
int sigcap;
int res = 0;
int x,y;
@@ -2664,6 +2706,33 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
#endif
spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
return res;
+ case ZT_SFCONFIG:
+ if (copy_from_user(&sf, (struct zt_chanconfig *)data, sizeof(sf)))
+ return -EFAULT;
+ VALID_CHANNEL(sf.chan);
+ if (chans[sf.chan]->sig != ZT_SIG_SF) return -EINVAL;
+ spin_lock_irqsave(&chans[sf.chan]->lock, flags);
+ chans[sf.chan]->rxp1 = sf.rxp1;
+ chans[sf.chan]->rxp2 = sf.rxp2;
+ chans[sf.chan]->rxp3 = sf.rxp3;
+ chans[sf.chan]->txtone = sf.txtone;
+ chans[sf.chan]->tx_v2 = sf.tx_v2;
+ chans[sf.chan]->tx_v3 = sf.tx_v3;
+ chans[sf.chan]->toneflags = sf.toneflag;
+ if (sf.txtone) /* if set to make tone for tx */
+ {
+ if ((chans[sf.chan]->txhooksig && !(sf.toneflag & ZT_REVERSE_TXTONE)) ||
+ ((!chans[sf.chan]->txhooksig) && (sf.toneflag & ZT_REVERSE_TXTONE)))
+ {
+ set_txtone(chans[sf.chan],sf.txtone,sf.tx_v2,sf.tx_v3);
+ }
+ else
+ {
+ set_txtone(chans[sf.chan],0,0,0);
+ }
+ }
+ spin_unlock_irqrestore(&chans[sf.chan]->lock, flags);
+ return res;
case ZT_DEFAULTZONE:
if (get_user(j,(int *)data))
return -EFAULT; /* get conf # */
@@ -3963,6 +4032,15 @@ static inline void zt_process_getaudio_chunk(struct zt_chan *ss, unsigned char *
memcpy(ms->getlin_lastchunk, ms->getlin, ZT_CHUNKSIZE * sizeof(short));
/* save value from current */
memcpy(ms->getlin, getlin, ZT_CHUNKSIZE * sizeof(short));
+ /* if to make tx tone */
+ if (ms->v1_1 || ms->v2_1 || ms->v3_1)
+ {
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ {
+ getlin[x] += zt_txtone_nextsample(ms);
+ txb[x] = ZT_LIN2X(getlin[x], ms);
+ }
+ }
/* This is what to send (after having applied gain) */
for (x=0;x<ZT_CHUNKSIZE;x++)
txb[x] = ms->txgain[txb[x]];
@@ -4434,13 +4512,62 @@ void zt_ec_chunk(struct zt_chan *ss, unsigned char *rxchunk, const unsigned char
spin_unlock_irqrestore(&ss->lock, flags);
}
+/* return 0 if nothing detected, 1 if lack of tone, 2 if presence of tone */
+/* modifies buffer pointed to by 'amp' with notched-out values */
+static inline int sf_detect (sf_detect_state_t *s,
+ short *amp,
+ int samples,long p1, long p2, long p3)
+{
+int i,rv = 0;
+long x,y;
+
+#define SF_DETECT_SAMPLES (ZT_CHUNKSIZE * 5)
+#define SF_DETECT_MIN_ENERGY 500
+#define NB 14 /* number of bits to shift left */
+
+ /* determine energy level before filtering */
+ for(i = 0; i < samples; i++)
+ {
+ if (amp[i] < 0) s->e1 -= amp[i];
+ else s->e1 += amp[i];
+ }
+ /* do 2nd order IIR notch filter at given freq. and calculate
+ energy */
+ for(i = 0; i < samples; i++)
+ {
+ x = amp[i] << NB;
+ y = s->x2 + (p1 * (s->x1 >> NB)) + x;
+ y += (p2 * (s->y2 >> NB)) +
+ (p3 * (s->y1 >> NB));
+ s->x2 = s->x1;
+ s->x1 = x;
+ s->y2 = s->y1;
+ s->y1 = y;
+ amp[i] = y >> NB;
+ if (amp[i] < 0) s->e2 -= amp[i];
+ else s->e2 += amp[i];
+ }
+ s->samps += i;
+ /* if time to do determination */
+ if ((s->samps) >= SF_DETECT_SAMPLES)
+ {
+ rv = 1; /* default to no tone */
+ /* if enough energy, it is determined to be a tone */
+ if (((s->e1 - s->e2) / s->samps) > SF_DETECT_MIN_ENERGY) rv = 2;
+ /* reset energy processing variables */
+ s->samps = 0;
+ s->e1 = s->e2 = 0;
+ }
+ return(rv);
+}
+
static inline void zt_process_putaudio_chunk(struct zt_chan *ss, unsigned char *rxb)
{
/* We transmit data from our master channel */
struct zt_chan *ms = ss->master;
/* Linear version of received data */
short putlin[ZT_CHUNKSIZE],k[ZT_CHUNKSIZE];
- int x;
+ int x,r;
if (ms->dialing) ms->afterdialingtimer = 50;
else if (ms->afterdialingtimer) ms->afterdialingtimer--;
@@ -4465,7 +4592,32 @@ static inline void zt_process_putaudio_chunk(struct zt_chan *ss, unsigned char *
}
}
}
-
+ /* if doing rx tone decoding */
+ if (ms->rxp1 && ms->rxp2 && ms->rxp3)
+ {
+ r = sf_detect(&ms->rd,putlin,ZT_CHUNKSIZE,ms->rxp1,
+ ms->rxp2,ms->rxp3);
+ /* Convert back */
+ for(x=0;x<ZT_CHUNKSIZE;x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
+ if (r) /* if something happened */
+ {
+ if (r != ms->rd.lastdetect)
+ {
+ if (((r == 2) && !(ms->toneflags & ZT_REVERSE_RXTONE)) ||
+ ((r == 1) && (ms->toneflags & ZT_REVERSE_RXTONE)))
+ {
+ qevent(ms,ZT_EVENT_RINGOFFHOOK);
+ }
+ else
+ {
+ qevent(ms,ZT_EVENT_ONHOOK);
+ }
+ ms->rd.lastdetect = r;
+ }
+ }
+ }
+
if (!(ms->flags & ZT_FLAG_PSEUDO)) {
memcpy(ms->putlin, putlin, ZT_CHUNKSIZE * sizeof(short));
}