[FL-2230] SubGhz: protocol API refactoring (#969)
* SubGhz: protocols library refactoring * SubGhz: new architecture and refactoring * SubGhz: simplify protocol structure, remove unused types * SubGhz: rename Subghz to SubGhz * SubGhz: add environment concept Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com> Co-authored-by: DrZlo13 <who.just.the.doctor@gmail.com>
This commit is contained in:
		
							parent
							
								
									052237f8c9
								
							
						
					
					
						commit
						3164184bbc
					
				| @ -58,7 +58,7 @@ Examples: | |||||||
| 
 | 
 | ||||||
| 	FuriHalUsb | 	FuriHalUsb | ||||||
| 	Gui | 	Gui | ||||||
| 	SubghzKeystore | 	SubGhzKeystore | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ### Functions are snake_case | ### Functions are snake_case | ||||||
| @ -73,8 +73,8 @@ This rule makes easier to locate types, functions and sources. | |||||||
| 
 | 
 | ||||||
| For example: | For example: | ||||||
| 
 | 
 | ||||||
| We have abstraction that we call `Subghz Keystore`, so there will be: | We have abstraction that we call `SubGhz Keystore`, so there will be: | ||||||
| file `subghz_keystore.h` we have type `SubghzKeystore` and function `subghz_keystore_read`. | file `subghz_keystore.h` we have type `SubGhzKeystore` and function `subghz_keystore_read`. | ||||||
| 
 | 
 | ||||||
| ### File names | ### File names | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								Makefile
									
									
									
									
									
								
							| @ -121,3 +121,8 @@ lint: | |||||||
| format: | format: | ||||||
| 	@echo "Reformating sources code" | 	@echo "Reformating sources code" | ||||||
| 	@$(PROJECT_ROOT)/scripts/lint.py format $(PROJECT_SOURCE_DIRECTORIES) | 	@$(PROJECT_ROOT)/scripts/lint.py format $(PROJECT_SOURCE_DIRECTORIES) | ||||||
|  | 
 | ||||||
|  | .PHONY: guruguru | ||||||
|  | guruguru: | ||||||
|  | 	@echo "ぐるぐる回る" | ||||||
|  | 	@$(PROJECT_ROOT)/scripts/guruguru.py $(PROJECT_ROOT) | ||||||
|  | |||||||
| @ -30,7 +30,7 @@ | |||||||
| - `snake_game`          - Snake game application | - `snake_game`          - Snake game application | ||||||
| - `storage`             - Storage service, internal + sdcard | - `storage`             - Storage service, internal + sdcard | ||||||
| - `storage_settings`    - Storage settings app | - `storage_settings`    - Storage settings app | ||||||
| - `subghz`              - Subghz application, 433 fobs and etc | - `subghz`              - SubGhz application, 433 fobs and etc | ||||||
| - `system`              - System settings, tools and API | - `system`              - System settings, tools and API | ||||||
| - `tests`               - Unit tests and etc | - `tests`               - Unit tests and etc | ||||||
| - `u2f`                 - U2F Application | - `u2f`                 - U2F Application | ||||||
|  | |||||||
| @ -23,12 +23,12 @@ static int32_t subghz_chat_worker_thread(void* context) { | |||||||
|     SubGhzChatWorker* instance = context; |     SubGhzChatWorker* instance = context; | ||||||
|     FURI_LOG_I(TAG, "Worker start"); |     FURI_LOG_I(TAG, "Worker start"); | ||||||
|     char c; |     char c; | ||||||
|     SubghzChatEvent event; |     SubGhzChatEvent event; | ||||||
|     event.event = SubghzChatEventUserEntrance; |     event.event = SubGhzChatEventUserEntrance; | ||||||
|     osMessageQueuePut(instance->event_queue, &event, 0, 0); |     osMessageQueuePut(instance->event_queue, &event, 0, 0); | ||||||
|     while(instance->worker_running) { |     while(instance->worker_running) { | ||||||
|         if(furi_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, 1000) == 1) { |         if(furi_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, 1000) == 1) { | ||||||
|             event.event = SubghzChatEventInputData; |             event.event = SubGhzChatEventInputData; | ||||||
|             event.c = c; |             event.c = c; | ||||||
|             osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever); |             osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever); | ||||||
|         } |         } | ||||||
| @ -41,13 +41,13 @@ static int32_t subghz_chat_worker_thread(void* context) { | |||||||
| static void subghz_chat_worker_update_rx_event_chat(void* context) { | static void subghz_chat_worker_update_rx_event_chat(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhzChatWorker* instance = context; |     SubGhzChatWorker* instance = context; | ||||||
|     SubghzChatEvent event; |     SubGhzChatEvent event; | ||||||
|     if((millis() - instance->last_time_rx_data) > SUBGHZ_CHAT_WORKER_TIMEOUT_BETWEEN_MESSAGES) { |     if((millis() - instance->last_time_rx_data) > SUBGHZ_CHAT_WORKER_TIMEOUT_BETWEEN_MESSAGES) { | ||||||
|         event.event = SubghzChatEventNewMessage; |         event.event = SubGhzChatEventNewMessage; | ||||||
|         osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever); |         osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever); | ||||||
|     } |     } | ||||||
|     instance->last_time_rx_data = millis(); |     instance->last_time_rx_data = millis(); | ||||||
|     event.event = SubghzChatEventRXData; |     event.event = SubGhzChatEventRXData; | ||||||
|     osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever); |     osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -55,12 +55,12 @@ SubGhzChatWorker* subghz_chat_worker_alloc() { | |||||||
|     SubGhzChatWorker* instance = malloc(sizeof(SubGhzChatWorker)); |     SubGhzChatWorker* instance = malloc(sizeof(SubGhzChatWorker)); | ||||||
| 
 | 
 | ||||||
|     instance->thread = furi_thread_alloc(); |     instance->thread = furi_thread_alloc(); | ||||||
|     furi_thread_set_name(instance->thread, "SubghzChat"); |     furi_thread_set_name(instance->thread, "SubGhzChat"); | ||||||
|     furi_thread_set_stack_size(instance->thread, 2048); |     furi_thread_set_stack_size(instance->thread, 2048); | ||||||
|     furi_thread_set_context(instance->thread, instance); |     furi_thread_set_context(instance->thread, instance); | ||||||
|     furi_thread_set_callback(instance->thread, subghz_chat_worker_thread); |     furi_thread_set_callback(instance->thread, subghz_chat_worker_thread); | ||||||
|     instance->subghz_txrx = subghz_tx_rx_worker_alloc(); |     instance->subghz_txrx = subghz_tx_rx_worker_alloc(); | ||||||
|     instance->event_queue = osMessageQueueNew(80, sizeof(SubghzChatEvent), NULL); |     instance->event_queue = osMessageQueueNew(80, sizeof(SubGhzChatEvent), NULL); | ||||||
|     return instance; |     return instance; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -109,18 +109,18 @@ bool subghz_chat_worker_is_running(SubGhzChatWorker* instance) { | |||||||
|     return instance->worker_running; |     return instance->worker_running; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SubghzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance) { | SubGhzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     SubghzChatEvent event; |     SubGhzChatEvent event; | ||||||
|     if(osMessageQueueGet(instance->event_queue, &event, NULL, osWaitForever) == osOK) { |     if(osMessageQueueGet(instance->event_queue, &event, NULL, osWaitForever) == osOK) { | ||||||
|         return event; |         return event; | ||||||
|     } else { |     } else { | ||||||
|         event.event = SubghzChatEventNoEvent; |         event.event = SubGhzChatEventNoEvent; | ||||||
|         return event; |         return event; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubghzChatEvent* event) { | void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubGhzChatEvent* event) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     osMessageQueuePut(instance->event_queue, event, 0, osWaitForever); |     osMessageQueuePut(instance->event_queue, event, 0, osWaitForever); | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,26 +4,26 @@ | |||||||
| typedef struct SubGhzChatWorker SubGhzChatWorker; | typedef struct SubGhzChatWorker SubGhzChatWorker; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubghzChatEventNoEvent, |     SubGhzChatEventNoEvent, | ||||||
|     SubghzChatEventUserEntrance, |     SubGhzChatEventUserEntrance, | ||||||
|     SubghzChatEventUserExit, |     SubGhzChatEventUserExit, | ||||||
|     SubghzChatEventInputData, |     SubGhzChatEventInputData, | ||||||
|     SubghzChatEventRXData, |     SubGhzChatEventRXData, | ||||||
|     SubghzChatEventNewMessage, |     SubGhzChatEventNewMessage, | ||||||
| } SubghzChatEventType; | } SubGhzChatEventType; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     SubghzChatEventType event; |     SubGhzChatEventType event; | ||||||
|     char c; |     char c; | ||||||
| } SubghzChatEvent; | } SubGhzChatEvent; | ||||||
| 
 | 
 | ||||||
| SubGhzChatWorker* subghz_chat_worker_alloc(); | SubGhzChatWorker* subghz_chat_worker_alloc(); | ||||||
| void subghz_chat_worker_free(SubGhzChatWorker* instance); | void subghz_chat_worker_free(SubGhzChatWorker* instance); | ||||||
| bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency); | bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency); | ||||||
| void subghz_chat_worker_stop(SubGhzChatWorker* instance); | void subghz_chat_worker_stop(SubGhzChatWorker* instance); | ||||||
| bool subghz_chat_worker_is_running(SubGhzChatWorker* instance); | bool subghz_chat_worker_is_running(SubGhzChatWorker* instance); | ||||||
| SubghzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance); | SubGhzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance); | ||||||
| void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubghzChatEvent* event); | void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubGhzChatEvent* event); | ||||||
| size_t subghz_chat_worker_available(SubGhzChatWorker* instance); | size_t subghz_chat_worker_available(SubGhzChatWorker* instance); | ||||||
| size_t subghz_chat_worker_read(SubGhzChatWorker* instance, uint8_t* data, size_t size); | size_t subghz_chat_worker_read(SubGhzChatWorker* instance, uint8_t* data, size_t size); | ||||||
| bool subghz_chat_worker_write(SubGhzChatWorker* instance, uint8_t* data, size_t size); | bool subghz_chat_worker_write(SubGhzChatWorker* instance, uint8_t* data, size_t size); | ||||||
|  | |||||||
| @ -1,46 +1,46 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubghzCustomEventManagerNoSet = 0, |     SubGhzCustomEventManagerNoSet = 0, | ||||||
|     SubghzCustomEventManagerSet, |     SubGhzCustomEventManagerSet, | ||||||
|     SubghzCustomEventManagerSetRAW, |     SubGhzCustomEventManagerSetRAW, | ||||||
| 
 | 
 | ||||||
|     SubghzCustomEventSceneDeleteSuccess = 100, |     SubGhzCustomEventSceneDeleteSuccess = 100, | ||||||
|     SubghzCustomEventSceneDelete, |     SubGhzCustomEventSceneDelete, | ||||||
|     SubghzCustomEventSceneDeleteRAW, |     SubGhzCustomEventSceneDeleteRAW, | ||||||
|     SubghzCustomEventSceneDeleteRAWBack, |     SubGhzCustomEventSceneDeleteRAWBack, | ||||||
| 
 | 
 | ||||||
|     SubghzCustomEventSceneReceiverInfoTxStart, |     SubGhzCustomEventSceneReceiverInfoTxStart, | ||||||
|     SubghzCustomEventSceneReceiverInfoTxStop, |     SubGhzCustomEventSceneReceiverInfoTxStop, | ||||||
|     SubghzCustomEventSceneReceiverInfoSave, |     SubGhzCustomEventSceneReceiverInfoSave, | ||||||
|     SubghzCustomEventSceneSaveName, |     SubGhzCustomEventSceneSaveName, | ||||||
|     SubghzCustomEventSceneSaveSuccess, |     SubGhzCustomEventSceneSaveSuccess, | ||||||
|     SubghzCustomEventSceneShowErrorBack, |     SubGhzCustomEventSceneShowErrorBack, | ||||||
|     SubghzCustomEventSceneShowErrorOk, |     SubGhzCustomEventSceneShowErrorOk, | ||||||
|     SubghzCustomEventSceneShowErrorSub, |     SubGhzCustomEventSceneShowErrorSub, | ||||||
|     SubghzCustomEventSceneShowOnlyRX, |     SubGhzCustomEventSceneShowOnlyRX, | ||||||
| 
 | 
 | ||||||
|     SubghzCustomEventSceneExit, |     SubGhzCustomEventSceneExit, | ||||||
|     SubghzCustomEventSceneStay, |     SubGhzCustomEventSceneStay, | ||||||
| 
 | 
 | ||||||
|     SubghzCustomEventViewReceverOK, |     SubGhzCustomEventViewReceverOK, | ||||||
|     SubghzCustomEventViewReceverConfig, |     SubGhzCustomEventViewReceverConfig, | ||||||
|     SubghzCustomEventViewReceverBack, |     SubGhzCustomEventViewReceverBack, | ||||||
| 
 | 
 | ||||||
|     SubghzCustomEventViewReadRAWBack, |     SubGhzCustomEventViewReadRAWBack, | ||||||
|     SubghzCustomEventViewReadRAWIDLE, |     SubGhzCustomEventViewReadRAWIDLE, | ||||||
|     SubghzCustomEventViewReadRAWREC, |     SubGhzCustomEventViewReadRAWREC, | ||||||
|     SubghzCustomEventViewReadRAWConfig, |     SubGhzCustomEventViewReadRAWConfig, | ||||||
|     SubghzCustomEventViewReadRAWErase, |     SubGhzCustomEventViewReadRAWErase, | ||||||
|     SubghzCustomEventViewReadRAWSendStart, |     SubGhzCustomEventViewReadRAWSendStart, | ||||||
|     SubghzCustomEventViewReadRAWSendStop, |     SubGhzCustomEventViewReadRAWSendStop, | ||||||
|     SubghzCustomEventViewReadRAWSave, |     SubGhzCustomEventViewReadRAWSave, | ||||||
|     SubghzCustomEventViewReadRAWVibro, |     SubGhzCustomEventViewReadRAWVibro, | ||||||
|     SubghzCustomEventViewReadRAWTXRXStop, |     SubGhzCustomEventViewReadRAWTXRXStop, | ||||||
|     SubghzCustomEventViewReadRAWMore, |     SubGhzCustomEventViewReadRAWMore, | ||||||
| 
 | 
 | ||||||
|     SubghzCustomEventViewTransmitterBack, |     SubGhzCustomEventViewTransmitterBack, | ||||||
|     SubghzCustomEventViewTransmitterSendStart, |     SubGhzCustomEventViewTransmitterSendStart, | ||||||
|     SubghzCustomEventViewTransmitterSendStop, |     SubGhzCustomEventViewTransmitterSendStop, | ||||||
|     SubghzCustomEventViewTransmitterError, |     SubGhzCustomEventViewTransmitterError, | ||||||
| } SubghzCustomEvent; | } SubGhzCustomEvent; | ||||||
|  | |||||||
| @ -145,7 +145,7 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc() { | |||||||
|     SubGhzFrequencyAnalyzerWorker* instance = malloc(sizeof(SubGhzFrequencyAnalyzerWorker)); |     SubGhzFrequencyAnalyzerWorker* instance = malloc(sizeof(SubGhzFrequencyAnalyzerWorker)); | ||||||
| 
 | 
 | ||||||
|     instance->thread = furi_thread_alloc(); |     instance->thread = furi_thread_alloc(); | ||||||
|     furi_thread_set_name(instance->thread, "SubghzFAWorker"); |     furi_thread_set_name(instance->thread, "SubGhzFAWorker"); | ||||||
|     furi_thread_set_stack_size(instance->thread, 2048); |     furi_thread_set_stack_size(instance->thread, 2048); | ||||||
|     furi_thread_set_context(instance->thread, instance); |     furi_thread_set_context(instance->thread, instance); | ||||||
|     furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread); |     furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread); | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ void subghz_scene_delete_callback(GuiButtonType result, InputType type, void* co | |||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { |     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { | ||||||
|         view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneDelete); |         view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneDelete); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -31,8 +31,7 @@ void subghz_scene_delete_on_enter(void* context) { | |||||||
|         AlignTop, |         AlignTop, | ||||||
|         FontSecondary, |         FontSecondary, | ||||||
|         string_get_cstr(modulation_str)); |         string_get_cstr(modulation_str)); | ||||||
| 
 |     subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text); | ||||||
|     subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text); |  | ||||||
|     widget_add_string_multiline_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)); | ||||||
| 
 | 
 | ||||||
| @ -43,13 +42,13 @@ void subghz_scene_delete_on_enter(void* context) { | |||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         subghz->widget, GuiButtonTypeRight, "Delete", subghz_scene_delete_callback, subghz); |         subghz->widget, GuiButtonTypeRight, "Delete", subghz_scene_delete_callback, subghz); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_delete_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_delete_on_event(void* context, SceneManagerEvent event) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzCustomEventSceneDelete) { |         if(event.event == SubGhzCustomEventSceneDelete) { | ||||||
|             strcpy(subghz->file_name_tmp, subghz->file_name); |             strcpy(subghz->file_name_tmp, subghz->file_name); | ||||||
|             if(subghz_delete_file(subghz)) { |             if(subghz_delete_file(subghz)) { | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); | ||||||
|  | |||||||
| @ -6,10 +6,10 @@ void subghz_scene_delete_raw_callback(GuiButtonType result, InputType type, void | |||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { |     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|             subghz->view_dispatcher, SubghzCustomEventSceneDeleteRAW); |             subghz->view_dispatcher, SubGhzCustomEventSceneDeleteRAW); | ||||||
|     } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { |     } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|             subghz->view_dispatcher, SubghzCustomEventSceneDeleteRAWBack); |             subghz->view_dispatcher, SubGhzCustomEventSceneDeleteRAWBack); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -49,13 +49,13 @@ void subghz_scene_delete_raw_on_enter(void* context) { | |||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         subghz->widget, GuiButtonTypeLeft, "Back", subghz_scene_delete_raw_callback, subghz); |         subghz->widget, GuiButtonTypeLeft, "Back", subghz_scene_delete_raw_callback, subghz); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_delete_raw_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_delete_raw_on_event(void* context, SceneManagerEvent event) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzCustomEventSceneDeleteRAW) { |         if(event.event == SubGhzCustomEventSceneDeleteRAW) { | ||||||
|             strcpy(subghz->file_name_tmp, subghz->file_name); |             strcpy(subghz->file_name_tmp, subghz->file_name); | ||||||
|             if(subghz_delete_file(subghz)) { |             if(subghz_delete_file(subghz)) { | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); | ||||||
| @ -64,7 +64,7 @@ bool subghz_scene_delete_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|                     subghz->scene_manager, SubGhzSceneStart); |                     subghz->scene_manager, SubGhzSceneStart); | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzCustomEventSceneDeleteRAWBack) { |         } else if(event.event == SubGhzCustomEventSceneDeleteRAWBack) { | ||||||
|             return scene_manager_previous_scene(subghz->scene_manager); |             return scene_manager_previous_scene(subghz->scene_manager); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ | |||||||
| void subghz_scene_delete_success_popup_callback(void* context) { | void subghz_scene_delete_success_popup_callback(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_send_custom_event( |     view_dispatcher_send_custom_event( | ||||||
|         subghz->view_dispatcher, SubghzCustomEventSceneDeleteSuccess); |         subghz->view_dispatcher, SubGhzCustomEventSceneDeleteSuccess); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_scene_delete_success_on_enter(void* context) { | void subghz_scene_delete_success_on_enter(void* context) { | ||||||
| @ -18,14 +18,14 @@ void subghz_scene_delete_success_on_enter(void* context) { | |||||||
|     popup_set_context(popup, subghz); |     popup_set_context(popup, subghz); | ||||||
|     popup_set_callback(popup, subghz_scene_delete_success_popup_callback); |     popup_set_callback(popup, subghz_scene_delete_success_popup_callback); | ||||||
|     popup_enable_timeout(popup); |     popup_enable_timeout(popup); | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_delete_success_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_delete_success_on_event(void* context, SceneManagerEvent event) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzCustomEventSceneDeleteSuccess) { |         if(event.event == SubGhzCustomEventSceneDeleteSuccess) { | ||||||
|             if(!scene_manager_search_and_switch_to_previous_scene( |             if(!scene_manager_search_and_switch_to_previous_scene( | ||||||
|                    subghz->scene_manager, SubGhzSceneSaved)) { |                    subghz->scene_manager, SubGhzSceneSaved)) { | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
| #include "../views/subghz_frequency_analyzer.h" | #include "../views/subghz_frequency_analyzer.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void subghz_scene_frequency_analyzer_callback(SubghzCustomEvent event, void* context) { | void subghz_scene_frequency_analyzer_callback(SubGhzCustomEvent event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); |     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); | ||||||
| @ -13,7 +13,7 @@ void subghz_scene_frequency_analyzer_on_enter(void* context) { | |||||||
|     DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer); |     DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer); | ||||||
|     subghz_frequency_analyzer_set_callback( |     subghz_frequency_analyzer_set_callback( | ||||||
|         subghz->subghz_frequency_analyzer, subghz_scene_frequency_analyzer_callback, subghz); |         subghz->subghz_frequency_analyzer, subghz_scene_frequency_analyzer_callback, subghz); | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewFrequencyAnalyzer); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdFrequencyAnalyzer); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_frequency_analyzer_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_frequency_analyzer_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -30,7 +30,7 @@ void subghz_scene_more_raw_on_enter(void* context) { | |||||||
|     submenu_set_selected_item( |     submenu_set_selected_item( | ||||||
|         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneMoreRAW)); |         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneMoreRAW)); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdMenu); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) { | ||||||
| @ -39,7 +39,7 @@ bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubmenuIndexDelete) { |         if(event.event == SubmenuIndexDelete) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet); |                 subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet); | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDelete); |                 subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDelete); | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW); | ||||||
|  | |||||||
| @ -6,9 +6,9 @@ void subghz_scene_need_saving_callback(GuiButtonType result, InputType type, voi | |||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 | 
 | ||||||
|     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { |     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { | ||||||
|         view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneStay); |         view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneStay); | ||||||
|     } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { |     } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { | ||||||
|         view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneExit); |         view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -31,7 +31,7 @@ void subghz_scene_need_saving_on_enter(void* context) { | |||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         subghz->widget, GuiButtonTypeLeft, "Exit", subghz_scene_need_saving_callback, subghz); |         subghz->widget, GuiButtonTypeLeft, "Exit", subghz_scene_need_saving_callback, subghz); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) { | ||||||
| @ -41,11 +41,11 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) { | |||||||
|         scene_manager_previous_scene(subghz->scene_manager); |         scene_manager_previous_scene(subghz->scene_manager); | ||||||
|         return true; |         return true; | ||||||
|     } else if(event.type == SceneManagerEventTypeCustom) { |     } else if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzCustomEventSceneStay) { |         if(event.event == SubGhzCustomEventSceneStay) { | ||||||
|             subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; |             subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; | ||||||
|             scene_manager_previous_scene(subghz->scene_manager); |             scene_manager_previous_scene(subghz->scene_manager); | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzCustomEventSceneExit) { |         } else if(event.event == SubGhzCustomEventSceneExit) { | ||||||
|             if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) { |             if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) { | ||||||
|                 subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; |                 subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||||
|                 scene_manager_search_and_switch_to_previous_scene( |                 scene_manager_search_and_switch_to_previous_scene( | ||||||
|  | |||||||
| @ -1,35 +1,35 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include "../views/subghz_read_raw.h" | #include "../views/subghz_read_raw.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_raw.h> | #include <lib/subghz/protocols/raw.h> | ||||||
| #include <lib/subghz/subghz_parser.h> |  | ||||||
| #include <lib/toolbox/path.h> | #include <lib/toolbox/path.h> | ||||||
| 
 | 
 | ||||||
| #define RAW_FILE_NAME "Raw_signal_" | #define RAW_FILE_NAME "Raw_signal_" | ||||||
|  | #define TAG "SubGhzSceneReadRAW" | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { | bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { | ||||||
|     bool ret = false; |     bool ret = false; | ||||||
|     //set the path to read the file
 |     //set the path to read the file
 | ||||||
|     if(strcmp( |  | ||||||
|            subghz_protocol_raw_get_last_file_name( |  | ||||||
|                (SubGhzProtocolRAW*)subghz->txrx->protocol_result), |  | ||||||
|            "")) { |  | ||||||
|     string_t temp_str; |     string_t temp_str; | ||||||
|         string_init_printf( |     string_init(temp_str); | ||||||
|             temp_str, |     do { | ||||||
|             "%s", |         if(!flipper_format_rewind(subghz->txrx->fff_data)) { | ||||||
|             subghz_protocol_raw_get_last_file_name( |             FURI_LOG_E(TAG, "Rewind error"); | ||||||
|                 (SubGhzProtocolRAW*)subghz->txrx->protocol_result)); |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(!flipper_format_read_string(subghz->txrx->fff_data, "File_name", temp_str)) { | ||||||
|  |             FURI_LOG_E(TAG, "Missing File_name"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str); |         path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str); | ||||||
|         strcpy(subghz->file_name, string_get_cstr(temp_str)); |         strcpy(subghz->file_name, string_get_cstr(temp_str)); | ||||||
|         string_printf( |  | ||||||
|             temp_str, "%s/%s%s", SUBGHZ_APP_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION); |  | ||||||
| 
 | 
 | ||||||
|         subghz_protocol_raw_set_last_file_name( |  | ||||||
|             (SubGhzProtocolRAW*)subghz->txrx->protocol_result, string_get_cstr(temp_str)); |  | ||||||
|         string_clear(temp_str); |  | ||||||
|         ret = true; |         ret = true; | ||||||
|     } |     } while(false); | ||||||
|  | 
 | ||||||
|  |     string_clear(temp_str); | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -51,7 +51,7 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { | |||||||
|     string_clear(modulation_str); |     string_clear(modulation_str); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_scene_read_raw_callback(SubghzCustomEvent event, void* context) { | void subghz_scene_read_raw_callback(SubGhzCustomEvent event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); |     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); | ||||||
| @ -61,7 +61,7 @@ void subghz_scene_read_raw_callback_end_tx(void* context) { | |||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_send_custom_event( |     view_dispatcher_send_custom_event( | ||||||
|         subghz->view_dispatcher, SubghzCustomEventViewReadRAWSendStop); |         subghz->view_dispatcher, SubGhzCustomEventViewReadRAWSendStop); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_scene_read_raw_on_enter(void* context) { | void subghz_scene_read_raw_on_enter(void* context) { | ||||||
| @ -69,46 +69,43 @@ void subghz_scene_read_raw_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     switch(subghz->txrx->rx_key_state) { |     switch(subghz->txrx->rx_key_state) { | ||||||
|     case SubGhzRxKeyStateBack: |     case SubGhzRxKeyStateBack: | ||||||
|         subghz_read_raw_set_status(subghz->subghz_read_raw, SubghzReadRAWStatusIDLE, ""); |         subghz_read_raw_set_status(subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, ""); | ||||||
|         break; |         break; | ||||||
|     case SubGhzRxKeyStateRAWLoad: |     case SubGhzRxKeyStateRAWLoad: | ||||||
|         subghz_read_raw_set_status( |         subghz_read_raw_set_status( | ||||||
|             subghz->subghz_read_raw, SubghzReadRAWStatusLoadKeyTX, subghz->file_name); |             subghz->subghz_read_raw, SubGhzReadRAWStatusLoadKeyTX, subghz->file_name); | ||||||
|         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; |         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||||
|         break; |         break; | ||||||
|     case SubGhzRxKeyStateRAWSave: |     case SubGhzRxKeyStateRAWSave: | ||||||
|         subghz_read_raw_set_status( |         subghz_read_raw_set_status( | ||||||
|             subghz->subghz_read_raw, SubghzReadRAWStatusSaveKey, subghz->file_name); |             subghz->subghz_read_raw, SubGhzReadRAWStatusSaveKey, subghz->file_name); | ||||||
|         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; |         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||||
|         break; |         break; | ||||||
|     default: |     default: | ||||||
|         subghz_read_raw_set_status(subghz->subghz_read_raw, SubghzReadRAWStatusStart, ""); |         subghz_read_raw_set_status(subghz->subghz_read_raw, SubGhzReadRAWStatusStart, ""); | ||||||
|         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; |         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     subghz_scene_read_raw_update_statusbar(subghz); |     subghz_scene_read_raw_update_statusbar(subghz); | ||||||
|  | 
 | ||||||
|  |     //set callback view raw
 | ||||||
|     subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz); |     subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz); | ||||||
| 
 | 
 | ||||||
|     subghz->txrx->protocol_result = subghz_parser_get_by_name(subghz->txrx->parser, "RAW"); |     subghz->txrx->decoder_result = | ||||||
|     furi_assert(subghz->txrx->protocol_result); |         subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "RAW"); | ||||||
|  |     furi_assert(subghz->txrx->decoder_result); | ||||||
| 
 | 
 | ||||||
|     subghz_worker_set_pair_callback( |     //set filter RAW feed
 | ||||||
|         subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_parser_raw_parse); |     subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_RAW); | ||||||
| 
 |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW); | ||||||
|     subghz_protocol_raw_file_encoder_worker_set_callback_end( |  | ||||||
|         (SubGhzProtocolRAW*)subghz->txrx->protocol_result, |  | ||||||
|         subghz_scene_read_raw_callback_end_tx, |  | ||||||
|         subghz); |  | ||||||
| 
 |  | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReadRAW); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         switch(event.event) { |         switch(event.event) { | ||||||
|         case SubghzCustomEventViewReadRAWBack: |         case SubGhzCustomEventViewReadRAWBack: | ||||||
|             //Stop TX
 |             //Stop TX
 | ||||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { |             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||||
|                 subghz_tx_stop(subghz); |                 subghz_tx_stop(subghz); | ||||||
| @ -121,7 +118,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|             }; |             }; | ||||||
|             //Stop save file
 |             //Stop save file
 | ||||||
|             subghz_protocol_raw_save_to_file_stop( |             subghz_protocol_raw_save_to_file_stop( | ||||||
|                 (SubGhzProtocolRAW*)subghz->txrx->protocol_result); |                 (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); | ||||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             //needed save?
 |             //needed save?
 | ||||||
|             if((subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) || |             if((subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) || | ||||||
| @ -144,7 +141,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case SubghzCustomEventViewReadRAWTXRXStop: |         case SubGhzCustomEventViewReadRAWTXRXStop: | ||||||
|             //Stop TX
 |             //Stop TX
 | ||||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { |             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||||
|                 subghz_tx_stop(subghz); |                 subghz_tx_stop(subghz); | ||||||
| @ -159,27 +156,27 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case SubghzCustomEventViewReadRAWConfig: |         case SubGhzCustomEventViewReadRAWConfig: | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerSet); |                 subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet); | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); | ||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case SubghzCustomEventViewReadRAWErase: |         case SubGhzCustomEventViewReadRAWErase: | ||||||
|             subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; |             subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case SubghzCustomEventViewReadRAWVibro: |         case SubGhzCustomEventViewReadRAWVibro: | ||||||
|             notification_message(subghz->notifications, &sequence_single_vibro); |             notification_message(subghz->notifications, &sequence_single_vibro); | ||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case SubghzCustomEventViewReadRAWMore: |         case SubGhzCustomEventViewReadRAWMore: | ||||||
|             if(subghz_scene_read_raw_update_filename(subghz)) { |             if(subghz_scene_read_raw_update_filename(subghz)) { | ||||||
|                 scene_manager_set_scene_state( |                 scene_manager_set_scene_state( | ||||||
|                     subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerSet); |                     subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet); | ||||||
|                 subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; |                 subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW); | ||||||
|                 return true; |                 return true; | ||||||
| @ -188,7 +185,8 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case SubghzCustomEventViewReadRAWSendStart: |         case SubGhzCustomEventViewReadRAWSendStart: | ||||||
|  | 
 | ||||||
|             if(subghz_scene_read_raw_update_filename(subghz)) { |             if(subghz_scene_read_raw_update_filename(subghz)) { | ||||||
|                 //start send
 |                 //start send
 | ||||||
|                 subghz->state_notifications = SubGhzNotificationStateIDLE; |                 subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
| @ -197,10 +195,17 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|                 } |                 } | ||||||
|                 if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || |                 if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || | ||||||
|                    (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { |                    (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { | ||||||
|                     if(!subghz_tx_start(subghz)) { |                     //ToDo FIX
 | ||||||
|  | 
 | ||||||
|  |                     if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) { | ||||||
|                         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); |                         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); | ||||||
|                     } else { |                     } else { | ||||||
|                         DOLPHIN_DEED(DolphinDeedSubGhzSend); |                         DOLPHIN_DEED(DolphinDeedSubGhzSend); | ||||||
|  |                         // set callback end tx
 | ||||||
|  |                         subghz_protocol_raw_file_encoder_worker_set_callback_end( | ||||||
|  |                             (SubGhzProtocolEncoderRAW*)subghz->txrx->transmitter->protocol_instance, | ||||||
|  |                             subghz_scene_read_raw_callback_end_tx, | ||||||
|  |                             subghz); | ||||||
|                         subghz->state_notifications = SubGhzNotificationStateTX; |                         subghz->state_notifications = SubGhzNotificationStateTX; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| @ -208,7 +213,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case SubghzCustomEventViewReadRAWSendStop: |         case SubGhzCustomEventViewReadRAWSendStop: | ||||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { |             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||||
|                 subghz_tx_stop(subghz); |                 subghz_tx_stop(subghz); | ||||||
| @ -218,13 +223,14 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case SubghzCustomEventViewReadRAWIDLE: |         case SubGhzCustomEventViewReadRAWIDLE: | ||||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { |             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { | ||||||
|                 subghz_rx_end(subghz); |                 subghz_rx_end(subghz); | ||||||
|                 subghz_sleep(subghz); |                 subghz_sleep(subghz); | ||||||
|             }; |             }; | ||||||
|             subghz_protocol_raw_save_to_file_stop( |             subghz_protocol_raw_save_to_file_stop( | ||||||
|                 (SubGhzProtocolRAW*)subghz->txrx->protocol_result); |                 (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); | ||||||
|  |             subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, RAW_FILE_NAME); | ||||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
| 
 | 
 | ||||||
|             subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; |             subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; | ||||||
| @ -232,16 +238,16 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case SubghzCustomEventViewReadRAWREC: |         case SubGhzCustomEventViewReadRAWREC: | ||||||
|             if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) { |             if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) { | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); | ||||||
|             } else { |             } else { | ||||||
|                 subghz_get_preset_name(subghz, subghz->error_str); |                 //subghz_get_preset_name(subghz, subghz->error_str);
 | ||||||
|                 if(subghz_protocol_raw_save_to_file_init( |                 if(subghz_protocol_raw_save_to_file_init( | ||||||
|                        (SubGhzProtocolRAW*)subghz->txrx->protocol_result, |                        (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, | ||||||
|                        RAW_FILE_NAME, |                        RAW_FILE_NAME, | ||||||
|                        subghz->txrx->frequency, |                        subghz->txrx->frequency, | ||||||
|                        string_get_cstr(subghz->error_str))) { |                        subghz->txrx->preset)) { | ||||||
|                     DOLPHIN_DEED(DolphinDeedSubGhzRawRec); |                     DOLPHIN_DEED(DolphinDeedSubGhzRawRec); | ||||||
|                     if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || |                     if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || | ||||||
|                        (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { |                        (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { | ||||||
| @ -258,10 +264,10 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case SubghzCustomEventViewReadRAWSave: |         case SubGhzCustomEventViewReadRAWSave: | ||||||
|             if(subghz_scene_read_raw_update_filename(subghz)) { |             if(subghz_scene_read_raw_update_filename(subghz)) { | ||||||
|                 scene_manager_set_scene_state( |                 scene_manager_set_scene_state( | ||||||
|                     subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerSetRAW); |                     subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW); | ||||||
|                 subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; |                 subghz->txrx->rx_key_state = SubGhzRxKeyStateBack; | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); | ||||||
|             } |             } | ||||||
| @ -278,7 +284,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|             subghz_read_raw_update_sample_write( |             subghz_read_raw_update_sample_write( | ||||||
|                 subghz->subghz_read_raw, |                 subghz->subghz_read_raw, | ||||||
|                 subghz_protocol_raw_get_sample_write( |                 subghz_protocol_raw_get_sample_write( | ||||||
|                     (SubGhzProtocolRAW*)subghz->txrx->protocol_result)); |                     (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result)); | ||||||
|             subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, furi_hal_subghz_get_rssi()); |             subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, furi_hal_subghz_get_rssi()); | ||||||
|             break; |             break; | ||||||
|         case SubGhzNotificationStateTX: |         case SubGhzNotificationStateTX: | ||||||
| @ -302,7 +308,6 @@ void subghz_scene_read_raw_on_exit(void* context) { | |||||||
|     }; |     }; | ||||||
|     subghz->state_notifications = SubGhzNotificationStateIDLE; |     subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
| 
 | 
 | ||||||
|     //Сallback restoration
 |     //filter restoration
 | ||||||
|     subghz_worker_set_pair_callback( |     subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable); | ||||||
|         subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_parser_parse); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include "../views/subghz_receiver.h" | #include "../views/receiver.h" | ||||||
| 
 | 
 | ||||||
| static void subghz_scene_receiver_update_statusbar(void* context) { | static void subghz_scene_receiver_update_statusbar(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| @ -14,7 +14,7 @@ static void subghz_scene_receiver_update_statusbar(void* context) { | |||||||
| 
 | 
 | ||||||
|         subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); |         subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); | ||||||
| 
 | 
 | ||||||
|         subghz_receiver_add_data_statusbar( |         subghz_view_receiver_add_data_statusbar( | ||||||
|             subghz->subghz_receiver, |             subghz->subghz_receiver, | ||||||
|             string_get_cstr(frequency_str), |             string_get_cstr(frequency_str), | ||||||
|             string_get_cstr(modulation_str), |             string_get_cstr(modulation_str), | ||||||
| @ -23,36 +23,41 @@ static void subghz_scene_receiver_update_statusbar(void* context) { | |||||||
|         string_clear(frequency_str); |         string_clear(frequency_str); | ||||||
|         string_clear(modulation_str); |         string_clear(modulation_str); | ||||||
|     } else { |     } else { | ||||||
|         subghz_receiver_add_data_statusbar( |         subghz_view_receiver_add_data_statusbar( | ||||||
|             subghz->subghz_receiver, string_get_cstr(history_stat_str), "", ""); |             subghz->subghz_receiver, string_get_cstr(history_stat_str), "", ""); | ||||||
|         subghz->state_notifications = SubGhzNotificationStateIDLE; |         subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|     } |     } | ||||||
|     string_clear(history_stat_str); |     string_clear(history_stat_str); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_scene_receiver_callback(SubghzCustomEvent event, void* context) { | void subghz_scene_receiver_callback(SubGhzCustomEvent event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); |     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_scene_add_to_history_callback(SubGhzProtocolCommon* parser, void* context) { | static void subghz_scene_add_to_history_callback( | ||||||
|  |     SubGhzReceiver* receiver, | ||||||
|  |     SubGhzProtocolDecoderBase* decoder_base, | ||||||
|  |     void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     string_t str_buff; |     string_t str_buff; | ||||||
|     string_init(str_buff); |     string_init(str_buff); | ||||||
| 
 | 
 | ||||||
|     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, decoder_base, subghz->txrx->frequency, subghz->txrx->preset)) { | ||||||
|         subghz_parser_reset(subghz->txrx->parser); |         subghz_receiver_reset(receiver); | ||||||
|         string_reset(str_buff); |         string_reset(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); | ||||||
|         subghz_receiver_add_item_to_menu( |         subghz_view_receiver_add_item_to_menu( | ||||||
|             subghz->subghz_receiver, |             subghz->subghz_receiver, | ||||||
|             string_get_cstr(str_buff), |             string_get_cstr(str_buff), | ||||||
|             subghz_history_get_type_protocol( |             subghz_history_get_type_protocol( | ||||||
|                 subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1)); |                 subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1)); | ||||||
|  | 
 | ||||||
|         subghz_scene_receiver_update_statusbar(subghz); |         subghz_scene_receiver_update_statusbar(subghz); | ||||||
|     } |     } | ||||||
|     string_clear(str_buff); |     string_clear(str_buff); | ||||||
| @ -70,11 +75,11 @@ void subghz_scene_receiver_on_enter(void* context) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     //Load history to receiver
 |     //Load history to receiver
 | ||||||
|     subghz_receiver_exit(subghz->subghz_receiver); |     subghz_view_receiver_exit(subghz->subghz_receiver); | ||||||
|     for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) { |     for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) { | ||||||
|         string_reset(str_buff); |         string_reset(str_buff); | ||||||
|         subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i); |         subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i); | ||||||
|         subghz_receiver_add_item_to_menu( |         subghz_view_receiver_add_item_to_menu( | ||||||
|             subghz->subghz_receiver, |             subghz->subghz_receiver, | ||||||
|             string_get_cstr(str_buff), |             string_get_cstr(str_buff), | ||||||
|             subghz_history_get_type_protocol(subghz->txrx->history, i)); |             subghz_history_get_type_protocol(subghz->txrx->history, i)); | ||||||
| @ -82,8 +87,10 @@ 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_view_receiver_set_callback( | ||||||
|     subghz_parser_enable_dump(subghz->txrx->parser, subghz_scene_add_to_history_callback, subghz); |         subghz->subghz_receiver, subghz_scene_receiver_callback, subghz); | ||||||
|  |     subghz_receiver_set_rx_callback( | ||||||
|  |         subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz); | ||||||
| 
 | 
 | ||||||
|     subghz->state_notifications = SubGhzNotificationStateRX; |     subghz->state_notifications = SubGhzNotificationStateRX; | ||||||
|     if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { |     if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { | ||||||
| @ -94,9 +101,9 @@ void subghz_scene_receiver_on_enter(void* context) { | |||||||
|         subghz_begin(subghz, subghz->txrx->preset); |         subghz_begin(subghz, subghz->txrx->preset); | ||||||
|         subghz_rx(subghz, subghz->txrx->frequency); |         subghz_rx(subghz, subghz->txrx->frequency); | ||||||
|     } |     } | ||||||
|     subghz_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); |     subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReceiver); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { | ||||||
| @ -104,7 +111,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { | |||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         switch(event.event) { |         switch(event.event) { | ||||||
|         case SubghzCustomEventViewReceverBack: |         case SubGhzCustomEventViewReceverBack: | ||||||
| 
 | 
 | ||||||
|             // Stop CC1101 Rx
 |             // Stop CC1101 Rx
 | ||||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
| @ -116,7 +123,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { | |||||||
|             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_parser_enable_dump(subghz->txrx->parser, NULL, subghz); |             subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); | ||||||
| 
 | 
 | ||||||
|             if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { |             if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { | ||||||
|                 subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; |                 subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; | ||||||
| @ -127,14 +134,16 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { | |||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
|         case SubghzCustomEventViewReceverOK: |         case SubGhzCustomEventViewReceverOK: | ||||||
|             subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver); |             subghz->txrx->idx_menu_chosen = | ||||||
|  |                 subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); | ||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
|         case SubghzCustomEventViewReceverConfig: |         case SubGhzCustomEventViewReceverConfig: | ||||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver); |             subghz->txrx->idx_menu_chosen = | ||||||
|  |                 subghz_view_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; | ||||||
|  | |||||||
| @ -127,7 +127,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { | |||||||
|     variable_item_set_current_value_text(item, subghz_frequencies_text[value_index]); |     variable_item_set_current_value_text(item, subghz_frequencies_text[value_index]); | ||||||
| 
 | 
 | ||||||
|     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != |     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != | ||||||
|        SubghzCustomEventManagerSet) { |        SubGhzCustomEventManagerSet) { | ||||||
|         item = variable_item_list_add( |         item = variable_item_list_add( | ||||||
|             subghz->variable_item_list, |             subghz->variable_item_list, | ||||||
|             "Hopping:", |             "Hopping:", | ||||||
| @ -151,7 +151,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { | |||||||
|     variable_item_set_current_value_index(item, value_index); |     variable_item_set_current_value_index(item, value_index); | ||||||
|     variable_item_set_current_value_text(item, preset_text[value_index]); |     variable_item_set_current_value_text(item, preset_text[value_index]); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewVariableItemList); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent event) { | ||||||
| @ -163,5 +163,5 @@ void subghz_scene_receiver_config_on_exit(void* context) { | |||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     variable_item_list_reset(subghz->variable_item_list); |     variable_item_list_reset(subghz->variable_item_list); | ||||||
|     scene_manager_set_scene_state( |     scene_manager_set_scene_state( | ||||||
|         subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet); |         subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet); | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,25 +8,24 @@ void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, v | |||||||
| 
 | 
 | ||||||
|     if((result == GuiButtonTypeCenter) && (type == InputTypePress)) { |     if((result == GuiButtonTypeCenter) && (type == InputTypePress)) { | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|             subghz->view_dispatcher, SubghzCustomEventSceneReceiverInfoTxStart); |             subghz->view_dispatcher, SubGhzCustomEventSceneReceiverInfoTxStart); | ||||||
|     } else if((result == GuiButtonTypeCenter) && (type == InputTypeRelease)) { |     } else if((result == GuiButtonTypeCenter) && (type == InputTypeRelease)) { | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|             subghz->view_dispatcher, SubghzCustomEventSceneReceiverInfoTxStop); |             subghz->view_dispatcher, SubGhzCustomEventSceneReceiverInfoTxStop); | ||||||
|     } else if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { |     } else if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|             subghz->view_dispatcher, SubghzCustomEventSceneReceiverInfoSave); |             subghz->view_dispatcher, SubGhzCustomEventSceneReceiverInfoSave); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 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_parser_get_by_name( |     subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( | ||||||
|         subghz->txrx->parser, |         subghz->txrx->receiver, | ||||||
|         subghz_history_get_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); |         subghz_history_get_protocol_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); | ||||||
| 
 |     if(subghz->txrx->decoder_result) { | ||||||
|     if(subghz->txrx->protocol_result->to_load_protocol != NULL) { |         subghz_protocol_decoder_base_deserialize( | ||||||
|         subghz->txrx->protocol_result->to_load_protocol( |             subghz->txrx->decoder_result, | ||||||
|             subghz->txrx->protocol_result, |  | ||||||
|             subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); |             subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen)); | ||||||
|         subghz->txrx->frequency = |         subghz->txrx->frequency = | ||||||
|             subghz_history_get_frequency(subghz->txrx->history, subghz->txrx->idx_menu_chosen); |             subghz_history_get_frequency(subghz->txrx->history, subghz->txrx->idx_menu_chosen); | ||||||
| @ -68,8 +67,7 @@ void subghz_scene_receiver_info_on_enter(void* context) { | |||||||
|             AlignTop, |             AlignTop, | ||||||
|             FontSecondary, |             FontSecondary, | ||||||
|             string_get_cstr(modulation_str)); |             string_get_cstr(modulation_str)); | ||||||
| 
 |         subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text); | ||||||
|         subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text); |  | ||||||
|         widget_add_string_multiline_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)); | ||||||
| 
 | 
 | ||||||
| @ -77,14 +75,19 @@ void subghz_scene_receiver_info_on_enter(void* context) { | |||||||
|         string_clear(modulation_str); |         string_clear(modulation_str); | ||||||
|         string_clear(text); |         string_clear(text); | ||||||
| 
 | 
 | ||||||
|         if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_file && |         if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == | ||||||
|            strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) { |            SubGhzProtocolFlag_Save) { | ||||||
|             widget_add_button_element( |             widget_add_button_element( | ||||||
|                 subghz->widget, |                 subghz->widget, | ||||||
|                 GuiButtonTypeRight, |                 GuiButtonTypeRight, | ||||||
|                 "Save", |                 "Save", | ||||||
|                 subghz_scene_receiver_info_callback, |                 subghz_scene_receiver_info_callback, | ||||||
|                 subghz); |                 subghz); | ||||||
|  |         } | ||||||
|  |         if(((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == | ||||||
|  |             SubGhzProtocolFlag_Send) && | ||||||
|  |            subghz->txrx->decoder_result->protocol->encoder->deserialize && | ||||||
|  |            subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeStatic) { | ||||||
|             widget_add_button_element( |             widget_add_button_element( | ||||||
|                 subghz->widget, |                 subghz->widget, | ||||||
|                 GuiButtonTypeCenter, |                 GuiButtonTypeCenter, | ||||||
| @ -92,20 +95,19 @@ void subghz_scene_receiver_info_on_enter(void* context) { | |||||||
|                 subghz_scene_receiver_info_callback, |                 subghz_scene_receiver_info_callback, | ||||||
|                 subghz); |                 subghz); | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|     } else { |     } else { | ||||||
|         widget_add_icon_element(subghz->widget, 32, 12, &I_DolphinFirstStart7_61x51); |         widget_add_icon_element(subghz->widget, 32, 12, &I_DolphinFirstStart7_61x51); | ||||||
|         widget_add_string_element( |         widget_add_string_element( | ||||||
|             subghz->widget, 13, 8, AlignLeft, AlignBottom, FontSecondary, "Error history parse."); |             subghz->widget, 13, 8, AlignLeft, AlignBottom, FontSecondary, "Error history parse."); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) { | 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 == SubghzCustomEventSceneReceiverInfoTxStart) { |         if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) { | ||||||
|             //CC1101 Stop RX -> Start TX
 |             //CC1101 Stop RX -> Start TX
 | ||||||
|             if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { |             if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { | ||||||
|                 subghz->txrx->hopper_state = SubGhzHopperStatePause; |                 subghz->txrx->hopper_state = SubGhzHopperStatePause; | ||||||
| @ -118,14 +120,17 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) | |||||||
|             } |             } | ||||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE || |             if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE || | ||||||
|                subghz->txrx->txrx_state == SubGhzTxRxStateSleep) { |                subghz->txrx->txrx_state == SubGhzTxRxStateSleep) { | ||||||
|                 if(!subghz_tx_start(subghz)) { |                 if(!subghz_tx_start( | ||||||
|  |                        subghz, | ||||||
|  |                        subghz_history_get_raw_data( | ||||||
|  |                            subghz->txrx->history, subghz->txrx->idx_menu_chosen))) { | ||||||
|                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); |                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); | ||||||
|                 } else { |                 } else { | ||||||
|                     subghz->state_notifications = SubGhzNotificationStateTX; |                     subghz->state_notifications = SubGhzNotificationStateTX; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzCustomEventSceneReceiverInfoTxStop) { |         } else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) { | ||||||
|             //CC1101 Stop Tx -> Start RX
 |             //CC1101 Stop Tx -> Start RX
 | ||||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { |             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||||
| @ -140,7 +145,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) | |||||||
|             } |             } | ||||||
|             subghz->state_notifications = SubGhzNotificationStateRX; |             subghz->state_notifications = SubGhzNotificationStateRX; | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzCustomEventSceneReceiverInfoSave) { |         } else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) { | ||||||
|             //CC1101 Stop RX -> Save
 |             //CC1101 Stop RX -> Save
 | ||||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { |             if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { | ||||||
| @ -153,8 +158,9 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) | |||||||
|             if(!subghz_scene_receiver_info_update_parser(subghz)) { |             if(!subghz_scene_receiver_info_update_parser(subghz)) { | ||||||
|                 return false; |                 return false; | ||||||
|             } |             } | ||||||
|             if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_file && | 
 | ||||||
|                strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) { |             if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == | ||||||
|  |                SubGhzProtocolFlag_Save) { | ||||||
|                 subghz_file_name_clear(subghz); |                 subghz_file_name_clear(subghz); | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -1,13 +1,13 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include <lib/toolbox/random_name.h> | #include <lib/toolbox/random_name.h> | ||||||
| #include "../helpers/subghz_custom_event.h" | #include "../helpers/subghz_custom_event.h" | ||||||
| #include <lib/subghz/protocols/subghz_protocol_raw.h> | #include <lib/subghz/protocols/raw.h> | ||||||
| #include <gui/modules/validators.h> | #include <gui/modules/validators.h> | ||||||
| 
 | 
 | ||||||
| void subghz_scene_save_name_text_input_callback(void* context) { | void subghz_scene_save_name_text_input_callback(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneSaveName); |     view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneSaveName); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_scene_save_name_on_enter(void* context) { | void subghz_scene_save_name_on_enter(void* context) { | ||||||
| @ -24,10 +24,10 @@ void subghz_scene_save_name_on_enter(void* context) { | |||||||
|     } else { |     } else { | ||||||
|         strcpy(subghz->file_name_tmp, subghz->file_name); |         strcpy(subghz->file_name_tmp, subghz->file_name); | ||||||
|         if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != |         if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != | ||||||
|            SubghzCustomEventManagerNoSet) { |            SubGhzCustomEventManagerNoSet) { | ||||||
|             subghz_get_next_name_file(subghz); |             subghz_get_next_name_file(subghz); | ||||||
|             if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) == |             if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) == | ||||||
|                SubghzCustomEventManagerSetRAW) { |                SubGhzCustomEventManagerSetRAW) { | ||||||
|                 dev_name_empty = true; |                 dev_name_empty = true; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -46,7 +46,7 @@ void subghz_scene_save_name_on_enter(void* context) { | |||||||
|         validator_is_file_alloc_init(SUBGHZ_APP_FOLDER, SUBGHZ_APP_EXTENSION); |         validator_is_file_alloc_init(SUBGHZ_APP_FOLDER, SUBGHZ_APP_EXTENSION); | ||||||
|     text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); |     text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTextInput); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTextInput); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { | ||||||
| @ -56,22 +56,35 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { | |||||||
|         scene_manager_previous_scene(subghz->scene_manager); |         scene_manager_previous_scene(subghz->scene_manager); | ||||||
|         return true; |         return true; | ||||||
|     } else if(event.type == SceneManagerEventTypeCustom) { |     } else if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzCustomEventSceneSaveName) { |         if(event.event == SubGhzCustomEventSceneSaveName) { | ||||||
|             if(strcmp(subghz->file_name, "")) { |             if(strcmp(subghz->file_name, "")) { | ||||||
|                 if(strcmp(subghz->file_name_tmp, "")) { |                 if(strcmp(subghz->file_name_tmp, "")) { | ||||||
|                     if(!subghz_rename_file(subghz)) { |                     if(!subghz_rename_file(subghz)) { | ||||||
|                         return false; |                         return false; | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     subghz_save_protocol_to_file(subghz, subghz->file_name); |                     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType) != | ||||||
|  |                        SubGhzCustomEventManagerNoSet) { | ||||||
|  |                         subghz_save_protocol_to_file( | ||||||
|  |                             subghz, subghz->txrx->fff_data, subghz->file_name); | ||||||
|  |                         scene_manager_set_scene_state( | ||||||
|  |                             subghz->scene_manager, | ||||||
|  |                             SubGhzSceneSetType, | ||||||
|  |                             SubGhzCustomEventManagerNoSet); | ||||||
|  |                     } else { | ||||||
|  |                         subghz_save_protocol_to_file( | ||||||
|  |                             subghz, | ||||||
|  |                             subghz_history_get_raw_data( | ||||||
|  |                                 subghz->txrx->history, subghz->txrx->idx_menu_chosen), | ||||||
|  |                             subghz->file_name); | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != |                 if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != | ||||||
|                    SubghzCustomEventManagerNoSet) { |                    SubGhzCustomEventManagerNoSet) { | ||||||
|                     subghz_protocol_raw_set_last_file_name( |                     subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, subghz->file_name); | ||||||
|                         (SubGhzProtocolRAW*)subghz->txrx->protocol_result, subghz->file_name); |  | ||||||
|                     scene_manager_set_scene_state( |                     scene_manager_set_scene_state( | ||||||
|                         subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet); |                         subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet); | ||||||
|                 } else { |                 } else { | ||||||
|                     subghz_file_name_clear(subghz); |                     subghz_file_name_clear(subghz); | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
| 
 | 
 | ||||||
| void subghz_scene_save_success_popup_callback(void* context) { | void subghz_scene_save_success_popup_callback(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneSaveSuccess); |     view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneSaveSuccess); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_scene_save_success_on_enter(void* context) { | void subghz_scene_save_success_on_enter(void* context) { | ||||||
| @ -20,13 +20,13 @@ void subghz_scene_save_success_on_enter(void* context) { | |||||||
|     popup_set_context(popup, subghz); |     popup_set_context(popup, subghz); | ||||||
|     popup_set_callback(popup, subghz_scene_save_success_popup_callback); |     popup_set_callback(popup, subghz_scene_save_success_popup_callback); | ||||||
|     popup_enable_timeout(popup); |     popup_enable_timeout(popup); | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzCustomEventSceneSaveSuccess) { |         if(event.event == SubGhzCustomEventSceneSaveSuccess) { | ||||||
|             if(!scene_manager_search_and_switch_to_previous_scene( |             if(!scene_manager_search_and_switch_to_previous_scene( | ||||||
|                    subghz->scene_manager, SubGhzSceneReceiver)) { |                    subghz->scene_manager, SubGhzSceneReceiver)) { | ||||||
|                 subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWSave; |                 subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWSave; | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ void subghz_scene_saved_on_enter(void* context) { | |||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 | 
 | ||||||
|     if(subghz_load_protocol_from_file(subghz)) { |     if(subghz_load_protocol_from_file(subghz)) { | ||||||
|         if((!strcmp(subghz->txrx->protocol_result->name, "RAW"))) { |         if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { | ||||||
|             subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; |             subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); | ||||||
|         } else { |         } else { | ||||||
|  | |||||||
| @ -38,7 +38,7 @@ void subghz_scene_saved_menu_on_enter(void* context) { | |||||||
|         subghz->submenu, |         subghz->submenu, | ||||||
|         scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSavedMenu)); |         scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSavedMenu)); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdMenu); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -1,6 +1,11 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include "../lib/subghz/protocols/subghz_protocol_keeloq.h" | #include <lib/subghz/protocols/keeloq.h> | ||||||
|  | #include <lib/subghz/blocks/math.h> | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
|  | #include <flipper_format/flipper_format_i.h> | ||||||
|  | #include <lib/toolbox/stream/stream.h> | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzSetType" | ||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexPricenton, |     SubmenuIndexPricenton, | ||||||
| @ -15,15 +20,52 @@ enum SubmenuIndex { | |||||||
|     SubmenuIndexDoorHan, |     SubmenuIndexDoorHan, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_set_type_submenu_to_find_protocol(void* context, const char* protocol_name) { | bool subghz_scene_set_type_submenu_gen_data_protocol( | ||||||
|  |     void* context, | ||||||
|  |     const char* protocol_name, | ||||||
|  |     uint64_t key, | ||||||
|  |     uint32_t bit) { | ||||||
|  |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     subghz->txrx->protocol_result = subghz_parser_get_by_name(subghz->txrx->parser, protocol_name); | 
 | ||||||
|     if(subghz->txrx->protocol_result == NULL) { |     bool res = false; | ||||||
|  | 
 | ||||||
|  |     subghz->txrx->decoder_result = | ||||||
|  |         subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, protocol_name); | ||||||
|  | 
 | ||||||
|  |     if(subghz->txrx->decoder_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, SubGhzSceneShowErrorSub); |         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     return true; | 
 | ||||||
|  |     do { | ||||||
|  |         Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); | ||||||
|  |         stream_clean(fff_data_stream); | ||||||
|  |         if(!subghz_protocol_decoder_base_serialize( | ||||||
|  |                subghz->txrx->decoder_result, | ||||||
|  |                subghz->txrx->fff_data, | ||||||
|  |                subghz_frequencies[subghz_frequencies_433_92], | ||||||
|  |                FuriHalSubGhzPresetOok650Async)) { | ||||||
|  |             FURI_LOG_E(TAG, "Unable to serialize"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if(!flipper_format_update_uint32(subghz->txrx->fff_data, "Bit", &bit, 1)) { | ||||||
|  |             FURI_LOG_E(TAG, "Unable to update Bit"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         uint8_t key_data[sizeof(uint64_t)] = {0}; | ||||||
|  |         for(size_t i = 0; i < sizeof(uint64_t); i++) { | ||||||
|  |             key_data[sizeof(uint64_t) - i - 1] = (key >> i * 8) & 0xFF; | ||||||
|  |         } | ||||||
|  |         if(!flipper_format_update_hex(subghz->txrx->fff_data, "Key", key_data, sizeof(uint64_t))) { | ||||||
|  |             FURI_LOG_E(TAG, "Unable to update Key"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         res = true; | ||||||
|  |     } while(false); | ||||||
|  |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_scene_set_type_submenu_callback(void* context, uint32_t index) { | void subghz_scene_set_type_submenu_callback(void* context, uint32_t index) { | ||||||
| @ -90,7 +132,7 @@ void subghz_scene_set_type_on_enter(void* context) { | |||||||
|     submenu_set_selected_item( |     submenu_set_selected_item( | ||||||
|         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType)); |         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType)); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdMenu); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { | ||||||
| @ -98,54 +140,45 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { | |||||||
|     bool generated_protocol = false; |     bool generated_protocol = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         //ToDo Fix
 | ||||||
|         uint32_t key = subghz_random_serial(); |         uint32_t key = subghz_random_serial(); | ||||||
|         switch(event.event) { |         switch(event.event) { | ||||||
|         case SubmenuIndexPricenton: |         case SubmenuIndexPricenton: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Princeton")) { |  | ||||||
|                 subghz->txrx->protocol_result->code_last_count_bit = 24; |  | ||||||
|             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 |             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 | ||||||
|                 subghz->txrx->protocol_result->code_last_found = key; |             if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "Princeton", key, 24)) { | ||||||
|  |                 uint32_t te = 400; | ||||||
|  |                 flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1); | ||||||
|                 generated_protocol = true; |                 generated_protocol = true; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case SubmenuIndexNiceFlo12bit: |         case SubmenuIndexNiceFlo12bit: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Nice FLO")) { |  | ||||||
|                 subghz->txrx->protocol_result->code_last_count_bit = 12; |  | ||||||
|             key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
 |             key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
 | ||||||
|                 subghz->txrx->protocol_result->code_last_found = key; |             if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "Nice FLO", key, 12)) { | ||||||
|                 generated_protocol = true; |                 generated_protocol = true; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case SubmenuIndexNiceFlo24bit: |         case SubmenuIndexNiceFlo24bit: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Nice FLO")) { |  | ||||||
|                 subghz->txrx->protocol_result->code_last_count_bit = 24; |  | ||||||
|             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 |             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 | ||||||
|                 subghz->txrx->protocol_result->code_last_found = key; |             if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "Nice FLO", key, 24)) { | ||||||
|                 generated_protocol = true; |                 generated_protocol = true; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case SubmenuIndexCAME12bit: |         case SubmenuIndexCAME12bit: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME")) { |  | ||||||
|                 subghz->txrx->protocol_result->code_last_count_bit = 12; |  | ||||||
|             key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
 |             key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
 | ||||||
|                 subghz->txrx->protocol_result->code_last_found = key; |             if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "CAME", key, 12)) { | ||||||
|                 generated_protocol = true; |                 generated_protocol = true; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case SubmenuIndexCAME24bit: |         case SubmenuIndexCAME24bit: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME")) { |  | ||||||
|                 subghz->txrx->protocol_result->code_last_count_bit = 24; |  | ||||||
|             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 |             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
 | ||||||
|                 subghz->txrx->protocol_result->code_last_found = key; |             if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "CAME", key, 24)) { | ||||||
|                 generated_protocol = true; |                 generated_protocol = true; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case SubmenuIndexCAMETwee: |         case SubmenuIndexCAMETwee: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME TWEE")) { |  | ||||||
|                 subghz->txrx->protocol_result->code_last_count_bit = 54; |  | ||||||
|             key = (key & 0x0FFFFFF0); |             key = (key & 0x0FFFFFF0); | ||||||
|                 subghz->txrx->protocol_result->code_last_found = 0x003FFF7200000000 | |             key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE); | ||||||
|                                                                  (key ^ 0xE0E0E0EE); |             if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "CAME TWEE", key, 54)) { | ||||||
|                 generated_protocol = true; |                 generated_protocol = true; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
| @ -156,33 +189,35 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { | |||||||
|         //     /* code */
 |         //     /* code */
 | ||||||
|         //     break;
 |         //     break;
 | ||||||
|         case SubmenuIndexGateTX: |         case SubmenuIndexGateTX: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "GateTX")) { |  | ||||||
|                 subghz->txrx->protocol_result->code_last_count_bit = 24; |  | ||||||
|             key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?)
 |             key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?)
 | ||||||
|                 subghz->txrx->protocol_result->code_last_found = |             uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24); | ||||||
|                     subghz_protocol_common_reverse_key( |             if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "GateTX", rev_key, 24)) { | ||||||
|                         key, subghz->txrx->protocol_result->code_last_count_bit); |  | ||||||
|                 generated_protocol = true; |                 generated_protocol = true; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case SubmenuIndexDoorHan: |         case SubmenuIndexDoorHan: | ||||||
|             if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "KeeLoq")) { |             subghz->txrx->transmitter = | ||||||
|                 subghz->txrx->protocol_result->code_last_count_bit = 64; |                 subghz_transmitter_alloc_init(subghz->txrx->environment, "KeeLoq"); | ||||||
|                 subghz->txrx->protocol_result->serial = key & 0x0FFFFFFF; |             if(subghz->txrx->transmitter) { | ||||||
|                 subghz->txrx->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
 |                 subghz_protocol_keeloq_create_data( | ||||||
|                 subghz->txrx->protocol_result->cnt = 0x0003; |                     subghz->txrx->transmitter->protocol_instance, | ||||||
|                 if(subghz_protocol_keeloq_set_manufacture_name( |                     subghz->txrx->fff_data, | ||||||
|                        subghz->txrx->protocol_result, "DoorHan")) { |                     key & 0x0FFFFFFF, | ||||||
|                     subghz->txrx->protocol_result->code_last_found = |                     0x2, | ||||||
|                         subghz_protocol_keeloq_gen_key(subghz->txrx->protocol_result); |                     0x0003, | ||||||
|  |                     "DoorHan", | ||||||
|  |                     subghz_frequencies[subghz_frequencies_433_92], | ||||||
|  |                     FuriHalSubGhzPresetOok650Async); | ||||||
|                 generated_protocol = true; |                 generated_protocol = true; | ||||||
|             } else { |             } else { | ||||||
|                 generated_protocol = false; |                 generated_protocol = false; | ||||||
|  |             } | ||||||
|  |             subghz_transmitter_free(subghz->txrx->transmitter); | ||||||
|  |             if(!generated_protocol) { | ||||||
|                 string_set( |                 string_set( | ||||||
|                     subghz->error_str, "Function requires\nan SD card with\nfresh databases."); |                     subghz->error_str, "Function requires\nan SD card with\nfresh databases."); | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); | ||||||
|             } |             } | ||||||
|             } |  | ||||||
|             break; |             break; | ||||||
|         default: |         default: | ||||||
|             return false; |             return false; | ||||||
| @ -190,10 +225,10 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(generated_protocol) { |         if(generated_protocol) { | ||||||
|             subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; |  | ||||||
|             subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; |  | ||||||
|             subghz_file_name_clear(subghz); |             subghz_file_name_clear(subghz); | ||||||
|             DOLPHIN_DEED(DolphinDeedSubGhzAddManually); |             DOLPHIN_DEED(DolphinDeedSubGhzAddManually); | ||||||
|  |             scene_manager_set_scene_state( | ||||||
|  |                 subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet); | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -7,10 +7,10 @@ void subghz_scene_show_error_callback(GuiButtonType result, InputType type, void | |||||||
| 
 | 
 | ||||||
|     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { |     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|             subghz->view_dispatcher, SubghzCustomEventSceneShowErrorOk); |             subghz->view_dispatcher, SubGhzCustomEventSceneShowErrorOk); | ||||||
|     } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { |     } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|             subghz->view_dispatcher, SubghzCustomEventSceneShowErrorBack); |             subghz->view_dispatcher, SubGhzCustomEventSceneShowErrorBack); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -28,7 +28,7 @@ void subghz_scene_show_error_on_enter(void* context) { | |||||||
|         FontSecondary, |         FontSecondary, | ||||||
|         string_get_cstr(subghz->error_str)); |         string_get_cstr(subghz->error_str)); | ||||||
|     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == |     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == | ||||||
|        SubghzCustomEventManagerSet) { |        SubGhzCustomEventManagerSet) { | ||||||
|         widget_add_button_element( |         widget_add_button_element( | ||||||
|             subghz->widget, GuiButtonTypeRight, "Ok", subghz_scene_show_error_callback, subghz); |             subghz->widget, GuiButtonTypeRight, "Ok", subghz_scene_show_error_callback, subghz); | ||||||
|     } |     } | ||||||
| @ -36,14 +36,14 @@ void subghz_scene_show_error_on_enter(void* context) { | |||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         subghz->widget, GuiButtonTypeLeft, "Back", subghz_scene_show_error_callback, subghz); |         subghz->widget, GuiButtonTypeLeft, "Back", subghz_scene_show_error_callback, subghz); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeBack) { |     if(event.type == SceneManagerEventTypeBack) { | ||||||
|         if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == |         if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == | ||||||
|            SubghzCustomEventManagerSet) { |            SubGhzCustomEventManagerSet) { | ||||||
|             return false; |             return false; | ||||||
|         } else { |         } else { | ||||||
|             scene_manager_search_and_switch_to_previous_scene( |             scene_manager_search_and_switch_to_previous_scene( | ||||||
| @ -51,15 +51,15 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { | |||||||
|         } |         } | ||||||
|         return true; |         return true; | ||||||
|     } else if(event.type == SceneManagerEventTypeCustom) { |     } else if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzCustomEventSceneShowErrorOk) { |         if(event.event == SubGhzCustomEventSceneShowErrorOk) { | ||||||
|             if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == |             if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == | ||||||
|                SubghzCustomEventManagerSet) { |                SubGhzCustomEventManagerSet) { | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzCustomEventSceneShowErrorBack) { |         } else if(event.event == SubGhzCustomEventSceneShowErrorBack) { | ||||||
|             if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == |             if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) == | ||||||
|                SubghzCustomEventManagerSet) { |                SubGhzCustomEventManagerSet) { | ||||||
|                 //exit app
 |                 //exit app
 | ||||||
|                 if(!scene_manager_previous_scene(subghz->scene_manager)) { |                 if(!scene_manager_previous_scene(subghz->scene_manager)) { | ||||||
|                     scene_manager_stop(subghz->scene_manager); |                     scene_manager_stop(subghz->scene_manager); | ||||||
| @ -78,7 +78,7 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) { | |||||||
| void subghz_scene_show_error_on_exit(void* context) { | void subghz_scene_show_error_on_exit(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     scene_manager_set_scene_state( |     scene_manager_set_scene_state( | ||||||
|         subghz->scene_manager, SubGhzSceneShowError, SubghzCustomEventManagerNoSet); |         subghz->scene_manager, SubGhzSceneShowError, SubGhzCustomEventManagerNoSet); | ||||||
|     widget_reset(subghz->widget); |     widget_reset(subghz->widget); | ||||||
|     string_reset(subghz->error_str); |     string_reset(subghz->error_str); | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
| 
 | 
 | ||||||
| void subghz_scene_show_error_sub_popup_callback(void* context) { | void subghz_scene_show_error_sub_popup_callback(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneShowErrorSub); |     view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneShowErrorSub); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_scene_show_error_sub_on_enter(void* context) { | void subghz_scene_show_error_sub_on_enter(void* context) { | ||||||
| @ -17,13 +17,13 @@ void subghz_scene_show_error_sub_on_enter(void* context) { | |||||||
|     popup_set_context(popup, subghz); |     popup_set_context(popup, subghz); | ||||||
|     popup_set_callback(popup, subghz_scene_show_error_sub_popup_callback); |     popup_set_callback(popup, subghz_scene_show_error_sub_popup_callback); | ||||||
|     popup_enable_timeout(popup); |     popup_enable_timeout(popup); | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_show_error_sub_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_show_error_sub_on_event(void* context, SceneManagerEvent event) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzCustomEventSceneShowErrorSub) { |         if(event.event == SubGhzCustomEventSceneShowErrorSub) { | ||||||
|             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; | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
| 
 | 
 | ||||||
| void subghz_scene_show_only_rx_popup_callback(void* context) { | void subghz_scene_show_only_rx_popup_callback(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneShowOnlyRX); |     view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneShowOnlyRX); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_scene_show_only_rx_on_enter(void* context) { | void subghz_scene_show_only_rx_on_enter(void* context) { | ||||||
| @ -23,13 +23,13 @@ void subghz_scene_show_only_rx_on_enter(void* context) { | |||||||
|     popup_set_context(popup, subghz); |     popup_set_context(popup, subghz); | ||||||
|     popup_set_callback(popup, subghz_scene_show_only_rx_popup_callback); |     popup_set_callback(popup, subghz_scene_show_only_rx_popup_callback); | ||||||
|     popup_enable_timeout(popup); |     popup_enable_timeout(popup); | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const bool subghz_scene_show_only_rx_on_event(void* context, SceneManagerEvent event) { | const bool subghz_scene_show_only_rx_on_event(void* context, SceneManagerEvent event) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzCustomEventSceneShowOnlyRX) { |         if(event.event == SubGhzCustomEventSceneShowOnlyRX) { | ||||||
|             scene_manager_previous_scene(subghz->scene_manager); |             scene_manager_previous_scene(subghz->scene_manager); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -48,7 +48,7 @@ void subghz_scene_start_on_enter(void* context) { | |||||||
|     submenu_set_selected_item( |     submenu_set_selected_item( | ||||||
|         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneStart)); |         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneStart)); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdMenu); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ void subghz_scene_test_on_enter(void* context) { | |||||||
|     submenu_set_selected_item( |     submenu_set_selected_item( | ||||||
|         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneTest)); |         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneTest)); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdMenu); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_test_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_test_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include "../views/subghz_test_carrier.h" | #include "../views/subghz_test_carrier.h" | ||||||
| 
 | 
 | ||||||
| void subghz_scene_test_carrier_callback(SubghzTestCarrierEvent event, void* context) { | void subghz_scene_test_carrier_callback(SubGhzTestCarrierEvent event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); |     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); | ||||||
| @ -11,13 +11,13 @@ void subghz_scene_test_carrier_on_enter(void* context) { | |||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     subghz_test_carrier_set_callback( |     subghz_test_carrier_set_callback( | ||||||
|         subghz->subghz_test_carrier, subghz_scene_test_carrier_callback, subghz); |         subghz->subghz_test_carrier, subghz_scene_test_carrier_callback, subghz); | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTestCarrier); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTestCarrier); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_test_carrier_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_test_carrier_on_event(void* context, SceneManagerEvent event) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzTestCarrierEventOnlyRx) { |         if(event.event == SubGhzTestCarrierEventOnlyRx) { | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include "../views/subghz_test_packet.h" | #include "../views/subghz_test_packet.h" | ||||||
| 
 | 
 | ||||||
| void subghz_scene_test_packet_callback(SubghzTestPacketEvent event, void* context) { | void subghz_scene_test_packet_callback(SubGhzTestPacketEvent event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); |     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); | ||||||
| @ -11,13 +11,13 @@ void subghz_scene_test_packet_on_enter(void* context) { | |||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     subghz_test_packet_set_callback( |     subghz_test_packet_set_callback( | ||||||
|         subghz->subghz_test_packet, subghz_scene_test_packet_callback, subghz); |         subghz->subghz_test_packet, subghz_scene_test_packet_callback, subghz); | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTestPacket); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTestPacket); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_test_packet_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_test_packet_on_event(void* context, SceneManagerEvent event) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzTestPacketEventOnlyRx) { |         if(event.event == SubGhzTestPacketEventOnlyRx) { | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include "../views/subghz_test_static.h" | #include "../views/subghz_test_static.h" | ||||||
| 
 | 
 | ||||||
| void subghz_scene_test_static_callback(SubghzTestStaticEvent event, void* context) { | void subghz_scene_test_static_callback(SubGhzTestStaticEvent event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); |     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); | ||||||
| @ -11,13 +11,13 @@ void subghz_scene_test_static_on_enter(void* context) { | |||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     subghz_test_static_set_callback( |     subghz_test_static_set_callback( | ||||||
|         subghz->subghz_test_static, subghz_scene_test_static_callback, subghz); |         subghz->subghz_test_static, subghz_scene_test_static_callback, subghz); | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewStatic); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdStatic); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_test_static_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_test_static_on_event(void* context, SceneManagerEvent event) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzTestStaticEventOnlyRx) { |         if(event.event == SubGhzTestStaticEventOnlyRx) { | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,18 +1,18 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include "../views/subghz_transmitter.h" | #include "../views/transmitter.h" | ||||||
| #include <lib/subghz/protocols/subghz_protocol_keeloq.h> |  | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void subghz_scene_transmitter_callback(SubghzCustomEvent event, void* context) { | void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); |     view_dispatcher_send_custom_event(subghz->view_dispatcher, event); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_transmitter_update_data_show(void* context) { | bool subghz_scene_transmitter_update_data_show(void* context) { | ||||||
|  |     //ToDo Fix
 | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 | 
 | ||||||
|     if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->get_upload_protocol) { |     if(subghz->txrx->decoder_result) { | ||||||
|         string_t key_str; |         string_t key_str; | ||||||
|         string_t frequency_str; |         string_t frequency_str; | ||||||
|         string_t modulation_str; |         string_t modulation_str; | ||||||
| @ -21,19 +21,18 @@ bool subghz_scene_transmitter_update_data_show(void* context) { | |||||||
|         string_init(frequency_str); |         string_init(frequency_str); | ||||||
|         string_init(modulation_str); |         string_init(modulation_str); | ||||||
|         uint8_t show_button = 0; |         uint8_t show_button = 0; | ||||||
|         subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, key_str); |  | ||||||
| 
 | 
 | ||||||
|         if((!strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) && |         subghz_protocol_decoder_base_deserialize( | ||||||
|            (!strcmp( |             subghz->txrx->decoder_result, subghz->txrx->fff_data); | ||||||
|                subghz_protocol_keeloq_get_manufacture_name(subghz->txrx->protocol_result), |         subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str); | ||||||
|                "Unknown"))) { | 
 | ||||||
|             show_button = 0; |         if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == | ||||||
|         } else { |            SubGhzProtocolFlag_Send) { | ||||||
|             show_button = 1; |             show_button = 1; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); |         subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); | ||||||
|         subghz_transmitter_add_data_to_show( |         subghz_view_transmitter_add_data_to_show( | ||||||
|             subghz->subghz_transmitter, |             subghz->subghz_transmitter, | ||||||
|             string_get_cstr(key_str), |             string_get_cstr(key_str), | ||||||
|             string_get_cstr(frequency_str), |             string_get_cstr(frequency_str), | ||||||
| @ -54,27 +53,27 @@ void subghz_scene_transmitter_on_enter(void* context) { | |||||||
|     DOLPHIN_DEED(DolphinDeedSubGhzSend); |     DOLPHIN_DEED(DolphinDeedSubGhzSend); | ||||||
|     if(!subghz_scene_transmitter_update_data_show(subghz)) { |     if(!subghz_scene_transmitter_update_data_show(subghz)) { | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|             subghz->view_dispatcher, SubghzCustomEventViewTransmitterError); |             subghz->view_dispatcher, SubGhzCustomEventViewTransmitterError); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     subghz_transmitter_set_callback( |     subghz_view_transmitter_set_callback( | ||||||
|         subghz->subghz_transmitter, subghz_scene_transmitter_callback, subghz); |         subghz->subghz_transmitter, subghz_scene_transmitter_callback, subghz); | ||||||
| 
 | 
 | ||||||
|     subghz->state_notifications = SubGhzNotificationStateIDLE; |     subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTransmitter); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzCustomEventViewTransmitterSendStart) { |         if(event.event == SubGhzCustomEventViewTransmitterSendStart) { | ||||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { |             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { | ||||||
|                 subghz_rx_end(subghz); |                 subghz_rx_end(subghz); | ||||||
|             } |             } | ||||||
|             if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || |             if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || | ||||||
|                (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { |                (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { | ||||||
|                 if(!subghz_tx_start(subghz)) { |                 if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) { | ||||||
|                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); |                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); | ||||||
|                 } else { |                 } else { | ||||||
|                     subghz->state_notifications = SubGhzNotificationStateTX; |                     subghz->state_notifications = SubGhzNotificationStateTX; | ||||||
| @ -82,19 +81,19 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzCustomEventViewTransmitterSendStop) { |         } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { | ||||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { |             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||||
|                 subghz_tx_stop(subghz); |                 subghz_tx_stop(subghz); | ||||||
|                 subghz_sleep(subghz); |                 subghz_sleep(subghz); | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzCustomEventViewTransmitterBack) { |         } else if(event.event == SubGhzCustomEventViewTransmitterBack) { | ||||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             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; | ||||||
|         } else if(event.event == SubghzCustomEventViewTransmitterError) { |         } else if(event.event == SubGhzCustomEventViewTransmitterError) { | ||||||
|             string_set(subghz->error_str, "Protocol not found"); |             string_set(subghz->error_str, "Protocol not found"); | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -85,80 +85,80 @@ SubGhz* subghz_alloc() { | |||||||
|     // SubMenu
 |     // SubMenu
 | ||||||
|     subghz->submenu = submenu_alloc(); |     subghz->submenu = submenu_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, SubGhzViewMenu, submenu_get_view(subghz->submenu)); |         subghz->view_dispatcher, SubGhzViewIdMenu, submenu_get_view(subghz->submenu)); | ||||||
| 
 | 
 | ||||||
|     // Receiver
 |     // Receiver
 | ||||||
|     subghz->subghz_receiver = subghz_receiver_alloc(); |     subghz->subghz_receiver = subghz_view_receiver_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, |         subghz->view_dispatcher, | ||||||
|         SubGhzViewReceiver, |         SubGhzViewIdReceiver, | ||||||
|         subghz_receiver_get_view(subghz->subghz_receiver)); |         subghz_view_receiver_get_view(subghz->subghz_receiver)); | ||||||
| 
 | 
 | ||||||
|     // Popup
 |     // Popup
 | ||||||
|     subghz->popup = popup_alloc(); |     subghz->popup = popup_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, SubGhzViewPopup, popup_get_view(subghz->popup)); |         subghz->view_dispatcher, SubGhzViewIdPopup, popup_get_view(subghz->popup)); | ||||||
| 
 | 
 | ||||||
|     // Text Input
 |     // Text Input
 | ||||||
|     subghz->text_input = text_input_alloc(); |     subghz->text_input = text_input_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, SubGhzViewTextInput, text_input_get_view(subghz->text_input)); |         subghz->view_dispatcher, SubGhzViewIdTextInput, text_input_get_view(subghz->text_input)); | ||||||
| 
 | 
 | ||||||
|     // Custom Widget
 |     // Custom Widget
 | ||||||
|     subghz->widget = widget_alloc(); |     subghz->widget = widget_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, SubGhzViewWidget, widget_get_view(subghz->widget)); |         subghz->view_dispatcher, SubGhzViewIdWidget, widget_get_view(subghz->widget)); | ||||||
| 
 | 
 | ||||||
|     //Dialog
 |     //Dialog
 | ||||||
|     subghz->dialogs = furi_record_open("dialogs"); |     subghz->dialogs = furi_record_open("dialogs"); | ||||||
| 
 | 
 | ||||||
|     // Transmitter
 |     // Transmitter
 | ||||||
|     subghz->subghz_transmitter = subghz_transmitter_alloc(); |     subghz->subghz_transmitter = subghz_view_transmitter_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, |         subghz->view_dispatcher, | ||||||
|         SubGhzViewTransmitter, |         SubGhzViewIdTransmitter, | ||||||
|         subghz_transmitter_get_view(subghz->subghz_transmitter)); |         subghz_view_transmitter_get_view(subghz->subghz_transmitter)); | ||||||
| 
 | 
 | ||||||
|     // Variable Item List
 |     // Variable Item List
 | ||||||
|     subghz->variable_item_list = variable_item_list_alloc(); |     subghz->variable_item_list = variable_item_list_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, |         subghz->view_dispatcher, | ||||||
|         SubGhzViewVariableItemList, |         SubGhzViewIdVariableItemList, | ||||||
|         variable_item_list_get_view(subghz->variable_item_list)); |         variable_item_list_get_view(subghz->variable_item_list)); | ||||||
| 
 | 
 | ||||||
|     // Frequency Analyzer
 |     // Frequency Analyzer
 | ||||||
|     subghz->subghz_frequency_analyzer = subghz_frequency_analyzer_alloc(); |     subghz->subghz_frequency_analyzer = subghz_frequency_analyzer_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, |         subghz->view_dispatcher, | ||||||
|         SubGhzViewFrequencyAnalyzer, |         SubGhzViewIdFrequencyAnalyzer, | ||||||
|         subghz_frequency_analyzer_get_view(subghz->subghz_frequency_analyzer)); |         subghz_frequency_analyzer_get_view(subghz->subghz_frequency_analyzer)); | ||||||
| 
 | 
 | ||||||
|     // Read RAW
 |     // Read RAW
 | ||||||
|     subghz->subghz_read_raw = subghz_read_raw_alloc(); |     subghz->subghz_read_raw = subghz_read_raw_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, |         subghz->view_dispatcher, | ||||||
|         SubGhzViewReadRAW, |         SubGhzViewIdReadRAW, | ||||||
|         subghz_read_raw_get_view(subghz->subghz_read_raw)); |         subghz_read_raw_get_view(subghz->subghz_read_raw)); | ||||||
| 
 | 
 | ||||||
|     // Carrier Test Module
 |     // Carrier Test Module
 | ||||||
|     subghz->subghz_test_carrier = subghz_test_carrier_alloc(); |     subghz->subghz_test_carrier = subghz_test_carrier_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, |         subghz->view_dispatcher, | ||||||
|         SubGhzViewTestCarrier, |         SubGhzViewIdTestCarrier, | ||||||
|         subghz_test_carrier_get_view(subghz->subghz_test_carrier)); |         subghz_test_carrier_get_view(subghz->subghz_test_carrier)); | ||||||
| 
 | 
 | ||||||
|     // Packet Test
 |     // Packet Test
 | ||||||
|     subghz->subghz_test_packet = subghz_test_packet_alloc(); |     subghz->subghz_test_packet = subghz_test_packet_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, |         subghz->view_dispatcher, | ||||||
|         SubGhzViewTestPacket, |         SubGhzViewIdTestPacket, | ||||||
|         subghz_test_packet_get_view(subghz->subghz_test_packet)); |         subghz_test_packet_get_view(subghz->subghz_test_packet)); | ||||||
| 
 | 
 | ||||||
|     // Static send
 |     // Static send
 | ||||||
|     subghz->subghz_test_static = subghz_test_static_alloc(); |     subghz->subghz_test_static = subghz_test_static_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, |         subghz->view_dispatcher, | ||||||
|         SubGhzViewStatic, |         SubGhzViewIdStatic, | ||||||
|         subghz_test_static_get_view(subghz->subghz_test_static)); |         subghz_test_static_get_view(subghz->subghz_test_static)); | ||||||
| 
 | 
 | ||||||
|     //init Worker & Protocol & History
 |     //init Worker & Protocol & History
 | ||||||
| @ -170,12 +170,21 @@ SubGhz* subghz_alloc() { | |||||||
|     subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; |     subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||||
|     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->parser = subghz_parser_alloc(); |     subghz->txrx->fff_data = flipper_format_string_alloc(); | ||||||
|  | 
 | ||||||
|  |     subghz->txrx->environment = subghz_environment_alloc(); | ||||||
|  |     subghz_environment_set_came_atomo_rainbow_table_file_name( | ||||||
|  |         subghz->txrx->environment, "/ext/subghz/assets/came_atomo"); | ||||||
|  |     subghz_environment_set_nice_flor_s_rainbow_table_file_name( | ||||||
|  |         subghz->txrx->environment, "/ext/subghz/assets/nice_flor_s"); | ||||||
|  |     subghz->txrx->receiver = subghz_receiver_alloc(subghz->txrx->environment); | ||||||
|  |     subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable); | ||||||
|  | 
 | ||||||
|     subghz_worker_set_overrun_callback( |     subghz_worker_set_overrun_callback( | ||||||
|         subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_parser_reset); |         subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); | ||||||
|     subghz_worker_set_pair_callback( |     subghz_worker_set_pair_callback( | ||||||
|         subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_parser_parse); |         subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); | ||||||
|     subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->parser); |     subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->receiver); | ||||||
| 
 | 
 | ||||||
|     //Init Error_str
 |     //Init Error_str
 | ||||||
|     string_init(subghz->error_str); |     string_init(subghz->error_str); | ||||||
| @ -187,54 +196,54 @@ void subghz_free(SubGhz* subghz) { | |||||||
|     furi_assert(subghz); |     furi_assert(subghz); | ||||||
| 
 | 
 | ||||||
|     // Packet Test
 |     // Packet Test
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTestPacket); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket); | ||||||
|     subghz_test_packet_free(subghz->subghz_test_packet); |     subghz_test_packet_free(subghz->subghz_test_packet); | ||||||
| 
 | 
 | ||||||
|     // Carrier Test
 |     // Carrier Test
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTestCarrier); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestCarrier); | ||||||
|     subghz_test_carrier_free(subghz->subghz_test_carrier); |     subghz_test_carrier_free(subghz->subghz_test_carrier); | ||||||
| 
 | 
 | ||||||
|     // Static
 |     // Static
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewStatic); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdStatic); | ||||||
|     subghz_test_static_free(subghz->subghz_test_static); |     subghz_test_static_free(subghz->subghz_test_static); | ||||||
| 
 | 
 | ||||||
|     // Receiver
 |     // Receiver
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewReceiver); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdReceiver); | ||||||
|     subghz_receiver_free(subghz->subghz_receiver); |     subghz_view_receiver_free(subghz->subghz_receiver); | ||||||
| 
 | 
 | ||||||
|     // TextInput
 |     // TextInput
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTextInput); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTextInput); | ||||||
|     text_input_free(subghz->text_input); |     text_input_free(subghz->text_input); | ||||||
| 
 | 
 | ||||||
|     // Custom Widget
 |     // Custom Widget
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewWidget); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdWidget); | ||||||
|     widget_free(subghz->widget); |     widget_free(subghz->widget); | ||||||
| 
 | 
 | ||||||
|     //Dialog
 |     //Dialog
 | ||||||
|     furi_record_close("dialogs"); |     furi_record_close("dialogs"); | ||||||
| 
 | 
 | ||||||
|     // Transmitter
 |     // Transmitter
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTransmitter); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTransmitter); | ||||||
|     subghz_transmitter_free(subghz->subghz_transmitter); |     subghz_view_transmitter_free(subghz->subghz_transmitter); | ||||||
| 
 | 
 | ||||||
|     // Variable Item List
 |     // Variable Item List
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewVariableItemList); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); | ||||||
|     variable_item_list_free(subghz->variable_item_list); |     variable_item_list_free(subghz->variable_item_list); | ||||||
| 
 | 
 | ||||||
|     // Frequency Analyzer
 |     // Frequency Analyzer
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewFrequencyAnalyzer); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdFrequencyAnalyzer); | ||||||
|     subghz_frequency_analyzer_free(subghz->subghz_frequency_analyzer); |     subghz_frequency_analyzer_free(subghz->subghz_frequency_analyzer); | ||||||
| 
 | 
 | ||||||
|     // Read RAW
 |     // Read RAW
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewReadRAW); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdReadRAW); | ||||||
|     subghz_read_raw_free(subghz->subghz_read_raw); |     subghz_read_raw_free(subghz->subghz_read_raw); | ||||||
| 
 | 
 | ||||||
|     // Submenu
 |     // Submenu
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewMenu); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdMenu); | ||||||
|     submenu_free(subghz->submenu); |     submenu_free(subghz->submenu); | ||||||
| 
 | 
 | ||||||
|     // Popup
 |     // Popup
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewPopup); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdPopup); | ||||||
|     popup_free(subghz->popup); |     popup_free(subghz->popup); | ||||||
| 
 | 
 | ||||||
|     // Scene manager
 |     // Scene manager
 | ||||||
| @ -248,8 +257,10 @@ void subghz_free(SubGhz* subghz) { | |||||||
|     subghz->gui = NULL; |     subghz->gui = NULL; | ||||||
| 
 | 
 | ||||||
|     //Worker & Protocol & History
 |     //Worker & Protocol & History
 | ||||||
|     subghz_parser_free(subghz->txrx->parser); |     subghz_receiver_free(subghz->txrx->receiver); | ||||||
|  |     subghz_environment_free(subghz->txrx->environment); | ||||||
|     subghz_worker_free(subghz->txrx->worker); |     subghz_worker_free(subghz->txrx->worker); | ||||||
|  |     flipper_format_free(subghz->txrx->fff_data); | ||||||
|     subghz_history_free(subghz->txrx->history); |     subghz_history_free(subghz->txrx->history); | ||||||
|     free(subghz->txrx); |     free(subghz->txrx); | ||||||
| 
 | 
 | ||||||
| @ -268,12 +279,10 @@ int32_t subghz_app(void* p) { | |||||||
|     SubGhz* subghz = subghz_alloc(); |     SubGhz* subghz = subghz_alloc(); | ||||||
| 
 | 
 | ||||||
|     //Load database
 |     //Load database
 | ||||||
|     bool load_database = |     bool load_database = subghz_environment_load_keystore( | ||||||
|         subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/assets/keeloq_mfcodes"); |         subghz->txrx->environment, "/ext/subghz/assets/keeloq_mfcodes"); | ||||||
|     subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/assets/keeloq_mfcodes_user"); |     subghz_environment_load_keystore( | ||||||
|     subghz_parser_load_nice_flor_s_file(subghz->txrx->parser, "/ext/subghz/assets/nice_flor_s_rx"); |         subghz->txrx->environment, "/ext/subghz/assets/keeloq_mfcodes_user"); | ||||||
|     subghz_parser_load_came_atomo_file(subghz->txrx->parser, "/ext/subghz/assets/came_atomo"); |  | ||||||
| 
 |  | ||||||
|     // Check argument and run corresponding scene
 |     // Check argument and run corresponding scene
 | ||||||
|     if(p && subghz_key_load(subghz, p)) { |     if(p && subghz_key_load(subghz, p)) { | ||||||
|         string_t filename; |         string_t filename; | ||||||
| @ -282,8 +291,7 @@ int32_t subghz_app(void* p) { | |||||||
|         path_extract_filename_no_ext(p, filename); |         path_extract_filename_no_ext(p, filename); | ||||||
|         strcpy(subghz->file_name, string_get_cstr(filename)); |         strcpy(subghz->file_name, string_get_cstr(filename)); | ||||||
|         string_clear(filename); |         string_clear(filename); | ||||||
| 
 |         if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { | ||||||
|         if((!strcmp(subghz->txrx->protocol_result->name, "RAW"))) { |  | ||||||
|             //Load Raw TX
 |             //Load Raw TX
 | ||||||
|             subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; |             subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); | ||||||
| @ -296,7 +304,7 @@ int32_t subghz_app(void* p) { | |||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); | ||||||
|         } else { |         } else { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 subghz->scene_manager, SubGhzSceneShowError, SubghzCustomEventManagerSet); |                 subghz->scene_manager, SubGhzSceneShowError, SubGhzCustomEventManagerSet); | ||||||
|             string_set( |             string_set( | ||||||
|                 subghz->error_str, |                 subghz->error_str, | ||||||
|                 "No SD card or\ndatabase found.\nSome app function\nmay be reduced."); |                 "No SD card or\ndatabase found.\nSome app function\nmay be reduced."); | ||||||
|  | |||||||
| @ -5,14 +5,15 @@ | |||||||
| #include <stream_buffer.h> | #include <stream_buffer.h> | ||||||
| 
 | 
 | ||||||
| #include <lib/toolbox/args.h> | #include <lib/toolbox/args.h> | ||||||
| #include <lib/subghz/subghz_parser.h> |  | ||||||
| #include <lib/subghz/subghz_keystore.h> | #include <lib/subghz/subghz_keystore.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_common.h> | 
 | ||||||
| #include <lib/subghz/protocols/subghz_protocol_princeton.h> | #include <lib/subghz/receiver.h> | ||||||
|  | #include <lib/subghz/transmitter.h> | ||||||
| 
 | 
 | ||||||
| #include "helpers/subghz_chat.h" | #include "helpers/subghz_chat.h" | ||||||
| 
 | 
 | ||||||
| #include <notification/notification_messages.h> | #include <notification/notification_messages.h> | ||||||
|  | #include <flipper_format/flipper_format_i.h> | ||||||
| 
 | 
 | ||||||
| #define SUBGHZ_FREQUENCY_RANGE_STR \ | #define SUBGHZ_FREQUENCY_RANGE_STR \ | ||||||
|     "299999755...348000000 or 386999938...464000000 or 778999847...928000000" |     "299999755...348000000 or 386999938...464000000 or 778999847...928000000" | ||||||
| @ -134,21 +135,35 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) { | |||||||
|         key, |         key, | ||||||
|         repeat); |         repeat); | ||||||
| 
 | 
 | ||||||
|     SubGhzDecoderPrinceton* protocol = subghz_decoder_princeton_alloc(); |     string_t flipper_format_string; | ||||||
|     protocol->common.code_last_found = key; |     string_init_printf( | ||||||
|     protocol->common.code_last_count_bit = 24; |         flipper_format_string, | ||||||
|  |         "Protocol: Princeton\n" | ||||||
|  |         "Bit: 24\n" | ||||||
|  |         "Key: 00 00 00 00 00 %X %X %X\n" | ||||||
|  |         "TE: 403\n" | ||||||
|  |         "Repeat: %d\n", | ||||||
|  |         (uint8_t)((key >> 16) & 0xFF), | ||||||
|  |         (uint8_t)((key >> 8) & 0xFF), | ||||||
|  |         (uint8_t)(key & 0xFF), | ||||||
|  |         repeat); | ||||||
|  |     FlipperFormat* flipper_format = flipper_format_string_alloc(); | ||||||
|  |     Stream* stream = flipper_format_get_raw_stream(flipper_format); | ||||||
|  |     stream_clean(stream); | ||||||
|  |     stream_write_cstring(stream, string_get_cstr(flipper_format_string)); | ||||||
| 
 | 
 | ||||||
|     SubGhzProtocolCommonEncoder* encoder = subghz_protocol_encoder_common_alloc(); |     SubGhzEnvironment* environment = subghz_environment_alloc(); | ||||||
|     encoder->repeat = repeat; | 
 | ||||||
|  |     SubGhzTransmitter* transmitter = subghz_transmitter_alloc_init(environment, "Princeton"); | ||||||
|  |     subghz_transmitter_deserialize(transmitter, flipper_format); | ||||||
| 
 | 
 | ||||||
|     subghz_protocol_princeton_send_key(protocol, encoder); |  | ||||||
|     furi_hal_subghz_reset(); |     furi_hal_subghz_reset(); | ||||||
|     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); |     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); | ||||||
|     frequency = furi_hal_subghz_set_frequency_and_path(frequency); |     frequency = furi_hal_subghz_set_frequency_and_path(frequency); | ||||||
| 
 | 
 | ||||||
|     furi_hal_power_suppress_charge_enter(); |     furi_hal_power_suppress_charge_enter(); | ||||||
| 
 | 
 | ||||||
|     furi_hal_subghz_start_async_tx(subghz_protocol_encoder_common_yield, encoder); |     furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter); | ||||||
| 
 | 
 | ||||||
|     while(!(furi_hal_subghz_is_async_tx_complete() || cli_cmd_interrupt_received(cli))) { |     while(!(furi_hal_subghz_is_async_tx_complete() || cli_cmd_interrupt_received(cli))) { | ||||||
|         printf("."); |         printf("."); | ||||||
| @ -160,8 +175,9 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) { | |||||||
| 
 | 
 | ||||||
|     furi_hal_power_suppress_charge_exit(); |     furi_hal_power_suppress_charge_exit(); | ||||||
| 
 | 
 | ||||||
|     subghz_decoder_princeton_free(protocol); |     flipper_format_free(flipper_format); | ||||||
|     subghz_protocol_encoder_common_free(encoder); |     subghz_transmitter_free(transmitter); | ||||||
|  |     subghz_environment_free(environment); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
| @ -170,7 +186,7 @@ typedef struct { | |||||||
|     size_t packet_count; |     size_t packet_count; | ||||||
| } SubGhzCliCommandRx; | } SubGhzCliCommandRx; | ||||||
| 
 | 
 | ||||||
| static void subghz_cli_command_rx_callback(bool level, uint32_t duration, void* context) { | static void subghz_cli_command_rx_capture_callback(bool level, uint32_t duration, void* context) { | ||||||
|     SubGhzCliCommandRx* instance = context; |     SubGhzCliCommandRx* instance = context; | ||||||
| 
 | 
 | ||||||
|     BaseType_t xHigherPriorityTaskWoken = pdFALSE; |     BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||||||
| @ -185,10 +201,19 @@ static void subghz_cli_command_rx_callback(bool level, uint32_t duration, void* | |||||||
|     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); |     portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void subghz_cli_command_rx_text_callback(string_t text, void* context) { | static void subghz_cli_command_rx_callback( | ||||||
|  |     SubGhzReceiver* receiver, | ||||||
|  |     SubGhzProtocolDecoderBase* decoder_base, | ||||||
|  |     void* context) { | ||||||
|     SubGhzCliCommandRx* instance = context; |     SubGhzCliCommandRx* instance = context; | ||||||
|     instance->packet_count++; |     instance->packet_count++; | ||||||
|  | 
 | ||||||
|  |     string_t text; | ||||||
|  |     string_init(text); | ||||||
|  |     subghz_protocol_decoder_base_get_string(decoder_base, text); | ||||||
|  |     subghz_receiver_reset(receiver); | ||||||
|     printf("%s", string_get_cstr(text)); |     printf("%s", string_get_cstr(text)); | ||||||
|  |     string_clear(text); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_cli_command_rx(Cli* cli, string_t args, void* context) { | void subghz_cli_command_rx(Cli* cli, string_t args, void* context) { | ||||||
| @ -214,12 +239,16 @@ 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); | ||||||
| 
 | 
 | ||||||
|     SubGhzParser* parser = subghz_parser_alloc(); |     SubGhzEnvironment* environment = subghz_environment_alloc(); | ||||||
|     subghz_parser_load_keeloq_file(parser, "/ext/subghz/assets/keeloq_mfcodes"); |     subghz_environment_load_keystore(environment, "/ext/subghz/assets/keeloq_mfcodes"); | ||||||
|     subghz_parser_load_keeloq_file(parser, "/ext/subghz/assets/keeloq_mfcodes_user"); |     subghz_environment_set_came_atomo_rainbow_table_file_name( | ||||||
|     subghz_parser_load_nice_flor_s_file(parser, "/ext/subghz/assets/nice_flor_s_rx"); |         environment, "/ext/subghz/assets/came_atomo"); | ||||||
|     subghz_parser_load_came_atomo_file(parser, "/ext/subghz/assets/came_atomo"); |     subghz_environment_set_nice_flor_s_rainbow_table_file_name( | ||||||
|     subghz_parser_enable_dump_text(parser, subghz_cli_command_rx_text_callback, instance); |         environment, "/ext/subghz/assets/nice_flor_s"); | ||||||
|  | 
 | ||||||
|  |     SubGhzReceiver* receiver = subghz_receiver_alloc(environment); | ||||||
|  |     subghz_receiver_set_filter(receiver, SubGhzProtocolFlag_Decodable); | ||||||
|  |     subghz_receiver_set_rx_callback(receiver, subghz_cli_command_rx_callback, instance); | ||||||
| 
 | 
 | ||||||
|     // Configure radio
 |     // Configure radio
 | ||||||
|     furi_hal_subghz_reset(); |     furi_hal_subghz_reset(); | ||||||
| @ -230,7 +259,7 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) { | |||||||
|     furi_hal_power_suppress_charge_enter(); |     furi_hal_power_suppress_charge_enter(); | ||||||
| 
 | 
 | ||||||
|     // Prepare and start RX
 |     // Prepare and start RX
 | ||||||
|     furi_hal_subghz_start_async_rx(subghz_cli_command_rx_callback, instance); |     furi_hal_subghz_start_async_rx(subghz_cli_command_rx_capture_callback, instance); | ||||||
| 
 | 
 | ||||||
|     // Wait for packets to arrive
 |     // Wait for packets to arrive
 | ||||||
|     printf("Listening at %lu. Press CTRL+C to stop\r\n", frequency); |     printf("Listening at %lu. Press CTRL+C to stop\r\n", frequency); | ||||||
| @ -241,11 +270,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_parser_reset(parser); |                 subghz_receiver_reset(receiver); | ||||||
|             } 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_parser_parse(parser, level, duration); |                 subghz_receiver_decode(receiver, level, duration); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -259,7 +288,8 @@ 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_parser_free(parser); |     subghz_receiver_free(receiver); | ||||||
|  |     subghz_environment_free(environment); | ||||||
|     vStreamBufferDelete(instance->stream); |     vStreamBufferDelete(instance->stream); | ||||||
|     free(instance); |     free(instance); | ||||||
| } | } | ||||||
| @ -416,7 +446,7 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) { | |||||||
|     string_t sysmsg; |     string_t sysmsg; | ||||||
|     string_init(sysmsg); |     string_init(sysmsg); | ||||||
|     bool exit = false; |     bool exit = false; | ||||||
|     SubghzChatEvent chat_event; |     SubGhzChatEvent chat_event; | ||||||
| 
 | 
 | ||||||
|     NotificationApp* notification = furi_record_open("notification"); |     NotificationApp* notification = furi_record_open("notification"); | ||||||
| 
 | 
 | ||||||
| @ -428,10 +458,10 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) { | |||||||
|     while(!exit) { |     while(!exit) { | ||||||
|         chat_event = subghz_chat_worker_get_event_chat(subghz_chat); |         chat_event = subghz_chat_worker_get_event_chat(subghz_chat); | ||||||
|         switch(chat_event.event) { |         switch(chat_event.event) { | ||||||
|         case SubghzChatEventInputData: |         case SubGhzChatEventInputData: | ||||||
|             if(chat_event.c == CliSymbolAsciiETX) { |             if(chat_event.c == CliSymbolAsciiETX) { | ||||||
|                 printf("\r\n"); |                 printf("\r\n"); | ||||||
|                 chat_event.event = SubghzChatEventUserExit; |                 chat_event.event = SubGhzChatEventUserExit; | ||||||
|                 subghz_chat_worker_put_event_chat(subghz_chat, &chat_event); |                 subghz_chat_worker_put_event_chat(subghz_chat, &chat_event); | ||||||
|                 break; |                 break; | ||||||
|             } else if( |             } else if( | ||||||
| @ -478,7 +508,7 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) { | |||||||
|                 fflush(stdout); |                 fflush(stdout); | ||||||
|                 string_push_back(input, chat_event.c); |                 string_push_back(input, chat_event.c); | ||||||
|                 break; |                 break; | ||||||
|             case SubghzChatEventRXData: |             case SubGhzChatEventRXData: | ||||||
|                 do { |                 do { | ||||||
|                     memset(message, 0x00, message_max_len); |                     memset(message, 0x00, message_max_len); | ||||||
|                     size_t len = subghz_chat_worker_read(subghz_chat, message, message_max_len); |                     size_t len = subghz_chat_worker_read(subghz_chat, message, message_max_len); | ||||||
| @ -497,10 +527,10 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) { | |||||||
|                     } |                     } | ||||||
|                 } while(subghz_chat_worker_available(subghz_chat)); |                 } while(subghz_chat_worker_available(subghz_chat)); | ||||||
|                 break; |                 break; | ||||||
|             case SubghzChatEventNewMessage: |             case SubGhzChatEventNewMessage: | ||||||
|                 notification_message(notification, &sequence_single_vibro); |                 notification_message(notification, &sequence_single_vibro); | ||||||
|                 break; |                 break; | ||||||
|             case SubghzChatEventUserEntrance: |             case SubGhzChatEventUserEntrance: | ||||||
|                 string_printf( |                 string_printf( | ||||||
|                     sysmsg, |                     sysmsg, | ||||||
|                     "\033[0;34m%s joined chat.\033[0m\r\n", |                     "\033[0;34m%s joined chat.\033[0m\r\n", | ||||||
| @ -510,7 +540,7 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) { | |||||||
|                     (uint8_t*)string_get_cstr(sysmsg), |                     (uint8_t*)string_get_cstr(sysmsg), | ||||||
|                     strlen(string_get_cstr(sysmsg))); |                     strlen(string_get_cstr(sysmsg))); | ||||||
|                 break; |                 break; | ||||||
|             case SubghzChatEventUserExit: |             case SubGhzChatEventUserExit: | ||||||
|                 string_printf( |                 string_printf( | ||||||
|                     sysmsg, "\033[0;31m%s left chat.\033[0m\r\n", furi_hal_version_get_name_ptr()); |                     sysmsg, "\033[0;31m%s left chat.\033[0m\r\n", furi_hal_version_get_name_ptr()); | ||||||
|                 subghz_chat_worker_write( |                 subghz_chat_worker_write( | ||||||
|  | |||||||
| @ -1,70 +1,83 @@ | |||||||
| #include "subghz_history.h" | #include "subghz_history.h" | ||||||
| #include <lib/subghz/protocols/subghz_protocol_keeloq.h> | #include <lib/subghz/receiver.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_star_line.h> | #include <lib/subghz/protocols/came.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_princeton.h> |  | ||||||
| #include <lib/subghz/protocols/subghz_protocol_somfy_keytis.h> |  | ||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <m-string.h> | #include <m-string.h> | ||||||
| 
 | 
 | ||||||
| #define SUBGHZ_HISTORY_MAX 50 | #define SUBGHZ_HISTORY_MAX 50 | ||||||
|  | #define TAG "SubGhzHistory" | ||||||
| 
 | 
 | ||||||
| typedef struct SubGhzHistoryStruct SubGhzHistoryStruct; | typedef struct { | ||||||
| 
 |     string_t item_str; | ||||||
| struct SubGhzHistoryStruct { |     FlipperFormat* flipper_string; | ||||||
|     const char* name; |     uint8_t type; | ||||||
|     const char* manufacture_name; |  | ||||||
|     uint8_t type_protocol; |  | ||||||
|     uint8_t code_count_bit; |  | ||||||
|     uint64_t code_found; |  | ||||||
|     uint32_t data1; |  | ||||||
|     FuriHalSubGhzPreset preset; |     FuriHalSubGhzPreset preset; | ||||||
|     uint32_t real_frequency; |     uint32_t frequency; | ||||||
| }; | } SubGhzHistoryItem; | ||||||
|  | 
 | ||||||
|  | ARRAY_DEF(SubGhzHistoryItemArray, SubGhzHistoryItem, M_POD_OPLIST) | ||||||
|  | 
 | ||||||
|  | #define M_OPL_SubGhzHistoryItemArray_t() ARRAY_OPLIST(SubGhzHistoryItemArray, M_POD_OPLIST) | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     SubGhzHistoryItemArray_t data; | ||||||
|  | } SubGhzHistoryStruct; | ||||||
| 
 | 
 | ||||||
| struct SubGhzHistory { | struct SubGhzHistory { | ||||||
|     uint32_t last_update_timestamp; |     uint32_t last_update_timestamp; | ||||||
|     uint16_t last_index_write; |     uint16_t last_index_write; | ||||||
|     uint64_t code_last_found; |     uint8_t code_last_hash_data; | ||||||
|     SubGhzHistoryStruct history[SUBGHZ_HISTORY_MAX]; |     string_t tmp_string; | ||||||
|     SubGhzProtocolCommonLoad data; |     SubGhzHistoryStruct* history; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| SubGhzHistory* subghz_history_alloc(void) { | SubGhzHistory* subghz_history_alloc(void) { | ||||||
|     SubGhzHistory* instance = malloc(sizeof(SubGhzHistory)); |     SubGhzHistory* instance = malloc(sizeof(SubGhzHistory)); | ||||||
|  |     string_init(instance->tmp_string); | ||||||
|  |     instance->history = malloc(sizeof(SubGhzHistoryStruct)); | ||||||
|  |     SubGhzHistoryItemArray_init(instance->history->data); | ||||||
|     return instance; |     return instance; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_history_free(SubGhzHistory* instance) { | void subghz_history_free(SubGhzHistory* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|  |     string_clear(instance->tmp_string); | ||||||
|  |     for | ||||||
|  |         M_EACH(item, instance->history->data, SubGhzHistoryItemArray_t) { | ||||||
|  |             string_clear(item->item_str); | ||||||
|  |             flipper_format_free(item->flipper_string); | ||||||
|  |             item->type = 0; | ||||||
|  |         } | ||||||
|  |     SubGhzHistoryItemArray_clear(instance->history->data); | ||||||
|  |     free(instance->history); | ||||||
|     free(instance); |     free(instance); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_history_set_frequency_preset( |  | ||||||
|     SubGhzHistory* instance, |  | ||||||
|     uint16_t idx, |  | ||||||
|     uint32_t frequency, |  | ||||||
|     FuriHalSubGhzPreset preset) { |  | ||||||
|     furi_assert(instance); |  | ||||||
|     if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return; |  | ||||||
|     instance->history[idx].preset = preset; |  | ||||||
|     instance->history[idx].real_frequency = frequency; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx) { | uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     return instance->history[idx].real_frequency; |     SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx); | ||||||
|  |     return item->frequency; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx) { | FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     return instance->history[idx].preset; |     SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx); | ||||||
|  |     return item->preset; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_history_reset(SubGhzHistory* instance) { | void subghz_history_reset(SubGhzHistory* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|  |     string_reset(instance->tmp_string); | ||||||
|  |     for | ||||||
|  |         M_EACH(item, instance->history->data, SubGhzHistoryItemArray_t) { | ||||||
|  |             string_clear(item->item_str); | ||||||
|  |             flipper_format_free(item->flipper_string); | ||||||
|  |             item->type = 0; | ||||||
|  |         } | ||||||
|  |     SubGhzHistoryItemArray_reset(instance->history->data); | ||||||
|     instance->last_index_write = 0; |     instance->last_index_write = 0; | ||||||
|     instance->code_last_found = 0; |     instance->code_last_hash_data = 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t subghz_history_get_item(SubGhzHistory* instance) { | uint16_t subghz_history_get_item(SubGhzHistory* instance) { | ||||||
| @ -74,20 +87,29 @@ uint16_t subghz_history_get_item(SubGhzHistory* instance) { | |||||||
| 
 | 
 | ||||||
| uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx) { | uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     return instance->history[idx].type_protocol; |     SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx); | ||||||
|  |     return item->type; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx) { | const char* subghz_history_get_protocol_name(SubGhzHistory* instance, uint16_t idx) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     return instance->history[idx].name; |     SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx); | ||||||
|  |     flipper_format_rewind(item->flipper_string); | ||||||
|  |     if(!flipper_format_read_string(item->flipper_string, "Protocol", instance->tmp_string)) { | ||||||
|  |         FURI_LOG_E(TAG, "Missing Protocol"); | ||||||
|  |         string_reset(instance->tmp_string); | ||||||
|  |     } | ||||||
|  |     return string_get_cstr(instance->tmp_string); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx) { | FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     instance->data.code_found = instance->history[idx].code_found; |     SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx); | ||||||
|     instance->data.code_count_bit = instance->history[idx].code_count_bit; |     if(item->flipper_string) { | ||||||
|     instance->data.param1 = instance->history[idx].data1; |         return item->flipper_string; | ||||||
|     return &instance->data; |     } else { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
| } | } | ||||||
| bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output) { | bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
| @ -99,34 +121,10 @@ bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output | |||||||
|         string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX); |         string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX); | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx) { |  | ||||||
|     if(instance->history[idx].code_count_bit < 33) { |  | ||||||
|         string_printf( |  | ||||||
|             output, |  | ||||||
|             "%s %lX", |  | ||||||
|             instance->history[idx].name, |  | ||||||
|             (uint32_t)(instance->history[idx].code_found & 0xFFFFFFFF)); |  | ||||||
|     } else { |  | ||||||
|         string_t str_buff; |  | ||||||
|         string_init(str_buff); |  | ||||||
|         if(strcmp(instance->history[idx].name, "KeeLoq") == 0) { |  | ||||||
|             string_set(str_buff, "KL "); |  | ||||||
|             string_cat(str_buff, instance->history[idx].manufacture_name); |  | ||||||
|         } else if(strcmp(instance->history[idx].name, "Star Line") == 0) { |  | ||||||
|             string_set(str_buff, "SL "); |  | ||||||
|             string_cat(str_buff, instance->history[idx].manufacture_name); |  | ||||||
|         } else { |  | ||||||
|             string_set(str_buff, instance->history[idx].name); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         string_printf( | void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx) { | ||||||
|             output, |     SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx); | ||||||
|             "%s %lX%08lX", |     string_set(output, item->item_str); | ||||||
|             string_get_cstr(str_buff), |  | ||||||
|             (uint32_t)(instance->history[idx].code_found >> 32), |  | ||||||
|             (uint32_t)(instance->history[idx].code_found & 0xFFFFFFFF)); |  | ||||||
|         string_clear(str_buff); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_history_add_to_history( | bool subghz_history_add_to_history( | ||||||
| @ -136,41 +134,85 @@ bool subghz_history_add_to_history( | |||||||
|     FuriHalSubGhzPreset preset) { |     FuriHalSubGhzPreset preset) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhzProtocolCommon* protocol = context; |  | ||||||
| 
 | 
 | ||||||
|     if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return false; |     if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return false; | ||||||
|     if((instance->code_last_found == (protocol->code_last_found & 0xFFFF0FFFFFFFFFFF)) && | 
 | ||||||
|  |     SubGhzProtocolDecoderBase* decoder_base = context; | ||||||
|  |     if((instance->code_last_hash_data == | ||||||
|  |         subghz_protocol_decoder_base_get_hash_data(decoder_base)) && | ||||||
|        ((millis() - instance->last_update_timestamp) < 500)) { |        ((millis() - instance->last_update_timestamp) < 500)) { | ||||||
|         instance->last_update_timestamp = millis(); |         instance->last_update_timestamp = millis(); | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     instance->code_last_found = protocol->code_last_found & 0xFFFF0FFFFFFFFFFF; |     instance->code_last_hash_data = subghz_protocol_decoder_base_get_hash_data(decoder_base); | ||||||
|     instance->last_update_timestamp = millis(); |     instance->last_update_timestamp = millis(); | ||||||
| 
 | 
 | ||||||
|     instance->history[instance->last_index_write].real_frequency = frequency; |     string_t text; | ||||||
|     instance->history[instance->last_index_write].preset = preset; |     string_init(text); | ||||||
|     instance->history[instance->last_index_write].data1 = 0; |     SubGhzHistoryItem* item = SubGhzHistoryItemArray_push_raw(instance->history->data); | ||||||
|     instance->history[instance->last_index_write].manufacture_name = NULL; |     item->type = decoder_base->protocol->type; | ||||||
|     instance->history[instance->last_index_write].name = protocol->name; |     item->frequency = frequency; | ||||||
|     instance->history[instance->last_index_write].code_count_bit = protocol->code_last_count_bit; |     item->preset = preset; | ||||||
|     instance->history[instance->last_index_write].code_found = protocol->code_last_found; | 
 | ||||||
|     if(strcmp(protocol->name, "KeeLoq") == 0) { |     string_init(item->item_str); | ||||||
|         instance->history[instance->last_index_write].manufacture_name = |     item->flipper_string = flipper_format_string_alloc(); | ||||||
|             subghz_protocol_keeloq_find_and_get_manufacture_name(protocol); |     subghz_protocol_decoder_base_serialize(decoder_base, item->flipper_string, frequency, preset); | ||||||
|     } else if(strcmp(protocol->name, "Star Line") == 0) { | 
 | ||||||
|         instance->history[instance->last_index_write].manufacture_name = |     do { | ||||||
|             subghz_protocol_star_line_find_and_get_manufacture_name(protocol); |         if(!flipper_format_rewind(item->flipper_string)) { | ||||||
|     } else if(strcmp(protocol->name, "Princeton") == 0) { |             FURI_LOG_E(TAG, "Rewind error"); | ||||||
|         instance->history[instance->last_index_write].data1 = |             break; | ||||||
|             subghz_protocol_princeton_get_te(protocol); |  | ||||||
|     } else if(strcmp(protocol->name, "Somfy Keytis") == 0) { |  | ||||||
|         instance->history[instance->last_index_write].data1 = |  | ||||||
|             subghz_protocol_somfy_keytis_get_press_duration(protocol); |  | ||||||
|         } |         } | ||||||
|  |         if(!flipper_format_read_string(item->flipper_string, "Protocol", instance->tmp_string)) { | ||||||
|  |             FURI_LOG_E(TAG, "Missing Protocol"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if(!strcmp(string_get_cstr(instance->tmp_string), "KeeLoq")) { | ||||||
|  |             string_set(instance->tmp_string, "KL "); | ||||||
|  |             if(!flipper_format_read_string(item->flipper_string, "Manufacture", text)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Missing Protocol"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             string_cat(instance->tmp_string, text); | ||||||
|  |         } else if(!strcmp(string_get_cstr(instance->tmp_string), "Star Line")) { | ||||||
|  |             string_set(instance->tmp_string, "SL "); | ||||||
|  |             if(!flipper_format_read_string(item->flipper_string, "Manufacture", text)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Missing Protocol"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             string_cat(instance->tmp_string, text); | ||||||
|  |         } | ||||||
|  |         if(!flipper_format_rewind(item->flipper_string)) { | ||||||
|  |             FURI_LOG_E(TAG, "Rewind error"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         uint8_t key_data[sizeof(uint64_t)] = {0}; | ||||||
|  |         if(!flipper_format_read_hex(item->flipper_string, "Key", key_data, sizeof(uint64_t))) { | ||||||
|  |             FURI_LOG_E(TAG, "Missing Key"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         uint64_t data = 0; | ||||||
|  |         for(uint8_t i = 0; i < sizeof(uint64_t); i++) { | ||||||
|  |             data = (data << 8) | key_data[i]; | ||||||
|  |         } | ||||||
|  |         if(!(uint32_t)(data >> 32)) { | ||||||
|  |             string_printf( | ||||||
|  |                 item->item_str, | ||||||
|  |                 "%s %lX", | ||||||
|  |                 string_get_cstr(instance->tmp_string), | ||||||
|  |                 (uint32_t)(data & 0xFFFFFFFF)); | ||||||
|  |         } else { | ||||||
|  |             string_printf( | ||||||
|  |                 item->item_str, | ||||||
|  |                 "%s %lX%08lX", | ||||||
|  |                 string_get_cstr(instance->tmp_string), | ||||||
|  |                 (uint32_t)(data >> 32), | ||||||
|  |                 (uint32_t)(data & 0xFFFFFFFF)); | ||||||
|  |         } | ||||||
|  |     } while(false); | ||||||
| 
 | 
 | ||||||
|     instance->history[instance->last_index_write].type_protocol = protocol->type_protocol; |     string_clear(text); | ||||||
| 
 |  | ||||||
|     instance->last_index_write++; |     instance->last_index_write++; | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,7 +1,10 @@ | |||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <lib/subghz/protocols/subghz_protocol_common.h> | #include <math.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include <furi_hal.h> | ||||||
|  | #include <lib/flipper_format/flipper_format.h> | ||||||
| 
 | 
 | ||||||
| typedef struct SubGhzHistory SubGhzHistory; | typedef struct SubGhzHistory SubGhzHistory; | ||||||
| 
 | 
 | ||||||
| @ -23,19 +26,6 @@ void subghz_history_free(SubGhzHistory* instance); | |||||||
|  */ |  */ | ||||||
| void subghz_history_reset(SubGhzHistory* instance); | void subghz_history_reset(SubGhzHistory* instance); | ||||||
| 
 | 
 | ||||||
| /** Set frequency and preset to history[idx]
 |  | ||||||
|  *  |  | ||||||
|  * @param instance  - SubGhzHistory instance |  | ||||||
|  * @param idx       - record index   |  | ||||||
|  * @param frequency - frequency Hz |  | ||||||
|  * @param preset    - FuriHalSubGhzPreset preset |  | ||||||
|  */ |  | ||||||
| void subghz_history_set_frequency_preset( |  | ||||||
|     SubGhzHistory* instance, |  | ||||||
|     uint16_t idx, |  | ||||||
|     uint32_t frequency, |  | ||||||
|     FuriHalSubGhzPreset preset); |  | ||||||
| 
 |  | ||||||
| /** Get frequency to history[idx]
 | /** Get frequency to history[idx]
 | ||||||
|  *  |  *  | ||||||
|  * @param instance  - SubGhzHistory instance |  * @param instance  - SubGhzHistory instance | ||||||
| @ -73,7 +63,7 @@ uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx); | |||||||
|  * @param idx       - record index   |  * @param idx       - record index   | ||||||
|  * @return name      - const char* name protocol   |  * @return name      - const char* name protocol   | ||||||
|  */ |  */ | ||||||
| const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx); | const char* subghz_history_get_protocol_name(SubGhzHistory* instance, uint16_t idx); | ||||||
| 
 | 
 | ||||||
| /** Get string item menu to history[idx]
 | /** Get string item menu to history[idx]
 | ||||||
|  *  |  *  | ||||||
| @ -111,4 +101,4 @@ bool subghz_history_add_to_history( | |||||||
|  * @param idx       - record index |  * @param idx       - record index | ||||||
|  * @return SubGhzProtocolCommonLoad* |  * @return SubGhzProtocolCommonLoad* | ||||||
|  */ |  */ | ||||||
| SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx); | FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx); | ||||||
|  | |||||||
| @ -8,9 +8,16 @@ | |||||||
| #include <notification/notification_messages.h> | #include <notification/notification_messages.h> | ||||||
| #include <flipper_format/flipper_format.h> | #include <flipper_format/flipper_format.h> | ||||||
| #include "../notification/notification.h" | #include "../notification/notification.h" | ||||||
| #include "views/subghz_receiver.h" | #include "views/receiver.h" | ||||||
| 
 | 
 | ||||||
| bool subghz_set_pteset(SubGhz* subghz, const char* preset) { | #include <flipper_format/flipper_format_i.h> | ||||||
|  | #include <lib/toolbox/stream/stream.h> | ||||||
|  | #include <lib/subghz/protocols/raw.h> | ||||||
|  | #include <lib/toolbox/path.h> | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhz" | ||||||
|  | 
 | ||||||
|  | bool subghz_set_preset(SubGhz* subghz, const char* preset) { | ||||||
|     if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { |     if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { | ||||||
|         subghz->txrx->preset = FuriHalSubGhzPresetOok270Async; |         subghz->txrx->preset = FuriHalSubGhzPresetOok270Async; | ||||||
|     } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { |     } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { | ||||||
| @ -20,36 +27,12 @@ bool subghz_set_pteset(SubGhz* subghz, const char* preset) { | |||||||
|     } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { |     } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { | ||||||
|         subghz->txrx->preset = FuriHalSubGhzPreset2FSKDev476Async; |         subghz->txrx->preset = FuriHalSubGhzPreset2FSKDev476Async; | ||||||
|     } else { |     } else { | ||||||
|         FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unknown preset"); |         FURI_LOG_E(TAG, "Unknown preset"); | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_get_preset_name(SubGhz* subghz, string_t preset) { |  | ||||||
|     const char* preset_name; |  | ||||||
|     switch(subghz->txrx->preset) { |  | ||||||
|     case FuriHalSubGhzPresetOok270Async: |  | ||||||
|         preset_name = "FuriHalSubGhzPresetOok270Async"; |  | ||||||
|         break; |  | ||||||
|     case FuriHalSubGhzPresetOok650Async: |  | ||||||
|         preset_name = "FuriHalSubGhzPresetOok650Async"; |  | ||||||
|         break; |  | ||||||
|     case FuriHalSubGhzPreset2FSKDev238Async: |  | ||||||
|         preset_name = "FuriHalSubGhzPreset2FSKDev238Async"; |  | ||||||
|         break; |  | ||||||
|     case FuriHalSubGhzPreset2FSKDev476Async: |  | ||||||
|         preset_name = "FuriHalSubGhzPreset2FSKDev476Async"; |  | ||||||
|         break; |  | ||||||
|     default: |  | ||||||
|         FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unknown preset"); |  | ||||||
|         return false; |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|     string_set(preset, preset_name); |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void subghz_get_frequency_modulation(SubGhz* subghz, string_t frequency, string_t modulation) { | void subghz_get_frequency_modulation(SubGhz* subghz, string_t frequency, string_t modulation) { | ||||||
|     furi_assert(subghz); |     furi_assert(subghz); | ||||||
|     if(frequency != NULL) { |     if(frequency != NULL) { | ||||||
| @ -143,16 +126,33 @@ void subghz_sleep(SubGhz* subghz) { | |||||||
|     subghz->txrx->txrx_state = SubGhzTxRxStateSleep; |     subghz->txrx->txrx_state = SubGhzTxRxStateSleep; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_tx_start(SubGhz* subghz) { | bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) { | ||||||
|     furi_assert(subghz); |     furi_assert(subghz); | ||||||
| 
 | 
 | ||||||
|     bool ret = false; |     bool ret = false; | ||||||
|     subghz->txrx->encoder = subghz_protocol_encoder_common_alloc(); |     string_t temp_str; | ||||||
|     subghz->txrx->encoder->repeat = 200; //max repeat with the button held down
 |     string_init(temp_str); | ||||||
|     //get upload
 |     uint32_t repeat = 200; | ||||||
|     if(subghz->txrx->protocol_result->get_upload_protocol) { |     do { | ||||||
|         if(subghz->txrx->protocol_result->get_upload_protocol( |         if(!flipper_format_rewind(flipper_format)) { | ||||||
|                subghz->txrx->protocol_result, subghz->txrx->encoder)) { |             FURI_LOG_E(TAG, "Rewind error"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { | ||||||
|  |             FURI_LOG_E(TAG, "Missing Protocol"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         //ToDo FIX
 | ||||||
|  |         if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { | ||||||
|  |             FURI_LOG_E(TAG, "Unable Repeat"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         subghz->txrx->transmitter = | ||||||
|  |             subghz_transmitter_alloc_init(subghz->txrx->environment, string_get_cstr(temp_str)); | ||||||
|  | 
 | ||||||
|  |         if(subghz->txrx->transmitter) { | ||||||
|  |             if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format)) { | ||||||
|                 if(subghz->txrx->preset) { |                 if(subghz->txrx->preset) { | ||||||
|                     subghz_begin(subghz, subghz->txrx->preset); |                     subghz_begin(subghz, subghz->txrx->preset); | ||||||
|                 } else { |                 } else { | ||||||
| @ -163,18 +163,20 @@ bool subghz_tx_start(SubGhz* subghz) { | |||||||
|                 } else { |                 } else { | ||||||
|                     ret = subghz_tx(subghz, 433920000); |                     ret = subghz_tx(subghz, 433920000); | ||||||
|                 } |                 } | ||||||
| 
 |  | ||||||
|                 if(ret) { |                 if(ret) { | ||||||
|                     //Start TX
 |                     //Start TX
 | ||||||
|                     furi_hal_subghz_start_async_tx( |                     furi_hal_subghz_start_async_tx( | ||||||
|                     subghz_protocol_encoder_common_yield, subghz->txrx->encoder); |                         subghz_transmitter_yield, subghz->txrx->transmitter); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if(!ret) { |         if(!ret) { | ||||||
|         subghz_protocol_encoder_common_free(subghz->txrx->encoder); |             subghz_transmitter_free(subghz->txrx->transmitter); | ||||||
|             subghz_idle(subghz); |             subghz_idle(subghz); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |     } while(false); | ||||||
|  |     string_clear(temp_str); | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -183,13 +185,15 @@ void subghz_tx_stop(SubGhz* subghz) { | |||||||
|     furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateTx); |     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_transmitter_stop(subghz->txrx->transmitter); | ||||||
|     subghz_idle(subghz); |     subghz_transmitter_free(subghz->txrx->transmitter); | ||||||
|  | 
 | ||||||
|     //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 == SubGhzProtocolCommonTypeDynamic) && |     if((subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) && | ||||||
|        (strcmp(subghz->file_name, ""))) { |        (strcmp(subghz->file_name, ""))) { | ||||||
|         subghz_save_protocol_to_file(subghz, subghz->file_name); |         subghz_save_protocol_to_file(subghz, subghz->txrx->fff_data, subghz->file_name); | ||||||
|     } |     } | ||||||
|  |     subghz_idle(subghz); | ||||||
|     notification_message(subghz->notifications, &sequence_reset_red); |     notification_message(subghz->notifications, &sequence_reset_red); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -198,24 +202,23 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { | |||||||
|     furi_assert(file_path); |     furi_assert(file_path); | ||||||
| 
 | 
 | ||||||
|     Storage* storage = furi_record_open("storage"); |     Storage* storage = furi_record_open("storage"); | ||||||
|     FlipperFormat* flipper_format = flipper_format_file_alloc(storage); |     FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); | ||||||
|  |     Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data); | ||||||
| 
 | 
 | ||||||
|     // Load device data
 |  | ||||||
|     bool loaded = false; |     bool loaded = false; | ||||||
|     string_t path; |  | ||||||
|     string_init_set_str(path, file_path); |  | ||||||
|     string_t temp_str; |     string_t temp_str; | ||||||
|     string_init(temp_str); |     string_init(temp_str); | ||||||
|     uint32_t version; |     uint32_t version; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(!flipper_format_file_open_existing(flipper_format, string_get_cstr(path))) { |         stream_clean(fff_data_stream); | ||||||
|             FURI_LOG_E( |         if(!flipper_format_file_open_existing(fff_data_file, file_path)) { | ||||||
|                 SUBGHZ_PARSER_TAG, "Unable to open file for read: %s", string_get_cstr(path)); |             FURI_LOG_E(TAG, "Error open file %s", file_path); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if(!flipper_format_read_header(flipper_format, temp_str, &version)) { | 
 | ||||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing or incorrect header"); |         if(!flipper_format_read_header(fff_data_file, temp_str, &version)) { | ||||||
|  |             FURI_LOG_E(TAG, "Missing or incorrect header"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -223,50 +226,59 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { | |||||||
|             (!strcmp(string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) && |             (!strcmp(string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) && | ||||||
|            version == SUBGHZ_KEY_FILE_VERSION) { |            version == SUBGHZ_KEY_FILE_VERSION) { | ||||||
|         } else { |         } else { | ||||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Type or version mismatch"); |             FURI_LOG_E(TAG, "Type or version mismatch"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(!flipper_format_read_uint32( |         if(!flipper_format_read_uint32( | ||||||
|                flipper_format, "Frequency", (uint32_t*)&subghz->txrx->frequency, 1)) { |                fff_data_file, "Frequency", (uint32_t*)&subghz->txrx->frequency, 1)) { | ||||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing Frequency"); |             FURI_LOG_E(TAG, "Missing Frequency"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(!flipper_format_read_string(flipper_format, "Preset", temp_str)) { |         if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { | ||||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing Preset"); |             FURI_LOG_E(TAG, "Missing Preset"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if(!subghz_set_pteset(subghz, string_get_cstr(temp_str))) { |         if(!subghz_set_preset(subghz, string_get_cstr(temp_str))) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { |         if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { | ||||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing Protocol"); |             FURI_LOG_E(TAG, "Missing Protocol"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  |         if(!strcmp(string_get_cstr(temp_str), "RAW")) { | ||||||
|  |             //if RAW
 | ||||||
|  |             string_t file_name; | ||||||
|  |             string_init(file_name); | ||||||
|  |             path_extract_filename_no_ext(file_path, file_name); | ||||||
|  |             subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, string_get_cstr(file_name)); | ||||||
|  |             string_clear(file_name); | ||||||
|  | 
 | ||||||
|  |         } else { | ||||||
|  |             stream_copy_full( | ||||||
|  |                 flipper_format_get_raw_stream(fff_data_file), | ||||||
|  |                 flipper_format_get_raw_stream(subghz->txrx->fff_data)); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         subghz->txrx->protocol_result = |         subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( | ||||||
|             subghz_parser_get_by_name(subghz->txrx->parser, string_get_cstr(temp_str)); |             subghz->txrx->receiver, string_get_cstr(temp_str)); | ||||||
|         if(subghz->txrx->protocol_result == NULL) { |         if(subghz->txrx->decoder_result) { | ||||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "This type of protocol was not found"); |             subghz_protocol_decoder_base_deserialize( | ||||||
|             break; |                 subghz->txrx->decoder_result, subghz->txrx->fff_data); | ||||||
|         } |  | ||||||
|         if(!subghz->txrx->protocol_result->to_load_protocol_from_file( |  | ||||||
|                flipper_format, subghz->txrx->protocol_result, string_get_cstr(path))) { |  | ||||||
|             break; |  | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         loaded = true; |         loaded = true; | ||||||
|     } while(0); |     } while(0); | ||||||
| 
 | 
 | ||||||
|     if(!loaded) { |     if(!loaded) { | ||||||
|         dialog_message_show_storage_error(subghz->dialogs, "Cannot parse\nfile"); |         dialog_message_show_storage_error(subghz->dialogs, "Cannot parse\nfile"); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     string_clear(temp_str); |     string_clear(temp_str); | ||||||
|     string_clear(path); |     //string_clear(path);
 | ||||||
| 
 |     flipper_format_free(fff_data_file); | ||||||
|     flipper_format_free(flipper_format); |  | ||||||
| 
 |  | ||||||
|     furi_record_close("storage"); |     furi_record_close("storage"); | ||||||
| 
 | 
 | ||||||
|     return loaded; |     return loaded; | ||||||
| @ -295,24 +307,26 @@ bool subghz_get_next_name_file(SubGhz* subghz) { | |||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name) { | bool subghz_save_protocol_to_file( | ||||||
|  |     SubGhz* subghz, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     const char* dev_name) { | ||||||
|     furi_assert(subghz); |     furi_assert(subghz); | ||||||
|     furi_assert(subghz->txrx->protocol_result); |     furi_assert(flipper_format); | ||||||
|  |     furi_assert(dev_name); | ||||||
| 
 | 
 | ||||||
|     Storage* storage = furi_record_open("storage"); |     Storage* storage = furi_record_open("storage"); | ||||||
|     FlipperFormat* flipper_format = flipper_format_file_alloc(storage); |     Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); | ||||||
|  | 
 | ||||||
|     string_t dev_file_name; |     string_t dev_file_name; | ||||||
|     string_init(dev_file_name); |     string_init(dev_file_name); | ||||||
|     string_t temp_str; |  | ||||||
|     string_init(temp_str); |  | ||||||
|     bool saved = false; |     bool saved = false; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         // Checking that this type of people can be saved
 |         //removing additional fields
 | ||||||
|         if(subghz->txrx->protocol_result->to_save_file == NULL) { |         flipper_format_delete_key(flipper_format, "Repeat"); | ||||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "No saving of this type of keys"); |         flipper_format_delete_key(flipper_format, "Manufacture"); | ||||||
|             break; | 
 | ||||||
|         } |  | ||||||
|         // Create subghz folder directory if necessary
 |         // Create subghz folder directory if necessary
 | ||||||
|         if(!storage_simply_mkdir(storage, SUBGHZ_APP_FOLDER)) { |         if(!storage_simply_mkdir(storage, SUBGHZ_APP_FOLDER)) { | ||||||
|             dialog_message_show_storage_error(subghz->dialogs, "Cannot create\nfolder"); |             dialog_message_show_storage_error(subghz->dialogs, "Cannot create\nfolder"); | ||||||
| @ -325,47 +339,16 @@ bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name) { | |||||||
|         if(!storage_simply_remove(storage, string_get_cstr(dev_file_name))) { |         if(!storage_simply_remove(storage, string_get_cstr(dev_file_name))) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 |         //ToDo check Write
 | ||||||
|         // Open file
 |         stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); | ||||||
|         if(!flipper_format_file_open_always(flipper_format, string_get_cstr(dev_file_name))) { |         stream_save_to_file( | ||||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to open file for write: %s", dev_file_name); |             flipper_format_stream, storage, string_get_cstr(dev_file_name), FSOM_CREATE_ALWAYS); | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(!flipper_format_write_header_cstr( |  | ||||||
|                flipper_format, SUBGHZ_KEY_FILE_TYPE, SUBGHZ_KEY_FILE_VERSION)) { |  | ||||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add header"); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(!flipper_format_write_uint32(flipper_format, "Frequency", &subghz->txrx->frequency, 1)) { |  | ||||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add Frequency"); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(!subghz_get_preset_name(subghz, temp_str)) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         if(!flipper_format_write_string_cstr(flipper_format, "Preset", string_get_cstr(temp_str))) { |  | ||||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add Preset"); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(!subghz->txrx->protocol_result->to_save_file( |  | ||||||
|                subghz->txrx->protocol_result, flipper_format)) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         saved = true; |         saved = true; | ||||||
|     } while(0); |     } while(0); | ||||||
| 
 | 
 | ||||||
|     string_clear(temp_str); |  | ||||||
|     string_clear(dev_file_name); |     string_clear(dev_file_name); | ||||||
| 
 |  | ||||||
|     flipper_format_free(flipper_format); |  | ||||||
| 
 |  | ||||||
|     furi_record_close("storage"); |     furi_record_close("storage"); | ||||||
| 
 |  | ||||||
|     return saved; |     return saved; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -501,7 +484,7 @@ void subghz_hopper_update(SubGhz* subghz) { | |||||||
|         subghz_rx_end(subghz); |         subghz_rx_end(subghz); | ||||||
|     }; |     }; | ||||||
|     if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { |     if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { | ||||||
|         subghz_parser_reset(subghz->txrx->parser); |         subghz_receiver_reset(subghz->txrx->receiver); | ||||||
|         subghz->txrx->frequency = subghz_hopper_frequencies[subghz->txrx->hopper_idx_frequency]; |         subghz->txrx->frequency = subghz_hopper_frequencies[subghz->txrx->hopper_idx_frequency]; | ||||||
|         subghz_rx(subghz, subghz->txrx->frequency); |         subghz_rx(subghz, subghz->txrx->frequency); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,8 +1,8 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "subghz.h" | #include "subghz.h" | ||||||
| #include "views/subghz_receiver.h" | #include "views/receiver.h" | ||||||
| #include "views/subghz_transmitter.h" | #include "views/transmitter.h" | ||||||
| #include "views/subghz_frequency_analyzer.h" | #include "views/subghz_frequency_analyzer.h" | ||||||
| #include "views/subghz_read_raw.h" | #include "views/subghz_read_raw.h" | ||||||
| 
 | 
 | ||||||
| @ -26,8 +26,9 @@ | |||||||
| 
 | 
 | ||||||
| #include <lib/subghz/subghz_worker.h> | #include <lib/subghz/subghz_worker.h> | ||||||
| 
 | 
 | ||||||
| #include <lib/subghz/subghz_parser.h> | #include <lib/subghz/receiver.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_common.h> | #include <lib/subghz/transmitter.h> | ||||||
|  | 
 | ||||||
| #include "subghz_history.h" | #include "subghz_history.h" | ||||||
| 
 | 
 | ||||||
| #include <gui/modules/variable_item_list.h> | #include <gui/modules/variable_item_list.h> | ||||||
| @ -79,9 +80,13 @@ typedef enum { | |||||||
| 
 | 
 | ||||||
| struct SubGhzTxRx { | struct SubGhzTxRx { | ||||||
|     SubGhzWorker* worker; |     SubGhzWorker* worker; | ||||||
|     SubGhzParser* parser; | 
 | ||||||
|     SubGhzProtocolCommon* protocol_result; |     SubGhzEnvironment* environment; | ||||||
|     SubGhzProtocolCommonEncoder* encoder; |     SubGhzReceiver* receiver; | ||||||
|  |     SubGhzTransmitter* transmitter; | ||||||
|  |     SubGhzProtocolDecoderBase* decoder_result; | ||||||
|  |     FlipperFormat* fff_data; | ||||||
|  | 
 | ||||||
|     uint32_t frequency; |     uint32_t frequency; | ||||||
|     FuriHalSubGhzPreset preset; |     FuriHalSubGhzPreset preset; | ||||||
|     SubGhzHistory* history; |     SubGhzHistory* history; | ||||||
| @ -113,46 +118,48 @@ struct SubGhz { | |||||||
|     char file_name_tmp[SUBGHZ_TEXT_STORE_SIZE + 1]; |     char file_name_tmp[SUBGHZ_TEXT_STORE_SIZE + 1]; | ||||||
|     SubGhzNotificationState state_notifications; |     SubGhzNotificationState state_notifications; | ||||||
| 
 | 
 | ||||||
|     SubghzReceiver* subghz_receiver; |     SubGhzViewReceiver* subghz_receiver; | ||||||
|     SubghzTransmitter* subghz_transmitter; |     SubGhzViewTransmitter* subghz_transmitter; | ||||||
|     VariableItemList* variable_item_list; |     VariableItemList* variable_item_list; | ||||||
| 
 | 
 | ||||||
|     SubghzFrequencyAnalyzer* subghz_frequency_analyzer; |     SubGhzFrequencyAnalyzer* subghz_frequency_analyzer; | ||||||
|     SubghzReadRAW* subghz_read_raw; |     SubGhzReadRAW* subghz_read_raw; | ||||||
|     SubghzTestStatic* subghz_test_static; |     SubGhzTestStatic* subghz_test_static; | ||||||
|     SubghzTestCarrier* subghz_test_carrier; |     SubGhzTestCarrier* subghz_test_carrier; | ||||||
|     SubghzTestPacket* subghz_test_packet; |     SubGhzTestPacket* subghz_test_packet; | ||||||
|     string_t error_str; |     string_t error_str; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubGhzViewMenu, |     SubGhzViewIdMenu, | ||||||
|  |     SubGhzViewIdReceiver, | ||||||
|  |     SubGhzViewIdPopup, | ||||||
|  |     SubGhzViewIdTextInput, | ||||||
|  |     SubGhzViewIdWidget, | ||||||
|  |     SubGhzViewIdTransmitter, | ||||||
|  |     SubGhzViewIdVariableItemList, | ||||||
|  |     SubGhzViewIdFrequencyAnalyzer, | ||||||
|  |     SubGhzViewIdReadRAW, | ||||||
| 
 | 
 | ||||||
|     SubGhzViewReceiver, |     SubGhzViewIdStatic, | ||||||
|     SubGhzViewPopup, |     SubGhzViewIdTestCarrier, | ||||||
|     SubGhzViewTextInput, |     SubGhzViewIdTestPacket, | ||||||
|     SubGhzViewWidget, | } SubGhzViewId; | ||||||
|     SubGhzViewTransmitter, |  | ||||||
|     SubGhzViewVariableItemList, |  | ||||||
|     SubGhzViewFrequencyAnalyzer, |  | ||||||
|     SubGhzViewReadRAW, |  | ||||||
|     SubGhzViewStatic, |  | ||||||
|     SubGhzViewTestCarrier, |  | ||||||
|     SubGhzViewTestPacket, |  | ||||||
| } SubGhzView; |  | ||||||
| 
 | 
 | ||||||
| bool subghz_set_pteset(SubGhz* subghz, const char* preset); | bool subghz_set_preset(SubGhz* subghz, const char* preset); | ||||||
| bool subghz_get_preset_name(SubGhz* subghz, string_t preset); |  | ||||||
| void subghz_get_frequency_modulation(SubGhz* subghz, string_t frequency, string_t modulation); | void subghz_get_frequency_modulation(SubGhz* subghz, string_t frequency, string_t modulation); | ||||||
| void subghz_begin(SubGhz* subghz, FuriHalSubGhzPreset preset); | void subghz_begin(SubGhz* subghz, FuriHalSubGhzPreset preset); | ||||||
| uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency); | uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency); | ||||||
| void subghz_rx_end(SubGhz* subghz); | void subghz_rx_end(SubGhz* subghz); | ||||||
| void subghz_sleep(SubGhz* subghz); | void subghz_sleep(SubGhz* subghz); | ||||||
| bool subghz_tx_start(SubGhz* subghz); | bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format); | ||||||
| void subghz_tx_stop(SubGhz* subghz); | void subghz_tx_stop(SubGhz* subghz); | ||||||
| bool subghz_key_load(SubGhz* subghz, const char* file_path); | bool subghz_key_load(SubGhz* subghz, const char* file_path); | ||||||
| bool subghz_get_next_name_file(SubGhz* subghz); | bool subghz_get_next_name_file(SubGhz* subghz); | ||||||
| bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name); | bool subghz_save_protocol_to_file( | ||||||
|  |     SubGhz* subghz, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     const char* dev_name); | ||||||
| bool subghz_load_protocol_from_file(SubGhz* subghz); | bool subghz_load_protocol_from_file(SubGhz* subghz); | ||||||
| bool subghz_rename_file(SubGhz* subghz); | bool subghz_rename_file(SubGhz* subghz); | ||||||
| bool subghz_delete_file(SubGhz* subghz); | bool subghz_delete_file(SubGhz* subghz); | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "subghz_receiver.h" | #include "receiver.h" | ||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| #include <math.h> | #include <math.h> | ||||||
| 
 | 
 | ||||||
| @ -29,14 +29,14 @@ struct SubGhzReceiverHistory { | |||||||
| typedef struct SubGhzReceiverHistory SubGhzReceiverHistory; | typedef struct SubGhzReceiverHistory SubGhzReceiverHistory; | ||||||
| 
 | 
 | ||||||
| static const Icon* ReceiverItemIcons[] = { | static const Icon* ReceiverItemIcons[] = { | ||||||
|     [SubGhzProtocolCommonTypeUnknown] = &I_Quest_7x8, |     [SubGhzProtocolTypeUnknown] = &I_Quest_7x8, | ||||||
|     [SubGhzProtocolCommonTypeStatic] = &I_Unlock_7x8, |     [SubGhzProtocolTypeStatic] = &I_Unlock_7x8, | ||||||
|     [SubGhzProtocolCommonTypeDynamic] = &I_Lock_7x8, |     [SubGhzProtocolTypeDynamic] = &I_Lock_7x8, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct SubghzReceiver { | struct SubGhzViewReceiver { | ||||||
|     View* view; |     View* view; | ||||||
|     SubghzReceiverCallback callback; |     SubGhzViewReceiverCallback callback; | ||||||
|     void* context; |     void* context; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -48,11 +48,11 @@ typedef struct { | |||||||
|     uint16_t idx; |     uint16_t idx; | ||||||
|     uint16_t list_offset; |     uint16_t list_offset; | ||||||
|     uint16_t history_item; |     uint16_t history_item; | ||||||
| } SubghzReceiverModel; | } SubGhzViewReceiverModel; | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_set_callback( | void subghz_view_receiver_set_callback( | ||||||
|     SubghzReceiver* subghz_receiver, |     SubGhzViewReceiver* subghz_receiver, | ||||||
|     SubghzReceiverCallback callback, |     SubGhzViewReceiverCallback callback, | ||||||
|     void* context) { |     void* context) { | ||||||
|     furi_assert(subghz_receiver); |     furi_assert(subghz_receiver); | ||||||
|     furi_assert(callback); |     furi_assert(callback); | ||||||
| @ -60,11 +60,11 @@ void subghz_receiver_set_callback( | |||||||
|     subghz_receiver->context = context; |     subghz_receiver->context = context; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) { | static void subghz_view_receiver_update_offset(SubGhzViewReceiver* subghz_receiver) { | ||||||
|     furi_assert(subghz_receiver); |     furi_assert(subghz_receiver); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubGhzViewReceiverModel * model) { | ||||||
|             size_t history_item = model->history_item; |             size_t history_item = model->history_item; | ||||||
|             uint16_t bounds = history_item > 3 ? 2 : history_item; |             uint16_t bounds = history_item > 3 ? 2 : history_item; | ||||||
| 
 | 
 | ||||||
| @ -79,13 +79,13 @@ static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) { | |||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_add_item_to_menu( | void subghz_view_receiver_add_item_to_menu( | ||||||
|     SubghzReceiver* subghz_receiver, |     SubGhzViewReceiver* subghz_receiver, | ||||||
|     const char* name, |     const char* name, | ||||||
|     uint8_t type) { |     uint8_t type) { | ||||||
|     furi_assert(subghz_receiver); |     furi_assert(subghz_receiver); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubGhzViewReceiverModel * model) { | ||||||
|             SubGhzReceiverMenuItem* item_menu = |             SubGhzReceiverMenuItem* item_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); | ||||||
| @ -99,17 +99,17 @@ void subghz_receiver_add_item_to_menu( | |||||||
| 
 | 
 | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|     subghz_receiver_update_offset(subghz_receiver); |     subghz_view_receiver_update_offset(subghz_receiver); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_add_data_statusbar( | void subghz_view_receiver_add_data_statusbar( | ||||||
|     SubghzReceiver* subghz_receiver, |     SubGhzViewReceiver* subghz_receiver, | ||||||
|     const char* frequency_str, |     const char* frequency_str, | ||||||
|     const char* preset_str, |     const char* preset_str, | ||||||
|     const char* history_stat_str) { |     const char* history_stat_str) { | ||||||
|     furi_assert(subghz_receiver); |     furi_assert(subghz_receiver); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubGhzViewReceiverModel * model) { | ||||||
|             string_set(model->frequency_str, frequency_str); |             string_set(model->frequency_str, frequency_str); | ||||||
|             string_set(model->preset_str, preset_str); |             string_set(model->preset_str, preset_str); | ||||||
|             string_set(model->history_stat_str, history_stat_str); |             string_set(model->history_stat_str, history_stat_str); | ||||||
| @ -117,7 +117,7 @@ void subghz_receiver_add_data_statusbar( | |||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) { | static void subghz_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) { | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT); |     canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT); | ||||||
| 
 | 
 | ||||||
| @ -131,7 +131,7 @@ static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scroll | |||||||
|     canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11); |     canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) { | void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { | ||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     canvas_set_font(canvas, FontSecondary); |     canvas_set_font(canvas, FontSecondary); | ||||||
| @ -162,7 +162,7 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) { | |||||||
|         string_set(str_buff, item_menu->item_str); |         string_set(str_buff, item_menu->item_str); | ||||||
|         elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX); |         elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX); | ||||||
|         if(model->idx == idx) { |         if(model->idx == idx) { | ||||||
|             subghz_receiver_draw_frame(canvas, i, scrollbar); |             subghz_view_receiver_draw_frame(canvas, i, scrollbar); | ||||||
|         } else { |         } else { | ||||||
|             canvas_set_color(canvas, ColorBlack); |             canvas_set_color(canvas, ColorBlack); | ||||||
|         } |         } | ||||||
| @ -176,17 +176,17 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) { | |||||||
|     string_clear(str_buff); |     string_clear(str_buff); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_receiver_input(InputEvent* event, void* context) { | bool subghz_view_receiver_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzReceiver* subghz_receiver = context; |     SubGhzViewReceiver* subghz_receiver = context; | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyBack && event->type == InputTypeShort) { |     if(event->key == InputKeyBack && event->type == InputTypeShort) { | ||||||
|         subghz_receiver->callback(SubghzCustomEventViewReceverBack, subghz_receiver->context); |         subghz_receiver->callback(SubGhzCustomEventViewReceverBack, subghz_receiver->context); | ||||||
|     } else if( |     } else if( | ||||||
|         event->key == InputKeyUp && |         event->key == InputKeyUp && | ||||||
|         (event->type == InputTypeShort || event->type == InputTypeRepeat)) { |         (event->type == InputTypeShort || event->type == InputTypeRepeat)) { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             subghz_receiver->view, (SubghzReceiverModel * model) { |             subghz_receiver->view, (SubGhzViewReceiverModel * model) { | ||||||
|                 if(model->idx != 0) model->idx--; |                 if(model->idx != 0) model->idx--; | ||||||
|                 return true; |                 return true; | ||||||
|             }); |             }); | ||||||
| @ -194,38 +194,38 @@ bool subghz_receiver_input(InputEvent* event, void* context) { | |||||||
|         event->key == InputKeyDown && |         event->key == InputKeyDown && | ||||||
|         (event->type == InputTypeShort || event->type == InputTypeRepeat)) { |         (event->type == InputTypeShort || event->type == InputTypeRepeat)) { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             subghz_receiver->view, (SubghzReceiverModel * model) { |             subghz_receiver->view, (SubGhzViewReceiverModel * model) { | ||||||
|                 if(model->idx != model->history_item - 1) model->idx++; |                 if(model->idx != model->history_item - 1) model->idx++; | ||||||
|                 return true; |                 return true; | ||||||
|             }); |             }); | ||||||
|     } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { |     } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { | ||||||
|         subghz_receiver->callback(SubghzCustomEventViewReceverConfig, subghz_receiver->context); |         subghz_receiver->callback(SubGhzCustomEventViewReceverConfig, subghz_receiver->context); | ||||||
|     } else if(event->key == InputKeyOk && event->type == InputTypeShort) { |     } else if(event->key == InputKeyOk && event->type == InputTypeShort) { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             subghz_receiver->view, (SubghzReceiverModel * model) { |             subghz_receiver->view, (SubGhzViewReceiverModel * model) { | ||||||
|                 if(model->history_item != 0) { |                 if(model->history_item != 0) { | ||||||
|                     subghz_receiver->callback( |                     subghz_receiver->callback( | ||||||
|                         SubghzCustomEventViewReceverOK, subghz_receiver->context); |                         SubGhzCustomEventViewReceverOK, subghz_receiver->context); | ||||||
|                 } |                 } | ||||||
|                 return false; |                 return false; | ||||||
|             }); |             }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     subghz_receiver_update_offset(subghz_receiver); |     subghz_view_receiver_update_offset(subghz_receiver); | ||||||
| 
 | 
 | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_enter(void* context) { | void subghz_view_receiver_enter(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     //SubghzReceiver* subghz_receiver = context;
 |     //SubGhzViewReceiver* subghz_receiver = context;
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_exit(void* context) { | void subghz_view_receiver_exit(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzReceiver* subghz_receiver = context; |     SubGhzViewReceiver* subghz_receiver = context; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubGhzViewReceiverModel * model) { | ||||||
|             string_reset(model->frequency_str); |             string_reset(model->frequency_str); | ||||||
|             string_reset(model->preset_str); |             string_reset(model->preset_str); | ||||||
|             string_reset(model->history_stat_str); |             string_reset(model->history_stat_str); | ||||||
| @ -242,20 +242,21 @@ void subghz_receiver_exit(void* context) { | |||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SubghzReceiver* subghz_receiver_alloc() { | SubGhzViewReceiver* subghz_view_receiver_alloc() { | ||||||
|     SubghzReceiver* subghz_receiver = malloc(sizeof(SubghzReceiver)); |     SubGhzViewReceiver* subghz_receiver = malloc(sizeof(SubGhzViewReceiver)); | ||||||
| 
 | 
 | ||||||
|     // View allocation and configuration
 |     // View allocation and configuration
 | ||||||
|     subghz_receiver->view = view_alloc(); |     subghz_receiver->view = view_alloc(); | ||||||
|     view_allocate_model(subghz_receiver->view, ViewModelTypeLocking, sizeof(SubghzReceiverModel)); |     view_allocate_model( | ||||||
|  |         subghz_receiver->view, ViewModelTypeLocking, sizeof(SubGhzViewReceiverModel)); | ||||||
|     view_set_context(subghz_receiver->view, subghz_receiver); |     view_set_context(subghz_receiver->view, subghz_receiver); | ||||||
|     view_set_draw_callback(subghz_receiver->view, (ViewDrawCallback)subghz_receiver_draw); |     view_set_draw_callback(subghz_receiver->view, (ViewDrawCallback)subghz_view_receiver_draw); | ||||||
|     view_set_input_callback(subghz_receiver->view, subghz_receiver_input); |     view_set_input_callback(subghz_receiver->view, subghz_view_receiver_input); | ||||||
|     view_set_enter_callback(subghz_receiver->view, subghz_receiver_enter); |     view_set_enter_callback(subghz_receiver->view, subghz_view_receiver_enter); | ||||||
|     view_set_exit_callback(subghz_receiver->view, subghz_receiver_exit); |     view_set_exit_callback(subghz_receiver->view, subghz_view_receiver_exit); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubGhzViewReceiverModel * model) { | ||||||
|             string_init(model->frequency_str); |             string_init(model->frequency_str); | ||||||
|             string_init(model->preset_str); |             string_init(model->preset_str); | ||||||
|             string_init(model->history_stat_str); |             string_init(model->history_stat_str); | ||||||
| @ -267,11 +268,11 @@ SubghzReceiver* subghz_receiver_alloc() { | |||||||
|     return subghz_receiver; |     return subghz_receiver; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_free(SubghzReceiver* subghz_receiver) { | void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver) { | ||||||
|     furi_assert(subghz_receiver); |     furi_assert(subghz_receiver); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubGhzViewReceiverModel * model) { | ||||||
|             string_clear(model->frequency_str); |             string_clear(model->frequency_str); | ||||||
|             string_clear(model->preset_str); |             string_clear(model->preset_str); | ||||||
|             string_clear(model->history_stat_str); |             string_clear(model->history_stat_str); | ||||||
| @ -288,29 +289,29 @@ void subghz_receiver_free(SubghzReceiver* subghz_receiver) { | |||||||
|     free(subghz_receiver); |     free(subghz_receiver); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver) { | View* subghz_view_receiver_get_view(SubGhzViewReceiver* subghz_receiver) { | ||||||
|     furi_assert(subghz_receiver); |     furi_assert(subghz_receiver); | ||||||
|     return subghz_receiver->view; |     return subghz_receiver->view; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t subghz_receiver_get_idx_menu(SubghzReceiver* subghz_receiver) { | uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver) { | ||||||
|     furi_assert(subghz_receiver); |     furi_assert(subghz_receiver); | ||||||
|     uint32_t idx = 0; |     uint32_t idx = 0; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubGhzViewReceiverModel * model) { | ||||||
|             idx = model->idx; |             idx = model->idx; | ||||||
|             return false; |             return false; | ||||||
|         }); |         }); | ||||||
|     return idx; |     return idx; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_set_idx_menu(SubghzReceiver* subghz_receiver, uint16_t idx) { | void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx) { | ||||||
|     furi_assert(subghz_receiver); |     furi_assert(subghz_receiver); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubGhzViewReceiverModel * model) { | ||||||
|             model->idx = idx; |             model->idx = idx; | ||||||
|             if(model->idx > 2) model->list_offset = idx - 2; |             if(model->idx > 2) model->list_offset = idx - 2; | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|     subghz_receiver_update_offset(subghz_receiver); |     subghz_view_receiver_update_offset(subghz_receiver); | ||||||
| } | } | ||||||
							
								
								
									
										36
									
								
								applications/subghz/views/receiver.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								applications/subghz/views/receiver.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include "../helpers/subghz_custom_event.h" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzViewReceiver SubGhzViewReceiver; | ||||||
|  | 
 | ||||||
|  | typedef void (*SubGhzViewReceiverCallback)(SubGhzCustomEvent event, void* context); | ||||||
|  | 
 | ||||||
|  | void subghz_view_receiver_set_callback( | ||||||
|  |     SubGhzViewReceiver* subghz_receiver, | ||||||
|  |     SubGhzViewReceiverCallback callback, | ||||||
|  |     void* context); | ||||||
|  | 
 | ||||||
|  | SubGhzViewReceiver* subghz_view_receiver_alloc(); | ||||||
|  | 
 | ||||||
|  | void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver); | ||||||
|  | 
 | ||||||
|  | View* subghz_view_receiver_get_view(SubGhzViewReceiver* subghz_receiver); | ||||||
|  | 
 | ||||||
|  | void subghz_view_receiver_add_data_statusbar( | ||||||
|  |     SubGhzViewReceiver* subghz_receiver, | ||||||
|  |     const char* frequency_str, | ||||||
|  |     const char* preset_str, | ||||||
|  |     const char* history_stat_str); | ||||||
|  | 
 | ||||||
|  | void subghz_view_receiver_add_item_to_menu( | ||||||
|  |     SubGhzViewReceiver* subghz_receiver, | ||||||
|  |     const char* name, | ||||||
|  |     uint8_t type); | ||||||
|  | 
 | ||||||
|  | uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver); | ||||||
|  | 
 | ||||||
|  | void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx); | ||||||
|  | 
 | ||||||
|  | void subghz_view_receiver_exit(void* context); | ||||||
| @ -6,30 +6,29 @@ | |||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <notification/notification_messages.h> | #include <notification/notification_messages.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_princeton.h> |  | ||||||
| #include "../helpers/subghz_frequency_analyzer_worker.h" | #include "../helpers/subghz_frequency_analyzer_worker.h" | ||||||
| 
 | 
 | ||||||
| #include <assets_icons.h> | #include <assets_icons.h> | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubghzFrequencyAnalyzerStatusIDLE, |     SubGhzFrequencyAnalyzerStatusIDLE, | ||||||
| } SubghzFrequencyAnalyzerStatus; | } SubGhzFrequencyAnalyzerStatus; | ||||||
| 
 | 
 | ||||||
| struct SubghzFrequencyAnalyzer { | struct SubGhzFrequencyAnalyzer { | ||||||
|     View* view; |     View* view; | ||||||
|     SubGhzFrequencyAnalyzerWorker* worker; |     SubGhzFrequencyAnalyzerWorker* worker; | ||||||
|     SubghzFrequencyAnalyzerCallback callback; |     SubGhzFrequencyAnalyzerCallback callback; | ||||||
|     void* context; |     void* context; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint32_t frequency; |     uint32_t frequency; | ||||||
|     float rssi; |     float rssi; | ||||||
| } SubghzFrequencyAnalyzerModel; | } SubGhzFrequencyAnalyzerModel; | ||||||
| 
 | 
 | ||||||
| void subghz_frequency_analyzer_set_callback( | void subghz_frequency_analyzer_set_callback( | ||||||
|     SubghzFrequencyAnalyzer* subghz_frequency_analyzer, |     SubGhzFrequencyAnalyzer* subghz_frequency_analyzer, | ||||||
|     SubghzFrequencyAnalyzerCallback callback, |     SubGhzFrequencyAnalyzerCallback callback, | ||||||
|     void* context) { |     void* context) { | ||||||
|     furi_assert(subghz_frequency_analyzer); |     furi_assert(subghz_frequency_analyzer); | ||||||
|     furi_assert(callback); |     furi_assert(callback); | ||||||
| @ -53,7 +52,7 @@ void subghz_frequency_analyzer_draw_rssi(Canvas* canvas, float rssi) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_frequency_analyzer_draw(Canvas* canvas, SubghzFrequencyAnalyzerModel* model) { | void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel* model) { | ||||||
|     char buffer[64]; |     char buffer[64]; | ||||||
| 
 | 
 | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
| @ -77,7 +76,6 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubghzFrequencyAnalyzerModel | |||||||
| 
 | 
 | ||||||
| bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { | bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     //SubghzFrequencyAnalyzer* instance = context;
 |  | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyBack) { |     if(event->key == InputKeyBack) { | ||||||
|         return false; |         return false; | ||||||
| @ -87,9 +85,9 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency, float rssi) { | void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency, float rssi) { | ||||||
|     SubghzFrequencyAnalyzer* instance = context; |     SubGhzFrequencyAnalyzer* instance = context; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzFrequencyAnalyzerModel * model) { |         instance->view, (SubGhzFrequencyAnalyzerModel * model) { | ||||||
|             model->rssi = rssi; |             model->rssi = rssi; | ||||||
|             model->frequency = frequency; |             model->frequency = frequency; | ||||||
|             return true; |             return true; | ||||||
| @ -98,7 +96,7 @@ void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency, | |||||||
| 
 | 
 | ||||||
| void subghz_frequency_analyzer_enter(void* context) { | void subghz_frequency_analyzer_enter(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzFrequencyAnalyzer* instance = context; |     SubGhzFrequencyAnalyzer* instance = context; | ||||||
| 
 | 
 | ||||||
|     //Start worker
 |     //Start worker
 | ||||||
|     instance->worker = subghz_frequency_analyzer_worker_alloc(); |     instance->worker = subghz_frequency_analyzer_worker_alloc(); | ||||||
| @ -111,7 +109,7 @@ void subghz_frequency_analyzer_enter(void* context) { | |||||||
|     subghz_frequency_analyzer_worker_start(instance->worker); |     subghz_frequency_analyzer_worker_start(instance->worker); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzFrequencyAnalyzerModel * model) { |         instance->view, (SubGhzFrequencyAnalyzerModel * model) { | ||||||
|             model->rssi = 0; |             model->rssi = 0; | ||||||
|             model->frequency = 0; |             model->frequency = 0; | ||||||
|             return true; |             return true; | ||||||
| @ -120,7 +118,7 @@ void subghz_frequency_analyzer_enter(void* context) { | |||||||
| 
 | 
 | ||||||
| void subghz_frequency_analyzer_exit(void* context) { | void subghz_frequency_analyzer_exit(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzFrequencyAnalyzer* instance = context; |     SubGhzFrequencyAnalyzer* instance = context; | ||||||
| 
 | 
 | ||||||
|     //Stop worker
 |     //Stop worker
 | ||||||
|     if(subghz_frequency_analyzer_worker_is_running(instance->worker)) { |     if(subghz_frequency_analyzer_worker_is_running(instance->worker)) { | ||||||
| @ -129,19 +127,19 @@ void subghz_frequency_analyzer_exit(void* context) { | |||||||
|     subghz_frequency_analyzer_worker_free(instance->worker); |     subghz_frequency_analyzer_worker_free(instance->worker); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzFrequencyAnalyzerModel * model) { |         instance->view, (SubGhzFrequencyAnalyzerModel * model) { | ||||||
|             model->rssi = 0; |             model->rssi = 0; | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SubghzFrequencyAnalyzer* subghz_frequency_analyzer_alloc() { | SubGhzFrequencyAnalyzer* subghz_frequency_analyzer_alloc() { | ||||||
|     SubghzFrequencyAnalyzer* instance = malloc(sizeof(SubghzFrequencyAnalyzer)); |     SubGhzFrequencyAnalyzer* instance = malloc(sizeof(SubGhzFrequencyAnalyzer)); | ||||||
| 
 | 
 | ||||||
|     // View allocation and configuration
 |     // View allocation and configuration
 | ||||||
|     instance->view = view_alloc(); |     instance->view = view_alloc(); | ||||||
|     view_allocate_model( |     view_allocate_model( | ||||||
|         instance->view, ViewModelTypeLocking, sizeof(SubghzFrequencyAnalyzerModel)); |         instance->view, ViewModelTypeLocking, sizeof(SubGhzFrequencyAnalyzerModel)); | ||||||
|     view_set_context(instance->view, instance); |     view_set_context(instance->view, instance); | ||||||
|     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_frequency_analyzer_draw); |     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_frequency_analyzer_draw); | ||||||
|     view_set_input_callback(instance->view, subghz_frequency_analyzer_input); |     view_set_input_callback(instance->view, subghz_frequency_analyzer_input); | ||||||
| @ -149,7 +147,7 @@ SubghzFrequencyAnalyzer* subghz_frequency_analyzer_alloc() { | |||||||
|     view_set_exit_callback(instance->view, subghz_frequency_analyzer_exit); |     view_set_exit_callback(instance->view, subghz_frequency_analyzer_exit); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzFrequencyAnalyzerModel * model) { |         instance->view, (SubGhzFrequencyAnalyzerModel * model) { | ||||||
|             model->rssi = 0; |             model->rssi = 0; | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| @ -157,14 +155,14 @@ SubghzFrequencyAnalyzer* subghz_frequency_analyzer_alloc() { | |||||||
|     return instance; |     return instance; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_frequency_analyzer_free(SubghzFrequencyAnalyzer* instance) { | void subghz_frequency_analyzer_free(SubGhzFrequencyAnalyzer* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
| 
 | 
 | ||||||
|     view_free(instance->view); |     view_free(instance->view); | ||||||
|     free(instance); |     free(instance); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| View* subghz_frequency_analyzer_get_view(SubghzFrequencyAnalyzer* instance) { | View* subghz_frequency_analyzer_get_view(SubGhzFrequencyAnalyzer* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     return instance->view; |     return instance->view; | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,17 +3,17 @@ | |||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
| #include "../helpers/subghz_custom_event.h" | #include "../helpers/subghz_custom_event.h" | ||||||
| 
 | 
 | ||||||
| typedef struct SubghzFrequencyAnalyzer SubghzFrequencyAnalyzer; | typedef struct SubGhzFrequencyAnalyzer SubGhzFrequencyAnalyzer; | ||||||
| 
 | 
 | ||||||
| typedef void (*SubghzFrequencyAnalyzerCallback)(SubghzCustomEvent event, void* context); | typedef void (*SubGhzFrequencyAnalyzerCallback)(SubGhzCustomEvent event, void* context); | ||||||
| 
 | 
 | ||||||
| void subghz_frequency_analyzer_set_callback( | void subghz_frequency_analyzer_set_callback( | ||||||
|     SubghzFrequencyAnalyzer* subghz_frequency_analyzer, |     SubGhzFrequencyAnalyzer* subghz_frequency_analyzer, | ||||||
|     SubghzFrequencyAnalyzerCallback callback, |     SubGhzFrequencyAnalyzerCallback callback, | ||||||
|     void* context); |     void* context); | ||||||
| 
 | 
 | ||||||
| SubghzFrequencyAnalyzer* subghz_frequency_analyzer_alloc(); | SubGhzFrequencyAnalyzer* subghz_frequency_analyzer_alloc(); | ||||||
| 
 | 
 | ||||||
| void subghz_frequency_analyzer_free(SubghzFrequencyAnalyzer* subghz_static); | void subghz_frequency_analyzer_free(SubGhzFrequencyAnalyzer* subghz_static); | ||||||
| 
 | 
 | ||||||
| View* subghz_frequency_analyzer_get_view(SubghzFrequencyAnalyzer* subghz_static); | View* subghz_frequency_analyzer_get_view(SubGhzFrequencyAnalyzer* subghz_static); | ||||||
|  | |||||||
| @ -6,15 +6,14 @@ | |||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_princeton.h> |  | ||||||
| 
 | 
 | ||||||
| #include <assets_icons.h> | #include <assets_icons.h> | ||||||
| #define SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE 100 | #define SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE 100 | ||||||
| #define TAG "SubghzReadRAW" | #define TAG "SubGhzReadRAW" | ||||||
| 
 | 
 | ||||||
| struct SubghzReadRAW { | struct SubGhzReadRAW { | ||||||
|     View* view; |     View* view; | ||||||
|     SubghzReadRAWCallback callback; |     SubGhzReadRAWCallback callback; | ||||||
|     void* context; |     void* context; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -27,12 +26,12 @@ typedef struct { | |||||||
|     bool rssi_history_end; |     bool rssi_history_end; | ||||||
|     uint8_t ind_write; |     uint8_t ind_write; | ||||||
|     uint8_t ind_sin; |     uint8_t ind_sin; | ||||||
|     SubghzReadRAWStatus satus; |     SubGhzReadRAWStatus satus; | ||||||
| } SubghzReadRAWModel; | } SubGhzReadRAWModel; | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_set_callback( | void subghz_read_raw_set_callback( | ||||||
|     SubghzReadRAW* subghz_read_raw, |     SubGhzReadRAW* subghz_read_raw, | ||||||
|     SubghzReadRAWCallback callback, |     SubGhzReadRAWCallback callback, | ||||||
|     void* context) { |     void* context) { | ||||||
|     furi_assert(subghz_read_raw); |     furi_assert(subghz_read_raw); | ||||||
|     furi_assert(callback); |     furi_assert(callback); | ||||||
| @ -41,19 +40,19 @@ void subghz_read_raw_set_callback( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_add_data_statusbar( | void subghz_read_raw_add_data_statusbar( | ||||||
|     SubghzReadRAW* instance, |     SubGhzReadRAW* instance, | ||||||
|     const char* frequency_str, |     const char* frequency_str, | ||||||
|     const char* preset_str) { |     const char* preset_str) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzReadRAWModel * model) { |         instance->view, (SubGhzReadRAWModel * model) { | ||||||
|             string_set(model->frequency_str, frequency_str); |             string_set(model->frequency_str, frequency_str); | ||||||
|             string_set(model->preset_str, preset_str); |             string_set(model->preset_str, preset_str); | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_add_data_rssi(SubghzReadRAW* instance, float rssi) { | void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     uint8_t u_rssi = 0; |     uint8_t u_rssi = 0; | ||||||
| 
 | 
 | ||||||
| @ -62,10 +61,9 @@ void subghz_read_raw_add_data_rssi(SubghzReadRAW* instance, float rssi) { | |||||||
|     } else { |     } else { | ||||||
|         u_rssi = (uint8_t)((rssi + 90) / 2.7); |         u_rssi = (uint8_t)((rssi + 90) / 2.7); | ||||||
|     } |     } | ||||||
|     //if(u_rssi > 34) u_rssi = 34;
 |  | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzReadRAWModel * model) { |         instance->view, (SubGhzReadRAWModel * model) { | ||||||
|             model->rssi_history[model->ind_write++] = u_rssi; |             model->rssi_history[model->ind_write++] = u_rssi; | ||||||
|             if(model->ind_write > SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE) { |             if(model->ind_write > SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE) { | ||||||
|                 model->rssi_history_end = true; |                 model->rssi_history_end = true; | ||||||
| @ -75,46 +73,46 @@ void subghz_read_raw_add_data_rssi(SubghzReadRAW* instance, float rssi) { | |||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_update_sample_write(SubghzReadRAW* instance, size_t sample) { | void subghz_read_raw_update_sample_write(SubGhzReadRAW* instance, size_t sample) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzReadRAWModel * model) { |         instance->view, (SubGhzReadRAWModel * model) { | ||||||
|             string_printf(model->sample_write, "%d spl.", sample); |             string_printf(model->sample_write, "%d spl.", sample); | ||||||
|             return false; |             return false; | ||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_stop_send(SubghzReadRAW* instance) { | void subghz_read_raw_stop_send(SubGhzReadRAW* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzReadRAWModel * model) { |         instance->view, (SubGhzReadRAWModel * model) { | ||||||
|             switch(model->satus) { |             switch(model->satus) { | ||||||
|             case SubghzReadRAWStatusTXRepeat: |             case SubGhzReadRAWStatusTXRepeat: | ||||||
|             case SubghzReadRAWStatusLoadKeyTXRepeat: |             case SubGhzReadRAWStatusLoadKeyTXRepeat: | ||||||
|                 instance->callback(SubghzCustomEventViewReadRAWSendStart, instance->context); |                 instance->callback(SubGhzCustomEventViewReadRAWSendStart, instance->context); | ||||||
|                 break; |                 break; | ||||||
|             case SubghzReadRAWStatusTX: |             case SubGhzReadRAWStatusTX: | ||||||
|                 model->satus = SubghzReadRAWStatusIDLE; |                 model->satus = SubGhzReadRAWStatusIDLE; | ||||||
|                 break; |                 break; | ||||||
|             case SubghzReadRAWStatusLoadKeyTX: |             case SubGhzReadRAWStatusLoadKeyTX: | ||||||
|                 model->satus = SubghzReadRAWStatusLoadKeyIDLE; |                 model->satus = SubGhzReadRAWStatusLoadKeyIDLE; | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             default: |             default: | ||||||
|                 FURI_LOG_W(TAG, "unknown status"); |                 FURI_LOG_W(TAG, "unknown status"); | ||||||
|                 model->satus = SubghzReadRAWStatusIDLE; |                 model->satus = SubGhzReadRAWStatusIDLE; | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_update_sin(SubghzReadRAW* instance) { | void subghz_read_raw_update_sin(SubGhzReadRAW* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzReadRAWModel * model) { |         instance->view, (SubGhzReadRAWModel * model) { | ||||||
|             if(model->ind_sin++ > 62) { |             if(model->ind_sin++ > 62) { | ||||||
|                 model->ind_sin = 0; |                 model->ind_sin = 0; | ||||||
|             } |             } | ||||||
| @ -134,7 +132,7 @@ static int8_t subghz_read_raw_tab_sin(uint8_t x) { | |||||||
|     return r; |     return r; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_draw_sin(Canvas* canvas, SubghzReadRAWModel* model) { | void subghz_read_raw_draw_sin(Canvas* canvas, SubGhzReadRAWModel* model) { | ||||||
| #define SUBGHZ_RAW_SIN_AMPLITUDE 11 | #define SUBGHZ_RAW_SIN_AMPLITUDE 11 | ||||||
|     for(int i = 113; i > 0; i--) { |     for(int i = 113; i > 0; i--) { | ||||||
|         canvas_draw_line( |         canvas_draw_line( | ||||||
| @ -154,7 +152,7 @@ void subghz_read_raw_draw_sin(Canvas* canvas, SubghzReadRAWModel* model) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_draw_scale(Canvas* canvas, SubghzReadRAWModel* model) { | void subghz_read_raw_draw_scale(Canvas* canvas, SubGhzReadRAWModel* model) { | ||||||
| #define SUBGHZ_RAW_TOP_SCALE 14 | #define SUBGHZ_RAW_TOP_SCALE 14 | ||||||
| #define SUBGHZ_RAW_END_SCALE 115 | #define SUBGHZ_RAW_END_SCALE 115 | ||||||
| 
 | 
 | ||||||
| @ -178,7 +176,7 @@ void subghz_read_raw_draw_scale(Canvas* canvas, SubghzReadRAWModel* model) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_draw_rssi(Canvas* canvas, SubghzReadRAWModel* model) { | void subghz_read_raw_draw_rssi(Canvas* canvas, SubGhzReadRAWModel* model) { | ||||||
|     int ind = 0; |     int ind = 0; | ||||||
|     int base = 0; |     int base = 0; | ||||||
|     if(model->rssi_history_end == false) { |     if(model->rssi_history_end == false) { | ||||||
| @ -214,7 +212,7 @@ void subghz_read_raw_draw_rssi(Canvas* canvas, SubghzReadRAWModel* model) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_draw(Canvas* canvas, SubghzReadRAWModel* model) { | void subghz_read_raw_draw(Canvas* canvas, SubGhzReadRAWModel* model) { | ||||||
|     uint8_t graphics_mode = 1; |     uint8_t graphics_mode = 1; | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     canvas_set_font(canvas, FontSecondary); |     canvas_set_font(canvas, FontSecondary); | ||||||
| @ -228,12 +226,12 @@ void subghz_read_raw_draw(Canvas* canvas, SubghzReadRAWModel* model) { | |||||||
|     canvas_draw_line(canvas, 115, 14, 115, 48); |     canvas_draw_line(canvas, 115, 14, 115, 48); | ||||||
| 
 | 
 | ||||||
|     switch(model->satus) { |     switch(model->satus) { | ||||||
|     case SubghzReadRAWStatusIDLE: |     case SubGhzReadRAWStatusIDLE: | ||||||
|         elements_button_left(canvas, "Erase"); |         elements_button_left(canvas, "Erase"); | ||||||
|         elements_button_center(canvas, "Send"); |         elements_button_center(canvas, "Send"); | ||||||
|         elements_button_right(canvas, "Save"); |         elements_button_right(canvas, "Save"); | ||||||
|         break; |         break; | ||||||
|     case SubghzReadRAWStatusLoadKeyIDLE: |     case SubGhzReadRAWStatusLoadKeyIDLE: | ||||||
|         elements_button_left(canvas, "New"); |         elements_button_left(canvas, "New"); | ||||||
|         elements_button_center(canvas, "Send"); |         elements_button_center(canvas, "Send"); | ||||||
|         elements_button_right(canvas, "More"); |         elements_button_right(canvas, "More"); | ||||||
| @ -241,15 +239,15 @@ void subghz_read_raw_draw(Canvas* canvas, SubghzReadRAWModel* model) { | |||||||
|             canvas, 4, 12, 110, 44, AlignCenter, AlignCenter, string_get_cstr(model->file_name)); |             canvas, 4, 12, 110, 44, AlignCenter, AlignCenter, string_get_cstr(model->file_name)); | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     case SubghzReadRAWStatusTX: |     case SubGhzReadRAWStatusTX: | ||||||
|     case SubghzReadRAWStatusTXRepeat: |     case SubGhzReadRAWStatusTXRepeat: | ||||||
|     case SubghzReadRAWStatusLoadKeyTX: |     case SubGhzReadRAWStatusLoadKeyTX: | ||||||
|     case SubghzReadRAWStatusLoadKeyTXRepeat: |     case SubGhzReadRAWStatusLoadKeyTXRepeat: | ||||||
|         graphics_mode = 0; |         graphics_mode = 0; | ||||||
|         elements_button_center(canvas, "Send"); |         elements_button_center(canvas, "Send"); | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     case SubghzReadRAWStatusStart: |     case SubGhzReadRAWStatusStart: | ||||||
|         elements_button_left(canvas, "Config"); |         elements_button_left(canvas, "Config"); | ||||||
|         elements_button_center(canvas, "REC"); |         elements_button_center(canvas, "REC"); | ||||||
|         break; |         break; | ||||||
| @ -272,7 +270,7 @@ void subghz_read_raw_draw(Canvas* canvas, SubghzReadRAWModel* model) { | |||||||
| 
 | 
 | ||||||
| bool subghz_read_raw_input(InputEvent* event, void* context) { | bool subghz_read_raw_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzReadRAW* instance = context; |     SubGhzReadRAW* instance = context; | ||||||
| 
 | 
 | ||||||
|     if((event->key == InputKeyOk) && |     if((event->key == InputKeyOk) && | ||||||
|        (event->type == InputTypeLong || event->type == InputTypeRepeat)) { |        (event->type == InputTypeLong || event->type == InputTypeRepeat)) { | ||||||
| @ -281,30 +279,30 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { | |||||||
|         return false; |         return false; | ||||||
|     } else if(event->key == InputKeyOk && event->type == InputTypePress) { |     } else if(event->key == InputKeyOk && event->type == InputTypePress) { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             instance->view, (SubghzReadRAWModel * model) { |             instance->view, (SubGhzReadRAWModel * model) { | ||||||
|                 uint8_t ret = false; |                 uint8_t ret = false; | ||||||
|                 switch(model->satus) { |                 switch(model->satus) { | ||||||
|                 case SubghzReadRAWStatusIDLE: |                 case SubGhzReadRAWStatusIDLE: | ||||||
|                     // Start TX
 |                     // Start TX
 | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWSendStart, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWSendStart, instance->context); | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWVibro, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWVibro, instance->context); | ||||||
|                     model->satus = SubghzReadRAWStatusTXRepeat; |                     model->satus = SubGhzReadRAWStatusTXRepeat; | ||||||
|                     ret = true; |                     ret = true; | ||||||
|                     break; |                     break; | ||||||
|                 case SubghzReadRAWStatusTX: |                 case SubGhzReadRAWStatusTX: | ||||||
|                     // Start TXRepeat
 |                     // Start TXRepeat
 | ||||||
|                     model->satus = SubghzReadRAWStatusTXRepeat; |                     model->satus = SubGhzReadRAWStatusTXRepeat; | ||||||
|                     break; |                     break; | ||||||
|                 case SubghzReadRAWStatusLoadKeyIDLE: |                 case SubGhzReadRAWStatusLoadKeyIDLE: | ||||||
|                     // Start Load Key TX
 |                     // Start Load Key TX
 | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWSendStart, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWSendStart, instance->context); | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWVibro, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWVibro, instance->context); | ||||||
|                     model->satus = SubghzReadRAWStatusLoadKeyTXRepeat; |                     model->satus = SubGhzReadRAWStatusLoadKeyTXRepeat; | ||||||
|                     ret = true; |                     ret = true; | ||||||
|                     break; |                     break; | ||||||
|                 case SubghzReadRAWStatusLoadKeyTX: |                 case SubGhzReadRAWStatusLoadKeyTX: | ||||||
|                     // Start Load Key TXRepeat
 |                     // Start Load Key TXRepeat
 | ||||||
|                     model->satus = SubghzReadRAWStatusLoadKeyTXRepeat; |                     model->satus = SubGhzReadRAWStatusLoadKeyTXRepeat; | ||||||
|                     break; |                     break; | ||||||
| 
 | 
 | ||||||
|                 default: |                 default: | ||||||
| @ -314,91 +312,91 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { | |||||||
|             }); |             }); | ||||||
|     } else if(event->key == InputKeyOk && event->type == InputTypeRelease) { |     } else if(event->key == InputKeyOk && event->type == InputTypeRelease) { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             instance->view, (SubghzReadRAWModel * model) { |             instance->view, (SubGhzReadRAWModel * model) { | ||||||
|                 if(model->satus == SubghzReadRAWStatusTXRepeat) { |                 if(model->satus == SubGhzReadRAWStatusTXRepeat) { | ||||||
|                     // Stop repeat TX
 |                     // Stop repeat TX
 | ||||||
|                     model->satus = SubghzReadRAWStatusTX; |                     model->satus = SubGhzReadRAWStatusTX; | ||||||
|                 } else if(model->satus == SubghzReadRAWStatusLoadKeyTXRepeat) { |                 } else if(model->satus == SubGhzReadRAWStatusLoadKeyTXRepeat) { | ||||||
|                     // Stop repeat TX
 |                     // Stop repeat TX
 | ||||||
|                     model->satus = SubghzReadRAWStatusLoadKeyTX; |                     model->satus = SubGhzReadRAWStatusLoadKeyTX; | ||||||
|                 } |                 } | ||||||
|                 return false; |                 return false; | ||||||
|             }); |             }); | ||||||
|     } else if(event->key == InputKeyBack && event->type == InputTypeShort) { |     } else if(event->key == InputKeyBack && event->type == InputTypeShort) { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             instance->view, (SubghzReadRAWModel * model) { |             instance->view, (SubGhzReadRAWModel * model) { | ||||||
|                 switch(model->satus) { |                 switch(model->satus) { | ||||||
|                 case SubghzReadRAWStatusREC: |                 case SubGhzReadRAWStatusREC: | ||||||
|                     //Stop REC
 |                     //Stop REC
 | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWIDLE, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context); | ||||||
|                     model->satus = SubghzReadRAWStatusIDLE; |                     model->satus = SubGhzReadRAWStatusIDLE; | ||||||
|                     break; |                     break; | ||||||
|                 case SubghzReadRAWStatusLoadKeyTX: |                 case SubGhzReadRAWStatusLoadKeyTX: | ||||||
|                     //Stop TxRx
 |                     //Stop TxRx
 | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWTXRXStop, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWTXRXStop, instance->context); | ||||||
|                     model->satus = SubghzReadRAWStatusLoadKeyIDLE; |                     model->satus = SubGhzReadRAWStatusLoadKeyIDLE; | ||||||
|                     break; |                     break; | ||||||
|                 case SubghzReadRAWStatusTX: |                 case SubGhzReadRAWStatusTX: | ||||||
|                     //Stop TxRx
 |                     //Stop TxRx
 | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWTXRXStop, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWTXRXStop, instance->context); | ||||||
|                     model->satus = SubghzReadRAWStatusIDLE; |                     model->satus = SubGhzReadRAWStatusIDLE; | ||||||
|                     break; |                     break; | ||||||
|                 case SubghzReadRAWStatusLoadKeyIDLE: |                 case SubGhzReadRAWStatusLoadKeyIDLE: | ||||||
|                     //Exit
 |                     //Exit
 | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWBack, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWBack, instance->context); | ||||||
|                     break; |                     break; | ||||||
| 
 | 
 | ||||||
|                 default: |                 default: | ||||||
|                     //Exit
 |                     //Exit
 | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWBack, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWBack, instance->context); | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|                 return true; |                 return true; | ||||||
|             }); |             }); | ||||||
|     } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { |     } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             instance->view, (SubghzReadRAWModel * model) { |             instance->view, (SubGhzReadRAWModel * model) { | ||||||
|                 if(model->satus == SubghzReadRAWStatusStart) { |                 if(model->satus == SubGhzReadRAWStatusStart) { | ||||||
|                     //Config
 |                     //Config
 | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWConfig, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWConfig, instance->context); | ||||||
|                 } else if( |                 } else if( | ||||||
|                     (model->satus == SubghzReadRAWStatusIDLE) || |                     (model->satus == SubGhzReadRAWStatusIDLE) || | ||||||
|                     (model->satus == SubghzReadRAWStatusLoadKeyIDLE)) { |                     (model->satus == SubGhzReadRAWStatusLoadKeyIDLE)) { | ||||||
|                     //Erase
 |                     //Erase
 | ||||||
|                     model->satus = SubghzReadRAWStatusStart; |                     model->satus = SubGhzReadRAWStatusStart; | ||||||
|                     model->rssi_history_end = false; |                     model->rssi_history_end = false; | ||||||
|                     model->ind_write = 0; |                     model->ind_write = 0; | ||||||
|                     string_set(model->sample_write, "0 spl."); |                     string_set(model->sample_write, "0 spl."); | ||||||
|                     string_reset(model->file_name); |                     string_reset(model->file_name); | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWErase, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWErase, instance->context); | ||||||
|                 } |                 } | ||||||
|                 return true; |                 return true; | ||||||
|             }); |             }); | ||||||
|     } else if(event->key == InputKeyRight && event->type == InputTypeShort) { |     } else if(event->key == InputKeyRight && event->type == InputTypeShort) { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             instance->view, (SubghzReadRAWModel * model) { |             instance->view, (SubGhzReadRAWModel * model) { | ||||||
|                 if(model->satus == SubghzReadRAWStatusIDLE) { |                 if(model->satus == SubGhzReadRAWStatusIDLE) { | ||||||
|                     //Save
 |                     //Save
 | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWSave, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWSave, instance->context); | ||||||
|                 } else if(model->satus == SubghzReadRAWStatusLoadKeyIDLE) { |                 } else if(model->satus == SubGhzReadRAWStatusLoadKeyIDLE) { | ||||||
|                     //More
 |                     //More
 | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWMore, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWMore, instance->context); | ||||||
|                 } |                 } | ||||||
|                 return true; |                 return true; | ||||||
|             }); |             }); | ||||||
|     } else if(event->key == InputKeyOk && event->type == InputTypeShort) { |     } else if(event->key == InputKeyOk && event->type == InputTypeShort) { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             instance->view, (SubghzReadRAWModel * model) { |             instance->view, (SubGhzReadRAWModel * model) { | ||||||
|                 if(model->satus == SubghzReadRAWStatusStart) { |                 if(model->satus == SubGhzReadRAWStatusStart) { | ||||||
|                     //Record
 |                     //Record
 | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWREC, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWREC, instance->context); | ||||||
|                     model->satus = SubghzReadRAWStatusREC; |                     model->satus = SubGhzReadRAWStatusREC; | ||||||
|                     model->ind_write = 0; |                     model->ind_write = 0; | ||||||
|                     model->rssi_history_end = false; |                     model->rssi_history_end = false; | ||||||
|                 } else if(model->satus == SubghzReadRAWStatusREC) { |                 } else if(model->satus == SubGhzReadRAWStatusREC) { | ||||||
|                     //Stop
 |                     //Stop
 | ||||||
|                     instance->callback(SubghzCustomEventViewReadRAWIDLE, instance->context); |                     instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context); | ||||||
|                     model->satus = SubghzReadRAWStatusIDLE; |                     model->satus = SubGhzReadRAWStatusIDLE; | ||||||
|                 } |                 } | ||||||
|                 return true; |                 return true; | ||||||
|             }); |             }); | ||||||
| @ -407,16 +405,16 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_set_status( | void subghz_read_raw_set_status( | ||||||
|     SubghzReadRAW* instance, |     SubGhzReadRAW* instance, | ||||||
|     SubghzReadRAWStatus satus, |     SubGhzReadRAWStatus satus, | ||||||
|     const char* file_name) { |     const char* file_name) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
| 
 | 
 | ||||||
|     switch(satus) { |     switch(satus) { | ||||||
|     case SubghzReadRAWStatusStart: |     case SubGhzReadRAWStatusStart: | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             instance->view, (SubghzReadRAWModel * model) { |             instance->view, (SubGhzReadRAWModel * model) { | ||||||
|                 model->satus = SubghzReadRAWStatusStart; |                 model->satus = SubGhzReadRAWStatusStart; | ||||||
|                 model->rssi_history_end = false; |                 model->rssi_history_end = false; | ||||||
|                 model->ind_write = 0; |                 model->ind_write = 0; | ||||||
|                 string_reset(model->file_name); |                 string_reset(model->file_name); | ||||||
| @ -424,17 +422,17 @@ void subghz_read_raw_set_status( | |||||||
|                 return true; |                 return true; | ||||||
|             }); |             }); | ||||||
|         break; |         break; | ||||||
|     case SubghzReadRAWStatusIDLE: |     case SubGhzReadRAWStatusIDLE: | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             instance->view, (SubghzReadRAWModel * model) { |             instance->view, (SubGhzReadRAWModel * model) { | ||||||
|                 model->satus = SubghzReadRAWStatusIDLE; |                 model->satus = SubGhzReadRAWStatusIDLE; | ||||||
|                 return true; |                 return true; | ||||||
|             }); |             }); | ||||||
|         break; |         break; | ||||||
|     case SubghzReadRAWStatusLoadKeyTX: |     case SubGhzReadRAWStatusLoadKeyTX: | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             instance->view, (SubghzReadRAWModel * model) { |             instance->view, (SubGhzReadRAWModel * model) { | ||||||
|                 model->satus = SubghzReadRAWStatusLoadKeyIDLE; |                 model->satus = SubGhzReadRAWStatusLoadKeyIDLE; | ||||||
|                 model->rssi_history_end = false; |                 model->rssi_history_end = false; | ||||||
|                 model->ind_write = 0; |                 model->ind_write = 0; | ||||||
|                 string_set(model->file_name, file_name); |                 string_set(model->file_name, file_name); | ||||||
| @ -442,10 +440,10 @@ void subghz_read_raw_set_status( | |||||||
|                 return true; |                 return true; | ||||||
|             }); |             }); | ||||||
|         break; |         break; | ||||||
|     case SubghzReadRAWStatusSaveKey: |     case SubGhzReadRAWStatusSaveKey: | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             instance->view, (SubghzReadRAWModel * model) { |             instance->view, (SubGhzReadRAWModel * model) { | ||||||
|                 model->satus = SubghzReadRAWStatusLoadKeyIDLE; |                 model->satus = SubGhzReadRAWStatusLoadKeyIDLE; | ||||||
|                 if(!model->ind_write) { |                 if(!model->ind_write) { | ||||||
|                     string_set(model->file_name, file_name); |                     string_set(model->file_name, file_name); | ||||||
|                     string_set(model->sample_write, "RAW"); |                     string_set(model->sample_write, "RAW"); | ||||||
| @ -464,31 +462,31 @@ void subghz_read_raw_set_status( | |||||||
| 
 | 
 | ||||||
| void subghz_read_raw_enter(void* context) { | void subghz_read_raw_enter(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     //SubghzReadRAW* instance = context;
 |     //SubGhzReadRAW* instance = context;
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_exit(void* context) { | void subghz_read_raw_exit(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzReadRAW* instance = context; |     SubGhzReadRAW* instance = context; | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzReadRAWModel * model) { |         instance->view, (SubGhzReadRAWModel * model) { | ||||||
|             if(model->satus != SubghzReadRAWStatusIDLE && |             if(model->satus != SubGhzReadRAWStatusIDLE && | ||||||
|                model->satus != SubghzReadRAWStatusStart && |                model->satus != SubGhzReadRAWStatusStart && | ||||||
|                model->satus != SubghzReadRAWStatusLoadKeyIDLE) { |                model->satus != SubGhzReadRAWStatusLoadKeyIDLE) { | ||||||
|                 instance->callback(SubghzCustomEventViewReadRAWIDLE, instance->context); |                 instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context); | ||||||
|                 model->satus = SubghzReadRAWStatusStart; |                 model->satus = SubGhzReadRAWStatusStart; | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SubghzReadRAW* subghz_read_raw_alloc() { | SubGhzReadRAW* subghz_read_raw_alloc() { | ||||||
|     SubghzReadRAW* instance = malloc(sizeof(SubghzReadRAW)); |     SubGhzReadRAW* instance = malloc(sizeof(SubGhzReadRAW)); | ||||||
| 
 | 
 | ||||||
|     // View allocation and configuration
 |     // View allocation and configuration
 | ||||||
|     instance->view = view_alloc(); |     instance->view = view_alloc(); | ||||||
|     view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubghzReadRAWModel)); |     view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubGhzReadRAWModel)); | ||||||
|     view_set_context(instance->view, instance); |     view_set_context(instance->view, instance); | ||||||
|     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_read_raw_draw); |     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_read_raw_draw); | ||||||
|     view_set_input_callback(instance->view, subghz_read_raw_input); |     view_set_input_callback(instance->view, subghz_read_raw_input); | ||||||
| @ -496,7 +494,7 @@ SubghzReadRAW* subghz_read_raw_alloc() { | |||||||
|     view_set_exit_callback(instance->view, subghz_read_raw_exit); |     view_set_exit_callback(instance->view, subghz_read_raw_exit); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzReadRAWModel * model) { |         instance->view, (SubGhzReadRAWModel * model) { | ||||||
|             string_init(model->frequency_str); |             string_init(model->frequency_str); | ||||||
|             string_init(model->preset_str); |             string_init(model->preset_str); | ||||||
|             string_init(model->sample_write); |             string_init(model->sample_write); | ||||||
| @ -508,11 +506,11 @@ SubghzReadRAW* subghz_read_raw_alloc() { | |||||||
|     return instance; |     return instance; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_free(SubghzReadRAW* instance) { | void subghz_read_raw_free(SubGhzReadRAW* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzReadRAWModel * model) { |         instance->view, (SubGhzReadRAWModel * model) { | ||||||
|             string_clear(model->frequency_str); |             string_clear(model->frequency_str); | ||||||
|             string_clear(model->preset_str); |             string_clear(model->preset_str); | ||||||
|             string_clear(model->sample_write); |             string_clear(model->sample_write); | ||||||
| @ -524,7 +522,7 @@ void subghz_read_raw_free(SubghzReadRAW* instance) { | |||||||
|     free(instance); |     free(instance); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| View* subghz_read_raw_get_view(SubghzReadRAW* instance) { | View* subghz_read_raw_get_view(SubGhzReadRAW* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     return instance->view; |     return instance->view; | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,48 +3,48 @@ | |||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
| #include "../helpers/subghz_custom_event.h" | #include "../helpers/subghz_custom_event.h" | ||||||
| 
 | 
 | ||||||
| typedef struct SubghzReadRAW SubghzReadRAW; | typedef struct SubGhzReadRAW SubGhzReadRAW; | ||||||
| 
 | 
 | ||||||
| typedef void (*SubghzReadRAWCallback)(SubghzCustomEvent event, void* context); | typedef void (*SubGhzReadRAWCallback)(SubGhzCustomEvent event, void* context); | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubghzReadRAWStatusStart, |     SubGhzReadRAWStatusStart, | ||||||
|     SubghzReadRAWStatusIDLE, |     SubGhzReadRAWStatusIDLE, | ||||||
|     SubghzReadRAWStatusREC, |     SubGhzReadRAWStatusREC, | ||||||
|     SubghzReadRAWStatusTX, |     SubGhzReadRAWStatusTX, | ||||||
|     SubghzReadRAWStatusTXRepeat, |     SubGhzReadRAWStatusTXRepeat, | ||||||
| 
 | 
 | ||||||
|     SubghzReadRAWStatusLoadKeyIDLE, |     SubGhzReadRAWStatusLoadKeyIDLE, | ||||||
|     SubghzReadRAWStatusLoadKeyTX, |     SubGhzReadRAWStatusLoadKeyTX, | ||||||
|     SubghzReadRAWStatusLoadKeyTXRepeat, |     SubGhzReadRAWStatusLoadKeyTXRepeat, | ||||||
|     SubghzReadRAWStatusSaveKey, |     SubGhzReadRAWStatusSaveKey, | ||||||
| } SubghzReadRAWStatus; | } SubGhzReadRAWStatus; | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_set_callback( | void subghz_read_raw_set_callback( | ||||||
|     SubghzReadRAW* subghz_read_raw, |     SubGhzReadRAW* subghz_read_raw, | ||||||
|     SubghzReadRAWCallback callback, |     SubGhzReadRAWCallback callback, | ||||||
|     void* context); |     void* context); | ||||||
| 
 | 
 | ||||||
| SubghzReadRAW* subghz_read_raw_alloc(); | SubGhzReadRAW* subghz_read_raw_alloc(); | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_free(SubghzReadRAW* subghz_static); | void subghz_read_raw_free(SubGhzReadRAW* subghz_static); | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_add_data_statusbar( | void subghz_read_raw_add_data_statusbar( | ||||||
|     SubghzReadRAW* instance, |     SubGhzReadRAW* instance, | ||||||
|     const char* frequency_str, |     const char* frequency_str, | ||||||
|     const char* preset_str); |     const char* preset_str); | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_update_sample_write(SubghzReadRAW* instance, size_t sample); | void subghz_read_raw_update_sample_write(SubGhzReadRAW* instance, size_t sample); | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_stop_send(SubghzReadRAW* instance); | void subghz_read_raw_stop_send(SubGhzReadRAW* instance); | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_update_sin(SubghzReadRAW* instance); | void subghz_read_raw_update_sin(SubGhzReadRAW* instance); | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_add_data_rssi(SubghzReadRAW* instance, float rssi); | void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi); | ||||||
| 
 | 
 | ||||||
| void subghz_read_raw_set_status( | void subghz_read_raw_set_status( | ||||||
|     SubghzReadRAW* instance, |     SubGhzReadRAW* instance, | ||||||
|     SubghzReadRAWStatus satus, |     SubGhzReadRAWStatus satus, | ||||||
|     const char* file_name); |     const char* file_name); | ||||||
| 
 | 
 | ||||||
| View* subghz_read_raw_get_view(SubghzReadRAW* subghz_static); | View* subghz_read_raw_get_view(SubGhzReadRAW* subghz_static); | ||||||
|  | |||||||
| @ -1,36 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <gui/view.h> |  | ||||||
| #include "../helpers/subghz_custom_event.h" |  | ||||||
| 
 |  | ||||||
| typedef struct SubghzReceiver SubghzReceiver; |  | ||||||
| 
 |  | ||||||
| typedef void (*SubghzReceiverCallback)(SubghzCustomEvent event, void* context); |  | ||||||
| 
 |  | ||||||
| void subghz_receiver_set_callback( |  | ||||||
|     SubghzReceiver* subghz_receiver, |  | ||||||
|     SubghzReceiverCallback callback, |  | ||||||
|     void* context); |  | ||||||
| 
 |  | ||||||
| SubghzReceiver* subghz_receiver_alloc(); |  | ||||||
| 
 |  | ||||||
| void subghz_receiver_free(SubghzReceiver* subghz_receiver); |  | ||||||
| 
 |  | ||||||
| View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver); |  | ||||||
| 
 |  | ||||||
| void subghz_receiver_add_data_statusbar( |  | ||||||
|     SubghzReceiver* subghz_receiver, |  | ||||||
|     const char* frequency_str, |  | ||||||
|     const char* preset_str, |  | ||||||
|     const char* history_stat_str); |  | ||||||
| 
 |  | ||||||
| void subghz_receiver_add_item_to_menu( |  | ||||||
|     SubghzReceiver* subghz_receiver, |  | ||||||
|     const char* name, |  | ||||||
|     uint8_t type); |  | ||||||
| 
 |  | ||||||
| uint16_t subghz_receiver_get_idx_menu(SubghzReceiver* subghz_receiver); |  | ||||||
| 
 |  | ||||||
| void subghz_receiver_set_idx_menu(SubghzReceiver* subghz_receiver, uint16_t idx); |  | ||||||
| 
 |  | ||||||
| void subghz_receiver_exit(void* context); |  | ||||||
| @ -7,29 +7,29 @@ | |||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| 
 | 
 | ||||||
| struct SubghzTestCarrier { | struct SubGhzTestCarrier { | ||||||
|     View* view; |     View* view; | ||||||
|     osTimerId_t timer; |     osTimerId_t timer; | ||||||
|     SubghzTestCarrierCallback callback; |     SubGhzTestCarrierCallback callback; | ||||||
|     void* context; |     void* context; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubghzTestCarrierModelStatusRx, |     SubGhzTestCarrierModelStatusRx, | ||||||
|     SubghzTestCarrierModelStatusTx, |     SubGhzTestCarrierModelStatusTx, | ||||||
| } SubghzTestCarrierModelStatus; | } SubGhzTestCarrierModelStatus; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint8_t frequency; |     uint8_t frequency; | ||||||
|     uint32_t real_frequency; |     uint32_t real_frequency; | ||||||
|     FuriHalSubGhzPath path; |     FuriHalSubGhzPath path; | ||||||
|     float rssi; |     float rssi; | ||||||
|     SubghzTestCarrierModelStatus status; |     SubGhzTestCarrierModelStatus status; | ||||||
| } SubghzTestCarrierModel; | } SubGhzTestCarrierModel; | ||||||
| 
 | 
 | ||||||
| void subghz_test_carrier_set_callback( | void subghz_test_carrier_set_callback( | ||||||
|     SubghzTestCarrier* subghz_test_carrier, |     SubGhzTestCarrier* subghz_test_carrier, | ||||||
|     SubghzTestCarrierCallback callback, |     SubGhzTestCarrierCallback callback, | ||||||
|     void* context) { |     void* context) { | ||||||
|     furi_assert(subghz_test_carrier); |     furi_assert(subghz_test_carrier); | ||||||
|     furi_assert(callback); |     furi_assert(callback); | ||||||
| @ -37,7 +37,7 @@ void subghz_test_carrier_set_callback( | |||||||
|     subghz_test_carrier->context = context; |     subghz_test_carrier->context = context; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_test_carrier_draw(Canvas* canvas, SubghzTestCarrierModel* model) { | void subghz_test_carrier_draw(Canvas* canvas, SubGhzTestCarrierModel* model) { | ||||||
|     char buffer[64]; |     char buffer[64]; | ||||||
| 
 | 
 | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
| @ -67,7 +67,7 @@ void subghz_test_carrier_draw(Canvas* canvas, SubghzTestCarrierModel* model) { | |||||||
|     } |     } | ||||||
|     snprintf(buffer, sizeof(buffer), "Path: %d - %s", model->path, path_name); |     snprintf(buffer, sizeof(buffer), "Path: %d - %s", model->path, path_name); | ||||||
|     canvas_draw_str(canvas, 0, 31, buffer); |     canvas_draw_str(canvas, 0, 31, buffer); | ||||||
|     if(model->status == SubghzTestCarrierModelStatusRx) { |     if(model->status == SubGhzTestCarrierModelStatusRx) { | ||||||
|         snprintf( |         snprintf( | ||||||
|             buffer, |             buffer, | ||||||
|             sizeof(buffer), |             sizeof(buffer), | ||||||
| @ -82,14 +82,14 @@ void subghz_test_carrier_draw(Canvas* canvas, SubghzTestCarrierModel* model) { | |||||||
| 
 | 
 | ||||||
| bool subghz_test_carrier_input(InputEvent* event, void* context) { | bool subghz_test_carrier_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTestCarrier* subghz_test_carrier = context; |     SubGhzTestCarrier* subghz_test_carrier = context; | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyBack || event->type != InputTypeShort) { |     if(event->key == InputKeyBack || event->type != InputTypeShort) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_test_carrier->view, (SubghzTestCarrierModel * model) { |         subghz_test_carrier->view, (SubGhzTestCarrierModel * model) { | ||||||
|             furi_hal_subghz_idle(); |             furi_hal_subghz_idle(); | ||||||
| 
 | 
 | ||||||
|             if(event->key == InputKeyLeft) { |             if(event->key == InputKeyLeft) { | ||||||
| @ -101,10 +101,10 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) { | |||||||
|             } else if(event->key == InputKeyUp) { |             } else if(event->key == InputKeyUp) { | ||||||
|                 if(model->path < FuriHalSubGhzPath868) model->path++; |                 if(model->path < FuriHalSubGhzPath868) model->path++; | ||||||
|             } else if(event->key == InputKeyOk) { |             } else if(event->key == InputKeyOk) { | ||||||
|                 if(model->status == SubghzTestCarrierModelStatusTx) { |                 if(model->status == SubGhzTestCarrierModelStatusTx) { | ||||||
|                     model->status = SubghzTestCarrierModelStatusRx; |                     model->status = SubGhzTestCarrierModelStatusRx; | ||||||
|                 } else { |                 } else { | ||||||
|                     model->status = SubghzTestCarrierModelStatusTx; |                     model->status = SubGhzTestCarrierModelStatusTx; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -112,7 +112,7 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) { | |||||||
|                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]); |                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]); | ||||||
|             furi_hal_subghz_set_path(model->path); |             furi_hal_subghz_set_path(model->path); | ||||||
| 
 | 
 | ||||||
|             if(model->status == SubghzTestCarrierModelStatusRx) { |             if(model->status == SubGhzTestCarrierModelStatusRx) { | ||||||
|                 hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); |                 hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); | ||||||
|                 furi_hal_subghz_rx(); |                 furi_hal_subghz_rx(); | ||||||
|             } else { |             } else { | ||||||
| @ -121,7 +121,7 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) { | |||||||
|                 if(!furi_hal_subghz_tx()) { |                 if(!furi_hal_subghz_tx()) { | ||||||
|                     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); |                     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); | ||||||
|                     subghz_test_carrier->callback( |                     subghz_test_carrier->callback( | ||||||
|                         SubghzTestCarrierEventOnlyRx, subghz_test_carrier->context); |                         SubGhzTestCarrierEventOnlyRx, subghz_test_carrier->context); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -133,7 +133,7 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) { | |||||||
| 
 | 
 | ||||||
| void subghz_test_carrier_enter(void* context) { | void subghz_test_carrier_enter(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTestCarrier* subghz_test_carrier = context; |     SubGhzTestCarrier* subghz_test_carrier = context; | ||||||
| 
 | 
 | ||||||
|     furi_hal_subghz_reset(); |     furi_hal_subghz_reset(); | ||||||
|     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); |     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); | ||||||
| @ -141,13 +141,13 @@ void subghz_test_carrier_enter(void* context) { | |||||||
|     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); |     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_test_carrier->view, (SubghzTestCarrierModel * model) { |         subghz_test_carrier->view, (SubGhzTestCarrierModel * model) { | ||||||
|             model->frequency = subghz_frequencies_433_92_testing; // 433
 |             model->frequency = subghz_frequencies_433_92_testing; // 433
 | ||||||
|             model->real_frequency = |             model->real_frequency = | ||||||
|                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]); |                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]); | ||||||
|             model->path = FuriHalSubGhzPathIsolate; // isolate
 |             model->path = FuriHalSubGhzPathIsolate; // isolate
 | ||||||
|             model->rssi = 0.0f; |             model->rssi = 0.0f; | ||||||
|             model->status = SubghzTestCarrierModelStatusRx; |             model->status = SubGhzTestCarrierModelStatusRx; | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
| @ -158,7 +158,7 @@ void subghz_test_carrier_enter(void* context) { | |||||||
| 
 | 
 | ||||||
| void subghz_test_carrier_exit(void* context) { | void subghz_test_carrier_exit(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTestCarrier* subghz_test_carrier = context; |     SubGhzTestCarrier* subghz_test_carrier = context; | ||||||
| 
 | 
 | ||||||
|     osTimerStop(subghz_test_carrier->timer); |     osTimerStop(subghz_test_carrier->timer); | ||||||
| 
 | 
 | ||||||
| @ -168,11 +168,11 @@ void subghz_test_carrier_exit(void* context) { | |||||||
| 
 | 
 | ||||||
| void subghz_test_carrier_rssi_timer_callback(void* context) { | void subghz_test_carrier_rssi_timer_callback(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTestCarrier* subghz_test_carrier = context; |     SubGhzTestCarrier* subghz_test_carrier = context; | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_test_carrier->view, (SubghzTestCarrierModel * model) { |         subghz_test_carrier->view, (SubGhzTestCarrierModel * model) { | ||||||
|             if(model->status == SubghzTestCarrierModelStatusRx) { |             if(model->status == SubGhzTestCarrierModelStatusRx) { | ||||||
|                 model->rssi = furi_hal_subghz_get_rssi(); |                 model->rssi = furi_hal_subghz_get_rssi(); | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
| @ -180,13 +180,13 @@ void subghz_test_carrier_rssi_timer_callback(void* context) { | |||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SubghzTestCarrier* subghz_test_carrier_alloc() { | SubGhzTestCarrier* subghz_test_carrier_alloc() { | ||||||
|     SubghzTestCarrier* subghz_test_carrier = malloc(sizeof(SubghzTestCarrier)); |     SubGhzTestCarrier* subghz_test_carrier = malloc(sizeof(SubGhzTestCarrier)); | ||||||
| 
 | 
 | ||||||
|     // View allocation and configuration
 |     // View allocation and configuration
 | ||||||
|     subghz_test_carrier->view = view_alloc(); |     subghz_test_carrier->view = view_alloc(); | ||||||
|     view_allocate_model( |     view_allocate_model( | ||||||
|         subghz_test_carrier->view, ViewModelTypeLocking, sizeof(SubghzTestCarrierModel)); |         subghz_test_carrier->view, ViewModelTypeLocking, sizeof(SubGhzTestCarrierModel)); | ||||||
|     view_set_context(subghz_test_carrier->view, subghz_test_carrier); |     view_set_context(subghz_test_carrier->view, subghz_test_carrier); | ||||||
|     view_set_draw_callback(subghz_test_carrier->view, (ViewDrawCallback)subghz_test_carrier_draw); |     view_set_draw_callback(subghz_test_carrier->view, (ViewDrawCallback)subghz_test_carrier_draw); | ||||||
|     view_set_input_callback(subghz_test_carrier->view, subghz_test_carrier_input); |     view_set_input_callback(subghz_test_carrier->view, subghz_test_carrier_input); | ||||||
| @ -199,14 +199,14 @@ SubghzTestCarrier* subghz_test_carrier_alloc() { | |||||||
|     return subghz_test_carrier; |     return subghz_test_carrier; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_test_carrier_free(SubghzTestCarrier* subghz_test_carrier) { | void subghz_test_carrier_free(SubGhzTestCarrier* subghz_test_carrier) { | ||||||
|     furi_assert(subghz_test_carrier); |     furi_assert(subghz_test_carrier); | ||||||
|     osTimerDelete(subghz_test_carrier->timer); |     osTimerDelete(subghz_test_carrier->timer); | ||||||
|     view_free(subghz_test_carrier->view); |     view_free(subghz_test_carrier->view); | ||||||
|     free(subghz_test_carrier); |     free(subghz_test_carrier); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| View* subghz_test_carrier_get_view(SubghzTestCarrier* subghz_test_carrier) { | View* subghz_test_carrier_get_view(SubGhzTestCarrier* subghz_test_carrier) { | ||||||
|     furi_assert(subghz_test_carrier); |     furi_assert(subghz_test_carrier); | ||||||
|     return subghz_test_carrier->view; |     return subghz_test_carrier->view; | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,20 +3,20 @@ | |||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubghzTestCarrierEventOnlyRx, |     SubGhzTestCarrierEventOnlyRx, | ||||||
| } SubghzTestCarrierEvent; | } SubGhzTestCarrierEvent; | ||||||
| 
 | 
 | ||||||
| typedef struct SubghzTestCarrier SubghzTestCarrier; | typedef struct SubGhzTestCarrier SubGhzTestCarrier; | ||||||
| 
 | 
 | ||||||
| typedef void (*SubghzTestCarrierCallback)(SubghzTestCarrierEvent event, void* context); | typedef void (*SubGhzTestCarrierCallback)(SubGhzTestCarrierEvent event, void* context); | ||||||
| 
 | 
 | ||||||
| void subghz_test_carrier_set_callback( | void subghz_test_carrier_set_callback( | ||||||
|     SubghzTestCarrier* subghz_test_carrier, |     SubGhzTestCarrier* subghz_test_carrier, | ||||||
|     SubghzTestCarrierCallback callback, |     SubGhzTestCarrierCallback callback, | ||||||
|     void* context); |     void* context); | ||||||
| 
 | 
 | ||||||
| SubghzTestCarrier* subghz_test_carrier_alloc(); | SubGhzTestCarrier* subghz_test_carrier_alloc(); | ||||||
| 
 | 
 | ||||||
| void subghz_test_carrier_free(SubghzTestCarrier* subghz_test_carrier); | void subghz_test_carrier_free(SubGhzTestCarrier* subghz_test_carrier); | ||||||
| 
 | 
 | ||||||
| View* subghz_test_carrier_get_view(SubghzTestCarrier* subghz_test_carrier); | View* subghz_test_carrier_get_view(SubGhzTestCarrier* subghz_test_carrier); | ||||||
|  | |||||||
| @ -7,26 +7,26 @@ | |||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <toolbox/level_duration.h> | #include <toolbox/level_duration.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_princeton.h> | #include <lib/subghz/protocols/princeton_for_testing.h> | ||||||
| 
 | 
 | ||||||
| #define SUBGHZ_TEST_PACKET_COUNT 500 | #define SUBGHZ_TEST_PACKET_COUNT 500 | ||||||
| 
 | 
 | ||||||
| struct SubghzTestPacket { | struct SubGhzTestPacket { | ||||||
|     View* view; |     View* view; | ||||||
|     osTimerId_t timer; |     osTimerId_t timer; | ||||||
| 
 | 
 | ||||||
|     SubGhzDecoderPrinceton* decoder; |     SubGhzDecoderPrinceton* decoder; | ||||||
|     SubGhzEncoderPrinceton* encoder; |     SubGhzEncoderPrinceton* encoder; | ||||||
|     volatile size_t packet_rx; |     volatile size_t packet_rx; | ||||||
|     SubghzTestPacketCallback callback; |     SubGhzTestPacketCallback callback; | ||||||
|     void* context; |     void* context; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubghzTestPacketModelStatusRx, |     SubGhzTestPacketModelStatusRx, | ||||||
|     SubghzTestPacketModelStatusOnlyRx, |     SubGhzTestPacketModelStatusOnlyRx, | ||||||
|     SubghzTestPacketModelStatusTx, |     SubGhzTestPacketModelStatusTx, | ||||||
| } SubghzTestPacketModelStatus; | } SubGhzTestPacketModelStatus; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint8_t frequency; |     uint8_t frequency; | ||||||
| @ -34,14 +34,14 @@ typedef struct { | |||||||
|     FuriHalSubGhzPath path; |     FuriHalSubGhzPath path; | ||||||
|     float rssi; |     float rssi; | ||||||
|     size_t packets; |     size_t packets; | ||||||
|     SubghzTestPacketModelStatus status; |     SubGhzTestPacketModelStatus status; | ||||||
| } SubghzTestPacketModel; | } SubGhzTestPacketModel; | ||||||
| 
 | 
 | ||||||
| volatile bool subghz_test_packet_overrun = false; | volatile bool subghz_test_packet_overrun = false; | ||||||
| 
 | 
 | ||||||
| void subghz_test_packet_set_callback( | void subghz_test_packet_set_callback( | ||||||
|     SubghzTestPacket* subghz_test_packet, |     SubGhzTestPacket* subghz_test_packet, | ||||||
|     SubghzTestPacketCallback callback, |     SubGhzTestPacketCallback callback, | ||||||
|     void* context) { |     void* context) { | ||||||
|     furi_assert(subghz_test_packet); |     furi_assert(subghz_test_packet); | ||||||
|     furi_assert(callback); |     furi_assert(callback); | ||||||
| @ -51,34 +51,36 @@ void subghz_test_packet_set_callback( | |||||||
| 
 | 
 | ||||||
| static void subghz_test_packet_rx_callback(bool level, uint32_t duration, void* context) { | static void subghz_test_packet_rx_callback(bool level, uint32_t duration, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTestPacket* instance = context; |     SubGhzTestPacket* instance = context; | ||||||
|     subghz_decoder_princeton_parse(instance->decoder, level, duration); |     subghz_decoder_princeton_for_testing_parse(instance->decoder, level, duration); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void subghz_test_packet_rx_pt_callback(SubGhzProtocolCommon* parser, void* context) { | //todo
 | ||||||
|  | static void subghz_test_packet_rx_pt_callback(SubGhzDecoderPrinceton* parser, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTestPacket* instance = context; |     SubGhzTestPacket* instance = context; | ||||||
|     instance->packet_rx++; |     instance->packet_rx++; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void subghz_test_packet_rssi_timer_callback(void* context) { | static void subghz_test_packet_rssi_timer_callback(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTestPacket* instance = context; |     SubGhzTestPacket* instance = context; | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzTestPacketModel * model) { |         instance->view, (SubGhzTestPacketModel * model) { | ||||||
|             if(model->status == SubghzTestPacketModelStatusRx) { |             if(model->status == SubGhzTestPacketModelStatusRx) { | ||||||
|                 model->rssi = furi_hal_subghz_get_rssi(); |                 model->rssi = furi_hal_subghz_get_rssi(); | ||||||
|                 model->packets = instance->packet_rx; |                 model->packets = instance->packet_rx; | ||||||
|             } else if(model->status == SubghzTestPacketModelStatusTx) { |             } else if(model->status == SubGhzTestPacketModelStatusTx) { | ||||||
|                 model->packets = SUBGHZ_TEST_PACKET_COUNT - |                 model->packets = | ||||||
|                                  subghz_encoder_princeton_get_repeat_left(instance->encoder); |                     SUBGHZ_TEST_PACKET_COUNT - | ||||||
|  |                     subghz_encoder_princeton_for_testing_get_repeat_left(instance->encoder); | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void subghz_test_packet_draw(Canvas* canvas, SubghzTestPacketModel* model) { | static void subghz_test_packet_draw(Canvas* canvas, SubGhzTestPacketModel* model) { | ||||||
|     char buffer[64]; |     char buffer[64]; | ||||||
| 
 | 
 | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
| @ -112,7 +114,7 @@ static void subghz_test_packet_draw(Canvas* canvas, SubghzTestPacketModel* model | |||||||
|     snprintf(buffer, sizeof(buffer), "Packets: %d", model->packets); |     snprintf(buffer, sizeof(buffer), "Packets: %d", model->packets); | ||||||
|     canvas_draw_str(canvas, 0, 42, buffer); |     canvas_draw_str(canvas, 0, 42, buffer); | ||||||
| 
 | 
 | ||||||
|     if(model->status == SubghzTestPacketModelStatusRx) { |     if(model->status == SubGhzTestPacketModelStatusRx) { | ||||||
|         snprintf( |         snprintf( | ||||||
|             buffer, |             buffer, | ||||||
|             sizeof(buffer), |             sizeof(buffer), | ||||||
| @ -127,18 +129,18 @@ static void subghz_test_packet_draw(Canvas* canvas, SubghzTestPacketModel* model | |||||||
| 
 | 
 | ||||||
| static bool subghz_test_packet_input(InputEvent* event, void* context) { | static bool subghz_test_packet_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTestPacket* instance = context; |     SubGhzTestPacket* instance = context; | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyBack || event->type != InputTypeShort) { |     if(event->key == InputKeyBack || event->type != InputTypeShort) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzTestPacketModel * model) { |         instance->view, (SubGhzTestPacketModel * model) { | ||||||
|             if(model->status == SubghzTestPacketModelStatusRx) { |             if(model->status == SubGhzTestPacketModelStatusRx) { | ||||||
|                 furi_hal_subghz_stop_async_rx(); |                 furi_hal_subghz_stop_async_rx(); | ||||||
|             } else if(model->status == SubghzTestPacketModelStatusTx) { |             } else if(model->status == SubGhzTestPacketModelStatusTx) { | ||||||
|                 subghz_encoder_princeton_stop(instance->encoder, millis()); |                 subghz_encoder_princeton_for_testing_stop(instance->encoder, millis()); | ||||||
|                 furi_hal_subghz_stop_async_tx(); |                 furi_hal_subghz_stop_async_tx(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -151,10 +153,10 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) { | |||||||
|             } else if(event->key == InputKeyUp) { |             } else if(event->key == InputKeyUp) { | ||||||
|                 if(model->path < FuriHalSubGhzPath868) model->path++; |                 if(model->path < FuriHalSubGhzPath868) model->path++; | ||||||
|             } else if(event->key == InputKeyOk) { |             } else if(event->key == InputKeyOk) { | ||||||
|                 if(model->status == SubghzTestPacketModelStatusRx) { |                 if(model->status == SubGhzTestPacketModelStatusRx) { | ||||||
|                     model->status = SubghzTestPacketModelStatusTx; |                     model->status = SubGhzTestPacketModelStatusTx; | ||||||
|                 } else { |                 } else { | ||||||
|                     model->status = SubghzTestPacketModelStatusRx; |                     model->status = SubGhzTestPacketModelStatusRx; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -162,18 +164,18 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) { | |||||||
|                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]); |                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]); | ||||||
|             furi_hal_subghz_set_path(model->path); |             furi_hal_subghz_set_path(model->path); | ||||||
| 
 | 
 | ||||||
|             if(model->status == SubghzTestPacketModelStatusRx) { |             if(model->status == SubGhzTestPacketModelStatusRx) { | ||||||
|                 furi_hal_subghz_start_async_rx(subghz_test_packet_rx_callback, instance); |                 furi_hal_subghz_start_async_rx(subghz_test_packet_rx_callback, instance); | ||||||
|             } else { |             } else { | ||||||
|                 subghz_encoder_princeton_set( |                 subghz_encoder_princeton_for_testing_set( | ||||||
|                     instance->encoder, |                     instance->encoder, | ||||||
|                     0x00AABBCC, |                     0x00AABBCC, | ||||||
|                     SUBGHZ_TEST_PACKET_COUNT, |                     SUBGHZ_TEST_PACKET_COUNT, | ||||||
|                     subghz_frequencies_testing[model->frequency]); |                     subghz_frequencies_testing[model->frequency]); | ||||||
|                 if(!furi_hal_subghz_start_async_tx( |                 if(!furi_hal_subghz_start_async_tx( | ||||||
|                        subghz_encoder_princeton_yield, instance->encoder)) { |                        subghz_encoder_princeton_for_testing_yield, instance->encoder)) { | ||||||
|                     model->status = SubghzTestPacketModelStatusOnlyRx; |                     model->status = SubGhzTestPacketModelStatusOnlyRx; | ||||||
|                     instance->callback(SubghzTestPacketEventOnlyRx, instance->context); |                     instance->callback(SubGhzTestPacketEventOnlyRx, instance->context); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -185,19 +187,19 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) { | |||||||
| 
 | 
 | ||||||
| void subghz_test_packet_enter(void* context) { | void subghz_test_packet_enter(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTestPacket* instance = context; |     SubGhzTestPacket* instance = context; | ||||||
| 
 | 
 | ||||||
|     furi_hal_subghz_reset(); |     furi_hal_subghz_reset(); | ||||||
|     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); |     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzTestPacketModel * model) { |         instance->view, (SubGhzTestPacketModel * model) { | ||||||
|             model->frequency = subghz_frequencies_433_92_testing; |             model->frequency = subghz_frequencies_433_92_testing; | ||||||
|             model->real_frequency = |             model->real_frequency = | ||||||
|                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]); |                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]); | ||||||
|             model->path = FuriHalSubGhzPathIsolate; // isolate
 |             model->path = FuriHalSubGhzPathIsolate; // isolate
 | ||||||
|             model->rssi = 0.0f; |             model->rssi = 0.0f; | ||||||
|             model->status = SubghzTestPacketModelStatusRx; |             model->status = SubGhzTestPacketModelStatusRx; | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
| @ -208,17 +210,17 @@ void subghz_test_packet_enter(void* context) { | |||||||
| 
 | 
 | ||||||
| void subghz_test_packet_exit(void* context) { | void subghz_test_packet_exit(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTestPacket* instance = context; |     SubGhzTestPacket* instance = context; | ||||||
| 
 | 
 | ||||||
|     osTimerStop(instance->timer); |     osTimerStop(instance->timer); | ||||||
| 
 | 
 | ||||||
|     // Reinitialize IC to default state
 |     // Reinitialize IC to default state
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzTestPacketModel * model) { |         instance->view, (SubGhzTestPacketModel * model) { | ||||||
|             if(model->status == SubghzTestPacketModelStatusRx) { |             if(model->status == SubGhzTestPacketModelStatusRx) { | ||||||
|                 furi_hal_subghz_stop_async_rx(); |                 furi_hal_subghz_stop_async_rx(); | ||||||
|             } else if(model->status == SubghzTestPacketModelStatusTx) { |             } else if(model->status == SubGhzTestPacketModelStatusTx) { | ||||||
|                 subghz_encoder_princeton_stop(instance->encoder, millis()); |                 subghz_encoder_princeton_for_testing_stop(instance->encoder, millis()); | ||||||
|                 furi_hal_subghz_stop_async_tx(); |                 furi_hal_subghz_stop_async_tx(); | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
| @ -226,12 +228,12 @@ void subghz_test_packet_exit(void* context) { | |||||||
|     furi_hal_subghz_sleep(); |     furi_hal_subghz_sleep(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SubghzTestPacket* subghz_test_packet_alloc() { | SubGhzTestPacket* subghz_test_packet_alloc() { | ||||||
|     SubghzTestPacket* instance = malloc(sizeof(SubghzTestPacket)); |     SubGhzTestPacket* instance = malloc(sizeof(SubGhzTestPacket)); | ||||||
| 
 | 
 | ||||||
|     // View allocation and configuration
 |     // View allocation and configuration
 | ||||||
|     instance->view = view_alloc(); |     instance->view = view_alloc(); | ||||||
|     view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubghzTestPacketModel)); |     view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubGhzTestPacketModel)); | ||||||
|     view_set_context(instance->view, instance); |     view_set_context(instance->view, instance); | ||||||
|     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_test_packet_draw); |     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_test_packet_draw); | ||||||
|     view_set_input_callback(instance->view, subghz_test_packet_input); |     view_set_input_callback(instance->view, subghz_test_packet_input); | ||||||
| @ -241,26 +243,26 @@ SubghzTestPacket* subghz_test_packet_alloc() { | |||||||
|     instance->timer = |     instance->timer = | ||||||
|         osTimerNew(subghz_test_packet_rssi_timer_callback, osTimerPeriodic, instance, NULL); |         osTimerNew(subghz_test_packet_rssi_timer_callback, osTimerPeriodic, instance, NULL); | ||||||
| 
 | 
 | ||||||
|     instance->decoder = subghz_decoder_princeton_alloc(); |     instance->decoder = subghz_decoder_princeton_for_testing_alloc(); | ||||||
|     subghz_protocol_common_set_callback( |     subghz_decoder_princeton_for_testing_set_callback( | ||||||
|         (SubGhzProtocolCommon*)instance->decoder, subghz_test_packet_rx_pt_callback, instance); |         instance->decoder, subghz_test_packet_rx_pt_callback, instance); | ||||||
|     instance->encoder = subghz_encoder_princeton_alloc(); |     instance->encoder = subghz_encoder_princeton_for_testing_alloc(); | ||||||
| 
 | 
 | ||||||
|     return instance; |     return instance; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_test_packet_free(SubghzTestPacket* instance) { | void subghz_test_packet_free(SubGhzTestPacket* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
| 
 | 
 | ||||||
|     subghz_decoder_princeton_free(instance->decoder); |     subghz_decoder_princeton_for_testing_free(instance->decoder); | ||||||
|     subghz_encoder_princeton_free(instance->encoder); |     subghz_encoder_princeton_for_testing_free(instance->encoder); | ||||||
| 
 | 
 | ||||||
|     osTimerDelete(instance->timer); |     osTimerDelete(instance->timer); | ||||||
|     view_free(instance->view); |     view_free(instance->view); | ||||||
|     free(instance); |     free(instance); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| View* subghz_test_packet_get_view(SubghzTestPacket* instance) { | View* subghz_test_packet_get_view(SubGhzTestPacket* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     return instance->view; |     return instance->view; | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,20 +3,20 @@ | |||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubghzTestPacketEventOnlyRx, |     SubGhzTestPacketEventOnlyRx, | ||||||
| } SubghzTestPacketEvent; | } SubGhzTestPacketEvent; | ||||||
| 
 | 
 | ||||||
| typedef struct SubghzTestPacket SubghzTestPacket; | typedef struct SubGhzTestPacket SubGhzTestPacket; | ||||||
| 
 | 
 | ||||||
| typedef void (*SubghzTestPacketCallback)(SubghzTestPacketEvent event, void* context); | typedef void (*SubGhzTestPacketCallback)(SubGhzTestPacketEvent event, void* context); | ||||||
| 
 | 
 | ||||||
| void subghz_test_packet_set_callback( | void subghz_test_packet_set_callback( | ||||||
|     SubghzTestPacket* subghz_test_packet, |     SubGhzTestPacket* subghz_test_packet, | ||||||
|     SubghzTestPacketCallback callback, |     SubGhzTestPacketCallback callback, | ||||||
|     void* context); |     void* context); | ||||||
| 
 | 
 | ||||||
| SubghzTestPacket* subghz_test_packet_alloc(); | SubGhzTestPacket* subghz_test_packet_alloc(); | ||||||
| 
 | 
 | ||||||
| void subghz_test_packet_free(SubghzTestPacket* subghz_test_packet); | void subghz_test_packet_free(SubGhzTestPacket* subghz_test_packet); | ||||||
| 
 | 
 | ||||||
| View* subghz_test_packet_get_view(SubghzTestPacket* subghz_test_packet); | View* subghz_test_packet_get_view(SubGhzTestPacket* subghz_test_packet); | ||||||
|  | |||||||
| @ -7,14 +7,14 @@ | |||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <notification/notification_messages.h> | #include <notification/notification_messages.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_princeton.h> | #include <lib/subghz/protocols/princeton_for_testing.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "SubGhzTestStatic" | #define TAG "SubGhzTestStatic" | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubghzTestStaticStatusIDLE, |     SubGhzTestStaticStatusIDLE, | ||||||
|     SubghzTestStaticStatusTX, |     SubGhzTestStaticStatusTX, | ||||||
| } SubghzTestStaticStatus; | } SubGhzTestStaticStatus; | ||||||
| 
 | 
 | ||||||
| static const uint32_t subghz_test_static_keys[] = { | static const uint32_t subghz_test_static_keys[] = { | ||||||
|     0x0074BADE, |     0x0074BADE, | ||||||
| @ -23,11 +23,11 @@ static const uint32_t subghz_test_static_keys[] = { | |||||||
|     0x00E34A4E, |     0x00E34A4E, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct SubghzTestStatic { | struct SubGhzTestStatic { | ||||||
|     View* view; |     View* view; | ||||||
|     SubghzTestStaticStatus satus_tx; |     SubGhzTestStaticStatus satus_tx; | ||||||
|     SubGhzEncoderPrinceton* encoder; |     SubGhzEncoderPrinceton* encoder; | ||||||
|     SubghzTestStaticCallback callback; |     SubGhzTestStaticCallback callback; | ||||||
|     void* context; |     void* context; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -35,11 +35,11 @@ typedef struct { | |||||||
|     uint8_t frequency; |     uint8_t frequency; | ||||||
|     uint32_t real_frequency; |     uint32_t real_frequency; | ||||||
|     uint8_t button; |     uint8_t button; | ||||||
| } SubghzTestStaticModel; | } SubGhzTestStaticModel; | ||||||
| 
 | 
 | ||||||
| void subghz_test_static_set_callback( | void subghz_test_static_set_callback( | ||||||
|     SubghzTestStatic* subghz_test_static, |     SubGhzTestStatic* subghz_test_static, | ||||||
|     SubghzTestStaticCallback callback, |     SubGhzTestStaticCallback callback, | ||||||
|     void* context) { |     void* context) { | ||||||
|     furi_assert(subghz_test_static); |     furi_assert(subghz_test_static); | ||||||
|     furi_assert(callback); |     furi_assert(callback); | ||||||
| @ -47,7 +47,7 @@ void subghz_test_static_set_callback( | |||||||
|     subghz_test_static->context = context; |     subghz_test_static->context = context; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_test_static_draw(Canvas* canvas, SubghzTestStaticModel* model) { | void subghz_test_static_draw(Canvas* canvas, SubGhzTestStaticModel* model) { | ||||||
|     char buffer[64]; |     char buffer[64]; | ||||||
| 
 | 
 | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
| @ -70,14 +70,14 @@ void subghz_test_static_draw(Canvas* canvas, SubghzTestStaticModel* model) { | |||||||
| 
 | 
 | ||||||
| bool subghz_test_static_input(InputEvent* event, void* context) { | bool subghz_test_static_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTestStatic* instance = context; |     SubGhzTestStatic* instance = context; | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyBack) { |     if(event->key == InputKeyBack) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzTestStaticModel * model) { |         instance->view, (SubGhzTestStaticModel * model) { | ||||||
|             if(event->type == InputTypeShort) { |             if(event->type == InputTypeShort) { | ||||||
|                 if(event->key == InputKeyLeft) { |                 if(event->key == InputKeyLeft) { | ||||||
|                     if(model->frequency > 0) model->frequency--; |                     if(model->frequency > 0) model->frequency--; | ||||||
| @ -99,31 +99,31 @@ bool subghz_test_static_input(InputEvent* event, void* context) { | |||||||
|                     furi_hal_subghz_set_frequency_and_path( |                     furi_hal_subghz_set_frequency_and_path( | ||||||
|                         subghz_frequencies_testing[model->frequency]); |                         subghz_frequencies_testing[model->frequency]); | ||||||
|                     if(!furi_hal_subghz_tx()) { |                     if(!furi_hal_subghz_tx()) { | ||||||
|                         instance->callback(SubghzTestStaticEventOnlyRx, instance->context); |                         instance->callback(SubGhzTestStaticEventOnlyRx, instance->context); | ||||||
|                     } else { |                     } else { | ||||||
|                         notification_message_block(notification, &sequence_set_red_255); |                         notification_message_block(notification, &sequence_set_red_255); | ||||||
| 
 | 
 | ||||||
|                         FURI_LOG_I(TAG, "TX Start"); |                         FURI_LOG_I(TAG, "TX Start"); | ||||||
| 
 | 
 | ||||||
|                         subghz_encoder_princeton_set( |                         subghz_encoder_princeton_for_testing_set( | ||||||
|                             instance->encoder, |                             instance->encoder, | ||||||
|                             subghz_test_static_keys[model->button], |                             subghz_test_static_keys[model->button], | ||||||
|                             10000, |                             10000, | ||||||
|                             subghz_frequencies_testing[model->frequency]); |                             subghz_frequencies_testing[model->frequency]); | ||||||
| 
 | 
 | ||||||
|                         furi_hal_subghz_start_async_tx( |                         furi_hal_subghz_start_async_tx( | ||||||
|                             subghz_encoder_princeton_yield, instance->encoder); |                             subghz_encoder_princeton_for_testing_yield, instance->encoder); | ||||||
|                         instance->satus_tx = SubghzTestStaticStatusTX; |                         instance->satus_tx = SubGhzTestStaticStatusTX; | ||||||
|                     } |                     } | ||||||
|                 } else if(event->type == InputTypeRelease) { |                 } else if(event->type == InputTypeRelease) { | ||||||
|                     if(instance->satus_tx == SubghzTestStaticStatusTX) { |                     if(instance->satus_tx == SubGhzTestStaticStatusTX) { | ||||||
|                         FURI_LOG_I(TAG, "TX Stop"); |                         FURI_LOG_I(TAG, "TX Stop"); | ||||||
|                         subghz_encoder_princeton_stop(instance->encoder, millis()); |                         subghz_encoder_princeton_for_testing_stop(instance->encoder, millis()); | ||||||
|                         subghz_encoder_princeton_print_log(instance->encoder); |                         subghz_encoder_princeton_for_testing_print_log(instance->encoder); | ||||||
|                         furi_hal_subghz_stop_async_tx(); |                         furi_hal_subghz_stop_async_tx(); | ||||||
|                         notification_message(notification, &sequence_reset_red); |                         notification_message(notification, &sequence_reset_red); | ||||||
|                     } |                     } | ||||||
|                     instance->satus_tx = SubghzTestStaticStatusIDLE; |                     instance->satus_tx = SubGhzTestStaticStatusIDLE; | ||||||
|                 } |                 } | ||||||
|                 furi_record_close("notification"); |                 furi_record_close("notification"); | ||||||
|             } |             } | ||||||
| @ -136,17 +136,17 @@ bool subghz_test_static_input(InputEvent* event, void* context) { | |||||||
| 
 | 
 | ||||||
| void subghz_test_static_enter(void* context) { | void subghz_test_static_enter(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTestStatic* instance = context; |     SubGhzTestStatic* instance = context; | ||||||
| 
 | 
 | ||||||
|     furi_hal_subghz_reset(); |     furi_hal_subghz_reset(); | ||||||
|     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); |     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); | ||||||
| 
 | 
 | ||||||
|     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); |     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); | ||||||
|     hal_gpio_write(&gpio_cc1101_g0, false); |     hal_gpio_write(&gpio_cc1101_g0, false); | ||||||
|     instance->satus_tx = SubghzTestStaticStatusIDLE; |     instance->satus_tx = SubGhzTestStaticStatusIDLE; | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzTestStaticModel * model) { |         instance->view, (SubGhzTestStaticModel * model) { | ||||||
|             model->frequency = subghz_frequencies_433_92_testing; |             model->frequency = subghz_frequencies_433_92_testing; | ||||||
|             model->real_frequency = subghz_frequencies_testing[model->frequency]; |             model->real_frequency = subghz_frequencies_testing[model->frequency]; | ||||||
|             model->button = 0; |             model->button = 0; | ||||||
| @ -160,31 +160,31 @@ void subghz_test_static_exit(void* context) { | |||||||
|     furi_hal_subghz_sleep(); |     furi_hal_subghz_sleep(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SubghzTestStatic* subghz_test_static_alloc() { | SubGhzTestStatic* subghz_test_static_alloc() { | ||||||
|     SubghzTestStatic* instance = malloc(sizeof(SubghzTestStatic)); |     SubGhzTestStatic* instance = malloc(sizeof(SubGhzTestStatic)); | ||||||
| 
 | 
 | ||||||
|     // View allocation and configuration
 |     // View allocation and configuration
 | ||||||
|     instance->view = view_alloc(); |     instance->view = view_alloc(); | ||||||
|     view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubghzTestStaticModel)); |     view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubGhzTestStaticModel)); | ||||||
|     view_set_context(instance->view, instance); |     view_set_context(instance->view, instance); | ||||||
|     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_test_static_draw); |     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_test_static_draw); | ||||||
|     view_set_input_callback(instance->view, subghz_test_static_input); |     view_set_input_callback(instance->view, subghz_test_static_input); | ||||||
|     view_set_enter_callback(instance->view, subghz_test_static_enter); |     view_set_enter_callback(instance->view, subghz_test_static_enter); | ||||||
|     view_set_exit_callback(instance->view, subghz_test_static_exit); |     view_set_exit_callback(instance->view, subghz_test_static_exit); | ||||||
| 
 | 
 | ||||||
|     instance->encoder = subghz_encoder_princeton_alloc(); |     instance->encoder = subghz_encoder_princeton_for_testing_alloc(); | ||||||
| 
 | 
 | ||||||
|     return instance; |     return instance; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_test_static_free(SubghzTestStatic* instance) { | void subghz_test_static_free(SubGhzTestStatic* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     subghz_encoder_princeton_free(instance->encoder); |     subghz_encoder_princeton_for_testing_free(instance->encoder); | ||||||
|     view_free(instance->view); |     view_free(instance->view); | ||||||
|     free(instance); |     free(instance); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| View* subghz_test_static_get_view(SubghzTestStatic* instance) { | View* subghz_test_static_get_view(SubGhzTestStatic* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     return instance->view; |     return instance->view; | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,20 +3,20 @@ | |||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubghzTestStaticEventOnlyRx, |     SubGhzTestStaticEventOnlyRx, | ||||||
| } SubghzTestStaticEvent; | } SubGhzTestStaticEvent; | ||||||
| 
 | 
 | ||||||
| typedef struct SubghzTestStatic SubghzTestStatic; | typedef struct SubGhzTestStatic SubGhzTestStatic; | ||||||
| 
 | 
 | ||||||
| typedef void (*SubghzTestStaticCallback)(SubghzTestStaticEvent event, void* context); | typedef void (*SubGhzTestStaticCallback)(SubGhzTestStaticEvent event, void* context); | ||||||
| 
 | 
 | ||||||
| void subghz_test_static_set_callback( | void subghz_test_static_set_callback( | ||||||
|     SubghzTestStatic* subghz_test_static, |     SubGhzTestStatic* subghz_test_static, | ||||||
|     SubghzTestStaticCallback callback, |     SubGhzTestStaticCallback callback, | ||||||
|     void* context); |     void* context); | ||||||
| 
 | 
 | ||||||
| SubghzTestStatic* subghz_test_static_alloc(); | SubGhzTestStatic* subghz_test_static_alloc(); | ||||||
| 
 | 
 | ||||||
| void subghz_test_static_free(SubghzTestStatic* subghz_static); | void subghz_test_static_free(SubGhzTestStatic* subghz_static); | ||||||
| 
 | 
 | ||||||
| View* subghz_test_static_get_view(SubghzTestStatic* subghz_static); | View* subghz_test_static_get_view(SubGhzTestStatic* subghz_static); | ||||||
|  | |||||||
| @ -1,26 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <gui/view.h> |  | ||||||
| #include "../helpers/subghz_custom_event.h" |  | ||||||
| 
 |  | ||||||
| typedef struct SubghzTransmitter SubghzTransmitter; |  | ||||||
| 
 |  | ||||||
| typedef void (*SubghzTransmitterCallback)(SubghzCustomEvent event, void* context); |  | ||||||
| 
 |  | ||||||
| void subghz_transmitter_set_callback( |  | ||||||
|     SubghzTransmitter* subghz_transmitter, |  | ||||||
|     SubghzTransmitterCallback callback, |  | ||||||
|     void* context); |  | ||||||
| 
 |  | ||||||
| SubghzTransmitter* subghz_transmitter_alloc(); |  | ||||||
| 
 |  | ||||||
| void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter); |  | ||||||
| 
 |  | ||||||
| View* subghz_transmitter_get_view(SubghzTransmitter* subghz_transmitter); |  | ||||||
| 
 |  | ||||||
| void subghz_transmitter_add_data_to_show( |  | ||||||
|     SubghzTransmitter* subghz_transmitter, |  | ||||||
|     const char* key_str, |  | ||||||
|     const char* frequency_str, |  | ||||||
|     const char* preset_str, |  | ||||||
|     uint8_t show_button); |  | ||||||
| @ -1,12 +1,12 @@ | |||||||
| #include "subghz_transmitter.h" | #include "transmitter.h" | ||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| 
 | 
 | ||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| 
 | 
 | ||||||
| struct SubghzTransmitter { | struct SubGhzViewTransmitter { | ||||||
|     View* view; |     View* view; | ||||||
|     SubghzTransmitterCallback callback; |     SubGhzViewTransmitterCallback callback; | ||||||
|     void* context; |     void* context; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -15,11 +15,11 @@ typedef struct { | |||||||
|     string_t preset_str; |     string_t preset_str; | ||||||
|     string_t key_str; |     string_t key_str; | ||||||
|     uint8_t show_button; |     uint8_t show_button; | ||||||
| } SubghzTransmitterModel; | } SubGhzViewTransmitterModel; | ||||||
| 
 | 
 | ||||||
| void subghz_transmitter_set_callback( | void subghz_view_transmitter_set_callback( | ||||||
|     SubghzTransmitter* subghz_transmitter, |     SubGhzViewTransmitter* subghz_transmitter, | ||||||
|     SubghzTransmitterCallback callback, |     SubGhzViewTransmitterCallback callback, | ||||||
|     void* context) { |     void* context) { | ||||||
|     furi_assert(subghz_transmitter); |     furi_assert(subghz_transmitter); | ||||||
| 
 | 
 | ||||||
| @ -27,15 +27,15 @@ void subghz_transmitter_set_callback( | |||||||
|     subghz_transmitter->context = context; |     subghz_transmitter->context = context; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_transmitter_add_data_to_show( | void subghz_view_transmitter_add_data_to_show( | ||||||
|     SubghzTransmitter* subghz_transmitter, |     SubGhzViewTransmitter* subghz_transmitter, | ||||||
|     const char* key_str, |     const char* key_str, | ||||||
|     const char* frequency_str, |     const char* frequency_str, | ||||||
|     const char* preset_str, |     const char* preset_str, | ||||||
|     uint8_t show_button) { |     uint8_t show_button) { | ||||||
|     furi_assert(subghz_transmitter); |     furi_assert(subghz_transmitter); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |         subghz_transmitter->view, (SubGhzViewTransmitterModel * model) { | ||||||
|             string_set(model->key_str, key_str); |             string_set(model->key_str, key_str); | ||||||
|             string_set(model->frequency_str, frequency_str); |             string_set(model->frequency_str, frequency_str); | ||||||
|             string_set(model->preset_str, preset_str); |             string_set(model->preset_str, preset_str); | ||||||
| @ -44,7 +44,7 @@ void subghz_transmitter_add_data_to_show( | |||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void subghz_transmitter_button_right(Canvas* canvas, const char* str) { | static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str) { | ||||||
|     const uint8_t button_height = 13; |     const uint8_t button_height = 13; | ||||||
|     const uint8_t vertical_offset = 3; |     const uint8_t vertical_offset = 3; | ||||||
|     const uint8_t horizontal_offset = 1; |     const uint8_t horizontal_offset = 1; | ||||||
| @ -75,24 +75,24 @@ static void subghz_transmitter_button_right(Canvas* canvas, const char* str) { | |||||||
|     canvas_invert_color(canvas); |     canvas_invert_color(canvas); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) { | void subghz_view_transmitter_draw(Canvas* canvas, SubGhzViewTransmitterModel* model) { | ||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     canvas_set_font(canvas, FontSecondary); |     canvas_set_font(canvas, FontSecondary); | ||||||
|     elements_multiline_text(canvas, 0, 8, string_get_cstr(model->key_str)); |     elements_multiline_text(canvas, 0, 8, string_get_cstr(model->key_str)); | ||||||
|     canvas_draw_str(canvas, 78, 8, string_get_cstr(model->frequency_str)); |     canvas_draw_str(canvas, 78, 8, string_get_cstr(model->frequency_str)); | ||||||
|     canvas_draw_str(canvas, 113, 8, string_get_cstr(model->preset_str)); |     canvas_draw_str(canvas, 113, 8, string_get_cstr(model->preset_str)); | ||||||
|     if(model->show_button) subghz_transmitter_button_right(canvas, "Send"); |     if(model->show_button) subghz_view_transmitter_button_right(canvas, "Send"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_transmitter_input(InputEvent* event, void* context) { | bool subghz_view_transmitter_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTransmitter* subghz_transmitter = context; |     SubGhzViewTransmitter* subghz_transmitter = context; | ||||||
|     bool can_be_sent = false; |     bool can_be_sent = false; | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyBack && event->type == InputTypeShort) { |     if(event->key == InputKeyBack && event->type == InputTypeShort) { | ||||||
|         with_view_model( |         with_view_model( | ||||||
|             subghz_transmitter->view, (SubghzTransmitterModel * model) { |             subghz_transmitter->view, (SubGhzViewTransmitterModel * model) { | ||||||
|                 string_reset(model->frequency_str); |                 string_reset(model->frequency_str); | ||||||
|                 string_reset(model->preset_str); |                 string_reset(model->preset_str); | ||||||
|                 string_reset(model->key_str); |                 string_reset(model->key_str); | ||||||
| @ -103,7 +103,7 @@ bool subghz_transmitter_input(InputEvent* event, void* context) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |         subghz_transmitter->view, (SubGhzViewTransmitterModel * model) { | ||||||
|             if(model->show_button) { |             if(model->show_button) { | ||||||
|                 can_be_sent = true; |                 can_be_sent = true; | ||||||
|             } |             } | ||||||
| @ -112,42 +112,41 @@ bool subghz_transmitter_input(InputEvent* event, void* context) { | |||||||
| 
 | 
 | ||||||
|     if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { |     if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { | ||||||
|         subghz_transmitter->callback( |         subghz_transmitter->callback( | ||||||
|             SubghzCustomEventViewTransmitterSendStart, subghz_transmitter->context); |             SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); | ||||||
|         return true; |         return true; | ||||||
|     } else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) { |     } else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) { | ||||||
|         subghz_transmitter->callback( |         subghz_transmitter->callback( | ||||||
|             SubghzCustomEventViewTransmitterSendStop, subghz_transmitter->context); |             SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_transmitter_enter(void* context) { | void subghz_view_transmitter_enter(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     // SubghzTransmitter* subghz_transmitter = context;
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_transmitter_exit(void* context) { | void subghz_view_transmitter_exit(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     // SubghzTransmitter* subghz_transmitter = context;
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SubghzTransmitter* subghz_transmitter_alloc() { | SubGhzViewTransmitter* subghz_view_transmitter_alloc() { | ||||||
|     SubghzTransmitter* subghz_transmitter = malloc(sizeof(SubghzTransmitter)); |     SubGhzViewTransmitter* subghz_transmitter = malloc(sizeof(SubGhzViewTransmitter)); | ||||||
| 
 | 
 | ||||||
|     // View allocation and configuration
 |     // View allocation and configuration
 | ||||||
|     subghz_transmitter->view = view_alloc(); |     subghz_transmitter->view = view_alloc(); | ||||||
|     view_allocate_model( |     view_allocate_model( | ||||||
|         subghz_transmitter->view, ViewModelTypeLocking, sizeof(SubghzTransmitterModel)); |         subghz_transmitter->view, ViewModelTypeLocking, sizeof(SubGhzViewTransmitterModel)); | ||||||
|     view_set_context(subghz_transmitter->view, subghz_transmitter); |     view_set_context(subghz_transmitter->view, subghz_transmitter); | ||||||
|     view_set_draw_callback(subghz_transmitter->view, (ViewDrawCallback)subghz_transmitter_draw); |     view_set_draw_callback( | ||||||
|     view_set_input_callback(subghz_transmitter->view, subghz_transmitter_input); |         subghz_transmitter->view, (ViewDrawCallback)subghz_view_transmitter_draw); | ||||||
|     view_set_enter_callback(subghz_transmitter->view, subghz_transmitter_enter); |     view_set_input_callback(subghz_transmitter->view, subghz_view_transmitter_input); | ||||||
|     view_set_exit_callback(subghz_transmitter->view, subghz_transmitter_exit); |     view_set_enter_callback(subghz_transmitter->view, subghz_view_transmitter_enter); | ||||||
|  |     view_set_exit_callback(subghz_transmitter->view, subghz_view_transmitter_exit); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |         subghz_transmitter->view, (SubGhzViewTransmitterModel * model) { | ||||||
|             string_init(model->frequency_str); |             string_init(model->frequency_str); | ||||||
|             string_init(model->preset_str); |             string_init(model->preset_str); | ||||||
|             string_init(model->key_str); |             string_init(model->key_str); | ||||||
| @ -156,11 +155,11 @@ SubghzTransmitter* subghz_transmitter_alloc() { | |||||||
|     return subghz_transmitter; |     return subghz_transmitter; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter) { | void subghz_view_transmitter_free(SubGhzViewTransmitter* subghz_transmitter) { | ||||||
|     furi_assert(subghz_transmitter); |     furi_assert(subghz_transmitter); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |         subghz_transmitter->view, (SubGhzViewTransmitterModel * model) { | ||||||
|             string_clear(model->frequency_str); |             string_clear(model->frequency_str); | ||||||
|             string_clear(model->preset_str); |             string_clear(model->preset_str); | ||||||
|             string_clear(model->key_str); |             string_clear(model->key_str); | ||||||
| @ -170,7 +169,7 @@ void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter) { | |||||||
|     free(subghz_transmitter); |     free(subghz_transmitter); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| View* subghz_transmitter_get_view(SubghzTransmitter* subghz_transmitter) { | View* subghz_view_transmitter_get_view(SubGhzViewTransmitter* subghz_transmitter) { | ||||||
|     furi_assert(subghz_transmitter); |     furi_assert(subghz_transmitter); | ||||||
|     return subghz_transmitter->view; |     return subghz_transmitter->view; | ||||||
| } | } | ||||||
							
								
								
									
										26
									
								
								applications/subghz/views/transmitter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								applications/subghz/views/transmitter.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include "../helpers/subghz_custom_event.h" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzViewTransmitter SubGhzViewTransmitter; | ||||||
|  | 
 | ||||||
|  | typedef void (*SubGhzViewTransmitterCallback)(SubGhzCustomEvent event, void* context); | ||||||
|  | 
 | ||||||
|  | void subghz_view_transmitter_set_callback( | ||||||
|  |     SubGhzViewTransmitter* subghz_transmitter, | ||||||
|  |     SubGhzViewTransmitterCallback callback, | ||||||
|  |     void* context); | ||||||
|  | 
 | ||||||
|  | SubGhzViewTransmitter* subghz_view_transmitter_alloc(); | ||||||
|  | 
 | ||||||
|  | void subghz_view_transmitter_free(SubGhzViewTransmitter* subghz_transmitter); | ||||||
|  | 
 | ||||||
|  | View* subghz_view_transmitter_get_view(SubGhzViewTransmitter* subghz_transmitter); | ||||||
|  | 
 | ||||||
|  | void subghz_view_transmitter_add_data_to_show( | ||||||
|  |     SubGhzViewTransmitter* subghz_transmitter, | ||||||
|  |     const char* key_str, | ||||||
|  |     const char* frequency_str, | ||||||
|  |     const char* preset_str, | ||||||
|  |     uint8_t show_button); | ||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										6
									
								
								assets/resources/subghz/nice_flor_s
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								assets/resources/subghz/nice_flor_s
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | Filetype: Flipper SubGhz Keystore RAW File | ||||||
|  | Version: 0 | ||||||
|  | Encryption: 1 | ||||||
|  | IV: 33 69 62 1D AD 20 1B B8 A1 6C CF 6F 6B 6F D5 18 | ||||||
|  | Encrypt_data: RAW | ||||||
|  | 9C1D6E6733912B28AC0FF1A191660810BDFF00D19BF7839AFF5B2AAFBBC91A38 | ||||||
| @ -1,5 +1,6 @@ | |||||||
| PROJECT_ROOT	= $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))..) | MAKEFILE_DIR	:= $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) | ||||||
| PROJECT			= bootloader | PROJECT_ROOT	:= $(abspath $(MAKEFILE_DIR)/..) | ||||||
|  | PROJECT			:= bootloader | ||||||
| 
 | 
 | ||||||
| include 		$(PROJECT_ROOT)/make/base.mk | include 		$(PROJECT_ROOT)/make/base.mk | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| PROJECT_ROOT	= $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))..) | MAKEFILE_DIR	:= $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) | ||||||
| PROJECT			= firmware | PROJECT_ROOT	:= $(abspath $(MAKEFILE_DIR)/..) | ||||||
|  | PROJECT			:= firmware | ||||||
| 
 | 
 | ||||||
| include 		$(PROJECT_ROOT)/make/base.mk | include 		$(PROJECT_ROOT)/make/base.mk | ||||||
| include 		$(PROJECT_ROOT)/make/freertos-heap.mk | include 		$(PROJECT_ROOT)/make/freertos-heap.mk | ||||||
|  | |||||||
| @ -20,6 +20,6 @@ | |||||||
| - `qrcode`              - Qr code generator library | - `qrcode`              - Qr code generator library | ||||||
| - `ST25RFAL002`         - ST253916 driver and NFC hal | - `ST25RFAL002`         - ST253916 driver and NFC hal | ||||||
| - `STM32CubeWB`         - STM32WB series cube package | - `STM32CubeWB`         - STM32WB series cube package | ||||||
| - `subghz`              - Subghz library | - `subghz`              - SubGhz library | ||||||
| - `toolbox`             - Toolbox of things that we are using but don't place in core | - `toolbox`             - Toolbox of things that we are using but don't place in core | ||||||
| - `u8g2`                - Graphics library that we use to draw GUI | - `u8g2`                - Graphics library that we use to draw GUI | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								lib/subghz/blocks/const.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								lib/subghz/blocks/const.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | #include "const.h" | ||||||
							
								
								
									
										12
									
								
								lib/subghz/blocks/const.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								lib/subghz/blocks/const.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stddef.h> | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     const uint16_t te_long; | ||||||
|  |     const uint16_t te_short; | ||||||
|  |     const uint16_t te_delta; | ||||||
|  |     const uint8_t min_count_bit_for_found; | ||||||
|  | } SubGhzBlockConst; | ||||||
							
								
								
									
										17
									
								
								lib/subghz/blocks/decoder.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								lib/subghz/blocks/decoder.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | #include "decoder.h" | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzBlockDecoder" | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_blocks_add_bit(SubGhzBlockDecoder* decoder, uint8_t bit) { | ||||||
|  |     decoder->decode_data = decoder->decode_data << 1 | bit; | ||||||
|  |     decoder->decode_count_bit++; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_blocks_get_hash_data(SubGhzBlockDecoder* decoder, size_t len) { | ||||||
|  |     uint8_t hash = 0; | ||||||
|  |     uint8_t* p = (uint8_t*)&decoder->decode_data; | ||||||
|  |     for(size_t i = 0; i < len; i++) { | ||||||
|  |         hash ^= p[i]; | ||||||
|  |     } | ||||||
|  |     return hash; | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								lib/subghz/blocks/decoder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								lib/subghz/blocks/decoder.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stddef.h> | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzBlockDecoder SubGhzBlockDecoder; | ||||||
|  | 
 | ||||||
|  | struct SubGhzBlockDecoder { | ||||||
|  |     uint32_t parser_step; | ||||||
|  |     uint32_t te_last; | ||||||
|  |     uint64_t decode_data; | ||||||
|  |     uint8_t decode_count_bit; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_blocks_add_bit(SubGhzBlockDecoder* decoder, uint8_t bit); | ||||||
|  | uint8_t subghz_protocol_blocks_get_hash_data(SubGhzBlockDecoder* decoder, size_t len); | ||||||
							
								
								
									
										3
									
								
								lib/subghz/blocks/encoder.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								lib/subghz/blocks/encoder.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | #include "encoder.h" | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzBlockEncoder" | ||||||
							
								
								
									
										16
									
								
								lib/subghz/blocks/encoder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								lib/subghz/blocks/encoder.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stddef.h> | ||||||
|  | 
 | ||||||
|  | #include <lib/toolbox/level_duration.h> | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     bool is_runing; | ||||||
|  |     size_t repeat; | ||||||
|  |     size_t front; | ||||||
|  |     size_t size_upload; | ||||||
|  |     LevelDuration* upload; | ||||||
|  | 
 | ||||||
|  | } SubGhzProtocolBlockEncoder; | ||||||
							
								
								
									
										118
									
								
								lib/subghz/blocks/generic.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								lib/subghz/blocks/generic.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,118 @@ | |||||||
|  | #include "generic.h" | ||||||
|  | #include "../types.h" | ||||||
|  | #include <lib/toolbox/stream/stream.h> | ||||||
|  | #include <lib/flipper_format/flipper_format_i.h> | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzBlockGeneric" | ||||||
|  | 
 | ||||||
|  | bool subghz_block_generic_get_preset_name(FuriHalSubGhzPreset preset, string_t preset_str) { | ||||||
|  |     const char* preset_name; | ||||||
|  |     switch(preset) { | ||||||
|  |     case FuriHalSubGhzPresetOok270Async: | ||||||
|  |         preset_name = "FuriHalSubGhzPresetOok270Async"; | ||||||
|  |         break; | ||||||
|  |     case FuriHalSubGhzPresetOok650Async: | ||||||
|  |         preset_name = "FuriHalSubGhzPresetOok650Async"; | ||||||
|  |         break; | ||||||
|  |     case FuriHalSubGhzPreset2FSKDev238Async: | ||||||
|  |         preset_name = "FuriHalSubGhzPreset2FSKDev238Async"; | ||||||
|  |         break; | ||||||
|  |     case FuriHalSubGhzPreset2FSKDev476Async: | ||||||
|  |         preset_name = "FuriHalSubGhzPreset2FSKDev476Async"; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         FURI_LOG_E(TAG, "Unknown preset"); | ||||||
|  |         return false; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     string_set(preset_str, preset_name); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_block_generic_serialize( | ||||||
|  |     SubGhzBlockGeneric* instance, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     bool res = false; | ||||||
|  |     string_t temp_str; | ||||||
|  |     string_init(temp_str); | ||||||
|  |     do { | ||||||
|  |         stream_clean(flipper_format_get_raw_stream(flipper_format)); | ||||||
|  |         if(!flipper_format_write_header_cstr( | ||||||
|  |                flipper_format, SUBGHZ_KEY_FILE_TYPE, SUBGHZ_KEY_FILE_VERSION)) { | ||||||
|  |             FURI_LOG_E(TAG, "Unable to add header"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(!flipper_format_write_uint32(flipper_format, "Frequency", &frequency, 1)) { | ||||||
|  |             FURI_LOG_E(TAG, "Unable to add Frequency"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if(!subghz_block_generic_get_preset_name(preset, temp_str)) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if(!flipper_format_write_string_cstr(flipper_format, "Preset", string_get_cstr(temp_str))) { | ||||||
|  |             FURI_LOG_E(TAG, "Unable to add Preset"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if(!flipper_format_write_string_cstr(flipper_format, "Protocol", instance->protocol_name)) { | ||||||
|  |             FURI_LOG_E(TAG, "Unable to add Protocol"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         uint32_t temp = instance->data_count_bit; | ||||||
|  |         if(!flipper_format_write_uint32(flipper_format, "Bit", &temp, 1)) { | ||||||
|  |             FURI_LOG_E(TAG, "Unable to add Bit"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         uint8_t key_data[sizeof(uint64_t)] = {0}; | ||||||
|  |         for(size_t i = 0; i < sizeof(uint64_t); i++) { | ||||||
|  |             key_data[sizeof(uint64_t) - i - 1] = (instance->data >> i * 8) & 0xFF; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(!flipper_format_write_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { | ||||||
|  |             FURI_LOG_E(TAG, "Unable to add Key"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         res = true; | ||||||
|  |     } while(false); | ||||||
|  |     string_clear(temp_str); | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     bool res = false; | ||||||
|  |     string_t temp_str; | ||||||
|  |     string_init(temp_str); | ||||||
|  |     uint32_t temp_data = 0; | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         if(!flipper_format_rewind(flipper_format)) { | ||||||
|  |             FURI_LOG_E(TAG, "Rewind error"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if(!flipper_format_read_uint32(flipper_format, "Bit", (uint32_t*)&temp_data, 1)) { | ||||||
|  |             FURI_LOG_E(TAG, "Missing Bit"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         instance->data_count_bit = (uint8_t)temp_data; | ||||||
|  | 
 | ||||||
|  |         uint8_t key_data[sizeof(uint64_t)] = {0}; | ||||||
|  |         if(!flipper_format_read_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { | ||||||
|  |             FURI_LOG_E(TAG, "Missing Key"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         for(uint8_t i = 0; i < sizeof(uint64_t); i++) { | ||||||
|  |             instance->data = instance->data << 8 | key_data[i]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         res = true; | ||||||
|  |     } while(0); | ||||||
|  | 
 | ||||||
|  |     string_clear(temp_str); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								lib/subghz/blocks/generic.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								lib/subghz/blocks/generic.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stddef.h> | ||||||
|  | 
 | ||||||
|  | #include <lib/flipper_format/flipper_format.h> | ||||||
|  | #include "furi.h" | ||||||
|  | #include "furi_hal.h" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzBlockGeneric SubGhzBlockGeneric; | ||||||
|  | 
 | ||||||
|  | struct SubGhzBlockGeneric { | ||||||
|  |     const char* protocol_name; | ||||||
|  |     uint64_t data; | ||||||
|  |     uint32_t serial; | ||||||
|  |     uint8_t data_count_bit; | ||||||
|  |     uint8_t btn; | ||||||
|  |     uint16_t cnt; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | bool subghz_block_generic_get_preset_name(FuriHalSubGhzPreset preset, string_t preset_str); | ||||||
|  | 
 | ||||||
|  | bool subghz_block_generic_serialize( | ||||||
|  |     SubGhzBlockGeneric* instance, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | 
 | ||||||
|  | bool subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperFormat* flipper_format); | ||||||
							
								
								
									
										9
									
								
								lib/subghz/blocks/math.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/subghz/blocks/math.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | #include "math.h" | ||||||
|  | 
 | ||||||
|  | uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t count_bit) { | ||||||
|  |     uint64_t key_reverse = 0; | ||||||
|  |     for(uint8_t i = 0; i < count_bit; i++) { | ||||||
|  |         key_reverse = key_reverse << 1 | bit_read(key, i); | ||||||
|  |     } | ||||||
|  |     return key_reverse; | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								lib/subghz/blocks/math.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								lib/subghz/blocks/math.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stddef.h> | ||||||
|  | 
 | ||||||
|  | #define bit_read(value, bit) (((value) >> (bit)) & 0x01) | ||||||
|  | #define bit_set(value, bit) ((value) |= (1UL << (bit))) | ||||||
|  | #define bit_clear(value, bit) ((value) &= ~(1UL << (bit))) | ||||||
|  | #define bit_write(value, bit, bitvalue) (bitvalue ? bit_set(value, bit) : bit_clear(value, bit)) | ||||||
|  | #define DURATION_DIFF(x, y) ((x < y) ? (y - x) : (x - y)) | ||||||
|  | 
 | ||||||
|  | uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t count_bit); | ||||||
							
								
								
									
										67
									
								
								lib/subghz/environment.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								lib/subghz/environment.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | |||||||
|  | #include "environment.h" | ||||||
|  | 
 | ||||||
|  | struct SubGhzEnvironment { | ||||||
|  |     SubGhzKeystore* keystore; | ||||||
|  |     const char* came_atomo_rainbow_table_file_name; | ||||||
|  |     const char* nice_flor_s_rainbow_table_file_name; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | SubGhzEnvironment* subghz_environment_alloc() { | ||||||
|  |     SubGhzEnvironment* instance = malloc(sizeof(SubGhzEnvironment)); | ||||||
|  | 
 | ||||||
|  |     instance->keystore = subghz_keystore_alloc(); | ||||||
|  |     instance->came_atomo_rainbow_table_file_name = NULL; | ||||||
|  |     instance->nice_flor_s_rainbow_table_file_name = NULL; | ||||||
|  | 
 | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_environment_free(SubGhzEnvironment* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  | 
 | ||||||
|  |     subghz_keystore_free(instance->keystore); | ||||||
|  | 
 | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_environment_load_keystore(SubGhzEnvironment* instance, const char* filename) { | ||||||
|  |     furi_assert(instance); | ||||||
|  | 
 | ||||||
|  |     return subghz_keystore_load(instance->keystore, filename); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SubGhzKeystore* subghz_environment_get_keystore(SubGhzEnvironment* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  | 
 | ||||||
|  |     return instance->keystore; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_environment_set_came_atomo_rainbow_table_file_name( | ||||||
|  |     SubGhzEnvironment* instance, | ||||||
|  |     const char* filename) { | ||||||
|  |     furi_assert(instance); | ||||||
|  | 
 | ||||||
|  |     instance->came_atomo_rainbow_table_file_name = filename; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char* | ||||||
|  |     subghz_environment_get_came_atomo_rainbow_table_file_name(SubGhzEnvironment* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  | 
 | ||||||
|  |     return instance->came_atomo_rainbow_table_file_name; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_environment_set_nice_flor_s_rainbow_table_file_name( | ||||||
|  |     SubGhzEnvironment* instance, | ||||||
|  |     const char* filename) { | ||||||
|  |     furi_assert(instance); | ||||||
|  | 
 | ||||||
|  |     instance->nice_flor_s_rainbow_table_file_name = filename; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char* | ||||||
|  |     subghz_environment_get_nice_flor_s_rainbow_table_file_name(SubGhzEnvironment* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  | 
 | ||||||
|  |     return instance->nice_flor_s_rainbow_table_file_name; | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								lib/subghz/environment.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								lib/subghz/environment.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | #include "subghz_keystore.h" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzEnvironment SubGhzEnvironment; | ||||||
|  | 
 | ||||||
|  | SubGhzEnvironment* subghz_environment_alloc(); | ||||||
|  | 
 | ||||||
|  | void subghz_environment_free(SubGhzEnvironment* instance); | ||||||
|  | 
 | ||||||
|  | bool subghz_environment_load_keystore(SubGhzEnvironment* instance, const char* filename); | ||||||
|  | 
 | ||||||
|  | SubGhzKeystore* subghz_environment_get_keystore(SubGhzEnvironment* instance); | ||||||
|  | 
 | ||||||
|  | void subghz_environment_set_came_atomo_rainbow_table_file_name( | ||||||
|  |     SubGhzEnvironment* instance, | ||||||
|  |     const char* filename); | ||||||
|  | 
 | ||||||
|  | const char* subghz_environment_get_came_atomo_rainbow_table_file_name(SubGhzEnvironment* instance); | ||||||
|  | 
 | ||||||
|  | void subghz_environment_set_nice_flor_s_rainbow_table_file_name( | ||||||
|  |     SubGhzEnvironment* instance, | ||||||
|  |     const char* filename); | ||||||
|  | 
 | ||||||
|  | const char* | ||||||
|  |     subghz_environment_get_nice_flor_s_rainbow_table_file_name(SubGhzEnvironment* instance); | ||||||
							
								
								
									
										64
									
								
								lib/subghz/protocols/base.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								lib/subghz/protocols/base.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | |||||||
|  | #include "base.h" | ||||||
|  | #include "registry.h" | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_base_set_decoder_callback( | ||||||
|  |     SubGhzProtocolDecoderBase* decoder_base, | ||||||
|  |     SubGhzProtocolDecoderBaseRxCallback callback, | ||||||
|  |     void* context) { | ||||||
|  |     decoder_base->callback = callback; | ||||||
|  |     decoder_base->context = context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_base_get_string( | ||||||
|  |     SubGhzProtocolDecoderBase* decoder_base, | ||||||
|  |     string_t output) { | ||||||
|  |     bool status = false; | ||||||
|  | 
 | ||||||
|  |     if(decoder_base->protocol && decoder_base->protocol->decoder && | ||||||
|  |        decoder_base->protocol->decoder->get_string) { | ||||||
|  |         decoder_base->protocol->decoder->get_string(decoder_base, output); | ||||||
|  |         status = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return status; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_base_serialize( | ||||||
|  |     SubGhzProtocolDecoderBase* decoder_base, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     bool status = false; | ||||||
|  | 
 | ||||||
|  |     if(decoder_base->protocol && decoder_base->protocol->decoder && | ||||||
|  |        decoder_base->protocol->decoder->serialize) { | ||||||
|  |         status = decoder_base->protocol->decoder->serialize( | ||||||
|  |             decoder_base, flipper_format, frequency, preset); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return status; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_base_deserialize( | ||||||
|  |     SubGhzProtocolDecoderBase* decoder_base, | ||||||
|  |     FlipperFormat* flipper_format) { | ||||||
|  |     bool status = false; | ||||||
|  | 
 | ||||||
|  |     if(decoder_base->protocol && decoder_base->protocol->decoder && | ||||||
|  |        decoder_base->protocol->decoder->deserialize) { | ||||||
|  |         status = decoder_base->protocol->decoder->deserialize(decoder_base, flipper_format); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return status; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_base_get_hash_data(SubGhzProtocolDecoderBase* decoder_base) { | ||||||
|  |     uint8_t hash = 0; | ||||||
|  | 
 | ||||||
|  |     if(decoder_base->protocol && decoder_base->protocol->decoder && | ||||||
|  |        decoder_base->protocol->decoder->get_hash_data) { | ||||||
|  |         hash = decoder_base->protocol->decoder->get_hash_data(decoder_base); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return hash; | ||||||
|  | } | ||||||
							
								
								
									
										51
									
								
								lib/subghz/protocols/base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								lib/subghz/protocols/base.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "../types.h" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzProtocolDecoderBase SubGhzProtocolDecoderBase; | ||||||
|  | 
 | ||||||
|  | typedef void ( | ||||||
|  |     *SubGhzProtocolDecoderBaseRxCallback)(SubGhzProtocolDecoderBase* instance, void* context); | ||||||
|  | 
 | ||||||
|  | typedef void ( | ||||||
|  |     *SubGhzProtocolDecoderBaseSerialize)(SubGhzProtocolDecoderBase* decoder_base, string_t output); | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolDecoderBase { | ||||||
|  |     // Decoder general section
 | ||||||
|  |     const SubGhzProtocol* protocol; | ||||||
|  | 
 | ||||||
|  |     // Callback section
 | ||||||
|  |     SubGhzProtocolDecoderBaseRxCallback callback; | ||||||
|  |     void* context; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_base_set_decoder_callback( | ||||||
|  |     SubGhzProtocolDecoderBase* decoder_base, | ||||||
|  |     SubGhzProtocolDecoderBaseRxCallback callback, | ||||||
|  |     void* context); | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_base_get_string( | ||||||
|  |     SubGhzProtocolDecoderBase* decoder_base, | ||||||
|  |     string_t output); | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_base_serialize( | ||||||
|  |     SubGhzProtocolDecoderBase* decoder_base, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_base_deserialize( | ||||||
|  |     SubGhzProtocolDecoderBase* decoder_base, | ||||||
|  |     FlipperFormat* flipper_format); | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_base_get_hash_data(SubGhzProtocolDecoderBase* decoder_base); | ||||||
|  | 
 | ||||||
|  | // Encoder Base
 | ||||||
|  | typedef struct SubGhzProtocolEncoderBase SubGhzProtocolEncoderBase; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolEncoderBase { | ||||||
|  |     // Decoder general section
 | ||||||
|  |     const SubGhzProtocol* protocol; | ||||||
|  | 
 | ||||||
|  |     // Callback section
 | ||||||
|  | }; | ||||||
							
								
								
									
										313
									
								
								lib/subghz/protocols/came.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										313
									
								
								lib/subghz/protocols/came.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,313 @@ | |||||||
|  | #include "came.h" | ||||||
|  | 
 | ||||||
|  | #include "../blocks/const.h" | ||||||
|  | #include "../blocks/decoder.h" | ||||||
|  | #include "../blocks/encoder.h" | ||||||
|  | #include "../blocks/generic.h" | ||||||
|  | #include "../blocks/math.h" | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Help | ||||||
|  |  * https://phreakerclub.com/447
 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzProtocolCAME" | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst subghz_protocol_came_const = { | ||||||
|  |     .te_short = 320, | ||||||
|  |     .te_long = 640, | ||||||
|  |     .te_delta = 150, | ||||||
|  |     .min_count_bit_for_found = 12, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolDecoderCame { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolEncoderCame { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     CameDecoderStepReset = 0, | ||||||
|  |     CameDecoderStepFoundStartBit, | ||||||
|  |     CameDecoderStepSaveDuration, | ||||||
|  |     CameDecoderStepCheckDuration, | ||||||
|  | } CameDecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder subghz_protocol_came_decoder = { | ||||||
|  |     .alloc = subghz_protocol_decoder_came_alloc, | ||||||
|  |     .free = subghz_protocol_decoder_came_free, | ||||||
|  | 
 | ||||||
|  |     .feed = subghz_protocol_decoder_came_feed, | ||||||
|  |     .reset = subghz_protocol_decoder_came_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = subghz_protocol_decoder_came_get_hash_data, | ||||||
|  |     .serialize = subghz_protocol_decoder_came_serialize, | ||||||
|  |     .deserialize = subghz_protocol_decoder_came_deserialize, | ||||||
|  |     .get_string = subghz_protocol_decoder_came_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder subghz_protocol_came_encoder = { | ||||||
|  |     .alloc = subghz_protocol_encoder_came_alloc, | ||||||
|  |     .free = subghz_protocol_encoder_came_free, | ||||||
|  | 
 | ||||||
|  |     .deserialize = subghz_protocol_encoder_came_deserialize, | ||||||
|  |     .stop = subghz_protocol_encoder_came_stop, | ||||||
|  |     .yield = subghz_protocol_encoder_came_yield, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol subghz_protocol_came = { | ||||||
|  |     .name = SUBGHZ_PROTOCOL_CAME_NAME, | ||||||
|  |     .type = SubGhzProtocolTypeStatic, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_AM | | ||||||
|  |             SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | | ||||||
|  |             SubGhzProtocolFlag_Send, | ||||||
|  | 
 | ||||||
|  |     .decoder = &subghz_protocol_came_decoder, | ||||||
|  |     .encoder = &subghz_protocol_came_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_came_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolEncoderCame* instance = malloc(sizeof(SubGhzProtocolEncoderCame)); | ||||||
|  | 
 | ||||||
|  |     instance->base.protocol = &subghz_protocol_came; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  | 
 | ||||||
|  |     instance->encoder.repeat = 10; | ||||||
|  |     instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop)
 | ||||||
|  |     instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_came_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderCame* instance = context; | ||||||
|  |     free(instance->encoder.upload); | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool subghz_protocol_encoder_came_get_upload(SubGhzProtocolEncoderCame* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     size_t index = 0; | ||||||
|  |     size_t size_upload = (instance->generic.data_count_bit * 2) + 2; | ||||||
|  |     if(size_upload > instance->encoder.size_upload) { | ||||||
|  |         FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); | ||||||
|  |         return false; | ||||||
|  |     } else { | ||||||
|  |         instance->encoder.size_upload = size_upload; | ||||||
|  |     } | ||||||
|  |     //Send header
 | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(false, (uint32_t)subghz_protocol_came_const.te_short * 36); | ||||||
|  |     //Send start bit
 | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_short); | ||||||
|  |     //Send key data
 | ||||||
|  |     for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { | ||||||
|  |         if(bit_read(instance->generic.data, i - 1)) { | ||||||
|  |             //send bit 1
 | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(false, (uint32_t)subghz_protocol_came_const.te_long); | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_short); | ||||||
|  |         } else { | ||||||
|  |             //send bit 0
 | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(false, (uint32_t)subghz_protocol_came_const.te_short); | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_long); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderCame* instance = context; | ||||||
|  |     bool res = false; | ||||||
|  |     do { | ||||||
|  |         if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { | ||||||
|  |             FURI_LOG_E(TAG, "Deserialize error"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         //optional parameter parameter
 | ||||||
|  |         flipper_format_read_uint32( | ||||||
|  |             flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); | ||||||
|  | 
 | ||||||
|  |         subghz_protocol_encoder_came_get_upload(instance); | ||||||
|  |         instance->encoder.is_runing = true; | ||||||
|  | 
 | ||||||
|  |         res = true; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_came_stop(void* context) { | ||||||
|  |     SubGhzProtocolEncoderCame* instance = context; | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | LevelDuration subghz_protocol_encoder_came_yield(void* context) { | ||||||
|  |     SubGhzProtocolEncoderCame* instance = context; | ||||||
|  | 
 | ||||||
|  |     if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { | ||||||
|  |         instance->encoder.is_runing = false; | ||||||
|  |         return level_duration_reset(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LevelDuration ret = instance->encoder.upload[instance->encoder.front]; | ||||||
|  | 
 | ||||||
|  |     if(++instance->encoder.front == instance->encoder.size_upload) { | ||||||
|  |         instance->encoder.repeat--; | ||||||
|  |         instance->encoder.front = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_came_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolDecoderCame* instance = malloc(sizeof(SubGhzProtocolDecoderCame)); | ||||||
|  |     instance->base.protocol = &subghz_protocol_came; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_came_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCame* instance = context; | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_came_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCame* instance = context; | ||||||
|  |     instance->decoder.parser_step = CameDecoderStepReset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_came_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCame* instance = context; | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case CameDecoderStepReset: | ||||||
|  |         if((!level) && (DURATION_DIFF(duration, subghz_protocol_came_const.te_short * 51) < | ||||||
|  |                         subghz_protocol_came_const.te_delta * 51)) { //Need protocol 36 te_short
 | ||||||
|  |             //Found header CAME
 | ||||||
|  |             instance->decoder.parser_step = CameDecoderStepFoundStartBit; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CameDecoderStepFoundStartBit: | ||||||
|  |         if(!level) { | ||||||
|  |             break; | ||||||
|  |         } else if( | ||||||
|  |             DURATION_DIFF(duration, subghz_protocol_came_const.te_short) < | ||||||
|  |             subghz_protocol_came_const.te_delta) { | ||||||
|  |             //Found start bit CAME
 | ||||||
|  |             instance->decoder.parser_step = CameDecoderStepSaveDuration; | ||||||
|  |             instance->decoder.decode_data = 0; | ||||||
|  |             instance->decoder.decode_count_bit = 0; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = CameDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CameDecoderStepSaveDuration: | ||||||
|  |         if(!level) { //save interval
 | ||||||
|  |             if(duration >= (subghz_protocol_came_const.te_short * 4)) { | ||||||
|  |                 instance->decoder.parser_step = CameDecoderStepFoundStartBit; | ||||||
|  |                 if(instance->decoder.decode_count_bit >= | ||||||
|  |                    subghz_protocol_came_const.min_count_bit_for_found) { | ||||||
|  |                     instance->generic.serial = 0x0; | ||||||
|  |                     instance->generic.btn = 0x0; | ||||||
|  | 
 | ||||||
|  |                     instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                     instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  | 
 | ||||||
|  |                     if(instance->base.callback) | ||||||
|  |                         instance->base.callback(&instance->base, instance->base.context); | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             instance->decoder.te_last = duration; | ||||||
|  |             instance->decoder.parser_step = CameDecoderStepCheckDuration; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = CameDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CameDecoderStepCheckDuration: | ||||||
|  |         if(level) { | ||||||
|  |             if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_came_const.te_short) < | ||||||
|  |                 subghz_protocol_came_const.te_delta) && | ||||||
|  |                (DURATION_DIFF(duration, subghz_protocol_came_const.te_long) < | ||||||
|  |                 subghz_protocol_came_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                 instance->decoder.parser_step = CameDecoderStepSaveDuration; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_came_const.te_long) < | ||||||
|  |                  subghz_protocol_came_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, subghz_protocol_came_const.te_short) < | ||||||
|  |                  subghz_protocol_came_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                 instance->decoder.parser_step = CameDecoderStepSaveDuration; | ||||||
|  |             } else | ||||||
|  |                 instance->decoder.parser_step = CameDecoderStepReset; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = CameDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_came_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCame* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_came_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCame* instance = context; | ||||||
|  |     return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_came_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCame* instance = context; | ||||||
|  |     return subghz_block_generic_deserialize(&instance->generic, flipper_format); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_came_get_string(void* context, string_t output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCame* instance = context; | ||||||
|  | 
 | ||||||
|  |     uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key( | ||||||
|  |         instance->generic.data, instance->generic.data_count_bit); | ||||||
|  | 
 | ||||||
|  |     uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %dbit\r\n" | ||||||
|  |         "Key:0x%08lX\r\n" | ||||||
|  |         "Yek:0x%08lX\r\n", | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         code_found_lo, | ||||||
|  |         code_found_reverse_lo); | ||||||
|  | } | ||||||
							
								
								
									
										63
									
								
								lib/subghz/protocols/came.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								lib/subghz/protocols/came.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "base.h" | ||||||
|  | 
 | ||||||
|  | #define SUBGHZ_PROTOCOL_CAME_NAME "CAME" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzProtocolDecoderCame SubGhzProtocolDecoderCame; | ||||||
|  | typedef struct SubGhzProtocolEncoderCame SubGhzProtocolEncoderCame; | ||||||
|  | 
 | ||||||
|  | extern const SubGhzProtocolDecoder subghz_protocol_came_decoder; | ||||||
|  | extern const SubGhzProtocolEncoder subghz_protocol_came_encoder; | ||||||
|  | extern const SubGhzProtocol subghz_protocol_came; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_came_alloc(SubGhzEnvironment* environment); | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_came_free(void* context); | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_came_stop(void* context); | ||||||
|  | 
 | ||||||
|  | LevelDuration subghz_protocol_encoder_came_yield(void* context); | ||||||
|  | 
 | ||||||
|  | /** Allocate SubGhzProtocolCame
 | ||||||
|  |  *  | ||||||
|  |  * @return SubGhzProtocolCame*  | ||||||
|  |  */ | ||||||
|  | void* subghz_protocol_decoder_came_alloc(SubGhzEnvironment* environment); | ||||||
|  | 
 | ||||||
|  | /** Free SubGhzProtocolCame
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  | ||||||
|  |  */ | ||||||
|  | void subghz_protocol_decoder_came_free(void* context); | ||||||
|  | 
 | ||||||
|  | /** Reset internal state
 | ||||||
|  |  * @param instance - SubGhzProtocolCame instance | ||||||
|  |  */ | ||||||
|  | void subghz_protocol_decoder_came_reset(void* context); | ||||||
|  | 
 | ||||||
|  | /** Parse accepted duration
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolCame instance | ||||||
|  |  * @param data - LevelDuration level_duration | ||||||
|  |  */ | ||||||
|  | void subghz_protocol_decoder_came_feed(void* context, bool level, uint32_t duration); | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_came_get_hash_data(void* context); | ||||||
|  | 
 | ||||||
|  | /** Outputting information from the parser
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolCame* instance | ||||||
|  |  * @param output   - output string | ||||||
|  |  */ | ||||||
|  | bool subghz_protocol_decoder_came_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_came_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_came_get_string(void* context, string_t output); | ||||||
							
								
								
									
										338
									
								
								lib/subghz/protocols/came_atomo.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										338
									
								
								lib/subghz/protocols/came_atomo.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,338 @@ | |||||||
|  | #include "came_atomo.h" | ||||||
|  | #include <lib/toolbox/manchester_decoder.h> | ||||||
|  | #include "../blocks/const.h" | ||||||
|  | #include "../blocks/decoder.h" | ||||||
|  | #include "../blocks/encoder.h" | ||||||
|  | #include "../blocks/generic.h" | ||||||
|  | #include "../blocks/math.h" | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzProtocoCameAtomo" | ||||||
|  | 
 | ||||||
|  | #define SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE 0xFFFFFFFFFFFFFFFF | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst subghz_protocol_came_atomo_const = { | ||||||
|  |     .te_short = 600, | ||||||
|  |     .te_long = 1200, | ||||||
|  |     .te_delta = 250, | ||||||
|  |     .min_count_bit_for_found = 62, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolDecoderCameAtomo { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | 
 | ||||||
|  |     ManchesterState manchester_saved_state; | ||||||
|  |     const char* came_atomo_rainbow_table_file_name; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolEncoderCameAtomo { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     CameAtomoDecoderStepReset = 0, | ||||||
|  |     CameAtomoDecoderStepDecoderData, | ||||||
|  | } CameAtomoDecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder subghz_protocol_came_atomo_decoder = { | ||||||
|  |     .alloc = subghz_protocol_decoder_came_atomo_alloc, | ||||||
|  |     .free = subghz_protocol_decoder_came_atomo_free, | ||||||
|  | 
 | ||||||
|  |     .feed = subghz_protocol_decoder_came_atomo_feed, | ||||||
|  |     .reset = subghz_protocol_decoder_came_atomo_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = subghz_protocol_decoder_came_atomo_get_hash_data, | ||||||
|  |     .serialize = subghz_protocol_decoder_came_atomo_serialize, | ||||||
|  |     .deserialize = subghz_protocol_decoder_came_atomo_deserialize, | ||||||
|  |     .get_string = subghz_protocol_decoder_came_atomo_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder subghz_protocol_came_atomo_encoder = { | ||||||
|  |     .alloc = NULL, | ||||||
|  |     .free = NULL, | ||||||
|  | 
 | ||||||
|  |     .deserialize = NULL, | ||||||
|  |     .stop = NULL, | ||||||
|  |     .yield = NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol subghz_protocol_came_atomo = { | ||||||
|  |     .name = SUBGHZ_PROTOCOL_CAME_ATOMO_NAME, | ||||||
|  |     .type = SubGhzProtocolTypeDynamic, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, | ||||||
|  | 
 | ||||||
|  |     .decoder = &subghz_protocol_came_atomo_decoder, | ||||||
|  |     .encoder = &subghz_protocol_came_atomo_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_came_atomo_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolDecoderCameAtomo* instance = malloc(sizeof(SubGhzProtocolDecoderCameAtomo)); | ||||||
|  |     instance->base.protocol = &subghz_protocol_came_atomo; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  |     instance->came_atomo_rainbow_table_file_name = | ||||||
|  |         subghz_environment_get_came_atomo_rainbow_table_file_name(environment); | ||||||
|  |     if(instance->came_atomo_rainbow_table_file_name) { | ||||||
|  |         FURI_LOG_I( | ||||||
|  |             TAG, "Loading rainbow table from %s", instance->came_atomo_rainbow_table_file_name); | ||||||
|  |     } | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_came_atomo_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCameAtomo* instance = context; | ||||||
|  |     instance->came_atomo_rainbow_table_file_name = NULL; | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_came_atomo_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCameAtomo* instance = context; | ||||||
|  |     instance->decoder.parser_step = CameAtomoDecoderStepReset; | ||||||
|  |     manchester_advance( | ||||||
|  |         instance->manchester_saved_state, | ||||||
|  |         ManchesterEventReset, | ||||||
|  |         &instance->manchester_saved_state, | ||||||
|  |         NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_came_atomo_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCameAtomo* instance = context; | ||||||
|  | 
 | ||||||
|  |     ManchesterEvent event = ManchesterEventReset; | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case CameAtomoDecoderStepReset: | ||||||
|  |         if((!level) && (DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long * 65) < | ||||||
|  |                         subghz_protocol_came_atomo_const.te_delta * 20)) { | ||||||
|  |             //Found header CAME
 | ||||||
|  |             instance->decoder.parser_step = CameAtomoDecoderStepDecoderData; | ||||||
|  |             instance->decoder.decode_data = 0; | ||||||
|  |             instance->decoder.decode_count_bit = 1; | ||||||
|  |             manchester_advance( | ||||||
|  |                 instance->manchester_saved_state, | ||||||
|  |                 ManchesterEventReset, | ||||||
|  |                 &instance->manchester_saved_state, | ||||||
|  |                 NULL); | ||||||
|  |             manchester_advance( | ||||||
|  |                 instance->manchester_saved_state, | ||||||
|  |                 ManchesterEventShortLow, | ||||||
|  |                 &instance->manchester_saved_state, | ||||||
|  |                 NULL); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CameAtomoDecoderStepDecoderData: | ||||||
|  |         if(!level) { | ||||||
|  |             if(DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_short) < | ||||||
|  |                subghz_protocol_came_atomo_const.te_delta) { | ||||||
|  |                 event = ManchesterEventShortLow; | ||||||
|  |             } else if( | ||||||
|  |                 DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long) < | ||||||
|  |                 subghz_protocol_came_atomo_const.te_delta) { | ||||||
|  |                 event = ManchesterEventLongLow; | ||||||
|  |             } else if( | ||||||
|  |                 duration >= (subghz_protocol_came_atomo_const.te_long * 2 + | ||||||
|  |                              subghz_protocol_came_atomo_const.te_delta)) { | ||||||
|  |                 if(instance->decoder.decode_count_bit == | ||||||
|  |                    subghz_protocol_came_atomo_const.min_count_bit_for_found) { | ||||||
|  |                     instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                     instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  |                     if(instance->base.callback) | ||||||
|  |                         instance->base.callback(&instance->base, instance->base.context); | ||||||
|  |                 } | ||||||
|  |                 instance->decoder.decode_data = 0; | ||||||
|  |                 instance->decoder.decode_count_bit = 1; | ||||||
|  |                 manchester_advance( | ||||||
|  |                     instance->manchester_saved_state, | ||||||
|  |                     ManchesterEventReset, | ||||||
|  |                     &instance->manchester_saved_state, | ||||||
|  |                     NULL); | ||||||
|  |                 manchester_advance( | ||||||
|  |                     instance->manchester_saved_state, | ||||||
|  |                     ManchesterEventShortLow, | ||||||
|  |                     &instance->manchester_saved_state, | ||||||
|  |                     NULL); | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = CameAtomoDecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             if(DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_short) < | ||||||
|  |                subghz_protocol_came_atomo_const.te_delta) { | ||||||
|  |                 event = ManchesterEventShortHigh; | ||||||
|  |             } else if( | ||||||
|  |                 DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long) < | ||||||
|  |                 subghz_protocol_came_atomo_const.te_delta) { | ||||||
|  |                 event = ManchesterEventLongHigh; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = CameAtomoDecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if(event != ManchesterEventReset) { | ||||||
|  |             bool data; | ||||||
|  |             bool data_ok = manchester_advance( | ||||||
|  |                 instance->manchester_saved_state, event, &instance->manchester_saved_state, &data); | ||||||
|  | 
 | ||||||
|  |             if(data_ok) { | ||||||
|  |                 instance->decoder.decode_data = (instance->decoder.decode_data << 1) | !data; | ||||||
|  |                 instance->decoder.decode_count_bit++; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** Read bytes from rainbow table
 | ||||||
|  |  * | ||||||
|  |  * @param file_name - file name rainbow table | ||||||
|  |  * @param number_atomo_magic_xor | ||||||
|  |  * @return atomo_magic_xor | ||||||
|  |  */ | ||||||
|  | static uint64_t subghz_protocol_came_atomo_get_magic_xor_in_file( | ||||||
|  |     const char* file_name, | ||||||
|  |     uint8_t number_atomo_magic_xor) { | ||||||
|  |     if(!strcmp(file_name, "")) return SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE; | ||||||
|  | 
 | ||||||
|  |     uint8_t buffer[sizeof(uint64_t)] = {0}; | ||||||
|  |     uint32_t address = number_atomo_magic_xor * sizeof(uint64_t); | ||||||
|  |     uint64_t atomo_magic_xor = 0; | ||||||
|  | 
 | ||||||
|  |     if(subghz_keystore_raw_get_data(file_name, address, buffer, sizeof(uint64_t))) { | ||||||
|  |         for(size_t i = 0; i < sizeof(uint64_t); i++) { | ||||||
|  |             atomo_magic_xor = (atomo_magic_xor << 8) | buffer[i]; | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         atomo_magic_xor = SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE; | ||||||
|  |     } | ||||||
|  |     return atomo_magic_xor; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** Analysis of received data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance SubGhzBlockGeneric instance | ||||||
|  |  */ | ||||||
|  | static void subghz_protocol_came_atomo_remote_controller( | ||||||
|  |     SubGhzBlockGeneric* instance, | ||||||
|  |     const char* file_name) { | ||||||
|  |     /* 
 | ||||||
|  |     * 0x1fafef3ed0f7d9ef | ||||||
|  |     * 0x185fcc1531ee86e7 | ||||||
|  |     * 0x184fa96912c567ff | ||||||
|  |     * 0x187f8a42f3dc38f7 | ||||||
|  |     * 0x186f63915492a5cd | ||||||
|  |     * 0x181f40bab58bfac5 | ||||||
|  |     * 0x180f25c696a01bdd | ||||||
|  |     * 0x183f06ed77b944d5 | ||||||
|  |     * 0x182ef661d83d21a9 | ||||||
|  |     * 0x18ded54a39247ea1 | ||||||
|  |     * 0x18ceb0361a0f9fb9 | ||||||
|  |     * 0x18fe931dfb16c0b1 | ||||||
|  |     * 0x18ee7ace5c585d8b | ||||||
|  |     * ........  | ||||||
|  |     * transmission consists of 99 parcels with increasing counter while holding down the button | ||||||
|  |     * with each new press, the counter in the encrypted part increases | ||||||
|  |     *  | ||||||
|  |     * 0x1FAFF13ED0F7D9EF | ||||||
|  |     * 0x1FAFF11ED0F7D9EF | ||||||
|  |     * 0x1FAFF10ED0F7D9EF | ||||||
|  |     * 0x1FAFF0FED0F7D9EF | ||||||
|  |     * 0x1FAFF0EED0F7D9EF | ||||||
|  |     * 0x1FAFF0DED0F7D9EF | ||||||
|  |     * 0x1FAFF0CED0F7D9EF | ||||||
|  |     * 0x1FAFF0BED0F7D9EF | ||||||
|  |     * 0x1FAFF0AED0F7D9EF  | ||||||
|  |     *  | ||||||
|  |     *                   where     0x1FAF - parcel counter, 0хF0A - button press counter, | ||||||
|  |     *                           0xED0F7D9E - serial number, 0хF -  key | ||||||
|  |     * 0x1FAF parcel counter - 1 in the parcel queue ^ 0x185F =  0x07F0 | ||||||
|  |     * 0x185f ^ 0x185F = 0x0000 | ||||||
|  |     * 0x184f ^ 0x185F = 0x0010 | ||||||
|  |     * 0x187f ^ 0x185F = 0x0020 | ||||||
|  |     * ..... | ||||||
|  |     * 0x182e ^ 0x185F = 0x0071  | ||||||
|  |     * 0x18de ^ 0x185F = 0x0081 | ||||||
|  |     * ..... | ||||||
|  |     * 0x1e43 ^ 0x185F = 0x061C | ||||||
|  |     *                           where the last nibble is incremented every 8 samples | ||||||
|  |     *  | ||||||
|  |     * Decode | ||||||
|  |     *  | ||||||
|  |     * 0x1cf6931dfb16c0b1 => 0x1cf6 | ||||||
|  |     * 0x1cf6 ^ 0x185F = 0x04A9 | ||||||
|  |     * 0x04A9 => 0x04A = 74 (dec) | ||||||
|  |     * 74+1 % 32(atomo_magic_xor) = 11 | ||||||
|  |     * GET atomo_magic_xor[11] = 0xXXXXXXXXXXXXXXXX | ||||||
|  |     * 0x931dfb16c0b1 ^ 0xXXXXXXXXXXXXXXXX =  0xEF3ED0F7D9EF | ||||||
|  |     * 0xEF3 ED0F7D9E F  => 0xEF3 - CNT, 0xED0F7D9E - SN, 0xF - key | ||||||
|  |     *  | ||||||
|  |     * */ | ||||||
|  | 
 | ||||||
|  |     uint16_t parcel_counter = instance->data >> 48; | ||||||
|  |     parcel_counter = parcel_counter ^ 0x185F; | ||||||
|  |     parcel_counter >>= 4; | ||||||
|  |     uint8_t ind = (parcel_counter + 1) % 32; | ||||||
|  |     uint64_t temp_data = instance->data & 0x0000FFFFFFFFFFFF; | ||||||
|  |     uint64_t atomo_magic_xor = subghz_protocol_came_atomo_get_magic_xor_in_file(file_name, ind); | ||||||
|  | 
 | ||||||
|  |     if(atomo_magic_xor != SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE) { | ||||||
|  |         temp_data = temp_data ^ atomo_magic_xor; | ||||||
|  |         instance->cnt = temp_data >> 36; | ||||||
|  |         instance->serial = (temp_data >> 4) & 0x000FFFFFFFF; | ||||||
|  |         instance->btn = temp_data & 0xF; | ||||||
|  |     } else { | ||||||
|  |         instance->cnt = 0; | ||||||
|  |         instance->serial = 0; | ||||||
|  |         instance->btn = 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_came_atomo_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCameAtomo* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_came_atomo_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCameAtomo* instance = context; | ||||||
|  |     return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_came_atomo_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCameAtomo* instance = context; | ||||||
|  |     return subghz_block_generic_deserialize(&instance->generic, flipper_format); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_came_atomo_get_string(void* context, string_t output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCameAtomo* instance = context; | ||||||
|  |     subghz_protocol_came_atomo_remote_controller( | ||||||
|  |         &instance->generic, instance->came_atomo_rainbow_table_file_name); | ||||||
|  |     uint32_t code_found_hi = instance->generic.data >> 32; | ||||||
|  |     uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %db\r\n" | ||||||
|  |         "Key:0x%lX%08lX\r\n" | ||||||
|  |         "Sn:0x%08lX  Btn:0x%01X\r\n" | ||||||
|  |         "Cnt:0x%03X\r\n", | ||||||
|  | 
 | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         code_found_hi, | ||||||
|  |         code_found_lo, | ||||||
|  |         instance->generic.serial, | ||||||
|  |         instance->generic.btn, | ||||||
|  |         instance->generic.cnt); | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								lib/subghz/protocols/came_atomo.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								lib/subghz/protocols/came_atomo.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "base.h" | ||||||
|  | 
 | ||||||
|  | #define SUBGHZ_PROTOCOL_CAME_ATOMO_NAME "CAME Atomo" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzProtocolDecoderCameAtomo SubGhzProtocolDecoderCameAtomo; | ||||||
|  | typedef struct SubGhzProtocolEncoderCameAtomo SubGhzProtocolEncoderCameAtomo; | ||||||
|  | 
 | ||||||
|  | extern const SubGhzProtocolDecoder subghz_protocol_came_atomo_decoder; | ||||||
|  | extern const SubGhzProtocolEncoder subghz_protocol_came_atomo_encoder; | ||||||
|  | extern const SubGhzProtocol subghz_protocol_came_atomo; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_came_atomo_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_decoder_came_atomo_free(void* context); | ||||||
|  | void subghz_protocol_decoder_came_atomo_reset(void* context); | ||||||
|  | void subghz_protocol_decoder_came_atomo_feed(void* context, bool level, uint32_t duration); | ||||||
|  | uint8_t subghz_protocol_decoder_came_atomo_get_hash_data(void* context); | ||||||
|  | bool subghz_protocol_decoder_came_atomo_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | bool subghz_protocol_decoder_came_atomo_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_decoder_came_atomo_get_string(void* context, string_t output); | ||||||
							
								
								
									
										445
									
								
								lib/subghz/protocols/came_twee.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										445
									
								
								lib/subghz/protocols/came_twee.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,445 @@ | |||||||
|  | #include "came_twee.h" | ||||||
|  | #include <lib/toolbox/manchester_decoder.h> | ||||||
|  | #include <lib/toolbox/manchester_encoder.h> | ||||||
|  | #include "../blocks/const.h" | ||||||
|  | #include "../blocks/decoder.h" | ||||||
|  | #include "../blocks/encoder.h" | ||||||
|  | #include "../blocks/generic.h" | ||||||
|  | #include "../blocks/math.h" | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Help | ||||||
|  |  * https://phreakerclub.com/forum/showthread.php?t=635&highlight=came+twin
 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzProtocolCAME_Twee" | ||||||
|  | 
 | ||||||
|  | #define DIP_PATTERN "%c%c%c%c%c%c%c%c%c%c" | ||||||
|  | #define CNT_TO_DIP(dip)                                                                     \ | ||||||
|  |     (dip & 0x0200 ? '1' : '0'), (dip & 0x0100 ? '1' : '0'), (dip & 0x0080 ? '1' : '0'),     \ | ||||||
|  |         (dip & 0x0040 ? '1' : '0'), (dip & 0x0020 ? '1' : '0'), (dip & 0x0010 ? '1' : '0'), \ | ||||||
|  |         (dip & 0x0008 ? '1' : '0'), (dip & 0x0004 ? '1' : '0'), (dip & 0x0002 ? '1' : '0'), \ | ||||||
|  |         (dip & 0x0001 ? '1' : '0') | ||||||
|  | 
 | ||||||
|  | static const uint32_t came_twee_magic_numbers_xor[15] = { | ||||||
|  |     0x0E0E0E00, | ||||||
|  |     0x1D1D1D11, | ||||||
|  |     0x2C2C2C22, | ||||||
|  |     0x3B3B3B33, | ||||||
|  |     0x4A4A4A44, | ||||||
|  |     0x59595955, | ||||||
|  |     0x68686866, | ||||||
|  |     0x77777777, | ||||||
|  |     0x86868688, | ||||||
|  |     0x95959599, | ||||||
|  |     0xA4A4A4AA, | ||||||
|  |     0xB3B3B3BB, | ||||||
|  |     0xC2C2C2CC, | ||||||
|  |     0xD1D1D1DD, | ||||||
|  |     0xE0E0E0EE, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst subghz_protocol_came_twee_const = { | ||||||
|  |     .te_short = 500, | ||||||
|  |     .te_long = 1000, | ||||||
|  |     .te_delta = 250, | ||||||
|  |     .min_count_bit_for_found = 54, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolDecoderCameTwee { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  |     ManchesterState manchester_saved_state; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolEncoderCameTwee { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     CameTweeDecoderStepReset = 0, | ||||||
|  |     CameTweeDecoderStepDecoderData, | ||||||
|  | } CameTweeDecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder subghz_protocol_came_twee_decoder = { | ||||||
|  |     .alloc = subghz_protocol_decoder_came_twee_alloc, | ||||||
|  |     .free = subghz_protocol_decoder_came_twee_free, | ||||||
|  | 
 | ||||||
|  |     .feed = subghz_protocol_decoder_came_twee_feed, | ||||||
|  |     .reset = subghz_protocol_decoder_came_twee_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = subghz_protocol_decoder_came_twee_get_hash_data, | ||||||
|  |     .serialize = subghz_protocol_decoder_came_twee_serialize, | ||||||
|  |     .deserialize = subghz_protocol_decoder_came_twee_deserialize, | ||||||
|  |     .get_string = subghz_protocol_decoder_came_twee_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder subghz_protocol_came_twee_encoder = { | ||||||
|  |     .alloc = subghz_protocol_encoder_came_twee_alloc, | ||||||
|  |     .free = subghz_protocol_encoder_came_twee_free, | ||||||
|  | 
 | ||||||
|  |     .deserialize = subghz_protocol_encoder_came_twee_deserialize, | ||||||
|  |     .stop = subghz_protocol_encoder_came_twee_stop, | ||||||
|  |     .yield = subghz_protocol_encoder_came_twee_yield, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol subghz_protocol_came_twee = { | ||||||
|  |     .name = SUBGHZ_PROTOCOL_CAME_TWEE_NAME, | ||||||
|  |     .type = SubGhzProtocolTypeStatic, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | | ||||||
|  |             SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, | ||||||
|  | 
 | ||||||
|  |     .decoder = &subghz_protocol_came_twee_decoder, | ||||||
|  |     .encoder = &subghz_protocol_came_twee_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_came_twee_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolEncoderCameTwee* instance = malloc(sizeof(SubGhzProtocolEncoderCameTwee)); | ||||||
|  | 
 | ||||||
|  |     instance->base.protocol = &subghz_protocol_came_twee; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  | 
 | ||||||
|  |     instance->encoder.repeat = 10; | ||||||
|  |     instance->encoder.size_upload = 1536; //max upload 92*14 = 1288 !!!!
 | ||||||
|  |     instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_came_twee_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderCameTwee* instance = context; | ||||||
|  |     free(instance->encoder.upload); | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static LevelDuration | ||||||
|  |     subghz_protocol_encoder_came_twee_add_duration_to_upload(ManchesterEncoderResult result) { | ||||||
|  |     LevelDuration data = {.duration = 0, .level = 0}; | ||||||
|  |     switch(result) { | ||||||
|  |     case ManchesterEncoderResultShortLow: | ||||||
|  |         data.duration = subghz_protocol_came_twee_const.te_short; | ||||||
|  |         data.level = false; | ||||||
|  |         break; | ||||||
|  |     case ManchesterEncoderResultLongLow: | ||||||
|  |         data.duration = subghz_protocol_came_twee_const.te_long; | ||||||
|  |         data.level = false; | ||||||
|  |         break; | ||||||
|  |     case ManchesterEncoderResultLongHigh: | ||||||
|  |         data.duration = subghz_protocol_came_twee_const.te_long; | ||||||
|  |         data.level = true; | ||||||
|  |         break; | ||||||
|  |     case ManchesterEncoderResultShortHigh: | ||||||
|  |         data.duration = subghz_protocol_came_twee_const.te_short; | ||||||
|  |         data.level = true; | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     default: | ||||||
|  |         FURI_LOG_E(TAG, "DO CRASH HERE."); | ||||||
|  |         furi_crash(NULL); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     return level_duration_make(data.level, data.duration); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void subghz_protocol_encoder_came_twee_get_upload(SubGhzProtocolEncoderCameTwee* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     size_t index = 0; | ||||||
|  | 
 | ||||||
|  |     ManchesterEncoderState enc_state; | ||||||
|  |     manchester_encoder_reset(&enc_state); | ||||||
|  |     ManchesterEncoderResult result; | ||||||
|  | 
 | ||||||
|  |     uint64_t temp_parcel = 0x003FFF7200000000; //parcel mask
 | ||||||
|  | 
 | ||||||
|  |     for(int i = 14; i >= 0; i--) { | ||||||
|  |         temp_parcel = (temp_parcel & 0xFFFFFFFF00000000) | | ||||||
|  |                       (instance->generic.serial ^ came_twee_magic_numbers_xor[i]); | ||||||
|  | 
 | ||||||
|  |         for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { | ||||||
|  |             if(!manchester_encoder_advance(&enc_state, !bit_read(temp_parcel, i - 1), &result)) { | ||||||
|  |                 instance->encoder.upload[index++] = | ||||||
|  |                     subghz_protocol_encoder_came_twee_add_duration_to_upload(result); | ||||||
|  |                 manchester_encoder_advance(&enc_state, !bit_read(temp_parcel, i - 1), &result); | ||||||
|  |             } | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 subghz_protocol_encoder_came_twee_add_duration_to_upload(result); | ||||||
|  |         } | ||||||
|  |         instance->encoder.upload[index] = subghz_protocol_encoder_came_twee_add_duration_to_upload( | ||||||
|  |             manchester_encoder_finish(&enc_state)); | ||||||
|  |         if(level_duration_get_level(instance->encoder.upload[index])) { | ||||||
|  |             index++; | ||||||
|  |         } | ||||||
|  |         instance->encoder.upload[index++] = | ||||||
|  |             level_duration_make(false, (uint32_t)subghz_protocol_came_twee_const.te_long * 51); | ||||||
|  |     } | ||||||
|  |     instance->encoder.size_upload = index; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** Analysis of received data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance SubGhzProtocolCameTwee instance | ||||||
|  |  */ | ||||||
|  | static void subghz_protocol_came_twee_remote_controller(SubGhzBlockGeneric* instance) { | ||||||
|  |     /*      Came Twee 54 bit, rolling code 15 parcels with
 | ||||||
|  |     *       a decreasing counter from 0xE to 0x0 | ||||||
|  |     *       with originally coded dip switches on the console 10 bit code | ||||||
|  |     *  | ||||||
|  |     *  0x003FFF72E04A6FEE | ||||||
|  |     *  0x003FFF72D17B5EDD | ||||||
|  |     *  0x003FFF72C2684DCC | ||||||
|  |     *  0x003FFF72B3193CBB | ||||||
|  |     *  0x003FFF72A40E2BAA | ||||||
|  |     *  0x003FFF72953F1A99 | ||||||
|  |     *  0x003FFF72862C0988 | ||||||
|  |     *  0x003FFF7277DDF877 | ||||||
|  |     *  0x003FFF7268C2E766 | ||||||
|  |     *  0x003FFF7259F3D655 | ||||||
|  |     *  0x003FFF724AE0C544 | ||||||
|  |     *  0x003FFF723B91B433 | ||||||
|  |     *  0x003FFF722C86A322 | ||||||
|  |     *  0x003FFF721DB79211 | ||||||
|  |     *  0x003FFF720EA48100 | ||||||
|  |     *  | ||||||
|  |     *   decryption | ||||||
|  |     * the last 32 bits, do XOR by the desired number, divide the result by 4, | ||||||
|  |     * convert the first 16 bits of the resulting 32-bit number to bin and do | ||||||
|  |     * bit-by-bit mirroring, adding up to 10 bits | ||||||
|  |     *  | ||||||
|  |     * Example | ||||||
|  |     * Step 1. 0x003FFF721DB79211        => 0x1DB79211 | ||||||
|  |     * Step 4. 0x1DB79211 xor 0x1D1D1D11 => 0x00AA8F00 | ||||||
|  |     * Step 4. 0x00AA8F00 / 4            => 0x002AA3C0 | ||||||
|  |     * Step 5. 0x002AA3C0                => 0x002A | ||||||
|  |     * Step 6. 0x002A    bin             => b101010 | ||||||
|  |     * Step 7. b101010                   => b0101010000 | ||||||
|  |     * Step 8. b0101010000               => (Dip) Off ON Off ON Off ON Off Off Off Off | ||||||
|  |     */ | ||||||
|  | 
 | ||||||
|  |     uint8_t cnt_parcel = (uint8_t)(instance->data & 0xF); | ||||||
|  |     uint32_t data = (uint32_t)(instance->data & 0x0FFFFFFFF); | ||||||
|  | 
 | ||||||
|  |     data = (data ^ came_twee_magic_numbers_xor[cnt_parcel]); | ||||||
|  |     instance->serial = data; | ||||||
|  |     data /= 4; | ||||||
|  |     instance->btn = (data >> 4) & 0x0F; | ||||||
|  |     data >>= 16; | ||||||
|  |     data = (uint16_t)subghz_protocol_blocks_reverse_key(data, 16); | ||||||
|  |     instance->cnt = data >> 6; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_encoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderCameTwee* instance = context; | ||||||
|  |     bool res = false; | ||||||
|  |     do { | ||||||
|  |         if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { | ||||||
|  |             FURI_LOG_E(TAG, "Deserialize error"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         //optional parameter parameter
 | ||||||
|  |         flipper_format_read_uint32( | ||||||
|  |             flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); | ||||||
|  | 
 | ||||||
|  |         subghz_protocol_came_twee_remote_controller(&instance->generic); | ||||||
|  |         subghz_protocol_encoder_came_twee_get_upload(instance); | ||||||
|  |         instance->encoder.is_runing = true; | ||||||
|  | 
 | ||||||
|  |         res = true; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_came_twee_stop(void* context) { | ||||||
|  |     SubGhzProtocolEncoderCameTwee* instance = context; | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | LevelDuration subghz_protocol_encoder_came_twee_yield(void* context) { | ||||||
|  |     SubGhzProtocolEncoderCameTwee* instance = context; | ||||||
|  | 
 | ||||||
|  |     if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { | ||||||
|  |         instance->encoder.is_runing = false; | ||||||
|  |         return level_duration_reset(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LevelDuration ret = instance->encoder.upload[instance->encoder.front]; | ||||||
|  | 
 | ||||||
|  |     if(++instance->encoder.front == instance->encoder.size_upload) { | ||||||
|  |         instance->encoder.repeat--; | ||||||
|  |         instance->encoder.front = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_came_twee_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolDecoderCameTwee* instance = malloc(sizeof(SubGhzProtocolDecoderCameTwee)); | ||||||
|  |     instance->base.protocol = &subghz_protocol_came_twee; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_came_twee_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCameTwee* instance = context; | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_came_twee_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCameTwee* instance = context; | ||||||
|  |     instance->decoder.parser_step = CameTweeDecoderStepReset; | ||||||
|  |     manchester_advance( | ||||||
|  |         instance->manchester_saved_state, | ||||||
|  |         ManchesterEventReset, | ||||||
|  |         &instance->manchester_saved_state, | ||||||
|  |         NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_came_twee_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCameTwee* instance = context; | ||||||
|  |     ManchesterEvent event = ManchesterEventReset; | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case CameTweeDecoderStepReset: | ||||||
|  |         if((!level) && (DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_long * 51) < | ||||||
|  |                         subghz_protocol_came_twee_const.te_delta * 20)) { | ||||||
|  |             //Found header CAME
 | ||||||
|  |             instance->decoder.parser_step = CameTweeDecoderStepDecoderData; | ||||||
|  |             instance->decoder.decode_data = 0; | ||||||
|  |             instance->decoder.decode_count_bit = 0; | ||||||
|  |             manchester_advance( | ||||||
|  |                 instance->manchester_saved_state, | ||||||
|  |                 ManchesterEventLongLow, | ||||||
|  |                 &instance->manchester_saved_state, | ||||||
|  |                 NULL); | ||||||
|  |             manchester_advance( | ||||||
|  |                 instance->manchester_saved_state, | ||||||
|  |                 ManchesterEventLongHigh, | ||||||
|  |                 &instance->manchester_saved_state, | ||||||
|  |                 NULL); | ||||||
|  |             manchester_advance( | ||||||
|  |                 instance->manchester_saved_state, | ||||||
|  |                 ManchesterEventShortLow, | ||||||
|  |                 &instance->manchester_saved_state, | ||||||
|  |                 NULL); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case CameTweeDecoderStepDecoderData: | ||||||
|  |         if(!level) { | ||||||
|  |             if(DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_short) < | ||||||
|  |                subghz_protocol_came_twee_const.te_delta) { | ||||||
|  |                 event = ManchesterEventShortLow; | ||||||
|  |             } else if( | ||||||
|  |                 DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_long) < | ||||||
|  |                 subghz_protocol_came_twee_const.te_delta) { | ||||||
|  |                 event = ManchesterEventLongLow; | ||||||
|  |             } else if( | ||||||
|  |                 duration >= (subghz_protocol_came_twee_const.te_long * 2 + | ||||||
|  |                              subghz_protocol_came_twee_const.te_delta)) { | ||||||
|  |                 if(instance->decoder.decode_count_bit >= | ||||||
|  |                    subghz_protocol_came_twee_const.min_count_bit_for_found) { | ||||||
|  |                     instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                     instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  | 
 | ||||||
|  |                     if(instance->base.callback) | ||||||
|  |                         instance->base.callback(&instance->base, instance->base.context); | ||||||
|  |                 } | ||||||
|  |                 instance->decoder.decode_data = 0; | ||||||
|  |                 instance->decoder.decode_count_bit = 0; | ||||||
|  |                 manchester_advance( | ||||||
|  |                     instance->manchester_saved_state, | ||||||
|  |                     ManchesterEventLongLow, | ||||||
|  |                     &instance->manchester_saved_state, | ||||||
|  |                     NULL); | ||||||
|  |                 manchester_advance( | ||||||
|  |                     instance->manchester_saved_state, | ||||||
|  |                     ManchesterEventLongHigh, | ||||||
|  |                     &instance->manchester_saved_state, | ||||||
|  |                     NULL); | ||||||
|  |                 manchester_advance( | ||||||
|  |                     instance->manchester_saved_state, | ||||||
|  |                     ManchesterEventShortLow, | ||||||
|  |                     &instance->manchester_saved_state, | ||||||
|  |                     NULL); | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = CameTweeDecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             if(DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_short) < | ||||||
|  |                subghz_protocol_came_twee_const.te_delta) { | ||||||
|  |                 event = ManchesterEventShortHigh; | ||||||
|  |             } else if( | ||||||
|  |                 DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_long) < | ||||||
|  |                 subghz_protocol_came_twee_const.te_delta) { | ||||||
|  |                 event = ManchesterEventLongHigh; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = CameTweeDecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if(event != ManchesterEventReset) { | ||||||
|  |             bool data; | ||||||
|  |             bool data_ok = manchester_advance( | ||||||
|  |                 instance->manchester_saved_state, event, &instance->manchester_saved_state, &data); | ||||||
|  | 
 | ||||||
|  |             if(data_ok) { | ||||||
|  |                 instance->decoder.decode_data = (instance->decoder.decode_data << 1) | !data; | ||||||
|  |                 instance->decoder.decode_count_bit++; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_came_twee_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCameTwee* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_came_twee_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCameTwee* instance = context; | ||||||
|  |     return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCameTwee* instance = context; | ||||||
|  |     return subghz_block_generic_deserialize(&instance->generic, flipper_format); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_came_twee_get_string(void* context, string_t output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderCameTwee* instance = context; | ||||||
|  |     subghz_protocol_came_twee_remote_controller(&instance->generic); | ||||||
|  |     uint32_t code_found_hi = instance->generic.data >> 32; | ||||||
|  |     uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %dbit\r\n" | ||||||
|  |         "Key:0x%lX%08lX\r\n" | ||||||
|  |         "Btn:%lX\r\n" | ||||||
|  |         "DIP:" DIP_PATTERN "\r\n", | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         code_found_hi, | ||||||
|  |         code_found_lo, | ||||||
|  |         instance->generic.btn, | ||||||
|  |         CNT_TO_DIP(instance->generic.cnt)); | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								lib/subghz/protocols/came_twee.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								lib/subghz/protocols/came_twee.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "base.h" | ||||||
|  | 
 | ||||||
|  | #define SUBGHZ_PROTOCOL_CAME_TWEE_NAME "CAME TWEE" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzProtocolDecoderCameTwee SubGhzProtocolDecoderCameTwee; | ||||||
|  | typedef struct SubGhzProtocolEncoderCameTwee SubGhzProtocolEncoderCameTwee; | ||||||
|  | 
 | ||||||
|  | extern const SubGhzProtocolDecoder subghz_protocol_came_twee_decoder; | ||||||
|  | extern const SubGhzProtocolEncoder subghz_protocol_came_twee_encoder; | ||||||
|  | extern const SubGhzProtocol subghz_protocol_came_twee; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_came_twee_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_encoder_came_twee_free(void* context); | ||||||
|  | bool subghz_protocol_encoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_encoder_came_twee_stop(void* context); | ||||||
|  | LevelDuration subghz_protocol_encoder_came_twee_yield(void* context); | ||||||
|  | void* subghz_protocol_decoder_came_twee_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_decoder_came_twee_free(void* context); | ||||||
|  | void subghz_protocol_decoder_came_twee_reset(void* context); | ||||||
|  | void subghz_protocol_decoder_came_twee_feed(void* context, bool level, uint32_t duration); | ||||||
|  | uint8_t subghz_protocol_decoder_came_twee_get_hash_data(void* context); | ||||||
|  | bool subghz_protocol_decoder_came_twee_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | bool subghz_protocol_decoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_decoder_came_twee_get_string(void* context, string_t output); | ||||||
							
								
								
									
										218
									
								
								lib/subghz/protocols/faac_slh.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								lib/subghz/protocols/faac_slh.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,218 @@ | |||||||
|  | #include "faac_slh.h" | ||||||
|  | 
 | ||||||
|  | #include "../blocks/const.h" | ||||||
|  | #include "../blocks/decoder.h" | ||||||
|  | #include "../blocks/encoder.h" | ||||||
|  | #include "../blocks/generic.h" | ||||||
|  | #include "../blocks/math.h" | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzProtocolFaacSHL" | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst subghz_protocol_faac_slh_const = { | ||||||
|  |     .te_short = 255, | ||||||
|  |     .te_long = 595, | ||||||
|  |     .te_delta = 100, | ||||||
|  |     .min_count_bit_for_found = 64, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolDecoderFaacSLH { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolEncoderFaacSLH { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     FaacSLHDecoderStepReset = 0, | ||||||
|  |     FaacSLHDecoderStepFoundPreambula, | ||||||
|  |     FaacSLHDecoderStepSaveDuration, | ||||||
|  |     FaacSLHDecoderStepCheckDuration, | ||||||
|  | } FaacSLHDecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder subghz_protocol_faac_slh_decoder = { | ||||||
|  |     .alloc = subghz_protocol_decoder_faac_slh_alloc, | ||||||
|  |     .free = subghz_protocol_decoder_faac_slh_free, | ||||||
|  | 
 | ||||||
|  |     .feed = subghz_protocol_decoder_faac_slh_feed, | ||||||
|  |     .reset = subghz_protocol_decoder_faac_slh_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = subghz_protocol_decoder_faac_slh_get_hash_data, | ||||||
|  |     .serialize = subghz_protocol_decoder_faac_slh_serialize, | ||||||
|  |     .deserialize = subghz_protocol_decoder_faac_slh_deserialize, | ||||||
|  |     .get_string = subghz_protocol_decoder_faac_slh_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder subghz_protocol_faac_slh_encoder = { | ||||||
|  |     .alloc = NULL, | ||||||
|  |     .free = NULL, | ||||||
|  | 
 | ||||||
|  |     .deserialize = NULL, | ||||||
|  |     .stop = NULL, | ||||||
|  |     .yield = NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol subghz_protocol_faac_slh = { | ||||||
|  |     .name = SUBGHZ_PROTOCOL_FAAC_SLH_NAME, | ||||||
|  |     .type = SubGhzProtocolTypeDynamic, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM | | ||||||
|  |             SubGhzProtocolFlag_Decodable, | ||||||
|  | 
 | ||||||
|  |     .decoder = &subghz_protocol_faac_slh_decoder, | ||||||
|  |     .encoder = &subghz_protocol_faac_slh_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_faac_slh_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolDecoderFaacSLH* instance = malloc(sizeof(SubGhzProtocolDecoderFaacSLH)); | ||||||
|  |     instance->base.protocol = &subghz_protocol_faac_slh; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_faac_slh_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderFaacSLH* instance = context; | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_faac_slh_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderFaacSLH* instance = context; | ||||||
|  |     instance->decoder.parser_step = FaacSLHDecoderStepReset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_faac_slh_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderFaacSLH* instance = context; | ||||||
|  | 
 | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case FaacSLHDecoderStepReset: | ||||||
|  |         if((level) && (DURATION_DIFF(duration, subghz_protocol_faac_slh_const.te_long * 2) < | ||||||
|  |                        subghz_protocol_faac_slh_const.te_delta * 3)) { | ||||||
|  |             instance->decoder.parser_step = FaacSLHDecoderStepFoundPreambula; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case FaacSLHDecoderStepFoundPreambula: | ||||||
|  |         if((!level) && (DURATION_DIFF(duration, subghz_protocol_faac_slh_const.te_long * 2) < | ||||||
|  |                         subghz_protocol_faac_slh_const.te_delta * 3)) { | ||||||
|  |             //Found Preambula
 | ||||||
|  |             instance->decoder.parser_step = FaacSLHDecoderStepSaveDuration; | ||||||
|  |             instance->decoder.decode_data = 0; | ||||||
|  |             instance->decoder.decode_count_bit = 0; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = FaacSLHDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case FaacSLHDecoderStepSaveDuration: | ||||||
|  |         if(level) { | ||||||
|  |             if(duration >= (subghz_protocol_faac_slh_const.te_short * 3 + | ||||||
|  |                             subghz_protocol_faac_slh_const.te_delta)) { | ||||||
|  |                 instance->decoder.parser_step = FaacSLHDecoderStepFoundPreambula; | ||||||
|  |                 if(instance->decoder.decode_count_bit >= | ||||||
|  |                    subghz_protocol_faac_slh_const.min_count_bit_for_found) { | ||||||
|  |                     instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                     instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  | 
 | ||||||
|  |                     if(instance->base.callback) | ||||||
|  |                         instance->base.callback(&instance->base, instance->base.context); | ||||||
|  |                 } | ||||||
|  |                 instance->decoder.decode_data = 0; | ||||||
|  |                 instance->decoder.decode_count_bit = 0; | ||||||
|  |                 break; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.te_last = duration; | ||||||
|  |                 instance->decoder.parser_step = FaacSLHDecoderStepCheckDuration; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = FaacSLHDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case FaacSLHDecoderStepCheckDuration: | ||||||
|  |         if(!level) { | ||||||
|  |             if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_faac_slh_const.te_short) < | ||||||
|  |                 subghz_protocol_faac_slh_const.te_delta) && | ||||||
|  |                (DURATION_DIFF(duration, subghz_protocol_faac_slh_const.te_long) < | ||||||
|  |                 subghz_protocol_faac_slh_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                 instance->decoder.parser_step = FaacSLHDecoderStepSaveDuration; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_faac_slh_const.te_long) < | ||||||
|  |                  subghz_protocol_faac_slh_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, subghz_protocol_faac_slh_const.te_short) < | ||||||
|  |                  subghz_protocol_faac_slh_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                 instance->decoder.parser_step = FaacSLHDecoderStepSaveDuration; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = FaacSLHDecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = FaacSLHDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void subghz_protocol_faac_slh_check_remote_controller(SubGhzBlockGeneric* instance) { | ||||||
|  |     uint64_t code_found_reverse = | ||||||
|  |         subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit); | ||||||
|  |     uint32_t code_fix = code_found_reverse & 0xFFFFFFFF; | ||||||
|  | 
 | ||||||
|  |     instance->serial = code_fix & 0xFFFFFFF; | ||||||
|  |     instance->btn = (code_fix >> 28) & 0x0F; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_faac_slh_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderFaacSLH* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_faac_slh_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderFaacSLH* instance = context; | ||||||
|  |     return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_faac_slh_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderFaacSLH* instance = context; | ||||||
|  |     return subghz_block_generic_deserialize(&instance->generic, flipper_format); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_faac_slh_get_string(void* context, string_t output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderFaacSLH* instance = context; | ||||||
|  |     subghz_protocol_faac_slh_check_remote_controller(&instance->generic); | ||||||
|  |     uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key( | ||||||
|  |         instance->generic.data, instance->generic.data_count_bit); | ||||||
|  |     uint32_t code_fix = code_found_reverse & 0xFFFFFFFF; | ||||||
|  |     uint32_t code_hop = (code_found_reverse >> 32) & 0xFFFFFFFF; | ||||||
|  | 
 | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %dbit\r\n" | ||||||
|  |         "Key:%lX%08lX\r\n" | ||||||
|  |         "Fix:%08lX \r\n" | ||||||
|  |         "Hop:%08lX \r\n" | ||||||
|  |         "Sn:%07lX Btn:%lX\r\n", | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         (uint32_t)(instance->generic.data >> 32), | ||||||
|  |         (uint32_t)instance->generic.data, | ||||||
|  |         code_fix, | ||||||
|  |         code_hop, | ||||||
|  |         instance->generic.serial, | ||||||
|  |         instance->generic.btn); | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								lib/subghz/protocols/faac_slh.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/subghz/protocols/faac_slh.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "base.h" | ||||||
|  | 
 | ||||||
|  | #define SUBGHZ_PROTOCOL_FAAC_SLH_NAME "Faac SLH" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzProtocolDecoderFaacSLH SubGhzProtocolDecoderFaacSLH; | ||||||
|  | typedef struct SubGhzProtocolEncoderFaacSLH SubGhzProtocolEncoderFaacSLH; | ||||||
|  | 
 | ||||||
|  | extern const SubGhzProtocolDecoder subghz_protocol_faac_slh_decoder; | ||||||
|  | extern const SubGhzProtocolEncoder subghz_protocol_faac_slh_encoder; | ||||||
|  | extern const SubGhzProtocol subghz_protocol_faac_slh; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_faac_slh_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_decoder_faac_slh_free(void* context); | ||||||
|  | void subghz_protocol_decoder_faac_slh_reset(void* context); | ||||||
|  | void subghz_protocol_decoder_faac_slh_feed(void* context, bool level, uint32_t duration); | ||||||
|  | uint8_t subghz_protocol_decoder_faac_slh_get_hash_data(void* context); | ||||||
|  | bool subghz_protocol_decoder_faac_slh_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | bool subghz_protocol_decoder_faac_slh_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_decoder_faac_slh_get_string(void* context, string_t output); | ||||||
							
								
								
									
										308
									
								
								lib/subghz/protocols/gate_tx.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								lib/subghz/protocols/gate_tx.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,308 @@ | |||||||
|  | #include "gate_tx.h" | ||||||
|  | 
 | ||||||
|  | #include "../blocks/const.h" | ||||||
|  | #include "../blocks/decoder.h" | ||||||
|  | #include "../blocks/encoder.h" | ||||||
|  | #include "../blocks/generic.h" | ||||||
|  | #include "../blocks/math.h" | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzProtocolGateTx" | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst subghz_protocol_gate_tx_const = { | ||||||
|  |     .te_short = 350, | ||||||
|  |     .te_long = 700, | ||||||
|  |     .te_delta = 100, | ||||||
|  |     .min_count_bit_for_found = 24, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolDecoderGateTx { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolEncoderGateTx { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     GateTXDecoderStepReset = 0, | ||||||
|  |     GateTXDecoderStepFoundStartBit, | ||||||
|  |     GateTXDecoderStepSaveDuration, | ||||||
|  |     GateTXDecoderStepCheckDuration, | ||||||
|  | } GateTXDecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder subghz_protocol_gate_tx_decoder = { | ||||||
|  |     .alloc = subghz_protocol_decoder_gate_tx_alloc, | ||||||
|  |     .free = subghz_protocol_decoder_gate_tx_free, | ||||||
|  | 
 | ||||||
|  |     .feed = subghz_protocol_decoder_gate_tx_feed, | ||||||
|  |     .reset = subghz_protocol_decoder_gate_tx_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = subghz_protocol_decoder_gate_tx_get_hash_data, | ||||||
|  |     .serialize = subghz_protocol_decoder_gate_tx_serialize, | ||||||
|  |     .deserialize = subghz_protocol_decoder_gate_tx_deserialize, | ||||||
|  |     .get_string = subghz_protocol_decoder_gate_tx_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder subghz_protocol_gate_tx_encoder = { | ||||||
|  |     .alloc = subghz_protocol_encoder_gate_tx_alloc, | ||||||
|  |     .free = subghz_protocol_encoder_gate_tx_free, | ||||||
|  | 
 | ||||||
|  |     .deserialize = subghz_protocol_encoder_gate_tx_deserialize, | ||||||
|  |     .stop = subghz_protocol_encoder_gate_tx_stop, | ||||||
|  |     .yield = subghz_protocol_encoder_gate_tx_yield, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol subghz_protocol_gate_tx = { | ||||||
|  |     .name = SUBGHZ_PROTOCOL_GATE_TX_NAME, | ||||||
|  |     .type = SubGhzProtocolTypeStatic, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | | ||||||
|  |             SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, | ||||||
|  | 
 | ||||||
|  |     .decoder = &subghz_protocol_gate_tx_decoder, | ||||||
|  |     .encoder = &subghz_protocol_gate_tx_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_gate_tx_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolEncoderGateTx* instance = malloc(sizeof(SubGhzProtocolEncoderGateTx)); | ||||||
|  | 
 | ||||||
|  |     instance->base.protocol = &subghz_protocol_gate_tx; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  | 
 | ||||||
|  |     instance->encoder.repeat = 10; | ||||||
|  |     instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop)
 | ||||||
|  |     instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_gate_tx_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderGateTx* instance = context; | ||||||
|  |     free(instance->encoder.upload); | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool subghz_protocol_encoder_gate_tx_get_upload(SubGhzProtocolEncoderGateTx* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     size_t index = 0; | ||||||
|  |     size_t size_upload = (instance->generic.data_count_bit * 2) + 2; | ||||||
|  |     if(size_upload > instance->encoder.size_upload) { | ||||||
|  |         FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); | ||||||
|  |         return false; | ||||||
|  |     } else { | ||||||
|  |         instance->encoder.size_upload = size_upload; | ||||||
|  |     } | ||||||
|  |     //Send header
 | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(false, (uint32_t)subghz_protocol_gate_tx_const.te_short * 49); | ||||||
|  |     //Send start bit
 | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(true, (uint32_t)subghz_protocol_gate_tx_const.te_long); | ||||||
|  |     //Send key data
 | ||||||
|  |     for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { | ||||||
|  |         if(bit_read(instance->generic.data, i - 1)) { | ||||||
|  |             //send bit 1
 | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(false, (uint32_t)subghz_protocol_gate_tx_const.te_long); | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(true, (uint32_t)subghz_protocol_gate_tx_const.te_short); | ||||||
|  |         } else { | ||||||
|  |             //send bit 0
 | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(false, (uint32_t)subghz_protocol_gate_tx_const.te_short); | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(true, (uint32_t)subghz_protocol_gate_tx_const.te_long); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_encoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderGateTx* instance = context; | ||||||
|  |     bool res = false; | ||||||
|  |     do { | ||||||
|  |         if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { | ||||||
|  |             FURI_LOG_E(TAG, "Deserialize error"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         //optional parameter parameter
 | ||||||
|  |         flipper_format_read_uint32( | ||||||
|  |             flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); | ||||||
|  | 
 | ||||||
|  |         subghz_protocol_encoder_gate_tx_get_upload(instance); | ||||||
|  |         instance->encoder.is_runing = true; | ||||||
|  | 
 | ||||||
|  |         res = true; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_gate_tx_stop(void* context) { | ||||||
|  |     SubGhzProtocolEncoderGateTx* instance = context; | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | LevelDuration subghz_protocol_encoder_gate_tx_yield(void* context) { | ||||||
|  |     SubGhzProtocolEncoderGateTx* instance = context; | ||||||
|  | 
 | ||||||
|  |     if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { | ||||||
|  |         instance->encoder.is_runing = false; | ||||||
|  |         return level_duration_reset(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LevelDuration ret = instance->encoder.upload[instance->encoder.front]; | ||||||
|  | 
 | ||||||
|  |     if(++instance->encoder.front == instance->encoder.size_upload) { | ||||||
|  |         instance->encoder.repeat--; | ||||||
|  |         instance->encoder.front = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_gate_tx_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolDecoderGateTx* instance = malloc(sizeof(SubGhzProtocolDecoderGateTx)); | ||||||
|  |     instance->base.protocol = &subghz_protocol_gate_tx; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_gate_tx_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderGateTx* instance = context; | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_gate_tx_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderGateTx* instance = context; | ||||||
|  |     instance->decoder.parser_step = GateTXDecoderStepReset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_gate_tx_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderGateTx* instance = context; | ||||||
|  | 
 | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case GateTXDecoderStepReset: | ||||||
|  |         if((!level) && (DURATION_DIFF(duration, subghz_protocol_gate_tx_const.te_short * 47) < | ||||||
|  |                         subghz_protocol_gate_tx_const.te_delta * 47)) { | ||||||
|  |             //Found Preambula
 | ||||||
|  |             instance->decoder.parser_step = GateTXDecoderStepFoundStartBit; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case GateTXDecoderStepFoundStartBit: | ||||||
|  |         if(level && ((DURATION_DIFF(duration, subghz_protocol_gate_tx_const.te_long) < | ||||||
|  |                       subghz_protocol_gate_tx_const.te_delta * 3))) { | ||||||
|  |             //Found start bit
 | ||||||
|  |             instance->decoder.parser_step = GateTXDecoderStepSaveDuration; | ||||||
|  |             instance->decoder.decode_data = 0; | ||||||
|  |             instance->decoder.decode_count_bit = 0; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = GateTXDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case GateTXDecoderStepSaveDuration: | ||||||
|  |         if(!level) { | ||||||
|  |             if(duration >= (subghz_protocol_gate_tx_const.te_short * 10 + | ||||||
|  |                             subghz_protocol_gate_tx_const.te_delta)) { | ||||||
|  |                 instance->decoder.parser_step = GateTXDecoderStepFoundStartBit; | ||||||
|  |                 if(instance->decoder.decode_count_bit >= | ||||||
|  |                    subghz_protocol_gate_tx_const.min_count_bit_for_found) { | ||||||
|  |                     instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                     instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  | 
 | ||||||
|  |                     if(instance->base.callback) | ||||||
|  |                         instance->base.callback(&instance->base, instance->base.context); | ||||||
|  |                 } | ||||||
|  |                 instance->decoder.decode_data = 0; | ||||||
|  |                 instance->decoder.decode_count_bit = 0; | ||||||
|  |                 break; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.te_last = duration; | ||||||
|  |                 instance->decoder.parser_step = GateTXDecoderStepCheckDuration; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case GateTXDecoderStepCheckDuration: | ||||||
|  |         if(level) { | ||||||
|  |             if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_gate_tx_const.te_short) < | ||||||
|  |                 subghz_protocol_gate_tx_const.te_delta) && | ||||||
|  |                (DURATION_DIFF(duration, subghz_protocol_gate_tx_const.te_long) < | ||||||
|  |                 subghz_protocol_gate_tx_const.te_delta * 3)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                 instance->decoder.parser_step = GateTXDecoderStepSaveDuration; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_gate_tx_const.te_long) < | ||||||
|  |                  subghz_protocol_gate_tx_const.te_delta * 3) && | ||||||
|  |                 (DURATION_DIFF(duration, subghz_protocol_gate_tx_const.te_short) < | ||||||
|  |                  subghz_protocol_gate_tx_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                 instance->decoder.parser_step = GateTXDecoderStepSaveDuration; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = GateTXDecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = GateTXDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void subghz_protocol_gate_tx_check_remote_controller(SubGhzBlockGeneric* instance) { | ||||||
|  |     uint32_t code_found_reverse = | ||||||
|  |         subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit); | ||||||
|  | 
 | ||||||
|  |     instance->serial = (code_found_reverse & 0xFF) << 12 | | ||||||
|  |                        ((code_found_reverse >> 8) & 0xFF) << 4 | | ||||||
|  |                        ((code_found_reverse >> 20) & 0x0F); | ||||||
|  |     instance->btn = ((code_found_reverse >> 16) & 0x0F); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_gate_tx_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderGateTx* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_gate_tx_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderGateTx* instance = context; | ||||||
|  |     return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderGateTx* instance = context; | ||||||
|  |     return subghz_block_generic_deserialize(&instance->generic, flipper_format); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_gate_tx_get_string(void* context, string_t output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderGateTx* instance = context; | ||||||
|  |     subghz_protocol_gate_tx_check_remote_controller(&instance->generic); | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %dbit\r\n" | ||||||
|  |         "Key:%06lX\r\n" | ||||||
|  |         "Sn:%05lX  Btn:%lX\r\n", | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         (uint32_t)(instance->generic.data & 0xFFFFFF), | ||||||
|  |         instance->generic.serial, | ||||||
|  |         instance->generic.btn); | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								lib/subghz/protocols/gate_tx.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								lib/subghz/protocols/gate_tx.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "base.h" | ||||||
|  | 
 | ||||||
|  | #define SUBGHZ_PROTOCOL_GATE_TX_NAME "GateTX" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzProtocolDecoderGateTx SubGhzProtocolDecoderGateTx; | ||||||
|  | typedef struct SubGhzProtocolEncoderGateTx SubGhzProtocolEncoderGateTx; | ||||||
|  | 
 | ||||||
|  | extern const SubGhzProtocolDecoder subghz_protocol_gate_tx_decoder; | ||||||
|  | extern const SubGhzProtocolEncoder subghz_protocol_gate_tx_encoder; | ||||||
|  | extern const SubGhzProtocol subghz_protocol_gate_tx; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_gate_tx_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_encoder_gate_tx_free(void* context); | ||||||
|  | bool subghz_protocol_encoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_encoder_gate_tx_stop(void* context); | ||||||
|  | LevelDuration subghz_protocol_encoder_gate_tx_yield(void* context); | ||||||
|  | void* subghz_protocol_decoder_gate_tx_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_decoder_gate_tx_free(void* context); | ||||||
|  | void subghz_protocol_decoder_gate_tx_reset(void* context); | ||||||
|  | void subghz_protocol_decoder_gate_tx_feed(void* context, bool level, uint32_t duration); | ||||||
|  | uint8_t subghz_protocol_decoder_gate_tx_get_hash_data(void* context); | ||||||
|  | bool subghz_protocol_decoder_gate_tx_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | bool subghz_protocol_decoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_decoder_gate_tx_get_string(void* context, string_t output); | ||||||
							
								
								
									
										331
									
								
								lib/subghz/protocols/hormann.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										331
									
								
								lib/subghz/protocols/hormann.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,331 @@ | |||||||
|  | #include "hormann.h" | ||||||
|  | 
 | ||||||
|  | #include "../blocks/const.h" | ||||||
|  | #include "../blocks/decoder.h" | ||||||
|  | #include "../blocks/encoder.h" | ||||||
|  | #include "../blocks/generic.h" | ||||||
|  | #include "../blocks/math.h" | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzProtocolHormannHSM" | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst subghz_protocol_hormann_const = { | ||||||
|  |     .te_short = 500, | ||||||
|  |     .te_long = 1000, | ||||||
|  |     .te_delta = 200, | ||||||
|  |     .min_count_bit_for_found = 44, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolDecoderHormann { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolEncoderHormann { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     HormannDecoderStepReset = 0, | ||||||
|  |     HormannDecoderStepFoundStartHeader, | ||||||
|  |     HormannDecoderStepFoundHeader, | ||||||
|  |     HormannDecoderStepFoundStartBit, | ||||||
|  |     HormannDecoderStepSaveDuration, | ||||||
|  |     HormannDecoderStepCheckDuration, | ||||||
|  | } HormannDecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder subghz_protocol_hormann_decoder = { | ||||||
|  |     .alloc = subghz_protocol_decoder_hormann_alloc, | ||||||
|  |     .free = subghz_protocol_decoder_hormann_free, | ||||||
|  | 
 | ||||||
|  |     .feed = subghz_protocol_decoder_hormann_feed, | ||||||
|  |     .reset = subghz_protocol_decoder_hormann_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = subghz_protocol_decoder_hormann_get_hash_data, | ||||||
|  |     .serialize = subghz_protocol_decoder_hormann_serialize, | ||||||
|  |     .deserialize = subghz_protocol_decoder_hormann_deserialize, | ||||||
|  |     .get_string = subghz_protocol_decoder_hormann_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder subghz_protocol_hormann_encoder = { | ||||||
|  |     .alloc = subghz_protocol_encoder_hormann_alloc, | ||||||
|  |     .free = subghz_protocol_encoder_hormann_free, | ||||||
|  | 
 | ||||||
|  |     .deserialize = subghz_protocol_encoder_hormann_deserialize, | ||||||
|  |     .stop = subghz_protocol_encoder_hormann_stop, | ||||||
|  |     .yield = subghz_protocol_encoder_hormann_yield, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol subghz_protocol_hormann = { | ||||||
|  |     .name = SUBGHZ_PROTOCOL_HORMANN_HSM_NAME, | ||||||
|  |     .type = SubGhzProtocolTypeStatic, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM | | ||||||
|  |             SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | | ||||||
|  |             SubGhzProtocolFlag_Send, | ||||||
|  | 
 | ||||||
|  |     .decoder = &subghz_protocol_hormann_decoder, | ||||||
|  |     .encoder = &subghz_protocol_hormann_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_hormann_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolEncoderHormann* instance = malloc(sizeof(SubGhzProtocolEncoderHormann)); | ||||||
|  | 
 | ||||||
|  |     instance->base.protocol = &subghz_protocol_hormann; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  | 
 | ||||||
|  |     instance->encoder.repeat = 10; | ||||||
|  |     instance->encoder.size_upload = 2048; | ||||||
|  |     instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_hormann_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderHormann* instance = context; | ||||||
|  |     free(instance->encoder.upload); | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool subghz_protocol_encoder_hormann_get_upload(SubGhzProtocolEncoderHormann* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  | 
 | ||||||
|  |     size_t index = 0; | ||||||
|  |     size_t size_upload = 3 + (instance->generic.data_count_bit * 2 + 2) * 20 + 1; | ||||||
|  |     if(size_upload > instance->encoder.size_upload) { | ||||||
|  |         FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); | ||||||
|  |         return false; | ||||||
|  |     } else { | ||||||
|  |         instance->encoder.size_upload = size_upload; | ||||||
|  |     } | ||||||
|  |     //Send header
 | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(false, (uint32_t)subghz_protocol_hormann_const.te_short * 64); | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_short * 64); | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(false, (uint32_t)subghz_protocol_hormann_const.te_short * 64); | ||||||
|  |     instance->encoder.repeat = 10; //original remote does 10 repeats
 | ||||||
|  | 
 | ||||||
|  |     for(size_t repeat = 0; repeat < 20; repeat++) { | ||||||
|  |         //Send start bit
 | ||||||
|  |         instance->encoder.upload[index++] = | ||||||
|  |             level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_short * 24); | ||||||
|  |         instance->encoder.upload[index++] = | ||||||
|  |             level_duration_make(false, (uint32_t)subghz_protocol_hormann_const.te_short); | ||||||
|  |         //Send key data
 | ||||||
|  |         for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { | ||||||
|  |             if(bit_read(instance->generic.data, i - 1)) { | ||||||
|  |                 //send bit 1
 | ||||||
|  |                 instance->encoder.upload[index++] = | ||||||
|  |                     level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_long); | ||||||
|  |                 instance->encoder.upload[index++] = | ||||||
|  |                     level_duration_make(false, (uint32_t)subghz_protocol_hormann_const.te_short); | ||||||
|  |             } else { | ||||||
|  |                 //send bit 0
 | ||||||
|  |                 instance->encoder.upload[index++] = | ||||||
|  |                     level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_short); | ||||||
|  |                 instance->encoder.upload[index++] = | ||||||
|  |                     level_duration_make(false, (uint32_t)subghz_protocol_hormann_const.te_long); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_short * 24); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_encoder_hormann_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderHormann* instance = context; | ||||||
|  |     bool res = false; | ||||||
|  |     do { | ||||||
|  |         if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { | ||||||
|  |             FURI_LOG_E(TAG, "Deserialize error"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         //optional parameter parameter
 | ||||||
|  |         flipper_format_read_uint32( | ||||||
|  |             flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); | ||||||
|  | 
 | ||||||
|  |         subghz_protocol_encoder_hormann_get_upload(instance); | ||||||
|  |         instance->encoder.is_runing = true; | ||||||
|  | 
 | ||||||
|  |         res = true; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_hormann_stop(void* context) { | ||||||
|  |     SubGhzProtocolEncoderHormann* instance = context; | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | LevelDuration subghz_protocol_encoder_hormann_yield(void* context) { | ||||||
|  |     SubGhzProtocolEncoderHormann* instance = context; | ||||||
|  | 
 | ||||||
|  |     if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { | ||||||
|  |         instance->encoder.is_runing = false; | ||||||
|  |         return level_duration_reset(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LevelDuration ret = instance->encoder.upload[instance->encoder.front]; | ||||||
|  | 
 | ||||||
|  |     if(++instance->encoder.front == instance->encoder.size_upload) { | ||||||
|  |         instance->encoder.repeat--; | ||||||
|  |         instance->encoder.front = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_hormann_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolDecoderHormann* instance = malloc(sizeof(SubGhzProtocolDecoderHormann)); | ||||||
|  |     instance->base.protocol = &subghz_protocol_hormann; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_hormann_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderHormann* instance = context; | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_hormann_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderHormann* instance = context; | ||||||
|  |     instance->decoder.parser_step = HormannDecoderStepReset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_hormann_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderHormann* instance = context; | ||||||
|  | 
 | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case HormannDecoderStepReset: | ||||||
|  |         if((level) && (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short * 64) < | ||||||
|  |                        subghz_protocol_hormann_const.te_delta * 64)) { | ||||||
|  |             instance->decoder.parser_step = HormannDecoderStepFoundStartHeader; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case HormannDecoderStepFoundStartHeader: | ||||||
|  |         if((!level) && (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short * 64) < | ||||||
|  |                         subghz_protocol_hormann_const.te_delta * 64)) { | ||||||
|  |             instance->decoder.parser_step = HormannDecoderStepFoundHeader; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = HormannDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case HormannDecoderStepFoundHeader: | ||||||
|  |         if((level) && (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short * 24) < | ||||||
|  |                        subghz_protocol_hormann_const.te_delta * 24)) { | ||||||
|  |             instance->decoder.parser_step = HormannDecoderStepFoundStartBit; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = HormannDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case HormannDecoderStepFoundStartBit: | ||||||
|  |         if((!level) && (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short) < | ||||||
|  |                         subghz_protocol_hormann_const.te_delta)) { | ||||||
|  |             instance->decoder.parser_step = HormannDecoderStepSaveDuration; | ||||||
|  |             instance->decoder.decode_data = 0; | ||||||
|  |             instance->decoder.decode_count_bit = 0; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = HormannDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case HormannDecoderStepSaveDuration: | ||||||
|  |         if(level) { //save interval
 | ||||||
|  |             if(duration >= (subghz_protocol_hormann_const.te_short * 5)) { | ||||||
|  |                 instance->decoder.parser_step = HormannDecoderStepFoundStartBit; | ||||||
|  |                 if(instance->decoder.decode_count_bit >= | ||||||
|  |                    subghz_protocol_hormann_const.min_count_bit_for_found) { | ||||||
|  |                     instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                     instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  | 
 | ||||||
|  |                     if(instance->base.callback) | ||||||
|  |                         instance->base.callback(&instance->base, instance->base.context); | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             instance->decoder.te_last = duration; | ||||||
|  |             instance->decoder.parser_step = HormannDecoderStepCheckDuration; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = HormannDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case HormannDecoderStepCheckDuration: | ||||||
|  |         if(!level) { | ||||||
|  |             if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_hormann_const.te_short) < | ||||||
|  |                 subghz_protocol_hormann_const.te_delta) && | ||||||
|  |                (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_long) < | ||||||
|  |                 subghz_protocol_hormann_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                 instance->decoder.parser_step = HormannDecoderStepSaveDuration; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_hormann_const.te_long) < | ||||||
|  |                  subghz_protocol_hormann_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short) < | ||||||
|  |                  subghz_protocol_hormann_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                 instance->decoder.parser_step = HormannDecoderStepSaveDuration; | ||||||
|  |             } else | ||||||
|  |                 instance->decoder.parser_step = HormannDecoderStepReset; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = HormannDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void subghz_protocol_hormann_check_remote_controller(SubGhzBlockGeneric* instance) { | ||||||
|  |     instance->btn = (instance->data >> 4) & 0xF; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_hormann_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderHormann* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_hormann_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderHormann* instance = context; | ||||||
|  |     return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_hormann_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderHormann* instance = context; | ||||||
|  |     return subghz_block_generic_deserialize(&instance->generic, flipper_format); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_hormann_get_string(void* context, string_t output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderHormann* instance = context; | ||||||
|  |     subghz_protocol_hormann_check_remote_controller(&instance->generic); | ||||||
|  | 
 | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "%s\r\n" | ||||||
|  |         "%dbit\r\n" | ||||||
|  |         "Key:0x%03lX%08lX\r\n" | ||||||
|  |         "Btn:0x%01X\r\n", | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         (uint32_t)(instance->generic.data >> 32), | ||||||
|  |         (uint32_t)instance->generic.data, | ||||||
|  |         instance->generic.btn); | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								lib/subghz/protocols/hormann.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								lib/subghz/protocols/hormann.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "base.h" | ||||||
|  | 
 | ||||||
|  | #define SUBGHZ_PROTOCOL_HORMANN_HSM_NAME "Hormann HSM" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzProtocolDecoderHormann SubGhzProtocolDecoderHormann; | ||||||
|  | typedef struct SubGhzProtocolEncoderHormann SubGhzProtocolEncoderHormann; | ||||||
|  | 
 | ||||||
|  | extern const SubGhzProtocolDecoder subghz_protocol_hormann_decoder; | ||||||
|  | extern const SubGhzProtocolEncoder subghz_protocol_hormann_encoder; | ||||||
|  | extern const SubGhzProtocol subghz_protocol_hormann; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_hormann_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_encoder_hormann_free(void* context); | ||||||
|  | bool subghz_protocol_encoder_hormann_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_encoder_hormann_stop(void* context); | ||||||
|  | LevelDuration subghz_protocol_encoder_hormann_yield(void* context); | ||||||
|  | void* subghz_protocol_decoder_hormann_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_decoder_hormann_free(void* context); | ||||||
|  | void subghz_protocol_decoder_hormann_reset(void* context); | ||||||
|  | void subghz_protocol_decoder_hormann_feed(void* context, bool level, uint32_t duration); | ||||||
|  | uint8_t subghz_protocol_decoder_hormann_get_hash_data(void* context); | ||||||
|  | bool subghz_protocol_decoder_hormann_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | bool subghz_protocol_decoder_hormann_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_decoder_hormann_get_string(void* context, string_t output); | ||||||
							
								
								
									
										218
									
								
								lib/subghz/protocols/ido.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								lib/subghz/protocols/ido.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,218 @@ | |||||||
|  | #include "ido.h" | ||||||
|  | 
 | ||||||
|  | #include "../blocks/const.h" | ||||||
|  | #include "../blocks/decoder.h" | ||||||
|  | #include "../blocks/encoder.h" | ||||||
|  | #include "../blocks/generic.h" | ||||||
|  | #include "../blocks/math.h" | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzProtocol_iDo_117/111" | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst subghz_protocol_ido_const = { | ||||||
|  |     .te_short = 450, | ||||||
|  |     .te_long = 1450, | ||||||
|  |     .te_delta = 150, | ||||||
|  |     .min_count_bit_for_found = 48, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolDecoderIDo { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolEncoderIDo { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     IDoDecoderStepReset = 0, | ||||||
|  |     IDoDecoderStepFoundPreambula, | ||||||
|  |     IDoDecoderStepSaveDuration, | ||||||
|  |     IDoDecoderStepCheckDuration, | ||||||
|  | } IDoDecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder subghz_protocol_ido_decoder = { | ||||||
|  |     .alloc = subghz_protocol_decoder_ido_alloc, | ||||||
|  |     .free = subghz_protocol_decoder_ido_free, | ||||||
|  | 
 | ||||||
|  |     .feed = subghz_protocol_decoder_ido_feed, | ||||||
|  |     .reset = subghz_protocol_decoder_ido_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = subghz_protocol_decoder_ido_get_hash_data, | ||||||
|  |     .deserialize = subghz_protocol_decoder_ido_deserialize, | ||||||
|  |     .serialize = subghz_protocol_decoder_ido_serialize, | ||||||
|  |     .get_string = subghz_protocol_decoder_ido_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder subghz_protocol_ido_encoder = { | ||||||
|  |     .alloc = NULL, | ||||||
|  |     .free = NULL, | ||||||
|  | 
 | ||||||
|  |     .deserialize = NULL, | ||||||
|  |     .stop = NULL, | ||||||
|  |     .yield = NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol subghz_protocol_ido = { | ||||||
|  |     .name = SUBGHZ_PROTOCOL_IDO_NAME, | ||||||
|  |     .type = SubGhzProtocolTypeDynamic, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, | ||||||
|  | 
 | ||||||
|  |     .decoder = &subghz_protocol_ido_decoder, | ||||||
|  |     .encoder = &subghz_protocol_ido_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_ido_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolDecoderIDo* instance = malloc(sizeof(SubGhzProtocolDecoderIDo)); | ||||||
|  |     instance->base.protocol = &subghz_protocol_ido; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  | 
 | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_ido_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderIDo* instance = context; | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_ido_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderIDo* instance = context; | ||||||
|  |     instance->decoder.parser_step = IDoDecoderStepReset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_ido_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderIDo* instance = context; | ||||||
|  | 
 | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case IDoDecoderStepReset: | ||||||
|  |         if((level) && (DURATION_DIFF(duration, subghz_protocol_ido_const.te_short * 10) < | ||||||
|  |                        subghz_protocol_ido_const.te_delta * 5)) { | ||||||
|  |             instance->decoder.parser_step = IDoDecoderStepFoundPreambula; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case IDoDecoderStepFoundPreambula: | ||||||
|  |         if((!level) && (DURATION_DIFF(duration, subghz_protocol_ido_const.te_short * 10) < | ||||||
|  |                         subghz_protocol_ido_const.te_delta * 5)) { | ||||||
|  |             //Found Preambula
 | ||||||
|  |             instance->decoder.parser_step = IDoDecoderStepSaveDuration; | ||||||
|  |             instance->decoder.decode_data = 0; | ||||||
|  |             instance->decoder.decode_count_bit = 0; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = IDoDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case IDoDecoderStepSaveDuration: | ||||||
|  |         if(level) { | ||||||
|  |             if(duration >= | ||||||
|  |                (subghz_protocol_ido_const.te_short * 5 + subghz_protocol_ido_const.te_delta)) { | ||||||
|  |                 instance->decoder.parser_step = IDoDecoderStepFoundPreambula; | ||||||
|  |                 if(instance->decoder.decode_count_bit >= | ||||||
|  |                    subghz_protocol_ido_const.min_count_bit_for_found) { | ||||||
|  |                     instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                     instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  |                     if(instance->base.callback) | ||||||
|  |                         instance->base.callback(&instance->base, instance->base.context); | ||||||
|  |                 } | ||||||
|  |                 instance->decoder.decode_data = 0; | ||||||
|  |                 instance->decoder.decode_count_bit = 0; | ||||||
|  |                 break; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.te_last = duration; | ||||||
|  |                 instance->decoder.parser_step = IDoDecoderStepCheckDuration; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = IDoDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case IDoDecoderStepCheckDuration: | ||||||
|  |         if(!level) { | ||||||
|  |             if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_ido_const.te_short) < | ||||||
|  |                 subghz_protocol_ido_const.te_delta) && | ||||||
|  |                (DURATION_DIFF(duration, subghz_protocol_ido_const.te_long) < | ||||||
|  |                 subghz_protocol_ido_const.te_delta * 3)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                 instance->decoder.parser_step = IDoDecoderStepSaveDuration; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_ido_const.te_short) < | ||||||
|  |                  subghz_protocol_ido_const.te_delta * 3) && | ||||||
|  |                 (DURATION_DIFF(duration, subghz_protocol_ido_const.te_short) < | ||||||
|  |                  subghz_protocol_ido_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                 instance->decoder.parser_step = IDoDecoderStepSaveDuration; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = IDoDecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = IDoDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void subghz_protocol_ido_check_remote_controller(SubGhzBlockGeneric* instance) { | ||||||
|  |     uint64_t code_found_reverse = | ||||||
|  |         subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit); | ||||||
|  |     uint32_t code_fix = code_found_reverse & 0xFFFFFF; | ||||||
|  | 
 | ||||||
|  |     instance->serial = code_fix & 0xFFFFF; | ||||||
|  |     instance->btn = (code_fix >> 20) & 0x0F; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_ido_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderIDo* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_ido_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderIDo* instance = context; | ||||||
|  |     return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_ido_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderIDo* instance = context; | ||||||
|  |     return subghz_block_generic_deserialize(&instance->generic, flipper_format); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_ido_get_string(void* context, string_t output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderIDo* instance = context; | ||||||
|  | 
 | ||||||
|  |     subghz_protocol_ido_check_remote_controller(&instance->generic); | ||||||
|  |     uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key( | ||||||
|  |         instance->generic.data, instance->generic.data_count_bit); | ||||||
|  |     uint32_t code_fix = code_found_reverse & 0xFFFFFF; | ||||||
|  |     uint32_t code_hop = (code_found_reverse >> 24) & 0xFFFFFF; | ||||||
|  | 
 | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %dbit\r\n" | ||||||
|  |         "Key:0x%lX%08lX\r\n" | ||||||
|  |         "Fix:%06lX \r\n" | ||||||
|  |         "Hop:%06lX \r\n" | ||||||
|  |         "Sn:%05lX Btn:%lX\r\n", | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         (uint32_t)(instance->generic.data >> 32), | ||||||
|  |         (uint32_t)instance->generic.data, | ||||||
|  |         code_fix, | ||||||
|  |         code_hop, | ||||||
|  |         instance->generic.serial, | ||||||
|  |         instance->generic.btn); | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								lib/subghz/protocols/ido.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/subghz/protocols/ido.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "base.h" | ||||||
|  | 
 | ||||||
|  | #define SUBGHZ_PROTOCOL_IDO_NAME "iDo 117/111" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzProtocolDecoderIDo SubGhzProtocolDecoderIDo; | ||||||
|  | typedef struct SubGhzProtocolEncoderIDo SubGhzProtocolEncoderIDo; | ||||||
|  | 
 | ||||||
|  | extern const SubGhzProtocolDecoder subghz_protocol_ido_decoder; | ||||||
|  | extern const SubGhzProtocolEncoder subghz_protocol_ido_encoder; | ||||||
|  | extern const SubGhzProtocol subghz_protocol_ido; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_ido_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_decoder_ido_free(void* context); | ||||||
|  | void subghz_protocol_decoder_ido_reset(void* context); | ||||||
|  | void subghz_protocol_decoder_ido_feed(void* context, bool level, uint32_t duration); | ||||||
|  | uint8_t subghz_protocol_decoder_ido_get_hash_data(void* context); | ||||||
|  | bool subghz_protocol_decoder_ido_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | bool subghz_protocol_decoder_ido_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_decoder_ido_get_string(void* context, string_t output); | ||||||
							
								
								
									
										681
									
								
								lib/subghz/protocols/keeloq.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										681
									
								
								lib/subghz/protocols/keeloq.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,681 @@ | |||||||
|  | #include "keeloq.h" | ||||||
|  | #include "keeloq_common.h" | ||||||
|  | 
 | ||||||
|  | #include "../subghz_keystore.h" | ||||||
|  | #include <m-string.h> | ||||||
|  | #include <m-array.h> | ||||||
|  | 
 | ||||||
|  | #include "../blocks/const.h" | ||||||
|  | #include "../blocks/decoder.h" | ||||||
|  | #include "../blocks/encoder.h" | ||||||
|  | #include "../blocks/generic.h" | ||||||
|  | #include "../blocks/math.h" | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzProtocolkeeloq" | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst subghz_protocol_keeloq_const = { | ||||||
|  |     .te_short = 400, | ||||||
|  |     .te_long = 800, | ||||||
|  |     .te_delta = 140, | ||||||
|  |     .min_count_bit_for_found = 64, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolDecoderKeeloq { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | 
 | ||||||
|  |     uint16_t header_count; | ||||||
|  |     SubGhzKeystore* keystore; | ||||||
|  |     const char* manufacture_name; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolEncoderKeeloq { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | 
 | ||||||
|  |     SubGhzKeystore* keystore; | ||||||
|  |     const char* manufacture_name; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     KeeloqDecoderStepReset = 0, | ||||||
|  |     KeeloqDecoderStepCheckPreambula, | ||||||
|  |     KeeloqDecoderStepSaveDuration, | ||||||
|  |     KeeloqDecoderStepCheckDuration, | ||||||
|  | } KeeloqDecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder subghz_protocol_keeloq_decoder = { | ||||||
|  |     .alloc = subghz_protocol_decoder_keeloq_alloc, | ||||||
|  |     .free = subghz_protocol_decoder_keeloq_free, | ||||||
|  | 
 | ||||||
|  |     .feed = subghz_protocol_decoder_keeloq_feed, | ||||||
|  |     .reset = subghz_protocol_decoder_keeloq_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = subghz_protocol_decoder_keeloq_get_hash_data, | ||||||
|  |     .serialize = subghz_protocol_decoder_keeloq_serialize, | ||||||
|  |     .deserialize = subghz_protocol_decoder_keeloq_deserialize, | ||||||
|  |     .get_string = subghz_protocol_decoder_keeloq_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder subghz_protocol_keeloq_encoder = { | ||||||
|  |     .alloc = subghz_protocol_encoder_keeloq_alloc, | ||||||
|  |     .free = subghz_protocol_encoder_keeloq_free, | ||||||
|  | 
 | ||||||
|  |     .deserialize = subghz_protocol_encoder_keeloq_deserialize, | ||||||
|  |     .stop = subghz_protocol_encoder_keeloq_stop, | ||||||
|  |     .yield = subghz_protocol_encoder_keeloq_yield, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol subghz_protocol_keeloq = { | ||||||
|  |     .name = SUBGHZ_PROTOCOL_KEELOQ_NAME, | ||||||
|  |     .type = SubGhzProtocolTypeDynamic, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_315 | | ||||||
|  |             SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | | ||||||
|  |             SubGhzProtocolFlag_Send, | ||||||
|  | 
 | ||||||
|  |     .decoder = &subghz_protocol_keeloq_decoder, | ||||||
|  |     .encoder = &subghz_protocol_keeloq_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void subghz_protocol_keeloq_check_remote_controller( | ||||||
|  |     SubGhzBlockGeneric* instance, | ||||||
|  |     SubGhzKeystore* keystore, | ||||||
|  |     const char** manufacture_name); | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_keeloq_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolEncoderKeeloq* instance = malloc(sizeof(SubGhzProtocolEncoderKeeloq)); | ||||||
|  | 
 | ||||||
|  |     instance->base.protocol = &subghz_protocol_keeloq; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  |     instance->keystore = subghz_environment_get_keystore(environment); | ||||||
|  | 
 | ||||||
|  |     instance->encoder.repeat = 10; | ||||||
|  |     instance->encoder.size_upload = 256; | ||||||
|  |     instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_keeloq_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderKeeloq* instance = context; | ||||||
|  |     free(instance->encoder.upload); | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool subghz_protocol_keeloq_gen_data(SubGhzProtocolEncoderKeeloq* instance, uint8_t btn) { | ||||||
|  |     instance->generic.cnt++; | ||||||
|  |     uint32_t fix = btn << 28 | instance->generic.serial; | ||||||
|  |     uint32_t decrypt = btn << 28 | | ||||||
|  |                        (instance->generic.serial & 0x3FF) | ||||||
|  |                            << 16 | //ToDo in some protocols the discriminator is 0
 | ||||||
|  |                        instance->generic.cnt; | ||||||
|  |     uint32_t hop = 0; | ||||||
|  |     uint64_t man = 0; | ||||||
|  |     int res = 0; | ||||||
|  | 
 | ||||||
|  |     for | ||||||
|  |         M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { | ||||||
|  |             res = strcmp(string_get_cstr(manufacture_code->name), instance->manufacture_name); | ||||||
|  |             if(res == 0) { | ||||||
|  |                 switch(manufacture_code->type) { | ||||||
|  |                 case KEELOQ_LEARNING_SIMPLE: | ||||||
|  |                     //Simple Learning
 | ||||||
|  |                     hop = subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key); | ||||||
|  |                     break; | ||||||
|  |                 case KEELOQ_LEARNING_NORMAL: | ||||||
|  |                     //Simple Learning
 | ||||||
|  |                     man = | ||||||
|  |                         subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); | ||||||
|  |                     hop = subghz_protocol_keeloq_common_encrypt(decrypt, man); | ||||||
|  |                     break; | ||||||
|  |                 case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1: | ||||||
|  |                     man = subghz_protocol_keeloq_common_magic_xor_type1_learning( | ||||||
|  |                         instance->generic.serial, manufacture_code->key); | ||||||
|  |                     hop = subghz_protocol_keeloq_common_encrypt(decrypt, man); | ||||||
|  |                     break; | ||||||
|  |                 case KEELOQ_LEARNING_UNKNOWN: | ||||||
|  |                     hop = 0; //todo
 | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     if(hop) { | ||||||
|  |         uint64_t yek = (uint64_t)fix << 32 | hop; | ||||||
|  |         instance->generic.data = | ||||||
|  |             subghz_protocol_blocks_reverse_key(yek, instance->generic.data_count_bit); | ||||||
|  |         return true; | ||||||
|  |     } else { | ||||||
|  |         instance->manufacture_name = "Unknown"; | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_keeloq_create_data( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t serial, | ||||||
|  |     uint8_t btn, | ||||||
|  |     uint16_t cnt, | ||||||
|  |     const char* manufacture_name, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderKeeloq* instance = context; | ||||||
|  |     instance->generic.serial = serial; | ||||||
|  |     instance->generic.cnt = cnt; | ||||||
|  |     instance->manufacture_name = manufacture_name; | ||||||
|  |     instance->generic.data_count_bit = 64; | ||||||
|  |     bool res = subghz_protocol_keeloq_gen_data(instance, btn); | ||||||
|  |     if(res) { | ||||||
|  |         res = | ||||||
|  |             subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||||
|  |     } | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool | ||||||
|  |     subghz_protocol_encoder_keeloq_get_upload(SubGhzProtocolEncoderKeeloq* instance, uint8_t btn) { | ||||||
|  |     furi_assert(instance); | ||||||
|  | 
 | ||||||
|  |     //gen new key
 | ||||||
|  |     if(subghz_protocol_keeloq_gen_data(instance, btn)) { | ||||||
|  |         //ToDo Update display data
 | ||||||
|  |         // if(instance->common.callback)
 | ||||||
|  |         //     instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
 | ||||||
|  |     } else { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     size_t index = 0; | ||||||
|  |     size_t size_upload = 11 * 2 + 2 + (instance->generic.data_count_bit * 2) + 4; | ||||||
|  |     if(size_upload > instance->encoder.size_upload) { | ||||||
|  |         FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); | ||||||
|  |         return false; | ||||||
|  |     } else { | ||||||
|  |         instance->encoder.size_upload = size_upload; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //Send header
 | ||||||
|  |     for(uint8_t i = 11; i > 0; i--) { | ||||||
|  |         instance->encoder.upload[index++] = | ||||||
|  |             level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short); | ||||||
|  |         instance->encoder.upload[index++] = | ||||||
|  |             level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_short); | ||||||
|  |     } | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short); | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_short * 10); | ||||||
|  | 
 | ||||||
|  |     //Send key data
 | ||||||
|  |     for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { | ||||||
|  |         if(bit_read(instance->generic.data, i - 1)) { | ||||||
|  |             //send bit 1
 | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short); | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_long); | ||||||
|  |         } else { | ||||||
|  |             //send bit 0
 | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_long); | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_short); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     // +send 2 status bit
 | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short); | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_long); | ||||||
|  |     // send end
 | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short); | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_short * 40); | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderKeeloq* instance = context; | ||||||
|  |     bool res = false; | ||||||
|  |     do { | ||||||
|  |         if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { | ||||||
|  |             FURI_LOG_E(TAG, "Deserialize error"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         subghz_protocol_keeloq_check_remote_controller( | ||||||
|  |             &instance->generic, instance->keystore, &instance->manufacture_name); | ||||||
|  | 
 | ||||||
|  |         if(strcmp(instance->manufacture_name, "DoorHan")) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         //optional parameter parameter
 | ||||||
|  |         flipper_format_read_uint32( | ||||||
|  |             flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); | ||||||
|  | 
 | ||||||
|  |         subghz_protocol_encoder_keeloq_get_upload(instance, instance->generic.btn); | ||||||
|  | 
 | ||||||
|  |         if(!flipper_format_rewind(flipper_format)) { | ||||||
|  |             FURI_LOG_E(TAG, "Rewind error"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         uint8_t key_data[sizeof(uint64_t)] = {0}; | ||||||
|  |         for(size_t i = 0; i < sizeof(uint64_t); i++) { | ||||||
|  |             key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF; | ||||||
|  |         } | ||||||
|  |         if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { | ||||||
|  |             FURI_LOG_E(TAG, "Unable to add Key"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         instance->encoder.is_runing = true; | ||||||
|  | 
 | ||||||
|  |         res = true; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_keeloq_stop(void* context) { | ||||||
|  |     SubGhzProtocolEncoderKeeloq* instance = context; | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | LevelDuration subghz_protocol_encoder_keeloq_yield(void* context) { | ||||||
|  |     SubGhzProtocolEncoderKeeloq* instance = context; | ||||||
|  | 
 | ||||||
|  |     if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { | ||||||
|  |         instance->encoder.is_runing = false; | ||||||
|  |         return level_duration_reset(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LevelDuration ret = instance->encoder.upload[instance->encoder.front]; | ||||||
|  | 
 | ||||||
|  |     if(++instance->encoder.front == instance->encoder.size_upload) { | ||||||
|  |         instance->encoder.repeat--; | ||||||
|  |         instance->encoder.front = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_keeloq_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolDecoderKeeloq* instance = malloc(sizeof(SubGhzProtocolDecoderKeeloq)); | ||||||
|  |     instance->base.protocol = &subghz_protocol_keeloq; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  |     instance->keystore = subghz_environment_get_keystore(environment); | ||||||
|  | 
 | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_keeloq_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderKeeloq* instance = context; | ||||||
|  | 
 | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_keeloq_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderKeeloq* instance = context; | ||||||
|  |     instance->decoder.parser_step = KeeloqDecoderStepReset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderKeeloq* instance = context; | ||||||
|  | 
 | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case KeeloqDecoderStepReset: | ||||||
|  |         if((level) && DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_short) < | ||||||
|  |                           subghz_protocol_keeloq_const.te_delta) { | ||||||
|  |             instance->decoder.parser_step = KeeloqDecoderStepCheckPreambula; | ||||||
|  |             instance->header_count++; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case KeeloqDecoderStepCheckPreambula: | ||||||
|  |         if((!level) && (DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_short) < | ||||||
|  |                         subghz_protocol_keeloq_const.te_delta)) { | ||||||
|  |             instance->decoder.parser_step = KeeloqDecoderStepReset; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if((instance->header_count > 2) && | ||||||
|  |            (DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_short * 10) < | ||||||
|  |             subghz_protocol_keeloq_const.te_delta * 10)) { | ||||||
|  |             // Found header
 | ||||||
|  |             instance->decoder.parser_step = KeeloqDecoderStepSaveDuration; | ||||||
|  |             instance->decoder.decode_data = 0; | ||||||
|  |             instance->decoder.decode_count_bit = 0; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = KeeloqDecoderStepReset; | ||||||
|  |             instance->header_count = 0; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case KeeloqDecoderStepSaveDuration: | ||||||
|  |         if(level) { | ||||||
|  |             instance->decoder.te_last = duration; | ||||||
|  |             instance->decoder.parser_step = KeeloqDecoderStepCheckDuration; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case KeeloqDecoderStepCheckDuration: | ||||||
|  |         if(!level) { | ||||||
|  |             if(duration >= (subghz_protocol_keeloq_const.te_short * 2 + | ||||||
|  |                             subghz_protocol_keeloq_const.te_delta)) { | ||||||
|  |                 // Found end TX
 | ||||||
|  |                 instance->decoder.parser_step = KeeloqDecoderStepReset; | ||||||
|  |                 if(instance->decoder.decode_count_bit >= | ||||||
|  |                    subghz_protocol_keeloq_const.min_count_bit_for_found) { | ||||||
|  |                     if(instance->generic.data != instance->decoder.decode_data) { | ||||||
|  |                         instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                         instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  |                         if(instance->base.callback) | ||||||
|  |                             instance->base.callback(&instance->base, instance->base.context); | ||||||
|  |                     } | ||||||
|  |                     instance->decoder.decode_data = 0; | ||||||
|  |                     instance->decoder.decode_count_bit = 0; | ||||||
|  |                     instance->header_count = 0; | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_keeloq_const.te_short) < | ||||||
|  |                  subghz_protocol_keeloq_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_long) < | ||||||
|  |                  subghz_protocol_keeloq_const.te_delta)) { | ||||||
|  |                 if(instance->decoder.decode_count_bit < | ||||||
|  |                    subghz_protocol_keeloq_const.min_count_bit_for_found) { | ||||||
|  |                     subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                 } | ||||||
|  |                 instance->decoder.parser_step = KeeloqDecoderStepSaveDuration; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_keeloq_const.te_long) < | ||||||
|  |                  subghz_protocol_keeloq_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_short) < | ||||||
|  |                  subghz_protocol_keeloq_const.te_delta)) { | ||||||
|  |                 if(instance->decoder.decode_count_bit < | ||||||
|  |                    subghz_protocol_keeloq_const.min_count_bit_for_found) { | ||||||
|  |                     subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                 } | ||||||
|  |                 instance->decoder.parser_step = KeeloqDecoderStepSaveDuration; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = KeeloqDecoderStepReset; | ||||||
|  |                 instance->header_count = 0; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = KeeloqDecoderStepReset; | ||||||
|  |             instance->header_count = 0; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline bool subghz_protocol_keeloq_check_decrypt( | ||||||
|  |     SubGhzBlockGeneric* instance, | ||||||
|  |     uint32_t decrypt, | ||||||
|  |     uint8_t btn, | ||||||
|  |     uint32_t end_serial) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     if((decrypt >> 28 == btn) && (((((uint16_t)(decrypt >> 16)) & 0xFF) == end_serial) || | ||||||
|  |                                   ((((uint16_t)(decrypt >> 16)) & 0xFF) == 0))) { | ||||||
|  |         instance->cnt = decrypt & 0x0000FFFF; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** Checking the accepted code against the database manafacture key
 | ||||||
|  |  *  | ||||||
|  |  * @param instance SubGhzProtocolKeeloq instance | ||||||
|  |  * @param fix fix part of the parcel | ||||||
|  |  * @param hop hop encrypted part of the parcel | ||||||
|  |  * @return true on successful search | ||||||
|  |  */ | ||||||
|  | static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( | ||||||
|  |     SubGhzBlockGeneric* instance, | ||||||
|  |     uint32_t fix, | ||||||
|  |     uint32_t hop, | ||||||
|  |     SubGhzKeystore* keystore, | ||||||
|  |     const char** manufacture_name) { | ||||||
|  |     // protocol HCS300 uses 10 bits in discriminator, HCS200 uses 8 bits, for backward compatibility, we are looking for the 8-bit pattern
 | ||||||
|  |     // HCS300 -> uint16_t end_serial = (uint16_t)(fix & 0x3FF);
 | ||||||
|  |     // HCS200 -> uint16_t end_serial = (uint16_t)(fix & 0xFF);
 | ||||||
|  | 
 | ||||||
|  |     uint16_t end_serial = (uint16_t)(fix & 0xFF); | ||||||
|  |     uint8_t btn = (uint8_t)(fix >> 28); | ||||||
|  |     uint32_t decrypt = 0; | ||||||
|  |     uint64_t man; | ||||||
|  |     uint32_t seed = 0; | ||||||
|  | 
 | ||||||
|  |     for | ||||||
|  |         M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) { | ||||||
|  |             switch(manufacture_code->type) { | ||||||
|  |             case KEELOQ_LEARNING_SIMPLE: | ||||||
|  |                 // Simple Learning
 | ||||||
|  |                 decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); | ||||||
|  |                 if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { | ||||||
|  |                     *manufacture_name = string_get_cstr(manufacture_code->name); | ||||||
|  |                     return 1; | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             case KEELOQ_LEARNING_NORMAL: | ||||||
|  |                 // Normal Learning
 | ||||||
|  |                 // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
 | ||||||
|  |                 man = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); | ||||||
|  |                 decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); | ||||||
|  |                 if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { | ||||||
|  |                     *manufacture_name = string_get_cstr(manufacture_code->name); | ||||||
|  |                     return 1; | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             case KEELOQ_LEARNING_SECURE: | ||||||
|  |                 man = subghz_protocol_keeloq_common_secure_learning( | ||||||
|  |                     fix, seed, manufacture_code->key); | ||||||
|  |                 decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); | ||||||
|  |                 if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { | ||||||
|  |                     *manufacture_name = string_get_cstr(manufacture_code->name); | ||||||
|  |                     return 1; | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1: | ||||||
|  |                 man = subghz_protocol_keeloq_common_magic_xor_type1_learning( | ||||||
|  |                     fix, manufacture_code->key); | ||||||
|  |                 decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); | ||||||
|  |                 if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { | ||||||
|  |                     *manufacture_name = string_get_cstr(manufacture_code->name); | ||||||
|  |                     return 1; | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             case KEELOQ_LEARNING_UNKNOWN: | ||||||
|  |                 // Simple Learning
 | ||||||
|  |                 decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); | ||||||
|  |                 if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { | ||||||
|  |                     *manufacture_name = string_get_cstr(manufacture_code->name); | ||||||
|  |                     return 1; | ||||||
|  |                 } | ||||||
|  |                 // Check for mirrored man
 | ||||||
|  |                 uint64_t man_rev = 0; | ||||||
|  |                 uint64_t man_rev_byte = 0; | ||||||
|  |                 for(uint8_t i = 0; i < 64; i += 8) { | ||||||
|  |                     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(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { | ||||||
|  |                     *manufacture_name = string_get_cstr(manufacture_code->name); | ||||||
|  |                     return 1; | ||||||
|  |                 } | ||||||
|  |                 //###########################
 | ||||||
|  |                 // Normal Learning
 | ||||||
|  |                 // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
 | ||||||
|  |                 man = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key); | ||||||
|  |                 decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); | ||||||
|  |                 if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { | ||||||
|  |                     *manufacture_name = string_get_cstr(manufacture_code->name); | ||||||
|  |                     return 1; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 // Check for mirrored man
 | ||||||
|  |                 man = subghz_protocol_keeloq_common_normal_learning(fix, man_rev); | ||||||
|  |                 decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); | ||||||
|  |                 if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { | ||||||
|  |                     *manufacture_name = string_get_cstr(manufacture_code->name); | ||||||
|  |                     return 1; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 // Secure Learning
 | ||||||
|  |                 man = subghz_protocol_keeloq_common_secure_learning( | ||||||
|  |                     fix, seed, manufacture_code->key); | ||||||
|  |                 decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); | ||||||
|  |                 if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { | ||||||
|  |                     *manufacture_name = string_get_cstr(manufacture_code->name); | ||||||
|  |                     return 1; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 // Check for mirrored man
 | ||||||
|  |                 man = subghz_protocol_keeloq_common_secure_learning(fix, seed, man_rev); | ||||||
|  |                 decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); | ||||||
|  |                 if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { | ||||||
|  |                     *manufacture_name = string_get_cstr(manufacture_code->name); | ||||||
|  |                     return 1; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 // Magic xor type1 learning
 | ||||||
|  |                 man = subghz_protocol_keeloq_common_magic_xor_type1_learning( | ||||||
|  |                     fix, manufacture_code->key); | ||||||
|  |                 decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); | ||||||
|  |                 if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { | ||||||
|  |                     *manufacture_name = string_get_cstr(manufacture_code->name); | ||||||
|  |                     return 1; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 // Check for mirrored man
 | ||||||
|  |                 man = subghz_protocol_keeloq_common_magic_xor_type1_learning(fix, man_rev); | ||||||
|  |                 decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); | ||||||
|  |                 if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { | ||||||
|  |                     *manufacture_name = string_get_cstr(manufacture_code->name); | ||||||
|  |                     return 1; | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     *manufacture_name = "Unknown"; | ||||||
|  |     instance->cnt = 0; | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** Analysis of received data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance SubGhzProtocolKeeloq instance | ||||||
|  |  */ | ||||||
|  | static void subghz_protocol_keeloq_check_remote_controller( | ||||||
|  |     SubGhzBlockGeneric* instance, | ||||||
|  |     SubGhzKeystore* keystore, | ||||||
|  |     const char** manufacture_name) { | ||||||
|  |     uint64_t key = subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit); | ||||||
|  |     uint32_t key_fix = key >> 32; | ||||||
|  |     uint32_t key_hop = key & 0x00000000ffffffff; | ||||||
|  |     // Check key AN-Motors
 | ||||||
|  |     if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) && | ||||||
|  |        (key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) { | ||||||
|  |         *manufacture_name = "AN-Motors"; | ||||||
|  |         instance->cnt = key_hop >> 16; | ||||||
|  |     } else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) { | ||||||
|  |         *manufacture_name = "HCS101"; | ||||||
|  |         instance->cnt = key_hop >> 16; | ||||||
|  |     } else { | ||||||
|  |         subghz_protocol_keeloq_check_remote_controller_selector( | ||||||
|  |             instance, key_fix, key_hop, keystore, manufacture_name); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     instance->serial = key_fix & 0x0FFFFFFF; | ||||||
|  |     instance->btn = key_fix >> 28; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_keeloq_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderKeeloq* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_keeloq_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderKeeloq* instance = context; | ||||||
|  |     subghz_protocol_keeloq_check_remote_controller( | ||||||
|  |         &instance->generic, instance->keystore, &instance->manufacture_name); | ||||||
|  | 
 | ||||||
|  |     bool res = | ||||||
|  |         subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||||
|  | 
 | ||||||
|  |     if(res && !flipper_format_write_string_cstr( | ||||||
|  |                   flipper_format, "Manufacture", instance->manufacture_name)) { | ||||||
|  |         FURI_LOG_E(TAG, "Unable to add manufacture name"); | ||||||
|  |         res = false; | ||||||
|  |     } | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderKeeloq* instance = context; | ||||||
|  |     bool res = false; | ||||||
|  |     do { | ||||||
|  |         if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { | ||||||
|  |             FURI_LOG_E(TAG, "Deserialize error"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         res = true; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_keeloq_get_string(void* context, string_t output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderKeeloq* instance = context; | ||||||
|  |     subghz_protocol_keeloq_check_remote_controller( | ||||||
|  |         &instance->generic, instance->keystore, &instance->manufacture_name); | ||||||
|  | 
 | ||||||
|  |     uint32_t code_found_hi = instance->generic.data >> 32; | ||||||
|  |     uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key( | ||||||
|  |         instance->generic.data, instance->generic.data_count_bit); | ||||||
|  |     uint32_t code_found_reverse_hi = code_found_reverse >> 32; | ||||||
|  |     uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %dbit\r\n" | ||||||
|  |         "Key:%08lX%08lX\r\n" | ||||||
|  |         "Fix:0x%08lX    Cnt:%04X\r\n" | ||||||
|  |         "Hop:0x%08lX    Btn:%01lX\r\n" | ||||||
|  |         "MF:%s\r\n" | ||||||
|  |         "Sn:0x%07lX \r\n", | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         code_found_hi, | ||||||
|  |         code_found_lo, | ||||||
|  |         code_found_reverse_hi, | ||||||
|  |         instance->generic.cnt, | ||||||
|  |         code_found_reverse_lo, | ||||||
|  |         instance->generic.btn, | ||||||
|  |         instance->manufacture_name, | ||||||
|  |         instance->generic.serial); | ||||||
|  | } | ||||||
							
								
								
									
										39
									
								
								lib/subghz/protocols/keeloq.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								lib/subghz/protocols/keeloq.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "base.h" | ||||||
|  | 
 | ||||||
|  | #define SUBGHZ_PROTOCOL_KEELOQ_NAME "KeeLoq" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzProtocolDecoderKeeloq SubGhzProtocolDecoderKeeloq; | ||||||
|  | typedef struct SubGhzProtocolEncoderKeeloq SubGhzProtocolEncoderKeeloq; | ||||||
|  | 
 | ||||||
|  | extern const SubGhzProtocolDecoder subghz_protocol_keeloq_decoder; | ||||||
|  | extern const SubGhzProtocolEncoder subghz_protocol_keeloq_encoder; | ||||||
|  | extern const SubGhzProtocol subghz_protocol_keeloq; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_keeloq_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_encoder_keeloq_free(void* context); | ||||||
|  | bool subghz_protocol_keeloq_create_data( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t serial, | ||||||
|  |     uint8_t btn, | ||||||
|  |     uint16_t cnt, | ||||||
|  |     const char* manufacture_name, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_encoder_keeloq_stop(void* context); | ||||||
|  | LevelDuration subghz_protocol_encoder_keeloq_yield(void* context); | ||||||
|  | void* subghz_protocol_decoder_keeloq_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_decoder_keeloq_free(void* context); | ||||||
|  | void subghz_protocol_decoder_keeloq_reset(void* context); | ||||||
|  | void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t duration); | ||||||
|  | uint8_t subghz_protocol_decoder_keeloq_get_hash_data(void* context); | ||||||
|  | bool subghz_protocol_decoder_keeloq_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | bool subghz_protocol_decoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_decoder_keeloq_get_string(void* context, string_t output); | ||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "subghz_protocol_keeloq_common.h" | #include "keeloq_common.h" | ||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| @ -8,7 +8,7 @@ | |||||||
| /** Simple Learning Encrypt
 | /** Simple Learning Encrypt
 | ||||||
|  * @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter |  * @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter | ||||||
|  * @param key - manufacture (64bit) |  * @param key - manufacture (64bit) | ||||||
|  * @return keelog encrypt data |  * @return keeloq encrypt data | ||||||
|  */ |  */ | ||||||
| inline uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const uint64_t key) { | inline uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const uint64_t key) { | ||||||
|     uint32_t x = data, r; |     uint32_t x = data, r; | ||||||
| @ -1,6 +1,6 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "subghz_protocol_common.h" | 
 | ||||||
| #include "file_worker.h" | #include "base.h" | ||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| @ -29,12 +29,12 @@ | |||||||
| /** Simple Learning Encrypt
 | /** Simple Learning Encrypt
 | ||||||
|  * @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter |  * @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter | ||||||
|  * @param key - manufacture (64bit) |  * @param key - manufacture (64bit) | ||||||
|  * @return keelog encrypt data |  * @return keeloq encrypt data | ||||||
|  */ |  */ | ||||||
| uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const uint64_t key); | uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const uint64_t key); | ||||||
| 
 | 
 | ||||||
| /** Simple Learning Decrypt
 | /** Simple Learning Decrypt
 | ||||||
|  * @param data - keelog encrypt data |  * @param data - keeloq encrypt data | ||||||
|  * @param key - manufacture (64bit) |  * @param key - manufacture (64bit) | ||||||
|  * @return 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter |  * @return 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter | ||||||
|  */ |  */ | ||||||
							
								
								
									
										268
									
								
								lib/subghz/protocols/kia.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								lib/subghz/protocols/kia.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,268 @@ | |||||||
|  | #include "kia.h" | ||||||
|  | 
 | ||||||
|  | #include "../blocks/const.h" | ||||||
|  | #include "../blocks/decoder.h" | ||||||
|  | #include "../blocks/encoder.h" | ||||||
|  | #include "../blocks/generic.h" | ||||||
|  | #include "../blocks/math.h" | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzProtocoKIA" | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst subghz_protocol_kia_const = { | ||||||
|  |     .te_short = 250, | ||||||
|  |     .te_long = 500, | ||||||
|  |     .te_delta = 100, | ||||||
|  |     .min_count_bit_for_found = 60, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolDecoderKIA { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | 
 | ||||||
|  |     uint16_t header_count; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolEncoderKIA { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     KIADecoderStepReset = 0, | ||||||
|  |     KIADecoderStepCheckPreambula, | ||||||
|  |     KIADecoderStepSaveDuration, | ||||||
|  |     KIADecoderStepCheckDuration, | ||||||
|  | } KIADecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder subghz_protocol_kia_decoder = { | ||||||
|  |     .alloc = subghz_protocol_decoder_kia_alloc, | ||||||
|  |     .free = subghz_protocol_decoder_kia_free, | ||||||
|  | 
 | ||||||
|  |     .feed = subghz_protocol_decoder_kia_feed, | ||||||
|  |     .reset = subghz_protocol_decoder_kia_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = subghz_protocol_decoder_kia_get_hash_data, | ||||||
|  |     .serialize = subghz_protocol_decoder_kia_serialize, | ||||||
|  |     .deserialize = subghz_protocol_decoder_kia_deserialize, | ||||||
|  |     .get_string = subghz_protocol_decoder_kia_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder subghz_protocol_kia_encoder = { | ||||||
|  |     .alloc = NULL, | ||||||
|  |     .free = NULL, | ||||||
|  | 
 | ||||||
|  |     .deserialize = NULL, | ||||||
|  |     .stop = NULL, | ||||||
|  |     .yield = NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol subghz_protocol_kia = { | ||||||
|  |     .name = SUBGHZ_PROTOCOL_KIA_NAME, | ||||||
|  |     .type = SubGhzProtocolTypeDynamic, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable, | ||||||
|  | 
 | ||||||
|  |     .decoder = &subghz_protocol_kia_decoder, | ||||||
|  |     .encoder = &subghz_protocol_kia_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_kia_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolDecoderKIA* instance = malloc(sizeof(SubGhzProtocolDecoderKIA)); | ||||||
|  |     instance->base.protocol = &subghz_protocol_kia; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  | 
 | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_kia_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderKIA* instance = context; | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_kia_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderKIA* instance = context; | ||||||
|  |     instance->decoder.parser_step = KIADecoderStepReset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderKIA* instance = context; | ||||||
|  | 
 | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case KIADecoderStepReset: | ||||||
|  |         if((!level) && (DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) < | ||||||
|  |                         subghz_protocol_kia_const.te_delta)) { | ||||||
|  |             instance->decoder.parser_step = KIADecoderStepCheckPreambula; | ||||||
|  |             instance->decoder.te_last = duration; | ||||||
|  |             instance->header_count = 0; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case KIADecoderStepCheckPreambula: | ||||||
|  |         if(!level) { | ||||||
|  |             if((DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) < | ||||||
|  |                 subghz_protocol_kia_const.te_delta) || | ||||||
|  |                (DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) < | ||||||
|  |                 subghz_protocol_kia_const.te_delta)) { | ||||||
|  |                 instance->decoder.te_last = duration; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = KIADecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else if( | ||||||
|  |             (DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) < | ||||||
|  |              subghz_protocol_kia_const.te_delta) && | ||||||
|  |             (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_short) < | ||||||
|  |              subghz_protocol_kia_const.te_delta)) { | ||||||
|  |             // Found header
 | ||||||
|  |             instance->header_count++; | ||||||
|  |             break; | ||||||
|  |         } else if( | ||||||
|  |             (DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) < | ||||||
|  |              subghz_protocol_kia_const.te_delta) && | ||||||
|  |             (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_long) < | ||||||
|  |              subghz_protocol_kia_const.te_delta)) { | ||||||
|  |             // Found start bit
 | ||||||
|  |             if(instance->header_count > 15) { | ||||||
|  |                 instance->decoder.parser_step = KIADecoderStepSaveDuration; | ||||||
|  |                 instance->decoder.decode_data = 0; | ||||||
|  |                 instance->decoder.decode_count_bit = 1; | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = KIADecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = KIADecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case KIADecoderStepSaveDuration: | ||||||
|  |         if(!level) { | ||||||
|  |             if(duration >= | ||||||
|  |                (subghz_protocol_kia_const.te_long + subghz_protocol_kia_const.te_delta * 2)) { | ||||||
|  |                 //Found stop bit
 | ||||||
|  |                 instance->decoder.parser_step = KIADecoderStepReset; | ||||||
|  |                 if(instance->decoder.decode_count_bit >= | ||||||
|  |                    subghz_protocol_kia_const.min_count_bit_for_found) { | ||||||
|  |                     instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                     instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  |                     if(instance->base.callback) | ||||||
|  |                         instance->base.callback(&instance->base, instance->base.context); | ||||||
|  |                 } | ||||||
|  |                 instance->decoder.decode_data = 0; | ||||||
|  |                 instance->decoder.decode_count_bit = 0; | ||||||
|  |                 break; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.te_last = duration; | ||||||
|  |                 instance->decoder.parser_step = KIADecoderStepCheckDuration; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = KIADecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case KIADecoderStepCheckDuration: | ||||||
|  |         if(level) { | ||||||
|  |             if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_short) < | ||||||
|  |                 subghz_protocol_kia_const.te_delta) && | ||||||
|  |                (DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) < | ||||||
|  |                 subghz_protocol_kia_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                 instance->decoder.parser_step = KIADecoderStepSaveDuration; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_long) < | ||||||
|  |                  subghz_protocol_kia_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) < | ||||||
|  |                  subghz_protocol_kia_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                 instance->decoder.parser_step = KIADecoderStepSaveDuration; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = KIADecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = KIADecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_kia_crc8(uint8_t* data, size_t len) { | ||||||
|  |     uint8_t crc = 0x08; | ||||||
|  |     size_t i, j; | ||||||
|  |     for(i = 0; i < len; i++) { | ||||||
|  |         crc ^= data[i]; | ||||||
|  |         for(j = 0; j < 8; j++) { | ||||||
|  |             if((crc & 0x80) != 0) | ||||||
|  |                 crc = (uint8_t)((crc << 1) ^ 0x7F); | ||||||
|  |             else | ||||||
|  |                 crc <<= 1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return crc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** Analysis of received data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance SubGhzProtocolKIA instance | ||||||
|  |  */ | ||||||
|  | static void subghz_protocol_kia_check_remote_controller(SubGhzBlockGeneric* instance) { | ||||||
|  |     /*
 | ||||||
|  |     *   0x0F 0112 43B04EC 1 7D | ||||||
|  |     *   0x0F 0113 43B04EC 1 DF | ||||||
|  |     *   0x0F 0114 43B04EC 1 30 | ||||||
|  |     *   0x0F 0115 43B04EC 2 13 | ||||||
|  |     *   0x0F 0116 43B04EC 3 F5 | ||||||
|  |     *         CNT  Serial K CRC8 Kia (CRC8, poly 0x7f, start_crc 0x08) | ||||||
|  |     */ | ||||||
|  | 
 | ||||||
|  |     instance->serial = (uint32_t)((instance->data >> 12) & 0x0FFFFFFF); | ||||||
|  |     instance->btn = (instance->data >> 8) & 0x0F; | ||||||
|  |     instance->cnt = (instance->data >> 40) & 0xFFFF; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_kia_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderKIA* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_kia_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderKIA* instance = context; | ||||||
|  |     return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderKIA* instance = context; | ||||||
|  |     return subghz_block_generic_deserialize(&instance->generic, flipper_format); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_kia_get_string(void* context, string_t output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderKIA* instance = context; | ||||||
|  | 
 | ||||||
|  |     subghz_protocol_kia_check_remote_controller(&instance->generic); | ||||||
|  |     uint32_t code_found_hi = instance->generic.data >> 32; | ||||||
|  |     uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %dbit\r\n" | ||||||
|  |         "Key:%08lX%08lX\r\n" | ||||||
|  |         "Sn:%07lX Btn:%lX Cnt:%04X\r\n", | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         code_found_hi, | ||||||
|  |         code_found_lo, | ||||||
|  |         instance->generic.serial, | ||||||
|  |         instance->generic.btn, | ||||||
|  |         instance->generic.cnt); | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								lib/subghz/protocols/kia.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/subghz/protocols/kia.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "base.h" | ||||||
|  | 
 | ||||||
|  | #define SUBGHZ_PROTOCOL_KIA_NAME "KIA Seed" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzProtocolDecoderKIA SubGhzProtocolDecoderKIA; | ||||||
|  | typedef struct SubGhzProtocolEncoderKIA SubGhzProtocolEncoderKIA; | ||||||
|  | 
 | ||||||
|  | extern const SubGhzProtocolDecoder subghz_protocol_kia_decoder; | ||||||
|  | extern const SubGhzProtocolEncoder subghz_protocol_kia_encoder; | ||||||
|  | extern const SubGhzProtocol subghz_protocol_kia; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_kia_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_decoder_kia_free(void* context); | ||||||
|  | void subghz_protocol_decoder_kia_reset(void* context); | ||||||
|  | void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t duration); | ||||||
|  | uint8_t subghz_protocol_decoder_kia_get_hash_data(void* context); | ||||||
|  | bool subghz_protocol_decoder_kia_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | bool subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_decoder_kia_get_string(void* context, string_t output); | ||||||
							
								
								
									
										375
									
								
								lib/subghz/protocols/nero_radio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										375
									
								
								lib/subghz/protocols/nero_radio.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,375 @@ | |||||||
|  | #include "nero_radio.h" | ||||||
|  | 
 | ||||||
|  | #include "../blocks/const.h" | ||||||
|  | #include "../blocks/decoder.h" | ||||||
|  | #include "../blocks/encoder.h" | ||||||
|  | #include "../blocks/generic.h" | ||||||
|  | #include "../blocks/math.h" | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzProtocolNeroRadio" | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst subghz_protocol_nero_radio_const = { | ||||||
|  |     .te_short = 200, | ||||||
|  |     .te_long = 400, | ||||||
|  |     .te_delta = 80, | ||||||
|  |     .min_count_bit_for_found = 56, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolDecoderNeroRadio { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | 
 | ||||||
|  |     uint16_t header_count; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolEncoderNeroRadio { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     NeroRadioDecoderStepReset = 0, | ||||||
|  |     NeroRadioDecoderStepCheckPreambula, | ||||||
|  |     NeroRadioDecoderStepSaveDuration, | ||||||
|  |     NeroRadioDecoderStepCheckDuration, | ||||||
|  | } NeroRadioDecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder subghz_protocol_nero_radio_decoder = { | ||||||
|  |     .alloc = subghz_protocol_decoder_nero_radio_alloc, | ||||||
|  |     .free = subghz_protocol_decoder_nero_radio_free, | ||||||
|  | 
 | ||||||
|  |     .feed = subghz_protocol_decoder_nero_radio_feed, | ||||||
|  |     .reset = subghz_protocol_decoder_nero_radio_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = subghz_protocol_decoder_nero_radio_get_hash_data, | ||||||
|  |     .serialize = subghz_protocol_decoder_nero_radio_serialize, | ||||||
|  |     .deserialize = subghz_protocol_decoder_nero_radio_deserialize, | ||||||
|  |     .get_string = subghz_protocol_decoder_nero_radio_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder subghz_protocol_nero_radio_encoder = { | ||||||
|  |     .alloc = subghz_protocol_encoder_nero_radio_alloc, | ||||||
|  |     .free = subghz_protocol_encoder_nero_radio_free, | ||||||
|  | 
 | ||||||
|  |     .deserialize = subghz_protocol_encoder_nero_radio_deserialize, | ||||||
|  |     .stop = subghz_protocol_encoder_nero_radio_stop, | ||||||
|  |     .yield = subghz_protocol_encoder_nero_radio_yield, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol subghz_protocol_nero_radio = { | ||||||
|  |     .name = SUBGHZ_PROTOCOL_NERO_RADIO_NAME, | ||||||
|  |     .type = SubGhzProtocolTypeStatic, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | | ||||||
|  |             SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, | ||||||
|  | 
 | ||||||
|  |     .decoder = &subghz_protocol_nero_radio_decoder, | ||||||
|  |     .encoder = &subghz_protocol_nero_radio_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_nero_radio_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolEncoderNeroRadio* instance = malloc(sizeof(SubGhzProtocolEncoderNeroRadio)); | ||||||
|  | 
 | ||||||
|  |     instance->base.protocol = &subghz_protocol_nero_radio; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  | 
 | ||||||
|  |     instance->encoder.repeat = 10; | ||||||
|  |     instance->encoder.size_upload = 256; | ||||||
|  |     instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_nero_radio_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderNeroRadio* instance = context; | ||||||
|  |     free(instance->encoder.upload); | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool | ||||||
|  |     subghz_protocol_encoder_nero_radio_get_upload(SubGhzProtocolEncoderNeroRadio* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     size_t index = 0; | ||||||
|  |     size_t size_upload = 49 * 2 + 2 + (instance->generic.data_count_bit * 2); | ||||||
|  |     if(size_upload > instance->encoder.size_upload) { | ||||||
|  |         FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); | ||||||
|  |         return false; | ||||||
|  |     } else { | ||||||
|  |         instance->encoder.size_upload = size_upload; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //Send header
 | ||||||
|  |     for(uint8_t i = 0; i < 49; i++) { | ||||||
|  |         instance->encoder.upload[index++] = | ||||||
|  |             level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_short); | ||||||
|  |         instance->encoder.upload[index++] = | ||||||
|  |             level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //Send start bit
 | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_short * 4); | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short); | ||||||
|  | 
 | ||||||
|  |     //Send key data
 | ||||||
|  |     for(uint8_t i = instance->generic.data_count_bit; i > 1; i--) { | ||||||
|  |         if(bit_read(instance->generic.data, i - 1)) { | ||||||
|  |             //send bit 1
 | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_long); | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short); | ||||||
|  |         } else { | ||||||
|  |             //send bit 0
 | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_short); | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_long); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if(bit_read(instance->generic.data, 0)) { | ||||||
|  |         //send bit 1
 | ||||||
|  |         instance->encoder.upload[index++] = | ||||||
|  |             level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_long); | ||||||
|  |         instance->encoder.upload[index++] = | ||||||
|  |             level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short * 37); | ||||||
|  |     } else { | ||||||
|  |         //send bit 0
 | ||||||
|  |         instance->encoder.upload[index++] = | ||||||
|  |             level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_short); | ||||||
|  |         instance->encoder.upload[index++] = | ||||||
|  |             level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short * 37); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_encoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderNeroRadio* instance = context; | ||||||
|  |     bool res = false; | ||||||
|  |     do { | ||||||
|  |         if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { | ||||||
|  |             FURI_LOG_E(TAG, "Deserialize error"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         //optional parameter parameter
 | ||||||
|  |         flipper_format_read_uint32( | ||||||
|  |             flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); | ||||||
|  | 
 | ||||||
|  |         subghz_protocol_encoder_nero_radio_get_upload(instance); | ||||||
|  |         instance->encoder.is_runing = true; | ||||||
|  | 
 | ||||||
|  |         res = true; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_nero_radio_stop(void* context) { | ||||||
|  |     SubGhzProtocolEncoderNeroRadio* instance = context; | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | LevelDuration subghz_protocol_encoder_nero_radio_yield(void* context) { | ||||||
|  |     SubGhzProtocolEncoderNeroRadio* instance = context; | ||||||
|  | 
 | ||||||
|  |     if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { | ||||||
|  |         instance->encoder.is_runing = false; | ||||||
|  |         return level_duration_reset(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LevelDuration ret = instance->encoder.upload[instance->encoder.front]; | ||||||
|  | 
 | ||||||
|  |     if(++instance->encoder.front == instance->encoder.size_upload) { | ||||||
|  |         instance->encoder.repeat--; | ||||||
|  |         instance->encoder.front = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_nero_radio_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolDecoderNeroRadio* instance = malloc(sizeof(SubGhzProtocolDecoderNeroRadio)); | ||||||
|  |     instance->base.protocol = &subghz_protocol_nero_radio; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nero_radio_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNeroRadio* instance = context; | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nero_radio_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNeroRadio* instance = context; | ||||||
|  |     instance->decoder.parser_step = NeroRadioDecoderStepReset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nero_radio_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNeroRadio* instance = context; | ||||||
|  | 
 | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case NeroRadioDecoderStepReset: | ||||||
|  |         if((level) && (DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short) < | ||||||
|  |                        subghz_protocol_nero_radio_const.te_delta)) { | ||||||
|  |             instance->decoder.parser_step = NeroRadioDecoderStepCheckPreambula; | ||||||
|  |             instance->decoder.te_last = duration; | ||||||
|  |             instance->header_count = 0; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case NeroRadioDecoderStepCheckPreambula: | ||||||
|  |         if(level) { | ||||||
|  |             if((DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short) < | ||||||
|  |                 subghz_protocol_nero_radio_const.te_delta) || | ||||||
|  |                (DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short * 4) < | ||||||
|  |                 subghz_protocol_nero_radio_const.te_delta)) { | ||||||
|  |                 instance->decoder.te_last = duration; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = NeroRadioDecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else if( | ||||||
|  |             DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short) < | ||||||
|  |             subghz_protocol_nero_radio_const.te_delta) { | ||||||
|  |             if(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_nero_radio_const.te_short) < | ||||||
|  |                subghz_protocol_nero_radio_const.te_delta) { | ||||||
|  |                 // Found header
 | ||||||
|  |                 instance->header_count++; | ||||||
|  |                 break; | ||||||
|  |             } else if( | ||||||
|  |                 DURATION_DIFF( | ||||||
|  |                     instance->decoder.te_last, subghz_protocol_nero_radio_const.te_short * 4) < | ||||||
|  |                 subghz_protocol_nero_radio_const.te_delta) { | ||||||
|  |                 // Found start bit
 | ||||||
|  |                 if(instance->header_count > 40) { | ||||||
|  |                     instance->decoder.parser_step = NeroRadioDecoderStepSaveDuration; | ||||||
|  |                     instance->decoder.decode_data = 0; | ||||||
|  |                     instance->decoder.decode_count_bit = 0; | ||||||
|  |                 } else { | ||||||
|  |                     instance->decoder.parser_step = NeroRadioDecoderStepReset; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = NeroRadioDecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = NeroRadioDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case NeroRadioDecoderStepSaveDuration: | ||||||
|  |         if(level) { | ||||||
|  |             instance->decoder.te_last = duration; | ||||||
|  |             instance->decoder.parser_step = NeroRadioDecoderStepCheckDuration; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = NeroRadioDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case NeroRadioDecoderStepCheckDuration: | ||||||
|  |         if(!level) { | ||||||
|  |             if(duration >= (subghz_protocol_nero_radio_const.te_short * 10 + | ||||||
|  |                             subghz_protocol_nero_radio_const.te_delta * 2)) { | ||||||
|  |                 //Found stop bit
 | ||||||
|  |                 if(DURATION_DIFF( | ||||||
|  |                        instance->decoder.te_last, subghz_protocol_nero_radio_const.te_short) < | ||||||
|  |                    subghz_protocol_nero_radio_const.te_delta) { | ||||||
|  |                     subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                 } else if( | ||||||
|  |                     DURATION_DIFF( | ||||||
|  |                         instance->decoder.te_last, subghz_protocol_nero_radio_const.te_long) < | ||||||
|  |                     subghz_protocol_nero_radio_const.te_delta) { | ||||||
|  |                     subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                 } | ||||||
|  |                 instance->decoder.parser_step = NeroRadioDecoderStepReset; | ||||||
|  |                 if(instance->decoder.decode_count_bit >= | ||||||
|  |                    subghz_protocol_nero_radio_const.min_count_bit_for_found) { | ||||||
|  |                     instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                     instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  | 
 | ||||||
|  |                     if(instance->base.callback) | ||||||
|  |                         instance->base.callback(&instance->base, instance->base.context); | ||||||
|  |                 } | ||||||
|  |                 instance->decoder.decode_data = 0; | ||||||
|  |                 instance->decoder.decode_count_bit = 0; | ||||||
|  |                 instance->decoder.parser_step = NeroRadioDecoderStepReset; | ||||||
|  |                 break; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF( | ||||||
|  |                      instance->decoder.te_last, subghz_protocol_nero_radio_const.te_short) < | ||||||
|  |                  subghz_protocol_nero_radio_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_long) < | ||||||
|  |                  subghz_protocol_nero_radio_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                 instance->decoder.parser_step = NeroRadioDecoderStepSaveDuration; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF( | ||||||
|  |                      instance->decoder.te_last, subghz_protocol_nero_radio_const.te_long) < | ||||||
|  |                  subghz_protocol_nero_radio_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short) < | ||||||
|  |                  subghz_protocol_nero_radio_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                 instance->decoder.parser_step = NeroRadioDecoderStepSaveDuration; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = NeroRadioDecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = NeroRadioDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_nero_radio_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNeroRadio* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_nero_radio_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNeroRadio* instance = context; | ||||||
|  |     return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNeroRadio* instance = context; | ||||||
|  |     return subghz_block_generic_deserialize(&instance->generic, flipper_format); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nero_radio_get_string(void* context, string_t output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNeroRadio* instance = context; | ||||||
|  | 
 | ||||||
|  |     uint32_t code_found_hi = instance->generic.data >> 32; | ||||||
|  |     uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key( | ||||||
|  |         instance->generic.data, instance->generic.data_count_bit); | ||||||
|  | 
 | ||||||
|  |     uint32_t code_found_reverse_hi = code_found_reverse >> 32; | ||||||
|  |     uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %dbit\r\n" | ||||||
|  |         "Key:0x%lX%08lX\r\n" | ||||||
|  |         "Yek:0x%lX%08lX\r\n", | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         code_found_hi, | ||||||
|  |         code_found_lo, | ||||||
|  |         code_found_reverse_hi, | ||||||
|  |         code_found_reverse_lo); | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								lib/subghz/protocols/nero_radio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								lib/subghz/protocols/nero_radio.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "base.h" | ||||||
|  | 
 | ||||||
|  | #define SUBGHZ_PROTOCOL_NERO_RADIO_NAME "Nero Radio" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzProtocolDecoderNeroRadio SubGhzProtocolDecoderNeroRadio; | ||||||
|  | typedef struct SubGhzProtocolEncoderNeroRadio SubGhzProtocolEncoderNeroRadio; | ||||||
|  | 
 | ||||||
|  | extern const SubGhzProtocolDecoder subghz_protocol_nero_radio_decoder; | ||||||
|  | extern const SubGhzProtocolEncoder subghz_protocol_nero_radio_encoder; | ||||||
|  | extern const SubGhzProtocol subghz_protocol_nero_radio; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_nero_radio_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_encoder_nero_radio_free(void* context); | ||||||
|  | bool subghz_protocol_encoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_encoder_nero_radio_stop(void* context); | ||||||
|  | LevelDuration subghz_protocol_encoder_nero_radio_yield(void* context); | ||||||
|  | void* subghz_protocol_decoder_nero_radio_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_decoder_nero_radio_free(void* context); | ||||||
|  | void subghz_protocol_decoder_nero_radio_reset(void* context); | ||||||
|  | void subghz_protocol_decoder_nero_radio_feed(void* context, bool level, uint32_t duration); | ||||||
|  | uint8_t subghz_protocol_decoder_nero_radio_get_hash_data(void* context); | ||||||
|  | bool subghz_protocol_decoder_nero_radio_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | bool subghz_protocol_decoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_decoder_nero_radio_get_string(void* context, string_t output); | ||||||
							
								
								
									
										366
									
								
								lib/subghz/protocols/nero_sketch.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										366
									
								
								lib/subghz/protocols/nero_sketch.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,366 @@ | |||||||
|  | #include "nero_sketch.h" | ||||||
|  | 
 | ||||||
|  | #include "../blocks/const.h" | ||||||
|  | #include "../blocks/decoder.h" | ||||||
|  | #include "../blocks/encoder.h" | ||||||
|  | #include "../blocks/generic.h" | ||||||
|  | #include "../blocks/math.h" | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Help | ||||||
|  |  * https://phreakerclub.com/447
 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzProtocolNeroSketch" | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst subghz_protocol_nero_sketch_const = { | ||||||
|  |     .te_short = 330, | ||||||
|  |     .te_long = 660, | ||||||
|  |     .te_delta = 150, | ||||||
|  |     .min_count_bit_for_found = 40, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolDecoderNeroSketch { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  |     uint16_t header_count; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolEncoderNeroSketch { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     NeroSketchDecoderStepReset = 0, | ||||||
|  |     NeroSketchDecoderStepCheckPreambula, | ||||||
|  |     NeroSketchDecoderStepSaveDuration, | ||||||
|  |     NeroSketchDecoderStepCheckDuration, | ||||||
|  | } NeroSketchDecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder subghz_protocol_nero_sketch_decoder = { | ||||||
|  |     .alloc = subghz_protocol_decoder_nero_sketch_alloc, | ||||||
|  |     .free = subghz_protocol_decoder_nero_sketch_free, | ||||||
|  | 
 | ||||||
|  |     .feed = subghz_protocol_decoder_nero_sketch_feed, | ||||||
|  |     .reset = subghz_protocol_decoder_nero_sketch_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = subghz_protocol_decoder_nero_sketch_get_hash_data, | ||||||
|  |     .serialize = subghz_protocol_decoder_nero_sketch_serialize, | ||||||
|  |     .deserialize = subghz_protocol_decoder_nero_sketch_deserialize, | ||||||
|  |     .get_string = subghz_protocol_decoder_nero_sketch_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder subghz_protocol_nero_sketch_encoder = { | ||||||
|  |     .alloc = subghz_protocol_encoder_nero_sketch_alloc, | ||||||
|  |     .free = subghz_protocol_encoder_nero_sketch_free, | ||||||
|  | 
 | ||||||
|  |     .deserialize = subghz_protocol_encoder_nero_sketch_deserialize, | ||||||
|  |     .stop = subghz_protocol_encoder_nero_sketch_stop, | ||||||
|  |     .yield = subghz_protocol_encoder_nero_sketch_yield, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol subghz_protocol_nero_sketch = { | ||||||
|  |     .name = SUBGHZ_PROTOCOL_NERO_SKETCH_NAME, | ||||||
|  |     .type = SubGhzProtocolTypeStatic, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | | ||||||
|  |             SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, | ||||||
|  | 
 | ||||||
|  |     .decoder = &subghz_protocol_nero_sketch_decoder, | ||||||
|  |     .encoder = &subghz_protocol_nero_sketch_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_nero_sketch_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolEncoderNeroSketch* instance = malloc(sizeof(SubGhzProtocolEncoderNeroSketch)); | ||||||
|  | 
 | ||||||
|  |     instance->base.protocol = &subghz_protocol_nero_sketch; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  | 
 | ||||||
|  |     instance->encoder.repeat = 10; | ||||||
|  |     instance->encoder.size_upload = 256; | ||||||
|  |     instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_nero_sketch_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderNeroSketch* instance = context; | ||||||
|  |     free(instance->encoder.upload); | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool | ||||||
|  |     subghz_protocol_encoder_nero_sketch_get_upload(SubGhzProtocolEncoderNeroSketch* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  | 
 | ||||||
|  |     size_t index = 0; | ||||||
|  |     size_t size_upload = 47 * 2 + 2 + (instance->generic.data_count_bit * 2) + 2; | ||||||
|  |     if(size_upload > instance->encoder.size_upload) { | ||||||
|  |         FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); | ||||||
|  |         return false; | ||||||
|  |     } else { | ||||||
|  |         instance->encoder.size_upload = size_upload; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //Send header
 | ||||||
|  |     for(uint8_t i = 0; i < 47; i++) { | ||||||
|  |         instance->encoder.upload[index++] = | ||||||
|  |             level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_short); | ||||||
|  |         instance->encoder.upload[index++] = | ||||||
|  |             level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_short); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //Send start bit
 | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_short * 4); | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_short); | ||||||
|  | 
 | ||||||
|  |     //Send key data
 | ||||||
|  |     for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { | ||||||
|  |         if(bit_read(instance->generic.data, i - 1)) { | ||||||
|  |             //send bit 1
 | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_long); | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_short); | ||||||
|  |         } else { | ||||||
|  |             //send bit 0
 | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_short); | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_long); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //Send stop bit
 | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_short * 3); | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_short); | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_encoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderNeroSketch* instance = context; | ||||||
|  |     bool res = false; | ||||||
|  |     do { | ||||||
|  |         if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { | ||||||
|  |             FURI_LOG_E(TAG, "Deserialize error"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         //optional parameter parameter
 | ||||||
|  |         flipper_format_read_uint32( | ||||||
|  |             flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); | ||||||
|  | 
 | ||||||
|  |         subghz_protocol_encoder_nero_sketch_get_upload(instance); | ||||||
|  |         instance->encoder.is_runing = true; | ||||||
|  | 
 | ||||||
|  |         res = true; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_nero_sketch_stop(void* context) { | ||||||
|  |     SubGhzProtocolEncoderNeroSketch* instance = context; | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | LevelDuration subghz_protocol_encoder_nero_sketch_yield(void* context) { | ||||||
|  |     SubGhzProtocolEncoderNeroSketch* instance = context; | ||||||
|  | 
 | ||||||
|  |     if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { | ||||||
|  |         instance->encoder.is_runing = false; | ||||||
|  |         return level_duration_reset(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LevelDuration ret = instance->encoder.upload[instance->encoder.front]; | ||||||
|  | 
 | ||||||
|  |     if(++instance->encoder.front == instance->encoder.size_upload) { | ||||||
|  |         instance->encoder.repeat--; | ||||||
|  |         instance->encoder.front = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_nero_sketch_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolDecoderNeroSketch* instance = malloc(sizeof(SubGhzProtocolDecoderNeroSketch)); | ||||||
|  |     instance->base.protocol = &subghz_protocol_nero_sketch; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nero_sketch_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNeroSketch* instance = context; | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nero_sketch_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNeroSketch* instance = context; | ||||||
|  |     instance->decoder.parser_step = NeroSketchDecoderStepReset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nero_sketch_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNeroSketch* instance = context; | ||||||
|  | 
 | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case NeroSketchDecoderStepReset: | ||||||
|  |         if((level) && (DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short) < | ||||||
|  |                        subghz_protocol_nero_sketch_const.te_delta)) { | ||||||
|  |             instance->decoder.parser_step = NeroSketchDecoderStepCheckPreambula; | ||||||
|  |             instance->decoder.te_last = duration; | ||||||
|  |             instance->header_count = 0; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case NeroSketchDecoderStepCheckPreambula: | ||||||
|  |         if(level) { | ||||||
|  |             if((DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short) < | ||||||
|  |                 subghz_protocol_nero_sketch_const.te_delta) || | ||||||
|  |                (DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short * 4) < | ||||||
|  |                 subghz_protocol_nero_sketch_const.te_delta)) { | ||||||
|  |                 instance->decoder.te_last = duration; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = NeroSketchDecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else if( | ||||||
|  |             DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short) < | ||||||
|  |             subghz_protocol_nero_sketch_const.te_delta) { | ||||||
|  |             if(DURATION_DIFF( | ||||||
|  |                    instance->decoder.te_last, subghz_protocol_nero_sketch_const.te_short) < | ||||||
|  |                subghz_protocol_nero_sketch_const.te_delta) { | ||||||
|  |                 // Found header
 | ||||||
|  |                 instance->header_count++; | ||||||
|  |                 break; | ||||||
|  |             } else if( | ||||||
|  |                 DURATION_DIFF( | ||||||
|  |                     instance->decoder.te_last, subghz_protocol_nero_sketch_const.te_short * 4) < | ||||||
|  |                 subghz_protocol_nero_sketch_const.te_delta) { | ||||||
|  |                 // Found start bit
 | ||||||
|  |                 if(instance->header_count > 40) { | ||||||
|  |                     instance->decoder.parser_step = NeroSketchDecoderStepSaveDuration; | ||||||
|  |                     instance->decoder.decode_data = 0; | ||||||
|  |                     instance->decoder.decode_count_bit = 0; | ||||||
|  |                 } else { | ||||||
|  |                     instance->decoder.parser_step = NeroSketchDecoderStepReset; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = NeroSketchDecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = NeroSketchDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case NeroSketchDecoderStepSaveDuration: | ||||||
|  |         if(level) { | ||||||
|  |             if(duration >= (subghz_protocol_nero_sketch_const.te_short * 2 + | ||||||
|  |                             subghz_protocol_nero_sketch_const.te_delta * 2)) { | ||||||
|  |                 //Found stop bit
 | ||||||
|  |                 instance->decoder.parser_step = NeroSketchDecoderStepReset; | ||||||
|  |                 if(instance->decoder.decode_count_bit >= | ||||||
|  |                    subghz_protocol_nero_sketch_const.min_count_bit_for_found) { | ||||||
|  |                     instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                     instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  |                     if(instance->base.callback) | ||||||
|  |                         instance->base.callback(&instance->base, instance->base.context); | ||||||
|  |                 } | ||||||
|  |                 instance->decoder.decode_data = 0; | ||||||
|  |                 instance->decoder.decode_count_bit = 0; | ||||||
|  |                 break; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.te_last = duration; | ||||||
|  |                 instance->decoder.parser_step = NeroSketchDecoderStepCheckDuration; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = NeroSketchDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case NeroSketchDecoderStepCheckDuration: | ||||||
|  |         if(!level) { | ||||||
|  |             if((DURATION_DIFF( | ||||||
|  |                     instance->decoder.te_last, subghz_protocol_nero_sketch_const.te_short) < | ||||||
|  |                 subghz_protocol_nero_sketch_const.te_delta) && | ||||||
|  |                (DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_long) < | ||||||
|  |                 subghz_protocol_nero_sketch_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                 instance->decoder.parser_step = NeroSketchDecoderStepSaveDuration; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF( | ||||||
|  |                      instance->decoder.te_last, subghz_protocol_nero_sketch_const.te_long) < | ||||||
|  |                  subghz_protocol_nero_sketch_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short) < | ||||||
|  |                  subghz_protocol_nero_sketch_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                 instance->decoder.parser_step = NeroSketchDecoderStepSaveDuration; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = NeroSketchDecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = NeroSketchDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_nero_sketch_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNeroSketch* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_nero_sketch_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNeroSketch* instance = context; | ||||||
|  |     return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNeroSketch* instance = context; | ||||||
|  |     return subghz_block_generic_deserialize(&instance->generic, flipper_format); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nero_sketch_get_string(void* context, string_t output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNeroSketch* instance = context; | ||||||
|  | 
 | ||||||
|  |     uint32_t code_found_hi = instance->generic.data >> 32; | ||||||
|  |     uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key( | ||||||
|  |         instance->generic.data, instance->generic.data_count_bit); | ||||||
|  | 
 | ||||||
|  |     uint32_t code_found_reverse_hi = code_found_reverse >> 32; | ||||||
|  |     uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %dbit\r\n" | ||||||
|  |         "Key:0x%lX%08lX\r\n" | ||||||
|  |         "Yek:0x%lX%08lX\r\n", | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         code_found_hi, | ||||||
|  |         code_found_lo, | ||||||
|  |         code_found_reverse_hi, | ||||||
|  |         code_found_reverse_lo); | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								lib/subghz/protocols/nero_sketch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								lib/subghz/protocols/nero_sketch.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "base.h" | ||||||
|  | 
 | ||||||
|  | #define SUBGHZ_PROTOCOL_NERO_SKETCH_NAME "Nero Sketch" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzProtocolDecoderNeroSketch SubGhzProtocolDecoderNeroSketch; | ||||||
|  | typedef struct SubGhzProtocolEncoderNeroSketch SubGhzProtocolEncoderNeroSketch; | ||||||
|  | 
 | ||||||
|  | extern const SubGhzProtocolDecoder subghz_protocol_nero_sketch_decoder; | ||||||
|  | extern const SubGhzProtocolEncoder subghz_protocol_nero_sketch_encoder; | ||||||
|  | extern const SubGhzProtocol subghz_protocol_nero_sketch; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_nero_sketch_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_encoder_nero_sketch_free(void* context); | ||||||
|  | bool subghz_protocol_encoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_encoder_nero_sketch_stop(void* context); | ||||||
|  | LevelDuration subghz_protocol_encoder_nero_sketch_yield(void* context); | ||||||
|  | void* subghz_protocol_decoder_nero_sketch_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_decoder_nero_sketch_free(void* context); | ||||||
|  | void subghz_protocol_decoder_nero_sketch_reset(void* context); | ||||||
|  | void subghz_protocol_decoder_nero_sketch_feed(void* context, bool level, uint32_t duration); | ||||||
|  | uint8_t subghz_protocol_decoder_nero_sketch_get_hash_data(void* context); | ||||||
|  | bool subghz_protocol_decoder_nero_sketch_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | bool subghz_protocol_decoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_decoder_nero_sketch_get_string(void* context, string_t output); | ||||||
							
								
								
									
										310
									
								
								lib/subghz/protocols/nice_flo.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										310
									
								
								lib/subghz/protocols/nice_flo.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,310 @@ | |||||||
|  | #include "nice_flo.h" | ||||||
|  | #include "../blocks/const.h" | ||||||
|  | #include "../blocks/decoder.h" | ||||||
|  | #include "../blocks/encoder.h" | ||||||
|  | #include "../blocks/generic.h" | ||||||
|  | #include "../blocks/math.h" | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Help | ||||||
|  |  * https://phreakerclub.com/447
 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzProtocolNiceFLO" | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst subghz_protocol_nice_flo_const = { | ||||||
|  |     .te_short = 700, | ||||||
|  |     .te_long = 1400, | ||||||
|  |     .te_delta = 200, | ||||||
|  |     .min_count_bit_for_found = 12, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolDecoderNiceFlo { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolEncoderNiceFlo { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     NiceFloDecoderStepReset = 0, | ||||||
|  |     NiceFloDecoderStepFoundStartBit, | ||||||
|  |     NiceFloDecoderStepSaveDuration, | ||||||
|  |     NiceFloDecoderStepCheckDuration, | ||||||
|  | } NiceFloDecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder subghz_protocol_nice_flo_decoder = { | ||||||
|  |     .alloc = subghz_protocol_decoder_nice_flo_alloc, | ||||||
|  |     .free = subghz_protocol_decoder_nice_flo_free, | ||||||
|  | 
 | ||||||
|  |     .feed = subghz_protocol_decoder_nice_flo_feed, | ||||||
|  |     .reset = subghz_protocol_decoder_nice_flo_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = subghz_protocol_decoder_nice_flo_get_hash_data, | ||||||
|  |     .serialize = subghz_protocol_decoder_nice_flo_serialize, | ||||||
|  |     .deserialize = subghz_protocol_decoder_nice_flo_deserialize, | ||||||
|  |     .get_string = subghz_protocol_decoder_nice_flo_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder subghz_protocol_nice_flo_encoder = { | ||||||
|  |     .alloc = subghz_protocol_encoder_nice_flo_alloc, | ||||||
|  |     .free = subghz_protocol_encoder_nice_flo_free, | ||||||
|  | 
 | ||||||
|  |     .deserialize = subghz_protocol_encoder_nice_flo_deserialize, | ||||||
|  |     .stop = subghz_protocol_encoder_nice_flo_stop, | ||||||
|  |     .yield = subghz_protocol_encoder_nice_flo_yield, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol subghz_protocol_nice_flo = { | ||||||
|  |     .name = SUBGHZ_PROTOCOL_NICE_FLO_NAME, | ||||||
|  |     .type = SubGhzProtocolTypeStatic, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_AM | | ||||||
|  |             SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | | ||||||
|  |             SubGhzProtocolFlag_Send, | ||||||
|  | 
 | ||||||
|  |     .decoder = &subghz_protocol_nice_flo_decoder, | ||||||
|  |     .encoder = &subghz_protocol_nice_flo_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_nice_flo_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolEncoderNiceFlo* instance = malloc(sizeof(SubGhzProtocolEncoderNiceFlo)); | ||||||
|  | 
 | ||||||
|  |     instance->base.protocol = &subghz_protocol_nice_flo; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  | 
 | ||||||
|  |     instance->encoder.repeat = 10; | ||||||
|  |     instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop)
 | ||||||
|  |     instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_nice_flo_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderNiceFlo* instance = context; | ||||||
|  |     free(instance->encoder.upload); | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool subghz_protocol_encoder_nice_flo_get_upload(SubGhzProtocolEncoderNiceFlo* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     size_t index = 0; | ||||||
|  |     size_t size_upload = (instance->generic.data_count_bit * 2) + 2; | ||||||
|  |     if(size_upload > instance->encoder.size_upload) { | ||||||
|  |         FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); | ||||||
|  |         return false; | ||||||
|  |     } else { | ||||||
|  |         instance->encoder.size_upload = size_upload; | ||||||
|  |     } | ||||||
|  |     //Send header
 | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(false, (uint32_t)subghz_protocol_nice_flo_const.te_short * 36); | ||||||
|  |     //Send start bit
 | ||||||
|  |     instance->encoder.upload[index++] = | ||||||
|  |         level_duration_make(true, (uint32_t)subghz_protocol_nice_flo_const.te_short); | ||||||
|  |     //Send key data
 | ||||||
|  |     for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { | ||||||
|  |         if(bit_read(instance->generic.data, i - 1)) { | ||||||
|  |             //send bit 1
 | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(false, (uint32_t)subghz_protocol_nice_flo_const.te_long); | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(true, (uint32_t)subghz_protocol_nice_flo_const.te_short); | ||||||
|  |         } else { | ||||||
|  |             //send bit 0
 | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(false, (uint32_t)subghz_protocol_nice_flo_const.te_short); | ||||||
|  |             instance->encoder.upload[index++] = | ||||||
|  |                 level_duration_make(true, (uint32_t)subghz_protocol_nice_flo_const.te_long); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolEncoderNiceFlo* instance = context; | ||||||
|  |     bool res = false; | ||||||
|  |     do { | ||||||
|  |         if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { | ||||||
|  |             FURI_LOG_E(TAG, "Deserialize error"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         //optional parameter parameter
 | ||||||
|  |         flipper_format_read_uint32( | ||||||
|  |             flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); | ||||||
|  | 
 | ||||||
|  |         subghz_protocol_encoder_nice_flo_get_upload(instance); | ||||||
|  |         instance->encoder.is_runing = true; | ||||||
|  | 
 | ||||||
|  |         res = true; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_encoder_nice_flo_stop(void* context) { | ||||||
|  |     SubGhzProtocolEncoderNiceFlo* instance = context; | ||||||
|  |     instance->encoder.is_runing = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | LevelDuration subghz_protocol_encoder_nice_flo_yield(void* context) { | ||||||
|  |     SubGhzProtocolEncoderNiceFlo* instance = context; | ||||||
|  | 
 | ||||||
|  |     if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { | ||||||
|  |         instance->encoder.is_runing = false; | ||||||
|  |         return level_duration_reset(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LevelDuration ret = instance->encoder.upload[instance->encoder.front]; | ||||||
|  | 
 | ||||||
|  |     if(++instance->encoder.front == instance->encoder.size_upload) { | ||||||
|  |         instance->encoder.repeat--; | ||||||
|  |         instance->encoder.front = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_nice_flo_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolDecoderNiceFlo* instance = malloc(sizeof(SubGhzProtocolDecoderNiceFlo)); | ||||||
|  |     instance->base.protocol = &subghz_protocol_nice_flo; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nice_flo_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNiceFlo* instance = context; | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nice_flo_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNiceFlo* instance = context; | ||||||
|  |     instance->decoder.parser_step = NiceFloDecoderStepReset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nice_flo_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNiceFlo* instance = context; | ||||||
|  | 
 | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case NiceFloDecoderStepReset: | ||||||
|  |         if((!level) && (DURATION_DIFF(duration, subghz_protocol_nice_flo_const.te_short * 36) < | ||||||
|  |                         subghz_protocol_nice_flo_const.te_delta * 36)) { | ||||||
|  |             //Found header Nice Flo
 | ||||||
|  |             instance->decoder.parser_step = NiceFloDecoderStepFoundStartBit; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case NiceFloDecoderStepFoundStartBit: | ||||||
|  |         if(!level) { | ||||||
|  |             break; | ||||||
|  |         } else if( | ||||||
|  |             DURATION_DIFF(duration, subghz_protocol_nice_flo_const.te_short) < | ||||||
|  |             subghz_protocol_nice_flo_const.te_delta) { | ||||||
|  |             //Found start bit Nice Flo
 | ||||||
|  |             instance->decoder.parser_step = NiceFloDecoderStepSaveDuration; | ||||||
|  |             instance->decoder.decode_data = 0; | ||||||
|  |             instance->decoder.decode_count_bit = 0; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = NiceFloDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case NiceFloDecoderStepSaveDuration: | ||||||
|  |         if(!level) { //save interval
 | ||||||
|  |             if(duration >= (subghz_protocol_nice_flo_const.te_short * 4)) { | ||||||
|  |                 instance->decoder.parser_step = NiceFloDecoderStepFoundStartBit; | ||||||
|  |                 if(instance->decoder.decode_count_bit >= | ||||||
|  |                    subghz_protocol_nice_flo_const.min_count_bit_for_found) { | ||||||
|  |                     instance->generic.serial = 0x0; | ||||||
|  |                     instance->generic.btn = 0x0; | ||||||
|  | 
 | ||||||
|  |                     instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                     instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  |                     if(instance->base.callback) | ||||||
|  |                         instance->base.callback(&instance->base, instance->base.context); | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             instance->decoder.te_last = duration; | ||||||
|  |             instance->decoder.parser_step = NiceFloDecoderStepCheckDuration; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = NiceFloDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case NiceFloDecoderStepCheckDuration: | ||||||
|  |         if(level) { | ||||||
|  |             if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_nice_flo_const.te_short) < | ||||||
|  |                 subghz_protocol_nice_flo_const.te_delta) && | ||||||
|  |                (DURATION_DIFF(duration, subghz_protocol_nice_flo_const.te_long) < | ||||||
|  |                 subghz_protocol_nice_flo_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                 instance->decoder.parser_step = NiceFloDecoderStepSaveDuration; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_nice_flo_const.te_long) < | ||||||
|  |                  subghz_protocol_nice_flo_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, subghz_protocol_nice_flo_const.te_short) < | ||||||
|  |                  subghz_protocol_nice_flo_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                 instance->decoder.parser_step = NiceFloDecoderStepSaveDuration; | ||||||
|  |             } else | ||||||
|  |                 instance->decoder.parser_step = NiceFloDecoderStepReset; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = NiceFloDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_nice_flo_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNiceFlo* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_nice_flo_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNiceFlo* instance = context; | ||||||
|  |     return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNiceFlo* instance = context; | ||||||
|  |     return subghz_block_generic_deserialize(&instance->generic, flipper_format); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nice_flo_get_string(void* context, string_t output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNiceFlo* instance = context; | ||||||
|  | 
 | ||||||
|  |     uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; | ||||||
|  |     uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key( | ||||||
|  |         instance->generic.data, instance->generic.data_count_bit); | ||||||
|  |     uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %dbit\r\n" | ||||||
|  |         "Key:0x%08lX\r\n" | ||||||
|  |         "Yek:0x%08lX\r\n", | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         code_found_lo, | ||||||
|  |         code_found_reverse_lo); | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								lib/subghz/protocols/nice_flo.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								lib/subghz/protocols/nice_flo.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "base.h" | ||||||
|  | 
 | ||||||
|  | #define SUBGHZ_PROTOCOL_NICE_FLO_NAME "Nice FLO" | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzProtocolDecoderNiceFlo SubGhzProtocolDecoderNiceFlo; | ||||||
|  | typedef struct SubGhzProtocolEncoderNiceFlo SubGhzProtocolEncoderNiceFlo; | ||||||
|  | 
 | ||||||
|  | extern const SubGhzProtocolDecoder subghz_protocol_nice_flo_decoder; | ||||||
|  | extern const SubGhzProtocolEncoder subghz_protocol_nice_flo_encoder; | ||||||
|  | extern const SubGhzProtocol subghz_protocol_nice_flo; | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_encoder_nice_flo_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_encoder_nice_flo_free(void* context); | ||||||
|  | bool subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | void subghz_protocol_encoder_nice_flo_stop(void* context); | ||||||
|  | LevelDuration subghz_protocol_encoder_nice_flo_yield(void* context); | ||||||
|  | void* subghz_protocol_decoder_nice_flo_alloc(SubGhzEnvironment* environment); | ||||||
|  | void subghz_protocol_decoder_nice_flo_free(void* context); | ||||||
|  | void subghz_protocol_decoder_nice_flo_reset(void* context); | ||||||
|  | void subghz_protocol_decoder_nice_flo_feed(void* context, bool level, uint32_t duration); | ||||||
|  | uint8_t subghz_protocol_decoder_nice_flo_get_hash_data(void* context); | ||||||
|  | void subghz_protocol_decoder_nice_flo_get_string(void* context, string_t output); | ||||||
|  | bool subghz_protocol_decoder_nice_flo_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | bool subghz_protocol_decoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
							
								
								
									
										366
									
								
								lib/subghz/protocols/nice_flor_s.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										366
									
								
								lib/subghz/protocols/nice_flor_s.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,366 @@ | |||||||
|  | #include "nice_flor_s.h" | ||||||
|  | 
 | ||||||
|  | #include "../blocks/const.h" | ||||||
|  | #include "../blocks/decoder.h" | ||||||
|  | #include "../blocks/encoder.h" | ||||||
|  | #include "../blocks/generic.h" | ||||||
|  | #include "../blocks/math.h" | ||||||
|  | /*
 | ||||||
|  |  * https://phreakerclub.com/1615
 | ||||||
|  |  * https://phreakerclub.com/forum/showthread.php?t=2360
 | ||||||
|  |  * https://vrtp.ru/index.php?showtopic=27867
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define TAG "SubGhzProtocoNiceFlorS" | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst subghz_protocol_nice_flor_s_const = { | ||||||
|  |     .te_short = 500, | ||||||
|  |     .te_long = 1000, | ||||||
|  |     .te_delta = 300, | ||||||
|  |     .min_count_bit_for_found = 52, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolDecoderNiceFlorS { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | 
 | ||||||
|  |     const char* nice_flor_s_rainbow_table_file_name; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzProtocolEncoderNiceFlorS { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     SubGhzBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     NiceFlorSDecoderStepReset = 0, | ||||||
|  |     NiceFlorSDecoderStepCheckHeader, | ||||||
|  |     NiceFlorSDecoderStepFoundHeader, | ||||||
|  |     NiceFlorSDecoderStepSaveDuration, | ||||||
|  |     NiceFlorSDecoderStepCheckDuration, | ||||||
|  | } NiceFlorSDecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder subghz_protocol_nice_flor_s_decoder = { | ||||||
|  |     .alloc = subghz_protocol_decoder_nice_flor_s_alloc, | ||||||
|  |     .free = subghz_protocol_decoder_nice_flor_s_free, | ||||||
|  | 
 | ||||||
|  |     .feed = subghz_protocol_decoder_nice_flor_s_feed, | ||||||
|  |     .reset = subghz_protocol_decoder_nice_flor_s_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = subghz_protocol_decoder_nice_flor_s_get_hash_data, | ||||||
|  |     .serialize = subghz_protocol_decoder_nice_flor_s_serialize, | ||||||
|  |     .deserialize = subghz_protocol_decoder_nice_flor_s_deserialize, | ||||||
|  |     .get_string = subghz_protocol_decoder_nice_flor_s_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder subghz_protocol_nice_flor_s_encoder = { | ||||||
|  |     .alloc = NULL, | ||||||
|  |     .free = NULL, | ||||||
|  | 
 | ||||||
|  |     .deserialize = NULL, | ||||||
|  |     .stop = NULL, | ||||||
|  |     .yield = NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol subghz_protocol_nice_flor_s = { | ||||||
|  |     .name = SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME, | ||||||
|  |     .type = SubGhzProtocolTypeDynamic, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM | | ||||||
|  |             SubGhzProtocolFlag_Decodable, | ||||||
|  | 
 | ||||||
|  |     .decoder = &subghz_protocol_nice_flor_s_decoder, | ||||||
|  |     .encoder = &subghz_protocol_nice_flor_s_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** Read bytes from rainbow table
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolNiceFlorS* instance | ||||||
|  |  * @param address  - address byte | ||||||
|  |  * @return byte data | ||||||
|  |  */ | ||||||
|  | static uint8_t | ||||||
|  |     subghz_protocol_nice_flor_s_get_byte_in_file(const char* file_name, uint32_t address) { | ||||||
|  |     if(!file_name) return 0; | ||||||
|  | 
 | ||||||
|  |     uint8_t buffer[1] = {0}; | ||||||
|  |     if(subghz_keystore_raw_get_data(file_name, address, buffer, sizeof(uint8_t))) { | ||||||
|  |         return buffer[0]; | ||||||
|  |     } else { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void subghz_protocol_decoder_nice_flor_s_magic_xor(uint8_t* p, uint8_t k) { | ||||||
|  |     for(uint8_t i = 1; i < 6; i++) { | ||||||
|  |         p[i] ^= k; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint64_t subghz_protocol_nice_flor_s_encrypt(uint64_t data, const char* file_name) { | ||||||
|  |     uint8_t* p = (uint8_t*)&data; | ||||||
|  | 
 | ||||||
|  |     uint8_t k = 0; | ||||||
|  |     for(uint8_t y = 0; y < 2; y++) { | ||||||
|  |         k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] & 0x1f); | ||||||
|  |         subghz_protocol_decoder_nice_flor_s_magic_xor(p, k); | ||||||
|  | 
 | ||||||
|  |         p[5] &= 0x0f; | ||||||
|  |         p[0] ^= k & 0xe0; | ||||||
|  |         k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] >> 3) + 0x25; | ||||||
|  |         subghz_protocol_decoder_nice_flor_s_magic_xor(p, k); | ||||||
|  | 
 | ||||||
|  |         p[5] &= 0x0f; | ||||||
|  |         p[0] ^= k & 0x7; | ||||||
|  |         if(y == 0) { | ||||||
|  |             k = p[0]; | ||||||
|  |             p[0] = p[1]; | ||||||
|  |             p[1] = k; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     p[5] = ~p[5] & 0x0f; | ||||||
|  |     k = ~p[4]; | ||||||
|  |     p[4] = ~p[0]; | ||||||
|  |     p[0] = ~p[2]; | ||||||
|  |     p[2] = k; | ||||||
|  |     k = ~p[3]; | ||||||
|  |     p[3] = ~p[1]; | ||||||
|  |     p[1] = k; | ||||||
|  | 
 | ||||||
|  |     return data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static uint64_t | ||||||
|  |     subghz_protocol_nice_flor_s_decrypt(SubGhzBlockGeneric* instance, const char* file_name) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     uint64_t data = instance->data; | ||||||
|  |     uint8_t* p = (uint8_t*)&data; | ||||||
|  | 
 | ||||||
|  |     uint8_t k = 0; | ||||||
|  | 
 | ||||||
|  |     k = ~p[4]; | ||||||
|  |     p[5] = ~p[5]; | ||||||
|  |     p[4] = ~p[2]; | ||||||
|  |     p[2] = ~p[0]; | ||||||
|  |     p[0] = k; | ||||||
|  |     k = ~p[3]; | ||||||
|  |     p[3] = ~p[1]; | ||||||
|  |     p[1] = k; | ||||||
|  | 
 | ||||||
|  |     for(uint8_t y = 0; y < 2; y++) { | ||||||
|  |         k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] >> 3) + 0x25; | ||||||
|  |         subghz_protocol_decoder_nice_flor_s_magic_xor(p, k); | ||||||
|  | 
 | ||||||
|  |         p[5] &= 0x0f; | ||||||
|  |         p[0] ^= k & 0x7; | ||||||
|  |         k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] & 0x1f); | ||||||
|  |         subghz_protocol_decoder_nice_flor_s_magic_xor(p, k); | ||||||
|  | 
 | ||||||
|  |         p[5] &= 0x0f; | ||||||
|  |         p[0] ^= k & 0xe0; | ||||||
|  | 
 | ||||||
|  |         if(y == 0) { | ||||||
|  |             k = p[0]; | ||||||
|  |             p[0] = p[1]; | ||||||
|  |             p[1] = k; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void* subghz_protocol_decoder_nice_flor_s_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     SubGhzProtocolDecoderNiceFlorS* instance = malloc(sizeof(SubGhzProtocolDecoderNiceFlorS)); | ||||||
|  |     instance->base.protocol = &subghz_protocol_nice_flor_s; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  |     instance->nice_flor_s_rainbow_table_file_name = | ||||||
|  |         subghz_environment_get_nice_flor_s_rainbow_table_file_name(environment); | ||||||
|  |     if(instance->nice_flor_s_rainbow_table_file_name) { | ||||||
|  |         FURI_LOG_I( | ||||||
|  |             TAG, "Loading rainbow table from %s", instance->nice_flor_s_rainbow_table_file_name); | ||||||
|  |     } | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nice_flor_s_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNiceFlorS* instance = context; | ||||||
|  |     instance->nice_flor_s_rainbow_table_file_name = NULL; | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nice_flor_s_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNiceFlorS* instance = context; | ||||||
|  |     instance->decoder.parser_step = NiceFlorSDecoderStepReset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nice_flor_s_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNiceFlorS* instance = context; | ||||||
|  | 
 | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case NiceFlorSDecoderStepReset: | ||||||
|  |         if((!level) && (DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short * 38) < | ||||||
|  |                         subghz_protocol_nice_flor_s_const.te_delta * 38)) { | ||||||
|  |             //Found start header Nice Flor-S
 | ||||||
|  |             instance->decoder.parser_step = NiceFlorSDecoderStepCheckHeader; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case NiceFlorSDecoderStepCheckHeader: | ||||||
|  |         if((level) && (DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short * 3) < | ||||||
|  |                        subghz_protocol_nice_flor_s_const.te_delta * 3)) { | ||||||
|  |             //Found next header Nice Flor-S
 | ||||||
|  |             instance->decoder.parser_step = NiceFlorSDecoderStepFoundHeader; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = NiceFlorSDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case NiceFlorSDecoderStepFoundHeader: | ||||||
|  |         if((!level) && (DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short * 3) < | ||||||
|  |                         subghz_protocol_nice_flor_s_const.te_delta * 3)) { | ||||||
|  |             //Found header Nice Flor-S
 | ||||||
|  |             instance->decoder.parser_step = NiceFlorSDecoderStepSaveDuration; | ||||||
|  |             instance->decoder.decode_data = 0; | ||||||
|  |             instance->decoder.decode_count_bit = 0; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = NiceFlorSDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case NiceFlorSDecoderStepSaveDuration: | ||||||
|  |         if(level) { | ||||||
|  |             if(DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short * 3) < | ||||||
|  |                subghz_protocol_nice_flor_s_const.te_delta) { | ||||||
|  |                 //Found STOP bit
 | ||||||
|  |                 instance->decoder.parser_step = NiceFlorSDecoderStepReset; | ||||||
|  |                 if(instance->decoder.decode_count_bit >= | ||||||
|  |                    subghz_protocol_nice_flor_s_const.min_count_bit_for_found) { | ||||||
|  |                     instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                     instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  |                     if(instance->base.callback) | ||||||
|  |                         instance->base.callback(&instance->base, instance->base.context); | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             } else { | ||||||
|  |                 //save interval
 | ||||||
|  |                 instance->decoder.te_last = duration; | ||||||
|  |                 instance->decoder.parser_step = NiceFlorSDecoderStepCheckDuration; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case NiceFlorSDecoderStepCheckDuration: | ||||||
|  |         if(!level) { | ||||||
|  |             if((DURATION_DIFF( | ||||||
|  |                     instance->decoder.te_last, subghz_protocol_nice_flor_s_const.te_short) < | ||||||
|  |                 subghz_protocol_nice_flor_s_const.te_delta) && | ||||||
|  |                (DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_long) < | ||||||
|  |                 subghz_protocol_nice_flor_s_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                 instance->decoder.parser_step = NiceFlorSDecoderStepSaveDuration; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF( | ||||||
|  |                      instance->decoder.te_last, subghz_protocol_nice_flor_s_const.te_long) < | ||||||
|  |                  subghz_protocol_nice_flor_s_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short) < | ||||||
|  |                  subghz_protocol_nice_flor_s_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                 instance->decoder.parser_step = NiceFlorSDecoderStepSaveDuration; | ||||||
|  |             } else | ||||||
|  |                 instance->decoder.parser_step = NiceFlorSDecoderStepReset; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = NiceFlorSDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** Decrypt protocol Nice Flor S
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzProtocolNiceFlorS* instance | ||||||
|  |  */ | ||||||
|  | static void subghz_protocol_nice_flor_s_remote_controller( | ||||||
|  |     SubGhzBlockGeneric* instance, | ||||||
|  |     const char* file_name) { | ||||||
|  |     /*
 | ||||||
|  |     * Packet format Nice Flor-s: START-P0-P1-P2-P3-P4-P5-P6-P7-STOP | ||||||
|  |     * P0 (4-bit)    - button positional code - 1:0x1, 2:0x2, 3:0x4, 4:0x8; | ||||||
|  |     * P1 (4-bit)    - batch repetition number, calculated by the formula: | ||||||
|  |     * P1 = 0xF ^ P0 ^ n; where n changes from 1 to 15, then 0, and then in a circle | ||||||
|  |     * key 1: {0xE,0xF,0xC,0xD,0xA,0xB,0x8,0x9,0x6,0x7,0x4,0x5,0x2,0x3,0x0,0x1}; | ||||||
|  |     * key 2: {0xD,0xC,0xF,0xE,0x9,0x8,0xB,0xA,0x5,0x4,0x7,0x6,0x1,0x0,0x3,0x2}; | ||||||
|  |     * key 3: {0xB,0xA,0x9,0x8,0xF,0xE,0xD,0xC,0x3,0x2,0x1,0x0,0x7,0x6,0x5,0x4}; | ||||||
|  |     * key 4: {0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0,0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8}; | ||||||
|  |     * P2 (4-bit)    - part of the serial number, P2 = (K ^ S3) & 0xF; | ||||||
|  |     * P3 (byte)     - the major part of the encrypted index | ||||||
|  |     * P4 (byte)     - the low-order part of the encrypted index | ||||||
|  |     * P5 (byte)     - part of the serial number, P5 = K ^ S2; | ||||||
|  |     * P6 (byte)     - part of the serial number, P6 = K ^ S1; | ||||||
|  |     * P7 (byte)     - part of the serial number, P7 = K ^ S0; | ||||||
|  |     * K (byte)      - depends on P3 and P4, K = Fk(P3, P4); | ||||||
|  |     * S3,S2,S1,S0   - serial number of the console 28 bit. | ||||||
|  |     * | ||||||
|  |     * data    => 0x1c5783607f7b3     key  serial  cnt | ||||||
|  |     * decrypt => 0x10436c6820444 => 0x1  0436c682 0444 | ||||||
|  |     *  | ||||||
|  |     */ | ||||||
|  |     if(!file_name) { | ||||||
|  |         instance->cnt = 0; | ||||||
|  |         instance->serial = 0; | ||||||
|  |         instance->btn = 0; | ||||||
|  |     } else { | ||||||
|  |         uint64_t decrypt = subghz_protocol_nice_flor_s_decrypt(instance, file_name); | ||||||
|  |         instance->cnt = decrypt & 0xFFFF; | ||||||
|  |         instance->serial = (decrypt >> 16) & 0xFFFFFFF; | ||||||
|  |         instance->btn = (decrypt >> 48) & 0xF; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_decoder_nice_flor_s_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNiceFlorS* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_nice_flor_s_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNiceFlorS* instance = context; | ||||||
|  |     return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_protocol_decoder_nice_flor_s_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNiceFlorS* instance = context; | ||||||
|  |     return subghz_block_generic_deserialize(&instance->generic, flipper_format); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_protocol_decoder_nice_flor_s_get_string(void* context, string_t output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolDecoderNiceFlorS* instance = context; | ||||||
|  | 
 | ||||||
|  |     subghz_protocol_nice_flor_s_remote_controller( | ||||||
|  |         &instance->generic, instance->nice_flor_s_rainbow_table_file_name); | ||||||
|  |     uint32_t code_found_hi = instance->generic.data >> 32; | ||||||
|  |     uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; | ||||||
|  | 
 | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %dbit\r\n" | ||||||
|  |         "Key:0x%lX%08lX\r\n" | ||||||
|  |         "Sn:%05lX\r\n" | ||||||
|  |         "Cnt:%04X Btn:%02lX\r\n", | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         code_found_hi, | ||||||
|  |         code_found_lo, | ||||||
|  |         instance->generic.serial, | ||||||
|  |         instance->generic.cnt, | ||||||
|  |         instance->generic.btn); | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Skorpionm
						Skorpionm