mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-10-01 01:26:06 -04:00
Subghz decoder (#1646)
* Initial commit - wip
* Half part of the transition of baseband processor.
* More SGD
* WIP, Weather refactor, UI improv
* Rename
* Added 4msps, and fixes
* Fixes
* princeton working
* Renamed proc_weather, bc now multifunctional
* Proto: bett
* FPS_CAME = 4,
FPS_PRASTEL = 5,
FPS_AIRFORCE = 6,
* Came Atomo, fixes
* Separate weather and sgd, bc of baseband size limit
* Fix display
* Save space
* More protos
* Dooya proto added
* More protos
* add protos
* More protos
* Move weather to ext app
* nw
* Revert "Move weather to ext app"
This reverts commit 8a84aac2f5
.
* revert
* Fix merge
* Better naming
* More protos
* More protos
* Add protos
* Fix warning
* Add NeroRadio
* more protos
* more protos
* More protos
* Shrink a bit
* fixes
* More protos
* Nicer code
* Fix naming
* Fix format
* Remove unused
* Fix some protos, that needs a LOOOONG part with the same lo/high
* Modify key calculation
This commit is contained in:
parent
02810bf527
commit
2ccda5aebd
@ -301,6 +301,7 @@ set(CPPSRC
|
||||
apps/ui_spectrum_painter.cpp
|
||||
apps/ui_ss_viewer.cpp
|
||||
apps/ui_sstvtx.cpp
|
||||
apps/ui_subghzd.cpp
|
||||
# apps/ui_test.cpp
|
||||
apps/ui_text_editor.cpp
|
||||
apps/ui_tone_search.cpp
|
||||
|
243
firmware/application/apps/ui_subghzd.cpp
Normal file
243
firmware/application/apps/ui_subghzd.cpp
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* 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 "portapack_persistent_memory.hpp"
|
||||
|
||||
using namespace portapack;
|
||||
using namespace ui;
|
||||
|
||||
namespace ui {
|
||||
|
||||
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_.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 (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,
|
||||
&recent_entries_view});
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_subghzd);
|
||||
|
||||
button_clear_list.on_select = [this](Button&) {
|
||||
recent.clear();
|
||||
recent_entries_view.set_dirty();
|
||||
};
|
||||
field_frequency.set_step(100000);
|
||||
|
||||
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(0); // am
|
||||
receiver_model.set_sampling_rate(4'000'000);
|
||||
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->serial, data->bits, data->data, data->btn, data->cnt};
|
||||
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_Invalid:
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string SubGhzDView::pad_string_with_spaces(int snakes) {
|
||||
std::string paddedStr(snakes, ' ');
|
||||
return paddedStr;
|
||||
}
|
||||
|
||||
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.serial);
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace ui
|
171
firmware/application/apps/ui_subghzd.hpp
Normal file
171
firmware/application/apps/ui_subghzd.hpp
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __UI_SUBGHZD_H__
|
||||
#define __UI_SUBGHZD_H__
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_freq_field.hpp"
|
||||
#include "app_settings.hpp"
|
||||
#include "radio_state.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "recent_entries.hpp"
|
||||
|
||||
#include "../baseband/fprotos/subghztypes.hpp"
|
||||
|
||||
using namespace ui;
|
||||
|
||||
namespace ui {
|
||||
|
||||
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)
|
||||
: sensorType{sensorType},
|
||||
btn{btn},
|
||||
serial{serial},
|
||||
bits{bits},
|
||||
cnt{cnt},
|
||||
data{data} {
|
||||
}
|
||||
Key key() const {
|
||||
return (data ^ ((static_cast<uint64_t>(serial) << 32) | (static_cast<uint64_t>(sensorType) & 0xFF) << 0));
|
||||
}
|
||||
void inc_age(int delta) {
|
||||
if (UINT16_MAX - delta > age) age += delta;
|
||||
}
|
||||
void reset_age() {
|
||||
age = 0;
|
||||
}
|
||||
};
|
||||
using SubGhzDRecentEntries = RecentEntries<SubGhzDRecentEntry>;
|
||||
using SubGhzDRecentEntriesView = RecentEntriesView<SubGhzDRecentEntries>;
|
||||
|
||||
class SubGhzDView : public View {
|
||||
public:
|
||||
SubGhzDView(NavigationView& nav);
|
||||
~SubGhzDView();
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "SubGhzD"; };
|
||||
static const char* getSensorTypeName(FPROTO_SUBGHZD_SENSOR type);
|
||||
static std::string pad_string_with_spaces(int snakes);
|
||||
|
||||
private:
|
||||
void on_tick_second();
|
||||
void on_data(const SubGhzDDataMessage* data);
|
||||
|
||||
NavigationView& nav_;
|
||||
RxRadioState radio_state_{
|
||||
433'920'000 /* frequency */,
|
||||
1'750'000 /* bandwidth */,
|
||||
4'000'000 /* sampling rate */,
|
||||
ReceiverModel::Mode::AMAudio};
|
||||
app_settings::SettingsManager settings_{
|
||||
"rx_subghzd",
|
||||
app_settings::Mode::RX,
|
||||
{}};
|
||||
|
||||
SubGhzDRecentEntries recent{};
|
||||
|
||||
RFAmpField field_rf_amp{
|
||||
{13 * 8, 0 * 16}};
|
||||
LNAGainField field_lna{
|
||||
{15 * 8, 0 * 16}};
|
||||
VGAGainField field_vga{
|
||||
{18 * 8, 0 * 16}};
|
||||
RSSI rssi{
|
||||
{21 * 8, 0, 6 * 8, 4}};
|
||||
RxFrequencyField field_frequency{
|
||||
{0 * 8, 0 * 16},
|
||||
nav_};
|
||||
|
||||
SignalToken signal_token_tick_second{};
|
||||
|
||||
Button button_clear_list{
|
||||
{0, 16, 7 * 8, 32},
|
||||
"Clear"};
|
||||
|
||||
static constexpr auto header_height = 3 * 16;
|
||||
|
||||
const RecentEntriesColumns columns{{
|
||||
{"Type", 19},
|
||||
{"Bits", 4},
|
||||
{"Age", 3},
|
||||
}};
|
||||
SubGhzDRecentEntriesView recent_entries_view{columns, recent};
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
Message::ID::SubGhzDData,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const SubGhzDDataMessage*>(p);
|
||||
this->on_data(message);
|
||||
}};
|
||||
};
|
||||
|
||||
class SubGhzDRecentEntryDetailView : public View {
|
||||
public:
|
||||
SubGhzDRecentEntryDetailView(NavigationView& nav, const SubGhzDRecentEntry& entry);
|
||||
|
||||
void update_data();
|
||||
void focus() override;
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
SubGhzDRecentEntry entry_{};
|
||||
Text text_type{{0 * 8, 1 * 16, 15 * 8, 16}, "?"};
|
||||
Text text_id{{6 * 8, 2 * 16, 10 * 8, 16}, "?"};
|
||||
|
||||
Console console{
|
||||
{0, 4 * 16, 240, screen_height - (4 * 16) - 36}};
|
||||
|
||||
Labels labels{
|
||||
{{0 * 8, 0 * 16}, "Type:", Color::light_grey()},
|
||||
{{0 * 8, 2 * 16}, "Serial: ", Color::light_grey()},
|
||||
{{0 * 8, 3 * 16}, "Data:", Color::light_grey()},
|
||||
};
|
||||
|
||||
Button button_done{
|
||||
{screen_width - 96 - 4, screen_height - 32 - 12, 96, 32},
|
||||
"Done"};
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
||||
#endif /*__UI_SUBGHZD_H__*/
|
@ -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");
|
||||
}
|
||||
|
||||
@ -205,8 +220,8 @@ void RecentEntriesTable<ui::WeatherRecentEntries>::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;
|
||||
|
@ -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},
|
||||
|
@ -320,7 +320,12 @@ void set_spectrum_painter_config(const uint16_t width, const uint16_t height, bo
|
||||
}
|
||||
|
||||
void set_weather() {
|
||||
const WeatherRxConfigureMessage message{};
|
||||
const SubGhzFPRxConfigureMessage message{0};
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
void set_subghzd(uint8_t modulation = 0) {
|
||||
const SubGhzFPRxConfigureMessage message{modulation};
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
|
@ -89,6 +89,7 @@ void set_siggen_tone(const uint32_t tone);
|
||||
void set_siggen_config(const uint32_t bw, const uint32_t shape, const uint32_t duration);
|
||||
void set_spectrum_painter_config(const uint16_t width, const uint16_t height, bool update, int32_t bw);
|
||||
void set_weather();
|
||||
void set_subghzd(uint8_t modulation);
|
||||
void request_beep();
|
||||
|
||||
void run_image(const portapack::spi_flash::image_tag_t image_tag);
|
||||
|
@ -80,6 +80,7 @@
|
||||
#include "ui_touchtunes.hpp"
|
||||
#include "ui_view_wav.hpp"
|
||||
#include "ui_weatherstation.hpp"
|
||||
#include "ui_subghzd.hpp"
|
||||
#include "ui_whipcalc.hpp"
|
||||
#include "ui_external_items_menu_loader.hpp"
|
||||
|
||||
@ -567,6 +568,7 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
|
||||
{"Search", Color::yellow(), &bitmap_icon_search, [&nav]() { nav.push<SearchView>(); }},
|
||||
{"TPMS Cars", Color::green(), &bitmap_icon_tpms, [&nav]() { nav.push<TPMSAppView>(); }},
|
||||
{"Weather", Color::green(), &bitmap_icon_thermometer, [&nav]() { nav.push<WeatherView>(); }},
|
||||
{"SubGhzD", Color::yellow(), &bitmap_icon_remote, [&nav]() { nav.push<SubGhzDView>(); }},
|
||||
// {"FSK RX", Color::yellow(), &bitmap_icon_remote, [&nav]() { nav.push<FskxRxMainView>(); }},
|
||||
// {"DMR", Color::dark_grey(), &bitmap_icon_dmr, [&nav](){ nav.push<NotImplementedView>(); }},
|
||||
// {"SIGFOX", Color::dark_grey(), &bitmap_icon_fox, [&nav](){ nav.push<NotImplementedView>(); }},
|
||||
|
@ -532,8 +532,15 @@ set(MODE_CPPSRC
|
||||
)
|
||||
DeclareTargets(PWFM wfm_audio)
|
||||
|
||||
### Weather Stations
|
||||
### SubGhz Decoders
|
||||
|
||||
set(MODE_CPPSRC
|
||||
proc_subghzd.cpp
|
||||
)
|
||||
DeclareTargets(PSGD subghzd)
|
||||
|
||||
|
||||
### Weather Stations
|
||||
set(MODE_CPPSRC
|
||||
proc_weather.cpp
|
||||
)
|
||||
|
200
firmware/baseband/fprotos/fprotogeneral.hpp
Normal file
200
firmware/baseband/fprotos/fprotogeneral.hpp
Normal file
@ -0,0 +1,200 @@
|
||||
#ifndef __FPROTO_GENERAL_H__
|
||||
#define __FPROTO_GENERAL_H__
|
||||
|
||||
// useful methods for both weather and subghzd
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define bit_read(value, bit) (((value) >> (bit)) & 0x01)
|
||||
#define bit_set(value, bit) \
|
||||
({ \
|
||||
__typeof__(value) _one = (1); \
|
||||
(value) |= (_one << (bit)); \
|
||||
})
|
||||
#define bit_clear(value, bit) \
|
||||
({ \
|
||||
__typeof__(value) _one = (1); \
|
||||
(value) &= ~(_one << (bit)); \
|
||||
})
|
||||
#define bit_write(value, bit, bitvalue) (bitvalue ? bit_set(value, bit) : bit_clear(value, bit))
|
||||
|
||||
#define DURATION_DIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
|
||||
|
||||
typedef enum {
|
||||
ManchesterStateStart1 = 0,
|
||||
ManchesterStateMid1 = 1,
|
||||
ManchesterStateMid0 = 2,
|
||||
ManchesterStateStart0 = 3
|
||||
} ManchesterState;
|
||||
typedef enum {
|
||||
ManchesterEventShortLow = 0,
|
||||
ManchesterEventShortHigh = 2,
|
||||
ManchesterEventLongLow = 4,
|
||||
ManchesterEventLongHigh = 6,
|
||||
ManchesterEventReset = 8
|
||||
} ManchesterEvent;
|
||||
|
||||
class FProtoGeneral {
|
||||
public:
|
||||
static bool manchester_advance(
|
||||
ManchesterState state,
|
||||
ManchesterEvent event,
|
||||
ManchesterState* next_state,
|
||||
bool* data) {
|
||||
bool result = false;
|
||||
ManchesterState new_state;
|
||||
|
||||
if (event == ManchesterEventReset) {
|
||||
new_state = ManchesterStateMid1;
|
||||
} else {
|
||||
new_state = (ManchesterState)(transitions[state] >> event & 0x3);
|
||||
if (new_state == state) {
|
||||
new_state = ManchesterStateMid1;
|
||||
} else {
|
||||
if (new_state == ManchesterStateMid0) {
|
||||
if (data) *data = false;
|
||||
result = true;
|
||||
} else if (new_state == ManchesterStateMid1) {
|
||||
if (data) *data = true;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*next_state = new_state;
|
||||
return result;
|
||||
}
|
||||
static uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t bit_count) {
|
||||
uint8_t parity = 0;
|
||||
for (uint8_t i = 0; i < bit_count; i++) {
|
||||
parity += bit_read(key, i);
|
||||
}
|
||||
return parity & 0x01;
|
||||
}
|
||||
|
||||
static uint8_t subghz_protocol_blocks_add_bytes(uint8_t const message[], size_t size) {
|
||||
uint32_t result = 0;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
result += message[i];
|
||||
}
|
||||
return (uint8_t)result;
|
||||
}
|
||||
|
||||
static uint8_t subghz_protocol_blocks_parity8(uint8_t byte) {
|
||||
byte ^= byte >> 4;
|
||||
byte &= 0xf;
|
||||
return (0x6996 >> byte) & 1;
|
||||
}
|
||||
|
||||
static uint8_t subghz_protocol_blocks_parity_bytes(uint8_t const message[], size_t size) {
|
||||
uint8_t result = 0;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
result ^= subghz_protocol_blocks_parity8(message[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint8_t subghz_protocol_blocks_lfsr_digest8(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t gen,
|
||||
uint8_t key) {
|
||||
uint8_t sum = 0;
|
||||
for (size_t byte = 0; byte < size; ++byte) {
|
||||
uint8_t data = message[byte];
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
// XOR key into sum if data bit is set
|
||||
if ((data >> i) & 1) sum ^= key;
|
||||
// roll the key right (actually the LSB is dropped here)
|
||||
// and apply the gen (needs to include the dropped LSB as MSB)
|
||||
if (key & 1)
|
||||
key = (key >> 1) ^ gen;
|
||||
else
|
||||
key = (key >> 1);
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
static float locale_fahrenheit_to_celsius(float temp_f) {
|
||||
return (temp_f - 32.f) / 1.8f;
|
||||
}
|
||||
|
||||
static uint8_t subghz_protocol_blocks_crc4(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t polynomial,
|
||||
uint8_t init) {
|
||||
uint8_t remainder = init << 4; // LSBs are unused
|
||||
uint8_t poly = polynomial << 4;
|
||||
uint8_t bit;
|
||||
|
||||
while (size--) {
|
||||
remainder ^= *message++;
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
if (remainder & 0x80) {
|
||||
remainder = (remainder << 1) ^ poly;
|
||||
} else {
|
||||
remainder = (remainder << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return remainder >> 4 & 0x0f; // discard the LSBs
|
||||
}
|
||||
static uint8_t subghz_protocol_blocks_lfsr_digest8_reflect(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t gen,
|
||||
uint8_t key) {
|
||||
uint8_t sum = 0;
|
||||
// Process message from last byte to first byte (reflected)
|
||||
for (int byte = size - 1; byte >= 0; --byte) {
|
||||
uint8_t data = message[byte];
|
||||
// Process individual bits of each byte (reflected)
|
||||
for (uint8_t i = 0; i < 8; ++i) {
|
||||
// XOR key into sum if data bit is set
|
||||
if ((data >> i) & 1) {
|
||||
sum ^= key;
|
||||
}
|
||||
// roll the key left (actually the LSB is dropped here)
|
||||
// and apply the gen (needs to include the dropped lsb as MSB)
|
||||
if (key & 0x80)
|
||||
key = (key << 1) ^ gen;
|
||||
else
|
||||
key = (key << 1);
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
static uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t bit_count) {
|
||||
uint64_t reverse_key = 0;
|
||||
for (uint8_t i = 0; i < bit_count; i++) {
|
||||
reverse_key = reverse_key << 1 | bit_read(key, i);
|
||||
}
|
||||
return reverse_key;
|
||||
}
|
||||
static uint8_t subghz_protocol_blocks_crc8(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t polynomial,
|
||||
uint8_t init) {
|
||||
uint8_t remainder = init;
|
||||
|
||||
for (size_t byte = 0; byte < size; ++byte) {
|
||||
remainder ^= message[byte];
|
||||
for (uint8_t bit = 0; bit < 8; ++bit) {
|
||||
if (remainder & 0x80) {
|
||||
remainder = (remainder << 1) ^ polynomial;
|
||||
} else {
|
||||
remainder = (remainder << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return remainder;
|
||||
}
|
||||
|
||||
private:
|
||||
static inline const uint8_t transitions[] = {0b00000001, 0b10010001, 0b10011011, 0b11111011};
|
||||
};
|
||||
|
||||
#endif
|
16
firmware/baseband/fprotos/fprotolistgeneral.hpp
Normal file
16
firmware/baseband/fprotos/fprotolistgeneral.hpp
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __FPROTO_PROTOLISTGENERAL_H__
|
||||
#define __FPROTO_PROTOLISTGENERAL_H__
|
||||
#include <stdint.h>
|
||||
|
||||
class FProtoListGeneral {
|
||||
public:
|
||||
FProtoListGeneral() {}
|
||||
virtual ~FProtoListGeneral() {}
|
||||
virtual void feed(bool level, uint32_t duration) = 0;
|
||||
void setModulation(uint8_t modulation) { modulation_ = modulation; }
|
||||
|
||||
protected:
|
||||
uint8_t modulation_ = 0;
|
||||
};
|
||||
|
||||
#endif
|
83
firmware/baseband/fprotos/s-bett.hpp
Normal file
83
firmware/baseband/fprotos/s-bett.hpp
Normal file
@ -0,0 +1,83 @@
|
||||
|
||||
#ifndef __FPROTO_BETT_H__
|
||||
#define __FPROTO_BETT_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
BETTDecoderStepReset = 0,
|
||||
BETTDecoderStepSaveDuration,
|
||||
BETTDecoderStepCheckDuration,
|
||||
} BETTDecoderStep;
|
||||
|
||||
class FProtoSubGhzDBett : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDBett() {
|
||||
sensorType = FPS_BETT;
|
||||
te_short = 340;
|
||||
te_long = 2000;
|
||||
te_delta = 150;
|
||||
min_count_bit_for_found = 18;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case BETTDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 44) <
|
||||
(te_delta * 15))) {
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
parser_step = BETTDecoderStepCheckDuration;
|
||||
}
|
||||
break;
|
||||
case BETTDecoderStepSaveDuration:
|
||||
if (!level) {
|
||||
if (DURATION_DIFF(duration, te_short * 44) <
|
||||
(te_delta * 15)) {
|
||||
if (decode_count_bit ==
|
||||
min_count_bit_for_found) {
|
||||
data = decode_data;
|
||||
data_count_bit = decode_count_bit;
|
||||
// dip decoder needed
|
||||
if (callback) callback(this);
|
||||
} else {
|
||||
parser_step = BETTDecoderStepReset;
|
||||
}
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
break;
|
||||
} else {
|
||||
if ((DURATION_DIFF(duration, te_short) <
|
||||
te_delta) ||
|
||||
(DURATION_DIFF(duration, te_long) <
|
||||
te_delta * 3)) {
|
||||
parser_step = BETTDecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = BETTDecoderStepReset;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BETTDecoderStepCheckDuration:
|
||||
if (level) {
|
||||
if (DURATION_DIFF(duration, te_long) <
|
||||
te_delta * 3) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = BETTDecoderStepSaveDuration;
|
||||
} else if (
|
||||
DURATION_DIFF(duration, te_short) <
|
||||
te_delta) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = BETTDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = BETTDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = BETTDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
95
firmware/baseband/fprotos/s-came.hpp
Normal file
95
firmware/baseband/fprotos/s-came.hpp
Normal file
@ -0,0 +1,95 @@
|
||||
|
||||
#ifndef __FPROTO_CAME_H__
|
||||
#define __FPROTO_CAME_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
#define CAME_12_COUNT_BIT 12
|
||||
#define CAME_24_COUNT_BIT 24
|
||||
#define PRASTEL_COUNT_BIT 25
|
||||
#define AIRFORCE_COUNT_BIT 18
|
||||
|
||||
typedef enum : uint8_t {
|
||||
CameDecoderStepReset = 0,
|
||||
CameDecoderStepFoundStartBit,
|
||||
CameDecoderStepSaveDuration,
|
||||
CameDecoderStepCheckDuration,
|
||||
} CameDecoderStep;
|
||||
|
||||
class FProtoSubGhzDCame : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDCame() {
|
||||
sensorType = FPS_CAME;
|
||||
te_short = 320;
|
||||
te_long = 640;
|
||||
te_delta = 150;
|
||||
min_count_bit_for_found = 12;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case CameDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 56) < te_delta * 47)) {
|
||||
// Found header CAME
|
||||
parser_step = CameDecoderStepFoundStartBit;
|
||||
}
|
||||
break;
|
||||
case CameDecoderStepFoundStartBit:
|
||||
if (!level) {
|
||||
break;
|
||||
} else if (
|
||||
DURATION_DIFF(duration, te_short) < te_delta) {
|
||||
// Found start bit CAME
|
||||
parser_step = CameDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = CameDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case CameDecoderStepSaveDuration:
|
||||
if (!level) { // save interval
|
||||
if (duration >= (te_short * 4)) {
|
||||
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
|
||||
sensorType = FPS_CAME;
|
||||
if (decode_count_bit == PRASTEL_COUNT_BIT) sensorType = FPS_PRASTEL;
|
||||
if (decode_count_bit == AIRFORCE_COUNT_BIT) sensorType = FPS_AIRFORCE;
|
||||
if (callback) callback(this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
te_last = duration;
|
||||
parser_step = CameDecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = CameDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case CameDecoderStepCheckDuration:
|
||||
if (level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = CameDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = CameDecoderStepSaveDuration;
|
||||
} else
|
||||
parser_step = CameDecoderStepReset;
|
||||
} else {
|
||||
parser_step = CameDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
133
firmware/baseband/fprotos/s-came_atomo.hpp
Normal file
133
firmware/baseband/fprotos/s-came_atomo.hpp
Normal file
@ -0,0 +1,133 @@
|
||||
|
||||
#ifndef __FPROTO_CAMEATOMO_H__
|
||||
#define __FPROTO_CAMEATOMO_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
CameAtomoDecoderStepReset = 0,
|
||||
CameAtomoDecoderStepDecoderData,
|
||||
} CameAtomoDecoderStep;
|
||||
|
||||
class FProtoSubGhzDCameAtomo : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDCameAtomo() {
|
||||
sensorType = FPS_CAMEATOMO;
|
||||
te_short = 600;
|
||||
te_long = 1200;
|
||||
te_delta = 250;
|
||||
min_count_bit_for_found = 62;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
ManchesterEvent event = ManchesterEventReset;
|
||||
switch (parser_step) {
|
||||
case CameAtomoDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_long * 60) < te_delta * 40)) {
|
||||
// Found header CAME
|
||||
parser_step = CameAtomoDecoderStepDecoderData;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 1;
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventShortLow, &manchester_saved_state, NULL);
|
||||
}
|
||||
break;
|
||||
case CameAtomoDecoderStepDecoderData:
|
||||
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 >= ((uint32_t)te_long * 2 + te_delta)) {
|
||||
if (decode_count_bit ==
|
||||
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;
|
||||
decode_count_bit = 1;
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventShortLow, &manchester_saved_state, NULL);
|
||||
} else {
|
||||
parser_step = CameAtomoDecoderStepReset;
|
||||
}
|
||||
} 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 = CameAtomoDecoderStepReset;
|
||||
}
|
||||
}
|
||||
if (event != ManchesterEventReset) {
|
||||
bool bit;
|
||||
bool data_ok = FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &bit);
|
||||
|
||||
if (data_ok) {
|
||||
decode_data = (decode_data << 1) | !bit;
|
||||
decode_count_bit++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ManchesterState manchester_saved_state = ManchesterStateMid1;
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
147
firmware/baseband/fprotos/s-came_twee.hpp
Normal file
147
firmware/baseband/fprotos/s-came_twee.hpp
Normal file
@ -0,0 +1,147 @@
|
||||
|
||||
#ifndef __FPROTO_CAMETWEE_H__
|
||||
#define __FPROTO_CAMETWEE_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
CameTweeDecoderStepReset = 0,
|
||||
CameTweeDecoderStepDecoderData,
|
||||
} CameTweeDecoderStep;
|
||||
|
||||
class FProtoSubGhzDCameTwee : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDCameTwee() {
|
||||
sensorType = FPS_CAMETWEE;
|
||||
te_short = 500;
|
||||
te_long = 1000;
|
||||
te_delta = 250;
|
||||
min_count_bit_for_found = 54;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
ManchesterEvent event = ManchesterEventReset;
|
||||
switch (parser_step) {
|
||||
case CameTweeDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_long * 51) < te_delta * 20)) {
|
||||
// Found header CAME
|
||||
parser_step = CameTweeDecoderStepDecoderData;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongLow, &manchester_saved_state, NULL);
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongHigh, &manchester_saved_state, NULL);
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventShortLow, &manchester_saved_state, NULL);
|
||||
}
|
||||
break;
|
||||
case CameTweeDecoderStepDecoderData:
|
||||
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 >= ((uint32_t)te_long * 2 + te_delta)) {
|
||||
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;
|
||||
decode_count_bit = 0;
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongLow, &manchester_saved_state, NULL);
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongHigh, &manchester_saved_state, NULL);
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventShortLow, &manchester_saved_state, NULL);
|
||||
} else {
|
||||
parser_step = CameTweeDecoderStepReset;
|
||||
}
|
||||
} 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 = CameTweeDecoderStepReset;
|
||||
}
|
||||
}
|
||||
if (event != ManchesterEventReset) {
|
||||
bool bit;
|
||||
if (FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &bit)) {
|
||||
decode_data = (decode_data << 1) | !bit;
|
||||
decode_count_bit++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
151
firmware/baseband/fprotos/s-chambcode.hpp
Normal file
151
firmware/baseband/fprotos/s-chambcode.hpp
Normal file
@ -0,0 +1,151 @@
|
||||
|
||||
#ifndef __FPROTO_CHAMBCODE_H__
|
||||
#define __FPROTO_CHAMBCODE_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
#define CHAMBERLAIN_CODE_BIT_STOP 0b0001
|
||||
#define CHAMBERLAIN_CODE_BIT_1 0b0011
|
||||
#define CHAMBERLAIN_CODE_BIT_0 0b0111
|
||||
|
||||
#define CHAMBERLAIN_7_CODE_MASK 0xF000000FF0F
|
||||
#define CHAMBERLAIN_8_CODE_MASK 0xF00000F00F
|
||||
#define CHAMBERLAIN_9_CODE_MASK 0xF000000000F
|
||||
|
||||
#define CHAMBERLAIN_7_CODE_MASK_CHECK 0x10000001101
|
||||
#define CHAMBERLAIN_8_CODE_MASK_CHECK 0x1000001001
|
||||
#define CHAMBERLAIN_9_CODE_MASK_CHECK 0x10000000001
|
||||
|
||||
typedef enum : uint8_t {
|
||||
Chamb_CodeDecoderStepReset = 0,
|
||||
Chamb_CodeDecoderStepFoundStartBit,
|
||||
Chamb_CodeDecoderStepSaveDuration,
|
||||
Chamb_CodeDecoderStepCheckDuration,
|
||||
} Chamb_CodeDecoderStep;
|
||||
|
||||
class FProtoSubGhzDChambCode : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDChambCode() {
|
||||
sensorType = FPS_CHAMBCODE;
|
||||
te_short = 1000;
|
||||
te_long = 3000;
|
||||
te_delta = 200;
|
||||
min_count_bit_for_found = 10;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case Chamb_CodeDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 39) < te_delta * 20)) {
|
||||
// Found header Chamb_Code
|
||||
parser_step = Chamb_CodeDecoderStepFoundStartBit;
|
||||
}
|
||||
break;
|
||||
case Chamb_CodeDecoderStepFoundStartBit:
|
||||
if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
// Found start bit Chamb_Code
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
decode_data = decode_data << 4 | CHAMBERLAIN_CODE_BIT_STOP;
|
||||
decode_count_bit++;
|
||||
parser_step = Chamb_CodeDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = Chamb_CodeDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case Chamb_CodeDecoderStepSaveDuration:
|
||||
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;
|
||||
if (callback) callback(this);
|
||||
}
|
||||
}
|
||||
parser_step = Chamb_CodeDecoderStepReset;
|
||||
} else {
|
||||
te_last = duration;
|
||||
parser_step = Chamb_CodeDecoderStepCheckDuration;
|
||||
}
|
||||
} else {
|
||||
parser_step = Chamb_CodeDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case Chamb_CodeDecoderStepCheckDuration:
|
||||
if (level) { // Found stop bit Chamb_Code
|
||||
if ((DURATION_DIFF(te_last, te_short * 3) <
|
||||
te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
decode_data = decode_data << 4 | CHAMBERLAIN_CODE_BIT_STOP;
|
||||
decode_count_bit++;
|
||||
parser_step = Chamb_CodeDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_short * 2) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short * 2) < te_delta)) {
|
||||
decode_data = decode_data << 4 | CHAMBERLAIN_CODE_BIT_1;
|
||||
decode_count_bit++;
|
||||
parser_step = Chamb_CodeDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short * 3) < te_delta)) {
|
||||
decode_data = decode_data << 4 | CHAMBERLAIN_CODE_BIT_0;
|
||||
decode_count_bit++;
|
||||
parser_step = Chamb_CodeDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = Chamb_CodeDecoderStepReset;
|
||||
}
|
||||
|
||||
} else {
|
||||
parser_step = Chamb_CodeDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool subghz_protocol_decoder_chamb_code_check_mask_and_parse() {
|
||||
if (decode_count_bit > min_count_bit_for_found + 1)
|
||||
return false;
|
||||
|
||||
if ((decode_data & CHAMBERLAIN_7_CODE_MASK) == CHAMBERLAIN_7_CODE_MASK_CHECK) {
|
||||
decode_count_bit = 7;
|
||||
decode_data &= ~CHAMBERLAIN_7_CODE_MASK;
|
||||
decode_data = (decode_data >> 12) | ((decode_data >> 4) & 0xF);
|
||||
} else if (
|
||||
(decode_data & CHAMBERLAIN_8_CODE_MASK) == CHAMBERLAIN_8_CODE_MASK_CHECK) {
|
||||
decode_count_bit = 8;
|
||||
decode_data &= ~CHAMBERLAIN_8_CODE_MASK;
|
||||
decode_data = decode_data >> 4 | CHAMBERLAIN_CODE_BIT_0 << 8; // DIP 6 no use
|
||||
} else if (
|
||||
(decode_data & CHAMBERLAIN_9_CODE_MASK) == CHAMBERLAIN_9_CODE_MASK_CHECK) {
|
||||
decode_count_bit = 9;
|
||||
decode_data &= ~CHAMBERLAIN_9_CODE_MASK;
|
||||
decode_data >>= 4;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return subghz_protocol_chamb_code_to_bit(&decode_data, decode_count_bit);
|
||||
}
|
||||
|
||||
bool subghz_protocol_chamb_code_to_bit(uint64_t* data, uint8_t size) {
|
||||
uint64_t data_tmp = data[0];
|
||||
uint64_t data_res = 0;
|
||||
for (uint8_t i = 0; i < size; i++) {
|
||||
if ((data_tmp & 0xFll) == CHAMBERLAIN_CODE_BIT_0) {
|
||||
bit_write(data_res, i, 0);
|
||||
} else if ((data_tmp & 0xFll) == CHAMBERLAIN_CODE_BIT_1) {
|
||||
bit_write(data_res, i, 1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
data_tmp >>= 4;
|
||||
}
|
||||
data[0] = data_res;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
89
firmware/baseband/fprotos/s-clemsa.hpp
Normal file
89
firmware/baseband/fprotos/s-clemsa.hpp
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
#ifndef __FPROTO_CLEMSA_H__
|
||||
#define __FPROTO_CLEMSA_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
ClemsaDecoderStepReset = 0,
|
||||
ClemsaDecoderStepSaveDuration,
|
||||
ClemsaDecoderStepCheckDuration,
|
||||
} ClemsaDecoderStep;
|
||||
|
||||
class FProtoSubGhzDClemsa : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDClemsa() {
|
||||
sensorType = FPS_CLEMSA;
|
||||
te_short = 385;
|
||||
te_long = 2695;
|
||||
te_delta = 150;
|
||||
min_count_bit_for_found = 18;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case ClemsaDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 51) < te_delta * 25)) {
|
||||
parser_step = ClemsaDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ClemsaDecoderStepSaveDuration:
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
parser_step = ClemsaDecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = ClemsaDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
|
||||
case ClemsaDecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
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 = ClemsaDecoderStepSaveDuration;
|
||||
} 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 = ClemsaDecoderStepSaveDuration;
|
||||
} else if (
|
||||
DURATION_DIFF(duration, te_short * 51) < te_delta * 25) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
} else if ((DURATION_DIFF(te_last, te_long) < te_delta * 3)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
} else {
|
||||
parser_step = ClemsaDecoderStepReset;
|
||||
}
|
||||
|
||||
if (decode_count_bit ==
|
||||
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;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
|
||||
} else {
|
||||
parser_step = ClemsaDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = ClemsaDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
86
firmware/baseband/fprotos/s-doitrand.hpp
Normal file
86
firmware/baseband/fprotos/s-doitrand.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
|
||||
#ifndef __FPROTO_DOITRAND_H__
|
||||
#define __FPROTO_DOITRAND_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
DoitrandDecoderStepReset = 0,
|
||||
DoitrandDecoderStepFoundStartBit,
|
||||
DoitrandDecoderStepSaveDuration,
|
||||
DoitrandDecoderStepCheckDuration,
|
||||
} DoitrandDecoderStep;
|
||||
|
||||
class FProtoSubGhzDDoitrand : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDDoitrand() {
|
||||
sensorType = FPS_DOITRAND;
|
||||
te_short = 400;
|
||||
te_long = 1100;
|
||||
te_delta = 150;
|
||||
min_count_bit_for_found = 37;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case DoitrandDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 62) < te_delta * 30)) {
|
||||
// Found Preambula
|
||||
parser_step = DoitrandDecoderStepFoundStartBit;
|
||||
}
|
||||
break;
|
||||
case DoitrandDecoderStepFoundStartBit:
|
||||
if (level && ((DURATION_DIFF(duration, (te_short * 2)) < te_delta * 3))) {
|
||||
// Found start bit
|
||||
parser_step = DoitrandDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = DoitrandDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case DoitrandDecoderStepSaveDuration:
|
||||
if (!level) {
|
||||
if (duration >= ((uint32_t)te_short * 10 + te_delta)) {
|
||||
parser_step = DoitrandDecoderStepFoundStartBit;
|
||||
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;
|
||||
decode_count_bit = 0;
|
||||
break;
|
||||
} else {
|
||||
te_last = duration;
|
||||
parser_step = DoitrandDecoderStepCheckDuration;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DoitrandDecoderStepCheckDuration:
|
||||
if (level) {
|
||||
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 = DoitrandDecoderStepSaveDuration;
|
||||
} 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 = DoitrandDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = DoitrandDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = DoitrandDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
111
firmware/baseband/fprotos/s-dooya.hpp
Normal file
111
firmware/baseband/fprotos/s-dooya.hpp
Normal file
@ -0,0 +1,111 @@
|
||||
|
||||
#ifndef __FPROTO_DOOYA_H__
|
||||
#define __FPROTO_DOOYA_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
DooyaDecoderStepReset = 0,
|
||||
DooyaDecoderStepFoundStartBit,
|
||||
DooyaDecoderStepSaveDuration,
|
||||
DooyaDecoderStepCheckDuration,
|
||||
} DooyaDecoderStep;
|
||||
|
||||
class FProtoSubGhzDDooya : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDDooya() {
|
||||
sensorType = FPS_DOOYA;
|
||||
te_short = 366;
|
||||
te_long = 733;
|
||||
te_delta = 120;
|
||||
min_count_bit_for_found = 40;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case DooyaDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_long * 12) < te_delta * 20)) {
|
||||
parser_step = DooyaDecoderStepFoundStartBit;
|
||||
}
|
||||
break;
|
||||
|
||||
case DooyaDecoderStepFoundStartBit:
|
||||
if (!level) {
|
||||
if (DURATION_DIFF(duration, te_long * 2) < te_delta * 3) {
|
||||
parser_step = DooyaDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = DooyaDecoderStepReset;
|
||||
}
|
||||
} else if (
|
||||
DURATION_DIFF(duration, te_short * 13) < te_delta * 5) {
|
||||
break;
|
||||
} else {
|
||||
parser_step = DooyaDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
|
||||
case DooyaDecoderStepSaveDuration:
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
parser_step = DooyaDecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = DooyaDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
|
||||
case DooyaDecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if (duration >= (te_long * 4)) {
|
||||
// add last bit
|
||||
if (DURATION_DIFF(te_last, te_short) < te_delta) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
} else if (
|
||||
DURATION_DIFF(te_last, te_long) <
|
||||
te_delta * 2) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
} else {
|
||||
parser_step = DooyaDecoderStepReset;
|
||||
break;
|
||||
}
|
||||
parser_step = DooyaDecoderStepFoundStartBit;
|
||||
if (decode_count_bit ==
|
||||
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;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta * 2)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = DooyaDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta * 2) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = DooyaDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = DooyaDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = DooyaDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
85
firmware/baseband/fprotos/s-faac.hpp
Normal file
85
firmware/baseband/fprotos/s-faac.hpp
Normal file
@ -0,0 +1,85 @@
|
||||
|
||||
#ifndef __FPROTO_FAAC_H__
|
||||
#define __FPROTO_FAAC_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
FaacSLHDecoderStepReset = 0,
|
||||
FaacSLHDecoderStepFoundPreambula,
|
||||
FaacSLHDecoderStepSaveDuration,
|
||||
FaacSLHDecoderStepCheckDuration,
|
||||
} FaacSLHDecoderStep;
|
||||
|
||||
class FProtoSubGhzDFaac : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDFaac() {
|
||||
sensorType = FPS_FAAC;
|
||||
te_short = 255;
|
||||
te_long = 595;
|
||||
te_delta = 100;
|
||||
min_count_bit_for_found = 64;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case FaacSLHDecoderStepReset:
|
||||
if ((level) && (DURATION_DIFF(duration, te_long * 2) < te_delta * 3)) {
|
||||
parser_step = FaacSLHDecoderStepFoundPreambula;
|
||||
}
|
||||
break;
|
||||
case FaacSLHDecoderStepFoundPreambula:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_long * 2) < te_delta * 3)) {
|
||||
// Found Preambula
|
||||
parser_step = FaacSLHDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = FaacSLHDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case FaacSLHDecoderStepSaveDuration:
|
||||
if (level) {
|
||||
if (duration >= ((uint32_t)te_short * 3 + te_delta)) {
|
||||
parser_step = FaacSLHDecoderStepFoundPreambula;
|
||||
if (decode_count_bit == min_count_bit_for_found) {
|
||||
data = decode_data;
|
||||
data_count_bit = decode_count_bit;
|
||||
// remark controller skipped
|
||||
if (callback) callback(this);
|
||||
}
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
break;
|
||||
} else {
|
||||
te_last = duration;
|
||||
parser_step = FaacSLHDecoderStepCheckDuration;
|
||||
}
|
||||
|
||||
} else {
|
||||
parser_step = FaacSLHDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case FaacSLHDecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = FaacSLHDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = FaacSLHDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = FaacSLHDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = FaacSLHDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
88
firmware/baseband/fprotos/s-gate_tx.hpp
Normal file
88
firmware/baseband/fprotos/s-gate_tx.hpp
Normal file
@ -0,0 +1,88 @@
|
||||
|
||||
#ifndef __FPROTO_GATETX_H__
|
||||
#define __FPROTO_GATETX_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
GateTXDecoderStepReset = 0,
|
||||
GateTXDecoderStepFoundStartBit,
|
||||
GateTXDecoderStepSaveDuration,
|
||||
GateTXDecoderStepCheckDuration,
|
||||
} GateTXDecoderStep;
|
||||
|
||||
class FProtoSubGhzDGateTx : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDGateTx() {
|
||||
sensorType = FPS_GATETX;
|
||||
te_short = 350;
|
||||
te_long = 700;
|
||||
te_delta = 100;
|
||||
min_count_bit_for_found = 24;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case GateTXDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 47) < te_delta * 47)) {
|
||||
// Found Preambula
|
||||
parser_step = GateTXDecoderStepFoundStartBit;
|
||||
}
|
||||
break;
|
||||
case GateTXDecoderStepFoundStartBit:
|
||||
if (level && ((DURATION_DIFF(duration, te_long) < te_delta * 3))) {
|
||||
// Found start bit
|
||||
parser_step = GateTXDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = GateTXDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case GateTXDecoderStepSaveDuration:
|
||||
if (!level) {
|
||||
if (duration >= ((uint32_t)te_short * 10 + te_delta)) {
|
||||
parser_step = GateTXDecoderStepFoundStartBit;
|
||||
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;
|
||||
decode_count_bit = 0;
|
||||
break;
|
||||
} else {
|
||||
te_last = duration;
|
||||
parser_step = GateTXDecoderStepCheckDuration;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GateTXDecoderStepCheckDuration:
|
||||
if (level) {
|
||||
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 = GateTXDecoderStepSaveDuration;
|
||||
} 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 = GateTXDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = GateTXDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = GateTXDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
107
firmware/baseband/fprotos/s-holtek.hpp
Normal file
107
firmware/baseband/fprotos/s-holtek.hpp
Normal file
@ -0,0 +1,107 @@
|
||||
|
||||
#ifndef __FPROTO_HOLTEK_H__
|
||||
#define __FPROTO_HOLTEK_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
#define HOLTEK_HEADER_MASK 0xF000000000
|
||||
#define HOLTEK_HEADER 0x5000000000
|
||||
|
||||
typedef enum : uint8_t {
|
||||
HoltekDecoderStepReset = 0,
|
||||
HoltekDecoderStepFoundStartBit,
|
||||
HoltekDecoderStepSaveDuration,
|
||||
HoltekDecoderStepCheckDuration,
|
||||
} HoltekDecoderStep;
|
||||
|
||||
class FProtoSubGhzDHoltek : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDHoltek() {
|
||||
sensorType = FPS_HOLTEK;
|
||||
te_short = 430;
|
||||
te_long = 870;
|
||||
te_delta = 100;
|
||||
min_count_bit_for_found = 40;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case HoltekDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 36) < te_delta * 36)) {
|
||||
// Found Preambula
|
||||
parser_step = HoltekDecoderStepFoundStartBit;
|
||||
}
|
||||
break;
|
||||
case HoltekDecoderStepFoundStartBit:
|
||||
if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
// Found StartBit
|
||||
parser_step = HoltekDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = HoltekDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case HoltekDecoderStepSaveDuration:
|
||||
// save duration
|
||||
if (!level) {
|
||||
if (duration >= ((uint32_t)te_short * 10 + te_delta)) {
|
||||
if (decode_count_bit ==
|
||||
min_count_bit_for_found) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
parser_step = HoltekDecoderStepFoundStartBit;
|
||||
break;
|
||||
} else {
|
||||
te_last = duration;
|
||||
parser_step = HoltekDecoderStepCheckDuration;
|
||||
}
|
||||
} else {
|
||||
parser_step = HoltekDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case HoltekDecoderStepCheckDuration:
|
||||
if (level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta * 2)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = HoltekDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta * 2) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = HoltekDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = HoltekDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = HoltekDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
90
firmware/baseband/fprotos/s-holtek_ht12x.hpp
Normal file
90
firmware/baseband/fprotos/s-holtek_ht12x.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
|
||||
#ifndef __FPROTO_HOLTEKTH12X_H__
|
||||
#define __FPROTO_HOLTEKTH12X_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
Holtek_HT12XDecoderStepReset = 0,
|
||||
Holtek_HT12XDecoderStepFoundStartBit,
|
||||
Holtek_HT12XDecoderStepSaveDuration,
|
||||
Holtek_HT12XDecoderStepCheckDuration,
|
||||
} Holtek_HT12XDecoderStep;
|
||||
|
||||
class FProtoSubGhzDHoltekHt12x : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDHoltekHt12x() {
|
||||
sensorType = FPS_HOLTEKHT12X;
|
||||
te_short = 320;
|
||||
te_long = 640;
|
||||
te_delta = 200;
|
||||
min_count_bit_for_found = 12;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case Holtek_HT12XDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 36) < te_delta * 36)) {
|
||||
// Found Preambula
|
||||
parser_step = Holtek_HT12XDecoderStepFoundStartBit;
|
||||
}
|
||||
break;
|
||||
case Holtek_HT12XDecoderStepFoundStartBit:
|
||||
if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
// Found StartBit
|
||||
parser_step = Holtek_HT12XDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = Holtek_HT12XDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case Holtek_HT12XDecoderStepSaveDuration:
|
||||
// save duration
|
||||
if (!level) {
|
||||
if (duration >= ((uint32_t)te_short * 10 + te_delta)) {
|
||||
if (decode_count_bit == min_count_bit_for_found) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
parser_step = Holtek_HT12XDecoderStepFoundStartBit;
|
||||
break;
|
||||
} else {
|
||||
te_last = duration;
|
||||
parser_step = Holtek_HT12XDecoderStepCheckDuration;
|
||||
}
|
||||
} else {
|
||||
parser_step = Holtek_HT12XDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case Holtek_HT12XDecoderStepCheckDuration:
|
||||
if (level) {
|
||||
if ((DURATION_DIFF(te_last, te_long) < te_delta * 2) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = Holtek_HT12XDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta * 2)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = Holtek_HT12XDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = Holtek_HT12XDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = Holtek_HT12XDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
108
firmware/baseband/fprotos/s-honeywell.hpp
Normal file
108
firmware/baseband/fprotos/s-honeywell.hpp
Normal file
@ -0,0 +1,108 @@
|
||||
|
||||
#ifndef __FPROTO_HONEYWELL_H__
|
||||
#define __FPROTO_HONEYWELL_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
class FProtoSubGhzDHoneywell : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDHoneywell() {
|
||||
sensorType = FPS_HONEYWELL;
|
||||
te_short = 280;
|
||||
te_long = 143;
|
||||
te_delta = 51;
|
||||
min_count_bit_for_found = 62;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
ManchesterEvent event = ManchesterEventReset;
|
||||
if (!level) {
|
||||
if (DURATION_DIFF(duration, te_short) < te_delta) {
|
||||
event = ManchesterEventShortLow;
|
||||
} else if (
|
||||
DURATION_DIFF(duration, te_long) < te_delta * 2) {
|
||||
event = ManchesterEventLongLow;
|
||||
}
|
||||
} else {
|
||||
if (DURATION_DIFF(duration, te_short) < te_delta) {
|
||||
event = ManchesterEventShortHigh;
|
||||
} else if (
|
||||
DURATION_DIFF(duration, te_long) < te_delta * 2) {
|
||||
event = ManchesterEventLongHigh;
|
||||
}
|
||||
}
|
||||
if (event != ManchesterEventReset) {
|
||||
bool bit;
|
||||
bool data_ok = FProtoGeneral::manchester_advance(
|
||||
manchester_saved_state, event, &manchester_saved_state, &bit);
|
||||
if (data_ok) {
|
||||
subghz_protocol_decoder_honeywell_addbit(bit);
|
||||
}
|
||||
} else {
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ManchesterState manchester_saved_state = ManchesterStateMid1;
|
||||
|
||||
void subghz_protocol_decoder_honeywell_addbit(bool bit) {
|
||||
decode_data = (decode_data << 1) | bit;
|
||||
decode_count_bit++;
|
||||
|
||||
uint16_t preamble = (decode_data >> 48) & 0xFFFF;
|
||||
// can be multiple, since flipper can't read it well..
|
||||
if (preamble == 0b0011111111111110 || preamble == 0b0111111111111110 ||
|
||||
preamble == 0b1111111111111110) {
|
||||
uint8_t datatocrc[4];
|
||||
datatocrc[0] = (decode_data >> 40) & 0xFFFF;
|
||||
datatocrc[1] = (decode_data >> 32) & 0xFFFF;
|
||||
datatocrc[2] = (decode_data >> 24) & 0xFFFF;
|
||||
datatocrc[3] = (decode_data >> 16) & 0xFFFF;
|
||||
uint8_t channel = (decode_data >> 44) & 0xF;
|
||||
uint16_t crc_calc = 0;
|
||||
if (channel == 0x2 || channel == 0x4 || channel == 0xA) {
|
||||
// 2GIG brand
|
||||
crc_calc = subghz_protocol_honeywell_crc16(datatocrc, 4, 0x8050, 0);
|
||||
} else { // channel == 0x8
|
||||
crc_calc = subghz_protocol_honeywell_crc16(datatocrc, 4, 0x8005, 0);
|
||||
}
|
||||
uint16_t crc = decode_data & 0xFFFF;
|
||||
if (crc == crc_calc) {
|
||||
// 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;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint16_t subghz_protocol_honeywell_crc16(
|
||||
uint8_t const message[],
|
||||
unsigned nBytes,
|
||||
uint16_t polynomial,
|
||||
uint16_t init) {
|
||||
uint16_t remainder = init;
|
||||
unsigned byte, bit;
|
||||
|
||||
for (byte = 0; byte < nBytes; ++byte) {
|
||||
remainder ^= message[byte] << 8;
|
||||
for (bit = 0; bit < 8; ++bit) {
|
||||
if (remainder & 0x8000) {
|
||||
remainder = (remainder << 1) ^ polynomial;
|
||||
} else {
|
||||
remainder = (remainder << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return remainder;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
74
firmware/baseband/fprotos/s-honeywellwdb.hpp
Normal file
74
firmware/baseband/fprotos/s-honeywellwdb.hpp
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
#ifndef __FPROTO_HONEYWELLWDB_H__
|
||||
#define __FPROTO_HONEYWELLWDB_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
Honeywell_WDBDecoderStepReset = 0,
|
||||
Honeywell_WDBDecoderStepFoundStartBit,
|
||||
Honeywell_WDBDecoderStepSaveDuration,
|
||||
Honeywell_WDBDecoderStepCheckDuration,
|
||||
} Honeywell_WDBDecoderStep;
|
||||
|
||||
class FProtoSubGhzDHoneywellWdb : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDHoneywellWdb() {
|
||||
sensorType = FPS_HONEYWELLWDB;
|
||||
te_short = 160;
|
||||
te_long = 320;
|
||||
te_delta = 61;
|
||||
min_count_bit_for_found = 48;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case Honeywell_WDBDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 3) < te_delta)) {
|
||||
// Found header Honeywell_WDB
|
||||
decode_count_bit = 0;
|
||||
decode_data = 0;
|
||||
parser_step = Honeywell_WDBDecoderStepSaveDuration;
|
||||
}
|
||||
break;
|
||||
case Honeywell_WDBDecoderStepSaveDuration:
|
||||
if (level) { // save interval
|
||||
if (DURATION_DIFF(duration, te_short * 3) < te_delta) {
|
||||
if ((decode_count_bit == min_count_bit_for_found) &&
|
||||
((decode_data & 0x01) == FProtoGeneral::subghz_protocol_blocks_get_parity(decode_data >> 1, min_count_bit_for_found - 1))) {
|
||||
data = decode_data;
|
||||
data_count_bit = decode_count_bit;
|
||||
// controller has too much, should be done on ui side
|
||||
if (callback) callback(this);
|
||||
}
|
||||
parser_step = Honeywell_WDBDecoderStepReset;
|
||||
break;
|
||||
}
|
||||
te_last = duration;
|
||||
parser_step = Honeywell_WDBDecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = Honeywell_WDBDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case Honeywell_WDBDecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = Honeywell_WDBDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = Honeywell_WDBDecoderStepSaveDuration;
|
||||
} else
|
||||
parser_step = Honeywell_WDBDecoderStepReset;
|
||||
} else {
|
||||
parser_step = Honeywell_WDBDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
85
firmware/baseband/fprotos/s-hormann.hpp
Normal file
85
firmware/baseband/fprotos/s-hormann.hpp
Normal file
@ -0,0 +1,85 @@
|
||||
|
||||
#ifndef __FPROTO_HORMANN_H__
|
||||
#define __FPROTO_HORMANN_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
HormannDecoderStepReset = 0,
|
||||
HormannDecoderStepFoundStartHeader,
|
||||
HormannDecoderStepFoundHeader,
|
||||
HormannDecoderStepFoundStartBit,
|
||||
HormannDecoderStepSaveDuration,
|
||||
HormannDecoderStepCheckDuration,
|
||||
} HormannDecoderStep;
|
||||
|
||||
#define HORMANN_HSM_PATTERN 0xFF000000003
|
||||
|
||||
class FProtoSubGhzDHormann : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDHormann() {
|
||||
sensorType = FPS_HORMANN;
|
||||
te_short = 500;
|
||||
te_long = 1000;
|
||||
te_delta = 200;
|
||||
min_count_bit_for_found = 44;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case HormannDecoderStepReset:
|
||||
if ((level) && (DURATION_DIFF(duration, te_short * 24) < te_delta * 24)) {
|
||||
parser_step = HormannDecoderStepFoundStartBit;
|
||||
}
|
||||
break;
|
||||
case HormannDecoderStepFoundStartBit:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
parser_step = HormannDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = HormannDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case HormannDecoderStepSaveDuration:
|
||||
if (level) { // save interval
|
||||
if (duration >= (te_short * 5) && (decode_data & HORMANN_HSM_PATTERN) == HORMANN_HSM_PATTERN) {
|
||||
parser_step = HormannDecoderStepFoundStartBit;
|
||||
if (decode_count_bit >=
|
||||
min_count_bit_for_found) {
|
||||
data = decode_data;
|
||||
data_count_bit = decode_count_bit;
|
||||
// controller
|
||||
btn = (data >> 4) & 0xF;
|
||||
if (callback) callback(this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
te_last = duration;
|
||||
parser_step = HormannDecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = HormannDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case HormannDecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = HormannDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = HormannDecoderStepSaveDuration;
|
||||
} else
|
||||
parser_step = HormannDecoderStepReset;
|
||||
} else {
|
||||
parser_step = HormannDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
91
firmware/baseband/fprotos/s-ido.hpp
Normal file
91
firmware/baseband/fprotos/s-ido.hpp
Normal file
@ -0,0 +1,91 @@
|
||||
|
||||
#ifndef __FPROTO_IDO_H__
|
||||
#define __FPROTO_IDO_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
IDoDecoderStepReset = 0,
|
||||
IDoDecoderStepFoundPreambula,
|
||||
IDoDecoderStepSaveDuration,
|
||||
IDoDecoderStepCheckDuration,
|
||||
} IDoDecoderStep;
|
||||
|
||||
class FProtoSubGhzDIdo : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDIdo() {
|
||||
sensorType = FPS_IDO;
|
||||
te_short = 450;
|
||||
te_long = 1450;
|
||||
te_delta = 150;
|
||||
min_count_bit_for_found = 48;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case IDoDecoderStepReset:
|
||||
if ((level) && (DURATION_DIFF(duration, te_short * 10) < te_delta * 5)) {
|
||||
parser_step = IDoDecoderStepFoundPreambula;
|
||||
}
|
||||
break;
|
||||
case IDoDecoderStepFoundPreambula:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 10) < te_delta * 5)) {
|
||||
// Found Preambula
|
||||
parser_step = IDoDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = IDoDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case IDoDecoderStepSaveDuration:
|
||||
if (level) {
|
||||
if (duration >= ((uint32_t)te_short * 5 + te_delta)) {
|
||||
parser_step = IDoDecoderStepFoundPreambula;
|
||||
if (decode_count_bit >=
|
||||
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;
|
||||
decode_count_bit = 0;
|
||||
break;
|
||||
} else {
|
||||
te_last = duration;
|
||||
parser_step = IDoDecoderStepCheckDuration;
|
||||
}
|
||||
|
||||
} else {
|
||||
parser_step = IDoDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case IDoDecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
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 = IDoDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_short) < te_delta * 3) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = IDoDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = IDoDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = IDoDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
148
firmware/baseband/fprotos/s-intertechnov3.hpp
Normal file
148
firmware/baseband/fprotos/s-intertechnov3.hpp
Normal file
@ -0,0 +1,148 @@
|
||||
|
||||
#ifndef __FPROTO_INTERTECHNOV3_H__
|
||||
#define __FPROTO_INTERTECHNOV3_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
#define INTERTECHNO_V3_DIMMING_COUNT_BIT 36
|
||||
|
||||
typedef enum : uint8_t {
|
||||
IntertechnoV3DecoderStepReset = 0,
|
||||
IntertechnoV3DecoderStepStartSync,
|
||||
IntertechnoV3DecoderStepFoundSync,
|
||||
IntertechnoV3DecoderStepStartDuration,
|
||||
IntertechnoV3DecoderStepSaveDuration,
|
||||
IntertechnoV3DecoderStepCheckDuration,
|
||||
IntertechnoV3DecoderStepEndDuration,
|
||||
} IntertechnoV3DecoderStep;
|
||||
|
||||
class FProtoSubGhzDIntertechnoV3 : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDIntertechnoV3() {
|
||||
sensorType = FPS_INTERTECHNOV3;
|
||||
te_short = 275;
|
||||
te_long = 1375;
|
||||
te_delta = 150;
|
||||
min_count_bit_for_found = 32;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case IntertechnoV3DecoderStepReset:
|
||||
if ((!level) &&
|
||||
(DURATION_DIFF(duration, te_short * 37) < te_delta * 15)) {
|
||||
parser_step = IntertechnoV3DecoderStepStartSync;
|
||||
}
|
||||
break;
|
||||
case IntertechnoV3DecoderStepStartSync:
|
||||
if (level && (DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
parser_step = IntertechnoV3DecoderStepFoundSync;
|
||||
} else {
|
||||
parser_step = IntertechnoV3DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
|
||||
case IntertechnoV3DecoderStepFoundSync:
|
||||
if (!level && (DURATION_DIFF(duration, te_short * 10) < te_delta * 3)) {
|
||||
parser_step = IntertechnoV3DecoderStepStartDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = IntertechnoV3DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
|
||||
case IntertechnoV3DecoderStepStartDuration:
|
||||
if (level && (DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
parser_step = IntertechnoV3DecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = IntertechnoV3DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
|
||||
case IntertechnoV3DecoderStepSaveDuration:
|
||||
if (!level) { // save interval
|
||||
if (duration >= (te_short * 11)) {
|
||||
parser_step = IntertechnoV3DecoderStepStartSync;
|
||||
if ((decode_count_bit == min_count_bit_for_found) ||
|
||||
(decode_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT)) {
|
||||
data = decode_data;
|
||||
data_count_bit = decode_count_bit;
|
||||
remote_controller();
|
||||
if (callback) callback(this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
te_last = duration;
|
||||
parser_step = IntertechnoV3DecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = IntertechnoV3DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case IntertechnoV3DecoderStepCheckDuration:
|
||||
if (level) {
|
||||
// Add 0 bit
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = IntertechnoV3DecoderStepEndDuration;
|
||||
} else if (
|
||||
// Add 1 bit
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta * 2) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = IntertechnoV3DecoderStepEndDuration;
|
||||
|
||||
} else if (
|
||||
// Add dimm_state
|
||||
(DURATION_DIFF(te_last, te_short) < te_delta * 2) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta) &&
|
||||
(decode_count_bit == 27)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = IntertechnoV3DecoderStepEndDuration;
|
||||
|
||||
} else
|
||||
parser_step = IntertechnoV3DecoderStepReset;
|
||||
} else {
|
||||
parser_step = IntertechnoV3DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
|
||||
case IntertechnoV3DecoderStepEndDuration:
|
||||
if (!level && ((DURATION_DIFF(duration, te_short) < te_delta) ||
|
||||
(DURATION_DIFF(duration, te_long) < te_delta * 2))) {
|
||||
parser_step = IntertechnoV3DecoderStepStartDuration;
|
||||
} else {
|
||||
parser_step = IntertechnoV3DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
107
firmware/baseband/fprotos/s-keeloq.hpp
Normal file
107
firmware/baseband/fprotos/s-keeloq.hpp
Normal file
@ -0,0 +1,107 @@
|
||||
|
||||
#ifndef __FPROTO_KEELOQ_H__
|
||||
#define __FPROTO_KEELOQ_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
KeeloqDecoderStepReset = 0,
|
||||
KeeloqDecoderStepCheckPreambula,
|
||||
KeeloqDecoderStepSaveDuration,
|
||||
KeeloqDecoderStepCheckDuration,
|
||||
} KeeloqDecoderStep;
|
||||
|
||||
class FProtoSubGhzDKeeLoq : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDKeeLoq() {
|
||||
sensorType = FPS_KEELOQ;
|
||||
te_short = 400;
|
||||
te_long = 800;
|
||||
te_delta = 140;
|
||||
min_count_bit_for_found = 64;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case KeeloqDecoderStepReset:
|
||||
if ((level) && DURATION_DIFF(duration, te_short) < te_delta) {
|
||||
parser_step = KeeloqDecoderStepCheckPreambula;
|
||||
header_count++;
|
||||
}
|
||||
break;
|
||||
case KeeloqDecoderStepCheckPreambula:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
parser_step = KeeloqDecoderStepReset;
|
||||
break;
|
||||
}
|
||||
if ((header_count > 2) && (DURATION_DIFF(duration, te_short * 10) < te_delta * 10)) {
|
||||
// Found header
|
||||
parser_step = KeeloqDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = KeeloqDecoderStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
case KeeloqDecoderStepSaveDuration:
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
parser_step = KeeloqDecoderStepCheckDuration;
|
||||
}
|
||||
break;
|
||||
case KeeloqDecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if (duration >= ((uint32_t)te_short * 2 + te_delta)) {
|
||||
// Found end TX
|
||||
parser_step = KeeloqDecoderStepReset;
|
||||
if ((decode_count_bit >= min_count_bit_for_found) &&
|
||||
(decode_count_bit <= min_count_bit_for_found + 2)) {
|
||||
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;
|
||||
decode_count_bit = 0;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta * 2)) {
|
||||
if (decode_count_bit < min_count_bit_for_found) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
} else {
|
||||
decode_count_bit++;
|
||||
}
|
||||
parser_step = KeeloqDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta * 2) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
if (decode_count_bit < min_count_bit_for_found) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
} else {
|
||||
decode_count_bit++;
|
||||
}
|
||||
parser_step = KeeloqDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = KeeloqDecoderStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
} else {
|
||||
parser_step = KeeloqDecoderStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
124
firmware/baseband/fprotos/s-kinggates_stylo_4k.hpp
Normal file
124
firmware/baseband/fprotos/s-kinggates_stylo_4k.hpp
Normal file
@ -0,0 +1,124 @@
|
||||
|
||||
#ifndef __FPROTO_KINGGATES_STYLO_4K_H__
|
||||
#define __FPROTO_KINGGATES_STYLO_4K_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
KingGates_stylo_4kDecoderStepReset = 0,
|
||||
KingGates_stylo_4kDecoderStepCheckPreambula,
|
||||
KingGates_stylo_4kDecoderStepCheckStartBit,
|
||||
KingGates_stylo_4kDecoderStepSaveDuration,
|
||||
KingGates_stylo_4kDecoderStepCheckDuration,
|
||||
} KingGates_stylo_4kDecoderStep;
|
||||
|
||||
class FProtoSubGhzDKinggatesStylo4K : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDKinggatesStylo4K() {
|
||||
sensorType = FPS_KINGGATESSTYLO4K;
|
||||
te_short = 400;
|
||||
te_long = 1100;
|
||||
te_delta = 140;
|
||||
min_count_bit_for_found = 89;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case KingGates_stylo_4kDecoderStepReset:
|
||||
if ((level) && DURATION_DIFF(duration, te_short) < te_delta) {
|
||||
parser_step = KingGates_stylo_4kDecoderStepCheckPreambula;
|
||||
header_count++;
|
||||
}
|
||||
break;
|
||||
case KingGates_stylo_4kDecoderStepCheckPreambula:
|
||||
if ((!level) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
parser_step = KingGates_stylo_4kDecoderStepReset;
|
||||
break;
|
||||
}
|
||||
if ((header_count > 2) &&
|
||||
(DURATION_DIFF(duration, te_long * 2) < te_delta * 2)) {
|
||||
// Found header
|
||||
parser_step = KingGates_stylo_4kDecoderStepCheckStartBit;
|
||||
} else {
|
||||
parser_step = KingGates_stylo_4kDecoderStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
case KingGates_stylo_4kDecoderStepCheckStartBit:
|
||||
if ((level) &&
|
||||
DURATION_DIFF(duration, te_short * 2) < te_delta * 2) {
|
||||
parser_step = KingGates_stylo_4kDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
data_2 = 0;
|
||||
decode_count_bit = 0;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
case KingGates_stylo_4kDecoderStepSaveDuration:
|
||||
if (!level) {
|
||||
if (duration >= ((uint32_t)te_long * 3)) {
|
||||
if (decode_count_bit ==
|
||||
min_count_bit_for_found) {
|
||||
data = data_2;
|
||||
data_2 = decode_data;
|
||||
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);
|
||||
}
|
||||
|
||||
parser_step = KingGates_stylo_4kDecoderStepReset;
|
||||
decode_data = 0;
|
||||
data_2 = 0;
|
||||
decode_count_bit = 0;
|
||||
header_count = 0;
|
||||
break;
|
||||
} else {
|
||||
te_last = duration;
|
||||
parser_step = KingGates_stylo_4kDecoderStepCheckDuration;
|
||||
}
|
||||
} else {
|
||||
parser_step = KingGates_stylo_4kDecoderStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
case KingGates_stylo_4kDecoderStepCheckDuration:
|
||||
if (level) {
|
||||
if ((DURATION_DIFF(
|
||||
te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta * 2)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = KingGates_stylo_4kDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(
|
||||
te_last, te_long) <
|
||||
te_delta * 2) &&
|
||||
(DURATION_DIFF(duration, te_short) <
|
||||
te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = KingGates_stylo_4kDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = KingGates_stylo_4kDecoderStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
if (decode_count_bit == 53) {
|
||||
data_2 = decode_data;
|
||||
decode_data = 0;
|
||||
}
|
||||
} else {
|
||||
parser_step = KingGates_stylo_4kDecoderStepReset;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
uint64_t data_2 = 0;
|
||||
};
|
||||
|
||||
#endif
|
88
firmware/baseband/fprotos/s-linear.hpp
Normal file
88
firmware/baseband/fprotos/s-linear.hpp
Normal file
@ -0,0 +1,88 @@
|
||||
|
||||
#ifndef __FPROTO_LINEAR_H__
|
||||
#define __FPROTO_LINEAR_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
LinearDecoderStepReset = 0,
|
||||
LinearDecoderStepSaveDuration,
|
||||
LinearDecoderStepCheckDuration,
|
||||
} LinearDecoderStep;
|
||||
|
||||
class FProtoSubGhzDLinear : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDLinear() {
|
||||
sensorType = FPS_LINEAR;
|
||||
te_short = 500;
|
||||
te_long = 1500;
|
||||
te_delta = 150;
|
||||
min_count_bit_for_found = 10;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case LinearDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 42) < te_delta * 20)) {
|
||||
// Found header Linear
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
parser_step = LinearDecoderStepSaveDuration;
|
||||
}
|
||||
break;
|
||||
case LinearDecoderStepSaveDuration:
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
parser_step = LinearDecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = LinearDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case LinearDecoderStepCheckDuration:
|
||||
if (!level) { // save interval
|
||||
if (duration >= (te_short * 5)) {
|
||||
parser_step = LinearDecoderStepReset;
|
||||
// checking that the duration matches the guardtime
|
||||
if ((DURATION_DIFF(duration, te_short * 42) > te_delta * 20)) {
|
||||
break;
|
||||
}
|
||||
if (DURATION_DIFF(te_last, te_short) < te_delta) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
} else if (
|
||||
DURATION_DIFF(te_last, te_long) <
|
||||
te_delta) {
|
||||
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;
|
||||
}
|
||||
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = LinearDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = LinearDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = LinearDecoderStepReset;
|
||||
}
|
||||
|
||||
} else {
|
||||
parser_step = LinearDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
87
firmware/baseband/fprotos/s-linear_delta3.hpp
Normal file
87
firmware/baseband/fprotos/s-linear_delta3.hpp
Normal file
@ -0,0 +1,87 @@
|
||||
|
||||
#ifndef __FPROTO_LINEARDELTA3_H__
|
||||
#define __FPROTO_LINEARDELTA3_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
LinearD3DecoderStepReset = 0,
|
||||
LinearD3DecoderStepSaveDuration,
|
||||
LinearD3DecoderStepCheckDuration,
|
||||
} LinearD3DecoderStep;
|
||||
|
||||
class FProtoSubGhzDLinearDelta3 : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDLinearDelta3() {
|
||||
sensorType = FPS_LINEARDELTA3;
|
||||
te_short = 500;
|
||||
te_long = 2000;
|
||||
te_delta = 150;
|
||||
min_count_bit_for_found = 8;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case LinearD3DecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 70) < te_delta * 24)) {
|
||||
// Found header Linear
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
parser_step = LinearD3DecoderStepSaveDuration;
|
||||
}
|
||||
break;
|
||||
case LinearD3DecoderStepSaveDuration:
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
parser_step = LinearD3DecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = LinearD3DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case LinearD3DecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if (duration >= (te_short * 10)) {
|
||||
parser_step = LinearD3DecoderStepReset;
|
||||
if (DURATION_DIFF(te_last, te_short) < te_delta) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
} else if (
|
||||
DURATION_DIFF(te_last, te_long) < te_delta) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short * 7) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = LinearD3DecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = LinearD3DecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = LinearD3DecoderStepReset;
|
||||
}
|
||||
|
||||
} else {
|
||||
parser_step = LinearD3DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
139
firmware/baseband/fprotos/s-magellan.hpp
Normal file
139
firmware/baseband/fprotos/s-magellan.hpp
Normal file
@ -0,0 +1,139 @@
|
||||
|
||||
#ifndef __FPROTO_MAGELLAN_H__
|
||||
#define __FPROTO_MAGELLAN_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
MagellanDecoderStepReset = 0,
|
||||
MagellanDecoderStepCheckPreambula,
|
||||
MagellanDecoderStepFoundPreambula,
|
||||
MagellanDecoderStepSaveDuration,
|
||||
MagellanDecoderStepCheckDuration,
|
||||
} MagellanDecoderStep;
|
||||
|
||||
class FProtoSubGhzDMagellan : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDMagellan() {
|
||||
sensorType = FPS_MAGELLAN;
|
||||
te_short = 200;
|
||||
te_long = 400;
|
||||
te_delta = 100;
|
||||
min_count_bit_for_found = 32;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case MagellanDecoderStepReset:
|
||||
if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
parser_step = MagellanDecoderStepCheckPreambula;
|
||||
te_last = duration;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case MagellanDecoderStepCheckPreambula:
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
} else {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
// Found header
|
||||
header_count++;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta * 2) &&
|
||||
(header_count > 10)) {
|
||||
parser_step = MagellanDecoderStepFoundPreambula;
|
||||
} else {
|
||||
parser_step = MagellanDecoderStepReset;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MagellanDecoderStepFoundPreambula:
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
} else {
|
||||
if ((DURATION_DIFF(te_last, te_short * 6) < te_delta * 3) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta * 2)) {
|
||||
parser_step = MagellanDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = MagellanDecoderStepReset;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MagellanDecoderStepSaveDuration:
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
parser_step = MagellanDecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = MagellanDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
|
||||
case MagellanDecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = MagellanDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = MagellanDecoderStepSaveDuration;
|
||||
} else if (duration >= (te_long * 3)) {
|
||||
// Found stop bit
|
||||
if ((decode_count_bit == min_count_bit_for_found) &&
|
||||
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;
|
||||
decode_count_bit = 0;
|
||||
parser_step = MagellanDecoderStepReset;
|
||||
} else {
|
||||
parser_step = MagellanDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = MagellanDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool subghz_protocol_magellan_check_crc() {
|
||||
uint8_t data[3] = {
|
||||
(uint8_t)(decode_data >> 24),
|
||||
(uint8_t)(decode_data >> 16),
|
||||
(uint8_t)(decode_data >> 8)};
|
||||
return (decode_data & 0xFF) == subghz_protocol_magellan_crc8(data, sizeof(data));
|
||||
}
|
||||
uint8_t subghz_protocol_magellan_crc8(uint8_t* data, size_t len) {
|
||||
uint8_t crc = 0x00;
|
||||
uint8_t i, j;
|
||||
for (i = 0; i < len; i++) {
|
||||
crc ^= data[i];
|
||||
for (j = 0; j < 8; j++) {
|
||||
if ((crc & 0x80) != 0)
|
||||
crc = (uint8_t)((crc << 1) ^ 0x31);
|
||||
else
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
86
firmware/baseband/fprotos/s-marantec.hpp
Normal file
86
firmware/baseband/fprotos/s-marantec.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
|
||||
#ifndef __FPROTO_MARANTEC_H__
|
||||
#define __FPROTO_MARANTEC_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
MarantecDecoderStepReset = 0,
|
||||
MarantecDecoderFoundHeader,
|
||||
MarantecDecoderStepDecoderData,
|
||||
} MarantecDecoderStep;
|
||||
|
||||
class FProtoSubGhzDMarantec : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDMarantec() {
|
||||
sensorType = FPS_MARANTEC;
|
||||
te_short = 1000;
|
||||
te_long = 2000;
|
||||
te_delta = 200;
|
||||
min_count_bit_for_found = 49;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
ManchesterEvent event = ManchesterEventReset;
|
||||
|
||||
switch (parser_step) {
|
||||
case MarantecDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_long * 5) < te_delta * 8)) {
|
||||
// Found header marantec
|
||||
parser_step = MarantecDecoderStepDecoderData;
|
||||
decode_data = 1;
|
||||
decode_count_bit = 1;
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
|
||||
}
|
||||
break;
|
||||
case MarantecDecoderStepDecoderData:
|
||||
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 >= ((uint32_t)te_long * 2 + te_delta)) {
|
||||
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;
|
||||
decode_count_bit = 1;
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
|
||||
} else {
|
||||
parser_step = MarantecDecoderStepReset;
|
||||
}
|
||||
} 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 = MarantecDecoderStepReset;
|
||||
}
|
||||
}
|
||||
if (event != ManchesterEventReset) {
|
||||
bool bitstate;
|
||||
bool data_ok = FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &bitstate);
|
||||
|
||||
if (data_ok) {
|
||||
decode_data = (decode_data << 1) | bitstate;
|
||||
decode_count_bit++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ManchesterState manchester_saved_state = ManchesterStateMid1;
|
||||
};
|
||||
|
||||
#endif
|
86
firmware/baseband/fprotos/s-mastercode.hpp
Normal file
86
firmware/baseband/fprotos/s-mastercode.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
|
||||
#ifndef __FPROTO_MASTERCODE_H__
|
||||
#define __FPROTO_MASTERCODE_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
MastercodeDecoderStepReset = 0,
|
||||
MastercodeDecoderStepSaveDuration,
|
||||
MastercodeDecoderStepCheckDuration,
|
||||
} MastercodeDecoderStep;
|
||||
|
||||
class FProtoSubGhzDMastercode : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDMastercode() {
|
||||
sensorType = FPS_MASTERCODE;
|
||||
te_short = 1072;
|
||||
te_long = 2145;
|
||||
te_delta = 150;
|
||||
min_count_bit_for_found = 36;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case MastercodeDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 15) < te_delta * 15)) {
|
||||
parser_step = MastercodeDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case MastercodeDecoderStepSaveDuration:
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
parser_step = MastercodeDecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = MastercodeDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
|
||||
case MastercodeDecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta * 8)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = MastercodeDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta * 8) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = MastercodeDecoderStepSaveDuration;
|
||||
} else if (
|
||||
DURATION_DIFF(duration, te_short * 15) < te_delta * 15) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
} else if ((DURATION_DIFF(te_last, te_long) < te_delta * 8)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
} else {
|
||||
parser_step = MastercodeDecoderStepReset;
|
||||
}
|
||||
|
||||
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;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
|
||||
} else {
|
||||
parser_step = MastercodeDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = MastercodeDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
104
firmware/baseband/fprotos/s-megacode.hpp
Normal file
104
firmware/baseband/fprotos/s-megacode.hpp
Normal file
@ -0,0 +1,104 @@
|
||||
|
||||
#ifndef __FPROTO_MEGACODE_H__
|
||||
#define __FPROTO_MEGACODE_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
MegaCodeDecoderStepReset = 0,
|
||||
MegaCodeDecoderStepFoundStartBit,
|
||||
MegaCodeDecoderStepSaveDuration,
|
||||
MegaCodeDecoderStepCheckDuration,
|
||||
} MegaCodeDecoderStep;
|
||||
|
||||
class FProtoSubGhzDMegacode : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDMegacode() {
|
||||
sensorType = FPS_MEGACODE;
|
||||
te_short = 1000;
|
||||
te_long = 1000;
|
||||
te_delta = 200;
|
||||
min_count_bit_for_found = 24;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case MegaCodeDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 13) < te_delta * 17)) { // 10..16ms
|
||||
// Found header MegaCode
|
||||
parser_step = MegaCodeDecoderStepFoundStartBit;
|
||||
}
|
||||
break;
|
||||
case MegaCodeDecoderStepFoundStartBit:
|
||||
if (level && (DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
// Found start bit MegaCode
|
||||
parser_step = MegaCodeDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
last_bit = 1;
|
||||
|
||||
} else {
|
||||
parser_step = MegaCodeDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case MegaCodeDecoderStepSaveDuration:
|
||||
if (!level) { // save interval
|
||||
if (duration >= (te_short * 10)) {
|
||||
parser_step = MegaCodeDecoderStepReset;
|
||||
if (decode_count_bit ==
|
||||
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;
|
||||
}
|
||||
|
||||
if (!last_bit) {
|
||||
te_last = duration - te_short * 3;
|
||||
} else {
|
||||
te_last = duration;
|
||||
}
|
||||
parser_step = MegaCodeDecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = MegaCodeDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case MegaCodeDecoderStepCheckDuration:
|
||||
if (level) {
|
||||
if ((DURATION_DIFF(te_last, te_short * 5) < te_delta * 5) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
last_bit = 1;
|
||||
parser_step = MegaCodeDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_short * 2) < te_delta * 2) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
last_bit = 0;
|
||||
parser_step = MegaCodeDecoderStepSaveDuration;
|
||||
} else
|
||||
parser_step = MegaCodeDecoderStepReset;
|
||||
} else {
|
||||
parser_step = MegaCodeDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t last_bit = false;
|
||||
};
|
||||
|
||||
#endif
|
108
firmware/baseband/fprotos/s-nero_sketch.hpp
Normal file
108
firmware/baseband/fprotos/s-nero_sketch.hpp
Normal file
@ -0,0 +1,108 @@
|
||||
|
||||
#ifndef __FPROTO_NEROSKETCH_H__
|
||||
#define __FPROTO_NEROSKETCH_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
NeroSketchDecoderStepReset = 0,
|
||||
NeroSketchDecoderStepCheckPreambula,
|
||||
NeroSketchDecoderStepSaveDuration,
|
||||
NeroSketchDecoderStepCheckDuration,
|
||||
} NeroSketchDecoderStep;
|
||||
|
||||
class FProtoSubGhzDNeroSketch : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDNeroSketch() {
|
||||
sensorType = FPS_NERO_SKETCH;
|
||||
te_short = 330;
|
||||
te_long = 660;
|
||||
te_delta = 150;
|
||||
min_count_bit_for_found = 40;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case NeroSketchDecoderStepReset:
|
||||
if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
parser_step = NeroSketchDecoderStepCheckPreambula;
|
||||
te_last = duration;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
case NeroSketchDecoderStepCheckPreambula:
|
||||
if (level) {
|
||||
if ((DURATION_DIFF(duration, te_short) < te_delta) ||
|
||||
(DURATION_DIFF(duration, te_short * 4) < te_delta)) {
|
||||
te_last = duration;
|
||||
} else {
|
||||
parser_step = NeroSketchDecoderStepReset;
|
||||
}
|
||||
} else if (
|
||||
DURATION_DIFF(duration, te_short) < te_delta) {
|
||||
if (DURATION_DIFF(te_last, te_short) < te_delta) {
|
||||
// Found header
|
||||
header_count++;
|
||||
break;
|
||||
} else if (
|
||||
DURATION_DIFF(te_last, te_short * 4) < te_delta) {
|
||||
// Found start bit
|
||||
if (header_count > 40) {
|
||||
parser_step = NeroSketchDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = NeroSketchDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = NeroSketchDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = NeroSketchDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case NeroSketchDecoderStepSaveDuration:
|
||||
if (level) {
|
||||
if (duration >= (te_short * 2 + te_delta * 2)) {
|
||||
// Found stop bit
|
||||
parser_step = NeroSketchDecoderStepReset;
|
||||
if (decode_count_bit == min_count_bit_for_found) {
|
||||
data = decode_data;
|
||||
data_count_bit = decode_count_bit;
|
||||
if (callback) callback(this);
|
||||
}
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
break;
|
||||
} else {
|
||||
te_last = duration;
|
||||
parser_step = NeroSketchDecoderStepCheckDuration;
|
||||
}
|
||||
|
||||
} else {
|
||||
parser_step = NeroSketchDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case NeroSketchDecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = NeroSketchDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = NeroSketchDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = NeroSketchDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = NeroSketchDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
115
firmware/baseband/fprotos/s-neroradio.hpp
Normal file
115
firmware/baseband/fprotos/s-neroradio.hpp
Normal file
@ -0,0 +1,115 @@
|
||||
|
||||
#ifndef __FPROTO_NERORADIO_H__
|
||||
#define __FPROTO_NERORADIO_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
NeroRadioDecoderStepReset = 0,
|
||||
NeroRadioDecoderStepCheckPreambula,
|
||||
NeroRadioDecoderStepSaveDuration,
|
||||
NeroRadioDecoderStepCheckDuration,
|
||||
} NeroRadioDecoderStep;
|
||||
|
||||
class FProtoSubGhzDNeroRadio : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDNeroRadio() {
|
||||
sensorType = FPS_NERORADIO;
|
||||
te_short = 200;
|
||||
te_long = 400;
|
||||
te_delta = 80;
|
||||
min_count_bit_for_found = 56;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case NeroRadioDecoderStepReset:
|
||||
if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
parser_step = NeroRadioDecoderStepCheckPreambula;
|
||||
te_last = duration;
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
case NeroRadioDecoderStepCheckPreambula:
|
||||
if (level) {
|
||||
if ((DURATION_DIFF(duration, te_short) < te_delta) ||
|
||||
(DURATION_DIFF(duration, te_short * 4) < te_delta)) {
|
||||
te_last = duration;
|
||||
} else {
|
||||
parser_step = NeroRadioDecoderStepReset;
|
||||
}
|
||||
} else if (
|
||||
DURATION_DIFF(duration, te_short) < te_delta) {
|
||||
if (DURATION_DIFF(te_last, te_short) < te_delta) {
|
||||
// Found header
|
||||
header_count++;
|
||||
break;
|
||||
} else if (
|
||||
DURATION_DIFF(te_last, te_short * 4) < te_delta) {
|
||||
// Found start bit
|
||||
if (header_count > 40) {
|
||||
parser_step = NeroRadioDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = NeroRadioDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = NeroRadioDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = NeroRadioDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case NeroRadioDecoderStepSaveDuration:
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
parser_step = NeroRadioDecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = NeroRadioDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case NeroRadioDecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if (duration >= ((uint32_t)1250)) {
|
||||
// Found stop bit
|
||||
if (DURATION_DIFF(te_last, te_short) < te_delta) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
} else if (
|
||||
DURATION_DIFF(te_last, te_long) < te_delta) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
}
|
||||
parser_step = NeroRadioDecoderStepReset;
|
||||
if ((decode_count_bit == min_count_bit_for_found) ||
|
||||
(decode_count_bit == min_count_bit_for_found + 1)) {
|
||||
data = decode_data;
|
||||
data_count_bit = decode_count_bit;
|
||||
|
||||
if (callback) callback(this);
|
||||
}
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
parser_step = NeroRadioDecoderStepReset; //-V1048
|
||||
break;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = NeroRadioDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = NeroRadioDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = NeroRadioDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = NeroRadioDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
86
firmware/baseband/fprotos/s-nice_flo.hpp
Normal file
86
firmware/baseband/fprotos/s-nice_flo.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
|
||||
#ifndef __FPROTO_NICE_FLO_H__
|
||||
#define __FPROTO_NICE_FLO_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
NiceFloDecoderStepReset = 0,
|
||||
NiceFloDecoderStepFoundStartBit,
|
||||
NiceFloDecoderStepSaveDuration,
|
||||
NiceFloDecoderStepCheckDuration,
|
||||
} NiceFloDecoderStep;
|
||||
|
||||
class FProtoSubGhzDNiceflo : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDNiceflo() {
|
||||
sensorType = FPS_NICEFLO;
|
||||
te_short = 700;
|
||||
te_long = 1400;
|
||||
te_delta = 200;
|
||||
min_count_bit_for_found = 12;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case NiceFloDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 36) < te_delta * 36)) {
|
||||
// Found header Nice Flo
|
||||
parser_step = NiceFloDecoderStepFoundStartBit;
|
||||
}
|
||||
break;
|
||||
case NiceFloDecoderStepFoundStartBit:
|
||||
if (!level) {
|
||||
break;
|
||||
} else if (
|
||||
DURATION_DIFF(duration, te_short) < te_delta) {
|
||||
// Found start bit Nice Flo
|
||||
parser_step = NiceFloDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = NiceFloDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case NiceFloDecoderStepSaveDuration:
|
||||
if (!level) { // save interval
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
te_last = duration;
|
||||
parser_step = NiceFloDecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = NiceFloDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case NiceFloDecoderStepCheckDuration:
|
||||
if (level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = NiceFloDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = NiceFloDecoderStepSaveDuration;
|
||||
} else
|
||||
parser_step = NiceFloDecoderStepReset;
|
||||
} else {
|
||||
parser_step = NiceFloDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
100
firmware/baseband/fprotos/s-nice_flors.hpp
Normal file
100
firmware/baseband/fprotos/s-nice_flors.hpp
Normal file
@ -0,0 +1,100 @@
|
||||
|
||||
#ifndef __FPROTO_NICE_FLORS_H__
|
||||
#define __FPROTO_NICE_FLORS_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
#define NICE_ONE_COUNT_BIT 72
|
||||
|
||||
typedef enum : uint8_t {
|
||||
NiceFlorSDecoderStepReset = 0,
|
||||
NiceFlorSDecoderStepCheckHeader,
|
||||
NiceFlorSDecoderStepFoundHeader,
|
||||
NiceFlorSDecoderStepSaveDuration,
|
||||
NiceFlorSDecoderStepCheckDuration,
|
||||
} NiceFlorSDecoderStep;
|
||||
|
||||
class FProtoSubGhzDNiceflors : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDNiceflors() {
|
||||
sensorType = FPS_NICEFLORS;
|
||||
te_short = 500;
|
||||
te_long = 1000;
|
||||
te_delta = 300;
|
||||
min_count_bit_for_found = 52;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case NiceFlorSDecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 38) < te_delta * 38)) {
|
||||
// Found start header Nice Flor-S
|
||||
parser_step = NiceFlorSDecoderStepCheckHeader;
|
||||
}
|
||||
break;
|
||||
case NiceFlorSDecoderStepCheckHeader:
|
||||
if ((level) && (DURATION_DIFF(duration, te_short * 3) < te_delta * 3)) {
|
||||
// Found next header Nice Flor-S
|
||||
parser_step = NiceFlorSDecoderStepFoundHeader;
|
||||
} else {
|
||||
parser_step = NiceFlorSDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case NiceFlorSDecoderStepFoundHeader:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 3) < te_delta * 3)) {
|
||||
// Found header Nice Flor-S
|
||||
parser_step = NiceFlorSDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = NiceFlorSDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case NiceFlorSDecoderStepSaveDuration:
|
||||
if (level) {
|
||||
if (DURATION_DIFF(duration, te_short * 3) < te_delta) {
|
||||
// Found STOP bit
|
||||
parser_step = NiceFlorSDecoderStepReset;
|
||||
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;
|
||||
} else {
|
||||
// save interval
|
||||
te_last = duration;
|
||||
parser_step = NiceFlorSDecoderStepCheckDuration;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NiceFlorSDecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = NiceFlorSDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = NiceFlorSDecoderStepSaveDuration;
|
||||
} else
|
||||
parser_step = NiceFlorSDecoderStepReset;
|
||||
} else {
|
||||
parser_step = NiceFlorSDecoderStepReset;
|
||||
}
|
||||
if (decode_count_bit == min_count_bit_for_found) {
|
||||
data = decode_data;
|
||||
decode_data = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
89
firmware/baseband/fprotos/s-phoenix_v2.hpp
Normal file
89
firmware/baseband/fprotos/s-phoenix_v2.hpp
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
#ifndef __FPROTO_PHOENIX_V2_H__
|
||||
#define __FPROTO_PHOENIX_V2_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
Phoenix_V2DecoderStepReset = 0,
|
||||
Phoenix_V2DecoderStepFoundStartBit,
|
||||
Phoenix_V2DecoderStepSaveDuration,
|
||||
Phoenix_V2DecoderStepCheckDuration,
|
||||
} Phoenix_V2DecoderStep;
|
||||
|
||||
class FProtoSubGhzDPhoenixV2 : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDPhoenixV2() {
|
||||
sensorType = FPS_PHOENIXV2;
|
||||
te_short = 427;
|
||||
te_long = 853;
|
||||
te_delta = 100;
|
||||
min_count_bit_for_found = 52;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case Phoenix_V2DecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 60) < te_delta * 30)) {
|
||||
// Found Preambula
|
||||
parser_step = Phoenix_V2DecoderStepFoundStartBit;
|
||||
}
|
||||
break;
|
||||
case Phoenix_V2DecoderStepFoundStartBit:
|
||||
if (level && ((DURATION_DIFF(duration, (te_short * 6)) < te_delta * 4))) {
|
||||
// Found start bit
|
||||
parser_step = Phoenix_V2DecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
parser_step = Phoenix_V2DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case Phoenix_V2DecoderStepSaveDuration:
|
||||
if (!level) {
|
||||
if (duration >= ((uint32_t)te_short * 10 + te_delta)) {
|
||||
parser_step = Phoenix_V2DecoderStepFoundStartBit;
|
||||
if (decode_count_bit ==
|
||||
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;
|
||||
decode_count_bit = 0;
|
||||
break;
|
||||
} else {
|
||||
te_last = duration;
|
||||
parser_step = Phoenix_V2DecoderStepCheckDuration;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Phoenix_V2DecoderStepCheckDuration:
|
||||
if (level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta * 3)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = Phoenix_V2DecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta * 3) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = Phoenix_V2DecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = Phoenix_V2DecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = Phoenix_V2DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
84
firmware/baseband/fprotos/s-power_smart.hpp
Normal file
84
firmware/baseband/fprotos/s-power_smart.hpp
Normal file
@ -0,0 +1,84 @@
|
||||
|
||||
#ifndef __FPROTO_POWER_SMART_H__
|
||||
#define __FPROTO_POWER_SMART_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
#define POWER_SMART_PACKET_HEADER 0xFD000000AA000000
|
||||
#define POWER_SMART_PACKET_HEADER_MASK 0xFF000000FF000000
|
||||
|
||||
typedef enum : uint8_t {
|
||||
PowerSmartDecoderStepReset = 0,
|
||||
PowerSmartDecoderFoundHeader,
|
||||
PowerSmartDecoderStepDecoderData,
|
||||
} PowerSmartDecoderStep;
|
||||
|
||||
class FProtoSubGhzDPowerSmart : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDPowerSmart() {
|
||||
sensorType = FPS_POWERSMART;
|
||||
te_short = 225;
|
||||
te_long = 450;
|
||||
te_delta = 100;
|
||||
min_count_bit_for_found = 64;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
ManchesterEvent event = ManchesterEventReset;
|
||||
if (!level) {
|
||||
if (DURATION_DIFF(duration, te_short) < te_delta) {
|
||||
event = ManchesterEventShortLow;
|
||||
} else if (
|
||||
DURATION_DIFF(duration, te_long) < te_delta * 2) {
|
||||
event = ManchesterEventLongLow;
|
||||
}
|
||||
} else {
|
||||
if (DURATION_DIFF(duration, te_short) < te_delta) {
|
||||
event = ManchesterEventShortHigh;
|
||||
} else if (
|
||||
DURATION_DIFF(duration, te_long) < te_delta * 2) {
|
||||
event = ManchesterEventLongHigh;
|
||||
}
|
||||
}
|
||||
if (event != ManchesterEventReset) {
|
||||
bool bit_val;
|
||||
bool data_ok = FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &bit_val);
|
||||
|
||||
if (data_ok) {
|
||||
decode_data = (decode_data << 1) | !bit_val;
|
||||
}
|
||||
if ((decode_data & POWER_SMART_PACKET_HEADER_MASK) == POWER_SMART_PACKET_HEADER) {
|
||||
if (subghz_protocol_power_smart_chek_valid(decode_data)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ManchesterState manchester_saved_state = ManchesterStateMid1;
|
||||
|
||||
bool subghz_protocol_power_smart_chek_valid(uint64_t packet) {
|
||||
uint32_t data_1 = (uint32_t)((packet >> 40) & 0xFFFF);
|
||||
uint32_t data_2 = (uint32_t)((~packet >> 8) & 0xFFFF);
|
||||
uint8_t data_3 = (uint8_t)(packet >> 32) & 0xFF;
|
||||
uint8_t data_4 = (uint8_t)(((~packet) & 0xFF) - 1);
|
||||
return (data_1 == data_2) && (data_3 == data_4);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
77
firmware/baseband/fprotos/s-princeton.hpp
Normal file
77
firmware/baseband/fprotos/s-princeton.hpp
Normal file
@ -0,0 +1,77 @@
|
||||
|
||||
#ifndef __FPROTO_PRINCETON_H__
|
||||
#define __FPROTO_PRINCETON_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum : uint8_t {
|
||||
PrincetonDecoderStepReset = 0,
|
||||
PrincetonDecoderStepSaveDuration,
|
||||
PrincetonDecoderStepCheckDuration,
|
||||
} PrincetonDecoderStep;
|
||||
|
||||
class FProtoSubGhzDPrinceton : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDPrinceton() {
|
||||
sensorType = FPS_PRINCETON;
|
||||
te_short = 390;
|
||||
te_long = 1170;
|
||||
te_delta = 300;
|
||||
min_count_bit_for_found = 24;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case PrincetonDecoderStepSaveDuration:
|
||||
// save duration
|
||||
if (level) {
|
||||
te_last = 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) {
|
||||
data = decode_data;
|
||||
data_count_bit = decode_count_bit;
|
||||
// controller
|
||||
serial = data >> 4;
|
||||
btn = data & 0xF;
|
||||
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 = 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
134
firmware/baseband/fprotos/s-secplus_v1.hpp
Normal file
134
firmware/baseband/fprotos/s-secplus_v1.hpp
Normal file
@ -0,0 +1,134 @@
|
||||
|
||||
#ifndef __FPROTO_SECPLUSV1_H__
|
||||
#define __FPROTO_SECPLUSV1_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
#include <string.h>
|
||||
|
||||
#define SECPLUS_V1_BIT_ERR -1 // 0b0000
|
||||
#define SECPLUS_V1_BIT_0 0 // 0b0001
|
||||
#define SECPLUS_V1_BIT_1 1 // 0b0011
|
||||
#define SECPLUS_V1_BIT_2 2 // 0b0111
|
||||
|
||||
#define SECPLUS_V1_PACKET_1_HEADER 0x00
|
||||
#define SECPLUS_V1_PACKET_2_HEADER 0x02
|
||||
#define SECPLUS_V1_PACKET_1_INDEX_BASE 0
|
||||
#define SECPLUS_V1_PACKET_2_INDEX_BASE 21
|
||||
#define SECPLUS_V1_PACKET_1_ACCEPTED (1 << 0)
|
||||
#define SECPLUS_V1_PACKET_2_ACCEPTED (1 << 1)
|
||||
|
||||
typedef enum : uint8_t {
|
||||
SecPlus_v1DecoderStepReset = 0,
|
||||
SecPlus_v1DecoderStepSearchStartBit,
|
||||
SecPlus_v1DecoderStepSaveDuration,
|
||||
SecPlus_v1DecoderStepDecoderData,
|
||||
} SecPlus_v1DecoderStep;
|
||||
|
||||
class FProtoSubGhzDSecPlusV1 : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDSecPlusV1() {
|
||||
sensorType = FPS_SECPLUSV1;
|
||||
te_short = 500;
|
||||
te_long = 1500;
|
||||
te_delta = 100;
|
||||
min_count_bit_for_found = 21;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case SecPlus_v1DecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 120) < te_delta * 120)) {
|
||||
// Found header Security+ 1.0
|
||||
parser_step = SecPlus_v1DecoderStepSearchStartBit;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
packet_accepted = 0;
|
||||
memset(data_array, 0, sizeof(data_array));
|
||||
}
|
||||
break;
|
||||
case SecPlus_v1DecoderStepSearchStartBit:
|
||||
if (level) {
|
||||
if (DURATION_DIFF(duration, te_short) < te_delta) {
|
||||
base_packet_index = SECPLUS_V1_PACKET_1_INDEX_BASE;
|
||||
data_array[decode_count_bit + base_packet_index] = SECPLUS_V1_BIT_0;
|
||||
decode_count_bit++;
|
||||
parser_step = SecPlus_v1DecoderStepSaveDuration;
|
||||
} else if (
|
||||
DURATION_DIFF(duration, te_long) < te_delta) {
|
||||
base_packet_index = SECPLUS_V1_PACKET_2_INDEX_BASE;
|
||||
data_array[decode_count_bit + base_packet_index] = SECPLUS_V1_BIT_2;
|
||||
decode_count_bit++;
|
||||
parser_step = SecPlus_v1DecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = SecPlus_v1DecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = SecPlus_v1DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case SecPlus_v1DecoderStepSaveDuration:
|
||||
if (!level) { // save interval
|
||||
if (DURATION_DIFF(duration, te_short * 120) < te_delta * 120) {
|
||||
if (decode_count_bit == min_count_bit_for_found) {
|
||||
if (base_packet_index == SECPLUS_V1_PACKET_1_INDEX_BASE)
|
||||
packet_accepted |= SECPLUS_V1_PACKET_1_ACCEPTED;
|
||||
if (base_packet_index == SECPLUS_V1_PACKET_2_INDEX_BASE)
|
||||
packet_accepted |= SECPLUS_V1_PACKET_2_ACCEPTED;
|
||||
|
||||
if (packet_accepted == (SECPLUS_V1_PACKET_1_ACCEPTED | SECPLUS_V1_PACKET_2_ACCEPTED)) {
|
||||
// subghz_protocol_secplus_v1_decode(); // disabled doe to lack of flash
|
||||
// controller
|
||||
// uint32_t fixed = (data >> 32) & 0xFFFFFFFF;
|
||||
// cnt = data & 0xFFFFFFFF;
|
||||
// btn = fixed % 3;
|
||||
if (callback) callback(this);
|
||||
parser_step = SecPlus_v1DecoderStepReset;
|
||||
}
|
||||
}
|
||||
parser_step = SecPlus_v1DecoderStepSearchStartBit;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
te_last = duration;
|
||||
parser_step = SecPlus_v1DecoderStepDecoderData;
|
||||
}
|
||||
} else {
|
||||
parser_step = SecPlus_v1DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case SecPlus_v1DecoderStepDecoderData:
|
||||
if (level && (decode_count_bit <= min_count_bit_for_found)) {
|
||||
if ((DURATION_DIFF(te_last, te_short * 3) < te_delta * 3) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
data_array[decode_count_bit + base_packet_index] = SECPLUS_V1_BIT_0;
|
||||
decode_count_bit++;
|
||||
parser_step = SecPlus_v1DecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_short * 2) < te_delta * 2) &&
|
||||
(DURATION_DIFF(duration, te_short * 2) < te_delta * 2)) {
|
||||
data_array[decode_count_bit + base_packet_index] = SECPLUS_V1_BIT_1;
|
||||
decode_count_bit++;
|
||||
parser_step = SecPlus_v1DecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short * 3) < te_delta * 3)) {
|
||||
data_array[decode_count_bit + base_packet_index] = SECPLUS_V1_BIT_2;
|
||||
decode_count_bit++;
|
||||
parser_step = SecPlus_v1DecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = SecPlus_v1DecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = SecPlus_v1DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t packet_accepted = 0;
|
||||
uint8_t base_packet_index = 0;
|
||||
uint8_t data_array[44];
|
||||
};
|
||||
|
||||
#endif
|
110
firmware/baseband/fprotos/s-secplus_v2.hpp
Normal file
110
firmware/baseband/fprotos/s-secplus_v2.hpp
Normal file
@ -0,0 +1,110 @@
|
||||
|
||||
#ifndef __FPROTO_SECPLUSV2_H__
|
||||
#define __FPROTO_SECPLUSV2_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
#define SECPLUS_V2_HEADER 0x3C0000000000
|
||||
#define SECPLUS_V2_HEADER_MASK 0xFFFF3C0000000000
|
||||
#define SECPLUS_V2_PACKET_1 0x000000000000
|
||||
#define SECPLUS_V2_PACKET_2 0x010000000000
|
||||
#define SECPLUS_V2_PACKET_MASK 0x30000000000
|
||||
|
||||
typedef enum : uint8_t {
|
||||
SecPlus_v2DecoderStepReset = 0,
|
||||
SecPlus_v2DecoderStepDecoderData,
|
||||
} SecPlus_v2DecoderStep;
|
||||
|
||||
class FProtoSubGhzDSecPlusV2 : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDSecPlusV2() {
|
||||
sensorType = FPS_SECPLUSV2;
|
||||
te_short = 250;
|
||||
te_long = 500;
|
||||
te_delta = 110;
|
||||
min_count_bit_for_found = 62;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
ManchesterEvent event = ManchesterEventReset;
|
||||
switch (parser_step) {
|
||||
case SecPlus_v2DecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_long * 130) < te_delta * 100)) {
|
||||
// Found header Security+ 2.0
|
||||
parser_step = SecPlus_v2DecoderStepDecoderData;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
secplus_packet_1 = 0;
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongHigh, &manchester_saved_state, NULL);
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventShortLow, &manchester_saved_state, NULL);
|
||||
}
|
||||
break;
|
||||
case SecPlus_v2DecoderStepDecoderData:
|
||||
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 * 2UL + te_delta)) {
|
||||
if (decode_count_bit == min_count_bit_for_found) {
|
||||
data = decode_data;
|
||||
data_count_bit = decode_count_bit;
|
||||
if (subghz_protocol_secplus_v2_check_packet()) {
|
||||
// controller too big
|
||||
if (callback) callback(this);
|
||||
parser_step = SecPlus_v2DecoderStepReset;
|
||||
}
|
||||
}
|
||||
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);
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventShortLow, &manchester_saved_state, NULL);
|
||||
} else {
|
||||
parser_step = SecPlus_v2DecoderStepReset;
|
||||
}
|
||||
} 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 = SecPlus_v2DecoderStepReset;
|
||||
}
|
||||
}
|
||||
if (event != ManchesterEventReset) {
|
||||
bool bit;
|
||||
bool data_ok = FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &bit);
|
||||
|
||||
if (data_ok) {
|
||||
decode_data = (decode_data << 1) | bit;
|
||||
decode_count_bit++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
uint64_t secplus_packet_1 = 0;
|
||||
ManchesterState manchester_saved_state = ManchesterStateMid0;
|
||||
|
||||
bool subghz_protocol_secplus_v2_check_packet() {
|
||||
if ((decode_data & SECPLUS_V2_HEADER_MASK) == SECPLUS_V2_HEADER) {
|
||||
if ((decode_data & SECPLUS_V2_PACKET_MASK) == SECPLUS_V2_PACKET_1) {
|
||||
secplus_packet_1 = decode_data;
|
||||
} else if (
|
||||
((decode_data & SECPLUS_V2_PACKET_MASK) == SECPLUS_V2_PACKET_2) &&
|
||||
(secplus_packet_1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
74
firmware/baseband/fprotos/s-smc5326.hpp
Normal file
74
firmware/baseband/fprotos/s-smc5326.hpp
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
#ifndef __FPROTO_SMC5326_H__
|
||||
#define __FPROTO_SMC5326_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum {
|
||||
SMC5326DecoderStepReset = 0,
|
||||
SMC5326DecoderStepSaveDuration,
|
||||
SMC5326DecoderStepCheckDuration,
|
||||
} SMC5326DecoderStep;
|
||||
|
||||
class FProtoSubGhzDSmc5326 : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDSmc5326() {
|
||||
sensorType = FPS_SECPLUSV2;
|
||||
te_short = 300;
|
||||
te_long = 900;
|
||||
te_delta = 200;
|
||||
min_count_bit_for_found = 25;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case SMC5326DecoderStepReset:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 24) < te_delta * 12)) {
|
||||
// Found Preambula
|
||||
parser_step = SMC5326DecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
}
|
||||
break;
|
||||
case SMC5326DecoderStepSaveDuration:
|
||||
// save duration
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
parser_step = SMC5326DecoderStepCheckDuration;
|
||||
}
|
||||
break;
|
||||
case SMC5326DecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if (duration >= ((uint32_t)te_long * 2)) {
|
||||
parser_step = SMC5326DecoderStepSaveDuration;
|
||||
if (decode_count_bit == min_count_bit_for_found) {
|
||||
data = decode_data;
|
||||
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 = SMC5326DecoderStepSaveDuration;
|
||||
} 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 = SMC5326DecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = SMC5326DecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = SMC5326DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
106
firmware/baseband/fprotos/s-star_line.hpp
Normal file
106
firmware/baseband/fprotos/s-star_line.hpp
Normal file
@ -0,0 +1,106 @@
|
||||
|
||||
#ifndef __FPROTO_STARLINE_H__
|
||||
#define __FPROTO_STARLINE_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum {
|
||||
StarLineDecoderStepReset = 0,
|
||||
StarLineDecoderStepCheckPreambula,
|
||||
StarLineDecoderStepSaveDuration,
|
||||
StarLineDecoderStepCheckDuration,
|
||||
} StarLineDecoderStep;
|
||||
|
||||
class FProtoSubGhzDStarLine : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDStarLine() {
|
||||
sensorType = FPS_STARLINE;
|
||||
te_short = 250;
|
||||
te_long = 500;
|
||||
te_delta = 120;
|
||||
min_count_bit_for_found = 64;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case StarLineDecoderStepReset:
|
||||
if (level) {
|
||||
if (DURATION_DIFF(duration, te_long * 2) < te_delta * 2) {
|
||||
parser_step = StarLineDecoderStepCheckPreambula;
|
||||
header_count++;
|
||||
} else if (header_count > 4) {
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
te_last = duration;
|
||||
parser_step = StarLineDecoderStepCheckDuration;
|
||||
}
|
||||
} else {
|
||||
header_count = 0;
|
||||
}
|
||||
break;
|
||||
case StarLineDecoderStepCheckPreambula:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_long * 2) < te_delta * 2)) {
|
||||
// Found Preambula
|
||||
parser_step = StarLineDecoderStepReset;
|
||||
} else {
|
||||
header_count = 0;
|
||||
parser_step = StarLineDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case StarLineDecoderStepSaveDuration:
|
||||
if (level) {
|
||||
if (duration >= (te_long + te_delta)) {
|
||||
parser_step = StarLineDecoderStepReset;
|
||||
if ((decode_count_bit >= min_count_bit_for_found) &&
|
||||
(decode_count_bit <= min_count_bit_for_found + 2)) {
|
||||
if (data != decode_data) {
|
||||
data = decode_data;
|
||||
data_count_bit = min_count_bit_for_found;
|
||||
if (callback) callback(this);
|
||||
}
|
||||
}
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
header_count = 0;
|
||||
break;
|
||||
} else {
|
||||
te_last = duration;
|
||||
parser_step = StarLineDecoderStepCheckDuration;
|
||||
}
|
||||
|
||||
} else {
|
||||
parser_step = StarLineDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case StarLineDecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
if (decode_count_bit < min_count_bit_for_found) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
} else {
|
||||
decode_count_bit++;
|
||||
}
|
||||
parser_step = StarLineDecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_long) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta)) {
|
||||
if (decode_count_bit <
|
||||
min_count_bit_for_found) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
} else {
|
||||
decode_count_bit++;
|
||||
}
|
||||
parser_step = StarLineDecoderStepSaveDuration;
|
||||
} else {
|
||||
parser_step = StarLineDecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
parser_step = StarLineDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
99
firmware/baseband/fprotos/s-x10.hpp
Normal file
99
firmware/baseband/fprotos/s-x10.hpp
Normal file
@ -0,0 +1,99 @@
|
||||
|
||||
#ifndef __FPROTO_X10_H__
|
||||
#define __FPROTO_X10_H__
|
||||
|
||||
#include "subghzdbase.hpp"
|
||||
|
||||
typedef enum {
|
||||
X10DecoderStepReset = 0,
|
||||
X10DecoderStepFoundPreambula,
|
||||
X10DecoderStepSaveDuration,
|
||||
X10DecoderStepCheckDuration,
|
||||
} X10DecoderStep;
|
||||
|
||||
class FProtoSubGhzDX10 : public FProtoSubGhzDBase {
|
||||
public:
|
||||
FProtoSubGhzDX10() {
|
||||
sensorType = FPS_X10;
|
||||
te_short = 600;
|
||||
te_long = 1800;
|
||||
te_delta = 100;
|
||||
min_count_bit_for_found = 32;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case X10DecoderStepReset:
|
||||
if ((level) && (DURATION_DIFF(duration, te_short * 16) < te_delta * 7)) {
|
||||
parser_step = X10DecoderStepFoundPreambula;
|
||||
}
|
||||
break;
|
||||
case X10DecoderStepFoundPreambula:
|
||||
if ((!level) && (DURATION_DIFF(duration, te_short * 8) < te_delta * 5)) {
|
||||
parser_step = X10DecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
parser_step = X10DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case X10DecoderStepSaveDuration:
|
||||
if (level) {
|
||||
if (DURATION_DIFF(duration, te_short) < te_delta) {
|
||||
if (decode_count_bit == min_count_bit_for_found) {
|
||||
parser_step = X10DecoderStepReset;
|
||||
if (decode_count_bit >= min_count_bit_for_found &&
|
||||
((((decode_data >> 24) ^ (decode_data >> 16)) & 0xFF) == 0xFF) &&
|
||||
((((decode_data >> 8) ^ (decode_data)) & 0xFF) == 0xFF)) {
|
||||
data = decode_data;
|
||||
data_count_bit = decode_count_bit;
|
||||
|
||||
if (callback) callback(this);
|
||||
}
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
parser_step = X10DecoderStepReset;
|
||||
} else {
|
||||
te_last = duration;
|
||||
parser_step = X10DecoderStepCheckDuration;
|
||||
}
|
||||
} else {
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
parser_step = X10DecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
parser_step = X10DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case X10DecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_short) < te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = X10DecoderStepSaveDuration;
|
||||
} else if (
|
||||
(DURATION_DIFF(te_last, te_short) < te_delta) &&
|
||||
(DURATION_DIFF(duration, te_long) < te_delta * 2)) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = X10DecoderStepSaveDuration;
|
||||
} else {
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
parser_step = X10DecoderStepReset;
|
||||
}
|
||||
} else {
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
parser_step = X10DecoderStepReset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
56
firmware/baseband/fprotos/subghzdbase.hpp
Normal file
56
firmware/baseband/fprotos/subghzdbase.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
Base class for all weather protocols.
|
||||
This and most of the weather protocols uses code from Flipper XTreme codebase ( https://github.com/Flipper-XFW/Xtreme-Firmware/tree/dev/lib/subghz ). Thanks for their work!
|
||||
For comments in a protocol implementation check w-nexus-th.hpp
|
||||
*/
|
||||
|
||||
#ifndef __FPROTO_SBASE_H__
|
||||
#define __FPROTO_SBASE_H__
|
||||
|
||||
#include "fprotogeneral.hpp"
|
||||
#include "subghztypes.hpp"
|
||||
|
||||
#include <string>
|
||||
// default values to indicate 'no value'
|
||||
|
||||
class FProtoSubGhzDBase;
|
||||
typedef void (*SubGhzDProtocolDecoderBaseRxCallback)(FProtoSubGhzDBase* instance);
|
||||
|
||||
class FProtoSubGhzDBase {
|
||||
public:
|
||||
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.
|
||||
|
||||
// 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:
|
||||
// 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) {
|
||||
decode_data = decode_data << 1 | bit;
|
||||
decode_count_bit++;
|
||||
}
|
||||
|
||||
// inner logic stuff, also for flipper compatibility.
|
||||
uint32_t te_short = UINT32_MAX;
|
||||
uint32_t te_long = UINT32_MAX;
|
||||
uint32_t te_delta = UINT32_MAX;
|
||||
uint32_t min_count_bit_for_found = UINT32_MAX;
|
||||
|
||||
SubGhzDProtocolDecoderBaseRxCallback callback = NULL;
|
||||
uint16_t header_count = 0;
|
||||
uint8_t parser_step = 0;
|
||||
uint32_t te_last = 0;
|
||||
uint32_t decode_count_bit = 0;
|
||||
uint64_t decode_data = 0;
|
||||
//
|
||||
};
|
||||
|
||||
#endif
|
132
firmware/baseband/fprotos/subghzdprotos.hpp
Normal file
132
firmware/baseband/fprotos/subghzdprotos.hpp
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
This is the protocol list handler. It holds an instance of all known protocols.
|
||||
So include here the .hpp, and add a new element to the protos vector in the constructor. That's all you need to do here if you wanna add a new proto.
|
||||
@htotoo
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include "fprotolistgeneral.hpp"
|
||||
#include "subghzdbase.hpp"
|
||||
#include "s-princeton.hpp"
|
||||
#include "s-bett.hpp"
|
||||
#include "s-came.hpp"
|
||||
#include "s-came_atomo.hpp"
|
||||
#include "s-came_twee.hpp"
|
||||
#include "s-chambcode.hpp"
|
||||
#include "s-clemsa.hpp"
|
||||
#include "s-doitrand.hpp"
|
||||
#include "s-dooya.hpp"
|
||||
#include "s-faac.hpp"
|
||||
#include "s-gate_tx.hpp"
|
||||
#include "s-holtek.hpp"
|
||||
#include "s-holtek_ht12x.hpp"
|
||||
#include "s-honeywell.hpp"
|
||||
#include "s-honeywellwdb.hpp"
|
||||
#include "s-hormann.hpp"
|
||||
#include "s-ido.hpp"
|
||||
#include "s-intertechnov3.hpp"
|
||||
#include "s-keeloq.hpp"
|
||||
#include "s-kinggates_stylo_4k.hpp"
|
||||
#include "s-linear.hpp"
|
||||
#include "s-linear_delta3.hpp"
|
||||
#include "s-magellan.hpp"
|
||||
#include "s-marantec.hpp"
|
||||
#include "s-mastercode.hpp"
|
||||
#include "s-megacode.hpp"
|
||||
#include "s-neroradio.hpp"
|
||||
#include "s-nero_sketch.hpp"
|
||||
#include "s-nice_flo.hpp"
|
||||
#include "s-nice_flors.hpp"
|
||||
#include "s-phoenix_v2.hpp"
|
||||
#include "s-power_smart.hpp"
|
||||
#include "s-secplus_v1.hpp"
|
||||
#include "s-secplus_v2.hpp"
|
||||
#include "s-smc5326.hpp"
|
||||
#include "s-star_line.hpp"
|
||||
#include "s-x10.hpp"
|
||||
|
||||
// GENIE FROM PR
|
||||
|
||||
#ifndef __FPROTO_PROTOLISTSGZ_H__
|
||||
#define __FPROTO_PROTOLISTSGZ_H__
|
||||
|
||||
class SubGhzDProtos : public FProtoListGeneral {
|
||||
public:
|
||||
SubGhzDProtos(const SubGhzDProtos&) { SubGhzDProtos(); }; // won't use, but makes compiler happy
|
||||
SubGhzDProtos& operator=(const SubGhzDProtos&) { return *this; } // won't use, but makes compiler happy
|
||||
SubGhzDProtos() {
|
||||
// add protos
|
||||
protos[FPS_PRINCETON] = new FProtoSubGhzDPrinceton();
|
||||
protos[FPS_BETT] = new FProtoSubGhzDBett();
|
||||
protos[FPS_CAME] = new FProtoSubGhzDCame();
|
||||
protos[FPS_CAMEATOMO] = new FProtoSubGhzDCameAtomo();
|
||||
protos[FPS_CAMETWEE] = new FProtoSubGhzDCameTwee();
|
||||
protos[FPS_CHAMBCODE] = new FProtoSubGhzDChambCode();
|
||||
protos[FPS_CLEMSA] = new FProtoSubGhzDClemsa();
|
||||
protos[FPS_DOITRAND] = new FProtoSubGhzDDoitrand();
|
||||
protos[FPS_DOOYA] = new FProtoSubGhzDDooya();
|
||||
protos[FPS_FAAC] = new FProtoSubGhzDFaac();
|
||||
protos[FPS_GATETX] = new FProtoSubGhzDGateTx();
|
||||
protos[FPS_HOLTEK] = new FProtoSubGhzDHoltek();
|
||||
protos[FPS_HOLTEKHT12X] = new FProtoSubGhzDHoltekHt12x();
|
||||
protos[FPS_HONEYWELL] = new FProtoSubGhzDHoneywell();
|
||||
protos[FPS_HONEYWELLWDB] = new FProtoSubGhzDHoneywellWdb();
|
||||
protos[FPS_HORMANN] = new FProtoSubGhzDHormann();
|
||||
protos[FPS_IDO] = new FProtoSubGhzDIdo();
|
||||
protos[FPS_INTERTECHNOV3] = new FProtoSubGhzDIntertechnoV3();
|
||||
protos[FPS_KEELOQ] = new FProtoSubGhzDKeeLoq();
|
||||
protos[FPS_KINGGATESSTYLO4K] = new FProtoSubGhzDKinggatesStylo4K();
|
||||
protos[FPS_LINEAR] = new FProtoSubGhzDLinear();
|
||||
protos[FPS_LINEARDELTA3] = new FProtoSubGhzDLinearDelta3();
|
||||
protos[FPS_MAGELLAN] = new FProtoSubGhzDMagellan();
|
||||
protos[FPS_MARANTEC] = new FProtoSubGhzDMarantec();
|
||||
protos[FPS_MASTERCODE] = new FProtoSubGhzDMastercode();
|
||||
protos[FPS_MEGACODE] = new FProtoSubGhzDMegacode();
|
||||
protos[FPS_NERORADIO] = new FProtoSubGhzDNeroRadio();
|
||||
protos[FPS_NERO_SKETCH] = new FProtoSubGhzDNeroSketch();
|
||||
protos[FPS_NICEFLO] = new FProtoSubGhzDNiceflo();
|
||||
protos[FPS_NICEFLORS] = new FProtoSubGhzDNiceflors();
|
||||
protos[FPS_PHOENIXV2] = new FProtoSubGhzDPhoenixV2();
|
||||
protos[FPS_POWERSMART] = new FProtoSubGhzDPowerSmart();
|
||||
protos[FPS_SECPLUSV1] = new FProtoSubGhzDSecPlusV1();
|
||||
protos[FPS_SECPLUSV2] = new FProtoSubGhzDSecPlusV2();
|
||||
protos[FPS_SMC5326] = new FProtoSubGhzDSmc5326();
|
||||
// somify keytis skipped
|
||||
// somify telis skipped
|
||||
protos[FPS_STARLINE] = new FProtoSubGhzDStarLine();
|
||||
protos[FPS_X10] = new FProtoSubGhzDX10();
|
||||
// genie skipped
|
||||
|
||||
for (uint8_t i = 0; i < FPS_COUNT; ++i) {
|
||||
if (protos[i] != NULL) protos[i]->setCallback(callbackTarget);
|
||||
}
|
||||
}
|
||||
|
||||
~SubGhzDProtos() { // not needed for current operation logic, but a bit more elegant :)
|
||||
for (uint8_t i = 0; i < FPS_COUNT; ++i) {
|
||||
if (protos[i] != NULL) {
|
||||
free(protos[i]);
|
||||
protos[i] = NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static void callbackTarget(FProtoSubGhzDBase* instance) {
|
||||
SubGhzDDataMessage packet_message{instance->sensorType, instance->btn, instance->data_count_bit, instance->serial, instance->data, instance->cnt};
|
||||
shared_memory.application_queue.push(packet_message);
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
for (uint8_t i = 0; i < FPS_COUNT; ++i) {
|
||||
if (protos[i] != NULL) protos[i]->feed(level, duration);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
FProtoSubGhzDBase* protos[FPS_COUNT] = {NULL};
|
||||
};
|
||||
|
||||
#endif
|
63
firmware/baseband/fprotos/subghztypes.hpp
Normal file
63
firmware/baseband/fprotos/subghztypes.hpp
Normal file
@ -0,0 +1,63 @@
|
||||
|
||||
#ifndef __FPROTO_SUBGHZDTYPES_H__
|
||||
#define __FPROTO_SUBGHZDTYPES_H__
|
||||
|
||||
/*
|
||||
Define known protocols.
|
||||
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.
|
||||
*/
|
||||
|
||||
#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,
|
||||
FPS_BETT,
|
||||
FPS_CAME,
|
||||
FPS_PRASTEL,
|
||||
FPS_AIRFORCE,
|
||||
FPS_CAMEATOMO,
|
||||
FPS_CAMETWEE,
|
||||
FPS_CHAMBCODE,
|
||||
FPS_CLEMSA,
|
||||
FPS_DOITRAND,
|
||||
FPS_DOOYA,
|
||||
FPS_FAAC,
|
||||
FPS_GATETX,
|
||||
FPS_HOLTEK,
|
||||
FPS_HOLTEKHT12X,
|
||||
FPS_HONEYWELL,
|
||||
FPS_HONEYWELLWDB,
|
||||
FPS_HORMANN,
|
||||
FPS_IDO,
|
||||
FPS_INTERTECHNOV3,
|
||||
FPS_KEELOQ,
|
||||
FPS_KINGGATESSTYLO4K,
|
||||
FPS_LINEAR,
|
||||
FPS_LINEARDELTA3,
|
||||
FPS_MAGELLAN,
|
||||
FPS_MARANTEC,
|
||||
FPS_MASTERCODE,
|
||||
FPS_MEGACODE,
|
||||
FPS_NERORADIO,
|
||||
FPS_NERO_SKETCH,
|
||||
FPS_NICEFLO,
|
||||
FPS_NICEFLORS,
|
||||
FPS_PHOENIXV2,
|
||||
FPS_POWERSMART,
|
||||
FPS_SECPLUSV1,
|
||||
FPS_SECPLUSV2,
|
||||
FPS_SMC5326,
|
||||
FPS_STARLINE,
|
||||
FPS_X10,
|
||||
|
||||
FPS_COUNT
|
||||
};
|
||||
|
||||
#endif
|
@ -130,9 +130,9 @@ class FProtoWeatherAcurite592TXR : public FProtoWeatherBase {
|
||||
static_cast<uint8_t>(decode_data >> 16),
|
||||
static_cast<uint8_t>(decode_data >> 8)};
|
||||
|
||||
if ((subghz_protocol_blocks_add_bytes(msg, 6) ==
|
||||
if ((FProtoGeneral::subghz_protocol_blocks_add_bytes(msg, 6) ==
|
||||
(uint8_t)(decode_data & 0xFF)) &&
|
||||
(!subghz_protocol_blocks_parity_bytes(&msg[2], 4))) {
|
||||
(!FProtoGeneral::subghz_protocol_blocks_parity_bytes(&msg[2], 4))) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -102,7 +102,7 @@ class FProtoWeatherAcurite606TX : public FProtoWeatherBase {
|
||||
static_cast<uint8_t>(decode_data >> 16),
|
||||
static_cast<uint8_t>(decode_data >> 8)};
|
||||
|
||||
uint8_t crc = subghz_protocol_blocks_lfsr_digest8(msg, 3, 0x98, 0xF1);
|
||||
uint8_t crc = FProtoGeneral::subghz_protocol_blocks_lfsr_digest8(msg, 3, 0x98, 0xF1);
|
||||
return (crc == (decode_data & 0xFF));
|
||||
}
|
||||
};
|
||||
|
@ -108,16 +108,16 @@ class FProtoWeatherAcurite986 : public FProtoWeatherBase {
|
||||
void ws_protocol_acurite_986_remote_controller() {
|
||||
int temp;
|
||||
|
||||
id = subghz_protocol_blocks_reverse_key(data >> 24, 8);
|
||||
id = (id << 8) | subghz_protocol_blocks_reverse_key(data >> 16, 8);
|
||||
id = FProtoGeneral::subghz_protocol_blocks_reverse_key(data >> 24, 8);
|
||||
id = (id << 8) | FProtoGeneral::subghz_protocol_blocks_reverse_key(data >> 16, 8);
|
||||
battery_low = (data >> 14) & 1;
|
||||
channel = ((data >> 15) & 1) + 1;
|
||||
|
||||
temp = subghz_protocol_blocks_reverse_key(data >> 32, 8);
|
||||
temp = FProtoGeneral::subghz_protocol_blocks_reverse_key(data >> 32, 8);
|
||||
if (temp & 0x80) {
|
||||
temp = -(temp & 0x7F);
|
||||
}
|
||||
temp = locale_fahrenheit_to_celsius((float)temp);
|
||||
temp = FProtoGeneral::locale_fahrenheit_to_celsius((float)temp);
|
||||
btn = WS_NO_BTN;
|
||||
humidity = WS_NO_HUMIDITY;
|
||||
}
|
||||
@ -130,7 +130,7 @@ class FProtoWeatherAcurite986 : public FProtoWeatherBase {
|
||||
(uint8_t)(decode_data >> 16),
|
||||
(uint8_t)(decode_data >> 8)};
|
||||
|
||||
uint8_t crc = subghz_protocol_blocks_crc8(msg, 4, 0x07, 0x00);
|
||||
uint8_t crc = FProtoGeneral::subghz_protocol_blocks_crc8(msg, 4, 0x07, 0x00);
|
||||
return (crc == (decode_data & 0xFF));
|
||||
}
|
||||
};
|
||||
|
@ -32,11 +32,11 @@ class FProtoWeatherAmbient : public FProtoWeatherBase {
|
||||
}
|
||||
}
|
||||
if (event != ManchesterEventReset) {
|
||||
bool data;
|
||||
bool data_ok = manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data);
|
||||
bool bit;
|
||||
bool data_ok = FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &bit);
|
||||
|
||||
if (data_ok) {
|
||||
decode_data = (decode_data << 1) | !data;
|
||||
decode_data = (decode_data << 1) | !bit;
|
||||
}
|
||||
|
||||
if (((decode_data & AMBIENT_WEATHER_PACKET_HEADER_MASK) == AMBIENT_WEATHER_PACKET_HEADER_1) ||
|
||||
@ -53,7 +53,7 @@ class FProtoWeatherAmbient : public FProtoWeatherBase {
|
||||
} else {
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ class FProtoWeatherAmbient : public FProtoWeatherBase {
|
||||
static_cast<uint8_t>(decode_data >> 16),
|
||||
static_cast<uint8_t>(decode_data >> 8)};
|
||||
|
||||
uint8_t crc = subghz_protocol_blocks_lfsr_digest8(msg, 5, 0x98, 0x3e) ^ 0x64;
|
||||
uint8_t crc = FProtoGeneral::subghz_protocol_blocks_lfsr_digest8(msg, 5, 0x98, 0x3e) ^ 0x64;
|
||||
return (crc == (uint8_t)(decode_data & 0xFF));
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@ class FProtoWeatherAmbient : public FProtoWeatherBase {
|
||||
id = (data >> 32) & 0xFF;
|
||||
battery_low = (data >> 31) & 1;
|
||||
channel = ((data >> 28) & 0x07) + 1;
|
||||
temp = locale_fahrenheit_to_celsius(((float)((data >> 16) & 0x0FFF) - 400.0f) / 10.0f);
|
||||
temp = FProtoGeneral::locale_fahrenheit_to_celsius(((float)((data >> 16) & 0x0FFF) - 400.0f) / 10.0f);
|
||||
humidity = (data >> 8) & 0xFF;
|
||||
btn = WS_NO_BTN;
|
||||
}
|
||||
|
@ -118,19 +118,16 @@ class FProtoWeatherInfactory : public FProtoWeatherBase {
|
||||
static_cast<uint8_t>(decode_data >> 8),
|
||||
static_cast<uint8_t>(decode_data)};
|
||||
|
||||
uint8_t crc =
|
||||
subghz_protocol_blocks_crc4(msg, 4, 0x13, 0); // Koopmann 0x9, CCITT-4; FP-4; ITU-T G.704
|
||||
crc ^= msg[4] >> 4; // last nibble is only XORed
|
||||
uint8_t crc = FProtoGeneral::subghz_protocol_blocks_crc4(msg, 4, 0x13, 0); // Koopmann 0x9, CCITT-4; FP-4; ITU-T G.704
|
||||
crc ^= msg[4] >> 4; // last nibble is only XORed
|
||||
return (crc == ((decode_data >> 28) & 0x0F));
|
||||
}
|
||||
void ws_protocol_infactory_remote_controller() {
|
||||
id = data >> 32;
|
||||
battery_low = (data >> 26) & 1;
|
||||
btn = WS_NO_BTN;
|
||||
temp =
|
||||
locale_fahrenheit_to_celsius(((float)((data >> 12) & 0x0FFF) - 900.0f) / 10.0f);
|
||||
humidity =
|
||||
(((data >> 8) & 0x0F) * 10) + ((data >> 4) & 0x0F); // BCD, 'A0'=100%rH
|
||||
temp = FProtoGeneral::locale_fahrenheit_to_celsius(((float)((data >> 12) & 0x0FFF) - 900.0f) / 10.0f);
|
||||
humidity = (((data >> 8) & 0x0F) * 10) + ((data >> 4) & 0x0F); // BCD, 'A0'=100%rH
|
||||
channel = data & 0x03;
|
||||
}
|
||||
};
|
||||
|
@ -155,7 +155,7 @@ class FProtoWeatherLaCrosseTx : public FProtoWeatherBase {
|
||||
static_cast<uint8_t>((decode_data >> 8) & 0x0F),
|
||||
static_cast<uint8_t>((decode_data >> 4) & 0x0F)};
|
||||
|
||||
uint8_t crc = subghz_protocol_blocks_add_bytes(msg, 9);
|
||||
uint8_t crc = FProtoGeneral::subghz_protocol_blocks_add_bytes(msg, 9);
|
||||
return ((crc & 0x0F) == (decode_data & 0x0F));
|
||||
}
|
||||
};
|
||||
|
@ -104,7 +104,7 @@ class FProtoWeatherLaCrosseTx141thbv2 : public FProtoWeatherBase {
|
||||
}
|
||||
uint8_t msg[] = {static_cast<uint8_t>(data >> 32), static_cast<uint8_t>(data >> 24), static_cast<uint8_t>(data >> 16), static_cast<uint8_t>(data >> 8)};
|
||||
|
||||
uint8_t crc = subghz_protocol_blocks_lfsr_digest8_reflect(msg, 4, 0x31, 0xF4);
|
||||
uint8_t crc = FProtoGeneral::subghz_protocol_blocks_lfsr_digest8_reflect(msg, 4, 0x31, 0xF4);
|
||||
return (crc == (data & 0xFF));
|
||||
}
|
||||
void ws_protocol_lacrosse_tx141thbv2_remote_controller() {
|
||||
|
@ -77,7 +77,7 @@ class FProtoWeatherOregon2 : public FProtoWeatherBase {
|
||||
decode_data = 0UL;
|
||||
decode_count_bit = 0;
|
||||
}
|
||||
if (manchester_advance(manchester_saved_state, event, &manchester_saved_state, &bit_value)) {
|
||||
if (FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &bit_value)) {
|
||||
if (have_bit) {
|
||||
if (!prev_bit && bit_value) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
@ -165,7 +165,7 @@ class FProtoWeatherOregon2 : public FProtoWeatherBase {
|
||||
parser_step = Oregon2DecoderStepReset;
|
||||
decode_data = 0UL;
|
||||
decode_count_bit = 0;
|
||||
manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
|
||||
have_bit = false;
|
||||
var_data = 0;
|
||||
var_bits = 0;
|
||||
|
@ -47,7 +47,7 @@ class FProtoWeatherOregon3 : public FProtoWeatherBase {
|
||||
decode_data = 0UL;
|
||||
decode_count_bit = 0;
|
||||
}
|
||||
if (manchester_advance(
|
||||
if (FProtoGeneral::manchester_advance(
|
||||
manchester_saved_state, event, &manchester_saved_state, &prev_bit)) {
|
||||
subghz_protocol_blocks_add_bit(prev_bit);
|
||||
}
|
||||
|
@ -64,11 +64,7 @@ class FProtoWeatherOregonV1 : public FProtoWeatherBase {
|
||||
// found all the necessary patterns
|
||||
decode_data = 0;
|
||||
decode_count_bit = 1;
|
||||
manchester_advance(
|
||||
manchester_saved_state,
|
||||
ManchesterEventReset,
|
||||
&manchester_saved_state,
|
||||
NULL);
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
|
||||
parser_step = Oregon_V1DecoderStepParse;
|
||||
if (duration < te_short * 4) {
|
||||
first_bit = 1;
|
||||
@ -114,22 +110,17 @@ class FProtoWeatherOregonV1 : public FProtoWeatherBase {
|
||||
}
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
manchester_advance(
|
||||
manchester_saved_state,
|
||||
ManchesterEventReset,
|
||||
&manchester_saved_state,
|
||||
NULL);
|
||||
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
|
||||
} else {
|
||||
parser_step = Oregon_V1DecoderStepReset;
|
||||
}
|
||||
}
|
||||
if (event != ManchesterEventReset) {
|
||||
bool data;
|
||||
bool data_ok = manchester_advance(
|
||||
manchester_saved_state, event, &manchester_saved_state, &data);
|
||||
bool bit;
|
||||
bool data_ok = FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &bit);
|
||||
|
||||
if (data_ok) {
|
||||
decode_data = (decode_data << 1) | !data;
|
||||
decode_data = (decode_data << 1) | !bit;
|
||||
decode_count_bit++;
|
||||
}
|
||||
}
|
||||
@ -149,13 +140,13 @@ class FProtoWeatherOregonV1 : public FProtoWeatherBase {
|
||||
|
||||
bool ws_protocol_oregon_v1_check() {
|
||||
if (!decode_data) return false;
|
||||
uint64_t data = subghz_protocol_blocks_reverse_key(decode_data, 32);
|
||||
uint64_t data = FProtoGeneral::subghz_protocol_blocks_reverse_key(decode_data, 32);
|
||||
uint16_t crc = (data & 0xff) + ((data >> 8) & 0xff) + ((data >> 16) & 0xff);
|
||||
crc = (crc & 0xff) + ((crc >> 8) & 0xff);
|
||||
return (crc == ((data >> 24) & 0xFF));
|
||||
}
|
||||
void ws_protocol_oregon_v1_remote_controller() {
|
||||
uint64_t data2 = subghz_protocol_blocks_reverse_key(data, 32);
|
||||
uint64_t data2 = FProtoGeneral::subghz_protocol_blocks_reverse_key(data, 32);
|
||||
|
||||
id = data2 & 0xFF;
|
||||
channel = ((data2 >> 6) & 0x03) + 1;
|
||||
|
@ -128,7 +128,7 @@ class FProtoWeatherWendoxW6726 : public FProtoWeatherBase {
|
||||
static_cast<uint8_t>(decode_data >> 12),
|
||||
static_cast<uint8_t>(decode_data >> 4)};
|
||||
|
||||
uint8_t crc = subghz_protocol_blocks_crc4(msg, 4, 0x9, 0xD);
|
||||
uint8_t crc = FProtoGeneral::subghz_protocol_blocks_crc4(msg, 4, 0x9, 0xD);
|
||||
return (crc == (decode_data & 0x0F));
|
||||
}
|
||||
void ws_protocol_wendox_w6726_remote_controller() {
|
||||
|
@ -7,33 +7,12 @@ For comments in a protocol implementation check w-nexus-th.hpp
|
||||
#ifndef __FPROTO_BASE_H__
|
||||
#define __FPROTO_BASE_H__
|
||||
|
||||
#define bit_read(value, bit) (((value) >> (bit)) & 0x01)
|
||||
|
||||
#include "fprotogeneral.hpp"
|
||||
#include "weathertypes.hpp"
|
||||
|
||||
#include <string>
|
||||
// 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
|
||||
|
||||
#define DURATION_DIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
|
||||
typedef enum {
|
||||
ManchesterStateStart1 = 0,
|
||||
ManchesterStateMid1 = 1,
|
||||
ManchesterStateMid0 = 2,
|
||||
ManchesterStateStart0 = 3
|
||||
} ManchesterState;
|
||||
typedef enum {
|
||||
ManchesterEventShortLow = 0,
|
||||
ManchesterEventShortHigh = 2,
|
||||
ManchesterEventLongLow = 4,
|
||||
ManchesterEventLongHigh = 6,
|
||||
ManchesterEventReset = 8
|
||||
} ManchesterEvent;
|
||||
class FProtoWeatherBase;
|
||||
typedef void (*SubGhzProtocolDecoderBaseRxCallback)(FProtoWeatherBase* instance);
|
||||
|
||||
@ -49,7 +28,6 @@ class FProtoWeatherBase {
|
||||
float getTemp() { return temp; }
|
||||
uint8_t getHumidity() { return humidity; }
|
||||
uint8_t getBattLow() { return battery_low; }
|
||||
uint32_t getTimestamp() { return timestamp; }
|
||||
uint8_t getChannel() { return channel; }
|
||||
uint8_t getButton() { return btn; }
|
||||
|
||||
@ -59,149 +37,6 @@ class FProtoWeatherBase {
|
||||
decode_data = decode_data << 1 | bit;
|
||||
decode_count_bit++;
|
||||
}
|
||||
uint8_t subghz_protocol_blocks_add_bytes(uint8_t const message[], size_t size) {
|
||||
uint32_t result = 0;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
result += message[i];
|
||||
}
|
||||
return (uint8_t)result;
|
||||
}
|
||||
uint8_t subghz_protocol_blocks_parity8(uint8_t byte) {
|
||||
byte ^= byte >> 4;
|
||||
byte &= 0xf;
|
||||
return (0x6996 >> byte) & 1;
|
||||
}
|
||||
uint8_t subghz_protocol_blocks_parity_bytes(uint8_t const message[], size_t size) {
|
||||
uint8_t result = 0;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
result ^= subghz_protocol_blocks_parity8(message[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
uint8_t subghz_protocol_blocks_lfsr_digest8(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t gen,
|
||||
uint8_t key) {
|
||||
uint8_t sum = 0;
|
||||
for (size_t byte = 0; byte < size; ++byte) {
|
||||
uint8_t data = message[byte];
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
// XOR key into sum if data bit is set
|
||||
if ((data >> i) & 1) sum ^= key;
|
||||
// roll the key right (actually the LSB is dropped here)
|
||||
// and apply the gen (needs to include the dropped LSB as MSB)
|
||||
if (key & 1)
|
||||
key = (key >> 1) ^ gen;
|
||||
else
|
||||
key = (key >> 1);
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
float locale_fahrenheit_to_celsius(float temp_f) {
|
||||
return (temp_f - 32.f) / 1.8f;
|
||||
}
|
||||
bool manchester_advance(
|
||||
ManchesterState state,
|
||||
ManchesterEvent event,
|
||||
ManchesterState* next_state,
|
||||
bool* data) {
|
||||
bool result = false;
|
||||
ManchesterState new_state;
|
||||
|
||||
if (event == ManchesterEventReset) {
|
||||
new_state = manchester_reset_state;
|
||||
} else {
|
||||
new_state = (ManchesterState)(transitions[state] >> event & 0x3);
|
||||
if (new_state == state) {
|
||||
new_state = manchester_reset_state;
|
||||
} else {
|
||||
if (new_state == ManchesterStateMid0) {
|
||||
if (data) *data = false;
|
||||
result = true;
|
||||
} else if (new_state == ManchesterStateMid1) {
|
||||
if (data) *data = true;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*next_state = new_state;
|
||||
return result;
|
||||
}
|
||||
uint8_t subghz_protocol_blocks_crc4(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t polynomial,
|
||||
uint8_t init) {
|
||||
uint8_t remainder = init << 4; // LSBs are unused
|
||||
uint8_t poly = polynomial << 4;
|
||||
uint8_t bit;
|
||||
|
||||
while (size--) {
|
||||
remainder ^= *message++;
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
if (remainder & 0x80) {
|
||||
remainder = (remainder << 1) ^ poly;
|
||||
} else {
|
||||
remainder = (remainder << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return remainder >> 4 & 0x0f; // discard the LSBs
|
||||
}
|
||||
uint8_t subghz_protocol_blocks_lfsr_digest8_reflect(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t gen,
|
||||
uint8_t key) {
|
||||
uint8_t sum = 0;
|
||||
// Process message from last byte to first byte (reflected)
|
||||
for (int byte = size - 1; byte >= 0; --byte) {
|
||||
uint8_t data = message[byte];
|
||||
// Process individual bits of each byte (reflected)
|
||||
for (uint8_t i = 0; i < 8; ++i) {
|
||||
// XOR key into sum if data bit is set
|
||||
if ((data >> i) & 1) {
|
||||
sum ^= key;
|
||||
}
|
||||
// roll the key left (actually the LSB is dropped here)
|
||||
// and apply the gen (needs to include the dropped lsb as MSB)
|
||||
if (key & 0x80)
|
||||
key = (key << 1) ^ gen;
|
||||
else
|
||||
key = (key << 1);
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t bit_count) {
|
||||
uint64_t reverse_key = 0;
|
||||
for (uint8_t i = 0; i < bit_count; i++) {
|
||||
reverse_key = reverse_key << 1 | bit_read(key, i);
|
||||
}
|
||||
return reverse_key;
|
||||
}
|
||||
uint8_t subghz_protocol_blocks_crc8(
|
||||
uint8_t const message[],
|
||||
size_t size,
|
||||
uint8_t polynomial,
|
||||
uint8_t init) {
|
||||
uint8_t remainder = init;
|
||||
|
||||
for (size_t byte = 0; byte < size; ++byte) {
|
||||
remainder ^= message[byte];
|
||||
for (uint8_t bit = 0; bit < 8; ++bit) {
|
||||
if (remainder & 0x80) {
|
||||
remainder = (remainder << 1) ^ polynomial;
|
||||
} else {
|
||||
remainder = (remainder << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return remainder;
|
||||
}
|
||||
|
||||
// General weather data holder
|
||||
uint8_t sensorType = FPW_Invalid;
|
||||
@ -209,11 +44,10 @@ class FProtoWeatherBase {
|
||||
float temp = WS_NO_TEMPERATURE;
|
||||
uint8_t humidity = WS_NO_HUMIDITY;
|
||||
uint8_t battery_low = WS_NO_BATT;
|
||||
uint32_t timestamp = 0;
|
||||
uint8_t channel = WS_NO_CHANNEL;
|
||||
uint8_t btn = WS_NO_BTN;
|
||||
|
||||
// inner logic stuff, also for flipper compatibility. //todo revork a bit, so won't have dupes (decode_data + data, ..), but check if any of the protos uses it in the same time or not. (shouldn't)
|
||||
// inner logic stuff, also for flipper compatibility.
|
||||
SubGhzProtocolDecoderBaseRxCallback callback = NULL;
|
||||
uint16_t header_count = 0;
|
||||
uint8_t parser_step = 0;
|
||||
@ -223,8 +57,6 @@ class FProtoWeatherBase {
|
||||
uint64_t decode_data = 0;
|
||||
uint32_t decode_count_bit = 0;
|
||||
ManchesterState manchester_saved_state = ManchesterStateMid1;
|
||||
static const ManchesterState manchester_reset_state = ManchesterStateMid1;
|
||||
static inline const uint8_t transitions[] = {0b00000001, 0b10010001, 0b10011011, 0b11111011};
|
||||
};
|
||||
|
||||
#endif
|
@ -3,6 +3,9 @@ This is the protocol list handler. It holds an instance of all known protocols.
|
||||
So include here the .hpp, and add a new element to the protos vector in the constructor. That's all you need to do here if you wanna add a new proto.
|
||||
@htotoo
|
||||
*/
|
||||
|
||||
#include "fprotolistgeneral.hpp"
|
||||
|
||||
#include "w-nexus-th.hpp"
|
||||
#include "w-acurite592txr.hpp"
|
||||
#include "w-acurite606tx.hpp"
|
||||
@ -26,10 +29,10 @@ So include here the .hpp, and add a new element to the protos vector in the cons
|
||||
#include <memory>
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#ifndef __FPROTO_PROTOLIST_H__
|
||||
#define __FPROTO_PROTOLIST_H__
|
||||
#ifndef __FPROTO_PROTOLISTWTH_H__
|
||||
#define __FPROTO_PROTOLISTWTH_H__
|
||||
|
||||
class WeatherProtos {
|
||||
class WeatherProtos : public FProtoListGeneral {
|
||||
public:
|
||||
WeatherProtos() {
|
||||
// add protos
|
||||
|
@ -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,
|
||||
|
87
firmware/baseband/proc_subghzd.cpp
Normal file
87
firmware/baseband/proc_subghzd.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 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 "proc_subghzd.hpp"
|
||||
#include "portapack_shared_memory.hpp"
|
||||
#include "event_m4.hpp"
|
||||
|
||||
void SubGhzDProcessor::execute(const buffer_c8_t& buffer) {
|
||||
if (!configured) return;
|
||||
|
||||
// SR = 4Mhz , and we are decimating by /8 in total , decim1_out clock 4Mhz /8= 500khz samples/sec.
|
||||
// buffer has 2048 complex i8 I,Q signed samples
|
||||
// decim0 out: 2048/4 = 512 complex i16 I,Q signed samples
|
||||
// decim1 out: 512/2 = 256 complex i16 I,Q signed samples
|
||||
// Regarding Filters, we are re-using existing FIR filters, @4Mhz, FIR decim1 ilter, BW =+-220Khz (at -3dB's). BW = 440kHZ.
|
||||
|
||||
const auto decim_0_out = decim_0.execute(buffer, dst_buffer); // Input:2048 complex/4 (decim factor) = 512_output complex (1024 I/Q samples)
|
||||
const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer); // Input:512 complex/2 (decim factor) = 256_output complex ( 512 I/Q samples)
|
||||
|
||||
for (size_t i = 0; i < decim_1_out.count; i++) {
|
||||
int16_t re = decim_1_out.p[i].real();
|
||||
int16_t im = decim_1_out.p[i].imag();
|
||||
uint32_t mag = ((uint32_t)re * (uint32_t)re) + ((uint32_t)im * (uint32_t)im);
|
||||
|
||||
mag = (mag >> 12); // Decim samples are calculated with saturated gain . (we could also reduce that sat. param at configure time)
|
||||
|
||||
bool meashl = (mag > threshold);
|
||||
tm += mag;
|
||||
if (meashl == currentHiLow && currentDuration < 30'000'000) // allow pass 'end' signal
|
||||
{
|
||||
if (currentDuration < UINT32_MAX) currentDuration += nsPerDecSamp;
|
||||
} else { // called on change, so send the last duration and dir.
|
||||
if (protoList) protoList->feed(currentHiLow, currentDuration / 1000);
|
||||
currentDuration = nsPerDecSamp;
|
||||
currentHiLow = meashl;
|
||||
}
|
||||
}
|
||||
|
||||
cnt += decim_1_out.count; // TODO , check if it is necessary that xdecim factor.
|
||||
if (cnt > 90'000) {
|
||||
threshold = (tm / cnt) / 2;
|
||||
cnt = 0;
|
||||
tm = 0;
|
||||
if (threshold < 50) threshold = 50;
|
||||
if (threshold > 1700) threshold = 1700;
|
||||
}
|
||||
}
|
||||
|
||||
void SubGhzDProcessor::on_message(const Message* const message) {
|
||||
if (message->id == Message::ID::SubGhzFPRxConfigure)
|
||||
configure(*reinterpret_cast<const SubGhzFPRxConfigureMessage*>(message));
|
||||
}
|
||||
|
||||
void SubGhzDProcessor::configure(const SubGhzFPRxConfigureMessage& message) {
|
||||
// constexpr size_t decim_0_output_fs = baseband_fs / decim_0.decimation_factor; //unused
|
||||
// constexpr size_t decim_1_output_fs = decim_0_output_fs / decim_1.decimation_factor; //unused
|
||||
|
||||
decim_0.configure(taps_200k_wfm_decim_0.taps);
|
||||
decim_1.configure(taps_200k_wfm_decim_1.taps);
|
||||
|
||||
configured = true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
EventDispatcher event_dispatcher{std::make_unique<SubGhzDProcessor>()};
|
||||
event_dispatcher.run();
|
||||
return 0;
|
||||
}
|
73
firmware/baseband/proc_subghzd.hpp
Normal file
73
firmware/baseband/proc_subghzd.hpp
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
/*
|
||||
Creator: @htotoo
|
||||
*/
|
||||
|
||||
#ifndef __PROC_WEATHER_H__
|
||||
#define __PROC_WEATHER_H__
|
||||
|
||||
#include "baseband_processor.hpp"
|
||||
#include "baseband_thread.hpp"
|
||||
#include "rssi_thread.hpp"
|
||||
#include "message.hpp"
|
||||
#include "dsp_decimate.hpp"
|
||||
|
||||
#include "fprotos/subghzdprotos.hpp"
|
||||
|
||||
class SubGhzDProcessor : public BasebandProcessor {
|
||||
public:
|
||||
void execute(const buffer_c8_t& buffer) override;
|
||||
void on_message(const Message* const message) override;
|
||||
|
||||
private:
|
||||
static constexpr size_t baseband_fs = 4'000'000; // it works, I think we need to write that master clock in the baseband_threat , even later we decimate it.
|
||||
static constexpr uint32_t nsPerDecSamp = 1'000'000'000 / baseband_fs * 8; // 10 exp9/baseband_fs * 8
|
||||
|
||||
/* Array Buffer aux. used in decim0 and decim1 IQ c16 signed data ; (decim0 defines the max length of the array) */
|
||||
std::array<complex16_t, 512> dst{}; // decim0 /4 , 2048/4 = 512 complex I,Q
|
||||
const buffer_c16_t dst_buffer{
|
||||
dst.data(),
|
||||
dst.size()};
|
||||
|
||||
/* Decimates */
|
||||
dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0{};
|
||||
dsp::decimate::FIRC16xR16x16Decim2 decim_1{};
|
||||
|
||||
uint32_t currentDuration = 0;
|
||||
uint32_t threshold = 0x0630; // will overwrite after the first iteration
|
||||
bool currentHiLow = false;
|
||||
bool configured{false};
|
||||
|
||||
// for threshold
|
||||
uint32_t cnt = 0;
|
||||
uint32_t tm = 0;
|
||||
|
||||
FProtoListGeneral* protoList = new SubGhzDProtos(); // holds all the protocols we can parse
|
||||
void configure(const SubGhzFPRxConfigureMessage& message);
|
||||
|
||||
/* NB: Threads should be the last members in the class definition. */
|
||||
BasebandThread baseband_thread{baseband_fs, this, baseband::Direction::Receive};
|
||||
RSSIThread rssi_thread{};
|
||||
};
|
||||
|
||||
#endif /*__PROC_WEATHER_H__*/
|
@ -45,18 +45,18 @@ void WeatherProcessor::execute(const buffer_c8_t& buffer) {
|
||||
|
||||
bool meashl = (mag > threshold);
|
||||
tm += mag;
|
||||
if (meashl == currentHiLow && currentDuration < 10'000'000) // allow pass 'end' signal
|
||||
if (meashl == currentHiLow && currentDuration < 30'000'000) // allow pass 'end' signal
|
||||
{
|
||||
if (currentDuration < UINT32_MAX) currentDuration += nsPerDecSamp;
|
||||
} else { // called on change, so send the last duration and dir.
|
||||
protoList.feed(currentHiLow, currentDuration / 1000);
|
||||
if (protoList) protoList->feed(currentHiLow, currentDuration / 1000);
|
||||
currentDuration = nsPerDecSamp;
|
||||
currentHiLow = meashl;
|
||||
}
|
||||
}
|
||||
|
||||
cnt += decim_1_out.count; // TODO , check if it is necessary that xdecim factor.
|
||||
if (cnt > 30'000) {
|
||||
if (cnt > 90'000) {
|
||||
threshold = (tm / cnt) / 2;
|
||||
cnt = 0;
|
||||
tm = 0;
|
||||
@ -66,19 +66,18 @@ void WeatherProcessor::execute(const buffer_c8_t& buffer) {
|
||||
}
|
||||
|
||||
void WeatherProcessor::on_message(const Message* const message) {
|
||||
if (message->id == Message::ID::WeatherRxConfigure)
|
||||
configure(*reinterpret_cast<const WeatherRxConfigureMessage*>(message));
|
||||
if (message->id == Message::ID::SubGhzFPRxConfigure)
|
||||
configure(*reinterpret_cast<const SubGhzFPRxConfigureMessage*>(message));
|
||||
}
|
||||
|
||||
void WeatherProcessor::configure(const WeatherRxConfigureMessage& message) {
|
||||
// unused:
|
||||
// constexpr size_t decim_0_output_fs = baseband_fs / decim_0.decimation_factor;
|
||||
// constexpr size_t decim_1_output_fs = decim_0_output_fs / decim_1.decimation_factor;
|
||||
void WeatherProcessor::configure(const SubGhzFPRxConfigureMessage& message) {
|
||||
// constexpr size_t decim_0_output_fs = baseband_fs / decim_0.decimation_factor; //unused
|
||||
// constexpr size_t decim_1_output_fs = decim_0_output_fs / decim_1.decimation_factor; //unused
|
||||
(void)message; // unused
|
||||
|
||||
decim_0.configure(taps_200k_wfm_decim_0.taps);
|
||||
decim_1.configure(taps_200k_wfm_decim_1.taps);
|
||||
|
||||
(void)message;
|
||||
configured = true;
|
||||
}
|
||||
|
||||
|
@ -58,12 +58,14 @@ class WeatherProcessor : public BasebandProcessor {
|
||||
bool currentHiLow = false;
|
||||
bool configured{false};
|
||||
|
||||
// for debug
|
||||
uint8_t modulation = 255; // 0 AM, 1 FM 255 = Not set
|
||||
uint8_t protoMode = 255; // 0 weather, 1 subghzd, 255 = Not set
|
||||
// for threshold
|
||||
uint32_t cnt = 0;
|
||||
uint32_t tm = 0;
|
||||
|
||||
WeatherProtos protoList{}; // holds all the protocols we can parse
|
||||
void configure(const WeatherRxConfigureMessage& message);
|
||||
FProtoListGeneral* protoList = new WeatherProtos(); // holds all the protocols we can parse
|
||||
void configure(const SubGhzFPRxConfigureMessage& message);
|
||||
|
||||
/* NB: Threads should be the last members in the class definition. */
|
||||
BasebandThread baseband_thread{baseband_fs, this, baseband::Direction::Receive};
|
||||
|
@ -115,8 +115,9 @@ class Message {
|
||||
FSKRxConfigure = 58,
|
||||
BlePacket = 58,
|
||||
BTLETxConfigure = 59,
|
||||
WeatherRxConfigure = 60,
|
||||
SubGhzFPRxConfigure = 60,
|
||||
WeatherData = 61,
|
||||
SubGhzDData = 62,
|
||||
MAX
|
||||
};
|
||||
|
||||
@ -1238,11 +1239,12 @@ class SpectrumPainterBufferConfigureResponseMessage : public Message {
|
||||
SpectrumPainterFIFO* fifo{nullptr};
|
||||
};
|
||||
|
||||
class WeatherRxConfigureMessage : public Message {
|
||||
class SubGhzFPRxConfigureMessage : public Message {
|
||||
public:
|
||||
constexpr WeatherRxConfigureMessage()
|
||||
: Message{ID::WeatherRxConfigure} {
|
||||
constexpr SubGhzFPRxConfigureMessage(uint8_t modulation = 0)
|
||||
: Message{ID::SubGhzFPRxConfigure}, modulation{modulation} {
|
||||
}
|
||||
uint8_t modulation = 0; // 0 am, 1 fm
|
||||
};
|
||||
|
||||
class WeatherDataMessage : public Message {
|
||||
@ -1273,4 +1275,29 @@ class WeatherDataMessage : public Message {
|
||||
uint8_t btn = 0xFF;
|
||||
};
|
||||
|
||||
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)
|
||||
: 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;
|
||||
};
|
||||
|
||||
#endif /*__MESSAGE_H__*/
|
||||
|
@ -113,6 +113,7 @@ constexpr image_tag_t image_tag_flash_utility{'P', 'F', 'U', 'T'};
|
||||
constexpr image_tag_t image_tag_usb_sd{'P', 'U', 'S', 'B'};
|
||||
|
||||
constexpr image_tag_t image_tag_weather{'P', 'W', 'T', 'H'};
|
||||
constexpr image_tag_t image_tag_subghzd{'P', 'S', 'G', 'D'};
|
||||
|
||||
constexpr image_tag_t image_tag_noop{'P', 'N', 'O', 'P'};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user