This commit is contained in:
Sil333033
2023-10-05 23:15:06 +02:00
113 changed files with 1397 additions and 4942 deletions

View File

@@ -803,6 +803,13 @@ MU_TEST(subghz_encoder_dooya_test) {
"Test encoder " SUBGHZ_PROTOCOL_DOOYA_NAME " error\r\n");
}
MU_TEST(subghz_decoder_acurite_592txr_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/acurite_592txr.sub"), WS_PROTOCOL_ACURITE_592TXR_NAME),
"Test decoder " WS_PROTOCOL_ACURITE_592TXR_NAME " error\r\n");
}
MU_TEST(subghz_random_test) {
mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n");
}
@@ -879,6 +886,7 @@ MU_TEST_SUITE(subghz) {
MU_RUN_TEST(subghz_encoder_smc5326_test);
MU_RUN_TEST(subghz_encoder_holtek_ht12x_test);
MU_RUN_TEST(subghz_encoder_dooya_test);
MU_RUN_TEST(subghz_decoder_acurite_592txr_test);
MU_RUN_TEST(subghz_random_test);
subghz_test_deinit();

View File

@@ -1,14 +0,0 @@
App(
appid="pocsag_pager",
name="POCSAG Pager",
apptype=FlipperAppType.EXTERNAL,
entry_point="pocsag_pager_app",
requires=["gui"],
stack_size=4 * 1024,
fap_icon="pocsag_pager_10px.png",
fap_category="Sub-GHz",
fap_icon_assets="images",
fap_author="@xMasterX & @Shmuma",
fap_version="1.0",
fap_description="App can capture POCSAG 1200 messages on CC1101 supported frequencies.",
)

View File

@@ -1,14 +0,0 @@
#pragma once
typedef enum {
//PCSGCustomEvent
PCSGCustomEventStartId = 100,
PCSGCustomEventSceneSettingLock,
PCSGCustomEventViewReceiverOK,
PCSGCustomEventViewReceiverConfig,
PCSGCustomEventViewReceiverBack,
PCSGCustomEventViewReceiverOffDisplay,
PCSGCustomEventViewReceiverUnlock,
} PCSGCustomEvent;

View File

@@ -1,49 +0,0 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#define PCSG_VERSION_APP "0.1"
#define PCSG_DEVELOPED "@xMasterX & @Shmuma"
#define PCSG_GITHUB "https://github.com/xMasterX/flipper-pager"
#define PCSG_KEY_FILE_VERSION 1
#define PCSG_KEY_FILE_TYPE "Flipper POCSAG Pager Key File"
/** PCSGRxKeyState state */
typedef enum {
PCSGRxKeyStateIDLE,
PCSGRxKeyStateBack,
PCSGRxKeyStateStart,
PCSGRxKeyStateAddKey,
} PCSGRxKeyState;
/** PCSGHopperState state */
typedef enum {
PCSGHopperStateOFF,
PCSGHopperStateRunnig,
PCSGHopperStatePause,
PCSGHopperStateRSSITimeOut,
} PCSGHopperState;
/** PCSGLock */
typedef enum {
PCSGLockOff,
PCSGLockOn,
} PCSGLock;
typedef enum {
POCSAGPagerViewVariableItemList,
POCSAGPagerViewSubmenu,
POCSAGPagerViewReceiver,
POCSAGPagerViewReceiverInfo,
POCSAGPagerViewWidget,
} POCSAGPagerView;
/** POCSAGPagerTxRx state */
typedef enum {
PCSGTxRxStateIDLE,
PCSGTxRxStateRx,
PCSGTxRxStateTx,
PCSGTxRxStateSleep,
} PCSGTxRxState;

View File

@@ -1,66 +0,0 @@
#include "radio_device_loader.h"
#include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
#include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h>
static void radio_device_loader_power_on() {
uint8_t attempts = 0;
while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
furi_hal_power_enable_otg();
//CC1101 power-up time
furi_delay_ms(10);
}
}
static void radio_device_loader_power_off() {
if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg();
}
bool radio_device_loader_is_connect_external(const char* name) {
bool is_connect = false;
bool is_otg_enabled = furi_hal_power_is_otg_enabled();
if(!is_otg_enabled) {
radio_device_loader_power_on();
}
is_connect = subghz_devices_is_connect(subghz_devices_get_by_name(name));
if(!is_otg_enabled) {
radio_device_loader_power_off();
}
return is_connect;
}
const SubGhzDevice* radio_device_loader_set(
const SubGhzDevice* current_radio_device,
SubGhzRadioDeviceType radio_device_type) {
const SubGhzDevice* radio_device;
if(radio_device_type == SubGhzRadioDeviceTypeExternalCC1101 &&
radio_device_loader_is_connect_external(SUBGHZ_DEVICE_CC1101_EXT_NAME)) {
radio_device_loader_power_on();
radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_EXT_NAME);
subghz_devices_begin(radio_device);
} else if(current_radio_device == NULL) {
radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME);
} else {
radio_device_loader_end(current_radio_device);
radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME);
}
return radio_device;
}
bool radio_device_loader_is_external(const SubGhzDevice* radio_device) {
furi_assert(radio_device);
return (radio_device != subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME));
}
void radio_device_loader_end(const SubGhzDevice* radio_device) {
furi_assert(radio_device);
radio_device_loader_power_off();
if(radio_device != subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME)) {
subghz_devices_end(radio_device);
}
}

View File

@@ -1,17 +0,0 @@
#pragma once
#include <lib/subghz/devices/devices.h>
/** SubGhzRadioDeviceType */
typedef enum {
SubGhzRadioDeviceTypeInternal,
SubGhzRadioDeviceTypeExternalCC1101,
} SubGhzRadioDeviceType;
const SubGhzDevice* radio_device_loader_set(
const SubGhzDevice* current_radio_device,
SubGhzRadioDeviceType radio_device_type);
bool radio_device_loader_is_external(const SubGhzDevice* radio_device);
void radio_device_loader_end(const SubGhzDevice* radio_device);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 B

View File

