[FL-2920] WS: add protocol Acurite-606TX, LaCrosse_TX141THBv2 (#1898)
* WS: add protocol Acurite-606TX * WS: history, added display of the channel (if any) in the general list * WS: added display of the button state if it is on the transmitter, and displaying the data that is in the signal * WS: fix batt info * WS: add protocol LaCrosse_TX141THBv2 * WS; fix syntax * Furi: bump api_symbols version Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									33892ebfb7
								
							
						
					
					
						commit
						c1bb10a694
					
				| @ -3,7 +3,7 @@ | |||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| 
 | 
 | ||||||
| #define WS_VERSION_APP "0.1" | #define WS_VERSION_APP "0.2" | ||||||
| #define WS_DEVELOPED "SkorP" | #define WS_DEVELOPED "SkorP" | ||||||
| #define WS_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
 | #define WS_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										252
									
								
								applications/plugins/weather_station/protocols/acurite_606tx.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								applications/plugins/weather_station/protocols/acurite_606tx.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,252 @@ | |||||||
|  | #include "acurite_606tx.h" | ||||||
|  | 
 | ||||||
|  | #define TAG "WSProtocolAcurite_606TX" | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Help | ||||||
|  |  * https://github.com/merbanan/rtl_433/blob/5bef4e43133ac4c0e2d18d36f87c52b4f9458453/src/devices/acurite.c#L1644
 | ||||||
|  |  *  | ||||||
|  |  *     0000 1111 | 0011 0000 | 0101 1100 | 1110 0111 | ||||||
|  |  *     iiii iiii | buuu tttt | tttt tttt | cccc cccc | ||||||
|  |  * - i: identification; changes on battery switch | ||||||
|  |  * - c: lfsr_digest8; | ||||||
|  |  * - u: unknown; | ||||||
|  |  * - b: battery low; flag to indicate low battery voltage | ||||||
|  |  * - t: Temperature; in °C | ||||||
|  |  *  | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst ws_protocol_acurite_606tx_const = { | ||||||
|  |     .te_short = 500, | ||||||
|  |     .te_long = 2000, | ||||||
|  |     .te_delta = 150, | ||||||
|  |     .min_count_bit_for_found = 32, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct WSProtocolDecoderAcurite_606TX { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     WSBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct WSProtocolEncoderAcurite_606TX { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     WSBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     Acurite_606TXDecoderStepReset = 0, | ||||||
|  |     Acurite_606TXDecoderStepSaveDuration, | ||||||
|  |     Acurite_606TXDecoderStepCheckDuration, | ||||||
|  | } Acurite_606TXDecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder ws_protocol_acurite_606tx_decoder = { | ||||||
|  |     .alloc = ws_protocol_decoder_acurite_606tx_alloc, | ||||||
|  |     .free = ws_protocol_decoder_acurite_606tx_free, | ||||||
|  | 
 | ||||||
|  |     .feed = ws_protocol_decoder_acurite_606tx_feed, | ||||||
|  |     .reset = ws_protocol_decoder_acurite_606tx_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = ws_protocol_decoder_acurite_606tx_get_hash_data, | ||||||
|  |     .serialize = ws_protocol_decoder_acurite_606tx_serialize, | ||||||
|  |     .deserialize = ws_protocol_decoder_acurite_606tx_deserialize, | ||||||
|  |     .get_string = ws_protocol_decoder_acurite_606tx_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder ws_protocol_acurite_606tx_encoder = { | ||||||
|  |     .alloc = NULL, | ||||||
|  |     .free = NULL, | ||||||
|  | 
 | ||||||
|  |     .deserialize = NULL, | ||||||
|  |     .stop = NULL, | ||||||
|  |     .yield = NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol ws_protocol_acurite_606tx = { | ||||||
|  |     .name = WS_PROTOCOL_ACURITE_606TX_NAME, | ||||||
|  |     .type = SubGhzProtocolWeatherStation, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 | | ||||||
|  |             SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, | ||||||
|  | 
 | ||||||
|  |     .decoder = &ws_protocol_acurite_606tx_decoder, | ||||||
|  |     .encoder = &ws_protocol_acurite_606tx_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void* ws_protocol_decoder_acurite_606tx_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     UNUSED(environment); | ||||||
|  |     WSProtocolDecoderAcurite_606TX* instance = malloc(sizeof(WSProtocolDecoderAcurite_606TX)); | ||||||
|  |     instance->base.protocol = &ws_protocol_acurite_606tx; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ws_protocol_decoder_acurite_606tx_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     WSProtocolDecoderAcurite_606TX* instance = context; | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ws_protocol_decoder_acurite_606tx_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     WSProtocolDecoderAcurite_606TX* instance = context; | ||||||
|  |     instance->decoder.parser_step = Acurite_606TXDecoderStepReset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool ws_protocol_acurite_606tx_check(WSProtocolDecoderAcurite_606TX* instance) { | ||||||
|  |     if(!instance->decoder.decode_data) return false; | ||||||
|  |     uint8_t msg[] = { | ||||||
|  |         instance->decoder.decode_data >> 24, | ||||||
|  |         instance->decoder.decode_data >> 16, | ||||||
|  |         instance->decoder.decode_data >> 8}; | ||||||
|  | 
 | ||||||
|  |     uint8_t crc = subghz_protocol_blocks_lfsr_digest8(msg, 3, 0x98, 0xF1); | ||||||
|  |     return (crc == (instance->decoder.decode_data & 0xFF)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Analysis of received data | ||||||
|  |  * @param instance Pointer to a WSBlockGeneric* instance | ||||||
|  |  */ | ||||||
|  | static void ws_protocol_acurite_606tx_remote_controller(WSBlockGeneric* instance) { | ||||||
|  |     instance->id = (instance->data >> 24) & 0xFF; | ||||||
|  |     instance->battery_low = (instance->data >> 23) & 1; | ||||||
|  | 
 | ||||||
|  |     instance->channel = WS_NO_CHANNEL; | ||||||
|  | 
 | ||||||
|  |     if(!((instance->data >> 19) & 1)) { | ||||||
|  |         instance->temp = (float)((instance->data >> 8) & 0x07FF) / 10.0f; | ||||||
|  |     } else { | ||||||
|  |         instance->temp = (float)((~(instance->data >> 8) & 0x07FF) + 1) / -10.0f; | ||||||
|  |     } | ||||||
|  |     instance->btn = WS_NO_BTN; | ||||||
|  |     instance->humidity = WS_NO_HUMIDITY; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ws_protocol_decoder_acurite_606tx_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     WSProtocolDecoderAcurite_606TX* instance = context; | ||||||
|  | 
 | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case Acurite_606TXDecoderStepReset: | ||||||
|  |         if((!level) && (DURATION_DIFF(duration, ws_protocol_acurite_606tx_const.te_short * 17) < | ||||||
|  |                         ws_protocol_acurite_606tx_const.te_delta * 8)) { | ||||||
|  |             //Found syncPrefix
 | ||||||
|  |             instance->decoder.parser_step = Acurite_606TXDecoderStepSaveDuration; | ||||||
|  |             instance->decoder.decode_data = 0; | ||||||
|  |             instance->decoder.decode_count_bit = 0; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case Acurite_606TXDecoderStepSaveDuration: | ||||||
|  |         if(level) { | ||||||
|  |             instance->decoder.te_last = duration; | ||||||
|  |             instance->decoder.parser_step = Acurite_606TXDecoderStepCheckDuration; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = Acurite_606TXDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case Acurite_606TXDecoderStepCheckDuration: | ||||||
|  |         if(!level) { | ||||||
|  |             if((DURATION_DIFF(instance->decoder.te_last, ws_protocol_acurite_606tx_const.te_short) < | ||||||
|  |                 ws_protocol_acurite_606tx_const.te_delta) && | ||||||
|  |                (DURATION_DIFF(duration, ws_protocol_acurite_606tx_const.te_short) < | ||||||
|  |                 ws_protocol_acurite_606tx_const.te_delta)) { | ||||||
|  |                 //Found syncPostfix
 | ||||||
|  |                 instance->decoder.parser_step = Acurite_606TXDecoderStepReset; | ||||||
|  |                 if((instance->decoder.decode_count_bit == | ||||||
|  |                     ws_protocol_acurite_606tx_const.min_count_bit_for_found) && | ||||||
|  |                    ws_protocol_acurite_606tx_check(instance)) { | ||||||
|  |                     instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                     instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  |                     ws_protocol_acurite_606tx_remote_controller(&instance->generic); | ||||||
|  |                     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 if( | ||||||
|  |                 (DURATION_DIFF( | ||||||
|  |                      instance->decoder.te_last, ws_protocol_acurite_606tx_const.te_short) < | ||||||
|  |                  ws_protocol_acurite_606tx_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, ws_protocol_acurite_606tx_const.te_long) < | ||||||
|  |                  ws_protocol_acurite_606tx_const.te_delta * 2)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                 instance->decoder.parser_step = Acurite_606TXDecoderStepSaveDuration; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF( | ||||||
|  |                      instance->decoder.te_last, ws_protocol_acurite_606tx_const.te_short) < | ||||||
|  |                  ws_protocol_acurite_606tx_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, ws_protocol_acurite_606tx_const.te_long * 2) < | ||||||
|  |                  ws_protocol_acurite_606tx_const.te_delta * 4)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                 instance->decoder.parser_step = Acurite_606TXDecoderStepSaveDuration; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = Acurite_606TXDecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = Acurite_606TXDecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t ws_protocol_decoder_acurite_606tx_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     WSProtocolDecoderAcurite_606TX* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ws_protocol_decoder_acurite_606tx_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     SubGhzRadioPreset* preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     WSProtocolDecoderAcurite_606TX* instance = context; | ||||||
|  |     return ws_block_generic_serialize(&instance->generic, flipper_format, preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ws_protocol_decoder_acurite_606tx_deserialize(void* context, FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     WSProtocolDecoderAcurite_606TX* instance = context; | ||||||
|  |     bool ret = false; | ||||||
|  |     do { | ||||||
|  |         if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if(instance->generic.data_count_bit != | ||||||
|  |            ws_protocol_acurite_606tx_const.min_count_bit_for_found) { | ||||||
|  |             FURI_LOG_E(TAG, "Wrong number of bits in key"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         ret = true; | ||||||
|  |     } while(false); | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ws_protocol_decoder_acurite_606tx_get_string(void* context, FuriString* output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     WSProtocolDecoderAcurite_606TX* instance = context; | ||||||
|  |     furi_string_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %dbit\r\n" | ||||||
|  |         "Key:0x%lX%08lX\r\n" | ||||||
|  |         "Sn:0x%lX Ch:%d  Bat:%d\r\n" | ||||||
|  |         "Temp:%d.%d C Hum:%d%%", | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         (uint32_t)(instance->generic.data >> 32), | ||||||
|  |         (uint32_t)(instance->generic.data), | ||||||
|  |         instance->generic.id, | ||||||
|  |         instance->generic.channel, | ||||||
|  |         instance->generic.battery_low, | ||||||
|  |         (int16_t)instance->generic.temp, | ||||||
|  |         abs(((int16_t)(instance->generic.temp * 10) - (((int16_t)instance->generic.temp) * 10))), | ||||||
|  |         instance->generic.humidity); | ||||||
|  | } | ||||||
| @ -0,0 +1,79 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <lib/subghz/protocols/base.h> | ||||||
|  | 
 | ||||||
|  | #include <lib/subghz/blocks/const.h> | ||||||
|  | #include <lib/subghz/blocks/decoder.h> | ||||||
|  | #include <lib/subghz/blocks/encoder.h> | ||||||
|  | #include "ws_generic.h" | ||||||
|  | #include <lib/subghz/blocks/math.h> | ||||||
|  | 
 | ||||||
|  | #define WS_PROTOCOL_ACURITE_606TX_NAME "Acurite-606TX" | ||||||
|  | 
 | ||||||
|  | typedef struct WSProtocolDecoderAcurite_606TX WSProtocolDecoderAcurite_606TX; | ||||||
|  | typedef struct WSProtocolEncoderAcurite_606TX WSProtocolEncoderAcurite_606TX; | ||||||
|  | 
 | ||||||
|  | extern const SubGhzProtocolDecoder ws_protocol_acurite_606tx_decoder; | ||||||
|  | extern const SubGhzProtocolEncoder ws_protocol_acurite_606tx_encoder; | ||||||
|  | extern const SubGhzProtocol ws_protocol_acurite_606tx; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Allocate WSProtocolDecoderAcurite_606TX. | ||||||
|  |  * @param environment Pointer to a SubGhzEnvironment instance | ||||||
|  |  * @return WSProtocolDecoderAcurite_606TX* pointer to a WSProtocolDecoderAcurite_606TX instance | ||||||
|  |  */ | ||||||
|  | void* ws_protocol_decoder_acurite_606tx_alloc(SubGhzEnvironment* environment); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Free WSProtocolDecoderAcurite_606TX. | ||||||
|  |  * @param context Pointer to a WSProtocolDecoderAcurite_606TX instance | ||||||
|  |  */ | ||||||
|  | void ws_protocol_decoder_acurite_606tx_free(void* context); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Reset decoder WSProtocolDecoderAcurite_606TX. | ||||||
|  |  * @param context Pointer to a WSProtocolDecoderAcurite_606TX instance | ||||||
|  |  */ | ||||||
|  | void ws_protocol_decoder_acurite_606tx_reset(void* context); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Parse a raw sequence of levels and durations received from the air. | ||||||
|  |  * @param context Pointer to a WSProtocolDecoderAcurite_606TX instance | ||||||
|  |  * @param level Signal level true-high false-low | ||||||
|  |  * @param duration Duration of this level in, us | ||||||
|  |  */ | ||||||
|  | void ws_protocol_decoder_acurite_606tx_feed(void* context, bool level, uint32_t duration); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Getting the hash sum of the last randomly received parcel. | ||||||
|  |  * @param context Pointer to a WSProtocolDecoderAcurite_606TX instance | ||||||
|  |  * @return hash Hash sum | ||||||
|  |  */ | ||||||
|  | uint8_t ws_protocol_decoder_acurite_606tx_get_hash_data(void* context); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Serialize data WSProtocolDecoderAcurite_606TX. | ||||||
|  |  * @param context Pointer to a WSProtocolDecoderAcurite_606TX instance | ||||||
|  |  * @param flipper_format Pointer to a FlipperFormat instance | ||||||
|  |  * @param preset The modulation on which the signal was received, SubGhzRadioPreset | ||||||
|  |  * @return true On success | ||||||
|  |  */ | ||||||
|  | bool ws_protocol_decoder_acurite_606tx_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     SubGhzRadioPreset* preset); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Deserialize data WSProtocolDecoderAcurite_606TX. | ||||||
|  |  * @param context Pointer to a WSProtocolDecoderAcurite_606TX instance | ||||||
|  |  * @param flipper_format Pointer to a FlipperFormat instance | ||||||
|  |  * @return true On success | ||||||
|  |  */ | ||||||
|  | bool ws_protocol_decoder_acurite_606tx_deserialize(void* context, FlipperFormat* flipper_format); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Getting a textual representation of the received data. | ||||||
|  |  * @param context Pointer to a WSProtocolDecoderAcurite_606TX instance | ||||||
|  |  * @param output Resulting text | ||||||
|  |  */ | ||||||
|  | void ws_protocol_decoder_acurite_606tx_get_string(void* context, FuriString* output); | ||||||
| @ -142,6 +142,7 @@ static bool ws_protocol_infactory_check_crc(WSProtocolDecoderInfactory* instance | |||||||
| static void ws_protocol_infactory_remote_controller(WSBlockGeneric* instance) { | static void ws_protocol_infactory_remote_controller(WSBlockGeneric* instance) { | ||||||
|     instance->id = instance->data >> 32; |     instance->id = instance->data >> 32; | ||||||
|     instance->battery_low = (instance->data >> 26) & 1; |     instance->battery_low = (instance->data >> 26) & 1; | ||||||
|  |     instance->btn = WS_NO_BTN; | ||||||
|     instance->temp = ws_block_generic_fahrenheit_to_celsius( |     instance->temp = ws_block_generic_fahrenheit_to_celsius( | ||||||
|         ((float)((instance->data >> 12) & 0x0FFF) - 900.0f) / 10.0f); |         ((float)((instance->data >> 12) & 0x0FFF) - 900.0f) / 10.0f); | ||||||
|     instance->humidity = |     instance->humidity = | ||||||
|  | |||||||
| @ -0,0 +1,298 @@ | |||||||
|  | #include "lacrosse_tx141thbv2.h" | ||||||
|  | 
 | ||||||
|  | #define TAG "WSProtocolLaCrosse_TX141THBv2" | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Help | ||||||
|  |  * https://github.com/merbanan/rtl_433/blob/7e83cfd27d14247b6c3c81732bfe4a4f9a974d30/src/devices/lacrosse_tx141x.c
 | ||||||
|  |  *   | ||||||
|  |  *     iiii iiii | bkcc tttt | tttt tttt | hhhh hhhh | cccc cccc | u | ||||||
|  |  * - i: identification; changes on battery switch | ||||||
|  |  * - c: lfsr_digest8_reflect; | ||||||
|  |  * - u: unknown;  | ||||||
|  |  * - b: battery low; flag to indicate low battery voltage | ||||||
|  |  * - h: Humidity;  | ||||||
|  |  * - t: Temperature; in °F as binary number with one decimal place + 50 °F offset | ||||||
|  |  * - n: Channel; Channel number 1 - 3 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | static const SubGhzBlockConst ws_protocol_lacrosse_tx141thbv2_const = { | ||||||
|  |     .te_short = 250, | ||||||
|  |     .te_long = 500, | ||||||
|  |     .te_delta = 120, | ||||||
|  |     .min_count_bit_for_found = 41, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct WSProtocolDecoderLaCrosse_TX141THBv2 { | ||||||
|  |     SubGhzProtocolDecoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzBlockDecoder decoder; | ||||||
|  |     WSBlockGeneric generic; | ||||||
|  | 
 | ||||||
|  |     uint16_t header_count; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct WSProtocolEncoderLaCrosse_TX141THBv2 { | ||||||
|  |     SubGhzProtocolEncoderBase base; | ||||||
|  | 
 | ||||||
|  |     SubGhzProtocolBlockEncoder encoder; | ||||||
|  |     WSBlockGeneric generic; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     LaCrosse_TX141THBv2DecoderStepReset = 0, | ||||||
|  |     LaCrosse_TX141THBv2DecoderStepCheckPreambule, | ||||||
|  |     LaCrosse_TX141THBv2DecoderStepSaveDuration, | ||||||
|  |     LaCrosse_TX141THBv2DecoderStepCheckDuration, | ||||||
|  | } LaCrosse_TX141THBv2DecoderStep; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolDecoder ws_protocol_lacrosse_tx141thbv2_decoder = { | ||||||
|  |     .alloc = ws_protocol_decoder_lacrosse_tx141thbv2_alloc, | ||||||
|  |     .free = ws_protocol_decoder_lacrosse_tx141thbv2_free, | ||||||
|  | 
 | ||||||
|  |     .feed = ws_protocol_decoder_lacrosse_tx141thbv2_feed, | ||||||
|  |     .reset = ws_protocol_decoder_lacrosse_tx141thbv2_reset, | ||||||
|  | 
 | ||||||
|  |     .get_hash_data = ws_protocol_decoder_lacrosse_tx141thbv2_get_hash_data, | ||||||
|  |     .serialize = ws_protocol_decoder_lacrosse_tx141thbv2_serialize, | ||||||
|  |     .deserialize = ws_protocol_decoder_lacrosse_tx141thbv2_deserialize, | ||||||
|  |     .get_string = ws_protocol_decoder_lacrosse_tx141thbv2_get_string, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocolEncoder ws_protocol_lacrosse_tx141thbv2_encoder = { | ||||||
|  |     .alloc = NULL, | ||||||
|  |     .free = NULL, | ||||||
|  | 
 | ||||||
|  |     .deserialize = NULL, | ||||||
|  |     .stop = NULL, | ||||||
|  |     .yield = NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const SubGhzProtocol ws_protocol_lacrosse_tx141thbv2 = { | ||||||
|  |     .name = WS_PROTOCOL_LACROSSE_TX141THBV2_NAME, | ||||||
|  |     .type = SubGhzProtocolWeatherStation, | ||||||
|  |     .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 | | ||||||
|  |             SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, | ||||||
|  | 
 | ||||||
|  |     .decoder = &ws_protocol_lacrosse_tx141thbv2_decoder, | ||||||
|  |     .encoder = &ws_protocol_lacrosse_tx141thbv2_encoder, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void* ws_protocol_decoder_lacrosse_tx141thbv2_alloc(SubGhzEnvironment* environment) { | ||||||
|  |     UNUSED(environment); | ||||||
|  |     WSProtocolDecoderLaCrosse_TX141THBv2* instance = | ||||||
|  |         malloc(sizeof(WSProtocolDecoderLaCrosse_TX141THBv2)); | ||||||
|  |     instance->base.protocol = &ws_protocol_lacrosse_tx141thbv2; | ||||||
|  |     instance->generic.protocol_name = instance->base.protocol->name; | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ws_protocol_decoder_lacrosse_tx141thbv2_free(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     WSProtocolDecoderLaCrosse_TX141THBv2* instance = context; | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ws_protocol_decoder_lacrosse_tx141thbv2_reset(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     WSProtocolDecoderLaCrosse_TX141THBv2* instance = context; | ||||||
|  |     instance->decoder.parser_step = LaCrosse_TX141THBv2DecoderStepReset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool | ||||||
|  |     ws_protocol_lacrosse_tx141thbv2_check_crc(WSProtocolDecoderLaCrosse_TX141THBv2* instance) { | ||||||
|  |     if(!instance->decoder.decode_data) return false; | ||||||
|  |     uint8_t msg[] = { | ||||||
|  |         instance->decoder.decode_data >> 33, | ||||||
|  |         instance->decoder.decode_data >> 25, | ||||||
|  |         instance->decoder.decode_data >> 17, | ||||||
|  |         instance->decoder.decode_data >> 9}; | ||||||
|  | 
 | ||||||
|  |     uint8_t crc = subghz_protocol_blocks_lfsr_digest8_reflect(msg, 4, 0x31, 0xF4); | ||||||
|  |     return (crc == ((instance->decoder.decode_data >> 1) & 0xFF)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Analysis of received data | ||||||
|  |  * @param instance Pointer to a WSBlockGeneric* instance | ||||||
|  |  */ | ||||||
|  | static void ws_protocol_lacrosse_tx141thbv2_remote_controller(WSBlockGeneric* instance) { | ||||||
|  |     instance->id = instance->data >> 33; | ||||||
|  |     instance->battery_low = (instance->data >> 32) & 1; | ||||||
|  |     instance->btn = (instance->data >> 31) & 1; | ||||||
|  |     instance->channel = ((instance->data >> 29) & 0x03) + 1; | ||||||
|  |     instance->temp = ((float)((instance->data >> 17) & 0x0FFF) - 500.0f) / 10.0f; | ||||||
|  |     instance->humidity = (instance->data >> 9) & 0xFF; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ws_protocol_decoder_lacrosse_tx141thbv2_feed(void* context, bool level, uint32_t duration) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     WSProtocolDecoderLaCrosse_TX141THBv2* instance = context; | ||||||
|  | 
 | ||||||
|  |     switch(instance->decoder.parser_step) { | ||||||
|  |     case LaCrosse_TX141THBv2DecoderStepReset: | ||||||
|  |         if((level) && | ||||||
|  |            (DURATION_DIFF(duration, ws_protocol_lacrosse_tx141thbv2_const.te_short * 3) < | ||||||
|  |             ws_protocol_lacrosse_tx141thbv2_const.te_delta * 2)) { | ||||||
|  |             instance->decoder.parser_step = LaCrosse_TX141THBv2DecoderStepCheckPreambule; | ||||||
|  |             instance->decoder.te_last = duration; | ||||||
|  |             instance->header_count = 0; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case LaCrosse_TX141THBv2DecoderStepCheckPreambule: | ||||||
|  |         if(level) { | ||||||
|  |             instance->decoder.te_last = duration; | ||||||
|  |         } else { | ||||||
|  |             if((DURATION_DIFF( | ||||||
|  |                     instance->decoder.te_last, | ||||||
|  |                     ws_protocol_lacrosse_tx141thbv2_const.te_short * 3) < | ||||||
|  |                 ws_protocol_lacrosse_tx141thbv2_const.te_delta * 2) && | ||||||
|  |                (DURATION_DIFF(duration, ws_protocol_lacrosse_tx141thbv2_const.te_short * 3) < | ||||||
|  |                 ws_protocol_lacrosse_tx141thbv2_const.te_delta * 2)) { | ||||||
|  |                 //Found preambule
 | ||||||
|  |                 instance->header_count++; | ||||||
|  |             } else if(instance->header_count == 4) { | ||||||
|  |                 if((DURATION_DIFF( | ||||||
|  |                         instance->decoder.te_last, | ||||||
|  |                         ws_protocol_lacrosse_tx141thbv2_const.te_short) < | ||||||
|  |                     ws_protocol_lacrosse_tx141thbv2_const.te_delta) && | ||||||
|  |                    (DURATION_DIFF(duration, ws_protocol_lacrosse_tx141thbv2_const.te_long) < | ||||||
|  |                     ws_protocol_lacrosse_tx141thbv2_const.te_delta)) { | ||||||
|  |                     instance->decoder.decode_data = 0; | ||||||
|  |                     instance->decoder.decode_count_bit = 0; | ||||||
|  |                     subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                     instance->decoder.parser_step = LaCrosse_TX141THBv2DecoderStepSaveDuration; | ||||||
|  |                 } else if( | ||||||
|  |                     (DURATION_DIFF( | ||||||
|  |                          instance->decoder.te_last, | ||||||
|  |                          ws_protocol_lacrosse_tx141thbv2_const.te_long) < | ||||||
|  |                      ws_protocol_lacrosse_tx141thbv2_const.te_delta) && | ||||||
|  |                     (DURATION_DIFF(duration, ws_protocol_lacrosse_tx141thbv2_const.te_short) < | ||||||
|  |                      ws_protocol_lacrosse_tx141thbv2_const.te_delta)) { | ||||||
|  |                     instance->decoder.decode_data = 0; | ||||||
|  |                     instance->decoder.decode_count_bit = 0; | ||||||
|  |                     subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                     instance->decoder.parser_step = LaCrosse_TX141THBv2DecoderStepSaveDuration; | ||||||
|  |                 } else { | ||||||
|  |                     instance->decoder.parser_step = LaCrosse_TX141THBv2DecoderStepReset; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = LaCrosse_TX141THBv2DecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case LaCrosse_TX141THBv2DecoderStepSaveDuration: | ||||||
|  |         if(level) { | ||||||
|  |             instance->decoder.te_last = duration; | ||||||
|  |             instance->decoder.parser_step = LaCrosse_TX141THBv2DecoderStepCheckDuration; | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = LaCrosse_TX141THBv2DecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case LaCrosse_TX141THBv2DecoderStepCheckDuration: | ||||||
|  |         if(!level) { | ||||||
|  |             if(((DURATION_DIFF( | ||||||
|  |                      instance->decoder.te_last, | ||||||
|  |                      ws_protocol_lacrosse_tx141thbv2_const.te_short * 3) < | ||||||
|  |                  ws_protocol_lacrosse_tx141thbv2_const.te_delta * 2) && | ||||||
|  |                 (DURATION_DIFF(duration, ws_protocol_lacrosse_tx141thbv2_const.te_short * 3) < | ||||||
|  |                  ws_protocol_lacrosse_tx141thbv2_const.te_delta * 2))) { | ||||||
|  |                 if((instance->decoder.decode_count_bit == | ||||||
|  |                     ws_protocol_lacrosse_tx141thbv2_const.min_count_bit_for_found) && | ||||||
|  |                    ws_protocol_lacrosse_tx141thbv2_check_crc(instance)) { | ||||||
|  |                     instance->generic.data = instance->decoder.decode_data; | ||||||
|  |                     instance->generic.data_count_bit = instance->decoder.decode_count_bit; | ||||||
|  |                     ws_protocol_lacrosse_tx141thbv2_remote_controller(&instance->generic); | ||||||
|  |                     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 = 1; | ||||||
|  |                 instance->decoder.parser_step = LaCrosse_TX141THBv2DecoderStepCheckPreambule; | ||||||
|  |                 break; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF( | ||||||
|  |                      instance->decoder.te_last, ws_protocol_lacrosse_tx141thbv2_const.te_short) < | ||||||
|  |                  ws_protocol_lacrosse_tx141thbv2_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, ws_protocol_lacrosse_tx141thbv2_const.te_long) < | ||||||
|  |                  ws_protocol_lacrosse_tx141thbv2_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 0); | ||||||
|  |                 instance->decoder.parser_step = LaCrosse_TX141THBv2DecoderStepSaveDuration; | ||||||
|  |             } else if( | ||||||
|  |                 (DURATION_DIFF( | ||||||
|  |                      instance->decoder.te_last, ws_protocol_lacrosse_tx141thbv2_const.te_long) < | ||||||
|  |                  ws_protocol_lacrosse_tx141thbv2_const.te_delta) && | ||||||
|  |                 (DURATION_DIFF(duration, ws_protocol_lacrosse_tx141thbv2_const.te_short) < | ||||||
|  |                  ws_protocol_lacrosse_tx141thbv2_const.te_delta)) { | ||||||
|  |                 subghz_protocol_blocks_add_bit(&instance->decoder, 1); | ||||||
|  |                 instance->decoder.parser_step = LaCrosse_TX141THBv2DecoderStepSaveDuration; | ||||||
|  |             } else { | ||||||
|  |                 instance->decoder.parser_step = LaCrosse_TX141THBv2DecoderStepReset; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             instance->decoder.parser_step = LaCrosse_TX141THBv2DecoderStepReset; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t ws_protocol_decoder_lacrosse_tx141thbv2_get_hash_data(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     WSProtocolDecoderLaCrosse_TX141THBv2* instance = context; | ||||||
|  |     return subghz_protocol_blocks_get_hash_data( | ||||||
|  |         &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ws_protocol_decoder_lacrosse_tx141thbv2_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     SubGhzRadioPreset* preset) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     WSProtocolDecoderLaCrosse_TX141THBv2* instance = context; | ||||||
|  |     return ws_block_generic_serialize(&instance->generic, flipper_format, preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ws_protocol_decoder_lacrosse_tx141thbv2_deserialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     WSProtocolDecoderLaCrosse_TX141THBv2* instance = context; | ||||||
|  |     bool ret = false; | ||||||
|  |     do { | ||||||
|  |         if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if(instance->generic.data_count_bit != | ||||||
|  |            ws_protocol_lacrosse_tx141thbv2_const.min_count_bit_for_found) { | ||||||
|  |             FURI_LOG_E(TAG, "Wrong number of bits in key"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         ret = true; | ||||||
|  |     } while(false); | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ws_protocol_decoder_lacrosse_tx141thbv2_get_string(void* context, FuriString* output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     WSProtocolDecoderLaCrosse_TX141THBv2* instance = context; | ||||||
|  |     furi_string_printf( | ||||||
|  |         output, | ||||||
|  |         "%s %dbit\r\n" | ||||||
|  |         "Key:0x%lX%08lX\r\n" | ||||||
|  |         "Sn:0x%lX Ch:%d  Bat:%d\r\n" | ||||||
|  |         "Temp:%d.%d C Hum:%d%%", | ||||||
|  |         instance->generic.protocol_name, | ||||||
|  |         instance->generic.data_count_bit, | ||||||
|  |         (uint32_t)(instance->generic.data >> 32), | ||||||
|  |         (uint32_t)(instance->generic.data), | ||||||
|  |         instance->generic.id, | ||||||
|  |         instance->generic.channel, | ||||||
|  |         instance->generic.battery_low, | ||||||
|  |         (int16_t)instance->generic.temp, | ||||||
|  |         abs(((int16_t)(instance->generic.temp * 10) - (((int16_t)instance->generic.temp) * 10))), | ||||||
|  |         instance->generic.humidity); | ||||||
|  | } | ||||||
| @ -0,0 +1,81 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <lib/subghz/protocols/base.h> | ||||||
|  | 
 | ||||||
|  | #include <lib/subghz/blocks/const.h> | ||||||
|  | #include <lib/subghz/blocks/decoder.h> | ||||||
|  | #include <lib/subghz/blocks/encoder.h> | ||||||
|  | #include "ws_generic.h" | ||||||
|  | #include <lib/subghz/blocks/math.h> | ||||||
|  | 
 | ||||||
|  | #define WS_PROTOCOL_LACROSSE_TX141THBV2_NAME "TX141THBv2" | ||||||
|  | 
 | ||||||
|  | typedef struct WSProtocolDecoderLaCrosse_TX141THBv2 WSProtocolDecoderLaCrosse_TX141THBv2; | ||||||
|  | typedef struct WSProtocolEncoderLaCrosse_TX141THBv2 WSProtocolEncoderLaCrosse_TX141THBv2; | ||||||
|  | 
 | ||||||
|  | extern const SubGhzProtocolDecoder ws_protocol_lacrosse_tx141thbv2_decoder; | ||||||
|  | extern const SubGhzProtocolEncoder ws_protocol_lacrosse_tx141thbv2_encoder; | ||||||
|  | extern const SubGhzProtocol ws_protocol_lacrosse_tx141thbv2; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Allocate WSProtocolDecoderLaCrosse_TX141THBv2. | ||||||
|  |  * @param environment Pointer to a SubGhzEnvironment instance | ||||||
|  |  * @return WSProtocolDecoderLaCrosse_TX141THBv2* pointer to a WSProtocolDecoderLaCrosse_TX141THBv2 instance | ||||||
|  |  */ | ||||||
|  | void* ws_protocol_decoder_lacrosse_tx141thbv2_alloc(SubGhzEnvironment* environment); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Free WSProtocolDecoderLaCrosse_TX141THBv2. | ||||||
|  |  * @param context Pointer to a WSProtocolDecoderLaCrosse_TX141THBv2 instance | ||||||
|  |  */ | ||||||
|  | void ws_protocol_decoder_lacrosse_tx141thbv2_free(void* context); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Reset decoder WSProtocolDecoderLaCrosse_TX141THBv2. | ||||||
|  |  * @param context Pointer to a WSProtocolDecoderLaCrosse_TX141THBv2 instance | ||||||
|  |  */ | ||||||
|  | void ws_protocol_decoder_lacrosse_tx141thbv2_reset(void* context); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Parse a raw sequence of levels and durations received from the air. | ||||||
|  |  * @param context Pointer to a WSProtocolDecoderLaCrosse_TX141THBv2 instance | ||||||
|  |  * @param level Signal level true-high false-low | ||||||
|  |  * @param duration Duration of this level in, us | ||||||
|  |  */ | ||||||
|  | void ws_protocol_decoder_lacrosse_tx141thbv2_feed(void* context, bool level, uint32_t duration); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Getting the hash sum of the last randomly received parcel. | ||||||
|  |  * @param context Pointer to a WSProtocolDecoderLaCrosse_TX141THBv2 instance | ||||||
|  |  * @return hash Hash sum | ||||||
|  |  */ | ||||||
|  | uint8_t ws_protocol_decoder_lacrosse_tx141thbv2_get_hash_data(void* context); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Serialize data WSProtocolDecoderLaCrosse_TX141THBv2. | ||||||
|  |  * @param context Pointer to a WSProtocolDecoderLaCrosse_TX141THBv2 instance | ||||||
|  |  * @param flipper_format Pointer to a FlipperFormat instance | ||||||
|  |  * @param preset The modulation on which the signal was received, SubGhzRadioPreset | ||||||
|  |  * @return true On success | ||||||
|  |  */ | ||||||
|  | bool ws_protocol_decoder_lacrosse_tx141thbv2_serialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format, | ||||||
|  |     SubGhzRadioPreset* preset); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Deserialize data WSProtocolDecoderLaCrosse_TX141THBv2. | ||||||
|  |  * @param context Pointer to a WSProtocolDecoderLaCrosse_TX141THBv2 instance | ||||||
|  |  * @param flipper_format Pointer to a FlipperFormat instance | ||||||
|  |  * @return true On success | ||||||
|  |  */ | ||||||
|  | bool ws_protocol_decoder_lacrosse_tx141thbv2_deserialize( | ||||||
|  |     void* context, | ||||||
|  |     FlipperFormat* flipper_format); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Getting a textual representation of the received data. | ||||||
|  |  * @param context Pointer to a WSProtocolDecoderLaCrosse_TX141THBv2 instance | ||||||
|  |  * @param output Resulting text | ||||||
|  |  */ | ||||||
|  | void ws_protocol_decoder_lacrosse_tx141thbv2_get_string(void* context, FuriString* output); | ||||||
| @ -127,7 +127,7 @@ static void ws_protocol_nexus_th_remote_controller(WSBlockGeneric* instance) { | |||||||
|     instance->id = (instance->data >> 28) & 0xFF; |     instance->id = (instance->data >> 28) & 0xFF; | ||||||
|     instance->battery_low = !((instance->data >> 27) & 1); |     instance->battery_low = !((instance->data >> 27) & 1); | ||||||
|     instance->channel = ((instance->data >> 24) & 0x03) + 1; |     instance->channel = ((instance->data >> 24) & 0x03) + 1; | ||||||
| 
 |     instance->btn = WS_NO_BTN; | ||||||
|     if(!((instance->data >> 23) & 1)) { |     if(!((instance->data >> 23) & 1)) { | ||||||
|         instance->temp = (float)((instance->data >> 12) & 0x07FF) / 10.0f; |         instance->temp = (float)((instance->data >> 12) & 0x07FF) / 10.0f; | ||||||
|     } else { |     } else { | ||||||
|  | |||||||
| @ -5,6 +5,8 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = { | |||||||
|     &ws_protocol_thermopro_tx4, |     &ws_protocol_thermopro_tx4, | ||||||
|     &ws_protocol_nexus_th, |     &ws_protocol_nexus_th, | ||||||
|     &ws_protocol_gt_wt_03, |     &ws_protocol_gt_wt_03, | ||||||
|  |     &ws_protocol_acurite_606tx, | ||||||
|  |     &ws_protocol_lacrosse_tx141thbv2, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const SubGhzProtocolRegistry weather_station_protocol_registry = { | const SubGhzProtocolRegistry weather_station_protocol_registry = { | ||||||
|  | |||||||
| @ -5,5 +5,7 @@ | |||||||
| #include "thermopro_tx4.h" | #include "thermopro_tx4.h" | ||||||
| #include "nexus_th.h" | #include "nexus_th.h" | ||||||
| #include "gt_wt_03.h" | #include "gt_wt_03.h" | ||||||
|  | #include "acurite_606tx.h" | ||||||
|  | #include "lacrosse_tx141thbv2.h" | ||||||
| 
 | 
 | ||||||
| extern const SubGhzProtocolRegistry weather_station_protocol_registry; | extern const SubGhzProtocolRegistry weather_station_protocol_registry; | ||||||
|  | |||||||
| @ -105,11 +105,11 @@ bool ws_block_generic_serialize( | |||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // temp_data = instance->btn;
 |         temp_data = instance->btn; | ||||||
|         // if(!flipper_format_write_uint32(flipper_format, "Btn", &temp_data, 1)) {
 |         if(!flipper_format_write_uint32(flipper_format, "Btn", &temp_data, 1)) { | ||||||
|         //     FURI_LOG_E(TAG, "Unable to add Btn");
 |             FURI_LOG_E(TAG, "Unable to add Btn"); | ||||||
|         //     break;
 |             break; | ||||||
|         // }
 |         } | ||||||
| 
 | 
 | ||||||
|         float temp = instance->temp; |         float temp = instance->temp; | ||||||
|         if(!flipper_format_write_float(flipper_format, "Temp", &temp, 1)) { |         if(!flipper_format_write_float(flipper_format, "Temp", &temp, 1)) { | ||||||
| @ -174,11 +174,11 @@ bool ws_block_generic_deserialize(WSBlockGeneric* instance, FlipperFormat* flipp | |||||||
|         } |         } | ||||||
|         instance->channel = (uint8_t)temp_data; |         instance->channel = (uint8_t)temp_data; | ||||||
| 
 | 
 | ||||||
|         // if(!flipper_format_read_uint32(flipper_format, "Btn", (uint32_t*)&temp_data, 1)) {
 |         if(!flipper_format_read_uint32(flipper_format, "Btn", (uint32_t*)&temp_data, 1)) { | ||||||
|         //     FURI_LOG_E(TAG, "Missing Btn");
 |             FURI_LOG_E(TAG, "Missing Btn"); | ||||||
|         //     break;
 |             break; | ||||||
|         // }
 |         } | ||||||
|         // instance->btn = (uint8_t)temp_data;
 |         instance->btn = (uint8_t)temp_data; | ||||||
| 
 | 
 | ||||||
|         float temp; |         float temp; | ||||||
|         if(!flipper_format_read_float(flipper_format, "Temp", (float*)&temp, 1)) { |         if(!flipper_format_read_float(flipper_format, "Temp", (float*)&temp, 1)) { | ||||||
|  | |||||||
| @ -13,6 +13,13 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #define WS_NO_ID 0xFFFFFFFF | ||||||
|  | #define WS_NO_BATT 0xFF | ||||||
|  | #define WS_NO_HUMIDITY 0xFF | ||||||
|  | #define WS_NO_CHANNEL 0xFF | ||||||
|  | #define WS_NO_BTN 0xFF | ||||||
|  | #define WS_NO_TEMPERATURE -273.0f | ||||||
|  | 
 | ||||||
| typedef struct WSBlockGeneric WSBlockGeneric; | typedef struct WSBlockGeneric WSBlockGeneric; | ||||||
| 
 | 
 | ||||||
| struct WSBlockGeneric { | struct WSBlockGeneric { | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ | |||||||
| #include "../protocols/ws_generic.h" | #include "../protocols/ws_generic.h" | ||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| #include "math.h" |  | ||||||
| 
 | 
 | ||||||
| #define abs(x) ((x) > 0 ? (x) : -(x)) | #define abs(x) ((x) > 0 ? (x) : -(x)) | ||||||
| 
 | 
 | ||||||
| @ -47,14 +46,26 @@ void ws_view_receiver_info_draw(Canvas* canvas, WSReceiverInfoModel* model) { | |||||||
|         model->generic->data_count_bit); |         model->generic->data_count_bit); | ||||||
|     canvas_draw_str(canvas, 5, 8, buffer); |     canvas_draw_str(canvas, 5, 8, buffer); | ||||||
| 
 | 
 | ||||||
|     snprintf(buffer, sizeof(buffer), "Ch: %01d", model->generic->channel); |     if(model->generic->channel != WS_NO_CHANNEL) { | ||||||
|     canvas_draw_str(canvas, 105, 8, buffer); |         snprintf(buffer, sizeof(buffer), "Ch: %01d", model->generic->channel); | ||||||
|  |         canvas_draw_str(canvas, 105, 8, buffer); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     snprintf(buffer, sizeof(buffer), "Sn: 0x%02lX", model->generic->id); |     if(model->generic->id != WS_NO_ID) { | ||||||
|     canvas_draw_str(canvas, 5, 20, buffer); |         snprintf(buffer, sizeof(buffer), "Sn: 0x%02lX", model->generic->id); | ||||||
|  |         canvas_draw_str(canvas, 5, 20, buffer); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     snprintf(buffer, sizeof(buffer), "Batt: %s", (!model->generic->battery_low ? "ok" : "low")); |     if(model->generic->btn != WS_NO_BTN) { | ||||||
|     canvas_draw_str(canvas, 85, 20, buffer); |         snprintf(buffer, sizeof(buffer), "Btn: %01d", model->generic->btn); | ||||||
|  |         canvas_draw_str(canvas, 62, 20, buffer); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(model->generic->battery_low != WS_NO_BATT) { | ||||||
|  |         snprintf( | ||||||
|  |             buffer, sizeof(buffer), "Batt: %s", (!model->generic->battery_low ? "ok" : "low")); | ||||||
|  |         canvas_draw_str(canvas, 90, 20, buffer); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     snprintf(buffer, sizeof(buffer), "Data: 0x%llX", model->generic->data); |     snprintf(buffer, sizeof(buffer), "Data: 0x%llX", model->generic->data); | ||||||
|     canvas_draw_str(canvas, 5, 32, buffer); |     canvas_draw_str(canvas, 5, 32, buffer); | ||||||
| @ -62,19 +73,23 @@ void ws_view_receiver_info_draw(Canvas* canvas, WSReceiverInfoModel* model) { | |||||||
|     elements_bold_rounded_frame(canvas, 2, 37, 123, 25); |     elements_bold_rounded_frame(canvas, 2, 37, 123, 25); | ||||||
|     canvas_set_font(canvas, FontPrimary); |     canvas_set_font(canvas, FontPrimary); | ||||||
| 
 | 
 | ||||||
|     canvas_draw_icon(canvas, 13 + 5, 42, &I_Therm_7x16); |     if(model->generic->temp != WS_NO_TEMPERATURE) { | ||||||
|     snprintf( |         canvas_draw_icon(canvas, 18, 42, &I_Therm_7x16); | ||||||
|         buffer, |         snprintf( | ||||||
|         sizeof(buffer), |             buffer, | ||||||
|         "%3.2d.%d C", |             sizeof(buffer), | ||||||
|         (int16_t)model->generic->temp, |             "%3.2d.%d C", | ||||||
|         abs(((int16_t)(model->generic->temp * 10) - (((int16_t)model->generic->temp) * 10)))); |             (int16_t)model->generic->temp, | ||||||
|     canvas_draw_str_aligned(canvas, 58 + 5, 46, AlignRight, AlignTop, buffer); |             abs(((int16_t)(model->generic->temp * 10) - (((int16_t)model->generic->temp) * 10)))); | ||||||
|     canvas_draw_circle(canvas, 50 + 5, 45, 1); |         canvas_draw_str_aligned(canvas, 63, 46, AlignRight, AlignTop, buffer); | ||||||
|  |         canvas_draw_circle(canvas, 55, 45, 1); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     canvas_draw_icon(canvas, 70 + 5, 42, &I_Humid_10x15); |     if(model->generic->humidity != WS_NO_HUMIDITY) { | ||||||
|     snprintf(buffer, sizeof(buffer), "%d%%", model->generic->humidity); |         canvas_draw_icon(canvas, 75, 42, &I_Humid_10x15); | ||||||
|     canvas_draw_str(canvas, 86 + 5, 54, buffer); |         snprintf(buffer, sizeof(buffer), "%d%%", model->generic->humidity); | ||||||
|  |         canvas_draw_str(canvas, 91, 54, buffer); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool ws_view_receiver_info_input(InputEvent* event, void* context) { | bool ws_view_receiver_info_input(InputEvent* event, void* context) { | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| #include <flipper_format/flipper_format_i.h> | #include <flipper_format/flipper_format_i.h> | ||||||
| #include <lib/toolbox/stream/stream.h> | #include <lib/toolbox/stream/stream.h> | ||||||
| #include <lib/subghz/receiver.h> | #include <lib/subghz/receiver.h> | ||||||
|  | #include "protocols/ws_generic.h" | ||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| @ -224,20 +225,18 @@ WSHistoryStateAddKey | |||||||
|             for(uint8_t i = 0; i < sizeof(uint64_t); i++) { |             for(uint8_t i = 0; i < sizeof(uint64_t); i++) { | ||||||
|                 data = (data << 8) | key_data[i]; |                 data = (data << 8) | key_data[i]; | ||||||
|             } |             } | ||||||
|             if(!(uint32_t)(data >> 32)) { |             uint32_t temp_data = 0; | ||||||
|                 furi_string_printf( |             if(!flipper_format_read_uint32(item->flipper_string, "Ch", (uint32_t*)&temp_data, 1)) { | ||||||
|                     item->item_str, |                 FURI_LOG_E(TAG, "Missing Channel"); | ||||||
|                     "%s %lX", |                 break; | ||||||
|                     furi_string_get_cstr(instance->tmp_string), |  | ||||||
|                     (uint32_t)(data & 0xFFFFFFFF)); |  | ||||||
|             } else { |  | ||||||
|                 furi_string_printf( |  | ||||||
|                     item->item_str, |  | ||||||
|                     "%s %lX%08lX", |  | ||||||
|                     furi_string_get_cstr(instance->tmp_string), |  | ||||||
|                     (uint32_t)(data >> 32), |  | ||||||
|                     (uint32_t)(data & 0xFFFFFFFF)); |  | ||||||
|             } |             } | ||||||
|  |             if(temp_data != WS_NO_CHANNEL) { | ||||||
|  |                 furi_string_cat_printf(instance->tmp_string, " Ch:%X", (uint8_t)temp_data); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             furi_string_printf( | ||||||
|  |                 item->item_str, "%s %llX", furi_string_get_cstr(instance->tmp_string), data); | ||||||
|  | 
 | ||||||
|         } while(false); |         } while(false); | ||||||
|         instance->last_index_write++; |         instance->last_index_write++; | ||||||
|         return WSHistoryStateAddKeyNewDada; |         return WSHistoryStateAddKeyNewDada; | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| entry,status,name,type,params | entry,status,name,type,params | ||||||
| Version,+,3.5,, | Version,+,3.6,, | ||||||
| Header,+,applications/services/bt/bt_service/bt.h,, | Header,+,applications/services/bt/bt_service/bt.h,, | ||||||
| Header,+,applications/services/cli/cli.h,, | Header,+,applications/services/cli/cli.h,, | ||||||
| Header,+,applications/services/cli/cli_vcp.h,, | Header,+,applications/services/cli/cli_vcp.h,, | ||||||
| @ -2271,13 +2271,19 @@ Function,-,subghz_keystore_raw_encrypted_save,_Bool,"const char*, const char*, u | |||||||
| Function,-,subghz_keystore_raw_get_data,_Bool,"const char*, size_t, uint8_t*, size_t" | Function,-,subghz_keystore_raw_get_data,_Bool,"const char*, size_t, uint8_t*, size_t" | ||||||
| Function,-,subghz_keystore_save,_Bool,"SubGhzKeystore*, const char*, uint8_t*" | Function,-,subghz_keystore_save,_Bool,"SubGhzKeystore*, const char*, uint8_t*" | ||||||
| Function,+,subghz_protocol_blocks_add_bit,void,"SubGhzBlockDecoder*, uint8_t" | Function,+,subghz_protocol_blocks_add_bit,void,"SubGhzBlockDecoder*, uint8_t" | ||||||
|  | Function,+,subghz_protocol_blocks_crc16,uint16_t,"const uint8_t[], unsigned, uint16_t, uint16_t" | ||||||
|  | Function,+,subghz_protocol_blocks_crc16lsb,uint16_t,"const uint8_t[], unsigned, uint16_t, uint16_t" | ||||||
| Function,+,subghz_protocol_blocks_crc4,uint8_t,"const uint8_t[], unsigned, uint8_t, uint8_t" | Function,+,subghz_protocol_blocks_crc4,uint8_t,"const uint8_t[], unsigned, uint8_t, uint8_t" | ||||||
| Function,+,subghz_protocol_blocks_crc7,uint8_t,"const uint8_t[], unsigned, uint8_t, uint8_t" | Function,+,subghz_protocol_blocks_crc7,uint8_t,"const uint8_t[], unsigned, uint8_t, uint8_t" | ||||||
| Function,+,subghz_protocol_blocks_crc8,uint8_t,"const uint8_t[], unsigned, uint8_t, uint8_t" | Function,+,subghz_protocol_blocks_crc8,uint8_t,"const uint8_t[], unsigned, uint8_t, uint8_t" | ||||||
|  | Function,+,subghz_protocol_blocks_crc8le,uint8_t,"const uint8_t[], unsigned, uint8_t, uint8_t" | ||||||
| Function,+,subghz_protocol_blocks_get_bit_array,_Bool,"uint8_t[], size_t" | Function,+,subghz_protocol_blocks_get_bit_array,_Bool,"uint8_t[], size_t" | ||||||
| Function,+,subghz_protocol_blocks_get_hash_data,uint8_t,"SubGhzBlockDecoder*, size_t" | Function,+,subghz_protocol_blocks_get_hash_data,uint8_t,"SubGhzBlockDecoder*, size_t" | ||||||
| Function,+,subghz_protocol_blocks_get_parity,uint8_t,"uint64_t, uint8_t" | Function,+,subghz_protocol_blocks_get_parity,uint8_t,"uint64_t, uint8_t" | ||||||
| Function,+,subghz_protocol_blocks_get_upload,size_t,"uint8_t[], size_t, LevelDuration*, size_t, uint32_t" | Function,+,subghz_protocol_blocks_get_upload,size_t,"uint8_t[], size_t, LevelDuration*, size_t, uint32_t" | ||||||
|  | Function,+,subghz_protocol_blocks_lfsr_digest16,uint16_t,"const uint8_t[], unsigned, uint16_t, uint16_t" | ||||||
|  | Function,+,subghz_protocol_blocks_lfsr_digest8,uint8_t,"const uint8_t[], unsigned, uint8_t, uint8_t" | ||||||
|  | Function,+,subghz_protocol_blocks_lfsr_digest8_reflect,uint8_t,"const uint8_t[], int, uint8_t, uint8_t" | ||||||
| Function,+,subghz_protocol_blocks_reverse_key,uint64_t,"uint64_t, uint8_t" | Function,+,subghz_protocol_blocks_reverse_key,uint64_t,"uint64_t, uint8_t" | ||||||
| Function,+,subghz_protocol_blocks_set_bit_array,void,"_Bool, uint8_t[], size_t, size_t" | Function,+,subghz_protocol_blocks_set_bit_array,void,"_Bool, uint8_t[], size_t, size_t" | ||||||
| Function,-,subghz_protocol_decoder_base_deserialize,_Bool,"SubGhzProtocolDecoderBase*, FlipperFormat*" | Function,-,subghz_protocol_decoder_base_deserialize,_Bool,"SubGhzProtocolDecoderBase*, FlipperFormat*" | ||||||
|  | |||||||
| 
 | 
| @ -80,3 +80,140 @@ uint8_t subghz_protocol_blocks_crc8( | |||||||
|     } |     } | ||||||
|     return remainder; |     return remainder; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_blocks_crc8le( | ||||||
|  |     uint8_t const message[], | ||||||
|  |     unsigned nBytes, | ||||||
|  |     uint8_t polynomial, | ||||||
|  |     uint8_t init) { | ||||||
|  |     uint8_t remainder = subghz_protocol_blocks_reverse_key(init, 8); | ||||||
|  |     unsigned byte, bit; | ||||||
|  |     polynomial = subghz_protocol_blocks_reverse_key(polynomial, 8); | ||||||
|  | 
 | ||||||
|  |     for(byte = 0; byte < nBytes; ++byte) { | ||||||
|  |         remainder ^= message[byte]; | ||||||
|  |         for(bit = 0; bit < 8; ++bit) { | ||||||
|  |             if(remainder & 1) { | ||||||
|  |                 remainder = (remainder >> 1) ^ polynomial; | ||||||
|  |             } else { | ||||||
|  |                 remainder = (remainder >> 1); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return remainder; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint16_t subghz_protocol_blocks_crc16lsb( | ||||||
|  |     uint8_t const message[], | ||||||
|  |     unsigned nBytes, | ||||||
|  |     uint16_t polynomial, | ||||||
|  |     uint16_t init) { | ||||||
|  |     uint16_t remainder = init; | ||||||
|  |     unsigned byte, bit; | ||||||
|  | 
 | ||||||
|  |     for(byte = 0; byte < nBytes; ++byte) { | ||||||
|  |         remainder ^= message[byte]; | ||||||
|  |         for(bit = 0; bit < 8; ++bit) { | ||||||
|  |             if(remainder & 1) { | ||||||
|  |                 remainder = (remainder >> 1) ^ polynomial; | ||||||
|  |             } else { | ||||||
|  |                 remainder = (remainder >> 1); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return remainder; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint16_t subghz_protocol_blocks_crc16( | ||||||
|  |     uint8_t const message[], | ||||||
|  |     unsigned nBytes, | ||||||
|  |     uint16_t polynomial, | ||||||
|  |     uint16_t init) { | ||||||
|  |     uint16_t remainder = init; | ||||||
|  |     unsigned byte, bit; | ||||||
|  | 
 | ||||||
|  |     for(byte = 0; byte < nBytes; ++byte) { | ||||||
|  |         remainder ^= message[byte] << 8; | ||||||
|  |         for(bit = 0; bit < 8; ++bit) { | ||||||
|  |             if(remainder & 0x8000) { | ||||||
|  |                 remainder = (remainder << 1) ^ polynomial; | ||||||
|  |             } else { | ||||||
|  |                 remainder = (remainder << 1); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return remainder; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_blocks_lfsr_digest8( | ||||||
|  |     uint8_t const message[], | ||||||
|  |     unsigned bytes, | ||||||
|  |     uint8_t gen, | ||||||
|  |     uint8_t key) { | ||||||
|  |     uint8_t sum = 0; | ||||||
|  |     for(unsigned k = 0; k < bytes; ++k) { | ||||||
|  |         uint8_t data = message[k]; | ||||||
|  |         for(int i = 7; i >= 0; --i) { | ||||||
|  |             // XOR key into sum if data bit is set
 | ||||||
|  |             if((data >> i) & 1) sum ^= key; | ||||||
|  | 
 | ||||||
|  |             // roll the key right (actually the lsb is dropped here)
 | ||||||
|  |             // and apply the gen (needs to include the dropped lsb as msb)
 | ||||||
|  |             if(key & 1) | ||||||
|  |                 key = (key >> 1) ^ gen; | ||||||
|  |             else | ||||||
|  |                 key = (key >> 1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return sum; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_protocol_blocks_lfsr_digest8_reflect( | ||||||
|  |     uint8_t const message[], | ||||||
|  |     int bytes, | ||||||
|  |     uint8_t gen, | ||||||
|  |     uint8_t key) { | ||||||
|  |     uint8_t sum = 0; | ||||||
|  |     // Process message from last byte to first byte (reflected)
 | ||||||
|  |     for(int k = bytes - 1; k >= 0; --k) { | ||||||
|  |         uint8_t data = message[k]; | ||||||
|  |         // Process individual bits of each byte (reflected)
 | ||||||
|  |         for(int i = 0; i < 8; ++i) { | ||||||
|  |             // XOR key into sum if data bit is set
 | ||||||
|  |             if((data >> i) & 1) { | ||||||
|  |                 sum ^= key; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // roll the key left (actually the lsb is dropped here)
 | ||||||
|  |             // and apply the gen (needs to include the dropped lsb as msb)
 | ||||||
|  |             if(key & 0x80) | ||||||
|  |                 key = (key << 1) ^ gen; | ||||||
|  |             else | ||||||
|  |                 key = (key << 1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return sum; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint16_t subghz_protocol_blocks_lfsr_digest16( | ||||||
|  |     uint8_t const message[], | ||||||
|  |     unsigned bytes, | ||||||
|  |     uint16_t gen, | ||||||
|  |     uint16_t key) { | ||||||
|  |     uint16_t sum = 0; | ||||||
|  |     for(unsigned k = 0; k < bytes; ++k) { | ||||||
|  |         uint8_t data = message[k]; | ||||||
|  |         for(int i = 7; i >= 0; --i) { | ||||||
|  |             // if data bit is set then xor with key
 | ||||||
|  |             if((data >> i) & 1) sum ^= key; | ||||||
|  | 
 | ||||||
|  |             // roll the key right (actually the lsb is dropped here)
 | ||||||
|  |             // and apply the gen (needs to include the dropped lsb as msb)
 | ||||||
|  |             if(key & 1) | ||||||
|  |                 key = (key >> 1) ^ gen; | ||||||
|  |             else | ||||||
|  |                 key = (key >> 1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return sum; | ||||||
|  | } | ||||||
| @ -19,7 +19,7 @@ extern "C" { | |||||||
|  * @param key In data |  * @param key In data | ||||||
|  * @param count_bit number of data bits |  * @param count_bit number of data bits | ||||||
|  * @return Reverse data |  * @return Reverse data | ||||||
|  */ |  **/ | ||||||
| uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t count_bit); | uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t count_bit); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -27,7 +27,7 @@ uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t count_bit); | |||||||
|  * @param key In data |  * @param key In data | ||||||
|  * @param count_bit number of data bits |  * @param count_bit number of data bits | ||||||
|  * @return parity |  * @return parity | ||||||
|  */ |  **/ | ||||||
| uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t count_bit); | uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t count_bit); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -37,7 +37,7 @@ uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t count_bit); | |||||||
|  * @param polynomial CRC polynomial |  * @param polynomial CRC polynomial | ||||||
|  * @param init starting crc value |  * @param init starting crc value | ||||||
|  * @return CRC value |  * @return CRC value | ||||||
|  */ |  **/ | ||||||
| uint8_t subghz_protocol_blocks_crc4( | uint8_t subghz_protocol_blocks_crc4( | ||||||
|     uint8_t const message[], |     uint8_t const message[], | ||||||
|     unsigned nBytes, |     unsigned nBytes, | ||||||
| @ -51,7 +51,7 @@ uint8_t subghz_protocol_blocks_crc4( | |||||||
|  * @param polynomial CRC polynomial |  * @param polynomial CRC polynomial | ||||||
|  * @param init starting crc value |  * @param init starting crc value | ||||||
|  * @return CRC value |  * @return CRC value | ||||||
|  */ |  **/ | ||||||
| uint8_t subghz_protocol_blocks_crc7( | uint8_t subghz_protocol_blocks_crc7( | ||||||
|     uint8_t const message[], |     uint8_t const message[], | ||||||
|     unsigned nBytes, |     unsigned nBytes, | ||||||
| @ -67,13 +67,100 @@ uint8_t subghz_protocol_blocks_crc7( | |||||||
|  * @param polynomial byte is from x^7 to x^0 (x^8 is implicitly one) |  * @param polynomial byte is from x^7 to x^0 (x^8 is implicitly one) | ||||||
|  * @param init starting crc value |  * @param init starting crc value | ||||||
|  * @return CRC value |  * @return CRC value | ||||||
|  */ |  **/ | ||||||
| uint8_t subghz_protocol_blocks_crc8( | uint8_t subghz_protocol_blocks_crc8( | ||||||
|     uint8_t const message[], |     uint8_t const message[], | ||||||
|     unsigned nBytes, |     unsigned nBytes, | ||||||
|     uint8_t polynomial, |     uint8_t polynomial, | ||||||
|     uint8_t init); |     uint8_t init); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * "Little-endian" Cyclic Redundancy Check CRC-8 LE | ||||||
|  |  *  Input and output are reflected, i.e. least significant bit is shifted in first. | ||||||
|  |  *  @param message array of bytes to check | ||||||
|  |  *  @param nBytes number of bytes in message | ||||||
|  |  *  @param polynomial CRC polynomial | ||||||
|  |  *  @param init starting crc value | ||||||
|  |  *  @return CRC value | ||||||
|  |  **/ | ||||||
|  | uint8_t subghz_protocol_blocks_crc8le( | ||||||
|  |     uint8_t const message[], | ||||||
|  |     unsigned nBytes, | ||||||
|  |     uint8_t polynomial, | ||||||
|  |     uint8_t init); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  *  CRC-16 LSB. | ||||||
|  |  *  Input and output are reflected, i.e. least significant bit is shifted in first. | ||||||
|  |  *  Note that poly and init already need to be reflected. | ||||||
|  |  *  @param message array of bytes to check | ||||||
|  |  *  @param nBytes number of bytes in message | ||||||
|  |  *  @param polynomial CRC polynomial | ||||||
|  |  *  @param init starting crc value | ||||||
|  |  *  @return CRC value | ||||||
|  |  **/ | ||||||
|  | uint16_t subghz_protocol_blocks_crc16lsb( | ||||||
|  |     uint8_t const message[], | ||||||
|  |     unsigned nBytes, | ||||||
|  |     uint16_t polynomial, | ||||||
|  |     uint16_t init); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * CRC-16. | ||||||
|  |  *  @param message array of bytes to check | ||||||
|  |  *  @param nBytes number of bytes in message | ||||||
|  |  *  @param polynomial CRC polynomial | ||||||
|  |  *  @param init starting crc value | ||||||
|  |  *  @return CRC value | ||||||
|  |  **/ | ||||||
|  | uint16_t subghz_protocol_blocks_crc16( | ||||||
|  |     uint8_t const message[], | ||||||
|  |     unsigned nBytes, | ||||||
|  |     uint16_t polynomial, | ||||||
|  |     uint16_t init); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  *  Digest-8 by "LFSR-based Toeplitz hash". | ||||||
|  |  *  @param message bytes of message data | ||||||
|  |  *  @param bytes number of bytes to digest | ||||||
|  |  *  @param gen key stream generator, needs to includes the MSB if the LFSR is rolling | ||||||
|  |  *  @param key initial key | ||||||
|  |  *  @return digest value | ||||||
|  |  **/ | ||||||
|  | uint8_t subghz_protocol_blocks_lfsr_digest8( | ||||||
|  |     uint8_t const message[], | ||||||
|  |     unsigned bytes, | ||||||
|  |     uint8_t gen, | ||||||
|  |     uint8_t key); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  *  Digest-8 by "LFSR-based Toeplitz hash", byte reflect, bit reflect. | ||||||
|  |  *  @param message bytes of message data | ||||||
|  |  *  @param bytes number of bytes to digest | ||||||
|  |  *  @param gen key stream generator, needs to includes the MSB if the LFSR is rolling | ||||||
|  |  *  @param key initial key | ||||||
|  |  *  @return digest value | ||||||
|  |  **/ | ||||||
|  | uint8_t subghz_protocol_blocks_lfsr_digest8_reflect( | ||||||
|  |     uint8_t const message[], | ||||||
|  |     int bytes, | ||||||
|  |     uint8_t gen, | ||||||
|  |     uint8_t key); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  *  Digest-16 by "LFSR-based Toeplitz hash". | ||||||
|  |  *  @param message bytes of message data | ||||||
|  |  *  @param bytes number of bytes to digest | ||||||
|  |  *  @param gen key stream generator, needs to includes the MSB if the LFSR is rolling | ||||||
|  |  *  @param key initial key | ||||||
|  |  *  @return digest value | ||||||
|  |  **/ | ||||||
|  | uint16_t subghz_protocol_blocks_lfsr_digest16( | ||||||
|  |     uint8_t const message[], | ||||||
|  |     unsigned bytes, | ||||||
|  |     uint16_t gen, | ||||||
|  |     uint16_t key); | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Skorpionm
						Skorpionm