[asterisk-commits] pkiefer: trunk r375150 - in /trunk: apps/ configs/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Oct 17 14:02:52 CDT 2012


Author: pkiefer
Date: Wed Oct 17 14:02:46 2012
New Revision: 375150

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=375150
Log:
Adds new formats to app_alarmreceiver, ALAW calls support and enhanced protection.

Commiting this on behalf of Kaloyan Kovachev (license 5506).
AlarmReceiver now supports the following DTMF signaling types: 
 - ContactId
 - 4x1
 - 4x2 
 - High Speed 
 - Super Fast
We are also auto-detecting which signaling is being received. So support for
those protocols should work out-the-box. Correctly identify ALAW / ULAW calls.
Some enhanced protection for broken panels and malicious callers where added.

Review: https://reviewboard.asterisk.org/r/2088/

Modified:
    trunk/apps/app_alarmreceiver.c
    trunk/configs/alarmreceiver.conf.sample

Modified: trunk/apps/app_alarmreceiver.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_alarmreceiver.c?view=diff&rev=375150&r1=375149&r2=375150
==============================================================================
--- trunk/apps/app_alarmreceiver.c (original)
+++ trunk/apps/app_alarmreceiver.c Wed Oct 17 14:02:46 2012
@@ -34,7 +34,7 @@
  * \addtogroup configuration_file Configuration Files
  */
 
-/*! 
+/*!
  * \page alarmreceiver.conf alarmreceiver.conf
  * \verbinclude alarmreceiver.conf.sample
  */
@@ -67,9 +67,65 @@
 #include "asterisk/indications.h"
 
 #define ALMRCV_CONFIG "alarmreceiver.conf"
+#define UNKNOWN_FORMAT "UNKNOWN_FORMAT"
+
 #define ADEMCO_CONTACT_ID "ADEMCO_CONTACT_ID"
+/*
+	AAAA _ID_ P CCC XX ZZZ S
+
+where AAAA is the account number, _ID_ is 18 or 98, P is the pin status (alarm or restore), CCC
+is the alarm code which is pre-defined by Ademco (but you may be able to reprogram it in the panel), XX
+is the dialer group, partition or area number, ZZZ is the zone or user number and S is the checksum
+*/
+
+#define ADEMCO_EXPRESS_4_1 "ADEMCO_EXPRESS_4_1"
+/*
+	AAAA _ID_ C S
+
+where AAAA is the account number, _ID_ is 17, C is the alarm code and S is the checksum.
+*/
+
+#define ADEMCO_EXPRESS_4_2 "ADEMCO_EXPRESS_4_2"
+/*
+	AAAA _ID_ C Z S
+
+where AAAA is the account number, _ID_ is 27, C is the alarm code, Z is the zone or user number and S is the checksum.
+*/
+
+#define ADEMCO_HIGH_SPEED "ADEMCO_HIGH_SPEED"
+/*
+	AAAA _ID_ PPPP PPPP X S
+
+where AAAA is the account number, _ID_ is 55, PPPP PPPP is the status of each zone, X
+is a special digit which describes the type of information in the PPPP PPPP fields and S is checksum.
+Each P field contains one of the following values:
+        1  new alarm           3  new restore           5  normal
+        2  new opening         4  new closing           6  outstanding
+The X field contains one of the following values:
+        0  AlarmNet messages
+        1  ambush or duress
+        2  opening by user (the first P field contains the user number)
+        3  bypass (the P fields indicate which zones are bypassed)
+        4  closing by user (the first P field contain the user number)
+        5  trouble (the P fields contain which zones are in trouble)
+        6  system trouble
+        7  normal message (the P fields indicate zone status)
+        8  low battery (the P fields indicate zone status)
+        9  test (the P fields indicate zone status)
+*/
+#define ADEMCO_SUPER_FAST "ADEMCO_SUPER_FAST"
+/*
+	AAAA _ID_ PPPP PPPP X
+where AAA is the account number, _ID_ is 56
+*/
+
 #define ADEMCO_MSG_TYPE_1 "18"
 #define ADEMCO_MSG_TYPE_2 "98"
