├── Makefile ├── readme.md ├── main.c ├── main.h ├── uart.c ├── goetzel.S ├── prototype └── goertzel.c └── dtmf.c /Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: main.hex 3 | 4 | CC = avr-gcc 5 | CFLAGS = -Os -Wall -g3 -mmcu=atmega168 -DF_CPU=11059200UL -fpack-struct 6 | OBJS = dtmf.o goetzel.o uart.o main.o 7 | 8 | main.hex: $(OBJS) 9 | $(CC) $(CFLAGS) -o main.elf $(OBJS) 10 | avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature main.elf main.hex 11 | 12 | goetzel.o: goetzel.S 13 | $(CC) $(CFLAGS) -c -o goetzel.o goetzel.S 14 | 15 | clean: 16 | rm -f *.lst *.hex *.o *.obj *.elf *.bin 17 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Efficient AVR DTMF Decoding 2 | --------------------------- 3 | 4 | Copyright (c) 2015, Paul Stoffregen 5 | 6 | I originally developed this 8 bit AVR-based DTMF decoding code in 2009 for a special one-off project. More recently, I created a superior implementation for 32 bit ARM Cortex-M4 in the Teensy Audio Library. 7 | 8 | http://www.pjrc.com/teensy/td_libs_Audio.html 9 | 10 | https://github.com/PaulStoffregen/Audio/blob/master/examples/Analysis/DialTone_Serial/DialTone_Serial.ino 11 | 12 | I highly recommend using the 32 bit version for new projects. However, this old 8 bit code may still be useful for some projects. If you use this code, I only ask that you preserve this info and links to the newer library. 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice, development history, 32 bit audio library links, and this permission notice shall be included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | 20 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | Efficient AVR DTMF Decoding 3 | Copyright (c) 2015, Paul Stoffregen 4 | 5 | I originally developed this 8 bit AVR-based DTMF decoding code in 2009 for a 6 | special one-off project. More recently, I created a superior implementation 7 | for 32 bit ARM Cortex-M4 in the Teensy Audio Library. 8 | 9 | http://www.pjrc.com/teensy/td_libs_Audio.html 10 | https://github.com/PaulStoffregen/Audio/blob/master/examples/Analysis/DialTone_Serial/DialTone_Serial.ino 11 | 12 | I highly recommend using the 32 bit version for new projects. However, this 13 | old 8 bit code may still be useful for some projects. If you use this code, 14 | I only ask that you preserve this info and links to the newer library. 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy 17 | of this software and associated documentation files (the "Software"), to deal 18 | in the Software without restriction, including without limitation the rights 19 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | copies of the Software, and to permit persons to whom the Software is 21 | furnished to do so, subject to the following conditions: 22 | 23 | The above copyright notice, development history, 32 bit audio library links, 24 | and this permission notice shall be included in all copies or substantial 25 | portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 33 | THE SOFTWARE. 34 | */ 35 | 36 | 37 | #include "main.h" 38 | 39 | 40 | int main() 41 | { 42 | char digit; 43 | 44 | uart_init(); 45 | print("\nAVR DTMF\nCopyright 2015, Paul Stoffregen\n"); 46 | dtmf_init(); 47 | while (1) { 48 | // process any new DTMF digits 49 | digit = dtmf_digit(); 50 | if (digit) { 51 | print("digit = "); 52 | cout(digit); 53 | print("\n"); 54 | } 55 | } 56 | 57 | } 58 | 59 | 60 | -------------------------------------------------------------------------------- /main.h: -------------------------------------------------------------------------------- 1 | /* 2 | Efficient AVR DTMF Decoding 3 | Copyright (c) 2015, Paul Stoffregen 4 | 5 | I originally developed this 8 bit AVR-based DTMF decoding code in 2009 for a 6 | special one-off project. More recently, I created a superior implementation 7 | for 32 bit ARM Cortex-M4 in the Teensy Audio Library. 8 | 9 | http://www.pjrc.com/teensy/td_libs_Audio.html 10 | https://github.com/PaulStoffregen/Audio/blob/master/examples/Analysis/DialTone_Serial/DialTone_Serial.ino 11 | 12 | I highly recommend using the 32 bit version for new projects. However, this 13 | old 8 bit code may still be useful for some projects. If you use this code, 14 | I only ask that you preserve this info and links to the newer library. 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy 17 | of this software and associated documentation files (the "Software"), to deal 18 | in the Software without restriction, including without limitation the rights 19 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | copies of the Software, and to permit persons to whom the Software is 21 | furnished to do so, subject to the following conditions: 22 | 23 | The above copyright notice, development history, 32 bit audio library links, 24 | and this permission notice shall be included in all copies or substantial 25 | portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 33 | THE SOFTWARE. 34 | */ 35 | 36 | 37 | #ifndef main_h_included__ 38 | #define main_h_included__ 39 | 40 | #define GOERTZEL_N 100 /* 12.5 ms with 8 kHz sample rate */ 41 | 42 | #ifndef __ASSEMBLER__ 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | // dtmf.c 51 | void dtmf_init(void); 52 | void dtmf_disable(void); 53 | char dtmf_digit(void); 54 | void dtmf_enable_debug(uint16_t num); 55 | 56 | // uart.c 57 | void cout(char c); 58 | char cin(void); 59 | void phex(unsigned char c); 60 | void phex1(unsigned char c); 61 | void phex16(uint16_t n); 62 | void phex32(uint32_t n); 63 | #define print(s) print_P(PSTR(s)) 64 | #define print_hex(s, n) print_P_hex(PSTR(s), (n)) 65 | #define print_hex16(s, n) print_P_hex16(PSTR(s), (n)) 66 | #define print_hex32(s, n) print_P_hex32(PSTR(s), (n)) 67 | void print_P(const char *s); 68 | void print_P_hex(const char *s, uint8_t n); 69 | void print_P_hex16(const char *s, uint16_t n); 70 | void print_P_hex32(const char *s, uint32_t n); 71 | void uart_init(void); 72 | 73 | // goetzel.S 74 | uint8_t goetzel_asm(uint8_t coef); 75 | 76 | //register uint8_t isr_status asm("r2"); 77 | 78 | #else // __ASSEMBLER__ 79 | 80 | //#define isr_status r2 81 | 82 | #endif 83 | #endif 84 | -------------------------------------------------------------------------------- /uart.c: -------------------------------------------------------------------------------- 1 | /* 2 | Efficient AVR DTMF Decoding 3 | Copyright (c) 2015, Paul Stoffregen 4 | 5 | I originally developed this 8 bit AVR-based DTMF decoding code in 2009 for a 6 | special one-off project. More recently, I created a superior implementation 7 | for 32 bit ARM Cortex-M4 in the Teensy Audio Library. 8 | 9 | http://www.pjrc.com/teensy/td_libs_Audio.html 10 | https://github.com/PaulStoffregen/Audio/blob/master/examples/Analysis/DialTone_Serial/DialTone_Serial.ino 11 | 12 | I highly recommend using the 32 bit version for new projects. However, this 13 | old 8 bit code may still be useful for some projects. If you use this code, 14 | I only ask that you preserve this info and links to the newer library. 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy 17 | of this software and associated documentation files (the "Software"), to deal 18 | in the Software without restriction, including without limitation the rights 19 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | copies of the Software, and to permit persons to whom the Software is 21 | furnished to do so, subject to the following conditions: 22 | 23 | The above copyright notice, development history, 32 bit audio library links, 24 | and this permission notice shall be included in all copies or substantial 25 | portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 33 | THE SOFTWARE. 34 | */ 35 | 36 | 37 | #include "main.h" 38 | 39 | 40 | void uart_init(void) 41 | { 42 | UBRR0L = 11; // 115.2 kbps @ 11.0592 MHz clock 43 | UBRR0H = 0; 44 | UCSR0A = (1<> 4); 106 | phex1(c & 15); 107 | } 108 | 109 | void phex16(uint16_t n) 110 | { 111 | phex(n >> 8); 112 | phex(n & 255); 113 | } 114 | 115 | void phex32(uint32_t n) 116 | { 117 | phex16(n >> 16); 118 | phex16(n & 0xFFFF); 119 | } 120 | 121 | -------------------------------------------------------------------------------- /goetzel.S: -------------------------------------------------------------------------------- 1 | /* 2 | Efficient AVR DTMF Decoding 3 | Copyright (c) 2015, Paul Stoffregen 4 | 5 | I originally developed this 8 bit AVR-based DTMF decoding code in 2009 for a 6 | special one-off project. More recently, I created a superior implementation 7 | for 32 bit ARM Cortex-M4 in the Teensy Audio Library. 8 | 9 | http://www.pjrc.com/teensy/td_libs_Audio.html 10 | https://github.com/PaulStoffregen/Audio/blob/master/examples/Analysis/DialTone_Serial/DialTone_Serial.ino 11 | 12 | I highly recommend using the 32 bit version for new projects. However, this 13 | old 8 bit code may still be useful for some projects. If you use this code, 14 | I only ask that you preserve this info and links to the newer library. 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy 17 | of this software and associated documentation files (the "Software"), to deal 18 | in the Software without restriction, including without limitation the rights 19 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | copies of the Software, and to permit persons to whom the Software is 21 | furnished to do so, subject to the following conditions: 22 | 23 | The above copyright notice, development history, 32 bit audio library links, 24 | and this permission notice shall be included in all copies or substantial 25 | portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 33 | THE SOFTWARE. 34 | */ 35 | 36 | 37 | 38 | #include "main.h" 39 | 40 | .global out_buffer 41 | 42 | 43 | #define r_coef r18 44 | #define r_zero r19 45 | #define q1_lsb r20 46 | #define q1_msb r21 47 | #define q2_lsb r22 48 | #define q2_msb r23 49 | #define q0_lsb r24 50 | #define q0_msb r25 51 | #define out0 r24 52 | #define out1 r25 53 | #define out2 r26 54 | #define out3 r27 55 | 56 | 57 | ; uint8_t goetzel_asm(uint8_t coef) 58 | .global goetzel_asm 59 | goetzel_asm: 60 | ;coef in r24 61 | ;clobber registers: r0,r18,r19,r20,r21,r22,r23,r24,r25,r26,r27,r30,r31 62 | ldi r30, lo8(out_buffer) 63 | ldi r31, hi8(out_buffer) 64 | mov r_coef, r24 65 | clr r_zero 66 | clr q1_lsb ;q1 = 0 67 | clr q1_msb 68 | movw q2_lsb, q1_lsb ;q2 = 0 69 | goetzel_loop: 70 | mulsu q1_msb, r_coef 71 | movw q0_lsb, r0 72 | mul q1_lsb, r_coef 73 | add q0_lsb, r1 ;q0+r0 = q1 * coef 74 | adc q0_msb, r_zero 75 | rol r0 76 | rol q0_lsb ;q0 = q1 * coef / 128 77 | rol q0_msb 78 | sub q0_lsb, q2_lsb ;q0 -= q2 79 | sbc q0_msb, q2_msb 80 | ld r0, Z+ ;fetch out_buffer[i] 81 | clr r1 82 | sbrc r0, 7 ;sign extend to 16 bits 83 | com r1 84 | add q0_lsb, r0 ;q0 += (int16_t)out_buffer[i] 85 | adc q0_msb, r1 86 | movw q2_lsb, q1_lsb ;q2 = q1 87 | movw q1_lsb, q0_lsb ;q1 = q0 88 | cpi r30, lo8(out_buffer + GOERTZEL_N) 89 | brne goetzel_loop 90 | muls q1_msb, q2_msb 91 | movw out2, r0 92 | mul q1_lsb, q2_lsb 93 | movw out0, r0 94 | mulsu q1_msb, q2_lsb 95 | sbc out3, r_zero 96 | add out1, r0 97 | adc out2, r1 98 | adc out3, r_zero 99 | mulsu q2_msb, q1_lsb 100 | sbc out3, r_zero 101 | add out1, r0 ;out = q1 * q2 102 | adc out2, r1 103 | adc out3, r_zero 104 | rol out0 105 | rol out1 106 | rol out2 107 | rol out3 ;out /= 128 108 | movw r30, out2 109 | mul out1, r_coef ;out *= coef 110 | movw out0, r0 111 | mov r_zero, r31 112 | mulsu r_zero, r_coef 113 | clr r_zero 114 | movw out2, r0 115 | mul r30, r_coef 116 | add out1, r0 117 | adc out2, r1 118 | adc out3, r_zero 119 | com out0 120 | com out1 121 | com out2 122 | com out3 123 | subi out0, 0xFF 124 | sbci out1, 0xFF 125 | sbci out2, 0xFF 126 | sbci out3, 0xFF 127 | muls q1_msb, q1_msb 128 | add out2, r0 129 | adc out3, r1 130 | mulsu q1_msb, q1_lsb 131 | sbc out3, r_zero 132 | add out1, r0 133 | adc out2, r1 134 | adc out3, r_zero 135 | mulsu q1_msb, q1_lsb 136 | sbc out3, r_zero 137 | add out1, r0 138 | adc out2, r1 139 | adc out3, r_zero 140 | mul q1_lsb, q1_lsb 141 | add out0, r0 142 | adc out1, r1 143 | adc out2, r_zero 144 | adc out3, r_zero 145 | muls q2_msb, q2_msb 146 | add out2, r0 147 | adc out3, r1 148 | mulsu q2_msb, q2_lsb 149 | sbc out3, r_zero 150 | add out1, r0 151 | adc out2, r1 152 | adc out3, r_zero 153 | mulsu q2_msb, q2_lsb 154 | sbc out3, r_zero 155 | add out1, r0 156 | adc out2, r1 157 | adc out3, r_zero 158 | mul q2_lsb, q2_lsb 159 | add out0, r0 160 | adc out1, r1 161 | adc out2, r_zero 162 | adc out3, r_zero 163 | rol out1 164 | rol out2 165 | rol out3 166 | clr r24 167 | brcs goetzel_end 168 | ldi r24, 255 169 | tst out3 170 | brne goetzel_end 171 | mov r24, out2 172 | goetzel_end: 173 | clr r1 174 | ret 175 | -------------------------------------------------------------------------------- /prototype/goertzel.c: -------------------------------------------------------------------------------- 1 | /* 2 | Goertzel prototype code 3 | Copyright (c) 2015 Paul Stoffregen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | // This program is meant to receive bytes containing raw A/D 38 | // measurements of the signal, on the following device: 39 | 40 | #define PORT "/dev/ttyMI1" 41 | 42 | 43 | 44 | void die(const char *format, ...) 45 | { 46 | va_list arg; 47 | 48 | va_start(arg, format); 49 | vfprintf(stderr, format, arg); 50 | exit(1); 51 | } 52 | 53 | 54 | //#define SAMPLING_RATE 8000 55 | #define SAMPLING_RATE (4629.63 * 2.0) 56 | #define GOERTZEL_N 100 57 | 58 | #define MAX_BINS 8 59 | 60 | //#define SAMPLING_RATE 6000 61 | //#define GOERTZEL_N 75 62 | 63 | int sample_count; 64 | double q1[MAX_BINS]; 65 | double q2[MAX_BINS]; 66 | double r[MAX_BINS]; 67 | double freqs[MAX_BINS] = {697, 770, 852, 941, 1209, 1336, 1477, 1633}; 68 | double coefs[MAX_BINS] ; 69 | 70 | uint16_t coef16[MAX_BINS]; 71 | 72 | 73 | void calc_coeffs() 74 | { 75 | int n; 76 | 77 | for(n = 0; n < MAX_BINS; n++) { 78 | coefs[n] = 2.0 * cos(2.0 * 3.141592654 * freqs[n] / SAMPLING_RATE); 79 | //coef16[n] = rint(coefs[n] * 16384); 80 | coef16[n] = rint(coefs[n] * 128); 81 | printf("coef %d is %.5f, int = %u\n", n, coefs[n], coef16[n]); 82 | } 83 | } 84 | 85 | // http://en.wikipedia.org/wiki/Goertzel_algorithm 86 | void post_testing() 87 | { 88 | int row, col, see_digit=0; 89 | int peak_count, max_index; 90 | double maxval, t; 91 | int i; 92 | char * row_col_ascii_codes[4][4] = { 93 | {"1", "2", "3", "A"}, 94 | {"4", "5", "6", "B"}, 95 | {"7", "8", "9", "C"}, 96 | {"*", "0", "#", "D"}}; 97 | 98 | 99 | /* Find the largest in the row group. */ 100 | row = 0; 101 | maxval = 0.0; 102 | for ( i=0; i<4; i++ ) { 103 | if ( r[i] > maxval ) { 104 | maxval = r[i]; 105 | row = i; 106 | } 107 | } 108 | 109 | /* Find the largest in the column group. */ 110 | col = 4; 111 | maxval = 0.0; 112 | for ( i=4; i<8; i++ ) { 113 | if ( r[i] > maxval ) { 114 | maxval = r[i]; 115 | col = i; 116 | } 117 | } 118 | /* Check for minimum energy */ 119 | 120 | printf(" "); 121 | for (i=0; i<8; i++) { 122 | printf("%8.0f ", r[i]); 123 | } 124 | printf("\n"); 125 | 126 | //printf("col:%d=%.2f, row=%d=%.2f\n", col, r[col], row, r[row]); 127 | 128 | if ( r[row] < 4.0e5 ) { 129 | /* 2.0e5 ... 1.0e8 no change */ 130 | /* energy not high enough */ 131 | } else if ( r[col] < 4.0e5 ) { 132 | /* energy not high enough */ 133 | } else { 134 | see_digit = 1; 135 | 136 | /* Twist check 137 | * CEPT => twist < 6dB 138 | * AT&T => forward twist < 4dB and reverse twist < 8dB 139 | * -ndB < 10 log10( v1 / v2 ), where v1 < v2 140 | * -4dB < 10 log10( v1 / v2 ) 141 | * -0.4 < log10( v1 / v2 ) 142 | * 0.398 < v1 / v2 143 | * 0.398 * v2 < v1 144 | */ 145 | if ( r[col] > r[row] ) { 146 | /* Normal twist */ 147 | max_index = col; 148 | if ( r[row] < (r[col] * 0.398) ) /* twist > 4dB, error */ 149 | see_digit = 0; 150 | } else { 151 | /* if ( r[row] > r[col] ) */ 152 | /* Reverse twist */ 153 | max_index = row; 154 | if ( r[col] < (r[row] * 0.158) ) /* twist > 8db, error */ 155 | see_digit = 0; 156 | } 157 | 158 | /* Signal to noise test 159 | * AT&T states that the noise must be 16dB down from the signal. 160 | * Here we count the number of signals above the threshold and 161 | * there ought to be only two. 162 | */ 163 | 164 | t = r[max_index] * 0.158; 165 | peak_count = 0; 166 | for ( i=0; i<8; i++ ) { 167 | if ( r[i] > t ) 168 | peak_count++; 169 | } 170 | if ( peak_count > 2 ) 171 | see_digit = 0; 172 | 173 | if ( see_digit ) { 174 | printf( "%s", row_col_ascii_codes[row][col-4] ); 175 | fflush(stdout); 176 | } 177 | } 178 | } 179 | 180 | 181 | 182 | void goertzel(int sample) 183 | { 184 | double q0; 185 | int i; 186 | 187 | sample_count++; 188 | /*q1[0] = q2[0] = 0;*/ 189 | for ( i=0; i max) max = buf[i]; 233 | if (buf[i] < min) min = buf[i]; 234 | } 235 | printf(" %4d to %3d\n", min, max); 236 | } 237 | 238 | 239 | 240 | 241 | void rx(const uint8_t *data, int num) 242 | { 243 | static int8_t c, buf[GOERTZEL_N]; 244 | static int count=0; 245 | int i; 246 | 247 | for (i=0; i= GOERTZEL_N) { 253 | my_goertzel(buf); 254 | count = 0; 255 | } 256 | } 257 | } 258 | 259 | 260 | int main() 261 | { 262 | int fd, num, errcount=0; 263 | uint8_t buf[512]; 264 | struct termios t; 265 | fd_set rdfs; 266 | 267 | fd = open(PORT, O_RDWR | O_NONBLOCK); 268 | if (fd < 0) die("unable to open %s\n", PORT); 269 | tcgetattr(fd, &t); 270 | t.c_iflag = IGNBRK | IGNPAR | IXANY; 271 | t.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; 272 | t.c_oflag = 0; 273 | t.c_lflag = 0; 274 | tcsetattr(fd, TCSANOW, &t); 275 | calc_coeffs(); 276 | 277 | while (1) { 278 | num = read(fd, buf, sizeof(buf)); 279 | //printf("num = %d\n", num); 280 | if (num < 0 && errno != EAGAIN) { 281 | if (++errcount > 20) die("error reading\n"); 282 | continue; 283 | } 284 | errcount=0; 285 | if (num > 0) { 286 | rx(buf, num); 287 | } else { 288 | FD_ZERO(&rdfs); 289 | FD_SET(fd, &rdfs); 290 | num = select(fd+1, &rdfs, NULL, NULL, NULL); 291 | if (num < 0) { 292 | if (++errcount > 20) die("error waiting\n"); 293 | continue; 294 | } 295 | } 296 | } 297 | return 0; 298 | } 299 | 300 | -------------------------------------------------------------------------------- /dtmf.c: -------------------------------------------------------------------------------- 1 | /* 2 | Efficient AVR DTMF Decoding 3 | Copyright (c) 2015, Paul Stoffregen 4 | 5 | I originally developed this 8 bit AVR-based DTMF decoding code in 2009 for a 6 | special one-off project. More recently, I created a superior implementation 7 | for 32 bit ARM Cortex-M4 in the Teensy Audio Library. 8 | 9 | http://www.pjrc.com/teensy/td_libs_Audio.html 10 | https://github.com/PaulStoffregen/Audio/blob/master/examples/Analysis/DialTone_Serial/DialTone_Serial.ino 11 | 12 | I highly recommend using the 32 bit version for new projects. However, this 13 | old 8 bit code may still be useful for some projects. If you use this code, 14 | I only ask that you preserve this info and links to the newer library. 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy 17 | of this software and associated documentation files (the "Software"), to deal 18 | in the Software without restriction, including without limitation the rights 19 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | copies of the Software, and to permit persons to whom the Software is 21 | furnished to do so, subject to the following conditions: 22 | 23 | The above copyright notice, development history, 32 bit audio library links, 24 | and this permission notice shall be included in all copies or substantial 25 | portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 33 | THE SOFTWARE. 34 | */ 35 | 36 | 37 | #include "main.h" 38 | 39 | // Tone duration tuning. Larger numbers reject more noise, but 40 | // at the expense of requiring longer tone & silence duration. 41 | // Units are number of 12.5 ms tone detection frames 42 | #define MIN_TONE 3 // time the tone must be present to be recognized 43 | #define MAX_TONE_DROPOUT 2 // allowable dropout while hearing tone 44 | #define MIN_SILENCE 4 // silence required after tone 45 | 46 | // Tone thresholds. Larger numbers reject more noise, but 47 | // these don't want to be too large because noise during only 48 | // part of a 12.5 ms window can lower the amount of a valid 49 | // tone. The dropout parameter above is intended to handle 50 | // noise or dropout causing small portions of a tone to go 51 | // below the threshold. 52 | #define MIN_ROW_VALUE 60 // detection threshold for row tone 53 | #define MIN_COL_VALUE 60 // detection threshold for column tone 54 | 55 | 56 | 57 | uint16_t print_raw_dtmf=0; 58 | 59 | #define ADC_SAMPLE_RATE 8000 60 | 61 | #define COEF_697 219 62 | #define COEF_770 211 63 | #define COEF_852 201 64 | #define COEF_941 189 65 | #define COEF_1209 149 66 | #define COEF_1336 128 67 | #define COEF_1477 102 68 | 69 | 70 | static uint8_t adc_count=0; 71 | static int8_t adc_buffer[GOERTZEL_N]; 72 | static volatile uint8_t detected_digit=0; 73 | int8_t out_buffer[GOERTZEL_N]; 74 | 75 | static inline uint8_t dtmf_analysis(void); 76 | static inline void dtmf_duration_check(uint8_t n); 77 | 78 | 79 | void dtmf_init(void) 80 | { 81 | cli(); 82 | TCCR1B = 0; // make sure timer1 is stopped 83 | TIFR1 = (1<> 8); 94 | ICR1L = ((F_CPU / ADC_SAMPLE_RATE - 1) & 255); 95 | TCCR1A = 0; // mode 12 96 | TCCR1B = (1< c2) { 169 | if (c1 > c3) goto col1; 170 | else goto col3; 171 | } else { 172 | if (c2 > c3) goto col2; 173 | else goto col3; 174 | } 175 | col1: 176 | if (c1 < MIN_COL_VALUE) return 0; 177 | noise_threshold = c1 / 3; 178 | col_signal = c1; 179 | if (c2 > noise_threshold) return 0; 180 | if (c3 > noise_threshold) return 0; 181 | //col_noise = c2 + c3; 182 | goto row; 183 | col2: 184 | if (c2 < MIN_COL_VALUE) return 0; 185 | noise_threshold = c2 / 3; 186 | col_signal = c2; 187 | if (c1 > noise_threshold) return 0; 188 | if (c3 > noise_threshold) return 0; 189 | //col_noise = c1 + c3; 190 | out = 1; 191 | goto row; 192 | col3: 193 | if (c3 < MIN_COL_VALUE) return 0; 194 | noise_threshold = c3 / 3; 195 | col_signal = c3; 196 | if (c1 > noise_threshold) return 0; 197 | if (c2 > noise_threshold) return 0; 198 | //col_noise = c1 + c2; 199 | out = 2; 200 | row: 201 | if (!print_raw_dtmf) { 202 | r1 = goetzel_asm(COEF_697); 203 | r2 = goetzel_asm(COEF_770); 204 | r3 = goetzel_asm(COEF_852); 205 | r4 = goetzel_asm(COEF_941); 206 | } 207 | if (r1 > r2) { 208 | if (r1 > r3) { 209 | if (r1 > r4) goto row1; 210 | else goto row4; 211 | } else { 212 | if (r3 > r4) goto row3; 213 | else goto row4; 214 | } 215 | } else { 216 | if (r2 > r3) { 217 | if (r2 > r4) goto row2; 218 | else goto row4; 219 | } else { 220 | if (r3 > r4) goto row3; 221 | else goto row4; 222 | } 223 | } 224 | row1: 225 | if (r1 < MIN_ROW_VALUE) return 0; 226 | noise_threshold = r1 / 3; 227 | row_signal = r1; 228 | if (r2 > noise_threshold) return 0; 229 | if (r3 > noise_threshold) return 0; 230 | if (r4 > noise_threshold) return 0; 231 | //row_noise = r2 + r3 + r4; 232 | out += 1; 233 | goto relative; 234 | row2: 235 | if (r2 < MIN_ROW_VALUE) return 0; 236 | noise_threshold = r2 / 3; 237 | row_signal = r2; 238 | if (r1 > noise_threshold) return 0; 239 | if (r3 > noise_threshold) return 0; 240 | if (r4 > noise_threshold) return 0; 241 | //row_noise = r1 + r3 + r4; 242 | out += 4; 243 | goto relative; 244 | row3: 245 | if (r3 < MIN_ROW_VALUE) return 0; 246 | noise_threshold = r3 / 3; 247 | row_signal = r3; 248 | if (r1 > noise_threshold) return 0; 249 | if (r2 > noise_threshold) return 0; 250 | if (r4 > noise_threshold) return 0; 251 | //row_noise = r1 + r2 + r4; 252 | out += 7; 253 | goto relative; 254 | row4: 255 | if (r4 < MIN_ROW_VALUE) return 0; 256 | noise_threshold = r4 / 3; 257 | row_signal = r4; 258 | if (r1 > noise_threshold) return 0; 259 | if (r2 > noise_threshold) return 0; 260 | if (r3 > noise_threshold) return 0; 261 | //row_noise = r1 + r2 + r3; 262 | out += 10; 263 | relative: 264 | if (col_signal > row_signal) { 265 | if (((uint16_t)col_signal * 50) > ((uint16_t)row_signal << 8)) return 0; 266 | } else { 267 | if (((uint16_t)row_signal * 38) > ((uint16_t)col_signal << 8)) return 0; 268 | } 269 | return out; 270 | } 271 | 272 | 273 | 274 | static inline void dtmf_duration_check(uint8_t n) 275 | { 276 | static uint8_t digit=0; 277 | static uint8_t digit_count=0; 278 | static uint8_t silent_count=0; 279 | 280 | if (n) { 281 | // we are hearing a tone right now 282 | if (n == digit && silent_count <= MAX_TONE_DROPOUT) { 283 | // if it's the same tone 284 | if (digit_count < 255) digit_count++; 285 | } else { 286 | // otherwise, begin new tone 287 | digit = n; 288 | digit_count = 1; 289 | } 290 | silent_count = 0; 291 | } else { 292 | // we are hearing silence right now 293 | if (silent_count < 255) silent_count++; 294 | if (digit) { 295 | // if we previously heard a tone 296 | if (silent_count >= MIN_SILENCE) { 297 | if (digit_count >= MIN_TONE) { 298 | // valid silence following valid tone 299 | detected_digit = digit; 300 | digit = 0; 301 | digit_count = 0; 302 | } 303 | // valid silence following surrious tone 304 | digit = 0; 305 | digit_count = 0; 306 | } 307 | } 308 | } 309 | } 310 | 311 | const char PROGMEM code_to_digit[] = { 312 | 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#' 313 | }; 314 | 315 | char dtmf_digit(void) 316 | { 317 | uint8_t n; 318 | 319 | cli(); 320 | n = detected_digit; 321 | detected_digit = 0; 322 | sei(); 323 | return pgm_read_byte(code_to_digit + n); 324 | } 325 | 326 | void dtmf_enable_debug(uint16_t num) 327 | { 328 | print_raw_dtmf = num; 329 | } 330 | 331 | --------------------------------------------------------------------------------