Merge remote-tracking branch 'ul/dev' into mntm-dev --nobuild

This commit is contained in:
WillyJL
2026-01-21 21:42:50 +01:00
105 changed files with 2816 additions and 2413 deletions

View File

@@ -4,6 +4,35 @@
#define TAG "SubGhzBlockGeneric"
// Main things: subghz protocols working (serialize, deserialize, decode and encode)
// with flipper_format data isolated from upper level subghz functions and structures.
// So if we need change something inside of protocol data - we need use this API from protocols to get and set data
SubGhzBlockGenericGlobal subghz_block_generic_global; //global structure for subghz
void subghz_block_generic_global_counter_override_set(uint32_t counter) {
subghz_block_generic_global.new_cnt = counter; // set global variable
subghz_block_generic_global.cnt_need_override = true; // set flag for protocols
}
bool subghz_block_generic_global_counter_override_get(uint32_t* counter) {
// if override flag was enabled then return succes TRUE and return overrided counter, else return success = FALSE
// we cut counter bit length to available protocol bits length by the logical AND function
if(subghz_block_generic_global.cnt_need_override) {
*counter = subghz_block_generic_global.new_cnt &
((0xFFFFFFFF >> (32 - subghz_block_generic_global.cnt_length_bit)));
subghz_block_generic_global.cnt_need_override = false;
return true;
} else {
return false;
}
}
void subghz_block_generic_global_reset(void* p) {
UNUSED(p);
memset(&subghz_block_generic_global, 0, sizeof(subghz_block_generic_global));
}
void subghz_block_generic_get_preset_name(const char* preset_name, FuriString* preset_str) {
const char* preset_name_temp;
if(!strcmp(preset_name, "AM270")) {
@@ -12,6 +41,8 @@ void subghz_block_generic_get_preset_name(const char* preset_name, FuriString* p
preset_name_temp = "FuriHalSubGhzPresetOok650Async";
} else if(!strcmp(preset_name, "FM238")) {
preset_name_temp = "FuriHalSubGhzPreset2FSKDev238Async";
} else if(!strcmp(preset_name, "FM12K")) {
preset_name_temp = "FuriHalSubGhzPreset2FSKDev12KAsync";
} else if(!strcmp(preset_name, "FM476")) {
preset_name_temp = "FuriHalSubGhzPreset2FSKDev476Async";
} else {

View File

@@ -27,6 +27,36 @@ struct SubGhzBlockGeneric {
uint32_t seed;
};
typedef struct SubGhzBlockGenericGlobal SubGhzBlockGenericGlobal;
struct SubGhzBlockGenericGlobal {
uint32_t current_cnt; // global counter value;
uint32_t new_cnt; // global counter value;
bool cnt_need_override; // flag for protocols to override signals counter inside of protocols
uint8_t cnt_length_bit; // counter length in bytes (used in counter editor giu)
bool cnt_is_available; // is there counter available for protocol (used in counter editor giu)
};
extern SubGhzBlockGenericGlobal subghz_block_generic_global; //global structure for subghz
/**
* Setup SubGhzBlockGenericGlobal.cnt and cnt_need_override flag to be used in protocols;
* @param counter new counter value;
*/
void subghz_block_generic_global_counter_override_set(uint32_t counter);
/**
* Return true if incomming variable was overrided by SubGhzBlockGenericGlobal.cnt
* else return false and not change incomming variable
* @param counter pointer to counter variable that must be changed
*/
bool subghz_block_generic_global_counter_override_get(uint32_t* counter);
/**
* Reset subghz_block_generic global structure;
*/
void subghz_block_generic_global_reset(void* p);
/**
* Get name preset.
* @param preset_name name preset

View File

@@ -220,6 +220,77 @@ const uint8_t subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs[] = {
0x00,
};
const uint8_t subghz_device_cc1101_preset_2fsk_dev12khz_async_regs[] = {
/* GPIO GD0 */
CC1101_IOCFG0,
0x0D, // GD0 as async serial data output/input
/* Frequency Synthesizer Control */
CC1101_FSCTRL1,
0x06, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz
/* Packet engine */
CC1101_PKTCTRL0,
0x32, // Async, continious, no whitening
CC1101_PKTCTRL1,
0x04,
// // Modem Configuration
CC1101_MDMCFG0,
0x00,
CC1101_MDMCFG1,
0x02,
CC1101_MDMCFG2,
0x04, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized)
CC1101_MDMCFG3,
0x83, // Data rate is 4.79794 kBaud
CC1101_MDMCFG4,
0x67, //Rx BW filter is 270.833333 kHz
CC1101_DEVIATN,
0x30, //Deviation 12.695312 kHz
/* Main Radio Control State Machine */
CC1101_MCSM0,
0x18, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us)
/* Frequency Offset Compensation Configuration */
CC1101_FOCCFG,
0x16, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off
/* Automatic Gain Control */
CC1101_AGCCTRL0,
0x91, //10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary
CC1101_AGCCTRL1,
0x00, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET
CC1101_AGCCTRL2,
0x07, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB
/* Wake on radio and timeouts control */
CC1101_WORCTRL,
0xFB, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours
/* Frontend configuration */
CC1101_FREND0,
0x10, // Adjusts current TX LO buffer
CC1101_FREND1,
0x56,
/* End load reg */
0,
0,
// 2fsk_async_patable[8]
0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
const uint8_t subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs[] = {
/* GPIO GD0 */

View File

@@ -8,6 +8,7 @@ extern "C" {
extern const uint8_t subghz_device_cc1101_preset_ook_270khz_async_regs[];
extern const uint8_t subghz_device_cc1101_preset_ook_650khz_async_regs[];
extern const uint8_t subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs[];
extern const uint8_t subghz_device_cc1101_preset_2fsk_dev12khz_async_regs[];
extern const uint8_t subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs[];
extern const uint8_t subghz_device_cc1101_preset_msk_99_97kb_async_regs[];
extern const uint8_t subghz_device_cc1101_preset_gfsk_9_99kb_async_regs[];

View File

@@ -38,6 +38,9 @@ static void subghz_device_cc1101_int_interconnect_load_preset(
case FuriHalSubGhzPreset2FSKDev238Async:
furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs);
break;
case FuriHalSubGhzPreset2FSKDev12KAsync:
furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_2fsk_dev12khz_async_regs);
break;
case FuriHalSubGhzPreset2FSKDev476Async:
furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs);
break;

View File

@@ -6,6 +6,7 @@ typedef enum {
FuriHalSubGhzPresetOok270Async, /**< OOK, bandwidth 270kHz, asynchronous */
FuriHalSubGhzPresetOok650Async, /**< OOK, bandwidth 650kHz, asynchronous */
FuriHalSubGhzPreset2FSKDev238Async, /**< FM, deviation 2.380371 kHz, asynchronous */
FuriHalSubGhzPreset2FSKDev12KAsync, /**< FM, deviation 12.695312 kHz, asynchronous */
FuriHalSubGhzPreset2FSKDev476Async, /**< FM, deviation 47.60742 kHz, asynchronous */
FuriHalSubGhzPresetMSK99_97KbAsync, /**< MSK, deviation 47.60742 kHz, 99.97Kb/s, asynchronous */
FuriHalSubGhzPresetGFSK9_99KbAsync, /**< GFSK, deviation 19.042969 kHz, 9.996Kb/s, asynchronous */

View File

@@ -0,0 +1,252 @@
#include "aes_common.h"
static const uint8_t aes_sbox[256] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab,
0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4,
0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71,
0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6,
0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb,
0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45,
0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44,
0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a,
0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49,
0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25,
0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e,
0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1,
0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb,
0x16};
static const uint8_t aes_sbox_inv[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7,
0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde,
0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42,
0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c,
0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15,
0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7,
0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc,
0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad,
0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d,
0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8,
0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51,
0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0,
0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c,
0x7d};
static const uint8_t aes_rcon[10] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
static uint8_t gf_mul2(uint8_t x) {
return ((x >> 7) * 0x1b) ^ (x << 1);
}
static void aes_subbytes(uint8_t* state) {
for(uint8_t row = 0; row < 4; row++) {
for(uint8_t col = 0; col < 4; col++) {
state[row + col * 4] = aes_sbox[state[row + col * 4]];
}
}
}
static void aes_subbytes_inv(uint8_t* state) {
for(uint8_t row = 0; row < 4; row++) {
for(uint8_t col = 0; col < 4; col++) {
state[row + col * 4] = aes_sbox_inv[state[row + col * 4]];
}
}
}
static void aes_shiftrows(uint8_t* state) {
uint8_t temp;
temp = state[1];
state[1] = state[5];
state[5] = state[9];
state[9] = state[13];
state[13] = temp;
temp = state[2];
state[2] = state[10];
state[10] = temp;
temp = state[6];
state[6] = state[14];
state[14] = temp;
temp = state[15];
state[15] = state[11];
state[11] = state[7];
state[7] = state[3];
state[3] = temp;
}
static void aes_shiftrows_inv(uint8_t* state) {
uint8_t temp;
temp = state[13];
state[13] = state[9];
state[9] = state[5];
state[5] = state[1];
state[1] = temp;
temp = state[2];
state[2] = state[10];
state[10] = temp;
temp = state[6];
state[6] = state[14];
state[14] = temp;
temp = state[3];
state[3] = state[7];
state[7] = state[11];
state[11] = state[15];
state[15] = temp;
}
static void aes_mixcolumns(uint8_t* state) {
uint8_t a, b, c, d;
for(uint8_t i = 0; i < 4; i++) {
a = state[i * 4];
b = state[i * 4 + 1];
c = state[i * 4 + 2];
d = state[i * 4 + 3];
uint8_t a2 = gf_mul2(a);
uint8_t b2 = gf_mul2(b);
uint8_t c2 = gf_mul2(c);
uint8_t d2 = gf_mul2(d);
state[i * 4] = a2 ^ b2 ^ b ^ c ^ d;
state[i * 4 + 1] = a ^ b2 ^ c2 ^ c ^ d;
state[i * 4 + 2] = a ^ b ^ c2 ^ d2 ^ d;
state[i * 4 + 3] = a2 ^ a ^ b ^ c ^ d2;
}
}
static void aes_mixcolumns_inv(uint8_t* state) {
uint8_t a, b, c, d;
for(uint8_t i = 0; i < 4; i++) {
a = state[i * 4];
b = state[i * 4 + 1];
c = state[i * 4 + 2];
d = state[i * 4 + 3];
uint8_t a2 = gf_mul2(a);
uint8_t a4 = gf_mul2(a2);
uint8_t a8 = gf_mul2(a4);
uint8_t b2 = gf_mul2(b);
uint8_t b4 = gf_mul2(b2);
uint8_t b8 = gf_mul2(b4);
uint8_t c2 = gf_mul2(c);
uint8_t c4 = gf_mul2(c2);
uint8_t c8 = gf_mul2(c4);
uint8_t d2 = gf_mul2(d);
uint8_t d4 = gf_mul2(d2);
uint8_t d8 = gf_mul2(d4);
state[i * 4] = (a8 ^ a4 ^ a2) ^ (b8 ^ b2 ^ b) ^ (c8 ^ c4 ^ c) ^ (d8 ^ d);
state[i * 4 + 1] = (a8 ^ a) ^ (b8 ^ b4 ^ b2) ^ (c8 ^ c2 ^ c) ^ (d8 ^ d4 ^ d);
state[i * 4 + 2] = (a8 ^ a4 ^ a) ^ (b8 ^ b) ^ (c8 ^ c4 ^ c2) ^ (d8 ^ d2 ^ d);
state[i * 4 + 3] = (a8 ^ a2 ^ a) ^ (b8 ^ b4 ^ b) ^ (c8 ^ c) ^ (d8 ^ d4 ^ d2);
}
}
static void aes_addroundkey(uint8_t* state, const uint8_t* round_key) {
for(uint8_t col = 0; col < 4; col++) {
state[col * 4] ^= round_key[col * 4];
state[col * 4 + 1] ^= round_key[col * 4 + 1];
state[col * 4 + 2] ^= round_key[col * 4 + 2];
state[col * 4 + 3] ^= round_key[col * 4 + 3];
}
}
void aes_key_expansion(const uint8_t* key, uint8_t* round_keys) {
for(uint8_t i = 0; i < 16; i++) {
round_keys[i] = key[i];
}
for(uint8_t i = 4; i < 44; i++) {
uint8_t prev_word_idx = (i - 1) * 4;
uint8_t b0 = round_keys[prev_word_idx];
uint8_t b1 = round_keys[prev_word_idx + 1];
uint8_t b2 = round_keys[prev_word_idx + 2];
uint8_t b3 = round_keys[prev_word_idx + 3];
if((i % 4) == 0) {
uint8_t new_b0 = aes_sbox[b1] ^ aes_rcon[(i / 4) - 1];
uint8_t new_b1 = aes_sbox[b2];
uint8_t new_b2 = aes_sbox[b3];
uint8_t new_b3 = aes_sbox[b0];
b0 = new_b0;
b1 = new_b1;
b2 = new_b2;
b3 = new_b3;
}
uint8_t back_word_idx = (i - 4) * 4;
b0 ^= round_keys[back_word_idx];
b1 ^= round_keys[back_word_idx + 1];
b2 ^= round_keys[back_word_idx + 2];
b3 ^= round_keys[back_word_idx + 3];
uint8_t curr_word_idx = i * 4;
round_keys[curr_word_idx] = b0;
round_keys[curr_word_idx + 1] = b1;
round_keys[curr_word_idx + 2] = b2;
round_keys[curr_word_idx + 3] = b3;
}
}
void aes128_encrypt(const uint8_t* expanded_key, uint8_t* data) {
uint8_t state[16];
memcpy(state, data, 16);
aes_addroundkey(state, &expanded_key[0]);
for(uint8_t round = 1; round < 10; round++) {
aes_subbytes(state);
aes_shiftrows(state);
aes_mixcolumns(state);
aes_addroundkey(state, &expanded_key[round * 16]);
}
aes_subbytes(state);
aes_shiftrows(state);
aes_addroundkey(state, &expanded_key[160]);
memcpy(data, state, 16);
}
void aes128_decrypt(const uint8_t* expanded_key, uint8_t* data) {
uint8_t state[16];
memcpy(state, data, 16);
aes_addroundkey(state, &expanded_key[160]);
for(uint8_t round = 9; round > 0; round--) {
aes_shiftrows_inv(state);
aes_subbytes_inv(state);
aes_addroundkey(state, &expanded_key[round * 16]);
aes_mixcolumns_inv(state);
}
aes_shiftrows_inv(state);
aes_subbytes_inv(state);
aes_addroundkey(state, &expanded_key[0]);
memcpy(data, state, 16);
}
void reverse_bits_in_bytes(uint8_t* data, uint8_t len) {
for(uint8_t i = 0; i < len; i++) {
uint8_t byte = data[i];
uint8_t step1 = ((byte & 0x55) << 1) | ((byte >> 1) & 0x55);
uint8_t step2 = ((step1 & 0x33) << 2) | ((step1 >> 2) & 0x33);
data[i] = ((step2 & 0x0F) << 4) | (step2 >> 4);
}
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "base.h"
#include <furi.h>
void reverse_bits_in_bytes(uint8_t* data, uint8_t len);
void aes128_decrypt(const uint8_t* expanded_key, uint8_t* data);
void aes128_encrypt(const uint8_t* expanded_key, uint8_t* data);
void aes_key_expansion(const uint8_t* key, uint8_t* round_keys);

View File

@@ -9,7 +9,8 @@
#define TAG "SubGhzProtocoAlutech_at_4n"
#define SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE 0xFFFFFFFF
#define SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE 0xFFFFFFFFFFFFFFFF
#define SUBGHZ_ALUTECH_AT_4N_RAINBOW_TABLE_SIZE_BYTES 32
static const SubGhzBlockConst subghz_protocol_alutech_at_4n_const = {
.te_short = 400,
@@ -142,27 +143,21 @@ LevelDuration subghz_protocol_encoder_alutech_at_4n_yield(void* context) {
}
/**
* Read bytes from rainbow table
* @param file_name Full path to rainbow table the file
* Read bytes from buffer array with rainbow table
* @param buffer Pointer to decrypted magic data buffer
* @param number_alutech_at_4n_magic_data number in the array
* @return alutech_at_4n_magic_data
*/
static uint32_t subghz_protocol_alutech_at_4n_get_magic_data_in_file(
const char* file_name,
static uint32_t subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(
uint8_t* buffer,
uint8_t number_alutech_at_4n_magic_data) {
if(!strcmp(file_name, "")) return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE;
uint8_t buffer[sizeof(uint32_t)] = {0};
uint32_t address = number_alutech_at_4n_magic_data * sizeof(uint32_t);
uint32_t alutech_at_4n_magic_data = 0;
if(subghz_keystore_raw_get_data(file_name, address, buffer, sizeof(uint32_t))) {
for(size_t i = 0; i < sizeof(uint32_t); i++) {
alutech_at_4n_magic_data = (alutech_at_4n_magic_data << 8) | buffer[i];
}
} else {
alutech_at_4n_magic_data = SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE;
for(size_t i = address; i < (address + sizeof(uint32_t)); i++) {
alutech_at_4n_magic_data = (alutech_at_4n_magic_data << 8) | buffer[i];
}
return alutech_at_4n_magic_data;
}
@@ -197,17 +192,29 @@ static uint8_t subghz_protocol_alutech_at_4n_decrypt_data_crc(uint8_t data) {
}
static uint64_t subghz_protocol_alutech_at_4n_decrypt(uint64_t data, const char* file_name) {
// load and decrypt rainbow table from file to buffer array in RAM
if(!file_name) return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE;
uint8_t buffer[SUBGHZ_ALUTECH_AT_4N_RAINBOW_TABLE_SIZE_BYTES] = {0};
uint8_t* buffer_ptr = (uint8_t*)&buffer;
if(subghz_keystore_raw_get_data(
file_name, 0, buffer, SUBGHZ_ALUTECH_AT_4N_RAINBOW_TABLE_SIZE_BYTES)) {
} else {
return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE;
}
uint8_t* p = (uint8_t*)&data;
uint32_t data1 = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
uint32_t data2 = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7];
uint32_t data3 = 0;
uint32_t magic_data[] = {
subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 0),
subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 1),
subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 2),
subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 3),
subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 4),
subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 5)};
subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 0),
subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 1),
subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 2),
subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 3),
subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 4),
subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 5)};
uint32_t i = magic_data[0];
do {
@@ -232,17 +239,29 @@ static uint64_t subghz_protocol_alutech_at_4n_decrypt(uint64_t data, const char*
}
static uint64_t subghz_protocol_alutech_at_4n_encrypt(uint64_t data, const char* file_name) {
// load and decrypt rainbow table from file to buffer array in RAM
if(!file_name) return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE;
uint8_t buffer[SUBGHZ_ALUTECH_AT_4N_RAINBOW_TABLE_SIZE_BYTES] = {0};
uint8_t* buffer_ptr = (uint8_t*)&buffer;
if(subghz_keystore_raw_get_data(
file_name, 0, buffer, SUBGHZ_ALUTECH_AT_4N_RAINBOW_TABLE_SIZE_BYTES)) {
} else {
return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE;
}
uint8_t* p = (uint8_t*)&data;
uint32_t data1 = 0;
uint32_t data2 = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
uint32_t data3 = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7];
uint32_t magic_data[] = {
subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 6),
subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 4),
subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 5),
subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 1),
subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 2),
subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 0)};
subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 6),
subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 4),
subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 5),
subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 1),
subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 2),
subghz_protocol_alutech_at_4n_get_magic_data_from_buffer(buffer_ptr, 0)};
do {
data1 = data1 + magic_data[0];
@@ -280,12 +299,17 @@ static bool subghz_protocol_alutech_at_4n_gen_data(
if(alutech_at4n_counter_mode == 0) {
// Check for OFEX (overflow experimental) mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
}
}
} else {
//OFFEX mode
if((instance->generic.cnt + 0x1) > 0xFFFF) {
instance->generic.cnt = 0;
} else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) {
@@ -461,7 +485,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_alutech_at_4n_deserialize(
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
@@ -872,6 +896,12 @@ void subghz_protocol_decoder_alutech_at_4n_get_string(void* context, FuriString*
uint32_t code_found_hi = instance->generic.data >> 32;
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
// push protocol data to global variable
subghz_block_generic_global.cnt_is_available = true;
subghz_block_generic_global.cnt_length_bit = 16;
subghz_block_generic_global.current_cnt = instance->generic.cnt;
//
furi_string_cat_printf(
output,
"%s\r\n"

View File

@@ -152,7 +152,7 @@ SubGhzProtocolStatus
FURI_LOG_E(TAG, "Deserialize error");
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -1,5 +1,6 @@
#include "base.h"
#include "registry.h"
#include "../blocks/generic.h"
void subghz_protocol_decoder_base_set_decoder_callback(
SubGhzProtocolDecoderBase* decoder_base,
@@ -17,6 +18,8 @@ bool subghz_protocol_decoder_base_get_string(
furi_check(decoder_base);
furi_check(output);
subghz_block_generic_global_reset(0);
bool status = false;
if(decoder_base->protocol && decoder_base->protocol->decoder &&

View File

@@ -0,0 +1,681 @@
#include "beninca_arc.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#include "core/log.h"
#include <stddef.h>
#include <stdint.h>
#include "aes_common.h"
#include "../blocks/custom_btn_i.h"
#define TAG "BenincaARC"
#define BENINCA_ARC_KEY_TYPE 9u
static const SubGhzBlockConst subghz_protocol_beninca_arc_const = {
.te_short = 300,
.te_long = 600,
.te_delta = 155,
.min_count_bit_for_found = 128,
};
typedef enum {
BenincaARCDecoderStart = 0,
BenincaARCDecoderHighLevel,
BenincaARCDecoderLowLevel,
} BenincaARCDecoderState;
struct SubGhzProtocolDecoderBenincaARC {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
SubGhzKeystore* keystore;
};
struct SubGhzProtocolEncoderBenincaARC {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
SubGhzKeystore* keystore;
};
const SubGhzProtocolDecoder subghz_protocol_beninca_arc_decoder = {
.alloc = subghz_protocol_decoder_beninca_arc_alloc,
.free = subghz_protocol_decoder_beninca_arc_free,
.feed = subghz_protocol_decoder_beninca_arc_feed,
.reset = subghz_protocol_decoder_beninca_arc_reset,
.get_hash_data = NULL,
.get_hash_data_long = subghz_protocol_decoder_beninca_arc_get_hash_data,
.serialize = subghz_protocol_decoder_beninca_arc_serialize,
.deserialize = subghz_protocol_decoder_beninca_arc_deserialize,
.get_string = subghz_protocol_decoder_beninca_arc_get_string,
.get_string_brief = NULL,
};
const SubGhzProtocolEncoder subghz_protocol_beninca_arc_encoder = {
.alloc = subghz_protocol_encoder_beninca_arc_alloc,
.free = subghz_protocol_encoder_beninca_arc_free,
.deserialize = subghz_protocol_encoder_beninca_arc_deserialize,
.stop = subghz_protocol_encoder_beninca_arc_stop,
.yield = subghz_protocol_encoder_beninca_arc_yield,
};
const SubGhzProtocol subghz_protocol_beninca_arc = {
.name = SUBGHZ_PROTOCOL_BENINCA_ARC_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_beninca_arc_decoder,
.encoder = &subghz_protocol_beninca_arc_encoder,
};
// Get custom button code
static uint8_t subghz_protocol_beninca_arc_get_btn_code(void) {
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_code = subghz_custom_btn_get_original();
uint8_t btn = original_btn_code;
// Set custom button
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) {
// Restore original button code
btn = original_btn_code;
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) {
switch(original_btn_code) {
case 0x02:
btn = 0x04;
break;
case 0x04:
btn = 0x02;
break;
case 0xFF:
btn = 0x04;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
switch(original_btn_code) {
case 0x02:
btn = 0xFF;
break;
case 0x04:
btn = 0xFF;
break;
case 0xFF:
btn = 0x02;
break;
default:
break;
}
}
return btn;
}
static void get_subghz_protocol_beninca_arc_aes_key(SubGhzKeystore* keystore, uint8_t* aes_key) {
uint64_t mfkey = 0;
for
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
if(manufacture_code->type == BENINCA_ARC_KEY_TYPE) {
mfkey = manufacture_code->key;
break;
}
}
uint32_t derived_lo = (uint32_t)(mfkey & 0xFFFFFFFF);
uint32_t derived_hi = (uint32_t)((mfkey >> 32) & 0xFFFFFFFF);
uint64_t val64_a = ((uint64_t)derived_hi << 32) | derived_lo;
for(uint8_t i = 0; i < 8; i++) {
aes_key[i] = (val64_a >> (56 - i * 8)) & 0xFF;
}
uint32_t new_lo = ((derived_hi >> 24) & 0xFF) | ((derived_hi >> 8) & 0xFF00) |
((derived_hi << 8) & 0xFF0000) | ((derived_hi << 24) & 0xFF000000);
uint32_t new_hi = ((derived_lo >> 24) & 0xFF) | ((derived_lo >> 8) & 0xFF00) |
((derived_lo << 8) & 0xFF0000) | ((derived_lo << 24) & 0xFF000000);
uint64_t val64_b = ((uint64_t)new_hi << 32) | new_lo;
for(uint8_t i = 0; i < 8; i++) {
aes_key[i + 8] = (val64_b >> (56 - i * 8)) & 0xFF;
}
}
static uint64_t
subghz_protocol_beninca_arc_decrypt(SubGhzBlockGeneric* generic, SubGhzKeystore* keystore) {
// Beninca ARC Decoder
// 01.2026 - @xMasterX (MMX) & @zero-mega
// Decrypt data
uint8_t encrypted_data[16];
for(uint8_t i = 0; i < 8; i++) {
encrypted_data[i] = (generic->data >> (56 - i * 8)) & 0xFF;
encrypted_data[i + 8] = (generic->data_2 >> (56 - i * 8)) & 0xFF;
}
reverse_bits_in_bytes(encrypted_data, 16);
uint8_t aes_key[16];
get_subghz_protocol_beninca_arc_aes_key(keystore, aes_key);
uint8_t expanded_key[176];
aes_key_expansion(aes_key, expanded_key);
aes128_decrypt(expanded_key, encrypted_data);
// Serial number of remote
generic->serial = ((uint32_t)encrypted_data[0] << 24) | ((uint32_t)encrypted_data[1] << 16) |
((uint32_t)encrypted_data[2] << 8) | encrypted_data[3];
// Button code
generic->btn = encrypted_data[4];
// Middle bytes contains mini counter that is increased while button is held
// its value mostly stored in encrypted_data[9] but might be in other bytes as well
// In order to support all variants we read all middle bytes as uint64_t
// In case you have the remote with ARC rolling code please share RAW recording where you hold button for 15+ sec with us to improve this part!
uint64_t middle_bytes = 0;
middle_bytes = ((uint64_t)encrypted_data[5] << 32) | ((uint64_t)encrypted_data[6] << 24) |
((uint64_t)encrypted_data[7] << 16) | ((uint64_t)encrypted_data[8] << 8) |
encrypted_data[9];
// 32-bit counter
generic->cnt = ((uint32_t)encrypted_data[10] << 24) | ((uint32_t)encrypted_data[11] << 16) |
((uint32_t)encrypted_data[12] << 8) | encrypted_data[13];
// Fixed constant value AA 55
generic->seed = ((uint16_t)encrypted_data[14] << 8) | encrypted_data[15];
// Save original button for later use
if(subghz_custom_btn_get_original() == 0) {
subghz_custom_btn_set_original(generic->btn);
}
subghz_custom_btn_set_max(2);
return middle_bytes;
}
static void subghz_protocol_beninca_arc_encrypt(
SubGhzBlockGeneric* generic,
SubGhzKeystore* keystore,
uint64_t middle_bytes) {
// Beninca ARC Encoder
// 01.2026 - @xMasterX (MMX) & @zero-mega
// Encrypt data
uint8_t plaintext[16];
plaintext[0] = (generic->serial >> 24) & 0xFF;
plaintext[1] = (generic->serial >> 16) & 0xFF;
plaintext[2] = (generic->serial >> 8) & 0xFF;
plaintext[3] = generic->serial & 0xFF;
plaintext[4] = generic->btn;
plaintext[5] = (middle_bytes >> 32) & 0xFF;
plaintext[6] = (middle_bytes >> 24) & 0xFF;
plaintext[7] = (middle_bytes >> 16) & 0xFF;
plaintext[8] = (middle_bytes >> 8) & 0xFF;
plaintext[9] = middle_bytes & 0xFF;
plaintext[10] = (generic->cnt >> 24) & 0xFF;
plaintext[11] = (generic->cnt >> 16) & 0xFF;
plaintext[12] = (generic->cnt >> 8) & 0xFF;
plaintext[13] = generic->cnt & 0xFF;
plaintext[14] = (generic->seed >> 8) & 0xFF;
plaintext[15] = generic->seed & 0xFF;
uint8_t aes_key[16];
get_subghz_protocol_beninca_arc_aes_key(keystore, aes_key);
uint8_t expanded_key[176];
aes_key_expansion(aes_key, expanded_key);
aes128_encrypt(expanded_key, plaintext);
reverse_bits_in_bytes(plaintext, 16);
for(uint8_t i = 0; i < 8; i++) {
generic->data = (generic->data << 8) | plaintext[i];
generic->data_2 = (generic->data_2 << 8) | plaintext[i + 8];
}
return;
}
void* subghz_protocol_encoder_beninca_arc_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolEncoderBenincaARC* instance = malloc(sizeof(SubGhzProtocolEncoderBenincaARC));
instance->base.protocol = &subghz_protocol_beninca_arc;
instance->generic.protocol_name = instance->base.protocol->name;
instance->keystore = subghz_environment_get_keystore(environment);
instance->encoder.repeat = 10;
instance->encoder.size_upload = 800;
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_running = false;
return instance;
}
void subghz_protocol_encoder_beninca_arc_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderBenincaARC* instance = context;
free(instance->encoder.upload);
free(instance);
}
void subghz_protocol_encoder_beninca_arc_stop(void* context) {
furi_assert(context);
SubGhzProtocolEncoderBenincaARC* instance = context;
instance->encoder.is_running = false;
}
static void subghz_protocol_beninca_arc_encoder_get_upload(
SubGhzProtocolEncoderBenincaARC* instance,
size_t* index) {
furi_assert(instance);
size_t index_local = *index;
// First part of data 64 bits
for(uint8_t i = 64; i > 0; i--) {
if(bit_read(instance->generic.data, i - 1)) {
// Send bit 1
instance->encoder.upload[index_local++] =
level_duration_make(true, (uint32_t)subghz_protocol_beninca_arc_const.te_short);
instance->encoder.upload[index_local++] =
level_duration_make(false, (uint32_t)subghz_protocol_beninca_arc_const.te_long);
} else {
// Send bit 0
instance->encoder.upload[index_local++] =
level_duration_make(true, (uint32_t)subghz_protocol_beninca_arc_const.te_long);
instance->encoder.upload[index_local++] =
level_duration_make(false, (uint32_t)subghz_protocol_beninca_arc_const.te_short);
}
}
// Second part of data 64 bits - total 128bits data
for(uint8_t i = 64; i > 0; i--) {
if(bit_read(instance->generic.data_2, i - 1)) {
// Send bit 1
instance->encoder.upload[index_local++] =
level_duration_make(true, (uint32_t)subghz_protocol_beninca_arc_const.te_short);
instance->encoder.upload[index_local++] =
level_duration_make(false, (uint32_t)subghz_protocol_beninca_arc_const.te_long);
} else {
// Send bit 0
instance->encoder.upload[index_local++] =
level_duration_make(true, (uint32_t)subghz_protocol_beninca_arc_const.te_long);
instance->encoder.upload[index_local++] =
level_duration_make(false, (uint32_t)subghz_protocol_beninca_arc_const.te_short);
}
}
// Add stop bit
instance->encoder.upload[index_local++] =
level_duration_make(true, (uint32_t)subghz_protocol_beninca_arc_const.te_short);
// Add gap between packets
instance->encoder.upload[index_local++] =
level_duration_make(false, (uint32_t)subghz_protocol_beninca_arc_const.te_long * 15);
*index = index_local;
}
static void subghz_protocol_beninca_arc_encoder_prepare_packets(
SubGhzProtocolEncoderBenincaARC* instance) {
furi_assert(instance);
// Counter increment
// check OFEX mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFFFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
}
}
} else {
// TODO: OFEX mode
instance->generic.cnt += 1;
}
// Index for upload array
size_t index = 0;
// Generate new key using custom or default button
instance->generic.btn = subghz_protocol_beninca_arc_get_btn_code();
// Make 3 packets with different mini counter values - 2, 4, 6
for(uint8_t i = 0; i < 3; i++) {
subghz_protocol_beninca_arc_encrypt(
&instance->generic, instance->keystore, (uint64_t)((i + 1) * 2));
subghz_protocol_beninca_arc_encoder_get_upload(instance, &index);
}
// Set final size of upload array
instance->encoder.size_upload = index;
}
bool subghz_protocol_beninca_arc_create_data(
void* context,
FlipperFormat* flipper_format,
uint32_t serial,
uint8_t btn,
uint32_t cnt,
SubGhzRadioPreset* preset) {
furi_assert(context);
// UwU
SubGhzProtocolEncoderBenincaARC* instance = context;
instance->generic.serial = serial;
instance->generic.btn = btn; // 02 / 04
instance->generic.cnt = cnt;
instance->generic.seed = 0xAA55; // Fixed value constant
instance->generic.data_count_bit = 128;
subghz_protocol_beninca_arc_encrypt(&instance->generic, instance->keystore, 0x1);
SubGhzProtocolStatus res =
subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
uint8_t key_data[sizeof(uint64_t)] = {0};
for(size_t i = 0; i < sizeof(uint64_t); i++) {
key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> (i * 8)) & 0xFF;
}
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
res = SubGhzProtocolStatusErrorParserOthers;
}
if((res == SubGhzProtocolStatusOk) &&
!flipper_format_insert_or_update_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Unable to add Data2");
res = SubGhzProtocolStatusErrorParserOthers;
}
return res == SubGhzProtocolStatusOk;
}
SubGhzProtocolStatus
subghz_protocol_encoder_beninca_arc_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderBenincaARC* instance = context;
SubGhzProtocolStatus res = SubGhzProtocolStatusError;
do {
if(SubGhzProtocolStatusOk !=
subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
FURI_LOG_E(TAG, "Deserialize error");
break;
}
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
uint8_t key_data[sizeof(uint64_t)] = {0};
if(!flipper_format_read_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Missing Data");
break;
}
for(uint8_t i = 0; i < sizeof(uint64_t); i++) {
instance->generic.data_2 = instance->generic.data_2 << 8 | key_data[i];
}
// TODO: if minicounter having larger value use it instead of fixed values
subghz_protocol_beninca_arc_decrypt(&instance->generic, instance->keystore);
subghz_protocol_beninca_arc_encoder_prepare_packets(instance);
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
for(size_t i = 0; i < sizeof(uint64_t); i++) {
key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF;
}
if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Unable to update Key");
break;
}
for(size_t i = 0; i < sizeof(uint64_t); i++) {
key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> i * 8) & 0xFF;
}
if(!flipper_format_update_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Unable to update Data");
break;
}
instance->encoder.is_running = true;
res = SubGhzProtocolStatusOk;
} while(false);
return res;
}
LevelDuration subghz_protocol_encoder_beninca_arc_yield(void* context) {
furi_assert(context);
SubGhzProtocolEncoderBenincaARC* instance = context;
if(instance->encoder.repeat == 0 || !instance->encoder.is_running) {
instance->encoder.is_running = 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_beninca_arc_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderBenincaARC* instance = malloc(sizeof(SubGhzProtocolDecoderBenincaARC));
instance->base.protocol = &subghz_protocol_beninca_arc;
instance->generic.protocol_name = instance->base.protocol->name;
instance->keystore = subghz_environment_get_keystore(environment);
instance->decoder.parser_step = BenincaARCDecoderStart;
return instance;
}
void subghz_protocol_decoder_beninca_arc_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderBenincaARC* instance = context;
free(instance);
}
void subghz_protocol_decoder_beninca_arc_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderBenincaARC* instance = context;
instance->decoder.parser_step = BenincaARCDecoderStart;
}
void subghz_protocol_decoder_beninca_arc_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderBenincaARC* instance = context;
switch(instance->decoder.parser_step) {
case BenincaARCDecoderStart:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_beninca_arc_const.te_long * 16) <
subghz_protocol_beninca_arc_const.te_delta * 15)) {
// GAP (9300 +- 2325 us) found switch to next state
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
instance->decoder.parser_step = BenincaARCDecoderHighLevel;
break;
}
// No GAP so stay in current state
break;
case BenincaARCDecoderHighLevel:
if(level) {
instance->decoder.te_last = duration;
instance->decoder.parser_step = BenincaARCDecoderLowLevel;
// Check if we have collected enough bits
if((instance->decoder.decode_count_bit ==
(subghz_protocol_beninca_arc_const.min_count_bit_for_found / 2)) &&
(instance->decoder.decode_data != 0)) {
// Half data captured 64 bits
instance->generic.data = instance->decoder.decode_data;
instance->decoder.decode_data = 0;
} else if(
instance->decoder.decode_count_bit ==
subghz_protocol_beninca_arc_const.min_count_bit_for_found) {
// Full data captured 128 bits
instance->generic.data_2 = instance->decoder.decode_data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
instance->decoder.parser_step = BenincaARCDecoderStart;
if(instance->base.callback) {
instance->base.callback(&instance->base, instance->base.context);
}
break;
}
} else {
instance->decoder.parser_step = BenincaARCDecoderStart;
}
break;
case BenincaARCDecoderLowLevel:
if(!level) {
// Bit 1 is short and long timing = 300us HIGH (te_last) and 600us LOW
if((DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_beninca_arc_const.te_short) <
subghz_protocol_beninca_arc_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_beninca_arc_const.te_long) <
subghz_protocol_beninca_arc_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = BenincaARCDecoderHighLevel;
// Bit 0 is long and short timing = 600us HIGH (te_last) and 300us LOW
} else if(
(DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_beninca_arc_const.te_long) <
subghz_protocol_beninca_arc_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_beninca_arc_const.te_short) <
subghz_protocol_beninca_arc_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = BenincaARCDecoderHighLevel;
} else {
instance->decoder.parser_step = BenincaARCDecoderStart;
}
break;
} else {
instance->decoder.parser_step = BenincaARCDecoderStart;
break;
}
}
}
uint32_t subghz_protocol_decoder_beninca_arc_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderBenincaARC* instance = context;
return subghz_protocol_blocks_get_hash_data_long(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
SubGhzProtocolStatus subghz_protocol_decoder_beninca_arc_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
SubGhzProtocolDecoderBenincaARC* instance = context;
SubGhzProtocolStatus ret =
subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
uint8_t key_data[sizeof(uint64_t)] = {0};
for(size_t i = 0; i < sizeof(uint64_t); i++) {
key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> (i * 8)) & 0xFF;
}
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
ret = SubGhzProtocolStatusErrorParserOthers;
}
if((ret == SubGhzProtocolStatusOk) &&
!flipper_format_insert_or_update_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Unable to add Data");
ret = SubGhzProtocolStatusErrorParserOthers;
}
return ret;
}
SubGhzProtocolStatus
subghz_protocol_decoder_beninca_arc_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderBenincaARC* instance = context;
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
do {
ret = subghz_block_generic_deserialize_check_count_bit(
&instance->generic,
flipper_format,
subghz_protocol_beninca_arc_const.min_count_bit_for_found);
if(ret != SubGhzProtocolStatusOk) {
break;
}
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
ret = SubGhzProtocolStatusErrorParserOthers;
break;
}
uint8_t key_data[sizeof(uint64_t)] = {0};
if(!flipper_format_read_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Missing Data");
ret = SubGhzProtocolStatusErrorParserOthers;
break;
}
for(uint8_t i = 0; i < sizeof(uint64_t); i++) {
instance->generic.data_2 = instance->generic.data_2 << 8 | key_data[i];
}
} while(false);
return ret;
}
void subghz_protocol_decoder_beninca_arc_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderBenincaARC* instance = context;
uint64_t middle_bytes_dec =
subghz_protocol_beninca_arc_decrypt(&instance->generic, instance->keystore);
// push protocol data to global variable
subghz_block_generic_global.cnt_is_available = true;
subghz_block_generic_global.cnt_length_bit = 32;
subghz_block_generic_global.current_cnt = instance->generic.cnt;
furi_string_printf(
output,
"%s %db\r\n"
"Key1:%08llX\r\n"
"Key2:%08llX\r\n"
"Sn:%08lX Btn:%02X\r\n"
"Mc:%0lX Cnt:%0lX\r\n"
"Fx:%04lX",
instance->base.protocol->name,
instance->generic.data_count_bit,
instance->generic.data,
instance->generic.data_2,
instance->generic.serial,
instance->generic.btn,
(uint32_t)(middle_bytes_dec & 0xFFFFFFFF),
instance->generic.cnt,
instance->generic.seed & 0xFFFF);
}

