UK CallerId on X100P SE

Introduction


I wanted to utilise an X100P SE to integrate my UK land line with my PBX. The purpose of this article is to document the configuration changes made and discuss the detection of caller id using this card.

Hardware


Authentic X100P SE 'Wildcard' purchased Sep 09

Software


dahdi-linux-2.2.0.2
dahdi-tools-2.2.0

asterisk-1.4.26.2
asterisk-addons-1.4.9

freepbx-2.5.2

I have updated the fixes below to include Dahdi 2.6.1+2.6.1 and Asterisk 11.2.1

Configuration


The correct modules were automatically loaded and the appropriate timing source automatically selected via the dahdi init script. The wcfxo module handles the si3034 chipset utilised by the X100P SE, it also handles other similar chipsets and cards.

/etc/dahdi/genconf_parameters

lc_country              uk
context_lines           from-zaptel
freepbx                 yes

optionally you may want to uncomment the following line to use the oslec echo canceller

echo_can                oslec

Generate config files

dahdi_genconf system chandahdi=verbose


This should create /etc/dahdi/system.conf and /etc/asterisk/dahdi-channels.cons

/etc/dahdi/system.conf

# Autogenerated by /usr/sbin/dahdi_genconf on Wed Sep 23 20:58:21 2009
# If you edit this file and execute /usr/sbin/dahdi_genconf again,
# your manual changes will be LOST.
# Dahdi Configuration File
#
# This file is parsed by the Dahdi Configurator, dahdi_cfg
#
# Span 1: WCFXO/0 "Wildcard X100P Board 1" (MASTER)
fxsks=1
echocanceller=mg2,1

# Global data

loadzone        = uk
defaultzone     = uk


/etc/asterisk/dahdi-channels.conf

; Autogenerated by /usr/sbin/dahdi_genconf on Wed Sep 23 20:58:21 2009
; If you edit this file and execute /usr/sbin/dahdi_genconf again,
; your manual changes will be LOST.
; Dahdi Channels Configurations (chan_dahdi.conf)
;
; This is not intended to be a complete chan_dahdi.conf. Rather, it is intended
; to be #include-d by /etc/chan_dahdi.conf that will include the global settings
;

; Span 1: WCFXO/0 "Wildcard X100P Board 1" (MASTER)
;;; line="1 WCFXO/0/0 FXSKS  (SWEC: MG2)"
signalling=fxs_ks
callerid=asreceived
group=0
context=from-zaptel
channel => 1
callerid=
group=
context=default

/etc/asterisk/chan_dahdi.conf

;# Flash Operator Panel will parse this file for dahdi trunk buttons
;# AMPLABEL will be used for the display labels on the buttons

;# %c Dahdi Channel number
;# %n Line number
;# %N Line number, but restart counter
;# Example:
;# ;AMPLABEL:Channel %c - Button %n

;# For Dahdi/* buttons use the following
;# (where x=number of buttons to dislpay)
;# ;AMPWILDCARDLABEL(x):MyLabel


[channels]
language=en
usecallerid=yes
cidsignalling=v23
cidstart=polarity  <-- If you are using the "usehist" patch mentioned below this needs to read cidstart=usehist
faxdetect=no
echotraining=yes

#include dahdi-channels.conf
; include dahdi extensions defined in FreePBX
#include chan_dahdi_additional.conf


Note #include dahdi-channels.conf has to be added to pull in the config file generated by dahdi_genconf,
The cidstart setting is specific to my configuration and is not the correct one for the history buffer patch.


/etc/modprobe.d/dahdi

I have applied the patch for TBR21 (complex impedance for UK and others) and set opermode=2 to utilise this.

options wcfxo opermode=2

or
options wcfxo opermode=2 debug=1

for debug

/etc/amportal.conf

changed
# ZAP2DAHDICOMPAT=true|false

to
ZAP2DAHDICOMPAT=true

to enable 'Zap Channel DIDs' to work properly

Discussion


I consider CID to be an important feature and was keen to get this working with my configuration. Initially I decided to investigate the possibility of adding polarity detection to the wcfxo module as the spec sheet for the si3034 suggested that this should be possible. After some testing I found that 2 different methods for polarity detection seem to work.


Polarity detection via SDO


As a first pass I attempted to use the data from the SDO as this was already being used to detect the ring signal. I surmised it may also be possible to detect the polarity change as a pulse akin to details in the spec which state that data received from the SDO should vary in cadence with the ring pins which can be utilised to detect the caller id polarity change. This actually got a partially working system very quickly, I later discovered that the On-Hook Line Monitor (ONHM) was interfering with this approach and turning it off makes it work reliably. Battery detection needs to be disabled to make this work and the ONHM needs to be switched on again when trying to read the caller id signal and turned off afterwards. See below for more details on the ONHM. I'm not sure if the Ring Detector Full Wave Rectifier needs to be on using this method, but it was on during my testing. The detection was working with it switched off, but the ONHM was on so I'm not sure about the results which showed some failures.


Polarity detection via Ring Pins (RDTP and RDTN)


The second method utilises the ring pins and the Ring Detector Full Wave Rectifier this method is described in the specification as the suggested approach and details only enabling the ONHM for caller id detection. I completed this as per specification with the required back off and squelch functions.

Gotcha's


In either of the 2 above scenarios there are times when a false detection will occur. For example the channel going on hook i.e. the OH (Off Hook) pin being cleared after a call has been made/accepted. The problem here is that due to the way the CID detection routine in asterisk works it will mark the channel unavailable till the CID detection is ended either via timeout or by ring. This can lead to issues such as being unable to make a call till the CID detection has timed out. The channel will also not accept another polarity reversal if it is still ringing. This can occur when a caller has hung up before the call was answered and someone else rings back before the previous call fully times out on that channel. The new call will eventually be accepted as the ring state continually toggles on and off as the ring signal is pulsed, however the CID will be blocked as there is currently no way to send the data again.

History buffer patch


I personally think this is the best approach as it need only be fired when a ring has definitely been detected and can prevent the above issues. Further more it is not incompatible with polarity detection and could be toggled on and off using a module parameter. As described in the BT SIN, polarity reversal is an event designed to trip the caller id detection circuit, it is not there as a definitive marker of either an incoming call or caller id data and can easily be caused by other reasons. As such this event is currently being treated incorrectly and a better approach is either to use the history buffer (which it seems was already rejected) or to allow detection within the module in some way.

I know this patch was originally released for use with zaptel and asterisk 1.4, but when I looked for the asterisk 1.6 and dahdi versions I could not find them. They have been mentioned as being posted on websites etc or available from asterisk.org but I searched high and low to no avail.

I have re-worked the patches to work against asterisk-1.6.1.10 and dahdi-linux-2.2.0.2 drivers. I can't find any mention of them being restricted from publication so here they are. Modified from the version zaptel-142 and asterisk 141 by Tony. from lusyn.com. I would send copies to the website, but I can't find an email address for Marc.

asterisk-1.6.1.10-x100p-uk-callerid-usehist.patch


--- asterisk-1.6.1.10/channels/chan_dahdi.c	2009-11-03 18:11:08.000000000 +0000

+++ asterisk-1.6.1.10.modified/channels/chan_dahdi.c	2009-11-26 09:02:03.000000000 +0000

@@ -1517,6 +1517,15 @@

	return 0;

}


+/* coop 1 */

+static int dahdi_get_history(int fd, void *buf, int buf_size)

+{

+	struct dahdi_history hist;

+	hist.buf=buf;

+	hist.len=buf_size;

+	return ioctl(fd, DAHDI_GET_HISTORY, &hist);

+}

+/* coop 1 end */


static int alloc_sub(struct dahdi_pvt *p, int x)

{

@@ -6546,6 +6555,7 @@

			on? "enabled" : "disabled");

}


+/* coop temp */

static void *ss_thread(void *data)


{

	struct ast_channel *chan = data;

@@ -7226,6 +7236,132 @@

		if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {

	    		number = smdi_msg->calling_st;



+

+

+

+

+

+/* coop 2 */

+	/* Check to see if caller ID needs to be extracted from

+	* the history buffer */

+	} else if (p->use_callerid && p->cid_start == CID_START_USEHIST) {

+		ast_log(LOG_DEBUG,"Using history buffer to extract caller ID\n");

+		cs = callerid_new(p->cid_signalling);

+		if (cs) {

+			unsigned char cidbuf[32768];

+			res=0;

+

+			res = dahdi_get_history(p->subs[idx].dfd,cidbuf,sizeof(cidbuf));

+			if(res<0) {

+				ast_log(LOG_ERROR,"dahdi_get_history failed: %s\n", strerror(errno));

+			} else {

+				res=callerid_feed(cs,cidbuf,sizeof(cidbuf),AST_LAW(p));

+				if (res < 0) {

+				ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));

+					}

+				}

+

+				if(res==1) {

+				callerid_get(cs, &name, &number, &flags);

+				if (option_debug) 

+				ast_log(LOG_DEBUG, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);

+				}

+			}

+			if (p->usedistinctiveringdetection == 1) {

+#if 1

+			bump_gains(p);

+#endif				

+				len = 0;

+				distMatches = 0;

+				/* Clear the current ring data array so we dont have old data in it. */

+				for (receivedRingT=0; receivedRingT < 3; receivedRingT++) {

+					curRingData[receivedRingT] = 0;

+				}

+				receivedRingT = 0;

+				counter = 0;

+				counter1 = 0;

+				/* Check to see if context is what it should be, if not set to be. */

+				if (strcmp(p->context,p->defcontext) != 0) {

+					strncpy(p->context, p->defcontext, sizeof(p->context)-1);

+					strncpy(chan->context,p->defcontext,sizeof(chan->context)-1);

+				}

+

+				for(;;) {	

+					i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;

+					if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i)))	{

+						ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));

