[FL-1758, FL-1790] SubGhz refactoring part 2, fix generation of a new GateTX serial (#696)

* WidGet: fix name  Multiline String Element
* SubGhz: rename  SubGhzProtocol to SubGhzParser and bring it up
* SubGhz: a new way to navigate in receiver views
* SubGhz: fix syntax
* WedGet: add forwarding input type to wedget button callback, fix using a callback in an application
* SubGhz: add assertions and status checks
* SubGhz: fix syntax
* [FL-1790] SubGhz: fix GateTX
* SubGhz:  add 434.42 MHz frequency support
* SubGhz: rename type protocol, add decoder stage names
* SubGhz: fix navigation through received signals when changing scenes
* SubGhz: fix 2-fsk config

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
Skorpionm 2021-09-15 19:24:19 +04:00 committed by GitHub
parent 72ca76097a
commit 8fd411097e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 1326 additions and 1113 deletions

View File

@ -118,7 +118,7 @@ static void widget_add_element(Widget* widget, WidgetElement* element) {
}); });
} }
void widget_add_string_multi_element( void widget_add_string_multiline_element(
Widget* widget, Widget* widget,
uint8_t x, uint8_t x,
uint8_t y, uint8_t y,
@ -127,9 +127,9 @@ void widget_add_string_multi_element(
Font font, Font font,
const char* text) { const char* text) {
furi_assert(widget); furi_assert(widget);
WidgetElement* string_multi_element = WidgetElement* string_multiline_element =
widget_element_string_multi_create(x, y, horizontal, vertical, font, text); widget_element_string_multiline_create(x, y, horizontal, vertical, font, text);
widget_add_element(widget, string_multi_element); widget_add_element(widget, string_multiline_element);
} }
void widget_add_string_element( void widget_add_string_element(

View File

@ -34,7 +34,7 @@ View* widget_get_view(Widget* widget);
* @param vertical - Align instance * @param vertical - Align instance
* @param font Font instance * @param font Font instance
*/ */
void widget_add_string_multi_element( void widget_add_string_multiline_element(
Widget* widget, Widget* widget,
uint8_t x, uint8_t x,
uint8_t y, uint8_t y,

View File

@ -32,26 +32,15 @@ static bool gui_button_input(InputEvent* event, WidgetElement* element) {
if(model->callback == NULL) return consumed; if(model->callback == NULL) return consumed;
if(event->key == InputKeyOk && event->type == InputTypePress && if((model->button_type == GuiButtonTypeLeft) && (event->key == InputKeyLeft)) {
model->button_type == GuiButtonTypeCenter) { model->callback(model->button_type, event->type, model->context);
model->callback(GuiButtonTypeCenterPress, model->context);
consumed = true; consumed = true;
} else if( } else if((model->button_type == GuiButtonTypeRight) && (event->key == InputKeyRight)) {
event->key == InputKeyOk && event->type == InputTypeRelease && model->callback(model->button_type, event->type, model->context);
model->button_type == GuiButtonTypeCenter) { consumed = true;
model->callback(GuiButtonTypeCenterRelease, model->context); } else if((model->button_type == GuiButtonTypeCenter) && (event->key == InputKeyOk)) {
model->callback(model->button_type, event->type, model->context);
consumed = true; consumed = true;
} else if(event->type == InputTypeShort) {
if((model->button_type == GuiButtonTypeLeft) && (event->key == InputKeyLeft)) {
model->callback(model->button_type, model->context);
consumed = true;
} else if((model->button_type == GuiButtonTypeRight) && (event->key == InputKeyRight)) {
model->callback(model->button_type, model->context);
consumed = true;
} else if((model->button_type == GuiButtonTypeCenter) && (event->key == InputKeyOk)) {
model->callback(model->button_type, model->context);
consumed = true;
}
} }
return consumed; return consumed;

View File

@ -1,16 +1,15 @@
#pragma once #pragma once
#include <furi.h> #include <furi.h>
#include <gui/view.h> #include <gui/view.h>
#include <input/input.h>
typedef enum { typedef enum {
GuiButtonTypeLeft, GuiButtonTypeLeft,
GuiButtonTypeCenter, GuiButtonTypeCenter,
GuiButtonTypeRight, GuiButtonTypeRight,
GuiButtonTypeCenterPress,
GuiButtonTypeCenterRelease,
} GuiButtonType; } GuiButtonType;
typedef void (*ButtonCallback)(GuiButtonType result, void* context); typedef void (*ButtonCallback)(GuiButtonType result, InputType type, void* context);
typedef struct WidgetElement WidgetElement; typedef struct WidgetElement WidgetElement;
typedef struct Widget Widget; typedef struct Widget Widget;
@ -31,7 +30,7 @@ struct WidgetElement {
}; };
/* Create multi string element */ /* Create multi string element */
WidgetElement* widget_element_string_multi_create( WidgetElement* widget_element_string_multiline_create(
uint8_t x, uint8_t x,
uint8_t y, uint8_t y,
Align horizontal, Align horizontal,

View File

@ -9,12 +9,12 @@ typedef struct {
Align vertical; Align vertical;
Font font; Font font;
string_t text; string_t text;
} GuiStringMultiModel; } GuiStringMultiLineModel;
static void gui_string_multi_draw(Canvas* canvas, WidgetElement* element) { static void gui_string_multiline_draw(Canvas* canvas, WidgetElement* element) {
furi_assert(canvas); furi_assert(canvas);
furi_assert(element); furi_assert(element);
GuiStringMultiModel* model = element->model; GuiStringMultiLineModel* model = element->model;
if(string_size(model->text)) { if(string_size(model->text)) {
canvas_set_font(canvas, model->font); canvas_set_font(canvas, model->font);
@ -28,16 +28,16 @@ static void gui_string_multi_draw(Canvas* canvas, WidgetElement* element) {
} }
} }
static void gui_string_multi_free(WidgetElement* gui_string) { static void gui_string_multiline_free(WidgetElement* gui_string) {
furi_assert(gui_string); furi_assert(gui_string);
GuiStringMultiModel* model = gui_string->model; GuiStringMultiLineModel* model = gui_string->model;
string_clear(model->text); string_clear(model->text);
free(gui_string->model); free(gui_string->model);
free(gui_string); free(gui_string);
} }
WidgetElement* widget_element_string_multi_create( WidgetElement* widget_element_string_multiline_create(
uint8_t x, uint8_t x,
uint8_t y, uint8_t y,
Align horizontal, Align horizontal,
@ -47,7 +47,7 @@ WidgetElement* widget_element_string_multi_create(
furi_assert(text); furi_assert(text);
// Allocate and init model // Allocate and init model
GuiStringMultiModel* model = furi_alloc(sizeof(GuiStringMultiModel)); GuiStringMultiLineModel* model = furi_alloc(sizeof(GuiStringMultiLineModel));
model->x = x; model->x = x;
model->y = y; model->y = y;
model->horizontal = horizontal; model->horizontal = horizontal;
@ -59,8 +59,8 @@ WidgetElement* widget_element_string_multi_create(
WidgetElement* gui_string = furi_alloc(sizeof(WidgetElement)); WidgetElement* gui_string = furi_alloc(sizeof(WidgetElement));
gui_string->parent = NULL; gui_string->parent = NULL;
gui_string->input = NULL; gui_string->input = NULL;
gui_string->draw = gui_string_multi_draw; gui_string->draw = gui_string_multiline_draw;
gui_string->free = gui_string_multi_free; gui_string->free = gui_string_multiline_free;
gui_string->model = model; gui_string->model = model;
return gui_string; return gui_string;

View File

@ -1,9 +1,10 @@
#include "../nfc_i.h" #include "../nfc_i.h"
void nfc_scene_delete_widget_callback(GuiButtonType result, void* context) { void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = (Nfc*)context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result); view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
} }
void nfc_scene_delete_on_enter(void* context) { void nfc_scene_delete_on_enter(void* context) {

View File

@ -7,9 +7,11 @@ enum {
NfcSceneDeviceInfoData, NfcSceneDeviceInfoData,
}; };
void nfc_scene_device_info_widget_callback(GuiButtonType result, void* context) { void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type, void* context) {
Nfc* nfc = context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, result); if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
} }
void nfc_scene_device_info_dialog_callback(DialogExResult result, void* context) { void nfc_scene_device_info_dialog_callback(DialogExResult result, void* context) {
@ -22,9 +24,11 @@ void nfc_scene_device_info_text_box_callback(void* context) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_SCENE_DEVICE_INFO_BACK_EVENT); view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_SCENE_DEVICE_INFO_BACK_EVENT);
} }
void nfc_scene_device_info_bank_card_callback(GuiButtonType result, void* context) { void nfc_scene_device_info_bank_card_callback(GuiButtonType result, InputType type, void* context) {
Nfc* nfc = context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_SCENE_DEVICE_INFO_BACK_EVENT); if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_SCENE_DEVICE_INFO_BACK_EVENT);
}
} }
void nfc_scene_device_info_on_enter(void* context) { void nfc_scene_device_info_on_enter(void* context) {

View File

@ -1,10 +1,14 @@
#include "../nfc_i.h" #include "../nfc_i.h"
#include "../helpers/nfc_emv_parser.h" #include "../helpers/nfc_emv_parser.h"
void nfc_scene_read_emv_data_success_widget_callback(GuiButtonType result, void* context) { void nfc_scene_read_emv_data_success_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = (Nfc*)context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result); view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
} }
void nfc_scene_read_emv_data_success_on_enter(void* context) { void nfc_scene_read_emv_data_success_on_enter(void* context) {

View File

@ -46,7 +46,7 @@ void subghz_scene_add_to_history_callback(SubGhzProtocolCommon* parser, void* co
if(subghz_history_add_to_history( if(subghz_history_add_to_history(
subghz->txrx->history, parser, subghz->txrx->frequency, subghz->txrx->preset)) { subghz->txrx->history, parser, subghz->txrx->frequency, subghz->txrx->preset)) {
subghz_protocol_reset(subghz->txrx->protocol); subghz_parser_reset(subghz->txrx->parser);
string_clean(str_buff); string_clean(str_buff);
subghz_history_get_text_item_menu( subghz_history_get_text_item_menu(
subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1); subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1);
@ -79,23 +79,18 @@ const void subghz_scene_receiver_on_enter(void* context) {
string_clear(str_buff); string_clear(str_buff);
subghz_scene_receiver_update_statusbar(subghz); subghz_scene_receiver_update_statusbar(subghz);
subghz_receiver_set_callback(subghz->subghz_receiver, subghz_scene_receiver_callback, subghz); subghz_receiver_set_callback(subghz->subghz_receiver, subghz_scene_receiver_callback, subghz);
subghz_protocol_enable_dump( subghz_parser_enable_dump(subghz->txrx->parser, subghz_scene_add_to_history_callback, subghz);
subghz->txrx->protocol, subghz_scene_add_to_history_callback, subghz);
subghz->state_notifications = NOTIFICATION_RX_STATE; subghz->state_notifications = NOTIFICATION_RX_STATE;
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
subghz_rx_end(subghz->txrx->worker); subghz_rx_end(subghz);
//subghz_sleep();
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
}; };
if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) { if((subghz->txrx->txrx_state == SubGhzTxRxStateIdle) ||
subghz_begin(subghz->txrx->preset); (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
subghz_rx(subghz->txrx->worker, subghz->txrx->frequency); subghz_begin(subghz, subghz->txrx->preset);
subghz->txrx->txrx_state = SubGhzTxRxStateRx; subghz_rx(subghz, subghz->txrx->frequency);
}
if(subghz->txrx->idx_menu_chosen != 0) {
subghz_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen);
} }
subghz_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen);
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReceiver); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReceiver);
} }
@ -108,16 +103,15 @@ const bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event
case SubghzReceverEventBack: case SubghzReceverEventBack:
// Stop CC1101 Rx // Stop CC1101 Rx
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
subghz_rx_end(subghz->txrx->worker); subghz_rx_end(subghz);
subghz_sleep(); subghz_sleep(subghz);
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
}; };
subghz_history_clean(subghz->txrx->history); subghz_history_clean(subghz->txrx->history);
subghz->txrx->hopper_state = SubGhzHopperStateOFF; subghz->txrx->hopper_state = SubGhzHopperStateOFF;
subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
subghz->txrx->idx_menu_chosen = 0; subghz->txrx->idx_menu_chosen = 0;
subghz_protocol_enable_dump(subghz->txrx->protocol, NULL, subghz); subghz_parser_enable_dump(subghz->txrx->parser, NULL, subghz);
scene_manager_search_and_switch_to_previous_scene( scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart); subghz->scene_manager, SubGhzSceneStart);
return true; return true;
@ -129,6 +123,7 @@ const bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event
break; break;
case SubghzReceverEventConfig: case SubghzReceverEventConfig:
subghz->state_notifications = NOTIFICATION_IDLE_STATE; subghz->state_notifications = NOTIFICATION_IDLE_STATE;
subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
return true; return true;
break; break;
@ -137,7 +132,7 @@ const bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event
} }
} else if(event.type == SceneManagerEventTypeTick) { } else if(event.type == SceneManagerEventTypeTick) {
if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
subghz_hopper_update(subghz->txrx); subghz_hopper_update(subghz);
subghz_scene_receiver_update_statusbar(subghz); subghz_scene_receiver_update_statusbar(subghz);
} }

View File

@ -1,15 +1,31 @@
#include "../subghz_i.h" #include "../subghz_i.h"
void subghz_scene_receiver_info_callback(GuiButtonType result, void* context) { typedef enum {
SubGhzSceneReceiverInfoCustomEventTxStart,
SubGhzSceneReceiverInfoCustomEventTxStop,
SubGhzSceneReceiverInfoCustomEventSave,
} SubGhzSceneReceiverInfoCustomEvent;
void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context); furi_assert(context);
SubGhz* subghz = context; SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, result);
if((result == GuiButtonTypeCenter) && (type == InputTypePress)) {
view_dispatcher_send_custom_event(
subghz->view_dispatcher, SubGhzSceneReceiverInfoCustomEventTxStart);
} else if((result == GuiButtonTypeCenter) && (type == InputTypeRelease)) {
view_dispatcher_send_custom_event(
subghz->view_dispatcher, SubGhzSceneReceiverInfoCustomEventTxStop);
} else if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
view_dispatcher_send_custom_event(
subghz->view_dispatcher, SubGhzSceneReceiverInfoCustomEventSave);
}
} }
static bool subghz_scene_receiver_info_update_parser(void* context) { static bool subghz_scene_receiver_info_update_parser(void* context) {
SubGhz* subghz = context; SubGhz* subghz = context;
subghz->txrx->protocol_result = subghz_protocol_get_by_name( subghz->txrx->protocol_result = subghz_parser_get_by_name(
subghz->txrx->protocol, subghz->txrx->parser,
subghz_history_get_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); subghz_history_get_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
if(subghz->txrx->protocol_result->to_load_protocol != NULL) { if(subghz->txrx->protocol_result->to_load_protocol != NULL) {
@ -51,7 +67,7 @@ const void subghz_scene_receiver_info_on_enter(void* context) {
string_t text; string_t text;
string_init(text); string_init(text);
subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text); subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text);
widget_add_string_multi_element( widget_add_string_multiline_element(
subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text)); subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text));
string_clear(text); string_clear(text);
@ -83,52 +99,46 @@ const void subghz_scene_receiver_info_on_enter(void* context) {
const bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) { const bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context; SubGhz* subghz = context;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeCenterPress) { if(event.event == SubGhzSceneReceiverInfoCustomEventTxStart) {
//CC1101 Stop RX -> Start TX //CC1101 Stop RX -> Start TX
subghz->state_notifications = NOTIFICATION_TX_STATE; subghz->state_notifications = NOTIFICATION_TX_STATE;
if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
subghz->txrx->hopper_state = SubGhzHopperStatePause; subghz->txrx->hopper_state = SubGhzHopperStatePause;
} }
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
subghz_rx_end(subghz->txrx->worker); subghz_rx_end(subghz);
//subghz_sleep();
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
} }
if(!subghz_scene_receiver_info_update_parser(subghz)) { if(!subghz_scene_receiver_info_update_parser(subghz)) {
return false; return false;
} }
if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) { if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) {
subghz_tx_start(subghz); subghz_tx_start(subghz);
subghz->txrx->txrx_state = SubGhzTxRxStateTx;
} }
return true; return true;
} else if(event.event == GuiButtonTypeCenterRelease) { } else if(event.event == SubGhzSceneReceiverInfoCustomEventTxStop) {
//CC1101 Stop Tx -> Start RX //CC1101 Stop Tx -> Start RX
subghz->state_notifications = NOTIFICATION_IDLE_STATE; subghz->state_notifications = NOTIFICATION_IDLE_STATE;
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
subghz_tx_stop(subghz); subghz_tx_stop(subghz);
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
} }
if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) { if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) {
subghz_begin(subghz->txrx->preset); subghz_begin(subghz, subghz->txrx->preset);
subghz_rx(subghz->txrx->worker, subghz->txrx->frequency); subghz_rx(subghz, subghz->txrx->frequency);
subghz->txrx->txrx_state = SubGhzTxRxStateRx;
} }
if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { if(subghz->txrx->hopper_state == SubGhzHopperStatePause) {
subghz->txrx->hopper_state = SubGhzHopperStateRunnig; subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
} }
subghz->state_notifications = NOTIFICATION_RX_STATE; subghz->state_notifications = NOTIFICATION_RX_STATE;
return true; return true;
} else if(event.event == GuiButtonTypeRight) { } else if(event.event == SubGhzSceneReceiverInfoCustomEventSave) {
//CC1101 Stop RX -> Save //CC1101 Stop RX -> Save
subghz->state_notifications = NOTIFICATION_IDLE_STATE; subghz->state_notifications = NOTIFICATION_IDLE_STATE;
if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
subghz->txrx->hopper_state = SubGhzHopperStateOFF; subghz->txrx->hopper_state = SubGhzHopperStateOFF;
} }
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
subghz_rx_end(subghz->txrx->worker); subghz_rx_end(subghz);
subghz_sleep(); subghz_sleep(subghz);
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
} }
if(!subghz_scene_receiver_info_update_parser(subghz)) { if(!subghz_scene_receiver_info_update_parser(subghz)) {
return false; return false;
@ -141,7 +151,7 @@ const bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent
} }
} else if(event.type == SceneManagerEventTypeTick) { } else if(event.type == SceneManagerEventTypeTick) {
if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
subghz_hopper_update(subghz->txrx); subghz_hopper_update(subghz);
} }
switch(subghz->state_notifications) { switch(subghz->state_notifications) {
case NOTIFICATION_TX_STATE: case NOTIFICATION_TX_STATE:

View File

@ -15,8 +15,7 @@ enum SubmenuIndex {
bool subghz_scene_set_type_submenu_to_find_protocol(void* context, const char* protocol_name) { bool subghz_scene_set_type_submenu_to_find_protocol(void* context, const char* protocol_name) {
SubGhz* subghz = context; SubGhz* subghz = context;
subghz->txrx->protocol_result = subghz->txrx->protocol_result = subghz_parser_get_by_name(subghz->txrx->parser, protocol_name);
subghz_protocol_get_by_name(subghz->txrx->protocol, protocol_name);
if(subghz->txrx->protocol_result == NULL) { if(subghz->txrx->protocol_result == NULL) {
string_set(subghz->error_str, "Protocol not found"); string_set(subghz->error_str, "Protocol not found");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
@ -142,7 +141,7 @@ const bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event
case SubmenuIndexGateTX: case SubmenuIndexGateTX:
if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "GateTX")) { if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "GateTX")) {
subghz->txrx->protocol_result->code_last_count_bit = 24; subghz->txrx->protocol_result->code_last_count_bit = 24;
key = (key & 0x00F0FFFF) | 0xF << 16; //btn 0xF, 0xC, 0xA, 0x6 key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?)
subghz->txrx->protocol_result->code_last_found = subghz->txrx->protocol_result->code_last_found =
subghz_protocol_common_reverse_key( subghz_protocol_common_reverse_key(
key, subghz->txrx->protocol_result->code_last_count_bit); key, subghz->txrx->protocol_result->code_last_count_bit);

View File

@ -70,21 +70,19 @@ const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent ev
if(event.event == SubghzTransmitterEventSendStart) { if(event.event == SubghzTransmitterEventSendStart) {
subghz->state_notifications = NOTIFICATION_TX_STATE; subghz->state_notifications = NOTIFICATION_TX_STATE;
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
subghz_rx_end(subghz->txrx->worker); subghz_rx_end(subghz);
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
} }
if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) { if((subghz->txrx->txrx_state == SubGhzTxRxStateIdle) ||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
subghz_tx_start(subghz); subghz_tx_start(subghz);
subghz_scene_transmitter_update_data_show(subghz); subghz_scene_transmitter_update_data_show(subghz);
subghz->txrx->txrx_state = SubGhzTxRxStateTx;
} }
return true; return true;
} else if(event.event == SubghzTransmitterEventSendStop) { } else if(event.event == SubghzTransmitterEventSendStop) {
subghz->state_notifications = NOTIFICATION_IDLE_STATE; subghz->state_notifications = NOTIFICATION_IDLE_STATE;
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
subghz_tx_stop(subghz); subghz_tx_stop(subghz);
subghz_sleep(); subghz_sleep(subghz);
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
} }
return true; return true;
} else if(event.event == SubghzTransmitterEventBack) { } else if(event.event == SubghzTransmitterEventBack) {

View File

@ -7,6 +7,7 @@ const char* const subghz_frequencies_text[] = {
"387.00", "387.00",
"433.08", "433.08",
"433.92", "433.92",
"434.42",
"434.78", "434.78",
"438.90", "438.90",
"464.00", "464.00",
@ -26,6 +27,7 @@ const uint32_t subghz_frequencies[] = {
387000000, 387000000,
433075000, /* LPD433 first */ 433075000, /* LPD433 first */
433920000, /* LPD433 mid */ 433920000, /* LPD433 mid */
434420000,
434775000, /* LPD433 last channels */ 434775000, /* LPD433 last channels */
438900000, 438900000,
464000000, 464000000,
@ -156,24 +158,24 @@ SubGhz* subghz_alloc() {
subghz->txrx = furi_alloc(sizeof(SubGhzTxRx)); subghz->txrx = furi_alloc(sizeof(SubGhzTxRx));
subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
subghz->txrx->txrx_state = SubGhzTxRxStateIdle; subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
subghz->txrx->hopper_state = SubGhzHopperStateOFF; subghz->txrx->hopper_state = SubGhzHopperStateOFF;
subghz->txrx->history = subghz_history_alloc(); subghz->txrx->history = subghz_history_alloc();
subghz->txrx->worker = subghz_worker_alloc(); subghz->txrx->worker = subghz_worker_alloc();
subghz->txrx->protocol = subghz_protocol_alloc(); subghz->txrx->parser = subghz_parser_alloc();
subghz_worker_set_overrun_callback( subghz_worker_set_overrun_callback(
subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset); subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_parser_reset);
subghz_worker_set_pair_callback( subghz_worker_set_pair_callback(
subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_parser_parse);
subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->protocol); subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->parser);
//Init Error_str //Init Error_str
string_init(subghz->error_str); string_init(subghz->error_str);
subghz_protocol_load_keeloq_file(subghz->txrx->protocol, "/ext/subghz/keeloq_mfcodes"); subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/keeloq_mfcodes");
subghz_protocol_load_nice_flor_s_file(subghz->txrx->protocol, "/ext/subghz/nice_floor_s_rx"); subghz_parser_load_nice_flor_s_file(subghz->txrx->parser, "/ext/subghz/nice_floor_s_rx");
//subghz_protocol_enable_dump_text(subghz->protocol, subghz_text_callback, subghz); //subghz_parser_enable_dump_text(subghz->protocol, subghz_text_callback, subghz);
return subghz; return subghz;
} }
@ -232,7 +234,7 @@ void subghz_free(SubGhz* subghz) {
subghz->gui = NULL; subghz->gui = NULL;
//Worker & Protocol & History //Worker & Protocol & History
subghz_protocol_free(subghz->txrx->protocol); subghz_parser_free(subghz->txrx->parser);
subghz_worker_free(subghz->txrx->worker); subghz_worker_free(subghz->txrx->worker);
subghz_history_free(subghz->txrx->history); subghz_history_free(subghz->txrx->history);
free(subghz->txrx); free(subghz->txrx);

View File

@ -3,7 +3,7 @@
#include <furi.h> #include <furi.h>
#include <furi-hal.h> #include <furi-hal.h>
#include <stream_buffer.h> #include <stream_buffer.h>
#include <lib/subghz/protocols/subghz_protocol.h> #include <lib/subghz/subghz_parser.h>
#include <lib/subghz/protocols/subghz_protocol_common.h> #include <lib/subghz/protocols/subghz_protocol_common.h>
#include <lib/subghz/protocols/subghz_protocol_princeton.h> #include <lib/subghz/protocols/subghz_protocol_princeton.h>
@ -205,10 +205,10 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
instance->stream = xStreamBufferCreate(sizeof(LevelDuration) * 1024, sizeof(LevelDuration)); instance->stream = xStreamBufferCreate(sizeof(LevelDuration) * 1024, sizeof(LevelDuration));
furi_check(instance->stream); furi_check(instance->stream);
SubGhzProtocol* protocol = subghz_protocol_alloc(); SubGhzParser* parser = subghz_parser_alloc();
subghz_protocol_load_keeloq_file(protocol, "/ext/subghz/keeloq_mfcodes"); subghz_parser_load_keeloq_file(parser, "/ext/subghz/keeloq_mfcodes");
subghz_protocol_load_nice_flor_s_file(protocol, "/ext/subghz/nice_floor_s_rx"); subghz_parser_load_nice_flor_s_file(parser, "/ext/subghz/nice_floor_s_rx");
subghz_protocol_enable_dump_text(protocol, subghz_cli_command_rx_text_callback, instance); subghz_parser_enable_dump_text(parser, subghz_cli_command_rx_text_callback, instance);
// Configure radio // Configure radio
furi_hal_subghz_reset(); furi_hal_subghz_reset();
@ -228,11 +228,11 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
if(ret == sizeof(LevelDuration)) { if(ret == sizeof(LevelDuration)) {
if(level_duration_is_reset(level_duration)) { if(level_duration_is_reset(level_duration)) {
printf("."); printf(".");
subghz_protocol_reset(protocol); subghz_parser_reset(parser);
} else { } else {
bool level = level_duration_get_level(level_duration); bool level = level_duration_get_level(level_duration);
uint32_t duration = level_duration_get_duration(level_duration); uint32_t duration = level_duration_get_duration(level_duration);
subghz_protocol_parse(protocol, level, duration); subghz_parser_parse(parser, level, duration);
} }
} }
} }
@ -244,7 +244,7 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
printf("\r\nPackets recieved %u\r\n", instance->packet_count); printf("\r\nPackets recieved %u\r\n", instance->packet_count);
// Cleanup // Cleanup
subghz_protocol_free(protocol); subghz_parser_free(parser);
vStreamBufferDelete(instance->stream); vStreamBufferDelete(instance->stream);
free(instance); free(instance);
} }

