diff --git a/firmware/application/apps/ui_subghzd.cpp b/firmware/application/apps/ui_subghzd.cpp index 141608ca..60d304b7 100644 --- a/firmware/application/apps/ui_subghzd.cpp +++ b/firmware/application/apps/ui_subghzd.cpp @@ -35,11 +35,7 @@ void SubGhzDRecentEntryDetailView::update_data() { // set text elements text_type.set(SubGhzDView::getSensorTypeName((FPROTO_SUBGHZD_SENSOR)entry_.sensorType)); text_id.set("0x" + to_string_hex(entry_.id)); - text_temp.set(to_string_decimal(entry_.temp, 2)); - text_hum.set(to_string_dec_uint(entry_.humidity) + "%"); - text_ch.set(to_string_dec_uint(entry_.channel)); - text_batt.set(to_string_dec_uint(entry_.battery_low) + " " + ((entry_.battery_low == 0) ? "OK" : "LOW")); - text_age.set(to_string_dec_uint(entry_.age) + " sec"); + // text_temp.set(to_string_decimal(entry_.temp, 2)); } SubGhzDRecentEntryDetailView::SubGhzDRecentEntryDetailView(NavigationView& nav, const SubGhzDRecentEntry& entry) @@ -49,10 +45,6 @@ SubGhzDRecentEntryDetailView::SubGhzDRecentEntryDetailView(NavigationView& nav, &text_type, &text_id, &text_temp, - &text_hum, - &text_ch, - &text_batt, - &text_age, &labels}); button_done.on_select = [&nav](const ui::Button&) { @@ -92,7 +84,7 @@ SubGhzDView::SubGhzDView(NavigationView& nav) recent_entries_view.on_select = [this](const SubGhzDRecentEntry& entry) { nav_.push(entry); }; - baseband::set_subghzd(0); + baseband::set_subghzd(0); // am receiver_model.enable(); signal_token_tick_second = rtc_time::signal_tick_second += [this]() { on_tick_second(); @@ -107,7 +99,7 @@ void SubGhzDView::on_tick_second() { } void SubGhzDView::on_data(const WeatherDataMessage* data) { - SubGhzDRecentEntry key{data->sensorType, data->id, data->temp, data->humidity, data->channel, data->battery_low}; + SubGhzDRecentEntry key{data->sensorType, data->id}; auto matching_recent = find(recent, key.key()); if (matching_recent != std::end(recent)) { // Found within. Move to front of list, increment counter. @@ -129,6 +121,10 @@ SubGhzDView::~SubGhzDView() { const char* SubGhzDView::getSensorTypeName(FPROTO_SUBGHZD_SENSOR type) { switch (type) { + case FPS_ANSONIC: + return "Ansonic"; + case FPS_PRINCETON: + return "Princeton"; case FPS_Invalid: default: return "Unknown"; @@ -150,20 +146,19 @@ void RecentEntriesTable::draw( line.reserve(30); line = SubGhzDView::getSensorTypeName((FPROTO_SUBGHZD_SENSOR)entry.sensorType); - if (line.length() < 10) { - line += SubGhzDView::pad_string_with_spaces(10 - line.length()); + if (line.length() < 14) { + line += SubGhzDView::pad_string_with_spaces(14 - line.length()); } else { - line = truncate(line, 10); + line = truncate(line, 14); } + // TODO - std::string temp = to_string_decimal(entry.temp, 1); - std::string humStr = to_string_dec_uint(entry.humidity) + "%"; - std::string chStr = to_string_dec_uint(entry.channel); + // std::string idStr = to_string_hex(entry.id); std::string ageStr = to_string_dec_uint(entry.age); - line += SubGhzDView::pad_string_with_spaces(6 - temp.length()) + temp; - line += SubGhzDView::pad_string_with_spaces(5 - humStr.length()) + humStr; - line += SubGhzDView::pad_string_with_spaces(4 - chStr.length()) + chStr; + // line += SubGhzDView::pad_string_with_spaces(6 - id.length()) + temp; + // line += SubGhzDView::pad_string_with_spaces(5 - humStr.length()) + humStr; + // line += SubGhzDView::pad_string_with_spaces(4 - chStr.length()) + chStr; line += SubGhzDView::pad_string_with_spaces(4 - ageStr.length()) + ageStr; line.resize(target_rect.width() / 8, ' '); diff --git a/firmware/application/apps/ui_subghzd.hpp b/firmware/application/apps/ui_subghzd.hpp index 39a35795..65ace46a 100644 --- a/firmware/application/apps/ui_subghzd.hpp +++ b/firmware/application/apps/ui_subghzd.hpp @@ -43,33 +43,19 @@ struct SubGhzDRecentEntry { static constexpr Key invalid_key = 0x0fffffff; // todo calc the invalid all uint8_t sensorType = FPS_Invalid; uint32_t id = 0xFFFFFFFF; - float temp = -273.0f; - uint8_t humidity = 0xFF; - uint8_t battery_low = 0xFF; - uint8_t channel = 0xFF; + uint16_t age = 0; // updated on each seconds, show how long the signal was last seen SubGhzDRecentEntry() {} SubGhzDRecentEntry( uint8_t sensorType, - uint32_t id, - float temp, - uint8_t humidity, - uint8_t channel, - uint8_t battery_low = 0xff) + uint32_t id) : sensorType{sensorType}, - id{id}, - temp{temp}, - humidity{humidity}, - battery_low{battery_low}, - channel{channel} { + id{id} { } Key key() const { - return (((static_cast(temp * 10) & 0xFFFF) << 48) ^ static_cast(id) << 24) | - (static_cast(sensorType) & 0xFF) << 16 | - (static_cast(humidity) & 0xFF) << 8 | - (static_cast(battery_low) & 0xF) << 4 | - (static_cast(channel) & 0xF); + return (static_cast(id) << 32) | + (static_cast(sensorType) & 0xFF) << 0; } void inc_age(int delta) { if (UINT16_MAX - delta > age) age += delta; @@ -156,20 +142,12 @@ class SubGhzDRecentEntryDetailView : public View { SubGhzDRecentEntry entry_{}; Text text_type{{0 * 8, 1 * 16, 15 * 8, 16}, "?"}; Text text_id{{6 * 8, 2 * 16, 10 * 8, 16}, "?"}; - Text text_temp{{6 * 8, 3 * 16, 8 * 8, 16}, "?"}; - Text text_hum{{11 * 8, 4 * 16, 6 * 8, 16}, "?"}; - Text text_ch{{11 * 8, 5 * 16, 6 * 8, 16}, "?"}; - Text text_batt{{11 * 8, 6 * 16, 6 * 8, 16}, "?"}; - Text text_age{{11 * 8, 7 * 16, 6 * 8, 16}, "?"}; + Text text_temp{{6 * 8, 3 * 16, 8 * 8, 7 * 16}, "?"}; Labels labels{ - {{0 * 8, 0 * 16}, "Station type:", Color::light_grey()}, + {{0 * 8, 0 * 16}, "Tpe:", Color::light_grey()}, {{0 * 8, 2 * 16}, "Id: ", Color::light_grey()}, - {{0 * 8, 3 * 16}, "Temp:", Color::light_grey()}, - {{0 * 8, 4 * 16}, "Humidity:", Color::light_grey()}, - {{0 * 8, 5 * 16}, "Channel:", Color::light_grey()}, - {{0 * 8, 6 * 16}, "Battery:", Color::light_grey()}, - {{0 * 8, 7 * 16}, "Age:", Color::light_grey()}, + {{0 * 8, 3 * 16}, "Data:", Color::light_grey()}, }; Button button_done{ diff --git a/firmware/application/apps/ui_weatherstation.cpp b/firmware/application/apps/ui_weatherstation.cpp index 1909c04e..79dd184f 100644 --- a/firmware/application/apps/ui_weatherstation.cpp +++ b/firmware/application/apps/ui_weatherstation.cpp @@ -35,11 +35,26 @@ namespace ui { void WeatherRecentEntryDetailView::update_data() { // set text elements text_type.set(WeatherView::getWeatherSensorTypeName((FPROTO_WEATHER_SENSOR)entry_.sensorType)); - text_id.set("0x" + to_string_hex(entry_.id)); - text_temp.set(weather_units_fahr ? to_string_decimal((entry_.temp * 9 / 5) + 32, 1) + STR_DEGREES_F : to_string_decimal(entry_.temp, 2) + STR_DEGREES_C); - text_hum.set(to_string_dec_uint(entry_.humidity) + "%"); - text_ch.set(to_string_dec_uint(entry_.channel)); - text_batt.set(to_string_dec_uint(entry_.battery_low) + " " + ((entry_.battery_low == 0) ? "OK" : "LOW")); + if (entry_.id != WS_NO_ID) + text_id.set("0x" + to_string_hex(entry_.id)); + else + text_id.set("-"); + if (entry_.temp != WS_NO_TEMPERATURE) + text_temp.set(weather_units_fahr ? to_string_decimal((entry_.temp * 9 / 5) + 32, 1) + STR_DEGREES_F : to_string_decimal(entry_.temp, 2) + STR_DEGREES_C); + else + text_temp.set("-"); + if (entry_.humidity != WS_NO_HUMIDITY) + text_hum.set(to_string_dec_uint(entry_.humidity) + "%"); + else + text_hum.set("-"); + if (entry_.channel != WS_NO_CHANNEL) + text_ch.set(to_string_dec_uint(entry_.channel)); + else + text_ch.set("-"); + if (entry_.battery_low != WS_NO_BATT) + text_batt.set(to_string_dec_uint(entry_.battery_low) + " " + ((entry_.battery_low == 0) ? "OK" : "LOW")); + else + text_batt.set("-"); text_age.set(to_string_dec_uint(entry_.age) + " sec"); } @@ -204,8 +219,8 @@ void RecentEntriesTable::draw( } std::string temp = (weather_units_fahr ? to_string_decimal((entry.temp * 9 / 5) + 32, 1) : to_string_decimal(entry.temp, 1)); - std::string humStr = to_string_dec_uint(entry.humidity) + "%"; - std::string chStr = to_string_dec_uint(entry.channel); + std::string humStr = (entry.humidity != WS_NO_HUMIDITY) ? to_string_dec_uint(entry.humidity) + "%" : "-"; + std::string chStr = (entry.channel != WS_NO_CHANNEL) ? to_string_dec_uint(entry.channel) : "-"; std::string ageStr = to_string_dec_uint(entry.age); line += WeatherView::pad_string_with_spaces(6 - temp.length()) + temp; diff --git a/firmware/application/apps/ui_weatherstation.hpp b/firmware/application/apps/ui_weatherstation.hpp index 52cc77b5..fe24a4ab 100644 --- a/firmware/application/apps/ui_weatherstation.hpp +++ b/firmware/application/apps/ui_weatherstation.hpp @@ -43,11 +43,11 @@ struct WeatherRecentEntry { using Key = uint64_t; static constexpr Key invalid_key = 0x0fffffff; // todo calc the invalid all uint8_t sensorType = FPW_Invalid; - uint32_t id = 0xFFFFFFFF; - float temp = -273.0f; - uint8_t humidity = 0xFF; - uint8_t battery_low = 0xFF; - uint8_t channel = 0xFF; + uint32_t id = WS_NO_ID; + float temp = WS_NO_TEMPERATURE; + uint8_t humidity = WS_NO_HUMIDITY; + uint8_t battery_low = WS_NO_BATT; + uint8_t channel = WS_NO_CHANNEL; uint16_t age = 0; // updated on each seconds, show how long the signal was last seen WeatherRecentEntry() {} @@ -57,7 +57,7 @@ struct WeatherRecentEntry { float temp, uint8_t humidity, uint8_t channel, - uint8_t battery_low = 0xff) + uint8_t battery_low = WS_NO_BATT) : sensorType{sensorType}, id{id}, temp{temp}, diff --git a/firmware/baseband/fprotos/s-ansonic.hpp b/firmware/baseband/fprotos/s-ansonic.hpp index 8592a3dd..0685a926 100644 --- a/firmware/baseband/fprotos/s-ansonic.hpp +++ b/firmware/baseband/fprotos/s-ansonic.hpp @@ -100,18 +100,13 @@ class FProtoSubGhzDAnsonic : public FProtoSubGhzDBase { cnt = data & 0xFFF; btn = ((data >> 1) & 0x3); } - void get_string(char* output, size_t outSize) { + void get_string(std::string& output) { subghz_protocol_ansonic_check_remote_controller(); - snprintf( - output, outSize, - "%dbit\r\n" - "Key:%03lX\r\n" - "Btn:%X\r\n" - "DIP:" ANSONICDIP_PATTERN "\r\n", - data_count_bit, - (uint32_t)(data & 0xFFFFFFFF), - btn, - ANSONICCNT_TO_DIP(cnt)); + + /* output = to_string_dec_uint(data_count_bit) + " bit\r\n"; + output += "Key: " + to_string_hex((uint32_t)(data & 0xFFFFFFFF)) + "\r\n"; + output += "BTN: " + to_string_dec_uint(btn) + "\r\n"; + output += "DIP: " + ANSONICCNT_TO_DIP(cnt) + "\r\n";*/ } protected: diff --git a/firmware/baseband/fprotos/s-princeton.hpp b/firmware/baseband/fprotos/s-princeton.hpp new file mode 100644 index 00000000..d4a93d11 --- /dev/null +++ b/firmware/baseband/fprotos/s-princeton.hpp @@ -0,0 +1,111 @@ + +#ifndef __FPROTO_PRINCETON_H__ +#define __FPROTO_PRINCETON_H__ + +#include "subghzdbase.hpp" + +typedef enum { + PrincetonDecoderStepReset = 0, + PrincetonDecoderStepSaveDuration, + PrincetonDecoderStepCheckDuration, +} PrincetonDecoderStep; + +class FProtoSubGhzDPrinceton : public FProtoSubGhzDBase { + public: + FProtoSubGhzDPrinceton() { + sensorType = FPS_ANSONIC; + } + + void feed(bool level, uint32_t duration) { + switch (parser_step) { + case PrincetonDecoderStepReset: + if ((!level) && (DURATION_DIFF(duration, te_short * 36) < te_delta * 36)) { + // Found Preambula + parser_step = PrincetonDecoderStepSaveDuration; + decode_data = 0; + decode_count_bit = 0; + te = 0; + } + break; + case PrincetonDecoderStepSaveDuration: + // save duration + if (level) { + te_last = duration; + te += duration; + parser_step = PrincetonDecoderStepCheckDuration; + } + break; + case PrincetonDecoderStepCheckDuration: + if (!level) { + if (duration >= ((uint32_t)te_long * 2)) { + parser_step = PrincetonDecoderStepSaveDuration; + if (decode_count_bit == + min_count_bit_for_found) { + if ((last_data == decode_data) && + last_data) { + te /= (decode_count_bit * 4 + 1); + + data = decode_data; + data_count_bit = decode_count_bit; + + if (callback) callback(this); + } + last_data = decode_data; + } + decode_data = 0; + decode_count_bit = 0; + te = 0; + break; + } + + te += duration; + + if ((DURATION_DIFF(te_last, te_short) < + te_delta) && + (DURATION_DIFF(duration, te_long) < + te_delta * 3)) { + subghz_protocol_blocks_add_bit(0); + parser_step = PrincetonDecoderStepSaveDuration; + } else if ( + (DURATION_DIFF(te_last, te_long) < + te_delta * 3) && + (DURATION_DIFF(duration, te_short) < + te_delta)) { + subghz_protocol_blocks_add_bit(1); + parser_step = PrincetonDecoderStepSaveDuration; + } else { + parser_step = PrincetonDecoderStepReset; + } + } else { + parser_step = PrincetonDecoderStepReset; + } + break; + } + } + void subghz_protocol_princeton_check_remote_controller() { + serial = data >> 4; + btn = data & 0xF; + } + void get_string(std::string& output) { + subghz_protocol_princeton_check_remote_controller(); + uint32_t data_rev = FProtoGeneral::subghz_protocol_blocks_reverse_key(data, data_count_bit); + + /* output = to_string_dec_uint(data_count_bit) + " bit\r\n"; + output += "Key: " + to_string_hex((uint32_t)(data & 0xFFFFFF)) + "\r\n"; + output += "Yek: " + to_string_hex(data_rev) + "\r\n"; + output += "SN: " + to_string_dec_uint(serial) + "\r\n"; + output += "BTN: " + to_string_dec_uint(btn) + "\r\n"; + output += "TE: " + to_string_dec_uint(te) + "\r\n"; */ + } + + protected: + uint32_t te_short = 390; + uint32_t te_long = 1170; + uint32_t te_delta = 300; + uint32_t min_count_bit_for_found = 24; + + uint32_t te = 0; + uint32_t last_data = 0; +}; + +#endif diff --git a/firmware/baseband/fprotos/subghzdbase.hpp b/firmware/baseband/fprotos/subghzdbase.hpp index f9b4c4f9..1c84ef07 100644 --- a/firmware/baseband/fprotos/subghzdbase.hpp +++ b/firmware/baseband/fprotos/subghzdbase.hpp @@ -11,7 +11,7 @@ For comments in a protocol implementation check w-nexus-th.hpp #include "subghztypes.hpp" #include -// default walues to indicate 'no value' +// default values to indicate 'no value' #define SD_NO_ID 0xFFFFFFFF class FProtoSubGhzDBase; @@ -23,10 +23,10 @@ class FProtoSubGhzDBase { virtual ~FProtoSubGhzDBase() {} virtual void feed(bool level, uint32_t duration) = 0; // need to be implemented on each protocol handler. void setCallback(SubGhzDProtocolDecoderBaseRxCallback cb) { callback = cb; } // this is called when there is a hit. - + virtual void get_string(std::string& output) = 0; uint8_t getSensorType() { return sensorType; } uint32_t getSensorId() { return id; } - FPROTO_SUBGHZD_MODULATION modulation = FPM_AM; // override this, if FM + uint8_t modulation = FPM_AM; // override this, if FM protected: // Helper functions to keep it as compatible with flipper as we can, so adding new protos will be easy. void subghz_protocol_blocks_add_bit(uint8_t bit) { diff --git a/firmware/baseband/fprotos/subghzdprotos.hpp b/firmware/baseband/fprotos/subghzdprotos.hpp index b7469e23..928c2a34 100644 --- a/firmware/baseband/fprotos/subghzdprotos.hpp +++ b/firmware/baseband/fprotos/subghzdprotos.hpp @@ -11,6 +11,7 @@ So include here the .hpp, and add a new element to the protos vector in the cons #include "fprotolistgeneral.hpp" #include "subghzdbase.hpp" #include "s-ansonic.hpp" +#include "s-princeton.hpp" #ifndef __FPROTO_PROTOLISTSGZ_H__ #define __FPROTO_PROTOLISTSGZ_H__ @@ -19,7 +20,8 @@ class SubGhzDProtos : public FProtoListGeneral { public: SubGhzDProtos() { // add protos - protos.push_back(std::make_unique()); // 1 + protos.push_back(std::make_unique()); // 1 + protos.push_back(std::make_unique()); // 2 // set callback for them for (const auto& obj : protos) { diff --git a/firmware/baseband/fprotos/subghztypes.hpp b/firmware/baseband/fprotos/subghztypes.hpp index 3a263d6a..afe8247c 100644 --- a/firmware/baseband/fprotos/subghztypes.hpp +++ b/firmware/baseband/fprotos/subghztypes.hpp @@ -4,18 +4,17 @@ /* Define known protocols. -These values must be present on the protocol's constructor, like FProtoWeatherAcurite592TXR() { sensorType = FPW_Acurite592TXR; } +These values must be present on the protocol's constructor, like FProtoWeatherAcurite592TXR() { sensorType = FPS_ANSONIC; } Also it must have a switch-case element in the getSubGhzDSensorTypeName() function, to display it's name. */ -enum FPROTO_SUBGHZD_MODULATION { - FPM_AM = 0, - FPM_FM = 1, -}; +#define FPM_AM 0 +#define FPM_FM 1 enum FPROTO_SUBGHZD_SENSOR { FPS_Invalid = 0, FPS_ANSONIC = 1, + FPS_PRINCETON = 2, }; diff --git a/firmware/baseband/fprotos/weatherbase.hpp b/firmware/baseband/fprotos/weatherbase.hpp index 4f2c3ea4..f5be5930 100644 --- a/firmware/baseband/fprotos/weatherbase.hpp +++ b/firmware/baseband/fprotos/weatherbase.hpp @@ -12,12 +12,6 @@ For comments in a protocol implementation check w-nexus-th.hpp #include // default walues to indicate 'no value' -#define WS_NO_ID 0xFFFFFFFF -#define WS_NO_BATT 0xFF -#define WS_NO_HUMIDITY 0xFF -#define WS_NO_CHANNEL 0xFF -#define WS_NO_BTN 0xFF -#define WS_NO_TEMPERATURE -273.0f class FProtoWeatherBase; typedef void (*SubGhzProtocolDecoderBaseRxCallback)(FProtoWeatherBase* instance); diff --git a/firmware/baseband/fprotos/weathertypes.hpp b/firmware/baseband/fprotos/weathertypes.hpp index bf1798c8..37129705 100644 --- a/firmware/baseband/fprotos/weathertypes.hpp +++ b/firmware/baseband/fprotos/weathertypes.hpp @@ -7,6 +7,12 @@ Define known protocols. These values must be present on the protocol's constructor, like FProtoWeatherAcurite592TXR() { sensorType = FPW_Acurite592TXR; } Also it must have a switch-case element in the getWeatherSensorTypeName() function, to display it's name. */ +#define WS_NO_ID 0xFFFFFFFF +#define WS_NO_BATT 0xFF +#define WS_NO_HUMIDITY 0xFF +#define WS_NO_CHANNEL 0xFF +#define WS_NO_BTN 0xFF +#define WS_NO_TEMPERATURE -273.0f enum FPROTO_WEATHER_SENSOR { FPW_Invalid = 0,