+						callerid_free(cs);

+						ast_hangup(chan);

+						return NULL;

+					}

+					if (i & DAHDI_IOMUX_SIGEVENT) {

+					res = dahdi_get_event(p->subs[idx].dfd);

+					ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));

+					res = 0;

+					/* Let us detect distinctive ring */

+

+						curRingData[receivedRingT] = p->ringt;

+

+						if (p->ringt < ringt_base/2)

+							break;

+					++receivedRingT; /* Increment the ringT counter so we can match it against

+							values in zapata.conf for distinctive ring */

+					} else if (i & DAHDI_IOMUX_READ) {

+						res = read(p->subs[idx].dfd, buf, sizeof(buf));

+						if (res < 0) {

+							if (errno != ELAST) {

+							ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));

+								callerid_free(cs);

+								ast_hangup(chan);

+								return NULL;

+							}

+							break;

+						}

+						if (p->ringt) 

+							p->ringt--;

+						if (p->ringt == 1) {

+							res = -1;

+							break;

+						}

+					}

+				}

+				if(option_verbose > 2) 

+				/* this only shows up if you have n of the dring patterns filled in */

+				ast_verbose( VERBOSE_PREFIX_3 "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);

+

+				for (counter=0; counter < 3; counter++) {

+				/* Check to see if the rings we received match any of the ones in zapata.conf for this channel */

+				distMatches = 0;

+				for (counter1=0; counter1 < 3; counter1++) {

+					if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1]+10) && curRingData[counter1] >=

+					(p->drings.ringnum[counter].ring[counter1]-10)) {

+						distMatches++;

+					}

+				}

+				if (distMatches == 3) {

+					/* The ring matches, set the context to whatever is for distinctive ring.. */

+					strncpy(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context)-1);

+					strncpy(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context)-1);

+					if(option_verbose > 2) 

+					ast_verbose( VERBOSE_PREFIX_3  "Distinctive Ring matched context %s\n",p->context);

+					break;

+				}

+			}

+		}

+		/* Restore linear mode (if appropriate) for Caller*ID processing */

+		dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);

+#if 1

+			restore_gains(p);

+#endif

+

+/* coop 2 end */

+

+

+

+

+

+

+

		/* If we want caller id, we're in a prering state due to a polarity reversal

		* and we're set to use a polarity reversal to trigger the start of caller id,

		* grab the caller id and wait for ringing to start... */

@@ -14356,6 +14492,10 @@

				confp->chan.cid_start = CID_START_POLARITY_IN;

			else if (!strcasecmp(v->value, "polarity"))

				confp->chan.cid_start = CID_START_POLARITY;

+/* coop 3 */

+			else if (!strcasecmp(v->value, "usehist"))

+				confp->chan.cid_start = CID_START_USEHIST;

+/* coop 3 end */

			else if (ast_true(v->value))

				confp->chan.cid_start = CID_START_RING;

		} else if (!strcasecmp(v->name, "threewaycalling")) {

 --- asterisk-1.6.1.10/include/asterisk/callerid.h	2009-03-09 21:22:42.000000000 +0000

+++ asterisk-1.6.1.10.modified/include/asterisk/callerid.h	2009-11-26 09:12:59.000000000 +0000

@@ -63,6 +63,9 @@

#define CID_START_RING	1

#define CID_START_POLARITY 2

#define CID_START_POLARITY_IN 3

+/* coop 1 */

+#define CID_START_USEHIST 4

+/* coop 1 end */



/* defines dealing with message waiting indication generation */

/*! MWI SDMF format */



This version fixes formatting issues above and updates for Asterisk 1.6.2.11

The text below should now be acceptable to "patch -p0"

Index: channels/chan_dahdi.c
===================================================================
--- channels/chan_dahdi.c       (revision 281981)
+++ channels/chan_dahdi.c       (working copy)
@@ -2173,6 +2173,15 @@
        return 0;
 }

+/* coop 1 */
+static int dahdi_get_history(int fd, void *buf, int buf_size)
+{
+       struct dahdi_history hist;
+       hist.buf=buf;
+       hist.len=buf_size;
+       return ioctl(fd, DAHDI_GET_HISTORY, &hist);
+}
+/* coop 1 end */

 static int alloc_sub(struct dahdi_pvt *p, int x)
 {
@@ -8444,6 +8453,121 @@
                if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {
                        number = smdi_msg->calling_st;

+/* coop 2 */
+       /* Check to see if caller ID needs to be extracted from
+       * the history buffer */
+       } else if (p->use_callerid && p->cid_start == CID_START_USEHIST) {
+        ast_log(LOG_DEBUG,"Using history buffer to extract caller ID\n");
+        cs = callerid_new(p->cid_signalling);
+        if (cs) {
+        unsigned char cidbuf[32768];
+        res=0;
+
+        res = dahdi_get_history(p->subs[idx].dfd,cidbuf,sizeof(cidbuf));
+        if(res<0) {
+        ast_log(LOG_ERROR,"dahdi_get_history failed: %s\n", strerror(errno));
+        } else {
+        res=callerid_feed(cs,cidbuf,sizeof(cidbuf),AST_LAW(p));
+        if (res < 0) {
+        ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
+        }
+        }
+
+        if(res==1) {
+        callerid_get(cs, &name, &number, &flags);
+        if (option_debug)
+        ast_log(LOG_DEBUG, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
+        }
+        }
+        if (p->usedistinctiveringdetection == 1) {
+#if 1
+        bump_gains(p);
+#endif
+        len = 0;
+        distMatches = 0;
+        /* Clear the current ring data array so we dont have old data in it. */
+        for (receivedRingT=0; receivedRingT < 3; receivedRingT++) {
+        curRingData[receivedRingT] = 0;
+        }
+        receivedRingT = 0;
+        counter = 0;
+        counter1 = 0;
+        /* Check to see if context is what it should be, if not set to be. */
+        if (strcmp(p->context,p->defcontext) != 0) {
+        strncpy(p->context, p->defcontext, sizeof(p->context)-1);
+        strncpy(chan->context,p->defcontext,sizeof(chan->context)-1);
+        }
+
+        for(;;) {
+        i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
+        if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i)))  {
+        ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
+        callerid_free(cs);
+        ast_hangup(chan);
+        return NULL;
+        }
+        if (i & DAHDI_IOMUX_SIGEVENT) {
+        res = dahdi_get_event(p->subs[idx].dfd);
+        ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
+        res = 0;
+        /* Let us detect distinctive ring */
+
+        curRingData[receivedRingT] = p->ringt;
+
+        if (p->ringt < ringt_base/2)
+        break;
+        ++receivedRingT; /* Increment the ringT counter so we can match it against
+        values in zapata.conf for distinctive ring */
+        } else if (i & DAHDI_IOMUX_READ) {
+        res = read(p->subs[idx].dfd, buf, sizeof(buf));
+        if (res < 0) {
+        if (errno != ELAST) {
+        ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
+        callerid_free(cs);
+        ast_hangup(chan);
+        return NULL;
+        }
+        break;
+        }
+        if (p->ringt)
+        p->ringt--;
+        if (p->ringt == 1) {
+        res = -1;
+        break;
+        }
+        }
+        }
+        if(option_verbose > 2)
+        /* this only shows up if you have n of the dring patterns filled in */
+        ast_verbose( VERBOSE_PREFIX_3 "Detected ring pattern: NaVd,%d %d %d\n",curRingData[0],curRingData[1],curRingData[2]);
+
+        for (counter=0; counter < 3; counter++) {
+        /* Check to see if the rings we received match any of the ones in zapata.conf for this channel */
+        distMatches = 0;
+        for (counter1=0; counter1 < 3; counter1++) {
+        if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1]+10) && curRingData[counter1] >=
+        (p->drings.ringnum[counter].ring[counter1]-10)) {
+        distMatches++;
+        }
+        }
+        if (distMatches == 3) {
+        /* The ring matches, set the context to whatever is for distinctive ring.. */
+        strncpy(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context)-1);
+        strncpy(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context)-1);
+        if(option_verbose > 2)
+        ast_verbose( VERBOSE_PREFIX_3  "Distinctive Ring matched context %s\n",p->context);
+        break;
+        }
+        }
+        }
+        /* Restore linear mode (if appropriate) for Caller*ID processing */
+        dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
+#if 1
+        restore_gains(p);
+#endif
+
+/* coop 2 end */
+
                /* If we want caller id, we're in a prering state due to a polarity reversal
                 * and we're set to use a polarity reversal to trigger the start of caller id,
                 * grab the caller id and wait for ringing to start... */
@@ -16297,6 +16421,10 @@
                                confp->chan.cid_start = CID_START_POLARITY_IN;
                        else if (!strcasecmp(v->value, "polarity"))
                                confp->chan.cid_start = CID_START_POLARITY;
