189 lines
6.2 KiB
C++
189 lines
6.2 KiB
C++
#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<len; n++) {
|
|
// Vlastní Goertzelův algoritmus.
|
|
int q0 = coeff * q1;
|
|
// pokud byl coeff zvětšen, je třeba to tu zase zmenšit
|
|
q0 >>= 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;
|
|
}
|