View File

@@ -0,0 +1,108 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_BENINCA_ARC_NAME "Beninca ARC"
typedef struct SubGhzProtocolDecoderBenincaARC SubGhzProtocolDecoderBenincaARC;
typedef struct SubGhzProtocolEncoderBenincaARC SubGhzProtocolEncoderBenincaARC;
extern const SubGhzProtocolDecoder subghz_protocol_beninca_arc_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_beninca_arc_encoder;
extern const SubGhzProtocol subghz_protocol_beninca_arc;
/**
* Allocate SubGhzProtocolEncoderBenincaARC.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolEncoderBenincaARC* pointer to a SubGhzProtocolEncoderBenincaARC instance
*/
void* subghz_protocol_encoder_beninca_arc_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolEncoderBenincaARC.
* @param context Pointer to a SubGhzProtocolEncoderBenincaARC instance
*/
void subghz_protocol_encoder_beninca_arc_free(void* context);
/**
* Deserialize and generating an upload to send.
* @param context Pointer to a SubGhzProtocolEncoderBenincaARC instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return true On success
*/
SubGhzProtocolStatus
subghz_protocol_encoder_beninca_arc_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Forced transmission stop.
* @param context Pointer to a SubGhzProtocolEncoderBenincaARC instance
*/
void subghz_protocol_encoder_beninca_arc_stop(void* context);
/**
* Getting the level and duration of the upload to be loaded into DMA.
* @param context Pointer to a SubGhzProtocolEncoderBenincaARC instance
* @return LevelDuration
*/
LevelDuration subghz_protocol_encoder_beninca_arc_yield(void* context);
/**
* Allocate SubGhzProtocolDecoderBenincaARC.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolDecoderBenincaARC* pointer to a SubGhzProtocolDecoderBenincaARC instance
*/
void* subghz_protocol_decoder_beninca_arc_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolDecoderBenincaARC.
* @param context Pointer to a SubGhzProtocolDecoderBenincaARC instance
*/
void subghz_protocol_decoder_beninca_arc_free(void* context);
/**
* Reset decoder SubGhzProtocolDecoderBenincaARC.
* @param context Pointer to a SubGhzProtocolDecoderBenincaARC instance
*/
void subghz_protocol_decoder_beninca_arc_reset(void* context);
/**
* Parse a raw sequence of levels and durations received from the air.
* @param context Pointer to a SubGhzProtocolDecoderBenincaARC instance
* @param level Signal level true-high false-low
* @param duration Duration of this level in, us
*/
void subghz_protocol_decoder_beninca_arc_feed(void* context, bool level, uint32_t duration);
/**
* Getting the hash sum of the last randomly received parcel.
* @param context Pointer to a SubGhzProtocolDecoderBenincaARC instance
* @return hash Hash sum
*/
uint32_t subghz_protocol_decoder_beninca_arc_get_hash_data(void* context);
/**
* Serialize data SubGhzProtocolDecoderBenincaARC.
* @param context Pointer to a SubGhzProtocolDecoderBenincaARC instance
* @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return status
*/
SubGhzProtocolStatus subghz_protocol_decoder_beninca_arc_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset);
/**
* Deserialize data SubGhzProtocolDecoderBenincaARC.
* @param context Pointer to a SubGhzProtocolDecoderBenincaARC instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return status
*/
SubGhzProtocolStatus
subghz_protocol_decoder_beninca_arc_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Getting a textual representation of the received data.
* @param context Pointer to a SubGhzProtocolDecoderBenincaARC instance
* @param output Resulting text
*/
void subghz_protocol_decoder_beninca_arc_get_string(void* context, FuriString* output);