+/* coop 3 */
+        else if (!strcasecmp(v->value, "usehist"))
+        confp->chan.cid_start = CID_START_USEHIST;
+/* coop 3 end */
                        else if (ast_true(v->value))
                                confp->chan.cid_start = CID_START_RING;
                } else if (!strcasecmp(v->name, "threewaycalling")) {
Index: include/asterisk/callerid.h
===================================================================
--- include/asterisk/callerid.h (revision 281981)
+++ include/asterisk/callerid.h (working copy)
@@ -63,6 +63,7 @@
 #define CID_START_RING 1
 #define CID_START_POLARITY 2
 #define CID_START_POLARITY_IN 3
+#define CID_START_USEHIST 4

 /* defines dealing with message waiting indication generation */
 /*! MWI SDMF format */





dahdi-linux-2.2.0.2-x100p-uk-callerid-usehist.patch






+++ dahdi-linux-2.2.0.2.modified/drivers/dahdi/dahdi-base.c 2009-11-25 15:37:18.000000000 +0000
@@ -903,6 +903,22 @@

unsigned char *newbuf, *oldbuf;

unsigned long flags;

int x;

+/* coop 1 */
+
+       /* Allocate history buffer, or not.  This probably shouldn't
+        * be here, but it's convenient */
+       if(!j)
+       {
+          if(ss->history) kfree(ss->history);
+          ss->history = NULL;
+       }
+       else
+       {
+         if(!ss->history) ss->history=kmalloc(DAHDI_HISTORY_BUF_LEN, GFP_KERNEL);
+       }
+       ss->historypos=0;
+
+/* coop 1 end */


/* Check numbufs */

if (numbufs < 2)

@@ -4345,6 +4361,10 @@

unsigned long flags;

int i, j, k, rv;

int ret, c;

+/* coop 2 */
+        int k1, k2;
+        struct dahdi_history hist;
+/* coop 2 end */


if (!chan)

return -EINVAL;

@@ -4818,6 +4838,31 @@

}

}

break;

+/* coop 3 */
+ case DAHDI_GET_HISTORY:
+ if (copy_from_user(&hist,(struct dahdi_history *) data,sizeof(hist)))
+ return -EIO;
+
+ if (!(chan->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
+ if (!chan->history) return -EINVAL;
+ j=hist.len;
+ k1=DAHDI_HISTORY_BUF_LEN-chan->historypos;
+ k2=chan->historypos;
+ if(j>0 && k1>0)
+ {
+ if (copy_to_user(hist.buf,chan->history+chan->historypos,min(j,k1)))
+ return -EIO;
+ j-=min(j,k1);
+ }
+ if(j>0 && k2>0)
+ {
+ if (copy_to_user(hist.buf+k1,chan->history,min(j,k2)))
+ return -EIO;
+ j-=min(j,k2);
+ }
+ /* Probably should assert j==0 here */
+ break;
+/* coop 3 end */
default:

/* Check for common ioctl's and private ones */

rv = dahdi_common_ioctl(inode, file, cmd, data, unit);

@@ -6827,6 +6872,16 @@

memcpy(ms->putlin, putlin, DAHDI_CHUNKSIZE * sizeof(short));

memcpy(ms->putraw, rxb, DAHDI_CHUNKSIZE);

}

+/* coop 4 */
+ /* Store in the history buffer */
+ if(ms->history)
+ {
+ memcpy(ms->history+ms->historypos,rxb,DAHDI_CHUNKSIZE);
+ ms->historypos+=DAHDI_CHUNKSIZE;
+ if(ms->historypos >= DAHDI_HISTORY_BUF_LEN)
+ ms->historypos=0;
+ }
+/* coop 4 end */


/* Take the rxc, twiddle it for conferencing if appropriate and put it

  back */



+++ dahdi-linux-2.2.0.2.modified/include/dahdi/kernel.h 2009-11-25 15:26:35.000000000 +0000
@@ -448,6 +448,10 @@

wait_queue_head_t writebufq; /*!< write wait queue */



int blocksize; /*!< Block size */

+/* coop 1 moved here from user.h */
+        u_char          *history;       /* History buffer, for pre-ring caller ID (DAHDI_HISTORY_BUF_LEN) */
+        u_short         historypos;     /* Current position within buffer */
+/* coop 1 end */


int eventinidx;  /*!< out index in event buf (circular) */

int eventoutidx;  /*!< in index in event buf (circular) */



+++ dahdi-linux-2.2.0.2.modified/include/dahdi/user.h 2009-11-25 15:31:43.000000000 +0000
@@ -114,6 +114,10 @@

  1. define DAHDI_MAX_NUM_BUFS 32

  1. define DAHDI_MAX_BUF_SPACE 32768



+/* coop 1 */
+#define DAHDI_HISTORY_BUF_LEN       16384 /* Count of ulaw samples */
+/* coop 1 end */
+
  1. define DAHDI_DEFAULT_BLOCKSIZE 1024

  1. define DAHDI_DEFAULT_MTR_MRU 2048



@@ -946,6 +950,22 @@

 *  60-80 are reserved for private drivers

 *  80-85 are reserved for dynamic span stuff

 */

+/* coop 3 now moved here to keep inline with numbers above */
+ /*
+ * Return history buffer
+ */
+#define DAHDI_GET_HISTORY _IOR(DAHDI_CODE, 66, struct dahdi_history)
+
+/* coop 3 end */
+
+/* coop 2 */
+
+typedef struct dahdi_history
+{
+ unsigned char   *buf;           /* Sample buffer */
+ int len;                /* Length of buffer, in bytes */
+} DAHDI_HISTORY;
+/* coop 2 end */


/*

 * Create a dynamic span



This version fixes formatting issues above and updates for Dahdi version 2.3.0.1+2.3.0

The text below should now be acceptable to "patch -p0"

Index: include/dahdi/user.h
===================================================================
--- include/dahdi/user.h        (revision 9129)
+++ include/dahdi/user.h        (working copy)
@@ -116,7 +116,10 @@
 #define DAHDI_DEFAULT_NUM_BUFS 2
 #define DAHDI_MAX_NUM_BUFS     32
 #define DAHDI_MAX_BUF_SPACE    32768
-
+/* coop 1 */
+#define DAHDI_HISTORY_BUF_LEN       16384 /* Count of ulaw samples */
+/* coop 1 end */
+
 #define DAHDI_DEFAULT_BLOCKSIZE 1024
 #define DAHDI_DEFAULT_MTR_MRU  2048

@@ -994,7 +997,22 @@
  *  60-80 are reserved for private drivers
  *  80-85 are reserved for dynamic span stuff
  */
-
+/* coop 3 now moved here to keep inline with numbers above */
+ /*
+ * Return history buffer
+ */
+#define DAHDI_GET_HISTORY _IOR(DAHDI_CODE, 66, struct dahdi_history)
+
+/* coop 3 end */
+
+/* coop 2 */
+
+typedef struct dahdi_history
+{
+       unsigned char   *buf;           /* Sample buffer */
+       int len;                /* Length of buffer, in bytes */
+} DAHDI_HISTORY;
+/* coop 2 end */
 /*
  * Create a dynamic span
  */
Index: include/dahdi/kernel.h
===================================================================
--- include/dahdi/kernel.h      (revision 9129)
+++ include/dahdi/kernel.h      (working copy)
@@ -454,6 +454,10 @@
        wait_queue_head_t writebufq; /*!< write wait queue */

        int             blocksize;      /*!< Block size */
+/* coop 1 moved here from user.h */
+        u_char          *history;       /* History buffer, for pre-ring caller ID (DAHDI_HISTORY_BUF_LEN) */
+        u_short         historypos;     /* Current position within buffer */
+/* coop 1 end */

        int             eventinidx;  /*!< out index in event buf (circular) */
        int             eventoutidx;  /*!< in index in event buf (circular) */
Index: drivers/dahdi/dahdi-base.c
===================================================================
--- drivers/dahdi/dahdi-base.c  (revision 9129)
+++ drivers/dahdi/dahdi-base.c  (working copy)
@@ -958,7 +958,22 @@
        unsigned char *oldrxbuf = NULL;
        unsigned long flags;
        int x;
-
+/* coop 1 */
+
+       /* Allocate history buffer, or not.  This probably shouldn't
+        * be here, but it's convenient */
+       if(!blocksize)
+       {
+          if(ss->history) kfree(ss->history);
+          ss->history = NULL;
+       }
+       else
+       {
+         if(!ss->history) ss->history=kmalloc(DAHDI_HISTORY_BUF_LEN, GFP_KERNEL);
+       }
+       ss->historypos=0;
+
+/* coop 1 end */
        /* Check numbufs */
        if (numbufs < 2)
                numbufs = 2;
@@ -4654,6 +4669,11 @@
        unsigned long flags;
        int i, j, k, rv;
        int ret, c;
+/* coop 2 */
+        int k1, k2;
+        struct dahdi_history hist;
+/* coop 2 end */
+
        void __user * const user_data = (void __user *)data;

        if (!chan)
@@ -5132,6 +5152,31 @@
                        }
                }
                break;
