SubGhz: add protocol BinRAW (binarization of data quantized by the minimum correlated duration) (#2322)
* SubGhz: add protocol DataRAW (binarization of data quantized by the minimum correlated duration) * SubGhz: fix name history * SubGhz: add encoder Data_RAW protocol * SubGhz: decreasing the size of the LevelDuration structure * SubGhz: history, added check that there is free RAM * SubGhz: checking for free memory, support to pass without gap * SubGhz: add running average to average the result, auto cut noise at the end of a burst * SubGhz: support for repeating sequences * SubGhz: fix secplus_v2 decoder * SubGhz: bin_RAW fix add history * SubGhz: add debug * SubGhz: debug refactoring * FURI_LOG: add FURI_LOG_RAW_x formatted string output like printf * SubGhz: fix new FURI_LOG metod * FURI_LOG: fix unit test * SubGhz: add enable/disable BinRAW protocol decoding * SubGhz: fix PVS * SubGhz: forcibly turn off the speaker when exiting SubGhz * SubGhz: adaptive adjustment to the noise level Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									71871949ec
								
							
						
					
					
						commit
						163be139eb
					
				| @ -70,7 +70,7 @@ void minunit_print_progress() { | ||||
| } | ||||
| 
 | ||||
| void minunit_print_fail(const char* str) { | ||||
|     printf(FURI_LOG_CLR_E "%s\r\n" FURI_LOG_CLR_RESET, str); | ||||
|     printf(_FURI_LOG_CLR_E "%s\r\n" _FURI_LOG_CLR_RESET, str); | ||||
| } | ||||
| 
 | ||||
| void unit_tests_cli(Cli* cli, FuriString* args, void* context) { | ||||
|  | ||||
| @ -12,7 +12,7 @@ App( | ||||
|     ], | ||||
|     provides=["subghz_start"], | ||||
|     icon="A_Sub1ghz_14", | ||||
|     stack_size=2 * 1024, | ||||
|     stack_size=3 * 1024, | ||||
|     order=10, | ||||
| ) | ||||
| 
 | ||||
|  | ||||
| @ -411,5 +411,5 @@ void subghz_scene_read_raw_on_exit(void* context) { | ||||
|     notification_message(subghz->notifications, &sequence_reset_rgb); | ||||
| 
 | ||||
|     //filter restoration
 | ||||
|     subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable); | ||||
|     subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| #include "../subghz_i.h" | ||||
| #include "../views/receiver.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| #include <lib/subghz/protocols/bin_raw.h> | ||||
| 
 | ||||
| static const NotificationSequence subghs_sequence_rx = { | ||||
|     &message_green_255, | ||||
| @ -143,6 +144,11 @@ void subghz_scene_receiver_on_enter(void* context) { | ||||
|     } | ||||
|     subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); | ||||
| 
 | ||||
|     //to use a universal decoder, we are looking for a link to it
 | ||||
|     subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( | ||||
|         subghz->txrx->receiver, SUBGHZ_PROTOCOL_BIN_RAW_NAME); | ||||
|     furi_assert(subghz->txrx->decoder_result); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver); | ||||
| } | ||||
| 
 | ||||
| @ -208,6 +214,13 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { | ||||
|             subghz_hopper_update(subghz); | ||||
|             subghz_scene_receiver_update_statusbar(subghz); | ||||
|         } | ||||
| 
 | ||||
|         //get RSSI
 | ||||
|         float rssi = furi_hal_subghz_get_rssi(); | ||||
|         subghz_receiver_rssi(subghz->subghz_receiver, rssi); | ||||
|         subghz_protocol_decoder_bin_raw_data_input_rssi( | ||||
|             (SubGhzProtocolDecoderBinRAW*)subghz->txrx->decoder_result, rssi); | ||||
| 
 | ||||
|         switch(subghz->state_notifications) { | ||||
|         case SubGhzNotificationStateRx: | ||||
|             notification_message(subghz->notifications, &sequence_blink_cyan_10); | ||||
|  | ||||
| @ -5,6 +5,7 @@ enum SubGhzSettingIndex { | ||||
|     SubGhzSettingIndexFrequency, | ||||
|     SubGhzSettingIndexHopping, | ||||
|     SubGhzSettingIndexModulation, | ||||
|     SubGhzSettingIndexBinRAW, | ||||
|     SubGhzSettingIndexSound, | ||||
|     SubGhzSettingIndexLock, | ||||
|     SubGhzSettingIndexRAWThesholdRSSI, | ||||
| @ -58,6 +59,15 @@ const uint32_t speaker_value[SPEAKER_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] = { | ||||
|     SubGhzProtocolFlag_Decodable, | ||||
|     SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_BinRAW, | ||||
| }; | ||||
| 
 | ||||
| uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) { | ||||
|     furi_assert(context); | ||||
| @ -186,6 +196,15 @@ static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { | ||||
|     subghz->txrx->speaker_state = speaker_value[index]; | ||||
| } | ||||
| 
 | ||||
| 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]); | ||||
|     subghz->txrx->filter = bin_raw_value[index]; | ||||
|     subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); | ||||
| } | ||||
| 
 | ||||
