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:
Skorpionm 2023-02-09 08:48:06 +04:00 committed by GitHub
parent 71871949ec
commit 163be139eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1451 additions and 65 deletions

View File

@ -70,7 +70,7 @@ void minunit_print_progress() {
} }
void minunit_print_fail(const char* str) { 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) { void unit_tests_cli(Cli* cli, FuriString* args, void* context) {

View File

@ -12,7 +12,7 @@ App(
], ],
provides=["subghz_start"], provides=["subghz_start"],
icon="A_Sub1ghz_14", icon="A_Sub1ghz_14",
stack_size=2 * 1024, stack_size=3 * 1024,
order=10, order=10,
) )

View File

@ -411,5 +411,5 @@ void subghz_scene_read_raw_on_exit(void* context) {
notification_message(subghz->notifications, &sequence_reset_rgb); notification_message(subghz->notifications, &sequence_reset_rgb);
//filter restoration //filter restoration
subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable); subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter);
} }

View File

@ -1,6 +1,7 @@
#include "../subghz_i.h" #include "../subghz_i.h"
#include "../views/receiver.h" #include "../views/receiver.h"
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
#include <lib/subghz/protocols/bin_raw.h>
static const NotificationSequence subghs_sequence_rx = { static const NotificationSequence subghs_sequence_rx = {
&message_green_255, &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); 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); 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_hopper_update(subghz);
subghz_scene_receiver_update_statusbar(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) { switch(subghz->state_notifications) {
case SubGhzNotificationStateRx: case SubGhzNotificationStateRx:
notification_message(subghz->notifications, &sequence_blink_cyan_10); notification_message(subghz->notifications, &sequence_blink_cyan_10);

View File

@ -5,6 +5,7 @@ enum SubGhzSettingIndex {
SubGhzSettingIndexFrequency, SubGhzSettingIndexFrequency,
SubGhzSettingIndexHopping, SubGhzSettingIndexHopping,
SubGhzSettingIndexModulation, SubGhzSettingIndexModulation,
SubGhzSettingIndexBinRAW,
SubGhzSettingIndexSound, SubGhzSettingIndexSound,
SubGhzSettingIndexLock, SubGhzSettingIndexLock,
SubGhzSettingIndexRAWThesholdRSSI, SubGhzSettingIndexRAWThesholdRSSI,
@ -58,6 +59,15 @@ const uint32_t speaker_value[SPEAKER_COUNT] = {
SubGhzSpeakerStateShutdown, SubGhzSpeakerStateShutdown,
SubGhzSpeakerStateEnable, 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) { uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
furi_assert(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]; 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) { static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item); SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(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( variable_item_set_current_value_text(
item, subghz_setting_get_preset_name(subghz->setting, value_index)); 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( item = variable_item_list_add(
subghz->variable_item_list, subghz->variable_item_list,
"Sound:", "Sound:",

View File

@ -194,7 +194,8 @@ SubGhz* subghz_alloc() {
subghz_environment_set_protocol_registry( subghz_environment_set_protocol_registry(
subghz->txrx->environment, (void*)&subghz_protocol_registry); subghz->txrx->environment, (void*)&subghz_protocol_registry);
subghz->txrx->receiver = subghz_receiver_alloc_init(subghz->txrx->environment); 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_worker_set_overrun_callback(
subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
@ -218,6 +219,8 @@ void subghz_free(SubGhz* subghz) {
subghz->rpc_ctx = NULL; subghz->rpc_ctx = NULL;
} }
subghz_speaker_off(subghz);
// Packet Test // Packet Test
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket); view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket);
subghz_test_packet_free(subghz->subghz_test_packet); subghz_test_packet_free(subghz->subghz_test_packet);

View File

@ -5,6 +5,7 @@
#include <furi.h> #include <furi.h>
#define SUBGHZ_HISTORY_MAX 50 #define SUBGHZ_HISTORY_MAX 50
#define SUBGHZ_HISTORY_FREE_HEAP 20480
#define TAG "SubGhzHistory" #define TAG "SubGhzHistory"
typedef struct { typedef struct {
@ -121,6 +122,10 @@ FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx
} }
bool subghz_history_get_text_space_left(SubGhzHistory* instance, FuriString* output) { bool subghz_history_get_text_space_left(SubGhzHistory* instance, FuriString* output) {
furi_assert(instance); 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(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; return true;
@ -142,6 +147,7 @@ bool subghz_history_add_to_history(
furi_assert(instance); furi_assert(instance);
furi_assert(context); furi_assert(context);
if(memmgr_get_free_heap() < SUBGHZ_HISTORY_FREE_HEAP) return false;
if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return false; if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return false;
SubGhzProtocolDecoderBase* decoder_base = context; SubGhzProtocolDecoderBase* decoder_base = context;
@ -200,13 +206,13 @@ bool subghz_history_add_to_history(
} }
uint8_t key_data[sizeof(uint64_t)] = {0}; uint8_t key_data[sizeof(uint64_t)] = {0};
if(!flipper_format_read_hex(item->flipper_string, "Key", key_data, sizeof(uint64_t))) { if(!flipper_format_read_hex(item->flipper_string, "Key", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Missing Key"); FURI_LOG_D(TAG, "No Key");
break;
} }
uint64_t data = 0; uint64_t data = 0;
for(uint8_t i = 0; i < sizeof(uint64_t); i++) { for(uint8_t i = 0; i < sizeof(uint64_t); i++) {
data = (data << 8) | key_data[i]; data = (data << 8) | key_data[i];
} }
if(data != 0) {
if(!(uint32_t)(data >> 32)) { if(!(uint32_t)(data >> 32)) {
furi_string_printf( furi_string_printf(
item->item_str, item->item_str,
@ -221,6 +227,10 @@ bool subghz_history_add_to_history(
(uint32_t)(data >> 32), (uint32_t)(data >> 32),
(uint32_t)(data & 0xFFFFFFFF)); (uint32_t)(data & 0xFFFFFFFF));
} }
} else {
furi_string_printf(item->item_str, "%s", furi_string_get_cstr(instance->tmp_string));
}
} while(false); } while(false);
furi_string_free(text); furi_string_free(text);

View File

@ -45,6 +45,7 @@ struct SubGhzTxRx {
SubGhzEnvironment* environment; SubGhzEnvironment* environment;
SubGhzReceiver* receiver; SubGhzReceiver* receiver;
SubGhzTransmitter* transmitter; SubGhzTransmitter* transmitter;
SubGhzProtocolFlag filter;
SubGhzProtocolDecoderBase* decoder_result; SubGhzProtocolDecoderBase* decoder_result;
FlipperFormat* fff_data; FlipperFormat* fff_data;

View File

@ -12,6 +12,8 @@
#define MENU_ITEMS 4u #define MENU_ITEMS 4u
#define UNLOCK_CNT 3 #define UNLOCK_CNT 3
#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f
typedef struct { typedef struct {
FuriString* item_str; FuriString* item_str;
uint8_t type; uint8_t type;
@ -59,8 +61,24 @@ typedef struct {
uint16_t list_offset; uint16_t list_offset;
uint16_t history_item; uint16_t history_item;
SubGhzViewReceiverBarShow bar_show; SubGhzViewReceiverBarShow bar_show;
uint8_t u_rssi;
} SubGhzViewReceiverModel; } 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) { void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock lock) {
furi_assert(subghz_receiver); furi_assert(subghz_receiver);
subghz_receiver->lock_count = 0; 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); 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) { void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) {
canvas_clear(canvas); canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack); canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
elements_button_left(canvas, "Config"); elements_button_left(canvas, "Config");
canvas_draw_line(canvas, 46, 51, 125, 51);
bool scrollbar = model->history_item > 4; bool scrollbar = model->history_item > 4;
FuriString* str_buff; FuriString* str_buff;
@ -206,11 +233,11 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) {
if(model->history_item == 0) { if(model->history_item == 0) {
canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52);
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 63, 46, "Scanning..."); canvas_draw_str(canvas, 63, 44, "Scanning...");
canvas_draw_line(canvas, 46, 51, 125, 51);
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
} }
subghz_view_rssi_draw(canvas, model);
switch(model->bar_show) { switch(model->bar_show) {
case SubGhzViewReceiverBarShowLock: case SubGhzViewReceiverBarShowLock:
canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8); canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8);

View File

@ -8,6 +8,8 @@ typedef struct SubGhzViewReceiver SubGhzViewReceiver;
typedef void (*SubGhzViewReceiverCallback)(SubGhzCustomEvent event, void* context); 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_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock keyboard);
void subghz_view_receiver_set_callback( void subghz_view_receiver_set_callback(

View File

@ -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) { void subghz_frequency_analyzer_draw_log_rssi(Canvas* canvas, uint8_t rssi, uint8_t x, uint8_t y) {
uint8_t column_height = 6; uint8_t column_height = 6;
if(rssi) { if(rssi) {
//rssi = rssi
if(rssi > 54) rssi = 54; if(rssi > 54) rssi = 54;
for(uint8_t i = 1; i < rssi; i++) { for(uint8_t i = 1; i < rssi; i++) {
if(i % 5) { if(i % 5) {

View File

@ -84,9 +84,10 @@ void subghz_view_transmitter_draw(Canvas* canvas, SubGhzViewTransmitterModel* mo
canvas_clear(canvas); canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack); canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
elements_multiline_text(canvas, 0, 8, furi_string_get_cstr(model->key_str)); elements_multiline_text_aligned(
canvas_draw_str(canvas, 78, 8, furi_string_get_cstr(model->frequency_str)); canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(model->key_str));
canvas_draw_str(canvas, 113, 8, furi_string_get_cstr(model->preset_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"); if(model->show_button) subghz_view_transmitter_button_right(canvas, "Send");
} }

View File

@ -1409,6 +1409,7 @@ Function,+,furi_kernel_unlock,int32_t,
Function,+,furi_log_get_level,FuriLogLevel, Function,+,furi_log_get_level,FuriLogLevel,
Function,-,furi_log_init,void, Function,-,furi_log_init,void,
Function,+,furi_log_print_format,void,"FuriLogLevel, const char*, const char*, ..." 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_level,void,FuriLogLevel
Function,-,furi_log_set_puts,void,FuriLogPuts Function,-,furi_log_set_puts,void,FuriLogPuts
Function,-,furi_log_set_timestamp,void,FuriLogTimestamp 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_bit_array,_Bool,"uint8_t[], size_t"
Function,+,subghz_protocol_blocks_get_hash_data,uint8_t,"SubGhzBlockDecoder*, 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_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_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,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" Function,+,subghz_protocol_blocks_lfsr_digest8_reflect,uint8_t,"const uint8_t[], size_t, uint8_t, uint8_t"

1 entry status name type params
1409 Function + furi_log_get_level FuriLogLevel
1410 Function - furi_log_init void
1411 Function + furi_log_print_format void FuriLogLevel, const char*, const char*, ...
1412 Function + furi_log_print_raw_format void FuriLogLevel, const char*, ...
1413 Function + furi_log_set_level void FuriLogLevel
1414 Function - furi_log_set_puts void FuriLogPuts
1415 Function - furi_log_set_timestamp void FuriLogTimestamp
2600 Function + subghz_protocol_blocks_get_bit_array _Bool uint8_t[], size_t
2601 Function + subghz_protocol_blocks_get_hash_data uint8_t SubGhzBlockDecoder*, size_t
2602 Function + subghz_protocol_blocks_get_parity uint8_t uint64_t, uint8_t
2603 Function + subghz_protocol_blocks_get_upload subghz_protocol_blocks_get_upload_from_bit_array size_t uint8_t[], size_t, LevelDuration*, size_t, uint32_t uint8_t[], size_t, LevelDuration*, size_t, uint32_t, SubGhzProtocolBlockAlignBit
2604 Function + subghz_protocol_blocks_lfsr_digest16 uint16_t const uint8_t[], size_t, uint16_t, uint16_t
2605 Function + subghz_protocol_blocks_lfsr_digest8 uint8_t const uint8_t[], size_t, uint8_t, uint8_t
2606 Function + subghz_protocol_blocks_lfsr_digest8_reflect uint8_t const uint8_t[], size_t, uint8_t, uint8_t

View File

@ -28,27 +28,27 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form
FuriString* string; FuriString* string;
string = furi_string_alloc(); string = furi_string_alloc();
const char* color = FURI_LOG_CLR_RESET; const char* color = _FURI_LOG_CLR_RESET;
const char* log_letter = " "; const char* log_letter = " ";
switch(level) { switch(level) {
case FuriLogLevelError: case FuriLogLevelError:
color = FURI_LOG_CLR_E; color = _FURI_LOG_CLR_E;
log_letter = "E"; log_letter = "E";
break; break;
case FuriLogLevelWarn: case FuriLogLevelWarn:
color = FURI_LOG_CLR_W; color = _FURI_LOG_CLR_W;
log_letter = "W"; log_letter = "W";
break; break;
case FuriLogLevelInfo: case FuriLogLevelInfo:
color = FURI_LOG_CLR_I; color = _FURI_LOG_CLR_I;
log_letter = "I"; log_letter = "I";
break; break;
case FuriLogLevelDebug: case FuriLogLevelDebug:
color = FURI_LOG_CLR_D; color = _FURI_LOG_CLR_D;
log_letter = "D"; log_letter = "D";
break; break;
case FuriLogLevelTrace: case FuriLogLevelTrace:
color = FURI_LOG_CLR_T; color = _FURI_LOG_CLR_T;
log_letter = "T"; log_letter = "T";
break; break;
default: default:
@ -58,7 +58,7 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form
// Timestamp // Timestamp
furi_string_printf( furi_string_printf(
string, string,
"%lu %s[%s][%s] " FURI_LOG_CLR_RESET, "%lu %s[%s][%s] " _FURI_LOG_CLR_RESET,
furi_log.timestamp(), furi_log.timestamp(),
color, color,
log_letter, 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) { void furi_log_set_level(FuriLogLevel level) {
if(level == FuriLogLevelDefault) { if(level == FuriLogLevelDefault) {
level = FURI_LOG_LEVEL_DEFAULT; level = FURI_LOG_LEVEL_DEFAULT;

View File

@ -22,21 +22,21 @@ typedef enum {
FuriLogLevelTrace = 6, FuriLogLevelTrace = 6,
} FuriLogLevel; } FuriLogLevel;
#define FURI_LOG_CLR(clr) "\033[0;" clr "m" #define _FURI_LOG_CLR(clr) "\033[0;" clr "m"
#define FURI_LOG_CLR_RESET "\033[0m" #define _FURI_LOG_CLR_RESET "\033[0m"
#define FURI_LOG_CLR_BLACK "30" #define _FURI_LOG_CLR_BLACK "30"
#define FURI_LOG_CLR_RED "31" #define _FURI_LOG_CLR_RED "31"
#define FURI_LOG_CLR_GREEN "32" #define _FURI_LOG_CLR_GREEN "32"
#define FURI_LOG_CLR_BROWN "33" #define _FURI_LOG_CLR_BROWN "33"
#define FURI_LOG_CLR_BLUE "34" #define _FURI_LOG_CLR_BLUE "34"
#define FURI_LOG_CLR_PURPLE "35" #define _FURI_LOG_CLR_PURPLE "35"
#define FURI_LOG_CLR_E FURI_LOG_CLR(FURI_LOG_CLR_RED) #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_W _FURI_LOG_CLR(_FURI_LOG_CLR_BROWN)
#define FURI_LOG_CLR_I FURI_LOG_CLR(FURI_LOG_CLR_GREEN) #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_D _FURI_LOG_CLR(_FURI_LOG_CLR_BLUE)
#define FURI_LOG_CLR_T FURI_LOG_CLR(FURI_LOG_CLR_PURPLE) #define _FURI_LOG_CLR_T _FURI_LOG_CLR(_FURI_LOG_CLR_PURPLE)
typedef void (*FuriLogPuts)(const char* data); typedef void (*FuriLogPuts)(const char* data);
typedef uint32_t (*FuriLogTimestamp)(void); 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, ...) void furi_log_print_format(FuriLogLevel level, const char* tag, const char* format, ...)
_ATTRIBUTE((__format__(__printf__, 3, 4))); _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 /** Set log level
* *
* @param[in] level The level * @param[in] level The level
@ -95,6 +104,22 @@ void furi_log_set_timestamp(FuriLogTimestamp timestamp);
#define FURI_LOG_T(tag, format, ...) \ #define FURI_LOG_T(tag, format, ...) \
furi_log_print_format(FuriLogLevelTrace, tag, format, ##__VA_ARGS__) 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -2,6 +2,8 @@
#include "math.h" #include "math.h"
#include <core/check.h> #include <core/check.h>
#include "furi.h"
#define TAG "SubGhzBlockEncoder" #define TAG "SubGhzBlockEncoder"
void subghz_protocol_blocks_set_bit_array( 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)); 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[], uint8_t data_array[],
size_t count_bit_data_array, size_t count_bit_data_array,
LevelDuration* upload, LevelDuration* upload,
size_t max_size_upload, size_t max_size_upload,
uint32_t duration_bit) { uint32_t duration_bit,
size_t index_bit = 0; SubGhzProtocolBlockAlignBit align_bit) {
size_t bias_bit = 0;
size_t size_upload = 0; size_t size_upload = 0;
uint32_t duration = duration_bit; 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++); 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)) { if(last_bit == subghz_protocol_blocks_get_bit_array(data_array, index_bit)) {
duration += duration_bit; duration += duration_bit;
} else { } 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( upload[size_upload++] = level_duration_make(
subghz_protocol_blocks_get_bit_array(data_array, index_bit - 1), duration); subghz_protocol_blocks_get_bit_array(data_array, index_bit - 1), duration);
last_bit = !last_bit; last_bit = !last_bit;

View File

@ -19,6 +19,11 @@ typedef struct {
} SubGhzProtocolBlockEncoder; } SubGhzProtocolBlockEncoder;
typedef enum {
SubGhzProtocolBlockAlignBitLeft,
SubGhzProtocolBlockAlignBitRight,
} SubGhzProtocolBlockAlignBit;
/** /**
* Set data bit when encoding HEX array. * Set data bit when encoding HEX array.
* @param bit_value The value of the bit to be set * @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 upload Pointer to a LevelDuration
* @param max_size_upload upload size, check not to overflow * @param max_size_upload upload size, check not to overflow
* @param duration_bit duration 1 bit * @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[], uint8_t data_array[],
size_t count_bit_data_array, size_t count_bit_data_array,
LevelDuration* upload, LevelDuration* upload,
size_t max_size_upload, size_t max_size_upload,
uint32_t duration_bit); uint32_t duration_bit,
SubGhzProtocolBlockAlignBit align_bit);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -100,7 +100,7 @@ bool subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperForma
FURI_LOG_E(TAG, "Missing Bit"); FURI_LOG_E(TAG, "Missing Bit");
break; 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}; uint8_t key_data[sizeof(uint64_t)] = {0};
if(!flipper_format_read_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { if(!flipper_format_read_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) {

View File

@ -19,7 +19,7 @@ struct SubGhzBlockGeneric {
const char* protocol_name; const char* protocol_name;
uint64_t data; uint64_t data;
uint32_t serial; uint32_t serial;
uint8_t data_count_bit; uint16_t data_count_bit;
uint8_t btn; uint8_t btn;
uint32_t cnt; uint32_t cnt;
}; };

File diff suppressed because it is too large Load Diff

View 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);

View File

@ -196,12 +196,13 @@ static bool
break; 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_data,
upload_hex_count_bit, upload_hex_count_bit,
instance->encoder.upload, instance->encoder.upload,
instance->encoder.size_upload, instance->encoder.size_upload,
subghz_protocol_chamb_code_const.te_short); subghz_protocol_chamb_code_const.te_short,
SubGhzProtocolBlockAlignBitLeft);
return true; return true;
} }

View File

@ -42,6 +42,7 @@ const SubGhzProtocol* subghz_protocol_registry_items[] = {
&subghz_protocol_dooya, &subghz_protocol_dooya,
&subghz_protocol_alutech_at_4n, &subghz_protocol_alutech_at_4n,
&subghz_protocol_kinggates_stylo_4k, &subghz_protocol_kinggates_stylo_4k,
&subghz_protocol_bin_raw,
}; };
const SubGhzProtocolRegistry subghz_protocol_registry = { const SubGhzProtocolRegistry subghz_protocol_registry = {

View File

@ -42,5 +42,6 @@
#include "dooya.h" #include "dooya.h"
#include "alutech_at_4n.h" #include "alutech_at_4n.h"
#include "kinggates_stylo_4k.h" #include "kinggates_stylo_4k.h"
#include "bin_raw.h"
extern const SubGhzProtocolRegistry subghz_protocol_registry; extern const SubGhzProtocolRegistry subghz_protocol_registry;

View File

@ -261,16 +261,16 @@ static bool
data = order << 4 | invert; data = order << 4 | invert;
int k = 0; int k = 0;
for(int i = 6; i >= 0; i -= 2) { for(int i = 6; i >= 0; i -= 2) {
roll_array[k++] = (data >> i) & 0x03; roll_array[k] = (data >> i) & 0x03;
if(roll_array[k] == 3) { if(roll_array[k++] == 3) {
FURI_LOG_E(TAG, "Roll_Array FAIL"); FURI_LOG_E(TAG, "Roll_Array FAIL");
return false; return false;
} }
} }
for(int i = 8; i >= 0; i -= 2) { for(int i = 8; i >= 0; i -= 2) {
roll_array[k++] = (p[2] >> i) & 0x03; roll_array[k] = (p[2] >> i) & 0x03;
if(roll_array[k] == 3) { if(roll_array[k++] == 3) {
FURI_LOG_E(TAG, "Roll_Array FAIL"); FURI_LOG_E(TAG, "Roll_Array FAIL");
return false; return false;
} }

View File

@ -64,7 +64,7 @@ void subghz_receiver_decode(SubGhzReceiver* instance, bool level, uint32_t durat
for for
M_EACH(slot, instance->slots, SubGhzReceiverSlotArray_t) { 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); slot->base->protocol->decoder->feed(slot->base, level, duration);
} }
} }

View File

@ -90,6 +90,7 @@ typedef enum {
SubGhzProtocolFlag_Save = (1 << 7), SubGhzProtocolFlag_Save = (1 << 7),
SubGhzProtocolFlag_Load = (1 << 8), SubGhzProtocolFlag_Load = (1 << 8),
SubGhzProtocolFlag_Send = (1 << 9), SubGhzProtocolFlag_Send = (1 << 9),
SubGhzProtocolFlag_BinRAW = (1 << 10),
} SubGhzProtocolFlag; } SubGhzProtocolFlag;
typedef struct { typedef struct {

View File

@ -13,8 +13,8 @@
#define LEVEL_DURATION_RESERVED 0x800000U #define LEVEL_DURATION_RESERVED 0x800000U
typedef struct { typedef struct {
uint32_t level; uint32_t duration : 30;
uint32_t duration; uint8_t level : 2;
} LevelDuration; } LevelDuration;
static inline LevelDuration level_duration_make(bool level, uint32_t duration) { static inline LevelDuration level_duration_make(bool level, uint32_t duration) {