Index: chan_phone.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_phone.c,v
retrieving revision 1.55
diff -u -r1.55 chan_phone.c
--- chan_phone.c	15 Jul 2005 23:00:46 -0000	1.55
+++ chan_phone.c	10 Aug 2005 22:53:55 -0000
@@ -76,12 +76,16 @@
 
 /* Default language */
 static char language[MAX_LANGUAGE] = "";
-static int usecnt =0;
 
-static int echocancel = AEC_OFF;
+static int usecnt = 0;
+/* tone filter and reorder & busy cadence */
+static IXJ_FILTER busyfilter;
+static IXJ_FILTER reorderfilter;
+static IXJ_FILTER_CADENCE busy;
+static IXJ_FILTER_CADENCE reorder;
 
+static int echocancel = AEC_OFF;
 static int silencesupression = 0;
-
 static int prefformat = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW;
 
 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
@@ -104,26 +108,26 @@
    
 #define MODE_DIALTONE 	1
 #define MODE_IMMEDIATE	2
-#define MODE_FXO		3
+#define MODE_FXO	3
 #define MODE_FXS        4
 
 static struct phone_pvt {
-	int fd;							/* Raw file descriptor for this device */
-	struct ast_channel *owner;		/* Channel we belong to, possibly NULL */
-	int mode;						/* Is this in the  */
+	int fd;						/* Raw file descriptor for this device */
+	struct ast_channel *owner;			/* Channel we belong to, possibly NULL */
+	int mode;					/* Is this in the  */
 	int lastformat;					/* Last output format */
 	int lastinput;					/* Last input format */
 	int ministate;					/* Miniature state, for dialtone mode */
 	char dev[256];					/* Device name */
-	struct phone_pvt *next;			/* Next channel in list */
-	struct ast_frame fr;			/* Frame */
+	struct phone_pvt *next;				/* Next channel in list */
+	struct ast_frame fr;				/* Frame */
 	char offset[AST_FRIENDLY_OFFSET];
-	char buf[PHONE_MAX_BUF];					/* Static buffer for reading frames */
+	char buf[PHONE_MAX_BUF];			/* Static buffer for reading frames */
 	int obuflen;
 	int dialtone;
-	int txgain, rxgain;             /* gain control for playing, recording  */
-									/* 0x100 - 1.0, 0x200 - 2.0, 0x80 - 0.5 */
-	int cpt;						/* Call Progress Tone playing? */
+	int txgain, rxgain;             		/* gain control for playing, recording  */
+							/* 0x100 - 1.0, 0x200 - 2.0, 0x80 - 0.5 */
+	int cpt;					/* Call Progress Tone playing? */
 	int silencesupression;
 	char context[AST_MAX_EXTENSION];
 	char obuf[PHONE_MAX_BUF * 2];
@@ -131,6 +135,7 @@
 	char language[MAX_LANGUAGE];
 	char cid_num[AST_MAX_EXTENSION];
 	char cid_name[AST_MAX_EXTENSION];
+	int flash;					/* are we "flashed over"? */
 } *iflist = NULL;
 
 static char cid_num[AST_MAX_EXTENSION];
@@ -147,7 +152,8 @@
 static int phone_send_text(struct ast_channel *ast, const char *text);
 static int phone_fixup(struct ast_channel *old, struct ast_channel *new);
 
