Merge remote-tracking branch 'origin/dev' into release-candidate
This commit is contained in:
		
						commit
						be4dec77da
					
				| @ -211,11 +211,12 @@ bool ibutton_save_key(iButton* ibutton, const char* key_name) { | ||||
|     bool result = false; | ||||
| 
 | ||||
|     do { | ||||
|         // First remove key if it was saved (we rename the key)
 | ||||
|         ibutton_delete_key(ibutton); | ||||
| 
 | ||||
|         // Set full file name, for new key
 | ||||
|         // Check if we has old key
 | ||||
|         if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||
|             // First remove old key
 | ||||
|             ibutton_delete_key(ibutton); | ||||
| 
 | ||||
|             // Remove old key name from path
 | ||||
|             size_t filename_start = string_search_rchar(ibutton->file_path, '/'); | ||||
|             string_left(ibutton->file_path, filename_start); | ||||
|         } | ||||
|  | ||||
| @ -81,7 +81,7 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */ | ||||
|     case LfrfidKeyType::KeyIoProxXSF: | ||||
|         line_1_text->set_text("HEX:", 65, 23, 0, AlignRight, AlignBottom, FontSecondary); | ||||
|         line_2l_text->set_text("FC:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary); | ||||
|         line_2r_text->set_text("V:", 95, 35, 0, AlignRight, AlignBottom, FontSecondary); | ||||
|         line_2r_text->set_text("VС:", 95, 35, 0, AlignRight, AlignBottom, FontSecondary); | ||||
|         line_3_text->set_text("Card:", 65, 47, 0, AlignRight, AlignBottom, FontSecondary); | ||||
| 
 | ||||
|         for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) { | ||||
|  | ||||
| @ -1,23 +1,10 @@ | ||||
| #include "lfrfid_app_scene_save_data.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| static void print_buffer(const uint8_t* buffer) { | ||||
|     for(uint8_t i = 0; i < LFRFID_KEY_SIZE; i++) { | ||||
|         printf("%02X", buffer[i]); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void LfRfidAppSceneSaveData::on_enter(LfRfidApp* app, bool need_restore) { | ||||
|     auto byte_input = app->view_controller.get<ByteInputVM>(); | ||||
|     RfidKey& key = app->worker.key; | ||||
| 
 | ||||
|     printf("k: "); | ||||
|     print_buffer(key.get_data()); | ||||
|     printf(" o: "); | ||||
|     print_buffer(old_key_data); | ||||
|     printf(" n: "); | ||||
|     print_buffer(new_key_data); | ||||
|     printf("\r\n"); | ||||
|     if(need_restore) printf("restored\r\n"); | ||||
| 
 | ||||
|     if(need_restore) { | ||||
|  | ||||
| @ -5,6 +5,26 @@ typedef enum { | ||||
|     SubGhzCustomEventManagerSet, | ||||
|     SubGhzCustomEventManagerSetRAW, | ||||
| 
 | ||||
|     //SubmenuIndex
 | ||||
|     SubmenuIndexPricenton, | ||||
|     SubmenuIndexNiceFlo12bit, | ||||
|     SubmenuIndexNiceFlo24bit, | ||||
|     SubmenuIndexCAME12bit, | ||||
|     SubmenuIndexCAME24bit, | ||||
|     SubmenuIndexCAMETwee, | ||||
|     SubmenuIndexNeroSketch, | ||||
|     SubmenuIndexNeroRadio, | ||||
|     SubmenuIndexGateTX, | ||||
|     SubmenuIndexDoorHan_315_00, | ||||
|     SubmenuIndexDoorHan_433_92, | ||||
|     SubmenuIndexLinear_300_00, | ||||
|     SubmenuIndexLiftMaster_315_00, | ||||
|     SubmenuIndexLiftMaster_390_00, | ||||
|     SubmenuIndexSecPlus_v2_310_00, | ||||
|     SubmenuIndexSecPlus_v2_315_00, | ||||
|     SubmenuIndexSecPlus_v2_390_00, | ||||
| 
 | ||||
|     //SubGhzCustomEvent
 | ||||
|     SubGhzCustomEventSceneDeleteSuccess = 100, | ||||
|     SubGhzCustomEventSceneDelete, | ||||
|     SubGhzCustomEventSceneDeleteRAW, | ||||
|  | ||||
| @ -26,9 +26,15 @@ bool subghz_scene_delete_success_on_event(void* context, SceneManagerEvent event | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubGhzCustomEventSceneDeleteSuccess) { | ||||
|             if(!scene_manager_search_and_switch_to_previous_scene( | ||||
|                    subghz->scene_manager, SubGhzSceneSaved)) { | ||||
|             if(scene_manager_search_and_switch_to_previous_scene( | ||||
|                    subghz->scene_manager, SubGhzSceneReadRAW)) { | ||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); | ||||
|             } else if(scene_manager_search_and_switch_to_previous_scene( | ||||
|                           subghz->scene_manager, SubGhzSceneSaved)) { | ||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); | ||||
|             } else { | ||||
|                 scene_manager_search_and_switch_to_previous_scene( | ||||
|                     subghz->scene_manager, SubGhzSceneStart); | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
| @ -167,11 +167,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | ||||
|             break; | ||||
| 
 | ||||
|         case SubGhzCustomEventViewReadRAWErase: | ||||
|             subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||
|             if(subghz_scene_read_raw_update_filename(subghz)) { | ||||
|                 string_set(subghz->file_path_tmp, subghz->file_path); | ||||
|                 subghz_delete_file(subghz); | ||||
|             if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { | ||||
|                 if(subghz_scene_read_raw_update_filename(subghz)) { | ||||
|                     string_set(subghz->file_path_tmp, subghz->file_path); | ||||
|                     subghz_delete_file(subghz); | ||||
|                 } | ||||
|             } | ||||
|             subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||
|             notification_message(subghz->notifications, &sequence_reset_rgb); | ||||
|             return true; | ||||
|             break; | ||||
| @ -184,7 +186,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | ||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW); | ||||
|                 return true; | ||||
|             } else { | ||||
|                 furi_crash("SugGhz: RAW file name update error."); | ||||
|                 furi_crash("SubGhz: RAW file name update error."); | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|  | ||||
| @ -10,26 +10,6 @@ | ||||
| 
 | ||||
| #define TAG "SubGhzSetType" | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexPricenton, | ||||
|     SubmenuIndexNiceFlo12bit, | ||||
|     SubmenuIndexNiceFlo24bit, | ||||
|     SubmenuIndexCAME12bit, | ||||
|     SubmenuIndexCAME24bit, | ||||
|     SubmenuIndexCAMETwee, | ||||
|     SubmenuIndexNeroSketch, | ||||
|     SubmenuIndexNeroRadio, | ||||
|     SubmenuIndexGateTX, | ||||
|     SubmenuIndexDoorHan_315_00, | ||||
|     SubmenuIndexDoorHan_433_92, | ||||
|     SubmenuIndexFirefly_300_00, | ||||
|     SubmenuIndexLiftMaster_315_00, | ||||
|     SubmenuIndexLiftMaster_390_00, | ||||
|     SubmenuIndexSecPlus_v2_310_00, | ||||
|     SubmenuIndexSecPlus_v2_315_00, | ||||
|     SubmenuIndexSecPlus_v2_390_00, | ||||
| }; | ||||
| 
 | ||||
| bool subghz_scene_set_type_submenu_gen_data_protocol( | ||||
|     void* context, | ||||
|     const char* protocol_name, | ||||
| @ -117,8 +97,8 @@ void subghz_scene_set_type_on_enter(void* context) { | ||||
|         subghz); | ||||
|     submenu_add_item( | ||||
|         subghz->submenu, | ||||
|         "Firefly_300", | ||||
|         SubmenuIndexFirefly_300_00, | ||||
|         "Linear_300", | ||||
|         SubmenuIndexLinear_300_00, | ||||
|         subghz_scene_set_type_submenu_callback, | ||||
|         subghz); | ||||
|     submenu_add_item( | ||||
| @ -256,11 +236,11 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { | ||||
|                 generated_protocol = true; | ||||
|             } | ||||
|             break; | ||||
|         case SubmenuIndexFirefly_300_00: | ||||
|         case SubmenuIndexLinear_300_00: | ||||
|             key = (key & 0x3FF); | ||||
|             if(subghz_scene_set_type_submenu_gen_data_protocol( | ||||
|                    subghz, | ||||
|                    SUBGHZ_PROTOCOL_FIREFLY_NAME, | ||||
|                    SUBGHZ_PROTOCOL_LINEAR_NAME, | ||||
|                    key, | ||||
|                    10, | ||||
|                    300000000, | ||||
|  | ||||
| @ -54,7 +54,7 @@ void subghz_get_frequency_modulation(SubGhz* subghz, string_t frequency, string_ | ||||
|             subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev476Async) { | ||||
|             string_set_str(modulation, "FM"); | ||||
|         } else { | ||||
|             furi_crash("SugGhz: Modulation is incorrect."); | ||||
|             furi_crash("SubGhz: Modulation is incorrect."); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -71,7 +71,7 @@ void subghz_begin(SubGhz* subghz, FuriHalSubGhzPreset preset) { | ||||
| uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency) { | ||||
|     furi_assert(subghz); | ||||
|     if(!furi_hal_subghz_is_frequency_valid(frequency)) { | ||||
|         furi_crash("SugGhz: Incorrect RX frequency."); | ||||
|         furi_crash("SubGhz: Incorrect RX frequency."); | ||||
|     } | ||||
|     furi_assert( | ||||
|         subghz->txrx->txrx_state != SubGhzTxRxStateRx && | ||||
| @ -92,7 +92,7 @@ uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency) { | ||||
| static bool subghz_tx(SubGhz* subghz, uint32_t frequency) { | ||||
|     furi_assert(subghz); | ||||
|     if(!furi_hal_subghz_is_frequency_valid(frequency)) { | ||||
|         furi_crash("SugGhz: Incorrect TX frequency."); | ||||
|         furi_crash("SubGhz: Incorrect TX frequency."); | ||||
|     } | ||||
|     furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep); | ||||
|     furi_hal_subghz_idle(); | ||||
|  | ||||
| @ -328,10 +328,10 @@ MU_TEST(subghz_decoder_star_line_test) { | ||||
|         "Test decoder " SUBGHZ_PROTOCOL_STAR_LINE_NAME " error\r\n"); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(subghz_decoder_firefly_test) { | ||||
| MU_TEST(subghz_decoder_linear_test) { | ||||
|     mu_assert( | ||||
|         subghz_decoder_test("/ext/unit_tests/subghz/firefly_raw.sub", SUBGHZ_PROTOCOL_FIREFLY_NAME), | ||||
|         "Test decoder " SUBGHZ_PROTOCOL_FIREFLY_NAME " error\r\n"); | ||||
|         subghz_decoder_test("/ext/unit_tests/subghz/linear_raw.sub", SUBGHZ_PROTOCOL_LINEAR_NAME), | ||||
|         "Test decoder " SUBGHZ_PROTOCOL_LINEAR_NAME " error\r\n"); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(subghz_decoder_megacode_test) { | ||||
| @ -398,10 +398,10 @@ MU_TEST(subghz_encoder_keelog_test) { | ||||
|         "Test encoder " SUBGHZ_PROTOCOL_KEELOQ_NAME " error\r\n"); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(subghz_encoder_firefly_test) { | ||||
| MU_TEST(subghz_encoder_linear_test) { | ||||
|     mu_assert( | ||||
|         subghz_encoder_test("/ext/unit_tests/subghz/firely.sub"), | ||||
|         "Test encoder " SUBGHZ_PROTOCOL_FIREFLY_NAME " error\r\n"); | ||||
|         subghz_encoder_test("/ext/unit_tests/subghz/linear.sub"), | ||||
|         "Test encoder " SUBGHZ_PROTOCOL_LINEAR_NAME " error\r\n"); | ||||
| } | ||||
| 
 | ||||
| MU_TEST(subghz_encoder_megacode_test) { | ||||
| @ -454,7 +454,7 @@ MU_TEST_SUITE(subghz) { | ||||
|     MU_RUN_TEST(subghz_decoder_somfy_keytis_test); | ||||
|     MU_RUN_TEST(subghz_decoder_somfy_telis_test); | ||||
|     MU_RUN_TEST(subghz_decoder_star_line_test); | ||||
|     MU_RUN_TEST(subghz_decoder_firefly_test); | ||||
|     MU_RUN_TEST(subghz_decoder_linear_test); | ||||
|     MU_RUN_TEST(subghz_decoder_megacode_test); | ||||
|     MU_RUN_TEST(subghz_decoder_secplus_v1_test); | ||||
|     MU_RUN_TEST(subghz_decoder_secplus_v2_test); | ||||
| @ -466,7 +466,7 @@ MU_TEST_SUITE(subghz) { | ||||
|     MU_RUN_TEST(subghz_encoder_gate_tx_test); | ||||
|     MU_RUN_TEST(subghz_encoder_nice_flo_test); | ||||
|     MU_RUN_TEST(subghz_encoder_keelog_test); | ||||
|     MU_RUN_TEST(subghz_encoder_firefly_test); | ||||
|     MU_RUN_TEST(subghz_encoder_linear_test); | ||||
|     MU_RUN_TEST(subghz_encoder_megacode_test); | ||||
|     MU_RUN_TEST(subghz_encoder_holtek_test); | ||||
|     MU_RUN_TEST(subghz_encoder_secplus_v1_test); | ||||
|  | ||||
| @ -2,6 +2,6 @@ Filetype: Flipper SubGhz Key File | ||||
| Version: 1 | ||||
| Frequency: 300000000 | ||||
| Preset: FuriHalSubGhzPresetOok650Async | ||||
| Protocol: Firefly | ||||
| Protocol: Linear | ||||
| Bit: 10 | ||||
| Key: 00 00 00 00 00 00 01 E4 | ||||
| @ -412,7 +412,7 @@ void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) { | ||||
|         furi_hal_subghz_load_registers(furi_hal_subghz_preset_gfsk_9_99kb_async_regs); | ||||
|         furi_hal_subghz_load_patable(furi_hal_subghz_preset_gfsk_async_patable); | ||||
|     } else { | ||||
|         furi_crash("SugGhz: Missing config."); | ||||
|         furi_crash("SubGhz: Missing config."); | ||||
|     } | ||||
|     furi_hal_subghz_preset = preset; | ||||
| } | ||||
| @ -564,7 +564,7 @@ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value) { | ||||
|     } else if(value >= 778999847 && value <= 928000000) { | ||||
|         furi_hal_subghz_set_path(FuriHalSubGhzPath868); | ||||
|     } else { | ||||
|         furi_crash("SugGhz: Incorrect frequency during set."); | ||||
|         furi_crash("SubGhz: Incorrect frequency during set."); | ||||
|     } | ||||
|     return value; | ||||
| } | ||||
|  | ||||
| @ -1,3 +1,45 @@ | ||||
| #include "encoder.h" | ||||
| #include "math.h" | ||||
| #include <furi/check.h> | ||||
| 
 | ||||
| #define TAG "SubGhzBlockEncoder" | ||||
| 
 | ||||
| void subghz_protocol_blocks_set_bit_array( | ||||
|     bool bit_value, | ||||
|     uint8_t data_array[], | ||||
|     size_t set_index_bit, | ||||
|     size_t max_size_array) { | ||||
|     furi_assert(set_index_bit < max_size_array * 8); | ||||
|     bit_write(data_array[set_index_bit >> 3], 7 - (set_index_bit & 0x7), bit_value); | ||||
| } | ||||
| 
 | ||||
| bool subghz_protocol_blocks_get_bit_array(uint8_t data_array[], size_t read_index_bit) { | ||||
|     return bit_read(data_array[read_index_bit >> 3], 7 - (read_index_bit & 0x7)); | ||||
| } | ||||
| 
 | ||||
| size_t subghz_protocol_blocks_get_upload( | ||||
|     uint8_t data_array[], | ||||
|     size_t count_bit_data_array, | ||||
|     LevelDuration* upload, | ||||
|     size_t max_size_upload, | ||||
|     uint32_t duration_bit) { | ||||
|     size_t index_bit = 0; | ||||
|     size_t size_upload = 0; | ||||
|     uint32_t duration = duration_bit; | ||||
|     bool last_bit = subghz_protocol_blocks_get_bit_array(data_array, index_bit++); | ||||
|     for(size_t i = 1; i < count_bit_data_array; i++) { | ||||
|         if(last_bit == subghz_protocol_blocks_get_bit_array(data_array, index_bit)) { | ||||
|             duration += duration_bit; | ||||
|         } else { | ||||
|             furi_assert(max_size_upload > size_upload); | ||||
|             upload[size_upload++] = level_duration_make( | ||||
|                 subghz_protocol_blocks_get_bit_array(data_array, index_bit - 1), duration); | ||||
|             last_bit = !last_bit; | ||||
|             duration = duration_bit; | ||||
|         } | ||||
|         index_bit++; | ||||
|     } | ||||
|     upload[size_upload++] = level_duration_make( | ||||
|         subghz_protocol_blocks_get_bit_array(data_array, index_bit - 1), duration); | ||||
|     return size_upload; | ||||
| } | ||||
| @ -14,3 +14,39 @@ typedef struct { | ||||
|     LevelDuration* upload; | ||||
| 
 | ||||
| } SubGhzProtocolBlockEncoder; | ||||
| 
 | ||||
| /**
 | ||||
|  * Set data bit when encoding HEX array. | ||||
|  * @param bit_value The value of the bit to be set | ||||
|  * @param data_array Pointer to a HEX array | ||||
|  * @param set_index_bit Number set a bit in the array starting from the left | ||||
|  * @param max_size_array array size, check not to overflow | ||||
|  */ | ||||
| void subghz_protocol_blocks_set_bit_array( | ||||
|     bool bit_value, | ||||
|     uint8_t data_array[], | ||||
|     size_t set_index_bit, | ||||
|     size_t max_size_array); | ||||
| 
 | ||||
| /**
 | ||||
|  * Get data bit when encoding HEX array. | ||||
|  * @param data_array Pointer to a HEX array | ||||
|  * @param read_index_bit Number get a bit in the array starting from the left | ||||
|  * @return bool value bit | ||||
|  */ | ||||
| bool subghz_protocol_blocks_get_bit_array(uint8_t data_array[], size_t read_index_bit); | ||||
| 
 | ||||
| /**
 | ||||
|  * Generating an upload from data. | ||||
|  * @param data_array Pointer to a HEX array | ||||
|  * @param count_bit_data_array How many bits in the array are processed | ||||
|  * @param upload Pointer to a LevelDuration | ||||
|  * @param max_size_upload upload size, check not to overflow | ||||
|  * @param duration_bit duration 1 bit | ||||
|  */ | ||||
| size_t subghz_protocol_blocks_get_upload( | ||||
|     uint8_t data_array[], | ||||
|     size_t count_bit_data_array, | ||||
|     LevelDuration* upload, | ||||
|     size_t max_size_upload, | ||||
|     uint32_t duration_bit); | ||||
|  | ||||
| @ -145,7 +145,7 @@ static LevelDuration | ||||
|         break; | ||||
| 
 | ||||
|     default: | ||||
|         furi_crash("SugGhz: ManchesterEncoderResult is incorrect."); | ||||
|         furi_crash("SubGhz: ManchesterEncoderResult is incorrect."); | ||||
|         break; | ||||
|     } | ||||
|     return level_duration_make(data.level, data.duration); | ||||
|  | ||||
							
								
								
									
										483
									
								
								lib/subghz/protocols/chamberlain_code.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										483
									
								
								lib/subghz/protocols/chamberlain_code.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,483 @@ | ||||
| #include "chamberlain_code.h" | ||||
| 
 | ||||
| #include "../blocks/const.h" | ||||
| #include "../blocks/decoder.h" | ||||
| #include "../blocks/encoder.h" | ||||
| #include "../blocks/generic.h" | ||||
| #include "../blocks/math.h" | ||||
| 
 | ||||
| #define TAG "SubGhzProtocolChamb_Code" | ||||
| 
 | ||||
| #define CHAMBERLAIN_CODE_BIT_STOP 0b0001 | ||||
| #define CHAMBERLAIN_CODE_BIT_1 0b0011 | ||||
| #define CHAMBERLAIN_CODE_BIT_0 0b0111 | ||||
| 
 | ||||
| #define CHAMBERLAIN_7_CODE_MASK 0xF000000FF0F | ||||
| #define CHAMBERLAIN_8_CODE_MASK 0xF00000F00F | ||||
| #define CHAMBERLAIN_9_CODE_MASK 0xF000000000F | ||||
| 
 | ||||
| #define CHAMBERLAIN_7_CODE_MASK_CHECK 0x10000001101 | ||||
| #define CHAMBERLAIN_8_CODE_MASK_CHECK 0x1000001001 | ||||
| #define CHAMBERLAIN_9_CODE_MASK_CHECK 0x10000000001 | ||||
| 
 | ||||
| #define CHAMBERLAIN_7_CODE_DIP_PATTERN "%c%c%c%c%c%c%c" | ||||
| #define CHAMBERLAIN_7_CODE_DATA_TO_DIP(dip)                                                 \ | ||||
|     (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') | ||||
| 
 | ||||
| #define CHAMBERLAIN_8_CODE_DIP_PATTERN "%c%c%c%c%cx%c%c" | ||||
| #define CHAMBERLAIN_8_CODE_DATA_TO_DIP(dip)                                                 \ | ||||
|     (dip & 0x0080 ? '1' : '0'), (dip & 0x0040 ? '1' : '0'), (dip & 0x0020 ? '1' : '0'),     \ | ||||
|         (dip & 0x0010 ? '1' : '0'), (dip & 0x0008 ? '1' : '0'), (dip & 0x0001 ? '1' : '0'), \ | ||||
|         (dip & 0x0002 ? '1' : '0') | ||||
| 
 | ||||
| #define CHAMBERLAIN_9_CODE_DIP_PATTERN "%c%c%c%c%c%c%c%c%c" | ||||
| #define CHAMBERLAIN_9_CODE_DATA_TO_DIP(dip)                                                 \ | ||||
|     (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 & 0x0001 ? '1' : '0'), (dip & 0x0002 ? '1' : '0'), (dip & 0x0004 ? '1' : '0') | ||||
| 
 | ||||
| static const SubGhzBlockConst subghz_protocol_chamb_code_const = { | ||||
|     .te_short = 1000, | ||||
|     .te_long = 3000, | ||||
|     .te_delta = 200, | ||||
|     .min_count_bit_for_found = 10, | ||||
| }; | ||||
| 
 | ||||
| struct SubGhzProtocolDecoderChamb_Code { | ||||
|     SubGhzProtocolDecoderBase base; | ||||
| 
 | ||||
|     SubGhzBlockDecoder decoder; | ||||
|     SubGhzBlockGeneric generic; | ||||
| }; | ||||
| 
 | ||||
| struct SubGhzProtocolEncoderChamb_Code { | ||||
|     SubGhzProtocolEncoderBase base; | ||||
| 
 | ||||
|     SubGhzProtocolBlockEncoder encoder; | ||||
|     SubGhzBlockGeneric generic; | ||||
| }; | ||||
| 
 | ||||
| typedef enum { | ||||
|     Chamb_CodeDecoderStepReset = 0, | ||||
|     Chamb_CodeDecoderStepFoundStartBit, | ||||
|     Chamb_CodeDecoderStepSaveDuration, | ||||
|     Chamb_CodeDecoderStepCheckDuration, | ||||
| } Chamb_CodeDecoderStep; | ||||
| 
 | ||||
| const SubGhzProtocolDecoder subghz_protocol_chamb_code_decoder = { | ||||
|     .alloc = subghz_protocol_decoder_chamb_code_alloc, | ||||
|     .free = subghz_protocol_decoder_chamb_code_free, | ||||
| 
 | ||||
|     .feed = subghz_protocol_decoder_chamb_code_feed, | ||||
|     .reset = subghz_protocol_decoder_chamb_code_reset, | ||||
| 
 | ||||
|     .get_hash_data = subghz_protocol_decoder_chamb_code_get_hash_data, | ||||
|     .serialize = subghz_protocol_decoder_chamb_code_serialize, | ||||
|     .deserialize = subghz_protocol_decoder_chamb_code_deserialize, | ||||
|     .get_string = subghz_protocol_decoder_chamb_code_get_string, | ||||
| }; | ||||
| 
 | ||||
| const SubGhzProtocolEncoder subghz_protocol_chamb_code_encoder = { | ||||
|     .alloc = subghz_protocol_encoder_chamb_code_alloc, | ||||
|     .free = subghz_protocol_encoder_chamb_code_free, | ||||
| 
 | ||||
|     .deserialize = subghz_protocol_encoder_chamb_code_deserialize, | ||||
|     .stop = subghz_protocol_encoder_chamb_code_stop, | ||||
|     .yield = subghz_protocol_encoder_chamb_code_yield, | ||||
| }; | ||||
| 
 | ||||
| const SubGhzProtocol subghz_protocol_chamb_code = { | ||||
|     .name = SUBGHZ_PROTOCOL_CHAMB_CODE_NAME, | ||||
|     .type = SubGhzProtocolTypeStatic, | ||||
|     .flag = SubGhzProtocolFlag_315 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | | ||||
|             SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, | ||||
| 
 | ||||
|     .decoder = &subghz_protocol_chamb_code_decoder, | ||||
|     .encoder = &subghz_protocol_chamb_code_encoder, | ||||
| }; | ||||
| 
 | ||||
| void* subghz_protocol_encoder_chamb_code_alloc(SubGhzEnvironment* environment) { | ||||
|     UNUSED(environment); | ||||
|     SubGhzProtocolEncoderChamb_Code* instance = malloc(sizeof(SubGhzProtocolEncoderChamb_Code)); | ||||
| 
 | ||||
|     instance->base.protocol = &subghz_protocol_chamb_code; | ||||
|     instance->generic.protocol_name = instance->base.protocol->name; | ||||
| 
 | ||||
|     instance->encoder.repeat = 10; | ||||
|     instance->encoder.size_upload = 24; | ||||
|     instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); | ||||
|     instance->encoder.is_runing = false; | ||||
|     return instance; | ||||
| } | ||||
| 
 | ||||
| void subghz_protocol_encoder_chamb_code_free(void* context) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolEncoderChamb_Code* instance = context; | ||||
|     free(instance->encoder.upload); | ||||
|     free(instance); | ||||
| } | ||||
| 
 | ||||
| static uint64_t subghz_protocol_chamb_bit_to_code(uint64_t data, uint8_t size) { | ||||
|     uint64_t data_res = 0; | ||||
|     for(uint8_t i = 0; i < size; i++) { | ||||
|         if(!(bit_read(data, size - i - 1))) { | ||||
|             data_res = data_res << 4 | CHAMBERLAIN_CODE_BIT_0; | ||||
|         } else { | ||||
|             data_res = data_res << 4 | CHAMBERLAIN_CODE_BIT_1; | ||||
|         } | ||||
|     } | ||||
|     return data_res; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Generating an upload from data. | ||||
|  * @param instance Pointer to a SubGhzProtocolEncoderChamb_Code instance | ||||
|  * @return true On success | ||||
|  */ | ||||
| static bool | ||||
|     subghz_protocol_encoder_chamb_code_get_upload(SubGhzProtocolEncoderChamb_Code* instance) { | ||||
|     furi_assert(instance); | ||||
| 
 | ||||
|     uint64_t data = subghz_protocol_chamb_bit_to_code( | ||||
|         instance->generic.data, instance->generic.data_count_bit); | ||||
| 
 | ||||
|     switch(instance->generic.data_count_bit) { | ||||
|     case 7: | ||||
|         data = ((data >> 4) << 16) | (data & 0xF) << 4 | CHAMBERLAIN_7_CODE_MASK_CHECK; | ||||
|         break; | ||||
|     case 8: | ||||
|         data = ((data >> 12) << 16) | (data & 0xFF) << 4 | CHAMBERLAIN_8_CODE_MASK_CHECK; | ||||
|         break; | ||||
|     case 9: | ||||
|         data = (data << 4) | CHAMBERLAIN_9_CODE_MASK_CHECK; | ||||
|         break; | ||||
| 
 | ||||
|     default: | ||||
|         furi_crash(TAG " unknown protocol."); | ||||
|         return false; | ||||
|         break; | ||||
|     } | ||||
| #define UPLOAD_HEX_DATA_SIZE 10 | ||||
|     uint8_t upload_hex_data[UPLOAD_HEX_DATA_SIZE] = {0}; | ||||
|     size_t upload_hex_count_bit = 0; | ||||
| 
 | ||||
|     //insert guard time
 | ||||
|     for(uint8_t i = 0; i < 36; i++) { | ||||
|         subghz_protocol_blocks_set_bit_array( | ||||
|             0, upload_hex_data, upload_hex_count_bit++, UPLOAD_HEX_DATA_SIZE); | ||||
|     } | ||||
| 
 | ||||
|     //insert data
 | ||||
|     switch(instance->generic.data_count_bit) { | ||||
|     case 7: | ||||
|     case 9: | ||||
|         for(uint8_t i = 44; i > 0; i--) { | ||||
|             if(!bit_read(data, i - 1)) { | ||||
|                 subghz_protocol_blocks_set_bit_array( | ||||
|                     0, upload_hex_data, upload_hex_count_bit++, UPLOAD_HEX_DATA_SIZE); | ||||
|             } else { | ||||
|                 subghz_protocol_blocks_set_bit_array( | ||||
|                     1, upload_hex_data, upload_hex_count_bit++, UPLOAD_HEX_DATA_SIZE); | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     case 8: | ||||
|         for(uint8_t i = 40; i > 0; i--) { | ||||
|             if(!bit_read(data, i - 1)) { | ||||
|                 subghz_protocol_blocks_set_bit_array( | ||||
|                     0, upload_hex_data, upload_hex_count_bit++, UPLOAD_HEX_DATA_SIZE); | ||||
|             } else { | ||||
|                 subghz_protocol_blocks_set_bit_array( | ||||
|                     1, upload_hex_data, upload_hex_count_bit++, UPLOAD_HEX_DATA_SIZE); | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     instance->encoder.size_upload = subghz_protocol_blocks_get_upload( | ||||
|         upload_hex_data, | ||||
|         upload_hex_count_bit, | ||||
|         instance->encoder.upload, | ||||
|         instance->encoder.size_upload, | ||||
|         subghz_protocol_chamb_code_const.te_short); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool subghz_protocol_encoder_chamb_code_deserialize(void* context, FlipperFormat* flipper_format) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolEncoderChamb_Code* 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_chamb_code_get_upload(instance); | ||||
|         instance->encoder.is_runing = true; | ||||
| 
 | ||||
|         res = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     return res; | ||||
| } | ||||
| 
 | ||||
| void subghz_protocol_encoder_chamb_code_stop(void* context) { | ||||
|     SubGhzProtocolEncoderChamb_Code* instance = context; | ||||
|     instance->encoder.is_runing = false; | ||||
| } | ||||
| 
 | ||||
| LevelDuration subghz_protocol_encoder_chamb_code_yield(void* context) { | ||||
|     SubGhzProtocolEncoderChamb_Code* 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_chamb_code_alloc(SubGhzEnvironment* environment) { | ||||
|     UNUSED(environment); | ||||
|     SubGhzProtocolDecoderChamb_Code* instance = malloc(sizeof(SubGhzProtocolDecoderChamb_Code)); | ||||
|     instance->base.protocol = &subghz_protocol_chamb_code; | ||||
|     instance->generic.protocol_name = instance->base.protocol->name; | ||||
|     return instance; | ||||
| } | ||||
| 
 | ||||
| void subghz_protocol_decoder_chamb_code_free(void* context) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolDecoderChamb_Code* instance = context; | ||||
|     free(instance); | ||||
| } | ||||
| 
 | ||||
| void subghz_protocol_decoder_chamb_code_reset(void* context) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolDecoderChamb_Code* instance = context; | ||||
|     instance->decoder.parser_step = Chamb_CodeDecoderStepReset; | ||||
| } | ||||
| 
 | ||||
| static bool subghz_protocol_chamb_code_to_bit(uint64_t* data, uint8_t size) { | ||||
|     uint64_t data_tmp = data[0]; | ||||
|     uint64_t data_res = 0; | ||||
|     for(uint8_t i = 0; i < size; i++) { | ||||
|         if((data_tmp & 0xF) == CHAMBERLAIN_CODE_BIT_0) { | ||||
|             bit_write(data_res, i, 0); | ||||
|         } else if((data_tmp & 0xF) == CHAMBERLAIN_CODE_BIT_1) { | ||||
|             bit_write(data_res, i, 1); | ||||
|         } else { | ||||
|             return false; | ||||
|         } | ||||
|         data_tmp >>= 4; | ||||
|     } | ||||
|     data[0] = data_res; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| static bool subghz_protocol_decoder_chamb_code_check_mask_and_parse( | ||||
|     SubGhzProtocolDecoderChamb_Code* instance) { | ||||
|     furi_assert(instance); | ||||
|     if(instance->decoder.decode_count_bit > | ||||
|        subghz_protocol_chamb_code_const.min_count_bit_for_found + 1) | ||||
|         return false; | ||||
| 
 | ||||
|     if((instance->decoder.decode_data & CHAMBERLAIN_7_CODE_MASK) == | ||||
|        CHAMBERLAIN_7_CODE_MASK_CHECK) { | ||||
|         instance->decoder.decode_count_bit = 7; | ||||
|         instance->decoder.decode_data &= ~CHAMBERLAIN_7_CODE_MASK; | ||||
|         instance->decoder.decode_data = (instance->decoder.decode_data >> 12) | | ||||
|                                         ((instance->decoder.decode_data >> 4) & 0xF); | ||||
|     } else if( | ||||
|         (instance->decoder.decode_data & CHAMBERLAIN_8_CODE_MASK) == | ||||
|         CHAMBERLAIN_8_CODE_MASK_CHECK) { | ||||
|         instance->decoder.decode_count_bit = 8; | ||||
|         instance->decoder.decode_data &= ~CHAMBERLAIN_8_CODE_MASK; | ||||
|         instance->decoder.decode_data = instance->decoder.decode_data >> 4 | | ||||
|                                         CHAMBERLAIN_CODE_BIT_0 << 8; //DIP 6 no use
 | ||||
|     } else if( | ||||
|         (instance->decoder.decode_data & CHAMBERLAIN_9_CODE_MASK) == | ||||
|         CHAMBERLAIN_9_CODE_MASK_CHECK) { | ||||
|         instance->decoder.decode_count_bit = 9; | ||||
|         instance->decoder.decode_data &= ~CHAMBERLAIN_9_CODE_MASK; | ||||
|         instance->decoder.decode_data >>= 4; | ||||
|     } else { | ||||
|         return false; | ||||
|     } | ||||
|     return subghz_protocol_chamb_code_to_bit( | ||||
|         &instance->decoder.decode_data, instance->decoder.decode_count_bit); | ||||
| } | ||||
| 
 | ||||
| void subghz_protocol_decoder_chamb_code_feed(void* context, bool level, uint32_t duration) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolDecoderChamb_Code* instance = context; | ||||
|     switch(instance->decoder.parser_step) { | ||||
|     case Chamb_CodeDecoderStepReset: | ||||
|         if((!level) && (DURATION_DIFF(duration, subghz_protocol_chamb_code_const.te_short * 39) < | ||||
|                         subghz_protocol_chamb_code_const.te_delta * 20)) { | ||||
|             //Found header Chamb_Code
 | ||||
|             instance->decoder.parser_step = Chamb_CodeDecoderStepFoundStartBit; | ||||
|         } | ||||
|         break; | ||||
|     case Chamb_CodeDecoderStepFoundStartBit: | ||||
|         if((level) && (DURATION_DIFF(duration, subghz_protocol_chamb_code_const.te_short) < | ||||
|                        subghz_protocol_chamb_code_const.te_delta)) { | ||||
|             //Found start bit Chamb_Code
 | ||||
|             instance->decoder.decode_data = 0; | ||||
|             instance->decoder.decode_count_bit = 0; | ||||
|             instance->decoder.decode_data = instance->decoder.decode_data << 4 | | ||||
|                                             CHAMBERLAIN_CODE_BIT_STOP; | ||||
|             instance->decoder.decode_count_bit++; | ||||
|             instance->decoder.parser_step = Chamb_CodeDecoderStepSaveDuration; | ||||
|         } else { | ||||
|             instance->decoder.parser_step = Chamb_CodeDecoderStepReset; | ||||
|         } | ||||
|         break; | ||||
|     case Chamb_CodeDecoderStepSaveDuration: | ||||
|         if(!level) { //save interval
 | ||||
|             if(duration > subghz_protocol_chamb_code_const.te_short * 5) { | ||||
|                 if(instance->decoder.decode_count_bit >= | ||||
|                    subghz_protocol_chamb_code_const.min_count_bit_for_found) { | ||||
|                     instance->generic.serial = 0x0; | ||||
|                     instance->generic.btn = 0x0; | ||||
|                     if(subghz_protocol_decoder_chamb_code_check_mask_and_parse(instance)) { | ||||
|                         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.parser_step = Chamb_CodeDecoderStepReset; | ||||
|             } else { | ||||
|                 instance->decoder.te_last = duration; | ||||
|                 instance->decoder.parser_step = Chamb_CodeDecoderStepCheckDuration; | ||||
|             } | ||||
|         } else { | ||||
|             instance->decoder.parser_step = Chamb_CodeDecoderStepReset; | ||||
|         } | ||||
|         break; | ||||
|     case Chamb_CodeDecoderStepCheckDuration: | ||||
|         if(level) { | ||||
|             if((DURATION_DIFF( //Found stop bit Chamb_Code
 | ||||
|                     instance->decoder.te_last, | ||||
|                     subghz_protocol_chamb_code_const.te_short * 3) < | ||||
|                 subghz_protocol_chamb_code_const.te_delta) && | ||||
|                (DURATION_DIFF(duration, subghz_protocol_chamb_code_const.te_short) < | ||||
|                 subghz_protocol_chamb_code_const.te_delta)) { | ||||
|                 instance->decoder.decode_data = instance->decoder.decode_data << 4 | | ||||
|                                                 CHAMBERLAIN_CODE_BIT_STOP; | ||||
|                 instance->decoder.decode_count_bit++; | ||||
|                 instance->decoder.parser_step = Chamb_CodeDecoderStepSaveDuration; | ||||
|             } else if( | ||||
|                 (DURATION_DIFF( | ||||
|                      instance->decoder.te_last, subghz_protocol_chamb_code_const.te_short * 2) < | ||||
|                  subghz_protocol_chamb_code_const.te_delta) && | ||||
|                 (DURATION_DIFF(duration, subghz_protocol_chamb_code_const.te_short * 2) < | ||||
|                  subghz_protocol_chamb_code_const.te_delta)) { | ||||
|                 instance->decoder.decode_data = instance->decoder.decode_data << 4 | | ||||
|                                                 CHAMBERLAIN_CODE_BIT_1; | ||||
|                 instance->decoder.decode_count_bit++; | ||||
|                 instance->decoder.parser_step = Chamb_CodeDecoderStepSaveDuration; | ||||
|             } else if( | ||||
|                 (DURATION_DIFF( | ||||
|                      instance->decoder.te_last, subghz_protocol_chamb_code_const.te_short) < | ||||
|                  subghz_protocol_chamb_code_const.te_delta) && | ||||
|                 (DURATION_DIFF(duration, subghz_protocol_chamb_code_const.te_short * 3) < | ||||
|                  subghz_protocol_chamb_code_const.te_delta)) { | ||||
|                 instance->decoder.decode_data = instance->decoder.decode_data << 4 | | ||||
|                                                 CHAMBERLAIN_CODE_BIT_0; | ||||
|                 instance->decoder.decode_count_bit++; | ||||
|                 instance->decoder.parser_step = Chamb_CodeDecoderStepSaveDuration; | ||||
|             } else { | ||||
|                 instance->decoder.parser_step = Chamb_CodeDecoderStepReset; | ||||
|             } | ||||
| 
 | ||||
|         } else { | ||||
|             instance->decoder.parser_step = Chamb_CodeDecoderStepReset; | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| uint8_t subghz_protocol_decoder_chamb_code_get_hash_data(void* context) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolDecoderChamb_Code* instance = context; | ||||
|     return subghz_protocol_blocks_get_hash_data( | ||||
|         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||
| } | ||||
| 
 | ||||
| bool subghz_protocol_decoder_chamb_code_serialize( | ||||
|     void* context, | ||||
|     FlipperFormat* flipper_format, | ||||
|     uint32_t frequency, | ||||
|     FuriHalSubGhzPreset preset) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolDecoderChamb_Code* instance = context; | ||||
|     return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||
| } | ||||
| 
 | ||||
| bool subghz_protocol_decoder_chamb_code_deserialize(void* context, FlipperFormat* flipper_format) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolDecoderChamb_Code* instance = context; | ||||
|     return subghz_block_generic_deserialize(&instance->generic, flipper_format); | ||||
| } | ||||
| 
 | ||||
| void subghz_protocol_decoder_chamb_code_get_string(void* context, string_t output) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolDecoderChamb_Code* 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 %db\r\n" | ||||
|         "Key:0x%03lX\r\n" | ||||
|         "Yek:0x%03lX\r\n", | ||||
|         instance->generic.protocol_name, | ||||
|         instance->generic.data_count_bit, | ||||
|         code_found_lo, | ||||
|         code_found_reverse_lo); | ||||
| 
 | ||||
|     switch(instance->generic.data_count_bit) { | ||||
|     case 7: | ||||
|         string_cat_printf( | ||||
|             output, | ||||
|             "DIP:" CHAMBERLAIN_7_CODE_DIP_PATTERN "\r\n", | ||||
|             CHAMBERLAIN_7_CODE_DATA_TO_DIP(code_found_lo)); | ||||
|         break; | ||||
|     case 8: | ||||
|         string_cat_printf( | ||||
|             output, | ||||
|             "DIP:" CHAMBERLAIN_8_CODE_DIP_PATTERN "\r\n", | ||||
|             CHAMBERLAIN_8_CODE_DATA_TO_DIP(code_found_lo)); | ||||
|         break; | ||||
|     case 9: | ||||
|         string_cat_printf( | ||||
|             output, | ||||
|             "DIP:" CHAMBERLAIN_9_CODE_DIP_PATTERN "\r\n", | ||||
|             CHAMBERLAIN_9_CODE_DATA_TO_DIP(code_found_lo)); | ||||
|         break; | ||||
| 
 | ||||
|     default: | ||||
|         break; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										109
									
								
								lib/subghz/protocols/chamberlain_code.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								lib/subghz/protocols/chamberlain_code.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,109 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "base.h" | ||||
| 
 | ||||
| #define SUBGHZ_PROTOCOL_CHAMB_CODE_NAME "Cham_Code" | ||||
| 
 | ||||
| typedef struct SubGhzProtocolDecoderChamb_Code SubGhzProtocolDecoderChamb_Code; | ||||
| typedef struct SubGhzProtocolEncoderChamb_Code SubGhzProtocolEncoderChamb_Code; | ||||
| 
 | ||||
| extern const SubGhzProtocolDecoder subghz_protocol_chamb_code_decoder; | ||||
| extern const SubGhzProtocolEncoder subghz_protocol_chamb_code_encoder; | ||||
| extern const SubGhzProtocol subghz_protocol_chamb_code; | ||||
| 
 | ||||
| /**
 | ||||
|  * Allocate SubGhzProtocolEncoderChamb_Code. | ||||
|  * @param environment Pointer to a SubGhzEnvironment instance | ||||
|  * @return SubGhzProtocolEncoderChamb_Code* pointer to a SubGhzProtocolEncoderChamb_Code instance | ||||
|  */ | ||||
| void* subghz_protocol_encoder_chamb_code_alloc(SubGhzEnvironment* environment); | ||||
| 
 | ||||
| /**
 | ||||
|  * Free SubGhzProtocolEncoderChamb_Code. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderChamb_Code instance | ||||
|  */ | ||||
| void subghz_protocol_encoder_chamb_code_free(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Deserialize and generating an upload to send. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderChamb_Code instance | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
|  * @return true On success | ||||
|  */ | ||||
| bool subghz_protocol_encoder_chamb_code_deserialize(void* context, FlipperFormat* flipper_format); | ||||
| 
 | ||||
| /**
 | ||||
|  * Forced transmission stop. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderChamb_Code instance | ||||
|  */ | ||||
| void subghz_protocol_encoder_chamb_code_stop(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Getting the level and duration of the upload to be loaded into DMA. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderChamb_Code instance | ||||
|  * @return LevelDuration  | ||||
|  */ | ||||
| LevelDuration subghz_protocol_encoder_chamb_code_yield(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Allocate SubGhzProtocolDecoderChamb_Code. | ||||
|  * @param environment Pointer to a SubGhzEnvironment instance | ||||
|  * @return SubGhzProtocolDecoderChamb_Code* pointer to a SubGhzProtocolDecoderChamb_Code instance | ||||
|  */ | ||||
| void* subghz_protocol_decoder_chamb_code_alloc(SubGhzEnvironment* environment); | ||||
| 
 | ||||
| /**
 | ||||
|  * Free SubGhzProtocolDecoderChamb_Code. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderChamb_Code instance | ||||
|  */ | ||||
| void subghz_protocol_decoder_chamb_code_free(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Reset decoder SubGhzProtocolDecoderChamb_Code. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderChamb_Code instance | ||||
|  */ | ||||
| void subghz_protocol_decoder_chamb_code_reset(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Parse a raw sequence of levels and durations received from the air. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderChamb_Code instance | ||||
|  * @param level Signal level true-high false-low | ||||
|  * @param duration Duration of this level in, us | ||||
|  */ | ||||
| void subghz_protocol_decoder_chamb_code_feed(void* context, bool level, uint32_t duration); | ||||
| 
 | ||||
| /**
 | ||||
|  * Getting the hash sum of the last randomly received parcel. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderChamb_Code instance | ||||
|  * @return hash Hash sum | ||||
|  */ | ||||
| uint8_t subghz_protocol_decoder_chamb_code_get_hash_data(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Serialize data SubGhzProtocolDecoderChamb_Code. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderChamb_Code instance | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
|  * @param frequency The frequency at which the signal was received, Hz | ||||
|  * @param preset The modulation on which the signal was received, FuriHalSubGhzPreset | ||||
|  * @return true On success | ||||
|  */ | ||||
| bool subghz_protocol_decoder_chamb_code_serialize( | ||||
|     void* context, | ||||
|     FlipperFormat* flipper_format, | ||||
|     uint32_t frequency, | ||||
|     FuriHalSubGhzPreset preset); | ||||
| 
 | ||||
| /**
 | ||||
|  * Deserialize data SubGhzProtocolDecoderChamb_Code. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderChamb_Code instance | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
|  * @return true On success | ||||
|  */ | ||||
| bool subghz_protocol_decoder_chamb_code_deserialize(void* context, FlipperFormat* flipper_format); | ||||
| 
 | ||||
| /**
 | ||||
|  * Getting a textual representation of the received data. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderChamb_Code instance | ||||
|  * @param output Resulting text | ||||
|  */ | ||||
| void subghz_protocol_decoder_chamb_code_get_string(void* context, string_t output); | ||||
| @ -1,109 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "base.h" | ||||
| 
 | ||||
| #define SUBGHZ_PROTOCOL_FIREFLY_NAME "Firefly" | ||||
| 
 | ||||
| typedef struct SubGhzProtocolDecoderFirefly SubGhzProtocolDecoderFirefly; | ||||
| typedef struct SubGhzProtocolEncoderFirefly SubGhzProtocolEncoderFirefly; | ||||
| 
 | ||||
| extern const SubGhzProtocolDecoder subghz_protocol_firefly_decoder; | ||||
| extern const SubGhzProtocolEncoder subghz_protocol_firefly_encoder; | ||||
| extern const SubGhzProtocol subghz_protocol_firefly; | ||||
| 
 | ||||
| /**
 | ||||
|  * Allocate SubGhzProtocolEncoderFirefly. | ||||
|  * @param environment Pointer to a SubGhzEnvironment instance | ||||
|  * @return SubGhzProtocolEncoderFirefly* pointer to a SubGhzProtocolEncoderFirefly instance | ||||
|  */ | ||||
| void* subghz_protocol_encoder_firefly_alloc(SubGhzEnvironment* environment); | ||||
| 
 | ||||
| /**
 | ||||
|  * Free SubGhzProtocolEncoderFirefly. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderFirefly instance | ||||
|  */ | ||||
| void subghz_protocol_encoder_firefly_free(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Deserialize and generating an upload to send. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderFirefly instance | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
|  * @return true On success | ||||
|  */ | ||||
| bool subghz_protocol_encoder_firefly_deserialize(void* context, FlipperFormat* flipper_format); | ||||
| 
 | ||||
| /**
 | ||||
|  * Forced transmission stop. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderFirefly instance | ||||
|  */ | ||||
| void subghz_protocol_encoder_firefly_stop(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Getting the level and duration of the upload to be loaded into DMA. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderFirefly instance | ||||
|  * @return LevelDuration  | ||||
|  */ | ||||
| LevelDuration subghz_protocol_encoder_firefly_yield(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Allocate SubGhzProtocolDecoderFirefly. | ||||
|  * @param environment Pointer to a SubGhzEnvironment instance | ||||
|  * @return SubGhzProtocolDecoderFirefly* pointer to a SubGhzProtocolDecoderFirefly instance | ||||
|  */ | ||||
| void* subghz_protocol_decoder_firefly_alloc(SubGhzEnvironment* environment); | ||||
| 
 | ||||
| /**
 | ||||
|  * Free SubGhzProtocolDecoderFirefly. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderFirefly instance | ||||
|  */ | ||||
| void subghz_protocol_decoder_firefly_free(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Reset decoder SubGhzProtocolDecoderFirefly. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderFirefly instance | ||||
|  */ | ||||
| void subghz_protocol_decoder_firefly_reset(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Parse a raw sequence of levels and durations received from the air. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderFirefly instance | ||||
|  * @param level Signal level true-high false-low | ||||
|  * @param duration Duration of this level in, us | ||||
|  */ | ||||
| void subghz_protocol_decoder_firefly_feed(void* context, bool level, uint32_t duration); | ||||
| 
 | ||||
| /**
 | ||||
|  * Getting the hash sum of the last randomly received parcel. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderFirefly instance | ||||
|  * @return hash Hash sum | ||||
|  */ | ||||
| uint8_t subghz_protocol_decoder_firefly_get_hash_data(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Serialize data SubGhzProtocolDecoderFirefly. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderFirefly instance | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
|  * @param frequency The frequency at which the signal was received, Hz | ||||
|  * @param preset The modulation on which the signal was received, FuriHalSubGhzPreset | ||||
|  * @return true On success | ||||
|  */ | ||||
| bool subghz_protocol_decoder_firefly_serialize( | ||||
|     void* context, | ||||
|     FlipperFormat* flipper_format, | ||||
|     uint32_t frequency, | ||||
|     FuriHalSubGhzPreset preset); | ||||
| 
 | ||||
| /**
 | ||||
|  * Deserialize data SubGhzProtocolDecoderFirefly. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderFirefly instance | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
|  * @return true On success | ||||
|  */ | ||||
| bool subghz_protocol_decoder_firefly_deserialize(void* context, FlipperFormat* flipper_format); | ||||
| 
 | ||||
| /**
 | ||||
|  * Getting a textual representation of the received data. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderFirefly instance | ||||
|  * @param output Resulting text | ||||
|  */ | ||||
| void subghz_protocol_decoder_firefly_get_string(void* context, string_t output); | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "firefly.h" | ||||
| #include "linear.h" | ||||
| 
 | ||||
| #include "../blocks/const.h" | ||||
| #include "../blocks/decoder.h" | ||||
| @ -6,7 +6,7 @@ | ||||
| #include "../blocks/generic.h" | ||||
| #include "../blocks/math.h" | ||||
| 
 | ||||
| #define TAG "SubGhzProtocolFirefly" | ||||
| #define TAG "SubGhzProtocolLinear" | ||||
| 
 | ||||
| #define DIP_PATTERN "%c%c%c%c%c%c%c%c%c%c" | ||||
| #define DATA_TO_DIP(dip)                                                                    \ | ||||
| @ -15,21 +15,21 @@ | ||||
|         (dip & 0x0008 ? '1' : '0'), (dip & 0x0004 ? '1' : '0'), (dip & 0x0002 ? '1' : '0'), \ | ||||
|         (dip & 0x0001 ? '1' : '0') | ||||
| 
 | ||||
| static const SubGhzBlockConst subghz_protocol_firefly_const = { | ||||
| static const SubGhzBlockConst subghz_protocol_linear_const = { | ||||
|     .te_short = 500, | ||||
|     .te_long = 1500, | ||||
|     .te_delta = 150, | ||||
|     .min_count_bit_for_found = 10, | ||||
| }; | ||||
| 
 | ||||
| struct SubGhzProtocolDecoderFirefly { | ||||
| struct SubGhzProtocolDecoderLinear { | ||||
|     SubGhzProtocolDecoderBase base; | ||||
| 
 | ||||
|     SubGhzBlockDecoder decoder; | ||||
|     SubGhzBlockGeneric generic; | ||||
| }; | ||||
| 
 | ||||
| struct SubGhzProtocolEncoderFirefly { | ||||
| struct SubGhzProtocolEncoderLinear { | ||||
|     SubGhzProtocolEncoderBase base; | ||||
| 
 | ||||
|     SubGhzProtocolBlockEncoder encoder; | ||||
| @ -37,48 +37,48 @@ struct SubGhzProtocolEncoderFirefly { | ||||
| }; | ||||
| 
 | ||||
| typedef enum { | ||||
|     FireflyDecoderStepReset = 0, | ||||
|     FireflyDecoderStepSaveDuration, | ||||
|     FireflyDecoderStepCheckDuration, | ||||
| } FireflyDecoderStep; | ||||
|     LinearDecoderStepReset = 0, | ||||
|     LinearDecoderStepSaveDuration, | ||||
|     LinearDecoderStepCheckDuration, | ||||
| } LinearDecoderStep; | ||||
| 
 | ||||
| const SubGhzProtocolDecoder subghz_protocol_firefly_decoder = { | ||||
|     .alloc = subghz_protocol_decoder_firefly_alloc, | ||||
|     .free = subghz_protocol_decoder_firefly_free, | ||||
| const SubGhzProtocolDecoder subghz_protocol_linear_decoder = { | ||||
|     .alloc = subghz_protocol_decoder_linear_alloc, | ||||
|     .free = subghz_protocol_decoder_linear_free, | ||||
| 
 | ||||
|     .feed = subghz_protocol_decoder_firefly_feed, | ||||
|     .reset = subghz_protocol_decoder_firefly_reset, | ||||
|     .feed = subghz_protocol_decoder_linear_feed, | ||||
|     .reset = subghz_protocol_decoder_linear_reset, | ||||
| 
 | ||||
|     .get_hash_data = subghz_protocol_decoder_firefly_get_hash_data, | ||||
|     .serialize = subghz_protocol_decoder_firefly_serialize, | ||||
|     .deserialize = subghz_protocol_decoder_firefly_deserialize, | ||||
|     .get_string = subghz_protocol_decoder_firefly_get_string, | ||||
|     .get_hash_data = subghz_protocol_decoder_linear_get_hash_data, | ||||
|     .serialize = subghz_protocol_decoder_linear_serialize, | ||||
|     .deserialize = subghz_protocol_decoder_linear_deserialize, | ||||
|     .get_string = subghz_protocol_decoder_linear_get_string, | ||||
| }; | ||||
| 
 | ||||
| const SubGhzProtocolEncoder subghz_protocol_firefly_encoder = { | ||||
|     .alloc = subghz_protocol_encoder_firefly_alloc, | ||||
|     .free = subghz_protocol_encoder_firefly_free, | ||||
| const SubGhzProtocolEncoder subghz_protocol_linear_encoder = { | ||||
|     .alloc = subghz_protocol_encoder_linear_alloc, | ||||
|     .free = subghz_protocol_encoder_linear_free, | ||||
| 
 | ||||
|     .deserialize = subghz_protocol_encoder_firefly_deserialize, | ||||
|     .stop = subghz_protocol_encoder_firefly_stop, | ||||
|     .yield = subghz_protocol_encoder_firefly_yield, | ||||
|     .deserialize = subghz_protocol_encoder_linear_deserialize, | ||||
|     .stop = subghz_protocol_encoder_linear_stop, | ||||
|     .yield = subghz_protocol_encoder_linear_yield, | ||||
| }; | ||||
| 
 | ||||
| const SubGhzProtocol subghz_protocol_firefly = { | ||||
|     .name = SUBGHZ_PROTOCOL_FIREFLY_NAME, | ||||
| const SubGhzProtocol subghz_protocol_linear = { | ||||
|     .name = SUBGHZ_PROTOCOL_LINEAR_NAME, | ||||
|     .type = SubGhzProtocolTypeStatic, | ||||
|     .flag = SubGhzProtocolFlag_315 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | | ||||
|             SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, | ||||
| 
 | ||||
|     .decoder = &subghz_protocol_firefly_decoder, | ||||
|     .encoder = &subghz_protocol_firefly_encoder, | ||||
|     .decoder = &subghz_protocol_linear_decoder, | ||||
|     .encoder = &subghz_protocol_linear_encoder, | ||||
| }; | ||||
| 
 | ||||
| void* subghz_protocol_encoder_firefly_alloc(SubGhzEnvironment* environment) { | ||||
| void* subghz_protocol_encoder_linear_alloc(SubGhzEnvironment* environment) { | ||||
|     UNUSED(environment); | ||||
|     SubGhzProtocolEncoderFirefly* instance = malloc(sizeof(SubGhzProtocolEncoderFirefly)); | ||||
|     SubGhzProtocolEncoderLinear* instance = malloc(sizeof(SubGhzProtocolEncoderLinear)); | ||||
| 
 | ||||
|     instance->base.protocol = &subghz_protocol_firefly; | ||||
|     instance->base.protocol = &subghz_protocol_linear; | ||||
|     instance->generic.protocol_name = instance->base.protocol->name; | ||||
| 
 | ||||
|     instance->encoder.repeat = 10; | ||||
| @ -88,19 +88,19 @@ void* subghz_protocol_encoder_firefly_alloc(SubGhzEnvironment* environment) { | ||||
|     return instance; | ||||
| } | ||||
| 
 | ||||
| void subghz_protocol_encoder_firefly_free(void* context) { | ||||
| void subghz_protocol_encoder_linear_free(void* context) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolEncoderFirefly* instance = context; | ||||
|     SubGhzProtocolEncoderLinear* instance = context; | ||||
|     free(instance->encoder.upload); | ||||
|     free(instance); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Generating an upload from data. | ||||
|  * @param instance Pointer to a SubGhzProtocolEncoderFirefly instance | ||||
|  * @param instance Pointer to a SubGhzProtocolEncoderLinear instance | ||||
|  * @return true On success | ||||
|  */ | ||||
| static bool subghz_protocol_encoder_firefly_get_upload(SubGhzProtocolEncoderFirefly* instance) { | ||||
| static bool subghz_protocol_encoder_linear_get_upload(SubGhzProtocolEncoderLinear* instance) { | ||||
|     furi_assert(instance); | ||||
|     size_t index = 0; | ||||
|     size_t size_upload = (instance->generic.data_count_bit * 2); | ||||
| @ -116,40 +116,40 @@ static bool subghz_protocol_encoder_firefly_get_upload(SubGhzProtocolEncoderFire | ||||
|         if(bit_read(instance->generic.data, i - 1)) { | ||||
|             //send bit 1
 | ||||
|             instance->encoder.upload[index++] = | ||||
|                 level_duration_make(true, (uint32_t)subghz_protocol_firefly_const.te_short * 3); | ||||
|                 level_duration_make(true, (uint32_t)subghz_protocol_linear_const.te_short * 3); | ||||
|             instance->encoder.upload[index++] = | ||||
|                 level_duration_make(false, (uint32_t)subghz_protocol_firefly_const.te_short); | ||||
|                 level_duration_make(false, (uint32_t)subghz_protocol_linear_const.te_short); | ||||
|         } else { | ||||
|             //send bit 0
 | ||||
|             instance->encoder.upload[index++] = | ||||
|                 level_duration_make(true, (uint32_t)subghz_protocol_firefly_const.te_short); | ||||
|                 level_duration_make(true, (uint32_t)subghz_protocol_linear_const.te_short); | ||||
|             instance->encoder.upload[index++] = | ||||
|                 level_duration_make(false, (uint32_t)subghz_protocol_firefly_const.te_short * 3); | ||||
|                 level_duration_make(false, (uint32_t)subghz_protocol_linear_const.te_short * 3); | ||||
|         } | ||||
|     } | ||||
|     //Send end bit
 | ||||
|     if(bit_read(instance->generic.data, 0)) { | ||||
|         //send bit 1
 | ||||
|         instance->encoder.upload[index++] = | ||||
|             level_duration_make(true, (uint32_t)subghz_protocol_firefly_const.te_short * 3); | ||||
|             level_duration_make(true, (uint32_t)subghz_protocol_linear_const.te_short * 3); | ||||
|         //Send PT_GUARD
 | ||||
|         instance->encoder.upload[index++] = | ||||
|             level_duration_make(false, (uint32_t)subghz_protocol_firefly_const.te_short * 42); | ||||
|             level_duration_make(false, (uint32_t)subghz_protocol_linear_const.te_short * 42); | ||||
|     } else { | ||||
|         //send bit 0
 | ||||
|         instance->encoder.upload[index++] = | ||||
|             level_duration_make(true, (uint32_t)subghz_protocol_firefly_const.te_short); | ||||
|             level_duration_make(true, (uint32_t)subghz_protocol_linear_const.te_short); | ||||
|         //Send PT_GUARD
 | ||||
|         instance->encoder.upload[index++] = | ||||
|             level_duration_make(false, (uint32_t)subghz_protocol_firefly_const.te_short * 44); | ||||
|             level_duration_make(false, (uint32_t)subghz_protocol_linear_const.te_short * 44); | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool subghz_protocol_encoder_firefly_deserialize(void* context, FlipperFormat* flipper_format) { | ||||
| bool subghz_protocol_encoder_linear_deserialize(void* context, FlipperFormat* flipper_format) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolEncoderFirefly* instance = context; | ||||
|     SubGhzProtocolEncoderLinear* instance = context; | ||||
|     bool res = false; | ||||
|     do { | ||||
|         if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { | ||||
| @ -161,7 +161,7 @@ bool subghz_protocol_encoder_firefly_deserialize(void* context, FlipperFormat* f | ||||
|         flipper_format_read_uint32( | ||||
|             flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); | ||||
| 
 | ||||
|         subghz_protocol_encoder_firefly_get_upload(instance); | ||||
|         subghz_protocol_encoder_linear_get_upload(instance); | ||||
|         instance->encoder.is_runing = true; | ||||
| 
 | ||||
|         res = true; | ||||
| @ -170,13 +170,13 @@ bool subghz_protocol_encoder_firefly_deserialize(void* context, FlipperFormat* f | ||||
|     return res; | ||||
| } | ||||
| 
 | ||||
| void subghz_protocol_encoder_firefly_stop(void* context) { | ||||
|     SubGhzProtocolEncoderFirefly* instance = context; | ||||
| void subghz_protocol_encoder_linear_stop(void* context) { | ||||
|     SubGhzProtocolEncoderLinear* instance = context; | ||||
|     instance->encoder.is_runing = false; | ||||
| } | ||||
| 
 | ||||
| LevelDuration subghz_protocol_encoder_firefly_yield(void* context) { | ||||
|     SubGhzProtocolEncoderFirefly* instance = context; | ||||
| LevelDuration subghz_protocol_encoder_linear_yield(void* context) { | ||||
|     SubGhzProtocolEncoderLinear* instance = context; | ||||
| 
 | ||||
|     if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { | ||||
|         instance->encoder.is_runing = false; | ||||
| @ -193,68 +193,66 @@ LevelDuration subghz_protocol_encoder_firefly_yield(void* context) { | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| void* subghz_protocol_decoder_firefly_alloc(SubGhzEnvironment* environment) { | ||||
| void* subghz_protocol_decoder_linear_alloc(SubGhzEnvironment* environment) { | ||||
|     UNUSED(environment); | ||||
|     SubGhzProtocolDecoderFirefly* instance = malloc(sizeof(SubGhzProtocolDecoderFirefly)); | ||||
|     instance->base.protocol = &subghz_protocol_firefly; | ||||
|     SubGhzProtocolDecoderLinear* instance = malloc(sizeof(SubGhzProtocolDecoderLinear)); | ||||
|     instance->base.protocol = &subghz_protocol_linear; | ||||
|     instance->generic.protocol_name = instance->base.protocol->name; | ||||
|     return instance; | ||||
| } | ||||
| 
 | ||||
| void subghz_protocol_decoder_firefly_free(void* context) { | ||||
| void subghz_protocol_decoder_linear_free(void* context) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolDecoderFirefly* instance = context; | ||||
|     SubGhzProtocolDecoderLinear* instance = context; | ||||
|     free(instance); | ||||
| } | ||||
| 
 | ||||
| void subghz_protocol_decoder_firefly_reset(void* context) { | ||||
| void subghz_protocol_decoder_linear_reset(void* context) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolDecoderFirefly* instance = context; | ||||
|     instance->decoder.parser_step = FireflyDecoderStepReset; | ||||
|     SubGhzProtocolDecoderLinear* instance = context; | ||||
|     instance->decoder.parser_step = LinearDecoderStepReset; | ||||
| } | ||||
| 
 | ||||
| void subghz_protocol_decoder_firefly_feed(void* context, bool level, uint32_t duration) { | ||||
| void subghz_protocol_decoder_linear_feed(void* context, bool level, uint32_t duration) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolDecoderFirefly* instance = context; | ||||
|     SubGhzProtocolDecoderLinear* instance = context; | ||||
|     switch(instance->decoder.parser_step) { | ||||
|     case FireflyDecoderStepReset: | ||||
|         if((!level) && (DURATION_DIFF(duration, subghz_protocol_firefly_const.te_short * 42) < | ||||
|                         subghz_protocol_firefly_const.te_delta * 20)) { | ||||
|             //Found header Firefly
 | ||||
|     case LinearDecoderStepReset: | ||||
|         if((!level) && (DURATION_DIFF(duration, subghz_protocol_linear_const.te_short * 42) < | ||||
|                         subghz_protocol_linear_const.te_delta * 20)) { | ||||
|             //Found header Linear
 | ||||
|             instance->decoder.decode_data = 0; | ||||
|             instance->decoder.decode_count_bit = 0; | ||||
|             instance->decoder.parser_step = FireflyDecoderStepSaveDuration; | ||||
|             instance->decoder.parser_step = LinearDecoderStepSaveDuration; | ||||
|         } | ||||
|         break; | ||||
|     case FireflyDecoderStepSaveDuration: | ||||
|     case LinearDecoderStepSaveDuration: | ||||
|         if(level) { | ||||
|             instance->decoder.te_last = duration; | ||||
|             instance->decoder.parser_step = FireflyDecoderStepCheckDuration; | ||||
|             instance->decoder.parser_step = LinearDecoderStepCheckDuration; | ||||
|         } else { | ||||
|             instance->decoder.parser_step = FireflyDecoderStepReset; | ||||
|             instance->decoder.parser_step = LinearDecoderStepReset; | ||||
|         } | ||||
|         break; | ||||
|     case FireflyDecoderStepCheckDuration: | ||||
|     case LinearDecoderStepCheckDuration: | ||||
|         if(!level) { //save interval
 | ||||
|             if(duration >= (subghz_protocol_firefly_const.te_short * 5)) { | ||||
|                 instance->decoder.parser_step = FireflyDecoderStepReset; | ||||
|             if(duration >= (subghz_protocol_linear_const.te_short * 5)) { | ||||
|                 instance->decoder.parser_step = LinearDecoderStepReset; | ||||
|                 //checking that the duration matches the guardtime
 | ||||
|                 if((DURATION_DIFF(duration, subghz_protocol_firefly_const.te_short * 42) > | ||||
|                     subghz_protocol_firefly_const.te_delta * 20)) { | ||||
|                 if((DURATION_DIFF(duration, subghz_protocol_linear_const.te_short * 42) > | ||||
|                     subghz_protocol_linear_const.te_delta * 20)) { | ||||
|                     break; | ||||
|                 } | ||||
|                 if(DURATION_DIFF( | ||||
|                        instance->decoder.te_last, subghz_protocol_firefly_const.te_short) < | ||||
|                    subghz_protocol_firefly_const.te_delta) { | ||||
|                 if(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_linear_const.te_short) < | ||||
|                    subghz_protocol_linear_const.te_delta) { | ||||
|                     subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||
|                 } else if( | ||||
|                     DURATION_DIFF( | ||||
|                         instance->decoder.te_last, subghz_protocol_firefly_const.te_long) < | ||||
|                     subghz_protocol_firefly_const.te_delta) { | ||||
|                     DURATION_DIFF(instance->decoder.te_last, subghz_protocol_linear_const.te_long) < | ||||
|                     subghz_protocol_linear_const.te_delta) { | ||||
|                     subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||
|                 } | ||||
|                 if(instance->decoder.decode_count_bit == | ||||
|                    subghz_protocol_firefly_const.min_count_bit_for_found) { | ||||
|                    subghz_protocol_linear_const.min_count_bit_for_found) { | ||||
|                     instance->generic.serial = 0x0; | ||||
|                     instance->generic.btn = 0x0; | ||||
| 
 | ||||
| @ -267,56 +265,56 @@ void subghz_protocol_decoder_firefly_feed(void* context, bool level, uint32_t du | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_firefly_const.te_short) < | ||||
|                 subghz_protocol_firefly_const.te_delta) && | ||||
|                (DURATION_DIFF(duration, subghz_protocol_firefly_const.te_long) < | ||||
|                 subghz_protocol_firefly_const.te_delta)) { | ||||
|             if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_linear_const.te_short) < | ||||
|                 subghz_protocol_linear_const.te_delta) && | ||||
|                (DURATION_DIFF(duration, subghz_protocol_linear_const.te_long) < | ||||
|                 subghz_protocol_linear_const.te_delta)) { | ||||
|                 subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||
|                 instance->decoder.parser_step = FireflyDecoderStepSaveDuration; | ||||
|                 instance->decoder.parser_step = LinearDecoderStepSaveDuration; | ||||
|             } else if( | ||||
|                 (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_firefly_const.te_long) < | ||||
|                  subghz_protocol_firefly_const.te_delta) && | ||||
|                 (DURATION_DIFF(duration, subghz_protocol_firefly_const.te_short) < | ||||
|                  subghz_protocol_firefly_const.te_delta)) { | ||||
|                 (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_linear_const.te_long) < | ||||
|                  subghz_protocol_linear_const.te_delta) && | ||||
|                 (DURATION_DIFF(duration, subghz_protocol_linear_const.te_short) < | ||||
|                  subghz_protocol_linear_const.te_delta)) { | ||||
|                 subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||
|                 instance->decoder.parser_step = FireflyDecoderStepSaveDuration; | ||||
|                 instance->decoder.parser_step = LinearDecoderStepSaveDuration; | ||||
|             } else { | ||||
|                 instance->decoder.parser_step = FireflyDecoderStepReset; | ||||
|                 instance->decoder.parser_step = LinearDecoderStepReset; | ||||
|             } | ||||
| 
 | ||||
|         } else { | ||||
|             instance->decoder.parser_step = FireflyDecoderStepReset; | ||||
|             instance->decoder.parser_step = LinearDecoderStepReset; | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| uint8_t subghz_protocol_decoder_firefly_get_hash_data(void* context) { | ||||
| uint8_t subghz_protocol_decoder_linear_get_hash_data(void* context) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolDecoderFirefly* instance = context; | ||||
|     SubGhzProtocolDecoderLinear* instance = context; | ||||
|     return subghz_protocol_blocks_get_hash_data( | ||||
|         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||
| } | ||||
| 
 | ||||
| bool subghz_protocol_decoder_firefly_serialize( | ||||
| bool subghz_protocol_decoder_linear_serialize( | ||||
|     void* context, | ||||
|     FlipperFormat* flipper_format, | ||||
|     uint32_t frequency, | ||||
|     FuriHalSubGhzPreset preset) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolDecoderFirefly* instance = context; | ||||
|     SubGhzProtocolDecoderLinear* instance = context; | ||||
|     return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset); | ||||
| } | ||||
| 
 | ||||
| bool subghz_protocol_decoder_firefly_deserialize(void* context, FlipperFormat* flipper_format) { | ||||
| bool subghz_protocol_decoder_linear_deserialize(void* context, FlipperFormat* flipper_format) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolDecoderFirefly* instance = context; | ||||
|     SubGhzProtocolDecoderLinear* instance = context; | ||||
|     return subghz_block_generic_deserialize(&instance->generic, flipper_format); | ||||
| } | ||||
| 
 | ||||
| void subghz_protocol_decoder_firefly_get_string(void* context, string_t output) { | ||||
| void subghz_protocol_decoder_linear_get_string(void* context, string_t output) { | ||||
|     furi_assert(context); | ||||
|     SubGhzProtocolDecoderFirefly* instance = context; | ||||
|     SubGhzProtocolDecoderLinear* instance = context; | ||||
| 
 | ||||
|     uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; | ||||
| 
 | ||||
							
								
								
									
										109
									
								
								lib/subghz/protocols/linear.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								lib/subghz/protocols/linear.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,109 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "base.h" | ||||
| 
 | ||||
| #define SUBGHZ_PROTOCOL_LINEAR_NAME "Linear" | ||||
| 
 | ||||
| typedef struct SubGhzProtocolDecoderLinear SubGhzProtocolDecoderLinear; | ||||
| typedef struct SubGhzProtocolEncoderLinear SubGhzProtocolEncoderLinear; | ||||
| 
 | ||||
| extern const SubGhzProtocolDecoder subghz_protocol_linear_decoder; | ||||
| extern const SubGhzProtocolEncoder subghz_protocol_linear_encoder; | ||||
| extern const SubGhzProtocol subghz_protocol_linear; | ||||
| 
 | ||||
| /**
 | ||||
|  * Allocate SubGhzProtocolEncoderLinear. | ||||
|  * @param environment Pointer to a SubGhzEnvironment instance | ||||
|  * @return SubGhzProtocolEncoderLinear* pointer to a SubGhzProtocolEncoderLinear instance | ||||
|  */ | ||||
| void* subghz_protocol_encoder_linear_alloc(SubGhzEnvironment* environment); | ||||
| 
 | ||||
| /**
 | ||||
|  * Free SubGhzProtocolEncoderLinear. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderLinear instance | ||||
|  */ | ||||
| void subghz_protocol_encoder_linear_free(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Deserialize and generating an upload to send. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderLinear instance | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
|  * @return true On success | ||||
|  */ | ||||
| bool subghz_protocol_encoder_linear_deserialize(void* context, FlipperFormat* flipper_format); | ||||
| 
 | ||||
| /**
 | ||||
|  * Forced transmission stop. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderLinear instance | ||||
|  */ | ||||
| void subghz_protocol_encoder_linear_stop(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Getting the level and duration of the upload to be loaded into DMA. | ||||
|  * @param context Pointer to a SubGhzProtocolEncoderLinear instance | ||||
|  * @return LevelDuration  | ||||
|  */ | ||||
| LevelDuration subghz_protocol_encoder_linear_yield(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Allocate SubGhzProtocolDecoderLinear. | ||||
|  * @param environment Pointer to a SubGhzEnvironment instance | ||||
|  * @return SubGhzProtocolDecoderLinear* pointer to a SubGhzProtocolDecoderLinear instance | ||||
|  */ | ||||
| void* subghz_protocol_decoder_linear_alloc(SubGhzEnvironment* environment); | ||||
| 
 | ||||
| /**
 | ||||
|  * Free SubGhzProtocolDecoderLinear. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderLinear instance | ||||
|  */ | ||||
| void subghz_protocol_decoder_linear_free(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Reset decoder SubGhzProtocolDecoderLinear. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderLinear instance | ||||
|  */ | ||||
| void subghz_protocol_decoder_linear_reset(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Parse a raw sequence of levels and durations received from the air. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderLinear instance | ||||
|  * @param level Signal level true-high false-low | ||||
|  * @param duration Duration of this level in, us | ||||
|  */ | ||||
| void subghz_protocol_decoder_linear_feed(void* context, bool level, uint32_t duration); | ||||
| 
 | ||||
| /**
 | ||||
|  * Getting the hash sum of the last randomly received parcel. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderLinear instance | ||||
|  * @return hash Hash sum | ||||
|  */ | ||||
| uint8_t subghz_protocol_decoder_linear_get_hash_data(void* context); | ||||
| 
 | ||||
| /**
 | ||||
|  * Serialize data SubGhzProtocolDecoderLinear. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderLinear instance | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
|  * @param frequency The frequency at which the signal was received, Hz | ||||
|  * @param preset The modulation on which the signal was received, FuriHalSubGhzPreset | ||||
|  * @return true On success | ||||
|  */ | ||||
| bool subghz_protocol_decoder_linear_serialize( | ||||
|     void* context, | ||||
|     FlipperFormat* flipper_format, | ||||
|     uint32_t frequency, | ||||
|     FuriHalSubGhzPreset preset); | ||||
| 
 | ||||
| /**
 | ||||
|  * Deserialize data SubGhzProtocolDecoderLinear. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderLinear instance | ||||
|  * @param flipper_format Pointer to a FlipperFormat instance | ||||
|  * @return true On success | ||||
|  */ | ||||
| bool subghz_protocol_decoder_linear_deserialize(void* context, FlipperFormat* flipper_format); | ||||
| 
 | ||||
| /**
 | ||||
|  * Getting a textual representation of the received data. | ||||
|  * @param context Pointer to a SubGhzProtocolDecoderLinear instance | ||||
|  * @param output Resulting text | ||||
|  */ | ||||
| void subghz_protocol_decoder_linear_get_string(void* context, string_t output); | ||||
| @ -247,7 +247,7 @@ void subghz_protocol_decoder_megacode_feed(void* context, bool level, uint32_t d | ||||
|     switch(instance->decoder.parser_step) { | ||||
|     case MegaCodeDecoderStepReset: | ||||
|         if((!level) && (DURATION_DIFF(duration, subghz_protocol_megacode_const.te_short * 13) < | ||||
|                         subghz_protocol_megacode_const.te_delta * 15)) { //10..16ms
 | ||||
|                         subghz_protocol_megacode_const.te_delta * 17)) { //10..16ms
 | ||||
|             //Found header MegaCode
 | ||||
|             instance->decoder.parser_step = MegaCodeDecoderStepFoundStartBit; | ||||
|         } | ||||
|  | ||||
| @ -7,8 +7,9 @@ const SubGhzProtocol* subghz_protocol_registry[] = { | ||||
|     &subghz_protocol_nero_sketch,  &subghz_protocol_ido,        &subghz_protocol_kia, | ||||
|     &subghz_protocol_hormann,      &subghz_protocol_nero_radio, &subghz_protocol_somfy_telis, | ||||
|     &subghz_protocol_somfy_keytis, &subghz_protocol_scher_khan, &subghz_protocol_princeton, | ||||
|     &subghz_protocol_raw,          &subghz_protocol_firefly,    &subghz_protocol_secplus_v2, | ||||
|     &subghz_protocol_raw,          &subghz_protocol_linear,     &subghz_protocol_secplus_v2, | ||||
|     &subghz_protocol_secplus_v1,   &subghz_protocol_megacode,   &subghz_protocol_holtek, | ||||
|     &subghz_protocol_chamb_code, | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -21,11 +21,12 @@ | ||||
| #include "scher_khan.h" | ||||
| #include "gate_tx.h" | ||||
| #include "raw.h" | ||||
| #include "firefly.h" | ||||
| #include "linear.h" | ||||
| #include "secplus_v2.h" | ||||
| #include "secplus_v1.h" | ||||
| #include "megacode.h" | ||||
| #include "holtek.h" | ||||
| #include "chamberlain_code.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * Registration by name SubGhzProtocol. | ||||
|  | ||||
| @ -442,7 +442,7 @@ static LevelDuration | ||||
|         break; | ||||
| 
 | ||||
|     default: | ||||
|         furi_crash("SugGhz: ManchesterEncoderResult is incorrect."); | ||||
|         furi_crash("SubGhz: ManchesterEncoderResult is incorrect."); | ||||
|         break; | ||||
|     } | ||||
|     return level_duration_make(data.level, data.duration); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Aleksandr Kutuzov
						Aleksandr Kutuzov