@@ -1,206 +0,0 @@
#include "pocsag_pager_app_i.h"
#include <furi.h>
#include <furi_hal.h>
#include <lib/flipper_format/flipper_format.h>
#include "protocols/protocol_items.h"
static bool pocsag_pager_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
POCSAGPagerApp* app = context;
return scene_manager_handle_custom_event(app->scene_manager, event);
}
static bool pocsag_pager_app_back_event_callback(void* context) {
furi_assert(context);
POCSAGPagerApp* app = context;
return scene_manager_handle_back_event(app->scene_manager);
}
static void pocsag_pager_app_tick_event_callback(void* context) {
furi_assert(context);
POCSAGPagerApp* app = context;
scene_manager_handle_tick_event(app->scene_manager);
}
POCSAGPagerApp* pocsag_pager_app_alloc() {
POCSAGPagerApp* app = malloc(sizeof(POCSAGPagerApp));
// GUI
app->gui = furi_record_open(RECORD_GUI);
// View Dispatcher
app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&pocsag_pager_scene_handlers, app);
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_custom_event_callback(
app->view_dispatcher, pocsag_pager_app_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
app->view_dispatcher, pocsag_pager_app_back_event_callback);
view_dispatcher_set_tick_event_callback(
app->view_dispatcher, pocsag_pager_app_tick_event_callback, 100);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
// Open Notification record
app->notifications = furi_record_open(RECORD_NOTIFICATION);
// Variable Item List
app->variable_item_list = variable_item_list_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
POCSAGPagerViewVariableItemList,
variable_item_list_get_view(app->variable_item_list));
// SubMenu
app->submenu = submenu_alloc();
view_dispatcher_add_view(
app->view_dispatcher, POCSAGPagerViewSubmenu, submenu_get_view(app->submenu));
// Widget
app->widget = widget_alloc();
view_dispatcher_add_view(
app->view_dispatcher, POCSAGPagerViewWidget, widget_get_view(app->widget));
// Receiver
app->pcsg_receiver = pcsg_view_receiver_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
POCSAGPagerViewReceiver,
pcsg_view_receiver_get_view(app->pcsg_receiver));
// Receiver Info
app->pcsg_receiver_info = pcsg_view_receiver_info_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
POCSAGPagerViewReceiverInfo,
pcsg_view_receiver_info_get_view(app->pcsg_receiver_info));
//init setting
app->setting = subghz_setting_alloc();
//ToDo FIX file name setting
subghz_setting_load(app->setting, EXT_PATH("pocsag/settings.txt"));
//init Worker & Protocol & History
app->lock = PCSGLockOff;
app->txrx = malloc(sizeof(POCSAGPagerTxRx));
app->txrx->preset = malloc(sizeof(SubGhzRadioPreset));
app->txrx->preset->name = furi_string_alloc();
furi_hal_power_suppress_charge_enter();
// Radio Devices init & load
subghz_devices_init();
app->txrx->radio_device =
radio_device_loader_set(app->txrx->radio_device, SubGhzRadioDeviceTypeExternalCC1101);
subghz_devices_reset(app->txrx->radio_device);
subghz_devices_idle(app->txrx->radio_device);
// Custom Presets load without using config file
FlipperFormat* temp_fm_preset = flipper_format_string_alloc();
flipper_format_write_string_cstr(
temp_fm_preset,
(const char*)"Custom_preset_data",
(const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 83 10 67 15 24 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00");
flipper_format_rewind(temp_fm_preset);
subghz_setting_load_custom_preset(app->setting, (const char*)"FM95", temp_fm_preset);
flipper_format_free(temp_fm_preset);
// custom presets loading - end
pcsg_preset_init(app, "FM95", 439987500, NULL, 0);
app->txrx->hopper_state = PCSGHopperStateOFF;
app->txrx->history = pcsg_history_alloc();
app->txrx->worker = subghz_worker_alloc();
app->txrx->environment = subghz_environment_alloc();
subghz_environment_set_protocol_registry(
app->txrx->environment, (void*)&pocsag_pager_protocol_registry);
app->txrx->receiver = subghz_receiver_alloc_init(app->txrx->environment);
subghz_receiver_set_filter(app->txrx->receiver, SubGhzProtocolFlag_Decodable);
subghz_worker_set_overrun_callback(
app->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
subghz_worker_set_pair_callback(
app->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode);
subghz_worker_set_context(app->txrx->worker, app->txrx->receiver);
scene_manager_next_scene(app->scene_manager, POCSAGPagerSceneStart);
return app;
}
void pocsag_pager_app_free(POCSAGPagerApp* app) {
furi_assert(app);
// Radio Devices sleep & off
pcsg_sleep(app);
radio_device_loader_end(app->txrx->radio_device);
subghz_devices_deinit();
// Submenu
view_dispatcher_remove_view(app->view_dispatcher, POCSAGPagerViewSubmenu);
submenu_free(app->submenu);
// Variable Item List
view_dispatcher_remove_view(app->view_dispatcher, POCSAGPagerViewVariableItemList);
variable_item_list_free(app->variable_item_list);
// Widget
view_dispatcher_remove_view(app->view_dispatcher, POCSAGPagerViewWidget);
widget_free(app->widget);
// Receiver
view_dispatcher_remove_view(app->view_dispatcher, POCSAGPagerViewReceiver);
pcsg_view_receiver_free(app->pcsg_receiver);
// Receiver Info
view_dispatcher_remove_view(app->view_dispatcher, POCSAGPagerViewReceiverInfo);
pcsg_view_receiver_info_free(app->pcsg_receiver_info);
//setting
subghz_setting_free(app->setting);
//Worker & Protocol & History
subghz_receiver_free(app->txrx->receiver);
subghz_environment_free(app->txrx->environment);
pcsg_history_free(app->txrx->history);
subghz_worker_free(app->txrx->worker);
furi_string_free(app->txrx->preset->name);
free(app->txrx->preset);
free(app->txrx);
// View dispatcher
view_dispatcher_free(app->view_dispatcher);
scene_manager_free(app->scene_manager);
// Notifications
furi_record_close(RECORD_NOTIFICATION);
app->notifications = NULL;
// Close records
furi_record_close(RECORD_GUI);
furi_hal_power_suppress_charge_exit();
free(app);
}
int32_t pocsag_pager_app(void* p) {
UNUSED(p);
POCSAGPagerApp* pocsag_pager_app = pocsag_pager_app_alloc();
view_dispatcher_run(pocsag_pager_app->view_dispatcher);
pocsag_pager_app_free(pocsag_pager_app);
return 0;
}

View File

@@ -1,146 +0,0 @@
#include "pocsag_pager_app_i.h"
#define TAG "POCSAGPager"
#include <flipper_format/flipper_format_i.h>
void pcsg_preset_init(
void* context,
const char* preset_name,
uint32_t frequency,
uint8_t* preset_data,
size_t preset_data_size) {
furi_assert(context);
POCSAGPagerApp* app = context;
furi_string_set(app->txrx->preset->name, preset_name);
app->txrx->preset->frequency = frequency;
app->txrx->preset->data = preset_data;
app->txrx->preset->data_size = preset_data_size;
}
void pcsg_get_frequency_modulation(
POCSAGPagerApp* app,
FuriString* frequency,
FuriString* modulation) {
furi_assert(app);
if(frequency != NULL) {
furi_string_printf(
frequency,
"%03ld.%02ld",
app->txrx->preset->frequency / 1000000 % 1000,
app->txrx->preset->frequency / 10000 % 100);
}
if(modulation != NULL) {
furi_string_printf(modulation, "%.2s", furi_string_get_cstr(app->txrx->preset->name));
}
}
void pcsg_begin(POCSAGPagerApp* app, uint8_t* preset_data) {
furi_assert(app);
subghz_devices_reset(app->txrx->radio_device);
subghz_devices_idle(app->txrx->radio_device);
subghz_devices_load_preset(app->txrx->radio_device, FuriHalSubGhzPresetCustom, preset_data);
// furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow);
app->txrx->txrx_state = PCSGTxRxStateIDLE;
}
uint32_t pcsg_rx(POCSAGPagerApp* app, uint32_t frequency) {
furi_assert(app);
if(!subghz_devices_is_frequency_valid(app->txrx->radio_device, frequency)) {
furi_crash("POCSAGPager: Incorrect RX frequency.");
}
furi_assert(
app->txrx->txrx_state != PCSGTxRxStateRx && app->txrx->txrx_state != PCSGTxRxStateSleep);
subghz_devices_idle(app->txrx->radio_device);
uint32_t value = subghz_devices_set_frequency(app->txrx->radio_device, frequency);
// Not need. init in subghz_devices_start_async_tx
// furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow);
subghz_devices_flush_rx(app->txrx->radio_device);
subghz_devices_set_rx(app->txrx->radio_device);
subghz_devices_start_async_rx(
app->txrx->radio_device, subghz_worker_rx_callback, app->txrx->worker);
subghz_worker_start(app->txrx->worker);
app->txrx->txrx_state = PCSGTxRxStateRx;
return value;
}
void pcsg_idle(POCSAGPagerApp* app) {
furi_assert(app);
furi_assert(app->txrx->txrx_state != PCSGTxRxStateSleep);
subghz_devices_idle(app->txrx->radio_device);
app->txrx->txrx_state = PCSGTxRxStateIDLE;
}
void pcsg_rx_end(POCSAGPagerApp* app) {
furi_assert(app);
furi_assert(app->txrx->txrx_state == PCSGTxRxStateRx);
if(subghz_worker_is_running(app->txrx->worker)) {
subghz_worker_stop(app->txrx->worker);
subghz_devices_stop_async_rx(app->txrx->radio_device);
}
subghz_devices_idle(app->txrx->radio_device);
app->txrx->txrx_state = PCSGTxRxStateIDLE;
}
void pcsg_sleep(POCSAGPagerApp* app) {
furi_assert(app);
subghz_devices_sleep(app->txrx->radio_device);
app->txrx->txrx_state = PCSGTxRxStateSleep;
}
void pcsg_hopper_update(POCSAGPagerApp* app) {
furi_assert(app);
switch(app->txrx->hopper_state) {
case PCSGHopperStateOFF:
return;
break;
case PCSGHopperStatePause:
return;
break;
case PCSGHopperStateRSSITimeOut:
if(app->txrx->hopper_timeout != 0) {
app->txrx->hopper_timeout--;
return;
}
break;
default:
break;
}
float rssi = -127.0f;
if(app->txrx->hopper_state != PCSGHopperStateRSSITimeOut) {
// See RSSI Calculation timings in CC1101 17.3 RSSI
rssi = subghz_devices_get_rssi(app->txrx->radio_device);
// Stay if RSSI is high enough
if(rssi > -90.0f) {
app->txrx->hopper_timeout = 10;
app->txrx->hopper_state = PCSGHopperStateRSSITimeOut;
return;
}
} else {
app->txrx->hopper_state = PCSGHopperStateRunnig;
}
// Select next frequency
if(app->txrx->hopper_idx_frequency <
subghz_setting_get_hopper_frequency_count(app->setting) - 1) {
app->txrx->hopper_idx_frequency++;
} else {
app->txrx->hopper_idx_frequency = 0;
}
if(app->txrx->txrx_state == PCSGTxRxStateRx) {
pcsg_rx_end(app);
};
if(app->txrx->txrx_state == PCSGTxRxStateIDLE) {
subghz_receiver_reset(app->txrx->receiver);
app->txrx->preset->frequency =
subghz_setting_get_hopper_frequency(app->setting, app->txrx->hopper_idx_frequency);
pcsg_rx(app, app->txrx->preset->frequency);
}
}

View File

@@ -1,76 +0,0 @@
#pragma once
#include "helpers/pocsag_pager_types.h"
#include "helpers/radio_device_loader.h"
#include "scenes/pocsag_pager_scene.h"
#include <gui/gui.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <gui/modules/submenu.h>
#include <gui/modules/variable_item_list.h>
#include <gui/modules/widget.h>
#include <notification/notification_messages.h>
#include "views/pocsag_pager_receiver.h"
#include "views/pocsag_pager_receiver_info.h"
#include "pocsag_pager_history.h"
#include <lib/subghz/subghz_setting.h>
#include <lib/subghz/subghz_worker.h>
#include <lib/subghz/receiver.h>
#include <lib/subghz/transmitter.h>
#include <lib/subghz/registry.h>
#include <lib/subghz/devices/devices.h>
typedef struct POCSAGPagerApp POCSAGPagerApp;
struct POCSAGPagerTxRx {
SubGhzWorker* worker;
SubGhzEnvironment* environment;
SubGhzReceiver* receiver;
SubGhzRadioPreset* preset;
PCSGHistory* history;
uint16_t idx_menu_chosen;
PCSGTxRxState txrx_state;
PCSGHopperState hopper_state;
uint8_t hopper_timeout;
uint8_t hopper_idx_frequency;
PCSGRxKeyState rx_key_state;
const SubGhzDevice* radio_device;
};
typedef struct POCSAGPagerTxRx POCSAGPagerTxRx;
struct POCSAGPagerApp {
Gui* gui;
ViewDispatcher* view_dispatcher;
POCSAGPagerTxRx* txrx;
SceneManager* scene_manager;
NotificationApp* notifications;
VariableItemList* variable_item_list;
Submenu* submenu;
Widget* widget;
PCSGReceiver* pcsg_receiver;
PCSGReceiverInfo* pcsg_receiver_info;
PCSGLock lock;
SubGhzSetting* setting;
};
void pcsg_preset_init(
void* context,
const char* preset_name,
uint32_t frequency,
uint8_t* preset_data,
size_t preset_data_size);
void pcsg_get_frequency_modulation(
POCSAGPagerApp* app,
FuriString* frequency,
FuriString* modulation);
void pcsg_begin(POCSAGPagerApp* app, uint8_t* preset_data);
uint32_t pcsg_rx(POCSAGPagerApp* app, uint32_t frequency);
void pcsg_idle(POCSAGPagerApp* app);
void pcsg_rx_end(POCSAGPagerApp* app);
void pcsg_sleep(POCSAGPagerApp* app);
void pcsg_hopper_update(POCSAGPagerApp* app);

View File

@@ -1,223 +0,0 @@
#include "pocsag_pager_history.h"
#include <flipper_format/flipper_format_i.h>
#include <lib/toolbox/stream/stream.h>
#include <lib/subghz/receiver.h>
#include "protocols/pcsg_generic.h"
#include <furi.h>
#define PCSG_HISTORY_MAX 50
#define TAG "PCSGHistory"
typedef struct {
FuriString* item_str;
FlipperFormat* flipper_string;
uint8_t type;
SubGhzRadioPreset* preset;
} PCSGHistoryItem;
ARRAY_DEF(PCSGHistoryItemArray, PCSGHistoryItem, M_POD_OPLIST)
#define M_OPL_PCSGHistoryItemArray_t() ARRAY_OPLIST(PCSGHistoryItemArray, M_POD_OPLIST)
typedef struct {
PCSGHistoryItemArray_t data;
} PCSGHistoryStruct;
struct PCSGHistory {
uint32_t last_update_timestamp;
uint16_t last_index_write;
uint8_t code_last_hash_data;
FuriString* tmp_string;
PCSGHistoryStruct* history;
};
PCSGHistory* pcsg_history_alloc(void) {
PCSGHistory* instance = malloc(sizeof(PCSGHistory));
instance->tmp_string = furi_string_alloc();
instance->history = malloc(sizeof(PCSGHistoryStruct));
PCSGHistoryItemArray_init(instance->history->data);
return instance;
}
void pcsg_history_free(PCSGHistory* instance) {
furi_assert(instance);
furi_string_free(instance->tmp_string);
for
M_EACH(item, instance->history->data, PCSGHistoryItemArray_t) {
furi_string_free(item->item_str);
furi_string_free(item->preset->name);
free(item->preset);
flipper_format_free(item->flipper_string);
item->type = 0;
}
PCSGHistoryItemArray_clear(instance->history->data);
free(instance->history);
free(instance);
}
uint32_t pcsg_history_get_frequency(PCSGHistory* instance, uint16_t idx) {
furi_assert(instance);
PCSGHistoryItem* item = PCSGHistoryItemArray_get(instance->history->data, idx);
return item->preset->frequency;
}
SubGhzRadioPreset* pcsg_history_get_radio_preset(PCSGHistory* instance, uint16_t idx) {
furi_assert(instance);
PCSGHistoryItem* item = PCSGHistoryItemArray_get(instance->history->data, idx);
return item->preset;
}
const char* pcsg_history_get_preset(PCSGHistory* instance, uint16_t idx) {
furi_assert(instance);
PCSGHistoryItem* item = PCSGHistoryItemArray_get(instance->history->data, idx);
return furi_string_get_cstr(item->preset->name);
}
void pcsg_history_reset(PCSGHistory* instance) {
furi_assert(instance);
furi_string_reset(instance->tmp_string);
for
M_EACH(item, instance->history->data, PCSGHistoryItemArray_t) {
furi_string_free(item->item_str);
furi_string_free(item->preset->name);
free(item->preset);
flipper_format_free(item->flipper_string);
item->type = 0;
}
PCSGHistoryItemArray_reset(instance->history->data);
instance->last_index_write = 0;
instance->code_last_hash_data = 0;
}
uint16_t pcsg_history_get_item(PCSGHistory* instance) {
furi_assert(instance);
return instance->last_index_write;
}
uint8_t pcsg_history_get_type_protocol(PCSGHistory* instance, uint16_t idx) {
furi_assert(instance);
PCSGHistoryItem* item = PCSGHistoryItemArray_get(instance->history->data, idx);
return item->type;
}
const char* pcsg_history_get_protocol_name(PCSGHistory* instance, uint16_t idx) {
furi_assert(instance);
PCSGHistoryItem* item = PCSGHistoryItemArray_get(instance->history->data, idx);
flipper_format_rewind(item->flipper_string);
if(!flipper_format_read_string(item->flipper_string, "Protocol", instance->tmp_string)) {
FURI_LOG_E(TAG, "Missing Protocol");
furi_string_reset(instance->tmp_string);
}
return furi_string_get_cstr(instance->tmp_string);
}
FlipperFormat* pcsg_history_get_raw_data(PCSGHistory* instance, uint16_t idx) {
furi_assert(instance);
PCSGHistoryItem* item = PCSGHistoryItemArray_get(instance->history->data, idx);
if(item->flipper_string) {
return item->flipper_string;
} else {
return NULL;
}
}
bool pcsg_history_get_text_space_left(PCSGHistory* instance, FuriString* output) {
furi_assert(instance);
if(instance->last_index_write == PCSG_HISTORY_MAX) {
if(output != NULL) furi_string_printf(output, "Memory is FULL");
return true;
}
if(output != NULL)
furi_string_printf(output, "%02u/%02u", instance->last_index_write, PCSG_HISTORY_MAX);
return false;
}
void pcsg_history_get_text_item_menu(PCSGHistory* instance, FuriString* output, uint16_t idx) {
PCSGHistoryItem* item = PCSGHistoryItemArray_get(instance->history->data, idx);
furi_string_set(output, item->item_str);
}
PCSGHistoryStateAddKey
pcsg_history_add_to_history(PCSGHistory* instance, void* context, SubGhzRadioPreset* preset) {
furi_assert(instance);
furi_assert(context);
if(instance->last_index_write >= PCSG_HISTORY_MAX) return PCSGHistoryStateAddKeyOverflow;
SubGhzProtocolDecoderBase* decoder_base = context;
if((instance->code_last_hash_data ==
subghz_protocol_decoder_base_get_hash_data(decoder_base)) &&
((furi_get_tick() - instance->last_update_timestamp) < 500)) {
instance->last_update_timestamp = furi_get_tick();
return PCSGHistoryStateAddKeyTimeOut;
}
instance->code_last_hash_data = subghz_protocol_decoder_base_get_hash_data(decoder_base);
instance->last_update_timestamp = furi_get_tick();
FlipperFormat* fff = flipper_format_string_alloc();
subghz_protocol_decoder_base_serialize(decoder_base, fff, preset);
do {
if(!flipper_format_rewind(fff)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
} while(false);
flipper_format_free(fff);
PCSGHistoryItem* item = PCSGHistoryItemArray_push_raw(instance->history->data);
item->preset = malloc(sizeof(SubGhzRadioPreset));
item->type = decoder_base->protocol->type;
item->preset->frequency = preset->frequency;
item->preset->name = furi_string_alloc();
furi_string_set(item->preset->name, preset->name);
item->preset->data = preset->data;
item->preset->data_size = preset->data_size;
item->item_str = furi_string_alloc();
item->flipper_string = flipper_format_string_alloc();
subghz_protocol_decoder_base_serialize(decoder_base, item->flipper_string, preset);
do {
if(!flipper_format_rewind(item->flipper_string)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
if(!flipper_format_read_string(item->flipper_string, "Protocol", instance->tmp_string)) {
FURI_LOG_E(TAG, "Missing Protocol");
break;
}
if(!flipper_format_rewind(item->flipper_string)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
FuriString* temp_ric = furi_string_alloc();
if(!flipper_format_read_string(item->flipper_string, "Ric", temp_ric)) {
FURI_LOG_E(TAG, "Missing Ric");
break;
}
FuriString* temp_message = furi_string_alloc();
if(!flipper_format_read_string(item->flipper_string, "Message", temp_message)) {
FURI_LOG_E(TAG, "Missing Message");
break;
}
furi_string_printf(
item->item_str,
"%s%s",
furi_string_get_cstr(temp_ric),
furi_string_get_cstr(temp_message));
furi_string_free(temp_message);
furi_string_free(temp_ric);
} while(false);
instance->last_index_write++;
return PCSGHistoryStateAddKeyNewDada;
return PCSGHistoryStateAddKeyUnknown;
}

View File

@@ -1,112 +0,0 @@
#pragma once
#include <math.h>
#include <furi.h>
#include <furi_hal.h>
#include <lib/flipper_format/flipper_format.h>
#include <lib/subghz/types.h>
typedef struct PCSGHistory PCSGHistory;
/** History state add key */
typedef enum {
PCSGHistoryStateAddKeyUnknown,
PCSGHistoryStateAddKeyTimeOut,
PCSGHistoryStateAddKeyNewDada,
PCSGHistoryStateAddKeyUpdateData,
PCSGHistoryStateAddKeyOverflow,
} PCSGHistoryStateAddKey;
/** Allocate PCSGHistory
*
* @return PCSGHistory*
*/
PCSGHistory* pcsg_history_alloc(void);
/** Free PCSGHistory
*
* @param instance - PCSGHistory instance
*/
void pcsg_history_free(PCSGHistory* instance);
/** Clear history
*
* @param instance - PCSGHistory instance
*/
void pcsg_history_reset(PCSGHistory* instance);
/** Get frequency to history[idx]
*
* @param instance - PCSGHistory instance
* @param idx - record index
* @return frequency - frequency Hz
*/
uint32_t pcsg_history_get_frequency(PCSGHistory* instance, uint16_t idx);
SubGhzRadioPreset* pcsg_history_get_radio_preset(PCSGHistory* instance, uint16_t idx);
/** Get preset to history[idx]
*
* @param instance - PCSGHistory instance
* @param idx - record index
* @return preset - preset name
*/
const char* pcsg_history_get_preset(PCSGHistory* instance, uint16_t idx);
/** Get history index write
*
* @param instance - PCSGHistory instance
* @return idx - current record index
*/
uint16_t pcsg_history_get_item(PCSGHistory* instance);
/** Get type protocol to history[idx]
*
* @param instance - PCSGHistory instance
* @param idx - record index
* @return type - type protocol
*/
uint8_t pcsg_history_get_type_protocol(PCSGHistory* instance, uint16_t idx);
/** Get name protocol to history[idx]
*
* @param instance - PCSGHistory instance
* @param idx - record index
* @return name - const char* name protocol
*/
const char* pcsg_history_get_protocol_name(PCSGHistory* instance, uint16_t idx);
/** Get string item menu to history[idx]
*
* @param instance - PCSGHistory instance
* @param output - FuriString* output
* @param idx - record index
*/
void pcsg_history_get_text_item_menu(PCSGHistory* instance, FuriString* output, uint16_t idx);
/** Get string the remaining number of records to history
*
* @param instance - PCSGHistory instance
* @param output - FuriString* output
* @return bool - is FUUL
*/
bool pcsg_history_get_text_space_left(PCSGHistory* instance, FuriString* output);
/** Add protocol to history
*
* @param instance - PCSGHistory instance
* @param context - SubGhzProtocolCommon context
* @param preset - SubGhzRadioPreset preset
* @return PCSGHistoryStateAddKey;
*/
PCSGHistoryStateAddKey
pcsg_history_add_to_history(PCSGHistory* instance, void* context, SubGhzRadioPreset* preset);
/** Get SubGhzProtocolCommonLoad to load into the protocol decoder bin data
*
* @param instance - PCSGHistory instance
* @param idx - record index
* @return SubGhzProtocolCommonLoad*
*/
FlipperFormat* pcsg_history_get_raw_data(PCSGHistory* instance, uint16_t idx);

View File

@@ -1,9 +0,0 @@
#include "protocol_items.h"
const SubGhzProtocol* pocsag_pager_protocol_registry_items[] = {
&subghz_protocol_pocsag,
};
const SubGhzProtocolRegistry pocsag_pager_protocol_registry = {
.items = pocsag_pager_protocol_registry_items,
.size = COUNT_OF(pocsag_pager_protocol_registry_items)};

View File

@@ -1,6 +0,0 @@
#pragma once
#include "../pocsag_pager_app_i.h"
#include "pocsag.h"
extern const SubGhzProtocolRegistry pocsag_pager_protocol_registry;

View File

@@ -1,214 +0,0 @@
#include "../pocsag_pager_app_i.h"
#include "../views/pocsag_pager_receiver.h"
static const NotificationSequence subghs_sequence_rx = {
&message_green_255,
&message_vibro_on,
&message_note_c6,
&message_delay_50,
&message_sound_off,
&message_vibro_off,
&message_delay_50,
NULL,
};
static const NotificationSequence subghs_sequence_rx_locked = {
&message_green_255,
&message_display_backlight_on,
&message_vibro_on,
&message_note_c6,
&message_delay_50,
&message_sound_off,
&message_vibro_off,
&message_delay_500,
&message_display_backlight_off,
NULL,
};
static void pocsag_pager_scene_receiver_update_statusbar(void* context) {
POCSAGPagerApp* app = context;
FuriString* history_stat_str;
history_stat_str = furi_string_alloc();
if(!pcsg_history_get_text_space_left(app->txrx->history, history_stat_str)) {
FuriString* frequency_str;
FuriString* modulation_str;
frequency_str = furi_string_alloc();
modulation_str = furi_string_alloc();
pcsg_get_frequency_modulation(app, frequency_str, modulation_str);
pcsg_view_receiver_add_data_statusbar(
app->pcsg_receiver,
furi_string_get_cstr(frequency_str),
furi_string_get_cstr(modulation_str),
furi_string_get_cstr(history_stat_str));
furi_string_free(frequency_str);
furi_string_free(modulation_str);
} else {
pcsg_view_receiver_add_data_statusbar(
app->pcsg_receiver, furi_string_get_cstr(history_stat_str), "", "");
}
furi_string_free(history_stat_str);
}
void pocsag_pager_scene_receiver_callback(PCSGCustomEvent event, void* context) {
furi_assert(context);
POCSAGPagerApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
static void pocsag_pager_scene_receiver_add_to_history_callback(
SubGhzReceiver* receiver,
SubGhzProtocolDecoderBase* decoder_base,
void* context) {
furi_assert(context);
POCSAGPagerApp* app = context;
FuriString* str_buff;
str_buff = furi_string_alloc();
if(pcsg_history_add_to_history(app->txrx->history, decoder_base, app->txrx->preset) ==
PCSGHistoryStateAddKeyNewDada) {
furi_string_reset(str_buff);
pcsg_history_get_text_item_menu(
app->txrx->history, str_buff, pcsg_history_get_item(app->txrx->history) - 1);
pcsg_view_receiver_add_item_to_menu(
app->pcsg_receiver,
furi_string_get_cstr(str_buff),
pcsg_history_get_type_protocol(
app->txrx->history, pcsg_history_get_item(app->txrx->history) - 1));
pocsag_pager_scene_receiver_update_statusbar(app);
notification_message(app->notifications, &sequence_blink_green_10);
if(app->lock != PCSGLockOn) {
notification_message(app->notifications, &subghs_sequence_rx);
} else {
notification_message(app->notifications, &subghs_sequence_rx_locked);
}
}
subghz_receiver_reset(receiver);
furi_string_free(str_buff);
app->txrx->rx_key_state = PCSGRxKeyStateAddKey;
}
void pocsag_pager_scene_receiver_on_enter(void* context) {
POCSAGPagerApp* app = context;
FuriString* str_buff;
str_buff = furi_string_alloc();
if(app->txrx->rx_key_state == PCSGRxKeyStateIDLE) {
pcsg_preset_init(app, "FM95", 439987500, NULL, 0);
pcsg_history_reset(app->txrx->history);
app->txrx->rx_key_state = PCSGRxKeyStateStart;
}
pcsg_view_receiver_set_lock(app->pcsg_receiver, app->lock);
pcsg_view_receiver_set_ext_module_state(
app->pcsg_receiver, radio_device_loader_is_external(app->txrx->radio_device));
//Load history to receiver
pcsg_view_receiver_exit(app->pcsg_receiver);
for(uint8_t i = 0; i < pcsg_history_get_item(app->txrx->history); i++) {
furi_string_reset(str_buff);
pcsg_history_get_text_item_menu(app->txrx->history, str_buff, i);
pcsg_view_receiver_add_item_to_menu(
app->pcsg_receiver,
furi_string_get_cstr(str_buff),
pcsg_history_get_type_protocol(app->txrx->history, i));
app->txrx->rx_key_state = PCSGRxKeyStateAddKey;
}
furi_string_free(str_buff);
pocsag_pager_scene_receiver_update_statusbar(app);
pcsg_view_receiver_set_callback(app->pcsg_receiver, pocsag_pager_scene_receiver_callback, app);
subghz_receiver_set_rx_callback(
app->txrx->receiver, pocsag_pager_scene_receiver_add_to_history_callback, app);
if(app->txrx->txrx_state == PCSGTxRxStateRx) {
pcsg_rx_end(app);
};
if((app->txrx->txrx_state == PCSGTxRxStateIDLE) ||
(app->txrx->txrx_state == PCSGTxRxStateSleep)) {
// Start RX
pcsg_begin(
app,
subghz_setting_get_preset_data_by_name(
app->setting, furi_string_get_cstr(app->txrx->preset->name)));
pcsg_rx(app, app->txrx->preset->frequency);
}
pcsg_view_receiver_set_idx_menu(app->pcsg_receiver, app->txrx->idx_menu_chosen);
view_dispatcher_switch_to_view(app->view_dispatcher, POCSAGPagerViewReceiver);
}
bool pocsag_pager_scene_receiver_on_event(void* context, SceneManagerEvent event) {
POCSAGPagerApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case PCSGCustomEventViewReceiverBack:
// Stop CC1101 Rx
if(app->txrx->txrx_state == PCSGTxRxStateRx) {
pcsg_rx_end(app);
pcsg_idle(app);
};
app->txrx->hopper_state = PCSGHopperStateOFF;
app->txrx->idx_menu_chosen = 0;
subghz_receiver_set_rx_callback(app->txrx->receiver, NULL, app);
app->txrx->rx_key_state = PCSGRxKeyStateIDLE;
pcsg_preset_init(app, "FM95", 439987500, NULL, 0);
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, POCSAGPagerSceneStart);
consumed = true;
break;
case PCSGCustomEventViewReceiverOK:
app->txrx->idx_menu_chosen = pcsg_view_receiver_get_idx_menu(app->pcsg_receiver);
scene_manager_next_scene(app->scene_manager, POCSAGPagerSceneReceiverInfo);
consumed = true;
break;
case PCSGCustomEventViewReceiverConfig:
app->txrx->idx_menu_chosen = pcsg_view_receiver_get_idx_menu(app->pcsg_receiver);
scene_manager_next_scene(app->scene_manager, POCSAGPagerSceneReceiverConfig);
consumed = true;
break;
case PCSGCustomEventViewReceiverOffDisplay:
notification_message(app->notifications, &sequence_display_backlight_off);
consumed = true;
break;
case PCSGCustomEventViewReceiverUnlock:
app->lock = PCSGLockOff;
consumed = true;
break;
default:
break;
}
} else if(event.type == SceneManagerEventTypeTick) {
if(app->txrx->hopper_state != PCSGHopperStateOFF) {
pcsg_hopper_update(app);
pocsag_pager_scene_receiver_update_statusbar(app);
}
// Get current RSSI
float rssi = subghz_devices_get_rssi(app->txrx->radio_device);
pcsg_receiver_rssi(app->pcsg_receiver, rssi);
if(app->txrx->txrx_state == PCSGTxRxStateRx) {
notification_message(app->notifications, &sequence_blink_cyan_10);
}
}
return consumed;
}
void pocsag_pager_scene_receiver_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -1,30 +0,0 @@
#include "../pocsag_pager_app_i.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const pocsag_pager_scene_on_enter_handlers[])(void*) = {
#include "pocsag_pager_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_event handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
bool (*const pocsag_pager_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "pocsag_pager_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_exit handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
void (*const pocsag_pager_scene_on_exit_handlers[])(void* context) = {
#include "pocsag_pager_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers pocsag_pager_scene_handlers = {
.on_enter_handlers = pocsag_pager_scene_on_enter_handlers,
.on_event_handlers = pocsag_pager_scene_on_event_handlers,
.on_exit_handlers = pocsag_pager_scene_on_exit_handlers,
.scene_num = POCSAGPagerSceneNum,
};

View File

@@ -1,29 +0,0 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) POCSAGPagerScene##id,
typedef enum {
#include "pocsag_pager_scene_config.h"
POCSAGPagerSceneNum,
} POCSAGPagerScene;
#undef ADD_SCENE
extern const SceneManagerHandlers pocsag_pager_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "pocsag_pager_scene_config.h"
#undef ADD_SCENE
// Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
#include "pocsag_pager_scene_config.h"
#undef ADD_SCENE
// Generate scene on_exit handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
#include "pocsag_pager_scene_config.h"
#undef ADD_SCENE

View File

@@ -1,74 +0,0 @@
#include "../pocsag_pager_app_i.h"
#include "../helpers/pocsag_pager_types.h"
void pocsag_pager_scene_about_widget_callback(GuiButtonType result, InputType type, void* context) {
POCSAGPagerApp* app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
}
void pocsag_pager_scene_about_on_enter(void* context) {
POCSAGPagerApp* app = context;
FuriString* temp_str;
temp_str = furi_string_alloc();
furi_string_printf(temp_str, "\e#%s\n", "Information");
furi_string_cat_printf(temp_str, "Version: %s\n", PCSG_VERSION_APP);
furi_string_cat_printf(temp_str, "Developed by:\n%s\n\n", PCSG_DEVELOPED);
furi_string_cat_printf(temp_str, "Github: %s\n\n", PCSG_GITHUB);
furi_string_cat_printf(temp_str, "\e#%s\n", "Description");
furi_string_cat_printf(temp_str, "Receiving POCSAG Pager \nmessages\n\n");
furi_string_cat_printf(temp_str, "Supported protocols:\n");
size_t i = 0;
const char* protocol_name =
subghz_environment_get_protocol_name_registry(app->txrx->environment, i++);
do {
furi_string_cat_printf(temp_str, "%s\n", protocol_name);
protocol_name = subghz_environment_get_protocol_name_registry(app->txrx->environment, i++);
} while(protocol_name != NULL);
widget_add_text_box_element(
app->widget,
0,
0,
128,
14,
AlignCenter,
AlignBottom,
"\e#\e! \e!\n",
false);
widget_add_text_box_element(
app->widget,
0,
2,
128,
14,
AlignCenter,
AlignBottom,
"\e#\e! POCSAG Pager \e!\n",
false);
widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str));
furi_string_free(temp_str);
view_dispatcher_switch_to_view(app->view_dispatcher, POCSAGPagerViewWidget);
}
bool pocsag_pager_scene_about_on_event(void* context, SceneManagerEvent event) {
POCSAGPagerApp* app = context;
bool consumed = false;
UNUSED(app);
UNUSED(event);
return consumed;
}
void pocsag_pager_scene_about_on_exit(void* context) {
POCSAGPagerApp* app = context;
// Clear views
widget_reset(app->widget);
}

View File

@@ -1,5 +0,0 @@
ADD_SCENE(pocsag_pager, start, Start)
ADD_SCENE(pocsag_pager, about, About)
ADD_SCENE(pocsag_pager, receiver, Receiver)
ADD_SCENE(pocsag_pager, receiver_config, ReceiverConfig)
ADD_SCENE(pocsag_pager, receiver_info, ReceiverInfo)

View File

@@ -1,221 +0,0 @@
#include "../pocsag_pager_app_i.h"
enum PCSGSettingIndex {
PCSGSettingIndexFrequency,
PCSGSettingIndexHopping,
PCSGSettingIndexModulation,
PCSGSettingIndexLock,
};
#define HOPPING_COUNT 2
const char* const hopping_text[HOPPING_COUNT] = {
"OFF",
"ON",
};
const uint32_t hopping_value[HOPPING_COUNT] = {
PCSGHopperStateOFF,
PCSGHopperStateRunnig,
};
uint8_t pocsag_pager_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
furi_assert(context);
POCSAGPagerApp* app = context;
uint8_t index = 0;
for(uint8_t i = 0; i < subghz_setting_get_frequency_count(app->setting); i++) {
if(value == subghz_setting_get_frequency(app->setting, i)) {
index = i;
break;
} else {
index = subghz_setting_get_frequency_default_index(app->setting);
}
}
return index;
}
uint8_t pocsag_pager_scene_receiver_config_next_preset(const char* preset_name, void* context) {
furi_assert(context);
POCSAGPagerApp* app = context;
uint8_t index = 0;
for(uint8_t i = 0; i < subghz_setting_get_preset_count(app->setting); i++) {
if(!strcmp(subghz_setting_get_preset_name(app->setting, i), preset_name)) {
index = i;
break;
} else {
// index = subghz_setting_get_frequency_default_index(app ->setting);
}
}
return index;
}
uint8_t pocsag_pager_scene_receiver_config_hopper_value_index(
const uint32_t value,
const uint32_t values[],
uint8_t values_count,
void* context) {
furi_assert(context);
UNUSED(values_count);
POCSAGPagerApp* app = context;
if(value == values[0]) {
return 0;
} else {
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
app->scene_manager, POCSAGPagerSceneReceiverConfig),
" -----");
return 1;
}
}
static void pocsag_pager_scene_receiver_config_set_frequency(VariableItem* item) {
POCSAGPagerApp* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
if(app->txrx->hopper_state == PCSGHopperStateOFF) {
char text_buf[10] = {0};
snprintf(
text_buf,
sizeof(text_buf),
"%lu.%02lu",
subghz_setting_get_frequency(app->setting, index) / 1000000,
(subghz_setting_get_frequency(app->setting, index) % 1000000) / 10000);
variable_item_set_current_value_text(item, text_buf);
app->txrx->preset->frequency = subghz_setting_get_frequency(app->setting, index);
} else {
variable_item_set_current_value_index(
item, subghz_setting_get_frequency_default_index(app->setting));
}
}
static void pocsag_pager_scene_receiver_config_set_preset(VariableItem* item) {
POCSAGPagerApp* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(
item, subghz_setting_get_preset_name(app->setting, index));
pcsg_preset_init(
app,
subghz_setting_get_preset_name(app->setting, index),
app->txrx->preset->frequency,
subghz_setting_get_preset_data(app->setting, index),
subghz_setting_get_preset_data_size(app->setting, index));
}
static void pocsag_pager_scene_receiver_config_set_hopping_running(VariableItem* item) {
POCSAGPagerApp* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, hopping_text[index]);
if(hopping_value[index] == PCSGHopperStateOFF) {
char text_buf[10] = {0};
snprintf(
text_buf,
sizeof(text_buf),
"%lu.%02lu",
subghz_setting_get_default_frequency(app->setting) / 1000000,
(subghz_setting_get_default_frequency(app->setting) % 1000000) / 10000);
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
app->scene_manager, POCSAGPagerSceneReceiverConfig),
text_buf);
app->txrx->preset->frequency = subghz_setting_get_default_frequency(app->setting);
variable_item_set_current_value_index(
(VariableItem*)scene_manager_get_scene_state(
app->scene_manager, POCSAGPagerSceneReceiverConfig),
subghz_setting_get_frequency_default_index(app->setting));
} else {
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
app->scene_manager, POCSAGPagerSceneReceiverConfig),
" -----");
variable_item_set_current_value_index(
(VariableItem*)scene_manager_get_scene_state(
app->scene_manager, POCSAGPagerSceneReceiverConfig),
subghz_setting_get_frequency_default_index(app->setting));
}
app->txrx->hopper_state = hopping_value[index];
}
static void
pocsag_pager_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) {
furi_assert(context);
POCSAGPagerApp* app = context;
if(index == PCSGSettingIndexLock) {
view_dispatcher_send_custom_event(app->view_dispatcher, PCSGCustomEventSceneSettingLock);
}
}
void pocsag_pager_scene_receiver_config_on_enter(void* context) {
POCSAGPagerApp* app = context;
VariableItem* item;
uint8_t value_index;
item = variable_item_list_add(
app->variable_item_list,
"Frequency:",
subghz_setting_get_frequency_count(app->setting),
pocsag_pager_scene_receiver_config_set_frequency,
app);
value_index =
pocsag_pager_scene_receiver_config_next_frequency(app->txrx->preset->frequency, app);
scene_manager_set_scene_state(
app->scene_manager, POCSAGPagerSceneReceiverConfig, (uint32_t)item);
variable_item_set_current_value_index(item, value_index);
char text_buf[10] = {0};
snprintf(
text_buf,
sizeof(text_buf),
"%lu.%02lu",
subghz_setting_get_frequency(app->setting, value_index) / 1000000,
(subghz_setting_get_frequency(app->setting, value_index) % 1000000) / 10000);
variable_item_set_current_value_text(item, text_buf);
item = variable_item_list_add(
app->variable_item_list,
"Hopping:",
HOPPING_COUNT,
pocsag_pager_scene_receiver_config_set_hopping_running,
app);
value_index = pocsag_pager_scene_receiver_config_hopper_value_index(
app->txrx->hopper_state, hopping_value, HOPPING_COUNT, app);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, hopping_text[value_index]);
item = variable_item_list_add(
app->variable_item_list,
"Modulation:",
subghz_setting_get_preset_count(app->setting),
pocsag_pager_scene_receiver_config_set_preset,
app);
value_index = pocsag_pager_scene_receiver_config_next_preset(
furi_string_get_cstr(app->txrx->preset->name), app);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(
item, subghz_setting_get_preset_name(app->setting, value_index));
variable_item_list_add(app->variable_item_list, "Lock Keyboard", 1, NULL, NULL);
variable_item_list_set_enter_callback(
app->variable_item_list, pocsag_pager_scene_receiver_config_var_list_enter_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, POCSAGPagerViewVariableItemList);
}
bool pocsag_pager_scene_receiver_config_on_event(void* context, SceneManagerEvent event) {
POCSAGPagerApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == PCSGCustomEventSceneSettingLock) {
app->lock = PCSGLockOn;
scene_manager_previous_scene(app->scene_manager);
consumed = true;
}
}
return consumed;
}
void pocsag_pager_scene_receiver_config_on_exit(void* context) {
POCSAGPagerApp* app = context;
variable_item_list_set_selected_item(app->variable_item_list, 0);
variable_item_list_reset(app->variable_item_list);
}

View File

