mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 20:49:49 +04:00
Compare commits
512 Commits
nfcrefacto
...
unlshd-071
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bddedd9efc | ||
|
|
12d70a3c32 | ||
|
|
5fce81cfa0 | ||
|
|
f9b6d22534 | ||
|
|
c63089a929 | ||
|
|
ebcc317816 | ||
|
|
be46c62105 | ||
|
|
603421bd8c | ||
|
|
6aa7f2e261 | ||
|
|
1bd42af688 | ||
|
|
398a468fd7 | ||
|
|
90b49926ea | ||
|
|
7caf2bd2ff | ||
|
|
3446b38a06 | ||
|
|
22be06174a | ||
|
|
6bfa591e92 | ||
|
|
4573046df8 | ||
|
|
fe05c678c4 | ||
|
|
f89a0c91e9 | ||
|
|
5d4dae5fa8 | ||
|
|
89e1620883 | ||
|
|
4fd0ce3eb5 | ||
|
|
28723949c4 | ||
|
|
cbab316607 | ||
|
|
19a5f02d66 | ||
|
|
754fffac6b | ||
|
|
289fbe56be | ||
|
|
c31052848a | ||
|
|
a8651a2861 | ||
|
|
76a5c444fa | ||
|
|
da44d70bf2 | ||
|
|
e702cdedc3 | ||
|
|
67eb679435 | ||
|
|
ed3cd21f5c | ||
|
|
d3dcc1d27d | ||
|
|
e6f078eeb7 | ||
|
|
097632fb7a | ||
|
|
834c2efb8b | ||
|
|
1cb8b0e369 | ||
|
|
100a46d7af | ||
|
|
b0371b3465 | ||
|
|
872987f002 | ||
|
|
51d8b18f3e | ||
|
|
92a25af3c3 | ||
|
|
ce80586822 | ||
|
|
fee4a5a8f7 | ||
|
|
a15312e052 | ||
|
|
d23bc9f58a | ||
|
|
35a93e6eef | ||
|
|
a5b77aa228 | ||
|
|
3612814a18 | ||
|
|
1165e25f00 | ||
|
|
64fe987fb5 | ||
|
|
c8ea167a06 | ||
|
|
653af9a5cd | ||
|
|
16d1c938bf | ||
|
|
1074af905c | ||
|
|
786f3568c0 | ||
|
|
830dbc7a71 | ||
|
|
686c05d20c | ||
|
|
4b786fb77e | ||
|
|
16b8fa4715 | ||
|
|
39055ff701 | ||
|
|
cbc0231461 | ||
|
|
1ceacc6555 | ||
|
|
ae04fc70eb | ||
|
|
acd6445d3b | ||
|
|
7a89789a28 | ||
|
|
63eeb86bc7 | ||
|
|
1e6fe92b44 | ||
|
|
c014491f55 | ||
|
|
5e384ccc43 | ||
|
|
3fce83eb79 | ||
|
|
3f6092d95c | ||
|
|
87f8f1d9c4 | ||
|
|
eb4d0bb737 | ||
|
|
b9498826fd | ||
|
|
2617eccb46 | ||
|
|
aef18f6b2f | ||
|
|
aad9f6be28 | ||
|
|
9fb14704c3 | ||
|
|
1ad17878e3 | ||
|
|
391c32654b | ||
|
|
74023e43ce | ||
|
|
c470748e3f | ||
|
|
84abb53712 | ||
|
|
46eec3f568 | ||
|
|
007e29425d | ||
|
|
41c316d612 | ||
|
|
39e9dd0ab0 | ||
|
|
a989c8adcc | ||
|
|
5f041a22e5 | ||
|
|
ecabcbc58a | ||
|
|
c002684233 | ||
|
|
a4ebbeabd2 | ||
|
|
7db8d5aa82 | ||
|
|
7981cb832e | ||
|
|
c27494ac39 | ||
|
|
f37d00a8ba | ||
|
|
11ecb54576 | ||
|
|
8d60c0ff21 | ||
|
|
a1e62c3e76 | ||
|
|
16a3f4c06a | ||
|
|
b5964b9795 | ||
|
|
eef4574a63 | ||
|
|
e3930a30c0 | ||
|
|
36114de5f7 | ||
|
|
1fd4839bb6 | ||
|
|
a7ab4b9c32 | ||
|
|
51f6dcffa4 | ||
|
|
ab236f3763 | ||
|
|
81e4e94adf | ||
|
|
5655be1b8f | ||
|
|
61067b0984 | ||
|
|
dc8b0b02d8 | ||
|
|
d9e4a60010 | ||
|
|
9e8e5d8ae9 | ||
|
|
bae0baa42f | ||
|
|
027ea9ea36 | ||
|
|
4f50ef9b54 | ||
|
|
a11fcfc72d | ||
|
|
cb0cf7b9e2 | ||
|
|
95737958ad | ||
|
|
f9f67e6d54 | ||
|
|
dd182ab179 | ||
|
|
fc043da9c6 | ||
|
|
f1a972607a | ||
|
|
4b7b0ad6b9 | ||
|
|
ba6b56445d | ||
|
|
be15c5ff4a | ||
|
|
957a89f2b3 | ||
|
|
08a5adf18e | ||
|
|
3a82b3aa3c | ||
|
|
d73d007797 | ||
|
|
3fd5f15e7f | ||
|
|
1f9fd4c42a | ||
|
|
c539cfa5ae | ||
|
|
48e4de1213 | ||
|
|
18ea59051a | ||
|
|
34517ec43e | ||
|
|
9aae348cae | ||
|
|
634e841ce8 | ||
|
|
924520a9a7 | ||
|
|
0d40e57cc8 | ||
|
|
321a56d934 | ||
|
|
22aba527b7 | ||
|
|
6103de1754 | ||
|
|
8799e1112b | ||
|
|
01d178a1f3 | ||
|
|
685ed6bfad | ||
|
|
d337222cbe | ||
|
|
81efe25a6e | ||
|
|
781794f699 | ||
|
|
bfffaf5b53 | ||
|
|
0789cbdefa | ||
|
|
d289545bf8 | ||
|
|
e8b468b492 | ||
|
|
e6db0842d4 | ||
|
|
4b3d6e7332 | ||
|
|
d3c994c403 | ||
|
|
4397e2cff5 | ||
|
|
8a3557bc97 | ||
|
|
b757544ede | ||
|
|
e9454b629b | ||
|
|
34539cda17 | ||
|
|
85f437ee22 | ||
|
|
14af1fe022 | ||
|
|
686fd208dc | ||
|
|
cfb974dc1f | ||
|
|
1ea99d119b | ||
|
|
843fa3eecc | ||
|
|
3959827fd4 | ||
|
|
d0c466ccc0 | ||
|
|
0b15fc3807 | ||
|
|
4d99a454fd | ||
|
|
3452fbc351 | ||
|
|
8c04947aa2 | ||
|
|
b71fb8c966 | ||
|
|
c85e1305c0 | ||
|
|
5dfa2fd24c | ||
|
|
71ed7f8e94 | ||
|
|
4636444464 | ||
|
|
e7bf9b4df2 | ||
|
|
f0e011e73a | ||
|
|
f224a8ec57 | ||
|
|
4a47644e64 | ||
|
|
7af56e8717 | ||
|
|
526f728f89 | ||
|
|
7de861bb4c | ||
|
|
4e068ba593 | ||
|
|
0d68fb409c | ||
|
|
b77f41949c | ||
|
|
1d35110a98 | ||
|
|
e5738ec703 | ||
|
|
942f024db9 | ||
|
|
a640dfecf8 | ||
|
|
4fa617b772 | ||
|
|
4b95efda49 | ||
|
|
f6a363e7d2 | ||
|
|
d2549b3b1a | ||
|
|
1bae3d19ee | ||
|
|
d1df26cc83 | ||
|
|
66756853a6 | ||
|
|
00d9c60515 | ||
|
|
e243ca47ba | ||
|
|
941652ec57 | ||
|
|
7eeb60e17e | ||
|
|
c8ce5e6ed4 | ||
|
|
1e89197349 | ||
|
|
b57f4ce848 | ||
|
|
48e80adccc | ||
|
|
d511d76a1b | ||
|
|
0049b19994 | ||
|
|
56ad7ece69 | ||
|
|
b48103196f | ||
|
|
4d5e096437 | ||
|
|
e5ceef3422 | ||
|
|
18fbe364f2 | ||
|
|
c9ffe4ab4d | ||
|
|
0a44c75b20 | ||
|
|
82ecc8e73f | ||
|
|
e2a7d5f3f4 | ||
|
|
5994c26de3 | ||
|
|
a7b60bf2a6 | ||
|
|
f4e738a9ef | ||
|
|
13fe87259f | ||
|
|
d55652deff | ||
|
|
4b363472dd | ||
|
|
bf78ace9e2 | ||
|
|
cf4b537c37 | ||
|
|
305d5bcc83 | ||
|
|
d65dfe1958 | ||
|
|
895694c624 | ||
|
|
3edbf8f538 | ||
|
|
2a0a54a224 | ||
|
|
35e74c07d1 | ||
|
|
f6a38352e8 | ||
|
|
76ed466eb4 | ||
|
|
f7e0338a75 | ||
|
|
ca62254ee7 | ||
|
|
a6bfc27530 | ||
|
|
40cc78489a | ||
|
|
bc2a2f5907 | ||
|
|
5ef6adb9ea | ||
|
|
eef8c0ffa7 | ||
|
|
528d29b82d | ||
|
|
5c00a403f6 | ||
|
|
c9e3f20314 | ||
|
|
0084443ed7 | ||
|
|
b84f14386c | ||
|
|
111750c420 | ||
|
|
2832160891 | ||
|
|
531ba24e9a | ||
|
|
4d56bb4e44 | ||
|
|
92bed4a081 | ||
|
|
bcadbc6353 | ||
|
|
1543170f4c | ||
|
|
18194b6bb5 | ||
|
|
cdede67f31 | ||
|
|
c5a76af1dd | ||
|
|
1acbd84b7c | ||
|
|
e9e44db964 | ||
|
|
271ec6cf97 | ||
|
|
9b156fbdca | ||
|
|
de9765fa25 | ||
|
|
abcb9b2f38 | ||
|
|
eaae5da519 | ||
|
|
77f458fb6e | ||
|
|
8fa21c49b2 | ||
|
|
49b2a4da8a | ||
|
|
09defbc4d4 | ||
|
|
2b3e12fcb6 | ||
|
|
bc1fdabce4 | ||
|
|
fc6e152fd1 | ||
|
|
3ec070313e | ||
|
|
33136b441c | ||
|
|
5bff5ca40d | ||
|
|
d5164c427f | ||
|
|
17b122990f | ||
|
|
78d1507f14 | ||
|
|
1e1d9fcb69 | ||
|
|
6f6074dc01 | ||
|
|
14c6abe4eb | ||
|
|
25d24f1e4c | ||
|
|
528d2a7ec3 | ||
|
|
4a77a236b4 | ||
|
|
cf6829f608 | ||
|
|
7642d67cae | ||
|
|
238187730c | ||
|
|
c53f5aa5b5 | ||
|
|
ebe1a8f55f | ||
|
|
510f217cd5 | ||
|
|
364b334654 | ||
|
|
afc2b14578 | ||
|
|
db57ff947b | ||
|
|
8c4716f170 | ||
|
|
11ac6240d2 | ||
|
|
d6680d1f75 | ||
|
|
09540929c3 | ||
|
|
36aecfbec9 | ||
|
|
0af74fb755 | ||
|
|
78b7310057 | ||
|
|
ccbb3a3498 | ||
|
|
69d1d5498e | ||
|
|
d7b54dfa66 | ||
|
|
04e28f3e39 | ||
|
|
1a56ce77e2 | ||
|
|
94e8e5d498 | ||
|
|
f3cbb0363d | ||
|
|
2d860b4a22 | ||
|
|
09a66e2285 | ||
|
|
fb17718a5d | ||
|
|
73145e0beb | ||
|
|
55b4f87cd7 | ||
|
|
3dde112676 | ||
|
|
155e4e9fa4 | ||
|
|
90cb1c4f2e | ||
|
|
e2e3663524 | ||
|
|
7b85e04462 | ||
|
|
96412202ba | ||
|
|
05b183f5e5 | ||
|
|
0b356c2d6d | ||
|
|
ee9092c8e5 | ||
|
|
2e7bb26eef | ||
|
|
5d28939c28 | ||
|
|
15a29e1483 | ||
|
|
c22b3b57bd | ||
|
|
1daa2fa377 | ||
|
|
59e94566fd | ||
|
|
1b45b8a17d | ||
|
|
e94beff204 | ||
|
|
82baf1e923 | ||
|
|
fa146d8770 | ||
|
|
064c60e52e | ||
|
|
18ea05edee | ||
|
|
c416041379 | ||
|
|
10444b943e | ||
|
|
2308a54ada | ||
|
|
0ed6738a5b | ||
|
|
12180ba707 | ||
|
|
278ae51d73 | ||
|
|
dc25bfb831 | ||
|
|
d113bbf4dd | ||
|
|
38b65fba3b | ||
|
|
7af6a46c8f | ||
|
|
ff724ce4b5 | ||
|
|
d6fcb04aa8 | ||
|
|
9bf8f1015d | ||
|
|
c477d1321a | ||
|
|
ec99b70b38 | ||
|
|
06a58ebd53 | ||
|
|
eb6fe0a4db | ||
|
|
c6a14e1a67 | ||
|
|
04cead1fc5 | ||
|
|
93732865ac | ||
|
|
6a5d63803a | ||
|
|
159aef022b | ||
|
|
f7c63c675b | ||
|
|
99d657fcfb | ||
|
|
00ceb2cd5d | ||
|
|
f151d3be01 | ||
|
|
fa04e36df2 | ||
|
|
7554e7bedb | ||
|
|
59e797b312 | ||
|
|
94cdaf20a2 | ||
|
|
b51a754fd9 | ||
|
|
c1e0d02afc | ||
|
|
890c9e87ce | ||
|
|
961dd297dd | ||
|
|
d675563271 | ||
|
|
e027d5c3e8 | ||
|
|
fdcfd5996b | ||
|
|
f7de65684a | ||
|
|
810dfa1b79 | ||
|
|
f0838dd5fc | ||
|
|
a849d49c92 | ||
|
|
ff129e524a | ||
|
|
05479103a6 | ||
|
|
ff41d262dc | ||
|
|
8628a2c6a2 | ||
|
|
30914678c9 | ||
|
|
c4bf1fe717 | ||
|
|
1946aaf5e1 | ||
|
|
a7b2427007 | ||
|
|
f9101d8084 | ||
|
|
1c3cbec661 | ||
|
|
cea423742b | ||
|
|
8c5f28d6a0 | ||
|
|
6c2e332638 | ||
|
|
5f18532a59 | ||
|
|
63f072a819 | ||
|
|
df1d6503c0 | ||
|
|
972054b377 | ||
|
|
e1c89834df | ||
|
|
c145cad653 | ||
|
|
4261063c99 | ||
|
|
f8546937c0 | ||
|
|
3daaea6ecf | ||
|
|
4a84fbc6e3 | ||
|
|
d8800e9fe3 | ||
|
|
7fd921227c | ||
|
|
b6ad07b47c | ||
|
|
1a21f0e3c9 | ||
|
|
c666368446 | ||
|
|
91d614dd25 | ||
|
|
baca59927b | ||
|
|
4eb40ce948 | ||
|
|
00b1018e9e | ||
|
|
9c92338ddf | ||
|
|
8188b63522 | ||
|
|
0e172b67eb | ||
|
|
156948ec58 | ||
|
|
bbdda5a3d7 | ||
|
|
51a2e638ed | ||
|
|
ffd9d3c218 | ||
|
|
9513ff5307 | ||
|
|
12e736b283 | ||
|
|
a64c9534e2 | ||
|
|
4b3e8aba29 | ||
|
|
98d5718ec9 | ||
|
|
457aa5331f | ||
|
|
a61b5d4b4c | ||
|
|
ba074068b0 | ||
|
|
615a147973 | ||
|
|
c00776ca22 | ||
|
|
d0b9a3a4ae | ||
|
|
dc246ddb09 | ||
|
|
591a2f2b02 | ||
|
|
7aaa847835 | ||
|
|
42101c6594 | ||
|
|
3e9ecd2f4f | ||
|
|
725811d7b3 | ||
|
|
a56a52b4bb | ||
|
|
da18305119 | ||
|
|
c71d04a660 | ||
|
|
f3f68fd5d3 | ||
|
|
d4ce47c941 | ||
|
|
7413a78013 | ||
|
|
83967d6e06 | ||
|
|
4d1c6a8d20 | ||
|
|
c95a0a0171 | ||
|
|
feba1dbc24 | ||
|
|
5b578cf69d | ||
|
|
dafea08581 | ||
|
|
5c50224571 | ||
|
|
b510df47f9 | ||
|
|
2aec3ec5fd | ||
|
|
4b8c017302 | ||
|
|
b579bca227 | ||
|
|
3a676f7afa | ||
|
|
ca479303a1 | ||
|
|
5e649d8c41 | ||
|
|
0bc626ba1d | ||
|
|
3821ee7709 | ||
|
|
cb17189b15 | ||
|
|
80e8167054 | ||
|
|
eede5ed29e | ||
|
|
360fef7777 | ||
|
|
b83da5d3cb | ||
|
|
ae5d28fbc5 | ||
|
|
f4cd7c0100 | ||
|
|
7b68fd30ec | ||
|
|
ac222f1b0c | ||
|
|
b0e8e68909 | ||
|
|
ef5f6e2f70 | ||
|
|
30f6da3fa3 | ||
|
|
3a47154cdb | ||
|
|
d953d35991 | ||
|
|
4b74d13e10 | ||
|
|
98bf353287 | ||
|
|
eb8c751b31 | ||
|
|
9abad8704f | ||
|
|
6716c0f792 | ||
|
|
35f7ec6c07 | ||
|
|
a524fd7674 | ||
|
|
ff27fd3094 | ||
|
|
977ac09fe6 | ||
|
|
1a88e01899 | ||
|
|
6e710c5164 | ||
|
|
fd56ac3400 | ||
|
|
1d801c38f9 | ||
|
|
8afdb5b7b4 | ||
|
|
83624b1dee | ||
|
|
56adcf1ad8 | ||
|
|
ad27f87a0c | ||
|
|
346cf299ee | ||
|
|
05489fda7d | ||
|
|
1b12526357 | ||
|
|
802035d92e | ||
|
|
a24d0f1958 | ||
|
|
da68f2e4ed | ||
|
|
8f16dbb8e7 | ||
|
|
49e458f1b5 | ||
|
|
5cf46d2aa9 | ||
|
|
beedf54e75 | ||
|
|
70ccb89c3d | ||
|
|
5ea43a2a4b | ||
|
|
41f60dbbf4 | ||
|
|
827341ec08 | ||
|
|
5c36043d03 | ||
|
|
cf5811f8d9 | ||
|
|
ec6a169bf8 | ||
|
|
f1dec87c1b | ||
|
|
ab29951a99 | ||
|
|
bbe9f88bbe | ||
|
|
9188bf0013 | ||
|
|
f33ed59567 | ||
|
|
3fd8c80861 | ||
|
|
7b8ac3a5a0 | ||
|
|
6fef957001 | ||
|
|
0de1c9df89 | ||
|
|
a0e8cfbe97 |
@@ -175,3 +175,10 @@ Max butthurt: 12
|
||||
Min level: 2
|
||||
Max level: 3
|
||||
Weight: 4
|
||||
|
||||
Name: L2_Secret_door_128x64
|
||||
Min butthurt: 0
|
||||
Max butthurt: 12
|
||||
Min level: 2
|
||||
Max level: 3
|
||||
Weight: 4
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c
|
||||
index 5769ced..c5d3088 100644
|
||||
index 9baa738..91ad7c1 100644
|
||||
--- a/applications/services/notification/notification_app.c
|
||||
+++ b/applications/services/notification/notification_app.c
|
||||
@@ -9,6 +9,7 @@
|
||||
@@ -19,7 +19,7 @@ index 5769ced..c5d3088 100644
|
||||
}
|
||||
|
||||
diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c
|
||||
index 1955012..19d953d 100644
|
||||
index 2a1d988..dda86f3 100644
|
||||
--- a/applications/settings/notification_settings/notification_settings_app.c
|
||||
+++ b/applications/settings/notification_settings/notification_settings_app.c
|
||||
@@ -3,6 +3,7 @@
|
||||
@@ -30,16 +30,16 @@ index 1955012..19d953d 100644
|
||||
|
||||
#define MAX_NOTIFICATION_SETTINGS 4
|
||||
|
||||
@@ -20,6 +21,8 @@ static const NotificationSequence sequence_note_c = {
|
||||
NULL,
|
||||
};
|
||||
@@ -13,6 +14,8 @@ typedef struct {
|
||||
VariableItemList* variable_item_list;
|
||||
} NotificationAppSettings;
|
||||
|
||||
+static VariableItem* temp_item;
|
||||
+
|
||||
#define CONTRAST_COUNT 11
|
||||
const char* const contrast_text[CONTRAST_COUNT] = {
|
||||
"-5",
|
||||
@@ -156,6 +159,59 @@ static void vibro_changed(VariableItem* item) {
|
||||
static const NotificationSequence sequence_note_c = {
|
||||
&message_note_c5,
|
||||
&message_delay_100,
|
||||
@@ -168,6 +171,59 @@ static void vibro_changed(VariableItem* item) {
|
||||
notification_message(app->notification, &sequence_single_vibro);
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ index 1955012..19d953d 100644
|
||||
static uint32_t notification_app_settings_exit(void* context) {
|
||||
UNUSED(context);
|
||||
return VIEW_NONE;
|
||||
@@ -180,8 +236,40 @@ static NotificationAppSettings* alloc_settings() {
|
||||
@@ -192,8 +248,40 @@ static NotificationAppSettings* alloc_settings() {
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, contrast_text[value_index]);
|
||||
|
||||
@@ -462,54 +462,6 @@ index 0000000..68dacda
|
||||
+ */
|
||||
+const char* rgb_backlight_get_color_text(uint8_t index);
|
||||
\ No newline at end of file
|
||||
diff --git a/firmware/targets/f7/furi_hal/furi_hal_light.c b/firmware/targets/f7/furi_hal/furi_hal_light.c
|
||||
index 83e1603..45798ca 100644
|
||||
--- a/firmware/targets/f7/furi_hal/furi_hal_light.c
|
||||
+++ b/firmware/targets/f7/furi_hal/furi_hal_light.c
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <furi_hal_light.h>
|
||||
#include <lp5562.h>
|
||||
#include <stdint.h>
|
||||
+#include <applications/settings/notification_settings/rgb_backlight.h>
|
||||
|
||||
#define LED_CURRENT_RED 50
|
||||
#define LED_CURRENT_GREEN 50
|
||||
@@ -31,22 +32,21 @@ void furi_hal_light_init() {
|
||||
}
|
||||
|
||||
void furi_hal_light_set(Light light, uint8_t value) {
|
||||
- furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
- if(light & LightRed) {
|
||||
- lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
|
||||
- }
|
||||
- if(light & LightGreen) {
|
||||
- lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
|
||||
- }
|
||||
- if(light & LightBlue) {
|
||||
- lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
|
||||
- }
|
||||
if(light & LightBacklight) {
|
||||
- uint8_t prev = lp5562_get_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite);
|
||||
- lp5562_execute_ramp(
|
||||
- &furi_hal_i2c_handle_power, LP5562Engine1, LP5562ChannelWhite, prev, value, 100);
|
||||
+ rgb_backlight_update(value, false);
|
||||
+ } else {
|
||||
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
+ if(light & LightRed) {
|
||||
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
|
||||
+ }
|
||||
+ if(light & LightGreen) {
|
||||
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
|
||||
+ }
|
||||
+ if(light & LightBlue) {
|
||||
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
|
||||
+ }
|
||||
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
- furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
|
||||
void furi_hal_light_blink_start(Light light, uint8_t brightness, uint16_t on_time, uint16_t period) {
|
||||
diff --git a/lib/drivers/SK6805.c b/lib/drivers/SK6805.c
|
||||
new file mode 100644
|
||||
index 0000000..572e1df
|
||||
@@ -675,3 +627,51 @@ index 0000000..7c58956
|
||||
+
|
||||
+#endif /* SK6805_H_ */
|
||||
\ No newline at end of file
|
||||
diff --git a/targets/f7/furi_hal/furi_hal_light.c b/targets/f7/furi_hal/furi_hal_light.c
|
||||
index 83e1603..45798ca 100644
|
||||
--- a/targets/f7/furi_hal/furi_hal_light.c
|
||||
+++ b/targets/f7/furi_hal/furi_hal_light.c
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <furi_hal_light.h>
|
||||
#include <lp5562.h>
|
||||
#include <stdint.h>
|
||||
+#include <applications/settings/notification_settings/rgb_backlight.h>
|
||||
|
||||
#define LED_CURRENT_RED 50
|
||||
#define LED_CURRENT_GREEN 50
|
||||
@@ -31,22 +32,21 @@ void furi_hal_light_init() {
|
||||
}
|
||||
|
||||
void furi_hal_light_set(Light light, uint8_t value) {
|
||||
- furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
- if(light & LightRed) {
|
||||
- lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
|
||||
- }
|
||||
- if(light & LightGreen) {
|
||||
- lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
|
||||
- }
|
||||
- if(light & LightBlue) {
|
||||
- lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
|
||||
- }
|
||||
if(light & LightBacklight) {
|
||||
- uint8_t prev = lp5562_get_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite);
|
||||
- lp5562_execute_ramp(
|
||||
- &furi_hal_i2c_handle_power, LP5562Engine1, LP5562ChannelWhite, prev, value, 100);
|
||||
+ rgb_backlight_update(value, false);
|
||||
+ } else {
|
||||
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
+ if(light & LightRed) {
|
||||
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
|
||||
+ }
|
||||
+ if(light & LightGreen) {
|
||||
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
|
||||
+ }
|
||||
+ if(light & LightBlue) {
|
||||
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
|
||||
+ }
|
||||
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
- furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
|
||||
void furi_hal_light_blink_start(Light light, uint8_t brightness, uint16_t on_time, uint16_t period) {
|
||||
|
||||
32
.drone.yml
32
.drone.yml
@@ -45,7 +45,9 @@ steps:
|
||||
- export FORCE_NO_DIRTY=yes
|
||||
- export FBT_GIT_SUBMODULE_SHALLOW=1
|
||||
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-base.tgz
|
||||
- tar zxvf all-the-apps-base.tgz
|
||||
- tar zxf all-the-apps-base.tgz
|
||||
- mkdir -p applications/main/clock_app/resources/apps
|
||||
- mkdir -p applications/main/clock_app/resources/apps_data
|
||||
- cp -R base_pack_build/artifacts-base/* applications/main/clock_app/resources/apps/
|
||||
- cp -R base_pack_build/apps_data/* applications/main/clock_app/resources/apps_data/
|
||||
- rm -rf base_pack_build
|
||||
@@ -65,7 +67,8 @@ steps:
|
||||
pull: never
|
||||
commands:
|
||||
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-extra.tgz
|
||||
- tar zxvf all-the-apps-extra.tgz
|
||||
- tar zxf all-the-apps-extra.tgz
|
||||
- mkdir -p applications/main/clock_app/resources/apps
|
||||
- cp -R extra_pack_build/artifacts-extra/* applications/main/clock_app/resources/apps/
|
||||
- rm -rf extra_pack_build
|
||||
- export DIST_SUFFIX=${DRONE_TAG}e
|
||||
@@ -117,7 +120,9 @@ steps:
|
||||
- rm -f build/f7-firmware-C/toolbox/version.*
|
||||
- ./fbt COMPACT=1 DEBUG=0 updater_package
|
||||
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-base.tgz
|
||||
- tar zxvf all-the-apps-base.tgz
|
||||
- tar zxf all-the-apps-base.tgz
|
||||
- mkdir -p applications/main/clock_app/resources/apps
|
||||
- mkdir -p applications/main/clock_app/resources/apps_data
|
||||
- cp -R base_pack_build/artifacts-base/* applications/main/clock_app/resources/apps/
|
||||
- cp -R base_pack_build/apps_data/* applications/main/clock_app/resources/apps_data/
|
||||
- rm -rf base_pack_build
|
||||
@@ -336,9 +341,10 @@ steps:
|
||||
DISCORD_WEBHOOK:
|
||||
from_secret: dis_release_webhook
|
||||
commands:
|
||||
- wget "https://raw.githubusercontent.com/fieu/discord.sh/e1dc1a7595efad2cad8f072f0b3531c470f5b7c8/discord.sh"
|
||||
- wget "https://raw.githubusercontent.com/fieu/discord.sh/2253303efc0e7211ac2777d2535054cbb872f1e0/discord.sh"
|
||||
- chmod +x ./discord.sh
|
||||
- ./discord.sh --text 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://github.com/xMasterX/all-the-plugins/releases/latest)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version with only main apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'c.tgz&channel=release-cfw&version='${DRONE_TAG}'c)\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with RGB patch - only for hardware mod! - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz&channel=release-cfw&version='${DRONE_TAG}'r)\n\n[-Version with RGB patch - only for hardware mod! - Direct download-](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz)\n\n[-Version with Extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)'
|
||||
- echo 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://github.com/xMasterX/all-the-plugins/releases/latest)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version with only main apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'c.tgz&channel=release-cfw&version='${DRONE_TAG}'c)\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with RGB patch - only for hardware mod! - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz&channel=release-cfw&version='${DRONE_TAG}'r)\n\n[-Version with RGB patch - only for hardware mod! - Direct download-](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'r.tgz)\n\n[-Version with Extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)' > messagedisc.txt
|
||||
- ./discord.sh --text "$(jq -Rs . <messagedisc.txt | cut -c 2- | rev | cut -c 2- | rev)"
|
||||
|
||||
- name: "Send clean build to telegram"
|
||||
image: appleboy/drone-telegram
|
||||
@@ -369,7 +375,7 @@ trigger:
|
||||
- tag
|
||||
|
||||
node:
|
||||
typ: haupt
|
||||
typ: dev1
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
@@ -420,7 +426,9 @@ steps:
|
||||
- export FORCE_NO_DIRTY=yes
|
||||
- export FBT_GIT_SUBMODULE_SHALLOW=1
|
||||
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-base.tgz
|
||||
- tar zxvf all-the-apps-base.tgz
|
||||
- tar zxf all-the-apps-base.tgz
|
||||
- mkdir -p applications/main/clock_app/resources/apps
|
||||
- mkdir -p applications/main/clock_app/resources/apps_data
|
||||
- cp -R base_pack_build/artifacts-base/* applications/main/clock_app/resources/apps/
|
||||
- cp -R base_pack_build/apps_data/* applications/main/clock_app/resources/apps_data/
|
||||
- rm -rf base_pack_build
|
||||
@@ -440,7 +448,8 @@ steps:
|
||||
pull: never
|
||||
commands:
|
||||
- wget https://github.com/xMasterX/all-the-plugins/releases/latest/download/all-the-apps-extra.tgz
|
||||
- tar zxvf all-the-apps-extra.tgz
|
||||
- tar zxf all-the-apps-extra.tgz
|
||||
- mkdir -p applications/main/clock_app/resources/apps
|
||||
- cp -R extra_pack_build/artifacts-extra/* applications/main/clock_app/resources/apps/
|
||||
- rm -rf extra_pack_build
|
||||
- export DIST_SUFFIX=${DRONE_BUILD_NUMBER}e
|
||||
@@ -657,9 +666,10 @@ steps:
|
||||
DISCORD_WEBHOOK:
|
||||
from_secret: dis_dev_webhook
|
||||
commands:
|
||||
- wget "https://raw.githubusercontent.com/fieu/discord.sh/e1dc1a7595efad2cad8f072f0b3531c470f5b7c8/discord.sh"
|
||||
- wget "https://raw.githubusercontent.com/fieu/discord.sh/2253303efc0e7211ac2777d2535054cbb872f1e0/discord.sh"
|
||||
- chmod +x ./discord.sh
|
||||
- ./discord.sh --text 'Unleashed firmware dev build successful!\n\nBuild - '${DRONE_BUILD_NUMBER}'\n\nCommit - https://github.com/DarkFlippers/unleashed-firmware/commit/'${DRONE_COMMIT_SHA}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[-Version with Extra apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'e.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'e)\n\n[-Version with only main apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'c.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'c)\n\n[-Version with RGB patch - only for hardware mod! - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'r.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'r)\n\n[-Version with RGB patch - only for hardware mod! - Direct download-](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'r.tgz)\n\n[-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}')'
|
||||
- echo 'Unleashed firmware dev build successful!\n\nBuild - '${DRONE_BUILD_NUMBER}'\n\nCommit - https://github.com/DarkFlippers/unleashed-firmware/commit/'${DRONE_COMMIT_SHA}'\n\n[-> Sponsor our project](https://boosty.to/mmxdev)\n\n[-Version with Extra apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'e.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'e)\n\n[-Version with only main apps - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'c.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'c)\n\n[-Version with RGB patch - only for hardware mod! - Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'r.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}'r)\n\n[-Version with RGB patch - only for hardware mod! - Direct download-](https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'r.tgz)\n\n[-Install via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/dev/flipper-z-f7-update-'${DRONE_BUILD_NUMBER}'.tgz&channel=dev-cfw&version='${DRONE_BUILD_NUMBER}')' > messagedisc.txt
|
||||
- ./discord.sh --text "$(jq -Rs . <messagedisc.txt | cut -c 2- | rev | cut -c 2- | rev)"
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
@@ -668,4 +678,4 @@ trigger:
|
||||
- push
|
||||
|
||||
node:
|
||||
typ: haupt
|
||||
typ: dev1
|
||||
|
||||
@@ -1 +1 @@
|
||||
--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/*
|
||||
--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/microtar -e lib/mlib -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/*
|
||||
|
||||
71
CHANGELOG.md
71
CHANGELOG.md
@@ -1,13 +1,60 @@
|
||||
## New changes
|
||||
* SubGHz: Add 4 more systems to Add Manually (untested!)
|
||||
* SubGHz: Add Manually fixes
|
||||
* SubGHz: Added NiceFlor-S to ignore options, removed colons. (by @G2Dolphin | PR #620)
|
||||
* Misc code cleanup
|
||||
* RGB: Fix white color on reboot, move settings, add custom color option
|
||||
* **BLE Spam app** updated to latest version (Android, Windows support) (by @Willy-JL) -> (app can be found in builds ` `, `e`, `n`, `r`)
|
||||
* OFW: Fix double arrows and add proper indication
|
||||
* OFW: SubGHz: add manually fix 12-bits is 0xFFF (or 0xFF0) CAME/NICE 12-bit
|
||||
* OFW: Fix various crashes if debug libraries used
|
||||
* NFC: **Fixed stuck Saved success screen**
|
||||
* NFC: **Fixed crash when reading mifare classic tag then going to add manually menu and adding NFC-A tag**
|
||||
* NFC: Fixed EMV txs render
|
||||
* NFC/LFRFID: Don't Stop emulation after 5 mins to avoid antenna damage if debug is ON (by @Leptopt1los)
|
||||
* LFRFID: Fixed T5577 custom password input (by @Leptopt1los)
|
||||
* OFW PR 3410: lfrfid/em4100: added support for different bit rates - by @Mrkvak (RF/32 full support, RF/16 support without reading (16clk removed for now))
|
||||
* OFW PR 3412: Fixed MyKey LockID - by @zProAle
|
||||
<br>----<br>
|
||||
**Changes from 070 release:**<br>
|
||||
* NFC: **EMV parser** added (by @Leptopt1los and @wosk | PR #700)
|
||||
* NFC: Metromoney parser balance fix (by @Leptopt1los | PR #699)
|
||||
* NFC/LFRFID: Stop emulation after 5 mins to avoid antenna damage (by @Leptopt1los)
|
||||
* Archive: Fix two filebrowser bugs
|
||||
* SubGHz: **Programming mode for Dea Mio** (right arrow button)
|
||||
* SubGHz: **Keeloq fix emulation for multiple systems and extend add manually support** for 2 of them (Dea Mio, Genius Bravo, GSN, Normstahl)
|
||||
* SubGHz: Fixed hopper state when entering Read via Freq analyzer
|
||||
* SubGHz: Raw erase fixes (by @Willy-JL)
|
||||
* SubGHz: Subghz save files with receive time (by @Willy-JL)
|
||||
* NFC: Fix NFC V dumps with v3 (pre refactor saves) crashing at info page
|
||||
* NFC: Zolotaya Korona Online parser added (by @Leptopt1los)
|
||||
* NFC: Add NFC **NDEF parser** (by @Willy-JL)
|
||||
* LF RFID: **Write T5577 with random and custom password** added (clear password via Extra actions) (by @Leptopt1los)
|
||||
* SubGHz: Update honeywell protocol (by @Willy-JL)
|
||||
* System: More contrast values for replacement displays (up to +8 or -8)
|
||||
* USB/BLE HID: Add macOS Music app volume control
|
||||
* Apps: **Check out Apps updates by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev)
|
||||
* OFW PR 3384: NFC: Display unread Mifare Classic bytes as question marks - by @TollyH
|
||||
* OFW PR 3396: NFC: **fix application opening from browser** - by @RebornedBrain (+ fix for leftover issues)
|
||||
* OFW PR 3382: NFC UI refactor - by @RebornedBrain
|
||||
* OFW PR 3391: Rework more info scene for Ultralight cards - by @RebornedBrain
|
||||
* OFW PR 3401: it-IT-mac layout - by @nminaylov
|
||||
* OFW: Fix expansion protocol crash when fed lots of garbage
|
||||
* OFW: 0.98.0-rc various fixes
|
||||
* OFW: RFID CLI: better usage
|
||||
* OFW: **Mf DESFire fixes**
|
||||
* OFW: NFC UI refactor
|
||||
* OFW: **Expansion module protocol** (+ expansion settings read and store in ram by @Willy-JL)
|
||||
* OFW: Bugfix: Strip last parity bit from decoded FDX-B data
|
||||
* OFW: FuriHal: interrupt priorities and documentation
|
||||
* OFW: FuriHal: **UART refactoring**
|
||||
* OFW: SubGhz: add `subghz tx_from_file` CLI cmd, major TX flow refactoring, various improvements and bug fixes
|
||||
* OFW: Furi_hal_rtc: new function
|
||||
* OFW: NFC UI refactor
|
||||
* OFW: assets: checking limits on image size; ufbt: cdb target
|
||||
* OFW: NFC: system dict skip when user dict is skipped fix (replaces our fix)
|
||||
* OFW: FuriHal: fix start duration furi_hal_subghz_async_tx
|
||||
* OFW: NFC: parsers minor cleanup
|
||||
* OFW: NFC Ntag success write freeze when not saved card
|
||||
* OFW: ufbt: fixed generated project paths on Windows
|
||||
<br><br>
|
||||
#### Known NFC post-refactor regressions list:
|
||||
- Mifare Mini clones reading is broken (original mini working fine) (OFW)
|
||||
- Option to unlock Slix-L (NFC V) with preset or custom password was removed with refactoring (OFW)
|
||||
- NFC CLI was removed with refactoring (OFW)
|
||||
- Current list of affected apps: https://github.com/xMasterX/all-the-plugins/tree/dev/apps_broken_by_last_refactors
|
||||
- Also in app **Enhanced Sub-GHz Chat** - NFC part was temporarily removed to make app usable, NFC part of the app requires remaking it with new nfc stack
|
||||
|
||||
----
|
||||
|
||||
@@ -31,8 +78,8 @@
|
||||
|XMR|(Monero)| `41xUz92suUu1u5Mu4qkrcs52gtfpu9rnZRdBpCJ244KRHf6xXSvVFevdf2cnjS7RAeYr5hn9MsEfxKoFDRSctFjG5fv1Mhn`|
|
||||
|TON||`EQCOqcnYkvzOZUV_9bPE_8oTbOrOF03MnF-VcJyjisTZmpGf`|
|
||||
|
||||
#### Thanks to our sponsors:
|
||||
callmezimbra, Quen0n, MERRON, grvpvl (lvpvrg), art_col, ThurstonWaffles, Moneron, UterGrooll, LUCFER, Northpirate, zloepuzo, T.Rat, Alexey B., ionelife, ...
|
||||
#### Thanks to our sponsors who supported project in the past and special thanks to sponsors who supports us on regular basis:
|
||||
ClaraCrazy, Pathfinder [Count Zero cDc], callmezimbra, Quen0n, MERRON, grvpvl (lvpvrg), art_col, ThurstonWaffles, Moneron, UterGrooll, LUCFER, Northpirate, zloepuzo, T.Rat, Alexey B., ionelife, ...
|
||||
and all other great people who supported our project and me (xMasterX), thanks to you all!
|
||||
|
||||
|
||||
@@ -50,7 +97,7 @@ What build I should download and what this name means - `flipper-z-f7-update-(ve
|
||||
| `c` | ✅ | | | |
|
||||
| `n` | | ✅ | | |
|
||||
| `e` | ✅ | ✅ | ✅ | |
|
||||
| `r` | ✅ | ✅ | ✅ | ✅ |
|
||||
| `r` | ✅ | ✅ | ✅ | ⚠️ |
|
||||
|
||||
⚠️This is [hardware mod](https://github.com/quen0n/flipperzero-firmware-rgb#readme), works only on modded flippers! do not install on non modded device!
|
||||
|
||||
|
||||
34
ReadMe.md
34
ReadMe.md
@@ -55,7 +55,7 @@
|
||||
- New frequency analyzer [(by ClusterM)](https://github.com/DarkFlippers/unleashed-firmware/pull/43)
|
||||
- Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
|
||||
- Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79)
|
||||
- New option to use timestamps + protocol name when you saving file, instead of random name - Enable in `Radio Settings -> Time in names = ON`
|
||||
- New option to use timestamps + protocol name when you saving file, instead of random name or timestamp only - Enable in `Radio Settings -> Protocol Names = ON`
|
||||
- Read mode UI improvements (shows time when signal was received) (by @wosk)
|
||||
- External CC1101 module support (Hardware SPI used)
|
||||
- **Hold right in received signal list to delete selected signal**
|
||||
@@ -79,8 +79,10 @@
|
||||
- **NFC/RFID/iButton**
|
||||
* LFRFID/iButton Fuzzer plugins
|
||||
* Extra Mifare Classic keys
|
||||
* `Add manually` -> Mifare Classic with custom UID
|
||||
* Picopass/iClass plugin (now with emulation support!) included in releases
|
||||
* EMV Protocol + Public data parser (by @Leptopt1los and @wosk)
|
||||
* NFC/LFRFID - Stop emulation after 5 mins to avoid antenna damage (by @Leptopt1los)
|
||||
* NFC `Add manually` -> Mifare Classic with custom UID
|
||||
* NFC parsers: Umarsh, Zolotaya Korona, Kazan, Metromoney, Moscow Social Card, Troika (reworked) and [many others](https://github.com/DarkFlippers/unleashed-firmware/tree/dev/applications/main/nfc/plugins/supported_cards) (by @Leptopt1los and @assasinfil)
|
||||
- **Quality of life & other features**
|
||||
- Customizable Flipper name **Update! Now can be changed in Settings->Desktop** (by @xMasterX and @Willy-JL)
|
||||
- Text Input UI element -> Cursor feature (by @Willy-JL)
|
||||
@@ -100,25 +102,12 @@ Also check the [changelog in releases](https://github.com/DarkFlippers/unleashed
|
||||
### Current modified and new Sub-GHz protocols list:
|
||||
Thanks to Official team (to their SubGHz Developer, Skorp) for implementing decoders for these protocols in OFW.
|
||||
|
||||
Keeloq [Not ALL systems supported for decode or emulation yet!] - [Supported manufacturers list](https://0bin.net/paste/VwR2lNJY#WH9vnPgvcp7w6zVKucFCuNREKAcOij8KsJ6vqLfMn3b)
|
||||
Keeloq [Not ALL systems supported for decode or emulation!] - [Supported manufacturers list](https://pastes.io/raw/unuj9bhe4m)
|
||||
|
||||
Encoders or sending made by @xMasterX:
|
||||
- Nero Radio 57bit (+ 56bit encoder improvements)
|
||||
- CAME 12bit/24bit encoder fixes (Fixes now merged in OFW)
|
||||
- Keeloq: HCS101
|
||||
- Keeloq: AN-Motors
|
||||
- Keeloq: JCM Tech
|
||||
- Keeloq: MHouse
|
||||
- Keeloq: Nice Smilo
|
||||
- Keeloq: DTM Neo
|
||||
- Keeloq: FAAC RC,XT
|
||||
- Keeloq: Mutancode
|
||||
- Keeloq: Normstahl
|
||||
- Keeloq: Beninca + Allmatic
|
||||
- Keeloq: Stilmatic
|
||||
- Keeloq: CAME Space
|
||||
- Keeloq: Aprimatic (model TR and similar)
|
||||
- Keeloq: Centurion Nova (thanks Carlos !)
|
||||
- Keeloq: HCS101, AN-Motors, JCM Tech, MHouse, Nice Smilo, DTM Neo, FAAC RC,XT, Mutancode, Normstahl, Beninca + Allmatic, Stilmatic, CAME Space, Aprimatic (model TR and similar), Centurion Nova (thanks Carlos !)
|
||||
|
||||
Encoders or sending made by @Eng1n33r(first implementation in Q2 2022) & @xMasterX (current version):
|
||||
- CAME Atomo -> Update! check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
@@ -139,10 +128,11 @@ Encoders made by @assasinfil & @xMasterX:
|
||||
The majority of this project is developed and maintained by me, @xMasterX.
|
||||
I'm unemployed, and the only income I receive is from your donations.
|
||||
Our team is small and the guys are working on this project as much as they can solely based on the enthusiasm they have for this project and the community.
|
||||
- @Leptopt1los - NFC, RFID, IR Assets (only ACs), Plugins, and many other things
|
||||
- @gid9798 - SubGHz, Plugins, many other things
|
||||
- @assasinfil - SubGHz protocols
|
||||
- @assasinfil - SubGHz protocols, NFC parsers
|
||||
- @Svaarich - UI design and animations
|
||||
- @amec0e & @Leptopt1los - Infrared assets
|
||||
- @amec0e - Infrared assets
|
||||
- Community moderators in Telegram, Discord, and Reddit
|
||||
- And of course our GitHub community. Your PRs are a very important part of this firmware and open-source development.
|
||||
|
||||
@@ -167,14 +157,14 @@ You can support us by using links or addresses below:
|
||||
## Community apps included
|
||||
|
||||
### [🎲 Download Extra plugins for Unleashed](https://github.com/xMasterX/all-the-plugins/releases/latest)
|
||||
### [List of Extra pack](https://github.com/xMasterX/all-the-plugins/tree/dev#extra-pack) | [List of Base *(Deafult)* pack](https://github.com/xMasterX/all-the-plugins/tree/dev#default-pack)
|
||||
### [List of Extra pack](https://github.com/xMasterX/all-the-plugins/tree/dev#extra-pack) | [List of Base *(Default)* pack](https://github.com/xMasterX/all-the-plugins/tree/dev#default-pack)
|
||||
|
||||
See full list and sources here: [xMasterX/all-the-plugins](https://github.com/xMasterX/all-the-plugins/tree/dev)
|
||||
|
||||
### Official Flipper Zero Apps Catalog [web version](https://lab.flipper.net/apps) or mobile app
|
||||
|
||||
# Instructions
|
||||
## First lock official docs [docs.flipper.net](https://docs.flipper.net/)
|
||||
## First look at official docs [docs.flipper.net](https://docs.flipper.net/)
|
||||
## [How to install](/documentation/HowToInstall.md) - [versions info](/CHANGELOG.md#recommended-update-option---web-updater): `n`,` `,`e`...
|
||||
## Firmware & Development
|
||||
|
||||
|
||||
49
SConstruct
49
SConstruct
@@ -172,17 +172,19 @@ Alias("fap_dist", fap_dist)
|
||||
|
||||
fap_deploy = distenv.PhonyTarget(
|
||||
"fap_deploy",
|
||||
[
|
||||
Action(
|
||||
[
|
||||
"${PYTHON3}",
|
||||
"${FBT_SCRIPT_DIR}/storage.py",
|
||||
"-p",
|
||||
"${FLIP_PORT}",
|
||||
"send",
|
||||
"${SOURCE}",
|
||||
"/ext/apps",
|
||||
[
|
||||
"${PYTHON3}",
|
||||
"${FBT_SCRIPT_DIR}/storage.py",
|
||||
"-p",
|
||||
"${FLIP_PORT}",
|
||||
"send",
|
||||
"${SOURCE}",
|
||||
"/ext/apps",
|
||||
]
|
||||
]
|
||||
],
|
||||
),
|
||||
source=firmware_env.Dir(("${RESOURCES_ROOT}/apps")),
|
||||
)
|
||||
Depends(fap_deploy, firmware_env["FW_RESOURCES_MANIFEST"])
|
||||
@@ -261,7 +263,7 @@ distenv.PhonyTarget(
|
||||
distenv.PhonyTarget(
|
||||
"debug_other_blackmagic",
|
||||
"${GDBPYCOM}",
|
||||
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
|
||||
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
|
||||
GDBREMOTE="${BLACKMAGIC_ADDR}",
|
||||
GDBPYOPTS=debug_other_opts,
|
||||
)
|
||||
@@ -276,23 +278,27 @@ distenv.PhonyTarget(
|
||||
# Linter
|
||||
distenv.PhonyTarget(
|
||||
"lint",
|
||||
"${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py check ${LINT_SOURCES}",
|
||||
[["${PYTHON3}", "${FBT_SCRIPT_DIR}/lint.py", "check", "${LINT_SOURCES}"]],
|
||||
LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]],
|
||||
)
|
||||
|
||||
distenv.PhonyTarget(
|
||||
"format",
|
||||
"${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py format ${LINT_SOURCES}",
|
||||
[["${PYTHON3}", "${FBT_SCRIPT_DIR}/lint.py", "format", "${LINT_SOURCES}"]],
|
||||
LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]],
|
||||
)
|
||||
|
||||
# PY_LINT_SOURCES contains recursively-built modules' SConscript files + application manifests
|
||||
# PY_LINT_SOURCES contains recursively-built modules' SConscript files
|
||||
# Here we add additional Python files residing in repo root
|
||||
firmware_env.Append(
|
||||
PY_LINT_SOURCES=[
|
||||
# Py code folders
|
||||
"site_scons",
|
||||
"scripts",
|
||||
"applications",
|
||||
"applications_user",
|
||||
"assets",
|
||||
"targets",
|
||||
# Extra files
|
||||
"SConstruct",
|
||||
"firmware.scons",
|
||||
@@ -302,7 +308,10 @@ firmware_env.Append(
|
||||
|
||||
|
||||
black_commandline = "@${PYTHON3} -m black ${PY_BLACK_ARGS} ${PY_LINT_SOURCES}"
|
||||
black_base_args = ["--include", '"\\.scons|\\.py|SConscript|SConstruct"']
|
||||
black_base_args = [
|
||||
"--include",
|
||||
'"(\\.scons|\\.py|SConscript|SConstruct|\\.fam)$"',
|
||||
]
|
||||
|
||||
distenv.PhonyTarget(
|
||||
"lint_py",
|
||||
@@ -323,10 +332,14 @@ distenv.PhonyTarget(
|
||||
)
|
||||
|
||||
# Start Flipper CLI via PySerial's miniterm
|
||||
distenv.PhonyTarget("cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py -p ${FLIP_PORT}")
|
||||
distenv.PhonyTarget(
|
||||
"cli", [["${PYTHON3}", "${FBT_SCRIPT_DIR}/serial_cli.py", "-p", "${FLIP_PORT}"]]
|
||||
)
|
||||
|
||||
# Update WiFi devboard firmware
|
||||
distenv.PhonyTarget("devboard_flash", "${PYTHON3} ${FBT_SCRIPT_DIR}/wifi_board.py")
|
||||
distenv.PhonyTarget(
|
||||
"devboard_flash", [["${PYTHON3}", "${FBT_SCRIPT_DIR}/wifi_board.py"]]
|
||||
)
|
||||
|
||||
|
||||
# Find blackmagic probe
|
||||
@@ -356,10 +369,10 @@ vscode_dist = distenv.Install(
|
||||
)
|
||||
distenv.Precious(vscode_dist)
|
||||
distenv.NoClean(vscode_dist)
|
||||
distenv.Alias("vscode_dist", vscode_dist)
|
||||
distenv.Alias("vscode_dist", (vscode_dist, firmware_env["FW_CDB"]))
|
||||
|
||||
# Configure shell with build tools
|
||||
distenv.PhonyTarget(
|
||||
"env",
|
||||
"@echo $( ${FBT_SCRIPT_DIR}/toolchain/fbtenv.sh $)",
|
||||
"@echo $( ${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh $)",
|
||||
)
|
||||
|
||||
@@ -40,7 +40,6 @@ Applications for main Flipper menu.
|
||||
Background services providing system APIs to applications.
|
||||
|
||||
- `applications.h` - Firmware application list header
|
||||
|
||||
- `bt` - BLE service and application
|
||||
- `cli` - Console service and API
|
||||
- `crypto` - Crypto cli tools
|
||||
|
||||
@@ -4,7 +4,6 @@ App(
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
targets=["f7"],
|
||||
entry_point="accessor_app",
|
||||
cdefines=["APP_ACCESSOR"],
|
||||
requires=["gui"],
|
||||
stack_size=4 * 1024,
|
||||
order=40,
|
||||
|
||||
@@ -3,7 +3,6 @@ App(
|
||||
name="Battery Test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="battery_test_app",
|
||||
cdefines=["APP_BATTERY_TEST"],
|
||||
requires=[
|
||||
"gui",
|
||||
"power",
|
||||
|
||||
@@ -3,7 +3,6 @@ App(
|
||||
name="Blink Test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="blink_test_app",
|
||||
cdefines=["APP_BLINK"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=10,
|
||||
|
||||
@@ -3,7 +3,6 @@ App(
|
||||
name="CCID Debug",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="ccid_test_app",
|
||||
cdefines=["CCID_TEST"],
|
||||
requires=[
|
||||
"gui",
|
||||
],
|
||||
|
||||
@@ -13,12 +13,12 @@ struct ISO7816_Command_APDU {
|
||||
//body
|
||||
uint8_t Lc;
|
||||
uint8_t Le;
|
||||
} __attribute__((packed));
|
||||
} FURI_PACKED;
|
||||
|
||||
struct ISO7816_Response_APDU {
|
||||
uint8_t SW1;
|
||||
uint8_t SW2;
|
||||
} __attribute__((packed));
|
||||
} FURI_PACKED;
|
||||
|
||||
void iso7816_answer_to_reset(uint8_t* atrBuffer, uint32_t* atrlen);
|
||||
void iso7816_read_command_apdu(
|
||||
|
||||
@@ -3,7 +3,6 @@ App(
|
||||
name="Crash Test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="crash_test_app",
|
||||
cdefines=["APP_CRASH_TEST"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
fap_category="Debug",
|
||||
|
||||
@@ -3,9 +3,8 @@ App(
|
||||
name="Display Test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="display_test_app",
|
||||
cdefines=["APP_DISPLAY_TEST"],
|
||||
requires=["gui"],
|
||||
fap_libs=["misc"],
|
||||
fap_libs=["u8g2"],
|
||||
stack_size=1 * 1024,
|
||||
order=120,
|
||||
fap_category="Debug",
|
||||
|
||||
12
applications/debug/expansion_test/application.fam
Normal file
12
applications/debug/expansion_test/application.fam
Normal file
@@ -0,0 +1,12 @@
|
||||
App(
|
||||
appid="expansion_test",
|
||||
name="Expansion Module Test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="expansion_test_app",
|
||||
requires=["expansion_start"],
|
||||
fap_libs=["assets"],
|
||||
stack_size=1 * 1024,
|
||||
order=20,
|
||||
fap_category="Debug",
|
||||
fap_file_assets="assets",
|
||||
)
|
||||
9
applications/debug/expansion_test/assets/test.txt
Normal file
9
applications/debug/expansion_test/assets/test.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
"Did you ever hear the tragedy of Darth Plagueis the Wise?"
|
||||
"No."
|
||||
"I thought not. It's not a story the Jedi would tell you. It's a Sith legend. Darth Plagueis... was a Dark Lord of the Sith so powerful and so wise, he could use the Force to influence the midi-chlorians... to create... life. He had such a knowledge of the dark side, he could even keep the ones he cared about... from dying."
|
||||
"He could actually... save people from death?"
|
||||
"The dark side of the Force is a pathway to many abilities... some consider to be unnatural."
|
||||
"Wh– What happened to him?"
|
||||
"He became so powerful, the only thing he was afraid of was... losing his power. Which eventually, of course, he did. Unfortunately, he taught his apprentice everything he knew. Then his apprentice killed him in his sleep. It's ironic. He could save others from death, but not himself."
|
||||
"Is it possible to learn this power?"
|
||||
"Not from a Jedi."
|
||||
457
applications/debug/expansion_test/expansion_test.c
Normal file
457
applications/debug/expansion_test/expansion_test.c
Normal file
@@ -0,0 +1,457 @@
|
||||
/**
|
||||
* @file expansion_test.c
|
||||
* @brief Expansion module support testing application.
|
||||
*
|
||||
* Before running, connect pins using the following scheme:
|
||||
* 13 -> 16 (USART TX to LPUART RX)
|
||||
* 14 -> 15 (USART RX to LPUART TX)
|
||||
*
|
||||
* What this application does:
|
||||
*
|
||||
* - Enables module support and emulates the module on a single device
|
||||
* (hence the above connection),
|
||||
* - Connects to the expansion module service, sets baud rate,
|
||||
* - Starts the RPC session,
|
||||
* - Creates a directory at `/ext/ExpansionTest` and writes a file
|
||||
* named `test.txt` under it,
|
||||
* - Plays an audiovisual alert (sound and blinking display),
|
||||
* - Waits 10 cycles of idle loop,
|
||||
* - Stops the RPC session,
|
||||
* - Waits another 10 cycles of idle loop,
|
||||
* - Exits (plays a sound if any of the above steps failed).
|
||||
*/
|
||||
#include <furi.h>
|
||||
|
||||
#include <furi_hal_resources.h>
|
||||
|
||||
#include <furi_hal_serial.h>
|
||||
#include <furi_hal_serial_control.h>
|
||||
|
||||
#include <pb.h>
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
|
||||
#include <flipper.pb.h>
|
||||
|
||||
#include <storage/storage.h>
|
||||
#include <expansion/expansion.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <expansion/expansion_protocol.h>
|
||||
|
||||
#define TAG "ExpansionTest"
|
||||
|
||||
#define TEST_DIR_PATH EXT_PATH(TAG)
|
||||
#define TEST_FILE_NAME "test.txt"
|
||||
#define TEST_FILE_PATH EXT_PATH(TAG "/" TEST_FILE_NAME)
|
||||
|
||||
#define HOST_SERIAL_ID (FuriHalSerialIdLpuart)
|
||||
#define MODULE_SERIAL_ID (FuriHalSerialIdUsart)
|
||||
|
||||
#define RECEIVE_BUFFER_SIZE (sizeof(ExpansionFrame) + sizeof(ExpansionFrameChecksum))
|
||||
|
||||
typedef enum {
|
||||
ExpansionTestAppFlagData = 1U << 0,
|
||||
ExpansionTestAppFlagExit = 1U << 1,
|
||||
} ExpansionTestAppFlag;
|
||||
|
||||
#define EXPANSION_TEST_APP_ALL_FLAGS (ExpansionTestAppFlagData | ExpansionTestAppFlagExit)
|
||||
|
||||
typedef struct {
|
||||
FuriThreadId thread_id;
|
||||
Expansion* expansion;
|
||||
FuriHalSerialHandle* handle;
|
||||
FuriStreamBuffer* buf;
|
||||
ExpansionFrame frame;
|
||||
PB_Main msg;
|
||||
Storage* storage;
|
||||
} ExpansionTestApp;
|
||||
|
||||
static void expansion_test_app_serial_rx_callback(
|
||||
FuriHalSerialHandle* handle,
|
||||
FuriHalSerialRxEvent event,
|
||||
void* context) {
|
||||
furi_assert(handle);
|
||||
furi_assert(context);
|
||||
ExpansionTestApp* app = context;
|
||||
|
||||
if(event == FuriHalSerialRxEventData) {
|
||||
const uint8_t data = furi_hal_serial_async_rx(handle);
|
||||
furi_stream_buffer_send(app->buf, &data, sizeof(data), 0);
|
||||
furi_thread_flags_set(app->thread_id, ExpansionTestAppFlagData);
|
||||
}
|
||||
}
|
||||
|
||||
static ExpansionTestApp* expansion_test_app_alloc() {
|
||||
ExpansionTestApp* instance = malloc(sizeof(ExpansionTestApp));
|
||||
instance->buf = furi_stream_buffer_alloc(RECEIVE_BUFFER_SIZE, 1);
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void expansion_test_app_free(ExpansionTestApp* instance) {
|
||||
furi_stream_buffer_free(instance->buf);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
static void expansion_test_app_start(ExpansionTestApp* instance) {
|
||||
instance->thread_id = furi_thread_get_current_id();
|
||||
instance->expansion = furi_record_open(RECORD_EXPANSION);
|
||||
instance->handle = furi_hal_serial_control_acquire(MODULE_SERIAL_ID);
|
||||
furi_check(instance->handle);
|
||||
// Configure the serial port
|
||||
furi_hal_serial_init(instance->handle, EXPANSION_PROTOCOL_DEFAULT_BAUD_RATE);
|
||||
// Start waiting for the initial pulse
|
||||
expansion_set_listen_serial(instance->expansion, HOST_SERIAL_ID);
|
||||
|
||||
furi_hal_serial_async_rx_start(
|
||||
instance->handle, expansion_test_app_serial_rx_callback, instance, false);
|
||||
}
|
||||
|
||||
static void expansion_test_app_stop(ExpansionTestApp* instance) {
|
||||
// Disable expansion module support
|
||||
expansion_disable(instance->expansion);
|
||||
// Give back the module handle
|
||||
furi_hal_serial_control_release(instance->handle);
|
||||
// Restore expansion user settings
|
||||
expansion_enable(instance->expansion);
|
||||
furi_record_close(RECORD_EXPANSION);
|
||||
}
|
||||
|
||||
static inline bool expansion_test_app_is_success_response(const ExpansionFrame* response) {
|
||||
return response->header.type == ExpansionFrameTypeStatus &&
|
||||
response->content.status.error == ExpansionFrameErrorNone;
|
||||
}
|
||||
|
||||
static inline bool expansion_test_app_is_success_rpc_message(const PB_Main* message) {
|
||||
return (message->command_status == PB_CommandStatus_OK ||
|
||||
message->command_status == PB_CommandStatus_ERROR_STORAGE_EXIST) &&
|
||||
(message->which_content == PB_Main_empty_tag);
|
||||
}
|
||||
|
||||
static size_t expansion_test_app_receive_callback(uint8_t* data, size_t data_size, void* context) {
|
||||
ExpansionTestApp* instance = context;
|
||||
|
||||
size_t received_size = 0;
|
||||
|
||||
while(true) {
|
||||
received_size += furi_stream_buffer_receive(
|
||||
instance->buf, data + received_size, data_size - received_size, 0);
|
||||
if(received_size == data_size) break;
|
||||
|
||||
const uint32_t flags = furi_thread_flags_wait(
|
||||
EXPANSION_TEST_APP_ALL_FLAGS, FuriFlagWaitAny, EXPANSION_PROTOCOL_TIMEOUT_MS);
|
||||
|
||||
// Exit on any error
|
||||
if(flags & FuriFlagError) break;
|
||||
}
|
||||
|
||||
return received_size;
|
||||
}
|
||||
|
||||
static size_t
|
||||
expansion_test_app_send_callback(const uint8_t* data, size_t data_size, void* context) {
|
||||
ExpansionTestApp* instance = context;
|
||||
|
||||
furi_hal_serial_tx(instance->handle, data, data_size);
|
||||
furi_hal_serial_tx_wait_complete(instance->handle);
|
||||
|
||||
return data_size;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_receive_frame(ExpansionTestApp* instance, ExpansionFrame* frame) {
|
||||
return expansion_protocol_decode(frame, expansion_test_app_receive_callback, instance) ==
|
||||
ExpansionProtocolStatusOk;
|
||||
}
|
||||
|
||||
static bool
|
||||
expansion_test_app_send_status_response(ExpansionTestApp* instance, ExpansionFrameError error) {
|
||||
ExpansionFrame frame = {
|
||||
.header.type = ExpansionFrameTypeStatus,
|
||||
.content.status.error = error,
|
||||
};
|
||||
return expansion_protocol_encode(&frame, expansion_test_app_send_callback, instance) ==
|
||||
ExpansionProtocolStatusOk;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_send_heartbeat(ExpansionTestApp* instance) {
|
||||
ExpansionFrame frame = {
|
||||
.header.type = ExpansionFrameTypeHeartbeat,
|
||||
.content.heartbeat = {},
|
||||
};
|
||||
return expansion_protocol_encode(&frame, expansion_test_app_send_callback, instance) ==
|
||||
ExpansionProtocolStatusOk;
|
||||
}
|
||||
|
||||
static bool
|
||||
expansion_test_app_send_baud_rate_request(ExpansionTestApp* instance, uint32_t baud_rate) {
|
||||
ExpansionFrame frame = {
|
||||
.header.type = ExpansionFrameTypeBaudRate,
|
||||
.content.baud_rate.baud = baud_rate,
|
||||
};
|
||||
return expansion_protocol_encode(&frame, expansion_test_app_send_callback, instance) ==
|
||||
ExpansionProtocolStatusOk;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_send_control_request(
|
||||
ExpansionTestApp* instance,
|
||||
ExpansionFrameControlCommand command) {
|
||||
ExpansionFrame frame = {
|
||||
.header.type = ExpansionFrameTypeControl,
|
||||
.content.control.command = command,
|
||||
};
|
||||
return expansion_protocol_encode(&frame, expansion_test_app_send_callback, instance) ==
|
||||
ExpansionProtocolStatusOk;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_send_data_request(
|
||||
ExpansionTestApp* instance,
|
||||
const uint8_t* data,
|
||||
size_t data_size) {
|
||||
furi_assert(data_size <= EXPANSION_PROTOCOL_MAX_DATA_SIZE);
|
||||
|
||||
ExpansionFrame frame = {
|
||||
.header.type = ExpansionFrameTypeData,
|
||||
.content.data.size = data_size,
|
||||
};
|
||||
|
||||
memcpy(frame.content.data.bytes, data, data_size);
|
||||
return expansion_protocol_encode(&frame, expansion_test_app_send_callback, instance) ==
|
||||
ExpansionProtocolStatusOk;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_rpc_encode_callback(
|
||||
pb_ostream_t* stream,
|
||||
const pb_byte_t* data,
|
||||
size_t data_size) {
|
||||
ExpansionTestApp* instance = stream->state;
|
||||
|
||||
size_t size_sent = 0;
|
||||
|
||||
while(size_sent < data_size) {
|
||||
const size_t current_size = MIN(data_size - size_sent, EXPANSION_PROTOCOL_MAX_DATA_SIZE);
|
||||
if(!expansion_test_app_send_data_request(instance, data + size_sent, current_size)) break;
|
||||
if(!expansion_test_app_receive_frame(instance, &instance->frame)) break;
|
||||
if(!expansion_test_app_is_success_response(&instance->frame)) break;
|
||||
size_sent += current_size;
|
||||
}
|
||||
|
||||
return size_sent == data_size;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_send_rpc_request(ExpansionTestApp* instance, PB_Main* message) {
|
||||
pb_ostream_t stream = {
|
||||
.callback = expansion_test_app_rpc_encode_callback,
|
||||
.state = instance,
|
||||
.max_size = SIZE_MAX,
|
||||
.bytes_written = 0,
|
||||
.errmsg = NULL,
|
||||
};
|
||||
|
||||
const bool success = pb_encode_ex(&stream, &PB_Main_msg, message, PB_ENCODE_DELIMITED);
|
||||
pb_release(&PB_Main_msg, message);
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_receive_rpc_request(ExpansionTestApp* instance, PB_Main* message) {
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!expansion_test_app_receive_frame(instance, &instance->frame)) break;
|
||||
if(!expansion_test_app_send_status_response(instance, ExpansionFrameErrorNone)) break;
|
||||
if(instance->frame.header.type != ExpansionFrameTypeData) break;
|
||||
pb_istream_t stream = pb_istream_from_buffer(
|
||||
instance->frame.content.data.bytes, instance->frame.content.data.size);
|
||||
if(!pb_decode_ex(&stream, &PB_Main_msg, message, PB_DECODE_DELIMITED)) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_send_presence(ExpansionTestApp* instance) {
|
||||
// Send pulses to emulate module insertion
|
||||
const uint8_t init = 0xAA;
|
||||
furi_hal_serial_tx(instance->handle, &init, sizeof(init));
|
||||
furi_hal_serial_tx_wait_complete(instance->handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_wait_ready(ExpansionTestApp* instance) {
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!expansion_test_app_receive_frame(instance, &instance->frame)) break;
|
||||
if(instance->frame.header.type != ExpansionFrameTypeHeartbeat) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_handshake(ExpansionTestApp* instance) {
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!expansion_test_app_send_baud_rate_request(instance, 230400)) break;
|
||||
if(!expansion_test_app_receive_frame(instance, &instance->frame)) break;
|
||||
if(!expansion_test_app_is_success_response(&instance->frame)) break;
|
||||
furi_hal_serial_set_br(instance->handle, 230400);
|
||||
furi_delay_ms(EXPANSION_PROTOCOL_BAUD_CHANGE_DT_MS);
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_start_rpc(ExpansionTestApp* instance) {
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!expansion_test_app_send_control_request(instance, ExpansionFrameControlCommandStartRpc))
|
||||
break;
|
||||
if(!expansion_test_app_receive_frame(instance, &instance->frame)) break;
|
||||
if(!expansion_test_app_is_success_response(&instance->frame)) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_rpc_mkdir(ExpansionTestApp* instance) {
|
||||
bool success = false;
|
||||
|
||||
instance->msg.command_id++;
|
||||
instance->msg.command_status = PB_CommandStatus_OK;
|
||||
instance->msg.which_content = PB_Main_storage_mkdir_request_tag;
|
||||
instance->msg.has_next = false;
|
||||
instance->msg.content.storage_mkdir_request.path = TEST_DIR_PATH;
|
||||
|
||||
do {
|
||||
if(!expansion_test_app_send_rpc_request(instance, &instance->msg)) break;
|
||||
if(!expansion_test_app_receive_rpc_request(instance, &instance->msg)) break;
|
||||
if(!expansion_test_app_is_success_rpc_message(&instance->msg)) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_rpc_write(ExpansionTestApp* instance) {
|
||||
bool success = false;
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(storage);
|
||||
|
||||
do {
|
||||
if(!storage_file_open(file, APP_ASSETS_PATH(TEST_FILE_NAME), FSAM_READ, FSOM_OPEN_EXISTING))
|
||||
break;
|
||||
|
||||
const uint64_t file_size = storage_file_size(file);
|
||||
|
||||
instance->msg.command_id++;
|
||||
instance->msg.command_status = PB_CommandStatus_OK;
|
||||
instance->msg.which_content = PB_Main_storage_write_request_tag;
|
||||
instance->msg.has_next = false;
|
||||
instance->msg.content.storage_write_request.path = TEST_FILE_PATH;
|
||||
instance->msg.content.storage_write_request.has_file = true;
|
||||
instance->msg.content.storage_write_request.file.data =
|
||||
malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(file_size));
|
||||
instance->msg.content.storage_write_request.file.data->size = file_size;
|
||||
|
||||
const size_t bytes_read = storage_file_read(
|
||||
file, instance->msg.content.storage_write_request.file.data->bytes, file_size);
|
||||
|
||||
if(bytes_read != file_size) {
|
||||
pb_release(&PB_Main_msg, &instance->msg);
|
||||
break;
|
||||
}
|
||||
|
||||
if(!expansion_test_app_send_rpc_request(instance, &instance->msg)) break;
|
||||
if(!expansion_test_app_receive_rpc_request(instance, &instance->msg)) break;
|
||||
if(!expansion_test_app_is_success_rpc_message(&instance->msg)) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
storage_file_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_rpc_alert(ExpansionTestApp* instance) {
|
||||
bool success = false;
|
||||
|
||||
instance->msg.command_id++;
|
||||
instance->msg.command_status = PB_CommandStatus_OK;
|
||||
instance->msg.which_content = PB_Main_system_play_audiovisual_alert_request_tag;
|
||||
instance->msg.has_next = false;
|
||||
|
||||
do {
|
||||
if(!expansion_test_app_send_rpc_request(instance, &instance->msg)) break;
|
||||
if(!expansion_test_app_receive_rpc_request(instance, &instance->msg)) break;
|
||||
if(instance->msg.which_content != PB_Main_empty_tag) break;
|
||||
if(instance->msg.command_status != PB_CommandStatus_OK) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_idle(ExpansionTestApp* instance, uint32_t num_cycles) {
|
||||
uint32_t num_cycles_done;
|
||||
for(num_cycles_done = 0; num_cycles_done < num_cycles; ++num_cycles_done) {
|
||||
if(!expansion_test_app_send_heartbeat(instance)) break;
|
||||
if(!expansion_test_app_receive_frame(instance, &instance->frame)) break;
|
||||
if(instance->frame.header.type != ExpansionFrameTypeHeartbeat) break;
|
||||
furi_delay_ms(EXPANSION_PROTOCOL_TIMEOUT_MS - 50);
|
||||
}
|
||||
|
||||
return num_cycles_done == num_cycles;
|
||||
}
|
||||
|
||||
static bool expansion_test_app_stop_rpc(ExpansionTestApp* instance) {
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!expansion_test_app_send_control_request(instance, ExpansionFrameControlCommandStopRpc))
|
||||
break;
|
||||
if(!expansion_test_app_receive_frame(instance, &instance->frame)) break;
|
||||
if(!expansion_test_app_is_success_response(&instance->frame)) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
int32_t expansion_test_app(void* p) {
|
||||
UNUSED(p);
|
||||
|
||||
ExpansionTestApp* instance = expansion_test_app_alloc();
|
||||
expansion_test_app_start(instance);
|
||||
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!expansion_test_app_send_presence(instance)) break;
|
||||
if(!expansion_test_app_wait_ready(instance)) break;
|
||||
if(!expansion_test_app_handshake(instance)) break;
|
||||
if(!expansion_test_app_start_rpc(instance)) break;
|
||||
if(!expansion_test_app_rpc_mkdir(instance)) break;
|
||||
if(!expansion_test_app_rpc_write(instance)) break;
|
||||
if(!expansion_test_app_rpc_alert(instance)) break;
|
||||
if(!expansion_test_app_idle(instance, 10)) break;
|
||||
if(!expansion_test_app_stop_rpc(instance)) break;
|
||||
if(!expansion_test_app_idle(instance, 10)) break;
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
expansion_test_app_stop(instance);
|
||||
expansion_test_app_free(instance);
|
||||
|
||||
if(!success) {
|
||||
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
notification_message(notification, &sequence_error);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3,7 +3,6 @@ App(
|
||||
name="File Browser Test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="file_browser_app",
|
||||
cdefines=["APP_FILE_BROWSER_TEST"],
|
||||
requires=["gui"],
|
||||
stack_size=2 * 1024,
|
||||
order=150,
|
||||
|
||||
@@ -3,7 +3,6 @@ App(
|
||||
name="Keypad Test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="keypad_test_app",
|
||||
cdefines=["APP_KEYPAD_TEST"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=30,
|
||||
|
||||
@@ -3,7 +3,6 @@ App(
|
||||
name="Locale Test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="locale_test_app",
|
||||
cdefines=["APP_LOCALE"],
|
||||
requires=["gui", "locale"],
|
||||
stack_size=2 * 1024,
|
||||
order=70,
|
||||
|
||||
@@ -3,7 +3,6 @@ App(
|
||||
name="Text Box Test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="text_box_test_app",
|
||||
cdefines=["APP_TEXT_BOX_TEST"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=140,
|
||||
|
||||
@@ -3,7 +3,6 @@ App(
|
||||
name="UART Echo",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="uart_echo_app",
|
||||
cdefines=["APP_UART_ECHO"],
|
||||
requires=["gui"],
|
||||
stack_size=2 * 1024,
|
||||
order=70,
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/elements.h>
|
||||
#include <furi_hal_uart.h>
|
||||
#include <furi_hal_console.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
#define LINES_ON_SCREEN 6
|
||||
#define COLUMNS_ON_SCREEN 21
|
||||
#define TAG "UartEcho"
|
||||
@@ -22,6 +23,7 @@ typedef struct {
|
||||
View* view;
|
||||
FuriThread* worker_thread;
|
||||
FuriStreamBuffer* rx_stream;
|
||||
FuriHalSerialHandle* serial_handle;
|
||||
} UartEchoApp;
|
||||
|
||||
typedef struct {
|
||||
@@ -39,10 +41,16 @@ struct UartDumpModel {
|
||||
typedef enum {
|
||||
WorkerEventReserved = (1 << 0), // Reserved for StreamBuffer internal event
|
||||
WorkerEventStop = (1 << 1),
|
||||
WorkerEventRx = (1 << 2),
|
||||
WorkerEventRxData = (1 << 2),
|
||||
WorkerEventRxIdle = (1 << 3),
|
||||
WorkerEventRxOverrunError = (1 << 4),
|
||||
WorkerEventRxFramingError = (1 << 5),
|
||||
WorkerEventRxNoiseError = (1 << 6),
|
||||
} WorkerEventFlags;
|
||||
|
||||
#define WORKER_EVENTS_MASK (WorkerEventStop | WorkerEventRx)
|
||||
#define WORKER_EVENTS_MASK \
|
||||
(WorkerEventStop | WorkerEventRxData | WorkerEventRxIdle | WorkerEventRxOverrunError | \
|
||||
WorkerEventRxFramingError | WorkerEventRxNoiseError)
|
||||
|
||||
const NotificationSequence sequence_notification = {
|
||||
&message_display_backlight_on,
|
||||
@@ -91,14 +99,39 @@ static uint32_t uart_echo_exit(void* context) {
|
||||
return VIEW_NONE;
|
||||
}
|
||||
|
||||
static void uart_echo_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) {
|
||||
static void
|
||||
uart_echo_on_irq_cb(FuriHalSerialHandle* handle, FuriHalSerialRxEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
UNUSED(handle);
|
||||
UartEchoApp* app = context;
|
||||
volatile FuriHalSerialRxEvent event_copy = event;
|
||||
UNUSED(event_copy);
|
||||
|
||||
if(ev == UartIrqEventRXNE) {
|
||||
WorkerEventFlags flag = 0;
|
||||
|
||||
if(event & FuriHalSerialRxEventData) {
|
||||
uint8_t data = furi_hal_serial_async_rx(handle);
|
||||
furi_stream_buffer_send(app->rx_stream, &data, 1, 0);
|
||||
furi_thread_flags_set(furi_thread_get_id(app->worker_thread), WorkerEventRx);
|
||||
flag |= WorkerEventRxData;
|
||||
}
|
||||
|
||||
if(event & FuriHalSerialRxEventIdle) {
|
||||
//idle line detected, packet transmission may have ended
|
||||
flag |= WorkerEventRxIdle;
|
||||
}
|
||||
|
||||
//error detected
|
||||
if(event & FuriHalSerialRxEventFrameError) {
|
||||
flag |= WorkerEventRxFramingError;
|
||||
}
|
||||
if(event & FuriHalSerialRxEventNoiseError) {
|
||||
flag |= WorkerEventRxNoiseError;
|
||||
}
|
||||
if(event & FuriHalSerialRxEventOverrunError) {
|
||||
flag |= WorkerEventRxOverrunError;
|
||||
}
|
||||
|
||||
furi_thread_flags_set(furi_thread_get_id(app->worker_thread), flag);
|
||||
}
|
||||
|
||||
static void uart_echo_push_to_list(UartDumpModel* model, const char data) {
|
||||
@@ -153,13 +186,13 @@ static int32_t uart_echo_worker(void* context) {
|
||||
furi_check((events & FuriFlagError) == 0);
|
||||
|
||||
if(events & WorkerEventStop) break;
|
||||
if(events & WorkerEventRx) {
|
||||
if(events & WorkerEventRxData) {
|
||||
size_t length = 0;
|
||||
do {
|
||||
uint8_t data[64];
|
||||
length = furi_stream_buffer_receive(app->rx_stream, data, 64, 0);
|
||||
if(length > 0) {
|
||||
furi_hal_uart_tx(FuriHalUartIdUSART1, data, length);
|
||||
furi_hal_serial_tx(app->serial_handle, data, length);
|
||||
with_view_model(
|
||||
app->view,
|
||||
UartDumpModel * model,
|
||||
@@ -176,6 +209,23 @@ static int32_t uart_echo_worker(void* context) {
|
||||
with_view_model(
|
||||
app->view, UartDumpModel * model, { UNUSED(model); }, true);
|
||||
}
|
||||
|
||||
if(events & WorkerEventRxIdle) {
|
||||
furi_hal_serial_tx(app->serial_handle, (uint8_t*)"\r\nDetect IDLE\r\n", 15);
|
||||
}
|
||||
|
||||
if(events &
|
||||
(WorkerEventRxOverrunError | WorkerEventRxFramingError | WorkerEventRxNoiseError)) {
|
||||
if(events & WorkerEventRxOverrunError) {
|
||||
furi_hal_serial_tx(app->serial_handle, (uint8_t*)"\r\nDetect ORE\r\n", 14);
|
||||
}
|
||||
if(events & WorkerEventRxFramingError) {
|
||||
furi_hal_serial_tx(app->serial_handle, (uint8_t*)"\r\nDetect FE\r\n", 13);
|
||||
}
|
||||
if(events & WorkerEventRxNoiseError) {
|
||||
furi_hal_serial_tx(app->serial_handle, (uint8_t*)"\r\nDetect NE\r\n", 13);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -221,9 +271,11 @@ static UartEchoApp* uart_echo_app_alloc(uint32_t baudrate) {
|
||||
furi_thread_start(app->worker_thread);
|
||||
|
||||
// Enable uart listener
|
||||
furi_hal_console_disable();
|
||||
furi_hal_uart_set_br(FuriHalUartIdUSART1, baudrate);
|
||||
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, uart_echo_on_irq_cb, app);
|
||||
app->serial_handle = furi_hal_serial_control_acquire(FuriHalSerialIdUsart);
|
||||
furi_check(app->serial_handle);
|
||||
furi_hal_serial_init(app->serial_handle, baudrate);
|
||||
|
||||
furi_hal_serial_async_rx_start(app->serial_handle, uart_echo_on_irq_cb, app, true);
|
||||
|
||||
return app;
|
||||
}
|
||||
@@ -231,12 +283,13 @@ static UartEchoApp* uart_echo_app_alloc(uint32_t baudrate) {
|
||||
static void uart_echo_app_free(UartEchoApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
furi_hal_console_enable(); // this will also clear IRQ callback so thread is no longer referenced
|
||||
|
||||
furi_thread_flags_set(furi_thread_get_id(app->worker_thread), WorkerEventStop);
|
||||
furi_thread_join(app->worker_thread);
|
||||
furi_thread_free(app->worker_thread);
|
||||
|
||||
furi_hal_serial_deinit(app->serial_handle);
|
||||
furi_hal_serial_control_release(app->serial_handle);
|
||||
|
||||
// Free views
|
||||
view_dispatcher_remove_view(app->view_dispatcher, 0);
|
||||
|
||||
|
||||
200
applications/debug/unit_tests/expansion/expansion_test.c
Normal file
200
applications/debug/unit_tests/expansion/expansion_test.c
Normal file
@@ -0,0 +1,200 @@
|
||||
#include "../minunit.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal_random.h>
|
||||
|
||||
#include <expansion/expansion_protocol.h>
|
||||
|
||||
#define EXPANSION_TEST_GARBAGE_MAGIC (0xB19AF)
|
||||
#define EXPANSION_TEST_GARBAGE_BUF_SIZE (0x100U)
|
||||
#define EXPANSION_TEST_GARBAGE_ITERATIONS (100U)
|
||||
|
||||
MU_TEST(test_expansion_encoded_size) {
|
||||
ExpansionFrame frame = {};
|
||||
|
||||
frame.header.type = ExpansionFrameTypeHeartbeat;
|
||||
mu_assert_int_eq(1, expansion_frame_get_encoded_size(&frame));
|
||||
|
||||
frame.header.type = ExpansionFrameTypeStatus;
|
||||
mu_assert_int_eq(2, expansion_frame_get_encoded_size(&frame));
|
||||
|
||||
frame.header.type = ExpansionFrameTypeBaudRate;
|
||||
mu_assert_int_eq(5, expansion_frame_get_encoded_size(&frame));
|
||||
|
||||
frame.header.type = ExpansionFrameTypeControl;
|
||||
mu_assert_int_eq(2, expansion_frame_get_encoded_size(&frame));
|
||||
|
||||
frame.header.type = ExpansionFrameTypeData;
|
||||
for(size_t i = 0; i <= EXPANSION_PROTOCOL_MAX_DATA_SIZE; ++i) {
|
||||
frame.content.data.size = i;
|
||||
mu_assert_int_eq(i + 2, expansion_frame_get_encoded_size(&frame));
|
||||
}
|
||||
}
|
||||
|
||||
MU_TEST(test_expansion_remaining_size) {
|
||||
ExpansionFrame frame = {};
|
||||
|
||||
size_t remaining_size;
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 0, &remaining_size));
|
||||
mu_assert_int_eq(1, remaining_size);
|
||||
|
||||
frame.header.type = ExpansionFrameTypeHeartbeat;
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 0, &remaining_size));
|
||||
mu_assert_int_eq(1, remaining_size);
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 1, &remaining_size));
|
||||
mu_assert_int_eq(0, remaining_size);
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 100, &remaining_size));
|
||||
mu_assert_int_eq(0, remaining_size);
|
||||
|
||||
frame.header.type = ExpansionFrameTypeStatus;
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 0, &remaining_size));
|
||||
mu_assert_int_eq(1, remaining_size);
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 1, &remaining_size));
|
||||
mu_assert_int_eq(1, remaining_size);
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 2, &remaining_size));
|
||||
mu_assert_int_eq(0, remaining_size);
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 100, &remaining_size));
|
||||
mu_assert_int_eq(0, remaining_size);
|
||||
|
||||
frame.header.type = ExpansionFrameTypeBaudRate;
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 0, &remaining_size));
|
||||
mu_assert_int_eq(1, remaining_size);
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 1, &remaining_size));
|
||||
mu_assert_int_eq(4, remaining_size);
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 5, &remaining_size));
|
||||
mu_assert_int_eq(0, remaining_size);
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 100, &remaining_size));
|
||||
mu_assert_int_eq(0, remaining_size);
|
||||
|
||||
frame.header.type = ExpansionFrameTypeControl;
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 0, &remaining_size));
|
||||
mu_assert_int_eq(1, remaining_size);
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 1, &remaining_size));
|
||||
mu_assert_int_eq(1, remaining_size);
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 2, &remaining_size));
|
||||
mu_assert_int_eq(0, remaining_size);
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 100, &remaining_size));
|
||||
mu_assert_int_eq(0, remaining_size);
|
||||
|
||||
frame.header.type = ExpansionFrameTypeData;
|
||||
frame.content.data.size = EXPANSION_PROTOCOL_MAX_DATA_SIZE;
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 0, &remaining_size));
|
||||
mu_assert_int_eq(1, remaining_size);
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 1, &remaining_size));
|
||||
mu_assert_int_eq(1, remaining_size);
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 2, &remaining_size));
|
||||
mu_assert_int_eq(EXPANSION_PROTOCOL_MAX_DATA_SIZE, remaining_size);
|
||||
for(size_t i = 0; i <= EXPANSION_PROTOCOL_MAX_DATA_SIZE; ++i) {
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, i + 2, &remaining_size));
|
||||
mu_assert_int_eq(EXPANSION_PROTOCOL_MAX_DATA_SIZE - i, remaining_size);
|
||||
}
|
||||
mu_check(expansion_frame_get_remaining_size(&frame, 100, &remaining_size));
|
||||
mu_assert_int_eq(0, remaining_size);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
void* data_out;
|
||||
size_t size_available;
|
||||
size_t size_sent;
|
||||
} TestExpansionSendStream;
|
||||
|
||||
static size_t test_expansion_send_callback(const uint8_t* data, size_t data_size, void* context) {
|
||||
TestExpansionSendStream* stream = context;
|
||||
const size_t size_sent = MIN(data_size, stream->size_available);
|
||||
|
||||
memcpy(stream->data_out + stream->size_sent, data, size_sent);
|
||||
|
||||
stream->size_available -= size_sent;
|
||||
stream->size_sent += size_sent;
|
||||
|
||||
return size_sent;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const void* data_in;
|
||||
size_t size_available;
|
||||
size_t size_received;
|
||||
} TestExpansionReceiveStream;
|
||||
|
||||
static size_t test_expansion_receive_callback(uint8_t* data, size_t data_size, void* context) {
|
||||
TestExpansionReceiveStream* stream = context;
|
||||
const size_t size_received = MIN(data_size, stream->size_available);
|
||||
|
||||
memcpy(data, stream->data_in + stream->size_received, size_received);
|
||||
|
||||
stream->size_available -= size_received;
|
||||
stream->size_received += size_received;
|
||||
|
||||
return size_received;
|
||||
}
|
||||
|
||||
MU_TEST(test_expansion_encode_decode_frame) {
|
||||
const ExpansionFrame frame_in = {
|
||||
.header.type = ExpansionFrameTypeData,
|
||||
.content.data.size = 8,
|
||||
.content.data.bytes = {0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xca, 0xfe},
|
||||
};
|
||||
|
||||
uint8_t encoded_data[sizeof(ExpansionFrame) + sizeof(ExpansionFrameChecksum)];
|
||||
memset(encoded_data, 0, sizeof(encoded_data));
|
||||
|
||||
TestExpansionSendStream send_stream = {
|
||||
.data_out = &encoded_data,
|
||||
.size_available = sizeof(encoded_data),
|
||||
.size_sent = 0,
|
||||
};
|
||||
|
||||
const size_t encoded_size = expansion_frame_get_encoded_size(&frame_in);
|
||||
|
||||
mu_assert_int_eq(
|
||||
expansion_protocol_encode(&frame_in, test_expansion_send_callback, &send_stream),
|
||||
ExpansionProtocolStatusOk);
|
||||
mu_assert_int_eq(encoded_size + sizeof(ExpansionFrameChecksum), send_stream.size_sent);
|
||||
mu_assert_int_eq(
|
||||
expansion_protocol_get_checksum((const uint8_t*)&frame_in, encoded_size),
|
||||
encoded_data[encoded_size]);
|
||||
mu_assert_mem_eq(&frame_in, &encoded_data, encoded_size);
|
||||
|
||||
TestExpansionReceiveStream stream = {
|
||||
.data_in = encoded_data,
|
||||
.size_available = send_stream.size_sent,
|
||||
.size_received = 0,
|
||||
};
|
||||
|
||||
ExpansionFrame frame_out;
|
||||
|
||||
mu_assert_int_eq(
|
||||
expansion_protocol_decode(&frame_out, test_expansion_receive_callback, &stream),
|
||||
ExpansionProtocolStatusOk);
|
||||
mu_assert_int_eq(encoded_size + sizeof(ExpansionFrameChecksum), stream.size_received);
|
||||
mu_assert_mem_eq(&frame_in, &frame_out, encoded_size);
|
||||
}
|
||||
|
||||
MU_TEST(test_expansion_garbage_input) {
|
||||
uint8_t garbage_data[EXPANSION_TEST_GARBAGE_BUF_SIZE];
|
||||
for(uint32_t i = 0; i < EXPANSION_TEST_GARBAGE_ITERATIONS; ++i) {
|
||||
furi_hal_random_fill_buf(garbage_data, sizeof(garbage_data));
|
||||
size_t remaining_size = EXPANSION_TEST_GARBAGE_MAGIC;
|
||||
if(expansion_frame_get_remaining_size(
|
||||
(ExpansionFrame*)garbage_data, sizeof(garbage_data), &remaining_size)) {
|
||||
// If by chance the garbage data is a valid frame, then the result
|
||||
// must be 0 because the amount of data provided is more than enough
|
||||
mu_assert_int_eq(0, remaining_size);
|
||||
} else {
|
||||
// If the frame is invalid, the remaining_size parameter should be untouched
|
||||
mu_assert_int_eq(EXPANSION_TEST_GARBAGE_MAGIC, remaining_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_expansion_suite) {
|
||||
MU_RUN_TEST(test_expansion_encoded_size);
|
||||
MU_RUN_TEST(test_expansion_remaining_size);
|
||||
MU_RUN_TEST(test_expansion_encode_decode_frame);
|
||||
MU_RUN_TEST(test_expansion_garbage_input);
|
||||
}
|
||||
|
||||
int run_minunit_test_expansion() {
|
||||
MU_RUN_SUITE(test_expansion_suite);
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
@@ -3,18 +3,29 @@
|
||||
#include <furi.h>
|
||||
#include "../minunit.h"
|
||||
|
||||
void test_furi_create_open() {
|
||||
// 1. Create record
|
||||
uint8_t test_data = 0;
|
||||
furi_record_create("test/holding", (void*)&test_data);
|
||||
#define TEST_RECORD_NAME "test/holding"
|
||||
|
||||
// 2. Open it
|
||||
void* record = furi_record_open("test/holding");
|
||||
void test_furi_create_open() {
|
||||
// Test that record does not exist
|
||||
mu_check(furi_record_exists(TEST_RECORD_NAME) == false);
|
||||
|
||||
// Create record
|
||||
uint8_t test_data = 0;
|
||||
furi_record_create(TEST_RECORD_NAME, (void*)&test_data);
|
||||
|
||||
// Test that record exists
|
||||
mu_check(furi_record_exists(TEST_RECORD_NAME) == true);
|
||||
|
||||
// Open it
|
||||
void* record = furi_record_open(TEST_RECORD_NAME);
|
||||
mu_assert_pointers_eq(record, &test_data);
|
||||
|
||||
// 3. Close it
|
||||
furi_record_close("test/holding");
|
||||
// Close it
|
||||
furi_record_close(TEST_RECORD_NAME);
|
||||
|
||||
// 4. Clean up
|
||||
furi_record_destroy("test/holding");
|
||||
// Clean up
|
||||
furi_record_destroy(TEST_RECORD_NAME);
|
||||
|
||||
// Test that record does not exist
|
||||
mu_check(furi_record_exists(TEST_RECORD_NAME) == false);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#include "furi_hal_rtc.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <lp5562_reg.h>
|
||||
#include "../minunit.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DATA_SIZE 4
|
||||
#define EEPROM_ADDRESS 0b10101000
|
||||
@@ -211,6 +214,37 @@ MU_TEST(furi_hal_i2c_ext_eeprom) {
|
||||
}
|
||||
}
|
||||
|
||||
MU_TEST(furi_hal_rtc_timestamp2datetime_min) {
|
||||
uint32_t test_value = 0;
|
||||
FuriHalRtcDateTime min_datetime_expected = {0, 0, 0, 1, 1, 1970, 0};
|
||||
|
||||
FuriHalRtcDateTime result = {0};
|
||||
furi_hal_rtc_timestamp_to_datetime(test_value, &result);
|
||||
|
||||
mu_assert_mem_eq(&min_datetime_expected, &result, sizeof(result));
|
||||
}
|
||||
|
||||
MU_TEST(furi_hal_rtc_timestamp2datetime_max) {
|
||||
uint32_t test_value = UINT32_MAX;
|
||||
FuriHalRtcDateTime max_datetime_expected = {6, 28, 15, 7, 2, 2106, 0};
|
||||
|
||||
FuriHalRtcDateTime result = {0};
|
||||
furi_hal_rtc_timestamp_to_datetime(test_value, &result);
|
||||
|
||||
mu_assert_mem_eq(&max_datetime_expected, &result, sizeof(result));
|
||||
}
|
||||
|
||||
MU_TEST(furi_hal_rtc_timestamp2datetime2timestamp) {
|
||||
uint32_t test_value = random();
|
||||
|
||||
FuriHalRtcDateTime datetime = {0};
|
||||
furi_hal_rtc_timestamp_to_datetime(test_value, &datetime);
|
||||
|
||||
uint32_t result = furi_hal_rtc_datetime_to_timestamp(&datetime);
|
||||
|
||||
mu_assert_int_eq(test_value, result);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(furi_hal_i2c_int_suite) {
|
||||
MU_SUITE_CONFIGURE(&furi_hal_i2c_int_setup, &furi_hal_i2c_int_teardown);
|
||||
MU_RUN_TEST(furi_hal_i2c_int_1b);
|
||||
@@ -224,8 +258,15 @@ MU_TEST_SUITE(furi_hal_i2c_ext_suite) {
|
||||
MU_RUN_TEST(furi_hal_i2c_ext_eeprom);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(furi_hal_rtc_datetime_suite) {
|
||||
MU_RUN_TEST(furi_hal_rtc_timestamp2datetime_min);
|
||||
MU_RUN_TEST(furi_hal_rtc_timestamp2datetime_max);
|
||||
MU_RUN_TEST(furi_hal_rtc_timestamp2datetime2timestamp);
|
||||
}
|
||||
|
||||
int run_minunit_test_furi_hal() {
|
||||
MU_RUN_SUITE(furi_hal_i2c_int_suite);
|
||||
MU_RUN_SUITE(furi_hal_i2c_ext_suite);
|
||||
MU_RUN_SUITE(furi_hal_rtc_datetime_suite);
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
|
||||
@@ -209,6 +209,25 @@ const int8_t indala26_test_timings[INDALA26_EMULATION_TIMINGS_COUNT] = {
|
||||
-1, 1, -1, 1, -1, 1, -1, 1,
|
||||
};
|
||||
|
||||
#define FDXB_TEST_DATA \
|
||||
{ 0x44, 0x88, 0x23, 0xF2, 0x5A, 0x6F, 0x00, 0x01, 0x00, 0x00, 0x00 }
|
||||
#define FDXB_TEST_DATA_SIZE 11
|
||||
#define FDXB_TEST_EMULATION_TIMINGS_COUNT (206)
|
||||
|
||||
const int8_t fdxb_test_timings[FDXB_TEST_EMULATION_TIMINGS_COUNT] = {
|
||||
32, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16,
|
||||
-16, 16, -32, 16, -16, 32, -16, 16, -16, 16, -16, 16, -32, 16, -16, 16, -16, 32, -32,
|
||||
16, -16, 16, -16, 16, -16, 32, -16, 16, -16, 16, -16, 16, -32, 16, -16, 16, -16, 32,
|
||||
-16, 16, -16, 16, -16, 16, -32, 32, -32, 32, -32, 32, -32, 16, -16, 16, -16, 32, -16,
|
||||
16, -32, 16, -16, 32, -16, 16, -32, 32, -16, 16, -32, 16, -16, 32, -16, 16, -32, 32,
|
||||
-16, 16, -32, 32, -32, 32, -32, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16,
|
||||
16, -16, 16, -16, 32, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16,
|
||||
-32, 32, -32, 32, -32, 32, -32, 16, -16, 32, -32, 32, -16, 16, -16, 16, -32, 32, -32,
|
||||
32, -32, 32, -32, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16,
|
||||
-16, 32, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -32,
|
||||
16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16,
|
||||
};
|
||||
|
||||
MU_TEST(test_lfrfid_protocol_em_read_simple) {
|
||||
ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
|
||||
mu_assert_int_eq(EM_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolEM4100));
|
||||
@@ -445,6 +464,73 @@ MU_TEST(test_lfrfid_protocol_inadala26_emulate_simple) {
|
||||
protocol_dict_free(dict);
|
||||
}
|
||||
|
||||
MU_TEST(test_lfrfid_protocol_fdxb_emulate_simple) {
|
||||
ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
|
||||
mu_assert_int_eq(FDXB_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolFDXB));
|
||||
mu_assert_string_eq("FDX-B", protocol_dict_get_name(dict, LFRFIDProtocolFDXB));
|
||||
mu_assert_string_eq("ISO", protocol_dict_get_manufacturer(dict, LFRFIDProtocolFDXB));
|
||||
|
||||
const uint8_t data[FDXB_TEST_DATA_SIZE] = FDXB_TEST_DATA;
|
||||
|
||||
protocol_dict_set_data(dict, LFRFIDProtocolFDXB, data, FDXB_TEST_DATA_SIZE);
|
||||
mu_check(protocol_dict_encoder_start(dict, LFRFIDProtocolFDXB));
|
||||
|
||||
for(size_t i = 0; i < FDXB_TEST_EMULATION_TIMINGS_COUNT; i++) {
|
||||
LevelDuration level_duration = protocol_dict_encoder_yield(dict, LFRFIDProtocolFDXB);
|
||||
|
||||
if(level_duration_get_level(level_duration)) {
|
||||
mu_assert_int_eq(fdxb_test_timings[i], level_duration_get_duration(level_duration));
|
||||
} else {
|
||||
mu_assert_int_eq(fdxb_test_timings[i], -level_duration_get_duration(level_duration));
|
||||
}
|
||||
}
|
||||
|
||||
protocol_dict_free(dict);
|
||||
}
|
||||
|
||||
MU_TEST(test_lfrfid_protocol_fdxb_read_simple) {
|
||||
ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
|
||||
mu_assert_int_eq(FDXB_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolFDXB));
|
||||
mu_assert_string_eq("FDX-B", protocol_dict_get_name(dict, LFRFIDProtocolFDXB));
|
||||
mu_assert_string_eq("ISO", protocol_dict_get_manufacturer(dict, LFRFIDProtocolFDXB));
|
||||
|
||||
const uint8_t data[FDXB_TEST_DATA_SIZE] = FDXB_TEST_DATA;
|
||||
|
||||
protocol_dict_decoders_start(dict);
|
||||
|
||||
ProtocolId protocol = PROTOCOL_NO;
|
||||
PulseGlue* pulse_glue = pulse_glue_alloc();
|
||||
|
||||
for(size_t i = 0; i < FDXB_TEST_EMULATION_TIMINGS_COUNT * 10; i++) {
|
||||
bool pulse_pop = pulse_glue_push(
|
||||
pulse_glue,
|
||||
fdxb_test_timings[i % FDXB_TEST_EMULATION_TIMINGS_COUNT] >= 0,
|
||||
abs(fdxb_test_timings[i % FDXB_TEST_EMULATION_TIMINGS_COUNT]) *
|
||||
LF_RFID_READ_TIMING_MULTIPLIER);
|
||||
|
||||
if(pulse_pop) {
|
||||
uint32_t length, period;
|
||||
pulse_glue_pop(pulse_glue, &length, &period);
|
||||
|
||||
protocol = protocol_dict_decoders_feed(dict, true, period);
|
||||
if(protocol != PROTOCOL_NO) break;
|
||||
|
||||
protocol = protocol_dict_decoders_feed(dict, false, length - period);
|
||||
if(protocol != PROTOCOL_NO) break;
|
||||
}
|
||||
}
|
||||
|
||||
pulse_glue_free(pulse_glue);
|
||||
|
||||
mu_assert_int_eq(LFRFIDProtocolFDXB, protocol);
|
||||
uint8_t received_data[FDXB_TEST_DATA_SIZE] = {0};
|
||||
protocol_dict_get_data(dict, protocol, received_data, FDXB_TEST_DATA_SIZE);
|
||||
|
||||
mu_assert_mem_eq(data, received_data, FDXB_TEST_DATA_SIZE);
|
||||
|
||||
protocol_dict_free(dict);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_lfrfid_protocols_suite) {
|
||||
MU_RUN_TEST(test_lfrfid_protocol_em_read_simple);
|
||||
MU_RUN_TEST(test_lfrfid_protocol_em_emulate_simple);
|
||||
@@ -456,6 +542,9 @@ MU_TEST_SUITE(test_lfrfid_protocols_suite) {
|
||||
MU_RUN_TEST(test_lfrfid_protocol_ioprox_xsf_emulate_simple);
|
||||
|
||||
MU_RUN_TEST(test_lfrfid_protocol_inadala26_emulate_simple);
|
||||
|
||||
MU_RUN_TEST(test_lfrfid_protocol_fdxb_read_simple);
|
||||
MU_RUN_TEST(test_lfrfid_protocol_fdxb_emulate_simple);
|
||||
}
|
||||
|
||||
int run_minunit_test_lfrfid_protocols() {
|
||||
|
||||
@@ -81,6 +81,7 @@ __attribute__((unused)) static void (*minunit_teardown)(void) = NULL;
|
||||
|
||||
void minunit_print_progress(void);
|
||||
void minunit_print_fail(const char* error);
|
||||
void minunit_printf_warning(const char* format, ...);
|
||||
|
||||
/* Definitions */
|
||||
#define MU_TEST(method_name) static void method_name(void)
|
||||
@@ -150,6 +151,10 @@ void minunit_print_fail(const char* error);
|
||||
minunit_end_proc_timer - minunit_proc_timer);)
|
||||
#define MU_EXIT_CODE minunit_fail
|
||||
|
||||
/* Warnings */
|
||||
#define mu_warn(message) \
|
||||
MU__SAFE_BLOCK(minunit_printf_warning("%s:%d: %s", __FILE__, __LINE__, message);)
|
||||
|
||||
/* Assertions */
|
||||
#define mu_check(test) \
|
||||
MU__SAFE_BLOCK( \
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
#include <nfc/nfc_poller.h>
|
||||
#include <nfc/nfc_listener.h>
|
||||
#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
|
||||
#include <nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h>
|
||||
#include <nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.h>
|
||||
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
|
||||
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h>
|
||||
#include <nfc/protocols/mf_classic/mf_classic_poller_sync_api.h>
|
||||
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h>
|
||||
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
|
||||
|
||||
#include <nfc/helpers/nfc_dict.h>
|
||||
#include <toolbox/keys_dict.h>
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "../minunit.h"
|
||||
@@ -182,8 +182,8 @@ MU_TEST(iso14443_3a_reader) {
|
||||
|
||||
Iso14443_3aData iso14443_3a_poller_data = {};
|
||||
mu_assert(
|
||||
iso14443_3a_poller_read(poller, &iso14443_3a_poller_data) == Iso14443_3aErrorNone,
|
||||
"iso14443_3a_poller_read() failed");
|
||||
iso14443_3a_poller_sync_read(poller, &iso14443_3a_poller_data) == Iso14443_3aErrorNone,
|
||||
"iso14443_3a_poller_sync_read() failed");
|
||||
|
||||
nfc_listener_stop(iso3_listener);
|
||||
mu_assert(
|
||||
@@ -203,15 +203,26 @@ static void mf_ultralight_reader_test(const char* path) {
|
||||
NfcDevice* nfc_device = nfc_device_alloc();
|
||||
mu_assert(nfc_device_load(nfc_device, path), "nfc_device_load() failed\r\n");
|
||||
|
||||
NfcListener* mfu_listener = nfc_listener_alloc(
|
||||
listener,
|
||||
NfcProtocolMfUltralight,
|
||||
nfc_device_get_data(nfc_device, NfcProtocolMfUltralight));
|
||||
MfUltralightData* data =
|
||||
(MfUltralightData*)nfc_device_get_data(nfc_device, NfcProtocolMfUltralight);
|
||||
|
||||
uint32_t features = mf_ultralight_get_feature_support_set(data->type);
|
||||
bool pwd_supported =
|
||||
mf_ultralight_support_feature(features, MfUltralightFeatureSupportPasswordAuth);
|
||||
uint8_t pwd_num = mf_ultralight_get_pwd_page_num(data->type);
|
||||
const uint8_t zero_pwd[4] = {0, 0, 0, 0};
|
||||
|
||||
if(pwd_supported && !memcmp(data->page[pwd_num].data, zero_pwd, sizeof(zero_pwd))) {
|
||||
data->pages_read -= 2;
|
||||
}
|
||||
|
||||
NfcListener* mfu_listener = nfc_listener_alloc(listener, NfcProtocolMfUltralight, data);
|
||||
|
||||
nfc_listener_start(mfu_listener, NULL, NULL);
|
||||
|
||||
MfUltralightData* mfu_data = mf_ultralight_alloc();
|
||||
MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data);
|
||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed");
|
||||
MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data);
|
||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed");
|
||||
|
||||
nfc_listener_stop(mfu_listener);
|
||||
nfc_listener_free(mfu_listener);
|
||||
@@ -259,8 +270,8 @@ MU_TEST(ntag_213_locked_reader) {
|
||||
nfc_listener_start(mfu_listener, NULL, NULL);
|
||||
|
||||
MfUltralightData* mfu_data = mf_ultralight_alloc();
|
||||
MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data);
|
||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed");
|
||||
MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data);
|
||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed");
|
||||
|
||||
nfc_listener_stop(mfu_listener);
|
||||
nfc_listener_free(mfu_listener);
|
||||
@@ -297,8 +308,8 @@ static void mf_ultralight_write() {
|
||||
MfUltralightData* mfu_data = mf_ultralight_alloc();
|
||||
|
||||
// Initial read
|
||||
MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data);
|
||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed");
|
||||
MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data);
|
||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed");
|
||||
|
||||
mu_assert(
|
||||
mf_ultralight_is_equal(mfu_data, nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)),
|
||||
@@ -310,13 +321,13 @@ static void mf_ultralight_write() {
|
||||
FURI_LOG_D(TAG, "Writing page %d", i);
|
||||
furi_hal_random_fill_buf(page.data, sizeof(MfUltralightPage));
|
||||
mfu_data->page[i] = page;
|
||||
error = mf_ultralight_poller_write_page(poller, i, &page);
|
||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_write_page() failed");
|
||||
error = mf_ultralight_poller_sync_write_page(poller, i, &page);
|
||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_write_page() failed");
|
||||
}
|
||||
|
||||
// Verification read
|
||||
error = mf_ultralight_poller_read_card(poller, mfu_data);
|
||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed");
|
||||
error = mf_ultralight_poller_sync_read_card(poller, mfu_data);
|
||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed");
|
||||
|
||||
nfc_listener_stop(mfu_listener);
|
||||
const MfUltralightData* mfu_listener_data =
|
||||
@@ -344,7 +355,7 @@ static void mf_classic_reader() {
|
||||
MfClassicBlock block = {};
|
||||
MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
||||
|
||||
mf_classic_poller_read_block(poller, 0, &key, MfClassicKeyTypeA, &block);
|
||||
mf_classic_poller_sync_read_block(poller, 0, &key, MfClassicKeyTypeA, &block);
|
||||
|
||||
nfc_listener_stop(mfc_listener);
|
||||
nfc_listener_free(mfc_listener);
|
||||
@@ -372,8 +383,8 @@ static void mf_classic_write() {
|
||||
furi_hal_random_fill_buf(block_write.data, sizeof(MfClassicBlock));
|
||||
MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
||||
|
||||
mf_classic_poller_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write);
|
||||
mf_classic_poller_read_block(poller, 1, &key, MfClassicKeyTypeA, &block_read);
|
||||
mf_classic_poller_sync_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write);
|
||||
mf_classic_poller_sync_read_block(poller, 1, &key, MfClassicKeyTypeA, &block_read);
|
||||
|
||||
nfc_listener_stop(mfc_listener);
|
||||
nfc_listener_free(mfc_listener);
|
||||
@@ -402,16 +413,18 @@ static void mf_classic_value_block() {
|
||||
mf_classic_value_to_block(value, 1, &block_write);
|
||||
|
||||
MfClassicError error = MfClassicErrorNone;
|
||||
error = mf_classic_poller_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write);
|
||||
error = mf_classic_poller_sync_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write);
|
||||
mu_assert(error == MfClassicErrorNone, "Write failed");
|
||||
|
||||
int32_t data = 200;
|
||||
int32_t new_value = 0;
|
||||
error = mf_classic_poller_change_value(poller, 1, &key, MfClassicKeyTypeA, data, &new_value);
|
||||
error =
|
||||
mf_classic_poller_sync_change_value(poller, 1, &key, MfClassicKeyTypeA, data, &new_value);
|
||||
mu_assert(error == MfClassicErrorNone, "Value increment failed");
|
||||
mu_assert(new_value == value + data, "Value not match");
|
||||
|
||||
error = mf_classic_poller_change_value(poller, 1, &key, MfClassicKeyTypeA, -data, &new_value);
|
||||
error =
|
||||
mf_classic_poller_sync_change_value(poller, 1, &key, MfClassicKeyTypeA, -data, &new_value);
|
||||
mu_assert(error == MfClassicErrorNone, "Value decrement failed");
|
||||
mu_assert(new_value == value, "Value not match");
|
||||
|
||||
@@ -430,36 +443,36 @@ MU_TEST(mf_classic_dict_test) {
|
||||
"Remove test dict failed");
|
||||
}
|
||||
|
||||
NfcDict* dict = nfc_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
mu_assert(dict != NULL, "nfc_dict_alloc() failed");
|
||||
KeysDict* dict = keys_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
mu_assert(dict != NULL, "keys_dict_alloc() failed");
|
||||
|
||||
size_t dict_keys_total = nfc_dict_get_total_keys(dict);
|
||||
mu_assert(dict_keys_total == 0, "nfc_dict_keys_total() failed");
|
||||
size_t dict_keys_total = keys_dict_get_total_keys(dict);
|
||||
mu_assert(dict_keys_total == 0, "keys_dict_keys_total() failed");
|
||||
|
||||
const uint32_t test_key_num = 30;
|
||||
MfClassicKey* key_arr_ref = malloc(test_key_num * sizeof(MfClassicKey));
|
||||
for(size_t i = 0; i < test_key_num; i++) {
|
||||
furi_hal_random_fill_buf(key_arr_ref[i].data, sizeof(MfClassicKey));
|
||||
mu_assert(
|
||||
nfc_dict_add_key(dict, key_arr_ref[i].data, sizeof(MfClassicKey)), "add key failed");
|
||||
keys_dict_add_key(dict, key_arr_ref[i].data, sizeof(MfClassicKey)), "add key failed");
|
||||
|
||||
size_t dict_keys_total = nfc_dict_get_total_keys(dict);
|
||||
mu_assert(dict_keys_total == (i + 1), "nfc_dict_keys_total() failed");
|
||||
size_t dict_keys_total = keys_dict_get_total_keys(dict);
|
||||
mu_assert(dict_keys_total == (i + 1), "keys_dict_keys_total() failed");
|
||||
}
|
||||
|
||||
nfc_dict_free(dict);
|
||||
keys_dict_free(dict);
|
||||
|
||||
dict = nfc_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
mu_assert(dict != NULL, "nfc_dict_alloc() failed");
|
||||
dict = keys_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
mu_assert(dict != NULL, "keys_dict_alloc() failed");
|
||||
|
||||
dict_keys_total = nfc_dict_get_total_keys(dict);
|
||||
mu_assert(dict_keys_total == test_key_num, "nfc_dict_keys_total() failed");
|
||||
dict_keys_total = keys_dict_get_total_keys(dict);
|
||||
mu_assert(dict_keys_total == test_key_num, "keys_dict_keys_total() failed");
|
||||
|
||||
MfClassicKey key_dut = {};
|
||||
size_t key_idx = 0;
|
||||
while(nfc_dict_get_next_key(dict, key_dut.data, sizeof(MfClassicKey))) {
|
||||
while(keys_dict_get_next_key(dict, key_dut.data, sizeof(MfClassicKey))) {
|
||||
mu_assert(
|
||||
memcmp(key_arr_ref[key_idx].data, key_dut.data, sizeof(MfClassicKey)) == 0,
|
||||
"Loaded key data mismatch");
|
||||
@@ -471,19 +484,19 @@ MU_TEST(mf_classic_dict_test) {
|
||||
for(size_t i = 0; i < COUNT_OF(delete_keys_idx); i++) {
|
||||
MfClassicKey* key = &key_arr_ref[delete_keys_idx[i]];
|
||||
mu_assert(
|
||||
nfc_dict_is_key_present(dict, key->data, sizeof(MfClassicKey)),
|
||||
"nfc_dict_is_key_present() failed");
|
||||
keys_dict_is_key_present(dict, key->data, sizeof(MfClassicKey)),
|
||||
"keys_dict_is_key_present() failed");
|
||||
mu_assert(
|
||||
nfc_dict_delete_key(dict, key->data, sizeof(MfClassicKey)),
|
||||
"nfc_dict_delete_key() failed");
|
||||
keys_dict_delete_key(dict, key->data, sizeof(MfClassicKey)),
|
||||
"keys_dict_delete_key() failed");
|
||||
}
|
||||
|
||||
dict_keys_total = nfc_dict_get_total_keys(dict);
|
||||
dict_keys_total = keys_dict_get_total_keys(dict);
|
||||
mu_assert(
|
||||
dict_keys_total == test_key_num - COUNT_OF(delete_keys_idx),
|
||||
"nfc_dict_keys_total() failed");
|
||||
"keys_dict_keys_total() failed");
|
||||
|
||||
nfc_dict_free(dict);
|
||||
keys_dict_free(dict);
|
||||
free(key_arr_ref);
|
||||
|
||||
mu_assert(
|
||||
|
||||
@@ -455,4 +455,19 @@ NfcError nfc_iso15693_listener_tx_sof(Nfc* instance) {
|
||||
return NfcErrorNone;
|
||||
}
|
||||
|
||||
NfcError nfc_felica_listener_set_sensf_res_data(
|
||||
Nfc* instance,
|
||||
const uint8_t* idm,
|
||||
const uint8_t idm_len,
|
||||
const uint8_t* pmm,
|
||||
const uint8_t pmm_len) {
|
||||
furi_assert(instance);
|
||||
furi_assert(idm);
|
||||
furi_assert(pmm);
|
||||
furi_assert(idm_len == 8);
|
||||
furi_assert(pmm_len == 8);
|
||||
|
||||
return NfcErrorNone;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
Filetype: Flipper SubGhz Key File
|
||||
Version: 1
|
||||
Frequency: 433920000
|
||||
Preset: FuriHalSubGhzPresetOok270Async
|
||||
Protocol: Mastercode
|
||||
Bit: 36
|
||||
Key: 00 00 00 0B 7E 00 3C 08
|
||||
@@ -0,0 +1,6 @@
|
||||
Filetype: Flipper SubGhz RAW File
|
||||
Version: 1
|
||||
Frequency: 433920000
|
||||
Preset: FuriHalSubGhzPresetOok270Async
|
||||
Protocol: RAW
|
||||
RAW_Data: 10389 -66 405095 -102 207 -106 1165 -130 963739 -1232 899 -2250 2003 -1190 2017 -1202 911 -2256 2021 -1162 2045 -1134 2047 -1164 2047 -1138 2031 -1180 2039 -1182 949 -2190 995 -2214 961 -2228 963 -2198 963 -2214 977 -2212 975 -2210 975 -2208 971 -2200 963 -2210 993 -2184 2075 -1130 2051 -1142 2055 -1136 2047 -1178 965 -2236 933 -2220 975 -2184 999 -2222 967 -2208 969 -2214 979 -2202 2027 -1156 975 -2242 943 -16080 2023 -1162 967 -2220 2057 -1114 2061 -1124 1007 -2242 2025 -1134 2055 -1168 2017 -1138 2075 -1134 2053 -1136 2075 -1130 979 -2214 979 -2174 999 -2182 1001 -2204 977 -2206 1003 -2188 979 -2176 999 -2182 1009 -2176 1009 -2176 1001 -2212 2029 -1116 2091 -1102 2109 -1092 2095 -1126 1001 -2150 1011 -2180 1011 -2180 1009 -2178 1009 -2172 1009 -2166 1001 -2198 2065 -1136 975 -2220 971 -16018 2097 -1166 951 -2240 2009 -1186 2011 -1160 979 -2208 2035 -1134 2053 -1138 2061 -1158 2045 -1152 2029 -1152 2051 -1166 963 -2188 993 -2222 951 -2214 963 -2220 965 -2212 979 -2212 977 -2180 1003 -2202 965 -2218 975 -2216 967 -2188 2061 -1124 2083 -1126 2071 -1130 2059 -1134 993 -2188 979 -2240 947 -2204 979 -2214 971 -2214 973 -2210 971 -2206 2053 -1130 979 -2216 969 -16056 2053 -1134 1001 -2224 2021 -1150 2051 -1154 953 -2240 2045 -1146 2023 -1168 2033 -1144 2065 -1146 2055 -1130 2071 -1160 961 -2192 973 -2190 1005 -2214 975 -2206 967 -2206 975 -2206 967 -2208 975 -2212 967 -2212 979 -2218 977 -2178 2063 -1156 2035 -1160 2061 -1126 2065 -1130 981 -2186 1003 -2210 977 -2208 973 -2202 977 -2200 965 -2248 943 -2206 2039 -1190 941 -48536 65 -7254 263 -68 363 -102 131 -232 263 -264 751 -230 225 -822 397 -634 231 -268 263 -134 267 -64 867 -132 305 -138 67 -100 331 -98 891 -66 455 -66 531 -100 299 -134 897 -98 693 -132 291 -132 333 -98 337 -68 331
|
||||
@@ -1,27 +1,31 @@
|
||||
#include "flipper.pb.h"
|
||||
#include <core/check.h>
|
||||
#include <core/record.h>
|
||||
#include "pb_decode.h"
|
||||
#include <rpc/rpc.h>
|
||||
#include "rpc/rpc_i.h"
|
||||
#include "storage.pb.h"
|
||||
#include "storage/filesystem_api_defines.h"
|
||||
#include "storage/storage.h"
|
||||
#include <furi.h>
|
||||
#include "../minunit.h"
|
||||
#include <stdint.h>
|
||||
#include <pb.h>
|
||||
#include <pb_encode.h>
|
||||
#include <m-list.h>
|
||||
#include <lib/toolbox/md5_calc.h>
|
||||
#include <lib/toolbox/path.h>
|
||||
#include <cli/cli.h>
|
||||
#include <loader/loader.h>
|
||||
#include <protobuf_version.h>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <semphr.h>
|
||||
|
||||
#include <rpc/rpc.h>
|
||||
#include <rpc/rpc_i.h>
|
||||
#include <cli/cli.h>
|
||||
#include <storage/storage.h>
|
||||
#include <loader/loader.h>
|
||||
#include <storage/filesystem_api_defines.h>
|
||||
|
||||
#include <lib/toolbox/md5_calc.h>
|
||||
#include <lib/toolbox/path.h>
|
||||
|
||||
#include <m-list.h>
|
||||
#include "../minunit.h"
|
||||
|
||||
#include <protobuf_version.h>
|
||||
#include <pb.h>
|
||||
#include <pb_encode.h>
|
||||
#include <pb_decode.h>
|
||||
#include <storage.pb.h>
|
||||
#include <flipper.pb.h>
|
||||
|
||||
LIST_DEF(MsgList, PB_Main, M_POD_OPLIST)
|
||||
#define M_OPL_MsgList_t() LIST_OPLIST(MsgList)
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ static bool write_file_13DA(Storage* storage, const char* path) {
|
||||
File* file = storage_file_alloc(storage);
|
||||
bool result = false;
|
||||
if(storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
|
||||
result = storage_file_write(file, "13DA", 4) == 4;
|
||||
result = (storage_file_write(file, "13DA", 4) == 4);
|
||||
}
|
||||
storage_file_close(file);
|
||||
storage_file_free(file);
|
||||
|
||||
@@ -115,6 +115,66 @@ MU_TEST(storage_file_open_close) {
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
static bool storage_file_read_write_test(File* file, uint8_t* data, size_t test_size) {
|
||||
const char* filename = UNIT_TESTS_PATH("storage_chunk.test");
|
||||
|
||||
// fill with pattern
|
||||
for(size_t i = 0; i < test_size; i++) {
|
||||
data[i] = (i % 113);
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
do {
|
||||
if(!storage_file_open(file, filename, FSAM_WRITE, FSOM_CREATE_ALWAYS)) break;
|
||||
if(test_size != storage_file_write(file, data, test_size)) break;
|
||||
storage_file_close(file);
|
||||
|
||||
// reset data
|
||||
memset(data, 0, test_size);
|
||||
|
||||
if(!storage_file_open(file, filename, FSAM_READ, FSOM_OPEN_EXISTING)) break;
|
||||
if(test_size != storage_file_read(file, data, test_size)) break;
|
||||
storage_file_close(file);
|
||||
|
||||
// check that data is correct
|
||||
for(size_t i = 0; i < test_size; i++) {
|
||||
if(data[i] != (i % 113)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result = true;
|
||||
} while(false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MU_TEST(storage_file_read_write_64k) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
File* file = storage_file_alloc(storage);
|
||||
|
||||
size_t size_1k = 1024;
|
||||
size_t size_64k = size_1k + size_1k * 63;
|
||||
size_t size_65k = size_64k + size_1k;
|
||||
size_t size_max = size_65k + 8;
|
||||
|
||||
size_t max_ram_block = memmgr_heap_get_max_free_block();
|
||||
|
||||
if(max_ram_block < size_max) {
|
||||
mu_warn("Not enough RAM for >64k block test");
|
||||
} else {
|
||||
uint8_t* data = malloc(size_max);
|
||||
mu_check(storage_file_read_write_test(file, data, size_1k));
|
||||
mu_check(storage_file_read_write_test(file, data, size_64k));
|
||||
mu_check(storage_file_read_write_test(file, data, size_65k));
|
||||
mu_check(storage_file_read_write_test(file, data, size_max));
|
||||
free(data);
|
||||
}
|
||||
|
||||
storage_file_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(storage_file) {
|
||||
storage_file_open_lock_setup();
|
||||
MU_RUN_TEST(storage_file_open_close);
|
||||
@@ -122,6 +182,10 @@ MU_TEST_SUITE(storage_file) {
|
||||
storage_file_open_lock_teardown();
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(storage_file_64k) {
|
||||
MU_RUN_TEST(storage_file_read_write_64k);
|
||||
}
|
||||
|
||||
MU_TEST(storage_dir_open_close) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
File* file;
|
||||
@@ -640,6 +704,7 @@ MU_TEST_SUITE(test_md5_calc_suite) {
|
||||
|
||||
int run_minunit_test_storage() {
|
||||
MU_RUN_SUITE(storage_file);
|
||||
MU_RUN_SUITE(storage_file_64k);
|
||||
MU_RUN_SUITE(storage_dir);
|
||||
MU_RUN_SUITE(storage_rename);
|
||||
MU_RUN_SUITE(test_data_path);
|
||||
|
||||
@@ -229,17 +229,17 @@ typedef struct {
|
||||
size_t pos;
|
||||
} SubGhzHalAsyncTxTest;
|
||||
|
||||
#define SUBGHZ_HAL_TEST_DURATION 1
|
||||
#define SUBGHZ_HAL_TEST_DURATION 3
|
||||
|
||||
static LevelDuration subghz_hal_async_tx_test_yield(void* context) {
|
||||
SubGhzHalAsyncTxTest* test = context;
|
||||
bool is_odd = test->pos % 2;
|
||||
|
||||
if(test->type == SubGhzHalAsyncTxTestTypeNormal) {
|
||||
if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_reset();
|
||||
} else {
|
||||
@@ -249,36 +249,36 @@ static LevelDuration subghz_hal_async_tx_test_yield(void* context) {
|
||||
if(test->pos == 0) {
|
||||
test->pos++;
|
||||
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
} else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_reset();
|
||||
} else {
|
||||
furi_crash("Yield after reset");
|
||||
}
|
||||
} else if(test->type == SubGhzHalAsyncTxTestTypeInvalidMid) {
|
||||
if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
|
||||
if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
|
||||
test->pos++;
|
||||
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
} else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_reset();
|
||||
} else {
|
||||
furi_crash("Yield after reset");
|
||||
}
|
||||
} else if(test->type == SubGhzHalAsyncTxTestTypeInvalidEnd) {
|
||||
if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
|
||||
if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
|
||||
test->pos++;
|
||||
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
} else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
|
||||
test->pos++;
|
||||
return level_duration_reset();
|
||||
} else {
|
||||
@@ -292,20 +292,20 @@ static LevelDuration subghz_hal_async_tx_test_yield(void* context) {
|
||||
furi_crash("Yield after reset");
|
||||
}
|
||||
} else if(test->type == SubGhzHalAsyncTxTestTypeResetMid) {
|
||||
if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
|
||||
if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
|
||||
test->pos++;
|
||||
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
|
||||
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
|
||||
test->pos++;
|
||||
return level_duration_reset();
|
||||
} else {
|
||||
furi_crash("Yield after reset");
|
||||
}
|
||||
} else if(test->type == SubGhzHalAsyncTxTestTypeResetEnd) {
|
||||
if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
|
||||
if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL) {
|
||||
test->pos++;
|
||||
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
|
||||
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
|
||||
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL) {
|
||||
test->pos++;
|
||||
return level_duration_reset();
|
||||
} else {
|
||||
@@ -324,6 +324,7 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) {
|
||||
furi_hal_subghz_set_frequency_and_path(433920000);
|
||||
|
||||
if(!furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test)) {
|
||||
mu_warn("SubGHZ transmission is prohibited");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -331,6 +332,8 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) {
|
||||
|
||||
while(!furi_hal_subghz_is_async_tx_complete()) {
|
||||
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||
furi_hal_subghz_stop_async_tx();
|
||||
furi_hal_subghz_sleep();
|
||||
return false;
|
||||
}
|
||||
furi_delay_ms(10);
|
||||
@@ -652,6 +655,13 @@ MU_TEST(subghz_decoder_kinggates_stylo4k_test) {
|
||||
"Test decoder " SUBGHZ_PROTOCOL_KINGGATES_STYLO_4K_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_decoder_mastercode_test) {
|
||||
mu_assert(
|
||||
subghz_decoder_test(
|
||||
EXT_PATH("unit_tests/subghz/mastercode_raw.sub"), SUBGHZ_PROTOCOL_MASTERCODE_NAME),
|
||||
"Test decoder " SUBGHZ_PROTOCOL_MASTERCODE_NAME " error\r\n");
|
||||
}
|
||||
|
||||
//test encoders
|
||||
MU_TEST(subghz_encoder_princeton_test) {
|
||||
mu_assert(
|
||||
@@ -803,6 +813,12 @@ MU_TEST(subghz_encoder_dooya_test) {
|
||||
"Test encoder " SUBGHZ_PROTOCOL_DOOYA_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_encoder_mastercode_test) {
|
||||
mu_assert(
|
||||
subghz_encoder_test(EXT_PATH("unit_tests/subghz/mastercode.sub")),
|
||||
"Test encoder " SUBGHZ_PROTOCOL_MASTERCODE_NAME " error\r\n");
|
||||
}
|
||||
|
||||
MU_TEST(subghz_random_test) {
|
||||
mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n");
|
||||
}
|
||||
@@ -853,6 +869,7 @@ MU_TEST_SUITE(subghz) {
|
||||
MU_RUN_TEST(subghz_decoder_alutech_at_4n_test);
|
||||
MU_RUN_TEST(subghz_decoder_nice_one_test);
|
||||
MU_RUN_TEST(subghz_decoder_kinggates_stylo4k_test);
|
||||
MU_RUN_TEST(subghz_decoder_mastercode_test);
|
||||
|
||||
MU_RUN_TEST(subghz_encoder_princeton_test);
|
||||
MU_RUN_TEST(subghz_encoder_came_test);
|
||||
@@ -879,6 +896,7 @@ MU_TEST_SUITE(subghz) {
|
||||
MU_RUN_TEST(subghz_encoder_smc5326_test);
|
||||
MU_RUN_TEST(subghz_encoder_holtek_ht12x_test);
|
||||
MU_RUN_TEST(subghz_encoder_dooya_test);
|
||||
MU_RUN_TEST(subghz_encoder_mastercode_test);
|
||||
|
||||
MU_RUN_TEST(subghz_random_test);
|
||||
subghz_test_deinit();
|
||||
|
||||
@@ -29,6 +29,7 @@ int run_minunit_test_bit_lib();
|
||||
int run_minunit_test_float_tools();
|
||||
int run_minunit_test_bt();
|
||||
int run_minunit_test_dialogs_file_browser_options();
|
||||
int run_minunit_test_expansion();
|
||||
|
||||
typedef int (*UnitTestEntry)();
|
||||
|
||||
@@ -60,6 +61,7 @@ const UnitTest unit_tests[] = {
|
||||
{.name = "bt", .entry = run_minunit_test_bt},
|
||||
{.name = "dialogs_file_browser_options",
|
||||
.entry = run_minunit_test_dialogs_file_browser_options},
|
||||
{.name = "expansion", .entry = run_minunit_test_expansion},
|
||||
};
|
||||
|
||||
void minunit_print_progress() {
|
||||
@@ -78,6 +80,16 @@ void minunit_print_fail(const char* str) {
|
||||
printf(_FURI_LOG_CLR_E "%s\r\n" _FURI_LOG_CLR_RESET, str);
|
||||
}
|
||||
|
||||
void minunit_printf_warning(const char* format, ...) {
|
||||
FuriString* str = furi_string_alloc();
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
furi_string_vprintf(str, format, args);
|
||||
va_end(args);
|
||||
printf(_FURI_LOG_CLR_W "%s\r\n" _FURI_LOG_CLR_RESET, furi_string_get_cstr(str));
|
||||
furi_string_free(str);
|
||||
}
|
||||
|
||||
void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
|
||||
UNUSED(cli);
|
||||
UNUSED(args);
|
||||
|
||||
@@ -3,7 +3,6 @@ App(
|
||||
name="USB Mouse",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="usb_mouse_app",
|
||||
cdefines=["APP_USB_MOUSE"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=60,
|
||||
|
||||
@@ -3,7 +3,6 @@ App(
|
||||
name="USB Test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="usb_test_app",
|
||||
cdefines=["APP_USB_TEST"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=50,
|
||||
|
||||
@@ -3,7 +3,6 @@ App(
|
||||
name="Vibro Test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="vibro_test_app",
|
||||
cdefines=["APP_VIBRO_TEST"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=20,
|
||||
|
||||
@@ -17,18 +17,18 @@
|
||||
|
||||
#define TAG "SubGhzDeviceCc1101Ext"
|
||||
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO &gpio_ext_pb2
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO (&gpio_ext_pb2)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO &gpio_ext_pc3
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_FORCE_DANGEROUS_RANGE false
|
||||
|
||||
#define SUBGHZ_DEVICE_CC1101_CONFIG_VER 1
|
||||
|
||||
/* DMA Channels definition */
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA DMA2
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL LL_DMA_CHANNEL_3
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL LL_DMA_CHANNEL_4
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL LL_DMA_CHANNEL_5
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ FuriHalInterruptIdDma2Ch3
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA (DMA2)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL (LL_DMA_CHANNEL_3)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL (LL_DMA_CHANNEL_4)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL (LL_DMA_CHANNEL_5)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ (FuriHalInterruptIdDma2Ch3)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF \
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF \
|
||||
@@ -37,10 +37,10 @@
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL
|
||||
|
||||
/** Low level buffer dimensions and guard times */
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL (256)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL (256u)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF \
|
||||
(SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL / 2)
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME 999 << 1
|
||||
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME (999u >> 1)
|
||||
|
||||
/** SubGhz state */
|
||||
typedef enum {
|
||||
@@ -48,7 +48,6 @@ typedef enum {
|
||||
SubGhzDeviceCC1101ExtStateIdle, /**< Idle, energy save mode */
|
||||
SubGhzDeviceCC1101ExtStateAsyncRx, /**< Async RX started */
|
||||
SubGhzDeviceCC1101ExtStateAsyncTx, /**< Async TX started, DMA and timer is on */
|
||||
SubGhzDeviceCC1101ExtStateAsyncTxEnd, /**< Async TX complete, cleanup needed */
|
||||
} SubGhzDeviceCC1101ExtState;
|
||||
|
||||
/** SubGhz regulation, receive transmission on the current frequency for the
|
||||
@@ -58,13 +57,25 @@ typedef enum {
|
||||
SubGhzDeviceCC1101ExtRegulationTxRx, /**TxRx*/
|
||||
} SubGhzDeviceCC1101ExtRegulation;
|
||||
|
||||
typedef enum {
|
||||
SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateIdle,
|
||||
SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateReset,
|
||||
SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateRun,
|
||||
} SubGhzDeviceCC1101ExtAsyncTxMiddlewareState;
|
||||
|
||||
typedef struct {
|
||||
SubGhzDeviceCC1101ExtAsyncTxMiddlewareState state;
|
||||
bool is_odd_level;
|
||||
uint32_t adder_duration;
|
||||
} SubGhzDeviceCC1101ExtAsyncTxMiddleware;
|
||||
|
||||
typedef struct {
|
||||
uint32_t* buffer;
|
||||
LevelDuration carry_ld;
|
||||
SubGhzDeviceCC1101ExtCallback callback;
|
||||
void* callback_context;
|
||||
uint32_t gpio_tx_buff[2];
|
||||
uint32_t debug_gpio_buff[2];
|
||||
SubGhzDeviceCC1101ExtAsyncTxMiddleware middleware;
|
||||
} SubGhzDeviceCC1101ExtAsyncTx;
|
||||
|
||||
typedef struct {
|
||||
@@ -283,8 +294,8 @@ void subghz_device_cc1101_ext_dump_state() {
|
||||
|
||||
void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data) {
|
||||
//load config
|
||||
subghz_device_cc1101_ext_reset();
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
uint32_t i = 0;
|
||||
uint8_t pa[8] = {0};
|
||||
while(preset_data[i]) {
|
||||
@@ -313,8 +324,8 @@ void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data) {
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_load_registers(const uint8_t* data) {
|
||||
subghz_device_cc1101_ext_reset();
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
uint32_t i = 0;
|
||||
while(data[i]) {
|
||||
cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, data[i], data[i + 1]);
|
||||
@@ -396,6 +407,7 @@ void subghz_device_cc1101_ext_reset() {
|
||||
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
// Warning: push pull cc1101 clock output on GD0
|
||||
cc1101_write_reg(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance);
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
@@ -404,6 +416,9 @@ void subghz_device_cc1101_ext_reset() {
|
||||
void subghz_device_cc1101_ext_idle() {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
//waiting for the chip to switch to IDLE mode
|
||||
furi_check(cc1101_wait_status_state(
|
||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101StateIDLE, 10000));
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
if(subghz_device_cc1101_ext->power_amp) {
|
||||
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 0);
|
||||
@@ -413,6 +428,9 @@ void subghz_device_cc1101_ext_idle() {
|
||||
void subghz_device_cc1101_ext_rx() {
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_switch_to_rx(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
//waiting for the chip to switch to Rx mode
|
||||
furi_check(
|
||||
cc1101_wait_status_state(subghz_device_cc1101_ext->spi_bus_handle, CC1101StateRX, 10000));
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
if(subghz_device_cc1101_ext->power_amp) {
|
||||
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 0);
|
||||
@@ -423,6 +441,9 @@ bool subghz_device_cc1101_ext_tx() {
|
||||
if(subghz_device_cc1101_ext->regulation != SubGhzDeviceCC1101ExtRegulationTxRx) return false;
|
||||
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
cc1101_switch_to_tx(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
//waiting for the chip to switch to Tx mode
|
||||
furi_check(
|
||||
cc1101_wait_status_state(subghz_device_cc1101_ext->spi_bus_handle, CC1101StateTX, 10000));
|
||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||
if(subghz_device_cc1101_ext->power_amp) {
|
||||
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 1);
|
||||
@@ -616,50 +637,90 @@ void subghz_device_cc1101_ext_stop_async_rx() {
|
||||
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
static void subghz_device_cc1101_ext_async_tx_refill(uint32_t* buffer, size_t samples) {
|
||||
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx);
|
||||
while(samples > 0) {
|
||||
bool is_odd = samples % 2;
|
||||
LevelDuration ld;
|
||||
if(level_duration_is_reset(subghz_device_cc1101_ext->async_tx.carry_ld)) {
|
||||
ld = subghz_device_cc1101_ext->async_tx.callback(
|
||||
subghz_device_cc1101_ext->async_tx.callback_context);
|
||||
} else {
|
||||
ld = subghz_device_cc1101_ext->async_tx.carry_ld;
|
||||
subghz_device_cc1101_ext->async_tx.carry_ld = level_duration_reset();
|
||||
void subghz_device_cc1101_ext_async_tx_middleware_idle(
|
||||
SubGhzDeviceCC1101ExtAsyncTxMiddleware* middleware) {
|
||||
middleware->state = SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateIdle;
|
||||
middleware->is_odd_level = false;
|
||||
middleware->adder_duration = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
|
||||
}
|
||||
|
||||
static inline uint32_t subghz_device_cc1101_ext_async_tx_middleware_get_duration(
|
||||
SubGhzDeviceCC1101ExtAsyncTxMiddleware* middleware,
|
||||
SubGhzDeviceCC1101ExtCallback callback) {
|
||||
uint32_t ret = 0;
|
||||
bool is_level = false;
|
||||
|
||||
if(middleware->state == SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateReset) return 0;
|
||||
|
||||
while(1) {
|
||||
LevelDuration ld = callback(subghz_device_cc1101_ext->async_tx.callback_context);
|
||||
if(level_duration_is_reset(ld)) {
|
||||
middleware->state = SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateReset;
|
||||
if(!middleware->is_odd_level) {
|
||||
return 0;
|
||||
} else {
|
||||
return middleware->adder_duration;
|
||||
}
|
||||
} else if(level_duration_is_wait(ld)) {
|
||||
middleware->is_odd_level = !middleware->is_odd_level;
|
||||
ret = middleware->adder_duration + SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
|
||||
middleware->adder_duration = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(level_duration_is_wait(ld)) {
|
||||
*buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
|
||||
buffer++;
|
||||
samples--;
|
||||
} else if(level_duration_is_reset(ld)) {
|
||||
is_level = level_duration_get_level(ld);
|
||||
|
||||
if(middleware->state == SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateIdle) {
|
||||
if(is_level != middleware->is_odd_level) {
|
||||
middleware->state = SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateRun;
|
||||
middleware->is_odd_level = is_level;
|
||||
middleware->adder_duration = level_duration_get_duration(ld);
|
||||
return SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(middleware->state == SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateRun) {
|
||||
if(is_level == middleware->is_odd_level) {
|
||||
middleware->adder_duration += level_duration_get_duration(ld);
|
||||
continue;
|
||||
} else {
|
||||
middleware->is_odd_level = is_level;
|
||||
ret = middleware->adder_duration;
|
||||
middleware->adder_duration = level_duration_get_duration(ld);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void subghz_device_cc1101_ext_async_tx_refill(uint32_t* buffer, size_t samples) {
|
||||
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx);
|
||||
|
||||
while(samples > 0) {
|
||||
volatile uint32_t duration = subghz_device_cc1101_ext_async_tx_middleware_get_duration(
|
||||
&subghz_device_cc1101_ext->async_tx.middleware,
|
||||
subghz_device_cc1101_ext->async_tx.callback);
|
||||
if(duration == 0) {
|
||||
*buffer = 0;
|
||||
buffer++;
|
||||
samples--;
|
||||
LL_DMA_DisableIT_HT(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
|
||||
LL_DMA_DisableIT_TC(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
|
||||
LL_TIM_EnableIT_UPDATE(TIM17);
|
||||
if(LL_DMA_IsActiveFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) {
|
||||
LL_DMA_ClearFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA);
|
||||
}
|
||||
if(LL_DMA_IsActiveFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) {
|
||||
LL_DMA_ClearFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
bool level = level_duration_get_level(ld);
|
||||
|
||||
// Inject guard time if level is incorrect
|
||||
if(is_odd != level) {
|
||||
*buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
|
||||
buffer++;
|
||||
samples--;
|
||||
|
||||
// Special case: prevent buffer overflow if sample is last
|
||||
if(samples == 0) {
|
||||
subghz_device_cc1101_ext->async_tx.carry_ld = ld;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t duration = level_duration_get_duration(ld);
|
||||
furi_assert(duration > 0);
|
||||
*buffer = duration >> 1;
|
||||
// Lowest possible value is 4us
|
||||
if(duration < 4) duration = 4;
|
||||
// Divide by 2 since timer resolution is 2us
|
||||
// Subtract 1 since we counting from 0
|
||||
*buffer = (duration >> 1) - 1;
|
||||
buffer++;
|
||||
samples--;
|
||||
}
|
||||
@@ -688,20 +749,6 @@ static void subghz_device_cc1101_ext_async_tx_dma_isr() {
|
||||
#endif
|
||||
}
|
||||
|
||||
static void subghz_device_cc1101_ext_async_tx_timer_isr() {
|
||||
if(LL_TIM_IsActiveFlag_UPDATE(TIM17)) {
|
||||
if(LL_TIM_GetAutoReload(TIM17) == 0) {
|
||||
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
|
||||
if(subghz_device_cc1101_ext->async_mirror_pin != NULL)
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false);
|
||||
LL_TIM_DisableCounter(TIM17);
|
||||
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTxEnd;
|
||||
}
|
||||
LL_TIM_ClearFlag_UPDATE(TIM17);
|
||||
}
|
||||
}
|
||||
|
||||
bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callback, void* context) {
|
||||
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle);
|
||||
furi_assert(callback);
|
||||
@@ -730,7 +777,7 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF,
|
||||
LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
|
||||
LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD |
|
||||
LL_DMA_MODE_NORMAL);
|
||||
LL_DMA_PRIORITY_VERYHIGH);
|
||||
LL_DMA_SetDataLength(
|
||||
SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL);
|
||||
LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, LL_DMAMUX_REQ_TIM17_UP);
|
||||
@@ -746,16 +793,15 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
|
||||
|
||||
// Configure TIM
|
||||
// Set the timer resolution to 2 us
|
||||
LL_TIM_SetPrescaler(TIM17, (64 << 1) - 1);
|
||||
LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP);
|
||||
LL_TIM_SetAutoReload(TIM17, 0xFFFF);
|
||||
LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1);
|
||||
LL_TIM_SetAutoReload(TIM17, 500);
|
||||
LL_TIM_SetPrescaler(TIM17, (64 << 1) - 1);
|
||||
LL_TIM_SetClockSource(TIM17, LL_TIM_CLOCKSOURCE_INTERNAL);
|
||||
LL_TIM_DisableARRPreload(TIM17);
|
||||
|
||||
furi_hal_interrupt_set_isr(
|
||||
FuriHalInterruptIdTim1TrgComTim17, subghz_device_cc1101_ext_async_tx_timer_isr, NULL);
|
||||
|
||||
subghz_device_cc1101_ext_async_tx_middleware_idle(
|
||||
&subghz_device_cc1101_ext->async_tx.middleware);
|
||||
subghz_device_cc1101_ext_async_tx_refill(
|
||||
subghz_device_cc1101_ext->async_tx.buffer, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL);
|
||||
|
||||
@@ -801,7 +847,6 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
|
||||
|
||||
// Start counter
|
||||
LL_TIM_EnableDMAReq_UPDATE(TIM17);
|
||||
LL_TIM_GenerateEvent_UPDATE(TIM17);
|
||||
|
||||
subghz_device_cc1101_ext_tx();
|
||||
|
||||
@@ -812,19 +857,22 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
|
||||
}
|
||||
|
||||
bool subghz_device_cc1101_ext_is_async_tx_complete() {
|
||||
return subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd;
|
||||
return (
|
||||
(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx) &&
|
||||
(LL_TIM_GetAutoReload(TIM17) == 0));
|
||||
}
|
||||
|
||||
void subghz_device_cc1101_ext_stop_async_tx() {
|
||||
furi_assert(
|
||||
subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx ||
|
||||
subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd);
|
||||
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx);
|
||||
|
||||
// Shutdown radio
|
||||
subghz_device_cc1101_ext_idle();
|
||||
|
||||
// Deinitialize GPIO
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
|
||||
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
// Deinitialize Timer
|
||||
FURI_CRITICAL_ENTER();
|
||||
furi_hal_bus_disable(FuriHalBusTIM17);
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdTim1TrgComTim17, NULL, NULL);
|
||||
|
||||
@@ -833,17 +881,11 @@ void subghz_device_cc1101_ext_stop_async_tx() {
|
||||
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF);
|
||||
furi_hal_interrupt_set_isr(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ, NULL, NULL);
|
||||
|
||||
// Deinitialize GPIO
|
||||
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
|
||||
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
// Stop debug
|
||||
if(subghz_device_cc1101_ext_stop_debug()) {
|
||||
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF);
|
||||
}
|
||||
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
free(subghz_device_cc1101_ext->async_tx.buffer);
|
||||
|
||||
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle;
|
||||
|
||||
@@ -14,6 +14,7 @@ App(
|
||||
entry_point="advanced_plugin1_ep",
|
||||
requires=["example_advanced_plugins"],
|
||||
sources=["plugin1.c"],
|
||||
fal_embedded=True,
|
||||
)
|
||||
|
||||
App(
|
||||
@@ -22,4 +23,5 @@ App(
|
||||
entry_point="advanced_plugin2_ep",
|
||||
requires=["example_advanced_plugins"],
|
||||
sources=["plugin2.c"],
|
||||
fal_embedded=True,
|
||||
)
|
||||
|
||||
@@ -23,7 +23,10 @@ int32_t example_advanced_plugins_app(void* p) {
|
||||
PLUGIN_APP_ID, PLUGIN_API_VERSION, composite_api_resolver_get(resolver));
|
||||
|
||||
do {
|
||||
if(plugin_manager_load_all(manager, APP_DATA_PATH("plugins")) != PluginManagerErrorNone) {
|
||||
// For built-in .fals (fal_embedded==True), use APP_ASSETS_PATH
|
||||
// Otherwise, use APP_DATA_PATH
|
||||
if(plugin_manager_load_all(manager, APP_ASSETS_PATH("plugins")) !=
|
||||
PluginManagerErrorNone) {
|
||||
FURI_LOG_E(TAG, "Failed to load all libs");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -153,7 +153,9 @@ void archive_update_focus(ArchiveBrowserView* browser, const char* target) {
|
||||
|
||||
archive_get_items(browser, furi_string_get_cstr(browser->path));
|
||||
|
||||
if(!archive_file_get_array_size(browser) && archive_is_home(browser)) {
|
||||
ArchiveTabEnum tab = archive_get_tab(browser);
|
||||
if(!archive_file_get_array_size(browser) && archive_is_home(browser) &&
|
||||
(tab != ArchiveTabBrowser)) {
|
||||
archive_switch_tab(browser, TAB_LEFT);
|
||||
} else {
|
||||
with_view_model(
|
||||
@@ -220,7 +222,8 @@ void archive_file_array_rm_selected(ArchiveBrowserView* browser) {
|
||||
},
|
||||
false);
|
||||
|
||||
if((items_cnt == 0) && (archive_is_home(browser))) {
|
||||
ArchiveTabEnum tab = archive_get_tab(browser);
|
||||
if((items_cnt == 0) && (archive_is_home(browser)) && (tab != ArchiveTabBrowser)) {
|
||||
archive_switch_tab(browser, TAB_LEFT);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,12 +12,12 @@ static bool archive_favorites_read_line(File* file, FuriString* str_result) {
|
||||
bool result = false;
|
||||
|
||||
do {
|
||||
uint16_t read_count = storage_file_read(file, buffer, ARCHIVE_FAV_FILE_BUF_LEN);
|
||||
size_t read_count = storage_file_read(file, buffer, ARCHIVE_FAV_FILE_BUF_LEN);
|
||||
if(storage_file_get_error(file) != FSE_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(uint16_t i = 0; i < read_count; i++) {
|
||||
for(size_t i = 0; i < read_count; i++) {
|
||||
if(buffer[i] == '\n') {
|
||||
uint32_t position = storage_file_tell(file);
|
||||
if(storage_file_get_error(file) != FSE_OK) {
|
||||
|
||||
@@ -585,6 +585,10 @@ static bool archive_view_input(InputEvent* event, void* context) {
|
||||
((model->item_idx - scroll_speed) + model->item_cnt) %
|
||||
model->item_cnt;
|
||||
}
|
||||
// Fix for empty folders, we can't select -1 item
|
||||
if(model->item_idx < 0) {
|
||||
model->item_idx = 0;
|
||||
}
|
||||
if(is_file_list_load_required(model)) {
|
||||
model->list_loading = true;
|
||||
browser->callback(ArchiveBrowserEventLoadPrevItems, browser->context);
|
||||
|
||||
Binary file not shown.
@@ -3,7 +3,7 @@ App(
|
||||
name="GPIO",
|
||||
apptype=FlipperAppType.MENUEXTERNAL,
|
||||
entry_point="gpio_app",
|
||||
stack_size=1 * 1024,
|
||||
stack_size=2 * 1024,
|
||||
icon="A_GPIO_14",
|
||||
order=50,
|
||||
fap_libs=["assets"],
|
||||
|
||||
@@ -24,6 +24,9 @@ static void gpio_app_tick_event_callback(void* context) {
|
||||
GpioApp* gpio_app_alloc() {
|
||||
GpioApp* app = malloc(sizeof(GpioApp));
|
||||
|
||||
app->expansion = furi_record_open(RECORD_EXPANSION);
|
||||
expansion_disable(app->expansion);
|
||||
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->gpio_items = gpio_items_alloc();
|
||||
|
||||
@@ -99,6 +102,9 @@ void gpio_app_free(GpioApp* app) {
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
|
||||
expansion_enable(app->expansion);
|
||||
furi_record_close(RECORD_EXPANSION);
|
||||
|
||||
gpio_items_free(app->gpio_items);
|
||||
free(app);
|
||||
}
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
#include "views/gpio_test.h"
|
||||
#include "views/gpio_usb_uart.h"
|
||||
#include <assets_icons.h>
|
||||
#include <expansion/expansion.h>
|
||||
|
||||
struct GpioApp {
|
||||
Expansion* expansion;
|
||||
Gui* gui;
|
||||
NotificationApp* notifications;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
|
||||
@@ -27,6 +27,7 @@ static const uint32_t baudrate_list[] = {
|
||||
460800,
|
||||
921600,
|
||||
};
|
||||
static const char* software_de_re[] = {"None", "4"};
|
||||
|
||||
bool gpio_scene_usb_uart_cfg_on_event(void* context, SceneManagerEvent event) {
|
||||
GpioApp* app = context;
|
||||
@@ -45,7 +46,7 @@ void line_ensure_flow_invariant(GpioApp* app) {
|
||||
// selected. This function enforces that invariant by resetting flow_pins
|
||||
// to None if it is configured to 16,15 when LPUART is selected.
|
||||
|
||||
uint8_t available_flow_pins = app->usb_uart_cfg->uart_ch == FuriHalUartIdLPUART1 ? 3 : 4;
|
||||
uint8_t available_flow_pins = app->usb_uart_cfg->uart_ch == FuriHalSerialIdLpuart ? 3 : 4;
|
||||
VariableItem* item = app->var_item_flow;
|
||||
variable_item_set_values_count(item, available_flow_pins);
|
||||
|
||||
@@ -76,14 +77,25 @@ static void line_port_cb(VariableItem* item) {
|
||||
variable_item_set_current_value_text(item, uart_ch[index]);
|
||||
|
||||
if(index == 0)
|
||||
app->usb_uart_cfg->uart_ch = FuriHalUartIdUSART1;
|
||||
app->usb_uart_cfg->uart_ch = FuriHalSerialIdUsart;
|
||||
else if(index == 1)
|
||||
app->usb_uart_cfg->uart_ch = FuriHalUartIdLPUART1;
|
||||
app->usb_uart_cfg->uart_ch = FuriHalSerialIdLpuart;
|
||||
|
||||
line_ensure_flow_invariant(app);
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet);
|
||||
}
|
||||
|
||||
static void line_software_de_re_cb(VariableItem* item) {
|
||||
GpioApp* app = variable_item_get_context(item);
|
||||
furi_assert(app);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, software_de_re[index]);
|
||||
|
||||
app->usb_uart_cfg->software_de_re = index;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet);
|
||||
}
|
||||
|
||||
static void line_flow_cb(VariableItem* item) {
|
||||
GpioApp* app = variable_item_get_context(item);
|
||||
furi_assert(app);
|
||||
@@ -155,6 +167,11 @@ void gpio_scene_usb_uart_cfg_on_enter(void* context) {
|
||||
app->var_item_flow = item;
|
||||
line_ensure_flow_invariant(app);
|
||||
|
||||
item = variable_item_list_add(
|
||||
var_item_list, "DE/RE Pin", COUNT_OF(software_de_re), line_software_de_re_cb, app);
|
||||
variable_item_set_current_value_index(item, app->usb_uart_cfg->software_de_re);
|
||||
variable_item_set_current_value_text(item, software_de_re[app->usb_uart_cfg->software_de_re]);
|
||||
|
||||
variable_item_list_set_selected_item(
|
||||
var_item_list, scene_manager_get_scene_state(app->scene_manager, GpioAppViewUsbUartCfg));
|
||||
|
||||
|
||||
@@ -6,11 +6,16 @@
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_usb_cdc.h>
|
||||
|
||||
//TODO: FL-3276 port to new USART API
|
||||
#include <stm32wbxx_ll_lpuart.h>
|
||||
#include <stm32wbxx_ll_usart.h>
|
||||
|
||||
#define USB_CDC_PKT_LEN CDC_DATA_SZ
|
||||
#define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5)
|
||||
|
||||
#define USB_CDC_BIT_DTR (1 << 0)
|
||||
#define USB_CDC_BIT_RTS (1 << 1)
|
||||
#define USB_USART_DE_RE_PIN &gpio_ext_pa4
|
||||
|
||||
static const GpioPin* flow_pins[][2] = {
|
||||
{&gpio_ext_pa7, &gpio_ext_pa6}, // 2, 3
|
||||
@@ -24,17 +29,18 @@ typedef enum {
|
||||
|
||||
WorkerEvtTxStop = (1 << 2),
|
||||
WorkerEvtCdcRx = (1 << 3),
|
||||
WorkerEvtCdcTxComplete = (1 << 4),
|
||||
|
||||
WorkerEvtCfgChange = (1 << 4),
|
||||
WorkerEvtCfgChange = (1 << 5),
|
||||
|
||||
WorkerEvtLineCfgSet = (1 << 5),
|
||||
WorkerEvtCtrlLineSet = (1 << 6),
|
||||
WorkerEvtLineCfgSet = (1 << 6),
|
||||
WorkerEvtCtrlLineSet = (1 << 7),
|
||||
|
||||
} WorkerEvtFlags;
|
||||
|
||||
#define WORKER_ALL_RX_EVENTS \
|
||||
(WorkerEvtStop | WorkerEvtRxDone | WorkerEvtCfgChange | WorkerEvtLineCfgSet | \
|
||||
WorkerEvtCtrlLineSet)
|
||||
WorkerEvtCtrlLineSet | WorkerEvtCdcTxComplete)
|
||||
#define WORKER_ALL_TX_EVENTS (WorkerEvtTxStop | WorkerEvtCdcRx)
|
||||
|
||||
struct UsbUartBridge {
|
||||
@@ -45,6 +51,7 @@ struct UsbUartBridge {
|
||||
FuriThread* tx_thread;
|
||||
|
||||
FuriStreamBuffer* rx_stream;
|
||||
FuriHalSerialHandle* serial_handle;
|
||||
|
||||
FuriMutex* usb_mutex;
|
||||
|
||||
@@ -75,11 +82,23 @@ static const CdcCallbacks cdc_cb = {
|
||||
|
||||
static int32_t usb_uart_tx_thread(void* context);
|
||||
|
||||
static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) {
|
||||
static void usb_uart_on_irq_rx_dma_cb(
|
||||
FuriHalSerialHandle* handle,
|
||||
FuriHalSerialRxEvent ev,
|
||||
size_t size,
|
||||
void* context) {
|
||||
UsbUartBridge* usb_uart = (UsbUartBridge*)context;
|
||||
|
||||
if(ev == UartIrqEventRXNE) {
|
||||
furi_stream_buffer_send(usb_uart->rx_stream, &data, 1, 0);
|
||||
if(ev & (FuriHalSerialRxEventData | FuriHalSerialRxEventIdle)) {
|
||||
uint8_t data[FURI_HAL_SERIAL_DMA_BUFFER_SIZE] = {0};
|
||||
while(size) {
|
||||
size_t ret = furi_hal_serial_dma_rx(
|
||||
handle,
|
||||
data,
|
||||
(size > FURI_HAL_SERIAL_DMA_BUFFER_SIZE) ? FURI_HAL_SERIAL_DMA_BUFFER_SIZE : size);
|
||||
furi_stream_buffer_send(usb_uart->rx_stream, data, ret, 0);
|
||||
size -= ret;
|
||||
};
|
||||
furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtRxDone);
|
||||
}
|
||||
}
|
||||
@@ -111,32 +130,33 @@ static void usb_uart_vcp_deinit(UsbUartBridge* usb_uart, uint8_t vcp_ch) {
|
||||
}
|
||||
|
||||
static void usb_uart_serial_init(UsbUartBridge* usb_uart, uint8_t uart_ch) {
|
||||
if(uart_ch == FuriHalUartIdUSART1) {
|
||||
furi_hal_console_disable();
|
||||
} else if(uart_ch == FuriHalUartIdLPUART1) {
|
||||
furi_hal_uart_init(uart_ch, 115200);
|
||||
}
|
||||
furi_hal_uart_set_irq_cb(uart_ch, usb_uart_on_irq_cb, usb_uart);
|
||||
furi_assert(!usb_uart->serial_handle);
|
||||
|
||||
usb_uart->serial_handle = furi_hal_serial_control_acquire(uart_ch);
|
||||
furi_assert(usb_uart->serial_handle);
|
||||
|
||||
furi_hal_serial_init(usb_uart->serial_handle, 115200);
|
||||
furi_hal_serial_dma_rx_start(
|
||||
usb_uart->serial_handle, usb_uart_on_irq_rx_dma_cb, usb_uart, false);
|
||||
}
|
||||
|
||||
static void usb_uart_serial_deinit(UsbUartBridge* usb_uart, uint8_t uart_ch) {
|
||||
UNUSED(usb_uart);
|
||||
furi_hal_uart_set_irq_cb(uart_ch, NULL, NULL);
|
||||
if(uart_ch == FuriHalUartIdUSART1)
|
||||
furi_hal_console_enable();
|
||||
else if(uart_ch == FuriHalUartIdLPUART1)
|
||||
furi_hal_uart_deinit(uart_ch);
|
||||
static void usb_uart_serial_deinit(UsbUartBridge* usb_uart) {
|
||||
furi_assert(usb_uart->serial_handle);
|
||||
|
||||
furi_hal_serial_deinit(usb_uart->serial_handle);
|
||||
furi_hal_serial_control_release(usb_uart->serial_handle);
|
||||
usb_uart->serial_handle = NULL;
|
||||
}
|
||||
|
||||
static void usb_uart_set_baudrate(UsbUartBridge* usb_uart, uint32_t baudrate) {
|
||||
if(baudrate != 0) {
|
||||
furi_hal_uart_set_br(usb_uart->cfg.uart_ch, baudrate);
|
||||
furi_hal_serial_set_br(usb_uart->serial_handle, baudrate);
|
||||
usb_uart->st.baudrate_cur = baudrate;
|
||||
} else {
|
||||
struct usb_cdc_line_coding* line_cfg =
|
||||
furi_hal_cdc_get_port_settings(usb_uart->cfg.vcp_ch);
|
||||
if(line_cfg->dwDTERate > 0) {
|
||||
furi_hal_uart_set_br(usb_uart->cfg.uart_ch, line_cfg->dwDTERate);
|
||||
furi_hal_serial_set_br(usb_uart->serial_handle, line_cfg->dwDTERate);
|
||||
usb_uart->st.baudrate_cur = line_cfg->dwDTERate;
|
||||
}
|
||||
}
|
||||
@@ -186,7 +206,7 @@ static int32_t usb_uart_worker(void* context) {
|
||||
furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
|
||||
furi_check(!(events & FuriFlagError));
|
||||
if(events & WorkerEvtStop) break;
|
||||
if(events & WorkerEvtRxDone) {
|
||||
if(events & (WorkerEvtRxDone | WorkerEvtCdcTxComplete)) {
|
||||
size_t len = furi_stream_buffer_receive(
|
||||
usb_uart->rx_stream, usb_uart->rx_buf, USB_CDC_PKT_LEN, 0);
|
||||
if(len > 0) {
|
||||
@@ -218,7 +238,7 @@ static int32_t usb_uart_worker(void* context) {
|
||||
furi_thread_flags_set(furi_thread_get_id(usb_uart->tx_thread), WorkerEvtTxStop);
|
||||
furi_thread_join(usb_uart->tx_thread);
|
||||
|
||||
usb_uart_serial_deinit(usb_uart, usb_uart->cfg.uart_ch);
|
||||
usb_uart_serial_deinit(usb_uart);
|
||||
usb_uart_serial_init(usb_uart, usb_uart->cfg_new.uart_ch);
|
||||
|
||||
usb_uart->cfg.uart_ch = usb_uart->cfg_new.uart_ch;
|
||||
@@ -247,6 +267,17 @@ static int32_t usb_uart_worker(void* context) {
|
||||
usb_uart->cfg.flow_pins = usb_uart->cfg_new.flow_pins;
|
||||
events |= WorkerEvtCtrlLineSet;
|
||||
}
|
||||
if(usb_uart->cfg.software_de_re != usb_uart->cfg_new.software_de_re) {
|
||||
usb_uart->cfg.software_de_re = usb_uart->cfg_new.software_de_re;
|
||||
if(usb_uart->cfg.software_de_re != 0) {
|
||||
furi_hal_gpio_write(USB_USART_DE_RE_PIN, true);
|
||||
furi_hal_gpio_init(
|
||||
USB_USART_DE_RE_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedMedium);
|
||||
} else {
|
||||
furi_hal_gpio_init(
|
||||
USB_USART_DE_RE_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
}
|
||||
api_lock_unlock(usb_uart->cfg_lock);
|
||||
}
|
||||
if(events & WorkerEvtLineCfgSet) {
|
||||
@@ -258,7 +289,9 @@ static int32_t usb_uart_worker(void* context) {
|
||||
}
|
||||
}
|
||||
usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch);
|
||||
usb_uart_serial_deinit(usb_uart, usb_uart->cfg.uart_ch);
|
||||
usb_uart_serial_deinit(usb_uart);
|
||||
|
||||
furi_hal_gpio_init(USB_USART_DE_RE_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
if(usb_uart->cfg.flow_pins != 0) {
|
||||
furi_hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][0], GpioModeAnalog);
|
||||
@@ -298,7 +331,16 @@ static int32_t usb_uart_tx_thread(void* context) {
|
||||
|
||||
if(len > 0) {
|
||||
usb_uart->st.tx_cnt += len;
|
||||
furi_hal_uart_tx(usb_uart->cfg.uart_ch, data, len);
|
||||
|
||||
if(usb_uart->cfg.software_de_re != 0)
|
||||
furi_hal_gpio_write(USB_USART_DE_RE_PIN, false);
|
||||
|
||||
furi_hal_serial_tx(usb_uart->serial_handle, data, len);
|
||||
|
||||
if(usb_uart->cfg.software_de_re != 0) {
|
||||
furi_hal_serial_tx_wait_complete(usb_uart->serial_handle);
|
||||
furi_hal_gpio_write(USB_USART_DE_RE_PIN, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -310,6 +352,7 @@ static int32_t usb_uart_tx_thread(void* context) {
|
||||
static void vcp_on_cdc_tx_complete(void* context) {
|
||||
UsbUartBridge* usb_uart = (UsbUartBridge*)context;
|
||||
furi_semaphore_release(usb_uart->tx_sem);
|
||||
furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtCdcTxComplete);
|
||||
}
|
||||
|
||||
static void vcp_on_cdc_rx(void* context) {
|
||||
|
||||
@@ -11,6 +11,7 @@ typedef struct {
|
||||
uint8_t flow_pins;
|
||||
uint8_t baudrate_mode;
|
||||
uint32_t baudrate;
|
||||
uint8_t software_de_re;
|
||||
} UsbUartConfig;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -174,22 +174,21 @@ void ibutton_free(iButton* ibutton) {
|
||||
free(ibutton);
|
||||
}
|
||||
|
||||
bool ibutton_load_key(iButton* ibutton) {
|
||||
bool ibutton_load_key(iButton* ibutton, bool show_error) {
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewLoading);
|
||||
|
||||
const bool success = ibutton_protocols_load(
|
||||
ibutton->protocols, ibutton->key, furi_string_get_cstr(ibutton->file_path));
|
||||
|
||||
if(!success) {
|
||||
dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file");
|
||||
|
||||
} else {
|
||||
if(success) {
|
||||
FuriString* tmp = furi_string_alloc();
|
||||
|
||||
path_extract_filename(ibutton->file_path, tmp, true);
|
||||
strncpy(ibutton->key_name, furi_string_get_cstr(tmp), IBUTTON_KEY_NAME_SIZE);
|
||||
|
||||
furi_string_free(tmp);
|
||||
} else if(show_error) {
|
||||
dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file");
|
||||
}
|
||||
|
||||
return success;
|
||||
@@ -210,7 +209,7 @@ bool ibutton_select_and_load_key(iButton* ibutton) {
|
||||
if(!dialog_file_browser_show(
|
||||
ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options))
|
||||
break;
|
||||
success = ibutton_load_key(ibutton);
|
||||
success = ibutton_load_key(ibutton, true);
|
||||
} while(!success);
|
||||
|
||||
return success;
|
||||
@@ -283,7 +282,7 @@ int32_t ibutton_app(void* arg) {
|
||||
|
||||
} else {
|
||||
furi_string_set(ibutton->file_path, (const char*)arg);
|
||||
key_loaded = ibutton_load_key(ibutton);
|
||||
key_loaded = ibutton_load_key(ibutton, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ typedef enum {
|
||||
} iButtonNotificationMessage;
|
||||
|
||||
bool ibutton_select_and_load_key(iButton* ibutton);
|
||||
bool ibutton_load_key(iButton* ibutton);
|
||||
bool ibutton_load_key(iButton* ibutton, bool show_error);
|
||||
bool ibutton_save_key(iButton* ibutton);
|
||||
bool ibutton_delete_key(iButton* ibutton);
|
||||
void ibutton_reset_key(iButton* ibutton);
|
||||
|
||||
@@ -43,7 +43,7 @@ bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) {
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
// User cancelled editing, reload the key from storage
|
||||
if(scene_manager_has_previous_scene(scene_manager, iButtonSceneSavedKeyMenu)) {
|
||||
if(!ibutton_load_key(ibutton)) {
|
||||
if(!ibutton_load_key(ibutton, true)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
scene_manager, iButtonSceneStart);
|
||||
}
|
||||
|
||||
@@ -9,9 +9,8 @@ void ibutton_scene_delete_success_on_enter(void* context) {
|
||||
iButton* ibutton = context;
|
||||
Popup* popup = ibutton->popup;
|
||||
|
||||
popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
|
||||
popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom);
|
||||
|
||||
popup_set_icon(popup, 0, 2, &I_DolphinMafia_119x62);
|
||||
popup_set_header(popup, "Deleted", 80, 19, AlignLeft, AlignBottom);
|
||||
popup_set_callback(popup, ibutton_scene_delete_success_popup_callback);
|
||||
popup_set_context(popup, ibutton);
|
||||
popup_set_timeout(popup, 1500);
|
||||
|
||||
@@ -23,15 +23,15 @@ void ibutton_scene_emulate_on_enter(void* context) {
|
||||
|
||||
furi_string_printf(
|
||||
tmp,
|
||||
"%s\n[%s]",
|
||||
furi_string_empty(ibutton->file_path) ? "Unsaved Key" : ibutton->key_name,
|
||||
ibutton_protocols_get_name(ibutton->protocols, ibutton_key_get_protocol_id(key)));
|
||||
"[%s]\n%s",
|
||||
ibutton_protocols_get_name(ibutton->protocols, ibutton_key_get_protocol_id(key)),
|
||||
furi_string_empty(ibutton->file_path) ? "Unsaved Key" : ibutton->key_name);
|
||||
|
||||
widget_add_text_box_element(
|
||||
widget, 52, 38, 75, 26, AlignCenter, AlignCenter, furi_string_get_cstr(tmp), true);
|
||||
widget, 52, 30, 75, 40, AlignCenter, AlignCenter, furi_string_get_cstr(tmp), true);
|
||||
|
||||
widget_add_string_multiline_element(
|
||||
widget, 88, 10, AlignCenter, AlignTop, FontPrimary, "iButton\nemulating");
|
||||
widget, 88, 5, AlignCenter, AlignTop, FontPrimary, "iButton\nemulating");
|
||||
|
||||
ibutton_worker_emulate_set_callback(ibutton->worker, ibutton_scene_emulate_callback, ibutton);
|
||||
ibutton_worker_emulate_start(ibutton->worker, key);
|
||||
|
||||
@@ -8,21 +8,19 @@ void ibutton_scene_info_on_enter(void* context) {
|
||||
const iButtonProtocolId protocol_id = ibutton_key_get_protocol_id(key);
|
||||
|
||||
FuriString* tmp = furi_string_alloc();
|
||||
FuriString* keynumber = furi_string_alloc();
|
||||
|
||||
ibutton_protocols_render_brief_data(ibutton->protocols, key, keynumber);
|
||||
|
||||
furi_string_printf(
|
||||
tmp,
|
||||
"\e#%s [%s]\e#",
|
||||
"\e#%s\n[%s]\e#\n%s",
|
||||
ibutton->key_name,
|
||||
ibutton_protocols_get_name(ibutton->protocols, protocol_id));
|
||||
ibutton_protocols_get_name(ibutton->protocols, protocol_id),
|
||||
furi_string_get_cstr(keynumber));
|
||||
|
||||
widget_add_text_box_element(
|
||||
widget, 0, 2, 128, 12, AlignLeft, AlignTop, furi_string_get_cstr(tmp), true);
|
||||
|
||||
furi_string_reset(tmp);
|
||||
ibutton_protocols_render_brief_data(ibutton->protocols, key, tmp);
|
||||
|
||||
widget_add_string_multiline_element(
|
||||
widget, 0, 16, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(tmp));
|
||||
widget, 0, 2, 128, 64, AlignLeft, AlignTop, furi_string_get_cstr(tmp), true);
|
||||
|
||||
if(ibutton_protocols_get_features(ibutton->protocols, protocol_id) &
|
||||
iButtonProtocolFeatureExtData) {
|
||||
@@ -32,6 +30,7 @@ void ibutton_scene_info_on_enter(void* context) {
|
||||
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
|
||||
furi_string_free(tmp);
|
||||
furi_string_free(keynumber);
|
||||
}
|
||||
|
||||
bool ibutton_scene_info_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
@@ -26,7 +26,7 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.event == iButtonCustomEventRpcLoadFile) {
|
||||
bool result = false;
|
||||
|
||||
if(ibutton_load_key(ibutton)) {
|
||||
if(ibutton_load_key(ibutton, false)) {
|
||||
popup_set_text(popup, ibutton->key_name, 82, 32, AlignCenter, AlignTop);
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
|
||||
|
||||
|
||||
@@ -9,9 +9,8 @@ void ibutton_scene_save_success_on_enter(void* context) {
|
||||
iButton* ibutton = context;
|
||||
Popup* popup = ibutton->popup;
|
||||
|
||||
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
|
||||
popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
|
||||
|
||||
popup_set_icon(popup, 36, 5, &I_DolphinSaved_92x58);
|
||||
popup_set_header(popup, "Saved", 15, 19, AlignLeft, AlignBottom);
|
||||
popup_set_callback(popup, ibutton_scene_save_success_popup_callback);
|
||||
popup_set_context(popup, ibutton);
|
||||
popup_set_timeout(popup, 1500);
|
||||
|
||||
@@ -42,12 +42,12 @@ void ibutton_scene_write_on_enter(void* context) {
|
||||
|
||||
furi_string_printf(
|
||||
tmp,
|
||||
"%s\n[%s]",
|
||||
ibutton->key_name,
|
||||
ibutton_protocols_get_name(ibutton->protocols, protocol_id));
|
||||
"[%s]\n%s ",
|
||||
ibutton_protocols_get_name(ibutton->protocols, protocol_id),
|
||||
ibutton->key_name);
|
||||
|
||||
widget_add_text_box_element(
|
||||
widget, 52, 38, 75, 26, AlignCenter, AlignCenter, furi_string_get_cstr(tmp), true);
|
||||
widget, 52, 30, 75, 40, AlignCenter, AlignCenter, furi_string_get_cstr(tmp), true);
|
||||
|
||||
ibutton_worker_write_set_callback(worker, ibutton_scene_write_callback, ibutton);
|
||||
|
||||
@@ -63,7 +63,7 @@ void ibutton_scene_write_on_enter(void* context) {
|
||||
}
|
||||
|
||||
widget_add_string_multiline_element(
|
||||
widget, 88, 10, AlignCenter, AlignTop, FontPrimary, furi_string_get_cstr(tmp));
|
||||
widget, 88, 5, AlignCenter, AlignTop, FontPrimary, furi_string_get_cstr(tmp));
|
||||
|
||||
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
|
||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
|
||||
|
||||
@@ -10,7 +10,7 @@ void ibutton_scene_write_success_on_enter(void* context) {
|
||||
iButton* ibutton = context;
|
||||
Popup* popup = ibutton->popup;
|
||||
|
||||
popup_set_icon(popup, 0, 12, &I_iButtonDolphinVerySuccess_108x52);
|
||||
popup_set_icon(popup, 0, 9, &I_iButtonDolphinVerySuccess_92x55);
|
||||
popup_set_text(popup, "Successfully written!", 40, 12, AlignLeft, AlignBottom);
|
||||
|
||||
popup_set_callback(popup, ibutton_scene_write_success_popup_callback);
|
||||
|
||||
@@ -807,3 +807,155 @@ type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 6175 7369 602 1570 602 1570 601 1570 573 1598 574 1598 573 1597 574 1597 574 1598 574 525 574 526 573 526 573 527 572 528 571 529 570 529 570 530 568 1603 568 1627 544 1627 544 1627 544 1628 544 554 545 1627 544 1628 544 555 544 555 544 555 544 555 544 554 544 1627 545 555 544 554 545 1627 544 1627 544 1627 544 1627 544 1627 544 1603 568 1602 569 1603 569 530 569 529 570 529 570 529 570 529 570 529 570 529 570 528 570 1601 571 528 570 1602 570 529 570 528 570 1601 570 1600 571 1601 571 528 571 1601 570 528 570 1601 570 1602 570 529 570 529 570 528 570 1601 570 1601 570 1600 571 1601 571 528 570 1601 570 1601 571 528 571 528 571 529 570 528 571 528 570 1601 571 528 571 528 570 1603 570 529 571 1603 570 529 570 1603 570 529 570 1603 570 529 571 1602 571 1603 570 529 571 1603 570 529 571 1603 570 529 571 1603 570 530 570 7370 570
|
||||
#
|
||||
# Model: AUX YKR-H/006E
|
||||
#
|
||||
name: Off
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8957 4502 539 1683 538 1681 540 559 538 559 538 556 541 557 540 1683 538 1682 539 1684 537 1682 539 1681 540 1684 537 1684 537 1682 539 1684 537 558 539 558 539 558 539 558 539 559 538 558 539 1682 539 1681 540 1683 538 557 540 558 539 558 539 557 540 559 538 557 540 557 540 561 536 559 538 558 539 557 540 558 539 558 539 1683 538 558 539 1682 540 557 540 559 538 557 540 557 540 561 536 558 539 559 538 558 539 560 537 557 540 558 539 558 539 558 539 559 538 558 539 1682 539 557 540 558 539 557 540 557 540 558 539 560 537 557 540 557 540 558 539 559 538 557 540 559 538 556 541 558 539 558 539 558 539 556 541 559 538 557 540 558 539 558 539 558 539 557 540 558 539 557 541 557 540 557 540 559 538 558 539 558 539 558 539 558 539 1681 540 557 540 1683 538 558 539 559 538 557 540 559 538 559 538 1683 538 1683 538 1683 538 557 540 558 539 558 540 1683 538 560 563
|
||||
#
|
||||
name: Dh
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8956 4504 536 1684 537 1687 534 559 538 559 538 559 538 560 537 1683 538 1685 536 1682 539 1684 537 1683 538 1684 537 1683 538 1684 537 1683 538 558 539 562 535 559 538 558 539 562 535 560 537 1683 538 1684 537 1683 538 561 536 561 536 561 537 560 537 561 536 558 539 560 537 559 538 560 537 561 536 561 536 563 534 559 538 1684 537 559 538 1684 537 561 536 560 537 560 537 560 537 560 537 560 537 559 538 559 538 559 538 588 509 558 539 559 538 559 538 564 533 1684 537 559 538 560 537 559 538 588 509 563 534 559 538 559 538 558 539 562 535 558 539 561 536 560 537 560 537 559 538 588 509 561 536 560 537 561 536 563 534 561 536 560 537 561 536 1684 537 559 538 559 538 559 538 561 536 560 537 560 537 559 538 561 536 558 539 560 537 1684 537 559 538 1683 538 561 536 561 536 563 534 559 538 558 539 1683 538 1684 537 1684 537 560 537 560 537 1683 538 560 537 560 563
|
||||
#
|
||||
name: Cool_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8957 4502 538 1683 538 1684 537 562 535 560 537 559 538 559 539 1683 538 1682 539 1711 510 1685 536 1683 538 558 539 588 509 557 540 1682 539 557 540 558 539 559 538 559 538 558 539 561 536 1681 540 1682 539 1683 538 559 538 559 538 559 538 561 536 560 537 559 538 558 539 559 538 559 538 559 538 559 538 560 537 560 537 1685 536 560 537 1685 536 560 537 559 538 560 537 560 537 559 538 558 539 559 538 560 537 587 510 562 535 559 538 560 537 557 540 1685 536 559 538 560 537 587 510 588 509 559 538 562 535 560 537 557 540 559 538 557 540 560 537 587 510 560 538 558 539 559 538 559 538 561 536 560 537 560 537 558 540 560 537 559 538 560 537 1683 538 562 535 560 537 559 538 560 537 558 539 559 538 558 539 560 537 560 537 559 538 1683 538 558 539 1684 537 559 538 558 539 559 538 558 539 558 539 1682 539 1684 537 1684 537 1683 538 560 537 558 539 1683 538 1684 564
|
||||
#
|
||||
name: Cool_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8956 4501 539 1682 539 1682 539 559 538 557 540 587 510 558 539 1684 537 1682 539 1682 539 1682 539 1680 541 1682 539 1682 539 1682 539 1681 540 558 539 558 539 558 539 557 540 558 539 557 540 1683 538 1683 538 1683 538 558 539 558 539 558 539 557 540 560 537 560 537 557 540 558 539 557 540 558 539 557 540 560 537 558 539 1681 540 556 541 1684 537 558 539 557 540 559 538 558 539 557 540 558 539 558 539 560 537 559 538 558 539 558 539 557 540 559 538 1685 536 559 538 558 539 587 510 557 540 559 538 559 538 560 537 560 537 558 539 559 538 558 539 559 538 562 535 558 539 557 540 557 540 559 538 559 538 558 539 559 538 558 539 558 539 557 540 1682 539 557 540 558 539 559 538 557 540 558 539 560 537 559 538 557 540 561 536 558 539 1682 539 558 539 1682 539 559 538 557 540 558 539 559 538 559 538 1682 539 1684 537 1683 538 557 540 558 539 558 539 560 537 559 564
|
||||
#
|
||||
name: Heat_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8959 4502 539 1682 539 1682 539 556 541 559 538 558 539 559 538 1680 541 1681 540 1684 537 1683 538 1684 537 557 540 560 537 558 539 1683 538 1682 539 558 539 559 538 559 538 558 539 558 539 1683 538 1681 540 1683 538 559 538 560 537 560 537 559 538 561 536 560 537 559 538 559 538 559 538 559 538 559 538 560 537 557 540 1682 539 557 540 1682 539 559 538 558 539 560 538 558 539 558 539 558 539 558 539 558 539 559 538 559 538 557 540 558 539 558 539 559 538 560 537 1684 537 561 536 557 540 559 538 559 538 557 540 558 539 559 538 560 537 558 539 558 539 559 538 558 539 559 539 559 538 557 540 559 538 557 540 558 540 561 536 558 539 558 539 1683 538 558 539 559 538 557 540 559 538 557 540 558 539 559 538 559 538 558 539 559 538 1681 540 558 539 1684 537 562 535 560 537 559 538 559 538 560 537 1682 539 1682 539 1682 539 1686 535 559 538 1682 539 559 538 1682 565
|
||||
#
|
||||
name: Heat_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8961 4501 539 1681 540 1681 540 559 538 558 539 558 539 557 540 1682 539 1682 539 1681 540 1682 539 1682 539 1683 538 1682 539 1683 538 1682 539 557 540 560 537 558 539 560 537 560 537 558 539 1681 540 1681 540 1682 539 557 540 558 539 561 536 558 539 560 537 558 539 556 541 558 539 558 539 557 540 559 538 558 539 559 538 1684 537 559 538 1682 539 558 539 556 541 559 538 562 535 556 541 558 539 558 539 557 540 558 539 557 540 558 539 559 538 560 537 557 540 557 540 1682 539 558 539 557 540 558 539 559 538 559 538 557 540 558 539 558 539 558 539 558 539 557 540 561 536 558 539 586 511 558 539 557 540 586 511 559 539 556 541 557 540 557 540 1682 539 559 538 558 539 558 539 559 538 558 539 560 537 558 539 559 538 558 539 557 540 1681 540 558 539 1680 541 557 540 557 540 559 538 558 539 559 538 1682 539 1682 539 1682 539 558 539 558 539 1682 539 1682 539 558 565
|
||||
#
|
||||
# Model: Carrier 42QG5A580SC
|
||||
#
|
||||
name: Off
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8403 4308 519 1425 518 625 520 1461 485 1427 518 559 517 564 567 1386 518 1429 517 562 597 524 519 1431 517 1430 518 567 516 1426 518 565 517 1429 518 1431 518 1425 519 565 517 1457 485 562 518 1429 519 1424 520 565 516 1426 517 561 519 1430 515 1427 518 563 595 525 518 1428 517 528 489 21085 8424 4296 642 467 568 1400 569 533 569 536 647 1402 569 1395 569 535 568 534 569 1405 566 1397 567 549 568 535 569 1401 567 533 570 1399 571 537 570 534 568 537 567 1397 570 535 571 1401 568 534 567 533 567 1399 567 539 568 1402 569 565 569 532 571 1399 571 1397 569 535 566 1358 489 21085 8401 4318 512 1438 517 573 515 1476 532 1389 516 573 518 609 535 1393 568 1392 516 574 567 528 566 1393 565 1390 516 576 516 1437 517 574 517 1441 516 1445 567 1389 517 578 566 1390 516 578 568 1398 566 1392 515 575 516 1437 516 574 517 1442 567 1425 483 597 515 575 516 1446 514 539 490
|
||||
#
|
||||
name: Dh
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8391 4318 536 1417 518 564 516 1432 517 1428 518 563 518 562 517 1433 516 1428 518 564 519 565 513 1433 517 1430 517 562 518 1463 483 561 517 1430 516 1428 518 563 595 1393 516 559 519 565 514 1425 519 1429 517 569 514 1426 518 566 514 1466 485 562 518 559 518 561 518 1425 519 531 488 21116 8369 4318 569 534 641 1326 640 462 641 465 641 1330 641 1325 639 464 568 534 595 1403 641 1328 641 462 639 467 640 1328 568 536 642 1367 568 531 567 536 569 1398 568 537 542 1432 640 1327 567 532 568 535 567 1400 567 539 567 1399 568 536 568 1402 569 1402 568 1401 567 537 565 1359 487 21117 8392 4294 565 1388 517 575 566 1393 516 1443 514 574 516 573 517 1443 567 1391 515 574 516 577 566 1393 565 1390 566 528 567 1392 516 575 567 1395 565 1390 515 576 568 1391 515 572 566 528 565 1395 565 1393 515 572 564 1391 515 581 563 1389 516 578 513 609 483 576 566 1391 514 538 487
|
||||
#
|
||||
name: Cool_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8424 4292 514 1428 518 559 518 1431 514 1432 517 561 515 566 512 1433 516 1434 516 562 519 562 516 1432 517 1426 518 566 516 1429 517 566 516 1429 518 1428 517 562 516 1467 481 570 517 561 518 565 519 563 515 566 516 567 516 1433 516 1429 514 564 518 561 518 562 519 1428 519 536 562 21009 8478 4280 638 461 641 1328 641 456 642 467 637 1325 643 1326 568 597 568 537 639 1330 641 1327 568 535 640 468 639 1324 568 534 543 1432 566 535 641 494 637 1327 566 532 640 1329 567 1398 640 1327 641 1327 640 1326 642 1328 568 531 568 538 567 1402 567 1406 566 1402 568 532 569 1357 489 21085 8401 4319 565 1394 516 577 567 1396 565 1390 515 574 543 566 516 1441 568 1392 516 575 566 531 566 1393 567 1390 516 576 515 1456 515 579 562 1392 515 1440 515 575 566 1391 516 576 544 569 563 525 516 574 514 606 514 576 514 1439 567 1390 515 575 515 574 570 566 567 1390 515 540 488
|
||||
#
|
||||
name: Cool_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8401 4306 518 1460 483 566 518 1432 517 1430 514 561 516 564 517 1429 518 1430 519 592 485 564 517 1427 517 1432 516 561 545 1430 516 566 518 1462 483 1430 515 568 517 1427 516 566 516 564 517 1430 518 1425 518 559 518 562 518 1426 518 1425 517 593 484 561 516 573 516 1427 517 530 564 21007 8401 4322 642 465 643 1324 643 457 643 458 643 1327 643 1327 641 463 642 461 644 1325 644 1324 643 462 642 483 643 1328 641 460 645 1321 643 458 643 464 641 1325 643 459 644 1327 642 1323 643 461 643 461 642 1347 644 1331 641 463 639 462 641 1327 571 1405 542 1428 670 462 645 1282 562 21007 8402 4317 515 1436 517 606 641 1321 516 1438 517 572 515 578 516 1441 515 1440 516 572 515 575 515 1474 610 1316 515 574 644 1314 516 574 567 1394 640 1316 517 578 639 1319 516 576 517 575 513 1447 641 1315 516 576 515 577 566 1396 514 1440 516 573 518 571 638 456 565 1393 515 538 564
|
||||
#
|
||||
name: Heat_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8399 4307 519 1426 518 560 517 1432 517 1460 485 561 518 558 517 1436 518 1427 518 555 520 561 517 1430 519 1428 516 560 519 1425 518 566 517 1430 516 1432 519 563 519 1425 518 563 515 1429 517 1433 517 1430 516 1432 518 1429 518 568 516 1432 515 1429 519 561 516 567 517 1427 519 533 487 21083 8424 4339 567 536 568 1402 641 493 608 462 545 1431 640 1326 567 532 568 538 640 1331 640 1329 641 536 565 534 641 1329 567 537 639 1329 640 462 642 467 641 1325 568 532 642 1332 640 488 568 534 565 536 566 566 536 567 641 1329 570 535 638 464 569 1401 641 1326 568 534 639 1287 490 21083 8403 4313 567 1390 516 579 514 1441 515 1438 517 575 516 576 568 1393 568 1394 515 606 534 530 515 1441 567 1425 482 576 568 1392 514 578 566 1392 569 1432 515 576 568 1389 517 577 515 1444 515 1437 569 1393 516 1444 566 1389 566 528 567 1394 566 1419 517 575 513 578 515 1440 516 539 490
|
||||
#
|
||||
name: Heat_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 8425 4291 542 1401 544 538 542 1404 518 1427 544 534 570 540 516 1434 542 1399 544 539 544 539 541 1403 541 1402 516 570 517 1427 545 566 511 1406 517 1431 542 534 544 1406 543 536 517 567 543 1404 542 1400 595 525 544 1405 542 534 516 1433 516 1428 544 537 544 535 543 1403 542 505 488 21084 8424 4298 566 535 569 1402 567 533 568 537 570 1403 570 1403 565 534 566 537 566 1402 569 1398 569 533 569 538 592 1446 569 535 570 1400 569 567 535 535 568 1437 568 533 568 1398 569 1402 565 533 567 534 569 1403 568 536 569 1402 568 535 567 534 571 1403 568 1415 566 536 571 1362 489 21084 8403 4313 516 1439 517 574 515 1442 515 1441 518 573 516 574 567 1397 514 1440 515 573 516 575 516 1443 515 1439 518 574 516 1440 517 608 535 1396 517 1441 517 579 515 1438 515 576 517 578 568 1390 569 1391 516 575 518 1439 516 573 517 1445 566 1391 516 571 517 572 516 1441 514 543 487
|
||||
#
|
||||
# Model: Samsung DB93
|
||||
#
|
||||
name: Off
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 667 17837 3089 8903 555 445 578 1411 583 442 554 442 529 468 528 468 554 443 554 442 554 444 552 1441 552 472 523 475 522 1473 522 1473 522 475 547 1447 548 1446 548 1446 548 1446 548 1446 548 449 548 450 547 451 546 474 523 476 521 476 521 476 522 476 521 475 546 451 547 450 548 449 548 449 548 449 548 449 548 449 548 449 548 450 547 450 547 451 546 474 523 474 523 476 521 477 520 477 520 477 521 476 521 476 546 450 547 450 547 450 546 450 547 451 546 451 546 1448 546 1472 522 2982 3005 8963 522 1499 495 502 495 502 495 502 496 501 496 501 521 476 522 475 522 475 522 1472 522 475 522 475 522 1473 521 475 522 1473 522 1499 495 1500 494 1500 496 1499 521 1473 522 475 522 475 522 475 522 475 522 475 522 475 522 476 521 475 522 476 521 476 521 476 521 502 495 503 494 503 495 502 495 501 496 501 521 476 522 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 503 494 503 494 503 493 504 494 502 495 502 495 502 520 477 520 2984 3003 8966 519 1475 520 477 520 477 520 477 520 478 519 477 520 478 519 479 518 504 493 1502 493 504 493 503 494 503 494 1501 519 1476 518 1475 519 478 519 1476 518 1476 519 1477 517 1501 493 1503 491 1503 493 1502 493 1502 518 479 518 479 518 479 518 1476 518 1477 517 1477 517 504 493 504 493 504 493 531 466 507 490 1529 467 506 491 529 468 1527 492 1502 492 505 493 1502 492 1502 492 505 492 504 493 504 492 505 492 506 491 532 465 532 465 531 467 530 467 530 467 1528 467 1527 492
|
||||
#
|
||||
name: Dh
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 667 17829 3090 8902 556 444 579 1410 584 441 529 468 529 468 554 443 554 442 555 443 553 444 551 1442 551 474 522 475 522 1473 522 475 522 475 547 1448 547 1447 547 1447 547 1447 548 1447 547 449 548 450 547 474 523 474 523 476 521 476 521 476 521 477 521 475 522 476 546 450 547 449 548 449 548 450 547 449 548 450 547 450 547 450 547 451 546 474 523 474 523 474 523 479 518 479 518 479 518 501 496 501 496 477 545 475 522 452 545 474 523 474 523 1472 522 1472 522 1472 522 1472 523 2981 3005 8990 494 1499 495 502 496 501 496 501 496 501 522 475 522 475 522 475 522 475 522 1473 521 475 522 475 522 1473 521 475 522 1473 521 1500 494 1500 495 1499 520 1474 522 1473 522 475 522 475 522 476 521 475 522 476 521 476 521 476 521 476 521 476 521 477 520 503 494 503 494 503 495 502 495 502 520 477 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 477 520 504 493 503 494 503 494 503 495 502 495 502 495 502 520 477 520 477 520 2984 3003 8966 519 1475 519 477 520 478 519 478 519 478 519 479 518 503 494 505 492 505 492 1503 493 504 493 504 493 504 518 1477 518 1476 518 1476 518 479 518 1477 517 1477 517 1501 493 1504 490 1528 468 1527 468 1527 493 1501 493 504 493 504 493 504 493 1501 493 1502 492 1502 492 504 493 505 491 532 440 556 466 531 467 530 468 530 467 530 467 1527 492 1503 491 505 492 504 493 504 493 505 491 1503 492 505 467 530 492 506 466 557 464 533 464 532 466 1528 467 1528 467 1528 466 1528 491
|
||||
#
|
||||
name: Cool_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 667 17831 3089 8903 581 420 578 1411 583 442 529 468 528 468 554 443 554 442 554 443 553 445 551 1443 550 475 521 475 522 1473 522 475 547 449 548 1447 548 1446 548 1446 548 1446 548 1446 548 449 548 449 548 450 547 473 524 476 521 475 522 476 520 476 522 475 522 475 547 449 549 449 548 449 548 449 548 449 548 449 548 449 548 449 548 449 548 450 547 474 523 474 523 476 521 476 521 476 520 477 521 476 546 451 547 450 547 450 547 449 548 450 547 1447 547 1448 546 1448 546 1472 523 2957 3029 8967 518 1477 517 502 495 501 496 501 521 475 522 475 522 475 522 475 522 475 522 1472 522 474 523 475 522 1473 521 475 522 1472 522 1499 495 1500 495 1499 520 1474 522 1473 521 475 522 475 522 475 522 475 522 475 522 475 522 475 522 475 522 476 521 502 495 502 495 503 494 502 496 501 496 501 521 476 522 476 521 475 522 475 522 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 503 494 503 494 503 494 503 495 502 495 502 520 477 520 476 521 476 521 2984 3003 8965 520 1474 521 477 520 477 520 477 520 477 520 477 520 478 519 504 493 504 493 1502 494 503 494 502 495 1500 520 1475 519 1475 519 1475 519 478 519 1475 519 1476 518 1501 493 1502 492 1503 493 1501 494 1501 518 1476 518 478 519 478 519 478 519 1476 518 1476 518 1477 517 504 493 506 491 506 491 506 491 506 492 505 492 504 493 504 518 481 516 1501 493 504 493 504 493 480 517 1501 493 504 493 504 493 504 493 505 491 532 466 531 466 532 466 1528 467 1527 468 1527 492 1502 492
|
||||
#
|
||||
name: Cool_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 667 17832 3088 8903 575 448 555 1411 583 441 529 468 529 468 554 443 554 442 554 443 553 444 551 1443 550 474 522 475 522 1473 522 475 522 475 547 1447 548 1446 548 1446 548 1446 548 1447 547 449 548 449 548 474 523 474 523 476 521 476 521 476 521 477 521 475 522 475 547 450 548 449 548 450 547 449 548 449 548 450 547 450 547 449 547 451 546 452 545 474 523 474 523 477 520 478 519 477 519 478 520 477 545 452 545 451 547 451 546 474 523 474 523 1450 544 1472 522 1472 522 1472 523 2981 3005 8990 494 1499 495 502 496 501 496 501 521 476 521 475 522 475 522 475 522 475 522 1473 521 475 522 475 522 1473 521 476 521 1473 521 1500 494 1500 495 1499 495 1499 521 1473 522 475 522 475 522 476 521 475 522 476 521 476 521 476 521 476 521 476 521 477 520 503 494 503 494 503 495 502 495 502 520 477 520 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 477 520 477 520 478 519 503 493 504 493 504 494 503 494 502 519 478 520 477 520 477 520 2984 3003 8966 519 1475 519 477 520 477 520 478 519 478 519 478 519 503 494 504 493 505 492 1503 493 504 493 504 493 503 519 478 519 1476 518 1476 518 478 519 1476 518 1477 517 1501 493 1504 490 1504 490 1503 493 1502 493 1502 517 480 517 504 493 480 517 1477 517 1502 492 1502 492 504 493 504 493 504 493 531 466 531 466 1529 467 1527 467 1527 492 504 493 1502 492 505 492 504 493 505 492 1503 492 505 492 505 492 505 467 557 464 532 441 556 466 532 466 1528 466 1528 491 1503 491 1503 466
|
||||
#
|
||||
name: Heat_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 665 17827 3090 8902 556 444 579 1412 583 441 530 467 529 468 554 442 555 442 554 442 554 444 551 1443 550 473 523 475 522 1472 521 475 523 474 523 1471 549 1446 548 1445 549 1446 548 1445 549 448 549 448 549 449 548 473 523 473 524 475 522 475 522 475 523 475 522 474 548 449 548 449 549 448 549 448 549 448 549 448 549 448 549 449 548 449 548 449 548 450 547 473 524 474 523 476 521 476 521 476 521 476 522 475 547 450 547 450 548 449 548 449 548 1447 547 1447 547 1447 547 1448 546 2957 3030 8962 522 1475 519 501 496 501 497 478 519 500 522 475 522 475 523 474 523 474 523 1472 522 474 523 474 523 1472 522 475 522 1472 522 1499 495 1499 496 1499 496 1498 522 1473 522 474 522 475 522 475 522 474 523 475 522 475 522 475 522 475 522 475 522 475 522 502 495 502 495 502 495 501 496 501 496 501 521 476 522 475 522 475 522 475 522 475 522 475 522 475 522 475 522 475 522 475 522 476 521 476 521 502 495 502 495 502 495 503 495 502 495 501 521 476 521 476 521 2983 3004 8964 521 1474 520 476 521 476 521 477 520 476 521 477 520 477 520 503 494 503 494 1501 494 502 495 502 495 502 520 477 521 1474 520 1474 520 477 520 1474 520 1475 519 1475 519 1500 494 1502 492 1502 493 1501 494 1500 519 478 519 477 520 477 520 1475 519 1475 519 1475 519 478 519 478 519 503 494 505 492 505 492 505 492 1503 493 1502 493 1502 517 1476 518 479 518 479 518 479 518 480 517 479 518 1501 493 504 493 504 493 530 467 531 466 531 467 1527 468 1527 491 1502 493 1501 493
|
||||
#
|
||||
name: Heat_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 668 17822 3064 8902 582 442 555 1413 581 442 528 468 529 494 528 469 502 495 527 470 526 471 525 1468 552 446 550 448 549 1446 548 448 549 448 549 1446 548 1448 546 1471 523 1473 521 1473 521 476 521 475 522 475 547 449 548 449 548 449 548 449 548 449 548 449 548 449 548 449 548 450 547 474 523 474 523 474 523 477 520 477 520 477 520 477 521 476 521 476 546 450 548 450 547 474 523 474 523 450 547 474 523 474 523 452 545 474 523 474 523 474 523 1500 494 1499 495 1499 496 1498 522 2955 3032 8963 521 1472 522 475 522 474 523 475 522 475 522 475 522 475 522 475 522 475 522 1499 495 502 495 502 495 1499 496 501 521 1473 522 1473 522 1472 522 1472 522 1473 521 1473 522 475 522 475 522 502 495 502 495 502 495 503 495 501 496 501 496 501 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 477 520 504 493 503 494 503 494 503 495 502 495 502 495 502 520 477 521 476 521 476 521 476 521 477 520 477 520 477 520 476 521 477 520 2984 3003 8967 518 1502 492 504 493 504 494 503 494 503 494 503 519 478 519 478 519 478 519 1476 518 478 518 479 518 478 519 478 519 1501 493 1501 493 506 491 1504 491 1527 468 1503 492 1526 493 1501 493 1501 494 1501 493 1501 493 504 493 504 493 504 493 1528 466 1529 466 1528 467 529 468 529 493 504 493 504 493 504 493 1502 492 1502 492 1502 467 529 493 1502 491 533 465 532 465 532 465 531 467 530 467 1528 467 530 467 530 467 530 467 530 467 530 467 1527 467 1528 466 1528 466 1529 492
|
||||
#
|
||||
# Model: Samsung AR-EH04
|
||||
#
|
||||
name: Off
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 663 17769 3057 8901 529 492 527 1434 556 465 529 464 529 464 555 439 555 438 556 438 554 440 553 1435 552 444 549 470 524 1465 524 1466 522 473 522 1467 522 1466 549 1440 549 1440 548 1440 548 445 549 445 549 446 548 447 547 471 523 470 524 471 523 472 522 472 521 473 522 472 522 472 523 472 548 446 549 445 548 446 548 447 547 447 547 446 548 447 547 470 524 471 523 471 523 471 523 471 523 498 496 475 519 498 496 497 498 497 522 472 523 471 524 470 523 471 523 1443 546 1442 547 2947 3023 8935 522 1466 522 471 523 472 522 474 520 498 496 498 496 498 497 497 497 497 523 1466 523 471 523 471 523 1466 523 471 523 1466 522 1467 522 1467 522 1493 495 1493 496 1493 497 497 522 472 523 471 523 471 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 499 495 499 495 499 495 499 495 499 496 498 522 472 523 472 523 471 522 472 522 472 522 472 522 472 522 473 521 473 521 473 521 473 521 473 521 499 495 500 494 499 495 499 496 499 521 2947 3024 8937 521 1467 521 473 521 473 521 472 521 473 521 473 521 473 521 473 521 474 520 1469 520 500 494 500 494 1495 495 500 495 499 520 474 521 1468 520 1468 521 1468 521 1468 521 1468 521 1469 519 1470 518 1495 493 1496 493 500 495 499 520 474 521 1468 520 1469 520 1469 520 473 521 474 520 474 520 475 519 476 518 500 494 502 492 502 491 1497 493 1495 495 499 495 499 520 474 520 475 519 475 519 475 519 475 519 475 519 500 494 501 493 501 493 501 493 501 493 1498 491 1497 519
|
||||
#
|
||||
name: Dh
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 665 17760 3083 8875 553 468 527 1432 584 438 555 439 529 464 555 439 555 438 556 438 555 439 553 1435 552 443 550 470 524 1466 523 471 522 473 521 1467 523 1466 549 1439 549 1440 549 1439 549 445 549 445 549 445 549 446 548 470 524 470 524 471 523 472 522 472 522 473 521 472 522 472 547 447 548 445 549 445 549 445 549 445 549 446 548 445 549 445 549 447 547 470 524 471 523 471 523 471 523 473 521 473 521 473 521 473 521 472 523 472 548 446 548 1441 547 1441 548 1441 547 1441 547 2947 3023 8935 522 1466 522 472 522 474 519 475 519 475 519 474 521 473 546 448 547 448 546 1465 523 449 545 448 546 1466 522 471 523 1467 522 1466 522 1493 495 1493 495 1493 496 1493 522 471 523 471 523 471 523 471 523 471 523 471 523 471 523 472 522 472 522 472 522 472 522 472 522 499 495 498 495 499 496 498 496 498 496 498 522 472 523 471 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 473 521 473 521 499 495 500 494 500 495 499 495 499 495 498 522 2947 3023 8937 520 1467 521 473 521 473 521 473 521 473 521 473 521 473 521 474 520 474 520 1495 494 500 494 500 495 500 494 1494 520 1468 521 1467 521 473 521 1468 521 1468 520 1469 519 1469 519 1471 517 1495 494 1495 494 1494 520 474 521 473 521 473 520 1468 521 1468 521 1468 520 474 520 475 519 475 519 500 493 500 494 501 493 501 493 501 493 1495 495 1494 520 474 520 474 520 474 520 475 519 1470 518 475 519 476 518 500 493 501 493 501 493 501 493 1497 492 1497 492 1496 493 1495 518
|
||||
#
|
||||
name: Cool_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 666 17765 3056 8901 529 492 526 1434 556 465 529 464 530 464 555 438 556 438 555 439 554 440 552 1436 551 443 550 470 524 1465 524 471 523 472 522 1467 521 1467 548 1441 549 1440 548 1440 548 445 549 445 549 445 549 446 548 447 547 470 524 471 523 471 523 473 521 472 522 473 521 473 521 473 522 472 548 446 549 446 548 446 548 447 547 447 547 470 524 447 547 471 523 471 523 471 523 471 523 471 523 475 519 498 496 498 496 498 496 497 498 497 523 1466 524 1443 545 1441 548 1442 546 2947 3023 8935 522 1466 522 472 522 472 522 498 496 498 496 498 496 498 496 498 522 472 523 1466 522 471 523 471 523 1466 523 471 523 1466 523 1467 522 1467 521 1493 496 1493 495 1493 497 497 522 472 523 471 523 471 523 472 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 473 521 499 495 499 495 499 495 499 496 498 496 498 522 472 522 472 523 472 521 472 522 472 522 472 522 472 522 473 521 473 521 473 521 473 521 474 520 500 494 500 494 500 495 500 495 499 521 2947 3024 8937 520 1467 521 473 521 473 521 473 521 473 521 473 521 473 521 474 520 474 520 1469 520 500 494 500 493 1496 494 1494 495 1494 520 1468 520 473 521 1469 519 1468 521 1469 519 1470 519 1470 519 1495 493 1496 493 1495 495 499 520 474 520 474 520 1469 520 1469 519 1469 519 474 520 475 519 500 494 500 494 500 494 502 492 502 492 502 493 501 493 1496 494 500 519 475 520 475 518 1470 519 475 518 476 518 475 519 476 494 525 493 501 493 501 493 1498 491 1498 491 1497 493 1496 518
|
||||
#
|
||||
name: Cool_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 664 17763 3082 8874 553 444 552 1433 583 438 529 464 530 464 555 439 555 438 556 438 555 440 553 1435 552 443 550 470 524 1466 523 472 521 472 522 1467 523 1466 549 1439 549 1439 549 1439 550 444 550 445 549 445 549 447 547 470 524 471 523 471 523 472 522 472 522 473 521 472 523 472 522 471 549 446 549 445 549 446 548 446 548 446 548 446 548 446 548 448 546 471 523 471 523 471 523 471 523 475 519 497 497 474 520 475 520 497 497 496 524 471 524 1465 523 1442 547 1442 547 1442 547 2946 3024 8935 522 1466 522 471 523 474 520 474 520 498 496 474 521 497 522 471 523 471 523 1465 523 471 523 471 523 1466 522 471 523 1466 523 1466 523 1493 495 1493 495 1493 496 1492 523 471 523 471 523 471 523 471 523 471 523 471 523 471 523 472 522 472 522 472 522 472 522 473 521 499 495 499 495 499 496 498 497 498 497 497 523 472 522 471 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 473 521 473 521 473 521 499 495 499 495 499 496 499 496 498 496 498 522 2946 3024 8937 521 1467 521 472 522 472 522 473 521 473 521 473 521 473 521 474 520 474 520 1495 493 500 494 499 495 499 495 499 496 1493 521 1468 520 473 521 1468 520 1468 521 1468 520 1469 519 1470 518 1495 494 1495 494 1494 495 499 520 473 521 473 521 1468 520 1469 520 1468 521 474 520 474 520 475 519 475 519 476 518 1496 492 1496 494 1495 495 499 520 1469 520 474 520 474 520 474 519 1470 520 474 520 476 518 476 519 477 517 500 494 500 494 503 491 1497 492 1496 493 1495 519 1470 519
|
||||
#
|
||||
name: Heat_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 666 17758 3056 8901 528 493 526 1434 580 441 554 439 529 465 554 439 555 439 555 439 554 440 553 1435 552 443 549 470 524 1465 524 472 522 472 521 1467 523 1467 548 1440 549 1440 548 1440 549 445 549 445 549 446 548 446 548 471 523 471 523 471 523 471 523 473 521 473 521 473 521 473 522 472 547 446 549 446 549 445 548 446 548 446 548 446 548 446 548 447 547 471 523 471 523 471 523 471 523 473 521 474 520 473 521 474 521 473 522 473 546 447 548 1441 548 1442 547 1442 547 1442 546 2948 3021 8936 521 1466 522 472 522 498 496 499 494 476 519 476 519 497 497 497 523 472 522 1466 523 471 523 472 522 1466 522 472 522 1466 522 1467 522 1467 522 1493 494 1495 495 1493 522 472 522 472 522 471 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 473 521 473 521 499 495 499 495 499 495 499 496 498 521 473 522 472 523 472 522 472 522 472 522 473 521 472 522 472 522 472 522 473 521 473 521 474 520 473 521 499 495 500 494 500 495 499 495 499 521 2947 3023 8938 520 1468 520 473 521 473 521 473 521 473 521 473 521 473 521 474 520 474 520 1495 494 500 494 500 494 500 495 500 494 1494 520 1468 521 474 520 1468 520 1469 520 1468 520 1469 520 1470 518 1496 493 1496 493 1495 495 499 519 475 520 474 520 1468 520 1469 519 1469 519 474 520 475 519 475 519 476 518 500 494 500 494 1497 492 1497 492 1496 493 1495 519 475 519 475 519 475 519 475 519 475 519 1471 518 476 518 500 494 501 493 501 493 501 493 1498 491 1498 491 1496 518 1472 517
|
||||
#
|
||||
name: Heat_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 664 17757 3057 8901 528 469 550 1434 556 465 553 440 529 465 554 439 555 439 555 438 555 440 553 1435 552 443 550 470 524 1466 522 472 522 472 521 1467 523 1466 549 1440 549 1440 548 1440 548 445 549 445 549 445 549 446 548 470 524 471 523 471 523 471 523 472 522 472 522 473 522 472 523 472 548 446 549 445 550 445 548 446 548 446 548 446 548 446 548 447 547 470 524 471 523 471 523 471 523 471 523 474 519 474 521 474 521 473 522 473 546 447 547 1441 548 1442 546 1442 547 1442 546 2947 3023 8935 522 1466 522 472 522 498 496 498 495 499 496 498 496 498 521 473 522 471 523 1466 522 471 523 471 522 1466 523 471 523 1467 522 1467 522 1467 521 1493 495 1494 496 1493 521 473 522 472 522 471 523 472 522 471 523 472 522 472 522 472 522 472 522 472 522 472 522 472 522 473 521 499 495 499 495 499 495 499 496 498 522 473 522 472 523 471 522 472 522 472 522 472 522 472 522 472 522 472 522 473 521 473 521 473 521 473 521 499 495 500 494 500 495 499 496 498 522 2947 3023 8937 521 1468 520 473 521 473 521 473 521 473 521 473 521 473 521 474 520 474 520 1470 518 500 494 500 494 500 494 500 494 1494 521 1468 521 473 521 1468 520 1468 520 1469 520 1469 520 1470 518 1495 493 1496 493 1495 494 500 519 475 520 474 520 1469 519 1469 520 1469 519 474 520 474 520 475 519 477 517 500 494 1496 493 1496 493 1496 493 500 495 1495 519 475 518 475 519 475 518 476 518 475 519 1470 519 500 494 500 494 501 493 501 493 501 493 1499 490 1497 493 1497 492 1496 518
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 1st Sept, 2023
|
||||
# Last Checked 1st Oct, 2023
|
||||
# Last Updated 21st Dec, 2023
|
||||
# Last Checked 21st Dec, 2023
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
@@ -3896,3 +3896,159 @@ type: parsed
|
||||
protocol: NECext
|
||||
address: 80 70 00 00
|
||||
command: C1 3E 00 00
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 87 7C 00 00
|
||||
command: C8 37 00 00
|
||||
#
|
||||
name: Pause
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 87 7C 00 00
|
||||
command: 4A B5 00 00
|
||||
#
|
||||
name: Play
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 87 7C 00 00
|
||||
command: 01 FE 00 00
|
||||
#
|
||||
name: Prev
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 87 7C 00 00
|
||||
command: 05 FA 00 00
|
||||
#
|
||||
name: Next
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 87 7C 00 00
|
||||
command: 06 F9 00 00
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 12 34 00 00
|
||||
command: 01 FE 00 00
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 12 34 00 00
|
||||
command: 0A F5 00 00
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 12 34 00 00
|
||||
command: 0B F4 00 00
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 12 34 00 00
|
||||
command: 09 F6 00 00
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 67 00 00 00
|
||||
#
|
||||
name: Next
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 38 00 00 00
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 3C 00 00 00
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 3D 00 00 00
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 8C 00 00 00
|
||||
#
|
||||
name: Prev
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 44 00 00 00
|
||||
#
|
||||
name: Vol_dn
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 07 00 00 00
|
||||
#
|
||||
name: Vol_up
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 1C 00 00 00
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.33
|
||||
data: 9120 4354 714 1539 660 497 633 499 631 500 630 503 628 503 628 503 629 503 628 503 628 1627 628 1627 628 1627 628 1627 628 1626 628 1627 628 1627 628 1627 628 1627 628 503 628 503 628 503 628 503 628 504 627 503 628 504 627 503 628 1627 628 1628 627 1628 627 1627 628 1627 628 1628 627 40094 9038 2194 628
|
||||
#
|
||||
name: Prev
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 5A 00 00 00
|
||||
#
|
||||
name: Next
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 5B 00 00 00
|
||||
#
|
||||
name: Pause
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: B2 00 00 00
|
||||
#
|
||||
name: Pause
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 EF 00 00
|
||||
command: 11 EE 00 00
|
||||
#
|
||||
name: Pause
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 2C 00 00 00
|
||||
#
|
||||
name: Play
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: B2 00 00 00
|
||||
#
|
||||
name: Play
|
||||
type: parsed
|
||||
protocol: NECext
|
||||
address: 00 EF 00 00
|
||||
command: 11 EE 00 00
|
||||
#
|
||||
name: Play
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 01 00 00 00
|
||||
command: 2C 00 00 00
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
#Last Updated 1st Oct, 2023
|
||||
#Last Checked 1st Oct, 2023
|
||||
#Last Updated 21st Dec, 2023
|
||||
#Last Checked 21st Dec, 2023
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
@@ -2103,3 +2103,39 @@ type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.33
|
||||
data: 1330 376 1303 376 460 1192 1331 376 1302 376 459 1191 463 1217 462 1218 1331 376 459 1195 484 1219 460 7907 1300 379 1300 380 456 1223 1300 380 1300 380 456 1224 456 1224 456 1224 1299 380 456 1224 456 1224 456 8166 1299 380 1299 380 456 1224 1299 380 1299 380 456 1224 456 1224 455 1224 1299 380 456 1224 455 1224 456 7909 1299 380 1299 380 455 1224 1299 380 1299 380 456 1224 455 1225 455 1225 1298 381 455 1225 454 1225 455
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.33
|
||||
data: 9213 4493 613 530 612 529 613 528 614 526 616 1631 615 1631 615 529 613 528 614 1631 615 1631 615 1632 614 1632 614 529 613 528 614 1632 614 1630 616 527 615 1631 615 528 614 1634 611 527 614 527 615 527 615 1630 616 1635 611 528 614 1632 614 527 615 1634 612 1631 615 1632 614 527 615 39730 9215 2228 617 95835 9215 2231 614
|
||||
#
|
||||
name: Speed_up
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 30 00 00 00
|
||||
command: 89 00 00 00
|
||||
#
|
||||
name: Timer
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.33
|
||||
data: 9279 4487 620 526 617 528 614 527 615 527 615 1633 612 1631 614 526 615 527 614 1634 611 1631 614 1633 612 1633 612 529 612 531 610 1633 612 1632 614 528 613 1630 615 1633 613 1632 613 526 615 529 613 527 615 1633 613 1632 614 526 615 526 616 527 615 1632 614 1631 614 1632 614 526 615 39731 9204 2230 614
|
||||
#
|
||||
name: Power
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.33
|
||||
data: 2227 839 757 1597 751 1599 749 829 757 815 750 817 748 814 751 806 749 866 751 836 750 832 754 823 753 819 757 811 754 807 758 799 756 103041 2229 837 749 1605 754 1597 751 826 750 823 753 815 750 812 753 804 751 864 753 834 752 830 756 821 755 818 758 809 756 806 749 808 757 64662 2229 774 749 1558 748 60749 2229 775 748 1559 758
|
||||
#
|
||||
name: Speed_up
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.33
|
||||
data: 2222 843 753 1626 732 1590 758 820 756 817 759 808 757 804 751 806 749 893 724 1603 755 827 748 1595 753 820 756 1578 759 1570 757 827 728 99745 2231 834 752 1601 757 1592 756 821 755 817 759 808 757 805 750 807 758 856 751 1630 728 827 749 1622 726 820 756 1605 732 1570 757 800 755
|
||||
#
|
||||
name: Speed_dn
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.33
|
||||
data: 2221 844 752 1600 758 1591 757 820 756 816 749 817 748 813 752 804 751 1632 758 1596 752 1597 751 1594 754 1585 752 1582 756 806 749 808 757 102464 2224 841 756 1597 751 1599 749 828 748 824 752 815 750 811 754 802 753 1629 750 1604 754 1595 753 1591 757 1583 755 1579 759 804 751 806 749
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 1st Oct, 2023
|
||||
# Last Checked 1st Oct, 2023
|
||||
# Last Checked 21st Dec, 2023
|
||||
#
|
||||
# TEMP FIX FOR POWER
|
||||
#
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 29th Oct, 2023
|
||||
# Last Checked 29th Oct, 2023
|
||||
# Last Updated 21st Dec, 2023
|
||||
# Last Checked 21st Dec, 2023
|
||||
#
|
||||
name: Power
|
||||
type: parsed
|
||||
@@ -2459,3 +2459,9 @@ type: parsed
|
||||
protocol: NEC
|
||||
address: 38 00 00 00
|
||||
command: 1C 00 00 00
|
||||
#
|
||||
name: Mute
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 38 00 00 00
|
||||
command: 04 00 00 00
|
||||
|
||||
@@ -4,9 +4,8 @@ void infrared_scene_edit_delete_done_on_enter(void* context) {
|
||||
InfraredApp* infrared = context;
|
||||
Popup* popup = infrared->popup;
|
||||
|
||||
popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
|
||||
popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom);
|
||||
|
||||
popup_set_icon(popup, 0, 2, &I_DolphinMafia_119x62);
|
||||
popup_set_header(popup, "Deleted", 80, 19, AlignLeft, AlignBottom);
|
||||
popup_set_callback(popup, infrared_popup_closed_callback);
|
||||
popup_set_context(popup, context);
|
||||
popup_set_timeout(popup, 1500);
|
||||
|
||||
@@ -4,9 +4,8 @@ void infrared_scene_edit_rename_done_on_enter(void* context) {
|
||||
InfraredApp* infrared = context;
|
||||
Popup* popup = infrared->popup;
|
||||
|
||||
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
|
||||
popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
|
||||
|
||||
popup_set_icon(popup, 36, 5, &I_DolphinSaved_92x58);
|
||||
popup_set_header(popup, "Saved", 15, 19, AlignLeft, AlignBottom);
|
||||
popup_set_callback(popup, infrared_popup_closed_callback);
|
||||
popup_set_context(popup, context);
|
||||
popup_set_timeout(popup, 1500);
|
||||
|
||||
@@ -4,12 +4,12 @@ void infrared_scene_learn_done_on_enter(void* context) {
|
||||
InfraredApp* infrared = context;
|
||||
Popup* popup = infrared->popup;
|
||||
|
||||
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
|
||||
|
||||
if(infrared->app_state.is_learning_new_remote) {
|
||||
popup_set_icon(popup, 48, 6, &I_DolphinDone_80x58);
|
||||
popup_set_header(popup, "New remote\ncreated!", 0, 0, AlignLeft, AlignTop);
|
||||
} else {
|
||||
popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
|
||||
popup_set_icon(popup, 36, 5, &I_DolphinSaved_92x58);
|
||||
popup_set_header(popup, "Saved", 15, 19, AlignLeft, AlignBottom);
|
||||
}
|
||||
|
||||
popup_set_callback(popup, infrared_popup_closed_callback);
|
||||
|
||||
@@ -54,11 +54,11 @@ static void infrared_progress_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
float progress_value = (float)model->progress / model->progress_total;
|
||||
elements_progress_bar(canvas, x + 4, y + 19, width - 7, progress_value);
|
||||
|
||||
uint8_t percent_value = 100 * model->progress / model->progress_total;
|
||||
char percents_string[10] = {0};
|
||||
snprintf(percents_string, sizeof(percents_string), "%d%%", percent_value);
|
||||
char number_string[10] = {0};
|
||||
snprintf(
|
||||
number_string, sizeof(number_string), "%d/%d", model->progress, model->progress_total);
|
||||
elements_multiline_text_aligned(
|
||||
canvas, x + 33, y + 37, AlignCenter, AlignCenter, percents_string);
|
||||
canvas, x + 33, y + 37, AlignCenter, AlignCenter, number_string);
|
||||
|
||||
canvas_draw_icon(canvas, x + 14, y + height - 14, &I_Pin_back_arrow_10x8);
|
||||
canvas_draw_str(canvas, x + 30, y + height - 6, "= stop");
|
||||
|
||||
@@ -1,6 +1,30 @@
|
||||
#include "lfrfid_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
//TODO: use .txt file in resources for passwords.
|
||||
const uint32_t default_passwords[] = {
|
||||
0x51243648, 0x000D8787, 0x19920427, 0x50524F58, 0xF9DCEBA0, 0x65857569, 0x05D73B9F, 0x89A69E60,
|
||||
0x314159E0, 0xAA55BBBB, 0xA5B4C3D2, 0x1C0B5848, 0x00434343, 0x444E4752, 0x4E457854, 0x44B44CAE,
|
||||
0x88661858, 0xE9920427, 0x575F4F4B, 0x50520901, 0x20206666, 0x65857569, 0x5469616E, 0x7686962A,
|
||||
0xC0F5009A, 0x07CEE75D, 0xfeedbeef, 0xdeadc0de, 0x00000000, 0x11111111, 0x22222222, 0x33333333,
|
||||
0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888, 0x99999999, 0xAAAAAAAA, 0xBBBBBBBB,
|
||||
0xCCCCCCCC, 0xDDDDDDDD, 0xEEEEEEEE, 0xFFFFFFFF, 0xa0a1a2a3, 0xb0b1b2b3, 0x50415353, 0x00000001,
|
||||
0x00000002, 0x0000000a, 0x0000000b, 0x01020304, 0x02030405, 0x03040506, 0x04050607, 0x05060708,
|
||||
0x06070809, 0x0708090A, 0x08090A0B, 0x090A0B0C, 0x0A0B0C0D, 0x0B0C0D0E, 0x0C0D0E0F, 0x01234567,
|
||||
0x12345678, 0x10000000, 0x20000000, 0x30000000, 0x40000000, 0x50000000, 0x60000000, 0x70000000,
|
||||
0x80000000, 0x90000000, 0xA0000000, 0xB0000000, 0xC0000000, 0xD0000000, 0xE0000000, 0xF0000000,
|
||||
0x10101010, 0x01010101, 0x11223344, 0x22334455, 0x33445566, 0x44556677, 0x55667788, 0x66778899,
|
||||
0x778899AA, 0x8899AABB, 0x99AABBCC, 0xAABBCCDD, 0xBBCCDDEE, 0xCCDDEEFF, 0x0CB7E7FC, 0xFABADA11,
|
||||
0x87654321, 0x12341234, 0x69696969, 0x12121212, 0x12344321, 0x1234ABCD, 0x11112222, 0x13131313,
|
||||
0x10041004, 0x31415926, 0xabcd1234, 0x20002000, 0x19721972, 0xaa55aa55, 0x55aa55aa, 0x4f271149,
|
||||
0x07d7bb0b, 0x9636ef8f, 0xb5f44686, 0x9E3779B9, 0xC6EF3720, 0x7854794A, 0xF1EA5EED, 0x69314718,
|
||||
0x57721566, 0x93C467E3, 0x27182818, 0x50415353};
|
||||
|
||||
const uint32_t* lfrfid_get_t5577_default_passwords(uint8_t* len) {
|
||||
*len = sizeof(default_passwords) / sizeof(uint32_t);
|
||||
return default_passwords;
|
||||
}
|
||||
|
||||
static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
LfRfid* app = context;
|
||||
|
||||
@@ -25,11 +25,13 @@ void lfrfid_on_system_start() {
|
||||
|
||||
static void lfrfid_cli_print_usage() {
|
||||
printf("Usage:\r\n");
|
||||
printf("rfid read <optional: normal | indala>\r\n");
|
||||
printf("rfid <write | emulate> <key_type> <key_data>\r\n");
|
||||
printf("rfid raw_read <ask | psk> <filename>\r\n");
|
||||
printf("rfid raw_emulate <filename>\r\n");
|
||||
printf("rfid raw_analyze <filename>\r\n");
|
||||
printf("rfid read <optional: normal | indala> - read in ASK/PSK mode\r\n");
|
||||
printf("rfid <write | emulate> <key_type> <key_data> - write or emulate a card\r\n");
|
||||
printf("rfid raw_read <ask | psk> <filename> - read and save raw data to a file\r\n");
|
||||
printf(
|
||||
"rfid raw_emulate <filename> - emulate raw data (not very useful, but helps debug protocols)\r\n");
|
||||
printf(
|
||||
"rfid raw_analyze <filename> - outputs raw data to the cli and tries to decode it (useful for protocol development)\r\n");
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -66,6 +66,7 @@ enum LfRfidCustomEvent {
|
||||
LfRfidEventWriteTooLongToWrite,
|
||||
LfRfidEventRpcLoadFile,
|
||||
LfRfidEventRpcSessionClose,
|
||||
LfRfidEventEmulationTimeExpired,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
@@ -98,6 +99,8 @@ struct LfRfid {
|
||||
uint8_t* old_key_data;
|
||||
uint8_t* new_key_data;
|
||||
|
||||
uint8_t password[4];
|
||||
|
||||
RpcAppSystem* rpc_ctx;
|
||||
LfRfidRpcState rpc_state;
|
||||
|
||||
@@ -145,3 +148,5 @@ void lfrfid_popup_timeout_callback(void* context);
|
||||
void lfrfid_widget_callback(GuiButtonType result, InputType type, void* context);
|
||||
|
||||
void lfrfid_text_input_callback(void* context);
|
||||
|
||||
const uint32_t* lfrfid_get_t5577_default_passwords(uint8_t* len);
|
||||
@@ -1,30 +1,13 @@
|
||||
#include "../lfrfid_i.h"
|
||||
#include "tools/t5577.h"
|
||||
#define TAG "Clear T5577"
|
||||
|
||||
static void lfrfid_clear_t5577_password_and_config_to_EM(LfRfid* app) {
|
||||
Popup* popup = app->popup;
|
||||
char curr_buf[32] = {};
|
||||
//TODO: use .txt file in resources for passwords.
|
||||
const uint32_t default_passwords[] = {
|
||||
0x51243648, 0x000D8787, 0x19920427, 0x50524F58, 0xF9DCEBA0, 0x65857569, 0x05D73B9F,
|
||||
0x89A69E60, 0x314159E0, 0xAA55BBBB, 0xA5B4C3D2, 0x1C0B5848, 0x00434343, 0x444E4752,
|
||||
0x4E457854, 0x44B44CAE, 0x88661858, 0xE9920427, 0x575F4F4B, 0x50520901, 0x20206666,
|
||||
0x65857569, 0x5469616E, 0x7686962A, 0xC0F5009A, 0x07CEE75D, 0xfeedbeef, 0xdeadc0de,
|
||||
0x00000000, 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, 0x66666666,
|
||||
0x77777777, 0x88888888, 0x99999999, 0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD,
|
||||
0xEEEEEEEE, 0xFFFFFFFF, 0xa0a1a2a3, 0xb0b1b2b3, 0x50415353, 0x00000001, 0x00000002,
|
||||
0x0000000a, 0x0000000b, 0x01020304, 0x02030405, 0x03040506, 0x04050607, 0x05060708,
|
||||
0x06070809, 0x0708090A, 0x08090A0B, 0x090A0B0C, 0x0A0B0C0D, 0x0B0C0D0E, 0x0C0D0E0F,
|
||||
0x01234567, 0x12345678, 0x10000000, 0x20000000, 0x30000000, 0x40000000, 0x50000000,
|
||||
0x60000000, 0x70000000, 0x80000000, 0x90000000, 0xA0000000, 0xB0000000, 0xC0000000,
|
||||
0xD0000000, 0xE0000000, 0xF0000000, 0x10101010, 0x01010101, 0x11223344, 0x22334455,
|
||||
0x33445566, 0x44556677, 0x55667788, 0x66778899, 0x778899AA, 0x8899AABB, 0x99AABBCC,
|
||||
0xAABBCCDD, 0xBBCCDDEE, 0xCCDDEEFF, 0x0CB7E7FC, 0xFABADA11, 0x87654321, 0x12341234,
|
||||
0x69696969, 0x12121212, 0x12344321, 0x1234ABCD, 0x11112222, 0x13131313, 0x10041004,
|
||||
0x31415926, 0xabcd1234, 0x20002000, 0x19721972, 0xaa55aa55, 0x55aa55aa, 0x4f271149,
|
||||
0x07d7bb0b, 0x9636ef8f, 0xb5f44686, 0x9E3779B9, 0xC6EF3720, 0x7854794A, 0xF1EA5EED,
|
||||
0x69314718, 0x57721566, 0x93C467E3, 0x27182818, 0x50415353};
|
||||
const uint8_t default_passwords_len = sizeof(default_passwords) / sizeof(uint32_t);
|
||||
|
||||
uint8_t default_passwords_len;
|
||||
const uint32_t* default_passwords = lfrfid_get_t5577_default_passwords(&default_passwords_len);
|
||||
|
||||
popup_set_header(popup, "Removing\npassword", 90, 36, AlignCenter, AlignCenter);
|
||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
|
||||
@@ -33,14 +16,26 @@ static void lfrfid_clear_t5577_password_and_config_to_EM(LfRfid* app) {
|
||||
|
||||
LFRFIDT5577 data = {
|
||||
.block[0] = 0b00000000000101001000000001000000,
|
||||
.blocks_to_write = 1,
|
||||
.block[7] = 0,
|
||||
.mask = 0b10000001,
|
||||
};
|
||||
|
||||
// Clear custom password
|
||||
uint32_t custom_pass = (app->password[0] << 24) | (app->password[1] << 16) |
|
||||
(app->password[2] << 8) | (app->password[3]);
|
||||
snprintf(curr_buf, sizeof(curr_buf), "Custom password");
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
|
||||
|
||||
t5577_write_with_mask(&data, 0, true, custom_pass);
|
||||
|
||||
furi_delay_ms(8);
|
||||
|
||||
// Clear default passwords
|
||||
for(uint8_t i = 0; i < default_passwords_len; i++) {
|
||||
snprintf(curr_buf, sizeof(curr_buf), "Pass %d of %d", i, default_passwords_len);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
|
||||
|
||||
t5577_write_with_pass(&data, default_passwords[i]);
|
||||
t5577_write_with_mask(&data, 0, true, default_passwords[i]);
|
||||
furi_delay_ms(8);
|
||||
}
|
||||
|
||||
@@ -55,8 +50,8 @@ void lfrfid_scene_clear_t5577_on_enter(void* context) {
|
||||
lfrfid_clear_t5577_password_and_config_to_EM(app);
|
||||
|
||||
notification_message(app->notifications, &sequence_success);
|
||||
popup_set_header(popup, "Done!", 94, 10, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 0, 7, &I_RFIDDolphinSuccess_108x57);
|
||||
popup_set_header(popup, "Success!", 75, 10, AlignLeft, AlignTop);
|
||||
popup_set_icon(popup, 0, 9, &I_DolphinSuccess_91x55);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_callback(popup, lfrfid_popup_timeout_callback);
|
||||
popup_set_timeout(popup, 1500);
|
||||
|
||||
@@ -6,6 +6,7 @@ ADD_SCENE(lfrfid, exit_confirm, ExitConfirm)
|
||||
ADD_SCENE(lfrfid, delete_confirm, DeleteConfirm)
|
||||
ADD_SCENE(lfrfid, read_key_menu, ReadKeyMenu)
|
||||
ADD_SCENE(lfrfid, write, Write)
|
||||
ADD_SCENE(lfrfid, write_and_set_pass, WriteAndSetPass)
|
||||
ADD_SCENE(lfrfid, write_success, WriteSuccess)
|
||||
ADD_SCENE(lfrfid, emulate, Emulate)
|
||||
ADD_SCENE(lfrfid, save_name, SaveName)
|
||||
@@ -17,6 +18,7 @@ ADD_SCENE(lfrfid, save_type, SaveType)
|
||||
ADD_SCENE(lfrfid, saved_info, SavedInfo)
|
||||
ADD_SCENE(lfrfid, clear_t5577, ClearT5577)
|
||||
ADD_SCENE(lfrfid, clear_t5577_confirm, ClearT5577Confirm)
|
||||
ADD_SCENE(lfrfid, enter_password, EnterPassword)
|
||||
ADD_SCENE(lfrfid, delete_success, DeleteSuccess)
|
||||
ADD_SCENE(lfrfid, extra_actions, ExtraActions)
|
||||
ADD_SCENE(lfrfid, raw_info, RawInfo)
|
||||
|
||||
@@ -4,8 +4,8 @@ void lfrfid_scene_delete_success_on_enter(void* context) {
|
||||
LfRfid* app = context;
|
||||
Popup* popup = app->popup;
|
||||
|
||||
popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
|
||||
popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom);
|
||||
popup_set_icon(popup, 0, 2, &I_DolphinMafia_119x62);
|
||||
popup_set_header(popup, "Deleted", 80, 19, AlignLeft, AlignBottom);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_callback(popup, lfrfid_popup_timeout_callback);
|
||||
popup_set_timeout(popup, 1500);
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
#include "../lfrfid_i.h"
|
||||
|
||||
#define LFRFID_EMULATION_TIME_MAX_MS (5 * 60 * 1000)
|
||||
|
||||
FuriTimer* timer_auto_exit;
|
||||
|
||||
void lfrfid_scene_emulate_popup_callback(void* context) {
|
||||
LfRfid* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventEmulationTimeExpired);
|
||||
}
|
||||
|
||||
void lfrfid_scene_emulate_on_enter(void* context) {
|
||||
LfRfid* app = context;
|
||||
Popup* popup = app->popup;
|
||||
@@ -22,18 +31,40 @@ void lfrfid_scene_emulate_on_enter(void* context) {
|
||||
lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id);
|
||||
notification_message(app->notifications, &sequence_blink_start_magenta);
|
||||
|
||||
timer_auto_exit =
|
||||
furi_timer_alloc(lfrfid_scene_emulate_popup_callback, FuriTimerTypeOnce, app);
|
||||
|
||||
if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug))
|
||||
furi_timer_start(timer_auto_exit, LFRFID_EMULATION_TIME_MAX_MS);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
|
||||
}
|
||||
|
||||
bool lfrfid_scene_emulate_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
LfRfid* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == LfRfidEventEmulationTimeExpired) {
|
||||
if(!scene_manager_previous_scene(app->scene_manager)) {
|
||||
scene_manager_stop(app->scene_manager);
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
} else {
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void lfrfid_scene_emulate_on_exit(void* context) {
|
||||
LfRfid* app = context;
|
||||
|
||||
furi_timer_stop(timer_auto_exit);
|
||||
furi_timer_free(timer_auto_exit);
|
||||
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
popup_reset(app->popup);
|
||||
lfrfid_worker_stop(app->lfworker);
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#include "../lfrfid_i.h"
|
||||
#include "gui/scene_manager.h"
|
||||
|
||||
int next_scene;
|
||||
|
||||
void lfrfid_scene_enter_password_on_enter(void* context) {
|
||||
LfRfid* app = context;
|
||||
ByteInput* byte_input = app->byte_input;
|
||||
|
||||
next_scene = scene_manager_get_scene_state(app->scene_manager, LfRfidSceneEnterPassword);
|
||||
|
||||
bool password_set = app->password[0] | app->password[1] | app->password[2] | app->password[3];
|
||||
|
||||
if(next_scene == LfRfidSceneWriteAndSetPass && !password_set) {
|
||||
uint8_t password_list_size;
|
||||
const uint32_t* password_list = lfrfid_get_t5577_default_passwords(&password_list_size);
|
||||
uint32_t pass = password_list[furi_get_tick() % password_list_size];
|
||||
|
||||
for(uint8_t i = 0; i < 4; i++) app->password[4 - (i + 1)] = (pass >> (8 * i)) & 0xFF;
|
||||
}
|
||||
|
||||
byte_input_set_header_text(byte_input, "Enter the password in hex");
|
||||
|
||||
byte_input_set_result_callback(
|
||||
byte_input, lfrfid_text_input_callback, NULL, app, app->password, 4);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewByteInput);
|
||||
}
|
||||
|
||||
bool lfrfid_scene_enter_password_on_event(void* context, SceneManagerEvent event) {
|
||||
LfRfid* app = context;
|
||||
SceneManager* scene_manager = app->scene_manager;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == LfRfidEventNext) {
|
||||
consumed = true;
|
||||
|
||||
scene_manager_next_scene(scene_manager, next_scene);
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
uint32_t prev_scenes[] = {LfRfidSceneExtraActions, LfRfidSceneSavedKeyMenu};
|
||||
scene_manager_search_and_switch_to_previous_scene_one_of(
|
||||
scene_manager, prev_scenes, sizeof(prev_scenes[0]));
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void lfrfid_scene_enter_password_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -80,7 +80,9 @@ bool lfrfid_scene_extra_actions_on_event(void* context, SceneManagerEvent event)
|
||||
dolphin_deed(DolphinDeedRfidRead);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexClearT5577) {
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneClearT5577Confirm);
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, LfRfidSceneEnterPassword, LfRfidSceneClearT5577Confirm);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneEnterPassword);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexRAW) {
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneRawName);
|
||||
|
||||
@@ -7,8 +7,8 @@ void lfrfid_scene_save_success_on_enter(void* context) {
|
||||
// Clear state of data enter scene
|
||||
scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveData, 0);
|
||||
|
||||
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
|
||||
popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
|
||||
popup_set_icon(popup, 36, 5, &I_DolphinSaved_92x58);
|
||||
popup_set_header(popup, "Saved", 15, 19, AlignLeft, AlignBottom);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_callback(popup, lfrfid_popup_timeout_callback);
|
||||
popup_set_timeout(popup, 1500);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
typedef enum {
|
||||
SubmenuIndexEmulate,
|
||||
SubmenuIndexWrite,
|
||||
SubmenuIndexWriteAndSetPass,
|
||||
SubmenuIndexEdit,
|
||||
SubmenuIndexDelete,
|
||||
SubmenuIndexInfo,
|
||||
@@ -23,6 +24,12 @@ void lfrfid_scene_saved_key_menu_on_enter(void* context) {
|
||||
submenu, "Emulate", SubmenuIndexEmulate, lfrfid_scene_saved_key_menu_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
submenu, "Write", SubmenuIndexWrite, lfrfid_scene_saved_key_menu_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Write and set password",
|
||||
SubmenuIndexWriteAndSetPass,
|
||||
lfrfid_scene_saved_key_menu_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu, "Edit", SubmenuIndexEdit, lfrfid_scene_saved_key_menu_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
@@ -48,6 +55,11 @@ bool lfrfid_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event
|
||||
} else if(event.event == SubmenuIndexWrite) {
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexWriteAndSetPass) {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, LfRfidSceneEnterPassword, LfRfidSceneWriteAndSetPass);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneEnterPassword);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexEdit) {
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveData);
|
||||
consumed = true;
|
||||
|
||||
@@ -57,7 +57,7 @@ bool lfrfid_scene_write_on_event(void* context, SceneManagerEvent event) {
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneWriteSuccess);
|
||||
consumed = true;
|
||||
} else if(event.event == LfRfidEventWriteProtocolCannotBeWritten) {
|
||||
popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48);
|
||||
popup_set_icon(popup, 83, 22, &I_WarningDolphinFlip_45x42);
|
||||
popup_set_header(popup, "Error", 64, 3, AlignCenter, AlignTop);
|
||||
popup_set_text(popup, "This protocol\ncannot be written", 3, 17, AlignLeft, AlignTop);
|
||||
notification_message(app->notifications, &sequence_blink_start_red);
|
||||
@@ -65,7 +65,7 @@ bool lfrfid_scene_write_on_event(void* context, SceneManagerEvent event) {
|
||||
} else if(
|
||||
(event.event == LfRfidEventWriteFobCannotBeWritten) ||
|
||||
(event.event == LfRfidEventWriteTooLongToWrite)) {
|
||||
popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48);
|
||||
popup_set_icon(popup, 83, 22, &I_WarningDolphinFlip_45x42);
|
||||
popup_set_header(popup, "Still trying to write...", 64, 3, AlignCenter, AlignTop);
|
||||
popup_set_text(
|
||||
popup,
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#include "../lfrfid_i.h"
|
||||
#include "gui/scene_manager.h"
|
||||
|
||||
static void lfrfid_write_and_set_pass_callback(LFRFIDWorkerWriteResult result, void* context) {
|
||||
LfRfid* app = context;
|
||||
uint32_t event = 0;
|
||||
|
||||
if(result == LFRFIDWorkerWriteOK) {
|
||||
event = LfRfidEventWriteOK;
|
||||
} else if(result == LFRFIDWorkerWriteProtocolCannotBeWritten) {
|
||||
event = LfRfidEventWriteProtocolCannotBeWritten;
|
||||
} else if(result == LFRFIDWorkerWriteFobCannotBeWritten) {
|
||||
event = LfRfidEventWriteFobCannotBeWritten;
|
||||
} else if(result == LFRFIDWorkerWriteTooLongToWrite) {
|
||||
event = LfRfidEventWriteTooLongToWrite;
|
||||
}
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void lfrfid_scene_write_and_set_pass_on_enter(void* context) {
|
||||
LfRfid* app = context;
|
||||
Popup* popup = app->popup;
|
||||
|
||||
popup_set_header(popup, "Writing\nwith password", 89, 30, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
|
||||
|
||||
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
|
||||
protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size);
|
||||
|
||||
lfrfid_worker_start_thread(app->lfworker);
|
||||
lfrfid_worker_write_and_set_pass_start(
|
||||
app->lfworker, (LFRFIDProtocol)app->protocol_id, lfrfid_write_and_set_pass_callback, app);
|
||||
notification_message(app->notifications, &sequence_blink_start_magenta);
|
||||
}
|
||||
|
||||
bool lfrfid_scene_write_and_set_pass_on_event(void* context, SceneManagerEvent event) {
|
||||
LfRfid* app = context;
|
||||
Popup* popup = app->popup;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == LfRfidEventWriteOK) {
|
||||
notification_message(app->notifications, &sequence_success);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneWriteSuccess);
|
||||
consumed = true;
|
||||
} else if(event.event == LfRfidEventWriteProtocolCannotBeWritten) {
|
||||
popup_set_icon(popup, 83, 22, &I_WarningDolphinFlip_45x42);
|
||||
popup_set_header(popup, "Error", 64, 3, AlignCenter, AlignTop);
|
||||
popup_set_text(popup, "This protocol\ncannot be written", 3, 17, AlignLeft, AlignTop);
|
||||
notification_message(app->notifications, &sequence_blink_start_red);
|
||||
consumed = true;
|
||||
} else if(
|
||||
(event.event == LfRfidEventWriteFobCannotBeWritten) ||
|
||||
(event.event == LfRfidEventWriteTooLongToWrite)) {
|
||||
popup_set_icon(popup, 83, 22, &I_WarningDolphinFlip_45x42);
|
||||
popup_set_header(popup, "Still trying to write...", 64, 3, AlignCenter, AlignTop);
|
||||
popup_set_text(
|
||||
popup,
|
||||
"Make sure this\ncard is writable\nand not\nprotected.",
|
||||
3,
|
||||
17,
|
||||
AlignLeft,
|
||||
AlignTop);
|
||||
notification_message(app->notifications, &sequence_blink_start_yellow);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void lfrfid_scene_write_and_set_pass_on_exit(void* context) {
|
||||
LfRfid* app = context;
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
popup_reset(app->popup);
|
||||
lfrfid_worker_stop(app->lfworker);
|
||||
lfrfid_worker_stop_thread(app->lfworker);
|
||||
|
||||
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
|
||||
protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size);
|
||||
}
|
||||
@@ -4,8 +4,8 @@ void lfrfid_scene_write_success_on_enter(void* context) {
|
||||
LfRfid* app = context;
|
||||
Popup* popup = app->popup;
|
||||
|
||||
popup_set_header(popup, "Successfully\nwritten!", 94, 3, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57);
|
||||
popup_set_header(popup, "Success!", 75, 10, AlignLeft, AlignTop);
|
||||
popup_set_icon(popup, 0, 9, &I_DolphinSuccess_91x55);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_callback(popup, lfrfid_popup_timeout_callback);
|
||||
popup_set_timeout(popup, 1500);
|
||||
|
||||
@@ -13,7 +13,7 @@ App(
|
||||
"!plugins",
|
||||
"!nfc_cli.c",
|
||||
],
|
||||
fap_libs=["assets"],
|
||||
fap_libs=["assets", "mbedtls"],
|
||||
fap_icon="icon.png",
|
||||
fap_category="NFC",
|
||||
)
|
||||
@@ -56,6 +56,15 @@ App(
|
||||
sources=["plugins/supported_cards/troika.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="social_moscow_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="social_moscow_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/social_moscow.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="plantain_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
@@ -74,6 +83,114 @@ App(
|
||||
sources=["plugins/supported_cards/two_cities.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="umarsh_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="umarsh_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/umarsh.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="metromoney_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="metromoney_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/metromoney.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="kazan_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="kazan_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/kazan.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="aime_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="aime_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/aime.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="saflok_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="saflok_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/saflok.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="mykey_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="mykey_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/mykey.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="zolotaya_korona_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="zolotaya_korona_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/zolotaya_korona.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="zolotaya_korona_online_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="zolotaya_korona_online_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/zolotaya_korona_online.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="hid_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="hid_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/hid.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="washcity_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="washcity_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/washcity.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="emv_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="emv_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc", "storage"],
|
||||
sources=["plugins/supported_cards/emv.c", "helpers/nfc_emv_parser.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="ndef_parser",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="ndef_plugin_ep",
|
||||
targets=["f7"],
|
||||
requires=["nfc"],
|
||||
sources=["plugins/supported_cards/ndef.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="nfc_start",
|
||||
targets=["f7"],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "mf_user_dict.h"
|
||||
|
||||
#include <nfc/helpers/nfc_dict.h>
|
||||
#include <toolbox/keys_dict.h>
|
||||
#include <nfc/protocols/mf_classic/mf_classic.h>
|
||||
#include <furi/furi.h>
|
||||
|
||||
@@ -15,22 +15,22 @@ struct MfUserDict {
|
||||
MfUserDict* mf_user_dict_alloc(size_t max_keys_to_load) {
|
||||
MfUserDict* instance = malloc(sizeof(MfUserDict));
|
||||
|
||||
NfcDict* dict = nfc_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
KeysDict* dict = keys_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
furi_assert(dict);
|
||||
|
||||
size_t dict_keys_num = nfc_dict_get_total_keys(dict);
|
||||
size_t dict_keys_num = keys_dict_get_total_keys(dict);
|
||||
instance->keys_num = MIN(max_keys_to_load, dict_keys_num);
|
||||
|
||||
if(instance->keys_num > 0) {
|
||||
instance->keys_arr = malloc(instance->keys_num * sizeof(MfClassicKey));
|
||||
for(size_t i = 0; i < instance->keys_num; i++) {
|
||||
bool key_loaded =
|
||||
nfc_dict_get_next_key(dict, instance->keys_arr[i].data, sizeof(MfClassicKey));
|
||||
keys_dict_get_next_key(dict, instance->keys_arr[i].data, sizeof(MfClassicKey));
|
||||
furi_assert(key_loaded);
|
||||
}
|
||||
}
|
||||
nfc_dict_free(dict);
|
||||
keys_dict_free(dict);
|
||||
|
||||
return instance;
|
||||
}
|
||||
@@ -67,13 +67,13 @@ bool mf_user_dict_delete_key(MfUserDict* instance, uint32_t index) {
|
||||
furi_assert(index < instance->keys_num);
|
||||
furi_assert(instance->keys_arr);
|
||||
|
||||
NfcDict* dict = nfc_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
KeysDict* dict = keys_dict_alloc(
|
||||
NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
|
||||
furi_assert(dict);
|
||||
|
||||
bool key_delete_success =
|
||||
nfc_dict_delete_key(dict, instance->keys_arr[index].data, sizeof(MfClassicKey));
|
||||
nfc_dict_free(dict);
|
||||
keys_dict_delete_key(dict, instance->keys_arr[index].data, sizeof(MfClassicKey));
|
||||
keys_dict_free(dict);
|
||||
|
||||
if(key_delete_success) {
|
||||
instance->keys_num--;
|
||||
|
||||
@@ -30,4 +30,6 @@ typedef enum {
|
||||
NfcCustomEventPollerFailure,
|
||||
|
||||
NfcCustomEventListenerUpdate,
|
||||
|
||||
NfcCustomEventEmulationTimeExpired,
|
||||
} NfcCustomEvent;
|
||||
|
||||
@@ -34,7 +34,7 @@ static bool nfc_emv_parser_search_data(
|
||||
|
||||
bool nfc_emv_parser_get_aid_name(
|
||||
Storage* storage,
|
||||
uint8_t* aid,
|
||||
const uint8_t* aid,
|
||||
uint8_t aid_len,
|
||||
FuriString* aid_name) {
|
||||
furi_assert(storage);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
*/
|
||||
bool nfc_emv_parser_get_aid_name(
|
||||
Storage* storage,
|
||||
uint8_t* aid,
|
||||
const uint8_t* aid,
|
||||
uint8_t aid_len,
|
||||
FuriString* aid_name);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "nfc_supported_cards.h"
|
||||
|
||||
#include "../plugins/supported_cards/nfc_supported_card_plugin.h"
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
@@ -7,22 +8,72 @@
|
||||
|
||||
#include <furi.h>
|
||||
#include <path.h>
|
||||
#include <m-array.h>
|
||||
|
||||
#define TAG "NfcSupportedCards"
|
||||
|
||||
#define NFC_SUPPORTED_CARDS_PLUGINS_PATH APP_DATA_PATH("plugins")
|
||||
#define NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX "_parser.fal"
|
||||
|
||||
typedef enum {
|
||||
NfcSupportedCardsPluginFeatureHasVerify = (1U << 0),
|
||||
NfcSupportedCardsPluginFeatureHasRead = (1U << 1),
|
||||
NfcSupportedCardsPluginFeatureHasParse = (1U << 2),
|
||||
} NfcSupportedCardsPluginFeature;
|
||||
|
||||
typedef struct {
|
||||
FuriString* path;
|
||||
NfcProtocol protocol;
|
||||
NfcSupportedCardsPluginFeature feature;
|
||||
} NfcSupportedCardsPluginCache;
|
||||
|
||||
ARRAY_DEF(NfcSupportedCardsPluginCache, NfcSupportedCardsPluginCache, M_POD_OPLIST);
|
||||
|
||||
typedef enum {
|
||||
NfcSupportedCardsLoadStateIdle,
|
||||
NfcSupportedCardsLoadStateInProgress,
|
||||
NfcSupportedCardsLoadStateSuccess,
|
||||
NfcSupportedCardsLoadStateFail,
|
||||
} NfcSupportedCardsLoadState;
|
||||
|
||||
typedef struct {
|
||||
Storage* storage;
|
||||
File* directory;
|
||||
FuriString* file_path;
|
||||
char file_name[256];
|
||||
FlipperApplication* app;
|
||||
} NfcSupportedCards;
|
||||
} NfcSupportedCardsLoadContext;
|
||||
|
||||
static NfcSupportedCards* nfc_supported_cards_alloc() {
|
||||
struct NfcSupportedCards {
|
||||
NfcSupportedCardsPluginCache_t plugins_cache_arr;
|
||||
NfcSupportedCardsLoadState load_state;
|
||||
NfcSupportedCardsLoadContext* load_context;
|
||||
};
|
||||
|
||||
NfcSupportedCards* nfc_supported_cards_alloc() {
|
||||
NfcSupportedCards* instance = malloc(sizeof(NfcSupportedCards));
|
||||
NfcSupportedCardsPluginCache_init(instance->plugins_cache_arr);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void nfc_supported_cards_free(NfcSupportedCards* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
NfcSupportedCardsPluginCache_it_t iter;
|
||||
for(NfcSupportedCardsPluginCache_it(iter, instance->plugins_cache_arr);
|
||||
!NfcSupportedCardsPluginCache_end_p(iter);
|
||||
NfcSupportedCardsPluginCache_next(iter)) {
|
||||
NfcSupportedCardsPluginCache* plugin_cache = NfcSupportedCardsPluginCache_ref(iter);
|
||||
furi_string_free(plugin_cache->path);
|
||||
}
|
||||
|
||||
NfcSupportedCardsPluginCache_clear(instance->plugins_cache_arr);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
static NfcSupportedCardsLoadContext* nfc_supported_cards_load_context_alloc() {
|
||||
NfcSupportedCardsLoadContext* instance = malloc(sizeof(NfcSupportedCardsLoadContext));
|
||||
|
||||
instance->storage = furi_record_open(RECORD_STORAGE);
|
||||
instance->directory = storage_file_alloc(instance->storage);
|
||||
@@ -35,7 +86,7 @@ static NfcSupportedCards* nfc_supported_cards_alloc() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void nfc_supported_cards_free(NfcSupportedCards* instance) {
|
||||
static void nfc_supported_cards_load_context_free(NfcSupportedCardsLoadContext* instance) {
|
||||
if(instance->app) {
|
||||
flipper_application_free(instance->app);
|
||||
}
|
||||
@@ -50,7 +101,36 @@ static void nfc_supported_cards_free(NfcSupportedCards* instance) {
|
||||
}
|
||||
|
||||
static const NfcSupportedCardsPlugin*
|
||||
nfc_supported_cards_get_next_plugin(NfcSupportedCards* instance) {
|
||||
nfc_supported_cards_get_plugin(NfcSupportedCardsLoadContext* instance, FuriString* path) {
|
||||
furi_assert(instance);
|
||||
furi_assert(path);
|
||||
|
||||
const NfcSupportedCardsPlugin* plugin = NULL;
|
||||
do {
|
||||
if(instance->app) flipper_application_free(instance->app);
|
||||
instance->app = flipper_application_alloc(instance->storage, firmware_api_interface);
|
||||
if(flipper_application_preload(instance->app, furi_string_get_cstr(path)) !=
|
||||
FlipperApplicationPreloadStatusSuccess)
|
||||
break;
|
||||
if(!flipper_application_is_plugin(instance->app)) break;
|
||||
if(flipper_application_map_to_memory(instance->app) != FlipperApplicationLoadStatusSuccess)
|
||||
break;
|
||||
const FlipperAppPluginDescriptor* descriptor =
|
||||
flipper_application_plugin_get_descriptor(instance->app);
|
||||
|
||||
if(descriptor == NULL) break;
|
||||
|
||||
if(strcmp(descriptor->appid, NFC_SUPPORTED_CARD_PLUGIN_APP_ID) != 0) break;
|
||||
if(descriptor->ep_api_version != NFC_SUPPORTED_CARD_PLUGIN_API_VERSION) break;
|
||||
|
||||
plugin = descriptor->entry_point;
|
||||
} while(false);
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
static const NfcSupportedCardsPlugin*
|
||||
nfc_supported_cards_get_next_plugin(NfcSupportedCardsLoadContext* instance) {
|
||||
const NfcSupportedCardsPlugin* plugin = NULL;
|
||||
|
||||
do {
|
||||
@@ -65,83 +145,137 @@ static const NfcSupportedCardsPlugin*
|
||||
|
||||
path_concat(NFC_SUPPORTED_CARDS_PLUGINS_PATH, instance->file_name, instance->file_path);
|
||||
|
||||
if(instance->app) flipper_application_free(instance->app);
|
||||
instance->app = flipper_application_alloc(instance->storage, firmware_api_interface);
|
||||
|
||||
if(flipper_application_preload(instance->app, furi_string_get_cstr(instance->file_path)) !=
|
||||
FlipperApplicationPreloadStatusSuccess)
|
||||
continue;
|
||||
if(!flipper_application_is_plugin(instance->app)) continue;
|
||||
|
||||
if(flipper_application_map_to_memory(instance->app) != FlipperApplicationLoadStatusSuccess)
|
||||
continue;
|
||||
|
||||
const FlipperAppPluginDescriptor* descriptor =
|
||||
flipper_application_plugin_get_descriptor(instance->app);
|
||||
|
||||
if(descriptor == NULL) continue;
|
||||
|
||||
if(strcmp(descriptor->appid, NFC_SUPPORTED_CARD_PLUGIN_APP_ID) != 0) continue;
|
||||
if(descriptor->ep_api_version != NFC_SUPPORTED_CARD_PLUGIN_API_VERSION) continue;
|
||||
|
||||
plugin = descriptor->entry_point;
|
||||
plugin = nfc_supported_cards_get_plugin(instance, instance->file_path);
|
||||
} while(plugin == NULL); //-V654
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc) {
|
||||
void nfc_supported_cards_load_cache(NfcSupportedCards* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
do {
|
||||
if((instance->load_state == NfcSupportedCardsLoadStateSuccess) ||
|
||||
(instance->load_state == NfcSupportedCardsLoadStateFail))
|
||||
break;
|
||||
|
||||
instance->load_context = nfc_supported_cards_load_context_alloc();
|
||||
|
||||
while(true) {
|
||||
const NfcSupportedCardsPlugin* plugin =
|
||||
nfc_supported_cards_get_next_plugin(instance->load_context);
|
||||
if(plugin == NULL) break; //-V547
|
||||
|
||||
NfcSupportedCardsPluginCache plugin_cache = {}; //-V779
|
||||
plugin_cache.path = furi_string_alloc_set(instance->load_context->file_path);
|
||||
plugin_cache.protocol = plugin->protocol;
|
||||
if(plugin->verify) {
|
||||
plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasVerify;
|
||||
}
|
||||
if(plugin->read) {
|
||||
plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasRead;
|
||||
}
|
||||
if(plugin->parse) {
|
||||
plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasParse;
|
||||
}
|
||||
NfcSupportedCardsPluginCache_push_back(instance->plugins_cache_arr, plugin_cache);
|
||||
}
|
||||
|
||||
nfc_supported_cards_load_context_free(instance->load_context);
|
||||
|
||||
size_t plugins_loaded = NfcSupportedCardsPluginCache_size(instance->plugins_cache_arr);
|
||||
if(plugins_loaded == 0) {
|
||||
FURI_LOG_D(TAG, "Plugins not found");
|
||||
instance->load_state = NfcSupportedCardsLoadStateFail;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Loaded %zu plugins", plugins_loaded);
|
||||
instance->load_state = NfcSupportedCardsLoadStateSuccess;
|
||||
}
|
||||
|
||||
} while(false);
|
||||
}
|
||||
|
||||
bool nfc_supported_cards_read(NfcSupportedCards* instance, NfcDevice* device, Nfc* nfc) {
|
||||
furi_assert(instance);
|
||||
furi_assert(device);
|
||||
furi_assert(nfc);
|
||||
|
||||
bool card_read = false;
|
||||
|
||||
NfcSupportedCards* supported_cards = nfc_supported_cards_alloc();
|
||||
NfcProtocol protocol = nfc_device_get_protocol(device);
|
||||
|
||||
do {
|
||||
const NfcSupportedCardsPlugin* plugin =
|
||||
nfc_supported_cards_get_next_plugin(supported_cards);
|
||||
if(plugin == NULL) break; //-V547
|
||||
if(instance->load_state != NfcSupportedCardsLoadStateSuccess) break;
|
||||
|
||||
const NfcProtocol protocol = nfc_device_get_protocol(device); //-V779
|
||||
if(plugin->protocol != protocol) continue;
|
||||
instance->load_context = nfc_supported_cards_load_context_alloc();
|
||||
|
||||
if(plugin->verify) {
|
||||
if(!plugin->verify(nfc)) continue;
|
||||
NfcSupportedCardsPluginCache_it_t iter;
|
||||
for(NfcSupportedCardsPluginCache_it(iter, instance->plugins_cache_arr);
|
||||
!NfcSupportedCardsPluginCache_end_p(iter);
|
||||
NfcSupportedCardsPluginCache_next(iter)) {
|
||||
NfcSupportedCardsPluginCache* plugin_cache = NfcSupportedCardsPluginCache_ref(iter);
|
||||
if(plugin_cache->protocol != protocol) continue;
|
||||
if((plugin_cache->feature & NfcSupportedCardsPluginFeatureHasRead) == 0) continue;
|
||||
|
||||
const NfcSupportedCardsPlugin* plugin =
|
||||
nfc_supported_cards_get_plugin(instance->load_context, plugin_cache->path);
|
||||
if(plugin == NULL) continue;
|
||||
|
||||
if(plugin->verify) {
|
||||
if(!plugin->verify(nfc)) continue;
|
||||
}
|
||||
|
||||
if(plugin->read) {
|
||||
if(plugin->read(nfc, device)) {
|
||||
card_read = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(plugin->read) {
|
||||
card_read = plugin->read(nfc, device);
|
||||
}
|
||||
nfc_supported_cards_load_context_free(instance->load_context);
|
||||
} while(false);
|
||||
|
||||
} while(!card_read);
|
||||
|
||||
nfc_supported_cards_free(supported_cards);
|
||||
return card_read;
|
||||
}
|
||||
|
||||
bool nfc_supported_cards_parse(const NfcDevice* device, FuriString* parsed_data) {
|
||||
bool nfc_supported_cards_parse(
|
||||
NfcSupportedCards* instance,
|
||||
NfcDevice* device,
|
||||
FuriString* parsed_data) {
|
||||
furi_assert(instance);
|
||||
furi_assert(device);
|
||||
furi_assert(parsed_data);
|
||||
|
||||
bool parsed = false;
|
||||
|
||||
NfcSupportedCards* supported_cards = nfc_supported_cards_alloc();
|
||||
bool card_parsed = false;
|
||||
NfcProtocol protocol = nfc_device_get_protocol(device);
|
||||
|
||||
do {
|
||||
const NfcSupportedCardsPlugin* plugin =
|
||||
nfc_supported_cards_get_next_plugin(supported_cards);
|
||||
if(plugin == NULL) break; //-V547
|
||||
if(instance->load_state != NfcSupportedCardsLoadStateSuccess) break;
|
||||
|
||||
const NfcProtocol protocol = nfc_device_get_protocol(device); //-V779
|
||||
if(plugin->protocol != protocol) continue;
|
||||
instance->load_context = nfc_supported_cards_load_context_alloc();
|
||||
|
||||
if(plugin->parse) {
|
||||
parsed = plugin->parse(device, parsed_data);
|
||||
NfcSupportedCardsPluginCache_it_t iter;
|
||||
for(NfcSupportedCardsPluginCache_it(iter, instance->plugins_cache_arr);
|
||||
!NfcSupportedCardsPluginCache_end_p(iter);
|
||||
NfcSupportedCardsPluginCache_next(iter)) {
|
||||
NfcSupportedCardsPluginCache* plugin_cache = NfcSupportedCardsPluginCache_ref(iter);
|
||||
if(plugin_cache->protocol != protocol) continue;
|
||||
if((plugin_cache->feature & NfcSupportedCardsPluginFeatureHasParse) == 0) continue;
|
||||
|
||||
const NfcSupportedCardsPlugin* plugin =
|
||||
nfc_supported_cards_get_plugin(instance->load_context, plugin_cache->path);
|
||||
if(plugin == NULL) continue;
|
||||
|
||||
if(plugin->parse) {
|
||||
if(plugin->parse(device, parsed_data)) {
|
||||
card_parsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while(!parsed);
|
||||
nfc_supported_cards_load_context_free(instance->load_context);
|
||||
} while(false);
|
||||
|
||||
nfc_supported_cards_free(supported_cards);
|
||||
return parsed;
|
||||
return card_parsed;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,34 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief NfcSupportedCards opaque type definition.
|
||||
*/
|
||||
typedef struct NfcSupportedCards NfcSupportedCards;
|
||||
|
||||
/**
|
||||
* @brief Allocate NfcSupportedCards instance.
|
||||
*
|
||||
* @return pointer to allocated NfcSupportedCards instance.
|
||||
*/
|
||||
NfcSupportedCards* nfc_supported_cards_alloc();
|
||||
|
||||
/**
|
||||
* @brief Delete an NfcSupportedCards instance
|
||||
*
|
||||
* @param[in] instance pointer to instance to be deleted.
|
||||
*/
|
||||
void nfc_supported_cards_free(NfcSupportedCards* instance);
|
||||
|
||||
/**
|
||||
* @brief Load plugins information to cache.
|
||||
*
|
||||
* @note This function must be called before calling read and parse fanctions.
|
||||
*
|
||||
* @param[in, out] instance pointer to NfcSupportedCards instance.
|
||||
*/
|
||||
void nfc_supported_cards_load_cache(NfcSupportedCards* instance);
|
||||
|
||||
/**
|
||||
* @brief Read the card using a custom procedure.
|
||||
*
|
||||
@@ -22,13 +50,14 @@ extern "C" {
|
||||
* try to execute the custom read procedure specified in each. Upon first success,
|
||||
* no further attempts will be made and the function will return.
|
||||
*
|
||||
* @param[in, out] instance pointer to NfcSupportedCards instance.
|
||||
* @param[in,out] device pointer to a device instance to hold the read data.
|
||||
* @param[in,out] nfc pointer to an Nfc instance.
|
||||
* @returns true if the card was successfully read, false otherwise.
|
||||
*
|
||||
* @see NfcSupportedCardPluginRead for detailed description.
|
||||
*/
|
||||
bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc);
|
||||
bool nfc_supported_cards_read(NfcSupportedCards* instance, NfcDevice* device, Nfc* nfc);
|
||||
|
||||
/**
|
||||
* @brief Parse raw data into human-readable representation.
|
||||
@@ -37,13 +66,17 @@ bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc);
|
||||
* try to parse the data according to each implementation. Upon first success,
|
||||
* no further attempts will be made and the function will return.
|
||||
*
|
||||
* @param[in, out] instance pointer to NfcSupportedCards instance.
|
||||
* @param[in] device pointer to a device instance holding the data is to be parsed.
|
||||
* @param[out] parsed_data pointer to the string to contain the formatted result.
|
||||
* @returns true if the card was successfully parsed, false otherwise.
|
||||
*
|
||||
* @see NfcSupportedCardPluginParse for detailed description.
|
||||
*/
|
||||
bool nfc_supported_cards_parse(const NfcDevice* device, FuriString* parsed_data);
|
||||
bool nfc_supported_cards_parse(
|
||||
NfcSupportedCards* instance,
|
||||
NfcDevice* device,
|
||||
FuriString* parsed_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
115
applications/main/nfc/helpers/protocol_support/emv/emv.c
Normal file
115
applications/main/nfc/helpers/protocol_support/emv/emv.c
Normal file
@@ -0,0 +1,115 @@
|
||||
#include "emv.h"
|
||||
#include "emv_render.h"
|
||||
|
||||
#include <nfc/protocols/emv/emv_poller.h>
|
||||
|
||||
#include "nfc/nfc_app_i.h"
|
||||
|
||||
#include "../nfc_protocol_support_common.h"
|
||||
#include "../nfc_protocol_support_gui_common.h"
|
||||
#include "../iso14443_4a/iso14443_4a_i.h"
|
||||
|
||||
static void nfc_scene_info_on_enter_emv(NfcApp* instance) {
|
||||
const NfcDevice* device = instance->nfc_device;
|
||||
const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv);
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
// furi_string_cat_printf(
|
||||
// temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
|
||||
nfc_render_emv_info(data, NfcProtocolFormatTypeFull, temp_str);
|
||||
|
||||
widget_add_text_scroll_element(
|
||||
instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));
|
||||
|
||||
furi_string_free(temp_str);
|
||||
}
|
||||
|
||||
static void nfc_scene_more_info_on_enter_emv(NfcApp* instance) {
|
||||
// Jump to advanced scene right away
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneEmvMoreInfo);
|
||||
}
|
||||
|
||||
static NfcCommand nfc_scene_read_poller_callback_emv(NfcGenericEvent event, void* context) {
|
||||
furi_assert(event.protocol == NfcProtocolEmv);
|
||||
|
||||
NfcApp* instance = context;
|
||||
const EmvPollerEvent* emv_event = event.event_data;
|
||||
|
||||
if(emv_event->type == EmvPollerEventTypeReadSuccess) {
|
||||
nfc_device_set_data(
|
||||
instance->nfc_device, NfcProtocolEmv, nfc_poller_get_data(instance->poller));
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess);
|
||||
return NfcCommandStop;
|
||||
}
|
||||
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
static void nfc_scene_read_on_enter_emv(NfcApp* instance) {
|
||||
nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_emv, instance);
|
||||
}
|
||||
|
||||
static void nfc_scene_read_success_on_enter_emv(NfcApp* instance) {
|
||||
const NfcDevice* device = instance->nfc_device;
|
||||
const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv);
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
// furi_string_cat_printf(
|
||||
// temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
|
||||
nfc_render_emv_info(data, NfcProtocolFormatTypeShort, temp_str);
|
||||
|
||||
widget_add_text_scroll_element(
|
||||
instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));
|
||||
|
||||
furi_string_free(temp_str);
|
||||
}
|
||||
|
||||
// static void nfc_scene_emulate_on_enter_emv(NfcApp* instance) {
|
||||
// const Iso14443_4aData* iso14443_4a_data =
|
||||
// nfc_device_get_data(instance->nfc_device, NfcProtocolIso14443_4a);
|
||||
|
||||
// instance->listener =
|
||||
// nfc_listener_alloc(instance->nfc, NfcProtocolIso14443_4a, iso14443_4a_data);
|
||||
// nfc_listener_start(
|
||||
// instance->listener, nfc_scene_emulate_listener_callback_iso14443_4a, instance);
|
||||
// }
|
||||
|
||||
const NfcProtocolSupportBase nfc_protocol_support_emv = {
|
||||
.features = NfcProtocolFeatureMoreInfo,
|
||||
|
||||
.scene_info =
|
||||
{
|
||||
.on_enter = nfc_scene_info_on_enter_emv,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_more_info =
|
||||
{
|
||||
.on_enter = nfc_scene_more_info_on_enter_emv,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_read =
|
||||
{
|
||||
.on_enter = nfc_scene_read_on_enter_emv,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_read_menu =
|
||||
{
|
||||
.on_enter = nfc_protocol_support_common_on_enter_empty,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_read_success =
|
||||
{
|
||||
.on_enter = nfc_scene_read_success_on_enter_emv,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_saved_menu =
|
||||
{
|
||||
.on_enter = nfc_protocol_support_common_on_enter_empty,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_save_name =
|
||||
{
|
||||
.on_enter = nfc_protocol_support_common_on_enter_empty,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
};
|
||||
5
applications/main/nfc/helpers/protocol_support/emv/emv.h
Normal file
5
applications/main/nfc/helpers/protocol_support/emv/emv.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "../nfc_protocol_support_base.h"
|
||||
|
||||
extern const NfcProtocolSupportBase nfc_protocol_support_emv;
|
||||
190
applications/main/nfc/helpers/protocol_support/emv/emv_render.c
Normal file
190
applications/main/nfc/helpers/protocol_support/emv/emv_render.c
Normal file
@@ -0,0 +1,190 @@
|
||||
#include "emv_render.h"
|
||||
|
||||
#include "../iso14443_4a/iso14443_4a_render.h"
|
||||
#include "nfc/nfc_app_i.h"
|
||||
|
||||
void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str) {
|
||||
nfc_render_emv_header(str);
|
||||
nfc_render_emv_uid(
|
||||
data->iso14443_4a_data->iso14443_3a_data->uid,
|
||||
data->iso14443_4a_data->iso14443_3a_data->uid_len,
|
||||
str);
|
||||
|
||||
if(format_type == NfcProtocolFormatTypeFull) nfc_render_emv_extra(data, str);
|
||||
}
|
||||
|
||||
void nfc_render_emv_header(FuriString* str) {
|
||||
furi_string_cat_printf(str, "\e#%s\n", "EMV");
|
||||
}
|
||||
|
||||
void nfc_render_emv_uid(const uint8_t* uid, const uint8_t uid_len, FuriString* str) {
|
||||
if(uid_len == 0) return;
|
||||
|
||||
furi_string_cat_printf(str, "UID: ");
|
||||
|
||||
for(uint8_t i = 0; i < uid_len; i++) {
|
||||
furi_string_cat_printf(str, "%02X ", uid[i]);
|
||||
}
|
||||
|
||||
furi_string_cat_printf(str, "\n");
|
||||
}
|
||||
|
||||
void nfc_render_emv_aid(const uint8_t* uid, const uint8_t uid_len, FuriString* str) {
|
||||
if(uid_len == 0) return;
|
||||
|
||||
furi_string_cat_printf(str, "UID: ");
|
||||
|
||||
for(uint8_t i = 0; i < uid_len; i++) {
|
||||
furi_string_cat_printf(str, "%02X ", uid[i]);
|
||||
}
|
||||
|
||||
furi_string_cat_printf(str, "\n");
|
||||
}
|
||||
|
||||
void nfc_render_emv_data(const EmvData* data, FuriString* str) {
|
||||
nfc_render_emv_pan(data->emv_application.pan, data->emv_application.pan_len, str);
|
||||
nfc_render_emv_name(data->emv_application.name, str);
|
||||
}
|
||||
|
||||
void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str) {
|
||||
if(len == 0) return;
|
||||
|
||||
FuriString* card_number = furi_string_alloc();
|
||||
for(uint8_t i = 0; i < len; i++) {
|
||||
if((i % 2 == 0) && (i != 0)) furi_string_cat_printf(card_number, " ");
|
||||
furi_string_cat_printf(card_number, "%02X", data[i]);
|
||||
}
|
||||
|
||||
// Cut padding 'F' from card number
|
||||
furi_string_trim(card_number, "F");
|
||||
furi_string_cat(str, card_number);
|
||||
furi_string_free(card_number);
|
||||
|
||||
furi_string_cat_printf(str, "\n");
|
||||
}
|
||||
|
||||
void nfc_render_emv_expired(const EmvApplication* apl, FuriString* str) {
|
||||
if(apl->exp_month == 0) return;
|
||||
furi_string_cat_printf(str, "Exp: %02X/%02X\n", apl->exp_month, apl->exp_year);
|
||||
}
|
||||
|
||||
void nfc_render_emv_currency(uint16_t cur_code, FuriString* str) {
|
||||
if(!cur_code) return;
|
||||
|
||||
furi_string_cat_printf(str, "Currency code: %04X\n", cur_code);
|
||||
}
|
||||
|
||||
void nfc_render_emv_country(uint16_t country_code, FuriString* str) {
|
||||
if(!country_code) return;
|
||||
|
||||
furi_string_cat_printf(str, "Country code: %04X\n", country_code);
|
||||
}
|
||||
|
||||
void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) {
|
||||
const uint8_t len = apl->aid_len;
|
||||
|
||||
if(!len) {
|
||||
furi_string_cat_printf(str, "No Pay Application found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
furi_string_cat_printf(str, "AID: ");
|
||||
|
||||
for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%02X", apl->aid[i]);
|
||||
|
||||
furi_string_cat_printf(str, "\n");
|
||||
}
|
||||
|
||||
static void nfc_render_emv_pin_try_counter(uint8_t counter, FuriString* str) {
|
||||
if(counter == 0xff) return;
|
||||
furi_string_cat_printf(str, "PIN attempts left: %d\n", counter);
|
||||
}
|
||||
|
||||
void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) {
|
||||
if(apl->transaction_counter)
|
||||
furi_string_cat_printf(str, "Transactions count: %d\n", apl->transaction_counter);
|
||||
if(apl->last_online_atc)
|
||||
furi_string_cat_printf(str, "Last Online ATC: %d\n", apl->last_online_atc);
|
||||
|
||||
const uint8_t len = apl->active_tr;
|
||||
if(!len) {
|
||||
furi_string_cat_printf(str, "No transactions info\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FuriString* tmp = furi_string_alloc();
|
||||
|
||||
furi_string_cat_printf(str, "Transactions:\n");
|
||||
for(int i = 0; i < len; i++) {
|
||||
// If no date and amount - skip
|
||||
if((!apl->trans[i].date) && (!apl->trans[i].amount)) continue;
|
||||
// transaction counter
|
||||
furi_string_cat_printf(str, "\e#%d: ", apl->trans[i].atc);
|
||||
|
||||
// Print transaction amount
|
||||
if(!apl->trans[i].amount) {
|
||||
furi_string_cat_printf(str, "???");
|
||||
} else {
|
||||
uint8_t* a = (uint8_t*)&apl->trans[i].amount;
|
||||
bool top = true;
|
||||
for(int x = 0; x < 6; x++) {
|
||||
// cents
|
||||
if(x == 5) {
|
||||
furi_string_cat_printf(str, ".%02X", a[x]);
|
||||
break;
|
||||
}
|
||||
if(a[x]) {
|
||||
if(top) {
|
||||
furi_string_cat_printf(str, "%X", a[x]);
|
||||
top = false;
|
||||
} else {
|
||||
furi_string_cat_printf(str, "%02X", a[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(apl->trans[i].currency) {
|
||||
furi_string_set_str(tmp, "UNK");
|
||||
nfc_emv_parser_get_currency_name(storage, apl->trans[i].currency, tmp);
|
||||
furi_string_cat_printf(str, " %s\n", furi_string_get_cstr(tmp));
|
||||
}
|
||||
|
||||
if(apl->trans[i].country) {
|
||||
furi_string_set_str(tmp, "UNK");
|
||||
nfc_emv_parser_get_country_name(storage, apl->trans[i].country, tmp);
|
||||
furi_string_cat_printf(str, "Country: %s\n", furi_string_get_cstr(tmp));
|
||||
}
|
||||
|
||||
if(apl->trans[i].date)
|
||||
furi_string_cat_printf(
|
||||
str,
|
||||
"%02lx.%02lx.%02lx ",
|
||||
apl->trans[i].date >> 16,
|
||||
(apl->trans[i].date >> 8) & 0xff,
|
||||
apl->trans[i].date & 0xff);
|
||||
|
||||
if(apl->trans[i].time)
|
||||
furi_string_cat_printf(
|
||||
str,
|
||||
"%02lx:%02lx:%02lx",
|
||||
apl->trans[i].time & 0xff,
|
||||
(apl->trans[i].time >> 8) & 0xff,
|
||||
apl->trans[i].time >> 16);
|
||||
|
||||
// Line break
|
||||
furi_string_cat_printf(str, "\n");
|
||||
}
|
||||
|
||||
furi_string_free(tmp);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
void nfc_render_emv_extra(const EmvData* data, FuriString* str) {
|
||||
nfc_render_emv_application(&data->emv_application, str);
|
||||
|
||||
nfc_render_emv_currency(data->emv_application.currency_code, str);
|
||||
nfc_render_emv_country(data->emv_application.country_code, str);
|
||||
nfc_render_emv_pin_try_counter(data->emv_application.pin_try_counter, str);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <nfc/protocols/emv/emv.h>
|
||||
|
||||
#include "../nfc_protocol_support_render_common.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str);
|
||||
|
||||
void nfc_render_emv_data(const EmvData* data, FuriString* str);
|
||||
|
||||
void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str);
|
||||
|
||||
void nfc_render_emv_name(const char* data, FuriString* str);
|
||||
|
||||
void nfc_render_emv_application(const EmvApplication* data, FuriString* str);
|
||||
|
||||
void nfc_render_emv_extra(const EmvData* data, FuriString* str);
|
||||
|
||||
void nfc_render_emv_expired(const EmvApplication* apl, FuriString* str);
|
||||
|
||||
void nfc_render_emv_country(uint16_t country_code, FuriString* str);
|
||||
|
||||
void nfc_render_emv_currency(uint16_t cur_code, FuriString* str);
|
||||
|
||||
void nfc_render_emv_transactions(const EmvApplication* data, FuriString* str);
|
||||
|
||||
void nfc_render_emv_uid(const uint8_t* uid, const uint8_t uid_len, FuriString* str);
|
||||
|
||||
void nfc_render_emv_header(FuriString* str);
|
||||
@@ -13,6 +13,7 @@ static void nfc_scene_info_on_enter_felica(NfcApp* instance) {
|
||||
const FelicaData* data = nfc_device_get_data(device, NfcProtocolFelica);
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
nfc_append_filename_string_when_present(instance, temp_str);
|
||||
furi_string_cat_printf(
|
||||
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
|
||||
nfc_render_felica_info(data, NfcProtocolFormatTypeFull, temp_str);
|
||||
@@ -58,8 +59,8 @@ static void nfc_scene_read_success_on_enter_felica(NfcApp* instance) {
|
||||
furi_string_free(temp_str);
|
||||
}
|
||||
|
||||
static bool nfc_scene_saved_menu_on_event_felica(NfcApp* instance, uint32_t event) {
|
||||
if(event == SubmenuIndexCommonEdit) {
|
||||
static bool nfc_scene_saved_menu_on_event_felica(NfcApp* instance, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom && event.event == SubmenuIndexCommonEdit) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid);
|
||||
return true;
|
||||
}
|
||||
@@ -67,8 +68,14 @@ static bool nfc_scene_saved_menu_on_event_felica(NfcApp* instance, uint32_t even
|
||||
return false;
|
||||
}
|
||||
|
||||
static void nfc_scene_emulate_on_enter_felica(NfcApp* instance) {
|
||||
const FelicaData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolFelica);
|
||||
instance->listener = nfc_listener_alloc(instance->nfc, NfcProtocolFelica, data);
|
||||
nfc_listener_start(instance->listener, NULL, NULL);
|
||||
}
|
||||
|
||||
const NfcProtocolSupportBase nfc_protocol_support_felica = {
|
||||
.features = NfcProtocolFeatureNone,
|
||||
.features = NfcProtocolFeatureEmulateUid,
|
||||
|
||||
.scene_info =
|
||||
{
|
||||
@@ -102,7 +109,7 @@ const NfcProtocolSupportBase nfc_protocol_support_felica = {
|
||||
},
|
||||
.scene_emulate =
|
||||
{
|
||||
.on_enter = nfc_protocol_support_common_on_enter_empty,
|
||||
.on_enter = nfc_scene_emulate_on_enter_felica,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -13,6 +13,8 @@ static void nfc_scene_info_on_enter_iso14443_3a(NfcApp* instance) {
|
||||
const Iso14443_3aData* data = nfc_device_get_data(device, NfcProtocolIso14443_3a);
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
nfc_append_filename_string_when_present(instance, temp_str);
|
||||
|
||||
furi_string_cat_printf(
|
||||
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
|
||||
nfc_render_iso14443_3a_info(data, NfcProtocolFormatTypeFull, temp_str);
|
||||
@@ -95,8 +97,8 @@ static void nfc_scene_emulate_on_enter_iso14443_3a(NfcApp* instance) {
|
||||
instance->listener, nfc_scene_emulate_listener_callback_iso14443_3a, instance);
|
||||
}
|
||||
|
||||
static bool nfc_scene_read_menu_on_event_iso14443_3a(NfcApp* instance, uint32_t event) {
|
||||
if(event == SubmenuIndexCommonEmulate) {
|
||||
static bool nfc_scene_read_menu_on_event_iso14443_3a(NfcApp* instance, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom && event.event == SubmenuIndexCommonEmulate) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneEmulate);
|
||||
return true;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user