Merge branch 'dev' of https://github.com/DarkFlippers/unleashed-firmware into xfw-dev --nobuild

This commit is contained in:
Willy-JL
2023-09-16 17:46:39 +02:00
55 changed files with 1885 additions and 1569 deletions
@@ -77,6 +77,7 @@ typedef enum {
SubGhzCustomEventSceneAnalyzerLock,
SubGhzCustomEventSceneAnalyzerUnlock,
SubGhzCustomEventSceneSettingLock,
SubGhzCustomEventSceneSettingResetToDefault,
SubGhzCustomEventSceneExit,
SubGhzCustomEventSceneStay,
+41 -13
View File
@@ -3,10 +3,9 @@
#include <lib/subghz/protocols/protocol_items.h>
#include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
#include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h>
#include <lib/subghz/blocks/custom_btn.h>
#define TAG "SubGhz"
#define TAG "SubGhzTxRx"
static void subghz_txrx_radio_device_power_on(SubGhzTxRx* instance) {
UNUSED(instance);
@@ -30,8 +29,7 @@ SubGhzTxRx* subghz_txrx_alloc() {
instance->preset = malloc(sizeof(SubGhzRadioPreset));
instance->preset->name = furi_string_alloc();
subghz_txrx_set_preset(
instance, "AM650", subghz_setting_get_default_frequency(instance->setting), NULL, 0);
subghz_txrx_set_default_preset(instance, 0);
instance->txrx_state = SubGhzTxRxStateSleep;
@@ -184,10 +182,11 @@ static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) {
static void subghz_txrx_idle(SubGhzTxRx* instance) {
furi_assert(instance);
furi_assert(instance->txrx_state != SubGhzTxRxStateSleep);
subghz_devices_idle(instance->radio_device);
subghz_txrx_speaker_off(instance);
instance->txrx_state = SubGhzTxRxStateIDLE;
if(instance->txrx_state != SubGhzTxRxStateSleep) {
subghz_devices_idle(instance->radio_device);
subghz_txrx_speaker_off(instance);
instance->txrx_state = SubGhzTxRxStateIDLE;
}
}
static void subghz_txrx_rx_end(SubGhzTxRx* instance) {
@@ -380,10 +379,11 @@ void subghz_txrx_hopper_update(SubGhzTxRx* instance) {
default:
break;
}
float rssi = -127.0f;
// Init value isn't using
// float rssi = -127.0f;
if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) {
// See RSSI Calculation timings in CC1101 17.3 RSSI
rssi = subghz_devices_get_rssi(instance->radio_device);
float rssi = subghz_devices_get_rssi(instance->radio_device);
// Stay if RSSI is high enough
if(rssi > -90.0f) {
@@ -404,7 +404,7 @@ void subghz_txrx_hopper_update(SubGhzTxRx* instance) {
if(instance->txrx_state == SubGhzTxRxStateRx) {
subghz_txrx_rx_end(instance);
};
}
if(instance->txrx_state == SubGhzTxRxStateIDLE) {
subghz_receiver_reset(instance->receiver);
instance->preset->frequency =
@@ -551,7 +551,7 @@ void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag fi
subghz_receiver_set_filter(instance->receiver, filter);
}
void subghz_txrx_set_rx_calback(
void subghz_txrx_set_rx_callback(
SubGhzTxRx* instance,
SubGhzReceiverCallback callback,
void* context) {
@@ -671,4 +671,32 @@ void subghz_txrx_reset_dynamic_and_custom_btns(SubGhzTxRx* instance) {
SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance) {
furi_assert(instance);
return instance->receiver;
}
}
void subghz_txrx_set_default_preset(SubGhzTxRx* instance, uint32_t frequency) {
furi_assert(instance);
const char* default_modulation = "AM650";
if(frequency == 0) {
frequency = subghz_setting_get_default_frequency(subghz_txrx_get_setting(instance));
}
subghz_txrx_set_preset(instance, default_modulation, frequency, NULL, 0);
}
const char*
subghz_txrx_set_preset_internal(SubGhzTxRx* instance, uint32_t frequency, uint8_t index) {
furi_assert(instance);
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,
subghz_setting_get_preset_data(setting, index),
subghz_setting_get_preset_data_size(setting, index));
return preset_name;
}
+21 -2
View File
@@ -274,7 +274,7 @@ void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag fi
* @param callback Callback for receive data
* @param context Context for callback
*/
void subghz_txrx_set_rx_calback(
void subghz_txrx_set_rx_callback(
SubGhzTxRx* instance,
SubGhzReceiverCallback callback,
void* context);
@@ -329,7 +329,7 @@ float subghz_txrx_radio_device_get_rssi(SubGhzTxRx* instance);
*/
const char* subghz_txrx_radio_device_get_name(SubGhzTxRx* instance);
/* Get get intelligence whether frequency the selected radio device to use
/* Get intelligence whether frequency the selected radio device to use
*
* @param instance Pointer to a SubGhzTxRx
* @return bool True if the frequency is valid
@@ -344,3 +344,22 @@ bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance);
void subghz_txrx_reset_dynamic_and_custom_btns(SubGhzTxRx* instance);
SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance); // TODO use only in DecodeRaw
/**
* @brief Set current preset AM650 without additional params
*
* @param instance - instance Pointer to a SubGhzTxRx
* @param frequency - frequency of preset, if pass 0 then taking default frequency 433.92MHz
*/
void subghz_txrx_set_default_preset(SubGhzTxRx* instance, uint32_t frequency);
/**
* @brief Set current preset by index
*
* @param instance - instance Pointer to a SubGhzTxRx
* @param frequency - frequency of new preset
* @param index - index of preset taken from SubGhzSetting
* @return const char* - name of preset
*/
const char*
subghz_txrx_set_preset_internal(SubGhzTxRx* instance, uint32_t frequency, uint8_t index);
@@ -1,8 +1,4 @@
#include "../subghz_i.h"
#include "../views/receiver.h"
#include <lib/subghz/protocols/raw.h>
#include <lib/subghz/subghz_file_encoder_worker.h>
#define TAG "SubGhzDecodeRaw"
#define SAMPLES_TO_READ_PER_TICK 400
@@ -21,13 +17,20 @@ static void subghz_scene_receiver_update_statusbar(void* context) {
subghz->subghz_receiver,
furi_string_get_cstr(frequency_str),
furi_string_get_cstr(modulation_str),
furi_string_get_cstr(history_stat_str));
furi_string_get_cstr(history_stat_str),
subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF,
READ_BIT(subghz->filter, SubGhzProtocolFlag_BinRAW) > 0);
furi_string_free(frequency_str);
furi_string_free(modulation_str);
} else {
subghz_view_receiver_add_data_statusbar(
subghz->subghz_receiver, furi_string_get_cstr(history_stat_str), "", "");
subghz->subghz_receiver,
furi_string_get_cstr(history_stat_str),
"",
"",
subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF,
READ_BIT(subghz->filter, SubGhzProtocolFlag_BinRAW) > 0);
}
furi_string_free(history_stat_str);
}
@@ -154,7 +157,7 @@ void subghz_scene_decode_raw_on_enter(void* context) {
subghz_view_receiver_set_callback(
subghz->subghz_receiver, subghz_scene_decode_raw_callback, subghz);
subghz_txrx_set_rx_calback(subghz->txrx, subghz_scene_add_to_history_callback, subghz);
subghz_txrx_set_rx_callback(subghz->txrx, subghz_scene_add_to_history_callback, subghz);
subghz_txrx_receiver_set_filter(subghz->txrx, SubGhzProtocolFlag_Decodable);
@@ -170,7 +173,7 @@ void subghz_scene_decode_raw_on_enter(void* context) {
} else {
//Load history to receiver
subghz_view_receiver_exit(subghz->subghz_receiver);
for(uint8_t i = 0; i < subghz_history_get_item(subghz->history); i++) {
for(uint16_t i = 0; i < subghz_history_get_item(subghz->history); i++) {
furi_string_reset(item_name);
furi_string_reset(item_time);
subghz_history_get_text_item_menu(subghz->history, item_name, i);
@@ -202,7 +205,7 @@ bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) {
subghz->scene_manager, SubGhzSceneDecodeRAW, SubGhzDecodeRawStateStart);
subghz->idx_menu_chosen = 0;
subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz);
subghz_txrx_set_rx_callback(subghz->txrx, NULL, subghz);
if(subghz_file_encoder_worker_is_running(subghz->decode_raw_file_worker_encoder)) {
subghz_file_encoder_worker_stop(subghz->decode_raw_file_worker_encoder);
@@ -1,5 +1,5 @@
#include "../subghz.h"
#include "../subghz_i.h"
#include "../helpers/subghz_custom_event.h"
void subghz_scene_delete_raw_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context);
@@ -60,6 +60,9 @@ bool subghz_scene_frequency_analyzer_on_event(void* context, SceneManagerEvent e
subghz_frequency_analyzer_get_frequency_to_save(subghz->subghz_frequency_analyzer);
if(frequency > 0) {
subghz->last_settings->frequency = frequency;
#ifdef FURI_DEBUG
subghz_last_settings_log(subghz->last_settings);
#endif
subghz_last_settings_save(subghz->last_settings);
}
@@ -104,8 +104,15 @@ void subghz_scene_read_raw_on_enter(void* context) {
if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateBack) {
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
#if SUBGHZ_LAST_SETTING_SAVE_PRESET
if(furi_string_empty(file_name)) {
subghz_txrx_set_preset_internal(
subghz->txrx,
subghz->last_settings->frequency,
subghz->last_settings->preset_index);
}
#endif
}
furi_string_free(file_name);
subghz_scene_read_raw_update_statusbar(subghz);
//set callback view raw
@@ -115,6 +122,8 @@ void subghz_scene_read_raw_on_enter(void* context) {
//set filter RAW feed
subghz_txrx_receiver_set_filter(subghz->txrx, SubGhzProtocolFlag_RAW);
furi_string_free(file_name);
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW);
// Start sending immediately with favorites
@@ -154,10 +163,9 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
} else {
//Restore default setting
if(subghz->raw_send_only) {
subghz_set_default_preset(subghz);
subghz_txrx_set_default_preset(subghz->txrx, 0);
} else {
subghz_txrx_set_preset(
subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0);
subghz_txrx_set_default_preset(subghz->txrx, subghz->last_settings->frequency);
}
if(!scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneSaved)) {
@@ -1,5 +1,4 @@
#include "../subghz_i.h"
#include "../views/receiver.h"
#include <dolphin/dolphin.h>
#include <lib/subghz/protocols/bin_raw.h>
@@ -70,13 +69,20 @@ static void subghz_scene_receiver_update_statusbar(void* context) {
subghz->subghz_receiver,
furi_string_get_cstr(frequency_str),
furi_string_get_cstr(modulation_str),
furi_string_get_cstr(history_stat_str));
furi_string_get_cstr(history_stat_str),
subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF,
READ_BIT(subghz->filter, SubGhzProtocolFlag_BinRAW) > 0);
furi_string_free(frequency_str);
furi_string_free(modulation_str);
} else {
subghz_view_receiver_add_data_statusbar(
subghz->subghz_receiver, furi_string_get_cstr(history_stat_str), "", "");
subghz->subghz_receiver,
furi_string_get_cstr(history_stat_str),
"",
"",
subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF,
READ_BIT(subghz->filter, SubGhzProtocolFlag_BinRAW) > 0);
subghz->state_notifications = SubGhzNotificationStateIDLE;
}
furi_string_free(history_stat_str);
@@ -142,7 +148,17 @@ void subghz_scene_receiver_on_enter(void* context) {
FuriString* item_time = furi_string_alloc();
if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) {
subghz_txrx_set_preset(subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0);
#if SUBGHZ_LAST_SETTING_SAVE_PRESET
subghz_txrx_set_preset_internal(
subghz->txrx, subghz->last_settings->frequency, subghz->last_settings->preset_index);
#else
subghz_txrx_set_default_preset(subghz->txrx, subghz->last_settings->frequency);
#endif
subghz->filter = subghz->last_settings->filter;
subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
subghz->ignore_filter = subghz->last_settings->ignore_filter;
subghz_history_reset(history);
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart);
subghz->idx_menu_chosen = 0;
@@ -151,9 +167,9 @@ void subghz_scene_receiver_on_enter(void* context) {
subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz_is_locked(subghz));
subghz_view_receiver_set_mode(subghz->subghz_receiver, SubGhzViewReceiverModeLive);
//Load history to receiver
// Load history to receiver
subghz_view_receiver_exit(subghz->subghz_receiver);
for(uint8_t i = 0; i < subghz_history_get_item(history); i++) {
for(uint16_t i = 0; i < subghz_history_get_item(history); i++) {
furi_string_reset(item_name);
furi_string_reset(item_time);
subghz_history_get_text_item_menu(history, item_name, i);
@@ -167,13 +183,22 @@ void subghz_scene_receiver_on_enter(void* context) {
}
furi_string_free(item_name);
furi_string_free(item_time);
subghz_view_receiver_set_callback(
subghz->subghz_receiver, subghz_scene_receiver_callback, subghz);
subghz_txrx_set_rx_calback(subghz->txrx, subghz_scene_add_to_history_callback, subghz);
subghz_txrx_set_rx_callback(subghz->txrx, subghz_scene_add_to_history_callback, subghz);
if(!subghz_history_get_text_space_left(subghz->history, NULL)) {
subghz->state_notifications = SubGhzNotificationStateRx;
}
// Check if hopping was enabled
if(subghz->last_settings->enable_hopping) {
subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateRunning);
} else {
subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF);
}
subghz_txrx_rx_start(subghz->txrx);
subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen);
@@ -199,15 +224,14 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
subghz->state_notifications = SubGhzNotificationStateIDLE;
subghz_txrx_stop(subghz->txrx);
subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF);
subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz);
subghz_txrx_set_rx_callback(subghz->txrx, NULL, subghz);
if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) {
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
} else {
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
subghz_txrx_set_preset(
subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0);
subghz_txrx_set_default_preset(subghz->txrx, subghz->last_settings->frequency);
scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart);
}
@@ -1,6 +1,8 @@
#include "../subghz_i.h"
#include <lib/toolbox/value_index.h>
#define TAG "SubGhzSceneReceiverConfig"
enum SubGhzSettingIndex {
SubGhzSettingIndexFrequency,
SubGhzSettingIndexHopping,
@@ -9,7 +11,9 @@ enum SubGhzSettingIndex {
SubGhzSettingIndexIgnoreStarline,
SubGhzSettingIndexIgnoreCars,
SubGhzSettingIndexIgnoreMagellan,
SubGhzSettingIndexIgnorePrinceton,
SubGhzSettingIndexSound,
SubGhzSettingIndexResetToDefault,
SubGhzSettingIndexLock,
SubGhzSettingIndexRAWThresholdRSSI,
};
@@ -43,47 +47,51 @@ const float raw_threshold_rssi_value[RAW_THRESHOLD_RSSI_COUNT] = {
-40.0f,
};
#define HOPPING_COUNT 2
const char* const hopping_text[HOPPING_COUNT] = {
"OFF",
"ON",
};
const uint32_t hopping_value[HOPPING_COUNT] = {
#define COMBO_BOX_COUNT 2
const uint32_t hopping_value[COMBO_BOX_COUNT] = {
SubGhzHopperStateOFF,
SubGhzHopperStateRunning,
};
#define SPEAKER_COUNT 2
const char* const speaker_text[SPEAKER_COUNT] = {
"OFF",
"ON",
};
const uint32_t speaker_value[SPEAKER_COUNT] = {
const uint32_t speaker_value[COMBO_BOX_COUNT] = {
SubGhzSpeakerStateShutdown,
SubGhzSpeakerStateEnable,
};
#define BIN_RAW_COUNT 2
const char* const bin_raw_text[BIN_RAW_COUNT] = {
"OFF",
"ON",
};
const uint32_t bin_raw_value[BIN_RAW_COUNT] = {
const uint32_t bin_raw_value[COMBO_BOX_COUNT] = {
SubGhzProtocolFlag_Decodable,
SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_BinRAW,
};
#define PROTOCOL_IGNORE_COUNT 2
const char* const protocol_ignore_text[PROTOCOL_IGNORE_COUNT] = {
const char* const combobox_text[COMBO_BOX_COUNT] = {
"OFF",
"ON",
};
static void
subghz_scene_receiver_config_set_ignore_filter(VariableItem* item, SubGhzProtocolFlag filter) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, combobox_text[index]);
if(index == 0) {
CLEAR_BIT(subghz->ignore_filter, filter);
} else {
SET_BIT(subghz->ignore_filter, filter);
}
subghz->last_settings->ignore_filter = subghz->ignore_filter;
}
uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
furi_assert(context);
SubGhz* subghz = context;
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
uint8_t index = 0;
for(uint8_t i = 0; i < subghz_setting_get_frequency_count(setting); i++) {
for(size_t i = 0; i < subghz_setting_get_frequency_count(setting); i++) {
if(value == subghz_setting_get_frequency(setting, i)) {
index = i;
break;
@@ -100,7 +108,7 @@ uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void*
uint8_t index = 0;
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
for(uint8_t i = 0; i < subghz_setting_get_preset_count(setting); i++) {
for(size_t i = 0; i < subghz_setting_get_preset_count(setting); i++) {
if(!strcmp(subghz_setting_get_preset_name(setting, i), preset_name)) {
index = i;
break;
@@ -111,23 +119,18 @@ uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void*
return index;
}
uint8_t subghz_scene_receiver_config_hopper_value_index(
const uint32_t value,
const uint32_t values[],
uint8_t values_count,
void* context) {
SubGhzHopperState subghz_scene_receiver_config_hopper_value_index(void* context) {
furi_assert(context);
UNUSED(values_count);
SubGhz* subghz = context;
if(value == values[0]) {
return 0;
if(subghz_txrx_hopper_get_state(subghz->txrx) == SubGhzHopperStateOFF) {
return SubGhzHopperStateOFF;
} else {
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig),
" -----");
return 1;
return SubGhzHopperStateRunning;
}
}
@@ -180,17 +183,19 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
preset.frequency,
subghz_setting_get_preset_data(setting, index),
subghz_setting_get_preset_data_size(setting, index));
subghz->last_settings->preset_index = index;
}
static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
SubGhzHopperState index = variable_item_get_current_value_index(item);
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
VariableItem* frequency_item = (VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig);
variable_item_set_current_value_text(item, hopping_text[index]);
if(hopping_value[index] == SubGhzHopperStateOFF) {
variable_item_set_current_value_text(item, combobox_text[(uint8_t)index]);
if(index == SubGhzHopperStateOFF) {
char text_buf[10] = {0};
uint32_t frequency = subghz_setting_get_default_frequency(setting);
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
@@ -203,6 +208,7 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item)
(frequency % 1000000) / 10000);
variable_item_set_current_value_text(frequency_item, text_buf);
// Maybe better add one more function with only with the frequency argument?
subghz_txrx_set_preset(
subghz->txrx,
furi_string_get_cstr(preset.name),
@@ -216,15 +222,15 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item)
variable_item_set_current_value_index(
frequency_item, subghz_setting_get_frequency_default_index(setting));
}
subghz_txrx_hopper_set_state(subghz->txrx, hopping_value[index]);
subghz->last_settings->enable_hopping = index != SubGhzHopperStateOFF;
subghz_txrx_hopper_set_state(subghz->txrx, index);
}
static void subghz_scene_receiver_config_set_speaker(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, speaker_text[index]);
variable_item_set_current_value_text(item, combobox_text[index]);
subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[index]);
}
@@ -232,9 +238,12 @@ static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, bin_raw_text[index]);
variable_item_set_current_value_text(item, combobox_text[index]);
subghz->filter = bin_raw_value[index];
subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
// We can set here, but during subghz_last_settings_save filter was changed to ignore BinRAW
subghz->last_settings->filter = subghz->filter;
}
static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) {
@@ -243,21 +252,10 @@ static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* it
variable_item_set_current_value_text(item, raw_threshold_rssi_text[index]);
subghz_threshold_rssi_set(subghz->threshold_rssi, raw_threshold_rssi_value[index]);
subghz->last_settings->rssi = raw_threshold_rssi_value[index];
}
static inline void
subghz_scene_receiver_config_set_ignore_filter(VariableItem* item, SubGhzProtocolFlag filter) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, protocol_ignore_text[index]);
if(index == 0) {
CLEAR_BIT(subghz->ignore_filter, filter);
} else {
SET_BIT(subghz->ignore_filter, filter);
}
}
static inline bool subghz_scene_receiver_config_ignore_filter_get_index(
SubGhzProtocolFlag filter,
SubGhzProtocolFlag flag) {
@@ -273,7 +271,11 @@ static void subghz_scene_receiver_config_set_auto_alarms(VariableItem* item) {
}
static void subghz_scene_receiver_config_set_magellan(VariableItem* item) {
subghz_scene_receiver_config_set_ignore_filter(item, SubGhzProtocolFlag_Magelan);
subghz_scene_receiver_config_set_ignore_filter(item, SubGhzProtocolFlag_Magellan);
}
static void subghz_scene_receiver_config_set_princeton(VariableItem* item) {
subghz_scene_receiver_config_set_ignore_filter(item, SubGhzProtocolFlag_Princeton);
}
static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) {
@@ -282,6 +284,46 @@ static void subghz_scene_receiver_config_var_list_enter_callback(void* context,
if(index == SubGhzSettingIndexLock) {
view_dispatcher_send_custom_event(
subghz->view_dispatcher, SubGhzCustomEventSceneSettingLock);
} else if(index == SubGhzSettingIndexResetToDefault) {
// Reset all values to default state!
#if SUBGHZ_LAST_SETTING_SAVE_PRESET
subghz_txrx_set_preset_internal(
subghz->txrx,
SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY,
SUBGHZ_LAST_SETTING_DEFAULT_PRESET);
#else
subghz_txrx_set_default_preset(subghz->txrx, SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY);
#endif
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
const char* preset_name = furi_string_get_cstr(preset.name);
int preset_index = subghz_setting_get_inx_preset_by_name(setting, preset_name);
const int default_index = 0;
subghz->last_settings->frequency = preset.frequency;
subghz->last_settings->preset_index = preset_index;
subghz_threshold_rssi_set(subghz->threshold_rssi, raw_threshold_rssi_value[default_index]);
subghz->filter = bin_raw_value[0];
subghz->ignore_filter = 0x00;
subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
subghz->last_settings->ignore_filter = subghz->ignore_filter;
subghz->last_settings->filter = subghz->filter;
subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[default_index]);
subghz_txrx_hopper_set_state(subghz->txrx, hopping_value[default_index]);
subghz->last_settings->enable_hopping = hopping_value[default_index];
variable_item_list_set_selected_item(subghz->variable_item_list, default_index);
variable_item_list_reset(subghz->variable_item_list);
#ifdef FURI_DEBUG
subghz_last_settings_log(subghz->last_settings);
#endif
subghz_last_settings_save(subghz->last_settings);
view_dispatcher_send_custom_event(
subghz->view_dispatcher, SubGhzCustomEventSceneSettingResetToDefault);
}
}
@@ -330,13 +372,13 @@ void subghz_scene_receiver_config_on_enter(void* context) {
item = variable_item_list_add(
subghz->variable_item_list,
"Hopping:",
HOPPING_COUNT,
COMBO_BOX_COUNT,
subghz_scene_receiver_config_set_hopping_running,
subghz);
value_index = subghz_scene_receiver_config_hopper_value_index(
subghz_txrx_hopper_get_state(subghz->txrx), hopping_value, HOPPING_COUNT, subghz);
value_index = subghz_scene_receiver_config_hopper_value_index(subghz);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, hopping_text[value_index]);
variable_item_set_current_value_text(item, combobox_text[value_index]);
}
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
@@ -344,12 +386,13 @@ void subghz_scene_receiver_config_on_enter(void* context) {
item = variable_item_list_add(
subghz->variable_item_list,
"Bin RAW:",
BIN_RAW_COUNT,
COMBO_BOX_COUNT,
subghz_scene_receiver_config_set_bin_raw,
subghz);
value_index = value_index_uint32(subghz->filter, bin_raw_value, BIN_RAW_COUNT);
value_index = value_index_uint32(subghz->filter, bin_raw_value, COMBO_BOX_COUNT);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, bin_raw_text[value_index]);
variable_item_set_current_value_text(item, combobox_text[value_index]);
}
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
@@ -357,52 +400,74 @@ void subghz_scene_receiver_config_on_enter(void* context) {
item = variable_item_list_add(
subghz->variable_item_list,
"Ignore Starline:",
PROTOCOL_IGNORE_COUNT,
COMBO_BOX_COUNT,
subghz_scene_receiver_config_set_starline,
subghz);
value_index = subghz_scene_receiver_config_ignore_filter_get_index(
subghz->ignore_filter, SubGhzProtocolFlag_StarLine);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, protocol_ignore_text[value_index]);
variable_item_set_current_value_text(item, combobox_text[value_index]);
item = variable_item_list_add(
subghz->variable_item_list,
"Ignore Cars:",
PROTOCOL_IGNORE_COUNT,
COMBO_BOX_COUNT,
subghz_scene_receiver_config_set_auto_alarms,
subghz);
value_index = subghz_scene_receiver_config_ignore_filter_get_index(
subghz->ignore_filter, SubGhzProtocolFlag_AutoAlarms);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, protocol_ignore_text[value_index]);
variable_item_set_current_value_text(item, combobox_text[value_index]);
item = variable_item_list_add(
subghz->variable_item_list,
"Ignore Magellan:",
PROTOCOL_IGNORE_COUNT,
COMBO_BOX_COUNT,
subghz_scene_receiver_config_set_magellan,
subghz);
value_index = subghz_scene_receiver_config_ignore_filter_get_index(
subghz->ignore_filter, SubGhzProtocolFlag_Magelan);
subghz->ignore_filter, SubGhzProtocolFlag_Magellan);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, protocol_ignore_text[value_index]);
variable_item_set_current_value_text(item, combobox_text[value_index]);
item = variable_item_list_add(
subghz->variable_item_list,
"Ignore Princeton:",
COMBO_BOX_COUNT,
subghz_scene_receiver_config_set_princeton,
subghz);
value_index = subghz_scene_receiver_config_ignore_filter_get_index(
subghz->ignore_filter, SubGhzProtocolFlag_Princeton);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, combobox_text[value_index]);
}
// Enable speaker, will send all incoming noises and signals to speaker so you can listen how your remote sounds like :)
item = variable_item_list_add(
subghz->variable_item_list,
"Sound:",
SPEAKER_COUNT,
COMBO_BOX_COUNT,
subghz_scene_receiver_config_set_speaker,
subghz);
value_index = value_index_uint32(
subghz_txrx_speaker_get_state(subghz->txrx), speaker_value, SPEAKER_COUNT);
subghz_txrx_speaker_get_state(subghz->txrx), speaker_value, COMBO_BOX_COUNT);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, speaker_text[value_index]);
variable_item_set_current_value_text(item, combobox_text[value_index]);
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
SubGhzCustomEventManagerSet) {
// Reset to default
variable_item_list_add(subghz->variable_item_list, "Reset to default", 1, NULL, NULL);
variable_item_list_set_enter_callback(
subghz->variable_item_list,
subghz_scene_receiver_config_var_list_enter_callback,
subghz);
}
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
SubGhzCustomEventManagerSet) {
// Lock keyboard
@@ -412,6 +477,7 @@ void subghz_scene_receiver_config_on_enter(void* context) {
subghz_scene_receiver_config_var_list_enter_callback,
subghz);
}
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) ==
SubGhzCustomEventManagerSet) {
item = variable_item_list_add(
@@ -439,6 +505,9 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even
subghz_lock(subghz);
scene_manager_previous_scene(subghz->scene_manager);
consumed = true;
} else if(event.event == SubGhzCustomEventSceneSettingResetToDefault) {
scene_manager_previous_scene(subghz->scene_manager);
consumed = true;
}
}
return consumed;
@@ -448,6 +517,9 @@ void subghz_scene_receiver_config_on_exit(void* context) {
SubGhz* subghz = context;
variable_item_list_set_selected_item(subghz->variable_item_list, 0);
variable_item_list_reset(subghz->variable_item_list);
#ifdef FURI_DEBUG
subghz_last_settings_log(subghz->last_settings);
#endif
subghz_last_settings_save(subghz->last_settings);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
@@ -1,8 +1,9 @@
#include "../subghz_i.h"
#include "../helpers/subghz_custom_event.h"
#include <lib/subghz/blocks/custom_btn.h>
#define TAG "SubGhzSceneReceiverInfo"
void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context);
SubGhz* subghz = context;
@@ -42,7 +42,7 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event)
subghz->scene_manager, SubGhzSceneDecodeRAW, SubGhzDecodeRawStateStart);
subghz->idx_menu_chosen = 0;
subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz);
subghz_txrx_set_rx_callback(subghz->txrx, NULL, subghz);
if(subghz_file_encoder_worker_is_running(subghz->decode_raw_file_worker_encoder)) {
subghz_file_encoder_worker_stop(subghz->decode_raw_file_worker_encoder);
@@ -1,5 +1,7 @@
#include "../subghz_i.h"
#define TAG "SubGhzSceneSaved"
void subghz_scene_saved_on_enter(void* context) {
SubGhz* subghz = context;
@@ -5,6 +5,8 @@
#include <lib/subghz/blocks/custom_btn.h>
#define TAG "SubGhzSceneTransmitter"
void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) {
furi_assert(context);
SubGhz* subghz = context;
+35 -21
View File
@@ -1,9 +1,10 @@
/* Abandon hope, all ye who enter here. */
#include <furi/core/log.h>
#include <subghz/types.h>
#include <lib/toolbox/path.h>
#include <float_tools.h>
#include "subghz_i.h"
#include <lib/subghz/protocols/protocol_items.h>
#include <applications/main/archive/helpers/archive_helpers_ext.h>
#include <xtreme.h>
@@ -76,7 +77,7 @@ static void subghz_load_custom_presets(SubGhzSetting* setting) {
FlipperFormat* fff_temp = flipper_format_string_alloc();
for(uint8_t i = 0; i < COUNT_OF(presets); i++) {
for(size_t i = 0; i < COUNT_OF(presets); i++) {
flipper_format_insert_or_update_string_cstr(fff_temp, "Custom_preset_data", presets[i][1]);
flipper_format_rewind(fff_temp);
@@ -114,7 +115,9 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
// Open Notification record
subghz->notifications = furi_record_open(RECORD_NOTIFICATION);
#if SUBGHZ_MEASURE_LOADING
uint32_t load_ticks = furi_get_tick();
#endif
subghz->txrx = subghz_txrx_alloc();
if(!alloc_for_tx_only) {
@@ -198,35 +201,46 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
// Load last used values for Read, Read RAW, etc. or default
subghz->last_settings = subghz_last_settings_alloc();
subghz_last_settings_load(subghz->last_settings, 0);
if(!alloc_for_tx_only) {
#if FURI_DEBUG
FURI_LOG_D(
TAG,
"last frequency: %ld, preset: %ld",
subghz->last_settings->frequency,
subghz->last_settings->preset);
size_t preset_count = subghz_setting_get_preset_count(setting);
subghz_last_settings_load(subghz->last_settings, preset_count);
#ifdef FURI_DEBUG
subghz_last_settings_log(subghz->last_settings);
#endif
subghz_setting_set_default_frequency(setting, subghz->last_settings->frequency);
}
if(!alloc_for_tx_only) {
subghz_txrx_set_preset(subghz->txrx, "AM650", subghz->last_settings->frequency, NULL, 0);
#if SUBGHZ_LAST_SETTING_SAVE_PRESET
subghz_txrx_set_preset_internal(
subghz->txrx, subghz->last_settings->frequency, subghz->last_settings->preset_index);
#else
subghz_txrx_set_default_preset(subghz->txrx, subghz->last_settings->frequency);
#endif
subghz->history = subghz_history_alloc();
}
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
if(!alloc_for_tx_only) {
subghz->history = subghz_history_alloc();
}
subghz->secure_data = malloc(sizeof(SecureData));
subghz->filter = SubGhzProtocolFlag_Decodable;
subghz->ignore_filter = 0x0;
if(!alloc_for_tx_only) {
subghz->ignore_filter = subghz->last_settings->ignore_filter;
subghz->filter = subghz->last_settings->filter;
} else {
subghz->filter = SubGhzProtocolFlag_Decodable;
subghz->ignore_filter = 0x0;
}
subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
subghz_txrx_set_need_save_callback(subghz->txrx, subghz_save_to_file, subghz);
if(!alloc_for_tx_only) {
if(!float_is_equal(subghz->last_settings->rssi, 0)) {
subghz_threshold_rssi_set(subghz->threshold_rssi, subghz->last_settings->rssi);
} else {
subghz->last_settings->rssi = SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER;
}
}
#if SUBGHZ_MEASURE_LOADING
load_ticks = furi_get_tick() - load_ticks;
FURI_LOG_I(TAG, "Loaded: %ld ms.", load_ticks);
#endif
//Init Error_str
subghz->error_str = furi_string_alloc();
+2 -18
View File
@@ -4,30 +4,13 @@
#include "subghz/types.h"
#include <math.h>
#include <furi.h>
#include <furi_hal.h>
#include <input/input.h>
#include <gui/elements.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <flipper_format/flipper_format.h>
#include "views/receiver.h"
#include <flipper_format/flipper_format_i.h>
#include <lib/toolbox/stream/stream.h>
#include <lib/subghz/protocols/raw.h>
#define TAG "SubGhz"
void subghz_set_default_preset(SubGhz* subghz) {
furi_assert(subghz);
subghz_txrx_set_preset(
subghz->txrx,
"AM650",
subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)),
NULL,
0);
}
void subghz_blink_start(SubGhz* subghz) {
furi_assert(subghz);
notification_message(subghz->notifications, &sequence_blink_stop);
@@ -60,7 +43,7 @@ void subghz_dialog_message_freq_error(SubGhz* subghz, bool only_rx) {
DialogsApp* dialogs = subghz->dialogs;
DialogMessage* message = dialog_message_alloc();
const char* header_text = "Frequency not supported";
const char* message_text = "Frequency\nis outside of\nsuported range.";
const char* message_text = "Frequency\nis outside of\nsupported range.";
if(only_rx) {
header_text = "Transmission is blocked";
@@ -124,6 +107,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
// TODO: use different frequency allowed lists for differnet modules (non cc1101)
if(!furi_hal_subghz_is_tx_allowed(temp_data32)) {
FURI_LOG_E(TAG, "This frequency can only be used for RX");
load_key_state = SubGhzLoadKeyStateOnlyRx;
break;
}
+2 -1
View File
@@ -42,6 +42,8 @@
#define SUBGHZ_MAX_LEN_NAME 64
#define SUBGHZ_EXT_PRESET_NAME true
#define SUBGHZ_RAW_THRESHOLD_MIN (-90.0f)
#define SUBGHZ_MEASURE_LOADING false
typedef struct {
uint8_t fix[4];
@@ -101,7 +103,6 @@ struct SubGhz {
void* rpc_ctx;
};
void subghz_set_default_preset(SubGhz* subghz);
void subghz_blink_start(SubGhz* subghz);
void subghz_blink_stop(SubGhz* subghz);
+127 -34
View File
@@ -6,21 +6,19 @@
#define SUBGHZ_LAST_SETTING_FILE_TYPE "Flipper SubGhz Last Setting File"
#define SUBGHZ_LAST_SETTING_FILE_VERSION 1
#define SUBGHZ_LAST_SETTINGS_PATH EXT_PATH("subghz/assets/last_subghz.settings")
// 1 = "AM650"
// "AM270", "AM650", "FM238", "FM476",
#define SUBGHZ_LAST_SETTING_DEFAULT_PRESET 1
#define SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY 433920000
#define SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_FEEDBACK_LEVEL 2
#define SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER -93.0f
#define SUBGHZ_LAST_SETTING_FIELD_FREQUENCY "Frequency"
//#define SUBGHZ_LAST_SETTING_FIELD_PRESET "Preset"
#define SUBGHZ_LAST_SETTING_FIELD_PRESET "Preset" // AKA Modulation
#define SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_FEEDBACK_LEVEL "FeedbackLevel"
#define SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_TRIGGER "FATrigger"
#define SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_ENABLED "External"
#define SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_POWER "ExtPower"
#define SUBGHZ_LAST_SETTING_FIELD_TIMESTAMP_FILE_NAMES "TimestampNames"
#define SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_POWER_AMP "ExtPowerAmp"
#define SUBGHZ_LAST_SETTING_FIELD_HOPPING_ENABLE "Hopping"
#define SUBGHZ_LAST_SETTING_FIELD_IGNORE_FILTER "IgnoreFilter"
#define SUBGHZ_LAST_SETTING_FIELD_FILTER "Filter"
#define SUBGHZ_LAST_SETTING_FIELD_RSSI_THRESHOLD "RSSI"
SubGhzLastSettings* subghz_last_settings_alloc(void) {
SubGhzLastSettings* instance = malloc(sizeof(SubGhzLastSettings));
@@ -33,11 +31,7 @@ void subghz_last_settings_free(SubGhzLastSettings* instance) {
}
void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count) {
UNUSED(preset_count);
furi_assert(instance);
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "subghz_last_settings_load");
#endif
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
@@ -49,15 +43,23 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
bool temp_external_module_power_5v_disable = false;
bool temp_external_module_power_amp = false;
bool temp_timestamp_file_names = false;
//int32_t temp_preset = 0;
bool temp_enable_hopping = false;
uint32_t temp_ignore_filter = 0;
uint32_t temp_filter = 0;
float temp_rssi = 0;
uint32_t temp_preset = 0;
bool preset_was_read = false;
bool rssi_was_read = false;
bool filter_was_read = false;
bool ignore_filter_was_read = false;
bool frequency_analyzer_feedback_level_was_read = false;
bool frequency_analyzer_trigger_was_read = false;
if(FSE_OK == storage_sd_status(storage) && SUBGHZ_LAST_SETTINGS_PATH &&
flipper_format_file_open_existing(fff_data_file, SUBGHZ_LAST_SETTINGS_PATH)) {
/*
flipper_format_read_int32(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_PRESET, (int32_t*)&temp_preset, 1);*/
preset_was_read = flipper_format_read_uint32(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_PRESET, (uint32_t*)&temp_preset, 1);
flipper_format_read_uint32(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_FREQUENCY, (uint32_t*)&temp_frequency, 1);
frequency_analyzer_feedback_level_was_read = flipper_format_read_uint32(
@@ -90,22 +92,40 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
SUBGHZ_LAST_SETTING_FIELD_EXTERNAL_MODULE_POWER_AMP,
(bool*)&temp_external_module_power_amp,
1);
flipper_format_read_bool(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_HOPPING_ENABLE,
(bool*)&temp_enable_hopping,
1);
rssi_was_read = flipper_format_read_float(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_RSSI_THRESHOLD, (float*)&temp_rssi, 1);
ignore_filter_was_read = flipper_format_read_uint32(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_IGNORE_FILTER,
(uint32_t*)&temp_ignore_filter,
1);
filter_was_read = flipper_format_read_uint32(
fff_data_file, SUBGHZ_LAST_SETTING_FIELD_FILTER, (uint32_t*)&temp_filter, 1);
} else {
FURI_LOG_E(TAG, "Error open file %s", SUBGHZ_LAST_SETTINGS_PATH);
}
if(temp_frequency == 0 || !furi_hal_subghz_is_tx_allowed(temp_frequency)) {
FURI_LOG_W(TAG, "Last used frequency not found or can't be used!");
instance->frequency = SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY;
instance->preset = SUBGHZ_LAST_SETTING_DEFAULT_PRESET;
instance->preset_index = SUBGHZ_LAST_SETTING_DEFAULT_PRESET;
instance->frequency_analyzer_feedback_level =
SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_FEEDBACK_LEVEL;
instance->frequency_analyzer_trigger = SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER;
instance->external_module_enabled = false;
instance->timestamp_file_names = false;
instance->external_module_power_amp = false;
instance->enable_hopping = false;
instance->ignore_filter = 0x00;
// See bin_raw_value in applications/main/subghz/scenes/subghz_scene_receiver_config.c
instance->filter = SubGhzProtocolFlag_Decodable;
instance->rssi = SUBGHZ_RAW_THRESHOLD_MIN;
} else {
instance->frequency = temp_frequency;
instance->frequency_analyzer_feedback_level =
@@ -117,10 +137,19 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
temp_frequency_analyzer_trigger :
SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER;
/*if(temp_preset > (int32_t)preset_count - 1 || temp_preset < 0) {
FURI_LOG_W(TAG, "Last used preset no found");*/
instance->preset = SUBGHZ_LAST_SETTING_DEFAULT_PRESET;
if(!preset_was_read) {
FURI_LOG_W(TAG, "Preset was not read. Set default");
instance->preset_index = SUBGHZ_LAST_SETTING_DEFAULT_PRESET;
} else if(temp_preset > (uint32_t)preset_count - 1) {
FURI_LOG_W(
TAG,
"Last used preset out of range. Preset to set: %ld, Max index: %ld. Set default",
temp_preset,
(uint32_t)preset_count - 1);
instance->preset_index = SUBGHZ_LAST_SETTING_DEFAULT_PRESET;
} else {
instance->preset_index = temp_preset;
}
instance->external_module_enabled = temp_external_module_enabled;
instance->external_module_power_5v_disable = temp_external_module_power_5v_disable;
@@ -130,12 +159,22 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
// External power amp CC1101
instance->external_module_power_amp = temp_external_module_power_amp;
instance->rssi = rssi_was_read ? temp_rssi : SUBGHZ_RAW_THRESHOLD_MIN;
instance->enable_hopping = temp_enable_hopping;
instance->ignore_filter = ignore_filter_was_read ? temp_ignore_filter : 0x00;
#if SUBGHZ_LAST_SETTING_SAVE_BIN_RAW
instance->filter = filter_was_read ? temp_filter : SubGhzProtocolFlag_Decodable;
#else
if(filter_was_read) {
instance->filter = temp_filter != SubGhzProtocolFlag_Decodable ?
SubGhzProtocolFlag_Decodable :
temp_filter;
} else {
instance->filter = SubGhzProtocolFlag_Decodable;
}
#endif
// Set globally in furi hal
furi_hal_subghz_set_ext_power_amp(instance->external_module_power_amp);
/*/} else {
instance->preset = temp_preset;
}*/
}
flipper_format_file_close(fff_data_file);
@@ -145,10 +184,10 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
bool subghz_last_settings_save(SubGhzLastSettings* instance) {
furi_assert(instance);
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "last_settings_save");
#endif
#if SUBGHZ_LAST_SETTING_SAVE_BIN_RAW != true
instance->filter = SubGhzProtocolFlag_Decodable;
#endif
bool saved = false;
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* file = flipper_format_file_alloc(storage);
@@ -165,12 +204,10 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) {
if(!flipper_format_write_header_cstr(
file, SUBGHZ_LAST_SETTING_FILE_TYPE, SUBGHZ_LAST_SETTING_FILE_VERSION))
break;
/*
if(!flipper_format_insert_or_update_int32(
file, SUBGHZ_LAST_SETTING_FIELD_PRESET, &instance->preset, 1)) {
if(!flipper_format_insert_or_update_uint32(
file, SUBGHZ_LAST_SETTING_FIELD_PRESET, &instance->preset_index, 1)) {
break;
}*/
}
if(!flipper_format_insert_or_update_uint32(
file, SUBGHZ_LAST_SETTING_FIELD_FREQUENCY, &instance->frequency, 1)) {
break;
@@ -217,6 +254,22 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) {
1)) {
break;
}
if(!flipper_format_insert_or_update_bool(
file, SUBGHZ_LAST_SETTING_FIELD_HOPPING_ENABLE, &instance->enable_hopping, 1)) {
break;
}
if(!flipper_format_insert_or_update_float(
file, SUBGHZ_LAST_SETTING_FIELD_RSSI_THRESHOLD, &instance->rssi, 1)) {
break;
}
if(!flipper_format_insert_or_update_uint32(
file, SUBGHZ_LAST_SETTING_FIELD_IGNORE_FILTER, &instance->ignore_filter, 1)) {
break;
}
if(!flipper_format_insert_or_update_uint32(
file, SUBGHZ_LAST_SETTING_FIELD_FILTER, &instance->filter, 1)) {
break;
}
saved = true;
} while(0);
@@ -230,3 +283,43 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) {
return saved;
}
const char* LOG_ON = "ON";
const char* LOG_OFF = "OFF";
static inline const char*
subghz_last_settings_log_filter_get_index(uint32_t filter, uint32_t flag) {
return READ_BIT(filter, flag) > 0 ? LOG_ON : LOG_OFF;
}
static inline const char* bool_to_char(bool value) {
return value ? LOG_ON : LOG_OFF;
}
void subghz_last_settings_log(SubGhzLastSettings* instance) {
furi_assert(instance);
FURI_LOG_I(
TAG,
"Frequency: %03ld.%02ld, FeedbackLevel: %ld, FATrigger: %.2f, External: %s, ExtPower: %s, TimestampNames: %s, ExtPowerAmp: %s,\n"
"Hopping: %s,\nPreset: %ld, RSSI: %.2f, "
"Starline: %s, Cars: %s, Magellan: %s, BinRAW: %s",
instance->frequency / 1000000 % 1000,
instance->frequency / 10000 % 100,
instance->frequency_analyzer_feedback_level,
(double)instance->frequency_analyzer_trigger,
bool_to_char(instance->external_module_enabled),
bool_to_char(instance->external_module_power_5v_disable),
bool_to_char(instance->timestamp_file_names),
bool_to_char(instance->external_module_power_amp),
bool_to_char(instance->enable_hopping),
instance->preset_index,
(double)instance->rssi,
subghz_last_settings_log_filter_get_index(
instance->ignore_filter, SubGhzProtocolFlag_StarLine),
subghz_last_settings_log_filter_get_index(
instance->ignore_filter, SubGhzProtocolFlag_AutoAlarms),
subghz_last_settings_log_filter_get_index(
instance->ignore_filter, SubGhzProtocolFlag_Magellan),
subghz_last_settings_log_filter_get_index(instance->filter, SubGhzProtocolFlag_BinRAW));
}
@@ -4,10 +4,20 @@
#include <stdint.h>
#include <stdbool.h>
#include <storage/storage.h>
#include <lib/subghz/types.h>
#define SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER (-93.0f)
#define SUBGHZ_LAST_SETTING_SAVE_BIN_RAW true
#define SUBGHZ_LAST_SETTING_SAVE_PRESET true
// 1 = "AM650"
// "AM270", "AM650", "FM238", "FM476",
#define SUBGHZ_LAST_SETTING_DEFAULT_PRESET 1
#define SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY 433920000
#define SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_FEEDBACK_LEVEL 2
typedef struct {
uint32_t frequency;
int32_t preset;
uint32_t preset_index; // AKA Modulation
uint32_t frequency_analyzer_feedback_level;
float frequency_analyzer_trigger;
// TODO not using but saved so as not to change the version
@@ -16,6 +26,10 @@ typedef struct {
bool external_module_power_amp;
// saved so as not to change the version
bool timestamp_file_names;
bool enable_hopping;
uint32_t ignore_filter;
uint32_t filter;
float rssi;
} SubGhzLastSettings;
SubGhzLastSettings* subghz_last_settings_alloc(void);
@@ -25,3 +39,5 @@ void subghz_last_settings_free(SubGhzLastSettings* instance);
void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count);
bool subghz_last_settings_save(SubGhzLastSettings* instance);
void subghz_last_settings_log(SubGhzLastSettings* instance);
+35 -8
View File
@@ -12,7 +12,7 @@
#define MENU_ITEMS 4u
#define UNLOCK_CNT 3
#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
// #define SUBGHZ_RAW_THRESHOLD_MIN (-90.0f)
#define FLIP_TIMEOUT (500)
@@ -62,6 +62,8 @@ typedef struct {
FuriString* preset_str;
FuriString* history_stat_str;
FuriString* progress_str;
bool hopping_enabled;
bool bin_raw_enabled;
SubGhzReceiverHistory* history;
uint16_t idx;
uint16_t list_offset;
@@ -200,7 +202,9 @@ void subghz_view_receiver_add_data_statusbar(
SubGhzViewReceiver* subghz_receiver,
const char* frequency_str,
const char* preset_str,
const char* history_stat_str) {
const char* history_stat_str,
bool hopping_enabled,
bool bin_raw_enabled) {
furi_assert(subghz_receiver);
with_view_model(
subghz_receiver->view,
@@ -209,6 +213,8 @@ void subghz_view_receiver_add_data_statusbar(
furi_string_set(model->frequency_str, frequency_str);
furi_string_set(model->preset_str, preset_str);
furi_string_set(model->history_stat_str, history_stat_str);
model->hopping_enabled = hopping_enabled;
model->bin_raw_enabled = bin_raw_enabled;
},
true);
}
@@ -311,7 +317,6 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) {
canvas_set_color(canvas, ColorBlack);
if(model->history_item == 0) {
// TODO
if(model->mode == SubGhzViewReceiverModeLive) {
canvas_draw_icon(
canvas,
@@ -320,9 +325,19 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) {
(model->device_type == SubGhzRadioDeviceTypeInternal) ? &I_Scanning_123x52 :
&I_Fishing_123x52);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 63, 46, "Scanning...");
if(model->hopping_enabled) {
canvas_draw_str(canvas, 59, 46, "Hopper scan...");
} else {
canvas_draw_str(canvas, 59, 46, "Fixed scan...");
}
//canvas_draw_line(canvas, 46, 51, 125, 51);
canvas_set_font(canvas, FontSecondary);
if(model->bin_raw_enabled) {
const uint8_t vertical_offset = 17;
const uint8_t horizontal_offset = 118;
canvas_draw_icon(canvas, horizontal_offset, vertical_offset, &I_Cos_9x7);
}
} else {
canvas_draw_icon(
canvas,
@@ -458,8 +473,10 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
return true;
}
bool consumed = false;
if(event->key == InputKeyBack && event->type == InputTypeShort) {
subghz_receiver->callback(SubGhzCustomEventViewReceiverBack, subghz_receiver->context);
consumed = true;
} else if(
event->key == InputKeyUp &&
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
@@ -471,6 +488,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
subghz_view_receiver_show_time_moment(context);
},
true);
consumed = true;
} else if(
event->key == InputKeyDown &&
(event->type == InputTypeShort || event->type == InputTypeRepeat)) {
@@ -484,8 +502,10 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
}
},
true);
consumed = true;
} else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
subghz_receiver->callback(SubGhzCustomEventViewReceiverConfig, subghz_receiver->context);
consumed = true;
} else if(event->key == InputKeyRight && event->type == InputTypeLong) {
with_view_model(
subghz_receiver->view,
@@ -498,6 +518,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
}
},
false);
consumed = true;
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
with_view_model(
subghz_receiver->view,
@@ -509,11 +530,13 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
}
},
false);
consumed = true;
}
subghz_view_receiver_update_offset(subghz_receiver);
return true;
if(consumed) {
subghz_view_receiver_update_offset(subghz_receiver);
}
return consumed;
}
void subghz_view_receiver_enter(void* context) {
@@ -543,6 +566,8 @@ void subghz_view_receiver_exit(void* context) {
model->list_offset = 0;
model->history_item = 0;
model->nodraw = false;
model->hopping_enabled = false;
model->bin_raw_enabled = false;
},
false);
furi_timer_stop(subghz_receiver->timer);
@@ -579,6 +604,8 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() {
model->bar_show = SubGhzViewReceiverBarShowDefault;
model->nodraw = false;
model->history = malloc(sizeof(SubGhzReceiverHistory));
model->hopping_enabled = false;
model->bin_raw_enabled = false;
SubGhzReceiverMenuItemArray_init(model->history->data);
},
true);
@@ -622,7 +649,7 @@ View* subghz_view_receiver_get_view(SubGhzViewReceiver* subghz_receiver) {
uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver) {
furi_assert(subghz_receiver);
uint16_t idx = 0;
uint16_t idx;
with_view_model(
subghz_receiver->view, SubGhzViewReceiverModel * model, { idx = model->idx; }, false);
return idx;
+3 -1
View File
@@ -31,7 +31,9 @@ void subghz_view_receiver_add_data_statusbar(
SubGhzViewReceiver* subghz_receiver,
const char* frequency_str,
const char* preset_str,
const char* history_stat_str);
const char* history_stat_str,
bool hopping_enabled,
bool bin_raw_enabled);
void subghz_view_receiver_set_radio_device_type(
SubGhzViewReceiver* subghz_receiver,
@@ -32,4 +32,4 @@ SubGHzFrequencyAnalyzerFeedbackLevel subghz_frequency_analyzer_feedback_level(
SubGHzFrequencyAnalyzerFeedbackLevel level,
bool update);
float subghz_frequency_analyzer_get_trigger_level(SubGhzFrequencyAnalyzer* instance);
float subghz_frequency_analyzer_get_trigger_level(SubGhzFrequencyAnalyzer* instance);
@@ -4,8 +4,6 @@
#include "../helpers/subghz_types.h"
#include "../helpers/subghz_custom_event.h"
#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
typedef struct SubGhzReadRAW SubGhzReadRAW;
typedef void (*SubGhzReadRAWCallback)(SubGhzCustomEvent event, void* context);
+1
View File
@@ -474,6 +474,7 @@ void cli_commands_init(Cli* cli) {
cli_add_command(cli, "uptime", CliCommandFlagDefault, cli_command_uptime, NULL);
cli_add_command(cli, "date", CliCommandFlagParallelSafe, cli_command_date, NULL);
cli_add_command(cli, "log", CliCommandFlagParallelSafe, cli_command_log, NULL);
cli_add_command(cli, "l", CliCommandFlagParallelSafe, cli_command_log, NULL);
cli_add_command(cli, "sysctl", CliCommandFlagDefault, cli_command_sysctl, NULL);
cli_add_command(cli, "ps", CliCommandFlagParallelSafe, cli_command_ps, NULL);
cli_add_command(cli, "free", CliCommandFlagParallelSafe, cli_command_free, NULL);
+1 -2
View File
@@ -313,8 +313,7 @@ void elements_multiline_text_aligned(
} else if((y + font_height) > canvas_height(canvas)) {
line = furi_string_alloc_printf("%.*s...\n", chars_fit, start);
} else {
// Account for the added "-" in length
line = furi_string_alloc_printf("%.*s-\n", chars_fit - 1, start);
line = furi_string_alloc_printf("%.*s-\n", chars_fit, start);
}
canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, furi_string_get_cstr(line));
furi_string_free(line);
@@ -94,24 +94,37 @@ static void variable_item_list_draw_callback(Canvas* canvas, void* _model) {
canvas_set_color(canvas, ColorBlack);
}
uint8_t temp_x_default = 73;
uint8_t temp_w_default = 66;
if(item->current_value_index == 0 && furi_string_empty(item->current_value_text)) {
// Only left text, no right text
canvas_draw_str(canvas, 6, item_text_y, furi_string_get_cstr(item->label));
} else {
if(furi_string_size(item->current_value_text) < (size_t)4) {
temp_x_default = 80;
temp_w_default = 71;
}
elements_scrollable_text_line_centered(
canvas, 6, item_text_y, 66, item->label, scroll_counter, false, false);
canvas,
6,
item_text_y,
temp_w_default,
item->label,
scroll_counter,
false,
false);
}
if(item->locked) {
canvas_draw_icon(canvas, 110, item_text_y - 8, &I_Lock_7x8);
} else {
if(item->current_value_index > 0) {
canvas_draw_str(canvas, 73, item_text_y, "<");
canvas_draw_str(canvas, temp_x_default, item_text_y, "<");
}
elements_scrollable_text_line_centered(
canvas,
(115 + 73) / 2 + 1,
(115 + temp_x_default) / 2 + 1,
item_text_y,
37,
item->current_value_text,
+3 -16
View File
@@ -174,23 +174,10 @@ void view_port_input_callback_set(
void view_port_update(ViewPort* view_port) {
furi_assert(view_port);
// view_port_update() does not modify viewport memory
// nor does it need time sensitive data in order to work
// but when used in apps in a input loop it can cause deadlocks with draw() being called by other means
// example:
// - app selector keeps loading animation in background, keeps drawing
// - because of this gui starts draw and locks viewport mutex, not in app render callback yet
// - app gets input, locks app mutex
// - app input handler calls view_port_update() which needs viewport mutex
// - viewport mutex already locked by draw previously
// - but app mutex locked by input so draw cannot complete
// - DEADLOCK => mutex removed from view_port_update()
// this is just one example, there may be many more edge cases
// point is, this view_port_update() has no need at all for mutex
// dont copy paste mutex into all functions to close jira tasks please :)
// furi_check(furi_mutex_acquire(view_port->mutex, FuriWaitForever) == FuriStatusOk);
// TODO: Uncomment when all apps are verified to be fixed !!!!!!!!!!!!!!!!!!!!!!!
//furi_check(furi_mutex_acquire(view_port->mutex, FuriWaitForever) == FuriStatusOk);
if(view_port->gui && view_port->is_enabled) gui_update(view_port->gui);
// furi_check(furi_mutex_release(view_port->mutex) == FuriStatusOk);
//furi_check(furi_mutex_release(view_port->mutex) == FuriStatusOk);
}
void view_port_gui_set(ViewPort* view_port, Gui* gui) {
+2 -1
View File
@@ -431,7 +431,8 @@ static LoaderStatus loader_start_external_app(
FlipperApplicationPreloadStatus preload_res =
flipper_application_preload(loader->app.fap, path);
bool api_mismatch = false;
if(preload_res == FlipperApplicationPreloadStatusApiMismatch) {
if(preload_res == FlipperApplicationPreloadStatusApiTooOld ||
preload_res == FlipperApplicationPreloadStatusApiTooNew) {
api_mismatch = true;
} else if(preload_res != FlipperApplicationPreloadStatusSuccess) {
const char* err_msg = flipper_application_preload_status_to_string(preload_res);
@@ -32,8 +32,6 @@ typedef struct {
uint32_t product_serial_number;
uint8_t manufacturing_month;
uint16_t manufacturing_year;
FS_Error error;
} SDInfo;
const char* sd_api_get_fs_type_text(SDFsType fs_type);
@@ -26,11 +26,11 @@ static FS_Error storage_ext_parse_error(SDError error);
static bool sd_mount_card_internal(StorageData* storage, bool notify) {
bool result = false;
uint8_t counter = sd_max_mount_retry_count();
uint8_t counter = furi_hal_sd_max_mount_retry_count();
uint8_t bsp_result;
SDData* sd_data = storage->data;
while(result == false && counter > 0 && hal_sd_detect()) {
while(result == false && counter > 0 && furi_hal_sd_is_present()) {
if(notify) {
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
sd_notify_wait(notification);
@@ -39,9 +39,9 @@ static bool sd_mount_card_internal(StorageData* storage, bool notify) {
if((counter % 2) == 0) {
// power reset sd card
bsp_result = sd_init(true);
bsp_result = furi_hal_sd_init(true);
} else {
bsp_result = sd_init(false);
bsp_result = furi_hal_sd_init(false);
}
if(bsp_result) {
@@ -225,18 +225,18 @@ FS_Error sd_card_info(StorageData* storage, SDInfo* sd_info) {
#endif
}
SD_CID cid;
SdSpiStatus status = sd_get_cid(&cid);
FuriHalSdInfo info;
FuriStatus status = furi_hal_sd_info(&info);
if(status == SdSpiStatusOK) {
sd_info->manufacturer_id = cid.ManufacturerID;
memcpy(sd_info->oem_id, cid.OEM_AppliID, sizeof(cid.OEM_AppliID));
memcpy(sd_info->product_name, cid.ProdName, sizeof(cid.ProdName));
sd_info->product_revision_major = cid.ProdRev >> 4;
sd_info->product_revision_minor = cid.ProdRev & 0x0F;
sd_info->product_serial_number = cid.ProdSN;
sd_info->manufacturing_year = 2000 + cid.ManufactYear;
sd_info->manufacturing_month = cid.ManufactMonth;
if(status == FuriStatusOk) {
sd_info->manufacturer_id = info.manufacturer_id;
memcpy(sd_info->oem_id, info.oem_id, sizeof(info.oem_id));
memcpy(sd_info->product_name, info.product_name, sizeof(info.product_name));
sd_info->product_revision_major = info.product_revision_major;
sd_info->product_revision_minor = info.product_revision_minor;
sd_info->product_serial_number = info.product_serial_number;
sd_info->manufacturing_year = info.manufacturing_year;
sd_info->manufacturing_month = info.manufacturing_month;
}
return storage_ext_parse_error(error);
@@ -246,19 +246,19 @@ static void storage_ext_tick_internal(StorageData* storage, bool notify) {
SDData* sd_data = storage->data;
if(sd_data->sd_was_present) {
if(hal_sd_detect()) {
if(furi_hal_sd_is_present()) {
FURI_LOG_I(TAG, "card detected");
sd_data->sd_was_present = false;
sd_mount_card(storage, notify);
if(!hal_sd_detect()) {
if(!furi_hal_sd_is_present()) {
FURI_LOG_I(TAG, "card removed while mounting");
sd_unmount_card(storage);
sd_data->sd_was_present = true;
}
}
} else {
if(!hal_sd_detect()) {
if(!furi_hal_sd_is_present()) {
FURI_LOG_I(TAG, "card removed");
sd_data->sd_was_present = true;
@@ -669,7 +669,7 @@ void storage_ext_init(StorageData* storage) {
storage->api.tick = storage_ext_tick;
storage->fs_api = &fs_api;
hal_sd_detect_init();
furi_hal_sd_presence_init();
// do not notify on first launch, notifications app is waiting for our thread to read settings
storage_ext_tick_internal(storage, false);
Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

+1
View File
@@ -93,6 +93,7 @@ else:
"FURI_RAM_EXEC",
],
)
env.AppendUnique(CPPDEFINES=["FW_CFG_${FIRMWARE_APP_SET}"])
env.ConfigureForTarget(env.subst("${TARGET_HW}"))
+11 -6
View File
@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,36.1,,
Version,+,38.0,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,,
@@ -827,8 +827,9 @@ Function,+,flipper_application_get_manifest,const FlipperApplicationManifest*,Fl
Function,+,flipper_application_is_plugin,_Bool,FlipperApplication*
Function,+,flipper_application_load_name_and_icon,_Bool,"FuriString*, Storage*, uint8_t**, FuriString*"
Function,+,flipper_application_load_status_to_string,const char*,FlipperApplicationLoadStatus
Function,+,flipper_application_manifest_is_compatible,_Bool,"const FlipperApplicationManifest*, const ElfApiInterface*"
Function,+,flipper_application_manifest_is_target_compatible,_Bool,const FlipperApplicationManifest*
Function,+,flipper_application_manifest_is_too_new,_Bool,"const FlipperApplicationManifest*, const ElfApiInterface*"
Function,+,flipper_application_manifest_is_too_old,_Bool,"const FlipperApplicationManifest*, const ElfApiInterface*"
Function,+,flipper_application_manifest_is_valid,_Bool,const FlipperApplicationManifest*
Function,+,flipper_application_map_to_memory,FlipperApplicationLoadStatus,FlipperApplication*
Function,+,flipper_application_plugin_get_descriptor,const FlipperAppPluginDescriptor*,FlipperApplication*
@@ -1223,6 +1224,14 @@ Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t
Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t"
Function,+,furi_hal_rtc_sync_shadow,void,
Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime*
Function,+,furi_hal_sd_get_card_state,FuriStatus,
Function,+,furi_hal_sd_info,FuriStatus,FuriHalSdInfo*
Function,+,furi_hal_sd_init,FuriStatus,_Bool
Function,+,furi_hal_sd_is_present,_Bool,
Function,+,furi_hal_sd_max_mount_retry_count,uint8_t,
Function,+,furi_hal_sd_presence_init,void,
Function,+,furi_hal_sd_read_blocks,FuriStatus,"uint32_t*, uint32_t, uint32_t"
Function,+,furi_hal_sd_write_blocks,FuriStatus,"const uint32_t*, uint32_t, uint32_t"
Function,+,furi_hal_speaker_acquire,_Bool,uint32_t
Function,-,furi_hal_speaker_deinit,void,
Function,-,furi_hal_speaker_init,void,
@@ -1478,9 +1487,6 @@ Function,+,gui_remove_view_port,void,"Gui*, ViewPort*"
Function,+,gui_set_lockdown,void,"Gui*, _Bool"
Function,-,gui_view_port_send_to_back,void,"Gui*, ViewPort*"
Function,+,gui_view_port_send_to_front,void,"Gui*, ViewPort*"
Function,+,hal_sd_detect,_Bool,
Function,+,hal_sd_detect_init,void,
Function,+,hal_sd_detect_set_low,void,
Function,+,hex_char_to_hex_nibble,_Bool,"char, uint8_t*"
Function,+,hex_char_to_uint8,_Bool,"char, char, uint8_t*"
Function,+,hex_chars_to_uint64,_Bool,"const char*, uint64_t*"
@@ -2424,7 +2430,6 @@ Variable,+,furi_hal_i2c_bus_external,FuriHalI2cBus,
Variable,+,furi_hal_i2c_bus_power,FuriHalI2cBus,
Variable,+,furi_hal_i2c_handle_external,FuriHalI2cBusHandle,
Variable,+,furi_hal_i2c_handle_power,FuriHalI2cBusHandle,
Variable,+,furi_hal_sd_spi_handle,FuriHalSpiBusHandle*,
Variable,+,furi_hal_spi_bus_d,FuriHalSpiBus,
Variable,+,furi_hal_spi_bus_handle_display,FuriHalSpiBusHandle,
Variable,+,furi_hal_spi_bus_handle_external,FuriHalSpiBusHandle,
1 entry status name type params
2 Version + 36.1 38.0
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
827 Function + flipper_application_is_plugin _Bool FlipperApplication*
828 Function + flipper_application_load_name_and_icon _Bool FuriString*, Storage*, uint8_t**, FuriString*
829 Function + flipper_application_load_status_to_string const char* FlipperApplicationLoadStatus
Function + flipper_application_manifest_is_compatible _Bool const FlipperApplicationManifest*, const ElfApiInterface*
830 Function + flipper_application_manifest_is_target_compatible _Bool const FlipperApplicationManifest*
831 Function + flipper_application_manifest_is_too_new _Bool const FlipperApplicationManifest*, const ElfApiInterface*
832 Function + flipper_application_manifest_is_too_old _Bool const FlipperApplicationManifest*, const ElfApiInterface*
833 Function + flipper_application_manifest_is_valid _Bool const FlipperApplicationManifest*
834 Function + flipper_application_map_to_memory FlipperApplicationLoadStatus FlipperApplication*
835 Function + flipper_application_plugin_get_descriptor const FlipperAppPluginDescriptor* FlipperApplication*
1224 Function + furi_hal_rtc_set_register void FuriHalRtcRegister, uint32_t
1225 Function + furi_hal_rtc_sync_shadow void
1226 Function + furi_hal_rtc_validate_datetime _Bool FuriHalRtcDateTime*
1227 Function + furi_hal_sd_get_card_state FuriStatus
1228 Function + furi_hal_sd_info FuriStatus FuriHalSdInfo*
1229 Function + furi_hal_sd_init FuriStatus _Bool
1230 Function + furi_hal_sd_is_present _Bool
1231 Function + furi_hal_sd_max_mount_retry_count uint8_t
1232 Function + furi_hal_sd_presence_init void
1233 Function + furi_hal_sd_read_blocks FuriStatus uint32_t*, uint32_t, uint32_t
1234 Function + furi_hal_sd_write_blocks FuriStatus const uint32_t*, uint32_t, uint32_t
1235 Function + furi_hal_speaker_acquire _Bool uint32_t
1236 Function - furi_hal_speaker_deinit void
1237 Function - furi_hal_speaker_init void
1487 Function + gui_set_lockdown void Gui*, _Bool
1488 Function - gui_view_port_send_to_back void Gui*, ViewPort*
1489 Function + gui_view_port_send_to_front void Gui*, ViewPort*
Function + hal_sd_detect _Bool
Function + hal_sd_detect_init void
Function + hal_sd_detect_set_low void
1490 Function + hex_char_to_hex_nibble _Bool char, uint8_t*
1491 Function + hex_char_to_uint8 _Bool char, char, uint8_t*
1492 Function + hex_chars_to_uint64 _Bool const char*, uint64_t*
2430 Variable + furi_hal_i2c_bus_power FuriHalI2cBus
2431 Variable + furi_hal_i2c_handle_external FuriHalI2cBusHandle
2432 Variable + furi_hal_i2c_handle_power FuriHalI2cBusHandle
Variable + furi_hal_sd_spi_handle FuriHalSpiBusHandle*
2433 Variable + furi_hal_spi_bus_d FuriHalSpiBus
2434 Variable + furi_hal_spi_bus_handle_display FuriHalSpiBusHandle
2435 Variable + furi_hal_spi_bus_handle_external FuriHalSpiBusHandle
@@ -136,6 +136,14 @@ static void furi_hal_resources_init_input_pins(GpioMode mode) {
}
}
static void furi_hal_resources_init_gpio_pins(GpioMode mode) {
for(size_t i = 0; i < gpio_pins_count; i++) {
if(!gpio_pins[i].debug) {
furi_hal_gpio_init(gpio_pins[i].pin, mode, GpioPullNo, GpioSpeedLow);
}
}
}
void furi_hal_resources_init_early() {
furi_hal_bus_enable(FuriHalBusGPIOA);
furi_hal_bus_enable(FuriHalBusGPIOB);
@@ -179,14 +187,7 @@ void furi_hal_resources_init_early() {
furi_hal_gpio_write(&gpio_usb_dp, 0);
// External header pins
furi_hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pc3, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pb2, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pb3, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pa4, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pa6, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pa7, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_resources_init_gpio_pins(GpioModeAnalog);
}
void furi_hal_resources_deinit_early() {
+12 -6
View File
@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,36.1,,
Version,+,38.0,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/main/archive/helpers/archive_helpers_ext.h,,
Header,+,applications/services/applications.h,,
@@ -951,8 +951,9 @@ Function,+,flipper_application_get_manifest,const FlipperApplicationManifest*,Fl
Function,+,flipper_application_is_plugin,_Bool,FlipperApplication*
Function,+,flipper_application_load_name_and_icon,_Bool,"FuriString*, Storage*, uint8_t**, FuriString*"
Function,+,flipper_application_load_status_to_string,const char*,FlipperApplicationLoadStatus
Function,+,flipper_application_manifest_is_compatible,_Bool,"const FlipperApplicationManifest*, const ElfApiInterface*"
Function,+,flipper_application_manifest_is_target_compatible,_Bool,const FlipperApplicationManifest*
Function,+,flipper_application_manifest_is_too_new,_Bool,"const FlipperApplicationManifest*, const ElfApiInterface*"
Function,+,flipper_application_manifest_is_too_old,_Bool,"const FlipperApplicationManifest*, const ElfApiInterface*"
Function,+,flipper_application_manifest_is_valid,_Bool,const FlipperApplicationManifest*
Function,+,flipper_application_map_to_memory,FlipperApplicationLoadStatus,FlipperApplication*
Function,+,flipper_application_plugin_get_descriptor,const FlipperAppPluginDescriptor*,FlipperApplication*
@@ -1432,6 +1433,14 @@ Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t
Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t"
Function,+,furi_hal_rtc_sync_shadow,void,
Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime*
Function,+,furi_hal_sd_get_card_state,FuriStatus,
Function,+,furi_hal_sd_info,FuriStatus,FuriHalSdInfo*
Function,+,furi_hal_sd_init,FuriStatus,_Bool
Function,+,furi_hal_sd_is_present,_Bool,
Function,+,furi_hal_sd_max_mount_retry_count,uint8_t,
Function,+,furi_hal_sd_presence_init,void,
Function,+,furi_hal_sd_read_blocks,FuriStatus,"uint32_t*, uint32_t, uint32_t"
Function,+,furi_hal_sd_write_blocks,FuriStatus,"const uint32_t*, uint32_t, uint32_t"
Function,-,furi_hal_set_is_normal_boot,void,_Bool
Function,+,furi_hal_speaker_acquire,_Bool,uint32_t
Function,-,furi_hal_speaker_deinit,void,
@@ -1731,9 +1740,6 @@ Function,+,gui_set_hide_statusbar,void,"Gui*, _Bool"
Function,+,gui_set_lockdown,void,"Gui*, _Bool"
Function,-,gui_view_port_send_to_back,void,"Gui*, ViewPort*"
Function,+,gui_view_port_send_to_front,void,"Gui*, ViewPort*"
Function,+,hal_sd_detect,_Bool,
Function,+,hal_sd_detect_init,void,
Function,+,hal_sd_detect_set_low,void,
Function,+,hex_char_to_hex_nibble,_Bool,"char, uint8_t*"
Function,+,hex_char_to_uint8,_Bool,"char, char, uint8_t*"
Function,+,hex_chars_to_uint64,_Bool,"const char*, uint64_t*"
@@ -3396,6 +3402,7 @@ Variable,+,I_Circles_47x47,Icon,
Variable,+,I_Clock_18x18,Icon,
Variable,+,I_Connect_me_62x31,Icon,
Variable,+,I_Connected_62x31,Icon,
Variable,+,I_Cos_9x7,Icon,
Variable,+,I_Cry_dolph_55x52,Icon,
Variable,+,I_DFU_128x50,Icon,
Variable,+,I_DolphinCommon_56x48,Icon,
@@ -3593,7 +3600,6 @@ Variable,+,furi_hal_i2c_bus_external,FuriHalI2cBus,
Variable,+,furi_hal_i2c_bus_power,FuriHalI2cBus,
Variable,+,furi_hal_i2c_handle_external,FuriHalI2cBusHandle,
Variable,+,furi_hal_i2c_handle_power,FuriHalI2cBusHandle,
Variable,+,furi_hal_sd_spi_handle,FuriHalSpiBusHandle*,
Variable,+,furi_hal_spi_bus_d,FuriHalSpiBus,
Variable,+,furi_hal_spi_bus_handle_display,FuriHalSpiBusHandle,
Variable,+,furi_hal_spi_bus_handle_external,FuriHalSpiBusHandle,
1 entry status name type params
2 Version + 36.1 38.0
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/main/archive/helpers/archive_helpers_ext.h
5 Header + applications/services/applications.h
951 Function + flipper_application_is_plugin _Bool FlipperApplication*
952 Function + flipper_application_load_name_and_icon _Bool FuriString*, Storage*, uint8_t**, FuriString*
953 Function + flipper_application_load_status_to_string const char* FlipperApplicationLoadStatus
Function + flipper_application_manifest_is_compatible _Bool const FlipperApplicationManifest*, const ElfApiInterface*
954 Function + flipper_application_manifest_is_target_compatible _Bool const FlipperApplicationManifest*
955 Function + flipper_application_manifest_is_too_new _Bool const FlipperApplicationManifest*, const ElfApiInterface*
956 Function + flipper_application_manifest_is_too_old _Bool const FlipperApplicationManifest*, const ElfApiInterface*
957 Function + flipper_application_manifest_is_valid _Bool const FlipperApplicationManifest*
958 Function + flipper_application_map_to_memory FlipperApplicationLoadStatus FlipperApplication*
959 Function + flipper_application_plugin_get_descriptor const FlipperAppPluginDescriptor* FlipperApplication*
1433 Function + furi_hal_rtc_set_register void FuriHalRtcRegister, uint32_t
1434 Function + furi_hal_rtc_sync_shadow void
1435 Function + furi_hal_rtc_validate_datetime _Bool FuriHalRtcDateTime*
1436 Function + furi_hal_sd_get_card_state FuriStatus
1437 Function + furi_hal_sd_info FuriStatus FuriHalSdInfo*
1438 Function + furi_hal_sd_init FuriStatus _Bool
1439 Function + furi_hal_sd_is_present _Bool
1440 Function + furi_hal_sd_max_mount_retry_count uint8_t
1441 Function + furi_hal_sd_presence_init void
1442 Function + furi_hal_sd_read_blocks FuriStatus uint32_t*, uint32_t, uint32_t
1443 Function + furi_hal_sd_write_blocks FuriStatus const uint32_t*, uint32_t, uint32_t
1444 Function - furi_hal_set_is_normal_boot void _Bool
1445 Function + furi_hal_speaker_acquire _Bool uint32_t
1446 Function - furi_hal_speaker_deinit void
1740 Function + gui_set_lockdown void Gui*, _Bool
1741 Function - gui_view_port_send_to_back void Gui*, ViewPort*
1742 Function + gui_view_port_send_to_front void Gui*, ViewPort*
Function + hal_sd_detect _Bool
Function + hal_sd_detect_init void
Function + hal_sd_detect_set_low void
1743 Function + hex_char_to_hex_nibble _Bool char, uint8_t*
1744 Function + hex_char_to_uint8 _Bool char, char, uint8_t*
1745 Function + hex_chars_to_uint64 _Bool const char*, uint64_t*
3402 Variable + I_Clock_18x18 Icon
3403 Variable + I_Connect_me_62x31 Icon
3404 Variable + I_Connected_62x31 Icon
3405 Variable + I_Cos_9x7 Icon
3406 Variable + I_Cry_dolph_55x52 Icon
3407 Variable + I_DFU_128x50 Icon
3408 Variable + I_DolphinCommon_56x48 Icon
3600 Variable + furi_hal_i2c_bus_power FuriHalI2cBus
3601 Variable + furi_hal_i2c_handle_external FuriHalI2cBusHandle
3602 Variable + furi_hal_i2c_handle_power FuriHalI2cBusHandle
Variable + furi_hal_sd_spi_handle FuriHalSpiBusHandle*
3603 Variable + furi_hal_spi_bus_d FuriHalSpiBus
3604 Variable + furi_hal_spi_bus_handle_display FuriHalSpiBusHandle
3605 Variable + furi_hal_spi_bus_handle_external FuriHalSpiBusHandle
-20
View File
@@ -1,21 +1,3 @@
/**
******************************************************************************
* @file fatfs.c
* @brief Code for fatfs applications
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include "fatfs.h"
#include "furi_hal_rtc.h"
@@ -39,5 +21,3 @@ DWORD get_fattime() {
return ((uint32_t)(furi_time.year - 1980) << 25) | furi_time.month << 21 |
furi_time.day << 16 | furi_time.hour << 11 | furi_time.minute << 5 | furi_time.second;
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+1 -21
View File
@@ -1,21 +1,3 @@
/**
******************************************************************************
* @file fatfs.h
* @brief Header for fatfs applications
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#pragma once
#include "fatfs/ff.h"
@@ -34,6 +16,4 @@ void fatfs_init(void);
#ifdef __cplusplus
}
#endif
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
#endif
-843
View File
@@ -1,843 +0,0 @@
#include "sd_spi_io.h"
#include "sector_cache.h"
#include <furi.h>
#include <furi_hal.h>
#include <furi/core/core_defines.h>
// #define SD_SPI_DEBUG 1
#define TAG "SdSpi"
#ifdef SD_SPI_DEBUG
#define sd_spi_debug(...) FURI_LOG_I(TAG, __VA_ARGS__)
#else
#define sd_spi_debug(...)
#endif
#define SD_CMD_LENGTH 6
#define SD_DUMMY_BYTE 0xFF
#define SD_ANSWER_RETRY_COUNT 8
#define SD_IDLE_RETRY_COUNT 100
#define FLAG_SET(x, y) (((x) & (y)) == (y))
static bool sd_high_capacity = false;
typedef enum {
SdSpiDataResponceOK = 0x05,
SdSpiDataResponceCRCError = 0x0B,
SdSpiDataResponceWriteError = 0x0D,
SdSpiDataResponceOtherError = 0xFF,
} SdSpiDataResponce;
typedef struct {
uint8_t r1;
uint8_t r2;
uint8_t r3;
uint8_t r4;
uint8_t r5;
} SdSpiCmdAnswer;
typedef enum {
SdSpiCmdAnswerTypeR1,
SdSpiCmdAnswerTypeR1B,
SdSpiCmdAnswerTypeR2,
SdSpiCmdAnswerTypeR3,
SdSpiCmdAnswerTypeR4R5,
SdSpiCmdAnswerTypeR7,
} SdSpiCmdAnswerType;
/*
SdSpiCmd and SdSpiToken use non-standard enum value names convention,
because it is more convenient to look for documentation on a specific command.
For example, to find out what the SD_CMD23_SET_BLOCK_COUNT command does, you need to look for
SET_BLOCK_COUNT or CMD23 in the "Part 1 Physical Layer Simplified Specification".
Do not use that naming convention in other places.
*/
typedef enum {
SD_CMD0_GO_IDLE_STATE = 0,
SD_CMD1_SEND_OP_COND = 1,
SD_CMD8_SEND_IF_COND = 8,
SD_CMD9_SEND_CSD = 9,
SD_CMD10_SEND_CID = 10,
SD_CMD12_STOP_TRANSMISSION = 12,
SD_CMD13_SEND_STATUS = 13,
SD_CMD16_SET_BLOCKLEN = 16,
SD_CMD17_READ_SINGLE_BLOCK = 17,
SD_CMD18_READ_MULT_BLOCK = 18,
SD_CMD23_SET_BLOCK_COUNT = 23,
SD_CMD24_WRITE_SINGLE_BLOCK = 24,
SD_CMD25_WRITE_MULT_BLOCK = 25,
SD_CMD27_PROG_CSD = 27,
SD_CMD28_SET_WRITE_PROT = 28,
SD_CMD29_CLR_WRITE_PROT = 29,
SD_CMD30_SEND_WRITE_PROT = 30,
SD_CMD32_SD_ERASE_GRP_START = 32,
SD_CMD33_SD_ERASE_GRP_END = 33,
SD_CMD34_UNTAG_SECTOR = 34,
SD_CMD35_ERASE_GRP_START = 35,
SD_CMD36_ERASE_GRP_END = 36,
SD_CMD37_UNTAG_ERASE_GROUP = 37,
SD_CMD38_ERASE = 38,
SD_CMD41_SD_APP_OP_COND = 41,
SD_CMD55_APP_CMD = 55,
SD_CMD58_READ_OCR = 58,
} SdSpiCmd;
/** Data tokens */
typedef enum {
SD_TOKEN_START_DATA_SINGLE_BLOCK_READ = 0xFE,
SD_TOKEN_START_DATA_MULTIPLE_BLOCK_READ = 0xFE,
SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE = 0xFE,
SD_TOKEN_START_DATA_MULTIPLE_BLOCK_WRITE = 0xFC,
SD_TOKEN_STOP_DATA_MULTIPLE_BLOCK_WRITE = 0xFD,
} SdSpiToken;
/** R1 answer value */
typedef enum {
SdSpi_R1_NO_ERROR = 0x00,
SdSpi_R1_IN_IDLE_STATE = 0x01,
SdSpi_R1_ERASE_RESET = 0x02,
SdSpi_R1_ILLEGAL_COMMAND = 0x04,
SdSpi_R1_COM_CRC_ERROR = 0x08,
SdSpi_R1_ERASE_SEQUENCE_ERROR = 0x10,
SdSpi_R1_ADDRESS_ERROR = 0x20,
SdSpi_R1_PARAMETER_ERROR = 0x40,
} SdSpiR1;
/** R2 answer value */
typedef enum {
/* R2 answer value */
SdSpi_R2_NO_ERROR = 0x00,
SdSpi_R2_CARD_LOCKED = 0x01,
SdSpi_R2_LOCKUNLOCK_ERROR = 0x02,
SdSpi_R2_ERROR = 0x04,
SdSpi_R2_CC_ERROR = 0x08,
SdSpi_R2_CARD_ECC_FAILED = 0x10,
SdSpi_R2_WP_VIOLATION = 0x20,
SdSpi_R2_ERASE_PARAM = 0x40,
SdSpi_R2_OUTOFRANGE = 0x80,
} SdSpiR2;
static inline void sd_spi_select_card() {
furi_hal_gpio_write(furi_hal_sd_spi_handle->cs, false);
furi_delay_us(10); // Entry guard time for some SD cards
}
static inline void sd_spi_deselect_card() {
furi_delay_us(10); // Exit guard time for some SD cards
furi_hal_gpio_write(furi_hal_sd_spi_handle->cs, true);
}
static void sd_spi_bus_to_ground() {
furi_hal_gpio_init_ex(
furi_hal_sd_spi_handle->miso,
GpioModeOutputPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFnUnused);
furi_hal_gpio_init_ex(
furi_hal_sd_spi_handle->mosi,
GpioModeOutputPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFnUnused);
furi_hal_gpio_init_ex(
furi_hal_sd_spi_handle->sck,
GpioModeOutputPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFnUnused);
sd_spi_select_card();
furi_hal_gpio_write(furi_hal_sd_spi_handle->miso, false);
furi_hal_gpio_write(furi_hal_sd_spi_handle->mosi, false);
furi_hal_gpio_write(furi_hal_sd_spi_handle->sck, false);
}
static void sd_spi_bus_rise_up() {
sd_spi_deselect_card();
furi_hal_gpio_init_ex(
furi_hal_sd_spi_handle->miso,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
furi_hal_gpio_init_ex(
furi_hal_sd_spi_handle->mosi,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
furi_hal_gpio_init_ex(
furi_hal_sd_spi_handle->sck,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn5SPI2);
}
static inline uint8_t sd_spi_read_byte(void) {
uint8_t responce;
furi_check(furi_hal_spi_bus_trx(furi_hal_sd_spi_handle, NULL, &responce, 1, SD_TIMEOUT_MS));
return responce;
}
static inline void sd_spi_write_byte(uint8_t data) {
furi_check(furi_hal_spi_bus_trx(furi_hal_sd_spi_handle, &data, NULL, 1, SD_TIMEOUT_MS));
}
static inline uint8_t sd_spi_write_and_read_byte(uint8_t data) {
uint8_t responce;
furi_check(furi_hal_spi_bus_trx(furi_hal_sd_spi_handle, &data, &responce, 1, SD_TIMEOUT_MS));
return responce;
}
static inline void sd_spi_write_bytes(uint8_t* data, uint32_t size) {
furi_check(furi_hal_spi_bus_trx(furi_hal_sd_spi_handle, data, NULL, size, SD_TIMEOUT_MS));
}
static inline void sd_spi_read_bytes(uint8_t* data, uint32_t size) {
furi_check(furi_hal_spi_bus_trx(furi_hal_sd_spi_handle, NULL, data, size, SD_TIMEOUT_MS));
}
static inline void sd_spi_write_bytes_dma(uint8_t* data, uint32_t size) {
uint32_t timeout_mul = (size / 512) + 1;
furi_check(furi_hal_spi_bus_trx_dma(
furi_hal_sd_spi_handle, data, NULL, size, SD_TIMEOUT_MS * timeout_mul));
}
static inline void sd_spi_read_bytes_dma(uint8_t* data, uint32_t size) {
uint32_t timeout_mul = (size / 512) + 1;
furi_check(furi_hal_spi_bus_trx_dma(
furi_hal_sd_spi_handle, NULL, data, size, SD_TIMEOUT_MS * timeout_mul));
}
static uint8_t sd_spi_wait_for_data_and_read(void) {
uint8_t retry_count = SD_ANSWER_RETRY_COUNT;
uint8_t responce;
// Wait until we get a valid data
do {
responce = sd_spi_read_byte();
retry_count--;
} while((responce == SD_DUMMY_BYTE) && retry_count);
return responce;
}
static SdSpiStatus sd_spi_wait_for_data(uint8_t data, uint32_t timeout_ms) {
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(timeout_ms * 1000);
uint8_t byte;
do {
byte = sd_spi_read_byte();
if(furi_hal_cortex_timer_is_expired(timer)) {
return SdSpiStatusTimeout;
}
} while((byte != data));
return SdSpiStatusOK;
}
static inline void sd_spi_deselect_card_and_purge() {
sd_spi_deselect_card();
sd_spi_read_byte();
}
static inline void sd_spi_purge_crc() {
sd_spi_read_byte();
sd_spi_read_byte();
}
static SdSpiCmdAnswer
sd_spi_send_cmd(SdSpiCmd cmd, uint32_t arg, uint8_t crc, SdSpiCmdAnswerType answer_type) {
uint8_t frame[SD_CMD_LENGTH];
SdSpiCmdAnswer cmd_answer = {
.r1 = SD_DUMMY_BYTE,
.r2 = SD_DUMMY_BYTE,
.r3 = SD_DUMMY_BYTE,
.r4 = SD_DUMMY_BYTE,
.r5 = SD_DUMMY_BYTE,
};
// R1 Length = NCS(0)+ 6 Bytes command + NCR(min1 max8) + 1 Bytes answer + NEC(0) = 15bytes
// R1b identical to R1 + Busy information
// R2 Length = NCS(0)+ 6 Bytes command + NCR(min1 max8) + 2 Bytes answer + NEC(0) = 16bytes
frame[0] = ((uint8_t)cmd | 0x40);
frame[1] = (uint8_t)(arg >> 24);
frame[2] = (uint8_t)(arg >> 16);
frame[3] = (uint8_t)(arg >> 8);
frame[4] = (uint8_t)(arg);
frame[5] = (crc | 0x01);
sd_spi_select_card();
sd_spi_write_bytes(frame, sizeof(frame));
switch(answer_type) {
case SdSpiCmdAnswerTypeR1:
cmd_answer.r1 = sd_spi_wait_for_data_and_read();
break;
case SdSpiCmdAnswerTypeR1B:
// TODO FL-3507: can be wrong, at least for SD_CMD12_STOP_TRANSMISSION you need to purge one byte before reading R1
cmd_answer.r1 = sd_spi_wait_for_data_and_read();
// In general this shenenigans seems suspicious, please double check SD specs if you are using SdSpiCmdAnswerTypeR1B
// reassert card
sd_spi_deselect_card();
furi_delay_us(1000);
sd_spi_deselect_card();
// and wait for it to be ready
while(sd_spi_read_byte() != 0xFF) {
};
break;
case SdSpiCmdAnswerTypeR2:
cmd_answer.r1 = sd_spi_wait_for_data_and_read();
cmd_answer.r2 = sd_spi_read_byte();
break;
case SdSpiCmdAnswerTypeR3:
case SdSpiCmdAnswerTypeR7:
cmd_answer.r1 = sd_spi_wait_for_data_and_read();
cmd_answer.r2 = sd_spi_read_byte();
cmd_answer.r3 = sd_spi_read_byte();
cmd_answer.r4 = sd_spi_read_byte();
cmd_answer.r5 = sd_spi_read_byte();
break;
default:
break;
}
return cmd_answer;
}
static SdSpiDataResponce sd_spi_get_data_response(uint32_t timeout_ms) {
SdSpiDataResponce responce = sd_spi_read_byte();
// read busy response byte
sd_spi_read_byte();
switch(responce & 0x1F) {
case SdSpiDataResponceOK:
// TODO FL-3508: check timings
sd_spi_deselect_card();
sd_spi_select_card();
// wait for 0xFF
if(sd_spi_wait_for_data(0xFF, timeout_ms) == SdSpiStatusOK) {
return SdSpiDataResponceOK;
} else {
return SdSpiDataResponceOtherError;
}
case SdSpiDataResponceCRCError:
return SdSpiDataResponceCRCError;
case SdSpiDataResponceWriteError:
return SdSpiDataResponceWriteError;
default:
return SdSpiDataResponceOtherError;
}
}
static SdSpiStatus sd_spi_init_spi_mode_v1(void) {
SdSpiCmdAnswer response;
uint8_t retry_count = 0;
sd_spi_debug("Init SD card in SPI mode v1");
do {
retry_count++;
// CMD55 (APP_CMD) before any ACMD command: R1 response (0x00: no errors)
sd_spi_send_cmd(SD_CMD55_APP_CMD, 0, 0xFF, SdSpiCmdAnswerTypeR1);
sd_spi_deselect_card_and_purge();
// ACMD41 (SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors)
response = sd_spi_send_cmd(SD_CMD41_SD_APP_OP_COND, 0, 0xFF, SdSpiCmdAnswerTypeR1);
sd_spi_deselect_card_and_purge();
if(retry_count >= SD_IDLE_RETRY_COUNT) {
return SdSpiStatusError;
}
} while(response.r1 == SdSpi_R1_IN_IDLE_STATE);
sd_spi_debug("Init SD card in SPI mode v1 done");
return SdSpiStatusOK;
}
static SdSpiStatus sd_spi_init_spi_mode_v2(void) {
SdSpiCmdAnswer response;
uint8_t retry_count = 0;
sd_spi_debug("Init SD card in SPI mode v2");
do {
retry_count++;
// CMD55 (APP_CMD) before any ACMD command: R1 response (0x00: no errors)
sd_spi_send_cmd(SD_CMD55_APP_CMD, 0, 0xFF, SdSpiCmdAnswerTypeR1);
sd_spi_deselect_card_and_purge();
// ACMD41 (APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors)
response =
sd_spi_send_cmd(SD_CMD41_SD_APP_OP_COND, 0x40000000, 0xFF, SdSpiCmdAnswerTypeR1);
sd_spi_deselect_card_and_purge();
if(retry_count >= SD_IDLE_RETRY_COUNT) {
sd_spi_debug("ACMD41 failed");
return SdSpiStatusError;
}
} while(response.r1 == SdSpi_R1_IN_IDLE_STATE);
if(FLAG_SET(response.r1, SdSpi_R1_ILLEGAL_COMMAND)) {
sd_spi_debug("ACMD41 is illegal command");
retry_count = 0;
do {
retry_count++;
// CMD55 (APP_CMD) before any ACMD command: R1 response (0x00: no errors)
response = sd_spi_send_cmd(SD_CMD55_APP_CMD, 0, 0xFF, SdSpiCmdAnswerTypeR1);
sd_spi_deselect_card_and_purge();
if(response.r1 != SdSpi_R1_IN_IDLE_STATE) {
sd_spi_debug("CMD55 failed");
return SdSpiStatusError;
}
// ACMD41 (SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors)
response = sd_spi_send_cmd(SD_CMD41_SD_APP_OP_COND, 0, 0xFF, SdSpiCmdAnswerTypeR1);
sd_spi_deselect_card_and_purge();
if(retry_count >= SD_IDLE_RETRY_COUNT) {
sd_spi_debug("ACMD41 failed");
return SdSpiStatusError;
}
} while(response.r1 == SdSpi_R1_IN_IDLE_STATE);
}
sd_spi_debug("Init SD card in SPI mode v2 done");
return SdSpiStatusOK;
}
static SdSpiStatus sd_spi_init_spi_mode(void) {
SdSpiCmdAnswer response;
uint8_t retry_count;
// CMD0 (GO_IDLE_STATE) to put SD in SPI mode and
// wait for In Idle State Response (R1 Format) equal to 0x01
retry_count = 0;
do {
retry_count++;
response = sd_spi_send_cmd(SD_CMD0_GO_IDLE_STATE, 0, 0x95, SdSpiCmdAnswerTypeR1);
sd_spi_deselect_card_and_purge();
if(retry_count >= SD_IDLE_RETRY_COUNT) {
sd_spi_debug("CMD0 failed");
return SdSpiStatusError;
}
} while(response.r1 != SdSpi_R1_IN_IDLE_STATE);
// CMD8 (SEND_IF_COND) to check the power supply status
// and wait until response (R7 Format) equal to 0xAA and
response = sd_spi_send_cmd(SD_CMD8_SEND_IF_COND, 0x1AA, 0x87, SdSpiCmdAnswerTypeR7);
sd_spi_deselect_card_and_purge();
if(FLAG_SET(response.r1, SdSpi_R1_ILLEGAL_COMMAND)) {
if(sd_spi_init_spi_mode_v1() != SdSpiStatusOK) {
sd_spi_debug("Init mode v1 failed");
return SdSpiStatusError;
}
sd_high_capacity = 0;
} else if(response.r1 == SdSpi_R1_IN_IDLE_STATE) {
if(sd_spi_init_spi_mode_v2() != SdSpiStatusOK) {
sd_spi_debug("Init mode v2 failed");
return SdSpiStatusError;
}
// CMD58 (READ_OCR) to initialize SDHC or SDXC cards: R3 response
response = sd_spi_send_cmd(SD_CMD58_READ_OCR, 0, 0xFF, SdSpiCmdAnswerTypeR3);
sd_spi_deselect_card_and_purge();
if(response.r1 != SdSpi_R1_NO_ERROR) {
sd_spi_debug("CMD58 failed");
return SdSpiStatusError;
}
sd_high_capacity = (response.r2 & 0x40) >> 6;
} else {
return SdSpiStatusError;
}
sd_spi_debug("SD card is %s", sd_high_capacity ? "SDHC or SDXC" : "SDSC");
return SdSpiStatusOK;
}
static SdSpiStatus sd_spi_get_csd(SD_CSD* csd) {
uint16_t counter = 0;
uint8_t csd_data[16];
SdSpiStatus ret = SdSpiStatusError;
SdSpiCmdAnswer response;
// CMD9 (SEND_CSD): R1 format (0x00 is no errors)
response = sd_spi_send_cmd(SD_CMD9_SEND_CSD, 0, 0xFF, SdSpiCmdAnswerTypeR1);
if(response.r1 == SdSpi_R1_NO_ERROR) {
if(sd_spi_wait_for_data(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ, SD_TIMEOUT_MS) ==
SdSpiStatusOK) {
// read CSD data
for(counter = 0; counter < 16; counter++) {
csd_data[counter] = sd_spi_read_byte();
}
sd_spi_purge_crc();
/*************************************************************************
CSD header decoding
*************************************************************************/
csd->CSDStruct = (csd_data[0] & 0xC0) >> 6;
csd->Reserved1 = csd_data[0] & 0x3F;
csd->TAAC = csd_data[1];
csd->NSAC = csd_data[2];
csd->MaxBusClkFrec = csd_data[3];
csd->CardComdClasses = (csd_data[4] << 4) | ((csd_data[5] & 0xF0) >> 4);
csd->RdBlockLen = csd_data[5] & 0x0F;
csd->PartBlockRead = (csd_data[6] & 0x80) >> 7;
csd->WrBlockMisalign = (csd_data[6] & 0x40) >> 6;
csd->RdBlockMisalign = (csd_data[6] & 0x20) >> 5;
csd->DSRImpl = (csd_data[6] & 0x10) >> 4;
/*************************************************************************
CSD v1/v2 decoding
*************************************************************************/
if(sd_high_capacity == 0) {
csd->version.v1.Reserved1 = ((csd_data[6] & 0x0C) >> 2);
csd->version.v1.DeviceSize = ((csd_data[6] & 0x03) << 10) | (csd_data[7] << 2) |
((csd_data[8] & 0xC0) >> 6);
csd->version.v1.MaxRdCurrentVDDMin = (csd_data[8] & 0x38) >> 3;
csd->version.v1.MaxRdCurrentVDDMax = (csd_data[8] & 0x07);
csd->version.v1.MaxWrCurrentVDDMin = (csd_data[9] & 0xE0) >> 5;
csd->version.v1.MaxWrCurrentVDDMax = (csd_data[9] & 0x1C) >> 2;
csd->version.v1.DeviceSizeMul = ((csd_data[9] & 0x03) << 1) |
((csd_data[10] & 0x80) >> 7);
} else {
csd->version.v2.Reserved1 = ((csd_data[6] & 0x0F) << 2) |
((csd_data[7] & 0xC0) >> 6);
csd->version.v2.DeviceSize = ((csd_data[7] & 0x3F) << 16) | (csd_data[8] << 8) |
csd_data[9];
csd->version.v2.Reserved2 = ((csd_data[10] & 0x80) >> 8);
}
csd->EraseSingleBlockEnable = (csd_data[10] & 0x40) >> 6;
csd->EraseSectorSize = ((csd_data[10] & 0x3F) << 1) | ((csd_data[11] & 0x80) >> 7);
csd->WrProtectGrSize = (csd_data[11] & 0x7F);
csd->WrProtectGrEnable = (csd_data[12] & 0x80) >> 7;
csd->Reserved2 = (csd_data[12] & 0x60) >> 5;
csd->WrSpeedFact = (csd_data[12] & 0x1C) >> 2;
csd->MaxWrBlockLen = ((csd_data[12] & 0x03) << 2) | ((csd_data[13] & 0xC0) >> 6);
csd->WriteBlockPartial = (csd_data[13] & 0x20) >> 5;
csd->Reserved3 = (csd_data[13] & 0x1F);
csd->FileFormatGrouop = (csd_data[14] & 0x80) >> 7;
csd->CopyFlag = (csd_data[14] & 0x40) >> 6;
csd->PermWrProtect = (csd_data[14] & 0x20) >> 5;
csd->TempWrProtect = (csd_data[14] & 0x10) >> 4;
csd->FileFormat = (csd_data[14] & 0x0C) >> 2;
csd->Reserved4 = (csd_data[14] & 0x03);
csd->crc = (csd_data[15] & 0xFE) >> 1;
csd->Reserved5 = (csd_data[15] & 0x01);
ret = SdSpiStatusOK;
}
}
sd_spi_deselect_card_and_purge();
return ret;
}
static SdSpiStatus sd_spi_get_cid(SD_CID* Cid) {
uint16_t counter = 0;
uint8_t cid_data[16];
SdSpiStatus ret = SdSpiStatusError;
SdSpiCmdAnswer response;
// CMD10 (SEND_CID): R1 format (0x00 is no errors)
response = sd_spi_send_cmd(SD_CMD10_SEND_CID, 0, 0xFF, SdSpiCmdAnswerTypeR1);
if(response.r1 == SdSpi_R1_NO_ERROR) {
if(sd_spi_wait_for_data(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ, SD_TIMEOUT_MS) ==
SdSpiStatusOK) {
// read CID data
for(counter = 0; counter < 16; counter++) {
cid_data[counter] = sd_spi_read_byte();
}
sd_spi_purge_crc();
Cid->ManufacturerID = cid_data[0];
memcpy(Cid->OEM_AppliID, cid_data + 1, 2);
memcpy(Cid->ProdName, cid_data + 3, 5);
Cid->ProdRev = cid_data[8];
Cid->ProdSN = cid_data[9] << 24;
Cid->ProdSN |= cid_data[10] << 16;
Cid->ProdSN |= cid_data[11] << 8;
Cid->ProdSN |= cid_data[12];
Cid->Reserved1 = (cid_data[13] & 0xF0) >> 4;
Cid->ManufactYear = (cid_data[13] & 0x0F) << 4;
Cid->ManufactYear |= (cid_data[14] & 0xF0) >> 4;
Cid->ManufactMonth = (cid_data[14] & 0x0F);
Cid->CID_CRC = (cid_data[15] & 0xFE) >> 1;
Cid->Reserved2 = 1;
ret = SdSpiStatusOK;
}
}
sd_spi_deselect_card_and_purge();
return ret;
}
static SdSpiStatus
sd_spi_cmd_read_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms) {
uint32_t block_address = address;
uint32_t offset = 0;
// CMD16 (SET_BLOCKLEN): R1 response (0x00: no errors)
SdSpiCmdAnswer response =
sd_spi_send_cmd(SD_CMD16_SET_BLOCKLEN, SD_BLOCK_SIZE, 0xFF, SdSpiCmdAnswerTypeR1);
sd_spi_deselect_card_and_purge();
if(response.r1 != SdSpi_R1_NO_ERROR) {
return SdSpiStatusError;
}
if(!sd_high_capacity) {
block_address = address * SD_BLOCK_SIZE;
}
while(blocks--) {
// CMD17 (READ_SINGLE_BLOCK): R1 response (0x00: no errors)
response =
sd_spi_send_cmd(SD_CMD17_READ_SINGLE_BLOCK, block_address, 0xFF, SdSpiCmdAnswerTypeR1);
if(response.r1 != SdSpi_R1_NO_ERROR) {
sd_spi_deselect_card_and_purge();
return SdSpiStatusError;
}
// Wait for the data start token
if(sd_spi_wait_for_data(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ, timeout_ms) ==
SdSpiStatusOK) {
// Read the data block
sd_spi_read_bytes_dma((uint8_t*)data + offset, SD_BLOCK_SIZE);
sd_spi_purge_crc();
// increase offset
offset += SD_BLOCK_SIZE;
// increase block address
if(sd_high_capacity) {
block_address += 1;
} else {
block_address += SD_BLOCK_SIZE;
}
} else {
sd_spi_deselect_card_and_purge();
return SdSpiStatusError;
}
sd_spi_deselect_card_and_purge();
}
return SdSpiStatusOK;
}
static SdSpiStatus sd_spi_cmd_write_blocks(
uint32_t* data,
uint32_t address,
uint32_t blocks,
uint32_t timeout_ms) {
uint32_t block_address = address;
uint32_t offset = 0;
// CMD16 (SET_BLOCKLEN): R1 response (0x00: no errors)
SdSpiCmdAnswer response =
sd_spi_send_cmd(SD_CMD16_SET_BLOCKLEN, SD_BLOCK_SIZE, 0xFF, SdSpiCmdAnswerTypeR1);
sd_spi_deselect_card_and_purge();
if(response.r1 != SdSpi_R1_NO_ERROR) {
return SdSpiStatusError;
}
if(!sd_high_capacity) {
block_address = address * SD_BLOCK_SIZE;
}
while(blocks--) {
// CMD24 (WRITE_SINGLE_BLOCK): R1 response (0x00: no errors)
response = sd_spi_send_cmd(
SD_CMD24_WRITE_SINGLE_BLOCK, block_address, 0xFF, SdSpiCmdAnswerTypeR1);
if(response.r1 != SdSpi_R1_NO_ERROR) {
sd_spi_deselect_card_and_purge();
return SdSpiStatusError;
}
// Send dummy byte for NWR timing : one byte between CMD_WRITE and TOKEN
// TODO FL-3509: check bytes count
sd_spi_write_byte(SD_DUMMY_BYTE);
sd_spi_write_byte(SD_DUMMY_BYTE);
// Send the data start token
sd_spi_write_byte(SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE);
sd_spi_write_bytes_dma((uint8_t*)data + offset, SD_BLOCK_SIZE);
sd_spi_purge_crc();
// Read data response
SdSpiDataResponce data_responce = sd_spi_get_data_response(timeout_ms);
sd_spi_deselect_card_and_purge();
if(data_responce != SdSpiDataResponceOK) {
return SdSpiStatusError;
}
// increase offset
offset += SD_BLOCK_SIZE;
// increase block address
if(sd_high_capacity) {
block_address += 1;
} else {
block_address += SD_BLOCK_SIZE;
}
}
return SdSpiStatusOK;
}
uint8_t sd_max_mount_retry_count() {
return 10;
}
SdSpiStatus sd_init(bool power_reset) {
// Slow speed init
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_slow);
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_slow;
// We reset card in spi_lock context, so it is safe to disturb spi bus
if(power_reset) {
sd_spi_debug("Power reset");
// disable power and set low on all bus pins
furi_hal_power_disable_external_3_3v();
sd_spi_bus_to_ground();
hal_sd_detect_set_low();
furi_delay_ms(250);
// reinit bus and enable power
sd_spi_bus_rise_up();
hal_sd_detect_init();
furi_hal_power_enable_external_3_3v();
furi_delay_ms(100);
}
SdSpiStatus status = SdSpiStatusError;
// Send 80 dummy clocks with CS high
sd_spi_deselect_card();
for(uint8_t i = 0; i < 80; i++) {
sd_spi_write_byte(SD_DUMMY_BYTE);
}
for(uint8_t i = 0; i < 128; i++) {
status = sd_spi_init_spi_mode();
if(status == SdSpiStatusOK) {
// SD initialized and init to SPI mode properly
sd_spi_debug("SD init OK after %d retries", i);
break;
}
}
furi_hal_sd_spi_handle = NULL;
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_slow);
// Init sector cache
sector_cache_init();
return status;
}
SdSpiStatus sd_get_card_state(void) {
SdSpiCmdAnswer response;
// Send CMD13 (SEND_STATUS) to get SD status
response = sd_spi_send_cmd(SD_CMD13_SEND_STATUS, 0, 0xFF, SdSpiCmdAnswerTypeR2);
sd_spi_deselect_card_and_purge();
// Return status OK if response is valid
if((response.r1 == SdSpi_R1_NO_ERROR) && (response.r2 == SdSpi_R2_NO_ERROR)) {
return SdSpiStatusOK;
}
return SdSpiStatusError;
}
SdSpiStatus sd_get_card_info(SD_CardInfo* card_info) {
SdSpiStatus status;
status = sd_spi_get_csd(&(card_info->Csd));
if(status != SdSpiStatusOK) {
return status;
}
status = sd_spi_get_cid(&(card_info->Cid));
if(status != SdSpiStatusOK) {
return status;
}
if(sd_high_capacity == 1) {
card_info->LogBlockSize = 512;
card_info->CardBlockSize = 512;
card_info->CardCapacity = ((uint64_t)card_info->Csd.version.v2.DeviceSize + 1UL) * 1024UL *
(uint64_t)card_info->LogBlockSize;
card_info->LogBlockNbr = (card_info->CardCapacity) / (card_info->LogBlockSize);
} else {
card_info->CardCapacity = (card_info->Csd.version.v1.DeviceSize + 1);
card_info->CardCapacity *= (1UL << (card_info->Csd.version.v1.DeviceSizeMul + 2));
card_info->LogBlockSize = 512;
card_info->CardBlockSize = 1UL << (card_info->Csd.RdBlockLen);
card_info->CardCapacity *= card_info->CardBlockSize;
card_info->LogBlockNbr = (card_info->CardCapacity) / (card_info->LogBlockSize);
}
return status;
}
SdSpiStatus
sd_read_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms) {
SdSpiStatus status = sd_spi_cmd_read_blocks(data, address, blocks, timeout_ms);
return status;
}
SdSpiStatus
sd_write_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms) {
SdSpiStatus status = sd_spi_cmd_write_blocks(data, address, blocks, timeout_ms);
return status;
}
SdSpiStatus sd_get_cid(SD_CID* cid) {
SdSpiStatus status;
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
memset(cid, 0, sizeof(SD_CID));
status = sd_spi_get_cid(cid);
furi_hal_sd_spi_handle = NULL;
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
return status;
}
-158
View File
@@ -1,158 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#define __IO volatile
#define SD_TIMEOUT_MS (1000)
#define SD_BLOCK_SIZE 512
typedef enum {
SdSpiStatusOK,
SdSpiStatusError,
SdSpiStatusTimeout,
} SdSpiStatus;
/**
* @brief Card Specific Data: CSD Register
*/
typedef struct {
/* Header part */
uint8_t CSDStruct : 2; /* CSD structure */
uint8_t Reserved1 : 6; /* Reserved */
uint8_t TAAC : 8; /* Data read access-time 1 */
uint8_t NSAC : 8; /* Data read access-time 2 in CLK cycles */
uint8_t MaxBusClkFrec : 8; /* Max. bus clock frequency */
uint16_t CardComdClasses : 12; /* Card command classes */
uint8_t RdBlockLen : 4; /* Max. read data block length */
uint8_t PartBlockRead : 1; /* Partial blocks for read allowed */
uint8_t WrBlockMisalign : 1; /* Write block misalignment */
uint8_t RdBlockMisalign : 1; /* Read block misalignment */
uint8_t DSRImpl : 1; /* DSR implemented */
/* v1 or v2 struct */
union csd_version {
struct {
uint8_t Reserved1 : 2; /* Reserved */
uint16_t DeviceSize : 12; /* Device Size */
uint8_t MaxRdCurrentVDDMin : 3; /* Max. read current @ VDD min */
uint8_t MaxRdCurrentVDDMax : 3; /* Max. read current @ VDD max */
uint8_t MaxWrCurrentVDDMin : 3; /* Max. write current @ VDD min */
uint8_t MaxWrCurrentVDDMax : 3; /* Max. write current @ VDD max */
uint8_t DeviceSizeMul : 3; /* Device size multiplier */
} v1;
struct {
uint8_t Reserved1 : 6; /* Reserved */
uint32_t DeviceSize : 22; /* Device Size */
uint8_t Reserved2 : 1; /* Reserved */
} v2;
} version;
uint8_t EraseSingleBlockEnable : 1; /* Erase single block enable */
uint8_t EraseSectorSize : 7; /* Erase group size multiplier */
uint8_t WrProtectGrSize : 7; /* Write protect group size */
uint8_t WrProtectGrEnable : 1; /* Write protect group enable */
uint8_t Reserved2 : 2; /* Reserved */
uint8_t WrSpeedFact : 3; /* Write speed factor */
uint8_t MaxWrBlockLen : 4; /* Max. write data block length */
uint8_t WriteBlockPartial : 1; /* Partial blocks for write allowed */
uint8_t Reserved3 : 5; /* Reserved */
uint8_t FileFormatGrouop : 1; /* File format group */
uint8_t CopyFlag : 1; /* Copy flag (OTP) */
uint8_t PermWrProtect : 1; /* Permanent write protection */
uint8_t TempWrProtect : 1; /* Temporary write protection */
uint8_t FileFormat : 2; /* File Format */
uint8_t Reserved4 : 2; /* Reserved */
uint8_t crc : 7; /* Reserved */
uint8_t Reserved5 : 1; /* always 1*/
} SD_CSD;
/**
* @brief Card Identification Data: CID Register
*/
typedef struct {
uint8_t ManufacturerID; /* ManufacturerID */
char OEM_AppliID[2]; /* OEM/Application ID */
char ProdName[5]; /* Product Name */
uint8_t ProdRev; /* Product Revision */
uint32_t ProdSN; /* Product Serial Number */
uint8_t Reserved1; /* Reserved1 */
uint8_t ManufactYear; /* Manufacturing Year */
uint8_t ManufactMonth; /* Manufacturing Month */
uint8_t CID_CRC; /* CID CRC */
uint8_t Reserved2; /* always 1 */
} SD_CID;
/**
* @brief SD Card information structure
*/
typedef struct {
SD_CSD Csd;
SD_CID Cid;
uint64_t CardCapacity; /*!< Card Capacity */
uint32_t CardBlockSize; /*!< Card Block Size */
uint32_t LogBlockNbr; /*!< Specifies the Card logical Capacity in blocks */
uint32_t LogBlockSize; /*!< Specifies logical block size in bytes */
} SD_CardInfo;
/**
* @brief SD card max mount retry count
*
* @return uint8_t
*/
uint8_t sd_max_mount_retry_count();
/**
* @brief Init sd card
*
* @param power_reset reset card power
* @return SdSpiStatus
*/
SdSpiStatus sd_init(bool power_reset);
/**
* @brief Get card state
*
* @return SdSpiStatus
*/
SdSpiStatus sd_get_card_state(void);
/**
* @brief Get card info
*
* @param card_info
* @return SdSpiStatus
*/
SdSpiStatus sd_get_card_info(SD_CardInfo* card_info);
/**
* @brief Read blocks
*
* @param data
* @param address
* @param blocks
* @param timeout_ms
* @return SdSpiStatus
*/
SdSpiStatus sd_read_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms);
/**
* @brief Write blocks
*
* @param data
* @param address
* @param blocks
* @param timeout_ms
* @return SdSpiStatus
*/
SdSpiStatus
sd_write_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms);
/**
* @brief Get card CSD register
*
* @param Cid
* @return SdSpiStatus
*/
SdSpiStatus sd_get_cid(SD_CID* cid);
+19 -191
View File
@@ -1,37 +1,8 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file user_diskio.c
* @brief This file includes a diskio driver skeleton to be completed by the user.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* USER CODE END Header */
#include "user_diskio.h"
#include <furi.h>
#include <furi_hal.h>
#include "user_diskio.h"
#include "sector_cache.h"
static DSTATUS driver_check_status(BYTE lun) {
UNUSED(lun);
DSTATUS status = 0;
if(sd_get_card_state() != SdSpiStatusOK) {
status = STA_NOINIT;
}
return status;
}
static DSTATUS driver_initialize(BYTE pdrv);
static DSTATUS driver_status(BYTE pdrv);
static DRESULT driver_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
@@ -46,79 +17,6 @@ Diskio_drvTypeDef sd_fatfs_driver = {
driver_ioctl,
};
static inline bool sd_cache_get(uint32_t address, uint32_t* data) {
uint8_t* cached_data = sector_cache_get(address);
if(cached_data) {
memcpy(data, cached_data, SD_BLOCK_SIZE);
return true;
}
return false;
}
static inline void sd_cache_put(uint32_t address, uint32_t* data) {
sector_cache_put(address, (uint8_t*)data);
}
static inline void sd_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector) {
sector_cache_invalidate_range(start_sector, end_sector);
}
static inline void sd_cache_invalidate_all() {
sector_cache_init();
}
static bool sd_device_read(uint32_t* buff, uint32_t sector, uint32_t count) {
bool result = false;
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
if(sd_read_blocks(buff, sector, count, SD_TIMEOUT_MS) == SdSpiStatusOK) {
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000);
/* wait until the read operation is finished */
result = true;
while(sd_get_card_state() != SdSpiStatusOK) {
if(furi_hal_cortex_timer_is_expired(timer)) {
result = false;
break;
}
}
}
furi_hal_sd_spi_handle = NULL;
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
return result;
}
static bool sd_device_write(uint32_t* buff, uint32_t sector, uint32_t count) {
bool result = false;
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
if(sd_write_blocks(buff, sector, count, SD_TIMEOUT_MS) == SdSpiStatusOK) {
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000);
/* wait until the Write operation is finished */
result = true;
while(sd_get_card_state() != SdSpiStatusOK) {
if(furi_hal_cortex_timer_is_expired(timer)) {
sd_cache_invalidate_all();
result = false;
break;
}
}
}
furi_hal_sd_spi_handle = NULL;
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
return result;
}
/**
* @brief Initializes a Drive
* @param pdrv: Physical drive number (0..)
@@ -135,13 +33,11 @@ static DSTATUS driver_initialize(BYTE pdrv) {
* @retval DSTATUS: Operation status
*/
static DSTATUS driver_status(BYTE pdrv) {
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
DSTATUS status = driver_check_status(pdrv);
furi_hal_sd_spi_handle = NULL;
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
UNUSED(pdrv);
DSTATUS status = 0;
if(furi_hal_sd_get_card_state() != FuriStatusOk) {
status = STA_NOINIT;
}
return status;
}
@@ -156,43 +52,8 @@ static DSTATUS driver_status(BYTE pdrv) {
*/
static DRESULT driver_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
UNUSED(pdrv);
bool result;
bool single_sector = count == 1;
if(single_sector) {
if(sd_cache_get(sector, (uint32_t*)buff)) {
return RES_OK;
}
}
result = sd_device_read((uint32_t*)buff, (uint32_t)(sector), count);
if(!result) {
uint8_t counter = sd_max_mount_retry_count();
while(result == false && counter > 0 && hal_sd_detect()) {
SdSpiStatus status;
if((counter % 2) == 0) {
// power reset sd card
status = sd_init(true);
} else {
status = sd_init(false);
}
if(status == SdSpiStatusOK) {
result = sd_device_read((uint32_t*)buff, (uint32_t)(sector), count);
}
counter--;
}
}
if(single_sector && result == true) {
sd_cache_put(sector, (uint32_t*)buff);
}
return result ? RES_OK : RES_ERROR;
FuriStatus status = furi_hal_sd_read_blocks((uint32_t*)buff, (uint32_t)(sector), count);
return status == FuriStatusOk ? RES_OK : RES_ERROR;
}
/**
@@ -205,33 +66,8 @@ static DRESULT driver_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
*/
static DRESULT driver_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
UNUSED(pdrv);
bool result;
sd_cache_invalidate_range(sector, sector + count);
result = sd_device_write((uint32_t*)buff, (uint32_t)(sector), count);
if(!result) {
uint8_t counter = sd_max_mount_retry_count();
while(result == false && counter > 0 && hal_sd_detect()) {
SdSpiStatus status;
if((counter % 2) == 0) {
// power reset sd card
status = sd_init(true);
} else {
status = sd_init(false);
}
if(status == SdSpiStatusOK) {
result = sd_device_write((uint32_t*)buff, (uint32_t)(sector), count);
}
counter--;
}
}
return result ? RES_OK : RES_ERROR;
FuriStatus status = furi_hal_sd_write_blocks((uint32_t*)buff, (uint32_t)(sector), count);
return status == FuriStatusOk ? RES_OK : RES_ERROR;
}
/**
@@ -243,12 +79,9 @@ static DRESULT driver_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT coun
*/
static DRESULT driver_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
DRESULT res = RES_ERROR;
SD_CardInfo CardInfo;
FuriHalSdInfo sd_info;
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
DSTATUS status = driver_check_status(pdrv);
DSTATUS status = driver_status(pdrv);
if(status & STA_NOINIT) return RES_NOTRDY;
switch(cmd) {
@@ -259,22 +92,22 @@ static DRESULT driver_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
/* Get number of sectors on the disk (DWORD) */
case GET_SECTOR_COUNT:
sd_get_card_info(&CardInfo);
*(DWORD*)buff = CardInfo.LogBlockNbr;
furi_hal_sd_info(&sd_info);
*(DWORD*)buff = sd_info.logical_block_count;
res = RES_OK;
break;
/* Get R/W sector size (WORD) */
case GET_SECTOR_SIZE:
sd_get_card_info(&CardInfo);
*(WORD*)buff = CardInfo.LogBlockSize;
furi_hal_sd_info(&sd_info);
*(WORD*)buff = sd_info.logical_block_size;
res = RES_OK;
break;
/* Get erase block size in unit of sector (DWORD) */
case GET_BLOCK_SIZE:
sd_get_card_info(&CardInfo);
*(DWORD*)buff = CardInfo.LogBlockSize;
furi_hal_sd_info(&sd_info);
*(DWORD*)buff = sd_info.logical_block_size;
res = RES_OK;
break;
@@ -282,10 +115,5 @@ static DRESULT driver_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
res = RES_PARERR;
}
furi_hal_sd_spi_handle = NULL;
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
return res;
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+1 -25
View File
@@ -1,37 +1,13 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file user_diskio.h
* @brief This file contains the common defines and functions prototypes for
* the user_diskio driver.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* USER CODE END Header */
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "sd_spi_io.h"
#include "fatfs/ff_gen_drv.h"
extern Diskio_drvTypeDef sd_fatfs_driver;
#ifdef __cplusplus
}
#endif
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
#endif
@@ -117,6 +117,14 @@ static void furi_hal_resources_init_input_pins(GpioMode mode) {
}
}
static void furi_hal_resources_init_gpio_pins(GpioMode mode) {
for(size_t i = 0; i < gpio_pins_count; i++) {
if(!gpio_pins[i].debug) {
furi_hal_gpio_init(gpio_pins[i].pin, mode, GpioPullNo, GpioSpeedLow);
}
}
}
void furi_hal_resources_init_early() {
furi_hal_bus_enable(FuriHalBusGPIOA);
furi_hal_bus_enable(FuriHalBusGPIOB);
@@ -161,14 +169,7 @@ void furi_hal_resources_init_early() {
furi_hal_gpio_write(&gpio_usb_dp, 0);
// External header pins
furi_hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pc3, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pb2, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pb3, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pa4, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pa6, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(&gpio_ext_pa7, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_resources_init_gpio_pins(GpioModeAnalog);
}
void furi_hal_resources_deinit_early() {
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -23,8 +23,8 @@ static FATFS* pfs = NULL;
}
static bool flipper_update_mount_sd() {
for(int i = 0; i < sd_max_mount_retry_count(); ++i) {
if(sd_init((i % 2) == 0) != SdSpiStatusOK) {
for(int i = 0; i < furi_hal_sd_max_mount_retry_count(); ++i) {
if(furi_hal_sd_init((i % 2) == 0) != FuriStatusOk) {
/* Next attempt will be without card reset, let it settle */
furi_delay_ms(1000);
continue;
@@ -51,7 +51,7 @@ static bool flipper_update_init() {
furi_hal_spi_config_init();
fatfs_init();
if(!hal_sd_detect()) {
if(!furi_hal_sd_is_present()) {
return false;
}
+67 -15
View File
@@ -4,30 +4,82 @@
* SD Card HAL API
*/
#include <stdint.h>
#include <stdbool.h>
#include <furi_hal_spi_types.h>
#include <furi.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Init SD card detect
*/
void hal_sd_detect_init(void);
typedef struct {
uint64_t capacity; /*!< total capacity in bytes */
uint32_t block_size; /*!< block size */
uint32_t logical_block_count; /*!< logical capacity in blocks */
uint32_t logical_block_size; /*!< logical block size in bytes */
/** Set SD card detect pin to low
*/
void hal_sd_detect_set_low(void);
uint8_t manufacturer_id; /*!< manufacturer ID */
char oem_id[3]; /*!< OEM ID, 2 characters + null terminator */
char product_name[6]; /*!< product name, 5 characters + null terminator */
uint8_t product_revision_major; /*!< product revision major */
uint8_t product_revision_minor; /*!< product revision minor */
uint32_t product_serial_number; /*!< product serial number */
uint8_t manufacturing_month; /*!< manufacturing month */
uint16_t manufacturing_year; /*!< manufacturing year */
} FuriHalSdInfo;
/** Get SD card status
*
* @return true if SD card present, false if SD card not present
/**
* @brief Init SD card presence detection
*/
bool hal_sd_detect(void);
void furi_hal_sd_presence_init();
/** Pointer to currently used SPI Handle */
extern FuriHalSpiBusHandle* furi_hal_sd_spi_handle;
/**
* @brief Get SD card status
* @return true if SD card is present
*/
bool furi_hal_sd_is_present();
/**
* @brief SD card max mount retry count
* @return uint8_t
*/
uint8_t furi_hal_sd_max_mount_retry_count();
/**
* @brief Init SD card
* @param power_reset reset card power
* @return FuriStatus
*/
FuriStatus furi_hal_sd_init(bool power_reset);
/**
* @brief Read blocks from SD card
* @param buff
* @param sector
* @param count
* @return FuriStatus
*/
FuriStatus furi_hal_sd_read_blocks(uint32_t* buff, uint32_t sector, uint32_t count);
/**
* @brief Write blocks to SD card
* @param buff
* @param sector
* @param count
* @return FuriStatus
*/
FuriStatus furi_hal_sd_write_blocks(const uint32_t* buff, uint32_t sector, uint32_t count);
/**
* @brief Get SD card info
* @param info
* @return FuriStatus
*/
FuriStatus furi_hal_sd_info(FuriHalSdInfo* info);
/**
* @brief Get SD card state
* @return FuriStatus
*/
FuriStatus furi_hal_sd_get_card_state();
#ifdef __cplusplus
}
+13 -2
View File
@@ -11,10 +11,21 @@ bool flipper_application_manifest_is_valid(const FlipperApplicationManifest* man
return true;
}
bool flipper_application_manifest_is_compatible(
bool flipper_application_manifest_is_too_old(
const FlipperApplicationManifest* manifest,
const ElfApiInterface* api_interface) {
if(manifest->base.api_version.major != api_interface->api_version_major /* ||
if(manifest->base.api_version.major < api_interface->api_version_major /* ||
manifest->base.api_version.minor > app->api_interface->api_version_minor */) {
return false;
}
return true;
}
bool flipper_application_manifest_is_too_new(
const FlipperApplicationManifest* manifest,
const ElfApiInterface* api_interface) {
if(manifest->base.api_version.major > api_interface->api_version_major /* ||
manifest->base.api_version.minor > app->api_interface->api_version_minor */) {
return false;
}
+18 -7
View File
@@ -54,14 +54,25 @@ typedef FlipperApplicationManifestV1 FlipperApplicationManifest;
*/
bool flipper_application_manifest_is_valid(const FlipperApplicationManifest* manifest);
/**
* @brief Check if manifest is compatible with current ELF API interface
*
* @param manifest
* @param api_interface
* @return bool
/** Check if API Version declared in manifest is older than firmware ELF API interface
*
* @param manifest The manifest
* @param api_interface The api interface
*
* @return bool
*/
bool flipper_application_manifest_is_compatible(
bool flipper_application_manifest_is_too_old(
const FlipperApplicationManifest* manifest,
const ElfApiInterface* api_interface);
/** Check if API Version declared in manifest is newer than firmware ELF API interface
*
* @param manifest The manifest
* @param api_interface The api interface
*
* @return bool
*/
bool flipper_application_manifest_is_too_new(
const FlipperApplicationManifest* manifest,
const ElfApiInterface* api_interface);
+15 -5
View File
@@ -102,9 +102,14 @@ static FlipperApplicationPreloadStatus
return FlipperApplicationPreloadStatusTargetMismatch;
}
if(!flipper_application_manifest_is_compatible(
if(!flipper_application_manifest_is_too_old(
&app->manifest, elf_file_get_api_interface(app->elf))) {
return FlipperApplicationPreloadStatusApiMismatch;
return FlipperApplicationPreloadStatusApiTooOld;
}
if(!flipper_application_manifest_is_too_new(
&app->manifest, elf_file_get_api_interface(app->elf))) {
return FlipperApplicationPreloadStatusApiTooNew;
}
return FlipperApplicationPreloadStatusSuccess;
@@ -258,7 +263,10 @@ static const char* preload_status_strings[] = {
[FlipperApplicationPreloadStatusUnspecifiedError] = "Unknown error",
[FlipperApplicationPreloadStatusInvalidFile] = "Invalid file",
[FlipperApplicationPreloadStatusInvalidManifest] = "Invalid file manifest",
[FlipperApplicationPreloadStatusApiMismatch] = "API version mismatch",
[FlipperApplicationPreloadStatusApiTooOld] =
"Update Application to use with this Firmware (ApiTooOld)",
[FlipperApplicationPreloadStatusApiTooNew] =
"Update Firmware to use with this Application (ApiTooNew)",
[FlipperApplicationPreloadStatusTargetMismatch] = "Hardware target mismatch",
};
@@ -266,7 +274,8 @@ static const char* load_status_strings[] = {
[FlipperApplicationLoadStatusSuccess] = "Success",
[FlipperApplicationLoadStatusUnspecifiedError] = "Unknown error",
[FlipperApplicationLoadStatusNoFreeMemory] = "Out of memory",
[FlipperApplicationLoadStatusMissingImports] = "Found unsatisfied imports",
[FlipperApplicationLoadStatusMissingImports] =
"Update Firmware to use with this Application (MissingImports)",
};
const char* flipper_application_preload_status_to_string(FlipperApplicationPreloadStatus status) {
@@ -330,7 +339,8 @@ bool flipper_application_load_name_and_icon(
flipper_application_preload_manifest(app, furi_string_get_cstr(path));
if(preload_res == FlipperApplicationPreloadStatusSuccess ||
preload_res == FlipperApplicationPreloadStatusApiMismatch) {
preload_res == FlipperApplicationPreloadStatusApiTooOld ||
preload_res == FlipperApplicationPreloadStatusApiTooNew) {
const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app);
if(manifest->has_icon && icon_ptr != NULL && *icon_ptr != NULL) {
memcpy(*icon_ptr, manifest->icon, FAP_MANIFEST_MAX_ICON_SIZE);
@@ -21,7 +21,8 @@ typedef enum {
FlipperApplicationPreloadStatusUnspecifiedError,
FlipperApplicationPreloadStatusInvalidFile,
FlipperApplicationPreloadStatusInvalidManifest,
FlipperApplicationPreloadStatusApiMismatch,
FlipperApplicationPreloadStatusApiTooOld,
FlipperApplicationPreloadStatusApiTooNew,
FlipperApplicationPreloadStatusTargetMismatch,
} FlipperApplicationPreloadStatus;
+1 -1
View File
@@ -65,7 +65,7 @@ const SubGhzProtocol subghz_protocol_magellan = {
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send |
SubGhzProtocolFlag_Magelan,
SubGhzProtocolFlag_Magellan,
.decoder = &subghz_protocol_magellan_decoder,
.encoder = &subghz_protocol_magellan_encoder,
+1 -1
View File
@@ -73,7 +73,7 @@ const SubGhzProtocol subghz_protocol_princeton = {
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_315 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load |
SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send | SubGhzProtocolFlag_Princeton,
.decoder = &subghz_protocol_princeton_decoder,
.encoder = &subghz_protocol_princeton_encoder,
+2 -1
View File
@@ -127,7 +127,8 @@ typedef enum {
SubGhzProtocolFlag_BinRAW = (1 << 10),
SubGhzProtocolFlag_StarLine = (1 << 11),
SubGhzProtocolFlag_AutoAlarms = (1 << 12),
SubGhzProtocolFlag_Magelan = (1 << 13),
SubGhzProtocolFlag_Magellan = (1 << 13),
SubGhzProtocolFlag_Princeton = (1 << 14),
} SubGhzProtocolFlag;
struct SubGhzProtocol {
+1 -1
View File
@@ -3,7 +3,7 @@
#include <furi_hal.h>
#define CONTRAST_ERC 31
#define CONTRAST_MGG 31
#define CONTRAST_MGG 27
uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) {
UNUSED(u8x8);
+4 -1
View File
@@ -67,7 +67,10 @@ class FlipperFormatFile:
self.writeLine("")
def writeComment(self, text: str):
self.writeLine(f"# {text}")
if text:
self.writeLine(f"# {text}")
else:
self.writeLine("#")
def getHeader(self):
if self.cursor != 0 and len(self.lines) == 0:
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env python3
from os import path
from flipper.app import App
from flipper.utils.fff import *
class Main(App):
def init(self):
# Subparsers
self.subparsers = self.parser.add_subparsers(help="sub-command help")
self.parser_cleanup = self.subparsers.add_parser(
"cleanup", help="Cleanup duplicate remotes"
)
self.parser_cleanup.add_argument("filename", type=str)
self.parser_cleanup.set_defaults(func=self.cleanup)
def cleanup(self):
f = FlipperFormatFile()
f.load(self.args.filename)
filetype, version = f.getHeader()
if filetype != "IR library file" or version != 1:
self.logger.error(f"Incorrect file type({filetype}) or version({version})")
return 1
data = []
unique = {}
while True:
try:
d = {}
d["name"] = f.readKey("name")
d["type"] = f.readKey("type")
key = None
if d["type"] == "parsed":
d["protocol"] = f.readKey("protocol")
d["address"] = f.readKey("address")
d["command"] = f.readKey("command")
key = f'{d["protocol"]}{d["address"]}{d["command"]}'
elif d["type"] == "raw":
d["frequency"] = f.readKey("frequency")
d["duty_cycle"] = f.readKey("duty_cycle")
d["data"] = f.readKey("data")
key = f'{d["frequency"]}{d["duty_cycle"]}{d["data"]}'
else:
raise Exception(f'Unknown type: {d["type"]}')
if not key in unique:
unique[key] = d
data.append(d)
else:
self.logger.warn(f"Duplicate key: {key}")
except EOFError:
break
# Form new file
f = FlipperFormatFile()
f.setHeader(filetype, version)
for i in data:
f.writeComment(None)
f.writeKey("name", i["name"])
f.writeKey("type", i["type"])
if i["type"] == "parsed":
f.writeKey("protocol", i["protocol"])
f.writeKey("address", i["address"])
f.writeKey("command", i["command"])
elif i["type"] == "raw":
f.writeKey("frequency", i["frequency"])
f.writeKey("duty_cycle", i["duty_cycle"])
f.writeKey("data", i["data"])
else:
raise Exception(f'Unknown type: {i["type"]}')
f.save(self.args.filename)
return 0
if __name__ == "__main__":
Main()()
+2 -1
View File
@@ -22,7 +22,8 @@ class Main(App):
self.parser_set = self.subparsers.add_parser("set", help="Set Option Bytes")
self._add_args(self.parser_set)
self.parser_set.set_defaults(func=self.set)
# Set command
# Recover command
self.parser_recover = self.subparsers.add_parser(
"recover", help="Recover Option Bytes"
)