// MyMonModuleZVEI.cpp: Implementierung der Klasse MonitorModuleZVEI.
//
// Edited 02/2007 - demod rewritten, fully functional but to be tested "in the wild":
// Martin Diedrich (martin@mdiedrich.de)
//////////////////////////////////////////////////////////////////////

#include <iostream>
#include <fstream>
#include "math.h"
#include "time.h"
#include "convert.h"

#include "MonitorModuleZVEI.h"
#include "MonitorLogging.h"

using namespace std;

#ifdef WIN32
	#include <vector>
	#include <algorithm>
	#include <functional>
#endif

#ifdef _DEBUG
#undef THIS_FILE
//static char THIS_FILE[]=__FILE__;
#endif

#ifdef WIN32
#ifndef M_PI
const float M_PI = 3.14159265358979 ;
#endif
#endif

#define COS(x) costabf[(((x) >> 6) & 0x3ffu)]
#define SIN(x) COS((x) + 0xc000)
#define BLOCKNUM 4

//////////////////////////////////////////////////////////////////////
// Konstruktion/Destruktion
//////////////////////////////////////////////////////////////////////

int MonitorModuleZVEI::PHINC(int x)
{
 return (x * 0x10000 / FREQ_SAMP) ;
}

/**
 * @brief constructor, initializing most of our little ZVEI universe ;)
 * @param sampleRate sample rate of data from soundcard to be analyzed by demod()
 */
