Пример #1
0
/*!
 * \brief Receive Ademco ContactID or other format Data String
 *
 * \param chan Asterisk Channel
 * \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_event(struct ast_channel *chan, event_node_t **ehead, char *signalling_type, int *no_checksum)
{
	int res = 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");

	/* Wait for first event */
	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, 0);
			if (!res) {
				ast_verb(4, "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n");
				res = send_tone_burst(chan, "2300", 100, 100);
			}
		}
		if (res) {
			return -1;
		}

		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);
				}
			}
			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;
				ack_retries++;
			}
			continue;
		}

		got_some_digits = 1;

		ast_verb(2, "AlarmReceiver: Received Event %s\n", event);
		ast_debug(1, "AlarmReceiver: Received event: %s\n", event);

		/* Calculate checksum */
		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");
			continue;
		}

		/* Check the message type for correctness */
		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++;

		/* Queue the Event */
		if (!(enew = ast_calloc(1, sizeof(*enew)))) {
			return -1;
		}

		enew->next = NULL;
		ast_copy_string(enew->data, event, sizeof(enew->data));

		/* Insert event onto end of list */
		if (*ehead == NULL) {
			*ehead = enew;
		} else {
			for (elp = *ehead; elp->next != NULL; elp = elp->next) {
				;
			}
			elp->next = enew;
		}

		/* 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");
			return 0;
		}
	}

	return res;
}
Пример #2
0
/*
* This function implements the logic to receive the Ademco contact ID  format.
*
* The function will return 0 when the caller hangs up, else a -1 if there was a problem.
*/
static int receive_ademco_contact_id(struct ast_channel *chan, const void *data, int fdto, int sdto, int tldn, event_node_t **ehead)
{
	int i, j;
	int res = 0;
	int checksum;
	char event[17];
	event_node_t *enew, *elp;
	int got_some_digits = 0;
	int events_received = 0;
	int ack_retries = 0;
	
	static char digit_map[15] = "0123456789*#ABC";
	static unsigned char digit_weights[15] = {10,1,2,3,4,5,6,7,8,9,11,12,13,14,15};

	database_increment("calls-received");

	/* Wait for first event */
	ast_verb(4, "AlarmReceiver: Waiting for first event from panel\n");

	while (res >= 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.0, 100, tldn);
			if (!res)
				res = ast_safe_sleep(chan, 100);
			if (!res) {
				ast_verb(4, "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n");
				res = send_tone_burst(chan, 2300.0, 100, tldn);
			}
		}
		if ( res >= 0)
			res = receive_dtmf_digits(chan, event, sizeof(event) - 1, fdto, sdto);
		if (res < 0) {
			if (events_received == 0) {
				/* Hangup with no events received should be logged in the DB */
				database_increment("no-events-received");
			} else {
				if (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");
			res = -1;
			break;
		}

		if (res != 0) {
			/* Didn't get all of the digits */
			ast_verb(2, "AlarmReceiver: Incomplete string: %s, trying again...\n", event);

			if (!got_some_digits) {
				got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0;
				ack_retries++;
			}
			continue;
		}

		got_some_digits = 1;

		ast_verb(2, "AlarmReceiver: Received Event %s\n", event);
		ast_debug(1, "AlarmReceiver: Received event: %s\n", event);

		/* Calculate checksum */

		for (j = 0, checksum = 0; j < 16; j++) {
			for (i = 0; i < sizeof(digit_map); i++) {
				if (digit_map[i] == event[j])
					break;
			}

			if (i == 16)
				break;

			checksum += digit_weights[i];
		}
		if (i == 16) {
			ast_verb(2, "AlarmReceiver: Bad DTMF character %c, trying again\n", event[j]);
			continue; /* Bad character */
		}

		/* Checksum is mod(15) of the total */

		checksum = checksum % 15;

		if (checksum) {
			database_increment("checksum-errors");
			ast_verb(2, "AlarmReceiver: Nonzero checksum\n");
			ast_debug(1, "AlarmReceiver: Nonzero checksum\n");
			continue;
		}

		/* Check the message type for correctness */

		if (strncmp(event + 4, "18", 2)) {
			if (strncmp(event + 4, "98", 2)) {
				database_increment("format-errors");
				ast_verb(2, "AlarmReceiver: Wrong message type\n");
				ast_debug(1, "AlarmReceiver: Wrong message type\n");
			continue;
			}
		}

		events_received++;

		/* Queue the Event */
		if (!(enew = ast_calloc(1, sizeof(*enew)))) {
			res = -1;
			break;
		}

		enew->next = NULL;
		ast_copy_string(enew->data, event, sizeof(enew->data));

		/*
		* Insert event onto end of list
		*/
		if (*ehead == NULL)
			*ehead = enew;
		else {
			for(elp = *ehead; elp->next != NULL; elp = elp->next)
			;
			elp->next = enew;
		}

		if (res > 0)
			res = 0;

		/* Let the user have the option of logging the single event before sending the kissoff tone */
		if ((res == 0) && (log_individual_events))
			res = log_events(chan, ADEMCO_CONTACT_ID, enew);
		/* Wait 200 msec before sending kissoff */
		if (res == 0)
			res = ast_safe_sleep(chan, 200);

		/* Send the kissoff tone */
		if (res == 0)
			res = send_tone_burst(chan, 1400.0, 900, tldn);
	}

	return res;
}