View File

@@ -171,7 +171,7 @@ SubGhzProtocolStatus
FURI_LOG_E(TAG, "Deserialize error");
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -311,7 +311,7 @@ SubGhzProtocolStatus
res = SubGhzProtocolStatusErrorParserOthers;
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -183,7 +183,7 @@ SubGhzProtocolStatus
ret = SubGhzProtocolStatusErrorValueBitCount;
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -192,12 +192,17 @@ static void subghz_protocol_encoder_came_atomo_get_upload(
if(came_atomo_counter_mode == 0) {
// Check for OFEX (overflow experimental) mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
}
}
} else {
//OFFEX mode
if((instance->generic.cnt + 0x1) > 0xFFFF) {
instance->generic.cnt = 0;
} else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) {
@@ -371,7 +376,7 @@ SubGhzProtocolStatus
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
@@ -822,6 +827,12 @@ void subghz_protocol_decoder_came_atomo_get_string(void* context, FuriString* ou
uint32_t code_found_hi = instance->generic.data >> 32;
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
// push protocol data to global variable
subghz_block_generic_global.cnt_is_available = true;
subghz_block_generic_global.cnt_length_bit = 16;
subghz_block_generic_global.current_cnt = instance->generic.cnt;
//
furi_string_cat_printf(
output,
"%s %db\r\n"

View File

@@ -256,7 +256,7 @@ SubGhzProtocolStatus
if(res != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -225,7 +225,7 @@ SubGhzProtocolStatus
ret = SubGhzProtocolStatusErrorValueBitCount;
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -170,7 +170,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -209,7 +209,7 @@ SubGhzProtocolStatus
ret = SubGhzProtocolStatusErrorValueBitCount;
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -151,7 +151,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -161,7 +161,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -143,7 +143,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -140,32 +140,37 @@ static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* inst
uint8_t data_prg[8];
data_prg[0] = 0x00;
// faac slh protocol have 20-bit counter so we take only 20 bits from mult (by AND 0xFFFFF)
if(allow_zero_seed || (instance->generic.seed != 0x0)) {
// check OFEX mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
if((instance->generic.cnt +
(furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF)) > 0xFFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt +=
(furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF);
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >
0xFFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
}
}
} else {
// to do OFEX mode
// TODO: OFEX mode
instance->generic.cnt += 1;
}
if(temp_counter_backup != 0x0) {
// check OFEX mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
if((temp_counter_backup +
(furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF)) > 0xFFFFF) {
temp_counter_backup = 0;
} else {
temp_counter_backup +=
(furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF);
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&temp_counter_backup)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((temp_counter_backup + furi_hal_subghz_get_rolling_counter_mult()) >
0xFFFFF) {
temp_counter_backup = 0;
} else {
temp_counter_backup += furi_hal_subghz_get_rolling_counter_mult();
}
}
} else {
// todo OFEX mode
@@ -236,17 +241,19 @@ static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* inst
fixx[i] = (fix >> (shiftby -= 4)) & 0xF;
}
// faac slh protocol have 20-bit counter so we take only 20 bits from mult (by AND 0xFFFFF)
if(allow_zero_seed || (instance->generic.seed != 0x0)) {
// check OFEX mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
if((instance->generic.cnt + (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF)) >
0xFFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFF);
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >
0xFFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
}
}
} else {
// OFEX mode
if(instance->generic.cnt < 0xFFFFF) {
@@ -393,7 +400,7 @@ SubGhzProtocolStatus
subghz_protocol_faac_slh_check_remote_controller(
&instance->generic, instance->keystore, &instance->manufacture_name);
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
@@ -747,6 +754,12 @@ void subghz_protocol_decoder_faac_slh_get_string(void* context, FuriString* outp
instance->generic.btn,
instance->generic.serial);
} else {
// push protocol data to global variable
subghz_block_generic_global.cnt_is_available = true;
subghz_block_generic_global.cnt_length_bit = 20;
subghz_block_generic_global.current_cnt = instance->generic.cnt;
//
furi_string_cat_printf(
output,
"%s %dbit\r\n"

View File

@@ -163,7 +163,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -261,7 +261,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -144,7 +144,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -149,11 +149,14 @@ static void subghz_protocol_encoder_hay21_get_upload(SubGhzProtocolEncoderHay21*
// Counter increment
// Check for OFEX (overflow experimental) mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
//not matter how big and long mult - we take only 4 bits ( AND 0xF) beacose hay21 counter have only 4 bits long (0..F)
if((instance->generic.cnt + (furi_hal_subghz_get_rolling_counter_mult() & 0xF)) > 0xF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += (furi_hal_subghz_get_rolling_counter_mult() & 0xF);
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
}
}
} else {
// OFEX mode
@@ -266,7 +269,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
@@ -462,6 +465,11 @@ void subghz_protocol_decoder_hay21_get_string(void* context, FuriString* output)
// Parse serial, button, counter
subghz_protocol_hay21_remote_controller(&instance->generic);
// push protocol data to global variable
subghz_block_generic_global.cnt_is_available = true;
subghz_block_generic_global.cnt_length_bit = 8;
subghz_block_generic_global.current_cnt = instance->generic.cnt;
furi_string_cat_printf(
output,
"%s - %dbit\r\n"

View File

@@ -257,7 +257,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -157,7 +157,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -172,7 +172,7 @@ SubGhzProtocolStatus
ret = SubGhzProtocolStatusErrorParserTe;
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -213,7 +213,7 @@ SubGhzProtocolStatus
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -160,7 +160,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_honeywell_wdb_deserialize(
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -155,7 +155,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -178,7 +178,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_intertechno_v3_deserialize(
ret = SubGhzProtocolStatusErrorValueBitCount;
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -189,10 +189,15 @@ static bool subghz_protocol_keeloq_gen_data(
if(keeloq_counter_mode == 0) {
// Check for OFEX (overflow experimental) mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >
0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
}
}
} else {
if((instance->generic.cnt + 0x1) > 0xFFFF) {
@@ -301,11 +306,13 @@ static bool subghz_protocol_keeloq_gen_data(
(strcmp(instance->manufacture_name, "Rosh") == 0) ||
(strcmp(instance->manufacture_name, "Rossi") == 0) ||
(strcmp(instance->manufacture_name, "Pecinin") == 0) ||
(strcmp(instance->manufacture_name, "Steelmate") == 0)) {
(strcmp(instance->manufacture_name, "Steelmate") == 0) ||
(strcmp(instance->manufacture_name, "Cardin_S449") == 0)) {
// DTM Neo, Came_Space uses 12bit serial -> simple learning
// FAAC_RC,XT , Mutanco_Mutancode, Genius_Bravo, GSN 12bit serial -> normal learning
// Rosh, Rossi, Pecinin -> 12bit serial - simple learning
// Steelmate -> 12bit serial - normal learning
// Cardin_S449 -> 12bit serial - normal learning
decrypt = btn << 28 | (instance->generic.serial & 0xFFF) << 16 |
instance->generic.cnt;
} else if(
@@ -507,12 +514,23 @@ static bool
(strcmp(instance->manufacture_name, "Monarch") == 0) ||
(strcmp(instance->manufacture_name, "NICE_Smilo") == 0)) {
klq_last_custom_btn = 0xB;
} else if((strcmp(instance->manufacture_name, "Novoferm") == 0)) {
} else if(
(strcmp(instance->manufacture_name, "Novoferm") == 0) ||
(strcmp(instance->manufacture_name, "Stilmatic") == 0)) {
klq_last_custom_btn = 0x9;
} else if((strcmp(instance->manufacture_name, "EcoStar") == 0)) {
} else if(
(strcmp(instance->manufacture_name, "EcoStar") == 0) ||
(strcmp(instance->manufacture_name, "Sommer") == 0)) {
klq_last_custom_btn = 0x6;
} else if((strcmp(instance->manufacture_name, "AN-Motors") == 0)) {
klq_last_custom_btn = 0xC;
} else if((strcmp(instance->manufacture_name, "Cardin_S449") == 0)) {
klq_last_custom_btn = 0xD;
}
uint32_t gap_duration = subghz_protocol_keeloq_const.te_short * 40;
if((strcmp(instance->manufacture_name, "Sommer") == 0)) {
gap_duration = subghz_protocol_keeloq_const.te_short * 29;
}
btn = subghz_protocol_keeloq_get_btn_code(klq_last_custom_btn);
@@ -569,8 +587,7 @@ static bool
// send end
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_short * 40);
instance->encoder.upload[index++] = level_duration_make(false, gap_duration);
return true;
}
@@ -613,6 +630,21 @@ SubGhzProtocolStatus
flipper_format, "Manufacture", instance->manufacture_from_file)) {
instance->manufacture_name = furi_string_get_cstr(instance->manufacture_from_file);
instance->keystore->mfname = instance->manufacture_name;
// Compatibility fixes for old names in user files
if(strcmp(instance->manufacture_name, "Sommer(fsk476)") == 0) {
instance->manufacture_name = "Sommer";
instance->keystore->mfname = instance->manufacture_name;
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
if(!flipper_format_update_string_cstr(
flipper_format, "Manufacture", instance->manufacture_name)) {
FURI_LOG_E(TAG, "DECODER: Unable to fix Sommer manufacture name");
ret = SubGhzProtocolStatusError;
break;
}
}
} else {
FURI_LOG_D(TAG, "ENCODER: Missing Manufacture");
}
@@ -637,7 +669,7 @@ SubGhzProtocolStatus
subghz_protocol_keeloq_check_remote_controller(
&instance->generic, instance->keystore, &instance->manufacture_name);
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
@@ -1264,6 +1296,21 @@ SubGhzProtocolStatus
flipper_format, "Manufacture", instance->manufacture_from_file)) {
instance->manufacture_name = furi_string_get_cstr(instance->manufacture_from_file);
instance->keystore->mfname = instance->manufacture_name;
// Compatibility fixes for old names in user files
if(strcmp(instance->manufacture_name, "Sommer(fsk476)") == 0) {
instance->manufacture_name = "Sommer";
instance->keystore->mfname = instance->manufacture_name;
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
if(!flipper_format_update_string_cstr(
flipper_format, "Manufacture", instance->manufacture_name)) {
FURI_LOG_E(TAG, "DECODER: Unable to fix Sommer manufacture name");
res = SubGhzProtocolStatusError;
break;
}
}
} else {
FURI_LOG_D(TAG, "DECODER: Missing Manufacture");
}
@@ -1325,6 +1372,12 @@ static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code) {
case 0xF:
btn = 0x1;
break;
case 0x9:
btn = 0x2;
break;
case 0x6:
btn = 0x2;
break;
default:
btn = 0x1;
@@ -1350,6 +1403,12 @@ static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code) {
case 0xF:
btn = 0x4;
break;
case 0x9:
btn = 0x4;
break;
case 0x6:
btn = 0x4;
break;
default:
btn = 0x4;
@@ -1375,6 +1434,12 @@ static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code) {
case 0xF:
btn = 0x8;
break;
case 0x9:
btn = 0x6;
break;
case 0x6:
btn = 0x9;
break;
default:
btn = 0x8;
@@ -1400,9 +1465,15 @@ static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code) {
case 0xF:
btn = 0x2;
break;
case 0x9:
btn = last_btn_code;
break;
case 0x6:
btn = last_btn_code;
break;
default:
btn = 0x2;
btn = last_btn_code;
break;
}
}
@@ -1426,6 +1497,9 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output
uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
if(strcmp(instance->manufacture_name, "BFT") == 0) {
subghz_block_generic_global.cnt_is_available = true;
subghz_block_generic_global.cnt_length_bit = 16;
subghz_block_generic_global.current_cnt = instance->generic.cnt;
furi_string_cat_printf(
output,
"%s %dbit\r\n"
@@ -1461,6 +1535,9 @@ void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output
instance->generic.btn,
instance->manufacture_name);
} else {
subghz_block_generic_global.cnt_is_available = true;
subghz_block_generic_global.cnt_length_bit = 16;
subghz_block_generic_global.current_cnt = instance->generic.cnt;
furi_string_cat_printf(
output,
"%s %dbit\r\n"

View File

@@ -25,6 +25,7 @@
#define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_1 6u
#define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_2 7u
#define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_3 8u
// #define BENINCA_ARC_KEY_TYPE 9u -- RESERVED
/**
* Simple Learning Encrypt

View File

@@ -1,276 +0,0 @@
#include "kia.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocoKia"
static const SubGhzBlockConst subghz_protocol_kia_const = {
.te_short = 250,
.te_long = 500,
.te_delta = 100,
.min_count_bit_for_found = 61,
};
struct SubGhzProtocolDecoderKIA {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
uint16_t header_count;
};
struct SubGhzProtocolEncoderKIA {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
KIADecoderStepReset = 0,
KIADecoderStepCheckPreambula,
KIADecoderStepSaveDuration,
KIADecoderStepCheckDuration,
} KIADecoderStep;
const SubGhzProtocolDecoder subghz_protocol_kia_decoder = {
.alloc = subghz_protocol_decoder_kia_alloc,
.free = subghz_protocol_decoder_kia_free,
.feed = subghz_protocol_decoder_kia_feed,
.reset = subghz_protocol_decoder_kia_reset,
.get_hash_data = NULL,
.get_hash_data_long = subghz_protocol_decoder_kia_get_hash_data,
.serialize = subghz_protocol_decoder_kia_serialize,
.deserialize = subghz_protocol_decoder_kia_deserialize,
.get_string = subghz_protocol_decoder_kia_get_string,
.get_string_brief = NULL,
};
const SubGhzProtocolEncoder subghz_protocol_kia_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol subghz_protocol_kia = {
.name = SUBGHZ_PROTOCOL_KIA_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable,
.decoder = &subghz_protocol_kia_decoder,
.encoder = &subghz_protocol_kia_encoder,
.filter = SubGhzProtocolFilter_Cars,
};
void* subghz_protocol_decoder_kia_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolDecoderKIA* instance = malloc(sizeof(SubGhzProtocolDecoderKIA));
instance->base.protocol = &subghz_protocol_kia;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_kia_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderKIA* instance = context;
free(instance);
}
void subghz_protocol_decoder_kia_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderKIA* instance = context;
instance->decoder.parser_step = KIADecoderStepReset;
}
void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderKIA* instance = context;
switch(instance->decoder.parser_step) {
case KIADecoderStepReset:
if((level) && (DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) <
subghz_protocol_kia_const.te_delta)) {
instance->decoder.parser_step = KIADecoderStepCheckPreambula;
instance->decoder.te_last = duration;
instance->header_count = 0;
}
break;
case KIADecoderStepCheckPreambula:
if(level) {
if((DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) <
subghz_protocol_kia_const.te_delta) ||
(DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) <
subghz_protocol_kia_const.te_delta)) {
instance->decoder.te_last = duration;
} else {
instance->decoder.parser_step = KIADecoderStepReset;
}
} else if(
(DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) <
subghz_protocol_kia_const.te_delta) &&
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_short) <
subghz_protocol_kia_const.te_delta)) {
// Found header
instance->header_count++;
break;
} else if(
(DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) <
subghz_protocol_kia_const.te_delta) &&
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_long) <
subghz_protocol_kia_const.te_delta)) {
// Found start bit
if(instance->header_count > 15) {
instance->decoder.parser_step = KIADecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 1;
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
} else {
instance->decoder.parser_step = KIADecoderStepReset;
}
} else {
instance->decoder.parser_step = KIADecoderStepReset;
}
break;
case KIADecoderStepSaveDuration:
if(level) {
if(duration >=
(subghz_protocol_kia_const.te_long + subghz_protocol_kia_const.te_delta * 2UL)) {
//Found stop bit
instance->decoder.parser_step = KIADecoderStepReset;
if(instance->decoder.decode_count_bit ==
subghz_protocol_kia_const.min_count_bit_for_found) {
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
}
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
break;
} else {
instance->decoder.te_last = duration;
instance->decoder.parser_step = KIADecoderStepCheckDuration;
}
} else {
instance->decoder.parser_step = KIADecoderStepReset;
}
break;
case KIADecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_short) <
subghz_protocol_kia_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) <
subghz_protocol_kia_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = KIADecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_long) <
subghz_protocol_kia_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) <
subghz_protocol_kia_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = KIADecoderStepSaveDuration;
} else {
instance->decoder.parser_step = KIADecoderStepReset;
}
} else {
instance->decoder.parser_step = KIADecoderStepReset;
}
break;
}
}
uint8_t subghz_protocol_kia_crc8(uint8_t* data, size_t len) {
uint8_t crc = 0x08;
size_t i, j;
for(i = 0; i < len; i++) {
crc ^= data[i];
for(j = 0; j < 8; j++) {
if((crc & 0x80) != 0)
crc = (uint8_t)((crc << 1) ^ 0x7F);
else
crc <<= 1;
}
}
return crc;
}
/**
* Analysis of received data
* @param instance Pointer to a SubGhzBlockGeneric* instance
*/
static void subghz_protocol_kia_check_remote_controller(SubGhzBlockGeneric* instance) {
/*
* 0x0F 0112 43B04EC 1 7D
* 0x0F 0113 43B04EC 1 DF
* 0x0F 0114 43B04EC 1 30
* 0x0F 0115 43B04EC 2 13
* 0x0F 0116 43B04EC 3 F5
* CNT Serial K CRC8 Kia (CRC8, poly 0x7f, start_crc 0x08)
*/
instance->serial = (uint32_t)((instance->data >> 12) & 0x0FFFFFFF);
instance->btn = (instance->data >> 8) & 0x0F;
instance->cnt = (instance->data >> 40) & 0xFFFF;
}
uint32_t subghz_protocol_decoder_kia_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderKIA* instance = context;
return subghz_protocol_blocks_get_hash_data_long(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
SubGhzProtocolStatus subghz_protocol_decoder_kia_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
SubGhzProtocolDecoderKIA* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
}
SubGhzProtocolStatus
subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderKIA* instance = context;
return subghz_block_generic_deserialize_check_count_bit(
&instance->generic, flipper_format, subghz_protocol_kia_const.min_count_bit_for_found);
}
void subghz_protocol_decoder_kia_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderKIA* instance = context;
subghz_protocol_kia_check_remote_controller(&instance->generic);
uint32_t code_found_hi = instance->generic.data >> 32;
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
// use 'Cntr:' instead of 'Cnt:' to exclude this protocol counter from Counter edit
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"Key:%08lX%08lX\r\n"
"Sn:%07lX Btn:%X\r\n"
"Cntr:%04lX\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
code_found_hi,
code_found_lo,
instance->generic.serial,
instance->generic.btn,
instance->generic.cnt);
}