+#define ADEMCO_MSG_TYPE_3 "17"
+#define ADEMCO_MSG_TYPE_4 "27"
+#define ADEMCO_MSG_TYPE_5 "55"
+#define ADEMCO_MSG_TYPE_6 "56"
+
 #define ADEMCO_AUDIO_CALL_NEXT "606"
 
 struct {
@@ -85,6 +141,8 @@
 };
 
 typedef struct event_node event_node_t;
+
+struct timeval call_start_time;
 
 static const char app[] = "AlarmReceiver";
 /*** DOCUMENTATION
@@ -101,8 +159,20 @@
 			events to the standard input of the application.
 			The configuration file also contains settings for DTMF timing, and for the loudness of the
 			acknowledgement tones.</para>
-			<note><para>Only 1 signalling format is supported at this time: Ademco Contact ID.</para></note>
+			<note><para>Few Ademco DTMF signalling formats are detected automaticaly: Contact ID, Express 4+1,
+			Express 4+2, High Speed and Super Fast.</para></note>
 		</description>
+		<para>The application is affected by the following variables:</para>
+		<variablelist>
+			<variable name="ALARMRECEIVER_CALL_LIMIT">
+				<para>Maximum call time, in milliseconds.</para>
+				<para>If set, this variable causes application to exit after the specified time.</para>
+			</variable>
+			<variable name="ALARMRECEIVER_RETRIES_LIMIT">
+				<para>Maximum number of retries per call.</para>
+				<para>If set, this variable causes application to exit after the specified number of messages.</para>
+			</variable>
+		</variablelist>
 		<see-also>
 			<ref type="filename">alarmreceiver.conf</ref>
 		</see-also>
@@ -112,8 +182,10 @@
 /* Config Variables */
 static int fdtimeout = 2000;
 static int sdtimeout = 200;
+static int answait = 1250;
 static int toneloudness = 4096;
 static int log_individual_events = 0;
+static int no_group_meta = 0;
 static char event_spool_dir[128] = {'\0'};
 static char event_app[128] = {'\0'};
 static char db_family[128] = {'\0'};
@@ -172,26 +244,24 @@
  * \param chan Asterisk Channel
  * \param digit_string Digits String
  * \param buf_size The size of the Digits String buffer
- * \param length Length of the message we expect
- * \param fdto First Digit Timeout
- * \param sdto Other Digits Timeout
+ * \param expected Digits expected for this message type
+ * \param received Pointer to number of digits received so far
  *
  * \retval 0 if all digits were successfully received
  * \retval 1 if a timeout occurred
  * \retval -1 if the caller hung up or on channel errors
  */
-static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int buf_size, int length, int fdto, int sdto)
+static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int buf_size, int expected, int *received)
 {
 	int rtn = 0;
-	int i = 0;
 	int r;
 	struct ast_frame *f;
 	struct timeval lastdigittime;
 
 	lastdigittime = ast_tvnow();
-	while (i < length && i < buf_size - 1) {
+	while (*received < expected && *received < buf_size - 1) {
 		/* If timed out, leave */
-		if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((i > 0) ? sdto : fdto)) {
+		if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((*received > 0) ? sdtimeout : fdtimeout)) {
 			ast_verb(4, "AlarmReceiver: DTMF Digit Timeout on %s\n", ast_channel_name(chan));
 			ast_debug(1, "AlarmReceiver: DTMF timeout on chan %s\n", ast_channel_name(chan));
 			rtn = 1;
@@ -226,14 +296,15 @@
 		}
 
 		/* Save digit */
-		digit_string[i++] = f->subclass.integer;
+		digit_string[(*received)++] = f->subclass.integer;
 		ast_frfree(f);
 
 		lastdigittime = ast_tvnow();
 	}
 
-	/* Null terminate the end of the digit string */
-	digit_string[i] = '\0';
+	/* Null terminate the end of the digit_string */
+	digit_string[*received] = '\0';
+
 	return rtn;
 }
 
