diff --git a/applications/main/subghz/views/subghz_frequency_analyzer.c b/applications/main/subghz/views/subghz_frequency_analyzer.c index 30e44e05a..f43e88dcf 100644 --- a/applications/main/subghz/views/subghz_frequency_analyzer.c +++ b/applications/main/subghz/views/subghz_frequency_analyzer.c @@ -15,7 +15,7 @@ #define RSSI_MIN -97 #define RSSI_MAX -60 -#define RSSI_SCALE 2.5 +#define RSSI_SCALE 2.3 #define TRIGGER_STEP 1 #define MAX_HISTORY 4 @@ -50,6 +50,7 @@ typedef struct { uint32_t frequency_to_save; float rssi; uint32_t history_frequency[MAX_HISTORY]; + uint8_t history_frequency_rx_count[MAX_HISTORY]; bool signal; float rssi_last; float trigger; @@ -86,7 +87,7 @@ void subghz_frequency_analyzer_draw_rssi( for(size_t i = 0; i <= (uint8_t)rssi; i++) { if((i + 1) % 4) { column_number++; - canvas_draw_box(canvas, x + 2 * i, y - column_number, 2, 4 + column_number); + canvas_draw_box(canvas, x + 2 * i, (y + 4) - column_number, 2, column_number); } } } @@ -98,7 +99,7 @@ void subghz_frequency_analyzer_draw_rssi( } int max_x = (int)((rssi_last - RSSI_MIN) / RSSI_SCALE) * 2; //if(!(max_x % 8)) max_x -= 2; - int max_h = (int)((rssi_last - RSSI_MIN) / RSSI_SCALE) + 4; + int max_h = (int)((rssi_last - RSSI_MIN) / RSSI_SCALE) + 1; max_h -= (max_h / 4) + 3; canvas_draw_line(canvas, x + max_x + 1, y - max_h, x + max_x + 1, y + 3); } @@ -144,7 +145,12 @@ static void subghz_frequency_analyzer_history_frequency_draw( } else { canvas_draw_str(canvas, current_x, current_y, "---.---"); } - canvas_draw_str(canvas, current_x + 41, current_y, "MHz"); + if(model->history_frequency_rx_count[i] > 0) { + snprintf(buffer, sizeof(buffer), "x%d", model->history_frequency_rx_count[i]); + canvas_draw_str(canvas, current_x + 41, current_y, buffer); + } else { + canvas_draw_str(canvas, current_x + 41, current_y, "MHz"); + } if(show_frame && i == model->selected_index) { elements_frame(canvas, current_x - 2, current_y - 9, 63, 11); @@ -298,7 +304,7 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { SubGhzFrequencyAnalyzerModel * model, { frequency_to_save = model->frequency_to_save; - if(model->show_frame) { + if(model->show_frame && !model->signal) { uint32_t prev_freq_to_save = model->frequency_to_save; uint32_t frequency_candidate = model->history_frequency[model->selected_index]; if(frequency_candidate == 0 || @@ -320,6 +326,36 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { model->frequency_to_save = frequency_candidate; updated = true; } + } else if(model->show_frame && model->signal) { + uint32_t prev_freq_to_save = model->frequency_to_save; + uint32_t frequency_candidate = subghz_frequency_find_correct(model->frequency); + if(frequency_candidate == 0 || + !furi_hal_subghz_is_frequency_valid(frequency_candidate) || + prev_freq_to_save == frequency_candidate) { + frequency_candidate = 0; + } else { + frequency_candidate = subghz_frequency_find_correct(frequency_candidate); + } + if(frequency_candidate > 0 && + frequency_candidate != model->frequency_to_save) { + model->frequency_to_save = frequency_candidate; + updated = true; + } + } else if(!model->show_frame && model->signal) { + uint32_t prev_freq_to_save = model->frequency_to_save; + uint32_t frequency_candidate = subghz_frequency_find_correct(model->frequency); + if(frequency_candidate == 0 || + !furi_hal_subghz_is_frequency_valid(frequency_candidate) || + prev_freq_to_save == frequency_candidate) { + frequency_candidate = 0; + } else { + frequency_candidate = subghz_frequency_find_correct(frequency_candidate); + } + if(frequency_candidate > 0 && + frequency_candidate != model->frequency_to_save) { + model->frequency_to_save = frequency_candidate; + updated = true; + } } }, true); @@ -346,6 +382,7 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { if(subghz_frequency_analyzer_worker_is_running(instance->worker)) { subghz_frequency_analyzer_worker_stop(instance->worker); } + instance->callback(SubGhzCustomEventViewReceiverUnlock, instance->context); } } @@ -404,16 +441,26 @@ void subghz_frequency_analyzer_pair_callback( for(size_t i = 0; i < MAX_HISTORY; i++) { if(model->history_frequency[i] == normal_frequency) { in_array = true; + if(model->history_frequency[i] > 0) { + if(model->history_frequency_rx_count[i] == 0) { + model->history_frequency_rx_count[i]++; + } + model->history_frequency_rx_count[i]++; + } if(i > 0) { size_t offset = 0; + uint8_t temp_rx_count = model->history_frequency_rx_count[i]; for(size_t j = MAX_HISTORY - 1; j > 0; j--) { if(j == i) { offset++; } model->history_frequency[j] = model->history_frequency[j - offset]; + model->history_frequency_rx_count[j] = + model->history_frequency_rx_count[j - offset]; } model->history_frequency[0] = normal_frequency; + model->history_frequency_rx_count[0] = temp_rx_count; } break; @@ -425,6 +472,11 @@ void subghz_frequency_analyzer_pair_callback( model->history_frequency[2] = model->history_frequency[1]; model->history_frequency[1] = model->history_frequency[0]; model->history_frequency[0] = normal_frequency; + + model->history_frequency_rx_count[3] = model->history_frequency_rx_count[2]; + model->history_frequency_rx_count[2] = model->history_frequency_rx_count[1]; + model->history_frequency_rx_count[1] = model->history_frequency_rx_count[0]; + model->history_frequency_rx_count[0] = 0; } if(max_index < MAX_HISTORY) { @@ -506,6 +558,10 @@ void subghz_frequency_analyzer_enter(void* context) { model->history_frequency[2] = 0; model->history_frequency[1] = 0; model->history_frequency[0] = 0; + model->history_frequency_rx_count[3] = 0; + model->history_frequency_rx_count[2] = 0; + model->history_frequency_rx_count[1] = 0; + model->history_frequency_rx_count[0] = 0; model->frequency_to_save = 0; model->trigger = RSSI_MIN; }, diff --git a/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.c b/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.c index bad7c7748..c06fa8ace 100644 --- a/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.c +++ b/applications/plugins/totp/scenes/generate_token/totp_scene_generate_token.c @@ -13,19 +13,21 @@ #include "../../services/roll_value/roll_value.h" #include "../scene_director.h" #include "../token_menu/totp_scene_token_menu.h" +#include "../../services/hid_worker/hid_worker.h" #define TOKEN_LIFETIME 30 #define DIGIT_TO_CHAR(digit) ((digit) + '0') typedef struct { uint16_t current_token_index; - char last_code[9]; + char last_code[TOTP_TOKEN_DIGITS_MAX_COUNT + 1]; char* last_code_name; bool need_token_update; uint32_t last_token_gen_time; + TotpHidWorkerTypeContext* hid_worker_context; } SceneState; -static const NotificationSequence sequence_short_vibro_and_sound = { +static const NotificationSequence notification_sequence_new_token = { &message_display_backlight_on, &message_green_255, &message_vibro_on, @@ -36,6 +38,19 @@ static const NotificationSequence sequence_short_vibro_and_sound = { NULL, }; +static const NotificationSequence notification_sequence_badusb = { + &message_vibro_on, + &message_note_d5, + &message_delay_50, + &message_note_e4, + &message_delay_50, + &message_note_f3, + &message_delay_50, + &message_vibro_off, + &message_sound_off, + NULL, +}; + static void i_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount len) { uint8_t str_token_length = 0; if(len == TOTP_8_DIGITS) { @@ -137,6 +152,9 @@ void totp_scene_generate_token_activate( plugin_state->current_scene_state = scene_state; FURI_LOG_D(LOGGING_TAG, "Timezone set to: %f", (double)plugin_state->timezone_offset); update_totp_params(plugin_state); + scene_state->hid_worker_context = totp_hid_worker_start(); + scene_state->hid_worker_context->string = &scene_state->last_code[0]; + scene_state->hid_worker_context->string_length = TOTP_TOKEN_DIGITS_MAX_COUNT + 1; } void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state) { @@ -172,12 +190,13 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ scene_state->need_token_update = false; scene_state->last_token_gen_time = curr_ts; - TokenInfo* tokenInfo = + const TokenInfo* tokenInfo = (TokenInfo*)(list_element_at( plugin_state->tokens_list, scene_state->current_token_index) ->data); if(tokenInfo->token != NULL && tokenInfo->token_length > 0) { + furi_mutex_acquire(scene_state->hid_worker_context->string_sync, FuriWaitForever); size_t key_length; uint8_t* key = totp_crypto_decrypt( tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length); @@ -196,11 +215,14 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_ memset_s(key, key_length, 0, key_length); free(key); } else { + furi_mutex_acquire(scene_state->hid_worker_context->string_sync, FuriWaitForever); i_token_to_str(0, scene_state->last_code, tokenInfo->digits); } + furi_mutex_release(scene_state->hid_worker_context->string_sync); + if(is_new_token_time) { - notification_message(plugin_state->notification, &sequence_short_vibro_and_sound); + notification_message(plugin_state->notification, ¬ification_sequence_new_token); } } @@ -263,11 +285,19 @@ bool totp_scene_generate_token_handle_event( return false; } + SceneState* scene_state; + if(event->input.type == InputTypeLong && event->input.key == InputKeyDown) { + scene_state = (SceneState*)plugin_state->current_scene_state; + totp_hid_worker_notify(scene_state->hid_worker_context, TotpHidWorkerEvtType); + notification_message(plugin_state->notification, ¬ification_sequence_badusb); + return true; + } + if(event->input.type != InputTypePress) { return true; } - SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; + scene_state = (SceneState*)plugin_state->current_scene_state; switch(event->input.key) { case InputKeyUp: break; @@ -312,6 +342,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) { if(plugin_state->current_scene_state == NULL) return; SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; + totp_hid_worker_stop(scene_state->hid_worker_context); + free(scene_state); plugin_state->current_scene_state = NULL; } diff --git a/applications/plugins/totp/services/hid_worker/hid_worker.c b/applications/plugins/totp/services/hid_worker/hid_worker.c new file mode 100644 index 000000000..f57a64eb1 --- /dev/null +++ b/applications/plugins/totp/services/hid_worker/hid_worker.c @@ -0,0 +1,106 @@ +#include "hid_worker.h" + +const uint8_t hid_number_keys[10] = { + HID_KEYBOARD_0, + HID_KEYBOARD_1, + HID_KEYBOARD_2, + HID_KEYBOARD_3, + HID_KEYBOARD_4, + HID_KEYBOARD_5, + HID_KEYBOARD_6, + HID_KEYBOARD_7, + HID_KEYBOARD_8, + HID_KEYBOARD_9}; + +static void totp_hid_worker_restore_usb_mode(TotpHidWorkerTypeContext* context) { + if(context->usb_mode_prev != NULL) { + furi_hal_usb_set_config(context->usb_mode_prev, NULL); + context->usb_mode_prev = NULL; + } +} + +static void totp_hid_worker_type_code(TotpHidWorkerTypeContext* context) { + context->usb_mode_prev = furi_hal_usb_get_config(); + furi_hal_usb_unlock(); + furi_check(furi_hal_usb_set_config(&usb_hid, NULL) == true); + uint8_t i = 0; + do { + furi_delay_ms(500); + i++; + } while(!furi_hal_hid_is_connected() && i < 50); + furi_delay_ms(500); + + if(furi_hal_hid_is_connected() && + furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) { + i = 0; + while(i < context->string_length && context->string[i] != 0) { + uint8_t digit = context->string[i] - '0'; + if(digit > 9) break; + uint8_t hid_kb_key = hid_number_keys[digit]; + furi_hal_hid_kb_press(hid_kb_key); + furi_delay_ms(30); + furi_hal_hid_kb_release(hid_kb_key); + i++; + } + + furi_mutex_release(context->string_sync); + + furi_delay_ms(100); + } + + totp_hid_worker_restore_usb_mode(context); +} + +static int32_t totp_hid_worker_callback(void* context) { + ValueMutex context_mutex; + if(!init_mutex(&context_mutex, context, sizeof(TotpHidWorkerTypeContext))) { + return 251; + } + + while(true) { + uint32_t flags = furi_thread_flags_wait( + TotpHidWorkerEvtStop | TotpHidWorkerEvtType, FuriFlagWaitAny, FuriWaitForever); + furi_check((flags & FuriFlagError) == 0); //-V562 + if(flags & TotpHidWorkerEvtStop) break; + + TotpHidWorkerTypeContext* h_context = acquire_mutex_block(&context_mutex); + if(flags & TotpHidWorkerEvtType) { + totp_hid_worker_type_code(h_context); + } + + release_mutex(&context_mutex, h_context); + } + + delete_mutex(&context_mutex); + + return 0; +} + +TotpHidWorkerTypeContext* totp_hid_worker_start() { + TotpHidWorkerTypeContext* context = malloc(sizeof(TotpHidWorkerTypeContext)); + furi_check(context != NULL); + context->string_sync = furi_mutex_alloc(FuriMutexTypeNormal); + context->thread = furi_thread_alloc(); + context->usb_mode_prev = NULL; + furi_thread_set_name(context->thread, "TOTPHidWorker"); + furi_thread_set_stack_size(context->thread, 1024); + furi_thread_set_context(context->thread, context); + furi_thread_set_callback(context->thread, totp_hid_worker_callback); + furi_thread_start(context->thread); + return context; +} + +void totp_hid_worker_stop(TotpHidWorkerTypeContext* context) { + furi_assert(context); + furi_thread_flags_set(furi_thread_get_id(context->thread), TotpHidWorkerEvtStop); + furi_thread_join(context->thread); + furi_thread_free(context->thread); + furi_mutex_free(context->string_sync); + totp_hid_worker_restore_usb_mode(context); + free(context); +} + +void totp_hid_worker_notify(TotpHidWorkerTypeContext* context, TotpHidWorkerEvtFlags event) { + furi_assert(context); + furi_thread_flags_set(furi_thread_get_id(context->thread), event); +} \ No newline at end of file diff --git a/applications/plugins/totp/services/hid_worker/hid_worker.h b/applications/plugins/totp/services/hid_worker/hid_worker.h new file mode 100644 index 000000000..c14492f47 --- /dev/null +++ b/applications/plugins/totp/services/hid_worker/hid_worker.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +typedef struct { + char* string; + uint8_t string_length; + FuriThread* thread; + FuriMutex* string_sync; + FuriHalUsbInterface* usb_mode_prev; +} TotpHidWorkerTypeContext; + +typedef enum { + TotpHidWorkerEvtReserved = (1 << 0), + TotpHidWorkerEvtStop = (1 << 1), + TotpHidWorkerEvtType = (1 << 2) +} TotpHidWorkerEvtFlags; + +TotpHidWorkerTypeContext* totp_hid_worker_start(); +void totp_hid_worker_stop(TotpHidWorkerTypeContext* context); +void totp_hid_worker_notify(TotpHidWorkerTypeContext* context, TotpHidWorkerEvtFlags event); \ No newline at end of file diff --git a/applications/plugins/totp/types/token_info.h b/applications/plugins/totp/types/token_info.h index 4f1223367..6c55e095f 100644 --- a/applications/plugins/totp/types/token_info.h +++ b/applications/plugins/totp/types/token_info.h @@ -6,6 +6,8 @@ typedef enum { SHA1, SHA256, SHA512 } TokenHashAlgo; typedef enum { TOTP_6_DIGITS, TOTP_8_DIGITS } TokenDigitsCount; +#define TOTP_TOKEN_DIGITS_MAX_COUNT 8 + typedef struct { uint8_t* token; size_t token_length; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 55aa41751..dcb64978f 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,7.41,, +Version,+,7.42,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1317,7 +1317,7 @@ Function,+,furi_hal_subghz_flush_tx,void, Function,+,furi_hal_subghz_get_lqi,uint8_t, Function,+,furi_hal_subghz_get_rssi,float, Function,+,furi_hal_subghz_idle,void, -Function,+,furi_hal_subghz_init,void, +Function,-,furi_hal_subghz_init,void, Function,+,furi_hal_subghz_is_async_tx_complete,_Bool, Function,+,furi_hal_subghz_is_frequency_valid,_Bool,uint32_t Function,+,furi_hal_subghz_is_rx_data_crc_valid,_Bool, @@ -2799,25 +2799,25 @@ Function,-,subghz_protocol_decoder_power_smart_get_hash_data,uint8_t,void* Function,-,subghz_protocol_decoder_power_smart_get_string,void,"void*, FuriString*" Function,-,subghz_protocol_decoder_power_smart_reset,void,void* Function,-,subghz_protocol_decoder_power_smart_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" -Function,-,subghz_protocol_decoder_princeton_alloc,void*,SubGhzEnvironment* -Function,-,subghz_protocol_decoder_princeton_deserialize,_Bool,"void*, FlipperFormat*" -Function,-,subghz_protocol_decoder_princeton_feed,void,"void*, _Bool, uint32_t" -Function,-,subghz_protocol_decoder_princeton_free,void,void* -Function,-,subghz_protocol_decoder_princeton_get_hash_data,uint8_t,void* -Function,-,subghz_protocol_decoder_princeton_get_string,void,"void*, FuriString*" -Function,-,subghz_protocol_decoder_princeton_reset,void,void* -Function,-,subghz_protocol_decoder_princeton_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" -Function,-,subghz_protocol_decoder_raw_alloc,void*,SubGhzEnvironment* -Function,-,subghz_protocol_decoder_raw_deserialize,_Bool,"void*, FlipperFormat*" -Function,-,subghz_protocol_decoder_raw_feed,void,"void*, _Bool, uint32_t" -Function,-,subghz_protocol_decoder_raw_free,void,void* -Function,-,subghz_protocol_decoder_raw_get_hash_data,uint8_t,void* -Function,-,subghz_protocol_decoder_raw_get_string,void,"void*, FuriString*" -Function,-,subghz_protocol_decoder_raw_reset,void,void* -Function,-,subghz_protocol_decoder_raw_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" -Function,-,subghz_protocol_decoder_raw_set_auto_mode,void,"void*, _Bool" -Function,-,subghz_protocol_decoder_raw_set_rssi_threshold,void,"void*, int" -Function,-,subghz_protocol_decoder_raw_write_data,_Bool,"void*, _Bool, uint32_t" +Function,+,subghz_protocol_decoder_princeton_alloc,void*,SubGhzEnvironment* +Function,+,subghz_protocol_decoder_princeton_deserialize,_Bool,"void*, FlipperFormat*" +Function,+,subghz_protocol_decoder_princeton_feed,void,"void*, _Bool, uint32_t" +Function,+,subghz_protocol_decoder_princeton_free,void,void* +Function,+,subghz_protocol_decoder_princeton_get_hash_data,uint8_t,void* +Function,+,subghz_protocol_decoder_princeton_get_string,void,"void*, FuriString*" +Function,+,subghz_protocol_decoder_princeton_reset,void,void* +Function,+,subghz_protocol_decoder_princeton_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" +Function,+,subghz_protocol_decoder_raw_alloc,void*,SubGhzEnvironment* +Function,+,subghz_protocol_decoder_raw_deserialize,_Bool,"void*, FlipperFormat*" +Function,+,subghz_protocol_decoder_raw_feed,void,"void*, _Bool, uint32_t" +Function,+,subghz_protocol_decoder_raw_free,void,void* +Function,+,subghz_protocol_decoder_raw_get_hash_data,uint8_t,void* +Function,+,subghz_protocol_decoder_raw_get_string,void,"void*, FuriString*" +Function,+,subghz_protocol_decoder_raw_reset,void,void* +Function,+,subghz_protocol_decoder_raw_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" +Function,+,subghz_protocol_decoder_raw_set_auto_mode,void,"void*, _Bool" +Function,+,subghz_protocol_decoder_raw_set_rssi_threshold,void,"void*, int" +Function,+,subghz_protocol_decoder_raw_write_data,_Bool,"void*, _Bool, uint32_t" Function,-,subghz_protocol_decoder_scher_khan_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_decoder_scher_khan_deserialize,_Bool,"void*, FlipperFormat*" Function,-,subghz_protocol_decoder_scher_khan_feed,void,"void*, _Bool, uint32_t" @@ -2987,11 +2987,11 @@ Function,-,subghz_protocol_encoder_power_smart_deserialize,_Bool,"void*, Flipper Function,-,subghz_protocol_encoder_power_smart_free,void,void* Function,-,subghz_protocol_encoder_power_smart_stop,void,void* Function,-,subghz_protocol_encoder_power_smart_yield,LevelDuration,void* -Function,-,subghz_protocol_encoder_princeton_alloc,void*,SubGhzEnvironment* -Function,-,subghz_protocol_encoder_princeton_deserialize,_Bool,"void*, FlipperFormat*" -Function,-,subghz_protocol_encoder_princeton_free,void,void* -Function,-,subghz_protocol_encoder_princeton_stop,void,void* -Function,-,subghz_protocol_encoder_princeton_yield,LevelDuration,void* +Function,+,subghz_protocol_encoder_princeton_alloc,void*,SubGhzEnvironment* +Function,+,subghz_protocol_encoder_princeton_deserialize,_Bool,"void*, FlipperFormat*" +Function,+,subghz_protocol_encoder_princeton_free,void,void* +Function,+,subghz_protocol_encoder_princeton_stop,void,void* +Function,+,subghz_protocol_encoder_princeton_yield,LevelDuration,void* Function,+,subghz_protocol_encoder_raw_alloc,void*,SubGhzEnvironment* Function,+,subghz_protocol_encoder_raw_deserialize,_Bool,"void*, FlipperFormat*" Function,+,subghz_protocol_encoder_raw_free,void,void* @@ -4814,9 +4814,9 @@ Variable,-,subghz_protocol_power_smart_encoder,const SubGhzProtocolEncoder, Variable,-,subghz_protocol_princeton,const SubGhzProtocol, Variable,-,subghz_protocol_princeton_decoder,const SubGhzProtocolDecoder, Variable,-,subghz_protocol_princeton_encoder,const SubGhzProtocolEncoder, -Variable,-,subghz_protocol_raw,const SubGhzProtocol, -Variable,-,subghz_protocol_raw_decoder,const SubGhzProtocolDecoder, -Variable,-,subghz_protocol_raw_encoder,const SubGhzProtocolEncoder, +Variable,+,subghz_protocol_raw,const SubGhzProtocol, +Variable,+,subghz_protocol_raw_decoder,const SubGhzProtocolDecoder, +Variable,+,subghz_protocol_raw_encoder,const SubGhzProtocolEncoder, Variable,+,subghz_protocol_registry,const SubGhzProtocolRegistry, Variable,-,subghz_protocol_scher_khan,const SubGhzProtocol, Variable,-,subghz_protocol_scher_khan_decoder,const SubGhzProtocolDecoder, diff --git a/lib/subghz/protocols/princeton.h b/lib/subghz/protocols/princeton.h index f63004db4..a2a11292e 100644 --- a/lib/subghz/protocols/princeton.h +++ b/lib/subghz/protocols/princeton.h @@ -4,6 +4,10 @@ #define SUBGHZ_PROTOCOL_PRINCETON_NAME "Princeton" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct SubGhzProtocolDecoderPrinceton SubGhzProtocolDecoderPrinceton; typedef struct SubGhzProtocolEncoderPrinceton SubGhzProtocolEncoderPrinceton; @@ -105,3 +109,7 @@ bool subghz_protocol_decoder_princeton_deserialize(void* context, FlipperFormat* * @param output Resulting text */ void subghz_protocol_decoder_princeton_get_string(void* context, FuriString* output); + +#ifdef __cplusplus +} +#endif