Compare commits
577 Commits
v0.1.0
...
d967be0245
| Author | SHA1 | Date | |
|---|---|---|---|
| d967be0245 | |||
| b040f336d4 | |||
| 1bf1ea7596 | |||
|
|
29303f7ec9 | ||
|
|
c6b06d4be6 | ||
|
|
c9b2f9dd23 | ||
|
|
40590d174f | ||
|
|
780fb72bba | ||
|
|
e9977a26e4 | ||
|
|
1d97f0ce84 | ||
|
|
895b6e89c5 | ||
|
|
9114bc4c49 | ||
|
|
9eae0cd253 | ||
|
|
37f096d3b5 | ||
|
|
6bf549b104 | ||
|
|
3054db9d9b | ||
|
|
69e7e2debe | ||
|
|
6083cca72e | ||
|
|
d17ea4da0f | ||
|
|
2ea0066536 | ||
|
|
3d23211c1e | ||
|
|
1769680d9e | ||
|
|
92351c0b92 | ||
|
|
0f6c31386b | ||
|
|
a9009a8cee | ||
|
|
31e1d51dbd | ||
|
|
41819f2fd6 | ||
|
|
17043f634f | ||
|
|
e1c5761df9 | ||
|
|
fbaae21011 | ||
|
|
fa2064b957 | ||
|
|
21a194f43d | ||
|
|
b255402659 | ||
|
|
dfabfbb921 | ||
|
|
3b36a70c9a | ||
|
|
d1386a8e9d | ||
|
|
67b92b7f56 | ||
|
|
a1f8516e60 | ||
|
|
cf52021d38 | ||
|
|
b78c9387a6 | ||
|
|
b748d99437 | ||
|
|
9a33fc0a69 | ||
|
|
4cddc01f22 | ||
|
|
1d80b5fff7 | ||
|
|
140cf07173 | ||
|
|
1e3a82f439 | ||
|
|
c90794e9f5 | ||
|
|
03c723c73d | ||
|
|
bad2ffdd07 | ||
|
|
eed39c9cfb | ||
|
|
7bd6d1d815 | ||
|
|
bb7fcd5c4d | ||
|
|
9b8e00c7fa | ||
|
|
b97825d552 | ||
|
|
085b5aed16 | ||
|
|
7f43624824 | ||
|
|
1ed0000819 | ||
|
|
3b79636d00 | ||
|
|
5a4b932a37 | ||
|
|
dd2ae149ad | ||
|
|
0f5d0a8889 | ||
|
|
3750ae6953 | ||
|
|
5be993f9eb | ||
|
|
57c43ce515 | ||
|
|
159ffa76fd | ||
|
|
1ac3d30d84 | ||
|
|
631ef6ba59 | ||
|
|
27393e47c3 | ||
|
|
bd47772c04 | ||
|
|
f3871388ce | ||
|
|
62874bebf4 | ||
|
|
2ca368305c | ||
|
|
f697ae6f11 | ||
|
|
ef6dd35977 | ||
|
|
ccf21b4eab | ||
|
|
e99c6124e7 | ||
|
|
5721bd74d7 | ||
|
|
ff443ca488 | ||
|
|
93e0a5d066 | ||
|
|
150c2ef26d | ||
|
|
4d81fcac26 | ||
|
|
a3bbdf1c16 | ||
|
|
39df2e7b54 | ||
|
|
6169f68119 | ||
|
|
e38e53bac0 | ||
|
|
b38a4d5d46 | ||
|
|
96412624d9 | ||
|
|
f8876bba87 | ||
|
|
68b5773827 | ||
|
|
74659901c0 | ||
|
|
73ede2838c | ||
|
|
273a86532b | ||
|
|
05e13dafed | ||
|
|
6af97d2691 | ||
|
|
f9fb78feed | ||
|
|
96dbbe0919 | ||
|
|
0ef66af342 | ||
|
|
7ed48bf9fc | ||
|
|
1335b84391 | ||
|
|
e2794d5f84 | ||
|
|
e7f35c584b | ||
|
|
1e49c3ff6f | ||
|
|
e256ac8e46 | ||
|
|
9c6e9d1525 | ||
|
|
41985e5743 | ||
|
|
f1e41f7cc1 | ||
|
|
6135e4f7b0 | ||
|
|
af8c7417b3 | ||
|
|
babdb1287f | ||
|
|
4532c88873 | ||
|
|
bc1b83d931 | ||
|
|
87ad0798e4 | ||
|
|
a80032d46c | ||
|
|
4dae304f51 | ||
|
|
9b7d34fa65 | ||
|
|
c0cc602c9a | ||
|
|
e5f98ff41f | ||
|
|
bc74c21599 | ||
|
|
3836ad20b7 | ||
|
|
b073290989 | ||
|
|
43c9d0db10 | ||
|
|
c40bdd68af | ||
|
|
620e457eb6 | ||
|
|
5c4da6e82b | ||
|
|
8c636e44f7 | ||
|
|
07e9aa1ded | ||
|
|
27a7faaab7 | ||
|
|
752768b1e2 | ||
|
|
f7c28eeea4 | ||
|
|
113b2fc31d | ||
|
|
86924d8785 | ||
|
|
219415174e | ||
|
|
8999cb9091 | ||
|
|
8337ac121e | ||
|
|
d332315e7a | ||
|
|
882f58bae4 | ||
|
|
2c86a36fe0 | ||
|
|
b984519546 | ||
|
|
7b0f6b22c1 | ||
|
|
3b8a4f1b60 | ||
|
|
edd2c0542b | ||
|
|
dbc905dca3 | ||
|
|
461e4c6df0 | ||
|
|
85a687fc56 | ||
|
|
c5361a4738 | ||
|
|
42c18859f3 | ||
|
|
1ba6834391 | ||
|
|
376a4db4cb | ||
|
|
775e06b259 | ||
|
|
3ba3c2a2be | ||
|
|
76ad89e2f1 | ||
|
|
2a7f1b52a0 | ||
|
|
bd75b54dce | ||
|
|
070f2afd66 | ||
|
|
0e84e08a18 | ||
|
|
4c1ab20ba4 | ||
|
|
63ac7b365d | ||
|
|
c51bf0b7db | ||
|
|
201db4668e | ||
|
|
250e67ab1f | ||
|
|
2e30d34021 | ||
|
|
2882eaa0c2 | ||
|
|
8faffedddc | ||
|
|
5260930919 | ||
|
|
24832d3277 | ||
|
|
8f338a6b30 | ||
|
|
3d3f3700a8 | ||
|
|
eae64d34e2 | ||
|
|
a27e76bfa7 | ||
|
|
b050662a5c | ||
|
|
f69b4bea4f | ||
|
|
4e3b081c60 | ||
|
|
a2de77ce30 | ||
|
|
5de98ed56c | ||
|
|
ff8ac6036c | ||
|
|
c3f12ab247 | ||
|
|
dfcb36361e | ||
|
|
c4a3e9e2ee | ||
|
|
fd1afea1bc | ||
|
|
65cf460691 | ||
|
|
046f7df7d1 | ||
|
|
8323bafd4c | ||
|
|
6b92aac1da | ||
|
|
3113b387c3 | ||
|
|
6d2b653f61 | ||
|
|
47daefe675 | ||
|
|
e8c18f4e66 | ||
|
|
76a82768fe | ||
|
|
8be5aeab59 | ||
|
|
fbfd96ecdb | ||
|
|
dee20c859c | ||
|
|
ce0a88147b | ||
|
|
7f62f1e965 | ||
|
|
b51501fb21 | ||
|
|
72ab64461c | ||
|
|
26b393e059 | ||
|
|
bc328657aa | ||
|
|
c579219427 | ||
|
|
3413d70210 | ||
|
|
8bbc7e13fb | ||
|
|
f1ecb312c7 | ||
|
|
3407891e9c | ||
|
|
8f447a4a72 | ||
|
|
8ace11e462 | ||
|
|
949dfe7266 | ||
|
|
f0d490aef9 | ||
|
|
bdedae981a | ||
|
|
9e0750c9d3 | ||
|
|
9a3e512b1b | ||
|
|
861e741030 | ||
|
|
a3e7e21d45 | ||
|
|
86db2fcf61 | ||
|
|
fcd72e013a | ||
|
|
2450f8c64b | ||
|
|
676a9b1686 | ||
|
|
b10db63c74 | ||
|
|
4b25ef7516 | ||
|
|
de0d19cda6 | ||
|
|
c55386af0e | ||
|
|
33fe1c7a54 | ||
|
|
bf6d05e92a | ||
|
|
b6113d8d2b | ||
|
|
bc31154035 | ||
|
|
edfe0329bf | ||
|
|
1e11dd776a | ||
|
|
028526d22d | ||
|
|
7ac2d854f2 | ||
|
|
279c81e431 | ||
|
|
4e319b40ed | ||
|
|
d082b39980 | ||
|
|
277402f577 | ||
|
|
9e95c507b1 | ||
|
|
7440fc6f46 | ||
|
|
a24028f674 | ||
|
|
00913b013f | ||
|
|
447d08d613 | ||
|
|
d4f7736b2d | ||
|
|
60f72fffdf | ||
|
|
77af9c1cba | ||
|
|
1b2414337f | ||
|
|
d41f1f2a4d | ||
|
|
f9967ff990 | ||
|
|
db0ab41ea4 | ||
|
|
da95cc30d3 | ||
|
|
6b3001573e | ||
|
|
b85f6f8c3f | ||
|
|
d036ac9fba | ||
|
|
f63a114371 | ||
|
|
8cb59661ac | ||
|
|
fc1da609f2 | ||
|
|
c6566323fd | ||
|
|
30e1533ad9 | ||
|
|
71dfea1904 | ||
|
|
4fa7457423 | ||
|
|
9583bb35f5 | ||
|
|
e806c4db3a | ||
|
|
665ab22de5 | ||
|
|
ec4e946643 | ||
|
|
9e4bbe3e36 | ||
|
|
1172c1a852 | ||
|
|
8a4392bb22 | ||
|
|
a79a2d60d3 | ||
|
|
9553ff66a3 | ||
|
|
79c6f05291 | ||
|
|
3e691de24a | ||
|
|
303def49cb | ||
|
|
18653781d5 | ||
|
|
2a75bdbeda | ||
|
|
4a6926eb6c | ||
|
|
3dc4007fa7 | ||
|
|
9c3833d66c | ||
|
|
41966f33c2 | ||
|
|
50fea2a8f0 | ||
|
|
05cb7f7947 | ||
|
|
5b6b80e3cd | ||
|
|
2c59af8399 | ||
|
|
b404f9fa42 | ||
|
|
8dc8340ce4 | ||
|
|
30f08a145e | ||
|
|
d3d140fa60 | ||
|
|
5f8e687e68 | ||
|
|
fab640901d | ||
|
|
9a053fb6ff | ||
|
|
24e4b0b376 | ||
|
|
b8eee999e2 | ||
|
|
7fe9a114b7 | ||
|
|
05b2fb4fcb | ||
|
|
830d8762cd | ||
|
|
3f81666369 | ||
|
|
d40f4003b5 | ||
|
|
1585e425ce | ||
|
|
bbc7613079 | ||
|
|
ec54745174 | ||
|
|
a29453de12 | ||
|
|
db5bf4fc46 | ||
|
|
9495e3418c | ||
|
|
83573a743b | ||
|
|
f5dcd82747 | ||
|
|
070ec2f48f | ||
|
|
96c7fdc02c | ||
|
|
dfde2d8a62 | ||
|
|
a3f57114da | ||
|
|
904af10914 | ||
|
|
9b5013a694 | ||
|
|
922adfd3d4 | ||
|
|
362144033b | ||
|
|
caf9a579d3 | ||
|
|
cb40fdcdbe | ||
|
|
ef15e754c9 | ||
|
|
d55568c146 | ||
|
|
e134863db1 | ||
|
|
c37ae51dd3 | ||
|
|
4fc2ff43c1 | ||
|
|
607f13d935 | ||
|
|
44c1a3f695 | ||
|
|
d30decfbc8 | ||
|
|
705b2f794e | ||
|
|
4958690d9e | ||
|
|
d7749d3a24 | ||
|
|
73e07a594f | ||
|
|
755c2ef400 | ||
|
|
3f588e970a | ||
|
|
3264807e77 | ||
|
|
01225d4648 | ||
|
|
48aa809c98 | ||
|
|
4a722d4069 | ||
|
|
07aca2a0e7 | ||
|
|
10000d9b6c | ||
|
|
f0e247f31e | ||
|
|
593dec5e88 | ||
|
|
c45b86c993 | ||
|
|
02f01f2199 | ||
|
|
88b1adc2d6 | ||
|
|
a0a0e6775b | ||
|
|
4096253694 | ||
|
|
33ba44ebda | ||
|
|
9b4cf2a92b | ||
|
|
e6b915d8e3 | ||
|
|
bb73fb5f55 | ||
|
|
10c5945afb | ||
|
|
0bd613d556 | ||
|
|
aae2f65b9e | ||
|
|
d02197474e | ||
|
|
41b37e9c24 | ||
|
|
b03400fac2 | ||
|
|
3e808f7b6b | ||
|
|
1e3a8971fb | ||
|
|
d8c0105b97 | ||
|
|
b3689cbac8 | ||
|
|
1b5d6472f7 | ||
|
|
e9511c507a | ||
|
|
365f64ded5 | ||
|
|
3601fa63d8 | ||
|
|
5d00ddf516 | ||
|
|
0051453cad | ||
|
|
7920ea2dda | ||
|
|
9416e45a75 | ||
|
|
98a65c81af | ||
|
|
8e1f06e79b | ||
|
|
58a09f453d | ||
|
|
7dc69982b6 | ||
|
|
46e4041ed8 | ||
|
|
0e129130b1 | ||
|
|
33c9868f90 | ||
|
|
fb04b1830e | ||
|
|
9509194bd0 | ||
|
|
60322a243a | ||
|
|
4ed7067537 | ||
|
|
69086e8fba | ||
|
|
a4b63bb037 | ||
|
|
5ffb2f6619 | ||
|
|
41eaf9b9e4 | ||
|
|
28bb777399 | ||
|
|
f375a35cc8 | ||
|
|
1d41d84083 | ||
|
|
357be177fc | ||
|
|
23c3335de8 | ||
|
|
963b164783 | ||
|
|
0c22a02641 | ||
|
|
10cb5c2c76 | ||
|
|
6d36c9ef7b | ||
|
|
aed97a5e92 | ||
|
|
b6008fc9bb | ||
|
|
f9359679ad | ||
|
|
052d7be1a9 | ||
|
|
ead577a116 | ||
|
|
ccf7d972ce | ||
|
|
b2df9e6a8b | ||
|
|
e37014ebd6 | ||
|
|
c96ef2ff7a | ||
|
|
c19dd0d87e | ||
|
|
02f972bd5f | ||
|
|
15facd8866 | ||
|
|
cf584c3bd6 | ||
|
|
4744351964 | ||
|
|
31b753ab5a | ||
|
|
3cb944dde2 | ||
|
|
1b4265f522 | ||
|
|
5d16338faa | ||
|
|
673b8233e5 | ||
|
|
0dd2e2583b | ||
|
|
c19f24cbfd | ||
|
|
cfb6830d95 | ||
|
|
27dea356cf | ||
|
|
352a425c4f | ||
|
|
4beaa79d02 | ||
|
|
e54eab83f2 | ||
|
|
e74a491b4a | ||
|
|
a9415c1db7 | ||
|
|
a83959ab5f | ||
|
|
b1896002e5 | ||
|
|
cc39de9b04 | ||
|
|
a286b5d067 | ||
|
|
f071f57abf | ||
|
|
0e0fe334cd | ||
|
|
23410c618d | ||
|
|
b44898f08d | ||
|
|
165f356439 | ||
|
|
1d0df2936b | ||
|
|
1684d63e04 | ||
|
|
cf5dfb43d6 | ||
|
|
ded6638ef6 | ||
|
|
a8228851d9 | ||
|
|
633289def6 | ||
|
|
f4ff13d6b7 | ||
|
|
0493ec2245 | ||
|
|
4c6bbb8aae | ||
|
|
b625f636be | ||
|
|
3bfd62d075 | ||
|
|
b405adb359 | ||
|
|
accf37de39 | ||
|
|
582eed3be8 | ||
|
|
35d5ec03a3 | ||
|
|
737c627d44 | ||
|
|
84a3120c7f | ||
|
|
99b9ed1181 | ||
|
|
0d636a3285 | ||
|
|
79ccd47f71 | ||
|
|
3ffc70abe5 | ||
|
|
f4f2eda481 | ||
|
|
f4b2c74b0e | ||
|
|
111e5a66b6 | ||
|
|
b90723130d | ||
|
|
e6179761d4 | ||
|
|
b371fd3468 | ||
|
|
c8fccdbb47 | ||
|
|
4876401809 | ||
|
|
45af7c188a | ||
|
|
236e9ccda6 | ||
|
|
94e8b9f87e | ||
|
|
c9580d6627 | ||
|
|
87929373e2 | ||
|
|
4e2aec9ced | ||
|
|
fa7957f5e2 | ||
|
|
4f15805246 | ||
|
|
cf67c815e9 | ||
|
|
5533dc807f | ||
|
|
ac2aabe6e3 | ||
|
|
c6a428ddd4 | ||
|
|
a83a845d5a | ||
|
|
c91b188f96 | ||
|
|
53a6f4593e | ||
|
|
0dda769d0f | ||
|
|
848df066c4 | ||
|
|
b4005d8bad | ||
|
|
34c0df2761 | ||
|
|
cedfc2c8db | ||
|
|
c9fe63ec7b | ||
|
|
2fedcb61b5 | ||
|
|
272b033253 | ||
|
|
cae03d54d6 | ||
|
|
e70f1a591f | ||
|
|
0e768ac6e4 | ||
|
|
bc056eaca2 | ||
|
|
a6ad84a3b8 | ||
|
|
a5b953dc80 | ||
|
|
d446b05387 | ||
|
|
e864e5ef24 | ||
|
|
e669507759 | ||
|
|
e50c04cbe1 | ||
|
|
56dd57f4a0 | ||
|
|
f2abb564c7 | ||
|
|
4e7abb2350 | ||
|
|
540e499389 | ||
|
|
191a2bdd2a | ||
|
|
4d1c8357b4 | ||
|
|
85b5b1df91 | ||
|
|
c3e2c105d4 | ||
|
|
dba602a081 | ||
|
|
c3f2ce57f0 | ||
|
|
bbf8e0b6b6 | ||
|
|
03ab020dc8 | ||
|
|
9c1f3225a6 | ||
|
|
f72dd3b7d7 | ||
|
|
48f6210607 | ||
|
|
6f9be2b139 | ||
|
|
3217525873 | ||
|
|
e26972bd2f | ||
|
|
bf31533306 | ||
|
|
0ca0577667 | ||
|
|
0e797e7e04 | ||
|
|
a661ef3a3f | ||
|
|
17dc1dcf8c | ||
|
|
4c27aa57b1 | ||
|
|
a21c07fa03 | ||
|
|
bdffa7ef53 | ||
|
|
22d40825bb | ||
|
|
50f26f546c | ||
|
|
9c7ea46ec3 | ||
|
|
5b4cf53d8a | ||
|
|
79a701a4d4 | ||
|
|
81897e634c | ||
|
|
3e11da4dd4 | ||
|
|
12aa7fef04 | ||
|
|
1ea6420bbc | ||
|
|
f3f1f36525 | ||
|
|
dee9a98cc3 | ||
|
|
3345ce3fb9 | ||
|
|
de70583838 | ||
|
|
a43a737004 | ||
|
|
1f6899354f | ||
|
|
9110a0c47e | ||
|
|
b549790798 | ||
|
|
5df430f3be | ||
|
|
f3e8bcd74a | ||
|
|
4b050e11cf | ||
|
|
7ddbc09564 | ||
|
|
d3d62f80fd | ||
|
|
bc7dbe6eec | ||
|
|
e625f55353 | ||
|
|
aeebff9d5d | ||
|
|
9a3c077ef1 | ||
|
|
91ae692058 | ||
|
|
ad590d1eb2 | ||
|
|
8b00358901 | ||
|
|
bf4d8bb9be | ||
|
|
157dd2f407 | ||
|
|
1dc47878d4 | ||
|
|
36e4b6fd45 | ||
|
|
36d9a6e7e4 | ||
|
|
b7cceed4d3 | ||
|
|
694c06e7f5 | ||
|
|
12338747bf | ||
|
|
f4f9788f68 | ||
|
|
b9cdcad262 | ||
|
|
e4cd2ddec8 | ||
|
|
1477649a50 | ||
|
|
2e80469ab3 | ||
|
|
ccf63a4cdb | ||
|
|
b464871f73 | ||
|
|
e44834a95e | ||
|
|
4efefc5c6c | ||
|
|
dfd852b2db | ||
|
|
afa7141ceb | ||
|
|
ed76b23c69 | ||
|
|
a469a466ff | ||
|
|
589d3ef4d8 | ||
|
|
5aba2eb4a1 | ||
|
|
b7df8d7b37 | ||
|
|
61554e6c7e | ||
|
|
d8cc61bc0e | ||
|
|
4b6e3956d6 | ||
|
|
9659ff8afa | ||
|
|
783955cc5d | ||
|
|
048556803b | ||
|
|
5c46939556 | ||
|
|
222d58e973 | ||
|
|
38343112a5 | ||
|
|
770a7bc4fa | ||
|
|
d6695f127d | ||
|
|
35e5fc5173 | ||
|
|
b58ea46c22 | ||
|
|
470eb64051 | ||
|
|
6192e9be72 | ||
|
|
b518451888 | ||
|
|
7b5dcdf07e | ||
|
|
515d47f055 |
32
.clang-format
Normal file
32
.clang-format
Normal file
@@ -0,0 +1,32 @@
|
||||
# 2025-02-12
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
AlignAfterOpenBracket: BlockIndent
|
||||
AlignArrayOfStructures: Left
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveMacros: AcrossComments
|
||||
AlignEscapedNewlinesLeft: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
ColumnLimit: 120
|
||||
ContinuationIndentWidth: 4
|
||||
EmptyLineBeforeAccessModifier: Always
|
||||
FixNamespaceComments: true
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 4
|
||||
LambdaBodyIndentation: Signature
|
||||
MaxEmptyLinesToKeep: 1
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000
|
||||
QualifierAlignment: Left
|
||||
ReflowComments: true
|
||||
SeparateDefinitionBlocks: Always
|
||||
TabWidth: 4
|
||||
UseTab: Always
|
||||
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
ko_fi: kuba2k2
|
||||
custom:
|
||||
- "https://paypal.me/kuba2k2"
|
||||
46
.github/workflows/platformio-publish.yml
vendored
46
.github/workflows/platformio-publish.yml
vendored
@@ -1,46 +0,0 @@
|
||||
name: PlatformIO Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*.*.*
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
- name: Publish PlatformIO package
|
||||
run: pio package publish --non-interactive
|
||||
env:
|
||||
CI: true
|
||||
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
|
||||
- name: Get latest version
|
||||
id: get_version
|
||||
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
|
||||
- name: Release on GitHub
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
name: ${{ steps.get_version.outputs.VERSION }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
13
.github/workflows/push-dev.yml
vendored
Normal file
13
.github/workflows/push-dev.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
name: Push (dev), Pull Request
|
||||
on:
|
||||
push:
|
||||
branches: ["**"]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
lint-clang:
|
||||
name: Run Clang lint
|
||||
uses: kuba2k2/kuba2k2/.github/workflows/lint-clang.yml@master
|
||||
lint-python:
|
||||
name: Run Python lint
|
||||
uses: kuba2k2/kuba2k2/.github/workflows/lint-python.yml@master
|
||||
44
.github/workflows/push-master.yml
vendored
Normal file
44
.github/workflows/push-master.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Push (master)
|
||||
on:
|
||||
push:
|
||||
branches: ["master"]
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
docs:
|
||||
name: Deploy docs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install docs dependencies
|
||||
run: pip install -U ltchiptool "boardgen>=0.11.0"
|
||||
|
||||
- name: Generate docs and static JSON files
|
||||
run: |
|
||||
mkdir -p site/
|
||||
boardgen ltci
|
||||
python docs/scripts/write_boards.py
|
||||
python docs/scripts/write_apis.py
|
||||
python docs/scripts/prepare_doxygen.py
|
||||
python docs/scripts/build_json.py
|
||||
cp *.json site/
|
||||
|
||||
- name: Set custom domain
|
||||
run: |
|
||||
mkdir -p site/
|
||||
echo docs.libretiny.eu > site/CNAME
|
||||
|
||||
- name: Deploy docs
|
||||
uses: libretiny-eu/mkdocs-deploy-gh-pages@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CONFIG_FILE: mkdocs.yml
|
||||
EXTRA_PACKAGES: build-base doxygen
|
||||
REQUIREMENTS: docs/requirements.txt
|
||||
CUSTOM_DOMAIN: docs.libretiny.eu
|
||||
22
.github/workflows/release.yml
vendored
Normal file
22
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Release
|
||||
on:
|
||||
push:
|
||||
tags: ["v*.*.*"]
|
||||
jobs:
|
||||
lint-clang:
|
||||
name: Run Clang lint
|
||||
uses: kuba2k2/kuba2k2/.github/workflows/lint-clang.yml@master
|
||||
publish-pio-platform:
|
||||
name: Publish PlatformIO platform
|
||||
needs:
|
||||
- lint-clang
|
||||
uses: kuba2k2/kuba2k2/.github/workflows/publish-pio-platform.yml@master
|
||||
secrets:
|
||||
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
|
||||
gh-release:
|
||||
name: Publish GitHub release
|
||||
needs:
|
||||
- publish-pio-platform
|
||||
uses: kuba2k2/kuba2k2/.github/workflows/gh-release.yml@master
|
||||
permissions:
|
||||
contents: write
|
||||
14
.gitignore
vendored
14
.gitignore
vendored
@@ -252,3 +252,17 @@ cython_debug/
|
||||
# End of https://www.toptal.com/developers/gitignore/api/c,c++,visualstudiocode,python
|
||||
|
||||
.vscode/settings.json
|
||||
|
||||
# mkdocs
|
||||
xml/
|
||||
ltapi/
|
||||
hashChanges.yaml
|
||||
.piopm
|
||||
|
||||
# board files
|
||||
docs/status/supported_*.md
|
||||
docs/status/unsupported_boards_*.md
|
||||
boards/**/*.svg
|
||||
boards/**/*.md
|
||||
# other generated files
|
||||
docs/contrib/lt-api-functions.md
|
||||
|
||||
197
README.md
197
README.md
@@ -1,196 +1,39 @@
|
||||
# LibreTuya
|
||||
# LibreTiny
|
||||
|
||||
<div align="center">
|
||||
<small>(formerly LibreTuya)</small>
|
||||
|
||||
<div align="center" markdown>
|
||||
|
||||
[](https://docs.libretiny.eu/)
|
||||

|
||||
|
||||
[](.clang-format)
|
||||
[](https://github.com/psf/black)
|
||||
|
||||
[](https://discord.gg/SyGCB9Xwtf)
|
||||
[](https://registry.platformio.org/platforms/kuba2k2/libretuya)
|
||||

|
||||
[](https://registry.platformio.org/platforms/kuba2k2/libretiny)
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
</div>
|
||||
|
||||
PlatformIO development platform for IoT modules manufactured by Tuya Inc.
|
||||
PlatformIO development platform for BK7231, RTL8710 and LN882H IoT chips.
|
||||
|
||||
The main goal of this project is to provide a usable build environment for IoT developers. While also providing vendor SDKs as PlatformIO cores,
|
||||
the project focuses on developing working Arduino-compatible cores for supported platforms. The cores are inspired by Espressif's official core for ESP32,
|
||||
which should make it easier to port/run existing ESP apps on Tuya IoT (and 3-rd party) platforms.
|
||||
the project focuses on developing working Arduino-compatible cores for supported families. The cores are inspired by Espressif's official core for ESP32,
|
||||
which should make it easier to port/run existing ESP apps on less-common, unsupported IoT modules.
|
||||
|
||||
LibreTuya also provides a common interface for all platform implementations. The interface is based on ESP32 official libraries.
|
||||
**There's an [ESPHome port](https://docs.libretiny.eu/docs/projects/esphome/) based on LibreTiny, which supports BK7231 and RTL8710B chips.**
|
||||
|
||||
**Note:** this project is work-in-progress.
|
||||
|
||||
## Usage
|
||||
<div align="center" markdown>
|
||||
|
||||
1. [Install PlatformIO](https://platformio.org/platformio-ide)
|
||||
2. `platformio platform install libretuya`
|
||||
3. Create a project, build it and upload!
|
||||
4. See the [docs](docs/README.md) for any questions/problems.
|
||||
## [⭐ Getting started ⭐](https://docs.libretiny.eu/docs/getting-started/)
|
||||
|
||||
## Board List
|
||||
|
||||
A (mostly) complete* list of Tuya wireless module boards.
|
||||
|
||||
| Module Name | MCU | Flash | RAM | Pins** | Wi-Fi | BLE | Platform name
|
||||
------------------------------|------------------------------------------------------------------------------------------------|-------------------------|-------|----------|-------------|-------|-----|---------------
|
||||
❌ | [WB1S](https://developer.tuya.com/en/docs/iot/wb1s?id=K9duevbj3ol4x) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WB2L](https://developer.tuya.com/en/docs/iot/wb2l-datasheet?id=K9duegc9bualu) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 7 (5 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WB2S](https://developer.tuya.com/en/docs/iot/wb2s-module-datasheet?id=K9ghecl7kc479) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 11 (8 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WB3L](https://developer.tuya.com/en/docs/iot/wb3l-module-datasheet?id=K9duiggw2v8sp) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WB3S](https://developer.tuya.com/en/docs/iot/wb3s-module-datasheet?id=K9dx20n6hz5n4) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 16 (11 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WB3S-IPEX](https://developer.tuya.com/en/docs/iot/wb3sipex-module-datasheet?id=K9irq0laun21z) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 16 (11 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WB8P](https://developer.tuya.com/en/docs/iot/wb8p-module-datasheet?id=K9fwx4f89tvzd) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 10 (8 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WBLC5](https://developer.tuya.com/en/docs/iot/wblc5-module-datasheet?id=K9duilns1f3gi) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 6 (3 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WBLC9](https://developer.tuya.com/en/docs/iot/wblc9-module-datasheet?id=K9hgglry2jp5h) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 8 (6 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB1S](https://developer.tuya.com/en/docs/iot/cb1s-module-datasheet?id=Kaij1abmwyjq2) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB2L](https://developer.tuya.com/en/docs/iot/cb2l-module-datasheet?id=Kai2eku1m3pyl) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 7 (5 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB2S](https://developer.tuya.com/en/docs/iot/cb2s-module-datasheet?id=Kafgfsa2aaypq) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 11 (8 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB3L](https://developer.tuya.com/en/docs/iot/cb3l-module-datasheet?id=Kai51ngmrh3qm) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 16 (11 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB3S](https://developer.tuya.com/en/docs/iot/cb3s?id=Kai94mec0s076) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 22 (14 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB3S-NL](https://developer.tuya.com/en/docs/iot/CB3S-NL-module-datasheet?id=Kbaesan0vyoms) | BK7231NL (?) @ 120 MHz | 2 MiB | 256 KiB | 22 (14 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB3SE](https://developer.tuya.com/en/docs/iot/CB3SE-Module-Datasheet?id=Kanoiluul7nl2) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 22 (17 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB8P](https://developer.tuya.com/en/docs/iot/cb8p-module-datasheet?id=Kahvig14r1yk9) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 10 (8 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CBLC5](https://developer.tuya.com/en/docs/iot/cblc5-module-datasheet?id=Ka07iqyusq1wm) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 6 (3 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CBLC9](https://developer.tuya.com/en/docs/iot/cblc9-module-datasheet?id=Ka42cqnj9r0i5) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 8 (6 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CBU](https://developer.tuya.com/en/docs/iot/cbu-module-datasheet?id=Ka07pykl5dk4u) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 21 (18 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CBU-IPEX](https://developer.tuya.com/en/docs/iot/cbuipex-module-datasheet?id=Kaedsyurckrhu) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 21 (18 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CBU-NL](https://developer.tuya.com/en/docs/iot/CBU-NL-module-datasheet?id=Kbaeq6j53y0yg) | BK7231N (?) @ 120 MHz | 2 MiB | 256 KiB | 21 (18 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WR1](https://developer.tuya.com/en/docs/iot/wifiwr1module?id=K9605tc0k90t3) | RTL8710BN @ 125 MHz | 1 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR1-IPEX](https://developer.tuya.com/en/docs/iot/wifiwr1ipexmodule?id=K9605t977tx5u) | RTL8710BN @ 125 MHz | 1 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR1E](https://developer.tuya.com/en/docs/iot/wr1e?id=K96smbbeycxtf) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR2](https://developer.tuya.com/en/docs/iot/wifiwr2module?id=K9605tko0juc3) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 11 (8 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR2E](https://developer.tuya.com/en/docs/iot/wr2e?id=K97scnsjhue4h) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 11 (8 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR2L](https://developer.tuya.com/en/docs/iot/wifiwr2lmodule?id=K9605tnbj7gva) | RTL8710BX @ 62.5 MHz | 2 MiB | 256 KiB | 7 (5 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR2LE](https://developer.tuya.com/en/docs/iot/wr2le?id=K9eio9y9e8i8c) | RTL8710BX @ 62.5 MHz | 2 MiB | 256 KiB | 7 (5 I/O) | ✔️ | ❌ | -
|
||||
[`wr3`](boards/wr3/README.md) | [WR3](https://developer.tuya.com/en/docs/iot/wr3-module-datasheet?id=K9g3ainzbj9z1) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | `realtek-ambz`
|
||||
❌ | [WR3E](https://developer.tuya.com/en/docs/iot/wr3e-module-datasheet?id=K9elwlqbfosbc) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR3L](https://developer.tuya.com/en/docs/iot/wifiwr3lmodule?id=K9605tt0kveqm) | RTL8710BX @ 125 MHz (?) | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR3LE](https://developer.tuya.com/en/docs/iot/wr3le?id=K986l7a1ha8tm) | RTL8710BX @ 62.5 MHz | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR3N](https://developer.tuya.com/en/docs/iot/wr3n-datasheet?id=K98zdx31ztdge) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 16 (10 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR4](https://developer.tuya.com/en/docs/iot/wifiwr4module?id=K9605tvu78p3e) | RTL8710BN @ 125 MHz | 1 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR5E](https://developer.tuya.com/en/docs/iot/wr5e?id=K986r9pxqxa8i) | RTL8710BX @ 62.5 MHz | 2 MiB | 256 KiB | 15 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR6-H](https://developer.tuya.com/en/docs/iot/wr6h-module-datasheet?id=K9pork8eeowgl) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 18 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR6](https://developer.tuya.com/en/docs/iot/wr6-datasheet?id=K97rp45u6gff9) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 18 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WRG1](https://developer.tuya.com/en/docs/iot/wr6-datasheet?id=K97rp45u6gff9) | RTL8711AM @ 166 MHz | 4 MiB | 2048 KiB | 25 (20 I/O) | ✔️ | ❌ | -
|
||||
❌ | [XR1](https://developer.tuya.com/en/docs/iot/xr1?id=K9lq3y9xo0zkx) | XR809 @ 160 MHz | 2 MiB | 384 KiB | 18 (11 I/O) | ✔️ | ❌ | -
|
||||
❌ | [XR1-IPEX](https://developer.tuya.com/en/docs/iot/xr1ipex-module-datasheet?id=K9razqu9gqele) | XR809 @ 160 MHz | 2 MiB | 384 KiB | 18 (11 I/O) | ✔️ | ❌ | -
|
||||
❌ | [XR3](https://developer.tuya.com/en/docs/iot/xr3-datasheet?id=K98s9168qi49g) | XR809 @ 160 MHz | 2 MiB | 384 KiB | 22 (17 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WE1S](https://developer.tuya.com/en/docs/iot/wifie1smodule?id=K9605thnvg3e7) | ESP8266EX @ 80/160 MHz | 2 MiB | 36 KiB | 18 (11 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WE2L](https://developer.tuya.com/en/docs/iot/wifie2lmodule?id=K9605ud0gkjmh) | ESP8285 @ 80/160 MHz | 1 MiB | 50 KiB | 7 (5 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WE2S](https://developer.tuya.com/en/docs/iot/wifie2smodule?id=K9605u79tgxug) | ESP8285 @ 80/160 MHz | 1 MiB | 50 KiB | 11 (8 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WE3L](https://developer.tuya.com/en/docs/iot/wifie3lpinmodule?id=K9605uj1ar87n) | ESP8266 @ 80/160 MHz | 2 MiB | 50 KiB | 16 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WE3S](https://developer.tuya.com/en/docs/iot/wifie3smodule?id=K9605ua1cx9tv) | ESP8266 @ 80/160 MHz | 2 MiB | 50 KiB | 16 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WE3SE](https://developer.tuya.com/en/docs/iot/we3se?id=K97qv6ab7oh8d) | ESP32 @ 240 MHz | 4 MiB | 520 KiB | 22 (17 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WE5P](https://developer.tuya.com/en/docs/iot/wifie5pmodule?id=K9605um3dtjbx) | ESP8266 @ 80/160 MHz | 1 MiB | 50 KiB | 15 (11 I/O) | ✔️ | ❌ | -
|
||||
|
||||
\* Only modules featuring at least Wi-Fi. WBR, JWBR, CR, (TY)JW and (TY)LC Series are not included here
|
||||
|
||||
** I/O count includes GPIOs, ADCs, PWM outputs and UART, but doesn't count CEN/RST and power pins.
|
||||
|
||||
## Project structure
|
||||
|
||||
```
|
||||
arduino/
|
||||
├─ <platform name>/ Arduino Core for specific platform
|
||||
│ ├─ cores/ Core files
|
||||
│ ├─ libraries/ Supported built-in libraries
|
||||
├─ libretuya/
|
||||
│ ├─ api/ LibreTuya API for Arduino frameworks
|
||||
│ ├─ compat/ Fixes for compatibility with ESP32 framework
|
||||
│ ├─ libraries/ Built-in platform-independent libraries
|
||||
boards/
|
||||
├─ <board name>/ Board-specific code
|
||||
│ ├─ variant.cpp Arduino variant initialization
|
||||
│ ├─ variant.h Arduino variant pin configs
|
||||
├─ <board name>.json PlatformIO board description
|
||||
builder/
|
||||
├─ frameworks/ Framework builders for PlatformIO
|
||||
│ ├─ <platform name>-sdk.py Vanilla SDK build system
|
||||
│ ├─ <platform name>-arduino.py Arduino Core build system
|
||||
├─ arduino-common.py Builder to provide ArduinoCore-API and LibreTuya APIs
|
||||
├─ main.py Main PlatformIO builder
|
||||
docs/ Project documentation, guides, tips, etc.
|
||||
platform/
|
||||
├─ <platform name>/ Platform-specific configurations
|
||||
│ ├─ bin/ Binary blobs (bootloaders, etc.)
|
||||
│ ├─ fixups/ Code fix-ups to replace SDK parts
|
||||
│ ├─ ld/ Linker scripts
|
||||
│ ├─ openocd/ OpenOCD configuration files
|
||||
tools/
|
||||
├─ <tool name>/ Tools used during the build
|
||||
platform.json PlatformIO manifest
|
||||
platform.py Custom PlatformIO script
|
||||
```
|
||||
|
||||
## Platforms
|
||||
|
||||
A list of platforms currently available in this project.
|
||||
|
||||
Platform name | Supported MCU(s) | Arduino Core | Source SDK (PIO framework)
|
||||
---------------|------------------------------------------------------------------------|--------------|--------------------------------------------------------------------------
|
||||
`realtek-ambz` | Realtek [AmebaZ](https://www.amebaiot.com/en/amebaz/) SoC (`RTL87xxB`) | ✔️ | `framework-realtek-amb1` ([amb1_sdk](https://github.com/ambiot/amb1_sdk))
|
||||
|
||||
### Realtek Ameba
|
||||
|
||||
The logic behind naming of Realtek chips and their series took me some time to figure out:
|
||||
- RTL8xxxA - Ameba1/Ameba Series
|
||||
- RTL8xxxB - AmebaZ Series
|
||||
- RTL8xxxC - AmebaZ2/ZII Series
|
||||
- RTL8xxxD - AmebaD Series
|
||||
|
||||
As such, there are numerous CPUs with the same numbers but different series, which makes them require different code and SDKs.
|
||||
- [RTL8195AM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8195am)
|
||||
- RTL8710AF (found in amb1_arduino)
|
||||
- [RTL8711AM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8711am)
|
||||
- [RTL8710BN](https://www.realtek.com/en/products/communications-network-ics/item/rtl8710bn)
|
||||
- RTL8710BX (found in Tuya product pages)
|
||||
- RTL8710B? (found in amb1_sdk)
|
||||
- RTL8711B? (found in amb1_sdk)
|
||||
- [RTL8710CM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8710cm)
|
||||
- RTL8722CSM (found in ambd_arduino)
|
||||
- RTL8720DN (found in ambd_arduino)
|
||||
- [RTL8721DM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8721dm)
|
||||
- RTL8722DM (found in ambd_arduino)
|
||||
- and probably many more
|
||||
|
||||
Different Ameba series are not compatible with each other. Apparently, there isn't an official public SDK for AmebaZ that can support C++ properly.
|
||||
|
||||
## Arduino Core support status
|
||||
|
||||
Note: this list will probably change with each functionality update.
|
||||
|
||||
| `realtek-ambz`
|
||||
--------------------|---------------
|
||||
Core functions | ✔️
|
||||
GPIO/PWM/IRQ | ✔️/❓/✔️
|
||||
Analog input | ❓
|
||||
UART I/O | ✔️
|
||||
Flash I/O | ❓
|
||||
**CORE LIBRARIES** |
|
||||
SoftwareSerial | ❌
|
||||
SPI | ❌
|
||||
Wire | ❌
|
||||
**OTHER LIBRARIES** |
|
||||
Wi-Fi Station | ✔️
|
||||
Wi-Fi Access Point | ✔️
|
||||
Wi-Fi Events | ❌
|
||||
Wi-Fi Client (SSL) | ✔️ (❌)
|
||||
Wi-Fi Server | ✔️
|
||||
SPIFFS | ❌
|
||||
BLE | -
|
||||
HTTP | ❌
|
||||
NTP | ❌
|
||||
OTA | ❌
|
||||
MDNS | ❌
|
||||
MQTT | ❌
|
||||
SD | ❌
|
||||
|
||||
Legend:
|
||||
- ✔️ working
|
||||
- ❗ broken
|
||||
- ❓ untested
|
||||
- ❌ not implemented (yet?)
|
||||
- \- not applicable
|
||||
</div>
|
||||
|
||||
## License
|
||||
|
||||
|
||||
65
SUMMARY.md
Normal file
65
SUMMARY.md
Normal file
@@ -0,0 +1,65 @@
|
||||
* [Home](README.md)
|
||||
* [😊 Getting started](docs/getting-started/README.md)
|
||||
* [➡️ Info on accessing GPIOs](docs/getting-started/gpio.md)
|
||||
* [](SUMMARY.md)
|
||||
* [📺 Cloudcutter & ESPHome video guide](https://www.youtube.com/watch?v=sSj8f-HCHQ0)
|
||||
* [💡 ESPHome setup guide](docs/projects/esphome.md)
|
||||
* [🛖 ESPHome Hassio Add-On](https://github.com/libretiny-eu/esphome-hass-addon/pkgs/container/libretiny-esphome-hassio)
|
||||
* [](SUMMARY.md)
|
||||
* [📲 Flashing/dumping guide](docs/flashing/)
|
||||
* [🔌 How to flash/enter download mode?](docs/platform/)
|
||||
* [](SUMMARY.md)
|
||||
* [💻 Chips, boards, features](docs/status/supported.md)
|
||||
* [All boards](boards/)
|
||||
* [](SUMMARY.md)
|
||||
* 🍪 Chip family docs & info
|
||||
* [Beken BK72xx](docs/platform/beken-72xx/README.md)
|
||||
* [Finding encryption keys](docs/platform/beken-72xx/keys.md)
|
||||
* [Realtek Ameba - info](docs/platform/realtek-amb/README.md)
|
||||
* [Realtek AmebaZ](docs/platform/realtek-ambz/README.md)
|
||||
* [Debugging](docs/platform/realtek-ambz/debugging.md)
|
||||
* [Exception decoder](docs/platform/realtek-ambz/exception-decoder.md)
|
||||
* [Lightning LN882x](docs/platform/lightning-ln882x/README.md)
|
||||
* [🔧 LT Configuration](docs/dev/config.md)
|
||||
* 🧑 Programmer's manual
|
||||
* [⚠️ Migration guide](docs/dev/migration_v1.0.0.md)
|
||||
* [🔋 PlatformIO Examples](examples/)
|
||||
* [📖 LibreTiny API](docs/dev/lt-api.md)
|
||||
* [C API](ltapi/dir_c7e317b16142bccc961a83c0babf0065.md)
|
||||
* [C++ API](ltapi/dir_930634efd5dc4a957bbb6e685a3ccda1.md)
|
||||
* 📚 Arduino Libraries
|
||||
* [SoftwareSerial](ltapi/class_software_serial.md)
|
||||
* [WiFi](ltapi/class_wi_fi_class.md)
|
||||
* [](SUMMARY.md)
|
||||
* [Flash](ltapi/class_flash_class.md)
|
||||
* [IPv6Address](ltapi/classarduino_1_1_i_pv6_address.md)
|
||||
* [MD5](ltapi/libraries_2common_2_m_d5_2_m_d5_8h.md)
|
||||
* [mDNS](ltapi/classm_d_n_s.md)
|
||||
* [Update](ltapi/class_update_class.md)
|
||||
* [WiFiClient](ltapi/class_i_wi_fi_client.md)
|
||||
* [WiFiClientSecure](ltapi/class_i_wi_fi_client_secure.md)
|
||||
* [WiFiServer](ltapi/class_i_wi_fi_server.md)
|
||||
* [WiFiUDP](ltapi/class_i_wi_fi_u_d_p.md)
|
||||
* [](SUMMARY.md)
|
||||
* [HTTPClient](ltapi/class_h_t_t_p_client.md)
|
||||
* [StreamString](ltapi/class_stream_string.md)
|
||||
* [WebServer](ltapi/class_web_server.md)
|
||||
* [WiFiMulti](ltapi/class_wi_fi_multi.md)
|
||||
* [](SUMMARY.md)
|
||||
* [External compatible libraries](docs/dev/libs-3rd-party.md)
|
||||
* Full documentation
|
||||
* [Classes](ltapi/classes.md)
|
||||
* [Functions](ltapi/functions.md)
|
||||
* [Macros](ltapi/macros.md)
|
||||
* [File list](ltapi/files.md)
|
||||
* 👷 Contributor's manual (WIP)
|
||||
* [Porting new families](docs/contrib/porting.md)
|
||||
* [API functions guide](docs/contrib/lt-api.md)
|
||||
* [C standard library](docs/contrib/stdlib.md)
|
||||
* [📁 Project structure](docs/contrib/project-structure.md)
|
||||
* [✈️ OTA format](docs/contrib/ota/README.md)
|
||||
* [uf2ota.py tool](docs/contrib/ota/uf2ota.md)
|
||||
* [uf2ota.h library](docs/contrib/ota/library.md)
|
||||
* [📓 TODO](docs/TODO.md)
|
||||
* [](SUMMARY.md)
|
||||
* [🔗 Resources](docs/resources/)
|
||||
@@ -1,2 +0,0 @@
|
||||
realtek-ambz Realtek AmebaZ Arduino Core
|
||||
libretuya Interfaces for LibreTuya Arduino cores
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t manufacturerId;
|
||||
uint8_t chipId;
|
||||
uint8_t chipSizeId;
|
||||
} FlashId;
|
||||
|
||||
class IFlashClass {
|
||||
public:
|
||||
IFlashClass() {}
|
||||
|
||||
~IFlashClass() {}
|
||||
|
||||
virtual FlashId getChipId() = 0;
|
||||
virtual uint32_t getSize() = 0;
|
||||
|
||||
virtual bool eraseSector(uint32_t sector) = 0;
|
||||
virtual bool readBlock(uint32_t offset, uint8_t *data, size_t size) = 0;
|
||||
virtual bool writeBlock(uint32_t offset, uint8_t *data, size_t size) = 0;
|
||||
};
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
IPv6Address.cpp - Base class that provides IPv6Address
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <api/Print.h>
|
||||
|
||||
#include "IPv6Address.h"
|
||||
|
||||
IPv6Address::IPv6Address()
|
||||
{
|
||||
memset(_address.bytes, 0, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const uint8_t *address)
|
||||
{
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const uint32_t *address)
|
||||
{
|
||||
memcpy(_address.bytes, (const uint8_t *)address, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
IPv6Address& IPv6Address::operator=(const uint8_t *address)
|
||||
{
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IPv6Address::operator==(const uint8_t* addr) const
|
||||
{
|
||||
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
|
||||
}
|
||||
|
||||
size_t IPv6Address::printTo(Print& p) const
|
||||
{
|
||||
/* size_t n = 0;
|
||||
for(int i = 0; i < 16; i+=2) {
|
||||
if(i){
|
||||
n += p.print(':');
|
||||
}
|
||||
n += p.printf("%02x", _address.bytes[i]);
|
||||
n += p.printf("%02x", _address.bytes[i+1]);
|
||||
|
||||
}
|
||||
return n; */
|
||||
}
|
||||
|
||||
String IPv6Address::toString() const
|
||||
{
|
||||
char szRet[40];
|
||||
sprintf(szRet,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||
_address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3],
|
||||
_address.bytes[4], _address.bytes[5], _address.bytes[6], _address.bytes[7],
|
||||
_address.bytes[8], _address.bytes[9], _address.bytes[10], _address.bytes[11],
|
||||
_address.bytes[12], _address.bytes[13], _address.bytes[14], _address.bytes[15]);
|
||||
return String(szRet);
|
||||
}
|
||||
|
||||
bool IPv6Address::fromString(const char *address)
|
||||
{
|
||||
//format 0011:2233:4455:6677:8899:aabb:ccdd:eeff
|
||||
if(strlen(address) != 39){
|
||||
return false;
|
||||
}
|
||||
char * pos = (char *)address;
|
||||
size_t i = 0;
|
||||
for(i = 0; i < 16; i+=2) {
|
||||
if(!sscanf(pos, "%2hhx", &_address.bytes[i]) || !sscanf(pos+2, "%2hhx", &_address.bytes[i+1])){
|
||||
return false;
|
||||
}
|
||||
pos += 5;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
IPv6Address.h - Base class that provides IPv6Address
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <api/String.h>
|
||||
#include <api/Print.h>
|
||||
|
||||
// A class to make it easier to handle and pass around IP addresses
|
||||
|
||||
namespace arduino {
|
||||
|
||||
class IPv6Address: public Printable
|
||||
{
|
||||
private:
|
||||
union {
|
||||
uint8_t bytes[16]; // IPv4 address
|
||||
uint32_t dword[4];
|
||||
} _address;
|
||||
|
||||
// Access the raw byte array containing the address. Because this returns a pointer
|
||||
// to the internal structure rather than a copy of the address this function should only
|
||||
// be used when you know that the usage of the returned uint8_t* will be transient and not
|
||||
// stored.
|
||||
uint8_t* raw_address()
|
||||
{
|
||||
return _address.bytes;
|
||||
}
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
IPv6Address();
|
||||
IPv6Address(const uint8_t *address);
|
||||
IPv6Address(const uint32_t *address);
|
||||
virtual ~IPv6Address() {}
|
||||
|
||||
bool fromString(const char *address);
|
||||
bool fromString(const String &address) { return fromString(address.c_str()); }
|
||||
|
||||
operator const uint8_t*() const
|
||||
{
|
||||
return _address.bytes;
|
||||
}
|
||||
operator const uint32_t*() const
|
||||
{
|
||||
return _address.dword;
|
||||
}
|
||||
bool operator==(const IPv6Address& addr) const
|
||||
{
|
||||
return (_address.dword[0] == addr._address.dword[0])
|
||||
&& (_address.dword[1] == addr._address.dword[1])
|
||||
&& (_address.dword[2] == addr._address.dword[2])
|
||||
&& (_address.dword[3] == addr._address.dword[3]);
|
||||
}
|
||||
bool operator==(const uint8_t* addr) const;
|
||||
|
||||
// Overloaded index operator to allow getting and setting individual octets of the address
|
||||
uint8_t operator[](int index) const
|
||||
{
|
||||
return _address.bytes[index];
|
||||
}
|
||||
uint8_t& operator[](int index)
|
||||
{
|
||||
return _address.bytes[index];
|
||||
}
|
||||
|
||||
// Overloaded copy operators to allow initialisation of IPv6Address objects from other types
|
||||
IPv6Address& operator=(const uint8_t *address);
|
||||
|
||||
// TODO implement printTo()
|
||||
virtual size_t printTo(Print& p) const;
|
||||
String toString() const;
|
||||
|
||||
friend class UDP;
|
||||
friend class Client;
|
||||
friend class Server;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using arduino::IPv6Address;
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef LT_VERSION
|
||||
#define LT_VERSION 1.0.0
|
||||
#endif
|
||||
|
||||
#ifndef LT_BOARD
|
||||
#define LT_BOARD unknown
|
||||
#endif
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
#define STRINGIFY_MACRO(x) STRINGIFY(x)
|
||||
#define LT_VERSION_STR STRINGIFY_MACRO(LT_VERSION)
|
||||
#define LT_BOARD_STR STRINGIFY_MACRO(LT_BOARD)
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "LibreTuyaConfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "lt_logger.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#define LT_BANNER() \
|
||||
LT_LOG( \
|
||||
LT_LEVEL_INFO, \
|
||||
"main.cpp", \
|
||||
__LINE__, \
|
||||
"LibreTuya v" LT_VERSION_STR " on " LT_BOARD_STR ", compiled at " __DATE__ " " __TIME__ \
|
||||
)
|
||||
@@ -1,64 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// see docs/API Configuration
|
||||
|
||||
// Loglevels
|
||||
#define LT_LEVEL_VERBOSE LT_LEVEL_TRACE
|
||||
#define LT_LEVEL_TRACE 0
|
||||
#define LT_LEVEL_DEBUG 1
|
||||
#define LT_LEVEL_INFO 2
|
||||
#define LT_LEVEL_WARN 3
|
||||
#define LT_LEVEL_ERROR 4
|
||||
#define LT_LEVEL_FATAL 5
|
||||
|
||||
// Logger enabled/disabled
|
||||
#ifndef LT_LOGGER
|
||||
#define LT_LOGGER 1
|
||||
#endif
|
||||
|
||||
// Logger format options
|
||||
#ifndef LT_LOGGER_TIMESTAMP
|
||||
#define LT_LOGGER_TIMESTAMP 1
|
||||
#endif
|
||||
|
||||
#ifndef LT_LOGGER_FILE
|
||||
#define LT_LOGGER_FILE 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_LOGGER_TASK
|
||||
#define LT_LOGGER_TASK 1
|
||||
#endif
|
||||
|
||||
#ifndef LT_LOGGER_COLOR
|
||||
#define LT_LOGGER_COLOR 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_PRINTF_BROKEN
|
||||
#define LT_PRINTF_BROKEN 0
|
||||
#endif
|
||||
|
||||
// Global loglevel
|
||||
#ifndef LT_LOGLEVEL
|
||||
#define LT_LOGLEVEL LT_LEVEL_INFO
|
||||
#endif
|
||||
|
||||
// Per-module debugging
|
||||
#ifndef LT_DEBUG_WIFI
|
||||
#define LT_DEBUG_WIFI 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_WIFI_CLIENT
|
||||
#define LT_DEBUG_WIFI_CLIENT 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_WIFI_SERVER
|
||||
#define LT_DEBUG_WIFI_SERVER 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_WIFI_STA
|
||||
#define LT_DEBUG_WIFI_STA 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_WIFI_AP
|
||||
#define LT_DEBUG_WIFI_AP 0
|
||||
#endif
|
||||
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
WiFi.h - esp32 Wifi support.
|
||||
Based on WiFi.h from Arduino WiFi shield library.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <api/IPAddress.h>
|
||||
#include <api/IPv6Address.h>
|
||||
#include <api/Print.h>
|
||||
|
||||
#include "WiFiType.h"
|
||||
|
||||
// TODO wifi events
|
||||
// TODO WiFiMulti library
|
||||
|
||||
class IWiFiClass {
|
||||
public:
|
||||
virtual void printDiag(Print &dest) = 0;
|
||||
};
|
||||
|
||||
class IWiFiGenericClass {
|
||||
public:
|
||||
virtual int32_t channel(void) = 0;
|
||||
virtual bool mode(WiFiMode mode) = 0;
|
||||
virtual WiFiMode getMode() = 0;
|
||||
virtual WiFiStatus status() = 0;
|
||||
|
||||
virtual bool enableSTA(bool enable) = 0;
|
||||
virtual bool enableAP(bool enable) = 0;
|
||||
|
||||
virtual bool setSleep(bool enable) = 0;
|
||||
virtual bool getSleep() = 0;
|
||||
|
||||
virtual bool setTxPower(int power) = 0;
|
||||
virtual int getTxPower() = 0;
|
||||
|
||||
virtual int hostByName(const char *hostname, IPAddress &aResult) {
|
||||
aResult = hostByName(hostname);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual IPAddress hostByName(const char *hostname) = 0;
|
||||
|
||||
static IPAddress calculateNetworkID(IPAddress ip, IPAddress subnet);
|
||||
static IPAddress calculateBroadcast(IPAddress ip, IPAddress subnet);
|
||||
static uint8_t calculateSubnetCIDR(IPAddress subnetMask);
|
||||
static String macToString(uint8_t *mac);
|
||||
};
|
||||
|
||||
class IWiFiSTAClass {
|
||||
public:
|
||||
virtual WiFiStatus begin(
|
||||
const char *ssid,
|
||||
const char *passphrase = NULL,
|
||||
int32_t channel = 0,
|
||||
const uint8_t *bssid = NULL,
|
||||
bool connect = true
|
||||
) = 0;
|
||||
virtual WiFiStatus begin(
|
||||
char *ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t *bssid = NULL, bool connect = true
|
||||
) = 0;
|
||||
|
||||
virtual bool config(
|
||||
IPAddress localIP,
|
||||
IPAddress gateway,
|
||||
IPAddress subnet,
|
||||
IPAddress dns1 = (uint32_t)0x00000000,
|
||||
IPAddress dns2 = (uint32_t)0x00000000
|
||||
) = 0;
|
||||
|
||||
virtual bool reconnect() = 0;
|
||||
virtual bool disconnect(bool wifiOff = false) = 0;
|
||||
|
||||
virtual bool isConnected();
|
||||
|
||||
virtual bool setAutoReconnect(bool autoReconnect) = 0;
|
||||
virtual bool getAutoReconnect() = 0;
|
||||
|
||||
virtual WiFiStatus waitForConnectResult(unsigned long timeout) = 0;
|
||||
|
||||
virtual IPAddress localIP() = 0;
|
||||
virtual uint8_t *macAddress(uint8_t *mac) = 0;
|
||||
virtual String macAddress() = 0;
|
||||
virtual IPAddress subnetMask() = 0;
|
||||
virtual IPAddress gatewayIP() = 0;
|
||||
virtual IPAddress dnsIP(uint8_t dns_no = 0) = 0;
|
||||
virtual IPAddress broadcastIP() = 0;
|
||||
virtual IPAddress networkID() = 0;
|
||||
virtual uint8_t subnetCIDR() = 0;
|
||||
virtual bool enableIpV6() = 0;
|
||||
virtual IPv6Address localIPv6() = 0;
|
||||
virtual const char *getHostname() = 0;
|
||||
virtual bool setHostname(const char *hostname) = 0;
|
||||
virtual bool setMacAddress(const uint8_t *mac) = 0;
|
||||
|
||||
inline bool hostname(const String &aHostname) {
|
||||
return setHostname(aHostname.c_str());
|
||||
}
|
||||
|
||||
virtual const String SSID() = 0;
|
||||
virtual const String psk() = 0;
|
||||
virtual uint8_t *BSSID() = 0;
|
||||
virtual String BSSIDstr() = 0;
|
||||
virtual int8_t RSSI() = 0;
|
||||
virtual WiFiAuthMode getEncryption() = 0;
|
||||
};
|
||||
|
||||
class IWiFiScanClass {
|
||||
public:
|
||||
virtual int16_t scanNetworks(
|
||||
bool async = false,
|
||||
bool showHidden = false,
|
||||
bool passive = false,
|
||||
uint32_t maxMsPerChannel = 300,
|
||||
uint8_t channel = 0
|
||||
) = 0;
|
||||
virtual bool getNetworkInfo(
|
||||
uint8_t networkItem,
|
||||
String &ssid,
|
||||
WiFiAuthMode &encryptionType,
|
||||
int32_t &RSSI,
|
||||
uint8_t *&BSSID,
|
||||
int32_t &channel
|
||||
) = 0;
|
||||
|
||||
virtual int16_t scanComplete() = 0;
|
||||
virtual void scanDelete() = 0;
|
||||
|
||||
virtual String SSID(uint8_t networkItem) = 0;
|
||||
virtual WiFiAuthMode encryptionType(uint8_t networkItem) = 0;
|
||||
virtual int32_t RSSI(uint8_t networkItem) = 0;
|
||||
virtual uint8_t *BSSID(uint8_t networkItem) = 0;
|
||||
virtual String BSSIDstr(uint8_t networkItem) = 0;
|
||||
virtual int32_t channel(uint8_t networkItem) = 0;
|
||||
};
|
||||
|
||||
class IWiFiAPClass {
|
||||
public:
|
||||
virtual bool softAP(
|
||||
const char *ssid, const char *passphrase = NULL, int channel = 1, bool ssidHidden = false, int maxClients = 4
|
||||
) = 0;
|
||||
virtual bool softAPConfig(IPAddress localIP, IPAddress gateway, IPAddress subnet) = 0;
|
||||
virtual bool softAPdisconnect(bool wifiOff = false) = 0;
|
||||
|
||||
virtual uint8_t softAPgetStationNum() = 0;
|
||||
|
||||
virtual IPAddress softAPIP() = 0;
|
||||
virtual IPAddress softAPBroadcastIP() = 0;
|
||||
virtual IPAddress softAPNetworkID() = 0;
|
||||
virtual uint8_t softAPSubnetCIDR() = 0;
|
||||
virtual bool softAPenableIpV6() = 0;
|
||||
virtual IPv6Address softAPIPv6() = 0;
|
||||
virtual const char *softAPgetHostname() = 0;
|
||||
virtual bool softAPsetHostname(const char *hostname) = 0;
|
||||
virtual uint8_t *softAPmacAddress(uint8_t *mac) = 0;
|
||||
virtual String softAPmacAddress(void) = 0;
|
||||
virtual const String softAPSSID(void) = 0;
|
||||
};
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
WiFiClientSecure.h - Base class that provides Client SSL to ESP32
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
Additions Copyright (C) 2017 Evandro Luis Copercini.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "WiFi.h"
|
||||
|
||||
class IWiFiClientSecure : public IWiFiClient {
|
||||
public:
|
||||
int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
|
||||
int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
|
||||
int connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey);
|
||||
int connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey);
|
||||
|
||||
int lastError(char *buf, const size_t size);
|
||||
void setInsecure(); // Don't validate the chain, just accept whatever is given. VERY INSECURE!
|
||||
void setPreSharedKey(const char *pskIdent, const char *psKey); // psKey in Hex
|
||||
void setCACert(const char *rootCA);
|
||||
void setCertificate(const char *client_ca);
|
||||
void setPrivateKey(const char *private_key);
|
||||
bool loadCACert(Stream &stream, size_t size);
|
||||
bool loadCertificate(Stream &stream, size_t size);
|
||||
bool loadPrivateKey(Stream &stream, size_t size);
|
||||
bool verify(const char *fingerprint, const char *domain_name);
|
||||
void setHandshakeTimeout(unsigned long handshake_timeout);
|
||||
|
||||
WiFiClientSecure &operator=(const WiFiClientSecure &other);
|
||||
|
||||
bool operator==(const bool value) {
|
||||
return bool() == value;
|
||||
}
|
||||
|
||||
bool operator!=(const bool value) {
|
||||
return bool() != value;
|
||||
}
|
||||
|
||||
bool operator==(const WiFiClientSecure &);
|
||||
|
||||
bool operator!=(const WiFiClientSecure &rhs) {
|
||||
return !this->operator==(rhs);
|
||||
};
|
||||
|
||||
using Print::write;
|
||||
};
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
ESP8266WiFiType.h - esp8266 Wifi support.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
Reworked by Markus Sattler, December 2015
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define WIFI_SCAN_RUNNING (-1)
|
||||
#define WIFI_SCAN_FAILED (-2)
|
||||
|
||||
#define WiFiMode_t wifi_mode_t
|
||||
#define WiFiMode wifi_mode_t
|
||||
#define WiFiStatus wl_status_t
|
||||
#define WiFiAuthMode wifi_auth_mode_t
|
||||
|
||||
#define WIFI_OFF WIFI_MODE_NULL
|
||||
#define WIFI_STA WIFI_MODE_STA
|
||||
#define WIFI_AP WIFI_MODE_AP
|
||||
#define WIFI_AP_STA WIFI_MODE_APSTA
|
||||
|
||||
typedef enum {
|
||||
WIFI_MODE_NULL = 0,
|
||||
WIFI_MODE_STA,
|
||||
WIFI_MODE_AP,
|
||||
WIFI_MODE_APSTA,
|
||||
WIFI_MODE_MAX,
|
||||
} wifi_mode_t;
|
||||
|
||||
typedef enum {
|
||||
WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library
|
||||
WL_IDLE_STATUS = 0,
|
||||
WL_NO_SSID_AVAIL = 1,
|
||||
WL_SCAN_COMPLETED = 2,
|
||||
WL_CONNECTED = 3,
|
||||
WL_CONNECT_FAILED = 4,
|
||||
WL_CONNECTION_LOST = 5,
|
||||
WL_DISCONNECTED = 6,
|
||||
} wl_status_t;
|
||||
|
||||
typedef enum {
|
||||
WIFI_AUTH_INVALID = 255,
|
||||
WIFI_AUTH_AUTO = 200,
|
||||
WIFI_AUTH_OPEN = 0,
|
||||
WIFI_AUTH_WEP = 1,
|
||||
WIFI_AUTH_WPA = 5,
|
||||
WIFI_AUTH_WPA2 = 6,
|
||||
WIFI_AUTH_WPA_PSK = 2,
|
||||
WIFI_AUTH_WPA2_PSK = 3,
|
||||
WIFI_AUTH_WPA_WPA2_PSK = 4,
|
||||
} wifi_auth_mode_t;
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <api/Udp.h>
|
||||
|
||||
class IWiFiUDP : public UDP {
|
||||
public:
|
||||
uint8_t beginMulticast(IPAddress ip, uint16_t port);
|
||||
int beginMulticastPacket();
|
||||
int beginPacket();
|
||||
};
|
||||
@@ -1,89 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "LibreTuyaConfig.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if LT_LOGGER_FILE
|
||||
#define LT_LOG(level, file, line, ...) lt_log(level, file, line, __VA_ARGS__)
|
||||
void lt_log(const uint8_t level, const char *filename, const unsigned short line, const char *format, ...);
|
||||
#else
|
||||
#define LT_LOG(level, file, line, ...) lt_log(level, __VA_ARGS__)
|
||||
void lt_log(const uint8_t level, const char *format, ...);
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_TRACE >= LT_LOGLEVEL
|
||||
#define LT_T(...) LT_LOG(LT_LEVEL_TRACE, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define LT_V(...) LT_LOG(LT_LEVEL_TRACE, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_T(...)
|
||||
#define LT_V(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_DEBUG >= LT_LOGLEVEL
|
||||
#define LT_D(...) LT_LOG(LT_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_D(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_INFO >= LT_LOGLEVEL
|
||||
#define LT_I(...) LT_LOG(LT_LEVEL_INFO, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_I(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_WARN >= LT_LOGLEVEL
|
||||
#define LT_W(...) LT_LOG(LT_LEVEL_WARN, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_W(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_ERROR >= LT_LOGLEVEL
|
||||
#define LT_E(...) LT_LOG(LT_LEVEL_ERROR, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_E(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_FATAL >= LT_LOGLEVEL
|
||||
#define LT_F(...) LT_LOG(LT_LEVEL_FATAL, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_F(...)
|
||||
#endif
|
||||
|
||||
#define LT_T_MOD(module, ...) \
|
||||
do { \
|
||||
if (module) { \
|
||||
LT_T(__VA_ARGS__) \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define LT_D_MOD(module, ...) \
|
||||
do { \
|
||||
if (module) { \
|
||||
LT_D(__VA_ARGS__) \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// WiFi.cpp
|
||||
#define LT_T_WG(...) LT_T_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
|
||||
#define LT_V_WG(...) LT_T_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
|
||||
#define LT_D_WG(...) LT_D_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
|
||||
|
||||
// WiFiClient.cpp
|
||||
#define LT_T_WC(...) LT_T_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
|
||||
#define LT_V_WC(...) LT_T_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
|
||||
#define LT_D_WC(...) LT_D_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
|
||||
|
||||
// WiFiServer.cpp
|
||||
#define LT_T_WS(...) LT_T_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
|
||||
#define LT_V_WS(...) LT_T_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
|
||||
#define LT_D_WS(...) LT_D_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
|
||||
|
||||
// WiFiSTA.cpp
|
||||
#define LT_T_WSTA(...) LT_T_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
|
||||
#define LT_V_WSTA(...) LT_T_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
|
||||
#define LT_D_WSTA(...) LT_D_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
|
||||
|
||||
// WiFiAP.cpp
|
||||
#define LT_T_WAP(...) LT_T_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
|
||||
#define LT_V_WAP(...) LT_T_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
|
||||
#define LT_D_WAP(...) LT_D_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
Arduino.h - Main include file for the Arduino SDK
|
||||
Copyright (c) 2005-2013 Arduino Team. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "WCharacterFixup.h"
|
||||
#endif
|
||||
#define PinMode PinModeArduino // this conflicts with SDK enum
|
||||
#include <api/ArduinoAPI.h>
|
||||
#include <api/LibreTuyaAPI.h>
|
||||
#undef PinMode
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
#define clockCyclesPerMicrosecond() ( SystemCoreClock / 1000000L )
|
||||
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (SystemCoreClock / 1000L) )
|
||||
#define microsecondsToClockCycles(a) ( (a) * (SystemCoreClock / 1000000L) )
|
||||
|
||||
#include "WVariant.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
// Include board variant
|
||||
#include "variant.h"
|
||||
|
||||
#define interrupts() vPortClearInterruptMask(0)
|
||||
#define noInterrupts() ulPortSetInterruptMask()
|
||||
|
||||
/*
|
||||
* \brief SAM3 products have only one reference for ADC
|
||||
*/
|
||||
typedef enum _eAnalogReference
|
||||
{
|
||||
AR_DEFAULT,
|
||||
} eAnalogReference ;
|
||||
@@ -1,7 +0,0 @@
|
||||
#include <api/Print.h>
|
||||
|
||||
class CountingStream : public Print
|
||||
{
|
||||
virtual size_t write(uint8_t) { return 1; };
|
||||
virtual size_t write(const uint8_t *buffer, size_t size) { return size; };
|
||||
};
|
||||
@@ -1,198 +0,0 @@
|
||||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef MBED_FUNCTIONPOINTER_H
|
||||
#define MBED_FUNCTIONPOINTER_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* If we had variaditic templates, this wouldn't be a problem, but until C++11 is enabled, we are stuck with multiple classes... */
|
||||
|
||||
/** A class for storing and calling a pointer to a static or member function
|
||||
*/
|
||||
template <typename R, typename A1>
|
||||
class FunctionPointerArg1{
|
||||
public:
|
||||
/** Create a FunctionPointer, attaching a static function
|
||||
*
|
||||
* @param function The static function to attach (default is none)
|
||||
*/
|
||||
FunctionPointerArg1(R (*function)(A1) = 0) {
|
||||
attach(function);
|
||||
}
|
||||
|
||||
/** Create a FunctionPointer, attaching a member function
|
||||
*
|
||||
* @param object The object pointer to invoke the member function on (i.e. the this pointer)
|
||||
* @param function The address of the member function to attach
|
||||
*/
|
||||
template<typename T>
|
||||
FunctionPointerArg1(T *object, R (T::*member)(A1)) {
|
||||
attach(object, member);
|
||||
}
|
||||
|
||||
/** Attach a static function
|
||||
*
|
||||
* @param function The static function to attach (default is none)
|
||||
*/
|
||||
void attach(R (*function)(A1)) {
|
||||
_p.function = function;
|
||||
_membercaller = 0;
|
||||
}
|
||||
|
||||
/** Attach a member function
|
||||
*
|
||||
* @param object The object pointer to invoke the member function on (i.e. the this pointer)
|
||||
* @param function The address of the member function to attach
|
||||
*/
|
||||
template<typename T>
|
||||
void attach(T *object, R (T::*member)(A1)) {
|
||||
_p.object = static_cast<void*>(object);
|
||||
*reinterpret_cast<R (T::**)(A1)>(_member) = member;
|
||||
_membercaller = &FunctionPointerArg1::membercaller<T>;
|
||||
}
|
||||
|
||||
/** Call the attached static or member function
|
||||
*/
|
||||
R call(A1 a) {
|
||||
if (_membercaller == 0 && _p.function) {
|
||||
return _p.function(a);
|
||||
} else if (_membercaller && _p.object) {
|
||||
return _membercaller(_p.object, _member, a);
|
||||
}
|
||||
return (R)0;
|
||||
}
|
||||
|
||||
/** Get registered static function
|
||||
*/
|
||||
R(*get_function(A1))() {
|
||||
return _membercaller ? (R(*)(A1))0 : (R(*)(A1))_p.function;
|
||||
}
|
||||
|
||||
R operator ()(A1 a) {
|
||||
return call(a);
|
||||
}
|
||||
operator bool(void) const {
|
||||
return (_membercaller != NULL ? _p.object : (void*)_p.function) != NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static R membercaller(void *object, uintptr_t *member, A1 a) {
|
||||
T* o = static_cast<T*>(object);
|
||||
R (T::**m)(A1) = reinterpret_cast<R (T::**)(A1)>(member);
|
||||
return (o->**m)(a);
|
||||
}
|
||||
|
||||
union {
|
||||
R (*function)(A1); // static function pointer
|
||||
void *object; // object this pointer
|
||||
} _p;
|
||||
uintptr_t _member[4]; // aligned raw member function pointer storage - converted back by registered _membercaller
|
||||
R (*_membercaller)(void*, uintptr_t*, A1); // registered membercaller function to convert back and call _m.member on _object
|
||||
};
|
||||
|
||||
/** A class for storing and calling a pointer to a static or member function (R ()(void))
|
||||
*/
|
||||
template <typename R>
|
||||
class FunctionPointerArg1<R, void>{
|
||||
public:
|
||||
/** Create a FunctionPointer, attaching a static function
|
||||
*
|
||||
* @param function The static function to attach (default is none)
|
||||
*/
|
||||
FunctionPointerArg1(R (*function)(void) = 0) {
|
||||
attach(function);
|
||||
}
|
||||
|
||||
/** Create a FunctionPointer, attaching a member function
|
||||
*
|
||||
* @param object The object pointer to invoke the member function on (i.e. the this pointer)
|
||||
* @param function The address of the void member function to attach
|
||||
*/
|
||||
template<typename T>
|
||||
FunctionPointerArg1(T *object, R (T::*member)(void)) {
|
||||
attach(object, member);
|
||||
}
|
||||
|
||||
/** Attach a static function
|
||||
*
|
||||
* @param function The void static function to attach (default is none)
|
||||
*/
|
||||
void attach(R (*function)(void)) {
|
||||
_p.function = function;
|
||||
_membercaller = 0;
|
||||
}
|
||||
|
||||
/** Attach a member function
|
||||
*
|
||||
* @param object The object pointer to invoke the member function on (i.e. the this pointer)
|
||||
* @param function The address of the void member function to attach
|
||||
*/
|
||||
template<typename T>
|
||||
void attach(T *object, R (T::*member)(void)) {
|
||||
_p.object = static_cast<void*>(object);
|
||||
*reinterpret_cast<R (T::**)(void)>(_member) = member;
|
||||
_membercaller = &FunctionPointerArg1::membercaller<T>;
|
||||
}
|
||||
|
||||
/** Call the attached static or member function
|
||||
*/
|
||||
R call(){
|
||||
if (_membercaller == 0 && _p.function) {
|
||||
return _p.function();
|
||||
} else if (_membercaller && _p.object) {
|
||||
return _membercaller(_p.object, _member);
|
||||
}
|
||||
return (R)0;
|
||||
}
|
||||
|
||||
/** Get registered static function
|
||||
*/
|
||||
R(*get_function())() {
|
||||
return _membercaller ? (R(*)())0 : (R(*)())_p.function;
|
||||
}
|
||||
|
||||
R operator ()(void) {
|
||||
return call();
|
||||
}
|
||||
operator bool(void) const {
|
||||
return (_membercaller != NULL ? _p.object : (void*)_p.function) != NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static R membercaller(void *object, uintptr_t *member) {
|
||||
T* o = static_cast<T*>(object);
|
||||
R (T::**m)(void) = reinterpret_cast<R (T::**)(void)>(member);
|
||||
return (o->**m)();
|
||||
}
|
||||
|
||||
union {
|
||||
R (*function)(void); // static function pointer
|
||||
void *object; // object this pointer
|
||||
} _p;
|
||||
uintptr_t _member[4]; // aligned raw member function pointer storage - converted back by registered _membercaller
|
||||
R (*_membercaller)(void*, uintptr_t*); // registered membercaller function to convert back and call _m.member on _object
|
||||
};
|
||||
|
||||
typedef FunctionPointerArg1<void, void> FunctionPointer;
|
||||
typedef FunctionPointerArg1<void, int> event_callback_t;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#include "LOGUARTClass.h"
|
||||
|
||||
#define LOG_UART_MODIFIABLE_BAUD_RATE 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "osdep_service.h"
|
||||
#include "rtl8710b.h"
|
||||
extern int LOGUART_SetBaud(uint32_t BaudRate); // from fixups/log_uart.c
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
RingBuffer rx_buffer0;
|
||||
|
||||
LOGUARTClass::LOGUARTClass(int dwIrq, RingBuffer* pRx_buffer )
|
||||
{
|
||||
_rx_buffer = pRx_buffer;
|
||||
_dwIrq = dwIrq;
|
||||
}
|
||||
|
||||
// Protected Methods //////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
// Public Methods //////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void IrqHandler( void )
|
||||
{
|
||||
|
||||
uint8_t data = 0;
|
||||
BOOL PullMode = _FALSE;
|
||||
uint32_t IrqEn = DiagGetIsrEnReg();
|
||||
|
||||
DiagSetIsrEnReg(0);
|
||||
|
||||
data = DiagGetChar(PullMode);
|
||||
if ( data > 0 )
|
||||
rx_buffer0.store_char(data);
|
||||
|
||||
DiagSetIsrEnReg(IrqEn);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void LOGUARTClass::begin( const uint32_t dwBaudRate )
|
||||
{
|
||||
DIAG_UartReInit((IRQ_FUN) IrqHandler);
|
||||
NVIC_SetPriority(UART_LOG_IRQ, 10);
|
||||
LOGUART_SetBaud(dwBaudRate);
|
||||
}
|
||||
|
||||
void LOGUARTClass::end( void )
|
||||
{
|
||||
// clear any received data
|
||||
_rx_buffer->_iHead = _rx_buffer->_iTail ;
|
||||
}
|
||||
|
||||
int LOGUARTClass::available( void )
|
||||
{
|
||||
return (uint32_t)(SERIAL_BUFFER_SIZE + _rx_buffer->_iHead - _rx_buffer->_iTail) % SERIAL_BUFFER_SIZE ;
|
||||
}
|
||||
|
||||
int LOGUARTClass::peek( void )
|
||||
{
|
||||
|
||||
if ( _rx_buffer->_iHead == _rx_buffer->_iTail )
|
||||
return -1 ;
|
||||
|
||||
return _rx_buffer->_aucBuffer[_rx_buffer->_iTail] ;
|
||||
|
||||
}
|
||||
|
||||
int LOGUARTClass::read( void )
|
||||
{
|
||||
// if the head isn't ahead of the tail, we don't have any characters
|
||||
if ( _rx_buffer->_iHead == _rx_buffer->_iTail )
|
||||
return -1 ;
|
||||
|
||||
uint8_t uc = _rx_buffer->_aucBuffer[_rx_buffer->_iTail] ;
|
||||
_rx_buffer->_iTail = (unsigned int)(_rx_buffer->_iTail + 1) % SERIAL_BUFFER_SIZE ;
|
||||
return uc ;
|
||||
|
||||
}
|
||||
|
||||
void LOGUARTClass::flush( void )
|
||||
{
|
||||
// TODO:
|
||||
// while ( serial_writable(&(this->sobj)) != 1 );
|
||||
/*
|
||||
// Wait for transmission to complete
|
||||
while ((_pUart->UART_SR & UART_SR_TXRDY) != UART_SR_TXRDY)
|
||||
;
|
||||
*/
|
||||
}
|
||||
|
||||
size_t LOGUARTClass::write( const uint8_t uc_data )
|
||||
{
|
||||
DiagPutChar(uc_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LOGUARTClass Serial(UART_LOG_IRQ, &rx_buffer0);
|
||||
|
||||
bool Serial_available() {
|
||||
return Serial.available() > 0;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/HardwareSerial.h"
|
||||
#include "api/RingBuffer.h"
|
||||
|
||||
using namespace arduino;
|
||||
|
||||
class LOGUARTClass : public HardwareSerial
|
||||
{
|
||||
public:
|
||||
LOGUARTClass(int dwIrq, RingBuffer* pRx_buffer );
|
||||
|
||||
void begin(const uint32_t dwBaudRate);
|
||||
inline void begin(const uint32_t dwBaudRate, uint16_t config) {
|
||||
begin(dwBaudRate); // TODO implement this properly
|
||||
}
|
||||
void end(void);
|
||||
int available(void);
|
||||
int peek(void);
|
||||
int read(void);
|
||||
void flush(void);
|
||||
size_t write(const uint8_t c);
|
||||
|
||||
using Print::write; // pull in write(str) and write(buf, size) from Print
|
||||
|
||||
operator bool() { return true; }; // UART always active
|
||||
|
||||
protected:
|
||||
RingBuffer *_rx_buffer;
|
||||
|
||||
int _dwIrq;
|
||||
|
||||
private:
|
||||
friend bool Serial_available();
|
||||
};
|
||||
@@ -1,59 +0,0 @@
|
||||
#include "PowerManagement.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#include "freertos_pmu.h"
|
||||
#include "sys_api.h"
|
||||
#include "sleep_ex_api.h"
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "variant.h"
|
||||
|
||||
#if defined(BOARD_RTL8195A)
|
||||
#define SAVE_LOCK_PIN 18
|
||||
#elif defined(BOARD_RTL8710)
|
||||
#define SAVE_LOCK_PIN 7 // PB_1
|
||||
#else
|
||||
#define SAVE_LOCK_PIN 18
|
||||
#endif
|
||||
|
||||
bool PowerManagementClass::reservePLL = true;
|
||||
|
||||
void PowerManagementClass::sleep(uint32_t bitflg) {
|
||||
if (!safeLock()) {
|
||||
pmu_release_wakelock(bitflg);
|
||||
}
|
||||
}
|
||||
|
||||
void PowerManagementClass::sleep(void) {
|
||||
if (!safeLock()) {
|
||||
pmu_release_wakelock(BIT(PMU_OS));
|
||||
}
|
||||
}
|
||||
|
||||
void PowerManagementClass::active(uint32_t bitflg) {
|
||||
pmu_acquire_wakelock(bitflg);
|
||||
}
|
||||
|
||||
void PowerManagementClass::active(void) {
|
||||
pmu_acquire_wakelock(BIT(PMU_OS));
|
||||
}
|
||||
|
||||
void PowerManagementClass::deepsleep(uint32_t duration_ms) {
|
||||
if (!safeLock()) {
|
||||
deepsleep_ex(DSLEEP_WAKEUP_BY_TIMER, duration_ms);
|
||||
}
|
||||
}
|
||||
|
||||
bool PowerManagementClass::safeLock() {
|
||||
pinMode(SAVE_LOCK_PIN, INPUT_PULLUP);
|
||||
return (digitalRead(SAVE_LOCK_PIN) == 1) ? false : true;
|
||||
}
|
||||
|
||||
void PowerManagementClass::softReset() {
|
||||
sys_reset();
|
||||
}
|
||||
|
||||
PowerManagementClass PowerManagement;
|
||||
@@ -1,76 +0,0 @@
|
||||
#ifndef _POWER_MANAGEMENT_H_
|
||||
#define _POWER_MANAGEMENT_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/**
|
||||
* @class PowerManagementClass PowerManagement.h
|
||||
* @brief Power management in Ameba
|
||||
*/
|
||||
class PowerManagementClass {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Allow OS automatically save power while idle
|
||||
*
|
||||
* As OS consider it would idle for more than 2s, it will invoke system suspend.
|
||||
* If wlan is associated with AP, than it will under asslociated idle state.
|
||||
*/
|
||||
static void sleep(void);
|
||||
static void sleep(uint32_t bitflg);
|
||||
|
||||
/**
|
||||
* @brief Disallow OS automatically save power while idle
|
||||
*/
|
||||
static void active(void);
|
||||
static void active(uint32_t bitflg);
|
||||
|
||||
/**
|
||||
* @brief Reserved PLL while sleep
|
||||
*
|
||||
* Reserve PLL would keep FIFO of peripherals (Ex. UART) but cost more power (around 5mA).
|
||||
* If we don't reserve PLL, it saves more power but we might missing data because FIFO is turned of this way.
|
||||
*
|
||||
* @param[in] reserve true for reserved, false for non-reserved
|
||||
*/
|
||||
static void setPllReserved(bool reserve);
|
||||
|
||||
/**
|
||||
* @brief Enter deepsleep immediately
|
||||
*
|
||||
* Invoke deepsleep would make system enter deepsleep state immediately.
|
||||
* It's the state that saves most power.
|
||||
* As it wakeup from deepsleep, the system would behave just like reboot.
|
||||
*
|
||||
* @param[in] duration_ms wakeup after specific time in unit of millisecond
|
||||
*/
|
||||
static void deepsleep(uint32_t duration_ms);
|
||||
|
||||
/**
|
||||
* @brief Check if system is allowed enter any power save state
|
||||
*
|
||||
* The pin 18 (GPIOE_5) is designed as safe lock.
|
||||
* If pin 18 is HIGH, then we prevent Ameba enter any power save state.\n\n
|
||||
* Under any power save state, we are not able to flash image to Ameba.
|
||||
* Thus if user misuse deepsleep and make Ameba enter deepsleep immediately after boot up,
|
||||
* then he would find it's hard to flash image.
|
||||
* In this case, he can pull up pin 18.
|
||||
*
|
||||
* @return true if system not allowed enter any power save state, and false vise versa
|
||||
*/
|
||||
static bool safeLock();
|
||||
|
||||
/**
|
||||
* @brief Reboot system
|
||||
*
|
||||
* Reboot system in soft way. Some registers is not powered off in this case, but mostly we could regard this as reboot.
|
||||
*/
|
||||
static void softReset();
|
||||
|
||||
private:
|
||||
static bool reservePLL;
|
||||
};
|
||||
|
||||
extern PowerManagementClass PowerManagement;
|
||||
|
||||
#endif
|
||||
@@ -1,17 +0,0 @@
|
||||
#if 1 // !defined(BOARD_RTL8710)
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern void _tone(uint32_t ulPin, unsigned int frequency, unsigned long duration);
|
||||
}
|
||||
#endif
|
||||
|
||||
// a wrapper that support default value of duration
|
||||
void tone(uint32_t ulPin, unsigned int frequency, unsigned long duration)
|
||||
{
|
||||
_tone(ulPin, frequency, duration);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,84 +0,0 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "gpio_api.h"
|
||||
#include "gpio_irq_api.h"
|
||||
#include "gpio_irq_ex_api.h"
|
||||
|
||||
extern void *gpio_pin_struct[PINS_COUNT];
|
||||
extern void *gpio_irq_handler_list[PINS_COUNT];
|
||||
|
||||
void gpioIrqHandler(uint32_t id, gpio_irq_event event) {
|
||||
if (gpio_irq_handler_list[id] != NULL) {
|
||||
((void (*)(uint32_t, uint32_t))gpio_irq_handler_list[id])(id, (uint32_t)event);
|
||||
}
|
||||
}
|
||||
|
||||
void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode) {
|
||||
if (pinInvalid(interruptNumber))
|
||||
return;
|
||||
|
||||
gpio_irq_handler_list[interruptNumber] = callback;
|
||||
|
||||
if (g_APinDescription[interruptNumber].ulPinType == PIO_GPIO_IRQ &&
|
||||
g_APinDescription[interruptNumber].ulPinMode == mode)
|
||||
// Nothing changes in pin mode
|
||||
return;
|
||||
|
||||
if (g_APinDescription[interruptNumber].ulPinType != PIO_GPIO_IRQ)
|
||||
// pin mode changes; deinit gpio and free memory
|
||||
pinRemoveMode(interruptNumber);
|
||||
|
||||
gpio_irq_t *gpio;
|
||||
|
||||
if (g_APinDescription[interruptNumber].ulPinType == NOT_INITIAL) {
|
||||
// allocate memory if pin not used before
|
||||
gpio = malloc(sizeof(gpio_irq_t));
|
||||
gpio_pin_struct[interruptNumber] = gpio;
|
||||
gpio_irq_init(gpio, g_APinDescription[interruptNumber].pinname, gpioIrqHandler, interruptNumber);
|
||||
g_APinDescription[interruptNumber].ulPinType = PIO_GPIO_IRQ;
|
||||
} else {
|
||||
// pin already used as irq
|
||||
gpio = (gpio_irq_t *)gpio_pin_struct[interruptNumber];
|
||||
}
|
||||
g_APinDescription[interruptNumber].ulPinMode = mode;
|
||||
|
||||
gpio_irq_event event;
|
||||
|
||||
switch (mode) {
|
||||
case LOW:
|
||||
event = IRQ_LOW;
|
||||
break;
|
||||
case HIGH:
|
||||
event = IRQ_HIGH;
|
||||
break;
|
||||
case FALLING:
|
||||
event = IRQ_FALL;
|
||||
break;
|
||||
case RISING:
|
||||
event = IRQ_RISE;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_irq_set(gpio, event, 1);
|
||||
gpio_irq_enable(gpio);
|
||||
}
|
||||
|
||||
void detachInterrupt(pin_size_t interruptNumber) {
|
||||
if (pinInvalid(interruptNumber))
|
||||
return;
|
||||
|
||||
if (g_APinDescription[interruptNumber].ulPinType == PIO_GPIO_IRQ) {
|
||||
pinRemoveMode(interruptNumber);
|
||||
}
|
||||
gpio_irq_handler_list[interruptNumber] = NULL;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "api/Common.h"
|
||||
|
||||
extern "C" {
|
||||
extern void rtl_srandom( uint32_t seed );
|
||||
extern uint32_t rtl_random( void );
|
||||
}
|
||||
|
||||
#ifndef srand
|
||||
#define srand rtl_srandom
|
||||
#endif
|
||||
#ifndef rand
|
||||
#define rand rtl_random
|
||||
#endif
|
||||
|
||||
extern void randomSeed( uint32_t dwSeed )
|
||||
{
|
||||
if ( dwSeed != 0 )
|
||||
{
|
||||
srand( dwSeed ) ;
|
||||
}
|
||||
}
|
||||
|
||||
extern long random( long howbig )
|
||||
{
|
||||
if ( howbig == 0 )
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
return rand() % howbig;
|
||||
}
|
||||
|
||||
extern long random( long howsmall, long howbig )
|
||||
{
|
||||
if (howsmall >= howbig)
|
||||
{
|
||||
return howsmall;
|
||||
}
|
||||
|
||||
long diff = howbig - howsmall;
|
||||
|
||||
return random(diff) + howsmall;
|
||||
}
|
||||
|
||||
extern long map(long x, long in_min, long in_max, long out_min, long out_max)
|
||||
{
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
extern uint16_t makeWord( uint16_t w )
|
||||
{
|
||||
return w ;
|
||||
}
|
||||
|
||||
extern uint16_t makeWord( uint8_t h, uint8_t l )
|
||||
{
|
||||
return (h << 8) | l ;
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "wiring_os.h"
|
||||
#include "wiring_watchdog.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#define boolean boolean_rtl
|
||||
#include "rtl_lib.h"
|
||||
#undef boolean
|
||||
|
||||
/* moved from Arduino.h */
|
||||
/*
|
||||
* \brief Set CPU CLK 166MHz
|
||||
* clk : 0 - 166666666 Hz, 1 - 83333333 Hz, 2 - 41666666 Hz, 3 - 20833333 Hz, 4 - 10416666 Hz, 5 - 4000000 Hz
|
||||
* baud: 38400,...
|
||||
*/
|
||||
extern void Init_CPU_CLK_UART(int clkn, int baud);
|
||||
extern void sys_info(void);
|
||||
/* HalGetChipId:
|
||||
* 0xff - RTL8711AM, 0xfe - RTL8195AM, 0xfd - RTL8711AF,
|
||||
* 0xfc - RTL8710AF, 0xfb - RTL8711AN, 0xfa - RTL8710AM */
|
||||
extern unsigned char HalGetChipId(void);
|
||||
extern unsigned int HalGetCpuClk(void);
|
||||
|
||||
extern void wait_us(int us);
|
||||
#define delay_us wait_us
|
||||
|
||||
extern void yield(void);
|
||||
|
||||
#ifndef printf
|
||||
#define printf rtl_printf
|
||||
#endif
|
||||
#ifndef sprintf
|
||||
#define sprintf rtl_sprintf
|
||||
#endif
|
||||
|
||||
#define NOT_INITIAL (1UL<<0)
|
||||
#define PIO_GPIO (1UL<<1)
|
||||
#define PIO_PWM (1UL<<2)
|
||||
#define PIO_I2C (1UL<<3)
|
||||
#define PIO_ADC (1UL<<4)
|
||||
#define PIO_DAC (1UL<<5)
|
||||
#define PIO_GPIO_IRQ (1UL<<6)
|
||||
|
||||
#define PWM_MODE_ENABLED 1
|
||||
#define PWM_MODE_DISABLED 0
|
||||
|
||||
/* Types used for the tables below */
|
||||
typedef struct _PinDescription
|
||||
{
|
||||
// HW PinNames
|
||||
uint32_t pinname;
|
||||
// Current Pin Type
|
||||
uint32_t ulPinType;
|
||||
// Supported Pin Function
|
||||
uint32_t ulPinAttribute;
|
||||
// Current Pin Mode
|
||||
uint32_t ulPinMode;
|
||||
} PinDescription ;
|
||||
|
||||
/* Pins table to be instanciated into variant.cpp */
|
||||
extern PinDescription g_APinDescription[];
|
||||
|
||||
extern bool pinInvalid(pin_size_t pinNumber);
|
||||
extern void pinRemoveMode(pin_size_t pinNumber);
|
||||
|
||||
/* moved from wiring_digital.h */
|
||||
/**************************** Extend API by RTK ***********************************/
|
||||
extern uint32_t digitalPinToPort( uint32_t pinNumber );
|
||||
extern uint32_t digitalPinToBitMask( uint32_t pinNumber );
|
||||
|
||||
/* moved from wiring_analog.h */
|
||||
/*
|
||||
* \brief Set the resolution of analogRead return values. Default is 10 bits (range from 0 to 1023).
|
||||
*
|
||||
* \param res
|
||||
*/
|
||||
extern void analogReadResolution(int res);
|
||||
/*
|
||||
* \brief Set the resolution of analogWrite parameters. Default is 8 bits (range from 0 to 255).
|
||||
*
|
||||
* \param res
|
||||
*/
|
||||
extern void analogWriteResolution(int res);
|
||||
extern void analogOutputInit( void ) ;
|
||||
extern void analogWritePeriod(int us);
|
||||
|
||||
/* moved from wiring_constants.h */
|
||||
#define DEFAULT 1
|
||||
#define EXTERNAL 0
|
||||
|
||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||
|
||||
extern uint32_t ulPortSetInterruptMask( void );
|
||||
extern void vPortClearInterruptMask( uint32_t ulNewMask );
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* WebSocketClient + SSL/TSL
|
||||
* RTL8710AF pvvx 12/12/2016
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "WebSocketClient.h"
|
||||
|
||||
WebSocketClient::WebSocketClient() {
|
||||
}
|
||||
|
||||
WebSocketClient::WebSocketClient(char *url, int port, char *path, char* origin) {
|
||||
client = create_wsclient(url, port, path, origin);
|
||||
}
|
||||
|
||||
WebSocketClient::~WebSocketClient() {
|
||||
close();
|
||||
}
|
||||
|
||||
int WebSocketClient::begin(char *url, int port, char *path, char* origin) {
|
||||
client = create_wsclient(url, port, path, origin);
|
||||
if(client != NULL) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
int WebSocketClient::connect() {
|
||||
if(client != NULL) return ws_connect_url(client);
|
||||
else return -1;
|
||||
}
|
||||
|
||||
void WebSocketClient::send(char* message, int message_len, int use_mask) {
|
||||
if(client != NULL && client->readyState > CLOSED) {
|
||||
ws_send(message, message_len, use_mask, client);
|
||||
ws_poll(0, client);
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketClient::sendBinary(uint8_t* message, int message_len, int use_mask) {
|
||||
if(client != NULL && client->readyState > CLOSED) {
|
||||
ws_sendBinary(message, message_len, use_mask, client);
|
||||
ws_poll(0, client);
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketClient::sendPing() {
|
||||
if(client != NULL && client->readyState > CLOSED) {
|
||||
ws_sendPing(client);
|
||||
ws_poll(0, client);
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketClient::poll(int timeout) {
|
||||
if(client != NULL) ws_poll(timeout, client);
|
||||
}
|
||||
|
||||
readyStateValues WebSocketClient::getReadyState() {
|
||||
if(client != NULL) return ws_getReadyState(client);
|
||||
else return CLOSED;
|
||||
}
|
||||
|
||||
void WebSocketClient::dispatch(void (*callback)(wsclient_context *, int))
|
||||
{
|
||||
if(client != NULL) ws_dispatch(callback);
|
||||
}
|
||||
|
||||
void WebSocketClient::close() {
|
||||
if(client != NULL) {
|
||||
ws_close(client);
|
||||
if(client->ssl) {
|
||||
free(client->ssl);
|
||||
client->ssl = NULL;
|
||||
}
|
||||
client = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void set_ssl_func(wsclient_context *wsclient); // in example_wsclient.c
|
||||
|
||||
void WebSocketClient::ssl_func_on(void)
|
||||
{
|
||||
set_ssl_func(client);
|
||||
/*
|
||||
client->fun_ops.ssl_fun_ops.memory_set_own = memory_set_own;
|
||||
client->fun_ops.ssl_fun_ops.net_connect = net_connect;
|
||||
client->fun_ops.ssl_fun_ops.ssl_init = ssl_init;
|
||||
client->fun_ops.ssl_fun_ops.ssl_set_endpoint = ssl_set_endpoint;
|
||||
client->fun_ops.ssl_fun_ops.ssl_set_authmode = ssl_set_authmode;
|
||||
client->fun_ops.ssl_fun_ops.ssl_set_rng = ssl_set_rng;
|
||||
client->fun_ops.ssl_fun_ops.ssl_set_bio = ssl_set_bio;
|
||||
client->fun_ops.ssl_fun_ops.ssl_handshake = ssl_handshake;
|
||||
client->fun_ops.ssl_fun_ops.net_close = net_close;
|
||||
client->fun_ops.ssl_fun_ops.ssl_free = ssl_free;
|
||||
client->fun_ops.ssl_fun_ops.ssl_read = ssl_read;
|
||||
client->fun_ops.ssl_fun_ops.ssl_write = ssl_write;
|
||||
client->fun_ops.ssl_fun_ops.net_recv = net_recv;
|
||||
client->fun_ops.ssl_fun_ops.net_send = net_send;
|
||||
client->ssl = (void *)zalloc(sizeof(struct _ssl_context)); // 380 bytes
|
||||
*/
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* WebSocketClient + SSL/TSL
|
||||
* RTL8710AF pvvx 12/12/2016
|
||||
*
|
||||
*/
|
||||
#ifndef WEBSOCKETCLIENT_H_
|
||||
#define WEBSOCKETCLIENT_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
extern "C" {
|
||||
#include "libwsclient.h"
|
||||
#include "wsclient_api.h"
|
||||
}
|
||||
|
||||
class WebSocketClient {
|
||||
public:
|
||||
WebSocketClient();
|
||||
~WebSocketClient();
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : begin
|
||||
** Description : Creating the websocket client context structure
|
||||
** Input : url:websocket server's url
|
||||
** port:websocket server's port, if not given, default 80 for "ws", 443 for "wss"
|
||||
** origin: the address or url of your self
|
||||
** Return : Ok: 1
|
||||
** Failed: 0
|
||||
**************************************************************************************************/
|
||||
WebSocketClient(char *url, int port, char *path = NULL, char* origin = NULL);
|
||||
int begin(char *url, int port, char *path = NULL, char* origin = NULL);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : connect
|
||||
** Description : Connecting to the websocket server
|
||||
** Input : wsclient: the websocket client context created by create_wsclientfunction
|
||||
** Return : Connected: the socket value
|
||||
** Failed: -1
|
||||
**************************************************************************************************/
|
||||
int connect();
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : ws_send
|
||||
** Description : Create the sending string data and copy to tx_buf
|
||||
** Input : message: the string that send to server(cannot exceeding the MAX_DATA_LEN
|
||||
** message_len: the length of the string
|
||||
** use_mask: 0/1; 1 means using mask for bynary
|
||||
** wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void send(char* message, int message_len, int use_mask);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : sendBinary
|
||||
** Description : Create the sending binary data and copy to tx_buf
|
||||
** Input : message: the binary that send to server(cannot exceeding the MAX_DATA_LEN
|
||||
** message_len: the length of the binary
|
||||
** use_mask: 0/1; 1 means using mask for bynary
|
||||
** wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void sendBinary(uint8_t* message, int message_len, int use_mask);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : sendPing
|
||||
** Description : Sending Ping to websocket server
|
||||
** Input : wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void sendPing();
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : poll
|
||||
** Description : Receicing data from server and send the data in tx_buf
|
||||
** Input : timeout(in milliseconds)
|
||||
wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void poll(int timeout);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : dispatch
|
||||
** Description : callback function when getting message from server
|
||||
** Input : function that resolve the message received and the message length
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void dispatch(void (*callback)(wsclient_context *, int));
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : getReadyState
|
||||
** Description : Getting the connection status
|
||||
** Input : wsclient: the websocket client context
|
||||
** Return : readyStateValues(4 types: CLOSING, CLOSED, CONNECTING, OPEN )
|
||||
**************************************************************************************************/
|
||||
readyStateValues getReadyState();
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : close
|
||||
** Description : Closing the connection with websocket server
|
||||
** Input : wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void close();
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : ssl_func_on
|
||||
** Description : Set SSL/TSL function
|
||||
** Input : None
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void ssl_func_on(void);
|
||||
|
||||
private:
|
||||
wsclient_context *client;
|
||||
};
|
||||
|
||||
#endif // WEBSOCKETCLIENT_H_
|
||||
@@ -1,214 +0,0 @@
|
||||
#include <platform_opts.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <platform/platform_stdlib.h>
|
||||
#include "ard_socket.h"
|
||||
|
||||
int start_server(uint16_t port, uint8_t protMode)
|
||||
{
|
||||
int _sock;
|
||||
int timeout;
|
||||
|
||||
if(protMode == 0) {
|
||||
timeout = 3000;
|
||||
_sock = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
lwip_setsockopt(_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
} else {
|
||||
timeout = 1000;
|
||||
_sock = lwip_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
lwip_setsockopt(_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
if (_sock < 0) {
|
||||
printf("\r\nERROR opening socket\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_in localHost;
|
||||
memset(&localHost, 0, sizeof(localHost));
|
||||
|
||||
localHost.sin_family = AF_INET;
|
||||
localHost.sin_port = htons(port);
|
||||
localHost.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if (lwip_bind(_sock, (struct sockaddr *)&localHost, sizeof(localHost)) < 0) {
|
||||
printf("\r\nERROR on binding\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _sock;
|
||||
}
|
||||
|
||||
int sock_listen(int sock, int max)
|
||||
{
|
||||
if(lwip_listen(sock , max) < 0){
|
||||
printf("\r\nERROR on listening\r\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_available(int sock)
|
||||
{
|
||||
int enable = 1;
|
||||
int timeout;
|
||||
int client_fd;
|
||||
int err;
|
||||
struct sockaddr_in cli_addr;
|
||||
|
||||
socklen_t client = sizeof(cli_addr);
|
||||
|
||||
do {
|
||||
client_fd = lwip_accept(sock, (struct sockaddr *) &cli_addr, &client);
|
||||
if (client_fd < 0) {
|
||||
err = get_sock_errno(sock);
|
||||
if (err != EAGAIN) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (client_fd < 0);
|
||||
|
||||
if(client_fd < 0){
|
||||
printf("\r\nERROR on accept\r\n");
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
timeout = 3000;
|
||||
lwip_setsockopt(client_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
timeout = 30000;
|
||||
lwip_setsockopt(client_fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
|
||||
lwip_setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
|
||||
lwip_setsockopt(client_fd, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
|
||||
printf("\r\nA client connected to this server :\r\n[PORT]: %d\r\n[IP]:%s\r\n\r\n", ntohs(cli_addr.sin_port), inet_ntoa(cli_addr.sin_addr.s_addr));
|
||||
return client_fd;
|
||||
}
|
||||
}
|
||||
|
||||
int get_receive(int sock, uint8_t* data, int length, int flag, uint32_t *peer_addr, uint16_t *peer_port)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sockaddr from;
|
||||
socklen_t fromlen;
|
||||
|
||||
uint8_t backup_recvtimeout = 0;
|
||||
int backup_recv_timeout, recv_timeout, len;
|
||||
|
||||
if (flag & 0x01) {
|
||||
// for MSG_PEEK, we try to peek packets by changing receiving timeout to 10ms
|
||||
ret = lwip_getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &backup_recv_timeout, &len);
|
||||
if (ret >= 0) {
|
||||
recv_timeout = 10;
|
||||
ret = lwip_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &recv_timeout, sizeof(recv_timeout));
|
||||
if (ret >= 0) {
|
||||
backup_recvtimeout = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = lwip_recvfrom(sock, data, length, flag, &from, &fromlen);
|
||||
if ( ret >= 0 ) {
|
||||
if (peer_addr != NULL) {
|
||||
*peer_addr = ((struct sockaddr_in *)&from)->sin_addr.s_addr;
|
||||
}
|
||||
if (peer_port != NULL) {
|
||||
*peer_port = ntohs(((struct sockaddr_in *)&from)->sin_port);
|
||||
}
|
||||
}
|
||||
|
||||
if ((flag & 0x01) && (backup_recvtimeout == 1)) {
|
||||
// restore receiving timeout
|
||||
lwip_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &backup_recv_timeout, sizeof(recv_timeout));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_sock_errno(int sock)
|
||||
{
|
||||
int so_error;
|
||||
socklen_t len = sizeof(so_error);
|
||||
getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &len);
|
||||
return so_error;
|
||||
}
|
||||
|
||||
int set_sock_recv_timeout(int sock, int timeout)
|
||||
{
|
||||
return lwip_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
void stop_socket(int sock)
|
||||
{
|
||||
lwip_close(sock);
|
||||
}
|
||||
|
||||
int send_data(int sock, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = lwip_write(sock, data, len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sendto_data(int sock, const uint8_t *data, uint16_t len, uint32_t peer_ip, uint16_t peer_port)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct sockaddr_in peer_addr;
|
||||
memset(&peer_addr, 0, sizeof(peer_addr));
|
||||
peer_addr.sin_family = AF_INET;
|
||||
peer_addr.sin_addr.s_addr = peer_ip;
|
||||
peer_addr.sin_port = htons(peer_port);
|
||||
|
||||
ret = lwip_sendto(sock, data, len, 0, (struct sockaddr*)&peer_addr, sizeof(struct sockaddr_in));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int start_client(uint32_t ipAddress, uint16_t port, uint8_t protMode)
|
||||
{
|
||||
int enable = 1;
|
||||
int timeout;
|
||||
int _sock;
|
||||
|
||||
if(protMode == 0)//tcp
|
||||
_sock = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
else
|
||||
_sock = lwip_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
if (_sock < 0) {
|
||||
printf("\r\nERROR opening socket\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_in serv_addr;
|
||||
memset(&serv_addr, 0, sizeof(serv_addr));
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_addr.s_addr = ipAddress;
|
||||
serv_addr.sin_port = htons(port);
|
||||
|
||||
if (protMode == 0){//TCP MODE
|
||||
if(connect(_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0){
|
||||
printf("\r\nConnect to Server successful!\r\n");
|
||||
|
||||
timeout = 3000;
|
||||
lwip_setsockopt(_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
timeout = 30000;
|
||||
lwip_setsockopt(_sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
|
||||
lwip_setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable));
|
||||
lwip_setsockopt(_sock, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
|
||||
|
||||
return _sock;
|
||||
}
|
||||
else{
|
||||
printf("\r\nConnect to Server failed!\r\n");
|
||||
stop_socket(_sock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//printf("\r\nUdp client setup Server's information successful!\r\n");
|
||||
}
|
||||
|
||||
return _sock;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef ARD_SOCKET_H
|
||||
#define ARD_SOCKET_H
|
||||
#include "main.h"
|
||||
|
||||
int start_server(uint16_t port, uint8_t protMode);
|
||||
|
||||
int sock_listen(int sock, int max);
|
||||
|
||||
int get_available(int sock);
|
||||
|
||||
int get_receive(int sock, uint8_t* data, int length, int flag, uint32_t *peer_addr, uint16_t *peer_port);
|
||||
|
||||
int get_sock_errno(int sock);
|
||||
|
||||
int set_sock_recv_timeout(int sock, int timeout);
|
||||
|
||||
void stop_socket(int sock);
|
||||
|
||||
int send_data(int sock, const uint8_t *data, uint16_t len);
|
||||
|
||||
int sendto_data(int sock, const uint8_t *data, uint16_t len, uint32_t peer_ip, uint16_t peer_port);
|
||||
|
||||
int start_client(uint32_t ipAddress, uint16_t port, uint8_t protMode);
|
||||
|
||||
#endif
|
||||
@@ -1,402 +0,0 @@
|
||||
#include "Arduino.h"
|
||||
#include <sockets.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
#include <mbedtls/net_sockets.h>
|
||||
#include <mbedtls/error.h>
|
||||
#include <mbedtls/debug.h>
|
||||
#include "ard_ssl.h"
|
||||
|
||||
#define ARDUINO_MBEDTLS_DEBUG_LEVEL 0 // Set to 0 to disable debug messsages, 5 to enable all debug messages
|
||||
|
||||
static unsigned int ard_ssl_arc4random(void)
|
||||
{
|
||||
unsigned int res = xTaskGetTickCount();
|
||||
static unsigned int seed = 0xDEADB00B;
|
||||
|
||||
seed = ((seed & 0x007F00FF) << 7) ^
|
||||
((seed & 0x0F80FF00) >> 8) ^ // be sure to stir those low bits
|
||||
(res << 13) ^ (res >> 9); // using the clock too!
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
static void get_random_bytes(void *buf, size_t len)
|
||||
{
|
||||
unsigned int ranbuf;
|
||||
unsigned int *lp;
|
||||
int i, count;
|
||||
count = len / sizeof(unsigned int);
|
||||
lp = (unsigned int *) buf;
|
||||
|
||||
for (i = 0; i < count; i ++) {
|
||||
lp[i] = ard_ssl_arc4random();
|
||||
len -= sizeof(unsigned int);
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
ranbuf = ard_ssl_arc4random();
|
||||
memcpy(&lp[i], &ranbuf, len);
|
||||
}
|
||||
}
|
||||
|
||||
static int my_random(void *p_rng, unsigned char *output, size_t output_len)
|
||||
{
|
||||
p_rng = p_rng;
|
||||
get_random_bytes(output, output_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
|
||||
{
|
||||
char buf[1024];
|
||||
((void)data);
|
||||
|
||||
mbedtls_x509_crt_info(buf, (sizeof(buf) - 1), "", crt);
|
||||
|
||||
if(ARDUINO_MBEDTLS_DEBUG_LEVEL < 3)
|
||||
return(0);
|
||||
|
||||
printf( "\nVerify requested for (Depth %d):\n", depth );
|
||||
printf( "%s", buf );
|
||||
|
||||
if ((*flags) == 0)
|
||||
printf(" This certificate has no flags\n");
|
||||
else
|
||||
{
|
||||
mbedtls_x509_crt_verify_info(buf, sizeof( buf ), " ! ", *flags);
|
||||
printf("%s\n", buf);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void* my_calloc(size_t nelements, size_t elementSize)
|
||||
{
|
||||
size_t size;
|
||||
void *ptr = NULL;
|
||||
|
||||
size = nelements * elementSize;
|
||||
ptr = pvPortMalloc(size);
|
||||
|
||||
if(ptr)
|
||||
memset(ptr, 0, size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void my_debug(void *ctx, int level, const char *file, int line, const char *str )
|
||||
{
|
||||
const char *p, *basename;
|
||||
|
||||
ctx = ctx; // Remove unused parameter warning
|
||||
// Extract basename from file
|
||||
for( p = basename = file; *p != '\0'; p++ )
|
||||
if( *p == '/' || *p == '\\' )
|
||||
basename = p + 1;
|
||||
|
||||
printf("%s:%04d: |%d| %s", basename, line, level, str );
|
||||
}
|
||||
|
||||
int start_ssl_client(sslclient_context *ssl_client, uint32_t ipAddress, uint32_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key, unsigned char* pskIdent, unsigned char* psKey, char* SNI_hostname)
|
||||
{
|
||||
int ret = 0;
|
||||
//int timeout;
|
||||
int enable = 1;
|
||||
int keep_idle = 30;
|
||||
mbedtls_x509_crt* cacert = NULL;
|
||||
mbedtls_x509_crt* _cli_crt = NULL;
|
||||
mbedtls_pk_context* _clikey_rsa = NULL;
|
||||
|
||||
do {
|
||||
ssl_client->socket = -1;
|
||||
ssl_client->socket = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (ssl_client->socket < 0) {
|
||||
printf("ERROR: opening socket failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
struct sockaddr_in serv_addr;
|
||||
memset(&serv_addr, 0, sizeof(serv_addr));
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_addr.s_addr = ipAddress;
|
||||
serv_addr.sin_port = htons(port);
|
||||
|
||||
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
|
||||
lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_KEEPIDLE, &keep_idle, sizeof(keep_idle));
|
||||
if (lwip_connect(ssl_client->socket, ((struct sockaddr *)&serv_addr), sizeof(serv_addr)) < 0) {
|
||||
lwip_close(ssl_client->socket);
|
||||
printf("ERROR: Connect to Server failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
} else {
|
||||
/*/
|
||||
if (lwip_connect(ssl_client->socket, ((struct sockaddr *)&serv_addr), sizeof(serv_addr)) == 0) {
|
||||
timeout = ssl_client->recvTimeout;
|
||||
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
timeout = 30000;
|
||||
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
|
||||
lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable));
|
||||
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
|
||||
} else {
|
||||
printf("ERROR: Connect to Server failed!\r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}//*/
|
||||
|
||||
mbedtls_platform_set_calloc_free(my_calloc,vPortFree);
|
||||
|
||||
ssl_client->ssl = (mbedtls_ssl_context *)malloc(sizeof(mbedtls_ssl_context));
|
||||
ssl_client->conf = (mbedtls_ssl_config *)malloc(sizeof(mbedtls_ssl_config));
|
||||
if (( ssl_client->ssl == NULL )||( ssl_client->conf == NULL )) {
|
||||
printf("ERROR: malloc ssl failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
mbedtls_ssl_init(ssl_client->ssl);
|
||||
mbedtls_ssl_config_init(ssl_client->conf);
|
||||
|
||||
if (ARDUINO_MBEDTLS_DEBUG_LEVEL > 0) {
|
||||
mbedtls_ssl_conf_verify(ssl_client->conf, my_verify, NULL);
|
||||
mbedtls_ssl_conf_dbg(ssl_client->conf, my_debug, NULL);
|
||||
mbedtls_debug_set_threshold(ARDUINO_MBEDTLS_DEBUG_LEVEL);
|
||||
}
|
||||
|
||||
if((mbedtls_ssl_config_defaults(ssl_client->conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
|
||||
printf("ERROR: mbedtls ssl config defaults failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
mbedtls_ssl_conf_rng(ssl_client->conf, my_random, NULL);
|
||||
|
||||
if (rootCABuff != NULL) {
|
||||
// Configure mbedTLS to use certificate authentication method
|
||||
cacert = (mbedtls_x509_crt *) mbedtls_calloc( sizeof(mbedtls_x509_crt), 1);
|
||||
mbedtls_x509_crt_init(cacert);
|
||||
if (mbedtls_x509_crt_parse(cacert, rootCABuff, (strlen((char*)rootCABuff)) + 1) != 0) {
|
||||
printf("ERROR: mbedtls x509 crt parse failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
mbedtls_ssl_conf_ca_chain(ssl_client->conf, cacert, NULL);
|
||||
mbedtls_ssl_conf_authmode(ssl_client->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
} else if (pskIdent != NULL && psKey != NULL) {
|
||||
// Configure mbedTLS to use PSK authentication method
|
||||
// Check for max length and even number of chars
|
||||
uint16_t pskey_char_len = strlen((char*)psKey);
|
||||
if ( ((pskey_char_len % 2) != 0) || (pskey_char_len > 2*MBEDTLS_PSK_MAX_LEN) ) {
|
||||
printf("ERROR: TLS PSK not in valid hex format or too long \n");
|
||||
return -1;
|
||||
}
|
||||
uint16_t psk_len = pskey_char_len/2;
|
||||
unsigned char psk[MBEDTLS_PSK_MAX_LEN];
|
||||
// Convert PSK from hexadecimal chars to binary
|
||||
int i;
|
||||
for (i = 0; i < pskey_char_len; i = i + 2) {
|
||||
char c = psKey[i];
|
||||
// Convert first 4 bits
|
||||
if (c >= '0' && c <= '9') {
|
||||
c = c - '0';
|
||||
} else if (c >= 'A' && c <= 'F') {
|
||||
c = c - 'A' + 10;
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
c = c - 'a' + 10;
|
||||
} else {
|
||||
printf("ERROR: TLS PSK not in valid hex format \n");
|
||||
return -1;
|
||||
}
|
||||
psk[i/2] = c << 4;
|
||||
c = psKey[i+1];
|
||||
// Convert next 4 bits
|
||||
if (c >= '0' && c <= '9') {
|
||||
c = c - '0';
|
||||
} else if (c >= 'A' && c <= 'F') {
|
||||
c = c - 'A' + 10;
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
c = c - 'a' + 10;
|
||||
} else {
|
||||
printf("ERROR: TLS PSK not in valid hex format \r\n");
|
||||
return -1;
|
||||
}
|
||||
psk[i/2] |= c;
|
||||
}
|
||||
if (mbedtls_ssl_conf_psk(ssl_client->conf, psk, psk_len, pskIdent, strlen((char*)pskIdent)) != 0) {
|
||||
printf("ERROR: mbedtls conf psk failed! \r\n");
|
||||
}
|
||||
} else {
|
||||
mbedtls_ssl_conf_authmode(ssl_client->conf, MBEDTLS_SSL_VERIFY_NONE);
|
||||
}
|
||||
|
||||
if ((cli_cert != NULL) && (cli_key != NULL)) {
|
||||
_cli_crt = (mbedtls_x509_crt *) mbedtls_calloc( sizeof(mbedtls_x509_crt), 1);
|
||||
if (_cli_crt == NULL) {
|
||||
printf("ERROR: malloc client_crt failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
mbedtls_x509_crt_init(_cli_crt);
|
||||
|
||||
_clikey_rsa = (mbedtls_pk_context *) mbedtls_calloc( sizeof(mbedtls_pk_context), 1);
|
||||
if (_clikey_rsa == NULL) {
|
||||
printf("ERROR: malloc client_rsa failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
mbedtls_pk_init(_clikey_rsa);
|
||||
|
||||
if (mbedtls_x509_crt_parse(_cli_crt, cli_cert, strlen((char*)cli_cert)+1) != 0) {
|
||||
printf("ERROR: mbedtls x509 parse client_crt failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mbedtls_pk_parse_key(_clikey_rsa, cli_key, strlen((char*)cli_key)+1, NULL, 0) != 0) {
|
||||
printf("ERROR: mbedtls x509 parse client_rsa failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
mbedtls_ssl_conf_own_cert(ssl_client->conf, _cli_crt, _clikey_rsa);
|
||||
}
|
||||
|
||||
if((mbedtls_ssl_setup(ssl_client->ssl, ssl_client->conf)) != 0) {
|
||||
printf("ERROR: mbedtls ssl setup failed!\r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
mbedtls_ssl_set_bio(ssl_client->ssl, &ssl_client->socket, mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||
|
||||
mbedtls_ssl_set_hostname(ssl_client->ssl, SNI_hostname);
|
||||
|
||||
ret = mbedtls_ssl_handshake(ssl_client->ssl);
|
||||
if (ret < 0) {
|
||||
printf("ERROR: mbedtls ssl handshake failed: -0x%04X \r\n", -ret);
|
||||
ret = -1;
|
||||
} else {
|
||||
if (ARDUINO_MBEDTLS_DEBUG_LEVEL > 0) {
|
||||
printf("mbedTLS SSL handshake success \r\n");
|
||||
}
|
||||
}
|
||||
//mbedtls_debug_set_threshold(ARDUINO_MBEDTLS_DEBUG_LEVEL);
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (_clikey_rsa) {
|
||||
mbedtls_pk_free(_clikey_rsa);
|
||||
mbedtls_free(_clikey_rsa);
|
||||
_clikey_rsa = NULL;
|
||||
}
|
||||
|
||||
if (_cli_crt) {
|
||||
mbedtls_x509_crt_free(_cli_crt);
|
||||
mbedtls_free(_cli_crt);
|
||||
_cli_crt = NULL;
|
||||
}
|
||||
|
||||
if (cacert) {
|
||||
mbedtls_x509_crt_free(cacert);
|
||||
mbedtls_free(cacert);
|
||||
cacert = NULL;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (ssl_client->socket >= 0) {
|
||||
mbedtls_net_free((mbedtls_net_context *)&ssl_client->socket);
|
||||
ssl_client->socket = -1;
|
||||
}
|
||||
|
||||
if (ssl_client->ssl != NULL) {
|
||||
mbedtls_ssl_free(ssl_client->ssl);
|
||||
free(ssl_client->ssl);
|
||||
ssl_client->ssl = NULL;
|
||||
}
|
||||
if (ssl_client->conf != NULL) {
|
||||
mbedtls_ssl_config_free(ssl_client->conf);
|
||||
free(ssl_client->conf);
|
||||
ssl_client->conf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ssl_client->socket;
|
||||
}
|
||||
|
||||
void stop_ssl_socket(sslclient_context *ssl_client)
|
||||
{
|
||||
lwip_shutdown(ssl_client->socket, SHUT_RDWR);
|
||||
lwip_close(ssl_client->socket);
|
||||
//mbedtls_net_free((mbedtls_net_context *)&ssl_client->socket);
|
||||
ssl_client->socket = -1;
|
||||
|
||||
if (ssl_client->ssl != NULL) {
|
||||
mbedtls_ssl_free(ssl_client->ssl);
|
||||
free(ssl_client->ssl);
|
||||
ssl_client->ssl = NULL;
|
||||
}
|
||||
if (ssl_client->conf != NULL) {
|
||||
mbedtls_ssl_config_free(ssl_client->conf);
|
||||
free(ssl_client->conf);
|
||||
ssl_client->conf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int send_ssl_data(sslclient_context *ssl_client, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (ssl_client->ssl != NULL) {
|
||||
ret = mbedtls_ssl_write(ssl_client->ssl, data, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_ssl_receive(sslclient_context *ssl_client, uint8_t* data, int length, int flag)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t has_backup_recvtimeout = 0;
|
||||
int backup_recv_timeout, recv_timeout;
|
||||
socklen_t len;
|
||||
|
||||
if (ssl_client->ssl == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (flag & 0x01) {
|
||||
// peek for 10ms
|
||||
ret = lwip_getsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &backup_recv_timeout, &len);
|
||||
if (ret >= 0) {
|
||||
recv_timeout = 100;
|
||||
ret = lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &recv_timeout, sizeof(recv_timeout));
|
||||
if (ret >= 0) {
|
||||
has_backup_recvtimeout = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(data, 0, length);
|
||||
ret = mbedtls_ssl_read(ssl_client->ssl, data, length);
|
||||
|
||||
if ((flag & 0x01) && (has_backup_recvtimeout == 1)) {
|
||||
// restore receiving timeout
|
||||
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &backup_recv_timeout, sizeof(recv_timeout));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_ssl_sock_errno(sslclient_context *ssl_client) {
|
||||
int so_error;
|
||||
socklen_t len = sizeof(so_error);
|
||||
lwip_getsockopt(ssl_client->socket, SOL_SOCKET, SO_ERROR, &so_error, &len);
|
||||
return so_error;
|
||||
}
|
||||
|
||||
int get_ssl_bytes_avail(sslclient_context *ssl_client) {
|
||||
if (ssl_client->ssl != NULL) {
|
||||
return mbedtls_ssl_get_bytes_avail(ssl_client->ssl);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#ifndef ARD_SSL_H
|
||||
#define ARD_SSL_H
|
||||
|
||||
struct mbedtls_ssl_context;
|
||||
struct mbedtls_ssl_config;
|
||||
|
||||
typedef struct {
|
||||
int socket;
|
||||
int recvTimeout;
|
||||
mbedtls_ssl_context *ssl;
|
||||
mbedtls_ssl_config *conf;
|
||||
} sslclient_context;
|
||||
|
||||
int start_ssl_client(sslclient_context *ssl_client, uint32_t ipAddress, uint32_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key, unsigned char* pskIdent, unsigned char* psKey, char* SNI_hostname);
|
||||
|
||||
void stop_ssl_socket(sslclient_context *ssl_client);
|
||||
|
||||
int send_ssl_data(sslclient_context *ssl_client, const uint8_t *data, uint16_t len);
|
||||
|
||||
int get_ssl_receive(sslclient_context *ssl_client, uint8_t* data, int length, int flag);
|
||||
|
||||
int get_ssl_sock_errno(sslclient_context *ssl_client);
|
||||
|
||||
int get_ssl_bytes_avail(sslclient_context *ssl_client);
|
||||
|
||||
#endif
|
||||
@@ -1,71 +0,0 @@
|
||||
// Simple Base64 code
|
||||
// (c) Copyright 2010 MCQN Ltd.
|
||||
// Released under Apache License, version 2.0
|
||||
|
||||
#include "b64.h"
|
||||
|
||||
/* Simple test program
|
||||
#include <stdio.h>
|
||||
void main()
|
||||
{
|
||||
char* in = "amcewen";
|
||||
char out[22];
|
||||
|
||||
b64_encode(in, 15, out, 22);
|
||||
out[21] = '\0';
|
||||
|
||||
printf(out);
|
||||
}
|
||||
*/
|
||||
|
||||
int b64_encode(const unsigned char* aInput, int aInputLen, unsigned char* aOutput, int aOutputLen)
|
||||
{
|
||||
// Work out if we've got enough space to encode the input
|
||||
// Every 6 bits of input becomes a byte of output
|
||||
if (aOutputLen < (aInputLen*8)/6)
|
||||
{
|
||||
// FIXME Should we return an error here, or just the length
|
||||
return (aInputLen*8)/6;
|
||||
}
|
||||
|
||||
// If we get here we've got enough space to do the encoding
|
||||
|
||||
const char* b64_dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
if (aInputLen == 3)
|
||||
{
|
||||
aOutput[0] = b64_dictionary[aInput[0] >> 2];
|
||||
aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4|(aInput[1]>>4)];
|
||||
aOutput[2] = b64_dictionary[(aInput[1]&0x0F)<<2|(aInput[2]>>6)];
|
||||
aOutput[3] = b64_dictionary[aInput[2]&0x3F];
|
||||
}
|
||||
else if (aInputLen == 2)
|
||||
{
|
||||
aOutput[0] = b64_dictionary[aInput[0] >> 2];
|
||||
aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4|(aInput[1]>>4)];
|
||||
aOutput[2] = b64_dictionary[(aInput[1]&0x0F)<<2];
|
||||
aOutput[3] = '=';
|
||||
}
|
||||
else if (aInputLen == 1)
|
||||
{
|
||||
aOutput[0] = b64_dictionary[aInput[0] >> 2];
|
||||
aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4];
|
||||
aOutput[2] = '=';
|
||||
aOutput[3] = '=';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Break the input into 3-byte chunks and process each of them
|
||||
int i;
|
||||
for (i = 0; i < aInputLen/3; i++)
|
||||
{
|
||||
b64_encode(&aInput[i*3], 3, &aOutput[i*4], 4);
|
||||
}
|
||||
if (aInputLen % 3 > 0)
|
||||
{
|
||||
// It doesn't fit neatly into a 3-byte chunk, so process what's left
|
||||
b64_encode(&aInput[i*3], aInputLen % 3, &aOutput[i*4], aOutputLen - (i*4));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#ifndef b64_h
|
||||
#define b64_h
|
||||
|
||||
int b64_encode(const unsigned char* aInput, int aInputLen, unsigned char* aOutput, int aOutputLen);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
extern "C" void __cxa_pure_virtual(void) ;
|
||||
|
||||
/* We compile with nodefaultlibs, so we need to provide an error
|
||||
* handler for an empty pure virtual function */
|
||||
extern "C" void __cxa_pure_virtual(void) {
|
||||
while(1)
|
||||
;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef ARD_DEBUG_H
|
||||
#define ARD_DEBUG_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef DEBUG_RTL_CORE
|
||||
#define DEBUGV(...) rtl_printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef DEBUGV
|
||||
#define DEBUGV(...)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
void hexdump(void * addr, int len = 16);
|
||||
#else
|
||||
void hexdump(void * addr, int len);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void print_udp_pcb(void);
|
||||
void print_tcp_pcb(void);
|
||||
void DumpForOneBytes(void *addr, int cnt); // cnt max 0x70 !
|
||||
|
||||
void __panic_func(const char* file, int line, const char* func) __attribute__((noreturn));
|
||||
#define panic() __panic_func(__FILE__, __LINE__, __func__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif//ARD_DEBUG_H
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2012 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* Empty yield() hook.
|
||||
*
|
||||
* This function is intended to be used by library writers to build
|
||||
* libraries or sketches that supports cooperative threads.
|
||||
*
|
||||
* Its defined as a weak symbol and it can be redefined to implement a
|
||||
* real cooperative scheduler.
|
||||
*/
|
||||
static void __empty() {
|
||||
// Empty
|
||||
}
|
||||
|
||||
#include "cmsis_os.h"
|
||||
|
||||
void yield(void) {
|
||||
vTaskDelay(1);
|
||||
taskYIELD();
|
||||
}
|
||||
|
||||
/**
|
||||
* SysTick hook
|
||||
*
|
||||
* This function is called from SysTick handler, before the default
|
||||
* handler provided by Arduino.
|
||||
*/
|
||||
static int __false() {
|
||||
// Return false
|
||||
return 0;
|
||||
}
|
||||
int sysTickHook(void) __attribute__ ((weak, alias("__false")));
|
||||
|
||||
/**
|
||||
* SVC hook
|
||||
* PendSV hook
|
||||
*
|
||||
* These functions are called from SVC handler, and PensSV handler.
|
||||
* Default action is halting.
|
||||
*/
|
||||
static void __halt() {
|
||||
// Halts
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
void svcHook(void) __attribute__ ((weak, alias("__halt")));
|
||||
void pendSVHook(void) __attribute__ ((weak, alias("__halt")));
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "api/itoa.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif // __cplusplus
|
||||
|
||||
extern char* ltoa(long value, char *string, int radix)
|
||||
{
|
||||
char tmp[33];
|
||||
char *tp = tmp;
|
||||
long i;
|
||||
unsigned long v;
|
||||
int sign;
|
||||
char *sp;
|
||||
|
||||
if ( string == NULL )
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
if (radix > 36 || radix <= 1)
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
sign = (radix == 10 && value < 0);
|
||||
if (sign)
|
||||
{
|
||||
v = -value;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = (unsigned long)value;
|
||||
}
|
||||
|
||||
while (v || tp == tmp)
|
||||
{
|
||||
i = v % radix;
|
||||
v = v / radix;
|
||||
if (i < 10)
|
||||
*tp++ = i+'0';
|
||||
else
|
||||
*tp++ = i + 'a' - 10;
|
||||
}
|
||||
|
||||
sp = string;
|
||||
|
||||
if (sign)
|
||||
*sp++ = '-';
|
||||
while (tp > tmp)
|
||||
*sp++ = *--tp;
|
||||
*sp = 0;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
extern char* ultoa(unsigned long value, char *string, int radix)
|
||||
{
|
||||
char tmp[33];
|
||||
char *tp = tmp;
|
||||
long i;
|
||||
unsigned long v = value;
|
||||
char *sp;
|
||||
|
||||
if ( string == NULL )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (radix > 36 || radix <= 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (v || tp == tmp)
|
||||
{
|
||||
i = v % radix;
|
||||
v = v / radix;
|
||||
if (i < 10)
|
||||
*tp++ = i+'0';
|
||||
else
|
||||
*tp++ = i + 'a' - 10;
|
||||
}
|
||||
|
||||
sp = string;
|
||||
|
||||
|
||||
while (tp > tmp)
|
||||
*sp++ = *--tp;
|
||||
*sp = 0;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
@@ -1,120 +0,0 @@
|
||||
#ifndef EASYWSCLIENT_H
|
||||
#define EASYWSCLIENT_H
|
||||
#include <platform/platform_stdlib.h>
|
||||
|
||||
/****************Define the debug message level*********************/
|
||||
#define DEBUG_WSCLIENT 1
|
||||
|
||||
#define WSCLIENT_LOG(level, fmt, ...) printf("\n\r[WSCLIENT %s] %s: " fmt "\n", level, __FUNCTION__, ##__VA_ARGS__)
|
||||
#if DEBUG_WSCLIENT == 2
|
||||
#define WSCLIENT_DEBUG(fmt, ...) WSCLIENT_LOG("DEBUG", fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define WSCLIENT_DEBUG(fmt, ...)
|
||||
#endif
|
||||
#if DEBUG_WSCLIENT
|
||||
#define WSCLIENT_ERROR(fmt, ...) WSCLIENT_LOG("ERROR", fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define WSCLIENT_ERROR(fmt, ...)
|
||||
#endif
|
||||
/*******************************************************************/
|
||||
|
||||
/****************Define the structures used*************************/
|
||||
typedef enum{
|
||||
CLOSING,
|
||||
CLOSED,
|
||||
CONNECTING,
|
||||
OPEN
|
||||
} readyStateValues;
|
||||
|
||||
struct wsheader_type{
|
||||
unsigned header_size;
|
||||
int fin;
|
||||
int mask;
|
||||
enum opcode_type {
|
||||
CONTINUATION = 0x0,
|
||||
TEXT_FRAME = 0x1,
|
||||
BINARY_FRAME = 0x2,
|
||||
CLOSE = 8,
|
||||
PING = 9,
|
||||
PONG = 0xa,
|
||||
} opcode;
|
||||
int N0;
|
||||
uint64_t N;
|
||||
uint8_t masking_key[4];
|
||||
};
|
||||
|
||||
struct _wsclient_context;
|
||||
struct _ssl_context;
|
||||
|
||||
struct ssl_fun_ops{
|
||||
int (*memory_set_own)( void * (*malloc_func)( size_t ),void (*free_func)( void * ) );
|
||||
int (*net_connect)( int *fd, const char *host, int port );
|
||||
int (*ssl_init)( struct _ssl_context *ssl );
|
||||
void (*ssl_set_endpoint)( struct _ssl_context *ssl, int endpoint );
|
||||
void (*ssl_set_authmode)( struct _ssl_context *ssl, int authmode );
|
||||
void (*ssl_set_rng)( struct _ssl_context *ssl,
|
||||
int (*f_rng)(void *, unsigned char *, size_t),
|
||||
void *p_rng );
|
||||
void (*ssl_set_bio)( struct _ssl_context *ssl,
|
||||
int (*f_recv)(void *, unsigned char *, size_t), void *p_recv,
|
||||
int (*f_send)(void *, const unsigned char *, size_t), void *p_send );
|
||||
int (*ssl_handshake)( struct _ssl_context *ssl );
|
||||
void (*net_close)( int fd );
|
||||
void (*ssl_free)( struct _ssl_context *ssl );
|
||||
int (*ssl_read)( struct _ssl_context *ssl, unsigned char *buf, size_t len );
|
||||
int (*ssl_write)( struct _ssl_context *ssl, const unsigned char *buf, size_t len );
|
||||
const char *(*ssl_get_ciphersuite)( const struct _ssl_context *ssl );
|
||||
int (*net_recv)( void *ctx, unsigned char *buf, size_t len );
|
||||
int (*net_send)( void *ctx, const unsigned char *buf, size_t len );
|
||||
};
|
||||
|
||||
struct ws_fun_ops{
|
||||
int (*hostname_connect)(struct _wsclient_context *wsclient);
|
||||
void (*client_close)(struct _wsclient_context *wsclient);
|
||||
int (*client_send)(struct _wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
||||
int (*client_read)(struct _wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
||||
struct ssl_fun_ops ssl_fun_ops;
|
||||
};
|
||||
|
||||
typedef struct _wsclient_context{
|
||||
char host[128];
|
||||
char path[128];
|
||||
char origin[200];
|
||||
int port;
|
||||
uint8_t use_ssl;
|
||||
int sockfd;
|
||||
readyStateValues readyState;
|
||||
int tx_len;
|
||||
void *ssl;
|
||||
uint8_t *txbuf;
|
||||
uint8_t *rxbuf;
|
||||
uint8_t *receivedData;
|
||||
struct ws_fun_ops fun_ops;
|
||||
}wsclient_context;
|
||||
/*******************************************************************/
|
||||
|
||||
/****************General functions used by wsclient*****************/
|
||||
void ws_get_random_bytes(void *buf, size_t len);
|
||||
void* ws_malloc(unsigned int size);
|
||||
void ws_free(void *buf);
|
||||
int ws_client_handshake(wsclient_context *wsclient);
|
||||
int ws_check_handshake(wsclient_context *wsclient);
|
||||
void ws_sendData(uint8_t type, size_t message_size, uint8_t* message, int useMask, wsclient_context *wsclient);
|
||||
/*******************************************************************/
|
||||
|
||||
/*************Functions used by wsclient without SSL****************/
|
||||
|
||||
int ws_hostname_connect(wsclient_context *wsclient);
|
||||
int ws_client_read(wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
||||
int ws_client_send(wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
||||
void ws_client_close(wsclient_context *wsclient);
|
||||
/*******************************************************************/
|
||||
|
||||
/***************Functions used by wsclient with SSL*****************/
|
||||
int wss_hostname_connect(wsclient_context *wsclient);
|
||||
int wss_client_read(wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
||||
int wss_client_send(wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
||||
void wss_client_close(wsclient_context *wsclient);
|
||||
/*******************************************************************/
|
||||
|
||||
#endif
|
||||
@@ -1,122 +0,0 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "lwip_netconf.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/err.h"
|
||||
//#include "lwip/mem.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/tcp_impl.h"
|
||||
#include "lwip/udp.h"
|
||||
|
||||
/* Get one byte from the 4-byte address */
|
||||
#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0])
|
||||
#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1])
|
||||
#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2])
|
||||
#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3])
|
||||
/* These are cast to u16_t, with the intent that they are often arguments
|
||||
* to printf using the U16_F format from cc.h. */
|
||||
#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr))
|
||||
#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr))
|
||||
#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr))
|
||||
#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr))
|
||||
|
||||
#define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \
|
||||
ip4_addr2_16(ipaddr), \
|
||||
ip4_addr3_16(ipaddr), \
|
||||
ip4_addr4_16(ipaddr)
|
||||
|
||||
#define IPSTR "%d.%d.%d.%d"
|
||||
|
||||
extern const char * const tcp_state_str[];
|
||||
/*
|
||||
static const char * const tcp_state_str[] = {
|
||||
"CLOSED",
|
||||
"LISTEN",
|
||||
"SYN_SENT",
|
||||
"SYN_RCVD",
|
||||
"ESTABLISHED",
|
||||
"FIN_WAIT_1",
|
||||
"FIN_WAIT_2",
|
||||
"CLOSE_WAIT",
|
||||
"CLOSING",
|
||||
"LAST_ACK",
|
||||
"TIME_WAIT"
|
||||
};
|
||||
*/
|
||||
/******************************************************************************
|
||||
* FunctionName : debug
|
||||
* Parameters :
|
||||
* Returns :
|
||||
*******************************************************************************/
|
||||
void print_udp_pcb(void)
|
||||
{
|
||||
struct udp_pcb *pcb;
|
||||
bool prt_none = true;
|
||||
rtl_printf("UDP pcbs:\n");
|
||||
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
rtl_printf("flg:%02x\t" IPSTR ":%d\t" IPSTR ":%d\trecv:%p\n", pcb->flags, IP2STR(&pcb->local_ip), pcb->local_port, IP2STR(&pcb->remote_ip), pcb->remote_port, pcb->recv );
|
||||
prt_none = false;
|
||||
}
|
||||
if(prt_none) rtl_printf("none\n");
|
||||
}
|
||||
/******************************************************************************
|
||||
* FunctionName : debug
|
||||
* Parameters :
|
||||
* Returns :
|
||||
*******************************************************************************/
|
||||
void print_tcp_pcb(void)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
rtl_printf("Active PCB states:\n");
|
||||
bool prt_none = true;
|
||||
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
rtl_printf("Port %d|%d\tflg:%02x\ttmr:%p\t%s\n", pcb->local_port, pcb->remote_port, pcb->flags, pcb->tmr, tcp_state_str[pcb->state]);
|
||||
prt_none = false;
|
||||
}
|
||||
if(prt_none) rtl_printf("none\n");
|
||||
rtl_printf("Listen PCB states:\n");
|
||||
prt_none = true;
|
||||
for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
rtl_printf("Port %d|%d\tflg:%02x\ttmr:%p\t%s\n", pcb->local_port, pcb->remote_port, pcb->flags, pcb->tmr, tcp_state_str[pcb->state]);
|
||||
prt_none = false;
|
||||
}
|
||||
if(prt_none) rtl_printf("none\n");
|
||||
rtl_printf("TIME-WAIT PCB states:\n");
|
||||
prt_none = true;
|
||||
for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
rtl_printf("Port %d|%d\tflg:%02x\ttmr:%p\t%s\n", pcb->local_port, pcb->remote_port, pcb->flags, pcb->tmr, tcp_state_str[pcb->state]);
|
||||
prt_none = false;
|
||||
}
|
||||
if(prt_none) rtl_printf("none\n");
|
||||
}
|
||||
/******************************************************************************
|
||||
* FunctionName : debug
|
||||
* Parameters :
|
||||
* Returns :
|
||||
*******************************************************************************/
|
||||
#if 0
|
||||
//------------------------------------------------------------------------------
|
||||
void chow_tcp_connection_info(void)
|
||||
{
|
||||
rtl_printf("TCP Server connections:\n");
|
||||
TCP_SERV_CFG * p;
|
||||
TCP_SERV_CONN * ts_conn;
|
||||
bool prt_none = true;
|
||||
for(p = phcfg; p != NULL; p = p->next) {
|
||||
for(ts_conn = p->conn_links; ts_conn != NULL; ts_conn = ts_conn->next) {
|
||||
rtl_printf("%d "IPSTR ":%d %s\n", p->port, ts_conn->remote_ip.b[0], ts_conn->remote_ip.b[1], ts_conn->remote_ip.b[2], ts_conn->remote_ip.b[3], ts_conn->remote_port, tspsrv_srvconn_state_msg(ts_conn->state) );
|
||||
prt_none = false;
|
||||
}
|
||||
}
|
||||
if(prt_none) rtl_printf("none\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
main.cpp - Main loop for Arduino sketches
|
||||
Copyright (c) 2005-2013 Arduino Team. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define ARDUINO_MAIN
|
||||
#include "Arduino.h"
|
||||
#include "cmsis_os.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "rtl8710b.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "diag.h"
|
||||
extern void HalCpuClkConfig(u8 CpuType);
|
||||
extern void SystemCoreClockUpdate(void);
|
||||
extern void En32KCalibration(void);
|
||||
extern int tcm_heap_freeSpace(void);
|
||||
extern void console_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
osThreadId main_tid = 0;
|
||||
|
||||
// Weak empty variant initialization function.
|
||||
// May be redefined by variant files.
|
||||
void initVariant() __attribute__((weak));
|
||||
void initVariant() { }
|
||||
|
||||
// Initialize C library
|
||||
extern "C" void __libc_init_array(void);
|
||||
|
||||
/*
|
||||
* \brief Init Random()
|
||||
* \note Use in void __low_level_init(void) { Init_Rand(); } !
|
||||
*/
|
||||
void Init_Rand(void)
|
||||
{
|
||||
extern u32 _rand_z1, _rand_z2, _rand_z3, _rand_z4, _rand_first;
|
||||
u32 *p = (u32 *)0x1FFFFF00;
|
||||
while(p < (u32 *)0x20000000) _rand_z1 ^= *p++;
|
||||
_rand_z1 ^= (*((u32 *)0x40002018) << 24) ^ (*((u32 *)0x40002118) << 16) ^ (*((u32 *)0x40002218) << 8) ^ *((u32 *)0x40002318);
|
||||
_rand_z2 = ((_rand_z1 & 0x007F00FF) << 7) ^ ((_rand_z1 & 0x0F80FF00) >> 8);
|
||||
_rand_z3 = ((_rand_z2 & 0x007F00FF) << 7) ^ ((_rand_z2 & 0x0F80FF00) >> 8);
|
||||
_rand_z4 = ((_rand_z3 & 0x007F00FF) << 7) ^ ((_rand_z3 & 0x0F80FF00) >> 8);
|
||||
_rand_first = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief handle sketch
|
||||
*/
|
||||
void main_task( void const *arg )
|
||||
{
|
||||
setup();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
loop();
|
||||
if (serialEventRun) serialEventRun();
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* \brief Main entry point of Arduino application
|
||||
*/
|
||||
int main( void )
|
||||
{
|
||||
LT_BANNER();
|
||||
init();
|
||||
|
||||
__libc_init_array();
|
||||
|
||||
initVariant();
|
||||
|
||||
osThreadDef(main_task, osPriorityRealtime, 1, 4096*4);
|
||||
main_tid = osThreadCreate(osThread (main_task), NULL);
|
||||
|
||||
osKernelStart();
|
||||
|
||||
while(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#ifndef __NETBIOS_H__
|
||||
#define __NETBIOS_H__
|
||||
|
||||
/** default port number for "NetBIOS Name service */
|
||||
#define NETBIOS_PORT 137
|
||||
|
||||
/** size of a NetBIOS name */
|
||||
#define NETBIOS_NAME_LEN 16
|
||||
|
||||
#ifndef NET_IF_NUM
|
||||
#define NET_IF_NUM 2
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern char netbios_name[NET_IF_NUM][NETBIOS_NAME_LEN + 1]; // default netifs/interfacenum: 0 - SoftAP, 1 - Station, 2 - Ethernet
|
||||
|
||||
// struct udp_pcb * netbios_pcb(void);
|
||||
void netbios_init(void);
|
||||
bool netbios_set_name(unsigned char interfacenum, char * name); // default netifs/interfacenum: 0 - SoftAP, 1 - Station, 2 - Ethernet
|
||||
bool netbios_off(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __NETBIOS_H__ */
|
||||
@@ -1,215 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2014 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include <diag.h>
|
||||
|
||||
extern void *pvPortMalloc( size_t xWantedSize );
|
||||
extern void *os_zalloc( size_t xWantedSize );
|
||||
extern void vPortFree( void *pv );
|
||||
extern void *pvPortReAlloc( void *pv, size_t xWantedSize );
|
||||
extern size_t xPortGetFreeHeapSize( void );
|
||||
extern size_t xPortGetMinimumEverFreeHeapSize( void );
|
||||
|
||||
extern void *tcm_heap_malloc(int size);
|
||||
extern void *tcm_heap_calloc(int size);
|
||||
extern void tcm_heap_free(void * mem);
|
||||
extern void tcm_heap_dump(void);
|
||||
extern int tcm_heap_freeSpace(void);
|
||||
|
||||
|
||||
__attribute__((noreturn)) void __panic_func(const char* file, int line, const char* func)
|
||||
{
|
||||
DiagPrintf("\r\nPanic: %s, line: %d, %s\r\n");
|
||||
while(1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
void hexdump(void * ptr, int cnt)
|
||||
{
|
||||
char * p = (char *) ptr;
|
||||
int c = cnt;
|
||||
while(c > 64) {
|
||||
DumpForOneBytes((void *)p, 64);
|
||||
p += 64;
|
||||
c -= 64;
|
||||
}
|
||||
if(c != 0) DumpForOneBytes((void *)p, c);
|
||||
}
|
||||
|
||||
void debug_on(void)
|
||||
{
|
||||
ConfigDebugErr = -1;
|
||||
ConfigDebugInfo = -1;
|
||||
ConfigDebugWarn = -1;
|
||||
CfgSysDebugErr = -1;
|
||||
CfgSysDebugInfo = -1;
|
||||
CfgSysDebugWarn = -1;
|
||||
}
|
||||
|
||||
void sys_info(void) {
|
||||
rtl_printf("\r\nCLK CPU\t\t%d Hz\r\nRAM heap\t%d bytes\r\nTCM heap\t%d bytes\r\n",
|
||||
HalGetCpuClk(), xPortGetFreeHeapSize(), tcm_heap_freeSpace());
|
||||
}
|
||||
|
||||
|
||||
/* void * malloc(size_t size)
|
||||
{
|
||||
void * ret;
|
||||
if((ret = pvPortMalloc(size)) == NULL)
|
||||
ret = tcm_heap_malloc(size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void * zalloc(size_t size)
|
||||
{
|
||||
void * ret;
|
||||
if((ret = pvPortMalloc(size)) == NULL)
|
||||
ret = tcm_heap_calloc(size);
|
||||
else memset(ret, 0, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *calloc(size_t count, size_t size)
|
||||
{
|
||||
return zalloc(count * size);
|
||||
} */
|
||||
|
||||
void free(void *pv)
|
||||
{
|
||||
vPortFree(pv);
|
||||
}
|
||||
|
||||
void * realloc(void *pv, size_t size)
|
||||
{
|
||||
return pvPortReAlloc(pv, size);
|
||||
}
|
||||
|
||||
/* void *operator new(size_t size)
|
||||
{
|
||||
void * ret;
|
||||
if((ret = zalloc(size)) == NULL) {
|
||||
DiagPrintf("\r\nMEM error!\r\n");
|
||||
while(1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *operator new[](size_t size)
|
||||
{
|
||||
void * ret;
|
||||
if((ret = zalloc(size)) == NULL) {
|
||||
DiagPrintf("\r\nMEM error!\r\n");
|
||||
while(1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void operator delete(void * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
} */
|
||||
|
||||
/*
|
||||
extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__));
|
||||
extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__));
|
||||
|
||||
void __cxa_pure_virtual(void)
|
||||
{
|
||||
panic();
|
||||
}
|
||||
|
||||
void __cxa_deleted_virtual(void)
|
||||
{
|
||||
panic();
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint8_t guard;
|
||||
uint8_t ps;
|
||||
} guard_t;
|
||||
|
||||
extern "C" int __cxa_guard_acquire(__guard* pg)
|
||||
{
|
||||
uint8_t ps = xt_rsil(15);
|
||||
if (reinterpret_cast<guard_t*>(pg)->guard) {
|
||||
xt_wsr_ps(ps);
|
||||
return 0;
|
||||
}
|
||||
reinterpret_cast<guard_t*>(pg)->ps = ps;
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern "C" void __cxa_guard_release(__guard* pg)
|
||||
{
|
||||
reinterpret_cast<guard_t*>(pg)->guard = 1;
|
||||
xt_wsr_ps(reinterpret_cast<guard_t*>(pg)->ps);
|
||||
}
|
||||
|
||||
extern "C" void __cxa_guard_abort(__guard* pg)
|
||||
{
|
||||
xt_wsr_ps(reinterpret_cast<guard_t*>(pg)->ps);
|
||||
}
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
void __throw_bad_function_call()
|
||||
{
|
||||
panic();
|
||||
}
|
||||
|
||||
void __throw_length_error(char const*)
|
||||
{
|
||||
panic();
|
||||
}
|
||||
|
||||
void __throw_bad_alloc()
|
||||
{
|
||||
panic();
|
||||
}
|
||||
|
||||
void __throw_logic_error(const char* str)
|
||||
{
|
||||
panic();
|
||||
}
|
||||
|
||||
void __throw_out_of_range(const char* str)
|
||||
{
|
||||
panic();
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -1,146 +0,0 @@
|
||||
#include "server_drv.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#include "ard_socket.h"
|
||||
#include "platform_stdlib.h"
|
||||
}
|
||||
#endif
|
||||
|
||||
// Start server TCP on port specified
|
||||
int ServerDrv::startServer(uint16_t port, uint8_t protMode)
|
||||
{
|
||||
int sock;
|
||||
|
||||
sock = start_server(port, protMode);
|
||||
if (sock >= 0) {
|
||||
if(protMode == TCP_MODE)
|
||||
sock_listen(sock, 1);
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
int ServerDrv::getAvailable(int sock)
|
||||
{
|
||||
return get_available(sock);
|
||||
}
|
||||
|
||||
int ServerDrv::availData(int sock)
|
||||
{
|
||||
int ret;
|
||||
uint8_t c;
|
||||
|
||||
if (sock < 0)
|
||||
return 0;
|
||||
|
||||
if(_available) {
|
||||
return 1;
|
||||
} else {
|
||||
// flag = MSG_PEEK
|
||||
ret = get_receive(sock, &c, 1, 1, &_peer_addr, &_peer_port);
|
||||
if ( ret == 1 ) {
|
||||
_available = true;
|
||||
return 1;
|
||||
}
|
||||
else{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ServerDrv::getData(int sock, uint8_t *data, uint8_t peek)
|
||||
{
|
||||
int ret = 0;
|
||||
int flag = 0;
|
||||
|
||||
if (peek) {
|
||||
flag |= 1;
|
||||
} else {
|
||||
_available = false;
|
||||
}
|
||||
|
||||
ret = get_receive(sock, data, 1, flag, &_peer_addr, &_peer_port);
|
||||
|
||||
if (ret == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int ServerDrv::getDataBuf(int sock, uint8_t *_data, uint16_t _dataLen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
_available = false;
|
||||
|
||||
ret = get_receive(sock, _data, _dataLen, 0, &_peer_addr, &_peer_port);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ServerDrv::getLastErrno(int sock)
|
||||
{
|
||||
return get_sock_errno(sock);
|
||||
}
|
||||
|
||||
void ServerDrv::stopClient(int sock)
|
||||
{
|
||||
stop_socket(sock);
|
||||
_available = false;
|
||||
}
|
||||
|
||||
bool ServerDrv::sendData(int sock, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (sock < 0)
|
||||
return false;
|
||||
|
||||
ret = send_data(sock, data, len);
|
||||
|
||||
if (ret <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ServerDrv::sendtoData(int sock, const uint8_t *data, uint16_t len, uint32_t peer_ip, uint16_t peer_port)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (sock < 0)
|
||||
return false;
|
||||
|
||||
ret = sendto_data(sock, data, len, peer_ip, peer_port);
|
||||
|
||||
if (ret == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int ServerDrv::startClient(uint32_t ipAddress, uint16_t port, uint8_t protMode)
|
||||
{
|
||||
int sock;
|
||||
|
||||
sock = start_client(ipAddress, port, protMode);
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
void ServerDrv::getRemoteData(int sock, uint32_t *ip, uint16_t *port)
|
||||
{
|
||||
// TODO: These data may be outdated?
|
||||
*ip = _peer_addr;
|
||||
*port = _peer_port;
|
||||
}
|
||||
|
||||
int ServerDrv::setSockRecvTimeout(int sock, int timeout)
|
||||
{
|
||||
return set_sock_recv_timeout(sock, timeout);
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
server_drv.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef Server_Drv_h
|
||||
#define Server_Drv_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef enum eProtMode {TCP_MODE, UDP_MODE}tProtMode;
|
||||
#define DATA_LENTH 128
|
||||
class ServerDrv
|
||||
{
|
||||
public:
|
||||
int startServer(uint16_t port, uint8_t protMode=TCP_MODE);
|
||||
int getAvailable(int sock);
|
||||
int startClient(uint32_t ipAddress, uint16_t port, uint8_t protMode=TCP_MODE);
|
||||
int getLastErrno(int sock);
|
||||
void stopClient(int sock);
|
||||
bool getData(int sock, uint8_t *data, uint8_t peek = 0);
|
||||
int getDataBuf(int sock, uint8_t *_data, uint16_t _dataLen);
|
||||
|
||||
/* Usually used by TCP */
|
||||
bool sendData(int sock, const uint8_t *data, uint16_t len);
|
||||
|
||||
/* Usually used by UDP */
|
||||
bool sendtoData(int sock, const uint8_t *data, uint16_t len, uint32_t peer_ip, uint16_t peer_port);
|
||||
|
||||
int availData(int sock);
|
||||
|
||||
void getRemoteData(int sock, uint32_t *ip, uint16_t *port);
|
||||
|
||||
int setSockRecvTimeout(int sock, int timeout);
|
||||
|
||||
private:
|
||||
bool _available;
|
||||
|
||||
uint32_t _peer_addr;
|
||||
uint16_t _peer_port;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,20 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2015 Peter Andersson (pelleplutt1976<at>gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,146 +0,0 @@
|
||||
# SPIFFS (SPI Flash File System)
|
||||
**V0.3.4**
|
||||
|
||||
Copyright (c) 2013-2016 Peter Andersson (pelleplutt1976 at gmail.com)
|
||||
|
||||
For legal stuff, see [LICENSE](https://github.com/pellepl/spiffs/blob/master/LICENSE). Basically, you may do whatever you want with the source. Use, modify, sell, print it out, roll it and smoke it - as long as I won't be held responsible.
|
||||
|
||||
Love to hear feedback though!
|
||||
|
||||
|
||||
## INTRODUCTION
|
||||
|
||||
Spiffs is a file system intended for SPI NOR flash devices on embedded targets.
|
||||
|
||||
Spiffs is designed with following characteristics in mind:
|
||||
- Small (embedded) targets, sparse RAM without heap
|
||||
- Only big areas of data (blocks) can be erased
|
||||
- An erase will reset all bits in block to ones
|
||||
- Writing pulls one to zeroes
|
||||
- Zeroes can only be pulled to ones by erase
|
||||
- Wear leveling
|
||||
|
||||
|
||||
## FEATURES
|
||||
|
||||
What spiffs does:
|
||||
- Specifically designed for low ram usage
|
||||
- Uses statically sized ram buffers, independent of number of files
|
||||
- Posix-like api: open, close, read, write, seek, stat, etc
|
||||
- It can be run on any NOR flash, not only SPI flash - theoretically also on embedded flash of an microprocessor
|
||||
- Multiple spiffs configurations can be run on same target - and even on same SPI flash device
|
||||
- Implements static wear leveling
|
||||
- Built in file system consistency checks
|
||||
|
||||
What spiffs does not:
|
||||
- Presently, spiffs does not support directories. It produces a flat structure. Creating a file with path *tmp/myfile.txt* will create a file called *tmp/myfile.txt* instead of a *myfile.txt* under directory *tmp*.
|
||||
- It is not a realtime stack. One write operation might take much longer than another.
|
||||
- Poor scalability. Spiffs is intended for small memory devices - the normal sizes for SPI flashes. Going beyond ~128MB is probably a bad idea. This is a side effect of the design goal to use as little ram as possible.
|
||||
- Presently, it does not detect or handle bad blocks.
|
||||
|
||||
|
||||
## MORE INFO
|
||||
|
||||
See the [wiki](https://github.com/pellepl/spiffs/wiki) for configuring, integrating and using spiffs.
|
||||
|
||||
For design, see [docs/TECH_SPEC](https://github.com/pellepl/spiffs/blob/master/docs/TECH_SPEC).
|
||||
|
||||
For a generic spi flash driver, see [this](https://github.com/pellepl/spiflash_driver).
|
||||
|
||||
## HISTORY
|
||||
|
||||
### 0.3.4
|
||||
- Added user callback file func.
|
||||
- Fixed a stat bug with obj id.
|
||||
- SPIFFS_probe_fs added
|
||||
- Add possibility to compile a read-only version of spiffs
|
||||
- Make magic dependent on fs length, if needed (see #59 & #66) (thanks @hreintke)
|
||||
- Exposed SPIFFS_open_by_page_function
|
||||
- Zero-size file cannot be seek #57 (thanks @lishen2)
|
||||
- Add tell and eof functions #54 (thanks @raburton)
|
||||
- Make api string params const #53 (thanks @raburton)
|
||||
- Preserve user_data during mount() #51 (thanks @rojer)
|
||||
|
||||
New API functions:
|
||||
- `SPIFFS_set_file_callback_func` - register a callback informing about file events
|
||||
- `SPIFFS_probe_fs` - probe a spi flash trying to figure out size of fs
|
||||
- `SPIFFS_open_by_page` - open a file by page index
|
||||
- `SPIFFS_eof` - checks if end of file is reached
|
||||
- `SPIFFS_tell` - returns current file offset
|
||||
|
||||
New config defines:
|
||||
- `SPIFFS_READ_ONLY`
|
||||
- `SPIFFS_USE_MAGIC_LENGTH`
|
||||
|
||||
### 0.3.3
|
||||
**Might not be compatible with 0.3.2 structures. See issue #40**
|
||||
- Possibility to add integer offset to file handles
|
||||
- Truncate function presumes too few free pages #49
|
||||
- Bug in truncate function #48 (thanks @PawelDefee)
|
||||
- Update spiffs_gc.c - remove unnecessary parameter (thanks @PawelDefee)
|
||||
- Update INTEGRATION docs (thanks @PawelDefee)
|
||||
- Fix pointer truncation in 64-bit platforms (thanks @igrr)
|
||||
- Zero-sized files cannot be read #44 (thanks @rojer)
|
||||
- (More) correct calculation of max_id in obj_lu_find #42 #41 (thanks @lishen2)
|
||||
- Check correct error code in obj_lu_find_free #41 (thanks @lishen2)
|
||||
- Moar comments for SPIFFS_lseek (thanks @igrr)
|
||||
- Fixed padding in spiffs_page_object_ix #40 (thanks @jmattsson @lishen2)
|
||||
- Fixed gc_quick test (thanks @jmattsson)
|
||||
- Add SPIFFS_EXCL flag #36
|
||||
- SPIFFS_close may fail silently if cache is enabled #37
|
||||
- User data in callbacks #34
|
||||
- Ignoring SINGLETON build in cache setup (thanks Luca)
|
||||
- Compilation error fixed #32 (thanks @chotasanjiv)
|
||||
- Align cand_scores (thanks @hefloryd)
|
||||
- Fix build warnings when SPIFFS_CACHE is 0 (thanks @ajaybhargav)
|
||||
|
||||
New config defines:
|
||||
- `SPIFFS_FILEHDL_OFFSET`
|
||||
|
||||
### 0.3.2
|
||||
- Limit cache size if too much cache is given (thanks pgeiem)
|
||||
- New feature - Controlled erase. #23
|
||||
- SPIFFS_rename leaks file descriptors #28 (thanks benpicco)
|
||||
- moved dbg print defines in test framework to params_test.h
|
||||
- lseek should return the resulting offset (thanks hefloryd)
|
||||
- fixed type on dbg ifdefs
|
||||
- silence warning about signed/unsigned comparison when spiffs_obj_id is 32 bit (thanks benpicco)
|
||||
- Possible error in test_spiffs.c #21 (thanks yihcdaso-yeskela)
|
||||
- Cache might writethrough too often #16
|
||||
- even moar testrunner updates
|
||||
- Test framework update and some added tests
|
||||
- Some thoughts for next gen
|
||||
- Test sigsevs when having too many sectors #13 (thanks alonewolfx2)
|
||||
- GC might be suboptimal #11
|
||||
- Fix eternal readdir when objheader at last block, last entry
|
||||
|
||||
New API functions:
|
||||
- `SPIFFS_gc_quick` - call a nonintrusive gc
|
||||
- `SPIFFS_gc` - call a full-scale intrusive gc
|
||||
|
||||
### 0.3.1
|
||||
- Removed two return warnings, was too triggerhappy on release
|
||||
|
||||
### 0.3.0
|
||||
- Added existing namecheck when creating files
|
||||
- Lots of static analysis bugs #6
|
||||
- Added rename func
|
||||
- Fix SPIFFS_read length when reading beyond file size
|
||||
- Added reading beyond file length testcase
|
||||
- Made build a bit more configurable
|
||||
- Changed name in spiffs from "errno" to "err_code" due to conflicts compiling in mingw
|
||||
- Improved GC checks, fixed an append bug, more robust truncate for very special case
|
||||
- GC checks preempts GC, truncate even less picky
|
||||
- Struct alignment needed for some targets, define in spiffs config #10
|
||||
- Spiffs filesystem magic, definable in config
|
||||
|
||||
New config defines:
|
||||
- `SPIFFS_USE_MAGIC` - enable or disable magic check upon mount
|
||||
- `SPIFFS_ALIGNED_OBJECT_INDEX_TABLES` - alignment for certain targets
|
||||
|
||||
New API functions:
|
||||
- `SPIFFS_rename` - rename files
|
||||
- `SPIFFS_clearerr` - clears last errno
|
||||
- `SPIFFS_info` - returns info on used and total bytes in fs
|
||||
- `SPIFFS_format` - formats the filesystem
|
||||
- `SPIFFS_mounted` - checks if filesystem is mounted
|
||||
@@ -1,239 +0,0 @@
|
||||
* USING SPIFFS
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
* SPIFFS DESIGN
|
||||
|
||||
Spiffs is inspired by YAFFS. However, YAFFS is designed for NAND flashes, and
|
||||
for bigger targets with much more ram. Nevertheless, many wise thoughts have
|
||||
been borrowed from YAFFS when writing spiffs. Kudos!
|
||||
|
||||
The main complication writing spiffs was that it cannot be assumed the target
|
||||
has a heap. Spiffs must go along only with the work ram buffer given to it.
|
||||
This forces extra implementation on many areas of spiffs.
|
||||
|
||||
|
||||
** SPI flash devices using NOR technology
|
||||
|
||||
Below is a small description of how SPI flashes work internally. This is to
|
||||
give an understanding of the design choices made in spiffs.
|
||||
|
||||
SPI flash devices are physically divided in blocks. On some SPI flash devices,
|
||||
blocks are further divided into sectors. Datasheets sometimes name blocks as
|
||||
sectors and vice versa.
|
||||
|
||||
Common memory capacaties for SPI flashes are 512kB up to 8MB of data, where
|
||||
blocks may be 64kB. Sectors can be e.g. 4kB, if supported. Many SPI flashes
|
||||
have uniform block sizes, whereas others have non-uniform - the latter meaning
|
||||
that e.g. the first 16 blocks are 4kB big, and the rest are 64kB.
|
||||
|
||||
The entire memory is linear and can be read and written in random access.
|
||||
Erasing can only be done block- or sectorwise; or by mass erase.
|
||||
|
||||
SPI flashes can normally be erased from 100.000 up to 1.000.000 cycles before
|
||||
they fail.
|
||||
|
||||
A clean SPI flash from factory have all bits in entire memory set to one. A
|
||||
mass erase will reset the device to this state. Block or sector erasing will
|
||||
put the all bits in the area given by the sector or block to ones. Writing to a
|
||||
NOR flash pulls ones to zeroes. Writing 0xFF to an address is simply a no-op.
|
||||
|
||||
Writing 0b10101010 to a flash address holding 0b00001111 will yield 0b00001010.
|
||||
|
||||
This way of "write by nand" is used considerably in spiffs.
|
||||
|
||||
Common characteristics of NOR flashes are quick reads, but slow writes.
|
||||
|
||||
And finally, unlike NAND flashes, NOR flashes seem to not need any error
|
||||
correction. They always write correctly I gather.
|
||||
|
||||
|
||||
** Spiffs logical structure
|
||||
|
||||
Some terminology before proceeding. Physical blocks/sectors means sizes stated
|
||||
in the datasheet. Logical blocks and pages is something the integrator choose.
|
||||
|
||||
|
||||
** Blocks and pages
|
||||
|
||||
Spiffs is allocated to a part or all of the memory of the SPI flash device.
|
||||
This area is divided into logical blocks, which in turn are divided into
|
||||
logical pages. The boundary of a logical block must coincide with one or more
|
||||
physical blocks. The sizes for logical blocks and logical pages always remain
|
||||
the same, they are uniform.
|
||||
|
||||
Example: non-uniform flash mapped to spiffs with 128kB logical blocks
|
||||
|
||||
PHYSICAL FLASH BLOCKS SPIFFS LOGICAL BLOCKS: 128kB
|
||||
|
||||
+-----------------------+ - - - +-----------------------+
|
||||
| Block 1 : 16kB | | Block 1 : 128kB |
|
||||
+-----------------------+ | |
|
||||
| Block 2 : 16kB | | |
|
||||
+-----------------------+ | |
|
||||
| Block 3 : 16kB | | |
|
||||
+-----------------------+ | |
|
||||
| Block 4 : 16kB | | |
|
||||
+-----------------------+ | |
|
||||
| Block 5 : 64kB | | |
|
||||
+-----------------------+ - - - +-----------------------+
|
||||
| Block 6 : 64kB | | Block 2 : 128kB |
|
||||
+-----------------------+ | |
|
||||
| Block 7 : 64kB | | |
|
||||
+-----------------------+ - - - +-----------------------+
|
||||
| Block 8 : 64kB | | Block 3 : 128kB |
|
||||
+-----------------------+ | |
|
||||
| Block 9 : 64kB | | |
|
||||
+-----------------------+ - - - +-----------------------+
|
||||
| ... | | ... |
|
||||
|
||||
A logical block is divided further into a number of logical pages. A page
|
||||
defines the smallest data holding element known to spiffs. Hence, if a file
|
||||
is created being one byte big, it will occupy one page for index and one page
|
||||
for data - it will occupy 2 x size of a logical page on flash.
|
||||
So it seems it is good to select a small page size.
|
||||
|
||||
Each page has a metadata header being normally 5 to 9 bytes. This said, a very
|
||||
small page size will make metadata occupy a lot of the memory on the flash. A
|
||||
page size of 64 bytes will waste 8-14% on metadata, while 256 bytes 2-4%.
|
||||
So it seems it is good to select a big page size.
|
||||
|
||||
Also, spiffs uses a ram buffer being two times the page size. This ram buffer
|
||||
is used for loading and manipulating pages, but it is also used for algorithms
|
||||
to find free file ids, scanning the file system, etc. Having too small a page
|
||||
size means less work buffer for spiffs, ending up in more reads operations and
|
||||
eventually gives a slower file system.
|
||||
|
||||
Choosing the page size for the system involves many factors:
|
||||
- How big is the logical block size
|
||||
- What is the normal size of most files
|
||||
- How much ram can be spent
|
||||
- How much data (vs metadata) must be crammed into the file system
|
||||
- How fast must spiffs be
|
||||
- Other things impossible to find out
|
||||
|
||||
So, chosing the Optimal Page Size (tm) seems tricky, to say the least. Don't
|
||||
fret - there is no optimal page size. This varies from how the target will use
|
||||
spiffs. Use the golden rule:
|
||||
|
||||
~~~ Logical Page Size = Logical Block Size / 256 ~~~
|
||||
|
||||
This is a good starting point. The final page size can then be derived through
|
||||
heuristical experimenting for us non-analytical minds.
|
||||
|
||||
|
||||
** Objects, indices and look-ups
|
||||
|
||||
A file, or an object as called in spiffs, is identified by an object id.
|
||||
Another YAFFS rip-off. This object id is a part of the page header. So, all
|
||||
pages know to which object/file they belong - not counting the free pages.
|
||||
|
||||
An object is made up of two types of pages: object index pages and data pages.
|
||||
Data pages contain the data written by user. Index pages contain metadata about
|
||||
the object, more specifically what data pages are part of the object.
|
||||
|
||||
The page header also includes something called a span index. Let's say a file
|
||||
is written covering three data pages. The first data page will then have span
|
||||
index 0, the second span index 1, and the last data page will have span index
|
||||
2. Simple as that.
|
||||
|
||||
Finally, each page header contain flags, telling if the page is used,
|
||||
deleted, finalized, holds index or data, and more.
|
||||
|
||||
Object indices also have span indices, where an object index with span index 0
|
||||
is referred to as the object index header. This page does not only contain
|
||||
references to data pages, but also extra info such as object name, object size
|
||||
in bytes, flags for file or directory, etc.
|
||||
|
||||
If one were to create a file covering three data pages, named e.g.
|
||||
"spandex-joke.txt", given object id 12, it could look like this:
|
||||
|
||||
PAGE 0 <things to be unveiled soon>
|
||||
|
||||
PAGE 1 page header: [obj_id:12 span_ix:0 flags:USED|DATA]
|
||||
<first data page of joke>
|
||||
|
||||
PAGE 2 page header: [obj_id:12 span_ix:1 flags:USED|DATA]
|
||||
<second data page of joke>
|
||||
|
||||
PAGE 3 page header: [obj_id:545 span_ix:13 flags:USED|DATA]
|
||||
<some data belonging to object 545, probably not very amusing>
|
||||
|
||||
PAGE 4 page header: [obj_id:12 span_ix:2 flags:USED|DATA]
|
||||
<third data page of joke>
|
||||
|
||||
PAGE 5 page header: [obj_id:12 span_ix:0 flags:USED|INDEX]
|
||||
obj ix header: [name:spandex-joke.txt size:600 bytes flags:FILE]
|
||||
obj ix: [1 2 4]
|
||||
|
||||
Looking in detail at page 5, the object index header page, the object index
|
||||
array refers to each data page in order, as mentioned before. The index of the
|
||||
object index array correlates with the data page span index.
|
||||
|
||||
entry ix: 0 1 2
|
||||
obj ix: [1 2 4]
|
||||
| | |
|
||||
PAGE 1, DATA, SPAN_IX 0 --------/ | |
|
||||
PAGE 2, DATA, SPAN_IX 1 --------/ |
|
||||
PAGE 4, DATA, SPAN_IX 2 --------/
|
||||
|
||||
Things to be unveiled in page 0 - well.. Spiffs is designed for systems low on
|
||||
ram. We cannot keep a dynamic list on the whereabouts of each object index
|
||||
header so we can find a file fast. There might not even be a heap! But, we do
|
||||
not want to scan all page headers on the flash to find the object index header.
|
||||
|
||||
The first page(s) of each block contains the so called object look-up. These
|
||||
are not normal pages, they do not have a header. Instead, they are arrays
|
||||
pointing out what object-id the rest of all pages in the block belongs to.
|
||||
|
||||
By this look-up, only the first page(s) in each block must to scanned to find
|
||||
the actual page which contains the object index header of the desired object.
|
||||
|
||||
The object lookup is redundant metadata. The assumption is that it presents
|
||||
less overhead reading a full page of data to memory from each block and search
|
||||
that, instead of reading a small amount of data from each page (i.e. the page
|
||||
header) in all blocks. Each read operation from SPI flash normally contains
|
||||
extra data as the read command itself and the flash address. Also, depending on
|
||||
the underlying implementation, other criterions may need to be passed for each
|
||||
read transaction, like mutexes and such.
|
||||
|
||||
The veiled example unveiled would look like this, with some extra pages:
|
||||
|
||||
PAGE 0 [ 12 12 545 12 12 34 34 4 0 0 0 0 ...]
|
||||
PAGE 1 page header: [obj_id:12 span_ix:0 flags:USED|DATA] ...
|
||||
PAGE 2 page header: [obj_id:12 span_ix:1 flags:USED|DATA] ...
|
||||
PAGE 3 page header: [obj_id:545 span_ix:13 flags:USED|DATA] ...
|
||||
PAGE 4 page header: [obj_id:12 span_ix:2 flags:USED|DATA] ...
|
||||
PAGE 5 page header: [obj_id:12 span_ix:0 flags:USED|INDEX] ...
|
||||
PAGE 6 page header: [obj_id:34 span_ix:0 flags:USED|DATA] ...
|
||||
PAGE 7 page header: [obj_id:34 span_ix:1 flags:USED|DATA] ...
|
||||
PAGE 8 page header: [obj_id:4 span_ix:1 flags:USED|INDEX] ...
|
||||
PAGE 9 page header: [obj_id:23 span_ix:0 flags:DELETED|INDEX] ...
|
||||
PAGE 10 page header: [obj_id:23 span_ix:0 flags:DELETED|DATA] ...
|
||||
PAGE 11 page header: [obj_id:23 span_ix:1 flags:DELETED|DATA] ...
|
||||
PAGE 12 page header: [obj_id:23 span_ix:2 flags:DELETED|DATA] ...
|
||||
...
|
||||
|
||||
Ok, so why are page 9 to 12 marked as 0 when they belong to object id 23? These
|
||||
pages are deleted, so this is marked both in page header flags and in the look
|
||||
up. This is an example where spiffs uses NOR flashes "nand-way" of writing.
|
||||
|
||||
As a matter of fact, there are two object id's which are special:
|
||||
|
||||
obj id 0 (all bits zeroes) - indicates a deleted page in object look up
|
||||
obj id 0xff.. (all bits ones) - indicates a free page in object look up
|
||||
|
||||
Actually, the object id's have another quirk: if the most significant bit is
|
||||
set, this indicates an object index page. If the most significant bit is zero,
|
||||
this indicates a data page. So to be fully correct, page 0 in above example
|
||||
would look like this:
|
||||
|
||||
PAGE 0 [ 12 12 545 12 *12 34 34 *4 0 0 0 0 ...]
|
||||
|
||||
where the asterisk means the msb of the object id is set.
|
||||
|
||||
This is another way to speed up the searches when looking for object indices.
|
||||
By looking on the object id's msb in the object lookup, it is also possible
|
||||
to find out whether the page is an object index page or a data page.
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
* When mending lost pages, also see if they fit into length specified in object index header
|
||||
|
||||
SPIFFS2 thoughts
|
||||
|
||||
* Instead of exact object id:s in the object lookup tables, use a hash of span index and object id.
|
||||
Eg. object id xor:ed with bit-reversed span index.
|
||||
This should decrease number of actual pages that needs to be visited when looking thru the obj lut.
|
||||
|
||||
* Logical number of each block. When moving stuff in a garbage collected page, the free
|
||||
page is assigned the same number as the garbage collected. Thus, object index pages do not have to
|
||||
be rewritten.
|
||||
|
||||
* Steal one page, use as a bit parity page. When starting an fs modification operation, write one bit
|
||||
as zero. When ending, write another bit as zero. On mount, if number of zeroes in page is uneven, a
|
||||
check is automatically run.
|
||||
@@ -1,681 +0,0 @@
|
||||
/*
|
||||
* spiffs.h
|
||||
*
|
||||
* Created on: May 26, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#ifndef SPIFFS_H_
|
||||
#define SPIFFS_H_
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "spiffs_config.h"
|
||||
|
||||
#define SPIFFS_OK 0
|
||||
#define SPIFFS_ERR_NOT_MOUNTED -10000
|
||||
#define SPIFFS_ERR_FULL -10001
|
||||
#define SPIFFS_ERR_NOT_FOUND -10002
|
||||
#define SPIFFS_ERR_END_OF_OBJECT -10003
|
||||
#define SPIFFS_ERR_DELETED -10004
|
||||
#define SPIFFS_ERR_NOT_FINALIZED -10005
|
||||
#define SPIFFS_ERR_NOT_INDEX -10006
|
||||
#define SPIFFS_ERR_OUT_OF_FILE_DESCS -10007
|
||||
#define SPIFFS_ERR_FILE_CLOSED -10008
|
||||
#define SPIFFS_ERR_FILE_DELETED -10009
|
||||
#define SPIFFS_ERR_BAD_DESCRIPTOR -10010
|
||||
#define SPIFFS_ERR_IS_INDEX -10011
|
||||
#define SPIFFS_ERR_IS_FREE -10012
|
||||
#define SPIFFS_ERR_INDEX_SPAN_MISMATCH -10013
|
||||
#define SPIFFS_ERR_DATA_SPAN_MISMATCH -10014
|
||||
#define SPIFFS_ERR_INDEX_REF_FREE -10015
|
||||
#define SPIFFS_ERR_INDEX_REF_LU -10016
|
||||
#define SPIFFS_ERR_INDEX_REF_INVALID -10017
|
||||
#define SPIFFS_ERR_INDEX_FREE -10018
|
||||
#define SPIFFS_ERR_INDEX_LU -10019
|
||||
#define SPIFFS_ERR_INDEX_INVALID -10020
|
||||
#define SPIFFS_ERR_NOT_WRITABLE -10021
|
||||
#define SPIFFS_ERR_NOT_READABLE -10022
|
||||
#define SPIFFS_ERR_CONFLICTING_NAME -10023
|
||||
#define SPIFFS_ERR_NOT_CONFIGURED -10024
|
||||
|
||||
#define SPIFFS_ERR_NOT_A_FS -10025
|
||||
#define SPIFFS_ERR_MOUNTED -10026
|
||||
#define SPIFFS_ERR_ERASE_FAIL -10027
|
||||
#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE -10028
|
||||
|
||||
#define SPIFFS_ERR_NO_DELETED_BLOCKS -10029
|
||||
|
||||
#define SPIFFS_ERR_FILE_EXISTS -10030
|
||||
|
||||
#define SPIFFS_ERR_NOT_A_FILE -10031
|
||||
#define SPIFFS_ERR_RO_NOT_IMPL -10032
|
||||
#define SPIFFS_ERR_RO_ABORTED_OPERATION -10033
|
||||
#define SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS -10034
|
||||
#define SPIFFS_ERR_PROBE_NOT_A_FS -10035
|
||||
#define SPIFFS_ERR_INTERNAL -10050
|
||||
|
||||
#define SPIFFS_ERR_TEST -10100
|
||||
|
||||
|
||||
// spiffs file descriptor index type. must be signed
|
||||
typedef s16_t spiffs_file;
|
||||
// spiffs file descriptor flags
|
||||
typedef u16_t spiffs_flags;
|
||||
// spiffs file mode
|
||||
typedef u16_t spiffs_mode;
|
||||
// object type
|
||||
typedef u8_t spiffs_obj_type;
|
||||
|
||||
struct spiffs_t;
|
||||
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* spi read call function type */
|
||||
typedef s32_t (*spiffs_read)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *dst);
|
||||
/* spi write call function type */
|
||||
typedef s32_t (*spiffs_write)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *src);
|
||||
/* spi erase call function type */
|
||||
typedef s32_t (*spiffs_erase)(struct spiffs_t *fs, u32_t addr, u32_t size);
|
||||
|
||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* spi read call function type */
|
||||
typedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst);
|
||||
/* spi write call function type */
|
||||
typedef s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src);
|
||||
/* spi erase call function type */
|
||||
typedef s32_t (*spiffs_erase)(u32_t addr, u32_t size);
|
||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* file system check callback report operation */
|
||||
typedef enum {
|
||||
SPIFFS_CHECK_LOOKUP = 0,
|
||||
SPIFFS_CHECK_INDEX,
|
||||
SPIFFS_CHECK_PAGE
|
||||
} spiffs_check_type;
|
||||
|
||||
/* file system check callback report type */
|
||||
typedef enum {
|
||||
SPIFFS_CHECK_PROGRESS = 0,
|
||||
SPIFFS_CHECK_ERROR,
|
||||
SPIFFS_CHECK_FIX_INDEX,
|
||||
SPIFFS_CHECK_FIX_LOOKUP,
|
||||
SPIFFS_CHECK_DELETE_ORPHANED_INDEX,
|
||||
SPIFFS_CHECK_DELETE_PAGE,
|
||||
SPIFFS_CHECK_DELETE_BAD_FILE,
|
||||
} spiffs_check_report;
|
||||
|
||||
/* file system check callback function */
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
typedef void (*spiffs_check_callback)(struct spiffs_t *fs, spiffs_check_type type, spiffs_check_report report,
|
||||
u32_t arg1, u32_t arg2);
|
||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report,
|
||||
u32_t arg1, u32_t arg2);
|
||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* file system listener callback operation */
|
||||
typedef enum {
|
||||
/* the file has been created */
|
||||
SPIFFS_CB_CREATED = 0,
|
||||
/* the file has been updated or moved to another page */
|
||||
SPIFFS_CB_UPDATED,
|
||||
/* the file has been deleted */
|
||||
SPIFFS_CB_DELETED,
|
||||
} spiffs_fileop_type;
|
||||
|
||||
/* file system listener callback function */
|
||||
typedef void (*spiffs_file_callback)(struct spiffs_t *fs, spiffs_fileop_type op, spiffs_obj_id obj_id, spiffs_page_ix pix);
|
||||
|
||||
#ifndef SPIFFS_DBG
|
||||
#define SPIFFS_DBG(...) \
|
||||
print(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef SPIFFS_GC_DBG
|
||||
#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef SPIFFS_CACHE_DBG
|
||||
#define SPIFFS_CACHE_DBG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef SPIFFS_CHECK_DBG
|
||||
#define SPIFFS_CHECK_DBG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* Any write to the filehandle is appended to end of the file */
|
||||
#define SPIFFS_APPEND (1<<0)
|
||||
/* If the opened file exists, it will be truncated to zero length before opened */
|
||||
#define SPIFFS_TRUNC (1<<1)
|
||||
/* If the opened file does not exist, it will be created before opened */
|
||||
#define SPIFFS_CREAT (1<<2)
|
||||
/* The opened file may only be read */
|
||||
#define SPIFFS_RDONLY (1<<3)
|
||||
/* The opened file may only be writted */
|
||||
#define SPIFFS_WRONLY (1<<4)
|
||||
/* The opened file may be both read and writted */
|
||||
#define SPIFFS_RDWR (SPIFFS_RDONLY | SPIFFS_WRONLY)
|
||||
/* Any writes to the filehandle will never be cached */
|
||||
#define SPIFFS_DIRECT (1<<5)
|
||||
/* If SPIFFS_CREAT and SPIFFS_EXCL are set, SPIFFS_open() shall fail if the file exists */
|
||||
#define SPIFFS_EXCL (1<<6)
|
||||
|
||||
#define SPIFFS_SEEK_SET (0)
|
||||
#define SPIFFS_SEEK_CUR (1)
|
||||
#define SPIFFS_SEEK_END (2)
|
||||
|
||||
#define SPIFFS_TYPE_FILE (1)
|
||||
#define SPIFFS_TYPE_DIR (2)
|
||||
#define SPIFFS_TYPE_HARD_LINK (3)
|
||||
#define SPIFFS_TYPE_SOFT_LINK (4)
|
||||
|
||||
#ifndef SPIFFS_LOCK
|
||||
#define SPIFFS_LOCK(fs)
|
||||
#endif
|
||||
|
||||
#ifndef SPIFFS_UNLOCK
|
||||
#define SPIFFS_UNLOCK(fs)
|
||||
#endif
|
||||
|
||||
// phys structs
|
||||
|
||||
// spiffs spi configuration struct
|
||||
typedef struct {
|
||||
// physical read function
|
||||
spiffs_read hal_read_f;
|
||||
// physical write function
|
||||
spiffs_write hal_write_f;
|
||||
// physical erase function
|
||||
spiffs_erase hal_erase_f;
|
||||
#if SPIFFS_SINGLETON == 0
|
||||
// physical size of the spi flash
|
||||
u32_t phys_size;
|
||||
// physical offset in spi flash used for spiffs,
|
||||
// must be on block boundary
|
||||
u32_t phys_addr;
|
||||
// physical size when erasing a block
|
||||
u32_t phys_erase_block;
|
||||
|
||||
// logical size of a block, must be on physical
|
||||
// block size boundary and must never be less than
|
||||
// a physical block
|
||||
u32_t log_block_size;
|
||||
// logical size of a page, must be at least
|
||||
// log_block_size / 8
|
||||
u32_t log_page_size;
|
||||
|
||||
#endif
|
||||
#if SPIFFS_FILEHDL_OFFSET
|
||||
// an integer offset added to each file handle
|
||||
u16_t fh_ix_offset;
|
||||
#endif
|
||||
} spiffs_config;
|
||||
|
||||
typedef struct spiffs_t {
|
||||
// file system configuration
|
||||
spiffs_config cfg;
|
||||
// number of logical blocks
|
||||
u32_t block_count;
|
||||
|
||||
// cursor for free blocks, block index
|
||||
spiffs_block_ix free_cursor_block_ix;
|
||||
// cursor for free blocks, entry index
|
||||
int free_cursor_obj_lu_entry;
|
||||
// cursor when searching, block index
|
||||
spiffs_block_ix cursor_block_ix;
|
||||
// cursor when searching, entry index
|
||||
int cursor_obj_lu_entry;
|
||||
|
||||
// primary work buffer, size of a logical page
|
||||
u8_t *lu_work;
|
||||
// secondary work buffer, size of a logical page
|
||||
u8_t *work;
|
||||
// file descriptor memory area
|
||||
u8_t *fd_space;
|
||||
// available file descriptors
|
||||
u32_t fd_count;
|
||||
|
||||
// last error
|
||||
s32_t err_code;
|
||||
|
||||
// current number of free blocks
|
||||
u32_t free_blocks;
|
||||
// current number of busy pages
|
||||
u32_t stats_p_allocated;
|
||||
// current number of deleted pages
|
||||
u32_t stats_p_deleted;
|
||||
// flag indicating that garbage collector is cleaning
|
||||
u8_t cleaning;
|
||||
// max erase count amongst all blocks
|
||||
spiffs_obj_id max_erase_count;
|
||||
|
||||
#if SPIFFS_GC_STATS
|
||||
u32_t stats_gc_runs;
|
||||
#endif
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
// cache memory
|
||||
void *cache;
|
||||
// cache size
|
||||
u32_t cache_size;
|
||||
#if SPIFFS_CACHE_STATS
|
||||
u32_t cache_hits;
|
||||
u32_t cache_misses;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// check callback function
|
||||
spiffs_check_callback check_cb_f;
|
||||
// file callback function
|
||||
spiffs_file_callback file_cb_f;
|
||||
// mounted flag
|
||||
u8_t mounted;
|
||||
// user data
|
||||
void *user_data;
|
||||
// config magic
|
||||
u32_t config_magic;
|
||||
} spiffs;
|
||||
|
||||
/* spiffs file status struct */
|
||||
typedef struct {
|
||||
spiffs_obj_id obj_id;
|
||||
u32_t size;
|
||||
spiffs_obj_type type;
|
||||
spiffs_page_ix pix;
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
} spiffs_stat;
|
||||
|
||||
struct spiffs_dirent {
|
||||
spiffs_obj_id obj_id;
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
spiffs_obj_type type;
|
||||
u32_t size;
|
||||
spiffs_page_ix pix;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
spiffs *fs;
|
||||
spiffs_block_ix block;
|
||||
int entry;
|
||||
} spiffs_DIR;
|
||||
|
||||
// functions
|
||||
|
||||
#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
|
||||
/**
|
||||
* Special function. This takes a spiffs config struct and returns the number
|
||||
* of blocks this file system was formatted with. This function relies on
|
||||
* that following info is set correctly in given config struct:
|
||||
*
|
||||
* phys_addr, log_page_size, and log_block_size.
|
||||
*
|
||||
* Also, hal_read_f must be set in the config struct.
|
||||
*
|
||||
* One must be sure of the correct page size and that the physical address is
|
||||
* correct in the probed file system when calling this function. It is not
|
||||
* checked if the phys_addr actually points to the start of the file system,
|
||||
* so one might get a false positive if entering a phys_addr somewhere in the
|
||||
* middle of the file system at block boundary. In addition, it is not checked
|
||||
* if the page size is actually correct. If it is not, weird file system sizes
|
||||
* will be returned.
|
||||
*
|
||||
* If this function detects a file system it returns the assumed file system
|
||||
* size, which can be used to set the phys_size.
|
||||
*
|
||||
* Otherwise, it returns an error indicating why it is not regarded as a file
|
||||
* system.
|
||||
*
|
||||
* Note: this function is not protected with SPIFFS_LOCK and SPIFFS_UNLOCK
|
||||
* macros. It returns the error code directly, instead of as read by
|
||||
* SPIFFS_errno.
|
||||
*
|
||||
* @param config essential parts of the physical and logical
|
||||
* configuration of the file system.
|
||||
*/
|
||||
s32_t SPIFFS_probe_fs(spiffs_config *config);
|
||||
#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
|
||||
|
||||
/**
|
||||
* Initializes the file system dynamic parameters and mounts the filesystem.
|
||||
* If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS
|
||||
* if the flash does not contain a recognizable file system.
|
||||
* In this case, SPIFFS_format must be called prior to remounting.
|
||||
* @param fs the file system struct
|
||||
* @param config the physical and logical configuration of the file system
|
||||
* @param work a memory work buffer comprising 2*config->log_page_size
|
||||
* bytes used throughout all file system operations
|
||||
* @param fd_space memory for file descriptors
|
||||
* @param fd_space_size memory size of file descriptors
|
||||
* @param cache memory for cache, may be null
|
||||
* @param cache_size memory size of cache
|
||||
* @param check_cb_f callback function for reporting during consistency checks
|
||||
*/
|
||||
s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
|
||||
u8_t *fd_space, u32_t fd_space_size,
|
||||
void *cache, u32_t cache_size,
|
||||
spiffs_check_callback check_cb_f);
|
||||
|
||||
/**
|
||||
* Unmounts the file system. All file handles will be flushed of any
|
||||
* cached writes and closed.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
void SPIFFS_unmount(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Creates a new file.
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the new file
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Opens/creates a file.
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the new file
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
||||
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Opens a file by given dir entry.
|
||||
* Optimization purposes, when traversing a file system with SPIFFS_readdir
|
||||
* a normal SPIFFS_open would need to traverse the filesystem again to find
|
||||
* the file, whilst SPIFFS_open_by_dirent already knows where the file resides.
|
||||
* @param fs the file system struct
|
||||
* @param e the dir entry to the file
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
||||
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
|
||||
* SPIFFS_CREAT will have no effect in this case.
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Opens a file by given page index.
|
||||
* Optimization purposes, opens a file by directly pointing to the page
|
||||
* index in the spi flash.
|
||||
* If the page index does not point to a file header SPIFFS_ERR_NOT_A_FILE
|
||||
* is returned.
|
||||
* @param fs the file system struct
|
||||
* @param page_ix the page index
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
||||
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
|
||||
* SPIFFS_CREAT will have no effect in this case.
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Reads from given filehandle.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param buf where to put read data
|
||||
* @param len how much to read
|
||||
* @returns number of bytes read, or -1 if error
|
||||
*/
|
||||
s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
|
||||
|
||||
/**
|
||||
* Writes to given filehandle.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param buf the data to write
|
||||
* @param len how much to write
|
||||
* @returns number of bytes written, or -1 if error
|
||||
*/
|
||||
s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
|
||||
|
||||
/**
|
||||
* Moves the read/write file offset. Resulting offset is returned or negative if error.
|
||||
* lseek(fs, fd, 0, SPIFFS_SEEK_CUR) will thus return current offset.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param offs how much/where to move the offset
|
||||
* @param whence if SPIFFS_SEEK_SET, the file offset shall be set to offset bytes
|
||||
* if SPIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset
|
||||
* if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offse, which should be negative
|
||||
*/
|
||||
s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence);
|
||||
|
||||
/**
|
||||
* Removes a file by path
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the file to remove
|
||||
*/
|
||||
s32_t SPIFFS_remove(spiffs *fs, const char *path);
|
||||
|
||||
/**
|
||||
* Removes a file by filehandle
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to remove
|
||||
*/
|
||||
s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Gets file status by path
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the file to stat
|
||||
* @param s the stat struct to populate
|
||||
*/
|
||||
s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s);
|
||||
|
||||
/**
|
||||
* Gets file status by filehandle
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to stat
|
||||
* @param s the stat struct to populate
|
||||
*/
|
||||
s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s);
|
||||
|
||||
/**
|
||||
* Flushes all pending write operations from cache for given file
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to flush
|
||||
*/
|
||||
s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Closes a filehandle. If there are pending write operations, these are finalized before closing.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to close
|
||||
*/
|
||||
s32_t SPIFFS_close(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Renames a file
|
||||
* @param fs the file system struct
|
||||
* @param old path of file to rename
|
||||
* @param newPath new path of file
|
||||
*/
|
||||
s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newPath);
|
||||
|
||||
/**
|
||||
* Returns last error of last file operation.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_errno(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Clears last error.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
void SPIFFS_clearerr(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Opens a directory stream corresponding to the given name.
|
||||
* The stream is positioned at the first entry in the directory.
|
||||
* On hydrogen builds the name argument is ignored as hydrogen builds always correspond
|
||||
* to a flat file structure - no directories.
|
||||
* @param fs the file system struct
|
||||
* @param name the name of the directory
|
||||
* @param d pointer the directory stream to be populated
|
||||
*/
|
||||
spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d);
|
||||
|
||||
/**
|
||||
* Closes a directory stream
|
||||
* @param d the directory stream to close
|
||||
*/
|
||||
s32_t SPIFFS_closedir(spiffs_DIR *d);
|
||||
|
||||
/**
|
||||
* Reads a directory into given spifs_dirent struct.
|
||||
* @param d pointer to the directory stream
|
||||
* @param e the dirent struct to be populated
|
||||
* @returns null if error or end of stream, else given dirent is returned
|
||||
*/
|
||||
struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);
|
||||
|
||||
/**
|
||||
* Runs a consistency check on given filesystem.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_check(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Returns number of total bytes available and number of used bytes.
|
||||
* This is an estimation, and depends on if there a many files with little
|
||||
* data or few files with much data.
|
||||
* NB: If used number of bytes exceeds total bytes, a SPIFFS_check should
|
||||
* run. This indicates a power loss in midst of things. In worst case
|
||||
* (repeated powerlosses in mending or gc) you might have to delete some files.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param total total number of bytes in filesystem
|
||||
* @param used used number of bytes in filesystem
|
||||
*/
|
||||
s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);
|
||||
|
||||
/**
|
||||
* Formats the entire file system. All data will be lost.
|
||||
* The filesystem must not be mounted when calling this.
|
||||
*
|
||||
* NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount
|
||||
* MUST be called prior to formatting in order to configure the filesystem.
|
||||
* If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling
|
||||
* SPIFFS_format.
|
||||
* If SPIFFS_mount fails, SPIFFS_format can be called directly without calling
|
||||
* SPIFFS_unmount first.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_format(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Returns nonzero if spiffs is mounted, or zero if unmounted.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
u8_t SPIFFS_mounted(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Tries to find a block where most or all pages are deleted, and erase that
|
||||
* block if found. Does not care for wear levelling. Will not move pages
|
||||
* around.
|
||||
* If parameter max_free_pages are set to 0, only blocks with only deleted
|
||||
* pages will be selected.
|
||||
*
|
||||
* NB: the garbage collector is automatically called when spiffs needs free
|
||||
* pages. The reason for this function is to give possibility to do background
|
||||
* tidying when user knows the system is idle.
|
||||
*
|
||||
* Use with care.
|
||||
*
|
||||
* Setting max_free_pages to anything larger than zero will eventually wear
|
||||
* flash more as a block containing free pages can be erased.
|
||||
*
|
||||
* Will set err_no to SPIFFS_OK if a block was found and erased,
|
||||
* SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found,
|
||||
* or other error.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param max_free_pages maximum number allowed free pages in block
|
||||
*/
|
||||
s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages);
|
||||
|
||||
/**
|
||||
* Will try to make room for given amount of bytes in the filesystem by moving
|
||||
* pages and erasing blocks.
|
||||
* If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If
|
||||
* there already is this amount (or more) of free space, SPIFFS_gc will
|
||||
* silently return. It is recommended to call SPIFFS_info before invoking
|
||||
* this method in order to determine what amount of bytes to give.
|
||||
*
|
||||
* NB: the garbage collector is automatically called when spiffs needs free
|
||||
* pages. The reason for this function is to give possibility to do background
|
||||
* tidying when user knows the system is idle.
|
||||
*
|
||||
* Use with care.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param size amount of bytes that should be freed
|
||||
*/
|
||||
s32_t SPIFFS_gc(spiffs *fs, u32_t size);
|
||||
|
||||
/**
|
||||
* Check if EOF reached.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to check
|
||||
*/
|
||||
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Get position in file.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to check
|
||||
*/
|
||||
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Registers a callback function that keeps track on operations on file
|
||||
* headers. Do note, that this callback is called from within internal spiffs
|
||||
* mechanisms. Any operations on the actual file system being callbacked from
|
||||
* in this callback will mess things up for sure - do not do this.
|
||||
* This can be used to track where files are and move around during garbage
|
||||
* collection, which in turn can be used to build location tables in ram.
|
||||
* Used in conjuction with SPIFFS_open_by_page this may improve performance
|
||||
* when opening a lot of files.
|
||||
* Must be invoked after mount.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param cb_func the callback on file operations
|
||||
*/
|
||||
s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func);
|
||||
|
||||
#if SPIFFS_TEST_VISUALISATION
|
||||
/**
|
||||
* Prints out a visualization of the filesystem.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_vis(spiffs *fs);
|
||||
#endif
|
||||
|
||||
#if SPIFFS_BUFFER_HELP
|
||||
/**
|
||||
* Returns number of bytes needed for the filedescriptor buffer given
|
||||
* amount of file descriptors.
|
||||
*/
|
||||
u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs);
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
/**
|
||||
* Returns number of bytes needed for the cache buffer given
|
||||
* amount of cache pages.
|
||||
*/
|
||||
u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
#endif
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SPIFFS_H_ */
|
||||
@@ -1,299 +0,0 @@
|
||||
/*
|
||||
* spiffs_cache.c
|
||||
*
|
||||
* Created on: Jun 23, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
|
||||
// returns cached page for give page index, or null if no such cached page
|
||||
static spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) return 0;
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->cpage_use_map & (1<<i)) &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||
cp->pix == pix ) {
|
||||
SPIFFS_CACHE_DBG("CACHE_GET: have cache page %i for %04x\n", i, pix);
|
||||
cp->last_access = cache->last_access;
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
//SPIFFS_CACHE_DBG("CACHE_GET: no cache for %04x\n", pix);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// frees cached page
|
||||
static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, ix);
|
||||
if (cache->cpage_use_map & (1<<ix)) {
|
||||
if (write_back &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, ix);
|
||||
res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
|
||||
}
|
||||
|
||||
cp->flags = 0;
|
||||
cache->cpage_use_map &= ~(1 << ix);
|
||||
|
||||
if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) {
|
||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %i objid %04x\n", ix, cp->obj_id);
|
||||
} else {
|
||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %i pix %04x\n", ix, cp->pix);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// removes the oldest accessed cached page
|
||||
static s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask) {
|
||||
// at least one free cpage
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
// all busy, scan thru all to find the cpage which has oldest access
|
||||
int i;
|
||||
int cand_ix = -1;
|
||||
u32_t oldest_val = 0;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->last_access - cp->last_access) > oldest_val &&
|
||||
(cp->flags & flag_mask) == flags) {
|
||||
oldest_val = cache->last_access - cp->last_access;
|
||||
cand_ix = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (cand_ix >= 0) {
|
||||
res = spiffs_cache_page_free(fs, cand_ix, 1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// allocates a new cached page and returns it, or null if all cache pages are busy
|
||||
static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
if (cache->cpage_use_map == 0xffffffff) {
|
||||
// out of cache memory
|
||||
return 0;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
if ((cache->cpage_use_map & (1<<i)) == 0) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
cache->cpage_use_map |= (1<<i);
|
||||
cp->last_access = cache->last_access;
|
||||
SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page %i\n", i);
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
// out of cache entries
|
||||
return 0;
|
||||
}
|
||||
|
||||
// drops the cache page for give page index
|
||||
void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix) {
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
||||
if (cp) {
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
|
||||
// reads from spi flash or the cache
|
||||
s32_t spiffs_phys_rd(
|
||||
spiffs *fs,
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *dst) {
|
||||
(void)fh;
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, SPIFFS_PADDR_TO_PAGE(fs, addr));
|
||||
cache->last_access++;
|
||||
if (cp) {
|
||||
#if SPIFFS_CACHE_STATS
|
||||
fs->cache_hits++;
|
||||
#endif
|
||||
cp->last_access = cache->last_access;
|
||||
} else {
|
||||
if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {
|
||||
// for second layer lookup functions, we do not cache in order to prevent shredding
|
||||
return SPIFFS_HAL_READ(fs, addr, len, dst);
|
||||
}
|
||||
#if SPIFFS_CACHE_STATS
|
||||
fs->cache_misses++;
|
||||
#endif
|
||||
res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
||||
cp = spiffs_cache_page_allocate(fs);
|
||||
if (cp) {
|
||||
cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;
|
||||
cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
||||
}
|
||||
s32_t res2 = SPIFFS_HAL_READ(fs,
|
||||
addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs),
|
||||
spiffs_get_cache_page(fs, cache, cp->ix));
|
||||
if (res2 != SPIFFS_OK) {
|
||||
res = res2;
|
||||
}
|
||||
}
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||
memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
|
||||
return res;
|
||||
}
|
||||
|
||||
// writes to spi flash and/or the cache
|
||||
s32_t spiffs_phys_wr(
|
||||
spiffs *fs,
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *src) {
|
||||
(void)fh;
|
||||
spiffs_page_ix pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
||||
|
||||
if (cp && (op & SPIFFS_OP_COM_MASK) != SPIFFS_OP_C_WRTHRU) {
|
||||
// have a cache page
|
||||
// copy in data to cache page
|
||||
|
||||
if ((op & SPIFFS_OP_COM_MASK) == SPIFFS_OP_C_DELE &&
|
||||
(op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {
|
||||
// page is being deleted, wipe from cache - unless it is a lookup page
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
}
|
||||
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||
memcpy(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);
|
||||
|
||||
cache->last_access++;
|
||||
cp->last_access = cache->last_access;
|
||||
|
||||
if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) {
|
||||
// page is being updated, no write-cache, just pass thru
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
} else {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
} else {
|
||||
// no cache page, no write cache - just write thru
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
}
|
||||
}
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
// returns the cache page that this fd refers, or null if no cache page
|
||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) {
|
||||
// all cpages free, no cpage cannot be assigned to obj_id
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->cpage_use_map & (1<<i)) &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) &&
|
||||
cp->obj_id == fd->obj_id) {
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// allocates a new cache page and refers this to given fd - flushes an old cache
|
||||
// page if all cache is busy
|
||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) {
|
||||
// before this function is called, it is ensured that there is no already existing
|
||||
// cache page with same object id
|
||||
spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_allocate(fs);
|
||||
if (cp == 0) {
|
||||
// could not get cache page
|
||||
return 0;
|
||||
}
|
||||
|
||||
cp->flags = SPIFFS_CACHE_FLAG_TYPE_WR;
|
||||
cp->obj_id = fd->obj_id;
|
||||
fd->cache_page = cp;
|
||||
return cp;
|
||||
}
|
||||
|
||||
// unrefers all fds that this cache page refers to and releases the cache page
|
||||
void spiffs_cache_fd_release(spiffs *fs, spiffs_cache_page *cp) {
|
||||
if (cp == 0) return;
|
||||
u32_t i;
|
||||
spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
|
||||
for (i = 0; i < fs->fd_count; i++) {
|
||||
spiffs_fd *cur_fd = &fds[i];
|
||||
if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp) {
|
||||
cur_fd->cache_page = 0;
|
||||
}
|
||||
}
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
|
||||
cp->obj_id = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// initializes the cache
|
||||
void spiffs_cache_init(spiffs *fs) {
|
||||
if (fs->cache == 0) return;
|
||||
u32_t sz = fs->cache_size;
|
||||
u32_t cache_mask = 0;
|
||||
int i;
|
||||
int cache_entries =
|
||||
(sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||
if (cache_entries <= 0) return;
|
||||
|
||||
for (i = 0; i < cache_entries; i++) {
|
||||
cache_mask <<= 1;
|
||||
cache_mask |= 1;
|
||||
}
|
||||
|
||||
spiffs_cache cache;
|
||||
memset(&cache, 0, sizeof(spiffs_cache));
|
||||
cache.cpage_count = cache_entries;
|
||||
cache.cpages = (u8_t *)((u8_t *)fs->cache + sizeof(spiffs_cache));
|
||||
|
||||
cache.cpage_use_map = 0xffffffff;
|
||||
cache.cpage_use_mask = cache_mask;
|
||||
memcpy(fs->cache, &cache, sizeof(spiffs_cache));
|
||||
|
||||
spiffs_cache *c = spiffs_get_cache(fs);
|
||||
|
||||
memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||
|
||||
c->cpage_use_map &= ~(c->cpage_use_mask);
|
||||
for (i = 0; i < cache.cpage_count; i++) {
|
||||
spiffs_get_cache_page_hdr(fs, c, i)->ix = i;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SPIFFS_CACHE
|
||||
@@ -1,995 +0,0 @@
|
||||
/*
|
||||
* spiffs_check.c
|
||||
*
|
||||
* Contains functionality for checking file system consistency
|
||||
* and mending problems.
|
||||
* Three levels of consistency checks are implemented:
|
||||
*
|
||||
* Look up consistency
|
||||
* Checks if indices in lookup pages are coherent with page headers
|
||||
* Object index consistency
|
||||
* Checks if there are any orphaned object indices (missing object index headers).
|
||||
* If an object index is found but not its header, the object index is deleted.
|
||||
* This is critical for the following page consistency check.
|
||||
* Page consistency
|
||||
* Checks for pages that ought to be indexed, ought not to be indexed, are multiple indexed
|
||||
*
|
||||
*
|
||||
* Created on: Jul 7, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
#if !SPIFFS_READ_ONLY
|
||||
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
|
||||
do { \
|
||||
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
|
||||
do { \
|
||||
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
//---------------------------------------
|
||||
// Look up consistency
|
||||
|
||||
// searches in the object indices and returns the referenced page index given
|
||||
// the object id and the data span index
|
||||
// destroys fs->lu_work
|
||||
static s32_t spiffs_object_get_data_page_index_reference(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix data_spix,
|
||||
spiffs_page_ix *pix,
|
||||
spiffs_page_ix *objix_pix) {
|
||||
s32_t res;
|
||||
|
||||
// calculate object index span index for given data page span index
|
||||
spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
|
||||
|
||||
// find obj index for obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, objix_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
// load obj index entry
|
||||
u32_t addr = SPIFFS_PAGE_TO_PADDR(fs, *objix_pix);
|
||||
if (objix_spix == 0) {
|
||||
// get referenced page from object index header
|
||||
addr += sizeof(spiffs_page_object_ix_header) + data_spix * sizeof(spiffs_page_ix);
|
||||
} else {
|
||||
// get referenced page from object index
|
||||
addr += sizeof(spiffs_page_object_ix) + SPIFFS_OBJ_IX_ENTRY(fs, data_spix) * sizeof(spiffs_page_ix);
|
||||
}
|
||||
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, 0, addr, sizeof(spiffs_page_ix), (u8_t *)pix);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// copies page contents to a new page
|
||||
static s32_t spiffs_rewrite_page(spiffs *fs, spiffs_page_ix cur_pix, spiffs_page_header *p_hdr, spiffs_page_ix *new_pix) {
|
||||
s32_t res;
|
||||
res = spiffs_page_allocate_data(fs, p_hdr->obj_id, p_hdr, 0,0,0,0, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_phys_cpy(fs, 0,
|
||||
SPIFFS_PAGE_TO_PADDR(fs, *new_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_DATA_PAGE_SIZE(fs));
|
||||
SPIFFS_CHECK_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// rewrites the object index for given object id and replaces the
|
||||
// data page index to a new page index
|
||||
static s32_t spiffs_rewrite_index(spiffs *fs, spiffs_obj_id obj_id, spiffs_span_ix data_spix, spiffs_page_ix new_data_pix, spiffs_page_ix objix_pix) {
|
||||
s32_t res;
|
||||
spiffs_block_ix bix;
|
||||
int entry;
|
||||
spiffs_page_ix free_pix;
|
||||
obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
|
||||
|
||||
// find free entry
|
||||
res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
|
||||
|
||||
// calculate object index span index for given data page span index
|
||||
spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
|
||||
if (objix_spix == 0) {
|
||||
// calc index in index header
|
||||
entry = data_spix;
|
||||
} else {
|
||||
// calc entry in index
|
||||
entry = SPIFFS_OBJ_IX_ENTRY(fs, data_spix);
|
||||
|
||||
}
|
||||
// load index
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;
|
||||
|
||||
// be ultra safe, double check header against provided data
|
||||
if (objix_p_hdr->obj_id != obj_id) {
|
||||
spiffs_page_delete(fs, free_pix);
|
||||
return SPIFFS_ERR_CHECK_OBJ_ID_MISM;
|
||||
}
|
||||
if (objix_p_hdr->span_ix != objix_spix) {
|
||||
spiffs_page_delete(fs, free_pix);
|
||||
return SPIFFS_ERR_CHECK_SPIX_MISM;
|
||||
}
|
||||
if ((objix_p_hdr->flags & (SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_INDEX |
|
||||
SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) !=
|
||||
(SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_DELET)) {
|
||||
spiffs_page_delete(fs, free_pix);
|
||||
return SPIFFS_ERR_CHECK_FLAGS_BAD;
|
||||
}
|
||||
|
||||
// rewrite in mem
|
||||
if (objix_spix == 0) {
|
||||
((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix;
|
||||
} else {
|
||||
((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix;
|
||||
}
|
||||
|
||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
|
||||
0, SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, free_pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, free_pix) * sizeof(spiffs_page_ix),
|
||||
sizeof(spiffs_obj_id),
|
||||
(u8_t *)&obj_id);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_page_delete(fs, objix_pix);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// deletes an object just by marking object index header as deleted
|
||||
static s32_t spiffs_delete_obj_lazy(spiffs *fs, spiffs_obj_id obj_id) {
|
||||
spiffs_page_ix objix_hdr_pix;
|
||||
s32_t res;
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, obj_id, 0, 0, &objix_hdr_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
u8_t flags = 0xff & ~SPIFFS_PH_FLAG_IXDELE;
|
||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags),
|
||||
sizeof(u8_t),
|
||||
(u8_t *)&flags);
|
||||
return res;
|
||||
}
|
||||
|
||||
// validates the given look up entry
|
||||
static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, spiffs_page_header *p_hdr,
|
||||
spiffs_page_ix cur_pix, spiffs_block_ix cur_block, int cur_entry, int *reload_lu) {
|
||||
(void)cur_block;
|
||||
(void)cur_entry;
|
||||
u8_t delete_page = 0;
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_page_ix objix_pix;
|
||||
spiffs_page_ix ref_pix;
|
||||
// check validity, take actions
|
||||
if (((lu_obj_id == SPIFFS_OBJ_ID_DELETED) && (p_hdr->flags & SPIFFS_PH_FLAG_DELET)) ||
|
||||
((lu_obj_id == SPIFFS_OBJ_ID_FREE) && (p_hdr->flags & SPIFFS_PH_FLAG_USED) == 0)) {
|
||||
// look up entry deleted / free but used in page header
|
||||
SPIFFS_CHECK_DBG("LU: pix %04x deleted/free in lu but not on page\n", cur_pix);
|
||||
*reload_lu = 1;
|
||||
delete_page = 1;
|
||||
if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
|
||||
// header says data page
|
||||
// data page can be removed if not referenced by some object index
|
||||
res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// no object with this id, so remove page safely
|
||||
res = SPIFFS_OK;
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (ref_pix == cur_pix) {
|
||||
// data page referenced by object index but deleted in lu
|
||||
// copy page to new place and re-write the object index to new place
|
||||
spiffs_page_ix new_pix;
|
||||
res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: data page not found elsewhere, rewriting %04x to new page %04x\n", cur_pix, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
*reload_lu = 1;
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: %04x rewritten to %04x, affected objix_pix %04x\n", cur_pix, new_pix, objix_pix);
|
||||
res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: index bad %i, cannot mend!\n", res);
|
||||
res = spiffs_page_delete(fs, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
|
||||
} else {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// header says index page
|
||||
// index page can be removed if other index with same obj_id and spanix is found
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, 0);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// no such index page found, check for a data page amongst page headers
|
||||
// lu cannot be trusted
|
||||
res = spiffs_obj_lu_find_id_and_span_by_phdr(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, 0);
|
||||
if (res == SPIFFS_OK) { // ignore other errors
|
||||
// got a data page also, assume lu corruption only, rewrite to new page
|
||||
spiffs_page_ix new_pix;
|
||||
res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting %04x to new page %04x\n", cur_pix, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
*reload_lu = 1;
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||
}
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lu_obj_id != SPIFFS_OBJ_ID_FREE && lu_obj_id != SPIFFS_OBJ_ID_DELETED) {
|
||||
// look up entry used
|
||||
if ((p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG) != (lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||
SPIFFS_CHECK_DBG("LU: pix %04x differ in obj_id lu:%04x ph:%04x\n", cur_pix, lu_obj_id, p_hdr->obj_id);
|
||||
delete_page = 1;
|
||||
if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0 ||
|
||||
(p_hdr->flags & SPIFFS_PH_FLAG_FINAL) ||
|
||||
(p_hdr->flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE)) == 0) {
|
||||
// page deleted or not finalized, just remove it
|
||||
} else {
|
||||
if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
|
||||
// if data page, check for reference to this page
|
||||
res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// no object with this id, so remove page safely
|
||||
res = SPIFFS_OK;
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// if found, rewrite page with object id, update index, and delete current
|
||||
if (ref_pix == cur_pix) {
|
||||
spiffs_page_ix new_pix;
|
||||
res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: index bad %i, cannot mend!\n", res);
|
||||
res = spiffs_page_delete(fs, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
|
||||
*reload_lu = 1;
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// else if index, check for other pages with both obj_id's and spanix
|
||||
spiffs_page_ix objix_pix_lu, objix_pix_ph;
|
||||
// see if other object index page exists for lookup obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_lu);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_lu = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// see if other object index exists for page header obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_ph);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_ph = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// if both obj_id's found, just delete current
|
||||
if (objix_pix_ph == 0 || objix_pix_lu == 0) {
|
||||
// otherwise try finding first corresponding data pages
|
||||
spiffs_page_ix data_pix_lu, data_pix_ph;
|
||||
// see if other data page exists for look up obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_lu);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_lu = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// see if other data page exists for page header obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_ph);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_ph = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
spiffs_page_header new_ph;
|
||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL);
|
||||
new_ph.span_ix = p_hdr->span_ix;
|
||||
spiffs_page_ix new_pix;
|
||||
if ((objix_pix_lu && data_pix_lu && data_pix_ph && objix_pix_ph == 0) ||
|
||||
(objix_pix_lu == 0 && data_pix_ph && objix_pix_ph == 0)) {
|
||||
// got a data page for page header obj id
|
||||
// rewrite as obj_id_ph
|
||||
new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
||||
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x to pix %04x\n", cur_pix, new_ph.obj_id, new_pix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
*reload_lu = 1;
|
||||
} else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) ||
|
||||
(objix_pix_ph == 0 && data_pix_lu && objix_pix_lu == 0)) {
|
||||
// got a data page for look up obj id
|
||||
// rewrite as obj_id_lu
|
||||
new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x\n", cur_pix, new_ph.obj_id);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
*reload_lu = 1;
|
||||
} else {
|
||||
// cannot safely do anything
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: nothing to do, just delete\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX)) ||
|
||||
((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0 && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) == 0)) {
|
||||
SPIFFS_CHECK_DBG("LU: %04x lu/page index marking differ\n", cur_pix);
|
||||
spiffs_page_ix data_pix, objix_pix_d;
|
||||
// see if other data page exists for given obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &data_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
data_pix = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// see if other object index exists for given obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &objix_pix_d);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_d = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
delete_page = 1;
|
||||
// if other data page exists and object index exists, just delete page
|
||||
if (data_pix && objix_pix_d) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: other index and data page exists, simply remove\n");
|
||||
} else
|
||||
// if only data page exists, make this page index
|
||||
if (data_pix && objix_pix_d == 0) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n");
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
|
||||
spiffs_page_header new_ph;
|
||||
spiffs_page_ix new_pix;
|
||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
|
||||
new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
||||
new_ph.span_ix = p_hdr->span_ix;
|
||||
res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else
|
||||
// if only index exists, make data page
|
||||
if (data_pix == 0 && objix_pix_d) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n");
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
|
||||
spiffs_page_header new_ph;
|
||||
spiffs_page_ix new_pix;
|
||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
|
||||
new_ph.obj_id = lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
new_ph.span_ix = p_hdr->span_ix;
|
||||
res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// if nothing exists, we cannot safely make a decision - delete
|
||||
}
|
||||
}
|
||||
else if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0) {
|
||||
SPIFFS_CHECK_DBG("LU: pix %04x busy in lu but deleted on page\n", cur_pix);
|
||||
delete_page = 1;
|
||||
} else if ((p_hdr->flags & SPIFFS_PH_FLAG_FINAL)) {
|
||||
SPIFFS_CHECK_DBG("LU: pix %04x busy but not final\n", cur_pix);
|
||||
// page can be removed if not referenced by object index
|
||||
*reload_lu = 1;
|
||||
res = spiffs_object_get_data_page_index_reference(fs, lu_obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// no object with this id, so remove page safely
|
||||
res = SPIFFS_OK;
|
||||
delete_page = 1;
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (ref_pix != cur_pix) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: other finalized page is referred, just delete\n");
|
||||
delete_page = 1;
|
||||
} else {
|
||||
// page referenced by object index but not final
|
||||
// just finalize
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n");
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||
u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL;
|
||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
|
||||
sizeof(u8_t), (u8_t*)&flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delete_page) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: deleting page %04x\n", cur_pix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, int cur_entry,
|
||||
const void *user_const_p, void *user_var_p) {
|
||||
(void)user_const_p;
|
||||
(void)user_var_p;
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
|
||||
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
|
||||
(cur_block * 256)/fs->block_count, 0);
|
||||
|
||||
// load header
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
int reload_lu = 0;
|
||||
|
||||
res = spiffs_lookup_check_validate(fs, obj_id, &p_hdr, cur_pix, cur_block, cur_entry, &reload_lu);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
if (res == SPIFFS_OK) {
|
||||
return reload_lu ? SPIFFS_VIS_COUNTINUE_RELOAD : SPIFFS_VIS_COUNTINUE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Scans all object look up. For each entry, corresponding page header is checked for validity.
|
||||
// If an object index header page is found, this is also checked
|
||||
s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
|
||||
(void)check_all_objects;
|
||||
s32_t res = SPIFFS_OK;
|
||||
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
|
||||
|
||||
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0);
|
||||
|
||||
if (res == SPIFFS_VIS_END) {
|
||||
res = SPIFFS_OK;
|
||||
}
|
||||
|
||||
if (res != SPIFFS_OK) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
|
||||
}
|
||||
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
// Page consistency
|
||||
|
||||
// Scans all pages (except lu pages), reserves 4 bits in working memory for each page
|
||||
// bit 0: 0 == FREE|DELETED, 1 == USED
|
||||
// bit 1: 0 == UNREFERENCED, 1 == REFERENCED
|
||||
// bit 2: 0 == NOT_INDEX, 1 == INDEX
|
||||
// bit 3: unused
|
||||
// A consistent file system will have only pages being
|
||||
// * x000 free, unreferenced, not index
|
||||
// * x011 used, referenced only once, not index
|
||||
// * x101 used, unreferenced, index
|
||||
// The working memory might not fit all pages so several scans might be needed
|
||||
static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
||||
const u32_t bits = 4;
|
||||
const spiffs_page_ix pages_per_scan = SPIFFS_CFG_LOG_PAGE_SZ(fs) * 8 / bits;
|
||||
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_page_ix pix_offset = 0;
|
||||
|
||||
// for each range of pages fitting into work memory
|
||||
while (pix_offset < SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) {
|
||||
// set this flag to abort all checks and rescan the page range
|
||||
u8_t restart = 0;
|
||||
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||
|
||||
spiffs_block_ix cur_block = 0;
|
||||
// build consistency bitmap for id range traversing all blocks
|
||||
while (!restart && cur_block < fs->block_count) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
|
||||
(pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) +
|
||||
((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count),
|
||||
0);
|
||||
// traverse each page except for lookup pages
|
||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;
|
||||
while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) {
|
||||
//if ((cur_pix & 0xff) == 0)
|
||||
// SPIFFS_CHECK_DBG("PA: processing pix %08x, block %08x of pix %08x, block %08x\n",
|
||||
// cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);
|
||||
|
||||
// read header
|
||||
spiffs_page_header p_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
u8_t within_range = (cur_pix >= pix_offset && cur_pix < pix_offset + pages_per_scan);
|
||||
const u32_t pix_byte_ix = (cur_pix - pix_offset) / (8/bits);
|
||||
const u8_t pix_bit_ix = (cur_pix & ((8/bits)-1)) * bits;
|
||||
|
||||
if (within_range &&
|
||||
(p_hdr.flags & SPIFFS_PH_FLAG_DELET) && (p_hdr.flags & SPIFFS_PH_FLAG_USED) == 0) {
|
||||
// used
|
||||
fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 0));
|
||||
}
|
||||
if ((p_hdr.flags & SPIFFS_PH_FLAG_DELET) &&
|
||||
(p_hdr.flags & SPIFFS_PH_FLAG_IXDELE) &&
|
||||
(p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) == 0) {
|
||||
// found non-deleted index
|
||||
if (within_range) {
|
||||
fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 2));
|
||||
}
|
||||
|
||||
// load non-deleted index
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
// traverse index for referenced pages
|
||||
spiffs_page_ix *object_page_index;
|
||||
spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;
|
||||
|
||||
int entries;
|
||||
int i;
|
||||
spiffs_span_ix data_spix_offset;
|
||||
if (p_hdr.span_ix == 0) {
|
||||
// object header page index
|
||||
entries = SPIFFS_OBJ_HDR_IX_LEN(fs);
|
||||
data_spix_offset = 0;
|
||||
object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header));
|
||||
} else {
|
||||
// object page index
|
||||
entries = SPIFFS_OBJ_IX_LEN(fs);
|
||||
data_spix_offset = SPIFFS_OBJ_HDR_IX_LEN(fs) + SPIFFS_OBJ_IX_LEN(fs) * (p_hdr.span_ix - 1);
|
||||
object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix));
|
||||
}
|
||||
|
||||
// for all entries in index
|
||||
for (i = 0; !restart && i < entries; i++) {
|
||||
spiffs_page_ix rpix = object_page_index[i];
|
||||
u8_t rpix_within_range = rpix >= pix_offset && rpix < pix_offset + pages_per_scan;
|
||||
|
||||
if ((rpix != (spiffs_page_ix)-1 && rpix > SPIFFS_MAX_PAGES(fs))
|
||||
|| (rpix_within_range && SPIFFS_IS_LOOKUP_PAGE(fs, rpix))) {
|
||||
|
||||
// bad reference
|
||||
SPIFFS_CHECK_DBG("PA: pix %04x bad pix / LU referenced from page %04x\n",
|
||||
rpix, cur_pix);
|
||||
// check for data page elsewhere
|
||||
spiffs_page_ix data_pix;
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
|
||||
data_spix_offset + i, 0, &data_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
data_pix = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (data_pix == 0) {
|
||||
// if not, allocate free page
|
||||
spiffs_page_header new_ph;
|
||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
|
||||
new_ph.obj_id = objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
new_ph.span_ix = data_spix_offset + i;
|
||||
res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &data_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: found no existing data page, created new @ %04x\n", data_pix);
|
||||
}
|
||||
// remap index
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: rewriting index pix %04x\n", cur_pix);
|
||||
res = spiffs_rewrite_index(fs, objix_p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG,
|
||||
data_spix_offset + i, data_pix, cur_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend - delete object\n", res);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);
|
||||
// delete file
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
} else {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
restart = 1;
|
||||
|
||||
} else if (rpix_within_range) {
|
||||
|
||||
// valid reference
|
||||
// read referenced page header
|
||||
spiffs_page_header rp_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
// cross reference page header check
|
||||
if (rp_hdr.obj_id != (p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) ||
|
||||
rp_hdr.span_ix != data_spix_offset + i ||
|
||||
(rp_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) !=
|
||||
(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX)) {
|
||||
SPIFFS_CHECK_DBG("PA: pix %04x has inconsistent page header ix id/span:%04x/%04x, ref id/span:%04x/%04x flags:%02x\n",
|
||||
rpix, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, data_spix_offset + i,
|
||||
rp_hdr.obj_id, rp_hdr.span_ix, rp_hdr.flags);
|
||||
// try finding correct page
|
||||
spiffs_page_ix data_pix;
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
|
||||
data_spix_offset + i, rpix, &data_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
data_pix = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (data_pix == 0) {
|
||||
// not found, this index is badly borked
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id %04x\n", p_hdr.obj_id);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
break;
|
||||
} else {
|
||||
// found it, so rewrite index
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: found correct data pix %04x, rewrite ix pix %04x id %04x\n",
|
||||
data_pix, cur_pix, p_hdr.obj_id);
|
||||
res = spiffs_rewrite_index(fs, p_hdr.obj_id, data_spix_offset + i, data_pix, cur_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||
} else {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
restart = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// mark rpix as referenced
|
||||
const u32_t rpix_byte_ix = (rpix - pix_offset) / (8/bits);
|
||||
const u8_t rpix_bit_ix = (rpix & ((8/bits)-1)) * bits;
|
||||
if (fs->work[rpix_byte_ix] & (1<<(rpix_bit_ix + 1))) {
|
||||
SPIFFS_CHECK_DBG("PA: pix %04x multiple referenced from page %04x\n",
|
||||
rpix, cur_pix);
|
||||
// Here, we should have fixed all broken references - getting this means there
|
||||
// must be multiple files with same object id. Only solution is to delete
|
||||
// the object which is referring to this page
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: removing object %04x and page %04x\n",
|
||||
p_hdr.obj_id, cur_pix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// extra precaution, delete this page also
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
restart = 1;
|
||||
}
|
||||
fs->work[rpix_byte_ix] |= (1<<(rpix_bit_ix + 1));
|
||||
}
|
||||
}
|
||||
} // for all index entries
|
||||
} // found index
|
||||
|
||||
// next page
|
||||
cur_pix++;
|
||||
}
|
||||
// next block
|
||||
cur_block++;
|
||||
}
|
||||
// check consistency bitmap
|
||||
if (!restart) {
|
||||
spiffs_page_ix objix_pix;
|
||||
spiffs_page_ix rpix;
|
||||
|
||||
u32_t byte_ix;
|
||||
u8_t bit_ix;
|
||||
for (byte_ix = 0; !restart && byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs); byte_ix++) {
|
||||
for (bit_ix = 0; !restart && bit_ix < 8/bits; bit_ix ++) {
|
||||
u8_t bitmask = (fs->work[byte_ix] >> (bit_ix * bits)) & 0x7;
|
||||
spiffs_page_ix cur_pix = pix_offset + byte_ix * (8/bits) + bit_ix;
|
||||
|
||||
// 000 ok - free, unreferenced, not index
|
||||
|
||||
if (bitmask == 0x1) {
|
||||
|
||||
// 001
|
||||
SPIFFS_CHECK_DBG("PA: pix %04x USED, UNREFERENCED, not index\n", cur_pix);
|
||||
|
||||
u8_t rewrite_ix_to_this = 0;
|
||||
u8_t delete_page = 0;
|
||||
// check corresponding object index entry
|
||||
spiffs_page_header p_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
res = spiffs_object_get_data_page_index_reference(fs, p_hdr.obj_id, p_hdr.span_ix,
|
||||
&rpix, &objix_pix);
|
||||
if (res == SPIFFS_OK) {
|
||||
if (((rpix == (spiffs_page_ix)-1 || rpix > SPIFFS_MAX_PAGES(fs)) || (SPIFFS_IS_LOOKUP_PAGE(fs, rpix)))) {
|
||||
// pointing to a bad page altogether, rewrite index to this
|
||||
rewrite_ix_to_this = 1;
|
||||
SPIFFS_CHECK_DBG("PA: corresponding ref is bad: %04x, rewrite to this %04x\n", rpix, cur_pix);
|
||||
} else {
|
||||
// pointing to something else, check what
|
||||
spiffs_page_header rp_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (((p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) == rp_hdr.obj_id) &&
|
||||
((rp_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL)) ==
|
||||
(SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET))) {
|
||||
// pointing to something else valid, just delete this page then
|
||||
SPIFFS_CHECK_DBG("PA: corresponding ref is good but different: %04x, delete this %04x\n", rpix, cur_pix);
|
||||
delete_page = 1;
|
||||
} else {
|
||||
// pointing to something weird, update index to point to this page instead
|
||||
if (rpix != cur_pix) {
|
||||
SPIFFS_CHECK_DBG("PA: corresponding ref is weird: %04x %s%s%s%s, rewrite this %04x\n", rpix,
|
||||
(rp_hdr.flags & SPIFFS_PH_FLAG_INDEX) ? "" : "INDEX ",
|
||||
(rp_hdr.flags & SPIFFS_PH_FLAG_DELET) ? "" : "DELETED ",
|
||||
(rp_hdr.flags & SPIFFS_PH_FLAG_USED) ? "NOTUSED " : "",
|
||||
(rp_hdr.flags & SPIFFS_PH_FLAG_FINAL) ? "NOTFINAL " : "",
|
||||
cur_pix);
|
||||
rewrite_ix_to_this = 1;
|
||||
} else {
|
||||
// should not happen, destined for fubar
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
SPIFFS_CHECK_DBG("PA: corresponding ref not found, delete %04x\n", cur_pix);
|
||||
delete_page = 1;
|
||||
res = SPIFFS_OK;
|
||||
}
|
||||
|
||||
if (rewrite_ix_to_this) {
|
||||
// if pointing to invalid page, redirect index to this page
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: rewrite index id %04x data spix %04x to point to this pix: %04x\n",
|
||||
p_hdr.obj_id, p_hdr.span_ix, cur_pix);
|
||||
res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||
} else {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
restart = 1;
|
||||
continue;
|
||||
} else if (delete_page) {
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: deleting page %04x\n", cur_pix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
if (bitmask == 0x2) {
|
||||
|
||||
// 010
|
||||
SPIFFS_CHECK_DBG("PA: pix %04x FREE, REFERENCED, not index\n", cur_pix);
|
||||
|
||||
// no op, this should be taken care of when checking valid references
|
||||
}
|
||||
|
||||
// 011 ok - busy, referenced, not index
|
||||
|
||||
if (bitmask == 0x4) {
|
||||
|
||||
// 100
|
||||
SPIFFS_CHECK_DBG("PA: pix %04x FREE, unreferenced, INDEX\n", cur_pix);
|
||||
|
||||
// this should never happen, major fubar
|
||||
}
|
||||
|
||||
// 101 ok - busy, unreferenced, index
|
||||
|
||||
if (bitmask == 0x6) {
|
||||
|
||||
// 110
|
||||
SPIFFS_CHECK_DBG("PA: pix %04x FREE, REFERENCED, INDEX\n", cur_pix);
|
||||
|
||||
// no op, this should be taken care of when checking valid references
|
||||
}
|
||||
if (bitmask == 0x7) {
|
||||
|
||||
// 111
|
||||
SPIFFS_CHECK_DBG("PA: pix %04x USED, REFERENCED, INDEX\n", cur_pix);
|
||||
|
||||
// no op, this should be taken care of when checking valid references
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SPIFFS_CHECK_DBG("PA: processed %04x, restart %i\n", pix_offset, restart);
|
||||
// next page range
|
||||
if (!restart) {
|
||||
pix_offset += pages_per_scan;
|
||||
}
|
||||
} // while page range not reached end
|
||||
return res;
|
||||
}
|
||||
|
||||
// Checks consistency amongst all pages and fixes irregularities
|
||||
s32_t spiffs_page_consistency_check(spiffs *fs) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
|
||||
s32_t res = spiffs_page_consistency_check_i(fs);
|
||||
if (res != SPIFFS_OK) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
|
||||
}
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
// Object index consistency
|
||||
|
||||
// searches for given object id in temporary object id index,
|
||||
// returns the index or -1
|
||||
static int spiffs_object_index_search(spiffs *fs, spiffs_obj_id obj_id) {
|
||||
u32_t i;
|
||||
spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
|
||||
obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id); i++) {
|
||||
if ((obj_table[i] & ~SPIFFS_OBJ_ID_IX_FLAG) == obj_id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block,
|
||||
int cur_entry, const void *user_const_p, void *user_var_p) {
|
||||
(void)user_const_p;
|
||||
s32_t res_c = SPIFFS_VIS_COUNTINUE;
|
||||
s32_t res = SPIFFS_OK;
|
||||
u32_t *log_ix = (u32_t*)user_var_p;
|
||||
spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
|
||||
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
|
||||
(cur_block * 256)/fs->block_count, 0);
|
||||
|
||||
if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
|
||||
|
||||
// load header
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
if (p_hdr.span_ix == 0 &&
|
||||
(p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==
|
||||
(SPIFFS_PH_FLAG_DELET)) {
|
||||
SPIFFS_CHECK_DBG("IX: pix %04x, obj id:%04x spix:%04x header not fully deleted - deleting\n",
|
||||
cur_pix, obj_id, p_hdr.span_ix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
return res_c;
|
||||
}
|
||||
|
||||
if ((p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==
|
||||
(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
|
||||
return res_c;
|
||||
}
|
||||
|
||||
if (p_hdr.span_ix == 0) {
|
||||
// objix header page, register objid as reachable
|
||||
int r = spiffs_object_index_search(fs, obj_id);
|
||||
if (r == -1) {
|
||||
// not registered, do it
|
||||
obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
(*log_ix)++;
|
||||
if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
|
||||
*log_ix = 0;
|
||||
}
|
||||
}
|
||||
} else { // span index
|
||||
// objix page, see if header can be found
|
||||
int r = spiffs_object_index_search(fs, obj_id);
|
||||
u8_t delete = 0;
|
||||
if (r == -1) {
|
||||
// not in temporary index, try finding it
|
||||
spiffs_page_ix objix_hdr_pix;
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &objix_hdr_pix);
|
||||
res_c = SPIFFS_VIS_COUNTINUE_RELOAD;
|
||||
if (res == SPIFFS_OK) {
|
||||
// found, register as reachable
|
||||
obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
} else if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// not found, register as unreachable
|
||||
delete = 1;
|
||||
obj_table[*log_ix] = obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
(*log_ix)++;
|
||||
if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
|
||||
*log_ix = 0;
|
||||
}
|
||||
} else {
|
||||
// in temporary index, check reachable flag
|
||||
if ((obj_table[r] & SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||
// registered as unreachable
|
||||
delete = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (delete) {
|
||||
SPIFFS_CHECK_DBG("IX: FIXUP: pix %04x, obj id:%04x spix:%04x is orphan index - deleting\n",
|
||||
cur_pix, obj_id, p_hdr.span_ix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
} // span index
|
||||
} // valid object index id
|
||||
|
||||
return res_c;
|
||||
}
|
||||
|
||||
// Removes orphaned and partially deleted index pages.
|
||||
// Scans for index pages. When an index page is found, corresponding index header is searched for.
|
||||
// If no such page exists, the index page cannot be reached as no index header exists and must be
|
||||
// deleted.
|
||||
s32_t spiffs_object_index_consistency_check(spiffs *fs) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
// impl note:
|
||||
// fs->work is used for a temporary object index memory, listing found object ids and
|
||||
// indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit.
|
||||
// In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate
|
||||
// a reachable/unreachable object id.
|
||||
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||
u32_t obj_id_log_ix = 0;
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
|
||||
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, &obj_id_log_ix,
|
||||
0, 0, 0);
|
||||
if (res == SPIFFS_VIS_END) {
|
||||
res = SPIFFS_OK;
|
||||
}
|
||||
if (res != SPIFFS_OK) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
|
||||
}
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif // !SPIFFS_READ_ONLY
|
||||
@@ -1,253 +0,0 @@
|
||||
/*
|
||||
* spiffs_config.h
|
||||
*
|
||||
* Created on: Jul 3, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#ifndef SPIFFS_CONFIG_H_
|
||||
#define SPIFFS_CONFIG_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define c_memcpy memcpy
|
||||
#define c_printf printf
|
||||
#define c_memset memset
|
||||
|
||||
typedef int16_t file_t;
|
||||
typedef int32_t s32_t;
|
||||
typedef uint32_t u32_t;
|
||||
typedef int16_t s16_t;
|
||||
typedef uint16_t u16_t;
|
||||
typedef int8_t s8_t;
|
||||
typedef uint8_t u8_t;
|
||||
|
||||
#ifndef SEEK_SET
|
||||
#define SEEK_SET 0 /* set file offset to offset */
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_CUR
|
||||
#define SEEK_CUR 1 /* set file offset to current plus offset */
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_END
|
||||
#define SEEK_END 2 /* set file offset to EOF plus offset */
|
||||
#endif
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF (-1)
|
||||
#endif
|
||||
|
||||
// compile time switches
|
||||
|
||||
// Set generic spiffs debug output call.
|
||||
#ifndef SPIFFS_DBG
|
||||
#define SPIFFS_DBG(...) //printf(__VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for garbage collecting.
|
||||
#ifndef SPIFFS_GC_DBG
|
||||
#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for caching.
|
||||
#ifndef SPIFFS_CACHE_DBG
|
||||
#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for system consistency checks.
|
||||
#ifndef SPIFFS_CHECK_DBG
|
||||
#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
// Enable/disable API functions to determine exact number of bytes
|
||||
// for filedescriptor and cache buffers. Once decided for a configuration,
|
||||
// this can be disabled to reduce flash.
|
||||
#ifndef SPIFFS_BUFFER_HELP
|
||||
#define SPIFFS_BUFFER_HELP 1
|
||||
#endif
|
||||
|
||||
// Enables/disable memory read caching of nucleus file system operations.
|
||||
// If enabled, memory area must be provided for cache in SPIFFS_mount.
|
||||
#ifndef SPIFFS_CACHE
|
||||
#define SPIFFS_CACHE 1
|
||||
#endif
|
||||
#if SPIFFS_CACHE
|
||||
// Enables memory write caching for file descriptors in hydrogen
|
||||
#ifndef SPIFFS_CACHE_WR
|
||||
#define SPIFFS_CACHE_WR 1
|
||||
#endif
|
||||
|
||||
// Enable/disable statistics on caching. Debug/test purpose only.
|
||||
#ifndef SPIFFS_CACHE_STATS
|
||||
#define SPIFFS_CACHE_STATS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Always check header of each accessed page to ensure consistent state.
|
||||
// If enabled it will increase number of reads, will increase flash.
|
||||
#ifndef SPIFFS_PAGE_CHECK
|
||||
#define SPIFFS_PAGE_CHECK 1
|
||||
#endif
|
||||
|
||||
// Define maximum number of gc runs to perform to reach desired free pages.
|
||||
#ifndef SPIFFS_GC_MAX_RUNS
|
||||
#define SPIFFS_GC_MAX_RUNS 5
|
||||
#endif
|
||||
|
||||
// Enable/disable statistics on gc. Debug/test purpose only.
|
||||
#ifndef SPIFFS_GC_STATS
|
||||
#define SPIFFS_GC_STATS 0
|
||||
#endif
|
||||
|
||||
// Garbage collecting examines all pages in a block which and sums up
|
||||
// to a block score. Deleted pages normally gives positive score and
|
||||
// used pages normally gives a negative score (as these must be moved).
|
||||
// To have a fair wear-leveling, the erase age is also included in score,
|
||||
// whose factor normally is the most positive.
|
||||
// The larger the score, the more likely it is that the block will
|
||||
// picked for garbage collection.
|
||||
|
||||
// Garbage collecting heuristics - weight used for deleted pages.
|
||||
#ifndef SPIFFS_GC_HEUR_W_DELET
|
||||
#define SPIFFS_GC_HEUR_W_DELET (5)
|
||||
#endif
|
||||
// Garbage collecting heuristics - weight used for used pages.
|
||||
#ifndef SPIFFS_GC_HEUR_W_USED
|
||||
#define SPIFFS_GC_HEUR_W_USED (-1)
|
||||
#endif
|
||||
// Garbage collecting heuristics - weight used for time between
|
||||
// last erased and erase of this block.
|
||||
#ifndef SPIFFS_GC_HEUR_W_ERASE_AGE
|
||||
#define SPIFFS_GC_HEUR_W_ERASE_AGE (50)
|
||||
#endif
|
||||
|
||||
// Object name maximum length.
|
||||
#ifndef SPIFFS_OBJ_NAME_LEN
|
||||
#define SPIFFS_OBJ_NAME_LEN (32)
|
||||
#endif
|
||||
|
||||
// Size of buffer allocated on stack used when copying data.
|
||||
// Lower value generates more read/writes. No meaning having it bigger
|
||||
// than logical page size.
|
||||
#ifndef SPIFFS_COPY_BUFFER_STACK
|
||||
#define SPIFFS_COPY_BUFFER_STACK (64)
|
||||
#endif
|
||||
|
||||
// Enable this to have an identifiable spiffs filesystem. This will look for
|
||||
// a magic in all sectors to determine if this is a valid spiffs system or
|
||||
// not on mount point. If not, SPIFFS_format must be called prior to mounting
|
||||
// again.
|
||||
#ifndef SPIFFS_USE_MAGIC
|
||||
#define SPIFFS_USE_MAGIC (1)
|
||||
#endif
|
||||
|
||||
// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level
|
||||
// These should be defined on a multithreaded system
|
||||
|
||||
// define this to enter a mutex if you're running on a multithreaded system
|
||||
#ifndef SPIFFS_LOCK
|
||||
#define SPIFFS_LOCK(fs)
|
||||
#endif
|
||||
// define this to exit a mutex if you're running on a multithreaded system
|
||||
#ifndef SPIFFS_UNLOCK
|
||||
#define SPIFFS_UNLOCK(fs)
|
||||
#endif
|
||||
|
||||
|
||||
// Enable if only one spiffs instance with constant configuration will exist
|
||||
// on the target. This will reduce calculations, flash and memory accesses.
|
||||
// Parts of configuration must be defined below instead of at time of mount.
|
||||
#ifndef SPIFFS_SINGLETON
|
||||
#define SPIFFS_SINGLETON 0
|
||||
#endif
|
||||
|
||||
#if SPIFFS_SINGLETON
|
||||
// Instead of giving parameters in config struct, singleton build must
|
||||
// give parameters in defines below.
|
||||
#ifndef SPIFFS_CFG_PHYS_SZ
|
||||
#define SPIFFS_CFG_PHYS_SZ(ignore) (1024*1024*2)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_PHYS_ERASE_SZ
|
||||
#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (65536)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_PHYS_ADDR
|
||||
#define SPIFFS_CFG_PHYS_ADDR(ignore) (0)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_LOG_PAGE_SZ
|
||||
#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_LOG_BLOCK_SZ
|
||||
#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (65536)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Enable this if your target needs aligned data for index tables
|
||||
#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
|
||||
#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1
|
||||
#endif
|
||||
|
||||
// Enable this if you want the HAL callbacks to be called with the spiffs struct
|
||||
#ifndef SPIFFS_HAL_CALLBACK_EXTRA
|
||||
#define SPIFFS_HAL_CALLBACK_EXTRA 0
|
||||
#endif
|
||||
|
||||
// Enable this if you want to add an integer offset to all file handles
|
||||
// (spiffs_file). This is useful if running multiple instances of spiffs on
|
||||
// same target, in order to recognise to what spiffs instance a file handle
|
||||
// belongs.
|
||||
// NB: This adds config field fh_ix_offset in the configuration struct when
|
||||
// mounting, which must be defined.
|
||||
#ifndef SPIFFS_FILEHDL_OFFSET
|
||||
#define SPIFFS_FILEHDL_OFFSET 0
|
||||
#endif
|
||||
|
||||
// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function
|
||||
// in the api. This function will visualize all filesystem using given printf
|
||||
// function.
|
||||
#ifndef SPIFFS_TEST_VISUALISATION
|
||||
#define SPIFFS_TEST_VISUALISATION 1
|
||||
#endif
|
||||
#if SPIFFS_TEST_VISUALISATION
|
||||
#ifndef spiffs_printf
|
||||
#define spiffs_printf(...) c_printf(__VA_ARGS__)
|
||||
#endif
|
||||
// spiffs_printf argument for a free page
|
||||
#ifndef SPIFFS_TEST_VIS_FREE_STR
|
||||
#define SPIFFS_TEST_VIS_FREE_STR "_"
|
||||
#endif
|
||||
// spiffs_printf argument for a deleted page
|
||||
#ifndef SPIFFS_TEST_VIS_DELE_STR
|
||||
#define SPIFFS_TEST_VIS_DELE_STR "/"
|
||||
#endif
|
||||
// spiffs_printf argument for an index page for given object id
|
||||
#ifndef SPIFFS_TEST_VIS_INDX_STR
|
||||
#define SPIFFS_TEST_VIS_INDX_STR(id) "i"
|
||||
#endif
|
||||
// spiffs_printf argument for a data page for given object id
|
||||
#ifndef SPIFFS_TEST_VIS_DATA_STR
|
||||
#define SPIFFS_TEST_VIS_DATA_STR(id) "d"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Types depending on configuration such as the amount of flash bytes
|
||||
// given to spiffs file system in total (spiffs_file_system_size),
|
||||
// the logical block size (log_block_size), and the logical page size
|
||||
// (log_page_size)
|
||||
|
||||
// Block index type. Make sure the size of this type can hold
|
||||
// the highest number of all blocks - i.e. spiffs_file_system_size / log_block_size
|
||||
typedef u16_t spiffs_block_ix;
|
||||
// Page index type. Make sure the size of this type can hold
|
||||
// the highest page number of all pages - i.e. spiffs_file_system_size / log_page_size
|
||||
typedef u16_t spiffs_page_ix;
|
||||
// Object id type - most significant bit is reserved for index flag. Make sure the
|
||||
// size of this type can hold the highest object id on a full system,
|
||||
// i.e. 2 + (spiffs_file_system_size / (2*log_page_size))*2
|
||||
typedef u16_t spiffs_obj_id;
|
||||
// Object span index type. Make sure the size of this type can
|
||||
// hold the largest possible span index on the system -
|
||||
// i.e. (spiffs_file_system_size / log_page_size) - 1
|
||||
typedef u16_t spiffs_span_ix;
|
||||
|
||||
#endif /* SPIFFS_CONFIG_H_ */
|
||||
@@ -1,576 +0,0 @@
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
#if !SPIFFS_READ_ONLY
|
||||
|
||||
// Erases a logical block and updates the erase counter.
|
||||
// If cache is enabled, all pages that might be cached in this block
|
||||
// is dropped.
|
||||
static s32_t spiffs_gc_erase_block(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix) {
|
||||
s32_t res;
|
||||
|
||||
SPIFFS_GC_DBG("gc: erase block %i\n", bix);
|
||||
res = spiffs_erase_block(fs, bix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
{
|
||||
u32_t i;
|
||||
for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) {
|
||||
spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, bix) + i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
// Searches for blocks where all entries are deleted - if one is found,
|
||||
// the block is erased. Compared to the non-quick gc, the quick one ensures
|
||||
// that no updates are needed on existing objects on pages that are erased.
|
||||
s32_t spiffs_gc_quick(
|
||||
spiffs *fs, u16_t max_free_pages) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
u32_t blocks = fs->block_count;
|
||||
spiffs_block_ix cur_block = 0;
|
||||
u32_t cur_block_addr = 0;
|
||||
int cur_entry = 0;
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
|
||||
SPIFFS_GC_DBG("gc_quick: running\n");
|
||||
#if SPIFFS_GC_STATS
|
||||
fs->stats_gc_runs++;
|
||||
#endif
|
||||
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
|
||||
// find fully deleted blocks
|
||||
// check each block
|
||||
while (res == SPIFFS_OK && blocks--) {
|
||||
u16_t deleted_pages_in_block = 0;
|
||||
u16_t free_pages_in_block = 0;
|
||||
|
||||
int obj_lookup_page = 0;
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page &&
|
||||
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
deleted_pages_in_block++;
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
// kill scan, go for next block
|
||||
free_pages_in_block++;
|
||||
if (free_pages_in_block > max_free_pages) {
|
||||
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
||||
res = 1; // kill object lu loop
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// kill scan, go for next block
|
||||
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
||||
res = 1; // kill object lu loop
|
||||
break;
|
||||
}
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
if (res == 1) res = SPIFFS_OK;
|
||||
|
||||
if (res == SPIFFS_OK &&
|
||||
deleted_pages_in_block + free_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs) &&
|
||||
free_pages_in_block <= max_free_pages) {
|
||||
// found a fully deleted block
|
||||
fs->stats_p_deleted -= deleted_pages_in_block;
|
||||
res = spiffs_gc_erase_block(fs, cur_block);
|
||||
return res;
|
||||
}
|
||||
|
||||
cur_entry = 0;
|
||||
cur_block++;
|
||||
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
||||
} // per block
|
||||
|
||||
if (res == SPIFFS_OK) {
|
||||
res = SPIFFS_ERR_NO_DELETED_BLOCKS;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Checks if garbage collecting is necessary. If so a candidate block is found,
|
||||
// cleansed and erased
|
||||
s32_t spiffs_gc_check(
|
||||
spiffs *fs,
|
||||
u32_t len) {
|
||||
s32_t res;
|
||||
s32_t free_pages =
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2)
|
||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||
int tries = 0;
|
||||
|
||||
if (fs->free_blocks > 3 &&
|
||||
(s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs);
|
||||
// if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) {
|
||||
// SPIFFS_GC_DBG("gc: full freeblk:%i needed:%i free:%i dele:%i\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
||||
// return SPIFFS_ERR_FULL;
|
||||
// }
|
||||
if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) {
|
||||
SPIFFS_GC_DBG("gc_check: full freeblk:%i needed:%i free:%i dele:%i\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
||||
return SPIFFS_ERR_FULL;
|
||||
}
|
||||
|
||||
do {
|
||||
SPIFFS_GC_DBG("\ngc_check #%i: run gc free_blocks:%i pfree:%i pallo:%i pdele:%i [%i] len:%i of %i\n",
|
||||
tries,
|
||||
fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted),
|
||||
len, free_pages*SPIFFS_DATA_PAGE_SIZE(fs));
|
||||
|
||||
spiffs_block_ix *cands;
|
||||
int count;
|
||||
spiffs_block_ix cand;
|
||||
s32_t prev_free_pages = free_pages;
|
||||
// if the fs is crammed, ignore block age when selecting candidate - kind of a bad state
|
||||
res = spiffs_gc_find_candidate(fs, &cands, &count, free_pages <= 0);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (count == 0) {
|
||||
SPIFFS_GC_DBG("gc_check: no candidates, return\n");
|
||||
return (s32_t)needed_pages < free_pages ? SPIFFS_OK : SPIFFS_ERR_FULL;
|
||||
}
|
||||
#if SPIFFS_GC_STATS
|
||||
fs->stats_gc_runs++;
|
||||
#endif
|
||||
cand = cands[0];
|
||||
fs->cleaning = 1;
|
||||
//printf("gcing: cleaning block %i\n", cand);
|
||||
res = spiffs_gc_clean(fs, cand);
|
||||
fs->cleaning = 0;
|
||||
if (res < 0) {
|
||||
SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res);
|
||||
} else {
|
||||
SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
res = spiffs_gc_erase_page_stats(fs, cand);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
res = spiffs_gc_erase_block(fs, cand);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
free_pages =
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
|
||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||
|
||||
if (prev_free_pages <= 0 && prev_free_pages == free_pages) {
|
||||
// abort early to reduce wear, at least tried once
|
||||
SPIFFS_GC_DBG("gc_check: early abort, no result on gc when fs crammed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
} while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||
|
||||
(s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)));
|
||||
|
||||
free_pages =
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
|
||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||
if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
|
||||
res = SPIFFS_ERR_FULL;
|
||||
}
|
||||
|
||||
SPIFFS_GC_DBG("gc_check: finished, %i dirty, blocks %i free, %i pages free, %i tries, res %i\n",
|
||||
fs->stats_p_allocated + fs->stats_p_deleted,
|
||||
fs->free_blocks, free_pages, tries, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Updates page statistics for a block that is about to be erased
|
||||
s32_t spiffs_gc_erase_page_stats(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
int obj_lookup_page = 0;
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
int cur_entry = 0;
|
||||
u32_t dele = 0;
|
||||
u32_t allo = 0;
|
||||
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
dele++;
|
||||
} else {
|
||||
allo++;
|
||||
}
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
SPIFFS_GC_DBG("gc_check: wipe pallo:%i pdele:%i\n", allo, dele);
|
||||
fs->stats_p_allocated -= allo;
|
||||
fs->stats_p_deleted -= dele;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Finds block candidates to erase
|
||||
s32_t spiffs_gc_find_candidate(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix **block_candidates,
|
||||
int *candidate_count,
|
||||
char fs_crammed) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
u32_t blocks = fs->block_count;
|
||||
spiffs_block_ix cur_block = 0;
|
||||
u32_t cur_block_addr = 0;
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
int cur_entry = 0;
|
||||
|
||||
// using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score
|
||||
int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t)));
|
||||
*candidate_count = 0;
|
||||
memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||
|
||||
// divide up work area into block indices and scores
|
||||
spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work;
|
||||
s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix));
|
||||
|
||||
// align cand_scores on s32_t boundary
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
|
||||
cand_scores = (s32_t*)(((ptrdiff_t)cand_scores + sizeof(ptrdiff_t) - 1) & ~(sizeof(ptrdiff_t) - 1));
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
*block_candidates = cand_blocks;
|
||||
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
|
||||
// check each block
|
||||
while (res == SPIFFS_OK && blocks--) {
|
||||
u16_t deleted_pages_in_block = 0;
|
||||
u16_t used_pages_in_block = 0;
|
||||
|
||||
int obj_lookup_page = 0;
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page &&
|
||||
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
// when a free entry is encountered, scan logic ensures that all following entries are free also
|
||||
res = 1; // kill object lu loop
|
||||
break;
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
deleted_pages_in_block++;
|
||||
} else {
|
||||
used_pages_in_block++;
|
||||
}
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
if (res == 1) res = SPIFFS_OK;
|
||||
|
||||
// calculate score and insert into candidate table
|
||||
// stoneage sort, but probably not so many blocks
|
||||
if (res == SPIFFS_OK && deleted_pages_in_block > 0) {
|
||||
// read erase count
|
||||
spiffs_obj_id erase_count;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,
|
||||
SPIFFS_ERASE_COUNT_PADDR(fs, cur_block),
|
||||
sizeof(spiffs_obj_id), (u8_t *)&erase_count);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
spiffs_obj_id erase_age;
|
||||
if (fs->max_erase_count > erase_count) {
|
||||
erase_age = fs->max_erase_count - erase_count;
|
||||
} else {
|
||||
erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count);
|
||||
}
|
||||
|
||||
s32_t score =
|
||||
deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET +
|
||||
used_pages_in_block * SPIFFS_GC_HEUR_W_USED +
|
||||
erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE);
|
||||
int cand_ix = 0;
|
||||
SPIFFS_GC_DBG("gc_check: bix:%i del:%i use:%i score:%i\n", cur_block, deleted_pages_in_block, used_pages_in_block, score);
|
||||
while (cand_ix < max_candidates) {
|
||||
if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) {
|
||||
cand_blocks[cand_ix] = cur_block;
|
||||
cand_scores[cand_ix] = score;
|
||||
break;
|
||||
} else if (cand_scores[cand_ix] < score) {
|
||||
int reorder_cand_ix = max_candidates - 2;
|
||||
while (reorder_cand_ix >= cand_ix) {
|
||||
cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix];
|
||||
cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix];
|
||||
reorder_cand_ix--;
|
||||
}
|
||||
cand_blocks[cand_ix] = cur_block;
|
||||
cand_scores[cand_ix] = score;
|
||||
break;
|
||||
}
|
||||
cand_ix++;
|
||||
}
|
||||
(*candidate_count)++;
|
||||
}
|
||||
|
||||
cur_entry = 0;
|
||||
cur_block++;
|
||||
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
||||
} // per block
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
FIND_OBJ_DATA,
|
||||
MOVE_OBJ_DATA,
|
||||
MOVE_OBJ_IX,
|
||||
FINISHED
|
||||
} spiffs_gc_clean_state;
|
||||
|
||||
typedef struct {
|
||||
spiffs_gc_clean_state state;
|
||||
spiffs_obj_id cur_obj_id;
|
||||
spiffs_span_ix cur_objix_spix;
|
||||
spiffs_page_ix cur_objix_pix;
|
||||
int stored_scan_entry_index;
|
||||
u8_t obj_id_found;
|
||||
} spiffs_gc;
|
||||
|
||||
// Empties given block by moving all data into free pages of another block
|
||||
// Strategy:
|
||||
// loop:
|
||||
// scan object lookup for object data pages
|
||||
// for first found id, check spix and load corresponding object index page to memory
|
||||
// push object scan lookup entry index
|
||||
// rescan object lookup, find data pages with same id and referenced by same object index
|
||||
// move data page, update object index in memory
|
||||
// when reached end of lookup, store updated object index
|
||||
// pop object scan lookup entry index
|
||||
// repeat loop until end of object lookup
|
||||
// scan object lookup again for remaining object index pages, move to new page in other block
|
||||
//
|
||||
s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
int cur_entry = 0;
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
spiffs_gc gc;
|
||||
spiffs_page_ix cur_pix = 0;
|
||||
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
|
||||
spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
|
||||
|
||||
SPIFFS_GC_DBG("gc_clean: cleaning block %i\n", bix);
|
||||
|
||||
memset(&gc, 0, sizeof(spiffs_gc));
|
||||
gc.state = FIND_OBJ_DATA;
|
||||
|
||||
if (fs->free_cursor_block_ix == bix) {
|
||||
// move free cursor to next block, cannot use free pages from the block we want to clean
|
||||
fs->free_cursor_block_ix = (bix+1)%fs->block_count;
|
||||
fs->free_cursor_obj_lu_entry = 0;
|
||||
SPIFFS_GC_DBG("gc_clean: move free cursor to block %i\n", fs->free_cursor_block_ix);
|
||||
}
|
||||
|
||||
while (res == SPIFFS_OK && gc.state != FINISHED) {
|
||||
SPIFFS_GC_DBG("gc_clean: state = %i entry:%i\n", gc.state, cur_entry);
|
||||
gc.obj_id_found = 0;
|
||||
|
||||
// scan through lookup pages
|
||||
int obj_lookup_page = cur_entry / entries_per_page;
|
||||
u8_t scan = 1;
|
||||
// check each object lookup page
|
||||
while (scan && res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (scan && res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry);
|
||||
|
||||
// act upon object id depending on gc state
|
||||
switch (gc.state) {
|
||||
case FIND_OBJ_DATA:
|
||||
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
|
||||
((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) {
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA state:%i - found obj id %04x\n", gc.state, obj_id);
|
||||
gc.obj_id_found = 1;
|
||||
gc.cur_obj_id = obj_id;
|
||||
scan = 0;
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_DATA:
|
||||
if (obj_id == gc.cur_obj_id) {
|
||||
spiffs_page_header p_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA found data page %04x:%04x @ %04x\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix);
|
||||
if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) {
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA no objix spix match, take in another run\n");
|
||||
} else {
|
||||
spiffs_page_ix new_data_pix;
|
||||
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
|
||||
// move page
|
||||
res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_data_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA move objix %04x:%04x page %04x to %04x\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// move wipes obj_lu, reload it
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// page is deleted but not deleted in lookup, scrap it
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wipe objix %04x:%04x page %04x\n", obj_id, p_hdr.span_ix, cur_pix);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
new_data_pix = SPIFFS_OBJ_ID_FREE;
|
||||
}
|
||||
// update memory representation of object index page with new data page
|
||||
if (gc.cur_objix_spix == 0) {
|
||||
// update object index header page
|
||||
((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix;
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page %04x to objix_hdr entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));
|
||||
} else {
|
||||
// update object index page
|
||||
((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix;
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page %04x to objix entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_IX:
|
||||
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
|
||||
(obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||
// found an index object id
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix new_pix;
|
||||
// load header
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
|
||||
// move page
|
||||
res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX move objix %04x:%04x page %04x to %04x\n", obj_id, p_hdr.span_ix, cur_pix, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_UPD, obj_id, p_hdr.span_ix, new_pix, 0);
|
||||
// move wipes obj_lu, reload it
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// page is deleted but not deleted in lookup, scrap it
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX wipe objix %04x:%04x page %04x\n", obj_id, p_hdr.span_ix, cur_pix);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
if (res == SPIFFS_OK) {
|
||||
spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0);
|
||||
}
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
scan = 0;
|
||||
break;
|
||||
}
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
|
||||
if (res != SPIFFS_OK) break;
|
||||
|
||||
// state finalization and switch
|
||||
switch (gc.state) {
|
||||
case FIND_OBJ_DATA:
|
||||
if (gc.obj_id_found) {
|
||||
// find out corresponding obj ix page and load it to memory
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix objix_pix;
|
||||
gc.stored_scan_entry_index = cur_entry;
|
||||
cur_entry = 0;
|
||||
gc.state = MOVE_OBJ_DATA;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix);
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA find objix span_ix:%04x\n", gc.cur_objix_spix);
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, 0, &objix_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA found object index at page %04x\n", objix_pix);
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix);
|
||||
gc.cur_objix_pix = objix_pix;
|
||||
} else {
|
||||
gc.state = MOVE_OBJ_IX;
|
||||
cur_entry = 0; // restart entry scan index
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_DATA: {
|
||||
// store modified objix (hdr) page
|
||||
spiffs_page_ix new_objix_pix;
|
||||
gc.state = FIND_OBJ_DATA;
|
||||
cur_entry = gc.stored_scan_entry_index;
|
||||
if (gc.cur_objix_spix == 0) {
|
||||
// store object index header page
|
||||
res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, &new_objix_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, %04x:%04x\n", new_objix_pix, 0);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// store object index page
|
||||
res = spiffs_page_move(fs, 0, fs->work, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, gc.cur_objix_pix, &new_objix_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix page, %04x:%04x\n", new_objix_pix, objix->p_hdr.span_ix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_UPD, gc.cur_obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_IX:
|
||||
gc.state = FINISHED;
|
||||
break;
|
||||
default:
|
||||
cur_entry = 0;
|
||||
break;
|
||||
}
|
||||
SPIFFS_GC_DBG("gc_clean: state-> %i\n", gc.state);
|
||||
} // while state != FINISHED
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif // !SPIFFS_READ_ONLY
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,751 +0,0 @@
|
||||
/*
|
||||
* spiffs_nucleus.h
|
||||
*
|
||||
* Created on: Jun 15, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
/* SPIFFS layout
|
||||
*
|
||||
* spiffs is designed for following spi flash characteristics:
|
||||
* - only big areas of data (blocks) can be erased
|
||||
* - erasing resets all bits in a block to ones
|
||||
* - writing pulls ones to zeroes
|
||||
* - zeroes cannot be pulled to ones, without erase
|
||||
* - wear leveling
|
||||
*
|
||||
* spiffs is also meant to be run on embedded, memory constraint devices.
|
||||
*
|
||||
* Entire area is divided in blocks. Entire area is also divided in pages.
|
||||
* Each block contains same number of pages. A page cannot be erased, but a
|
||||
* block can be erased.
|
||||
*
|
||||
* Entire area must be block_size * x
|
||||
* page_size must be block_size / (2^y) where y > 2
|
||||
*
|
||||
* ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes
|
||||
*
|
||||
* BLOCK 0 PAGE 0 object lookup 1
|
||||
* PAGE 1 object lookup 2
|
||||
* ...
|
||||
* PAGE n-1 object lookup n
|
||||
* PAGE n object data 1
|
||||
* PAGE n+1 object data 2
|
||||
* ...
|
||||
* PAGE n+m-1 object data m
|
||||
*
|
||||
* BLOCK 1 PAGE n+m object lookup 1
|
||||
* PAGE n+m+1 object lookup 2
|
||||
* ...
|
||||
* PAGE 2n+m-1 object lookup n
|
||||
* PAGE 2n+m object data 1
|
||||
* PAGE 2n+m object data 2
|
||||
* ...
|
||||
* PAGE 2n+2m-1 object data m
|
||||
* ...
|
||||
*
|
||||
* n is number of object lookup pages, which is number of pages needed to index all pages
|
||||
* in a block by object id
|
||||
* : block_size / page_size * sizeof(obj_id) / page_size
|
||||
* m is number data pages, which is number of pages in block minus number of lookup pages
|
||||
* : block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size
|
||||
* thus, n+m is total number of pages in a block
|
||||
* : block_size / page_size
|
||||
*
|
||||
* ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256
|
||||
*
|
||||
* Object lookup pages contain object id entries. Each entry represent the corresponding
|
||||
* data page.
|
||||
* Assuming a 16 bit object id, an object id being 0xffff represents a free page.
|
||||
* An object id being 0x0000 represents a deleted page.
|
||||
*
|
||||
* ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff ..
|
||||
* page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff ..
|
||||
* page 2 : data : data for object id 0008
|
||||
* page 3 : data : data for object id 0001
|
||||
* page 4 : data : data for object id 0aaa
|
||||
* ...
|
||||
*
|
||||
*
|
||||
* Object data pages can be either object index pages or object content.
|
||||
* All object data pages contains a data page header, containing object id and span index.
|
||||
* The span index denotes the object page ordering amongst data pages with same object id.
|
||||
* This applies to both object index pages (when index spans more than one page of entries),
|
||||
* and object data pages.
|
||||
* An object index page contains page entries pointing to object content page. The entry index
|
||||
* in a object index page correlates to the span index in the actual object data page.
|
||||
* The first object index page (span index 0) is called object index header page, and also
|
||||
* contains object flags (directory/file), size, object name etc.
|
||||
*
|
||||
* ex:
|
||||
* BLOCK 1
|
||||
* PAGE 256: objectl lookup page 1
|
||||
* [*123] [ 123] [ 123] [ 123]
|
||||
* [ 123] [*123] [ 123] [ 123]
|
||||
* [free] [free] [free] [free] ...
|
||||
* PAGE 257: objectl lookup page 2
|
||||
* [free] [free] [free] [free] ...
|
||||
* PAGE 258: object index page (header)
|
||||
* obj.id:0123 span.ix:0000 flags:INDEX
|
||||
* size:1600 name:ex.txt type:file
|
||||
* [259] [260] [261] [262]
|
||||
* PAGE 259: object data page
|
||||
* obj.id:0123 span.ix:0000 flags:DATA
|
||||
* PAGE 260: object data page
|
||||
* obj.id:0123 span.ix:0001 flags:DATA
|
||||
* PAGE 261: object data page
|
||||
* obj.id:0123 span.ix:0002 flags:DATA
|
||||
* PAGE 262: object data page
|
||||
* obj.id:0123 span.ix:0003 flags:DATA
|
||||
* PAGE 263: object index page
|
||||
* obj.id:0123 span.ix:0001 flags:INDEX
|
||||
* [264] [265] [fre] [fre]
|
||||
* [fre] [fre] [fre] [fre]
|
||||
* PAGE 264: object data page
|
||||
* obj.id:0123 span.ix:0004 flags:DATA
|
||||
* PAGE 265: object data page
|
||||
* obj.id:0123 span.ix:0005 flags:DATA
|
||||
*
|
||||
*/
|
||||
#ifndef SPIFFS_NUCLEUS_H_
|
||||
#define SPIFFS_NUCLEUS_H_
|
||||
|
||||
#define _SPIFFS_ERR_CHECK_FIRST (SPIFFS_ERR_INTERNAL - 1)
|
||||
#define SPIFFS_ERR_CHECK_OBJ_ID_MISM (SPIFFS_ERR_INTERNAL - 1)
|
||||
#define SPIFFS_ERR_CHECK_SPIX_MISM (SPIFFS_ERR_INTERNAL - 2)
|
||||
#define SPIFFS_ERR_CHECK_FLAGS_BAD (SPIFFS_ERR_INTERNAL - 3)
|
||||
#define _SPIFFS_ERR_CHECK_LAST (SPIFFS_ERR_INTERNAL - 4)
|
||||
|
||||
#define SPIFFS_VIS_COUNTINUE (SPIFFS_ERR_INTERNAL - 20)
|
||||
#define SPIFFS_VIS_COUNTINUE_RELOAD (SPIFFS_ERR_INTERNAL - 21)
|
||||
#define SPIFFS_VIS_END (SPIFFS_ERR_INTERNAL - 22)
|
||||
|
||||
#define SPIFFS_EV_IX_UPD 0
|
||||
#define SPIFFS_EV_IX_NEW 1
|
||||
#define SPIFFS_EV_IX_DEL 2
|
||||
|
||||
#define SPIFFS_OBJ_ID_IX_FLAG ((spiffs_obj_id)(1<<(8*sizeof(spiffs_obj_id)-1)))
|
||||
|
||||
#define SPIFFS_UNDEFINED_LEN (u32_t)(-1)
|
||||
|
||||
#define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0)
|
||||
#define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1)
|
||||
|
||||
#if SPIFFS_USE_MAGIC
|
||||
#if !SPIFFS_USE_MAGIC_LENGTH
|
||||
#define SPIFFS_MAGIC(fs, bix) \
|
||||
((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs)))
|
||||
#else // SPIFFS_USE_MAGIC_LENGTH
|
||||
#define SPIFFS_MAGIC(fs, bix) \
|
||||
((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs) ^ ((fs)->block_count - (bix))))
|
||||
#endif // SPIFFS_USE_MAGIC_LENGTH
|
||||
#endif // SPIFFS_USE_MAGIC
|
||||
|
||||
#define SPIFFS_CONFIG_MAGIC (0x20090315)
|
||||
|
||||
#if SPIFFS_SINGLETON == 0
|
||||
#define SPIFFS_CFG_LOG_PAGE_SZ(fs) \
|
||||
((fs)->cfg.log_page_size)
|
||||
#define SPIFFS_CFG_LOG_BLOCK_SZ(fs) \
|
||||
((fs)->cfg.log_block_size)
|
||||
#define SPIFFS_CFG_PHYS_SZ(fs) \
|
||||
((fs)->cfg.phys_size)
|
||||
#define SPIFFS_CFG_PHYS_ERASE_SZ(fs) \
|
||||
((fs)->cfg.phys_erase_block)
|
||||
#define SPIFFS_CFG_PHYS_ADDR(fs) \
|
||||
((fs)->cfg.phys_addr)
|
||||
#endif
|
||||
|
||||
// total number of pages
|
||||
#define SPIFFS_MAX_PAGES(fs) \
|
||||
( SPIFFS_CFG_PHYS_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// total number of pages per block, including object lookup pages
|
||||
#define SPIFFS_PAGES_PER_BLOCK(fs) \
|
||||
( SPIFFS_CFG_LOG_BLOCK_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// number of object lookup pages per block
|
||||
#define SPIFFS_OBJ_LOOKUP_PAGES(fs) \
|
||||
(MAX(1, (SPIFFS_PAGES_PER_BLOCK(fs) * sizeof(spiffs_obj_id)) / SPIFFS_CFG_LOG_PAGE_SZ(fs)) )
|
||||
// checks if page index belongs to object lookup
|
||||
#define SPIFFS_IS_LOOKUP_PAGE(fs,pix) \
|
||||
(((pix) % SPIFFS_PAGES_PER_BLOCK(fs)) < SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
// number of object lookup entries in all object lookup pages
|
||||
#define SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) \
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
// converts a block to physical address
|
||||
#define SPIFFS_BLOCK_TO_PADDR(fs, block) \
|
||||
( SPIFFS_CFG_PHYS_ADDR(fs) + (block)* SPIFFS_CFG_LOG_BLOCK_SZ(fs) )
|
||||
// converts a object lookup entry to page index
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, block, entry) \
|
||||
((block)*SPIFFS_PAGES_PER_BLOCK(fs) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry))
|
||||
// converts a object lookup entry to physical address of corresponding page
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, block, entry) \
|
||||
(SPIFFS_BLOCK_TO_PADDR(fs, block) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// converts a page to physical address
|
||||
#define SPIFFS_PAGE_TO_PADDR(fs, page) \
|
||||
( SPIFFS_CFG_PHYS_ADDR(fs) + (page) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// converts a physical address to page
|
||||
#define SPIFFS_PADDR_TO_PAGE(fs, addr) \
|
||||
( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) / SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// gives index in page for a physical address
|
||||
#define SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr) \
|
||||
( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) % SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// returns containing block for given page
|
||||
#define SPIFFS_BLOCK_FOR_PAGE(fs, page) \
|
||||
( (page) / SPIFFS_PAGES_PER_BLOCK(fs) )
|
||||
// returns starting page for block
|
||||
#define SPIFFS_PAGE_FOR_BLOCK(fs, block) \
|
||||
( (block) * SPIFFS_PAGES_PER_BLOCK(fs) )
|
||||
// converts page to entry in object lookup page
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, page) \
|
||||
( (page) % SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs) )
|
||||
// returns data size in a data page
|
||||
#define SPIFFS_DATA_PAGE_SIZE(fs) \
|
||||
( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) )
|
||||
// returns physical address for block's erase count,
|
||||
// always in the physical last entry of the last object lookup page
|
||||
#define SPIFFS_ERASE_COUNT_PADDR(fs, bix) \
|
||||
( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id) )
|
||||
// returns physical address for block's magic,
|
||||
// always in the physical second last entry of the last object lookup page
|
||||
#define SPIFFS_MAGIC_PADDR(fs, bix) \
|
||||
( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id)*2 )
|
||||
// checks if there is any room for magic in the object luts
|
||||
#define SPIFFS_CHECK_MAGIC_POSSIBLE(fs) \
|
||||
( (SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) % (SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(spiffs_obj_id))) * sizeof(spiffs_obj_id) \
|
||||
<= (SPIFFS_CFG_LOG_PAGE_SZ(fs)-sizeof(spiffs_obj_id)*2) )
|
||||
|
||||
// define helpers object
|
||||
|
||||
// entries in an object header page index
|
||||
#define SPIFFS_OBJ_HDR_IX_LEN(fs) \
|
||||
((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header))/sizeof(spiffs_page_ix))
|
||||
// entries in an object page index
|
||||
#define SPIFFS_OBJ_IX_LEN(fs) \
|
||||
((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix))/sizeof(spiffs_page_ix))
|
||||
// object index entry for given data span index
|
||||
#define SPIFFS_OBJ_IX_ENTRY(fs, spix) \
|
||||
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? (spix) : (((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))%SPIFFS_OBJ_IX_LEN(fs)))
|
||||
// object index span index number for given data span index or entry
|
||||
#define SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, spix) \
|
||||
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? 0 : (1+((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))/SPIFFS_OBJ_IX_LEN(fs)))
|
||||
|
||||
|
||||
#define SPIFFS_OP_T_OBJ_LU (0<<0)
|
||||
#define SPIFFS_OP_T_OBJ_LU2 (1<<0)
|
||||
#define SPIFFS_OP_T_OBJ_IX (2<<0)
|
||||
#define SPIFFS_OP_T_OBJ_DA (3<<0)
|
||||
#define SPIFFS_OP_C_DELE (0<<2)
|
||||
#define SPIFFS_OP_C_UPDT (1<<2)
|
||||
#define SPIFFS_OP_C_MOVS (2<<2)
|
||||
#define SPIFFS_OP_C_MOVD (3<<2)
|
||||
#define SPIFFS_OP_C_FLSH (4<<2)
|
||||
#define SPIFFS_OP_C_READ (5<<2)
|
||||
#define SPIFFS_OP_C_WRTHRU (6<<2)
|
||||
|
||||
#define SPIFFS_OP_TYPE_MASK (3<<0)
|
||||
#define SPIFFS_OP_COM_MASK (7<<2)
|
||||
|
||||
|
||||
// if 0, this page is written to, else clean
|
||||
#define SPIFFS_PH_FLAG_USED (1<<0)
|
||||
// if 0, writing is finalized, else under modification
|
||||
#define SPIFFS_PH_FLAG_FINAL (1<<1)
|
||||
// if 0, this is an index page, else a data page
|
||||
#define SPIFFS_PH_FLAG_INDEX (1<<2)
|
||||
// if 0, page is deleted, else valid
|
||||
#define SPIFFS_PH_FLAG_DELET (1<<7)
|
||||
// if 0, this index header is being deleted
|
||||
#define SPIFFS_PH_FLAG_IXDELE (1<<6)
|
||||
|
||||
|
||||
#define SPIFFS_CHECK_MOUNT(fs) \
|
||||
((fs)->mounted != 0)
|
||||
|
||||
#define SPIFFS_CHECK_CFG(fs) \
|
||||
((fs)->config_magic == SPIFFS_CONFIG_MAGIC)
|
||||
|
||||
#define SPIFFS_CHECK_RES(res) \
|
||||
do { \
|
||||
if ((res) < SPIFFS_OK) return (res); \
|
||||
} while (0);
|
||||
|
||||
#define SPIFFS_API_CHECK_MOUNT(fs) \
|
||||
if (!SPIFFS_CHECK_MOUNT((fs))) { \
|
||||
(fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
#define SPIFFS_API_CHECK_CFG(fs) \
|
||||
if (!SPIFFS_CHECK_CFG((fs))) { \
|
||||
(fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
#define SPIFFS_API_CHECK_RES(fs, res) \
|
||||
if ((res) < SPIFFS_OK) { \
|
||||
(fs)->err_code = (res); \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \
|
||||
if ((res) < SPIFFS_OK) { \
|
||||
(fs)->err_code = (res); \
|
||||
SPIFFS_UNLOCK(fs); \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
#define SPIFFS_VALIDATE_OBJIX(ph, objid, spix) \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) != 0) return SPIFFS_ERR_NOT_INDEX; \
|
||||
if (((objid) & SPIFFS_OBJ_ID_IX_FLAG) == 0) return SPIFFS_ERR_NOT_INDEX; \
|
||||
if ((ph).span_ix != (spix)) return SPIFFS_ERR_INDEX_SPAN_MISMATCH;
|
||||
//if ((spix) == 0 && ((ph).flags & SPIFFS_PH_FLAG_IXDELE) == 0) return SPIFFS_ERR_DELETED;
|
||||
|
||||
#define SPIFFS_VALIDATE_DATA(ph, objid, spix) \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) == 0) return SPIFFS_ERR_IS_INDEX; \
|
||||
if ((objid) & SPIFFS_OBJ_ID_IX_FLAG) return SPIFFS_ERR_IS_INDEX; \
|
||||
if ((ph).span_ix != (spix)) return SPIFFS_ERR_DATA_SPAN_MISMATCH;
|
||||
|
||||
|
||||
// check id
|
||||
#define SPIFFS_VIS_CHECK_ID (1<<0)
|
||||
// report argument object id to visitor - else object lookup id is reported
|
||||
#define SPIFFS_VIS_CHECK_PH (1<<1)
|
||||
// stop searching at end of all look up pages
|
||||
#define SPIFFS_VIS_NO_WRAP (1<<2)
|
||||
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
|
||||
(_fs)->cfg.hal_write_f((_fs), (_paddr), (_len), (_src))
|
||||
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
|
||||
(_fs)->cfg.hal_read_f((_fs), (_paddr), (_len), (_dst))
|
||||
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
|
||||
(_fs)->cfg.hal_erase_f((_fs), (_paddr), (_len))
|
||||
|
||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
|
||||
(_fs)->cfg.hal_write_f((_paddr), (_len), (_src))
|
||||
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
|
||||
(_fs)->cfg.hal_read_f((_paddr), (_len), (_dst))
|
||||
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
|
||||
(_fs)->cfg.hal_erase_f((_paddr), (_len))
|
||||
|
||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
|
||||
#define SPIFFS_CACHE_FLAG_DIRTY (1<<0)
|
||||
#define SPIFFS_CACHE_FLAG_WRTHRU (1<<1)
|
||||
#define SPIFFS_CACHE_FLAG_OBJLU (1<<2)
|
||||
#define SPIFFS_CACHE_FLAG_OBJIX (1<<3)
|
||||
#define SPIFFS_CACHE_FLAG_DATA (1<<4)
|
||||
#define SPIFFS_CACHE_FLAG_TYPE_WR (1<<7)
|
||||
|
||||
#define SPIFFS_CACHE_PAGE_SIZE(fs) \
|
||||
(sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs))
|
||||
|
||||
#define spiffs_get_cache(fs) \
|
||||
((spiffs_cache *)((fs)->cache))
|
||||
|
||||
#define spiffs_get_cache_page_hdr(fs, c, ix) \
|
||||
((spiffs_cache_page *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])))
|
||||
|
||||
#define spiffs_get_cache_page(fs, c, ix) \
|
||||
((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page))
|
||||
|
||||
// cache page struct
|
||||
typedef struct {
|
||||
// cache flags
|
||||
u8_t flags;
|
||||
// cache page index
|
||||
u8_t ix;
|
||||
// last access of this cache page
|
||||
u32_t last_access;
|
||||
union {
|
||||
// type read cache
|
||||
struct {
|
||||
// read cache page index
|
||||
spiffs_page_ix pix;
|
||||
};
|
||||
#if SPIFFS_CACHE_WR
|
||||
// type write cache
|
||||
struct {
|
||||
// write cache
|
||||
spiffs_obj_id obj_id;
|
||||
// offset in cache page
|
||||
u32_t offset;
|
||||
// size of cache page
|
||||
u16_t size;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
} spiffs_cache_page;
|
||||
|
||||
// cache struct
|
||||
typedef struct {
|
||||
u8_t cpage_count;
|
||||
u32_t last_access;
|
||||
u32_t cpage_use_map;
|
||||
u32_t cpage_use_mask;
|
||||
u8_t *cpages;
|
||||
} spiffs_cache;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// spiffs nucleus file descriptor
|
||||
typedef struct {
|
||||
// the filesystem of this descriptor
|
||||
spiffs *fs;
|
||||
// number of file descriptor - if 0, the file descriptor is closed
|
||||
spiffs_file file_nbr;
|
||||
// object id - if SPIFFS_OBJ_ID_ERASED, the file was deleted
|
||||
spiffs_obj_id obj_id;
|
||||
// size of the file
|
||||
u32_t size;
|
||||
// cached object index header page index
|
||||
spiffs_page_ix objix_hdr_pix;
|
||||
// cached offset object index page index
|
||||
spiffs_page_ix cursor_objix_pix;
|
||||
// cached offset object index span index
|
||||
spiffs_span_ix cursor_objix_spix;
|
||||
// current absolute offset
|
||||
u32_t offset;
|
||||
// current file descriptor offset
|
||||
u32_t fdoffset;
|
||||
// fd flags
|
||||
spiffs_flags flags;
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_cache_page *cache_page;
|
||||
#endif
|
||||
} spiffs_fd;
|
||||
|
||||
|
||||
// object structs
|
||||
|
||||
// page header, part of each page except object lookup pages
|
||||
// NB: this is always aligned when the data page is an object index,
|
||||
// as in this case struct spiffs_page_object_ix is used
|
||||
typedef struct __attribute(( packed )) {
|
||||
// object id
|
||||
spiffs_obj_id obj_id;
|
||||
// object span index
|
||||
spiffs_span_ix span_ix;
|
||||
// flags
|
||||
u8_t flags;
|
||||
} spiffs_page_header;
|
||||
|
||||
// object index header page header
|
||||
typedef struct __attribute(( packed ))
|
||||
#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
|
||||
__attribute(( aligned(sizeof(spiffs_page_ix)) ))
|
||||
#endif
|
||||
{
|
||||
// common page header
|
||||
spiffs_page_header p_hdr;
|
||||
// alignment
|
||||
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
||||
// size of object
|
||||
u32_t size;
|
||||
// type of object
|
||||
spiffs_obj_type type;
|
||||
// name of object
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
} spiffs_page_object_ix_header;
|
||||
|
||||
// object index page header
|
||||
typedef struct __attribute(( packed )) {
|
||||
spiffs_page_header p_hdr;
|
||||
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
||||
} spiffs_page_object_ix;
|
||||
|
||||
// callback func for object lookup visitor
|
||||
typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,
|
||||
const void *user_const_p, void *user_var_p);
|
||||
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
#define _spiffs_rd(fs, op, fh, addr, len, dst) \
|
||||
spiffs_phys_rd((fs), (op), (fh), (addr), (len), (dst))
|
||||
#define _spiffs_wr(fs, op, fh, addr, len, src) \
|
||||
spiffs_phys_wr((fs), (op), (fh), (addr), (len), (src))
|
||||
#else
|
||||
#define _spiffs_rd(fs, op, fh, addr, len, dst) \
|
||||
spiffs_phys_rd((fs), (addr), (len), (dst))
|
||||
#define _spiffs_wr(fs, op, fh, addr, len, src) \
|
||||
spiffs_phys_wr((fs), (addr), (len), (src))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_phys_rd(
|
||||
spiffs *fs,
|
||||
#if SPIFFS_CACHE
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
#endif
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *dst);
|
||||
|
||||
s32_t spiffs_phys_wr(
|
||||
spiffs *fs,
|
||||
#if SPIFFS_CACHE
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
#endif
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *src);
|
||||
|
||||
s32_t spiffs_phys_cpy(
|
||||
spiffs *fs,
|
||||
spiffs_file fh,
|
||||
u32_t dst,
|
||||
u32_t src,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_phys_count_free_blocks(
|
||||
spiffs *fs);
|
||||
|
||||
s32_t spiffs_obj_lu_find_entry_visitor(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_lu_entry,
|
||||
u8_t flags,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_visitor_f v,
|
||||
const void *user_const_p,
|
||||
void *user_var_p,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *lu_entry);
|
||||
|
||||
s32_t spiffs_erase_block(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix);
|
||||
|
||||
#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH
|
||||
s32_t spiffs_probe(
|
||||
spiffs_config *cfg);
|
||||
#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_obj_lu_scan(
|
||||
spiffs *fs);
|
||||
|
||||
s32_t spiffs_obj_lu_find_free_obj_id(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id *obj_id,
|
||||
const u8_t *conflicting_name);
|
||||
|
||||
s32_t spiffs_obj_lu_find_free(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_lu_entry,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *lu_entry);
|
||||
|
||||
s32_t spiffs_obj_lu_find_id(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_lu_entry,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *lu_entry);
|
||||
|
||||
s32_t spiffs_obj_lu_find_id_and_span(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix spix,
|
||||
spiffs_page_ix exclusion_pix,
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
s32_t spiffs_obj_lu_find_id_and_span_by_phdr(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix spix,
|
||||
spiffs_page_ix exclusion_pix,
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_page_allocate_data(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_page_header *ph,
|
||||
u8_t *data,
|
||||
u32_t len,
|
||||
u32_t page_offs,
|
||||
u8_t finalize,
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
s32_t spiffs_page_move(
|
||||
spiffs *fs,
|
||||
spiffs_file fh,
|
||||
u8_t *page_data,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_page_header *page_hdr,
|
||||
spiffs_page_ix src_pix,
|
||||
spiffs_page_ix *dst_pix);
|
||||
|
||||
s32_t spiffs_page_delete(
|
||||
spiffs *fs,
|
||||
spiffs_page_ix pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_object_create(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
const u8_t name[SPIFFS_OBJ_NAME_LEN],
|
||||
spiffs_obj_type type,
|
||||
spiffs_page_ix *objix_hdr_pix);
|
||||
|
||||
s32_t spiffs_object_update_index_hdr(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_page_ix objix_hdr_pix,
|
||||
u8_t *new_objix_hdr_data,
|
||||
const u8_t name[SPIFFS_OBJ_NAME_LEN],
|
||||
u32_t size,
|
||||
spiffs_page_ix *new_pix);
|
||||
|
||||
void spiffs_cb_object_event(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd,
|
||||
int ev,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix spix,
|
||||
spiffs_page_ix new_pix,
|
||||
u32_t new_size);
|
||||
|
||||
s32_t spiffs_object_open_by_id(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_fd *f,
|
||||
spiffs_flags flags,
|
||||
spiffs_mode mode);
|
||||
|
||||
s32_t spiffs_object_open_by_page(
|
||||
spiffs *fs,
|
||||
spiffs_page_ix pix,
|
||||
spiffs_fd *f,
|
||||
spiffs_flags flags,
|
||||
spiffs_mode mode);
|
||||
|
||||
s32_t spiffs_object_append(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u8_t *data,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_object_modify(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u8_t *data,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_object_read(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u32_t len,
|
||||
u8_t *dst);
|
||||
|
||||
s32_t spiffs_object_truncate(
|
||||
spiffs_fd *fd,
|
||||
u32_t new_len,
|
||||
u8_t remove_object);
|
||||
|
||||
s32_t spiffs_object_find_object_index_header_by_name(
|
||||
spiffs *fs,
|
||||
const u8_t name[SPIFFS_OBJ_NAME_LEN],
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_gc_check(
|
||||
spiffs *fs,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_gc_erase_page_stats(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix);
|
||||
|
||||
s32_t spiffs_gc_find_candidate(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix **block_candidate,
|
||||
int *candidate_count,
|
||||
char fs_crammed);
|
||||
|
||||
s32_t spiffs_gc_clean(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix);
|
||||
|
||||
s32_t spiffs_gc_quick(
|
||||
spiffs *fs, u16_t max_free_pages);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_fd_find_new(
|
||||
spiffs *fs,
|
||||
spiffs_fd **fd);
|
||||
|
||||
s32_t spiffs_fd_return(
|
||||
spiffs *fs,
|
||||
spiffs_file f);
|
||||
|
||||
s32_t spiffs_fd_get(
|
||||
spiffs *fs,
|
||||
spiffs_file f,
|
||||
spiffs_fd **fd);
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
void spiffs_cache_init(
|
||||
spiffs *fs);
|
||||
|
||||
void spiffs_cache_drop_page(
|
||||
spiffs *fs,
|
||||
spiffs_page_ix pix);
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd);
|
||||
|
||||
void spiffs_cache_fd_release(
|
||||
spiffs *fs,
|
||||
spiffs_cache_page *cp);
|
||||
|
||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
s32_t spiffs_lookup_consistency_check(
|
||||
spiffs *fs,
|
||||
u8_t check_all_objects);
|
||||
|
||||
s32_t spiffs_page_consistency_check(
|
||||
spiffs *fs);
|
||||
|
||||
s32_t spiffs_object_index_consistency_check(
|
||||
spiffs *fs);
|
||||
|
||||
#endif /* SPIFFS_NUCLEUS_H_ */
|
||||
@@ -1,131 +0,0 @@
|
||||
#include "ssl_drv.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#include "platform_stdlib.h"
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t SSLDrv::availData(sslclient_context *ssl_client)
|
||||
{
|
||||
//int ret;
|
||||
|
||||
if (ssl_client->socket < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_available) {
|
||||
return 1;
|
||||
} else {
|
||||
return getData(ssl_client, c, 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool SSLDrv::getData(sslclient_context *ssl_client, uint8_t *data, uint8_t peek)
|
||||
{
|
||||
int ret = 0;
|
||||
int flag = 0;
|
||||
|
||||
if (_available) {
|
||||
/* we already has data to read */
|
||||
data[0] = c[0];
|
||||
|
||||
//if (peek) {
|
||||
//} else {
|
||||
// /* It's not peek and the data has been taken */
|
||||
// _available = false;
|
||||
//}
|
||||
if (!peek) {
|
||||
/* It's not peek and the data has been taken */
|
||||
_available = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (peek) {
|
||||
flag |= 1;
|
||||
}
|
||||
|
||||
ret = get_ssl_receive(ssl_client, c, 1, flag);
|
||||
|
||||
if (ret == 1) {
|
||||
data[0] = c[0];
|
||||
if (peek) {
|
||||
_available = true;
|
||||
} else {
|
||||
_available = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int SSLDrv::getDataBuf(sslclient_context *ssl_client, uint8_t *_data, uint16_t _dataLen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (_available) {
|
||||
/* there is one byte cached */
|
||||
_data[0] = c[0];
|
||||
_available = false;
|
||||
_dataLen--;
|
||||
if (_dataLen > 0) {
|
||||
ret = get_ssl_receive(ssl_client, _data, _dataLen, 0);
|
||||
if (ret > 0) {
|
||||
ret++;
|
||||
return ret;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
ret = get_ssl_receive(ssl_client, _data, _dataLen, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SSLDrv::stopClient(sslclient_context *ssl_client)
|
||||
{
|
||||
stop_ssl_socket(ssl_client);
|
||||
_available = false;
|
||||
}
|
||||
|
||||
bool SSLDrv::sendData(sslclient_context *ssl_client, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ssl_client->socket < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = send_ssl_data(ssl_client, data, len);
|
||||
|
||||
if (ret == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int SSLDrv::startClient(sslclient_context *ssl_client, uint32_t ipAddress, uint32_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key, unsigned char* pskIdent, unsigned char* psKey, char* SNI_hostname)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = start_ssl_client(ssl_client, ipAddress, port, rootCABuff, cli_cert, cli_key, pskIdent, psKey, SNI_hostname);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SSLDrv::getLastErrno(sslclient_context *ssl_client)
|
||||
{
|
||||
return get_ssl_sock_errno(ssl_client);
|
||||
}
|
||||
|
||||
int SSLDrv::setSockRecvTimeout(int sock, int timeout)
|
||||
{
|
||||
return setSockRecvTimeout(sock, timeout);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef SSL_DRV_H
|
||||
#define SSL_DRV_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
#define DATA_LENTH 128
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#include "ard_ssl.h"
|
||||
}
|
||||
#endif
|
||||
|
||||
class SSLDrv
|
||||
{
|
||||
public:
|
||||
int startClient(sslclient_context *ssl_client, uint32_t ipAddress, uint32_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key, unsigned char* pskIdent, unsigned char* psKey, char* SNI_hostname);
|
||||
void stopClient(sslclient_context *ssl_client);
|
||||
bool getData(sslclient_context *ssl_client, uint8_t *data, uint8_t peek=0);
|
||||
int getDataBuf(sslclient_context *ssl_client, uint8_t *_data, uint16_t _dataLen);
|
||||
bool sendData(sslclient_context *ssl_client, const uint8_t *data, uint16_t len);
|
||||
uint16_t availData(sslclient_context *ssl_client);
|
||||
sslclient_context *init(void);
|
||||
int getLastErrno(sslclient_context *ssl_client);
|
||||
|
||||
int setSockRecvTimeout(int sock, int timeout);
|
||||
|
||||
private:
|
||||
bool _available;
|
||||
uint8_t c[1];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file syscalls.h
|
||||
*
|
||||
* Implementation of newlib syscall.
|
||||
*
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Headers
|
||||
*----------------------------------------------------------------------------*/
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Exported functions
|
||||
*----------------------------------------------------------------------------*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern caddr_t _sbrk( int incr ) ;
|
||||
|
||||
extern int link( char *cOld, char *cNew ) ;
|
||||
|
||||
extern int _close( int file ) ;
|
||||
|
||||
extern int _fstat( int file, struct stat *st ) ;
|
||||
|
||||
extern int _isatty( int file ) ;
|
||||
|
||||
extern int _lseek( int file, int ptr, int dir ) ;
|
||||
|
||||
extern int _read(int file, char *ptr, int len) ;
|
||||
|
||||
extern int _write( int file, char *ptr, int len ) ;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,492 +0,0 @@
|
||||
#include "wifi_drv.h"
|
||||
|
||||
// arduino includes
|
||||
#include "wl_definitions.h"
|
||||
#include "wl_types.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
// RTK includes
|
||||
#include "main.h"
|
||||
#include "wifi_conf.h"
|
||||
#include "wifi_constants.h"
|
||||
#include "wifi_structures.h"
|
||||
#include "lwip_netconf.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/api.h"
|
||||
#include <dhcp/dhcps.h>
|
||||
|
||||
extern struct netif xnetif[NET_IF_NUM];
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// Array of data to cache the information related to the networks discovered
|
||||
uint8_t WiFiDrv::_networkCount = 0;
|
||||
char WiFiDrv::_networkSsid[][WL_SSID_MAX_LENGTH] = {{"1"},{"2"},{"3"},{"4"},{"5"}};
|
||||
int32_t WiFiDrv::_networkRssi[WL_NETWORKS_LIST_MAXNUM] = { 0 };
|
||||
uint32_t WiFiDrv::_networkEncr[WL_NETWORKS_LIST_MAXNUM] = { 0 };
|
||||
|
||||
static bool init_wlan = false;
|
||||
static int wifi_mode = NULL;
|
||||
|
||||
static rtw_network_info_t wifi = {0};
|
||||
static rtw_ap_info_t ap = {0};
|
||||
static unsigned char password[65] = {0};
|
||||
|
||||
rtw_wifi_setting_t WiFiDrv::wifi_setting;
|
||||
|
||||
static void init_wifi_struct(void)
|
||||
{
|
||||
memset(wifi.ssid.val, 0, sizeof(wifi.ssid.val));
|
||||
memset(wifi.bssid.octet, 0, ETH_ALEN);
|
||||
memset(password, 0, sizeof(password));
|
||||
wifi.ssid.len = 0;
|
||||
wifi.password = NULL;
|
||||
wifi.password_len = 0;
|
||||
wifi.key_id = -1;
|
||||
memset(ap.ssid.val, 0, sizeof(ap.ssid.val));
|
||||
ap.ssid.len = 0;
|
||||
ap.password = NULL;
|
||||
ap.password_len = 0;
|
||||
ap.channel = 1;
|
||||
}
|
||||
|
||||
void WiFiDrv::wifiDriverInit()
|
||||
{
|
||||
struct netif * pnetif = &xnetif[0];
|
||||
|
||||
if (init_wlan == false) {
|
||||
init_wlan = true;
|
||||
LwIP_Init();
|
||||
wifi_on(RTW_MODE_STA);
|
||||
wifi_mode = RTW_MODE_STA;
|
||||
}else if (init_wlan == true) {
|
||||
if (wifi_mode != RTW_MODE_STA){
|
||||
dhcps_deinit();
|
||||
wifi_off();
|
||||
vTaskDelay(20);
|
||||
wifi_on(RTW_MODE_STA);
|
||||
dhcps_init(pnetif);
|
||||
wifi_mode = RTW_MODE_STA;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int8_t WiFiDrv::wifiSetNetwork(char* ssid, uint8_t ssid_len)
|
||||
{
|
||||
int ret;
|
||||
uint8_t dhcp_result;
|
||||
|
||||
memset(wifi.bssid.octet, 0, ETH_ALEN);
|
||||
memcpy(wifi.ssid.val, ssid, ssid_len);
|
||||
wifi.ssid.len = ssid_len;
|
||||
|
||||
wifi.security_type = RTW_SECURITY_OPEN;
|
||||
wifi.password = NULL;
|
||||
wifi.password_len = 0;
|
||||
wifi.key_id = 0;
|
||||
|
||||
ret = wifi_connect((char*)wifi.ssid.val, wifi.security_type, (char*)wifi.password, wifi.ssid.len,
|
||||
wifi.password_len, wifi.key_id, NULL);
|
||||
|
||||
if (ret == RTW_SUCCESS) {
|
||||
|
||||
dhcp_result = LwIP_DHCP(0, DHCP_START);
|
||||
|
||||
init_wifi_struct();
|
||||
|
||||
if ( dhcp_result == DHCP_ADDRESS_ASSIGNED ) {
|
||||
return WL_SUCCESS;
|
||||
} else {
|
||||
wifi_disconnect();
|
||||
return WL_FAILURE;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
init_wifi_struct();
|
||||
|
||||
return WL_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
int8_t WiFiDrv::wifiSetPassphrase(char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len)
|
||||
{
|
||||
int ret;
|
||||
uint8_t dhcp_result;
|
||||
|
||||
memset(wifi.bssid.octet, 0, ETH_ALEN);
|
||||
memcpy(wifi.ssid.val, ssid, ssid_len);
|
||||
wifi.ssid.len = ssid_len;
|
||||
|
||||
wifi.security_type = RTW_SECURITY_WPA2_AES_PSK;
|
||||
memset(password, 0, sizeof(password));
|
||||
memcpy(password, passphrase, len);
|
||||
wifi.password = password;
|
||||
wifi.password_len = len;
|
||||
wifi.key_id = 0;
|
||||
|
||||
ret = wifi_connect((char*)wifi.ssid.val, wifi.security_type, (char*)wifi.password, wifi.ssid.len,
|
||||
wifi.password_len, wifi.key_id, NULL);
|
||||
|
||||
if (ret == RTW_SUCCESS) {
|
||||
|
||||
dhcp_result = LwIP_DHCP(0, DHCP_START);
|
||||
|
||||
init_wifi_struct();
|
||||
|
||||
if ( dhcp_result == DHCP_ADDRESS_ASSIGNED ) {
|
||||
return WL_SUCCESS;
|
||||
} else {
|
||||
wifi_disconnect();
|
||||
return WL_FAILURE;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
init_wifi_struct();
|
||||
|
||||
return WL_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
int8_t WiFiDrv::wifiSetKey(char* ssid, uint8_t ssid_len, uint8_t key_idx, const void *key, const uint8_t len)
|
||||
{
|
||||
int ret;
|
||||
uint8_t dhcp_result;
|
||||
int i, idx;
|
||||
const unsigned char* k = (const unsigned char *)key;
|
||||
|
||||
memset(wifi.bssid.octet, 0, ETH_ALEN);
|
||||
memcpy(wifi.ssid.val, ssid, ssid_len);
|
||||
wifi.ssid.len = ssid_len;
|
||||
|
||||
wifi.security_type = RTW_SECURITY_WEP_PSK;
|
||||
memset(password, 0, sizeof(password));
|
||||
|
||||
// convert hex sring to hex value
|
||||
for (i=0, idx=0; i<len; i++) {
|
||||
|
||||
if ( k[i] >= '0' && k[i] <= '9' ) {
|
||||
password[idx] += (k[i] - '0');
|
||||
} else if ( k[i] >= 'a' && k[i] <= 'f' ) {
|
||||
password[idx] += (k[i] - 'a' + 10);
|
||||
} else if ( k[i] >= 'A' && k[i] <= 'F' ) {
|
||||
password[idx] += (k[i] - 'A' + 10);
|
||||
}
|
||||
|
||||
if (i % 2 == 0) {
|
||||
password[idx] *= 16;
|
||||
} else {
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
wifi.password = password;
|
||||
wifi.password_len = len/2;
|
||||
wifi.key_id = key_idx;
|
||||
|
||||
ret = wifi_connect((char*)wifi.ssid.val, wifi.security_type, (char*)wifi.password, wifi.ssid.len,
|
||||
wifi.password_len, wifi.key_id, NULL);
|
||||
|
||||
if (ret == RTW_SUCCESS) {
|
||||
|
||||
dhcp_result = LwIP_DHCP(0, DHCP_START);
|
||||
|
||||
init_wifi_struct();
|
||||
|
||||
if ( dhcp_result == DHCP_ADDRESS_ASSIGNED ) {
|
||||
return WL_SUCCESS;
|
||||
} else {
|
||||
wifi_disconnect();
|
||||
return WL_FAILURE;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
init_wifi_struct();
|
||||
|
||||
return WL_FAILURE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int8_t WiFiDrv::apSetNetwork(char* ssid, uint8_t ssid_len)
|
||||
{
|
||||
int ret = WL_SUCCESS;
|
||||
|
||||
ap.ssid.len = ssid_len;
|
||||
|
||||
if(ap.ssid.len > 32){
|
||||
printf("Error: SSID length can't exceed 32\n\r");
|
||||
ret = WL_FAILURE;
|
||||
}
|
||||
strcpy((char *)ap.ssid.val, (char*)ssid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int8_t WiFiDrv::apSetPassphrase(const char *passphrase, uint8_t len)
|
||||
|
||||
{
|
||||
int ret = WL_SUCCESS;
|
||||
strcpy((char *)password, (char*)passphrase);
|
||||
ap.password = password;
|
||||
ap.password_len = len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int8_t WiFiDrv::apSetChannel(const char *channel)
|
||||
{
|
||||
int ret = WL_SUCCESS;
|
||||
ap.channel = (unsigned char) atoi((const char *)channel);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int8_t WiFiDrv::apActivate()
|
||||
{
|
||||
#if CONFIG_LWIP_LAYER
|
||||
struct ip_addr ipaddr;
|
||||
struct ip_addr netmask;
|
||||
struct ip_addr gw;
|
||||
struct netif * pnetif = &xnetif[0];
|
||||
#endif
|
||||
int timeout = 20;
|
||||
int ret = WL_SUCCESS;
|
||||
if(ap.ssid.val[0] == 0){
|
||||
printf("Error: SSID can't be empty\n\r");
|
||||
ret = WL_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
if(ap.password == NULL){
|
||||
ap.security_type = RTW_SECURITY_OPEN;
|
||||
}
|
||||
else{
|
||||
ap.security_type = RTW_SECURITY_WPA2_AES_PSK;
|
||||
}
|
||||
|
||||
#if CONFIG_LWIP_LAYER
|
||||
dhcps_deinit();
|
||||
IP4_ADDR(&ipaddr, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
|
||||
IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1 , NETMASK_ADDR2, NETMASK_ADDR3);
|
||||
IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
|
||||
netif_set_addr(pnetif, &ipaddr, &netmask,&gw);
|
||||
#endif
|
||||
wifi_off();
|
||||
vTaskDelay(20);
|
||||
if (wifi_on(RTW_MODE_AP) < 0){
|
||||
printf("\n\rERROR: Wifi on failed!");
|
||||
ret = WL_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
printf("\n\rStarting AP ...");
|
||||
|
||||
if((ret = wifi_start_ap((char*)ap.ssid.val, ap.security_type, (char*)ap.password, ap.ssid.len, ap.password_len, ap.channel) )< 0) {
|
||||
printf("\n\rERROR: Operation failed!");
|
||||
ret = WL_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
char essid[33];
|
||||
|
||||
if(wext_get_ssid(WLAN0_NAME, (unsigned char *) essid) > 0) {
|
||||
if(strcmp((const char *) essid, (const char *)ap.ssid.val) == 0) {
|
||||
printf("\n\r%s started\n", ap.ssid.val);
|
||||
ret = WL_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(timeout == 0) {
|
||||
printf("\n\rERROR: Start AP timeout!");
|
||||
ret = WL_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
vTaskDelay(1 * configTICK_RATE_HZ);
|
||||
timeout --;
|
||||
}
|
||||
#if CONFIG_LWIP_LAYER
|
||||
//LwIP_UseStaticIP(pnetif);
|
||||
dhcps_init(pnetif);
|
||||
#endif
|
||||
|
||||
exit:
|
||||
init_wifi_struct( );
|
||||
if(ret == WL_SUCCESS){
|
||||
wifi_mode = RTW_MODE_AP;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
int8_t WiFiDrv::disconnect()
|
||||
{
|
||||
wifi_disconnect();
|
||||
|
||||
return WL_DISCONNECTED;
|
||||
}
|
||||
|
||||
uint8_t WiFiDrv::getConnectionStatus()
|
||||
{
|
||||
wifiDriverInit();
|
||||
|
||||
if (wifi_is_connected_to_ap() == 0) {
|
||||
return WL_CONNECTED;
|
||||
} else {
|
||||
return WL_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* WiFiDrv::getMacAddress()
|
||||
{
|
||||
return LwIP_GetMAC(&xnetif[0]);
|
||||
}
|
||||
|
||||
void WiFiDrv::getIpAddress(IPAddress& ip)
|
||||
{
|
||||
ip = LwIP_GetIP(&xnetif[0]);
|
||||
}
|
||||
|
||||
void WiFiDrv::getSubnetMask(IPAddress& mask)
|
||||
{
|
||||
mask = LwIP_GetMASK(&xnetif[0]);
|
||||
}
|
||||
|
||||
void WiFiDrv::getGatewayIP(IPAddress& ip)
|
||||
{
|
||||
ip = LwIP_GetGW(&xnetif[0]);
|
||||
}
|
||||
|
||||
char* WiFiDrv::getCurrentSSID()
|
||||
{
|
||||
wifi_get_setting(WLAN0_NAME, &wifi_setting);
|
||||
|
||||
return (char *)(wifi_setting.ssid);
|
||||
}
|
||||
|
||||
uint8_t* WiFiDrv::getCurrentBSSID()
|
||||
{
|
||||
uint8_t bssid[ETH_ALEN];
|
||||
wext_get_bssid(WLAN0_NAME, bssid);
|
||||
return bssid;
|
||||
}
|
||||
|
||||
int32_t WiFiDrv::getCurrentRSSI()
|
||||
{
|
||||
int rssi = 0;
|
||||
|
||||
wifi_get_rssi(&rssi);
|
||||
|
||||
return rssi;
|
||||
}
|
||||
|
||||
uint8_t WiFiDrv::getCurrentEncryptionType()
|
||||
{
|
||||
wifi_get_setting(WLAN0_NAME, &wifi_setting);
|
||||
|
||||
return (wifi_setting.security_type);
|
||||
}
|
||||
|
||||
rtw_result_t WiFiDrv::wifidrv_scan_result_handler( rtw_scan_handler_result_t* malloced_scan_result )
|
||||
{
|
||||
rtw_scan_result_t* record;
|
||||
|
||||
if (malloced_scan_result->scan_complete != RTW_TRUE) {
|
||||
record = &malloced_scan_result->ap_details;
|
||||
record->SSID.val[record->SSID.len] = 0; /* Ensure the SSID is null terminated */
|
||||
|
||||
if ( _networkCount < WL_NETWORKS_LIST_MAXNUM ) {
|
||||
strcpy( _networkSsid[_networkCount], (char *)record->SSID.val);
|
||||
_networkRssi[_networkCount] = record->signal_strength;
|
||||
_networkEncr[_networkCount] = record->security;
|
||||
_networkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return RTW_SUCCESS;
|
||||
}
|
||||
|
||||
int8_t WiFiDrv::startScanNetworks()
|
||||
{
|
||||
_networkCount = 0;
|
||||
if( wifi_scan_networks(wifidrv_scan_result_handler, NULL ) != RTW_SUCCESS ){
|
||||
return WL_FAILURE;
|
||||
}
|
||||
|
||||
return WL_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t WiFiDrv::getScanNetworks()
|
||||
{
|
||||
return _networkCount;
|
||||
}
|
||||
|
||||
char* WiFiDrv::getSSIDNetoworks(uint8_t networkItem)
|
||||
{
|
||||
if (networkItem >= WL_NETWORKS_LIST_MAXNUM)
|
||||
return NULL;
|
||||
|
||||
return _networkSsid[networkItem];
|
||||
}
|
||||
|
||||
uint8_t WiFiDrv::getEncTypeNetowrks(uint8_t networkItem)
|
||||
{
|
||||
if (networkItem >= WL_NETWORKS_LIST_MAXNUM)
|
||||
return NULL;
|
||||
|
||||
uint8_t encType = 0;
|
||||
|
||||
if ( _networkEncr[networkItem] == RTW_SECURITY_OPEN ) {
|
||||
encType = ENC_TYPE_NONE;
|
||||
} else if ( (_networkEncr[networkItem] & AES_ENABLED) || (_networkEncr[networkItem] == RTW_SECURITY_WPA_WPA2_MIXED) ) {
|
||||
encType = ENC_TYPE_CCMP;
|
||||
} else if ( _networkEncr[networkItem] & TKIP_ENABLED ) {
|
||||
encType = ENC_TYPE_TKIP;
|
||||
} else if ( _networkEncr[networkItem] == RTW_SECURITY_WEP_PSK ) {
|
||||
encType = ENC_TYPE_WEP;
|
||||
}
|
||||
|
||||
return encType;
|
||||
}
|
||||
|
||||
uint32_t WiFiDrv::getEncTypeNetowrksEx(uint8_t networkItem)
|
||||
{
|
||||
return (networkItem >= WL_NETWORKS_LIST_MAXNUM) ? NULL : _networkEncr[networkItem];
|
||||
}
|
||||
|
||||
int32_t WiFiDrv::getRSSINetoworks(uint8_t networkItem)
|
||||
{
|
||||
if (networkItem >= WL_NETWORKS_LIST_MAXNUM)
|
||||
return NULL;
|
||||
|
||||
return _networkRssi[networkItem];
|
||||
}
|
||||
|
||||
char* WiFiDrv::getFwVersion()
|
||||
{
|
||||
// The version is for compatible to arduino example code
|
||||
return "1.1.0";
|
||||
}
|
||||
|
||||
int WiFiDrv::getHostByName(const char* aHostname, IPAddress& aResult)
|
||||
{
|
||||
ip_addr_t ip_addr;
|
||||
err_t err;
|
||||
|
||||
err = netconn_gethostbyname(aHostname, &ip_addr);
|
||||
|
||||
if (err != ERR_OK) {
|
||||
return WL_FAILURE;
|
||||
}
|
||||
else{
|
||||
aResult = ip_addr.addr;
|
||||
return WL_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
int WiFiDrv::disablePowerSave()
|
||||
{
|
||||
return wifi_disable_powersave();
|
||||
}
|
||||
@@ -1,272 +0,0 @@
|
||||
/*
|
||||
wifi_drv.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef WiFi_Drv_h
|
||||
#define WiFi_Drv_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "api/IPAddress.h"
|
||||
#include "wl_definitions.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
// rtk includes
|
||||
#include "wifi_structures.h"
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// Key index length
|
||||
#define KEY_IDX_LEN 1
|
||||
// 5 secs of delay to have the connection established
|
||||
#define WL_DELAY_START_CONNECTION 5000
|
||||
// firmware version string length
|
||||
#define WL_FW_VER_LENGTH 6
|
||||
|
||||
class WiFiDrv
|
||||
{
|
||||
private:
|
||||
// settings of requested network
|
||||
static uint8_t _networkCount;
|
||||
static char _networkSsid[WL_NETWORKS_LIST_MAXNUM][WL_SSID_MAX_LENGTH];
|
||||
static int32_t _networkRssi[WL_NETWORKS_LIST_MAXNUM];
|
||||
static uint32_t _networkEncr[WL_NETWORKS_LIST_MAXNUM];
|
||||
|
||||
// settings of current selected network
|
||||
static rtw_wifi_setting_t wifi_setting;
|
||||
|
||||
static rtw_result_t wifidrv_scan_result_handler( rtw_scan_handler_result_t* malloced_scan_result );
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
* Driver initialization
|
||||
*/
|
||||
static void wifiDriverInit();
|
||||
|
||||
/*
|
||||
* Set the desired network which the connection manager should try to
|
||||
* connect to.
|
||||
*
|
||||
* The ssid of the desired network should be specified.
|
||||
*
|
||||
* param ssid: The ssid of the desired network.
|
||||
* param ssid_len: Lenght of ssid string.
|
||||
* return: WL_SUCCESS or WL_FAILURE
|
||||
*/
|
||||
static int8_t wifiSetNetwork(char* ssid, uint8_t ssid_len);
|
||||
|
||||
/* Start Wifi connection with passphrase
|
||||
* the most secure supported mode will be automatically selected
|
||||
*
|
||||
* param ssid: Pointer to the SSID string.
|
||||
* param ssid_len: Lenght of ssid string.
|
||||
* param passphrase: Passphrase. Valid characters in a passphrase
|
||||
* must be between ASCII 32-126 (decimal).
|
||||
* param len: Lenght of passphrase string.
|
||||
* return: WL_SUCCESS or WL_FAILURE
|
||||
*/
|
||||
static int8_t wifiSetPassphrase(char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len);
|
||||
|
||||
/* Start Wifi connection with WEP encryption.
|
||||
* Configure a key into the device. The key type (WEP-40, WEP-104)
|
||||
* is determined by the size of the key (5 bytes for WEP-40, 13 bytes for WEP-104).
|
||||
*
|
||||
* param ssid: Pointer to the SSID string.
|
||||
* param ssid_len: Lenght of ssid string.
|
||||
* param key_idx: The key index to set. Valid values are 0-3.
|
||||
* param key: Key input buffer.
|
||||
* param len: Lenght of key string.
|
||||
* return: WL_SUCCESS or WL_FAILURE
|
||||
*/
|
||||
static int8_t wifiSetKey(char* ssid, uint8_t ssid_len, uint8_t key_idx, const void *key, const uint8_t len);
|
||||
|
||||
/* Set ip configuration disabling dhcp client
|
||||
*
|
||||
* param validParams: set the number of parameters that we want to change
|
||||
* i.e. validParams = 1 means that we'll change only ip address
|
||||
* validParams = 3 means that we'll change ip address, gateway and netmask
|
||||
* param local_ip: Static ip configuration
|
||||
* param gateway: Static gateway configuration
|
||||
* param subnet: Static subnet mask configuration
|
||||
*/
|
||||
static void config(uint8_t validParams, uint32_t local_ip, uint32_t gateway, uint32_t subnet);
|
||||
|
||||
/* Set DNS ip configuration
|
||||
*
|
||||
* param validParams: set the number of parameters that we want to change
|
||||
* i.e. validParams = 1 means that we'll change only dns_server1
|
||||
* validParams = 2 means that we'll change dns_server1 and dns_server2
|
||||
* param dns_server1: Static DNS server1 configuration
|
||||
* param dns_server2: Static DNS server2 configuration
|
||||
*/
|
||||
static void setDNS(uint8_t validParams, uint32_t dns_server1, uint32_t dns_server2);
|
||||
|
||||
/*
|
||||
* Disconnect from the network
|
||||
*
|
||||
* return: WL_SUCCESS or WL_FAILURE
|
||||
*/
|
||||
static int8_t disconnect();
|
||||
|
||||
/*
|
||||
* Disconnect from the network
|
||||
*
|
||||
* return: one value of wl_status_t enum
|
||||
*/
|
||||
static uint8_t getConnectionStatus();
|
||||
|
||||
/*
|
||||
* Get the interface MAC address.
|
||||
*
|
||||
* return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
|
||||
*/
|
||||
static uint8_t* getMacAddress();
|
||||
|
||||
/*
|
||||
* Get the interface IP address.
|
||||
*
|
||||
* return: copy the ip address value in IPAddress object
|
||||
*/
|
||||
static void getIpAddress(IPAddress& ip);
|
||||
|
||||
/*
|
||||
* Get the interface subnet mask address.
|
||||
*
|
||||
* return: copy the subnet mask address value in IPAddress object
|
||||
*/
|
||||
static void getSubnetMask(IPAddress& mask);
|
||||
|
||||
/*
|
||||
* Get the gateway ip address.
|
||||
*
|
||||
* return: copy the gateway ip address value in IPAddress object
|
||||
*/
|
||||
static void getGatewayIP(IPAddress& ip);
|
||||
|
||||
/*
|
||||
* Return the current SSID associated with the network
|
||||
*
|
||||
* return: ssid string
|
||||
*/
|
||||
static char* getCurrentSSID();
|
||||
|
||||
/*
|
||||
* Return the current BSSID associated with the network.
|
||||
* It is the MAC address of the Access Point
|
||||
*
|
||||
* return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
|
||||
*/
|
||||
static uint8_t* getCurrentBSSID();
|
||||
|
||||
/*
|
||||
* Return the current RSSI /Received Signal Strength in dBm)
|
||||
* associated with the network
|
||||
*
|
||||
* return: signed value
|
||||
*/
|
||||
static int32_t getCurrentRSSI();
|
||||
|
||||
/*
|
||||
* Return the Encryption Type associated with the network
|
||||
*
|
||||
* return: one value of wl_enc_type enum
|
||||
*/
|
||||
static uint8_t getCurrentEncryptionType();
|
||||
|
||||
/*
|
||||
* Start scan WiFi networks available
|
||||
*
|
||||
* return: Number of discovered networks
|
||||
*/
|
||||
static int8_t startScanNetworks();
|
||||
|
||||
/*
|
||||
* Get the networks available
|
||||
*
|
||||
* return: Number of discovered networks
|
||||
*/
|
||||
static uint8_t getScanNetworks();
|
||||
|
||||
/*
|
||||
* Return the SSID discovered during the network scan.
|
||||
*
|
||||
* param networkItem: specify from which network item want to get the information
|
||||
*
|
||||
* return: ssid string of the specified item on the networks scanned list
|
||||
*/
|
||||
static char* getSSIDNetoworks(uint8_t networkItem);
|
||||
|
||||
/*
|
||||
* Return the RSSI of the networks discovered during the scanNetworks
|
||||
*
|
||||
* param networkItem: specify from which network item want to get the information
|
||||
*
|
||||
* return: signed value of RSSI of the specified item on the networks scanned list
|
||||
*/
|
||||
static int32_t getRSSINetoworks(uint8_t networkItem);
|
||||
|
||||
/*
|
||||
* Return the encryption type of the networks discovered during the scanNetworks
|
||||
*
|
||||
* param networkItem: specify from which network item want to get the information
|
||||
*
|
||||
* return: encryption type (enum wl_enc_type) of the specified item on the networks scanned list
|
||||
*/
|
||||
static uint8_t getEncTypeNetowrks(uint8_t networkItem);
|
||||
|
||||
/*
|
||||
* Return the security type and encryption type of the networks discovered during the scanNetworks
|
||||
*
|
||||
* param networkItem: specify from which network item want to get the information
|
||||
*
|
||||
* return: security and encryption type of the specified item on the networks scanned list
|
||||
*/
|
||||
static uint32_t getEncTypeNetowrksEx(uint8_t networkItem);
|
||||
|
||||
/*
|
||||
* Resolve the given hostname to an IP address.
|
||||
* param aHostname: Name to be resolved
|
||||
* param aResult: IPAddress structure to store the returned IP address
|
||||
* result: 1 if aIPAddrString was successfully converted to an IP address,
|
||||
* else error code
|
||||
*/
|
||||
static int getHostByName(const char* aHostname, IPAddress& aResult);
|
||||
|
||||
/*
|
||||
* Get the firmware version
|
||||
* result: version as string with this format a.b.c
|
||||
*/
|
||||
static char* getFwVersion();
|
||||
|
||||
static int8_t apSetNetwork(char* ssid, uint8_t ssid_len);
|
||||
|
||||
static int8_t apSetPassphrase(const char *passphrase, uint8_t len);
|
||||
|
||||
static int8_t apSetChannel(const char *channel);
|
||||
|
||||
static int8_t apActivate();
|
||||
|
||||
static int disablePowerSave();
|
||||
};
|
||||
|
||||
extern WiFiDrv wiFiDrv;
|
||||
|
||||
#endif
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "cmsis_os.h"
|
||||
|
||||
#ifndef portNVIC_SYSTICK_CURRENT_VALUE_REG
|
||||
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile uint32_t * ) 0xe000e018 ) )
|
||||
#endif
|
||||
|
||||
extern uint32_t xTaskGetTickCount();
|
||||
extern uint32_t xTaskGetTickCountFromISR();
|
||||
|
||||
static __inline uint32_t __get_ipsr__(void)
|
||||
{
|
||||
volatile uint32_t __regIPSR __asm("ipsr");
|
||||
return(__regIPSR);
|
||||
}
|
||||
|
||||
void init(void)
|
||||
{
|
||||
// nop
|
||||
}
|
||||
|
||||
void delay( uint32_t ms )
|
||||
{
|
||||
osStatus ret;
|
||||
|
||||
ret = osDelay(ms);
|
||||
if ( (ret != osEventTimeout) && (ret != osOK) ) {
|
||||
//printf("delay : ERROR : 0x%x \n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
void delayMicroseconds(unsigned int us)
|
||||
{
|
||||
int i;
|
||||
uint32_t t0, tn;
|
||||
int dfactor = 0;
|
||||
|
||||
#if defined(BOARD_RTL8710)
|
||||
// dfactor = 10 * us - 10 + (40 * us / 100);
|
||||
dfactor = 20 * us - 10 + (81 * us / 100);
|
||||
#elif defined(BOARD_RTL8195A)
|
||||
dfactor = 20 * us - 10 + (81 * us / 100);
|
||||
#else
|
||||
dfactor = 20 * us - 10 + (81 * us / 100);
|
||||
#endif
|
||||
|
||||
if ( us > 100 ) {
|
||||
t0 = micros();
|
||||
do {
|
||||
tn = micros();
|
||||
} while ( tn >= t0 && tn < (t0 + us - 1) );
|
||||
} else {
|
||||
for (i=0; i<dfactor; i++) {
|
||||
asm("nop");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t millis( void )
|
||||
{
|
||||
return (__get_ipsr__() == 0) ? xTaskGetTickCount() : xTaskGetTickCountFromISR();
|
||||
}
|
||||
|
||||
uint32_t micros( void )
|
||||
{
|
||||
uint32_t tick1, tick2;
|
||||
uint32_t us;
|
||||
uint32_t tick_per_us;
|
||||
|
||||
#if defined(BOARD_RTL8710)
|
||||
tick_per_us = 166666; // 83333;
|
||||
#elif defined(BOARD_RTL8195A)
|
||||
tick_per_us = 166666;
|
||||
#else
|
||||
tick_per_us = 166666;
|
||||
#endif
|
||||
|
||||
if (__get_ipsr__() == 0) {
|
||||
tick1 = xTaskGetTickCount();
|
||||
us = portNVIC_SYSTICK_CURRENT_VALUE_REG;
|
||||
tick2 = xTaskGetTickCount();
|
||||
} else {
|
||||
tick1 = xTaskGetTickCountFromISR();
|
||||
us = portNVIC_SYSTICK_CURRENT_VALUE_REG;
|
||||
tick2 = xTaskGetTickCountFromISR();
|
||||
}
|
||||
|
||||
if (tick1 == tick2) {
|
||||
return tick1 * 1000 - us*1000 / tick_per_us;
|
||||
} else if( (us*1000 / tick_per_us) < 500 ) {
|
||||
return tick1 * 1000 - us*1000 / tick_per_us;
|
||||
} else {
|
||||
return tick1 * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
// RTL8710 module do not support ADC/DAC
|
||||
#if 1 // !defined(BOARD_RTL8710)
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "analogin_api.h"
|
||||
#include "analogout_api.h"
|
||||
#include "pwmout_api.h"
|
||||
#include "gpio_ex_api.h"
|
||||
|
||||
|
||||
/* ADC */
|
||||
analogin_t adc1;
|
||||
analogin_t adc2;
|
||||
analogin_t adc3;
|
||||
|
||||
static const float ADC_slope1 = (3.12)/(3410.0-674.0);
|
||||
static const float ADC_slope2 = (3.3-3.12)/(3454.0-3410.0);
|
||||
|
||||
bool g_adc_enabled[] = {
|
||||
false, false, false
|
||||
};
|
||||
|
||||
extern void *gpio_pin_struct[];
|
||||
|
||||
//
|
||||
// Arduino
|
||||
//
|
||||
|
||||
static int _readResolution = 10;
|
||||
static int _writeResolution = 8;
|
||||
static int _writePeriod = 20000;
|
||||
|
||||
void analogReadResolution(int res) {
|
||||
_readResolution = res;
|
||||
}
|
||||
|
||||
void analogWriteResolution(int res) {
|
||||
_writeResolution = res;
|
||||
}
|
||||
|
||||
void analogWritePeriod(int us) {
|
||||
_writePeriod = us;
|
||||
}
|
||||
|
||||
static inline uint32_t mapResolution(uint32_t value, uint32_t from, uint32_t to) {
|
||||
if (from == to)
|
||||
return value;
|
||||
if (from > to)
|
||||
return value >> (from-to);
|
||||
else
|
||||
return value << (to-from);
|
||||
}
|
||||
|
||||
uint8_t analog_reference = AR_DEFAULT;
|
||||
|
||||
void analogReference(uint8_t mode)
|
||||
{
|
||||
analog_reference = mode;
|
||||
}
|
||||
|
||||
int analogRead(pin_size_t pinNumber)
|
||||
{
|
||||
uint32_t ulValue = 0;
|
||||
uint32_t ulChannel;
|
||||
uint16_t ret = 0;
|
||||
float voltage;
|
||||
float adc_value;
|
||||
|
||||
switch ( pinNumber ) {
|
||||
case PIN_A0:
|
||||
if (g_adc_enabled[0] == false)
|
||||
{
|
||||
analogin_init(&adc1, AD_1);
|
||||
g_adc_enabled[0] = true;
|
||||
}
|
||||
case PIN_A1:
|
||||
if (g_adc_enabled[1] == false)
|
||||
{
|
||||
analogin_init(&adc2, AD_2);
|
||||
g_adc_enabled[1] = true;
|
||||
}
|
||||
ret = analogin_read_u16(&adc2);
|
||||
break;
|
||||
case PIN_A2:
|
||||
if (g_adc_enabled[2] == false)
|
||||
{
|
||||
analogin_init(&adc3, AD_3);
|
||||
g_adc_enabled[2] = true;
|
||||
}
|
||||
ret = analogin_read_u16(&adc3);
|
||||
break;
|
||||
default:
|
||||
printf("%s : pinNumber %d wrong\n", __FUNCTION__, pinNumber);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret >>= 4;
|
||||
if (ret < 674) {
|
||||
voltage = 0;
|
||||
} else if ( ret > 3410){
|
||||
voltage = (float)(ret - 3410)*ADC_slope2 + 3.12;
|
||||
} else {
|
||||
voltage = (float)(ret-674)*ADC_slope1;
|
||||
}
|
||||
|
||||
ret = round((1<<_readResolution)*voltage/3.3);
|
||||
if ( ret >= (1<<_readResolution) ) ret = (1<<_readResolution) - 1;
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void analogOutputInit(void) {
|
||||
// nop
|
||||
}
|
||||
|
||||
// Right now, PWM output only works on the pins with
|
||||
// hardware support. These are defined in the appropriate
|
||||
// pins_*.c file. For the rest of the pins, we default
|
||||
// to digital output.
|
||||
void analogWrite(pin_size_t pinNumber, int value)
|
||||
{
|
||||
pwmout_t *obj;
|
||||
|
||||
if ((g_APinDescription[pinNumber].ulPinAttribute & PIO_PWM) == PIO_PWM) {
|
||||
/* Handle */
|
||||
if ( g_APinDescription[pinNumber].ulPinType != PIO_PWM )
|
||||
{
|
||||
if ( (g_APinDescription[pinNumber].ulPinType == PIO_GPIO) || (g_APinDescription[pinNumber].ulPinType == PIO_GPIO_IRQ) ) {
|
||||
pinRemoveMode(pinNumber);
|
||||
}
|
||||
gpio_pin_struct[pinNumber] = malloc ( sizeof(pwmout_t) );
|
||||
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber];
|
||||
pwmout_init( obj, g_APinDescription[pinNumber].pinname );
|
||||
pwmout_period_us( obj, _writePeriod);
|
||||
pwmout_write( obj, value * 1.0 / (1<<_writeResolution));
|
||||
g_APinDescription[pinNumber].ulPinType = PIO_PWM;
|
||||
g_APinDescription[pinNumber].ulPinMode = PWM_MODE_ENABLED;
|
||||
} else {
|
||||
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber];
|
||||
pwmout_period_us( obj, _writePeriod);
|
||||
pwmout_write( obj, value * 1.0 / (1<<_writeResolution));
|
||||
/* if ( g_APinDescription[pinNumber].ulPinMode == PWM_MODE_DISABLED ) {
|
||||
HAL_Pwm_Enable( &obj->pwm_hal_adp );
|
||||
} */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct _tone_argument {
|
||||
uint32_t ulPin;
|
||||
uint32_t timer_id;
|
||||
};
|
||||
|
||||
void _tone_timer_handler(void const *argument)
|
||||
{
|
||||
struct _tone_argument *arg = (struct _tone_argument *)argument;
|
||||
|
||||
uint32_t ulPin = (uint32_t) argument;
|
||||
|
||||
noTone(arg->ulPin);
|
||||
|
||||
os_timer_delete(arg->timer_id);
|
||||
|
||||
free( (struct _tone_argument *) arg );
|
||||
}
|
||||
|
||||
void _tone(uint32_t ulPin, unsigned int frequency, unsigned long duration)
|
||||
{
|
||||
pwmout_t *obj;
|
||||
|
||||
if ((g_APinDescription[ulPin].ulPinAttribute & PIO_PWM) != PIO_PWM) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( g_APinDescription[ulPin].ulPinType != PIO_PWM )
|
||||
{
|
||||
if ( (g_APinDescription[ulPin].ulPinType == PIO_GPIO) || (g_APinDescription[ulPin].ulPinType == PIO_GPIO_IRQ) ) {
|
||||
pinRemoveMode(ulPin);
|
||||
}
|
||||
gpio_pin_struct[ulPin] = malloc ( sizeof(pwmout_t) );
|
||||
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[ulPin];
|
||||
pwmout_init( obj, g_APinDescription[ulPin].pinname);
|
||||
pwmout_period( obj, 1.0/frequency );
|
||||
pwmout_pulsewidth( obj, 1.0/(frequency * 2) );
|
||||
g_APinDescription[ulPin].ulPinType = PIO_PWM;
|
||||
g_APinDescription[ulPin].ulPinMode = PWM_MODE_ENABLED;
|
||||
|
||||
} else {
|
||||
// There is already a PWM configured
|
||||
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[ulPin];
|
||||
pwmout_period( obj, 1.0/frequency );
|
||||
pwmout_pulsewidth( obj, 1.0/(frequency * 2));
|
||||
/* if (g_APinDescription[ulPin].ulPinMode == PWM_MODE_DISABLED) {
|
||||
HAL_Pwm_Enable( &obj->pwm_hal_adp );
|
||||
} */
|
||||
}
|
||||
|
||||
if (duration > 0) {
|
||||
struct _tone_argument *arg = (struct _tone_argument *) malloc ( sizeof(struct _tone_argument) );
|
||||
arg->ulPin = ulPin;
|
||||
arg->timer_id = os_timer_create(_tone_timer_handler, 0, arg);
|
||||
os_timer_start(arg->timer_id, duration);
|
||||
}
|
||||
}
|
||||
|
||||
void noTone(uint32_t ulPin)
|
||||
{
|
||||
pinRemoveMode(ulPin);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
//#else // #if !defined(BOARD_RTL8710)
|
||||
|
||||
#endif // #if !defined(BOARD_RTL8710)
|
||||
@@ -1,144 +0,0 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "gpio_api.h"
|
||||
#include "gpio_irq_api.h"
|
||||
#include "gpio_irq_ex_api.h"
|
||||
#include "pwmout_api.h"
|
||||
|
||||
extern void *gpio_pin_struct[PINS_COUNT];
|
||||
extern void *gpio_irq_handler_list[PINS_COUNT];
|
||||
|
||||
bool pinInvalid(pin_size_t pinNumber) {
|
||||
return pinNumber < 0 || pinNumber >= PINS_COUNT || g_APinDescription[pinNumber].pinname == NC;
|
||||
}
|
||||
|
||||
void pinRemoveMode(pin_size_t pinNumber) {
|
||||
if (pinInvalid(pinNumber))
|
||||
return;
|
||||
if (g_APinDescription[pinNumber].ulPinType == PIO_PWM) {
|
||||
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber];
|
||||
pwmout_free(obj);
|
||||
}
|
||||
if (g_APinDescription[pinNumber].ulPinType == PIO_GPIO) {
|
||||
gpio_t *obj = (gpio_t *)gpio_pin_struct[pinNumber];
|
||||
gpio_deinit(obj, g_APinDescription[pinNumber].pinname);
|
||||
free(obj);
|
||||
}
|
||||
if (g_APinDescription[pinNumber].ulPinType == PIO_GPIO_IRQ) {
|
||||
gpio_irq_t *obj = (gpio_irq_t *)gpio_pin_struct[pinNumber];
|
||||
gpio_irq_deinit(obj);
|
||||
free(obj);
|
||||
}
|
||||
gpio_pin_struct[pinNumber] = NULL;
|
||||
g_APinDescription[pinNumber].ulPinType = NOT_INITIAL;
|
||||
g_APinDescription[pinNumber].ulPinMode = NOT_INITIAL;
|
||||
}
|
||||
|
||||
void pinMode(pin_size_t pinNumber, PinModeArduino pinMode) {
|
||||
if (pinInvalid(pinNumber))
|
||||
return;
|
||||
|
||||
if (g_APinDescription[pinNumber].ulPinType == PIO_GPIO && g_APinDescription[pinNumber].ulPinMode == pinMode)
|
||||
// Nothing changes in pin mode
|
||||
return;
|
||||
|
||||
/* if (g_APinDescription[pinNumber].ulPinType == PIO_PWM) {
|
||||
// If this pin has been configured as PWM, then it cannot change to another mode
|
||||
return;
|
||||
} */
|
||||
|
||||
if (g_APinDescription[pinNumber].ulPinType != PIO_GPIO)
|
||||
// pin mode changes; deinit gpio and free memory
|
||||
pinRemoveMode(pinNumber);
|
||||
|
||||
gpio_t *gpio;
|
||||
|
||||
if (g_APinDescription[pinNumber].ulPinType == NOT_INITIAL) {
|
||||
// allocate memory if pin not used before
|
||||
gpio = malloc(sizeof(gpio_t));
|
||||
gpio_pin_struct[pinNumber] = gpio;
|
||||
gpio_init(gpio, g_APinDescription[pinNumber].pinname);
|
||||
g_APinDescription[pinNumber].ulPinType = PIO_GPIO;
|
||||
} else {
|
||||
// pin already used as gpio
|
||||
gpio = (gpio_t *)gpio_pin_struct[pinNumber];
|
||||
}
|
||||
g_APinDescription[pinNumber].ulPinMode = pinMode;
|
||||
|
||||
PinDirection dir;
|
||||
PinMode mode;
|
||||
|
||||
switch (pinMode) {
|
||||
case INPUT:
|
||||
dir = PIN_INPUT;
|
||||
mode = PullNone;
|
||||
break;
|
||||
case INPUT_PULLDOWN:
|
||||
dir = PIN_INPUT;
|
||||
mode = PullDown;
|
||||
break;
|
||||
case INPUT_PULLUP:
|
||||
dir = PIN_INPUT;
|
||||
mode = PullUp;
|
||||
break;
|
||||
case OUTPUT:
|
||||
dir = PIN_OUTPUT;
|
||||
mode = PullNone;
|
||||
break;
|
||||
case OUTPUT_OPENDRAIN:
|
||||
dir = PIN_OUTPUT;
|
||||
mode = OpenDrain;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_dir(gpio, dir);
|
||||
gpio_mode(gpio, mode);
|
||||
}
|
||||
|
||||
void digitalWrite(pin_size_t pinNumber, PinStatus status) {
|
||||
if (pinInvalid(pinNumber))
|
||||
return;
|
||||
if (g_APinDescription[pinNumber].ulPinType != PIO_GPIO)
|
||||
return;
|
||||
|
||||
gpio_t *gpio = (gpio_t *)gpio_pin_struct[pinNumber];
|
||||
gpio_write(gpio, status);
|
||||
}
|
||||
|
||||
PinStatus digitalRead(pin_size_t pinNumber) {
|
||||
if (pinInvalid(pinNumber))
|
||||
return;
|
||||
if (g_APinDescription[pinNumber].ulPinType != PIO_GPIO)
|
||||
return;
|
||||
|
||||
gpio_t *gpio = (gpio_t *)gpio_pin_struct[pinNumber];
|
||||
return gpio_read(gpio);
|
||||
}
|
||||
|
||||
/**************************** Extend API by RTK ***********************************/
|
||||
|
||||
uint32_t digitalPinToPort(uint32_t pinNumber) {
|
||||
if (pinInvalid(pinNumber))
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
uint32_t pin_name = HAL_GPIO_GetPinName(g_APinDescription[pinNumber].pinname);
|
||||
return HAL_GPIO_GET_PORT_BY_NAME(pin_name);
|
||||
}
|
||||
|
||||
uint32_t digitalPinToBitMask(uint32_t pinNumber) {
|
||||
if (pinInvalid(pinNumber))
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
uint32_t pin_name = HAL_GPIO_GetPinName(g_APinDescription[pinNumber].pinname);
|
||||
return 1 << (HAL_GPIO_GET_PIN_BY_NAME(pin_name));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,118 +0,0 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "wiring_os.h"
|
||||
#include "cmsis_os.h"
|
||||
|
||||
uint32_t os_thread_create( void (*task)(const void *argument), void *argument, int priority, uint32_t stack_size ) {
|
||||
|
||||
osThreadDef_t thread_def;
|
||||
|
||||
thread_def.pthread = task;
|
||||
thread_def.tpriority = (osPriority)priority;
|
||||
// the underlying freertos implementation on cmsis os divide stack size by 4
|
||||
thread_def.stacksize = stack_size * 4;
|
||||
thread_def.name = "ARDUINO";
|
||||
|
||||
return (uint32_t)osThreadCreate(&thread_def, argument);
|
||||
}
|
||||
|
||||
uint32_t os_thread_get_id( void ) {
|
||||
return osThreadGetId();
|
||||
}
|
||||
|
||||
uint32_t os_thread_terminate( uint32_t thread_id ) {
|
||||
return (uint32_t)osThreadTerminate(thread_id);
|
||||
}
|
||||
|
||||
uint32_t os_thread_yield( void ) {
|
||||
return (uint32_t)osThreadYield();
|
||||
}
|
||||
|
||||
uint32_t os_thread_set_priority( uint32_t thread_id, int priority ) {
|
||||
return (uint32_t)osThreadSetPriority(thread_id, (osPriority)priority);
|
||||
}
|
||||
|
||||
int os_thread_get_priority( uint32_t thread_id ) {
|
||||
return (int)osThreadGetPriority(thread_id);
|
||||
}
|
||||
|
||||
int32_t os_signal_set( uint32_t thread_id, int32_t signals ) {
|
||||
return osSignalSet(thread_id, signals);
|
||||
}
|
||||
|
||||
int32_t os_signal_clear( uint32_t thread_id, int32_t signals ) {
|
||||
return osSignalClear(thread_id, signals);
|
||||
}
|
||||
|
||||
os_event_t os_signal_wait( int32_t signals, uint32_t millisec ) {
|
||||
|
||||
osEvent evt;
|
||||
os_event_t ret;
|
||||
|
||||
evt = osSignalWait(signals, millisec);
|
||||
ret.status = (uint32_t)evt.status;
|
||||
ret.value.signals = evt.value.signals;
|
||||
ret.def.message_id = evt.def.message_id;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef void (*os_ptimer) (void const *argument);
|
||||
|
||||
uint32_t os_timer_create(void (*callback)(void const *argument), uint8_t isPeriodic, void *argument) {
|
||||
|
||||
osTimerDef_t *pTimerDef;
|
||||
|
||||
pTimerDef = (osTimerDef_t *) malloc ( sizeof(osTimerDef_t) );
|
||||
pTimerDef->ptimer = callback;
|
||||
pTimerDef->custom = (struct os_timer_custom *) malloc ( sizeof (struct os_timer_custom) );
|
||||
|
||||
return osTimerCreate(pTimerDef, (isPeriodic ? osTimerPeriodic : osTimerOnce), argument);
|
||||
}
|
||||
|
||||
uint32_t os_timer_start (uint32_t timer_id, uint32_t millisec) {
|
||||
return osTimerStart (timer_id, millisec);
|
||||
}
|
||||
|
||||
uint32_t os_timer_stop (uint32_t timer_id) {
|
||||
return osTimerStop(timer_id);
|
||||
}
|
||||
|
||||
uint32_t os_timer_delete(uint32_t timer_id) {
|
||||
|
||||
osTimerDef_t *pTimerDef;
|
||||
|
||||
pTimerDef = (osTimerDef_t *) pvTimerGetTimerID(timer_id);
|
||||
free (pTimerDef->custom);
|
||||
free (pTimerDef);
|
||||
|
||||
return osTimerDelete(timer_id);
|
||||
}
|
||||
|
||||
uint32_t os_semaphore_create(int32_t count) {
|
||||
return (uint32_t)osSemaphoreCreate(NULL, count);
|
||||
}
|
||||
|
||||
int32_t os_semaphore_wait(uint32_t semaphore_id, uint32_t millisec) {
|
||||
if (osSemaphoreWait((osSemaphoreId)semaphore_id, millisec) == 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t os_semaphore_release(uint32_t semaphore_id) {
|
||||
return (uint32_t)osSemaphoreRelease((osSemaphoreId)semaphore_id);
|
||||
}
|
||||
|
||||
uint32_t os_semaphore_delete(uint32_t semaphore_id) {
|
||||
return (uint32_t)osSemaphoreDelete((osSemaphoreId)semaphore_id);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,310 +0,0 @@
|
||||
/** @file wiring_os.h */
|
||||
|
||||
/**
|
||||
* @defgroup wiring_os wiring_os
|
||||
* OS realted function for thread, signal, software timer, semaphore
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _WIRING_OS_H_
|
||||
#define _WIRING_OS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @defgroup os_status os_status
|
||||
* Redefinition from enum osStatus
|
||||
* @{
|
||||
*/
|
||||
/** function completed; no error or event occurred. */
|
||||
#define OS_OK 0x00
|
||||
/** function completed; signal event occurred. */
|
||||
#define OS_EVENT_SIGNAL 0x08
|
||||
/** function completed; message event occurred. */
|
||||
#define OS_EVENT_MESSAGE 0x10
|
||||
/** function completed; mail event occurred. */
|
||||
#define OS_EVENT_MAIL 0x20
|
||||
/** function completed; timeout occurred. */
|
||||
#define OS_EVENT_TIMEOUT 0x40
|
||||
/** parameter error: a mandatory parameter was missing or specified an incorrect object. */
|
||||
#define OS_ERROR_PARAMETER 0x80
|
||||
/** resource not available: a specified resource was not available. */
|
||||
#define OS_ERROR_RESOURCE 0x81
|
||||
/** resource not available within given time: a specified resource was not available within the timeout period. */
|
||||
#define OS_ERROR_TIMEOUT_RESOURCE 0xC1
|
||||
/** not allowed in ISR context: the function cannot be called from interrupt service routines. */
|
||||
#define OS_ERROR_ISR 0x82
|
||||
/** function called multiple times from ISR with same object. */
|
||||
#define OS_ERROR_ISR_RECURSIVE 0x83
|
||||
/** system cannot determine priority or thread has illegal priority. */
|
||||
#define OS_ERROR_PRIORITY 0x84
|
||||
/** system is out of memory: it was impossible to allocate or reserve memory for the operation. */
|
||||
#define OS_ERROR_NO_MEMORY 0x85
|
||||
/** value of a parameter is out of range. */
|
||||
#define OS_ERROR_VALUE 0x86
|
||||
/** unspecified RTOS error: run-time error but no other error message fits. */
|
||||
#define OS_ERROR_OS 0xFF
|
||||
/** @} */ // end of group os_status
|
||||
|
||||
/**
|
||||
* @defgroup os_priority os_priority
|
||||
* Redefinition from enum osPriority
|
||||
* @{
|
||||
*/
|
||||
/** priority: idle (lowest) */
|
||||
#define OS_PRIORITY_IDLE (-3)
|
||||
/** priority: low */
|
||||
#define OS_PRIORITY_LOW (-2)
|
||||
/** priority: below normal */
|
||||
#define OS_PRIORITY_BELOW_NORMAL (-1)
|
||||
/** priority: normal (default) */
|
||||
#define OS_PRIORITY_NORMAL ( 0)
|
||||
/** priority: above normal */
|
||||
#define OS_PRIORITY_ABOVENORMAL (+1)
|
||||
/** priority: high */
|
||||
#define OS_PRIORITY_HIGH (+2)
|
||||
/** priority: realtime (highest) */
|
||||
#define OS_PRIORITY_REALTIME (+3)
|
||||
/** @} */ // end of group os_priority
|
||||
|
||||
#ifndef DEFAULT_STACK_SIZE
|
||||
/**
|
||||
* @ingroup wiring_os
|
||||
* @brief default stack size
|
||||
*
|
||||
* It is suggest that thread is assigned stack size more than DEFAULT_STACK_SIZE
|
||||
*/
|
||||
#define DEFAULT_STACK_SIZE 512
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup wiring_os
|
||||
* @struct os_event_t
|
||||
* Redefine osEvent in cmsis_os.h
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t status; ///< status code: event or error information
|
||||
union {
|
||||
uint32_t v; ///< message as 32-bit value
|
||||
void *p; ///< message or mail as void pointer
|
||||
int32_t signals; ///< signal flags
|
||||
} value; ///< event value
|
||||
union {
|
||||
void *mail_id; ///< mail id obtained by osMailCreate
|
||||
void *message_id; ///< message id obtained by osMessageCreate
|
||||
} def; ///< event definition
|
||||
} os_event_t;
|
||||
|
||||
/**
|
||||
* @defgroup thread_management thread_management
|
||||
* Thread management include create, get thread id, terminate, yield, and set/get priority
|
||||
**/
|
||||
|
||||
/**
|
||||
* @ingroup thread_management
|
||||
* @brief Create a thread and add it to Active Threads and set it to state READY.
|
||||
*
|
||||
* @param[in] task Function pointer which is the thread body. It should not run into the end of function unless os_thread_terminate is invoked
|
||||
* @param[in] argument the data pointer which brings to task
|
||||
* @param[in] priority The underlying os is FreeRTOS. It executes tasks with highest priority which are not in idle state.\n
|
||||
* If there are more than 2 tasks to be executed, then they share the time slice.
|
||||
* @param[in] stack_size The stack_size is used as memory heap only for this task. \n
|
||||
* The local variables and call stacks would occupy this heap. Please make sure the the stack_size is big enough to avoid curroption
|
||||
* @return The thread id which is used in thread operation and signaling.
|
||||
*/
|
||||
extern uint32_t os_thread_create(void (*task)(const void *argument), void *argument, int priority, uint32_t stack_size);
|
||||
|
||||
/**
|
||||
* @ingroup thread_management
|
||||
* @brief Return the thread ID of the current running thread.
|
||||
*
|
||||
* @return Current thread id which calls os_thread_get_id
|
||||
*/
|
||||
extern uint32_t os_thread_get_id( void );
|
||||
|
||||
/**
|
||||
* @ingroup thread_management
|
||||
* @brief Terminate execution of a thread and remove it from Active Threads.
|
||||
*
|
||||
* Thread should not ended without terminate first
|
||||
*
|
||||
* @param[in] thread_id Terminate the thread with specific thread_id
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_thread_terminate(uint32_t thread_id);
|
||||
|
||||
/**
|
||||
* @ingroup thread_management
|
||||
* @brief Pass control to next thread that is in state \b READY.
|
||||
*
|
||||
* By default the minimal execution unit is 1 millisecond. In a scenario that if a thread with smaller want to handout execution right to a thread with
|
||||
* higher priority immediately without waiting for the ending of current 1 millisecond, then invoke os_thread_yield can transfer exection right to
|
||||
* OS's idle task and check which is the next execution thread.
|
||||
*
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_thread_yield(void);
|
||||
|
||||
/**
|
||||
* @ingroup thread_management
|
||||
* @brief Change priority of an active thread.
|
||||
*
|
||||
* @param[in] thread_id The target thread with the thread id to be changed
|
||||
* @param[in] priority The updated priority
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_thread_set_priority(uint32_t thread_id, int priority);
|
||||
|
||||
/**
|
||||
* @ingroup thread_management
|
||||
* @brief Get current priority of an active thread.
|
||||
*
|
||||
* @param[in] thread_id The target thread with the thread id to be searched
|
||||
* @return os_priority
|
||||
*/
|
||||
extern int os_thread_get_priority(uint32_t thread_id);
|
||||
|
||||
/**
|
||||
* @defgroup signal_management signal_management
|
||||
* Signaling between threads include set, clear, and wait
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup signal_management
|
||||
* @brief Set the specified Signal Flags of an active thread.
|
||||
*
|
||||
* @param[in] thread_id Send signal to a thread with the thread id
|
||||
* @param[in] signals the signals to be send
|
||||
* @return os_status code
|
||||
*/
|
||||
extern int32_t os_signal_set(uint32_t thread_id, int32_t signals);
|
||||
|
||||
/**
|
||||
* @ingroup signal_management
|
||||
* @brief Clear the specified Signal Flags of an active thread.
|
||||
*
|
||||
* @param[in] thread_id Clear signal to a thread with the thread id
|
||||
* @param[in] signals The signals to be clear
|
||||
* @return os_status code
|
||||
*/
|
||||
extern int32_t os_signal_clear(uint32_t thread_id, int32_t signals);
|
||||
|
||||
/**
|
||||
* @ingroup signal_management
|
||||
* @brief Wait for one or more Signal Flags to become signaled for the current \b RUNNING thread.
|
||||
*
|
||||
* @param[in] signals the signals to be wait
|
||||
* @param[in] millisec the timeout value if no signal comes in. Fill in 0xFFFFFFFF for infinite wait.
|
||||
* @return os_status code
|
||||
*/
|
||||
extern os_event_t os_signal_wait(int32_t signals, uint32_t millisec);
|
||||
|
||||
/**
|
||||
* @defgroup timer_management timer_management
|
||||
* Software timer management include create, start, stop, delete.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup timer_management
|
||||
* @brief specify timer type that invoke only once
|
||||
*/
|
||||
#define OS_TIMER_ONCE (0)
|
||||
|
||||
/**
|
||||
* @ingroup timer_management
|
||||
* @brief specify timer type that invoke periodically
|
||||
*/
|
||||
#define OS_TIMER_PERIODIC (1)
|
||||
|
||||
/**
|
||||
* @ingroup timer_management
|
||||
* @brief Create a timer.
|
||||
*
|
||||
* @param[in] callback The function to be invoke when timer timeout
|
||||
* @param[in] isPeriodic \b OS_TIMER_ONCE or \b OS_TIMER_PERIODIC
|
||||
* @param[in] argument The argument that is bring into callback function
|
||||
* @return timer id
|
||||
*/
|
||||
extern uint32_t os_timer_create(void (*callback)(void const *argument), uint8_t isPeriodic, void *argument);
|
||||
|
||||
/**
|
||||
* @ingroup timer_management
|
||||
* @brief Start or restart a timer.
|
||||
*
|
||||
* @param[in] timer_id The timer id obtained from by os_timer_create
|
||||
* @param[in] millisec The delays after timer starts
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_timer_start (uint32_t timer_id, uint32_t millisec);
|
||||
|
||||
/**
|
||||
* @ingroup timer_management
|
||||
* @brief Stop the timer.
|
||||
*
|
||||
* @param[in] timer_id The timer id obtained from by os_timer_create
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_timer_stop (uint32_t timer_id);
|
||||
|
||||
/**
|
||||
* @ingroup timer_management
|
||||
* @brief Delete a timer that was created by os_timer_create
|
||||
*
|
||||
* @param[in] timer_id The timer id obtained from by os_timer_create
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_timer_delete(uint32_t timer_id);
|
||||
|
||||
/**
|
||||
* @defgroup semaphore_management semaphore_management
|
||||
* Semaphore API between threads include create, wait, release, delete.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup semaphore_management
|
||||
* @brief Create and Initialize a Semaphore object used for managing resources
|
||||
*
|
||||
* @param[in] count The number of available resources
|
||||
* @return semaphore ID
|
||||
*/
|
||||
extern uint32_t os_semaphore_create(int32_t count);
|
||||
|
||||
/**
|
||||
* @ingroup semaphore_management
|
||||
* @brief Wait until a Semaphore token becomes available
|
||||
*
|
||||
* @param[in] semaphore_id semaphore id obtained from os_semaphore_create
|
||||
* @param[in] millisec timeout value
|
||||
* @return os_status code
|
||||
*/
|
||||
extern int32_t os_semaphore_wait(uint32_t semaphore_id, uint32_t millisec);
|
||||
|
||||
/**
|
||||
* @ingroup semaphore_management
|
||||
* @brief Release a Semaphore token
|
||||
*
|
||||
* @param[in] semaphore_id semaphore id obtained from os_semaphore_create
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_semaphore_release(uint32_t semaphore_id);
|
||||
|
||||
/**
|
||||
* @ingroup semaphore_management
|
||||
* @brief Delete a Semaphore that was created by os_semaphore_create.
|
||||
*
|
||||
* @param[in] semaphore_id semaphore id obtained from os_semaphore_create
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_semaphore_delete(uint32_t semaphore_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */ // end of group wiring_os
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
uint8_t shiftIn(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder)
|
||||
{
|
||||
uint8_t value = 0 ;
|
||||
uint8_t i ;
|
||||
|
||||
for ( i=0 ; i < 8 ; ++i )
|
||||
{
|
||||
digitalWrite( dataPin, HIGH ) ;
|
||||
|
||||
if ( bitOrder == LSBFIRST )
|
||||
{
|
||||
value |= digitalRead( dataPin ) << i ;
|
||||
}
|
||||
else
|
||||
{
|
||||
value |= digitalRead( dataPin ) << (7 - i) ;
|
||||
}
|
||||
|
||||
digitalWrite( clockPin, LOW ) ;
|
||||
}
|
||||
|
||||
return value ;
|
||||
}
|
||||
|
||||
void shiftOut(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder, uint8_t val)
|
||||
{
|
||||
uint8_t i ;
|
||||
|
||||
for ( i=0 ; i < 8 ; i++ )
|
||||
{
|
||||
if ( bitOrder == LSBFIRST )
|
||||
{
|
||||
digitalWrite( dataPin, !!(val & (1 << i)) ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite( dataPin, !!(val & (1 << (7 - i))) ) ;
|
||||
}
|
||||
|
||||
digitalWrite( clockPin, HIGH ) ;
|
||||
digitalWrite( clockPin, LOW ) ;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -1,37 +0,0 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "wdt_api.h"
|
||||
|
||||
extern uint32_t ConfigDebugErr;
|
||||
|
||||
void wdt_reset() {
|
||||
watchdog_refresh();
|
||||
}
|
||||
|
||||
void wdt_enable(uint32_t timeout_ms) {
|
||||
|
||||
uint32_t backup_ConfigDebugErr;
|
||||
|
||||
backup_ConfigDebugErr = ConfigDebugErr;
|
||||
ConfigDebugErr = 0x00000000;
|
||||
|
||||
if (timeout_ms > 8000) {
|
||||
timeout_ms = 8000;
|
||||
}
|
||||
watchdog_init(timeout_ms);
|
||||
watchdog_start();
|
||||
|
||||
ConfigDebugErr = backup_ConfigDebugErr;
|
||||
}
|
||||
|
||||
void wdt_disable() {
|
||||
watchdog_stop();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -1,46 +0,0 @@
|
||||
/** @file wiring_watchdog.h */
|
||||
|
||||
/**
|
||||
* @defgroup wiring_watchdog wiring_watchdog
|
||||
* watchdog is used for reboot system when device hang
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _WIRING_WATCHDOG_H_
|
||||
#define _WIRING_WATCHDOG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @defgroup watchdog */
|
||||
|
||||
/**
|
||||
* @ingroup watchdog
|
||||
* Feed watchdog to avoid it barks
|
||||
*/
|
||||
extern void wdt_reset();
|
||||
|
||||
/**
|
||||
* @ingroup watchdog
|
||||
* @brief Enable watchdog
|
||||
*
|
||||
* After enbling watchdog, user defined code needs to reset it before watchdog barks. Otherwise it would make system reboot.
|
||||
*
|
||||
* @param[in] timeout_ms The timeout value that watchdog barks. The maximum value is 8 seconds.
|
||||
*/
|
||||
extern void wdt_enable(uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @ingroup watchdog
|
||||
* Disable watchdog
|
||||
*/
|
||||
extern void wdt_disable();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _WIRING_WATCHDOG_H_ */
|
||||
|
||||
/** @} */ // end of group wiring_watchdog
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
wl_definitions.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
/*
|
||||
* wl_definitions.h
|
||||
*
|
||||
* Created on: Mar 6, 2011
|
||||
* Author: dlafauci
|
||||
*/
|
||||
|
||||
#ifndef WL_DEFINITIONS_H_
|
||||
#define WL_DEFINITIONS_H_
|
||||
|
||||
// Maximum size of a SSID
|
||||
#define WL_SSID_MAX_LENGTH 32
|
||||
// Length of passphrase. Valid lengths are 8-63.
|
||||
#define WL_WPA_KEY_MAX_LENGTH 63
|
||||
// Length of key in bytes. Valid values are 5 and 13.
|
||||
#define WL_WEP_KEY_MAX_LENGTH 13
|
||||
// Size of a MAC-address or BSSID
|
||||
#define WL_MAC_ADDR_LENGTH 6
|
||||
// Size of a MAC-address or BSSID
|
||||
#define WL_IPV4_LENGTH 4
|
||||
// Maximum size of a SSID list
|
||||
#define WL_NETWORKS_LIST_MAXNUM 50
|
||||
// Maxmium number of socket
|
||||
#define MAX_SOCK_NUM 4
|
||||
// Socket not available constant
|
||||
#define SOCK_NOT_AVAIL 255
|
||||
// Default state value for Wifi state field
|
||||
#define NA_STATE -1
|
||||
//Maximum number of attempts to establish wifi connection
|
||||
#define WL_MAX_ATTEMPT_CONNECTION 10
|
||||
|
||||
typedef enum {
|
||||
WL_NO_SHIELD = 255,
|
||||
WL_IDLE_STATUS = 0,
|
||||
WL_NO_SSID_AVAIL,
|
||||
WL_SCAN_COMPLETED,
|
||||
WL_CONNECTED,
|
||||
WL_CONNECT_FAILED,
|
||||
WL_CONNECTION_LOST,
|
||||
WL_DISCONNECTED
|
||||
} wl_status_t;
|
||||
|
||||
/* Encryption modes */
|
||||
enum wl_enc_type { /* Values map to 802.11 encryption suites... */
|
||||
ENC_TYPE_WEP = 5,
|
||||
ENC_TYPE_TKIP = 2,
|
||||
ENC_TYPE_CCMP = 4,
|
||||
/* ... except these two, 7 and 8 are reserved in 802.11-2007 */
|
||||
ENC_TYPE_NONE = 7,
|
||||
ENC_TYPE_AUTO = 8
|
||||
};
|
||||
|
||||
/* RTK added type */
|
||||
#ifndef WEP_ENABLED
|
||||
|
||||
#define WEP_ENABLED 0x0001
|
||||
#define TKIP_ENABLED 0x0002
|
||||
#define AES_ENABLED 0x0004
|
||||
#define WSEC_SWFLAG 0x0008
|
||||
|
||||
#define SHARED_ENABLED 0x00008000
|
||||
#define WPA_SECURITY 0x00200000
|
||||
#define WPA2_SECURITY 0x00400000
|
||||
#define WPS_ENABLED 0x10000000
|
||||
|
||||
#endif // #ifndef WEP_ENABLED
|
||||
|
||||
/* redefined from enum rtw_security_t */
|
||||
#define SECURITY_OPEN ( 0 )
|
||||
#define SECURITY_WEP_PSK ( WEP_ENABLED )
|
||||
#define SECURITY_WEP_SHARED ( WEP_ENABLED | SHARED_ENABLED )
|
||||
#define SECURITY_WPA_TKIP_PSK ( WPA_SECURITY | TKIP_ENABLED )
|
||||
#define SECURITY_WPA_AES_PSK ( WPA_SECURITY | AES_ENABLED )
|
||||
#define SECURITY_WPA2_AES_PSK ( WPA2_SECURITY | AES_ENABLED )
|
||||
#define SECURITY_WPA2_TKIP_PSK ( WPA2_SECURITY | TKIP_ENABLED )
|
||||
#define SECURITY_WPA2_MIXED_PSK ( WPA2_SECURITY | AES_ENABLED | TKIP_ENABLED )
|
||||
#define SECURITY_WPA_WPA2_MIXED ( WPA_SECURITY | WPA2_SECURITY )
|
||||
|
||||
|
||||
#endif /* WL_DEFINITIONS_H_ */
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
wl_types.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
/*
|
||||
* wl_types.h
|
||||
*
|
||||
* Created on: Jul 30, 2010
|
||||
* Author: dlafauci
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _WL_TYPES_H_
|
||||
#define _WL_TYPES_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef enum {
|
||||
WL_FAILURE = -1,
|
||||
WL_SUCCESS = 1,
|
||||
} wl_error_code_t;
|
||||
|
||||
/* Authentication modes */
|
||||
enum wl_auth_mode {
|
||||
AUTH_MODE_INVALID,
|
||||
AUTH_MODE_AUTO,
|
||||
AUTH_MODE_OPEN_SYSTEM,
|
||||
AUTH_MODE_SHARED_KEY,
|
||||
AUTH_MODE_WPA,
|
||||
AUTH_MODE_WPA2,
|
||||
AUTH_MODE_WPA_PSK,
|
||||
AUTH_MODE_WPA2_PSK
|
||||
};
|
||||
|
||||
#endif //_WL_TYPES_H_
|
||||
@@ -1,108 +0,0 @@
|
||||
#ifndef WSCLIENT_H
|
||||
#define WSCLIENT_H
|
||||
#include <websocket/libwsclient.h>
|
||||
|
||||
|
||||
/******Define the maximum bytes of data send and receive********/
|
||||
#define MAX_DATA_LEN 1500
|
||||
/****************Define if using the polarssl*******************/
|
||||
#define USING_SSL
|
||||
|
||||
|
||||
/******************Define the function used*********************/
|
||||
#ifdef USING_SSL
|
||||
int wss_set_fun_ops(wsclient_context *wsclient);
|
||||
#define wsclient_set_fun_ops(wsclient) wss_set_fun_ops(wsclient)
|
||||
#else
|
||||
int ws_set_fun_ops(wsclient_context *wsclient);
|
||||
#define wsclient_set_fun_ops(wsclient) ws_set_fun_ops(wsclient)
|
||||
#endif
|
||||
/***************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : create_wsclient
|
||||
** Description : Creating the websocket client context structure
|
||||
** Input : url:websocket server's url
|
||||
** port:websocket server's port, if not given, default 80 for "ws", 443 for "wss"
|
||||
** origin: the address or url of your self
|
||||
** Return : Created: websocket client context structure
|
||||
** Failed: NULL
|
||||
**************************************************************************************************/
|
||||
wsclient_context *create_wsclient(char *url, int port,char *path, char* origin);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : ws_connect_url
|
||||
** Description : Connecting to the websocket server
|
||||
** Input : wsclient: the websocket client context created by create_wsclientfunction
|
||||
** Return : Connected: the socket value
|
||||
** Failed: -1
|
||||
**************************************************************************************************/
|
||||
int ws_connect_url(wsclient_context *wsclient);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : ws_send
|
||||
** Description : Create the sending string data and copy to tx_buf
|
||||
** Input : message: the string that send to server(cannot exceeding the MAX_DATA_LEN
|
||||
** message_len: the length of the string
|
||||
** use_mask: 0/1; 1 means using mask for bynary
|
||||
** wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void ws_send(char* message, int message_len, int use_mask, wsclient_context *wsclient);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : ws_sendBinary
|
||||
** Description : Create the sending binary data and copy to tx_buf
|
||||
** Input : message: the binary that send to server(cannot exceeding the MAX_DATA_LEN
|
||||
** message_len: the length of the binary
|
||||
** use_mask: 0/1; 1 means using mask for bynary
|
||||
** wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void ws_sendBinary(uint8_t* message, int message_len, int use_mask, wsclient_context *wsclient);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : ws_sendPing
|
||||
** Description : Sending Ping to websocket server
|
||||
** Input : wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void ws_sendPing(wsclient_context *wsclient);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : ws_poll
|
||||
** Description : Receicing data from server and send the data in tx_buf
|
||||
** Input : timeout(in milliseconds)
|
||||
wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void ws_poll(int timeout, wsclient_context *wsclient);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : ws_dispatch
|
||||
** Description : callback function when getting message from server
|
||||
** Input : function that resolve the message received and the message length
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void ws_dispatch(void (*callback)(wsclient_context *, int)) ;
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : ws_getReadyState
|
||||
** Description : Getting the connection status
|
||||
** Input : wsclient: the websocket client context
|
||||
** Return : readyStateValues(4 types:CLOSING, CLOSED, CONNECTING, OPEN)
|
||||
**************************************************************************************************/
|
||||
readyStateValues ws_getReadyState(wsclient_context *wsclient);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : ws_close
|
||||
** Description : Closing the connection with websocket server
|
||||
** Input : wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void ws_close(wsclient_context *wsclient);
|
||||
|
||||
#endif
|
||||
@@ -1,69 +0,0 @@
|
||||
#include "Flash.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include <flash_api.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
FlashClass::FlashClass() {
|
||||
flash = NULL;
|
||||
}
|
||||
|
||||
FlashClass::~FlashClass() {
|
||||
if (!flash)
|
||||
return;
|
||||
free(flash);
|
||||
flash = NULL;
|
||||
}
|
||||
|
||||
void FlashClass::initialize() {
|
||||
if (flash)
|
||||
return;
|
||||
flash = (flash_t *)malloc(sizeof(flash_t));
|
||||
flash_get_status(flash);
|
||||
}
|
||||
|
||||
FlashId FlashClass::getChipId() {
|
||||
initialize();
|
||||
FlashId id;
|
||||
uint8_t idBytes[3];
|
||||
flash_read_id(flash, idBytes, 3);
|
||||
id.manufacturerId = idBytes[0];
|
||||
id.chipId = idBytes[1];
|
||||
id.chipSizeId = idBytes[2];
|
||||
return id;
|
||||
}
|
||||
|
||||
uint32_t FlashClass::getSize() {
|
||||
initialize();
|
||||
FlashId id = getChipId();
|
||||
if (id.chipSizeId >= 0x14 && id.chipSizeId <= 0x19) {
|
||||
return (1 << id.chipSizeId);
|
||||
}
|
||||
return 1024 * 1024;
|
||||
}
|
||||
|
||||
bool FlashClass::eraseSector(uint32_t offset) {
|
||||
initialize();
|
||||
flash_erase_sector(flash, offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FlashClass::readBlock(uint32_t offset, uint8_t *data, size_t size) {
|
||||
initialize();
|
||||
return flash_stream_read(flash, offset, size, data);
|
||||
}
|
||||
|
||||
bool FlashClass::writeBlock(uint32_t offset, uint8_t *data, size_t size) {
|
||||
initialize();
|
||||
return flash_stream_write(flash, offset, size, data);
|
||||
}
|
||||
|
||||
FlashClass Flash;
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "api/Flash.h"
|
||||
|
||||
struct flash_s;
|
||||
typedef struct flash_s flash_t;
|
||||
|
||||
class FlashClass : public IFlashClass {
|
||||
private:
|
||||
flash_t *flash;
|
||||
void initialize();
|
||||
|
||||
public:
|
||||
FlashClass();
|
||||
~FlashClass();
|
||||
|
||||
FlashId getChipId();
|
||||
uint32_t getSize();
|
||||
|
||||
bool eraseSector(uint32_t offset);
|
||||
bool readBlock(uint32_t offset, uint8_t *data, size_t size);
|
||||
bool writeBlock(uint32_t offset, uint8_t *data, size_t size);
|
||||
};
|
||||
|
||||
extern FlashClass Flash;
|
||||
@@ -1,94 +0,0 @@
|
||||
#include "WiFi.h"
|
||||
#include "WiFiPriv.h"
|
||||
|
||||
rtw_network_info_t wifi = {0};
|
||||
rtw_ap_info_t ap = {0};
|
||||
rtw_wifi_setting_t wifi_setting;
|
||||
unsigned char sta_password[65] = {0};
|
||||
unsigned char ap_password[65] = {0};
|
||||
|
||||
void reset_wifi_struct(void) {
|
||||
memset(wifi.ssid.val, 0, sizeof(wifi.ssid.val));
|
||||
memset(wifi.bssid.octet, 0, ETH_ALEN);
|
||||
memset(sta_password, 0, sizeof(sta_password));
|
||||
memset(ap_password, 0, sizeof(ap_password));
|
||||
wifi.ssid.len = 0;
|
||||
wifi.password = NULL;
|
||||
wifi.password_len = 0;
|
||||
wifi.key_id = -1;
|
||||
memset(ap.ssid.val, 0, sizeof(ap.ssid.val));
|
||||
ap.ssid.len = 0;
|
||||
ap.password = NULL;
|
||||
ap.password_len = 0;
|
||||
ap.channel = 1;
|
||||
}
|
||||
|
||||
WiFiClass::WiFiClass() {
|
||||
_scanSem = xSemaphoreCreateBinary();
|
||||
}
|
||||
|
||||
WiFiClass::~WiFiClass() {
|
||||
vSemaphoreDelete(_scanSem);
|
||||
}
|
||||
|
||||
void WiFiClass::printDiag(Print &dest) {
|
||||
const char *modes[] = {"NULL", "STA", "AP", "STA+AP"};
|
||||
const char *enc[] = {"Open", "WEP", "WPA PSK", "WPA2 PSK", "WPA/WPA2", "WPA", "WPA2"};
|
||||
|
||||
dest.print("Mode: ");
|
||||
dest.println(modes[getMode()]);
|
||||
|
||||
if (wifi_mode & WIFI_MODE_STA) {
|
||||
dest.println("-- Station --");
|
||||
dest.print("SSID: ");
|
||||
dest.println(SSID());
|
||||
if (isConnected()) {
|
||||
dest.print("BSSID: ");
|
||||
dest.println(BSSIDstr());
|
||||
dest.print("RSSI: ");
|
||||
dest.println(RSSI());
|
||||
dest.print("Encryption: ");
|
||||
dest.println(enc[getEncryption()]);
|
||||
dest.print("IP: ");
|
||||
dest.println(localIP());
|
||||
dest.print("MAC: ");
|
||||
dest.println(macAddress());
|
||||
dest.print("Hostname: ");
|
||||
dest.println(getHostname());
|
||||
}
|
||||
}
|
||||
|
||||
if (wifi_mode & WIFI_MODE_AP) {
|
||||
dest.println("-- Access Point --");
|
||||
dest.print("SSID: ");
|
||||
dest.println(softAPSSID());
|
||||
dest.print("IP: ");
|
||||
dest.println(softAPIP());
|
||||
dest.print("MAC: ");
|
||||
dest.println(softAPmacAddress());
|
||||
dest.print("Hostname: ");
|
||||
dest.println(softAPgetHostname());
|
||||
}
|
||||
}
|
||||
|
||||
WiFiAuthMode WiFiClass::securityTypeToAuthMode(uint8_t type) {
|
||||
switch (wifi_setting.security_type) {
|
||||
case RTW_SECURITY_OPEN:
|
||||
return WIFI_AUTH_OPEN;
|
||||
case RTW_SECURITY_WEP_SHARED:
|
||||
return WIFI_AUTH_WEP;
|
||||
case RTW_SECURITY_WPA_TKIP_PSK:
|
||||
return WIFI_AUTH_WPA_PSK;
|
||||
case RTW_SECURITY_WPA_AES_PSK:
|
||||
return WIFI_AUTH_WPA;
|
||||
case RTW_SECURITY_WPA2_TKIP_PSK:
|
||||
return WIFI_AUTH_WPA2_PSK;
|
||||
case RTW_SECURITY_WPA2_AES_PSK:
|
||||
return WIFI_AUTH_WPA2;
|
||||
case RTW_SECURITY_WPA_WPA2_MIXED:
|
||||
return WIFI_AUTH_WPA_WPA2_PSK;
|
||||
}
|
||||
return WIFI_AUTH_INVALID;
|
||||
}
|
||||
|
||||
WiFiClass WiFi;
|
||||
@@ -1,180 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <api/WiFi.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <semphr.h>
|
||||
#include <wifi_structures.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#include "WiFiClient.h"
|
||||
#include "WiFiServer.h"
|
||||
|
||||
class WiFiClass : public IWiFiClass,
|
||||
public IWiFiGenericClass,
|
||||
public IWiFiSTAClass,
|
||||
public IWiFiScanClass,
|
||||
public IWiFiAPClass {
|
||||
private:
|
||||
static WiFiAuthMode securityTypeToAuthMode(uint8_t type);
|
||||
|
||||
bool _initialized;
|
||||
bool _sleep;
|
||||
|
||||
bool _scanning = false;
|
||||
SemaphoreHandle_t _scanSem;
|
||||
uint8_t _netCount = 0;
|
||||
char **_netSsid = NULL;
|
||||
WiFiAuthMode *_netEncr = NULL;
|
||||
int32_t *_netRssi = NULL;
|
||||
rtw_mac_t *_netBssid = NULL;
|
||||
int32_t *_netChannel = NULL;
|
||||
|
||||
static rtw_result_t scanHandler(rtw_scan_handler_result_t *result);
|
||||
|
||||
public:
|
||||
// IWiFiClass
|
||||
WiFiClass();
|
||||
~WiFiClass();
|
||||
void printDiag(Print &dest);
|
||||
|
||||
public:
|
||||
// IWiFiGenericClass
|
||||
int32_t channel(void);
|
||||
|
||||
bool mode(WiFiMode mode) override;
|
||||
WiFiMode getMode();
|
||||
WiFiStatus status();
|
||||
|
||||
bool enableSTA(bool enable);
|
||||
bool enableAP(bool enable);
|
||||
|
||||
bool setSleep(bool enable);
|
||||
bool getSleep();
|
||||
|
||||
bool setTxPower(int power);
|
||||
int getTxPower();
|
||||
|
||||
IPAddress hostByName(const char *hostname);
|
||||
|
||||
static IPAddress calculateNetworkID(IPAddress ip, IPAddress subnet);
|
||||
static IPAddress calculateBroadcast(IPAddress ip, IPAddress subnet);
|
||||
static uint8_t calculateSubnetCIDR(IPAddress subnetMask);
|
||||
static String macToString(uint8_t *mac);
|
||||
|
||||
public:
|
||||
// IWiFiSTAClass
|
||||
WiFiStatus begin(
|
||||
const char *ssid,
|
||||
const char *passphrase = NULL,
|
||||
int32_t channel = 0,
|
||||
const uint8_t *bssid = NULL,
|
||||
bool connect = true
|
||||
) override;
|
||||
WiFiStatus
|
||||
begin(char *ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t *bssid = NULL, bool connect = true);
|
||||
|
||||
bool config(
|
||||
IPAddress localIP,
|
||||
IPAddress gateway,
|
||||
IPAddress subnet,
|
||||
IPAddress dns1 = (uint32_t)0x00000000,
|
||||
IPAddress dns2 = (uint32_t)0x00000000
|
||||
);
|
||||
|
||||
inline bool reconnect() {
|
||||
return reconnect(NULL);
|
||||
}
|
||||
|
||||
bool reconnect(const uint8_t *bssid = NULL);
|
||||
bool disconnect(bool wifiOff = false);
|
||||
|
||||
bool isConnected() override;
|
||||
|
||||
bool setAutoReconnect(bool autoReconnect);
|
||||
bool getAutoReconnect();
|
||||
|
||||
WiFiStatus waitForConnectResult(unsigned long timeout);
|
||||
|
||||
IPAddress localIP();
|
||||
uint8_t *macAddress(uint8_t *mac);
|
||||
String macAddress();
|
||||
IPAddress subnetMask();
|
||||
IPAddress gatewayIP();
|
||||
IPAddress dnsIP(uint8_t dns_no);
|
||||
IPAddress broadcastIP();
|
||||
IPAddress networkID();
|
||||
uint8_t subnetCIDR();
|
||||
bool enableIpV6();
|
||||
IPv6Address localIPv6();
|
||||
const char *getHostname();
|
||||
bool setHostname(const char *hostname);
|
||||
bool setMacAddress(const uint8_t *mac);
|
||||
|
||||
const String SSID();
|
||||
const String psk();
|
||||
uint8_t *BSSID();
|
||||
String BSSIDstr();
|
||||
int8_t RSSI();
|
||||
WiFiAuthMode getEncryption();
|
||||
|
||||
public:
|
||||
// IWiFiScanClass
|
||||
int16_t scanNetworks(
|
||||
bool async = false,
|
||||
bool showHidden = false,
|
||||
bool passive = false,
|
||||
uint32_t maxMsPerChannel = 300,
|
||||
uint8_t channel = 0
|
||||
);
|
||||
bool getNetworkInfo(
|
||||
uint8_t networkItem,
|
||||
String &ssid,
|
||||
WiFiAuthMode &encryptionType,
|
||||
int32_t &RSSI,
|
||||
uint8_t *&BSSID,
|
||||
int32_t &channel
|
||||
);
|
||||
|
||||
int16_t scanComplete();
|
||||
void scanDelete();
|
||||
|
||||
String SSID(uint8_t networkItem);
|
||||
WiFiAuthMode encryptionType(uint8_t networkItem);
|
||||
int32_t RSSI(uint8_t networkItem);
|
||||
uint8_t *BSSID(uint8_t networkItem);
|
||||
String BSSIDstr(uint8_t networkItem);
|
||||
int32_t channel(uint8_t networkItem);
|
||||
|
||||
public:
|
||||
// IWiFiAPClass
|
||||
bool softAP(
|
||||
const char *ssid, const char *passphrase = NULL, int channel = 1, bool ssidHidden = false, int maxClients = 4
|
||||
);
|
||||
bool softAPConfig(IPAddress localIP, IPAddress gateway, IPAddress subnet);
|
||||
bool softAPdisconnect(bool wifiOff = false);
|
||||
|
||||
uint8_t softAPgetStationNum();
|
||||
|
||||
IPAddress softAPIP();
|
||||
IPAddress softAPBroadcastIP();
|
||||
IPAddress softAPNetworkID();
|
||||
uint8_t softAPSubnetCIDR();
|
||||
bool softAPenableIpV6();
|
||||
IPv6Address softAPIPv6();
|
||||
const char *softAPgetHostname();
|
||||
bool softAPsetHostname(const char *hostname);
|
||||
uint8_t *softAPmacAddress(uint8_t *mac);
|
||||
String softAPmacAddress(void);
|
||||
const String softAPSSID(void);
|
||||
};
|
||||
|
||||
extern WiFiClass WiFi;
|
||||
@@ -1,162 +0,0 @@
|
||||
#include "WiFi.h"
|
||||
#include "WiFiPriv.h"
|
||||
|
||||
bool WiFiClass::softAP(const char *ssid, const char *passphrase, int channel, bool ssidHidden, int maxClients) {
|
||||
if (!enableAP(true))
|
||||
return false;
|
||||
|
||||
vTaskDelay(20);
|
||||
|
||||
if (!ssid || *ssid == 0x00 || strlen(ssid) > 32) {
|
||||
LT_W("SSID not specified or too long");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (passphrase && strlen(passphrase) < 8) {
|
||||
LT_W("Passphrase too short");
|
||||
return false;
|
||||
}
|
||||
|
||||
strcpy((char *)ap.ssid.val, ssid);
|
||||
ap.ssid.len = strlen(ssid);
|
||||
ap.channel = channel;
|
||||
|
||||
ap.security_type = RTW_SECURITY_OPEN;
|
||||
ap.password = NULL;
|
||||
ap.password_len = 0;
|
||||
|
||||
if (passphrase) {
|
||||
strcpy((char *)ap_password, passphrase);
|
||||
ap.security_type = RTW_SECURITY_WPA2_AES_PSK;
|
||||
ap.password = ap_password;
|
||||
ap.password_len = strlen(passphrase);
|
||||
}
|
||||
|
||||
dhcps_deinit();
|
||||
|
||||
LT_I("Creating SoftAP %s", ssid);
|
||||
|
||||
int ret;
|
||||
if (!ssidHidden) {
|
||||
ret = wifi_start_ap(
|
||||
(char *)ap.ssid.val,
|
||||
ap.security_type,
|
||||
(char *)ap.password,
|
||||
ap.ssid.len,
|
||||
ap.password_len,
|
||||
ap.channel
|
||||
);
|
||||
} else {
|
||||
ret = wifi_start_ap_with_hidden_ssid(
|
||||
(char *)ap.ssid.val,
|
||||
ap.security_type,
|
||||
(char *)ap.password,
|
||||
ap.ssid.len,
|
||||
ap.password_len,
|
||||
ap.channel
|
||||
);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
LT_E("SoftAP failed; ret=%d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t timeout = 20;
|
||||
unsigned char essid[33];
|
||||
|
||||
const char *ifname = NETNAME_AP;
|
||||
struct netif *ifs = NETIF_RTW_AP;
|
||||
|
||||
while (1) {
|
||||
if (wext_get_ssid(ifname, essid) > 0) {
|
||||
if (strcmp((const char *)essid, (const char *)ap.ssid.val) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!timeout)
|
||||
return false;
|
||||
|
||||
vTaskDelay(1 * configTICK_RATE_HZ);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
dhcps_init(ifs);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WiFiClass::softAPConfig(IPAddress localIP, IPAddress gateway, IPAddress subnet) {
|
||||
if (!enableAP(true))
|
||||
return false;
|
||||
struct netif *ifs = NETIF_RTW_AP;
|
||||
struct ip_addr ipaddr, netmask, gw;
|
||||
ipaddr.addr = localIP;
|
||||
netmask.addr = subnet;
|
||||
gw.addr = gateway;
|
||||
netif_set_addr(ifs, &ipaddr, &netmask, &gw);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WiFiClass::softAPdisconnect(bool wifiOff) {
|
||||
// TODO implement wifi_restart_ap
|
||||
if (wifiOff)
|
||||
return enableAP(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t WiFiClass::softAPgetStationNum() {
|
||||
// TODO
|
||||
// the struct is at wifi_conf.c:2576
|
||||
return 0;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::softAPIP() {
|
||||
return LwIP_GetIP(NETIF_RTW_AP);
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::softAPBroadcastIP() {
|
||||
return calculateBroadcast(softAPIP(), LwIP_GetMASK(NETIF_RTW_AP));
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::softAPNetworkID() {
|
||||
return calculateNetworkID(softAPIP(), LwIP_GetMASK(NETIF_RTW_AP));
|
||||
}
|
||||
|
||||
uint8_t WiFiClass::softAPSubnetCIDR() {
|
||||
return calculateSubnetCIDR(LwIP_GetMASK(NETIF_RTW_AP));
|
||||
}
|
||||
|
||||
bool WiFiClass::softAPenableIpV6() {
|
||||
return false;
|
||||
}
|
||||
|
||||
IPv6Address WiFiClass::softAPIPv6() {
|
||||
return IPv6Address();
|
||||
}
|
||||
|
||||
const char *WiFiClass::softAPgetHostname() {
|
||||
return netif_get_hostname(NETIF_RTW_AP);
|
||||
}
|
||||
|
||||
bool WiFiClass::softAPsetHostname(const char *hostname) {
|
||||
netif_set_hostname(NETIF_RTW_AP, (char *)hostname);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t *WiFiClass::softAPmacAddress(uint8_t *mac) {
|
||||
uint8_t *macLocal = LwIP_GetMAC(NETIF_RTW_AP);
|
||||
memcpy(mac, macLocal, ETH_ALEN);
|
||||
free(macLocal);
|
||||
return mac;
|
||||
}
|
||||
|
||||
String WiFiClass::softAPmacAddress(void) {
|
||||
uint8_t mac[ETH_ALEN];
|
||||
macAddress(mac);
|
||||
return macToString(mac);
|
||||
}
|
||||
|
||||
const String WiFiClass::softAPSSID(void) {
|
||||
wifi_get_setting(NETNAME_AP, &wifi_setting);
|
||||
return (char *)wifi_setting.ssid;
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
#include "WiFi.h"
|
||||
#include "WiFiPriv.h"
|
||||
|
||||
int32_t WiFiClass::channel() {
|
||||
int channel;
|
||||
wifi_get_channel(&channel);
|
||||
return channel;
|
||||
}
|
||||
|
||||
bool WiFiClass::mode(WiFiMode mode) {
|
||||
WiFiMode currentMode = getMode();
|
||||
LT_D_WG("Mode changing %u -> %u", currentMode, mode);
|
||||
if (mode == currentMode)
|
||||
return true;
|
||||
|
||||
if (!currentMode && mode && !_initialized) {
|
||||
// initialize wifi first
|
||||
LT_I("Initializing LwIP");
|
||||
LwIP_Init();
|
||||
reset_wifi_struct();
|
||||
// wifi_manager_init(); // these are events!
|
||||
_initialized = true;
|
||||
}
|
||||
if (currentMode) {
|
||||
// stop wifi to change mode
|
||||
LT_D_WG("Stopping WiFi to change mode");
|
||||
if (wifi_off() != RTW_SUCCESS)
|
||||
return false;
|
||||
vTaskDelay(20);
|
||||
if (mode == WIFI_MODE_NULL)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wifi_on((rtw_mode_t)mode) != RTW_SUCCESS) {
|
||||
LT_E("Error while changing mode(%u)", mode);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
WiFiMode WiFiClass::getMode() {
|
||||
if (!_initialized)
|
||||
return WIFI_MODE_NULL;
|
||||
return (WiFiMode)wifi_mode;
|
||||
}
|
||||
|
||||
WiFiStatus WiFiClass::status() {
|
||||
if (wifi_is_connected_to_ap() == 0) {
|
||||
return WL_CONNECTED;
|
||||
} else {
|
||||
return WL_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
bool WiFiClass::enableSTA(bool enable) {
|
||||
WiFiMode currentMode = getMode();
|
||||
if (((currentMode & WIFI_MODE_STA) != 0) != enable) {
|
||||
return mode((WiFiMode)(currentMode ^ WIFI_MODE_STA));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WiFiClass::enableAP(bool enable) {
|
||||
WiFiMode currentMode = getMode();
|
||||
if (((currentMode & WIFI_MODE_AP) != 0) != enable) {
|
||||
return mode((WiFiMode)(currentMode ^ WIFI_MODE_AP));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WiFiClass::setSleep(bool enable) {
|
||||
LT_D_WG("WiFi sleep mode %u", enable);
|
||||
if (enable)
|
||||
if (wifi_enable_powersave() != RTW_SUCCESS)
|
||||
return false;
|
||||
else if (wifi_disable_powersave() != RTW_SUCCESS)
|
||||
return false;
|
||||
_sleep = enable;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WiFiClass::getSleep() {
|
||||
return _sleep;
|
||||
}
|
||||
|
||||
bool WiFiClass::setTxPower(int power) {
|
||||
return false; // wifi_set_txpower(power) == RTW_SUCCESS;
|
||||
}
|
||||
|
||||
int WiFiClass::getTxPower() {
|
||||
return 0;
|
||||
int power = 0;
|
||||
wifi_get_txpower(&power);
|
||||
return power;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::hostByName(const char *hostname) {
|
||||
ip_addr_t ip;
|
||||
int ret = netconn_gethostbyname(hostname, &ip);
|
||||
if (ret == ERR_OK) {
|
||||
return ip.addr;
|
||||
}
|
||||
return IPAddress();
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::calculateNetworkID(IPAddress ip, IPAddress subnet) {
|
||||
IPAddress networkID;
|
||||
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
networkID[i] = subnet[i] & ip[i];
|
||||
|
||||
return networkID;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::calculateBroadcast(IPAddress ip, IPAddress subnet) {
|
||||
IPAddress broadcastIp;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
broadcastIp[i] = ~subnet[i] | ip[i];
|
||||
|
||||
return broadcastIp;
|
||||
}
|
||||
|
||||
uint8_t WiFiClass::calculateSubnetCIDR(IPAddress subnetMask) {
|
||||
uint8_t CIDR = 0;
|
||||
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
if (subnetMask[i] == 0x80) // 128
|
||||
CIDR += 1;
|
||||
else if (subnetMask[i] == 0xC0) // 192
|
||||
CIDR += 2;
|
||||
else if (subnetMask[i] == 0xE0) // 224
|
||||
CIDR += 3;
|
||||
else if (subnetMask[i] == 0xF0) // 242
|
||||
CIDR += 4;
|
||||
else if (subnetMask[i] == 0xF8) // 248
|
||||
CIDR += 5;
|
||||
else if (subnetMask[i] == 0xFC) // 252
|
||||
CIDR += 6;
|
||||
else if (subnetMask[i] == 0xFE) // 254
|
||||
CIDR += 7;
|
||||
else if (subnetMask[i] == 0xFF) // 255
|
||||
CIDR += 8;
|
||||
}
|
||||
|
||||
return CIDR;
|
||||
}
|
||||
|
||||
String WiFiClass::macToString(uint8_t *mac) {
|
||||
char macStr[ETH_ALEN * 3];
|
||||
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
return macStr;
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
// these are defined in PIO builder (for IDE to understand)
|
||||
#define LWIP_TIMEVAL_PRIVATE 0
|
||||
#define LWIP_NETIF_HOSTNAME 1
|
||||
// this should define all errno values, as well as the extern int
|
||||
#define LWIP_PROVIDE_ERRNO 1
|
||||
#define LWIP_SO_RCVBUF 1
|
||||
|
||||
#define MAX_SOCK_NUM 4
|
||||
#define WIFI_CLIENT_CONNECT_TIMEOUT 3000
|
||||
#define WIFI_CLIENT_READ_TIMEOUT 3000
|
||||
#define WIFI_CLIENT_WRITE_RETRY 10
|
||||
#define WIFI_CLIENT_SELECT_TIMEOUT 1000
|
||||
#define WIFI_CLIENT_FLUSH_BUF_SIZE 1024
|
||||
|
||||
// I think I don't understand how that works.
|
||||
// For some reason, LwIP uses a different (extern) errno,
|
||||
// while this macro refers to a function __errno, which
|
||||
// reads a totally different variable.
|
||||
#undef errno
|
||||
#include <lwip/arch.h>
|
||||
|
||||
// disable #defines removing lwip_ prefix
|
||||
#undef LWIP_COMPAT_SOCKETS
|
||||
#define LWIP_COMPAT_SOCKETS 0
|
||||
#include <lwip/sockets.h>
|
||||
|
||||
#include <autoconf.h>
|
||||
#include <dhcp/dhcps.h>
|
||||
#include <lwip/api.h>
|
||||
#include <lwip/dns.h>
|
||||
#include <lwip/err.h>
|
||||
#include <lwip_netconf.h>
|
||||
#include <sys/time.h>
|
||||
#include <wifi_conf.h>
|
||||
#include <wifi_constants.h>
|
||||
#include <wifi_structures.h>
|
||||
|
||||
extern struct netif xnetif[NET_IF_NUM];
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "WiFi.h"
|
||||
|
||||
extern rtw_network_info_t wifi;
|
||||
extern rtw_ap_info_t ap;
|
||||
extern rtw_wifi_setting_t wifi_setting;
|
||||
extern unsigned char sta_password[65];
|
||||
extern unsigned char ap_password[65];
|
||||
extern void reset_wifi_struct(void);
|
||||
extern rtw_mode_t wifi_mode;
|
||||
|
||||
#define NETIF_RTW_STA &xnetif[RTW_STA_INTERFACE]
|
||||
#define NETIF_RTW_AP (wifi_mode == WIFI_MODE_APSTA ? &xnetif[RTW_AP_INTERFACE] : NETIF_RTW_STA)
|
||||
|
||||
#define NETNAME_STA WLAN0_NAME
|
||||
#define NETNAME_AP (wifi_mode == WIFI_MODE_APSTA ? WLAN1_NAME : WLAN0_NAME)
|
||||
@@ -1,235 +0,0 @@
|
||||
#include "WiFi.h"
|
||||
#include "WiFiPriv.h"
|
||||
|
||||
WiFiStatus WiFiClass::begin(char *ssid, char *passphrase, int32_t channel, const uint8_t *bssid, bool connect) {
|
||||
return begin((const char *)ssid, (const char *)passphrase, channel, bssid, connect);
|
||||
}
|
||||
|
||||
WiFiStatus
|
||||
WiFiClass::begin(const char *ssid, const char *passphrase, int32_t channel, const uint8_t *bssid, bool connect) {
|
||||
if (!enableSTA(true))
|
||||
return WL_CONNECT_FAILED;
|
||||
|
||||
if (!ssid || *ssid == 0x00 || strlen(ssid) > 32) {
|
||||
LT_W("SSID not specified or too long");
|
||||
return WL_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
if (passphrase && strlen(passphrase) > 64) {
|
||||
LT_W("Passphrase too long");
|
||||
return WL_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
memset(wifi.bssid.octet, 0, ETH_ALEN);
|
||||
strcpy((char *)wifi.ssid.val, ssid);
|
||||
wifi.ssid.len = strlen(ssid);
|
||||
|
||||
wifi.security_type = RTW_SECURITY_OPEN;
|
||||
wifi.password = NULL;
|
||||
wifi.password_len = 0;
|
||||
wifi.key_id = 0;
|
||||
|
||||
if (passphrase) {
|
||||
strcpy((char *)sta_password, passphrase);
|
||||
wifi.security_type = RTW_SECURITY_WPA2_AES_PSK;
|
||||
wifi.password = sta_password;
|
||||
wifi.password_len = strlen(passphrase);
|
||||
}
|
||||
|
||||
if (reconnect(bssid))
|
||||
return WL_CONNECTED;
|
||||
else
|
||||
return WL_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
bool WiFiClass::config(IPAddress localIP, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2) {
|
||||
if (!enableSTA(true))
|
||||
return false;
|
||||
struct netif *ifs = NETIF_RTW_STA;
|
||||
struct ip_addr ipaddr, netmask, gw, d1, d2;
|
||||
ipaddr.addr = localIP;
|
||||
netmask.addr = subnet;
|
||||
gw.addr = gateway;
|
||||
d1.addr = dns1;
|
||||
d2.addr = dns2;
|
||||
netif_set_addr(ifs, &ipaddr, &netmask, &gw);
|
||||
if (dns1[0])
|
||||
dns_setserver(0, &d1);
|
||||
if (dns2[0])
|
||||
dns_setserver(0, &d2);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WiFiClass::reconnect(const uint8_t *bssid) {
|
||||
int ret;
|
||||
uint8_t dhcpRet;
|
||||
|
||||
LT_I("Connecting to %s", wifi.ssid.val);
|
||||
|
||||
if (!bssid) {
|
||||
ret = wifi_connect(
|
||||
(char *)wifi.ssid.val,
|
||||
wifi.security_type,
|
||||
(char *)wifi.password,
|
||||
wifi.ssid.len,
|
||||
wifi.password_len,
|
||||
wifi.key_id,
|
||||
NULL
|
||||
);
|
||||
} else {
|
||||
ret = wifi_connect_bssid(
|
||||
(unsigned char *)bssid,
|
||||
(char *)wifi.ssid.val,
|
||||
wifi.security_type,
|
||||
(char *)wifi.password,
|
||||
ETH_ALEN,
|
||||
wifi.ssid.len,
|
||||
wifi.password_len,
|
||||
wifi.key_id,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
if (ret == RTW_SUCCESS) {
|
||||
dhcpRet = LwIP_DHCP(0, DHCP_START);
|
||||
if (dhcpRet == DHCP_ADDRESS_ASSIGNED)
|
||||
return true;
|
||||
LT_E("DHCP failed; dhcpRet=%d", dhcpRet);
|
||||
wifi_disconnect();
|
||||
return false;
|
||||
}
|
||||
LT_E("Connection failed; ret=%d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WiFiClass::disconnect(bool wifiOff) {
|
||||
int ret = wifi_disconnect();
|
||||
if (wifiOff)
|
||||
enableSTA(false);
|
||||
return ret == RTW_SUCCESS;
|
||||
}
|
||||
|
||||
bool WiFiClass::isConnected() {
|
||||
return status() == WL_CONNECTED;
|
||||
}
|
||||
|
||||
bool WiFiClass::setAutoReconnect(bool autoReconnect) {
|
||||
return wifi_set_autoreconnect(autoReconnect) == RTW_SUCCESS;
|
||||
}
|
||||
|
||||
bool WiFiClass::getAutoReconnect() {
|
||||
bool autoReconnect;
|
||||
wifi_get_autoreconnect((uint8_t *)&autoReconnect);
|
||||
return autoReconnect;
|
||||
}
|
||||
|
||||
WiFiStatus WiFiClass::waitForConnectResult(unsigned long timeout) {
|
||||
if ((wifi_mode & WIFI_MODE_STA) == 0) {
|
||||
return WL_DISCONNECTED;
|
||||
}
|
||||
unsigned long start = millis();
|
||||
while ((!status() || status() >= WL_DISCONNECTED) && (millis() - start) < timeout) {
|
||||
delay(100);
|
||||
}
|
||||
return status();
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::localIP() {
|
||||
if (!wifi_mode)
|
||||
return IPAddress();
|
||||
return LwIP_GetIP(NETIF_RTW_STA);
|
||||
}
|
||||
|
||||
uint8_t *WiFiClass::macAddress(uint8_t *mac) {
|
||||
uint8_t *macLocal = LwIP_GetMAC(NETIF_RTW_STA);
|
||||
memcpy(mac, macLocal, ETH_ALEN);
|
||||
free(macLocal);
|
||||
return mac;
|
||||
}
|
||||
|
||||
String WiFiClass::macAddress(void) {
|
||||
uint8_t mac[ETH_ALEN];
|
||||
macAddress(mac);
|
||||
return macToString(mac);
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::subnetMask() {
|
||||
return LwIP_GetMASK(NETIF_RTW_STA);
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::gatewayIP() {
|
||||
return LwIP_GetGW(NETIF_RTW_STA);
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::dnsIP(uint8_t dns_no) {
|
||||
struct ip_addr dns;
|
||||
LwIP_GetDNS(&dns);
|
||||
return dns.addr;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::broadcastIP() {
|
||||
return LwIP_GetBC(NETIF_RTW_STA);
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::networkID() {
|
||||
return calculateNetworkID(gatewayIP(), subnetMask());
|
||||
}
|
||||
|
||||
uint8_t WiFiClass::subnetCIDR() {
|
||||
return calculateSubnetCIDR(subnetMask());
|
||||
}
|
||||
|
||||
bool WiFiClass::enableIpV6() {
|
||||
return false;
|
||||
}
|
||||
|
||||
IPv6Address WiFiClass::localIPv6() {
|
||||
return IPv6Address();
|
||||
}
|
||||
|
||||
const char *WiFiClass::getHostname() {
|
||||
return netif_get_hostname(NETIF_RTW_STA);
|
||||
}
|
||||
|
||||
bool WiFiClass::setHostname(const char *hostname) {
|
||||
netif_set_hostname(NETIF_RTW_STA, (char *)hostname);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WiFiClass::setMacAddress(const uint8_t *mac) {
|
||||
return wifi_set_mac_address((char *)mac) == RTW_SUCCESS;
|
||||
}
|
||||
|
||||
const String WiFiClass::SSID() {
|
||||
if (!isConnected())
|
||||
return "";
|
||||
wifi_get_setting(NETNAME_STA, &wifi_setting);
|
||||
return (char *)wifi_setting.ssid;
|
||||
}
|
||||
|
||||
const String WiFiClass::psk() {
|
||||
if (!isConnected() || !wifi.password)
|
||||
return "";
|
||||
return (char *)wifi.password;
|
||||
}
|
||||
|
||||
uint8_t *WiFiClass::BSSID() {
|
||||
uint8_t bssid[ETH_ALEN];
|
||||
wext_get_bssid(NETNAME_STA, bssid);
|
||||
return bssid;
|
||||
}
|
||||
|
||||
String WiFiClass::BSSIDstr() {
|
||||
return macToString(BSSID());
|
||||
}
|
||||
|
||||
int8_t WiFiClass::RSSI() {
|
||||
int rssi = 0;
|
||||
wifi_get_rssi(&rssi);
|
||||
return rssi;
|
||||
}
|
||||
|
||||
WiFiAuthMode WiFiClass::getEncryption() {
|
||||
wifi_get_setting(NETNAME_STA, &wifi_setting);
|
||||
return WiFiClass::securityTypeToAuthMode(wifi_setting.security_type);
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
#include "WiFi.h"
|
||||
#include "WiFiPriv.h"
|
||||
|
||||
rtw_result_t WiFiClass::scanHandler(rtw_scan_handler_result_t *result) {
|
||||
WiFiClass *cls = (WiFiClass *)result->user_data;
|
||||
|
||||
if (result->scan_complete == RTW_TRUE) {
|
||||
cls->_scanning = false;
|
||||
xSemaphoreGive(cls->_scanSem);
|
||||
return RTW_SUCCESS;
|
||||
}
|
||||
|
||||
rtw_scan_result_t *net = &result->ap_details;
|
||||
net->SSID.val[net->SSID.len] = '\0';
|
||||
|
||||
uint8_t newSize = cls->_netCount + 1;
|
||||
cls->_netSsid = (char **)realloc(cls->_netSsid, newSize * sizeof(char *));
|
||||
cls->_netEncr = (WiFiAuthMode *)realloc(cls->_netEncr, newSize * sizeof(WiFiAuthMode));
|
||||
cls->_netRssi = (int32_t *)realloc(cls->_netRssi, newSize * sizeof(int32_t));
|
||||
cls->_netBssid = (rtw_mac_t *)realloc(cls->_netBssid, newSize * sizeof(rtw_mac_t));
|
||||
cls->_netChannel = (int32_t *)realloc(cls->_netChannel, newSize * sizeof(int32_t));
|
||||
|
||||
cls->_netSsid[cls->_netCount] = (char *)malloc((net->SSID.len + 1) * sizeof(char));
|
||||
strcpy(cls->_netSsid[cls->_netCount], (char *)net->SSID.val);
|
||||
cls->_netEncr[cls->_netCount] = WiFiClass::securityTypeToAuthMode(net->security);
|
||||
cls->_netRssi[cls->_netCount] = net->signal_strength;
|
||||
memcpy(cls->_netBssid[cls->_netCount].octet, net->BSSID.octet, ETH_ALEN);
|
||||
cls->_netChannel[cls->_netCount] = net->channel;
|
||||
cls->_netCount++;
|
||||
|
||||
return RTW_SUCCESS;
|
||||
}
|
||||
|
||||
int16_t WiFiClass::scanNetworks(bool async, bool showHidden, bool passive, uint32_t maxMsPerChannel, uint8_t channel) {
|
||||
if (_scanning)
|
||||
return WIFI_SCAN_RUNNING;
|
||||
scanDelete();
|
||||
|
||||
if (wifi_scan_networks(scanHandler, this) != RTW_SUCCESS)
|
||||
return WIFI_SCAN_FAILED;
|
||||
|
||||
_scanning = true;
|
||||
|
||||
if (!async) {
|
||||
xSemaphoreTake(_scanSem, 1); // reset the semaphore quickly
|
||||
xSemaphoreTake(_scanSem, pdMS_TO_TICKS(maxMsPerChannel * 20));
|
||||
return _netCount;
|
||||
}
|
||||
return WIFI_SCAN_RUNNING;
|
||||
}
|
||||
|
||||
bool WiFiClass::getNetworkInfo(
|
||||
uint8_t networkItem, String &ssid, WiFiAuthMode &encType, int32_t &rssi, uint8_t *&bssid, int32_t &channel
|
||||
) {
|
||||
ssid = SSID(networkItem);
|
||||
encType = encryptionType(networkItem);
|
||||
rssi = RSSI(networkItem);
|
||||
bssid = BSSID(networkItem);
|
||||
channel = this->channel(networkItem);
|
||||
}
|
||||
|
||||
int16_t WiFiClass::scanComplete() {
|
||||
if (_scanning)
|
||||
return WIFI_SCAN_RUNNING;
|
||||
return _netCount;
|
||||
}
|
||||
|
||||
void WiFiClass::scanDelete() {
|
||||
for (uint8_t i = 0; i < _netCount; i++) {
|
||||
free(_netSsid[i]);
|
||||
}
|
||||
free(_netSsid);
|
||||
free(_netEncr);
|
||||
free(_netRssi);
|
||||
free(_netBssid);
|
||||
free(_netChannel);
|
||||
_netCount = 0;
|
||||
_netSsid = NULL;
|
||||
_netEncr = NULL;
|
||||
_netRssi = NULL;
|
||||
_netBssid = NULL;
|
||||
_netChannel = NULL;
|
||||
}
|
||||
|
||||
String WiFiClass::SSID(uint8_t networkItem) {
|
||||
if (networkItem >= _netCount)
|
||||
return "";
|
||||
return _netSsid[networkItem];
|
||||
}
|
||||
|
||||
WiFiAuthMode WiFiClass::encryptionType(uint8_t networkItem) {
|
||||
if (networkItem >= _netCount)
|
||||
return WIFI_AUTH_INVALID;
|
||||
return _netEncr[networkItem];
|
||||
}
|
||||
|
||||
int32_t WiFiClass::RSSI(uint8_t networkItem) {
|
||||
if (networkItem >= _netCount)
|
||||
return 0;
|
||||
return _netRssi[networkItem];
|
||||
}
|
||||
|
||||
uint8_t *WiFiClass::BSSID(uint8_t networkItem) {
|
||||
if (networkItem >= _netCount)
|
||||
return NULL;
|
||||
return _netBssid[networkItem].octet;
|
||||
}
|
||||
|
||||
String WiFiClass::BSSIDstr(uint8_t networkItem) {
|
||||
return macToString(BSSID(networkItem));
|
||||
}
|
||||
|
||||
int32_t WiFiClass::channel(uint8_t networkItem) {
|
||||
if (networkItem >= _netCount)
|
||||
return 0;
|
||||
return _netChannel[networkItem];
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFiServer.h>
|
||||
|
||||
#include "WiFiClient.h"
|
||||
|
||||
class WiFiServer : public IWiFiServer<WiFiClient> {
|
||||
private:
|
||||
int _sock;
|
||||
int _sockAccepted;
|
||||
uint16_t _port;
|
||||
uint8_t _maxClients;
|
||||
bool _active;
|
||||
bool _noDelay = false;
|
||||
|
||||
public:
|
||||
WiFiServer(uint16_t port = 80, uint8_t maxClients = 4);
|
||||
|
||||
operator bool();
|
||||
|
||||
bool begin(uint16_t port = 0, bool reuseAddr = true);
|
||||
void end();
|
||||
WiFiClient accept();
|
||||
|
||||
size_t write(const uint8_t *buffer, size_t size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stopAll() {}
|
||||
|
||||
int setTimeout(uint32_t seconds);
|
||||
void setNoDelay(bool noDelay);
|
||||
bool getNoDelay();
|
||||
bool hasClient();
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
name=WiFi
|
||||
version=1.0.1
|
||||
author=Realtek
|
||||
maintainer=Realtek <ameba.arduino@gmail.com>
|
||||
sentence=Enables network connection (local and Internet).
|
||||
paragraph=With this library you can instantiate Servers, Clients and send/receive UDP packets through WiFi.
|
||||
category=Communication
|
||||
url=http://www.amebaiot.com/ameba-arduino-peripherals-examples/
|
||||
architectures=Ameba1
|
||||
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
WiFi.cpp - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "WiFi.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "wifi_drv.h"
|
||||
|
||||
WiFiClass::WiFiClass() {
|
||||
}
|
||||
|
||||
void WiFiClass::init() {
|
||||
WiFiDrv::wifiDriverInit();
|
||||
}
|
||||
|
||||
char* WiFiClass::firmwareVersion() {
|
||||
return WiFiDrv::getFwVersion();
|
||||
}
|
||||
|
||||
int WiFiClass::begin(char* ssid) {
|
||||
uint8_t status = WL_IDLE_STATUS;
|
||||
|
||||
WiFiDrv::wifiDriverInit();
|
||||
|
||||
if (WiFiDrv::wifiSetNetwork(ssid, strlen(ssid)) != WL_FAILURE) {
|
||||
status = WiFiDrv::getConnectionStatus();
|
||||
} else {
|
||||
status = WL_CONNECT_FAILED;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int WiFiClass::begin(char* ssid, uint8_t key_idx, const char *key) {
|
||||
uint8_t status = WL_IDLE_STATUS;
|
||||
|
||||
WiFiDrv::wifiDriverInit();
|
||||
|
||||
// set encryption key
|
||||
if (WiFiDrv::wifiSetKey(ssid, strlen(ssid), key_idx, key, strlen(key)) != WL_FAILURE) {
|
||||
status = WiFiDrv::getConnectionStatus();
|
||||
} else {
|
||||
status = WL_CONNECT_FAILED;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int WiFiClass::begin(char* ssid, const char *passphrase) {
|
||||
uint8_t status = WL_IDLE_STATUS;
|
||||
|
||||
WiFiDrv::wifiDriverInit();
|
||||
|
||||
// set passphrase
|
||||
if (WiFiDrv::wifiSetPassphrase(ssid, strlen(ssid), passphrase, strlen(passphrase))!= WL_FAILURE) {
|
||||
status = WiFiDrv::getConnectionStatus();
|
||||
} else {
|
||||
status = WL_CONNECT_FAILED;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int WiFiClass::disconnect() {
|
||||
return WiFiDrv::disconnect();
|
||||
}
|
||||
|
||||
uint8_t* WiFiClass::macAddress(uint8_t* mac) {
|
||||
uint8_t* _mac = WiFiDrv::getMacAddress();
|
||||
memcpy(mac, _mac, WL_MAC_ADDR_LENGTH);
|
||||
return mac;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::localIP() {
|
||||
IPAddress ret;
|
||||
WiFiDrv::getIpAddress(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::subnetMask() {
|
||||
IPAddress ret;
|
||||
WiFiDrv::getSubnetMask(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::gatewayIP() {
|
||||
IPAddress ret;
|
||||
WiFiDrv::getGatewayIP(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* WiFiClass::SSID() {
|
||||
return WiFiDrv::getCurrentSSID();
|
||||
}
|
||||
|
||||
uint8_t* WiFiClass::BSSID(uint8_t* bssid) {
|
||||
uint8_t* _bssid = WiFiDrv::getCurrentBSSID();
|
||||
memcpy(bssid, _bssid, WL_MAC_ADDR_LENGTH);
|
||||
return bssid;
|
||||
}
|
||||
|
||||
int32_t WiFiClass::RSSI() {
|
||||
return WiFiDrv::getCurrentRSSI();
|
||||
}
|
||||
|
||||
uint8_t WiFiClass::encryptionType() {
|
||||
return WiFiDrv::getCurrentEncryptionType();
|
||||
}
|
||||
|
||||
|
||||
int8_t WiFiClass::scanNetworks() {
|
||||
uint8_t attempts = 10;
|
||||
uint8_t numOfNetworks = 0;
|
||||
|
||||
if (WiFiDrv::startScanNetworks() == WL_FAILURE) {
|
||||
return WL_FAILURE;
|
||||
}
|
||||
do {
|
||||
delay(2000);
|
||||
numOfNetworks = WiFiDrv::getScanNetworks();
|
||||
} while (( numOfNetworks == 0)&&(--attempts>0));
|
||||
return numOfNetworks;
|
||||
}
|
||||
|
||||
char* WiFiClass::SSID(uint8_t networkItem) {
|
||||
return WiFiDrv::getSSIDNetoworks(networkItem);
|
||||
}
|
||||
|
||||
int32_t WiFiClass::RSSI(uint8_t networkItem) {
|
||||
return WiFiDrv::getRSSINetoworks(networkItem);
|
||||
}
|
||||
|
||||
uint8_t WiFiClass::encryptionType(uint8_t networkItem) {
|
||||
return WiFiDrv::getEncTypeNetowrks(networkItem);
|
||||
}
|
||||
|
||||
uint32_t WiFiClass::encryptionTypeEx(uint8_t networkItem) {
|
||||
return WiFiDrv::getEncTypeNetowrksEx(networkItem);
|
||||
}
|
||||
|
||||
uint8_t WiFiClass::status() {
|
||||
return WiFiDrv::getConnectionStatus();
|
||||
}
|
||||
|
||||
int WiFiClass::hostByName(const char* aHostname, IPAddress& aResult) {
|
||||
return WiFiDrv::getHostByName(aHostname, aResult);
|
||||
}
|
||||
|
||||
int WiFiClass::apbegin(char* ssid, char* channel) {
|
||||
uint8_t status = WL_IDLE_STATUS;
|
||||
|
||||
if (WiFiDrv::apSetNetwork(ssid, strlen(ssid)) != WL_FAILURE) {
|
||||
WiFiDrv::apSetChannel(channel);
|
||||
|
||||
if (WiFiDrv::apActivate() != WL_FAILURE) {
|
||||
status = WL_CONNECTED;
|
||||
} else {
|
||||
status = WL_CONNECT_FAILED;
|
||||
}
|
||||
} else {
|
||||
status = WL_CONNECT_FAILED;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int WiFiClass::apbegin(char* ssid, char* password, char* channel) {
|
||||
uint8_t status = WL_IDLE_STATUS;
|
||||
|
||||
if (WiFiDrv::apSetNetwork(ssid, strlen(ssid)) != WL_FAILURE) {
|
||||
WiFiDrv::apSetPassphrase(password, strlen(password));
|
||||
WiFiDrv::apSetChannel(channel);
|
||||
|
||||
if(WiFiDrv::apActivate() != WL_FAILURE) {
|
||||
status = WL_CONNECTED;
|
||||
} else {
|
||||
status = WL_CONNECT_FAILED;
|
||||
}
|
||||
} else {
|
||||
status = WL_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int WiFiClass::disablePowerSave() {
|
||||
return WiFiDrv::disablePowerSave();
|
||||
}
|
||||
|
||||
WiFiClass WiFi;
|
||||
@@ -1,255 +0,0 @@
|
||||
/*
|
||||
WiFi.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef WiFi_h
|
||||
#define WiFi_h
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
extern "C" {
|
||||
#include "wl_definitions.h"
|
||||
#include "wl_types.h"
|
||||
}
|
||||
|
||||
#include "WiFiClient.h"
|
||||
#include "WiFiServer.h"
|
||||
#include "WiFiSSLClient.h"
|
||||
|
||||
class WiFiClass
|
||||
{
|
||||
private:
|
||||
static void init();
|
||||
|
||||
public:
|
||||
|
||||
WiFiClass();
|
||||
|
||||
/*
|
||||
* Get firmware version
|
||||
*/
|
||||
static char* firmwareVersion();
|
||||
|
||||
/* Start Wifi connection for OPEN networks
|
||||
*
|
||||
* param ssid: Pointer to the SSID string.
|
||||
*/
|
||||
int begin(char* ssid);
|
||||
|
||||
/* Start Wifi connection with WEP encryption.
|
||||
* Configure a key into the device. The key type (WEP-40, WEP-104)
|
||||
* is determined by the size of the key (5 bytes for WEP-40, 13 bytes for WEP-104).
|
||||
*
|
||||
* param ssid: Pointer to the SSID string.
|
||||
* param key_idx: The key index to set. Valid values are 0-3.
|
||||
* param key: Key input buffer.
|
||||
*/
|
||||
int begin(char* ssid, uint8_t key_idx, const char* key);
|
||||
|
||||
/* Start Wifi connection with passphrase
|
||||
* the most secure supported mode will be automatically selected
|
||||
*
|
||||
* param ssid: Pointer to the SSID string.
|
||||
* param passphrase: Passphrase. Valid characters in a passphrase
|
||||
* must be between ASCII 32-126 (decimal).
|
||||
*/
|
||||
int begin(char* ssid, const char *passphrase);
|
||||
|
||||
/* Change Ip configuration settings disabling the dhcp client
|
||||
*
|
||||
* param local_ip: Static ip configuration
|
||||
*/
|
||||
void config(IPAddress local_ip);
|
||||
|
||||
/* Change Ip configuration settings disabling the dhcp client
|
||||
*
|
||||
* param local_ip: Static ip configuration
|
||||
* param dns_server: IP configuration for DNS server 1
|
||||
*/
|
||||
void config(IPAddress local_ip, IPAddress dns_server);
|
||||
|
||||
/* Change Ip configuration settings disabling the dhcp client
|
||||
*
|
||||
* param local_ip: Static ip configuration
|
||||
* param dns_server: IP configuration for DNS server 1
|
||||
* param gateway : Static gateway configuration
|
||||
*/
|
||||
void config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway);
|
||||
|
||||
/* Change Ip configuration settings disabling the dhcp client
|
||||
*
|
||||
* param local_ip: Static ip configuration
|
||||
* param dns_server: IP configuration for DNS server 1
|
||||
* param gateway: Static gateway configuration
|
||||
* param subnet: Static Subnet mask
|
||||
*/
|
||||
void config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet);
|
||||
|
||||
/* Change DNS Ip configuration
|
||||
*
|
||||
* param dns_server1: ip configuration for DNS server 1
|
||||
*/
|
||||
void setDNS(IPAddress dns_server1);
|
||||
|
||||
/* Change DNS Ip configuration
|
||||
*
|
||||
* param dns_server1: ip configuration for DNS server 1
|
||||
* param dns_server2: ip configuration for DNS server 2
|
||||
*
|
||||
*/
|
||||
void setDNS(IPAddress dns_server1, IPAddress dns_server2);
|
||||
|
||||
/*
|
||||
* Disconnect from the network
|
||||
*
|
||||
* return: one value of wl_status_t enum
|
||||
*/
|
||||
int disconnect(void);
|
||||
|
||||
/*
|
||||
* Get the interface MAC address.
|
||||
*
|
||||
* return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
|
||||
*/
|
||||
uint8_t* macAddress(uint8_t* mac);
|
||||
|
||||
/*
|
||||
* Get the interface IP address.
|
||||
*
|
||||
* return: Ip address value
|
||||
*/
|
||||
IPAddress localIP();
|
||||
|
||||
/*
|
||||
* Get the interface subnet mask address.
|
||||
*
|
||||
* return: subnet mask address value
|
||||
*/
|
||||
IPAddress subnetMask();
|
||||
|
||||
/*
|
||||
* Get the gateway ip address.
|
||||
*
|
||||
* return: gateway ip address value
|
||||
*/
|
||||
IPAddress gatewayIP();
|
||||
|
||||
/*
|
||||
* Return the current SSID associated with the network
|
||||
*
|
||||
* return: ssid string
|
||||
*/
|
||||
char* SSID();
|
||||
|
||||
/*
|
||||
* Return the current BSSID associated with the network.
|
||||
* It is the MAC address of the Access Point
|
||||
*
|
||||
* return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
|
||||
*/
|
||||
uint8_t* BSSID(uint8_t* bssid);
|
||||
|
||||
/*
|
||||
* Return the current RSSI /Received Signal Strength in dBm)
|
||||
* associated with the network
|
||||
*
|
||||
* return: signed value
|
||||
*/
|
||||
int32_t RSSI();
|
||||
|
||||
/*
|
||||
* Return the Encryption Type associated with the network
|
||||
*
|
||||
* return: one value of wl_enc_type enum
|
||||
*/
|
||||
uint8_t encryptionType();
|
||||
|
||||
/*
|
||||
* Start scan WiFi networks available
|
||||
*
|
||||
* return: Number of discovered networks
|
||||
*/
|
||||
int8_t scanNetworks();
|
||||
|
||||
/*
|
||||
* Return the SSID discovered during the network scan.
|
||||
*
|
||||
* param networkItem: specify from which network item want to get the information
|
||||
*
|
||||
* return: ssid string of the specified item on the networks scanned list
|
||||
*/
|
||||
char* SSID(uint8_t networkItem);
|
||||
|
||||
/*
|
||||
* Return the encryption type of the networks discovered during the scanNetworks
|
||||
*
|
||||
* param networkItem: specify from which network item want to get the information
|
||||
*
|
||||
* return: encryption type (enum wl_enc_type) of the specified item on the networks scanned list
|
||||
*/
|
||||
uint8_t encryptionType(uint8_t networkItem);
|
||||
|
||||
/*
|
||||
* Return the security type and encryption type of the networks discovered during the scanNetworks
|
||||
*
|
||||
* param networkItem: specify from which network item want to get the information
|
||||
*
|
||||
* return: security and encryption type of the specified item on the networks scanned list
|
||||
*/
|
||||
uint32_t encryptionTypeEx(uint8_t networkItem);
|
||||
|
||||
/*
|
||||
* Return the RSSI of the networks discovered during the scanNetworks
|
||||
*
|
||||
* param networkItem: specify from which network item want to get the information
|
||||
*
|
||||
* return: signed value of RSSI of the specified item on the networks scanned list
|
||||
*/
|
||||
int32_t RSSI(uint8_t networkItem);
|
||||
|
||||
/*
|
||||
* Return Connection status.
|
||||
*
|
||||
* return: one of the value defined in wl_status_t
|
||||
*/
|
||||
uint8_t status();
|
||||
|
||||
/*
|
||||
* Resolve the given hostname to an IP address.
|
||||
* param aHostname: Name to be resolved
|
||||
* param aResult: IPAddress structure to store the returned IP address
|
||||
* result: 1 if aIPAddrString was successfully converted to an IP address,
|
||||
* else error code
|
||||
*/
|
||||
int hostByName(const char* aHostname, IPAddress& aResult);
|
||||
|
||||
int apbegin(char* ssid, char* channel);
|
||||
|
||||
int apbegin(char* ssid, char* password, char* channel);
|
||||
|
||||
int disablePowerSave();
|
||||
|
||||
friend class WiFiClient;
|
||||
friend class WiFiServer;
|
||||
friend class WiFiSSLClient;
|
||||
};
|
||||
|
||||
extern WiFiClass WiFi;
|
||||
|
||||
#endif
|
||||
@@ -1,191 +0,0 @@
|
||||
|
||||
extern "C" {
|
||||
#include "wl_definitions.h"
|
||||
#include "wl_types.h"
|
||||
#include "string.h"
|
||||
#include "errno.h"
|
||||
#include "update.h"
|
||||
}
|
||||
|
||||
#include "WiFi.h"
|
||||
#include "WiFiClient.h"
|
||||
#include "WiFiServer.h"
|
||||
#include "server_drv.h"
|
||||
|
||||
WiFiClient::WiFiClient() : _sock(MAX_SOCK_NUM) {
|
||||
_is_connected = false;
|
||||
recvTimeout = 3000;
|
||||
}
|
||||
|
||||
WiFiClient::WiFiClient(uint8_t sock) {
|
||||
_sock = sock;
|
||||
if(sock >= 0 && sock != 0xFF) {
|
||||
_is_connected = true;
|
||||
}
|
||||
recvTimeout = 3000;
|
||||
}
|
||||
|
||||
uint8_t WiFiClient::connected() {
|
||||
if ((_sock < 0) || (_sock == 0xFF)) {
|
||||
_is_connected = false;
|
||||
return 0;
|
||||
} else {
|
||||
if (_is_connected) {
|
||||
return 1;
|
||||
} else {
|
||||
stop();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int WiFiClient::available() {
|
||||
int ret = 0;
|
||||
int err;
|
||||
|
||||
if( !_is_connected) {
|
||||
return 0;
|
||||
}
|
||||
if (_sock >= 0) {
|
||||
ret = clientdrv.availData(_sock);
|
||||
if (ret > 0) {
|
||||
return 1;
|
||||
} else {
|
||||
err = clientdrv.getLastErrno(_sock);
|
||||
if (err != EAGAIN) {
|
||||
_is_connected = false;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int WiFiClient::read() {
|
||||
int ret;
|
||||
int err;
|
||||
uint8_t b[1];
|
||||
|
||||
if (!available()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = clientdrv.getData(_sock, b);
|
||||
if (ret > 0) {
|
||||
return b[0];
|
||||
} else {
|
||||
err = clientdrv.getLastErrno(_sock);
|
||||
if (err != EAGAIN) {
|
||||
_is_connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int WiFiClient::read(uint8_t* buf, size_t size) {
|
||||
uint16_t _size = size;
|
||||
int ret;
|
||||
int err;
|
||||
|
||||
ret = clientdrv.getDataBuf(_sock, buf, _size);
|
||||
if (ret <= 0) {
|
||||
err = clientdrv.getLastErrno(_sock);
|
||||
if (err != EAGAIN) {
|
||||
_is_connected = false;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void WiFiClient::stop() {
|
||||
if (_sock < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
clientdrv.stopClient(_sock);
|
||||
_is_connected = false;
|
||||
|
||||
_sock = -1;
|
||||
}
|
||||
|
||||
size_t WiFiClient::write(uint8_t b) {
|
||||
return write(&b, 1);
|
||||
}
|
||||
|
||||
size_t WiFiClient::write(const uint8_t *buf, size_t size) {
|
||||
if (_sock < 0) {
|
||||
setWriteError();
|
||||
return 0;
|
||||
}
|
||||
if (size==0) {
|
||||
setWriteError();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!clientdrv.sendData(_sock, buf, size)) {
|
||||
setWriteError();
|
||||
_is_connected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
WiFiClient::operator bool() {
|
||||
return _sock >= 0;
|
||||
}
|
||||
|
||||
int WiFiClient::connect(const char* host, uint16_t port) {
|
||||
IPAddress remote_addr;
|
||||
|
||||
if (WiFi.hostByName(host, remote_addr)) {
|
||||
return connect(remote_addr, port);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WiFiClient::connect(IPAddress ip, uint16_t port) {
|
||||
_is_connected = false;
|
||||
|
||||
_sock = clientdrv.startClient(ip, port);
|
||||
|
||||
if (_sock < 0) {
|
||||
_is_connected = false;
|
||||
return 0;
|
||||
} else {
|
||||
_is_connected = true;
|
||||
clientdrv.setSockRecvTimeout(_sock, recvTimeout);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WiFiClient::peek() {
|
||||
uint8_t b;
|
||||
|
||||
if (!available()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
clientdrv.getData(_sock, &b, 1);
|
||||
return b;
|
||||
}
|
||||
|
||||
void WiFiClient::flush() {
|
||||
while (available()) {
|
||||
read();
|
||||
}
|
||||
}
|
||||
|
||||
// extend API from RTK
|
||||
|
||||
int WiFiClient::setRecvTimeout(int timeout) {
|
||||
if (connected()) {
|
||||
recvTimeout = timeout;
|
||||
clientdrv.setSockRecvTimeout(_sock, recvTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
int WiFiClient::read(char *buf, size_t size) {
|
||||
read((uint8_t *)buf, size);
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
#ifndef wificlient_h
|
||||
#define wificlient_h
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "api/Client.h"
|
||||
#include "server_drv.h"
|
||||
|
||||
class WiFiClient : public Client {
|
||||
public:
|
||||
WiFiClient();
|
||||
WiFiClient(uint8_t sock);
|
||||
|
||||
uint8_t status();
|
||||
virtual int connect(IPAddress ip, uint16_t port);
|
||||
virtual int connect(const char *host, uint16_t port);
|
||||
virtual size_t write(uint8_t);
|
||||
virtual size_t write(const uint8_t *buf, size_t size);
|
||||
virtual int available();
|
||||
virtual int read();
|
||||
virtual int read(uint8_t *buf, size_t size);
|
||||
virtual int peek();
|
||||
virtual void flush();
|
||||
virtual void stop();
|
||||
virtual uint8_t connected();
|
||||
virtual operator bool();
|
||||
|
||||
friend class WiFiServer;
|
||||
|
||||
using Print::write;
|
||||
|
||||
// extend API from RTK
|
||||
|
||||
int setRecvTimeout(int timeout);
|
||||
int read(char *buf, size_t size);
|
||||
|
||||
private:
|
||||
int _sock;
|
||||
ServerDrv clientdrv;
|
||||
bool _is_connected;
|
||||
uint8_t data[DATA_LENTH];
|
||||
|
||||
int recvTimeout;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int update_ota_local(char *ip, int port);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,271 +0,0 @@
|
||||
#include "WiFi.h"
|
||||
#include "WiFiSSLClient.h"
|
||||
|
||||
extern "C" {
|
||||
#include "wl_definitions.h"
|
||||
#include "wl_types.h"
|
||||
#include "string.h"
|
||||
#include "errno.h"
|
||||
}
|
||||
|
||||
WiFiSSLClient::WiFiSSLClient() {
|
||||
_is_connected = false;
|
||||
_sock = -1;
|
||||
|
||||
sslclient.socket = -1;
|
||||
sslclient.ssl = NULL;
|
||||
sslclient.recvTimeout = 3000;
|
||||
|
||||
_rootCABuff = NULL;
|
||||
_cli_cert = NULL;
|
||||
_cli_key = NULL;
|
||||
_psKey = NULL;
|
||||
_pskIdent = NULL;
|
||||
_sni_hostname = NULL;
|
||||
}
|
||||
|
||||
WiFiSSLClient::WiFiSSLClient(uint8_t sock) {
|
||||
_sock = sock;
|
||||
|
||||
sslclient.socket = -1;
|
||||
sslclient.ssl = NULL;
|
||||
sslclient.recvTimeout = 3000;
|
||||
|
||||
// if(sock >= 0) {
|
||||
// _is_connected = true;
|
||||
// }
|
||||
_is_connected = true;
|
||||
|
||||
_rootCABuff = NULL;
|
||||
_cli_cert = NULL;
|
||||
_cli_key = NULL;
|
||||
_psKey = NULL;
|
||||
_pskIdent = NULL;
|
||||
_sni_hostname = NULL;
|
||||
}
|
||||
|
||||
uint8_t WiFiSSLClient::connected() {
|
||||
if (sslclient.socket < 0) {
|
||||
_is_connected = false;
|
||||
return 0;
|
||||
} else {
|
||||
if (_is_connected) {
|
||||
return 1;
|
||||
} else {
|
||||
stop();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int WiFiSSLClient::available() {
|
||||
int ret = 0;
|
||||
int err;
|
||||
|
||||
if (!_is_connected) {
|
||||
return 0;
|
||||
}
|
||||
if (sslclient.socket >= 0) {
|
||||
ret = ssldrv.availData(&sslclient);
|
||||
if (ret > 0) {
|
||||
return 1;
|
||||
} else {
|
||||
err = ssldrv.getLastErrno(&sslclient);
|
||||
if ((err > 0) && (err != EAGAIN)) {
|
||||
_is_connected = false;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WiFiSSLClient::read() {
|
||||
int ret;
|
||||
int err;
|
||||
uint8_t b[1];
|
||||
|
||||
if (!available()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ssldrv.getData(&sslclient, b);
|
||||
if (ret > 0) {
|
||||
return b[0];
|
||||
} else {
|
||||
err = ssldrv.getLastErrno(&sslclient);
|
||||
if ((err > 0) && (err != EAGAIN)) {
|
||||
_is_connected = false;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int WiFiSSLClient::read(uint8_t* buf, size_t size) {
|
||||
uint16_t _size = size;
|
||||
int ret;
|
||||
int err;
|
||||
|
||||
ret = ssldrv.getDataBuf(&sslclient, buf, _size);
|
||||
if (ret <= 0) {
|
||||
err = ssldrv.getLastErrno(&sslclient);
|
||||
if ((err > 0) && (err != EAGAIN)) {
|
||||
_is_connected = false;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void WiFiSSLClient::stop() {
|
||||
|
||||
if (sslclient.socket < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ssldrv.stopClient(&sslclient);
|
||||
_is_connected = false;
|
||||
|
||||
sslclient.socket = -1;
|
||||
_sock = -1;
|
||||
}
|
||||
|
||||
size_t WiFiSSLClient::write(uint8_t b) {
|
||||
return write(&b, 1);
|
||||
}
|
||||
|
||||
size_t WiFiSSLClient::write(const uint8_t *buf, size_t size) {
|
||||
if (sslclient.socket < 0) {
|
||||
setWriteError();
|
||||
return 0;
|
||||
}
|
||||
if (size == 0) {
|
||||
setWriteError();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ssldrv.sendData(&sslclient, buf, size)) {
|
||||
setWriteError();
|
||||
_is_connected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
WiFiSSLClient::operator bool() {
|
||||
return (sslclient.socket >= 0);
|
||||
}
|
||||
|
||||
int WiFiSSLClient::connect(IPAddress ip, uint16_t port) {
|
||||
if (_psKey != NULL && _pskIdent != NULL)
|
||||
return connect(ip, port, _pskIdent, _psKey);
|
||||
return connect(ip, port, _rootCABuff, _cli_cert, _cli_key);
|
||||
}
|
||||
|
||||
int WiFiSSLClient::connect(const char *host, uint16_t port) {
|
||||
|
||||
if (_sni_hostname == NULL) {
|
||||
_sni_hostname = (char*)host;
|
||||
}
|
||||
|
||||
if (_psKey != NULL && _pskIdent != NULL)
|
||||
return connect(host, port, _pskIdent, _psKey);
|
||||
return connect(host, port, _rootCABuff, _cli_cert, _cli_key);
|
||||
}
|
||||
|
||||
int WiFiSSLClient::connect(const char* host, uint16_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key) {
|
||||
IPAddress remote_addr;
|
||||
|
||||
if (_sni_hostname == NULL) {
|
||||
_sni_hostname = (char*)host;
|
||||
}
|
||||
|
||||
if (WiFi.hostByName(host, remote_addr)) {
|
||||
return connect(remote_addr, port, rootCABuff, cli_cert, cli_key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WiFiSSLClient::connect(IPAddress ip, uint16_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key) {
|
||||
int ret = 0;
|
||||
|
||||
ret = ssldrv.startClient(&sslclient, uint32_t(ip), port, rootCABuff, cli_cert, cli_key, NULL, NULL, _sni_hostname);
|
||||
|
||||
if (ret < 0) {
|
||||
_is_connected = false;
|
||||
return 0;
|
||||
} else {
|
||||
_is_connected = true;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WiFiSSLClient::connect(const char *host, uint16_t port, unsigned char* pskIdent, unsigned char* psKey) {
|
||||
IPAddress remote_addr;
|
||||
|
||||
if (_sni_hostname == NULL) {
|
||||
_sni_hostname = (char*)host;
|
||||
}
|
||||
|
||||
if (WiFi.hostByName(host, remote_addr)) {
|
||||
return connect(remote_addr, port, pskIdent, psKey);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WiFiSSLClient::connect(IPAddress ip, uint16_t port, unsigned char* pskIdent, unsigned char* psKey) {
|
||||
int ret = 0;
|
||||
|
||||
ret = ssldrv.startClient(&sslclient, uint32_t(ip), port, NULL, NULL, NULL, pskIdent, psKey, _sni_hostname);
|
||||
|
||||
if (ret < 0) {
|
||||
_is_connected = false;
|
||||
return 0;
|
||||
} else {
|
||||
_is_connected = true;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WiFiSSLClient::peek() {
|
||||
uint8_t b;
|
||||
|
||||
if (!available()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssldrv.getData(&sslclient, &b, 1);
|
||||
|
||||
return b;
|
||||
}
|
||||
void WiFiSSLClient::flush() {
|
||||
while (available()) {
|
||||
read();
|
||||
}
|
||||
}
|
||||
|
||||
void WiFiSSLClient::setRootCA(unsigned char *rootCA) {
|
||||
_rootCABuff = rootCA;
|
||||
}
|
||||
|
||||
void WiFiSSLClient::setClientCertificate(unsigned char *client_ca, unsigned char *private_key) {
|
||||
_cli_cert = client_ca;
|
||||
_cli_key = private_key;
|
||||
}
|
||||
|
||||
void WiFiSSLClient::setPreSharedKey(unsigned char *pskIdent, unsigned char *psKey) {
|
||||
_psKey = psKey;
|
||||
_pskIdent = pskIdent;
|
||||
}
|
||||
|
||||
int WiFiSSLClient::setRecvTimeout(int timeout) {
|
||||
sslclient.recvTimeout = timeout;
|
||||
if (connected()) {
|
||||
ssldrv.setSockRecvTimeout(sslclient.socket, sslclient.recvTimeout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
#ifndef wifisslclient_h
|
||||
#define wifisslclient_h
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "api/Client.h"
|
||||
#include "ssl_drv.h"
|
||||
|
||||
struct mbedtls_ssl_context;
|
||||
class WiFiSSLClient : public Client {
|
||||
|
||||
public:
|
||||
WiFiSSLClient();
|
||||
WiFiSSLClient(uint8_t sock);
|
||||
|
||||
uint8_t status();
|
||||
virtual int connect(IPAddress ip, uint16_t port);
|
||||
virtual int connect(const char *host, uint16_t port);
|
||||
virtual size_t write(uint8_t);
|
||||
virtual size_t write(const uint8_t *buf, size_t size);
|
||||
virtual int available();
|
||||
virtual int read();
|
||||
virtual int read(uint8_t *buf, size_t size);
|
||||
virtual int peek();
|
||||
virtual void flush();
|
||||
virtual void stop();
|
||||
virtual uint8_t connected();
|
||||
virtual operator bool();
|
||||
|
||||
void setRootCA(unsigned char *rootCA);
|
||||
void setClientCertificate(unsigned char *client_ca, unsigned char *private_key);
|
||||
void setPreSharedKey(unsigned char *pskIdent, unsigned char *psKey); // psKey expressed as hexadecimal string
|
||||
|
||||
int connect(const char *host, uint16_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key);
|
||||
int connect(IPAddress ip, uint16_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key);
|
||||
int connect(const char *host, uint16_t port, unsigned char* pskIdent, unsigned char* psKey);
|
||||
int connect(IPAddress ip, uint16_t port, unsigned char* pskIdent, unsigned char* psKey);
|
||||
|
||||
using Print::write;
|
||||
int setRecvTimeout(int timeout);
|
||||
|
||||
private:
|
||||
int _sock;
|
||||
bool _is_connected;
|
||||
sslclient_context sslclient;
|
||||
SSLDrv ssldrv;
|
||||
|
||||
unsigned char *_rootCABuff;
|
||||
unsigned char *_cli_cert;
|
||||
unsigned char *_cli_key;
|
||||
unsigned char *_psKey;
|
||||
unsigned char *_pskIdent;
|
||||
char *_sni_hostname;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
WiFiServer.cpp - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "server_drv.h"
|
||||
#include "WiFi.h"
|
||||
#include "WiFiClient.h"
|
||||
#include "WiFiServer.h"
|
||||
|
||||
WiFiServer::WiFiServer(uint16_t port) {
|
||||
_port = port;
|
||||
}
|
||||
|
||||
void WiFiServer::begin() {
|
||||
_sock_ser = serverfd.startServer(_port);
|
||||
}
|
||||
|
||||
WiFiClient WiFiServer::available(uint8_t* status) {
|
||||
int client_fd;
|
||||
|
||||
client_fd = serverfd.getAvailable(_sock_ser);
|
||||
|
||||
return WiFiClient(client_fd);
|
||||
}
|
||||
|
||||
size_t WiFiServer::write(uint8_t b) {
|
||||
return write(&b, 1);
|
||||
}
|
||||
|
||||
size_t WiFiServer::write(const uint8_t *buf, size_t size) {
|
||||
if (_sock_ser < 0) {
|
||||
setWriteError();
|
||||
return 0;
|
||||
}
|
||||
if (size == 0) {
|
||||
setWriteError();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!serverfd.sendData(_sock_ser, buf, size)) {
|
||||
setWriteError();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
#if 0
|
||||
uint8_t WiFiServer::status() {
|
||||
return ServerDrv::getServerState(0);
|
||||
}
|
||||
|
||||
|
||||
size_t WiFiServer::write(uint8_t b) {
|
||||
return write(&b, 1);
|
||||
}
|
||||
|
||||
size_t WiFiServer::write(const uint8_t *buffer, size_t size) {
|
||||
size_t n = 0;
|
||||
|
||||
for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
|
||||
if (WiFiClass::_server_port[sock] != 0) {
|
||||
WiFiClient client(sock);
|
||||
|
||||
if ((WiFiClass::_server_port[sock] == _port) && (client.status() == ESTABLISHED)) {
|
||||
n+=client.write(buffer, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
#endif
|
||||
@@ -1,29 +0,0 @@
|
||||
#ifndef wifiserver_h
|
||||
#define wifiserver_h
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "api/Server.h"
|
||||
#include "server_drv.h"
|
||||
|
||||
class WiFiClient;
|
||||
|
||||
class WiFiServer : public Server {
|
||||
private:
|
||||
uint16_t _port;
|
||||
int _sock_ser;
|
||||
ServerDrv serverfd;
|
||||
|
||||
public:
|
||||
WiFiServer(uint16_t);
|
||||
|
||||
WiFiClient available(uint8_t* status = NULL);
|
||||
|
||||
void begin();
|
||||
virtual size_t write(uint8_t b);
|
||||
virtual size_t write(const uint8_t *buf, size_t size);
|
||||
//uint8_t status();
|
||||
|
||||
using Print::write;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
WiFiUdp.cpp - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
extern int rtl_printf(const char *fmt, ...);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include "server_drv.h"
|
||||
#include "wifi_drv.h"
|
||||
#include "WiFi.h"
|
||||
#include "WiFiUdp.h"
|
||||
#include "WiFiClient.h"
|
||||
#include "WiFiServer.h"
|
||||
|
||||
/* Constructor */
|
||||
WiFiUDP::WiFiUDP() : _sock(-1), _client_sock(-1) {}
|
||||
|
||||
/* Start WiFiUDP socket, listening at local port PORT */
|
||||
uint8_t WiFiUDP::begin(uint16_t port) {
|
||||
if (_port == port && _sock >= 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
_port = port;
|
||||
_sock = serverDrv.startServer(port, UDP_MODE);
|
||||
|
||||
if (_sock >=0 ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return number of bytes available in the current packet,
|
||||
will return zero if parsePacket hasn't been called yet */
|
||||
int WiFiUDP::available() {
|
||||
int ret;
|
||||
|
||||
if (_sock >= 0) {
|
||||
ret = serverDrv.availData(_sock);
|
||||
if (ret > 0) {
|
||||
return ret;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Release any resources being used by this WiFiUDP instance */
|
||||
void WiFiUDP::stop() {
|
||||
if (_sock < 0) {
|
||||
return;
|
||||
}
|
||||
serverDrv.stopClient(_sock);
|
||||
_sock = -1;
|
||||
}
|
||||
|
||||
int WiFiUDP::beginPacket(const char *host, uint16_t port) {
|
||||
// Look up the host first
|
||||
int ret = 0;
|
||||
IPAddress remote_addr;
|
||||
if (WiFi.hostByName(host, remote_addr)) {
|
||||
return beginPacket(remote_addr, port);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int WiFiUDP::beginPacket(IPAddress ip, uint16_t port) {
|
||||
peer_ip = ip;
|
||||
peer_port = port;
|
||||
|
||||
if (_sock >= 0) {
|
||||
_client_sock = _sock;
|
||||
} else {
|
||||
_client_sock = serverDrv.startClient(ip, port, UDP_MODE);
|
||||
}
|
||||
|
||||
if (_client_sock < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int WiFiUDP::endPacket() {
|
||||
if (_client_sock >= 0 && _client_sock != _sock) {
|
||||
serverDrv.stopClient(_client_sock);
|
||||
}
|
||||
|
||||
peer_ip = 0;
|
||||
peer_port = 0;
|
||||
_client_sock = -1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t WiFiUDP::write(uint8_t byte) {
|
||||
return write(&byte, 1);
|
||||
}
|
||||
|
||||
size_t WiFiUDP::write(const uint8_t *buffer, size_t size) {
|
||||
writeImmediately(buffer, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t WiFiUDP::writeImmediately(const uint8_t *buffer, size_t size) {
|
||||
serverDrv.sendtoData(_client_sock, buffer, size, peer_ip, peer_port);
|
||||
return size;
|
||||
}
|
||||
|
||||
int WiFiUDP::parsePacket() {
|
||||
return available();
|
||||
}
|
||||
|
||||
int WiFiUDP::read() {
|
||||
int ret;
|
||||
uint8_t b;
|
||||
|
||||
ret = serverDrv.getData(_sock, &b);
|
||||
if (ret == 1) {
|
||||
return b;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
int WiFiUDP::read(unsigned char* buffer, size_t len) {
|
||||
return serverDrv.getDataBuf(_sock, buffer, len);
|
||||
}
|
||||
|
||||
int WiFiUDP::peek() {
|
||||
uint8_t b;
|
||||
if (!available()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
serverDrv.getData(_sock, &b, 1);
|
||||
return b;
|
||||
}
|
||||
|
||||
void WiFiUDP::flush() {
|
||||
while (read() > 0);
|
||||
}
|
||||
|
||||
IPAddress WiFiUDP::remoteIP() {
|
||||
uint32_t _remoteIp;
|
||||
uint16_t _remotePort;
|
||||
|
||||
serverDrv.getRemoteData(_sock, &_remoteIp, &_remotePort);
|
||||
|
||||
IPAddress ip(_remoteIp);
|
||||
return ip;
|
||||
}
|
||||
|
||||
uint16_t WiFiUDP::remotePort() {
|
||||
uint32_t _remoteIp;
|
||||
uint16_t _remotePort;
|
||||
|
||||
serverDrv.getRemoteData(_sock, &_remoteIp, &_remotePort);
|
||||
|
||||
return _remotePort;
|
||||
}
|
||||
|
||||
// extend API by RTK
|
||||
|
||||
void WiFiUDP::setRecvTimeout(int timeout) {
|
||||
if (_sock >= 0) {
|
||||
serverDrv.setSockRecvTimeout(_sock, timeout);
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
WiFiUdp.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef wifiudp_h
|
||||
#define wifiudp_h
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Udp.h>
|
||||
|
||||
#include "server_drv.h"
|
||||
|
||||
#define UDP_TX_PACKET_MAX_SIZE 24
|
||||
|
||||
class WiFiUDP : public UDP {
|
||||
private:
|
||||
int _sock; // socket ID
|
||||
uint16_t _port; // local port to listen on
|
||||
ServerDrv serverDrv; // socket driver
|
||||
|
||||
int _client_sock;
|
||||
uint32_t peer_ip;
|
||||
uint32_t peer_port;
|
||||
|
||||
public:
|
||||
WiFiUDP(); // Constructor
|
||||
virtual uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
|
||||
virtual void stop(); // Finish with the UDP socket
|
||||
|
||||
// Sending UDP packets
|
||||
|
||||
// Start building up a packet to send to the remote host specific in ip and port
|
||||
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
|
||||
virtual int beginPacket(IPAddress ip, uint16_t port);
|
||||
// Start building up a packet to send to the remote host specific in host and port
|
||||
// Returns 1 if successful, 0 if there was a problem resolving the hostname or port
|
||||
virtual int beginPacket(const char *host, uint16_t port);
|
||||
// Finish off this packet and send it
|
||||
// Returns 1 if the packet was sent successfully, 0 if there was an error
|
||||
virtual int endPacket();
|
||||
// Write a single byte into the packet
|
||||
virtual size_t write(uint8_t);
|
||||
// Write size bytes from buffer into the packet
|
||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||
|
||||
// Send packet immediately from buffer
|
||||
size_t writeImmediately(const uint8_t *buffer, size_t size);
|
||||
|
||||
using Print::write;
|
||||
|
||||
// Start processing the next available incoming packet
|
||||
// Returns the size of the packet in bytes, or 0 if no packets are available
|
||||
virtual int parsePacket();
|
||||
// Number of bytes remaining in the current packet
|
||||
virtual int available();
|
||||
// Read a single byte from the current packet
|
||||
virtual int read();
|
||||
// Read up to len bytes from the current packet and place them into buffer
|
||||
// Returns the number of bytes read, or 0 if none are available
|
||||
virtual int read(unsigned char* buffer, size_t len);
|
||||
// Read up to len characters from the current packet and place them into buffer
|
||||
// Returns the number of characters read, or 0 if none are available
|
||||
virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); };
|
||||
// Return the next byte from the current packet without moving on to the next byte
|
||||
virtual int peek();
|
||||
virtual void flush(); // Finish reading the current packet
|
||||
|
||||
// Return the IP address of the host who sent the current incoming packet
|
||||
virtual IPAddress remoteIP();
|
||||
// Return the port of the host who sent the current incoming packet
|
||||
virtual uint16_t remotePort();
|
||||
|
||||
friend class WiFiDrv;
|
||||
|
||||
// extend API by RTK
|
||||
|
||||
void setRecvTimeout(int timeout);
|
||||
};
|
||||
|
||||
#endif
|
||||
8
boards/_base/beken-7231-tuya.json
Normal file
8
boards/_base/beken-7231-tuya.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"build": {
|
||||
"bkcrypt_coeffs": "510fb093a3cbeadc5993a17ec7adeb03"
|
||||
},
|
||||
"flash": {
|
||||
"tuya": "0x1ED000+0x13000"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user