+/* coop 3 */
+       case DAHDI_GET_HISTORY:
+        if (copy_from_user(&hist,(struct dahdi_history *) data,sizeof(hist)))
+        return -EIO;
+
+        if (!(chan->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
+        if (!chan->history) return -EINVAL;
+        j=hist.len;
+        k1=DAHDI_HISTORY_BUF_LEN-chan->historypos;
+        k2=chan->historypos;
+        if(j>0 && k1>0)
+        {
+        if (copy_to_user(hist.buf,chan->history+chan->historypos,min(j,k1)))
+        return -EIO;
+        j-=min(j,k1);
+        }
+        if(j>0 && k2>0)
+        {
+        if (copy_to_user(hist.buf+k1,chan->history,min(j,k2)))
+        return -EIO;
+        j-=min(j,k2);
+        }
+        /* Probably should assert j==0 here */
+        break;
+/* coop 3 end */
        default:
                /* Check for common ioctl's and private ones */
                rv = dahdi_common_ioctl(file, cmd, data, unit);
@@ -7265,6 +7310,17 @@
                memcpy(ms->putraw, rxb, DAHDI_CHUNKSIZE);
        }

+/* coop 4 */
+       /* Store in the history buffer */
+       if(ms->history)
+       {
+        memcpy(ms->history+ms->historypos,rxb,DAHDI_CHUNKSIZE);
+        ms->historypos+=DAHDI_CHUNKSIZE;
+        if(ms->historypos >= DAHDI_HISTORY_BUF_LEN)
+        ms->historypos=0;
+       }
+/* coop 4 end */
+
        /* Take the rxc, twiddle it for conferencing if appropriate and put it
           back */
        if ((!ms->confmute && !ms->afterdialingtimer) ||





Below are the changes for Dahdi 2.6.1+2.6.1 and Asterisk 11.2.1


Dahdi 2.6.1+2.6.1



Index: linux/drivers/dahdi/dahdi-base.c
===================================================================
--- linux/drivers/dahdi/dahdi-base.c    (revision 10725)
+++ linux/drivers/dahdi/dahdi-base.c    (working copy)
@@ -1073,6 +1073,24 @@
        unsigned long flags;
        int x;

+/* coop 1 */
+
+       /* Allocate history buffer, or not.  This probably shouldn't
+        * be here, but it's convenient */
+       if(!blocksize)
+       {
+          if(ss->history) kfree(ss->history);
+          ss->history = NULL;
+       }
+       else
+       {
+         if(!ss->history) ss->history=kmalloc(DAHDI_HISTORY_BUF_LEN, GFP_KERNEL);
+       }
+       ss->historypos=0;
+
+/* coop 1 end */
+
+
        /* Check numbufs */
        if (numbufs < 2)
                numbufs = 2;
@@ -5680,6 +5698,13 @@
        } stack;
        unsigned long flags;
        int i, j, rv;
+
+/* coop 2 */
+        int k1, k2;
+        struct dahdi_history hist;
+/* coop 2 end */
+
+
        void __user * const user_data = (void __user *)data;

        if (!chan)
@@ -5917,6 +5942,33 @@
                        }
                }
                break;