View File

@ -112,5 +112,3 @@ bool subghz_history_add_to_history(
* @return SubGhzProtocolCommonLoad* * @return SubGhzProtocolCommonLoad*
*/ */
SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx); SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx);
void subghz_hopper_update(void* context);

View File

@ -10,19 +10,23 @@
#include "../notification/notification.h" #include "../notification/notification.h"
#include "views/subghz_receiver.h" #include "views/subghz_receiver.h"
void subghz_begin(FuriHalSubGhzPreset preset) { void subghz_begin(SubGhz* subghz, FuriHalSubGhzPreset preset) {
furi_assert(subghz);
furi_hal_subghz_reset(); furi_hal_subghz_reset();
furi_hal_subghz_idle(); furi_hal_subghz_idle();
furi_hal_subghz_load_preset(preset); furi_hal_subghz_load_preset(preset);
hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
} }
uint32_t subghz_rx(void* context, uint32_t frequency) { uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency) {
furi_assert(context); furi_assert(subghz);
if(!furi_hal_subghz_is_frequency_valid(frequency)) { if(!furi_hal_subghz_is_frequency_valid(frequency)) {
furi_crash(NULL); furi_crash(NULL);
} }
SubGhzWorker* worker = context; furi_assert(
subghz->txrx->txrx_state != SubGhzTxRxStateRx &&
subghz->txrx->txrx_state != SubGhzTxRxStateSleep);
furi_hal_subghz_idle(); furi_hal_subghz_idle();
uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
@ -30,45 +34,54 @@ uint32_t subghz_rx(void* context, uint32_t frequency) {
furi_hal_subghz_flush_rx(); furi_hal_subghz_flush_rx();
furi_hal_subghz_rx(); furi_hal_subghz_rx();
furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, worker); furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->txrx->worker);
subghz_worker_start(worker); subghz_worker_start(subghz->txrx->worker);
subghz->txrx->txrx_state = SubGhzTxRxStateRx;
return value; return value;
} }
uint32_t subghz_tx(uint32_t frequency) { uint32_t subghz_tx(SubGhz* subghz, uint32_t frequency) {
furi_assert(subghz);
if(!furi_hal_subghz_is_frequency_valid(frequency)) { if(!furi_hal_subghz_is_frequency_valid(frequency)) {
furi_crash(NULL); furi_crash(NULL);
} }
furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep);
furi_hal_subghz_idle(); furi_hal_subghz_idle();
uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
hal_gpio_write(&gpio_cc1101_g0, true); hal_gpio_write(&gpio_cc1101_g0, true);
furi_hal_subghz_tx(); furi_hal_subghz_tx();
subghz->txrx->txrx_state = SubGhzTxRxStateTx;
return value; return value;
} }
void subghz_idle(void) { void subghz_idle(SubGhz* subghz) {
furi_assert(subghz);
furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep);
furi_hal_subghz_idle(); furi_hal_subghz_idle();
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
} }
void subghz_rx_end(void* context) { void subghz_rx_end(SubGhz* subghz) {
furi_assert(context); furi_assert(subghz);
SubGhzWorker* worker = context; furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateRx);
if(subghz_worker_is_running(subghz->txrx->worker)) {
if(subghz_worker_is_running(worker)) { subghz_worker_stop(subghz->txrx->worker);
subghz_worker_stop(worker);
furi_hal_subghz_stop_async_rx(); furi_hal_subghz_stop_async_rx();
} }
furi_hal_subghz_idle(); furi_hal_subghz_idle();
subghz->txrx->txrx_state = SubGhzTxRxStateIdle;
} }
void subghz_sleep(void) { void subghz_sleep(SubGhz* subghz) {
furi_assert(subghz);
furi_hal_subghz_sleep(); furi_hal_subghz_sleep();
subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
} }
void subghz_frequency_preset_to_str(void* context, string_t output) { static void subghz_frequency_preset_to_str(SubGhz* subghz, string_t output) {
furi_assert(context); furi_assert(subghz);
SubGhz* subghz = context;
string_cat_printf( string_cat_printf(
output, output,
"Frequency: %d\n" "Frequency: %d\n"
@ -77,9 +90,9 @@ void subghz_frequency_preset_to_str(void* context, string_t output) {
(int)subghz->txrx->preset); (int)subghz->txrx->preset);
} }
void subghz_tx_start(void* context) { void subghz_tx_start(SubGhz* subghz) {
furi_assert(context); furi_assert(subghz);
SubGhz* subghz = context;
subghz->txrx->encoder = subghz_protocol_encoder_common_alloc(); subghz->txrx->encoder = subghz_protocol_encoder_common_alloc();
subghz->txrx->encoder->repeat = 200; //max repeat with the button held down subghz->txrx->encoder->repeat = 200; //max repeat with the button held down
//get upload //get upload
@ -87,14 +100,14 @@ void subghz_tx_start(void* context) {
if(subghz->txrx->protocol_result->get_upload_protocol( if(subghz->txrx->protocol_result->get_upload_protocol(
subghz->txrx->protocol_result, subghz->txrx->encoder)) { subghz->txrx->protocol_result, subghz->txrx->encoder)) {
if(subghz->txrx->preset) { if(subghz->txrx->preset) {
subghz_begin(subghz->txrx->preset); subghz_begin(subghz, subghz->txrx->preset);
} else { } else {
subghz_begin(FuriHalSubGhzPresetOok270Async); subghz_begin(subghz, FuriHalSubGhzPresetOok270Async);
} }
if(subghz->txrx->frequency) { if(subghz->txrx->frequency) {
subghz_tx(subghz->txrx->frequency); subghz_tx(subghz, subghz->txrx->frequency);
} else { } else {
subghz_tx(433920000); subghz_tx(subghz, 433920000);
} }
//Start TX //Start TX
@ -104,15 +117,15 @@ void subghz_tx_start(void* context) {
} }
} }
void subghz_tx_stop(void* context) { void subghz_tx_stop(SubGhz* subghz) {
furi_assert(context); furi_assert(subghz);
SubGhz* subghz = context; furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateTx);
//Stop TX //Stop TX
furi_hal_subghz_stop_async_tx(); furi_hal_subghz_stop_async_tx();
subghz_protocol_encoder_common_free(subghz->txrx->encoder); subghz_protocol_encoder_common_free(subghz->txrx->encoder);
furi_hal_subghz_idle(); subghz_idle(subghz);
//if protocol dynamic then we save the last upload //if protocol dynamic then we save the last upload
if(subghz->txrx->protocol_result->type_protocol == TYPE_PROTOCOL_DYNAMIC) { if(subghz->txrx->protocol_result->type_protocol == SubGhzProtocolCommonTypeDynamic) {
subghz_save_protocol_to_file(subghz, subghz->text_store); subghz_save_protocol_to_file(subghz, subghz->text_store);
} }
notification_message(subghz->notifications, &sequence_reset_red); notification_message(subghz->notifications, &sequence_reset_red);
@ -164,7 +177,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) {
// strlen("Protocol: ") = 10 // strlen("Protocol: ") = 10
string_right(temp_str, 10); string_right(temp_str, 10);
subghz->txrx->protocol_result = subghz->txrx->protocol_result =
subghz_protocol_get_by_name(subghz->txrx->protocol, string_get_cstr(temp_str)); subghz_parser_get_by_name(subghz->txrx->parser, string_get_cstr(temp_str));
if(subghz->txrx->protocol_result == NULL) { if(subghz->txrx->protocol_result == NULL) {
break; break;
} }
@ -186,10 +199,10 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) {
return loaded; return loaded;
} }
bool subghz_save_protocol_to_file(void* context, const char* dev_name) { bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name) {
furi_assert(context); furi_assert(subghz);
SubGhz* subghz = context;
furi_assert(subghz->txrx->protocol_result); furi_assert(subghz->txrx->protocol_result);
FileWorker* file_worker = file_worker_alloc(false); FileWorker* file_worker = file_worker_alloc(false);
string_t dev_file_name; string_t dev_file_name;
string_init(dev_file_name); string_init(dev_file_name);
@ -308,7 +321,7 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) {
// strlen("Protocol: ") = 10 // strlen("Protocol: ") = 10
string_right(temp_str, 10); string_right(temp_str, 10);
subghz->txrx->protocol_result = subghz->txrx->protocol_result =
subghz_protocol_get_by_name(subghz->txrx->protocol, string_get_cstr(temp_str)); subghz_parser_get_by_name(subghz->txrx->parser, string_get_cstr(temp_str));
if(subghz->txrx->protocol_result == NULL) { if(subghz->txrx->protocol_result == NULL) {
break; break;
} }
@ -342,11 +355,10 @@ uint32_t subghz_random_serial(void) {
return (uint32_t)rand(); return (uint32_t)rand();
} }
void subghz_hopper_update(void* context) { void subghz_hopper_update(SubGhz* subghz) {
furi_assert(context); furi_assert(subghz);
SubGhzTxRx* txrx = context;
switch(txrx->hopper_state) { switch(subghz->txrx->hopper_state) {
case SubGhzHopperStateOFF: case SubGhzHopperStateOFF:
return; return;
break; break;
@ -354,8 +366,8 @@ void subghz_hopper_update(void* context) {
return; return;
break; break;
case SubGhzHopperStateRSSITimeOut: case SubGhzHopperStateRSSITimeOut:
if(txrx->hopper_timeout != 0) { if(subghz->txrx->hopper_timeout != 0) {
txrx->hopper_timeout--; subghz->txrx->hopper_timeout--;
return; return;
} }
break; break;
@ -363,35 +375,33 @@ void subghz_hopper_update(void* context) {
break; break;
} }
float rssi = -127.0f; float rssi = -127.0f;
if(txrx->hopper_state != SubGhzHopperStateRSSITimeOut) { if(subghz->txrx->hopper_state != SubGhzHopperStateRSSITimeOut) {
// See RSSI Calculation timings in CC1101 17.3 RSSI // See RSSI Calculation timings in CC1101 17.3 RSSI
rssi = furi_hal_subghz_get_rssi(); rssi = furi_hal_subghz_get_rssi();
// Stay if RSSI is high enough // Stay if RSSI is high enough
if(rssi > -90.0f) { if(rssi > -90.0f) {
txrx->hopper_timeout = 10; subghz->txrx->hopper_timeout = 10;
txrx->hopper_state = SubGhzHopperStateRSSITimeOut; subghz->txrx->hopper_state = SubGhzHopperStateRSSITimeOut;
return; return;
} }
} else { } else {
txrx->hopper_state = SubGhzHopperStateRunnig; subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
} }
// Select next frequency // Select next frequency
if(txrx->hopper_idx_frequency < subghz_hopper_frequencies_count - 1) { if(subghz->txrx->hopper_idx_frequency < subghz_hopper_frequencies_count - 1) {
txrx->hopper_idx_frequency++; subghz->txrx->hopper_idx_frequency++;
} else { } else {
txrx->hopper_idx_frequency = 0; subghz->txrx->hopper_idx_frequency = 0;
} }
if(txrx->txrx_state == SubGhzTxRxStateRx) { if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
subghz_rx_end(txrx->worker); subghz_rx_end(subghz);
txrx->txrx_state = SubGhzTxRxStateIdle;
}; };
if(txrx->txrx_state == SubGhzTxRxStateIdle) { if(subghz->txrx->txrx_state == SubGhzTxRxStateIdle) {
subghz_protocol_reset(txrx->protocol); subghz_parser_reset(subghz->txrx->parser);
txrx->frequency = subghz_hopper_frequencies[txrx->hopper_idx_frequency]; subghz->txrx->frequency = subghz_hopper_frequencies[subghz->txrx->hopper_idx_frequency];
subghz_rx(txrx->worker, txrx->frequency); subghz_rx(subghz, subghz->txrx->frequency);
txrx->txrx_state = SubGhzTxRxStateRx;
} }
} }

View File

@ -22,7 +22,8 @@
#include <subghz/scenes/subghz_scene.h> #include <subghz/scenes/subghz_scene.h>
#include <lib/subghz/subghz_worker.h> #include <lib/subghz/subghz_worker.h>
#include <lib/subghz/protocols/subghz_protocol.h>
#include <lib/subghz/subghz_parser.h>
#include <lib/subghz/protocols/subghz_protocol_common.h> #include <lib/subghz/protocols/subghz_protocol_common.h>
#include "subghz_history.h" #include "subghz_history.h"
@ -47,6 +48,7 @@ typedef enum {
SubGhzTxRxStateIdle, SubGhzTxRxStateIdle,
SubGhzTxRxStateRx, SubGhzTxRxStateRx,
SubGhzTxRxStateTx, SubGhzTxRxStateTx,
SubGhzTxRxStateSleep,
} SubGhzTxRxState; } SubGhzTxRxState;
/** SubGhzHopperState state */ /** SubGhzHopperState state */
@ -59,7 +61,7 @@ typedef enum {
struct SubGhzTxRx { struct SubGhzTxRx {
SubGhzWorker* worker; SubGhzWorker* worker;
SubGhzProtocol* protocol; SubGhzParser* parser;
SubGhzProtocolCommon* protocol_result; SubGhzProtocolCommon* protocol_result;
SubGhzProtocolCommonEncoder* encoder; SubGhzProtocolCommonEncoder* encoder;
uint32_t frequency; uint32_t frequency;
@ -115,15 +117,14 @@ typedef enum {
SubGhzViewTestPacket, SubGhzViewTestPacket,
} SubGhzView; } SubGhzView;
void subghz_begin(FuriHalSubGhzPreset preset); void subghz_begin(SubGhz* subghz, FuriHalSubGhzPreset preset);
uint32_t subghz_rx(void* context, uint32_t frequency); uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency);
uint32_t subghz_tx(uint32_t frequency); void subghz_rx_end(SubGhz* subghz);
void subghz_idle(void); void subghz_sleep(SubGhz* subghz);
void subghz_rx_end(void* context); void subghz_tx_start(SubGhz* subghz);
void subghz_sleep(void); void subghz_tx_stop(SubGhz* subghz);
void subghz_tx_start(void* context);
void subghz_tx_stop(void* context);
bool subghz_key_load(SubGhz* subghz, const char* file_path); bool subghz_key_load(SubGhz* subghz, const char* file_path);
bool subghz_save_protocol_to_file(void* context, const char* dev_name); bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name);
bool subghz_load_protocol_from_file(SubGhz* subghz); bool subghz_load_protocol_from_file(SubGhz* subghz);
uint32_t subghz_random_serial(void); uint32_t subghz_random_serial(void);
void subghz_hopper_update(SubGhz* subghz);

View File

@ -29,9 +29,9 @@ struct SubGhzReceiverHistory {
typedef struct SubGhzReceiverHistory SubGhzReceiverHistory; typedef struct SubGhzReceiverHistory SubGhzReceiverHistory;
static const Icon* ReceiverItemIcons[] = { static const Icon* ReceiverItemIcons[] = {
[TYPE_PROTOCOL_UNKNOWN] = &I_Quest_7x8, [SubGhzProtocolCommonTypeUnknown] = &I_Quest_7x8,
[TYPE_PROTOCOL_STATIC] = &I_Unlock_7x8, [SubGhzProtocolCommonTypeStatic] = &I_Unlock_7x8,
[TYPE_PROTOCOL_DYNAMIC] = &I_Lock_7x8, [SubGhzProtocolCommonTypeDynamic] = &I_Lock_7x8,
}; };
struct SubghzReceiver { struct SubghzReceiver {
@ -90,7 +90,13 @@ void subghz_receiver_add_item_to_menu(
SubGhzReceiverMenuItemArray_push_raw(model->history->data); SubGhzReceiverMenuItemArray_push_raw(model->history->data);
string_init_set_str(item_menu->item_str, name); string_init_set_str(item_menu->item_str, name);
item_menu->type = type; item_menu->type = type;
model->history_item++; if((model->idx == model->history_item - 1)) {
model->history_item++;
model->idx++;
} else {
model->history_item++;
}
return true; return true;
}); });
subghz_receiver_update_offset(subghz_receiver); subghz_receiver_update_offset(subghz_receiver);

View File

@ -15,166 +15,174 @@ static const uint8_t furi_hal_subghz_preset_ook_270khz_async_regs[][2] = {
// https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration
/* GPIO GD0 */ /* GPIO GD0 */
{ CC1101_IOCFG0, 0x0D }, // GD0 as async serial data output/input {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input
/* FIFO and internals */ /* FIFO and internals */
{ CC1101_FIFOTHR, 0x47 }, // The only important bit is ADC_RETENTION, FIFO Tx=33 Rx=32 {CC1101_FIFOTHR, 0x47}, // The only important bit is ADC_RETENTION, FIFO Tx=33 Rx=32
/* Packet engine */ /* Packet engine */
{ CC1101_PKTCTRL0, 0x32 }, // Async, continious, no whitening {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening
/* Frequency Synthesizer Control */ /* Frequency Synthesizer Control */
{ CC1101_FSCTRL1, 0x06 }, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz
// Modem Configuration // Modem Configuration
{ CC1101_MDMCFG0, 0x00 }, // Channel spacing is 25kHz {CC1101_MDMCFG0, 0x00}, // Channel spacing is 25kHz
{ CC1101_MDMCFG1, 0x00 }, // Channel spacing is 25kHz {CC1101_MDMCFG1, 0x00}, // Channel spacing is 25kHz
{ CC1101_MDMCFG2, 0x30 }, // Format ASK/OOK, No preamble/sync {CC1101_MDMCFG2, 0x30}, // Format ASK/OOK, No preamble/sync
{ CC1101_MDMCFG3, 0x32 }, // Data rate is 3.79372 kBaud {CC1101_MDMCFG3, 0x32}, // Data rate is 3.79372 kBaud
{ CC1101_MDMCFG4, 0x67 }, // Rx BW filter is 270.833333kHz {CC1101_MDMCFG4, 0x67}, // Rx BW filter is 270.833333kHz
/* Main Radio Control State Machine */ /* Main Radio Control State Machine */
{ CC1101_MCSM0, 0x18 }, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us)
/* Frequency Offset Compensation Configuration */ /* Frequency Offset Compensation Configuration */
{ CC1101_FOCCFG, 0x18 }, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off {CC1101_FOCCFG,
0x18}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off
/* Automatic Gain Control */ /* Automatic Gain Control */
{ CC1101_AGCTRL0, 0x40 }, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary {CC1101_AGCTRL0,
{ CC1101_AGCTRL1, 0x00 }, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET 0x40}, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary
{ CC1101_AGCTRL2, 0x03 }, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB {CC1101_AGCTRL1,
0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET
{CC1101_AGCTRL2, 0x03}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB
/* Wake on radio and timeouts control */ /* Wake on radio and timeouts control */
{ CC1101_WORCTRL, 0xFB }, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours
/* Frontend configuration */ /* Frontend configuration */
{ CC1101_FREND0, 0x11 }, // Adjusts current TX LO buffer + high is PATABLE[1] {CC1101_FREND0, 0x11}, // Adjusts current TX LO buffer + high is PATABLE[1]
{ CC1101_FREND1, 0xB6 }, // {CC1101_FREND1, 0xB6}, //
/* Frequency Synthesizer Calibration, valid for 433.92 */ /* Frequency Synthesizer Calibration, valid for 433.92 */
{ CC1101_FSCAL3, 0xE9 }, {CC1101_FSCAL3, 0xE9},
{ CC1101_FSCAL2, 0x2A }, {CC1101_FSCAL2, 0x2A},
{ CC1101_FSCAL1, 0x00 }, {CC1101_FSCAL1, 0x00},
{ CC1101_FSCAL0, 0x1F }, {CC1101_FSCAL0, 0x1F},
/* Magic f4ckery */ /* Magic f4ckery */
{ CC1101_TEST2, 0x81 }, // FIFOTHR ADC_RETENTION=1 matched value {CC1101_TEST2, 0x81}, // FIFOTHR ADC_RETENTION=1 matched value
{ CC1101_TEST1, 0x35 }, // FIFOTHR ADC_RETENTION=1 matched value {CC1101_TEST1, 0x35}, // FIFOTHR ADC_RETENTION=1 matched value
{ CC1101_TEST0, 0x09 }, // VCO selection calibration stage is disabled {CC1101_TEST0, 0x09}, // VCO selection calibration stage is disabled
/* End */ /* End */
{ 0, 0 }, {0, 0},
}; };
static const uint8_t furi_hal_subghz_preset_ook_650khz_async_regs[][2] = { static const uint8_t furi_hal_subghz_preset_ook_650khz_async_regs[][2] = {
// https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration
/* GPIO GD0 */ /* GPIO GD0 */
{ CC1101_IOCFG0, 0x0D }, // GD0 as async serial data output/input {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input
/* FIFO and internals */ /* FIFO and internals */
{ CC1101_FIFOTHR, 0x07 }, // The only important bit is ADC_RETENTION {CC1101_FIFOTHR, 0x07}, // The only important bit is ADC_RETENTION
/* Packet engine */ /* Packet engine */
{ CC1101_PKTCTRL0, 0x32 }, // Async, continious, no whitening {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening
/* Frequency Synthesizer Control */ /* Frequency Synthesizer Control */
{ CC1101_FSCTRL1, 0x06 }, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz
// Modem Configuration // Modem Configuration
{ CC1101_MDMCFG0, 0x00 }, // Channel spacing is 25kHz {CC1101_MDMCFG0, 0x00}, // Channel spacing is 25kHz
{ CC1101_MDMCFG1, 0x00 }, // Channel spacing is 25kHz {CC1101_MDMCFG1, 0x00}, // Channel spacing is 25kHz
{ CC1101_MDMCFG2, 0x30 }, // Format ASK/OOK, No preamble/sync {CC1101_MDMCFG2, 0x30}, // Format ASK/OOK, No preamble/sync
{ CC1101_MDMCFG3, 0x32 }, // Data rate is 3.79372 kBaud {CC1101_MDMCFG3, 0x32}, // Data rate is 3.79372 kBaud
{ CC1101_MDMCFG4, 0x17 }, // Rx BW filter is 650.000kHz {CC1101_MDMCFG4, 0x17}, // Rx BW filter is 650.000kHz
/* Main Radio Control State Machine */ /* Main Radio Control State Machine */
{ CC1101_MCSM0, 0x18 }, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us)
/* Frequency Offset Compensation Configuration */ /* Frequency Offset Compensation Configuration */
{ CC1101_FOCCFG, 0x18 }, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off {CC1101_FOCCFG,
0x18}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off
/* Automatic Gain Control */ /* Automatic Gain Control */
{ CC1101_AGCTRL0, 0x40 }, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary {CC1101_AGCTRL0,
{ CC1101_AGCTRL1, 0x00 }, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET 0x40}, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary
{ CC1101_AGCTRL2, 0x03 }, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB {CC1101_AGCTRL1,
0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET
{CC1101_AGCTRL2, 0x03}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB
/* Wake on radio and timeouts control */ /* Wake on radio and timeouts control */
{ CC1101_WORCTRL, 0xFB }, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours
/* Frontend configuration */ /* Frontend configuration */
{ CC1101_FREND0, 0x11 }, // Adjusts current TX LO buffer + high is PATABLE[1] {CC1101_FREND0, 0x11}, // Adjusts current TX LO buffer + high is PATABLE[1]
{ CC1101_FREND1, 0xB6 }, // {CC1101_FREND1, 0xB6}, //
/* Frequency Synthesizer Calibration, valid for 433.92 */ /* Frequency Synthesizer Calibration, valid for 433.92 */
{ CC1101_FSCAL3, 0xE9 }, {CC1101_FSCAL3, 0xE9},
{ CC1101_FSCAL2, 0x2A }, {CC1101_FSCAL2, 0x2A},
{ CC1101_FSCAL1, 0x00 }, {CC1101_FSCAL1, 0x00},
{ CC1101_FSCAL0, 0x1F }, {CC1101_FSCAL0, 0x1F},
/* Magic f4ckery */ /* Magic f4ckery */
{ CC1101_TEST2, 0x88 }, {CC1101_TEST2, 0x88},
{ CC1101_TEST1, 0x31 }, {CC1101_TEST1, 0x31},
{ CC1101_TEST0, 0x09 }, // VCO selection calibration stage is disabled {CC1101_TEST0, 0x09}, // VCO selection calibration stage is disabled
/* End */ /* End */
{ 0, 0 }, {0, 0},
}; };
static const uint8_t furi_hal_subghz_preset_2fsk_async_regs[][2] = { static const uint8_t furi_hal_subghz_preset_2fsk_async_regs[][2] = {
// https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration
/* GPIO GD0 */ /* GPIO GD0 */
{ CC1101_IOCFG0, 0x0D }, // GD0 as async serial data output/input {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input
/* FIFO and internals */ /* FIFO and internals */
{ CC1101_FIFOTHR, 0x47 }, // The only important bit is ADC_RETENTION {CC1101_FIFOTHR, 0x47}, // The only important bit is ADC_RETENTION
/* Packet engine */ /* Packet engine */
{ CC1101_PKTCTRL0, 0x32 }, // Async, continious, no whitening {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening
/* Frequency Synthesizer Control */ /* Frequency Synthesizer Control */
{ CC1101_FSCTRL1, 0x06 }, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz
// Modem Configuration // Modem Configuration
{ CC1101_MDMCFG0, 0xF8 }, {CC1101_MDMCFG0, 0x00},
{ CC1101_MDMCFG1, 0x00 }, // No preamble/sync {CC1101_MDMCFG1, 0x02},
{ CC1101_MDMCFG2, 0x80 }, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized) {CC1101_MDMCFG2, 0x04}, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized)
{ CC1101_MDMCFG3, 0x83 }, // Data rate is 9.59587 kBaud {CC1101_MDMCFG3, 0x8B}, // Data rate is 19.5885 kBaud
{ CC1101_MDMCFG4, 0x88 }, // Rx BW filter is 203.125000kHz {CC1101_MDMCFG4, 0x69}, // Rx BW filter is 270.833333 kHz
{ CC1101_DEVIATN, 0x14}, //Deviation 4.760742 khz {CC1101_DEVIATN, 0x47}, //Deviation 47.607422 khz
/* Main Radio Control State Machine */ /* Main Radio Control State Machine */
{ CC1101_MCSM0, 0x18 }, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us)
/* Frequency Offset Compensation Configuration */ /* Frequency Offset Compensation Configuration */
{ CC1101_FOCCFG, 0x18 }, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off {CC1101_FOCCFG,
0x16}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off
/* Automatic Gain Control */ /* Automatic Gain Control */
{ CC1101_AGCTRL0, 0x40 }, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary {CC1101_AGCTRL0,
{ CC1101_AGCTRL1, 0x00 }, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET 0x40}, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary
{ CC1101_AGCTRL2, 0x03 }, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB {CC1101_AGCTRL1,
0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET
{CC1101_AGCTRL2, 0x03}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB
/* Wake on radio and timeouts control */ /* Wake on radio and timeouts control */
{ CC1101_WORCTRL, 0xFB }, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours
/* Frontend configuration */ /* Frontend configuration */
{ CC1101_FREND0, 0x10 }, // Adjusts current TX LO buffer {CC1101_FREND0, 0x10}, // Adjusts current TX LO buffer
{ CC1101_FREND1, 0xB6 }, // {CC1101_FREND1, 0xB6}, //
/* Frequency Synthesizer Calibration, valid for 433.92 */ /* Frequency Synthesizer Calibration, valid for 433.92 */
{ CC1101_FSCAL3, 0xE9 }, {CC1101_FSCAL3, 0xE9},
{ CC1101_FSCAL2, 0x2A }, {CC1101_FSCAL2, 0x2A},
{ CC1101_FSCAL1, 0x00 }, {CC1101_FSCAL1, 0x00},
{ CC1101_FSCAL0, 0x1F }, {CC1101_FSCAL0, 0x1F},
/* Magic f4ckery */ /* Magic f4ckery */
{ CC1101_TEST2, 0x81 }, // FIFOTHR ADC_RETENTION=1 matched value {CC1101_TEST2, 0x81}, // FIFOTHR ADC_RETENTION=1 matched value
{ CC1101_TEST1, 0x35 }, // FIFOTHR ADC_RETENTION=1 matched value {CC1101_TEST1, 0x35}, // FIFOTHR ADC_RETENTION=1 matched value
{ CC1101_TEST0, 0x09 }, // VCO selection calibration stage is disabled {CC1101_TEST0, 0x09}, // VCO selection calibration stage is disabled
/* End */ /* End */
{ 0, 0 }, {0, 0},
}; };
static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = { static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = {
0x00, 0x00,
@ -184,8 +192,7 @@ static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = {
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00 0x00};
};
static const uint8_t furi_hal_subghz_preset_2fsk_async_patable[8] = { static const uint8_t furi_hal_subghz_preset_2fsk_async_patable[8] = {
0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
0x00, 0x00,
@ -195,6 +202,7 @@ static const uint8_t furi_hal_subghz_preset_2fsk_async_patable[8] = {
0x00, 0x00,
0x00, 0x00,
0x00 0x00
}; };
void furi_hal_subghz_init() { void furi_hal_subghz_init() {
@ -217,11 +225,13 @@ void furi_hal_subghz_init() {
// GD0 low // GD0 low
cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW); cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW);
while(hal_gpio_read(&gpio_cc1101_g0) != false); while(hal_gpio_read(&gpio_cc1101_g0) != false)
;
// GD0 high // GD0 high
cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV);
while(hal_gpio_read(&gpio_cc1101_g0) != true); while(hal_gpio_read(&gpio_cc1101_g0) != true)
;
// Reset GD0 to floating state // Reset GD0 to floating state
cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance); cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance);
@ -257,8 +267,7 @@ void furi_hal_subghz_dump_state() {
printf( printf(
"[furi_hal_subghz] cc1101 chip %d, version %d\r\n", "[furi_hal_subghz] cc1101 chip %d, version %d\r\n",
cc1101_get_partnumber(device), cc1101_get_partnumber(device),
cc1101_get_version(device) cc1101_get_version(device));
);
furi_hal_spi_device_return(device); furi_hal_spi_device_return(device);
} }
@ -266,10 +275,10 @@ void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
if(preset == FuriHalSubGhzPresetOok650Async) { if(preset == FuriHalSubGhzPresetOok650Async) {
furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_650khz_async_regs); furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_650khz_async_regs);
furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable); furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable);
} else if(preset == FuriHalSubGhzPresetOok270Async){ } else if(preset == FuriHalSubGhzPresetOok270Async) {
furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_270khz_async_regs); furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_270khz_async_regs);
furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable); furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable);
} else if(preset == FuriHalSubGhzPreset2FSKAsync){ } else if(preset == FuriHalSubGhzPreset2FSKAsync) {
furi_hal_subghz_load_registers(furi_hal_subghz_preset_2fsk_async_regs); furi_hal_subghz_load_registers(furi_hal_subghz_preset_2fsk_async_regs);
furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable); furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable);
}else { }else {
@ -289,7 +298,7 @@ void furi_hal_subghz_load_registers(const uint8_t data[][2]) {
const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
cc1101_reset(device); cc1101_reset(device);
uint32_t i = 0; uint32_t i = 0;
while (data[i][0]) { while(data[i][0]) {
cc1101_write_reg(device, data[i][0], data[i][1]); cc1101_write_reg(device, data[i][0], data[i][1]);
i++; i++;
} }
@ -401,7 +410,7 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
while(true) { while(true) {
CC1101Status status = cc1101_get_status(device); CC1101Status status = cc1101_get_status(device);
if (status.STATE == CC1101StateIDLE) break; if(status.STATE == CC1101StateIDLE) break;
} }
furi_hal_spi_device_return(device); furi_hal_spi_device_return(device);
@ -411,16 +420,16 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
void furi_hal_subghz_set_path(FuriHalSubGhzPath path) { void furi_hal_subghz_set_path(FuriHalSubGhzPath path) {
const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
if (path == FuriHalSubGhzPath433) { if(path == FuriHalSubGhzPath433) {
hal_gpio_write(&gpio_rf_sw_0, 0); hal_gpio_write(&gpio_rf_sw_0, 0);
cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
} else if (path == FuriHalSubGhzPath315) { } else if(path == FuriHalSubGhzPath315) {
hal_gpio_write(&gpio_rf_sw_0, 1); hal_gpio_write(&gpio_rf_sw_0, 1);
cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW); cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW);
} else if (path == FuriHalSubGhzPath868) { } else if(path == FuriHalSubGhzPath868) {
hal_gpio_write(&gpio_rf_sw_0, 1); hal_gpio_write(&gpio_rf_sw_0, 1);
cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
} else if (path == FuriHalSubGhzPathIsolate) { } else if(path == FuriHalSubGhzPathIsolate) {
hal_gpio_write(&gpio_rf_sw_0, 0); hal_gpio_write(&gpio_rf_sw_0, 0);
cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW); cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW);
} else { } else {
@ -438,24 +447,25 @@ static void furi_hal_subghz_capture_ISR() {
if(LL_TIM_IsActiveFlag_CC1(TIM2)) { if(LL_TIM_IsActiveFlag_CC1(TIM2)) {
LL_TIM_ClearFlag_CC1(TIM2); LL_TIM_ClearFlag_CC1(TIM2);
furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2); furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2);
if (furi_hal_subghz_capture_callback) { if(furi_hal_subghz_capture_callback) {
furi_hal_subghz_capture_callback(true, furi_hal_subghz_capture_delta_duration, furi_hal_subghz_capture_callback(
(void*)furi_hal_subghz_capture_callback_context true,
); furi_hal_subghz_capture_delta_duration,
(void*)furi_hal_subghz_capture_callback_context);
} }
} }
// Channel 2 // Channel 2
if(LL_TIM_IsActiveFlag_CC2(TIM2)) { if(LL_TIM_IsActiveFlag_CC2(TIM2)) {
LL_TIM_ClearFlag_CC2(TIM2); LL_TIM_ClearFlag_CC2(TIM2);
if (furi_hal_subghz_capture_callback) { if(furi_hal_subghz_capture_callback) {
furi_hal_subghz_capture_callback(false, LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration, furi_hal_subghz_capture_callback(
(void*)furi_hal_subghz_capture_callback_context false,
); LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration,
(void*)furi_hal_subghz_capture_callback_context);
} }
} }
} }
void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* context) { void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* context) {
furi_assert(furi_hal_subghz_state == SubGhzStateIdle); furi_assert(furi_hal_subghz_state == SubGhzStateIdle);
furi_hal_subghz_state = SubGhzStateAsyncRx; furi_hal_subghz_state = SubGhzStateAsyncRx;
@ -463,12 +473,13 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void*
furi_hal_subghz_capture_callback = callback; furi_hal_subghz_capture_callback = callback;
furi_hal_subghz_capture_callback_context = context; furi_hal_subghz_capture_callback_context = context;
hal_gpio_init_ex(&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); hal_gpio_init_ex(
&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2);
// Timer: base // Timer: base
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
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 = 0x7FFFFFFE; TIM_InitStruct.Autoreload = 0x7FFFFFFE;
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
@ -498,7 +509,7 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void*
// ISR setup // ISR setup
furi_hal_interrupt_set_timer_isr(TIM2, furi_hal_subghz_capture_ISR); furi_hal_interrupt_set_timer_isr(TIM2, furi_hal_subghz_capture_ISR);
NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0)); NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
NVIC_EnableIRQ(TIM2_IRQn); NVIC_EnableIRQ(TIM2_IRQn);
// Interrupts and channels // Interrupts and channels
@ -508,7 +519,7 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void*
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2);
// Enable NVIC // Enable NVIC
NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0)); NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
NVIC_EnableIRQ(TIM2_IRQn); NVIC_EnableIRQ(TIM2_IRQn);
// Start timer // Start timer
@ -534,8 +545,8 @@ void furi_hal_subghz_stop_async_rx() {
} }
#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256) #define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256)
#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL/2) #define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL / 2)
#define API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME 333 #define API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME 333
typedef struct { typedef struct {
uint32_t* buffer; uint32_t* buffer;
@ -547,12 +558,13 @@ typedef struct {
static FuriHalSubGhzAsyncTx furi_hal_subghz_async_tx = {0}; static FuriHalSubGhzAsyncTx furi_hal_subghz_async_tx = {0};
static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) {
while (samples > 0) { while(samples > 0) {
bool is_odd = samples % 2; bool is_odd = samples % 2;
LevelDuration ld = furi_hal_subghz_async_tx.callback(furi_hal_subghz_async_tx.callback_context); LevelDuration ld =
if (level_duration_is_reset(ld)) { furi_hal_subghz_async_tx.callback(furi_hal_subghz_async_tx.callback_context);
if(level_duration_is_reset(ld)) {
// One more even sample required to end at low level // One more even sample required to end at low level
if (is_odd) { if(is_odd) {
*buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; *buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME;
buffer++; buffer++;
samples--; samples--;
@ -560,7 +572,7 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) {
break; break;
} else { } else {
// Inject guard time if level is incorrect // Inject guard time if level is incorrect
if (is_odd == level_duration_get_level(ld)) { if(is_odd == level_duration_get_level(ld)) {
*buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; *buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME;
buffer++; buffer++;
samples--; samples--;
@ -579,21 +591,24 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) {
static void furi_hal_subghz_async_tx_dma_isr() { static void furi_hal_subghz_async_tx_dma_isr() {
furi_assert(furi_hal_subghz_state == SubGhzStateAsyncTx); furi_assert(furi_hal_subghz_state == SubGhzStateAsyncTx);
if (LL_DMA_IsActiveFlag_HT1(DMA1)) { if(LL_DMA_IsActiveFlag_HT1(DMA1)) {
LL_DMA_ClearFlag_HT1(DMA1); LL_DMA_ClearFlag_HT1(DMA1);
furi_hal_subghz_async_tx_refill(furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF); furi_hal_subghz_async_tx_refill(
furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF);
} }
if (LL_DMA_IsActiveFlag_TC1(DMA1)) { if(LL_DMA_IsActiveFlag_TC1(DMA1)) {
LL_DMA_ClearFlag_TC1(DMA1); LL_DMA_ClearFlag_TC1(DMA1);
furi_hal_subghz_async_tx_refill(furi_hal_subghz_async_tx.buffer+API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF); furi_hal_subghz_async_tx_refill(
furi_hal_subghz_async_tx.buffer + API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF,
API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF);
} }
} }
static void furi_hal_subghz_async_tx_timer_isr() { static void furi_hal_subghz_async_tx_timer_isr() {
if(LL_TIM_IsActiveFlag_UPDATE(TIM2)) { if(LL_TIM_IsActiveFlag_UPDATE(TIM2)) {
LL_TIM_ClearFlag_UPDATE(TIM2); LL_TIM_ClearFlag_UPDATE(TIM2);
if (LL_TIM_GetAutoReload(TIM2) == 0) { if(LL_TIM_GetAutoReload(TIM2) == 0) {
if (furi_hal_subghz_state == SubGhzStateAsyncTx) { if(furi_hal_subghz_state == SubGhzStateAsyncTx) {
furi_hal_subghz_state = SubGhzStateAsyncTxLast; furi_hal_subghz_state = SubGhzStateAsyncTxLast;
} else { } else {
furi_hal_subghz_state = SubGhzStateAsyncTxEnd; furi_hal_subghz_state = SubGhzStateAsyncTxEnd;
@ -612,15 +627,18 @@ void furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
furi_hal_subghz_state = SubGhzStateAsyncTx; furi_hal_subghz_state = SubGhzStateAsyncTx;
furi_hal_subghz_async_tx.buffer = furi_alloc(API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); furi_hal_subghz_async_tx.buffer =
furi_hal_subghz_async_tx_refill(furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL); furi_alloc(API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t));
furi_hal_subghz_async_tx_refill(
furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL);
// Connect CC1101_GD0 to TIM2 as output // Connect CC1101_GD0 to TIM2 as output
hal_gpio_init_ex(&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullDown, GpioSpeedLow, GpioAltFn1TIM2); hal_gpio_init_ex(
&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullDown, GpioSpeedLow, GpioAltFn1TIM2);
// Configure DMA // Configure DMA
LL_DMA_InitTypeDef dma_config = {0}; LL_DMA_InitTypeDef dma_config = {0};
dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(TIM2->ARR); dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR);
dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_async_tx.buffer; dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_async_tx.buffer;
dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
dma_config.Mode = LL_DMA_MODE_CIRCULAR; dma_config.Mode = LL_DMA_MODE_CIRCULAR;
@ -632,7 +650,8 @@ void furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
dma_config.Priority = LL_DMA_MODE_NORMAL; dma_config.Priority = LL_DMA_MODE_NORMAL;
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config); LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config);
furi_hal_interrupt_set_dma_channel_isr(DMA1, LL_DMA_CHANNEL_1, furi_hal_subghz_async_tx_dma_isr); furi_hal_interrupt_set_dma_channel_isr(
DMA1, LL_DMA_CHANNEL_1, furi_hal_subghz_async_tx_dma_isr);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1); LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_1); LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
@ -640,7 +659,7 @@ void furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
// Configure TIM2 // Configure TIM2
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
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 = 1000; TIM_InitStruct.Autoreload = 1000;
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
@ -672,7 +691,7 @@ void furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
furi_hal_subghz_tx(); furi_hal_subghz_tx();
// Enable NVIC // Enable NVIC
NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0)); NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
NVIC_EnableIRQ(TIM2_IRQn); NVIC_EnableIRQ(TIM2_IRQn);
LL_TIM_SetCounter(TIM2, 0); LL_TIM_SetCounter(TIM2, 0);
@ -685,10 +704,9 @@ bool furi_hal_subghz_is_async_tx_complete() {
void furi_hal_subghz_stop_async_tx() { void furi_hal_subghz_stop_async_tx() {
furi_assert( furi_assert(
furi_hal_subghz_state == SubGhzStateAsyncTx furi_hal_subghz_state == SubGhzStateAsyncTx ||
|| furi_hal_subghz_state == SubGhzStateAsyncTxLast furi_hal_subghz_state == SubGhzStateAsyncTxLast ||
|| furi_hal_subghz_state == SubGhzStateAsyncTxEnd furi_hal_subghz_state == SubGhzStateAsyncTxEnd);
);
// Shutdown radio // Shutdown radio
furi_hal_subghz_idle(); furi_hal_subghz_idle();

View File

@ -15,166 +15,174 @@ static const uint8_t furi_hal_subghz_preset_ook_270khz_async_regs[][2] = {
// https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration
/* GPIO GD0 */ /* GPIO GD0 */
{ CC1101_IOCFG0, 0x0D }, // GD0 as async serial data output/input {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input
/* FIFO and internals */ /* FIFO and internals */
{ CC1101_FIFOTHR, 0x47 }, // The only important bit is ADC_RETENTION, FIFO Tx=33 Rx=32 {CC1101_FIFOTHR, 0x47}, // The only important bit is ADC_RETENTION, FIFO Tx=33 Rx=32
/* Packet engine */ /* Packet engine */
{ CC1101_PKTCTRL0, 0x32 }, // Async, continious, no whitening {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening
/* Frequency Synthesizer Control */ /* Frequency Synthesizer Control */
{ CC1101_FSCTRL1, 0x06 }, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz
// Modem Configuration // Modem Configuration
{ CC1101_MDMCFG0, 0x00 }, // Channel spacing is 25kHz {CC1101_MDMCFG0, 0x00}, // Channel spacing is 25kHz
{ CC1101_MDMCFG1, 0x00 }, // Channel spacing is 25kHz {CC1101_MDMCFG1, 0x00}, // Channel spacing is 25kHz
{ CC1101_MDMCFG2, 0x30 }, // Format ASK/OOK, No preamble/sync {CC1101_MDMCFG2, 0x30}, // Format ASK/OOK, No preamble/sync
{ CC1101_MDMCFG3, 0x32 }, // Data rate is 3.79372 kBaud {CC1101_MDMCFG3, 0x32}, // Data rate is 3.79372 kBaud
{ CC1101_MDMCFG4, 0x67 }, // Rx BW filter is 270.833333kHz {CC1101_MDMCFG4, 0x67}, // Rx BW filter is 270.833333kHz
/* Main Radio Control State Machine */ /* Main Radio Control State Machine */
{ CC1101_MCSM0, 0x18 }, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us)
/* Frequency Offset Compensation Configuration */ /* Frequency Offset Compensation Configuration */
{ CC1101_FOCCFG, 0x18 }, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off {CC1101_FOCCFG,
0x18}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off
/* Automatic Gain Control */ /* Automatic Gain Control */
{ CC1101_AGCTRL0, 0x40 }, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary {CC1101_AGCTRL0,
{ CC1101_AGCTRL1, 0x00 }, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET 0x40}, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary
{ CC1101_AGCTRL2, 0x03 }, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB {CC1101_AGCTRL1,
0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET
{CC1101_AGCTRL2, 0x03}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB
/* Wake on radio and timeouts control */ /* Wake on radio and timeouts control */
{ CC1101_WORCTRL, 0xFB }, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours
/* Frontend configuration */ /* Frontend configuration */
{ CC1101_FREND0, 0x11 }, // Adjusts current TX LO buffer + high is PATABLE[1] {CC1101_FREND0, 0x11}, // Adjusts current TX LO buffer + high is PATABLE[1]
{ CC1101_FREND1, 0xB6 }, // {CC1101_FREND1, 0xB6}, //
/* Frequency Synthesizer Calibration, valid for 433.92 */ /* Frequency Synthesizer Calibration, valid for 433.92 */
{ CC1101_FSCAL3, 0xE9 }, {CC1101_FSCAL3, 0xE9},
{ CC1101_FSCAL2, 0x2A }, {CC1101_FSCAL2, 0x2A},
{ CC1101_FSCAL1, 0x00 }, {CC1101_FSCAL1, 0x00},
{ CC1101_FSCAL0, 0x1F }, {CC1101_FSCAL0, 0x1F},
/* Magic f4ckery */ /* Magic f4ckery */
{ CC1101_TEST2, 0x81 }, // FIFOTHR ADC_RETENTION=1 matched value {CC1101_TEST2, 0x81}, // FIFOTHR ADC_RETENTION=1 matched value
{ CC1101_TEST1, 0x35 }, // FIFOTHR ADC_RETENTION=1 matched value {CC1101_TEST1, 0x35}, // FIFOTHR ADC_RETENTION=1 matched value
{ CC1101_TEST0, 0x09 }, // VCO selection calibration stage is disabled {CC1101_TEST0, 0x09}, // VCO selection calibration stage is disabled
/* End */ /* End */
{ 0, 0 }, {0, 0},
}; };
static const uint8_t furi_hal_subghz_preset_ook_650khz_async_regs[][2] = { static const uint8_t furi_hal_subghz_preset_ook_650khz_async_regs[][2] = {
// https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration
/* GPIO GD0 */ /* GPIO GD0 */
{ CC1101_IOCFG0, 0x0D }, // GD0 as async serial data output/input {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input
/* FIFO and internals */ /* FIFO and internals */
{ CC1101_FIFOTHR, 0x07 }, // The only important bit is ADC_RETENTION {CC1101_FIFOTHR, 0x07}, // The only important bit is ADC_RETENTION
/* Packet engine */ /* Packet engine */
{ CC1101_PKTCTRL0, 0x32 }, // Async, continious, no whitening {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening
/* Frequency Synthesizer Control */ /* Frequency Synthesizer Control */
{ CC1101_FSCTRL1, 0x06 }, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz
// Modem Configuration // Modem Configuration
{ CC1101_MDMCFG0, 0x00 }, // Channel spacing is 25kHz {CC1101_MDMCFG0, 0x00}, // Channel spacing is 25kHz
{ CC1101_MDMCFG1, 0x00 }, // Channel spacing is 25kHz {CC1101_MDMCFG1, 0x00}, // Channel spacing is 25kHz
{ CC1101_MDMCFG2, 0x30 }, // Format ASK/OOK, No preamble/sync {CC1101_MDMCFG2, 0x30}, // Format ASK/OOK, No preamble/sync
{ CC1101_MDMCFG3, 0x32 }, // Data rate is 3.79372 kBaud {CC1101_MDMCFG3, 0x32}, // Data rate is 3.79372 kBaud
{ CC1101_MDMCFG4, 0x17 }, // Rx BW filter is 650.000kHz {CC1101_MDMCFG4, 0x17}, // Rx BW filter is 650.000kHz
/* Main Radio Control State Machine */ /* Main Radio Control State Machine */
{ CC1101_MCSM0, 0x18 }, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us)
/* Frequency Offset Compensation Configuration */ /* Frequency Offset Compensation Configuration */
{ CC1101_FOCCFG, 0x18 }, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off {CC1101_FOCCFG,
0x18}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off
/* Automatic Gain Control */ /* Automatic Gain Control */
{ CC1101_AGCTRL0, 0x40 }, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary {CC1101_AGCTRL0,
{ CC1101_AGCTRL1, 0x00 }, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET 0x40}, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary
{ CC1101_AGCTRL2, 0x03 }, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB {CC1101_AGCTRL1,
0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET
{CC1101_AGCTRL2, 0x03}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB
/* Wake on radio and timeouts control */ /* Wake on radio and timeouts control */
{ CC1101_WORCTRL, 0xFB }, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours
/* Frontend configuration */ /* Frontend configuration */
{ CC1101_FREND0, 0x11 }, // Adjusts current TX LO buffer + high is PATABLE[1] {CC1101_FREND0, 0x11}, // Adjusts current TX LO buffer + high is PATABLE[1]
{ CC1101_FREND1, 0xB6 }, // {CC1101_FREND1, 0xB6}, //
/* Frequency Synthesizer Calibration, valid for 433.92 */ /* Frequency Synthesizer Calibration, valid for 433.92 */
{ CC1101_FSCAL3, 0xE9 }, {CC1101_FSCAL3, 0xE9},
{ CC1101_FSCAL2, 0x2A }, {CC1101_FSCAL2, 0x2A},
{ CC1101_FSCAL1, 0x00 }, {CC1101_FSCAL1, 0x00},
{ CC1101_FSCAL0, 0x1F }, {CC1101_FSCAL0, 0x1F},
/* Magic f4ckery */ /* Magic f4ckery */
{ CC1101_TEST2, 0x88 }, {CC1101_TEST2, 0x88},
{ CC1101_TEST1, 0x31 }, {CC1101_TEST1, 0x31},
{ CC1101_TEST0, 0x09 }, // VCO selection calibration stage is disabled {CC1101_TEST0, 0x09}, // VCO selection calibration stage is disabled
/* End */ /* End */
{ 0, 0 }, {0, 0},
}; };
static const uint8_t furi_hal_subghz_preset_2fsk_async_regs[][2] = { static const uint8_t furi_hal_subghz_preset_2fsk_async_regs[][2] = {
// https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration
/* GPIO GD0 */ /* GPIO GD0 */
{ CC1101_IOCFG0, 0x0D }, // GD0 as async serial data output/input {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input
/* FIFO and internals */ /* FIFO and internals */
{ CC1101_FIFOTHR, 0x47 }, // The only important bit is ADC_RETENTION {CC1101_FIFOTHR, 0x47}, // The only important bit is ADC_RETENTION
/* Packet engine */ /* Packet engine */
{ CC1101_PKTCTRL0, 0x32 }, // Async, continious, no whitening {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening
/* Frequency Synthesizer Control */ /* Frequency Synthesizer Control */
{ CC1101_FSCTRL1, 0x06 }, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz
// Modem Configuration // Modem Configuration
{ CC1101_MDMCFG0, 0xF8 }, {CC1101_MDMCFG0, 0x00},
{ CC1101_MDMCFG1, 0x00 }, // No preamble/sync {CC1101_MDMCFG1, 0x02},
{ CC1101_MDMCFG2, 0x80 }, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized) {CC1101_MDMCFG2, 0x04}, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized)
{ CC1101_MDMCFG3, 0x83 }, // Data rate is 9.59587 kBaud {CC1101_MDMCFG3, 0x8B}, // Data rate is 19.5885 kBaud
{ CC1101_MDMCFG4, 0x88 }, // Rx BW filter is 203.125000kHz {CC1101_MDMCFG4, 0x69}, // Rx BW filter is 270.833333 kHz
{ CC1101_DEVIATN, 0x14}, //Deviation 4.760742 khz {CC1101_DEVIATN, 0x47}, //Deviation 47.607422 khz
/* Main Radio Control State Machine */ /* Main Radio Control State Machine */
{ CC1101_MCSM0, 0x18 }, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us)
/* Frequency Offset Compensation Configuration */ /* Frequency Offset Compensation Configuration */
{ CC1101_FOCCFG, 0x18 }, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off {CC1101_FOCCFG,
0x16}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off
/* Automatic Gain Control */ /* Automatic Gain Control */
{ CC1101_AGCTRL0, 0x40 }, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary {CC1101_AGCTRL0,
{ CC1101_AGCTRL1, 0x00 }, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET 0x40}, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary
{ CC1101_AGCTRL2, 0x03 }, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB {CC1101_AGCTRL1,
0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET
{CC1101_AGCTRL2, 0x03}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB
/* Wake on radio and timeouts control */ /* Wake on radio and timeouts control */
{ CC1101_WORCTRL, 0xFB }, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours
/* Frontend configuration */ /* Frontend configuration */
{ CC1101_FREND0, 0x10 }, // Adjusts current TX LO buffer {CC1101_FREND0, 0x10}, // Adjusts current TX LO buffer
{ CC1101_FREND1, 0xB6 }, // {CC1101_FREND1, 0xB6}, //
/* Frequency Synthesizer Calibration, valid for 433.92 */ /* Frequency Synthesizer Calibration, valid for 433.92 */
{ CC1101_FSCAL3, 0xE9 }, {CC1101_FSCAL3, 0xE9},
{ CC1101_FSCAL2, 0x2A }, {CC1101_FSCAL2, 0x2A},
{ CC1101_FSCAL1, 0x00 }, {CC1101_FSCAL1, 0x00},
{ CC1101_FSCAL0, 0x1F }, {CC1101_FSCAL0, 0x1F},
/* Magic f4ckery */ /* Magic f4ckery */
{ CC1101_TEST2, 0x81 }, // FIFOTHR ADC_RETENTION=1 matched value {CC1101_TEST2, 0x81}, // FIFOTHR ADC_RETENTION=1 matched value
{ CC1101_TEST1, 0x35 }, // FIFOTHR ADC_RETENTION=1 matched value {CC1101_TEST1, 0x35}, // FIFOTHR ADC_RETENTION=1 matched value
{ CC1101_TEST0, 0x09 }, // VCO selection calibration stage is disabled {CC1101_TEST0, 0x09}, // VCO selection calibration stage is disabled
/* End */ /* End */
{ 0, 0 }, {0, 0},
}; };
static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = { static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = {
0x00, 0x00,
@ -184,8 +192,7 @@ static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = {
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00 0x00};
};
static const uint8_t furi_hal_subghz_preset_2fsk_async_patable[8] = { static const uint8_t furi_hal_subghz_preset_2fsk_async_patable[8] = {
0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
0x00, 0x00,
@ -194,8 +201,7 @@ static const uint8_t furi_hal_subghz_preset_2fsk_async_patable[8] = {
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00 0x00};
};
void furi_hal_subghz_init() { void furi_hal_subghz_init() {
furi_assert(furi_hal_subghz_state == SubGhzStateInit); furi_assert(furi_hal_subghz_state == SubGhzStateInit);
@ -217,11 +223,13 @@ void furi_hal_subghz_init() {
// GD0 low // GD0 low
cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW); cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW);
while(hal_gpio_read(&gpio_cc1101_g0) != false); while(hal_gpio_read(&gpio_cc1101_g0) != false)
;
// GD0 high // GD0 high
cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV);
while(hal_gpio_read(&gpio_cc1101_g0) != true); while(hal_gpio_read(&gpio_cc1101_g0) != true)
;
// Reset GD0 to floating state // Reset GD0 to floating state
cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance); cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance);
@ -257,8 +265,7 @@ void furi_hal_subghz_dump_state() {
printf( printf(
"[furi_hal_subghz] cc1101 chip %d, version %d\r\n", "[furi_hal_subghz] cc1101 chip %d, version %d\r\n",
cc1101_get_partnumber(device), cc1101_get_partnumber(device),
cc1101_get_version(device) cc1101_get_version(device));
);
furi_hal_spi_device_return(device); furi_hal_spi_device_return(device);
} }
@ -266,10 +273,10 @@ void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
if(preset == FuriHalSubGhzPresetOok650Async) { if(preset == FuriHalSubGhzPresetOok650Async) {
furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_650khz_async_regs); furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_650khz_async_regs);
furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable); furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable);
} else if(preset == FuriHalSubGhzPresetOok270Async){ } else if(preset == FuriHalSubGhzPresetOok270Async) {
furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_270khz_async_regs); furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_270khz_async_regs);
furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable); furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable);
} else if(preset == FuriHalSubGhzPreset2FSKAsync){ } else if(preset == FuriHalSubGhzPreset2FSKAsync) {
furi_hal_subghz_load_registers(furi_hal_subghz_preset_2fsk_async_regs); furi_hal_subghz_load_registers(furi_hal_subghz_preset_2fsk_async_regs);
furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable); furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable);
}else { }else {
@ -289,7 +296,7 @@ void furi_hal_subghz_load_registers(const uint8_t data[][2]) {
const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
cc1101_reset(device); cc1101_reset(device);
uint32_t i = 0; uint32_t i = 0;
while (data[i][0]) { while(data[i][0]) {
cc1101_write_reg(device, data[i][0], data[i][1]); cc1101_write_reg(device, data[i][0], data[i][1]);
i++; i++;
} }
@ -401,7 +408,7 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
while(true) { while(true) {
CC1101Status status = cc1101_get_status(device); CC1101Status status = cc1101_get_status(device);
if (status.STATE == CC1101StateIDLE) break; if(status.STATE == CC1101StateIDLE) break;
} }
furi_hal_spi_device_return(device); furi_hal_spi_device_return(device);
@ -411,16 +418,16 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
void furi_hal_subghz_set_path(FuriHalSubGhzPath path) { void furi_hal_subghz_set_path(FuriHalSubGhzPath path) {
const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz); const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
if (path == FuriHalSubGhzPath433) { if(path == FuriHalSubGhzPath433) {
hal_gpio_write(&gpio_rf_sw_0, 0); hal_gpio_write(&gpio_rf_sw_0, 0);
cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
} else if (path == FuriHalSubGhzPath315) { } else if(path == FuriHalSubGhzPath315) {
hal_gpio_write(&gpio_rf_sw_0, 1); hal_gpio_write(&gpio_rf_sw_0, 1);
cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW); cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW);
} else if (path == FuriHalSubGhzPath868) { } else if(path == FuriHalSubGhzPath868) {
hal_gpio_write(&gpio_rf_sw_0, 1); hal_gpio_write(&gpio_rf_sw_0, 1);
cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
} else if (path == FuriHalSubGhzPathIsolate) { } else if(path == FuriHalSubGhzPathIsolate) {
hal_gpio_write(&gpio_rf_sw_0, 0); hal_gpio_write(&gpio_rf_sw_0, 0);
cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW); cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW);
} else { } else {
@ -438,24 +445,25 @@ static void furi_hal_subghz_capture_ISR() {
if(LL_TIM_IsActiveFlag_CC1(TIM2)) { if(LL_TIM_IsActiveFlag_CC1(TIM2)) {
LL_TIM_ClearFlag_CC1(TIM2); LL_TIM_ClearFlag_CC1(TIM2);
furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2); furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2);
if (furi_hal_subghz_capture_callback) { if(furi_hal_subghz_capture_callback) {
furi_hal_subghz_capture_callback(true, furi_hal_subghz_capture_delta_duration, furi_hal_subghz_capture_callback(
(void*)furi_hal_subghz_capture_callback_context true,
); furi_hal_subghz_capture_delta_duration,
(void*)furi_hal_subghz_capture_callback_context);
} }
} }
// Channel 2 // Channel 2
if(LL_TIM_IsActiveFlag_CC2(TIM2)) { if(LL_TIM_IsActiveFlag_CC2(TIM2)) {
LL_TIM_ClearFlag_CC2(TIM2); LL_TIM_ClearFlag_CC2(TIM2);
if (furi_hal_subghz_capture_callback) { if(furi_hal_subghz_capture_callback) {
furi_hal_subghz_capture_callback(false, LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration, furi_hal_subghz_capture_callback(
(void*)furi_hal_subghz_capture_callback_context false,
); LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration,
(void*)furi_hal_subghz_capture_callback_context);
} }
} }
} }
void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* context) { void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* context) {
furi_assert(furi_hal_subghz_state == SubGhzStateIdle); furi_assert(furi_hal_subghz_state == SubGhzStateIdle);
furi_hal_subghz_state = SubGhzStateAsyncRx; furi_hal_subghz_state = SubGhzStateAsyncRx;
@ -463,12 +471,13 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void*
furi_hal_subghz_capture_callback = callback; furi_hal_subghz_capture_callback = callback;
furi_hal_subghz_capture_callback_context = context; furi_hal_subghz_capture_callback_context = context;
hal_gpio_init_ex(&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); hal_gpio_init_ex(
&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2);
// Timer: base // Timer: base
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
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 = 0x7FFFFFFE; TIM_InitStruct.Autoreload = 0x7FFFFFFE;
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
@ -498,7 +507,7 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void*
// ISR setup // ISR setup
furi_hal_interrupt_set_timer_isr(TIM2, furi_hal_subghz_capture_ISR); furi_hal_interrupt_set_timer_isr(TIM2, furi_hal_subghz_capture_ISR);
NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0)); NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
NVIC_EnableIRQ(TIM2_IRQn); NVIC_EnableIRQ(TIM2_IRQn);
// Interrupts and channels // Interrupts and channels
@ -508,7 +517,7 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void*
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2);
// Enable NVIC // Enable NVIC
NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0)); NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
NVIC_EnableIRQ(TIM2_IRQn); NVIC_EnableIRQ(TIM2_IRQn);
// Start timer // Start timer
@ -534,8 +543,8 @@ void furi_hal_subghz_stop_async_rx() {
} }
#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256) #define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256)
#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL/2) #define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL / 2)
#define API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME 333 #define API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME 333
typedef struct { typedef struct {
uint32_t* buffer; uint32_t* buffer;
@ -547,12 +556,13 @@ typedef struct {
static FuriHalSubGhzAsyncTx furi_hal_subghz_async_tx = {0}; static FuriHalSubGhzAsyncTx furi_hal_subghz_async_tx = {0};
static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) {
while (samples > 0) { while(samples > 0) {
bool is_odd = samples % 2; bool is_odd = samples % 2;
LevelDuration ld = furi_hal_subghz_async_tx.callback(furi_hal_subghz_async_tx.callback_context); LevelDuration ld =
if (level_duration_is_reset(ld)) { furi_hal_subghz_async_tx.callback(furi_hal_subghz_async_tx.callback_context);
if(level_duration_is_reset(ld)) {
// One more even sample required to end at low level // One more even sample required to end at low level
if (is_odd) { if(is_odd) {
*buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; *buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME;
buffer++; buffer++;
samples--; samples--;
@ -560,7 +570,7 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) {
break; break;
} else { } else {
// Inject guard time if level is incorrect // Inject guard time if level is incorrect
if (is_odd == level_duration_get_level(ld)) { if(is_odd == level_duration_get_level(ld)) {
*buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME; *buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME;
buffer++; buffer++;
samples--; samples--;
@ -579,21 +589,24 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) {
static void furi_hal_subghz_async_tx_dma_isr() { static void furi_hal_subghz_async_tx_dma_isr() {
furi_assert(furi_hal_subghz_state == SubGhzStateAsyncTx); furi_assert(furi_hal_subghz_state == SubGhzStateAsyncTx);
if (LL_DMA_IsActiveFlag_HT1(DMA1)) { if(LL_DMA_IsActiveFlag_HT1(DMA1)) {
LL_DMA_ClearFlag_HT1(DMA1); LL_DMA_ClearFlag_HT1(DMA1);
furi_hal_subghz_async_tx_refill(furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF); furi_hal_subghz_async_tx_refill(
furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF);
} }
if (LL_DMA_IsActiveFlag_TC1(DMA1)) { if(LL_DMA_IsActiveFlag_TC1(DMA1)) {
LL_DMA_ClearFlag_TC1(DMA1); LL_DMA_ClearFlag_TC1(DMA1);
furi_hal_subghz_async_tx_refill(furi_hal_subghz_async_tx.buffer+API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF); furi_hal_subghz_async_tx_refill(
furi_hal_subghz_async_tx.buffer + API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF,
API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF);
} }
} }
static void furi_hal_subghz_async_tx_timer_isr() { static void furi_hal_subghz_async_tx_timer_isr() {
if(LL_TIM_IsActiveFlag_UPDATE(TIM2)) { if(LL_TIM_IsActiveFlag_UPDATE(TIM2)) {
LL_TIM_ClearFlag_UPDATE(TIM2); LL_TIM_ClearFlag_UPDATE(TIM2);
if (LL_TIM_GetAutoReload(TIM2) == 0) { if(LL_TIM_GetAutoReload(TIM2) == 0) {
if (furi_hal_subghz_state == SubGhzStateAsyncTx) { if(furi_hal_subghz_state == SubGhzStateAsyncTx) {
furi_hal_subghz_state = SubGhzStateAsyncTxLast; furi_hal_subghz_state = SubGhzStateAsyncTxLast;
} else { } else {
furi_hal_subghz_state = SubGhzStateAsyncTxEnd; furi_hal_subghz_state = SubGhzStateAsyncTxEnd;
@ -612,15 +625,18 @@ void furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
furi_hal_subghz_state = SubGhzStateAsyncTx; furi_hal_subghz_state = SubGhzStateAsyncTx;
furi_hal_subghz_async_tx.buffer = furi_alloc(API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); furi_hal_subghz_async_tx.buffer =
furi_hal_subghz_async_tx_refill(furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL); furi_alloc(API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t));
furi_hal_subghz_async_tx_refill(
furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL);
// Connect CC1101_GD0 to TIM2 as output // Connect CC1101_GD0 to TIM2 as output
hal_gpio_init_ex(&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullDown, GpioSpeedLow, GpioAltFn1TIM2); hal_gpio_init_ex(
&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullDown, GpioSpeedLow, GpioAltFn1TIM2);
// Configure DMA // Configure DMA
LL_DMA_InitTypeDef dma_config = {0}; LL_DMA_InitTypeDef dma_config = {0};
dma_config.PeriphOrM2MSrcAddress = (uint32_t)&(TIM2->ARR); dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR);
dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_async_tx.buffer; dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_async_tx.buffer;
dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
dma_config.Mode = LL_DMA_MODE_CIRCULAR; dma_config.Mode = LL_DMA_MODE_CIRCULAR;
@ -632,7 +648,8 @@ void furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
dma_config.Priority = LL_DMA_MODE_NORMAL; dma_config.Priority = LL_DMA_MODE_NORMAL;
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config); LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config);
furi_hal_interrupt_set_dma_channel_isr(DMA1, LL_DMA_CHANNEL_1, furi_hal_subghz_async_tx_dma_isr); furi_hal_interrupt_set_dma_channel_isr(
DMA1, LL_DMA_CHANNEL_1, furi_hal_subghz_async_tx_dma_isr);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1); LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_1); LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
@ -640,7 +657,7 @@ void furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
// Configure TIM2 // Configure TIM2
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
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 = 1000; TIM_InitStruct.Autoreload = 1000;
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
@ -672,7 +689,7 @@ void furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
furi_hal_subghz_tx(); furi_hal_subghz_tx();
// Enable NVIC // Enable NVIC
NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0)); NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
NVIC_EnableIRQ(TIM2_IRQn); NVIC_EnableIRQ(TIM2_IRQn);
LL_TIM_SetCounter(TIM2, 0); LL_TIM_SetCounter(TIM2, 0);
@ -685,10 +702,9 @@ bool furi_hal_subghz_is_async_tx_complete() {
void furi_hal_subghz_stop_async_tx() { void furi_hal_subghz_stop_async_tx() {
furi_assert( furi_assert(
furi_hal_subghz_state == SubGhzStateAsyncTx furi_hal_subghz_state == SubGhzStateAsyncTx ||
|| furi_hal_subghz_state == SubGhzStateAsyncTxLast furi_hal_subghz_state == SubGhzStateAsyncTxLast ||
|| furi_hal_subghz_state == SubGhzStateAsyncTxEnd furi_hal_subghz_state == SubGhzStateAsyncTxEnd);
);
// Shutdown radio // Shutdown radio
furi_hal_subghz_idle(); furi_hal_subghz_idle();

View File

@ -1,72 +0,0 @@
#pragma once
#include "subghz_protocol_common.h"
typedef void (*SubGhzProtocolTextCallback)(string_t text, void* context);
typedef void (*SubGhzProtocolCommonCallbackDump)(SubGhzProtocolCommon *parser, void* context);
typedef struct SubGhzProtocol SubGhzProtocol;
/** Allocate SubGhzProtocol
*
* @return SubGhzProtocol*
*/
SubGhzProtocol* subghz_protocol_alloc();
/** Free SubGhzProtocol
*
* @param instance
*/
void subghz_protocol_free(SubGhzProtocol* instance);
/** Get protocol by name
*
* @param instance - SubGhzProtocol instance
* @param name - name protocol
* @param SubGhzProtocolCommon
*/
SubGhzProtocolCommon* subghz_protocol_get_by_name(SubGhzProtocol* instance, const char* name);
/** Outputting data text from all parsers
*
* @param instance - SubGhzProtocol instance
* @param callback - SubGhzProtocolTextCallback callback
* @param 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
*
* @param instance - SubGhzProtocol instance
* @param file_name - "path/file_name"
*/
void subghz_protocol_load_nice_flor_s_file(SubGhzProtocol* instance, const char* file_name);
/** File upload manufacture keys
*
* @param instance - SubGhzProtocol instance
* @param file_name - "path/file_name"
*/
void subghz_protocol_load_keeloq_file(SubGhzProtocol* instance, const char* file_name);
/** Restarting all parsers
*
* @param instance - SubGhzProtocol instance
*/
void subghz_protocol_reset(SubGhzProtocol* instance);
/** Loading data into all parsers
*
* @param instance - SubGhzProtocol instance
* @param level - true is high, false if low
* @param duration - level duration in microseconds
*/
void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t duration);

View File

@ -11,6 +11,13 @@ struct SubGhzProtocolCame {
SubGhzProtocolCommon common; SubGhzProtocolCommon common;
}; };
typedef enum {
CameDecoderStepReset = 0,
CameDecoderStepFoundStartBit,
CameDecoderStepSaveDuration,
CameDecoderStepCheckDuration,
} CameDecoderStep;
SubGhzProtocolCame* subghz_protocol_came_alloc() { SubGhzProtocolCame* subghz_protocol_came_alloc() {
SubGhzProtocolCame* instance = furi_alloc(sizeof(SubGhzProtocolCame)); SubGhzProtocolCame* instance = furi_alloc(sizeof(SubGhzProtocolCame));
@ -19,11 +26,11 @@ SubGhzProtocolCame* subghz_protocol_came_alloc() {
instance->common.te_short = 320; instance->common.te_short = 320;
instance->common.te_long = 640; instance->common.te_long = 640;
instance->common.te_delta = 150; instance->common.te_delta = 150;
instance->common.type_protocol = TYPE_PROTOCOL_STATIC; instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_came_to_str; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_came_to_str;
instance->common.to_save_string = instance->common.to_save_string =
(SubGhzProtocolCommonGetStrSave)subghz_protocol_came_to_save_str; (SubGhzProtocolCommonGetStrSave)subghz_protocol_came_to_save_str;
instance->common.to_load_protocol_from_file= instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_protocol_came_to_load_protocol_from_file; (SubGhzProtocolCommonLoadFromFile)subghz_protocol_came_to_load_protocol_from_file;
instance->common.to_load_protocol = instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_came_to_load_protocol; (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_came_to_load_protocol;
@ -38,97 +45,106 @@ void subghz_protocol_came_free(SubGhzProtocolCame* instance) {
free(instance); free(instance);
} }
bool subghz_protocol_came_send_key(SubGhzProtocolCame* instance, SubGhzProtocolCommonEncoder* encoder){ bool subghz_protocol_came_send_key(
SubGhzProtocolCame* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance); furi_assert(instance);
furi_assert(encoder); furi_assert(encoder);
size_t index = 0; size_t index = 0;
encoder->size_upload =(instance->common.code_last_count_bit * 2) + 2; encoder->size_upload = (instance->common.code_last_count_bit * 2) + 2;
if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false; if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
//Send header //Send header
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short * 36); encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short * 36);
//Send start bit //Send start bit
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short); encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
//Send key data //Send key data
for (uint8_t i = instance->common.code_last_count_bit; i > 0; i--) { for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
if(bit_read(instance->common.code_last_found, i - 1)){ if(bit_read(instance->common.code_last_found, i - 1)) {
//send bit 1 //send bit 1
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_long); encoder->upload[index++] =
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short); level_duration_make(false, (uint32_t)instance->common.te_long);
}else{ encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_short);
} else {
//send bit 0 //send bit 0
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short); encoder->upload[index++] =
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_long); level_duration_make(false, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_long);
} }
} }
return true; return true;
} }
void subghz_protocol_came_reset(SubGhzProtocolCame* instance) { void subghz_protocol_came_reset(SubGhzProtocolCame* instance) {
instance->common.parser_step = 0; instance->common.parser_step = CameDecoderStepReset;
} }
void subghz_protocol_came_parse(SubGhzProtocolCame* instance, bool level, uint32_t duration) { 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 CameDecoderStepReset:
if ((!level) if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 51) <
&& (DURATION_DIFF(duration, instance->common.te_short * 51)< instance->common.te_delta * 51)) { //Need protocol 36 te_short instance->common.te_delta * 51)) { //Need protocol 36 te_short
//Found header CAME //Found header CAME
instance->common.parser_step = 1; instance->common.parser_step = CameDecoderStepFoundStartBit;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = CameDecoderStepReset;
} }
break; break;
case 1: case CameDecoderStepFoundStartBit:
if (!level) { if(!level) {
break; break;
} else if (DURATION_DIFF(duration, instance->common.te_short)< instance->common.te_delta) { } else if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
//Found start bit CAME //Found start bit CAME
instance->common.parser_step = 2; instance->common.parser_step = CameDecoderStepSaveDuration;
instance->common.code_found = 0; instance->common.code_found = 0;
instance->common.code_count_bit = 0; instance->common.code_count_bit = 0;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = CameDecoderStepReset;
} }
break; break;
case 2: case CameDecoderStepSaveDuration:
if (!level) { //save interval if(!level) { //save interval
if (duration >= (instance->common.te_short * 4)) { if(duration >= (instance->common.te_short * 4)) {
instance->common.parser_step = 1; instance->common.parser_step = CameDecoderStepFoundStartBit;
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.serial = 0x0; instance->common.serial = 0x0;
instance->common.btn = 0x0; instance->common.btn = 0x0;
instance->common.code_last_found = instance->common.code_found; instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit; instance->common.code_last_count_bit = instance->common.code_count_bit;
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 = duration; instance->common.te_last = duration;
instance->common.parser_step = 3; instance->common.parser_step = CameDecoderStepCheckDuration;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = CameDecoderStepReset;
} }
break; break;
case 3: case CameDecoderStepCheckDuration:
if (level) { if(level) {
if ((DURATION_DIFF(instance->common.te_last,instance->common.te_short) < instance->common.te_delta) if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
&& (DURATION_DIFF(duration, instance->common.te_long)< instance->common.te_delta)) { 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 = CameDecoderStepSaveDuration;
} else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_long)< instance->common.te_delta) } else if(
&& (DURATION_DIFF(duration, instance->common.te_short)< instance->common.te_delta)) { (DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < 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 = CameDecoderStepSaveDuration;
} else } else
instance->common.parser_step = 0; instance->common.parser_step = CameDecoderStepReset;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = CameDecoderStepReset;
} }
break; break;
} }
@ -150,8 +166,7 @@ void subghz_protocol_came_to_str(SubGhzProtocolCame* instance, string_t output)
instance->common.name, instance->common.name,
instance->common.code_last_count_bit, instance->common.code_last_count_bit,
code_found_lo, code_found_lo,
code_found_reverse_lo code_found_reverse_lo);
);
} }
void subghz_protocol_came_to_save_str(SubGhzProtocolCame* instance, string_t output) { void subghz_protocol_came_to_save_str(SubGhzProtocolCame* instance, string_t output) {
@ -165,7 +180,9 @@ void subghz_protocol_came_to_save_str(SubGhzProtocolCame* instance, string_t out
(uint32_t)(instance->common.code_last_found & 0x00000000ffffffff)); (uint32_t)(instance->common.code_last_found & 0x00000000ffffffff));
} }
bool subghz_protocol_came_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolCame* instance){ bool subghz_protocol_came_to_load_protocol_from_file(
FileWorker* file_worker,
SubGhzProtocolCame* instance) {
bool loaded = false; bool loaded = false;
string_t temp_str; string_t temp_str;
string_init(temp_str); string_init(temp_str);
@ -202,9 +219,7 @@ bool subghz_protocol_came_to_load_protocol_from_file(FileWorker* file_worker, Su
return loaded; return loaded;
} }
void subghz_decoder_came_to_load_protocol( void subghz_decoder_came_to_load_protocol(SubGhzProtocolCame* instance, void* context) {
SubGhzProtocolCame* instance,
void* context) {
furi_assert(context); furi_assert(context);
furi_assert(instance); furi_assert(instance);
SubGhzProtocolCommonLoad* data = context; SubGhzProtocolCommonLoad* data = context;

View File

@ -19,12 +19,11 @@
#define SUBGHZ_APP_EXTENSION ".sub" #define SUBGHZ_APP_EXTENSION ".sub"
#define SUBGHZ_ENCODER_UPLOAD_MAX_SIZE 512 #define SUBGHZ_ENCODER_UPLOAD_MAX_SIZE 512
enum { typedef enum {
TYPE_PROTOCOL_UNKNOWN, SubGhzProtocolCommonTypeUnknown,
TYPE_PROTOCOL_STATIC, SubGhzProtocolCommonTypeStatic,
TYPE_PROTOCOL_DYNAMIC, SubGhzProtocolCommonTypeDynamic,
}; }SubGhzProtocolCommonType;
typedef struct SubGhzProtocolCommon SubGhzProtocolCommon; typedef struct SubGhzProtocolCommon SubGhzProtocolCommon;
typedef struct SubGhzProtocolCommonEncoder SubGhzProtocolCommonEncoder; typedef struct SubGhzProtocolCommonEncoder SubGhzProtocolCommonEncoder;
@ -38,7 +37,8 @@ typedef void (*SubGhzProtocolCommonToStr)(SubGhzProtocolCommon* instance, string
typedef void (*SubGhzProtocolCommonGetStrSave)(SubGhzProtocolCommon* instance, string_t output); typedef void (*SubGhzProtocolCommonGetStrSave)(SubGhzProtocolCommon* instance, string_t output);
//Load protocol from file //Load protocol from file
typedef bool (*SubGhzProtocolCommonLoadFromFile)(FileWorker* file_worker, SubGhzProtocolCommon* instance); typedef bool (
*SubGhzProtocolCommonLoadFromFile)(FileWorker* file_worker, SubGhzProtocolCommon* instance);
//Load protocol //Load protocol
typedef void (*SubGhzProtocolCommonLoadFromRAW)(SubGhzProtocolCommon* instance, void* context); typedef void (*SubGhzProtocolCommonLoadFromRAW)(SubGhzProtocolCommon* instance, void* context);
//Get upload encoder protocol //Get upload encoder protocol
@ -56,13 +56,13 @@ struct SubGhzProtocolCommon {
uint64_t code_found; uint64_t code_found;
uint64_t code_last_found; uint64_t code_last_found;
uint8_t code_min_count_bit_for_found; uint8_t code_min_count_bit_for_found;
uint8_t parser_step;
uint8_t type_protocol;
uint32_t te_last;
uint8_t header_count;
uint16_t cnt;
uint32_t serial;
uint8_t btn; uint8_t btn;
uint8_t header_count;
SubGhzProtocolCommonType type_protocol;
uint32_t te_last;
uint32_t serial;
uint32_t parser_step;
uint16_t cnt;
/* Standard Callback for on rx complete event */ /* Standard Callback for on rx complete event */
SubGhzProtocolCommonCallback callback; SubGhzProtocolCommonCallback callback;
@ -88,7 +88,7 @@ struct SubGhzProtocolCommonEncoder {
LevelDuration* upload; LevelDuration* upload;
}; };
struct SubGhzProtocolCommonLoad{ struct SubGhzProtocolCommonLoad {
uint64_t code_found; uint64_t code_found;
uint8_t code_count_bit; uint8_t code_count_bit;
uint32_t param1; uint32_t param1;

View File

@ -1,19 +1,25 @@
#include "subghz_protocol_faac_slh.h" #include "subghz_protocol_faac_slh.h"
struct SubGhzProtocolFaacSLH { struct SubGhzProtocolFaacSLH {
SubGhzProtocolCommon common; SubGhzProtocolCommon common;
}; };
typedef enum {
FaacSLHDecoderStepReset = 0,
FaacSLHDecoderStepFoundPreambula,
FaacSLHDecoderStepSaveDuration,
FaacSLHDecoderStepCheckDuration,
} FaacSLHDecoderStep;
SubGhzProtocolFaacSLH* subghz_protocol_faac_slh_alloc(void) { SubGhzProtocolFaacSLH* subghz_protocol_faac_slh_alloc(void) {
SubGhzProtocolFaacSLH* instance = furi_alloc(sizeof(SubGhzProtocolFaacSLH)); SubGhzProtocolFaacSLH* instance = furi_alloc(sizeof(SubGhzProtocolFaacSLH));
instance->common.name = "Faac SLH"; instance->common.name = "Faac SLH";
instance->common.code_min_count_bit_for_found = 64; instance->common.code_min_count_bit_for_found = 64;
instance->common.te_short = 255; instance->common.te_short = 255;
instance->common.te_long = 595; instance->common.te_long = 595;
instance->common.te_delta = 100; instance->common.te_delta = 100;
instance->common.type_protocol = TYPE_PROTOCOL_DYNAMIC; instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_faac_slh_to_str; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_faac_slh_to_str;
instance->common.to_load_protocol = instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_faac_slh_to_load_protocol; (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_faac_slh_to_load_protocol;
@ -32,7 +38,7 @@ void subghz_protocol_faac_slh_free(SubGhzProtocolFaacSLH* instance) {
* @param bit - bit * @param bit - bit
*/ */
void subghz_protocol_faac_slh_send_bit(SubGhzProtocolFaacSLH* instance, uint8_t bit) { void subghz_protocol_faac_slh_send_bit(SubGhzProtocolFaacSLH* instance, uint8_t bit) {
if (bit) { if(bit) {
//send bit 1 //send bit 1
SUBGHZ_TX_PIN_HIGH(); SUBGHZ_TX_PIN_HIGH();
delay_us(instance->common.te_long); delay_us(instance->common.te_long);
@ -47,22 +53,26 @@ void subghz_protocol_faac_slh_send_bit(SubGhzProtocolFaacSLH* instance, uint8_t
} }
} }
void subghz_protocol_faac_slh_send_key(SubGhzProtocolFaacSLH* instance, uint64_t key, uint8_t bit,uint8_t repeat) { void subghz_protocol_faac_slh_send_key(
while (repeat--) { SubGhzProtocolFaacSLH* instance,
uint64_t key,
uint8_t bit,
uint8_t repeat) {
while(repeat--) {
SUBGHZ_TX_PIN_HIGH(); SUBGHZ_TX_PIN_HIGH();
//Send header //Send header
delay_us(instance->common.te_long * 2); delay_us(instance->common.te_long * 2);
SUBGHZ_TX_PIN_LOW(); SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_long * 2); delay_us(instance->common.te_long * 2);
//Send key data //Send key data
for (uint8_t i = bit; i > 0; i--) { for(uint8_t i = bit; i > 0; i--) {
subghz_protocol_faac_slh_send_bit(instance, bit_read(key, i - 1)); subghz_protocol_faac_slh_send_bit(instance, bit_read(key, i - 1));
} }
} }
} }
void subghz_protocol_faac_slh_reset(SubGhzProtocolFaacSLH* instance) { void subghz_protocol_faac_slh_reset(SubGhzProtocolFaacSLH* instance) {
instance->common.parser_step = 0; instance->common.parser_step = FaacSLHDecoderStepReset;
} }
/** Analysis of received data /** Analysis of received data
@ -70,7 +80,8 @@ void subghz_protocol_faac_slh_reset(SubGhzProtocolFaacSLH* instance) {
* @param instance SubGhzProtocolFaacSLH instance * @param instance SubGhzProtocolFaacSLH instance
*/ */
void subghz_protocol_faac_slh_check_remote_controller(SubGhzProtocolFaacSLH* instance) { void subghz_protocol_faac_slh_check_remote_controller(SubGhzProtocolFaacSLH* instance) {
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_last_found, instance->common.code_last_count_bit); uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t code_fix = code_found_reverse & 0xFFFFFFFF; uint32_t code_fix = code_found_reverse & 0xFFFFFFFF;
//uint32_t code_hop = (code_found_reverse >> 24) & 0xFFFFF; //uint32_t code_hop = (code_found_reverse >> 24) & 0xFFFFF;
@ -79,62 +90,68 @@ void subghz_protocol_faac_slh_check_remote_controller(SubGhzProtocolFaacSLH* ins
} }
void subghz_protocol_faac_slh_parse(SubGhzProtocolFaacSLH* instance, bool level, uint32_t duration) { void subghz_protocol_faac_slh_parse(SubGhzProtocolFaacSLH* instance, bool level, uint32_t duration) {
switch (instance->common.parser_step) { switch(instance->common.parser_step) {
case 0: case FaacSLHDecoderStepReset:
if ((level) if((level) && (DURATION_DIFF(duration, instance->common.te_long * 2) <
&& (DURATION_DIFF(duration,instance->common.te_long * 2)< instance->common.te_delta * 3)) { instance->common.te_delta * 3)) {
instance->common.parser_step = 1; instance->common.parser_step = FaacSLHDecoderStepFoundPreambula;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = FaacSLHDecoderStepReset;
} }
break; break;
case 1: case FaacSLHDecoderStepFoundPreambula:
if ((!level) if((!level) && (DURATION_DIFF(duration, instance->common.te_long * 2) <
&& (DURATION_DIFF(duration,instance->common.te_long * 2)< instance->common.te_delta * 3)) { instance->common.te_delta * 3)) {
//Found Preambula //Found Preambula
instance->common.parser_step = 2; instance->common.parser_step = FaacSLHDecoderStepSaveDuration;
instance->common.code_found = 0; instance->common.code_found = 0;
instance->common.code_count_bit = 0; instance->common.code_count_bit = 0;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = FaacSLHDecoderStepReset;
} }
break; break;
case 2: case FaacSLHDecoderStepSaveDuration:
if (level) { if(level) {
if (duration >= (instance->common.te_short * 3 + instance->common.te_delta)) { if(duration >= (instance->common.te_short * 3 + instance->common.te_delta)) {
instance->common.parser_step = 1; instance->common.parser_step = FaacSLHDecoderStepFoundPreambula;
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_count_bit = instance->common.code_count_bit; instance->common.code_last_count_bit = instance->common.code_count_bit;
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;
break; break;
} else { } else {
instance->common.te_last = duration; instance->common.te_last = duration;
instance->common.parser_step = 3; instance->common.parser_step = FaacSLHDecoderStepCheckDuration;
} }
}else{ } else {
instance->common.parser_step = 0; instance->common.parser_step = FaacSLHDecoderStepReset;
} }
break; break;
case 3: case FaacSLHDecoderStepCheckDuration:
if(!level){ if(!level) {
if ((DURATION_DIFF(instance->common.te_last,instance->common.te_short)< instance->common.te_delta) if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
&& (DURATION_DIFF(duration,instance->common.te_long)< instance->common.te_delta)) { 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 = FaacSLHDecoderStepSaveDuration;
} else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_long )< instance->common.te_delta) } else if(
&& (DURATION_DIFF(duration,instance->common.te_short)< instance->common.te_delta)) { (DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < 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 = FaacSLHDecoderStepSaveDuration;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = FaacSLHDecoderStepReset;
} }
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = FaacSLHDecoderStepReset;
} }
break; break;
} }
@ -142,28 +159,29 @@ void subghz_protocol_faac_slh_parse(SubGhzProtocolFaacSLH* instance, bool level,
void subghz_protocol_faac_slh_to_str(SubGhzProtocolFaacSLH* instance, string_t output) { void subghz_protocol_faac_slh_to_str(SubGhzProtocolFaacSLH* instance, string_t output) {
subghz_protocol_faac_slh_check_remote_controller(instance); subghz_protocol_faac_slh_check_remote_controller(instance);
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_last_found, instance->common.code_last_count_bit); uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t code_fix = code_found_reverse & 0xFFFFFFFF; uint32_t code_fix = code_found_reverse & 0xFFFFFFFF;
uint32_t code_hop = (code_found_reverse >>32) & 0xFFFFFFFF; uint32_t code_hop = (code_found_reverse >> 32) & 0xFFFFFFFF;
string_cat_printf(output, string_cat_printf(
"%s %dbit\r\n" output,
"Key:0x%lX%08lX\r\n" "%s %dbit\r\n"
"Fix:%08lX \r\n" "Key:0x%lX%08lX\r\n"
"Hop:%08lX \r\n" "Fix:%08lX \r\n"
"Sn:%07lX Btn:%lX\r\n", "Hop:%08lX \r\n"
instance->common.name, "Sn:%07lX Btn:%lX\r\n",
instance->common.code_last_count_bit, instance->common.name,
(uint32_t)(instance->common.code_last_found >> 32), instance->common.code_last_count_bit,
(uint32_t)instance->common.code_last_found, (uint32_t)(instance->common.code_last_found >> 32),
code_fix, code_hop, (uint32_t)instance->common.code_last_found,
instance->common.serial, code_fix,
instance->common.btn); code_hop,
instance->common.serial,
instance->common.btn);
} }
void subghz_decoder_faac_slh_to_load_protocol( void subghz_decoder_faac_slh_to_load_protocol(SubGhzProtocolFaacSLH* instance, void* context) {
SubGhzProtocolFaacSLH* instance,
void* context) {
furi_assert(context); furi_assert(context);
furi_assert(instance); furi_assert(instance);
SubGhzProtocolCommonLoad* data = context; SubGhzProtocolCommonLoad* data = context;

View File

@ -1,10 +1,16 @@
#include "subghz_protocol_gate_tx.h" #include "subghz_protocol_gate_tx.h"
struct SubGhzProtocolGateTX { struct SubGhzProtocolGateTX {
SubGhzProtocolCommon common; SubGhzProtocolCommon common;
}; };
typedef enum {
GateTXDecoderStepReset = 0,
GateTXDecoderStepFoundStartBit,
GateTXDecoderStepSaveDuration,
GateTXDecoderStepCheckDuration,
} GateTXDecoderStep;
SubGhzProtocolGateTX* subghz_protocol_gate_tx_alloc(void) { SubGhzProtocolGateTX* subghz_protocol_gate_tx_alloc(void) {
SubGhzProtocolGateTX* instance = furi_alloc(sizeof(SubGhzProtocolGateTX)); SubGhzProtocolGateTX* instance = furi_alloc(sizeof(SubGhzProtocolGateTX));
@ -13,11 +19,11 @@ SubGhzProtocolGateTX* subghz_protocol_gate_tx_alloc(void) {
instance->common.te_short = 350; instance->common.te_short = 350;
instance->common.te_long = 700; instance->common.te_long = 700;
instance->common.te_delta = 100; instance->common.te_delta = 100;
instance->common.type_protocol = TYPE_PROTOCOL_STATIC; instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_gate_tx_to_str; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_gate_tx_to_str;
instance->common.to_save_string = instance->common.to_save_string =
(SubGhzProtocolCommonGetStrSave)subghz_protocol_gate_tx_to_save_str; (SubGhzProtocolCommonGetStrSave)subghz_protocol_gate_tx_to_save_str;
instance->common.to_load_protocol_from_file= instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_protocol_gate_tx_to_load_protocol_from_file; (SubGhzProtocolCommonLoadFromFile)subghz_protocol_gate_tx_to_load_protocol_from_file;
instance->common.to_load_protocol = instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_gate_tx_to_load_protocol; (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_gate_tx_to_load_protocol;
@ -31,33 +37,40 @@ void subghz_protocol_gate_tx_free(SubGhzProtocolGateTX* instance) {
free(instance); free(instance);
} }
bool subghz_protocol_gate_tx_send_key(SubGhzProtocolGateTX* instance, SubGhzProtocolCommonEncoder* encoder){ bool subghz_protocol_gate_tx_send_key(
SubGhzProtocolGateTX* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance); furi_assert(instance);
furi_assert(encoder); furi_assert(encoder);
size_t index = 0; size_t index = 0;
encoder->size_upload =(instance->common.code_last_count_bit * 2) + 2; encoder->size_upload = (instance->common.code_last_count_bit * 2) + 2;
if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false; if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
//Send header //Send header
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short * 49); encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short * 49);
//Send start bit //Send start bit
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_long); encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_long);
//Send key data //Send key data
for (uint8_t i = instance->common.code_last_count_bit; i > 0; i--) { for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
if(bit_read(instance->common.code_last_found, i - 1)){ if(bit_read(instance->common.code_last_found, i - 1)) {
//send bit 1 //send bit 1
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_long); encoder->upload[index++] =
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short); level_duration_make(false, (uint32_t)instance->common.te_long);
}else{ encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_short);
} else {
//send bit 0 //send bit 0
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short); encoder->upload[index++] =
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_long); level_duration_make(false, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_long);
} }
} }
return true; return true;
} }
void subghz_protocol_gate_tx_reset(SubGhzProtocolGateTX* instance) { void subghz_protocol_gate_tx_reset(SubGhzProtocolGateTX* instance) {
instance->common.parser_step = 0; instance->common.parser_step = GateTXDecoderStepReset;
} }
/** Analysis of received data /** Analysis of received data
@ -65,68 +78,78 @@ void subghz_protocol_gate_tx_reset(SubGhzProtocolGateTX* instance) {
* @param instance SubGhzProtocolFaacSLH instance * @param instance SubGhzProtocolFaacSLH instance
*/ */
void subghz_protocol_gate_tx_check_remote_controller(SubGhzProtocolGateTX* instance) { void subghz_protocol_gate_tx_check_remote_controller(SubGhzProtocolGateTX* instance) {
uint32_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_last_found, instance->common.code_last_count_bit); uint32_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
instance->common.serial = (code_found_reverse & 0xFF) << 12 | ((code_found_reverse >>8) & 0xFF) << 4 | ((code_found_reverse >>20) & 0x0F) ; instance->common.serial = (code_found_reverse & 0xFF) << 12 |
((code_found_reverse >> 8) & 0xFF) << 4 |
((code_found_reverse >> 20) & 0x0F);
instance->common.btn = ((code_found_reverse >> 16) & 0x0F); instance->common.btn = ((code_found_reverse >> 16) & 0x0F);
} }
void subghz_protocol_gate_tx_parse(SubGhzProtocolGateTX* instance, bool level, uint32_t duration) { void subghz_protocol_gate_tx_parse(SubGhzProtocolGateTX* instance, bool level, uint32_t duration) {
switch (instance->common.parser_step) { switch(instance->common.parser_step) {
case 0: case GateTXDecoderStepReset:
if ((!level) if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 47) <
&& (DURATION_DIFF(duration,instance->common.te_short * 47)< instance->common.te_delta * 47)) { instance->common.te_delta * 47)) {
//Found Preambula //Found Preambula
instance->common.parser_step = 1; instance->common.parser_step = GateTXDecoderStepFoundStartBit;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = GateTXDecoderStepReset;
} }
break; break;
case 1: case GateTXDecoderStepFoundStartBit:
if (level && ((DURATION_DIFF(duration,instance->common.te_long)< instance->common.te_delta*3))){ if(level &&
((DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta * 3))) {
//Found start bit //Found start bit
instance->common.parser_step = 2; instance->common.parser_step = GateTXDecoderStepSaveDuration;
instance->common.code_found = 0; instance->common.code_found = 0;
instance->common.code_count_bit = 0; instance->common.code_count_bit = 0;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = GateTXDecoderStepReset;
} }
break; break;
case 2: case GateTXDecoderStepSaveDuration:
if (!level) { if(!level) {
if (duration >= (instance->common.te_short * 10 + instance->common.te_delta)) { if(duration >= (instance->common.te_short * 10 + instance->common.te_delta)) {
instance->common.parser_step = 1; instance->common.parser_step = GateTXDecoderStepFoundStartBit;
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_count_bit = instance->common.code_count_bit; instance->common.code_last_count_bit = instance->common.code_count_bit;
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;
break; break;
} else { } else {
instance->common.te_last = duration; instance->common.te_last = duration;
instance->common.parser_step = 3; instance->common.parser_step = GateTXDecoderStepCheckDuration;
} }
} }
break; break;
case 3: case GateTXDecoderStepCheckDuration:
if(level){ if(level) {
if ((DURATION_DIFF(instance->common.te_last,instance->common.te_short)< instance->common.te_delta) if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
&& (DURATION_DIFF(duration,instance->common.te_long)< instance->common.te_delta*3)) { instance->common.te_delta) &&
(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 = 2; instance->common.parser_step = GateTXDecoderStepSaveDuration;
} else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_long)< instance->common.te_delta*3) } else if(
&& (DURATION_DIFF(duration,instance->common.te_short)< instance->common.te_delta)) { (DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta * 3) &&
(DURATION_DIFF(duration, instance->common.te_short) < 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 = GateTXDecoderStepSaveDuration;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = GateTXDecoderStepReset;
} }
}else{ } else {
instance->common.parser_step = 0; instance->common.parser_step = GateTXDecoderStepReset;
} }
break; break;
} }
@ -134,16 +157,16 @@ void subghz_protocol_gate_tx_parse(SubGhzProtocolGateTX* instance, bool level, u
void subghz_protocol_gate_tx_to_str(SubGhzProtocolGateTX* instance, string_t output) { void subghz_protocol_gate_tx_to_str(SubGhzProtocolGateTX* instance, string_t output) {
subghz_protocol_gate_tx_check_remote_controller(instance); subghz_protocol_gate_tx_check_remote_controller(instance);
string_cat_printf(output, string_cat_printf(
"%s %dbit\r\n" output,
"Key:%06lX\r\n" "%s %dbit\r\n"
"Sn:%05lX Btn:%lX\r\n", "Key:%06lX\r\n"
instance->common.name, "Sn:%05lX Btn:%lX\r\n",
instance->common.code_last_count_bit, instance->common.name,
(uint32_t)(instance->common.code_last_found & 0xFFFFFF), instance->common.code_last_count_bit,
instance->common.serial, (uint32_t)(instance->common.code_last_found & 0xFFFFFF),
instance->common.btn instance->common.serial,
); instance->common.btn);
} }
void subghz_protocol_gate_tx_to_save_str(SubGhzProtocolGateTX* instance, string_t output) { void subghz_protocol_gate_tx_to_save_str(SubGhzProtocolGateTX* instance, string_t output) {
@ -157,7 +180,9 @@ void subghz_protocol_gate_tx_to_save_str(SubGhzProtocolGateTX* instance, string_
(uint32_t)(instance->common.code_last_found & 0x00000000ffffffff)); (uint32_t)(instance->common.code_last_found & 0x00000000ffffffff));
} }
bool subghz_protocol_gate_tx_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolGateTX* instance){ bool subghz_protocol_gate_tx_to_load_protocol_from_file(
FileWorker* file_worker,
SubGhzProtocolGateTX* instance) {
bool loaded = false; bool loaded = false;
string_t temp_str; string_t temp_str;
string_init(temp_str); string_init(temp_str);
@ -195,9 +220,7 @@ bool subghz_protocol_gate_tx_to_load_protocol_from_file(FileWorker* file_worker,
return loaded; return loaded;
} }
void subghz_decoder_gate_tx_to_load_protocol( void subghz_decoder_gate_tx_to_load_protocol(SubGhzProtocolGateTX* instance, void* context) {
SubGhzProtocolGateTX* instance,
void* context) {
furi_assert(context); furi_assert(context);
furi_assert(instance); furi_assert(instance);
SubGhzProtocolCommonLoad* data = context; SubGhzProtocolCommonLoad* data = context;

View File

@ -4,6 +4,13 @@ struct SubGhzProtocolIDo {
SubGhzProtocolCommon common; SubGhzProtocolCommon common;
}; };
typedef enum {
IDoDecoderStepReset = 0,
IDoDecoderStepFoundPreambula,
IDoDecoderStepSaveDuration,
IDoDecoderStepCheckDuration,
} IDoDecoderStep;
SubGhzProtocolIDo* subghz_protocol_ido_alloc(void) { SubGhzProtocolIDo* subghz_protocol_ido_alloc(void) {
SubGhzProtocolIDo* instance = furi_alloc(sizeof(SubGhzProtocolIDo)); SubGhzProtocolIDo* instance = furi_alloc(sizeof(SubGhzProtocolIDo));
@ -12,7 +19,7 @@ SubGhzProtocolIDo* subghz_protocol_ido_alloc(void) {
instance->common.te_short = 450; instance->common.te_short = 450;
instance->common.te_long = 1450; instance->common.te_long = 1450;
instance->common.te_delta = 150; instance->common.te_delta = 150;
instance->common.type_protocol = TYPE_PROTOCOL_DYNAMIC; instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_ido_to_str; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_ido_to_str;
instance->common.to_load_protocol = instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_ido_to_load_protocol; (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_ido_to_load_protocol;
@ -65,7 +72,7 @@ void subghz_protocol_ido_send_key(
} }
void subghz_protocol_ido_reset(SubGhzProtocolIDo* instance) { void subghz_protocol_ido_reset(SubGhzProtocolIDo* instance) {
instance->common.parser_step = 0; instance->common.parser_step = IDoDecoderStepReset;
} }
/** Analysis of received data /** Analysis of received data
@ -83,29 +90,29 @@ void subghz_protocol_ido_check_remote_controller(SubGhzProtocolIDo* instance) {
void subghz_protocol_ido_parse(SubGhzProtocolIDo* instance, bool level, uint32_t duration) { void subghz_protocol_ido_parse(SubGhzProtocolIDo* instance, bool level, uint32_t duration) {
switch(instance->common.parser_step) { switch(instance->common.parser_step) {
case 0: case IDoDecoderStepReset:
if((level) && (DURATION_DIFF(duration, instance->common.te_short * 10) < if((level) && (DURATION_DIFF(duration, instance->common.te_short * 10) <
instance->common.te_delta * 5)) { instance->common.te_delta * 5)) {
instance->common.parser_step = 1; instance->common.parser_step = IDoDecoderStepFoundPreambula;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = IDoDecoderStepReset;
} }
break; break;
case 1: case IDoDecoderStepFoundPreambula:
if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 10) < if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 10) <
instance->common.te_delta * 5)) { instance->common.te_delta * 5)) {
//Found Preambula //Found Preambula
instance->common.parser_step = 2; instance->common.parser_step = IDoDecoderStepSaveDuration;
instance->common.code_found = 0; instance->common.code_found = 0;
instance->common.code_count_bit = 0; instance->common.code_count_bit = 0;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = IDoDecoderStepReset;
} }
break; break;
case 2: case IDoDecoderStepSaveDuration:
if(level) { if(level) {
if(duration >= (instance->common.te_short * 5 + instance->common.te_delta)) { if(duration >= (instance->common.te_short * 5 + instance->common.te_delta)) {
instance->common.parser_step = 1; instance->common.parser_step = IDoDecoderStepFoundPreambula;
if(instance->common.code_count_bit >= if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) { 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;
@ -119,32 +126,32 @@ void subghz_protocol_ido_parse(SubGhzProtocolIDo* instance, bool level, uint32_t
break; break;
} else { } else {
instance->common.te_last = duration; instance->common.te_last = duration;
instance->common.parser_step = 3; instance->common.parser_step = IDoDecoderStepCheckDuration;
} }
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = IDoDecoderStepReset;
} }
break; break;
case 3: case IDoDecoderStepCheckDuration:
if(!level) { if(!level) {
if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) < if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) && instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_long) < (DURATION_DIFF(duration, instance->common.te_long) <
instance->common.te_delta * 3)) { 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 = 2; instance->common.parser_step = IDoDecoderStepSaveDuration;
} else if( } else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_short) < (DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta * 3) && instance->common.te_delta * 3) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) { (DURATION_DIFF(duration, instance->common.te_short) < 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 = IDoDecoderStepSaveDuration;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = IDoDecoderStepReset;
} }
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = IDoDecoderStepReset;
} }
break; break;
} }
@ -174,9 +181,7 @@ void subghz_protocol_ido_to_str(SubGhzProtocolIDo* instance, string_t output) {
instance->common.btn); instance->common.btn);
} }
void subghz_decoder_ido_to_load_protocol( void subghz_decoder_ido_to_load_protocol(SubGhzProtocolIDo* instance, void* context) {
SubGhzProtocolIDo* instance,
void* context) {
furi_assert(context); furi_assert(context);
furi_assert(instance); furi_assert(instance);
SubGhzProtocolCommonLoad* data = context; SubGhzProtocolCommonLoad* data = context;

View File

@ -13,6 +13,13 @@ struct SubGhzProtocolKeeloq {
const char* manufacture_name; const char* manufacture_name;
}; };
typedef enum {
KeeloqDecoderStepReset = 0,
KeeloqDecoderStepCheckPreambula,
KeeloqDecoderStepSaveDuration,
KeeloqDecoderStepCheckDuration,
} KeeloqDecoderStep;
SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(SubGhzKeystore* keystore) { SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(SubGhzKeystore* keystore) {
SubGhzProtocolKeeloq* instance = furi_alloc(sizeof(SubGhzProtocolKeeloq)); SubGhzProtocolKeeloq* instance = furi_alloc(sizeof(SubGhzProtocolKeeloq));
@ -23,7 +30,7 @@ SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(SubGhzKeystore* keystore) {
instance->common.te_short = 400; instance->common.te_short = 400;
instance->common.te_long = 800; instance->common.te_long = 800;
instance->common.te_delta = 140; instance->common.te_delta = 140;
instance->common.type_protocol = TYPE_PROTOCOL_DYNAMIC; instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_keeloq_to_str; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_keeloq_to_str;
instance->common.to_save_string = instance->common.to_save_string =
(SubGhzProtocolCommonGetStrSave)subghz_protocol_keeloq_to_save_str; (SubGhzProtocolCommonGetStrSave)subghz_protocol_keeloq_to_save_str;
@ -297,50 +304,50 @@ bool subghz_protocol_keeloq_send_key(
} }
void subghz_protocol_keeloq_reset(SubGhzProtocolKeeloq* instance) { void subghz_protocol_keeloq_reset(SubGhzProtocolKeeloq* instance) {
instance->common.parser_step = 0; instance->common.parser_step = KeeloqDecoderStepReset;
} }
void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, uint32_t duration) { 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 KeeloqDecoderStepReset:
if((level) && if((level) &&
DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) { DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
instance->common.parser_step = 1; instance->common.parser_step = KeeloqDecoderStepCheckPreambula;
instance->common.header_count++; instance->common.header_count++;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = KeeloqDecoderStepReset;
} }
break; break;
case 1: case KeeloqDecoderStepCheckPreambula:
if((!level) && if((!level) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) { (DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
instance->common.parser_step = 0; instance->common.parser_step = KeeloqDecoderStepReset;
break; break;
} }
if((instance->common.header_count > 2) && if((instance->common.header_count > 2) &&
(DURATION_DIFF(duration, instance->common.te_short * 10) < (DURATION_DIFF(duration, instance->common.te_short * 10) <
instance->common.te_delta * 10)) { instance->common.te_delta * 10)) {
// Found header // Found header
instance->common.parser_step = 2; instance->common.parser_step = KeeloqDecoderStepSaveDuration;
instance->common.code_found = 0; instance->common.code_found = 0;
instance->common.code_count_bit = 0; instance->common.code_count_bit = 0;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = KeeloqDecoderStepReset;
instance->common.header_count = 0; instance->common.header_count = 0;
} }
break; break;
case 2: case KeeloqDecoderStepSaveDuration:
if(level) { if(level) {
instance->common.te_last = duration; instance->common.te_last = duration;
instance->common.parser_step = 3; instance->common.parser_step = KeeloqDecoderStepCheckDuration;
} }
break; break;
case 3: case KeeloqDecoderStepCheckDuration:
if(!level) { if(!level) {
if(duration >= (instance->common.te_short * 2 + instance->common.te_delta)) { if(duration >= (instance->common.te_short * 2 + instance->common.te_delta)) {
// Found end TX // Found end TX
instance->common.parser_step = 0; instance->common.parser_step = KeeloqDecoderStepReset;
if(instance->common.code_count_bit >= if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) { instance->common.code_min_count_bit_for_found) {
if(instance->common.code_last_found != instance->common.code_found) { if(instance->common.code_last_found != instance->common.code_found) {
@ -363,7 +370,7 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, ui
instance->common.code_min_count_bit_for_found) { 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 = KeeloqDecoderStepSaveDuration;
} else if( } else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) < (DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) && instance->common.te_delta) &&
@ -372,13 +379,13 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, ui
instance->common.code_min_count_bit_for_found) { instance->common.code_min_count_bit_for_found) {
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 = KeeloqDecoderStepSaveDuration;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = KeeloqDecoderStepReset;
instance->common.header_count = 0; instance->common.header_count = 0;
} }
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = KeeloqDecoderStepReset;
instance->common.header_count = 0; instance->common.header_count = 0;
} }
break; break;

View File

@ -4,6 +4,13 @@ struct SubGhzProtocolNeroRadio {
SubGhzProtocolCommon common; SubGhzProtocolCommon common;
}; };
typedef enum {
NeroRadioDecoderStepReset = 0,
NeroRadioDecoderStepCheckPreambula,
NeroRadioDecoderStepSaveDuration,
NeroRadioDecoderStepCheckDuration,
} NeroRadioDecoderStep;
SubGhzProtocolNeroRadio* subghz_protocol_nero_radio_alloc(void) { SubGhzProtocolNeroRadio* subghz_protocol_nero_radio_alloc(void) {
SubGhzProtocolNeroRadio* instance = furi_alloc(sizeof(SubGhzProtocolNeroRadio)); SubGhzProtocolNeroRadio* instance = furi_alloc(sizeof(SubGhzProtocolNeroRadio));
@ -12,7 +19,7 @@ SubGhzProtocolNeroRadio* subghz_protocol_nero_radio_alloc(void) {
instance->common.te_short = 200; instance->common.te_short = 200;
instance->common.te_long = 400; instance->common.te_long = 400;
instance->common.te_delta = 80; instance->common.te_delta = 80;
instance->common.type_protocol = TYPE_PROTOCOL_STATIC; instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nero_radio_to_str; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nero_radio_to_str;
instance->common.to_save_string = instance->common.to_save_string =
(SubGhzProtocolCommonGetStrSave)subghz_protocol_nero_radio_to_save_str; (SubGhzProtocolCommonGetStrSave)subghz_protocol_nero_radio_to_save_str;
@ -74,7 +81,7 @@ bool subghz_protocol_nero_radio_send_key(
} }
void subghz_protocol_nero_radio_reset(SubGhzProtocolNeroRadio* instance) { void subghz_protocol_nero_radio_reset(SubGhzProtocolNeroRadio* instance) {
instance->common.parser_step = 0; instance->common.parser_step = NeroRadioDecoderStepReset;
} }
/** Analysis of received data /** Analysis of received data
@ -99,24 +106,24 @@ void subghz_protocol_nero_radio_parse(
bool level, bool level,
uint32_t duration) { uint32_t duration) {
switch(instance->common.parser_step) { switch(instance->common.parser_step) {
case 0: case NeroRadioDecoderStepReset:
if((level) && if((level) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) { (DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
instance->common.parser_step = 1; instance->common.parser_step = NeroRadioDecoderStepCheckPreambula;
instance->common.te_last = duration; instance->common.te_last = duration;
instance->common.header_count = 0; instance->common.header_count = 0;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroRadioDecoderStepReset;
} }
break; break;
case 1: case NeroRadioDecoderStepCheckPreambula:
if(level) { if(level) {
if((DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) || if((DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) ||
(DURATION_DIFF(duration, instance->common.te_short * 4) < (DURATION_DIFF(duration, instance->common.te_short * 4) <
instance->common.te_delta)) { instance->common.te_delta)) {
instance->common.te_last = duration; instance->common.te_last = duration;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroRadioDecoderStepReset;
} }
} else if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) { } else if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
if(DURATION_DIFF(instance->common.te_last, instance->common.te_short) < if(DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
@ -129,32 +136,32 @@ void subghz_protocol_nero_radio_parse(
instance->common.te_delta) { instance->common.te_delta) {
// Found start bit // Found start bit
if(instance->common.header_count > 40) { if(instance->common.header_count > 40) {
instance->common.parser_step = 2; instance->common.parser_step = NeroRadioDecoderStepSaveDuration;
instance->common.code_found = 0; instance->common.code_found = 0;
instance->common.code_count_bit = 0; instance->common.code_count_bit = 0;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroRadioDecoderStepReset;
} }
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroRadioDecoderStepReset;
} }
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroRadioDecoderStepReset;
} }
break; break;
case 2: case NeroRadioDecoderStepSaveDuration:
if(level) { if(level) {
instance->common.te_last = duration; instance->common.te_last = duration;
instance->common.parser_step = 3; instance->common.parser_step = NeroRadioDecoderStepCheckDuration;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroRadioDecoderStepReset;
} }
break; break;
case 3: case NeroRadioDecoderStepCheckDuration:
if(!level) { if(!level) {
if(duration >= (instance->common.te_short * 10 + instance->common.te_delta * 2)) { if(duration >= (instance->common.te_short * 10 + instance->common.te_delta * 2)) {
//Found stop bit //Found stop bit
instance->common.parser_step = 0; instance->common.parser_step = NeroRadioDecoderStepReset;
if(instance->common.code_count_bit >= if(instance->common.code_count_bit >=
instance->common.code_min_count_bit_for_found) { 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;
@ -165,25 +172,25 @@ void subghz_protocol_nero_radio_parse(
} }
instance->common.code_found = 0; instance->common.code_found = 0;
instance->common.code_count_bit = 0; instance->common.code_count_bit = 0;
instance->common.parser_step = 0; instance->common.parser_step = NeroRadioDecoderStepReset;
break; break;
} else if( } else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_short) < (DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) && instance->common.te_delta) &&
(DURATION_DIFF(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 = NeroRadioDecoderStepSaveDuration;
} else if( } else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) < (DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) && instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) { (DURATION_DIFF(duration, instance->common.te_short) < 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 = NeroRadioDecoderStepSaveDuration;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroRadioDecoderStepReset;
} }
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroRadioDecoderStepReset;
} }
break; break;
} }

View File

@ -1,23 +1,29 @@
#include "subghz_protocol_nero_sketch.h" #include "subghz_protocol_nero_sketch.h"
struct SubGhzProtocolNeroSketch { struct SubGhzProtocolNeroSketch {
SubGhzProtocolCommon common; SubGhzProtocolCommon common;
}; };
typedef enum {
NeroSketchDecoderStepReset = 0,
NeroSketchDecoderStepCheckPreambula,
NeroSketchDecoderStepSaveDuration,
NeroSketchDecoderStepCheckDuration,
} NeroSketchDecoderStep;
SubGhzProtocolNeroSketch* subghz_protocol_nero_sketch_alloc(void) { SubGhzProtocolNeroSketch* subghz_protocol_nero_sketch_alloc(void) {
SubGhzProtocolNeroSketch* instance = furi_alloc(sizeof(SubGhzProtocolNeroSketch)); SubGhzProtocolNeroSketch* instance = furi_alloc(sizeof(SubGhzProtocolNeroSketch));
instance->common.name = "Nero Sketch"; instance->common.name = "Nero Sketch";
instance->common.code_min_count_bit_for_found = 40; instance->common.code_min_count_bit_for_found = 40;
instance->common.te_short = 330; instance->common.te_short = 330;
instance->common.te_long = 660; instance->common.te_long = 660;
instance->common.te_delta = 150; instance->common.te_delta = 150;
instance->common.type_protocol = TYPE_PROTOCOL_STATIC; instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nero_sketch_to_str; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nero_sketch_to_str;
instance->common.to_save_string = instance->common.to_save_string =
(SubGhzProtocolCommonGetStrSave)subghz_protocol_nero_sketch_to_save_str; (SubGhzProtocolCommonGetStrSave)subghz_protocol_nero_sketch_to_save_str;
instance->common.to_load_protocol_from_file= instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_protocol_nero_sketch_to_load_protocol_from_file; (SubGhzProtocolCommonLoadFromFile)subghz_protocol_nero_sketch_to_load_protocol_from_file;
instance->common.to_load_protocol = instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nero_sketch_to_load_protocol; (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nero_sketch_to_load_protocol;
@ -32,45 +38,51 @@ void subghz_protocol_nero_sketch_free(SubGhzProtocolNeroSketch* instance) {
free(instance); free(instance);
} }
bool subghz_protocol_nero_sketch_send_key(SubGhzProtocolNeroSketch* instance, SubGhzProtocolCommonEncoder* encoder){ bool subghz_protocol_nero_sketch_send_key(
SubGhzProtocolNeroSketch* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance); furi_assert(instance);
furi_assert(encoder); furi_assert(encoder);
size_t index = 0; size_t index = 0;
encoder->size_upload = 47*2+2+(instance->common.code_last_count_bit * 2) + 2; encoder->size_upload = 47 * 2 + 2 + (instance->common.code_last_count_bit * 2) + 2;
if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false; if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
//Send header //Send header
for(uint8_t i = 0; i < 47; i++){ for(uint8_t i = 0; i < 47; i++) {
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short); encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short); encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
} }
//Send start bit //Send start bit
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short*4); encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short * 4);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short); encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
//Send key data //Send key data
for (uint8_t i = instance->common.code_last_count_bit; i > 0; i--) { for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
if(bit_read(instance->common.code_last_found, i - 1)){ if(bit_read(instance->common.code_last_found, i - 1)) {
//send bit 1 //send bit 1
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_long); encoder->upload[index++] =
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short); level_duration_make(true, (uint32_t)instance->common.te_long);
}else{ encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short);
} else {
//send bit 0 //send bit 0
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short); encoder->upload[index++] =
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_long); level_duration_make(true, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_long);
} }
} }
//Send stop bit //Send stop bit
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short*3); encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short * 3);
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short); encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
return true; return true;
} }
void subghz_protocol_nero_sketch_reset(SubGhzProtocolNeroSketch* instance) { void subghz_protocol_nero_sketch_reset(SubGhzProtocolNeroSketch* instance) {
instance->common.parser_step = 0; instance->common.parser_step = NeroSketchDecoderStepReset;
} }
/** Analysis of received data /** Analysis of received data
@ -90,112 +102,123 @@ void subghz_protocol_nero_sketch_reset(SubGhzProtocolNeroSketch* instance) {
// } // }
void subghz_protocol_nero_sketch_parse(SubGhzProtocolNeroSketch* instance, bool level, uint32_t duration) { void subghz_protocol_nero_sketch_parse(
switch (instance->common.parser_step) { SubGhzProtocolNeroSketch* instance,
case 0: bool level,
if ((level) uint32_t duration) {
&& (DURATION_DIFF(duration,instance->common.te_short)< instance->common.te_delta)) { switch(instance->common.parser_step) {
instance->common.parser_step = 1; case NeroSketchDecoderStepReset:
if((level) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
instance->common.parser_step = NeroSketchDecoderStepCheckPreambula;
instance->common.te_last = duration; instance->common.te_last = duration;
instance->common.header_count = 0; instance->common.header_count = 0;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroSketchDecoderStepReset;
} }
break; break;
case 1: case NeroSketchDecoderStepCheckPreambula:
if (level){ if(level) {
if((DURATION_DIFF(duration,instance->common.te_short)< instance->common.te_delta ) if((DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) ||
|| (DURATION_DIFF(duration,instance->common.te_short*4)< instance->common.te_delta)) { (DURATION_DIFF(duration, instance->common.te_short * 4) <
instance->common.te_delta)) {
instance->common.te_last = duration; instance->common.te_last = duration;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroSketchDecoderStepReset;
} }
} else if(DURATION_DIFF(duration,instance->common.te_short)< instance->common.te_delta){ } else if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
if(DURATION_DIFF(instance->common.te_last,instance->common.te_short)< instance->common.te_delta){ if(DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
instance->common.te_delta) {
// Found header // Found header
instance->common.header_count++; instance->common.header_count++;
break; break;
}else if(DURATION_DIFF(instance->common.te_last,instance->common.te_short*4)< instance->common.te_delta){ } else if(
// Found start bit DURATION_DIFF(instance->common.te_last, instance->common.te_short * 4) <
if(instance->common.header_count>40) { instance->common.te_delta) {
instance->common.parser_step = 2; // Found start bit
if(instance->common.header_count > 40) {
instance->common.parser_step = NeroSketchDecoderStepSaveDuration;
instance->common.code_found = 0; instance->common.code_found = 0;
instance->common.code_count_bit = 0; instance->common.code_count_bit = 0;
}else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroSketchDecoderStepReset;
} }
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroSketchDecoderStepReset;
} }
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroSketchDecoderStepReset;
} }
break; break;
case 2: case NeroSketchDecoderStepSaveDuration:
if (level) { if(level) {
if (duration >= (instance->common.te_short * 2 + instance->common.te_delta*2)) { if(duration >= (instance->common.te_short * 2 + instance->common.te_delta * 2)) {
//Found stop bit //Found stop bit
instance->common.parser_step = 0; instance->common.parser_step = NeroSketchDecoderStepReset;
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_count_bit = instance->common.code_count_bit; instance->common.code_last_count_bit = instance->common.code_count_bit;
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;
break; break;
} else { } else {
instance->common.te_last = duration; instance->common.te_last = duration;
instance->common.parser_step = 3; instance->common.parser_step = NeroSketchDecoderStepCheckDuration;
} }
}else{ } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroSketchDecoderStepReset;
} }
break; break;
case 3: case NeroSketchDecoderStepCheckDuration:
if(!level){ if(!level) {
if ((DURATION_DIFF(instance->common.te_last,instance->common.te_short)< instance->common.te_delta) if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
&& (DURATION_DIFF(duration,instance->common.te_long)< instance->common.te_delta)) { 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 = NeroSketchDecoderStepSaveDuration;
} else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_long )< instance->common.te_delta) } else if(
&& (DURATION_DIFF(duration,instance->common.te_short)< instance->common.te_delta)) { (DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < 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 = NeroSketchDecoderStepSaveDuration;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroSketchDecoderStepReset;
} }
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NeroSketchDecoderStepReset;
} }
break; break;
} }
} }
void subghz_protocol_nero_sketch_to_str(SubGhzProtocolNeroSketch* instance, string_t output) { void subghz_protocol_nero_sketch_to_str(SubGhzProtocolNeroSketch* instance, string_t output) {
uint32_t code_found_hi = instance->common.code_last_found >> 32; uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff; uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_last_found, instance->common.code_last_count_bit); uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t code_found_reverse_hi = code_found_reverse>>32; uint32_t code_found_reverse_hi = code_found_reverse >> 32;
uint32_t code_found_reverse_lo = code_found_reverse&0x00000000ffffffff; uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
string_cat_printf(output, string_cat_printf(
"%s %dbit\r\n" output,
"Key:0x%lX%08lX\r\n" "%s %dbit\r\n"
"Yek:0x%lX%08lX\r\n", "Key:0x%lX%08lX\r\n"
instance->common.name, "Yek:0x%lX%08lX\r\n",
instance->common.code_last_count_bit, instance->common.name,
code_found_hi, instance->common.code_last_count_bit,
code_found_lo, code_found_hi,
code_found_reverse_hi, code_found_lo,
code_found_reverse_lo code_found_reverse_hi,
); code_found_reverse_lo);
} }
void subghz_protocol_nero_sketch_to_save_str(SubGhzProtocolNeroSketch* instance, string_t output) { void subghz_protocol_nero_sketch_to_save_str(SubGhzProtocolNeroSketch* instance, string_t output) {
@ -210,11 +233,12 @@ void subghz_protocol_nero_sketch_to_save_str(SubGhzProtocolNeroSketch* instance,
instance->common.name, instance->common.name,
instance->common.code_last_count_bit, instance->common.code_last_count_bit,
code_found_hi, code_found_hi,
code_found_lo code_found_lo);
);
} }
bool subghz_protocol_nero_sketch_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNeroSketch* instance){ bool subghz_protocol_nero_sketch_to_load_protocol_from_file(
FileWorker* file_worker,
SubGhzProtocolNeroSketch* instance) {
bool loaded = false; bool loaded = false;
string_t temp_str; string_t temp_str;
string_init(temp_str); string_init(temp_str);
@ -242,7 +266,7 @@ bool subghz_protocol_nero_sketch_to_load_protocol_from_file(FileWorker* file_wor
if(res != 2) { if(res != 2) {
break; break;
} }
instance->common.code_last_found = (uint64_t)temp_key_hi<<32 | temp_key_lo; instance->common.code_last_found = (uint64_t)temp_key_hi << 32 | temp_key_lo;
loaded = true; loaded = true;
} while(0); } while(0);
@ -252,9 +276,7 @@ bool subghz_protocol_nero_sketch_to_load_protocol_from_file(FileWorker* file_wor
return loaded; return loaded;
} }
void subghz_decoder_nero_sketch_to_load_protocol( void subghz_decoder_nero_sketch_to_load_protocol(SubGhzProtocolNeroSketch* instance, void* context) {
SubGhzProtocolNeroSketch* instance,
void* context) {
furi_assert(context); furi_assert(context);
furi_assert(instance); furi_assert(instance);
SubGhzProtocolCommonLoad* data = context; SubGhzProtocolCommonLoad* data = context;

View File

@ -10,6 +10,13 @@ struct SubGhzProtocolNiceFlo {
SubGhzProtocolCommon common; SubGhzProtocolCommon common;
}; };
typedef enum {
NiceFloDecoderStepReset = 0,
NiceFloDecoderStepFoundStartBit,
NiceFloDecoderStepSaveDuration,
NiceFloDecoderStepCheckDuration,
} NiceFloDecoderStep;
SubGhzProtocolNiceFlo* subghz_protocol_nice_flo_alloc() { SubGhzProtocolNiceFlo* subghz_protocol_nice_flo_alloc() {
SubGhzProtocolNiceFlo* instance = furi_alloc(sizeof(SubGhzProtocolNiceFlo)); SubGhzProtocolNiceFlo* instance = furi_alloc(sizeof(SubGhzProtocolNiceFlo));
@ -18,11 +25,11 @@ SubGhzProtocolNiceFlo* subghz_protocol_nice_flo_alloc() {
instance->common.te_short = 700; instance->common.te_short = 700;
instance->common.te_long = 1400; instance->common.te_long = 1400;
instance->common.te_delta = 200; instance->common.te_delta = 200;
instance->common.type_protocol = TYPE_PROTOCOL_STATIC; instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nice_flo_to_str; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nice_flo_to_str;
instance->common.to_save_string = instance->common.to_save_string =
(SubGhzProtocolCommonGetStrSave)subghz_protocol_nice_flo_to_save_str; (SubGhzProtocolCommonGetStrSave)subghz_protocol_nice_flo_to_save_str;
instance->common.to_load_protocol_from_file= instance->common.to_load_protocol_from_file =
(SubGhzProtocolCommonLoadFromFile)subghz_protocol_nice_flo_to_load_protocol_from_file; (SubGhzProtocolCommonLoadFromFile)subghz_protocol_nice_flo_to_load_protocol_from_file;
instance->common.to_load_protocol = instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nice_flo_to_load_protocol; (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nice_flo_to_load_protocol;
@ -36,94 +43,105 @@ void subghz_protocol_nice_flo_free(SubGhzProtocolNiceFlo* instance) {
free(instance); free(instance);
} }
bool subghz_protocol_nice_flo_send_key(SubGhzProtocolNiceFlo* instance, SubGhzProtocolCommonEncoder* encoder){ bool subghz_protocol_nice_flo_send_key(
SubGhzProtocolNiceFlo* instance,
SubGhzProtocolCommonEncoder* encoder) {
furi_assert(instance); furi_assert(instance);
furi_assert(encoder); furi_assert(encoder);
size_t index = 0; size_t index = 0;
encoder->size_upload =(instance->common.code_last_count_bit * 2) + 2; encoder->size_upload = (instance->common.code_last_count_bit * 2) + 2;
if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false; if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
//Send header //Send header
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short * 36); encoder->upload[index++] =
level_duration_make(false, (uint32_t)instance->common.te_short * 36);
//Send start bit //Send start bit
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short); encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
//Send key data //Send key data
for (uint8_t i = instance->common.code_last_count_bit; i > 0; i--) { for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
if(bit_read(instance->common.code_last_found, i - 1)){ if(bit_read(instance->common.code_last_found, i - 1)) {
//send bit 1 //send bit 1
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_long); encoder->upload[index++] =
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short); level_duration_make(false, (uint32_t)instance->common.te_long);
}else{ encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_short);
} else {
//send bit 0 //send bit 0
encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short); encoder->upload[index++] =
encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_long); level_duration_make(false, (uint32_t)instance->common.te_short);
encoder->upload[index++] =
level_duration_make(true, (uint32_t)instance->common.te_long);
} }
} }
return true; return true;
} }
void subghz_protocol_nice_flo_reset(SubGhzProtocolNiceFlo* instance) { void subghz_protocol_nice_flo_reset(SubGhzProtocolNiceFlo* instance) {
instance->common.parser_step = 0; instance->common.parser_step = NiceFloDecoderStepReset;
} }
void subghz_protocol_nice_flo_parse(SubGhzProtocolNiceFlo* instance, bool level, uint32_t duration) { 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 NiceFloDecoderStepReset:
if ((!level) if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 36) <
&& (DURATION_DIFF(duration, instance->common.te_short * 36)< instance->common.te_delta * 36)) { instance->common.te_delta * 36)) {
//Found header Nice Flo //Found header Nice Flo
instance->common.parser_step = 1; instance->common.parser_step = NiceFloDecoderStepFoundStartBit;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NiceFloDecoderStepReset;
} }
break; break;
case 1: case NiceFloDecoderStepFoundStartBit:
if (!level) { if(!level) {
break; break;
} else if (DURATION_DIFF(duration, instance->common.te_short)< instance->common.te_delta) { } else if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
//Found start bit Nice Flo //Found start bit Nice Flo
instance->common.parser_step = 2; instance->common.parser_step = NiceFloDecoderStepSaveDuration;
instance->common.code_found = 0; instance->common.code_found = 0;
instance->common.code_count_bit = 0; instance->common.code_count_bit = 0;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NiceFloDecoderStepReset;
} }
break; break;
case 2: case NiceFloDecoderStepSaveDuration:
if (!level) { //save interval if(!level) { //save interval
if (duration >= (instance->common.te_short * 4)) { if(duration >= (instance->common.te_short * 4)) {
instance->common.parser_step = 1; instance->common.parser_step = NiceFloDecoderStepFoundStartBit;
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.serial = 0x0; instance->common.serial = 0x0;
instance->common.btn = 0x0; instance->common.btn = 0x0;
instance->common.code_last_found = instance->common.code_found; instance->common.code_last_found = instance->common.code_found;
instance->common.code_last_count_bit = instance->common.code_count_bit; instance->common.code_last_count_bit = instance->common.code_count_bit;
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 = duration; instance->common.te_last = duration;
instance->common.parser_step = 3; instance->common.parser_step = NiceFloDecoderStepCheckDuration;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NiceFloDecoderStepReset;
} }
break; break;
case 3: case NiceFloDecoderStepCheckDuration:
if (level) { if(level) {
if ((DURATION_DIFF(instance->common.te_last,instance->common.te_short) < instance->common.te_delta) if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
&& (DURATION_DIFF(duration, instance->common.te_long)< instance->common.te_delta)) { 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 = NiceFloDecoderStepSaveDuration;
} else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_long)< instance->common.te_delta) } else if(
&& (DURATION_DIFF(duration, instance->common.te_short)< instance->common.te_delta)) { (DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < 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 = NiceFloDecoderStepSaveDuration;
} else } else
instance->common.parser_step = 0; instance->common.parser_step = NiceFloDecoderStepReset;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NiceFloDecoderStepReset;
} }
break; break;
} }
@ -145,11 +163,9 @@ void subghz_protocol_nice_flo_to_str(SubGhzProtocolNiceFlo* instance, string_t o
instance->common.name, instance->common.name,
instance->common.code_last_count_bit, instance->common.code_last_count_bit,
code_found_lo, code_found_lo,
code_found_reverse_lo code_found_reverse_lo);
);
} }
void subghz_protocol_nice_flo_to_save_str(SubGhzProtocolNiceFlo* instance, string_t output) { void subghz_protocol_nice_flo_to_save_str(SubGhzProtocolNiceFlo* instance, string_t output) {
string_printf( string_printf(
output, output,
@ -161,7 +177,9 @@ void subghz_protocol_nice_flo_to_save_str(SubGhzProtocolNiceFlo* instance, strin
(uint32_t)(instance->common.code_last_found & 0x00000000ffffffff)); (uint32_t)(instance->common.code_last_found & 0x00000000ffffffff));
} }
bool subghz_protocol_nice_flo_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNiceFlo* instance){ bool subghz_protocol_nice_flo_to_load_protocol_from_file(
FileWorker* file_worker,
SubGhzProtocolNiceFlo* instance) {
bool loaded = false; bool loaded = false;
string_t temp_str; string_t temp_str;
string_init(temp_str); string_init(temp_str);
@ -198,9 +216,7 @@ bool subghz_protocol_nice_flo_to_load_protocol_from_file(FileWorker* file_worker
return loaded; return loaded;
} }
void subghz_decoder_nice_flo_to_load_protocol( void subghz_decoder_nice_flo_to_load_protocol(SubGhzProtocolNiceFlo* instance, void* context) {
SubGhzProtocolNiceFlo* instance,
void* context) {
furi_assert(context); furi_assert(context);
furi_assert(instance); furi_assert(instance);
SubGhzProtocolCommonLoad* data = context; SubGhzProtocolCommonLoad* data = context;

View File

@ -13,6 +13,14 @@ struct SubGhzProtocolNiceFlorS {
const char* rainbow_table_file_name; const char* rainbow_table_file_name;
}; };
typedef enum {
NiceFlorSDecoderStepReset = 0,
NiceFlorSDecoderStepCheckHeader,
NiceFlorSDecoderStepFoundHeader,
NiceFlorSDecoderStepSaveDuration,
NiceFlorSDecoderStepCheckDuration,
} NiceFlorSDecoderStep;
SubGhzProtocolNiceFlorS* subghz_protocol_nice_flor_s_alloc() { SubGhzProtocolNiceFlorS* subghz_protocol_nice_flor_s_alloc() {
SubGhzProtocolNiceFlorS* instance = furi_alloc(sizeof(SubGhzProtocolNiceFlorS)); SubGhzProtocolNiceFlorS* instance = furi_alloc(sizeof(SubGhzProtocolNiceFlorS));
@ -21,7 +29,7 @@ SubGhzProtocolNiceFlorS* subghz_protocol_nice_flor_s_alloc() {
instance->common.te_short = 500; instance->common.te_short = 500;
instance->common.te_long = 1000; instance->common.te_long = 1000;
instance->common.te_delta = 300; instance->common.te_delta = 300;
instance->common.type_protocol = TYPE_PROTOCOL_DYNAMIC; instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nice_flor_s_to_str; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nice_flor_s_to_str;
instance->common.to_load_protocol = instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nice_flor_s_to_load_protocol; (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nice_flor_s_to_load_protocol;
@ -93,16 +101,14 @@ void subghz_protocol_nice_flor_s_send_key(
* @return byte data * @return byte data
*/ */
uint8_t subghz_nice_flor_s_get_byte_in_file(SubGhzProtocolNiceFlorS* instance, uint32_t address) { uint8_t subghz_nice_flor_s_get_byte_in_file(SubGhzProtocolNiceFlorS* instance, uint32_t address) {
if(!instance->rainbow_table_file_name) if(!instance->rainbow_table_file_name) return 0;
return 0;
uint8_t buffer = 0; uint8_t buffer = 0;
FileWorker* file_worker = file_worker_alloc(true); FileWorker* file_worker = file_worker_alloc(true);
if(file_worker_open(file_worker, instance->rainbow_table_file_name, FSAM_READ, FSOM_OPEN_EXISTING)) { if(file_worker_open(
file_worker, instance->rainbow_table_file_name, FSAM_READ, FSOM_OPEN_EXISTING)) {
file_worker_seek(file_worker, address, true); file_worker_seek(file_worker, address, true);
file_worker_read(file_worker, &buffer, 1); file_worker_read(file_worker, &buffer, 1);
// bool res = file_worker_read(file_worker, &buffer, 1);
// furi_assert(res== true);
} }
file_worker_close(file_worker); file_worker_close(file_worker);
file_worker_free(file_worker); file_worker_free(file_worker);
@ -134,8 +140,11 @@ void subghz_nice_flor_s_decoder_decrypt(SubGhzProtocolNiceFlorS* instance) {
*/ */
uint16_t p3p4 = (uint16_t)(instance->common.code_last_found >> 24); uint16_t p3p4 = (uint16_t)(instance->common.code_last_found >> 24);
instance->common.cnt = subghz_nice_flor_s_get_byte_in_file(instance,p3p4*2) << 8 | subghz_nice_flor_s_get_byte_in_file(instance,p3p4*2+1); instance->common.cnt = subghz_nice_flor_s_get_byte_in_file(instance, p3p4 * 2) << 8 |
uint8_t k =(uint8_t)(p3p4 & 0x00FF) ^subghz_nice_flor_s_get_byte_in_file(instance,(0x20000 |(instance->common.cnt &0x00ff))); subghz_nice_flor_s_get_byte_in_file(instance, p3p4 * 2 + 1);
uint8_t k =
(uint8_t)(p3p4 & 0x00FF) ^
subghz_nice_flor_s_get_byte_in_file(instance, (0x20000 | (instance->common.cnt & 0x00ff)));
uint8_t s3 = ((uint8_t)(instance->common.code_last_found >> 40) ^ k) & 0x0f; uint8_t s3 = ((uint8_t)(instance->common.code_last_found >> 40) ^ k) & 0x0f;
uint8_t s2 = ((uint8_t)(instance->common.code_last_found >> 16) ^ k); uint8_t s2 = ((uint8_t)(instance->common.code_last_found >> 16) ^ k);
@ -147,73 +156,82 @@ void subghz_nice_flor_s_decoder_decrypt(SubGhzProtocolNiceFlorS* instance) {
} }
void subghz_protocol_nice_flor_s_reset(SubGhzProtocolNiceFlorS* instance) { void subghz_protocol_nice_flor_s_reset(SubGhzProtocolNiceFlorS* instance) {
instance->common.parser_step = 0; instance->common.parser_step = NiceFlorSDecoderStepReset;
} }
void subghz_protocol_nice_flor_s_parse(SubGhzProtocolNiceFlorS* instance, bool level, uint32_t duration) { 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 NiceFlorSDecoderStepReset:
if((!level) if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 38) <
&& (DURATION_DIFF(duration, instance->common.te_short * 38) < instance->common.te_delta * 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 = NiceFlorSDecoderStepCheckHeader;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NiceFlorSDecoderStepReset;
} }
break; break;
case 1: case NiceFlorSDecoderStepCheckHeader:
if((level) if((level) && (DURATION_DIFF(duration, instance->common.te_short * 3) <
&& (DURATION_DIFF(duration, instance->common.te_short * 3) < instance->common.te_delta * 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 = NiceFlorSDecoderStepFoundHeader;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NiceFlorSDecoderStepReset;
} }
break; break;
case 2: case NiceFlorSDecoderStepFoundHeader:
if((!level) if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 3) <
&& (DURATION_DIFF(duration, instance->common.te_short * 3) < instance->common.te_delta * 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 = NiceFlorSDecoderStepSaveDuration;
instance->common.code_found = 0; instance->common.code_found = 0;
instance->common.code_count_bit = 0; instance->common.code_count_bit = 0;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NiceFlorSDecoderStepReset;
} }
break; break;
case 3: case NiceFlorSDecoderStepSaveDuration:
if(level) { if(level) {
if(DURATION_DIFF(duration, instance->common.te_short * 3) < instance->common.te_delta) { if(DURATION_DIFF(duration, instance->common.te_short * 3) <
instance->common.te_delta) {
//Found STOP bit //Found STOP bit
instance->common.parser_step = 0; instance->common.parser_step = NiceFlorSDecoderStepReset;
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_count_bit = instance->common.code_count_bit; instance->common.code_last_count_bit = instance->common.code_count_bit;
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;
} else { } else {
//save interval //save interval
instance->common.te_last = duration; instance->common.te_last = duration;
instance->common.parser_step = 4; instance->common.parser_step = NiceFlorSDecoderStepCheckDuration;
} }
} }
break; break;
case 4: case NiceFlorSDecoderStepCheckDuration:
if(!level) { if(!level) {
if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) < instance->common.te_delta) if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
&&(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta)) { 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 = NiceFlorSDecoderStepSaveDuration;
} 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) <
&&(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) { instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < 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 = NiceFlorSDecoderStepSaveDuration;
} else } else
instance->common.parser_step = 0; instance->common.parser_step = NiceFlorSDecoderStepReset;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = NiceFlorSDecoderStepReset;
} }
break; break;
} }
@ -236,13 +254,10 @@ void subghz_protocol_nice_flor_s_to_str(SubGhzProtocolNiceFlorS* instance, strin
code_found_lo, code_found_lo,
instance->common.serial, instance->common.serial,
instance->common.cnt, instance->common.cnt,
instance->common.btn instance->common.btn);
);
} }
void subghz_decoder_nice_flor_s_to_load_protocol( void subghz_decoder_nice_flor_s_to_load_protocol(SubGhzProtocolNiceFlorS* instance, void* context) {
SubGhzProtocolNiceFlorS* instance,
void* context) {
furi_assert(context); furi_assert(context);
furi_assert(instance); furi_assert(instance);
SubGhzProtocolCommonLoad* data = context; SubGhzProtocolCommonLoad* data = context;

View File

@ -16,6 +16,12 @@ struct SubGhzEncoderPrinceton {
size_t front; size_t front;
}; };
typedef enum {
PrincetonDecoderStepReset = 0,
PrincetonDecoderStepSaveDuration,
PrincetonDecoderStepCheckDuration,
} PrincetonDecoderStep;
SubGhzEncoderPrinceton* subghz_encoder_princeton_alloc() { SubGhzEncoderPrinceton* subghz_encoder_princeton_alloc() {
SubGhzEncoderPrinceton* instance = furi_alloc(sizeof(SubGhzEncoderPrinceton)); SubGhzEncoderPrinceton* instance = furi_alloc(sizeof(SubGhzEncoderPrinceton));
return instance; return instance;
@ -87,7 +93,7 @@ SubGhzDecoderPrinceton* subghz_decoder_princeton_alloc(void) {
instance->common.te_short = SUBGHZ_PT_SHORT; //150; instance->common.te_short = SUBGHZ_PT_SHORT; //150;
instance->common.te_long = SUBGHZ_PT_LONG; //450; instance->common.te_long = SUBGHZ_PT_LONG; //450;
instance->common.te_delta = 250; //50; instance->common.te_delta = 250; //50;
instance->common.type_protocol = TYPE_PROTOCOL_STATIC; instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_decoder_princeton_to_str; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_decoder_princeton_to_str;
instance->common.to_save_string = instance->common.to_save_string =
(SubGhzProtocolCommonGetStrSave)subghz_decoder_princeton_to_save_str; (SubGhzProtocolCommonGetStrSave)subghz_decoder_princeton_to_save_str;
@ -142,7 +148,7 @@ bool subghz_protocol_princeton_send_key(
} }
void subghz_decoder_princeton_reset(SubGhzDecoderPrinceton* instance) { void subghz_decoder_princeton_reset(SubGhzDecoderPrinceton* instance) {
instance->common.parser_step = 0; instance->common.parser_step = PrincetonDecoderStepReset;
} }
void subghz_decoder_princeton_parse( void subghz_decoder_princeton_parse(
@ -150,28 +156,28 @@ void subghz_decoder_princeton_parse(
bool level, bool level,
uint32_t duration) { uint32_t duration) {
switch(instance->common.parser_step) { switch(instance->common.parser_step) {
case 0: case PrincetonDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 36) < if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 36) <
instance->common.te_delta * 36)) { instance->common.te_delta * 36)) {
//Found Preambula //Found Preambula
instance->common.parser_step = 1; instance->common.parser_step = PrincetonDecoderStepSaveDuration;
instance->common.code_found = 0; instance->common.code_found = 0;
instance->common.code_count_bit = 0; instance->common.code_count_bit = 0;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = PrincetonDecoderStepReset;
} }
break; break;
case 1: case PrincetonDecoderStepSaveDuration:
//save duration //save duration
if(level) { if(level) {
instance->common.te_last = duration; instance->common.te_last = duration;
instance->common.parser_step = 2; instance->common.parser_step = PrincetonDecoderStepCheckDuration;
} }
break; break;
case 2: case PrincetonDecoderStepCheckDuration:
if(!level) { if(!level) {
if(duration >= (instance->common.te_short * 10 + instance->common.te_delta)) { if(duration >= (instance->common.te_short * 10 + instance->common.te_delta)) {
instance->common.parser_step = 1; instance->common.parser_step = PrincetonDecoderStepSaveDuration;
if(instance->common.code_count_bit == if(instance->common.code_count_bit ==
instance->common.code_min_count_bit_for_found) { instance->common.code_min_count_bit_for_found) {
if(instance->common.code_last_found == instance->common.code_found) { if(instance->common.code_last_found == instance->common.code_found) {
@ -201,18 +207,18 @@ void subghz_decoder_princeton_parse(
(DURATION_DIFF(duration, instance->common.te_long) < (DURATION_DIFF(duration, instance->common.te_long) <
instance->common.te_delta * 3)) { 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 = PrincetonDecoderStepSaveDuration;
} else if( } else if(
(DURATION_DIFF(instance->common.te_last, instance->common.te_long) < (DURATION_DIFF(instance->common.te_last, instance->common.te_long) <
instance->common.te_delta * 3) && instance->common.te_delta * 3) &&
(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) { (DURATION_DIFF(duration, instance->common.te_short) < 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 = PrincetonDecoderStepSaveDuration;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = PrincetonDecoderStepReset;
} }
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = PrincetonDecoderStepReset;
} }
break; break;
} }
@ -306,9 +312,7 @@ bool subghz_decoder_princeton_to_load_protocol_from_file(
return loaded; return loaded;
} }
void subghz_decoder_princeton_to_load_protocol( void subghz_decoder_princeton_to_load_protocol(SubGhzDecoderPrinceton* instance, void* context) {
SubGhzDecoderPrinceton* instance,
void* context) {
furi_assert(context); furi_assert(context);
furi_assert(instance); furi_assert(instance);
SubGhzProtocolCommonLoad* data = context; SubGhzProtocolCommonLoad* data = context;

View File

@ -8,24 +8,30 @@
#include <m-string.h> #include <m-string.h>
#include <m-array.h> #include <m-array.h>
struct SubGhzProtocolStarLine { struct SubGhzProtocolStarLine {
SubGhzProtocolCommon common; SubGhzProtocolCommon common;
SubGhzKeystore* keystore; SubGhzKeystore* keystore;
const char* manufacture_name; const char* manufacture_name;
}; };
typedef enum {
StarLineDecoderStepReset = 0,
StarLineDecoderStepCheckPreambula,
StarLineDecoderStepSaveDuration,
StarLineDecoderStepCheckDuration,
} StarLineDecoderStep;
SubGhzProtocolStarLine* subghz_protocol_star_line_alloc(SubGhzKeystore* keystore) { SubGhzProtocolStarLine* subghz_protocol_star_line_alloc(SubGhzKeystore* keystore) {
SubGhzProtocolStarLine* instance = furi_alloc(sizeof(SubGhzProtocolStarLine)); SubGhzProtocolStarLine* instance = furi_alloc(sizeof(SubGhzProtocolStarLine));
instance->keystore = keystore; instance->keystore = keystore;
instance->common.name = "Star Line"; instance->common.name = "Star Line";
instance->common.code_min_count_bit_for_found = 64; instance->common.code_min_count_bit_for_found = 64;
instance->common.te_short = 250; instance->common.te_short = 250;
instance->common.te_long = 500; instance->common.te_long = 500;
instance->common.te_delta = 120; instance->common.te_delta = 120;
instance->common.type_protocol = TYPE_PROTOCOL_DYNAMIC; instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_star_line_to_str; instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_star_line_to_str;
instance->common.to_load_protocol = instance->common.to_load_protocol =
(SubGhzProtocolCommonLoadFromRAW)subghz_decoder_star_line_to_load_protocol; (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_star_line_to_load_protocol;
@ -38,13 +44,13 @@ void subghz_protocol_star_line_free(SubGhzProtocolStarLine* instance) {
free(instance); free(instance);
} }
const char* subghz_protocol_star_line_find_and_get_manufacture_name (void* context){ const char* subghz_protocol_star_line_find_and_get_manufacture_name(void* context) {
SubGhzProtocolStarLine* instance = context; SubGhzProtocolStarLine* instance = context;
subghz_protocol_star_line_check_remote_controller(instance); subghz_protocol_star_line_check_remote_controller(instance);
return instance->manufacture_name; return instance->manufacture_name;
} }
const char* subghz_protocol_star_line_get_manufacture_name (void* context){ const char* subghz_protocol_star_line_get_manufacture_name(void* context) {
SubGhzProtocolStarLine* instance = context; SubGhzProtocolStarLine* instance = context;
return instance->manufacture_name; return instance->manufacture_name;
} }
@ -55,7 +61,7 @@ const char* subghz_protocol_star_line_get_manufacture_name (void* context){
* @param bit - bit * @param bit - bit
*/ */
void subghz_protocol_star_line_send_bit(SubGhzProtocolStarLine* instance, uint8_t bit) { void subghz_protocol_star_line_send_bit(SubGhzProtocolStarLine* instance, uint8_t bit) {
if (bit) { if(bit) {
//send bit 1 //send bit 1
SUBGHZ_TX_PIN_HIGH(); SUBGHZ_TX_PIN_HIGH();
delay_us(instance->common.te_long); delay_us(instance->common.te_long);
@ -70,18 +76,22 @@ void subghz_protocol_star_line_send_bit(SubGhzProtocolStarLine* instance, uint8_
} }
} }
void subghz_protocol_star_line_send_key(SubGhzProtocolStarLine* instance, uint64_t key, uint8_t bit,uint8_t repeat) { void subghz_protocol_star_line_send_key(
while (repeat--) { SubGhzProtocolStarLine* instance,
uint64_t key,
uint8_t bit,
uint8_t repeat) {
while(repeat--) {
//Send header //Send header
for(uint8_t i = 0; i < 6; i++){ for(uint8_t i = 0; i < 6; i++) {
SUBGHZ_TX_PIN_HIGH(); SUBGHZ_TX_PIN_HIGH();
delay_us(instance->common.te_long * 2); delay_us(instance->common.te_long * 2);
SUBGHZ_TX_PIN_LOW(); SUBGHZ_TX_PIN_LOW();
delay_us(instance->common.te_long * 2); delay_us(instance->common.te_long * 2);
} }
//Send Start bit ?????????? //Send Start bit ??????????
//Send key data //Send key data
for (uint8_t i = bit; i > 0; i--) { for(uint8_t i = bit; i > 0; i--) {
subghz_protocol_star_line_send_bit(instance, bit_read(key, i - 1)); subghz_protocol_star_line_send_bit(instance, bit_read(key, i - 1));
} }
//Send Stop bit ?????????? //Send Stop bit ??????????
@ -89,7 +99,7 @@ void subghz_protocol_star_line_send_key(SubGhzProtocolStarLine* instance, uint64
} }
void subghz_protocol_star_line_reset(SubGhzProtocolStarLine* instance) { void subghz_protocol_star_line_reset(SubGhzProtocolStarLine* instance) {
instance->common.parser_step = 0; instance->common.parser_step = StarLineDecoderStepReset;
} }
/** Checking the accepted code against the database manafacture key /** Checking the accepted code against the database manafacture key
@ -99,86 +109,97 @@ void subghz_protocol_star_line_reset(SubGhzProtocolStarLine* instance) {
* @param hop hop encrypted part of the parcel * @param hop hop encrypted part of the parcel
* @return true on successful search * @return true on successful search
*/ */
uint8_t subghz_protocol_star_line_check_remote_controller_selector(SubGhzProtocolStarLine* instance, uint32_t fix , uint32_t hop) { uint8_t subghz_protocol_star_line_check_remote_controller_selector(
uint16_t end_serial = (uint16_t)(fix&0xFF); SubGhzProtocolStarLine* instance,
uint8_t btn = (uint8_t)(fix>>24); uint32_t fix,
uint32_t hop) {
uint16_t end_serial = (uint16_t)(fix & 0xFF);
uint8_t btn = (uint8_t)(fix >> 24);
uint32_t decrypt = 0; uint32_t decrypt = 0;
uint64_t man_normal_learning; uint64_t man_normal_learning;
for for
M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
switch (manufacture_code->type){ switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE: case KEELOQ_LEARNING_SIMPLE:
//Simple Learning //Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if((decrypt>>24 == btn) && ((((uint16_t)(decrypt>>16)) & 0x00FF) == end_serial)){ if((decrypt >> 24 == btn) &&
instance->manufacture_name = string_get_cstr(manufacture_code->name); ((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) {
instance->common.cnt = decrypt & 0x0000FFFF; instance->manufacture_name = string_get_cstr(manufacture_code->name);
return 1; instance->common.cnt = decrypt & 0x0000FFFF;
} return 1;
}
break; break;
case KEELOQ_LEARNING_NORMAL: case KEELOQ_LEARNING_NORMAL:
// Normal_Learning // Normal_Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37 // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); man_normal_learning =
decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
if( (decrypt>>24 ==btn)&& ((((uint16_t)(decrypt>>16))&0x00FF)==end_serial)){ decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
instance->manufacture_name = string_get_cstr(manufacture_code->name); if((decrypt >> 24 == btn) &&
instance->common.cnt = decrypt & 0x0000FFFF; ((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) {
return 1; instance->manufacture_name = string_get_cstr(manufacture_code->name);
} instance->common.cnt = decrypt & 0x0000FFFF;
return 1;
}
break; break;
case KEELOQ_LEARNING_UNKNOWN: case KEELOQ_LEARNING_UNKNOWN:
// Simple Learning // Simple Learning
decrypt=subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if( (decrypt>>24 ==btn) && ((((uint16_t)(decrypt>>16))&0x00FF)==end_serial)){ if((decrypt >> 24 == btn) &&
instance->manufacture_name = string_get_cstr(manufacture_code->name); ((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) {
instance->common.cnt = decrypt & 0x0000FFFF; instance->manufacture_name = string_get_cstr(manufacture_code->name);
return 1; instance->common.cnt = decrypt & 0x0000FFFF;
} return 1;
// Check for mirrored man }
uint64_t man_rev=0; // Check for mirrored man
uint64_t man_rev_byte=0; uint64_t man_rev = 0;
for(uint8_t i=0; i<64; i+=8){ uint64_t man_rev_byte = 0;
man_rev_byte=(uint8_t)(manufacture_code->key >> i); for(uint8_t i = 0; i < 64; i += 8) {
man_rev = man_rev | man_rev_byte << (56-i); man_rev_byte = (uint8_t)(manufacture_code->key >> i);
} man_rev = man_rev | man_rev_byte << (56 - i);
decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_rev); }
if( (decrypt>>24 ==btn) && ((((uint16_t)(decrypt>>16))&0x00FF)==end_serial)){ decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev);
instance->manufacture_name = string_get_cstr(manufacture_code->name); if((decrypt >> 24 == btn) &&
instance->common.cnt= decrypt&0x0000FFFF; ((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) {
return 1; instance->manufacture_name = string_get_cstr(manufacture_code->name);
} instance->common.cnt = decrypt & 0x0000FFFF;
//########################### return 1;
// Normal_Learning }
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37 //###########################
man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); // Normal_Learning
decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
if( (decrypt>>24 ==btn)&& ((((uint16_t)(decrypt>>16))&0x00FF)==end_serial)){ man_normal_learning =
instance->manufacture_name = string_get_cstr(manufacture_code->name); subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
instance->common.cnt= decrypt&0x0000FFFF; decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
return 1; if((decrypt >> 24 == btn) &&
} ((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) {
// Check for mirrored man instance->manufacture_name = string_get_cstr(manufacture_code->name);
man_rev=0; instance->common.cnt = decrypt & 0x0000FFFF;
man_rev_byte=0; return 1;
for(uint8_t i=0; i<64; i+=8){ }
man_rev_byte = (uint8_t)(manufacture_code->key >> i); // Check for mirrored man
man_rev = man_rev | man_rev_byte << (56-i); man_rev = 0;
} man_rev_byte = 0;
man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev); for(uint8_t i = 0; i < 64; i += 8) {
decrypt=subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning); man_rev_byte = (uint8_t)(manufacture_code->key >> i);
if( (decrypt>>24 ==btn) && ((((uint16_t)(decrypt>>16))&0x00FF)==end_serial)){ man_rev = man_rev | man_rev_byte << (56 - i);
instance->manufacture_name = string_get_cstr(manufacture_code->name); }
instance->common.cnt= decrypt&0x0000FFFF; man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev);
return 1; decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
} if((decrypt >> 24 == btn) &&
((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) {
instance->manufacture_name = string_get_cstr(manufacture_code->name);
instance->common.cnt = decrypt & 0x0000FFFF;
return 1;
}
break; break;
} }
} }
instance->manufacture_name = "Unknown"; instance->manufacture_name = "Unknown";
instance->common.cnt=0; instance->common.cnt = 0;
return 0; return 0;
} }
@ -188,53 +209,61 @@ uint8_t subghz_protocol_star_line_check_remote_controller_selector(SubGhzProtoco
* @param instance SubGhzProtocolStarLine instance * @param instance SubGhzProtocolStarLine instance
*/ */
void subghz_protocol_star_line_check_remote_controller(SubGhzProtocolStarLine* instance) { void subghz_protocol_star_line_check_remote_controller(SubGhzProtocolStarLine* instance) {
uint64_t key = subghz_protocol_common_reverse_key(instance->common.code_last_found, instance->common.code_last_count_bit); uint64_t key = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t key_fix = key >> 32; uint32_t key_fix = key >> 32;
uint32_t key_hop = key & 0x00000000ffffffff; uint32_t key_hop = key & 0x00000000ffffffff;
subghz_protocol_star_line_check_remote_controller_selector(instance, key_fix, key_hop); subghz_protocol_star_line_check_remote_controller_selector(instance, key_fix, key_hop);
instance ->common.serial= key_fix&0x00FFFFFF; instance->common.serial = key_fix & 0x00FFFFFF;
instance->common.btn = key_fix >> 24; instance->common.btn = key_fix >> 24;
} }
void subghz_protocol_star_line_parse(SubGhzProtocolStarLine* instance, bool level, uint32_t duration) { void subghz_protocol_star_line_parse(
switch (instance->common.parser_step) { SubGhzProtocolStarLine* instance,
case 0: bool level,
if (level){ uint32_t duration) {
if(DURATION_DIFF(duration,instance->common.te_long * 2)< instance->common.te_delta * 2) { switch(instance->common.parser_step) {
instance->common.parser_step = 1; case StarLineDecoderStepReset:
if(level) {
if(DURATION_DIFF(duration, instance->common.te_long * 2) <
instance->common.te_delta * 2) {
instance->common.parser_step = StarLineDecoderStepCheckPreambula;
instance->common.header_count++; instance->common.header_count++;
} else if(instance->common.header_count>4){ } else if(instance->common.header_count > 4) {
instance->common.code_found = 0; instance->common.code_found = 0;
instance->common.code_count_bit = 0; instance->common.code_count_bit = 0;
instance->common.te_last = duration; instance->common.te_last = duration;
instance->common.parser_step = 3; instance->common.parser_step = StarLineDecoderStepCheckDuration;
} }
}else{ } else {
instance->common.parser_step = 0; instance->common.parser_step = StarLineDecoderStepReset;
instance->common.header_count = 0; instance->common.header_count = 0;
} }
break; break;
case 1: case StarLineDecoderStepCheckPreambula:
if ((!level) if((!level) && (DURATION_DIFF(duration, instance->common.te_long * 2) <
&& (DURATION_DIFF(duration,instance->common.te_long * 2)< instance->common.te_delta * 2)) { instance->common.te_delta * 2)) {
//Found Preambula //Found Preambula
instance->common.parser_step = 0; instance->common.parser_step = StarLineDecoderStepReset;
} else { } else {
instance->common.header_count = 0; instance->common.header_count = 0;
instance->common.parser_step = 0; instance->common.parser_step = StarLineDecoderStepReset;
} }
break; break;
case 2: case StarLineDecoderStepSaveDuration:
if (level) { if(level) {
if (duration >= (instance->common.te_long + instance->common.te_delta)) { if(duration >= (instance->common.te_long + instance->common.te_delta)) {
instance->common.parser_step = 0; instance->common.parser_step = StarLineDecoderStepReset;
if (instance->common.code_count_bit>= instance->common.code_min_count_bit_for_found) { if(instance->common.code_count_bit >=
if(instance->common.code_last_found != instance->common.code_found){ instance->common.code_min_count_bit_for_found) {
if(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;
instance->common.code_last_count_bit = instance->common.code_count_bit; instance->common.code_last_count_bit = instance->common.code_count_bit;
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;
@ -243,28 +272,31 @@ void subghz_protocol_star_line_parse(SubGhzProtocolStarLine* instance, bool leve
break; break;
} else { } else {
instance->common.te_last = duration; instance->common.te_last = duration;
instance->common.parser_step = 3; instance->common.parser_step = StarLineDecoderStepCheckDuration;
} }
}else{ } else {
instance->common.parser_step = 0; instance->common.parser_step = StarLineDecoderStepReset;
} }
break; break;
case 3: case StarLineDecoderStepCheckDuration:
if(!level){ if(!level) {
if ((DURATION_DIFF(instance->common.te_last,instance->common.te_short)< instance->common.te_delta) if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
&& (DURATION_DIFF(duration,instance->common.te_short)< instance->common.te_delta)) { instance->common.te_delta) &&
(DURATION_DIFF(duration, instance->common.te_short) < 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 = StarLineDecoderStepSaveDuration;
} else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_long )< instance->common.te_delta) } else if(
&& (DURATION_DIFF(duration,instance->common.te_long)< instance->common.te_delta)) { (DURATION_DIFF(instance->common.te_last, 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, 1); subghz_protocol_common_add_bit(&instance->common, 1);
instance->common.parser_step = 2; instance->common.parser_step = StarLineDecoderStepSaveDuration;
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = StarLineDecoderStepReset;
} }
} else { } else {
instance->common.parser_step = 0; instance->common.parser_step = StarLineDecoderStepReset;
} }
break; break;
} }
@ -275,10 +307,11 @@ void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t
uint32_t code_found_hi = instance->common.code_last_found >> 32; uint32_t code_found_hi = instance->common.code_last_found >> 32;
uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff; uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_last_found, instance->common.code_last_count_bit); uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
instance->common.code_last_found, instance->common.code_last_count_bit);
uint32_t code_found_reverse_hi = code_found_reverse>>32; uint32_t code_found_reverse_hi = code_found_reverse >> 32;
uint32_t code_found_reverse_lo = code_found_reverse&0x00000000ffffffff; uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
string_cat_printf( string_cat_printf(
output, output,
"%s %dbit\r\n" "%s %dbit\r\n"
@ -296,13 +329,10 @@ void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t
code_found_reverse_lo, code_found_reverse_lo,
instance->common.btn, instance->common.btn,
instance->manufacture_name, instance->manufacture_name,
instance->common.serial instance->common.serial);
);
} }
void subghz_decoder_star_line_to_load_protocol( void subghz_decoder_star_line_to_load_protocol(SubGhzProtocolStarLine* instance, void* context) {
SubGhzProtocolStarLine* instance,
void* context) {
furi_assert(context); furi_assert(context);
furi_assert(instance); furi_assert(instance);
SubGhzProtocolCommonLoad* data = context; SubGhzProtocolCommonLoad* data = context;

View File

@ -1,18 +1,19 @@
#include "subghz_protocol.h"
#include "subghz_protocol_came.h"
#include "subghz_protocol_cfm.h"
#include "subghz_protocol_keeloq.h"
#include "subghz_protocol_nice_flo.h"
#include "subghz_protocol_nice_flor_s.h"
#include "subghz_protocol_princeton.h"
#include "subghz_protocol_gate_tx.h"
#include "subghz_protocol_ido.h"
#include "subghz_protocol_faac_slh.h"
#include "subghz_protocol_nero_sketch.h"
#include "subghz_protocol_star_line.h"
#include "subghz_protocol_nero_radio.h"
#include "../subghz_keystore.h" #include "subghz_parser.h"
#include "protocols/subghz_protocol_came.h"
#include "protocols/subghz_protocol_cfm.h"
#include "protocols/subghz_protocol_keeloq.h"
#include "protocols/subghz_protocol_nice_flo.h"
#include "protocols/subghz_protocol_nice_flor_s.h"
#include "protocols/subghz_protocol_princeton.h"
#include "protocols/subghz_protocol_gate_tx.h"
#include "protocols/subghz_protocol_ido.h"
#include "protocols/subghz_protocol_faac_slh.h"
#include "protocols/subghz_protocol_nero_sketch.h"
#include "protocols/subghz_protocol_star_line.h"
#include "protocols/subghz_protocol_nero_radio.h"
#include "subghz_keystore.h"
#include <furi.h> #include <furi.h>
#include <m-string.h> #include <m-string.h>
@ -33,7 +34,7 @@ typedef enum {
SubGhzProtocolTypeMax, SubGhzProtocolTypeMax,
} SubGhzProtocolType; } SubGhzProtocolType;
struct SubGhzProtocol { struct SubGhzParser {
SubGhzKeystore* keystore; SubGhzKeystore* keystore;
SubGhzProtocolCommon* protocols[SubGhzProtocolTypeMax]; SubGhzProtocolCommon* protocols[SubGhzProtocolTypeMax];
@ -44,8 +45,8 @@ struct SubGhzProtocol {
void* parser_callback_context; void* parser_callback_context;
}; };
static void subghz_protocol_text_rx_callback(SubGhzProtocolCommon* parser, void* context) { static void subghz_parser_text_rx_callback(SubGhzProtocolCommon* parser, void* context) {
SubGhzProtocol* instance = context; SubGhzParser* instance = context;
string_t output; string_t output;
string_init(output); string_init(output);
@ -58,15 +59,15 @@ static void subghz_protocol_text_rx_callback(SubGhzProtocolCommon* parser, void*
string_clear(output); string_clear(output);
} }
static void subghz_protocol_parser_rx_callback(SubGhzProtocolCommon* parser, void* context) { static void subghz_parser_parser_rx_callback(SubGhzProtocolCommon* parser, void* context) {
SubGhzProtocol* instance = context; SubGhzParser* instance = context;
if(instance->parser_callback) { if(instance->parser_callback) {
instance->parser_callback(parser, instance->parser_callback_context); instance->parser_callback(parser, instance->parser_callback_context);
} }
} }
SubGhzProtocol* subghz_protocol_alloc() { SubGhzParser* subghz_parser_alloc() {
SubGhzProtocol* instance = furi_alloc(sizeof(SubGhzProtocol)); SubGhzParser* instance = furi_alloc(sizeof(SubGhzParser));
instance->keystore = subghz_keystore_alloc(); instance->keystore = subghz_keystore_alloc();
@ -96,7 +97,7 @@ SubGhzProtocol* subghz_protocol_alloc() {
return instance; return instance;
} }
void subghz_protocol_free(SubGhzProtocol* instance) { void subghz_parser_free(SubGhzParser* instance) {
furi_assert(instance); furi_assert(instance);
subghz_protocol_came_free((SubGhzProtocolCame*)instance->protocols[SubGhzProtocolTypeCame]); subghz_protocol_came_free((SubGhzProtocolCame*)instance->protocols[SubGhzProtocolTypeCame]);
@ -125,7 +126,7 @@ void subghz_protocol_free(SubGhzProtocol* instance) {
free(instance); free(instance);
} }
SubGhzProtocolCommon* subghz_protocol_get_by_name(SubGhzProtocol* instance, const char* name) { SubGhzProtocolCommon* subghz_parser_get_by_name(SubGhzParser* instance, const char* name) {
SubGhzProtocolCommon* result = NULL; SubGhzProtocolCommon* result = NULL;
for(size_t i = 0; i < SubGhzProtocolTypeMax; i++) { for(size_t i = 0; i < SubGhzProtocolTypeMax; i++) {
@ -138,46 +139,46 @@ SubGhzProtocolCommon* subghz_protocol_get_by_name(SubGhzProtocol* instance, cons
return result; return result;
} }
void subghz_protocol_enable_dump_text( void subghz_parser_enable_dump_text(
SubGhzProtocol* instance, SubGhzParser* instance,
SubGhzProtocolTextCallback callback, SubGhzProtocolTextCallback callback,
void* context) { void* context) {
furi_assert(instance); furi_assert(instance);
for(size_t i = 0; i < SubGhzProtocolTypeMax; i++) { for(size_t i = 0; i < SubGhzProtocolTypeMax; i++) {
subghz_protocol_common_set_callback( subghz_protocol_common_set_callback(
instance->protocols[i], subghz_protocol_text_rx_callback, instance); instance->protocols[i], subghz_parser_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( void subghz_parser_enable_dump(
SubGhzProtocol* instance, SubGhzParser* instance,
SubGhzProtocolCommonCallbackDump callback, SubGhzProtocolCommonCallbackDump callback,
void* context) { void* context) {
furi_assert(instance); furi_assert(instance);
for(size_t i = 0; i < SubGhzProtocolTypeMax; i++) { for(size_t i = 0; i < SubGhzProtocolTypeMax; i++) {
subghz_protocol_common_set_callback( subghz_protocol_common_set_callback(
instance->protocols[i], subghz_protocol_parser_rx_callback, instance); instance->protocols[i], subghz_parser_parser_rx_callback, instance);
} }
instance->parser_callback = callback; instance->parser_callback = callback;
instance->parser_callback_context = context; instance->parser_callback_context = context;
} }
void subghz_protocol_load_nice_flor_s_file(SubGhzProtocol* instance, const char* file_name) { void subghz_parser_load_nice_flor_s_file(SubGhzParser* instance, const char* file_name) {
subghz_protocol_nice_flor_s_name_file( subghz_protocol_nice_flor_s_name_file(
(SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS], file_name); (SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS], file_name);
} }
void subghz_protocol_load_keeloq_file(SubGhzProtocol* instance, const char* file_name) { void subghz_parser_load_keeloq_file(SubGhzParser* instance, const char* file_name) {
subghz_keystore_load(instance->keystore, file_name); subghz_keystore_load(instance->keystore, file_name);
} }
void subghz_protocol_reset(SubGhzProtocol* instance) { void subghz_parser_reset(SubGhzParser* instance) {
subghz_protocol_came_reset((SubGhzProtocolCame*)instance->protocols[SubGhzProtocolTypeCame]); subghz_protocol_came_reset((SubGhzProtocolCame*)instance->protocols[SubGhzProtocolTypeCame]);
subghz_protocol_keeloq_reset( subghz_protocol_keeloq_reset(
(SubGhzProtocolKeeloq*)instance->protocols[SubGhzProtocolTypeKeeloq]); (SubGhzProtocolKeeloq*)instance->protocols[SubGhzProtocolTypeKeeloq]);
@ -200,7 +201,7 @@ void subghz_protocol_reset(SubGhzProtocol* instance) {
(SubGhzProtocolNeroRadio*)instance->protocols[SubGhzProtocolTypeNeroRadio]); (SubGhzProtocolNeroRadio*)instance->protocols[SubGhzProtocolTypeNeroRadio]);
} }
void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t duration) { void subghz_parser_parse(SubGhzParser* instance, bool level, uint32_t duration) {
subghz_protocol_came_parse( subghz_protocol_came_parse(
(SubGhzProtocolCame*)instance->protocols[SubGhzProtocolTypeCame], level, duration); (SubGhzProtocolCame*)instance->protocols[SubGhzProtocolTypeCame], level, duration);
subghz_protocol_keeloq_parse( subghz_protocol_keeloq_parse(

View File

@ -0,0 +1,72 @@
#pragma once
#include "protocols/subghz_protocol_common.h"
typedef void (*SubGhzProtocolTextCallback)(string_t text, void* context);
typedef void (*SubGhzProtocolCommonCallbackDump)(SubGhzProtocolCommon *parser, void* context);
typedef struct SubGhzParser SubGhzParser;
/** Allocate SubGhzParser
*
* @return SubGhzParser*
*/
SubGhzParser* subghz_parser_alloc();
/** Free SubGhzParser
*
* @param instance
*/
void subghz_parser_free(SubGhzParser* instance);
/** Get protocol by name
*
* @param instance - SubGhzParser instance
* @param name - name protocol
* @param SubGhzProtocolCommon
*/
SubGhzProtocolCommon* subghz_parser_get_by_name(SubGhzParser* instance, const char* name);
/** Outputting data text from all parsers
*
* @param instance - SubGhzParser instance
* @param callback - SubGhzProtocolTextCallback callback
* @param context
*/
void subghz_parser_enable_dump_text(SubGhzParser* instance, SubGhzProtocolTextCallback callback, void* context);
/** Outputting data SubGhzParser from all parsers
*
* @param instance - SubGhzParser instance
* @param callback - SubGhzProtocolTextCallback callback
* @param context
*/
void subghz_parser_enable_dump(SubGhzParser* instance, SubGhzProtocolCommonCallbackDump callback, void* context);
/** File name rainbow table Nice Flor-S
*
* @param instance - SubGhzParser instance
* @param file_name - "path/file_name"
*/
void subghz_parser_load_nice_flor_s_file(SubGhzParser* instance, const char* file_name);
/** File upload manufacture keys
*
* @param instance - SubGhzParser instance
* @param file_name - "path/file_name"
*/
void subghz_parser_load_keeloq_file(SubGhzParser* instance, const char* file_name);
/** Restarting all parsers
*
* @param instance - SubGhzParser instance
*/
void subghz_parser_reset(SubGhzParser* instance);
/** Loading data into all parsers
*
* @param instance - SubGhzParser instance
* @param level - true is high, false if low
* @param duration - level duration in microseconds
*/
void subghz_parser_parse(SubGhzParser* instance, bool level, uint32_t duration);