MonitorModuleZVEI::MonitorModuleZVEI(int sampleRate,XMLNode* pConfig)
{
	unsigned int i ;
	
	debugmodus = getNodeInt(*pConfig,"debugmodus",0);
	int gm900 = getNodeInt(*pConfig,"gm900",0); // ONLY FOR GM900 AT FHD OSTERODE
	squelch = getNodeInt(*pConfig,"squelch",51);
	squelch = squelch/100;

	m_lpszName="ZVEI" ;

	FREQ_SAMP=sampleRate ;
	BLOCKLEN=sampleRate / 100 ;

	// Definition der zu betrachtenden Frequenzen
	zvei_freq[0]=PHINC(2400) ; // Ziffer 0
	if(gm900 == 1) {
		zvei_freq[0]=PHINC(2410) ; // Ziffer 0 for slightly too high tone by motorola gm900 in use at fhd osterode
	}
	zvei_freq[1]=PHINC(1060) ; // Ziffer 1
	zvei_freq[2]=PHINC(1160) ; // Ziffer 2
	zvei_freq[3]=PHINC(1270) ; // Ziffer 3
	zvei_freq[4]=PHINC(1400) ; // Ziffer 4
	zvei_freq[5]=PHINC(1530) ; // Ziffer 5
	zvei_freq[6]=PHINC(1670) ; // Ziffer 6
	zvei_freq[7]=PHINC(1830) ; // Ziffer 7
	zvei_freq[8]=PHINC(2000) ; // Ziffer 8
	zvei_freq[9]=PHINC(2200) ; // Ziffer 9
	zvei_freq[10]=PHINC(2800) ; // A = N / Spezialfall Gruppenruf
	zvei_freq[11]=PHINC(810) ; // C
	zvei_freq[12]=PHINC(675) ; // Sirenendoppelton I
	zvei_freq[13]=PHINC(1240) ; // Sirenendoppelton II
	zvei_freq[14]=PHINC(2600) ; // E = W (Wiederholungs- und Melderweckton)
	zvei_freq[15]=PHINC(0) ; // Stille/Rauschen/keine eindeutige Frequenz
	zvei_freq[16]=PHINC(1860) ; // Sirenendoppelton III
	zvei_freq[17]=PHINC(825) ; // Sirenendoppelton IV
	zvei_freq[18]=PHINC(2280) ; // Sirenendoppelton V
	zvei_freq[19]=PHINC(1010) ; // Sirenendoppelton VI

	// Definition der zu betrachtenden Frequenzen
	zvei_character[0]='0' ; // Ziffer 0
	zvei_character[1]='1' ; // Ziffer 1
	zvei_character[2]='2' ; // Ziffer 2
	zvei_character[3]='3' ; // Ziffer 3
	zvei_character[4]='4' ; // Ziffer 4
	zvei_character[5]='5' ; // Ziffer 5
	zvei_character[6]='6' ; // Ziffer 6
	zvei_character[7]='7' ; // Ziffer 7
	zvei_character[8]='8' ; // Ziffer 8
	zvei_character[9]='9' ; // Ziffer 9
	zvei_character[10]='A' ; // A = N / Spezialfall Gruppenruf
	zvei_character[11]='C' ; // C
	zvei_character[12]='S' ; // Sirenendoppelton I
	zvei_character[13]='S' ; // Sirenendoppelton II
	zvei_character[14]='W' ; // E = W (Wiederholungs- und Melderweckton)
	zvei_character[15]='-' ; // Stille/Rauschen/keine eindeutige Frequenz
	zvei_character[16]='S' ; // Sirenendoppelton III
	zvei_character[17]='S' ; // Sirenendoppelton IV
	zvei_character[18]='S' ; // Sirenendoppelton V
	zvei_character[19]='S' ; // Sirenendoppelton VI

	// initializing our matrixes -> zeroing
	for (i=0; i <= sizeof(zvei_freq)/sizeof(zvei_freq[0]); i++) {
		ph[i]=0;
	}
	for (i=0; i < 4  ;i++) {
		energy[i]=0;
	}
	for (i=0; i< 4; i++) {
		for (unsigned int j=0; j <= 2*sizeof(zvei_freq)/sizeof(zvei_freq[0]); j++) {
			tenergy[i][j]=0;
		}
	}

	blkcount=0 ;

	folge_position = 0; // gibt die aktuelle Position bei der Erkennung an, in gewisser Weise der "Zustandsautomat"
	timeout = 0; // Zu lange Pause nach Tonfolge -> triggert Ausgabe und Resets
	pause_length = 0; // Laenge der bisher gemessenen Pause, reset bei 100
	tone_count = 0; // wie oft wurde der ton erkannt?
	seven_count = 0;
	siren_count = 0;
	maxlength = sizeof(zvei_folge)/sizeof(zvei_folge[0]); // Laenge der n-Tonfolge. Normalerweise 5. Es gab einen Request fuer 7.

	/*
	* Format des Arrays fount_tones:
	* [0] - energiereichste Frequenz, [1] - zweitenergier. Freq., [2] - drittenergier. Freq., [3] - Energie I, [4] - Energie II - [5] - Energie III,
	* [6] - Totale Energie; damit stehen drei Toene und Energien zur Verfuegung fuer Auswertung und Filter
	*/
	found_tones = new int[7]; // Rueckgabe der process_block()-Methode
	for (i=0; i < 7; i++) {
		for(int j=0; j<7; j++) {
			detected_seven[i][j] = -1;
		}
	}

	for(i=0; i < maxlength; i++) {
		zvei_folge[i] = -2;
	}

	for (i = 0; i < COSTABSIZE; i++) {
		costabf[i] = (float) cos(M_PI*2.0*i/COSTABSIZE);
	}

}

MonitorModuleZVEI::~MonitorModuleZVEI()
{

}

/**
 * @brief demodulates raw sounddata from card to ZVEI-Tonfolgen
 * @param buffer pointer to sound buffer
 * @param length length of that buffer
 * @author Martin Diedrich (mdi)
 * @date 11/2007
 */