+
+/* coop 3 */
+       case DAHDI_GET_HISTORY:
+        if (copy_from_user(&hist,(struct dahdi_history *) data,sizeof(hist)))
+        return -EIO;
+
+        if (!(chan->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
+        if (!chan->history) return -EINVAL;
+        j=hist.len;
+        k1=DAHDI_HISTORY_BUF_LEN-chan->historypos;
+        k2=chan->historypos;
+        if(j>0 && k1>0)
+        {
+        if (copy_to_user(hist.buf,chan->history+chan->historypos,min(j,k1)))
+        return -EIO;
+        j-=min(j,k1);
+        }
+        if(j>0 && k2>0)
+        {
+        if (copy_to_user(hist.buf+k1,chan->history,min(j,k2)))
+        return -EIO;
+        j-=min(j,k2);
+        }
+        /* Probably should assert j==0 here */
+        break;
+/* coop 3 end */
+
        default:
                /* Check for common ioctl's and private ones */
                rv = dahdi_common_ioctl(file, cmd, data);
@@ -8521,6 +8573,18 @@
                memcpy(ms->putraw, rxb, DAHDI_CHUNKSIZE);
        }

+/* coop 4 */
+       /* Store in the history buffer */
+       if(ms->history)
+       {
+        memcpy(ms->history+ms->historypos,rxb,DAHDI_CHUNKSIZE);
+        ms->historypos+=DAHDI_CHUNKSIZE;
+        if(ms->historypos >= DAHDI_HISTORY_BUF_LEN)
+        ms->historypos=0;
+       }
+/* coop 4 end */
+
+
        /* Take the rxc, twiddle it for conferencing if appropriate and put it
           back */
        if ((!ms->confmute && !ms->afterdialingtimer) || is_pseudo_chan(ms)) {
Index: linux/include/dahdi/user.h
===================================================================
--- linux/include/dahdi/user.h  (revision 10725)
+++ linux/include/dahdi/user.h  (working copy)
@@ -118,6 +118,11 @@
 #define DAHDI_MAX_NUM_BUFS     32
 #define DAHDI_MAX_BUF_SPACE    32768

+/* coop 1 */
+#define DAHDI_HISTORY_BUF_LEN       16384 /* Count of ulaw samples */
+/* coop 1 end */
+
+
 #define DAHDI_DEFAULT_BLOCKSIZE 1024
 #define DAHDI_DEFAULT_MTR_MRU  2048

@@ -1002,7 +1007,26 @@
  *  80-85 are reserved for dynamic span stuff
  */

+/* coop 3 now moved here to keep inline with numbers above */
+
 /*
+ * Return history buffer
+ */
+#define DAHDI_GET_HISTORY _IOR(DAHDI_CODE, 66, struct dahdi_history)
+
+/* coop 3 end */
+
+/* coop 2 */
+
+  typedef struct dahdi_history
+{
+       unsigned char   *buf;           /* Sample buffer */
+       int len;                /* Length of buffer, in bytes */
+}
+ DAHDI_HISTORY;
+/* coop 2 end */
+
+/*
  * Create a dynamic span
  */
 struct dahdi_dynamic_span {
Index: linux/include/dahdi/kernel.h
===================================================================
--- linux/include/dahdi/kernel.h        (revision 10725)
+++ linux/include/dahdi/kernel.h        (working copy)
@@ -500,6 +500,12 @@

        int             blocksize;      /*!< Block size */

+/* coop 1 moved here from user.h */
+        u_char          *history;       /* History buffer, for pre-ring caller ID (DAHDI_HISTORY_BUF_LEN) */
+        u_short         historypos;     /* Current position within buffer */
+/* coop 1 end */
+
+
        int             eventinidx;  /*!< out index in event buf (circular) */
        int             eventoutidx;  /*!< in index in event buf (circular) */
        unsigned int    eventbuf[DAHDI_MAX_EVENTSIZE];  /*!< event circ. buffer */




Asterisk 11.2.1



Index: channels/chan_dahdi.c
===================================================================
--- channels/chan_dahdi.c       (revision 381845)
+++ channels/chan_dahdi.c       (working copy)
@@ -1767,6 +1767,16 @@
        return 0;
 }

+/* coop 1 */
+static int dahdi_get_history(int fd, void *buf, int buf_size)
+{
+       struct dahdi_history hist;
+       hist.buf=buf;
+       hist.len=buf_size;
+       return ioctl(fd, DAHDI_GET_HISTORY, &hist);
+}
+/* coop 1 end */
+
 static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
 {
        struct dahdi_pvt *p = pvt;
@@ -1775,7 +1785,10 @@
        char *name, *num;
        int index = SUB_REAL;
        int res;
-       unsigned char buf[256];
+/* coop 2 increase buffer size from 256 to 32768 to match history buffer */
+/* unsigned char buf[256]; */
+       unsigned char buf[32768];
+/* coop 2 end */
        int flags;
        struct ast_format tmpfmt;

@@ -1796,7 +1809,20 @@
                 * to enable slin mode and allocate cid detector. get_callerid should be able to be called any number of times until
                 * either a timeout occurs or CID is detected (returns 0). returning 1 should be event received, and -1 should be
                 * a failure and die, and returning 2 means no event was received. */
+/* coop 3a try history buffer otherwise if it fails call read function from original code
+ * To use the history buffer, in /etc/asterisk/chan_dahdi.conf, you should set
+ * cidsignalling=v23   ; to get the CID_SIG_V23 code below
+ * cidstart=ring               ; to get this routine called in the absence of X100P polarity reversal detection
+ */
+               res = dahdi_get_history(p->subs[index].dfd,buf,sizeof(buf));
+               if (res < 0) {
+/* coop 3a end (original line follows) */
                res = read(p->subs[index].dfd, buf, sizeof(buf));
+/* coop 3b return the length of the history buffer */
+               } else {
+                   res = sizeof(buf);
+               }
+/* coop 3b end */
                if (res < 0) {
                        if (errno != ELAST) {
                                ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));





On-Hook Line Monitor (ONHM)


As mentioned above I turned off the ONHM to get polarity detection working reliably. It appears currently the ONHM is turned on by default to monitor the battery and determine whether or not the line is connected, this may also be important for some systems that use interruption of the battery voltage for signaling. According to the si3034 specification the ONHM draws a typical current of 450uA when enabled, according to the BT specifications this is only acceptable on hook whilst reading caller id.

The following is an exert from SIN 227

3.2.1.1.4 D.C. Load

ETS 300 001:1992[2] requires that the total of TE on a line shall not draw in excess of 120 μA
in the Idle State. However, the CDS TE may, as an option, draw d.c. of up to 0.5 mA per
device at 50 V line voltage, but only during CDS Idle State signalling. At other times the
conditions of ETS 300 001:1992 apply.

Impedance matching


I did some quick testing of the FCC, CTR21 and TBR21 DAA modes. With the echo canceler disabled all 3 modes produced an obvious level of echo however TBR21 produced noticeably less echo than the others. This was clearly visible when the channel was monitored using dahdi_monitor.

Exert from the si3034 specification

DC Termination Considerations
                                               
Under certain line conditions, it may be beneficial to use 
other dc termination modes not intended for a particular 
world region. For instance, in countries that comply with 
the CTR21 standard, improved distortion characteristics   
can be seen for very low loop current lines by switching  
to FCC mode. Thus, after going off-hook in CTR21 
mode, the loop current monitor bits (LCS[3:0]) may be
used to measure the loop current, and if LCS[3:0] < 3, it
is recommended that FCC mode be used.


References


History buffer patch
International settings inc TBR21 patch
BT SIN 227 - CDS Calling Line Identification Service - Service Description
si3034 datasheet



Introduction


I wanted to utilise an X100P SE to integrate my UK land line with my PBX. The purpose of this article is to document the configuration changes made and discuss the detection of caller id using this card.

Hardware


Authentic X100P SE 'Wildcard' purchased Sep 09

Software


dahdi-linux-2.2.0.2
dahdi-tools-2.2.0

asterisk-1.4.26.2
asterisk-addons-1.4.9

freepbx-2.5.2

I have updated the fixes below to include Dahdi 2.6.1+2.6.1 and Asterisk 11.2.1

Configuration


The correct modules were automatically loaded and the appropriate timing source automatically selected via the dahdi init script. The wcfxo module handles the si3034 chipset utilised by the X100P SE, it also handles other similar chipsets and cards.

/etc/dahdi/genconf_parameters

lc_country              uk
context_lines           from-zaptel
freepbx                 yes

optionally you may want to uncomment the following line to use the oslec echo canceller

echo_can                oslec

Generate config files

dahdi_genconf system chandahdi=verbose


This should create /etc/dahdi/system.conf and /etc/asterisk/dahdi-channels.cons

/etc/dahdi/system.conf

# Autogenerated by /usr/sbin/dahdi_genconf on Wed Sep 23 20:58:21 2009
# If you edit this file and execute /usr/sbin/dahdi_genconf again,
# your manual changes will be LOST.
# Dahdi Configuration File
#
# This file is parsed by the Dahdi Configurator, dahdi_cfg
#
# Span 1: WCFXO/0 "Wildcard X100P Board 1" (MASTER)
fxsks=1
echocanceller=mg2,1

# Global data

loadzone        = uk
defaultzone     = uk


/etc/asterisk/dahdi-channels.conf

; Autogenerated by /usr/sbin/dahdi_genconf on Wed Sep 23 20:58:21 2009
; If you edit this file and execute /usr/sbin/dahdi_genconf again,
; your manual changes will be LOST.
; Dahdi Channels Configurations (chan_dahdi.conf)
;
; This is not intended to be a complete chan_dahdi.conf. Rather, it is intended
; to be #include-d by /etc/chan_dahdi.conf that will include the global settings
;

; Span 1: WCFXO/0 "Wildcard X100P Board 1" (MASTER)
;;; line="1 WCFXO/0/0 FXSKS  (SWEC: MG2)"
signalling=fxs_ks
callerid=asreceived
group=0
context=from-zaptel
channel => 1
callerid=
group=
context=default

/etc/asterisk/chan_dahdi.conf

;# Flash Operator Panel will parse this file for dahdi trunk buttons
;# AMPLABEL will be used for the display labels on the buttons

;# %c Dahdi Channel number
;# %n Line number
;# %N Line number, but restart counter
;# Example:
;# ;AMPLABEL:Channel %c - Button %n

;# For Dahdi/* buttons use the following
;# (where x=number of buttons to dislpay)
;# ;AMPWILDCARDLABEL(x):MyLabel


[channels]
language=en
usecallerid=yes
cidsignalling=v23
cidstart=polarity  <-- If you are using the "usehist" patch mentioned below this needs to read cidstart=usehist
faxdetect=no
echotraining=yes

#include dahdi-channels.conf
; include dahdi extensions defined in FreePBX
#include chan_dahdi_additional.conf


Note #include dahdi-channels.conf has to be added to pull in the config file generated by dahdi_genconf,
The cidstart setting is specific to my configuration and is not the correct one for the history buffer patch.


/etc/modprobe.d/dahdi

I have applied the patch for TBR21 (complex impedance for UK and others) and set opermode=2 to utilise this.

options wcfxo opermode=2

or
options wcfxo opermode=2 debug=1

for debug

/etc/amportal.conf

changed
# ZAP2DAHDICOMPAT=true|false

to
ZAP2DAHDICOMPAT=true

to enable 'Zap Channel DIDs' to work properly

Discussion


I consider CID to be an important feature and was keen to get this working with my configuration. Initially I decided to investigate the possibility of adding polarity detection to the wcfxo module as the spec sheet for the si3034 suggested that this should be possible. After some testing I found that 2 different methods for polarity detection seem to work.


Polarity detection via SDO


As a first pass I attempted to use the data from the SDO as this was already being used to detect the ring signal. I surmised it may also be possible to detect the polarity change as a pulse akin to details in the spec which state that data received from the SDO should vary in cadence with the ring pins which can be utilised to detect the caller id polarity change. This actually got a partially working system very quickly, I later discovered that the On-Hook Line Monitor (ONHM) was interfering with this approach and turning it off makes it work reliably. Battery detection needs to be disabled to make this work and the ONHM needs to be switched on again when trying to read the caller id signal and turned off afterwards. See below for more details on the ONHM. I'm not sure if the Ring Detector Full Wave Rectifier needs to be on using this method, but it was on during my testing. The detection was working with it switched off, but the ONHM was on so I'm not sure about the results which showed some failures.


Polarity detection via Ring Pins (RDTP and RDTN)


The second method utilises the ring pins and the Ring Detector Full Wave Rectifier this method is described in the specification as the suggested approach and details only enabling the ONHM for caller id detection. I completed this as per specification with the required back off and squelch functions.

Gotcha's


In either of the 2 above scenarios there are times when a false detection will occur. For example the channel going on hook i.e. the OH (Off Hook) pin being cleared after a call has been made/accepted. The problem here is that due to the way the CID detection routine in asterisk works it will mark the channel unavailable till the CID detection is ended either via timeout or by ring. This can lead to issues such as being unable to make a call till the CID detection has timed out. The channel will also not accept another polarity reversal if it is still ringing. This can occur when a caller has hung up before the call was answered and someone else rings back before the previous call fully times out on that channel. The new call will eventually be accepted as the ring state continually toggles on and off as the ring signal is pulsed, however the CID will be blocked as there is currently no way to send the data again.

History buffer patch


I personally think this is the best approach as it need only be fired when a ring has definitely been detected and can prevent the above issues. Further more it is not incompatible with polarity detection and could be toggled on and off using a module parameter. As described in the BT SIN, polarity reversal is an event designed to trip the caller id detection circuit, it is not there as a definitive marker of either an incoming call or caller id data and can easily be caused by other reasons. As such this event is currently being treated incorrectly and a better approach is either to use the history buffer (which it seems was already rejected) or to allow detection within the module in some way.

I know this patch was originally released for use with zaptel and asterisk 1.4, but when I looked for the asterisk 1.6 and dahdi versions I could not find them. They have been mentioned as being posted on websites etc or available from asterisk.org but I searched high and low to no avail.

I have re-worked the patches to work against asterisk-1.6.1.10 and dahdi-linux-2.2.0.2 drivers. I can't find any mention of them being restricted from publication so here they are. Modified from the version zaptel-142 and asterisk 141 by Tony. from lusyn.com. I would send copies to the website, but I can't find an email address for Marc.

asterisk-1.6.1.10-x100p-uk-callerid-usehist.patch


--- asterisk-1.6.1.10/channels/chan_dahdi.c	2009-11-03 18:11:08.000000000 +0000

+++ asterisk-1.6.1.10.modified/channels/chan_dahdi.c	2009-11-26 09:02:03.000000000 +0000

@@ -1517,6 +1517,15 @@

	return 0;

}


+/* coop 1 */

+static int dahdi_get_history(int fd, void *buf, int buf_size)

+{

+	struct dahdi_history hist;

+	hist.buf=buf;

+	hist.len=buf_size;

+	return ioctl(fd, DAHDI_GET_HISTORY, &hist);

+}

+/* coop 1 end */


static int alloc_sub(struct dahdi_pvt *p, int x)

{

@@ -6546,6 +6555,7 @@

			on? "enabled" : "disabled");

}


+/* coop temp */

static void *ss_thread(void *data)


{

	struct ast_channel *chan = data;

@@ -7226,6 +7236,132 @@

		if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {

	    		number = smdi_msg->calling_st;



+

+

+

+

+

+/* coop 2 */

+	/* Check to see if caller ID needs to be extracted from

+	* the history buffer */

+	} else if (p->use_callerid && p->cid_start == CID_START_USEHIST) {

+		ast_log(LOG_DEBUG,"Using history buffer to extract caller ID\n");

+		cs = callerid_new(p->cid_signalling);

+		if (cs) {

+			unsigned char cidbuf[32768];

+			res=0;

+

+			res = dahdi_get_history(p->subs[idx].dfd,cidbuf,sizeof(cidbuf));

+			if(res<0) {

+				ast_log(LOG_ERROR,"dahdi_get_history failed: %s\n", strerror(errno));

+			} else {

+				res=callerid_feed(cs,cidbuf,sizeof(cidbuf),AST_LAW(p));

+				if (res < 0) {

+				ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));

+					}

+				}

+

+				if(res==1) {

+				callerid_get(cs, &name, &number, &flags);

+				if (option_debug) 

+				ast_log(LOG_DEBUG, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);

+				}

+			}

+			if (p->usedistinctiveringdetection == 1) {

+#if 1

+			bump_gains(p);

+#endif				

+				len = 0;

+				distMatches = 0;

+				/* Clear the current ring data array so we dont have old data in it. */

+				for (receivedRingT=0; receivedRingT < 3; receivedRingT++) {

+					curRingData[receivedRingT] = 0;

+				}

+				receivedRingT = 0;

+				counter = 0;

+				counter1 = 0;

+				/* Check to see if context is what it should be, if not set to be. */

+				if (strcmp(p->context,p->defcontext) != 0) {

+					strncpy(p->context, p->defcontext, sizeof(p->context)-1);

+					strncpy(chan->context,p->defcontext,sizeof(chan->context)-1);

+				}

+

+				for(;;) {	

+					i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;

+					if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i)))	{

+						ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));