-static const struct ast_channel_tech phone_tech = {
+/* This channel tech is used for FXO mode */
+static const struct ast_channel_tech phone_tech_fxo = {
 	.type = type,
 	.description = tdesc,
 	.capabilities = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW,
@@ -162,9 +168,11 @@
 	.fixup = phone_fixup
 };
 
+/* This channel tech is used for FXS mode */
 static struct ast_channel_tech phone_tech_fxs = {
 	.type = type,
 	.description = tdesc,
+	.capabilities = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW,
 	.requester = phone_request,
 	.send_digit = phone_digit,
 	.call = phone_call,
@@ -192,10 +200,11 @@
 {
 	struct phone_pvt *p;
 	int outdigit;
+	
 	p = ast->tech_pvt;
-	ast_log(LOG_NOTICE, "Dialed %c\n", digit);
+	if (option_debug)
+	    ast_log(LOG_DEBUG, "Dialed %c\n", digit);
 	switch(digit) {
-	case '0':
 	case '1':
 	case '2':
 	case '3':
@@ -205,9 +214,13 @@
 	case '7':
 	case '8':
 	case '9':
+	
 		outdigit = digit - '0';
 		break;
 	case '*':
+		outdigit = 10;
+		break;
+	case '0':
 		outdigit = 11;
 		break;
 	case '#':
@@ -218,13 +231,15 @@
 		ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);
 		usleep(320000);
 		ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);
-		p->lastformat = -1;
+		if (p->flash)
+		    p->flash = 0;
+		else
+		    p->flash = 1;
 		return 0;
 	default:
 		ast_log(LOG_WARNING, "Unknown digit '%c'\n", digit);
 		return -1;
 	}
-	ast_log(LOG_NOTICE, "Dialed %d\n", outdigit);
 	ioctl(p->fd, PHONE_PLAY_TONE, outdigit);
 	p->lastformat = -1;
 	return 0;
@@ -309,16 +324,19 @@
 
 	/* If it's an FXO, hang them up */
 	if (p->mode == MODE_FXO) {
-		if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK)) 
+		ast_log(LOG_DEBUG, "Got hunghup, hanging up\n");
+		if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK) == -1) 
 			ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",ast->name, strerror(errno));
 	}
 
 	/* If they're off hook, give a busy signal */
-	if (ioctl(p->fd, PHONE_HOOKSTATE)) {
-		if (option_debug)
-			ast_log(LOG_DEBUG, "Got hunghup, giving busy signal\n");
-		ioctl(p->fd, PHONE_BUSY);
-		p->cpt = 1;
+	else {
+		if (ioctl(p->fd, PHONE_HOOKSTATE)) {
+			if (option_debug)
+				ast_log(LOG_DEBUG, "Got hunghup, giving busy signal\n");
+			ioctl(p->fd, PHONE_BUSY);
+			p->cpt = 1;
+		}
 	}
 	p->lastformat = -1;
 	p->lastinput = -1;
@@ -338,6 +356,7 @@
 	ast->tech_pvt = NULL;
 	ast_setstate(ast, AST_STATE_DOWN);
 	restart_monitor();
+	p->flash = 0;  /* we're hanging up so we won't be flashed anymore */
 	return 0;
 }
 
@@ -447,12 +466,11 @@
 	p->fr.offset = 0;
 	p->fr.mallocd=0;
 	p->fr.delivery = ast_tv(0,0);
-	
 	phonee.bytes = ioctl(p->fd, PHONE_EXCEPTION);
+		
 	if (phonee.bits.dtmf_ready)  {
 		if (option_debug)
 			ast_log(LOG_DEBUG, "phone_exception(): DTMF\n");
-	
 		/* We've got a digit -- Just handle this nicely and easily */
 		digit =  ioctl(p->fd, PHONE_GET_DTMF_ASCII);
 		p->fr.subclass = digit;
@@ -482,12 +500,57 @@
 	}
 #if 1
 	if (phonee.bits.pstn_ring)
-		ast_verbose("Unit is ringing\n");
+		//ast_verbose("Unit is ringing\n");
 	if (phonee.bits.caller_id) {
 		ast_verbose("We have caller ID\n");
 	}
 	if (phonee.bits.pstn_wink)
 		ast_verbose("Detected Wink\n");
