diff --git a/applications/external/totp/features_config.h b/applications/external/totp/features_config.h index 15e81b28a..59a1e0ecc 100644 --- a/applications/external/totp/features_config.h +++ b/applications/external/totp/features_config.h @@ -1,3 +1,8 @@ +// Application automatic lock timeout if user IDLE. (ticks) +#ifndef TOTP_AUTO_LOCK_IDLE_TIMEOUT_SEC +#define TOTP_AUTO_LOCK_IDLE_TIMEOUT_SEC (60) +#endif + // Include Bluetooth token input automation #define TOTP_BADBT_TYPE_ENABLED diff --git a/applications/external/totp/services/crypto/crypto.c b/applications/external/totp/services/crypto/crypto.c index c9aa2bd5a..8c20fe785 100644 --- a/applications/external/totp/services/crypto/crypto.c +++ b/applications/external/totp/services/crypto/crypto.c @@ -6,10 +6,11 @@ #include "memset_s.h" #define CRYPTO_KEY_SLOT (2) -#define CRYPTO_VERIFY_KEY "FFF_Crypto_pass" #define CRYPTO_VERIFY_KEY_LENGTH (16) #define CRYPTO_ALIGNMENT_FACTOR (16) +static const char* CRYPTO_VERIFY_KEY = "FFF_Crypto_pass"; + uint8_t* totp_crypto_encrypt( const uint8_t* plain_data, const size_t plain_data_length, @@ -107,7 +108,7 @@ CryptoSeedIVResult plugin_state->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH; plugin_state->crypto_verify_data = totp_crypto_encrypt( - (uint8_t*)CRYPTO_VERIFY_KEY, + (const uint8_t*)CRYPTO_VERIFY_KEY, CRYPTO_VERIFY_KEY_LENGTH, &plugin_state->iv[0], &plugin_state->crypto_verify_data_length); @@ -122,7 +123,7 @@ CryptoSeedIVResult bool totp_crypto_verify_key(const PluginState* plugin_state) { size_t decrypted_key_length; - const uint8_t* decrypted_key = totp_crypto_decrypt( + uint8_t* decrypted_key = totp_crypto_decrypt( plugin_state->crypto_verify_data, plugin_state->crypto_verify_data_length, &plugin_state->iv[0], @@ -133,5 +134,7 @@ bool totp_crypto_verify_key(const PluginState* plugin_state) { if(decrypted_key[i] != CRYPTO_VERIFY_KEY[i]) key_valid = false; } + free(decrypted_key); + return key_valid; } diff --git a/applications/external/totp/services/idle_timeout/idle_timeout.c b/applications/external/totp/services/idle_timeout/idle_timeout.c new file mode 100644 index 000000000..9df1b5487 --- /dev/null +++ b/applications/external/totp/services/idle_timeout/idle_timeout.c @@ -0,0 +1,66 @@ +#include "idle_timeout.h" +#include +#include + +#define IDLE_TIMER_CHECK_PERIODICITY_SEC (1) +#define SEC_TO_TICKS(sec) ((sec)*1000) + +struct IdleTimeoutContext { + FuriTimer* timer; + bool activity_reported; + void* on_idle_callback_context; + IDLE_TIMEOUT_CALLBACK on_idle_callback; + uint16_t timeout_sec; + uint16_t idle_period_sec; + bool idle_handled; +}; + +static void idle_timer_callback(void* context) { + IdleTimeoutContext* instance = context; + if(instance->activity_reported) { + instance->idle_period_sec = 0; + instance->idle_handled = false; + instance->activity_reported = false; + } else if(!instance->idle_handled) { + if(instance->idle_period_sec >= instance->timeout_sec) { + instance->idle_handled = + instance->on_idle_callback(instance->on_idle_callback_context); + } else { + instance->idle_period_sec += IDLE_TIMER_CHECK_PERIODICITY_SEC; + } + } +} + +IdleTimeoutContext* idle_timeout_alloc( + uint16_t timeout_sec, + IDLE_TIMEOUT_CALLBACK on_idle_callback, + void* on_idle_callback_context) { + IdleTimeoutContext* instance = malloc(sizeof(IdleTimeoutContext)); + if(instance == NULL) return NULL; + + instance->timer = furi_timer_alloc(&idle_timer_callback, FuriTimerTypePeriodic, instance); + if(instance->timer == NULL) return NULL; + + instance->timeout_sec = timeout_sec; + instance->on_idle_callback = on_idle_callback; + instance->on_idle_callback_context = on_idle_callback_context; + return instance; +} + +void idle_timeout_start(IdleTimeoutContext* context) { + furi_timer_start(context->timer, SEC_TO_TICKS(IDLE_TIMER_CHECK_PERIODICITY_SEC)); +} + +void idle_timeout_stop(IdleTimeoutContext* context) { + furi_timer_stop(context->timer); +} + +void idle_timeout_report_activity(IdleTimeoutContext* context) { + context->activity_reported = true; +} + +void idle_timeout_free(IdleTimeoutContext* context) { + furi_timer_stop(context->timer); + furi_timer_free(context->timer); + free(context); +} diff --git a/applications/external/totp/services/idle_timeout/idle_timeout.h b/applications/external/totp/services/idle_timeout/idle_timeout.h new file mode 100644 index 000000000..12825e454 --- /dev/null +++ b/applications/external/totp/services/idle_timeout/idle_timeout.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +typedef struct IdleTimeoutContext IdleTimeoutContext; + +typedef bool (*IDLE_TIMEOUT_CALLBACK)(void* context); + +/** + * @brief Initializes a new instance of IDLE timeout + * @param timeout_sec IDLE timeout in seconds + * @param on_idle_callback callback function to trigger when IDLE timeout happened + * @param on_idle_callback_context callback function context + * @return IDLE timeout context + */ +IdleTimeoutContext* idle_timeout_alloc( + uint16_t timeout_sec, + IDLE_TIMEOUT_CALLBACK on_idle_callback, + void* on_idle_callback_context); + +/** + * @brief Starts IDLE timeout + * @param context IDLE timeout context + */ +void idle_timeout_start(IdleTimeoutContext* context); + +/** + * @brief Stops IDLE timeout + * @param context IDLE timeout context + */ +void idle_timeout_stop(IdleTimeoutContext* context); + +/** + * @brief Reports activity to IDLE timeout + * @param context IDLE timeout context + */ +void idle_timeout_report_activity(IdleTimeoutContext* context); + +/** + * @brief Disposes IDLE timeout and releases all the resources + * @param context IDLE timeout context + */ +void idle_timeout_free(IdleTimeoutContext* context); diff --git a/applications/external/totp/totp_app.c b/applications/external/totp/totp_app.c index 281f803c8..c87fdd496 100644 --- a/applications/external/totp/totp_app.c +++ b/applications/external/totp/totp_app.c @@ -17,8 +17,6 @@ #include "services/crypto/crypto.h" #include "cli/cli.h" -#define IDLE_TIMEOUT (60000) - static void render_callback(Canvas* const canvas, void* ctx) { furi_assert(ctx); PluginState* plugin_state = ctx; @@ -105,6 +103,17 @@ static bool totp_activate_initial_scene(PluginState* const plugin_state) { return true; } +static bool on_user_idle(void* context) { + PluginState* plugin_state = context; + if(plugin_state->current_scene != TotpSceneAuthentication && + plugin_state->current_scene != TotpSceneStandby) { + totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication); + return true; + } + + return false; +} + static bool totp_plugin_state_init(PluginState* const plugin_state) { plugin_state->selected_font = 0; plugin_state->gui = furi_record_open(RECORD_GUI); @@ -127,10 +136,23 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) { } #endif + if(plugin_state->pin_set) { + plugin_state->idle_timeout_context = + idle_timeout_alloc(TOTP_AUTO_LOCK_IDLE_TIMEOUT_SEC, &on_user_idle, plugin_state); + idle_timeout_start(plugin_state->idle_timeout_context); + } else { + plugin_state->idle_timeout_context = NULL; + } + return true; } static void totp_plugin_state_free(PluginState* plugin_state) { + if(plugin_state->idle_timeout_context != NULL) { + idle_timeout_stop(plugin_state->idle_timeout_context); + idle_timeout_free(plugin_state->idle_timeout_context); + } + furi_record_close(RECORD_GUI); furi_record_close(RECORD_NOTIFICATION); furi_record_close(RECORD_DIALOGS); @@ -184,14 +206,13 @@ int32_t totp_app() { PluginEvent event; bool processing = true; - uint32_t last_user_interaction_time = furi_get_tick(); while(processing) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); + FuriStatus event_status = furi_message_queue_get(event_queue, &event, FuriWaitForever); if(furi_mutex_acquire(plugin_state->mutex, FuriWaitForever) == FuriStatusOk) { if(event_status == FuriStatusOk) { - if(event.type == EventTypeKey) { - last_user_interaction_time = furi_get_tick(); + if(event.type == EventTypeKey && plugin_state->idle_timeout_context != NULL) { + idle_timeout_report_activity(plugin_state->idle_timeout_context); } if(event.type == EventForceCloseApp) { @@ -199,11 +220,6 @@ int32_t totp_app() { } else { processing = totp_scene_director_handle_event(&event, plugin_state); } - } else if( - plugin_state->pin_set && plugin_state->current_scene != TotpSceneAuthentication && - plugin_state->current_scene != TotpSceneStandby && - furi_get_tick() - last_user_interaction_time > IDLE_TIMEOUT) { - totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication); } view_port_update(view_port); diff --git a/applications/external/totp/types/plugin_state.h b/applications/external/totp/types/plugin_state.h index 97d126330..234894d58 100644 --- a/applications/external/totp/types/plugin_state.h +++ b/applications/external/totp/types/plugin_state.h @@ -6,6 +6,7 @@ #include "../features_config.h" #include "../ui/totp_scenes_enum.h" #include "../services/config/config_file_context.h" +#include "../services/idle_timeout/idle_timeout.h" #include "notification_method.h" #include "automation_method.h" #ifdef TOTP_BADBT_TYPE_ENABLED @@ -48,6 +49,9 @@ typedef struct { */ float timezone_offset; + /** + * @brief Config file context + */ ConfigFileContext* config_file_context; /** @@ -101,4 +105,9 @@ typedef struct { */ TotpBtTypeCodeWorkerContext* bt_type_code_worker_context; #endif + + /** + * @brief IDLE timeout context + */ + IdleTimeoutContext* idle_timeout_context; } PluginState; diff --git a/applications/services/dialogs/dialogs.c b/applications/services/dialogs/dialogs.c index 3908ca31b..10c08a991 100644 --- a/applications/services/dialogs/dialogs.c +++ b/applications/services/dialogs/dialogs.c @@ -9,12 +9,13 @@ void dialog_file_browser_set_basic_options( const char* extension, const Icon* icon) { options->extension = extension; + options->base_path = NULL; options->skip_assets = true; + options->hide_dot_files = true; options->icon = icon; options->hide_ext = true; options->item_loader_callback = NULL; options->item_loader_context = NULL; - options->base_path = NULL; } static DialogsApp* dialogs_app_alloc() { diff --git a/lib/infrared/encoder_decoder/infrared.c b/lib/infrared/encoder_decoder/infrared.c index fcfc5da2b..56f2c3f9e 100644 --- a/lib/infrared/encoder_decoder/infrared.c +++ b/lib/infrared/encoder_decoder/infrared.c @@ -11,6 +11,7 @@ #include "rc6/infrared_protocol_rc6.h" #include "sirc/infrared_protocol_sirc.h" #include "kaseikyo/infrared_protocol_kaseikyo.h" +#include "rca/infrared_protocol_rca.h" typedef struct { InfraredAlloc alloc; @@ -127,6 +128,20 @@ static const InfraredEncoderDecoder infrared_encoder_decoder[] = { .free = infrared_encoder_kaseikyo_free}, .get_protocol_variant = infrared_protocol_kaseikyo_get_variant, }, + { + .decoder = + {.alloc = infrared_decoder_rca_alloc, + .decode = infrared_decoder_rca_decode, + .reset = infrared_decoder_rca_reset, + .check_ready = infrared_decoder_rca_check_ready, + .free = infrared_decoder_rca_free}, + .encoder = + {.alloc = infrared_encoder_rca_alloc, + .encode = infrared_encoder_rca_encode, + .reset = infrared_encoder_rca_reset, + .free = infrared_encoder_rca_free}, + .get_protocol_variant = infrared_protocol_rca_get_variant, + }, }; static int infrared_find_index_by_protocol(InfraredProtocol protocol); diff --git a/lib/infrared/encoder_decoder/infrared.h b/lib/infrared/encoder_decoder/infrared.h index 3ab46cbbf..ada449b98 100644 --- a/lib/infrared/encoder_decoder/infrared.h +++ b/lib/infrared/encoder_decoder/infrared.h @@ -33,6 +33,7 @@ typedef enum { InfraredProtocolSIRC15, InfraredProtocolSIRC20, InfraredProtocolKaseikyo, + InfraredProtocolRCA, InfraredProtocolMAX, } InfraredProtocol; diff --git a/lib/infrared/encoder_decoder/rca/infrared_decoder_rca.c b/lib/infrared/encoder_decoder/rca/infrared_decoder_rca.c new file mode 100644 index 000000000..b6d02a38c --- /dev/null +++ b/lib/infrared/encoder_decoder/rca/infrared_decoder_rca.c @@ -0,0 +1,45 @@ +#include "infrared_protocol_rca_i.h" +#include + +InfraredMessage* infrared_decoder_rca_check_ready(void* ctx) { + return infrared_common_decoder_check_ready(ctx); +} + +bool infrared_decoder_rca_interpret(InfraredCommonDecoder* decoder) { + furi_assert(decoder); + + uint32_t* data = (void*)&decoder->data; + + uint8_t address = (*data & 0xF); + uint8_t command = (*data >> 4) & 0xFF; + uint8_t address_inverse = (*data >> 12) & 0xF; + uint8_t command_inverse = (*data >> 16) & 0xFF; + uint8_t inverse_address_inverse = (uint8_t)~address_inverse & 0xF; + uint8_t inverse_command_inverse = (uint8_t)~command_inverse; + + if((command == inverse_command_inverse) && (address == inverse_address_inverse)) { + decoder->message.protocol = InfraredProtocolRCA; + decoder->message.address = address; + decoder->message.command = command; + decoder->message.repeat = false; + return true; + } + + return false; +} + +void* infrared_decoder_rca_alloc(void) { + return infrared_common_decoder_alloc(&infrared_protocol_rca); +} + +InfraredMessage* infrared_decoder_rca_decode(void* decoder, bool level, uint32_t duration) { + return infrared_common_decode(decoder, level, duration); +} + +void infrared_decoder_rca_free(void* decoder) { + infrared_common_decoder_free(decoder); +} + +void infrared_decoder_rca_reset(void* decoder) { + infrared_common_decoder_reset(decoder); +} diff --git a/lib/infrared/encoder_decoder/rca/infrared_encoder_rca.c b/lib/infrared/encoder_decoder/rca/infrared_encoder_rca.c new file mode 100644 index 000000000..f0be4a6a9 --- /dev/null +++ b/lib/infrared/encoder_decoder/rca/infrared_encoder_rca.c @@ -0,0 +1,37 @@ +#include "infrared_protocol_rca_i.h" + +#include + +void infrared_encoder_rca_reset(void* encoder_ptr, const InfraredMessage* message) { + furi_assert(encoder_ptr); + furi_assert(message); + + InfraredCommonEncoder* encoder = encoder_ptr; + infrared_common_encoder_reset(encoder); + + uint32_t* data = (void*)encoder->data; + + uint8_t address = message->address; + uint8_t address_inverse = ~address; + uint8_t command = message->command; + uint8_t command_inverse = ~command; + + *data = address & 0xF; + *data |= command << 4; + *data |= (address_inverse & 0xF) << 12; + *data |= command_inverse << 16; + + encoder->bits_to_encode = encoder->protocol->databit_len[0]; +} + +void* infrared_encoder_rca_alloc(void) { + return infrared_common_encoder_alloc(&infrared_protocol_rca); +} + +void infrared_encoder_rca_free(void* encoder_ptr) { + infrared_common_encoder_free(encoder_ptr); +} + +InfraredStatus infrared_encoder_rca_encode(void* encoder_ptr, uint32_t* duration, bool* level) { + return infrared_common_encode(encoder_ptr, duration, level); +} diff --git a/lib/infrared/encoder_decoder/rca/infrared_protocol_rca.c b/lib/infrared/encoder_decoder/rca/infrared_protocol_rca.c new file mode 100644 index 000000000..8e1e76dbd --- /dev/null +++ b/lib/infrared/encoder_decoder/rca/infrared_protocol_rca.c @@ -0,0 +1,40 @@ +#include "infrared_protocol_rca_i.h" + +const InfraredCommonProtocolSpec infrared_protocol_rca = { + .timings = + { + .preamble_mark = INFRARED_RCA_PREAMBLE_MARK, + .preamble_space = INFRARED_RCA_PREAMBLE_SPACE, + .bit1_mark = INFRARED_RCA_BIT1_MARK, + .bit1_space = INFRARED_RCA_BIT1_SPACE, + .bit0_mark = INFRARED_RCA_BIT0_MARK, + .bit0_space = INFRARED_RCA_BIT0_SPACE, + .preamble_tolerance = INFRARED_RCA_PREAMBLE_TOLERANCE, + .bit_tolerance = INFRARED_RCA_BIT_TOLERANCE, + .silence_time = INFRARED_RCA_SILENCE, + .min_split_time = INFRARED_RCA_MIN_SPLIT_TIME, + }, + .databit_len[0] = 24, + .no_stop_bit = false, + .decode = infrared_common_decode_pdwm, + .encode = infrared_common_encode_pdwm, + .interpret = infrared_decoder_rca_interpret, + .decode_repeat = NULL, + .encode_repeat = NULL, +}; + +static const InfraredProtocolVariant infrared_protocol_variant_rca = { + .name = "RCA", + .address_length = 4, + .command_length = 8, + .frequency = INFRARED_COMMON_CARRIER_FREQUENCY, + .duty_cycle = INFRARED_COMMON_DUTY_CYCLE, + .repeat_count = INFRARED_RCA_REPEAT_COUNT_MIN, +}; + +const InfraredProtocolVariant* infrared_protocol_rca_get_variant(InfraredProtocol protocol) { + if(protocol == InfraredProtocolRCA) + return &infrared_protocol_variant_rca; + else + return NULL; +} diff --git a/lib/infrared/encoder_decoder/rca/infrared_protocol_rca.h b/lib/infrared/encoder_decoder/rca/infrared_protocol_rca.h new file mode 100644 index 000000000..d9cae48e4 --- /dev/null +++ b/lib/infrared/encoder_decoder/rca/infrared_protocol_rca.h @@ -0,0 +1,30 @@ +#pragma once + +#include "../infrared_i.h" + +/*************************************************************************************************** +* RCA protocol description +* https://www.sbprojects.net/knowledge/ir/rca.php +**************************************************************************************************** +* Preamble Preamble Pulse Distance/Width Pause Preamble Preamble +* mark space Modulation up to period repeat repeat +* mark space +* +* 4000 4000 24 bit ...8000 4000 4000 +* __________ _ _ _ _ _ _ _ _ _ _ _ _ _ ___________ +* ____ __________ _ _ _ __ __ __ _ _ __ __ _ _ ________________ ___________ +* +***************************************************************************************************/ + +void* infrared_decoder_rca_alloc(void); +void infrared_decoder_rca_reset(void* decoder); +void infrared_decoder_rca_free(void* decoder); +InfraredMessage* infrared_decoder_rca_check_ready(void* decoder); +InfraredMessage* infrared_decoder_rca_decode(void* decoder, bool level, uint32_t duration); + +void* infrared_encoder_rca_alloc(void); +InfraredStatus infrared_encoder_rca_encode(void* encoder_ptr, uint32_t* duration, bool* level); +void infrared_encoder_rca_reset(void* encoder_ptr, const InfraredMessage* message); +void infrared_encoder_rca_free(void* encoder_ptr); + +const InfraredProtocolVariant* infrared_protocol_rca_get_variant(InfraredProtocol protocol); diff --git a/lib/infrared/encoder_decoder/rca/infrared_protocol_rca_i.h b/lib/infrared/encoder_decoder/rca/infrared_protocol_rca_i.h new file mode 100644 index 000000000..9ec4fe3b1 --- /dev/null +++ b/lib/infrared/encoder_decoder/rca/infrared_protocol_rca_i.h @@ -0,0 +1,30 @@ +#pragma once + +#include "../common/infrared_common_i.h" + +#define INFRARED_RCA_PREAMBLE_MARK 4000 +#define INFRARED_RCA_PREAMBLE_SPACE 4000 +#define INFRARED_RCA_BIT1_MARK 500 +#define INFRARED_RCA_BIT1_SPACE 2000 +#define INFRARED_RCA_BIT0_MARK 500 +#define INFRARED_RCA_BIT0_SPACE 1000 +#define INFRARED_RCA_REPEAT_PERIOD 8000 +#define INFRARED_RCA_SILENCE INFRARED_RCA_REPEAT_PERIOD + +#define INFRARED_RCA_MIN_SPLIT_TIME INFRARED_RCA_REPEAT_PAUSE_MIN +#define INFRARED_RCA_REPEAT_PAUSE_MIN 4000 +#define INFRARED_RCA_REPEAT_PAUSE_MAX 150000 +#define INFRARED_RCA_REPEAT_COUNT_MIN 1 +#define INFRARED_RCA_REPEAT_MARK INFRARED_RCA_PREAMBLE_MARK +#define INFRARED_RCA_REPEAT_SPACE INFRARED_RCA_PREAMBLE_SPACE +#define INFRARED_RCA_PREAMBLE_TOLERANCE 200 // us +#define INFRARED_RCA_BIT_TOLERANCE 120 // us + +extern const InfraredCommonProtocolSpec infrared_protocol_rca; + +bool infrared_decoder_rca_interpret(InfraredCommonDecoder* decoder); +InfraredStatus infrared_decoder_rca_decode_repeat(InfraredCommonDecoder* decoder); +InfraredStatus infrared_encoder_rca_encode_repeat( + InfraredCommonEncoder* encoder, + uint32_t* duration, + bool* level);