| static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) { | ||||
|     SubGhz* subghz = variable_item_get_context(item); | ||||
|     uint8_t index = variable_item_get_current_value_index(item); | ||||
| @ -254,6 +273,19 @@ void subghz_scene_receiver_config_on_enter(void* context) { | ||||
|     variable_item_set_current_value_text( | ||||
|         item, subghz_setting_get_preset_name(subghz->setting, value_index)); | ||||
| 
 | ||||
|     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != | ||||
|        SubGhzCustomEventManagerSet) { | ||||
|         item = variable_item_list_add( | ||||
|             subghz->variable_item_list, | ||||
|             "Bin_RAW:", | ||||
|             BIN_RAW_COUNT, | ||||
|             subghz_scene_receiver_config_set_bin_raw, | ||||
|             subghz); | ||||
|         value_index = value_index_uint32(subghz->txrx->filter, bin_raw_value, BIN_RAW_COUNT); | ||||
|         variable_item_set_current_value_index(item, value_index); | ||||
|         variable_item_set_current_value_text(item, bin_raw_text[value_index]); | ||||
|     } | ||||
| 
 | ||||
|     item = variable_item_list_add( | ||||
|         subghz->variable_item_list, | ||||
|         "Sound:", | ||||
|  | ||||
| @ -194,7 +194,8 @@ SubGhz* subghz_alloc() { | ||||
|     subghz_environment_set_protocol_registry( | ||||
|         subghz->txrx->environment, (void*)&subghz_protocol_registry); | ||||
|     subghz->txrx->receiver = subghz_receiver_alloc_init(subghz->txrx->environment); | ||||
|     subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable); | ||||
|     subghz->txrx->filter = SubGhzProtocolFlag_Decodable; | ||||
|     subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); | ||||
| 
 | ||||
|     subghz_worker_set_overrun_callback( | ||||
|         subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); | ||||
| @ -218,6 +219,8 @@ void subghz_free(SubGhz* subghz) { | ||||
|         subghz->rpc_ctx = NULL; | ||||
|     } | ||||
| 
 | ||||
|     subghz_speaker_off(subghz); | ||||
| 
 | ||||
|     // Packet Test
 | ||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket); | ||||
|     subghz_test_packet_free(subghz->subghz_test_packet); | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #define SUBGHZ_HISTORY_MAX 50 | ||||
| #define SUBGHZ_HISTORY_FREE_HEAP 20480 | ||||
| #define TAG "SubGhzHistory" | ||||
| 
 | ||||
