diff --git a/firmware/application/apps/ui_subghzd.cpp b/firmware/application/apps/ui_subghzd.cpp index e482eb77d..027e39124 100644 --- a/firmware/application/apps/ui_subghzd.cpp +++ b/firmware/application/apps/ui_subghzd.cpp @@ -61,6 +61,19 @@ void SubGhzDRecentEntryDetailView::update_data() { if (entry_.data != 0) console.writeln("Data: " + to_string_hex(entry_.data)); + if (entry_.sensorType == FPS_RESTAURANT_PAGER) { + uint8_t pager_addr = (entry_.data >> 5) & 0x0F; + uint8_t func_code = (entry_.data >> 1) & 0x0F; + console.writeln("Station: 0x" + to_string_hex(serial) + " (" + to_string_dec_uint(serial) + ")"); + console.writeln("Pager: " + to_string_dec_uint(pager_addr)); + if (func_code == 0x0D) + console.writeln("Action: Buzz"); + else if (func_code == 0x0F) + console.writeln("Action: Sync"); + else + console.writeln("Action: 0x" + to_string_hex(func_code)); + } + if (entry_.sensorType == FPS_KEELOQ) { console.writeln("Fix: " + to_string_hex(fix)); console.writeln("Encrypted: " + to_string_hex(encrypted)); @@ -280,6 +293,8 @@ const char* SubGhzDView::getSensorTypeName(FPROTO_SUBGHZD_SENSOR type) { return "Marantec24"; case FPS_HOLTEKHT6P20B: return "Holtek HT6P20B"; + case FPS_RESTAURANT_PAGER: + return "Rest. Pager"; case FPS_Invalid: default: return "Unknown"; @@ -306,7 +321,14 @@ void RecentEntriesTable::draw( line.reserve(30); line = SubGhzDView::getSensorTypeName((FPROTO_SUBGHZD_SENSOR)entry.sensorType); - line = line + " " + to_string_hex(entry.data << 32); + if (entry.sensorType == FPS_RESTAURANT_PAGER) { + uint8_t pgr = (entry.data >> 5) & 0x0F; + uint8_t func = (entry.data >> 1) & 0x0F; + line += " P:" + to_string_dec_uint(pgr) + (func == 0x0D ? " Buzz" : func == 0x0F ? " Sync" + : ""); + } else { + line = line + " " + to_string_hex(entry.data << 32); + } line.resize(columns.at(0).second, ' '); std::string ageStr = to_string_dec_uint(entry.age); std::string bitsStr = to_string_dec_uint(entry.bits); @@ -873,5 +895,12 @@ void SubGhzDRecentEntryDetailView::parseProtocol() { btn = (entry_.data >> 4) & 0xF; return; } + + if (entry_.sensorType == FPS_RESTAURANT_PAGER) { + // 25-bit EV1527-variant: [sysid:16][pager:4][func:4][stop:1] + serial = (entry_.data >> 9) & 0xFFFF; // System ID + // btn/cnt left as SD_NO values; friendly output in update_data() + return; + } } } // namespace ui diff --git a/firmware/baseband/fprotos/s-restaurant_pager.hpp b/firmware/baseband/fprotos/s-restaurant_pager.hpp new file mode 100644 index 000000000..875f2368c --- /dev/null +++ b/firmware/baseband/fprotos/s-restaurant_pager.hpp @@ -0,0 +1,75 @@ + +#ifndef __FPROTO_RESTAURANT_PAGER_H__ +#define __FPROTO_RESTAURANT_PAGER_H__ + +#include "subghzdbase.hpp" + +typedef enum : uint8_t { + RestaurantPagerDecoderStepReset = 0, + RestaurantPagerDecoderStepSaveDuration, + RestaurantPagerDecoderStepCheckDuration, +} RestaurantPagerDecoderStep; + +class FProtoSubGhzDRestaurantPager : public FProtoSubGhzDBase { + public: + FProtoSubGhzDRestaurantPager() { + sensorType = FPS_RESTAURANT_PAGER; + te_short = 204; + te_long = 636; + te_delta = 100; + min_count_bit_for_found = 25; + } + + void feed(bool level, uint32_t duration) { + switch (parser_step) { + case RestaurantPagerDecoderStepReset: + if ((!level) && (DURATION_DIFF(duration, te_short * 36) < te_delta * 36)) { + // Found preamble + parser_step = RestaurantPagerDecoderStepSaveDuration; + decode_data = 0; + decode_count_bit = 0; + } + break; + case RestaurantPagerDecoderStepSaveDuration: + if (level) { + te_last = duration; + parser_step = RestaurantPagerDecoderStepCheckDuration; + } + break; + case RestaurantPagerDecoderStepCheckDuration: + if (!level) { + if (duration >= ((uint32_t)te_long * 2)) { + parser_step = RestaurantPagerDecoderStepSaveDuration; + if (decode_count_bit == min_count_bit_for_found) { + // Skip all-ones preamble frames + if ((decode_data >> 1) != 0xFFFFFF) { + data_count_bit = decode_count_bit; + if (callback) callback(this); + } + } + decode_data = 0; + decode_count_bit = 0; + break; + } + + 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 = RestaurantPagerDecoderStepSaveDuration; + } 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 = RestaurantPagerDecoderStepSaveDuration; + } else { + parser_step = RestaurantPagerDecoderStepReset; + } + } else { + parser_step = RestaurantPagerDecoderStepReset; + } + break; + } + } +}; + +#endif diff --git a/firmware/baseband/fprotos/subghzdprotos.hpp b/firmware/baseband/fprotos/subghzdprotos.hpp index 82ed3889e..cdc83b87f 100644 --- a/firmware/baseband/fprotos/subghzdprotos.hpp +++ b/firmware/baseband/fprotos/subghzdprotos.hpp @@ -55,6 +55,7 @@ So include here the .hpp, and add a new element to the protos vector in the cons #include "s-marantec24.hpp" // GENIE FROM PR #include "s-holtek_ht6p20b.hpp" +#include "s-restaurant_pager.hpp" #ifndef __FPROTO_PROTOLISTSGZ_H__ #define __FPROTO_PROTOLISTSGZ_H__ @@ -109,6 +110,7 @@ class SubGhzDProtos : public FProtoListGeneral { protos[FPS_GANGQI] = new FProtoSubGhzDGangqi(); protos[FPS_MARANTEC24] = new FProtoSubGhzDMarantec24(); protos[FPS_HOLTEKHT6P20B] = new FProtoSubGhzDHoltekHt6p20b(); + protos[FPS_RESTAURANT_PAGER] = new FProtoSubGhzDRestaurantPager(); for (uint8_t i = 0; i < FPS_COUNT; ++i) { if (protos[i] != NULL) protos[i]->setCallback(callbackTarget); diff --git a/firmware/baseband/fprotos/subghztypes.hpp b/firmware/baseband/fprotos/subghztypes.hpp index e2fe99960..89cdcb53d 100644 --- a/firmware/baseband/fprotos/subghztypes.hpp +++ b/firmware/baseband/fprotos/subghztypes.hpp @@ -59,6 +59,7 @@ enum FPROTO_SUBGHZD_SENSOR : uint8_t { FPS_GANGQI, FPS_MARANTEC24, FPS_HOLTEKHT6P20B, + FPS_RESTAURANT_PAGER, FPS_COUNT };