void MonitorModuleZVEI::demod(float *buffer, int length)
{
	unsigned int i ;
	float s_in=0;
	short int last_zvei_last_character = -2;

	// uebernommen aus dem vorherigen code
	for (; length > 0; length--, buffer++) {
		s_in = *buffer;
		energy[0] += fsqr(s_in);


/*	Berechnen und Aufaddieren der Spalte 0 der tenergy-Matrix
 *	mit 220 (BLOCKLEN) aufeinanderfolgenden Bufferwerten:
 *	Zeilen  0-17: Cos-Werte, Zeilen 18-35: Sin-Werte	*/
		for (i = 0; i < sizeof(zvei_freq)/sizeof(zvei_freq[0]); i++) {
			tenergy[0][i] += COS(ph[i]) * s_in;
			tenergy[0][i + sizeof(zvei_freq)/sizeof(zvei_freq[0])] += SIN(ph[i]) * s_in;
			ph[i] += zvei_freq[i];
		}

		if ((blkcount--) <= 0) {
			blkcount = BLOCKLEN;
			found_tones = process_block(found_tones);

			memcpy(detected_seven[seven_count], found_tones, sizeof(int)*7);

			int f = fuzzyseven();

			if( debugmodus > 5 && ((f >= 0 && f <= 11) || f == 14)) {
				cout << " -> " << f << " -> " << zvei_character[f] << endl;
			}

			// ZVEI digit or repeating tone found, not end of ZVEI quintett
			if(((f >= 0 && f <= 11) || f == 14) && folge_position != maxlength) {
				if(folge_position != 0) {
					if(f != zvei_folge[folge_position-1]) {
						zvei_folge[folge_position] = f;
						folge_position++;
					}
				} else {
						zvei_folge[folge_position] = f;
						folge_position++;
				}
				pause_length = 0;
			}

			// wakeup found shortly before maximum pause time
			if(f == 14 && folge_position == maxlength && pause_length > 52) {
				if(zvei_ok()) {
					if(debugmodus > 2) {
						cout << endl;
						for(i=0; i<5; i++) {
							cout << (zvei_folge[i] == 14 ? zvei_folge[(i+(maxlength-1))%maxlength] : zvei_folge[i]);
						}
						cout << " (Melderausloesung)" << endl << endl;
					}
					std::string numString="";
					for(unsigned int counter=0;counter<maxlength;counter++) {
						// numString+=convertIntToHexString((zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter]));
						numString+=zvei_character[(zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter])];
					}
					DisplayResult(numString,1,"Melderausloesung");
				}
				for(i=0; i<maxlength; i++) {
					zvei_folge[i] = -2;
				}
				folge_position = 0;
				pause_length = 0;
				siren_count = 0;
			}

			// normal pause handling
			if ((f == 15 || f == -1) && folge_position != maxlength ) {
				pause_length++;
				if(pause_length == 6) {
					for(i=0; i<maxlength; i++) {
						zvei_folge[i] = -2;
					}
					folge_position = 0;
					pause_length = 0;
				}
				if(debugmodus > 5) {
					cout << " Pause: " << pause_length;
				}
			}

			// waiting for siren or wakeup - or reacting on timeout
			if ((f == 15 || f == -1) && folge_position == maxlength ) {
				pause_length++;
				if(debugmodus > 5) {
					cout << " Pause: " << pause_length;
				}
				if(pause_length == 64) { // timeout
					if(zvei_ok()) {
						if(debugmodus > 2) {
							cout << endl;
							for(i=0; i<maxlength; i++) {
								cout << (zvei_folge[i] == 14 ? zvei_folge[(i+(maxlength-1))%maxlength] : zvei_folge[i]);
							}
							cout << " (Timeout)" << endl << endl;
						}
						std::string numString="";
						for(unsigned int counter=0;counter<maxlength;counter++) {
							// numString+=convertIntToHexString((zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter]));
							numString+=zvei_character[(zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter])];
						}
						DisplayResult(numString,0,"unklare Ausloesung");
					}
					for(i=0; i<maxlength; i++) {
						zvei_folge[i] = -2;
					}
					last_zvei_last_character = -2;
					folge_position = 0;
					pause_length = 0;
					siren_count = 0;
				}
			}

			// got siren tone 12/13 - fire
			if ( ((found_tones[0] == 12 && found_tones[1] == 13) || (found_tones[1] == 12 && found_tones[0] == 13)) && folge_position == maxlength) {
				siren_count++;
				pause_length = 0;
				if(siren_count > 20) {
					if(zvei_ok()) {
						if(debugmodus > 2) {
							cout << endl;
							for(i=0; i<maxlength; i++) {
								cout << (zvei_folge[i] == 14 ? zvei_folge[(i+(maxlength-1))%maxlength] : zvei_folge[i]);
							}
							cout << " (Siren2)" << endl << endl;
						}
						std::string numString="";
						for(unsigned int counter=0;counter<maxlength;counter++) {
							// numString+=convertIntToHexString((zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter]));
							numString+=zvei_character[(zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter])];
						}
						DisplayResult(numString,2,"Sirenenausloesung: Feueralarm");
					}
					for(i=0; i<maxlength; i++) {
						zvei_folge[i] = -2;
					}
					folge_position = 0;
					siren_count = 0;
				}
			}

			// got siren tone 12/19 - ZVS-Entwarnung
			if ( ((found_tones[0] == 12 && found_tones[1] == 19) || (found_tones[1] == 12 && found_tones[0] == 19)) && folge_position == maxlength) {
				siren_count++;
				pause_length = 0;
				if(siren_count > 20) {
					if(zvei_ok()) {
						if(debugmodus > 2) {
							cout << endl;
							for(i=0; i<maxlength; i++) {
								cout << (zvei_folge[i] == 14 ? zvei_folge[(i+(maxlength-1))%maxlength] : zvei_folge[i]);
							}
							cout << " (Siren6)" << endl << endl;
						}
						std::string numString="";
						for(unsigned int counter=0;counter<maxlength;counter++) {
							// numString+=convertIntToHexString((zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter]));
							numString+=zvei_character[(zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter])];
						}
						DisplayResult(numString,6,"Sirenenausloesung: Entwarnung");
					}
					for(i=0; i<maxlength; i++) {
						zvei_folge[i] = -2;
					}
					folge_position = 0;
					siren_count = 0;
				}
			}

			// got siren tone 12/16 - Probe
			if ( ((found_tones[0] == 12 && found_tones[1] == 16) || (found_tones[1] == 12 && found_tones[0] == 16)) && folge_position == maxlength) {
				siren_count++;
				pause_length = 0;
				if(siren_count > 20) {
					if(zvei_ok()) {
						if(debugmodus > 2) {
							cout << endl;
							for(i=0; i<maxlength; i++) {
								cout << (zvei_folge[i] == 14 ? zvei_folge[(i+(maxlength-1))%maxlength] : zvei_folge[i]);
							}
							cout << " (Siren3)" << endl << endl;
						}
						std::string numString="";
						for(unsigned int counter=0;counter<maxlength;counter++) {
							// numString+=convertIntToHexString((zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter]));
							numString+=zvei_character[(zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter])];
						}
						DisplayResult(numString,3,"Sirenenausloesung: Probe");
					}
					for(i=0; i<maxlength; i++) {
						zvei_folge[i] = -2;
					}
					folge_position = 0;
					siren_count = 0;
				}
			}

			// got siren tone 12/17 - ZVS-Alarm
			if ( ((found_tones[0] == 12 && found_tones[1] == 17) || (found_tones[1] == 12 && found_tones[0] == 17)) && folge_position == maxlength) {
				siren_count++;
				pause_length = 0;
				if(siren_count > 20) {
					if(zvei_ok()) {
						if(debugmodus > 2) {
							cout << endl;
							for(i=0; i<maxlength; i++) {
								cout << (zvei_folge[i] == 14 ? zvei_folge[(i+(maxlength-1))%maxlength] : zvei_folge[i]);
							}
							cout << " (Siren4): " << found_tones[0] << " " << found_tones[1] << endl << endl;
						}
						std::string numString="";
						for(unsigned int counter=0;counter<maxlength;counter++) {
							// numString+=convertIntToHexString((zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter]));
							numString+=zvei_character[(zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter])];
						}
						DisplayResult(numString,4,"Sirenenausloesung: ZVS-Alarm");
					}
					for(i=0; i<maxlength; i++) {
						zvei_folge[i] = -2;
					}
					folge_position = 0;
					siren_count = 0;
				}
			}

			// got siren tone 12/18 - ZVS-Warnung
			if ( ((found_tones[0] == 12 && found_tones[1] == 18) || (found_tones[1] == 12 && found_tones[0] == 18)) && folge_position == maxlength) {
				siren_count++;
				pause_length = 0;
				if(siren_count > 20) {
					if(zvei_ok()) {
						if(debugmodus > 2) {
							cout << endl;
							for(i=0; i<maxlength; i++) {
								cout << (zvei_folge[i] == 14 ? zvei_folge[(i+(maxlength-1))%maxlength] : zvei_folge[i]);
							}
							cout << " (Siren5)" << endl << endl;
						}
						std::string numString="";
						for(unsigned int counter=0;counter<maxlength;counter++) {
							// numString+=convertIntToHexString((zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter]));
							numString+=zvei_character[(zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter])];
						}
						DisplayResult(numString,5,"Sirenenausloesung: ZVS-Warnung");
					}
					for(i=0; i<maxlength; i++) {
						zvei_folge[i] = -2;
					}
					folge_position = 0;
					siren_count = 0;
				}
			}

			// new digit after full zvei_folge
			if(((f >= 0 && f <= 11) || f == 14) && folge_position == maxlength && zvei_ok() && (zvei_folge[4] != f || pause_length > 10 )) {
				if(debugmodus > 2) {
					cout << endl;
					for(i=0; i<maxlength; i++) {
						cout << (zvei_folge[i] == 14 ? zvei_folge[(i+(maxlength-1))%maxlength] : zvei_folge[i]);
					}
					cout << " (Nachfolger): " << f << endl;
				}
				
				// Motorola Sonderbehandlung
				if(zvei_folge[0] == 14) {
					zvei_folge[0] = last_zvei_last_character;
				}
				
				std::string numString="";
				for(unsigned int counter=0;counter<maxlength;counter++) {
					// numString+=convertIntToHexString((zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter]));
					numString+=zvei_character[(zvei_folge[counter] == 14 ? zvei_folge[(counter+(maxlength-1))%maxlength] : zvei_folge[counter])];
				}
				DisplayResult(numString,0,"unklare Ausloesung");
				
				// first tone 14 not in ZVEI-Standard but used by Motorola radios when two select5 are sent directly following, this saves last character of decoded select5.
				if(zvei_folge[4] == 14) {
					last_zvei_last_character = zvei_folge[3];
				} else {
					last_zvei_last_character = zvei_folge[4];
				}

				for(i=0; i<maxlength; i++) {
					zvei_folge[i] = -2;
				}
				folge_position = 0;

				zvei_folge[folge_position] = f;
				folge_position++;

				pause_length = 0;
				siren_count = 0;
			}

			seven_count++;

			// just resetting our counter for the buffer of seven detected tones
			if(seven_count == 7) {
				seven_count = 0;
				if(false) { // DEBUG
					for(int i=0; i<7; i++) {
						cout << detected_seven[i][0] << " - " << detected_seven[i][1] << endl;
					}
					cout << endl;
				}
			}
		}
	}

}