+						callerid_free(cs);

+						ast_hangup(chan);

+						return NULL;

+					}

+					if (i & DAHDI_IOMUX_SIGEVENT) {

+					res = dahdi_get_event(p->subs[idx].dfd);

+					ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));

+					res = 0;

+					/* Let us detect distinctive ring */

+

+						curRingData[receivedRingT] = p->ringt;

+

+						if (p->ringt < ringt_base/2)

+							break;

+					++receivedRingT; /* Increment the ringT counter so we can match it against

+							values in zapata.conf for distinctive ring */

+					} else if (i & DAHDI_IOMUX_READ) {

+						res = read(p->subs[idx].dfd, buf, sizeof(buf));

+						if (res < 0) {

+							if (errno != ELAST) {

+							ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));

+								callerid_free(cs);

+								ast_hangup(chan);

+								return NULL;

+							}

+							break;

+						}

+						if (p->ringt) 

+							p->ringt--;

+						if (p->ringt == 1) {

+							res = -1;

+							break;

+						}

+					}

+				}

+				if(option_verbose > 2) 

+				/* this only shows up if you have n of the dring patterns filled in */

+				ast_verbose( VERBOSE_PREFIX_3 "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);

+

+				for (counter=0; counter < 3; counter++) {

+				/* Check to see if the rings we received match any of the ones in zapata.conf for this channel */

+				distMatches = 0;

+				for (counter1=0; counter1 < 3; counter1++) {

+					if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1]+10) && curRingData[counter1] >=

+					(p->drings.ringnum[counter].ring[counter1]-10)) {

+						distMatches++;

+					}

+				}

+				if (distMatches == 3) {

+					/* The ring matches, set the context to whatever is for distinctive ring.. */

+					strncpy(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context)-1);

+					strncpy(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context)-1);

+					if(option_verbose > 2) 

+					ast_verbose( VERBOSE_PREFIX_3  "Distinctive Ring matched context %s\n",p->context);

+					break;

+				}

+			}

+		}

+		/* Restore linear mode (if appropriate) for Caller*ID processing */

+		dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);

+#if 1

+			restore_gains(p);

+#endif

+

+/* coop 2 end */

+

+

+

+

+

+

+

		/* If we want caller id, we're in a prering state due to a polarity reversal

		* and we're set to use a polarity reversal to trigger the start of caller id,

		* grab the caller id and wait for ringing to start... */

@@ -14356,6 +14492,10 @@

				confp->chan.cid_start = CID_START_POLARITY_IN;

			else if (!strcasecmp(v->value, "polarity"))

				confp->chan.cid_start = CID_START_POLARITY;

+/* coop 3 */

+			else if (!strcasecmp(v->value, "usehist"))

+				confp->chan.cid_start = CID_START_USEHIST;

+/* coop 3 end */

			else if (ast_true(v->value))

				confp->chan.cid_start = CID_START_RING;

		} else if (!strcasecmp(v->name, "threewaycalling")) {

 --- asterisk-1.6.1.10/include/asterisk/callerid.h	2009-03-09 21:22:42.000000000 +0000

+++ asterisk-1.6.1.10.modified/include/asterisk/callerid.h	2009-11-26 09:12:59.000000000 +0000

@@ -63,6 +63,9 @@

#define CID_START_RING	1

#define CID_START_POLARITY 2

#define CID_START_POLARITY_IN 3

+/* coop 1 */

+#define CID_START_USEHIST 4

+/* coop 1 end */



/* defines dealing with message waiting indication generation */

/*! MWI SDMF format */



This version fixes formatting issues above and updates for Asterisk 1.6.2.11

The text below should now be acceptable to "patch -p0"

Index: channels/chan_dahdi.c
===================================================================
--- channels/chan_dahdi.c       (revision 281981)
+++ channels/chan_dahdi.c       (working copy)
@@ -2173,6 +2173,15 @@
        return 0;
 }

+/* coop 1 */
+static int dahdi_get_history(int fd, void *buf, int buf_size)
+{
+       struct dahdi_history hist;
+       hist.buf=buf;
+       hist.len=buf_size;
+       return ioctl(fd, DAHDI_GET_HISTORY, &hist);
+}
+/* coop 1 end */

 static int alloc_sub(struct dahdi_pvt *p, int x)
 {
@@ -8444,6 +8453,121 @@
                if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {
                        number = smdi_msg->calling_st;

+/* coop 2 */
+       /* Check to see if caller ID needs to be extracted from
+       * the history buffer */
+       } else if (p->use_callerid && p->cid_start == CID_START_USEHIST) {
+        ast_log(LOG_DEBUG,"Using history buffer to extract caller ID\n");
+        cs = callerid_new(p->cid_signalling);
+        if (cs) {
+        unsigned char cidbuf[32768];
+        res=0;
+
+        res = dahdi_get_history(p->subs[idx].dfd,cidbuf,sizeof(cidbuf));
+        if(res<0) {
+        ast_log(LOG_ERROR,"dahdi_get_history failed: %s\n", strerror(errno));
+        } else {
+        res=callerid_feed(cs,cidbuf,sizeof(cidbuf),AST_LAW(p));
+        if (res < 0) {
+        ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
+        }
+        }
+
+        if(res==1) {
+        callerid_get(cs, &name, &number, &flags);
+        if (option_debug)
+        ast_log(LOG_DEBUG, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
+        }
+        }
+        if (p->usedistinctiveringdetection == 1) {
+#if 1
+        bump_gains(p);
+#endif
+        len = 0;
+        distMatches = 0;
+        /* Clear the current ring data array so we dont have old data in it. */
+        for (receivedRingT=0; receivedRingT < 3; receivedRingT++) {
+        curRingData[receivedRingT] = 0;
+        }
+        receivedRingT = 0;
+        counter = 0;
+        counter1 = 0;
+        /* Check to see if context is what it should be, if not set to be. */
+        if (strcmp(p->context,p->defcontext) != 0) {
+        strncpy(p->context, p->defcontext, sizeof(p->context)-1);
+        strncpy(chan->context,p->defcontext,sizeof(chan->context)-1);
+        }
+
+        for(;;) {
+        i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
+        if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i)))  {
+        ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
+        callerid_free(cs);
+        ast_hangup(chan);
+        return NULL;
+        }
+        if (i & DAHDI_IOMUX_SIGEVENT) {
+        res = dahdi_get_event(p->subs[idx].dfd);
+        ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
+        res = 0;
+        /* Let us detect distinctive ring */
+
+        curRingData[receivedRingT] = p->ringt;
+
+        if (p->ringt < ringt_base/2)
+        break;
+        ++receivedRingT; /* Increment the ringT counter so we can match it against
+        values in zapata.conf for distinctive ring */
+        } else if (i & DAHDI_IOMUX_READ) {
+        res = read(p->subs[idx].dfd, buf, sizeof(buf));
+        if (res < 0) {
+        if (errno != ELAST) {
+        ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
+        callerid_free(cs);
+        ast_hangup(chan);
+        return NULL;
+        }
+        break;
+        }
+        if (p->ringt)
+        p->ringt--;
+        if (p->ringt == 1) {
+        res = -1;
+        break;
+        }
+        }
+        }
+        if(option_verbose > 2)
+        /* this only shows up if you have n of the dring patterns filled in */
+        ast_verbose( VERBOSE_PREFIX_3 "Detected ring pattern: NaVd,%d %d %d\n",curRingData[0],curRingData[1],curRingData[2]);
+
+        for (counter=0; counter < 3; counter++) {
+        /* Check to see if the rings we received match any of the ones in zapata.conf for this channel */
+        distMatches = 0;
+        for (counter1=0; counter1 < 3; counter1++) {
+        if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1]+10) && curRingData[counter1] >=
+        (p->drings.ringnum[counter].ring[counter1]-10)) {
+        distMatches++;
+        }
+        }
+        if (distMatches == 3) {
+        /* The ring matches, set the context to whatever is for distinctive ring.. */
+        strncpy(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context)-1);
+        strncpy(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context)-1);
+        if(option_verbose > 2)
+        ast_verbose( VERBOSE_PREFIX_3  "Distinctive Ring matched context %s\n",p->context);
+        break;
+        }
+        }
+        }
+        /* Restore linear mode (if appropriate) for Caller*ID processing */
+        dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
+#if 1
+        restore_gains(p);
+#endif
+
+/* coop 2 end */
+
                /* If we want caller id, we're in a prering state due to a polarity reversal
                 * and we're set to use a polarity reversal to trigger the start of caller id,
                 * grab the caller id and wait for ringing to start... */
@@ -16297,6 +16421,10 @@
                                confp->chan.cid_start = CID_START_POLARITY_IN;
                        else if (!strcasecmp(v->value, "polarity"))
                                confp->chan.cid_start = CID_START_POLARITY;
