Skorp subghz capture refactoring (#569)
* SubGhz: changing the operation of the capture timer, and the logic of the work of parsers * Add toolbox lib. Move levels to toolbox. Subghz switch to levels. * Subghz: update worker signatures * SubGhz: pluggable level duration implementations. * SubGhz : test drawing pictures in Gui * SubGhz: Added a callback with the parser structure as argument * SubGhz: copy protocol data to model * SubGhz: refactoing code * SubGhz: cleanup and format sources * SubGhz: remove comments Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com> Co-authored-by: DrZlo13 <who.just.the.doctor@gmail.com>
This commit is contained in:
parent
a7283280ef
commit
4ce41a3e6f
@ -216,19 +216,16 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) {
|
|||||||
|
|
||||||
volatile bool subghz_cli_overrun = false;
|
volatile bool subghz_cli_overrun = false;
|
||||||
|
|
||||||
void subghz_cli_command_rx_callback(
|
void subghz_cli_command_rx_callback(bool level, uint32_t duration, void* context) {
|
||||||
ApiHalSubGhzCaptureLevel level,
|
|
||||||
uint32_t duration,
|
|
||||||
void* context) {
|
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
LevelPair pair = {.level = level, .duration = duration};
|
LevelDuration level_duration = level_duration_make(level, duration);
|
||||||
if(subghz_cli_overrun) {
|
if(subghz_cli_overrun) {
|
||||||
subghz_cli_overrun = false;
|
subghz_cli_overrun = false;
|
||||||
pair.level = ApiHalSubGhzCaptureLevelOverrun;
|
level_duration = level_duration_reset();
|
||||||
}
|
}
|
||||||
size_t ret =
|
size_t ret = xStreamBufferSendFromISR(
|
||||||
xStreamBufferSendFromISR(context, &pair, sizeof(LevelPair), &xHigherPriorityTaskWoken);
|
context, &level_duration, sizeof(LevelDuration), &xHigherPriorityTaskWoken);
|
||||||
if(sizeof(LevelPair) != ret) subghz_cli_overrun = true;
|
if(sizeof(LevelDuration) != ret) subghz_cli_overrun = true;
|
||||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
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();
|
SubGhzProtocol* protocol = subghz_protocol_alloc();
|
||||||
subghz_protocol_load_keeloq_file(protocol, "/assets/subghz/keeloq_mfcodes");
|
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_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);
|
frequency = api_hal_subghz_set_frequency_and_path(frequency);
|
||||||
hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||||
|
|
||||||
StreamBufferHandle_t rx_stream =
|
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_set_capture_callback(subghz_cli_command_rx_callback, rx_stream);
|
||||||
api_hal_subghz_enable_capture();
|
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();
|
api_hal_subghz_rx();
|
||||||
|
|
||||||
printf("Listening at %lu. Press CTRL+C to stop\r\n", frequency);
|
printf("Listening at %lu. Press CTRL+C to stop\r\n", frequency);
|
||||||
LevelPair pair;
|
LevelDuration level_duration;
|
||||||
while(!cli_cmd_interrupt_received(cli)) {
|
while(!cli_cmd_interrupt_received(cli)) {
|
||||||
int ret = xStreamBufferReceive(rx_stream, &pair, sizeof(LevelPair), 10);
|
int ret = xStreamBufferReceive(rx_stream, &level_duration, sizeof(LevelDuration), 10);
|
||||||
if(ret == sizeof(LevelPair)) {
|
if(ret == sizeof(LevelDuration)) {
|
||||||
if(pair.level == ApiHalSubGhzCaptureLevelOverrun) {
|
if(level_duration_is_reset(level_duration)) {
|
||||||
printf(".");
|
printf(".");
|
||||||
subghz_protocol_reset(protocol);
|
subghz_protocol_reset(protocol);
|
||||||
} else {
|
} 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#include <fl_subghz/subghz_worker.h>
|
#include <fl_subghz/subghz_worker.h>
|
||||||
#include <fl_subghz/protocols/subghz_protocol.h>
|
#include <fl_subghz/protocols/subghz_protocol.h>
|
||||||
|
|
||||||
|
#include <assets_icons.h>
|
||||||
|
|
||||||
struct SubghzCapture {
|
struct SubghzCapture {
|
||||||
View* view;
|
View* view;
|
||||||
SubGhzWorker* worker;
|
SubGhzWorker* worker;
|
||||||
@ -22,6 +24,8 @@ typedef struct {
|
|||||||
uint32_t real_frequency;
|
uint32_t real_frequency;
|
||||||
uint32_t counter;
|
uint32_t counter;
|
||||||
string_t text;
|
string_t text;
|
||||||
|
uint16_t scene;
|
||||||
|
SubGhzProtocolCommon parser;
|
||||||
} SubghzCaptureModel;
|
} SubghzCaptureModel;
|
||||||
|
|
||||||
static const char subghz_symbols[] = {'-', '\\', '|', '/'};
|
static const char subghz_symbols[] = {'-', '\\', '|', '/'};
|
||||||
@ -41,8 +45,22 @@ void subghz_capture_draw(Canvas* canvas, SubghzCaptureModel* model) {
|
|||||||
subghz_symbols[model->counter % 4]);
|
subghz_symbols[model->counter % 4]);
|
||||||
canvas_draw_str(canvas, 0, 8, buffer);
|
canvas_draw_str(canvas, 0, 8, buffer);
|
||||||
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
switch(model->scene) {
|
||||||
elements_multiline_text(canvas, 0, 20, string_get_cstr(model->text));
|
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) {
|
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) {
|
subghz_capture->view, (SubghzCaptureModel * model) {
|
||||||
model->counter++;
|
model->counter++;
|
||||||
string_set(model->text, text);
|
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;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -104,6 +150,7 @@ void subghz_capture_enter(void* context) {
|
|||||||
model->frequency = subghz_frequencies_433_92;
|
model->frequency = subghz_frequencies_433_92;
|
||||||
model->real_frequency =
|
model->real_frequency =
|
||||||
api_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]);
|
api_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]);
|
||||||
|
model->scene = 1;
|
||||||
return true;
|
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_keeloq_file(subghz_capture->protocol, "/assets/subghz/keeloq_mfcodes");
|
||||||
subghz_protocol_load_nice_flor_s_file(
|
subghz_protocol_load_nice_flor_s_file(
|
||||||
subghz_capture->protocol, "/assets/subghz/nice_floor_s_rx");
|
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);
|
subghz_capture->protocol, subghz_capture_text_callback, subghz_capture);
|
||||||
|
|
||||||
return subghz_capture;
|
return subghz_capture;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <toolbox/level_duration.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -107,21 +108,8 @@ uint32_t api_hal_subghz_set_frequency(uint32_t value);
|
|||||||
*/
|
*/
|
||||||
void api_hal_subghz_set_path(ApiHalSubGhzPath path);
|
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 */
|
/** 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
|
/** Set signal timings capture callback
|
||||||
* @param callback - your callback for front capture
|
* @param callback - your callback for front capture
|
||||||
|
@ -292,9 +292,7 @@ static void api_hal_subghz_capture_ISR() {
|
|||||||
LL_TIM_ClearFlag_CC1(TIM2);
|
LL_TIM_ClearFlag_CC1(TIM2);
|
||||||
api_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2);
|
api_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2);
|
||||||
if (api_hal_subghz_capture_callback) {
|
if (api_hal_subghz_capture_callback) {
|
||||||
api_hal_subghz_capture_callback(
|
api_hal_subghz_capture_callback(true, api_hal_subghz_capture_delta_duration,
|
||||||
ApiHalSubGhzCaptureLevelHigh,
|
|
||||||
api_hal_subghz_capture_delta_duration,
|
|
||||||
(void*)api_hal_subghz_capture_callback_context
|
(void*)api_hal_subghz_capture_callback_context
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -303,9 +301,7 @@ static void api_hal_subghz_capture_ISR() {
|
|||||||
if(LL_TIM_IsActiveFlag_CC2(TIM2)) {
|
if(LL_TIM_IsActiveFlag_CC2(TIM2)) {
|
||||||
LL_TIM_ClearFlag_CC2(TIM2);
|
LL_TIM_ClearFlag_CC2(TIM2);
|
||||||
if (api_hal_subghz_capture_callback) {
|
if (api_hal_subghz_capture_callback) {
|
||||||
api_hal_subghz_capture_callback(
|
api_hal_subghz_capture_callback(false, LL_TIM_IC_GetCaptureCH2(TIM2) - api_hal_subghz_capture_delta_duration,
|
||||||
ApiHalSubGhzCaptureLevelLow,
|
|
||||||
LL_TIM_IC_GetCaptureCH2(TIM2) - api_hal_subghz_capture_delta_duration,
|
|
||||||
(void*)api_hal_subghz_capture_callback_context
|
(void*)api_hal_subghz_capture_callback_context
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -323,7 +319,7 @@ void api_hal_subghz_enable_capture() {
|
|||||||
LL_TIM_InitTypeDef TIM_InitStruct = {0};
|
LL_TIM_InitTypeDef TIM_InitStruct = {0};
|
||||||
TIM_InitStruct.Prescaler = 64-1;
|
TIM_InitStruct.Prescaler = 64-1;
|
||||||
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
||||||
TIM_InitStruct.Autoreload = 0xFFFFFFFF;
|
TIM_InitStruct.Autoreload = 0x7FFFFFFE;
|
||||||
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
|
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
|
||||||
LL_TIM_Init(TIM2, &TIM_InitStruct);
|
LL_TIM_Init(TIM2, &TIM_InitStruct);
|
||||||
|
|
||||||
|
@ -22,9 +22,11 @@ struct SubGhzProtocol {
|
|||||||
|
|
||||||
SubGhzProtocolTextCallback text_callback;
|
SubGhzProtocolTextCallback text_callback;
|
||||||
void* text_callback_context;
|
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;
|
SubGhzProtocol* instance = context;
|
||||||
|
|
||||||
string_t output;
|
string_t output;
|
||||||
@ -38,6 +40,13 @@ static void subghz_protocol_came_rx_callback(SubGhzProtocolCommon* parser, void*
|
|||||||
string_clear(output);
|
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* subghz_protocol_alloc() {
|
||||||
SubGhzProtocol* instance = furi_alloc(sizeof(SubGhzProtocol));
|
SubGhzProtocol* instance = furi_alloc(sizeof(SubGhzProtocol));
|
||||||
|
|
||||||
@ -62,19 +71,31 @@ void subghz_protocol_free(SubGhzProtocol* instance) {
|
|||||||
free(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);
|
furi_assert(instance);
|
||||||
|
|
||||||
subghz_protocol_common_set_callback((SubGhzProtocolCommon*)instance->came, 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_came_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_came_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_came_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_came_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 = callback;
|
||||||
instance->text_callback_context = context;
|
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) {
|
static void subghz_protocol_load_keeloq_file_process_line(SubGhzProtocol* instance, string_t line) {
|
||||||
uint64_t key = 0;
|
uint64_t key = 0;
|
||||||
uint16_t type = 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) {
|
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) {
|
void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t duration) {
|
||||||
subghz_protocol_came_parse(instance->came, data);
|
subghz_protocol_came_parse(instance->came, level, duration);
|
||||||
subghz_protocol_keeloq_parse(instance->keeloq, data);
|
subghz_protocol_keeloq_parse(instance->keeloq, level, duration);
|
||||||
subghz_protocol_princeton_parse(instance->princeton, data);
|
subghz_protocol_princeton_parse(instance->princeton, level, duration);
|
||||||
subghz_protocol_nice_flo_parse(instance->nice_flo, data);
|
subghz_protocol_nice_flo_parse(instance->nice_flo, level, duration);
|
||||||
subghz_protocol_nice_flor_s_parse(instance->nice_flor_s, data);
|
subghz_protocol_nice_flor_s_parse(instance->nice_flor_s, level, duration);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "subghz_protocol_common.h"
|
#include "subghz_protocol_common.h"
|
||||||
|
|
||||||
typedef void (*SubGhzProtocolTextCallback)(string_t text, void* context);
|
typedef void (*SubGhzProtocolTextCallback)(string_t text, void* context);
|
||||||
|
typedef void (*SubGhzProtocolCommonCallbackDump)(SubGhzProtocolCommon *parser, void* context);
|
||||||
|
|
||||||
typedef struct SubGhzProtocol SubGhzProtocol;
|
typedef struct SubGhzProtocol SubGhzProtocol;
|
||||||
|
|
||||||
@ -18,16 +19,21 @@ SubGhzProtocol* subghz_protocol_alloc();
|
|||||||
*/
|
*/
|
||||||
void subghz_protocol_free(SubGhzProtocol* instance);
|
void subghz_protocol_free(SubGhzProtocol* instance);
|
||||||
|
|
||||||
/** Outputting data from all parsers
|
/** Outputting data text from all parsers
|
||||||
*
|
*
|
||||||
* @param instance - SubGhzProtocol instance
|
* @param instance - SubGhzProtocol instance
|
||||||
* @param callback - SubGhzProtocolTextCallback callback
|
* @param callback - SubGhzProtocolTextCallback callback
|
||||||
* @param context
|
* @param context
|
||||||
*/
|
*/
|
||||||
void subghz_protocol_enable_dump(
|
void subghz_protocol_enable_dump_text(SubGhzProtocol* instance,SubGhzProtocolTextCallback callback,void* context);
|
||||||
SubGhzProtocol* instance,
|
|
||||||
SubGhzProtocolTextCallback callback,
|
/** Outputting data SubGhzProtocol from all parsers
|
||||||
void* context);
|
*
|
||||||
|
* @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
|
/** File name rainbow table Nice Flor-S
|
||||||
*
|
*
|
||||||
@ -52,6 +58,7 @@ void subghz_protocol_reset(SubGhzProtocol* instance);
|
|||||||
/** Loading data into all parsers
|
/** Loading data into all parsers
|
||||||
*
|
*
|
||||||
* @param instance - SubGhzProtocol instance
|
* @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);
|
||||||
|
@ -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) {
|
switch (instance->common.parser_step) {
|
||||||
case 0:
|
case 0:
|
||||||
if ((data.level == ApiHalSubGhzCaptureLevelLow)
|
if ((!level)
|
||||||
&& (DURATION_DIFF(data.duration,instance->common.te_shot * 51)< instance->common.te_delta * 51)) { //Need protocol 36 te_shot
|
&& (DURATION_DIFF(duration, instance->common.te_shot * 51)< instance->common.te_delta * 51)) { //Need protocol 36 te_shot
|
||||||
//Found header CAME
|
//Found header CAME
|
||||||
instance->common.parser_step = 1;
|
instance->common.parser_step = 1;
|
||||||
} else {
|
} else {
|
||||||
@ -75,9 +79,9 @@ void subghz_protocol_came_parse(SubGhzProtocolCame* instance, LevelPair data) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (data.level == ApiHalSubGhzCaptureLevelLow) {
|
if (!level) {
|
||||||
break;
|
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
|
//Found start bit CAME
|
||||||
instance->common.parser_step = 2;
|
instance->common.parser_step = 2;
|
||||||
instance->common.code_found = 0;
|
instance->common.code_found = 0;
|
||||||
@ -87,33 +91,34 @@ void subghz_protocol_came_parse(SubGhzProtocolCame* instance, LevelPair data) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (data.level == ApiHalSubGhzCaptureLevelLow) { //save interval
|
if (!level) { //save interval
|
||||||
if (data.duration >= (instance->common.te_shot * 4)) {
|
if (duration >= (instance->common.te_shot * 4)) {
|
||||||
instance->common.parser_step = 1;
|
instance->common.parser_step = 1;
|
||||||
if (instance->common.code_count_bit>= instance->common.code_min_count_bit_for_found) {
|
if (instance->common.code_count_bit>= instance->common.code_min_count_bit_for_found) {
|
||||||
|
|
||||||
//ToDo out data display
|
|
||||||
instance->common.serial = 0x0;
|
instance->common.serial = 0x0;
|
||||||
instance->common.btn = 0x0;
|
instance->common.btn = 0x0;
|
||||||
if (instance->common.callback)
|
if (instance->common.callback)
|
||||||
instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
|
instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
instance->common.te_last = data.duration;
|
instance->common.te_last = duration;
|
||||||
instance->common.parser_step = 3;
|
instance->common.parser_step = 3;
|
||||||
} else {
|
} else {
|
||||||
instance->common.parser_step = 0;
|
instance->common.parser_step = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (data.level == ApiHalSubGhzCaptureLevelHigh) {
|
if (level) {
|
||||||
if ((DURATION_DIFF(instance->common.te_last,instance->common.te_shot) < instance->common.te_delta)
|
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);
|
subghz_protocol_common_add_bit(&instance->common, 0);
|
||||||
instance->common.parser_step = 2;
|
instance->common.parser_step = 2;
|
||||||
} else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_long)< instance->common.te_delta)
|
} 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);
|
subghz_protocol_common_add_bit(&instance->common, 1);
|
||||||
instance->common.parser_step = 2;
|
instance->common.parser_step = 2;
|
||||||
} else
|
} else
|
||||||
|
@ -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);
|
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
|
/** Parse accepted duration
|
||||||
*
|
*
|
||||||
* @param instance - SubGhzProtocolCame instance
|
* @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);;
|
||||||
|
@ -27,6 +27,7 @@ void subghz_protocol_common_set_callback(SubGhzProtocolCommon* common, SubGhzPro
|
|||||||
common->context = context;
|
common->context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void subghz_protocol_common_to_str(SubGhzProtocolCommon* instance, string_t output) {
|
void subghz_protocol_common_to_str(SubGhzProtocolCommon* instance, string_t output) {
|
||||||
if (instance->to_string) {
|
if (instance->to_string) {
|
||||||
instance->to_string(instance, output);
|
instance->to_string(instance, output);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#define SUBGHZ_TX_PIN_HIGTH()
|
#define SUBGHZ_TX_PIN_HIGTH()
|
||||||
#define SUBGHZ_TX_PIN_LOW()
|
#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;
|
typedef struct SubGhzProtocolCommon SubGhzProtocolCommon;
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ struct SubGhzProtocolCommon {
|
|||||||
uint8_t code_count_bit;
|
uint8_t code_count_bit;
|
||||||
uint8_t code_min_count_bit_for_found;
|
uint8_t code_min_count_bit_for_found;
|
||||||
uint8_t parser_step;
|
uint8_t parser_step;
|
||||||
uint16_t te_last;
|
uint32_t te_last;
|
||||||
uint8_t header_count;
|
uint8_t header_count;
|
||||||
uint16_t cnt;
|
uint16_t cnt;
|
||||||
uint32_t serial;
|
uint32_t serial;
|
||||||
|
@ -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) {
|
switch (instance->common.parser_step) {
|
||||||
case 0:
|
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.parser_step = 1;
|
||||||
instance->common.header_count++;
|
instance->common.header_count++;
|
||||||
} else {
|
} else {
|
||||||
@ -283,11 +287,11 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, LevelPair data
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
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;
|
instance->common.parser_step = 0;
|
||||||
break;
|
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
|
// Found header
|
||||||
instance->common.parser_step = 2;
|
instance->common.parser_step = 2;
|
||||||
instance->common.code_found = 0;
|
instance->common.code_found = 0;
|
||||||
@ -298,21 +302,19 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, LevelPair data
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (data.level == ApiHalSubGhzCaptureLevelHigh) {
|
if (level) {
|
||||||
instance->common.te_last = data.duration;
|
instance->common.te_last = duration;
|
||||||
instance->common.parser_step = 3;
|
instance->common.parser_step = 3;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (data.level == ApiHalSubGhzCaptureLevelLow) {
|
if (!level) {
|
||||||
if (data.duration >= (instance->common.te_shot * 2 + instance->common.te_delta)) {
|
if (duration >= (instance->common.te_shot * 2 + instance->common.te_delta)) {
|
||||||
// Found end TX
|
// Found end TX
|
||||||
instance->common.parser_step = 0;
|
instance->common.parser_step = 0;
|
||||||
if (instance->common.code_count_bit >= instance->common.code_min_count_bit_for_found) {
|
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;
|
instance->common.code_last_found = instance->common.code_found;
|
||||||
|
|
||||||
//ToDo out data display
|
|
||||||
subghz_protocol_keeloq_check_remote_controller(instance);
|
subghz_protocol_keeloq_check_remote_controller(instance);
|
||||||
|
|
||||||
instance->common.code_found = 0;
|
instance->common.code_found = 0;
|
||||||
@ -321,13 +323,13 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, LevelPair data
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else if ((DURATION_DIFF(instance->common.te_last, instance->common.te_shot) < instance->common.te_delta)
|
} 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) {
|
if (instance->common.code_count_bit < instance->common.code_min_count_bit_for_found) {
|
||||||
subghz_protocol_common_add_bit(&instance->common, 1);
|
subghz_protocol_common_add_bit(&instance->common, 1);
|
||||||
}
|
}
|
||||||
instance->common.parser_step = 2;
|
instance->common.parser_step = 2;
|
||||||
} else if ((DURATION_DIFF(instance->common.te_last, instance->common.te_long) < instance->common.te_delta)
|
} 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) {
|
if (instance->common.code_count_bit < instance->common.code_min_count_bit_for_found) {
|
||||||
subghz_protocol_common_add_bit(&instance->common, 0);
|
subghz_protocol_common_add_bit(&instance->common, 0);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
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
|
/** Parse accepted duration
|
||||||
*
|
*
|
||||||
* @param instance - SubGhzProtocolKeeloq instance
|
* @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
|
/** Outputting information from the parser
|
||||||
*
|
*
|
||||||
|
@ -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) {
|
switch (instance->common.parser_step) {
|
||||||
case 0:
|
case 0:
|
||||||
if ((data.level == ApiHalSubGhzCaptureLevelLow)
|
if ((!level)
|
||||||
&& (DURATION_DIFF(data.duration,instance->common.te_shot * 36)< instance->common.te_delta * 36)) {
|
&& (DURATION_DIFF(duration, instance->common.te_shot * 36)< instance->common.te_delta * 36)) {
|
||||||
//Found header Nice Flo
|
//Found header Nice Flo
|
||||||
instance->common.parser_step = 1;
|
instance->common.parser_step = 1;
|
||||||
} else {
|
} else {
|
||||||
@ -74,9 +78,9 @@ void subghz_protocol_nice_flo_parse(SubGhzProtocolNiceFlo* instance, LevelPair d
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (data.level == ApiHalSubGhzCaptureLevelLow) {
|
if (!level) {
|
||||||
break;
|
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
|
//Found start bit Nice Flo
|
||||||
instance->common.parser_step = 2;
|
instance->common.parser_step = 2;
|
||||||
instance->common.code_found = 0;
|
instance->common.code_found = 0;
|
||||||
@ -86,31 +90,30 @@ void subghz_protocol_nice_flo_parse(SubGhzProtocolNiceFlo* instance, LevelPair d
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (data.level == ApiHalSubGhzCaptureLevelLow) { //save interval
|
if (!level) { //save interval
|
||||||
if (data.duration >= (instance->common.te_shot * 4)) {
|
if (duration >= (instance->common.te_shot * 4)) {
|
||||||
instance->common.parser_step = 1;
|
instance->common.parser_step = 1;
|
||||||
if (instance->common.code_count_bit>= instance->common.code_min_count_bit_for_found) {
|
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);
|
if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
instance->common.te_last = data.duration;
|
instance->common.te_last = duration;
|
||||||
instance->common.parser_step = 3;
|
instance->common.parser_step = 3;
|
||||||
} else {
|
} else {
|
||||||
instance->common.parser_step = 0;
|
instance->common.parser_step = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (data.level == ApiHalSubGhzCaptureLevelHigh) {
|
if (level) {
|
||||||
if ((DURATION_DIFF(instance->common.te_last,instance->common.te_shot) < instance->common.te_delta)
|
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);
|
subghz_protocol_common_add_bit(&instance->common, 0);
|
||||||
instance->common.parser_step = 2;
|
instance->common.parser_step = 2;
|
||||||
} else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_long)< instance->common.te_delta)
|
} 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);
|
subghz_protocol_common_add_bit(&instance->common, 1);
|
||||||
instance->common.parser_step = 2;
|
instance->common.parser_step = 2;
|
||||||
} else
|
} else
|
||||||
|
@ -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);
|
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
|
/** Parse accepted duration
|
||||||
*
|
*
|
||||||
* @param instance - SubGhzProtocolNiceFlo instance
|
* @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);;
|
||||||
|
@ -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);
|
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) {
|
switch(instance->common.parser_step) {
|
||||||
case 0:
|
case 0:
|
||||||
if((data.level == ApiHalSubGhzCaptureLevelLow)
|
if((!level)
|
||||||
&& (DURATION_DIFF(data.duration, instance->common.te_shot * 38) < instance->common.te_delta * 38)) {
|
&& (DURATION_DIFF(duration, instance->common.te_shot * 38) < instance->common.te_delta * 38)) {
|
||||||
//Found start header Nice Flor-S
|
//Found start header Nice Flor-S
|
||||||
instance->common.parser_step = 1;
|
instance->common.parser_step = 1;
|
||||||
} else {
|
} else {
|
||||||
@ -156,8 +160,8 @@ void subghz_protocol_nice_flor_s_parse(SubGhzProtocolNiceFlorS* instance, LevelP
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if((data.level == ApiHalSubGhzCaptureLevelHigh)
|
if((level)
|
||||||
&& (DURATION_DIFF(data.duration, instance->common.te_shot * 3) < instance->common.te_delta * 3)) {
|
&& (DURATION_DIFF(duration, instance->common.te_shot * 3) < instance->common.te_delta * 3)) {
|
||||||
//Found next header Nice Flor-S
|
//Found next header Nice Flor-S
|
||||||
instance->common.parser_step = 2;
|
instance->common.parser_step = 2;
|
||||||
} else {
|
} else {
|
||||||
@ -165,8 +169,8 @@ void subghz_protocol_nice_flor_s_parse(SubGhzProtocolNiceFlorS* instance, LevelP
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if((data.level == ApiHalSubGhzCaptureLevelLow)
|
if((!level)
|
||||||
&& (DURATION_DIFF(data.duration, instance->common.te_shot * 3) < instance->common.te_delta * 3)) {
|
&& (DURATION_DIFF(duration, instance->common.te_shot * 3) < instance->common.te_delta * 3)) {
|
||||||
//Found header Nice Flor-S
|
//Found header Nice Flor-S
|
||||||
instance->common.parser_step = 3;
|
instance->common.parser_step = 3;
|
||||||
instance->common.code_found = 0;
|
instance->common.code_found = 0;
|
||||||
@ -176,31 +180,32 @@ void subghz_protocol_nice_flor_s_parse(SubGhzProtocolNiceFlorS* instance, LevelP
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if(data.level == ApiHalSubGhzCaptureLevelHigh) {
|
if(level) {
|
||||||
if(DURATION_DIFF(data.duration, instance->common.te_shot * 3) < instance->common.te_delta) {
|
if(DURATION_DIFF(duration, instance->common.te_shot * 3) < instance->common.te_delta) {
|
||||||
//Found STOP bit
|
//Found STOP bit
|
||||||
instance->common.parser_step = 0;
|
instance->common.parser_step = 0;
|
||||||
if(instance->common.code_count_bit >=instance->common.code_min_count_bit_for_found) {
|
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);
|
subghz_nice_flor_s_decoder_decrypt(instance);
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
//save interval
|
//save interval
|
||||||
instance->common.te_last = data.duration;
|
instance->common.te_last = duration;
|
||||||
instance->common.parser_step = 4;
|
instance->common.parser_step = 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
if(data.level == ApiHalSubGhzCaptureLevelLow) {
|
if(!level) {
|
||||||
if((DURATION_DIFF(instance->common.te_last, instance->common.te_shot) < instance->common.te_delta)
|
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);
|
subghz_protocol_common_add_bit(&instance->common, 0);
|
||||||
instance->common.parser_step = 3;
|
instance->common.parser_step = 3;
|
||||||
} else if(
|
} else if(
|
||||||
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) < instance->common.te_delta)
|
(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);
|
subghz_protocol_common_add_bit(&instance->common, 1);
|
||||||
instance->common.parser_step = 3;
|
instance->common.parser_step = 3;
|
||||||
} else
|
} else
|
||||||
|
@ -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);
|
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
|
/** Parse accepted duration
|
||||||
*
|
*
|
||||||
* @param instance - SubGhzProtocolNiceFlorS instance
|
* @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
|
/** Outputting information from the parser
|
||||||
*
|
*
|
||||||
|
@ -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) {
|
switch (instance->common.parser_step) {
|
||||||
case 0:
|
case 0:
|
||||||
if ((data.level == ApiHalSubGhzCaptureLevelLow)
|
if ((!level)
|
||||||
&& (DURATION_DIFF(data.duration,instance->common.te_shot * 36)< instance->common.te_delta * 36)) {
|
&& (DURATION_DIFF(duration,instance->common.te_shot * 36)< instance->common.te_delta * 36)) {
|
||||||
//Found Preambula
|
//Found Preambula
|
||||||
instance->common.parser_step = 1;
|
instance->common.parser_step = 1;
|
||||||
instance->common.code_found = 0;
|
instance->common.code_found = 0;
|
||||||
@ -77,20 +81,21 @@ void subghz_protocol_princeton_parse(SubGhzProtocolPrinceton* instance, LevelPai
|
|||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
//save duration
|
//save duration
|
||||||
if (data.level == ApiHalSubGhzCaptureLevelHigh) {
|
if (level) {
|
||||||
instance->common.te_last = data.duration;
|
instance->common.te_last = duration;
|
||||||
instance->common.parser_step = 2;
|
instance->common.parser_step = 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (data.level == ApiHalSubGhzCaptureLevelLow) {
|
if (!level) {
|
||||||
if (data.duration>= (instance->common.te_shot * 10+ instance->common.te_delta)) {
|
if (duration >= (instance->common.te_shot * 10 + instance->common.te_delta)) {
|
||||||
instance->common.parser_step = 1;
|
instance->common.parser_step = 1;
|
||||||
if (instance->common.code_count_bit>= instance->common.code_min_count_bit_for_found) {
|
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.serial = instance->common.code_found >> 4;
|
||||||
instance->common.btn = (uint8_t)instance->common.code_found & 0x00000F;
|
instance->common.btn = (uint8_t)instance->common.code_found & 0x00000F;
|
||||||
if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
|
if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
|
||||||
|
|
||||||
}
|
}
|
||||||
instance->common.code_found = 0;
|
instance->common.code_found = 0;
|
||||||
instance->common.code_count_bit = 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)
|
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);
|
subghz_protocol_common_add_bit(&instance->common, 0);
|
||||||
instance->common.parser_step = 1;
|
instance->common.parser_step = 1;
|
||||||
} else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_long)< instance->common.te_delta*3)
|
} 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);
|
subghz_protocol_common_add_bit(&instance->common, 1);
|
||||||
instance->common.parser_step = 1;
|
instance->common.parser_step = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -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);
|
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
|
/** Parse accepted duration
|
||||||
*
|
*
|
||||||
* @param instance - SubGhzProtocolPrinceton instance
|
* @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
|
/** Outputting information from the parser
|
||||||
*
|
*
|
||||||
|
@ -21,22 +21,18 @@ struct SubGhzWorker {
|
|||||||
* @param duration received signal duration
|
* @param duration received signal duration
|
||||||
* @param context
|
* @param context
|
||||||
*/
|
*/
|
||||||
void subghz_worker_rx_callback(
|
void subghz_worker_rx_callback(bool level, uint32_t duration, void* context) {
|
||||||
ApiHalSubGhzCaptureLevel level,
|
|
||||||
uint32_t duration,
|
|
||||||
void* context) {
|
|
||||||
|
|
||||||
SubGhzWorker* instance = context;
|
SubGhzWorker* instance = context;
|
||||||
|
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
LevelPair pair = {.level = level, .duration = duration};
|
LevelDuration level_duration = level_duration_make(level, duration);
|
||||||
if(instance->overrun) {
|
if(instance->overrun) {
|
||||||
instance->overrun = false;
|
instance->overrun = false;
|
||||||
pair.level = ApiHalSubGhzCaptureLevelOverrun;
|
level_duration = level_duration_reset();
|
||||||
}
|
}
|
||||||
size_t ret =
|
size_t ret =
|
||||||
xStreamBufferSendFromISR(instance->stream, &pair, sizeof(LevelPair), &xHigherPriorityTaskWoken);
|
xStreamBufferSendFromISR(instance->stream, &level_duration, sizeof(LevelDuration), &xHigherPriorityTaskWoken);
|
||||||
if(sizeof(LevelPair) != ret) instance->overrun = true;
|
if(sizeof(LevelDuration) != ret) instance->overrun = true;
|
||||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,15 +44,17 @@ void subghz_worker_rx_callback(
|
|||||||
static int32_t subghz_worker_thread_callback(void* context) {
|
static int32_t subghz_worker_thread_callback(void* context) {
|
||||||
SubGhzWorker* instance = context;
|
SubGhzWorker* instance = context;
|
||||||
|
|
||||||
LevelPair pair;
|
LevelDuration level_duration;
|
||||||
while(instance->running) {
|
while(instance->running) {
|
||||||
int ret = xStreamBufferReceive(instance->stream, &pair, sizeof(LevelPair), 10);
|
int ret = xStreamBufferReceive(instance->stream, &level_duration, sizeof(LevelDuration), 10);
|
||||||
if(ret == sizeof(LevelPair)) {
|
if(ret == sizeof(LevelDuration)) {
|
||||||
if(pair.level == ApiHalSubGhzCaptureLevelOverrun) {
|
if(level_duration_is_reset(level_duration)) {
|
||||||
printf(".");
|
printf(".");
|
||||||
if (instance->overrun_callback) instance->overrun_callback(instance->context);
|
if (instance->overrun_callback) instance->overrun_callback(instance->context);
|
||||||
} else {
|
} 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_context(instance->thread, instance);
|
||||||
furi_thread_set_callback(instance->thread, subghz_worker_thread_callback);
|
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;
|
return instance;
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@ typedef struct SubGhzWorker SubGhzWorker;
|
|||||||
|
|
||||||
typedef void (*SubGhzWorkerOverrunCallback)(void* context);
|
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
|
/** Allocate SubGhzWorker
|
||||||
*
|
*
|
||||||
|
71
lib/toolbox/level_duration.h
Normal file
71
lib/toolbox/level_duration.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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
|
Loading…
Reference in New Issue
Block a user