+	if (phonee.bits.f0)  //filter 0
+		ast_verbose("Detected f0\n");
+	if (phonee.bits.f1)  //filter 1
+		ast_verbose("Detected f1\n");
+	if (phonee.bits.f2)  //filter 2
+		ast_verbose("Detected f2\n");
+	if (phonee.bits.f3)  //filter 3
+		ast_verbose("Detected f3\n");
+		
+	if (phonee.bits.fc0) { //filter cadence 0
+		//aparently one must reset this everytime it's detected
+		if (ioctl(p->fd, IXJCTL_FILTER_CADENCE, &busy) == -1)
+			ast_log(LOG_ERROR, "IXJCTL_FILTER_CADENCE faild\n");                        
+		if (p->flash) {
+			if (option_debug)
+				ast_log(LOG_DEBUG, "busy signal detected- we're flashed so ignore.\n");
+		} else {
+			if (option_debug)
+				ast_log(LOG_DEBUG, "busy signal detected- hang up.\n");
+			//p->fr.frametype = AST_FRAME_CONTROL;
+			//p->fr.subclass = AST_CONTROL_HANGUP;
+			//return &p->fr;
+			return 0;
+		}
+	}
+	if (phonee.bits.fc1) { //filter cadnece 1
+		//aparently one must reset this everytime it's detected
+		if (ioctl(p->fd, IXJCTL_FILTER_CADENCE, &reorder) == -1)
+			ast_log(LOG_ERROR, "IXJCTL_FILTER_CADENCE faild\n");                        
+		if (p->flash) {
+			if (option_debug)
+				ast_log(LOG_DEBUG, "reorder signal detected- we're flashed so ignore.\n");
+		} else {
+			if (option_debug)
+				ast_log(LOG_DEBUG, "reorder signal detected- hang up.\n");
+			//p->fr.frametype = AST_FRAME_CONTROL;
+			//p->fr.subclass = AST_CONTROL_HANGUP;
+			//return &p->fr;
+			return 0;
+		}
+	}
+	if (phonee.bits.fc2)  //filter cadence 2
+		ast_verbose("Detected fc2\n");
+	if (phonee.bits.fc3)  //filter cadence 3
+		ast_verbose("Detected fc3\n");
 #endif
 	/* Strange -- nothing there.. */
 	p->fr.frametype = AST_FRAME_NULL;
@@ -772,10 +835,14 @@
 	return 0;
 }
 
