mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 12:42:30 +04:00
Compare commits
644 Commits
nfcrefacto
...
leptoptilo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c5a78a59f | ||
|
|
4e7f25a539 | ||
|
|
5e47048369 | ||
|
|
a6c5a1ba69 | ||
|
|
7b26dc5ebf | ||
|
|
1070064f89 | ||
|
|
88b354b57e | ||
|
|
4b7ca736d6 | ||
|
|
18ea2371a4 | ||
|
|
22be2629e0 | ||
|
|
7fc4ba7c1c | ||
|
|
a2739ab0c1 | ||
|
|
bc309cebe6 | ||
|
|
cc937a97ef | ||
|
|
02f8840ac7 | ||
|
|
1c56a30d35 | ||
|
|
b0a741233f | ||
|
|
b29a5896a4 | ||
|
|
dbb81055f2 | ||
|
|
465fcf93a7 | ||
|
|
65b0aa8e99 | ||
|
|
90a8009d43 | ||
|
|
b1ebb142c4 | ||
|
|
d4433fabd4 | ||
|
|
10d2911af2 | ||
|
|
b8d5dfdd05 | ||
|
|
c778233223 | ||
|
|
614f9b8705 | ||
|
|
26cb315845 | ||
|
|
e1bc60b7eb | ||
|
|
a88adc2a27 | ||
|
|
aa54a477d8 | ||
|
|
c69ce4c921 | ||
|
|
b77e430df5 | ||
|
|
a64907d84b | ||
|
|
bc98c788fe | ||
|
|
59370e03db | ||
|
|
16d1e71d6e | ||
|
|
111438361d | ||
|
|
113afc0d0f | ||
|
|
21962da715 | ||
|
|
d731918197 | ||
|
|
e143833ee1 | ||
|
|
ee11aca464 | ||
|
|
71e763d9b3 | ||
|
|
02a827da38 | ||
|
|
2d32ea68fe | ||
|
|
66c60e65aa | ||
|
|
b15787053a | ||
|
|
b38d2e8d84 | ||
|
|
9fcf3795ee | ||
|
|
073902f83e | ||
|
|
c7952d57d8 | ||
|
|
e114c01ce2 | ||
|
|
1e473e59f4 | ||
|
|
3e3250ea5f | ||
|
|
a484e42d42 | ||
|
|
c2613c00f1 | ||
|
|
90e60560c7 | ||
|
|
9edf2a7624 | ||
|
|
fb956e2427 | ||
|
|
4e1089ec49 | ||
|
|
2c650b5bc7 | ||
|
|
fcf3b50f69 | ||
|
|
88a3b4593d | ||
|
|
b6a6528526 | ||
|
|
01d937ca0b | ||
|
|
60a9d7e6cf | ||
|
|
ae160efa16 | ||
|
|
33cf554f06 | ||
|
|
200a6138ef | ||
|
|
4adb492e29 | ||
|
|
698d0b4b49 | ||
|
|
f7742c692d | ||
|
|
b8b344c6e1 | ||
|
|
4d73794100 | ||
|
|
913659325b | ||
|
|
d19f8f51ea | ||
|
|
8e4c366f0b | ||
|
|
7b01a33b3f | ||
|
|
11a34e5bc3 | ||
|
|
2c5973be22 | ||
|
|
597d295743 | ||
|
|
62edabe9dd | ||
|
|
890bb9838c | ||
|
|
87804374c5 | ||
|
|
26ac455fb9 | ||
|
|
9298e567d0 | ||
|
|
c3c54f672c | ||
|
|
feb45f6645 | ||
|
|
887083b7f5 | ||
|
|
c061fb1681 | ||
|
|
8dd59a5d9e | ||
|
|
cc457fade2 | ||
|
|
d72c449b13 | ||
|
|
d70bcfdfff | ||
|
|
6d15c23231 | ||
|
|
0397dd0a40 | ||
|
|
dd988ba449 | ||
|
|
a46038acbf | ||
|
|
3f29295380 | ||
|
|
3c77dc7930 | ||
|
|
13493916e2 | ||
|
|
0acd3bfc66 | ||
|
|
3d9a6a41db | ||
|
|
7d7f15bdf1 | ||
|
|
5c88e680a6 | ||
|
|
fdde5856b8 | ||
|
|
949098bbc5 | ||
|
|
4042852825 | ||
|
|
71a93e8cc3 | ||
|
|
d75f2c62ca | ||
|
|
dd87afcbde | ||
|
|
f5cc40af0c | ||
|
|
25a280c818 | ||
|
|
19fe8e8954 | ||
|
|
9d5135daff | ||
|
|
3a847243bc | ||
|
|
a9fb8da642 | ||
|
|
7e7c2b746c | ||
|
|
42d3876d22 | ||
|
|
0f7411d03a | ||
|
|
d61931e69d | ||
|
|
75c7c7473a | ||
|
|
c8e62ba5e8 | ||
|
|
1faeca6e1b | ||
|
|
0fddc8ed60 | ||
|
|
9d1b14effa | ||
|
|
0154018363 | ||
|
|
b904555ebf | ||
|
|
14d3510d8e | ||
|
|
11cfbd1ec8 | ||
|
|
389affd904 | ||
|
|
6d09bebf14 | ||
|
|
b0df852944 | ||
|
|
6836a7b7c5 | ||
|
|
14dabf523a | ||
|
|
809e1b3aff | ||
|
|
a9de06d6f2 | ||
|
|
08f096df24 | ||
|
|
4a382bc1de | ||
|
|
6f71f1113a | ||
|
|
c24625fae8 | ||
|
|
a35159c220 | ||
|
|
2d2fac5045 | ||
|
|
c35f258ab8 | ||
|
|
702e4f39ab | ||
|
|
56875ed9a7 | ||
|
|
1e09034e23 | ||
|
|
8a86571068 | ||
|
|
37708b0e79 | ||
|
|
14ae52f88f | ||
|
|
8584702fd7 | ||
|
|
ed9cb357b5 | ||
|
|
34a1d9eba4 | ||
|
|
357df80642 | ||
|
|
1a02152d03 | ||
|
|
ab609bc294 | ||
|
|
e6935f2a9d | ||
|
|
5b97ddc842 | ||
|
|
7ab888bb98 | ||
|
|
b135c8e792 | ||
|
|
edda4e5508 | ||
|
|
ed055cbdf6 | ||
|
|
cf41c98d66 | ||
|
|
73deff8863 | ||
|
|
4c2e997997 | ||
|
|
ade84ccb9c | ||
|
|
bcdb9cb13c | ||
|
|
afad5e4407 | ||
|
|
962d809ad7 | ||
|
|
3c73123a81 | ||
|
|
f3f3e56c63 | ||
|
|
b2a7bb0696 | ||
|
|
c0db3d541e | ||
|
|
50e0521bf7 | ||
|
|
ebd09a1981 | ||
|
|
6bc63b7734 | ||
|
|
f6eb79e1e5 | ||
|
|
d195de502e | ||
|
|
ec356626fa | ||
|
|
b1674711a1 | ||
|
|
9ceae3a3b2 | ||
|
|
ded9b121ba | ||
|
|
534fe2fb26 | ||
|
|
3cbc68f07a | ||
|
|
26da5f564b | ||
|
|
1ad9bb8caf | ||
|
|
5a92adaefc | ||
|
|
c489c956e7 | ||
|
|
afd41aade1 | ||
|
|
fee6f12684 | ||
|
|
4265b9c28e | ||
|
|
95e653cf76 | ||
|
|
29fa68118d | ||
|
|
4625d6f17c | ||
|
|
dd4f873439 | ||
|
|
4984e9e414 | ||
|
|
3e53e69827 | ||
|
|
8c54c14742 | ||
|
|
e180266c1a | ||
|
|
751cf23410 | ||
|
|
cd8e76bbcd | ||
|
|
2d78e23d25 | ||
|
|
9d6f51484a | ||
|
|
9a77dbec56 | ||
|
|
a83e421d71 | ||
|
|
2c784d3fea | ||
|
|
c736c3f3f0 | ||
|
|
e0782966d4 | ||
|
|
ed34dfa1c6 | ||
|
|
962a7b1ba7 | ||
|
|
2e05489a82 | ||
|
|
ff28c23f64 | ||
|
|
3721a71eab | ||
|
|
6846e808cf | ||
|
|
2f0adf73c7 | ||
|
|
35674a306b | ||
|
|
fb2bff6c4d | ||
|
|
12d70a3c32 | ||
|
|
f9b6d22534 | ||
|
|
c63089a929 | ||
|
|
ebcc317816 | ||
|
|
603421bd8c | ||
|
|
6aa7f2e261 | ||
|
|
1bd42af688 | ||
|
|
398a468fd7 | ||
|
|
90b49926ea | ||
|
|
7caf2bd2ff | ||
|
|
3446b38a06 | ||
|
|
22be06174a | ||
|
|
6bfa591e92 | ||
|
|
4573046df8 | ||
|
|
fe05c678c4 | ||
|
|
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 | ||
|
|
c85e1305c0 | ||
|
|
5dfa2fd24c | ||
|
|
71ed7f8e94 | ||
|
|
4636444464 | ||
|
|
e7bf9b4df2 | ||
|
|
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 | ||
|
|
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 | ||
|
|
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 |
@@ -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 lib/mjs -e */arm-none-eabi/*
|
||||
|
||||
15
.vscode/example/cpptools/c_cpp_properties.json
vendored
15
.vscode/example/cpptools/c_cpp_properties.json
vendored
@@ -5,27 +5,24 @@
|
||||
"compilerPath": "${workspaceFolder}/toolchain/x86_64-windows/bin/arm-none-eabi-gcc.exe",
|
||||
"intelliSenseMode": "gcc-arm",
|
||||
"compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
|
||||
"configurationProvider": "ms-vscode.cpptools",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "c++17"
|
||||
"cStandard": "gnu23",
|
||||
"cppStandard": "c++20"
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"compilerPath": "${workspaceFolder}/toolchain/x86_64-linux/bin/arm-none-eabi-gcc",
|
||||
"intelliSenseMode": "gcc-arm",
|
||||
"compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
|
||||
"configurationProvider": "ms-vscode.cpptools",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "c++17"
|
||||
"cStandard": "gnu23",
|
||||
"cppStandard": "c++20"
|
||||
},
|
||||
{
|
||||
"name": "Mac",
|
||||
"compilerPath": "${workspaceFolder}/toolchain/x86_64-darwin/bin/arm-none-eabi-gcc",
|
||||
"intelliSenseMode": "gcc-arm",
|
||||
"compileCommands": "${workspaceFolder}/build/latest/compile_commands.json",
|
||||
"configurationProvider": "ms-vscode.cpptools",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "c++17"
|
||||
"cStandard": "gnu23",
|
||||
"cppStandard": "c++20"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
|
||||
16
.vscode/example/settings.json
vendored
16
.vscode/example/settings.json
vendored
@@ -1,20 +1,14 @@
|
||||
{
|
||||
"C_Cpp.default.cStandard": "gnu17",
|
||||
"C_Cpp.default.cppStandard": "c++17",
|
||||
"C_Cpp.default.cStandard": "gnu23",
|
||||
"C_Cpp.default.cppStandard": "c++20",
|
||||
"python.formatting.provider": "black",
|
||||
"workbench.tree.indent": 12,
|
||||
"cortex-debug.enableTelemetry": false,
|
||||
"cortex-debug.variableUseNaturalFormat": true,
|
||||
"cortex-debug.showRTOS": true,
|
||||
"cortex-debug.armToolchainPath.windows": "${workspaceFolder}/toolchain/x86_64-windows/bin",
|
||||
"cortex-debug.armToolchainPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/bin",
|
||||
"cortex-debug.armToolchainPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/bin",
|
||||
"cortex-debug.openocdPath.windows": "${workspaceFolder}/toolchain/x86_64-windows/openocd/bin/openocd.exe",
|
||||
"cortex-debug.openocdPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/openocd/bin/openocd",
|
||||
"cortex-debug.openocdPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/openocd/bin/openocd",
|
||||
"cortex-debug.gdbPath.windows": "${workspaceFolder}/toolchain/x86_64-windows/bin/arm-none-eabi-gdb-py.bat",
|
||||
"cortex-debug.gdbPath.linux": "${workspaceFolder}/toolchain/x86_64-linux/bin/arm-none-eabi-gdb-py",
|
||||
"cortex-debug.gdbPath.osx": "${workspaceFolder}/toolchain/x86_64-darwin/bin/arm-none-eabi-gdb-py",
|
||||
"cortex-debug.armToolchainPath": "${workspaceFolder}/toolchain/current/bin",
|
||||
"cortex-debug.openocdPath": "${workspaceFolder}/toolchain/current/bin/openocd",
|
||||
"cortex-debug.gdbPath": "${workspaceFolder}/toolchain/current/bin/arm-none-eabi-gdb-py3",
|
||||
"editor.formatOnSave": true,
|
||||
"files.associations": {
|
||||
"*.scons": "python",
|
||||
|
||||
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!
|
||||
|
||||
|
||||
48
ReadMe.md
48
ReadMe.md
@@ -55,13 +55,13 @@
|
||||
- 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**
|
||||
- **Custom buttons for Keeloq / Alutech AT4N / Nice Flor S / Somfy Telis / Security+ 2.0 / CAME Atomo** - now you can use arrow buttons to send signal with different button code
|
||||
- `Add manually` menu extended with new protocols
|
||||
- FAAC SLH, BFT Mitto / Somfy Telis / Nice Flor S / CAME Atomo, etc.. manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis)
|
||||
- FAAC SLH, BFT Mitto / Somfy Telis / Nice Flor S / CAME Atomo, etc.. manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis, (right arrow button for other protocols))
|
||||
- Debug mode counter increase settings (+1 -> +5, +10, default: +1)
|
||||
- Debug PIN output settings for protocol development
|
||||
|
||||
@@ -79,13 +79,15 @@
|
||||
- **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)
|
||||
- Byte Input Mini editor -> **Press UP** multiple times until the nibble editor appears
|
||||
- Clock on Desktop -> `Settings -> Desktop -> Show Clock`
|
||||
- Byte Input Mini editor -> **Press UP** multiple times until the nibble editor appears (by @gid9798)
|
||||
- Clock on Desktop -> `Settings -> Desktop -> Show Clock` (by @gid9798)
|
||||
- Battery percentage display with different styles `Settings -> Desktop -> Battery View`
|
||||
- More games in Dummy Mode -> click or hold any of arrow buttons
|
||||
- Lock device with pin(or regular lock if pin not set) by holding UP button on main screen [(by an4tur0r)](https://github.com/DarkFlippers/unleashed-firmware/pull/107)
|
||||
@@ -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: Dea Mio, Genius Bravo, GSN, 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
|
||||
|
||||
@@ -196,22 +186,20 @@ See full list and sources here: [xMasterX/all-the-plugins](https://github.com/xM
|
||||
|
||||
## **Sub-GHz**
|
||||
|
||||
### - [How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis, Aprimatic, AN-Motors, etc..)](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
|
||||
### - External Radio: [How to connect CC1101 module](https://github.com/quen0n/flipperzero-ext-cc1101)
|
||||
|
||||
### - Transmission is blocked? [How to extend Sub-GHz frequency range](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md)
|
||||
|
||||
### - [How to add extra Sub-GHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md)
|
||||
|
||||
### - [How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis, Aprimatic, AN-Motors, etc..)](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
|
||||
|
||||
### - [~~Configure Sub-GHz Remote App~~](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md) Not recomeded, please use embedded configurator
|
||||
### - [~~Configure Sub-GHz Remote App~~](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md) Not recommended, please use embedded configurator
|
||||
|
||||
## **Plugins**
|
||||
|
||||
### - TOTP (Authenticator): [config description](https://github.com/akopachov/flipper-zero_authenticator/blob/master/docs/conf-file_description.md)
|
||||
|
||||
### - Mifare Nested plugin: [How to recover keys](https://github.com/AloneLiberty/FlipperNested#how-to-use-it)
|
||||
|
||||
### - Barcode Generator: [How to use](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/BarcodeGenerator.md)
|
||||
|
||||
### - Multi Converter: [How to use](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/MultiConverter.md)
|
||||
|
||||
102
SConstruct
102
SConstruct
@@ -66,6 +66,7 @@ if GetOption("fullenv") or any(
|
||||
|
||||
# Target for self-update package
|
||||
dist_basic_arguments = [
|
||||
"${ARGS}",
|
||||
"--bundlever",
|
||||
"${UPDATE_VERSION_STRING}",
|
||||
]
|
||||
@@ -172,17 +173,20 @@ 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",
|
||||
"${ARGS}",
|
||||
]
|
||||
]
|
||||
],
|
||||
),
|
||||
source=firmware_env.Dir(("${RESOURCES_ROOT}/apps")),
|
||||
)
|
||||
Depends(fap_deploy, firmware_env["FW_RESOURCES_MANIFEST"])
|
||||
@@ -206,7 +210,7 @@ distenv.Alias("jflash", firmware_jflash)
|
||||
|
||||
distenv.PhonyTarget(
|
||||
"gdb_trace_all",
|
||||
"$GDB $GDBOPTS $SOURCES $GDBFLASH",
|
||||
[["${GDB}", "${GDBOPTS}", "${SOURCES}", "${GDBFLASH}"]],
|
||||
source=firmware_env["FW_ELF"],
|
||||
GDBOPTS="${GDBOPTS_BASE}",
|
||||
GDBREMOTE="${OPENOCD_GDB_PIPE}",
|
||||
@@ -261,7 +265,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,
|
||||
)
|
||||
@@ -270,29 +274,49 @@ distenv.PhonyTarget(
|
||||
# Just start OpenOCD
|
||||
distenv.PhonyTarget(
|
||||
"openocd",
|
||||
"${OPENOCDCOM}",
|
||||
[["${OPENOCDCOM}", "${ARGS}"]],
|
||||
)
|
||||
|
||||
# Linter
|
||||
distenv.PhonyTarget(
|
||||
"lint",
|
||||
"${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py check ${LINT_SOURCES}",
|
||||
[
|
||||
[
|
||||
"${PYTHON3}",
|
||||
"${FBT_SCRIPT_DIR}/lint.py",
|
||||
"check",
|
||||
"${LINT_SOURCES}",
|
||||
"${ARGS}",
|
||||
]
|
||||
],
|
||||
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}",
|
||||
"${ARGS}",
|
||||
]
|
||||
],
|
||||
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",
|
||||
@@ -301,8 +325,20 @@ firmware_env.Append(
|
||||
)
|
||||
|
||||
|
||||
black_commandline = "@${PYTHON3} -m black ${PY_BLACK_ARGS} ${PY_LINT_SOURCES}"
|
||||
black_base_args = ["--include", '"\\.scons|\\.py|SConscript|SConstruct"']
|
||||
black_commandline = [
|
||||
[
|
||||
"@${PYTHON3}",
|
||||
"-m",
|
||||
"black",
|
||||
"${PY_BLACK_ARGS}",
|
||||
"${PY_LINT_SOURCES}",
|
||||
"${ARGS}",
|
||||
]
|
||||
]
|
||||
black_base_args = [
|
||||
"--include",
|
||||
'"(\\.scons|\\.py|SConscript|SConstruct|\\.fam)$"',
|
||||
]
|
||||
|
||||
distenv.PhonyTarget(
|
||||
"lint_py",
|
||||
@@ -323,10 +359,30 @@ 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}",
|
||||
"${ARGS}",
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
# Update WiFi devboard firmware
|
||||
distenv.PhonyTarget("devboard_flash", "${PYTHON3} ${FBT_SCRIPT_DIR}/wifi_board.py")
|
||||
# Update WiFi devboard firmware with release channel
|
||||
distenv.PhonyTarget(
|
||||
"devboard_flash",
|
||||
[
|
||||
[
|
||||
"${PYTHON3}",
|
||||
"${FBT_SCRIPT_DIR}/wifi_board.py",
|
||||
"${ARGS}",
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
# Find blackmagic probe
|
||||
@@ -340,7 +396,7 @@ distenv.PhonyTarget(
|
||||
distenv.PhonyTarget(
|
||||
"get_stlink",
|
||||
distenv.Action(
|
||||
lambda **kw: distenv.GetDevices(),
|
||||
lambda **_: distenv.GetDevices(),
|
||||
None,
|
||||
),
|
||||
)
|
||||
@@ -356,10 +412,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
|
||||
@@ -72,7 +71,10 @@ Small applications providing configuration for basic firmware and its services.
|
||||
|
||||
## system
|
||||
|
||||
Utility apps not visible in other menus.
|
||||
Utility apps not visible in other menus, plus few external apps pre-packaged with the firmware.
|
||||
|
||||
- `hid_app` - BLE & USB HID remote
|
||||
- `js_app` - JS engine runner
|
||||
- `snake_game` - Snake game
|
||||
- `storage_move_to_sd` - Data migration tool for internal storage
|
||||
- `updater` - Update service & application
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "accessor_view_manager.h"
|
||||
#include "accessor_event.h"
|
||||
#include <callback-connector.h>
|
||||
#include "callback_connector.h"
|
||||
|
||||
AccessorAppViewManager::AccessorAppViewManager() {
|
||||
event_queue = furi_message_queue_alloc(10, sizeof(AccessorEvent));
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
#ifndef CALLBACKCONNECTOR_H
|
||||
#define CALLBACKCONNECTOR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <functional>
|
||||
namespace cbc {
|
||||
namespace Details {
|
||||
|
||||
template <std::size_t Tag, typename T, typename Ret, typename... Args> class FuncMemberWrapper {
|
||||
template <std::size_t Tag, typename T, typename Ret, typename... Args>
|
||||
class FuncMemberWrapper {
|
||||
public:
|
||||
FuncMemberWrapper() = delete;
|
||||
using member_fun_t = Ret (T::*)(Args...);
|
||||
@@ -43,7 +46,8 @@ template <std::size_t Tag, typename T, typename Ret, typename... Args>
|
||||
typename FuncMemberWrapper<Tag, T, Ret, Args...>::const_member_fun_t
|
||||
FuncMemberWrapper<Tag, T, Ret, Args...>::const_member{};
|
||||
|
||||
template <typename Functor, typename Ret, typename... Args> struct FunctorWrapper {
|
||||
template <typename Functor, typename Ret, typename... Args>
|
||||
struct FunctorWrapper {
|
||||
public:
|
||||
static std::function<Ret(Args...)> functor;
|
||||
static auto instatiate(Functor fn) {
|
||||
@@ -75,7 +79,8 @@ auto const_instantiate(T* t, Ret (T::*ptr)(Args...) const) {
|
||||
return FuncMemberWrapper<tag, T, Ret, Args...>::instantiate(t, ptr);
|
||||
}
|
||||
|
||||
template <std::size_t tag, typename T, typename Func> auto const_instantiate(T* t, Func ptr) {
|
||||
template <std::size_t tag, typename T, typename Func>
|
||||
auto const_instantiate(T* t, Func ptr) {
|
||||
return const_instantiate(t, ptr);
|
||||
}
|
||||
|
||||
@@ -91,9 +96,11 @@ auto obtain_connector(T* t, Ret (T::*ptr)(Args...) const) {
|
||||
return Details::FuncMemberWrapper<tag, T, Ret, Args...>::instantiate(t, ptr);
|
||||
}
|
||||
|
||||
template <typename Functor> auto obtain_connector(Functor functor) {
|
||||
template <typename Functor>
|
||||
auto obtain_connector(Functor functor) {
|
||||
return Details::deducer(std::move(functor), &Functor::operator());
|
||||
}
|
||||
} //end of cbc scope
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // CALLBACKCONNECTOR_H
|
||||
@@ -2,12 +2,12 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
volatile unsigned long WIEGAND::_cardTempHigh = 0;
|
||||
volatile unsigned long WIEGAND::_cardTemp = 0;
|
||||
volatile unsigned long WIEGAND::_lastWiegand = 0;
|
||||
unsigned long WIEGAND::_cardTempHigh = 0;
|
||||
unsigned long WIEGAND::_cardTemp = 0;
|
||||
unsigned long WIEGAND::_lastWiegand = 0;
|
||||
unsigned long WIEGAND::_code = 0;
|
||||
unsigned long WIEGAND::_codeHigh = 0;
|
||||
volatile int WIEGAND::_bitCount = 0;
|
||||
int WIEGAND::_bitCount = 0;
|
||||
int WIEGAND::_wiegandType = 0;
|
||||
|
||||
constexpr uint32_t clocks_in_ms = 64 * 1000;
|
||||
@@ -98,10 +98,7 @@ void WIEGAND::ReadD1() {
|
||||
_lastWiegand = DWT->CYCCNT; // Keep track of last wiegand bit received
|
||||
}
|
||||
|
||||
unsigned long WIEGAND::GetCardId(
|
||||
volatile unsigned long* codehigh,
|
||||
volatile unsigned long* codelow,
|
||||
char bitlength) {
|
||||
unsigned long WIEGAND::GetCardId(unsigned long* codehigh, unsigned long* codelow, char bitlength) {
|
||||
if(bitlength == 26) // EM tag
|
||||
return (*codelow & 0x1FFFFFE) >> 1;
|
||||
|
||||
|
||||
@@ -15,15 +15,13 @@ public:
|
||||
|
||||
private:
|
||||
static bool DoWiegandConversion();
|
||||
static unsigned long GetCardId(
|
||||
volatile unsigned long* codehigh,
|
||||
volatile unsigned long* codelow,
|
||||
char bitlength);
|
||||
static unsigned long
|
||||
GetCardId(unsigned long* codehigh, unsigned long* codelow, char bitlength);
|
||||
|
||||
static volatile unsigned long _cardTempHigh;
|
||||
static volatile unsigned long _cardTemp;
|
||||
static volatile unsigned long _lastWiegand;
|
||||
static volatile int _bitCount;
|
||||
static unsigned long _cardTempHigh;
|
||||
static unsigned long _cardTemp;
|
||||
static unsigned long _lastWiegand;
|
||||
static int _bitCount;
|
||||
static int _wiegandType;
|
||||
static unsigned long _code;
|
||||
static unsigned long _codeHigh;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "../accessor_app.h"
|
||||
#include "../accessor_view_manager.h"
|
||||
#include "../accessor_event.h"
|
||||
#include <callback-connector.h>
|
||||
#include "callback_connector.h"
|
||||
#include "accessor_scene_start.h"
|
||||
|
||||
void AccessorSceneStart::on_enter(AccessorApp* app) {
|
||||
|
||||
@@ -3,7 +3,6 @@ App(
|
||||
name="Battery Test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="battery_test_app",
|
||||
cdefines=["APP_BATTERY_TEST"],
|
||||
requires=[
|
||||
"gui",
|
||||
"power",
|
||||
|
||||
@@ -12,7 +12,8 @@ void battery_test_dialog_callback(DialogExResult result, void* context) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t battery_test_exit_confirm_view() {
|
||||
uint32_t battery_test_exit_confirm_view(void* context) {
|
||||
UNUSED(context);
|
||||
return BatteryTestAppViewExitDialog;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -30,7 +30,7 @@ static void locale_test_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
}
|
||||
canvas_draw_str(canvas, 0, 10, furi_string_get_cstr(tmp_string));
|
||||
|
||||
FuriHalRtcDateTime datetime;
|
||||
DateTime datetime;
|
||||
furi_hal_rtc_get_datetime(&datetime);
|
||||
|
||||
locale_format_time(tmp_string, &datetime, locale_get_time_format(), false);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <furi.h>
|
||||
#include "../minunit.h"
|
||||
#include <lfrfid/tools/bit_lib.h>
|
||||
#include <bit_lib/bit_lib.h>
|
||||
|
||||
MU_TEST(test_bit_lib_increment_index) {
|
||||
uint32_t index = 0;
|
||||
@@ -218,6 +218,178 @@ MU_TEST(test_bit_lib_get_bits_32) {
|
||||
mu_assert_int_eq(0b00001001101100011000110001100010, bit_lib_get_bits_32(value, 0, 32));
|
||||
}
|
||||
|
||||
MU_TEST(test_bit_lib_get_bits_64) {
|
||||
uint8_t value[8] = {
|
||||
0b00001001,
|
||||
0b10110001,
|
||||
0b10001100,
|
||||
0b01100010,
|
||||
0b00001001,
|
||||
0b10110001,
|
||||
0b10001100,
|
||||
0b01100010};
|
||||
mu_assert_int_eq(0b0, bit_lib_get_bits_64(value, 0, 1));
|
||||
mu_assert_int_eq(0b00, bit_lib_get_bits_64(value, 0, 2));
|
||||
mu_assert_int_eq(0b000, bit_lib_get_bits_64(value, 0, 3));
|
||||
mu_assert_int_eq(0b0000, bit_lib_get_bits_64(value, 0, 4));
|
||||
mu_assert_int_eq(0b00001, bit_lib_get_bits_64(value, 0, 5));
|
||||
mu_assert_int_eq(0b000010, bit_lib_get_bits_64(value, 0, 6));
|
||||
mu_assert_int_eq(0b0000100, bit_lib_get_bits_64(value, 0, 7));
|
||||
mu_assert_int_eq(0b00001001, bit_lib_get_bits_64(value, 0, 8));
|
||||
mu_assert_int_eq(0b000010011, bit_lib_get_bits_64(value, 0, 9));
|
||||
mu_assert_int_eq(0b0000100110, bit_lib_get_bits_64(value, 0, 10));
|
||||
mu_assert_int_eq(0b00001001101, bit_lib_get_bits_64(value, 0, 11));
|
||||
mu_assert_int_eq(0b000010011011, bit_lib_get_bits_64(value, 0, 12));
|
||||
mu_assert_int_eq(0b0000100110110, bit_lib_get_bits_64(value, 0, 13));
|
||||
mu_assert_int_eq(0b00001001101100, bit_lib_get_bits_64(value, 0, 14));
|
||||
mu_assert_int_eq(0b000010011011000, bit_lib_get_bits_64(value, 0, 15));
|
||||
mu_assert_int_eq(0b0000100110110001, bit_lib_get_bits_64(value, 0, 16));
|
||||
mu_assert_int_eq(0b00001001101100011, bit_lib_get_bits_64(value, 0, 17));
|
||||
mu_assert_int_eq(0b000010011011000110, bit_lib_get_bits_64(value, 0, 18));
|
||||
mu_assert_int_eq(0b0000100110110001100, bit_lib_get_bits_64(value, 0, 19));
|
||||
mu_assert_int_eq(0b00001001101100011000, bit_lib_get_bits_64(value, 0, 20));
|
||||
mu_assert_int_eq(0b000010011011000110001, bit_lib_get_bits_64(value, 0, 21));
|
||||
mu_assert_int_eq(0b0000100110110001100011, bit_lib_get_bits_64(value, 0, 22));
|
||||
mu_assert_int_eq(0b00001001101100011000110, bit_lib_get_bits_64(value, 0, 23));
|
||||
mu_assert_int_eq(0b000010011011000110001100, bit_lib_get_bits_64(value, 0, 24));
|
||||
mu_assert_int_eq(0b0000100110110001100011000, bit_lib_get_bits_64(value, 0, 25));
|
||||
mu_assert_int_eq(0b00001001101100011000110001, bit_lib_get_bits_64(value, 0, 26));
|
||||
mu_assert_int_eq(0b000010011011000110001100011, bit_lib_get_bits_64(value, 0, 27));
|
||||
mu_assert_int_eq(0b0000100110110001100011000110, bit_lib_get_bits_64(value, 0, 28));
|
||||
mu_assert_int_eq(0b00001001101100011000110001100, bit_lib_get_bits_64(value, 0, 29));
|
||||
mu_assert_int_eq(0b000010011011000110001100011000, bit_lib_get_bits_64(value, 0, 30));
|
||||
mu_assert_int_eq(0b0000100110110001100011000110001, bit_lib_get_bits_64(value, 0, 31));
|
||||
mu_assert_int_eq(0b00001001101100011000110001100010, bit_lib_get_bits_64(value, 0, 32));
|
||||
|
||||
uint64_t res = bit_lib_get_bits_64(value, 0, 33);
|
||||
uint64_t expected = 0b000010011011000110001100011000100;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 34);
|
||||
expected = 0b0000100110110001100011000110001000;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 35);
|
||||
expected = 0b00001001101100011000110001100010000;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 36);
|
||||
expected = 0b000010011011000110001100011000100000;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 37);
|
||||
expected = 0b0000100110110001100011000110001000001;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 38);
|
||||
expected = 0b00001001101100011000110001100010000010;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 39);
|
||||
expected = 0b000010011011000110001100011000100000100;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 40);
|
||||
expected = 0b0000100110110001100011000110001000001001;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 41);
|
||||
expected = 0b00001001101100011000110001100010000010011;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 42);
|
||||
expected = 0b000010011011000110001100011000100000100110;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 43);
|
||||
expected = 0b0000100110110001100011000110001000001001101;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 44);
|
||||
expected = 0b00001001101100011000110001100010000010011011;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 45);
|
||||
expected = 0b000010011011000110001100011000100000100110110;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 46);
|
||||
expected = 0b0000100110110001100011000110001000001001101100;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 47);
|
||||
expected = 0b00001001101100011000110001100010000010011011000;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 48);
|
||||
expected = 0b000010011011000110001100011000100000100110110001;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 49);
|
||||
expected = 0b0000100110110001100011000110001000001001101100011;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 50);
|
||||
expected = 0b00001001101100011000110001100010000010011011000110;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 51);
|
||||
expected = 0b000010011011000110001100011000100000100110110001100;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 52);
|
||||
expected = 0b0000100110110001100011000110001000001001101100011000;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 53);
|
||||
expected = 0b00001001101100011000110001100010000010011011000110001;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 54);
|
||||
expected = 0b000010011011000110001100011000100000100110110001100011;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 55);
|
||||
expected = 0b0000100110110001100011000110001000001001101100011000110;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 56);
|
||||
expected = 0b00001001101100011000110001100010000010011011000110001100;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 57);
|
||||
expected = 0b000010011011000110001100011000100000100110110001100011000;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 58);
|
||||
expected = 0b0000100110110001100011000110001000001001101100011000110001;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 59);
|
||||
expected = 0b00001001101100011000110001100010000010011011000110001100011;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 60);
|
||||
expected = 0b000010011011000110001100011000100000100110110001100011000110;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 61);
|
||||
expected = 0b0000100110110001100011000110001000001001101100011000110001100;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 62);
|
||||
expected = 0b00001001101100011000110001100010000010011011000110001100011000;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 63);
|
||||
expected = 0b000010011011000110001100011000100000100110110001100011000110001;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
|
||||
res = bit_lib_get_bits_64(value, 0, 64);
|
||||
expected = 0b0000100110110001100011000110001000001001101100011000110001100010;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
}
|
||||
|
||||
MU_TEST(test_bit_lib_test_parity_u32) {
|
||||
// test even parity
|
||||
mu_assert_int_eq(bit_lib_test_parity_32(0b00000000, BitLibParityEven), 0);
|
||||
@@ -447,6 +619,95 @@ MU_TEST(test_bit_lib_crc16) {
|
||||
mu_assert_int_eq(0x31C3, bit_lib_crc16(data, data_size, 0x1021, 0x0000, false, false, 0x0000));
|
||||
}
|
||||
|
||||
MU_TEST(test_bit_lib_num_to_bytes_be) {
|
||||
uint8_t src[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
|
||||
uint8_t dest[8];
|
||||
|
||||
bit_lib_num_to_bytes_be(0x01, 1, dest);
|
||||
mu_assert_mem_eq(src, dest, sizeof(src[0]));
|
||||
|
||||
bit_lib_num_to_bytes_be(0x0123456789ABCDEF, 4, dest);
|
||||
mu_assert_mem_eq(src + 4, dest, 4 * sizeof(src[0]));
|
||||
|
||||
bit_lib_num_to_bytes_be(0x0123456789ABCDEF, 8, dest);
|
||||
mu_assert_mem_eq(src, dest, 8 * sizeof(src[0]));
|
||||
|
||||
bit_lib_num_to_bytes_be(bit_lib_bytes_to_num_be(src, 8), 8, dest);
|
||||
mu_assert_mem_eq(src, dest, 8 * sizeof(src[0]));
|
||||
}
|
||||
|
||||
MU_TEST(test_bit_lib_num_to_bytes_le) {
|
||||
uint8_t dest[8];
|
||||
|
||||
uint8_t n2b_le_expected_1[] = {0x01};
|
||||
bit_lib_num_to_bytes_le(0x01, 1, dest);
|
||||
mu_assert_mem_eq(n2b_le_expected_1, dest, sizeof(n2b_le_expected_1[0]));
|
||||
|
||||
uint8_t n2b_le_expected_2[] = {0xEF, 0xCD, 0xAB, 0x89};
|
||||
bit_lib_num_to_bytes_le(0x0123456789ABCDEF, 4, dest);
|
||||
mu_assert_mem_eq(n2b_le_expected_2, dest, 4 * sizeof(n2b_le_expected_2[0]));
|
||||
|
||||
uint8_t n2b_le_expected_3[] = {0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01};
|
||||
bit_lib_num_to_bytes_le(0x0123456789ABCDEF, 8, dest);
|
||||
mu_assert_mem_eq(n2b_le_expected_3, dest, 8 * sizeof(n2b_le_expected_3[0]));
|
||||
|
||||
bit_lib_num_to_bytes_le(bit_lib_bytes_to_num_le(n2b_le_expected_3, 8), 8, dest);
|
||||
mu_assert_mem_eq(n2b_le_expected_3, dest, 8 * sizeof(n2b_le_expected_3[0]));
|
||||
}
|
||||
|
||||
MU_TEST(test_bit_lib_bytes_to_num_be) {
|
||||
uint8_t src[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
|
||||
uint64_t res;
|
||||
|
||||
res = bit_lib_bytes_to_num_be(src, 1);
|
||||
mu_assert_int_eq(0x01, res);
|
||||
|
||||
res = bit_lib_bytes_to_num_be(src, 4);
|
||||
mu_assert_int_eq(0x01234567, res);
|
||||
|
||||
res = bit_lib_bytes_to_num_be(src, 8);
|
||||
uint64_t expected = 0x0123456789ABCDEF;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
}
|
||||
|
||||
MU_TEST(test_bit_lib_bytes_to_num_le) {
|
||||
uint8_t src[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
|
||||
uint64_t res;
|
||||
|
||||
res = bit_lib_bytes_to_num_le(src, 1);
|
||||
mu_assert_int_eq(0x01, res);
|
||||
|
||||
res = bit_lib_bytes_to_num_le(src, 4);
|
||||
mu_assert_int_eq(0x67452301, res);
|
||||
|
||||
res = bit_lib_bytes_to_num_le(src, 8);
|
||||
uint64_t expected = 0xEFCDAB8967452301;
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
}
|
||||
|
||||
MU_TEST(test_bit_lib_bytes_to_num_bcd) {
|
||||
uint8_t src[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
|
||||
uint64_t res;
|
||||
bool is_bcd_res;
|
||||
|
||||
res = bit_lib_bytes_to_num_bcd(src, 1, &is_bcd_res);
|
||||
mu_assert_int_eq(01, res);
|
||||
mu_assert_int_eq(true, is_bcd_res);
|
||||
|
||||
res = bit_lib_bytes_to_num_bcd(src, 4, &is_bcd_res);
|
||||
mu_assert_int_eq(1234567, res);
|
||||
mu_assert_int_eq(true, is_bcd_res);
|
||||
|
||||
uint8_t digits[5] = {0x98, 0x76, 0x54, 0x32, 0x10};
|
||||
uint64_t expected = 9876543210;
|
||||
res = bit_lib_bytes_to_num_bcd(digits, 5, &is_bcd_res);
|
||||
mu_assert_mem_eq(&expected, &res, sizeof(expected));
|
||||
mu_assert_int_eq(true, is_bcd_res);
|
||||
|
||||
res = bit_lib_bytes_to_num_bcd(src, 8, &is_bcd_res);
|
||||
mu_assert_int_eq(false, is_bcd_res);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_bit_lib) {
|
||||
MU_RUN_TEST(test_bit_lib_increment_index);
|
||||
MU_RUN_TEST(test_bit_lib_is_set);
|
||||
@@ -457,6 +718,7 @@ MU_TEST_SUITE(test_bit_lib) {
|
||||
MU_RUN_TEST(test_bit_lib_get_bits);
|
||||
MU_RUN_TEST(test_bit_lib_get_bits_16);
|
||||
MU_RUN_TEST(test_bit_lib_get_bits_32);
|
||||
MU_RUN_TEST(test_bit_lib_get_bits_64);
|
||||
MU_RUN_TEST(test_bit_lib_test_parity_u32);
|
||||
MU_RUN_TEST(test_bit_lib_test_parity);
|
||||
MU_RUN_TEST(test_bit_lib_remove_bit_every_nth);
|
||||
@@ -465,6 +727,11 @@ MU_TEST_SUITE(test_bit_lib) {
|
||||
MU_RUN_TEST(test_bit_lib_get_bit_count);
|
||||
MU_RUN_TEST(test_bit_lib_reverse_16_fast);
|
||||
MU_RUN_TEST(test_bit_lib_crc16);
|
||||
MU_RUN_TEST(test_bit_lib_num_to_bytes_be);
|
||||
MU_RUN_TEST(test_bit_lib_num_to_bytes_le);
|
||||
MU_RUN_TEST(test_bit_lib_bytes_to_num_be);
|
||||
MU_RUN_TEST(test_bit_lib_bytes_to_num_le);
|
||||
MU_RUN_TEST(test_bit_lib_bytes_to_num_bcd);
|
||||
}
|
||||
|
||||
int run_minunit_test_bit_lib() {
|
||||
175
applications/debug/unit_tests/datetimelib/datetimelib_test.c
Normal file
175
applications/debug/unit_tests/datetimelib/datetimelib_test.c
Normal file
@@ -0,0 +1,175 @@
|
||||
#include <furi.h>
|
||||
#include "../minunit.h"
|
||||
|
||||
#include <datetime/datetime.h>
|
||||
|
||||
MU_TEST(test_datetime_validate_datetime_correct_min) {
|
||||
DateTime correct_min = {0, 0, 0, 1, 1, 2000, 1};
|
||||
bool result = datetime_validate_datetime(&correct_min);
|
||||
|
||||
mu_assert_int_eq(true, result);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_validate_datetime_correct_max) {
|
||||
DateTime correct_max = {23, 59, 59, 31, 12, 2099, 7};
|
||||
bool result = datetime_validate_datetime(&correct_max);
|
||||
|
||||
mu_assert_int_eq(true, result);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_validate_datetime_incorrect_second) {
|
||||
DateTime incorrect_sec = {0, 0, 60, 1, 1, 2000, 1};
|
||||
bool result = datetime_validate_datetime(&incorrect_sec);
|
||||
|
||||
mu_assert_int_eq(false, result);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_validate_datetime_incorrect_minute) {
|
||||
DateTime incorrect_min = {0, 60, 0, 1, 1, 2000, 1};
|
||||
bool result = datetime_validate_datetime(&incorrect_min);
|
||||
|
||||
mu_assert_int_eq(false, result);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_validate_datetime_incorrect_hour) {
|
||||
DateTime incorrect_hour = {24, 0, 0, 1, 1, 2000, 1};
|
||||
bool result = datetime_validate_datetime(&incorrect_hour);
|
||||
|
||||
mu_assert_int_eq(false, result);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_validate_datetime_incorrect_day_min) {
|
||||
DateTime incorrect_day_min = {0, 0, 0, 0, 1, 2000, 1};
|
||||
bool result = datetime_validate_datetime(&incorrect_day_min);
|
||||
|
||||
mu_assert_int_eq(false, result);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_validate_datetime_incorrect_day_max) {
|
||||
DateTime incorrect_day_max = {0, 0, 0, 32, 1, 2000, 1};
|
||||
bool result = datetime_validate_datetime(&incorrect_day_max);
|
||||
|
||||
mu_assert_int_eq(false, result);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_validate_datetime_incorrect_month_min) {
|
||||
DateTime incorrect_month_min = {0, 0, 0, 1, 0, 2000, 1};
|
||||
bool result = datetime_validate_datetime(&incorrect_month_min);
|
||||
|
||||
mu_assert_int_eq(false, result);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_validate_datetime_incorrect_month_max) {
|
||||
DateTime incorrect_month_max = {0, 0, 0, 1, 13, 2000, 1};
|
||||
bool result = datetime_validate_datetime(&incorrect_month_max);
|
||||
|
||||
mu_assert_int_eq(false, result);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_validate_datetime_incorrect_year_min) {
|
||||
DateTime incorrect_year_min = {0, 0, 0, 1, 1, 1999, 1};
|
||||
bool result = datetime_validate_datetime(&incorrect_year_min);
|
||||
|
||||
mu_assert_int_eq(false, result);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_validate_datetime_incorrect_year_max) {
|
||||
DateTime incorrect_year_max = {0, 0, 0, 1, 1, 2100, 1};
|
||||
bool result = datetime_validate_datetime(&incorrect_year_max);
|
||||
|
||||
mu_assert_int_eq(false, result);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_validate_datetime_incorrect_weekday_min) {
|
||||
DateTime incorrect_weekday_min = {0, 0, 0, 1, 1, 2000, 0};
|
||||
bool result = datetime_validate_datetime(&incorrect_weekday_min);
|
||||
|
||||
mu_assert_int_eq(false, result);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_validate_datetime_incorrect_weekday_max) {
|
||||
DateTime incorrect_weekday_max = {0, 0, 0, 1, 1, 2000, 8};
|
||||
bool result = datetime_validate_datetime(&incorrect_weekday_max);
|
||||
|
||||
mu_assert_int_eq(false, result);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_datetime_validate_datetime) {
|
||||
MU_RUN_TEST(test_datetime_validate_datetime_correct_min);
|
||||
MU_RUN_TEST(test_datetime_validate_datetime_correct_max);
|
||||
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_second);
|
||||
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_minute);
|
||||
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_hour);
|
||||
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_day_min);
|
||||
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_day_max);
|
||||
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_month_min);
|
||||
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_month_max);
|
||||
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_year_min);
|
||||
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_year_max);
|
||||
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_weekday_min);
|
||||
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_weekday_max);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_timestamp_to_datetime_min) {
|
||||
uint32_t test_value = 0;
|
||||
DateTime min_datetime_expected = {0, 0, 0, 1, 1, 1970, 0};
|
||||
|
||||
DateTime result = {0};
|
||||
datetime_timestamp_to_datetime(test_value, &result);
|
||||
|
||||
mu_assert_mem_eq(&min_datetime_expected, &result, sizeof(result));
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_timestamp_to_datetime_max) {
|
||||
uint32_t test_value = UINT32_MAX;
|
||||
DateTime max_datetime_expected = {6, 28, 15, 7, 2, 2106, 0};
|
||||
|
||||
DateTime result = {0};
|
||||
datetime_timestamp_to_datetime(test_value, &result);
|
||||
|
||||
mu_assert_mem_eq(&max_datetime_expected, &result, sizeof(result));
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_timestamp_to_datetime_to_timestamp) {
|
||||
uint32_t test_value = random();
|
||||
|
||||
DateTime datetime = {0};
|
||||
datetime_timestamp_to_datetime(test_value, &datetime);
|
||||
|
||||
uint32_t result = datetime_datetime_to_timestamp(&datetime);
|
||||
|
||||
mu_assert_int_eq(test_value, result);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_datetime_timestamp_to_datetime_suite) {
|
||||
MU_RUN_TEST(test_datetime_timestamp_to_datetime_min);
|
||||
MU_RUN_TEST(test_datetime_timestamp_to_datetime_max);
|
||||
MU_RUN_TEST(test_datetime_timestamp_to_datetime_to_timestamp);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_datetime_to_timestamp_min) {
|
||||
DateTime min_datetime = {0, 0, 0, 1, 1, 1970, 0};
|
||||
|
||||
uint32_t result = datetime_datetime_to_timestamp(&min_datetime);
|
||||
mu_assert_int_eq(0, result);
|
||||
}
|
||||
|
||||
MU_TEST(test_datetime_datetime_to_timestamp_max) {
|
||||
DateTime max_datetime = {6, 28, 15, 7, 2, 2106, 0};
|
||||
|
||||
uint32_t result = datetime_datetime_to_timestamp(&max_datetime);
|
||||
mu_assert_int_eq(UINT32_MAX, result);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_datetime_datetime_to_timestamp_suite) {
|
||||
MU_RUN_TEST(test_datetime_datetime_to_timestamp_min);
|
||||
MU_RUN_TEST(test_datetime_datetime_to_timestamp_max);
|
||||
}
|
||||
|
||||
int run_minunit_test_datetime() {
|
||||
MU_RUN_SUITE(test_datetime_timestamp_to_datetime_suite);
|
||||
MU_RUN_SUITE(test_datetime_datetime_to_timestamp_suite);
|
||||
MU_RUN_SUITE(test_datetime_validate_datetime);
|
||||
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void test_furi_memmgr() {
|
||||
void* ptr;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -26,9 +26,11 @@ int run_minunit_test_protocol_dict();
|
||||
int run_minunit_test_lfrfid_protocols();
|
||||
int run_minunit_test_nfc();
|
||||
int run_minunit_test_bit_lib();
|
||||
int run_minunit_test_datetime();
|
||||
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)();
|
||||
|
||||
@@ -56,10 +58,12 @@ const UnitTest unit_tests[] = {
|
||||
{.name = "protocol_dict", .entry = run_minunit_test_protocol_dict},
|
||||
{.name = "lfrfid", .entry = run_minunit_test_lfrfid_protocols},
|
||||
{.name = "bit_lib", .entry = run_minunit_test_bit_lib},
|
||||
{.name = "datetime", .entry = run_minunit_test_datetime},
|
||||
{.name = "float_tools", .entry = run_minunit_test_float_tools},
|
||||
{.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 +82,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);
|
||||
@@ -527,7 +548,8 @@ static bool subghz_device_cc1101_ext_stop_debug() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void subghz_device_cc1101_ext_capture_ISR() {
|
||||
static void subghz_device_cc1101_ext_capture_ISR(void* context) {
|
||||
UNUSED(context);
|
||||
if(!furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin)) {
|
||||
if(subghz_device_cc1101_ext->async_rx.capture_callback) {
|
||||
if(subghz_device_cc1101_ext->async_mirror_pin != NULL)
|
||||
@@ -616,57 +638,98 @@ 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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void subghz_device_cc1101_ext_async_tx_dma_isr() {
|
||||
static void subghz_device_cc1101_ext_async_tx_dma_isr(void* context) {
|
||||
UNUSED(context);
|
||||
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx);
|
||||
|
||||
#if SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL == LL_DMA_CHANNEL_3
|
||||
@@ -688,20 +751,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 +779,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 +795,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 +849,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 +859,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 +883,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;
|
||||
|
||||
11
applications/examples/example_ble_beacon/application.fam
Normal file
11
applications/examples/example_ble_beacon/application.fam
Normal file
@@ -0,0 +1,11 @@
|
||||
App(
|
||||
appid="example_ble_beacon",
|
||||
name="Example: BLE Beacon",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="ble_beacon_app",
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
fap_icon="example_ble_beacon_10px.png",
|
||||
fap_category="Examples",
|
||||
fap_icon_assets="images",
|
||||
)
|
||||
149
applications/examples/example_ble_beacon/ble_beacon_app.c
Normal file
149
applications/examples/example_ble_beacon/ble_beacon_app.c
Normal file
@@ -0,0 +1,149 @@
|
||||
#include "ble_beacon_app.h"
|
||||
|
||||
#include <extra_beacon.h>
|
||||
#include <furi_hal_version.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define TAG "ble_beacon_app"
|
||||
|
||||
static bool ble_beacon_app_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
BleBeaconApp* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool ble_beacon_app_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
BleBeaconApp* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void ble_beacon_app_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
BleBeaconApp* app = context;
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void ble_beacon_app_restore_beacon_state(BleBeaconApp* app) {
|
||||
// Restore beacon data from service
|
||||
GapExtraBeaconConfig* local_config = &app->beacon_config;
|
||||
const GapExtraBeaconConfig* config = furi_hal_bt_extra_beacon_get_config();
|
||||
if(config) {
|
||||
// We have a config, copy it
|
||||
memcpy(local_config, config, sizeof(app->beacon_config));
|
||||
} else {
|
||||
// No config, set up default values - they will stay until overriden or device is reset
|
||||
local_config->min_adv_interval_ms = 50;
|
||||
local_config->max_adv_interval_ms = 150;
|
||||
|
||||
local_config->adv_channel_map = GapAdvChannelMapAll;
|
||||
local_config->adv_power_level = GapAdvPowerLevel_0dBm;
|
||||
|
||||
local_config->address_type = GapAddressTypePublic;
|
||||
memcpy(
|
||||
local_config->address, furi_hal_version_get_ble_mac(), sizeof(local_config->address));
|
||||
// Modify MAC address to make it different from the one used by the main app
|
||||
local_config->address[0] ^= 0xFF;
|
||||
local_config->address[3] ^= 0xFF;
|
||||
|
||||
furi_check(furi_hal_bt_extra_beacon_set_config(local_config));
|
||||
}
|
||||
|
||||
// Get beacon state
|
||||
app->is_beacon_active = furi_hal_bt_extra_beacon_is_active();
|
||||
|
||||
// Restore last beacon data
|
||||
app->beacon_data_len = furi_hal_bt_extra_beacon_get_data(app->beacon_data);
|
||||
}
|
||||
|
||||
static BleBeaconApp* ble_beacon_app_alloc() {
|
||||
BleBeaconApp* app = malloc(sizeof(BleBeaconApp));
|
||||
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
app->scene_manager = scene_manager_alloc(&ble_beacon_app_scene_handlers, app);
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
|
||||
app->status_string = furi_string_alloc();
|
||||
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
app->view_dispatcher, ble_beacon_app_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, ble_beacon_app_back_event_callback);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
app->view_dispatcher, ble_beacon_app_tick_event_callback, 100);
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
|
||||
app->submenu = submenu_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BleBeaconAppViewSubmenu, submenu_get_view(app->submenu));
|
||||
|
||||
app->dialog_ex = dialog_ex_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BleBeaconAppViewDialog, dialog_ex_get_view(app->dialog_ex));
|
||||
|
||||
app->byte_input = byte_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BleBeaconAppViewByteInput, byte_input_get_view(app->byte_input));
|
||||
|
||||
ble_beacon_app_restore_beacon_state(app);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
static void ble_beacon_app_free(BleBeaconApp* app) {
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BleBeaconAppViewByteInput);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BleBeaconAppViewSubmenu);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BleBeaconAppViewDialog);
|
||||
|
||||
free(app->byte_input);
|
||||
free(app->submenu);
|
||||
free(app->dialog_ex);
|
||||
|
||||
free(app->scene_manager);
|
||||
free(app->view_dispatcher);
|
||||
|
||||
free(app->status_string);
|
||||
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_record_close(RECORD_GUI);
|
||||
app->gui = NULL;
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t ble_beacon_app(void* args) {
|
||||
UNUSED(args);
|
||||
|
||||
BleBeaconApp* app = ble_beacon_app_alloc();
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, BleBeaconAppSceneRunBeacon);
|
||||
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
|
||||
ble_beacon_app_free(app);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ble_beacon_app_update_state(BleBeaconApp* app) {
|
||||
furi_hal_bt_extra_beacon_stop();
|
||||
|
||||
furi_check(furi_hal_bt_extra_beacon_set_config(&app->beacon_config));
|
||||
|
||||
app->beacon_data_len = 0;
|
||||
while((app->beacon_data[app->beacon_data_len] != 0) &&
|
||||
(app->beacon_data_len < sizeof(app->beacon_data))) {
|
||||
app->beacon_data_len++;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "beacon_data_len: %d", app->beacon_data_len);
|
||||
|
||||
furi_check(furi_hal_bt_extra_beacon_set_data(app->beacon_data, app->beacon_data_len));
|
||||
|
||||
if(app->is_beacon_active) {
|
||||
furi_check(furi_hal_bt_extra_beacon_start());
|
||||
}
|
||||
}
|
||||
50
applications/examples/example_ble_beacon/ble_beacon_app.h
Normal file
50
applications/examples/example_ble_beacon/ble_beacon_app.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "extra_beacon.h"
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
|
||||
#include <gui/modules/widget.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/byte_input.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
|
||||
#include <rpc/rpc_app.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
#include <furi_hal_bt.h>
|
||||
|
||||
#include "scenes/scenes.h"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
Gui* gui;
|
||||
SceneManager* scene_manager;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
|
||||
Submenu* submenu;
|
||||
ByteInput* byte_input;
|
||||
DialogEx* dialog_ex;
|
||||
|
||||
FuriString* status_string;
|
||||
|
||||
GapExtraBeaconConfig beacon_config;
|
||||
uint8_t beacon_data[EXTRA_BEACON_MAX_DATA_SIZE];
|
||||
uint8_t beacon_data_len;
|
||||
bool is_beacon_active;
|
||||
} BleBeaconApp;
|
||||
|
||||
typedef enum {
|
||||
BleBeaconAppViewSubmenu,
|
||||
BleBeaconAppViewByteInput,
|
||||
BleBeaconAppViewDialog,
|
||||
} BleBeaconAppView;
|
||||
|
||||
typedef enum {
|
||||
BleBeaconAppCustomEventDataEditResult = 100,
|
||||
} BleBeaconAppCustomEvent;
|
||||
|
||||
void ble_beacon_app_update_state(BleBeaconApp* app);
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
@@ -0,0 +1,4 @@
|
||||
ADD_SCENE(ble_beacon_app, menu, Menu)
|
||||
ADD_SCENE(ble_beacon_app, input_mac_addr, InputMacAddress)
|
||||
ADD_SCENE(ble_beacon_app, input_beacon_data, InputBeaconData)
|
||||
ADD_SCENE(ble_beacon_app, run_beacon, RunBeacon)
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "../ble_beacon_app.h"
|
||||
|
||||
static void ble_beacon_app_scene_add_type_byte_input_callback(void* context) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
view_dispatcher_send_custom_event(
|
||||
ble_beacon->view_dispatcher, BleBeaconAppCustomEventDataEditResult);
|
||||
}
|
||||
|
||||
void ble_beacon_app_scene_input_beacon_data_on_enter(void* context) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
byte_input_set_header_text(ble_beacon->byte_input, "Enter beacon data");
|
||||
|
||||
byte_input_set_result_callback(
|
||||
ble_beacon->byte_input,
|
||||
ble_beacon_app_scene_add_type_byte_input_callback,
|
||||
NULL,
|
||||
context,
|
||||
ble_beacon->beacon_data,
|
||||
sizeof(ble_beacon->beacon_data));
|
||||
|
||||
view_dispatcher_switch_to_view(ble_beacon->view_dispatcher, BleBeaconAppViewByteInput);
|
||||
}
|
||||
|
||||
bool ble_beacon_app_scene_input_beacon_data_on_event(void* context, SceneManagerEvent event) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
SceneManager* scene_manager = ble_beacon->scene_manager;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == BleBeaconAppCustomEventDataEditResult) {
|
||||
ble_beacon_app_update_state(ble_beacon);
|
||||
scene_manager_previous_scene(scene_manager);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ble_beacon_app_scene_input_beacon_data_on_exit(void* context) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
|
||||
byte_input_set_result_callback(ble_beacon->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(ble_beacon->byte_input, NULL);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "../ble_beacon_app.h"
|
||||
|
||||
static void ble_beacon_app_scene_add_type_byte_input_callback(void* context) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
view_dispatcher_send_custom_event(
|
||||
ble_beacon->view_dispatcher, BleBeaconAppCustomEventDataEditResult);
|
||||
}
|
||||
|
||||
void ble_beacon_app_scene_input_mac_addr_on_enter(void* context) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
byte_input_set_header_text(ble_beacon->byte_input, "Enter MAC (reversed)");
|
||||
|
||||
byte_input_set_result_callback(
|
||||
ble_beacon->byte_input,
|
||||
ble_beacon_app_scene_add_type_byte_input_callback,
|
||||
NULL,
|
||||
context,
|
||||
ble_beacon->beacon_config.address,
|
||||
sizeof(ble_beacon->beacon_config.address));
|
||||
|
||||
view_dispatcher_switch_to_view(ble_beacon->view_dispatcher, BleBeaconAppViewByteInput);
|
||||
}
|
||||
|
||||
bool ble_beacon_app_scene_input_mac_addr_on_event(void* context, SceneManagerEvent event) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
SceneManager* scene_manager = ble_beacon->scene_manager;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == BleBeaconAppCustomEventDataEditResult) {
|
||||
ble_beacon_app_update_state(ble_beacon);
|
||||
scene_manager_previous_scene(scene_manager);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ble_beacon_app_scene_input_mac_addr_on_exit(void* context) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
|
||||
byte_input_set_result_callback(ble_beacon->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||
byte_input_set_header_text(ble_beacon->byte_input, NULL);
|
||||
}
|
||||
56
applications/examples/example_ble_beacon/scenes/scene_menu.c
Normal file
56
applications/examples/example_ble_beacon/scenes/scene_menu.c
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "../ble_beacon_app.h"
|
||||
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexSetMac,
|
||||
SubmenuIndexSetData,
|
||||
};
|
||||
|
||||
static void ble_beacon_app_scene_menu_submenu_callback(void* context, uint32_t index) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
view_dispatcher_send_custom_event(ble_beacon->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void ble_beacon_app_scene_menu_on_enter(void* context) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
Submenu* submenu = ble_beacon->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Set MAC",
|
||||
SubmenuIndexSetMac,
|
||||
ble_beacon_app_scene_menu_submenu_callback,
|
||||
ble_beacon);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Set Data",
|
||||
SubmenuIndexSetData,
|
||||
ble_beacon_app_scene_menu_submenu_callback,
|
||||
ble_beacon);
|
||||
|
||||
view_dispatcher_switch_to_view(ble_beacon->view_dispatcher, BleBeaconAppViewSubmenu);
|
||||
}
|
||||
|
||||
bool ble_beacon_app_scene_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
SceneManager* scene_manager = ble_beacon->scene_manager;
|
||||
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
const uint32_t submenu_index = event.event;
|
||||
if(submenu_index == SubmenuIndexSetMac) {
|
||||
scene_manager_next_scene(scene_manager, BleBeaconAppSceneInputMacAddress);
|
||||
consumed = true;
|
||||
} else if(submenu_index == SubmenuIndexSetData) {
|
||||
scene_manager_next_scene(scene_manager, BleBeaconAppSceneInputBeaconData);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void ble_beacon_app_scene_menu_on_exit(void* context) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
submenu_reset(ble_beacon->submenu);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "../ble_beacon_app.h"
|
||||
#include <example_ble_beacon_icons.h>
|
||||
|
||||
static void
|
||||
ble_beacon_app_scene_run_beacon_confirm_dialog_callback(DialogExResult result, void* context) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
|
||||
view_dispatcher_send_custom_event(ble_beacon->view_dispatcher, result);
|
||||
}
|
||||
|
||||
static void update_status_text(BleBeaconApp* ble_beacon) {
|
||||
DialogEx* dialog_ex = ble_beacon->dialog_ex;
|
||||
|
||||
dialog_ex_set_header(dialog_ex, "BLE Beacon Demo", 64, 0, AlignCenter, AlignTop);
|
||||
|
||||
FuriString* status = ble_beacon->status_string;
|
||||
|
||||
furi_string_reset(status);
|
||||
|
||||
furi_string_cat_str(status, "Status: ");
|
||||
if(ble_beacon->is_beacon_active) {
|
||||
furi_string_cat_str(status, "Running\n");
|
||||
} else {
|
||||
furi_string_cat_str(status, "Stopped\n");
|
||||
}
|
||||
|
||||
// Output MAC in reverse order
|
||||
for(int i = sizeof(ble_beacon->beacon_config.address) - 1; i >= 0; i--) {
|
||||
furi_string_cat_printf(status, "%02X", ble_beacon->beacon_config.address[i]);
|
||||
if(i > 0) {
|
||||
furi_string_cat_str(status, ":");
|
||||
}
|
||||
}
|
||||
|
||||
furi_string_cat_printf(status, "\nData length: %d", ble_beacon->beacon_data_len);
|
||||
|
||||
dialog_ex_set_text(dialog_ex, furi_string_get_cstr(status), 0, 29, AlignLeft, AlignCenter);
|
||||
|
||||
dialog_ex_set_icon(dialog_ex, 93, 20, &I_lighthouse_35x44);
|
||||
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Config");
|
||||
|
||||
dialog_ex_set_center_button_text(dialog_ex, ble_beacon->is_beacon_active ? "Stop" : "Start");
|
||||
|
||||
dialog_ex_set_result_callback(
|
||||
dialog_ex, ble_beacon_app_scene_run_beacon_confirm_dialog_callback);
|
||||
dialog_ex_set_context(dialog_ex, ble_beacon);
|
||||
}
|
||||
|
||||
void ble_beacon_app_scene_run_beacon_on_enter(void* context) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
|
||||
update_status_text(ble_beacon);
|
||||
|
||||
view_dispatcher_switch_to_view(ble_beacon->view_dispatcher, BleBeaconAppViewDialog);
|
||||
}
|
||||
|
||||
bool ble_beacon_app_scene_run_beacon_on_event(void* context, SceneManagerEvent event) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
SceneManager* scene_manager = ble_beacon->scene_manager;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == DialogExResultLeft) {
|
||||
scene_manager_next_scene(scene_manager, BleBeaconAppSceneMenu);
|
||||
return true;
|
||||
} else if(event.event == DialogExResultCenter) {
|
||||
ble_beacon->is_beacon_active = !ble_beacon->is_beacon_active;
|
||||
ble_beacon_app_update_state(ble_beacon);
|
||||
update_status_text(ble_beacon);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ble_beacon_app_scene_run_beacon_on_exit(void* context) {
|
||||
BleBeaconApp* ble_beacon = context;
|
||||
UNUSED(ble_beacon);
|
||||
}
|
||||
30
applications/examples/example_ble_beacon/scenes/scenes.c
Normal file
30
applications/examples/example_ble_beacon/scenes/scenes.c
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "scenes.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const ble_beacon_app_on_enter_handlers[])(void*) = {
|
||||
#include "scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||
bool (*const ble_beacon_app_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||
void (*const ble_beacon_app_on_exit_handlers[])(void* context) = {
|
||||
#include "scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers ble_beacon_app_scene_handlers = {
|
||||
.on_enter_handlers = ble_beacon_app_on_enter_handlers,
|
||||
.on_event_handlers = ble_beacon_app_on_event_handlers,
|
||||
.on_exit_handlers = ble_beacon_app_on_exit_handlers,
|
||||
.scene_num = BleBeaconAppSceneNum,
|
||||
};
|
||||
29
applications/examples/example_ble_beacon/scenes/scenes.h
Normal file
29
applications/examples/example_ble_beacon/scenes/scenes.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) BleBeaconAppScene##id,
|
||||
typedef enum {
|
||||
#include "scene_config.h"
|
||||
BleBeaconAppSceneNum,
|
||||
} BleBeaconAppScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers ble_beacon_app_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) \
|
||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||
#include "scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||
#include "scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -1,9 +1,9 @@
|
||||
App(
|
||||
appid="example_custom_font",
|
||||
name="Example: custom font",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="example_custom_font_main",
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
fap_category="Debug",
|
||||
fap_category="Examples",
|
||||
)
|
||||
@@ -18,8 +18,8 @@ constexpr HashtableApiInterface applicaton_hashtable_api_interface{
|
||||
.resolver_callback = &elf_resolve_from_hashtable,
|
||||
},
|
||||
/* pointers to application's API table boundaries */
|
||||
.table_cbegin = app_api_table.cbegin(),
|
||||
.table_cend = app_api_table.cend(),
|
||||
app_api_table.cbegin(),
|
||||
app_api_table.cend(),
|
||||
};
|
||||
|
||||
/* Casting to generic resolver to use in Composite API resolver */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "archive_files.h"
|
||||
|
||||
typedef enum {
|
||||
ArchiveAppTypeU2f,
|
||||
ArchiveAppTypeUnknown,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,9 +32,11 @@ static const char* known_ext[] = {
|
||||
[ArchiveFileTypeBadUsb] = ".txt",
|
||||
[ArchiveFileTypeU2f] = "?",
|
||||
[ArchiveFileTypeApplication] = ".fap",
|
||||
[ArchiveFileTypeJS] = ".js",
|
||||
[ArchiveFileTypeUpdateManifest] = ".fuf",
|
||||
[ArchiveFileTypeFolder] = "?",
|
||||
[ArchiveFileTypeUnknown] = "*",
|
||||
[ArchiveFileTypeAppOrJs] = ".fap|.js",
|
||||
};
|
||||
|
||||
static const ArchiveFileTypeEnum known_type[] = {
|
||||
@@ -47,7 +49,7 @@ static const ArchiveFileTypeEnum known_type[] = {
|
||||
[ArchiveTabInfrared] = ArchiveFileTypeInfrared,
|
||||
[ArchiveTabBadUsb] = ArchiveFileTypeBadUsb,
|
||||
[ArchiveTabU2f] = ArchiveFileTypeU2f,
|
||||
[ArchiveTabApplications] = ArchiveFileTypeApplication,
|
||||
[ArchiveTabApplications] = ArchiveFileTypeAppOrJs,
|
||||
[ArchiveTabInternal] = ArchiveFileTypeUnknown,
|
||||
[ArchiveTabBrowser] = ArchiveFileTypeUnknown,
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -15,7 +15,7 @@ void archive_set_file_type(ArchiveFile_t* file, const char* path, bool is_folder
|
||||
} else {
|
||||
for(size_t i = 0; i < COUNT_OF(known_ext); i++) {
|
||||
if((known_ext[i][0] == '?') || (known_ext[i][0] == '*')) continue;
|
||||
if(furi_string_search(file->path, known_ext[i], 0) != FURI_STRING_FAILURE) {
|
||||
if(furi_string_end_with(file->path, known_ext[i])) {
|
||||
if(i == ArchiveFileTypeBadUsb) {
|
||||
if(furi_string_search(
|
||||
file->path, archive_get_default_path(ArchiveTabBadUsb)) == 0) {
|
||||
|
||||
@@ -19,8 +19,10 @@ typedef enum {
|
||||
ArchiveFileTypeU2f,
|
||||
ArchiveFileTypeApplication,
|
||||
ArchiveFileTypeUpdateManifest,
|
||||
ArchiveFileTypeJS,
|
||||
ArchiveFileTypeFolder,
|
||||
ArchiveFileTypeUnknown,
|
||||
ArchiveFileTypeAppOrJs,
|
||||
ArchiveFileTypeLoading,
|
||||
} ArchiveFileTypeEnum;
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ static const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) {
|
||||
return "U2F";
|
||||
case ArchiveFileTypeUpdateManifest:
|
||||
return "UpdaterApp";
|
||||
case ArchiveFileTypeJS:
|
||||
return "JS Runner";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@@ -244,6 +246,7 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
||||
break;
|
||||
case ArchiveBrowserEventFileMenuDelete:
|
||||
if(archive_get_tab(browser) != ArchiveTabFavorites) {
|
||||
archive_show_file_menu(browser, false);
|
||||
scene_manager_set_scene_state(
|
||||
archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH);
|
||||
scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneDelete);
|
||||
|
||||
@@ -26,6 +26,12 @@ void archive_scene_delete_on_enter(void* context) {
|
||||
filename = furi_string_alloc();
|
||||
|
||||
ArchiveFile_t* current = archive_get_current_file(app->browser);
|
||||
|
||||
FuriString* filename_no_ext = furi_string_alloc();
|
||||
path_extract_filename(current->path, filename_no_ext, true);
|
||||
strlcpy(app->text_store, furi_string_get_cstr(filename_no_ext), MAX_NAME_LEN);
|
||||
furi_string_free(filename_no_ext);
|
||||
|
||||
path_extract_filename(current->path, filename, false);
|
||||
|
||||
char delete_str[64];
|
||||
|
||||
@@ -38,6 +38,8 @@ static const Icon* ArchiveItemIcons[] = {
|
||||
[ArchiveFileTypeFolder] = &I_dir_10px,
|
||||
[ArchiveFileTypeUnknown] = &I_unknown_10px,
|
||||
[ArchiveFileTypeLoading] = &I_loading_10px,
|
||||
[ArchiveFileTypeJS] = &I_js_script_10px,
|
||||
[ArchiveFileTypeAppOrJs] = &I_unknown_10px,
|
||||
};
|
||||
|
||||
void archive_browser_set_callback(
|
||||
@@ -585,6 +587,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.
@@ -24,9 +24,9 @@ static void clock_render_callback(Canvas* const canvas, void* ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
FuriHalRtcDateTime curr_dt;
|
||||
DateTime curr_dt;
|
||||
furi_hal_rtc_get_datetime(&curr_dt);
|
||||
uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
|
||||
uint32_t curr_ts = datetime_datetime_to_timestamp(&curr_dt);
|
||||
|
||||
char time_string[TIME_LEN];
|
||||
char date_string[DATE_LEN];
|
||||
@@ -191,9 +191,9 @@ int32_t clock_app(void* p) {
|
||||
case InputKeyOk:;
|
||||
// START/STOP TIMER
|
||||
|
||||
FuriHalRtcDateTime curr_dt;
|
||||
DateTime curr_dt;
|
||||
furi_hal_rtc_get_datetime(&curr_dt);
|
||||
uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
|
||||
uint32_t curr_ts = datetime_datetime_to_timestamp(&curr_dt);
|
||||
|
||||
if(plugin_state->timer_running) {
|
||||
// Update stopped seconds
|
||||
|
||||
@@ -30,7 +30,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
LocaleDateFormat date_format;
|
||||
LocaleTimeFormat time_format;
|
||||
FuriHalRtcDateTime datetime;
|
||||
DateTime datetime;
|
||||
FuriMutex* mutex;
|
||||
FuriMessageQueue* event_queue;
|
||||
uint32_t timer_start_timestamp;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -123,7 +123,7 @@ struct InfraredApp {
|
||||
InfraredProgressView* progress; /**< Custom view for showing brute force progress. */
|
||||
|
||||
FuriString* file_path; /**< Full path to the currently loaded file. */
|
||||
FuriString* button_name; /** Name of the button requested in RPC mode. */
|
||||
FuriString* button_name; /**< Name of the button requested in RPC mode. */
|
||||
/** Arbitrary text storage for various inputs. */
|
||||
char text_store[INFRARED_TEXT_STORE_NUM][INFRARED_TEXT_STORE_SIZE + 1];
|
||||
InfraredAppState app_state; /**< Application state. */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user