@ -34,7 +34,7 @@
* \ addtogroup configuration_file Configuration Files
*/
/*!
/*!
* \ page alarmreceiver . conf alarmreceiver . conf
* \ verbinclude alarmreceiver . conf . sample
*/
@ -67,9 +67,65 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
# 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 {
@ -86,6 +142,8 @@ struct event_node{
typedef struct event_node event_node_t ;
struct timeval call_start_time ;
static const char app [ ] = " AlarmReceiver " ;
/*** DOCUMENTATION
< application name = " AlarmReceiver " language = " en_US " >
@ -101,8 +159,20 @@ static const char app[] = "AlarmReceiver";
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 @@ static const char app[] = "AlarmReceiver";
/* 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 @@ static void database_increment(char *key)
* \ 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 ) ? sdt o : fdt o) ) {
if ( ast_tvdiff_ms ( ast_tvnow ( ) , lastdigittime ) > ( ( * rece ived > 0 ) ? sdt ime out : fdt ime out ) ) {
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 @@ static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int
}
/* Save digit */
digit_string [ i+ + ] = f - > subclass . integer ;
digit_string [ ( * rece ived) + + ] = 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 @@ static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int
* \ 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 @@ static int write_metadata(FILE *logfile, char *signalling_type, struct ast_chann
/* 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 ;
" [events] \n \n " ,
signalling_type , ( ! no_checksum ) ? " yes " : " no " , cl , cn , timestamp ) > - 1 ) {
return 0 ;
}
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_metadata(FILE *logfile, char *signalling_type, struct ast_chann
*/
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 @@ static int log_events(struct ast_channel *chan, char *signalling_type, event_nod
}
/* 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 @@ static int ademco_verify_checksum(char *event, int expected)
* \ 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 , t ldn, tone_freq , 0 ) ) {
if ( ast_playtones_start ( chan , t one lou dness , tone_freq , 0 ) ) {
return - 1 ;
}
@ -431,26 +513,113 @@ static int send_tone_burst(struct ast_channel *chan, const char *tone_freq, int
}
/*!
* \ 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 @@ static int receive_ademco_contact_id(struct ast_channel *chan, int fdto, int sdt
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 ) {
ast_verb ( 4 , " AlarmReceiver: ACK retries during this call: %d \n " , 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 ;
@ -509,7 +725,7 @@ static int receive_ademco_contact_id(struct ast_channel *chan, int fdto, int sdt
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 @@ static int receive_ademco_contact_id(struct ast_channel *chan, int fdto, int sdt
}
/* 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,25 +760,22 @@ static int receive_ademco_contact_id(struct ast_channel *chan, int fdto, int sdt
elp - > next = enew ;
}
/* Audio call follows, exit alarm receiver app */
if ( ! 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 ;
}
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) */
res = send_tone_burst ( chan , " 1400 " , 900 , tldn , 200 ) ;
if ( res ) {
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 ;
@ -582,53 +793,53 @@ static int receive_ademco_contact_id(struct ast_channel *chan, int fdto, int sdt
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_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_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_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 @@ static int alarmreceiver_exec(struct ast_channel *chan, const char *data)
/*!
* \ brief Load the configuration from the configuration file
*
* \ param reload True on reload
*
* \ retval 1 success
* \ retval 0 failure
*/
static int load_config ( vo id)
static int load_config ( int reloa d)
{
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 @@ static int load_config(void)
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 @@ static int load_config(void)
}
}
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 @@ static int unload_module(void)
* 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 ;
}
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_STANDARD ( ASTERISK_GPL_KEY , " Alarm Receiver for Asterisk " ) ;
AST_MODULE_INFO ( ASTERISK_GPL_KEY , AST_MODFLAG_DEFAULT , " Alarm Receiver for Asterisk " ,
. load = load_module ,
. unload = unload_module ,
. reload = reload ,
) ;