+/* coop 3 */
+        else if (!strcasecmp(v->value, "usehist"))
+        confp->chan.cid_start = CID_START_USEHIST;
+/* coop 3 end */
                        else if (ast_true(v->value))
                                confp->chan.cid_start = CID_START_RING;
                } else if (!strcasecmp(v->name, "threewaycalling")) {
Index: include/asterisk/callerid.h
===================================================================
--- include/asterisk/callerid.h (revision 281981)
+++ include/asterisk/callerid.h (working copy)
@@ -63,6 +63,7 @@
 #define CID_START_RING 1
 #define CID_START_POLARITY 2
 #define CID_START_POLARITY_IN 3
+#define CID_START_USEHIST 4

 /* defines dealing with message waiting indication generation */
 /*! MWI SDMF format */





dahdi-linux-2.2.0.2-x100p-uk-callerid-usehist.patch






+++ dahdi-linux-2.2.0.2.modified/drivers/dahdi/dahdi-base.c 2009-11-25 15:37:18.000000000 +0000
@@ -903,6 +903,22 @@

unsigned char *newbuf, *oldbuf;

unsigned long flags;

int x;

+/* coop 1 */
+
+       /* Allocate history buffer, or not.  This probably shouldn't
+        * be here, but it's convenient */
+       if(!j)
+       {
+          if(ss->history) kfree(ss->history);
+          ss->history = NULL;
+       }
+       else
+       {
+         if(!ss->history) ss->history=kmalloc(DAHDI_HISTORY_BUF_LEN, GFP_KERNEL);
+       }
+       ss->historypos=0;
+
+/* coop 1 end */


/* Check numbufs */

if (numbufs < 2)

@@ -4345,6 +4361,10 @@

unsigned long flags;

int i, j, k, rv;

int ret, c;

+/* coop 2 */
+        int k1, k2;
+        struct dahdi_history hist;
+/* coop 2 end */


if (!chan)

return -EINVAL;

@@ -4818,6 +4838,31 @@

}

}

break;

+/* coop 3 */
+ case DAHDI_GET_HISTORY:
+ if (copy_from_user(&hist,(struct dahdi_history *) data,sizeof(hist)))
+ return -EIO;
+
+ if (!(chan->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
+ if (!chan->history) return -EINVAL;
+ j=hist.len;
+ k1=DAHDI_HISTORY_BUF_LEN-chan->historypos;
+ k2=chan->historypos;
+ if(j>0 && k1>0)
+ {
+ if (copy_to_user(hist.buf,chan->history+chan->historypos,min(j,k1)))
+ return -EIO;
+ j-=min(j,k1);
+ }
+ if(j>0 && k2>0)
+ {
+ if (copy_to_user(hist.buf+k1,chan->history,min(j,k2)))
+ return -EIO;
+ j-=min(j,k2);
+ }
+ /* Probably should assert j==0 here */
+ break;
+/* coop 3 end */
default:

/* Check for common ioctl's and private ones */

rv = dahdi_common_ioctl(inode, file, cmd, data, unit);

@@ -6827,6 +6872,16 @@

memcpy(ms->putlin, putlin, DAHDI_CHUNKSIZE * sizeof(short));

memcpy(ms->putraw, rxb, DAHDI_CHUNKSIZE);

}

+/* coop 4 */
+ /* Store in the history buffer */
+ if(ms->history)
+ {
+ memcpy(ms->history+ms->historypos,rxb,DAHDI_CHUNKSIZE);
+ ms->historypos+=DAHDI_CHUNKSIZE;
+ if(ms->historypos >= DAHDI_HISTORY_BUF_LEN)
+ ms->historypos=0;
+ }
+/* coop 4 end */


/* Take the rxc, twiddle it for conferencing if appropriate and put it

  back */



+++ dahdi-linux-2.2.0.2.modified/include/dahdi/kernel.h 2009-11-25 15:26:35.000000000 +0000
@@ -448,6 +448,10 @@

wait_queue_head_t writebufq; /*!< write wait queue */



int blocksize; /*!< Block size */

+/* coop 1 moved here from user.h */
+        u_char          *history;       /* History buffer, for pre-ring caller ID (DAHDI_HISTORY_BUF_LEN) */
+        u_short         historypos;     /* Current position within buffer */
+/* coop 1 end */


int eventinidx;  /*!< out index in event buf (circular) */

int eventoutidx;  /*!< in index in event buf (circular) */



+++ dahdi-linux-2.2.0.2.modified/include/dahdi/user.h 2009-11-25 15:31:43.000000000 +0000
@@ -114,6 +114,10 @@

  1. define DAHDI_MAX_NUM_BUFS 32

  1. define DAHDI_MAX_BUF_SPACE 32768



+/* coop 1 */
+#define DAHDI_HISTORY_BUF_LEN       16384 /* Count of ulaw samples */
+/* coop 1 end */
+
  1. define DAHDI_DEFAULT_BLOCKSIZE 1024

  1. define DAHDI_DEFAULT_MTR_MRU 2048



@@ -946,6 +950,22 @@

 *  60-80 are reserved for private drivers

 *  80-85 are reserved for dynamic span stuff

 */

+/* coop 3 now moved here to keep inline with numbers above */
+ /*
+ * Return history buffer
+ */
+#define DAHDI_GET_HISTORY _IOR(DAHDI_CODE, 66, struct dahdi_history)
+
+/* coop 3 end */
+
+/* coop 2 */
+
+typedef struct dahdi_history
+{
+ unsigned char   *buf;           /* Sample buffer */
+ int len;                /* Length of buffer, in bytes */
+} DAHDI_HISTORY;
+/* coop 2 end */


/*

 * Create a dynamic span



This version fixes formatting issues above and updates for Dahdi version 2.3.0.1+2.3.0

The text below should now be acceptable to "patch -p0"

Index: include/dahdi/user.h
===================================================================
--- include/dahdi/user.h        (revision 9129)
+++ include/dahdi/user.h        (working copy)
@@ -116,7 +116,10 @@
 #define DAHDI_DEFAULT_NUM_BUFS 2
 #define DAHDI_MAX_NUM_BUFS     32
 #define DAHDI_MAX_BUF_SPACE    32768
-
+/* coop 1 */
+#define DAHDI_HISTORY_BUF_LEN       16384 /* Count of ulaw samples */
+/* coop 1 end */
+
 #define DAHDI_DEFAULT_BLOCKSIZE 1024
 #define DAHDI_DEFAULT_MTR_MRU  2048

@@ -994,7 +997,22 @@
  *  60-80 are reserved for private drivers
  *  80-85 are reserved for dynamic span stuff
  */
-
+/* coop 3 now moved here to keep inline with numbers above */
+ /*
+ * Return history buffer
+ */
+#define DAHDI_GET_HISTORY _IOR(DAHDI_CODE, 66, struct dahdi_history)
+
+/* coop 3 end */
+
+/* coop 2 */
+
+typedef struct dahdi_history
+{
+       unsigned char   *buf;           /* Sample buffer */
+       int len;                /* Length of buffer, in bytes */
+} DAHDI_HISTORY;
+/* coop 2 end */
 /*
  * Create a dynamic span
  */
Index: include/dahdi/kernel.h
===================================================================
--- include/dahdi/kernel.h      (revision 9129)
+++ include/dahdi/kernel.h      (working copy)
@@ -454,6 +454,10 @@
        wait_queue_head_t writebufq; /*!< write wait queue */

        int             blocksize;      /*!< Block size */
+/* coop 1 moved here from user.h */
+        u_char          *history;       /* History buffer, for pre-ring caller ID (DAHDI_HISTORY_BUF_LEN) */
+        u_short         historypos;     /* Current position within buffer */
+/* coop 1 end */

        int             eventinidx;  /*!< out index in event buf (circular) */
        int             eventoutidx;  /*!< in index in event buf (circular) */
Index: drivers/dahdi/dahdi-base.c
===================================================================
--- drivers/dahdi/dahdi-base.c  (revision 9129)
+++ drivers/dahdi/dahdi-base.c  (working copy)
@@ -958,7 +958,22 @@
        unsigned char *oldrxbuf = NULL;
        unsigned long flags;
        int x;
-
+/* coop 1 */
+
+       /* Allocate history buffer, or not.  This probably shouldn't
+        * be here, but it's convenient */
+       if(!blocksize)
+       {
+          if(ss->history) kfree(ss->history);
+          ss->history = NULL;
+       }
+       else
+       {
+         if(!ss->history) ss->history=kmalloc(DAHDI_HISTORY_BUF_LEN, GFP_KERNEL);
+       }
+       ss->historypos=0;
+
+/* coop 1 end */
        /* Check numbufs */
        if (numbufs < 2)
                numbufs = 2;
@@ -4654,6 +4669,11 @@
        unsigned long flags;
        int i, j, k, rv;
        int ret, c;
+/* coop 2 */
+        int k1, k2;
+        struct dahdi_history hist;
+/* coop 2 end */
+
        void __user * const user_data = (void __user *)data;

        if (!chan)
@@ -5132,6 +5152,31 @@
                        }
                }
                break;
