#include "hdo.h" static constexpr int factor = int (double(1U << 20) * (1.0 / 1330.0) + 0.5); static constexpr int period = 120; // perioda vyhodnocení Goertzelovým algoritmem // pro výpočet dělení použijeme tento union union divu { int32_t val; struct { uint32_t unu : 16; uint32_t res : 4; uint32_t div : 12; }; }; static constexpr const int index_table [] = {19,20,21,22, 24,25,26,27, 29,30,31,32, 34,35,36,37}; unsigned Hdo::Send (uint16_t *const ptr, const unsigned len) { int q2 = 0, q1 = 0; for (unsigned n=0; n>= ISHIFT; // zmenšení pro int q0 += ((int) ptr [n]) - q2; // vlastní výpočet q2 = q1; // posuv o vzorek q1 = q0; // (rekurze) } int rv = q1 * q2; rv *= -coeff; rv >>= ISHIFT; // tady nutno zmenšit tak, jak bylo zvětšeno v calc_coeff() rv += q1 * q1 + q2 * q2; // výkon by byl sqrt (rv), není nutné počítat, napětí stačí data.Write (rv); // dáme do FIFO, vybíráme v main() return len; } void Hdo::pass () { int value; if (!data.Read (value)) return; // DEBUG value cout << value << " \r"; value -= trigger; if (value > 0) led << SW__ON; // LED je zapojená proti VCC else led << SW_OFF; // Konečné vyhodnocení. if (Decode (value, buf1)) { // Telegram OK. HumanRead (buf1, buf2); // Převeď ho do čitelné podoby cout << buf2 << EOL; // Vypíšeme telegram int i = Action (buf2, cmd); // Nakonec proveď akci if (i == +1) relay << true; if (i == -1) relay << false; } } /////////////////////////////////////////////////////////////// int Hdo::Decode(int num, char * str) { int rv = 0; uint32_t cv = 0, bi = 0; switch (status) { case WAIT_FOR_BEGIN: counter = 0; // start telegramu if (num > 0) status = SYNC_PULSE; break; case SYNC_PULSE: counter++; if (num < 0) { // pokles if (counter > SYNC_HI) { // pokud je včas, určuje další časování counter = 0; status = SYNC_SPACE; } else // chyba status = WAIT_FOR_BEGIN; } break; case SYNC_SPACE: counter++; if (num > 0) // vzestup během mezery = chyba status = WAIT_FOR_BEGIN; if (counter > SYNC_LO) { // celá synchronizační mezera counter = -1; // jeden prázdný cyklus suma = 0; bits = 0; status = CORELATE; } break; // Budeme to dělat jako korelaci. Perioda pak nemusí být pevná, // nakonec je to jednodušší a pochopitejnější. case CORELATE: counter++; if (counter <= 0) break; // ten prázdný cyklus (synchronizace, určeno měřením) divu dv; // Tohle je fakticky dělení periodou 1330 ms dv.val = counter * period * factor; bi = dv.div; // index bitu (kolikátá perioda, podíl) cv = dv.res; // 0..15 v periodě (zbytek po dělení) if (bi != bits) { // napřed vyhodnoceni předchozího bits = bi; if (suma > 0) suma = 1; else suma = 0; // output '0' or '1' str [bits - 1] = (char) suma + 0x30; suma = 0; if (bits >= 44) { // TELEGRAM END status = WAIT_FOR_BEGIN; rv = 1; str [bits] = 0; } } // pak korelace if (cv < 14) suma += num; // 0..13 kladná korelace (puls) else suma -= num; // jinak záporná korelace (mezera) break; default : break; } return rv; } void Hdo::HumanRead(const char * src, char * dst) { int tindex, windex = 0; char c, avg; for (tindex = 0; tindex < 44; tindex++) { avg = src [tindex] - 0x30; // Doplním písmenka if (tindex == 0) dst [windex++] = 'A'; if (tindex == 4) dst [windex++] = 'B'; if (tindex == 12) { dst [windex++] = ' '; dst [windex++] = 'D'; dst [windex++] = 'P'; dst [windex++] = ':'; } // Skupina A if (tindex < 4) { if (avg) c = '1' + tindex; else c = '-'; dst [windex++] = c; } // Skupina B else if (tindex < 12) { if (avg) c = '1' + tindex - 4; else c = '-'; dst [windex++] = c; } // Dvojpovel else { // skupiny po 4 oddělit mezerami pro lepší čitelnost if (!((tindex+4) % 8)) dst [windex++] = ' '; if (tindex % 2) { // bit "vypnuto" na tindex - to až následně if (dst [windex] == '-') { // zapnuto nebylo if (avg) dst [windex] = 'Z'; // tedy je zapnuto } else { // bylo zapnuto if (avg) dst [windex] = 'E'; // tedy je chyba - nemůže být obojí } windex++; } else { // bit "zapnuto" na tindex - to je první !!! if (avg) dst [windex] = 'V'; // je vypnuto else dst [windex] = '-'; // ještě se uvidí } } } dst [windex] = 0; } int Hdo::Action(char * tlg, const char * command) { int i, j; char c; i = command [1] - '1'; // An if ((i < 0) || (i > 3)) return 0; // chyba if (tlg [i+1] == '-') return 0; // není pro mne i = command [3] - '1'; // Bn if ((i < 0) || (i > 7)) return 0; // chyba if (tlg [i+6] == '-') return 0; // není pro mne i = command [6] - '0'; // DPn j = command [7]; // DPn+1 if (j) { j -= '0'; i *= 10; i += j; } // v i je číslo za DP if ((i < 1) || (i > 16)) return 0; // chyba i--; // index bude o 1 menší j = index_table [i]; // v telegramu na pozici j c = tlg [j]; // je písmeno if (c == 'Z') return +1; // Z - potom zapni if (c == 'V') return -1; // V - vypni return 0; }