/**
 * @brief fourier transformation (Goertzel) on given block of sound data
 */
int *MonitorModuleZVEI::process_block(int *found_tones)
{
	float tote = 0;
	float totte[2*sizeof(zvei_freq)/sizeof(zvei_freq[0])];
	unsigned int i, j;

	/*	Aufaddieren der energy-Eintraege nach TOTal-Energy (tote)	*/
	for (i = 0; i < BLOCKNUM; i++) tote += energy[i];

	/*	Aufaddieren der Zeilen der tenergy-Matrix nach TOTal-TEnergy (totte)	*/
	for (i = 0; i < 2*sizeof(zvei_freq)/sizeof(zvei_freq[0]); i++) {
		totte[i] = 0;
		for (j = 0; j < BLOCKNUM; j++)
			totte[i] += tenergy[j][i];
	}
	// tote *= (BLOCKNUM * BLOCKLEN * 0.5);  /* adjust for block lengths */
	/*	Summe der Quadrate der korrespondierenden Sinus- und Cosinuseintraege	*/
	for (i = 0; i < sizeof(zvei_freq)/sizeof(zvei_freq[0]); i++) totte[i] = fsqr(totte[i]) + fsqr(totte[i+sizeof(zvei_freq)/sizeof(zvei_freq[0])]);

	/*	Weiterschieben der energy-Eintraege, Ruecksetzen Feld [0] 	*/
	memmove(energy + 1, energy,
		sizeof(energy) - sizeof(energy[0]));
	energy[0] = 0;

	/*	Weiterschieben der tenergy-Spalten, Ruecksetzen Spalte [0] 	*/
	memmove(tenergy + 1, tenergy,
		sizeof(tenergy) - sizeof(tenergy[0]));
	memset(tenergy, 0, sizeof(tenergy[0]));

	tote = 0;
	for( i = 0; i < 2*sizeof(zvei_freq)/sizeof(zvei_freq[0]) ; i++ ) {
		tote += totte[i];
	}

	if(false) { // DEBUG
		printf("ZVEI: Energies: %8.5f\n0->%8.5f\t1->%8.5f\t2->%8.5f\n3->%8.5f\t4->%8.5f\t5->%8.5f\n6->%8.5f\t7->%8.5f\t"
		   "8->%8.5f\n9->%8.5f\t10(2800)->%8.5f\t11(810)->%8.5f\n12(675)->%8.5f\t13(1240)->%8.5f\t14(w)->%8.5f\n15(NULL)->%8.5f\t16(1860)->%8.5f\t17(825)->%8.5f\n18(2280)->%8.5f\t19(1010)->%8.5f\n\n",
		   tote, totte[0], totte[1], totte[2], totte[3], totte[4], totte[5], totte[6], totte[7],
		   totte[8], totte[9], totte[10], totte[11], totte[12], totte[13], totte[14], totte[15], totte[16], totte[17], totte[18], totte[19]);
	}

	if(debugmodus > 9) { //DEBUG, USE WITH CAUTION, generates possibly big logfile on long runtime!
		ofstream outfile;
		outfile.open ("freq_dmp.txt", ios_base::app);
		outfile << tote << "|";
		for(unsigned int count = 0; count < sizeof(zvei_freq)/sizeof(zvei_freq[0]); count++) {
			outfile << (int)totte[count] << "|";
		}
		outfile << endl;
		outfile.close();
	}

	// kein groesster index gefunden -> -1 zurueckgeben
	/*if ((i = find_max_index(totte, -1, -1)) < 0) {
		//return -1;
	} */

	found_tones[0] = find_max_index(totte, -1, -1); // groesste Energie
	found_tones[1] = find_max_index(totte, found_tones[0], -1); // zweitgroesste Energie
	found_tones[2] = find_max_index(totte, found_tones[0], found_tones[1]); // drittgroesste Energie
	found_tones[3] = (int) totte[found_tones[0]]; // Energie I
	found_tones[4] = (int) totte[found_tones[1]]; // Energie II
	found_tones[5] = (int) totte[found_tones[2]]; // Energie III
	found_tones[6] = (int) tote; // Total Energie

	if(false) { // DEBUG
		cout << "process_block/found_tones: " << endl;
		cout << found_tones[0] << " -> " << totte[found_tones[0]] << ", " << found_tones[1] << " -> " << totte[found_tones[1]] << ", " << found_tones[2] << " -> " << totte[found_tones[2]] << endl;
		cout << found_tones[3] << ", " << found_tones[4] << ", " << "Squelch: " << (squelch * found_tones[6]) << " (" << (found_tones[3] > (squelch * found_tones[6])) << ")" << endl << endl;
	}

	if(false) { // DEBUG
		cout << "Tone index: " << found_tones[0] << " above squelch: " << (found_tones[3] > (squelch * found_tones[6])) << endl;
	}

	// Energielevel passen nicht (hier ist der Energielevel des gefundenen Tons kleiner als 40% der Gesamtenergie, zu geringer Rauschabstand)
	//if ((tote * 0.4) > totte[index1]) return -1;

	return found_tones;
}

