mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-12-15 10:44:34 -05:00
762 lines
23 KiB
C++
762 lines
23 KiB
C++
/*
|
|
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
|
* Copyright (C) 2017 Furrtek
|
|
*
|
|
* This file is part of PortaPack.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "ui_subghzd.hpp"
|
|
#include "audio.hpp"
|
|
#include "baseband_api.hpp"
|
|
#include "string_format.hpp"
|
|
#include "file_path.hpp"
|
|
#include "portapack_persistent_memory.hpp"
|
|
|
|
using namespace portapack;
|
|
using namespace ui;
|
|
|
|
namespace ui {
|
|
|
|
std::string SubGhzDRecentEntry::to_csv() {
|
|
std::string csv = ";";
|
|
csv += SubGhzDView::getSensorTypeName((FPROTO_SUBGHZD_SENSOR)sensorType);
|
|
csv += ";" + to_string_dec_uint(bits) + ";";
|
|
csv += to_string_hex(data, 64 / 4);
|
|
return csv;
|
|
}
|
|
|
|
void SubGhzDLogger::log_data(SubGhzDRecentEntry& data) {
|
|
log_file.write_entry(data.to_csv());
|
|
}
|
|
|
|
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(serial));
|
|
if (entry_.bits > 0) console.writeln("Bits: " + to_string_dec_uint(entry_.bits));
|
|
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));
|
|
}
|
|
|
|
SubGhzDRecentEntryDetailView::SubGhzDRecentEntryDetailView(NavigationView& nav, const SubGhzDRecentEntry& entry)
|
|
: nav_{nav},
|
|
entry_{entry} {
|
|
add_children({&button_done,
|
|
&text_type,
|
|
&text_id,
|
|
&console,
|
|
&labels});
|
|
|
|
button_done.on_select = [&nav](const ui::Button&) {
|
|
nav.pop();
|
|
};
|
|
update_data();
|
|
}
|
|
|
|
void SubGhzDRecentEntryDetailView::focus() {
|
|
button_done.focus();
|
|
}
|
|
|
|
void SubGhzDView::focus() {
|
|
field_frequency.focus();
|
|
}
|
|
|
|
SubGhzDView::SubGhzDView(NavigationView& nav)
|
|
: nav_{nav} {
|
|
add_children({&rssi,
|
|
&field_rf_amp,
|
|
&field_lna,
|
|
&field_vga,
|
|
&field_frequency,
|
|
&button_clear_list,
|
|
&check_log,
|
|
&recent_entries_view});
|
|
|
|
baseband::run_image(portapack::spi_flash::image_tag_subghzd);
|
|
logger = std::make_unique<SubGhzDLogger>();
|
|
|
|
button_clear_list.on_select = [this](Button&) {
|
|
recent.clear();
|
|
recent_entries_view.set_dirty();
|
|
};
|
|
field_frequency.set_step(10000);
|
|
check_log.on_select = [this](Checkbox&, bool v) {
|
|
logging = v;
|
|
if (logger && logging) {
|
|
logger->append(logs_dir.string() + "/SUBGHZDLOG_" + to_string_timestamp(rtc_time::now()) + ".CSV");
|
|
logger->write_header();
|
|
}
|
|
};
|
|
check_log.set_value(logging);
|
|
const Rect content_rect{0, header_height, screen_width, screen_height - header_height};
|
|
recent_entries_view.set_parent_rect(content_rect);
|
|
recent_entries_view.on_select = [this](const SubGhzDRecentEntry& entry) {
|
|
nav_.push<SubGhzDRecentEntryDetailView>(entry);
|
|
};
|
|
baseband::set_subghzd_config(0, receiver_model.sampling_rate()); // 0=am
|
|
receiver_model.enable();
|
|
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
|
on_tick_second();
|
|
};
|
|
}
|
|
|
|
void SubGhzDView::on_tick_second() {
|
|
for (auto& entry : recent) {
|
|
entry.inc_age(1);
|
|
}
|
|
recent_entries_view.set_dirty();
|
|
}
|
|
|
|
void SubGhzDView::on_data(const SubGhzDDataMessage* data) {
|
|
SubGhzDRecentEntry key{data->sensorType, data->data, data->bits};
|
|
if (logger && logging) {
|
|
logger->log_data(key);
|
|
}
|
|
auto matching_recent = find(recent, key.key());
|
|
if (matching_recent != std::end(recent)) {
|
|
// Found within. Move to front of list, increment counter.
|
|
(*matching_recent).reset_age();
|
|
recent.push_front(*matching_recent);
|
|
recent.erase(matching_recent);
|
|
} else {
|
|
recent.emplace_front(key);
|
|
truncate_entries(recent, 64);
|
|
}
|
|
recent_entries_view.set_dirty();
|
|
}
|
|
|
|
SubGhzDView::~SubGhzDView() {
|
|
rtc_time::signal_tick_second -= signal_token_tick_second;
|
|
receiver_model.disable();
|
|
baseband::shutdown();
|
|
}
|
|
|
|
const char* SubGhzDView::getSensorTypeName(FPROTO_SUBGHZD_SENSOR type) {
|
|
switch (type) {
|
|
case FPS_PRINCETON:
|
|
return "Princeton";
|
|
case FPS_BETT:
|
|
return "Bett";
|
|
case FPS_CAME:
|
|
return "Came";
|
|
case FPS_PRASTEL:
|
|
return "Prastel";
|
|
case FPS_AIRFORCE:
|
|
return "Airforce";
|
|
case FPS_CAMEATOMO:
|
|
return "Came Atomo";
|
|
case FPS_CAMETWEE:
|
|
return "Came Twee";
|
|
case FPS_CHAMBCODE:
|
|
return "Chamb Code";
|
|
case FPS_CLEMSA:
|
|
return "Clemsa";
|
|
case FPS_DOITRAND:
|
|
return "Doitrand";
|
|
case FPS_DOOYA:
|
|
return "Dooya";
|
|
case FPS_FAAC:
|
|
return "Faac";
|
|
case FPS_GATETX:
|
|
return "Gate TX";
|
|
case FPS_HOLTEK:
|
|
return "Holtek";
|
|
case FPS_HOLTEKHT12X:
|
|
return "Holtek HT12X";
|
|
case FPS_HONEYWELL:
|
|
return "Honeywell";
|
|
case FPS_HONEYWELLWDB:
|
|
return "Honeywell Wdb";
|
|
case FPS_HORMANN:
|
|
return "Hormann";
|
|
case FPS_IDO:
|
|
return "Ido 11x";
|
|
case FPS_INTERTECHNOV3:
|
|
return "InterTehcno v3";
|
|
case FPS_KEELOQ:
|
|
return "KeeLoq";
|
|
case FPS_KINGGATESSTYLO4K:
|
|
return "Kinggate Stylo4K";
|
|
case FPS_LINEAR:
|
|
return "Linear";
|
|
case FPS_LINEARDELTA3:
|
|
return "Linear Delta3";
|
|
case FPS_MAGELLAN:
|
|
return "Magellan";
|
|
case FPS_MARANTEC:
|
|
return "Marantec";
|
|
case FPS_MASTERCODE:
|
|
return "Mastercode";
|
|
case FPS_MEGACODE:
|
|
return "Megacode";
|
|
case FPS_NERORADIO:
|
|
return "Nero Radio";
|
|
case FPS_NERO_SKETCH:
|
|
return "Nero Sketch";
|
|
case FPS_NICEFLO:
|
|
return "Nice Flo";
|
|
case FPS_NICEFLORS:
|
|
return "Nice Flor S";
|
|
case FPS_PHOENIXV2:
|
|
return "Phoenix V2";
|
|
case FPS_POWERSMART:
|
|
return "PowerSmart";
|
|
case FPS_SECPLUSV1:
|
|
return "SecPlus V1";
|
|
case FPS_SECPLUSV2:
|
|
return "SecPlus V2";
|
|
case FPS_SMC5326:
|
|
return "SMC5326";
|
|
case FPS_STARLINE:
|
|
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_GANGQI:
|
|
return "GangQi";
|
|
case FPS_MARANTEC24:
|
|
return "Marantec24";
|
|
case FPS_Invalid:
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
std::string SubGhzDView::pad_string_with_spaces(int snakes) {
|
|
std::string paddedStr(snakes, ' ');
|
|
return paddedStr;
|
|
}
|
|
|
|
void SubGhzDView::on_freqchg(int64_t freq) {
|
|
field_frequency.set_value(freq);
|
|
}
|
|
|
|
template <>
|
|
void RecentEntriesTable<ui::SubGhzDRecentEntries>::draw(
|
|
const Entry& entry,
|
|
const Rect& target_rect,
|
|
Painter& painter,
|
|
const Style& style) {
|
|
std::string line{};
|
|
line.reserve(30);
|
|
|
|
line = SubGhzDView::getSensorTypeName((FPROTO_SUBGHZD_SENSOR)entry.sensorType);
|
|
line = line + " " + to_string_hex(entry.data << 32);
|
|
if (line.length() < 19) {
|
|
line += SubGhzDView::pad_string_with_spaces(19 - line.length());
|
|
} else {
|
|
line = truncate(line, 19);
|
|
}
|
|
std::string ageStr = to_string_dec_uint(entry.age);
|
|
std::string bitsStr = to_string_dec_uint(entry.bits);
|
|
line += SubGhzDView::pad_string_with_spaces(5 - bitsStr.length()) + bitsStr;
|
|
line += SubGhzDView::pad_string_with_spaces(4 - ageStr.length()) + ageStr;
|
|
|
|
line.resize(target_rect.width() / 8, ' ');
|
|
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;
|
|
}
|
|
|
|
if (entry_.sensorType == FPS_GANGQI) {
|
|
btn = 0; // parser needs some time i think in flipper side.
|
|
cnt = (uint8_t)(entry_.data >> 32);
|
|
serial = (entry_.data & 0xFFFFFFFF);
|
|
return;
|
|
}
|
|
|
|
if (entry_.sensorType == FPS_MARANTEC24) {
|
|
serial = (entry_.data >> 4);
|
|
btn = entry_.data & 0xf;
|
|
return;
|
|
}
|
|
}
|
|
} // namespace ui
|