Files
mayhem-firmware/firmware/baseband/fprotos/c-vw.hpp
T
2025-12-21 11:21:55 +01:00

237 lines
7.6 KiB
C++

#pragma once
#include "subcarbase.hpp"
typedef enum {
VwDecoderStepReset = 0,
VwDecoderStepFoundSync,
VwDecoderStepFoundStart1,
VwDecoderStepFoundStart2,
VwDecoderStepFoundStart3,
VwDecoderStepFoundData,
} VwDecoderStep;
class FProtoSubCarVW : public FProtoSubCarBase {
public:
FProtoSubCarVW() {
sensorType = FPC_VW;
te_short = 500;
te_long = 1000;
te_delta = 130;
min_count_bit_for_found = 80;
}
uint8_t vw_get_bit_index(uint8_t bit) {
uint8_t bit_index = 0;
if (bit < 72 && bit >= 8) {
// use generic.data (bytes 1-8)
bit_index = bit - 8;
} else {
// use data_2
if (bit >= 72) {
bit_index = bit - 64; // byte 0 = type
}
if (bit < 8) {
bit_index = bit; // byte 9 = check digit
}
bit_index |= 0x80; // mark for data_2
}
return bit_index;
}
void vw_add_bit(bool level) {
if (data_count_bit >= min_count_bit_for_found) {
return;
}
uint8_t bit_index_full = min_count_bit_for_found - 1 - data_count_bit;
uint8_t bit_index_masked = vw_get_bit_index(bit_index_full);
uint8_t bit_index = bit_index_masked & 0x7F;
if (bit_index_masked & 0x80) {
// use data_2
if (level) {
decode_data2 |= (1ULL << bit_index);
} else {
decode_data2 &= ~(1ULL << bit_index);
}
} else {
// use data
if (level) {
decode_data |= (1ULL << bit_index);
} else {
decode_data &= ~(1ULL << bit_index);
}
}
data_count_bit++;
if (data_count_bit >= min_count_bit_for_found) {
if (callback) {
callback(this);
}
}
}
void subghz_protocol_decoder_vw_reset() {
parser_step = VwDecoderStepReset;
data_count_bit = 0;
decode_data = 0;
decode_data2 = 0;
manchester_state = ManchesterStateMid1;
}
bool vw_manchester_advance(
ManchesterState state,
ManchesterEvent event,
ManchesterState* next_state,
bool* data) {
bool result = false;
ManchesterState new_state = ManchesterStateMid1;
if (event == ManchesterEventReset) {
new_state = ManchesterStateMid1;
} else if (state == ManchesterStateMid0 || state == ManchesterStateMid1) {
if (event == ManchesterEventShortHigh) {
new_state = ManchesterStateStart1;
} else if (event == ManchesterEventShortLow) {
new_state = ManchesterStateStart0;
} else {
new_state = ManchesterStateMid1;
}
} else if (state == ManchesterStateStart1) {
if (event == ManchesterEventShortLow) {
new_state = ManchesterStateMid1;
result = true;
if (data)
*data = true;
} else if (event == ManchesterEventLongLow) {
new_state = ManchesterStateStart0;
result = true;
if (data)
*data = true;
} else {
new_state = ManchesterStateMid1;
}
} else if (state == ManchesterStateStart0) {
if (event == ManchesterEventShortHigh) {
new_state = ManchesterStateMid0;
result = true;
if (data)
*data = false;
} else if (event == ManchesterEventLongHigh) {
new_state = ManchesterStateStart1;
result = true;
if (data)
*data = false;
} else {
new_state = ManchesterStateMid1;
}
}
*next_state = new_state;
return result;
}
void feed(bool level, uint32_t duration) {
uint32_t te_med = (te_long + te_short) / 2;
uint32_t te_end = te_long * 5;
ManchesterEvent event = ManchesterEventReset;
switch (parser_step) {
case VwDecoderStepReset:
if (DURATION_DIFF(duration, te_short) < te_delta) {
parser_step = VwDecoderStepFoundSync;
}
break;
case VwDecoderStepFoundSync:
if (DURATION_DIFF(duration, te_short) < te_delta) {
// Stay - sync pattern repeats ~43 times
break;
}
if (level && DURATION_DIFF(duration, te_long) < te_delta) {
parser_step = VwDecoderStepFoundStart1;
break;
}
parser_step = VwDecoderStepReset;
break;
case VwDecoderStepFoundStart1:
if (!level && DURATION_DIFF(duration, te_short) < te_delta) {
parser_step = VwDecoderStepFoundStart2;
break;
}
parser_step = VwDecoderStepReset;
break;
case VwDecoderStepFoundStart2:
if (level && DURATION_DIFF(duration, te_med) < te_delta) {
parser_step = VwDecoderStepFoundStart3;
break;
}
parser_step = VwDecoderStepReset;
break;
case VwDecoderStepFoundStart3:
if (DURATION_DIFF(duration, te_med) < te_delta) {
// Stay - med pattern repeats
break;
}
if (level && DURATION_DIFF(duration, te_short) < te_delta) {
// Start data collection
vw_manchester_advance(
manchester_state,
ManchesterEventReset,
&manchester_state,
NULL);
vw_manchester_advance(
manchester_state,
ManchesterEventShortHigh,
&manchester_state,
NULL);
data_count_bit = 0;
decode_data = 0;
decode_data2 = 0;
parser_step = VwDecoderStepFoundData;
break;
}
parser_step = VwDecoderStepReset;
break;
case VwDecoderStepFoundData:
if (DURATION_DIFF(duration, te_short) < te_delta) {
event = level ? ManchesterEventShortHigh : ManchesterEventShortLow;
}
if (DURATION_DIFF(duration, te_long) < te_delta) {
event = level ? ManchesterEventLongHigh : ManchesterEventLongLow;
}
// Last bit can be arbitrarily long
if (data_count_bit == min_count_bit_for_found - 1 &&
!level && duration > te_end) {
event = ManchesterEventShortLow;
}
if (event == ManchesterEventReset) {
subghz_protocol_decoder_vw_reset();
} else {
bool new_level;
if (vw_manchester_advance(
manchester_state,
event,
&manchester_state,
&new_level)) {
vw_add_bit(new_level);
}
}
break;
}
}
ManchesterState manchester_state = ManchesterStateMid1;
};