| typedef struct { | ||||
| @ -121,8 +122,12 @@ FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx | ||||
| } | ||||
| bool subghz_history_get_text_space_left(SubGhzHistory* instance, FuriString* output) { | ||||
|     furi_assert(instance); | ||||
|     if(memmgr_get_free_heap() < SUBGHZ_HISTORY_FREE_HEAP) { | ||||
|         if(output != NULL) furi_string_printf(output, "    Free heap LOW"); | ||||
|         return true; | ||||
|     } | ||||
|     if(instance->last_index_write == SUBGHZ_HISTORY_MAX) { | ||||
|         if(output != NULL) furi_string_printf(output, "Memory is FULL"); | ||||
|         if(output != NULL) furi_string_printf(output, "   Memory is FULL"); | ||||
|         return true; | ||||
|     } | ||||
|     if(output != NULL) | ||||
| @ -142,6 +147,7 @@ bool subghz_history_add_to_history( | ||||
|     furi_assert(instance); | ||||
|     furi_assert(context); | ||||
| 
 | ||||
|     if(memmgr_get_free_heap() < SUBGHZ_HISTORY_FREE_HEAP) return false; | ||||
|     if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return false; | ||||
| 
 | ||||
|     SubGhzProtocolDecoderBase* decoder_base = context; | ||||
| @ -200,27 +206,31 @@ bool subghz_history_add_to_history( | ||||
|         } | ||||
|         uint8_t key_data[sizeof(uint64_t)] = {0}; | ||||
|         if(!flipper_format_read_hex(item->flipper_string, "Key", key_data, sizeof(uint64_t))) { | ||||
|             FURI_LOG_E(TAG, "Missing Key"); | ||||
|             break; | ||||
|             FURI_LOG_D(TAG, "No Key"); | ||||
|         } | ||||
|         uint64_t data = 0; | ||||
|         for(uint8_t i = 0; i < sizeof(uint64_t); i++) { | ||||
|             data = (data << 8) | key_data[i]; | ||||
|         } | ||||
|         if(!(uint32_t)(data >> 32)) { | ||||
|             furi_string_printf( | ||||
|                 item->item_str, | ||||
|                 "%s %lX", | ||||
|                 furi_string_get_cstr(instance->tmp_string), | ||||
|                 (uint32_t)(data & 0xFFFFFFFF)); | ||||
|         if(data != 0) { | ||||
|             if(!(uint32_t)(data >> 32)) { | ||||
|                 furi_string_printf( | ||||
|                     item->item_str, | ||||
|                     "%s %lX", | ||||
|                     furi_string_get_cstr(instance->tmp_string), | ||||
|                     (uint32_t)(data & 0xFFFFFFFF)); | ||||
|             } else { | ||||
|                 furi_string_printf( | ||||
|                     item->item_str, | ||||
|                     "%s %lX%08lX", | ||||
|                     furi_string_get_cstr(instance->tmp_string), | ||||
|                     (uint32_t)(data >> 32), | ||||
|                     (uint32_t)(data & 0xFFFFFFFF)); | ||||
|             } | ||||
|         } else { | ||||
|             furi_string_printf( | ||||
|                 item->item_str, | ||||
|                 "%s %lX%08lX", | ||||
|                 furi_string_get_cstr(instance->tmp_string), | ||||
|                 (uint32_t)(data >> 32), | ||||
|                 (uint32_t)(data & 0xFFFFFFFF)); | ||||
|             furi_string_printf(item->item_str, "%s", furi_string_get_cstr(instance->tmp_string)); | ||||
|         } | ||||
| 
 | ||||
|     } while(false); | ||||
| 
 | ||||
|     furi_string_free(text); | ||||
|  | ||||
| @ -45,6 +45,7 @@ struct SubGhzTxRx { | ||||
|     SubGhzEnvironment* environment; | ||||
|     SubGhzReceiver* receiver; | ||||
|     SubGhzTransmitter* transmitter; | ||||
|     SubGhzProtocolFlag filter; | ||||
|     SubGhzProtocolDecoderBase* decoder_result; | ||||
|     FlipperFormat* fff_data; | ||||
| 
 | ||||
|  | ||||
| @ -12,6 +12,8 @@ | ||||
| #define MENU_ITEMS 4u | ||||
| #define UNLOCK_CNT 3 | ||||
| 
 | ||||
| #define SUBGHZ_RAW_TRESHOLD_MIN -90.0f | ||||
| 
 | ||||
| typedef struct { | ||||
|     FuriString* item_str; | ||||
|     uint8_t type; | ||||
| @ -59,8 +61,24 @@ typedef struct { | ||||
|     uint16_t list_offset; | ||||
|     uint16_t history_item; | ||||
|     SubGhzViewReceiverBarShow bar_show; | ||||
|     uint8_t u_rssi; | ||||
| } SubGhzViewReceiverModel; | ||||
| 
 | ||||
| void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) { | ||||
|     furi_assert(instance); | ||||
|     with_view_model( | ||||
|         instance->view, | ||||
|         SubGhzViewReceiverModel * model, | ||||
|         { | ||||
|             if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { | ||||
|                 model->u_rssi = 0; | ||||
|             } else { | ||||
|                 model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); | ||||
|             } | ||||
|         }, | ||||
|         true); | ||||
| } | ||||
| 
 | ||||
| void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock lock) { | ||||
|     furi_assert(subghz_receiver); | ||||
|     subghz_receiver->lock_count = 0; | ||||
| @ -168,13 +186,22 @@ static void subghz_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool s | ||||
|     canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11); | ||||
| } | ||||
| 
 | ||||
