diff options
Diffstat (limited to 'zaptel.c')
-rwxr-xr-x | zaptel.c | 162 |
1 files changed, 157 insertions, 5 deletions
@@ -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)); } |