+/* coop 3 */
+       case DAHDI_GET_HISTORY:
+        if (copy_from_user(&hist,(struct dahdi_history *) data,sizeof(hist)))
+        return -EIO;
+
+        if (!(chan->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
+        if (!chan->history) return -EINVAL;
+        j=hist.len;
+        k1=DAHDI_HISTORY_BUF_LEN-chan->historypos;
+        k2=chan->historypos;
+        if(j>0 && k1>0)
+        {
+        if (copy_to_user(hist.buf,chan->history+chan->historypos,min(j,k1)))
+        return -EIO;
+        j-=min(j,k1);
+        }
+        if(j>0 && k2>0)
+        {
+        if (copy_to_user(hist.buf+k1,chan->history,min(j,k2)))
+        return -EIO;
+        j-=min(j,k2);
+        }
+        /* Probably should assert j==0 here */
+        break;
+/* coop 3 end */
        default:
                /* Check for common ioctl's and private ones */
                rv = dahdi_common_ioctl(file, cmd, data, unit);
@@ -7265,6 +7310,17 @@
                memcpy(ms->putraw, rxb, DAHDI_CHUNKSIZE);
        }

+/* coop 4 */
+       /* Store in the history buffer */
+       if(ms->history)
+       {
+        memcpy(ms->history+ms->historypos,rxb,DAHDI_CHUNKSIZE);
+        ms->historypos+=DAHDI_CHUNKSIZE;
+        if(ms->historypos >= DAHDI_HISTORY_BUF_LEN)
+        ms->historypos=0;
+       }
+/* coop 4 end */
+
        /* Take the rxc, twiddle it for conferencing if appropriate and put it
           back */
        if ((!ms->confmute && !ms->afterdialingtimer) ||





Below are the changes for Dahdi 2.6.1+2.6.1 and Asterisk 11.2.1


Dahdi 2.6.1+2.6.1



Index: linux/drivers/dahdi/dahdi-base.c
===================================================================
--- linux/drivers/dahdi/dahdi-base.c    (revision 10725)
+++ linux/drivers/dahdi/dahdi-base.c    (working copy)
@@ -1073,6 +1073,24 @@
        unsigned long flags;
        int x;

+/* coop 1 */
+
+       /* Allocate history buffer, or not.  This probably shouldn't
+        * be here, but it's convenient */
+       if(!blocksize)
+       {
+          if(ss->history) kfree(ss->history);
+          ss->history = NULL;
+       }
+       else
+       {
+         if(!ss->history) ss->history=kmalloc(DAHDI_HISTORY_BUF_LEN, GFP_KERNEL);
+       }
+       ss->historypos=0;
+
+/* coop 1 end */
+
+
        /* Check numbufs */
        if (numbufs < 2)
                numbufs = 2;
@@ -5680,6 +5698,13 @@
        } stack;
        unsigned long flags;
        int i, j, rv;
+
+/* coop 2 */
+        int k1, k2;
+        struct dahdi_history hist;
+/* coop 2 end */
+
+
        void __user * const user_data = (void __user *)data;

        if (!chan)
@@ -5917,6 +5942,33 @@
                        }
                }
                break;
+
+/* coop 3 */
+       case DAHDI_GET_HISTORY:
+        if (copy_from_user(&hist,(struct dahdi_history *) data,sizeof(hist)))
+        return -EIO;
+
+        if (!(chan->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
+        if (!chan->history) return -EINVAL;
+        j=hist.len;
+        k1=DAHDI_HISTORY_BUF_LEN-chan->historypos;
+        k2=chan->historypos;
+        if(j>0 && k1>0)
+        {
+        if (copy_to_user(hist.buf,chan->history+chan->historypos,min(j,k1)))
+        return -EIO;
+        j-=min(j,k1);
+        }
+        if(j>0 && k2>0)
+        {
+        if (copy_to_user(hist.buf+k1,chan->history,min(j,k2)))
+        return -EIO;
+        j-=min(j,k2);
+        }
+        /* Probably should assert j==0 here */
+        break;
+/* coop 3 end */
+
        default:
                /* Check for common ioctl's and private ones */
                rv = dahdi_common_ioctl(file, cmd, data);
@@ -8521,6 +8573,18 @@
                memcpy(ms->putraw, rxb, DAHDI_CHUNKSIZE);
        }

+/* coop 4 */
+       /* Store in the history buffer */
+       if(ms->history)
+       {
+        memcpy(ms->history+ms->historypos,rxb,DAHDI_CHUNKSIZE);
+        ms->historypos+=DAHDI_CHUNKSIZE;
+        if(ms->historypos >= DAHDI_HISTORY_BUF_LEN)
+        ms->historypos=0;
+       }
+/* coop 4 end */
+
+
        /* Take the rxc, twiddle it for conferencing if appropriate and put it
           back */
        if ((!ms->confmute && !ms->afterdialingtimer) || is_pseudo_chan(ms)) {
Index: linux/include/dahdi/user.h
===================================================================
--- linux/include/dahdi/user.h  (revision 10725)
+++ linux/include/dahdi/user.h  (working copy)
@@ -118,6 +118,11 @@
 #define DAHDI_MAX_NUM_BUFS     32
 #define DAHDI_MAX_BUF_SPACE    32768

+/* coop 1 */
+#define DAHDI_HISTORY_BUF_LEN       16384 /* Count of ulaw samples */
+/* coop 1 end */
+
+
 #define DAHDI_DEFAULT_BLOCKSIZE 1024
 #define DAHDI_DEFAULT_MTR_MRU  2048

@@ -1002,7 +1007,26 @@
  *  80-85 are reserved for dynamic span stuff
  */

+/* coop 3 now moved here to keep inline with numbers above */
+
 /*
+ * Return history buffer
+ */
+#define DAHDI_GET_HISTORY _IOR(DAHDI_CODE, 66, struct dahdi_history)
+
+/* coop 3 end */
+
+/* coop 2 */
+
+  typedef struct dahdi_history
+{
+       unsigned char   *buf;           /* Sample buffer */
+       int len;                /* Length of buffer, in bytes */
+}
+ DAHDI_HISTORY;
+/* coop 2 end */
+
+/*
  * Create a dynamic span
  */
 struct dahdi_dynamic_span {
Index: linux/include/dahdi/kernel.h
===================================================================
--- linux/include/dahdi/kernel.h        (revision 10725)
+++ linux/include/dahdi/kernel.h        (working copy)
@@ -500,6 +500,12 @@

        int             blocksize;      /*!< Block size */

+/* coop 1 moved here from user.h */
+        u_char          *history;       /* History buffer, for pre-ring caller ID (DAHDI_HISTORY_BUF_LEN) */
+        u_short         historypos;     /* Current position within buffer */
+/* coop 1 end */
+
+
        int             eventinidx;  /*!< out index in event buf (circular) */
        int             eventoutidx;  /*!< in index in event buf (circular) */
        unsigned int    eventbuf[DAHDI_MAX_EVENTSIZE];  /*!< event circ. buffer */




Asterisk 11.2.1



Index: channels/chan_dahdi.c
===================================================================
--- channels/chan_dahdi.c       (revision 381845)
+++ channels/chan_dahdi.c       (working copy)
@@ -1767,6 +1767,16 @@
        return 0;
 }

+/* coop 1 */
+static int dahdi_get_history(int fd, void *buf, int buf_size)
+{
+       struct dahdi_history hist;
+       hist.buf=buf;
+       hist.len=buf_size;
+       return ioctl(fd, DAHDI_GET_HISTORY, &hist);
+}
+/* coop 1 end */
+
 static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
 {
        struct dahdi_pvt *p = pvt;
@@ -1775,7 +1785,10 @@
        char *name, *num;
        int index = SUB_REAL;
        int res;
-       unsigned char buf[256];
+/* coop 2 increase buffer size from 256 to 32768 to match history buffer */
+/* unsigned char buf[256]; */
+       unsigned char buf[32768];
+/* coop 2 end */
        int flags;
        struct ast_format tmpfmt;

@@ -1796,7 +1809,20 @@
                 * to enable slin mode and allocate cid detector. get_callerid should be able to be called any number of times until
                 * either a timeout occurs or CID is detected (returns 0). returning 1 should be event received, and -1 should be
                 * a failure and die, and returning 2 means no event was received. */
+/* coop 3a try history buffer otherwise if it fails call read function from original code
+ * To use the history buffer, in /etc/asterisk/chan_dahdi.conf, you should set
+ * cidsignalling=v23   ; to get the CID_SIG_V23 code below
+ * cidstart=ring               ; to get this routine called in the absence of X100P polarity reversal detection
+ */
+               res = dahdi_get_history(p->subs[index].dfd,buf,sizeof(buf));
+               if (res < 0) {
+/* coop 3a end (original line follows) */
                res = read(p->subs[index].dfd, buf, sizeof(buf));
+/* coop 3b return the length of the history buffer */
+               } else {
+                   res = sizeof(buf);
+               }
+/* coop 3b end */
                if (res < 0) {
                        if (errno != ELAST) {
                                ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));





On-Hook Line Monitor (ONHM)


As mentioned above I turned off the ONHM to get polarity detection working reliably. It appears currently the ONHM is turned on by default to monitor the battery and determine whether or not the line is connected, this may also be important for some systems that use interruption of the battery voltage for signaling. According to the si3034 specification the ONHM draws a typical current of 450uA when enabled, according to the BT specifications this is only acceptable on hook whilst reading caller id.

The following is an exert from SIN 227

3.2.1.1.4 D.C. Load

ETS 300 001:1992[2] requires that the total of TE on a line shall not draw in excess of 120 μA
in the Idle State. However, the CDS TE may, as an option, draw d.c. of up to 0.5 mA per
device at 50 V line voltage, but only during CDS Idle State signalling. At other times the
conditions of ETS 300 001:1992 apply.

Impedance matching


I did some quick testing of the FCC, CTR21 and TBR21 DAA modes. With the echo canceler disabled all 3 modes produced an obvious level of echo however TBR21 produced noticeably less echo than the others. This was clearly visible when the channel was monitored using dahdi_monitor.

Exert from the si3034 specification

DC Termination Considerations
                                               
Under certain line conditions, it may be beneficial to use 
other dc termination modes not intended for a particular 
world region. For instance, in countries that comply with 
the CTR21 standard, improved distortion characteristics   
can be seen for very low loop current lines by switching  
to FCC mode. Thus, after going off-hook in CTR21 
mode, the loop current monitor bits (LCS[3:0]) may be
used to measure the loop current, and if LCS[3:0] < 3, it
is recommended that FCC mode be used.


References


History buffer patch
International settings inc TBR21 patch
BT SIN 227 - CDS Calling Line Identification Service - Service Description
si3034 datasheet



Created by: troublebot, Last modification: Thu 28 of Feb, 2013 (10:55 UTC) by whiskerp
Please update this page with new information, just login and click on the "Edit" or "Discussion" tab. Get a free login here: Register Thanks! - Find us on Google+