@@ -1,50 +0,0 @@
#include "../pocsag_pager_app_i.h"
#include "../views/pocsag_pager_receiver.h"
void pocsag_pager_scene_receiver_info_callback(PCSGCustomEvent event, void* context) {
furi_assert(context);
POCSAGPagerApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
static void pocsag_pager_scene_receiver_info_add_to_history_callback(
SubGhzReceiver* receiver,
SubGhzProtocolDecoderBase* decoder_base,
void* context) {
furi_assert(context);
POCSAGPagerApp* app = context;
if(pcsg_history_add_to_history(app->txrx->history, decoder_base, app->txrx->preset) ==
PCSGHistoryStateAddKeyUpdateData) {
pcsg_view_receiver_info_update(
app->pcsg_receiver_info,
pcsg_history_get_raw_data(app->txrx->history, app->txrx->idx_menu_chosen));
subghz_receiver_reset(receiver);
notification_message(app->notifications, &sequence_blink_green_10);
app->txrx->rx_key_state = PCSGRxKeyStateAddKey;
}
}
void pocsag_pager_scene_receiver_info_on_enter(void* context) {
POCSAGPagerApp* app = context;
subghz_receiver_set_rx_callback(
app->txrx->receiver, pocsag_pager_scene_receiver_info_add_to_history_callback, app);
pcsg_view_receiver_info_update(
app->pcsg_receiver_info,
pcsg_history_get_raw_data(app->txrx->history, app->txrx->idx_menu_chosen));
view_dispatcher_switch_to_view(app->view_dispatcher, POCSAGPagerViewReceiverInfo);
}
bool pocsag_pager_scene_receiver_info_on_event(void* context, SceneManagerEvent event) {
POCSAGPagerApp* app = context;
bool consumed = false;
UNUSED(app);
UNUSED(event);
return consumed;
}
void pocsag_pager_scene_receiver_info_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -1,58 +0,0 @@
#include "../pocsag_pager_app_i.h"
typedef enum {
SubmenuIndexPOCSAGPagerReceiver,
SubmenuIndexPOCSAGPagerAbout,
} SubmenuIndex;
void pocsag_pager_scene_start_submenu_callback(void* context, uint32_t index) {
POCSAGPagerApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void pocsag_pager_scene_start_on_enter(void* context) {
UNUSED(context);
POCSAGPagerApp* app = context;
Submenu* submenu = app->submenu;
submenu_add_item(
submenu,
"Receive messages",
SubmenuIndexPOCSAGPagerReceiver,
pocsag_pager_scene_start_submenu_callback,
app);
submenu_add_item(
submenu,
"About",
SubmenuIndexPOCSAGPagerAbout,
pocsag_pager_scene_start_submenu_callback,
app);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(app->scene_manager, POCSAGPagerSceneStart));
view_dispatcher_switch_to_view(app->view_dispatcher, POCSAGPagerViewSubmenu);
}
bool pocsag_pager_scene_start_on_event(void* context, SceneManagerEvent event) {
POCSAGPagerApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexPOCSAGPagerAbout) {
scene_manager_next_scene(app->scene_manager, POCSAGPagerSceneAbout);
consumed = true;
} else if(event.event == SubmenuIndexPOCSAGPagerReceiver) {
scene_manager_next_scene(app->scene_manager, POCSAGPagerSceneReceiver);
consumed = true;
}
scene_manager_set_scene_state(app->scene_manager, POCSAGPagerSceneStart, event.event);
}
return consumed;
}
void pocsag_pager_scene_start_on_exit(void* context) {
POCSAGPagerApp* app = context;
submenu_reset(app->submenu);
}

View File

@@ -1,479 +0,0 @@
#include "pocsag_pager_receiver.h"
#include "../pocsag_pager_app_i.h"
#include "pocsag_pager_icons.h"
#include <assets_icons.h>
#include <math.h>
#include <input/input.h>
#include <gui/elements.h>
#include <m-array.h>
#define FRAME_HEIGHT 12
#define MAX_LEN_PX 112
#define MENU_ITEMS 4u
#define UNLOCK_CNT 3
#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
typedef struct {
FuriString* item_str;
uint8_t type;
} PCSGReceiverMenuItem;
ARRAY_DEF(PCSGReceiverMenuItemArray, PCSGReceiverMenuItem, M_POD_OPLIST)
#define M_OPL_PCSGReceiverMenuItemArray_t() ARRAY_OPLIST(PCSGReceiverMenuItemArray, M_POD_OPLIST)
struct PCSGReceiverHistory {
PCSGReceiverMenuItemArray_t data;
};
typedef struct PCSGReceiverHistory PCSGReceiverHistory;
static const Icon* ReceiverItemIcons[] = {
[SubGhzProtocolTypeUnknown] = &I_Quest_7x8,
[SubGhzProtocolTypeStatic] = &I_Message_8x7,
[SubGhzProtocolTypeDynamic] = &I_Lock_7x8,
};
typedef enum {
PCSGReceiverBarShowDefault,
PCSGReceiverBarShowLock,
PCSGReceiverBarShowToUnlockPress,
PCSGReceiverBarShowUnlock,
} PCSGReceiverBarShow;
struct PCSGReceiver {
PCSGLock lock;
uint8_t lock_count;
FuriTimer* timer;
View* view;
PCSGReceiverCallback callback;
void* context;
};
typedef struct {
FuriString* frequency_str;
FuriString* preset_str;
FuriString* history_stat_str;
PCSGReceiverHistory* history;
uint16_t idx;
uint16_t list_offset;
uint16_t history_item;
PCSGReceiverBarShow bar_show;
uint8_t u_rssi;
bool ext_module;
} PCSGReceiverModel;
void pcsg_receiver_rssi(PCSGReceiver* instance, float rssi) {
furi_assert(instance);
with_view_model(
instance->view,
PCSGReceiverModel * model,
{
if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) {
model->u_rssi = 0;
} else {
model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN);
}
},
true);
}
void pcsg_view_receiver_set_lock(PCSGReceiver* pcsg_receiver, PCSGLock lock) {
furi_assert(pcsg_receiver);
pcsg_receiver->lock_count = 0;
if(lock == PCSGLockOn) {
pcsg_receiver->lock = lock;
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{ model->bar_show = PCSGReceiverBarShowLock; },
true);
furi_timer_start(pcsg_receiver->timer, pdMS_TO_TICKS(1000));
} else {
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{ model->bar_show = PCSGReceiverBarShowDefault; },
true);
}
}
void pcsg_view_receiver_set_ext_module_state(PCSGReceiver* pcsg_receiver, bool is_external) {
furi_assert(pcsg_receiver);
with_view_model(
pcsg_receiver->view, PCSGReceiverModel * model, { model->ext_module = is_external; }, true);
}
void pcsg_view_receiver_set_callback(
PCSGReceiver* pcsg_receiver,
PCSGReceiverCallback callback,
void* context) {
furi_assert(pcsg_receiver);
furi_assert(callback);
pcsg_receiver->callback = callback;
pcsg_receiver->context = context;
}
static void pcsg_view_receiver_update_offset(PCSGReceiver* pcsg_receiver) {
furi_assert(pcsg_receiver);
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{
size_t history_item = model->history_item;
uint16_t bounds = history_item > 3 ? 2 : history_item;
if(history_item > 3 && model->idx >= (int16_t)(history_item - 1)) {
model->list_offset = model->idx - 3;
} else if(model->list_offset < model->idx - bounds) {
model->list_offset =
CLAMP(model->list_offset + 1, (int16_t)(history_item - bounds), 0);
} else if(model->list_offset > model->idx - bounds) {
model->list_offset = CLAMP(model->idx - 1, (int16_t)(history_item - bounds), 0);
}
},
true);
}
void pcsg_view_receiver_add_item_to_menu(
PCSGReceiver* pcsg_receiver,
const char* name,
uint8_t type) {
furi_assert(pcsg_receiver);
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{
PCSGReceiverMenuItem* item_menu =
PCSGReceiverMenuItemArray_push_raw(model->history->data);
item_menu->item_str = furi_string_alloc_set(name);
item_menu->type = type;
if((model->idx == model->history_item - 1)) {
model->history_item++;
model->idx++;
} else {
model->history_item++;
}
},
true);
pcsg_view_receiver_update_offset(pcsg_receiver);
}
void pcsg_view_receiver_add_data_statusbar(
PCSGReceiver* pcsg_receiver,
const char* frequency_str,
const char* preset_str,
const char* history_stat_str) {
furi_assert(pcsg_receiver);
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{
furi_string_set_str(model->frequency_str, frequency_str);
furi_string_set_str(model->preset_str, preset_str);
furi_string_set_str(model->history_stat_str, history_stat_str);
},
true);
}
static void pcsg_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) {
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT);
canvas_set_color(canvas, ColorWhite);
canvas_draw_dot(canvas, 0, 0 + idx * FRAME_HEIGHT);
canvas_draw_dot(canvas, 1, 0 + idx * FRAME_HEIGHT);
canvas_draw_dot(canvas, 0, (0 + idx * FRAME_HEIGHT) + 1);
canvas_draw_dot(canvas, 0, (0 + idx * FRAME_HEIGHT) + 11);
canvas_draw_dot(canvas, scrollbar ? 121 : 126, 0 + idx * FRAME_HEIGHT);
canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11);
}
static void pcsg_view_rssi_draw(Canvas* canvas, PCSGReceiverModel* model) {
for(uint8_t i = 1; i < model->u_rssi; i++) {
if(i % 5) {
canvas_draw_dot(canvas, 46 + i, 50);
canvas_draw_dot(canvas, 47 + i, 51);
canvas_draw_dot(canvas, 46 + i, 52);
}
}
}
void pcsg_view_receiver_draw(Canvas* canvas, PCSGReceiverModel* model) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
elements_button_left(canvas, "Config");
//canvas_draw_line(canvas, 46, 51, 125, 51);
bool scrollbar = model->history_item > 4;
FuriString* str_buff;
str_buff = furi_string_alloc();
PCSGReceiverMenuItem* item_menu;
for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) {
size_t idx = CLAMP((uint16_t)(i + model->list_offset), model->history_item, 0);
item_menu = PCSGReceiverMenuItemArray_get(model->history->data, idx);
furi_string_set(str_buff, item_menu->item_str);
furi_string_replace_all(str_buff, "#", "");
elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 7 : MAX_LEN_PX);
if(model->idx == idx) {
pcsg_view_receiver_draw_frame(canvas, i, scrollbar);
} else {
canvas_set_color(canvas, ColorBlack);
}
canvas_draw_icon(canvas, 4, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]);
canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, furi_string_get_cstr(str_buff));
furi_string_reset(str_buff);
}
if(scrollbar) {
elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item);
}
furi_string_free(str_buff);
canvas_set_color(canvas, ColorBlack);
if(model->history_item == 0) {
canvas_draw_icon(canvas, 0, 0, model->ext_module ? &I_Fishing_123x52 : &I_Scanning_123x52);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 63, 46, "Scanning...");
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 44, 10, model->ext_module ? "Ext" : "Int");
}
// Draw RSSI
pcsg_view_rssi_draw(canvas, model);
switch(model->bar_show) {
case PCSGReceiverBarShowLock:
canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8);
canvas_draw_str(canvas, 74, 62, "Locked");
break;
case PCSGReceiverBarShowToUnlockPress:
canvas_draw_str(canvas, 44, 62, furi_string_get_cstr(model->frequency_str));
canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str));
canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str));
canvas_set_font(canvas, FontSecondary);
elements_bold_rounded_frame(canvas, 14, 8, 99, 48);
elements_multiline_text(canvas, 65, 26, "To unlock\npress:");
canvas_draw_icon(canvas, 65, 42, &I_Pin_back_arrow_10x8);
canvas_draw_icon(canvas, 80, 42, &I_Pin_back_arrow_10x8);
canvas_draw_icon(canvas, 95, 42, &I_Pin_back_arrow_10x8);
canvas_draw_icon(canvas, 16, 13, &I_WarningDolphin_45x42);
canvas_draw_dot(canvas, 17, 61);
break;
case PCSGReceiverBarShowUnlock:
canvas_draw_icon(canvas, 64, 55, &I_Unlock_7x8);
canvas_draw_str(canvas, 74, 62, "Unlocked");
break;
default:
canvas_draw_str(canvas, 44, 62, furi_string_get_cstr(model->frequency_str));
canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str));
canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str));
break;
}
}
static void pcsg_view_receiver_timer_callback(void* context) {
furi_assert(context);
PCSGReceiver* pcsg_receiver = context;
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{ model->bar_show = PCSGReceiverBarShowDefault; },
true);
if(pcsg_receiver->lock_count < UNLOCK_CNT) {
pcsg_receiver->callback(PCSGCustomEventViewReceiverOffDisplay, pcsg_receiver->context);
} else {
pcsg_receiver->lock = PCSGLockOff;
pcsg_receiver->callback(PCSGCustomEventViewReceiverUnlock, pcsg_receiver->context);
}
pcsg_receiver->lock_count = 0;
}
bool pcsg_view_receiver_input(InputEvent* event, void* context) {
furi_assert(context);
PCSGReceiver* pcsg_receiver = context;
if(pcsg_receiver->lock == PCSGLockOn) {
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{ model->bar_show = PCSGReceiverBarShowToUnlockPress; },
true);
if(pcsg_receiver->lock_count == 0) {
furi_timer_start(pcsg_receiver->timer, pdMS_TO_TICKS(1000));
}
if(event->key == InputKeyBack && event->type == InputTypeShort) {
pcsg_receiver->lock_count++;
}
if(pcsg_receiver->lock_count >= UNLOCK_CNT) {
pcsg_receiver->callback(PCSGCustomEventViewReceiverUnlock, pcsg_receiver->context);
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{ model->bar_show = PCSGReceiverBarShowUnlock; },
true);
pcsg_receiver->lock = PCSGLockOff;
furi_timer_start(pcsg_receiver->timer, pdMS_TO_TICKS(650));
}
return true;
}
if(event->key == InputKeyBack && event->type == InputTypeShort) {
pcsg_receiver->callback(PCSGCustomEventViewReceiverBack, pcsg_receiver->context);
} else if(
event->key == InputKeyUp &&
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{
if(model->idx != 0) model->idx--;
},
true);
} else if(
event->key == InputKeyDown &&
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{
if(model->history_item && model->idx != model->history_item - 1) model->idx++;
},
true);
} else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
pcsg_receiver->callback(PCSGCustomEventViewReceiverConfig, pcsg_receiver->context);
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{
if(model->history_item != 0) {
pcsg_receiver->callback(PCSGCustomEventViewReceiverOK, pcsg_receiver->context);
}
},
false);
}
pcsg_view_receiver_update_offset(pcsg_receiver);
return true;
}
void pcsg_view_receiver_enter(void* context) {
furi_assert(context);
}
void pcsg_view_receiver_exit(void* context) {
furi_assert(context);
PCSGReceiver* pcsg_receiver = context;
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{
furi_string_reset(model->frequency_str);
furi_string_reset(model->preset_str);
furi_string_reset(model->history_stat_str);
for
M_EACH(item_menu, model->history->data, PCSGReceiverMenuItemArray_t) {
furi_string_free(item_menu->item_str);
item_menu->type = 0;
}
PCSGReceiverMenuItemArray_reset(model->history->data);
model->idx = 0;
model->list_offset = 0;
model->history_item = 0;
},
false);
furi_timer_stop(pcsg_receiver->timer);
}
PCSGReceiver* pcsg_view_receiver_alloc() {
PCSGReceiver* pcsg_receiver = malloc(sizeof(PCSGReceiver));
// View allocation and configuration
pcsg_receiver->view = view_alloc();
pcsg_receiver->lock = PCSGLockOff;
pcsg_receiver->lock_count = 0;
view_allocate_model(pcsg_receiver->view, ViewModelTypeLocking, sizeof(PCSGReceiverModel));
view_set_context(pcsg_receiver->view, pcsg_receiver);
view_set_draw_callback(pcsg_receiver->view, (ViewDrawCallback)pcsg_view_receiver_draw);
view_set_input_callback(pcsg_receiver->view, pcsg_view_receiver_input);
view_set_enter_callback(pcsg_receiver->view, pcsg_view_receiver_enter);
view_set_exit_callback(pcsg_receiver->view, pcsg_view_receiver_exit);
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{
model->frequency_str = furi_string_alloc();
model->preset_str = furi_string_alloc();
model->history_stat_str = furi_string_alloc();
model->bar_show = PCSGReceiverBarShowDefault;
model->history = malloc(sizeof(PCSGReceiverHistory));
PCSGReceiverMenuItemArray_init(model->history->data);
},
true);
pcsg_receiver->timer =
furi_timer_alloc(pcsg_view_receiver_timer_callback, FuriTimerTypeOnce, pcsg_receiver);
return pcsg_receiver;
}
void pcsg_view_receiver_free(PCSGReceiver* pcsg_receiver) {
furi_assert(pcsg_receiver);
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{
furi_string_free(model->frequency_str);
furi_string_free(model->preset_str);
furi_string_free(model->history_stat_str);
for
M_EACH(item_menu, model->history->data, PCSGReceiverMenuItemArray_t) {
furi_string_free(item_menu->item_str);
item_menu->type = 0;
}
PCSGReceiverMenuItemArray_clear(model->history->data);
free(model->history);
},
false);
furi_timer_free(pcsg_receiver->timer);
view_free(pcsg_receiver->view);
free(pcsg_receiver);
}
View* pcsg_view_receiver_get_view(PCSGReceiver* pcsg_receiver) {
furi_assert(pcsg_receiver);
return pcsg_receiver->view;
}
uint16_t pcsg_view_receiver_get_idx_menu(PCSGReceiver* pcsg_receiver) {
furi_assert(pcsg_receiver);
uint32_t idx = 0;
with_view_model(
pcsg_receiver->view, PCSGReceiverModel * model, { idx = model->idx; }, false);
return idx;
}
void pcsg_view_receiver_set_idx_menu(PCSGReceiver* pcsg_receiver, uint16_t idx) {
furi_assert(pcsg_receiver);
with_view_model(
pcsg_receiver->view,
PCSGReceiverModel * model,
{
model->idx = idx;
if(model->idx > 2) model->list_offset = idx - 2;
},
true);
pcsg_view_receiver_update_offset(pcsg_receiver);
}

View File

@@ -1,43 +0,0 @@
#pragma once
#include <gui/view.h>
#include "../helpers/pocsag_pager_types.h"
#include "../helpers/pocsag_pager_event.h"
typedef struct PCSGReceiver PCSGReceiver;
typedef void (*PCSGReceiverCallback)(PCSGCustomEvent event, void* context);
void pcsg_receiver_rssi(PCSGReceiver* instance, float rssi);
void pcsg_view_receiver_set_lock(PCSGReceiver* pcsg_receiver, PCSGLock keyboard);
void pcsg_view_receiver_set_ext_module_state(PCSGReceiver* pcsg_receiver, bool is_external);
void pcsg_view_receiver_set_callback(
PCSGReceiver* pcsg_receiver,
PCSGReceiverCallback callback,
void* context);
PCSGReceiver* pcsg_view_receiver_alloc();
void pcsg_view_receiver_free(PCSGReceiver* pcsg_receiver);
View* pcsg_view_receiver_get_view(PCSGReceiver* pcsg_receiver);
void pcsg_view_receiver_add_data_statusbar(
PCSGReceiver* pcsg_receiver,
const char* frequency_str,
const char* preset_str,
const char* history_stat_str);
void pcsg_view_receiver_add_item_to_menu(
PCSGReceiver* pcsg_receiver,
const char* name,
uint8_t type);
uint16_t pcsg_view_receiver_get_idx_menu(PCSGReceiver* pcsg_receiver);
void pcsg_view_receiver_set_idx_menu(PCSGReceiver* pcsg_receiver, uint16_t idx);
void pcsg_view_receiver_exit(void* context);

View File

@@ -1,138 +0,0 @@
#include "pocsag_pager_receiver.h"
#include "../pocsag_pager_app_i.h"
#include "pocsag_pager_icons.h"
#include <assets_icons.h>
#include "../protocols/pcsg_generic.h"
#include <input/input.h>
#include <gui/elements.h>
#define abs(x) ((x) > 0 ? (x) : -(x))
struct PCSGReceiverInfo {
View* view;
};
typedef struct {
FuriString* protocol_name;
PCSGBlockGeneric* generic;
} PCSGReceiverInfoModel;
void pcsg_view_receiver_info_update(PCSGReceiverInfo* pcsg_receiver_info, FlipperFormat* fff) {
furi_assert(pcsg_receiver_info);
furi_assert(fff);
with_view_model(
pcsg_receiver_info->view,
PCSGReceiverInfoModel * model,
{
flipper_format_rewind(fff);
flipper_format_read_string(fff, "Protocol", model->protocol_name);
pcsg_block_generic_deserialize(model->generic, fff);
},
true);
}
void pcsg_view_receiver_info_draw(Canvas* canvas, PCSGReceiverInfoModel* model) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
if(model->generic->result_ric != NULL) {
elements_text_box(
canvas,
0,
0,
128,
64,
AlignLeft,
AlignTop,
furi_string_get_cstr(model->generic->result_ric),
false);
}
if(model->generic->result_msg != NULL) {
elements_text_box(
canvas,
0,
12,
128,
64,
AlignLeft,
AlignTop,
furi_string_get_cstr(model->generic->result_msg),
false);
}
}
bool pcsg_view_receiver_info_input(InputEvent* event, void* context) {
furi_assert(context);
//PCSGReceiverInfo* pcsg_receiver_info = context;
if(event->key == InputKeyBack) {
return false;
}
return true;
}
void pcsg_view_receiver_info_enter(void* context) {
furi_assert(context);
}
void pcsg_view_receiver_info_exit(void* context) {
furi_assert(context);
PCSGReceiverInfo* pcsg_receiver_info = context;
with_view_model(
pcsg_receiver_info->view,
PCSGReceiverInfoModel * model,
{ furi_string_reset(model->protocol_name); },
false);
}
PCSGReceiverInfo* pcsg_view_receiver_info_alloc() {
PCSGReceiverInfo* pcsg_receiver_info = malloc(sizeof(PCSGReceiverInfo));
// View allocation and configuration
pcsg_receiver_info->view = view_alloc();
view_allocate_model(
pcsg_receiver_info->view, ViewModelTypeLocking, sizeof(PCSGReceiverInfoModel));
view_set_context(pcsg_receiver_info->view, pcsg_receiver_info);
view_set_draw_callback(
pcsg_receiver_info->view, (ViewDrawCallback)pcsg_view_receiver_info_draw);
view_set_input_callback(pcsg_receiver_info->view, pcsg_view_receiver_info_input);
view_set_enter_callback(pcsg_receiver_info->view, pcsg_view_receiver_info_enter);
view_set_exit_callback(pcsg_receiver_info->view, pcsg_view_receiver_info_exit);
with_view_model(
pcsg_receiver_info->view,
PCSGReceiverInfoModel * model,
{
model->generic = malloc(sizeof(PCSGBlockGeneric));
model->protocol_name = furi_string_alloc();
},
true);
return pcsg_receiver_info;
}
void pcsg_view_receiver_info_free(PCSGReceiverInfo* pcsg_receiver_info) {
furi_assert(pcsg_receiver_info);
with_view_model(
pcsg_receiver_info->view,
PCSGReceiverInfoModel * model,
{
furi_string_free(model->protocol_name);
free(model->generic);
},
false);
view_free(pcsg_receiver_info->view);
free(pcsg_receiver_info);
}
View* pcsg_view_receiver_info_get_view(PCSGReceiverInfo* pcsg_receiver_info) {
furi_assert(pcsg_receiver_info);
return pcsg_receiver_info->view;
}

View File

@@ -1,16 +0,0 @@
#pragma once
#include <gui/view.h>
#include "../helpers/pocsag_pager_types.h"
#include "../helpers/pocsag_pager_event.h"
#include <lib/flipper_format/flipper_format.h>
typedef struct PCSGReceiverInfo PCSGReceiverInfo;
void pcsg_view_receiver_info_update(PCSGReceiverInfo* pcsg_receiver_info, FlipperFormat* fff);
PCSGReceiverInfo* pcsg_view_receiver_info_alloc();
void pcsg_view_receiver_info_free(PCSGReceiverInfo* pcsg_receiver_info);
View* pcsg_view_receiver_info_get_view(PCSGReceiverInfo* pcsg_receiver_info);

View File

@@ -1,14 +0,0 @@
App(
appid="weather_station",
name="Weather Station",
apptype=FlipperAppType.EXTERNAL,
targets=["f7"],
entry_point="weather_station_app",
requires=["gui"],
stack_size=4 * 1024,
fap_description="Receive weather data from a wide range of supported Sub-1GHz remote sensor",
fap_version="1.1",
fap_icon="weather_station_10px.png",
fap_category="Sub-GHz",
fap_icon_assets="images",
)

View File

@@ -1,69 +0,0 @@
#include "radio_device_loader.h"
#include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
#include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h>
static void radio_device_loader_power_on() {
uint8_t attempts = 0;
while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
furi_hal_power_enable_otg();
//CC1101 power-up time
furi_delay_ms(10);
}
}
static void radio_device_loader_power_off() {
if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg();
}
bool radio_device_loader_is_connect_external(const char* name) {
bool is_connect = false;
bool is_otg_enabled = furi_hal_power_is_otg_enabled();
if(!is_otg_enabled) {
radio_device_loader_power_on();
}
const SubGhzDevice* device = subghz_devices_get_by_name(name);
if(device) {
is_connect = subghz_devices_is_connect(device);
}
if(!is_otg_enabled) {
radio_device_loader_power_off();
}
return is_connect;
}
const SubGhzDevice* radio_device_loader_set(
const SubGhzDevice* current_radio_device,
SubGhzRadioDeviceType radio_device_type) {
const SubGhzDevice* radio_device;
if(radio_device_type == SubGhzRadioDeviceTypeExternalCC1101 &&
radio_device_loader_is_connect_external(SUBGHZ_DEVICE_CC1101_EXT_NAME)) {
radio_device_loader_power_on();
radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_EXT_NAME);
subghz_devices_begin(radio_device);
} else if(current_radio_device == NULL) {
radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME);
} else {
radio_device_loader_end(current_radio_device);
radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME);
}
return radio_device;
}
bool radio_device_loader_is_external(const SubGhzDevice* radio_device) {
furi_assert(radio_device);
return (radio_device != subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME));
}
void radio_device_loader_end(const SubGhzDevice* radio_device) {
furi_assert(radio_device);
radio_device_loader_power_off();
if(radio_device != subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME)) {
subghz_devices_end(radio_device);
}
}

View File

@@ -1,17 +0,0 @@
#pragma once
#include <lib/subghz/devices/devices.h>
/** SubGhzRadioDeviceType */
typedef enum {
SubGhzRadioDeviceTypeInternal,
SubGhzRadioDeviceTypeExternalCC1101,
} SubGhzRadioDeviceType;
const SubGhzDevice* radio_device_loader_set(
const SubGhzDevice* current_radio_device,
SubGhzRadioDeviceType radio_device_type);
bool radio_device_loader_is_external(const SubGhzDevice* radio_device);
void radio_device_loader_end(const SubGhzDevice* radio_device);

