Compare commits

...

21 Commits

Author SHA1 Message Date
jLynx 53bbf74f4d V1.9.0 (#1660)
* Update version.txt

* Update past_version.txt
2023-12-22 07:35:54 +13:00
Mark Thompson 19a66fac20 Enable Sample Rate to be spec'd in .ini file for Weather & SubGhzDecoder apps (#1659) 2023-12-21 19:33:06 +01:00
Totoo 36e1b9a36e Portapack USB screen tx (#1653)
* implemented 2 screen read functions, and haxfixed windows usb bug
* Support up to 64 byte per packet for faster tx
* Added filesize command
2023-12-19 22:25:22 +01:00
Netro 1ca9288bbe initial USB serial thread integrated to BLE RX (#1651) 2023-12-19 22:20:13 +01:00
Mark Thompson 4ca2d1e352 Fix compile error (#1650) 2023-12-18 07:35:00 +01:00
gullradriel 0b11730835 fix wrong direction in tx freq correction (#1649)
Co-authored-by: GullCode <gullradriel@hotmail.com>
2023-12-17 18:47:20 -06:00
Bernd Herzog 6069145b68 Usb serial (#1648)
* enabled usb clock
* added usb stack to application
* fixed pll0usb clock setup
* implemented serial usb handshake
* implemented serial communication
* integrated chibios shell
* implemented device reset
* implemented enter dfu mode
* implemented hackrf mode command
* implemented flash command
* implemented memory manipulation
* implemented button control
* fixed mode change
* improved reset behavior
* implemented directory commands
* implemented file commands
* improved data communication
* refactorings
2023-12-17 17:20:35 +01:00
Totoo 2ccda5aebd Subghz decoder (#1646)
* Initial commit - wip

* Half part of the transition of baseband processor.

* More SGD

* WIP, Weather refactor, UI improv

* Rename

* Added 4msps, and fixes

* Fixes

* princeton working

* Renamed proc_weather, bc now multifunctional

* Proto: bett

* FPS_CAME = 4,
    FPS_PRASTEL = 5,
    FPS_AIRFORCE = 6,

* Came Atomo, fixes

* Separate weather and sgd, bc of baseband size limit

* Fix display

* Save space

* More protos

* Dooya proto added

* More protos

* add protos

* More protos

* Move weather to ext app

* nw

* Revert "Move weather to ext app"

This reverts commit 8a84aac2f5.

* revert

* Fix merge

* Better naming

* More protos

* More protos

* Add protos

* Fix warning

* Add NeroRadio

* more protos

* more protos

* More protos

* Shrink a bit

* fixes

* More protos

* Nicer code

* Fix naming

* Fix format

* Remove unused

* Fix some protos, that needs a LOOOONG part with the same lo/high

* Modify key calculation
2023-12-16 16:37:51 -06:00
Totoo 02810bf527 Move Jammer ext app (with baseband image too) (#1647) 2023-12-15 20:18:21 +01:00
Totoo b58ee761a1 Move more apps + language module (#1643)
* CoasterP to ext (Burger pager)
* LGE to ext app
* Solve compiler literal removal with centralizing common string literals.
2023-12-12 16:55:50 +01:00
Totoo 5b9d898202 Fix oregon2 weather protocol (#1642) 2023-12-12 06:45:56 +01:00
Totoo 5f8e44e7b7 NRF RX to ext app (#1641)
* NFR Rx to ext app
2023-12-11 11:57:04 +01:00
Totoo ec80859d93 AnalogTV to ext (#1638) 2023-12-11 08:55:07 +01:00
Totoo 5e9d92d65c Set sr to 4m (#1636)
* Set sr to 4m

* Rename variable
2023-12-10 23:40:11 +01:00
Mark Thompson c3bb9c0a16 Weather display beautification (#1635) 2023-12-10 17:57:21 +01:00
Netro bd475e6f9c BLE RX - Find From File Initial Commit. (#1627)
* initial work
* Handling capping count only at total count
* Adding logging back in
2023-12-09 18:02:00 +01:00
Mark Thompson 0f1708d8fd Increase SSP timing margin for MAX2839 registers (#1632) 2023-12-09 14:09:20 +01:00
Mark Thompson efa0e270ad Updated Weather & TPMS app icons (#1630) 2023-12-09 09:25:41 +01:00
Totoo ff882024d4 Ble spam improvements (#1626)
* Much faster ble  spam tx
* Better Android handling
2023-12-09 09:24:02 +01:00
Brumi-2021 60d95447fb Improved sensitivity/selectivity Weather App (#1628) 2023-12-08 21:33:48 +01:00
Mark Thompson a474bf8fe3 Add files via upload (#1629) 2023-12-08 19:20:59 +01:00
139 changed files with 8121 additions and 531 deletions
+1 -1
View File
@@ -1 +1 @@
v1.7.4
v1.8.0
+1 -1
View File
@@ -1 +1 @@
v1.8.0
v1.9.0
+1
View File
@@ -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}
+27 -8
View File
@@ -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
@@ -162,6 +173,7 @@ set(CPPSRC
${COMMON}/ui_painter.cpp
${COMMON}/ui_text.cpp
${COMMON}/ui_widget.cpp
${COMMON}/ui_language.cpp
${COMMON}/utility.cpp
${COMMON}/wm8731.cpp
${COMMON}/performance_counter.cpp
@@ -190,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
@@ -243,15 +259,14 @@ set(CPPSRC
apps/acars_app.cpp
apps/ais_app.cpp
apps/analog_audio_app.cpp
apps/analog_tv_app.cpp
# apps/analog_tv_app.cpp
apps/ble_comm_app.cpp
apps/ble_rx_app.cpp
apps/ble_tx_app.cpp
apps/capture_app.cpp
apps/ert_app.cpp
apps/gps_sim_app.cpp
apps/lge_app.cpp
apps/lge_app.cpp
# apps/lge_app.cpp
apps/pocsag_app.cpp
# apps/replay_app.cpp
apps/soundboard_app.cpp
@@ -264,7 +279,7 @@ set(CPPSRC
apps/ui_aprs_tx.cpp
apps/ui_bht_tx.cpp
apps/ui_btle_rx.cpp
apps/ui_coasterp.cpp
# apps/ui_coasterp.cpp
apps/ui_debug.cpp
apps/ui_dfu_menu.cpp
apps/ui_encoders.cpp
@@ -273,15 +288,15 @@ 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_lcr.cpp
apps/ui_level.cpp
apps/ui_looking_glass_app.cpp
apps/ui_mictx.cpp
apps/ui_modemsetup.cpp
apps/ui_morse.cpp
apps/ui_nrf_rx.cpp
# apps/ui_nrf_rx.cpp
# apps/ui_nuoptix.cpp
apps/ui_playlist.cpp
apps/ui_pocsag_tx.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
@@ -314,7 +330,7 @@ set(CPPSRC
protocols/bht.cpp
protocols/dcs.cpp
protocols/encoders.cpp
protocols/lcr.cpp
# protocols/lcr.cpp
protocols/modems.cpp
protocols/rds.cpp
# ui_handwrite.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
+107 -30
View File
@@ -22,19 +22,22 @@
*/
#include "ble_rx_app.hpp"
#include "ble_rx_app.hpp"
#include "ui_modemsetup.hpp"
#include "modems.hpp"
#include "audio.hpp"
#include "io_file.hpp"
#include "rtc_time.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
#include "ui_fileman.hpp"
#include "ui_textentry.hpp"
using namespace portapack;
using namespace modems;
namespace fs = std::filesystem;
void BLELogger::log_raw_data(const std::string& data) {
log_file.write_entry(data);
@@ -199,8 +202,6 @@ BleRecentEntryDetailView::BleRecentEntryDetailView(NavigationView& nav, const Bl
}
void BleRecentEntryDetailView::on_save_file(const std::string value, BLETxPacket packetToSave) {
std::filesystem::path packet_save_path{u"BLERX/Packets/????.TXT"};
ensure_directory(packet_save_path);
auto folder = packet_save_path.parent_path();
auto ext = packet_save_path.extension();
@@ -403,6 +404,10 @@ void BLERxView::focus() {
options_channel.focus();
}
void BLERxView::file_error() {
nav_.display_modal("Error", "File read error.");
}
BLERxView::BLERxView(NavigationView& nav)
: nav_{nav} {
baseband::run_image(portapack::spi_flash::image_tag_btle_rx);
@@ -415,9 +420,12 @@ BLERxView::BLERxView(NavigationView& nav)
&options_channel,
&field_frequency,
&check_log,
&button_find,
&check_name,
&label_sort,
&options_sort,
&label_found,
&text_found_count,
&button_filter,
&button_save_list,
&button_clear_list,
@@ -428,6 +436,12 @@ 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);
filterBuffer = filter;
button_filter.on_select = [this](Button&) {
@@ -440,6 +454,21 @@ BLERxView::BLERxView(NavigationView& nav)
});
};
logger = std::make_unique<BLELogger>();
check_log.set_value(logging);
check_log.on_select = [this](Checkbox&, bool v) {
str_log = "";
logging = v;
if (logger && logging)
logger->append(
"BLERX/Logs"
"/BLELOG_" +
to_string_timestamp(rtc_time::now()) + ".TXT");
};
button_save_list.on_select = [this, &nav](const ui::Button&) {
listFileBuffer = "";
text_prompt(
@@ -461,16 +490,6 @@ BLERxView::BLERxView(NavigationView& nav)
field_frequency.set_step(0);
check_log.set_value(logging);
check_log.on_select = [this](Checkbox&, bool v) {
str_log = "";
logging = v;
if (logger && logging)
logger->append(LOG_ROOT_DIR "/BLELOG_" + to_string_timestamp(rtc_time::now()) + ".TXT");
};
check_name.set_value(name_enable);
check_name.on_select = [this](Checkbox&, bool v) {
@@ -504,7 +523,14 @@ BLERxView::BLERxView(NavigationView& nav)
options_channel.set_selected_index(channel_index, true);
options_sort.set_selected_index(sort_index, true);
logger = std::make_unique<BLELogger>();
button_find.on_select = [this](Button&) {
auto open_view = nav_.push<FileLoadView>(".TXT");
open_view->on_changed = [this](std::filesystem::path new_file_path) {
on_file_changed(new_file_path);
// nav_.set_on_pop([this]() { button_play.focus(); });
};
};
// Auto-configure modem for LCR RX (will be removed later)
baseband::set_btlerx(channel_number);
@@ -529,9 +555,6 @@ std::string BLERxView::build_line_str(BleRecentEntry entry) {
}
void BLERxView::on_save_file(const std::string value) {
std::filesystem::path packet_save_path{u"BLERX/Lists/????.csv"};
ensure_directory(packet_save_path);
auto folder = packet_save_path.parent_path();
auto ext = packet_save_path.extension();
auto new_path = folder / value + ext;
@@ -663,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;
@@ -688,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.
@@ -707,7 +720,29 @@ 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();
while (it != searchList.end()) {
std::string searchStr = (std::string)*it;
if (entry.dataString.find(searchStr) != std::string::npos) {
searchList.erase(it);
found_count++;
break;
}
it++;
}
text_found_count.set(to_string_dec_uint(found_count) + "/" + to_string_dec_uint(total_count));
}
}
@@ -722,6 +757,48 @@ void BLERxView::on_filter_change(std::string value) {
filter = value;
}
void BLERxView::on_file_changed(const std::filesystem::path& new_file_path) {
file_path = fs::path(u"/") + new_file_path;
found_count = 0;
total_count = 0;
searchList.clear();
{ // Get the size of the data file.
File data_file;
auto error = data_file.open(file_path, true, false);
if (error) {
file_error();
file_path = "";
return;
}
uint64_t bytesRead = 0;
uint64_t bytePos = 0;
char currentLine[maxLineLength];
do {
memset(currentLine, 0, maxLineLength);
bytesRead = readUntil(data_file, currentLine, maxLineLength, '\n');
// Remove return if found.
if (currentLine[strlen(currentLine)] == '\r') {
currentLine[strlen(currentLine)] = '\0';
}
if (!bytesRead) {
break;
}
searchList.push_back(currentLine);
total_count++;
bytePos += bytesRead;
} while (bytePos <= data_file.size());
}
}
// called each 1/60th of second, so 6 = 100ms
void BLERxView::on_timer() {
if (++timer_count == timer_period) {
+28 -2
View File
@@ -35,6 +35,7 @@
#include "radio_state.hpp"
#include "log_file.hpp"
#include "utility.hpp"
#include "usb_serial_thread.hpp"
#include "recent_entries.hpp"
@@ -132,6 +133,7 @@ class BleRecentEntryDetailView : public View {
void on_save_file(const std::string value, BLETxPacket packetToSave);
bool saveFile(const std::filesystem::path& path, BLETxPacket packetToSave);
std::string packetFileBuffer{};
std::filesystem::path packet_save_path{u"BLERX/Lists/????.csv"};
static constexpr uint8_t total_data_lines{5};
@@ -193,8 +195,11 @@ 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);
void file_error();
void on_timer();
void handle_entries_sort(uint8_t index);
void updateEntry(const BlePacketData* packet, BleRecentEntry& entry, ADV_PDU_TYPE pdu_type);
@@ -210,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",
@@ -222,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;
@@ -235,7 +242,16 @@ class BLERxView : public View {
std::string headerStr = "Timestamp, MAC Address, Name, Packet Type, Data, Hits, dB, Channel";
uint16_t maxLineLength = 140;
static constexpr auto header_height = 3 * 16;
std::filesystem::path file_path{};
uint64_t found_count = 0;
uint64_t total_count = 0;
std::vector<std::string> searchList{};
std::filesystem::path find_packet_path{u"BLERX/Find/????.TXT"};
std::filesystem::path log_packets_path{u"BLERX/Logs/????.TXT"};
std::filesystem::path packet_save_path{u"BLERX/Lists/????.csv"};
static constexpr auto header_height = 4 * 16;
static constexpr auto switch_button_height = 3 * 16;
OptionsField options_channel{
@@ -293,6 +309,17 @@ class BLERxView : public View {
"Name",
true};
Button button_find{
{0 * 8, 6 * 8, 4 * 8, 16},
"Find"};
Labels label_found{
{{5 * 8, 6 * 8}, "Found:", Color::light_grey()}};
Text text_found_count{
{11 * 8, 3 * 16, 20 * 8, 16},
"0/0"};
Console console{
{0, 4 * 16, 240, 240}};
@@ -309,7 +336,6 @@ class BLERxView : public View {
"Tx"};
std::string str_log{""};
std::unique_ptr<BLELogger> logger{};
BleRecentEntries recent{};
+2 -2
View File
@@ -131,10 +131,10 @@ bool MorseView::start_tx() {
transmitter_model.set_baseband_bandwidth(1'750'000); // Min TX LPF .already tested in FM morse max tone 9,999k , max dev 150khz
transmitter_model.enable();
baseband::set_tones_config(transmitter_model.channel_bandwidth(), 0, symbol_count, false, false);
if (mode_cw) {
ookthread = chThdCreateStatic(ookthread_wa, sizeof(ookthread_wa), NORMALPRIO + 10, ookthread_fn, this);
} else {
baseband::set_tones_config(transmitter_model.channel_bandwidth(), 0, symbol_count, false, false);
}
return true;
+1 -1
View File
@@ -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);
};
+242
View File
@@ -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
+171
View File
@@ -0,0 +1,171 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __UI_SUBGHZD_H__
#define __UI_SUBGHZD_H__
#include "ui.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "ui_freq_field.hpp"
#include "app_settings.hpp"
#include "radio_state.hpp"
#include "utility.hpp"
#include "recent_entries.hpp"
#include "../baseband/fprotos/subghztypes.hpp"
using namespace ui;
namespace ui {
struct SubGhzDRecentEntry {
using Key = uint64_t;
static constexpr Key invalid_key = 0x0fffffff;
uint8_t sensorType = FPS_Invalid;
uint8_t btn = SD_NO_BTN;
uint32_t serial = SD_NO_SERIAL;
uint16_t bits = 0;
uint16_t age = 0; // updated on each seconds, show how long the signal was last seen
uint32_t cnt = SD_NO_CNT;
uint64_t data = 0;
SubGhzDRecentEntry() {}
SubGhzDRecentEntry(
uint8_t sensorType,
uint32_t serial,
uint16_t bits = 0,
uint64_t data = 0,
uint8_t btn = SD_NO_BTN,
uint32_t cnt = SD_NO_CNT)
: sensorType{sensorType},
btn{btn},
serial{serial},
bits{bits},
cnt{cnt},
data{data} {
}
Key key() const {
return (data ^ ((static_cast<uint64_t>(serial) << 32) | (static_cast<uint64_t>(sensorType) & 0xFF) << 0));
}
void inc_age(int delta) {
if (UINT16_MAX - delta > age) age += delta;
}
void reset_age() {
age = 0;
}
};
using SubGhzDRecentEntries = RecentEntries<SubGhzDRecentEntry>;
using SubGhzDRecentEntriesView = RecentEntriesView<SubGhzDRecentEntries>;
class SubGhzDView : public View {
public:
SubGhzDView(NavigationView& nav);
~SubGhzDView();
void focus() override;
std::string title() const override { return "SubGhzD"; };
static const char* getSensorTypeName(FPROTO_SUBGHZD_SENSOR type);
static std::string pad_string_with_spaces(int snakes);
private:
void on_tick_second();
void on_data(const SubGhzDDataMessage* data);
NavigationView& nav_;
RxRadioState radio_state_{
433'920'000 /* frequency */,
1'750'000 /* bandwidth */,
4'000'000 /* sampling rate */,
ReceiverModel::Mode::AMAudio};
app_settings::SettingsManager settings_{
"rx_subghzd",
app_settings::Mode::RX,
{}};
SubGhzDRecentEntries recent{};
RFAmpField field_rf_amp{
{13 * 8, 0 * 16}};
LNAGainField field_lna{
{15 * 8, 0 * 16}};
VGAGainField field_vga{
{18 * 8, 0 * 16}};
RSSI rssi{
{21 * 8, 0, 6 * 8, 4}};
RxFrequencyField field_frequency{
{0 * 8, 0 * 16},
nav_};
SignalToken signal_token_tick_second{};
Button button_clear_list{
{0, 16, 7 * 8, 32},
"Clear"};
static constexpr auto header_height = 3 * 16;
const RecentEntriesColumns columns{{
{"Type", 19},
{"Bits", 4},
{"Age", 3},
}};
SubGhzDRecentEntriesView recent_entries_view{columns, recent};
MessageHandlerRegistration message_handler_packet{
Message::ID::SubGhzDData,
[this](Message* const p) {
const auto message = static_cast<const SubGhzDDataMessage*>(p);
this->on_data(message);
}};
};
class SubGhzDRecentEntryDetailView : public View {
public:
SubGhzDRecentEntryDetailView(NavigationView& nav, const SubGhzDRecentEntry& entry);
void update_data();
void focus() override;
private:
NavigationView& nav_;
SubGhzDRecentEntry entry_{};
Text text_type{{0 * 8, 1 * 16, 15 * 8, 16}, "?"};
Text text_id{{6 * 8, 2 * 16, 10 * 8, 16}, "?"};
Console console{
{0, 4 * 16, 240, screen_height - (4 * 16) - 36}};
Labels labels{
{{0 * 8, 0 * 16}, "Type:", Color::light_grey()},
{{0 * 8, 2 * 16}, "Serial: ", Color::light_grey()},
{{0 * 8, 3 * 16}, "Data:", Color::light_grey()},
};
Button button_done{
{screen_width - 96 - 4, screen_height - 32 - 12, 96, 32},
"Done"};
};
} // namespace ui
#endif /*__UI_SUBGHZD_H__*/
+25 -10
View File
@@ -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,7 +115,7 @@ WeatherView::WeatherView(NavigationView& nav)
recent_entries_view.on_select = [this](const WeatherRecentEntry& entry) {
nav_.push<WeatherRecentEntryDetailView>(entry);
};
baseband::set_weather();
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();
@@ -204,17 +219,17 @@ 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;
line += WeatherView::pad_string_with_spaces(5 - humStr.length()) + humStr;
line += WeatherView::pad_string_with_spaces(4 - chStr.length()) + chStr;
line += WeatherView::pad_string_with_spaces(4 - ageStr.length()) + ageStr;
line += WeatherView::pad_string_with_spaces(5 - ageStr.length()) + ageStr;
line.resize(target_rect.width() / 8, ' ');
painter.draw_string(target_rect.location(), style, line);
}
} // namespace ui
} // namespace ui
+16 -15
View File
@@ -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},
@@ -143,7 +143,7 @@ class WeatherView : public View {
{"Temp", 5},
{"Hum", 4},
{"Ch", 3},
{"Age", 3},
{"Age", 4},
}};
WeatherRecentEntriesView recent_entries_view{columns, recent};
@@ -165,16 +165,17 @@ class WeatherRecentEntryDetailView : public View {
private:
NavigationView& nav_;
WeatherRecentEntry entry_{};
Text text_type{{0 * 8, 1 * 16, 15 * 8, 16}, "?"};
Text text_id{{6 * 8, 2 * 16, 10 * 8, 16}, "?"};
Text text_temp{{6 * 8, 3 * 16, 8 * 8, 16}, "?"};
Text text_hum{{11 * 8, 4 * 16, 6 * 8, 16}, "?"};
Text text_ch{{11 * 8, 5 * 16, 6 * 8, 16}, "?"};
Text text_batt{{11 * 8, 6 * 16, 6 * 8, 16}, "?"};
Text text_age{{11 * 8, 7 * 16, 6 * 8, 16}, "?"};
Text text_type{{10 * 8, 1 * 16, 15 * 8, 16}, "?"};
Text text_id{{10 * 8, 2 * 16, 10 * 8, 16}, "?"};
Text text_temp{{10 * 8, 3 * 16, 8 * 8, 16}, "?"};
Text text_hum{{10 * 8, 4 * 16, 6 * 8, 16}, "?"};
Text text_ch{{10 * 8, 5 * 16, 6 * 8, 16}, "?"};
Text text_batt{{10 * 8, 6 * 16, 6 * 8, 16}, "?"};
Text text_age{{10 * 8, 7 * 16, 10 * 8, 16}, "?"};
Labels labels{
{{0 * 8, 0 * 16}, "Weather station type:", Color::light_grey()},
{{0 * 8, 0 * 16}, "Weather Station", Color::light_grey()},
{{0 * 8, 1 * 16}, "Type:", Color::light_grey()},
{{0 * 8, 2 * 16}, "Id: ", Color::light_grey()},
{{0 * 8, 3 * 16}, "Temp:", Color::light_grey()},
{{0 * 8, 4 * 16}, "Humidity:", Color::light_grey()},
+2 -2
View File
@@ -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);
}
+1 -1
View File
@@ -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);
+52 -14
View File
@@ -1169,20 +1169,20 @@ static constexpr uint8_t bitmap_icon_tpms_data[] = {
0xEC,
0x37,
0x36,
0x6C,
0x1A,
0x58,
0x0B,
0xD0,
0x0B,
0xD0,
0x0B,
0xD0,
0x0B,
0xD0,
0x1A,
0x58,
0x36,
0x6D,
0x3A,
0x59,
0x4B,
0xD5,
0x8B,
0xD3,
0xCB,
0xD1,
0xAB,
0xD2,
0x9A,
0x5C,
0xB6,
0x6C,
0xEC,
0x37,
@@ -5721,6 +5721,44 @@ static constexpr Bitmap bitmap_icon_hide{
{16, 16},
bitmap_icon_hide_data};
static constexpr uint8_t bitmap_icon_thermometer_data[] = {
0xC0,
0x00,
0x20,
0x01,
0x10,
0x02,
0x10,
0x3A,
0x10,
0x02,
0x10,
0x1A,
0x10,
0x02,
0xD0,
0x3A,
0xD0,
0x02,
0xD0,
0x1A,
0xD0,
0x02,
0xE8,
0x05,
0xE8,
0x05,
0xC8,
0x04,
0x10,
0x02,
0xE0,
0x01,
};
static constexpr Bitmap bitmap_icon_thermometer{
{16, 16},
bitmap_icon_thermometer_data};
} /* namespace ui */
#endif /*__BITMAP_HPP__*/
+1
View File
@@ -113,6 +113,7 @@ void EventDispatcher::run() {
while (is_running) {
const auto events = wait();
dispatch(events);
portapack::usb_serial.dispatch();
}
}
+4 -3
View File
@@ -24,6 +24,7 @@
#define __UI_AFSK_RX_H__
#include "ui.hpp"
#include "ui_language.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "ui_freq_field.hpp"
@@ -92,16 +93,16 @@ class AFSKRxView : public View {
Checkbox check_log{
{0 * 8, 1 * 16},
3,
"LOG",
LanguageHelper::currentMessages[LANG_LOG],
false};
Text text_debug{
{0 * 8, 12 + 2 * 16, screen_width, 16},
"DEBUG"};
LanguageHelper::currentMessages[LANG_DEBUG]};
Button button_modem_setup{
{screen_width - 12 * 8, 1 * 16, 96, 24},
"Modem setup"};
LanguageHelper::currentMessages[LANG_MODEM_SETUP]};
Console console{
{0, 4 * 16, 240, screen_width}};
@@ -37,7 +37,7 @@ using namespace tonekey;
#include "string_format.hpp"
namespace ui {
namespace ui::external_app::analogtv {
/* AnalogTvView *******************************************************/
@@ -192,10 +192,11 @@ void AnalogTvView::update_modulation(const ReceiverModel::Mode modulation) {
baseband::shutdown();
portapack::spi_flash::image_tag_t image_tag;
image_tag = portapack::spi_flash::image_tag_am_tv;
// portapack::spi_flash::image_tag_t image_tag; //moved to ext app, disabled
// image_tag = portapack::spi_flash::image_tag_am_tv;
baseband::run_image(image_tag);
// baseband::run_image(image_tag);
baseband::run_prepared_image(portapack::memory::map::m4_code.base()); // moved the baseband too
receiver_model.set_modulation(modulation);
receiver_model.set_sampling_rate(2000000);
@@ -203,4 +204,4 @@ void AnalogTvView::update_modulation(const ReceiverModel::Mode modulation) {
receiver_model.enable();
}
} /* namespace ui */
} // namespace ui::external_app::analogtv
@@ -36,7 +36,7 @@
#include "tone_key.hpp"
namespace ui {
namespace ui::external_app::analogtv {
class AnalogTvView : public View {
public:
@@ -111,6 +111,6 @@ class AnalogTvView : public View {
void update_modulation(const ReceiverModel::Mode modulation);
};
} /* namespace ui */
} // namespace ui::external_app::analogtv
#endif /*__ANALOG_TV_APP_H__*/
+82
View File
@@ -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 "analog_tv_app.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::analogtv {
void initialize_app(ui::NavigationView& nav) {
nav.push<AnalogTvView>();
}
} // namespace ui::external_app::analogtv
extern "C" {
__attribute__((section(".external_app.app_analogtv.application_information"), used)) application_information_t _application_information_analogtv = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::analogtv::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "Analog TV",
/*.bitmap_data = */ {
0x00,
0x00,
0x00,
0x00,
0xFE,
0x7F,
0x03,
0xC0,
0x53,
0xD5,
0xAB,
0xCA,
0x53,
0xD5,
0xAB,
0xCA,
0x53,
0xD5,
0xAB,
0xCA,
0x53,
0xD5,
0x03,
0xC0,
0xFF,
0xFF,
0xFB,
0xD7,
0xFE,
0x7F,
0x00,
0x00,
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::RX,
/*.m4_app_tag = portapack::spi_flash::image_tag_am_tv */ {'P', 'A', 'M', 'T'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
+41 -23
View File
@@ -85,11 +85,11 @@ BLESpamView::BLESpamView(NavigationView& nav)
if (is_running) {
is_running = false;
stop();
button_startstop.set_text("Start");
button_startstop.set_text(LanguageHelper::currentMessages[LANG_START]);
} else {
is_running = true;
start();
button_startstop.set_text("Stop");
button_startstop.set_text(LanguageHelper::currentMessages[LANG_STOP]);
}
};
chk_randdev.set_value(true);
@@ -104,7 +104,7 @@ BLESpamView::BLESpamView(NavigationView& nav)
console.writeln("Based on work of:");
console.writeln("@Willy-JL, @ECTO-1A,");
console.writeln("@Spooks4576, @iNetro");
console.writeln("");
changePacket(true); // init
}
@@ -140,6 +140,15 @@ void BLESpamView::randomizeMac() {
mac[12] = '\0'; // Null-terminate the string
}
void BLESpamView::on_tx_progress(const bool done) {
if (done) {
if (is_running) {
changePacket(false);
baseband::set_btletx(channel_number, mac, advertisementData, pduType);
}
}
}
void BLESpamView::furi_hal_random_fill_buf(uint8_t* buf, uint32_t len) {
for (uint32_t i = 0; i < len; i += 4) {
const uint32_t random_val = rand();
@@ -473,23 +482,38 @@ void BLESpamView::createIosPacket(bool crash = false) {
}
void BLESpamView::createFastPairPacket() {
uint32_t model;
model = fastpairModels[rand() % fastpairModels_count].value;
uint32_t model = fastpairModels[rand() % fastpairModels_count].value;
uint8_t size = 14;
uint8_t* packet = (uint8_t*)malloc(size);
uint8_t i = 0;
packet[i++] = 3; // Size
packet[i++] = 0x03; // AD Type (Service UUID List)
packet[i++] = 0x2C; // Service UUID (Google LLC, FastPair)
packet[i++] = 0xFE; // ...
packet[i++] = 6; // Size
packet[i++] = 0x16; // AD Type (Service Data)
packet[i++] = 0x2C; // Service UUID (Google LLC, FastPair)
packet[i++] = 0xFE; // ...
packet[i++] = (model >> 0x10) & 0xFF; // Device Model
packet[i++] = (model >> 0x08) & 0xFF; // ...
packet[i++] = (model >> 0x00) & 0xFF; // ...
packet[i++] = 2; // Size
packet[i++] = 0x0A; // AD Type (Tx Power Level)
packet[i++] = (rand() % 120) - 100; // -100 to +20 dBm
// size, packet
std::string res = to_string_hex_array(packet, size);
memset(advertisementData, 0, sizeof(advertisementData));
// 0 0 6
const char* source = "03032CFE06162CFED5A59E020AB4\0";
memcpy(advertisementData, source, 28);
advertisementData[16] = uint_to_char((model >> 20) & 0x0F, 16);
advertisementData[17] = uint_to_char((model >> 16) & 0x0F, 16);
advertisementData[18] = uint_to_char((model >> 12) & 0x0F, 16);
advertisementData[19] = uint_to_char((model >> 8) & 0x0F, 16);
advertisementData[20] = uint_to_char((model >> 4) & 0x0F, 16);
advertisementData[21] = uint_to_char((model >> 0) & 0x0F, 16);
std::copy(res.begin(), res.end(), advertisementData);
free(packet);
}
void BLESpamView::changePacket(bool forced = false) {
counter++; // need to send it multiple times to be accepted
if (counter >= 3 || forced) {
if (counter >= 4 || forced) {
// really change packet and mac.
counter = 0;
randomizeMac();
@@ -516,21 +540,15 @@ void BLESpamView::changePacket(bool forced = false) {
}
// rate limit console display
displayCounter++;
if (displayCounter > 5) {
if (displayCounter > 25) {
displayCounter = 0;
console.writeln(advertisementData);
}
}
}
// called each 1/60th of second, so 6 = 100ms
void BLESpamView::on_timer() {
if (is_running) {
changePacket();
reset();
}
}
BLESpamView::~BLESpamView() {
is_running = false;
stop();
}
+9 -6
View File
@@ -28,6 +28,7 @@
#define __UI_BLESPAM_H__
#include "ui.hpp"
#include "ui_language.hpp"
#include "ui_navigation.hpp"
#include "ui_transmitter.hpp"
#include "ui_freq_field.hpp"
@@ -107,7 +108,7 @@ class BLESpamView : public View {
Button button_startstop{
{0, 3 * 16, 96, 24},
"Start"};
LanguageHelper::currentMessages[LANG_START]};
Checkbox chk_randdev{{100, 16}, 10, "Rnd device", true};
Console console{
@@ -145,17 +146,19 @@ class BLESpamView : public View {
void createSamsungPacket();
void createWindowsPacket();
void changePacket(bool forced);
void on_timer();
void on_tx_progress(const bool done);
uint64_t get_freq_by_channel_number(uint8_t channel_number);
void randomizeMac();
void randomChn();
void furi_hal_random_fill_buf(uint8_t* buf, uint32_t len);
MessageHandlerRegistration message_handler_frame_sync{
Message::ID::DisplayFrameSync,
[this](const Message* const) {
this->on_timer();
MessageHandlerRegistration message_handler_tx_progress{
Message::ID::TXProgress,
[this](const Message* const p) {
const auto message = *reinterpret_cast<const TXProgressMessage*>(p);
this->on_tx_progress(message.done);
}};
// continuity
+83
View File
@@ -0,0 +1,83 @@
/*
* 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_coasterp.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::coasterp {
void initialize_app(ui::NavigationView& nav) {
nav.push<CoasterPagerView>();
}
} // namespace ui::external_app::coasterp
extern "C" {
__attribute__((section(".external_app.app_coasterp.application_information"), used)) application_information_t _application_information_coasterp = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::coasterp::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "BurgerPgr",
/*.bitmap_data = */ {
0x00,
0x00,
0xE0,
0x07,
0xF8,
0x1F,
0xFC,
0x3F,
0xFE,
0x7F,
0xFF,
0xFF,
0xFF,
0xFF,
0x00,
0x00,
0x55,
0x55,
0xAA,
0xAA,
0x55,
0x55,
0x00,
0x00,
0xFF,
0xFF,
0xFF,
0xFF,
0xFE,
0x7F,
0x00,
0x00,
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::TX,
/*.m4_app_tag = portapack::spi_flash::image_tag_fsktx */ {'P', 'F', 'S', 'K'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -30,7 +30,7 @@
using namespace portapack;
namespace ui {
namespace ui::external_app::coasterp {
void CoasterPagerView::focus() {
sym_data.focus();
@@ -131,4 +131,4 @@ CoasterPagerView::CoasterPagerView(NavigationView& nav) {
};
}
} /* namespace ui */
} /* namespace ui::external_app::coasterp */
@@ -21,6 +21,7 @@
*/
#include "ui.hpp"
#include "ui_language.hpp"
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "ui_transmitter.hpp"
@@ -31,7 +32,7 @@
#include "radio_state.hpp"
#include "portapack.hpp"
namespace ui {
namespace ui::external_app::coasterp {
class CoasterPagerView : public View {
public:
@@ -65,7 +66,7 @@ class CoasterPagerView : public View {
Labels labels{
{{1 * 8, 3 * 8}, "Syscall pager TX beta", Color::light_grey()},
{{1 * 8, 8 * 8}, "Data:", Color::light_grey()}};
{{1 * 8, 8 * 8}, LanguageHelper::currentMessages[LANG_DATADP], Color::light_grey()}};
SymField sym_data{
{7 * 8, 8 * 8},
@@ -75,7 +76,7 @@ class CoasterPagerView : public View {
Checkbox checkbox_scan{
{10 * 8, 14 * 8},
4,
"Scan"};
LanguageHelper::currentMessages[LANG_SCAN]};
/*
ProgressBar progressbar {
@@ -99,4 +100,4 @@ class CoasterPagerView : public View {
}};
};
} /* namespace ui */
} /* namespace ui::external_app::coasterp */
+30
View File
@@ -19,7 +19,31 @@ set(EXTCPPSRC
#blespam
external/blespam/main.cpp
external/blespam/ui_blespam.cpp
#analogtv
external/analogtv/main.cpp
external/analogtv/analog_tv_app.cpp
#nrf_rx
external/nrf_rx/main.cpp
external/nrf_rx/ui_nrf_rx.cpp
#coasterp
external/coasterp/main.cpp
external/coasterp/ui_coasterp.cpp
#lge
external/lge/main.cpp
external/lge/lge_app.cpp
#lcr
external/lcr/main.cpp
external/lcr/ui_lcr.cpp
#lcr
external/jammer/main.cpp
external/jammer/ui_jammer.cpp
)
set(EXTAPPLIST
@@ -28,4 +52,10 @@ set(EXTAPPLIST
calculator
font_viewer
blespam
nrf_rx
analogtv
coasterp
lge
lcr
jammer
)
+46
View File
@@ -22,6 +22,12 @@ MEMORY
ram_external_app_calculator (rwx) : org = 0xEEEB0000, len = 32k
ram_external_app_font_viewer(rwx) : org = 0xEEEC0000, len = 32k
ram_external_app_blespam(rwx) : org = 0xEEED0000, len = 32k
ram_external_app_analogtv(rwx) : org = 0xEEEE0000, len = 32k
ram_external_app_nrf_rx(rwx) : org = 0xEEEF0000, len = 32k
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
@@ -56,4 +62,44 @@ SECTIONS
KEEP(*(.external_app.app_blespam.application_information));
*(*ui*external_app*blespam*);
} > ram_external_app_blespam
.external_app_analogtv : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_analogtv.application_information));
*(*ui*external_app*analogtv*);
} > ram_external_app_analogtv
.external_app_nrf_rx : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_nrf_rx.application_information));
*(*ui*external_app*nrf_rx*);
} > ram_external_app_nrf_rx
.external_app_coasterp : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_coasterp.application_information));
*(*ui*external_app*coasterp*);
} > ram_external_app_coasterp
.external_app_lge : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_lge.application_information));
*(*ui*external_app*lge*);
} > ram_external_app_lge
.external_app_lcr : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_lcr.application_information));
*(*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
View File
@@ -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
};
}
@@ -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
@@ -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
+82
View File
@@ -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_lcr.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::lcr {
void initialize_app(ui::NavigationView& nav) {
nav.push<LCRView>();
}
} // namespace ui::external_app::lcr
extern "C" {
__attribute__((section(".external_app.app_lcr.application_information"), used)) application_information_t _application_information_lcr = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::lcr::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "TEDI/LCR",
/*.bitmap_data = */ {
0x0C,
0x00,
0xFF,
0x7F,
0x01,
0x80,
0xC1,
0x9B,
0xFF,
0x7F,
0x0C,
0x00,
0xFF,
0x7F,
0x01,
0x80,
0xC1,
0x9D,
0xFF,
0x7F,
0x0C,
0x00,
0x0C,
0x00,
0x0C,
0x00,
0x0C,
0x00,
0x0C,
0x00,
0x0C,
0x00,
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::TX,
/*.m4_app_tag = portapack::spi_flash::image_tag_afsk */ {'P', 'A', 'F', 'T'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -23,7 +23,6 @@
#include "ui_lcr.hpp"
#include "ui_modemsetup.hpp"
#include "lcr.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
@@ -31,7 +30,7 @@
using namespace portapack;
namespace ui {
namespace ui::external_app::lcr {
void LCRView::focus() {
button_set_rgsb.focus();
@@ -42,6 +41,49 @@ LCRView::~LCRView() {
baseband::shutdown();
}
std::string LCRView::generate_message(std::string rgsb, std::vector<std::string> litterals, size_t option_ec) {
const std::string ec_lut[4] = {"A", "J", "N", "S"}; // Eclairage (Auto, Jour, Nuit)
char eom[3] = {3, 0, 0}; // EOM and space for checksum
uint8_t i;
std::string lcr_message{127, 127, 127, 127, 127, 127, 127, 5}; // 5/15 ? Modem sync and SOM
char checksum = 0;
// Pad litterals to 7 chars (not required ?)
for (auto& litteral : litterals)
while (litteral.length() < 7)
litteral += ' ';
// Compose LCR message
lcr_message += rgsb;
lcr_message += "PA ";
i = 1;
for (auto& litteral : litterals) {
lcr_message += "AM=";
lcr_message += to_string_dec_uint(i, 1);
lcr_message += " AF=\"";
lcr_message += litteral;
lcr_message += "\" CL=0 ";
i++;
}
lcr_message += "EC=";
lcr_message += ec_lut[option_ec];
lcr_message += " SAB=0";
// Checksum
i = 7; // Skip modem sync
while (lcr_message[i])
checksum ^= lcr_message[i++];
checksum ^= eom[0]; // EOM char
checksum &= 0x7F; // Trim
eom[1] = checksum;
lcr_message += eom;
return lcr_message;
}
/*
// Recap: frequency @ baudrate
final_str = to_string_short_freq(persistent_memory::tuned_frequency());
@@ -53,7 +95,7 @@ text_recap.set(final_str);*/
void LCRView::update_progress() {
if (tx_mode == IDLE) {
text_status.set("Ready");
text_status.set(LanguageHelper::currentMessages[LANG_READY]);
progress.set_value(0);
} else {
std::string progress_str = to_string_dec_uint(repeat_index) + "/" + to_string_dec_uint(persistent_memory::modem_repeat()) +
@@ -125,7 +167,7 @@ void LCRView::start_tx(const bool scan) {
litterals_list.push_back(litteral[i]);
}
modems::generate_data(lcr::generate_message(rgsb, litterals_list, options_ec.selected_index()), lcr_message_data);
modems::generate_data(generate_message(rgsb, litterals_list, options_ec.selected_index()), lcr_message_data);
/* It is AFSK modulation , measuring original fw 1.7.4 spectrum BW is just around 30khz , NBFM */
transmitter_model.set_baseband_bandwidth(1'750'000); // Min TX LPF 1M75, same spectrum as previous fw 1.7.4
@@ -269,4 +311,4 @@ LCRView::LCRView(NavigationView& nav) {
};
}
} /* namespace ui */
} /* namespace ui::external_app::lcr */
@@ -21,6 +21,7 @@
*/
#include "ui.hpp"
#include "ui_language.hpp"
#include "ui_widget.hpp"
#include "ui_textentry.hpp"
#include "ui_transmitter.hpp"
@@ -31,7 +32,7 @@
#include "app_settings.hpp"
#include "radio_state.hpp"
namespace ui {
namespace ui::external_app::lcr {
#define LCR_MAX_AM 5
@@ -101,6 +102,7 @@ class LCRView : public View {
void start_tx(const bool scan);
void on_tx_progress(const uint32_t progress, const bool done);
void on_button_set_am(NavigationView& nav, int16_t button_id);
std::string generate_message(std::string rgsb, std::vector<std::string> litterals, size_t option_ec);
Labels labels{
{{0, 8}, "EC: RGSB:", Color::light_grey()},
@@ -125,11 +127,11 @@ class LCRView : public View {
Checkbox check_scan{
{22 * 8, 4},
4,
"Scan"};
LanguageHelper::currentMessages[LANG_SCAN]};
Button button_modem_setup{
{1 * 8, 4 * 8 + 2, 14 * 8, 24},
"Modem setup"};
LanguageHelper::currentMessages[LANG_MODEM_SETUP]};
OptionsField options_scanlist{
{22 * 8, 4 * 8},
6,
@@ -137,11 +139,11 @@ class LCRView : public View {
Button button_clear{
{22 * 8, 8 * 8, 7 * 8, 19 * 8},
"CLEAR"};
LanguageHelper::currentMessages[LANG_CLEAR]};
Text text_status{
{2 * 8, 27 * 8 + 4, 26 * 8, 16},
"Ready"};
LanguageHelper::currentMessages[LANG_READY]};
ProgressBar progress{
{2 * 8, 29 * 8 + 4, 26 * 8, 16}};
@@ -158,4 +160,4 @@ class LCRView : public View {
}};
};
} /* namespace ui */
} /* namespace ui::external_app::lcr */
@@ -36,7 +36,7 @@
using namespace portapack;
namespace ui {
namespace ui::external_app::lge {
void LGEView::focus() {
options_frame.focus();
@@ -354,4 +354,4 @@ LGEView::LGEView(NavigationView& nav) {
};
}
} /* namespace ui */
} /* namespace ui::external_app::lge */
@@ -21,6 +21,7 @@
*/
#include "ui.hpp"
#include "ui_language.hpp"
#include "ui_widget.hpp"
#include "ui_navigation.hpp"
#include "ui_transmitter.hpp"
@@ -32,7 +33,7 @@
#include "app_settings.hpp"
#include "radio_state.hpp"
namespace ui {
namespace ui::external_app::lge {
class LGEView : public View {
public:
@@ -105,7 +106,7 @@ class LGEView : public View {
{"Set nickname", 1},
{"Set team", 2},
{"Brdcst nick", 3},
{"Start", 4},
{LanguageHelper::currentMessages[LANG_START], 4},
{"Game over", 5},
{"Set vest", 6}}};
@@ -185,4 +186,4 @@ class LGEView : public View {
}};
};
} /* namespace ui */
} /* namespace ui::external_app::lge */
+82
View File
@@ -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 "lge_app.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::lge {
void initialize_app(ui::NavigationView& nav) {
nav.push<LGEView>();
}
} // namespace ui::external_app::lge
extern "C" {
__attribute__((section(".external_app.app_lge.application_information"), used)) application_information_t _application_information_lge = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::lge::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "LGE",
/*.bitmap_data = */ {
0x00,
0x00,
0x80,
0x00,
0xA4,
0x12,
0xA8,
0x0A,
0xD0,
0x05,
0xEC,
0x1B,
0xF0,
0x07,
0xFE,
0xFF,
0xF0,
0x07,
0xEC,
0x1B,
0xD0,
0x05,
0xA8,
0x0A,
0xA4,
0x12,
0x80,
0x00,
0x00,
0x00,
0x00,
0x00,
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::TX,
/*.m4_app_tag = portapack::spi_flash::image_tag_fsktx */ {'P', 'F', 'S', 'K'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
+83
View File
@@ -0,0 +1,83 @@
/*
* 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_nrf_rx.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::nrf_rx {
void initialize_app(ui::NavigationView& nav) {
nav.push<NRFRxView>();
}
} // namespace ui::external_app::nrf_rx
extern "C" {
__attribute__((section(".external_app.app_nrf_rx.application_information"), used)) application_information_t _application_information_nrf_rx = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::nrf_rx::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "NRF",
/*.bitmap_data = */ {
0x00,
0x01,
0x00,
0x01,
0x00,
0x01,
0x00,
0x01,
0x00,
0x01,
0x00,
0x01,
0x00,
0x01,
0xF8,
0x3F,
0xFC,
0x7F,
0xFC,
0x7F,
0xDC,
0x7F,
0x8C,
0x6B,
0xDC,
0x7F,
0xFC,
0x7F,
0xFC,
0x7F,
0xF8,
0x3F,
},
/*.icon_color = */ ui::Color::yellow().v,
/*.menu_location = */ app_location_t::RX,
/*.m4_app_tag = portapack::spi_flash::image_tag_nrf_rx */ {'P', 'N', 'R', 'R'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
@@ -34,7 +34,7 @@
using namespace portapack;
using namespace modems;
namespace ui {
namespace ui::external_app::nrf_rx {
void NRFRxView::focus() {
field_frequency.focus();
@@ -42,7 +42,8 @@ void NRFRxView::focus() {
NRFRxView::NRFRxView(NavigationView& nav)
: nav_{nav} {
baseband::run_image(portapack::spi_flash::image_tag_nrf_rx);
// baseband::run_image(portapack::spi_flash::image_tag_nrf_rx);
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
add_children({&rssi,
&channel,
@@ -130,4 +131,4 @@ NRFRxView::~NRFRxView() {
baseband::shutdown();
}
} /* namespace ui */
} // namespace ui::external_app::nrf_rx
@@ -25,6 +25,7 @@
#define __UI_NRF_RX_H__
#include "ui.hpp"
#include "ui_language.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "ui_freq_field.hpp"
@@ -34,7 +35,7 @@
#include "utility.hpp"
namespace ui {
namespace ui::external_app::nrf_rx {
class NRFRxView : public View {
public:
@@ -77,7 +78,7 @@ class NRFRxView : public View {
Button button_modem_setup{
{240 - 12 * 8, 1 * 16, 96, 24},
"Modem setup"};
LanguageHelper::currentMessages[LANG_MODEM_SETUP]};
Console console{
{0, 4 * 16, 240, 240}};
@@ -90,6 +91,6 @@ class NRFRxView : public View {
}};
};
} /* namespace ui */
} /* namespace ui::external_app::nrf_rx */
#endif /*__UI_NRF_RX_H__*/
+1 -1
View File
@@ -285,7 +285,7 @@
* buffers.
*/
#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
#define SERIAL_BUFFERS_SIZE 16
#define SERIAL_BUFFERS_SIZE 64
#endif
/*===========================================================================*/
+23 -4
View File
@@ -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
+1
View File
@@ -56,6 +56,7 @@ namespace control {
namespace debug {
uint8_t switches();
void inject_switch(uint8_t);
} // namespace debug
} // namespace control
+4 -1
View File
@@ -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);
+2
View File
@@ -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;
-71
View File
@@ -1,71 +0,0 @@
/*
* Copyright (C) 2014 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 "lcr.hpp"
#include "string_format.hpp"
namespace lcr {
std::string generate_message(std::string rgsb, std::vector<std::string> litterals, size_t option_ec) {
const std::string ec_lut[4] = {"A", "J", "N", "S"}; // Eclairage (Auto, Jour, Nuit)
char eom[3] = {3, 0, 0}; // EOM and space for checksum
uint8_t i;
std::string lcr_message{127, 127, 127, 127, 127, 127, 127, 5}; // 5/15 ? Modem sync and SOM
char checksum = 0;
// Pad litterals to 7 chars (not required ?)
for (auto& litteral : litterals)
while (litteral.length() < 7)
litteral += ' ';
// Compose LCR message
lcr_message += rgsb;
lcr_message += "PA ";
i = 1;
for (auto& litteral : litterals) {
lcr_message += "AM=";
lcr_message += to_string_dec_uint(i, 1);
lcr_message += " AF=\"";
lcr_message += litteral;
lcr_message += "\" CL=0 ";
i++;
}
lcr_message += "EC=";
lcr_message += ec_lut[option_ec];
lcr_message += " SAB=0";
// Checksum
i = 7; // Skip modem sync
while (lcr_message[i])
checksum ^= lcr_message[i++];
checksum ^= eom[0]; // EOM char
checksum &= 0x7F; // Trim
eom[1] = checksum;
lcr_message += eom;
return lcr_message;
}
} /* namespace lcr */
+1 -1
View File
@@ -61,7 +61,7 @@ static constexpr SPIConfig ssp_config_max283x = {
.ssport = gpio_max283x_select.port(),
.sspad = gpio_max283x_select.pad(),
.cr0 =
CR0_CLOCKRATE(ssp_scr(ssp1_pclk_f, ssp1_cpsr, max283x_spi_f) + 1) | CR0_FRFSPI | CR0_DSS16BIT,
CR0_CLOCKRATE(ssp_scr(ssp1_pclk_f, ssp1_cpsr, max283x_spi_f) + 3) | CR0_FRFSPI | CR0_DSS16BIT,
.cpsr = ssp1_cpsr,
};
+16 -14
View File
@@ -38,7 +38,7 @@
#include "ui_aprs_tx.hpp"
#include "ui_bht_tx.hpp"
#include "ui_btle_rx.hpp"
#include "ui_coasterp.hpp"
// #include "ui_coasterp.hpp" //moved to ext
#include "ui_debug.hpp"
#include "ui_encoders.hpp"
#include "ui_fileman.hpp"
@@ -47,14 +47,14 @@
#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"
#include "ui_morse.hpp"
#include "ui_nrf_rx.hpp"
// #include "ui_nrf_rx.hpp" //moved to ext
// #include "ui_numbers.hpp"
// #include "ui_nuoptix.hpp"
// #include "ui_playdead.hpp"
@@ -80,20 +80,21 @@
#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"
// #include "acars_app.hpp"
#include "ais_app.hpp"
#include "analog_audio_app.hpp"
#include "analog_tv_app.hpp"
// #include "analog_tv_app.hpp" //moved to ext
#include "ble_comm_app.hpp"
#include "ble_rx_app.hpp"
#include "ble_tx_app.hpp"
#include "capture_app.hpp"
#include "ert_app.hpp"
#include "gps_sim_app.hpp"
#include "lge_app.hpp"
// #include "lge_app.hpp" //moved to ext
#include "pocsag_app.hpp"
#include "replay_app.hpp"
#include "soundboard_app.hpp"
@@ -552,7 +553,7 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
// {"ACARS", Color::yellow(), &bitmap_icon_adsb, [&nav](){ nav.push<ACARSAppView>(); }},
{"ADS-B", Color::green(), &bitmap_icon_adsb, [&nav]() { nav.push<ADSBRxView>(); }},
{"AIS Boats", Color::green(), &bitmap_icon_ais, [&nav]() { nav.push<AISAppView>(); }},
{"Analog TV", Color::yellow(), &bitmap_icon_sstv, [&nav]() { nav.push<AnalogTvView>(); }},
//{"Analog TV", Color::yellow(), &bitmap_icon_sstv, [&nav]() { nav.push<AnalogTvView>(); }}, //moved to ext
{"APRS", Color::green(), &bitmap_icon_aprs, [&nav]() { nav.push<APRSRXView>(); }},
{"Audio", Color::green(), &bitmap_icon_speaker, [&nav]() { nav.push<AnalogAudioView>(); }},
//{"BTLE", Color::yellow(), &bitmap_icon_btle, [&nav]() { nav.push<BTLERxView>(); }},
@@ -560,13 +561,14 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
{"BLE Rx", Color::green(), &bitmap_icon_btle, [&nav]() { nav.push<BLERxView>(); }},
{"ERT Meter", Color::green(), &bitmap_icon_ert, [&nav]() { nav.push<ERTAppView>(); }},
{"Level", Color::green(), &bitmap_icon_options_radio, [&nav]() { nav.push<LevelView>(); }},
{"NRF", Color::yellow(), &bitmap_icon_nrf, [&nav]() { nav.push<NRFRxView>(); }},
//{"NRF", Color::yellow(), &bitmap_icon_nrf, [&nav]() { nav.push<NRFRxView>(); }}, //moved to ext
{"POCSAG", Color::green(), &bitmap_icon_pocsag, [&nav]() { nav.push<POCSAGAppView>(); }},
{"Radiosnde", Color::green(), &bitmap_icon_sonde, [&nav]() { nav.push<SondeView>(); }},
{"Recon", Color::green(), &bitmap_icon_scanner, [&nav]() { nav.push<ReconView>(); }},
{"Search", Color::yellow(), &bitmap_icon_search, [&nav]() { nav.push<SearchView>(); }},
{"TPMS Cars", Color::green(), &bitmap_icon_tpms, [&nav]() { nav.push<TPMSAppView>(); }},
{"Weather", Color::yellow(), &bitmap_icon_lge, [&nav]() { nav.push<WeatherView>(); }},
{"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>(); }},
@@ -591,11 +593,11 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
{"APRS TX", ui::Color::green(), &bitmap_icon_aprs, [&nav]() { nav.push<APRSTXView>(); }},
{"BHT Xy/EP", ui::Color::green(), &bitmap_icon_bht, [&nav]() { nav.push<BHTView>(); }},
{"BLE Tx", ui::Color::green(), &bitmap_icon_btle, [&nav]() { nav.push<BLETxView>(); }},
{"BurgerPgr", ui::Color::yellow(), &bitmap_icon_burger, [&nav]() { nav.push<CoasterPagerView>(); }},
// {"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>(); }},
// {"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>(); }},
// { "Nuoptix DTMF", ui::Color::green(), &bitmap_icon_nuoptix, [&nav](){ nav.push<NuoptixView>(); }},
{"OOK", ui::Color::yellow(), &bitmap_icon_remote, [&nav]() { nav.push<EncodersView>(); }},
@@ -604,7 +606,7 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
{"Soundbrd", ui::Color::green(), &bitmap_icon_soundboard, [&nav]() { nav.push<SoundBoardView>(); }},
{"S.Painter", ui::Color::orange(), &bitmap_icon_paint, [&nav]() { nav.push<SpectrumPainterView>(); }},
{"SSTV", ui::Color::green(), &bitmap_icon_sstv, [&nav]() { nav.push<SSTVTXView>(); }},
{"TEDI/LCR", ui::Color::yellow(), &bitmap_icon_lcr, [&nav]() { nav.push<LCRView>(); }},
// {"TEDI/LCR", ui::Color::yellow(), &bitmap_icon_lcr, [&nav]() { nav.push<LCRView>(); }}, //moved to ext
{"TouchTune", ui::Color::green(), &bitmap_icon_touchtunes, [&nav]() { nav.push<TouchTunesView>(); }},
});
+97
View File
@@ -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
+48
View File
@@ -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
+143
View File
@@ -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;
}
+46
View File
@@ -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);
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* Copyright (C) 2023 Bernd Herzog
*
* This file is part of PortaPack.
*
@@ -20,18 +19,16 @@
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include <cstring>
#include <string>
#include <vector>
#include "usb_serial_event.hpp"
#ifndef __LCR_H__
#define __LCR_H__
#include "portapack.hpp"
namespace lcr {
extern "C" {
void on_channel_opened() {
portapack::usb_serial.on_channel_opened();
}
std::string generate_message(std::string rgsb, std::vector<std::string> litterals, size_t option_ec);
} /* namespace lcr */
#endif /*__LCR_H__*/
void on_channel_closed() {
portapack::usb_serial.on_channel_closed();
}
}
+34
View File
@@ -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
+144
View File
@@ -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);
}
+46
View File
@@ -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);
+510
View File
@@ -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);
}
+29
View File
@@ -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__*/
+30 -19
View File
@@ -347,12 +347,6 @@ set(MODE_CPPSRC
)
DeclareTargets(PAPR aprsrx)
### NRF RX
set(MODE_CPPSRC
proc_nrfrx.cpp
)
DeclareTargets(PNRR nrfrx)
### BTLE RX
@@ -382,12 +376,6 @@ set(MODE_CPPSRC
)
DeclareTargets(PAMA am_audio)
### AM TV
set(MODE_CPPSRC
proc_am_tv.cpp
)
DeclareTargets(PAMT am_tv)
### Audio transmit
@@ -431,12 +419,6 @@ set(MODE_CPPSRC
)
DeclareTargets(PFSR fskrx)
### Jammer
set(MODE_CPPSRC
proc_jammer.cpp
)
DeclareTargets(PJAM jammer)
### Microphone transmit
@@ -550,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
)
@@ -626,6 +615,28 @@ set(MODE_CPPSRC
)
DeclareTargets(PAFR afskrx)
### NRF RX
set(MODE_CPPSRC
proc_nrfrx.cpp
)
DeclareTargets(PNRR nrfrx)
### Jammer
set(MODE_CPPSRC
proc_jammer.cpp
)
DeclareTargets(PJAM jammer)
### AM TV
set(MODE_CPPSRC
proc_am_tv.cpp
)
DeclareTargets(PAMT am_tv)
### Test
set(MODE_CPPSRC
+200
View File
@@ -0,0 +1,200 @@
#ifndef __FPROTO_GENERAL_H__
#define __FPROTO_GENERAL_H__
// useful methods for both weather and subghzd
#include <stdint.h>
#include <stddef.h>
#define bit_read(value, bit) (((value) >> (bit)) & 0x01)
#define bit_set(value, bit) \
({ \
__typeof__(value) _one = (1); \
(value) |= (_one << (bit)); \
})
#define bit_clear(value, bit) \
({ \
__typeof__(value) _one = (1); \
(value) &= ~(_one << (bit)); \
})
#define bit_write(value, bit, bitvalue) (bitvalue ? bit_set(value, bit) : bit_clear(value, bit))
#define DURATION_DIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
typedef enum {
ManchesterStateStart1 = 0,
ManchesterStateMid1 = 1,
ManchesterStateMid0 = 2,
ManchesterStateStart0 = 3
} ManchesterState;
typedef enum {
ManchesterEventShortLow = 0,
ManchesterEventShortHigh = 2,
ManchesterEventLongLow = 4,
ManchesterEventLongHigh = 6,
ManchesterEventReset = 8
} ManchesterEvent;
class FProtoGeneral {
public:
static bool manchester_advance(
ManchesterState state,
ManchesterEvent event,
ManchesterState* next_state,
bool* data) {
bool result = false;
ManchesterState new_state;
if (event == ManchesterEventReset) {
new_state = ManchesterStateMid1;
} else {
new_state = (ManchesterState)(transitions[state] >> event & 0x3);
if (new_state == state) {
new_state = ManchesterStateMid1;
} else {
if (new_state == ManchesterStateMid0) {
if (data) *data = false;
result = true;
} else if (new_state == ManchesterStateMid1) {
if (data) *data = true;
result = true;
}
}
}
*next_state = new_state;
return result;
}
static uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t bit_count) {
uint8_t parity = 0;
for (uint8_t i = 0; i < bit_count; i++) {
parity += bit_read(key, i);
}
return parity & 0x01;
}
static uint8_t subghz_protocol_blocks_add_bytes(uint8_t const message[], size_t size) {
uint32_t result = 0;
for (size_t i = 0; i < size; ++i) {
result += message[i];
}
return (uint8_t)result;
}
static uint8_t subghz_protocol_blocks_parity8(uint8_t byte) {
byte ^= byte >> 4;
byte &= 0xf;
return (0x6996 >> byte) & 1;
}
static uint8_t subghz_protocol_blocks_parity_bytes(uint8_t const message[], size_t size) {
uint8_t result = 0;
for (size_t i = 0; i < size; ++i) {
result ^= subghz_protocol_blocks_parity8(message[i]);
}
return result;
}
static uint8_t subghz_protocol_blocks_lfsr_digest8(
uint8_t const message[],
size_t size,
uint8_t gen,
uint8_t key) {
uint8_t sum = 0;
for (size_t byte = 0; byte < size; ++byte) {
uint8_t data = message[byte];
for (int i = 7; i >= 0; --i) {
// XOR key into sum if data bit is set
if ((data >> i) & 1) sum ^= key;
// roll the key right (actually the LSB is dropped here)
// and apply the gen (needs to include the dropped LSB as MSB)
if (key & 1)
key = (key >> 1) ^ gen;
else
key = (key >> 1);
}
}
return sum;
}
static float locale_fahrenheit_to_celsius(float temp_f) {
return (temp_f - 32.f) / 1.8f;
}
static uint8_t subghz_protocol_blocks_crc4(
uint8_t const message[],
size_t size,
uint8_t polynomial,
uint8_t init) {
uint8_t remainder = init << 4; // LSBs are unused
uint8_t poly = polynomial << 4;
uint8_t bit;
while (size--) {
remainder ^= *message++;
for (bit = 0; bit < 8; bit++) {
if (remainder & 0x80) {
remainder = (remainder << 1) ^ poly;
} else {
remainder = (remainder << 1);
}
}
}
return remainder >> 4 & 0x0f; // discard the LSBs
}
static uint8_t subghz_protocol_blocks_lfsr_digest8_reflect(
uint8_t const message[],
size_t size,
uint8_t gen,
uint8_t key) {
uint8_t sum = 0;
// Process message from last byte to first byte (reflected)
for (int byte = size - 1; byte >= 0; --byte) {
uint8_t data = message[byte];
// Process individual bits of each byte (reflected)
for (uint8_t i = 0; i < 8; ++i) {
// XOR key into sum if data bit is set
if ((data >> i) & 1) {
sum ^= key;
}
// roll the key left (actually the LSB is dropped here)
// and apply the gen (needs to include the dropped lsb as MSB)
if (key & 0x80)
key = (key << 1) ^ gen;
else
key = (key << 1);
}
}
return sum;
}
static uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t bit_count) {
uint64_t reverse_key = 0;
for (uint8_t i = 0; i < bit_count; i++) {
reverse_key = reverse_key << 1 | bit_read(key, i);
}
return reverse_key;
}
static uint8_t subghz_protocol_blocks_crc8(
uint8_t const message[],
size_t size,
uint8_t polynomial,
uint8_t init) {
uint8_t remainder = init;
for (size_t byte = 0; byte < size; ++byte) {
remainder ^= message[byte];
for (uint8_t bit = 0; bit < 8; ++bit) {
if (remainder & 0x80) {
remainder = (remainder << 1) ^ polynomial;
} else {
remainder = (remainder << 1);
}
}
}
return remainder;
}
private:
static inline const uint8_t transitions[] = {0b00000001, 0b10010001, 0b10011011, 0b11111011};
};
#endif
@@ -0,0 +1,16 @@
#ifndef __FPROTO_PROTOLISTGENERAL_H__
#define __FPROTO_PROTOLISTGENERAL_H__
#include <stdint.h>
class FProtoListGeneral {
public:
FProtoListGeneral() {}
virtual ~FProtoListGeneral() {}
virtual void feed(bool level, uint32_t duration) = 0;
void setModulation(uint8_t modulation) { modulation_ = modulation; }
protected:
uint8_t modulation_ = 0;
};
#endif
+83
View File
@@ -0,0 +1,83 @@
#ifndef __FPROTO_BETT_H__
#define __FPROTO_BETT_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
BETTDecoderStepReset = 0,
BETTDecoderStepSaveDuration,
BETTDecoderStepCheckDuration,
} BETTDecoderStep;
class FProtoSubGhzDBett : public FProtoSubGhzDBase {
public:
FProtoSubGhzDBett() {
sensorType = FPS_BETT;
te_short = 340;
te_long = 2000;
te_delta = 150;
min_count_bit_for_found = 18;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case BETTDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 44) <
(te_delta * 15))) {
decode_data = 0;
decode_count_bit = 0;
parser_step = BETTDecoderStepCheckDuration;
}
break;
case BETTDecoderStepSaveDuration:
if (!level) {
if (DURATION_DIFF(duration, te_short * 44) <
(te_delta * 15)) {
if (decode_count_bit ==
min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
// dip decoder needed
if (callback) callback(this);
} else {
parser_step = BETTDecoderStepReset;
}
decode_data = 0;
decode_count_bit = 0;
break;
} else {
if ((DURATION_DIFF(duration, te_short) <
te_delta) ||
(DURATION_DIFF(duration, te_long) <
te_delta * 3)) {
parser_step = BETTDecoderStepCheckDuration;
} else {
parser_step = BETTDecoderStepReset;
}
}
}
break;
case BETTDecoderStepCheckDuration:
if (level) {
if (DURATION_DIFF(duration, te_long) <
te_delta * 3) {
subghz_protocol_blocks_add_bit(1);
parser_step = BETTDecoderStepSaveDuration;
} else if (
DURATION_DIFF(duration, te_short) <
te_delta) {
subghz_protocol_blocks_add_bit(0);
parser_step = BETTDecoderStepSaveDuration;
} else {
parser_step = BETTDecoderStepReset;
}
} else {
parser_step = BETTDecoderStepReset;
}
break;
}
}
};
#endif
+95
View File
@@ -0,0 +1,95 @@
#ifndef __FPROTO_CAME_H__
#define __FPROTO_CAME_H__
#include "subghzdbase.hpp"
#define CAME_12_COUNT_BIT 12
#define CAME_24_COUNT_BIT 24
#define PRASTEL_COUNT_BIT 25
#define AIRFORCE_COUNT_BIT 18
typedef enum : uint8_t {
CameDecoderStepReset = 0,
CameDecoderStepFoundStartBit,
CameDecoderStepSaveDuration,
CameDecoderStepCheckDuration,
} CameDecoderStep;
class FProtoSubGhzDCame : public FProtoSubGhzDBase {
public:
FProtoSubGhzDCame() {
sensorType = FPS_CAME;
te_short = 320;
te_long = 640;
te_delta = 150;
min_count_bit_for_found = 12;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case CameDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 56) < te_delta * 47)) {
// Found header CAME
parser_step = CameDecoderStepFoundStartBit;
}
break;
case CameDecoderStepFoundStartBit:
if (!level) {
break;
} else if (
DURATION_DIFF(duration, te_short) < te_delta) {
// Found start bit CAME
parser_step = CameDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = CameDecoderStepReset;
}
break;
case CameDecoderStepSaveDuration:
if (!level) { // save interval
if (duration >= (te_short * 4)) {
parser_step = CameDecoderStepFoundStartBit;
if ((decode_count_bit == min_count_bit_for_found) || (decode_count_bit == AIRFORCE_COUNT_BIT) ||
(decode_count_bit == PRASTEL_COUNT_BIT) || (decode_count_bit == CAME_24_COUNT_BIT)) {
serial = SD_NO_SERIAL;
btn = SD_NO_BTN;
data = decode_data;
data_count_bit = decode_count_bit;
// if flippa hacky, i hacky
sensorType = FPS_CAME;
if (decode_count_bit == PRASTEL_COUNT_BIT) sensorType = FPS_PRASTEL;
if (decode_count_bit == AIRFORCE_COUNT_BIT) sensorType = FPS_AIRFORCE;
if (callback) callback(this);
}
break;
}
te_last = duration;
parser_step = CameDecoderStepCheckDuration;
} else {
parser_step = CameDecoderStepReset;
}
break;
case CameDecoderStepCheckDuration:
if (level) {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
parser_step = CameDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = CameDecoderStepSaveDuration;
} else
parser_step = CameDecoderStepReset;
} else {
parser_step = CameDecoderStepReset;
}
break;
}
}
};
#endif
+133
View File
@@ -0,0 +1,133 @@
#ifndef __FPROTO_CAMEATOMO_H__
#define __FPROTO_CAMEATOMO_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
CameAtomoDecoderStepReset = 0,
CameAtomoDecoderStepDecoderData,
} CameAtomoDecoderStep;
class FProtoSubGhzDCameAtomo : public FProtoSubGhzDBase {
public:
FProtoSubGhzDCameAtomo() {
sensorType = FPS_CAMEATOMO;
te_short = 600;
te_long = 1200;
te_delta = 250;
min_count_bit_for_found = 62;
}
void feed(bool level, uint32_t duration) {
ManchesterEvent event = ManchesterEventReset;
switch (parser_step) {
case CameAtomoDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_long * 60) < te_delta * 40)) {
// Found header CAME
parser_step = CameAtomoDecoderStepDecoderData;
decode_data = 0;
decode_count_bit = 1;
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventShortLow, &manchester_saved_state, NULL);
}
break;
case CameAtomoDecoderStepDecoderData:
if (!level) {
if (DURATION_DIFF(duration, te_short) < te_delta) {
event = ManchesterEventShortLow;
} else if (
DURATION_DIFF(duration, te_long) < te_delta) {
event = ManchesterEventLongLow;
} else if (
duration >= ((uint32_t)te_long * 2 + te_delta)) {
if (decode_count_bit ==
min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller
data ^= 0xFFFFFFFFFFFFFFFF;
data <<= 4;
uint8_t pack[8] = {};
pack[0] = (data >> 56);
pack[1] = ((data >> 48) & 0xFF);
pack[2] = ((data >> 40) & 0xFF);
pack[3] = ((data >> 32) & 0xFF);
pack[4] = ((data >> 24) & 0xFF);
pack[5] = ((data >> 16) & 0xFF);
pack[6] = ((data >> 8) & 0xFF);
pack[7] = (data & 0xFF);
atomo_decrypt(pack);
cnt = (uint16_t)pack[1] << 8 | pack[2];
serial = (uint32_t)(pack[3]) << 24 | pack[4] << 16 | pack[5] << 8 | pack[6];
uint8_t btn_decode = (pack[7] >> 4);
if (btn_decode == 0x0) {
btn = 0x1;
} else if (btn_decode == 0x2) {
btn = 0x2;
} else if (btn_decode == 0x4) {
btn = 0x3;
} else if (btn_decode == 0x6) {
btn = 0x4;
}
if (callback) callback(this);
}
decode_data = 0;
decode_count_bit = 1;
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventShortLow, &manchester_saved_state, NULL);
} else {
parser_step = CameAtomoDecoderStepReset;
}
} else {
if (DURATION_DIFF(duration, te_short) < te_delta) {
event = ManchesterEventShortHigh;
} else if (
DURATION_DIFF(duration, te_long) < te_delta) {
event = ManchesterEventLongHigh;
} else {
parser_step = CameAtomoDecoderStepReset;
}
}
if (event != ManchesterEventReset) {
bool bit;
bool data_ok = FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &bit);
if (data_ok) {
decode_data = (decode_data << 1) | !bit;
decode_count_bit++;
}
}
break;
}
}
protected:
ManchesterState manchester_saved_state = ManchesterStateMid1;
void atomo_decrypt(uint8_t* buff) {
buff[0] = (buff[0] ^ 5) & 0x7F;
uint8_t tmpB = (-buff[0]) & 0x7F;
uint8_t bitCnt = 8;
while (bitCnt < 59) {
if ((tmpB & 0x18) && (((tmpB / 8) & 3) != 3)) {
tmpB = ((tmpB << 1) & 0xFF) | 1;
} else {
tmpB = (tmpB << 1) & 0xFF;
}
if (tmpB & 0x80) {
buff[bitCnt / 8] ^= (0x80 >> (bitCnt & 7));
}
bitCnt++;
}
}
};
#endif
+147
View File
@@ -0,0 +1,147 @@
#ifndef __FPROTO_CAMETWEE_H__
#define __FPROTO_CAMETWEE_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
CameTweeDecoderStepReset = 0,
CameTweeDecoderStepDecoderData,
} CameTweeDecoderStep;
class FProtoSubGhzDCameTwee : public FProtoSubGhzDBase {
public:
FProtoSubGhzDCameTwee() {
sensorType = FPS_CAMETWEE;
te_short = 500;
te_long = 1000;
te_delta = 250;
min_count_bit_for_found = 54;
}
void feed(bool level, uint32_t duration) {
ManchesterEvent event = ManchesterEventReset;
switch (parser_step) {
case CameTweeDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_long * 51) < te_delta * 20)) {
// Found header CAME
parser_step = CameTweeDecoderStepDecoderData;
decode_data = 0;
decode_count_bit = 0;
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongLow, &manchester_saved_state, NULL);
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongHigh, &manchester_saved_state, NULL);
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventShortLow, &manchester_saved_state, NULL);
}
break;
case CameTweeDecoderStepDecoderData:
if (!level) {
if (DURATION_DIFF(duration, te_short) < te_delta) {
event = ManchesterEventShortLow;
} else if (
DURATION_DIFF(duration, te_long) < te_delta) {
event = ManchesterEventLongLow;
} else if (
duration >= ((uint32_t)te_long * 2 + te_delta)) {
if (decode_count_bit == min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
subghz_protocol_came_twee_remote_controller();
if (callback) callback(this);
}
decode_data = 0;
decode_count_bit = 0;
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongLow, &manchester_saved_state, NULL);
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongHigh, &manchester_saved_state, NULL);
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventShortLow, &manchester_saved_state, NULL);
} else {
parser_step = CameTweeDecoderStepReset;
}
} else {
if (DURATION_DIFF(duration, te_short) < te_delta) {
event = ManchesterEventShortHigh;
} else if (
DURATION_DIFF(duration, te_long) < te_delta) {
event = ManchesterEventLongHigh;
} else {
parser_step = CameTweeDecoderStepReset;
}
}
if (event != ManchesterEventReset) {
bool bit;
if (FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &bit)) {
decode_data = (decode_data << 1) | !bit;
decode_count_bit++;
}
}
break;
}
}
protected:
ManchesterState manchester_saved_state = ManchesterStateMid1;
void subghz_protocol_came_twee_remote_controller() {
/* Came Twee 54 bit, rolling code 15 parcels with
* a decreasing counter from 0xE to 0x0
* with originally coded dip switches on the console 10 bit code
*
* 0x003FFF72E04A6FEE
* 0x003FFF72D17B5EDD
* 0x003FFF72C2684DCC
* 0x003FFF72B3193CBB
* 0x003FFF72A40E2BAA
* 0x003FFF72953F1A99
* 0x003FFF72862C0988
* 0x003FFF7277DDF877
* 0x003FFF7268C2E766
* 0x003FFF7259F3D655
* 0x003FFF724AE0C544
* 0x003FFF723B91B433
* 0x003FFF722C86A322
* 0x003FFF721DB79211
* 0x003FFF720EA48100
*
* decryption
* the last 32 bits, do XOR by the desired number, divide the result by 4,
* convert the first 16 bits of the resulting 32-bit number to bin and do
* bit-by-bit mirroring, adding up to 10 bits
*
* Example
* Step 1. 0x003FFF721DB79211 => 0x1DB79211
* Step 4. 0x1DB79211 xor 0x1D1D1D11 => 0x00AA8F00
* Step 4. 0x00AA8F00 / 4 => 0x002AA3C0
* Step 5. 0x002AA3C0 => 0x002A
* Step 6. 0x002A bin => b101010
* Step 7. b101010 => b0101010000
* Step 8. b0101010000 => (Dip) Off ON Off ON Off ON Off Off Off Off
*/
uint8_t cnt_parcel = (uint8_t)(data & 0xF);
serial = (uint32_t)(data & 0x0FFFFFFFF);
data = (data ^ came_twee_magic_numbers_xor[cnt_parcel]);
data /= 4;
btn = (data >> 4) & 0x0F;
data >>= 16;
data = (uint16_t)FProtoGeneral::subghz_protocol_blocks_reverse_key(data, 16);
cnt = data >> 6;
}
inline static const uint32_t came_twee_magic_numbers_xor[15] = {
0x0E0E0E00,
0x1D1D1D11,
0x2C2C2C22,
0x3B3B3B33,
0x4A4A4A44,
0x59595955,
0x68686866,
0x77777777,
0x86868688,
0x95959599,
0xA4A4A4AA,
0xB3B3B3BB,
0xC2C2C2CC,
0xD1D1D1DD,
0xE0E0E0EE,
};
};
#endif
+151
View File
@@ -0,0 +1,151 @@
#ifndef __FPROTO_CHAMBCODE_H__
#define __FPROTO_CHAMBCODE_H__
#include "subghzdbase.hpp"
#define CHAMBERLAIN_CODE_BIT_STOP 0b0001
#define CHAMBERLAIN_CODE_BIT_1 0b0011
#define CHAMBERLAIN_CODE_BIT_0 0b0111
#define CHAMBERLAIN_7_CODE_MASK 0xF000000FF0F
#define CHAMBERLAIN_8_CODE_MASK 0xF00000F00F
#define CHAMBERLAIN_9_CODE_MASK 0xF000000000F
#define CHAMBERLAIN_7_CODE_MASK_CHECK 0x10000001101
#define CHAMBERLAIN_8_CODE_MASK_CHECK 0x1000001001
#define CHAMBERLAIN_9_CODE_MASK_CHECK 0x10000000001
typedef enum : uint8_t {
Chamb_CodeDecoderStepReset = 0,
Chamb_CodeDecoderStepFoundStartBit,
Chamb_CodeDecoderStepSaveDuration,
Chamb_CodeDecoderStepCheckDuration,
} Chamb_CodeDecoderStep;
class FProtoSubGhzDChambCode : public FProtoSubGhzDBase {
public:
FProtoSubGhzDChambCode() {
sensorType = FPS_CHAMBCODE;
te_short = 1000;
te_long = 3000;
te_delta = 200;
min_count_bit_for_found = 10;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case Chamb_CodeDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 39) < te_delta * 20)) {
// Found header Chamb_Code
parser_step = Chamb_CodeDecoderStepFoundStartBit;
}
break;
case Chamb_CodeDecoderStepFoundStartBit:
if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
// Found start bit Chamb_Code
decode_data = 0;
decode_count_bit = 0;
decode_data = decode_data << 4 | CHAMBERLAIN_CODE_BIT_STOP;
decode_count_bit++;
parser_step = Chamb_CodeDecoderStepSaveDuration;
} else {
parser_step = Chamb_CodeDecoderStepReset;
}
break;
case Chamb_CodeDecoderStepSaveDuration:
if (!level) { // save interval
if (duration > te_short * 5) {
if (decode_count_bit >= min_count_bit_for_found) {
serial = SD_NO_SERIAL;
btn = SD_NO_BTN;
if (subghz_protocol_decoder_chamb_code_check_mask_and_parse()) {
data = decode_data;
data_count_bit = decode_count_bit;
if (callback) callback(this);
}
}
parser_step = Chamb_CodeDecoderStepReset;
} else {
te_last = duration;
parser_step = Chamb_CodeDecoderStepCheckDuration;
}
} else {
parser_step = Chamb_CodeDecoderStepReset;
}
break;
case Chamb_CodeDecoderStepCheckDuration:
if (level) { // Found stop bit Chamb_Code
if ((DURATION_DIFF(te_last, te_short * 3) <
te_delta) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
decode_data = decode_data << 4 | CHAMBERLAIN_CODE_BIT_STOP;
decode_count_bit++;
parser_step = Chamb_CodeDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_short * 2) < te_delta) &&
(DURATION_DIFF(duration, te_short * 2) < te_delta)) {
decode_data = decode_data << 4 | CHAMBERLAIN_CODE_BIT_1;
decode_count_bit++;
parser_step = Chamb_CodeDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_short * 3) < te_delta)) {
decode_data = decode_data << 4 | CHAMBERLAIN_CODE_BIT_0;
decode_count_bit++;
parser_step = Chamb_CodeDecoderStepSaveDuration;
} else {
parser_step = Chamb_CodeDecoderStepReset;
}
} else {
parser_step = Chamb_CodeDecoderStepReset;
}
break;
}
}
protected:
bool subghz_protocol_decoder_chamb_code_check_mask_and_parse() {
if (decode_count_bit > min_count_bit_for_found + 1)
return false;
if ((decode_data & CHAMBERLAIN_7_CODE_MASK) == CHAMBERLAIN_7_CODE_MASK_CHECK) {
decode_count_bit = 7;
decode_data &= ~CHAMBERLAIN_7_CODE_MASK;
decode_data = (decode_data >> 12) | ((decode_data >> 4) & 0xF);
} else if (
(decode_data & CHAMBERLAIN_8_CODE_MASK) == CHAMBERLAIN_8_CODE_MASK_CHECK) {
decode_count_bit = 8;
decode_data &= ~CHAMBERLAIN_8_CODE_MASK;
decode_data = decode_data >> 4 | CHAMBERLAIN_CODE_BIT_0 << 8; // DIP 6 no use
} else if (
(decode_data & CHAMBERLAIN_9_CODE_MASK) == CHAMBERLAIN_9_CODE_MASK_CHECK) {
decode_count_bit = 9;
decode_data &= ~CHAMBERLAIN_9_CODE_MASK;
decode_data >>= 4;
} else {
return false;
}
return subghz_protocol_chamb_code_to_bit(&decode_data, decode_count_bit);
}
bool subghz_protocol_chamb_code_to_bit(uint64_t* data, uint8_t size) {
uint64_t data_tmp = data[0];
uint64_t data_res = 0;
for (uint8_t i = 0; i < size; i++) {
if ((data_tmp & 0xFll) == CHAMBERLAIN_CODE_BIT_0) {
bit_write(data_res, i, 0);
} else if ((data_tmp & 0xFll) == CHAMBERLAIN_CODE_BIT_1) {
bit_write(data_res, i, 1);
} else {
return false;
}
data_tmp >>= 4;
}
data[0] = data_res;
return true;
}
};
#endif
+89
View File
@@ -0,0 +1,89 @@
#ifndef __FPROTO_CLEMSA_H__
#define __FPROTO_CLEMSA_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
ClemsaDecoderStepReset = 0,
ClemsaDecoderStepSaveDuration,
ClemsaDecoderStepCheckDuration,
} ClemsaDecoderStep;
class FProtoSubGhzDClemsa : public FProtoSubGhzDBase {
public:
FProtoSubGhzDClemsa() {
sensorType = FPS_CLEMSA;
te_short = 385;
te_long = 2695;
te_delta = 150;
min_count_bit_for_found = 18;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case ClemsaDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 51) < te_delta * 25)) {
parser_step = ClemsaDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
}
break;
case ClemsaDecoderStepSaveDuration:
if (level) {
te_last = duration;
parser_step = ClemsaDecoderStepCheckDuration;
} else {
parser_step = ClemsaDecoderStepReset;
}
break;
case ClemsaDecoderStepCheckDuration:
if (!level) {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta * 3)) {
subghz_protocol_blocks_add_bit(0);
parser_step = ClemsaDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta * 3) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = ClemsaDecoderStepSaveDuration;
} else if (
DURATION_DIFF(duration, te_short * 51) < te_delta * 25) {
if ((DURATION_DIFF(te_last, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
} else if ((DURATION_DIFF(te_last, te_long) < te_delta * 3)) {
subghz_protocol_blocks_add_bit(1);
} else {
parser_step = ClemsaDecoderStepReset;
}
if (decode_count_bit ==
min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller
serial = (data >> 2) & 0xFFFF;
btn = (data & 0x03);
if (callback) callback(this);
}
parser_step = ClemsaDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = ClemsaDecoderStepReset;
}
} else {
parser_step = ClemsaDecoderStepReset;
}
break;
}
}
};
#endif
+86
View File
@@ -0,0 +1,86 @@
#ifndef __FPROTO_DOITRAND_H__
#define __FPROTO_DOITRAND_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
DoitrandDecoderStepReset = 0,
DoitrandDecoderStepFoundStartBit,
DoitrandDecoderStepSaveDuration,
DoitrandDecoderStepCheckDuration,
} DoitrandDecoderStep;
class FProtoSubGhzDDoitrand : public FProtoSubGhzDBase {
public:
FProtoSubGhzDDoitrand() {
sensorType = FPS_DOITRAND;
te_short = 400;
te_long = 1100;
te_delta = 150;
min_count_bit_for_found = 37;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case DoitrandDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 62) < te_delta * 30)) {
// Found Preambula
parser_step = DoitrandDecoderStepFoundStartBit;
}
break;
case DoitrandDecoderStepFoundStartBit:
if (level && ((DURATION_DIFF(duration, (te_short * 2)) < te_delta * 3))) {
// Found start bit
parser_step = DoitrandDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = DoitrandDecoderStepReset;
}
break;
case DoitrandDecoderStepSaveDuration:
if (!level) {
if (duration >= ((uint32_t)te_short * 10 + te_delta)) {
parser_step = DoitrandDecoderStepFoundStartBit;
if (decode_count_bit == min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller
cnt = (data >> 24) | ((data >> 15) & 0x1);
btn = ((data >> 18) & 0x3);
if (callback) callback(this);
}
decode_data = 0;
decode_count_bit = 0;
break;
} else {
te_last = duration;
parser_step = DoitrandDecoderStepCheckDuration;
}
}
break;
case DoitrandDecoderStepCheckDuration:
if (level) {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta * 3)) {
subghz_protocol_blocks_add_bit(0);
parser_step = DoitrandDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta * 3) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = DoitrandDecoderStepSaveDuration;
} else {
parser_step = DoitrandDecoderStepReset;
}
} else {
parser_step = DoitrandDecoderStepReset;
}
break;
}
}
};
#endif
+111
View File
@@ -0,0 +1,111 @@
#ifndef __FPROTO_DOOYA_H__
#define __FPROTO_DOOYA_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
DooyaDecoderStepReset = 0,
DooyaDecoderStepFoundStartBit,
DooyaDecoderStepSaveDuration,
DooyaDecoderStepCheckDuration,
} DooyaDecoderStep;
class FProtoSubGhzDDooya : public FProtoSubGhzDBase {
public:
FProtoSubGhzDDooya() {
sensorType = FPS_DOOYA;
te_short = 366;
te_long = 733;
te_delta = 120;
min_count_bit_for_found = 40;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case DooyaDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_long * 12) < te_delta * 20)) {
parser_step = DooyaDecoderStepFoundStartBit;
}
break;
case DooyaDecoderStepFoundStartBit:
if (!level) {
if (DURATION_DIFF(duration, te_long * 2) < te_delta * 3) {
parser_step = DooyaDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = DooyaDecoderStepReset;
}
} else if (
DURATION_DIFF(duration, te_short * 13) < te_delta * 5) {
break;
} else {
parser_step = DooyaDecoderStepReset;
}
break;
case DooyaDecoderStepSaveDuration:
if (level) {
te_last = duration;
parser_step = DooyaDecoderStepCheckDuration;
} else {
parser_step = DooyaDecoderStepReset;
}
break;
case DooyaDecoderStepCheckDuration:
if (!level) {
if (duration >= (te_long * 4)) {
// add last bit
if (DURATION_DIFF(te_last, te_short) < te_delta) {
subghz_protocol_blocks_add_bit(0);
} else if (
DURATION_DIFF(te_last, te_long) <
te_delta * 2) {
subghz_protocol_blocks_add_bit(1);
} else {
parser_step = DooyaDecoderStepReset;
break;
}
parser_step = DooyaDecoderStepFoundStartBit;
if (decode_count_bit ==
min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller:
serial = (data >> 16);
if ((data >> 12) & 0x0F) {
cnt = (data >> 8) & 0x0F;
} else {
cnt = 0xFF;
}
btn = data & 0xFF;
if (callback) callback(this);
}
break;
} else if (
(DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta * 2)) {
subghz_protocol_blocks_add_bit(0);
parser_step = DooyaDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta * 2) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = DooyaDecoderStepSaveDuration;
} else {
parser_step = DooyaDecoderStepReset;
}
} else {
parser_step = DooyaDecoderStepReset;
}
break;
}
}
};
#endif
+85
View File
@@ -0,0 +1,85 @@
#ifndef __FPROTO_FAAC_H__
#define __FPROTO_FAAC_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
FaacSLHDecoderStepReset = 0,
FaacSLHDecoderStepFoundPreambula,
FaacSLHDecoderStepSaveDuration,
FaacSLHDecoderStepCheckDuration,
} FaacSLHDecoderStep;
class FProtoSubGhzDFaac : public FProtoSubGhzDBase {
public:
FProtoSubGhzDFaac() {
sensorType = FPS_FAAC;
te_short = 255;
te_long = 595;
te_delta = 100;
min_count_bit_for_found = 64;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case FaacSLHDecoderStepReset:
if ((level) && (DURATION_DIFF(duration, te_long * 2) < te_delta * 3)) {
parser_step = FaacSLHDecoderStepFoundPreambula;
}
break;
case FaacSLHDecoderStepFoundPreambula:
if ((!level) && (DURATION_DIFF(duration, te_long * 2) < te_delta * 3)) {
// Found Preambula
parser_step = FaacSLHDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = FaacSLHDecoderStepReset;
}
break;
case FaacSLHDecoderStepSaveDuration:
if (level) {
if (duration >= ((uint32_t)te_short * 3 + te_delta)) {
parser_step = FaacSLHDecoderStepFoundPreambula;
if (decode_count_bit == min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
// remark controller skipped
if (callback) callback(this);
}
decode_data = 0;
decode_count_bit = 0;
break;
} else {
te_last = duration;
parser_step = FaacSLHDecoderStepCheckDuration;
}
} else {
parser_step = FaacSLHDecoderStepReset;
}
break;
case FaacSLHDecoderStepCheckDuration:
if (!level) {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
parser_step = FaacSLHDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = FaacSLHDecoderStepSaveDuration;
} else {
parser_step = FaacSLHDecoderStepReset;
}
} else {
parser_step = FaacSLHDecoderStepReset;
}
break;
}
}
};
#endif
+88
View File
@@ -0,0 +1,88 @@
#ifndef __FPROTO_GATETX_H__
#define __FPROTO_GATETX_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
GateTXDecoderStepReset = 0,
GateTXDecoderStepFoundStartBit,
GateTXDecoderStepSaveDuration,
GateTXDecoderStepCheckDuration,
} GateTXDecoderStep;
class FProtoSubGhzDGateTx : public FProtoSubGhzDBase {
public:
FProtoSubGhzDGateTx() {
sensorType = FPS_GATETX;
te_short = 350;
te_long = 700;
te_delta = 100;
min_count_bit_for_found = 24;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case GateTXDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 47) < te_delta * 47)) {
// Found Preambula
parser_step = GateTXDecoderStepFoundStartBit;
}
break;
case GateTXDecoderStepFoundStartBit:
if (level && ((DURATION_DIFF(duration, te_long) < te_delta * 3))) {
// Found start bit
parser_step = GateTXDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = GateTXDecoderStepReset;
}
break;
case GateTXDecoderStepSaveDuration:
if (!level) {
if (duration >= ((uint32_t)te_short * 10 + te_delta)) {
parser_step = GateTXDecoderStepFoundStartBit;
if (decode_count_bit == min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller
uint32_t code_found_reverse = FProtoGeneral::subghz_protocol_blocks_reverse_key(data, data_count_bit);
serial = (code_found_reverse & 0xFF) << 12 | ((code_found_reverse >> 8) & 0xFF) << 4 | ((code_found_reverse >> 20) & 0x0F);
btn = ((code_found_reverse >> 16) & 0x0F);
if (callback) callback(this);
}
decode_data = 0;
decode_count_bit = 0;
break;
} else {
te_last = duration;
parser_step = GateTXDecoderStepCheckDuration;
}
}
break;
case GateTXDecoderStepCheckDuration:
if (level) {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta * 3)) {
subghz_protocol_blocks_add_bit(0);
parser_step = GateTXDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta * 3) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = GateTXDecoderStepSaveDuration;
} else {
parser_step = GateTXDecoderStepReset;
}
} else {
parser_step = GateTXDecoderStepReset;
}
break;
}
}
};
#endif
+107
View File
@@ -0,0 +1,107 @@
#ifndef __FPROTO_HOLTEK_H__
#define __FPROTO_HOLTEK_H__
#include "subghzdbase.hpp"
#define HOLTEK_HEADER_MASK 0xF000000000
#define HOLTEK_HEADER 0x5000000000
typedef enum : uint8_t {
HoltekDecoderStepReset = 0,
HoltekDecoderStepFoundStartBit,
HoltekDecoderStepSaveDuration,
HoltekDecoderStepCheckDuration,
} HoltekDecoderStep;
class FProtoSubGhzDHoltek : public FProtoSubGhzDBase {
public:
FProtoSubGhzDHoltek() {
sensorType = FPS_HOLTEK;
te_short = 430;
te_long = 870;
te_delta = 100;
min_count_bit_for_found = 40;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case HoltekDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 36) < te_delta * 36)) {
// Found Preambula
parser_step = HoltekDecoderStepFoundStartBit;
}
break;
case HoltekDecoderStepFoundStartBit:
if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
// Found StartBit
parser_step = HoltekDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = HoltekDecoderStepReset;
}
break;
case HoltekDecoderStepSaveDuration:
// save duration
if (!level) {
if (duration >= ((uint32_t)te_short * 10 + te_delta)) {
if (decode_count_bit ==
min_count_bit_for_found) {
if ((decode_data & HOLTEK_HEADER_MASK) == HOLTEK_HEADER) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller
serial = FProtoGeneral::subghz_protocol_blocks_reverse_key((data >> 16) & 0xFFFFF, 20);
uint16_t btn = data & 0xFFFF;
if ((btn & 0xf) != 0xA) {
btn = 0x1 << 4 | (btn & 0xF);
} else if (((btn >> 4) & 0xF) != 0xA) {
btn = 0x2 << 4 | ((btn >> 4) & 0xF);
} else if (((btn >> 8) & 0xF) != 0xA) {
btn = 0x3 << 4 | ((btn >> 8) & 0xF);
} else if (((btn >> 12) & 0xF) != 0xA) {
btn = 0x4 << 4 | ((btn >> 12) & 0xF);
} else {
btn = 0;
}
if (callback) callback(this);
}
}
decode_data = 0;
decode_count_bit = 0;
parser_step = HoltekDecoderStepFoundStartBit;
break;
} else {
te_last = duration;
parser_step = HoltekDecoderStepCheckDuration;
}
} else {
parser_step = HoltekDecoderStepReset;
}
break;
case HoltekDecoderStepCheckDuration:
if (level) {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta * 2)) {
subghz_protocol_blocks_add_bit(0);
parser_step = HoltekDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta * 2) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = HoltekDecoderStepSaveDuration;
} else {
parser_step = HoltekDecoderStepReset;
}
} else {
parser_step = HoltekDecoderStepReset;
}
break;
}
}
};
#endif
@@ -0,0 +1,90 @@
#ifndef __FPROTO_HOLTEKTH12X_H__
#define __FPROTO_HOLTEKTH12X_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
Holtek_HT12XDecoderStepReset = 0,
Holtek_HT12XDecoderStepFoundStartBit,
Holtek_HT12XDecoderStepSaveDuration,
Holtek_HT12XDecoderStepCheckDuration,
} Holtek_HT12XDecoderStep;
class FProtoSubGhzDHoltekHt12x : public FProtoSubGhzDBase {
public:
FProtoSubGhzDHoltekHt12x() {
sensorType = FPS_HOLTEKHT12X;
te_short = 320;
te_long = 640;
te_delta = 200;
min_count_bit_for_found = 12;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case Holtek_HT12XDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 36) < te_delta * 36)) {
// Found Preambula
parser_step = Holtek_HT12XDecoderStepFoundStartBit;
}
break;
case Holtek_HT12XDecoderStepFoundStartBit:
if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
// Found StartBit
parser_step = Holtek_HT12XDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = Holtek_HT12XDecoderStepReset;
}
break;
case Holtek_HT12XDecoderStepSaveDuration:
// save duration
if (!level) {
if (duration >= ((uint32_t)te_short * 10 + te_delta)) {
if (decode_count_bit == min_count_bit_for_found) {
if (data != decode_data) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller
btn = data & 0x0F;
cnt = (data >> 4) & 0xFF;
if (callback) callback(this);
}
}
decode_data = 0;
decode_count_bit = 0;
parser_step = Holtek_HT12XDecoderStepFoundStartBit;
break;
} else {
te_last = duration;
parser_step = Holtek_HT12XDecoderStepCheckDuration;
}
} else {
parser_step = Holtek_HT12XDecoderStepReset;
}
break;
case Holtek_HT12XDecoderStepCheckDuration:
if (level) {
if ((DURATION_DIFF(te_last, te_long) < te_delta * 2) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = Holtek_HT12XDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta * 2)) {
subghz_protocol_blocks_add_bit(0);
parser_step = Holtek_HT12XDecoderStepSaveDuration;
} else {
parser_step = Holtek_HT12XDecoderStepReset;
}
} else {
parser_step = Holtek_HT12XDecoderStepReset;
}
break;
}
}
};
#endif
+108
View File
@@ -0,0 +1,108 @@
#ifndef __FPROTO_HONEYWELL_H__
#define __FPROTO_HONEYWELL_H__
#include "subghzdbase.hpp"
class FProtoSubGhzDHoneywell : public FProtoSubGhzDBase {
public:
FProtoSubGhzDHoneywell() {
sensorType = FPS_HONEYWELL;
te_short = 280;
te_long = 143;
te_delta = 51;
min_count_bit_for_found = 62;
}
void feed(bool level, uint32_t duration) {
ManchesterEvent event = ManchesterEventReset;
if (!level) {
if (DURATION_DIFF(duration, te_short) < te_delta) {
event = ManchesterEventShortLow;
} else if (
DURATION_DIFF(duration, te_long) < te_delta * 2) {
event = ManchesterEventLongLow;
}
} else {
if (DURATION_DIFF(duration, te_short) < te_delta) {
event = ManchesterEventShortHigh;
} else if (
DURATION_DIFF(duration, te_long) < te_delta * 2) {
event = ManchesterEventLongHigh;
}
}
if (event != ManchesterEventReset) {
bool bit;
bool data_ok = FProtoGeneral::manchester_advance(
manchester_saved_state, event, &manchester_saved_state, &bit);
if (data_ok) {
subghz_protocol_decoder_honeywell_addbit(bit);
}
} else {
decode_data = 0;
decode_count_bit = 0;
}
}
protected:
ManchesterState manchester_saved_state = ManchesterStateMid1;
void subghz_protocol_decoder_honeywell_addbit(bool bit) {
decode_data = (decode_data << 1) | bit;
decode_count_bit++;
uint16_t preamble = (decode_data >> 48) & 0xFFFF;
// can be multiple, since flipper can't read it well..
if (preamble == 0b0011111111111110 || preamble == 0b0111111111111110 ||
preamble == 0b1111111111111110) {
uint8_t datatocrc[4];
datatocrc[0] = (decode_data >> 40) & 0xFFFF;
datatocrc[1] = (decode_data >> 32) & 0xFFFF;
datatocrc[2] = (decode_data >> 24) & 0xFFFF;
datatocrc[3] = (decode_data >> 16) & 0xFFFF;
uint8_t channel = (decode_data >> 44) & 0xF;
uint16_t crc_calc = 0;
if (channel == 0x2 || channel == 0x4 || channel == 0xA) {
// 2GIG brand
crc_calc = subghz_protocol_honeywell_crc16(datatocrc, 4, 0x8050, 0);
} else { // channel == 0x8
crc_calc = subghz_protocol_honeywell_crc16(datatocrc, 4, 0x8005, 0);
}
uint16_t crc = decode_data & 0xFFFF;
if (crc == crc_calc) {
// the data is good. process it.
data = decode_data;
data_count_bit = decode_count_bit; // maybe set it to 64, and hack the first 2 bits to 1! will see if replay needs it
serial = (decode_data >> 24) & 0xFFFFF;
btn = (decode_data >> 16) & 0xFF; // not exactly button, but can contain btn data too.
if (callback) callback(this);
decode_data = 0;
decode_count_bit = 0;
} else {
return;
}
}
}
uint16_t subghz_protocol_honeywell_crc16(
uint8_t const message[],
unsigned nBytes,
uint16_t polynomial,
uint16_t init) {
uint16_t remainder = init;
unsigned byte, bit;
for (byte = 0; byte < nBytes; ++byte) {
remainder ^= message[byte] << 8;
for (bit = 0; bit < 8; ++bit) {
if (remainder & 0x8000) {
remainder = (remainder << 1) ^ polynomial;
} else {
remainder = (remainder << 1);
}
}
}
return remainder;
}
};
#endif
@@ -0,0 +1,74 @@
#ifndef __FPROTO_HONEYWELLWDB_H__
#define __FPROTO_HONEYWELLWDB_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
Honeywell_WDBDecoderStepReset = 0,
Honeywell_WDBDecoderStepFoundStartBit,
Honeywell_WDBDecoderStepSaveDuration,
Honeywell_WDBDecoderStepCheckDuration,
} Honeywell_WDBDecoderStep;
class FProtoSubGhzDHoneywellWdb : public FProtoSubGhzDBase {
public:
FProtoSubGhzDHoneywellWdb() {
sensorType = FPS_HONEYWELLWDB;
te_short = 160;
te_long = 320;
te_delta = 61;
min_count_bit_for_found = 48;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case Honeywell_WDBDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 3) < te_delta)) {
// Found header Honeywell_WDB
decode_count_bit = 0;
decode_data = 0;
parser_step = Honeywell_WDBDecoderStepSaveDuration;
}
break;
case Honeywell_WDBDecoderStepSaveDuration:
if (level) { // save interval
if (DURATION_DIFF(duration, te_short * 3) < te_delta) {
if ((decode_count_bit == min_count_bit_for_found) &&
((decode_data & 0x01) == FProtoGeneral::subghz_protocol_blocks_get_parity(decode_data >> 1, min_count_bit_for_found - 1))) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller has too much, should be done on ui side
if (callback) callback(this);
}
parser_step = Honeywell_WDBDecoderStepReset;
break;
}
te_last = duration;
parser_step = Honeywell_WDBDecoderStepCheckDuration;
} else {
parser_step = Honeywell_WDBDecoderStepReset;
}
break;
case Honeywell_WDBDecoderStepCheckDuration:
if (!level) {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
parser_step = Honeywell_WDBDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = Honeywell_WDBDecoderStepSaveDuration;
} else
parser_step = Honeywell_WDBDecoderStepReset;
} else {
parser_step = Honeywell_WDBDecoderStepReset;
}
break;
}
}
};
#endif
+85
View File
@@ -0,0 +1,85 @@
#ifndef __FPROTO_HORMANN_H__
#define __FPROTO_HORMANN_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
HormannDecoderStepReset = 0,
HormannDecoderStepFoundStartHeader,
HormannDecoderStepFoundHeader,
HormannDecoderStepFoundStartBit,
HormannDecoderStepSaveDuration,
HormannDecoderStepCheckDuration,
} HormannDecoderStep;
#define HORMANN_HSM_PATTERN 0xFF000000003
class FProtoSubGhzDHormann : public FProtoSubGhzDBase {
public:
FProtoSubGhzDHormann() {
sensorType = FPS_HORMANN;
te_short = 500;
te_long = 1000;
te_delta = 200;
min_count_bit_for_found = 44;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case HormannDecoderStepReset:
if ((level) && (DURATION_DIFF(duration, te_short * 24) < te_delta * 24)) {
parser_step = HormannDecoderStepFoundStartBit;
}
break;
case HormannDecoderStepFoundStartBit:
if ((!level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
parser_step = HormannDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = HormannDecoderStepReset;
}
break;
case HormannDecoderStepSaveDuration:
if (level) { // save interval
if (duration >= (te_short * 5) && (decode_data & HORMANN_HSM_PATTERN) == HORMANN_HSM_PATTERN) {
parser_step = HormannDecoderStepFoundStartBit;
if (decode_count_bit >=
min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller
btn = (data >> 4) & 0xF;
if (callback) callback(this);
}
break;
}
te_last = duration;
parser_step = HormannDecoderStepCheckDuration;
} else {
parser_step = HormannDecoderStepReset;
}
break;
case HormannDecoderStepCheckDuration:
if (!level) {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
parser_step = HormannDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = HormannDecoderStepSaveDuration;
} else
parser_step = HormannDecoderStepReset;
} else {
parser_step = HormannDecoderStepReset;
}
break;
}
}
};
#endif
+91
View File
@@ -0,0 +1,91 @@
#ifndef __FPROTO_IDO_H__
#define __FPROTO_IDO_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
IDoDecoderStepReset = 0,
IDoDecoderStepFoundPreambula,
IDoDecoderStepSaveDuration,
IDoDecoderStepCheckDuration,
} IDoDecoderStep;
class FProtoSubGhzDIdo : public FProtoSubGhzDBase {
public:
FProtoSubGhzDIdo() {
sensorType = FPS_IDO;
te_short = 450;
te_long = 1450;
te_delta = 150;
min_count_bit_for_found = 48;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case IDoDecoderStepReset:
if ((level) && (DURATION_DIFF(duration, te_short * 10) < te_delta * 5)) {
parser_step = IDoDecoderStepFoundPreambula;
}
break;
case IDoDecoderStepFoundPreambula:
if ((!level) && (DURATION_DIFF(duration, te_short * 10) < te_delta * 5)) {
// Found Preambula
parser_step = IDoDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = IDoDecoderStepReset;
}
break;
case IDoDecoderStepSaveDuration:
if (level) {
if (duration >= ((uint32_t)te_short * 5 + te_delta)) {
parser_step = IDoDecoderStepFoundPreambula;
if (decode_count_bit >=
min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller
uint64_t code_found_reverse = FProtoGeneral::subghz_protocol_blocks_reverse_key(data, data_count_bit);
uint32_t code_fix = code_found_reverse & 0xFFFFFF;
serial = code_fix & 0xFFFFF;
btn = (code_fix >> 20) & 0x0F;
if (callback) callback(this);
}
decode_data = 0;
decode_count_bit = 0;
break;
} else {
te_last = duration;
parser_step = IDoDecoderStepCheckDuration;
}
} else {
parser_step = IDoDecoderStepReset;
}
break;
case IDoDecoderStepCheckDuration:
if (!level) {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta * 3)) {
subghz_protocol_blocks_add_bit(0);
parser_step = IDoDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_short) < te_delta * 3) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = IDoDecoderStepSaveDuration;
} else {
parser_step = IDoDecoderStepReset;
}
} else {
parser_step = IDoDecoderStepReset;
}
break;
}
}
};
#endif
@@ -0,0 +1,148 @@
#ifndef __FPROTO_INTERTECHNOV3_H__
#define __FPROTO_INTERTECHNOV3_H__
#include "subghzdbase.hpp"
#define INTERTECHNO_V3_DIMMING_COUNT_BIT 36
typedef enum : uint8_t {
IntertechnoV3DecoderStepReset = 0,
IntertechnoV3DecoderStepStartSync,
IntertechnoV3DecoderStepFoundSync,
IntertechnoV3DecoderStepStartDuration,
IntertechnoV3DecoderStepSaveDuration,
IntertechnoV3DecoderStepCheckDuration,
IntertechnoV3DecoderStepEndDuration,
} IntertechnoV3DecoderStep;
class FProtoSubGhzDIntertechnoV3 : public FProtoSubGhzDBase {
public:
FProtoSubGhzDIntertechnoV3() {
sensorType = FPS_INTERTECHNOV3;
te_short = 275;
te_long = 1375;
te_delta = 150;
min_count_bit_for_found = 32;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case IntertechnoV3DecoderStepReset:
if ((!level) &&
(DURATION_DIFF(duration, te_short * 37) < te_delta * 15)) {
parser_step = IntertechnoV3DecoderStepStartSync;
}
break;
case IntertechnoV3DecoderStepStartSync:
if (level && (DURATION_DIFF(duration, te_short) < te_delta)) {
parser_step = IntertechnoV3DecoderStepFoundSync;
} else {
parser_step = IntertechnoV3DecoderStepReset;
}
break;
case IntertechnoV3DecoderStepFoundSync:
if (!level && (DURATION_DIFF(duration, te_short * 10) < te_delta * 3)) {
parser_step = IntertechnoV3DecoderStepStartDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = IntertechnoV3DecoderStepReset;
}
break;
case IntertechnoV3DecoderStepStartDuration:
if (level && (DURATION_DIFF(duration, te_short) < te_delta)) {
parser_step = IntertechnoV3DecoderStepSaveDuration;
} else {
parser_step = IntertechnoV3DecoderStepReset;
}
break;
case IntertechnoV3DecoderStepSaveDuration:
if (!level) { // save interval
if (duration >= (te_short * 11)) {
parser_step = IntertechnoV3DecoderStepStartSync;
if ((decode_count_bit == min_count_bit_for_found) ||
(decode_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT)) {
data = decode_data;
data_count_bit = decode_count_bit;
remote_controller();
if (callback) callback(this);
}
break;
}
te_last = duration;
parser_step = IntertechnoV3DecoderStepCheckDuration;
} else {
parser_step = IntertechnoV3DecoderStepReset;
}
break;
case IntertechnoV3DecoderStepCheckDuration:
if (level) {
// Add 0 bit
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
parser_step = IntertechnoV3DecoderStepEndDuration;
} else if (
// Add 1 bit
(DURATION_DIFF(te_last, te_long) < te_delta * 2) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = IntertechnoV3DecoderStepEndDuration;
} else if (
// Add dimm_state
(DURATION_DIFF(te_last, te_short) < te_delta * 2) &&
(DURATION_DIFF(duration, te_short) < te_delta) &&
(decode_count_bit == 27)) {
subghz_protocol_blocks_add_bit(0);
parser_step = IntertechnoV3DecoderStepEndDuration;
} else
parser_step = IntertechnoV3DecoderStepReset;
} else {
parser_step = IntertechnoV3DecoderStepReset;
}
break;
case IntertechnoV3DecoderStepEndDuration:
if (!level && ((DURATION_DIFF(duration, te_short) < te_delta) ||
(DURATION_DIFF(duration, te_long) < te_delta * 2))) {
parser_step = IntertechnoV3DecoderStepStartDuration;
} else {
parser_step = IntertechnoV3DecoderStepReset;
}
break;
}
}
protected:
void remote_controller() {
if (data_count_bit == min_count_bit_for_found) {
serial = (data >> 6) & 0x3FFFFFF;
if ((data >> 5) & 0x1) {
cnt = 1 << 5;
} else {
cnt = (~data & 0xF);
}
btn = (data >> 4) & 0x1;
} else if (data_count_bit == INTERTECHNO_V3_DIMMING_COUNT_BIT) {
serial = (data >> 10) & 0x3FFFFFF;
if ((data >> 9) & 0x1) {
cnt = 1 << 5;
} else {
cnt = (~(data >> 4) & 0xF);
}
btn = data & 0xF;
} else {
serial = 0;
cnt = 0;
btn = 0;
}
}
};
#endif
+107
View File
@@ -0,0 +1,107 @@
#ifndef __FPROTO_KEELOQ_H__
#define __FPROTO_KEELOQ_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
KeeloqDecoderStepReset = 0,
KeeloqDecoderStepCheckPreambula,
KeeloqDecoderStepSaveDuration,
KeeloqDecoderStepCheckDuration,
} KeeloqDecoderStep;
class FProtoSubGhzDKeeLoq : public FProtoSubGhzDBase {
public:
FProtoSubGhzDKeeLoq() {
sensorType = FPS_KEELOQ;
te_short = 400;
te_long = 800;
te_delta = 140;
min_count_bit_for_found = 64;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case KeeloqDecoderStepReset:
if ((level) && DURATION_DIFF(duration, te_short) < te_delta) {
parser_step = KeeloqDecoderStepCheckPreambula;
header_count++;
}
break;
case KeeloqDecoderStepCheckPreambula:
if ((!level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
parser_step = KeeloqDecoderStepReset;
break;
}
if ((header_count > 2) && (DURATION_DIFF(duration, te_short * 10) < te_delta * 10)) {
// Found header
parser_step = KeeloqDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = KeeloqDecoderStepReset;
header_count = 0;
}
break;
case KeeloqDecoderStepSaveDuration:
if (level) {
te_last = duration;
parser_step = KeeloqDecoderStepCheckDuration;
}
break;
case KeeloqDecoderStepCheckDuration:
if (!level) {
if (duration >= ((uint32_t)te_short * 2 + te_delta)) {
// Found end TX
parser_step = KeeloqDecoderStepReset;
if ((decode_count_bit >= min_count_bit_for_found) &&
(decode_count_bit <= min_count_bit_for_found + 2)) {
if (data != decode_data) {
data = decode_data;
data_count_bit = min_count_bit_for_found;
// controller
uint64_t key = FProtoGeneral::subghz_protocol_blocks_reverse_key(data, data_count_bit);
uint32_t key_fix = key >> 32;
// uint32_t key_hop = key & 0x00000000ffffffff; //unused
serial = key_fix & 0x0FFFFFFF;
btn = key_fix >> 28;
if (callback) callback(this);
}
decode_data = 0;
decode_count_bit = 0;
header_count = 0;
}
break;
} else if (
(DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta * 2)) {
if (decode_count_bit < min_count_bit_for_found) {
subghz_protocol_blocks_add_bit(1);
} else {
decode_count_bit++;
}
parser_step = KeeloqDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta * 2) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
if (decode_count_bit < min_count_bit_for_found) {
subghz_protocol_blocks_add_bit(0);
} else {
decode_count_bit++;
}
parser_step = KeeloqDecoderStepSaveDuration;
} else {
parser_step = KeeloqDecoderStepReset;
header_count = 0;
}
} else {
parser_step = KeeloqDecoderStepReset;
header_count = 0;
}
break;
}
}
};
#endif
@@ -0,0 +1,124 @@
#ifndef __FPROTO_KINGGATES_STYLO_4K_H__
#define __FPROTO_KINGGATES_STYLO_4K_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
KingGates_stylo_4kDecoderStepReset = 0,
KingGates_stylo_4kDecoderStepCheckPreambula,
KingGates_stylo_4kDecoderStepCheckStartBit,
KingGates_stylo_4kDecoderStepSaveDuration,
KingGates_stylo_4kDecoderStepCheckDuration,
} KingGates_stylo_4kDecoderStep;
class FProtoSubGhzDKinggatesStylo4K : public FProtoSubGhzDBase {
public:
FProtoSubGhzDKinggatesStylo4K() {
sensorType = FPS_KINGGATESSTYLO4K;
te_short = 400;
te_long = 1100;
te_delta = 140;
min_count_bit_for_found = 89;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case KingGates_stylo_4kDecoderStepReset:
if ((level) && DURATION_DIFF(duration, te_short) < te_delta) {
parser_step = KingGates_stylo_4kDecoderStepCheckPreambula;
header_count++;
}
break;
case KingGates_stylo_4kDecoderStepCheckPreambula:
if ((!level) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
parser_step = KingGates_stylo_4kDecoderStepReset;
break;
}
if ((header_count > 2) &&
(DURATION_DIFF(duration, te_long * 2) < te_delta * 2)) {
// Found header
parser_step = KingGates_stylo_4kDecoderStepCheckStartBit;
} else {
parser_step = KingGates_stylo_4kDecoderStepReset;
header_count = 0;
}
break;
case KingGates_stylo_4kDecoderStepCheckStartBit:
if ((level) &&
DURATION_DIFF(duration, te_short * 2) < te_delta * 2) {
parser_step = KingGates_stylo_4kDecoderStepSaveDuration;
decode_data = 0;
data_2 = 0;
decode_count_bit = 0;
header_count = 0;
}
break;
case KingGates_stylo_4kDecoderStepSaveDuration:
if (!level) {
if (duration >= ((uint32_t)te_long * 3)) {
if (decode_count_bit ==
min_count_bit_for_found) {
data = data_2;
data_2 = decode_data;
data_count_bit = decode_count_bit;
// controller
uint64_t fix = FProtoGeneral::subghz_protocol_blocks_reverse_key(data, 53);
btn = (fix >> 17) & 0x0F;
serial = ((fix >> 5) & 0xFFFF0000) | (fix & 0xFFFF);
if (callback) callback(this);
}
parser_step = KingGates_stylo_4kDecoderStepReset;
decode_data = 0;
data_2 = 0;
decode_count_bit = 0;
header_count = 0;
break;
} else {
te_last = duration;
parser_step = KingGates_stylo_4kDecoderStepCheckDuration;
}
} else {
parser_step = KingGates_stylo_4kDecoderStepReset;
header_count = 0;
}
break;
case KingGates_stylo_4kDecoderStepCheckDuration:
if (level) {
if ((DURATION_DIFF(
te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta * 2)) {
subghz_protocol_blocks_add_bit(1);
parser_step = KingGates_stylo_4kDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(
te_last, te_long) <
te_delta * 2) &&
(DURATION_DIFF(duration, te_short) <
te_delta)) {
subghz_protocol_blocks_add_bit(0);
parser_step = KingGates_stylo_4kDecoderStepSaveDuration;
} else {
parser_step = KingGates_stylo_4kDecoderStepReset;
header_count = 0;
}
if (decode_count_bit == 53) {
data_2 = decode_data;
decode_data = 0;
}
} else {
parser_step = KingGates_stylo_4kDecoderStepReset;
header_count = 0;
}
break;
}
}
protected:
uint64_t data_2 = 0;
};
#endif
+88
View File
@@ -0,0 +1,88 @@
#ifndef __FPROTO_LINEAR_H__
#define __FPROTO_LINEAR_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
LinearDecoderStepReset = 0,
LinearDecoderStepSaveDuration,
LinearDecoderStepCheckDuration,
} LinearDecoderStep;
class FProtoSubGhzDLinear : public FProtoSubGhzDBase {
public:
FProtoSubGhzDLinear() {
sensorType = FPS_LINEAR;
te_short = 500;
te_long = 1500;
te_delta = 150;
min_count_bit_for_found = 10;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case LinearDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 42) < te_delta * 20)) {
// Found header Linear
decode_data = 0;
decode_count_bit = 0;
parser_step = LinearDecoderStepSaveDuration;
}
break;
case LinearDecoderStepSaveDuration:
if (level) {
te_last = duration;
parser_step = LinearDecoderStepCheckDuration;
} else {
parser_step = LinearDecoderStepReset;
}
break;
case LinearDecoderStepCheckDuration:
if (!level) { // save interval
if (duration >= (te_short * 5)) {
parser_step = LinearDecoderStepReset;
// checking that the duration matches the guardtime
if ((DURATION_DIFF(duration, te_short * 42) > te_delta * 20)) {
break;
}
if (DURATION_DIFF(te_last, te_short) < te_delta) {
subghz_protocol_blocks_add_bit(0);
} else if (
DURATION_DIFF(te_last, te_long) <
te_delta) {
subghz_protocol_blocks_add_bit(1);
}
if (decode_count_bit == min_count_bit_for_found) {
serial = SD_NO_SERIAL;
btn = SD_NO_BTN;
data = decode_data;
data_count_bit = decode_count_bit;
if (callback) callback(this);
}
break;
}
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
parser_step = LinearDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = LinearDecoderStepSaveDuration;
} else {
parser_step = LinearDecoderStepReset;
}
} else {
parser_step = LinearDecoderStepReset;
}
break;
}
}
};
#endif
@@ -0,0 +1,87 @@
#ifndef __FPROTO_LINEARDELTA3_H__
#define __FPROTO_LINEARDELTA3_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
LinearD3DecoderStepReset = 0,
LinearD3DecoderStepSaveDuration,
LinearD3DecoderStepCheckDuration,
} LinearD3DecoderStep;
class FProtoSubGhzDLinearDelta3 : public FProtoSubGhzDBase {
public:
FProtoSubGhzDLinearDelta3() {
sensorType = FPS_LINEARDELTA3;
te_short = 500;
te_long = 2000;
te_delta = 150;
min_count_bit_for_found = 8;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case LinearD3DecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 70) < te_delta * 24)) {
// Found header Linear
decode_data = 0;
decode_count_bit = 0;
parser_step = LinearD3DecoderStepSaveDuration;
}
break;
case LinearD3DecoderStepSaveDuration:
if (level) {
te_last = duration;
parser_step = LinearD3DecoderStepCheckDuration;
} else {
parser_step = LinearD3DecoderStepReset;
}
break;
case LinearD3DecoderStepCheckDuration:
if (!level) {
if (duration >= (te_short * 10)) {
parser_step = LinearD3DecoderStepReset;
if (DURATION_DIFF(te_last, te_short) < te_delta) {
subghz_protocol_blocks_add_bit(1);
} else if (
DURATION_DIFF(te_last, te_long) < te_delta) {
subghz_protocol_blocks_add_bit(0);
}
if (decode_count_bit == min_count_bit_for_found) {
if ((data == decode_data) && data) {
serial = SD_NO_SERIAL;
btn = SD_NO_BTN;
data = decode_data;
data_count_bit = decode_count_bit;
if (callback) callback(this);
}
parser_step = LinearD3DecoderStepSaveDuration;
}
break;
}
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_short * 7) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = LinearD3DecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
parser_step = LinearD3DecoderStepSaveDuration;
} else {
parser_step = LinearD3DecoderStepReset;
}
} else {
parser_step = LinearD3DecoderStepReset;
}
break;
}
}
};
#endif
+139
View File
@@ -0,0 +1,139 @@
#ifndef __FPROTO_MAGELLAN_H__
#define __FPROTO_MAGELLAN_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
MagellanDecoderStepReset = 0,
MagellanDecoderStepCheckPreambula,
MagellanDecoderStepFoundPreambula,
MagellanDecoderStepSaveDuration,
MagellanDecoderStepCheckDuration,
} MagellanDecoderStep;
class FProtoSubGhzDMagellan : public FProtoSubGhzDBase {
public:
FProtoSubGhzDMagellan() {
sensorType = FPS_MAGELLAN;
te_short = 200;
te_long = 400;
te_delta = 100;
min_count_bit_for_found = 32;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case MagellanDecoderStepReset:
if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
parser_step = MagellanDecoderStepCheckPreambula;
te_last = duration;
header_count = 0;
}
break;
case MagellanDecoderStepCheckPreambula:
if (level) {
te_last = duration;
} else {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
// Found header
header_count++;
} else if (
(DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta * 2) &&
(header_count > 10)) {
parser_step = MagellanDecoderStepFoundPreambula;
} else {
parser_step = MagellanDecoderStepReset;
}
}
break;
case MagellanDecoderStepFoundPreambula:
if (level) {
te_last = duration;
} else {
if ((DURATION_DIFF(te_last, te_short * 6) < te_delta * 3) &&
(DURATION_DIFF(duration, te_long) < te_delta * 2)) {
parser_step = MagellanDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = MagellanDecoderStepReset;
}
}
break;
case MagellanDecoderStepSaveDuration:
if (level) {
te_last = duration;
parser_step = MagellanDecoderStepCheckDuration;
} else {
parser_step = MagellanDecoderStepReset;
}
break;
case MagellanDecoderStepCheckDuration:
if (!level) {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = MagellanDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
parser_step = MagellanDecoderStepSaveDuration;
} else if (duration >= (te_long * 3)) {
// Found stop bit
if ((decode_count_bit == min_count_bit_for_found) &&
subghz_protocol_magellan_check_crc()) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller
uint64_t data_rev = FProtoGeneral::subghz_protocol_blocks_reverse_key(data >> 8, 24);
serial = data_rev & 0xFFFF;
btn = (data_rev >> 16) & 0xFF;
if (callback) callback(this);
}
decode_data = 0;
decode_count_bit = 0;
parser_step = MagellanDecoderStepReset;
} else {
parser_step = MagellanDecoderStepReset;
}
} else {
parser_step = MagellanDecoderStepReset;
}
break;
}
}
protected:
bool subghz_protocol_magellan_check_crc() {
uint8_t data[3] = {
(uint8_t)(decode_data >> 24),
(uint8_t)(decode_data >> 16),
(uint8_t)(decode_data >> 8)};
return (decode_data & 0xFF) == subghz_protocol_magellan_crc8(data, sizeof(data));
}
uint8_t subghz_protocol_magellan_crc8(uint8_t* data, size_t len) {
uint8_t crc = 0x00;
uint8_t i, j;
for (i = 0; i < len; i++) {
crc ^= data[i];
for (j = 0; j < 8; j++) {
if ((crc & 0x80) != 0)
crc = (uint8_t)((crc << 1) ^ 0x31);
else
crc <<= 1;
}
}
return crc;
}
};
#endif
+86
View File
@@ -0,0 +1,86 @@
#ifndef __FPROTO_MARANTEC_H__
#define __FPROTO_MARANTEC_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
MarantecDecoderStepReset = 0,
MarantecDecoderFoundHeader,
MarantecDecoderStepDecoderData,
} MarantecDecoderStep;
class FProtoSubGhzDMarantec : public FProtoSubGhzDBase {
public:
FProtoSubGhzDMarantec() {
sensorType = FPS_MARANTEC;
te_short = 1000;
te_long = 2000;
te_delta = 200;
min_count_bit_for_found = 49;
}
void feed(bool level, uint32_t duration) {
ManchesterEvent event = ManchesterEventReset;
switch (parser_step) {
case MarantecDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_long * 5) < te_delta * 8)) {
// Found header marantec
parser_step = MarantecDecoderStepDecoderData;
decode_data = 1;
decode_count_bit = 1;
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
}
break;
case MarantecDecoderStepDecoderData:
if (!level) {
if (DURATION_DIFF(duration, te_short) < te_delta) {
event = ManchesterEventShortLow;
} else if (
DURATION_DIFF(duration, te_long) < te_delta) {
event = ManchesterEventLongLow;
} else if (
duration >= ((uint32_t)te_long * 2 + te_delta)) {
if (decode_count_bit == min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller
btn = (data >> 16) & 0xF;
serial = ((data >> 12) & 0xFFFFFF00) | ((data >> 8) & 0xFF);
if (callback) callback(this);
}
decode_data = 1;
decode_count_bit = 1;
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
} else {
parser_step = MarantecDecoderStepReset;
}
} else {
if (DURATION_DIFF(duration, te_short) < te_delta) {
event = ManchesterEventShortHigh;
} else if (
DURATION_DIFF(duration, te_long) < te_delta) {
event = ManchesterEventLongHigh;
} else {
parser_step = MarantecDecoderStepReset;
}
}
if (event != ManchesterEventReset) {
bool bitstate;
bool data_ok = FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &bitstate);
if (data_ok) {
decode_data = (decode_data << 1) | bitstate;
decode_count_bit++;
}
}
break;
}
}
protected:
ManchesterState manchester_saved_state = ManchesterStateMid1;
};
#endif
@@ -0,0 +1,86 @@
#ifndef __FPROTO_MASTERCODE_H__
#define __FPROTO_MASTERCODE_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
MastercodeDecoderStepReset = 0,
MastercodeDecoderStepSaveDuration,
MastercodeDecoderStepCheckDuration,
} MastercodeDecoderStep;
class FProtoSubGhzDMastercode : public FProtoSubGhzDBase {
public:
FProtoSubGhzDMastercode() {
sensorType = FPS_MASTERCODE;
te_short = 1072;
te_long = 2145;
te_delta = 150;
min_count_bit_for_found = 36;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case MastercodeDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 15) < te_delta * 15)) {
parser_step = MastercodeDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
}
break;
case MastercodeDecoderStepSaveDuration:
if (level) {
te_last = duration;
parser_step = MastercodeDecoderStepCheckDuration;
} else {
parser_step = MastercodeDecoderStepReset;
}
break;
case MastercodeDecoderStepCheckDuration:
if (!level) {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta * 8)) {
subghz_protocol_blocks_add_bit(0);
parser_step = MastercodeDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta * 8) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = MastercodeDecoderStepSaveDuration;
} else if (
DURATION_DIFF(duration, te_short * 15) < te_delta * 15) {
if ((DURATION_DIFF(te_last, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
} else if ((DURATION_DIFF(te_last, te_long) < te_delta * 8)) {
subghz_protocol_blocks_add_bit(1);
} else {
parser_step = MastercodeDecoderStepReset;
}
if (decode_count_bit == min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller
serial = (data >> 4) & 0xFFFF;
btn = (data >> 2 & 0x03);
if (callback) callback(this);
}
parser_step = MastercodeDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = MastercodeDecoderStepReset;
}
} else {
parser_step = MastercodeDecoderStepReset;
}
break;
}
}
};
#endif
+104
View File
@@ -0,0 +1,104 @@
#ifndef __FPROTO_MEGACODE_H__
#define __FPROTO_MEGACODE_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
MegaCodeDecoderStepReset = 0,
MegaCodeDecoderStepFoundStartBit,
MegaCodeDecoderStepSaveDuration,
MegaCodeDecoderStepCheckDuration,
} MegaCodeDecoderStep;
class FProtoSubGhzDMegacode : public FProtoSubGhzDBase {
public:
FProtoSubGhzDMegacode() {
sensorType = FPS_MEGACODE;
te_short = 1000;
te_long = 1000;
te_delta = 200;
min_count_bit_for_found = 24;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case MegaCodeDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 13) < te_delta * 17)) { // 10..16ms
// Found header MegaCode
parser_step = MegaCodeDecoderStepFoundStartBit;
}
break;
case MegaCodeDecoderStepFoundStartBit:
if (level && (DURATION_DIFF(duration, te_short) < te_delta)) {
// Found start bit MegaCode
parser_step = MegaCodeDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
subghz_protocol_blocks_add_bit(1);
last_bit = 1;
} else {
parser_step = MegaCodeDecoderStepReset;
}
break;
case MegaCodeDecoderStepSaveDuration:
if (!level) { // save interval
if (duration >= (te_short * 10)) {
parser_step = MegaCodeDecoderStepReset;
if (decode_count_bit ==
min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller
if ((data >> 23) == 1) {
serial = (data >> 3) & 0xFFFF;
btn = data & 0b111;
cnt = (data >> 19) & 0b1111;
} else {
serial = 0;
btn = 0;
cnt = 0;
}
if (callback) callback(this);
}
break;
}
if (!last_bit) {
te_last = duration - te_short * 3;
} else {
te_last = duration;
}
parser_step = MegaCodeDecoderStepCheckDuration;
} else {
parser_step = MegaCodeDecoderStepReset;
}
break;
case MegaCodeDecoderStepCheckDuration:
if (level) {
if ((DURATION_DIFF(te_last, te_short * 5) < te_delta * 5) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
last_bit = 1;
parser_step = MegaCodeDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_short * 2) < te_delta * 2) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
last_bit = 0;
parser_step = MegaCodeDecoderStepSaveDuration;
} else
parser_step = MegaCodeDecoderStepReset;
} else {
parser_step = MegaCodeDecoderStepReset;
}
break;
}
}
protected:
uint8_t last_bit = false;
};
#endif
+108
View File
@@ -0,0 +1,108 @@
#ifndef __FPROTO_NEROSKETCH_H__
#define __FPROTO_NEROSKETCH_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
NeroSketchDecoderStepReset = 0,
NeroSketchDecoderStepCheckPreambula,
NeroSketchDecoderStepSaveDuration,
NeroSketchDecoderStepCheckDuration,
} NeroSketchDecoderStep;
class FProtoSubGhzDNeroSketch : public FProtoSubGhzDBase {
public:
FProtoSubGhzDNeroSketch() {
sensorType = FPS_NERO_SKETCH;
te_short = 330;
te_long = 660;
te_delta = 150;
min_count_bit_for_found = 40;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case NeroSketchDecoderStepReset:
if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
parser_step = NeroSketchDecoderStepCheckPreambula;
te_last = duration;
header_count = 0;
}
break;
case NeroSketchDecoderStepCheckPreambula:
if (level) {
if ((DURATION_DIFF(duration, te_short) < te_delta) ||
(DURATION_DIFF(duration, te_short * 4) < te_delta)) {
te_last = duration;
} else {
parser_step = NeroSketchDecoderStepReset;
}
} else if (
DURATION_DIFF(duration, te_short) < te_delta) {
if (DURATION_DIFF(te_last, te_short) < te_delta) {
// Found header
header_count++;
break;
} else if (
DURATION_DIFF(te_last, te_short * 4) < te_delta) {
// Found start bit
if (header_count > 40) {
parser_step = NeroSketchDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = NeroSketchDecoderStepReset;
}
} else {
parser_step = NeroSketchDecoderStepReset;
}
} else {
parser_step = NeroSketchDecoderStepReset;
}
break;
case NeroSketchDecoderStepSaveDuration:
if (level) {
if (duration >= (te_short * 2 + te_delta * 2)) {
// Found stop bit
parser_step = NeroSketchDecoderStepReset;
if (decode_count_bit == min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
if (callback) callback(this);
}
decode_data = 0;
decode_count_bit = 0;
break;
} else {
te_last = duration;
parser_step = NeroSketchDecoderStepCheckDuration;
}
} else {
parser_step = NeroSketchDecoderStepReset;
}
break;
case NeroSketchDecoderStepCheckDuration:
if (!level) {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
parser_step = NeroSketchDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = NeroSketchDecoderStepSaveDuration;
} else {
parser_step = NeroSketchDecoderStepReset;
}
} else {
parser_step = NeroSketchDecoderStepReset;
}
break;
}
}
};
#endif
+115
View File
@@ -0,0 +1,115 @@
#ifndef __FPROTO_NERORADIO_H__
#define __FPROTO_NERORADIO_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
NeroRadioDecoderStepReset = 0,
NeroRadioDecoderStepCheckPreambula,
NeroRadioDecoderStepSaveDuration,
NeroRadioDecoderStepCheckDuration,
} NeroRadioDecoderStep;
class FProtoSubGhzDNeroRadio : public FProtoSubGhzDBase {
public:
FProtoSubGhzDNeroRadio() {
sensorType = FPS_NERORADIO;
te_short = 200;
te_long = 400;
te_delta = 80;
min_count_bit_for_found = 56;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case NeroRadioDecoderStepReset:
if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) {
parser_step = NeroRadioDecoderStepCheckPreambula;
te_last = duration;
header_count = 0;
}
break;
case NeroRadioDecoderStepCheckPreambula:
if (level) {
if ((DURATION_DIFF(duration, te_short) < te_delta) ||
(DURATION_DIFF(duration, te_short * 4) < te_delta)) {
te_last = duration;
} else {
parser_step = NeroRadioDecoderStepReset;
}
} else if (
DURATION_DIFF(duration, te_short) < te_delta) {
if (DURATION_DIFF(te_last, te_short) < te_delta) {
// Found header
header_count++;
break;
} else if (
DURATION_DIFF(te_last, te_short * 4) < te_delta) {
// Found start bit
if (header_count > 40) {
parser_step = NeroRadioDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = NeroRadioDecoderStepReset;
}
} else {
parser_step = NeroRadioDecoderStepReset;
}
} else {
parser_step = NeroRadioDecoderStepReset;
}
break;
case NeroRadioDecoderStepSaveDuration:
if (level) {
te_last = duration;
parser_step = NeroRadioDecoderStepCheckDuration;
} else {
parser_step = NeroRadioDecoderStepReset;
}
break;
case NeroRadioDecoderStepCheckDuration:
if (!level) {
if (duration >= ((uint32_t)1250)) {
// Found stop bit
if (DURATION_DIFF(te_last, te_short) < te_delta) {
subghz_protocol_blocks_add_bit(0);
} else if (
DURATION_DIFF(te_last, te_long) < te_delta) {
subghz_protocol_blocks_add_bit(1);
}
parser_step = NeroRadioDecoderStepReset;
if ((decode_count_bit == min_count_bit_for_found) ||
(decode_count_bit == min_count_bit_for_found + 1)) {
data = decode_data;
data_count_bit = decode_count_bit;
if (callback) callback(this);
}
decode_data = 0;
decode_count_bit = 0;
parser_step = NeroRadioDecoderStepReset; //-V1048
break;
} else if (
(DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
parser_step = NeroRadioDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = NeroRadioDecoderStepSaveDuration;
} else {
parser_step = NeroRadioDecoderStepReset;
}
} else {
parser_step = NeroRadioDecoderStepReset;
}
break;
}
}
};
#endif
+86
View File
@@ -0,0 +1,86 @@
#ifndef __FPROTO_NICE_FLO_H__
#define __FPROTO_NICE_FLO_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
NiceFloDecoderStepReset = 0,
NiceFloDecoderStepFoundStartBit,
NiceFloDecoderStepSaveDuration,
NiceFloDecoderStepCheckDuration,
} NiceFloDecoderStep;
class FProtoSubGhzDNiceflo : public FProtoSubGhzDBase {
public:
FProtoSubGhzDNiceflo() {
sensorType = FPS_NICEFLO;
te_short = 700;
te_long = 1400;
te_delta = 200;
min_count_bit_for_found = 12;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case NiceFloDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 36) < te_delta * 36)) {
// Found header Nice Flo
parser_step = NiceFloDecoderStepFoundStartBit;
}
break;
case NiceFloDecoderStepFoundStartBit:
if (!level) {
break;
} else if (
DURATION_DIFF(duration, te_short) < te_delta) {
// Found start bit Nice Flo
parser_step = NiceFloDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = NiceFloDecoderStepReset;
}
break;
case NiceFloDecoderStepSaveDuration:
if (!level) { // save interval
if (duration >= (te_short * 4)) {
parser_step = NiceFloDecoderStepFoundStartBit;
if (decode_count_bit >= min_count_bit_for_found) {
serial = SD_NO_SERIAL;
btn = SD_NO_BTN;
data = decode_data;
data_count_bit = decode_count_bit;
if (callback) callback(this);
}
break;
}
te_last = duration;
parser_step = NiceFloDecoderStepCheckDuration;
} else {
parser_step = NiceFloDecoderStepReset;
}
break;
case NiceFloDecoderStepCheckDuration:
if (level) {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
parser_step = NiceFloDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = NiceFloDecoderStepSaveDuration;
} else
parser_step = NiceFloDecoderStepReset;
} else {
parser_step = NiceFloDecoderStepReset;
}
break;
}
}
};
#endif
+100
View File
@@ -0,0 +1,100 @@
#ifndef __FPROTO_NICE_FLORS_H__
#define __FPROTO_NICE_FLORS_H__
#include "subghzdbase.hpp"
#define NICE_ONE_COUNT_BIT 72
typedef enum : uint8_t {
NiceFlorSDecoderStepReset = 0,
NiceFlorSDecoderStepCheckHeader,
NiceFlorSDecoderStepFoundHeader,
NiceFlorSDecoderStepSaveDuration,
NiceFlorSDecoderStepCheckDuration,
} NiceFlorSDecoderStep;
class FProtoSubGhzDNiceflors : public FProtoSubGhzDBase {
public:
FProtoSubGhzDNiceflors() {
sensorType = FPS_NICEFLORS;
te_short = 500;
te_long = 1000;
te_delta = 300;
min_count_bit_for_found = 52;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case NiceFlorSDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 38) < te_delta * 38)) {
// Found start header Nice Flor-S
parser_step = NiceFlorSDecoderStepCheckHeader;
}
break;
case NiceFlorSDecoderStepCheckHeader:
if ((level) && (DURATION_DIFF(duration, te_short * 3) < te_delta * 3)) {
// Found next header Nice Flor-S
parser_step = NiceFlorSDecoderStepFoundHeader;
} else {
parser_step = NiceFlorSDecoderStepReset;
}
break;
case NiceFlorSDecoderStepFoundHeader:
if ((!level) && (DURATION_DIFF(duration, te_short * 3) < te_delta * 3)) {
// Found header Nice Flor-S
parser_step = NiceFlorSDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = NiceFlorSDecoderStepReset;
}
break;
case NiceFlorSDecoderStepSaveDuration:
if (level) {
if (DURATION_DIFF(duration, te_short * 3) < te_delta) {
// Found STOP bit
parser_step = NiceFlorSDecoderStepReset;
if ((decode_count_bit == min_count_bit_for_found) || (decode_count_bit == NICE_ONE_COUNT_BIT)) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller-
cnt = SD_NO_CNT;
serial = SD_NO_SERIAL;
btn = SD_NO_BTN;
if (callback) callback(this);
}
break;
} else {
// save interval
te_last = duration;
parser_step = NiceFlorSDecoderStepCheckDuration;
}
}
break;
case NiceFlorSDecoderStepCheckDuration:
if (!level) {
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta)) {
subghz_protocol_blocks_add_bit(0);
parser_step = NiceFlorSDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = NiceFlorSDecoderStepSaveDuration;
} else
parser_step = NiceFlorSDecoderStepReset;
} else {
parser_step = NiceFlorSDecoderStepReset;
}
if (decode_count_bit == min_count_bit_for_found) {
data = decode_data;
decode_data = 0;
}
break;
}
}
};
#endif
@@ -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
+77
View File
@@ -0,0 +1,77 @@
#ifndef __FPROTO_PRINCETON_H__
#define __FPROTO_PRINCETON_H__
#include "subghzdbase.hpp"
typedef enum : uint8_t {
PrincetonDecoderStepReset = 0,
PrincetonDecoderStepSaveDuration,
PrincetonDecoderStepCheckDuration,
} PrincetonDecoderStep;
class FProtoSubGhzDPrinceton : public FProtoSubGhzDBase {
public:
FProtoSubGhzDPrinceton() {
sensorType = FPS_PRINCETON;
te_short = 390;
te_long = 1170;
te_delta = 300;
min_count_bit_for_found = 24;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case PrincetonDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 36) < te_delta * 36)) {
// Found Preambula
parser_step = PrincetonDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
}
break;
case PrincetonDecoderStepSaveDuration:
// save duration
if (level) {
te_last = duration;
parser_step = PrincetonDecoderStepCheckDuration;
}
break;
case PrincetonDecoderStepCheckDuration:
if (!level) {
if (duration >= ((uint32_t)te_long * 2)) {
parser_step = PrincetonDecoderStepSaveDuration;
if (decode_count_bit == min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
// controller
serial = data >> 4;
btn = data & 0xF;
if (callback) callback(this);
}
decode_data = 0;
decode_count_bit = 0;
break;
}
if ((DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_long) < te_delta * 3)) {
subghz_protocol_blocks_add_bit(0);
parser_step = PrincetonDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) < te_delta * 3) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = PrincetonDecoderStepSaveDuration;
} else {
parser_step = PrincetonDecoderStepReset;
}
} else {
parser_step = PrincetonDecoderStepReset;
}
break;
}
}
};
#endif
+134
View File
@@ -0,0 +1,134 @@
#ifndef __FPROTO_SECPLUSV1_H__
#define __FPROTO_SECPLUSV1_H__
#include "subghzdbase.hpp"
#include <string.h>
#define SECPLUS_V1_BIT_ERR -1 // 0b0000
#define SECPLUS_V1_BIT_0 0 // 0b0001
#define SECPLUS_V1_BIT_1 1 // 0b0011
#define SECPLUS_V1_BIT_2 2 // 0b0111
#define SECPLUS_V1_PACKET_1_HEADER 0x00
#define SECPLUS_V1_PACKET_2_HEADER 0x02
#define SECPLUS_V1_PACKET_1_INDEX_BASE 0
#define SECPLUS_V1_PACKET_2_INDEX_BASE 21
#define SECPLUS_V1_PACKET_1_ACCEPTED (1 << 0)
#define SECPLUS_V1_PACKET_2_ACCEPTED (1 << 1)
typedef enum : uint8_t {
SecPlus_v1DecoderStepReset = 0,
SecPlus_v1DecoderStepSearchStartBit,
SecPlus_v1DecoderStepSaveDuration,
SecPlus_v1DecoderStepDecoderData,
} SecPlus_v1DecoderStep;
class FProtoSubGhzDSecPlusV1 : public FProtoSubGhzDBase {
public:
FProtoSubGhzDSecPlusV1() {
sensorType = FPS_SECPLUSV1;
te_short = 500;
te_long = 1500;
te_delta = 100;
min_count_bit_for_found = 21;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case SecPlus_v1DecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 120) < te_delta * 120)) {
// Found header Security+ 1.0
parser_step = SecPlus_v1DecoderStepSearchStartBit;
decode_data = 0;
decode_count_bit = 0;
packet_accepted = 0;
memset(data_array, 0, sizeof(data_array));
}
break;
case SecPlus_v1DecoderStepSearchStartBit:
if (level) {
if (DURATION_DIFF(duration, te_short) < te_delta) {
base_packet_index = SECPLUS_V1_PACKET_1_INDEX_BASE;
data_array[decode_count_bit + base_packet_index] = SECPLUS_V1_BIT_0;
decode_count_bit++;
parser_step = SecPlus_v1DecoderStepSaveDuration;
} else if (
DURATION_DIFF(duration, te_long) < te_delta) {
base_packet_index = SECPLUS_V1_PACKET_2_INDEX_BASE;
data_array[decode_count_bit + base_packet_index] = SECPLUS_V1_BIT_2;
decode_count_bit++;
parser_step = SecPlus_v1DecoderStepSaveDuration;
} else {
parser_step = SecPlus_v1DecoderStepReset;
}
} else {
parser_step = SecPlus_v1DecoderStepReset;
}
break;
case SecPlus_v1DecoderStepSaveDuration:
if (!level) { // save interval
if (DURATION_DIFF(duration, te_short * 120) < te_delta * 120) {
if (decode_count_bit == min_count_bit_for_found) {
if (base_packet_index == SECPLUS_V1_PACKET_1_INDEX_BASE)
packet_accepted |= SECPLUS_V1_PACKET_1_ACCEPTED;
if (base_packet_index == SECPLUS_V1_PACKET_2_INDEX_BASE)
packet_accepted |= SECPLUS_V1_PACKET_2_ACCEPTED;
if (packet_accepted == (SECPLUS_V1_PACKET_1_ACCEPTED | SECPLUS_V1_PACKET_2_ACCEPTED)) {
// subghz_protocol_secplus_v1_decode(); // disabled doe to lack of flash
// controller
// uint32_t fixed = (data >> 32) & 0xFFFFFFFF;
// cnt = data & 0xFFFFFFFF;
// btn = fixed % 3;
if (callback) callback(this);
parser_step = SecPlus_v1DecoderStepReset;
}
}
parser_step = SecPlus_v1DecoderStepSearchStartBit;
decode_data = 0;
decode_count_bit = 0;
} else {
te_last = duration;
parser_step = SecPlus_v1DecoderStepDecoderData;
}
} else {
parser_step = SecPlus_v1DecoderStepReset;
}
break;
case SecPlus_v1DecoderStepDecoderData:
if (level && (decode_count_bit <= min_count_bit_for_found)) {
if ((DURATION_DIFF(te_last, te_short * 3) < te_delta * 3) &&
(DURATION_DIFF(duration, te_short) < te_delta)) {
data_array[decode_count_bit + base_packet_index] = SECPLUS_V1_BIT_0;
decode_count_bit++;
parser_step = SecPlus_v1DecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_short * 2) < te_delta * 2) &&
(DURATION_DIFF(duration, te_short * 2) < te_delta * 2)) {
data_array[decode_count_bit + base_packet_index] = SECPLUS_V1_BIT_1;
decode_count_bit++;
parser_step = SecPlus_v1DecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_short) < te_delta) &&
(DURATION_DIFF(duration, te_short * 3) < te_delta * 3)) {
data_array[decode_count_bit + base_packet_index] = SECPLUS_V1_BIT_2;
decode_count_bit++;
parser_step = SecPlus_v1DecoderStepSaveDuration;
} else {
parser_step = SecPlus_v1DecoderStepReset;
}
} else {
parser_step = SecPlus_v1DecoderStepReset;
}
break;
}
}
protected:
uint8_t packet_accepted = 0;
uint8_t base_packet_index = 0;
uint8_t data_array[44];
};
#endif
+110
View File
@@ -0,0 +1,110 @@
#ifndef __FPROTO_SECPLUSV2_H__
#define __FPROTO_SECPLUSV2_H__
#include "subghzdbase.hpp"
#define SECPLUS_V2_HEADER 0x3C0000000000
#define SECPLUS_V2_HEADER_MASK 0xFFFF3C0000000000
#define SECPLUS_V2_PACKET_1 0x000000000000
#define SECPLUS_V2_PACKET_2 0x010000000000
#define SECPLUS_V2_PACKET_MASK 0x30000000000
typedef enum : uint8_t {
SecPlus_v2DecoderStepReset = 0,
SecPlus_v2DecoderStepDecoderData,
} SecPlus_v2DecoderStep;
class FProtoSubGhzDSecPlusV2 : public FProtoSubGhzDBase {
public:
FProtoSubGhzDSecPlusV2() {
sensorType = FPS_SECPLUSV2;
te_short = 250;
te_long = 500;
te_delta = 110;
min_count_bit_for_found = 62;
}
void feed(bool level, uint32_t duration) {
ManchesterEvent event = ManchesterEventReset;
switch (parser_step) {
case SecPlus_v2DecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_long * 130) < te_delta * 100)) {
// Found header Security+ 2.0
parser_step = SecPlus_v2DecoderStepDecoderData;
decode_data = 0;
decode_count_bit = 0;
secplus_packet_1 = 0;
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongHigh, &manchester_saved_state, NULL);
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventShortLow, &manchester_saved_state, NULL);
}
break;
case SecPlus_v2DecoderStepDecoderData:
if (!level) {
if (DURATION_DIFF(duration, te_short) < te_delta) {
event = ManchesterEventShortLow;
} else if (
DURATION_DIFF(duration, te_long) < te_delta) {
event = ManchesterEventLongLow;
} else if (
duration >= (te_long * 2UL + te_delta)) {
if (decode_count_bit == min_count_bit_for_found) {
data = decode_data;
data_count_bit = decode_count_bit;
if (subghz_protocol_secplus_v2_check_packet()) {
// controller too big
if (callback) callback(this);
parser_step = SecPlus_v2DecoderStepReset;
}
}
decode_data = 0;
decode_count_bit = 0;
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventLongHigh, &manchester_saved_state, NULL);
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventShortLow, &manchester_saved_state, NULL);
} else {
parser_step = SecPlus_v2DecoderStepReset;
}
} else {
if (DURATION_DIFF(duration, te_short) < te_delta) {
event = ManchesterEventShortHigh;
} else if (
DURATION_DIFF(duration, te_long) < te_delta) {
event = ManchesterEventLongHigh;
} else {
parser_step = SecPlus_v2DecoderStepReset;
}
}
if (event != ManchesterEventReset) {
bool bit;
bool data_ok = FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &bit);
if (data_ok) {
decode_data = (decode_data << 1) | bit;
decode_count_bit++;
}
}
break;
}
}
protected:
uint64_t secplus_packet_1 = 0;
ManchesterState manchester_saved_state = ManchesterStateMid0;
bool subghz_protocol_secplus_v2_check_packet() {
if ((decode_data & SECPLUS_V2_HEADER_MASK) == SECPLUS_V2_HEADER) {
if ((decode_data & SECPLUS_V2_PACKET_MASK) == SECPLUS_V2_PACKET_1) {
secplus_packet_1 = decode_data;
} else if (
((decode_data & SECPLUS_V2_PACKET_MASK) == SECPLUS_V2_PACKET_2) &&
(secplus_packet_1)) {
return true;
}
}
return false;
}
};
#endif

Some files were not shown because too many files have changed in this diff Show More