summaryrefslogtreecommitdiffstats
path: root/ss5_decode.c
diff options
context:
space:
mode:
authorAndreas Eversberg2009-09-26 13:20:29 +0200
committerAndreas Eversberg2009-09-26 13:20:29 +0200
commit323cbc387b1a068f8e2bcfd1034666406ba18c93 (patch)
treeee251a238dde61870ef4bef687e7fcb6fff1f749 /ss5_decode.c
parentSome minor corrections on default/interface.conf (diff)
downloadlcr-323cbc387b1a068f8e2bcfd1034666406ba18c93.tar.gz
lcr-323cbc387b1a068f8e2bcfd1034666406ba18c93.tar.xz
lcr-323cbc387b1a068f8e2bcfd1034666406ba18c93.zip
Added support for signalling system no. 5.
More infos will follow on the isdn4linux mailing list. modified: Makefile.am modified: Makefile.in modified: README modified: apppbx.cpp modified: configure modified: configure.ac modified: default/options.conf modified: dss1.cpp modified: ie.cpp modified: interface.c modified: interface.h modified: lcradmin.c modified: lcrsocket.h modified: mISDN.cpp modified: mISDN.h modified: main.c modified: main.h modified: port.h modified: socket_server.c new file: ss5.cpp new file: ss5.h new file: ss5_decode.c new file: ss5_decode.h new file: ss5_encode.c new file: ss5_encode.h
Diffstat (limited to 'ss5_decode.c')
-rw-r--r--ss5_decode.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/ss5_decode.c b/ss5_decode.c
new file mode 100644
index 0000000..541f6be
--- /dev/null
+++ b/ss5_decode.c
@@ -0,0 +1,181 @@
+/*
+ * SS5 signal decoder.
+ *
+ * Copyright by Andreas Eversberg (jolly@eversberg.eu)
+ * based on different decoders such as ISDN4Linux
+ * copyright by Karsten Keil
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include "main.h"
+#include "ss5_decode.h"
+
+/* enable level debugging */
+//#define DEBUG_LEVELS
+
+#define NCOEFF 8 /* number of frequencies to be analyzed */
+
+#define MIN_DB 0.01995262 /* -17 db */
+#define DIFF_DB 0.31622777 /* -5 db */
+#define SNR 1.3 /* noise may not exceed signal by that factor */
+
+/* For DTMF recognition:
+ * 2 * cos(2 * PI * k / N) precalculated for all k
+ */
+static signed long long cos2pik[NCOEFF] =
+{
+ /* k = 2*cos(2*PI*f/8000), k << 15
+ * 700, 900, 1100, 1300, 1500, 1700, 2400, 2600 */
+ 55879, 49834, 42562, 34242, 25080, 15299, -20252, -29753
+};
+
+/* detection matrix for two frequencies */
+static char decode_two[8][8] =
+{
+ {' ', '1', '2', '4', '7', '*', ' ', ' '}, /* * = code 11 */
+ {'1', ' ', '3', '5', '8', '#', ' ', ' '}, /* # = code 12 */
+ {'2', '3', ' ', '6', '9', 'a', ' ', ' '}, /* a = KP1 */
+ {'4', '5', '6', ' ', '0', 'b', ' ', ' '}, /* b = KP2 */
+ {'7', '8', '9', '0', ' ', 'c', ' ', ' '}, /* c = ST */
+ {'*', '#', 'a', 'b', 'c', ' ', ' ', ' '},
+ {' ', ' ', ' ', ' ', ' ', ' ', ' ', 'C'}, /* C = 2600+2400 */
+ {' ', ' ', ' ', ' ', ' ', ' ', 'C', ' '}
+};
+
+static char decode_one[8] =
+ {' ', ' ', ' ', ' ', ' ', ' ', 'A', 'B'}; /* A = 2400, B = 2600 */
+/*
+ * calculate the coefficients of the given sample and decode
+ */
+
+char ss5_decode(unsigned char *data, int len)
+{
+ signed short buf[len];
+ signed long sk, sk1, sk2, low, high;
+ int k, n, i;
+ int f1 = 0, f2 = 0, f3 = 0;
+ double result[NCOEFF], power, noise, snr;
+ signed long long cos2pik_;
+ char digit = ' ';
+
+ /* convert samples */
+ for (i = 0; i < len; i++)
+ buf[i] = audio_law_to_s32[*data++];
+
+ /* now we have a full buffer of signed long samples - we do goertzel */
+ for (k = 0; k < NCOEFF; k++) {
+ sk = 0;
+ sk1 = 0;
+ sk2 = 0;
+ cos2pik_ = cos2pik[k];
+ for (n = 0; n < len; n++) {
+ sk = ((cos2pik_*sk1)>>15) - sk2 + buf[n];
+ sk2 = sk1;
+ sk1 = sk;
+ }
+ sk >>= 8;
+ sk2 >>= 8;
+ if (sk > 32767 || sk < -32767 || sk2 > 32767 || sk2 < -32767)
+ PERROR("Tone-Detection overflow\n");
+ /* compute |X(k)|**2 */
+ result[k] = sqrt (
+ (sk * sk) -
+ (((cos2pik[k] * sk) >> 15) * sk2) +
+ (sk2 * sk2)
+ ) / len / 62; /* level of 1 is 0 db*/
+ }
+
+ /* now we do noise level calculation */
+ low = 32767;
+ high = -32768;
+ for (n = 0; n < len; n++) {
+ sk = buf[n];
+ if (sk < low)
+ low = sk;
+ if (sk > high)
+ high = sk;
+ }
+ noise = ((double)(high-low) / 65536.0);
+
+ /* find the two loudest frequencies + one less lower frequency to detect noise */
+ power = 0.0;
+ for (i = 0; i < NCOEFF; i++) {
+ if (result[i] > power) {
+ power = result[i];
+ f1 = i;
+ }
+ }
+ power = 0.0;
+ for (i = 0; i < NCOEFF; i++) {
+ if (i != f1 && result[i] > power) {
+ power = result[i];
+ f2 = i;
+ }
+ }
+ power = 0.0;
+ for (i = 0; i < NCOEFF; i++) {
+ if (i != f1 && i != f2 && result[i] > power) {
+ power = result[i];
+ f3 = i;
+ }
+ }
+
+#if 0
+ /* check one frequency */
+ if (result[f1] > MIN_DB /* must be at least -17 db */
+ && result[f1]*DIFF_DB > result[f2]) /* must be 5 db above other tones */
+ digit = decode_one[f1];
+ /* check two frequencies */
+ if (result[f1] > MIN_DB && result[f2] > MIN_DB /* must be at lease -17 db */
+ && result[f1]*DIFF_DB <= result[f2] /* f2 must be not less than 5 db below f1 */
+ && result[f1]*DIFF_DB > result[f3]) /* f1 must be 5 db above other tones */
+ digit = decode_two[f1][f2];
+#endif
+ snr = 0;
+ /* check one frequency */
+ if (result[f1] > MIN_DB /* must be at least -17 db */
+ && result[f1]*SNR > noise) { /* */
+ digit = decode_one[f1];
+ snr = result[f1] / noise;
+ }
+ /* check two frequencies */
+ if (result[f1] > MIN_DB && result[f2] > MIN_DB /* must be at lease -17 db */
+ && result[f1]*DIFF_DB <= result[f2] /* f2 must be not less than 5 db below f1 */
+ && (result[f1]+result[f2])*SNR > noise) { /* */
+ digit = decode_two[f1][f2];
+ snr = (result[f1]+result[f2]) / noise;
+ }
+
+ /* debug powers */
+#ifdef DEBUG_LEVELS
+ for (i = 0; i < NCOEFF; i++)
+ printf("%d:%3d %c ", i, (int)(result[i]*100), (f1==i || f2==i)?'*':' ');
+ printf("N:%3d digit:%c snr=%3d\n", (int)(noise*100), digit, (int)(snr*100));
+#endif
+
+ return digit;
+}
+
+void ss5_test_decode(void)
+{
+#ifdef DEBUG_LEVELS
+ double phase;
+ int i, j;
+ signed short sample;
+
+ unsigned char buffer[SS5_DECODER_NPOINTS];
+ for (i = 0; i < 4000; i += 10) {
+ phase = 2.0 * 3.14159265 * i / 8000.0;
+ for (j = 0; j < SS5_DECODER_NPOINTS; j++) {
+ sample = sin(phase * j) * 1000;
+ buffer[j] = audio_s16_to_law[sample & 0xffff];
+ }
+ printf("FRQ:%04d:", i);
+ ss5_decode(buffer, SS5_DECODER_NPOINTS);
+ }
+#endif
+}
+