View File

@@ -1,14 +0,0 @@
#pragma once
typedef enum {
//WSCustomEvent
WSCustomEventStartId = 100,
WSCustomEventSceneSettingLock,
WSCustomEventViewReceiverOK,
WSCustomEventViewReceiverConfig,
WSCustomEventViewReceiverBack,
WSCustomEventViewReceiverOffDisplay,
WSCustomEventViewReceiverUnlock,
} WSCustomEvent;

View File

@@ -1,49 +0,0 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#define WS_VERSION_APP "1.1"
#define WS_DEVELOPED "SkorP"
#define WS_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
#define WS_KEY_FILE_VERSION 1
#define WS_KEY_FILE_TYPE "Flipper Weather Station Key File"
/** WSRxKeyState state */
typedef enum {
WSRxKeyStateIDLE,
WSRxKeyStateBack,
WSRxKeyStateStart,
WSRxKeyStateAddKey,
} WSRxKeyState;
/** WSHopperState state */
typedef enum {
WSHopperStateOFF,
WSHopperStateRunnig,
WSHopperStatePause,
WSHopperStateRSSITimeOut,
} WSHopperState;
/** WSLock */
typedef enum {
WSLockOff,
WSLockOn,
} WSLock;
typedef enum {
WeatherStationViewVariableItemList,
WeatherStationViewSubmenu,
WeatherStationViewReceiver,
WeatherStationViewReceiverInfo,
WeatherStationViewWidget,
} WeatherStationView;
/** WeatherStationTxRx state */
typedef enum {
WSTxRxStateIDLE,
WSTxRxStateRx,
WSTxRxStateTx,
WSTxRxStateSleep,
} WSTxRxState;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -1,26 +0,0 @@
#include "protocol_items.h"
const SubGhzProtocol* weather_station_protocol_registry_items[] = {
&ws_protocol_infactory,
&ws_protocol_thermopro_tx4,
&ws_protocol_nexus_th,
&ws_protocol_gt_wt_02,
&ws_protocol_gt_wt_03,
&ws_protocol_acurite_606tx,
&ws_protocol_acurite_609txc,
&ws_protocol_lacrosse_tx,
&ws_protocol_lacrosse_tx141thbv2,
&ws_protocol_oregon2,
&ws_protocol_oregon3,
&ws_protocol_acurite_592txr,
&ws_protocol_ambient_weather,
&ws_protocol_auriol_th,
&ws_protocol_oregon_v1,
&ws_protocol_tx_8300,
&ws_protocol_wendox_w6726,
&ws_protocol_auriol_ahfl,
};
const SubGhzProtocolRegistry weather_station_protocol_registry = {
.items = weather_station_protocol_registry_items,
.size = COUNT_OF(weather_station_protocol_registry_items)};

View File

@@ -1,23 +0,0 @@
#pragma once
#include "../weather_station_app_i.h"
#include "infactory.h"
#include "thermopro_tx4.h"
#include "nexus_th.h"
#include "gt_wt_02.h"
#include "gt_wt_03.h"
#include "acurite_606tx.h"
#include "acurite_609txc.h"
#include "lacrosse_tx.h"
#include "lacrosse_tx141thbv2.h"
#include "oregon2.h"
#include "oregon3.h"
#include "acurite_592txr.h"
#include "ambient_weather.h"
#include "auriol_hg0601a.h"
#include "oregon_v1.h"
#include "tx_8300.h"
#include "wendox_w6726.h"
#include "auriol_ahfl.h"
extern const SubGhzProtocolRegistry weather_station_protocol_registry;

View File

@@ -1,216 +0,0 @@
#include "../weather_station_app_i.h"
#include "../views/weather_station_receiver.h"
static const NotificationSequence subghs_sequence_rx = {
&message_green_255,
&message_vibro_on,
&message_note_c6,
&message_delay_50,
&message_sound_off,
&message_vibro_off,
&message_delay_50,
NULL,
};
static const NotificationSequence subghs_sequence_rx_locked = {
&message_green_255,
&message_display_backlight_on,
&message_vibro_on,
&message_note_c6,
&message_delay_50,
&message_sound_off,
&message_vibro_off,
&message_delay_500,
&message_display_backlight_off,
NULL,
};
static void weather_station_scene_receiver_update_statusbar(void* context) {
WeatherStationApp* app = context;
FuriString* history_stat_str;
history_stat_str = furi_string_alloc();
if(!ws_history_get_text_space_left(app->txrx->history, history_stat_str)) {
FuriString* frequency_str;
FuriString* modulation_str;
frequency_str = furi_string_alloc();
modulation_str = furi_string_alloc();
ws_get_frequency_modulation(app, frequency_str, modulation_str);
ws_view_receiver_add_data_statusbar(
app->ws_receiver,
furi_string_get_cstr(frequency_str),
furi_string_get_cstr(modulation_str),
furi_string_get_cstr(history_stat_str),
radio_device_loader_is_external(app->txrx->radio_device));
furi_string_free(frequency_str);
furi_string_free(modulation_str);
} else {
ws_view_receiver_add_data_statusbar(
app->ws_receiver,
furi_string_get_cstr(history_stat_str),
"",
"",
radio_device_loader_is_external(app->txrx->radio_device));
}
furi_string_free(history_stat_str);
}
void weather_station_scene_receiver_callback(WSCustomEvent event, void* context) {
furi_assert(context);
WeatherStationApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
static void weather_station_scene_receiver_add_to_history_callback(
SubGhzReceiver* receiver,
SubGhzProtocolDecoderBase* decoder_base,
void* context) {
furi_assert(context);
WeatherStationApp* app = context;
FuriString* str_buff;
str_buff = furi_string_alloc();
if(ws_history_add_to_history(app->txrx->history, decoder_base, app->txrx->preset) ==
WSHistoryStateAddKeyNewDada) {
furi_string_reset(str_buff);
ws_history_get_text_item_menu(
app->txrx->history, str_buff, ws_history_get_item(app->txrx->history) - 1);
ws_view_receiver_add_item_to_menu(
app->ws_receiver,
furi_string_get_cstr(str_buff),
ws_history_get_type_protocol(
app->txrx->history, ws_history_get_item(app->txrx->history) - 1));
weather_station_scene_receiver_update_statusbar(app);
notification_message(app->notifications, &sequence_blink_green_10);
if(app->lock != WSLockOn) {
notification_message(app->notifications, &subghs_sequence_rx);
} else {
notification_message(app->notifications, &subghs_sequence_rx_locked);
}
}
subghz_receiver_reset(receiver);
furi_string_free(str_buff);
app->txrx->rx_key_state = WSRxKeyStateAddKey;
}
void weather_station_scene_receiver_on_enter(void* context) {
WeatherStationApp* app = context;
FuriString* str_buff;
str_buff = furi_string_alloc();
if(app->txrx->rx_key_state == WSRxKeyStateIDLE) {
ws_preset_init(app, "AM650", subghz_setting_get_default_frequency(app->setting), NULL, 0);
ws_history_reset(app->txrx->history);
app->txrx->rx_key_state = WSRxKeyStateStart;
}
ws_view_receiver_set_lock(app->ws_receiver, app->lock);
//Load history to receiver
ws_view_receiver_exit(app->ws_receiver);
for(uint8_t i = 0; i < ws_history_get_item(app->txrx->history); i++) {
furi_string_reset(str_buff);
ws_history_get_text_item_menu(app->txrx->history, str_buff, i);
ws_view_receiver_add_item_to_menu(
app->ws_receiver,
furi_string_get_cstr(str_buff),
ws_history_get_type_protocol(app->txrx->history, i));
app->txrx->rx_key_state = WSRxKeyStateAddKey;
}
furi_string_free(str_buff);
weather_station_scene_receiver_update_statusbar(app);
ws_view_receiver_set_callback(app->ws_receiver, weather_station_scene_receiver_callback, app);
subghz_receiver_set_rx_callback(
app->txrx->receiver, weather_station_scene_receiver_add_to_history_callback, app);
if(app->txrx->txrx_state == WSTxRxStateRx) {
ws_rx_end(app);
};
if((app->txrx->txrx_state == WSTxRxStateIDLE) || (app->txrx->txrx_state == WSTxRxStateSleep)) {
ws_begin(
app,
subghz_setting_get_preset_data_by_name(
app->setting, furi_string_get_cstr(app->txrx->preset->name)));
ws_rx(app, app->txrx->preset->frequency);
}
ws_view_receiver_set_idx_menu(app->ws_receiver, app->txrx->idx_menu_chosen);
view_dispatcher_switch_to_view(app->view_dispatcher, WeatherStationViewReceiver);
}
bool weather_station_scene_receiver_on_event(void* context, SceneManagerEvent event) {
WeatherStationApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case WSCustomEventViewReceiverBack:
// Stop CC1101 Rx
if(app->txrx->txrx_state == WSTxRxStateRx) {
ws_rx_end(app);
ws_sleep(app);
};
app->txrx->hopper_state = WSHopperStateOFF;
app->txrx->idx_menu_chosen = 0;
subghz_receiver_set_rx_callback(app->txrx->receiver, NULL, app);
app->txrx->rx_key_state = WSRxKeyStateIDLE;
ws_preset_init(
app, "AM650", subghz_setting_get_default_frequency(app->setting), NULL, 0);
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, WeatherStationSceneStart);
consumed = true;
break;
case WSCustomEventViewReceiverOK:
app->txrx->idx_menu_chosen = ws_view_receiver_get_idx_menu(app->ws_receiver);
scene_manager_next_scene(app->scene_manager, WeatherStationSceneReceiverInfo);
consumed = true;
break;
case WSCustomEventViewReceiverConfig:
app->txrx->idx_menu_chosen = ws_view_receiver_get_idx_menu(app->ws_receiver);
scene_manager_next_scene(app->scene_manager, WeatherStationSceneReceiverConfig);
consumed = true;
break;
case WSCustomEventViewReceiverOffDisplay:
notification_message(app->notifications, &sequence_display_backlight_off);
consumed = true;
break;
case WSCustomEventViewReceiverUnlock:
app->lock = WSLockOff;
consumed = true;
break;
default:
break;
}
} else if(event.type == SceneManagerEventTypeTick) {
if(app->txrx->hopper_state != WSHopperStateOFF) {
ws_hopper_update(app);
weather_station_scene_receiver_update_statusbar(app);
}
// Get current RSSI
float rssi = subghz_devices_get_rssi(app->txrx->radio_device);
ws_view_receiver_set_rssi(app->ws_receiver, rssi);
if(app->txrx->txrx_state == WSTxRxStateRx) {
notification_message(app->notifications, &sequence_blink_cyan_10);
}
}
return consumed;
}
void weather_station_scene_receiver_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -1,30 +0,0 @@
#include "../weather_station_app_i.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const weather_station_scene_on_enter_handlers[])(void*) = {
#include "weather_station_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_event handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
bool (*const weather_station_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "weather_station_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_exit handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
void (*const weather_station_scene_on_exit_handlers[])(void* context) = {
#include "weather_station_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers weather_station_scene_handlers = {
.on_enter_handlers = weather_station_scene_on_enter_handlers,
.on_event_handlers = weather_station_scene_on_event_handlers,
.on_exit_handlers = weather_station_scene_on_exit_handlers,
.scene_num = WeatherStationSceneNum,
};

View File

@@ -1,29 +0,0 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) WeatherStationScene##id,
typedef enum {
#include "weather_station_scene_config.h"
WeatherStationSceneNum,
} WeatherStationScene;
#undef ADD_SCENE
extern const SceneManagerHandlers weather_station_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "weather_station_scene_config.h"
#undef ADD_SCENE
// Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
#include "weather_station_scene_config.h"
#undef ADD_SCENE
// Generate scene on_exit handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
#include "weather_station_scene_config.h"
#undef ADD_SCENE

View File

@@ -1,78 +0,0 @@
#include "../weather_station_app_i.h"
#include "../helpers/weather_station_types.h"
void weather_station_scene_about_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
WeatherStationApp* app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
}
void weather_station_scene_about_on_enter(void* context) {
WeatherStationApp* app = context;
FuriString* temp_str;
temp_str = furi_string_alloc();
furi_string_printf(temp_str, "\e#%s\n", "Information");
furi_string_cat_printf(temp_str, "Version: %s\n", WS_VERSION_APP);
furi_string_cat_printf(temp_str, "Developed by: %s\n", WS_DEVELOPED);
furi_string_cat_printf(temp_str, "Github: %s\n\n", WS_GITHUB);
furi_string_cat_printf(temp_str, "\e#%s\n", "Description");
furi_string_cat_printf(
temp_str, "Reading messages from\nweather stations that work\nwith SubGhz sensors\n\n");
furi_string_cat_printf(temp_str, "Supported protocols:\n");
size_t i = 0;
const char* protocol_name =
subghz_environment_get_protocol_name_registry(app->txrx->environment, i++);
do {
furi_string_cat_printf(temp_str, "%s\n", protocol_name);
protocol_name = subghz_environment_get_protocol_name_registry(app->txrx->environment, i++);
} while(protocol_name != NULL);
widget_add_text_box_element(
app->widget,
0,
0,
128,
14,
AlignCenter,
AlignBottom,
"\e#\e! \e!\n",
false);
widget_add_text_box_element(
app->widget,
0,
2,
128,
14,
AlignCenter,
AlignBottom,
"\e#\e! Weather station \e!\n",
false);
widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str));
furi_string_free(temp_str);
view_dispatcher_switch_to_view(app->view_dispatcher, WeatherStationViewWidget);
}
bool weather_station_scene_about_on_event(void* context, SceneManagerEvent event) {
WeatherStationApp* app = context;
bool consumed = false;
UNUSED(app);
UNUSED(event);
return consumed;
}
void weather_station_scene_about_on_exit(void* context) {
WeatherStationApp* app = context;
// Clear views
widget_reset(app->widget);
}

View File

@@ -1,5 +0,0 @@
ADD_SCENE(weather_station, start, Start)
ADD_SCENE(weather_station, about, About)
ADD_SCENE(weather_station, receiver, Receiver)
ADD_SCENE(weather_station, receiver_config, ReceiverConfig)
ADD_SCENE(weather_station, receiver_info, ReceiverInfo)

View File

@@ -1,223 +0,0 @@
#include "../weather_station_app_i.h"
enum WSSettingIndex {
WSSettingIndexFrequency,
WSSettingIndexHopping,
WSSettingIndexModulation,
WSSettingIndexLock,
};
#define HOPPING_COUNT 2
const char* const hopping_text[HOPPING_COUNT] = {
"OFF",
"ON",
};
const uint32_t hopping_value[HOPPING_COUNT] = {
WSHopperStateOFF,
WSHopperStateRunnig,
};
uint8_t weather_station_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
furi_assert(context);
WeatherStationApp* app = context;
uint8_t index = 0;
for(uint8_t i = 0; i < subghz_setting_get_frequency_count(app->setting); i++) {
if(value == subghz_setting_get_frequency(app->setting, i)) {
index = i;
break;
} else {
index = subghz_setting_get_frequency_default_index(app->setting);
}
}
return index;
}
uint8_t weather_station_scene_receiver_config_next_preset(const char* preset_name, void* context) {
furi_assert(context);
WeatherStationApp* app = context;
uint8_t index = 0;
for(uint8_t i = 0; i < subghz_setting_get_preset_count(app->setting); i++) {
if(!strcmp(subghz_setting_get_preset_name(app->setting, i), preset_name)) {
index = i;
break;
} else {
// index = subghz_setting_get_frequency_default_index(app ->setting);
}
}
return index;
}
uint8_t weather_station_scene_receiver_config_hopper_value_index(
const uint32_t value,
const uint32_t values[],
uint8_t values_count,
void* context) {
furi_assert(context);
UNUSED(values_count);
WeatherStationApp* app = context;
if(value == values[0]) {
return 0;
} else {
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
app->scene_manager, WeatherStationSceneReceiverConfig),
" -----");
return 1;
}
}
static void weather_station_scene_receiver_config_set_frequency(VariableItem* item) {
WeatherStationApp* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
if(app->txrx->hopper_state == WSHopperStateOFF) {
char text_buf[10] = {0};
snprintf(
text_buf,
sizeof(text_buf),
"%lu.%02lu",
subghz_setting_get_frequency(app->setting, index) / 1000000,
(subghz_setting_get_frequency(app->setting, index) % 1000000) / 10000);
variable_item_set_current_value_text(item, text_buf);
app->txrx->preset->frequency = subghz_setting_get_frequency(app->setting, index);
} else {
variable_item_set_current_value_index(
item, subghz_setting_get_frequency_default_index(app->setting));
}
}
static void weather_station_scene_receiver_config_set_preset(VariableItem* item) {
WeatherStationApp* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(
item, subghz_setting_get_preset_name(app->setting, index));
ws_preset_init(
app,
subghz_setting_get_preset_name(app->setting, index),
app->txrx->preset->frequency,
subghz_setting_get_preset_data(app->setting, index),
subghz_setting_get_preset_data_size(app->setting, index));
}
static void weather_station_scene_receiver_config_set_hopping_running(VariableItem* item) {
WeatherStationApp* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, hopping_text[index]);
if(hopping_value[index] == WSHopperStateOFF) {
char text_buf[10] = {0};
snprintf(
text_buf,
sizeof(text_buf),
"%lu.%02lu",
subghz_setting_get_default_frequency(app->setting) / 1000000,
(subghz_setting_get_default_frequency(app->setting) % 1000000) / 10000);
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
app->scene_manager, WeatherStationSceneReceiverConfig),
text_buf);
app->txrx->preset->frequency = subghz_setting_get_default_frequency(app->setting);
variable_item_set_current_value_index(
(VariableItem*)scene_manager_get_scene_state(
app->scene_manager, WeatherStationSceneReceiverConfig),
subghz_setting_get_frequency_default_index(app->setting));
} else {
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
app->scene_manager, WeatherStationSceneReceiverConfig),
" -----");
variable_item_set_current_value_index(
(VariableItem*)scene_manager_get_scene_state(
app->scene_manager, WeatherStationSceneReceiverConfig),
subghz_setting_get_frequency_default_index(app->setting));
}
app->txrx->hopper_state = hopping_value[index];
}
static void
weather_station_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) {
furi_assert(context);
WeatherStationApp* app = context;
if(index == WSSettingIndexLock) {
view_dispatcher_send_custom_event(app->view_dispatcher, WSCustomEventSceneSettingLock);
}
}
void weather_station_scene_receiver_config_on_enter(void* context) {
WeatherStationApp* app = context;
VariableItem* item;
uint8_t value_index;
item = variable_item_list_add(
app->variable_item_list,
"Frequency:",
subghz_setting_get_frequency_count(app->setting),
weather_station_scene_receiver_config_set_frequency,
app);
value_index =
weather_station_scene_receiver_config_next_frequency(app->txrx->preset->frequency, app);
scene_manager_set_scene_state(
app->scene_manager, WeatherStationSceneReceiverConfig, (uint32_t)item);
variable_item_set_current_value_index(item, value_index);
char text_buf[10] = {0};
snprintf(
text_buf,
sizeof(text_buf),
"%lu.%02lu",
subghz_setting_get_frequency(app->setting, value_index) / 1000000,
(subghz_setting_get_frequency(app->setting, value_index) % 1000000) / 10000);
variable_item_set_current_value_text(item, text_buf);
item = variable_item_list_add(
app->variable_item_list,
"Hopping:",
HOPPING_COUNT,
weather_station_scene_receiver_config_set_hopping_running,
app);
value_index = weather_station_scene_receiver_config_hopper_value_index(
app->txrx->hopper_state, hopping_value, HOPPING_COUNT, app);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, hopping_text[value_index]);
item = variable_item_list_add(
app->variable_item_list,
"Modulation:",
subghz_setting_get_preset_count(app->setting),
weather_station_scene_receiver_config_set_preset,
app);
value_index = weather_station_scene_receiver_config_next_preset(
furi_string_get_cstr(app->txrx->preset->name), app);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(
item, subghz_setting_get_preset_name(app->setting, value_index));
variable_item_list_add(app->variable_item_list, "Lock Keyboard", 1, NULL, NULL);
variable_item_list_set_enter_callback(
app->variable_item_list,
weather_station_scene_receiver_config_var_list_enter_callback,
app);
view_dispatcher_switch_to_view(app->view_dispatcher, WeatherStationViewVariableItemList);
}
bool weather_station_scene_receiver_config_on_event(void* context, SceneManagerEvent event) {
WeatherStationApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == WSCustomEventSceneSettingLock) {
app->lock = WSLockOn;
scene_manager_previous_scene(app->scene_manager);
consumed = true;
}
}
return consumed;
}
void weather_station_scene_receiver_config_on_exit(void* context) {
WeatherStationApp* app = context;
variable_item_list_set_selected_item(app->variable_item_list, 0);
variable_item_list_reset(app->variable_item_list);
}

View File

@@ -1,50 +0,0 @@
#include "../weather_station_app_i.h"
#include "../views/weather_station_receiver.h"
void weather_station_scene_receiver_info_callback(WSCustomEvent event, void* context) {
furi_assert(context);
WeatherStationApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
static void weather_station_scene_receiver_info_add_to_history_callback(
SubGhzReceiver* receiver,
SubGhzProtocolDecoderBase* decoder_base,
void* context) {
furi_assert(context);
WeatherStationApp* app = context;
if(ws_history_add_to_history(app->txrx->history, decoder_base, app->txrx->preset) ==
WSHistoryStateAddKeyUpdateData) {
ws_view_receiver_info_update(
app->ws_receiver_info,
ws_history_get_raw_data(app->txrx->history, app->txrx->idx_menu_chosen));
subghz_receiver_reset(receiver);
notification_message(app->notifications, &sequence_blink_green_10);
app->txrx->rx_key_state = WSRxKeyStateAddKey;
}
}
void weather_station_scene_receiver_info_on_enter(void* context) {
WeatherStationApp* app = context;
subghz_receiver_set_rx_callback(
app->txrx->receiver, weather_station_scene_receiver_info_add_to_history_callback, app);
ws_view_receiver_info_update(
app->ws_receiver_info,
ws_history_get_raw_data(app->txrx->history, app->txrx->idx_menu_chosen));
view_dispatcher_switch_to_view(app->view_dispatcher, WeatherStationViewReceiverInfo);
}
bool weather_station_scene_receiver_info_on_event(void* context, SceneManagerEvent event) {
WeatherStationApp* app = context;
bool consumed = false;
UNUSED(app);
UNUSED(event);
return consumed;
}
void weather_station_scene_receiver_info_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -1,58 +0,0 @@
#include "../weather_station_app_i.h"
typedef enum {
SubmenuIndexWeatherStationReceiver,
SubmenuIndexWeatherStationAbout,
} SubmenuIndex;
void weather_station_scene_start_submenu_callback(void* context, uint32_t index) {
WeatherStationApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void weather_station_scene_start_on_enter(void* context) {
UNUSED(context);
WeatherStationApp* app = context;
Submenu* submenu = app->submenu;
submenu_add_item(
submenu,
"Read Weather Station",
SubmenuIndexWeatherStationReceiver,
weather_station_scene_start_submenu_callback,
app);
submenu_add_item(
submenu,
"About",
SubmenuIndexWeatherStationAbout,
weather_station_scene_start_submenu_callback,
app);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(app->scene_manager, WeatherStationSceneStart));
view_dispatcher_switch_to_view(app->view_dispatcher, WeatherStationViewSubmenu);
}
bool weather_station_scene_start_on_event(void* context, SceneManagerEvent event) {
WeatherStationApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexWeatherStationAbout) {
scene_manager_next_scene(app->scene_manager, WeatherStationSceneAbout);
consumed = true;
} else if(event.event == SubmenuIndexWeatherStationReceiver) {
scene_manager_next_scene(app->scene_manager, WeatherStationSceneReceiver);
consumed = true;
}
scene_manager_set_scene_state(app->scene_manager, WeatherStationSceneStart, event.event);
}
return consumed;
}
void weather_station_scene_start_on_exit(void* context) {
WeatherStationApp* app = context;
submenu_reset(app->submenu);
}

View File