/**
 * @brief finds maximum energy from energies matrix given by MonitorModuleZVEI::process_block()
 * @param totte energies matrix created in MonitorModuleZVEI::process_block()
 * @return index pointing to frequency holding maximum energy/-1 if problem/filter
 */
int MonitorModuleZVEI::find_max_index(const float *totte, int index1, int index2)
{

	float en = 0;
	int index = -1;
	int i;

	/*	Ermitteln des Index' fuer den (erst-, zweit-, dritt-) groessten Eintrag	*/
	for (i = 0; i < (int)(sizeof(zvei_freq)/sizeof(zvei_freq[0])); i++) {
		if (totte[i] > en && i != index1 && i != index2){
			en = totte[i];
			index = i;
		}
	}

/*	en *= 0.25; // sirenenton ab 0.8 detektiert - Gruetze irgendwo/Algorithmus sinnvoll?

	for (i = 0; i < 16; i++) {
		if (index != i && totte[i] > en) return -1;
	} */

	return index;
}

/**
 * @brief finds a digit out of o block of seven buffers; must be same digit four times following for detection
 */
int MonitorModuleZVEI::fuzzyseven() {
	int tone0count = 0;
	int fail = 0;
	int tone0 = detected_seven[(seven_count + 1) % 7][0];

	if(debugmodus > 5) {
		cout << endl;
		for(int i=0; i<7; i++) {
				cout << detected_seven[(seven_count + i + 1) % 7][0] << " ";
		}
	}

	if(detected_seven[(seven_count + 1) % 7][0] == -1) {
		return -1; // deleted entry, already being detected
	}

	if(detected_seven[(seven_count + 1) % 7][3] < (squelch * detected_seven[(seven_count + 1) % 7][6])) {
		if(debugmodus > 3) {
			cout << "SQUELCH (" << detected_seven[(seven_count + 1) % 7][0] << ")!" << endl;
		}
		return -1; // Rauschsperre zu
	}

	for(int i = 0; i < 5; i++) {
		if(detected_seven[(seven_count + i + 1) % 7][0] == tone0) {
			tone0count++;
		} else {
			fail++;
		}
		if(debugmodus > 6) {
			cout << "tone0count: " << tone0count << " " << "(" << tone0 <<  ")";
		}
		if(tone0count == 4) {
			return tone0;
		}
	}
	return -1;
}

