diff --git a/firmware/application/external/subcarrx/ui_subcar.cpp b/firmware/application/external/subcarrx/ui_subcar.cpp index 8d075c9d9..7b88ec740 100644 --- a/firmware/application/external/subcarrx/ui_subcar.cpp +++ b/firmware/application/external/subcarrx/ui_subcar.cpp @@ -91,6 +91,7 @@ SubCarView::SubCarView(NavigationView& nav) &button_clear_list, &check_log, &labels, + &options_mode, &recent_entries_view}); baseband::run_prepared_image(portapack::memory::map::m4_code.base()); @@ -114,11 +115,17 @@ SubCarView::SubCarView(NavigationView& nav) recent_entries_view.on_select = [this](const SubCarRecentEntry& entry) { nav_.push(entry); }; - baseband::set_subghzd_config(0, receiver_model.sampling_rate()); // 0=am - receiver_model.enable(); + + options_mode.on_change = [this](size_t, int32_t v) { + modulation = v; + chThdSleepMilliseconds(100); // wait for the baseband thread to process the previous config, to avoid glitchy output when switching modes + baseband::set_subghzd_config(modulation, receiver_model.sampling_rate()); + }; signal_token_tick_second = rtc_time::signal_tick_second += [this]() { on_tick_second(); }; + options_mode.set_selected_index(modulation, true); + receiver_model.enable(); } void SubCarView::on_tick_second() { @@ -176,6 +183,8 @@ const char* SubCarView::getSensorTypeName(FPROTO_SUBCAR_SENSOR type) { return "Fiat V0"; case FPC_BMWV0: return "BMW V0"; + /* case FPC_KIAV6: + return "Kia V6";*/ case FPC_Invalid: default: @@ -491,6 +500,13 @@ void SubCarRecentEntryDetailView::parseProtocol() { btn = to_string_dec_uint(button); } + /*if (entry_.sensorType == FPC_KIAV6) { + // not decrypted! + serial = 0; + btn = "?"; + cnt = 0; + }*/ + return; } diff --git a/firmware/application/external/subcarrx/ui_subcar.hpp b/firmware/application/external/subcarrx/ui_subcar.hpp index a309fffa1..5fd9af62e 100644 --- a/firmware/application/external/subcarrx/ui_subcar.hpp +++ b/firmware/application/external/subcarrx/ui_subcar.hpp @@ -116,25 +116,27 @@ class SubCarView : public View { 4'000'000 /* sampling rate */, ReceiverModel::Mode::AMAudio}; bool logging = false; + uint8_t modulation = 0; app_settings::SettingsManager settings_{ "rx_subcar", app_settings::Mode::RX, { {"log"sv, &logging}, + {"modulationmode"sv, &modulation}, }}; SubCarRecentEntries recent{}; RFAmpField field_rf_amp{ - {13 * 8, UI_POS_Y(0)}}; + {UI_POS_X(13), UI_POS_Y(0)}}; LNAGainField field_lna{ - {15 * 8, UI_POS_Y(0)}}; + {UI_POS_X(15), UI_POS_Y(0)}}; VGAGainField field_vga{ - {18 * 8, UI_POS_Y(0)}}; + {UI_POS_X(18), UI_POS_Y(0)}}; RSSI rssi{ - {21 * 8, 0, UI_POS_WIDTH_REMAINING(24), 4}}; + {UI_POS_X(21), 0, UI_POS_WIDTH_REMAINING(24), 4}}; Channel channel{ - {21 * 8, 5, UI_POS_WIDTH_REMAINING(24), 4}, + {UI_POS_X(21), 5, UI_POS_WIDTH_REMAINING(24), 4}, }; RxFrequencyField field_frequency{ {UI_POS_X(0), UI_POS_Y(0)}, @@ -143,18 +145,22 @@ class SubCarView : public View { SignalToken signal_token_tick_second{}; Button button_clear_list{ - {0, 16, 7 * 8, 32}, + {UI_POS_X(0), UI_POS_Y(1), UI_POS_WIDTH(7), UI_POS_HEIGHT(2)}, "Clear"}; Checkbox check_log{ - {10 * 8, 18}, + {UI_POS_X(8), UI_POS_Y(1)}, 3, "Log", true}; Labels labels{ - {{UI_POS_X_RIGHT(14), UI_POS_Y(1)}, "no fm yet :(", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(15), UI_POS_Y(1)}, "Mode:", Theme::getInstance()->fg_light->foreground}, }; + ui::OptionsField options_mode{ + {UI_POS_X(22), UI_POS_Y(1)}, + 3, + {{"AM", 0}, {"FM", 1}}}; static constexpr auto header_height = 3 * 16; @@ -198,16 +204,16 @@ class SubCarRecentEntryDetailView : public View { std::string btn = ""; uint32_t cnt = SD_NO_CNT; - Text text_type{{UI_POS_X(0), 1 * 16, 15 * 8, 16}, "?"}; - Text text_id{{6 * 8, 2 * 16, 10 * 8, 16}, "?"}; + Text text_type{{UI_POS_X(0), UI_POS_Y(1), UI_POS_WIDTH(15), UI_POS_HEIGHT(1)}, "?"}; + Text text_id{{UI_POS_X(6), UI_POS_Y(2), UI_POS_WIDTH(10), UI_POS_HEIGHT(1)}, "?"}; Console console{ - {0, 4 * 16, screen_width, screen_height - (4 * 16) - 36}}; + {UI_POS_X(0), UI_POS_Y(4), UI_POS_MAXWIDTH, screen_height - (4 * 16) - 36}}; Labels labels{ {{UI_POS_X(0), UI_POS_Y(0)}, "Type:", Theme::getInstance()->fg_light->foreground}, - {{UI_POS_X(0), 2 * 16}, "Serial: ", Theme::getInstance()->fg_light->foreground}, - {{UI_POS_X(0), 3 * 16}, "Data:", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(0), UI_POS_Y(2)}, "Serial: ", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(0), UI_POS_Y(3)}, "Data:", Theme::getInstance()->fg_light->foreground}, }; Button button_done{ diff --git a/firmware/baseband/fprotos/c-kia_v6.hpp b/firmware/baseband/fprotos/c-kia_v6.hpp new file mode 100644 index 000000000..49e4167f6 --- /dev/null +++ b/firmware/baseband/fprotos/c-kia_v6.hpp @@ -0,0 +1,204 @@ +#pragma once +#include "subcarbase.hpp" +#include + +typedef enum { + KiaV6DecoderStepReset = 0, + KiaV6DecoderStepWaitFirstHigh, + KiaV6DecoderStepCountPreamble, + KiaV6DecoderStepWaitLongHigh, + KiaV6DecoderStepData, +} KiaV6DecoderStep; + +#define KIA_V6_XOR_MASK_LOW 0x84AF25FB +#define KIA_V6_XOR_MASK_HIGH 0x638766AB + +class FProtoSubCarKiaV6 : public FProtoSubCarBase { + public: + FProtoSubCarKiaV6() { + sensorType = FPC_KIAV6; + te_short = 200; + te_long = 400; + te_delta = 100; + min_count_bit_for_found = 144; + } + + void feed(bool level, uint32_t duration) { + uint32_t uVar4, uVar5; + ManchesterEvent event; + bool data_bit; + uint8_t bit_count_inc; + uint32_t step_value; + + switch (parser_step) { + case KiaV6DecoderStepReset: // case 0 + if (level == 0) { + return; + } + if (DURATION_DIFF(duration, te_short) < + te_delta) { + parser_step = KiaV6DecoderStepWaitFirstHigh; + te_last = duration; + header_count = 0; + FProtoGeneral::manchester_advance( + manchester_state, + ManchesterEventReset, + &manchester_state, + NULL); + } + return; + + case KiaV6DecoderStepWaitFirstHigh: { // case 1 + if (level != 0) { + return; + } + uint32_t diff_short = DURATION_DIFF(duration, te_short); + uint32_t diff_long = DURATION_DIFF(duration, te_long); + + uint32_t diff = (diff_long < diff_short) ? diff_long : diff_short; + + if (diff_long < te_delta && diff_long < diff_short) { + if (header_count >= 0x259) { // 601 decimal + header_count = 0; + te_last = duration; + parser_step = KiaV6DecoderStepWaitLongHigh; + return; + } + } + + if (diff >= te_delta) { + step_value = KiaV6DecoderStepReset; + goto LAB_reset; + } + + if (DURATION_DIFF(te_last, te_short) < + te_delta) { + te_last = duration; + header_count++; + return; + } else { + step_value = KiaV6DecoderStepReset; + goto LAB_reset; + } + } + case KiaV6DecoderStepWaitLongHigh: { // case 2 + if (level == 0) { + step_value = KiaV6DecoderStepReset; + goto LAB_reset; + } + uint32_t diff_long_check = DURATION_DIFF(duration, te_long); + uint32_t diff_short_check = DURATION_DIFF(duration, te_short); + + if (diff_long_check >= te_delta) { + if (diff_short_check >= te_delta) { + step_value = KiaV6DecoderStepReset; + goto LAB_reset; + } + } + + if (DURATION_DIFF(te_last, te_long) >= + te_delta) { + step_value = KiaV6DecoderStepReset; + goto LAB_reset; + } + decode_data = 0; + decode_count_bit = 0; + + subghz_protocol_blocks_add_bit(1); + subghz_protocol_blocks_add_bit(1); + subghz_protocol_blocks_add_bit(0); + subghz_protocol_blocks_add_bit(1); + + data_part1_low = (uint32_t)(decode_data & 0xFFFFFFFF); + data_part1_high = (uint32_t)((decode_data >> 32) & 0xFFFFFFFF); + bit_count = decode_count_bit; + + parser_step = KiaV6DecoderStepData; + return; + } + case KiaV6DecoderStepData: // case 3 + if (DURATION_DIFF(duration, te_short) < + te_delta) { + event = (ManchesterEvent)((level & 0x7F) << 1); + goto manchester_process; + } else if ( + DURATION_DIFF(duration, te_long) < + te_delta) { + event = (ManchesterEvent)(level ? 6 : 4); + goto manchester_process; + } + step_value = KiaV6DecoderStepReset; + goto LAB_reset; + + manchester_process: + if (FProtoGeneral::manchester_advance( + manchester_state, event, &manchester_state, &data_bit)) { + uVar4 = data_part1_low; + uVar5 = (uVar4 << 1) | (data_bit ? 1 : 0); + + uint32_t carry = (uVar4 >> 31) & 1; + uVar4 = (data_part1_high << 1) | carry; + + data_part1_low = uVar5; + data_part1_high = uVar4; + + decode_data = ((uint64_t)uVar4 << 32) | uVar5; + + bit_count_inc = bit_count + 1; + bit_count = bit_count_inc; + + if (bit_count_inc == 0x40) { + // stored_part1_low = ~uVar5; + // stored_part1_high = ~uVar4; + data_part1_low = 0; + data_part1_high = 0; + } else if (bit_count_inc == 0x80) { + // stored_part2_low = ~uVar5; + // stored_part2_high = ~uVar4; + data_part1_low = 0; + data_part1_high = 0; + } + } + + te_last = duration; + + if (bit_count != min_count_bit_for_found) { + return; + } + data_count_bit = min_count_bit_for_found; + // data_part3 = ~((uint16_t)data_part1_low); + + // kia_v6_decrypt(); --won't + decode_data = data_part1_low | ((uint64_t)data_part1_high << 32); + if (callback) { + callback(this); + } + + data_part1_low = 0; + data_part1_high = 0; + bit_count = 0; + step_value = KiaV6DecoderStepReset; + goto LAB_reset; + + default: + return; + } + + LAB_reset: + parser_step = step_value; + return; + } + + uint8_t bit_count = 0; + + uint16_t header_count = 0; + ManchesterState manchester_state = ManchesterStateMid1; + uint32_t data_part1_low = 0; + uint32_t data_part1_high = 0; + + // uint32_t stored_part1_low = 0; + // uint32_t stored_part1_high = 0; + // uint32_t stored_part2_low = 0; + // uint32_t stored_part2_high = 0; + // uint16_t data_part3 = 0; +}; diff --git a/firmware/baseband/fprotos/s-secplus_v1.hpp b/firmware/baseband/fprotos/s-secplus_v1.hpp index 98413486a..ce34fd634 100644 --- a/firmware/baseband/fprotos/s-secplus_v1.hpp +++ b/firmware/baseband/fprotos/s-secplus_v1.hpp @@ -76,7 +76,7 @@ class FProtoSubGhzDSecPlusV1 : public FProtoSubGhzDBase { packet_accepted |= SECPLUS_V1_PACKET_2_ACCEPTED; if (packet_accepted == (SECPLUS_V1_PACKET_1_ACCEPTED | SECPLUS_V1_PACKET_2_ACCEPTED)) { - // subghz_protocol_secplus_v1_decode(); // disabled doe to lack of flash + // subghz_protocol_secplus_v1_decode(); // disabled due to lack of flash // controller // uint32_t fixed = (data >> 32) & 0xFFFFFFFF; // cnt = data & 0xFFFFFFFF; diff --git a/firmware/baseband/fprotos/subcarprotos.hpp b/firmware/baseband/fprotos/subcarprotos.hpp index d88e8d69f..31272ec0a 100644 --- a/firmware/baseband/fprotos/subcarprotos.hpp +++ b/firmware/baseband/fprotos/subcarprotos.hpp @@ -21,6 +21,7 @@ So include here the .hpp, and add a new element to the protos vector in the cons #include "c-ford_v0.hpp" #include "c-fiat_v0.hpp" #include "c-bmw_v0.hpp" +// #include "c-kia_v6.hpp" #ifndef __FPROTO_PROTOLISTCAR_H__ #define __FPROTO_PROTOLISTCAR_H__ @@ -42,6 +43,7 @@ class SubCarProtos : public FProtoListGeneral { protos[FPC_FORDV0] = new FProtoSubCarFordV0(); protos[FPC_FIATV0] = new FProtoSubCarFiatV0(); protos[FPC_BMWV0] = new FProtoSubCarBMWV0(); + // protos[FPC_KIAV6] = new FProtoSubCarKiaV6(); //-- disabled, due to whole encrypted. for (uint8_t i = 0; i < FPC_COUNT; ++i) { if (protos[i] != NULL) protos[i]->setCallback(callbackTarget); diff --git a/firmware/baseband/fprotos/subcartypes.hpp b/firmware/baseband/fprotos/subcartypes.hpp index 3b01cdbc7..052ecf2cd 100644 --- a/firmware/baseband/fprotos/subcartypes.hpp +++ b/firmware/baseband/fprotos/subcartypes.hpp @@ -8,9 +8,6 @@ These values must be present on the protocol's constructor, like FProtoWeatherAc Also it must have a switch-case element in the getSubGhzDSensorTypeName() function, to display it's name. */ -#define FPM_AM 0 -#define FPM_FM 1 - enum FPROTO_SUBCAR_SENSOR : uint8_t { FPC_Invalid = 0, FPC_SUZUKI = 1, @@ -24,6 +21,8 @@ enum FPROTO_SUBCAR_SENSOR : uint8_t { FPC_FORDV0 = 9, FPC_FIATV0 = 10, FPC_BMWV0 = 11, + // FPC_KIAV6 = 12, //disabled, due to whole encrypted. + // FPC_PSA = 13, // IS whole encrypted FPC_COUNT }; diff --git a/firmware/baseband/proc_subcar.cpp b/firmware/baseband/proc_subcar.cpp index 846266d99..a604d774f 100644 --- a/firmware/baseband/proc_subcar.cpp +++ b/firmware/baseband/proc_subcar.cpp @@ -25,14 +25,6 @@ #include "portapack_shared_memory.hpp" #include "event_m4.hpp" -static inline int get_quadrant(int16_t i, int16_t q) { - if (i >= 0) { - return (q >= 0) ? 0 : 3; - } else { - return (q >= 0) ? 1 : 2; - } -} - void SubCarProcessor::execute(const buffer_c8_t& buffer) { if (!configured) return; @@ -46,10 +38,6 @@ void SubCarProcessor::execute(const buffer_c8_t& buffer) { const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer); // Input:512 complex/2 (decim factor) = 256_output complex ( 512 I/Q samples) feed_channel_stats(decim_1_out); - // for fm - const int32_t DC_ALPHA = 5; // Auto-centering speed - int32_t buffer_rotation_sum = 0; - for (size_t i = 0; i < decim_1_out.count; i++) { // am threshold = (low_estimate + high_estimate) / 2; @@ -57,126 +45,103 @@ void SubCarProcessor::execute(const buffer_c8_t& buffer) { int16_t re = decim_1_out.p[i].real(); int16_t im = decim_1_out.p[i].imag(); uint32_t mag = ((uint32_t)re * (uint32_t)re) + ((uint32_t)im * (uint32_t)im); - mag = (mag >> 10); - int32_t const ook_low_delta = mag - low_estimate; - bool meashl = currentHiLow; - if (sig_state == STATE_IDLE) { - if (mag > (threshold + hysteresis)) { // just become high - meashl = true; - sig_state = STATE_PULSE; - numg = 0; - } else { - meashl = false; // still low - low_estimate += ook_low_delta / OOK_EST_LOW_RATIO; - low_estimate += ((ook_low_delta > 0) ? 1 : -1); // Hack to compensate for lack of fixed-point scaling - // Calculate default OOK high level estimate - high_estimate = 1.35 * low_estimate; // Default is a ratio of low level - high_estimate = std::max(high_estimate, min_high_level); - high_estimate = std::min(high_estimate, (uint32_t)OOK_MAX_HIGH_LEVEL); - } - - } else if (sig_state == STATE_PULSE) { - ++numg; - if (numg > 100) numg = 100; - if (mag < (threshold - hysteresis)) { - // check if really a bad value - if (numg < 3) { - // susp - sig_state = STATE_GAP; - } else { + if (modulation == 0) { + int32_t const ook_low_delta = mag - low_estimate; + bool meashl = currentHiLow; + if (sig_state == STATE_IDLE) { + if (mag > (threshold + hysteresis)) { // just become high + meashl = true; + sig_state = STATE_PULSE; numg = 0; - sig_state = STATE_GAP_START; + } else { + meashl = false; // still low + low_estimate += ook_low_delta / OOK_EST_LOW_RATIO; + low_estimate += ((ook_low_delta > 0) ? 1 : -1); // Hack to compensate for lack of fixed-point scaling + // Calculate default OOK high level estimate + high_estimate = 1.35 * low_estimate; // Default is a ratio of low level + high_estimate = std::max(high_estimate, min_high_level); + high_estimate = std::min(high_estimate, (uint32_t)OOK_MAX_HIGH_LEVEL); + } + + } else if (sig_state == STATE_PULSE) { + ++numg; + if (numg > 100) numg = 100; + if (mag < (threshold - hysteresis)) { + // check if really a bad value + if (numg < 3) { + // susp + sig_state = STATE_GAP; + } else { + numg = 0; + sig_state = STATE_GAP_START; + } + meashl = false; // low + } else { + high_estimate += mag / OOK_EST_HIGH_RATIO - high_estimate / OOK_EST_HIGH_RATIO; + high_estimate = std::max(high_estimate, min_high_level); + high_estimate = std::min(high_estimate, (uint32_t)OOK_MAX_HIGH_LEVEL); + meashl = true; // still high + } + } else if (sig_state == STATE_GAP_START) { + ++numg; + if (mag > (threshold + hysteresis)) { // New pulse? + sig_state = STATE_PULSE; + meashl = true; + } else if (numg >= 3) { + sig_state = STATE_GAP; + meashl = false; // gap + } + } else if (sig_state == STATE_GAP) { + ++numg; + if (mag > (threshold + hysteresis)) { // New pulse? + numg = 0; + sig_state = STATE_PULSE; + meashl = true; + } else { + meashl = false; + } + } + + if (meashl == currentHiLow && currentDuration < 30'000'000) // allow pass 'end' signal + { + currentDuration += nsPerDecSamp; + } else { // called on change, so send the last duration and dir. + if (currentDuration >= 30'000'000) sig_state = STATE_IDLE; + if (protoList) protoList->feed(currentHiLow, currentDuration / 1000); + currentDuration = nsPerDecSamp; + currentHiLow = meashl; + } + } + if (modulation == 1) { + int32_t discrim = ((int32_t)im * fm_state.last_re) - ((int32_t)re * fm_state.last_im); + fm_state.last_re = re; + fm_state.last_im = im; + fm_state.smoothed_discrim += (discrim - fm_state.smoothed_discrim) >> 4; + + // --- FM Part (Simple 2-FSK) --- + if (mag > (threshold / 2)) { + const int32_t fm_hysteresis = 2000; + bool new_level = fm_state.current_logic_level; + if (fm_state.smoothed_discrim > fm_hysteresis) { + new_level = true; + } else if (fm_state.smoothed_discrim < -fm_hysteresis) { + new_level = false; + } + if (new_level == fm_state.current_logic_level) { + fm_state.buffer_count++; + } else { + int32_t duration_us = (fm_state.buffer_count * nsPerDecSamp) / 1000; + if (duration_us > 15) { + if (protoList) protoList->feed(fm_state.current_logic_level, duration_us); + } + fm_state.current_logic_level = new_level; + fm_state.buffer_count = 1; } - meashl = false; // low } else { - high_estimate += mag / OOK_EST_HIGH_RATIO - high_estimate / OOK_EST_HIGH_RATIO; - high_estimate = std::max(high_estimate, min_high_level); - high_estimate = std::min(high_estimate, (uint32_t)OOK_MAX_HIGH_LEVEL); - meashl = true; // still high - } - } else if (sig_state == STATE_GAP_START) { - ++numg; - if (mag > (threshold + hysteresis)) { // New pulse? - sig_state = STATE_PULSE; - meashl = true; - } else if (numg >= 3) { - sig_state = STATE_GAP; - meashl = false; // gap - } - } else if (sig_state == STATE_GAP) { - ++numg; - if (mag > (threshold + hysteresis)) { // New pulse? - numg = 0; - sig_state = STATE_PULSE; - meashl = true; - } else { - meashl = false; + fm_state.buffer_count = 0; } } - - if (meashl == currentHiLow && currentDuration < 30'000'000) // allow pass 'end' signal - { - currentDuration += nsPerDecSamp; - } else { // called on change, so send the last duration and dir. - if (currentDuration >= 30'000'000) sig_state = STATE_IDLE; - if (protoList) protoList->feed(currentHiLow, currentDuration / 1000); - currentDuration = nsPerDecSamp; - currentHiLow = meashl; - } - - // fm part: -- NOT WORKING!!!! TODO FIX. AI code ;) - int current_quad = get_quadrant(re, im); - // Calculate Step (Current - Previous) - int diff = current_quad - fm_state.prev_quad; - // Handle Wrap-Around (crossing from Q3 to Q0 or Q0 to Q3) - // 3 -> 0 should be +1 (CCW) - // 0 -> 3 should be -1 (CW) - if (diff == -3) - diff = 1; - else if (diff == 3) - diff = -1; - // Update History - fm_state.prev_quad = current_quad; - // Accumulate Rotation - buffer_rotation_sum += diff; - } - - // fm finish: - // 3. AUTO-CENTERING (DC BLOCKER) - // Even with quadrant counting, "drift" (hand effect) makes the wheel spin - // faster or slower. We need to subtract the average speed. - // Update our "Average Speed" estimate - // Note: buffer_rotation_sum is roughly proportional to frequency. - fm_state.dc_offset = (fm_state.dc_offset * ((1 << DC_ALPHA) - 1) + buffer_rotation_sum) >> DC_ALPHA; - // Remove the drift - int32_t centered_rotation = buffer_rotation_sum - fm_state.dc_offset; - // 4. LOW PASS FILTER - const int32_t LPF_ALPHA = 4; - fm_state.smoothed_error = (fm_state.smoothed_error * (LPF_ALPHA - 1) + centered_rotation) / LPF_ALPHA; - // 5. DECISION LOGIC - // Threshold is small now because we are counting quadrant steps. - // Max steps per buffer (256 samples) is 256. - // Typical FSK deviation might give you +/- 10 to 50 steps per buffer. - const int32_t THRESHOLD = 3; - bool new_level = fm_state.current_logic_level; - if (fm_state.smoothed_error > THRESHOLD) { - new_level = true; - } else if (fm_state.smoothed_error < -THRESHOLD) { - new_level = false; - } - // 6. TIMING OUTPUT - if (new_level == fm_state.current_logic_level) { - fm_state.buffer_count++; - } else { - // Output pulse duration - int32_t duration_us = fm_state.buffer_count * 512; - - if (duration_us > 250) { - if (protoListFm) protoListFm->feed(fm_state.current_logic_level, duration_us); - } - fm_state.current_logic_level = new_level; - fm_state.buffer_count = 1; } } @@ -189,6 +154,14 @@ void SubCarProcessor::configure(const SubGhzFPRxConfigureMessage& message) { // constexpr size_t decim_0_output_fs = baseband_fs / decim_0.decimation_factor; //unused // constexpr size_t decim_1_output_fs = decim_0_output_fs / decim_1.decimation_factor; //unused + if (modulation != message.modulation) { + // reload protos to reset them all + if (protoList) { + delete protoList; + } + protoList = new SubCarProtos(); + } + modulation = message.modulation; baseband_fs = message.sampling_rate; baseband_thread.set_sampling_rate(baseband_fs); nsPerDecSamp = 1'000'000'000 / baseband_fs * 8; // Scaled it due to less array buffer sampes due to /8 decimation. 250 nseg (4Mhz) * 8 diff --git a/firmware/baseband/proc_subcar.hpp b/firmware/baseband/proc_subcar.hpp index 9d16e79ba..6c923ce11 100644 --- a/firmware/baseband/proc_subcar.hpp +++ b/firmware/baseband/proc_subcar.hpp @@ -56,8 +56,8 @@ class SubCarProcessor : public BasebandProcessor { uint32_t low_estimate = 100; uint32_t high_estimate = 12000; uint32_t min_high_level = 10; - uint8_t numg = 0; // count of matched signals to filter spikes - size_t baseband_fs = 0; // will be set later by configure message + uint8_t numg = 0; // count of matched signals to filter spikes + size_t baseband_fs = 4'000'000; // will be set later by configure message uint32_t nsPerDecSamp = 0; /* Array Buffer aux. used in decim0 and decim1 IQ c16 signed data ; (decim0 defines the max length of the array) */ @@ -74,20 +74,20 @@ class SubCarProcessor : public BasebandProcessor { uint32_t threshold = 0x0630; bool currentHiLow = false; bool configured{false}; - uint8_t mode = 0; // 0 = am, 1 = fm // fm part: struct DemodFMState { - int prev_quad = 0; // Stores 0, 1, 2, or 3 - int32_t dc_offset = 0; - int32_t smoothed_error = 0; bool current_logic_level = false; uint32_t buffer_count = 0; + int16_t last_re = 0; // Store previous Real sample + int16_t last_im = 0; + int32_t smoothed_discrim = 0; }; DemodFMState fm_state{}; - FProtoListGeneral* protoList = new SubCarProtos(); // holds all the protocols we can parse - FProtoListGeneral* protoListFm = new SubCarProtos(); // holds all the protocols we can parse, but for fm (dupe, bc most of it is dual) + uint8_t modulation = 0; // 0 am, 1 fm + + FProtoListGeneral* protoList = new SubCarProtos(); // holds all the protocols we can parse void configure(const SubGhzFPRxConfigureMessage& message); /* NB: Threads should be the last members in the class definition. */