@@ -1,473 +0,0 @@
#include "weather_station_receiver.h"
#include "../weather_station_app_i.h"
#include "weather_station_icons.h"
#include <assets_icons.h>
#include <math.h>
#include <input/input.h>
#include <gui/elements.h>
#include <m-array.h>
#define FRAME_HEIGHT 12
#define MAX_LEN_PX 112
#define MENU_ITEMS 4u
#define UNLOCK_CNT 3
#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
typedef struct {
FuriString* item_str;
uint8_t type;
} WSReceiverMenuItem;
ARRAY_DEF(WSReceiverMenuItemArray, WSReceiverMenuItem, M_POD_OPLIST)
#define M_OPL_WSReceiverMenuItemArray_t() ARRAY_OPLIST(WSReceiverMenuItemArray, M_POD_OPLIST)
struct WSReceiverHistory {
WSReceiverMenuItemArray_t data;
};
typedef struct WSReceiverHistory WSReceiverHistory;
static const Icon* ReceiverItemIcons[] = {
[SubGhzProtocolTypeUnknown] = &I_Quest_7x8,
[SubGhzProtocolTypeStatic] = &I_Unlock_7x8,
[SubGhzProtocolTypeDynamic] = &I_Lock_7x8,
[SubGhzProtocolWeatherStation] = &I_station_icon,
};
typedef enum {
WSReceiverBarShowDefault,
WSReceiverBarShowLock,
WSReceiverBarShowToUnlockPress,
WSReceiverBarShowUnlock,
} WSReceiverBarShow;
struct WSReceiver {
WSLock lock;
uint8_t lock_count;
FuriTimer* timer;
View* view;
WSReceiverCallback callback;
void* context;
};
typedef struct {
FuriString* frequency_str;
FuriString* preset_str;
FuriString* history_stat_str;
WSReceiverHistory* history;
uint16_t idx;
uint16_t list_offset;
uint16_t history_item;
WSReceiverBarShow bar_show;
uint8_t u_rssi;
bool external_redio;
} WSReceiverModel;
void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi) {
furi_assert(instance);
with_view_model(
instance->view,
WSReceiverModel * model,
{
if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) {
model->u_rssi = 0;
} else {
model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN);
}
},
true);
}
void ws_view_receiver_set_lock(WSReceiver* ws_receiver, WSLock lock) {
furi_assert(ws_receiver);
ws_receiver->lock_count = 0;
if(lock == WSLockOn) {
ws_receiver->lock = lock;
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{ model->bar_show = WSReceiverBarShowLock; },
true);
furi_timer_start(ws_receiver->timer, pdMS_TO_TICKS(1000));
} else {
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{ model->bar_show = WSReceiverBarShowDefault; },
true);
}
}
void ws_view_receiver_set_callback(
WSReceiver* ws_receiver,
WSReceiverCallback callback,
void* context) {
furi_assert(ws_receiver);
furi_assert(callback);
ws_receiver->callback = callback;
ws_receiver->context = context;
}
static void ws_view_receiver_update_offset(WSReceiver* ws_receiver) {
furi_assert(ws_receiver);
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{
size_t history_item = model->history_item;
uint16_t bounds = history_item > 3 ? 2 : history_item;
if(history_item > 3 && model->idx >= (int16_t)(history_item - 1)) {
model->list_offset = model->idx - 3;
} else if(model->list_offset < model->idx - bounds) {
model->list_offset =
CLAMP(model->list_offset + 1, (int16_t)(history_item - bounds), 0);
} else if(model->list_offset > model->idx - bounds) {
model->list_offset = CLAMP(model->idx - 1, (int16_t)(history_item - bounds), 0);
}
},
true);
}
void ws_view_receiver_add_item_to_menu(WSReceiver* ws_receiver, const char* name, uint8_t type) {
furi_assert(ws_receiver);
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{
WSReceiverMenuItem* item_menu = WSReceiverMenuItemArray_push_raw(model->history->data);
item_menu->item_str = furi_string_alloc_set(name);
item_menu->type = type;
if((model->idx == model->history_item - 1)) {
model->history_item++;
model->idx++;
} else {
model->history_item++;
}
},
true);
ws_view_receiver_update_offset(ws_receiver);
}
void ws_view_receiver_add_data_statusbar(
WSReceiver* ws_receiver,
const char* frequency_str,
const char* preset_str,
const char* history_stat_str,
bool external) {
furi_assert(ws_receiver);
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{
furi_string_set_str(model->frequency_str, frequency_str);
furi_string_set_str(model->preset_str, preset_str);
furi_string_set_str(model->history_stat_str, history_stat_str);
model->external_redio = external;
},
true);
}
static void ws_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) {
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT);
canvas_set_color(canvas, ColorWhite);
canvas_draw_dot(canvas, 0, 0 + idx * FRAME_HEIGHT);
canvas_draw_dot(canvas, 1, 0 + idx * FRAME_HEIGHT);
canvas_draw_dot(canvas, 0, (0 + idx * FRAME_HEIGHT) + 1);
canvas_draw_dot(canvas, 0, (0 + idx * FRAME_HEIGHT) + 11);
canvas_draw_dot(canvas, scrollbar ? 121 : 126, 0 + idx * FRAME_HEIGHT);
canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11);
}
static void ws_view_rssi_draw(Canvas* canvas, WSReceiverModel* model) {
for(uint8_t i = 1; i < model->u_rssi; i++) {
if(i % 5) {
canvas_draw_dot(canvas, 46 + i, 50);
canvas_draw_dot(canvas, 47 + i, 51);
canvas_draw_dot(canvas, 46 + i, 52);
}
}
}
void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
elements_button_left(canvas, "Config");
bool scrollbar = model->history_item > 4;
FuriString* str_buff;
str_buff = furi_string_alloc();
// bool ext_module = furi_hal_subghz_get_radio_type();
WSReceiverMenuItem* item_menu;
for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) {
size_t idx = CLAMP((uint16_t)(i + model->list_offset), model->history_item, 0);
item_menu = WSReceiverMenuItemArray_get(model->history->data, idx);
furi_string_set(str_buff, item_menu->item_str);
elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX);
if(model->idx == idx) {
ws_view_receiver_draw_frame(canvas, i, scrollbar);
} else {
canvas_set_color(canvas, ColorBlack);
}
canvas_draw_icon(canvas, 4, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]);
canvas_draw_str(canvas, 14, 9 + i * FRAME_HEIGHT, furi_string_get_cstr(str_buff));
furi_string_reset(str_buff);
}
if(scrollbar) {
elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item);
}
furi_string_free(str_buff);
canvas_set_color(canvas, ColorBlack);
if(model->history_item == 0) {
canvas_draw_icon(
canvas, 0, 0, model->external_redio ? &I_Fishing_123x52 : &I_Scanning_123x52);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 63, 46, "Scanning...");
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 44, 10, model->external_redio ? "Ext" : "Int");
}
// Draw RSSI
ws_view_rssi_draw(canvas, model);
switch(model->bar_show) {
case WSReceiverBarShowLock:
canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8);
canvas_draw_str(canvas, 74, 62, "Locked");
break;
case WSReceiverBarShowToUnlockPress:
canvas_draw_str(canvas, 44, 62, furi_string_get_cstr(model->frequency_str));
canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str));
canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str));
canvas_set_font(canvas, FontSecondary);
elements_bold_rounded_frame(canvas, 14, 8, 99, 48);
elements_multiline_text(canvas, 65, 26, "To unlock\npress:");
canvas_draw_icon(canvas, 65, 42, &I_Pin_back_arrow_10x8);
canvas_draw_icon(canvas, 80, 42, &I_Pin_back_arrow_10x8);
canvas_draw_icon(canvas, 95, 42, &I_Pin_back_arrow_10x8);
canvas_draw_icon(canvas, 16, 13, &I_WarningDolphin_45x42);
canvas_draw_dot(canvas, 17, 61);
break;
case WSReceiverBarShowUnlock:
canvas_draw_icon(canvas, 64, 55, &I_Unlock_7x8);
canvas_draw_str(canvas, 74, 62, "Unlocked");
break;
default:
canvas_draw_str(canvas, 44, 62, furi_string_get_cstr(model->frequency_str));
canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str));
canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str));
break;
}
}
static void ws_view_receiver_timer_callback(void* context) {
furi_assert(context);
WSReceiver* ws_receiver = context;
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{ model->bar_show = WSReceiverBarShowDefault; },
true);
if(ws_receiver->lock_count < UNLOCK_CNT) {
ws_receiver->callback(WSCustomEventViewReceiverOffDisplay, ws_receiver->context);
} else {
ws_receiver->lock = WSLockOff;
ws_receiver->callback(WSCustomEventViewReceiverUnlock, ws_receiver->context);
}
ws_receiver->lock_count = 0;
}
bool ws_view_receiver_input(InputEvent* event, void* context) {
furi_assert(context);
WSReceiver* ws_receiver = context;
if(ws_receiver->lock == WSLockOn) {
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{ model->bar_show = WSReceiverBarShowToUnlockPress; },
true);
if(ws_receiver->lock_count == 0) {
furi_timer_start(ws_receiver->timer, pdMS_TO_TICKS(1000));
}
if(event->key == InputKeyBack && event->type == InputTypeShort) {
ws_receiver->lock_count++;
}
if(ws_receiver->lock_count >= UNLOCK_CNT) {
ws_receiver->callback(WSCustomEventViewReceiverUnlock, ws_receiver->context);
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{ model->bar_show = WSReceiverBarShowUnlock; },
true);
ws_receiver->lock = WSLockOff;
furi_timer_start(ws_receiver->timer, pdMS_TO_TICKS(650));
}
return true;
}
if(event->key == InputKeyBack && event->type == InputTypeShort) {
ws_receiver->callback(WSCustomEventViewReceiverBack, ws_receiver->context);
} else if(
event->key == InputKeyUp &&
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{
if(model->idx != 0) model->idx--;
},
true);
} else if(
event->key == InputKeyDown &&
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{
if(model->history_item && model->idx != model->history_item - 1) model->idx++;
},
true);
} else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
ws_receiver->callback(WSCustomEventViewReceiverConfig, ws_receiver->context);
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{
if(model->history_item != 0) {
ws_receiver->callback(WSCustomEventViewReceiverOK, ws_receiver->context);
}
},
false);
}
ws_view_receiver_update_offset(ws_receiver);
return true;
}
void ws_view_receiver_enter(void* context) {
furi_assert(context);
}
void ws_view_receiver_exit(void* context) {
furi_assert(context);
WSReceiver* ws_receiver = context;
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{
furi_string_reset(model->frequency_str);
furi_string_reset(model->preset_str);
furi_string_reset(model->history_stat_str);
for
M_EACH(item_menu, model->history->data, WSReceiverMenuItemArray_t) {
furi_string_free(item_menu->item_str);
item_menu->type = 0;
}
WSReceiverMenuItemArray_reset(model->history->data);
model->idx = 0;
model->list_offset = 0;
model->history_item = 0;
},
false);
furi_timer_stop(ws_receiver->timer);
}
WSReceiver* ws_view_receiver_alloc() {
WSReceiver* ws_receiver = malloc(sizeof(WSReceiver));
// View allocation and configuration
ws_receiver->view = view_alloc();
ws_receiver->lock = WSLockOff;
ws_receiver->lock_count = 0;
view_allocate_model(ws_receiver->view, ViewModelTypeLocking, sizeof(WSReceiverModel));
view_set_context(ws_receiver->view, ws_receiver);
view_set_draw_callback(ws_receiver->view, (ViewDrawCallback)ws_view_receiver_draw);
view_set_input_callback(ws_receiver->view, ws_view_receiver_input);
view_set_enter_callback(ws_receiver->view, ws_view_receiver_enter);
view_set_exit_callback(ws_receiver->view, ws_view_receiver_exit);
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{
model->frequency_str = furi_string_alloc();
model->preset_str = furi_string_alloc();
model->history_stat_str = furi_string_alloc();
model->bar_show = WSReceiverBarShowDefault;
model->history = malloc(sizeof(WSReceiverHistory));
model->external_redio = false;
WSReceiverMenuItemArray_init(model->history->data);
},
true);
ws_receiver->timer =
furi_timer_alloc(ws_view_receiver_timer_callback, FuriTimerTypeOnce, ws_receiver);
return ws_receiver;
}
void ws_view_receiver_free(WSReceiver* ws_receiver) {
furi_assert(ws_receiver);
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{
furi_string_free(model->frequency_str);
furi_string_free(model->preset_str);
furi_string_free(model->history_stat_str);
for
M_EACH(item_menu, model->history->data, WSReceiverMenuItemArray_t) {
furi_string_free(item_menu->item_str);
item_menu->type = 0;
}
WSReceiverMenuItemArray_clear(model->history->data);
free(model->history);
},
false);
furi_timer_free(ws_receiver->timer);
view_free(ws_receiver->view);
free(ws_receiver);
}
View* ws_view_receiver_get_view(WSReceiver* ws_receiver) {
furi_assert(ws_receiver);
return ws_receiver->view;
}
uint16_t ws_view_receiver_get_idx_menu(WSReceiver* ws_receiver) {
furi_assert(ws_receiver);
uint32_t idx = 0;
with_view_model(
ws_receiver->view, WSReceiverModel * model, { idx = model->idx; }, false);
return idx;
}
void ws_view_receiver_set_idx_menu(WSReceiver* ws_receiver, uint16_t idx) {
furi_assert(ws_receiver);
with_view_model(
ws_receiver->view,
WSReceiverModel * model,
{
model->idx = idx;
if(model->idx > 2) model->list_offset = idx - 2;
},
true);
ws_view_receiver_update_offset(ws_receiver);
}

View File

@@ -1,39 +0,0 @@
#pragma once
#include <gui/view.h>
#include "../helpers/weather_station_types.h"
#include "../helpers/weather_station_event.h"
typedef struct WSReceiver WSReceiver;
typedef void (*WSReceiverCallback)(WSCustomEvent event, void* context);
void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi);
void ws_view_receiver_set_lock(WSReceiver* ws_receiver, WSLock keyboard);
void ws_view_receiver_set_callback(
WSReceiver* ws_receiver,
WSReceiverCallback callback,
void* context);
WSReceiver* ws_view_receiver_alloc();
void ws_view_receiver_free(WSReceiver* ws_receiver);
View* ws_view_receiver_get_view(WSReceiver* ws_receiver);
void ws_view_receiver_add_data_statusbar(
WSReceiver* ws_receiver,
const char* frequency_str,
const char* preset_str,
const char* history_stat_str,
bool external);
void ws_view_receiver_add_item_to_menu(WSReceiver* ws_receiver, const char* name, uint8_t type);
uint16_t ws_view_receiver_get_idx_menu(WSReceiver* ws_receiver);
void ws_view_receiver_set_idx_menu(WSReceiver* ws_receiver, uint16_t idx);
void ws_view_receiver_exit(void* context);

View File

@@ -1,246 +0,0 @@
#include "weather_station_receiver.h"
#include "../weather_station_app_i.h"
#include "weather_station_icons.h"
#include <assets_icons.h>
#include "../protocols/ws_generic.h"
#include <input/input.h>
#include <gui/elements.h>
#include <float_tools.h>
struct WSReceiverInfo {
View* view;
FuriTimer* timer;
};
typedef struct {
uint32_t curr_ts;
FuriString* protocol_name;
WSBlockGeneric* generic;
} WSReceiverInfoModel;
void ws_view_receiver_info_update(WSReceiverInfo* ws_receiver_info, FlipperFormat* fff) {
furi_assert(ws_receiver_info);
furi_assert(fff);
with_view_model(
ws_receiver_info->view,
WSReceiverInfoModel * model,
{
flipper_format_rewind(fff);
flipper_format_read_string(fff, "Protocol", model->protocol_name);
ws_block_generic_deserialize(model->generic, fff);
FuriHalRtcDateTime curr_dt;
furi_hal_rtc_get_datetime(&curr_dt);
model->curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
},
true);
}
void ws_view_receiver_info_draw(Canvas* canvas, WSReceiverInfoModel* model) {
char buffer[64];
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
snprintf(
buffer,
sizeof(buffer),
"%s %db",
furi_string_get_cstr(model->protocol_name),
model->generic->data_count_bit);
canvas_draw_str(canvas, 0, 8, buffer);
if(model->generic->channel != WS_NO_CHANNEL) {
snprintf(buffer, sizeof(buffer), "Ch: %01d", model->generic->channel);
canvas_draw_str(canvas, 106, 8, buffer);
}
if(model->generic->id != WS_NO_ID) {
snprintf(buffer, sizeof(buffer), "Sn: 0x%02lX", model->generic->id);
canvas_draw_str(canvas, 0, 20, buffer);
}
if(model->generic->btn != WS_NO_BTN) {
snprintf(buffer, sizeof(buffer), "Btn: %01d", model->generic->btn);
canvas_draw_str(canvas, 57, 20, buffer);
}
if(model->generic->battery_low != WS_NO_BATT) {
snprintf(
buffer, sizeof(buffer), "Batt: %s", (!model->generic->battery_low ? "ok" : "low"));
canvas_draw_str_aligned(canvas, 126, 17, AlignRight, AlignCenter, buffer);
}
snprintf(buffer, sizeof(buffer), "Data: 0x%llX", model->generic->data);
canvas_draw_str(canvas, 0, 32, buffer);
elements_bold_rounded_frame(canvas, 0, 38, 127, 25);
canvas_set_font(canvas, FontPrimary);
if(!float_is_equal(model->generic->temp, WS_NO_TEMPERATURE)) {
canvas_draw_icon(canvas, 6, 43, &I_Therm_7x16);
uint8_t temp_x1 = 0;
uint8_t temp_x2 = 0;
if(furi_hal_rtc_get_locale_units() == FuriHalRtcLocaleUnitsMetric) {
snprintf(buffer, sizeof(buffer), "%3.1f C", (double)model->generic->temp);
if(model->generic->temp < -9.0f) {
temp_x1 = 49;
temp_x2 = 40;
} else {
temp_x1 = 47;
temp_x2 = 38;
}
} else {
snprintf(
buffer,
sizeof(buffer),
"%3.1f F",
(double)locale_celsius_to_fahrenheit(model->generic->temp));
if((model->generic->temp < -27.77f) || (model->generic->temp > 37.77f)) {
temp_x1 = 50;
temp_x2 = 42;
} else {
temp_x1 = 48;
temp_x2 = 40;
}
}
canvas_draw_str_aligned(canvas, temp_x1, 47, AlignRight, AlignTop, buffer);
canvas_draw_circle(canvas, temp_x2, 46, 1);
}
if(model->generic->humidity != WS_NO_HUMIDITY) {
canvas_draw_icon(canvas, 53, 44, &I_Humid_8x13);
snprintf(buffer, sizeof(buffer), "%d%%", model->generic->humidity);
canvas_draw_str(canvas, 64, 55, buffer);
}
if((int)model->generic->timestamp > 0 && model->curr_ts) {
int ts_diff = (int)model->curr_ts - (int)model->generic->timestamp;
canvas_draw_icon(canvas, 91, 46, &I_Timer_11x11);
if(ts_diff > 60) {
int tmp_sec = ts_diff;
int cnt_min = 1;
for(int i = 1; tmp_sec > 60; i++) {
tmp_sec = tmp_sec - 60;
cnt_min = i;
}
if(model->curr_ts % 2 == 0) {
canvas_draw_str_aligned(canvas, 105, 51, AlignLeft, AlignCenter, "Old");
} else {
if(cnt_min >= 59) {
canvas_draw_str_aligned(canvas, 105, 51, AlignLeft, AlignCenter, "Old");
} else {
snprintf(buffer, sizeof(buffer), "%dm", cnt_min);
canvas_draw_str_aligned(canvas, 114, 51, AlignCenter, AlignCenter, buffer);
}
}
} else {
snprintf(buffer, sizeof(buffer), "%d", ts_diff);
canvas_draw_str_aligned(canvas, 112, 51, AlignCenter, AlignCenter, buffer);
}
}
}
bool ws_view_receiver_info_input(InputEvent* event, void* context) {
furi_assert(context);
//WSReceiverInfo* ws_receiver_info = context;
if(event->key == InputKeyBack) {
return false;
}
return true;
}
static void ws_view_receiver_info_enter(void* context) {
furi_assert(context);
WSReceiverInfo* ws_receiver_info = context;
furi_timer_start(ws_receiver_info->timer, 1000);
}
static void ws_view_receiver_info_exit(void* context) {
furi_assert(context);
WSReceiverInfo* ws_receiver_info = context;
furi_timer_stop(ws_receiver_info->timer);
with_view_model(
ws_receiver_info->view,
WSReceiverInfoModel * model,
{ furi_string_reset(model->protocol_name); },
false);
}
static void ws_view_receiver_info_timer(void* context) {
WSReceiverInfo* ws_receiver_info = context;
// Force redraw
with_view_model(
ws_receiver_info->view,
WSReceiverInfoModel * model,
{
FuriHalRtcDateTime curr_dt;
furi_hal_rtc_get_datetime(&curr_dt);
model->curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
},
true);
}
WSReceiverInfo* ws_view_receiver_info_alloc() {
WSReceiverInfo* ws_receiver_info = malloc(sizeof(WSReceiverInfo));
// View allocation and configuration
ws_receiver_info->view = view_alloc();
view_allocate_model(ws_receiver_info->view, ViewModelTypeLocking, sizeof(WSReceiverInfoModel));
view_set_context(ws_receiver_info->view, ws_receiver_info);
view_set_draw_callback(ws_receiver_info->view, (ViewDrawCallback)ws_view_receiver_info_draw);
view_set_input_callback(ws_receiver_info->view, ws_view_receiver_info_input);
view_set_enter_callback(ws_receiver_info->view, ws_view_receiver_info_enter);
view_set_exit_callback(ws_receiver_info->view, ws_view_receiver_info_exit);
with_view_model(
ws_receiver_info->view,
WSReceiverInfoModel * model,
{
model->generic = malloc(sizeof(WSBlockGeneric));
model->protocol_name = furi_string_alloc();
},
true);
ws_receiver_info->timer =
furi_timer_alloc(ws_view_receiver_info_timer, FuriTimerTypePeriodic, ws_receiver_info);
return ws_receiver_info;
}
void ws_view_receiver_info_free(WSReceiverInfo* ws_receiver_info) {
furi_assert(ws_receiver_info);
furi_timer_free(ws_receiver_info->timer);
with_view_model(
ws_receiver_info->view,
WSReceiverInfoModel * model,
{
furi_string_free(model->protocol_name);
free(model->generic);
},
false);
view_free(ws_receiver_info->view);
free(ws_receiver_info);
}
View* ws_view_receiver_info_get_view(WSReceiverInfo* ws_receiver_info) {
furi_assert(ws_receiver_info);
return ws_receiver_info->view;
}

View File

@@ -1,16 +0,0 @@
#pragma once
#include <gui/view.h>
#include "../helpers/weather_station_types.h"
#include "../helpers/weather_station_event.h"
#include <lib/flipper_format/flipper_format.h>
typedef struct WSReceiverInfo WSReceiverInfo;
void ws_view_receiver_info_update(WSReceiverInfo* ws_receiver_info, FlipperFormat* fff);
WSReceiverInfo* ws_view_receiver_info_alloc();
void ws_view_receiver_info_free(WSReceiverInfo* ws_receiver_info);
View* ws_view_receiver_info_get_view(WSReceiverInfo* ws_receiver_info);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 B

View File

@@ -1,188 +0,0 @@
#include "weather_station_app_i.h"
#include <furi.h>
#include <furi_hal.h>
#include "protocols/protocol_items.h"
static bool weather_station_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
WeatherStationApp* app = context;
return scene_manager_handle_custom_event(app->scene_manager, event);
}
static bool weather_station_app_back_event_callback(void* context) {
furi_assert(context);
WeatherStationApp* app = context;
return scene_manager_handle_back_event(app->scene_manager);
}
static void weather_station_app_tick_event_callback(void* context) {
furi_assert(context);
WeatherStationApp* app = context;
scene_manager_handle_tick_event(app->scene_manager);
}
WeatherStationApp* weather_station_app_alloc() {
WeatherStationApp* app = malloc(sizeof(WeatherStationApp));
// GUI
app->gui = furi_record_open(RECORD_GUI);
// View Dispatcher
app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&weather_station_scene_handlers, app);
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_custom_event_callback(
app->view_dispatcher, weather_station_app_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
app->view_dispatcher, weather_station_app_back_event_callback);
view_dispatcher_set_tick_event_callback(
app->view_dispatcher, weather_station_app_tick_event_callback, 100);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
// Open Notification record
app->notifications = furi_record_open(RECORD_NOTIFICATION);
// Variable Item List
app->variable_item_list = variable_item_list_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
WeatherStationViewVariableItemList,
variable_item_list_get_view(app->variable_item_list));
// SubMenu
app->submenu = submenu_alloc();
view_dispatcher_add_view(
app->view_dispatcher, WeatherStationViewSubmenu, submenu_get_view(app->submenu));
// Widget
app->widget = widget_alloc();
view_dispatcher_add_view(
app->view_dispatcher, WeatherStationViewWidget, widget_get_view(app->widget));
// Receiver
app->ws_receiver = ws_view_receiver_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
WeatherStationViewReceiver,
ws_view_receiver_get_view(app->ws_receiver));
// Receiver Info
app->ws_receiver_info = ws_view_receiver_info_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
WeatherStationViewReceiverInfo,
ws_view_receiver_info_get_view(app->ws_receiver_info));
//init setting
app->setting = subghz_setting_alloc();
//ToDo FIX file name setting
subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user"));
//init Worker & Protocol & History
app->lock = WSLockOff;
app->txrx = malloc(sizeof(WeatherStationTxRx));
app->txrx->preset = malloc(sizeof(SubGhzRadioPreset));
app->txrx->preset->name = furi_string_alloc();
ws_preset_init(app, "AM650", subghz_setting_get_default_frequency(app->setting), NULL, 0);
app->txrx->hopper_state = WSHopperStateOFF;
app->txrx->history = ws_history_alloc();
app->txrx->worker = subghz_worker_alloc();
app->txrx->environment = subghz_environment_alloc();
subghz_environment_set_protocol_registry(
app->txrx->environment, (void*)&weather_station_protocol_registry);
app->txrx->receiver = subghz_receiver_alloc_init(app->txrx->environment);
subghz_devices_init();
app->txrx->radio_device =
radio_device_loader_set(app->txrx->radio_device, SubGhzRadioDeviceTypeExternalCC1101);
subghz_devices_reset(app->txrx->radio_device);
subghz_devices_idle(app->txrx->radio_device);
subghz_receiver_set_filter(app->txrx->receiver, SubGhzProtocolFlag_Decodable);
subghz_worker_set_overrun_callback(
app->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
subghz_worker_set_pair_callback(
app->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode);
subghz_worker_set_context(app->txrx->worker, app->txrx->receiver);
furi_hal_power_suppress_charge_enter();
scene_manager_next_scene(app->scene_manager, WeatherStationSceneStart);
return app;
}
void weather_station_app_free(WeatherStationApp* app) {
furi_assert(app);
subghz_devices_sleep(app->txrx->radio_device);
radio_device_loader_end(app->txrx->radio_device);
subghz_devices_deinit();
// Submenu
view_dispatcher_remove_view(app->view_dispatcher, WeatherStationViewSubmenu);
submenu_free(app->submenu);
// Variable Item List
view_dispatcher_remove_view(app->view_dispatcher, WeatherStationViewVariableItemList);
variable_item_list_free(app->variable_item_list);
// Widget
view_dispatcher_remove_view(app->view_dispatcher, WeatherStationViewWidget);
widget_free(app->widget);
// Receiver
view_dispatcher_remove_view(app->view_dispatcher, WeatherStationViewReceiver);
ws_view_receiver_free(app->ws_receiver);
// Receiver Info
view_dispatcher_remove_view(app->view_dispatcher, WeatherStationViewReceiverInfo);
ws_view_receiver_info_free(app->ws_receiver_info);
//setting
subghz_setting_free(app->setting);
//Worker & Protocol & History
subghz_receiver_free(app->txrx->receiver);
subghz_environment_free(app->txrx->environment);
ws_history_free(app->txrx->history);
subghz_worker_free(app->txrx->worker);
furi_string_free(app->txrx->preset->name);
free(app->txrx->preset);
free(app->txrx);
// View dispatcher
view_dispatcher_free(app->view_dispatcher);
scene_manager_free(app->scene_manager);
// Notifications
furi_record_close(RECORD_NOTIFICATION);
app->notifications = NULL;
// Close records
furi_record_close(RECORD_GUI);
furi_hal_power_suppress_charge_exit();
free(app);
}
int32_t weather_station_app(void* p) {
UNUSED(p);
WeatherStationApp* weather_station_app = weather_station_app_alloc();
view_dispatcher_run(weather_station_app->view_dispatcher);
weather_station_app_free(weather_station_app);
return 0;
}