View File

@@ -1,74 +0,0 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_KIA_NAME "KIA Seed"
typedef struct SubGhzProtocolDecoderKIA SubGhzProtocolDecoderKIA;
typedef struct SubGhzProtocolEncoderKIA SubGhzProtocolEncoderKIA;
extern const SubGhzProtocolDecoder subghz_protocol_kia_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_kia_encoder;
extern const SubGhzProtocol subghz_protocol_kia;
/**
* Allocate SubGhzProtocolDecoderKIA.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolDecoderKIA* pointer to a SubGhzProtocolDecoderKIA instance
*/
void* subghz_protocol_decoder_kia_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolDecoderKIA.
* @param context Pointer to a SubGhzProtocolDecoderKIA instance
*/
void subghz_protocol_decoder_kia_free(void* context);
/**
* Reset decoder SubGhzProtocolDecoderKIA.
* @param context Pointer to a SubGhzProtocolDecoderKIA instance
*/
void subghz_protocol_decoder_kia_reset(void* context);
/**
* Parse a raw sequence of levels and durations received from the air.
* @param context Pointer to a SubGhzProtocolDecoderKIA instance
* @param level Signal level true-high false-low
* @param duration Duration of this level in, us
*/
void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t duration);
/**
* Getting the hash sum of the last randomly received parcel.
* @param context Pointer to a SubGhzProtocolDecoderKIA instance
* @return hash Hash sum
*/
uint32_t subghz_protocol_decoder_kia_get_hash_data(void* context);
/**
* Serialize data SubGhzProtocolDecoderKIA.
* @param context Pointer to a SubGhzProtocolDecoderKIA instance
* @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return status
*/
SubGhzProtocolStatus subghz_protocol_decoder_kia_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset);
/**
* Deserialize data SubGhzProtocolDecoderKIA.
* @param context Pointer to a SubGhzProtocolDecoderKIA instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return status
*/
SubGhzProtocolStatus
subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Getting a textual representation of the received data.
* @param context Pointer to a SubGhzProtocolDecoderKIA instance
* @param output Resulting text
*/
void subghz_protocol_decoder_kia_get_string(void* context, FuriString* output);

View File