| static void subghz_view_rssi_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { | ||||
|     for(uint8_t i = 1; i < model->u_rssi; i++) { | ||||
|         if(i % 5) { | ||||
|             canvas_draw_dot(canvas, 46 + i, 50); | ||||
|             canvas_draw_dot(canvas, 47 + i, 51); | ||||
|             canvas_draw_dot(canvas, 46 + i, 52); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_color(canvas, ColorBlack); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
| 
 | ||||
|     elements_button_left(canvas, "Config"); | ||||
|     canvas_draw_line(canvas, 46, 51, 125, 51); | ||||
| 
 | ||||
|     bool scrollbar = model->history_item > 4; | ||||
|     FuriString* str_buff; | ||||
| @ -206,11 +233,11 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { | ||||
|     if(model->history_item == 0) { | ||||
|         canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); | ||||
|         canvas_set_font(canvas, FontPrimary); | ||||
|         canvas_draw_str(canvas, 63, 46, "Scanning..."); | ||||
|         canvas_draw_line(canvas, 46, 51, 125, 51); | ||||
|         canvas_draw_str(canvas, 63, 44, "Scanning..."); | ||||
|         canvas_set_font(canvas, FontSecondary); | ||||
|     } | ||||
| 
 | ||||
|     subghz_view_rssi_draw(canvas, model); | ||||
|     switch(model->bar_show) { | ||||
|     case SubGhzViewReceiverBarShowLock: | ||||
|         canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8); | ||||
|  | ||||
| @ -8,6 +8,8 @@ typedef struct SubGhzViewReceiver SubGhzViewReceiver; | ||||
| 
 | ||||
| typedef void (*SubGhzViewReceiverCallback)(SubGhzCustomEvent event, void* context); | ||||
| 
 | ||||
| void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi); | ||||
| 
 | ||||
| void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock keyboard); | ||||
| 
 | ||||
| void subghz_view_receiver_set_callback( | ||||
|  | ||||
| @ -79,7 +79,6 @@ void subghz_frequency_analyzer_draw_rssi(Canvas* canvas, uint8_t rssi, uint8_t x | ||||
| void subghz_frequency_analyzer_draw_log_rssi(Canvas* canvas, uint8_t rssi, uint8_t x, uint8_t y) { | ||||
|     uint8_t column_height = 6; | ||||
|     if(rssi) { | ||||
|         //rssi = rssi
 | ||||
|         if(rssi > 54) rssi = 54; | ||||
|         for(uint8_t i = 1; i < rssi; i++) { | ||||
|             if(i % 5) { | ||||
|  | ||||
| @ -84,9 +84,10 @@ void subghz_view_transmitter_draw(Canvas* canvas, SubGhzViewTransmitterModel* mo | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_color(canvas, ColorBlack); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     elements_multiline_text(canvas, 0, 8, furi_string_get_cstr(model->key_str)); | ||||
|     canvas_draw_str(canvas, 78, 8, furi_string_get_cstr(model->frequency_str)); | ||||
|     canvas_draw_str(canvas, 113, 8, furi_string_get_cstr(model->preset_str)); | ||||
|     elements_multiline_text_aligned( | ||||
|         canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(model->key_str)); | ||||
|     canvas_draw_str(canvas, 78, 7, furi_string_get_cstr(model->frequency_str)); | ||||
|     canvas_draw_str(canvas, 113, 7, furi_string_get_cstr(model->preset_str)); | ||||
|     if(model->show_button) subghz_view_transmitter_button_right(canvas, "Send"); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1409,6 +1409,7 @@ Function,+,furi_kernel_unlock,int32_t, | ||||
| Function,+,furi_log_get_level,FuriLogLevel, | ||||
| Function,-,furi_log_init,void, | ||||
| Function,+,furi_log_print_format,void,"FuriLogLevel, const char*, const char*, ..." | ||||
| Function,+,furi_log_print_raw_format,void,"FuriLogLevel, const char*, ..." | ||||
| Function,+,furi_log_set_level,void,FuriLogLevel | ||||
| Function,-,furi_log_set_puts,void,FuriLogPuts | ||||
| Function,-,furi_log_set_timestamp,void,FuriLogTimestamp | ||||
| @ -2599,7 +2600,7 @@ Function,+,subghz_protocol_blocks_crc8le,uint8_t,"const uint8_t[], size_t, uint8 | ||||
| Function,+,subghz_protocol_blocks_get_bit_array,_Bool,"uint8_t[], size_t" | ||||
| Function,+,subghz_protocol_blocks_get_hash_data,uint8_t,"SubGhzBlockDecoder*, size_t" | ||||
| Function,+,subghz_protocol_blocks_get_parity,uint8_t,"uint64_t, uint8_t" | ||||
| Function,+,subghz_protocol_blocks_get_upload,size_t,"uint8_t[], size_t, LevelDuration*, size_t, uint32_t" | ||||
| Function,+,subghz_protocol_blocks_get_upload_from_bit_array,size_t,"uint8_t[], size_t, LevelDuration*, size_t, uint32_t, SubGhzProtocolBlockAlignBit" | ||||
| Function,+,subghz_protocol_blocks_lfsr_digest16,uint16_t,"const uint8_t[], size_t, uint16_t, uint16_t" | ||||
| Function,+,subghz_protocol_blocks_lfsr_digest8,uint8_t,"const uint8_t[], size_t, uint8_t, uint8_t" | ||||
| Function,+,subghz_protocol_blocks_lfsr_digest8_reflect,uint8_t,"const uint8_t[], size_t, uint8_t, uint8_t" | ||||
|  | ||||
| 
 | 
| @ -28,27 +28,27 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form | ||||
|         FuriString* string; | ||||
|         string = furi_string_alloc(); | ||||
| 
 | ||||
|         const char* color = FURI_LOG_CLR_RESET; | ||||
|         const char* color = _FURI_LOG_CLR_RESET; | ||||
|         const char* log_letter = " "; | ||||
|         switch(level) { | ||||
|         case FuriLogLevelError: | ||||
|             color = FURI_LOG_CLR_E; | ||||
|             color = _FURI_LOG_CLR_E; | ||||
|             log_letter = "E"; | ||||
|             break; | ||||
|         case FuriLogLevelWarn: | ||||
|             color = FURI_LOG_CLR_W; | ||||
|             color = _FURI_LOG_CLR_W; | ||||
|             log_letter = "W"; | ||||
|             break; | ||||
|         case FuriLogLevelInfo: | ||||
|             color = FURI_LOG_CLR_I; | ||||
|             color = _FURI_LOG_CLR_I; | ||||
|             log_letter = "I"; | ||||
|             break; | ||||
|         case FuriLogLevelDebug: | ||||
|             color = FURI_LOG_CLR_D; | ||||
|             color = _FURI_LOG_CLR_D; | ||||
|             log_letter = "D"; | ||||
|             break; | ||||
|         case FuriLogLevelTrace: | ||||
|             color = FURI_LOG_CLR_T; | ||||
|             color = _FURI_LOG_CLR_T; | ||||
|             log_letter = "T"; | ||||
|             break; | ||||
|         default: | ||||
| @ -58,7 +58,7 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form | ||||
|         // Timestamp
 | ||||
|         furi_string_printf( | ||||
|             string, | ||||
|             "%lu %s[%s][%s] " FURI_LOG_CLR_RESET, | ||||
|             "%lu %s[%s][%s] " _FURI_LOG_CLR_RESET, | ||||
|             furi_log.timestamp(), | ||||
|             color, | ||||
|             log_letter, | ||||
| @ -80,6 +80,23 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void furi_log_print_raw_format(FuriLogLevel level, const char* format, ...) { | ||||
|     if(level <= furi_log.log_level && | ||||
|        furi_mutex_acquire(furi_log.mutex, FuriWaitForever) == FuriStatusOk) { | ||||
|         FuriString* string; | ||||
|         string = furi_string_alloc(); | ||||
|         va_list args; | ||||
|         va_start(args, format); | ||||
|         furi_string_vprintf(string, format, args); | ||||
|         va_end(args); | ||||
| 
 | ||||
|         furi_log.puts(furi_string_get_cstr(string)); | ||||
|         furi_string_free(string); | ||||
| 
 | ||||
|         furi_mutex_release(furi_log.mutex); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void furi_log_set_level(FuriLogLevel level) { | ||||
|     if(level == FuriLogLevelDefault) { | ||||
|         level = FURI_LOG_LEVEL_DEFAULT; | ||||
|  | ||||
| @ -22,21 +22,21 @@ typedef enum { | ||||
|     FuriLogLevelTrace = 6, | ||||
| } FuriLogLevel; | ||||
| 
 | ||||
| #define FURI_LOG_CLR(clr) "\033[0;" clr "m" | ||||
| #define FURI_LOG_CLR_RESET "\033[0m" | ||||
| #define _FURI_LOG_CLR(clr) "\033[0;" clr "m" | ||||
| #define _FURI_LOG_CLR_RESET "\033[0m" | ||||
| 
 | ||||
| #define FURI_LOG_CLR_BLACK "30" | ||||
| #define FURI_LOG_CLR_RED "31" | ||||
| #define FURI_LOG_CLR_GREEN "32" | ||||
| #define FURI_LOG_CLR_BROWN "33" | ||||
| #define FURI_LOG_CLR_BLUE "34" | ||||
| #define FURI_LOG_CLR_PURPLE "35" | ||||
| #define _FURI_LOG_CLR_BLACK "30" | ||||
| #define _FURI_LOG_CLR_RED "31" | ||||
| #define _FURI_LOG_CLR_GREEN "32" | ||||
| #define _FURI_LOG_CLR_BROWN "33" | ||||
| #define _FURI_LOG_CLR_BLUE "34" | ||||
| #define _FURI_LOG_CLR_PURPLE "35" | ||||
| 
 | ||||
| #define FURI_LOG_CLR_E FURI_LOG_CLR(FURI_LOG_CLR_RED) | ||||
| #define FURI_LOG_CLR_W FURI_LOG_CLR(FURI_LOG_CLR_BROWN) | ||||
| #define FURI_LOG_CLR_I FURI_LOG_CLR(FURI_LOG_CLR_GREEN) | ||||
| #define FURI_LOG_CLR_D FURI_LOG_CLR(FURI_LOG_CLR_BLUE) | ||||
| #define FURI_LOG_CLR_T FURI_LOG_CLR(FURI_LOG_CLR_PURPLE) | ||||
| #define _FURI_LOG_CLR_E _FURI_LOG_CLR(_FURI_LOG_CLR_RED) | ||||
| #define _FURI_LOG_CLR_W _FURI_LOG_CLR(_FURI_LOG_CLR_BROWN) | ||||
| #define _FURI_LOG_CLR_I _FURI_LOG_CLR(_FURI_LOG_CLR_GREEN) | ||||
| #define _FURI_LOG_CLR_D _FURI_LOG_CLR(_FURI_LOG_CLR_BLUE) | ||||
| #define _FURI_LOG_CLR_T _FURI_LOG_CLR(_FURI_LOG_CLR_PURPLE) | ||||
| 
 | ||||
| typedef void (*FuriLogPuts)(const char* data); | ||||
| typedef uint32_t (*FuriLogTimestamp)(void); | ||||
| @ -54,6 +54,15 @@ void furi_log_init(); | ||||
| void furi_log_print_format(FuriLogLevel level, const char* tag, const char* format, ...) | ||||
|     _ATTRIBUTE((__format__(__printf__, 3, 4))); | ||||
| 
 | ||||
| /** Print log record
 | ||||
|  *  | ||||
|  * @param level  | ||||
|  * @param format  | ||||
|  * @param ...  | ||||
|  */ | ||||
| void furi_log_print_raw_format(FuriLogLevel level, const char* format, ...) | ||||
|     _ATTRIBUTE((__format__(__printf__, 2, 3))); | ||||
| 
 | ||||
| /** Set log level
 | ||||
|  * | ||||
|  * @param[in]  level  The level | ||||
| @ -95,6 +104,22 @@ void furi_log_set_timestamp(FuriLogTimestamp timestamp); | ||||
| #define FURI_LOG_T(tag, format, ...) \ | ||||
|     furi_log_print_format(FuriLogLevelTrace, tag, format, ##__VA_ARGS__) | ||||
| 
 | ||||
| /** Log methods
 | ||||
|  * | ||||
|  * @param      format  The raw format  | ||||
|  * @param      ...     VA Args | ||||
|  */ | ||||
| #define FURI_LOG_RAW_E(format, ...) \ | ||||
|     furi_log_print_raw_format(FuriLogLevelError, format, ##__VA_ARGS__) | ||||
| #define FURI_LOG_RAW_W(format, ...) \ | ||||
|     furi_log_print_raw_format(FuriLogLevelWarn, format, ##__VA_ARGS__) | ||||
| #define FURI_LOG_RAW_I(format, ...) \ | ||||
|     furi_log_print_raw_format(FuriLogLevelInfo, format, ##__VA_ARGS__) | ||||
| #define FURI_LOG_RAW_D(format, ...) \ | ||||
|     furi_log_print_raw_format(FuriLogLevelDebug, format, ##__VA_ARGS__) | ||||
| #define FURI_LOG_RAW_T(format, ...) \ | ||||
|     furi_log_print_raw_format(FuriLogLevelTrace, format, ##__VA_ARGS__) | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -2,6 +2,8 @@ | ||||
| #include "math.h" | ||||
| #include <core/check.h> | ||||
| 
 | ||||
| #include "furi.h" | ||||
| 
 | ||||
| #define TAG "SubGhzBlockEncoder" | ||||
| 
 | ||||
| void subghz_protocol_blocks_set_bit_array( | ||||
| @ -17,21 +19,32 @@ bool subghz_protocol_blocks_get_bit_array(uint8_t data_array[], size_t read_inde | ||||
|     return bit_read(data_array[read_index_bit >> 3], 7 - (read_index_bit & 0x7)); | ||||
| } | ||||
| 
 | ||||
| size_t subghz_protocol_blocks_get_upload( | ||||
| size_t subghz_protocol_blocks_get_upload_from_bit_array( | ||||
|     uint8_t data_array[], | ||||
|     size_t count_bit_data_array, | ||||
|     LevelDuration* upload, | ||||
|     size_t max_size_upload, | ||||
|     uint32_t duration_bit) { | ||||
|     size_t index_bit = 0; | ||||
|     uint32_t duration_bit, | ||||
|     SubGhzProtocolBlockAlignBit align_bit) { | ||||
|     size_t bias_bit = 0; | ||||
|     size_t size_upload = 0; | ||||
|     uint32_t duration = duration_bit; | ||||
| 
 | ||||
|     if(align_bit == SubGhzProtocolBlockAlignBitRight) { | ||||
|         if(count_bit_data_array & 0x7) { | ||||
|             bias_bit = 8 - (count_bit_data_array & 0x7); | ||||
|         } | ||||
|     } | ||||
|     size_t index_bit = bias_bit; | ||||
| 
 | ||||
|     bool last_bit = subghz_protocol_blocks_get_bit_array(data_array, index_bit++); | ||||
|     for(size_t i = 1; i < count_bit_data_array; i++) { | ||||
|     for(size_t i = 1 + bias_bit; i < count_bit_data_array + bias_bit; i++) { | ||||
|         if(last_bit == subghz_protocol_blocks_get_bit_array(data_array, index_bit)) { | ||||
|             duration += duration_bit; | ||||
|         } else { | ||||
|             furi_assert(max_size_upload > size_upload); | ||||
|             if(size_upload > max_size_upload) { | ||||
|                 furi_crash("SubGhz: Encoder buffer overflow"); | ||||
|             } | ||||
|             upload[size_upload++] = level_duration_make( | ||||
|                 subghz_protocol_blocks_get_bit_array(data_array, index_bit - 1), duration); | ||||
|             last_bit = !last_bit; | ||||
|  | ||||
| @ -19,6 +19,11 @@ typedef struct { | ||||
| 
 | ||||
| } SubGhzProtocolBlockEncoder; | ||||
| 
 | ||||
| typedef enum { | ||||
|     SubGhzProtocolBlockAlignBitLeft, | ||||
|     SubGhzProtocolBlockAlignBitRight, | ||||
| } SubGhzProtocolBlockAlignBit; | ||||
| 
 | ||||
| /**
 | ||||
|  * Set data bit when encoding HEX array. | ||||
|  * @param bit_value The value of the bit to be set | ||||
| @ -47,13 +52,15 @@ bool subghz_protocol_blocks_get_bit_array(uint8_t data_array[], size_t read_inde | ||||
|  * @param upload Pointer to a LevelDuration | ||||
|  * @param max_size_upload upload size, check not to overflow | ||||
|  * @param duration_bit duration 1 bit | ||||
|  * @param align_bit alignment of useful bits in an array | ||||
|  */ | ||||
| size_t subghz_protocol_blocks_get_upload( | ||||
| size_t subghz_protocol_blocks_get_upload_from_bit_array( | ||||
|     uint8_t data_array[], | ||||
|     size_t count_bit_data_array, | ||||
|     LevelDuration* upload, | ||||
|     size_t max_size_upload, | ||||
|     uint32_t duration_bit); | ||||
|     uint32_t duration_bit, | ||||
|     SubGhzProtocolBlockAlignBit align_bit); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|  | ||||
| @ -100,7 +100,7 @@ bool subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperForma | ||||
|             FURI_LOG_E(TAG, "Missing Bit"); | ||||
|             break; | ||||
|         } | ||||
|         instance->data_count_bit = (uint8_t)temp_data; | ||||
|         instance->data_count_bit = (uint16_t)temp_data; | ||||
| 
 | ||||
|         uint8_t key_data[sizeof(uint64_t)] = {0}; | ||||
|         if(!flipper_format_read_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { | ||||
|  | ||||
| @ -19,7 +19,7 @@ struct SubGhzBlockGeneric { | ||||
|     const char* protocol_name; | ||||
|     uint64_t data; | ||||
|     uint32_t serial; | ||||
|     uint8_t data_count_bit; | ||||
|     uint16_t data_count_bit; | ||||
|     uint8_t btn; | ||||
|     uint32_t cnt; | ||||
| }; | ||||
|  | ||||
							
								
								
									
										1120
									
								
								lib/subghz/protocols/bin_raw.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1120
									
								
								lib/subghz/protocols/bin_raw.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										111
									
								
								lib/subghz/protocols/bin_raw.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								lib/subghz/protocols/bin_raw.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,111 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "base.h" | ||||
| 
 | ||||
| #define SUBGHZ_PROTOCOL_BIN_RAW_NAME "BinRAW" | ||||
| 
 | ||||
| typedef struct SubGhzProtocolDecoderBinRAW SubGhzProtocolDecoderBinRAW; | ||||
| typedef struct SubGhzProtocolEncoderBinRAW SubGhzProtocolEncoderBinRAW; | ||||
| 
 | ||||
| extern const SubGhzProtocolDecoder subghz_protocol_bin_raw_decoder; | ||||
| extern const SubGhzProtocolEncoder subghz_protocol_bin_raw_encoder; | ||||
| extern const SubGhzProtocol subghz_protocol_bin_raw; | ||||
| 
 | ||||
| /**
 | ||||
|  * Allocate SubGhzProtocolEncoderBinRAW. | ||||
|  * @param environment Pointer to a SubGhzEnvironment instance | ||||
|  * @return SubGhzProtocolEncoderBinRAW* pointer to a SubGhzProtocolEncoderBinRAW instance | ||||
|  */ | ||||
| void* subghz_protocol_encoder_bin_raw_alloc(SubGhzEnvironment* environment); | ||||
| 
 | ||||
| /**
 | ||||
|  * Free SubGhzProtocolEncoderBinRAW. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderBinRAW instance | ||||
|  */ | ||||
| void subghz_protocol_encoder_bin_raw_free(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Deserialize and generating an upload to send. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderBinRAW instance | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
|  * @return true On success | ||||
|  */ | ||||
| bool subghz_protocol_encoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format); | ||||
| 
 | ||||
| /**
 | ||||
|  * Forced transmission stop. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderBinRAW instance | ||||
|  */ | ||||
| void subghz_protocol_encoder_bin_raw_stop(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Getting the level and duration of the upload to be loaded into DMA. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderBinRAW instance | ||||
|  * @return LevelDuration  | ||||
|  */ | ||||
| LevelDuration subghz_protocol_encoder_bin_raw_yield(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Allocate SubGhzProtocolDecoderBinRAW. | ||||
|  * @param environment Pointer to a SubGhzEnvironment instance | ||||
|  * @return SubGhzProtocolDecoderBinRAW* pointer to a SubGhzProtocolDecoderBinRAW instance | ||||
|  */ | ||||
| void* subghz_protocol_decoder_bin_raw_alloc(SubGhzEnvironment* environment); | ||||
| 
 | ||||
| /**
 | ||||
|  * Free SubGhzProtocolDecoderBinRAW. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance | ||||
|  */ | ||||
| void subghz_protocol_decoder_bin_raw_free(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Reset decoder SubGhzProtocolDecoderBinRAW. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance | ||||
|  */ | ||||
| void subghz_protocol_decoder_bin_raw_reset(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Parse a raw sequence of levels and durations received from the air. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance | ||||
|  * @param level Signal level true-high false-low | ||||
|  * @param duration Duration of this level in, us | ||||
|  */ | ||||
| void subghz_protocol_decoder_bin_raw_feed(void* context, bool level, uint32_t duration); | ||||
| 
 | ||||
| /**
 | ||||
|  * Getting the hash sum of the last randomly received parcel. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance | ||||
|  * @return hash Hash sum | ||||
|  */ | ||||
| uint8_t subghz_protocol_decoder_bin_raw_get_hash_data(void* context); | ||||
| 
 | ||||
| void subghz_protocol_decoder_bin_raw_data_input_rssi( | ||||
|     SubGhzProtocolDecoderBinRAW* instance, | ||||
|     float rssi); | ||||
| 
 | ||||
| /**
 | ||||
|  * Serialize data SubGhzProtocolDecoderBinRAW. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
|  * @param preset The modulation on which the signal was received, SubGhzRadioPreset | ||||
|  * @return true On success | ||||
|  */ | ||||
| bool subghz_protocol_decoder_bin_raw_serialize( | ||||
|     void* context, | ||||
|     FlipperFormat* flipper_format, | ||||
|     SubGhzRadioPreset* preset); | ||||
| 
 | ||||
| /**
 | ||||
|  * Deserialize data SubGhzProtocolDecoderBinRAW. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
|  * @return true On success | ||||
|  */ | ||||
| bool subghz_protocol_decoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format); | ||||
| 
 | ||||
| /**
 | ||||
|  * Getting a textual representation of the received data. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance | ||||
|  * @param output Resulting text | ||||
|  */ | ||||
| void subghz_protocol_decoder_bin_raw_get_string(void* context, FuriString* output); | ||||
| @ -196,12 +196,13 @@ static bool | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     instance->encoder.size_upload = subghz_protocol_blocks_get_upload( | ||||
|     instance->encoder.size_upload = subghz_protocol_blocks_get_upload_from_bit_array( | ||||
|         upload_hex_data, | ||||
|         upload_hex_count_bit, | ||||
|         instance->encoder.upload, | ||||
|         instance->encoder.size_upload, | ||||
|         subghz_protocol_chamb_code_const.te_short); | ||||
|         subghz_protocol_chamb_code_const.te_short, | ||||
|         SubGhzProtocolBlockAlignBitLeft); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @ -42,6 +42,7 @@ const SubGhzProtocol* subghz_protocol_registry_items[] = { | ||||
|     &subghz_protocol_dooya, | ||||
|     &subghz_protocol_alutech_at_4n, | ||||
|     &subghz_protocol_kinggates_stylo_4k, | ||||
|     &subghz_protocol_bin_raw, | ||||
| }; | ||||
| 
 | ||||
| const SubGhzProtocolRegistry subghz_protocol_registry = { | ||||
|  | ||||
| @ -42,5 +42,6 @@ | ||||
| #include "dooya.h" | ||||
| #include "alutech_at_4n.h" | ||||
| #include "kinggates_stylo_4k.h" | ||||
| #include "bin_raw.h" | ||||
| 
 | ||||
| extern const SubGhzProtocolRegistry subghz_protocol_registry; | ||||
|  | ||||
| @ -261,16 +261,16 @@ static bool | ||||
|     data = order << 4 | invert; | ||||
|     int k = 0; | ||||
|     for(int i = 6; i >= 0; i -= 2) { | ||||
|         roll_array[k++] = (data >> i) & 0x03; | ||||
|         if(roll_array[k] == 3) { | ||||
|         roll_array[k] = (data >> i) & 0x03; | ||||
|         if(roll_array[k++] == 3) { | ||||
|             FURI_LOG_E(TAG, "Roll_Array FAIL"); | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for(int i = 8; i >= 0; i -= 2) { | ||||
|         roll_array[k++] = (p[2] >> i) & 0x03; | ||||
|         if(roll_array[k] == 3) { | ||||
|         roll_array[k] = (p[2] >> i) & 0x03; | ||||
|         if(roll_array[k++] == 3) { | ||||
|             FURI_LOG_E(TAG, "Roll_Array FAIL"); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
| @ -64,7 +64,7 @@ void subghz_receiver_decode(SubGhzReceiver* instance, bool level, uint32_t durat | ||||
| 
 | ||||
|     for | ||||
|         M_EACH(slot, instance->slots, SubGhzReceiverSlotArray_t) { | ||||
|             if((slot->base->protocol->flag & instance->filter) == instance->filter) { | ||||
|             if((slot->base->protocol->flag & instance->filter) != 0) { | ||||
|                 slot->base->protocol->decoder->feed(slot->base, level, duration); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -90,6 +90,7 @@ typedef enum { | ||||
|     SubGhzProtocolFlag_Save = (1 << 7), | ||||
|     SubGhzProtocolFlag_Load = (1 << 8), | ||||
|     SubGhzProtocolFlag_Send = (1 << 9), | ||||
|     SubGhzProtocolFlag_BinRAW = (1 << 10), | ||||
| } SubGhzProtocolFlag; | ||||
| 
 | ||||
| typedef struct { | ||||
|  | ||||
| @ -13,8 +13,8 @@ | ||||
| #define LEVEL_DURATION_RESERVED 0x800000U | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint32_t level; | ||||
|     uint32_t duration; | ||||
|     uint32_t duration : 30; | ||||
|     uint8_t level : 2; | ||||
| } LevelDuration; | ||||
| 
 | ||||
| static inline LevelDuration level_duration_make(bool level, uint32_t duration) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Skorpionm
						Skorpionm