View File

@@ -1,155 +0,0 @@
#include "weather_station_app_i.h"
#define TAG "WeatherStation"
#include <flipper_format/flipper_format_i.h>
void ws_preset_init(
void* context,
const char* preset_name,
uint32_t frequency,
uint8_t* preset_data,
size_t preset_data_size) {
furi_assert(context);
WeatherStationApp* app = context;
furi_string_set(app->txrx->preset->name, preset_name);
app->txrx->preset->frequency = frequency;
app->txrx->preset->data = preset_data;
app->txrx->preset->data_size = preset_data_size;
}
bool ws_set_preset(WeatherStationApp* app, const char* preset) {
if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
furi_string_set(app->txrx->preset->name, "AM270");
} else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
furi_string_set(app->txrx->preset->name, "AM650");
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) {
furi_string_set(app->txrx->preset->name, "FM238");
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
furi_string_set(app->txrx->preset->name, "FM476");
} else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) {
furi_string_set(app->txrx->preset->name, "CUSTOM");
} else {
FURI_LOG_E(TAG, "Unknown preset");
return false;
}
return true;
}
void ws_get_frequency_modulation(
WeatherStationApp* app,
FuriString* frequency,
FuriString* modulation) {
furi_assert(app);
if(frequency != NULL) {
furi_string_printf(
frequency,
"%03ld.%02ld",
app->txrx->preset->frequency / 1000000 % 1000,
app->txrx->preset->frequency / 10000 % 100);
}
if(modulation != NULL) {
furi_string_printf(modulation, "%.2s", furi_string_get_cstr(app->txrx->preset->name));
}
}
void ws_begin(WeatherStationApp* app, uint8_t* preset_data) {
furi_assert(app);
subghz_devices_reset(app->txrx->radio_device);
subghz_devices_idle(app->txrx->radio_device);
subghz_devices_load_preset(app->txrx->radio_device, FuriHalSubGhzPresetCustom, preset_data);
app->txrx->txrx_state = WSTxRxStateIDLE;
}
uint32_t ws_rx(WeatherStationApp* app, uint32_t frequency) {
furi_assert(app);
if(!subghz_devices_is_frequency_valid(app->txrx->radio_device, frequency)) {
furi_crash("WeatherStation: Incorrect RX frequency.");
}
furi_assert(
app->txrx->txrx_state != WSTxRxStateRx && app->txrx->txrx_state != WSTxRxStateSleep);
subghz_devices_idle(app->txrx->radio_device);
uint32_t value = subghz_devices_set_frequency(app->txrx->radio_device, frequency);
subghz_devices_flush_rx(app->txrx->radio_device);
subghz_devices_set_rx(app->txrx->radio_device);
subghz_devices_start_async_rx(
app->txrx->radio_device, subghz_worker_rx_callback, app->txrx->worker);
subghz_worker_start(app->txrx->worker);
app->txrx->txrx_state = WSTxRxStateRx;
return value;
}
void ws_idle(WeatherStationApp* app) {
furi_assert(app);
furi_assert(app->txrx->txrx_state != WSTxRxStateSleep);
subghz_devices_idle(app->txrx->radio_device);
app->txrx->txrx_state = WSTxRxStateIDLE;
}
void ws_rx_end(WeatherStationApp* app) {
furi_assert(app);
furi_assert(app->txrx->txrx_state == WSTxRxStateRx);
if(subghz_worker_is_running(app->txrx->worker)) {
subghz_worker_stop(app->txrx->worker);
subghz_devices_stop_async_rx(app->txrx->radio_device);
}
subghz_devices_idle(app->txrx->radio_device);
app->txrx->txrx_state = WSTxRxStateIDLE;
}
void ws_sleep(WeatherStationApp* app) {
furi_assert(app);
subghz_devices_sleep(app->txrx->radio_device);
app->txrx->txrx_state = WSTxRxStateSleep;
}
void ws_hopper_update(WeatherStationApp* app) {
furi_assert(app);
switch(app->txrx->hopper_state) {
case WSHopperStateOFF:
case WSHopperStatePause:
return;
case WSHopperStateRSSITimeOut:
if(app->txrx->hopper_timeout != 0) {
app->txrx->hopper_timeout--;
return;
}
break;
default:
break;
}
float rssi = -127.0f;
if(app->txrx->hopper_state != WSHopperStateRSSITimeOut) {
// See RSSI Calculation timings in CC1101 17.3 RSSI
rssi = subghz_devices_get_rssi(app->txrx->radio_device);
// Stay if RSSI is high enough
if(rssi > -90.0f) {
app->txrx->hopper_timeout = 10;
app->txrx->hopper_state = WSHopperStateRSSITimeOut;
return;
}
} else {
app->txrx->hopper_state = WSHopperStateRunnig;
}
// Select next frequency
if(app->txrx->hopper_idx_frequency <
subghz_setting_get_hopper_frequency_count(app->setting) - 1) {
app->txrx->hopper_idx_frequency++;
} else {
app->txrx->hopper_idx_frequency = 0;
}
if(app->txrx->txrx_state == WSTxRxStateRx) {
ws_rx_end(app);
};
if(app->txrx->txrx_state == WSTxRxStateIDLE) {
subghz_receiver_reset(app->txrx->receiver);
app->txrx->preset->frequency =
subghz_setting_get_hopper_frequency(app->setting, app->txrx->hopper_idx_frequency);
ws_rx(app, app->txrx->preset->frequency);
}
}

View File

@@ -1,76 +0,0 @@
#pragma once
#include "helpers/weather_station_types.h"
#include "scenes/weather_station_scene.h"
#include <gui/gui.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <gui/modules/submenu.h>
#include <gui/modules/variable_item_list.h>
#include <gui/modules/widget.h>
#include <notification/notification_messages.h>
#include "views/weather_station_receiver.h"
#include "views/weather_station_receiver_info.h"
#include "weather_station_history.h"
#include <lib/subghz/subghz_setting.h>
#include <lib/subghz/subghz_worker.h>
#include <lib/subghz/receiver.h>
#include <lib/subghz/transmitter.h>
#include <lib/subghz/registry.h>
#include "helpers/radio_device_loader.h"
typedef struct WeatherStationApp WeatherStationApp;
struct WeatherStationTxRx {
SubGhzWorker* worker;
const SubGhzDevice* radio_device;
SubGhzEnvironment* environment;
SubGhzReceiver* receiver;
SubGhzRadioPreset* preset;
WSHistory* history;
uint16_t idx_menu_chosen;
WSTxRxState txrx_state;
WSHopperState hopper_state;
uint8_t hopper_timeout;
uint8_t hopper_idx_frequency;
WSRxKeyState rx_key_state;
};
typedef struct WeatherStationTxRx WeatherStationTxRx;
struct WeatherStationApp {
Gui* gui;
ViewDispatcher* view_dispatcher;
WeatherStationTxRx* txrx;
SceneManager* scene_manager;
NotificationApp* notifications;
VariableItemList* variable_item_list;
Submenu* submenu;
Widget* widget;
WSReceiver* ws_receiver;
WSReceiverInfo* ws_receiver_info;
WSLock lock;
SubGhzSetting* setting;
};
void ws_preset_init(
void* context,
const char* preset_name,
uint32_t frequency,
uint8_t* preset_data,
size_t preset_data_size);
bool ws_set_preset(WeatherStationApp* app, const char* preset);
void ws_get_frequency_modulation(
WeatherStationApp* app,
FuriString* frequency,
FuriString* modulation);
void ws_begin(WeatherStationApp* app, uint8_t* preset_data);
uint32_t ws_rx(WeatherStationApp* app, uint32_t frequency);
void ws_idle(WeatherStationApp* app);
void ws_rx_end(WeatherStationApp* app);
void ws_sleep(WeatherStationApp* app);
void ws_hopper_update(WeatherStationApp* app);

View File