@@ -8,6 +8,8 @@
#include "../blocks/generic.h"
#include "../blocks/math.h"
#include "../blocks/custom_btn_i.h"
#define TAG "SubGhzProtocoKingGatesStylo4k"
static const SubGhzBlockConst subghz_protocol_kinggates_stylo_4k_const = {
@@ -86,6 +88,13 @@ static void subghz_protocol_kinggates_stylo_4k_remote_controller(
SubGhzBlockGeneric* instance,
SubGhzKeystore* keystore);
/**
* Defines the button value for the current btn_id
* Basic set | 0xE | 0xD | 0xB | 0x7 |
* @return Button code
*/
static uint8_t subghz_protocol_kinggates_stylo_4k_get_btn_code(void);
void* subghz_protocol_encoder_kinggates_stylo_4k_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolEncoderKingGates_stylo_4k* instance =
malloc(sizeof(SubGhzProtocolEncoderKingGates_stylo_4k));
@@ -140,29 +149,23 @@ LevelDuration subghz_protocol_encoder_kinggates_stylo_4k_yield(void* context) {
static bool subghz_protocol_kinggates_stylo_4k_gen_data(
SubGhzProtocolEncoderKingGates_stylo_4k* instance,
uint8_t btn) {
UNUSED(btn);
uint32_t hop = subghz_protocol_blocks_reverse_key(instance->generic.data_2 >> 4, 32);
uint64_t fix = subghz_protocol_blocks_reverse_key(instance->generic.data, 53);
int res = 0;
uint32_t decrypt = 0;
// Save original button for later use
if(subghz_custom_btn_get_original() == 0) {
subghz_custom_btn_set_original(btn);
}
for
M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
res = strcmp(furi_string_get_cstr(manufacture_code->name), "Kingates_Stylo4k");
if(res == 0) {
//Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
break;
}
}
instance->generic.cnt = decrypt & 0xFFFF;
btn = subghz_protocol_kinggates_stylo_4k_get_btn_code();
// Check for OFEX (overflow experimental) mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
}
}
} else {
if((instance->generic.cnt + 0x1) > 0xFFFF) {
@@ -174,18 +177,21 @@ static bool subghz_protocol_kinggates_stylo_4k_gen_data(
}
}
instance->generic.btn = (fix >> 17) & 0x0F;
instance->generic.serial = ((fix >> 5) & 0xFFFF0000) | (fix & 0xFFFF);
// hop is encrypted part
uint32_t hop = (uint64_t)btn << 28 | (((uint32_t)0x0C) << 24) |
((instance->generic.serial & 0xFF) << 16) | (instance->generic.cnt & 0xFFFF);
uint32_t data = (decrypt & 0xFFFF0000) | instance->generic.cnt;
uint64_t fix = ((uint64_t)((instance->generic.serial >> 16) & 0xFFFF) << 21) |
(uint64_t)btn << 17 | 0b1 << 16 | (instance->generic.serial & 0xFFFF);
instance->generic.data = subghz_protocol_blocks_reverse_key(fix, 53);
uint64_t encrypt = 0;
for
M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
res = strcmp(furi_string_get_cstr(manufacture_code->name), "Kingates_Stylo4k");
if(res == 0) {
//Simple Learning
encrypt = subghz_protocol_keeloq_common_encrypt(data, manufacture_code->key);
if(strcmp(furi_string_get_cstr(manufacture_code->name), "Kingates_Stylo4k") == 0) {
// Simple Learning
encrypt = subghz_protocol_keeloq_common_encrypt(hop, manufacture_code->key);
encrypt = subghz_protocol_blocks_reverse_key(encrypt, 32);
instance->generic.data_2 = encrypt << 4;
return true;
@@ -195,6 +201,63 @@ static bool subghz_protocol_kinggates_stylo_4k_gen_data(
return false;
}
bool subghz_protocol_kinggates_stylo_4k_create_data(
void* context,
FlipperFormat* flipper_format,
uint32_t serial,
uint8_t btn,
uint16_t cnt,
SubGhzRadioPreset* preset) {
furi_assert(context);
SubGhzProtocolEncoderKingGates_stylo_4k* instance = context;
instance->generic.serial = serial;
instance->generic.cnt = cnt;
instance->generic.btn = btn;
instance->generic.data_count_bit = 89;
uint32_t decrypt = instance->generic.btn << 28 | (((uint32_t)0x0C) << 24) |
((instance->generic.serial & 0xFF) << 16) |
(instance->generic.cnt & 0xFFFF);
uint64_t encrypt = 0;
for
M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
if(strcmp(furi_string_get_cstr(manufacture_code->name), "Kingates_Stylo4k") == 0) {
// Simple Learning
encrypt = subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
encrypt = subghz_protocol_blocks_reverse_key(encrypt, 32);
instance->generic.data_2 = encrypt << 4;
break;
}
}
uint64_t fix = ((uint64_t)((instance->generic.serial >> 16) & 0xFFFF) << 21) |
instance->generic.btn << 17 | 0b1 << 16 | (instance->generic.serial & 0xFFFF);
instance->generic.data = subghz_protocol_blocks_reverse_key(fix, 53);
SubGhzProtocolStatus res =
subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
uint8_t key_data[sizeof(uint64_t)] = {0};
for(size_t i = 0; i < sizeof(uint64_t); i++) {
key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> (i * 8)) & 0xFF;
}
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
res = SubGhzProtocolStatusErrorParserOthers;
}
if((res == SubGhzProtocolStatusOk) &&
!flipper_format_insert_or_update_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Unable to add Data2");
res = SubGhzProtocolStatusErrorParserOthers;
}
return res == SubGhzProtocolStatusOk;
}
/**
* Generating an upload from data.
* @param instance Pointer to a SubGhzProtocolEncoderKingGates_stylo_4k instance
@@ -283,10 +346,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_kinggates_stylo_4k_deserialize(
break;
}
subghz_protocol_kinggates_stylo_4k_remote_controller(
&instance->generic, instance->keystore);
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
@@ -305,6 +365,9 @@ SubGhzProtocolStatus subghz_protocol_encoder_kinggates_stylo_4k_deserialize(
instance->generic.data_2 = instance->generic.data_2 << 8 | key_data[i];
}
subghz_protocol_kinggates_stylo_4k_remote_controller(
&instance->generic, instance->keystore);
subghz_protocol_encoder_kinggates_stylo_4k_get_upload(instance, instance->generic.btn);
if(!flipper_format_rewind(flipper_format)) {
@@ -312,6 +375,14 @@ SubGhzProtocolStatus subghz_protocol_encoder_kinggates_stylo_4k_deserialize(
break;
}
for(size_t i = 0; i < sizeof(uint64_t); i++) {
key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF;
}
if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Unable to update Key");
break;
}
for(size_t i = 0; i < sizeof(uint64_t); i++) {
key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> i * 8) & 0xFF;
}
@@ -503,6 +574,11 @@ static void subghz_protocol_kinggates_stylo_4k_remote_controller(
}
if(ret) {
instance->cnt = decrypt & 0xFFFF;
// Save original button for later use
if(subghz_custom_btn_get_original() == 0) {
subghz_custom_btn_set_original(instance->btn);
}
subghz_custom_btn_set_max(3);
} else {
instance->btn = 0;
instance->serial = 0;
@@ -577,11 +653,84 @@ SubGhzProtocolStatus subghz_protocol_decoder_kinggates_stylo_4k_deserialize(
return ret;
}
static uint8_t subghz_protocol_kinggates_stylo_4k_get_btn_code(void) {
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_code = subghz_custom_btn_get_original();
uint8_t btn = original_btn_code;
// Set custom button
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) {
// Restore original button code
btn = original_btn_code;
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) {
switch(original_btn_code) {
case 0xE:
btn = 0xD;
break;
case 0xD:
btn = 0xE;
break;
case 0xB:
btn = 0xE;
break;
case 0x7:
btn = 0xE;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
switch(original_btn_code) {
case 0xE:
btn = 0xB;
break;
case 0xD:
btn = 0xB;
break;
case 0xB:
btn = 0xD;
break;
case 0x7:
btn = 0xD;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) {
switch(original_btn_code) {
case 0xE:
btn = 0x7;
break;
case 0xD:
btn = 0x7;
break;
case 0xB:
btn = 0x7;
break;
case 0x7:
btn = 0xB;
break;
default:
break;
}
}
return btn;
}
void subghz_protocol_decoder_kinggates_stylo_4k_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderKingGates_stylo_4k* instance = context;
subghz_protocol_kinggates_stylo_4k_remote_controller(&instance->generic, instance->keystore);
// push protocol data to global variable
subghz_block_generic_global.cnt_is_available = true;
subghz_block_generic_global.cnt_length_bit = 16;
subghz_block_generic_global.current_cnt = instance->generic.cnt;
furi_string_cat_printf(
output,
"%s\r\n"

View File

@@ -162,7 +162,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -166,7 +166,7 @@ SubGhzProtocolStatus subghz_protocol_encoder_linear_delta3_deserialize(
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -167,7 +167,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -215,7 +215,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -161,7 +161,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -170,7 +170,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -190,7 +190,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -182,7 +182,7 @@ SubGhzProtocolStatus
break;
}
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -163,7 +163,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -149,7 +149,7 @@ SubGhzProtocolStatus
ret = SubGhzProtocolStatusErrorValueBitCount;
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -16,8 +16,10 @@
#define TAG "SubGhzProtocolNiceFlorS"
#define NICE_ONE_COUNT_BIT 72
#define NICE_ONE_NAME "Nice One"
#define NICE_ONE_COUNT_BIT 72
#define NICE_ONE_NAME "Nice One"
#define SUBGHZ_NICE_FLOR_S_RAINBOW_TABLE_SIZE_BYTES 32
#define SUBGHZ_NO_NICE_FLOR_S_RAINBOW_TABLE 0
static const SubGhzBlockConst subghz_protocol_nice_flor_s_const = {
.te_short = 500,
@@ -33,7 +35,6 @@ struct SubGhzProtocolDecoderNiceFlorS {
SubGhzBlockGeneric generic;
const char* nice_flor_s_rainbow_table_file_name;
uint64_t data;
};
struct SubGhzProtocolEncoderNiceFlorS {
@@ -159,10 +160,14 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload(
if(nice_flors_counter_mode == 0) {
// Check for OFEX (overflow experimental) mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
}
}
} else {
if((instance->generic.cnt + 0x1) > 0xFFFF) {
@@ -278,7 +283,7 @@ SubGhzProtocolStatus
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
// flipper_format_read_uint32(
@@ -414,21 +419,13 @@ static void subghz_protocol_nice_one_get_data(uint8_t* p, uint8_t num_parcel, ui
}
/**
* Read bytes from rainbow table
* @param file_name Full path to rainbow table the file
* Read bytes from buffer array with rainbow table
* @param buffer pointer to decrypted rainbow table
* @param address Byte address in file
* @return data
*/
static uint8_t
subghz_protocol_nice_flor_s_get_byte_in_file(const char* file_name, uint32_t address) {
if(!file_name) return 0;
uint8_t buffer[1] = {0};
if(subghz_keystore_raw_get_data(file_name, address, buffer, sizeof(uint8_t))) {
return buffer[0];
} else {
return 0;
}
static uint8_t subghz_protocol_nice_flor_s_get_byte_from_buffer(uint8_t* buffer, uint8_t address) {
return buffer[address];
}
static inline void subghz_protocol_decoder_nice_flor_s_magic_xor(uint8_t* p, uint8_t k) {
@@ -438,16 +435,28 @@ static inline void subghz_protocol_decoder_nice_flor_s_magic_xor(uint8_t* p, uin
}
uint64_t subghz_protocol_nice_flor_s_encrypt(uint64_t data, const char* file_name) {
// load and decrypt rainbow table from file to buffer array in RAM
if(!file_name) return SUBGHZ_NO_NICE_FLOR_S_RAINBOW_TABLE;
uint8_t buffer[SUBGHZ_NICE_FLOR_S_RAINBOW_TABLE_SIZE_BYTES] = {0};
uint8_t* buffer_ptr = (uint8_t*)&buffer;
if(subghz_keystore_raw_get_data(
file_name, 0, buffer, SUBGHZ_NICE_FLOR_S_RAINBOW_TABLE_SIZE_BYTES)) {
} else {
return SUBGHZ_NO_NICE_FLOR_S_RAINBOW_TABLE;
}
uint8_t* p = (uint8_t*)&data;
uint8_t k = 0;
for(uint8_t y = 0; y < 2; y++) {
k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] & 0x1f);
k = subghz_protocol_nice_flor_s_get_byte_from_buffer(buffer_ptr, p[0] & 0x1f);
subghz_protocol_decoder_nice_flor_s_magic_xor(p, k);
p[5] &= 0x0f;
p[0] ^= k & 0xe0;
k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] >> 3) + 0x25;
k = subghz_protocol_nice_flor_s_get_byte_from_buffer(buffer_ptr, p[0] >> 3) + 0x25;
subghz_protocol_decoder_nice_flor_s_magic_xor(p, k);
p[5] &= 0x0f;
@@ -475,6 +484,19 @@ static uint64_t
subghz_protocol_nice_flor_s_decrypt(SubGhzBlockGeneric* instance, const char* file_name) {
furi_assert(instance);
uint64_t data = instance->data;
// load and decrypt rainbow table from file to buffer array in RAM
if(!file_name) return SUBGHZ_NO_NICE_FLOR_S_RAINBOW_TABLE;
uint8_t buffer[SUBGHZ_NICE_FLOR_S_RAINBOW_TABLE_SIZE_BYTES] = {0};
uint8_t* buffer_ptr = (uint8_t*)&buffer;
if(subghz_keystore_raw_get_data(
file_name, 0, buffer, SUBGHZ_NICE_FLOR_S_RAINBOW_TABLE_SIZE_BYTES)) {
} else {
return SUBGHZ_NO_NICE_FLOR_S_RAINBOW_TABLE;
}
uint8_t* p = (uint8_t*)&data;
uint8_t k = 0;
@@ -489,12 +511,12 @@ static uint64_t
p[1] = k;
for(uint8_t y = 0; y < 2; y++) {
k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] >> 3) + 0x25;
k = subghz_protocol_nice_flor_s_get_byte_from_buffer(buffer_ptr, p[0] >> 3) + 0x25;
subghz_protocol_decoder_nice_flor_s_magic_xor(p, k);
p[5] &= 0x0f;
p[0] ^= k & 0x7;
k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] & 0x1f);
k = subghz_protocol_nice_flor_s_get_byte_from_buffer(buffer_ptr, p[0] & 0x1f);
subghz_protocol_decoder_nice_flor_s_magic_xor(p, k);
p[5] &= 0x0f;
@@ -619,8 +641,8 @@ void subghz_protocol_decoder_nice_flor_s_feed(void* context, bool level, uint32_
if((instance->decoder.decode_count_bit ==
subghz_protocol_nice_flor_s_const.min_count_bit_for_found) ||
(instance->decoder.decode_count_bit == NICE_ONE_COUNT_BIT)) {
instance->generic.data = instance->data;
instance->data = instance->decoder.decode_data;
instance->generic.data = instance->generic.data_2;
instance->generic.data_2 = instance->decoder.decode_data;
instance->decoder.decode_data = instance->generic.data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
@@ -659,7 +681,7 @@ void subghz_protocol_decoder_nice_flor_s_feed(void* context, bool level, uint32_
}
if(instance->decoder.decode_count_bit ==
subghz_protocol_nice_flor_s_const.min_count_bit_for_found) {
instance->data = instance->decoder.decode_data;
instance->generic.data_2 = instance->decoder.decode_data;
instance->decoder.decode_data = 0;
}
break;
@@ -755,7 +777,7 @@ SubGhzProtocolStatus subghz_protocol_decoder_nice_flor_s_serialize(
}
if((ret == SubGhzProtocolStatusOk) &&
!flipper_format_insert_or_update_uint32(
flipper_format, "Data", (uint32_t*)&instance->data, 1)) {
flipper_format, "Data", (uint32_t*)&instance->generic.data_2, 1)) {
FURI_LOG_E(TAG, "Unable to add Data");
ret = SubGhzProtocolStatusErrorParserOthers;
}
@@ -792,7 +814,7 @@ SubGhzProtocolStatus
ret = SubGhzProtocolStatusErrorParserOthers;
break;
}
instance->data = (uint64_t)temp;
instance->generic.data_2 = (uint64_t)temp;
}
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
@@ -914,6 +936,11 @@ void subghz_protocol_decoder_nice_flor_s_get_string(void* context, FuriString* o
subghz_protocol_nice_flor_s_remote_controller(
&instance->generic, instance->nice_flor_s_rainbow_table_file_name);
// push protocol data to global variable
subghz_block_generic_global.cnt_is_available = true;
subghz_block_generic_global.cnt_length_bit = 16;
subghz_block_generic_global.current_cnt = instance->generic.cnt;
if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) {
furi_string_cat_printf(
output,
@@ -924,7 +951,7 @@ void subghz_protocol_decoder_nice_flor_s_get_string(void* context, FuriString* o
NICE_ONE_NAME,
instance->generic.data_count_bit,
instance->generic.data,
instance->data,
instance->generic.data_2,
instance->generic.serial,
instance->generic.cnt,
instance->generic.btn);

View File

@@ -256,10 +256,14 @@ static bool
// Reconstruction of the data
// Check for OFEX (overflow experimental) mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
}
}
} else {
if((instance->generic.cnt + 0x1) > 0xFFFF) {
@@ -320,7 +324,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
@@ -590,6 +594,12 @@ void subghz_protocol_decoder_phoenix_v2_get_string(void* context, FuriString* ou
furi_assert(context);
SubGhzProtocolDecoderPhoenix_V2* instance = context;
subghz_protocol_phoenix_v2_check_remote_controller(&instance->generic);
// push protocol data to global variable
subghz_block_generic_global.cnt_is_available = true;
subghz_block_generic_global.cnt_length_bit = 16;
subghz_block_generic_global.current_cnt = instance->generic.cnt;
furi_string_cat_printf(
output,
"V2 Phoenix %dbit\r\n"

View File

@@ -208,7 +208,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -358,7 +358,7 @@ SubGhzProtocolStatus
ret = SubGhzProtocolStatusErrorParserTe;
break;
}
//optional parameter parameter
// Optional value
if(!flipper_format_read_uint32(
flipper_format, "Guard_time", (uint32_t*)&instance->guard_time, 1)) {
instance->guard_time = PRINCETON_GUARD_TIME_DEFALUT;

View File

@@ -3,7 +3,6 @@
const SubGhzProtocol* const subghz_protocol_registry_items[] = {
&subghz_protocol_gate_tx,
&subghz_protocol_keeloq,
&subghz_protocol_star_line,
&subghz_protocol_nice_flo,
&subghz_protocol_came,
&subghz_protocol_faac_slh,
@@ -12,12 +11,10 @@ const SubGhzProtocol* const subghz_protocol_registry_items[] = {
&subghz_protocol_came_atomo,
&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_linear,
@@ -84,6 +81,8 @@ const SubGhzProtocol* const subghz_protocol_registry_items[] = {
&subghz_protocol_feron,
&subghz_protocol_roger,
&subghz_protocol_elplast,
&subghz_protocol_treadmill37,
&subghz_protocol_beninca_arc,
};
const SubGhzProtocolRegistry subghz_protocol_registry = {

View File

@@ -4,7 +4,6 @@
#include "princeton.h"
#include "keeloq.h"
#include "star_line.h"
#include "nice_flo.h"
#include "came.h"
#include "faac_slh.h"
@@ -13,12 +12,10 @@
#include "came_atomo.h"
#include "nero_sketch.h"
#include "ido.h"
#include "kia.h"
#include "hormann.h"
#include "nero_radio.h"
#include "somfy_telis.h"
#include "somfy_keytis.h"
#include "scher_khan.h"
#include "gate_tx.h"
#include "raw.h"
#include "linear.h"
@@ -85,3 +82,5 @@
#include "feron.h"
#include "roger.h"
#include "elplast.h"
#include "treadmill37.h"
#include "beninca_arc.h"

View File

@@ -159,26 +159,6 @@ bool subghz_protocol_nice_flor_s_create_data(
SubGhzRadioPreset* preset,
bool nice_one);
/**
* Key generation from simple data.
* @param context Pointer to a SubGhzProtocolEncoderStarLine instance
* @param flipper_format Pointer to a FlipperFormat instance
* @param serial Serial number, 24 bit
* @param btn Button number, 8 bit
* @param cnt Counter value, 16 bit
* @param manufacture_name Name of manufacturer's key
* @param preset Modulation, SubGhzRadioPreset
* @return true On success
*/
bool subghz_protocol_star_line_create_data(
void* context,
FlipperFormat* flipper_format,
uint32_t serial,
uint8_t btn,
uint16_t cnt,
const char* manufacture_name,
SubGhzRadioPreset* preset);
/**
* Key generation from simple data.
* @param context Pointer to a SubGhzProtocolEncoderSomfyTelis instance
@@ -215,6 +195,42 @@ bool subghz_protocol_somfy_keytis_create_data(
uint16_t cnt,
SubGhzRadioPreset* preset);
/**
* Key generation from simple data.
* @param context Pointer to a SubGhzProtocolEncoderKingGates_stylo_4k instance
* @param flipper_format Pointer to a FlipperFormat instance
* @param serial Serial number, 24 bit
* @param btn Button number, 8 bit
* @param cnt Counter value, 16 bit
* @param preset Modulation, SubGhzRadioPreset
* @return true On success
*/
bool subghz_protocol_kinggates_stylo_4k_create_data(
void* context,
FlipperFormat* flipper_format,
uint32_t serial,
uint8_t btn,
uint16_t cnt,
SubGhzRadioPreset* preset);
/**
* Key generation from simple data.
* @param context Pointer to a SubGhzProtocolEncoderBenincaARC instance
* @param flipper_format Pointer to a FlipperFormat instance
* @param serial Serial number, 32 bit
* @param btn Button number, 8 bit
* @param cnt Counter value, 32 bit
* @param preset Modulation, SubGhzRadioPreset
* @return true On success
*/
bool subghz_protocol_beninca_arc_create_data(
void* context,
FlipperFormat* flipper_format,
uint32_t serial,
uint8_t btn,
uint32_t cnt,
SubGhzRadioPreset* preset);
typedef struct SubGhzProtocolDecoderBinRAW SubGhzProtocolDecoderBinRAW;
void subghz_protocol_decoder_bin_raw_data_input_rssi(

View File

@@ -68,6 +68,8 @@ const SubGhzProtocol subghz_protocol_revers_rb2 = {
.decoder = &subghz_protocol_revers_rb2_decoder,
.encoder = &subghz_protocol_revers_rb2_encoder,
.filter = SubGhzProtocolFilter_ReversRB2,
};
void* subghz_protocol_encoder_revers_rb2_alloc(SubGhzEnvironment* environment) {
@@ -178,7 +180,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -265,7 +265,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -1,320 +0,0 @@
#include "scher_khan.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
//https://phreakerclub.com/72
//https://phreakerclub.com/forum/showthread.php?t=7&page=2
//https://phreakerclub.com/forum/showthread.php?t=274&highlight=magicar
//!!! https://phreakerclub.com/forum/showthread.php?t=489&highlight=magicar&page=5
#define TAG "SubGhzProtocolScherKhan"
static const SubGhzBlockConst subghz_protocol_scher_khan_const = {
.te_short = 750,
.te_long = 1100,
.te_delta = 150,
.min_count_bit_for_found = 35,
};
struct SubGhzProtocolDecoderScherKhan {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
uint16_t header_count;
const char* protocol_name;
};
struct SubGhzProtocolEncoderScherKhan {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
ScherKhanDecoderStepReset = 0,
ScherKhanDecoderStepCheckPreambula,
ScherKhanDecoderStepSaveDuration,
ScherKhanDecoderStepCheckDuration,
} ScherKhanDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_scher_khan_decoder = {
.alloc = subghz_protocol_decoder_scher_khan_alloc,
.free = subghz_protocol_decoder_scher_khan_free,
.feed = subghz_protocol_decoder_scher_khan_feed,
.reset = subghz_protocol_decoder_scher_khan_reset,
.get_hash_data = NULL,
.get_hash_data_long = subghz_protocol_decoder_scher_khan_get_hash_data,
.serialize = subghz_protocol_decoder_scher_khan_serialize,
.deserialize = subghz_protocol_decoder_scher_khan_deserialize,
.get_string = subghz_protocol_decoder_scher_khan_get_string,
.get_string_brief = NULL,
};
const SubGhzProtocolEncoder subghz_protocol_scher_khan_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol subghz_protocol_scher_khan = {
.name = SUBGHZ_PROTOCOL_SCHER_KHAN_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Save,
.decoder = &subghz_protocol_scher_khan_decoder,
.encoder = &subghz_protocol_scher_khan_encoder,
.filter = SubGhzProtocolFilter_Cars,
};
void* subghz_protocol_decoder_scher_khan_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolDecoderScherKhan* instance = malloc(sizeof(SubGhzProtocolDecoderScherKhan));
instance->base.protocol = &subghz_protocol_scher_khan;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_scher_khan_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderScherKhan* instance = context;
free(instance);
}
void subghz_protocol_decoder_scher_khan_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderScherKhan* instance = context;
instance->decoder.parser_step = ScherKhanDecoderStepReset;
}
void subghz_protocol_decoder_scher_khan_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderScherKhan* instance = context;
switch(instance->decoder.parser_step) {
case ScherKhanDecoderStepReset:
if((level) && (DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short * 2) <
subghz_protocol_scher_khan_const.te_delta)) {
instance->decoder.parser_step = ScherKhanDecoderStepCheckPreambula;
instance->decoder.te_last = duration;
instance->header_count = 0;
}
break;
case ScherKhanDecoderStepCheckPreambula:
if(level) {
if((DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short * 2) <
subghz_protocol_scher_khan_const.te_delta) ||
(DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short) <
subghz_protocol_scher_khan_const.te_delta)) {
instance->decoder.te_last = duration;
} else {
instance->decoder.parser_step = ScherKhanDecoderStepReset;
}
} else if(
(DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short * 2) <
subghz_protocol_scher_khan_const.te_delta) ||
(DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short) <
subghz_protocol_scher_khan_const.te_delta)) {
if(DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_scher_khan_const.te_short * 2) <
subghz_protocol_scher_khan_const.te_delta) {
// Found header
instance->header_count++;
break;
} else if(
DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_scher_khan_const.te_short) <
subghz_protocol_scher_khan_const.te_delta) {
// Found start bit
if(instance->header_count >= 2) {
instance->decoder.parser_step = ScherKhanDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 1;
} else {
instance->decoder.parser_step = ScherKhanDecoderStepReset;
}
} else {
instance->decoder.parser_step = ScherKhanDecoderStepReset;
}
} else {
instance->decoder.parser_step = ScherKhanDecoderStepReset;
}
break;
case ScherKhanDecoderStepSaveDuration:
if(level) {
if(duration >= (subghz_protocol_scher_khan_const.te_delta * 2UL +
subghz_protocol_scher_khan_const.te_long)) {
//Found stop bit
instance->decoder.parser_step = ScherKhanDecoderStepReset;
if(instance->decoder.decode_count_bit >=
subghz_protocol_scher_khan_const.min_count_bit_for_found) {
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
}
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
break;
} else {
instance->decoder.te_last = duration;
instance->decoder.parser_step = ScherKhanDecoderStepCheckDuration;
}
} else {
instance->decoder.parser_step = ScherKhanDecoderStepReset;
}
break;
case ScherKhanDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_scher_khan_const.te_short) <
subghz_protocol_scher_khan_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_short) <
subghz_protocol_scher_khan_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = ScherKhanDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_scher_khan_const.te_long) <
subghz_protocol_scher_khan_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_scher_khan_const.te_long) <
subghz_protocol_scher_khan_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = ScherKhanDecoderStepSaveDuration;
} else {
instance->decoder.parser_step = ScherKhanDecoderStepReset;
}
} else {
instance->decoder.parser_step = ScherKhanDecoderStepReset;
}
break;
}
}
/**
* Analysis of received data
* @param instance Pointer to a SubGhzBlockGeneric* instance
* @param protocol_name
*/
static void subghz_protocol_scher_khan_check_remote_controller(
SubGhzBlockGeneric* instance,
const char** protocol_name) {
/*
* MAGICAR 51 bit 00000001A99121DE83C3 MAGIC CODE, Dynamic
* 0E8C1619E830C -> 000011101000110000010110 0001 1001 1110 1000001100001100
* 0E8C1629D830D -> 000011101000110000010110 0010 1001 1101 1000001100001101
* 0E8C1649B830E -> 000011101000110000010110 0100 1001 1011 1000001100001110
* 0E8C16897830F -> 000011101000110000010110 1000 1001 0111 1000001100001111
* Serial Key Ser ~Key CNT
*/
switch(instance->data_count_bit) {
case 35: //MAGIC CODE, Static
*protocol_name = "MAGIC CODE, Static";
instance->serial = 0;
instance->btn = 0;
instance->cnt = 0;
break;
case 51: //MAGIC CODE, Dynamic
*protocol_name = "MAGIC CODE, Dynamic";
instance->serial = ((instance->data >> 24) & 0xFFFFFF0) | ((instance->data >> 20) & 0x0F);
instance->btn = (instance->data >> 24) & 0x0F;
instance->cnt = instance->data & 0xFFFF;
break;
case 57: //MAGIC CODE PRO / PRO2
*protocol_name = "MAGIC CODE PRO/PRO2";
instance->serial = 0;
instance->btn = 0;
instance->cnt = 0;
break;
case 63: //MAGIC CODE, Dynamic Response
*protocol_name = "MAGIC CODE, Response";
instance->serial = 0;
instance->btn = 0;
instance->cnt = 0;
break;
case 64: //MAGICAR, Response ???
*protocol_name = "MAGICAR, Response";
instance->serial = 0;
instance->btn = 0;
instance->cnt = 0;
break;
case 81: // MAGIC CODE PRO / PRO2 Response ???
case 82: // MAGIC CODE PRO / PRO2 Response ???
*protocol_name = "MAGIC CODE PRO,\n Response";
instance->serial = 0;
instance->btn = 0;
instance->cnt = 0;
break;
default:
*protocol_name = "Unknown";
instance->serial = 0;
instance->btn = 0;
instance->cnt = 0;
break;
}
}
uint32_t subghz_protocol_decoder_scher_khan_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderScherKhan* instance = context;
return subghz_protocol_blocks_get_hash_data_long(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
SubGhzProtocolStatus subghz_protocol_decoder_scher_khan_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
SubGhzProtocolDecoderScherKhan* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
}
SubGhzProtocolStatus
subghz_protocol_decoder_scher_khan_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderScherKhan* instance = context;
return subghz_block_generic_deserialize(&instance->generic, flipper_format);
}
void subghz_protocol_decoder_scher_khan_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderScherKhan* instance = context;
subghz_protocol_scher_khan_check_remote_controller(
&instance->generic, &instance->protocol_name);
// use 'Cntr:' instead of 'Cnt:' to exclude this protocol counter from Counter edit
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:%07lX Btn:%X\r\n"
"Cntr:%04lX\r\n"
"Pt: %s\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 32),
(uint32_t)instance->generic.data,
instance->generic.serial,
instance->generic.btn,
instance->generic.cnt,
instance->protocol_name);
}

