Skip to content

Commit

Permalink
[FL-2920] WS: add protocol Acurite-606TX, LaCrosse_TX141THBv2 (flippe…
Browse files Browse the repository at this point in the history
…rdevices#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: あく <[email protected]>
  • Loading branch information
Skorpionm and skotopes authored Oct 20, 2022
1 parent 33892eb commit c1bb10a
Show file tree
Hide file tree
Showing 16 changed files with 1,017 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include <furi.h>
#include <furi_hal.h>

#define WS_VERSION_APP "0.1"
#define WS_VERSION_APP "0.2"
#define WS_DEVELOPED "SkorP"
#define WS_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"

Expand Down
252 changes: 252 additions & 0 deletions applications/plugins/weather_station/protocols/acurite_606tx.c
Original file line number Diff line number Diff line change
@@ -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);
}
79 changes: 79 additions & 0 deletions applications/plugins/weather_station/protocols/acurite_606tx.h
Original file line number Diff line number Diff line change
@@ -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);
1 change: 1 addition & 0 deletions applications/plugins/weather_station/protocols/infactory.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ static bool ws_protocol_infactory_check_crc(WSProtocolDecoderInfactory* instance
static void ws_protocol_infactory_remote_controller(WSBlockGeneric* instance) {
instance->id = instance->data >> 32;
instance->battery_low = (instance->data >> 26) & 1;
instance->btn = WS_NO_BTN;
instance->temp = ws_block_generic_fahrenheit_to_celsius(
((float)((instance->data >> 12) & 0x0FFF) - 900.0f) / 10.0f);
instance->humidity =
Expand Down
Loading

0 comments on commit c1bb10a

Please sign in to comment.