@@ -1,245 +0,0 @@
#include "weather_station_history.h"
#include <flipper_format/flipper_format_i.h>
#include <lib/toolbox/stream/stream.h>
#include <lib/subghz/receiver.h>
#include "protocols/ws_generic.h"
#include <furi.h>
#define WS_HISTORY_MAX 50
#define TAG "WSHistory"
typedef struct {
FuriString* item_str;
FlipperFormat* flipper_string;
uint8_t type;
uint32_t id;
SubGhzRadioPreset* preset;
} WSHistoryItem;
ARRAY_DEF(WSHistoryItemArray, WSHistoryItem, M_POD_OPLIST)
#define M_OPL_WSHistoryItemArray_t() ARRAY_OPLIST(WSHistoryItemArray, M_POD_OPLIST)
typedef struct {
WSHistoryItemArray_t data;
} WSHistoryStruct;
struct WSHistory {
uint32_t last_update_timestamp;
uint16_t last_index_write;
uint8_t code_last_hash_data;
FuriString* tmp_string;
WSHistoryStruct* history;
};
WSHistory* ws_history_alloc(void) {
WSHistory* instance = malloc(sizeof(WSHistory));
instance->tmp_string = furi_string_alloc();
instance->history = malloc(sizeof(WSHistoryStruct));
WSHistoryItemArray_init(instance->history->data);
return instance;
}
void ws_history_free(WSHistory* instance) {
furi_assert(instance);
furi_string_free(instance->tmp_string);
for
M_EACH(item, instance->history->data, WSHistoryItemArray_t) {
furi_string_free(item->item_str);
furi_string_free(item->preset->name);
free(item->preset);
flipper_format_free(item->flipper_string);
item->type = 0;
}
WSHistoryItemArray_clear(instance->history->data);
free(instance->history);
free(instance);
}
uint32_t ws_history_get_frequency(WSHistory* instance, uint16_t idx) {
furi_assert(instance);
WSHistoryItem* item = WSHistoryItemArray_get(instance->history->data, idx);
return item->preset->frequency;
}
SubGhzRadioPreset* ws_history_get_radio_preset(WSHistory* instance, uint16_t idx) {
furi_assert(instance);
WSHistoryItem* item = WSHistoryItemArray_get(instance->history->data, idx);
return item->preset;
}
const char* ws_history_get_preset(WSHistory* instance, uint16_t idx) {
furi_assert(instance);
WSHistoryItem* item = WSHistoryItemArray_get(instance->history->data, idx);
return furi_string_get_cstr(item->preset->name);
}
void ws_history_reset(WSHistory* instance) {
furi_assert(instance);
furi_string_reset(instance->tmp_string);
for
M_EACH(item, instance->history->data, WSHistoryItemArray_t) {
furi_string_free(item->item_str);
furi_string_free(item->preset->name);
free(item->preset);
flipper_format_free(item->flipper_string);
item->type = 0;
}
WSHistoryItemArray_reset(instance->history->data);
instance->last_index_write = 0;
instance->code_last_hash_data = 0;
}
uint16_t ws_history_get_item(WSHistory* instance) {
furi_assert(instance);
return instance->last_index_write;
}
uint8_t ws_history_get_type_protocol(WSHistory* instance, uint16_t idx) {
furi_assert(instance);
WSHistoryItem* item = WSHistoryItemArray_get(instance->history->data, idx);
return item->type;
}
const char* ws_history_get_protocol_name(WSHistory* instance, uint16_t idx) {
furi_assert(instance);
WSHistoryItem* item = WSHistoryItemArray_get(instance->history->data, idx);
flipper_format_rewind(item->flipper_string);
if(!flipper_format_read_string(item->flipper_string, "Protocol", instance->tmp_string)) {
FURI_LOG_E(TAG, "Missing Protocol");
furi_string_reset(instance->tmp_string);
}
return furi_string_get_cstr(instance->tmp_string);
}
FlipperFormat* ws_history_get_raw_data(WSHistory* instance, uint16_t idx) {
furi_assert(instance);
WSHistoryItem* item = WSHistoryItemArray_get(instance->history->data, idx);
if(item->flipper_string) {
return item->flipper_string;
} else {
return NULL;
}
}
bool ws_history_get_text_space_left(WSHistory* instance, FuriString* output) {
furi_assert(instance);
if(instance->last_index_write == WS_HISTORY_MAX) {
if(output != NULL) furi_string_printf(output, "Memory is FULL");
return true;
}
if(output != NULL)
furi_string_printf(output, "%02u/%02u", instance->last_index_write, WS_HISTORY_MAX);
return false;
}
void ws_history_get_text_item_menu(WSHistory* instance, FuriString* output, uint16_t idx) {
WSHistoryItem* item = WSHistoryItemArray_get(instance->history->data, idx);
furi_string_set(output, item->item_str);
}
WSHistoryStateAddKey
ws_history_add_to_history(WSHistory* instance, void* context, SubGhzRadioPreset* preset) {
furi_assert(instance);
furi_assert(context);
if(instance->last_index_write >= WS_HISTORY_MAX) return WSHistoryStateAddKeyOverflow;
SubGhzProtocolDecoderBase* decoder_base = context;
if((instance->code_last_hash_data ==
subghz_protocol_decoder_base_get_hash_data(decoder_base)) &&
((furi_get_tick() - instance->last_update_timestamp) < 500)) {
instance->last_update_timestamp = furi_get_tick();
return WSHistoryStateAddKeyTimeOut;
}
instance->code_last_hash_data = subghz_protocol_decoder_base_get_hash_data(decoder_base);
instance->last_update_timestamp = furi_get_tick();
FlipperFormat* fff = flipper_format_string_alloc();
uint32_t id = 0;
subghz_protocol_decoder_base_serialize(decoder_base, fff, preset);
do {
if(!flipper_format_rewind(fff)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
if(!flipper_format_read_uint32(fff, "Id", (uint32_t*)&id, 1)) {
FURI_LOG_E(TAG, "Missing Id");
break;
}
} while(false);
flipper_format_free(fff);
//Update record if found
bool sensor_found = false;
for(size_t i = 0; i < WSHistoryItemArray_size(instance->history->data); i++) {
WSHistoryItem* item = WSHistoryItemArray_get(instance->history->data, i);
if(item->id == id) {
sensor_found = true;
Stream* flipper_string_stream = flipper_format_get_raw_stream(item->flipper_string);
stream_clean(flipper_string_stream);
subghz_protocol_decoder_base_serialize(decoder_base, item->flipper_string, preset);
return WSHistoryStateAddKeyUpdateData;
}
}
// or add new record
if(!sensor_found) { //-V547
WSHistoryItem* item = WSHistoryItemArray_push_raw(instance->history->data);
item->preset = malloc(sizeof(SubGhzRadioPreset));
item->type = decoder_base->protocol->type;
item->preset->frequency = preset->frequency;
item->preset->name = furi_string_alloc();
furi_string_set(item->preset->name, preset->name);
item->preset->data = preset->data;
item->preset->data_size = preset->data_size;
item->id = id;
item->item_str = furi_string_alloc();
item->flipper_string = flipper_format_string_alloc();
subghz_protocol_decoder_base_serialize(decoder_base, item->flipper_string, preset);
do {
if(!flipper_format_rewind(item->flipper_string)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
if(!flipper_format_read_string(
item->flipper_string, "Protocol", instance->tmp_string)) {
FURI_LOG_E(TAG, "Missing Protocol");
break;
}
if(!flipper_format_rewind(item->flipper_string)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
uint8_t key_data[sizeof(uint64_t)] = {0};
if(!flipper_format_read_hex(item->flipper_string, "Data", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Missing Data");
break;
}
uint64_t data = 0;
for(uint8_t i = 0; i < sizeof(uint64_t); i++) {
data = (data << 8) | key_data[i];
}
uint32_t temp_data = 0;
if(!flipper_format_read_uint32(item->flipper_string, "Ch", (uint32_t*)&temp_data, 1)) {
FURI_LOG_E(TAG, "Missing Channel");
break;
}
if(temp_data != WS_NO_CHANNEL) {
furi_string_cat_printf(instance->tmp_string, " Ch:%X", (uint8_t)temp_data);
}
furi_string_printf(
item->item_str, "%s %llX", furi_string_get_cstr(instance->tmp_string), data);
} while(false);
instance->last_index_write++;
return WSHistoryStateAddKeyNewDada;
}
return WSHistoryStateAddKeyUnknown;
}

View File

@@ -1,112 +0,0 @@
#pragma once
#include <math.h>
#include <furi.h>
#include <furi_hal.h>
#include <lib/flipper_format/flipper_format.h>
#include <lib/subghz/types.h>
typedef struct WSHistory WSHistory;
/** History state add key */
typedef enum {
WSHistoryStateAddKeyUnknown,
WSHistoryStateAddKeyTimeOut,
WSHistoryStateAddKeyNewDada,
WSHistoryStateAddKeyUpdateData,
WSHistoryStateAddKeyOverflow,
} WSHistoryStateAddKey;
/** Allocate WSHistory
*
* @return WSHistory*
*/
WSHistory* ws_history_alloc(void);
/** Free WSHistory
*
* @param instance - WSHistory instance
*/
void ws_history_free(WSHistory* instance);
/** Clear history
*
* @param instance - WSHistory instance
*/
void ws_history_reset(WSHistory* instance);
/** Get frequency to history[idx]
*
* @param instance - WSHistory instance
* @param idx - record index
* @return frequency - frequency Hz
*/
uint32_t ws_history_get_frequency(WSHistory* instance, uint16_t idx);
SubGhzRadioPreset* ws_history_get_radio_preset(WSHistory* instance, uint16_t idx);
/** Get preset to history[idx]
*
* @param instance - WSHistory instance
* @param idx - record index
* @return preset - preset name
*/
const char* ws_history_get_preset(WSHistory* instance, uint16_t idx);
/** Get history index write
*
* @param instance - WSHistory instance
* @return idx - current record index
*/
uint16_t ws_history_get_item(WSHistory* instance);
/** Get type protocol to history[idx]
*
* @param instance - WSHistory instance
* @param idx - record index
* @return type - type protocol
*/
uint8_t ws_history_get_type_protocol(WSHistory* instance, uint16_t idx);
/** Get name protocol to history[idx]
*
* @param instance - WSHistory instance
* @param idx - record index
* @return name - const char* name protocol
*/
const char* ws_history_get_protocol_name(WSHistory* instance, uint16_t idx);
/** Get string item menu to history[idx]
*
* @param instance - WSHistory instance
* @param output - FuriString* output
* @param idx - record index
*/
void ws_history_get_text_item_menu(WSHistory* instance, FuriString* output, uint16_t idx);
/** Get string the remaining number of records to history
*
* @param instance - WSHistory instance
* @param output - FuriString* output
* @return bool - is FUUL
*/
bool ws_history_get_text_space_left(WSHistory* instance, FuriString* output);
/** Add protocol to history
*
* @param instance - WSHistory instance
* @param context - SubGhzProtocolCommon context
* @param preset - SubGhzRadioPreset preset
* @return WSHistoryStateAddKey;
*/
WSHistoryStateAddKey
ws_history_add_to_history(WSHistory* instance, void* context, SubGhzRadioPreset* preset);
/** Get SubGhzProtocolCommonLoad to load into the protocol decoder bin data
*
* @param instance - WSHistory instance
* @param idx - record index
* @return SubGhzProtocolCommonLoad*
*/
FlipperFormat* ws_history_get_raw_data(WSHistory* instance, uint16_t idx);

View File

@@ -11,6 +11,8 @@ enum SubGhzSettingIndex {
SubGhzSettingIndexIgnoreStarline,
SubGhzSettingIndexIgnoreCars,
SubGhzSettingIndexIgnoreMagellan,
SubGhzSettingIndexIgnoreWeather,
SubGhzSettingIndexIgnoreTPMS,
SubGhzSettingIndexIgnorePrinceton,
SubGhzSettingIndexSound,
SubGhzSettingIndexResetToDefault,
@@ -280,6 +282,13 @@ static void subghz_scene_receiver_config_set_magellan(VariableItem* item) {
subghz_scene_receiver_config_set_ignore_filter(item, SubGhzProtocolFlag_Magellan);
}
static void subghz_scene_receiver_config_set_weather(VariableItem* item) {
subghz_scene_receiver_config_set_ignore_filter(item, SubGhzProtocolFlag_Weather);
}
static void subghz_scene_receiver_config_set_tpms(VariableItem* item) {
subghz_scene_receiver_config_set_ignore_filter(item, SubGhzProtocolFlag_TPMS);
}
static void subghz_scene_receiver_config_set_princeton(VariableItem* item) {
subghz_scene_receiver_config_set_ignore_filter(item, SubGhzProtocolFlag_Princeton);
}
@@ -439,6 +448,30 @@ void subghz_scene_receiver_config_on_enter(void* context) {
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, combobox_text[value_index]);
item = variable_item_list_add(
subghz->variable_item_list,
"Ignore Weather:",
COMBO_BOX_COUNT,
subghz_scene_receiver_config_set_weather,
subghz);
value_index = subghz_scene_receiver_config_ignore_filter_get_index(
subghz->ignore_filter, SubGhzProtocolFlag_Weather);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, combobox_text[value_index]);
item = variable_item_list_add(
subghz->variable_item_list,
"Ignore TPMS:",
COMBO_BOX_COUNT,
subghz_scene_receiver_config_set_tpms,
subghz);
value_index = subghz_scene_receiver_config_ignore_filter_get_index(
subghz->ignore_filter, SubGhzProtocolFlag_TPMS);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, combobox_text[value_index]);
item = variable_item_list_add(
subghz->variable_item_list,
"Ignore Princeton:",

View File

@@ -1,7 +1,7 @@
Filetype: IR library file
Version: 1
# Last Updated 1st Sept, 2023
# Last Checked 14th Sept, 2023
# Last Checked 1st Oct, 2023
#
name: Power
type: parsed

View File

@@ -1,7 +1,7 @@
Filetype: IR library file
Version: 1
#Last Updated 14th Sept, 2023
#Last Checked 14th Sept, 2023
#Last Updated 1st Oct, 2023
#Last Checked 1st Oct, 2023
#
name: Power
type: raw
@@ -1995,3 +1995,111 @@ type: raw
frequency: 38000
duty_cycle: 0.330000
data: 2280 776 785 1565 783 796 782 790 783 1549 783 810 752 805 752 800 752 858 752 830 752 826 776 797 775 793 774 789 773 810 747 805 747 102605 2223 832 752 1595 753 825 752 820 752 1581 752 811 751 806 751 802 750 860 750 833 775 804 773 799 773 795 773 790 773 785 772 780 773
#
name: Power
type: raw
frequency: 38000
duty_cycle: 0.33
data: 4612 4435 543 1461 544 1460 545 1461 544 1460 543 1462 518 1487 518 2441 516 1513 491 1513 492 2465 492 1513 516 2441 516 1488 516 1489 515 2443 514 1492 514 1485 4580 4467 513 1492 513 1492 513 1492 513 1491 514 1492 513 1492 513 2445 513 1492 513 1492 513 2445 513 1492 513 2445 513 1492 513 1492 513 2445 513 1493 513 14064 9205 2275 513
#
name: Speed_up
type: raw
frequency: 38000
duty_cycle: 0.33
data: 4611 4435 544 1460 545 1460 546 1459 546 1460 519 1487 517 1487 518 2440 518 1488 517 1488 516 1512 517 2440 517 1488 516 1488 516 1489 515 2444 513 2445 514 1485 4581 4467 513 1492 513 1492 513 1492 513 1492 513 1492 513 1492 513 2444 514 1492 513 1491 514 1492 513 2445 513 1492 513 1492 513 1492 513 2444 513 2446 513 14066 9203 2275 513
#
name: Speed_dn
type: raw
frequency: 38000
duty_cycle: 0.33
data: 4611 4434 545 1460 545 1459 546 1457 548 1458 521 1485 520 1485 545 2413 544 1462 542 2439 518 1487 517 1489 515 2444 512 1493 512 1493 512 1493 512 2446 512 1486 4581 4470 512 1493 511 1493 512 1493 512 1493 512 1493 512 1493 512 2446 511 1493 511 2446 512 1493 512 1493 512 2446 512 1493 512 1494 511 1493 512 2447 512 14071 9203 2279 511
#
name: Timer
type: raw
frequency: 38000
duty_cycle: 0.33
data: 4608 4436 545 1458 547 1458 547 1458 547 1458 521 1484 521 1485 520 2439 544 1461 544 2440 518 1487 517 2441 516 1489 515 2444 513 1493 512 1492 513 1494 512 1486 4577 4471 512 1493 512 1493 512 1493 512 1492 513 1493 512 1493 512 2446 512 1493 512 2446 512 1493 512 2446 512 1493 512 2446 512 1493 512 1493 512 1494 512 14051 9198 2279 512
#
name: Rotate
type: raw
frequency: 38000
duty_cycle: 0.33
data: 4605 4437 544 1460 545 1459 546 1458 546 1459 520 1485 520 1486 545 2414 543 1487 517 1488 515 1489 515 1491 513 2446 512 2446 511 2446 512 1493 512 1494 511 1487 4573 4472 511 1493 511 1493 511 1493 511 1493 512 1494 510 1494 511 2446 511 1493 511 1494 511 1494 510 1493 511 2447 511 2446 511 2446 511 1494 511 1495 511 14064 9191 2281 510
#
name: Mode
type: raw
frequency: 38000
duty_cycle: 0.33
data: 4617 4436 544 1459 545 1458 545 1458 546 1458 520 1485 519 1485 545 2413 544 1462 542 1486 517 2440 515 2442 513 1492 512 1492 513 2444 512 1492 512 1493 513 1485 4582 4469 512 1493 512 1492 512 1492 512 1493 511 1493 512 1492 512 2445 511 1493 511 1493 511 2445 512 2446 511 1493 511 1493 511 2445 511 1493 511 1494 511 14048 9216 2280 512
#
name: Power
type: raw
frequency: 38000
duty_cycle: 0.33
data: 9220 4459 632 565 628 539 628 539 627 540 626 542 624 545 622 548 619 571 596 1652 596 1652 596 1652 596 1652 596 1652 596 1652 596 1652 596 1652 596 1652 596 1652 596 1652 596 571 596 571 596 572 595 1652 596 571 596 571 596 571 596 572 595 1652 596 1652 596 1653 595 571 596 1652 596 39508 9197 2229 595 96159 9231 2229 596
#
name: Speed_up
type: raw
frequency: 38000
duty_cycle: 0.33
data: 9244 4432 633 564 629 538 630 538 629 539 627 540 626 542 624 570 598 547 620 1651 597 1651 597 1651 597 1651 597 1651 597 1651 597 1651 598 1651 597 1651 597 1651 597 1651 597 570 597 570 597 570 597 570 597 570 597 570 597 570 597 570 598 1651 597 1651 597 1651 597 1651 597 1652 596 39509 9207 2227 597
#
name: Speed_dn
type: raw
frequency: 38000
duty_cycle: 0.33
data: 9223 4461 632 565 628 540 627 540 626 541 625 542 624 545 622 547 621 571 597 1629 620 1652 597 1653 595 1653 596 1653 596 1653 596 1653 596 1653 596 572 596 572 595 1653 596 1653 595 572 595 572 596 572 595 572 595 1653 596 1653 596 572 595 572 595 1653 596 1653 595 1653 596 1653 595 39519 9204 2229 596
#
name: Timer
type: raw
frequency: 38000
duty_cycle: 0.33
data: 9227 4459 634 564 629 539 629 538 629 539 627 541 625 543 624 570 598 571 597 1652 597 1652 597 1652 597 1652 597 1652 597 1652 597 1652 597 1652 597 1652 597 571 597 571 596 1652 597 571 596 571 597 571 596 571 597 571 596 1652 597 1652 597 571 597 1652 597 1652 597 1653 596 1653 596 39523 9207 2229 596
#
name: Rotate
type: raw
frequency: 38000
duty_cycle: 0.33
data: 9223 4459 633 564 629 538 629 538 628 539 627 541 624 544 622 570 597 570 597 1651 597 1651 597 1651 597 1651 598 1651 597 1651 597 1651 597 1651 597 570 597 1651 597 1651 597 1651 597 1651 597 570 598 1651 597 570 597 1651 597 570 597 570 597 570 597 570 597 1652 596 570 597 1652 596 39519 9202 2226 597
#
name: Mode
type: raw
frequency: 38000
duty_cycle: 0.33
data: 9241 4434 633 565 602 565 628 539 628 539 627 540 626 542 624 545 622 547 620 1628 620 1629 619 1629 619 1652 596 1653 595 1629 619 1652 596 1653 595 571 596 1653 595 571 596 571 596 572 595 571 596 1653 595 572 595 1653 595 571 596 1653 595 1653 595 1653 595 1653 596 572 595 1653 595 39519 9226 2229 597
#
name: Power
type: raw
frequency: 40000
duty_cycle: 0.4
data: 20592 6864 2288 9152 11440 2288 2288 6864 2288 2288 2288 13728
#
name: Power
type: raw
frequency: 38000
duty_cycle: 0.33
data: 1328 375 1304 375 460 1196 1327 379 1299 379 430 1221 459 1221 458 1222 483 1197 483 1198 481 1222 1299 7068 1297 382 1297 382 453 1227 1296 382 1297 382 453 1227 453 1228 452 1228 452 1227 453 1228 452 1228 1296 7322 1295 383 1296 383 452 1228 1296 383 1296 383 452 1228 452 1228 452 1228 452 1228 452 1228 452 1228 1296 7070 1295 383 1296 384 451 1228 1296 383 1296 383 452 1228 452 1229 451 1228 451 1229 451 1228 451 1229 1295
#
name: Speed_up
type: raw
frequency: 38000
duty_cycle: 0.33
data: 1327 373 1306 377 459 1194 1329 373 1305 377 1276 402 433 1219 486 1194 486 1195 484 1219 1302 379 1299 7067 1299 380 1299 381 455 1224 1299 381 1298 381 1298 381 455 1225 455 1225 455 1225 455 1225 1298 381 1298 7344 1298 381 1299 381 455 1225 1298 381 1298 381 1298 381 455 1225 455 1225 455 1225 455 1226 1298 381 1298 7069 1298 382 1298 382 454 1225 1298 382 1298 382 1298 382 454 1226 454 1226 454 1226 454 1226 1297 382 1297
#
name: Speed_dn
type: raw
frequency: 38000
duty_cycle: 0.33
data: 1330 377 1302 377 459 1193 1330 376 1303 376 1277 401 435 1218 487 1194 486 1194 1329 377 1299 380 456 7911 1299 380 1299 380 456 1225 1299 380 1299 380 1299 380 456 1224 456 1225 455 1225 1298 381 1299 380 456 8149 1299 381 1298 381 455 1225 1299 380 1299 381 1299 381 455 1225 455 1225 455 1226 1298 381 1299 381 455 7913 1298 381 1299 381 455 1226 1298 381 1299 381 1298 382 454 1225 455 1226 454 1226 1298 382 1298 381 455
#
name: Rotate
type: raw
frequency: 38000
duty_cycle: 0.33
data: 1329 373 1306 377 459 1193 1330 377 1302 377 1277 402 434 1219 485 1195 1329 377 1300 379 456 1224 455 7911 1299 381 1298 381 455 1224 1299 380 1299 381 1298 381 455 1225 455 1225 1299 380 1299 381 455 1225 455 8165 1298 381 1299 381 455 1225 1299 381 1299 381 1298 381 455 1225 455 1226 1298 381 1299 381 455 1225 455 7913 1298 381 1298 381 455 1226 1297 381 1298 382 1297 382 454 1226 454 1226 1297 382 1298 382 454 1226 454
#
name: Timer
type: raw
frequency: 38000
duty_cycle: 0.33
data: 1330 376 1303 376 460 1192 1331 376 1302 376 459 1191 463 1217 462 1218 1331 376 459 1195 484 1219 460 7907 1300 379 1300 380 456 1223 1300 380 1300 380 456 1224 456 1224 456 1224 1299 380 456 1224 456 1224 456 8166 1299 380 1299 380 456 1224 1299 380 1299 380 456 1224 456 1224 455 1224 1299 380 456 1224 455 1224 456 7909 1299 380 1299 380 455 1224 1299 380 1299 380 456 1224 455 1225 455 1225 1298 381 455 1225 454 1225 455

View File

@@ -1,9 +1,9 @@
Filetype: IR library file
Version: 1
# Last Updated 14th Sept, 2023
# Last Checked 14th Sept, 2023
#
# TEMPORARY POWER FIX EDITION (All power buttons duplicated for a double press)
# Last Updated 1st Oct, 2023
# Last Checked 1st Oct, 2023
#
# TEMP FIX FOR POWER
#
# ON
name: Power
@@ -85,18 +85,18 @@ address: 08 13 00 00
command: 87 78 00 00
#
name: Power
type: parsed
protocol: NECext
address: 08 13 00 00
command: 87 78 00 00
#
name: Power
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 9055 4338 672 1551 669 1553 618 1603 619 481 617 482 616 481 617 507 591 1605 645 479 619 1577 645 1578 644 1578 644 479 619 480 618 1581 641 480 617 1605 617 1606 616 1606 615 483 615 1608 614 484 614 484 614 484 614 484 614 484 614 484 614 1609 614 484 614 1609 614 1609 613 1609 613 40058 9000 2068 614 95467 9022 2068 614
#
name: Power
type: parsed
protocol: NECext
address: 08 13 00 00
command: 87 78 00 00
#
name: Power
type: raw
frequency: 38000
duty_cycle: 0.330000
@@ -150,18 +150,19 @@ protocol: NEC
address: 02 00 00 00
command: 1D 00 00 00
#
name: Power
type: parsed
protocol: NEC
address: 02 00 00 00
command: 1D 00 00 00
#
# ON
name: Power
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 9096 4436 620 505 647 478 648 501 623 1599 647 1624 623 502 623 503 621 504 619 1628 618 507 617 507 617 1630 617 508 616 1630 617 1630 617 1631 616 508 616 508 617 508 616 1631 616 508 617 508 617 508 616 508 616 1630 616 1630 616 1631 616 508 616 1630 617 1630 617 1630 617 1631 617 509 616 508 616 509 616 509 616 509 616 509 615 509 616 508 617 1631 616 1631 615 1631 616 1631 616 1631 616 1631 616 1631 615 1631 616 14435 9093 2186 615 96359 9095 2184 617
#
name: Power
type: parsed
protocol: NEC
address: 02 00 00 00
command: 1D 00 00 00
#
# ON
name: Power
type: raw
@@ -227,7 +228,19 @@ name: Power
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 529 7218 126 6585 219 703 180 5362 427 18618 177
# ON
name: Power
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 3522 1701 472 426 444 1269 472 426 444 426 443 427 443 427 443 426 444 427 443 426 444 427 442 428 441 429 440 431 438 1304 437 433 437 433 438 433 437 433 437 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 1305 436 434 436 434 436 1305 436 435 435 435 435 435 435 435 435 435 435 435 435 435 435 459 411 459 411 459 411 1330 411 1330 411 1330 411 1330 411 1330 411 460 410 459 411 459 411 1330 411 1330 411 460 410 1330 411 1330 411 1331 410 1330 411 74392 3516 1736 436 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 434 436 433 437 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 435 435 1305 436 435 435 435 435 1306 435 435 435 435 435 435 435 436 434 436 434 436 434 435 435 436 434 436 434 436 434 1330 411 1331 410 1330 411 1330 411 1330 411 459 411 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 433 437 433 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 435 436 434 436 1306 435 435 435 435 435 1306 435 435 435 435 435 435 435 435 435 435 435 436 434 436 434 435 435 436 434 435 435 1306 435 1330 411 1307 434 1331 410 1308 433 436 434 436 434 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 435 435 434 436 434 436 434 436 434 436 434 436 1306 435 435 435 435 435 435 435 1306 435 435 435 436 434 1306 435 435 435 436 434 436 434 435 435 436 434 436 434 460 410 460 410 460 410 460 410 1331 410 1331 410 1331 410 1331 410 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 433 437 434 436 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 435 435 435 435 434 436 1306 435 434 436 435 435 435 435 1306 435 436 434 435 435 1306 435 435 435 436 434 436 434 436 434 436 434 460 410 437 433 459 411 460 410 460 410 1331 410 1331 410 1331 410 1331 410 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74393 3514 1736 437 434 436 1304 437 433 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 435 435 434 436 434 436 435 435 434 436 1305 436 435 435 435 435 435 435 1306 435 435 435 435 435 1306 435 435 435 436 434 435 435 459 411 436 434 435 435 459 411 459 411 459 411 459 411 1330 411 1306 435 1330 411 1330 411 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410
# ON
name: Power
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 529 7218 126 6585 219 703 180 5362 427 18618 177
#
name: Vol_up
type: raw
@@ -252,18 +265,18 @@ type: parsed
protocol: NECext
address: 83 F4 00 00
command: 4F B0 00 00
# ON
name: Power
type: parsed
protocol: NECext
address: 83 F4 00 00
command: 4F B0 00 00
#
name: Power
type: parsed
protocol: NECext
address: 80 19 00 00
command: 10 EF 00 00
# ON
name: Power
type: parsed
protocol: NECext
address: 83 F4 00 00
command: 4F B0 00 00
#
name: Power
type: parsed
@@ -291,18 +304,6 @@ command: 51 00 00 00
#
name: Power
type: parsed
protocol: NEC
address: 80 00 00 00
command: 51 00 00 00
#
name: Power
type: parsed
protocol: NECext
address: 40 40 00 00
command: 0A F5 00 00
#
name: Power
type: parsed
protocol: NECext
address: 40 40 00 00
command: 0A F5 00 00
@@ -315,6 +316,18 @@ command: 4E B1 00 00
#
name: Power
type: parsed
protocol: NEC
address: 80 00 00 00
command: 51 00 00 00
#
name: Power
type: parsed
protocol: NECext
address: 40 40 00 00
command: 0A F5 00 00
#
name: Power
type: parsed
protocol: NECext
address: 00 30 00 00
command: 4E B1 00 00
@@ -406,14 +419,14 @@ command: 0B F4 00 00
name: Power
type: parsed
protocol: NECext
address: 84 F4 00 00
command: 0B F4 00 00
address: 33 00 00 00
command: 00 FF 00 00
#
name: Power
type: parsed
protocol: NECext
address: 33 00 00 00
command: 00 FF 00 00
address: 84 F4 00 00
command: 0B F4 00 00
#
name: Power
type: parsed
@@ -497,13 +510,13 @@ name: Power
type: parsed
protocol: NEC
address: 32 00 00 00
command: 02 00 00 00
command: 2E 00 00 00
#
name: Power
type: parsed
protocol: NEC
address: 32 00 00 00
command: 2E 00 00 00
command: 02 00 00 00
#
name: Power
type: parsed
@@ -587,13 +600,13 @@ name: Power
type: parsed
protocol: NEC
address: 31 00 00 00
command: 91 00 00 00
command: 90 00 00 00
#
name: Power
type: parsed
protocol: NEC
address: 31 00 00 00
command: 90 00 00 00
command: 91 00 00 00
#
name: Power
type: parsed
@@ -652,18 +665,6 @@ command: 00 00 00 00
name: Power
type: parsed
protocol: NECext
address: 30 00 00 00
command: 00 00 00 00
#
name: Power
type: parsed
protocol: NECext
address: 87 4E 00 00
command: 0D 00 00 00
#
name: Power
type: parsed
protocol: NECext
address: 87 4E 00 00
command: 0D 00 00 00
#
@@ -674,6 +675,18 @@ duty_cycle: 0.330000
data: 9032 4479 597 560 572 558 564 566 566 1666 589 1671 594 562 570 560 562 568 564 1669 596 560 562 568 564 1669 596 560 562 1671 594 1666 588 1671 594 562 570 560 562 568 564 1669 596 560 562 568 564 566 566 563 569 1664 591 1669 596 1664 590 565 567 1667 598 1661 593 1666 588 1671 594 562 570 560 562 568 564 565 567 563 569 560 562 568 564 565 567 1666 588 1671 594 1665 589 1670 595 1665 590 1669 596 1664 590 1668 597 13983 9029 2222 599 96237 9030 2221 589 96244 9034 2217 594 96244 9033 2218 592 96249 9038 2213 597 96239 9037 2214 596 96238 9028 2223 598 96221 9032 2215 595
#
name: Power
type: parsed
protocol: NECext
address: 30 00 00 00
command: 00 00 00 00
#
name: Power
type: parsed
protocol: NECext
address: 87 4E 00 00
command: 0D 00 00 00
#
name: Power
type: raw
frequency: 38000
duty_cycle: 0.330000
@@ -714,18 +727,18 @@ type: parsed
protocol: NECext
address: 83 F4 00 00
command: 4E B1 00 00
# OFF
name: Power
type: parsed
protocol: NECext
address: 83 F4 00 00
command: 4E B1 00 00
#
name: Power
type: parsed
protocol: NEC
address: 03 00 00 00
command: 1D 00 00 00
# OFF
name: Power
type: parsed
protocol: NECext
address: 83 F4 00 00
command: 4E B1 00 00
#
name: Power
type: parsed
@@ -750,18 +763,18 @@ type: raw
frequency: 38000
duty_cycle: 0.330000
data: 9075 4307 677 433 675 456 651 461 651 1579 650 1576 649 459 649 460 648 465 648 1578 647 461 622 491 622 1604 647 465 647 1583 622 1608 647 1579 647 461 647 466 622 1604 647 465 647 1579 647 461 645 463 648 465 648 1583 646 1580 646 466 647 1579 622 491 647 1583 622 1608 647 1579 647 461 647 461 622 486 622 486 647 461 647 462 646 462 622 491 646 1584 622 1608 647 1584 621 1608 647 1583 646 1584 647 1584 646 1592 622 14330 9047 2137 621
# OFF
name: Power
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 9075 4307 677 433 675 456 651 461 651 1579 650 1576 649 459 649 460 648 465 648 1578 647 461 622 491 622 1604 647 465 647 1583 622 1608 647 1579 647 461 647 466 622 1604 647 465 647 1579 647 461 645 463 648 465 648 1583 646 1580 646 466 647 1579 622 491 647 1583 622 1608 647 1579 647 461 647 461 622 486 622 486 647 461 647 462 646 462 622 491 646 1584 622 1608 647 1584 621 1608 647 1583 646 1584 647 1584 646 1592 622 14330 9047 2137 621
#
name: Power
type: parsed
protocol: Samsung32
address: 07 00 00 00
command: E6 00 00 00
# OFF
name: Power
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 9075 4307 677 433 675 456 651 461 651 1579 650 1576 649 459 649 460 648 465 648 1578 647 461 622 491 622 1604 647 465 647 1583 622 1608 647 1579 647 461 647 466 622 1604 647 465 647 1579 647 461 645 463 648 465 648 1583 646 1580 646 466 647 1579 622 491 647 1583 622 1608 647 1579 647 461 647 461 622 486 622 486 647 461 647 462 646 462 622 491 646 1584 622 1608 647 1584 621 1608 647 1583 646 1584 647 1584 646 1592 622 14330 9047 2137 621
#
name: Power
type: parsed
@@ -1041,18 +1054,18 @@ command: 81 00 00 00
#
name: Power
type: parsed
protocol: NEC
address: 31 00 00 00
command: 81 00 00 00
#
name: Power
type: parsed
protocol: NECext
address: 83 F4 00 00
command: 17 E8 00 00
#
name: Power
type: parsed
protocol: NEC
address: 31 00 00 00
command: 81 00 00 00
#
name: Power
type: parsed
protocol: NECext
address: 83 F4 00 00
command: 17 E8 00 00
@@ -1269,18 +1282,18 @@ command: 40 00 00 00
#
name: Power
type: parsed
protocol: NEC
address: 01 00 00 00
command: 40 00 00 00
#
name: Power
type: parsed
protocol: NECext
address: 00 BD 00 00
command: 01 FE 00 00
#
name: Power
type: parsed
protocol: NEC
address: 01 00 00 00
command: 40 00 00 00
#
name: Power
type: parsed
protocol: NECext
address: 00 BD 00 00
command: 01 FE 00 00
@@ -1464,3 +1477,21 @@ type: raw
frequency: 38000
duty_cycle: 0.33
data: 353 1742 355 693 355 1742 355 1742 355 693 355 1744 353 694 354 1743 354 693 355 1743 354 694 354 693 355 694 354 1742 355 695 353 43687 354 1743 354 696 352 1744 353 1744 353 694 354 695 353 1742 355 694 354 1743 354 694 354 1743 354 1742 355 1742 355 694 354 1744 353 41606 351 1745 352 696 352 1746 351 1746 351 697 351 1747 350 696 352 1745 352 698 350 1746 351 698 350 696 352 698 350 1746 351 699 349
#
name: Power
type: parsed
protocol: Samsung32
address: 07 00 00 00
command: 02 00 00 00
#
name: Power
type: parsed
protocol: Samsung32
address: 07 00 00 00
command: 02 00 00 00
#
name: Mute
type: parsed
protocol: Samsung32
address: 07 00 00 00
command: D1 00 00 00

View File

@@ -1,7 +1,7 @@
Filetype: IR library file
Version: 1
# Last Updated 1st Sept, 2023
# Last Checked 14th Sept, 2023
# Last Updated 1st Oct, 2023
# Last Checked 1st Oct, 2023
#
name: Power
type: parsed
@@ -2369,3 +2369,27 @@ type: parsed
protocol: NECext
address: 00 7F 00 00
command: 06 F9 00 00
#
name: Power
type: parsed
protocol: NECext
address: 69 69 00 00
command: 01 FE 00 00
#
name: Vol_up
type: parsed
protocol: NECext
address: 69 69 00 00
command: 0A F5 00 00
#
name: Vol_dn
type: parsed
protocol: NECext
address: 69 69 00 00
command: 0B F4 00 00
#
name: Mute
type: parsed
protocol: NECext
address: 69 69 00 00
command: 0E F1 00 00

View File

@@ -0,0 +1,6 @@
Filetype: Flipper SubGhz RAW File
Version: 1
Frequency: 433920000
Preset: FuriHalSubGhzPresetOok270Async
Protocol: RAW
RAW_Data: 24683 -68 97699 -66 49329 -68 77683 -66 369085 -100 59281 -68 29331 -64 357017 -68 284193 -66 128025 -64 198459 -64 522601 -66 111101 -70 132215 -64 288735 -68 747835 -102 26103 -70 25451 -68 349459 -66 166857 -66 68137 -66 595143 -128 59929 -66 17225 -66 16705 -66 105655 -66 10015 -38916 101 -2318 493 -708 395 -716 505 -734 487 -694 343 -274 339 -260 163 -440 343 -306 319 -268 159 -436 201 -432 157 -438 387 -244 179 -410 379 -234 187 -430 397 -218 183 -436 387 -236 371 -244 179 -414 409 -190 223 -410 193 -416 213 -396 393 -228 199 -406 209 -422 207 -392 387 -240 207 -384 419 -204 219 -394 203 -418 379 -244 395 -202 395 -208 251 -392 205 -380 221 -378 417 -242 215 -392 205 -396 203 -408 417 -204 217 -396 203 -394 389 -246 393 -206 393 -240 217 -396 203 -394 205 -410 191 -418 411 -190 401 -246 389 -206 393 -240 379 -222 187 -400 239 -2198 615 -592 615 -612 605 -614 597 -620 367 -224 411 -214 215 -402 387 -206 407 -226 197 -404 209 -422 205 -394 387 -238 207 -384 417 -204 219 -394 389 -238 205 -388 415 -206 379 -222 227 -400 417 -204 217 -396 203 -394 231 -370 413 -240 217 -394 203 -394 207 -408 393 -240 217 -392 367 -222 225 -400 209 -418 367 -224 413 -214 393 -204 215 -428 207 -394 201 -394 391 -246 213 -368 245 -394 203 -394 385 -240 209 -392 243 -390 395 -226 385 -212 395 -238 219 -392 205 -394 203 -418 223 -412 387 -242 369 -226 393 -210 395 -238 393 -208 217 -394 203 -59252 317 -277080 99 -1690 201 -634 469 -270 1393 -300 97817 -66 55659 -64 628165 -64 110139 -100 61425 -66 59611 -66 6621 -68 18847 -66 468225 -64 99275

View File

@@ -110,9 +110,9 @@ void t5577_write_with_pass(LFRFIDT5577* data, uint32_t password) {
t5577_start();
FURI_CRITICAL_ENTER();
for(size_t i = 0; i < data->blocks_to_write; i++) {
t5577_write_block_pass(0, false, data->block[i], true, password);
t5577_write_block_pass(i, false, data->block[i], true, password);
}
t5577_write_reset();
FURI_CRITICAL_EXIT();
t5577_stop();
}
}

View File

@@ -26,6 +26,8 @@
* - However 14 bits available for temperature, giving possible range of -100 C to 1538.4 C
* - @todo - check if high 3 bits ever used for anything else
*
* SUB file generator: https://htotoo.github.io/FlipperSUBGenerator/acurite_592txr-generator/index.html
*
*/
static const SubGhzBlockConst ws_protocol_acurite_592txr_const = {
@@ -72,19 +74,20 @@ const SubGhzProtocolDecoder ws_protocol_acurite_592txr_decoder = {
};
const SubGhzProtocolEncoder ws_protocol_acurite_592txr_encoder = {
.alloc = NULL,
.free = NULL,
.alloc = ws_protocol_encoder_acurite_592txr_alloc,
.free = ws_protocol_encoder_acurite_592txr_free,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
.deserialize = ws_protocol_encoder_acurite_592txr_deserialize,
.stop = ws_protocol_encoder_acurite_592txr_stop,
.yield = ws_protocol_encoder_acurite_592txr_yield,
};
const SubGhzProtocol ws_protocol_acurite_592txr = {
.name = WS_PROTOCOL_ACURITE_592TXR_NAME,
.type = SubGhzProtocolWeatherStation,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Weather |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &ws_protocol_acurite_592txr_decoder,
.encoder = &ws_protocol_acurite_592txr_encoder,
@@ -280,9 +283,9 @@ SubGhzProtocolStatus
void ws_protocol_decoder_acurite_592txr_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderAcurite_592TXR* instance = context;
furi_string_printf(
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"%s\r\n%dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%3.1f C Hum:%d%%",
@@ -296,3 +299,120 @@ void ws_protocol_decoder_acurite_592txr_get_string(void* context, FuriString* ou
(double)instance->generic.temp,
instance->generic.humidity);
}
void* ws_protocol_encoder_acurite_592txr_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
WSProtocolEncoderAcurite_592TXR* instance = malloc(sizeof(WSProtocolEncoderAcurite_592TXR));
instance->base.protocol = &ws_protocol_acurite_592txr;
instance->generic.protocol_name = instance->base.protocol->name;
instance->encoder.repeat = 6;
instance->encoder.size_upload =
ws_protocol_acurite_592txr_const.min_count_bit_for_found * 2 + 8;
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_running = false;
return instance;
}
void ws_protocol_encoder_acurite_592txr_free(void* context) {
furi_assert(context);
WSProtocolEncoderAcurite_592TXR* instance = context;
free(instance->encoder.upload);
free(instance);
}
bool ws_protocol_encoder_acurite_592txr_get_upload(WSProtocolEncoderAcurite_592TXR* instance) {
furi_assert(instance);
size_t index = 0;
size_t size_upload = (instance->generic.data_count_bit * 2) + 8;
if(size_upload > instance->encoder.size_upload) {
FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
return false;
} else {
instance->encoder.size_upload = size_upload;
}
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)ws_protocol_acurite_592txr_const.te_short * 3);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)ws_protocol_acurite_592txr_const.te_short * 3);
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)ws_protocol_acurite_592txr_const.te_short * 3);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)ws_protocol_acurite_592txr_const.te_short * 3);
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)ws_protocol_acurite_592txr_const.te_short * 3);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)ws_protocol_acurite_592txr_const.te_short * 3);
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)ws_protocol_acurite_592txr_const.te_short * 3);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)ws_protocol_acurite_592txr_const.te_short * 3);
for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
if(!bit_read(instance->generic.data, i - 1)) {
//send bit 1
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)ws_protocol_acurite_592txr_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)ws_protocol_acurite_592txr_const.te_long);
} else {
//send bit 0
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)ws_protocol_acurite_592txr_const.te_long);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)ws_protocol_acurite_592txr_const.te_short);
}
}
return true;
}
SubGhzProtocolStatus
ws_protocol_encoder_acurite_592txr_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
WSProtocolEncoderAcurite_592TXR* instance = context;
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
do {
ret = ws_block_generic_deserialize(&instance->generic, flipper_format);
if(ret != SubGhzProtocolStatusOk) {
break;
}
if((instance->generic.data_count_bit >
ws_protocol_acurite_592txr_const.min_count_bit_for_found)) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
ret = SubGhzProtocolStatusErrorValueBitCount;
break;
}
//optional parameter parameter
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 6);
if(!ws_protocol_encoder_acurite_592txr_get_upload(instance)) {
ret = SubGhzProtocolStatusErrorEncoderGetUpload;
break;
}
instance->encoder.is_running = true;
} while(false);
return ret;
}
LevelDuration ws_protocol_encoder_acurite_592txr_yield(void* context) {
WSProtocolEncoderAcurite_592TXR* instance = context;
if(instance->encoder.repeat == 0 || !instance->encoder.is_running) {
instance->encoder.is_running = false;
return level_duration_reset();
}
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
if(++instance->encoder.front == instance->encoder.size_upload) {
instance->encoder.repeat--;
instance->encoder.front = 0;
}
return ret;
}
void ws_protocol_encoder_acurite_592txr_stop(void* context) {
WSProtocolEncoderAcurite_592TXR* instance = context;
instance->encoder.is_running = false;
}

