123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- /*
- * SpanDSP - a series of DSP components for telephony
- *
- * ademco_contactid.c - Ademco ContactID alarm protocol
- *
- * Written by Steve Underwood <steveu@coppice.org>
- *
- * Copyright (C) 2012 Steve Underwood
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version 2.1,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- /*! \page ademco_contactid_tests_page Ademco ContactID tests
- \section ademco_contactid_tests_page_sec_1 What does it do?
- \section ademco_contactid_tests_page_sec_2 How does it work?
- */
- #if defined(HAVE_CONFIG_H)
- #include "config.h"
- #endif
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <assert.h>
- #include <sndfile.h>
- #include "spandsp.h"
- #include "spandsp-sim.h"
- #define SAMPLES_PER_CHUNK 160
- #define OUTPUT_FILE_NAME "ademco_contactid.wav"
- #define MITEL_DIR "../test-data/mitel/"
- #define BELLCORE_DIR "../test-data/bellcore/"
- const char *bellcore_files[] =
- {
- MITEL_DIR "mitel-cm7291-talkoff.wav",
- BELLCORE_DIR "tr-tsy-00763-1.wav",
- BELLCORE_DIR "tr-tsy-00763-2.wav",
- BELLCORE_DIR "tr-tsy-00763-3.wav",
- BELLCORE_DIR "tr-tsy-00763-4.wav",
- BELLCORE_DIR "tr-tsy-00763-5.wav",
- BELLCORE_DIR "tr-tsy-00763-6.wav",
- ""
- };
- static const ademco_contactid_report_t reports[] =
- {
- {0x1234, 0x18, 0x1, 0x131, 0x1, 0x15},
- {0x1234, 0x18, 0x3, 0x131, 0x1, 0x15},
- {0x1234, 0x18, 0x1, 0x401, 0x2, 0x3},
- {0x1234, 0x18, 0x3, 0x401, 0x3, 0x5},
- {0x1234, 0x56, 0x7, 0x890, 0xBC, 0xDEF},
- {0x1234, 0x56, 0x7, 0x89A, 0xBC, 0xDEF} /* This one is bad, as it contains a hex 'A' */
- };
- static int reports_entry = 0;
- static int16_t amp[1000000];
- bool tx_callback_reported = false;
- bool rx_callback_reported = false;
- bool sending_complete = false;
- SNDFILE *outhandle;
- static void talkoff_tx_callback(void *user_data, int tone, int level, int duration)
- {
- printf("Ademco sender report %d\n", tone);
- tx_callback_reported = true;
- }
- static int mitel_cm7291_side_2_and_bellcore_tests(void)
- {
- int j;
- SNDFILE *inhandle;
- int frames;
- ademco_contactid_sender_state_t *sender;
- logging_state_t *logging;
- if ((sender = ademco_contactid_sender_init(NULL, talkoff_tx_callback, NULL)) == NULL)
- return -1;
- logging = ademco_contactid_sender_get_logging_state(sender);
- span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
- span_log_set_tag(logging, "Ademco-tx");
- tx_callback_reported = false;
- /* The remainder of the Mitel tape is the talk-off test */
- /* Here we use the Bellcore test tapes (much tougher), in six
- files - 1 from each side of the original 3 cassette tapes */
- /* Bellcore say you should get no more than 470 false detections with
- a good receiver. Dialogic claim 20. Of course, we can do better than
- that, eh? */
- printf("Talk-off test\n");
- for (j = 0; bellcore_files[j][0]; j++)
- {
- if ((inhandle = sf_open_telephony_read(bellcore_files[j], 1)) == NULL)
- {
- printf(" Cannot open speech file '%s'\n", bellcore_files[j]);
- return -1;
- }
- while ((frames = sf_readf_short(inhandle, amp, SAMPLE_RATE)))
- {
- ademco_contactid_sender_rx(sender, amp, frames);
- }
- if (sf_close_telephony(inhandle))
- {
- printf(" Cannot close speech file '%s'\n", bellcore_files[j]);
- return -1;
- }
- printf(" File %d gave %d false hits.\n", j + 1, 0);
- }
- if (tx_callback_reported)
- {
- printf(" Failed\n");
- return -1;
- }
- printf(" Passed\n");
- ademco_contactid_sender_free(sender);
- return 0;
- }
- /*- End of function --------------------------------------------------------*/
- static void rx_callback(void *user_data, const ademco_contactid_report_t *report)
- {
- printf("Ademco Contact ID message:\n");
- printf(" Account %X\n", report->acct);
- printf(" Message type %X\n", report->mt);
- printf(" Qualifier %X\n", report->q);
- printf(" Event %X\n", report->xyz);
- printf(" Group/partition %X\n", report->gg);
- printf(" User/Zone information %X\n", report->ccc);
- if (memcmp(&reports[reports_entry], report, sizeof(*report)))
- {
- printf("Report mismatch\n");
- exit(2);
- }
- rx_callback_reported = true;
- }
- /*- End of function --------------------------------------------------------*/
- static void tx_callback(void *user_data, int tone, int level, int duration)
- {
- ademco_contactid_sender_state_t *sender;
- sender = (ademco_contactid_sender_state_t *) user_data;
- printf("Ademco sender report %d\n", tone);
- switch (tone)
- {
- case -1:
- /* We are connected and ready to send */
- ademco_contactid_sender_put(sender, &reports[reports_entry]);
- break;
- case 1:
- /* We have succeeded in sending, and are ready to send another message. */
- if (++reports_entry < 5)
- ademco_contactid_sender_put(sender, &reports[reports_entry]);
- else
- sending_complete = true;
- break;
- case 0:
- /* Sending failed after retries */
- sending_complete = true;
- break;
- }
- }
- /*- End of function --------------------------------------------------------*/
- static int end_to_end_tests(void)
- {
- ademco_contactid_receiver_state_t *receiver;
- ademco_contactid_sender_state_t *sender;
- logging_state_t *logging;
- codec_munge_state_t *munge;
- awgn_state_t noise_source;
- int16_t amp[SAMPLES_PER_CHUNK];
- int16_t sndfile_buf[2*SAMPLES_PER_CHUNK];
- int samples;
- int i;
- int j;
- printf("End to end tests\n");
- if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 2)) == NULL)
- {
- fprintf(stderr, " Cannot open audio file '%s'\n", OUTPUT_FILE_NAME);
- exit(2);
- }
- if ((receiver = ademco_contactid_receiver_init(NULL, rx_callback, NULL)) == NULL)
- return -1;
- ademco_contactid_receiver_set_realtime_callback(receiver, rx_callback, receiver);
- logging = ademco_contactid_receiver_get_logging_state(receiver);
- span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
- span_log_set_tag(logging, "Ademco-rx");
- if ((sender = ademco_contactid_sender_init(NULL, tx_callback, NULL)) == NULL)
- return -1;
- ademco_contactid_sender_set_realtime_callback(sender, tx_callback, sender);
- logging = ademco_contactid_sender_get_logging_state(sender);
- span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
- span_log_set_tag(logging, "Ademco-tx");
- awgn_init_dbm0(&noise_source, 1234567, -50);
- munge = codec_munge_init(MUNGE_CODEC_ALAW, 0);
- sending_complete = false;
- rx_callback_reported = false;
- for (i = 0; i < 1000; i++)
- {
- samples = ademco_contactid_sender_tx(sender, amp, SAMPLES_PER_CHUNK);
- for (j = samples; j < SAMPLES_PER_CHUNK; j++)
- amp[j] = 0;
- for (j = 0; j < SAMPLES_PER_CHUNK; j++)
- sndfile_buf[2*j] = amp[j];
- /* There is no point in impairing this signal. It is just DTMF tones, which
- will work as wel as the DTMF detector beign used. */
- ademco_contactid_receiver_rx(receiver, amp, SAMPLES_PER_CHUNK);
- samples = ademco_contactid_receiver_tx(receiver, amp, SAMPLES_PER_CHUNK);
- for (j = samples; j < SAMPLES_PER_CHUNK; j++)
- amp[j] = 0;
- /* We add AWGN and codec impairments to the signal, to stress the tone detector. */
- codec_munge(munge, amp, SAMPLES_PER_CHUNK);
- for (j = 0; j < SAMPLES_PER_CHUNK; j++)
- {
- sndfile_buf[2*j + 1] = amp[j];
- /* Add noise to the tones */
- amp[j] += awgn(&noise_source);
- }
- codec_munge(munge, amp, SAMPLES_PER_CHUNK);
- ademco_contactid_sender_rx(sender, amp, SAMPLES_PER_CHUNK);
- sf_writef_short(outhandle, sndfile_buf, SAMPLES_PER_CHUNK);
- }
- codec_munge_free(munge);
- if (!rx_callback_reported)
- {
- fprintf(stderr, " Report not received\n");
- return -1;
- }
- if (sf_close_telephony(outhandle))
- {
- fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME);
- return -1;
- }
- printf(" Passed\n");
- ademco_contactid_sender_free(sender);
- ademco_contactid_receiver_free(receiver);
- return 0;
- }
- /*- End of function --------------------------------------------------------*/
- static int encode_decode_tests(void)
- {
- char buf[100];
- ademco_contactid_receiver_state_t *receiver;
- ademco_contactid_sender_state_t *sender;
- logging_state_t *logging;
- ademco_contactid_report_t result;
- int i;
- printf("Encode and decode tests\n");
- if ((receiver = ademco_contactid_receiver_init(NULL, NULL, NULL)) == NULL)
- return 2;
- logging = ademco_contactid_receiver_get_logging_state(receiver);
- span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
- span_log_set_tag(logging, "Ademco-rx");
- if ((sender = ademco_contactid_sender_init(NULL, NULL, NULL)) == NULL)
- return 2;
- logging = ademco_contactid_sender_get_logging_state(sender);
- span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
- span_log_set_tag(logging, "Ademco-tx");
- for (i = 0; i < 5; i++)
- {
- if (encode_msg(buf, &reports[i]) < 0)
- {
- printf("Bad encode message\n");
- return -1;
- }
- printf("'%s'\n", buf);
- if (decode_msg(&result, buf))
- {
- printf("Bad decode message\n");
- return -1;
- }
- ademco_contactid_receiver_log_msg(receiver, &result);
- printf("\n");
- if (memcmp(&reports[i], &result, sizeof(result)))
- {
- printf("Received message does not match the one sent\n");
- return -1;
- }
- }
- if (encode_msg(buf, &reports[5]) >= 0)
- {
- printf("Incorrectly good message\n");
- return -1;
- }
- printf("'%s'\n", buf);
- printf("\n");
- printf(" Passed\n");
- ademco_contactid_sender_free(sender);
- ademco_contactid_receiver_free(receiver);
- return 0;
- }
- /*- End of function --------------------------------------------------------*/
- static void decode_file(const char *file)
- {
- //SPAN_DECLARE(int) decode_msg(ademco_contactid_report_t *report, const char buf[])
- }
- /*- End of function --------------------------------------------------------*/
- int main(int argc, char *argv[])
- {
- int opt;
- const char *decode_test_file;
- decode_test_file = NULL;
- while ((opt = getopt(argc, argv, "d:")) != -1)
- {
- switch (opt)
- {
- case 'd':
- decode_test_file = optarg;
- break;
- default:
- //usage();
- exit(2);
- break;
- }
- }
- if (decode_test_file)
- {
- decode_file(decode_test_file);
- return 0;
- }
- if (encode_decode_tests())
- {
- printf("Tests failed\n");
- return 2;
- }
- if (mitel_cm7291_side_2_and_bellcore_tests())
- {
- printf("Tests failed\n");
- return 2;
- }
- if (end_to_end_tests())
- {
- printf("Tests failed\n");
- return 2;
- }
- printf("Tests passed\n");
- return 0;
- }
- /*- End of function --------------------------------------------------------*/
- /*- End of file ------------------------------------------------------------*/
|