Merge commit '48db77f307c2b998a34e99317e7a8add0c9e7d18' into mntm-dev

This commit is contained in:
WillyJL
2026-02-28 20:35:55 +01:00
16 changed files with 226 additions and 64 deletions
+2
View File
@@ -15,6 +15,7 @@
- UL: Add 390MHz and 430.5MHz to default hopper list (6 elements like in OFW) (works well with Hopper RSSI level set for your enviroment) (by @xMasterX)
- UL: Add signals button editor and real remote simulation (full signal transmit with just one click) (by @Dmitry422)
- UL: KeeLoq add counter mode 7 (sends 7 signals increasing counter with 0x3333 steps) - may bypass counter on some receivers! (by @xMasterX)
- UL: TX Power setting (by @LeeroysHub)
- UL: JS: Add IR capabilities to the JS engine (by @LuisMayo)
- UL: Docs: Add [full list of supported SubGHz protocols](https://github.com/Next-Flip/Momentum-Firmware/blob/dev/documentation/SubGHzSupportedSystems.md) and their frequencies/modulations that can be used for reading remotes (by @xMasterX)
@@ -55,6 +56,7 @@
- Fix sending 32+ byte ISO 15693-3 commands (by @WillyJL)
- Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (#501 by @WillyJL & aaronjamt)
- UL: Fix LED not blinking at SLIX unlock (by @xMasterX)
- UL: Settings: Storage settings exit scenes properly if used via favourites (by @xMasterX)
- UL: UI: Some small changes (by @xMasterX)
### Removed:
+43 -9
View File
@@ -104,6 +104,7 @@ void subghz_txrx_set_preset(
size_t preset_data_size) {
furi_assert(instance);
furi_string_set(instance->preset->name, preset_name);
SubGhzRadioPreset* preset = instance->preset;
preset->frequency = frequency;
preset->latitude = latitude;
@@ -112,6 +113,32 @@ void subghz_txrx_set_preset(
preset->data_size = preset_data_size;
}
uint8_t*
subghz_txrx_set_tx_power(uint8_t* preset_data, size_t preset_data_size, uint8_t tx_power) {
#define TX_POWER_OFFSET 7
#define TX_PRESET_POWER_COUNT 11
const uint8_t tx_power_value[TX_PRESET_POWER_COUNT] = {
0,
0xC0,
0xC5,
0xCD,
0x86,
0x50,
0x37,
0x26,
0x1D,
0x17,
0x03,
};
//Set the TX Power Here in the CC1101 register...
if(tx_power)
preset_data[preset_data_size - TX_POWER_OFFSET] = (uint8_t)tx_power_value[tx_power];
//Pass back the preset_so we can call one liners.
return preset_data;
}
const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset) {
UNUSED(instance);
const char* preset_name = "";
@@ -686,22 +713,29 @@ void subghz_txrx_set_default_preset(SubGhzTxRx* instance, uint32_t frequency) {
subghz_txrx_set_preset(instance, default_modulation, frequency, NAN, NAN, NULL, 0);
}
const char*
subghz_txrx_set_preset_internal(SubGhzTxRx* instance, uint32_t frequency, uint8_t index) {
const char* subghz_txrx_set_preset_internal(
SubGhzTxRx* instance,
uint32_t frequency,
uint8_t index,
uint8_t tx_power) {
furi_assert(instance);
//Grab the prset name.
SubGhzSetting* setting = subghz_txrx_get_setting(instance);
const char* preset_name = subghz_setting_get_preset_name(setting, index);
subghz_setting_set_default_frequency(setting, frequency);
subghz_txrx_set_preset(
instance,
preset_name,
frequency,
//Get the preset data now so we can set TX power.
uint8_t* preset_data = subghz_setting_get_preset_data(setting, index);
size_t preset_data_size = subghz_setting_get_preset_data_size(setting, index);
//Edit TX power, if necessary.
subghz_txrx_set_tx_power(preset_data, preset_data_size, tx_power);
//Set the Updated Preset.
subghz_txrx_set_preset(instance, preset_name, frequency,
NAN,
NAN,
subghz_setting_get_preset_data(setting, index),
subghz_setting_get_preset_data_size(setting, index));
NAN, preset_data, preset_data_size);
return preset_name;
}
+15 -2
View File
@@ -61,6 +61,15 @@ void subghz_txrx_set_preset(
uint8_t* preset_data,
size_t preset_data_size);
/**
* Set TX Power
*
* @param preset_data Data of preset
* @param preset_data_size Size of preset data
* @param tx_power Menu Index of TX Power Setting. (Saves iterating in Config enter)
*/
uint8_t* subghz_txrx_set_tx_power(uint8_t* preset_data, size_t preset_data_size, uint8_t tx_power);
/**
* Get name of preset
*
@@ -390,7 +399,11 @@ void subghz_txrx_set_default_preset(SubGhzTxRx* instance, uint32_t frequency);
* @param instance - instance Pointer to a SubGhzTxRx
* @param frequency - frequency of new preset
* @param index - index of preset taken from SubGhzSetting
* @param tx_power - index of TX Power menu index option to use.
* @return const char* - name of preset
*/
const char*
subghz_txrx_set_preset_internal(SubGhzTxRx* instance, uint32_t frequency, uint8_t index);
const char* subghz_txrx_set_preset_internal(
SubGhzTxRx* instance,
uint32_t frequency,
uint8_t index,
uint8_t tx_power);
@@ -76,6 +76,22 @@ const int32_t debug_counter_val[DEBUG_COUNTER_COUNT] = {
-50,
};
//TX Power
#define TX_POWER_COUNT 11
const char* const tx_power_text[TX_POWER_COUNT] = {
"Preset",
"12dBm",
"10dBm",
"7dBm",
"5dBm",
"0dBm",
"-6dBm",
"-10dBm",
"-15dBm",
"-20dBm",
"-30dBm",
};
static void subghz_scene_radio_settings_set_device(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
@@ -90,6 +106,20 @@ static void subghz_scene_radio_settings_set_device(VariableItem* item) {
subghz_txrx_radio_device_set(subghz->txrx, radio_device_value[index]);
}
static void subghz_scene_radio_settings_set_tx_power(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
//Update the Menu Item on screen
variable_item_set_current_value_text(item, tx_power_text[index]);
//Set TX power and remember setting
subghz->last_settings->tx_power = subghz->tx_power = index;
//Save the settings now, this is the convention here!
subghz_last_settings_save(subghz->last_settings);
}
static void subghz_scene_receiver_config_set_debug_pin(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
@@ -175,6 +205,18 @@ void subghz_scene_radio_settings_on_enter(void* context) {
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, radio_device_text[value_index]);
//Add TX Power
item = variable_item_list_add(
subghz->variable_item_list,
"TX Power",
TX_POWER_COUNT,
subghz_scene_radio_settings_set_tx_power,
subghz);
value_index = subghz->tx_power;
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, tx_power_text[value_index]);
item = variable_item_list_add(
variable_item_list,
"GPS Baudrate",
@@ -111,7 +111,8 @@ void subghz_scene_read_raw_on_enter(void* context) {
subghz_txrx_set_preset_internal(
subghz->txrx,
subghz->last_settings->frequency,
subghz->last_settings->preset_index);
subghz->last_settings->preset_index,
subghz->last_settings->tx_power);
}
}
subghz_scene_read_raw_update_statusbar(subghz);
@@ -255,12 +255,16 @@ void subghz_scene_receiver_on_enter(void* context) {
if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) {
subghz_txrx_set_preset_internal(
subghz->txrx, subghz->last_settings->frequency, subghz->last_settings->preset_index);
subghz->txrx,
subghz->last_settings->frequency,
subghz->last_settings->preset_index,
subghz->last_settings->tx_power);
subghz->filter = subghz->last_settings->filter;
subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
subghz->ignore_filter = subghz->last_settings->ignore_filter;
subghz_txrx_receiver_set_ignore_filter(subghz->txrx, subghz->ignore_filter);
subghz->tx_power = subghz->last_settings->tx_power;
subghz_history_reset(history);
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart);
@@ -207,6 +207,11 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
frequency / 1000000,
(frequency % 1000000) / 10000);
variable_item_set_current_value_text(item, text_buf);
//Set TX Power
subghz_txrx_set_tx_power(preset.data, preset.data_size, subghz->tx_power);
//Set the preset now.
subghz_txrx_set_preset(
subghz->txrx,
furi_string_get_cstr(preset.name),
@@ -235,14 +240,16 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
variable_item_set_current_value_text(item, preset_name);
//subghz->last_settings->preset = index;
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
uint8_t* preset_data = subghz_setting_get_preset_data(setting, index);
size_t preset_data_size = subghz_setting_get_preset_data_size(setting, index);
//Edit TX power, if necessary.
subghz_txrx_set_tx_power(preset_data, preset_data_size, subghz->tx_power);
subghz_txrx_set_preset(
subghz->txrx,
preset_name,
preset.frequency,
subghz->txrx, preset_name, preset.frequency,
NAN,
NAN,
subghz_setting_get_preset_data(setting, index),
subghz_setting_get_preset_data_size(setting, index));
NAN,preset_data, preset_data_size);
subghz->last_settings->preset_index = index;
}
@@ -268,6 +275,9 @@ static void subghz_scene_receiver_config_set_hopping(VariableItem* item) {
(frequency % 1000000) / 10000);
variable_item_set_current_value_text(frequency_item, text_buf);
//Edit TX power, if necessary.
subghz_txrx_set_tx_power(preset.data, preset.data_size, subghz->tx_power);
// Maybe better add one more function with only with the frequency argument?
subghz_txrx_set_preset(
subghz->txrx,
@@ -453,7 +463,8 @@ static void subghz_scene_receiver_config_var_list_enter_callback(void* context,
subghz_txrx_set_preset_internal(
subghz->txrx,
SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY,
SUBGHZ_LAST_SETTING_DEFAULT_PRESET);
SUBGHZ_LAST_SETTING_DEFAULT_PRESET,
subghz->tx_power);
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
@@ -477,6 +488,7 @@ static void subghz_scene_receiver_config_var_list_enter_callback(void* context,
subghz->repeater = SubGhzRepeaterStateOff;
subghz->last_settings->delete_old_signals = false;
subghz->last_settings->autosave = false;
subghz->last_settings->tx_power = subghz->tx_power = 0;
subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[default_index]);
subghz->last_settings->enable_sound = false;
@@ -39,6 +39,10 @@ static bool subghz_scene_receiver_info_update_parser(void* context) {
SubGhzRadioPreset* preset =
subghz_history_get_radio_preset(subghz->history, subghz->idx_menu_chosen);
//Edit TX power, if necessary.
subghz_txrx_set_tx_power(preset->data, preset->data_size, subghz->tx_power);
subghz_txrx_set_preset(
subghz->txrx,
furi_string_get_cstr(preset->name),
@@ -1,6 +1,8 @@
#include "../subghz_i.h"
#include <lib/subghz/blocks/custom_btn.h>
#include <lib/subghz/blocks/generic.h>
#include "applications/main/subghz/helpers/subghz_txrx_i.h"
typedef enum {
SubGhzRpcStateIdle,
@@ -52,9 +54,13 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
} else if(event.event == SubGhzCustomEventSceneRpcButtonPress) {
bool result = false;
if(state == SubGhzRpcStateLoaded) {
// START endless TX until user release button
// variable used in protocol yield for endless TX
subghz_block_generic_global.endless_tx = true;
switch(
subghz_txrx_tx_start(subghz->txrx, subghz_txrx_get_fff_data(subghz->txrx))) {
case SubGhzTxRxStartTxStateErrorOnlyRx:
subghz_block_generic_global.endless_tx = false;
rpc_system_app_set_error_code(
subghz->rpc_ctx, RpcAppSystemErrorCodeRegionLock);
rpc_system_app_set_error_text(
@@ -62,6 +68,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
"Transmission on this frequency is restricted in your settings");
break;
case SubGhzTxRxStartTxStateErrorParserOthers:
subghz_block_generic_global.endless_tx = false;
rpc_system_app_set_error_code(
subghz->rpc_ctx, RpcAppSystemErrorCodeInternalParse);
rpc_system_app_set_error_text(
@@ -80,50 +87,53 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
} else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) {
bool result = false;
if(state == SubGhzRpcStateTx) {
subghz_txrx_stop(subghz->txrx);
subghz_blink_stop(subghz);
// user release button
// set endless TX to OFF and switch off TX in section event.type == SceneManagerEventTypeTick
subghz_block_generic_global.endless_tx = false;
result = true;
}
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle);
// scene_manager_set_scene_state(
// subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle);
rpc_system_app_confirm(subghz->rpc_ctx, result);
} else if(event.event == SubGhzCustomEventSceneRpcButtonPressRelease) {
bool result = false;
if(state == SubGhzRpcStateLoaded) {
switch(
subghz_txrx_tx_start(subghz->txrx, subghz_txrx_get_fff_data(subghz->txrx))) {
case SubGhzTxRxStartTxStateErrorOnlyRx:
rpc_system_app_set_error_code(
subghz->rpc_ctx, RpcAppSystemErrorCodeRegionLock);
rpc_system_app_set_error_text(
subghz->rpc_ctx,
"Transmission on this frequency is restricted in your region");
break;
case SubGhzTxRxStartTxStateErrorParserOthers:
rpc_system_app_set_error_code(
subghz->rpc_ctx, RpcAppSystemErrorCodeInternalParse);
rpc_system_app_set_error_text(
subghz->rpc_ctx, "Error in protocol parameters description");
break;
default: //if(SubGhzTxRxStartTxStateOk)
result = true;
subghz_blink_start(subghz);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateTx);
break;
}
}
// USELESS PART
// } else if(event.event == SubGhzCustomEventSceneRpcButtonPressRelease) {
// bool result = false;
// if(state == SubGhzRpcStateLoaded) {
// switch(
// subghz_txrx_tx_start(subghz->txrx, subghz_txrx_get_fff_data(subghz->txrx))) {
// case SubGhzTxRxStartTxStateErrorOnlyRx:
// rpc_system_app_set_error_code(
// subghz->rpc_ctx, RpcAppSystemErrorCodeRegionLock);
// rpc_system_app_set_error_text(
// subghz->rpc_ctx,
// "Transmission on this frequency is restricted in your region");
// break;
// case SubGhzTxRxStartTxStateErrorParserOthers:
// rpc_system_app_set_error_code(
// subghz->rpc_ctx, RpcAppSystemErrorCodeInternalParse);
// rpc_system_app_set_error_text(
// subghz->rpc_ctx, "Error in protocol parameters description");
// break;
// Stop transmission
if(state == SubGhzRpcStateTx) {
subghz_txrx_stop(subghz->txrx);
subghz_blink_stop(subghz);
result = true;
}
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle);
rpc_system_app_confirm(subghz->rpc_ctx, result);
// default: //if(SubGhzTxRxStartTxStateOk)
// result = true;
// subghz_blink_start(subghz);
// scene_manager_set_scene_state(
// subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateTx);
// break;
// }
// }
// // Stop transmission
// if(state == SubGhzRpcStateTx) {
// subghz_txrx_stop(subghz->txrx);
// subghz_blink_stop(subghz);
// result = true;
// }
// scene_manager_set_scene_state(
// subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle);
// rpc_system_app_confirm(subghz->rpc_ctx, result);
} else if(event.event == SubGhzCustomEventSceneRpcLoad) {
bool result = false;
if(state == SubGhzRpcStateIdle) {
@@ -139,6 +149,19 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
}
rpc_system_app_confirm(subghz->rpc_ctx, result);
}
} else if(event.type == SceneManagerEventTypeTick) {
// if hardware TX finished then stop TX correctly
if(subghz_devices_is_async_complete_tx(subghz->txrx->radio_device)) {
bool result = false;
if(state == SubGhzRpcStateTx) {
subghz_txrx_stop(subghz->txrx);
subghz_blink_stop(subghz);
result = true;
}
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle);
rpc_system_app_confirm(subghz->rpc_ctx, result);
}
}
return consumed;
}
@@ -39,6 +39,7 @@ bool subghz_scene_transmitter_update_data_show(void* context) {
furi_string_get_cstr(frequency_str),
furi_string_get_cstr(modulation_str),
subghz_txrx_protocol_is_transmittable(subghz->txrx, false));
ret = true;
}
furi_string_free(frequency_str);
+7 -1
View File
@@ -229,7 +229,10 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
}
subghz_txrx_set_preset_internal(
subghz->txrx, subghz->last_settings->frequency, subghz->last_settings->preset_index);
subghz->txrx,
subghz->last_settings->frequency,
subghz->last_settings->preset_index,
subghz->tx_power);
subghz->history = subghz_history_alloc();
}
@@ -241,11 +244,14 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
subghz->remove_duplicates = subghz->last_settings->remove_duplicates;
subghz->ignore_filter = subghz->last_settings->ignore_filter;
subghz->filter = subghz->last_settings->filter;
subghz->tx_power = subghz->last_settings->tx_power;
} else {
subghz->filter = SubGhzProtocolFlag_Decodable;
subghz->ignore_filter = 0x0;
subghz->remove_duplicates = false;
subghz->tx_power = 0;
}
subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
subghz_txrx_receiver_set_ignore_filter(subghz->txrx, subghz->ignore_filter);
subghz_txrx_set_need_save_callback(subghz->txrx, subghz_save_to_file, subghz);
+9 -2
View File
@@ -183,14 +183,21 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
size_t preset_index =
subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(temp_str));
//Edit TX power, if necessary.
uint8_t* preset_data = subghz_setting_get_preset_data(setting, preset_index);
size_t preset_data_size = subghz_setting_get_preset_data_size(setting, preset_index);
subghz_txrx_set_tx_power(preset_data, preset_data_size, subghz->tx_power);
//Set the Updated Preset.
subghz_txrx_set_preset(
subghz->txrx,
furi_string_get_cstr(temp_str),
temp_data32,
temp_lat,
temp_lon,
subghz_setting_get_preset_data(setting, preset_index),
subghz_setting_get_preset_data_size(setting, preset_index));
preset_data,
preset_data_size);
//Load protocol
if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
+1
View File
@@ -103,6 +103,7 @@ struct SubGhz {
bool fav_timeout;
FuriTimer* timer;
uint8_t tx_power;
void* rpc_ctx;
};
@@ -24,6 +24,7 @@
#define SUBGHZ_LAST_SETTING_FIELD_ENABLE_SOUND "Sound"
#define SUBGHZ_LAST_SETTING_FIELD_AUTOSAVE "Autosave"
#define SUBGHZ_LAST_SETTING_FIELD_HOPPING_THRESHOLD "HoppingThreshold"
#define SUBGHZ_LAST_SETTING_FIELD_TX_POWER "TXPower"
SubGhzLastSettings* subghz_last_settings_alloc(void) {
SubGhzLastSettings* instance = malloc(sizeof(SubGhzLastSettings));
@@ -162,6 +163,12 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
1)) {
flipper_format_rewind(fff_data_file);
}
uint32_t tx_power = 0;
if(!flipper_format_read_uint32(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_TX_POWER, &tx_power, 1)) {
flipper_format_rewind(fff_data_file);
}
instance->tx_power = (uint8_t)(tx_power & 0xFF);
} while(0);
} else {
FURI_LOG_E(TAG, "Error open file %s", SUBGHZ_LAST_SETTINGS_PATH);
@@ -281,6 +288,10 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) {
1)) {
break;
}
uint32_t tx_power = instance->tx_power;
if(!flipper_format_write_uint32(file, SUBGHZ_LAST_SETTING_FIELD_TX_POWER, &tx_power, 1)) {
break;
}
saved = true;
} while(0);
@@ -31,6 +31,7 @@ typedef struct {
bool enable_sound;
bool autosave;
float hopping_threshold;
uint8_t tx_power;
} SubGhzLastSettings;
SubGhzLastSettings* subghz_last_settings_alloc(void);
+2 -2
View File
@@ -269,7 +269,7 @@ void subghz_protocol_decoder_power_smart_reset(void* context) {
NULL);
}
bool subghz_protocol_power_smart_chek_valid(uint64_t packet) {
bool subghz_protocol_power_smart_check_valid(uint64_t packet) {
uint32_t data_1 = (uint32_t)((packet >> 40) & 0xFFFF);
uint32_t data_2 = (uint32_t)((~packet >> 8) & 0xFFFF);
uint8_t data_3 = (uint8_t)(packet >> 32) & 0xFF;
@@ -313,7 +313,7 @@ void subghz_protocol_decoder_power_smart_feed(
}
if((instance->decoder.decode_data & POWER_SMART_PACKET_HEADER_MASK) ==
POWER_SMART_PACKET_HEADER) {
if(subghz_protocol_power_smart_chek_valid(instance->decoder.decode_data)) {
if(subghz_protocol_power_smart_check_valid(instance->decoder.decode_data)) {
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit =
subghz_protocol_power_smart_const.min_count_bit_for_found;