Merge commit '484ea661f1032276bf937ceb83fa2311c41ba9f4' into mntm-dev
@@ -5,6 +5,7 @@
|
||||
- Sub-GHz:
|
||||
- UL: Cardin S449 protocol full support (64bit keeloq) (with Add manually, and all button codes) (use FSK12K modulation to read the remote) (by @xMasterX & @zero-mega)
|
||||
- UL: Beninca ARC AES128 protocol full support (128bit dynamic) (with Add manually, and 2 button codes) (by @xMasterX & @zero-mega)
|
||||
- UL: Jarolift protocol full support (72bit dynamic) (with Add manually, and all button codes) (by @xMasterX & d82k & Steffen (bastelbudenbuben de))
|
||||
- UL: Treadmill37 protocol support (37bit static) (by @xMasterX)
|
||||
- UL: New modulation FSK with 12KHz deviation (by @xMasterX)
|
||||
- UL: KingGates Stylo 4k Add manually and button switch support and refactoring of encoder (by @xMasterX)
|
||||
@@ -32,14 +33,16 @@
|
||||
- UL: Alutech AT-4N & Nice Flor S turbo speedup (by @Dmitry422)
|
||||
- UL: Sommer fm2 in Add manually now uses FM12K modulation (Sommer without fm2 tag uses FM476) (try this if regular option doesn't work for you) (by @xMasterX)
|
||||
- UL: Replaced Cars ignore option with Revers RB2 protocol ignore option (by @xMasterX)
|
||||
- UL: Improve docs on low level code (by @Dmitry422)
|
||||
- Archive: Support opening and pinning ProtoPirate files from Archive (#510 by @LeeroysHub)
|
||||
|
||||
### Fixed:
|
||||
- Sub-GHz:
|
||||
- UL: Fixed button mapping for FAAC RC/XT (by @xMasterX)
|
||||
- UL: Possible Sommer timings fix (by @xMasterX)
|
||||
- UL: Various fixes (by @xMasterX)
|
||||
- UL: Various fixes and cleanup (by @xMasterX)
|
||||
- UL: Nice Flor S remove extra uint64 variable (by @xMasterX)
|
||||
- UL: Fix Alutech AT4N false positives (by @xMasterX)
|
||||
- NFC:
|
||||
- Fix sending 32+ byte ISO 15693-3 commands (by @WillyJL)
|
||||
- Fixes to `READ_MULTI` and `GET_BLOCK_SECURITY` commands in ISO 15693-3 emulation (#501 by @WillyJL & aaronjamt)
|
||||
@@ -50,3 +53,4 @@
|
||||
- Sub-GHz:
|
||||
- Removed Starline, ScherKhan and Kia protocols from main Sub-GHz app, they can be decoded with `Apps > Sub-GHz > ProtoPirate` external app
|
||||
- Disabled X10 and Hormann Bisecur protocols due to flash space constraints and very limited usefulness, Momentum now has same protocol list as Unleashed
|
||||
- Desktop: Removed winter holidays anims
|
||||
|
||||
@@ -826,12 +826,17 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
|
||||
subghz_device_cc1101_ext->async_tx.buffer =
|
||||
malloc(SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t));
|
||||
|
||||
// here we do the same things as in /unleashed-firmware/targets/f7/furi_hal/furi_hal_subghz.c
|
||||
// use first DMA to update timer TIM17 durations, but TIM17 have not output chanel
|
||||
// so we use second DMA to transfer data from gpio_tx_buff directly to gpio pin using BSSR.
|
||||
// BSSR allow us tranfer data directly to pin in gpio port.
|
||||
|
||||
//Signal generation with mem-to-mem DMA
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
|
||||
furi_hal_gpio_init(
|
||||
subghz_device_cc1101_ext->g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
||||
|
||||
// Configure DMA update timer
|
||||
// Configure DMA to update timer TIM17 ARR by durations from buffer
|
||||
LL_DMA_SetMemoryAddress(
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t)subghz_device_cc1101_ext->async_tx.buffer);
|
||||
LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t) & (TIM17->ARR));
|
||||
@@ -853,7 +858,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
|
||||
|
||||
furi_hal_bus_enable(FuriHalBusTIM17);
|
||||
|
||||
// Configure TIM
|
||||
// Configure TIM 17
|
||||
// Set the timer resolution to 2 us
|
||||
LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP);
|
||||
LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1);
|
||||
@@ -867,7 +872,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
|
||||
subghz_device_cc1101_ext_async_tx_refill(
|
||||
subghz_device_cc1101_ext->async_tx.buffer, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL);
|
||||
|
||||
// Configure tx gpio dma
|
||||
// Configure DMA to transfer data from gpio_tx_buff directly to gpio pin using BSSR
|
||||
const GpioPin* gpio = subghz_device_cc1101_ext->g0_pin;
|
||||
|
||||
subghz_device_cc1101_ext->async_tx.gpio_tx_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER;
|
||||
|
||||
@@ -80,6 +80,7 @@ typedef enum {
|
||||
SetTypeSomfyTelis,
|
||||
SetTypeKingGatesStylo4k,
|
||||
SetTypeBenincaARC,
|
||||
SetTypeJarolift,
|
||||
SetTypeANMotorsAT4,
|
||||
SetTypeAlutechAT4N,
|
||||
SetTypePhoenix_V2_433,
|
||||
|
||||
@@ -541,6 +541,15 @@ void subghz_scene_set_type_fill_generation_infos(GenInfo* infos_dest, SetType ty
|
||||
.beninca_arc.btn = 0x02,
|
||||
.beninca_arc.cnt = 0x03};
|
||||
break;
|
||||
case SetTypeJarolift:
|
||||
gen_info = (GenInfo){
|
||||
.type = GenJarolift,
|
||||
.mod = "AM650",
|
||||
.freq = 433920000,
|
||||
.jarolift.serial = key & 0xFFFFF00,
|
||||
.jarolift.btn = 0x02,
|
||||
.jarolift.cnt = 0x03};
|
||||
break;
|
||||
case SetTypeMotorline433:
|
||||
gen_info = (GenInfo){
|
||||
.type = GenKeeloq,
|
||||
|
||||
@@ -12,6 +12,7 @@ typedef enum {
|
||||
GenSomfyTelis,
|
||||
GenKingGatesStylo4k,
|
||||
GenBenincaARC,
|
||||
GenJarolift,
|
||||
GenNiceFlorS,
|
||||
GenSecPlus1,
|
||||
GenSecPlus2,
|
||||
@@ -73,6 +74,11 @@ typedef struct {
|
||||
uint8_t btn;
|
||||
uint32_t cnt;
|
||||
} beninca_arc;
|
||||
struct {
|
||||
uint32_t serial;
|
||||
uint8_t btn;
|
||||
uint16_t cnt;
|
||||
} jarolift;
|
||||
struct {
|
||||
uint32_t serial;
|
||||
uint8_t btn;
|
||||
|
||||
@@ -395,6 +395,36 @@ bool subghz_txrx_gen_beninca_arc_protocol(
|
||||
return res;
|
||||
}
|
||||
|
||||
bool subghz_txrx_gen_jarolift_protocol(
|
||||
void* context,
|
||||
const char* preset_name,
|
||||
uint32_t frequency,
|
||||
uint32_t serial,
|
||||
uint8_t btn,
|
||||
uint16_t cnt) {
|
||||
SubGhzTxRx* txrx = context;
|
||||
|
||||
bool res = false;
|
||||
|
||||
txrx->transmitter =
|
||||
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_JAROLIFT_NAME);
|
||||
subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0);
|
||||
|
||||
if(txrx->transmitter && subghz_protocol_jarolift_create_data(
|
||||
subghz_transmitter_get_protocol_instance(txrx->transmitter),
|
||||
txrx->fff_data,
|
||||
serial,
|
||||
btn,
|
||||
cnt,
|
||||
txrx->preset)) {
|
||||
res = true;
|
||||
}
|
||||
|
||||
subghz_transmitter_free(txrx->transmitter);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool subghz_txrx_gen_secplus_v2_protocol(
|
||||
SubGhzTxRx* instance,
|
||||
const char* name_preset,
|
||||
|
||||
@@ -124,6 +124,14 @@ bool subghz_txrx_gen_beninca_arc_protocol(
|
||||
uint8_t btn,
|
||||
uint32_t cnt);
|
||||
|
||||
bool subghz_txrx_gen_jarolift_protocol(
|
||||
void* context,
|
||||
const char* preset_name,
|
||||
uint32_t frequency,
|
||||
uint32_t serial,
|
||||
uint8_t btn,
|
||||
uint16_t cnt);
|
||||
|
||||
bool subghz_txrx_gen_came_atomo_protocol(
|
||||
void* context,
|
||||
const char* preset_name,
|
||||
|
||||
@@ -1,71 +1,72 @@
|
||||
Filetype: Flipper SubGhz Keystore File
|
||||
Version: 0
|
||||
Encryption: 1
|
||||
IV: 4F 77 4F 20 66 75 72 72 79 20 49 56 20 55 77 55
|
||||
1D0560740B25F58EE0E85BF949139971E5AA08C5499CC74B11992D124C281012
|
||||
C05E2D2C715D8E24C518EF2841DA02173C05DD5BA5310EE85D09709500DB1726
|
||||
9EA5721836369FF918859077F50E33100F7AC53E8E8F31E25296579F875359DF
|
||||
D2A8AD1B65BC66B459525124CDC5011C79D98F542702FC69EABD64F908C0D80D
|
||||
2FA5F078BEB59851D42BC7E4E331AE3A8C384892DF003238CDA82450A6CD02AC
|
||||
E54ED5F49A093BC938521195C86FECF35FB6EC463C54C6E1609592DC5FA03CCB5E1EDA362FC9AB008C85E66B60147EBA
|
||||
048F4A28B18496487D65A924F4E37766C3563F41090D442DE61D7A5DD82F5FF1
|
||||
DA876A11401727E5102B578F87CCF9596AB9D9925FC90CDF99C9DEC7261B2C8C
|
||||
03D3842335D69A3AA42452274130B3FAAEE6087CB8D783B0E770062C034BB302
|
||||
7F50401E9FFAF10D1F61067C2E830EBBEC7C8B3B20F5C0AC2E10E68912BF2C82
|
||||
160BC0CA2FF01E076830F29846C1F6CCBAC7857F2043E8163449048BA8C99AA8
|
||||
09357F089CB148DDC578E0F11EC10659EF68A57440700F584922CB9842E2BF08AC977CCAA11355E89FA5C18113349F5E
|
||||
910D166F40F264225BD4C8EB16C5CC6374F8F8E1202D5BF28FA2E8BA38E420A36E67611E6D151051F7C74843E4A72BBC
|
||||
D9ACEBC528D7CA74B894A0378095E03C9BDBBE13DDA3FCD6D60CD3CAC49746B8
|
||||
90F94FD262E1859B7E5C08E7ED5B16CDB56D0E930034E315CD011DE3759150DA
|
||||
6620E176FC61DF250EF2BBC2AB27E0DA45A6E1E27F4E94405EE01C36E892EFBF
|
||||
7D6A062453236E4C353F19B875D079157D016B223B7D429C8F5BEA9D0F703EED
|
||||
20631589CB541B32C23CA7EA93B12E2016B5A90A2C9CAA6F5849C0B67158EA635858F26A86282C124AEA3FD31B7FD365
|
||||
E6CF167CEA0639D1504E0BFC8BAAA7FC7FA36A2286CBBE1312803422018A9F00
|
||||
0EB81E23FF37366BA4890CBD46BC8AF5A2CD56E9802B8DF5CDDD5114F677CDF6
|
||||
62195292F6F920DAF91F812FC3B94E8539C157D35D3BC94F2FB7A8481406C655AC0F112C4E10AC36892D43D95827BC1D
|
||||
65FB9BEBDB9BE975168D47B02CA8A2E0ADE2CD1949E90B06689B0475395663BD5AF3C8FEC42C4138CBBB8956AC55B475
|
||||
EF0A6961C754FCDBAE0222099DD8AA38DD6A92BCD53A576E105BC5BBD23400B7
|
||||
A608752C8602A5BD538441DE046DD7AE011FBA87210B57372BCBB471ECC2B720
|
||||
222C83DDC445F72152E563CD068851389364C1D83C9F7D6353325EFD553560B1
|
||||
96977544F2F821408C1A88FADB9B1E12D9CA97638A622190F83BC640508B6029
|
||||
B596A98BDDA5BD2FF1F812BE67FD00456D4D313E9497147E2439B51972B6B752
|
||||
FC276CAC90756F397C3BC616631CE8B9257E6C25D0DC15C5ED1CEB439ACF04D9
|
||||
383DD624B98E650E5B4BA28990B4D1912B785C689E6B6A05D77B47B6501CD98F
|
||||
410814DC8B38DD6EF781B55CA02730092F252082A77400AD90F22BF45A41C849
|
||||
8DA240E13E8B512B50FF4504A61037D0A3920B00523D51EEF9996CC3907C175E
|
||||
E655B7C31E346154C5EF7C59E3A710A2A2F145E7403E4ADB388B3A27D6FF59DE
|
||||
E2FB7F96EA16B20589995E95D0959B4ECC1EDDF86E347EB85FD29D0D5933A2A1
|
||||
00D910F2B050900735A8446220FF7321813252862A69C05A7A534118E50E61DB
|
||||
BA1B9E7E26E04542183F085060421553CDD3FD9034AAAFCB7EE980A68B98087E
|
||||
216EBA33FCE4B834BF64621E557923D8AE41F5895266B7BBDFCA6EAF985F036E
|
||||
2E9075A45ED6D86C172C9ADAAF5E991DA8DA9CBF2F24D746D22A331E236FBA4A
|
||||
04E4B185C150AF45A67E15D68282C7558B13BFFB05BFCB71BCFD2B92DE5D9701
|
||||
1FDC4D759EA89681F76A8F7D336118FE6801EFD10D73925C2749775D9DFED282
|
||||
FFB32167FBF860418AAABF29B0D4FEF57BB07454ECF4BD2CF175D44E84C04CED
|
||||
7C6E419658872D298F2E7B02568B9ED870FDFFE5082ED0BBE689FD04EFFFE7E7
|
||||
ADAB0F3108398C75ECC6D2E572960B5685C336DDF3D6F5B9C12D069F27BA15A8
|
||||
DAC772C1A81181738CDB8C0E89C2E5B7A57E2DA65CA15232DE96A3C4A599A0E9
|
||||
7F6204274D90E88B3F5D5AC86EEEE76C27C0D083E79ADA7BCF7D060FE6F05A3E
|
||||
5BAB4CCB593418CD8965C09C0925EDB78BB4C8A10892F264DF12F50E532F006E
|
||||
7C67525C921ABAEC4BFAA376162A7B2B2827AE4C9840DC37F067FE3B72BE7304B6EEB5FB1AD17CFF5F079EFECC04AD56
|
||||
94FF6DD4CE63381778E86E61423EDDDD9CC71C3462D66F1AD9A0AD5D378AECE2
|
||||
E9CA5BA5C6D6101EA3A51F28E48D49789D60273A9F70D56020D003265517AFA3
|
||||
EBF55649D226E9FDAAB57C2E1D75E3FD3A8D216488E97D00E932B3542E731D20
|
||||
2B576C3616DDAFEE23A8ECE24BBD89590C8C2D551F14D8EFA4DBB30216F89C31
|
||||
EE8D3CF3C503DE4FF368F23585F1A7017FF66A910696A6760AFD2B9822911960
|
||||
A32910F791C5EE9998DCE5371B3252427315C9D11AD506CE65760611D873C81D
|
||||
740646D11A32C65A8549B3AEA8A499866C35D926B2BA21ED73934AA37ADCC1E6
|
||||
0E66EF4CA934A5D1ACED28CBEEAA3AF7941E10918DA79379090B6339F11E267E
|
||||
D79D8666FD947B0D0D504FF10B048B147CB000AD8CDC1F0DEB395FB72B789963
|
||||
2F7BA07F18F4A91AEDC08867E9CC4B8689B0831A7CE0E0AEF3D92C0CA9BBC698
|
||||
1AB4351CFF02CC600C972CE87F69B23F8ECCC32A90BD5F429F8017A80306F23D
|
||||
ED2AD447E7DF7A34D78A313395FA1C3AF63CE02B77A5B08CE19493CFA1173232
|
||||
C8C8DEAF10AA3994EE7D6DC8E1EB403042627E0F3524409F40C03A7C0C106A80
|
||||
5778B4A3E7BE82C07BA6A311A87649F3C7AE5107A89571E14AEF05B9E285C87A
|
||||
30080347DB3B580B18E8EAC66E1B7227F791773F0342EE0DF8267EC993EC3F24
|
||||
2DB3B2A17C165B5C6A1D4944A5B595016588F028DD4F763C4ED6B7FE7849E918
|
||||
C1F0CF343B77F31D9A2E810821393EE9D1E0D4B54A87B2DD8CCFBB16FBD77A75B50A0E78D1E8A86310572443731B9DB5
|
||||
88EF373C37AADAE1155E7DBDBB7E0B048E3BFEFB412DC49EA8A48E1544B6DC87
|
||||
98694781F3EE698ABA8D2CDFFB1CA0425AA17BFE904FC7812E65A78DF1CA06C2
|
||||
6BBBCA6672311E1A3BF7001B3222890C8A68A8B7D87DE91624BB9D1FEC0E2728
|
||||
4550A44B654085C3A3620B5D4D2C6A7F962275BC5926B9B7E3A706F128BF6D6C967E2BF2ACD4DD000BDC8BDE69684F6F
|
||||
IV: 6E 6F 74 69 63 65 73 20 62 75 6C 67 65 4F 77 4F
|
||||
212F687B2D38E6E9066E95894E455A6AD3A8861CDDAFD09DBC2557506676332D
|
||||
2CFF25E9743E4588820D24998B5047E8019C6E200922BCB66830C7F722822A79
|
||||
74AA0EF345C27F583042C4EDDBB83D5446387D4E5B31DFD3F7B9D09F0662A0AA95BEB40BF37678954CAE0200B2898D22
|
||||
6998443F71D17938425CD231B8500E769976601315D79D673AA37E4F9BDCE50B
|
||||
3335691566FEDDDE5828BE0A5BBBD9AC013987A1134E68020D3F0F477E09BC71
|
||||
1B3A3CBB3D56783220BEAECEA15FFF5CD92AF44F63547F6F84F4533D2B3D820B
|
||||
A1ECFE74E714D0E1514D0C18903598E7FB7E7AF5C0165DEDE85DFAE05B26C0EC
|
||||
BA3F2EFBE7CB6671206EA90DA903FF48CCABEC9F393D55B9DB3B7E207A48C059
|
||||
CA91805C8ADF02501B41D6BF0C69D7C3DD6E218D4B4EB6BED2FDE1367256E544
|
||||
5465E78D877F2594AF40115723C8AC71D09F60ACCC8121CD3B6BA271BEA43B5C
|
||||
BB1D3DE0A048694FC86CA8E79BB7BFBB1EF91515C44E917FD5017676EE5C4B13
|
||||
48C08D8B2B42D025D2557CC650EDA3C5CC301CD71169CFE0044C07A95224109B
|
||||
3DAE6C5B94C237FF10CF82FAA58517DB4DD4E4D82FD81CFAAA4836C9B8460CE1
|
||||
645F8F5D213889BAB0F437497856A0CF402E3D4A3679258BB0BF2B768D1F1714
|
||||
AFC3C462698C795B1A407F27F499CD1757931BD676BA43E4B41E8EF2672EC4AE
|
||||
5A19F0D1CD87C40883D7BE51377CDAD94C977B4F6CFCCECED91D56867C9EC211
|
||||
716645BD4F5B18002417A92D6A2BD29D18087F7ADB549A90A2661EB4163EF190
|
||||
54B83F7F7F50AD4C3DC3498822240AEB7D9A43728704F14691A39C79FAC9B6A3
|
||||
FFDDCEFAFF3ADA3616B388684B1AD4987B83E459BA5037E377FE17CC7EDAA430
|
||||
9CC98590A371E580B164A5F1369945A6DB653797331EC898755E84BE93EDF3EF
|
||||
63697AD15064194A3986CC1F3111A09E3D86AC8D370A8EC4D22EDDA4B9661B63
|
||||
F7CE4FA63EA9D388AE4AB6A468768AE91E2E3CF6F1D9A5EA17845466A6801A8C
|
||||
38B2DE32CF36D68842CB31FD97394892B76FB4E81FCFB33164676BAB354939DE
|
||||
93192FA1D7E347AF9FC98EE49A8B02869527511D0B263FD3B08CCFE645A39F51
|
||||
3D5F832CF75D94B58B078B4EE0DFC1D987795CD49959517F391F9E9F09CA187C
|
||||
6CBCCCE0F8E6A833D5CA18E09E821A7F93B9FD7D912632E277B1721985F4B701
|
||||
5896050E9F4950CD7061ED4DD3BA9FC6013CA52F5C1B0493110FA3934116AC66
|
||||
F0D3FF283FBD7CFBFE697DBE752EDD5A1F124DCCAE3B629A146E0E85A7ED4E06
|
||||
6B6C7C365A5CABA2F1023ED1F97D182F0B9D575C64393272E19B8B809DF3C329
|
||||
1AF30761D85AE1C6DD4D78D4ECE79983C7F58ECE859709570262811CFCA8C97F
|
||||
FC86201D96F4AE36C63A1C00DA34AC14BFDE317383D19A534362E6149E860366
|
||||
54F55F34A27E1D690F56269D29C795105C8407A4E1A9ED431588F559948C115A
|
||||
4DD62ECD2FE8CBB783E3D7F0B1D95496D585405DE5AEB07C8A4E053B3AAAD808
|
||||
EDB356AFA869EFB987F099239449D6B9F1469EA6D8C9F0A6B4171F685E2853A1
|
||||
03C058A2C0DB83179E520F035BBAAB01673EFE4FDE717A0F5D1AB6B81BC9D033
|
||||
D2F33C08136AB161EED6121E721F8C479CED5F26A1B7DEEDEA8580314C232C5E
|
||||
51CB3275D6D7250CD88A446242590C3DFD36DF83F5E34379DE73601511CD24B9
|
||||
ED4EC928AC505CBEFA6ACB2901C8E2221FC5073624B0B78F8365DD0442EFBA10
|
||||
76F959BBF8A4EC4AC22F41F06719BCBA58F070CB65B282BFC2C99F6CC02E30DB
|
||||
0A44A7C5D4ECF2F08CBDF3FE947D45C6AC586D4558DBFB36719927F58EBB525B
|
||||
F096777DDC5BF671CBF1A9682EBEE8308AA1002F6CB6899D575A30CFACB30125C8378864C77922360ADD0AC486EFF7F4
|
||||
372863D5B6F6D7A671AB734A99403AF230DEBBBA435AB8F236B179960FAFDFC6
|
||||
6CC31C5E86CF6851D92FA973253B3B1FC9023B150980A216A63720CD74592EB7
|
||||
6643B2CA94415FE4A4E25A3086B8370172C53283360A7BD54B322BD889A5A831
|
||||
03209037BD7E96A16C69A4F0B6FEB3F2ABA1408353BE09C53485CB7C2362A490
|
||||
BE4619EC34F7FB8DFE53A8ABFDE6A831895B88D0AB1A9B4861BC7EC7F1121611
|
||||
41223F7AD8B0F28D08C1EEC2B96324F337F6428759032CAE58A04E8511BC4CBCE497EE1502F18BED5B5038E719F4F085
|
||||
1533D9B78F16803DFD8AC0C9C85ECEB6BABE9ADF83BF0B6692857BAA03843444064FCDBC89464D9E002AAFF53C65098B
|
||||
466CC36F82D1AF9BA0704789B2F8B249E79D4964E7E5CB74917760E7D30AB7FA
|
||||
E9673C0CF35137C179132DDCA57869E285FE6014BB32C5DD78E7549ED0076906
|
||||
A511A9999C777750FA348772A9E2881A75DEC94ED833AC282037B3E10913B150
|
||||
F20652B2CA0E0ADD34331D2462CD5AFACC4E01F24EF17C97CFF57089039AD7D8
|
||||
AFCB6518894626B9E8AFC7E7D9D0430D1D820969CE79B61B91E63D08D4995308D8403705AE4E25AB0F254D47FB03A1A2
|
||||
C43987548689A1DD9A65A3BE76F97A8470263ACAC0696B5882383AE97893B5D6
|
||||
7FB47AC9A16094C38D436F9932041A40F6B4644A633361B47C6F6E4A8F2E7C26
|
||||
BDD48C4689912872055999ECADCF93D152ACDEC34C6318F2FBBBA1A34C8CC166FCBA31AED11F95C973B21A646828CEEA
|
||||
1582E265DF46C8A9A019AF338104C267873FD3C2C7AF290263FEF921CC9926E76F37FA31881307C675CF37F8A5A236D7
|
||||
790D8AF6D9F5B634F953F5751378BA5412425B950C696549902EB6A9383630D0
|
||||
6F44FF0DB55651218C81B41153C9D77B1911C5BFA70650FB9326DD6B8A1479EE
|
||||
4B0891C1C24E004AB2869A858941C47346EF0789DFAEA1CD1B0E008A73AF2F7E
|
||||
7E9F990652FD6632612866B6ECA726EAE2112234EBCA59D0C1BF220B94E1F472
|
||||
9C08E9DAE977DD30E61E6634F51BFD654330C34E9FB3AA2E8856B428141D7164
|
||||
7C0E756C593FFBBE2609F63D142A0D53F99772EB0722616DFC7B203BA70AA5AE
|
||||
52C03D8984496DFF95503D843CA1980A6CA46AAE3390C6D4D38E277A0937429C185C118B98B6EBE0711F10F47F8D8F3F
|
||||
DE8A5BFD2AB351BCAD1D7817737946EF2445E3C974C9E11BF7AD058463F0E437
|
||||
D09ABB320F59A75C4B2EE8B52E45D52C46226DD8BC8339F53229578733928F1F
|
||||
C2E6F135E638C83363097EB79ED9A58E94A8E5F626E27083D1363E8BC61B55A4
|
||||
F06CC55446D0FCCCE5AD007949AE3FCA9C6FCB3C0CA1B5DE1BA65544B55326F1CF726E1F1E5CA90CA2B986930C9B9D83
|
||||
|
||||
@@ -44,6 +44,10 @@ void subghz_scene_set_button_on_enter(void* context) {
|
||||
byte_ptr = &subghz->gen_info->beninca_arc.btn;
|
||||
byte_count = sizeof(subghz->gen_info->beninca_arc.btn);
|
||||
break;
|
||||
case GenJarolift:
|
||||
byte_ptr = &subghz->gen_info->jarolift.btn;
|
||||
byte_count = sizeof(subghz->gen_info->jarolift.btn);
|
||||
break;
|
||||
case GenNiceFlorS:
|
||||
byte_ptr = &subghz->gen_info->nice_flor_s.btn;
|
||||
byte_count = sizeof(subghz->gen_info->nice_flor_s.btn);
|
||||
@@ -92,6 +96,7 @@ bool subghz_scene_set_button_on_event(void* context, SceneManagerEvent event) {
|
||||
case GenSomfyTelis:
|
||||
case GenKingGatesStylo4k:
|
||||
case GenBenincaARC:
|
||||
case GenJarolift:
|
||||
case GenNiceFlorS:
|
||||
case GenSecPlus2:
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetCounter);
|
||||
|
||||
@@ -50,6 +50,10 @@ void subghz_scene_set_counter_on_enter(void* context) {
|
||||
byte_ptr = (uint8_t*)&subghz->gen_info->beninca_arc.cnt;
|
||||
byte_count = sizeof(subghz->gen_info->beninca_arc.cnt);
|
||||
break;
|
||||
case GenJarolift:
|
||||
byte_ptr = (uint8_t*)&subghz->gen_info->jarolift.cnt;
|
||||
byte_count = sizeof(subghz->gen_info->jarolift.cnt);
|
||||
break;
|
||||
case GenNiceFlorS:
|
||||
byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.cnt;
|
||||
byte_count = sizeof(subghz->gen_info->nice_flor_s.cnt);
|
||||
@@ -128,6 +132,9 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) {
|
||||
case GenBenincaARC:
|
||||
subghz->gen_info->beninca_arc.cnt = __bswap32(subghz->gen_info->beninca_arc.cnt);
|
||||
break;
|
||||
case GenJarolift:
|
||||
subghz->gen_info->jarolift.cnt = __bswap16(subghz->gen_info->jarolift.cnt);
|
||||
break;
|
||||
case GenNiceFlorS:
|
||||
subghz->gen_info->nice_flor_s.cnt = __bswap16(subghz->gen_info->nice_flor_s.cnt);
|
||||
break;
|
||||
@@ -204,6 +211,15 @@ bool subghz_scene_set_counter_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz->gen_info->beninca_arc.btn,
|
||||
subghz->gen_info->beninca_arc.cnt);
|
||||
break;
|
||||
case GenJarolift:
|
||||
generated_protocol = subghz_txrx_gen_jarolift_protocol(
|
||||
subghz->txrx,
|
||||
subghz->gen_info->mod,
|
||||
subghz->gen_info->freq,
|
||||
subghz->gen_info->jarolift.serial,
|
||||
subghz->gen_info->jarolift.btn,
|
||||
subghz->gen_info->jarolift.cnt);
|
||||
break;
|
||||
case GenNiceFlorS:
|
||||
generated_protocol = subghz_txrx_gen_nice_flor_s_protocol(
|
||||
subghz->txrx,
|
||||
|
||||
@@ -32,6 +32,7 @@ void subghz_scene_set_seed_on_enter(void* context) {
|
||||
case GenSomfyTelis:
|
||||
case GenKingGatesStylo4k:
|
||||
case GenBenincaARC:
|
||||
case GenJarolift:
|
||||
case GenNiceFlorS:
|
||||
case GenSecPlus2:
|
||||
case GenPhoenixV2:
|
||||
@@ -93,6 +94,7 @@ bool subghz_scene_set_seed_on_event(void* context, SceneManagerEvent event) {
|
||||
case GenSomfyTelis:
|
||||
case GenKingGatesStylo4k:
|
||||
case GenBenincaARC:
|
||||
case GenJarolift:
|
||||
case GenNiceFlorS:
|
||||
case GenSecPlus2:
|
||||
case GenPhoenixV2:
|
||||
|
||||
@@ -50,6 +50,10 @@ void subghz_scene_set_serial_on_enter(void* context) {
|
||||
byte_ptr = (uint8_t*)&subghz->gen_info->beninca_arc.serial;
|
||||
byte_count = sizeof(subghz->gen_info->beninca_arc.serial);
|
||||
break;
|
||||
case GenJarolift:
|
||||
byte_ptr = (uint8_t*)&subghz->gen_info->jarolift.serial;
|
||||
byte_count = sizeof(subghz->gen_info->jarolift.serial);
|
||||
break;
|
||||
case GenNiceFlorS:
|
||||
byte_ptr = (uint8_t*)&subghz->gen_info->nice_flor_s.serial;
|
||||
byte_count = sizeof(subghz->gen_info->nice_flor_s.serial);
|
||||
@@ -122,6 +126,9 @@ bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz->gen_info->kinggates_stylo_4k.serial =
|
||||
__bswap32(subghz->gen_info->kinggates_stylo_4k.serial);
|
||||
break;
|
||||
case GenJarolift:
|
||||
subghz->gen_info->jarolift.serial = __bswap32(subghz->gen_info->jarolift.serial);
|
||||
break;
|
||||
case GenBenincaARC:
|
||||
subghz->gen_info->beninca_arc.serial =
|
||||
__bswap32(subghz->gen_info->beninca_arc.serial);
|
||||
@@ -154,6 +161,7 @@ bool subghz_scene_set_serial_on_event(void* context, SceneManagerEvent event) {
|
||||
case GenSomfyTelis:
|
||||
case GenKingGatesStylo4k:
|
||||
case GenBenincaARC:
|
||||
case GenJarolift:
|
||||
case GenNiceFlorS:
|
||||
case GenSecPlus2:
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetButton);
|
||||
|
||||
@@ -22,6 +22,7 @@ static const char* submenu_names[SetTypeMAX] = {
|
||||
[SetTypePhoenix_V2_433] = "V2 Phoenix 433MHz",
|
||||
[SetTypeKingGatesStylo4k] = "KingGates Stylo4k 433M.",
|
||||
[SetTypeBenincaARC] = "Beninca ARC 433MHz",
|
||||
[SetTypeJarolift] = "Jarolift 433MHz",
|
||||
[SetTypeHCS101_433_92] = "KL: HCS101 433MHz",
|
||||
[SetTypeDoorHan_315_00] = "KL: DoorHan 315MHz",
|
||||
[SetTypeDoorHan_433_92] = "KL: DoorHan 433MHz",
|
||||
@@ -207,6 +208,15 @@ bool subghz_scene_set_type_generate_protocol_from_infos(SubGhz* subghz) {
|
||||
gen_info.beninca_arc.btn,
|
||||
gen_info.beninca_arc.cnt);
|
||||
break;
|
||||
case GenJarolift:
|
||||
generated_protocol = subghz_txrx_gen_jarolift_protocol(
|
||||
subghz->txrx,
|
||||
gen_info.mod,
|
||||
gen_info.freq,
|
||||
gen_info.jarolift.serial,
|
||||
gen_info.jarolift.btn,
|
||||
gen_info.jarolift.cnt);
|
||||
break;
|
||||
case GenNiceFlorS:
|
||||
generated_protocol = subghz_txrx_gen_nice_flor_s_protocol(
|
||||
subghz->txrx,
|
||||
@@ -288,6 +298,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
||||
case GenSomfyTelis: // Serial (u32), Button (u8), Counter (u16)
|
||||
case GenKingGatesStylo4k: // Serial (u32), Button (u8), Counter (u16)
|
||||
case GenBenincaARC: // Serial (u32), Button (u8), Counter (u32)
|
||||
case GenJarolift: // Serial (u32), Button (u4), Counter (u16)
|
||||
case GenNiceFlorS: // Serial (u32), Button (u8), Counter (u16)
|
||||
case GenSecPlus2: // Serial (u32), Button (u8), Counter (u32)
|
||||
case GenPhoenixV2: // Serial (u32), Counter (u16)
|
||||
|
||||
|
Before Width: | Height: | Size: 858 B |
|
Before Width: | Height: | Size: 855 B |
|
Before Width: | Height: | Size: 872 B |
|
Before Width: | Height: | Size: 861 B |
|
Before Width: | Height: | Size: 853 B |
|
Before Width: | Height: | Size: 851 B |
|
Before Width: | Height: | Size: 852 B |
|
Before Width: | Height: | Size: 856 B |
|
Before Width: | Height: | Size: 850 B |
|
Before Width: | Height: | Size: 851 B |
|
Before Width: | Height: | Size: 860 B |
|
Before Width: | Height: | Size: 857 B |
|
Before Width: | Height: | Size: 863 B |
@@ -1,23 +0,0 @@
|
||||
Filetype: Flipper Animation
|
||||
Version: 1
|
||||
|
||||
Width: 128
|
||||
Height: 64
|
||||
Passive frames: 10
|
||||
Active frames: 18
|
||||
Frames order: 0 1 2 1 0 1 2 1 0 1 2 3 4 5 6 5 4 7 2 8 9 10 11 10 9 10 11 12
|
||||
Active cycles: 1
|
||||
Frame rate: 2
|
||||
Duration: 3600
|
||||
Active cooldown: 7
|
||||
|
||||
Bubble slots: 1
|
||||
|
||||
Slot: 0
|
||||
X: 11
|
||||
Y: 19
|
||||
Text: HAPPY\nHOLIDAYS!
|
||||
AlignH: Right
|
||||
AlignV: Center
|
||||
StartFrame: 22
|
||||
EndFrame: 27
|
||||
|
Before Width: | Height: | Size: 820 B |
|
Before Width: | Height: | Size: 881 B |
|
Before Width: | Height: | Size: 788 B |
|
Before Width: | Height: | Size: 816 B |
|
Before Width: | Height: | Size: 864 B |
|
Before Width: | Height: | Size: 798 B |
|
Before Width: | Height: | Size: 813 B |
|
Before Width: | Height: | Size: 879 B |
|
Before Width: | Height: | Size: 855 B |
|
Before Width: | Height: | Size: 772 B |
|
Before Width: | Height: | Size: 817 B |
|
Before Width: | Height: | Size: 867 B |
|
Before Width: | Height: | Size: 866 B |
|
Before Width: | Height: | Size: 809 B |
|
Before Width: | Height: | Size: 795 B |
|
Before Width: | Height: | Size: 870 B |
|
Before Width: | Height: | Size: 852 B |
|
Before Width: | Height: | Size: 805 B |
|
Before Width: | Height: | Size: 858 B |
|
Before Width: | Height: | Size: 830 B |
|
Before Width: | Height: | Size: 828 B |
|
Before Width: | Height: | Size: 585 B |
|
Before Width: | Height: | Size: 431 B |
|
Before Width: | Height: | Size: 812 B |
|
Before Width: | Height: | Size: 281 B |
|
Before Width: | Height: | Size: 270 B |
|
Before Width: | Height: | Size: 236 B |
|
Before Width: | Height: | Size: 485 B |
|
Before Width: | Height: | Size: 771 B |
|
Before Width: | Height: | Size: 887 B |
|
Before Width: | Height: | Size: 809 B |
|
Before Width: | Height: | Size: 890 B |
|
Before Width: | Height: | Size: 819 B |
|
Before Width: | Height: | Size: 799 B |
|
Before Width: | Height: | Size: 817 B |
|
Before Width: | Height: | Size: 875 B |
|
Before Width: | Height: | Size: 823 B |
@@ -1,23 +0,0 @@
|
||||
Filetype: Flipper Animation
|
||||
Version: 1
|
||||
|
||||
Width: 128
|
||||
Height: 64
|
||||
Passive frames: 18
|
||||
Active frames: 19
|
||||
Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
|
||||
Active cycles: 1
|
||||
Frame rate: 2
|
||||
Duration: 3600
|
||||
Active cooldown: 7
|
||||
|
||||
Bubble slots: 1
|
||||
|
||||
Slot: 0
|
||||
X: 21
|
||||
Y: 25
|
||||
Text: AAAAaAAAAHHh!!
|
||||
AlignH: Right
|
||||
AlignV: Bottom
|
||||
StartFrame: 30
|
||||
EndFrame: 32
|
||||
14
assets/dolphin/external/manifest.txt
vendored
@@ -245,17 +245,3 @@ Max butthurt: 13
|
||||
Min level: 9
|
||||
Max level: 30
|
||||
Weight: 4
|
||||
|
||||
Name: L1_Happy_holidays_128x64
|
||||
Min butthurt: 0
|
||||
Max butthurt: 14
|
||||
Min level: 1
|
||||
Max level: 30
|
||||
Weight: 3
|
||||
|
||||
Name: L1_Sleigh_ride_128x64
|
||||
Min butthurt: 0
|
||||
Max butthurt: 14
|
||||
Min level: 1
|
||||
Max level: 30
|
||||
Weight: 4
|
||||
|
||||
@@ -68,9 +68,10 @@ That list is only for default SubGHz app, apps like *Weather Station* have their
|
||||
- Legrand `AM650` (18 bits, Static) - Doorbells
|
||||
- Somfy Telis `433.92MHz` `AM650` (56 bits, Dynamic)
|
||||
- Feron `433.92MHz` `AM650` (32 bits, Static) - RGB LED remotes, other.
|
||||
- Honeywell `AM650` (64 bits, Dynamic) - Alarm, Sensor
|
||||
- Honeywell WDB `AM650` (48 bits, Dynamic) - Doorbell
|
||||
- Honeywell `AM650` (64 bits, Static) - Alarm, Sensor
|
||||
- Honeywell WDB `AM650` (48 bits, Static) - Doorbell
|
||||
- Magellan `433.92MHz` `AM650` (32 bits, Static) - Sensor, alarm
|
||||
- Jarolift `433.92MHz` `AM650` (72 bits, Dynamic, KeeLoq based) - Automatic roller shutters
|
||||
|
||||
### Alarms
|
||||
- Hollarm `433.92MHz` `AM650` (42 bits, Static) - Bike alarms
|
||||
|
||||
@@ -25,7 +25,6 @@ struct SubGhzProtocolDecoderAlutech_at_4n {
|
||||
SubGhzBlockDecoder decoder;
|
||||
SubGhzBlockGeneric generic;
|
||||
|
||||
uint64_t data;
|
||||
uint32_t crc;
|
||||
uint16_t header_count;
|
||||
|
||||
@@ -580,13 +579,12 @@ void subghz_protocol_decoder_alutech_at_4n_feed(void* context, bool level, uint3
|
||||
instance->decoder.parser_step = Alutech_at_4nDecoderStepReset;
|
||||
break;
|
||||
}
|
||||
if((instance->header_count > 2) &&
|
||||
if((instance->header_count > 9) &&
|
||||
(DURATION_DIFF(duration, subghz_protocol_alutech_at_4n_const.te_short * 10) <
|
||||
subghz_protocol_alutech_at_4n_const.te_delta * 10)) {
|
||||
// Found header
|
||||
instance->decoder.parser_step = Alutech_at_4nDecoderStepSaveDuration;
|
||||
instance->decoder.decode_data = 0;
|
||||
instance->data = 0;
|
||||
instance->decoder.decode_count_bit = 0;
|
||||
} else {
|
||||
instance->decoder.parser_step = Alutech_at_4nDecoderStepReset;
|
||||
@@ -619,8 +617,8 @@ void subghz_protocol_decoder_alutech_at_4n_feed(void* context, bool level, uint3
|
||||
instance->decoder.parser_step = Alutech_at_4nDecoderStepReset;
|
||||
if(instance->decoder.decode_count_bit ==
|
||||
subghz_protocol_alutech_at_4n_const.min_count_bit_for_found) {
|
||||
if(instance->generic.data != instance->data) {
|
||||
instance->generic.data = instance->data;
|
||||
if(instance->generic.data != instance->generic.data_2) {
|
||||
instance->generic.data = instance->generic.data_2;
|
||||
|
||||
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
|
||||
instance->crc = instance->decoder.decode_data;
|
||||
@@ -629,7 +627,6 @@ void subghz_protocol_decoder_alutech_at_4n_feed(void* context, bool level, uint3
|
||||
instance->base.callback(&instance->base, instance->base.context);
|
||||
}
|
||||
instance->decoder.decode_data = 0;
|
||||
instance->data = 0;
|
||||
instance->decoder.decode_count_bit = 0;
|
||||
instance->header_count = 0;
|
||||
}
|
||||
@@ -642,7 +639,7 @@ void subghz_protocol_decoder_alutech_at_4n_feed(void* context, bool level, uint3
|
||||
subghz_protocol_alutech_at_4n_const.te_delta * 2)) {
|
||||
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
|
||||
if(instance->decoder.decode_count_bit == 64) {
|
||||
instance->data = instance->decoder.decode_data;
|
||||
instance->generic.data_2 = instance->decoder.decode_data;
|
||||
instance->decoder.decode_data = 0;
|
||||
}
|
||||
instance->decoder.parser_step = Alutech_at_4nDecoderStepSaveDuration;
|
||||
@@ -654,7 +651,7 @@ void subghz_protocol_decoder_alutech_at_4n_feed(void* context, bool level, uint3
|
||||
subghz_protocol_alutech_at_4n_const.te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
|
||||
if(instance->decoder.decode_count_bit == 64) {
|
||||
instance->data = instance->decoder.decode_data;
|
||||
instance->generic.data_2 = instance->decoder.decode_data;
|
||||
instance->decoder.decode_data = 0;
|
||||
}
|
||||
instance->decoder.parser_step = Alutech_at_4nDecoderStepSaveDuration;
|
||||
|
||||
@@ -98,7 +98,7 @@ static uint8_t subghz_protocol_beninca_arc_get_btn_code(void) {
|
||||
case 0x04:
|
||||
btn = 0x02;
|
||||
break;
|
||||
case 0xFF:
|
||||
case 0x00:
|
||||
btn = 0x04;
|
||||
break;
|
||||
|
||||
@@ -108,12 +108,12 @@ static uint8_t subghz_protocol_beninca_arc_get_btn_code(void) {
|
||||
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
|
||||
switch(original_btn_code) {
|
||||
case 0x02:
|
||||
btn = 0xFF;
|
||||
btn = 0x00;
|
||||
break;
|
||||
case 0x04:
|
||||
btn = 0xFF;
|
||||
btn = 0x00;
|
||||
break;
|
||||
case 0xFF:
|
||||
case 0x00:
|
||||
btn = 0x02;
|
||||
break;
|
||||
|
||||
|
||||
779
lib/subghz/protocols/jarolift.c
Normal file
@@ -0,0 +1,779 @@
|
||||
#include "jarolift.h"
|
||||
#include "core/log.h"
|
||||
#include "keeloq_common.h"
|
||||
|
||||
#include "../subghz_keystore.h"
|
||||
#include "../blocks/const.h"
|
||||
#include "../blocks/decoder.h"
|
||||
#include "../blocks/encoder.h"
|
||||
#include "../blocks/generic.h"
|
||||
#include "../blocks/math.h"
|
||||
|
||||
#include "../blocks/custom_btn_i.h"
|
||||
|
||||
#define TAG "SubGhzProtocolJarolift"
|
||||
|
||||
static const SubGhzBlockConst subghz_protocol_jarolift_const = {
|
||||
.te_short = 400,
|
||||
.te_long = 800,
|
||||
.te_delta = 167,
|
||||
.min_count_bit_for_found = 72,
|
||||
};
|
||||
|
||||
struct SubGhzProtocolDecoderJarolift {
|
||||
SubGhzProtocolDecoderBase base;
|
||||
|
||||
SubGhzBlockDecoder decoder;
|
||||
SubGhzBlockGeneric generic;
|
||||
|
||||
uint16_t header_count;
|
||||
SubGhzKeystore* keystore;
|
||||
};
|
||||
|
||||
struct SubGhzProtocolEncoderJarolift {
|
||||
SubGhzProtocolEncoderBase base;
|
||||
|
||||
SubGhzProtocolBlockEncoder encoder;
|
||||
SubGhzBlockGeneric generic;
|
||||
SubGhzKeystore* keystore;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
JaroliftDecoderStepReset = 0,
|
||||
JaroliftDecoderStepCheckPreambula,
|
||||
JaroliftDecoderStepSaveDuration,
|
||||
JaroliftDecoderStepCheckDuration,
|
||||
} JaroliftDecoderStep;
|
||||
|
||||
const SubGhzProtocolDecoder subghz_protocol_jarolift_decoder = {
|
||||
.alloc = subghz_protocol_decoder_jarolift_alloc,
|
||||
.free = subghz_protocol_decoder_jarolift_free,
|
||||
|
||||
.feed = subghz_protocol_decoder_jarolift_feed,
|
||||
.reset = subghz_protocol_decoder_jarolift_reset,
|
||||
|
||||
.get_hash_data = NULL,
|
||||
.get_hash_data_long = subghz_protocol_decoder_jarolift_get_hash_data,
|
||||
.serialize = subghz_protocol_decoder_jarolift_serialize,
|
||||
.deserialize = subghz_protocol_decoder_jarolift_deserialize,
|
||||
.get_string = subghz_protocol_decoder_jarolift_get_string,
|
||||
.get_string_brief = NULL,
|
||||
};
|
||||
|
||||
const SubGhzProtocolEncoder subghz_protocol_jarolift_encoder = {
|
||||
.alloc = subghz_protocol_encoder_jarolift_alloc,
|
||||
.free = subghz_protocol_encoder_jarolift_free,
|
||||
|
||||
.deserialize = subghz_protocol_encoder_jarolift_deserialize,
|
||||
.stop = subghz_protocol_encoder_jarolift_stop,
|
||||
.yield = subghz_protocol_encoder_jarolift_yield,
|
||||
};
|
||||
|
||||
const SubGhzProtocol subghz_protocol_jarolift = {
|
||||
.name = SUBGHZ_PROTOCOL_JAROLIFT_NAME,
|
||||
.type = SubGhzProtocolTypeDynamic,
|
||||
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
|
||||
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
|
||||
|
||||
.decoder = &subghz_protocol_jarolift_decoder,
|
||||
.encoder = &subghz_protocol_jarolift_encoder,
|
||||
};
|
||||
|
||||
//
|
||||
// Encoder
|
||||
//
|
||||
|
||||
// Pre define function
|
||||
static void subghz_protocol_jarolift_remote_controller(
|
||||
SubGhzBlockGeneric* instance,
|
||||
SubGhzKeystore* keystore);
|
||||
|
||||
/**
|
||||
* Defines the button value for the current btn_id
|
||||
* Basic set | 0x1 | 0x2 | 0x4 | 0x8 |
|
||||
* @return Button code
|
||||
*/
|
||||
static uint8_t subghz_protocol_jarolift_get_btn_code(void);
|
||||
|
||||
void* subghz_protocol_encoder_jarolift_alloc(SubGhzEnvironment* environment) {
|
||||
SubGhzProtocolEncoderJarolift* instance = malloc(sizeof(SubGhzProtocolEncoderJarolift));
|
||||
|
||||
instance->base.protocol = &subghz_protocol_jarolift;
|
||||
instance->generic.protocol_name = instance->base.protocol->name;
|
||||
instance->keystore = subghz_environment_get_keystore(environment);
|
||||
|
||||
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_jarolift_free(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolEncoderJarolift* instance = context;
|
||||
free(instance->encoder.upload);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void subghz_protocol_encoder_jarolift_stop(void* context) {
|
||||
SubGhzProtocolEncoderJarolift* instance = context;
|
||||
instance->encoder.is_running = false;
|
||||
}
|
||||
|
||||
LevelDuration subghz_protocol_encoder_jarolift_yield(void* context) {
|
||||
SubGhzProtocolEncoderJarolift* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Key generation from simple data
|
||||
* @param instance Pointer to a SubGhzProtocolEncoderJarolift* instance
|
||||
* @param btn Button number, 4 bit
|
||||
*/
|
||||
static bool
|
||||
subghz_protocol_jarolift_gen_data(SubGhzProtocolEncoderJarolift* instance, uint8_t btn) {
|
||||
// Save original button for later use
|
||||
if(subghz_custom_btn_get_original() == 0) {
|
||||
subghz_custom_btn_set_original(btn);
|
||||
}
|
||||
|
||||
btn = subghz_protocol_jarolift_get_btn_code();
|
||||
|
||||
// Check for OFEX (overflow experimental) 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()) > 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++;
|
||||
}
|
||||
}
|
||||
|
||||
//(instance->generic.seed >> 8) = 8 bit grouping channel 0-7
|
||||
uint32_t hop_decrypted = (uint64_t)((instance->generic.seed >> 8) & 0xFF) << 24 |
|
||||
((instance->generic.serial & 0xFF) << 16) |
|
||||
(instance->generic.cnt & 0xFFFF);
|
||||
|
||||
uint64_t hop_encrypted = 0;
|
||||
for
|
||||
M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
|
||||
if(manufacture_code->type == KEELOQ_LEARNING_NORMAL_JAROLIFT) {
|
||||
// Normal Learning
|
||||
uint64_t man = subghz_protocol_keeloq_common_normal_learning(
|
||||
instance->generic.serial, manufacture_code->key);
|
||||
hop_encrypted = subghz_protocol_keeloq_common_encrypt(hop_decrypted, man);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we got some issue, return false
|
||||
if(hop_encrypted == 0) {
|
||||
return false;
|
||||
}
|
||||
uint64_t fix = (uint64_t)btn << 60 | ((uint64_t)(instance->generic.serial & 0xFFFFFFF) << 32) |
|
||||
hop_encrypted;
|
||||
|
||||
instance->generic.data = subghz_protocol_blocks_reverse_key(fix, 64);
|
||||
//(instance->generic.seed & 0xFF) = 8 bit for grouping 8-16
|
||||
instance->generic.data_2 =
|
||||
subghz_protocol_blocks_reverse_key((instance->generic.seed & 0xFF), 8);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool subghz_protocol_jarolift_create_data(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
uint32_t serial,
|
||||
uint8_t btn,
|
||||
uint16_t cnt,
|
||||
SubGhzRadioPreset* preset) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolEncoderJarolift* instance = context;
|
||||
instance->generic.serial = (serial & 0xFFFFF00);
|
||||
instance->generic.cnt = cnt;
|
||||
instance->generic.btn = btn;
|
||||
instance->generic.seed = 0x0100;
|
||||
instance->generic.data_count_bit = 72;
|
||||
|
||||
// Encode data
|
||||
|
||||
//(instance->generic.seed >> 8) = 8 bit grouping channel 0-7
|
||||
uint32_t hop_decrypted = (uint64_t)((instance->generic.seed >> 8) & 0xFF) << 24 |
|
||||
((instance->generic.serial & 0xFF) << 16) |
|
||||
(instance->generic.cnt & 0xFFFF);
|
||||
|
||||
uint64_t hop_encrypted = 0;
|
||||
for
|
||||
M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
|
||||
if(manufacture_code->type == KEELOQ_LEARNING_NORMAL_JAROLIFT) {
|
||||
// Normal Learning
|
||||
uint64_t man = subghz_protocol_keeloq_common_normal_learning(
|
||||
instance->generic.serial, manufacture_code->key);
|
||||
hop_encrypted = subghz_protocol_keeloq_common_encrypt(hop_decrypted, man);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t fix = (uint64_t)instance->generic.btn << 60 |
|
||||
((uint64_t)(instance->generic.serial & 0xFFFFFFF) << 32) | hop_encrypted;
|
||||
|
||||
instance->generic.data = subghz_protocol_blocks_reverse_key(fix, 64);
|
||||
//(instance->generic.seed & 0xFF) = 8 bit for grouping 8-16
|
||||
instance->generic.data_2 =
|
||||
subghz_protocol_blocks_reverse_key((instance->generic.seed & 0xFF), 8);
|
||||
|
||||
// Encode complete, now serialize
|
||||
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 SubGhzProtocolEncoderJarolift instance
|
||||
* @return true On success
|
||||
*/
|
||||
static bool subghz_protocol_encoder_jarolift_get_upload(
|
||||
SubGhzProtocolEncoderJarolift* instance,
|
||||
uint8_t btn) {
|
||||
furi_assert(instance);
|
||||
|
||||
// Gen new key
|
||||
if(!subghz_protocol_jarolift_gen_data(instance, btn)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
// Start 14k us delay
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(false, (uint32_t)subghz_protocol_jarolift_const.te_long * 18);
|
||||
|
||||
// First header bit
|
||||
instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)1500);
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(false, (uint32_t)subghz_protocol_jarolift_const.te_short);
|
||||
|
||||
// Finish header
|
||||
for(uint8_t i = 8; i > 0; i--) {
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(true, (uint32_t)subghz_protocol_jarolift_const.te_short);
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(false, (uint32_t)subghz_protocol_jarolift_const.te_short);
|
||||
}
|
||||
|
||||
// After header
|
||||
instance->encoder.upload[index - 1].duration = (uint32_t)3800; // Adjust last low duration
|
||||
|
||||
// Send key fix
|
||||
for(uint8_t i = 64; 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_jarolift_const.te_short);
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(false, (uint32_t)subghz_protocol_jarolift_const.te_long);
|
||||
} else {
|
||||
//send bit 0
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(true, (uint32_t)subghz_protocol_jarolift_const.te_long);
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(false, (uint32_t)subghz_protocol_jarolift_const.te_short);
|
||||
}
|
||||
}
|
||||
|
||||
// Send grouping byte
|
||||
for(uint8_t i = 8; i > 0; i--) {
|
||||
if(bit_read(instance->generic.data_2, i - 1)) {
|
||||
//send bit 1
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(true, (uint32_t)subghz_protocol_jarolift_const.te_short);
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(false, (uint32_t)subghz_protocol_jarolift_const.te_long);
|
||||
} else {
|
||||
//send bit 0
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(true, (uint32_t)subghz_protocol_jarolift_const.te_long);
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(false, (uint32_t)subghz_protocol_jarolift_const.te_short);
|
||||
}
|
||||
}
|
||||
|
||||
// Set upload size after generating upload, fix it later
|
||||
instance->encoder.size_upload = index;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SubGhzProtocolStatus
|
||||
subghz_protocol_encoder_jarolift_deserialize(void* context, FlipperFormat* flipper_format) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolEncoderJarolift* 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];
|
||||
}
|
||||
|
||||
subghz_protocol_jarolift_remote_controller(&instance->generic, instance->keystore);
|
||||
|
||||
subghz_protocol_encoder_jarolift_get_upload(instance, instance->generic.btn);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//
|
||||
// Decoder
|
||||
//
|
||||
void* subghz_protocol_decoder_jarolift_alloc(SubGhzEnvironment* environment) {
|
||||
SubGhzProtocolDecoderJarolift* instance = malloc(sizeof(SubGhzProtocolDecoderJarolift));
|
||||
instance->base.protocol = &subghz_protocol_jarolift;
|
||||
instance->generic.protocol_name = instance->base.protocol->name;
|
||||
instance->keystore = subghz_environment_get_keystore(environment);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void subghz_protocol_decoder_jarolift_free(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderJarolift* instance = context;
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void subghz_protocol_decoder_jarolift_reset(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderJarolift* instance = context;
|
||||
instance->decoder.parser_step = JaroliftDecoderStepReset;
|
||||
}
|
||||
|
||||
void subghz_protocol_decoder_jarolift_feed(void* context, bool level, uint32_t duration) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderJarolift* instance = context;
|
||||
|
||||
switch(instance->decoder.parser_step) {
|
||||
case JaroliftDecoderStepReset:
|
||||
if((level) && DURATION_DIFF(duration, subghz_protocol_jarolift_const.te_short) <
|
||||
subghz_protocol_jarolift_const.te_delta) {
|
||||
instance->decoder.parser_step = JaroliftDecoderStepCheckPreambula;
|
||||
instance->header_count++;
|
||||
}
|
||||
break;
|
||||
case JaroliftDecoderStepCheckPreambula:
|
||||
if((!level) && (DURATION_DIFF(duration, subghz_protocol_jarolift_const.te_short) <
|
||||
subghz_protocol_jarolift_const.te_delta)) {
|
||||
instance->decoder.parser_step = JaroliftDecoderStepReset;
|
||||
break;
|
||||
}
|
||||
if((!level) && (instance->header_count == 8) &&
|
||||
(DURATION_DIFF(duration, subghz_protocol_jarolift_const.te_long * 5) <
|
||||
subghz_protocol_jarolift_const.te_delta * 6)) {
|
||||
// Found gap after header - 4000us +- 996us
|
||||
instance->decoder.parser_step = JaroliftDecoderStepSaveDuration;
|
||||
instance->decoder.decode_data = 0;
|
||||
instance->decoder.decode_count_bit = 0;
|
||||
instance->header_count = 0;
|
||||
break;
|
||||
} else {
|
||||
instance->decoder.parser_step = JaroliftDecoderStepReset;
|
||||
instance->header_count = 0;
|
||||
}
|
||||
break;
|
||||
case JaroliftDecoderStepSaveDuration:
|
||||
if(level) {
|
||||
instance->decoder.te_last = duration;
|
||||
instance->decoder.parser_step = JaroliftDecoderStepCheckDuration;
|
||||
} else {
|
||||
instance->header_count = 0;
|
||||
instance->decoder.parser_step = JaroliftDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
case JaroliftDecoderStepCheckDuration:
|
||||
if(!level) {
|
||||
if(instance->decoder.decode_count_bit == 64) {
|
||||
instance->generic.data = instance->decoder.decode_data;
|
||||
instance->decoder.decode_data = 0;
|
||||
}
|
||||
if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_jarolift_const.te_short) <
|
||||
subghz_protocol_jarolift_const.te_delta) &&
|
||||
(DURATION_DIFF(duration, subghz_protocol_jarolift_const.te_long) <
|
||||
subghz_protocol_jarolift_const.te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
|
||||
instance->decoder.parser_step = JaroliftDecoderStepSaveDuration;
|
||||
} else if(
|
||||
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_jarolift_const.te_long) <
|
||||
subghz_protocol_jarolift_const.te_delta) &&
|
||||
(DURATION_DIFF(duration, subghz_protocol_jarolift_const.te_short) <
|
||||
subghz_protocol_jarolift_const.te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
|
||||
instance->decoder.parser_step = JaroliftDecoderStepSaveDuration;
|
||||
} else {
|
||||
if(duration >= ((uint32_t)subghz_protocol_jarolift_const.te_long * 3)) {
|
||||
// Add endbit
|
||||
if((DURATION_DIFF(
|
||||
instance->decoder.te_last, subghz_protocol_jarolift_const.te_long) <
|
||||
subghz_protocol_jarolift_const.te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
|
||||
} else if((DURATION_DIFF(
|
||||
instance->decoder.te_last,
|
||||
subghz_protocol_jarolift_const.te_short) <
|
||||
subghz_protocol_jarolift_const.te_delta)) {
|
||||
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
|
||||
}
|
||||
if(instance->decoder.decode_count_bit ==
|
||||
subghz_protocol_jarolift_const.min_count_bit_for_found) {
|
||||
instance->generic.data_2 = instance->decoder.decode_data;
|
||||
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
|
||||
|
||||
if(instance->base.callback)
|
||||
instance->base.callback(&instance->base, instance->base.context);
|
||||
}
|
||||
|
||||
instance->decoder.parser_step = JaroliftDecoderStepReset;
|
||||
instance->decoder.decode_data = 0;
|
||||
instance->decoder.decode_count_bit = 0;
|
||||
instance->header_count = 0;
|
||||
break;
|
||||
}
|
||||
instance->decoder.parser_step = JaroliftDecoderStepReset;
|
||||
instance->header_count = 0;
|
||||
}
|
||||
} else {
|
||||
instance->decoder.parser_step = JaroliftDecoderStepReset;
|
||||
instance->header_count = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get button name.
|
||||
* @param btn Button number, 4 bit
|
||||
*/
|
||||
static const char* subghz_protocol_jarolift_get_button_name(uint8_t btn) {
|
||||
const char* btn_name;
|
||||
switch(btn) {
|
||||
case 0x1:
|
||||
btn_name = "Learn";
|
||||
break;
|
||||
case 0x2:
|
||||
btn_name = "Down";
|
||||
break;
|
||||
case 0x4:
|
||||
btn_name = "Stop";
|
||||
break;
|
||||
case 0x8:
|
||||
btn_name = "Up";
|
||||
break;
|
||||
default:
|
||||
btn_name = "Unkn";
|
||||
break;
|
||||
}
|
||||
return btn_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analysis of received data
|
||||
* @param instance Pointer to a SubGhzBlockGeneric* instance
|
||||
* @param data Input encrypted data
|
||||
* @param keystore Pointer to a SubGhzKeystore* instance
|
||||
*/
|
||||
static void subghz_protocol_jarolift_remote_controller(
|
||||
SubGhzBlockGeneric* instance,
|
||||
SubGhzKeystore* keystore) {
|
||||
// Jarolift Decoder
|
||||
// 01.2026 - @xMasterX (MMX) & d82k & Steffen (@bastelbudenbuben de)
|
||||
|
||||
// Key samples (reversed)
|
||||
// 0x821EB600EAC2EAD4 - Btn Up - cnt 0059 group 0100
|
||||
// 0x821EB6007D9BD66A - Btn Up - cnt 005A group 0100
|
||||
// 0x821EB600A029FA0E - Btn Up - cnt 005B group 0100
|
||||
|
||||
uint32_t group = subghz_protocol_blocks_reverse_key(instance->data_2, 8);
|
||||
uint64_t key = subghz_protocol_blocks_reverse_key(instance->data, 64);
|
||||
bool ret = false;
|
||||
uint32_t decrypt = 0;
|
||||
instance->serial = (key >> 32) & 0xFFFFFFF;
|
||||
uint32_t hop = key & 0xFFFFFFFF;
|
||||
|
||||
for
|
||||
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
|
||||
if(manufacture_code->type == KEELOQ_LEARNING_NORMAL_JAROLIFT) {
|
||||
uint64_t man = subghz_protocol_keeloq_common_normal_learning(
|
||||
instance->serial, manufacture_code->key);
|
||||
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
|
||||
if(((decrypt >> 16) & 0xFF) == (instance->serial & 0xFF)) {
|
||||
ret = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(ret) {
|
||||
instance->btn = (key >> 60) & 0xF;
|
||||
instance->seed = ((decrypt >> 24) << 8) | (group >> 8);
|
||||
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;
|
||||
instance->cnt = 0;
|
||||
instance->seed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t subghz_protocol_decoder_jarolift_get_hash_data(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderJarolift* instance = context;
|
||||
uint32_t hash = 0;
|
||||
uint32_t* p = (uint32_t*)&instance->generic.data;
|
||||
for(size_t i = 0; i < 4; i++) {
|
||||
hash ^= p[i];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
SubGhzProtocolStatus subghz_protocol_decoder_jarolift_serialize(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
SubGhzRadioPreset* preset) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderJarolift* 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_jarolift_deserialize(void* context, FlipperFormat* flipper_format) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderJarolift* instance = context;
|
||||
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
|
||||
do {
|
||||
ret = subghz_block_generic_deserialize_check_count_bit(
|
||||
&instance->generic,
|
||||
flipper_format,
|
||||
subghz_protocol_jarolift_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;
|
||||
}
|
||||
|
||||
static uint8_t subghz_protocol_jarolift_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 0x1:
|
||||
btn = 0x2;
|
||||
break;
|
||||
case 0x2:
|
||||
btn = 0x1;
|
||||
break;
|
||||
case 0x4:
|
||||
btn = 0x1;
|
||||
break;
|
||||
case 0x8:
|
||||
btn = 0x1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
|
||||
switch(original_btn_code) {
|
||||
case 0x1:
|
||||
btn = 0x4;
|
||||
break;
|
||||
case 0x2:
|
||||
btn = 0x4;
|
||||
break;
|
||||
case 0x4:
|
||||
btn = 0x2;
|
||||
break;
|
||||
case 0x8:
|
||||
btn = 0x4;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) {
|
||||
switch(original_btn_code) {
|
||||
case 0x1:
|
||||
btn = 0x8;
|
||||
break;
|
||||
case 0x2:
|
||||
btn = 0x8;
|
||||
break;
|
||||
case 0x4:
|
||||
btn = 0x8;
|
||||
break;
|
||||
case 0x8:
|
||||
btn = 0x2;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return btn;
|
||||
}
|
||||
|
||||
void subghz_protocol_decoder_jarolift_get_string(void* context, FuriString* output) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderJarolift* instance = context;
|
||||
subghz_protocol_jarolift_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 %dbit\r\n"
|
||||
"Key:%0llX\r\n"
|
||||
"Sn:%07lX Btn:%01X - %s\r\n"
|
||||
"Cnt:%04lX Group:%04lX\r\n",
|
||||
instance->generic.protocol_name,
|
||||
instance->generic.data_count_bit,
|
||||
instance->generic.data,
|
||||
instance->generic.serial,
|
||||
instance->generic.btn,
|
||||
subghz_protocol_jarolift_get_button_name(instance->generic.btn),
|
||||
instance->generic.cnt,
|
||||
instance->generic.seed);
|
||||
}
|
||||
108
lib/subghz/protocols/jarolift.h
Normal file
@@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
#include "base.h"
|
||||
|
||||
#define SUBGHZ_PROTOCOL_JAROLIFT_NAME "Jarolift"
|
||||
|
||||
typedef struct SubGhzProtocolDecoderJarolift SubGhzProtocolDecoderJarolift;
|
||||
typedef struct SubGhzProtocolEncoderJarolift SubGhzProtocolEncoderJarolift;
|
||||
|
||||
extern const SubGhzProtocolDecoder subghz_protocol_jarolift_decoder;
|
||||
extern const SubGhzProtocolEncoder subghz_protocol_jarolift_encoder;
|
||||
extern const SubGhzProtocol subghz_protocol_jarolift;
|
||||
|
||||
/**
|
||||
* Allocate SubGhzProtocolEncoderJarolift.
|
||||
* @param environment Pointer to a SubGhzEnvironment instance
|
||||
* @return SubGhzProtocolEncoderJarolift* pointer to a SubGhzProtocolEncoderJarolift instance
|
||||
*/
|
||||
void* subghz_protocol_encoder_jarolift_alloc(SubGhzEnvironment* environment);
|
||||
|
||||
/**
|
||||
* Free SubGhzProtocolEncoderJarolift.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderJarolift instance
|
||||
*/
|
||||
void subghz_protocol_encoder_jarolift_free(void* context);
|
||||
|
||||
/**
|
||||
* Deserialize and generating an upload to send.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderJarolift instance
|
||||
* @param flipper_format Pointer to a FlipperFormat instance
|
||||
* @return true On success
|
||||
*/
|
||||
SubGhzProtocolStatus
|
||||
subghz_protocol_encoder_jarolift_deserialize(void* context, FlipperFormat* flipper_format);
|
||||
|
||||
/**
|
||||
* Forced transmission stop.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderJarolift instance
|
||||
*/
|
||||
void subghz_protocol_encoder_jarolift_stop(void* context);
|
||||
|
||||
/**
|
||||
* Getting the level and duration of the upload to be loaded into DMA.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderJarolift instance
|
||||
* @return LevelDuration
|
||||
*/
|
||||
LevelDuration subghz_protocol_encoder_jarolift_yield(void* context);
|
||||
|
||||
/**
|
||||
* Allocate SubGhzProtocolDecoderJarolift.
|
||||
* @param environment Pointer to a SubGhzEnvironment instance
|
||||
* @return SubGhzProtocolDecoderJarolift* pointer to a SubGhzProtocolDecoderJarolift instance
|
||||
*/
|
||||
void* subghz_protocol_decoder_jarolift_alloc(SubGhzEnvironment* environment);
|
||||
|
||||
/**
|
||||
* Free SubGhzProtocolDecoderJarolift.
|
||||
* @param context Pointer to a SubGhzProtocolDecoderJarolift instance
|
||||
*/
|
||||
void subghz_protocol_decoder_jarolift_free(void* context);
|
||||
|
||||
/**
|
||||
* Reset decoder SubGhzProtocolDecoderJarolift.
|
||||
* @param context Pointer to a SubGhzProtocolDecoderJarolift instance
|
||||
*/
|
||||
void subghz_protocol_decoder_jarolift_reset(void* context);
|
||||
|
||||
/**
|
||||
* Parse a raw sequence of levels and durations received from the air.
|
||||
* @param context Pointer to a SubGhzProtocolDecoderJarolift instance
|
||||
* @param level Signal level true-high false-low
|
||||
* @param duration Duration of this level in, us
|
||||
*/
|
||||
void subghz_protocol_decoder_jarolift_feed(void* context, bool level, uint32_t duration);
|
||||
|
||||
/**
|
||||
* Getting the hash sum of the last randomly received parcel.
|
||||
* @param context Pointer to a SubGhzProtocolDecoderJarolift instance
|
||||
* @return hash Hash sum
|
||||
*/
|
||||
uint32_t subghz_protocol_decoder_jarolift_get_hash_data(void* context);
|
||||
|
||||
/**
|
||||
* Serialize data SubGhzProtocolDecoderJarolift.
|
||||
* @param context Pointer to a SubGhzProtocolDecoderJarolift 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_jarolift_serialize(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
SubGhzRadioPreset* preset);
|
||||
|
||||
/**
|
||||
* Deserialize data SubGhzProtocolDecoderJarolift.
|
||||
* @param context Pointer to a SubGhzProtocolDecoderJarolift instance
|
||||
* @param flipper_format Pointer to a FlipperFormat instance
|
||||
* @return status
|
||||
*/
|
||||
SubGhzProtocolStatus
|
||||
subghz_protocol_decoder_jarolift_deserialize(void* context, FlipperFormat* flipper_format);
|
||||
|
||||
/**
|
||||
* Getting a textual representation of the received data.
|
||||
* @param context Pointer to a SubGhzProtocolDecoderJarolift instance
|
||||
* @param output Resulting text
|
||||
*/
|
||||
void subghz_protocol_decoder_jarolift_get_string(void* context, FuriString* output);
|
||||
@@ -26,6 +26,8 @@
|
||||
#define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_2 7u
|
||||
#define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_3 8u
|
||||
// #define BENINCA_ARC_KEY_TYPE 9u -- RESERVED
|
||||
#define KEELOQ_LEARNING_SIMPLE_KINGGATES 10u
|
||||
#define KEELOQ_LEARNING_NORMAL_JAROLIFT 11u
|
||||
|
||||
/**
|
||||
* Simple Learning Encrypt
|
||||
|
||||
@@ -189,7 +189,7 @@ static bool subghz_protocol_kinggates_stylo_4k_gen_data(
|
||||
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) {
|
||||
if(manufacture_code->type == KEELOQ_LEARNING_SIMPLE_KINGGATES) {
|
||||
// Simple Learning
|
||||
encrypt = subghz_protocol_keeloq_common_encrypt(hop, manufacture_code->key);
|
||||
encrypt = subghz_protocol_blocks_reverse_key(encrypt, 32);
|
||||
@@ -222,7 +222,7 @@ bool subghz_protocol_kinggates_stylo_4k_create_data(
|
||||
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) {
|
||||
if(manufacture_code->type == KEELOQ_LEARNING_SIMPLE_KINGGATES) {
|
||||
// Simple Learning
|
||||
encrypt = subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
|
||||
encrypt = subghz_protocol_blocks_reverse_key(encrypt, 32);
|
||||
@@ -458,7 +458,6 @@ void subghz_protocol_decoder_kinggates_stylo_4k_feed(void* context, bool level,
|
||||
subghz_protocol_kinggates_stylo_4k_const.te_delta * 2) {
|
||||
instance->decoder.parser_step = KingGates_stylo_4kDecoderStepSaveDuration;
|
||||
instance->decoder.decode_data = 0;
|
||||
instance->generic.data_2 = 0;
|
||||
instance->decoder.decode_count_bit = 0;
|
||||
instance->header_count = 0;
|
||||
}
|
||||
@@ -478,7 +477,6 @@ void subghz_protocol_decoder_kinggates_stylo_4k_feed(void* context, bool level,
|
||||
|
||||
instance->decoder.parser_step = KingGates_stylo_4kDecoderStepReset;
|
||||
instance->decoder.decode_data = 0;
|
||||
instance->generic.data_2 = 0;
|
||||
instance->decoder.decode_count_bit = 0;
|
||||
instance->header_count = 0;
|
||||
break;
|
||||
@@ -563,7 +561,7 @@ static void subghz_protocol_kinggates_stylo_4k_remote_controller(
|
||||
|
||||
for
|
||||
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
|
||||
if(manufacture_code->type == KEELOQ_LEARNING_SIMPLE) {
|
||||
if(manufacture_code->type == KEELOQ_LEARNING_SIMPLE_KINGGATES) {
|
||||
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
|
||||
if(((decrypt >> 28) == instance->btn) && (((decrypt >> 24) & 0x0F) == 0x0C) &&
|
||||
(((decrypt >> 16) & 0xFF) == (instance->serial & 0xFF))) {
|
||||
|
||||
@@ -83,6 +83,7 @@ const SubGhzProtocol* const subghz_protocol_registry_items[] = {
|
||||
&subghz_protocol_elplast,
|
||||
&subghz_protocol_treadmill37,
|
||||
&subghz_protocol_beninca_arc,
|
||||
&subghz_protocol_jarolift,
|
||||
};
|
||||
|
||||
const SubGhzProtocolRegistry subghz_protocol_registry = {
|
||||
|
||||
@@ -84,3 +84,4 @@
|
||||
#include "elplast.h"
|
||||
#include "treadmill37.h"
|
||||
#include "beninca_arc.h"
|
||||
#include "jarolift.h"
|
||||
|
||||
@@ -231,6 +231,24 @@ bool subghz_protocol_beninca_arc_create_data(
|
||||
uint32_t cnt,
|
||||
SubGhzRadioPreset* preset);
|
||||
|
||||
/**
|
||||
* Key generation from simple data.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderJarolift 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_jarolift_create_data(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
uint32_t serial,
|
||||
uint8_t btn,
|
||||
uint16_t cnt,
|
||||
SubGhzRadioPreset* preset);
|
||||
|
||||
typedef struct SubGhzProtocolDecoderBinRAW SubGhzProtocolDecoderBinRAW;
|
||||
|
||||
void subghz_protocol_decoder_bin_raw_data_input_rssi(
|
||||
|
||||
@@ -3733,6 +3733,7 @@ Function,+,subghz_protocol_encoder_raw_free,void,void*
|
||||
Function,+,subghz_protocol_encoder_raw_stop,void,void*
|
||||
Function,+,subghz_protocol_encoder_raw_yield,LevelDuration,void*
|
||||
Function,+,subghz_protocol_faac_slh_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint32_t, uint32_t, const char*, SubGhzRadioPreset*"
|
||||
Function,+,subghz_protocol_jarolift_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*"
|
||||
Function,+,subghz_protocol_keeloq_bft_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, uint32_t, const char*, SubGhzRadioPreset*"
|
||||
Function,+,subghz_protocol_keeloq_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, const char*, SubGhzRadioPreset*"
|
||||
Function,+,subghz_protocol_kinggates_stylo_4k_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*"
|
||||
|
||||
|
@@ -706,6 +706,8 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) {
|
||||
while(samples > 0) {
|
||||
volatile uint32_t duration = furi_hal_subghz_async_tx_middleware_get_duration(
|
||||
&furi_hal_subghz_async_tx.middleware, furi_hal_subghz_async_tx.callback);
|
||||
// if duration == 0 then we stop DMA interrupt(that used to refill buffer) and write to buffer 0 as last element.
|
||||
// later DMA write this 0 to ARR and timer TIM2 will be stopped.
|
||||
if(duration == 0) {
|
||||
*buffer = 0;
|
||||
buffer++;
|
||||
@@ -778,48 +780,64 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
|
||||
furi_hal_subghz_async_tx.buffer =
|
||||
malloc(FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t));
|
||||
|
||||
// Connect CC1101_GD0 to TIM2 as output
|
||||
// Here we use TIM2_CH2 (Timer 2 Channel 2) to generate HI/LOW signals for C1101 with current durations.
|
||||
// DMA update/rewrite TIM2 settings (ARR) with new duration each time TIM2 completes.
|
||||
// Every time when timer counter exeed current TIM2-ARR (AutoReload Register) value timer generate event that call DMA
|
||||
// DMA load next new value from buffer to TIM2-ARR and timer start count up from 0 to new value again
|
||||
// Totally we have timer that generate events and update they settings with new durations by DMA action.
|
||||
// When duration = 0 then DMA wirte 0 to ARR. So when we set ARR=0 - thats mean TIM2 stop counting.
|
||||
|
||||
// Connect CC1101_GD0 to TIM2 as output (Pin B3 - GpioAltFn1TIM2 - TIM2, CH2)
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2);
|
||||
|
||||
// Configure DMA
|
||||
LL_DMA_InitTypeDef dma_config = {0};
|
||||
dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR);
|
||||
dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_async_tx.buffer;
|
||||
dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
|
||||
dma_config.Mode = LL_DMA_MODE_CIRCULAR;
|
||||
dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
|
||||
dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
|
||||
dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
|
||||
dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
|
||||
dma_config.NbData = FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL;
|
||||
dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
|
||||
// Configure DMA to update TIM2->ARR
|
||||
LL_DMA_InitTypeDef dma_config = {0}; // DMA settings structure
|
||||
dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); // DMA destination TIM2->ARR
|
||||
dma_config.MemoryOrM2MDstAddress =
|
||||
(uint32_t)furi_hal_subghz_async_tx.buffer; // DMA buffer with signals durations
|
||||
dma_config.Direction =
|
||||
LL_DMA_DIRECTION_MEMORY_TO_PERIPH; // DMA direction from memory to periperhal
|
||||
dma_config.Mode = LL_DMA_MODE_CIRCULAR; // DMA mode
|
||||
dma_config.PeriphOrM2MSrcIncMode =
|
||||
LL_DMA_PERIPH_NOINCREMENT; // DMA destination not changed - allways stay on ARR (AutoReload Register)
|
||||
dma_config.MemoryOrM2MDstIncMode =
|
||||
LL_DMA_MEMORY_INCREMENT; // DMA source increment - step by step on durations buffer
|
||||
dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; // DMA source packet size
|
||||
dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; // DMA destination packet size
|
||||
dma_config.NbData = FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL; // DMA buffer size
|
||||
dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; // DMA start by TIM2 event
|
||||
dma_config.Priority =
|
||||
LL_DMA_PRIORITY_VERYHIGH; // Ensure that ARR is updated before anyone else try to check it
|
||||
LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config);
|
||||
LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config); // Setup DMA with settings structure
|
||||
// setup interrupt for DMA. When DMA generate interrupt event we call furi_hal_subghz_async_tx_dma_isr
|
||||
furi_hal_interrupt_set_isr(SUBGHZ_DMA_CH1_IRQ, furi_hal_subghz_async_tx_dma_isr, NULL);
|
||||
LL_DMA_EnableIT_TC(SUBGHZ_DMA_CH1_DEF);
|
||||
LL_DMA_EnableIT_HT(SUBGHZ_DMA_CH1_DEF);
|
||||
LL_DMA_EnableChannel(SUBGHZ_DMA_CH1_DEF);
|
||||
LL_DMA_EnableIT_TC(SUBGHZ_DMA_CH1_DEF); // interrupt for full buffer sent
|
||||
LL_DMA_EnableIT_HT(SUBGHZ_DMA_CH1_DEF); // interrupt for half buffer sent
|
||||
LL_DMA_EnableChannel(SUBGHZ_DMA_CH1_DEF); // Enable
|
||||
|
||||
furi_hal_bus_enable(FuriHalBusTIM2);
|
||||
furi_hal_bus_enable(FuriHalBusTIM2); // Enable TIM2
|
||||
|
||||
// Configure TIM2
|
||||
LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP);
|
||||
LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); // TIM2 set counter mode UP
|
||||
// Set the division ratio between the timer clock and the sampling clock 1:1
|
||||
LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1);
|
||||
LL_TIM_SetPrescaler(TIM2, 64 - 1); // Perscaler 64 Mghz/64 = 1 Mghz (1 000 000 tick/sec)
|
||||
// AutoReload Register (ARR) 1000 ticks = 1/1000 Mghz = 1 millisecond, will be changed by DMA by new durations
|
||||
LL_TIM_SetAutoReload(TIM2, 1000);
|
||||
LL_TIM_SetPrescaler(TIM2, 64 - 1);
|
||||
LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);
|
||||
LL_TIM_DisableARRPreload(TIM2);
|
||||
LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); // ClockSource for TIM2
|
||||
LL_TIM_DisableARRPreload(
|
||||
TIM2); // Change TIM2 setting immediately (dont wait when counter will be overload)
|
||||
|
||||
// Configure TIM2 CH2
|
||||
LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
|
||||
LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; //Settings structure
|
||||
// CH2 working mode - TOGGLE (swith between HI and LOW levels)
|
||||
TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_TOGGLE;
|
||||
TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE;
|
||||
TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE;
|
||||
TIM_OC_InitStruct.CompareValue = 0;
|
||||
TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH;
|
||||
LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct);
|
||||
TIM_OC_InitStruct.CompareValue = 0; // Counter value to generate events and TOGGLE output
|
||||
TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; // Initial CH2 state - HIGH level
|
||||
LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct); // Apply settings to CH2
|
||||
LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH2);
|
||||
LL_TIM_DisableMasterSlaveMode(TIM2);
|
||||
|
||||
@@ -827,8 +845,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
|
||||
furi_hal_subghz_async_tx_refill(
|
||||
furi_hal_subghz_async_tx.buffer, FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL);
|
||||
|
||||
LL_TIM_EnableDMAReq_UPDATE(TIM2);
|
||||
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2);
|
||||
LL_TIM_EnableDMAReq_UPDATE(TIM2); // Setup calling DMA by TIM2 events
|
||||
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); //Enable TIM2 CH2
|
||||
|
||||
// Start debug
|
||||
if(furi_hal_subghz_start_debug()) {
|
||||
@@ -863,8 +881,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
|
||||
#endif
|
||||
furi_hal_subghz_tx();
|
||||
|
||||
LL_TIM_SetCounter(TIM2, 0);
|
||||
LL_TIM_EnableCounter(TIM2);
|
||||
LL_TIM_SetCounter(TIM2, 0); // Reset TIM2
|
||||
LL_TIM_EnableCounter(TIM2); // Start TIM2 counting.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||