mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-02 04:49:01 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 53bbf74f4d | |||
| 19a66fac20 | |||
| 36e1b9a36e | |||
| 1ca9288bbe | |||
| 4ca2d1e352 | |||
| 0b11730835 | |||
| 6069145b68 | |||
| 2ccda5aebd | |||
| 02810bf527 |
@@ -1 +1 @@
|
||||
v1.7.4
|
||||
v1.8.0
|
||||
|
||||
@@ -1 +1 @@
|
||||
v1.8.0
|
||||
v1.9.0
|
||||
|
||||
@@ -54,6 +54,7 @@ add_custom_target(
|
||||
|
||||
add_custom_target(
|
||||
program
|
||||
COMMAND ${PROJECT_SOURCE_DIR}/tools/enter_mode.sh hackrf
|
||||
COMMAND dfu-util --device 1fc9:000c --download ${HACKRF_FIRMWARE_DFU_IMAGE} || (exit 0) # We need to add it for dfu-utils v.011 , (in v.09 it is not necessary)
|
||||
COMMAND sleep 3s
|
||||
COMMAND hackrf_spiflash -i -R -w ${FIRMWARE_FILENAME}
|
||||
|
||||
@@ -113,6 +113,17 @@ set(CSRC
|
||||
${BOARDSRC}
|
||||
${FATFSSRC}
|
||||
firmware_info.c
|
||||
usb_serial_cdc.c
|
||||
usb_serial_descriptor.c
|
||||
usb_serial_endpoints.c
|
||||
usb_serial_io.c
|
||||
${HACKRF_PATH}/firmware/common/usb.c
|
||||
${HACKRF_PATH}/firmware/common/usb_queue.c
|
||||
${HACKRF_PATH}/firmware/hackrf_usb/usb_device.c
|
||||
${HACKRF_PATH}/firmware/common/usb_request.c
|
||||
${HACKRF_PATH}/firmware/common/usb_standard_request.c
|
||||
${CHIBIOS}/os/various/shell.c
|
||||
${CHIBIOS}/os/various/chprintf.c
|
||||
)
|
||||
|
||||
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
||||
@@ -191,6 +202,10 @@ set(CPPSRC
|
||||
log_file.cpp
|
||||
metadata_file.cpp
|
||||
portapack.cpp
|
||||
usb_serial_shell.cpp
|
||||
usb_serial_event.cpp
|
||||
usb_serial_thread.cpp
|
||||
usb_serial.cpp
|
||||
qrcodegen.cpp
|
||||
radio.cpp
|
||||
receiver_model.cpp
|
||||
@@ -273,7 +288,7 @@ set(CPPSRC
|
||||
apps/ui_freqman.cpp
|
||||
apps/ui_fsk_rx.cpp
|
||||
apps/ui_iq_trim.cpp
|
||||
apps/ui_jammer.cpp
|
||||
# apps/ui_jammer.cpp
|
||||
# apps/ui_keyfob.cpp
|
||||
# apps/ui_lcr.cpp
|
||||
apps/ui_level.cpp
|
||||
@@ -301,6 +316,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
|
||||
@@ -362,6 +378,9 @@ set(INCDIR ${CMAKE_CURRENT_BINARY_DIR} ${COMMON} ${PORTINC} ${KERNINC} ${TESTINC
|
||||
${HALINC} ${PLATFORMINC} ${BOARDINC}
|
||||
${FATFSINC}
|
||||
${CHIBIOS}/os/various
|
||||
${HACKRF_PATH}/firmware/libopencm3/include
|
||||
${HACKRF_PATH}/firmware/common
|
||||
${HACKRF_PATH}/firmware
|
||||
ui
|
||||
hw
|
||||
apps
|
||||
|
||||
@@ -436,6 +436,8 @@ BLERxView::BLERxView(NavigationView& nav)
|
||||
nav_.push<BleRecentEntryDetailView>(entry);
|
||||
};
|
||||
|
||||
usb_serial_thread = std::make_unique<UsbSerialThread>();
|
||||
|
||||
ensure_directory(find_packet_path);
|
||||
ensure_directory(log_packets_path);
|
||||
ensure_directory(packet_save_path);
|
||||
@@ -684,24 +686,16 @@ bool BLERxView::saveFile(const std::filesystem::path& path) {
|
||||
}
|
||||
|
||||
void BLERxView::on_data(BlePacketData* packet) {
|
||||
std::string str_console = "";
|
||||
|
||||
if (!logging) {
|
||||
str_log = "";
|
||||
}
|
||||
|
||||
str_console += pdu_type_to_string((ADV_PDU_TYPE)packet->type);
|
||||
|
||||
str_console += " Len:";
|
||||
str_console += to_string_dec_uint(packet->size);
|
||||
|
||||
str_console += "\n";
|
||||
|
||||
str_console += "Mac:";
|
||||
str_console += " Mac:";
|
||||
str_console += to_string_mac_address(packet->macAddress, 6, false);
|
||||
|
||||
str_console += "\n";
|
||||
str_console += "Data:";
|
||||
str_console += " Data:";
|
||||
|
||||
int i;
|
||||
|
||||
@@ -709,8 +703,6 @@ void BLERxView::on_data(BlePacketData* packet) {
|
||||
str_console += to_string_hex(packet->data[i], 2);
|
||||
}
|
||||
|
||||
str_console += "\n";
|
||||
|
||||
uint64_t macAddressEncoded = copy_mac_address_to_uint64(packet->macAddress);
|
||||
|
||||
// Start of Packet stuffing.
|
||||
@@ -728,9 +720,13 @@ void BLERxView::on_data(BlePacketData* packet) {
|
||||
|
||||
// Log at End of Packet.
|
||||
if (logger && logging) {
|
||||
logger->log_raw_data(str_console);
|
||||
logger->log_raw_data(str_console + "\r\n");
|
||||
}
|
||||
|
||||
usb_serial_thread->serial_str = str_console + "\r\n";
|
||||
usb_serial_thread->str_ready = true;
|
||||
str_console = "";
|
||||
|
||||
if (!searchList.empty()) {
|
||||
auto it = searchList.begin();
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "radio_state.hpp"
|
||||
#include "log_file.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "usb_serial_thread.hpp"
|
||||
|
||||
#include "recent_entries.hpp"
|
||||
|
||||
@@ -194,6 +195,7 @@ class BLERxView : public View {
|
||||
std::string build_line_str(BleRecentEntry entry);
|
||||
void on_save_file(const std::string value);
|
||||
bool saveFile(const std::filesystem::path& path);
|
||||
std::unique_ptr<UsbSerialThread> usb_serial_thread{};
|
||||
void on_data(BlePacketData* packetData);
|
||||
void on_filter_change(std::string value);
|
||||
void on_file_changed(const std::filesystem::path& new_file_path);
|
||||
@@ -213,6 +215,7 @@ class BLERxView : public View {
|
||||
uint8_t sort_index{0};
|
||||
std::string filter{};
|
||||
bool logging{false};
|
||||
|
||||
bool name_enable{true};
|
||||
app_settings::SettingsManager settings_{
|
||||
"rx_ble",
|
||||
@@ -225,6 +228,7 @@ class BLERxView : public View {
|
||||
{"name"sv, &name_enable},
|
||||
}};
|
||||
|
||||
std::string str_console = "";
|
||||
uint8_t console_color{0};
|
||||
uint32_t prev_value{0};
|
||||
uint8_t channel_number = 37;
|
||||
|
||||
@@ -459,7 +459,7 @@ SetFrequencyCorrectionView::SetFrequencyCorrectionView(NavigationView& nav) {
|
||||
pmem::set_freq_rx_correction_updown(v);
|
||||
};
|
||||
|
||||
opt_tx_correction_mode.set_by_value(pmem::config_freq_rx_correction_updown());
|
||||
opt_tx_correction_mode.set_by_value(pmem::config_freq_tx_correction_updown());
|
||||
opt_tx_correction_mode.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
pmem::set_freq_tx_correction_updown(v);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* 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_config(0, receiver_model.sampling_rate()); // 0=am
|
||||
receiver_model.enable();
|
||||
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
||||
on_tick_second();
|
||||
};
|
||||
}
|
||||
|
||||
void SubGhzDView::on_tick_second() {
|
||||
for (auto& entry : recent) {
|
||||
entry.inc_age(1);
|
||||
}
|
||||
recent_entries_view.set_dirty();
|
||||
}
|
||||
|
||||
void SubGhzDView::on_data(const SubGhzDDataMessage* data) {
|
||||
SubGhzDRecentEntry key{data->sensorType, data->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
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -100,8 +115,7 @@ WeatherView::WeatherView(NavigationView& nav)
|
||||
recent_entries_view.on_select = [this](const WeatherRecentEntry& entry) {
|
||||
nav_.push<WeatherRecentEntryDetailView>(entry);
|
||||
};
|
||||
baseband::set_weather();
|
||||
receiver_model.set_sampling_rate(4'000'000); // needed too
|
||||
baseband::set_subghzd_config(0, receiver_model.sampling_rate()); // 0=am
|
||||
receiver_model.enable();
|
||||
signal_token_tick_second = rtc_time::signal_tick_second += [this]() {
|
||||
on_tick_second();
|
||||
@@ -205,8 +219,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;
|
||||
@@ -218,4 +232,4 @@ void RecentEntriesTable<ui::WeatherRecentEntries>::draw(
|
||||
painter.draw_string(target_rect.location(), style, line);
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
} // namespace ui
|
||||
|
||||
@@ -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},
|
||||
@@ -100,8 +100,8 @@ class WeatherView : public View {
|
||||
NavigationView& nav_;
|
||||
RxRadioState radio_state_{
|
||||
433'920'000 /* frequency */,
|
||||
2'500'000 /* bandwidth max283x*/,
|
||||
4'000'000 /* sampling rate */,
|
||||
1'750'000 /* bandwidth */,
|
||||
2'000'000 /* sampling rate */,
|
||||
ReceiverModel::Mode::AMAudio};
|
||||
app_settings::SettingsManager settings_{
|
||||
"rx_weather",
|
||||
|
||||
@@ -319,8 +319,8 @@ void set_spectrum_painter_config(const uint16_t width, const uint16_t height, bo
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
void set_weather() {
|
||||
const WeatherRxConfigureMessage message{};
|
||||
void set_subghzd_config(uint8_t modulation = 0, uint32_t sampling_rate = 0) {
|
||||
const SubGhzFPRxConfigureMessage message{modulation, sampling_rate};
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ void set_spectrum(const size_t sampling_rate, const size_t trigger);
|
||||
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_config(uint8_t modulation, uint32_t sampling_rate);
|
||||
void request_beep();
|
||||
|
||||
void run_image(const portapack::spi_flash::image_tag_t image_tag);
|
||||
|
||||
@@ -113,6 +113,7 @@ void EventDispatcher::run() {
|
||||
while (is_running) {
|
||||
const auto events = wait();
|
||||
dispatch(events);
|
||||
portapack::usb_serial.dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,10 @@ set(EXTCPPSRC
|
||||
external/lcr/main.cpp
|
||||
external/lcr/ui_lcr.cpp
|
||||
|
||||
|
||||
#lcr
|
||||
external/jammer/main.cpp
|
||||
external/jammer/ui_jammer.cpp
|
||||
)
|
||||
|
||||
set(EXTAPPLIST
|
||||
@@ -53,4 +57,5 @@ set(EXTAPPLIST
|
||||
coasterp
|
||||
lge
|
||||
lcr
|
||||
jammer
|
||||
)
|
||||
|
||||
+9
@@ -27,6 +27,7 @@ MEMORY
|
||||
ram_external_app_coasterp(rwx) : org = 0xEEF00000, len = 32k
|
||||
ram_external_app_lge(rwx) : org = 0xEEF10000, len = 32k
|
||||
ram_external_app_lcr(rwx) : org = 0xEEF20000, len = 32k
|
||||
ram_external_app_jammer(rwx) : org = 0xEEF30000, len = 32k
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -93,4 +94,12 @@ SECTIONS
|
||||
*(*ui*external_app*lcr*);
|
||||
} > ram_external_app_lcr
|
||||
|
||||
|
||||
.external_app_jammer : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_jammer.application_information));
|
||||
*(*ui*external_app*jammer*);
|
||||
} > ram_external_app_jammer
|
||||
|
||||
|
||||
}
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* 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.hpp"
|
||||
#include "ui_jammer.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::jammer {
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<JammerView>();
|
||||
}
|
||||
} // namespace ui::external_app::jammer
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_jammer.application_information"), used)) application_information_t _application_information_jammer = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::jammer::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "Jammer",
|
||||
/*.bitmap_data = */ {
|
||||
0xE0,
|
||||
0x07,
|
||||
0xF8,
|
||||
0x1F,
|
||||
0x1C,
|
||||
0x38,
|
||||
0x0E,
|
||||
0x78,
|
||||
0x06,
|
||||
0x7C,
|
||||
0x03,
|
||||
0xCE,
|
||||
0x03,
|
||||
0xC7,
|
||||
0x83,
|
||||
0xC3,
|
||||
0xC3,
|
||||
0xC1,
|
||||
0xE3,
|
||||
0xC0,
|
||||
0x73,
|
||||
0xC0,
|
||||
0x3E,
|
||||
0x60,
|
||||
0x1E,
|
||||
0x70,
|
||||
0x1C,
|
||||
0x38,
|
||||
0xF8,
|
||||
0x1F,
|
||||
0xE0,
|
||||
0x07,
|
||||
},
|
||||
/*.icon_color = */ ui::Color::green().v,
|
||||
/*.menu_location = */ app_location_t::TX,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_jammer */ {'P', 'J', 'A', 'M'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
||||
Vendored
+4
-3
@@ -29,7 +29,7 @@
|
||||
|
||||
using namespace portapack;
|
||||
|
||||
namespace ui {
|
||||
namespace ui::external_app::jammer {
|
||||
|
||||
void RangeView::focus() {
|
||||
check_enabled.focus();
|
||||
@@ -331,7 +331,8 @@ JammerView::JammerView(
|
||||
NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
Rect view_rect = {0, 3 * 8, 240, 80};
|
||||
baseband::run_image(portapack::spi_flash::image_tag_jammer);
|
||||
// baseband::run_image(portapack::spi_flash::image_tag_jammer);
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
|
||||
|
||||
add_children({&tab_view,
|
||||
&view_range_a,
|
||||
@@ -372,4 +373,4 @@ JammerView::JammerView(
|
||||
};
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
} // namespace ui::external_app::jammer
|
||||
Vendored
+2
-2
@@ -33,7 +33,7 @@
|
||||
|
||||
using namespace jammer;
|
||||
|
||||
namespace ui {
|
||||
namespace ui::external_app::jammer {
|
||||
|
||||
class RangeView : public View {
|
||||
public:
|
||||
@@ -242,4 +242,4 @@ class JammerView : public View {
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
} // namespace ui::external_app::jammer
|
||||
@@ -285,7 +285,7 @@
|
||||
* buffers.
|
||||
*/
|
||||
#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
|
||||
#define SERIAL_BUFFERS_SIZE 16
|
||||
#define SERIAL_BUFFERS_SIZE 64
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
|
||||
@@ -122,6 +122,8 @@ static bool touch_update() {
|
||||
}
|
||||
|
||||
static uint8_t switches_raw = 0;
|
||||
static uint8_t injected_switch = 0;
|
||||
static uint8_t injected_encoder = 0;
|
||||
|
||||
/* The raw data is not packed in a way that makes looping over it easy.
|
||||
* One option would be an accessor helper (RawSwitch). Another option
|
||||
@@ -170,8 +172,11 @@ static bool encoder_update(const uint8_t raw) {
|
||||
|
||||
static bool encoder_read() {
|
||||
const auto delta = encoder.update(
|
||||
encoder_debounce[0].state(),
|
||||
encoder_debounce[1].state());
|
||||
encoder_debounce[0].state() | (injected_encoder == 1),
|
||||
encoder_debounce[1].state() | (injected_encoder == 2));
|
||||
|
||||
if (injected_encoder > 0)
|
||||
injected_encoder = 0;
|
||||
|
||||
if (delta != 0) {
|
||||
encoder_position += delta;
|
||||
@@ -186,10 +191,10 @@ void timer0_callback(GPTDriver* const) {
|
||||
if (touch_update()) event_mask |= EVT_MASK_TOUCH;
|
||||
|
||||
switches_raw = swizzled_switches();
|
||||
if (switches_update(switches_raw))
|
||||
if (switches_update(switches_raw) || (injected_switch > 0))
|
||||
event_mask |= EVT_MASK_SWITCHES;
|
||||
|
||||
if (encoder_update(switches_raw) && encoder_read())
|
||||
if (encoder_update(switches_raw) || encoder_read())
|
||||
event_mask |= EVT_MASK_ENCODER;
|
||||
|
||||
/* Signal event loop */
|
||||
@@ -238,6 +243,13 @@ SwitchesState get_switches_state() {
|
||||
for (size_t i = 0; i < result.size(); i++)
|
||||
result[i] = switch_debounce[i].state();
|
||||
|
||||
if (injected_switch > 0 && injected_switch <= 6) {
|
||||
result[injected_switch - 1] = 1;
|
||||
injected_switch = 0xff;
|
||||
} else if (injected_switch == 0xff) {
|
||||
injected_switch = 0x00;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -277,5 +289,12 @@ uint8_t switches() {
|
||||
return switches_raw;
|
||||
}
|
||||
|
||||
void inject_switch(uint8_t button) {
|
||||
if (button <= 6)
|
||||
injected_switch = button;
|
||||
else if (button > 6)
|
||||
injected_encoder = button - 6;
|
||||
}
|
||||
|
||||
} // namespace debug
|
||||
} // namespace control
|
||||
|
||||
@@ -56,6 +56,7 @@ namespace control {
|
||||
namespace debug {
|
||||
|
||||
uint8_t switches();
|
||||
void inject_switch(uint8_t);
|
||||
|
||||
} // namespace debug
|
||||
} // namespace control
|
||||
|
||||
@@ -70,6 +70,7 @@ lcd::ILI9341 display;
|
||||
|
||||
I2C i2c0(&I2CD0);
|
||||
SPI ssp1(&SPID2);
|
||||
portapack::USBSerial usb_serial;
|
||||
|
||||
si5351::Si5351 clock_generator{
|
||||
i2c0, hackrf::one::si5351_i2c_address};
|
||||
@@ -368,7 +369,7 @@ static void shutdown_base() {
|
||||
*
|
||||
* XTAL_OSC = powered down
|
||||
*
|
||||
* PLL0USB = powered down
|
||||
* PLL0USB = XTAL, 480 MHz
|
||||
* PLL0AUDIO = GP_CLKIN, Fcco=491.52 MHz, Fout=12.288 MHz
|
||||
* PLL1 =
|
||||
* OG: GP_CLKIN * 10 = 200 MHz
|
||||
@@ -464,6 +465,8 @@ bool init() {
|
||||
/* Remove /2P divider from PLL1 output to achieve full speed */
|
||||
cgu::pll1::direct();
|
||||
|
||||
usb_serial.initialize();
|
||||
|
||||
i2c0.start(i2c_config_fast_clock);
|
||||
chThdSleepMilliseconds(10);
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "si5351.hpp"
|
||||
#include "lcd_ili9341.hpp"
|
||||
#include "backlight.hpp"
|
||||
#include "usb_serial.hpp"
|
||||
|
||||
#include "radio.hpp"
|
||||
#include "clock_manager.hpp"
|
||||
@@ -46,6 +47,7 @@ extern lcd::ILI9341 display;
|
||||
|
||||
extern I2C i2c0;
|
||||
extern SPI ssp1;
|
||||
extern portapack::USBSerial usb_serial;
|
||||
|
||||
extern si5351::Si5351 clock_generator;
|
||||
extern ClockManager clock_manager;
|
||||
|
||||
@@ -47,9 +47,9 @@
|
||||
#include "ui_freqman.hpp"
|
||||
#include "ui_fsk_rx.hpp"
|
||||
#include "ui_iq_trim.hpp"
|
||||
#include "ui_jammer.hpp"
|
||||
// #include "ui_keyfob.hpp"
|
||||
// #include "ui_lcr.hpp"
|
||||
// #include "ui_jammer.hpp" //moved to ext
|
||||
// #include "ui_keyfob.hpp"
|
||||
// #include "ui_lcr.hpp"
|
||||
#include "ui_level.hpp"
|
||||
#include "ui_looking_glass_app.hpp"
|
||||
#include "ui_mictx.hpp"
|
||||
@@ -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>(); }},
|
||||
@@ -593,7 +595,7 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
|
||||
{"BLE Tx", ui::Color::green(), &bitmap_icon_btle, [&nav]() { nav.push<BLETxView>(); }},
|
||||
// {"BurgerPgr", ui::Color::yellow(), &bitmap_icon_burger, [&nav]() { nav.push<CoasterPagerView>(); }}, //moved to ext
|
||||
{"GPS Sim", ui::Color::green(), &bitmap_icon_gps_sim, [&nav]() { nav.push<GpsSimAppView>(); }},
|
||||
{"Jammer", ui::Color::green(), &bitmap_icon_jammer, [&nav]() { nav.push<JammerView>(); }},
|
||||
//{"Jammer", ui::Color::green(), &bitmap_icon_jammer, [&nav]() { nav.push<JammerView>(); }}, //moved to ext
|
||||
// { "Key fob", ui::Color::orange(), &bitmap_icon_keyfob, [&nav](){ nav.push<KeyfobView>(); }},
|
||||
// {"LGE", ui::Color::yellow(), &bitmap_icon_lge, [&nav]() { nav.push<LGEView>(); }}, //moved to ext
|
||||
{"Morse", ui::Color::green(), &bitmap_icon_morse, [&nav]() { nav.push<MorseView>(); }},
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
extern "C" {
|
||||
#include "usb_serial_io.h"
|
||||
#include "usb_serial_cdc.h"
|
||||
}
|
||||
|
||||
#include "usb_serial_shell.hpp"
|
||||
#include "usb_serial.hpp"
|
||||
#include "portapack.hpp"
|
||||
|
||||
#include <libopencm3/cm3/common.h>
|
||||
#include <libopencm3/lpc43xx/usb.h>
|
||||
|
||||
namespace portapack {
|
||||
|
||||
void USBSerial::initialize() {
|
||||
enable_xtal();
|
||||
disable_pll0();
|
||||
|
||||
setup_pll0();
|
||||
enable_pll0();
|
||||
|
||||
setup_usb_clock();
|
||||
setup_usb_serial_controller();
|
||||
|
||||
init_serial_usb_driver(&SUSBD1);
|
||||
shellInit();
|
||||
}
|
||||
|
||||
void USBSerial::dispatch() {
|
||||
if (!connected)
|
||||
return;
|
||||
|
||||
if (shell_created == false) {
|
||||
shell_created = true;
|
||||
create_shell();
|
||||
}
|
||||
|
||||
bulk_out_receive();
|
||||
}
|
||||
|
||||
void USBSerial::on_channel_opened() {
|
||||
connected = true;
|
||||
}
|
||||
|
||||
void USBSerial::on_channel_closed() {
|
||||
connected = false;
|
||||
}
|
||||
|
||||
void USBSerial::enable_xtal() {
|
||||
LPC_CGU->XTAL_OSC_CTRL.ENABLE = 0;
|
||||
LPC_CGU->XTAL_OSC_CTRL.HF = 0;
|
||||
}
|
||||
|
||||
void USBSerial::disable_pll0() {
|
||||
LPC_CGU->PLL0USB_CTRL.PD = 1;
|
||||
LPC_CGU->PLL0USB_CTRL.AUTOBLOCK = 1;
|
||||
|
||||
LPC_CGU->PLL0USB_CTRL.BYPASS = 0;
|
||||
LPC_CGU->PLL0USB_CTRL.DIRECTI = 0;
|
||||
LPC_CGU->PLL0USB_CTRL.DIRECTO = 0;
|
||||
LPC_CGU->PLL0USB_CTRL.CLKEN = 0;
|
||||
LPC_CGU->PLL0USB_CTRL.FRM = 0;
|
||||
LPC_CGU->PLL0USB_CTRL.CLK_SEL = 0x06; // 12MHz internal XTAL
|
||||
}
|
||||
|
||||
void USBSerial::setup_pll0() {
|
||||
/* use XTAL_OSC as clock source for PLL0USB */
|
||||
|
||||
while (LPC_CGU->PLL0USB_STAT.LOCK) {
|
||||
}
|
||||
|
||||
// /* configure PLL0USB to produce 480 MHz clock from 12 MHz XTAL_OSC */
|
||||
// /* Values from User Manual v1.4 Table 94, for 12MHz oscillator. */
|
||||
LPC_CGU->PLL0USB_MDIV = 0x06167FFA;
|
||||
LPC_CGU->PLL0USB_NP_DIV = 0x00302062;
|
||||
LPC_CGU->PLL0USB_CTRL.PD = 1;
|
||||
LPC_CGU->PLL0USB_CTRL.DIRECTI = 1;
|
||||
LPC_CGU->PLL0USB_CTRL.DIRECTO = 1;
|
||||
LPC_CGU->PLL0USB_CTRL.CLKEN = 1;
|
||||
}
|
||||
|
||||
void USBSerial::enable_pll0() {
|
||||
// /* power on PLL0USB and wait until stable */
|
||||
LPC_CGU->PLL0USB_CTRL.PD = 0;
|
||||
|
||||
while (!LPC_CGU->PLL0USB_STAT.LOCK) {
|
||||
}
|
||||
}
|
||||
|
||||
void USBSerial::setup_usb_clock() {
|
||||
/* use PLL0USB as clock source for USB0 */
|
||||
LPC_CGU->BASE_USB0_CLK.AUTOBLOCK = 1;
|
||||
LPC_CGU->BASE_USB0_CLK.CLK_SEL = 0x07;
|
||||
LPC_CGU->BASE_USB0_CLK.PD = 0;
|
||||
}
|
||||
|
||||
} // namespace portapack
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
namespace portapack {
|
||||
|
||||
class USBSerial {
|
||||
public:
|
||||
void initialize();
|
||||
void dispatch();
|
||||
void on_channel_opened();
|
||||
void on_channel_closed();
|
||||
|
||||
private:
|
||||
void enable_xtal();
|
||||
void disable_pll0();
|
||||
void setup_pll0();
|
||||
void enable_pll0();
|
||||
|
||||
void setup_usb_clock();
|
||||
|
||||
bool connected{false};
|
||||
bool shell_created{false};
|
||||
};
|
||||
|
||||
} // namespace portapack
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* 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 "usb_serial_cdc.h"
|
||||
#include "usb_serial_endpoints.h"
|
||||
#include "usb_serial_event.hpp"
|
||||
|
||||
extern void usb0_isr(void);
|
||||
CH_IRQ_HANDLER(USB0_IRQHandler) {
|
||||
CH_IRQ_PROLOGUE();
|
||||
usb0_isr();
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
uint32_t __ldrex(volatile uint32_t* addr) {
|
||||
__disable_irq();
|
||||
return *addr;
|
||||
}
|
||||
|
||||
uint32_t __strex(uint32_t val, volatile uint32_t* addr) {
|
||||
(void)val;
|
||||
(void)addr;
|
||||
|
||||
*addr = val;
|
||||
__enable_irq();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nvic_enable_irq(uint8_t irqn) {
|
||||
NVIC_ISER(irqn / 32) = (1 << (irqn % 32));
|
||||
}
|
||||
|
||||
void usb_configuration_changed(usb_device_t* const device) {
|
||||
(void)device;
|
||||
|
||||
usb_endpoint_init(&usb_endpoint_int_in);
|
||||
usb_endpoint_init(&usb_endpoint_bulk_in);
|
||||
usb_endpoint_init(&usb_endpoint_bulk_out);
|
||||
}
|
||||
|
||||
void setup_usb_serial_controller(void) {
|
||||
usb_set_configuration_changed_cb(usb_configuration_changed);
|
||||
usb_peripheral_reset();
|
||||
|
||||
usb_device_init(0, &usb_device);
|
||||
|
||||
usb_queue_init(&usb_endpoint_control_out_queue);
|
||||
usb_queue_init(&usb_endpoint_control_in_queue);
|
||||
usb_queue_init(&usb_endpoint_int_in_queue);
|
||||
usb_queue_init(&usb_endpoint_bulk_out_queue);
|
||||
usb_queue_init(&usb_endpoint_bulk_in_queue);
|
||||
|
||||
usb_endpoint_init(&usb_endpoint_control_out);
|
||||
usb_endpoint_init(&usb_endpoint_control_in);
|
||||
|
||||
usb_run(&usb_device);
|
||||
}
|
||||
|
||||
const usb_request_handlers_t usb_request_handlers = {
|
||||
.standard = usb_standard_request,
|
||||
.class = usb_class_request,
|
||||
.vendor = 0,
|
||||
.reserved = 0};
|
||||
|
||||
usb_request_status_t usb_class_request(usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) {
|
||||
usb_request_status_t status = USB_REQUEST_STATUS_STALL;
|
||||
|
||||
volatile uint8_t request = endpoint->setup.request;
|
||||
|
||||
if (request == 0x21) // GET LINE CODING REQUEST
|
||||
return usb_get_line_coding_request(endpoint, stage);
|
||||
|
||||
if (request == 0x22) // SET CONTROL LINE STATE REQUEST
|
||||
return usb_set_control_line_state_request(endpoint, stage);
|
||||
|
||||
if (request == 0x20) // SET LINE CODING REQUEST
|
||||
return usb_set_line_coding_request(endpoint, stage);
|
||||
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_get_line_coding_request(usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
usb_transfer_schedule_block(
|
||||
endpoint->in,
|
||||
&endpoint->buffer,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
} else if (stage == USB_TRANSFER_STAGE_DATA) {
|
||||
usb_transfer_schedule_ack(endpoint->out);
|
||||
}
|
||||
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
usb_request_status_t usb_set_control_line_state_request(usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
// if (endpoint->setup.value == 3) {
|
||||
on_channel_opened();
|
||||
//} else {
|
||||
// on_channel_closed();
|
||||
//}
|
||||
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_set_line_coding_request(usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) {
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
usb_transfer_schedule_block(
|
||||
endpoint->out,
|
||||
&endpoint->buffer,
|
||||
32,
|
||||
NULL,
|
||||
NULL);
|
||||
} else if (stage == USB_TRANSFER_STAGE_DATA) {
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#ifndef __cplusplus
|
||||
#pragma GCC diagnostic push
|
||||
// external code, so ignore warnings
|
||||
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
||||
|
||||
#include <common/usb.h>
|
||||
#include <common/usb_request.h>
|
||||
#include <common/usb_standard_request.h>
|
||||
#include <hackrf_usb/usb_device.h>
|
||||
#include <hackrf_usb/usb_endpoint.h>
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
usb_request_status_t usb_class_request(usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
||||
usb_request_status_t usb_get_line_coding_request(usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
||||
usb_request_status_t usb_set_control_line_state_request(usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
||||
usb_request_status_t usb_set_line_coding_request(usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
||||
#endif
|
||||
|
||||
void setup_usb_serial_controller(void);
|
||||
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* 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 "usb_serial_descriptor.h"
|
||||
|
||||
#include "usb_serial_endpoints.h"
|
||||
|
||||
#define USB_VENDOR_ID (0x1D50)
|
||||
#define USB_PRODUCT_ID (0x6018)
|
||||
#define USB_API_VERSION (0x0100)
|
||||
|
||||
#define USB_WORD(x) (x & 0xFF), ((x >> 8) & 0xFF)
|
||||
#define USB_MAX_PACKET0 (64)
|
||||
#define USB_MAX_PACKET_BULK_FS (64)
|
||||
#define USB_MAX_PACKET_BULK_HS (64)
|
||||
#define USB_STRING_LANGID (0x0409)
|
||||
|
||||
uint8_t usb_descriptor_device[] = {
|
||||
18, // bLength
|
||||
USB_DESCRIPTOR_TYPE_DEVICE, // bDescriptorType
|
||||
USB_WORD(0x0200), // bcdUSB
|
||||
0xef, // bDeviceClass
|
||||
0x02, // bDeviceSubClass
|
||||
0x01, // bDeviceProtocol
|
||||
USB_MAX_PACKET0, // bMaxPacketSize0
|
||||
USB_WORD(USB_VENDOR_ID), // idVendor
|
||||
USB_WORD(USB_PRODUCT_ID), // idProduct
|
||||
USB_WORD(USB_API_VERSION), // bcdDevice
|
||||
0x01, // iManufacturer
|
||||
0x02, // iProduct
|
||||
0x03, // iSerialNumber
|
||||
0x01 // bNumConfigurations
|
||||
};
|
||||
|
||||
uint8_t usb_descriptor_device_qualifier[] = {
|
||||
10, // bLength
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, // bDescriptorType
|
||||
USB_WORD(0x0200), // bcdUSB
|
||||
0xef, // bDeviceClass
|
||||
0x02, // bDeviceSubClass
|
||||
0x01, // bDeviceProtocol
|
||||
USB_MAX_PACKET0, // bMaxPacketSize0
|
||||
0x01, // bNumOtherSpeedConfigurations
|
||||
0x00 // bReserved
|
||||
};
|
||||
|
||||
uint8_t usb_descriptor_configuration_full_speed[] = {
|
||||
9, // bLength
|
||||
USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType
|
||||
USB_WORD((16 + 8 + 9 + 5 + 5 + 4 + 5 + 9 + 7 + 7)), // wTotalLength
|
||||
0x02, // bNumInterfaces
|
||||
0x01, // bConfigurationValue
|
||||
0x00, // iConfiguration
|
||||
0x80, // bmAttributes: USB-powered
|
||||
250, // bMaxPower: 500mA
|
||||
|
||||
8, // bLength
|
||||
0xb, // bDescriptorType
|
||||
0,
|
||||
2,
|
||||
0x02,
|
||||
0x02,
|
||||
0x00,
|
||||
4,
|
||||
|
||||
9, // bLength
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType
|
||||
0x00, // bInterfaceNumber
|
||||
0x00, // bAlternateSetting
|
||||
0x01, // bNumEndpoints
|
||||
0x02, // bInterfaceClass: vendor-specific
|
||||
0x02, // bInterfaceSubClass
|
||||
0x00, // bInterfaceProtocol: vendor-specific
|
||||
0x04, // iInterface
|
||||
|
||||
5,
|
||||
0x24, // ACM
|
||||
0x00,
|
||||
USB_WORD(0x0110),
|
||||
|
||||
5,
|
||||
0x24,
|
||||
0x01,
|
||||
0x00,
|
||||
0x01,
|
||||
|
||||
4,
|
||||
0x24,
|
||||
0x02,
|
||||
0x02,
|
||||
|
||||
5,
|
||||
0x24,
|
||||
0x06,
|
||||
0x00,
|
||||
0x01,
|
||||
|
||||
7, // bLength
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType
|
||||
USB_INT_IN_EP_ADDR, // bEndpointAddress
|
||||
0x03, // bmAttributes: BULK
|
||||
USB_WORD(16), // wMaxPacketSize
|
||||
0xFF, // bInterval: no NAK
|
||||
|
||||
9, // bLength
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType
|
||||
0x01, // bInterfaceNumber
|
||||
0x00, // bAlternateSetting
|
||||
0x02, // bNumEndpoints
|
||||
0x0a, // bInterfaceClass: vendor-specific
|
||||
0x00, // bInterfaceSubClass
|
||||
0x00, // bInterfaceProtocol: vendor-specific
|
||||
0x00, // iInterface
|
||||
|
||||
7, // bLength
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType
|
||||
USB_BULK_OUT_EP_ADDR, // bEndpointAddress
|
||||
0x02, // bmAttributes: BULK
|
||||
USB_WORD(USB_MAX_PACKET_BULK_FS), // wMaxPacketSize
|
||||
0x01, // bInterval: no NAK
|
||||
|
||||
7, // bLength
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType
|
||||
USB_BULK_IN_EP_ADDR, // bEndpointAddress
|
||||
0x02, // bmAttributes: BULK
|
||||
USB_WORD(USB_MAX_PACKET_BULK_FS), // wMaxPacketSize
|
||||
0x01, // bInterval: NAK
|
||||
|
||||
0, // TERMINATOR
|
||||
};
|
||||
|
||||
uint8_t usb_descriptor_configuration_high_speed[] = {
|
||||
9, // bLength
|
||||
USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType
|
||||
USB_WORD((16 + 8 + 9 + 5 + 5 + 4 + 5 + 9 + 7 + 7)), // wTotalLength
|
||||
0x02, // bNumInterfaces
|
||||
0x01, // bConfigurationValue
|
||||
0x00, // iConfiguration
|
||||
0x80, // bmAttributes: USB-powered
|
||||
250, // bMaxPower: 500mA
|
||||
|
||||
8, // bLength
|
||||
0xb, // bDescriptorType
|
||||
0,
|
||||
2,
|
||||
0x02,
|
||||
0x02,
|
||||
0x00,
|
||||
4,
|
||||
|
||||
9, // bLength
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType
|
||||
0x00, // bInterfaceNumber
|
||||
0x00, // bAlternateSetting
|
||||
0x01, // bNumEndpoints
|
||||
0x02, // bInterfaceClass: vendor-specific
|
||||
0x02, // bInterfaceSubClass
|
||||
0x00, // bInterfaceProtocol: vendor-specific
|
||||
0x04, // iInterface
|
||||
|
||||
5,
|
||||
0x24,
|
||||
0x00,
|
||||
USB_WORD(0x0110),
|
||||
|
||||
5,
|
||||
0x24,
|
||||
0x01,
|
||||
0x00,
|
||||
0x01,
|
||||
|
||||
4,
|
||||
0x24,
|
||||
0x02,
|
||||
0x02,
|
||||
|
||||
5,
|
||||
0x24,
|
||||
0x06,
|
||||
0x00,
|
||||
0x01,
|
||||
|
||||
7, // bLength
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType
|
||||
USB_INT_IN_EP_ADDR, // bEndpointAddress
|
||||
0x03, // bmAttributes: BULK
|
||||
USB_WORD(16), // wMaxPacketSize
|
||||
0xFF, // bInterval: no NAK
|
||||
|
||||
9, // bLength
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType
|
||||
0x01, // bInterfaceNumber
|
||||
0x00, // bAlternateSetting
|
||||
0x02, // bNumEndpoints
|
||||
0x0a, // bInterfaceClass: vendor-specific
|
||||
0x00, // bInterfaceSubClass
|
||||
0x00, // bInterfaceProtocol: vendor-specific
|
||||
0x00, // iInterface
|
||||
|
||||
7, // bLength
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType
|
||||
USB_BULK_OUT_EP_ADDR, // bEndpointAddress
|
||||
0x02, // bmAttributes: BULK
|
||||
USB_WORD(USB_MAX_PACKET_BULK_HS), // wMaxPacketSize
|
||||
0x01, // bInterval: no NAK
|
||||
|
||||
7, // bLength
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType
|
||||
USB_BULK_IN_EP_ADDR, // bEndpointAddress
|
||||
0x02, // bmAttributes: BULK
|
||||
USB_WORD(USB_MAX_PACKET_BULK_HS), // wMaxPacketSize
|
||||
0x01, // bInterval: NAK
|
||||
|
||||
0, // TERMINATOR
|
||||
};
|
||||
|
||||
uint8_t usb_descriptor_string_languages[] = {
|
||||
0x04, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
USB_WORD(USB_STRING_LANGID), // wLANGID
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
uint8_t usb_descriptor_string_manufacturer[] = {
|
||||
40, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'G', 0x00,
|
||||
'r', 0x00,
|
||||
'e', 0x00,
|
||||
'a', 0x00,
|
||||
't', 0x00,
|
||||
' ', 0x00,
|
||||
'S', 0x00,
|
||||
'c', 0x00,
|
||||
'o', 0x00,
|
||||
't', 0x00,
|
||||
't', 0x00,
|
||||
' ', 0x00,
|
||||
'G', 0x00,
|
||||
'a', 0x00,
|
||||
'd', 0x00,
|
||||
'g', 0x00,
|
||||
'e', 0x00,
|
||||
't', 0x00,
|
||||
's', 0x00,
|
||||
};
|
||||
|
||||
uint8_t usb_descriptor_string_product[] = {
|
||||
43, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'P', 0x00,
|
||||
'o', 0x00,
|
||||
'r', 0x00,
|
||||
't', 0x00,
|
||||
'a', 0x00,
|
||||
'P', 0x00,
|
||||
'a', 0x00,
|
||||
'c', 0x00,
|
||||
'k', 0x00,
|
||||
' ', 0x00,
|
||||
'M', 0x00,
|
||||
'a', 0x00,
|
||||
'y', 0x00,
|
||||
'h', 0x00,
|
||||
'e', 0x00,
|
||||
'm', 0x00,
|
||||
};
|
||||
|
||||
uint8_t usb_descriptor_string_config_description[] = {
|
||||
24, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'T', 0x00,
|
||||
'r', 0x00,
|
||||
'a', 0x00,
|
||||
'n', 0x00,
|
||||
's', 0x00,
|
||||
'c', 0x00,
|
||||
'e', 0x00,
|
||||
'i', 0x00,
|
||||
'v', 0x00,
|
||||
'e', 0x00,
|
||||
'r', 0x00,
|
||||
};
|
||||
|
||||
uint8_t usb_descriptor_string_serial_number[USB_DESCRIPTOR_STRING_SERIAL_BUF_LEN];
|
||||
|
||||
uint8_t* usb_descriptor_strings[] = {
|
||||
usb_descriptor_string_languages,
|
||||
usb_descriptor_string_manufacturer,
|
||||
usb_descriptor_string_product,
|
||||
usb_descriptor_string_config_description,
|
||||
usb_descriptor_string_serial_number,
|
||||
0, // TERMINATOR
|
||||
};
|
||||
|
||||
uint8_t wcid_string_descriptor[] = {
|
||||
18, // bLength
|
||||
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||
'M', 0x00,
|
||||
'S', 0x00,
|
||||
'F', 0x00,
|
||||
'T', 0x00,
|
||||
'1', 0x00,
|
||||
'0', 0x00,
|
||||
'0', 0x00,
|
||||
USB_WCID_VENDOR_REQ, // vendor request code for further descriptor
|
||||
0x00
|
||||
};
|
||||
|
||||
uint8_t wcid_feature_descriptor[] = {
|
||||
0x28, 0x00, 0x00, 0x00, // bLength
|
||||
USB_WORD(0x0100), // WCID version
|
||||
USB_WORD(0x0004), // WICD descriptor index
|
||||
0x01, // bNumSections
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Reserved
|
||||
0x00, // bInterfaceNumber
|
||||
0x01, // Reserved
|
||||
'W', 'I', 'N', 'U', 'S', 'B', 0x00,0x00, // Compatible ID, padded with zeros
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Sub-compatible ID
|
||||
0x00,0x00,0x00,0x00,0x00,0x00 // Reserved
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
extern uint8_t usb_descriptor_device[];
|
||||
extern uint8_t usb_descriptor_device_qualifier[];
|
||||
extern uint8_t usb_descriptor_configuration_full_speed[];
|
||||
extern uint8_t usb_descriptor_configuration_high_speed[];
|
||||
extern uint8_t usb_descriptor_string_languages[];
|
||||
extern uint8_t usb_descriptor_string_manufacturer[];
|
||||
extern uint8_t usb_descriptor_string_product[];
|
||||
|
||||
#define USB_DESCRIPTOR_STRING_SERIAL_LEN 32
|
||||
#define USB_DESCRIPTOR_STRING_SERIAL_BUF_LEN \
|
||||
(USB_DESCRIPTOR_STRING_SERIAL_LEN * 2 + 2) /* UTF-16LE */
|
||||
extern uint8_t usb_descriptor_string_serial_number[];
|
||||
|
||||
extern uint8_t* usb_descriptor_strings[];
|
||||
|
||||
#define USB_WCID_VENDOR_REQ 0x19
|
||||
extern uint8_t wcid_string_descriptor[];
|
||||
extern uint8_t wcid_feature_descriptor[];
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* 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 "usb_serial_endpoints.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
// external code, so ignore warnings
|
||||
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
||||
|
||||
#include <common/usb.h>
|
||||
#include <common/usb_request.h>
|
||||
#include <common/usb_standard_request.h>
|
||||
#include <hackrf_usb/usb_device.h>
|
||||
#include <hackrf_usb/usb_endpoint.h>
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
usb_endpoint_t usb_endpoint_control_out = {
|
||||
.address = USB_CONTROL_OUT_EP_ADDR,
|
||||
.device = &usb_device,
|
||||
.in = &usb_endpoint_control_in,
|
||||
.out = &usb_endpoint_control_out,
|
||||
.setup_complete = usb_setup_complete,
|
||||
.transfer_complete = usb_control_out_complete,
|
||||
};
|
||||
USB_DEFINE_QUEUE(usb_endpoint_control_out, 4);
|
||||
|
||||
usb_endpoint_t usb_endpoint_control_in = {
|
||||
.address = USB_CONTROL_IN_EP_ADDR,
|
||||
.device = &usb_device,
|
||||
.in = &usb_endpoint_control_in,
|
||||
.out = &usb_endpoint_control_out,
|
||||
.setup_complete = 0,
|
||||
.transfer_complete = usb_control_in_complete,
|
||||
};
|
||||
static USB_DEFINE_QUEUE(usb_endpoint_control_in, 4);
|
||||
|
||||
usb_endpoint_t usb_endpoint_int_in = {
|
||||
.address = USB_INT_IN_EP_ADDR,
|
||||
.device = &usb_device,
|
||||
.in = &usb_endpoint_int_in,
|
||||
.out = 0,
|
||||
.setup_complete = 0,
|
||||
.transfer_complete = usb_queue_transfer_complete};
|
||||
static USB_DEFINE_QUEUE(usb_endpoint_int_in, 1);
|
||||
|
||||
usb_endpoint_t usb_endpoint_bulk_in = {
|
||||
.address = USB_BULK_IN_EP_ADDR,
|
||||
.device = &usb_device,
|
||||
.in = &usb_endpoint_bulk_in,
|
||||
.out = 0,
|
||||
.setup_complete = 0,
|
||||
.transfer_complete = usb_queue_transfer_complete};
|
||||
static USB_DEFINE_QUEUE(usb_endpoint_bulk_in, 1);
|
||||
|
||||
usb_endpoint_t usb_endpoint_bulk_out = {
|
||||
.address = USB_BULK_OUT_EP_ADDR,
|
||||
.device = &usb_device,
|
||||
.in = 0,
|
||||
.out = &usb_endpoint_bulk_out,
|
||||
.setup_complete = 0,
|
||||
.transfer_complete = usb_queue_transfer_complete};
|
||||
static USB_DEFINE_QUEUE(usb_endpoint_bulk_out, 1);
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#include <usb_type.h>
|
||||
#include <usb_queue.h>
|
||||
|
||||
#define USB_CONTROL_IN_EP_ADDR (0x80)
|
||||
#define USB_CONTROL_OUT_EP_ADDR (0x00)
|
||||
|
||||
#define USB_INT_IN_EP_ADDR (0x82)
|
||||
|
||||
#define USB_BULK_OUT_EP_ADDR (0x01)
|
||||
#define USB_BULK_IN_EP_ADDR (0x81)
|
||||
|
||||
extern usb_endpoint_t usb_endpoint_control_out;
|
||||
extern USB_DECLARE_QUEUE(usb_endpoint_control_out);
|
||||
|
||||
extern usb_endpoint_t usb_endpoint_control_in;
|
||||
extern USB_DECLARE_QUEUE(usb_endpoint_control_in);
|
||||
|
||||
extern usb_endpoint_t usb_endpoint_int_in;
|
||||
extern USB_DECLARE_QUEUE(usb_endpoint_int_in);
|
||||
|
||||
extern usb_endpoint_t usb_endpoint_bulk_in;
|
||||
extern USB_DECLARE_QUEUE(usb_endpoint_bulk_in);
|
||||
|
||||
extern usb_endpoint_t usb_endpoint_bulk_out;
|
||||
extern USB_DECLARE_QUEUE(usb_endpoint_bulk_out);
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* 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 "usb_serial_event.hpp"
|
||||
|
||||
#include "portapack.hpp"
|
||||
|
||||
extern "C" {
|
||||
void on_channel_opened() {
|
||||
portapack::usb_serial.on_channel_opened();
|
||||
}
|
||||
|
||||
void on_channel_closed() {
|
||||
portapack::usb_serial.on_channel_closed();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void on_channel_opened(void);
|
||||
void on_channel_closed(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* 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 "usb_serial_io.h"
|
||||
|
||||
#include "usb_serial_endpoints.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
// external code, so ignore warnings
|
||||
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
||||
|
||||
#include <common/usb.h>
|
||||
#include <common/usb_request.h>
|
||||
#include <common/usb_standard_request.h>
|
||||
#include <hackrf_usb/usb_device.h>
|
||||
#include <hackrf_usb/usb_endpoint.h>
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#include <usb_request.h>
|
||||
#include <string.h>
|
||||
|
||||
SerialUSBDriver SUSBD1;
|
||||
|
||||
void bulk_out_receive(void) {
|
||||
int ret;
|
||||
do {
|
||||
ret = usb_transfer_schedule(
|
||||
&usb_endpoint_bulk_out,
|
||||
&usb_endpoint_bulk_out.buffer[0],
|
||||
32,
|
||||
serial_bulk_transfer_complete,
|
||||
NULL);
|
||||
|
||||
} while (ret != -1);
|
||||
}
|
||||
|
||||
void serial_bulk_transfer_complete(void* user_data, unsigned int bytes_transferred) {
|
||||
(void)user_data;
|
||||
|
||||
chSysLockFromIsr();
|
||||
|
||||
for (unsigned int i = 0; i < bytes_transferred; i++) {
|
||||
msg_t ret;
|
||||
do {
|
||||
ret = chIQPutI(&SUSBD1.iqueue, usb_endpoint_bulk_out.buffer[i]);
|
||||
if (ret == Q_FULL)
|
||||
chThdSleepMilliseconds(1);
|
||||
|
||||
} while (ret == Q_FULL);
|
||||
}
|
||||
|
||||
chSysUnlockFromIsr();
|
||||
}
|
||||
|
||||
static void onotify(GenericQueue* qp) {
|
||||
SerialUSBDriver* sdp = chQGetLink(qp);
|
||||
uint8_t buff[64];
|
||||
int n = chOQGetFullI(&sdp->oqueue);
|
||||
if (n > 64) n = 64; // don't overflow
|
||||
if (n > 0) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
buff[i] = chOQGetI(&sdp->oqueue);
|
||||
}
|
||||
|
||||
int ret;
|
||||
chSysUnlock();
|
||||
do {
|
||||
ret = usb_transfer_schedule(
|
||||
&usb_endpoint_bulk_in,
|
||||
&buff[0],
|
||||
n,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (ret == -1)
|
||||
chThdSleepMilliseconds(1);
|
||||
|
||||
} while (ret == -1);
|
||||
chSysLock();
|
||||
}
|
||||
}
|
||||
|
||||
static size_t write(void* ip, const uint8_t* bp, size_t n) {
|
||||
return chOQWriteTimeout(&((SerialUSBDriver*)ip)->oqueue, bp,
|
||||
n, TIME_INFINITE);
|
||||
}
|
||||
|
||||
static size_t read(void* ip, uint8_t* bp, size_t n) {
|
||||
return chIQReadTimeout(&((SerialUSBDriver*)ip)->iqueue, bp,
|
||||
n, TIME_INFINITE);
|
||||
}
|
||||
|
||||
static msg_t put(void* ip, uint8_t b) {
|
||||
return chOQPutTimeout(&((SerialUSBDriver*)ip)->oqueue, b, TIME_INFINITE);
|
||||
}
|
||||
|
||||
static msg_t get(void* ip) {
|
||||
return chIQGetTimeout(&((SerialUSBDriver*)ip)->iqueue, TIME_INFINITE);
|
||||
}
|
||||
|
||||
static msg_t putt(void* ip, uint8_t b, systime_t timeout) {
|
||||
return chOQPutTimeout(&((SerialUSBDriver*)ip)->oqueue, b, timeout);
|
||||
}
|
||||
|
||||
static msg_t gett(void* ip, systime_t timeout) {
|
||||
return chIQGetTimeout(&((SerialUSBDriver*)ip)->iqueue, timeout);
|
||||
}
|
||||
|
||||
static size_t writet(void* ip, const uint8_t* bp, size_t n, systime_t time) {
|
||||
return chOQWriteTimeout(&((SerialUSBDriver*)ip)->oqueue, bp, n, time);
|
||||
}
|
||||
|
||||
static size_t readt(void* ip, uint8_t* bp, size_t n, systime_t time) {
|
||||
return chIQReadTimeout(&((SerialUSBDriver*)ip)->iqueue, bp, n, time);
|
||||
}
|
||||
|
||||
static const struct SerialUSBDriverVMT vmt = {
|
||||
write, read, put, get,
|
||||
putt, gett, writet, readt};
|
||||
|
||||
void init_serial_usb_driver(SerialUSBDriver* sdp) {
|
||||
sdp->vmt = &vmt;
|
||||
chIQInit(&sdp->iqueue, sdp->ib, SERIAL_BUFFERS_SIZE, NULL, sdp);
|
||||
chOQInit(&sdp->oqueue, sdp->ob, SERIAL_BUFFERS_SIZE, onotify, sdp);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
struct SerialUSBDriverVMT {
|
||||
_base_asynchronous_channel_methods
|
||||
};
|
||||
|
||||
struct SerialUSBDriver {
|
||||
/** @brief Virtual Methods Table.*/
|
||||
const struct SerialUSBDriverVMT* vmt;
|
||||
InputQueue iqueue; /* Output queue.*/
|
||||
OutputQueue oqueue; /* Input circular buffer.*/
|
||||
uint8_t ib[SERIAL_BUFFERS_SIZE]; /* Output circular buffer.*/
|
||||
uint8_t ob[SERIAL_BUFFERS_SIZE];
|
||||
};
|
||||
|
||||
typedef struct SerialUSBDriver SerialUSBDriver;
|
||||
|
||||
extern SerialUSBDriver SUSBD1;
|
||||
|
||||
void init_serial_usb_driver(SerialUSBDriver* sdp);
|
||||
void bulk_out_receive(void);
|
||||
void serial_bulk_transfer_complete(void* user_data, unsigned int bytes_transferred);
|
||||
@@ -0,0 +1,510 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* 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 "usb_serial_shell.hpp"
|
||||
#include "event_m0.hpp"
|
||||
#include "baseband_api.hpp"
|
||||
#include "core_control.hpp"
|
||||
#include "bitmap.hpp"
|
||||
#include "png_writer.hpp"
|
||||
#include "irq_controls.hpp"
|
||||
|
||||
#include "usb_serial_io.h"
|
||||
#include "ff.h"
|
||||
#include "chprintf.h"
|
||||
#include "chqueues.h"
|
||||
|
||||
#include <string>
|
||||
#include <codecvt>
|
||||
#include <cstring>
|
||||
#include <locale>
|
||||
|
||||
#define SHELL_WA_SIZE THD_WA_SIZE(1024 * 3)
|
||||
#define palOutputPad(port, pad) (LPC_GPIO->DIR[(port)] |= 1 << (pad))
|
||||
|
||||
// queue handler from ch
|
||||
static msg_t qwait(GenericQueue* qp, systime_t time) {
|
||||
if (TIME_IMMEDIATE == time)
|
||||
return Q_TIMEOUT;
|
||||
currp->p_u.wtobjp = qp;
|
||||
queue_insert(currp, &qp->q_waiting);
|
||||
return chSchGoSleepTimeoutS(THD_STATE_WTQUEUE, time);
|
||||
}
|
||||
|
||||
// This function fills the output buffer, and sends all data in 1 packet
|
||||
static size_t fillOBuffer(OutputQueue* oqp, const uint8_t* bp, size_t n) {
|
||||
qnotify_t nfy = oqp->q_notify;
|
||||
size_t w = 0;
|
||||
|
||||
chDbgCheck(n > 0, "chOQWriteTimeout");
|
||||
chSysLock();
|
||||
while (TRUE) {
|
||||
while (chOQIsFullI(oqp)) {
|
||||
if (qwait((GenericQueue*)oqp, TIME_INFINITE) != Q_OK) {
|
||||
chSysUnlock();
|
||||
return w;
|
||||
}
|
||||
}
|
||||
while (!chOQIsFullI(oqp) && n > 0) {
|
||||
oqp->q_counter--;
|
||||
*oqp->q_wrptr++ = *bp++;
|
||||
if (oqp->q_wrptr >= oqp->q_top)
|
||||
oqp->q_wrptr = oqp->q_buffer;
|
||||
w++;
|
||||
--n;
|
||||
}
|
||||
if (nfy) nfy(oqp);
|
||||
|
||||
chSysUnlock(); /* Gives a preemption chance in a controlled point.*/
|
||||
if (n == 0) return w;
|
||||
chSysLock();
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_reboot(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
(void)chp;
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
m4_request_shutdown();
|
||||
chThdSleepMilliseconds(50);
|
||||
|
||||
LPC_RGU->RESET_CTRL[0] = (1 << 0);
|
||||
}
|
||||
|
||||
static void cmd_dfu(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
(void)chp;
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
m4_request_shutdown();
|
||||
chThdSleepMilliseconds(50);
|
||||
|
||||
LPC_SCU->SFSP2_8 = (LPC_SCU->SFSP2_8 & ~(7)) | 4;
|
||||
palOutputPad(5, 7);
|
||||
palSetPad(5, 7);
|
||||
|
||||
LPC_RGU->RESET_CTRL[0] = (1 << 0);
|
||||
}
|
||||
|
||||
static void cmd_hackrf(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
(void)chp;
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
m4_request_shutdown();
|
||||
chThdSleepMilliseconds(50);
|
||||
EventDispatcher::request_stop();
|
||||
}
|
||||
|
||||
static void cmd_sd_over_usb(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
(void)chp;
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
ui::Painter painter;
|
||||
painter.fill_rectangle(
|
||||
{0, 0, portapack::display.width(), portapack::display.height()},
|
||||
ui::Color::black());
|
||||
|
||||
painter.draw_bitmap(
|
||||
{portapack::display.width() / 2 - 8, portapack::display.height() / 2 - 8},
|
||||
ui::bitmap_icon_hackrf,
|
||||
ui::Color::yellow(),
|
||||
ui::Color::black());
|
||||
|
||||
sdcDisconnect(&SDCD1);
|
||||
sdcStop(&SDCD1);
|
||||
|
||||
m4_request_shutdown();
|
||||
chThdSleepMilliseconds(50);
|
||||
portapack::shutdown(true);
|
||||
m4_init(portapack::spi_flash::image_tag_usb_sd, portapack::memory::map::m4_code, false);
|
||||
m0_halt();
|
||||
}
|
||||
|
||||
std::filesystem::path path_from_string8(char* path) {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> conv;
|
||||
return conv.from_bytes(path);
|
||||
}
|
||||
|
||||
static void cmd_flash(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
if (argc != 1) {
|
||||
chprintf(chp, "Usage: flash /FIRMWARE/portapack-h1_h2-mayhem.bin\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
auto path = path_from_string8(argv[0]);
|
||||
size_t filename_length = strlen(argv[0]);
|
||||
|
||||
if (!std::filesystem::file_exists(path)) {
|
||||
chprintf(chp, "file not found.\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
std::memcpy(&shared_memory.bb_data.data[0], path.c_str(), (filename_length + 1) * 2);
|
||||
|
||||
m4_request_shutdown();
|
||||
chThdSleepMilliseconds(50);
|
||||
m4_init(portapack::spi_flash::image_tag_flash_utility, portapack::memory::map::m4_code, false);
|
||||
m0_halt();
|
||||
}
|
||||
|
||||
static void cmd_screenshot(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
ensure_directory("SCREENSHOTS");
|
||||
auto path = next_filename_matching_pattern(u"SCREENSHOTS/SCR_????.PNG");
|
||||
|
||||
if (path.empty())
|
||||
return;
|
||||
|
||||
PNGWriter png;
|
||||
auto error = png.create(path);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < ui::screen_height; i++) {
|
||||
std::array<ui::ColorRGB888, ui::screen_width> row;
|
||||
portapack::display.read_pixels({0, i, ui::screen_width, 1}, row);
|
||||
png.write_scanline(row);
|
||||
}
|
||||
|
||||
chprintf(chp, "generated %s\r\n", path.string().c_str());
|
||||
}
|
||||
|
||||
// gives full color.
|
||||
static void cmd_screenframe(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
for (int i = 0; i < ui::screen_height; i++) {
|
||||
std::array<ui::ColorRGB888, ui::screen_width> row;
|
||||
portapack::display.read_pixels({0, i, ui::screen_width, 1}, row);
|
||||
for (int px = 0; px < ui::screen_width; px += 5) {
|
||||
char buffer[5 * 3 * 2];
|
||||
sprintf(buffer, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", row[px].r, row[px].g, row[px].b, row[px + 1].r, row[px + 1].g, row[px + 1].b, row[px + 2].r, row[px + 2].g, row[px + 2].b, row[px + 3].r, row[px + 3].g, row[px + 3].b, row[px + 4].r, row[px + 4].g, row[px + 4].b);
|
||||
fillOBuffer(&((SerialUSBDriver*)chp)->oqueue, (const uint8_t*)buffer, 5 * 3 * 2);
|
||||
}
|
||||
chprintf(chp, "\r\n");
|
||||
}
|
||||
chprintf(chp, "ok\r\n");
|
||||
}
|
||||
|
||||
static char getChrFromRgb(uint8_t r, uint8_t g, uint8_t b) {
|
||||
uint8_t chR = r >> 6; // 3bit
|
||||
uint8_t chG = g >> 6; // 3bit
|
||||
uint8_t chB = b >> 6; // 3bit
|
||||
uint8_t res = chR << 4 | chG << 2 | chB;
|
||||
res += 32;
|
||||
return res;
|
||||
}
|
||||
|
||||
// sends only 1 byte (printable only) per pixel, so around 96 colors
|
||||
static void cmd_screenframeshort(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
for (int y = 0; y < ui::screen_height; y++) {
|
||||
std::array<ui::ColorRGB888, ui::screen_width> row;
|
||||
portapack::display.read_pixels({0, y, ui::screen_width, 1}, row);
|
||||
for (int px = 0; px < ui::screen_width; px += 60) {
|
||||
char buffer[60];
|
||||
for (int i = 0; i < 60; ++i) {
|
||||
buffer[i] = getChrFromRgb(row[px + i].r, row[px + i].g, row[px + i].b);
|
||||
}
|
||||
fillOBuffer(&((SerialUSBDriver*)chp)->oqueue, (const uint8_t*)buffer, 60);
|
||||
}
|
||||
chprintf(chp, "\r\n");
|
||||
}
|
||||
|
||||
chprintf(chp, "ok\r\n");
|
||||
}
|
||||
static void cmd_write_memory(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
chprintf(chp, "usage: write_memory <address> <value (1 or 4 bytes)>\r\n");
|
||||
chprintf(chp, "example: write_memory 0x40004008 0x00000002\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int value_length = strlen(argv[1]);
|
||||
if (value_length != 10 && value_length != 4) {
|
||||
chprintf(chp, "usage: write_memory <address> <value (1 or 4 bytes)>\r\n");
|
||||
chprintf(chp, "example: write_memory 0x40004008 0x00000002\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t address = (uint32_t)strtol(argv[0], NULL, 16);
|
||||
uint32_t value = (uint32_t)strtol(argv[1], NULL, 16);
|
||||
|
||||
if (value_length == 10) {
|
||||
uint32_t* data_pointer = (uint32_t*)address;
|
||||
*data_pointer = value;
|
||||
} else {
|
||||
uint8_t* data_pointer = (uint8_t*)address;
|
||||
*data_pointer = (uint8_t)value;
|
||||
}
|
||||
|
||||
chprintf(chp, "ok\r\n");
|
||||
}
|
||||
|
||||
static void cmd_read_memory(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
if (argc != 1) {
|
||||
chprintf(chp, "usage: read_memory 0x40004008\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int address = (int)strtol(argv[0], NULL, 16);
|
||||
uint32_t* data_pointer = (uint32_t*)address;
|
||||
|
||||
chprintf(chp, "%x\r\n", *data_pointer);
|
||||
}
|
||||
|
||||
static void cmd_button(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
if (argc != 1) {
|
||||
chprintf(chp, "usage: button 1\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int button = (int)strtol(argv[0], NULL, 10);
|
||||
if (button < 1 || button > 8) {
|
||||
chprintf(chp, "usage: button <number 1 to 8>\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
control::debug::inject_switch(button);
|
||||
|
||||
chprintf(chp, "ok\r\n");
|
||||
}
|
||||
|
||||
static void cmd_sd_list_dir(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
if (argc != 1) {
|
||||
chprintf(chp, "usage: ls /\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
auto path = path_from_string8(argv[0]);
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(path, "*")) {
|
||||
if (std::filesystem::is_directory(entry.status())) {
|
||||
chprintf(chp, "%s/\r\n", entry.path().string().c_str());
|
||||
} else if (std::filesystem::is_regular_file(entry.status())) {
|
||||
chprintf(chp, "%s\r\n", entry.path().string().c_str());
|
||||
} else {
|
||||
chprintf(chp, "%s *\r\n", entry.path().string().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_sd_delete(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
if (argc != 1) {
|
||||
chprintf(chp, "usage: rm <path>\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
auto path = path_from_string8(argv[0]);
|
||||
|
||||
if (!std::filesystem::file_exists(path)) {
|
||||
chprintf(chp, "file not found.\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
delete_file(path);
|
||||
|
||||
chprintf(chp, "ok\r\n");
|
||||
}
|
||||
|
||||
File* shell_file = nullptr;
|
||||
|
||||
static void cmd_sd_filesize(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
if (argc != 1) {
|
||||
chprintf(chp, "usage: filesize <path>\r\n");
|
||||
return;
|
||||
}
|
||||
auto path = path_from_string8(argv[0]);
|
||||
FILINFO res;
|
||||
auto stat = f_stat(path.tchar(), &res);
|
||||
if (stat == FR_OK) {
|
||||
chprintf(chp, "%lu\r\n", res.fsize);
|
||||
chprintf(chp, "ok\r\n");
|
||||
} else {
|
||||
chprintf(chp, "error\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_sd_open(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
if (argc != 1) {
|
||||
chprintf(chp, "usage: open <path>\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (shell_file != nullptr) {
|
||||
chprintf(chp, "file already open\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
auto path = path_from_string8(argv[0]);
|
||||
shell_file = new File();
|
||||
shell_file->open(path, false, true);
|
||||
|
||||
chprintf(chp, "ok\r\n");
|
||||
}
|
||||
|
||||
static void cmd_sd_seek(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
if (argc != 1) {
|
||||
chprintf(chp, "usage: seek <offset>\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (shell_file == nullptr) {
|
||||
chprintf(chp, "no open file\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int address = (int)strtol(argv[0], NULL, 10);
|
||||
shell_file->seek(address);
|
||||
|
||||
chprintf(chp, "ok\r\n");
|
||||
}
|
||||
|
||||
static void cmd_sd_close(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
(void)argv;
|
||||
|
||||
if (argc != 0) {
|
||||
chprintf(chp, "usage: close\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (shell_file == nullptr) {
|
||||
chprintf(chp, "no open file\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
delete shell_file;
|
||||
shell_file = nullptr;
|
||||
|
||||
chprintf(chp, "ok\r\n");
|
||||
}
|
||||
|
||||
static void cmd_sd_read(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
if (argc != 1) {
|
||||
chprintf(chp, "usage: read <number of bytes>\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (shell_file == nullptr) {
|
||||
chprintf(chp, "no open file\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int size = (int)strtol(argv[0], NULL, 10);
|
||||
|
||||
uint8_t buffer[16];
|
||||
|
||||
do {
|
||||
File::Size bytes_to_read = size > 16 ? 16 : size;
|
||||
auto bytes_read = shell_file->read(buffer, bytes_to_read);
|
||||
if (bytes_read.is_error()) {
|
||||
chprintf(chp, "error %d\r\n", bytes_read.error());
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < bytes_read.value(); i++)
|
||||
chprintf(chp, "%02X", buffer[i]);
|
||||
|
||||
chprintf(chp, "\r\n");
|
||||
|
||||
if (bytes_to_read != bytes_read.value())
|
||||
return;
|
||||
|
||||
size -= bytes_to_read;
|
||||
} while (size > 0);
|
||||
chprintf(chp, "ok\r\n");
|
||||
}
|
||||
|
||||
static void cmd_sd_write(BaseSequentialStream* chp, int argc, char* argv[]) {
|
||||
const char* usage = "usage: write 0123456789ABCDEF\r\n";
|
||||
if (argc != 1) {
|
||||
chprintf(chp, usage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (shell_file == nullptr) {
|
||||
chprintf(chp, "no open file\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t data_string_len = strlen(argv[0]);
|
||||
if (data_string_len % 2 != 0) {
|
||||
chprintf(chp, usage);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < data_string_len; i++) {
|
||||
char c = argv[0][i];
|
||||
if ((c < '0' || c > '9') && (c < 'A' || c > 'F')) {
|
||||
chprintf(chp, usage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
char buffer[3] = {0, 0, 0};
|
||||
|
||||
for (size_t i = 0; i < data_string_len / 2; i++) {
|
||||
buffer[0] = argv[0][i * 2];
|
||||
buffer[1] = argv[0][i * 2 + 1];
|
||||
uint8_t value = (uint8_t)strtol(buffer, NULL, 16);
|
||||
shell_file->write(&value, 1);
|
||||
}
|
||||
|
||||
chprintf(chp, "ok\r\n");
|
||||
}
|
||||
|
||||
static const ShellCommand commands[] = {
|
||||
{"reboot", cmd_reboot},
|
||||
{"dfu", cmd_dfu},
|
||||
{"hackrf", cmd_hackrf},
|
||||
{"sd_over_usb", cmd_sd_over_usb},
|
||||
{"flash", cmd_flash},
|
||||
{"screenshot", cmd_screenshot},
|
||||
{"screenframe", cmd_screenframe},
|
||||
{"screenframeshort", cmd_screenframeshort},
|
||||
{"write_memory", cmd_write_memory},
|
||||
{"read_memory", cmd_read_memory},
|
||||
{"button", cmd_button},
|
||||
{"ls", cmd_sd_list_dir},
|
||||
{"rm", cmd_sd_delete},
|
||||
{"open", cmd_sd_open},
|
||||
{"seek", cmd_sd_seek},
|
||||
{"close", cmd_sd_close},
|
||||
{"read", cmd_sd_read},
|
||||
{"write", cmd_sd_write},
|
||||
{"filesize", cmd_sd_filesize},
|
||||
{NULL, NULL}};
|
||||
|
||||
static const ShellConfig shell_cfg1 = {
|
||||
(BaseSequentialStream*)&SUSBD1,
|
||||
commands};
|
||||
|
||||
void create_shell() {
|
||||
shellCreate(&shell_cfg1, SHELL_WA_SIZE, NORMALPRIO);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
void create_shell(void);
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
|
||||
*
|
||||
* 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 "usb_serial_thread.hpp"
|
||||
#include "buffer_exchange.hpp"
|
||||
|
||||
// UsbSerialThread //////////////////////////////////////////////////////////
|
||||
|
||||
UsbSerialThread::UsbSerialThread() {
|
||||
create_thread();
|
||||
}
|
||||
|
||||
UsbSerialThread::~UsbSerialThread() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void UsbSerialThread::create_thread() {
|
||||
thread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO + 10, UsbSerialThread::static_fn, this);
|
||||
}
|
||||
|
||||
void UsbSerialThread::stop() {
|
||||
if (thread) {
|
||||
chThdTerminate(thread);
|
||||
chThdWait(thread);
|
||||
thread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
msg_t UsbSerialThread::static_fn(void* arg) {
|
||||
auto obj = static_cast<UsbSerialThread*>(arg);
|
||||
obj->run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UsbSerialThread::run() {
|
||||
while (!chThdShouldTerminate()) {
|
||||
if (str_ready) {
|
||||
str_ready = false;
|
||||
chprintf((BaseSequentialStream*)&SUSBD1, serial_str.c_str());
|
||||
}
|
||||
|
||||
chThdSleepMilliseconds(50);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
|
||||
*
|
||||
* 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 __USB_SERIAL_THREAD_H__
|
||||
#define __USB_SERIAL_THREAD_H__
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
#include "event_m0.hpp"
|
||||
|
||||
#include "io.hpp"
|
||||
#include "optional.hpp"
|
||||
|
||||
#include "chprintf.h"
|
||||
#include "usb_serial_io.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
class UsbSerialThread {
|
||||
public:
|
||||
UsbSerialThread();
|
||||
~UsbSerialThread();
|
||||
|
||||
void stop();
|
||||
|
||||
UsbSerialThread(const UsbSerialThread&) = delete;
|
||||
UsbSerialThread(UsbSerialThread&&) = delete;
|
||||
UsbSerialThread& operator=(const UsbSerialThread&) = delete;
|
||||
UsbSerialThread& operator=(UsbSerialThread&&) = delete;
|
||||
bool str_ready = false;
|
||||
std::string serial_str{};
|
||||
|
||||
private:
|
||||
Thread* thread{nullptr};
|
||||
static msg_t static_fn(void* arg);
|
||||
void run();
|
||||
void create_thread();
|
||||
};
|
||||
|
||||
#endif /*__CAPTURE_THREAD_H__*/
|
||||
@@ -419,12 +419,6 @@ set(MODE_CPPSRC
|
||||
)
|
||||
DeclareTargets(PFSR fskrx)
|
||||
|
||||
### Jammer
|
||||
|
||||
set(MODE_CPPSRC
|
||||
proc_jammer.cpp
|
||||
)
|
||||
DeclareTargets(PJAM jammer)
|
||||
|
||||
### Microphone transmit
|
||||
|
||||
@@ -538,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
|
||||
)
|
||||
@@ -622,6 +623,13 @@ set(MODE_CPPSRC
|
||||
DeclareTargets(PNRR nrfrx)
|
||||
|
||||
|
||||
### Jammer
|
||||
|
||||
set(MODE_CPPSRC
|
||||
proc_jammer.cpp
|
||||
)
|
||||
DeclareTargets(PJAM jammer)
|
||||
|
||||
### AM TV
|
||||
|
||||
set(MODE_CPPSRC
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -58,6 +58,8 @@ int main() {
|
||||
|
||||
f_close(&firmware_file);
|
||||
|
||||
LPC_RGU->RESET_CTRL[0] = (1 << 0);
|
||||
|
||||
while (1)
|
||||
__WFE();
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
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
|
||||
|
||||
modulation = message.modulation; // TODO: add support for FM (currently AM only)
|
||||
|
||||
baseband_fs = message.sampling_rate;
|
||||
baseband_thread.set_sampling_rate(baseband_fs);
|
||||
nsPerDecSamp = 1'000'000'000 / baseband_fs * 8; // Scaled it due to less array buffer sampes due to /8 decimation. 250 nseg (4Mhz) * 8
|
||||
|
||||
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;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user