mirror of
https://protopirate.net/ProtoPirate/ProtoPirate.git
synced 2026-10-23 04:23:27 +00:00
@xMasterX (MMX) --> Add StarLine and Scher-Khan protocol support plus encryptions and fixes
This commit is from @xMasterX (MMX) and introduces implementation files for StarLine and Scher-Khan SubGhz protocols, including protocol decoders, encoders, and keeloq key management. Adds common protocol utilities, keystore handling, and protocol-specific logic for key generation, serialization, and deserialization.
This commit is contained in:
1 parent
8a8b4ef9d1
commit
a4937375ea
12 files changed
+1979
-43
No files matched your search
@@ -17,15 +17,19 @@ Decoders:
|
||||
- KIA V6
|
||||
- Fiat
|
||||
- Ford V0
|
||||
- Scher-Khan
|
||||
- StarLine
|
||||
- Subaru
|
||||
- Suzuki
|
||||
- Volkswagen (VW)
|
||||
|
||||
Encoders:
|
||||
|
||||
- Ford V0
|
||||
- KIA V0
|
||||
- KIA V1
|
||||
- KIA V2
|
||||
- StarLine
|
||||
- More Coming Soon
|
||||
|
||||
## **Features**
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
Filetype: Flipper SubGhz Keystore File
|
||||
Version: 0
|
||||
Encryption: 1
|
||||
IV: 4E 6F 20 70 72 65 79 2C 20 6E 6F 20 70 61 79 2E
|
||||
EA7FE261D240CE6414D1D361E43AF320E38F6D922EB21E548D8D435464559BB7
|
||||
29BA3E03BB2DB4C615050DFB7946828673099C4F6D86D09441161FB10CDB7B4D
|
||||
18F800AA5B0332F2C0F4BCEB3D59686800BAB251D8F0DBC53B1F4EAC8A2E2387
|
||||
7C097B02B18F69AE74596FB4DF6CE3351434CDAAE5412D231160BF91A1EDB0EF
|
||||
08251F5CCE10B6BD15D9756FD52E67BCADBA41D15C995954BE029D44B5DB05AF
|
||||
A5D615FF2348A9D96005C5E730633F4CC40D302BB2DF71FC64FD9E4E8196EAC9461F1D8F28E7B4A74226BD87D41B71C9
|
||||
07F37E323DA69045B0A1638CAD103026116C79C4E7E4C722D9F2174EE9E329AF
|
||||
37ED45AA9A2F5A9417D37810EC3119B2F20DACF5CD844E5DEEED456A71FE7C4E
|
||||
46186986D6729A519FE9625C1ADDE6DFE29C0CE839B02FDCE35D6D5FEA364DBC
|
||||
AE4A7B44CA6BFBFF8F95B31CE369FE72558AD42382DCF0FD80760E0714B45995
|
||||
943C2F4CB7ACAA63D21B94AF50C2E0DB718E519B0021B2D8D7AF5769F6399F78
|
||||
252941621E705A49F60DF319A66D1C59A545029EDE8492A858659DC692B3429685D7042BCA24CBD281179C2CD73156A3
|
||||
8CE09F0770B9BA239E45F30A49EC136DAA0E4AC613B3E315B494DA424C7E5FE61F99FEF4DED839E4B2956FAA59657281
|
||||
CD2F173EDEB6BFB8754583D1E1C8CCD65CC6E3E79B5A868A53AA350E419B6607
|
||||
E49D6A039693731B6919CA29B416BE7067065D05F5B30BF9D8D1E0B8AC8EF364
|
||||
026BD7A08BE3A3D0C3EBDA6FDD0206D83A2CFA891272FF1629169B03EA37E300
|
||||
D9EE70D91292697EEAA6BA6564DB652182002B9A70848C3897C2CDBC129027DF
|
||||
31AB2CAE71DA2C317EC216D90342B969660B7FE0956D24D4B3C8C9DFD8A69E7F4A36675B34EC109CDBB88C044985CA23
|
||||
9C3A04D257748CC33FB013977E675EEBCECA502A3D10F4D2D7A28871A14A9D95
|
||||
543D8FBCFA879F2DBB023AA07D80FB0BDAABA864811AB7E38FC9A425A04C48EF
|
||||
DB8D083B1F209874629B046CC27E2DED5A251801C395CDF4A6940B4F05E13FA29CFC470020B217A3F94DF94D0C9C9EA4
|
||||
7FD6DD318E2D9E3BB137247BC70D42D9B5ED18C93ED07154B932A8EDD107F012AB65283CE6668CA555EFADE608DDA79C
|
||||
9E381D3E7D3D58FBECB3512C7D5DBDFB5E1708C79DC68E2EA6B13D82D3F9F851
|
||||
EC148A795CA521C1EE70EA4FB1377DAE06CA957CA9DBDFB970314B95E4AD9A89
|
||||
A2BE6299F878A91A60D3C0F4DD882A50F20EED7DB00C28AAC0A9E3B4609EAAC1
|
||||
0889904CC32C152F3A5A6874E2C172075F46AB4E63C696E35211CC609953F8D7
|
||||
E654760783674373EB889D80597AA35C416E8086FCE5DE4C02CA2EA42EBD569CA4A67F691ABC0209A6B208BAD5593CEE
|
||||
@@ -0,0 +1,142 @@
|
||||
#include "keeloq_common.h"
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#include <m-array.h>
|
||||
|
||||
#define bit(x, n) (((x) >> (n)) & 1)
|
||||
#define g5(x, a, b, c, d, e) \
|
||||
(bit(x, a) + bit(x, b) * 2 + bit(x, c) * 4 + bit(x, d) * 8 + bit(x, e) * 16)
|
||||
|
||||
/** Simple Learning Encrypt
|
||||
* @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter
|
||||
* @param key - manufacture (64bit)
|
||||
* @return keeloq encrypt data
|
||||
*/
|
||||
inline uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const uint64_t key) {
|
||||
uint32_t x = data, r;
|
||||
for(r = 0; r < 528; r++)
|
||||
x = (x >> 1) ^ ((bit(x, 0) ^ bit(x, 16) ^ (uint32_t)bit(key, r & 63) ^
|
||||
bit(KEELOQ_NLF, g5(x, 1, 9, 20, 26, 31)))
|
||||
<< 31);
|
||||
return x;
|
||||
}
|
||||
|
||||
/** Simple Learning Decrypt
|
||||
* @param data - keeloq encrypt data
|
||||
* @param key - manufacture (64bit)
|
||||
* @return 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter
|
||||
*/
|
||||
inline uint32_t subghz_protocol_keeloq_common_decrypt(const uint32_t data, const uint64_t key) {
|
||||
uint32_t x = data, r;
|
||||
for(r = 0; r < 528; r++)
|
||||
x = (x << 1) ^ bit(x, 31) ^ bit(x, 15) ^ (uint32_t)bit(key, (15 - r) & 63) ^
|
||||
bit(KEELOQ_NLF, g5(x, 0, 8, 19, 25, 30));
|
||||
return x;
|
||||
}
|
||||
|
||||
/** Normal Learning
|
||||
* @param data - serial number (28bit)
|
||||
* @param key - manufacture (64bit)
|
||||
* @return manufacture for this serial number (64bit)
|
||||
*/
|
||||
inline uint64_t subghz_protocol_keeloq_common_normal_learning(uint32_t data, const uint64_t key) {
|
||||
uint32_t k1, k2;
|
||||
|
||||
data &= 0x0FFFFFFF;
|
||||
data |= 0x20000000;
|
||||
k1 = subghz_protocol_keeloq_common_decrypt(data, key);
|
||||
|
||||
data &= 0x0FFFFFFF;
|
||||
data |= 0x60000000;
|
||||
k2 = subghz_protocol_keeloq_common_decrypt(data, key);
|
||||
|
||||
return ((uint64_t)k2 << 32) | k1; // key - shifrovanoya
|
||||
}
|
||||
|
||||
/** Secure Learning
|
||||
* @param data - serial number (28bit)
|
||||
* @param seed - seed number (32bit)
|
||||
* @param key - manufacture (64bit)
|
||||
* @return manufacture for this serial number (64bit)
|
||||
*/
|
||||
|
||||
inline uint64_t subghz_protocol_keeloq_common_secure_learning(
|
||||
uint32_t data,
|
||||
uint32_t seed,
|
||||
const uint64_t key) {
|
||||
uint32_t k1, k2;
|
||||
|
||||
data &= 0x0FFFFFFF;
|
||||
k1 = subghz_protocol_keeloq_common_decrypt(data, key);
|
||||
k2 = subghz_protocol_keeloq_common_decrypt(seed, key);
|
||||
|
||||
return ((uint64_t)k1 << 32) | k2;
|
||||
}
|
||||
|
||||
/** Magic_xor_type1 Learning
|
||||
* @param data - serial number (28bit)
|
||||
* @param xor - magic xor (64bit)
|
||||
* @return manufacture for this serial number (64bit)
|
||||
*/
|
||||
|
||||
inline uint64_t
|
||||
subghz_protocol_keeloq_common_magic_xor_type1_learning(uint32_t data, uint64_t xor) {
|
||||
data &= 0x0FFFFFFF;
|
||||
return (((uint64_t)data << 32) | data) ^ xor;
|
||||
}
|
||||
|
||||
/** Faac SLH (Spa) Learning
|
||||
* @param seed - seed number (32bit)
|
||||
* @param key - mfkey (64bit)
|
||||
* @return man_learning for this seed number (64bit)
|
||||
*/
|
||||
|
||||
inline uint64_t
|
||||
subghz_protocol_keeloq_common_faac_learning(const uint32_t seed, const uint64_t key) {
|
||||
uint16_t hs = seed >> 16;
|
||||
const uint16_t ending = 0x544D;
|
||||
uint32_t lsb = (uint32_t)hs << 16 | ending;
|
||||
uint64_t man = (uint64_t)subghz_protocol_keeloq_common_encrypt(seed, key) << 32 |
|
||||
subghz_protocol_keeloq_common_encrypt(lsb, key);
|
||||
return man;
|
||||
}
|
||||
/** Magic_serial_type1 Learning
|
||||
* @param data - serial number (28bit)
|
||||
* @param man - magic man (64bit)
|
||||
* @return manufacture for this serial number (64bit)
|
||||
*/
|
||||
|
||||
inline uint64_t
|
||||
subghz_protocol_keeloq_common_magic_serial_type1_learning(uint32_t data, uint64_t man) {
|
||||
return (man & 0xFFFFFFFF) | ((uint64_t)data << 40) |
|
||||
((uint64_t)(((data & 0xff) + ((data >> 8) & 0xFF)) & 0xFF) << 32);
|
||||
}
|
||||
|
||||
/** Magic_serial_type2 Learning
|
||||
* @param data - btn+serial number (32bit)
|
||||
* @param man - magic man (64bit)
|
||||
* @return manufacture for this serial number (64bit)
|
||||
*/
|
||||
|
||||
inline uint64_t
|
||||
subghz_protocol_keeloq_common_magic_serial_type2_learning(uint32_t data, uint64_t man) {
|
||||
uint8_t* p = (uint8_t*)&data;
|
||||
uint8_t* m = (uint8_t*)&man;
|
||||
m[7] = p[0];
|
||||
m[6] = p[1];
|
||||
m[5] = p[2];
|
||||
m[4] = p[3];
|
||||
return man;
|
||||
}
|
||||
|
||||
/** Magic_serial_type3 Learning
|
||||
* @param data - serial number (24bit)
|
||||
* @param man - magic man (64bit)
|
||||
* @return manufacture for this serial number (64bit)
|
||||
*/
|
||||
|
||||
inline uint64_t
|
||||
subghz_protocol_keeloq_common_magic_serial_type3_learning(uint32_t data, uint64_t man) {
|
||||
return (man & 0xFFFFFFFFFF000000) | (data & 0xFFFFFF);
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <lib/subghz/protocols/base.h>
|
||||
#include <lib/subghz/types.h>
|
||||
#include <lib/subghz/blocks/const.h>
|
||||
#include <lib/subghz/blocks/decoder.h>
|
||||
#include <lib/subghz/blocks/encoder.h>
|
||||
#include <lib/subghz/blocks/generic.h>
|
||||
#include <lib/subghz/blocks/math.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <lib/toolbox/manchester_decoder.h>
|
||||
|
||||
#include <m-array.h>
|
||||
|
||||
struct SubGhzKeystore {
|
||||
SubGhzKeyArray_t data;
|
||||
const char* mfname;
|
||||
uint8_t kl_type;
|
||||
};
|
||||
|
||||
/*
|
||||
* Keeloq
|
||||
* https://ru.wikipedia.org/wiki/KeeLoq
|
||||
* https://phreakerclub.com/forum/showthread.php?t=1094
|
||||
*
|
||||
*/
|
||||
#define KEELOQ_NLF 0x3A5C742E
|
||||
|
||||
/*
|
||||
* KeeLoq learning types
|
||||
* https://phreakerclub.com/forum/showthread.php?t=67
|
||||
*/
|
||||
#define KEELOQ_LEARNING_UNKNOWN 0u
|
||||
#define KEELOQ_LEARNING_SIMPLE 1u
|
||||
#define KEELOQ_LEARNING_NORMAL 2u
|
||||
// #define KEELOQ_LEARNING_SECURE 3u
|
||||
#define KEELOQ_LEARNING_MAGIC_XOR_TYPE_1 4u
|
||||
// #define KEELOQ_LEARNING_FAAC 5u
|
||||
#define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_1 6u
|
||||
#define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_2 7u
|
||||
#define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_3 8u
|
||||
|
||||
/**
|
||||
* Simple Learning Encrypt
|
||||
* @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter
|
||||
* @param key - manufacture (64bit)
|
||||
* @return keeloq encrypt data
|
||||
*/
|
||||
uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const uint64_t key);
|
||||
|
||||
/**
|
||||
* Simple Learning Decrypt
|
||||
* @param data - keeloq encrypt data
|
||||
* @param key - manufacture (64bit)
|
||||
* @return 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter
|
||||
*/
|
||||
uint32_t subghz_protocol_keeloq_common_decrypt(const uint32_t data, const uint64_t key);
|
||||
|
||||
/**
|
||||
* Normal Learning
|
||||
* @param data - serial number (28bit)
|
||||
* @param key - manufacture (64bit)
|
||||
* @return manufacture for this serial number (64bit)
|
||||
*/
|
||||
uint64_t subghz_protocol_keeloq_common_normal_learning(uint32_t data, const uint64_t key);
|
||||
|
||||
/**
|
||||
* Secure Learning
|
||||
* @param data - serial number (28bit)
|
||||
* @param seed - seed number (32bit)
|
||||
* @param key - manufacture (64bit)
|
||||
* @return manufacture for this serial number (64bit)
|
||||
*/
|
||||
uint64_t
|
||||
subghz_protocol_keeloq_common_secure_learning(uint32_t data, uint32_t seed, const uint64_t key);
|
||||
|
||||
/**
|
||||
* Magic_xor_type1 Learning
|
||||
* @param data - serial number (28bit)
|
||||
* @param xor - magic xor (64bit)
|
||||
* @return manufacture for this serial number (64bit)
|
||||
*/
|
||||
uint64_t subghz_protocol_keeloq_common_magic_xor_type1_learning(uint32_t data, uint64_t xor);
|
||||
|
||||
/** Faac SLH (Spa) Learning
|
||||
* @param seed - seed number (32bit)
|
||||
* @param key - mfkey (64bit)
|
||||
* @return man_learning for this fix number (64bit)
|
||||
*/
|
||||
uint64_t subghz_protocol_keeloq_common_faac_learning(const uint32_t seed, const uint64_t key);
|
||||
|
||||
/** Magic_serial_type1 Learning
|
||||
* @param data - serial number (28bit)
|
||||
* @param man - magic man (64bit)
|
||||
* @return manufacture for this serial number (64bit)
|
||||
*/
|
||||
|
||||
uint64_t subghz_protocol_keeloq_common_magic_serial_type1_learning(uint32_t data, uint64_t man);
|
||||
|
||||
/** Magic_serial_type2 Learning
|
||||
* @param data - btn+serial number (32bit)
|
||||
* @param man - magic man (64bit)
|
||||
* @return manufacture for this serial number (64bit)
|
||||
*/
|
||||
|
||||
uint64_t subghz_protocol_keeloq_common_magic_serial_type2_learning(uint32_t data, uint64_t man);
|
||||
|
||||
/** Magic_serial_type3 Learning
|
||||
* @param data - btn+serial number (32bit)
|
||||
* @param man - magic man (64bit)
|
||||
* @return manufacture for this serial number (64bit)
|
||||
*/
|
||||
|
||||
uint64_t subghz_protocol_keeloq_common_magic_serial_type3_learning(uint32_t data, uint64_t man);
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "keys.h"
|
||||
|
||||
#define KIA_KEY1 10u
|
||||
#define KIA_KEY2 11u
|
||||
#define KIA_KEY3 12u
|
||||
|
||||
uint64_t kia_mf_key = 0;
|
||||
uint64_t kia_v6_a_key = 0;
|
||||
uint64_t kia_v6_b_key = 0;
|
||||
|
||||
void protopirate_keys_load(SubGhzEnvironment* environment) {
|
||||
SubGhzKeystore* keystore = subghz_environment_get_keystore(environment);
|
||||
// Load keys from secure keystore
|
||||
for
|
||||
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
|
||||
switch(manufacture_code->type) {
|
||||
case KIA_KEY1:
|
||||
kia_mf_key = manufacture_code->key;
|
||||
break;
|
||||
case KIA_KEY2:
|
||||
kia_v6_a_key = manufacture_code->key;
|
||||
break;
|
||||
case KIA_KEY3:
|
||||
kia_v6_b_key = manufacture_code->key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t get_kia_mf_key() {
|
||||
return kia_mf_key;
|
||||
}
|
||||
|
||||
uint64_t get_kia_v6_keystore_a() {
|
||||
return kia_v6_a_key;
|
||||
}
|
||||
|
||||
uint64_t get_kia_v6_keystore_b() {
|
||||
return kia_v6_b_key;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "protocols_common.h"
|
||||
|
||||
const char* protopirate_get_short_preset_name(const char* preset_name) {
|
||||
if(!strcmp(preset_name, "FuriHalSubGhzPresetOok270Async")) {
|
||||
return "AM270";
|
||||
} else if(!strcmp(preset_name, "FuriHalSubGhzPresetOok650Async")) {
|
||||
return "AM650";
|
||||
} else if(!strcmp(preset_name, "FuriHalSubGhzPreset2FSKDev238Async")) {
|
||||
return "FM238";
|
||||
} else if(!strcmp(preset_name, "FuriHalSubGhzPreset2FSKDev12KAsync")) {
|
||||
return "FM12K";
|
||||
} else if(!strcmp(preset_name, "FuriHalSubGhzPreset2FSKDev476Async")) {
|
||||
return "FM476";
|
||||
} else if(!strcmp(preset_name, "FuriHalSubGhzPresetCustom")) {
|
||||
return "CUSTOM";
|
||||
}
|
||||
return preset_name;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <lib/subghz/types.h>
|
||||
|
||||
const char* protopirate_get_short_preset_name(const char* preset_name);
|
||||
@@ -0,0 +1,361 @@
|
||||
#include "scher_khan.h"
|
||||
|
||||
#include "protocols_common.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 = 180,
|
||||
.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 = 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,
|
||||
};
|
||||
|
||||
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,
|
||||
|
||||
.decoder = &subghz_protocol_scher_khan_decoder,
|
||||
.encoder = &subghz_protocol_scher_khan_encoder,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t subghz_protocol_decoder_scher_khan_get_hash_data(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderScherKhan* instance = context;
|
||||
return subghz_protocol_blocks_get_hash_data(
|
||||
&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;
|
||||
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
|
||||
|
||||
do {
|
||||
if(preset != NULL) {
|
||||
if(!flipper_format_insert_or_update_uint32(
|
||||
flipper_format, "Frequency", &preset->frequency, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
const char* preset_name = furi_string_get_cstr(preset->name);
|
||||
const char* short_preset = protopirate_get_short_preset_name(preset_name);
|
||||
if(!flipper_format_insert_or_update_string_cstr(
|
||||
flipper_format, "Preset", short_preset)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!flipper_format_insert_or_update_string_cstr(
|
||||
flipper_format, "Protocol", instance->generic.protocol_name)) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t bits = instance->generic.data_count_bit;
|
||||
if(!flipper_format_insert_or_update_uint32(flipper_format, "Bit", &bits, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
char key_str[20];
|
||||
snprintf(key_str, sizeof(key_str), "%016llX", instance->generic.data);
|
||||
if(!flipper_format_insert_or_update_string_cstr(flipper_format, "Key", key_str)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_insert_or_update_uint32(
|
||||
flipper_format, "Serial", &instance->generic.serial, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t temp = instance->generic.btn;
|
||||
if(!flipper_format_insert_or_update_uint32(flipper_format, "Btn", &temp, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_insert_or_update_uint32(
|
||||
flipper_format, "Cnt", &instance->generic.cnt, 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
ret = SubGhzProtocolStatusOk;
|
||||
} while(false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <lib/subghz/protocols/base.h>
|
||||
#include <lib/subghz/types.h>
|
||||
#include <lib/subghz/blocks/const.h>
|
||||
#include <lib/subghz/blocks/decoder.h>
|
||||
#include <lib/subghz/blocks/encoder.h>
|
||||
#include <lib/subghz/blocks/generic.h>
|
||||
#include <lib/subghz/blocks/math.h>
|
||||
#include <lib/toolbox/manchester_decoder.h>
|
||||
#include <flipper_format/flipper_format.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
|
||||
*/
|
||||
uint8_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);
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,117 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <lib/subghz/protocols/base.h>
|
||||
#include <lib/subghz/types.h>
|
||||
#include <lib/subghz/blocks/const.h>
|
||||
#include <lib/subghz/blocks/decoder.h>
|
||||
#include <lib/subghz/blocks/encoder.h>
|
||||
#include <lib/subghz/blocks/generic.h>
|
||||
#include <lib/subghz/blocks/math.h>
|
||||
#include <lib/toolbox/manchester_decoder.h>
|
||||
#include <flipper_format/flipper_format.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
|
||||
*/
|
||||
uint8_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);
|
||||
+55
-43
@@ -5,34 +5,31 @@
|
||||
#include <furi_hal.h>
|
||||
#include "protocols/protocol_items.h"
|
||||
#include "helpers/protopirate_settings.h"
|
||||
#include "helpers/protopirate_storage.h"
|
||||
#include "helpers/protopirate_storage.h"
|
||||
#include "protocols/keys.h"
|
||||
|
||||
#define TAG "ProtoPirateApp"
|
||||
|
||||
static bool protopirate_app_custom_event_callback(void *context, uint32_t event)
|
||||
{
|
||||
static bool protopirate_app_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
ProtoPirateApp *app = context;
|
||||
ProtoPirateApp* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool protopirate_app_back_event_callback(void *context)
|
||||
{
|
||||
static bool protopirate_app_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
ProtoPirateApp *app = context;
|
||||
ProtoPirateApp* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void protopirate_app_tick_event_callback(void *context)
|
||||
{
|
||||
static void protopirate_app_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
ProtoPirateApp *app = context;
|
||||
ProtoPirateApp* app = context;
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
ProtoPirateApp *protopirate_app_alloc()
|
||||
{
|
||||
ProtoPirateApp *app = malloc(sizeof(ProtoPirateApp));
|
||||
ProtoPirateApp* protopirate_app_alloc() {
|
||||
ProtoPirateApp* app = malloc(sizeof(ProtoPirateApp));
|
||||
|
||||
FURI_LOG_I(TAG, "Allocating ProtoPirate Decoder App");
|
||||
|
||||
@@ -99,7 +96,7 @@ ProtoPirateApp *protopirate_app_alloc()
|
||||
// Load saved settings
|
||||
ProtoPirateSettings settings;
|
||||
protopirate_settings_load(&settings);
|
||||
|
||||
|
||||
// Apply auto-save setting
|
||||
app->auto_save = settings.auto_save;
|
||||
|
||||
@@ -114,7 +111,7 @@ ProtoPirateApp *protopirate_app_alloc()
|
||||
// Apply loaded frequency and preset, with validation
|
||||
uint32_t frequency = settings.frequency;
|
||||
uint8_t preset_index = settings.preset_index;
|
||||
|
||||
|
||||
// Validate frequency - check if it exists in settings
|
||||
bool frequency_valid = false;
|
||||
for(size_t i = 0; i < subghz_setting_get_frequency_count(app->setting); i++) {
|
||||
@@ -127,26 +124,31 @@ ProtoPirateApp *protopirate_app_alloc()
|
||||
frequency = subghz_setting_get_default_frequency(app->setting);
|
||||
FURI_LOG_W(TAG, "Saved frequency invalid, using default: %lu", frequency);
|
||||
}
|
||||
|
||||
|
||||
// Validate preset index
|
||||
if(preset_index >= subghz_setting_get_preset_count(app->setting)) {
|
||||
preset_index = 0;
|
||||
FURI_LOG_W(TAG, "Saved preset index invalid, using default");
|
||||
}
|
||||
|
||||
|
||||
// Get preset name and data
|
||||
const char* preset_name = subghz_setting_get_preset_name(app->setting, preset_index);
|
||||
uint8_t* preset_data = subghz_setting_get_preset_data(app->setting, preset_index);
|
||||
size_t preset_data_size = subghz_setting_get_preset_data_size(app->setting, preset_index);
|
||||
|
||||
FURI_LOG_I(TAG, "Applying settings: freq=%lu, preset=%s, auto_save=%d, hopping=%d",
|
||||
frequency, preset_name, settings.auto_save, settings.hopping_enabled);
|
||||
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"Applying settings: freq=%lu, preset=%s, auto_save=%d, hopping=%d",
|
||||
frequency,
|
||||
preset_name,
|
||||
settings.auto_save,
|
||||
settings.hopping_enabled);
|
||||
|
||||
protopirate_preset_init(app, preset_name, frequency, preset_data, preset_data_size);
|
||||
|
||||
// Apply hopping state from settings
|
||||
app->txrx->hopper_state = settings.hopping_enabled ?
|
||||
ProtoPirateHopperStateRunning : ProtoPirateHopperStateOFF;
|
||||
app->txrx->hopper_state = settings.hopping_enabled ? ProtoPirateHopperStateRunning :
|
||||
ProtoPirateHopperStateOFF;
|
||||
app->txrx->hopper_idx_frequency = 0;
|
||||
app->txrx->hopper_timeout = 0;
|
||||
app->txrx->idx_menu_chosen = 0;
|
||||
@@ -157,9 +159,17 @@ ProtoPirateApp *protopirate_app_alloc()
|
||||
// Create environment with our custom protocols
|
||||
app->txrx->environment = subghz_environment_alloc();
|
||||
|
||||
// Load keystores
|
||||
subghz_environment_load_keystore(app->txrx->environment, PROTOPIRATE_KEYSTORE_DIR_NAME);
|
||||
subghz_environment_load_keystore(app->txrx->environment, SUBGHZ_KEYSTORE_DIR_USER_NAME);
|
||||
|
||||
FURI_LOG_I(TAG, "Registering %zu ProtoPirate protocols", protopirate_protocol_registry.size);
|
||||
subghz_environment_set_protocol_registry(
|
||||
app->txrx->environment, (void *)&protopirate_protocol_registry);
|
||||
app->txrx->environment, (void*)&protopirate_protocol_registry);
|
||||
|
||||
// Load ProtoPirate specific keys
|
||||
protopirate_keys_load(app->txrx->environment);
|
||||
FURI_LOG_I(TAG, "Loaded ProtoPirate secure keys");
|
||||
|
||||
// Create receiver
|
||||
app->txrx->receiver = subghz_receiver_alloc_init(app->txrx->environment);
|
||||
@@ -168,15 +178,16 @@ ProtoPirateApp *protopirate_app_alloc()
|
||||
subghz_devices_init();
|
||||
|
||||
// Try external CC1101 first, fallback to internal
|
||||
app->txrx->radio_device =
|
||||
radio_device_loader_set(NULL, SubGhzRadioDeviceTypeExternalCC1101);
|
||||
app->txrx->radio_device = radio_device_loader_set(NULL, SubGhzRadioDeviceTypeExternalCC1101);
|
||||
|
||||
if(!app->txrx->radio_device) {
|
||||
FURI_LOG_E(TAG, "Failed to initialize any radio device!");
|
||||
} else {
|
||||
const char* device_name = subghz_devices_get_name(app->txrx->radio_device);
|
||||
bool is_external = device_name && strstr(device_name, "ext");
|
||||
FURI_LOG_I(TAG, "Radio device initialized: %s (%s)",
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"Radio device initialized: %s (%s)",
|
||||
device_name ? device_name : "unknown",
|
||||
is_external ? "external" : "internal");
|
||||
}
|
||||
@@ -201,21 +212,20 @@ ProtoPirateApp *protopirate_app_alloc()
|
||||
return app;
|
||||
}
|
||||
|
||||
void protopirate_app_free(ProtoPirateApp *app)
|
||||
{
|
||||
void protopirate_app_free(ProtoPirateApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
FURI_LOG_I(TAG, "Freeing ProtoPirate Decoder App");
|
||||
|
||||
// Free the storage file list cache
|
||||
protopirate_storage_free_file_list();
|
||||
protopirate_storage_free_file_list();
|
||||
|
||||
// Save settings before exiting
|
||||
ProtoPirateSettings settings;
|
||||
settings.frequency = app->txrx->preset->frequency;
|
||||
settings.auto_save = app->auto_save;
|
||||
settings.hopping_enabled = (app->txrx->hopper_state != ProtoPirateHopperStateOFF);
|
||||
|
||||
|
||||
// Find current preset index
|
||||
settings.preset_index = 0;
|
||||
const char* current_preset = furi_string_get_cstr(app->txrx->preset->name);
|
||||
@@ -225,21 +235,24 @@ void protopirate_app_free(ProtoPirateApp *app)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Saving settings: freq=%lu, preset=%u, auto_save=%d, hopping=%d",
|
||||
settings.frequency, settings.preset_index, settings.auto_save, settings.hopping_enabled);
|
||||
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"Saving settings: freq=%lu, preset=%u, auto_save=%d, hopping=%d",
|
||||
settings.frequency,
|
||||
settings.preset_index,
|
||||
settings.auto_save,
|
||||
settings.hopping_enabled);
|
||||
|
||||
protopirate_settings_save(&settings);
|
||||
|
||||
// Make sure we're not receiving
|
||||
if (app->txrx->txrx_state == ProtoPirateTxRxStateRx)
|
||||
{
|
||||
if(app->txrx->txrx_state == ProtoPirateTxRxStateRx) {
|
||||
subghz_worker_stop(app->txrx->worker);
|
||||
subghz_devices_stop_async_rx(app->txrx->radio_device);
|
||||
}
|
||||
|
||||
if (app->loaded_file_path)
|
||||
{
|
||||
if(app->loaded_file_path) {
|
||||
furi_string_free(app->loaded_file_path);
|
||||
}
|
||||
|
||||
@@ -300,14 +313,13 @@ void protopirate_app_free(ProtoPirateApp *app)
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t protopirate_app(void *p)
|
||||
{
|
||||
int32_t protopirate_app(void* p) {
|
||||
UNUSED(p);
|
||||
ProtoPirateApp *protopirate_app = protopirate_app_alloc();
|
||||
ProtoPirateApp* protopirate_app = protopirate_app_alloc();
|
||||
|
||||
view_dispatcher_run(protopirate_app->view_dispatcher);
|
||||
|
||||
protopirate_app_free(protopirate_app);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user