View File

@@ -1,74 +0,0 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_SCHER_KHAN_NAME "Scher-Khan"
typedef struct SubGhzProtocolDecoderScherKhan SubGhzProtocolDecoderScherKhan;
typedef struct SubGhzProtocolEncoderScherKhan SubGhzProtocolEncoderScherKhan;
extern const SubGhzProtocolDecoder subghz_protocol_scher_khan_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_scher_khan_encoder;
extern const SubGhzProtocol subghz_protocol_scher_khan;
/**
* Allocate SubGhzProtocolDecoderScherKhan.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolDecoderScherKhan* pointer to a SubGhzProtocolDecoderScherKhan instance
*/
void* subghz_protocol_decoder_scher_khan_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolDecoderScherKhan.
* @param context Pointer to a SubGhzProtocolDecoderScherKhan instance
*/
void subghz_protocol_decoder_scher_khan_free(void* context);
/**
* Reset decoder SubGhzProtocolDecoderScherKhan.
* @param context Pointer to a SubGhzProtocolDecoderScherKhan instance
*/
void subghz_protocol_decoder_scher_khan_reset(void* context);
/**
* Parse a raw sequence of levels and durations received from the air.
* @param context Pointer to a SubGhzProtocolDecoderScherKhan instance
* @param level Signal level true-high false-low
* @param duration Duration of this level in, us
*/
void subghz_protocol_decoder_scher_khan_feed(void* context, bool level, uint32_t duration);
/**
* Getting the hash sum of the last randomly received parcel.
* @param context Pointer to a SubGhzProtocolDecoderScherKhan instance
* @return hash Hash sum
*/
uint32_t subghz_protocol_decoder_scher_khan_get_hash_data(void* context);
/**
* Serialize data SubGhzProtocolDecoderScherKhan.
* @param context Pointer to a SubGhzProtocolDecoderScherKhan instance
* @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return status
*/
SubGhzProtocolStatus subghz_protocol_decoder_scher_khan_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset);
/**
* Deserialize data SubGhzProtocolDecoderScherKhan.
* @param context Pointer to a SubGhzProtocolDecoderScherKhan instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return status
*/
SubGhzProtocolStatus
subghz_protocol_decoder_scher_khan_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Getting a textual representation of the received data.
* @param context Pointer to a SubGhzProtocolDecoderScherKhan instance
* @param output Resulting text
*/
void subghz_protocol_decoder_scher_khan_get_string(void* context, FuriString* output);

View File

