diff --git a/applications/subghz/subghz_cli.c b/applications/subghz/subghz_cli.c index 5cf95e2d..ac9d439b 100644 --- a/applications/subghz/subghz_cli.c +++ b/applications/subghz/subghz_cli.c @@ -216,19 +216,16 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) { volatile bool subghz_cli_overrun = false; -void subghz_cli_command_rx_callback( - ApiHalSubGhzCaptureLevel level, - uint32_t duration, - void* context) { +void subghz_cli_command_rx_callback(bool level, uint32_t duration, void* context) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; - LevelPair pair = {.level = level, .duration = duration}; + LevelDuration level_duration = level_duration_make(level, duration); if(subghz_cli_overrun) { subghz_cli_overrun = false; - pair.level = ApiHalSubGhzCaptureLevelOverrun; + level_duration = level_duration_reset(); } - size_t ret = - xStreamBufferSendFromISR(context, &pair, sizeof(LevelPair), &xHigherPriorityTaskWoken); - if(sizeof(LevelPair) != ret) subghz_cli_overrun = true; + size_t ret = xStreamBufferSendFromISR( + context, &level_duration, sizeof(LevelDuration), &xHigherPriorityTaskWoken); + if(sizeof(LevelDuration) != ret) subghz_cli_overrun = true; portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } @@ -257,13 +254,13 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) { SubGhzProtocol* protocol = subghz_protocol_alloc(); subghz_protocol_load_keeloq_file(protocol, "/assets/subghz/keeloq_mfcodes"); subghz_protocol_load_nice_flor_s_file(protocol, "/assets/subghz/nice_floor_s_rx"); - subghz_protocol_enable_dump(protocol, NULL, NULL); + subghz_protocol_enable_dump_text(protocol, NULL, NULL); frequency = api_hal_subghz_set_frequency_and_path(frequency); hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); StreamBufferHandle_t rx_stream = - xStreamBufferCreate(sizeof(LevelPair) * 1024, sizeof(LevelPair)); + xStreamBufferCreate(sizeof(LevelDuration) * 1024, sizeof(LevelDuration)); api_hal_subghz_set_capture_callback(subghz_cli_command_rx_callback, rx_stream); api_hal_subghz_enable_capture(); @@ -272,15 +269,17 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) { api_hal_subghz_rx(); printf("Listening at %lu. Press CTRL+C to stop\r\n", frequency); - LevelPair pair; + LevelDuration level_duration; while(!cli_cmd_interrupt_received(cli)) { - int ret = xStreamBufferReceive(rx_stream, &pair, sizeof(LevelPair), 10); - if(ret == sizeof(LevelPair)) { - if(pair.level == ApiHalSubGhzCaptureLevelOverrun) { + int ret = xStreamBufferReceive(rx_stream, &level_duration, sizeof(LevelDuration), 10); + if(ret == sizeof(LevelDuration)) { + if(level_duration_is_reset(level_duration)) { printf("."); subghz_protocol_reset(protocol); } else { - subghz_protocol_parse(protocol, pair); + bool level = level_duration_get_level(level_duration); + uint32_t duration = level_duration_get_duration(level_duration); + subghz_protocol_parse(protocol, level, duration); } } } diff --git a/applications/subghz/views/subghz_capture.c b/applications/subghz/views/subghz_capture.c index 94ca5e28..3dbcb5f3 100644 --- a/applications/subghz/views/subghz_capture.c +++ b/applications/subghz/views/subghz_capture.c @@ -11,6 +11,8 @@ #include #include +#include + struct SubghzCapture { View* view; SubGhzWorker* worker; @@ -22,6 +24,8 @@ typedef struct { uint32_t real_frequency; uint32_t counter; string_t text; + uint16_t scene; + SubGhzProtocolCommon parser; } SubghzCaptureModel; static const char subghz_symbols[] = {'-', '\\', '|', '/'}; @@ -41,8 +45,22 @@ void subghz_capture_draw(Canvas* canvas, SubghzCaptureModel* model) { subghz_symbols[model->counter % 4]); canvas_draw_str(canvas, 0, 8, buffer); - canvas_set_font(canvas, FontSecondary); - elements_multiline_text(canvas, 0, 20, string_get_cstr(model->text)); + switch(model->scene) { + case 1: + canvas_draw_icon(canvas, 0, 10, &I_RFIDDolphinReceive_97x61); + canvas_invert_color(canvas); + canvas_draw_box(canvas, 80, 12, 20, 20); + canvas_invert_color(canvas); + canvas_draw_icon(canvas, 75, 18, &I_sub1_10px); + elements_multiline_text_aligned( + canvas, 90, 38, AlignCenter, AlignTop, "Detecting\r\nSubGhz"); + break; + + default: + canvas_set_font(canvas, FontSecondary); + elements_multiline_text(canvas, 0, 20, string_get_cstr(model->text)); + break; + } } bool subghz_capture_input(InputEvent* event, void* context) { @@ -87,6 +105,34 @@ void subghz_capture_text_callback(string_t text, void* context) { subghz_capture->view, (SubghzCaptureModel * model) { model->counter++; string_set(model->text, text); + model->scene = 0; + return true; + }); +} + +void subghz_capture_protocol_callback(SubGhzProtocolCommon* parser, void* context) { + furi_assert(context); + SubghzCapture* subghz_capture = context; + char buffer[64]; + snprintf( + buffer, + sizeof(buffer), + "%s\r\n" + "K:%lX%lX\r\n" + "SN:%lX\r\n" + "BTN:%X", + parser->name, + (uint32_t)(parser->code_found >> 32), + (uint32_t)(parser->code_found & 0x00000000FFFFFFFF), + parser->serial, + parser->btn); + + with_view_model( + subghz_capture->view, (SubghzCaptureModel * model) { + model->counter++; + model->parser = *parser; + string_set(model->text, buffer); + model->scene = 0; return true; }); } @@ -104,6 +150,7 @@ void subghz_capture_enter(void* context) { model->frequency = subghz_frequencies_433_92; model->real_frequency = api_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]); + model->scene = 1; return true; }); @@ -163,7 +210,7 @@ SubghzCapture* subghz_capture_alloc() { subghz_protocol_load_keeloq_file(subghz_capture->protocol, "/assets/subghz/keeloq_mfcodes"); subghz_protocol_load_nice_flor_s_file( subghz_capture->protocol, "/assets/subghz/nice_floor_s_rx"); - subghz_protocol_enable_dump( + subghz_protocol_enable_dump_text( subghz_capture->protocol, subghz_capture_text_callback, subghz_capture); return subghz_capture; diff --git a/firmware/targets/api-hal-include/api-hal-subghz.h b/firmware/targets/api-hal-include/api-hal-subghz.h index 1c26c2d4..d4e5cb5d 100644 --- a/firmware/targets/api-hal-include/api-hal-subghz.h +++ b/firmware/targets/api-hal-include/api-hal-subghz.h @@ -2,6 +2,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -107,21 +108,8 @@ uint32_t api_hal_subghz_set_frequency(uint32_t value); */ void api_hal_subghz_set_path(ApiHalSubGhzPath path); -/** Front Definition for capture callback */ -typedef enum { - ApiHalSubGhzCaptureLevelHigh, - ApiHalSubGhzCaptureLevelLow, - ApiHalSubGhzCaptureLevelOverrun, - ApiHalSubGhzCaptureLevelUnderrun, -} ApiHalSubGhzCaptureLevel; - -typedef struct { - ApiHalSubGhzCaptureLevel level; - uint32_t duration; -} LevelPair; - /** Signal Timings Capture callback */ -typedef void (*ApiHalSubGhzCaptureCallback)(ApiHalSubGhzCaptureLevel level, uint32_t time, void* context); +typedef void (*ApiHalSubGhzCaptureCallback)(bool level, uint32_t duration, void* context); /** Set signal timings capture callback * @param callback - your callback for front capture diff --git a/firmware/targets/f6/api-hal/api-hal-subghz.c b/firmware/targets/f6/api-hal/api-hal-subghz.c index c9ba3353..eb9d4eab 100644 --- a/firmware/targets/f6/api-hal/api-hal-subghz.c +++ b/firmware/targets/f6/api-hal/api-hal-subghz.c @@ -292,9 +292,7 @@ static void api_hal_subghz_capture_ISR() { LL_TIM_ClearFlag_CC1(TIM2); api_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2); if (api_hal_subghz_capture_callback) { - api_hal_subghz_capture_callback( - ApiHalSubGhzCaptureLevelHigh, - api_hal_subghz_capture_delta_duration, + api_hal_subghz_capture_callback(true, api_hal_subghz_capture_delta_duration, (void*)api_hal_subghz_capture_callback_context ); } @@ -303,9 +301,7 @@ static void api_hal_subghz_capture_ISR() { if(LL_TIM_IsActiveFlag_CC2(TIM2)) { LL_TIM_ClearFlag_CC2(TIM2); if (api_hal_subghz_capture_callback) { - api_hal_subghz_capture_callback( - ApiHalSubGhzCaptureLevelLow, - LL_TIM_IC_GetCaptureCH2(TIM2) - api_hal_subghz_capture_delta_duration, + api_hal_subghz_capture_callback(false, LL_TIM_IC_GetCaptureCH2(TIM2) - api_hal_subghz_capture_delta_duration, (void*)api_hal_subghz_capture_callback_context ); } @@ -323,7 +319,7 @@ void api_hal_subghz_enable_capture() { LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64-1; TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; - TIM_InitStruct.Autoreload = 0xFFFFFFFF; + TIM_InitStruct.Autoreload = 0x7FFFFFFE; TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; LL_TIM_Init(TIM2, &TIM_InitStruct); diff --git a/lib/fl_subghz/protocols/subghz_protocol.c b/lib/fl_subghz/protocols/subghz_protocol.c index 0d62e753..684e0629 100644 --- a/lib/fl_subghz/protocols/subghz_protocol.c +++ b/lib/fl_subghz/protocols/subghz_protocol.c @@ -22,9 +22,11 @@ struct SubGhzProtocol { SubGhzProtocolTextCallback text_callback; void* text_callback_context; + SubGhzProtocolCommonCallbackDump parser_callback; + void* parser_callback_context; }; -static void subghz_protocol_came_rx_callback(SubGhzProtocolCommon* parser, void* context) { +static void subghz_protocol_text_rx_callback(SubGhzProtocolCommon* parser, void* context) { SubGhzProtocol* instance = context; string_t output; @@ -38,6 +40,13 @@ static void subghz_protocol_came_rx_callback(SubGhzProtocolCommon* parser, void* string_clear(output); } +static void subghz_protocol_parser_rx_callback(SubGhzProtocolCommon* parser, void* context) { + SubGhzProtocol* instance = context; + if (instance->parser_callback) { + instance->parser_callback(parser, instance->parser_callback_context); + } +} + SubGhzProtocol* subghz_protocol_alloc() { SubGhzProtocol* instance = furi_alloc(sizeof(SubGhzProtocol)); @@ -62,19 +71,31 @@ void subghz_protocol_free(SubGhzProtocol* instance) { free(instance); } -void subghz_protocol_enable_dump(SubGhzProtocol* instance, SubGhzProtocolTextCallback callback, void* context) { +void subghz_protocol_enable_dump_text(SubGhzProtocol* instance, SubGhzProtocolTextCallback callback, void* context) { furi_assert(instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->came, subghz_protocol_came_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->keeloq, subghz_protocol_came_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->princeton, subghz_protocol_came_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->nice_flo, subghz_protocol_came_rx_callback, instance); - subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->nice_flor_s, subghz_protocol_came_rx_callback, instance); + subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->came, subghz_protocol_text_rx_callback, instance); + subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->keeloq, subghz_protocol_text_rx_callback, instance); + subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->princeton, subghz_protocol_text_rx_callback, instance); + subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->nice_flo, subghz_protocol_text_rx_callback, instance); + subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->nice_flor_s, subghz_protocol_text_rx_callback, instance); instance->text_callback = callback; instance->text_callback_context = context; } +void subghz_protocol_enable_dump(SubGhzProtocol* instance, SubGhzProtocolCommonCallbackDump callback, void* context) { + furi_assert(instance); + + subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->came, subghz_protocol_parser_rx_callback, instance); + subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->keeloq, subghz_protocol_parser_rx_callback, instance); + subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->princeton, subghz_protocol_parser_rx_callback, instance); + subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->nice_flo, subghz_protocol_parser_rx_callback, instance); + subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->nice_flor_s, subghz_protocol_parser_rx_callback, instance); + instance->parser_callback = callback; + instance->parser_callback_context = context; +} + static void subghz_protocol_load_keeloq_file_process_line(SubGhzProtocol* instance, string_t line) { uint64_t key = 0; uint16_t type = 0; @@ -123,12 +144,17 @@ void subghz_protocol_load_keeloq_file(SubGhzProtocol* instance, const char* file } void subghz_protocol_reset(SubGhzProtocol* instance) { + subghz_protocol_came_reset(instance->came); + subghz_protocol_keeloq_reset(instance->keeloq); + subghz_protocol_princeton_reset(instance->princeton); + subghz_protocol_nice_flo_reset(instance->nice_flo); + subghz_protocol_nice_flor_s_reset(instance->nice_flor_s); } -void subghz_protocol_parse(SubGhzProtocol* instance, LevelPair data) { - subghz_protocol_came_parse(instance->came, data); - subghz_protocol_keeloq_parse(instance->keeloq, data); - subghz_protocol_princeton_parse(instance->princeton, data); - subghz_protocol_nice_flo_parse(instance->nice_flo, data); - subghz_protocol_nice_flor_s_parse(instance->nice_flor_s, data); +void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t duration) { + subghz_protocol_came_parse(instance->came, level, duration); + subghz_protocol_keeloq_parse(instance->keeloq, level, duration); + subghz_protocol_princeton_parse(instance->princeton, level, duration); + subghz_protocol_nice_flo_parse(instance->nice_flo, level, duration); + subghz_protocol_nice_flor_s_parse(instance->nice_flor_s, level, duration); } diff --git a/lib/fl_subghz/protocols/subghz_protocol.h b/lib/fl_subghz/protocols/subghz_protocol.h index 8cd3172f..d5731403 100644 --- a/lib/fl_subghz/protocols/subghz_protocol.h +++ b/lib/fl_subghz/protocols/subghz_protocol.h @@ -3,6 +3,7 @@ #include "subghz_protocol_common.h" typedef void (*SubGhzProtocolTextCallback)(string_t text, void* context); +typedef void (*SubGhzProtocolCommonCallbackDump)(SubGhzProtocolCommon *parser, void* context); typedef struct SubGhzProtocol SubGhzProtocol; @@ -18,16 +19,21 @@ SubGhzProtocol* subghz_protocol_alloc(); */ void subghz_protocol_free(SubGhzProtocol* instance); -/** Outputting data from all parsers +/** Outputting data text from all parsers * * @param instance - SubGhzProtocol instance * @param callback - SubGhzProtocolTextCallback callback * @param context */ -void subghz_protocol_enable_dump( - SubGhzProtocol* instance, - SubGhzProtocolTextCallback callback, - void* context); +void subghz_protocol_enable_dump_text(SubGhzProtocol* instance,SubGhzProtocolTextCallback callback,void* context); + +/** Outputting data SubGhzProtocol from all parsers + * + * @param instance - SubGhzProtocol instance + * @param callback - SubGhzProtocolTextCallback callback + * @param context + */ +void subghz_protocol_enable_dump( SubGhzProtocol* instance, SubGhzProtocolCommonCallbackDump callback, void* context); /** File name rainbow table Nice Flor-S * @@ -52,6 +58,7 @@ void subghz_protocol_reset(SubGhzProtocol* instance); /** Loading data into all parsers * * @param instance - SubGhzProtocol instance - * @param data - LevelPair data + * @param level - true is high, false if low + * @param duration - level duration in microseconds */ -void subghz_protocol_parse(SubGhzProtocol* instance, LevelPair data); +void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t duration); diff --git a/lib/fl_subghz/protocols/subghz_protocol_came.c b/lib/fl_subghz/protocols/subghz_protocol_came.c index 4854a2a1..68f78576 100644 --- a/lib/fl_subghz/protocols/subghz_protocol_came.c +++ b/lib/fl_subghz/protocols/subghz_protocol_came.c @@ -63,11 +63,15 @@ void subghz_protocol_came_send_key(SubGhzProtocolCame* instance, uint64_t key, u } } -void subghz_protocol_came_parse(SubGhzProtocolCame* instance, LevelPair data) { +void subghz_protocol_came_reset(SubGhzProtocolCame* instance) { + instance->common.parser_step = 0; +} + +void subghz_protocol_came_parse(SubGhzProtocolCame* instance, bool level, uint32_t duration) { switch (instance->common.parser_step) { case 0: - if ((data.level == ApiHalSubGhzCaptureLevelLow) - && (DURATION_DIFF(data.duration,instance->common.te_shot * 51)< instance->common.te_delta * 51)) { //Need protocol 36 te_shot + if ((!level) + && (DURATION_DIFF(duration, instance->common.te_shot * 51)< instance->common.te_delta * 51)) { //Need protocol 36 te_shot //Found header CAME instance->common.parser_step = 1; } else { @@ -75,9 +79,9 @@ void subghz_protocol_came_parse(SubGhzProtocolCame* instance, LevelPair data) { } break; case 1: - if (data.level == ApiHalSubGhzCaptureLevelLow) { + if (!level) { break; - } else if (DURATION_DIFF(data.duration,instance->common.te_shot)< instance->common.te_delta) { + } else if (DURATION_DIFF(duration, instance->common.te_shot)< instance->common.te_delta) { //Found start bit CAME instance->common.parser_step = 2; instance->common.code_found = 0; @@ -87,33 +91,34 @@ void subghz_protocol_came_parse(SubGhzProtocolCame* instance, LevelPair data) { } break; case 2: - if (data.level == ApiHalSubGhzCaptureLevelLow) { //save interval - if (data.duration >= (instance->common.te_shot * 4)) { + if (!level) { //save interval + if (duration >= (instance->common.te_shot * 4)) { instance->common.parser_step = 1; if (instance->common.code_count_bit>= instance->common.code_min_count_bit_for_found) { - //ToDo out data display + instance->common.serial = 0x0; instance->common.btn = 0x0; if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); + } break; } - instance->common.te_last = data.duration; + instance->common.te_last = duration; instance->common.parser_step = 3; } else { instance->common.parser_step = 0; } break; case 3: - if (data.level == ApiHalSubGhzCaptureLevelHigh) { + if (level) { if ((DURATION_DIFF(instance->common.te_last,instance->common.te_shot) < instance->common.te_delta) - && (DURATION_DIFF(data.duration,instance->common.te_long)< instance->common.te_delta)) { + && (DURATION_DIFF(duration, instance->common.te_long)< instance->common.te_delta)) { subghz_protocol_common_add_bit(&instance->common, 0); instance->common.parser_step = 2; } else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_long)< instance->common.te_delta) - && (DURATION_DIFF(data.duration,instance->common.te_shot)< instance->common.te_delta)) { + && (DURATION_DIFF(duration, instance->common.te_shot)< instance->common.te_delta)) { subghz_protocol_common_add_bit(&instance->common, 1); instance->common.parser_step = 2; } else diff --git a/lib/fl_subghz/protocols/subghz_protocol_came.h b/lib/fl_subghz/protocols/subghz_protocol_came.h index 51783e4e..3babbff1 100644 --- a/lib/fl_subghz/protocols/subghz_protocol_came.h +++ b/lib/fl_subghz/protocols/subghz_protocol_came.h @@ -25,9 +25,14 @@ void subghz_protocol_came_free(SubGhzProtocolCame* instance); */ void subghz_protocol_came_send_key(SubGhzProtocolCame* instance, uint64_t key, uint8_t bit, uint8_t repeat); +/** Reset internal state + * @param instance - SubGhzProtocolCame instance + */ +void subghz_protocol_came_reset(SubGhzProtocolCame* instance); + /** Parse accepted duration * * @param instance - SubGhzProtocolCame instance - * @param data - LevelPair data + * @param data - LevelDuration level_duration */ -void subghz_protocol_came_parse(SubGhzProtocolCame* instance, LevelPair data); +void subghz_protocol_came_parse(SubGhzProtocolCame* instance, bool level, uint32_t duration);; diff --git a/lib/fl_subghz/protocols/subghz_protocol_common.c b/lib/fl_subghz/protocols/subghz_protocol_common.c index a973e5d3..97ded06e 100644 --- a/lib/fl_subghz/protocols/subghz_protocol_common.c +++ b/lib/fl_subghz/protocols/subghz_protocol_common.c @@ -27,6 +27,7 @@ void subghz_protocol_common_set_callback(SubGhzProtocolCommon* common, SubGhzPro common->context = context; } + void subghz_protocol_common_to_str(SubGhzProtocolCommon* instance, string_t output) { if (instance->to_string) { instance->to_string(instance, output); diff --git a/lib/fl_subghz/protocols/subghz_protocol_common.h b/lib/fl_subghz/protocols/subghz_protocol_common.h index e1d608d3..cd4c9ec8 100644 --- a/lib/fl_subghz/protocols/subghz_protocol_common.h +++ b/lib/fl_subghz/protocols/subghz_protocol_common.h @@ -11,7 +11,7 @@ #define SUBGHZ_TX_PIN_HIGTH() #define SUBGHZ_TX_PIN_LOW() -#define DURATION_DIFF(x,y) ((x < y) ? (y - x) : (x - y)) +#define DURATION_DIFF(x, y) ((x < y) ? (y - x) : (x - y)) typedef struct SubGhzProtocolCommon SubGhzProtocolCommon; @@ -29,7 +29,7 @@ struct SubGhzProtocolCommon { uint8_t code_count_bit; uint8_t code_min_count_bit_for_found; uint8_t parser_step; - uint16_t te_last; + uint32_t te_last; uint8_t header_count; uint16_t cnt; uint32_t serial; diff --git a/lib/fl_subghz/protocols/subghz_protocol_keeloq.c b/lib/fl_subghz/protocols/subghz_protocol_keeloq.c index cfc0478f..974dcec9 100644 --- a/lib/fl_subghz/protocols/subghz_protocol_keeloq.c +++ b/lib/fl_subghz/protocols/subghz_protocol_keeloq.c @@ -271,10 +271,14 @@ void subghz_protocol_keeloq_send_key(SubGhzProtocolKeeloq* instance, uint64_t ke } } -void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, LevelPair data) { +void subghz_protocol_keeloq_reset(SubGhzProtocolKeeloq* instance) { + instance->common.parser_step = 0; +} + +void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, uint32_t duration) { switch (instance->common.parser_step) { case 0: - if ((data.level == ApiHalSubGhzCaptureLevelHigh) && DURATION_DIFF(data.duration, instance->common.te_shot)< instance->common.te_delta) { + if ((level) && DURATION_DIFF(duration, instance->common.te_shot)< instance->common.te_delta) { instance->common.parser_step = 1; instance->common.header_count++; } else { @@ -283,11 +287,11 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, LevelPair data break; case 1: - if ((data.level == ApiHalSubGhzCaptureLevelLow) && (DURATION_DIFF(data.duration, instance->common.te_shot ) < instance->common.te_delta)) { + if ((!level) && (DURATION_DIFF(duration, instance->common.te_shot ) < instance->common.te_delta)) { instance->common.parser_step = 0; break; } - if ((instance->common.header_count > 2) && ( DURATION_DIFF(data.duration, instance->common.te_shot * 10)< instance->common.te_delta * 10)) { + if ((instance->common.header_count > 2) && ( DURATION_DIFF(duration, instance->common.te_shot * 10)< instance->common.te_delta * 10)) { // Found header instance->common.parser_step = 2; instance->common.code_found = 0; @@ -298,21 +302,19 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, LevelPair data } break; case 2: - if (data.level == ApiHalSubGhzCaptureLevelHigh) { - instance->common.te_last = data.duration; + if (level) { + instance->common.te_last = duration; instance->common.parser_step = 3; } break; case 3: - if (data.level == ApiHalSubGhzCaptureLevelLow) { - if (data.duration >= (instance->common.te_shot * 2 + instance->common.te_delta)) { + if (!level) { + if (duration >= (instance->common.te_shot * 2 + instance->common.te_delta)) { // Found end TX instance->common.parser_step = 0; if (instance->common.code_count_bit >= instance->common.code_min_count_bit_for_found) { - //&& (instance->common.code_last_found != instance->common.code_found )) { instance->common.code_last_found = instance->common.code_found; - //ToDo out data display subghz_protocol_keeloq_check_remote_controller(instance); instance->common.code_found = 0; @@ -321,13 +323,13 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, LevelPair data } break; } else if ((DURATION_DIFF(instance->common.te_last, instance->common.te_shot) < instance->common.te_delta) - && (DURATION_DIFF(data.duration, instance->common.te_long) < instance->common.te_delta)) { + && (DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) { if (instance->common.code_count_bit < instance->common.code_min_count_bit_for_found) { subghz_protocol_common_add_bit(&instance->common, 1); } instance->common.parser_step = 2; } else if ((DURATION_DIFF(instance->common.te_last, instance->common.te_long) < instance->common.te_delta) - && (DURATION_DIFF(data.duration, instance->common.te_shot) < instance->common.te_delta)) { + && (DURATION_DIFF(duration, instance->common.te_shot) < instance->common.te_delta)) { if (instance->common.code_count_bit < instance->common.code_min_count_bit_for_found) { subghz_protocol_common_add_bit(&instance->common, 0); } diff --git a/lib/fl_subghz/protocols/subghz_protocol_keeloq.h b/lib/fl_subghz/protocols/subghz_protocol_keeloq.h index 9a429d39..a4bf61bd 100644 --- a/lib/fl_subghz/protocols/subghz_protocol_keeloq.h +++ b/lib/fl_subghz/protocols/subghz_protocol_keeloq.h @@ -34,12 +34,17 @@ void subghz_protocol_keeloq_add_manafacture_key(SubGhzProtocolKeeloq* instance, */ void subghz_protocol_keeloq_send_key(SubGhzProtocolKeeloq* instance, uint64_t key, uint8_t bit, uint8_t repeat); +/** Reset internal state + * @param instance - SubGhzProtocolKeeloq instance + */ +void subghz_protocol_keeloq_reset(SubGhzProtocolKeeloq* instance); + /** Parse accepted duration * * @param instance - SubGhzProtocolKeeloq instance - * @param data - LevelPair data + * @param data - LevelDuration level_duration */ -void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, LevelPair data); +void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, uint32_t duration);; /** Outputting information from the parser * diff --git a/lib/fl_subghz/protocols/subghz_protocol_nice_flo.c b/lib/fl_subghz/protocols/subghz_protocol_nice_flo.c index 59bf121f..0c0cb207 100644 --- a/lib/fl_subghz/protocols/subghz_protocol_nice_flo.c +++ b/lib/fl_subghz/protocols/subghz_protocol_nice_flo.c @@ -62,11 +62,15 @@ void subghz_protocol_nice_flo_send_key(SubGhzProtocolNiceFlo* instance, uint64_t } } -void subghz_protocol_nice_flo_parse(SubGhzProtocolNiceFlo* instance, LevelPair data) { +void subghz_protocol_nice_flo_reset(SubGhzProtocolNiceFlo* instance) { + instance->common.parser_step = 0; +} + +void subghz_protocol_nice_flo_parse(SubGhzProtocolNiceFlo* instance, bool level, uint32_t duration) { switch (instance->common.parser_step) { case 0: - if ((data.level == ApiHalSubGhzCaptureLevelLow) - && (DURATION_DIFF(data.duration,instance->common.te_shot * 36)< instance->common.te_delta * 36)) { + if ((!level) + && (DURATION_DIFF(duration, instance->common.te_shot * 36)< instance->common.te_delta * 36)) { //Found header Nice Flo instance->common.parser_step = 1; } else { @@ -74,9 +78,9 @@ void subghz_protocol_nice_flo_parse(SubGhzProtocolNiceFlo* instance, LevelPair d } break; case 1: - if (data.level == ApiHalSubGhzCaptureLevelLow) { + if (!level) { break; - } else if (DURATION_DIFF(data.duration,instance->common.te_shot)< instance->common.te_delta) { + } else if (DURATION_DIFF(duration, instance->common.te_shot)< instance->common.te_delta) { //Found start bit Nice Flo instance->common.parser_step = 2; instance->common.code_found = 0; @@ -86,31 +90,30 @@ void subghz_protocol_nice_flo_parse(SubGhzProtocolNiceFlo* instance, LevelPair d } break; case 2: - if (data.level == ApiHalSubGhzCaptureLevelLow) { //save interval - if (data.duration >= (instance->common.te_shot * 4)) { + if (!level) { //save interval + if (duration >= (instance->common.te_shot * 4)) { instance->common.parser_step = 1; if (instance->common.code_count_bit>= instance->common.code_min_count_bit_for_found) { - //ToDo out data display - //instance->common.serial = 0x12345; if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); + } break; } - instance->common.te_last = data.duration; + instance->common.te_last = duration; instance->common.parser_step = 3; } else { instance->common.parser_step = 0; } break; case 3: - if (data.level == ApiHalSubGhzCaptureLevelHigh) { + if (level) { if ((DURATION_DIFF(instance->common.te_last,instance->common.te_shot) < instance->common.te_delta) - && (DURATION_DIFF(data.duration,instance->common.te_long)< instance->common.te_delta)) { + && (DURATION_DIFF(duration, instance->common.te_long)< instance->common.te_delta)) { subghz_protocol_common_add_bit(&instance->common, 0); instance->common.parser_step = 2; } else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_long)< instance->common.te_delta) - && (DURATION_DIFF(data.duration,instance->common.te_shot)< instance->common.te_delta)) { + && (DURATION_DIFF(duration, instance->common.te_shot)< instance->common.te_delta)) { subghz_protocol_common_add_bit(&instance->common, 1); instance->common.parser_step = 2; } else diff --git a/lib/fl_subghz/protocols/subghz_protocol_nice_flo.h b/lib/fl_subghz/protocols/subghz_protocol_nice_flo.h index d19de3d9..6e2c0df3 100644 --- a/lib/fl_subghz/protocols/subghz_protocol_nice_flo.h +++ b/lib/fl_subghz/protocols/subghz_protocol_nice_flo.h @@ -25,9 +25,14 @@ void subghz_protocol_nice_flo_free(SubGhzProtocolNiceFlo* instance); */ void subghz_protocol_nice_flo_send_key(SubGhzProtocolNiceFlo* instance, uint64_t key, uint8_t bit, uint8_t repeat); +/** Reset internal state + * @param instance - SubGhzProtocolNiceFlo instance + */ +void subghz_protocol_nice_flo_reset(SubGhzProtocolNiceFlo* instance); + /** Parse accepted duration * * @param instance - SubGhzProtocolNiceFlo instance - * @param data - LevelPair data + * @param data - LevelDuration level_duration */ -void subghz_protocol_nice_flo_parse(SubGhzProtocolNiceFlo* instance, LevelPair data); +void subghz_protocol_nice_flo_parse(SubGhzProtocolNiceFlo* instance, bool level, uint32_t duration);; diff --git a/lib/fl_subghz/protocols/subghz_protocol_nice_flor_s.c b/lib/fl_subghz/protocols/subghz_protocol_nice_flor_s.c index 726dd3f0..f774e6d8 100644 --- a/lib/fl_subghz/protocols/subghz_protocol_nice_flor_s.c +++ b/lib/fl_subghz/protocols/subghz_protocol_nice_flor_s.c @@ -144,11 +144,15 @@ void subghz_nice_flor_s_decoder_decrypt(SubGhzProtocolNiceFlorS* instance) { if(instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); } -void subghz_protocol_nice_flor_s_parse(SubGhzProtocolNiceFlorS* instance, LevelPair data) { +void subghz_protocol_nice_flor_s_reset(SubGhzProtocolNiceFlorS* instance) { + instance->common.parser_step = 0; +} + +void subghz_protocol_nice_flor_s_parse(SubGhzProtocolNiceFlorS* instance, bool level, uint32_t duration) { switch(instance->common.parser_step) { case 0: - if((data.level == ApiHalSubGhzCaptureLevelLow) - && (DURATION_DIFF(data.duration, instance->common.te_shot * 38) < instance->common.te_delta * 38)) { + if((!level) + && (DURATION_DIFF(duration, instance->common.te_shot * 38) < instance->common.te_delta * 38)) { //Found start header Nice Flor-S instance->common.parser_step = 1; } else { @@ -156,8 +160,8 @@ void subghz_protocol_nice_flor_s_parse(SubGhzProtocolNiceFlorS* instance, LevelP } break; case 1: - if((data.level == ApiHalSubGhzCaptureLevelHigh) - && (DURATION_DIFF(data.duration, instance->common.te_shot * 3) < instance->common.te_delta * 3)) { + if((level) + && (DURATION_DIFF(duration, instance->common.te_shot * 3) < instance->common.te_delta * 3)) { //Found next header Nice Flor-S instance->common.parser_step = 2; } else { @@ -165,8 +169,8 @@ void subghz_protocol_nice_flor_s_parse(SubGhzProtocolNiceFlorS* instance, LevelP } break; case 2: - if((data.level == ApiHalSubGhzCaptureLevelLow) - && (DURATION_DIFF(data.duration, instance->common.te_shot * 3) < instance->common.te_delta * 3)) { + if((!level) + && (DURATION_DIFF(duration, instance->common.te_shot * 3) < instance->common.te_delta * 3)) { //Found header Nice Flor-S instance->common.parser_step = 3; instance->common.code_found = 0; @@ -176,31 +180,32 @@ void subghz_protocol_nice_flor_s_parse(SubGhzProtocolNiceFlorS* instance, LevelP } break; case 3: - if(data.level == ApiHalSubGhzCaptureLevelHigh) { - if(DURATION_DIFF(data.duration, instance->common.te_shot * 3) < instance->common.te_delta) { + if(level) { + if(DURATION_DIFF(duration, instance->common.te_shot * 3) < instance->common.te_delta) { //Found STOP bit instance->common.parser_step = 0; if(instance->common.code_count_bit >=instance->common.code_min_count_bit_for_found) { - //ToDo out data display + subghz_nice_flor_s_decoder_decrypt(instance); + } break; } else { //save interval - instance->common.te_last = data.duration; + instance->common.te_last = duration; instance->common.parser_step = 4; } } break; case 4: - if(data.level == ApiHalSubGhzCaptureLevelLow) { + if(!level) { if((DURATION_DIFF(instance->common.te_last, instance->common.te_shot) < instance->common.te_delta) - &&(DURATION_DIFF(data.duration, instance->common.te_long) < instance->common.te_delta)) { + &&(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) { subghz_protocol_common_add_bit(&instance->common, 0); instance->common.parser_step = 3; } else if( (DURATION_DIFF(instance->common.te_last, instance->common.te_long) < instance->common.te_delta) - &&(DURATION_DIFF(data.duration, instance->common.te_shot) < instance->common.te_delta)) { + &&(DURATION_DIFF(duration, instance->common.te_shot) < instance->common.te_delta)) { subghz_protocol_common_add_bit(&instance->common, 1); instance->common.parser_step = 3; } else diff --git a/lib/fl_subghz/protocols/subghz_protocol_nice_flor_s.h b/lib/fl_subghz/protocols/subghz_protocol_nice_flor_s.h index b0e2951a..2ece1927 100644 --- a/lib/fl_subghz/protocols/subghz_protocol_nice_flor_s.h +++ b/lib/fl_subghz/protocols/subghz_protocol_nice_flor_s.h @@ -32,12 +32,17 @@ void subghz_protocol_nice_flor_s_name_file(SubGhzProtocolNiceFlorS* instance, co */ void subghz_protocol_nice_flor_s_send_key(SubGhzProtocolNiceFlorS* instance, uint64_t key, uint8_t bit, uint8_t repeat); +/** Reset internal state + * @param instance - SubGhzProtocolNiceFlorS instance + */ +void subghz_protocol_nice_flor_s_reset(SubGhzProtocolNiceFlorS* instance); + /** Parse accepted duration * * @param instance - SubGhzProtocolNiceFlorS instance - * @param data - LevelPair data + * @param data - LevelDuration level_duration */ -void subghz_protocol_nice_flor_s_parse(SubGhzProtocolNiceFlorS* instance, LevelPair data); +void subghz_protocol_nice_flor_s_parse(SubGhzProtocolNiceFlorS* instance, bool level, uint32_t duration);; /** Outputting information from the parser * diff --git a/lib/fl_subghz/protocols/subghz_protocol_princeton.c b/lib/fl_subghz/protocols/subghz_protocol_princeton.c index a83197f4..6761a09a 100644 --- a/lib/fl_subghz/protocols/subghz_protocol_princeton.c +++ b/lib/fl_subghz/protocols/subghz_protocol_princeton.c @@ -62,11 +62,15 @@ void subghz_protocol_princeton_send_key(SubGhzProtocolPrinceton* instance, uint6 } } -void subghz_protocol_princeton_parse(SubGhzProtocolPrinceton* instance, LevelPair data) { +void subghz_protocol_princeton_reset(SubGhzProtocolPrinceton* instance) { + instance->common.parser_step = 0; +} + +void subghz_protocol_princeton_parse(SubGhzProtocolPrinceton* instance, bool level, uint32_t duration) { switch (instance->common.parser_step) { case 0: - if ((data.level == ApiHalSubGhzCaptureLevelLow) - && (DURATION_DIFF(data.duration,instance->common.te_shot * 36)< instance->common.te_delta * 36)) { + if ((!level) + && (DURATION_DIFF(duration,instance->common.te_shot * 36)< instance->common.te_delta * 36)) { //Found Preambula instance->common.parser_step = 1; instance->common.code_found = 0; @@ -77,20 +81,21 @@ void subghz_protocol_princeton_parse(SubGhzProtocolPrinceton* instance, LevelPai break; case 1: //save duration - if (data.level == ApiHalSubGhzCaptureLevelHigh) { - instance->common.te_last = data.duration; + if (level) { + instance->common.te_last = duration; instance->common.parser_step = 2; } break; case 2: - if (data.level == ApiHalSubGhzCaptureLevelLow) { - if (data.duration>= (instance->common.te_shot * 10+ instance->common.te_delta)) { + if (!level) { + if (duration >= (instance->common.te_shot * 10 + instance->common.te_delta)) { instance->common.parser_step = 1; if (instance->common.code_count_bit>= instance->common.code_min_count_bit_for_found) { - //ToDo out data display + instance->common.serial = instance->common.code_found >> 4; instance->common.btn = (uint8_t)instance->common.code_found & 0x00000F; if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context); + } instance->common.code_found = 0; instance->common.code_count_bit = 0; @@ -98,11 +103,11 @@ void subghz_protocol_princeton_parse(SubGhzProtocolPrinceton* instance, LevelPai } if ((DURATION_DIFF(instance->common.te_last,instance->common.te_shot)< instance->common.te_delta) - && (DURATION_DIFF(data.duration,instance->common.te_long)< instance->common.te_delta*3)) { + && (DURATION_DIFF(duration,instance->common.te_long)< instance->common.te_delta*3)) { subghz_protocol_common_add_bit(&instance->common, 0); instance->common.parser_step = 1; } else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_long)< instance->common.te_delta*3) - && (DURATION_DIFF(data.duration,instance->common.te_shot)< instance->common.te_delta)) { + && (DURATION_DIFF(duration,instance->common.te_shot)< instance->common.te_delta)) { subghz_protocol_common_add_bit(&instance->common, 1); instance->common.parser_step = 1; } else { diff --git a/lib/fl_subghz/protocols/subghz_protocol_princeton.h b/lib/fl_subghz/protocols/subghz_protocol_princeton.h index 291a2567..02c5c717 100644 --- a/lib/fl_subghz/protocols/subghz_protocol_princeton.h +++ b/lib/fl_subghz/protocols/subghz_protocol_princeton.h @@ -25,12 +25,17 @@ void subghz_protocol_princeton_free(SubGhzProtocolPrinceton* instance); */ void subghz_protocol_princeton_send_key(SubGhzProtocolPrinceton* instance, uint64_t key, uint8_t bit, uint8_t repeat); +/** Reset internal state + * @param instance - SubGhzProtocolPrinceton instance + */ +void subghz_protocol_princeton_reset(SubGhzProtocolPrinceton* instance); + /** Parse accepted duration * * @param instance - SubGhzProtocolPrinceton instance - * @param data - LevelPair data + * @param data - LevelDuration level_duration */ -void subghz_protocol_princeton_parse(SubGhzProtocolPrinceton* instance, LevelPair data); +void subghz_protocol_princeton_parse(SubGhzProtocolPrinceton* instance, bool level, uint32_t duration);; /** Outputting information from the parser * diff --git a/lib/fl_subghz/subghz_worker.c b/lib/fl_subghz/subghz_worker.c index a1574a3e..8cab5e01 100644 --- a/lib/fl_subghz/subghz_worker.c +++ b/lib/fl_subghz/subghz_worker.c @@ -21,22 +21,18 @@ struct SubGhzWorker { * @param duration received signal duration * @param context */ -void subghz_worker_rx_callback( - ApiHalSubGhzCaptureLevel level, - uint32_t duration, - void* context) { - +void subghz_worker_rx_callback(bool level, uint32_t duration, void* context) { SubGhzWorker* instance = context; BaseType_t xHigherPriorityTaskWoken = pdFALSE; - LevelPair pair = {.level = level, .duration = duration}; + LevelDuration level_duration = level_duration_make(level, duration); if(instance->overrun) { instance->overrun = false; - pair.level = ApiHalSubGhzCaptureLevelOverrun; + level_duration = level_duration_reset(); } size_t ret = - xStreamBufferSendFromISR(instance->stream, &pair, sizeof(LevelPair), &xHigherPriorityTaskWoken); - if(sizeof(LevelPair) != ret) instance->overrun = true; + xStreamBufferSendFromISR(instance->stream, &level_duration, sizeof(LevelDuration), &xHigherPriorityTaskWoken); + if(sizeof(LevelDuration) != ret) instance->overrun = true; portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } @@ -48,15 +44,17 @@ void subghz_worker_rx_callback( static int32_t subghz_worker_thread_callback(void* context) { SubGhzWorker* instance = context; - LevelPair pair; + LevelDuration level_duration; while(instance->running) { - int ret = xStreamBufferReceive(instance->stream, &pair, sizeof(LevelPair), 10); - if(ret == sizeof(LevelPair)) { - if(pair.level == ApiHalSubGhzCaptureLevelOverrun) { + int ret = xStreamBufferReceive(instance->stream, &level_duration, sizeof(LevelDuration), 10); + if(ret == sizeof(LevelDuration)) { + if(level_duration_is_reset(level_duration)) { printf("."); if (instance->overrun_callback) instance->overrun_callback(instance->context); } else { - if (instance->pair_callback) instance->pair_callback(instance->context, pair); + bool level = level_duration_get_level(level_duration); + uint32_t duration = level_duration_get_duration(level_duration); + if (instance->pair_callback) instance->pair_callback(instance->context, level, duration); } } } @@ -73,7 +71,7 @@ SubGhzWorker* subghz_worker_alloc() { furi_thread_set_context(instance->thread, instance); furi_thread_set_callback(instance->thread, subghz_worker_thread_callback); - instance->stream = xStreamBufferCreate(sizeof(LevelPair) * 1024, sizeof(LevelPair)); + instance->stream = xStreamBufferCreate(sizeof(LevelDuration) * 1024, sizeof(LevelDuration)); return instance; } diff --git a/lib/fl_subghz/subghz_worker.h b/lib/fl_subghz/subghz_worker.h index 58316341..53af3102 100644 --- a/lib/fl_subghz/subghz_worker.h +++ b/lib/fl_subghz/subghz_worker.h @@ -6,9 +6,9 @@ typedef struct SubGhzWorker SubGhzWorker; typedef void (*SubGhzWorkerOverrunCallback)(void* context); -typedef void (*SubGhzWorkerPairCallback)(void* context, LevelPair pair); +typedef void (*SubGhzWorkerPairCallback)(void* context, bool level, uint32_t duration); -void subghz_worker_rx_callback(ApiHalSubGhzCaptureLevel level, uint32_t duration, void* context); +void subghz_worker_rx_callback(bool level, uint32_t duration, void* context); /** Allocate SubGhzWorker * diff --git a/lib/toolbox/level_duration.h b/lib/toolbox/level_duration.h new file mode 100644 index 00000000..958c3890 --- /dev/null +++ b/lib/toolbox/level_duration.h @@ -0,0 +1,71 @@ +#pragma once + +#include + +#define LEVEL_DURATION_BIG + +#ifdef LEVEL_DURATION_BIG + +#define LEVEL_DURATION_RESET 0U +#define LEVEL_DURATION_LEVEL_LOW 1U +#define LEVEL_DURATION_LEVEL_HIGH 2U +#define LEVEL_DURATION_RESERVED 0x800000U + +typedef struct { + uint32_t level; + uint32_t duration; +} LevelDuration; + +static inline LevelDuration level_duration_make(bool level, uint32_t duration) { + LevelDuration level_duration; + level_duration.level = level ? LEVEL_DURATION_LEVEL_HIGH : LEVEL_DURATION_LEVEL_LOW; + level_duration.duration = duration; + return level_duration; +} + +static inline LevelDuration level_duration_reset() { + LevelDuration level_duration; + level_duration.level = LEVEL_DURATION_RESET; + return level_duration; +} + +static inline bool level_duration_is_reset(LevelDuration level_duration) { + return level_duration.level == LEVEL_DURATION_RESET; +} + +static inline bool level_duration_get_level(LevelDuration level_duration) { + return level_duration.level == LEVEL_DURATION_LEVEL_HIGH; +} + +static inline uint32_t level_duration_get_duration(LevelDuration level_duration) { + return level_duration.duration; +} + +#else + +#define LEVEL_DURATION_RESET 0U +#define LEVEL_DURATION_RESERVED 0x800000U + +typedef int32_t LevelDuration; + +static inline LevelDuration level_duration(bool level, uint32_t duration) { + return level ? duration : -(int32_t)duration; +} + +static inline LevelDuration level_duration_reset() { + return LEVEL_DURATION_RESET; +} + +static inline bool level_duration_is_reset(LevelDuration level_duration) { + return (level_duration == LEVEL_DURATION_RESET); +} + +static inline bool level_duration_get_level(LevelDuration level_duration) { + return (level_duration > 0); +} + +static inline uint32_t level_duration_get_duration(LevelDuration level_duration) { + return (level_duration >= 0) ? level_duration : -level_duration; +} + +#endif \ No newline at end of file