[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:
		
							parent
							
								
									72ca76097a
								
							
						
					
					
						commit
						8fd411097e
					
				| @ -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( | ||||||
|  | |||||||
| @ -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, | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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, | ||||||
|  | |||||||
| @ -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; | ||||||
| @ -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) { | ||||||
|  | |||||||
| @ -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) { | ||||||
|  | |||||||
| @ -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) { | ||||||
|  | |||||||
| @ -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); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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: | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
| @ -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) { | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
| @ -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); | ||||||
| } | } | ||||||
|  | |||||||
| @ -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); |  | ||||||
|  | |||||||
| @ -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; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
| @ -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(); | ||||||
|  | |||||||
| @ -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(); | ||||||
|  | |||||||
| @ -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); |  | ||||||
| @ -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; | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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( | ||||||
							
								
								
									
										72
									
								
								lib/subghz/subghz_parser.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								lib/subghz/subghz_parser.h
									
									
									
									
									
										Normal 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); | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Skorpionm
						Skorpionm