/**
 * @brief checks zvei tones for correctness
 */
bool MonitorModuleZVEI::zvei_ok() {

	// Geloeschte Folge oder Pause in der Tonfolge:
	for(unsigned int i = 0; i < maxlength; i++) {
		if(zvei_folge[i] == -1 || zvei_folge[i] == -2) {
			return false;
		}
	}

	// Fehlerfall: Doppeleintraege
	for(int i = 0; i < 4; i++) {
		if(zvei_folge[i] == zvei_folge[i+1]) {
			return false;
		}
	}

	// sonst: ok.
	return true;
}

/**
 * @brief output alarm/ZVEI-Tonfolge to connected clients (NO storing of data!)
 * @param Adresse ZVEI-Tonfolge
 * @param typ alarm type [0|1|2]
 * @param Text free text (human readable type)
 */
void MonitorModuleZVEI::DisplayResult(std::string Adresse,int typ, std::string Text)
{
	std::string alarmTypString ;
	std::string jetzt ;
	char dateStr[9];
	char timeStr[9];

	alarmTypString = convertIntToString(typ) ;

	// aktuelle Uhrzeit holen (Klartext & unix timestamp)
	currentTime(jetzt) ;
	struct tm* tm_time= localtime(&m_time) ;
	// FIXME warum nur ein zweistelliges Jahr?
	strftime(dateStr,9,"%d.%m.%y" ,tm_time) ;
	strftime(timeStr,9,"%H:%M:%S" ,tm_time) ;

	ModuleResultBase *pRes =new ModuleResultBase() ;

	pRes->set("timestamp",jetzt);
	pRes->set("uhrzeit",timeStr) ;
	pRes->set("datum",dateStr) ;
	pRes->set("servernamehex",m_serverNameHex);
	pRes->set("channelnamehex",m_channelNameHex);
	pRes->set("channelnum",convertIntToString(m_iChannelNum));

	pRes->set("typ","zvei");
	pRes->set("zvei",Adresse) ;
	pRes->set("weckton",alarmTypString) ;
	pRes->set("text",Text) ;
	pRes->Dump();
	
	GlobalDispatcher->addResult(pRes) ;
}


/**
 * @brief output alarm/ZVEI-Tonfolge to some storage engine (NO displaying!)
 * @param Adresse ZVEI-Tonfolge
 * @param typ alarm type [0|1|2]
 * @param text free text (human readable type)
 */
void MonitorModuleZVEI::StoreResult(std::string Adresse,int typ,  std::string text)
{

}