@@ -222,43 +222,19 @@ static bool subghz_protocol_secplus_v1_encode(SubGhzProtocolEncoderSecPlus_v1* i
//increment the counter
//rolling += 2; - old way
// Experemental case - we dont know counter size exactly, so just will be think that it is in range of 0xE6000000 - 0xFFFFFFFF
// one case when we have mult = 0xFFFFFFFF - its when we reset counter before applying new cnt value
// so at first step we reset cnt to 0 and now we sure here will be second step (set new cnt value);
// at second step check what user set for new Cnt (and correct it if cnt less than 0xE6000000 or more than 0xFFFFFFFF)
int32_t multicntr = (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFFFF);
// Adjust for negative multiplier
if(furi_hal_subghz_get_rolling_counter_mult() < 0) {
multicntr = furi_hal_subghz_get_rolling_counter_mult();
}
if(multicntr == 1) {
multicntr = 2; // to keep old behaviour when mult = 1
}
// Check for OFEX (overflow experimental) mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
if((furi_hal_subghz_get_rolling_counter_mult() == (int32_t)0xFFFFFFF) & (rolling != 0)) {
rolling = 0;
} else {
// if cnt was reset to 0 on previous step and user want new Cnt then set it to 0xE6000000 or 0xFFFFFFFF or new user value
if(rolling == 0) {
if((furi_hal_subghz_get_rolling_counter_mult()) < (int32_t)0x6000000) {
rolling = 0xE6000000;
} else {
if((furi_hal_subghz_get_rolling_counter_mult()) >= (int32_t)0xFFFFFFF) {
rolling = 0xFFFFFFFF;
} else {
rolling = 0xE0000000;
rolling += multicntr;
}
}
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&rolling)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((rolling + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFFFFFF) {
rolling = 0xE6000000;
} else {
// if we have not special cases - so work as standart mode
if((rolling + multicntr) > 0xFFFFFFFF) {
rolling = 0xE6000000;
} else {
rolling += multicntr;
}
rolling += furi_hal_subghz_get_rolling_counter_mult();
}
}
if(rolling < 0xE6000000) rolling = 0xE6000000;
} else {
// OFEX (overflow experimental) mode
if((rolling + 0x1) > 0xFFFFFFFF) {
@@ -324,7 +300,7 @@ SubGhzProtocolStatus
if(ret != SubGhzProtocolStatusOk) {
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
@@ -607,6 +583,11 @@ void subghz_protocol_decoder_secplus_v1_get_string(void* context, FuriString* ou
uint8_t id1 = (fixed / 9) % 3;
uint16_t pin = 0;
// push protocol data to global variable
subghz_block_generic_global.cnt_is_available = true;
subghz_block_generic_global.cnt_length_bit = 32;
subghz_block_generic_global.current_cnt = instance->generic.cnt;
furi_string_cat_printf(
output,
"%s %db\r\n"

View File

@@ -404,40 +404,19 @@ static void subghz_protocol_secplus_v2_encode(SubGhzProtocolEncoderSecPlus_v2* i
uint8_t roll_2[9] = {0};
// Experemental case - we dont know counter size exactly, so just will be think that it is in range of 0xE500000 - 0xFFFFFFF
// one case when we have mult = 0xFFFFFFFF - its when we reset counter before applying new cnt value
// so at first step we reset cnt to 0 and now we sure here will be second step (set new cnt value);
// at second step check what user set for new Cnt (and correct it if cnt less than 0xE500000 or more than 0xFFFFFFF)
int32_t multicntr = (furi_hal_subghz_get_rolling_counter_mult() & 0xFFFFFFF);
// Adjust for negative multiplier
if(furi_hal_subghz_get_rolling_counter_mult() < 0) {
multicntr = furi_hal_subghz_get_rolling_counter_mult();
}
// Check for OFEX (overflow experimental) mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
if((furi_hal_subghz_get_rolling_counter_mult() == (int32_t)0xFFFFFFF) &
(instance->generic.cnt != 0)) {
instance->generic.cnt = 0;
} else {
// if cnt was reset to 0 on previous step and user want new Cnt then set it to 0xE500000 or 0xFFFFFFF or new user value
if(instance->generic.cnt == 0) {
if(furi_hal_subghz_get_rolling_counter_mult() < (int32_t)0xE500000) {
instance->generic.cnt = 0xE500000;
} else {
if(furi_hal_subghz_get_rolling_counter_mult() >= (int32_t)0xFFFFFFF) {
instance->generic.cnt = 0xFFFFFFF;
} else {
instance->generic.cnt += multicntr;
}
}
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFFFFF) {
instance->generic.cnt = 0xE500000;
} else {
// if we have not special cases - so work as standart mode
if((instance->generic.cnt + multicntr) > 0xFFFFFFF) {
instance->generic.cnt = 0xE500000;
} else {
instance->generic.cnt += multicntr;
}
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
}
}
if(instance->generic.cnt < 0xE500000) instance->generic.cnt = 0xE500000;
} else {
// OFEX (overflow experimental) mode
if((instance->generic.cnt + 0x1) > 0xFFFFFFF) {
@@ -597,7 +576,7 @@ SubGhzProtocolStatus
subghz_protocol_secplus_v2_remote_controller(
&instance->generic, instance->secplus_packet_1);
subghz_protocol_secplus_v2_encode(instance);
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
subghz_protocol_encoder_secplus_v2_get_upload(instance);
@@ -984,6 +963,11 @@ void subghz_protocol_decoder_secplus_v2_get_string(void* context, FuriString* ou
subghz_protocol_secplus_v2_remote_controller(&instance->generic, instance->secplus_packet_1);
// need to research or practice check how much bits in counter
// push protocol data to global variable
subghz_block_generic_global.cnt_is_available = true;
subghz_block_generic_global.cnt_length_bit = 28;
subghz_block_generic_global.current_cnt = instance->generic.cnt;
furi_string_cat_printf(
output,
"%s %db\r\n"

View File

@@ -180,7 +180,7 @@ SubGhzProtocolStatus
ret = SubGhzProtocolStatusErrorParserTe;
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);

View File

@@ -134,10 +134,14 @@ static bool
// Check for OFEX (overflow experimental) mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
}
}
} else {
if((instance->generic.cnt + 0x1) > 0xFFFF) {
@@ -410,7 +414,7 @@ SubGhzProtocolStatus
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
@@ -794,6 +798,11 @@ void subghz_protocol_decoder_somfy_keytis_get_string(void* context, FuriString*
subghz_protocol_somfy_keytis_check_remote_controller(&instance->generic);
// push protocol data to global variable
subghz_block_generic_global.cnt_is_available = true;
subghz_block_generic_global.cnt_length_bit = 16;
subghz_block_generic_global.current_cnt = instance->generic.cnt;
furi_string_cat_printf(
output,
"%s %db\r\n"

View File

@@ -128,10 +128,14 @@ static bool subghz_protocol_somfy_telis_gen_data(
// Check for OFEX (overflow experimental) mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
// standart counter mode. PULL data from subghz_block_generic_global variables
if(!subghz_block_generic_global_counter_override_get(&instance->generic.cnt)) {
// if counter_override_get return FALSE then counter was not changed and we increase counter by standart mult value
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
}
}
} else {
if((instance->generic.cnt + 0x1) > 0xFFFF) {
@@ -339,7 +343,7 @@ SubGhzProtocolStatus
break;
}
//optional parameter parameter
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
@@ -750,6 +754,12 @@ void subghz_protocol_decoder_somfy_telis_get_string(void* context, FuriString* o
SubGhzProtocolDecoderSomfyTelis* instance = context;
subghz_protocol_somfy_telis_check_remote_controller(&instance->generic);
// push protocol data to global variable
subghz_block_generic_global.cnt_is_available = true;
subghz_block_generic_global.cnt_length_bit = 16;
subghz_block_generic_global.current_cnt = instance->generic.cnt;
furi_string_cat_printf(
output,
"%s %db\r\n"

View File

@@ -1,741 +0,0 @@
#include "star_line.h"
#include "keeloq_common.h"
#include "../subghz_keystore.h"
#include <m-array.h>
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#include "../subghz_keystore_i.h"
#define TAG "SubGhzProtocolStarLine"
static const SubGhzBlockConst subghz_protocol_star_line_const = {
.te_short = 250,
.te_long = 500,
.te_delta = 120,
.min_count_bit_for_found = 64,
};
struct SubGhzProtocolDecoderStarLine {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
uint16_t header_count;
SubGhzKeystore* keystore;
const char* manufacture_name;
FuriString* manufacture_from_file;
};
struct SubGhzProtocolEncoderStarLine {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
SubGhzKeystore* keystore;
const char* manufacture_name;
FuriString* manufacture_from_file;
};
typedef enum {
StarLineDecoderStepReset = 0,
StarLineDecoderStepCheckPreambula,
StarLineDecoderStepSaveDuration,
StarLineDecoderStepCheckDuration,
} StarLineDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_star_line_decoder = {
.alloc = subghz_protocol_decoder_star_line_alloc,
.free = subghz_protocol_decoder_star_line_free,
.feed = subghz_protocol_decoder_star_line_feed,
.reset = subghz_protocol_decoder_star_line_reset,
.get_hash_data = NULL,
.get_hash_data_long = subghz_protocol_decoder_star_line_get_hash_data,
.serialize = subghz_protocol_decoder_star_line_serialize,
.deserialize = subghz_protocol_decoder_star_line_deserialize,
.get_string = subghz_protocol_decoder_star_line_get_string,
.get_string_brief = NULL,
};
const SubGhzProtocolEncoder subghz_protocol_star_line_encoder = {
.alloc = subghz_protocol_encoder_star_line_alloc,
.free = subghz_protocol_encoder_star_line_free,
.deserialize = subghz_protocol_encoder_star_line_deserialize,
.stop = subghz_protocol_encoder_star_line_stop,
.yield = subghz_protocol_encoder_star_line_yield,
};
const SubGhzProtocol subghz_protocol_star_line = {
.name = SUBGHZ_PROTOCOL_STAR_LINE_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_star_line_decoder,
.encoder = &subghz_protocol_star_line_encoder,
.filter = SubGhzProtocolFilter_Cars,
};
/**
* Analysis of received data
* @param instance Pointer to a SubGhzBlockGeneric* instance
* @param keystore Pointer to a SubGhzKeystore* instance
* @param manufacture_name
*/
static void subghz_protocol_star_line_check_remote_controller(
SubGhzBlockGeneric* instance,
SubGhzKeystore* keystore,
const char** manufacture_name);
void* subghz_protocol_encoder_star_line_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolEncoderStarLine* instance = malloc(sizeof(SubGhzProtocolEncoderStarLine));
instance->base.protocol = &subghz_protocol_star_line;
instance->generic.protocol_name = instance->base.protocol->name;
instance->keystore = subghz_environment_get_keystore(environment);
instance->manufacture_from_file = furi_string_alloc();
instance->encoder.repeat = 10;
instance->encoder.size_upload = 256;
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_running = false;
return instance;
}
void subghz_protocol_encoder_star_line_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderStarLine* instance = context;
furi_string_free(instance->manufacture_from_file);
free(instance->encoder.upload);
free(instance);
}
/**
* Key generation from simple data
* @param instance Pointer to a SubGhzProtocolEncoderKeeloq* instance
* @param btn Button number, 4 bit
*/
static bool
subghz_protocol_star_line_gen_data(SubGhzProtocolEncoderStarLine* instance, uint8_t btn) {
// Check for OFEX (overflow experimental) mode
if(furi_hal_subghz_get_rolling_counter_mult() != -0x7FFFFFFF) {
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) > 0xFFFF) {
instance->generic.cnt = 0;
} else {
instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult();
}
} else {
if((instance->generic.cnt + 0x1) > 0xFFFF) {
instance->generic.cnt = 0;
} else if(instance->generic.cnt >= 0x1 && instance->generic.cnt != 0xFFFE) {
instance->generic.cnt = 0xFFFE;
} else {
instance->generic.cnt++;
}
}
uint32_t fix = btn << 24 | instance->generic.serial;
uint32_t decrypt = btn << 24 | (instance->generic.serial & 0xFF) << 16 | instance->generic.cnt;
uint32_t hop = 0;
uint64_t man = 0;
uint64_t code_found_reverse;
int res = 0;
if(instance->manufacture_name == 0x0) {
instance->manufacture_name = "";
}
if(strcmp(instance->manufacture_name, "Unknown") == 0) {
code_found_reverse = subghz_protocol_blocks_reverse_key(
instance->generic.data, instance->generic.data_count_bit);
hop = code_found_reverse & 0x00000000ffffffff;
} else {
uint8_t kl_type_en = instance->keystore->kl_type;
for
M_EACH(
manufacture_code,
*subghz_keystore_get_data(instance->keystore),
SubGhzKeyArray_t) {
res = strcmp(
furi_string_get_cstr(manufacture_code->name), instance->manufacture_name);
if(res == 0) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
//Simple Learning
hop =
subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
break;
case KEELOQ_LEARNING_NORMAL:
//Normal Learning
man = subghz_protocol_keeloq_common_normal_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_UNKNOWN:
if(kl_type_en == 1) {
hop = subghz_protocol_keeloq_common_encrypt(
decrypt, manufacture_code->key);
}
if(kl_type_en == 2) {
man = subghz_protocol_keeloq_common_normal_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
break;
}
break;
}
}
}
if(hop) {
uint64_t yek = (uint64_t)fix << 32 | hop;
instance->generic.data =
subghz_protocol_blocks_reverse_key(yek, instance->generic.data_count_bit);
return true;
} else {
instance->manufacture_name = "Unknown";
return false;
}
}
bool subghz_protocol_star_line_create_data(
void* context,
FlipperFormat* flipper_format,
uint32_t serial,
uint8_t btn,
uint16_t cnt,
const char* manufacture_name,
SubGhzRadioPreset* preset) {
furi_assert(context);
SubGhzProtocolEncoderStarLine* instance = context;
instance->generic.serial = serial;
instance->generic.cnt = cnt;
instance->manufacture_name = manufacture_name;
instance->generic.data_count_bit = 64;
bool res = subghz_protocol_star_line_gen_data(instance, btn);
if(res) {
return SubGhzProtocolStatusOk ==
subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
}
return res;
}
/**
* Generating an upload from data.
* @param instance Pointer to a SubGhzProtocolEncoderKeeloq instance
* @return true On success
*/
static bool subghz_protocol_encoder_star_line_get_upload(
SubGhzProtocolEncoderStarLine* instance,
uint8_t btn) {
furi_assert(instance);
// Gen new key
if(!subghz_protocol_star_line_gen_data(instance, btn)) {
return false;
}
size_t index = 0;
size_t size_upload = 6 * 2 + (instance->generic.data_count_bit * 2);
if(size_upload > instance->encoder.size_upload) {
FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
return false;
} else {
instance->encoder.size_upload = size_upload;
}
//Send header
for(uint8_t i = 6; i > 0; i--) {
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_star_line_const.te_long * 2);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_star_line_const.te_long * 2);
}
//Send key data
for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
if(bit_read(instance->generic.data, i - 1)) {
//send bit 1
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_star_line_const.te_long);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_star_line_const.te_long);
} else {
//send bit 0
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_star_line_const.te_short);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)subghz_protocol_star_line_const.te_short);
}
}
return true;
}
SubGhzProtocolStatus
subghz_protocol_encoder_star_line_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderStarLine* instance = context;
SubGhzProtocolStatus res = SubGhzProtocolStatusError;
do {
if(SubGhzProtocolStatusOk !=
subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
FURI_LOG_E(TAG, "Deserialize error");
break;
}
// Read manufacturer from file
if(flipper_format_read_string(
flipper_format, "Manufacture", instance->manufacture_from_file)) {
instance->manufacture_name = furi_string_get_cstr(instance->manufacture_from_file);
instance->keystore->mfname = instance->manufacture_name;
} else {
FURI_LOG_D(TAG, "ENCODER: Missing Manufacture");
}
subghz_protocol_star_line_check_remote_controller(
&instance->generic, instance->keystore, &instance->manufacture_name);
//optional parameter parameter
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
subghz_protocol_encoder_star_line_get_upload(instance, instance->generic.btn);
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
uint8_t key_data[sizeof(uint64_t)] = {0};
for(size_t i = 0; i < sizeof(uint64_t); i++) {
key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF;
}
if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Unable to add Key");
break;
}
instance->encoder.is_running = true;
res = SubGhzProtocolStatusOk;
} while(false);
return res;
}
void subghz_protocol_encoder_star_line_stop(void* context) {
SubGhzProtocolEncoderStarLine* instance = context;
instance->encoder.is_running = false;
}
LevelDuration subghz_protocol_encoder_star_line_yield(void* context) {
SubGhzProtocolEncoderStarLine* instance = context;
if(instance->encoder.repeat == 0 || !instance->encoder.is_running) {
instance->encoder.is_running = 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_star_line_alloc(SubGhzEnvironment* environment) {
SubGhzProtocolDecoderStarLine* instance = malloc(sizeof(SubGhzProtocolDecoderStarLine));
instance->base.protocol = &subghz_protocol_star_line;
instance->generic.protocol_name = instance->base.protocol->name;
instance->manufacture_from_file = furi_string_alloc();
instance->keystore = subghz_environment_get_keystore(environment);
return instance;
}
void subghz_protocol_decoder_star_line_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderStarLine* instance = context;
furi_string_free(instance->manufacture_from_file);
free(instance);
}
void subghz_protocol_decoder_star_line_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderStarLine* instance = context;
instance->decoder.parser_step = StarLineDecoderStepReset;
// TODO
instance->keystore->mfname = "";
instance->keystore->kl_type = 0;
}
void subghz_protocol_decoder_star_line_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderStarLine* instance = context;
switch(instance->decoder.parser_step) {
case StarLineDecoderStepReset:
if(level) {
if(DURATION_DIFF(duration, subghz_protocol_star_line_const.te_long * 2) <
subghz_protocol_star_line_const.te_delta * 2) {
instance->decoder.parser_step = StarLineDecoderStepCheckPreambula;
instance->header_count++;
} else if(instance->header_count > 4) {
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
instance->decoder.te_last = duration;
instance->decoder.parser_step = StarLineDecoderStepCheckDuration;
}
} else {
instance->header_count = 0;
}
break;
case StarLineDecoderStepCheckPreambula:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_star_line_const.te_long * 2) <
subghz_protocol_star_line_const.te_delta * 2)) {
//Found Preambula
instance->decoder.parser_step = StarLineDecoderStepReset;
} else {
instance->header_count = 0;
instance->decoder.parser_step = StarLineDecoderStepReset;
}
break;
case StarLineDecoderStepSaveDuration:
if(level) {
if(duration >= (subghz_protocol_star_line_const.te_long +
subghz_protocol_star_line_const.te_delta)) {
instance->decoder.parser_step = StarLineDecoderStepReset;
if((instance->decoder.decode_count_bit >=
subghz_protocol_star_line_const.min_count_bit_for_found) &&
(instance->decoder.decode_count_bit <=
subghz_protocol_star_line_const.min_count_bit_for_found + 2)) {
if(instance->generic.data != instance->decoder.decode_data) {
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit =
subghz_protocol_star_line_const.min_count_bit_for_found;
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
}
}
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
instance->header_count = 0;
break;
} else {
instance->decoder.te_last = duration;
instance->decoder.parser_step = StarLineDecoderStepCheckDuration;
}
} else {
instance->decoder.parser_step = StarLineDecoderStepReset;
}
break;
case StarLineDecoderStepCheckDuration:
if(!level) {
if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_star_line_const.te_short) <
subghz_protocol_star_line_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_star_line_const.te_short) <
subghz_protocol_star_line_const.te_delta)) {
if(instance->decoder.decode_count_bit <
subghz_protocol_star_line_const.min_count_bit_for_found) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
} else {
instance->decoder.decode_count_bit++;
}
instance->decoder.parser_step = StarLineDecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_star_line_const.te_long) <
subghz_protocol_star_line_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_star_line_const.te_long) <
subghz_protocol_star_line_const.te_delta)) {
if(instance->decoder.decode_count_bit <
subghz_protocol_star_line_const.min_count_bit_for_found) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
} else {
instance->decoder.decode_count_bit++;
}
instance->decoder.parser_step = StarLineDecoderStepSaveDuration;
} else {
instance->decoder.parser_step = StarLineDecoderStepReset;
}
} else {
instance->decoder.parser_step = StarLineDecoderStepReset;
}
break;
}
}
/**
* Validation of decrypt data.
* @param instance Pointer to a SubGhzBlockGeneric instance
* @param decrypt Decrypd data
* @param btn Button number, 4 bit
* @param end_serial decrement the last 10 bits of the serial number
* @return true On success
*/
static inline bool subghz_protocol_star_line_check_decrypt(
SubGhzBlockGeneric* instance,
uint32_t decrypt,
uint8_t btn,
uint32_t end_serial) {
furi_assert(instance);
if((decrypt >> 24 == btn) && ((((uint16_t)(decrypt >> 16)) & 0x00FF) == end_serial)) {
instance->cnt = decrypt & 0x0000FFFF;
return true;
}
return false;
}
/**
* Checking the accepted code against the database manafacture key
* @param instance Pointer to a SubGhzBlockGeneric* instance
* @param fix Fix part of the parcel
* @param hop Hop encrypted part of the parcel
* @param keystore Pointer to a SubGhzKeystore* instance
* @param manufacture_name
* @return true on successful search
*/
static uint8_t subghz_protocol_star_line_check_remote_controller_selector(
SubGhzBlockGeneric* instance,
uint32_t fix,
uint32_t hop,
SubGhzKeystore* keystore,
const char** manufacture_name) {
uint16_t end_serial = (uint16_t)(fix & 0xFF);
uint8_t btn = (uint8_t)(fix >> 24);
uint32_t decrypt = 0;
uint64_t man_normal_learning;
bool mf_not_set = false;
// TODO:
// if(mfname == 0x0) {
// mfname = "";
// }
const char* mfname = keystore->mfname;
if(strcmp(mfname, "Unknown") == 0) {
return 1;
} else if(strcmp(mfname, "") == 0) {
mf_not_set = true;
}
for
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
if(mf_not_set || (strcmp(furi_string_get_cstr(manufacture_code->name), mfname) == 0)) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_star_line_check_decrypt(
instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
keystore->mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_NORMAL:
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man_normal_learning =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if(subghz_protocol_star_line_check_decrypt(
instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
keystore->mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_UNKNOWN:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_star_line_check_decrypt(
instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
keystore->mfname = *manufacture_name;
keystore->kl_type = 1;
return 1;
}
// Check for mirrored man
uint64_t man_rev = 0;
uint64_t man_rev_byte = 0;
for(uint8_t i = 0; i < 64; i += 8) {
man_rev_byte = (uint8_t)(manufacture_code->key >> i);
man_rev = man_rev | man_rev_byte << (56 - i);
}
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev);
if(subghz_protocol_star_line_check_decrypt(
instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
keystore->mfname = *manufacture_name;
keystore->kl_type = 1;
return 1;
}
//###########################
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man_normal_learning =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if(subghz_protocol_star_line_check_decrypt(
instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
keystore->mfname = *manufacture_name;
keystore->kl_type = 2;
return 1;
}
// Check for mirrored man
man_normal_learning =
subghz_protocol_keeloq_common_normal_learning(fix, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if(subghz_protocol_star_line_check_decrypt(
instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
keystore->mfname = *manufacture_name;
keystore->kl_type = 2;
return 1;
}
break;
}
}
}
*manufacture_name = "Unknown";
keystore->mfname = "Unknown";
instance->cnt = 0;
return 0;
}
/**
* Analysis of received data
* @param instance Pointer to a SubGhzBlockGeneric* instance
* @param keystore Pointer to a SubGhzKeystore* instance
* @param manufacture_name
*/
static void subghz_protocol_star_line_check_remote_controller(
SubGhzBlockGeneric* instance,
SubGhzKeystore* keystore,
const char** manufacture_name) {
uint64_t key = subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit);
uint32_t key_fix = key >> 32;
uint32_t key_hop = key & 0x00000000ffffffff;
subghz_protocol_star_line_check_remote_controller_selector(
instance, key_fix, key_hop, keystore, manufacture_name);
instance->serial = key_fix & 0x00FFFFFF;
instance->btn = key_fix >> 24;
}
uint32_t subghz_protocol_decoder_star_line_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderStarLine* instance = context;
return subghz_protocol_blocks_get_hash_data_long(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
SubGhzProtocolStatus subghz_protocol_decoder_star_line_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
SubGhzProtocolDecoderStarLine* instance = context;
subghz_protocol_star_line_check_remote_controller(
&instance->generic, instance->keystore, &instance->manufacture_name);
SubGhzProtocolStatus ret =
subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
if((ret == SubGhzProtocolStatusOk) &&
!flipper_format_write_string_cstr(
flipper_format, "Manufacture", instance->manufacture_name)) {
FURI_LOG_E(TAG, "Unable to add manufacture name");
ret = SubGhzProtocolStatusErrorParserOthers;
}
if((ret == SubGhzProtocolStatusOk) &&
instance->generic.data_count_bit !=
subghz_protocol_star_line_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
ret = SubGhzProtocolStatusErrorParserOthers;
}
return ret;
}
SubGhzProtocolStatus
subghz_protocol_decoder_star_line_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderStarLine* instance = context;
SubGhzProtocolStatus res = SubGhzProtocolStatusError;
do {
if(SubGhzProtocolStatusOk !=
subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
FURI_LOG_E(TAG, "Deserialize error");
break;
}
// Read manufacturer from file
if(flipper_format_read_string(
flipper_format, "Manufacture", instance->manufacture_from_file)) {
instance->manufacture_name = furi_string_get_cstr(instance->manufacture_from_file);
instance->keystore->mfname = instance->manufacture_name;
} else {
FURI_LOG_D(TAG, "DECODER: Missing Manufacture");
}
res = SubGhzProtocolStatusOk;
} while(false);
return res;
}
void subghz_protocol_decoder_star_line_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderStarLine* instance = context;
subghz_protocol_star_line_check_remote_controller(
&instance->generic, instance->keystore, &instance->manufacture_name);
uint32_t code_found_hi = instance->generic.data >> 32;
uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
instance->generic.data, instance->generic.data_count_bit);
uint32_t code_found_reverse_hi = code_found_reverse >> 32;
uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"Key:%08lX%08lX\r\n"
"Fix:0x%08lX Cnt:%04lX\r\n"
"Hop:0x%08lX Btn:%02X\r\n"
"MF:%s\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
code_found_hi,
code_found_lo,
code_found_reverse_hi,
instance->generic.cnt,
code_found_reverse_lo,
instance->generic.btn,
instance->manufacture_name);
}