View File

@@ -78,3 +78,11 @@ SubGhzProtocolStatus
* @param output Resulting text
*/
void ws_protocol_decoder_acurite_592txr_get_string(void* context, FuriString* output);
void* ws_protocol_encoder_acurite_592txr_alloc(SubGhzEnvironment* environment);
void ws_protocol_encoder_acurite_592txr_free(void* context);
bool ws_protocol_encoder_acurite_592txr_get_upload(WSProtocolEncoderAcurite_592TXR* instance);
SubGhzProtocolStatus
ws_protocol_encoder_acurite_592txr_deserialize(void* context, FlipperFormat* flipper_format);
LevelDuration ws_protocol_encoder_acurite_592txr_yield(void* context);
void ws_protocol_encoder_acurite_592txr_stop(void* context);

View File

@@ -67,9 +67,10 @@ const SubGhzProtocolEncoder ws_protocol_acurite_606tx_encoder = {
const SubGhzProtocol ws_protocol_acurite_606tx = {
.name = WS_PROTOCOL_ACURITE_606TX_NAME,
.type = SubGhzProtocolWeatherStation,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Weather |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save,
.decoder = &ws_protocol_acurite_606tx_decoder,
.encoder = &ws_protocol_acurite_606tx_encoder,
@@ -221,9 +222,9 @@ SubGhzProtocolStatus
void ws_protocol_decoder_acurite_606tx_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderAcurite_606TX* instance = context;
furi_string_printf(
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"%s\r\n%dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%3.1f C Hum:%d%%",

View File

@@ -68,9 +68,10 @@ const SubGhzProtocolEncoder ws_protocol_acurite_609txc_encoder = {
const SubGhzProtocol ws_protocol_acurite_609txc = {
.name = WS_PROTOCOL_ACURITE_609TXC_NAME,
.type = SubGhzProtocolWeatherStation,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Weather |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save,
.decoder = &ws_protocol_acurite_609txc_decoder,
.encoder = &ws_protocol_acurite_609txc_encoder,
@@ -221,9 +222,9 @@ SubGhzProtocolStatus
void ws_protocol_decoder_acurite_609txc_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context;
furi_string_printf(
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"%s\r\n%dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%3.1f C Hum:%d%%",

View File

@@ -82,9 +82,10 @@ const SubGhzProtocolEncoder ws_protocol_ambient_weather_encoder = {
const SubGhzProtocol ws_protocol_ambient_weather = {
.name = WS_PROTOCOL_AMBIENT_WEATHER_NAME,
.type = SubGhzProtocolWeatherStation,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Weather |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save,
.decoder = &ws_protocol_ambient_weather_decoder,
.encoder = &ws_protocol_ambient_weather_encoder,
@@ -250,9 +251,9 @@ SubGhzProtocolStatus
void ws_protocol_decoder_ambient_weather_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderAmbient_Weather* instance = context;
furi_string_printf(
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"%s\r\n%dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%3.1f C Hum:%d%%",

View File

@@ -79,9 +79,10 @@ const SubGhzProtocolEncoder ws_protocol_auriol_ahfl_encoder = {
const SubGhzProtocol ws_protocol_auriol_ahfl = {
.name = WS_PROTOCOL_AURIOL_AHFL_NAME,
.type = SubGhzProtocolWeatherStation,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Weather |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save,
.decoder = &ws_protocol_auriol_ahfl_decoder,
.encoder = &ws_protocol_auriol_ahfl_encoder,
@@ -236,9 +237,9 @@ SubGhzProtocolStatus
void ws_protocol_decoder_auriol_ahfl_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderAuriol_AHFL* instance = context;
furi_string_printf(
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"%s\r\n%dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%3.1f C Hum:%d%%",

View File

@@ -78,9 +78,10 @@ const SubGhzProtocolEncoder ws_protocol_auriol_th_encoder = {
const SubGhzProtocol ws_protocol_auriol_th = {
.name = WS_PROTOCOL_AURIOL_TH_NAME,
.type = SubGhzProtocolWeatherStation,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Weather |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save,
.decoder = &ws_protocol_auriol_th_decoder,
.encoder = &ws_protocol_auriol_th_encoder,
@@ -230,9 +231,9 @@ SubGhzProtocolStatus
void ws_protocol_decoder_auriol_th_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderAuriol_TH* instance = context;
furi_string_printf(
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"%s\r\n%dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%3.1f C Hum:%d%%",

View File

@@ -9,9 +9,9 @@
* GT-WT-02 sensor on 433.92MHz.
* Example and frame description provided by https://github.com/ludwich66
* [01] {37} 34 00 ed 47 60 : 00110100 00000000 11101101 01000111 01100000
* code, BatOK,not-man-send, Channel1, +23,7°C, 35%
* code, BatOK,not-man-send, Channel1, +23,7<EFBFBD>C, 35%
* [01] {37} 34 8f 87 15 90 : 00110100 10001111 10000111 00010101 10010000
* code, BatOK,not-man-send, Channel1,-12,1°C, 10%
* code, BatOK,not-man-send, Channel1,-12,1<EFBFBD>C, 10%
* Humidity:
* - the working range is 20-90 %
* - if "LL" in display view it sends 10 %
@@ -81,9 +81,10 @@ const SubGhzProtocolEncoder ws_protocol_gt_wt_02_encoder = {
const SubGhzProtocol ws_protocol_gt_wt_02 = {
.name = WS_PROTOCOL_GT_WT_02_NAME,
.type = SubGhzProtocolWeatherStation,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Weather |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save,
.decoder = &ws_protocol_gt_wt_02_decoder,
.encoder = &ws_protocol_gt_wt_02_encoder,
@@ -237,9 +238,9 @@ SubGhzProtocolStatus
void ws_protocol_decoder_gt_wt_02_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderGT_WT02* instance = context;
furi_string_printf(
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"%s\r\n%dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%3.1f C Hum:%d%%",

View File

@@ -107,9 +107,10 @@ const SubGhzProtocolEncoder ws_protocol_gt_wt_03_encoder = {
const SubGhzProtocol ws_protocol_gt_wt_03 = {
.name = WS_PROTOCOL_GT_WT_03_NAME,
.type = SubGhzProtocolWeatherStation,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Weather |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save,
.decoder = &ws_protocol_gt_wt_03_decoder,
.encoder = &ws_protocol_gt_wt_03_encoder,
@@ -312,9 +313,9 @@ SubGhzProtocolStatus
void ws_protocol_decoder_gt_wt_03_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderGT_WT03* instance = context;
furi_string_printf(
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"%s\r\n%dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%3.1f C Hum:%d%%",

View File

@@ -92,9 +92,10 @@ const SubGhzProtocolEncoder ws_protocol_infactory_encoder = {
const SubGhzProtocol ws_protocol_infactory = {
.name = WS_PROTOCOL_INFACTORY_NAME,
.type = SubGhzProtocolWeatherStation,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Weather |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save,
.decoder = &ws_protocol_infactory_decoder,
.encoder = &ws_protocol_infactory_encoder,
@@ -268,9 +269,9 @@ SubGhzProtocolStatus
void ws_protocol_decoder_infactory_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderInfactory* instance = context;
furi_string_printf(
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"%s\r\n%dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%3.1f C Hum:%d%%",

View File

@@ -96,9 +96,9 @@ const SubGhzProtocolEncoder ws_protocol_lacrosse_tx_encoder = {
const SubGhzProtocol ws_protocol_lacrosse_tx = {
.name = WS_PROTOCOL_LACROSSE_TX_NAME,
.type = SubGhzProtocolWeatherStation,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Weather,
.decoder = &ws_protocol_lacrosse_tx_decoder,
.encoder = &ws_protocol_lacrosse_tx_encoder,
@@ -301,9 +301,9 @@ SubGhzProtocolStatus
void ws_protocol_decoder_lacrosse_tx_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderLaCrosse_TX* instance = context;
furi_string_printf(
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"%s\r\n%dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%3.1f C Hum:%d%%",

View File

@@ -74,9 +74,10 @@ const SubGhzProtocolEncoder ws_protocol_lacrosse_tx141thbv2_encoder = {
const SubGhzProtocol ws_protocol_lacrosse_tx141thbv2 = {
.name = WS_PROTOCOL_LACROSSE_TX141THBV2_NAME,
.type = SubGhzProtocolWeatherStation,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Weather |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save,
.decoder = &ws_protocol_lacrosse_tx141thbv2_decoder,
.encoder = &ws_protocol_lacrosse_tx141thbv2_encoder,
@@ -276,9 +277,9 @@ SubGhzProtocolStatus ws_protocol_decoder_lacrosse_tx141thbv2_deserialize(
void ws_protocol_decoder_lacrosse_tx141thbv2_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderLaCrosse_TX141THBv2* instance = context;
furi_string_printf(
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"%s\r\n%dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%3.1f C Hum:%d%%",

View File

@@ -25,13 +25,14 @@
* - humidity is 8 bits
* The sensors can be bought at Clas Ohlsen (Nexus) and Pearl (infactory/FreeTec).
*
* Generate test files: https://htotoo.github.io/FlipperSUBGenerator/nexus-th-generator/index.html
*/
#define NEXUS_TH_CONST_DATA 0b1111
static const SubGhzBlockConst ws_protocol_nexus_th_const = {
.te_short = 500,
.te_long = 2000,
.te_short = 490,
.te_long = 1980,
.te_delta = 150,
.min_count_bit_for_found = 36,
};
@@ -56,37 +57,26 @@ typedef enum {
Nexus_THDecoderStepCheckDuration,
} Nexus_THDecoderStep;
const SubGhzProtocolDecoder ws_protocol_nexus_th_decoder = {
.alloc = ws_protocol_decoder_nexus_th_alloc,
.free = ws_protocol_decoder_nexus_th_free,
void* ws_protocol_encoder_nexus_th_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
WSProtocolEncoderNexus_TH* instance = malloc(sizeof(WSProtocolEncoderNexus_TH));
.feed = ws_protocol_decoder_nexus_th_feed,
.reset = ws_protocol_decoder_nexus_th_reset,
instance->base.protocol = &ws_protocol_nexus_th;
instance->generic.protocol_name = instance->base.protocol->name;
.get_hash_data = ws_protocol_decoder_nexus_th_get_hash_data,
.serialize = ws_protocol_decoder_nexus_th_serialize,
.deserialize = ws_protocol_decoder_nexus_th_deserialize,
.get_string = ws_protocol_decoder_nexus_th_get_string,
};
instance->encoder.repeat = 12;
instance->encoder.size_upload = ws_protocol_nexus_th_const.min_count_bit_for_found * 2 + 2;
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_running = false;
return instance;
}
const SubGhzProtocolEncoder ws_protocol_nexus_th_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol ws_protocol_nexus_th = {
.name = WS_PROTOCOL_NEXUS_TH_NAME,
.type = SubGhzProtocolWeatherStation,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
.decoder = &ws_protocol_nexus_th_decoder,
.encoder = &ws_protocol_nexus_th_encoder,
};
void ws_protocol_encoder_nexus_th_free(void* context) {
furi_assert(context);
WSProtocolEncoderNexus_TH* instance = context;
free(instance->encoder.upload);
free(instance);
}
void* ws_protocol_decoder_nexus_th_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
@@ -119,6 +109,93 @@ static bool ws_protocol_nexus_th_check(WSProtocolDecoderNexus_TH* instance) {
return true;
}
static bool ws_protocol_encoder_nexus_th_get_upload(WSProtocolEncoderNexus_TH* instance) {
furi_assert(instance);
size_t index = 0;
size_t size_upload = (instance->generic.data_count_bit * 2) + 2;
if(size_upload > instance->encoder.size_upload) {
FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
return false;
} else {
instance->encoder.size_upload = size_upload;
}
for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
if(!bit_read(instance->generic.data, i - 1)) {
//send bit 1
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)ws_protocol_nexus_th_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)ws_protocol_nexus_th_const.te_short * 2);
} else {
//send bit 0
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)ws_protocol_nexus_th_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)ws_protocol_nexus_th_const.te_short * 4);
}
}
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)ws_protocol_nexus_th_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)ws_protocol_nexus_th_const.te_short * 8);
return true;
}
SubGhzProtocolStatus
ws_protocol_encoder_nexus_th_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
WSProtocolEncoderNexus_TH* instance = context;
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
do {
ret = ws_block_generic_deserialize(&instance->generic, flipper_format);
if(ret != SubGhzProtocolStatusOk) {
break;
}
if((instance->generic.data_count_bit >
ws_protocol_nexus_th_const.min_count_bit_for_found + 1)) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
ret = SubGhzProtocolStatusErrorValueBitCount;
break;
}
//optional parameter parameter
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 12);
if(!ws_protocol_encoder_nexus_th_get_upload(instance)) {
ret = SubGhzProtocolStatusErrorEncoderGetUpload;
break;
}
instance->encoder.is_running = true;
} while(false);
return ret;
}
LevelDuration ws_protocol_encoder_nexus_th_yield(void* context) {
WSProtocolEncoderNexus_TH* instance = context;
if(instance->encoder.repeat == 0 || !instance->encoder.is_running) {
instance->encoder.is_running = false;
return level_duration_reset();
}
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
if(++instance->encoder.front == instance->encoder.size_upload) {
instance->encoder.repeat--;
instance->encoder.front = 0;
}
return ret;
}
void ws_protocol_encoder_nexus_th_stop(void* context) {
WSProtocolEncoderNexus_TH* instance = context;
instance->encoder.is_running = false;
}
/**
* Analysis of received data
* @param instance Pointer to a WSBlockGeneric* instance
@@ -236,9 +313,9 @@ SubGhzProtocolStatus
void ws_protocol_decoder_nexus_th_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderNexus_TH* instance = context;
furi_string_printf(
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"%s\r\n%dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%3.1f C Hum:%d%%",
@@ -252,3 +329,36 @@ void ws_protocol_decoder_nexus_th_get_string(void* context, FuriString* output)
(double)instance->generic.temp,
instance->generic.humidity);
}
const SubGhzProtocolDecoder ws_protocol_nexus_th_decoder = {
.alloc = ws_protocol_decoder_nexus_th_alloc,
.free = ws_protocol_decoder_nexus_th_free,
.feed = ws_protocol_decoder_nexus_th_feed,
.reset = ws_protocol_decoder_nexus_th_reset,
.get_hash_data = ws_protocol_decoder_nexus_th_get_hash_data,
.serialize = ws_protocol_decoder_nexus_th_serialize,
.deserialize = ws_protocol_decoder_nexus_th_deserialize,
.get_string = ws_protocol_decoder_nexus_th_get_string,
};
const SubGhzProtocolEncoder ws_protocol_nexus_th_encoder = {
.alloc = ws_protocol_encoder_nexus_th_alloc,
.free = ws_protocol_encoder_nexus_th_free,
.deserialize = ws_protocol_encoder_nexus_th_deserialize,
.stop = ws_protocol_encoder_nexus_th_stop,
.yield = ws_protocol_encoder_nexus_th_yield,
};
const SubGhzProtocol ws_protocol_nexus_th = {
.name = WS_PROTOCOL_NEXUS_TH_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Weather |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &ws_protocol_nexus_th_decoder,
.encoder = &ws_protocol_nexus_th_encoder,
};

View File

@@ -387,7 +387,7 @@ void ws_protocol_decoder_oregon2_get_string(void* context, FuriString* output) {
furi_string_cat_printf(
output,
"%s\r\n"
"ID: 0x%04lX, ch: %d, bat: %d, rc: 0x%02lX\r\n",
"ID: 0x%04lX, ch: %d,\r\nbat: %d, rc: 0x%02lX\r\n",
instance->generic.protocol_name,
instance->generic.id,
instance->generic.channel,
@@ -422,8 +422,9 @@ const SubGhzProtocolDecoder ws_protocol_oregon2_decoder = {
const SubGhzProtocol ws_protocol_oregon2 = {
.name = WS_PROTOCOL_OREGON2_NAME,
.type = SubGhzProtocolWeatherStation,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Weather | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save,
.decoder = &ws_protocol_oregon2_decoder,
};

View File

@@ -323,7 +323,7 @@ void ws_protocol_decoder_oregon3_get_string(void* context, FuriString* output) {
furi_string_cat_printf(
output,
"%s\r\n"
"ID: 0x%04lX, ch: %d, bat: %d, rc: 0x%02lX\r\n",
"ID: 0x%04lX, ch: %d,\r\nbat: %d, rc: 0x%02lX\r\n",
instance->generic.protocol_name,
instance->generic.id,
instance->generic.channel,
@@ -358,8 +358,9 @@ const SubGhzProtocolDecoder ws_protocol_oregon3_decoder = {
const SubGhzProtocol ws_protocol_oregon3 = {
.name = WS_PROTOCOL_OREGON3_NAME,
.type = SubGhzProtocolWeatherStation,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Weather | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save,
.decoder = &ws_protocol_oregon3_decoder,
};

View File

@@ -30,9 +30,9 @@
* - u: unknown;
* - b: battery low; flag to indicate low battery voltage
* - s: temperature sign
* - T: BCD, Temperature; in °C * 10
* - t: BCD, Temperature; in °C * 1
* - z: BCD, Temperature; in °C * 0.1
* - T: BCD, Temperature; in <EFBFBD>C * 10
* - t: BCD, Temperature; in <EFBFBD>C * 1
* - z: BCD, Temperature; in <EFBFBD>C * 0.1
* - c: Channel 00=CH1, 01=CH2, 10=CH3
*
*/
@@ -93,9 +93,10 @@ const SubGhzProtocolEncoder ws_protocol_oregon_v1_encoder = {
const SubGhzProtocol ws_protocol_oregon_v1 = {
.name = WS_PROTOCOL_OREGON_V1_NAME,
.type = SubGhzProtocolWeatherStation,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Weather |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save,
.decoder = &ws_protocol_oregon_v1_decoder,
.encoder = &ws_protocol_oregon_v1_encoder,
@@ -303,9 +304,9 @@ SubGhzProtocolStatus
void ws_protocol_decoder_oregon_v1_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderOregon_V1* instance = context;
furi_string_printf(
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"%s\r\n%dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%3.1f C Hum:%d%%",

View File

@@ -1,7 +1,6 @@
#include "pcsg_generic.h"
#include <lib/toolbox/stream/stream.h>
#include <lib/flipper_format/flipper_format_i.h>
#include "../helpers/pocsag_pager_types.h"
#define TAG "PCSGBlockGeneric"

View File

@@ -13,6 +13,9 @@
extern "C" {
#endif
#define PCSG_KEY_FILE_VERSION 1
#define PCSG_KEY_FILE_TYPE "Flipper SubGhz Key File"
typedef struct PCSGBlockGeneric PCSGBlockGeneric;
struct PCSGBlockGeneric {

View File

@@ -364,6 +364,14 @@ const SubGhzProtocolDecoder subghz_protocol_pocsag_decoder = {
.get_string = subhz_protocol_decoder_pocsag_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_pocsag_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol subghz_protocol_pocsag = {
.name = SUBGHZ_PROTOCOL_POCSAG_NAME,
.type = SubGhzProtocolTypeStatic,
@@ -371,4 +379,5 @@ const SubGhzProtocol subghz_protocol_pocsag = {
SubGhzProtocolFlag_Load,
.decoder = &subghz_protocol_pocsag_decoder,
.encoder = &subghz_protocol_pocsag_encoder,
};

View File

@@ -42,6 +42,26 @@ const SubGhzProtocol* subghz_protocol_registry_items[] = {
&subghz_protocol_dooya,
&subghz_protocol_alutech_at_4n,
&subghz_protocol_kinggates_stylo_4k,
&ws_protocol_infactory,
&ws_protocol_thermopro_tx4,
&ws_protocol_nexus_th,
&ws_protocol_gt_wt_02,
&ws_protocol_gt_wt_03,
&ws_protocol_acurite_606tx,
&ws_protocol_acurite_609txc,
&ws_protocol_lacrosse_tx,
&ws_protocol_lacrosse_tx141thbv2,
&ws_protocol_oregon2,
&ws_protocol_oregon3,
&ws_protocol_acurite_592txr,
&ws_protocol_ambient_weather,
&ws_protocol_auriol_th,
&ws_protocol_oregon_v1,
&ws_protocol_tx_8300,
&ws_protocol_wendox_w6726,
&ws_protocol_auriol_ahfl,
&subghz_protocol_pocsag,
&tpms_protocol_schrader_gg4,
&subghz_protocol_bin_raw,
};

View File

@@ -43,4 +43,24 @@
#include "dooya.h"
#include "alutech_at_4n.h"
#include "kinggates_stylo_4k.h"
#include "infactory.h"
#include "thermopro_tx4.h"
#include "nexus_th.h"
#include "gt_wt_02.h"
#include "gt_wt_03.h"
#include "acurite_606tx.h"
#include "acurite_609txc.h"
#include "lacrosse_tx.h"
#include "lacrosse_tx141thbv2.h"
#include "oregon2.h"
#include "oregon3.h"
#include "acurite_592txr.h"
#include "ambient_weather.h"
#include "auriol_hg0601a.h"
#include "oregon_v1.h"
#include "tx_8300.h"
#include "wendox_w6726.h"
#include "auriol_ahfl.h"
#include "pocsag.h"
#include "schrader_gg4.h"
#include "bin_raw.h"

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