diff --git a/firmware/application/apps/ui_subghzd.cpp b/firmware/application/apps/ui_subghzd.cpp index aafc98648..7bf2e0512 100644 --- a/firmware/application/apps/ui_subghzd.cpp +++ b/firmware/application/apps/ui_subghzd.cpp @@ -32,12 +32,15 @@ using namespace ui; namespace ui { void SubGhzDRecentEntryDetailView::update_data() { + // process protocol data + parseProtocol(); // set text elements text_type.set(SubGhzDView::getSensorTypeName((FPROTO_SUBGHZD_SENSOR)entry_.sensorType)); - text_id.set("0x" + to_string_hex(entry_.serial)); + + text_id.set("0x" + to_string_hex(serial)); if (entry_.bits > 0) console.writeln("Bits: " + to_string_dec_uint(entry_.bits)); - if (entry_.btn != SD_NO_BTN) console.writeln("Btn: " + to_string_dec_uint(entry_.btn)); - if (entry_.cnt != SD_NO_CNT) console.writeln("Cnt: " + to_string_dec_uint(entry_.cnt)); + if (btn != SD_NO_BTN) console.writeln("Btn: " + to_string_dec_uint(btn)); + if (cnt != SD_NO_CNT) console.writeln("Cnt: " + to_string_dec_uint(cnt)); if (entry_.data != 0) console.writeln("Data: " + to_string_hex(entry_.data)); } @@ -103,7 +106,7 @@ void SubGhzDView::on_tick_second() { } void SubGhzDView::on_data(const SubGhzDDataMessage* data) { - SubGhzDRecentEntry key{data->sensorType, data->serial, data->bits, data->data, data->btn, data->cnt}; + SubGhzDRecentEntry key{data->sensorType, data->data, data->bits}; auto matching_recent = find(recent, key.key()); if (matching_recent != std::end(recent)) { // Found within. Move to front of list, increment counter. @@ -203,6 +206,13 @@ const char* SubGhzDView::getSensorTypeName(FPROTO_SUBGHZD_SENSOR type) { return "Star Line"; case FPS_X10: return "X10"; + case FPS_LEGRAND: + return "Legrand"; + case FPS_SOMIFY_KEYTIS: + return "Somify Keytis"; + case FPS_SOMIFY_TELIS: + return "Somify Telis"; + case FPS_Invalid: default: return "Unknown"; @@ -224,7 +234,7 @@ void RecentEntriesTable::draw( line.reserve(30); line = SubGhzDView::getSensorTypeName((FPROTO_SUBGHZD_SENSOR)entry.sensorType); - line = line + " " + to_string_hex(entry.serial); + line = line + " " + to_string_hex(entry.data << 32); if (line.length() < 19) { line += SubGhzDView::pad_string_with_spaces(19 - line.length()); } else { @@ -239,4 +249,469 @@ void RecentEntriesTable::draw( painter.draw_string(target_rect.location(), style, line); } +// decoder helper functions + +void atomo_decrypt(uint8_t* buff) { + buff[0] = (buff[0] ^ 5) & 0x7F; + uint8_t tmpB = (-buff[0]) & 0x7F; + + uint8_t bitCnt = 8; + while (bitCnt < 59) { + if ((tmpB & 0x18) && (((tmpB / 8) & 3) != 3)) { + tmpB = ((tmpB << 1) & 0xFF) | 1; + } else { + tmpB = (tmpB << 1) & 0xFF; + } + + if (tmpB & 0x80) { + buff[bitCnt / 8] ^= (0x80 >> (bitCnt & 7)); + } + + bitCnt++; + } +} + +const uint32_t came_twee_magic_numbers_xor[15] = { + 0x0E0E0E00, + 0x1D1D1D11, + 0x2C2C2C22, + 0x3B3B3B33, + 0x4A4A4A44, + 0x59595955, + 0x68686866, + 0x77777777, + 0x86868688, + 0x95959599, + 0xA4A4A4AA, + 0xB3B3B3BB, + 0xC2C2C2CC, + 0xD1D1D1DD, + 0xE0E0E0EE, +}; + +// to save some byte of fw space, these will be inline. unreadeable? yes. needs a tons of free space? certanly. so sorry for this. + +void SubGhzDRecentEntryDetailView::parseProtocol() { + btn = SD_NO_BTN; + cnt = SD_NO_CNT; + serial = 0; + + if (entry_.sensorType == FPS_Invalid) return; + + if (entry_.sensorType == FPS_BETT) { + return; // needs dip pattern output. + } + + if (entry_.sensorType == FPS_AIRFORCE || entry_.sensorType == FPS_PRASTEL || entry_.sensorType == FPS_CAME) { + return; // nothing + } + + if (entry_.sensorType == FPS_CAMEATOMO) { + entry_.data ^= 0xFFFFFFFFFFFFFFFF; + entry_.data <<= 4; + uint8_t pack[8] = {}; + pack[0] = (entry_.data >> 56); + pack[1] = ((entry_.data >> 48) & 0xFF); + pack[2] = ((entry_.data >> 40) & 0xFF); + pack[3] = ((entry_.data >> 32) & 0xFF); + pack[4] = ((entry_.data >> 24) & 0xFF); + pack[5] = ((entry_.data >> 16) & 0xFF); + pack[6] = ((entry_.data >> 8) & 0xFF); + pack[7] = (entry_.data & 0xFF); + + atomo_decrypt(pack); + + // cnt_2 = pack[0]; + cnt = (uint16_t)pack[1] << 8 | pack[2]; + serial = (uint32_t)(pack[3]) << 24 | pack[4] << 16 | pack[5] << 8 | pack[6]; + + uint8_t btn_decode = (pack[7] >> 4); + if (btn_decode == 0x0) { + btn = 0x1; + } else if (btn_decode == 0x2) { + btn = 0x2; + } else if (btn_decode == 0x4) { + btn = 0x3; + } else if (btn_decode == 0x6) { + btn = 0x4; + } + return; + } + + if (entry_.sensorType == FPS_CAMETWEE) { + uint8_t cnt_parcel = (uint8_t)(entry_.data & 0xF); + uint32_t data = (uint32_t)(entry_.data & 0x0FFFFFFFF); + + data = (data ^ came_twee_magic_numbers_xor[cnt_parcel]); + serial = data; + data /= 4; + btn = (data >> 4) & 0x0F; + data >>= 16; + data = (uint16_t)FProtoGeneral::subghz_protocol_blocks_reverse_key(data, 16); + cnt = data >> 6; + return; + } + + if (entry_.sensorType == FPS_CHAMBCODE) { + return; // nothing + } + + if (entry_.sensorType == FPS_CLEMSA) { + serial = (entry_.data >> 2) & 0xFFFF; + btn = (entry_.data & 0x03); + return; + } + + if (entry_.sensorType == FPS_DOITRAND) { + cnt = (entry_.data >> 24) | ((entry_.data >> 15) & 0x1); + btn = ((entry_.data >> 18) & 0x3); + return; + } + + if (entry_.sensorType == FPS_DOOYA) { + serial = (entry_.data >> 16); + if ((entry_.data >> 12) & 0x0F) { + cnt = (entry_.data >> 8) & 0x0F; + } else { + cnt = 0xff; + } + btn = entry_.data & 0xFF; + return; + } + + if (entry_.sensorType == FPS_FAAC) { // stripped down a lot. + uint32_t code_fix = entry_.data >> 32; + uint32_t code_hop = entry_.data & 0xFFFFFFFF; + // uint32_t decrypt = 0; + // uint64_t man; + + uint8_t data_tmp = 0; + uint8_t data_prg[8]; + data_prg[0] = (code_hop & 0xFF); + data_prg[1] = ((code_hop >> 8) & 0xFF); + data_prg[2] = ((code_hop >> 16) & 0xFF); + data_prg[3] = (code_hop >> 24); + data_prg[4] = (code_fix & 0xFF); + data_prg[5] = ((code_fix >> 8) & 0xFF); + data_prg[6] = ((code_fix >> 16) & 0xFF); + data_prg[7] = (code_fix >> 24); + + if (((data_prg[7] == 0x52) && (data_prg[6] == 0x0F) && (data_prg[0] == 0x00))) { + // ProgMode ON + for (uint8_t i = data_prg[1] & 0xF; i != 0; i--) { + data_tmp = data_prg[2]; + + data_prg[2] = data_prg[2] >> 1 | (data_prg[3] & 1) << 7; + data_prg[3] = data_prg[3] >> 1 | (data_prg[4] & 1) << 7; + data_prg[4] = data_prg[4] >> 1 | (data_prg[5] & 1) << 7; + data_prg[5] = data_prg[5] >> 1 | (data_tmp & 1) << 7; + } + data_prg[2] ^= data_prg[1]; + data_prg[3] ^= data_prg[1]; + data_prg[4] ^= data_prg[1]; + data_prg[5] ^= data_prg[1]; + seed = data_prg[5] << 24 | data_prg[4] << 16 | data_prg[3] << 8 | data_prg[2]; + // uint32_t dec_prg_1 = data_prg[7] << 24 | data_prg[6] << 16 | data_prg[5] << 8 | data_prg[4]; + // uint32_t dec_prg_2 = data_prg[3] << 24 | data_prg[2] << 16 | data_prg[1] << 8 | data_prg[0]; + // entry_.data_2 = (uint64_t)dec_prg_1 << 32 | dec_prg_2; + cnt = data_prg[1]; + } else { + if (code_fix != 0x0) { + serial = code_fix >> 4; + btn = code_fix & 0xF; + } + } + return; + } + + if (entry_.sensorType == FPS_GATETX) { + uint32_t code_found_reverse = FProtoGeneral::subghz_protocol_blocks_reverse_key(entry_.data, entry_.bits); + serial = (code_found_reverse & 0xFF) << 12 | ((code_found_reverse >> 8) & 0xFF) << 4 | ((code_found_reverse >> 20) & 0x0F); + btn = ((code_found_reverse >> 16) & 0x0F); + return; + } + + if (entry_.sensorType == FPS_HOLTEK) { + if ((entry_.data & 0xF000000000) == 0x5000000000) { + serial = FProtoGeneral::subghz_protocol_blocks_reverse_key((entry_.data >> 16) & 0xFFFFF, 20); + uint16_t btn_ = entry_.data & 0xFFFF; + if ((btn_ & 0xf) != 0xA) { + btn = 0x1 << 4 | (btn_ & 0xF); + } else if (((btn_ >> 4) & 0xF) != 0xA) { + btn = 0x2 << 4 | ((btn_ >> 4) & 0xF); + } else if (((btn_ >> 8) & 0xF) != 0xA) { + btn = 0x3 << 4 | ((btn_ >> 8) & 0xF); + } else if (((btn_ >> 12) & 0xF) != 0xA) { + btn = 0x4 << 4 | ((btn_ >> 12) & 0xF); + } else { + btn = 0; + } + } else { + serial = 0; + btn = 0; + cnt = 0; + } + return; + } + + if (entry_.sensorType == FPS_HOLTEKHT12X) { + btn = entry_.data & 0x0F; + cnt = (entry_.data >> 4) & 0xFF; + return; + } + + if (entry_.sensorType == FPS_HONEYWELL) { + serial = (entry_.data >> 24) & 0xFFFFF; + btn = (entry_.data >> 16) & 0xFF; // not exactly button, but can contain btn data too. + cnt = (entry_.data >> 44) & 0xF; + /* + uint8_t contact = (entry_.databtn & 0x80) >> 7; + uint8_t tamper = (entry_.databtn & 0x40) >> 6; + uint8_t reed = (entry_.databtn & 0x20) >> 5; + uint8_t alarm = (entry_.databtn & 0x10) >> 4; + uint8_t battery_low = (entry_.databtn & 0x08) >> 3; + uint8_t heartbeat = (entry_.databtn & 0x04) >> 2; + */ + return; + } + + if (entry_.sensorType == FPS_HONEYWELLWDB) { + serial = (entry_.data >> 28) & 0xFFFFF; + // enabled, when we'll have extra fields and free fw space + /* switch ((entry_.data >> 20) & 0x3) { + case 0x02: + device_type = "Doorbell"; + break; + case 0x01: + device_type = "PIR-Motion"; + break; + default: + device_type = "Unknown"; + break; + } + + switch ((entry_.data >> 16) & 0x3) { + case 0x00: + alert = "Normal"; + break; + case 0x01: + case 0x02: + alert = "High"; + break; + case 0x03: + alert = "Full"; + break; + default: + alert = "Unknown"; + break; + } + + secret_knock = (uint8_t)((entry_.data >> 4) & 0x1); + relay = (uint8_t)((entry_.data >> 3) & 0x1); + lowbat = (uint8_t)((entry_.data >> 1) & 0x1);*/ + return; + } + + if (entry_.sensorType == FPS_HORMANN) { + btn = (entry_.data >> 8) & 0xF; + return; + } + + /* if (entry_.sensorType == FPS_HORMANNBISECURE) { //fm not implemented + serial = 0; + + for (uint8_t i = 1; i < 5; i++) { + serial = serial << 8 | ((uint8_t*)(&entry_.data))[i]; + } + } */ + + if (entry_.sensorType == FPS_IDO) { + uint64_t code_found_reverse = FProtoGeneral::subghz_protocol_blocks_reverse_key(entry_.data, entry_.bits); + uint32_t code_fix = code_found_reverse & 0xFFFFFF; + serial = code_fix & 0xFFFFF; + btn = (code_fix >> 20) & 0x0F; + return; + } + + if (entry_.sensorType == FPS_INTERTECHNOV3) { + if (entry_.bits == 32) { + serial = (entry_.data >> 6) & 0x3FFFFFF; + if ((entry_.data >> 5) & 0x1) { + cnt = 1 << 5; + } else { + cnt = (~entry_.data & 0xF); + } + btn = (entry_.data >> 4) & 0x1; + } else if (entry_.bits == 36) { + serial = (entry_.data >> 10) & 0x3FFFFFF; + if ((entry_.data >> 9) & 0x1) { + cnt = 1 << 5; + } else { + cnt = (~(entry_.data >> 4) & 0xF); + } + btn = (entry_.data) & 0xF; + } else { + serial = 0; + cnt = 0; + btn = 0; + } + return; + } + + if (entry_.sensorType == FPS_KEELOQ) { + // too many sub protocol versions, skipping. maybe in future when we'll have much more fw space + return; + } + + /* fm not implemented + if (entry_.sensorType == FPS_KIA) { + serial = (uint32_t)((entry_.data >> 12) & 0x0FFFFFFF); + btn = (entry_.data >> 8) & 0x0F; + cnt = (entry_.data >> 40) & 0xFFFF; + return; + } + */ + + if (entry_.sensorType == FPS_KINGGATESSTYLO4K) { + uint64_t fix = FProtoGeneral::subghz_protocol_blocks_reverse_key(entry_.data, 53); + btn = (fix >> 17) & 0x0F; + serial = ((fix >> 5) & 0xFFFF0000) | (fix & 0xFFFF); + return; + } + + if (entry_.sensorType == FPS_LEGRAND) { + return; // nothing + } + + if (entry_.sensorType == FPS_LINEAR || entry_.sensorType == FPS_LINEARDELTA3) { + return; // nothing + } + + if (entry_.sensorType == FPS_MAGELLAN) { + uint64_t data_rev = FProtoGeneral::subghz_protocol_blocks_reverse_key(entry_.data >> 8, 24); + serial = data_rev & 0xFFFF; + btn = (data_rev >> 16) & 0xFF; + return; + } + + if (entry_.sensorType == FPS_MARANTEC) { + btn = (entry_.data >> 16) & 0xF; + serial = ((entry_.data >> 12) & 0xFFFFFF00) | ((entry_.data >> 8) & 0xFF); + return; + } + + if (entry_.sensorType == FPS_MASTERCODE) { + serial = (entry_.data >> 4) & 0xFFFF; + btn = (entry_.data >> 2 & 0x03); + return; + } + + if (entry_.sensorType == FPS_MEGACODE) { + if ((entry_.data >> 23) == 1) { + serial = (entry_.data >> 3) & 0xFFFF; + btn = entry_.data & 0b111; + cnt = (entry_.data >> 19) & 0b1111; + } else { + serial = 0; + btn = 0; + cnt = 0; + } + return; + } + + if (entry_.sensorType == FPS_NERORADIO) { + return; // nothing + } + + if (entry_.sensorType == FPS_NERO_SKETCH) { + return; // nothing + } + + if (entry_.sensorType == FPS_NICEFLO || entry_.sensorType == FPS_NICEFLORS) { + return; // nothing, and can't + } + + if (entry_.sensorType == FPS_PHOENIXV2) { + uint64_t data_rev = FProtoGeneral::subghz_protocol_blocks_reverse_key(entry_.data, entry_.bits + 4); + serial = data_rev & 0xFFFFFFFF; + cnt = (data_rev >> 40) & 0xFFFF; + btn = (data_rev >> 32) & 0xF; + return; + } + + if (entry_.sensorType == FPS_POWERSMART) { + btn = ((entry_.data >> 54) & 0x02) | ((entry_.data >> 40) & 0x1); + serial = ((entry_.data >> 33) & 0x3FFF00) | ((entry_.data >> 32) & 0xFF); + cnt = ((entry_.data >> 49) & 0x3F); + return; + } + + if (entry_.sensorType == FPS_PRINCETON) { + serial = entry_.data >> 4; + btn = entry_.data & 0xF; + return; + } + if (entry_.sensorType == FPS_SECPLUSV1) { + uint32_t fixed = (entry_.data >> 32) & 0xFFFFFFFF; + cnt = entry_.data & 0xFFFFFFFF; + btn = fixed % 3; + // uint8_t id0 = (fixed / 3) % 3; + uint8_t id1 = (fixed / 9) % 3; + // uint16_t pin = 0; + if (id1 == 0) { + // (fixed // 3**3) % (3**7) 3^3=27 3^73=72187 + + serial = (fixed / 27) % 2187; + // pin = (fixed // 3**10) % (3**9) 3^10=59049 3^9=19683 + // pin = (fixed / 59049) % 19683; + + /* if (pin <= 9999) { + furi_string_cat_printf(output, " pin:%d", pin); + } else if (pin <= 11029) { + furi_string_cat_printf(output, " pin:enter"); + } */ + } else { + // id = fixed / 27; + serial = fixed / 27; + } + } + + if (entry_.sensorType == FPS_SECPLUSV2) { + return; // fw space saver + } + + if (entry_.sensorType == FPS_SMC5326) { + return; // dip pattern output needed. skipping + } + + if (entry_.sensorType == FPS_STARLINE) { + uint64_t key = FProtoGeneral::subghz_protocol_blocks_reverse_key(entry_.data, entry_.bits); + uint32_t key_fix = key >> 32; + serial = key_fix & 0x00FFFFFF; + btn = key_fix >> 24; + return; + } + + if (entry_.sensorType == FPS_X10) { + serial = (entry_.data & 0xF0000000) >> (24 + 4); + btn = (((entry_.data & 0x07000000) >> 24) | ((entry_.data & 0xF800) >> 8)); + return; + } + + if (entry_.sensorType == FPS_SOMIFY_KEYTIS) { + uint64_t dataa = entry_.data ^ (entry_.data >> 8); + btn = (dataa >> 48) & 0xF; + cnt = (dataa >> 24) & 0xFFFF; + serial = dataa & 0xFFFFFF; + return; + } + + if (entry_.sensorType == FPS_SOMIFY_TELIS) { + uint64_t dataa = entry_.data ^ (entry_.data >> 8); + btn = (dataa >> 44) & 0xF; // ctrl + cnt = (dataa >> 24) & 0xFFFF; // rolling code + serial = dataa & 0xFFFFFF; // address} + return; + } +} } // namespace ui \ No newline at end of file diff --git a/firmware/application/apps/ui_subghzd.hpp b/firmware/application/apps/ui_subghzd.hpp index 8594996ee..c55a4a752 100644 --- a/firmware/application/apps/ui_subghzd.hpp +++ b/firmware/application/apps/ui_subghzd.hpp @@ -23,6 +23,10 @@ #ifndef __UI_SUBGHZD_H__ #define __UI_SUBGHZD_H__ +#define SD_NO_SERIAL 0xFFFFFFFF +#define SD_NO_BTN 0xFF +#define SD_NO_CNT 0xFF + #include "ui.hpp" #include "ui_navigation.hpp" #include "ui_receiver.hpp" @@ -33,6 +37,7 @@ #include "recent_entries.hpp" #include "../baseband/fprotos/subghztypes.hpp" +#include "../baseband/fprotos/fprotogeneral.hpp" using namespace ui; @@ -42,29 +47,20 @@ struct SubGhzDRecentEntry { using Key = uint64_t; static constexpr Key invalid_key = 0x0fffffff; uint8_t sensorType = FPS_Invalid; - uint8_t btn = SD_NO_BTN; - uint32_t serial = SD_NO_SERIAL; uint16_t bits = 0; uint16_t age = 0; // updated on each seconds, show how long the signal was last seen - uint32_t cnt = SD_NO_CNT; uint64_t data = 0; SubGhzDRecentEntry() {} SubGhzDRecentEntry( uint8_t sensorType, - uint32_t serial, - uint16_t bits = 0, uint64_t data = 0, - uint8_t btn = SD_NO_BTN, - uint32_t cnt = SD_NO_CNT) + uint16_t bits = 0) : sensorType{sensorType}, - btn{btn}, - serial{serial}, bits{bits}, - cnt{cnt}, data{data} { } Key key() const { - return (data ^ ((static_cast(serial) << 32) | (static_cast(sensorType) & 0xFF) << 0)); + return (data ^ ((static_cast(sensorType) & 0xFF) << 0)); } void inc_age(int delta) { if (UINT16_MAX - delta > age) age += delta; @@ -149,6 +145,12 @@ class SubGhzDRecentEntryDetailView : public View { private: NavigationView& nav_; SubGhzDRecentEntry entry_{}; + + uint32_t serial = 0; + uint8_t btn = SD_NO_BTN; + uint32_t cnt = SD_NO_CNT; + uint32_t seed = 0; + Text text_type{{0 * 8, 1 * 16, 15 * 8, 16}, "?"}; Text text_id{{6 * 8, 2 * 16, 10 * 8, 16}, "?"}; @@ -164,6 +166,8 @@ class SubGhzDRecentEntryDetailView : public View { Button button_done{ {screen_width - 96 - 4, screen_height - 32 - 12, 96, 32}, "Done"}; + + void parseProtocol(); }; } // namespace ui diff --git a/firmware/baseband/fprotos/s-came.hpp b/firmware/baseband/fprotos/s-came.hpp index 9f6b59c03..81065c9cb 100644 --- a/firmware/baseband/fprotos/s-came.hpp +++ b/firmware/baseband/fprotos/s-came.hpp @@ -53,8 +53,6 @@ class FProtoSubGhzDCame : public FProtoSubGhzDBase { parser_step = CameDecoderStepFoundStartBit; if ((decode_count_bit == min_count_bit_for_found) || (decode_count_bit == AIRFORCE_COUNT_BIT) || (decode_count_bit == PRASTEL_COUNT_BIT) || (decode_count_bit == CAME_24_COUNT_BIT)) { - serial = SD_NO_SERIAL; - btn = SD_NO_BTN; data = decode_data; data_count_bit = decode_count_bit; // if flippa hacky, i hacky diff --git a/firmware/baseband/fprotos/s-came_atomo.hpp b/firmware/baseband/fprotos/s-came_atomo.hpp index 96f71f721..60dd3af15 100644 --- a/firmware/baseband/fprotos/s-came_atomo.hpp +++ b/firmware/baseband/fprotos/s-came_atomo.hpp @@ -45,36 +45,6 @@ class FProtoSubGhzDCameAtomo : public FProtoSubGhzDBase { min_count_bit_for_found) { data = decode_data; data_count_bit = decode_count_bit; - // controller - data ^= 0xFFFFFFFFFFFFFFFF; - data <<= 4; - - uint8_t pack[8] = {}; - pack[0] = (data >> 56); - pack[1] = ((data >> 48) & 0xFF); - pack[2] = ((data >> 40) & 0xFF); - pack[3] = ((data >> 32) & 0xFF); - pack[4] = ((data >> 24) & 0xFF); - pack[5] = ((data >> 16) & 0xFF); - pack[6] = ((data >> 8) & 0xFF); - pack[7] = (data & 0xFF); - - atomo_decrypt(pack); - - cnt = (uint16_t)pack[1] << 8 | pack[2]; - serial = (uint32_t)(pack[3]) << 24 | pack[4] << 16 | pack[5] << 8 | pack[6]; - - uint8_t btn_decode = (pack[7] >> 4); - if (btn_decode == 0x0) { - btn = 0x1; - } else if (btn_decode == 0x2) { - btn = 0x2; - } else if (btn_decode == 0x4) { - btn = 0x3; - } else if (btn_decode == 0x6) { - btn = 0x4; - } - if (callback) callback(this); } decode_data = 0; diff --git a/firmware/baseband/fprotos/s-came_twee.hpp b/firmware/baseband/fprotos/s-came_twee.hpp index 92c938ad0..9fbd8cb3a 100644 --- a/firmware/baseband/fprotos/s-came_twee.hpp +++ b/firmware/baseband/fprotos/s-came_twee.hpp @@ -45,7 +45,6 @@ class FProtoSubGhzDCameTwee : public FProtoSubGhzDBase { if (decode_count_bit == min_count_bit_for_found) { data = decode_data; data_count_bit = decode_count_bit; - subghz_protocol_came_twee_remote_controller(); if (callback) callback(this); } decode_data = 0; @@ -79,69 +78,6 @@ class FProtoSubGhzDCameTwee : public FProtoSubGhzDBase { protected: ManchesterState manchester_saved_state = ManchesterStateMid1; - - void subghz_protocol_came_twee_remote_controller() { - /* Came Twee 54 bit, rolling code 15 parcels with - * a decreasing counter from 0xE to 0x0 - * with originally coded dip switches on the console 10 bit code - * - * 0x003FFF72E04A6FEE - * 0x003FFF72D17B5EDD - * 0x003FFF72C2684DCC - * 0x003FFF72B3193CBB - * 0x003FFF72A40E2BAA - * 0x003FFF72953F1A99 - * 0x003FFF72862C0988 - * 0x003FFF7277DDF877 - * 0x003FFF7268C2E766 - * 0x003FFF7259F3D655 - * 0x003FFF724AE0C544 - * 0x003FFF723B91B433 - * 0x003FFF722C86A322 - * 0x003FFF721DB79211 - * 0x003FFF720EA48100 - * - * decryption - * the last 32 bits, do XOR by the desired number, divide the result by 4, - * convert the first 16 bits of the resulting 32-bit number to bin and do - * bit-by-bit mirroring, adding up to 10 bits - * - * Example - * Step 1. 0x003FFF721DB79211 => 0x1DB79211 - * Step 4. 0x1DB79211 xor 0x1D1D1D11 => 0x00AA8F00 - * Step 4. 0x00AA8F00 / 4 => 0x002AA3C0 - * Step 5. 0x002AA3C0 => 0x002A - * Step 6. 0x002A bin => b101010 - * Step 7. b101010 => b0101010000 - * Step 8. b0101010000 => (Dip) Off ON Off ON Off ON Off Off Off Off - */ - - uint8_t cnt_parcel = (uint8_t)(data & 0xF); - serial = (uint32_t)(data & 0x0FFFFFFFF); - data = (data ^ came_twee_magic_numbers_xor[cnt_parcel]); - data /= 4; - btn = (data >> 4) & 0x0F; - data >>= 16; - data = (uint16_t)FProtoGeneral::subghz_protocol_blocks_reverse_key(data, 16); - cnt = data >> 6; - } - inline static const uint32_t came_twee_magic_numbers_xor[15] = { - 0x0E0E0E00, - 0x1D1D1D11, - 0x2C2C2C22, - 0x3B3B3B33, - 0x4A4A4A44, - 0x59595955, - 0x68686866, - 0x77777777, - 0x86868688, - 0x95959599, - 0xA4A4A4AA, - 0xB3B3B3BB, - 0xC2C2C2CC, - 0xD1D1D1DD, - 0xE0E0E0EE, - }; }; #endif diff --git a/firmware/baseband/fprotos/s-chambcode.hpp b/firmware/baseband/fprotos/s-chambcode.hpp index c106c4a24..2380c0930 100644 --- a/firmware/baseband/fprotos/s-chambcode.hpp +++ b/firmware/baseband/fprotos/s-chambcode.hpp @@ -57,8 +57,6 @@ class FProtoSubGhzDChambCode : public FProtoSubGhzDBase { if (!level) { // save interval if (duration > te_short * 5) { if (decode_count_bit >= min_count_bit_for_found) { - serial = SD_NO_SERIAL; - btn = SD_NO_BTN; if (subghz_protocol_decoder_chamb_code_check_mask_and_parse()) { data = decode_data; data_count_bit = decode_count_bit; diff --git a/firmware/baseband/fprotos/s-clemsa.hpp b/firmware/baseband/fprotos/s-clemsa.hpp index 118fe39f3..0cceae98c 100644 --- a/firmware/baseband/fprotos/s-clemsa.hpp +++ b/firmware/baseband/fprotos/s-clemsa.hpp @@ -64,11 +64,6 @@ class FProtoSubGhzDClemsa : public FProtoSubGhzDBase { min_count_bit_for_found) { data = decode_data; data_count_bit = decode_count_bit; - - // controller - serial = (data >> 2) & 0xFFFF; - btn = (data & 0x03); - if (callback) callback(this); } parser_step = ClemsaDecoderStepSaveDuration; diff --git a/firmware/baseband/fprotos/s-doitrand.hpp b/firmware/baseband/fprotos/s-doitrand.hpp index 843bfed89..e94f7432a 100644 --- a/firmware/baseband/fprotos/s-doitrand.hpp +++ b/firmware/baseband/fprotos/s-doitrand.hpp @@ -46,10 +46,6 @@ class FProtoSubGhzDDoitrand : public FProtoSubGhzDBase { if (decode_count_bit == min_count_bit_for_found) { data = decode_data; data_count_bit = decode_count_bit; - - // controller - cnt = (data >> 24) | ((data >> 15) & 0x1); - btn = ((data >> 18) & 0x3); if (callback) callback(this); } decode_data = 0; diff --git a/firmware/baseband/fprotos/s-dooya.hpp b/firmware/baseband/fprotos/s-dooya.hpp index 0c51c2a87..fb1d9faef 100644 --- a/firmware/baseband/fprotos/s-dooya.hpp +++ b/firmware/baseband/fprotos/s-dooya.hpp @@ -74,16 +74,6 @@ class FProtoSubGhzDDooya : public FProtoSubGhzDBase { min_count_bit_for_found) { data = decode_data; data_count_bit = decode_count_bit; - - // controller: - serial = (data >> 16); - if ((data >> 12) & 0x0F) { - cnt = (data >> 8) & 0x0F; - } else { - cnt = 0xFF; - } - btn = data & 0xFF; - if (callback) callback(this); } break; diff --git a/firmware/baseband/fprotos/s-gate_tx.hpp b/firmware/baseband/fprotos/s-gate_tx.hpp index 6db6027d0..cb4803259 100644 --- a/firmware/baseband/fprotos/s-gate_tx.hpp +++ b/firmware/baseband/fprotos/s-gate_tx.hpp @@ -46,12 +46,6 @@ class FProtoSubGhzDGateTx : public FProtoSubGhzDBase { if (decode_count_bit == min_count_bit_for_found) { data = decode_data; data_count_bit = decode_count_bit; - - // controller - uint32_t code_found_reverse = FProtoGeneral::subghz_protocol_blocks_reverse_key(data, data_count_bit); - serial = (code_found_reverse & 0xFF) << 12 | ((code_found_reverse >> 8) & 0xFF) << 4 | ((code_found_reverse >> 20) & 0x0F); - btn = ((code_found_reverse >> 16) & 0x0F); - if (callback) callback(this); } decode_data = 0; diff --git a/firmware/baseband/fprotos/s-holtek.hpp b/firmware/baseband/fprotos/s-holtek.hpp index 2cba22092..8f3313dc3 100644 --- a/firmware/baseband/fprotos/s-holtek.hpp +++ b/firmware/baseband/fprotos/s-holtek.hpp @@ -51,22 +51,6 @@ class FProtoSubGhzDHoltek : public FProtoSubGhzDBase { if ((decode_data & HOLTEK_HEADER_MASK) == HOLTEK_HEADER) { data = decode_data; data_count_bit = decode_count_bit; - - // controller - serial = FProtoGeneral::subghz_protocol_blocks_reverse_key((data >> 16) & 0xFFFFF, 20); - uint16_t btn = data & 0xFFFF; - if ((btn & 0xf) != 0xA) { - btn = 0x1 << 4 | (btn & 0xF); - } else if (((btn >> 4) & 0xF) != 0xA) { - btn = 0x2 << 4 | ((btn >> 4) & 0xF); - } else if (((btn >> 8) & 0xF) != 0xA) { - btn = 0x3 << 4 | ((btn >> 8) & 0xF); - } else if (((btn >> 12) & 0xF) != 0xA) { - btn = 0x4 << 4 | ((btn >> 12) & 0xF); - } else { - btn = 0; - } - if (callback) callback(this); } } diff --git a/firmware/baseband/fprotos/s-holtek_ht12x.hpp b/firmware/baseband/fprotos/s-holtek_ht12x.hpp index 24c1f870b..7cffd4f68 100644 --- a/firmware/baseband/fprotos/s-holtek_ht12x.hpp +++ b/firmware/baseband/fprotos/s-holtek_ht12x.hpp @@ -47,9 +47,6 @@ class FProtoSubGhzDHoltekHt12x : public FProtoSubGhzDBase { if (data != decode_data) { data = decode_data; data_count_bit = decode_count_bit; - // controller - btn = data & 0x0F; - cnt = (data >> 4) & 0xFF; if (callback) callback(this); } } diff --git a/firmware/baseband/fprotos/s-honeywell.hpp b/firmware/baseband/fprotos/s-honeywell.hpp index d106d6ad1..0dd6ec9a6 100644 --- a/firmware/baseband/fprotos/s-honeywell.hpp +++ b/firmware/baseband/fprotos/s-honeywell.hpp @@ -73,8 +73,6 @@ class FProtoSubGhzDHoneywell : public FProtoSubGhzDBase { // the data is good. process it. data = decode_data; data_count_bit = decode_count_bit; // maybe set it to 64, and hack the first 2 bits to 1! will see if replay needs it - serial = (decode_data >> 24) & 0xFFFFF; - btn = (decode_data >> 16) & 0xFF; // not exactly button, but can contain btn data too. if (callback) callback(this); decode_data = 0; decode_count_bit = 0; diff --git a/firmware/baseband/fprotos/s-hormann.hpp b/firmware/baseband/fprotos/s-hormann.hpp index f43a7f514..636210311 100644 --- a/firmware/baseband/fprotos/s-hormann.hpp +++ b/firmware/baseband/fprotos/s-hormann.hpp @@ -49,8 +49,6 @@ class FProtoSubGhzDHormann : public FProtoSubGhzDBase { min_count_bit_for_found) { data = decode_data; data_count_bit = decode_count_bit; - // controller - btn = (data >> 4) & 0xF; if (callback) callback(this); } break; diff --git a/firmware/baseband/fprotos/s-hormannbisecure.hpp b/firmware/baseband/fprotos/s-hormannbisecure.hpp new file mode 100644 index 000000000..db56dc488 --- /dev/null +++ b/firmware/baseband/fprotos/s-hormannbisecure.hpp @@ -0,0 +1,130 @@ + +#ifndef __FPROTO_HORMANNBISECURE_H__ +#define __FPROTO_HORMANNBISECURE_H__ + +#include "subghzdbase.hpp" + +typedef enum { + HormannBiSecurDecoderStepReset = 0, + HormannBiSecurDecoderStepFoundPreambleAlternatingShort, + HormannBiSecurDecoderStepFoundPreambleHighVeryLong, + HormannBiSecurDecoderStepFoundPreambleAlternatingLong, + HormannBiSecurDecoderStepFoundData, +} HormannBiSecurDecoderStep; + +class FProtoSubGhzDHormannBiSecure : public FProtoSubGhzDBase { + public: + FProtoSubGhzDHormannBiSecure() { + sensorType = FPS_HORMANN; + te_short = 208; + te_long = 416; + te_delta = 104; + min_count_bit_for_found = 176; + } + + void subghz_protocol_decoder_hormann_bisecur_reset() { + parser_step = HormannBiSecurDecoderStepReset; + data = 0; + for (uint8_t i = 0; i < 22; ++i) dataa[i] = 0; + data_count_bit = 0; + manchester_saved_state = ManchesterStateStart1; + } + + void feed(bool level, uint32_t duration) { + ManchesterEvent event = ManchesterEventReset; + + switch (parser_step) { + case HormannBiSecurDecoderStepReset: + if (!level && DURATION_DIFF(duration, duration_short + duration_half_short) < te_delta) { + parser_step = HormannBiSecurDecoderStepFoundPreambleAlternatingShort; + } + break; + case HormannBiSecurDecoderStepFoundPreambleAlternatingShort: + if (DURATION_DIFF(duration, duration_short) < te_delta) { + // stay on the same step, the pattern repeats around 21 times + break; + } + + if (level && DURATION_DIFF(duration, duration_long * 4) < te_delta) { + parser_step = HormannBiSecurDecoderStepFoundPreambleHighVeryLong; + break; + } + + parser_step = HormannBiSecurDecoderStepReset; + break; + case HormannBiSecurDecoderStepFoundPreambleHighVeryLong: + if (!level && DURATION_DIFF(duration, duration_long) < te_delta) { + sync_cnt = 3; + parser_step = HormannBiSecurDecoderStepFoundPreambleAlternatingLong; + break; + } + + parser_step = HormannBiSecurDecoderStepReset; + break; + case HormannBiSecurDecoderStepFoundPreambleAlternatingLong: + if (level == (sync_cnt-- & 1) && + DURATION_DIFF(duration, duration_long) < te_delta) { + if (!sync_cnt) { + FProtoGeneral::manchester_advance_alt(manchester_saved_state, event, &manchester_saved_state, NULL); + parser_step = HormannBiSecurDecoderStepFoundData; + } + + // stay on the same step, or advance to the next if enough transitions are found + break; + } + + parser_step = HormannBiSecurDecoderStepReset; + break; + case HormannBiSecurDecoderStepFoundData: + if (DURATION_DIFF(duration, duration_short) < te_delta || + ( + // the last bit can be arbitrary long, but it is parsed as a short + data_count_bit == min_count_bit_for_found - 1 && + duration > duration_short)) { + event = !level ? ManchesterEventShortHigh : ManchesterEventShortLow; + } + + if (DURATION_DIFF(duration, duration_long) < te_delta) { + event = !level ? ManchesterEventLongHigh : ManchesterEventLongLow; + } + + if (event == ManchesterEventReset) { + subghz_protocol_decoder_hormann_bisecur_reset(); + } else { + bool new_level; + + if (manchester_advance_alt(instance->manchester_saved_state, event, &instance->manchester_saved_state, &new_level)) { + subghz_protocol_decoder_hormann_bisecur_add_bit(instance, new_level); + } + } + break; + } + } + + void subghz_protocol_decoder_hormann_bisecur_add_bit(bool level) { + if (data_count_bit >= min_count_bit_for_found) { + return; + } + + if (level) { + uint8_t byte_index = data_count_bit / 8; + uint8_t bit_index = data_count_bit % 8; + dataa[byte_index] |= 1 << (7 - bit_index); + } + data_count_bit++; + if (data_count_bit >= min_count_bit_for_found) { + if (callback) { + callback(this); + } else { + subghz_protocol_decoder_hormann_bisecur_reset(); + } + } + } + + protected: + ManchesterState manchester_saved_state = ManchesterStateMid1; + uint8_t dataa[22] = {0}; + uint8_t sync_cnt = 0; +}; + +#endif diff --git a/firmware/baseband/fprotos/s-ido.hpp b/firmware/baseband/fprotos/s-ido.hpp index 59bfa3fba..ee1616d85 100644 --- a/firmware/baseband/fprotos/s-ido.hpp +++ b/firmware/baseband/fprotos/s-ido.hpp @@ -46,12 +46,6 @@ class FProtoSubGhzDIdo : public FProtoSubGhzDBase { min_count_bit_for_found) { data = decode_data; data_count_bit = decode_count_bit; - // controller - uint64_t code_found_reverse = FProtoGeneral::subghz_protocol_blocks_reverse_key(data, data_count_bit); - uint32_t code_fix = code_found_reverse & 0xFFFFFF; - - serial = code_fix & 0xFFFFF; - btn = (code_fix >> 20) & 0x0F; if (callback) callback(this); } decode_data = 0; diff --git a/firmware/baseband/fprotos/s-intertechnov3.hpp b/firmware/baseband/fprotos/s-intertechnov3.hpp index 63552b461..24b0655bc 100644 --- a/firmware/baseband/fprotos/s-intertechnov3.hpp +++ b/firmware/baseband/fprotos/s-intertechnov3.hpp @@ -68,7 +68,6 @@ class FProtoSubGhzDIntertechnoV3 : public FProtoSubGhzDBase { (decode_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT)) { data = decode_data; data_count_bit = decode_count_bit; - remote_controller(); if (callback) callback(this); } break; @@ -120,29 +119,6 @@ class FProtoSubGhzDIntertechnoV3 : public FProtoSubGhzDBase { } protected: - void remote_controller() { - if (data_count_bit == min_count_bit_for_found) { - serial = (data >> 6) & 0x3FFFFFF; - if ((data >> 5) & 0x1) { - cnt = 1 << 5; - } else { - cnt = (~data & 0xF); - } - btn = (data >> 4) & 0x1; - } else if (data_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT) { - serial = (data >> 10) & 0x3FFFFFF; - if ((data >> 9) & 0x1) { - cnt = 1 << 5; - } else { - cnt = (~(data >> 4) & 0xF); - } - btn = data & 0xF; - } else { - serial = 0; - cnt = 0; - btn = 0; - } - } }; #endif diff --git a/firmware/baseband/fprotos/s-keeloq.hpp b/firmware/baseband/fprotos/s-keeloq.hpp index 9e09a3c33..ff92490d2 100644 --- a/firmware/baseband/fprotos/s-keeloq.hpp +++ b/firmware/baseband/fprotos/s-keeloq.hpp @@ -60,12 +60,6 @@ class FProtoSubGhzDKeeLoq : public FProtoSubGhzDBase { if (data != decode_data) { data = decode_data; data_count_bit = min_count_bit_for_found; - // controller - uint64_t key = FProtoGeneral::subghz_protocol_blocks_reverse_key(data, data_count_bit); - uint32_t key_fix = key >> 32; - // uint32_t key_hop = key & 0x00000000ffffffff; //unused - serial = key_fix & 0x0FFFFFFF; - btn = key_fix >> 28; if (callback) callback(this); } decode_data = 0; diff --git a/firmware/baseband/fprotos/s-kinggates_stylo_4k.hpp b/firmware/baseband/fprotos/s-kinggates_stylo_4k.hpp index 4122dc171..d8f223aa3 100644 --- a/firmware/baseband/fprotos/s-kinggates_stylo_4k.hpp +++ b/firmware/baseband/fprotos/s-kinggates_stylo_4k.hpp @@ -61,13 +61,8 @@ class FProtoSubGhzDKinggatesStylo4K : public FProtoSubGhzDBase { if (decode_count_bit == min_count_bit_for_found) { data = data_2; - data_2 = decode_data; + data_2 = decode_data; // TODO DATA2 data_count_bit = decode_count_bit; - // controller - uint64_t fix = FProtoGeneral::subghz_protocol_blocks_reverse_key(data, 53); - - btn = (fix >> 17) & 0x0F; - serial = ((fix >> 5) & 0xFFFF0000) | (fix & 0xFFFF); if (callback) callback(this); } diff --git a/firmware/baseband/fprotos/s-legrand.hpp b/firmware/baseband/fprotos/s-legrand.hpp new file mode 100644 index 000000000..5ab3de92e --- /dev/null +++ b/firmware/baseband/fprotos/s-legrand.hpp @@ -0,0 +1,113 @@ + +#ifndef __FPROTO_LEGRAND_H__ +#define __FPROTO_LEGRAND_H__ + +#include "subghzdbase.hpp" + +typedef enum { + LegrandDecoderStepReset = 0, + LegrandDecoderStepFirstBit, + LegrandDecoderStepSaveDuration, + LegrandDecoderStepCheckDuration, +} LegrandDecoderStep; + +class FProtoSubGhzDLegrand : public FProtoSubGhzDBase { + public: + FProtoSubGhzDLegrand() { + sensorType = FPS_LEGRAND; + te_short = 375; + te_long = 1125; + te_delta = 150; + min_count_bit_for_found = 18; + } + + void feed(bool level, uint32_t duration) { + switch (parser_step) { + case LegrandDecoderStepReset: + if (!level && DURATION_DIFF(duration, te_short * 16) < te_delta * 8) { + parser_step = LegrandDecoderStepFirstBit; + decode_data = 0; + decode_count_bit = 0; + te = 0; + } + break; + case LegrandDecoderStepFirstBit: + if (level) { + if (DURATION_DIFF(duration, te_short) < te_delta) { + subghz_protocol_blocks_add_bit(0); + te += duration * 4; // long low that is part of sync, then short high + } + + if (DURATION_DIFF(duration, te_long) < te_delta * 3) { + subghz_protocol_blocks_add_bit(1); + te += duration / 3 * 4; // short low that is part of sync, then long high + } + + if (decode_count_bit > 0) { + // advance to the next step if either short or long is found + parser_step = LegrandDecoderStepSaveDuration; + break; + } + } + + parser_step = LegrandDecoderStepReset; + break; + case LegrandDecoderStepSaveDuration: + if (!level) { + te_last = duration; + te += duration; + parser_step = LegrandDecoderStepCheckDuration; + break; + } + + parser_step = LegrandDecoderStepReset; + break; + case LegrandDecoderStepCheckDuration: + if (level) { + uint8_t found = 0; + + if (DURATION_DIFF(te_last, te_long) < te_delta * 3 && DURATION_DIFF(duration, te_short) < te_delta) { + found = 1; + subghz_protocol_blocks_add_bit(0); + } + + if (DURATION_DIFF(te_last, te_short) < te_delta && DURATION_DIFF(duration, te_long) < te_delta * 3) { + found = 1; + subghz_protocol_blocks_add_bit(1); + } + + if (found) { + te += duration; + + if (decode_count_bit < + min_count_bit_for_found) { + parser_step = LegrandDecoderStepSaveDuration; + break; + } + + // enough bits for a packet found, save it only if there was a previous packet + // with the same data + if (data && (data != decode_data)) { + te /= decode_count_bit * 4; + + data = decode_data; + data_count_bit = decode_count_bit; + + if (callback) { + callback(this); + } + } + // fallthrough to reset, the next bit is expected to be a sync + // it also takes care of resetting the decoder state + } + } + parser_step = LegrandDecoderStepReset; + break; + } + } + + protected: + uint32_t te = 0; +}; + +#endif diff --git a/firmware/baseband/fprotos/s-linear.hpp b/firmware/baseband/fprotos/s-linear.hpp index c54327618..ad69957e7 100644 --- a/firmware/baseband/fprotos/s-linear.hpp +++ b/firmware/baseband/fprotos/s-linear.hpp @@ -54,11 +54,8 @@ class FProtoSubGhzDLinear : public FProtoSubGhzDBase { subghz_protocol_blocks_add_bit(1); } if (decode_count_bit == min_count_bit_for_found) { - serial = SD_NO_SERIAL; - btn = SD_NO_BTN; data = decode_data; data_count_bit = decode_count_bit; - if (callback) callback(this); } break; diff --git a/firmware/baseband/fprotos/s-linear_delta3.hpp b/firmware/baseband/fprotos/s-linear_delta3.hpp index 96aa09eba..92e997a71 100644 --- a/firmware/baseband/fprotos/s-linear_delta3.hpp +++ b/firmware/baseband/fprotos/s-linear_delta3.hpp @@ -50,12 +50,8 @@ class FProtoSubGhzDLinearDelta3 : public FProtoSubGhzDBase { } if (decode_count_bit == min_count_bit_for_found) { if ((data == decode_data) && data) { - serial = SD_NO_SERIAL; - btn = SD_NO_BTN; - data = decode_data; data_count_bit = decode_count_bit; - if (callback) callback(this); } parser_step = LinearD3DecoderStepSaveDuration; diff --git a/firmware/baseband/fprotos/s-magellan.hpp b/firmware/baseband/fprotos/s-magellan.hpp index 1d997aea2..968488bcb 100644 --- a/firmware/baseband/fprotos/s-magellan.hpp +++ b/firmware/baseband/fprotos/s-magellan.hpp @@ -92,11 +92,6 @@ class FProtoSubGhzDMagellan : public FProtoSubGhzDBase { subghz_protocol_magellan_check_crc()) { data = decode_data; data_count_bit = decode_count_bit; - - // controller - uint64_t data_rev = FProtoGeneral::subghz_protocol_blocks_reverse_key(data >> 8, 24); - serial = data_rev & 0xFFFF; - btn = (data_rev >> 16) & 0xFF; if (callback) callback(this); } decode_data = 0; diff --git a/firmware/baseband/fprotos/s-marantec.hpp b/firmware/baseband/fprotos/s-marantec.hpp index b41f02b0e..bba6d8b74 100644 --- a/firmware/baseband/fprotos/s-marantec.hpp +++ b/firmware/baseband/fprotos/s-marantec.hpp @@ -45,9 +45,6 @@ class FProtoSubGhzDMarantec : public FProtoSubGhzDBase { if (decode_count_bit == min_count_bit_for_found) { data = decode_data; data_count_bit = decode_count_bit; - // controller - btn = (data >> 16) & 0xF; - serial = ((data >> 12) & 0xFFFFFF00) | ((data >> 8) & 0xFF); if (callback) callback(this); } decode_data = 1; diff --git a/firmware/baseband/fprotos/s-mastercode.hpp b/firmware/baseband/fprotos/s-mastercode.hpp index 6d8365578..fae6c1b5b 100644 --- a/firmware/baseband/fprotos/s-mastercode.hpp +++ b/firmware/baseband/fprotos/s-mastercode.hpp @@ -63,9 +63,7 @@ class FProtoSubGhzDMastercode : public FProtoSubGhzDBase { if (decode_count_bit == min_count_bit_for_found) { data = decode_data; data_count_bit = decode_count_bit; - // controller - serial = (data >> 4) & 0xFFFF; - btn = (data >> 2 & 0x03); + if (callback) callback(this); } parser_step = MastercodeDecoderStepSaveDuration; diff --git a/firmware/baseband/fprotos/s-megacode.hpp b/firmware/baseband/fprotos/s-megacode.hpp index 14fb7c6ab..7c58b3463 100644 --- a/firmware/baseband/fprotos/s-megacode.hpp +++ b/firmware/baseband/fprotos/s-megacode.hpp @@ -50,16 +50,7 @@ class FProtoSubGhzDMegacode : public FProtoSubGhzDBase { min_count_bit_for_found) { data = decode_data; data_count_bit = decode_count_bit; - // controller - if ((data >> 23) == 1) { - serial = (data >> 3) & 0xFFFF; - btn = data & 0b111; - cnt = (data >> 19) & 0b1111; - } else { - serial = 0; - btn = 0; - cnt = 0; - } + if (callback) callback(this); } break; diff --git a/firmware/baseband/fprotos/s-nice_flo.hpp b/firmware/baseband/fprotos/s-nice_flo.hpp index ec14771ff..7cf2d270e 100644 --- a/firmware/baseband/fprotos/s-nice_flo.hpp +++ b/firmware/baseband/fprotos/s-nice_flo.hpp @@ -47,9 +47,6 @@ class FProtoSubGhzDNiceflo : public FProtoSubGhzDBase { if (duration >= (te_short * 4)) { parser_step = NiceFloDecoderStepFoundStartBit; if (decode_count_bit >= min_count_bit_for_found) { - serial = SD_NO_SERIAL; - btn = SD_NO_BTN; - data = decode_data; data_count_bit = decode_count_bit; if (callback) callback(this); diff --git a/firmware/baseband/fprotos/s-nice_flors.hpp b/firmware/baseband/fprotos/s-nice_flors.hpp index bf70f55b6..ffce97e48 100644 --- a/firmware/baseband/fprotos/s-nice_flors.hpp +++ b/firmware/baseband/fprotos/s-nice_flors.hpp @@ -58,10 +58,7 @@ class FProtoSubGhzDNiceflors : public FProtoSubGhzDBase { if ((decode_count_bit == min_count_bit_for_found) || (decode_count_bit == NICE_ONE_COUNT_BIT)) { data = decode_data; data_count_bit = decode_count_bit; - // controller- - cnt = SD_NO_CNT; - serial = SD_NO_SERIAL; - btn = SD_NO_BTN; + if (callback) callback(this); } break; diff --git a/firmware/baseband/fprotos/s-phoenix_v2.hpp b/firmware/baseband/fprotos/s-phoenix_v2.hpp index 3c7e42145..eaba6c197 100644 --- a/firmware/baseband/fprotos/s-phoenix_v2.hpp +++ b/firmware/baseband/fprotos/s-phoenix_v2.hpp @@ -47,12 +47,6 @@ class FProtoSubGhzDPhoenixV2 : public FProtoSubGhzDBase { min_count_bit_for_found) { data = decode_data; data_count_bit = decode_count_bit; - // controller - uint64_t data_rev = FProtoGeneral::subghz_protocol_blocks_reverse_key(data, data_count_bit + 4); - serial = data_rev & 0xFFFFFFFF; - cnt = (data_rev >> 40) & 0xFFFF; - btn = (data_rev >> 32) & 0xF; - if (callback) callback(this); } decode_data = 0; diff --git a/firmware/baseband/fprotos/s-power_smart.hpp b/firmware/baseband/fprotos/s-power_smart.hpp index 05940e8cb..807473409 100644 --- a/firmware/baseband/fprotos/s-power_smart.hpp +++ b/firmware/baseband/fprotos/s-power_smart.hpp @@ -52,11 +52,6 @@ class FProtoSubGhzDPowerSmart : public FProtoSubGhzDBase { data = decode_data; data_count_bit = min_count_bit_for_found; - // controller - btn = ((data >> 54) & 0x02) | ((data >> 40) & 0x1); - serial = ((data >> 33) & 0x3FFF00) | ((data >> 32) & 0xFF); - cnt = ((data >> 49) & 0x3F); - if (callback) callback(this); decode_data = 0; decode_count_bit = 0; diff --git a/firmware/baseband/fprotos/s-princeton.hpp b/firmware/baseband/fprotos/s-princeton.hpp index 9cdf425cf..8fe20b767 100644 --- a/firmware/baseband/fprotos/s-princeton.hpp +++ b/firmware/baseband/fprotos/s-princeton.hpp @@ -44,9 +44,6 @@ class FProtoSubGhzDPrinceton : public FProtoSubGhzDBase { if (decode_count_bit == min_count_bit_for_found) { data = decode_data; data_count_bit = decode_count_bit; - // controller - serial = data >> 4; - btn = data & 0xF; if (callback) callback(this); } decode_data = 0; diff --git a/firmware/baseband/fprotos/s-somify_keytis.hpp b/firmware/baseband/fprotos/s-somify_keytis.hpp new file mode 100644 index 000000000..2facb53f9 --- /dev/null +++ b/firmware/baseband/fprotos/s-somify_keytis.hpp @@ -0,0 +1,129 @@ + +#ifndef __FPROTO_SOMIFYKEYTIS_H__ +#define __FPROTO_SOMIFYKEYTIS_H__ + +#include "subghzdbase.hpp" + +typedef enum { + SomfyKeytisDecoderStepReset = 0, + SomfyKeytisDecoderStepCheckPreambula, + SomfyKeytisDecoderStepFoundPreambula, + SomfyKeytisDecoderStepStartDecode, + SomfyKeytisDecoderStepDecoderData, +} SomfyKeytisDecoderStep; + +class FProtoSubGhzDSomifyKeytis : public FProtoSubGhzDBase { + public: + FProtoSubGhzDSomifyKeytis() { + sensorType = FPS_SOMIFY_KEYTIS; + te_short = 640; + te_long = 1280; + te_delta = 250; + min_count_bit_for_found = 80; + } + + void feed(bool level, uint32_t duration) { + ManchesterEvent event = ManchesterEventReset; + switch (parser_step) { + case SomfyKeytisDecoderStepReset: + if ((level) && DURATION_DIFF(duration, te_short * 4) < te_delta * 4) { + parser_step = SomfyKeytisDecoderStepFoundPreambula; + header_count++; + } + break; + case SomfyKeytisDecoderStepFoundPreambula: + if ((!level) && (DURATION_DIFF(duration, te_short * 4) < te_delta * 4)) { + parser_step = SomfyKeytisDecoderStepCheckPreambula; + } else { + header_count = 0; + parser_step = SomfyKeytisDecoderStepReset; + } + break; + case SomfyKeytisDecoderStepCheckPreambula: + if (level) { + if (DURATION_DIFF(duration, te_short * 4) < te_delta * 4) { + parser_step = SomfyKeytisDecoderStepFoundPreambula; + header_count++; + } else if ( + (header_count > 1) && (DURATION_DIFF(duration, te_short * 7) < te_delta * 4)) { + parser_step = SomfyKeytisDecoderStepDecoderData; + decode_data = 0; + decode_count_bit = 0; + // press_duration_counter = 0; + FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL); + FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongHigh, &manchester_saved_state, NULL); + } + } + + break; + + case SomfyKeytisDecoderStepDecoderData: + if (!level) { + if (DURATION_DIFF(duration, te_short) < te_delta) { + event = ManchesterEventShortLow; + } else if ( + DURATION_DIFF(duration, te_long) < te_delta) { + event = ManchesterEventLongLow; + } else if ( + duration >= (te_long + te_delta)) { + if (decode_count_bit == min_count_bit_for_found) { + // check crc + uint64_t data_tmp = data ^ (data >> 8); + if (((data_tmp >> 40) & 0xF) == subghz_protocol_somfy_keytis_crc(data_tmp)) { + data = decode_data; + data_count_bit = decode_count_bit; + + if (callback) callback(this); + } + } + decode_data = 0; + decode_count_bit = 0; + FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL); + FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongHigh, &manchester_saved_state, NULL); + parser_step = SomfyKeytisDecoderStepReset; + } else { + parser_step = SomfyKeytisDecoderStepReset; + } + } else { + if (DURATION_DIFF(duration, te_short) < + te_delta) { + event = ManchesterEventShortHigh; + } else if ( + DURATION_DIFF(duration, te_long) < + te_delta) { + event = ManchesterEventLongHigh; + } else { + parser_step = SomfyKeytisDecoderStepReset; + } + } + if (event != ManchesterEventReset) { + bool data; + bool data_ok = FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data); + + if (data_ok) { + if (decode_count_bit < 56) { + decode_data = (decode_data << 1) | data; + } else { + // press_duration_counter = (press_duration_counter << 1) | data; + } + + decode_count_bit++; + } + } + break; + } + } + + protected: + ManchesterState manchester_saved_state = ManchesterStateMid1; + uint8_t subghz_protocol_somfy_keytis_crc(uint64_t data) { + uint8_t crc = 0; + data &= 0xFFF0FFFFFFFFFF; + for (uint8_t i = 0; i < 56; i += 8) { + crc = crc ^ data >> i ^ (data >> (i + 4)); + } + return crc & 0xf; + } +}; + +#endif diff --git a/firmware/baseband/fprotos/s-somify_telis.hpp b/firmware/baseband/fprotos/s-somify_telis.hpp new file mode 100644 index 000000000..02416dfd4 --- /dev/null +++ b/firmware/baseband/fprotos/s-somify_telis.hpp @@ -0,0 +1,123 @@ + +#ifndef __FPROTO_SOMIFYTELIS_H__ +#define __FPROTO_SOMIFYTELIS_H__ + +#include "subghzdbase.hpp" + +typedef enum { + SomfyTelisDecoderStepReset = 0, + SomfyTelisDecoderStepCheckPreambula, + SomfyTelisDecoderStepFoundPreambula, + SomfyTelisDecoderStepStartDecode, + SomfyTelisDecoderStepDecoderData, +} SomfyTelisDecoderStep; + +class FProtoSubGhzDSomifyTelis : public FProtoSubGhzDBase { + public: + FProtoSubGhzDSomifyTelis() { + sensorType = FPS_SOMIFY_TELIS; + te_short = 640; + te_long = 1280; + te_delta = 250; + min_count_bit_for_found = 56; + } + + void feed(bool level, uint32_t duration) { + ManchesterEvent event = ManchesterEventReset; + switch (parser_step) { + case SomfyTelisDecoderStepReset: + if ((level) && DURATION_DIFF(duration, te_short * 4) < te_delta * 4) { + parser_step = SomfyTelisDecoderStepFoundPreambula; + header_count++; + } + break; + case SomfyTelisDecoderStepFoundPreambula: + if ((!level) && (DURATION_DIFF(duration, te_short * 4) < te_delta * 4)) { + parser_step = SomfyTelisDecoderStepCheckPreambula; + } else { + header_count = 0; + parser_step = SomfyTelisDecoderStepReset; + } + break; + case SomfyTelisDecoderStepCheckPreambula: + if (level) { + if (DURATION_DIFF(duration, te_short * 4) < te_delta * 4) { + parser_step = SomfyTelisDecoderStepFoundPreambula; + header_count++; + } else if ( + (header_count > 1) && + (DURATION_DIFF(duration, te_short * 7) < te_delta * 4)) { + parser_step = SomfyTelisDecoderStepDecoderData; + decode_data = 0; + decode_count_bit = 0; + header_count = 0; + FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL); + FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongHigh, &manchester_saved_state, NULL); + } + } + + break; + + case SomfyTelisDecoderStepDecoderData: + if (!level) { + if (DURATION_DIFF(duration, te_short) < te_delta) { + event = ManchesterEventShortLow; + } else if ( + DURATION_DIFF(duration, te_long) < te_delta) { + event = ManchesterEventLongLow; + } else if ( + duration >= (te_long + te_delta)) { + if (decode_count_bit == min_count_bit_for_found) { + // check crc + uint64_t data_tmp = decode_data ^ (decode_data >> 8); + if (((data_tmp >> 40) & 0xF) == subghz_protocol_somfy_telis_crc(data_tmp)) { + data = decode_data; + data_count_bit = decode_count_bit; + + if (callback) callback(this); + } + } + decode_data = 0; + decode_count_bit = 0; + FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL); + FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongHigh, &manchester_saved_state, NULL); + parser_step = SomfyTelisDecoderStepReset; + } else { + parser_step = SomfyTelisDecoderStepReset; + } + } else { + if (DURATION_DIFF(duration, te_short) < te_delta) { + event = ManchesterEventShortHigh; + } else if ( + DURATION_DIFF(duration, te_long) < te_delta) { + event = ManchesterEventLongHigh; + } else { + parser_step = SomfyTelisDecoderStepReset; + } + } + if (event != ManchesterEventReset) { + bool data; + bool data_ok = FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data); + + if (data_ok) { + decode_data = (decode_data << 1) | data; + decode_count_bit++; + } + } + break; + } + } + + protected: + ManchesterState manchester_saved_state = ManchesterStateMid1; + uint8_t subghz_protocol_somfy_telis_crc(uint64_t data) { + uint8_t crc = 0; + data &= 0xFFF0FFFFFFFFFF; + for (uint8_t i = 0; i < 56; i += 8) { + crc = crc ^ data >> i ^ (data >> (i + 4)); + } + return crc & 0xf; + } +}; + +#endif diff --git a/firmware/baseband/fprotos/subghzdbase.hpp b/firmware/baseband/fprotos/subghzdbase.hpp index bc374d9fa..ca0cbe67b 100644 --- a/firmware/baseband/fprotos/subghzdbase.hpp +++ b/firmware/baseband/fprotos/subghzdbase.hpp @@ -25,10 +25,7 @@ class FProtoSubGhzDBase { // General data holder, these will be passed uint8_t sensorType = FPS_Invalid; - uint8_t btn = SD_NO_BTN; uint16_t data_count_bit = 0; - uint32_t cnt = SD_NO_CNT; - uint32_t serial = SD_NO_SERIAL; uint64_t data = 0; protected: diff --git a/firmware/baseband/fprotos/subghzdprotos.hpp b/firmware/baseband/fprotos/subghzdprotos.hpp index caeb043bd..57ece9f49 100644 --- a/firmware/baseband/fprotos/subghzdprotos.hpp +++ b/firmware/baseband/fprotos/subghzdprotos.hpp @@ -47,6 +47,10 @@ So include here the .hpp, and add a new element to the protos vector in the cons #include "s-smc5326.hpp" #include "s-star_line.hpp" #include "s-x10.hpp" +// #include "s-hormannbisecure.hpp" //fm +#include "s-legrand.hpp" +#include "s-somify_keytis.hpp" +#include "s-somify_telis.hpp" // GENIE FROM PR @@ -94,11 +98,12 @@ class SubGhzDProtos : public FProtoListGeneral { protos[FPS_SECPLUSV1] = new FProtoSubGhzDSecPlusV1(); protos[FPS_SECPLUSV2] = new FProtoSubGhzDSecPlusV2(); protos[FPS_SMC5326] = new FProtoSubGhzDSmc5326(); - // somify keytis skipped - // somify telis skipped + protos[FPS_SOMIFY_KEYTIS] = new FProtoSubGhzDSomifyKeytis(); + protos[FPS_SOMIFY_TELIS] = new FProtoSubGhzDSomifyTelis(); protos[FPS_STARLINE] = new FProtoSubGhzDStarLine(); protos[FPS_X10] = new FProtoSubGhzDX10(); - // genie skipped + // protos[FPS_HORMANNBISECURE] = new FProtoSubGhzDHormannBiSecure(); //fm + protos[FPS_LEGRAND] = new FProtoSubGhzDLegrand(); for (uint8_t i = 0; i < FPS_COUNT; ++i) { if (protos[i] != NULL) protos[i]->setCallback(callbackTarget); @@ -115,7 +120,7 @@ class SubGhzDProtos : public FProtoListGeneral { }; static void callbackTarget(FProtoSubGhzDBase* instance) { - SubGhzDDataMessage packet_message{instance->sensorType, instance->btn, instance->data_count_bit, instance->serial, instance->data, instance->cnt}; + SubGhzDDataMessage packet_message{instance->sensorType, instance->data_count_bit, instance->data}; shared_memory.application_queue.push(packet_message); } diff --git a/firmware/baseband/fprotos/subghztypes.hpp b/firmware/baseband/fprotos/subghztypes.hpp index 872fc22e4..32193dc84 100644 --- a/firmware/baseband/fprotos/subghztypes.hpp +++ b/firmware/baseband/fprotos/subghztypes.hpp @@ -11,10 +11,6 @@ Also it must have a switch-case element in the getSubGhzDSensorTypeName() functi #define FPM_AM 0 #define FPM_FM 1 -#define SD_NO_SERIAL 0xFFFFFFFF -#define SD_NO_BTN 0xFF -#define SD_NO_CNT 0xFF - enum FPROTO_SUBGHZD_SENSOR : uint8_t { FPS_Invalid = 0, FPS_PRINCETON, @@ -35,10 +31,12 @@ enum FPROTO_SUBGHZD_SENSOR : uint8_t { FPS_HONEYWELL, FPS_HONEYWELLWDB, FPS_HORMANN, + // FPS_HORMANNBISECURE, FPS_IDO, FPS_INTERTECHNOV3, FPS_KEELOQ, FPS_KINGGATESSTYLO4K, + FPS_LEGRAND, FPS_LINEAR, FPS_LINEARDELTA3, FPS_MAGELLAN, @@ -56,7 +54,8 @@ enum FPROTO_SUBGHZD_SENSOR : uint8_t { FPS_SMC5326, FPS_STARLINE, FPS_X10, - + FPS_SOMIFY_KEYTIS, + FPS_SOMIFY_TELIS, FPS_COUNT }; diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index c5ce6b905..2a422be74 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -1289,24 +1289,15 @@ class SubGhzDDataMessage : public Message { public: constexpr SubGhzDDataMessage( uint8_t sensorType = 0, - uint8_t btn = 0xFF, uint16_t bits = 0, - uint32_t serial = 0xFFFFFFFF, - uint64_t data = 0, - uint32_t cnt = 0xFF) + uint64_t data = 0) : Message{ID::SubGhzDData}, sensorType{sensorType}, - btn{btn}, bits{bits}, - serial{serial}, - cnt{cnt}, data{data} { } uint8_t sensorType = 0; - uint8_t btn = 0xFF; uint16_t bits = 0; - uint32_t serial = 0xFFFFFFFF; - uint32_t cnt = 0xFF; uint64_t data = 0; };