+/*******************************************************************************
+
+*******************************************************************************/
 static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *context)
 {
 	struct ast_channel *tmp;
 	struct phone_codec_data codec;
+
 	tmp = ast_channel_alloc(1);
 	if (tmp) {
 		tmp->tech = cur_tech;
@@ -788,13 +855,11 @@
 			if (codec.type == LINEAR16)
 				tmp->nativeformats =
 				tmp->rawreadformat =
-				tmp->rawwriteformat =
-				AST_FORMAT_SLINEAR;
+				tmp->rawwriteformat = AST_FORMAT_SLINEAR;
 			else {
 				tmp->nativeformats =
 				tmp->rawreadformat =
-				tmp->rawwriteformat =
-				prefformat & ~AST_FORMAT_SLINEAR;
+				tmp->rawwriteformat = prefformat & ~AST_FORMAT_SLINEAR;
 			}
 		}
 		else {
@@ -837,28 +902,38 @@
 	return tmp;
 }
 
+/*******************************************************************************
+This function is called by do_monitor whenever there's activity (select) on a 
+file descriptor associated with an interface. Since the interface just started 
+doing something this "packet" is probably bungie.
+*******************************************************************************/
 static void phone_mini_packet(struct phone_pvt *i)
 {
 	int res;
 	char buf[1024];
 	/* Ignore stuff we read... */
 	res = read(i->fd, buf, sizeof(buf));
-	if (res < 1) {
+	if (res < 0
+	
+	) {
 		ast_log(LOG_WARNING, "Read returned %d: %s\n", res, strerror(errno));
 		return;
 	}
 }
 
+/*******************************************************************************
+This function is called by do_monitor whenever there's activity (select) on a
+file descriptor associated with an interface. First we poll for exceptions and
+then we take action on many of them.
+*******************************************************************************/
 static void phone_check_exception(struct phone_pvt *i)
 {
 	int offhook=0;
 	char digit[2] = {0 , 0};
 	union telephony_exception phonee;
-	/* XXX Do something XXX */
-#if 0
-	ast_log(LOG_DEBUG, "Exception!\n");
-#endif
+	
 	phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION);
+	ast_log(LOG_DEBUG, "Exception %d \n", phonee.bytes);
 	if (phonee.bits.dtmf_ready)  {
 		digit[0] = ioctl(i->fd, PHONE_GET_DTMF_ASCII);
 		if (i->mode == MODE_DIALTONE || i->mode == MODE_FXS) {
@@ -934,7 +1009,8 @@
 		}
 	}
 	if (phonee.bits.pstn_ring) {
-		ast_verbose("Unit is ringing\n");
+		if (option_debug)
+			ast_verbose("Unit is ringing\n");
 		phone_new(i, AST_STATE_RING, i->context);
 	}
 	if (phonee.bits.caller_id)
@@ -943,6 +1019,15 @@
 	
 }
 
+/*******************************************************************************
+This thread monitors all interfaces which are not yet in use (and thus do not 
+have a separate thread) indefinitely. We begin by making our thread "killable"
+and then enter an infinate loop. The while loop spins through the interface list 
+looking for interfaces that are not owned (in use?) and putting "FD_SETs" on
+their file descriptors. Now we block for something to happen. When it does we
+spin through the interfaces (that arn't owned) and call phone_mini_packet
+and then phone_check_exception for those that had some activity and then loop.
+*******************************************************************************/
 static void *do_monitor(void *data)
 {
 	fd_set rfds, efds;
@@ -952,8 +1037,7 @@
 	/* The tone we're playing this round */
 	struct timeval tv = {0,0};
 	int dotone;
-	/* This thread monitors all the frame relay interfaces which are not yet in use
-	   (and thus do not have a separate thread) indefinitely */
+	
 	/* From here on out, we die whenever asked */
 	if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
 		ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
@@ -1060,7 +1144,10 @@
 	return NULL;
 	
 }
-
+/*******************************************************************************
+This function is called by load_module and creates the thread associated with
+the monitor loop in do_monitor.
+*******************************************************************************/
 static int restart_monitor()
 {
 	/* If we're supposed to be stopped -- stay stopped */
@@ -1119,16 +1206,31 @@
 				 if (mode != MODE_FXS)
 				      ast_log(LOG_DEBUG, "Unable to set port to POTS\n");
 		}
-		ioctl(tmp->fd, PHONE_PLAY_STOP);
-		ioctl(tmp->fd, PHONE_REC_STOP);
-		ioctl(tmp->fd, PHONE_RING_STOP);
-		ioctl(tmp->fd, PHONE_CPT_STOP);
+		//ioctl(tmp->fd, IXJCTL_DSP_RESET);
+		//ioctl(tmp->fd, PHONE_PLAY_STOP);
+		//ioctl(tmp->fd, PHONE_REC_STOP);
+		//ioctl(tmp->fd, PHONE_RING_STOP);
+		//ioctl(tmp->fd, PHONE_CPT_STOP);
 		if (ioctl(tmp->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK)) 
 			ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",iface, strerror(errno));
 		if (echocancel != AEC_OFF)
 			ioctl(tmp->fd, IXJCTL_AEC_START, echocancel);
 		if (silencesupression) 
 			tmp->silencesupression = 1;
+                //set filters
+		if (busyfilter.enable)
+			if (ioctl(tmp->fd, IXJCTL_SET_FILTER, &busyfilter) == -1)
+				ast_log(LOG_ERROR, "busy: IXJCTL_SET_FILTER faild\n");                        
+		if (reorderfilter.enable)
+			if (ioctl(tmp->fd, IXJCTL_SET_FILTER, &reorderfilter) == -1)
+				ast_log(LOG_ERROR, "reorder: IXJCTL_SET_FILTER faild\n");                   
+		//set cadences
+		if (busy.enable)
+			if (ioctl(tmp->fd, IXJCTL_FILTER_CADENCE, &busy) == -1)
+				ast_log(LOG_ERROR, "busy: IXJCTL_FILTER_CADENCE faild\n");                        
+		if (reorder.enable)
+			if (ioctl(tmp->fd, IXJCTL_FILTER_CADENCE, &reorder) == -1)
+				ast_log(LOG_ERROR, "reorder: IXJCTL_FILTER_CADENCE faild\n");                        
 #ifdef PHONE_VAD
 		ioctl(tmp->fd, PHONE_VAD, tmp->silencesupression);
 #endif
@@ -1279,6 +1381,13 @@
 	return __unload_module();
 }
 