View File

@@ -1,109 +0,0 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_STAR_LINE_NAME "Star Line"
typedef struct SubGhzProtocolDecoderStarLine SubGhzProtocolDecoderStarLine;
typedef struct SubGhzProtocolEncoderStarLine SubGhzProtocolEncoderStarLine;
extern const SubGhzProtocolDecoder subghz_protocol_star_line_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_star_line_encoder;
extern const SubGhzProtocol subghz_protocol_star_line;
/**
* Allocate SubGhzProtocolEncoderStarLine.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolEncoderStarLine* pointer to a SubGhzProtocolEncoderStarLine instance
*/
void* subghz_protocol_encoder_star_line_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolEncoderStarLine.
* @param context Pointer to a SubGhzProtocolEncoderStarLine instance
*/
void subghz_protocol_encoder_star_line_free(void* context);
/**
* Deserialize and generating an upload to send.
* @param context Pointer to a SubGhzProtocolEncoderStarLine instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return true On success
*/
SubGhzProtocolStatus
subghz_protocol_encoder_star_line_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Forced transmission stop.
* @param context Pointer to a SubGhzProtocolEncoderStarLine instance
*/
void subghz_protocol_encoder_star_line_stop(void* context);
/**
* Getting the level and duration of the upload to be loaded into DMA.
* @param context Pointer to a SubGhzProtocolEncoderStarLine instance
* @return LevelDuration
*/
LevelDuration subghz_protocol_encoder_star_line_yield(void* context);
/**
* Allocate SubGhzProtocolDecoderStarLine.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolDecoderStarLine* pointer to a SubGhzProtocolDecoderStarLine instance
*/
void* subghz_protocol_decoder_star_line_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolDecoderStarLine.
* @param context Pointer to a SubGhzProtocolDecoderStarLine instance
*/
void subghz_protocol_decoder_star_line_free(void* context);
/**
* Reset decoder SubGhzProtocolDecoderStarLine.
* @param context Pointer to a SubGhzProtocolDecoderStarLine instance
*/
void subghz_protocol_decoder_star_line_reset(void* context);
/**
* Parse a raw sequence of levels and durations received from the air.
* @param context Pointer to a SubGhzProtocolDecoderStarLine instance
* @param level Signal level true-high false-low
* @param duration Duration of this level in, us
*/
void subghz_protocol_decoder_star_line_feed(void* context, bool level, uint32_t duration);
/**
* Getting the hash sum of the last randomly received parcel.
* @param context Pointer to a SubGhzProtocolDecoderStarLine instance
* @return hash Hash sum
*/
uint32_t subghz_protocol_decoder_star_line_get_hash_data(void* context);
/**
* Serialize data SubGhzProtocolDecoderStarLine.
* @param context Pointer to a SubGhzProtocolDecoderStarLine instance
* @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return status
*/
SubGhzProtocolStatus subghz_protocol_decoder_star_line_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset);
/**
* Deserialize data SubGhzProtocolDecoderStarLine.
* @param context Pointer to a SubGhzProtocolDecoderStarLine instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return status
*/
SubGhzProtocolStatus
subghz_protocol_decoder_star_line_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Getting a textual representation of the received data.
* @param context Pointer to a SubGhzProtocolDecoderStarLine instance
* @param output Resulting text
*/
void subghz_protocol_decoder_star_line_get_string(void* context, FuriString* output);

View File

@@ -0,0 +1,351 @@
#include "treadmill37.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocolTreadmill37"
static const SubGhzBlockConst subghz_protocol_treadmill37_const = {
.te_short = 300,
.te_long = 900,
.te_delta = 150,
.min_count_bit_for_found = 37,
};
struct SubGhzProtocolDecoderTreadmill37 {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
};
struct SubGhzProtocolEncoderTreadmill37 {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
};
typedef enum {
Treadmill37DecoderStepReset = 0,
Treadmill37DecoderStepSaveDuration,
Treadmill37DecoderStepCheckDuration,
} Treadmill37DecoderStep;
const SubGhzProtocolDecoder subghz_protocol_treadmill37_decoder = {
.alloc = subghz_protocol_decoder_treadmill37_alloc,
.free = subghz_protocol_decoder_treadmill37_free,
.feed = subghz_protocol_decoder_treadmill37_feed,
.reset = subghz_protocol_decoder_treadmill37_reset,
.get_hash_data = NULL,
.get_hash_data_long = subghz_protocol_decoder_treadmill37_get_hash_data,
.serialize = subghz_protocol_decoder_treadmill37_serialize,
.deserialize = subghz_protocol_decoder_treadmill37_deserialize,
.get_string = subghz_protocol_decoder_treadmill37_get_string,
.get_string_brief = NULL,
};
const SubGhzProtocolEncoder subghz_protocol_treadmill37_encoder = {
.alloc = subghz_protocol_encoder_treadmill37_alloc,
.free = subghz_protocol_encoder_treadmill37_free,
.deserialize = subghz_protocol_encoder_treadmill37_deserialize,
.stop = subghz_protocol_encoder_treadmill37_stop,
.yield = subghz_protocol_encoder_treadmill37_yield,
};
const SubGhzProtocol subghz_protocol_treadmill37 = {
.name = SUBGHZ_PROTOCOL_TREADMILL37_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_treadmill37_decoder,
.encoder = &subghz_protocol_treadmill37_encoder,
};
void* subghz_protocol_encoder_treadmill37_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolEncoderTreadmill37* instance = malloc(sizeof(SubGhzProtocolEncoderTreadmill37));
instance->base.protocol = &subghz_protocol_treadmill37;
instance->generic.protocol_name = instance->base.protocol->name;
instance->encoder.repeat = 10;
instance->encoder.size_upload = 256;
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_running = false;
return instance;
}
void subghz_protocol_encoder_treadmill37_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderTreadmill37* instance = context;
free(instance->encoder.upload);
free(instance);
}
/**
* Generating an upload from data.
* @param instance Pointer to a SubGhzProtocolEncoderTreadmill37 instance
*/
static void
subghz_protocol_encoder_treadmill37_get_upload(SubGhzProtocolEncoderTreadmill37* instance) {
furi_assert(instance);
size_t index = 0;
// Send key and GAP
for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
if(bit_read(instance->generic.data, i - 1)) {
// Send bit 1
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_treadmill37_const.te_long);
if(i == 1) {
//Send gap if bit was last
instance->encoder.upload[index++] = level_duration_make(
false, (uint32_t)subghz_protocol_treadmill37_const.te_short * 20);
} else {
instance->encoder.upload[index++] = level_duration_make(
false, (uint32_t)subghz_protocol_treadmill37_const.te_short);
}
} else {
// Send bit 0
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)subghz_protocol_treadmill37_const.te_short);
if(i == 1) {
//Send gap if bit was last
instance->encoder.upload[index++] = level_duration_make(
false, (uint32_t)subghz_protocol_treadmill37_const.te_short * 20);
} else {
instance->encoder.upload[index++] = level_duration_make(
false, (uint32_t)subghz_protocol_treadmill37_const.te_long);
}
}
}
instance->encoder.size_upload = index;
return;
}
/**
* Analysis of received data
* @param instance Pointer to a SubGhzBlockGeneric* instance
*/
static void subghz_protocol_treadmill37_check_remote_controller(SubGhzBlockGeneric* instance) {
instance->serial = instance->data >> 17;
instance->cnt = (instance->data >> 1) & 0xFFFF;
}
SubGhzProtocolStatus
subghz_protocol_encoder_treadmill37_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderTreadmill37* instance = context;
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
do {
ret = subghz_block_generic_deserialize_check_count_bit(
&instance->generic,
flipper_format,
subghz_protocol_treadmill37_const.min_count_bit_for_found);
if(ret != SubGhzProtocolStatusOk) {
break;
}
// Optional value
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
subghz_protocol_treadmill37_check_remote_controller(&instance->generic);
subghz_protocol_encoder_treadmill37_get_upload(instance);
instance->encoder.is_running = true;
} while(false);
return ret;
}
void subghz_protocol_encoder_treadmill37_stop(void* context) {
SubGhzProtocolEncoderTreadmill37* instance = context;
instance->encoder.is_running = false;
}
LevelDuration subghz_protocol_encoder_treadmill37_yield(void* context) {
SubGhzProtocolEncoderTreadmill37* instance = context;
if(instance->encoder.repeat == 0 || !instance->encoder.is_running) {
instance->encoder.is_running = 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_treadmill37_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolDecoderTreadmill37* instance = malloc(sizeof(SubGhzProtocolDecoderTreadmill37));
instance->base.protocol = &subghz_protocol_treadmill37;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_treadmill37_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderTreadmill37* instance = context;
free(instance);
}
void subghz_protocol_decoder_treadmill37_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderTreadmill37* instance = context;
instance->decoder.parser_step = Treadmill37DecoderStepReset;
}
void subghz_protocol_decoder_treadmill37_feed(
void* context,
bool level,
volatile uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderTreadmill37* instance = context;
// Treadmill37 (QH-433) Decoder
// 2026 - @xMasterX (MMX)
// Key samples
// serial button stop
// 1800001830 = 00011000000000000000000 0000110000011000 0
// 180000061E = 00011000000000000000000 0000001100001111 0
// 180000142C = 00011000000000000000000 0000101000010110 0
// 1800000C24 = 00011000000000000000000 0000011000010010 0
// 180001556C = 00011000000000000000000 1010101010110110 0
// 180001334A = 00011000000000000000000 1001100110100101 0
switch(instance->decoder.parser_step) {
case Treadmill37DecoderStepReset:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_treadmill37_const.te_short * 20) <
subghz_protocol_treadmill37_const.te_delta * 4)) {
//Found GAP
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
instance->decoder.parser_step = Treadmill37DecoderStepSaveDuration;
}
break;
case Treadmill37DecoderStepSaveDuration:
if(level) {
instance->decoder.te_last = duration;
instance->decoder.parser_step = Treadmill37DecoderStepCheckDuration;
} else {
instance->decoder.parser_step = Treadmill37DecoderStepReset;
}
break;
case Treadmill37DecoderStepCheckDuration:
if(!level) {
// Bit 0 is short and long timing = 300us HIGH (te_last) and 900us LOW
if((DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_treadmill37_const.te_short) <
subghz_protocol_treadmill37_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_treadmill37_const.te_long) <
subghz_protocol_treadmill37_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = Treadmill37DecoderStepSaveDuration;
// Bit 1 is long and short timing = 900us HIGH (te_last) and 300us LOW
} else if(
(DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_treadmill37_const.te_long) <
subghz_protocol_treadmill37_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_treadmill37_const.te_short) <
subghz_protocol_treadmill37_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = Treadmill37DecoderStepSaveDuration;
} else if(
// End of the key
DURATION_DIFF(duration, subghz_protocol_treadmill37_const.te_short * 20) <
subghz_protocol_treadmill37_const.te_delta * 4) {
//Found next GAP and add bit 0 or 1 (only bit 0 was found on the remotes)
if((DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_treadmill37_const.te_short) <
subghz_protocol_treadmill37_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
}
if((DURATION_DIFF(
instance->decoder.te_last, subghz_protocol_treadmill37_const.te_long) <
subghz_protocol_treadmill37_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
}
// If got 37 bits key reading is finished
if(instance->decoder.decode_count_bit ==
subghz_protocol_treadmill37_const.min_count_bit_for_found) {
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
}
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
instance->decoder.parser_step = Treadmill37DecoderStepReset;
} else {
instance->decoder.parser_step = Treadmill37DecoderStepReset;
}
} else {
instance->decoder.parser_step = Treadmill37DecoderStepReset;
}
break;
}
}
uint32_t subghz_protocol_decoder_treadmill37_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderTreadmill37* instance = context;
return subghz_protocol_blocks_get_hash_data_long(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
SubGhzProtocolStatus subghz_protocol_decoder_treadmill37_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
SubGhzProtocolDecoderTreadmill37* instance = context;
return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
}
SubGhzProtocolStatus
subghz_protocol_decoder_treadmill37_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderTreadmill37* instance = context;
return subghz_block_generic_deserialize_check_count_bit(
&instance->generic,
flipper_format,
subghz_protocol_treadmill37_const.min_count_bit_for_found);
}
void subghz_protocol_decoder_treadmill37_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderTreadmill37* instance = context;
subghz_protocol_treadmill37_check_remote_controller(&instance->generic);
uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
instance->generic.data, instance->generic.data_count_bit);
furi_string_cat_printf(
output,
"%s %db\r\n"
"Key: 0x%08llX\r\n"
"Yek: 0x%08llX\r\n"
"Serial: 0x%06lX\r\n"
"Btn: %04lX",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint64_t)(instance->generic.data & 0xFFFFFFFFFF),
(code_found_reverse & 0xFFFFFFFFFF),
instance->generic.serial,
instance->generic.cnt);
}

View File

@@ -0,0 +1,109 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_TREADMILL37_NAME "Treadmill37"
typedef struct SubGhzProtocolDecoderTreadmill37 SubGhzProtocolDecoderTreadmill37;
typedef struct SubGhzProtocolEncoderTreadmill37 SubGhzProtocolEncoderTreadmill37;
extern const SubGhzProtocolDecoder subghz_protocol_treadmill37_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_treadmill37_encoder;
extern const SubGhzProtocol subghz_protocol_treadmill37;
/**
* Allocate SubGhzProtocolEncoderTreadmill37.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolEncoderTreadmill37* pointer to a SubGhzProtocolEncoderTreadmill37 instance
*/
void* subghz_protocol_encoder_treadmill37_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolEncoderTreadmill37.
* @param context Pointer to a SubGhzProtocolEncoderTreadmill37 instance
*/
void subghz_protocol_encoder_treadmill37_free(void* context);
/**
* Deserialize and generating an upload to send.
* @param context Pointer to a SubGhzProtocolEncoderTreadmill37 instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return status
*/
SubGhzProtocolStatus
subghz_protocol_encoder_treadmill37_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Forced transmission stop.
* @param context Pointer to a SubGhzProtocolEncoderTreadmill37 instance
*/
void subghz_protocol_encoder_treadmill37_stop(void* context);
/**
* Getting the level and duration of the upload to be loaded into DMA.
* @param context Pointer to a SubGhzProtocolEncoderTreadmill37 instance
* @return LevelDuration
*/
LevelDuration subghz_protocol_encoder_treadmill37_yield(void* context);
/**
* Allocate SubGhzProtocolDecoderTreadmill37.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolDecoderTreadmill37* pointer to a SubGhzProtocolDecoderTreadmill37 instance
*/
void* subghz_protocol_decoder_treadmill37_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolDecoderTreadmill37.
* @param context Pointer to a SubGhzProtocolDecoderTreadmill37 instance
*/
void subghz_protocol_decoder_treadmill37_free(void* context);
/**
* Reset decoder SubGhzProtocolDecoderTreadmill37.
* @param context Pointer to a SubGhzProtocolDecoderTreadmill37 instance
*/
void subghz_protocol_decoder_treadmill37_reset(void* context);
/**
* Parse a raw sequence of levels and durations received from the air.
* @param context Pointer to a SubGhzProtocolDecoderTreadmill37 instance
* @param level Signal level true-high false-low
* @param duration Duration of this level in, us
*/
void subghz_protocol_decoder_treadmill37_feed(void* context, bool level, uint32_t duration);
/**
* Getting the hash sum of the last randomly received parcel.
* @param context Pointer to a SubGhzProtocolDecoderTreadmill37 instance
* @return hash Hash sum
*/
uint32_t subghz_protocol_decoder_treadmill37_get_hash_data(void* context);
/**
* Serialize data SubGhzProtocolDecoderTreadmill37.
* @param context Pointer to a SubGhzProtocolDecoderTreadmill37 instance
* @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return status
*/
SubGhzProtocolStatus subghz_protocol_decoder_treadmill37_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset);
/**
* Deserialize data SubGhzProtocolDecoderTreadmill37.
* @param context Pointer to a SubGhzProtocolDecoderTreadmill37 instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return status
*/
SubGhzProtocolStatus
subghz_protocol_decoder_treadmill37_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Getting a textual representation of the received data.
* @param context Pointer to a SubGhzProtocolDecoderTreadmill37 instance
* @param output Resulting text
*/
void subghz_protocol_decoder_treadmill37_get_string(void* context, FuriString* output);

View File

@@ -83,6 +83,8 @@ static const uint32_t subghz_frequency_list[] = {
static const uint32_t subghz_hopper_frequency_list[] = {
315000000,
390000000,
430500000,
433920000,
434420000,
868350000,
@@ -187,6 +189,8 @@ static void subghz_setting_load_default_region(SubGhzSetting* instance) {
instance, "FM238", subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs);
subghz_setting_load_default_preset(
instance, "FM476", subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs);
subghz_setting_load_default_preset(
instance, "FM12K", subghz_device_cc1101_preset_2fsk_dev12khz_async_regs);
}
// Region check removed

View File

@@ -137,7 +137,7 @@ typedef enum {
} SubGhzProtocolFlag;
typedef enum {
SubGhzProtocolFilter_Cars = (1 << 0),
SubGhzProtocolFilter_ReversRB2 = (1 << 0),
SubGhzProtocolFilter_Alarms = (1 << 1),
SubGhzProtocolFilter_Sensors = (1 << 2),
SubGhzProtocolFilter_Princeton = (1 << 3),