@@ -243,11 +314,12 @@
  * \param logfile Log File Pointer
  * \param signalling_type Signaling Type
  * \param chan Asterisk Channel
+ * \param no_checksum Expecting messages without checksum
  *
  * \retval 0 success
  * \retval -1 failure
  */
-static int write_metadata(FILE *logfile, char *signalling_type, struct ast_channel *chan)
+static int write_metadata(FILE *logfile, char *signalling_type, struct ast_channel *chan, int no_checksum)
 {
 	struct timeval t;
 	struct ast_tm now;
@@ -276,18 +348,27 @@
 	/* Format the time */
 	ast_strftime(timestamp, sizeof(timestamp), time_stamp_format, &now);
 
-	if (fprintf(logfile, "\n\n[metadata]\n\n"
+	if (no_group_meta && fprintf(logfile, "PROTOCOL=%s\n"
+			"CHECKSUM=%s\n"
+			"CALLINGFROM=%s\n"
+			"CALLERNAME=%s\n"
+			"TIMESTAMP=%s\n\n",
+			signalling_type, (!no_checksum) ? "yes" : "no", cl, cn, timestamp) > -1) {
+		return 0;
+	} else if (fprintf(logfile, "\n\n[metadata]\n\n"
 			"PROTOCOL=%s\n"
+			"CHECKSUM=%s\n"
 			"CALLINGFROM=%s\n"
 			"CALLERNAME=%s\n"
 			"TIMESTAMP=%s\n\n"
-			"[events]\n\n", signalling_type, cl, cn, timestamp) < 0) {
-		ast_verb(3, "AlarmReceiver: can't write metadata\n");
-		ast_debug(1, "AlarmReceiver: can't write metadata\n");
-		return -1;
-	}
-
-	return 0;
+			"[events]\n\n",
+			signalling_type, (!no_checksum) ? "yes" : "no", cl, cn, timestamp) > -1) {
+		return 0;
+	}
+
+	ast_verb(3, "AlarmReceiver: can't write metadata\n");
+	ast_debug(1, "AlarmReceiver: can't write metadata\n");
+	return -1;
 }
 
 /*!
@@ -301,23 +382,25 @@
  */
 static int write_event(FILE *logfile, event_node_t *event)
 {
-	if (fprintf(logfile, "%s\n", event->data) < 0) {
+	if (fprintf(logfile, "%s%s\n", no_group_meta ? "event=" : "", event->data) < 0) {
 		return -1;
 	}
+
 	return 0;
 }
 
 /*!
- * \brief Log events if configuration key logindividualevents is enabled
+ * \brief Log events if configuration key logindividualevents is enabled or on exit
  *
  * \param chan Asterisk Channel
  * \param signalling_type Signaling Type
  * \param event Event Structure
+ * \param no_checksum Expecting messages without checksum
  *
  * \retval 0 success
  * \retval -1 failure
  */
-static int log_events(struct ast_channel *chan, char *signalling_type, event_node_t *event)
+static int log_events(struct ast_channel *chan, char *signalling_type, event_node_t *event, int no_checksum)
 {
 	char workstring[sizeof(event_spool_dir) + sizeof(event_file)] = "";
 	int fd;
@@ -344,13 +427,13 @@
 		}
 
 		/* Write the file */
-		if (write_metadata(logfile, signalling_type, chan) != 0) {
+		if (write_metadata(logfile, signalling_type, chan, no_checksum)) {
 			fflush(logfile);
 			fclose(logfile);
 			return -1;
 		}
 
-		while ((write_event(logfile, elp) > 0) && (elp != NULL)) {
+		while ((elp != NULL) && (write_event(logfile, elp) == 0)) {
 			elp = elp->next;
 		}
 
@@ -406,19 +489,18 @@
  * \param chan Asterisk Channel
  * \param tone_freq Frequency of the tone to send
  * \param tone_duration Tone duration in ms
- * \param tldn Tone loudness
  * \param delay Delay before sending the tone
  *
  * \retval 0 success
  * \retval -1 failure
  */
-static int send_tone_burst(struct ast_channel *chan, const char *tone_freq, int tone_duration, int tldn, int delay)
+static int send_tone_burst(struct ast_channel *chan, const char *tone_freq, int tone_duration, int delay)
 {
 	if (delay && ast_safe_sleep(chan, delay)) {
 		return -1;
 	}
 
-	if (ast_playtones_start(chan, tldn, tone_freq, 0)) {
+	if (ast_playtones_start(chan, toneloudness, tone_freq, 0)) {
 		return -1;
 	}
 
@@ -431,26 +513,113 @@
 }
 
 /*!
- * \brief Receive Ademco ContactID Data String
+ * \brief Check if the message is in known and valid Ademco format
+ *
+ * \param signalling_type Expected signalling type for the message
+ * \param event event received
+ *
+ * \retval 0 The event is valid
+ * \retval -1 The event is not valid
+ */
+static int ademco_check_valid(char *signalling_type, char *event)
+{
+	if (!strcmp(signalling_type, UNKNOWN_FORMAT)) {
+		return 1;
+	}
+
+	if (!strcmp(signalling_type, ADEMCO_CONTACT_ID)
+		&& strncmp(event + 4, ADEMCO_MSG_TYPE_1, 2)
+		&& strncmp(event + 4, ADEMCO_MSG_TYPE_2, 2)) {
+		return -1;
+	}
+
+	if (!strcmp(signalling_type, ADEMCO_EXPRESS_4_1) && strncmp(event + 4, ADEMCO_MSG_TYPE_3, 2)) {
+		return -1;
+	}
+
+	if (!strcmp(signalling_type, ADEMCO_EXPRESS_4_2) && strncmp(event + 4, ADEMCO_MSG_TYPE_4, 2)) {
+		return -1;
+	}
+
+	if (!strcmp(signalling_type, ADEMCO_HIGH_SPEED) && strncmp(event + 4, ADEMCO_MSG_TYPE_5, 2)) {
+		return -1;
+	}
+
+	if (!strcmp(signalling_type, ADEMCO_SUPER_FAST) && strncmp(event + 4, ADEMCO_MSG_TYPE_6, 2)) {
+		return -1;
+	}
+
+	return 0;
+}
+
+/*!
+ * \brief Detect the message format of an event
+ *
+ * \param signalling_type Expected signalling type for the message
+ * \param event event received
+ * \param no_checksum Should we calculate checksum for the message
+ *
+ * \returns The expected digits for the detected event type
+ */
+static int ademco_detect_format(char *signalling_type, char *event, int *no_checksum)
+{
+	int res = 16;
+
+	if (!strncmp(event + 4, ADEMCO_MSG_TYPE_1, 2)
+		|| !strncmp(event + 4, ADEMCO_MSG_TYPE_2, 2)) {
+		sprintf(signalling_type, "%s", ADEMCO_CONTACT_ID);
+	}
+
+	if (!strncmp(event + 4, ADEMCO_MSG_TYPE_3, 2)) {
+		sprintf(signalling_type, "%s", ADEMCO_EXPRESS_4_1);
+		res = 8;
+	}
+
+	if (!strncmp(event + 4, ADEMCO_MSG_TYPE_4, 2)) {
+		sprintf(signalling_type, "%s", ADEMCO_EXPRESS_4_2);
+		res = 9;
+	}
+
+	if (!strncmp(event + 4, ADEMCO_MSG_TYPE_5, 2)) {
+		sprintf(signalling_type, "%s", ADEMCO_HIGH_SPEED);
+	}
+
+	if (!strncmp(event + 4, ADEMCO_MSG_TYPE_6, 2)) {
+		sprintf(signalling_type, "%s", ADEMCO_SUPER_FAST);
+		*no_checksum = 1;
+		res = 15;
+	}
+
+	if (strcmp(signalling_type, UNKNOWN_FORMAT)) {
+		ast_verb(4, "AlarmMonitoring: Detected format %s.\n", signalling_type);
+		ast_debug(1, "AlarmMonitoring: Autodetected format %s.\n", signalling_type);
+	}
+
+	return res;
+}
+
+/*!
+ * \brief Receive Ademco ContactID or other format Data String
  *
  * \param chan Asterisk Channel
- * \param fdto First Digit Timeout
- * \param sdto Other Digits Timeout
- * \param tldn Tone loudness
  * \param ehead Pointer to events list
+ * \param signalling_type Expected signalling type for the message
+ * \param no_checksum Should we calculate checksum for the message
  *
  * \retval 0 success
  * \retval -1 failure
  */
-static int receive_ademco_contact_id(struct ast_channel *chan, int fdto, int sdto, int tldn, event_node_t **ehead)
+static int receive_ademco_event(struct ast_channel *chan, event_node_t **ehead, char *signalling_type, int *no_checksum)
 {
 	int res = 0;
-	int exit_on_next = 0;
+	const char *limit;
 	char event[17];
 	event_node_t *enew, *elp;
 	int got_some_digits = 0;
 	int events_received = 0;
 	int ack_retries = 0;
+	int limit_retries = 0;
+	int expected_length = sizeof(event) - 1;
 
 	database_increment("calls-received");
 
@@ -458,43 +627,90 @@
 	ast_verb(4, "AlarmReceiver: Waiting for first event from panel...\n");
 
 	while (res >= 0) {
+		int digits_received = 0;
+
 		res = 0;
+
+		if (log_individual_events) {
+			sprintf(signalling_type, "%s", UNKNOWN_FORMAT);
+			expected_length = 16;
+			*no_checksum = 0;
+		}
+
 		if (got_some_digits == 0) {
 			/* Send ACK tone sequence */
 			ast_verb(4, "AlarmReceiver: Sending 1400Hz 100ms burst (ACK)\n");
-			res = send_tone_burst(chan, "1400", 100, tldn, 0);
+			res = send_tone_burst(chan, "1400", 100, 0);
 			if (!res) {
 				ast_verb(4, "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n");
-				res = send_tone_burst(chan, "2300", 100, tldn, 100);
+				res = send_tone_burst(chan, "2300", 100, 100);
 			}
 		}
 		if (res) {
 			return -1;
 		}
 
-		if (exit_on_next) {
-			res = send_tone_burst(chan, "1400", 900, tldn, 200);
-			return 0;
-		}
-
-		res = receive_dtmf_digits(chan, event, sizeof(event), sizeof(event) - 1, fdto, sdto);
+		res = receive_dtmf_digits(chan, event, sizeof(event), expected_length, &digits_received);
 		if (res < 0) {
 			if (events_received == 0) {
 				/* Hangup with no events received should be logged in the DB */
 				database_increment("no-events-received");
+				ast_verb(4, "AlarmReceiver: No events received!\n");
 			} else {
 				if (ack_retries) {
+					database_increment("ack-retries");
 					ast_verb(4, "AlarmReceiver: ACK retries during this call: %d\n", ack_retries);
-					database_increment("ack-retries");
 				}
 			}
 			ast_verb(4, "AlarmReceiver: App exiting...\n");
 			break;
 		}
 
+		if (!strcmp(signalling_type, UNKNOWN_FORMAT) && digits_received > 5) {
+			expected_length = ademco_detect_format(signalling_type, event, no_checksum);
+
+			if (res > 0) {
+				if (digits_received == expected_length) {
+					res = limit_retries = 0;
+				} else if (digits_received == expected_length - 1
+					&& (!strcmp(signalling_type, ADEMCO_EXPRESS_4_2)
+					|| !strcmp(signalling_type, ADEMCO_EXPRESS_4_1))) {
+					/* ADEMCO EXPRESS without checksum */
+					res = limit_retries = 0;
+					expected_length--;
+					*no_checksum = 1;
+					ast_verb(4, "AlarmMonitoring: Skipping checksum for format %s.\n", signalling_type);
+					ast_debug(1, "AlarmMonitoring: Skipping checksum for format %s.\n", signalling_type);
+				}
+			}
+		}
+
+		ast_channel_lock(chan);
+		limit = pbx_builtin_getvar_helper(chan, "ALARMRECEIVER_CALL_LIMIT");
+		if (!ast_strlen_zero(limit)) {
+			if (ast_tvdiff_ms(ast_tvnow(), call_start_time) > atoi(limit)) {
+				ast_channel_unlock(chan);
+				return -1;
+			}
+		}
+		limit = pbx_builtin_getvar_helper(chan, "ALARMRECEIVER_RETRIES_LIMIT");
+		ast_channel_unlock(chan);
+		if (!ast_strlen_zero(limit)) {
+			if (limit_retries + 1 >= atoi(limit)) {
+				return -1;
+			}
+		}
+
 		if (res) {
 			/* Didn't get all of the digits */
 			ast_verb(2, "AlarmReceiver: Incomplete string: %s, trying again...\n", event);
+			limit_retries++;
+
+			if (!events_received && strcmp(signalling_type, UNKNOWN_FORMAT))
+			{
+				sprintf(signalling_type, "%s", UNKNOWN_FORMAT);
+				expected_length = sizeof(event) - 1;
+			}
 
 			if (!got_some_digits) {
 				got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0;
@@ -509,7 +725,7 @@
 		ast_debug(1, "AlarmReceiver: Received event: %s\n", event);
 
 		/* Calculate checksum */
-		if (ademco_verify_checksum(event, 16)) {
+		if (!(*no_checksum) && ademco_verify_checksum(event, expected_length)) {
 			database_increment("checksum-errors");
 			ast_verb(2, "AlarmReceiver: Nonzero checksum\n");
 			ast_debug(1, "AlarmReceiver: Nonzero checksum\n");
@@ -517,13 +733,11 @@
 		}
 
 		/* Check the message type for correctness */
-		if (strncmp(event + 4, ADEMCO_MSG_TYPE_1, 2)) {
-			if (strncmp(event + 4, ADEMCO_MSG_TYPE_2, 2)) {
-				database_increment("format-errors");
-				ast_verb(2, "AlarmReceiver: Wrong message type\n");
-				ast_debug(1, "AlarmReceiver: Wrong message type\n");
+		if (ademco_check_valid(signalling_type, event)) {
+			database_increment("format-errors");
+			ast_verb(2, "AlarmReceiver: Wrong message type\n");
+			ast_debug(1, "AlarmReceiver: Wrong message type\n");
 			continue;
-			}
 		}
 
 		events_received++;
@@ -546,24 +760,21 @@
 			elp->next = enew;
 		}
 
-		/* Audio call follows, exit alarm receiver app */
-		if (!strncmp(event + 7, ADEMCO_AUDIO_CALL_NEXT, 3)) {
+		/* Let the user have the option of logging the single event before sending the kissoff tone */
+		if (log_individual_events && log_events(chan, signalling_type, enew, *no_checksum)) {
+			return -1;
+		}
+
+		/* Send the kissoff tone (1400 Hz, 900 ms, after 200ms delay) */
+		if (send_tone_burst(chan, "1400", 900, 200)) {
+			return -1;
+		}
+
+		/* If audio call follows, exit alarm receiver app */
+		if (!strcmp(signalling_type, ADEMCO_CONTACT_ID)
+			&& !strncmp(event + 7, ADEMCO_AUDIO_CALL_NEXT, 3)) {
 			ast_verb(4, "AlarmReceiver: App exiting... Audio call next!\n");
-			exit_on_next = 1;
-		}
-
-		/* Let the user have the option of logging the single event before sending the kissoff tone */
-		if (log_individual_events) {
-			res = log_events(chan, ADEMCO_CONTACT_ID, enew);
-			if (res) {
-				return -1;
-			}
-		}
-
-		/* Send the kissoff tone (1400 Hz, 900 ms, after 200ms delay) */
-		res = send_tone_burst(chan, "1400", 900, tldn, 200);
-		if (res) {
-			return -1;
+			return 0;
 		}
 	}
 
@@ -582,53 +793,53 @@
 static int alarmreceiver_exec(struct ast_channel *chan, const char *data)
 {
 	int res = 0;
+	int no_checksum = 0;
 	event_node_t *elp, *efree;
 	char signalling_type[64] = "";
 	event_node_t *event_head = NULL;
 
-	/* Set write and read formats to ULAW */
-	ast_verb(4, "AlarmReceiver: Setting read and write formats to ULAW\n");
-
-	if (ast_set_write_format_by_id(chan,AST_FORMAT_ULAW)) {
-		ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",ast_channel_name(chan));
-		return -1;
-	}
-
-	if (ast_set_read_format_by_id(chan,AST_FORMAT_ULAW)) {
-		ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",ast_channel_name(chan));
-		return -1;
+	if (ast_channel_writeformat(chan)->id != AST_FORMAT_ALAW
+		&& ast_channel_writeformat(chan)->id != AST_FORMAT_ULAW) {
+		ast_verb(4, "AlarmReceiver: Setting write format to Mu-law\n");
+		if (ast_set_write_format_by_id(chan,AST_FORMAT_ULAW)) {
+			ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",ast_channel_name(chan));
+			return -1;
+		}
+	}
+
+	if (ast_channel_readformat(chan)->id != AST_FORMAT_ALAW
+		&& ast_channel_readformat(chan)->id != AST_FORMAT_ULAW) {
+		ast_verb(4, "AlarmReceiver: Setting read format to Mu-law\n");
+		if (ast_set_read_format_by_id(chan,AST_FORMAT_ULAW)) {
+			ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",ast_channel_name(chan));
+			return -1;
+		}
 	}
 
 	/* Set default values for this invocation of the application */
-	ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type));
+	ast_copy_string(signalling_type, UNKNOWN_FORMAT, sizeof(signalling_type));
+	call_start_time = ast_tvnow();
 
 	/* Answer the channel if it is not already */
-	ast_verb(4, "AlarmReceiver: Answering channel\n");
 	if (ast_channel_state(chan) != AST_STATE_UP) {
-		if ((res = ast_answer(chan))) {
+		ast_verb(4, "AlarmReceiver: Answering channel\n");
+		if (ast_answer(chan)) {
 			return -1;
 		}
 	}
 
 	/* Wait for the connection to settle post-answer */
 	ast_verb(4, "AlarmReceiver: Waiting for connection to stabilize\n");
-	res = ast_safe_sleep(chan, 1250);
+	if (ast_safe_sleep(chan, answait)) {
+		return -1;
+	}
 
 	/* Attempt to receive the events */
-	if (!res) {
-		/* Determine the protocol to receive in advance */
-		/* Note: Ademco contact is the only one supported at this time */
-		/* Others may be added later */
-		if (!strcmp(signalling_type, ADEMCO_CONTACT_ID)) {
-			receive_ademco_contact_id(chan, fdtimeout, sdtimeout, toneloudness, &event_head);
-		} else {
-			res = -1;
-		}
-	}
+	receive_ademco_event(chan, &event_head, signalling_type, &no_checksum);
 
 	/* Events queued by receiver, write them all out here if so configured */
-	if ((!res) && (log_individual_events == 0)) {
-		res = log_events(chan, signalling_type, event_head);
+	if (!log_individual_events) {
+		res = log_events(chan, signalling_type, event_head, no_checksum);
 	}
 
 	/* Do we exec a command line at the end? */
@@ -650,14 +861,16 @@
 /*!
  * \brief Load the configuration from the configuration file
  *
+ * \param reload True on reload
+ *
  * \retval 1 success
  * \retval 0 failure
  */
-static int load_config(void)
+static int load_config(int reload)
 {
 	struct ast_config *cfg;
 	const char *value;
-	struct ast_flags config_flags = { 0 };
+	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
 
 	/* Read in the config file */
 	cfg = ast_config_load(ALMRCV_CONFIG, config_flags);
@@ -665,6 +878,8 @@
 	if (!cfg) {
 		ast_verb(4, "AlarmReceiver: No config file\n");
 		return 0;
+	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
+		return 1;
 	} else if (cfg == CONFIG_STATUS_FILEINVALID) {
 		ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n",
 			ALMRCV_CONFIG);
@@ -702,6 +917,19 @@
 		}
 	}
 
+	if ((value = ast_variable_retrieve(cfg, "general", "answait")) != NULL) {
+		answait = atoi(value);
+		if (answait < 500) {
+			answait = 500;
+		} else if (answait > 10000) {
+			answait = 10000;
+		}
+	}
+
+	if ((value = ast_variable_retrieve(cfg, "general", "no_group_meta")) != NULL) {
+		no_group_meta = ast_true(value);
+	}
+
 	if ((value = ast_variable_retrieve(cfg, "general", "logindividualevents")) != NULL) {
 		log_individual_events = ast_true(value);
 	}
@@ -740,20 +968,33 @@
  * Module loading including tests for configuration or dependencies.
  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
+ * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
+ * configuration file or other non-critical problem return
  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
  */
 static int load_module(void)
 {
-	if (load_config()) {
+	if (load_config(0)) {
 		if (ast_register_application_xml(app, alarmreceiver_exec)) {
 			return AST_MODULE_LOAD_FAILURE;
 		}
 		return AST_MODULE_LOAD_SUCCESS;
-	} else {
-		return AST_MODULE_LOAD_DECLINE;
-	}
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Alarm Receiver for Asterisk");
+	}
+
+	return AST_MODULE_LOAD_DECLINE;
+}
+
+static int reload(void)
+{
+	if (load_config(1)) {
+		return AST_MODULE_LOAD_SUCCESS;
+	}
+
+	return AST_MODULE_LOAD_DECLINE;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Alarm Receiver for Asterisk",
+		.load = load_module,
+		.unload = unload_module,
+		.reload = reload,
+);

Modified: trunk/configs/alarmreceiver.conf.sample
URL: http://svnview.digium.com/svn/asterisk/trunk/configs/alarmreceiver.conf.sample?view=diff&rev=375150&r1=375149&r2=375150
==============================================================================
--- trunk/configs/alarmreceiver.conf.sample (original)
+++ trunk/configs/alarmreceiver.conf.sample Wed Oct 17 14:02:46 2012
@@ -60,6 +60,17 @@
 sdtimeout = 200
 
 ;
+; Wait for the connection to settle post-answer. Adjustable from 500 msec. to 10000 msec.
+; The default is 1250 msec.
+;
+
+answait = 1250
+
+; When logging individual events it may be desirable to skip grouping of metadata
+
+;no_group_meta = yes
+
+;
 ; The loudness of the ACK and Kissoff tones is adjustable from 100 to 8192.
 ; The default is 8192. This shouldn't need to be messed with, but is included
 ; just in case there are problems with signal levels.




More information about the asterisk-commits mailing list