+/*******************************************************************************
+ This is the first function called after the module is loaded. It calles mkif
+ which initialized the card and populates phone_pvt. It parses the 
+ phone.conf file, sets a bunch of globals, and calls ast_channel_register with 
+ an ast_channel_tech based either on phone_tech_fxo or phone_tech_fxs. Lastly
+ it calls restart monitor (for the first time).
+*******************************************************************************/
 int load_module()
 {
 	struct ast_config *cfg;
@@ -1286,9 +1395,9 @@
 	struct phone_pvt *tmp;
 	int mode = MODE_IMMEDIATE;
 	int txgain = DEFAULT_GAIN, rxgain = DEFAULT_GAIN; /* default gain 1.0 */
+	
 	cfg = ast_config_load(config);
-
-	/* We *must* have a config file otherwise stop immediately */
+        	/* We *must* have a config file otherwise stop immediately */
 	if (!cfg) {
 		ast_log(LOG_ERROR, "Unable to load config %s\n", config);
 		return -1;
@@ -1316,6 +1425,46 @@
 				}
 		} else if (!strcasecmp(v->name, "silencesupression")) {
 			silencesupression = ast_true(v->value);
+			
+                } else if (!strcasecmp(v->name, "busyfilter")) {
+			busyfilter.filter = 0; 
+                        busyfilter.freq = atoi(v->value); /* the freq (or range) */
+			busyfilter.enable = 1;
+		} else if (!strcasecmp(v->name, "busyon1")) {
+			busy.enable = 1; /* the patern of busy */
+			busy.en_filter = 0;
+			busy.filter = 0; 
+			busy.on1 = atoi(v->value);
+		} else if (!strcasecmp(v->name, "busyoff1")) {
+			busy.off1 = atoi(v->value);
+		} else if (!strcasecmp(v->name, "busyon2")) {
+			busy.on2 = atoi(v->value);
+		} else if (!strcasecmp(v->name, "busyoff2")) {
+			busy.off2 = atoi(v->value);
+		} else if (!strcasecmp(v->name, "busyon3")) {
+			busy.on3 = atoi(v->value);
+		} else if (!strcasecmp(v->name, "busyoff3")) {
+			busy.off3 = atoi(v->value);
+		} else if (!strcasecmp(v->name, "reorderfilter")) {
+			reorderfilter.filter = 1; 
+                        reorderfilter.freq = atoi(v->value); /* the freq (or range) */
+			reorderfilter.enable = 1;
+		} else if (!strcasecmp(v->name, "reorderon1")) {
+			reorder.enable = 1; /* the pattern of reorder */
+			reorder.en_filter = 0;
+			reorder.filter = 1;
+			reorder.on1 = atoi(v->value);
+		} else if (!strcasecmp(v->name, "reorderoff1")) {
+			reorder.off1 = atoi(v->value);
+		} else if (!strcasecmp(v->name, "reorderon2")) {
+			reorder.on2 = atoi(v->value);
+		} else if (!strcasecmp(v->name, "reorderoff2")) {
+			reorder.off2 = atoi(v->value);
+		} else if (!strcasecmp(v->name, "reorderon3")) {
+			reorder.on3 = atoi(v->value);
+		} else if (!strcasecmp(v->name, "reorderoff3")) {
+			reorder.off3 = atoi(v->value);
+	
 		} else if (!strcasecmp(v->name, "language")) {
 			strncpy(language, v->value, sizeof(language)-1);
 		} else if (!strcasecmp(v->name, "callerid")) {
@@ -1366,11 +1515,10 @@
 	}
 	ast_mutex_unlock(&iflock);
 
-	if (mode == MODE_FXS) {
-		phone_tech_fxs.capabilities = prefformat;
+	if (mode == MODE_FXS)
 		cur_tech = &phone_tech_fxs;
-	} else
-		cur_tech = (struct ast_channel_tech *) &phone_tech;
+	else
+		cur_tech = (struct ast_channel_tech *) &phone_tech_fxo;
 
 	/* Make sure we can register our Adtranphone channel type */
 
