mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-26 12:14:56 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
236724ea29 | ||
|
|
b503915ca5 | ||
|
|
156db0bc5e | ||
|
|
11b6bd7d9c | ||
|
|
7ca952faa6 | ||
|
|
4fc40f0ffb | ||
|
|
cac4b3e254 | ||
|
|
0d5cb5cbcc | ||
|
|
a35901121b | ||
|
|
e0740fc2ca | ||
|
|
7d22b5fe18 | ||
|
|
d2e66ac58d | ||
|
|
34cc8da87e | ||
|
|
1957ba8ffe | ||
|
|
72758812f5 | ||
|
|
ab5a0c43de | ||
|
|
c8291e4ae9 | ||
|
|
84e9ea76db | ||
|
|
b8994f8bc3 | ||
|
|
b53d8439e5 | ||
|
|
337e8abf2f | ||
|
|
f0bc1c031f | ||
|
|
19d2b93ec7 | ||
|
|
e0304f2b8f | ||
|
|
f7a86f8cf1 | ||
|
|
340f0dbf89 | ||
|
|
d90b62d911 | ||
|
|
d84aff6420 | ||
|
|
b3b73f4751 | ||
|
|
3c7b2dcd6d | ||
|
|
49470f9bd2 | ||
|
|
f7cf4f60ef | ||
|
|
7e0d06689e | ||
|
|
b843957bd2 | ||
|
|
1a0167eb6d | ||
|
|
6ea3b98941 | ||
|
|
4b0b93d4f3 | ||
|
|
64abf061bf | ||
|
|
05d5c68982 | ||
|
|
235dafe646 | ||
|
|
0cc40b0c70 | ||
|
|
07a0d1265b | ||
|
|
967d746574 | ||
|
|
bd12cb1b87 | ||
|
|
a21ca5d40b | ||
|
|
2d399107fb | ||
|
|
03bfa3806b | ||
|
|
6536ae9bcc | ||
|
|
e8fc817a0c | ||
|
|
e621ade392 | ||
|
|
3273c20ca9 | ||
|
|
a6b2124fd5 | ||
|
|
5a1ff125d7 | ||
|
|
ad58a48144 | ||
|
|
a205fd7877 | ||
|
|
776360ca93 | ||
|
|
af7602497d | ||
|
|
0f83c2a6e5 | ||
|
|
0d58748e63 | ||
|
|
01902bb8b9 | ||
|
|
e28e9aa1d7 | ||
|
|
587e79dc05 | ||
|
|
acd65f2340 | ||
|
|
d55fb80746 | ||
|
|
4536694f20 | ||
|
|
2c5a6d4df6 | ||
|
|
4c8e219643 | ||
|
|
daeca8128b | ||
|
|
fe6d357858 | ||
|
|
a99cc3dbaf | ||
|
|
3c4c04199a | ||
|
|
8ca692100f | ||
|
|
0b9f28b8e3 | ||
|
|
1dff394b63 | ||
|
|
f4c35d1036 | ||
|
|
81c166ad74 | ||
|
|
1f56776050 | ||
|
|
b3a0e7b884 | ||
|
|
8594507b5b | ||
|
|
fa811ce12b | ||
|
|
c1ef477ff3 | ||
|
|
4be3a96987 | ||
|
|
387f875aa1 | ||
|
|
cc069e7e5d | ||
|
|
df994df611 | ||
|
|
8f77fd3940 | ||
|
|
7530062e4b | ||
|
|
0e63510708 | ||
|
|
26260a1d88 | ||
|
|
9e82844f10 | ||
|
|
0568b5a75b | ||
|
|
3baabebb34 | ||
|
|
bf4dd15317 | ||
|
|
b0f2f9621a | ||
|
|
04d6d05e9e | ||
|
|
7339c7dfe7 | ||
|
|
c1152f5eeb | ||
|
|
024922d566 | ||
|
|
6f64c8c0de | ||
|
|
2a5ac3c2e5 | ||
|
|
7b0120f0c2 | ||
|
|
7ee1f14a6d | ||
|
|
3aaf7d0da7 | ||
|
|
434f3f8415 | ||
|
|
739d78a45a | ||
|
|
8a62633b2f | ||
|
|
aae1a687a9 | ||
|
|
61285ec418 | ||
|
|
a00b3f1c6c | ||
|
|
2c813f3e72 | ||
|
|
ea68d7a705 | ||
|
|
654f401038 | ||
|
|
ad89122a06 | ||
|
|
73ed158e76 | ||
|
|
548c3dc77f | ||
|
|
c1fa067a1f | ||
|
|
9fd87060f9 | ||
|
|
de0a3b035a | ||
|
|
9f76ea8030 | ||
|
|
76b7356873 | ||
|
|
c24d5aabd8 | ||
|
|
0df6645b90 | ||
|
|
b19cf8654f | ||
|
|
19933a4673 | ||
|
|
76963f7d01 | ||
|
|
e670ea3d61 | ||
|
|
fa33b57e4f | ||
|
|
77e369bc79 | ||
|
|
94ad9767d3 | ||
|
|
aa76f5673b | ||
|
|
81a699c801 | ||
|
|
bd15c456b2 | ||
|
|
10d9e1e9ae | ||
|
|
6a3813f633 | ||
|
|
51fe22a95f | ||
|
|
105762416f | ||
|
|
db7087f455 | ||
|
|
c5693503cb | ||
|
|
b74590a4a5 | ||
|
|
d5eeed48eb | ||
|
|
fc5c0d0964 | ||
|
|
aa2647c0bc | ||
|
|
cef0acdb40 | ||
|
|
2140656acc | ||
|
|
fd0c969f16 | ||
|
|
dfeb929e0e | ||
|
|
d3e67733a6 | ||
|
|
eff74fdc9d | ||
|
|
5e4c40ad09 | ||
|
|
087e6d3142 | ||
|
|
587b074822 | ||
|
|
6aa8c01ac7 | ||
|
|
3bbcd5df3e | ||
|
|
af512c57ef | ||
|
|
58297a7871 | ||
|
|
18a530048c | ||
|
|
f9ed75d6b3 | ||
|
|
3c1f41e575 | ||
|
|
c772936dd1 | ||
|
|
253696be45 | ||
|
|
79b7accc55 | ||
|
|
7a1e846c73 | ||
|
|
ce59ff89c3 | ||
|
|
d31d064d5e | ||
|
|
467fbf4bb4 | ||
|
|
6769223ce1 | ||
|
|
294e483885 | ||
|
|
43513e2d56 | ||
|
|
d1b7687e98 | ||
|
|
9ac09da1d2 | ||
|
|
24a330c750 | ||
|
|
13a9c773f2 | ||
|
|
3cd166d065 | ||
|
|
490066fd17 | ||
|
|
94fce72ade | ||
|
|
eacc64bdd1 | ||
|
|
7b037f4957 | ||
|
|
fa841916c1 | ||
|
|
75c11436ff | ||
|
|
e07a8283ec | ||
|
|
2a174b0d3b | ||
|
|
013993abae | ||
|
|
dccc153c68 | ||
|
|
db0867f435 | ||
|
|
7234121835 | ||
|
|
3aafc073d8 | ||
|
|
b527ed313c | ||
|
|
cd86559685 | ||
|
|
f67e843be6 | ||
|
|
4f9ebd8092 | ||
|
|
6c044d6aeb | ||
|
|
c6ee909aa4 | ||
|
|
393063428e | ||
|
|
1494f5e831 | ||
|
|
8bfd0c2ca3 | ||
|
|
e9de2f3eb1 | ||
|
|
8bf9d09d96 | ||
|
|
67255ce8f5 | ||
|
|
5db89aa264 | ||
|
|
8a9b1d9873 | ||
|
|
c08c1afb1e | ||
|
|
2c7f58aed2 | ||
|
|
b3ee71acbe | ||
|
|
52ab6bc499 | ||
|
|
bf059ad42f | ||
|
|
85df6a6131 | ||
|
|
d840b4a4ee | ||
|
|
a8c2ce544e | ||
|
|
b95022a3b3 | ||
|
|
8c45a9d2c9 | ||
|
|
0fe64fbff9 | ||
|
|
64e806628b | ||
|
|
ccd2b2699f | ||
|
|
0b5c0c9889 | ||
|
|
6293e7dbec | ||
|
|
87325ece82 | ||
|
|
6cbd9b3067 | ||
|
|
aa27fde9d0 | ||
|
|
e854585802 | ||
|
|
2c5aba24cc | ||
|
|
806ee0f2cb | ||
|
|
e72b95fb1c | ||
|
|
471e7ff61a | ||
|
|
3d2de154d1 | ||
|
|
fc551ec2e9 | ||
|
|
f5e2c68c8b | ||
|
|
074ef5197b | ||
|
|
5f1f4a0df8 | ||
|
|
86334e9040 | ||
|
|
f71cc3ebc3 | ||
|
|
00910462e7 | ||
|
|
2fc56dd1d0 | ||
|
|
a5ebe71394 | ||
|
|
0eb8bf6b51 | ||
|
|
3a0fe5288c | ||
|
|
bfca233160 | ||
|
|
acf217601b | ||
|
|
b0d0fbfd9f | ||
|
|
9411f1c7b6 | ||
|
|
d7d7ebf99a | ||
|
|
8072ae2057 | ||
|
|
e529e644ab | ||
|
|
d6fdfe5b1b | ||
|
|
50e15e574f | ||
|
|
58f1533779 | ||
|
|
f4a49829ea | ||
|
|
3efe6641eb | ||
|
|
0459d9e106 | ||
|
|
305d69ee36 | ||
|
|
98e744a9ad | ||
|
|
1d97f2e2b5 | ||
|
|
c92bc4b4ac | ||
|
|
6a3e1e41c4 | ||
|
|
650caface3 | ||
|
|
8b6e02e985 | ||
|
|
3ee6fe45f9 | ||
|
|
e811afd397 | ||
|
|
b197a674e1 | ||
|
|
08f6b99b13 | ||
|
|
b18d0301f3 | ||
|
|
5596621420 | ||
|
|
bd8a66eee7 | ||
|
|
b62ebb3c10 | ||
|
|
45d796fe5b | ||
|
|
d8a3b90cad | ||
|
|
5be9e55425 | ||
|
|
6b6acd3967 | ||
|
|
1b06403a19 | ||
|
|
b740c80855 | ||
|
|
29594283c1 | ||
|
|
51f54f9b7e | ||
|
|
1f48b1ca65 | ||
|
|
fd2d7cccf3 | ||
|
|
5726e680ec | ||
|
|
fadf28adb4 | ||
|
|
a321c2d096 | ||
|
|
bbb07bf6f7 | ||
|
|
a801160bc0 | ||
|
|
662cc27f4f | ||
|
|
ccfe7e0724 | ||
|
|
8061a41b38 | ||
|
|
d01aa01a51 | ||
|
|
39392b3690 | ||
|
|
54d4611eb6 | ||
|
|
34cdce750d | ||
|
|
f3fafb6759 | ||
|
|
0372c97ff5 | ||
|
|
b46136a0af | ||
|
|
ac3d41fb79 | ||
|
|
14be42c868 | ||
|
|
f0ec14543a | ||
|
|
f46c5b7214 | ||
|
|
ccd6bcd95f | ||
|
|
a3b63f3b0d | ||
|
|
f2905a5e10 | ||
|
|
1ef6c6aeb5 | ||
|
|
bd53529b45 | ||
|
|
cc8ecc5a42 | ||
|
|
5a816a1d41 | ||
|
|
9922286c67 | ||
|
|
cdc439bc38 | ||
|
|
ae8422e304 | ||
|
|
539d080346 | ||
|
|
041ec6e1f8 | ||
|
|
f618fe125c | ||
|
|
8ab514fabc | ||
|
|
08ad2c3145 | ||
|
|
c64fd404d4 | ||
|
|
143b0ac126 | ||
|
|
c2e2432010 | ||
|
|
1d2a768184 | ||
|
|
fb099641bc | ||
|
|
6da9afbf29 | ||
|
|
dceb4beb09 | ||
|
|
6f697db49d | ||
|
|
b44193780e | ||
|
|
8e0212c3db | ||
|
|
3861e2e1e7 | ||
|
|
21eefa4b55 | ||
|
|
fb6c6aafeb | ||
|
|
df07426e78 | ||
|
|
5cf1523a13 | ||
|
|
f2fe47e9f7 | ||
|
|
2557ab2e60 | ||
|
|
fbc1708000 | ||
|
|
0539cf1023 | ||
|
|
07b410447b | ||
|
|
fb69016196 | ||
|
|
169cbc044f | ||
|
|
08091d02e5 | ||
|
|
6f2dcf92a7 | ||
|
|
578e52618d | ||
|
|
ec0fe66a17 | ||
|
|
8fee24291a | ||
|
|
05bba2958d | ||
|
|
e656b1c792 | ||
|
|
e0ccbadd25 | ||
|
|
40a2a8822f | ||
|
|
e2ee356a87 | ||
|
|
189bef61d3 | ||
|
|
7d94f9f61b | ||
|
|
e37a0b9056 | ||
|
|
0b57b23951 | ||
|
|
c84826e84e | ||
|
|
064fc6ff7b | ||
|
|
042ea53478 | ||
|
|
900b0acf7a | ||
|
|
dc5f2e295a | ||
|
|
c1849c2b19 | ||
|
|
4eadf3699f | ||
|
|
b30cf6587c | ||
|
|
fbc231f33e | ||
|
|
bc8c839342 | ||
|
|
90a23fe230 | ||
|
|
065027843e | ||
|
|
8906b1ac0f | ||
|
|
05f9e61a41 | ||
|
|
782896b5d3 | ||
|
|
4258f62560 | ||
|
|
537ba64a54 | ||
|
|
25d20b7354 | ||
|
|
04d8362905 | ||
|
|
21266e9a45 | ||
|
|
7304e2171d | ||
|
|
61fc480850 | ||
|
|
562e82f5ac | ||
|
|
d7ff85bb48 | ||
|
|
55bc6105e1 | ||
|
|
306c0b6096 | ||
|
|
024078ae33 | ||
|
|
b5a9ba8390 | ||
|
|
93f36927ca | ||
|
|
1db90cafd1 | ||
|
|
bf23a0def7 | ||
|
|
ea1cbeea9d | ||
|
|
aeda7e5520 | ||
|
|
a7899af8b8 | ||
|
|
b0385f47af | ||
|
|
86c384657c | ||
|
|
6e569110d2 | ||
|
|
3b1024b13c | ||
|
|
b3f5d11275 | ||
|
|
1078ba0a92 | ||
|
|
005c8170d4 | ||
|
|
b8d1d7a10b | ||
|
|
76769fb4d5 | ||
|
|
6ff6f0a4c6 | ||
|
|
72a45d2f6a | ||
|
|
2fe7c8a410 | ||
|
|
5269eb9c39 | ||
|
|
0a86bc0af2 | ||
|
|
bc9f6ba0b0 | ||
|
|
9e16a0ae42 | ||
|
|
9ccbb49aef | ||
|
|
d59f84fbbc | ||
|
|
4bbb5008b1 | ||
|
|
49ce25511e | ||
|
|
985276665d | ||
|
|
91f553c45f | ||
|
|
38ede8ec58 | ||
|
|
997f6543ce | ||
|
|
b50081a83b | ||
|
|
34f512d244 | ||
|
|
eb5752f41b | ||
|
|
ef8e7419fa | ||
|
|
cfcdd15b89 | ||
|
|
b26debaebc | ||
|
|
6deb061b12 | ||
|
|
4c6745670c | ||
|
|
01c662b7de | ||
|
|
179fe652c2 | ||
|
|
394bc3260d | ||
|
|
ce1a70e2dc | ||
|
|
99022896f6 | ||
|
|
446b400667 | ||
|
|
a0d9b6a7e0 | ||
|
|
7d53c21efe | ||
|
|
b78efbac36 | ||
|
|
9be9dcec46 | ||
|
|
3766ab802b | ||
|
|
b9141925a3 | ||
|
|
ed79fe86aa | ||
|
|
2f0b0955a9 | ||
|
|
2f8e15a900 | ||
|
|
b8b3a5c305 | ||
|
|
e7ea421c54 | ||
|
|
8de9699390 | ||
|
|
bf592a22ae | ||
|
|
8d4a619a15 | ||
|
|
1a3588624d | ||
|
|
74b3fd2efc | ||
|
|
091356ed59 | ||
|
|
fc0e1ee311 | ||
|
|
8dbfcbff58 | ||
|
|
317591bc8a | ||
|
|
f71b3b91c0 | ||
|
|
9e255bcbce | ||
|
|
8af319b953 | ||
|
|
f90fd9cec4 | ||
|
|
d386b1c12d | ||
|
|
81551ec50d | ||
|
|
8fafcf6eaa | ||
|
|
f0df6c61c9 | ||
|
|
6cf36b5771 | ||
|
|
54799187e9 | ||
|
|
6d0320be06 | ||
|
|
317a1527ad | ||
|
|
490eb0f57f | ||
|
|
f95283e341 | ||
|
|
837da0e458 | ||
|
|
8ce82a100e | ||
|
|
9ece98c101 | ||
|
|
6a83147b33 | ||
|
|
90e4228e1d | ||
|
|
553aeeef77 | ||
|
|
6147e865f8 | ||
|
|
7b296fabb0 | ||
|
|
00c8f8acd0 | ||
|
|
1e1efa2c5e | ||
|
|
b0b0dd9f0b | ||
|
|
30bb1c52d0 | ||
|
|
7fc96a61ad | ||
|
|
4a164c39b4 | ||
|
|
b0e4069bb7 | ||
|
|
19cbb27b4c | ||
|
|
d44c864387 | ||
|
|
36e21e53e0 | ||
|
|
b7598cc354 | ||
|
|
0a4f322d49 | ||
|
|
bf013fcdae | ||
|
|
fd52fccc15 | ||
|
|
c493d3a4ce | ||
|
|
aeceb2b9e7 | ||
|
|
cb5f833dd2 | ||
|
|
0740ccd9f7 | ||
|
|
716c84c896 | ||
|
|
c5fda07d1e | ||
|
|
7fffe0abaa | ||
|
|
8a42325c23 | ||
|
|
78900304bf | ||
|
|
fb6dfbcd3c | ||
|
|
3dd4c7da2a | ||
|
|
03c955410c | ||
|
|
74f77c9ded | ||
|
|
3caca03e8a | ||
|
|
49469840ab | ||
|
|
85613ab02d | ||
|
|
6e4ce85c87 | ||
|
|
2a093dc183 | ||
|
|
01eeadbaf4 | ||
|
|
851b3a7cfb | ||
|
|
b6dc830bcb | ||
|
|
8ef02aae41 | ||
|
|
423dbd58a1 | ||
|
|
5582db615a | ||
|
|
1479ebfb5d | ||
|
|
4389ef1e77 | ||
|
|
5c305e7fa8 | ||
|
|
0427908eae | ||
|
|
2df53c3d27 | ||
|
|
53ec9adb1b | ||
|
|
8b95a22e75 | ||
|
|
665298a04b | ||
|
|
7e668df1fe | ||
|
|
85414cfec2 | ||
|
|
b973187960 | ||
|
|
991080e613 | ||
|
|
72bf199577 | ||
|
|
7bda43a6ec | ||
|
|
2b8b0ebe95 | ||
|
|
0aa61ce58f | ||
|
|
51a5dc78d7 | ||
|
|
232bd9a22b | ||
|
|
58327a1753 | ||
|
|
7844d84798 | ||
|
|
7a30a42797 | ||
|
|
094202ff16 | ||
|
|
9c4523f4fa | ||
|
|
69859c61e0 | ||
|
|
9878518e29 | ||
|
|
cde270728f | ||
|
|
5559d0fa68 | ||
|
|
8feff78526 | ||
|
|
226a3de55d | ||
|
|
67d0f5f4ae | ||
|
|
192f5e563c | ||
|
|
b6296e7a67 | ||
|
|
67e17d3bc3 | ||
|
|
64a6fef823 | ||
|
|
e0c64cc4ff | ||
|
|
3e55478b3b | ||
|
|
9aef821862 | ||
|
|
f394df840e | ||
|
|
7d33699173 | ||
|
|
d3ffe8c647 | ||
|
|
9b99f62311 | ||
|
|
3319ce78d3 | ||
|
|
8eabf43525 | ||
|
|
adb12bb7be | ||
|
|
3c10b36651 | ||
|
|
d37c300d87 | ||
|
|
9fc92e901e | ||
|
|
5b52529295 | ||
|
|
f77a7ad623 | ||
|
|
504ef9422e | ||
|
|
cbbcec0895 | ||
|
|
32d90c38db | ||
|
|
e1f7f3d7bb | ||
|
|
244536ea72 | ||
|
|
fa24a3e09e | ||
|
|
5ec26a5015 | ||
|
|
8a8ff2aef0 | ||
|
|
069254be6a | ||
|
|
f3cd74cb46 | ||
|
|
4be8aa0f91 | ||
|
|
93dd7a85f6 | ||
|
|
062596e3fb | ||
|
|
5af2de635e | ||
|
|
a16df91fbb | ||
|
|
44178b9103 | ||
|
|
b767f930ad | ||
|
|
ba61a6545a | ||
|
|
23ada5c7a5 | ||
|
|
97c37efffe | ||
|
|
5db95be4fc | ||
|
|
5897422c70 | ||
|
|
a7db0d3cc5 | ||
|
|
c49036a713 | ||
|
|
03246997fa | ||
|
|
f4eac6e4fc | ||
|
|
48f695f3e6 | ||
|
|
3525f044f5 | ||
|
|
b58f8b9d7c | ||
|
|
c00962e881 | ||
|
|
9bcf1d662b | ||
|
|
586e0721d8 | ||
|
|
882dd1f3a7 | ||
|
|
399291d783 | ||
|
|
46ac2e5252 | ||
|
|
a81818b2db | ||
|
|
9b0d112176 | ||
|
|
ac17df0c65 | ||
|
|
c4be4e7928 | ||
|
|
877cbbd11d | ||
|
|
b2bb03310e | ||
|
|
5c8885ee5f | ||
|
|
40ec6b263d | ||
|
|
3742da8770 | ||
|
|
19b06418c5 | ||
|
|
b7b8b9219d | ||
|
|
949966964f | ||
|
|
c0a0f9c1df | ||
|
|
7cff2fa8f1 | ||
|
|
c1b703a039 | ||
|
|
e0eff1d2bb | ||
|
|
037ef76ad8 | ||
|
|
ae8025cd5c | ||
|
|
1804cc3a09 | ||
|
|
2d8e6b45ec | ||
|
|
3fa52d0d7d | ||
|
|
6a7129d7af | ||
|
|
f0e113a532 | ||
|
|
8b3e415201 | ||
|
|
eb6a8afe8d | ||
|
|
a705a89e4a | ||
|
|
ea509c0a36 | ||
|
|
269600d875 | ||
|
|
95e3a8f3cc | ||
|
|
ffeff3ab69 | ||
|
|
bdc009eb65 | ||
|
|
683f65f8ac | ||
|
|
a737698372 | ||
|
|
eeecbbcff9 | ||
|
|
44b3d60692 | ||
|
|
641c7d1967 | ||
|
|
7923d1e930 | ||
|
|
42e072a868 | ||
|
|
97296934ab | ||
|
|
83dbe5fa3e | ||
|
|
b566b8b45a | ||
|
|
ecdfda56c2 | ||
|
|
166c4a244a | ||
|
|
be7bfbac39 | ||
|
|
3c8953672d | ||
|
|
045b196eeb | ||
|
|
d763fce8ed | ||
|
|
15c8ba5d3f | ||
|
|
1b75017c3c | ||
|
|
3ffe5e958f | ||
|
|
4f6a78cde8 | ||
|
|
3081d0766b | ||
|
|
c1e34cb9b5 | ||
|
|
dedf67fb52 | ||
|
|
a74fb940aa | ||
|
|
09275ae4ca | ||
|
|
657717d0fb | ||
|
|
4493d35d26 | ||
|
|
0d26ce9bcc | ||
|
|
fe77075996 | ||
|
|
4d6b126b9d | ||
|
|
7b1900d547 | ||
|
|
5a8c56e784 | ||
|
|
8c4cfc8101 | ||
|
|
5f1f5ffffd | ||
|
|
603c4b7672 | ||
|
|
4b49c63344 | ||
|
|
9bdc910327 | ||
|
|
730f50f770 | ||
|
|
91606a9e3f | ||
|
|
22b52f831b | ||
|
|
071b3f558f | ||
|
|
59cd4004ac | ||
|
|
7f7c1ff6c2 | ||
|
|
ad3acf355e | ||
|
|
4dcc4e3308 | ||
|
|
a9902b55d8 | ||
|
|
d46798c2a7 | ||
|
|
90623492b7 | ||
|
|
ddf3ba8a15 | ||
|
|
0c4d33d558 | ||
|
|
1c3b6ad59b | ||
|
|
473a12d700 | ||
|
|
774cfc4bdc | ||
|
|
509fbcc4f8 | ||
|
|
00862344f7 | ||
|
|
5ad2b0531a | ||
|
|
be8dbb0dc7 | ||
|
|
bdfa0b302b | ||
|
|
7541304a9a | ||
|
|
395a51eeca | ||
|
|
17e2d49c43 | ||
|
|
ac71c320cd | ||
|
|
0356bf6092 | ||
|
|
8bc1edd027 | ||
|
|
403f0dc8a5 | ||
|
|
dffa198ebd | ||
|
|
7028417d88 | ||
|
|
2d4ebba3ed | ||
|
|
aa3fda9c33 | ||
|
|
0f9f0b545e | ||
|
|
9fcc398540 | ||
|
|
61f4ab61cb | ||
|
|
1f481cbe54 | ||
|
|
f4ee10a96a | ||
|
|
9974be3fdc | ||
|
|
793171e9e0 | ||
|
|
cee7087d54 | ||
|
|
f9bcffcbd5 | ||
|
|
8fd7e87333 | ||
|
|
c436194d43 | ||
|
|
fcd160cc8c | ||
|
|
5adbadc901 | ||
|
|
5084279d81 | ||
|
|
bd21d0d0cf | ||
|
|
a3fd81540a | ||
|
|
ba3f6a5e76 | ||
|
|
25c56e86c9 | ||
|
|
0897b0969d | ||
|
|
6cb1c3c0e9 | ||
|
|
df257a8e8a | ||
|
|
71abdc1bda | ||
|
|
22de1dc0f2 | ||
|
|
6357b30712 | ||
|
|
b0e18d5e8a | ||
|
|
be58d73a0a | ||
|
|
c1f630f5ed | ||
|
|
ab75bfa6e7 | ||
|
|
a4e0225c69 | ||
|
|
6d3d6c3601 | ||
|
|
2872de75a0 | ||
|
|
70936e3738 | ||
|
|
c272883ec1 | ||
|
|
d9619a8fa4 | ||
|
|
9ec2022447 | ||
|
|
10f56c55e6 | ||
|
|
69682d6d97 | ||
|
|
b61575eb2b | ||
|
|
6942de4f57 | ||
|
|
8085e21a05 | ||
|
|
0061fe02e6 |
No files matched your search
@@ -0,0 +1 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
name: Issue template
|
||||||
|
about: Please fill this issue template for reporting Mongoose issues
|
||||||
|
#title:
|
||||||
|
#labels:
|
||||||
|
#assignees:
|
||||||
|
---
|
||||||
|
|
||||||
|
- My goal is: _describe_
|
||||||
|
- My actions were: _describe_
|
||||||
|
- My expectation was: _describe_
|
||||||
|
- The result I saw: _provide logs or description_
|
||||||
|
- My question is: _your question_
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
|
||||||
|
- mongoose version: _X.Y_
|
||||||
|
- Compiler/IDE and SDK: ZZZ version _X.Y_
|
||||||
|
- Target hardware/board: _?_
|
||||||
|
- Connectivity chip/module: _?_
|
||||||
|
- Target RTOS/OS (if applicable): _?_
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
- My goal is: _describe_
|
|
||||||
- My actions were: _describe_
|
|
||||||
- My expectation was: _describe_
|
|
||||||
- The result I saw: _provide logs or description_
|
|
||||||
- My question is: _your question_
|
|
||||||
|
|
||||||
# Environment
|
|
||||||
|
|
||||||
- mongoose version: _X.Y_
|
|
||||||
- Compiler/IDE and SDK: ZZZ version _X.Y_
|
|
||||||
- Target hardware/board: _?_
|
|
||||||
- Connectivity chip/module: _?_
|
|
||||||
- Target RTOS/OS (if applicable): _?_
|
|
||||||
@@ -11,17 +11,14 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: if ./test/match_changed_files.sh '^src/' ; then echo GO=1 >> $GITHUB_ENV ; fi
|
|
||||||
- name: Build Fuzzers
|
- name: Build Fuzzers
|
||||||
id: build
|
id: build
|
||||||
if: ${{ env.GO == 1 }}
|
|
||||||
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
||||||
with:
|
with:
|
||||||
oss-fuzz-project-name: 'mongoose'
|
oss-fuzz-project-name: 'mongoose'
|
||||||
dry-run: false
|
dry-run: false
|
||||||
language: c++
|
language: c++
|
||||||
- name: Run Fuzzers
|
- name: Run Fuzzers
|
||||||
if: ${{ env.GO == 1 }}
|
|
||||||
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
||||||
with:
|
with:
|
||||||
oss-fuzz-project-name: 'mongoose'
|
oss-fuzz-project-name: 'mongoose'
|
||||||
@@ -29,8 +26,8 @@ jobs:
|
|||||||
dry-run: false
|
dry-run: false
|
||||||
language: c++
|
language: c++
|
||||||
- name: Upload Crash
|
- name: Upload Crash
|
||||||
uses: actions/upload-artifact@v1
|
uses: actions/upload-artifact@v4
|
||||||
if: env.GO == 1 && failure() && steps.build.outcome == 'success'
|
if: failure() && steps.build.outcome == 'success'
|
||||||
with:
|
with:
|
||||||
name: artifacts
|
name: artifacts
|
||||||
path: ./out/artifacts
|
path: ./out/artifacts
|
||||||
@@ -2,8 +2,8 @@ name: "CodeQL Scanning"
|
|||||||
# https://github.com/github/codeql-action
|
# https://github.com/github/codeql-action
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
#schedule:
|
||||||
- cron: '30 2 * * *' # run at 2:30 AM UTC
|
# - cron: '30 23 * * *' # run at 11:30 PM UTC
|
||||||
# Allow manual runs
|
# Allow manual runs
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
@@ -17,11 +17,11 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
security-events: write
|
security-events: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v2
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
languages: cpp
|
languages: cpp
|
||||||
- run: |
|
- run: |
|
||||||
@@ -29,4 +29,4 @@ jobs:
|
|||||||
./test/setup_ga_network.sh && make -C test mip_test CC=gcc ASAN= ASAN_OPTIONS=
|
./test/setup_ga_network.sh && make -C test mip_test CC=gcc ASAN= ASAN_OPTIONS=
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v2
|
uses: github/codeql-action/analyze@v3
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
name: Fuzz
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 21 * * *' # run at 9 PM UTC
|
||||||
|
# Allow manual runs
|
||||||
|
workflow_dispatch:
|
||||||
|
env:
|
||||||
|
CC: clang
|
||||||
|
jobs:
|
||||||
|
fuzz:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
target: [fuzz, fuzz_tls]
|
||||||
|
name: ${{ matrix.target }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 2 }
|
||||||
|
- run: make -C test ${{ matrix.target }} ARGS="-max_total_time=7200"
|
||||||
|
|
||||||
|
# as we're not getting access to test units causing a problem, convert from the log:
|
||||||
|
# base64 -d > dataofdeath
|
||||||
|
# then paste the base64 data, enter, Ctrl-D; maybe check with hexdump -C dataofdeath
|
||||||
+228
-215
@@ -1,7 +1,7 @@
|
|||||||
name: Full build and test
|
name: Full build and test
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 1 * * *' # run at 1 AM UTC
|
- cron: '0 22 * * *' # run at 10 PM UTC
|
||||||
# Allow manual runs
|
# Allow manual runs
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
env:
|
env:
|
||||||
@@ -13,7 +13,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
cc: [gcc, clang, g++, clang++]
|
cc: [gcc, clang, g++, clang++]
|
||||||
target: [test, mip_test]
|
target: [test]
|
||||||
ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL]
|
ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL]
|
||||||
select: ["-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=0", "-DMG_ENABLE_POLL=1 -DMG_ENABLE_EPOLL=0", "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=1"]
|
select: ["-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=0", "-DMG_ENABLE_POLL=1 -DMG_ENABLE_EPOLL=0", "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=1"]
|
||||||
exclude:
|
exclude:
|
||||||
@@ -33,11 +33,61 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CC: ${{ matrix.cc }}
|
CC: ${{ matrix.cc }}
|
||||||
SSL: ${{ matrix.ssl }}
|
SSL: ${{ matrix.ssl }}
|
||||||
TFLAGS: ${{ matrix.select }}
|
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST -DNO_ABORT
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: ./test/setup_ga_network.sh && sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && make -C test ${{ matrix.target }}
|
- uses: webfactory/ssh-agent@v0.9.1
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
|
||||||
|
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && test/setup_mqtt_server.sh && make -C test ${{ matrix.target }} > log
|
||||||
|
- if: success() || failure()
|
||||||
|
run: |
|
||||||
|
cat log
|
||||||
|
test/health.awk < log > json
|
||||||
|
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/linux_${{ matrix.target }}_${{ matrix.cc }}_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
|
||||||
|
mip:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
cc: [gcc, clang, g++, clang++]
|
||||||
|
target: [mip_test, mip_tap_test]
|
||||||
|
ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL]
|
||||||
|
# #3226: built-in TCP is currently not working with WolfSSL (builds fine)
|
||||||
|
exclude:
|
||||||
|
- ssl: WOLFSSL
|
||||||
|
target: mip_tap_test
|
||||||
|
name: ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }}
|
||||||
|
env:
|
||||||
|
CC: ${{ matrix.cc }}
|
||||||
|
SSL: ${{ matrix.ssl }}
|
||||||
|
TFLAGS: -DMQTT_LOCALHOST -DNO_ABORT
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 2 }
|
||||||
|
- uses: webfactory/ssh-agent@v0.9.1
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
|
||||||
|
- run: if [ "${{ matrix.target }}" == "mip_tap_test" ]; then ./test/setup_ga_network.sh ; fi && sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev && make -C test ${{ matrix.target }} IPV6=0 > log
|
||||||
|
- if: success() || failure()
|
||||||
|
run: |
|
||||||
|
cat log
|
||||||
|
test/health.awk < log > json
|
||||||
|
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/${{ matrix.target }}_${{ matrix.cc }}_${{ matrix.ssl }}_$(date +"%Y%m%d").json"
|
||||||
|
|
||||||
|
mip89:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
max-parallel: 1 # no parallel runs, to minimize MQTT errors
|
||||||
|
matrix:
|
||||||
|
target: [mip_vc98]
|
||||||
|
name: mip89 ${{ matrix.target }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 2 }
|
||||||
|
- run: make -C test ${{ matrix.target }}
|
||||||
s390:
|
s390:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -45,10 +95,12 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
ssl: ["", BUILTIN]
|
ssl: ["", BUILTIN]
|
||||||
name: S390 SSL=${{ matrix.ssl }}
|
name: S390 SSL=${{ matrix.ssl }}
|
||||||
|
env:
|
||||||
|
TFLAGS: -DMQTT_LOCALHOST
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: sudo apt -y update ; sudo apt -y install qemu binfmt-support qemu-user-static && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test s390 SSL=${{ matrix.ssl }}
|
- run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && ./test/setup_mqtt_server.sh && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test s390 SSL=${{ matrix.ssl }} MULTIREC=NO
|
||||||
armhf:
|
armhf:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -56,10 +108,12 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
ssl: ["", BUILTIN]
|
ssl: ["", BUILTIN]
|
||||||
name: ArmHF SSL=${{ matrix.ssl }}
|
name: ArmHF SSL=${{ matrix.ssl }}
|
||||||
|
env:
|
||||||
|
TFLAGS: -DMQTT_LOCALHOST
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: sudo apt -y update ; sudo apt -y install qemu binfmt-support qemu-user-static && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test armhf SSL=${{ matrix.ssl }}
|
- run: sudo apt -y update ; sudo apt -y install binfmt-support qemu-user-static && ./test/setup_mqtt_server.sh && docker run --rm --privileged multiarch/qemu-user-static --reset -p yes && make -C test armhf SSL=${{ matrix.ssl }} MULTIREC=NO
|
||||||
unamalgamated-mg_prefix:
|
unamalgamated-mg_prefix:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -71,7 +125,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev
|
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev
|
||||||
- run: make -C test unamalgamated && make -C test mg_prefix
|
- run: make -C test unamalgamated SSL=${{ matrix.ssl }} && make -C test mg_prefix
|
||||||
valgrind:
|
valgrind:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -79,35 +133,53 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL]
|
ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL]
|
||||||
name: Valgrind SSL=${{ matrix.ssl }}
|
name: Valgrind SSL=${{ matrix.ssl }}
|
||||||
|
env:
|
||||||
|
TFLAGS: -DMQTT_LOCALHOST
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev valgrind
|
- run: sudo apt -y update ; sudo apt -y install libmbedtls-dev libwolfssl-dev valgrind
|
||||||
- run: make -C test valgrind SSL=${{ matrix.ssl }}
|
- run: ./test/setup_mqtt_server.sh && make -C test valgrind SSL=${{ matrix.ssl }}
|
||||||
macos:
|
macos:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
ssl: ["", BUILTIN, MBEDTLS, OPENSSL, WOLFSSL]
|
# Mongoose does not work with WolfSSL version in MacOS
|
||||||
|
ssl: ["", BUILTIN, MBEDTLS, OPENSSL] # , WOLFSSL]
|
||||||
select: [-DMG_ENABLE_POLL=0, -DMG_ENABLE_POLL=1]
|
select: [-DMG_ENABLE_POLL=0, -DMG_ENABLE_POLL=1]
|
||||||
|
include:
|
||||||
|
- ssl: MBEDTLS
|
||||||
|
env:
|
||||||
|
# MbedTLS version in MacOS refuses to validate a certificate without a hostname, causing MQTT tests to fail when using MQTT_LOCALHOST
|
||||||
|
tflags: -DNO_MQTT_TESTS
|
||||||
exclude:
|
exclude:
|
||||||
- ssl: MBEDTLS
|
- ssl: MBEDTLS
|
||||||
select: -DMG_ENABLE_POLL=0
|
select: -DMG_ENABLE_POLL=0
|
||||||
- ssl: OPENSSL
|
- ssl: OPENSSL
|
||||||
select: -DMG_ENABLE_POLL=0
|
select: -DMG_ENABLE_POLL=0
|
||||||
- ssl: WOLFSSL
|
#- ssl: WOLFSSL
|
||||||
select: -DMG_ENABLE_POLL=0
|
# select: -DMG_ENABLE_POLL=0
|
||||||
name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
|
name: macos SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
|
||||||
env:
|
env:
|
||||||
SSL: ${{ matrix.ssl }}
|
SSL: ${{ matrix.ssl }}
|
||||||
TFLAGS: ${{ matrix.select }} -DNO_SNTP_CHECK -Wno-sign-conversion # Workaround for MbedTLS 3.5.0
|
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST ${{ matrix.env.tflags }} -Wno-sign-conversion # Workaround for MbedTLS 3.5.0
|
||||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: brew install mbedtls wolfssl # jq openssl already pre-installed
|
- uses: webfactory/ssh-agent@v0.9.1
|
||||||
- run: make -C test test ASAN_OPTIONS= MBEDTLS=$(echo $(brew --cellar)/mbedtls*/*) OPENSSL=$(echo $(brew --cellar)/openssl*/*) WOLFSSL=$(echo $(brew --cellar)/wolfssl*/*)
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
|
||||||
|
- run: brew install mbedtls wolfssl mosquitto gawk # jq openssl already pre-installed
|
||||||
|
- run: /opt/homebrew/opt/mosquitto/sbin/mosquitto -c /Users/runner/work/mongoose/mongoose/test/mosquitto.conf.macos &
|
||||||
|
- run: make -C test test ASAN_OPTIONS= MBEDTLS=$(echo $(brew --cellar)/mbedtls*/*) OPENSSL=$(echo $(brew --cellar)/openssl*/*) WOLFSSL=$(echo $(brew --cellar)/wolfssl*/*) > log
|
||||||
|
- if: success() || failure()
|
||||||
|
run: |
|
||||||
|
cat log
|
||||||
|
test/health.awk < log > json
|
||||||
|
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/macos_test_cc_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
|
||||||
|
|
||||||
windows:
|
windows:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -122,12 +194,21 @@ jobs:
|
|||||||
select: -DMG_ENABLE_POLL=1
|
select: -DMG_ENABLE_POLL=1
|
||||||
name: windows ${{ matrix.target }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
|
name: windows ${{ matrix.target }} SSL=${{ matrix.ssl }} TFLAGS=${{ matrix.select }}
|
||||||
env:
|
env:
|
||||||
SSL: SSL=${{ matrix.ssl }}
|
SSL: ${{ matrix.ssl }}
|
||||||
TFLAGS: ${{ matrix.select }}
|
TFLAGS: ${{ matrix.select }} -DMQTT_LOCALHOST
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: make -C test ${{ matrix.target }}
|
- uses: webfactory/ssh-agent@v0.9.1
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
|
||||||
|
- run: ./test/setup_mqtt_server.sh && make -C test ${{ matrix.target }} > log
|
||||||
|
- if: success() || failure()
|
||||||
|
run: |
|
||||||
|
cat log
|
||||||
|
test/health.awk < log > json
|
||||||
|
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/windows_${{ matrix.target }}_${{ matrix.cc }}_${{ matrix.ssl }}_${{ matrix.select }}_$(date +"%Y%m%d").json"
|
||||||
|
|
||||||
arm:
|
arm:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -149,109 +230,33 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- run: make -C test riscv SSL=${{ matrix.ssl }}
|
- run: make -C test riscv SSL=${{ matrix.ssl }}
|
||||||
|
|
||||||
examples:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
|
|
||||||
name: examples ${{ matrix.ssl }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- run: sudo apt -y install libpcap-dev
|
|
||||||
- run: make -C test examples CFLAGS_EXTRA="${{ matrix.ssl }}"
|
|
||||||
- run: make -C test clean_examples
|
|
||||||
examples_win:
|
|
||||||
runs-on: windows-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
|
|
||||||
name: examples_win ${{ matrix.ssl }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
# - uses: egor-tensin/setup-mingw@v2
|
|
||||||
# with:
|
|
||||||
# platform: x64
|
|
||||||
- name: test they build
|
|
||||||
run: make -C test examples_win CFLAGS_EXTRA="${{ matrix.ssl }}"
|
|
||||||
shell: cmd
|
|
||||||
- name: test they clean
|
|
||||||
run: make -C test clean_examples_win
|
|
||||||
shell: cmd
|
|
||||||
examples_mac:
|
|
||||||
runs-on: macos-latest
|
|
||||||
env: { HOMEBREW_NO_AUTO_UPDATE: 1 }
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
|
|
||||||
name: examples_mac ${{ matrix.ssl }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- run: make -C test examples_mac CFLAGS_EXTRA="${{ matrix.ssl }}"
|
|
||||||
- run: make -C test clean_examples_mac
|
|
||||||
|
|
||||||
refprojs:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
|
|
||||||
name: reference-projects ${{ matrix.ssl }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- run: make -C test refprojs CFLAGS_EXTRA="${{ matrix.ssl }}"
|
|
||||||
- run: make -C test clean_refprojs
|
|
||||||
refprojs_win:
|
|
||||||
runs-on: windows-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
|
|
||||||
name: reference-projects_win ${{ matrix.ssl }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
# - uses: egor-tensin/setup-mingw@v2
|
|
||||||
# with:
|
|
||||||
# platform: x64
|
|
||||||
- name: test they build
|
|
||||||
run: make -C test refprojs_win CFLAGS_EXTRA="${{ matrix.ssl }}"
|
|
||||||
shell: cmd
|
|
||||||
- name: test they clean
|
|
||||||
run: make -C test clean_refprojs_win
|
|
||||||
shell: cmd
|
|
||||||
refprojs_mac:
|
|
||||||
runs-on: macos-latest
|
|
||||||
env: { HOMEBREW_NO_AUTO_UPDATE: 1 }
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
|
|
||||||
name: reference-projects_mac ${{ matrix.ssl }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- run: make -C test refprojs CFLAGS_EXTRA="${{ matrix.ssl }}"
|
|
||||||
- run: make -C test clean_refprojs
|
|
||||||
|
|
||||||
tutorials:
|
tutorials:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
|
ssl: [-DMG_TLS=MG_TLS_NONE, -DMG_TLS=MG_TLS_BUILTIN]
|
||||||
name: tutorials ${{ matrix.ssl }}
|
name: tutorials ${{ matrix.ssl }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- uses: webfactory/ssh-agent@v0.9.1
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.HEALTH_TESTS_SSH_KEY }}
|
||||||
- run: sudo apt -y install libpcap-dev
|
- run: sudo apt -y install libpcap-dev
|
||||||
- run: make -C test tutorials CFLAGS_EXTRA="${{ matrix.ssl }}"
|
- run: make -C test tutorials CFLAGS_EXTRA="${{ matrix.ssl }}" > log
|
||||||
|
- if: success() || failure()
|
||||||
|
run: |
|
||||||
|
cat log
|
||||||
|
test/health.awk < log > json
|
||||||
|
scp -o "StrictHostKeyChecking=no" json "root@176.9.217.245:/data/downloads/health/tutorials_${{ matrix.ssl }}_$(date +"%Y%m%d").json"
|
||||||
- run: make -C test clean_tutorials
|
- run: make -C test clean_tutorials
|
||||||
|
|
||||||
tutorials_win:
|
tutorials_win:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
|
ssl: [-DMG_TLS=MG_TLS_NONE, -DMG_TLS=MG_TLS_BUILTIN]
|
||||||
name: tutorials_win ${{ matrix.ssl }}
|
name: tutorials_win ${{ matrix.ssl }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -270,7 +275,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
|
ssl: [-DMG_TLS=MG_TLS_NONE, -DMG_TLS=MG_TLS_BUILTIN]
|
||||||
name: tutorials_mac ${{ matrix.ssl }}
|
name: tutorials_mac ${{ matrix.ssl }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -284,9 +289,67 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: echo # nothing specific to install or do
|
- run: echo # nothing specific to install or do
|
||||||
- run: make -C examples/arduino arduino-xiao
|
- run: make -C test/arduino
|
||||||
# - run: make -C examples/arduino arduino-nano
|
- run: make -C test/arduino cleanall
|
||||||
- run: make -C examples/arduino clean
|
|
||||||
|
|
||||||
|
# wizard_examples:
|
||||||
|
# runs-on: ubuntu-latest
|
||||||
|
# strategy:
|
||||||
|
# fail-fast: false
|
||||||
|
# matrix:
|
||||||
|
# example:
|
||||||
|
# - path: esp32/esp32-idf
|
||||||
|
# name: ${{ matrix.example.path }}
|
||||||
|
# env:
|
||||||
|
# GO: 0
|
||||||
|
# steps:
|
||||||
|
# - uses: actions/checkout@v4
|
||||||
|
# with: { fetch-depth: 2 }
|
||||||
|
# - run: echo # nothing specific to install or do
|
||||||
|
# fi
|
||||||
|
# - run: make -C tutorials/${{ matrix.example.path }} build
|
||||||
|
|
||||||
|
wizard_examples_arm:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
example:
|
||||||
|
- path: infineon/xmc47_relax-make-baremetal-builtin
|
||||||
|
- path: infineon/xmc_plt2go_4400-make-baremetal-builtin
|
||||||
|
- path: infineon/xmc72_evk-make-baremetal-builtin
|
||||||
|
- path: nxp/frdm-mcxn947-make-baremetal-builtin
|
||||||
|
- path: nxp/frdm-mcxn947-make-freertos-builtin
|
||||||
|
- path: nxp/rt1020-evk-make-baremetal-builtin
|
||||||
|
- path: nxp/rt1060-evk-make-baremetal-builtin
|
||||||
|
- path: nxp/rt1170-evk-make-baremetal-builtin
|
||||||
|
- path: pico-sdk/pico-w-picosdk-baremetal-builtin
|
||||||
|
- path: pico-sdk/pico-2-w-picosdk-baremetal-builtin
|
||||||
|
- path: pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin
|
||||||
|
- path: pico-sdk/w5500-evb-pico2-picosdk-baremetal-builtin
|
||||||
|
- path: stm32/nucleo-f429zi-make-baremetal-builtin
|
||||||
|
- path: stm32/nucleo-f429zi-make-freertos-builtin
|
||||||
|
- path: stm32/nucleo-f746zg-make-baremetal-builtin
|
||||||
|
- path: stm32/nucleo-f746zg-make-freertos-builtin
|
||||||
|
- path: stm32/nucleo-h563zi-make-baremetal-builtin
|
||||||
|
- path: stm32/nucleo-h563zi-make-freertos-builtin
|
||||||
|
- path: stm32/nucleo-h723zg-make-baremetal-builtin
|
||||||
|
- path: stm32/nucleo-h723zg-make-freertos-builtin
|
||||||
|
- path: stm32/nucleo-h743zi-make-baremetal-builtin
|
||||||
|
- path: stm32/nucleo-h743zi-make-freertos-builtin
|
||||||
|
- path: stm32/stm32h573i-dk-make-baremetal-builtin
|
||||||
|
- path: stm32/stm32h573i-dk-make-freertos-builtin
|
||||||
|
- path: ti/ek-tm4c1294xl-make-baremetal-builtin
|
||||||
|
- path: ti/ek-tm4c1294xl-make-freertos-builtin
|
||||||
|
name: ${{ matrix.example.path }}
|
||||||
|
env:
|
||||||
|
GO: 0
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 2 }
|
||||||
|
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
|
- run: make -C tutorials/${{ matrix.example.path }} build
|
||||||
|
|
||||||
|
|
||||||
generic_examples:
|
generic_examples:
|
||||||
@@ -295,18 +358,17 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
example:
|
example:
|
||||||
- path: esp32/uart-bridge
|
- path: micropython/esp32
|
||||||
- path: esp32/micropython
|
- path: http/uart-bridge/esp32
|
||||||
- path: esp8266/http-client-server
|
- path: http/http-client/esp8266/http-client-server
|
||||||
name: ${{ matrix.example.path }}
|
name: ${{ matrix.example.path }}
|
||||||
env:
|
env:
|
||||||
GO: 0
|
GO: 0
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: if ./test/match_changed_files.sh '^src|^examples/${{ matrix.example.path }}'; then echo GO=1 >> $GITHUB_ENV ; fi
|
|
||||||
- run: echo # nothing specific to install or do
|
- run: echo # nothing specific to install or do
|
||||||
- run: make -C examples/${{ matrix.example.path }} build
|
- run: make -C tutorials/${{ matrix.example.path }} build
|
||||||
|
|
||||||
generic_examples_arm:
|
generic_examples_arm:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -314,9 +376,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
example:
|
example:
|
||||||
- path: microchip/same54-xpro/mqtt-client
|
- path: mqtt/mqtt-client/microchip/same54-xpro
|
||||||
- path: infineon/infineon-xmc4700_4800-lwip-rtx-rtos
|
|
||||||
- path: nxp/nxp-mimxrt1020-azurertos
|
|
||||||
- path: nxp/nxp-frdmk66f-freertos
|
- path: nxp/nxp-frdmk66f-freertos
|
||||||
- path: nxp/nxp-lpcxpresso54s018m-freertos
|
- path: nxp/nxp-lpcxpresso54s018m-freertos
|
||||||
- path: nxp/nxp-mimxrt1020-freertos
|
- path: nxp/nxp-mimxrt1020-freertos
|
||||||
@@ -335,7 +395,7 @@ jobs:
|
|||||||
- path: nxp/nxp-lpcxpresso54628-lwip-freertos
|
- path: nxp/nxp-lpcxpresso54628-lwip-freertos
|
||||||
- path: nxp/nxp-twrk65f180m-lwip-freertos
|
- path: nxp/nxp-twrk65f180m-lwip-freertos
|
||||||
- path: nxp/nxp-twrkv58f220m-lwip-freertos
|
- path: nxp/nxp-twrkv58f220m-lwip-freertos
|
||||||
- path: rp2040/pico-rmii
|
- path: pico-sdk/pico-rmii
|
||||||
- path: stm32/nucleo-f429zi-make-baremetal-builtin-rndis
|
- path: stm32/nucleo-f429zi-make-baremetal-builtin-rndis
|
||||||
- path: stm32/nucleo-f746zg-make-baremetal-builtin-rndis
|
- path: stm32/nucleo-f746zg-make-baremetal-builtin-rndis
|
||||||
- path: stm32/nucleo-g031-make-baremetal-builtin
|
- path: stm32/nucleo-g031-make-baremetal-builtin
|
||||||
@@ -346,7 +406,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/${{ matrix.example.path }} build
|
- run: make -C tutorials/${{ matrix.example.path }} build
|
||||||
|
|
||||||
device_dashboard_examples:
|
device_dashboard_examples:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -354,13 +414,14 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
example:
|
example:
|
||||||
- path: esp32/device-dashboard
|
- path: esp32
|
||||||
name: ${{ matrix.example.path }}
|
name: ${{ matrix.example.path }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: echo # nothing specific to install or do
|
- run: echo # nothing specific to install or do
|
||||||
- run: make -C examples/${{ matrix.example.path }} build
|
- run: make -C tutorials/http/device-dashboard/${{ matrix.example.path }} build
|
||||||
|
|
||||||
|
|
||||||
device_dashboard_examples_arm:
|
device_dashboard_examples_arm:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -369,37 +430,22 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
|
ssl: ["", -DMG_TLS=MG_TLS_BUILTIN]
|
||||||
example:
|
example:
|
||||||
- path: microchip/same54-xpro/device-dashboard
|
- path: http/device-dashboard/microchip/same54-xpro
|
||||||
- path: nxp/rt1020-evk-make-baremetal-builtin
|
|
||||||
- path: nxp/rt1020-evk-make-freertos-builtin
|
- path: nxp/rt1020-evk-make-freertos-builtin
|
||||||
- path: nxp/rt1060-evk-make-baremetal-builtin
|
|
||||||
- path: nxp/rt1060-evk-make-freertos-builtin
|
- path: nxp/rt1060-evk-make-freertos-builtin
|
||||||
- path: nxp/rt1170-evk-make-baremetal-builtin
|
- path: nxp/rt1170-evk-make-freertos-builtin
|
||||||
- path: renesas/ek-ra6m4-make-baremetal-builtin
|
- path: renesas/ek-ra6m4-make-baremetal-builtin
|
||||||
- path: rp2040/pico-rndis-dashboard
|
- path: pico-sdk/pico-rndis-dashboard
|
||||||
- path: rp2040/pico-w
|
- path: pico-sdk/pico-w-picosdk-freertos-lwip
|
||||||
- path: rp2040/pico-w5500
|
- path: pico-sdk/pico-2-w-picosdk-freertos-lwip
|
||||||
- path: stm32/nucleo-f429zi-make-baremetal-builtin
|
|
||||||
- path: stm32/nucleo-f429zi-make-freertos-builtin
|
|
||||||
- path: stm32/nucleo-f746zg-make-baremetal-builtin
|
|
||||||
- path: stm32/nucleo-f746zg-make-freertos-builtin
|
|
||||||
- path: stm32/nucleo-f746zg-make-freertos-tcp
|
- path: stm32/nucleo-f746zg-make-freertos-tcp
|
||||||
- path: stm32/nucleo-f746zg-make-baremetal-builtin-cmsis_driver
|
- path: stm32/nucleo-f746zg-make-baremetal-builtin-cmsis_driver
|
||||||
- path: stm32/nucleo-h563zi-make-baremetal-builtin
|
|
||||||
- path: stm32/nucleo-h563zi-make-freertos-builtin
|
|
||||||
- path: stm32/nucleo-h723zg-make-freertos-builtin
|
|
||||||
- path: stm32/nucleo-h743zi-make-baremetal-builtin
|
|
||||||
- path: stm32/nucleo-h743zi-make-freertos-builtin
|
|
||||||
- path: stm32/stm32h573i-dk-make-baremetal-builtin
|
|
||||||
- path: stm32/stm32h573i-dk-make-freertos-builtin
|
|
||||||
- path: ti/ek-tm4c1294xl-make-baremetal-builtin
|
|
||||||
- path: ti/ek-tm4c1294xl-make-freertos-builtin
|
|
||||||
name: ${{ matrix.example.path }} ${{ matrix.ssl }}
|
name: ${{ matrix.example.path }} ${{ matrix.ssl }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/${{ matrix.example.path }} build CFLAGS_EXTRA="${{ matrix.ssl }}"
|
- run: make -C tutorials/${{ matrix.example.path }} build CFLAGS_EXTRA="${{ matrix.ssl }}"
|
||||||
|
|
||||||
# mqtt_dashboard_examples:
|
# mqtt_dashboard_examples:
|
||||||
# runs-on: ubuntu-latest
|
# runs-on: ubuntu-latest
|
||||||
@@ -413,7 +459,7 @@ jobs:
|
|||||||
# - uses: actions/checkout@v4
|
# - uses: actions/checkout@v4
|
||||||
# with: { fetch-depth: 2 }
|
# with: { fetch-depth: 2 }
|
||||||
# - run: echo # nothing specific to install or do
|
# - run: echo # nothing specific to install or do
|
||||||
# - run: make -C examples/${{ matrix.example.path }} build
|
# - run: make -C tutorials/${{ matrix.example.path }} build
|
||||||
|
|
||||||
mqtt_dashboard_examples_arm:
|
mqtt_dashboard_examples_arm:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -421,13 +467,13 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
example:
|
example:
|
||||||
- path: rp2040/pico-rndis-device
|
- path: pico-sdk/pico-rndis-device
|
||||||
name: ${{ matrix.example.path }}
|
name: ${{ matrix.example.path }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/${{ matrix.example.path }} build
|
- run: make -C tutorials/${{ matrix.example.path }} build
|
||||||
|
|
||||||
# dual_examples:
|
# dual_examples:
|
||||||
# runs-on: ubuntu-latest
|
# runs-on: ubuntu-latest
|
||||||
@@ -441,50 +487,17 @@ jobs:
|
|||||||
# - uses: actions/checkout@v4
|
# - uses: actions/checkout@v4
|
||||||
# with: { fetch-depth: 2 }
|
# with: { fetch-depth: 2 }
|
||||||
# - run: echo # nothing specific to install or do
|
# - run: echo # nothing specific to install or do
|
||||||
# - run: make -C examples/${{ matrix.example.path }} device_dashboard
|
# - run: make -C tutorials/${{ matrix.example.path }} device_dashboard
|
||||||
# - run: make -C examples/${{ matrix.example.path }} mqtt_dashboard
|
# - run: make -C tutorials/${{ matrix.example.path }} mqtt_dashboard
|
||||||
|
|
||||||
dual_examples_arm:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
example:
|
|
||||||
- path: stm32/nucleo-h723zg-make-baremetal-builtin
|
|
||||||
name: ${{ matrix.example.path }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with: { fetch-depth: 2 }
|
|
||||||
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
|
||||||
- run: make -C examples/${{ matrix.example.path }} device_dashboard
|
|
||||||
- run: make -C examples/${{ matrix.example.path }} mqtt_dashboard
|
|
||||||
|
|
||||||
cube_examples:
|
cube_examples:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- run: echo # nothing specific to install or do
|
- run: sudo pip install yq
|
||||||
- run: cd test/cube && make
|
- run: cd test/cube && make
|
||||||
|
|
||||||
zephyr_examples:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with: { fetch-depth: 2 }
|
|
||||||
- run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
|
||||||
- run: make -C examples/zephyr init
|
|
||||||
- name: minify manifest
|
|
||||||
uses: mikefarah/yq@master
|
|
||||||
with:
|
|
||||||
cmd: yq -i eval '(.manifest.defaults, .manifest.remotes, .manifest.projects[] | select(.name == "cmsis" or .name == "hal_stm32" or .name == "mbedtls" or .name == "mcuboot" or .name == "picolibc" | del(.null) ), .manifest.self) as $i ireduce({};setpath($i | path; $i)) | del(.manifest.projects.[].null) | del(..|select(length==0))' examples/zephyr/zephyrproject/zephyr/west.yml
|
|
||||||
- run: make -C examples/zephyr update
|
|
||||||
- run: make -C examples/zephyr/device-dashboard build
|
|
||||||
- run: make -C examples/zephyr/http-client build
|
|
||||||
- run: make -C examples/zephyr/http-server build
|
|
||||||
- run: make -C examples/zephyr/mqtt-aws-client build
|
|
||||||
- run: make -C examples/zephyr/websocket-server build
|
|
||||||
|
|
||||||
test_f7:
|
test_f7:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -492,14 +505,14 @@ jobs:
|
|||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- name: baremetal
|
- name: baremetal
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/stm32/nucleo-f746zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/stm32/nucleo-f746zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
- run: make -C examples/stm32/nucleo-f746zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/stm32/nucleo-f746zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
- run: make -C examples/stm32/nucleo-f746zg-make-freertos-tcp test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/stm32/nucleo-f746zg-make-freertos-tcp test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
- name: Cube
|
- name: Cube
|
||||||
run: echo # nothing specific to install or do
|
run: echo # nothing specific to install or do
|
||||||
- run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f746zg-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
|
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
|
||||||
- run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f746zg-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
|
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
|
||||||
- run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f746zg-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
|
- run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f746zg-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=5
|
||||||
|
|
||||||
test_f4:
|
test_f4:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -508,13 +521,13 @@ jobs:
|
|||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- name: baremetal
|
- name: baremetal
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/stm32/nucleo-f429zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/stm32/nucleo-f429zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
- run: make -C examples/stm32/nucleo-f429zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/stm32/nucleo-f429zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
- name: Cube
|
- name: Cube
|
||||||
run: echo # nothing specific to install or do
|
run: echo # nothing specific to install or do
|
||||||
- run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f429zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
|
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
|
||||||
- run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f429zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
|
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
|
||||||
- run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-f429zi-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
|
- run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-f429zi-cube-freertos-lwip VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=2
|
||||||
|
|
||||||
test_h743:
|
test_h743:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -523,12 +536,12 @@ jobs:
|
|||||||
with: { fetch-depth: 3 }
|
with: { fetch-depth: 3 }
|
||||||
- name: baremetal
|
- name: baremetal
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/stm32/nucleo-h743zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/stm32/nucleo-h743zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
- run: make -C examples/stm32/nucleo-h743zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/stm32/nucleo-h743zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
- name: Cube
|
# - name: Cube
|
||||||
run: echo # nothing specific to install or do
|
# run: echo # nothing specific to install or do
|
||||||
- run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-h743zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
|
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-baremetal-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
|
||||||
- run: make -C test/cube test PROJECTS=../../examples/stm32/nucleo-h743zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
|
# - run: make -C test/cube PROJECTS=../../tutorials/stm32/nucleo-h743zi-cube-freertos-builtin VCON_API_KEY=${{secrets.VCON_API_KEY}} DEVICE=6
|
||||||
|
|
||||||
test_h723:
|
test_h723:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -537,8 +550,8 @@ jobs:
|
|||||||
with: { fetch-depth: 3 }
|
with: { fetch-depth: 3 }
|
||||||
- name: baremetal
|
- name: baremetal
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/stm32/nucleo-h723zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/stm32/nucleo-h723zg-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
- run: make -C examples/stm32/nucleo-h723zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/stm32/nucleo-h723zg-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
test_h5:
|
test_h5:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -547,8 +560,8 @@ jobs:
|
|||||||
with: { fetch-depth: 3 }
|
with: { fetch-depth: 3 }
|
||||||
- name: baremetal
|
- name: baremetal
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/stm32/nucleo-h563zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/stm32/nucleo-h563zi-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
- run: make -C examples/stm32/nucleo-h563zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/stm32/nucleo-h563zi-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
test_rt1020:
|
test_rt1020:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -557,8 +570,8 @@ jobs:
|
|||||||
with: { fetch-depth: 3 }
|
with: { fetch-depth: 3 }
|
||||||
- name: baremetal
|
- name: baremetal
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/nxp/rt1020-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/nxp/rt1020-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
- run: make -C examples/nxp/rt1020-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/nxp/rt1020-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
test_rt1060:
|
test_rt1060:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -567,8 +580,8 @@ jobs:
|
|||||||
with: { fetch-depth: 3 }
|
with: { fetch-depth: 3 }
|
||||||
- name: baremetal
|
- name: baremetal
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/nxp/rt1060-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/nxp/rt1060-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
- run: make -C examples/nxp/rt1060-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/nxp/rt1060-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
test_rt1170:
|
test_rt1170:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -577,8 +590,8 @@ jobs:
|
|||||||
with: { fetch-depth: 3 }
|
with: { fetch-depth: 3 }
|
||||||
- name: baremetal
|
- name: baremetal
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/nxp/rt1170-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/nxp/rt1170-evk-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
# - run: make -C examples/nxp/rt1170-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/nxp/rt1170-evk-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
test_ra6m4:
|
test_ra6m4:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -587,8 +600,8 @@ jobs:
|
|||||||
with: { fetch-depth: 3 }
|
with: { fetch-depth: 3 }
|
||||||
- name: baremetal
|
- name: baremetal
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/renesas/ek-ra6m4-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/renesas/ek-ra6m4-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
# - run: make -C examples/renesas/ek-ra6m4-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
# - run: make -C tutorials/renesas/ek-ra6m4-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
test_tm4c:
|
test_tm4c:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -597,8 +610,8 @@ jobs:
|
|||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- name: baremetal
|
- name: baremetal
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/ti/ek-tm4c1294xl-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/ti/ek-tm4c1294xl-make-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
- run: make -C examples/ti/ek-tm4c1294xl-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/ti/ek-tm4c1294xl-make-freertos-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
test_same54:
|
test_same54:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -607,8 +620,8 @@ jobs:
|
|||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- name: baremetal
|
- name: baremetal
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/microchip/same54-xpro/device-dashboard test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/http/device-dashboard/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
- run: make -C examples/microchip/same54-xpro/mqtt-client test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/mqtt/mqtt-client/microchip/same54-xpro test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
test_pico_w5500:
|
test_pico_w5500:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -617,5 +630,5 @@ jobs:
|
|||||||
with: { fetch-depth: 2 }
|
with: { fetch-depth: 2 }
|
||||||
- name: SDK
|
- name: SDK
|
||||||
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
run: sudo apt -y update && sudo apt -y install gcc-arm-none-eabi
|
||||||
- run: make -C examples/rp2040/pico-w5500 test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
- run: make -C tutorials/pico-sdk/w5500-evb-pico-picosdk-baremetal-builtin test VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
|
||||||
+500
-548
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,26 @@
|
|||||||
|
name: Zephyr
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * *' # run at 12 AM UTC
|
||||||
|
# Allow manual runs
|
||||||
|
workflow_dispatch:
|
||||||
|
jobs:
|
||||||
|
zephyr_examples:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
revno: ["--mr v3.7-branch", "--mr v4.2.0"] # LTS, latest stable
|
||||||
|
name: Zephyr ${{ matrix.revno }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with: { fetch-depth: 2 }
|
||||||
|
- run: test/setup_ga_docker_filesystem.sh
|
||||||
|
- run: make -C tutorials/zephyr init REPO=zephyrprojectrtos/ci REVNO="${{ matrix.revno }}"
|
||||||
|
- run: make -C tutorials/zephyr minify REVNO="${{ matrix.revno }}"
|
||||||
|
- run: make -C tutorials/zephyr update
|
||||||
|
- run: make -C tutorials/zephyr/device-dashboard build
|
||||||
|
- run: make -C tutorials/zephyr/http-client build
|
||||||
|
- run: make -C tutorials/zephyr/http-server build
|
||||||
|
- run: make -C tutorials/zephyr/mqtt-aws-client build
|
||||||
|
- run: make -C tutorials/zephyr/websocket-server build
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
Copyright (c) 2004-2013 Sergey Lyubka
|
Copyright (c) 2004-2013 Sergey Lyubka
|
||||||
Copyright (c) 2013-2024 Cesanta Software Limited
|
Copyright (c) 2013-2025 Cesanta Software Limited
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
This software is dual-licensed: you can redistribute it and/or modify
|
This software is dual-licensed: you can redistribute it and/or modify
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
# Mongoose - Embedded Web Server / Embedded Network Library
|
# Mongoose - Embedded Web Server / Embedded Network Library
|
||||||
|
|
||||||
[](https://opensource.org/licenses/gpl-2.0.php)
|
[](https://opensource.org/licenses/gpl-2.0.php)
|
||||||
[](https://github.com/cesanta/mongoose/actions)
|
[](https://github.com/cesanta/mongoose/actions)
|
||||||
[](https://codecov.io/gh/cesanta/mongoose)
|
[](https://codecov.io/gh/cesanta/mongoose)
|
||||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:mongoose)
|
[](https://issues.oss-fuzz.com/issues?sort=-opened&can=1&q=proj:mongoose)
|
||||||
|
|
||||||
Mongoose is a network library for C/C++. It provides event-driven non-blocking
|
Mongoose is a network library for C/C++. It provides event-driven non-blocking
|
||||||
APIs for TCP, UDP, HTTP, WebSocket, MQTT, and other protocols. It is designed
|
APIs for TCP, UDP, HTTP, WebSocket, MQTT, and other protocols. It is designed
|
||||||
@@ -14,7 +14,7 @@ robust, and easy. Features include:
|
|||||||
|
|
||||||
- Cross-platform:
|
- Cross-platform:
|
||||||
- works on Linux/UNIX, MacOS, Windows, Android
|
- works on Linux/UNIX, MacOS, Windows, Android
|
||||||
- works on STM32, NXP, ESP32, NRF52, TI, Microchip, and other
|
- works on ST, NXP, ESP32, Nordic, TI, Microchip, Infineon, Renesas and other chips
|
||||||
- write code once - and it'll work everywhere
|
- write code once - and it'll work everywhere
|
||||||
- ideal for the unification of the network infrastructure code across company
|
- ideal for the unification of the network infrastructure code across company
|
||||||
- Built-in protocols: plain TCP/UDP, SNTP, HTTP, MQTT, Websocket, and other
|
- Built-in protocols: plain TCP/UDP, SNTP, HTTP, MQTT, Websocket, and other
|
||||||
@@ -34,6 +34,35 @@ robust, and easy. Features include:
|
|||||||
|
|
||||||
See https://mongoose.ws/ for complete documentation, videos, case studies, etc.
|
See https://mongoose.ws/ for complete documentation, videos, case studies, etc.
|
||||||
|
|
||||||
|
## Supported platforms
|
||||||
|
|
||||||
|
Mongoose can work on top of any TCP/IP stack that supports BSD sockets API.
|
||||||
|
Platforms supported by the 3rd party TCP/IP stacks:
|
||||||
|
|
||||||
|
| TCP/IP stack | Notes |
|
||||||
|
| :-------------- | :------- |
|
||||||
|
| **lwIP** | All devices running lwIP, for example ESP32, ESP32S3, ESP32C3, ESP32C6, etc |
|
||||||
|
| **Zephyr** | All devices supported by Zephyr |
|
||||||
|
| **Other** | Any other TCP/IP stack that supports BSD socket API, for example Amazon FreeRTOS-TCP |
|
||||||
|
| **Linux, Mac, Windows** | Workstations, server, single board computers, embedded Linux devices running on MPUs or FPGAs |
|
||||||
|
|
||||||
|
Optionally, Mongoose provides its own built-in TCP/IP stack, eliminating the
|
||||||
|
need for additional software to implement networking functionality. The
|
||||||
|
built-in stack supports operation in both bare-metal and RTOS environments.
|
||||||
|
Platforms supported by the Mongoose built-in TCP/IP stack:
|
||||||
|
|
||||||
|
| Hardware | Notes |
|
||||||
|
| :------------- | :------- |
|
||||||
|
| **STM32** | All STM32 MCUs with built-in Ethernet: STM32Fxx, STM32H5xx, STM32H7xx |
|
||||||
|
| **NXP** | All NXP MCUs with built-in Ethernet: IMXRT102x, IMXRT104x, IMXRT105x, IMXRT106x, IMXRT117x, RW612, MCXN94x |
|
||||||
|
| **Microchip** | ATSAME54 MCUs with built-int Ethernet |
|
||||||
|
| **Renesas** | RA5M, RA6M, RA8M MCUs with built-in Ethernet |
|
||||||
|
| **Infineon** | XMC4, XMC7 MCUs with built-in Ethernet |
|
||||||
|
| **Texas Instruments** | TM4C, TMS570 MCUs with built-in Ethernet |
|
||||||
|
| **Cypress WiFi** | Any MCU with CY43xx WiFi chips, like RP2040 Pico-W, RP2350 Pico2-W, Arduino Portenta |
|
||||||
|
| **Wiznet Ethernet** | Any MCU that use Wiznet W5500 or Wiznet 5100 MAC+PHY chips |
|
||||||
|
| **Cellular** | NRF9160, SIM800 |
|
||||||
|
|
||||||
## Usage Examples
|
## Usage Examples
|
||||||
|
|
||||||
Below are quick snippets that should give an idea how simple the API is and
|
Below are quick snippets that should give an idea how simple the API is and
|
||||||
@@ -70,7 +99,7 @@ HTTP server implements a REST API that returns current time. JSON formatting:
|
|||||||
static void ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
static void ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||||
if (ev == MG_EV_HTTP_MSG) {
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
if (mg_http_match_uri(hm, "/api/time/get")) {
|
if (mg_match(hm->uri, mg_str("/api/time/get"), NULL)) {
|
||||||
mg_http_reply(c, 200, "", "{%m:%lu}\n", MG_ESC("time"), time(NULL));
|
mg_http_reply(c, 200, "", "{%m:%lu}\n", MG_ESC("time"), time(NULL));
|
||||||
} else {
|
} else {
|
||||||
mg_http_reply(c, 500, "", "{%m:%m}\n", MG_ESC("error"), MG_ESC("Unsupported URI"));
|
mg_http_reply(c, 500, "", "{%m:%m}\n", MG_ESC("error"), MG_ESC("Unsupported URI"));
|
||||||
@@ -170,6 +199,20 @@ We take security seriously:
|
|||||||
of which we get notified and in case of any issue, act similar to (3).
|
of which we get notified and in case of any issue, act similar to (3).
|
||||||
|
|
||||||
|
|
||||||
|
## Articles
|
||||||
|
|
||||||
|
Technical guides and deep dives into embedded web servers, WebUI integration and embedded networking technologies:
|
||||||
|
- [Embedded Web Server: A Comprehensive Guide for Modern Connected Devices](https://mongoose.ws/articles/embedded-web-server-a-comprehensive-guide-for-modern-connected-devices/)
|
||||||
|
- [Building Embedded Web Device Dashboards](https://mongoose.ws/articles/building-embedded-web-device-dashboard/)
|
||||||
|
- [ESP32 Device Dashboard: A Step-by-Step Guide for Developers](https://mongoose.ws/articles/esp32-device-dashboard/)
|
||||||
|
- [How to build an STM32 Web Dashboard](https://mongoose.ws/articles/stm32-device-dashboard/)
|
||||||
|
- [STM32 WebSocket Guide](https://mongoose.ws/articles/stm32-websocket-guide/)
|
||||||
|
- [Web File Manager on STM32, ESP32 and Embedded Linux](https://mongoose.ws/articles/building-a-web-file-manager-on-stm32-esp32-embedded-linux/)
|
||||||
|
- [Web dashboard on Zephyr RTOS](https://mongoose.ws/articles/web-dashboard-on-zephyr-rtos/)
|
||||||
|
- [Limiting TCP/IP RAM usage on STM32](https://mongoose.ws/articles/limiting-tcpip-ram-usage-on-stm32/)
|
||||||
|
- [STM32 Ethernet explained](https://mongoose.ws/articles/stm32-ethernet-explained/)
|
||||||
|
|
||||||
|
|
||||||
## Contributions
|
## Contributions
|
||||||
|
|
||||||
Contributions are welcome! Please follow the guidelines below:
|
Contributions are welcome! Please follow the guidelines below:
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
# Mongoose Network Library Examples
|
|
||||||
|
|
||||||
In order to build and run any of the existing examples, please follow:
|
|
||||||
https://mongoose.ws/documentation/#how-to-build-and-run-examples
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Rules for creating a new example:
|
|
||||||
|
|
||||||
- Makefile golden reference for desktop/server example: [http-server](http-server)
|
|
||||||
- Makefile golden reference for the embedded example:
|
|
||||||
[stm32/nucleo-f746zg-baremetal](stm32/nucleo-f746zg-baremetal)
|
|
||||||
- An example must build on Windows, Mac and Ubuntu Linux systems
|
|
||||||
- Assume that user installed tools according to https://mongoose.ws/tutorials/tools/
|
|
||||||
- Makefile must not include any other make files
|
|
||||||
- Use `CFLAGS` for system-specific compilation options
|
|
||||||
- Use `CFLAGS_MONGOOSE` for mongoose-specific compilation options
|
|
||||||
- Use `$(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA)` to compile
|
|
||||||
- If external repository is required, download it on demand using git
|
|
||||||
shallow clone. See embedded example golden reference
|
|
||||||
- Keep Makefile as short as possible, but verbose to understand it easily
|
|
||||||
- Symlink files when required, like `mongoose.c`, `ca.pem`, etc. Make no copies
|
|
||||||
- Example's README.md should contain only the title and the link to mongoose.ws
|
|
||||||
tutorial page
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
|
|
||||||
all:
|
|
||||||
example:
|
|
||||||
true
|
|
||||||
|
|
||||||
arduino: ENV = -v $(CWD):/root
|
|
||||||
arduino:
|
|
||||||
curl -sL http://downloads.arduino.cc/arduino-1.8.19-linux64.tar.xz | unxz | tar -xf -
|
|
||||||
mv arduino-* $@
|
|
||||||
|
|
||||||
arduino-xiao-board:
|
|
||||||
./arduino/arduino --pref "boardsmanager.additional.urls=https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json" --save-prefs
|
|
||||||
./arduino/arduino --pref "compiler.warning_level=all" --save-prefs
|
|
||||||
./arduino/arduino --install-boards Seeeduino:samd
|
|
||||||
|
|
||||||
arduino-xiao: arduino arduino-xiao-board
|
|
||||||
cd w5500-http && ../arduino/arduino --verbose --verify --board Seeeduino:samd:seeed_XIAO_m0 w5500-http.ino
|
|
||||||
cd w5500-mqtt && ../arduino/arduino --verbose --verify --board Seeeduino:samd:seeed_XIAO_m0 w5500-mqtt.ino
|
|
||||||
|
|
||||||
arduino-nano: arduino
|
|
||||||
cd w5500-http && ../arduino/arduino --pref compiler.cpp.extra_flags=-DMG_ENABLE_LOG=0 --verbose --verify --board arduino:avr:nano w5500-http.ino
|
|
||||||
cd w5500-mqtt && ../arduino/arduino --pref compiler.cpp.extra_flags=-DMG_ENABLE_LOG=0 --verbose --verify --board arduino:avr:nano w5500-mqtt.ino
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf arduino
|
|
||||||
|
|
||||||
cleanall: clean #otherwise some parts of xiao-board installation will fail as already installed
|
|
||||||
rm -rf ~/.arduino15 ~/.oracle_jre_usage
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define MG_ARCH MG_ARCH_NEWLIB // Use ARM toolchain
|
|
||||||
#define MG_ENABLE_TCPIP 1 // Enable built-in network stack
|
|
||||||
#define MG_ENABLE_DRIVER_IMXRT 1 // Enable RTxx driver
|
|
||||||
#define MG_ENABLE_CUSTOM_MILLIS 1 // Let user implement mg_millis()
|
|
||||||
#define MG_ENABLE_POSIX_FS 0 // Disable POSIX filesystem
|
|
||||||
#define MG_ENABLE_PACKED_FS 1 // Enable packed filesystem
|
|
||||||
|
|
||||||
#define HTTP_URL "http://0.0.0.0"
|
|
||||||
#define HTTPS_URL "https://0.0.0.0"
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#define MG_ARCH MG_ARCH_CUSTOM
|
|
||||||
#define MG_ENABLE_SOCKET 0
|
|
||||||
#define MG_ENABLE_TCPIP 1
|
|
||||||
#define MG_ENABLE_DRIVER_W5500 1
|
|
||||||
#define mkdir(a, b) (-1)
|
|
||||||
#define MG_IO_SIZE 128
|
|
||||||
//#define MG_ENABLE_LOG 0
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#include <SPI.h>
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
#define SS_PIN 3 // Slave select pin
|
|
||||||
struct mg_mgr mgr; // Mongoose event manager
|
|
||||||
struct mg_tcpip_spi spi = {
|
|
||||||
NULL, // SPI data
|
|
||||||
[](void *) { digitalWrite(SS_PIN, LOW); }, // begin transation
|
|
||||||
[](void *) { digitalWrite(SS_PIN, HIGH); }, // end transaction
|
|
||||||
[](void *, uint8_t c) { return SPI.transfer(c); }, // execute transaction
|
|
||||||
};
|
|
||||||
struct mg_tcpip_if mif = {.mac = {2, 0, 1, 2, 3, 5}}; // network interface
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(115200);
|
|
||||||
pinMode(SS_PIN, OUTPUT);
|
|
||||||
SPI.begin();
|
|
||||||
|
|
||||||
// Set logging function to a serial print
|
|
||||||
mg_log_set_fn([](char ch, void *) { Serial.print(ch); }, NULL);
|
|
||||||
mg_mgr_init(&mgr);
|
|
||||||
|
|
||||||
delay(3000);
|
|
||||||
MG_INFO(("Starting TCP/IP stack..."));
|
|
||||||
|
|
||||||
mif.driver = &mg_tcpip_driver_w5500;
|
|
||||||
mif.driver_data = &spi;
|
|
||||||
mg_tcpip_init(&mgr, &mif);
|
|
||||||
|
|
||||||
// Start a 5 sec timer, print status message periodically
|
|
||||||
mg_timer_add(
|
|
||||||
&mgr, 5000, MG_TIMER_REPEAT,
|
|
||||||
[](void *) {
|
|
||||||
MG_INFO(("ethernet: %s", mg_tcpip_driver_w5500.up(&mif) ? "up" : "down"));
|
|
||||||
},
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
// Setup HTTP listener. Respond "ok" on any HTTP request
|
|
||||||
mg_http_listen(
|
|
||||||
&mgr, "http://0.0.0.0",
|
|
||||||
[](struct mg_connection *c, int ev, void *ev_data) {
|
|
||||||
if (ev == MG_EV_HTTP_MSG) mg_http_reply(c, 200, "", "ok\n");
|
|
||||||
},
|
|
||||||
&mgr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
mg_mgr_poll(&mgr, 1);
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#define MG_ARCH MG_ARCH_CUSTOM
|
|
||||||
#define MG_ENABLE_SOCKET 0
|
|
||||||
#define MG_ENABLE_TCPIP 1
|
|
||||||
#define MG_ENABLE_DRIVER_W5500 1
|
|
||||||
#define mkdir(a, b) (-1)
|
|
||||||
#define MG_IO_SIZE 512
|
|
||||||
//#define MG_ENABLE_LOG 0
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
#include "net.h"
|
|
||||||
|
|
||||||
#define MQTT_SERVER "mqtt://broker.hivemq.com:1883"
|
|
||||||
struct mg_connection *mqtt_connection;
|
|
||||||
const char *mqtt_subscribe_topic = "mg/rx";
|
|
||||||
const char *mqtt_publish_topic = "mg/tx";
|
|
||||||
|
|
||||||
struct mg_mgr mgr; // Mongoose event manager
|
|
||||||
struct mg_tcpip_if mif = {.mac = {2, 0, 1, 2, 3, 5}}; // network interface
|
|
||||||
|
|
||||||
void mqtt_publish(const char *message) {
|
|
||||||
struct mg_mqtt_opts opts = {};
|
|
||||||
opts.topic = mg_str(mqtt_publish_topic);
|
|
||||||
opts.message = mg_str(message);
|
|
||||||
if (mqtt_connection) mg_mqtt_pub(mqtt_connection, &opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fn(struct mg_connection *c, int ev, void *ev_data) {
|
|
||||||
if (ev == MG_EV_MQTT_OPEN) {
|
|
||||||
MG_INFO(("%lu CONNECTED to %s", c->id, MQTT_SERVER));
|
|
||||||
struct mg_mqtt_opts opts = {};
|
|
||||||
opts.topic = mg_str(mqtt_subscribe_topic);
|
|
||||||
mg_mqtt_sub(c, &opts);
|
|
||||||
MG_INFO(("%lu SUBSCRIBED to %s", c->id, mqtt_subscribe_topic));
|
|
||||||
} else if (ev == MG_EV_MQTT_MSG) {
|
|
||||||
// Received MQTT message
|
|
||||||
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
|
||||||
MG_INFO(("%lu RECEIVED %.*s <- %.*s", c->id, (int) mm->data.len,
|
|
||||||
mm->data.buf, (int) mm->topic.len, mm->topic.buf));
|
|
||||||
exec_command(mm->data.buf, mm->data.len);
|
|
||||||
} else if (ev == MG_EV_CLOSE) {
|
|
||||||
MG_INFO(("%lu CLOSED", c->id));
|
|
||||||
mqtt_connection = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void timer_fn(void *arg) {
|
|
||||||
struct mg_mgr *mgr = (struct mg_mgr *) arg;
|
|
||||||
struct mg_mqtt_opts opts;
|
|
||||||
memset(&opts, 0, sizeof(opts));
|
|
||||||
opts.clean = true;
|
|
||||||
if (mif.state == MG_TCPIP_STATE_READY && mqtt_connection == NULL) {
|
|
||||||
mqtt_connection = mg_mqtt_connect(mgr, MQTT_SERVER, &opts, fn, NULL);
|
|
||||||
}
|
|
||||||
// MG_INFO(("Eth: %d, MQTT: %p", mif.state, mqtt_connection));
|
|
||||||
}
|
|
||||||
|
|
||||||
void net_init(void) {
|
|
||||||
// Set Mongoose logging function to a serial print
|
|
||||||
mg_mgr_init(&mgr);
|
|
||||||
|
|
||||||
mif.driver = &mg_tcpip_driver_w5500;
|
|
||||||
mif.driver_data = &spi;
|
|
||||||
mg_tcpip_init(&mgr, &mif);
|
|
||||||
|
|
||||||
// Start a timer that keeps MQTT connection alive
|
|
||||||
mg_timer_add(&mgr, 3000, MG_TIMER_REPEAT, timer_fn, &mgr);
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern struct mg_tcpip_spi spi;
|
|
||||||
extern struct mg_mgr mgr;
|
|
||||||
void mqtt_publish(const char *message);
|
|
||||||
void net_init(void);
|
|
||||||
void exec_command(const char *req, size_t req_len);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
#include <SPI.h>
|
|
||||||
#include "net.h"
|
|
||||||
|
|
||||||
#define SS_PIN 17 // Slave select pin
|
|
||||||
struct mg_tcpip_spi spi = {
|
|
||||||
NULL, // SPI data
|
|
||||||
[](void *) { digitalWrite(SS_PIN, LOW); }, // Begin transaction
|
|
||||||
[](void *) { digitalWrite(SS_PIN, HIGH); }, // End transaction
|
|
||||||
[](void *, uint8_t c) { return SPI.transfer(c); }, // Execute transaction
|
|
||||||
};
|
|
||||||
|
|
||||||
void exec_command(const char *req, size_t req_len) {
|
|
||||||
char res[100];
|
|
||||||
if (req_len == 2 && strncmp(req, "on", req_len) == 0) {
|
|
||||||
digitalWrite(LED_BUILTIN, true);
|
|
||||||
snprintf(res, sizeof(res), "LED on");
|
|
||||||
} else if (req_len == 3 && strncmp(req, "off", req_len) == 0) {
|
|
||||||
digitalWrite(LED_BUILTIN, false);
|
|
||||||
snprintf(res, sizeof(res), "LED off");
|
|
||||||
} else {
|
|
||||||
snprintf(res, sizeof(res), "Unknown command: [%.*s]", (int) req_len, req);
|
|
||||||
}
|
|
||||||
Serial.println(res);
|
|
||||||
mqtt_publish(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void process_input(char c) {
|
|
||||||
static char buf[100];
|
|
||||||
static size_t len = 0;
|
|
||||||
char response[100];
|
|
||||||
if (c != '\n' && c != '\0') buf[len++] = c; // Append to the buffer
|
|
||||||
if (len >= sizeof(buf)) len = 0; // On overflow, reset
|
|
||||||
if (c == '\n' && len > 0) {
|
|
||||||
exec_command(buf, len);
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(115200);
|
|
||||||
SPI.begin();
|
|
||||||
pinMode(SS_PIN, OUTPUT);
|
|
||||||
pinMode(LED_BUILTIN, OUTPUT);
|
|
||||||
mg_log_set_fn([](char ch, void *) { Serial.print(ch); }, NULL);
|
|
||||||
net_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
if (Serial.available()) process_input(Serial.read());
|
|
||||||
mg_mgr_poll(&mgr, 1);
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
PROG ?= ./example # Program we are building
|
|
||||||
PACK ?= ./pack # Packing executable
|
|
||||||
DELETE = rm -rf # Command to remove files
|
|
||||||
GZIP ?= gzip # For compressing files in web_root/
|
|
||||||
OUT ?= -o $(PROG) # Compiler argument for output file
|
|
||||||
SOURCES = main.c mongoose.c net.c packed_fs.c # Source code files
|
|
||||||
CFLAGS = -W -Wall -Wextra -g -I. # Build options
|
|
||||||
NPX ?= npx
|
|
||||||
|
|
||||||
# Mongoose build options. See https://mongoose.ws/documentation/#build-options
|
|
||||||
CFLAGS_MONGOOSE += -DMG_ENABLE_PACKED_FS=1
|
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT) # Windows settings. Assume MinGW compiler. To use VC: make CC=cl CFLAGS=/MD OUT=/Feprog.exe
|
|
||||||
PROG = example.exe # Use .exe suffix for the binary
|
|
||||||
PACK = pack.exe # Packing executable
|
|
||||||
CC = gcc # Use MinGW gcc compiler
|
|
||||||
CFLAGS += -lws2_32 # Link against Winsock library
|
|
||||||
DELETE = cmd /C del /Q /F /S # Command prompt command to delete files
|
|
||||||
GZIP = echo # No gzip on Windows
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Default target. Build and run program
|
|
||||||
all: $(PROG)
|
|
||||||
$(RUN) $(PROG) $(ARGS)
|
|
||||||
|
|
||||||
# Build program from sources
|
|
||||||
$(PROG): $(SOURCES)
|
|
||||||
$(CC) $(SOURCES) $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) $(OUT)
|
|
||||||
|
|
||||||
# Bundle JS libraries (preact, preact-router, ...) into a single file
|
|
||||||
web_root/bundle.js:
|
|
||||||
curl -s https://npm.reversehttp.com/preact,preact/hooks,htm/preact,preact-router -o $@
|
|
||||||
|
|
||||||
# Create optimised CSS. Prerequisite: npm -g i tailwindcss tailwindcss-font-inter
|
|
||||||
web_root/main.css: web_root/index.html $(wildcard web_root/*.js)
|
|
||||||
$(NPX) tailwindcss -o $@ --minify
|
|
||||||
|
|
||||||
# Generate packed filesystem for serving Web UI
|
|
||||||
packed_fs.c: $(wildcard web_root/*) $(wildcard certs/*) Makefile web_root/main.css web_root/bundle.js
|
|
||||||
$(GZIP) web_root/*
|
|
||||||
$(CC) ../../test/pack.c -o $(PACK)
|
|
||||||
$(PACK) web_root/* certs/* > $@
|
|
||||||
$(GZIP) -d web_root/*
|
|
||||||
|
|
||||||
mbedtls:
|
|
||||||
git clone --depth 1 -b v2.28.2 https://github.com/mbed-tls/mbedtls $@
|
|
||||||
|
|
||||||
ifeq ($(TLS), mbedtls)
|
|
||||||
CFLAGS += -DMG_TLS=MG_TLS_MBED -Wno-conversion -Imbedtls/include
|
|
||||||
CFLAGS += -DMBEDTLS_CONFIG_FILE=\"mbedtls_config.h\" mbedtls/library/*.c
|
|
||||||
$(PROG): mbedtls
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Cleanup. Delete built program and all build artifacts
|
|
||||||
clean:
|
|
||||||
$(DELETE) $(PROG) $(PACK) *.o *.obj *.exe *.dSYM mbedtls
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../mongoose.c
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../mongoose.h
|
|
||||||
@@ -1,327 +0,0 @@
|
|||||||
// Copyright (c) 2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
|
|
||||||
#include "net.h"
|
|
||||||
|
|
||||||
// Authenticated user.
|
|
||||||
// A user can be authenticated by:
|
|
||||||
// - a name:pass pair, passed in a header Authorization: Basic .....
|
|
||||||
// - an access_token, passed in a header Cookie: access_token=....
|
|
||||||
// When a user is shown a login screen, she enters a user:pass. If successful,
|
|
||||||
// a server responds with a http-only access_token cookie set.
|
|
||||||
struct user {
|
|
||||||
const char *name, *pass, *access_token;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Settings
|
|
||||||
struct settings {
|
|
||||||
bool log_enabled;
|
|
||||||
int log_level;
|
|
||||||
long brightness;
|
|
||||||
char *device_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct settings s_settings = {true, 1, 57, NULL};
|
|
||||||
|
|
||||||
static const char *s_json_header =
|
|
||||||
"Content-Type: application/json\r\n"
|
|
||||||
"Cache-Control: no-cache\r\n";
|
|
||||||
static uint64_t s_boot_timestamp = 0; // Updated by SNTP
|
|
||||||
|
|
||||||
// This is for newlib and TLS (mbedTLS)
|
|
||||||
uint64_t mg_now(void) {
|
|
||||||
return mg_millis() + s_boot_timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ui_event_next(int no, struct ui_event *e) {
|
|
||||||
if (no < 0 || no >= MAX_EVENTS_NO) return 0;
|
|
||||||
|
|
||||||
srand((unsigned) no);
|
|
||||||
e->type = (uint8_t) rand() % 4;
|
|
||||||
e->prio = (uint8_t) rand() % 3;
|
|
||||||
e->timestamp =
|
|
||||||
(unsigned long) ((int64_t) mg_now() - 86400 * 1000 /* one day back */ +
|
|
||||||
no * 300 * 1000 /* 5 mins between alerts */ +
|
|
||||||
1000 * (rand() % 300) /* randomize event time */) /
|
|
||||||
1000UL;
|
|
||||||
|
|
||||||
mg_snprintf(e->text, MAX_EVENT_TEXT_SIZE, "event#%d", no);
|
|
||||||
return no + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SNTP connection event handler. When we get a response from an SNTP server,
|
|
||||||
// adjust s_boot_timestamp. We'll get a valid time from that point on
|
|
||||||
static void sfn(struct mg_connection *c, int ev, void *ev_data) {
|
|
||||||
uint64_t *expiration_time = (uint64_t *) c->data;
|
|
||||||
if (ev == MG_EV_OPEN) {
|
|
||||||
*expiration_time = mg_millis() + 3000; // Store expiration time in 3s
|
|
||||||
} else if (ev == MG_EV_SNTP_TIME) {
|
|
||||||
uint64_t t = *(uint64_t *) ev_data;
|
|
||||||
s_boot_timestamp = t - mg_millis();
|
|
||||||
c->is_closing = 1;
|
|
||||||
} else if (ev == MG_EV_POLL) {
|
|
||||||
if (mg_millis() > *expiration_time) c->is_closing = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void timer_sntp_fn(void *param) { // SNTP timer function. Sync up time
|
|
||||||
mg_sntp_connect(param, "udp://time.google.com:123", sfn, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse HTTP requests, return authenticated user or NULL
|
|
||||||
static struct user *authenticate(struct mg_http_message *hm) {
|
|
||||||
// In production, make passwords strong and tokens randomly generated
|
|
||||||
// In this example, user list is kept in RAM. In production, it can
|
|
||||||
// be backed by file, database, or some other method.
|
|
||||||
static struct user users[] = {
|
|
||||||
{"admin", "admin", "admin_token"},
|
|
||||||
{"user1", "user1", "user1_token"},
|
|
||||||
{"user2", "user2", "user2_token"},
|
|
||||||
{NULL, NULL, NULL},
|
|
||||||
};
|
|
||||||
char user[64], pass[64];
|
|
||||||
struct user *u, *result = NULL;
|
|
||||||
mg_http_creds(hm, user, sizeof(user), pass, sizeof(pass));
|
|
||||||
MG_VERBOSE(("user [%s] pass [%s]", user, pass));
|
|
||||||
|
|
||||||
if (user[0] != '\0' && pass[0] != '\0') {
|
|
||||||
// Both user and password is set, search by user/password
|
|
||||||
for (u = users; result == NULL && u->name != NULL; u++)
|
|
||||||
if (strcmp(user, u->name) == 0 && strcmp(pass, u->pass) == 0) result = u;
|
|
||||||
} else if (user[0] == '\0') {
|
|
||||||
// Only password is set, search by token
|
|
||||||
for (u = users; result == NULL && u->name != NULL; u++)
|
|
||||||
if (strcmp(pass, u->access_token) == 0) result = u;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_login(struct mg_connection *c, struct user *u) {
|
|
||||||
char cookie[256];
|
|
||||||
mg_snprintf(cookie, sizeof(cookie),
|
|
||||||
"Set-Cookie: access_token=%s; Path=/; "
|
|
||||||
"%sHttpOnly; SameSite=Lax; Max-Age=%d\r\n",
|
|
||||||
u->access_token, c->is_tls ? "Secure; " : "", 3600 * 24);
|
|
||||||
mg_http_reply(c, 200, cookie, "{%m:%m}", MG_ESC("user"), MG_ESC(u->name));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_logout(struct mg_connection *c) {
|
|
||||||
char cookie[256];
|
|
||||||
mg_snprintf(cookie, sizeof(cookie),
|
|
||||||
"Set-Cookie: access_token=; Path=/; "
|
|
||||||
"Expires=Thu, 01 Jan 1970 00:00:00 UTC; "
|
|
||||||
"%sHttpOnly; Max-Age=0; \r\n",
|
|
||||||
c->is_tls ? "Secure; " : "");
|
|
||||||
mg_http_reply(c, 200, cookie, "true\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_debug(struct mg_connection *c, struct mg_http_message *hm) {
|
|
||||||
int level = mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG);
|
|
||||||
mg_log_set(level);
|
|
||||||
mg_http_reply(c, 200, "", "Debug level set to %d\n", level);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t print_int_arr(void (*out)(char, void *), void *ptr, va_list *ap) {
|
|
||||||
size_t i, len = 0, num = va_arg(*ap, size_t); // Number of items in the array
|
|
||||||
int *arr = va_arg(*ap, int *); // Array ptr
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
len += mg_xprintf(out, ptr, "%s%d", i == 0 ? "" : ",", arr[i]);
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_stats_get(struct mg_connection *c) {
|
|
||||||
int points[] = {21, 22, 22, 19, 18, 20, 23, 23, 22, 22, 22, 23, 22};
|
|
||||||
mg_http_reply(c, 200, s_json_header, "{%m:%d,%m:%d,%m:[%M]}\n",
|
|
||||||
MG_ESC("temperature"), 21, //
|
|
||||||
MG_ESC("humidity"), 67, //
|
|
||||||
MG_ESC("points"), print_int_arr,
|
|
||||||
sizeof(points) / sizeof(points[0]), points);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t print_events(void (*out)(char, void *), void *ptr, va_list *ap) {
|
|
||||||
size_t len = 0;
|
|
||||||
struct ui_event ev;
|
|
||||||
int pageno = va_arg(*ap, int);
|
|
||||||
int no = (pageno - 1) * EVENTS_PER_PAGE;
|
|
||||||
int end = no + EVENTS_PER_PAGE;
|
|
||||||
|
|
||||||
while ((no = ui_event_next(no, &ev)) != 0 && no <= end) {
|
|
||||||
len += mg_xprintf(out, ptr, "%s{%m:%lu,%m:%d,%m:%d,%m:%m}\n", //
|
|
||||||
len == 0 ? "" : ",", //
|
|
||||||
MG_ESC("time"), ev.timestamp, //
|
|
||||||
MG_ESC("type"), ev.type, //
|
|
||||||
MG_ESC("prio"), ev.prio, //
|
|
||||||
MG_ESC("text"), MG_ESC(ev.text));
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_events_get(struct mg_connection *c,
|
|
||||||
struct mg_http_message *hm) {
|
|
||||||
int pageno = mg_json_get_long(hm->body, "$.page", 1);
|
|
||||||
mg_http_reply(c, 200, s_json_header, "{%m:[%M], %m:%d}\n", MG_ESC("arr"),
|
|
||||||
print_events, pageno, MG_ESC("totalCount"), MAX_EVENTS_NO);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_settings_set(struct mg_connection *c, struct mg_str body) {
|
|
||||||
struct settings settings;
|
|
||||||
char *s = mg_json_get_str(body, "$.device_name");
|
|
||||||
bool ok = true;
|
|
||||||
memset(&settings, 0, sizeof(settings));
|
|
||||||
mg_json_get_bool(body, "$.log_enabled", &settings.log_enabled);
|
|
||||||
settings.log_level = mg_json_get_long(body, "$.log_level", 0);
|
|
||||||
settings.brightness = mg_json_get_long(body, "$.brightness", 0);
|
|
||||||
if (s && strlen(s) < MAX_DEVICE_NAME) {
|
|
||||||
free(settings.device_name);
|
|
||||||
settings.device_name = s;
|
|
||||||
} else {
|
|
||||||
free(s);
|
|
||||||
}
|
|
||||||
s_settings = settings; // Save to the device flash
|
|
||||||
mg_http_reply(c, 200, s_json_header,
|
|
||||||
"{%m:%s,%m:%m}", //
|
|
||||||
MG_ESC("status"), ok ? "true" : "false", //
|
|
||||||
MG_ESC("message"), MG_ESC(ok ? "Success" : "Failed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_settings_get(struct mg_connection *c) {
|
|
||||||
mg_http_reply(c, 200, s_json_header, "{%m:%s,%m:%hhu,%m:%hhu,%m:%m}\n", //
|
|
||||||
MG_ESC("log_enabled"),
|
|
||||||
s_settings.log_enabled ? "true" : "false", //
|
|
||||||
MG_ESC("log_level"), s_settings.log_level, //
|
|
||||||
MG_ESC("brightness"), s_settings.brightness, //
|
|
||||||
MG_ESC("device_name"), MG_ESC(s_settings.device_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_firmware_upload(struct mg_connection *c,
|
|
||||||
struct mg_http_message *hm) {
|
|
||||||
char name[64], offset[20], total[20];
|
|
||||||
struct mg_str data = hm->body;
|
|
||||||
long ofs = -1, tot = -1;
|
|
||||||
name[0] = offset[0] = '\0';
|
|
||||||
mg_http_get_var(&hm->query, "name", name, sizeof(name));
|
|
||||||
mg_http_get_var(&hm->query, "offset", offset, sizeof(offset));
|
|
||||||
mg_http_get_var(&hm->query, "total", total, sizeof(total));
|
|
||||||
MG_INFO(("File %s, offset %s, len %lu", name, offset, data.len));
|
|
||||||
if ((ofs = mg_json_get_long(mg_str(offset), "$", -1)) < 0 ||
|
|
||||||
(tot = mg_json_get_long(mg_str(total), "$", -1)) < 0) {
|
|
||||||
mg_http_reply(c, 500, "", "offset and total not set\n");
|
|
||||||
} else if (ofs == 0 && mg_ota_begin((size_t) tot) == false) {
|
|
||||||
mg_http_reply(c, 500, "", "mg_ota_begin(%ld) failed\n", tot);
|
|
||||||
} else if (data.len > 0 && mg_ota_write(data.buf, data.len) == false) {
|
|
||||||
mg_http_reply(c, 500, "", "mg_ota_write(%lu) @%ld failed\n", data.len, ofs);
|
|
||||||
mg_ota_end();
|
|
||||||
} else if (data.len == 0 && mg_ota_end() == false) {
|
|
||||||
mg_http_reply(c, 500, "", "mg_ota_end() failed\n", tot);
|
|
||||||
} else {
|
|
||||||
mg_http_reply(c, 200, s_json_header, "true\n");
|
|
||||||
if (data.len == 0) {
|
|
||||||
// Successful mg_ota_end() called, schedule device reboot
|
|
||||||
mg_timer_add(c->mgr, 500, 0, (void (*)(void *)) mg_device_reset, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_firmware_commit(struct mg_connection *c) {
|
|
||||||
mg_http_reply(c, 200, s_json_header, "%s\n",
|
|
||||||
mg_ota_commit() ? "true" : "false");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_firmware_rollback(struct mg_connection *c) {
|
|
||||||
mg_http_reply(c, 200, s_json_header, "%s\n",
|
|
||||||
mg_ota_rollback() ? "true" : "false");
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t print_status(void (*out)(char, void *), void *ptr, va_list *ap) {
|
|
||||||
int fw = va_arg(*ap, int);
|
|
||||||
return mg_xprintf(out, ptr, "{%m:%d,%m:%c%lx%c,%m:%u,%m:%u}\n",
|
|
||||||
MG_ESC("status"), mg_ota_status(fw), MG_ESC("crc32"), '"',
|
|
||||||
mg_ota_crc32(fw), '"', MG_ESC("size"), mg_ota_size(fw),
|
|
||||||
MG_ESC("timestamp"), mg_ota_timestamp(fw));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_firmware_status(struct mg_connection *c) {
|
|
||||||
mg_http_reply(c, 200, s_json_header, "[%M,%M]\n", print_status,
|
|
||||||
MG_FIRMWARE_CURRENT, print_status, MG_FIRMWARE_PREVIOUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_device_reset(struct mg_connection *c) {
|
|
||||||
mg_http_reply(c, 200, s_json_header, "true\n");
|
|
||||||
mg_timer_add(c->mgr, 500, 0, (void (*)(void *)) mg_device_reset, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_device_eraselast(struct mg_connection *c) {
|
|
||||||
size_t ss = mg_flash_sector_size(), size = mg_flash_size();
|
|
||||||
char *base = (char *) mg_flash_start(), *last = base + size - ss;
|
|
||||||
if (mg_flash_bank() == 2) last -= size / 2;
|
|
||||||
mg_flash_erase(last);
|
|
||||||
mg_http_reply(c, 200, s_json_header, "true\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTP request handler function
|
|
||||||
static void fn(struct mg_connection *c, int ev, void *ev_data) {
|
|
||||||
if (ev == MG_EV_ACCEPT) {
|
|
||||||
if (c->fn_data != NULL) { // TLS listener!
|
|
||||||
struct mg_tls_opts opts = {0};
|
|
||||||
opts.cert = mg_unpacked("/certs/server_cert.pem");
|
|
||||||
opts.key = mg_unpacked("/certs/server_key.pem");
|
|
||||||
mg_tls_init(c, &opts);
|
|
||||||
}
|
|
||||||
} else if (ev == MG_EV_HTTP_MSG) {
|
|
||||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
|
||||||
struct user *u = authenticate(hm);
|
|
||||||
|
|
||||||
if (mg_match(hm->uri, mg_str("/api/#"), NULL) && u == NULL) {
|
|
||||||
mg_http_reply(c, 403, "", "Not Authorised\n");
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/login"), NULL)) {
|
|
||||||
handle_login(c, u);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/logout"), NULL)) {
|
|
||||||
handle_logout(c);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/debug"), NULL)) {
|
|
||||||
handle_debug(c, hm);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/stats/get"), NULL)) {
|
|
||||||
handle_stats_get(c);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/events/get"), NULL)) {
|
|
||||||
handle_events_get(c, hm);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/settings/get"), NULL)) {
|
|
||||||
handle_settings_get(c);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/settings/set"), NULL)) {
|
|
||||||
handle_settings_set(c, hm->body);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/firmware/upload"), NULL)) {
|
|
||||||
handle_firmware_upload(c, hm);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/firmware/commit"), NULL)) {
|
|
||||||
handle_firmware_commit(c);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/firmware/rollback"), NULL)) {
|
|
||||||
handle_firmware_rollback(c);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/firmware/status"), NULL)) {
|
|
||||||
handle_firmware_status(c);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/device/reset"), NULL)) {
|
|
||||||
handle_device_reset(c);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/device/eraselast"), NULL)) {
|
|
||||||
handle_device_eraselast(c);
|
|
||||||
} else {
|
|
||||||
struct mg_http_serve_opts opts;
|
|
||||||
memset(&opts, 0, sizeof(opts));
|
|
||||||
#if MG_ARCH == MG_ARCH_UNIX || MG_ARCH == MG_ARCH_WIN32
|
|
||||||
opts.root_dir = "web_root"; // On workstations, use filesystem
|
|
||||||
#else
|
|
||||||
opts.root_dir = "/web_root"; // On embedded, use packed files
|
|
||||||
opts.fs = &mg_fs_packed;
|
|
||||||
#endif
|
|
||||||
mg_http_serve_dir(c, ev_data, &opts);
|
|
||||||
}
|
|
||||||
MG_DEBUG(("%lu %.*s %.*s -> %.*s", c->id, (int) hm->method.len,
|
|
||||||
hm->method.buf, (int) hm->uri.len, hm->uri.buf, (int) 3,
|
|
||||||
&c->send.buf[9]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void web_init(struct mg_mgr *mgr) {
|
|
||||||
s_settings.device_name = strdup("My Device");
|
|
||||||
mg_http_listen(mgr, HTTP_URL, fn, NULL);
|
|
||||||
mg_http_listen(mgr, HTTPS_URL, fn, (void *) 1);
|
|
||||||
mg_timer_add(mgr, 3600 * 1000, MG_TIMER_RUN_NOW | MG_TIMER_REPEAT,
|
|
||||||
timer_sntp_fn, mgr);
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -1,15 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en" class="h-full bg-white">
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='1.5' stroke='currentColor'> <path stroke-linecap='round' stroke-linejoin='round' d='M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0' /> </svg>" />
|
|
||||||
<link href="main.css" rel="stylesheet" />
|
|
||||||
<link href="https://rsms.me/inter/inter.css" rel="stylesheet" />
|
|
||||||
</head>
|
|
||||||
<body class="h-full"></body>
|
|
||||||
<script src="history.min.js"></script>
|
|
||||||
<script type="module" src="main.js"></script>
|
|
||||||
</html>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter var,Helvetica,sans-serif;font-feature-settings:"cv11","ss01";font-variation-settings:"opsz" 32}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.left-0{left:0}.right-auto{right:auto}.top-0{top:0}.isolate{isolation:isolate}.z-10{z-index:10}.z-\[48\]{z-index:48}.z-\[60\]{z-index:60}.col-span-2{grid-column:span 2/span 2}.m-4{margin:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-top:0;margin-bottom:0}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-5{margin-top:1.25rem;margin-bottom:1.25rem}.mb-1{margin-bottom:.25rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-2{margin-right:.5rem}.mr-4{margin-right:1rem}.mt-1{margin-top:.25rem}.mt-3{margin-top:.75rem}.mt-5{margin-top:1.25rem}.mt-7{margin-top:1.75rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-12{height:3rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-0{width:0}.w-11{width:2.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-72{width:18rem}.w-96{width:24rem}.w-full{width:100%}.min-w-full{min-width:100%}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.grow-0{flex-grow:0}.basis-\[30px\]{flex-basis:30px}.border-separate{border-collapse:initial}.border-spacing-0Line truncated
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
THISDIR = $(realpath $(CURDIR))
|
|
||||||
ROOTDIR = $(realpath $(CURDIR)/../../..)
|
|
||||||
DOCKER ?= docker run --rm $(DA) -v $(ROOTDIR):$(ROOTDIR) -w $(THISDIR) espressif/idf
|
|
||||||
CMD ?= idf.py build
|
|
||||||
PORT ?= /dev/ttyUSB0
|
|
||||||
|
|
||||||
all: example
|
|
||||||
|
|
||||||
example:
|
|
||||||
true
|
|
||||||
|
|
||||||
build: Makefile $(wildcard main/*)
|
|
||||||
$(DOCKER) $(CMD)
|
|
||||||
|
|
||||||
flash:
|
|
||||||
flash: CMD = idf.py flash
|
|
||||||
flash: DA = --device $(PORT)
|
|
||||||
flash: build
|
|
||||||
|
|
||||||
.PHONY: build
|
|
||||||
|
|
||||||
dashboard.hex: build
|
|
||||||
esputil mkhex \
|
|
||||||
0x8000 build/partition_table/partition-table.bin \
|
|
||||||
0x1000 build/bootloader/bootloader.bin \
|
|
||||||
0x100000 build/mongoose-esp32-example.bin > $@
|
|
||||||
|
|
||||||
flash2: dashboard.hex
|
|
||||||
esputil -p $(PORT) -b 921600 -fp 0x220 flash dashboard.hex
|
|
||||||
esputil -p $(PORT) monitor
|
|
||||||
|
|
||||||
ESPTOOL ?= esptool.py
|
|
||||||
|
|
||||||
flash3:
|
|
||||||
cd build && $(ESPTOOL) --chip esp32 -p $(PORT) -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 2MB 0x8000 partition_table/partition-table.bin 0x1000 bootloader/bootloader.bin 0x100000 mongoose-esp32-example.bin
|
|
||||||
|
|
||||||
clean:
|
|
||||||
test -d build && $(DOCKER) rm -rf build sdkconfig || true
|
|
||||||
@@ -1,265 +0,0 @@
|
|||||||
// Copyright (c) 2020 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
|
|
||||||
#include "mongoose.h"
|
|
||||||
#include "net.h"
|
|
||||||
|
|
||||||
#define WIFI_SSID "YOUR_WIFI_NETWORK_NAME" // SET THIS!
|
|
||||||
#define WIFI_PASS "YOUR_WIFI_PASSWORD" // SET THIS!
|
|
||||||
|
|
||||||
void app_main(void) {
|
|
||||||
// Setup wifi. This function is implemented in wifi.c
|
|
||||||
// It blocks until connected to the configured WiFi network
|
|
||||||
void wifi_init(const char *ssid, const char *pass);
|
|
||||||
wifi_init(WIFI_SSID, WIFI_PASS);
|
|
||||||
|
|
||||||
// Connected to WiFi, now start HTTP server
|
|
||||||
struct mg_mgr mgr;
|
|
||||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
|
||||||
mg_mgr_init(&mgr);
|
|
||||||
MG_INFO(("Mongoose version : v%s", MG_VERSION));
|
|
||||||
MG_INFO(("Listening on : %s", HTTP_URL));
|
|
||||||
#if MG_ENABLE_MBEDTLS
|
|
||||||
MG_INFO(("Listening on : %s", HTTPS_URL));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
web_init(&mgr);
|
|
||||||
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
|
||||||
}
|
|
||||||
|
|
||||||
#if MG_DEVICE == MG_DEVICE_CUSTOM
|
|
||||||
void *mg_flash_start(void) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
size_t mg_flash_size(void) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
size_t mg_flash_sector_size(void) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
size_t mg_flash_write_align(void) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int mg_flash_bank(void) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
bool mg_flash_erase(void *location) {
|
|
||||||
(void) location;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool mg_flash_swap_bank(void) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool mg_flash_write(void *addr, const void *buf, size_t len) {
|
|
||||||
(void) addr, (void) buf, (void) len;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void mg_device_reset(void) {
|
|
||||||
esp_restart();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if MG_OTA == MG_OTA_CUSTOM
|
|
||||||
#include "esp_app_format.h"
|
|
||||||
#include "esp_ota_ops.h"
|
|
||||||
|
|
||||||
static size_t s_size = 0; // Firmware size to flash. In-progress indicator
|
|
||||||
static bool rx_checked = false; // Whether firmware being received has been checked as valid
|
|
||||||
const esp_partition_t * update_partition = NULL; // The partition the update is being applied to
|
|
||||||
esp_ota_handle_t update_handle = 0; // Handle of the current update process
|
|
||||||
|
|
||||||
const esp_partition_t * get_partition_from_fw(int fw) {
|
|
||||||
if (MG_FIRMWARE_CURRENT == fw) {
|
|
||||||
return esp_ota_get_running_partition();
|
|
||||||
}
|
|
||||||
const esp_partition_t * p = esp_ota_get_last_invalid_partition();
|
|
||||||
if (NULL == p) {
|
|
||||||
p = esp_ota_get_next_update_partition(NULL);
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if the data buffer contains the header of a valid firmware
|
|
||||||
const size_t fw_size_required = sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t);
|
|
||||||
bool check_fw_header(const void* buf, size_t len) {
|
|
||||||
// Ensure we have received enough data to do the check
|
|
||||||
if (len < fw_size_required) {
|
|
||||||
MG_ERROR(("Insufficient data to check firmware header - %d bytes, require %d bytes", len, fw_size_required));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the magic word of the received firmare
|
|
||||||
esp_app_desc_t* rx_app_info = (esp_app_desc_t*)(((char*)buf) + sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t));
|
|
||||||
if (ESP_APP_DESC_MAGIC_WORD != rx_app_info->magic_word) {
|
|
||||||
MG_ERROR(("Invalid app - invalid magic word"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
MG_INFO(("Received firmware: %s %s", rx_app_info->project_name, rx_app_info->version));
|
|
||||||
|
|
||||||
// Get the name/version of the running firmware
|
|
||||||
const esp_partition_t *current = esp_ota_get_running_partition();
|
|
||||||
esp_app_desc_t curr_app_info;
|
|
||||||
esp_err_t res = esp_ota_get_partition_description(current, &curr_app_info);
|
|
||||||
if (ESP_OK != res) {
|
|
||||||
MG_ERROR(("Unable to get name/version of running firmware"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
MG_INFO(("Running firmware: %s %s", curr_app_info.project_name, curr_app_info.version));
|
|
||||||
|
|
||||||
// Check the name of the new firmware is the same as the old firmware
|
|
||||||
if (memcmp(curr_app_info.project_name, rx_app_info->project_name, sizeof(curr_app_info.project_name)) != 0) {
|
|
||||||
MG_ERROR(("Firmware name is different. Wrong firmware uploaded! Current %s Uploaded %s", curr_app_info.project_name, rx_app_info->project_name));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the version of the new firmware is different from the old firmware
|
|
||||||
if (memcmp(curr_app_info.version, rx_app_info->version, sizeof(curr_app_info.version)) == 0) {
|
|
||||||
MG_ERROR(("Firmware version is the same. Wrong firmware uploaded! Current %s, Uploaded %s", curr_app_info.version, rx_app_info->version));
|
|
||||||
//return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mg_ota_begin(size_t new_firmware_size) {
|
|
||||||
rx_checked = false;
|
|
||||||
if (s_size) {
|
|
||||||
MG_ERROR(("OTA already in progress. Call mg_ota_end()"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int partition_size = mg_ota_size(MG_FIRMWARE_PREVIOUS);
|
|
||||||
if (new_firmware_size > partition_size) {
|
|
||||||
MG_ERROR(("Firmware %lu bytes, max %lu", new_firmware_size, partition_size));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
update_partition = esp_ota_get_next_update_partition(NULL);
|
|
||||||
if (NULL == update_partition) {
|
|
||||||
MG_ERROR(("esp_ota_get_next_update_partition returned NULL"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
esp_err_t res = esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
esp_ota_abort(update_handle);
|
|
||||||
MG_ERROR(("esp_ota_begin failed (%s)", esp_err_to_name(res)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
s_size = new_firmware_size;
|
|
||||||
MG_INFO(("Starting OTA, firmware size %lu", s_size));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mg_ota_write(const void *buf, size_t len) {
|
|
||||||
if (s_size == 0) {
|
|
||||||
MG_ERROR(("OTA is not started, call mg_ota_begin()"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!rx_checked) {
|
|
||||||
if (!check_fw_header(buf, len)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
rx_checked = true;
|
|
||||||
}
|
|
||||||
esp_err_t res = esp_ota_write(update_handle, buf, len);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
esp_ota_abort(update_handle);
|
|
||||||
MG_ERROR(("esp_ota_write FAILED (%s)", esp_err_to_name(res)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mg_ota_end(void) {
|
|
||||||
if (0 == s_size) {
|
|
||||||
MG_INFO(("Finishing OTA: fail"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
s_size = 0;
|
|
||||||
esp_err_t err = esp_ota_end(update_handle);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
MG_ERROR(("esp_ota_end failed (%s)!", esp_err_to_name(err)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
err = esp_ota_set_boot_partition(update_partition);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
MG_ERROR(("esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mg_ota_commit(void) {
|
|
||||||
esp_ota_mark_app_valid_cancel_rollback();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mg_ota_rollback(void) {
|
|
||||||
if(esp_ota_check_rollback_is_possible()) {
|
|
||||||
esp_ota_mark_app_invalid_rollback_and_reboot();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
MG_ERROR(("Rollback NOT possible"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mg_ota_status(int fw) {
|
|
||||||
const esp_partition_t *p = get_partition_from_fw(fw);
|
|
||||||
if (NULL == p) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int status = MG_OTA_UNAVAILABLE;
|
|
||||||
|
|
||||||
esp_ota_img_states_t img_state = ESP_OTA_IMG_UNDEFINED;
|
|
||||||
esp_err_t res = esp_ota_get_state_partition(p, &img_state);
|
|
||||||
if (ESP_OK == res) {
|
|
||||||
if (ESP_OTA_IMG_VALID == img_state) {
|
|
||||||
status = MG_OTA_COMMITTED;
|
|
||||||
} else if (ESP_OTA_IMG_UNDEFINED == img_state) {
|
|
||||||
status = MG_OTA_UNCOMMITTED;
|
|
||||||
} else if (ESP_OTA_IMG_INVALID == img_state) {
|
|
||||||
status = MG_OTA_UNAVAILABLE;
|
|
||||||
} else if (ESP_OTA_IMG_ABORTED == img_state) {
|
|
||||||
status = MG_OTA_UNAVAILABLE;
|
|
||||||
} else if (ESP_OTA_IMG_NEW == img_state) {
|
|
||||||
status = MG_OTA_FIRST_BOOT;
|
|
||||||
} else if (ESP_OTA_IMG_PENDING_VERIFY == img_state) {
|
|
||||||
status = MG_OTA_UNCOMMITTED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t mg_ota_crc32(int fw) {
|
|
||||||
(void) fw;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t mg_ota_timestamp(int fw) {
|
|
||||||
const esp_partition_t *p = get_partition_from_fw(fw);
|
|
||||||
|
|
||||||
esp_app_desc_t app;
|
|
||||||
esp_err_t res = esp_ota_get_partition_description(p, &app);
|
|
||||||
if (ESP_OK != res)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct tm datetime = {};
|
|
||||||
if (NULL == strptime(app.date, "%b %d %Y", &datetime))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (NULL == strptime(app.time, "%H:%M:%S", &datetime))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return mktime(&datetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t mg_ota_size(int fw) {
|
|
||||||
const esp_partition_t *p = get_partition_from_fw(fw);
|
|
||||||
if (NULL == p) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return p->size;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#define MG_ARCH MG_ARCH_ESP32
|
|
||||||
|
|
||||||
#define MG_ENABLE_PACKED_FS 1
|
|
||||||
#define MG_TLS MG_TLS_NONE // change to 'MG_TLS_MBED' to enable TLS
|
|
||||||
#define MG_OTA MG_OTA_CUSTOM
|
|
||||||
#define MG_DEVICE MG_DEVICE_CUSTOM
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
// Code taken from the ESP32 IDF WiFi station Example
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "esp_event.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "esp_system.h"
|
|
||||||
#include "esp_wifi.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/event_groups.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "nvs_flash.h"
|
|
||||||
|
|
||||||
#include "lwip/err.h"
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
static EventGroupHandle_t s_wifi_event_group;
|
|
||||||
|
|
||||||
/* The event group allows multiple bits for each event, but we only care about
|
|
||||||
* two events:
|
|
||||||
* - we are connected to the AP with an IP
|
|
||||||
* - we failed to connect after the maximum amount of retries */
|
|
||||||
#define WIFI_CONNECTED_BIT BIT0
|
|
||||||
#define WIFI_FAIL_BIT BIT1
|
|
||||||
|
|
||||||
static int s_retry_num = 0;
|
|
||||||
|
|
||||||
static void event_handler(void *arg, esp_event_base_t event_base,
|
|
||||||
int32_t event_id, void *event_data) {
|
|
||||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
|
||||||
esp_wifi_connect();
|
|
||||||
} else if (event_base == WIFI_EVENT &&
|
|
||||||
event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
|
||||||
if (s_retry_num < 10) {
|
|
||||||
esp_wifi_connect();
|
|
||||||
s_retry_num++;
|
|
||||||
MG_INFO(("retry to connect to the AP"));
|
|
||||||
} else {
|
|
||||||
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
|
|
||||||
}
|
|
||||||
MG_ERROR(("connect to the AP fail"));
|
|
||||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
|
||||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
|
|
||||||
MG_INFO(("IP ADDRESS:" IPSTR, IP2STR(&event->ip_info.ip)));
|
|
||||||
s_retry_num = 0;
|
|
||||||
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void wifi_init(const char *ssid, const char *pass) {
|
|
||||||
esp_err_t ret = nvs_flash_init();
|
|
||||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
|
|
||||||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
|
||||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
|
||||||
ret = nvs_flash_init();
|
|
||||||
}
|
|
||||||
ESP_ERROR_CHECK(ret);
|
|
||||||
|
|
||||||
s_wifi_event_group = xEventGroupCreate();
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_netif_init());
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
|
||||||
esp_netif_create_default_wifi_sta();
|
|
||||||
|
|
||||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
|
||||||
|
|
||||||
esp_event_handler_instance_t instance_any_id;
|
|
||||||
esp_event_handler_instance_t instance_got_ip;
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
|
||||||
WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id));
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
|
||||||
IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip));
|
|
||||||
|
|
||||||
wifi_config_t c = {.sta = {.threshold = {.authmode = WIFI_AUTH_WPA2_PSK},
|
|
||||||
.pmf_cfg = {.capable = true, .required = false}}};
|
|
||||||
snprintf((char *) c.sta.ssid, sizeof(c.sta.ssid), "%s", ssid);
|
|
||||||
snprintf((char *) c.sta.password, sizeof(c.sta.password), "%s", pass);
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &c));
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_start());
|
|
||||||
MG_DEBUG(("wifi_init_sta finished."));
|
|
||||||
|
|
||||||
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
|
||||||
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
|
|
||||||
pdFALSE, pdFALSE, portMAX_DELAY);
|
|
||||||
|
|
||||||
if (bits & WIFI_CONNECTED_BIT) {
|
|
||||||
MG_INFO(("connected to ap SSID:%s password:%s", ssid, pass));
|
|
||||||
} else if (bits & WIFI_FAIL_BIT) {
|
|
||||||
MG_ERROR(("Failed to connect to SSID:%s, password:%s", ssid, pass));
|
|
||||||
} else {
|
|
||||||
MG_ERROR(("UNEXPECTED EVENT"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The event will not be processed after unregister */
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
|
|
||||||
IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
|
|
||||||
WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
|
|
||||||
vEventGroupDelete(s_wifi_event_group);
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# Mongoose as a MicroPython user module on the ESP32
|
|
||||||
|
|
||||||
The most basic usage is:
|
|
||||||
|
|
||||||
```python
|
|
||||||
import network
|
|
||||||
import mongoose
|
|
||||||
|
|
||||||
sta_if = network.WLAN(network.STA_IF)
|
|
||||||
sta_if.active(True)
|
|
||||||
sta_if.connect("<SSID>", "<PASSWORD>")
|
|
||||||
while not sta_if.isconnected():
|
|
||||||
pass
|
|
||||||
|
|
||||||
mongoose.init()
|
|
||||||
while True:
|
|
||||||
mongoose.poll(1000)
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Check [_thread](https://docs.micropython.org/en/latest/library/_thread.html) support for more advanced usage
|
|
||||||
|
|
||||||
https://docs.micropython.org/en/latest/develop/cmodules.html
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../micropython/mongoose/micropython.cmake
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../micropython/mongoose/micropython.mk
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../micropython/mongoose/module.c
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
CWD = $(realpath $(CURDIR))
|
|
||||||
MNT = $(realpath $(CURDIR)/../../..)
|
|
||||||
PORT ?= /dev/ttyUSB0
|
|
||||||
CMD ?= build
|
|
||||||
|
|
||||||
all: example
|
|
||||||
|
|
||||||
example:
|
|
||||||
true
|
|
||||||
|
|
||||||
build: Makefile $(wildcard main/*)
|
|
||||||
docker run --rm $(DA) -v $(MNT):$(MNT) -w $(CWD) espressif/idf idf.py $(CMD)
|
|
||||||
|
|
||||||
flash:
|
|
||||||
flash: CMD = flash
|
|
||||||
flash: DA = --device $(PORT)
|
|
||||||
flash: build
|
|
||||||
|
|
||||||
.PHONY: build
|
|
||||||
|
|
||||||
bridge.hex: build
|
|
||||||
esputil mkhex \
|
|
||||||
0x8000 build/partition_table/partition-table.bin \
|
|
||||||
0x1000 build/bootloader/bootloader.bin \
|
|
||||||
0x100000 build/mongoose-esp32-example.bin > $@
|
|
||||||
|
|
||||||
flash2: bridge.hex
|
|
||||||
esputil -p $(PORT) -b 921600 -fp 0x220 flash bridge.hex
|
|
||||||
esputil -p $(PORT) monitor
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf build
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
// Copyright (c) 2020 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
|
|
||||||
#include "main.h"
|
|
||||||
|
|
||||||
const char *s_listening_url = "http://0.0.0.0:80";
|
|
||||||
|
|
||||||
struct mg_str config_read(void) {
|
|
||||||
return mg_file_read(&mg_fs_posix, FS_ROOT "/config.json");
|
|
||||||
}
|
|
||||||
|
|
||||||
void config_write(struct mg_str config) {
|
|
||||||
mg_file_write(&mg_fs_posix, FS_ROOT "/config.json", config.buf, config.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_main(void) {
|
|
||||||
// Mount filesystem
|
|
||||||
esp_vfs_spiffs_conf_t conf = {
|
|
||||||
.base_path = FS_ROOT, .max_files = 20, .format_if_mount_failed = true};
|
|
||||||
int res = esp_vfs_spiffs_register(&conf);
|
|
||||||
MG_INFO(("FS at %s initialised, status: %d", conf.base_path, res));
|
|
||||||
|
|
||||||
// Try to connect to wifi by using saved WiFi credentials
|
|
||||||
struct mg_str json = mg_file_read(&mg_fs_posix, WIFI_FILE);
|
|
||||||
if (json.buf != NULL) {
|
|
||||||
char *ssid = mg_json_get_str(json, "$.ssid");
|
|
||||||
char *pass = mg_json_get_str(json, "$.pass");
|
|
||||||
while (!wifi_init(ssid, pass)) (void) 0;
|
|
||||||
free(ssid);
|
|
||||||
free(pass);
|
|
||||||
free((void *) json.buf);
|
|
||||||
} else {
|
|
||||||
// If WiFi is not configured, run CLI until configured
|
|
||||||
MG_INFO(("WiFi is not configured, running CLI. Press enter"));
|
|
||||||
cli_init();
|
|
||||||
for (;;) {
|
|
||||||
uint8_t ch = getchar();
|
|
||||||
cli(ch);
|
|
||||||
usleep(10000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connected to WiFi, now start HTTP server
|
|
||||||
struct mg_mgr mgr;
|
|
||||||
mg_mgr_init(&mgr);
|
|
||||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
|
||||||
MG_INFO(("Mongoose v%s on %s", MG_VERSION, s_listening_url));
|
|
||||||
mg_http_listen(&mgr, s_listening_url, uart_bridge_fn, NULL);
|
|
||||||
for (;;) mg_mgr_poll(&mgr, 10); // Infinite event loop
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../uart-bridge/net.c
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../uart-bridge/packed_fs.c
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
// Code taken from the ESP32 IDF WiFi station Example
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "esp_event.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "esp_system.h"
|
|
||||||
#include "esp_wifi.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/event_groups.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "nvs_flash.h"
|
|
||||||
|
|
||||||
#include "lwip/err.h"
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
static EventGroupHandle_t s_wifi_event_group;
|
|
||||||
|
|
||||||
/* The event group allows multiple bits for each event, but we only care about
|
|
||||||
* two events:
|
|
||||||
* - we are connected to the AP with an IP
|
|
||||||
* - we failed to connect after the maximum amount of retries */
|
|
||||||
#define WIFI_CONNECTED_BIT BIT0
|
|
||||||
#define WIFI_FAIL_BIT BIT1
|
|
||||||
|
|
||||||
static int s_retry_num = 0;
|
|
||||||
|
|
||||||
static void event_handler(void *arg, esp_event_base_t event_base,
|
|
||||||
int32_t event_id, void *event_data) {
|
|
||||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
|
||||||
esp_wifi_connect();
|
|
||||||
} else if (event_base == WIFI_EVENT &&
|
|
||||||
event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
|
||||||
if (s_retry_num < 3) {
|
|
||||||
esp_wifi_connect();
|
|
||||||
s_retry_num++;
|
|
||||||
MG_INFO(("retry to connect to the AP"));
|
|
||||||
} else {
|
|
||||||
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
|
|
||||||
}
|
|
||||||
MG_ERROR(("connect to the AP fail"));
|
|
||||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
|
||||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
|
|
||||||
MG_INFO(("IP ADDRESS: " IPSTR ". Go to:", IP2STR(&event->ip_info.ip)));
|
|
||||||
MG_INFO(("http://" IPSTR, IP2STR(&event->ip_info.ip)));
|
|
||||||
s_retry_num = 0;
|
|
||||||
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wifi_init(const char *ssid, const char *pass) {
|
|
||||||
bool result = false;
|
|
||||||
esp_err_t ret = nvs_flash_init();
|
|
||||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
|
|
||||||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
|
||||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
|
||||||
ret = nvs_flash_init();
|
|
||||||
}
|
|
||||||
ESP_ERROR_CHECK(ret);
|
|
||||||
|
|
||||||
s_wifi_event_group = xEventGroupCreate();
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_netif_init());
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
|
||||||
esp_netif_create_default_wifi_sta();
|
|
||||||
|
|
||||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
|
||||||
|
|
||||||
esp_event_handler_instance_t instance_any_id;
|
|
||||||
esp_event_handler_instance_t instance_got_ip;
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
|
||||||
WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id));
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
|
||||||
IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip));
|
|
||||||
|
|
||||||
wifi_config_t c = {.sta = {.threshold = {.authmode = WIFI_AUTH_WPA2_PSK},
|
|
||||||
.pmf_cfg = {.capable = true, .required = false}}};
|
|
||||||
snprintf((char *) c.sta.ssid, sizeof(c.sta.ssid), "%s", ssid);
|
|
||||||
snprintf((char *) c.sta.password, sizeof(c.sta.password), "%s", pass);
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &c));
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_start());
|
|
||||||
MG_DEBUG(("wifi_init_sta finished."));
|
|
||||||
|
|
||||||
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
|
||||||
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
|
|
||||||
pdFALSE, pdFALSE, portMAX_DELAY);
|
|
||||||
|
|
||||||
if (bits & WIFI_CONNECTED_BIT) {
|
|
||||||
MG_INFO(("connected to ap SSID:%s", ssid));
|
|
||||||
result = true;
|
|
||||||
} else if (bits & WIFI_FAIL_BIT) {
|
|
||||||
MG_ERROR(("Failed to connect to SSID:%s, password:%s", ssid, pass));
|
|
||||||
} else {
|
|
||||||
MG_ERROR(("UNEXPECTED EVENT"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The event will not be processed after unregister */
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
|
|
||||||
IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
|
|
||||||
WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
|
|
||||||
vEventGroupDelete(s_wifi_event_group);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
THISDIR = $(realpath $(CURDIR))
|
|
||||||
ROOTDIR = $(realpath $(CURDIR)/../../..)
|
|
||||||
DOCKER ?= docker run --rm $(DA) -v $(ROOTDIR):$(ROOTDIR) -w $(THISDIR) docker.io/mdashnet/8266
|
|
||||||
CMD ?= make -C src defconfig app
|
|
||||||
PORT ?= /dev/ttyUSB0
|
|
||||||
|
|
||||||
all: example
|
|
||||||
|
|
||||||
example:
|
|
||||||
true
|
|
||||||
|
|
||||||
build: Makefile $(wildcard src/main/*)
|
|
||||||
$(DOCKER) $(CMD)
|
|
||||||
|
|
||||||
flash:
|
|
||||||
flash: CMD = python /esp/components/esptool_py/esptool/esptool.py \
|
|
||||||
--chip esp8266 --port $(PORT) --baud 115200 --before default_reset \
|
|
||||||
--after hard_reset write_flash -z --flash_mode dio --flash_freq 40m \
|
|
||||||
--flash_size 2MB 0x10000 $(THISDIR)/src/build/mongoose-example.bin
|
|
||||||
flash: DA = --device $(PORT)
|
|
||||||
flash: build
|
|
||||||
|
|
||||||
buildall:
|
|
||||||
buildall: CMD = make -C src all
|
|
||||||
buildall: build
|
|
||||||
|
|
||||||
flashall:
|
|
||||||
flashall: CMD = python /esp/components/esptool_py/esptool/esptool.py \
|
|
||||||
--chip esp8266 --port $(PORT) --baud 115200 --before default_reset \
|
|
||||||
--after hard_reset write_flash -z --flash_mode dio --flash_freq 40m \
|
|
||||||
--flash_size 2MB 0x0 $(THISDIR)/src/build/bootloader/bootloader.bin \
|
|
||||||
0x10000 $(THISDIR)/src/build/mongoose-example.bin \
|
|
||||||
0x8000 $(THISDIR)/src/build/partitions_singleapp.bin
|
|
||||||
flashall: DA = --device $(PORT)
|
|
||||||
flashall: build
|
|
||||||
|
|
||||||
monitor:
|
|
||||||
monitor: CMD = /esp/tools/idf_monitor.py --port $(PORT) $(THISDIR)/src/build/mongoose-example.elf
|
|
||||||
monitor: build
|
|
||||||
|
|
||||||
.PHONY: build
|
|
||||||
|
|
||||||
clean:
|
|
||||||
test -d src/build && $(DOCKER) rm -rf src/build || true
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../mongoose.c
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../mongoose.h
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
NAME ?= $(notdir $(CURDIR))
|
|
||||||
|
|
||||||
build:
|
|
||||||
git clone --depth 1 https://github.com/mongoose-examples/$(NAME)
|
|
||||||
cp ./../../../mongoose.[ch] $(NAME)
|
|
||||||
make -C $(NAME) build
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf $(NAME)
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
CFLAGS = -W -Wall -Werror -Wextra -Wundef -Wshadow -Wdouble-promotion
|
|
||||||
CFLAGS += -Wformat-truncation -fno-common # -Wconversion is not SDK-friendly
|
|
||||||
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
|
|
||||||
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_xmc7/devices/COMPONENT_CAT1C/include/
|
|
||||||
CFLAGS += -Icmsis_xmc7/devices/COMPONENT_CAT1C/include/ip/
|
|
||||||
CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16 $(CFLAGS_EXTRA)
|
|
||||||
LDSCRIPT = link.ld
|
|
||||||
LDFLAGS ?= -T$(LDSCRIPT) -nostdlib -nostartfiles --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
|
||||||
|
|
||||||
SOURCES = main.c hal.c startup.c
|
|
||||||
CFLAGS += -D__ATOLLIC__ -D__STARTUP_CLEAR_BSS # Make startup code work as expected
|
|
||||||
|
|
||||||
# Mongoose options are defined in mongoose_custom.h
|
|
||||||
SOURCES += mongoose.c net.c packed_fs.c
|
|
||||||
|
|
||||||
# Example specific build options. See README.md
|
|
||||||
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\" -DHTTPS_URL=\"https://0.0.0.0/\"
|
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
|
||||||
RM = cmd /C del /Q /F /S
|
|
||||||
else
|
|
||||||
RM = rm -rf
|
|
||||||
endif
|
|
||||||
|
|
||||||
all build example: firmware.bin
|
|
||||||
|
|
||||||
firmware.bin: firmware.elf
|
|
||||||
arm-none-eabi-objcopy -O binary $< $@
|
|
||||||
|
|
||||||
firmware.elf: cmsis_core cmsis_xmc7 $(SOURCES) hal.h link.ld Makefile
|
|
||||||
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@
|
|
||||||
arm-none-eabi-size $@
|
|
||||||
|
|
||||||
cmsis_core: # ARM CMSIS core headers
|
|
||||||
git clone -q --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
|
|
||||||
cmsis_xmc7:
|
|
||||||
git clone https://github.com/Infineon/mtb-pdl-cat1.git $@
|
|
||||||
echo "" > cmsis_xmc7/devices/COMPONENT_CAT1C/include/ip/system_cat1c.h
|
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) firmware.* *.su cmsis_core cmsis_xmc7 *.zip
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
// Copyright (c) 2024 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
|
|
||||||
#include "hal.h"
|
|
||||||
|
|
||||||
static volatile uint64_t s_ticks; // Milliseconds since boot
|
|
||||||
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
|
|
||||||
s_ticks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_random(void *buf, size_t len) { // Use on-board RNG
|
|
||||||
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
|
|
||||||
uint32_t r = rng_read();
|
|
||||||
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t mg_millis(void) { // Let Mongoose use our uptime function
|
|
||||||
return s_ticks; // Return number of milliseconds since boot
|
|
||||||
}
|
|
||||||
|
|
||||||
void hal_init(void) {
|
|
||||||
clock_init(); // Set system clock to SYS_FREQUENCY
|
|
||||||
SystemCoreClock = SYS_FREQUENCY; // Update SystemCoreClock global var
|
|
||||||
SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms
|
|
||||||
rng_init(); // Initialise random number generator
|
|
||||||
|
|
||||||
uart_init(UART_DEBUG, 115200); // Initialise UART
|
|
||||||
gpio_output(LED1); // Initialise LED1
|
|
||||||
gpio_output(LED2); // Initialise LED2
|
|
||||||
gpio_output(LED3); // Initialise LED3
|
|
||||||
ethernet_init(); // Initialise Ethernet pins
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__ARMCC_VERSION)
|
|
||||||
// Keil specific - implement IO printf redirection
|
|
||||||
int fputc(int c, FILE *stream) {
|
|
||||||
if (stream == stdout || stream == stderr) uart_write_byte(UART_DEBUG, c);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
// ARM GCC specific. ARM GCC is shipped with Newlib C library.
|
|
||||||
// Implement newlib syscalls:
|
|
||||||
// _sbrk() for malloc
|
|
||||||
// _write() for printf redirection
|
|
||||||
// the rest are just stubs
|
|
||||||
#include <sys/stat.h> // For _fstat()
|
|
||||||
|
|
||||||
uint32_t SystemCoreClock;
|
|
||||||
void SystemInit(void) { // Called automatically by startup code
|
|
||||||
}
|
|
||||||
|
|
||||||
int _fstat(int fd, struct stat *st) {
|
|
||||||
(void) fd, (void) st;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern unsigned char _end[]; // End of data section, start of heap. See link.ld
|
|
||||||
static unsigned char *s_current_heap_end = _end;
|
|
||||||
|
|
||||||
size_t hal_ram_used(void) {
|
|
||||||
return (size_t) (s_current_heap_end - _end);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t hal_ram_free(void) {
|
|
||||||
unsigned char endofstack;
|
|
||||||
return (size_t) (&endofstack - s_current_heap_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *_sbrk(int incr) {
|
|
||||||
unsigned char *prev_heap;
|
|
||||||
unsigned char *heap_end = (unsigned char *) ((size_t) &heap_end - 256);
|
|
||||||
prev_heap = s_current_heap_end;
|
|
||||||
// Check how much space we got from the heap end to the stack end
|
|
||||||
if (s_current_heap_end + incr > heap_end) return (void *) -1;
|
|
||||||
s_current_heap_end += incr;
|
|
||||||
return prev_heap;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _open(const char *path) {
|
|
||||||
(void) path;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _close(int fd) {
|
|
||||||
(void) fd;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _isatty(int fd) {
|
|
||||||
(void) fd;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _lseek(int fd, int ptr, int dir) {
|
|
||||||
(void) fd, (void) ptr, (void) dir;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _exit(int status) {
|
|
||||||
(void) status;
|
|
||||||
for (;;) asm volatile("BKPT #0");
|
|
||||||
}
|
|
||||||
|
|
||||||
void _kill(int pid, int sig) {
|
|
||||||
(void) pid, (void) sig;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _getpid(void) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _write(int fd, char *ptr, int len) {
|
|
||||||
(void) fd, (void) ptr, (void) len;
|
|
||||||
if (fd == 1) uart_write_buf(UART_DEBUG, ptr, (size_t) len);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _read(int fd, char *ptr, int len) {
|
|
||||||
(void) fd, (void) ptr, (void) len;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _link(const char *a, const char *b) {
|
|
||||||
(void) a, (void) b;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _unlink(const char *a) {
|
|
||||||
(void) a;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _stat(const char *path, struct stat *st) {
|
|
||||||
(void) path, (void) st;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mkdir(const char *path, mode_t mode) {
|
|
||||||
(void) path, (void) mode;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _init(void) {
|
|
||||||
}
|
|
||||||
#endif // __GNUC__
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
// Copyright (c) 2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define LED1 PIN(16, 1)
|
|
||||||
#define LED2 PIN(16, 2)
|
|
||||||
#define LED3 PIN(16, 3)
|
|
||||||
|
|
||||||
#include "xmc7200d_e272k8384.h"
|
|
||||||
|
|
||||||
#define BIT(x) (1UL << (x))
|
|
||||||
#define CLRSET(reg, clear, set) ((reg) = ((reg) & ~(clear)) | (set))
|
|
||||||
#define PIN(bank, num) ((bank << 8) | (num))
|
|
||||||
#define PINNO(pin) (pin & 255)
|
|
||||||
#define PINBANK(pin) (pin >> 8)
|
|
||||||
|
|
||||||
void hal_init(void);
|
|
||||||
size_t hal_ram_free(void);
|
|
||||||
size_t hal_ram_used(void);
|
|
||||||
|
|
||||||
static inline void spin(volatile uint32_t count) {
|
|
||||||
while (count--) (void) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern uint32_t SystemCoreClock;
|
|
||||||
|
|
||||||
enum {PLL_FEEDBACK = 50, PLL_REF = 1, PLL_OUT = 4};
|
|
||||||
#define CLK_IMO 8000000UL
|
|
||||||
#define SYS_FREQUENCY ((CLK_IMO * PLL_FEEDBACK) / (PLL_REF * PLL_OUT))
|
|
||||||
|
|
||||||
#ifndef UART_DEBUG
|
|
||||||
#define UART_DEBUG SCB3
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG };
|
|
||||||
enum { GPIO_HIGHZ = 0, GPIO_PULLUP = 2, GPIO_PULLDOWN = 3, GPIO_OPENDRAIN_LOW = 4,
|
|
||||||
GPIO_OPENDRAIN_HIGH = 5, GPIO_STRONG = 6, GPIO_PULLUP_DOWN = 7};
|
|
||||||
enum { GPIO_SPEED_LOW = 3, GPIO_SPEED_MEDIUM = 2, GPIO_SPEED_HIGH = 0};
|
|
||||||
#undef GPIO
|
|
||||||
#define GPIO_TypeDef GPIO_PRT_Type
|
|
||||||
#define GPIO(N) ((GPIO_TypeDef *) (GPIO_BASE + 0x80 * (N)))
|
|
||||||
|
|
||||||
static GPIO_TypeDef *gpio_bank(uint16_t pin) { return GPIO(PINBANK(pin)); }
|
|
||||||
|
|
||||||
static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
|
|
||||||
uint8_t speed, uint8_t pull, uint8_t af) {
|
|
||||||
(void) pin, (void) mode, (void) type, (void) speed, (void) pull, (void) af;
|
|
||||||
GPIO_TypeDef *gpio = gpio_bank(pin);
|
|
||||||
uint8_t pinno = PINNO(pin);
|
|
||||||
uint32_t msk, pos;
|
|
||||||
|
|
||||||
// configure input / output direction
|
|
||||||
if (mode == GPIO_MODE_INPUT) {
|
|
||||||
gpio->CFG |= 1 << (4 * pinno + 3); // enable input buffer (IN_ENx)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (af || (mode == GPIO_MODE_AF && af)) {
|
|
||||||
// configure alternate function
|
|
||||||
HSIOM_PRT_Type* hsiom = ((HSIOM_PRT_Type*) HSIOM) + PINBANK(pin);
|
|
||||||
volatile uint32_t *port_sel = pinno < 4 ? &hsiom->PORT_SEL0 : &hsiom->PORT_SEL1;
|
|
||||||
pos = 8 * (pinno % 4), msk = 0x1f << pos;
|
|
||||||
*port_sel &= ~msk, *port_sel |= af << pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
// configure driver mode
|
|
||||||
msk = 7, pos = 4 * pinno;
|
|
||||||
CLRSET(gpio->CFG, msk << pos, type << pos);
|
|
||||||
|
|
||||||
// configure speed
|
|
||||||
msk = 3, pos = 2 * pinno + 16;
|
|
||||||
CLRSET(gpio->CFG_OUT, msk << pos, speed << pos);
|
|
||||||
|
|
||||||
if (mode == GPIO_MODE_OUTPUT /*&& af == 0*/) {
|
|
||||||
gpio->OUT_SET = (1 << pinno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void gpio_input(uint16_t pin) {
|
|
||||||
gpio_init(pin, GPIO_MODE_INPUT, GPIO_HIGHZ, GPIO_SPEED_HIGH,
|
|
||||||
0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void gpio_output(uint16_t pin) {
|
|
||||||
gpio_init(pin, GPIO_MODE_OUTPUT, GPIO_STRONG, GPIO_SPEED_MEDIUM,
|
|
||||||
0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool gpio_read(uint16_t pin) {
|
|
||||||
GPIO_TypeDef *gpio = gpio_bank(pin);
|
|
||||||
uint8_t pinno = PINNO(pin);
|
|
||||||
if (gpio->CFG & (1 << (4 * pinno + 3))) {
|
|
||||||
// pin mode is input, reading from GPIO_PRT_IN
|
|
||||||
return gpio->IN & (1 << pinno);
|
|
||||||
} else {
|
|
||||||
// pin mode is output, reading from GPIO_PRT_OUT
|
|
||||||
return gpio->OUT & (1 << pinno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void gpio_write(uint16_t pin, bool value) {
|
|
||||||
GPIO_TypeDef *gpio = gpio_bank(pin);
|
|
||||||
uint8_t pinno = PINNO(pin);
|
|
||||||
if (value) {
|
|
||||||
gpio->OUT_SET = 1 << pinno;
|
|
||||||
} else {
|
|
||||||
gpio->OUT_CLR = 1 << pinno;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void gpio_toggle(uint16_t pin) {
|
|
||||||
gpio_write(pin, !gpio_read(pin));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void uart_init(volatile CySCB_Type *uart, unsigned long baud) {
|
|
||||||
(void) uart, (void) baud;
|
|
||||||
uint16_t rx = 0, tx = 0;
|
|
||||||
if (uart == SCB3) {
|
|
||||||
rx = PIN(13, 0), tx = PIN(13, 1);
|
|
||||||
} else {
|
|
||||||
return; // unsupported uart
|
|
||||||
}
|
|
||||||
|
|
||||||
// set pins
|
|
||||||
gpio_init(rx, GPIO_MODE_INPUT, GPIO_HIGHZ, GPIO_SPEED_HIGH, 0, 17);
|
|
||||||
gpio_init(tx, GPIO_MODE_OUTPUT, GPIO_STRONG, GPIO_SPEED_HIGH, 0, 17);
|
|
||||||
|
|
||||||
// enable peripheral clock (18.6.2)
|
|
||||||
// compute divider first (we choose 24 bit divider 0)
|
|
||||||
unsigned long div = 0, frac = 0, ovs = 16;
|
|
||||||
div = SYS_FREQUENCY / (baud * ovs);
|
|
||||||
if (div == 0) div = 1;
|
|
||||||
frac = SYS_FREQUENCY % (baud * ovs);
|
|
||||||
frac = (frac * 100) / (baud * ovs);
|
|
||||||
PERI_PCLK->GR[1].DIV_CMD = (3 << PERI_PCLK_GR_DIV_CMD_TYPE_SEL_Pos) |
|
|
||||||
PERI_PCLK_GR_DIV_CMD_PA_DIV_SEL_Msk |
|
|
||||||
PERI_PCLK_GR_DIV_CMD_PA_TYPE_SEL_Msk;
|
|
||||||
PERI_PCLK->GR[1].DIV_CMD |= PERI_PCLK_GR_DIV_CMD_DISABLE_Msk; // disable divider
|
|
||||||
PERI_PCLK->GR[1].DIV_24_5_CTL[0] = (((uint8_t) (div - 1)) << PERI_PCLK_GR_DIV_24_5_CTL_INT24_DIV_Pos) |
|
|
||||||
(frac << PERI_PCLK_GR_DIV_24_5_CTL_FRAC5_DIV_Pos);
|
|
||||||
PERI_PCLK->GR[1].DIV_CMD = (3 << PERI_PCLK_GR_DIV_CMD_TYPE_SEL_Pos) |
|
|
||||||
PERI_PCLK_GR_DIV_CMD_PA_DIV_SEL_Msk |
|
|
||||||
PERI_PCLK_GR_DIV_CMD_PA_TYPE_SEL_Msk;;
|
|
||||||
PERI_PCLK->GR[1].DIV_CMD |= PERI_PCLK_GR_DIV_CMD_ENABLE_Msk; // enable divider
|
|
||||||
PERI_PCLK->GR[1].CLOCK_CTL[PCLK_SCB3_CLOCK & 0xff] = 3 << PERI_PCLK_GR_CLOCK_CTL_TYPE_SEL_Pos; // connect SCB3 to div_24_5_ctl[0]
|
|
||||||
|
|
||||||
// configure UART interface
|
|
||||||
uart->CTRL = ((ovs - 1) << SCB_CTRL_OVS_Pos) | (2 << SCB_CTRL_MODE_Pos);
|
|
||||||
uart->UART_CTRL = 0;
|
|
||||||
uart->UART_RX_CTRL = 1 << SCB_UART_RX_CTRL_STOP_BITS_Pos;
|
|
||||||
uart->RX_CTRL = 7 << SCB_RX_CTRL_DATA_WIDTH_Pos;
|
|
||||||
uart->UART_TX_CTRL = 1 << SCB_UART_TX_CTRL_STOP_BITS_Pos;
|
|
||||||
uart->TX_CTRL = 7 << SCB_TX_CTRL_DATA_WIDTH_Pos;
|
|
||||||
uart->TX_FIFO_CTRL = 1 << 16;
|
|
||||||
uart->TX_FIFO_CTRL = 0;
|
|
||||||
uart->CTRL |= 1 << SCB_CTRL_ENABLED_Pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void uart_write_byte(volatile CySCB_Type *uart, uint8_t byte) {
|
|
||||||
(void) byte; (void) uart;
|
|
||||||
while((uart->INTR_TX & SCB_INTR_TX_EMPTY_Msk) == 0) spin(1);
|
|
||||||
uart->TX_FIFO_WR = byte;
|
|
||||||
uart->INTR_TX |= ~SCB_INTR_TX_EMPTY_Msk;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void uart_write_buf(volatile CySCB_Type *uart, char *buf, size_t len) {
|
|
||||||
while (len-- > 0) uart_write_byte(uart, *(uint8_t *) buf++);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void rng_init(void) {
|
|
||||||
}
|
|
||||||
static inline uint32_t rng_read(void) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ethernet_init(void) {
|
|
||||||
gpio_init(PIN(26, 0), GPIO_MODE_INPUT, GPIO_HIGHZ, GPIO_SPEED_HIGH, 0, 27); // ETH1_REF_CLK
|
|
||||||
gpio_init(PIN(26, 1), GPIO_MODE_OUTPUT, GPIO_STRONG, GPIO_SPEED_HIGH, 0, 27); // ETH1_TX_CTL
|
|
||||||
gpio_init(PIN(26, 2), GPIO_MODE_OUTPUT, GPIO_STRONG, GPIO_SPEED_HIGH, 0, 27); // ETH1_TX_CLK
|
|
||||||
gpio_init(PIN(26, 3), GPIO_MODE_OUTPUT, GPIO_STRONG, GPIO_SPEED_HIGH, 0, 27); // ETH1_TXD_0
|
|
||||||
gpio_init(PIN(26, 4), GPIO_MODE_OUTPUT, GPIO_STRONG, GPIO_SPEED_HIGH, 0, 27); // ETH1_TXD_1
|
|
||||||
gpio_init(PIN(26, 5), GPIO_MODE_OUTPUT, GPIO_STRONG, GPIO_SPEED_HIGH, 0, 27); // ETH1_TXD_2
|
|
||||||
gpio_init(PIN(26, 6), GPIO_MODE_OUTPUT, GPIO_STRONG, GPIO_SPEED_HIGH, 0, 27); // ETH1_TXD_3
|
|
||||||
gpio_init(PIN(26, 7), GPIO_MODE_INPUT, GPIO_HIGHZ, GPIO_SPEED_HIGH, 0, 27); // ETH1_RXD_0
|
|
||||||
|
|
||||||
gpio_init(PIN(27, 0), GPIO_MODE_INPUT, GPIO_HIGHZ, GPIO_SPEED_HIGH, 0, 27); // ETH1_RXD_1
|
|
||||||
gpio_init(PIN(27, 1), GPIO_MODE_INPUT, GPIO_HIGHZ, GPIO_SPEED_HIGH, 0, 27); // ETH1_RXD_2
|
|
||||||
gpio_init(PIN(27, 2), GPIO_MODE_INPUT, GPIO_HIGHZ, GPIO_SPEED_HIGH, 0, 27); // ETH1_RXD_3
|
|
||||||
gpio_init(PIN(27, 3), GPIO_MODE_INPUT, GPIO_HIGHZ, GPIO_SPEED_HIGH, 0, 27); // ETH1_RX_CTL
|
|
||||||
gpio_init(PIN(27, 4), GPIO_MODE_INPUT, GPIO_HIGHZ, GPIO_SPEED_HIGH, 0, 27); // ETH1_RX_CLK
|
|
||||||
gpio_init(PIN(27, 5), GPIO_MODE_INPUT, GPIO_STRONG, GPIO_SPEED_LOW, 0, 27); // ETH1_MDIO
|
|
||||||
gpio_init(PIN(27, 6), GPIO_MODE_OUTPUT, GPIO_STRONG, GPIO_SPEED_LOW, 0, 27); // ETH1_MDC
|
|
||||||
//gpio_init(PIN(27, 7), GPIO_MODE_OUTPUT, GPIO_HIGHZ, GPIO_SPEED_HIGH, 0, 0); // ETH1_RST
|
|
||||||
|
|
||||||
CPUSS->CM7_0_SYSTEM_INT_CTL[eth_1_interrupt_eth_0_IRQn] = 0x80000003; // assign CPU interrupt #3
|
|
||||||
NVIC->ISER[0] = 1 << 3;
|
|
||||||
|
|
||||||
spin(10000000); // artificial delay to wait for PHY init
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void clock_init(void) {
|
|
||||||
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU
|
|
||||||
asm("DSB");
|
|
||||||
asm("ISB");
|
|
||||||
|
|
||||||
// configure PLL
|
|
||||||
CLRSET(SRSS->CLK_PLL400M[0].CONFIG, CLK_PLL400M_CONFIG_BYPASS_SEL_Msk, BIT(29)); // First bypass PLL
|
|
||||||
spin(10);
|
|
||||||
SRSS->CLK_PLL400M[0].CONFIG &= ~CLK_PLL400M_CONFIG_ENABLE_Msk; // disable the PLL itself
|
|
||||||
|
|
||||||
// IMO source generates a frequency of 8MHz. The final frequency will be
|
|
||||||
// calculated as (CLK_IMO * feedback) / (reference * output_div)
|
|
||||||
CLRSET(SRSS->CLK_PLL400M[0].CONFIG, CLK_PLL400M_CONFIG_FEEDBACK_DIV_Msk, PLL_FEEDBACK << CLK_PLL400M_CONFIG_FEEDBACK_DIV_Pos);
|
|
||||||
CLRSET(SRSS->CLK_PLL400M[0].CONFIG, CLK_PLL400M_CONFIG_REFERENCE_DIV_Msk, PLL_REF << CLK_PLL400M_CONFIG_REFERENCE_DIV_Pos);
|
|
||||||
CLRSET(SRSS->CLK_PLL400M[0].CONFIG, CLK_PLL400M_CONFIG_OUTPUT_DIV_Msk, PLL_OUT << CLK_PLL400M_CONFIG_OUTPUT_DIV_Pos);
|
|
||||||
CLRSET(SRSS->CLK_PLL400M[0].CONFIG2, CLK_PLL400M_CONFIG2_FRAC_DIV_Msk, 0);
|
|
||||||
CLRSET(SRSS->CLK_PLL400M[0].CONFIG2, CLK_PLL400M_CONFIG2_FRAC_DITHER_EN_Msk, 0);
|
|
||||||
CLRSET(SRSS->CLK_PLL400M[0].CONFIG2, CLK_PLL400M_CONFIG2_FRAC_EN_Msk, 1 << CLK_PLL400M_CONFIG2_FRAC_EN_Pos);
|
|
||||||
CLRSET(SRSS->CLK_PLL400M[0].CONFIG, CLK_PLL400M_CONFIG_BYPASS_SEL_Msk, 0);
|
|
||||||
spin(10);
|
|
||||||
SRSS->CLK_PLL400M[0].CONFIG |= CLK_PLL400M_CONFIG_ENABLE_Msk; // enable the PLL
|
|
||||||
while (SRSS->CLK_PLL400M[0].CONFIG & 1) spin(1);
|
|
||||||
|
|
||||||
// configure PATH1 with source set to IMO
|
|
||||||
SRSS->CLK_PATH_SELECT[1] = 0;
|
|
||||||
|
|
||||||
// enable CLK_HFx
|
|
||||||
uint8_t clocks[] = {0, 1, 2, 3, 4, 5, 6};
|
|
||||||
for (size_t i = 0; i < sizeof(clocks) / sizeof(uint8_t); i++) {
|
|
||||||
CLRSET(SRSS->CLK_ROOT_SELECT[clocks[i]], SRSS_CLK_ROOT_SELECT_ROOT_MUX_Msk, 1); // choose PATH1
|
|
||||||
CLRSET(SRSS->CLK_ROOT_SELECT[clocks[i]], SRSS_CLK_ROOT_SELECT_DIRECT_MUX_Msk, 1 << SRSS_CLK_ROOT_SELECT_DIRECT_MUX_Pos);
|
|
||||||
if (clocks[i] != 0) // CLF_HF0 is already enabled
|
|
||||||
SRSS->CLK_ROOT_SELECT[clocks[i]] |= SRSS_CLK_ROOT_SELECT_ENABLE_Msk; // enable clock root
|
|
||||||
}
|
|
||||||
|
|
||||||
// set systick frequency
|
|
||||||
uint32_t tenms = SYS_FREQUENCY / 100 - 1; // number of cycles executed in 10ms
|
|
||||||
CPUSS->SYSTICK_CTL = tenms | (3 << CPUSS_SYSTICK_CTL_CLOCK_SOURCE_Pos); // select CLK_HF as source
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
OUTPUT_FORMAT("elf32-littlearm")
|
|
||||||
OUTPUT_ARCH(arm)
|
|
||||||
ENTRY(Reset_Handler)
|
|
||||||
|
|
||||||
MEMORY
|
|
||||||
{
|
|
||||||
flash(RX) : ORIGIN = 0x10080000, LENGTH = 0x80000
|
|
||||||
sram(!RX) : ORIGIN = 0x28000800, LENGTH = 510K
|
|
||||||
}
|
|
||||||
|
|
||||||
_estack = ORIGIN(sram) + LENGTH(sram);
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
.vectors : { . = ALIGN(4); KEEP(*(.vectors)); . = ALIGN(4); } > flash
|
|
||||||
.text : { *(.text*) } > flash
|
|
||||||
.rodata : { *(.rodata*) } > flash
|
|
||||||
|
|
||||||
.data : {
|
|
||||||
_sdata = .;
|
|
||||||
*(.first_data)
|
|
||||||
*(.data SORT(.data.*))
|
|
||||||
_edata = .;
|
|
||||||
} > sram AT > flash
|
|
||||||
_sidata = LOADADDR(.data);
|
|
||||||
|
|
||||||
.bss : { _sbss = .; *(.bss SORT(.bss.*) COMMON) _ebss = .; } > sram
|
|
||||||
|
|
||||||
. = ALIGN(8);
|
|
||||||
_end = .;
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
// Copyright (c) 2024 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
|
|
||||||
#include "hal.h"
|
|
||||||
#include "mongoose.h"
|
|
||||||
#include "net.h"
|
|
||||||
|
|
||||||
#define BLINK_PERIOD_MS 1000
|
|
||||||
|
|
||||||
static void timer_fn(void *arg) {
|
|
||||||
gpio_toggle(LED1); // Blink LED
|
|
||||||
(void) arg; // Unused
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
struct mg_mgr mgr; // Mongoose event manager
|
|
||||||
|
|
||||||
hal_init(); // Cross-platform hardware init
|
|
||||||
|
|
||||||
mg_mgr_init(&mgr); // Initialise it
|
|
||||||
mg_log_set(MG_LL_DEBUG); // Set log level to debug
|
|
||||||
mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_fn, &mgr);
|
|
||||||
|
|
||||||
MG_INFO(("Initialising application..."));
|
|
||||||
web_init(&mgr);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
mg_mgr_poll(&mgr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// See https://mongoose.ws/documentation/#build-options
|
|
||||||
#define MG_ARCH MG_ARCH_NEWLIB
|
|
||||||
|
|
||||||
#define MG_ENABLE_TCPIP 1
|
|
||||||
#define MG_ENABLE_DRIVER_XMC7 1
|
|
||||||
#define MG_IO_SIZE 256
|
|
||||||
#define MG_ENABLE_CUSTOM_MILLIS 1
|
|
||||||
#define MG_ENABLE_CUSTOM_RANDOM 1
|
|
||||||
#define MG_ENABLE_PACKED_FS 1
|
|
||||||
|
|
||||||
// For static IP configuration, define MG_TCPIP_{IP,MASK,GW}
|
|
||||||
// By default, those are set to zero, meaning that DHCP is used
|
|
||||||
//
|
|
||||||
// #define MG_TCPIP_IP MG_IPV4(192, 168, 1, 10)
|
|
||||||
// #define MG_TCPIP_GW MG_IPV4(192, 168, 1, 1)
|
|
||||||
// #define MG_TCPIP_MASK MG_IPV4(255, 255, 255, 0)
|
|
||||||
|
|
||||||
// Set custom MAC address. By default, it is randomly generated
|
|
||||||
// Using a build-time constant:
|
|
||||||
// #define MG_SET_MAC_ADDRESS(mac) do { uint8_t buf_[6] = {2,3,4,5,6,7}; memmove(mac, buf_, sizeof(buf_)); } while (0)
|
|
||||||
//
|
|
||||||
// Using custom function:
|
|
||||||
// extern void my_function(unsigned char *mac);
|
|
||||||
// #define MG_SET_MAC_ADDRESS(mac) my_function(mac)
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
#include "xmc7200d_e272k8384.h"
|
|
||||||
|
|
||||||
void Reset_Handler(void); // Defined below
|
|
||||||
void Dummy_Handler(void); // Defined below
|
|
||||||
void SysTick_Handler(void); // Defined in main.c
|
|
||||||
void SystemInit(void); // Defined in main.c, called by reset handler
|
|
||||||
void _estack(void); // Defined in link.ld
|
|
||||||
|
|
||||||
#define WEAK_ALIAS __attribute__((weak, alias("Default_Handler")))
|
|
||||||
|
|
||||||
WEAK_ALIAS void NMI_Handler(void);
|
|
||||||
WEAK_ALIAS void HardFault_Handler(void);
|
|
||||||
WEAK_ALIAS void SVCall_Handler(void);
|
|
||||||
WEAK_ALIAS void PendSV_Handler(void);
|
|
||||||
WEAK_ALIAS void SysTick_Handler(void);
|
|
||||||
|
|
||||||
WEAK_ALIAS void Default_Intr_Handler(void);
|
|
||||||
WEAK_ALIAS void CM0P_CpuIntr0_Handler(void);
|
|
||||||
WEAK_ALIAS void CM0P_CpuIntr1_Handler(void);
|
|
||||||
WEAK_ALIAS void CM0P_CpuIntr2_Handler(void);
|
|
||||||
WEAK_ALIAS void CM0P_CpuIntr4_Handler(void);
|
|
||||||
WEAK_ALIAS void CM0P_CpuIntr5_Handler(void);
|
|
||||||
WEAK_ALIAS void CM0P_CpuIntr6_Handler(void);
|
|
||||||
WEAK_ALIAS void CM0P_CpuIntr7_Handler(void);
|
|
||||||
WEAK_ALIAS void ETH_IRQHandler(void);
|
|
||||||
|
|
||||||
void CM0P_CpuIntr3_Handler(void) {
|
|
||||||
ETH_IRQHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((section(".vectors"))) void (*const tab[16 + 16])(void) = {
|
|
||||||
_estack,
|
|
||||||
Reset_Handler,
|
|
||||||
NMI_Handler,
|
|
||||||
HardFault_Handler,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
SVCall_Handler,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
PendSV_Handler,
|
|
||||||
SysTick_Handler,
|
|
||||||
CM0P_CpuIntr0_Handler,
|
|
||||||
CM0P_CpuIntr1_Handler,
|
|
||||||
CM0P_CpuIntr2_Handler,
|
|
||||||
CM0P_CpuIntr3_Handler,
|
|
||||||
CM0P_CpuIntr4_Handler,
|
|
||||||
CM0P_CpuIntr5_Handler,
|
|
||||||
CM0P_CpuIntr6_Handler,
|
|
||||||
CM0P_CpuIntr7_Handler,
|
|
||||||
Default_Intr_Handler,
|
|
||||||
Default_Intr_Handler,
|
|
||||||
Default_Intr_Handler,
|
|
||||||
Default_Intr_Handler,
|
|
||||||
Default_Intr_Handler,
|
|
||||||
Default_Intr_Handler,
|
|
||||||
Default_Intr_Handler,
|
|
||||||
Default_Intr_Handler
|
|
||||||
};
|
|
||||||
|
|
||||||
__attribute__((naked, noreturn)) void Reset_Handler(void) {
|
|
||||||
// Clear BSS section, and copy data section from flash to RAM
|
|
||||||
extern long _sbss, _ebss, _sdata, _edata, _sidata;
|
|
||||||
for (long *src = &_sbss; src < &_ebss; src++) *src = 0;
|
|
||||||
for (long *src = &_sdata, *dst = &_sidata; src < &_edata;) *src++ = *dst++;
|
|
||||||
|
|
||||||
SCB->VTOR = (uint32_t) &tab;
|
|
||||||
SystemInit();
|
|
||||||
|
|
||||||
// Call main()
|
|
||||||
extern void main(void);
|
|
||||||
main();
|
|
||||||
for (;;) (void) 0; // Infinite loop
|
|
||||||
}
|
|
||||||
|
|
||||||
void Default_Handler(void) {
|
|
||||||
for (;;) (void) 0;
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
CFLAGS = -W -Wall -Wextra -Wundef -Wshadow -Wdouble-promotion
|
|
||||||
CFLAGS += -Wformat-truncation -fno-common -Wconversion
|
|
||||||
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
|
|
||||||
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include
|
|
||||||
CFLAGS += -D__SAME54P20A__ -Icmsis_sam/include
|
|
||||||
CFLAGS += -mcpu=cortex-m4 -mthumb -mfloat-abi=softfp
|
|
||||||
LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
|
||||||
|
|
||||||
SOURCES = main.c syscalls.c startup.c
|
|
||||||
|
|
||||||
# Mongoose-specific source code files and build options. See https://mongoose.ws/documentation/#build-options
|
|
||||||
SOURCES += mongoose.c net.c packed_fs.c
|
|
||||||
CFLAGS += -DMG_ENABLE_TCPIP=1 -DMG_ARCH=MG_ARCH_NEWLIB -DMG_ENABLE_CUSTOM_MILLIS=1 -DMG_ENABLE_LINES=1
|
|
||||||
CFLAGS += -DMG_ENABLE_DRIVER_SAME54=1 -DMG_ENABLE_CUSTOM_RANDOM=1 -DMG_ENABLE_PACKED_FS=1 $(CFLAGS_EXTRA)
|
|
||||||
|
|
||||||
# Example specific build options. See README.md
|
|
||||||
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\"
|
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
|
||||||
RM = cmd /C del /Q /F
|
|
||||||
else
|
|
||||||
RM = rm -rf
|
|
||||||
endif
|
|
||||||
|
|
||||||
build: firmware.bin
|
|
||||||
|
|
||||||
firmware.bin: firmware.elf
|
|
||||||
arm-none-eabi-objcopy -O binary $< $@
|
|
||||||
|
|
||||||
firmware.elf: cmsis_core cmsis_sam hal.h link.ld Makefile $(SOURCES)
|
|
||||||
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@
|
|
||||||
|
|
||||||
flash: firmware.bin
|
|
||||||
bossac -p /dev/cu.usb* -w -v -b $<
|
|
||||||
|
|
||||||
cmsis_core:
|
|
||||||
git clone --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
|
|
||||||
cmsis_sam:
|
|
||||||
curl -sL https://packs.download.microchip.com/Microchip.SAME54_DFP.3.8.234.pack -o $@.zip
|
|
||||||
mkdir $@ && cd $@ && unzip ../$@.zip
|
|
||||||
|
|
||||||
# Automated test via https://vcon.io/automated-firmware-tests/. Set VCON_API_KEY and update DEVICE_URL
|
|
||||||
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/9
|
|
||||||
update: firmware.bin
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @$<
|
|
||||||
|
|
||||||
test update: CFLAGS += -DUART_DEBUG=USART1
|
|
||||||
test: update
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
|
|
||||||
grep 'READY, IP:' /tmp/output.txt # Check for network init
|
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) firmware.* cmsis_core cmsis_sam *.zip
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022-2023 Cesanta Software Limited
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
#include "hal.h"
|
|
||||||
#include "mongoose.h"
|
|
||||||
#include "net.h"
|
|
||||||
|
|
||||||
#define BLINK_PERIOD_MS 500 // LED blinking period in millis
|
|
||||||
#define LOG_PERIOD_MS 1000 // Info log period in millis
|
|
||||||
|
|
||||||
void SystemInit(void) { // Called automatically by startup code
|
|
||||||
clock_init();
|
|
||||||
rng_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
static volatile uint64_t s_ticks; // Milliseconds since boot
|
|
||||||
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
|
|
||||||
s_ticks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t mg_millis(void) { // Let Mongoose use our uptime function
|
|
||||||
return s_ticks; // Return number of milliseconds since boot
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_random(void *buf, size_t len) { // Use on-board RNG
|
|
||||||
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
|
|
||||||
uint32_t r = rng_read();
|
|
||||||
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void timer_fn(void *arg) {
|
|
||||||
struct mg_tcpip_if *ifp = arg; // show network stats
|
|
||||||
const char *names[] = {"down", "up", "req", "ready"};
|
|
||||||
MG_INFO(("Ethernet: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u",
|
|
||||||
names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent,
|
|
||||||
ifp->ndrop, ifp->nerr));
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
gpio_input(BUTTON_PIN);
|
|
||||||
gpio_output(LED_PIN);
|
|
||||||
uart_init(UART_DEBUG, 115200);
|
|
||||||
ethernet_init();
|
|
||||||
|
|
||||||
MG_INFO(("Starting, CPU freq %g MHz", (double) clock_sys_freq() / 1000000));
|
|
||||||
|
|
||||||
struct mg_mgr mgr; // Initialise
|
|
||||||
mg_mgr_init(&mgr); // Mongoose event manager
|
|
||||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
|
||||||
|
|
||||||
// Initialise Mongoose network stack
|
|
||||||
struct mg_tcpip_driver_same54_data driver_data = {.mdc_cr = 5};
|
|
||||||
struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC()/*{2, 3, 4, 5, 6, 7}*/,
|
|
||||||
// Uncomment below for static configuration:
|
|
||||||
// .ip = mg_htonl(MG_U32(192, 168, 0, 223)),
|
|
||||||
// .mask = mg_htonl(MG_U32(255, 255, 255, 0)),
|
|
||||||
// .gw = mg_htonl(MG_U32(192, 168, 0, 1)),
|
|
||||||
.driver = &mg_tcpip_driver_same54,
|
|
||||||
.driver_data = &driver_data};
|
|
||||||
mg_tcpip_init(&mgr, &mif);
|
|
||||||
mg_timer_add(&mgr, LOG_PERIOD_MS, MG_TIMER_REPEAT, timer_fn, &mif);
|
|
||||||
|
|
||||||
MG_INFO(("MAC: %M. Waiting for IP...", mg_print_mac, mif.mac));
|
|
||||||
while (mif.state != MG_TCPIP_STATE_READY) {
|
|
||||||
mg_mgr_poll(&mgr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
MG_INFO(("Initialising application..."));
|
|
||||||
web_init(&mgr);
|
|
||||||
|
|
||||||
MG_INFO(("Starting event loop"));
|
|
||||||
for (;;) {
|
|
||||||
mg_mgr_poll(&mgr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
CFLAGS = -W -Wall -Wextra -Wundef -Wshadow -Wdouble-promotion
|
|
||||||
CFLAGS += -Wformat-truncation -fno-common -Wconversion
|
|
||||||
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
|
|
||||||
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include
|
|
||||||
CFLAGS += -D__SAME54P20A__ -Icmsis_sam/include
|
|
||||||
CFLAGS += -mcpu=cortex-m4 -mthumb -mfloat-abi=softfp
|
|
||||||
LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
|
||||||
|
|
||||||
SOURCES = main.c syscalls.c startup.c
|
|
||||||
|
|
||||||
# Mongoose-specific source code files and build options. See https://mongoose.ws/documentation/#build-options
|
|
||||||
SOURCES += mongoose.c
|
|
||||||
CFLAGS += -DMG_ENABLE_TCPIP=1 -DMG_ARCH=MG_ARCH_NEWLIB -DMG_ENABLE_CUSTOM_MILLIS=1 -DMG_ENABLE_LINES=1
|
|
||||||
CFLAGS += -DMG_ENABLE_DRIVER_SAME54=1 -DMG_ENABLE_CUSTOM_RANDOM=1 -DMG_ENABLE_PACKED_FS=1 $(CFLAGS_EXTRA)
|
|
||||||
|
|
||||||
# Example specific build options. See README.md
|
|
||||||
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\"
|
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
|
||||||
RM = cmd /C del /Q /F
|
|
||||||
else
|
|
||||||
RM = rm -rf
|
|
||||||
endif
|
|
||||||
|
|
||||||
build: firmware.bin
|
|
||||||
|
|
||||||
firmware.bin: firmware.elf
|
|
||||||
arm-none-eabi-objcopy -O binary $< $@
|
|
||||||
|
|
||||||
firmware.elf: cmsis_core cmsis_sam hal.h link.ld Makefile $(SOURCES)
|
|
||||||
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@
|
|
||||||
|
|
||||||
flash: firmware.bin
|
|
||||||
bossac -p /dev/cu.usb* -w -v -b $<
|
|
||||||
|
|
||||||
cmsis_core:
|
|
||||||
git clone --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
|
|
||||||
cmsis_sam:
|
|
||||||
curl -sL https://packs.download.microchip.com/Microchip.SAME54_DFP.3.8.234.pack -o $@.zip
|
|
||||||
mkdir $@ && cd $@ && unzip ../$@.zip
|
|
||||||
|
|
||||||
# Automated test via https://vcon.io/automated-firmware-tests/. Set VCON_API_KEY and update DEVICE_URL
|
|
||||||
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/9
|
|
||||||
update: firmware.bin
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @$<
|
|
||||||
|
|
||||||
test update: CFLAGS += -DUART_DEBUG=USART1
|
|
||||||
test: update
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
|
|
||||||
grep 'READY, IP:' /tmp/output.txt # Check for network init
|
|
||||||
grep 'RECEIVED hello' /tmp/output.txt # Check for MQTT success
|
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) firmware.* cmsis_core cmsis_sam *.zip
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
// Copyright (c) 2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
|
|
||||||
#include "hal.h"
|
|
||||||
#include "mongoose.h"
|
|
||||||
|
|
||||||
static const char *s_url = "mqtt://broker.hivemq.com:1883";
|
|
||||||
static const char *s_sub_topic = "mg/+/test"; // Publish topic
|
|
||||||
static const char *s_pub_topic = "mg/clnt/test"; // Subscribe topic
|
|
||||||
static const uint8_t s_qos = 1; // MQTT QoS
|
|
||||||
static struct mg_connection *s_conn; // Client connection
|
|
||||||
|
|
||||||
void SystemInit(void) { // Called automatically by startup code
|
|
||||||
clock_init();
|
|
||||||
rng_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
static volatile uint64_t s_ticks; // Milliseconds since boot
|
|
||||||
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
|
|
||||||
s_ticks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t mg_millis(void) { // Let Mongoose use our uptime function
|
|
||||||
return s_ticks; // Return number of milliseconds since boot
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_random(void *buf, size_t len) { // Use on-board RNG
|
|
||||||
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
|
|
||||||
uint32_t r = rng_read();
|
|
||||||
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fn(struct mg_connection *c, int ev, void *ev_data) {
|
|
||||||
if (ev == MG_EV_OPEN) {
|
|
||||||
MG_INFO(("%lu CREATED", c->id));
|
|
||||||
// c->is_hexdumping = 1;
|
|
||||||
} else if (ev == MG_EV_ERROR) {
|
|
||||||
// On error, log error message
|
|
||||||
MG_ERROR(("%lu ERROR %s", c->id, (char *) ev_data));
|
|
||||||
} else if (ev == MG_EV_MQTT_OPEN) {
|
|
||||||
// MQTT connect is successful
|
|
||||||
struct mg_str subt = mg_str(s_sub_topic);
|
|
||||||
struct mg_str pubt = mg_str(s_pub_topic), data = mg_str("hello");
|
|
||||||
MG_INFO(("%lu CONNECTED to %s", c->id, s_url));
|
|
||||||
struct mg_mqtt_opts sub_opts;
|
|
||||||
memset(&sub_opts, 0, sizeof(sub_opts));
|
|
||||||
sub_opts.topic = subt;
|
|
||||||
sub_opts.qos = s_qos;
|
|
||||||
mg_mqtt_sub(c, &sub_opts);
|
|
||||||
MG_INFO(("%lu SUBSCRIBED to %.*s", c->id, (int) subt.len, subt.buf));
|
|
||||||
struct mg_mqtt_opts pub_opts;
|
|
||||||
memset(&pub_opts, 0, sizeof(pub_opts));
|
|
||||||
pub_opts.topic = pubt;
|
|
||||||
pub_opts.message = data;
|
|
||||||
pub_opts.qos = s_qos, pub_opts.retain = false;
|
|
||||||
mg_mqtt_pub(c, &pub_opts);
|
|
||||||
MG_INFO(("%lu PUBLISHED %.*s -> %.*s", c->id, (int) data.len, data.buf,
|
|
||||||
(int) pubt.len, pubt.buf));
|
|
||||||
} else if (ev == MG_EV_MQTT_MSG) {
|
|
||||||
// When we get echo response, print it
|
|
||||||
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
|
||||||
MG_INFO(("%lu RECEIVED %.*s <- %.*s", c->id, (int) mm->data.len,
|
|
||||||
mm->data.buf, (int) mm->topic.len, mm->topic.buf));
|
|
||||||
} else if (ev == MG_EV_CLOSE) {
|
|
||||||
MG_INFO(("%lu CLOSED", c->id));
|
|
||||||
s_conn = NULL; // Mark that we're closed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timer function - recreate client connection if it is closed
|
|
||||||
static void timer_fn(void *arg) {
|
|
||||||
struct mg_mgr *mgr = (struct mg_mgr *) arg;
|
|
||||||
struct mg_mqtt_opts opts = {.clean = true,
|
|
||||||
.qos = s_qos,
|
|
||||||
.topic = mg_str(s_pub_topic),
|
|
||||||
.version = 4,
|
|
||||||
.message = mg_str("bye")};
|
|
||||||
if (s_conn == NULL) s_conn = mg_mqtt_connect(mgr, s_url, &opts, fn, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
gpio_input(BUTTON_PIN);
|
|
||||||
gpio_output(LED_PIN);
|
|
||||||
uart_init(UART_DEBUG, 115200);
|
|
||||||
ethernet_init();
|
|
||||||
MG_INFO(("Starting, CPU freq %g MHz", (double) clock_sys_freq() / 1000000));
|
|
||||||
|
|
||||||
struct mg_mgr mgr; // Initialise
|
|
||||||
mg_mgr_init(&mgr); // Mongoose event manager
|
|
||||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
|
||||||
|
|
||||||
// Initialise Mongoose network stack
|
|
||||||
struct mg_tcpip_driver_same54_data driver_data = {.mdc_cr = 5};
|
|
||||||
struct mg_tcpip_if mif = {
|
|
||||||
.mac = GENERATE_LOCALLY_ADMINISTERED_MAC() /*{2, 3, 4, 5, 6, 7}*/,
|
|
||||||
// Uncomment below for static configuration:
|
|
||||||
// .ip = mg_htonl(MG_U32(192, 168, 0, 223)),
|
|
||||||
// .mask = mg_htonl(MG_U32(255, 255, 255, 0)),
|
|
||||||
// .gw = mg_htonl(MG_U32(192, 168, 0, 1)),
|
|
||||||
.driver = &mg_tcpip_driver_same54,
|
|
||||||
.driver_data = &driver_data};
|
|
||||||
mg_tcpip_init(&mgr, &mif);
|
|
||||||
|
|
||||||
MG_INFO(("MAC: %M. Waiting for IP...", mg_print_mac, mif.mac));
|
|
||||||
while (mif.state != MG_TCPIP_STATE_READY) {
|
|
||||||
mg_mgr_poll(&mgr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
MG_INFO(("Initialising application..."));
|
|
||||||
mg_timer_add(&mgr, 3000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr);
|
|
||||||
|
|
||||||
MG_INFO(("Starting event loop"));
|
|
||||||
for (;;) {
|
|
||||||
mg_mgr_poll(&mgr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
# Mongoose as a MicroPython user module
|
|
||||||
|
|
||||||
The most basic usage is in `main.py`.
|
|
||||||
|
|
||||||
You'll have to configure Mongoose for your desired platform, this example runs on the `unix` port and Mongoose detects it as a known architecture and hence configures itself to use sockets and time base. For other platforms, you'll have to do your homework (there's plenty of Mongoose examples for several platforms); also check respective MicroPython build instructions.
|
|
||||||
|
|
||||||
Check [_thread](https://docs.micropython.org/en/latest/library/_thread.html) support for more advanced usage
|
|
||||||
|
|
||||||
https://docs.micropython.org/en/latest/develop/cmodules.html
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
PROG ?= ./example # Program we are building
|
|
||||||
PACK ?= ./pack # Packing executable
|
|
||||||
DELETE = rm -rf # Command to remove files
|
|
||||||
GZIP ?= gzip # For compressing files in web_root/
|
|
||||||
OUT ?= -o $(PROG) # Compiler argument for output file
|
|
||||||
SOURCES = main.c mongoose.c net.c packed_fs.c # Source code files
|
|
||||||
CFLAGS = -W -Wall -Wextra -g -I. # Build options
|
|
||||||
|
|
||||||
# Mongoose build options. See https://mongoose.ws/documentation/#build-options
|
|
||||||
CFLAGS_MONGOOSE += -DMG_ENABLE_PACKED_FS=1
|
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT) # Windows settings. Assume MinGW compiler. To use VC: make CC=cl CFLAGS=/MD OUT=/Feprog.exe
|
|
||||||
PROG = example.exe # Use .exe suffix for the binary
|
|
||||||
PACK = pack.exe # Packing executable
|
|
||||||
CC = gcc # Use MinGW gcc compiler
|
|
||||||
CFLAGS += -lws2_32 # Link against Winsock library
|
|
||||||
DELETE = cmd /C del /Q /F /S # Command prompt command to delete files
|
|
||||||
GZIP = echo # No gzip on Windows
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Default target. Build and run program
|
|
||||||
all: $(PROG)
|
|
||||||
$(RUN) $(PROG) $(ARGS)
|
|
||||||
|
|
||||||
# Build program from sources
|
|
||||||
$(PROG): $(SOURCES)
|
|
||||||
$(CC) $(SOURCES) $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) $(OUT)
|
|
||||||
|
|
||||||
# Bundle JS libraries (preact, preact-router, ...) into a single file
|
|
||||||
web_root/bundle.js:
|
|
||||||
curl -s https://npm.reversehttp.com/preact,preact/hooks,htm/preact,preact-router -o $@
|
|
||||||
|
|
||||||
# Create optimised CSS. Prerequisite: npm -g i tailwindcss tailwindcss-font-inter
|
|
||||||
web_root/main.css: web_root/index.html $(wildcard web_root/*.js)
|
|
||||||
npx tailwindcss -o $@ --minify
|
|
||||||
|
|
||||||
# Generate packed filesystem for serving Web UI
|
|
||||||
packed_fs.c: $(wildcard web_root/*) $(wildcard certs/*) Makefile web_root/main.css web_root/bundle.js
|
|
||||||
$(GZIP) web_root/*
|
|
||||||
$(CC) ../../test/pack.c -o $(PACK)
|
|
||||||
$(PACK) web_root/* certs/* > $@
|
|
||||||
$(GZIP) -d web_root/*
|
|
||||||
|
|
||||||
mbedtls:
|
|
||||||
git clone --depth 1 -b v2.28.2 https://github.com/mbed-tls/mbedtls $@
|
|
||||||
|
|
||||||
ifeq ($(TLS), mbedtls)
|
|
||||||
CFLAGS += -DMG_TLS=MG_TLS_MBED -Wno-conversion -Imbedtls/include
|
|
||||||
CFLAGS += -DMBEDTLS_CONFIG_FILE=\"mbedtls_config.h\" mbedtls/library/*.c
|
|
||||||
$(PROG): mbedtls
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Cleanup. Delete built program and all build artifacts
|
|
||||||
clean:
|
|
||||||
$(DELETE) $(PROG) $(PACK) *.o *.obj *.exe *.bin *.dSYM mbedtls
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../device-dashboard/certs
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
// Copyright (c) 2020-2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
|
|
||||||
#include "mongoose.h"
|
|
||||||
#include "net.h"
|
|
||||||
|
|
||||||
#define CONFIG_FILE "settings.bin"
|
|
||||||
|
|
||||||
static int s_sig_num;
|
|
||||||
static void signal_handler(int sig_num) {
|
|
||||||
signal(sig_num, signal_handler);
|
|
||||||
s_sig_num = sig_num;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool web_load_settings(void *buf, size_t len) {
|
|
||||||
bool ok = false;
|
|
||||||
struct mg_str data = mg_file_read(&mg_fs_posix, CONFIG_FILE);
|
|
||||||
if (data.buf == NULL) {
|
|
||||||
MG_ERROR(("Error reading %s", CONFIG_FILE));
|
|
||||||
} else if (data.len != len) {
|
|
||||||
MG_ERROR(("%s size != %lu", CONFIG_FILE, len));
|
|
||||||
} else {
|
|
||||||
memcpy(buf, data.buf, len);
|
|
||||||
}
|
|
||||||
free((void *) data.buf);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool web_save_settings(void *buf, size_t len) {
|
|
||||||
MG_INFO(("Saving to %s", CONFIG_FILE));
|
|
||||||
return mg_file_write(&mg_fs_posix, CONFIG_FILE, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
struct mg_mgr mgr;
|
|
||||||
|
|
||||||
signal(SIGPIPE, SIG_IGN);
|
|
||||||
signal(SIGINT, signal_handler);
|
|
||||||
signal(SIGTERM, signal_handler);
|
|
||||||
|
|
||||||
mg_log_set(MG_LL_DEBUG); // Set debug log level
|
|
||||||
mg_mgr_init(&mgr);
|
|
||||||
|
|
||||||
web_init(&mgr);
|
|
||||||
while (s_sig_num == 0) {
|
|
||||||
mg_mgr_poll(&mgr, 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
mg_mgr_free(&mgr);
|
|
||||||
MG_INFO(("Exiting on signal %d", s_sig_num));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../mongoose.c
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../mongoose.h
|
|
||||||
@@ -1,304 +0,0 @@
|
|||||||
// Copyright (c) 2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
|
|
||||||
#include "net.h"
|
|
||||||
|
|
||||||
// Device settings
|
|
||||||
struct device_settings {
|
|
||||||
uint32_t magic;
|
|
||||||
int log_level;
|
|
||||||
bool mqtt_enabled;
|
|
||||||
char mqtt_server_url[64];
|
|
||||||
char mqtt_topic_tx[16];
|
|
||||||
char mqtt_topic_rx[16];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct conndata {
|
|
||||||
uint64_t expiration_time; // Modbus request timeout
|
|
||||||
unsigned long id; // Connection ID waiting for the Modbus response
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct device_settings s_settings;
|
|
||||||
static const char *s_json_header =
|
|
||||||
"Content-Type: application/json\r\n"
|
|
||||||
"Cache-Control: no-cache\r\n";
|
|
||||||
static uint64_t s_boot_timestamp = 0; // Updated by SNTP
|
|
||||||
|
|
||||||
static void set_default_settings(struct device_settings *s) {
|
|
||||||
s->magic = SETTINGS_MAGIC;
|
|
||||||
s->log_level = MG_LL_DEBUG;
|
|
||||||
mg_snprintf(s->mqtt_server_url, sizeof(s->mqtt_server_url), "%s",
|
|
||||||
"mqtt://broker.hivemq.com:1883");
|
|
||||||
mg_snprintf(s->mqtt_topic_tx, sizeof(s->mqtt_topic_tx), "%s", "modbus1/tx");
|
|
||||||
mg_snprintf(s->mqtt_topic_rx, sizeof(s->mqtt_topic_rx), "%s", "modbus1/rx");
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is for newlib and TLS (mbedTLS)
|
|
||||||
uint64_t mg_now(void) {
|
|
||||||
return mg_millis() + s_boot_timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SNTP connection event handler. When we get a response from an SNTP server,
|
|
||||||
// adjust s_boot_timestamp. We'll get a valid time from that point on
|
|
||||||
static void sfn(struct mg_connection *c, int ev, void *ev_data) {
|
|
||||||
uint64_t *expiration_time = (uint64_t *) c->data;
|
|
||||||
if (ev == MG_EV_OPEN) {
|
|
||||||
*expiration_time = mg_millis() + 3000; // Store expiration time in 3s
|
|
||||||
} else if (ev == MG_EV_SNTP_TIME) {
|
|
||||||
uint64_t t = *(uint64_t *) ev_data;
|
|
||||||
s_boot_timestamp = t - mg_millis();
|
|
||||||
c->is_closing = 1;
|
|
||||||
} else if (ev == MG_EV_POLL) {
|
|
||||||
if (mg_millis() > *expiration_time) c->is_closing = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SNTP timer function. Sync up time
|
|
||||||
static void timer_sntp_fn(void *param) {
|
|
||||||
mg_sntp_connect(param, "udp://time.google.com:123", sfn, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setfromjson(struct mg_str json, const char *jsonpath, char *buf,
|
|
||||||
size_t len) {
|
|
||||||
char *val = mg_json_get_str(json, jsonpath);
|
|
||||||
if (val != NULL) mg_snprintf(buf, len, "%s", val);
|
|
||||||
free(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_settings_set(struct mg_connection *c, struct mg_str body) {
|
|
||||||
struct device_settings settings;
|
|
||||||
memset(&settings, 0, sizeof(settings));
|
|
||||||
set_default_settings(&settings);
|
|
||||||
mg_json_get_bool(body, "$.mqtt_enabled", &settings.mqtt_enabled);
|
|
||||||
settings.log_level = mg_json_get_long(body, "$.log_level", MG_LL_INFO);
|
|
||||||
setfromjson(body, "$.mqtt_server_url", settings.mqtt_server_url,
|
|
||||||
sizeof(settings.mqtt_server_url));
|
|
||||||
setfromjson(body, "$.mqtt_topic_rx", settings.mqtt_topic_rx,
|
|
||||||
sizeof(settings.mqtt_topic_rx));
|
|
||||||
setfromjson(body, "$.mqtt_topic_tx", settings.mqtt_topic_tx,
|
|
||||||
sizeof(settings.mqtt_topic_tx));
|
|
||||||
|
|
||||||
s_settings = settings;
|
|
||||||
bool ok = web_save_settings(&s_settings, sizeof(s_settings));
|
|
||||||
mg_http_reply(c, 200, s_json_header,
|
|
||||||
"{%m:%s,%m:%m}", //
|
|
||||||
MG_ESC("status"), ok ? "true" : "false", //
|
|
||||||
MG_ESC("message"), MG_ESC(ok ? "Success" : "Failed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_settings_get(struct mg_connection *c) {
|
|
||||||
mg_http_reply(c, 200, s_json_header,
|
|
||||||
"{%m:%s,%m:%d,%m:%m,%m:%m,%m:%m}\n", //
|
|
||||||
MG_ESC("mqtt_enabled"),
|
|
||||||
s_settings.mqtt_enabled ? "true" : "false", //
|
|
||||||
MG_ESC("log_level"), s_settings.log_level, //
|
|
||||||
MG_ESC("mqtt_server_url"), MG_ESC(s_settings.mqtt_server_url),
|
|
||||||
MG_ESC("mqtt_topic_rx"), MG_ESC(s_settings.mqtt_topic_rx),
|
|
||||||
MG_ESC("mqtt_topic_tx"), MG_ESC(s_settings.mqtt_topic_tx));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modbus handler function
|
|
||||||
static void mfn(struct mg_connection *c, int ev, void *ev_data) {
|
|
||||||
struct conndata *cd = (struct conndata *) c->data;
|
|
||||||
if (ev == MG_EV_READ) {
|
|
||||||
MG_INFO(("%lu RECEIVED %lu", c->id, c->recv.len));
|
|
||||||
if (c->recv.len < 8) return; // Less than minimum length, buffer more
|
|
||||||
uint16_t len = mg_ntohs(*(uint16_t *) &c->recv.buf[4]); // PDU length
|
|
||||||
if (c->recv.len < len + 4U) return; // Partial frame, buffer more
|
|
||||||
// Notify parent connection
|
|
||||||
for (struct mg_connection *t = c->mgr->conns; t != NULL; t = t->next) {
|
|
||||||
if (t->id == cd->id) mg_call(t, MG_EV_USER, &c->recv);
|
|
||||||
}
|
|
||||||
c->is_closing = 1;
|
|
||||||
} else if (MG_EV_POLL) {
|
|
||||||
// MG_INFO(("%lu closing tmout %llu", c->id, cd->expiration_time));
|
|
||||||
if (cd->expiration_time > 0 && cd->expiration_time < mg_millis()) {
|
|
||||||
c->is_closing = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(void) ev_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void send8(struct mg_connection *c, uint8_t val) {
|
|
||||||
mg_send(c, &val, sizeof(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void send16(struct mg_connection *c, uint16_t val) {
|
|
||||||
send8(c, (uint8_t) (val >> 8) & 255);
|
|
||||||
send8(c, (uint8_t) (val & 255));
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct mg_connection *start_modbus_request(struct mg_mgr *mgr,
|
|
||||||
struct mg_str json,
|
|
||||||
unsigned long cid) {
|
|
||||||
struct mg_connection *c = NULL;
|
|
||||||
char *url = mg_json_get_str(json, "$.url");
|
|
||||||
long timeout = mg_json_get_long(json, "$.timeout", 750);
|
|
||||||
uint8_t id = (uint8_t) mg_json_get_long(json, "$.id", 1);
|
|
||||||
uint16_t reg = (uint16_t) mg_json_get_long(json, "$.reg", 1);
|
|
||||||
uint8_t func = (uint8_t) mg_json_get_long(json, "$.func", 0);
|
|
||||||
uint16_t nregs = (uint16_t) mg_json_get_long(json, "$.nregs", 1);
|
|
||||||
MG_INFO(("%lu REQUEST: %.*s", cid, json.len, json.buf));
|
|
||||||
if (func == 0) {
|
|
||||||
MG_ERROR(("Set func to a valid modbus function code"));
|
|
||||||
} else if ((c = mg_connect(mgr, url, mfn, NULL)) == NULL) {
|
|
||||||
MG_ERROR(("Failed to start modbus connection at %M", MG_ESC(url)));
|
|
||||||
} else {
|
|
||||||
send16(c, 1); // TID. Use random?
|
|
||||||
send16(c, 0); // Protocol identifier: 0 (modbus)
|
|
||||||
uint16_t *lp = (uint16_t *) &c->send.buf[c->send.len];
|
|
||||||
send16(c, 0); // Length: to be set later
|
|
||||||
size_t len = c->send.len;
|
|
||||||
|
|
||||||
send8(c, id); // Client ID
|
|
||||||
send8(c, func); // Function
|
|
||||||
|
|
||||||
if (func == 3 || func == 4 || func == 6 || func == 16) {
|
|
||||||
send16(c, reg); // Start register
|
|
||||||
send16(c, nregs); // Number of registers
|
|
||||||
|
|
||||||
if (func == 16) { // Fill in register values to write
|
|
||||||
send8(c, (uint8_t) (nregs * 2)); // Send number of bytes
|
|
||||||
for (uint16_t i = 0; i < nregs; i++) {
|
|
||||||
char path[20];
|
|
||||||
mg_snprintf(path, sizeof(path), "$.values[%hu]", i);
|
|
||||||
uint16_t r = (uint16_t) mg_json_get_long(json, path, 0);
|
|
||||||
send16(c, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (func == 43) {
|
|
||||||
send8(c, 14); // MEI
|
|
||||||
send8(c, 1); // Basic device ID: 1
|
|
||||||
send8(c, 0); // Object ID: 0 (vendor name)
|
|
||||||
}
|
|
||||||
|
|
||||||
*lp = mg_htons((uint16_t) (c->send.len - len)); // Set length field
|
|
||||||
mg_hexdump(c->send.buf, c->send.len);
|
|
||||||
MG_INFO(("%lu SENDING %lu", c->id, c->send.len));
|
|
||||||
|
|
||||||
struct conndata *cd = (struct conndata *) c->data;
|
|
||||||
cd->id = cid; // Store parent connection ID
|
|
||||||
cd->expiration_time = mg_millis() + timeout;
|
|
||||||
}
|
|
||||||
free(url);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_modbus_exec(struct mg_connection *c, struct mg_str body) {
|
|
||||||
struct mg_connection *mc = start_modbus_request(c->mgr, body, c->id);
|
|
||||||
if (mc == NULL) {
|
|
||||||
mg_http_reply(c, 200, s_json_header, "false\n");
|
|
||||||
} else {
|
|
||||||
struct conndata *cd = (struct conndata *) c->data;
|
|
||||||
cd->expiration_time = mg_millis() + 1500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print modbus response
|
|
||||||
static size_t print_mb_resp(void (*out)(char, void *), void *ptr, va_list *ap) {
|
|
||||||
int func = va_arg(*ap, int);
|
|
||||||
size_t len = va_arg(*ap, size_t);
|
|
||||||
uint8_t *buf = va_arg(*ap, uint8_t *);
|
|
||||||
size_t n = 0;
|
|
||||||
if (func == 3 || func == 4) {
|
|
||||||
// For "multiple" read responses, print registers
|
|
||||||
n += mg_xprintf(out, ptr, "[");
|
|
||||||
for (size_t ofs = 1; ofs < len; ofs += 2) {
|
|
||||||
uint16_t reg = mg_ntohs(*(uint8_t *) &buf[ofs]);
|
|
||||||
n += mg_xprintf(out, ptr, "%s%hu", ofs == 1 ? "" : ",", reg);
|
|
||||||
}
|
|
||||||
n += mg_xprintf(out, ptr, "]");
|
|
||||||
} else if (func == 43) {
|
|
||||||
n += mg_xprintf(out, ptr, "{");
|
|
||||||
if (len >= 6) {
|
|
||||||
n += mg_xprintf(out, ptr, "%m:%d", MG_ESC("mei"), buf[0]);
|
|
||||||
n += mg_xprintf(out, ptr, ",%m:%d", MG_ESC("devid"), buf[1]);
|
|
||||||
n += mg_xprintf(out, ptr, ",%m:%d", MG_ESC("conformity"), buf[2]);
|
|
||||||
n += mg_xprintf(out, ptr, ",%m:%d", MG_ESC("more"), buf[3]);
|
|
||||||
n += mg_xprintf(out, ptr, ",%m:%d", MG_ESC("next"), buf[4]);
|
|
||||||
n += mg_xprintf(out, ptr, ",%m:[", MG_ESC("objects"));
|
|
||||||
size_t ofs = 6;
|
|
||||||
while (ofs < len) {
|
|
||||||
if (ofs > 6) n += mg_xprintf(out, ptr, ",");
|
|
||||||
n += mg_xprintf(out, ptr, "{");
|
|
||||||
n += mg_xprintf(out, ptr, "%m:%d", MG_ESC("id"), buf[ofs++]);
|
|
||||||
if (ofs < len) {
|
|
||||||
uint8_t olen = buf[ofs++];
|
|
||||||
if (olen > (uint8_t) (len - ofs)) olen = (uint8_t) (len - ofs);
|
|
||||||
n += mg_xprintf(out, ptr, ",%m:%m", MG_ESC("value"), mg_print_esc,
|
|
||||||
olen, &buf[ofs]);
|
|
||||||
ofs += olen;
|
|
||||||
}
|
|
||||||
n += mg_xprintf(out, ptr, "}");
|
|
||||||
}
|
|
||||||
n += mg_xprintf(out, ptr, "]");
|
|
||||||
}
|
|
||||||
n += mg_xprintf(out, ptr, "}");
|
|
||||||
} else {
|
|
||||||
n += mg_xprintf(out, ptr, "null");
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTP request handler function
|
|
||||||
static void fn(struct mg_connection *c, int ev, void *ev_data) {
|
|
||||||
struct conndata *cd = (struct conndata *) c->data;
|
|
||||||
if (ev == MG_EV_ACCEPT) {
|
|
||||||
if (c->fn_data != NULL) { // TLS listener!
|
|
||||||
struct mg_tls_opts opts = {0};
|
|
||||||
opts.cert = mg_unpacked("/certs/server_cert.pem");
|
|
||||||
opts.key = mg_unpacked("/certs/server_key.pem");
|
|
||||||
mg_tls_init(c, &opts);
|
|
||||||
}
|
|
||||||
} else if (ev == MG_EV_HTTP_MSG) {
|
|
||||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
|
||||||
|
|
||||||
if (mg_match(hm->uri, mg_str("/api/settings/get"), NULL)) {
|
|
||||||
handle_settings_get(c);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/settings/set"), NULL)) {
|
|
||||||
handle_settings_set(c, hm->body);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/settings/set"), NULL)) {
|
|
||||||
handle_settings_set(c, hm->body);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/modbus/exec"), NULL)) {
|
|
||||||
handle_modbus_exec(c, hm->body);
|
|
||||||
} else if (mg_match(hm->uri, mg_str("/api/device/reset"), NULL)) {
|
|
||||||
mg_timer_add(c->mgr, 500, 0, (void (*)(void *)) mg_device_reset, NULL);
|
|
||||||
mg_http_reply(c, 200, s_json_header, "true\n");
|
|
||||||
} else {
|
|
||||||
struct mg_http_serve_opts opts;
|
|
||||||
memset(&opts, 0, sizeof(opts));
|
|
||||||
#if MG_ARCH == MG_ARCH_UNIX || MG_ARCH == MG_ARCH_WIN32
|
|
||||||
opts.root_dir = "web_root"; // On workstations, use filesystem
|
|
||||||
#else
|
|
||||||
opts.root_dir = "/web_root"; // On embedded, use packed files
|
|
||||||
opts.fs = &mg_fs_packed;
|
|
||||||
#endif
|
|
||||||
mg_http_serve_dir(c, ev_data, &opts);
|
|
||||||
}
|
|
||||||
MG_DEBUG(("%lu %.*s %.*s", c->id, (int) hm->method.len, hm->method.buf,
|
|
||||||
(int) hm->uri.len, hm->uri.buf));
|
|
||||||
} else if (ev == MG_EV_POLL) {
|
|
||||||
if (cd->expiration_time > 0 && cd->expiration_time < mg_millis()) {
|
|
||||||
cd->expiration_time = 0;
|
|
||||||
mg_http_reply(c, 200, s_json_header, "false\n");
|
|
||||||
}
|
|
||||||
} else if (ev == MG_EV_USER) {
|
|
||||||
cd->expiration_time = 0; // Cleanup timeout setting
|
|
||||||
struct mg_iobuf *io = ev_data;
|
|
||||||
uint8_t f = io->buf[7];
|
|
||||||
mg_http_reply(c, 200, s_json_header, "{%m:%s,%m:%m,%m:%M}\n", //
|
|
||||||
MG_ESC("success"), "true", //
|
|
||||||
MG_ESC("raw"), mg_print_hex, io->len - 7, io->buf + 7, //
|
|
||||||
MG_ESC("data"), print_mb_resp, f, io->len - 8, io->buf + 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void web_init(struct mg_mgr *mgr) {
|
|
||||||
set_default_settings(&s_settings);
|
|
||||||
web_load_settings(&s_settings, sizeof(s_settings));
|
|
||||||
|
|
||||||
mg_http_listen(mgr, HTTP_URL, fn, NULL);
|
|
||||||
mg_http_listen(mgr, HTTPS_URL, fn, (void *) 1);
|
|
||||||
mg_timer_add(mgr, 10 * 60 * 1000, MG_TIMER_RUN_NOW | MG_TIMER_REPEAT,
|
|
||||||
timer_sntp_fn, mgr);
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -1,15 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en" class="h-full bg-white">
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='1.5' stroke='currentColor'> <path stroke-linecap='round' stroke-linejoin='round' d='M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0' /> </svg>" />
|
|
||||||
<link href="main.css" rel="stylesheet" />
|
|
||||||
<link href="https://rsms.me/inter/inter.css" rel="stylesheet" />
|
|
||||||
</head>
|
|
||||||
<body class="h-full"></body>
|
|
||||||
<script src="history.min.js"></script>
|
|
||||||
<script type="module" src="main.js"></script>
|
|
||||||
</html>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
/*! tailwindcss v3.3.5 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter var,Helvetica,sans-serif;font-feature-settings:"cv11","ss01";font-variation-settings:"opsz" 32}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.left-0{left:0}.right-auto{right:auto}.top-0{top:0}.z-10{z-index:10}.z-\[48\]{z-index:48}.z-\[60\]{z-index:60}.m-4{margin:1rem}.my-0{margin-top:0;margin-bottom:0}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.mb-1{margin-bottom:.25rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-2{margin-right:.5rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-12{height:3rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.max-h-64{max-height:16rem}.min-h-screen{min-height:100vh}.w-0{width:0}.w-11{width:2.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-72{width:18rem}.w-full{width:100%}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.grow-0{flex-grow:0}.basis-\[30px\]{flex-basis:30px}.-translate-x-full{--tw-translate-x:-100%}.-translate-x-full,.translate-x-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x:0px}.translate-x-5{--tw-translate-x:1.25rem}.translate-x-5,.translate-y-0{transform:tranLine truncated
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
PWD := $(shell pwd)
|
|
||||||
NPX ?= npx
|
|
||||||
|
|
||||||
all: bundle.js main.css
|
|
||||||
make -C ../../../tutorials/http/http-server ARGS="-d $(PWD)"
|
|
||||||
|
|
||||||
# Bundle JS libraries (preact, preact-router, ...) into a single file
|
|
||||||
bundle.js:
|
|
||||||
curl -s https://npm.reversehttp.com/preact,preact/hooks,htm/preact,preact-router -o $@
|
|
||||||
|
|
||||||
# Create optimised CSS. Prerequisite: npm -g i tailwindcss tailwindcss-font-inter
|
|
||||||
main.css: index.html $(wildcard *.js)
|
|
||||||
$(NPX) tailwindcss -o $@ --minify
|
|
||||||
|
|
||||||
clean:
|
|
||||||
true
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en" class="h-full bg-white">
|
|
||||||
<head>
|
|
||||||
<title></title>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='1.5' stroke='currentColor'> <path stroke-linecap='round' stroke-linejoin='round' d='M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0' /> </svg>" />
|
|
||||||
<link href="main.css" rel="stylesheet" />
|
|
||||||
<link href="https://rsms.me/inter/inter.css" rel="stylesheet" />
|
|
||||||
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
|
|
||||||
</head>
|
|
||||||
<body class="h-full"></body>
|
|
||||||
<script type="module" src="main.js"></script>
|
|
||||||
</html>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter var,Helvetica,sans-serif;font-feature-settings:"cv11","ss01";font-variation-settings:"opsz" 32}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.pointer-events-none{pointer-events:none}.absolute{position:absolute}.relative{position:relative}.right-4{right:1rem}.top-0{top:0}.top-4{top:1rem}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-auto{margin-top:auto;margin-bottom:auto}.mb-4{margin-bottom:1rem}.mt-3{margin-top:.75rem}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-11{width:2.75rem}.w-24{width:6rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-60{width:15rem}.w-64{width:16rem}.w-96{width:24rem}.w-full{width:100%}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.flex-grow,.grow{flex-grow:1}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-5{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-5{--tw-translate-x:1.25rem}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-widtLine truncated
|
|
||||||
@@ -1,618 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
import {h, html, render, useEffect, useRef, useState} from './bundle.js';
|
|
||||||
|
|
||||||
const Logo = props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12.87 12.85"><defs><style>.ll-cls-1{fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:0.5px;}</style></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="ll-cls-1" d="M12.62,1.82V8.91A1.58,1.58,0,0,1,11,10.48H4a1.44,1.44,0,0,1-1-.37A.69.69,0,0,1,2.84,10l-.1-.12a.81.81,0,0,1-.15-.48V5.57a.87.87,0,0,1,.86-.86H4.73V7.28a.86.86,0,0,0,.86.85H9.42a.85.85,0,0,0,.85-.85V3.45A.86.86,0,0,0,10.13,3,.76.76,0,0,0,10,2.84a.29.29,0,0,0-.12-.1,1.49,1.49,0,0,0-1-.37H2.39V1.82A1.57,1.57,0,0,1,4,.25H11A1.57,1.57,0,0,1,12.62,1.82Z"/><path class="ll-cls-1" d="M10.48,10.48V11A1.58,1.58,0,0,1,8.9,12.6H1.82A1.57,1.57,0,0,1,.25,11V3.94A1.57,1.57,0,0,1,1.82,2.37H8.9a1.49,1.49,0,0,1,1,.37l.12.1a.76.76,0,0,1,.11.14.86.86,0,0,1,.14.47V7.28a.85.85,0,0,1-.85.85H8.13V5.57a.86.86,0,0,0-.85-.86H3.45a.87.87,0,0,0-.86.86V9.4a.81.81,0,0,0,.15.48l.1.12a.69.69,0,0,0,.13.11,1.44,1.44,0,0,0,1,.37Z"/></g></g></svg>`;
|
|
||||||
const DefaultTopic = 'mg_mqtt_dashboard';
|
|
||||||
const DefaultUrl = location.protocol == 'https:'
|
|
||||||
? 'wss://broker.hivemq.com:8884/mqtt'
|
|
||||||
: 'ws://broker.hivemq.com:8000/mqtt';
|
|
||||||
const DefaultDeviceConfig = {pin_map: [], pin_state: [], log_level: 0, pin_count: 0};
|
|
||||||
const Delay = (ms, val) => new Promise(resolve => setTimeout(resolve, ms, val));
|
|
||||||
const handleFetchError = r => r.ok || alert(`Error: ${r.statusText}`);
|
|
||||||
const LabelClass = 'text-sm truncate text-gray-500 font-medium my-auto whitespace-nowrap';
|
|
||||||
const BadgeClass = 'flex-inline text-sm rounded-md rounded px-2 py-0.5 ring-1 ring-inset';
|
|
||||||
const InputClass = 'font-normal text-sm rounded w-full flex-1 py-0.5 px-2 text-gray-700 placeholder:text-gray-400 focus:outline-none disabled:cursor-not-allowed disabled:bg-gray-100 disabled:text-gray-500 rounded border';
|
|
||||||
const TitleClass = 'font-semibold xuppercase xtext-gray-600';
|
|
||||||
const Colors = {
|
|
||||||
green: 'bg-green-100 text-green-900 ring-green-300',
|
|
||||||
yellow: 'bg-yellow-100 text-yellow-900 ring-yellow-300',
|
|
||||||
info: 'bg-zinc-100 text-zinc-900 ring-zinc-300',
|
|
||||||
red: 'bg-red-100 text-red-900 ring-red-300',
|
|
||||||
};
|
|
||||||
|
|
||||||
let MqttClient;
|
|
||||||
|
|
||||||
const Icons = {
|
|
||||||
logo: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="59.1" height="75.7" viewBox="0 0 1514 1182"> <path style="fill: #2f409a;" d="m52.8 572h345.1v346.5h-345.1zm-10.9-434.2c-12.6 6.4-32.2 20.9-35.5 37.9 0 0-6.1 35.9-6.1 36.8-2.1 13.1 10.5 10 15.8 6.7 53.9-31.8 113.9-60.7 168.7-77.5 258.2-78.2 585.9-80.2 643.1 88.8 40.3 117.1-123.6 214.8-216.1 258.4-35.7 16.8-47.6 32.8-50 49.8-2 15.3 3.2 37.8 23.8 68.3 129.7 194.8 515 474 893.1 571.7 15.7 4.2 23.5 2.8 29.9-1.1 3.5-2 7.9-4.8 1.1-8.2-251.1-132.2-490.9-353.9-610.9-525.1-27.4-39.5-34.5-65.9-32.7-87.2 1.7-18.4 18.7-34.5 54.8-51.4 134.1-62.3 270.9-157.1 230-314.9-59.5-226.9-700.5-260.1-1109-53z"/></svg>`,
|
|
||||||
activity: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline></svg>`,
|
|
||||||
refresh: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"></polyline><polyline points="1 20 1 14 7 14"></polyline><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path></svg>`,
|
|
||||||
info: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>`,
|
|
||||||
login: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path><polyline points="10 17 15 12 10 7"></polyline><line x1="15" y1="12" x2="3" y2="12"></line></svg>`,
|
|
||||||
logout: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="16 17 21 12 16 7"></polyline><line x1="21" y1="12" x2="9" y2="12"></line></svg>`,
|
|
||||||
menu: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>`,
|
|
||||||
upload: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg>`,
|
|
||||||
monitor: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect><line x1="8" y1="21" x2="16" y2="21"></line><line x1="12" y1="17" x2="12" y2="21"></line></svg>`,
|
|
||||||
settings: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>`,
|
|
||||||
download: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>`,
|
|
||||||
file: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline></svg>`,
|
|
||||||
check: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`,
|
|
||||||
rollback: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="11 17 6 12 11 7"></polyline><polyline points="18 17 13 12 18 7"></polyline></svg>`,
|
|
||||||
save: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path><polyline points="17 21 17 13 7 13 7 21"></polyline><polyline points="7 3 7 8 15 8"></polyline></svg>`,
|
|
||||||
bolt: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>`,
|
|
||||||
delete: props => html`<svg class=${props.class} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>`,
|
|
||||||
};
|
|
||||||
|
|
||||||
export function Button({title, onclick, disabled, extraClass, icon, ref, colors, hovercolor, disabledcolor}) {
|
|
||||||
const [spin, setSpin] = useState(false);
|
|
||||||
const cb = function(ev) {
|
|
||||||
const res = onclick ? onclick() : null;
|
|
||||||
if (res && typeof (res.catch) === 'function') {
|
|
||||||
setSpin(true);
|
|
||||||
res.catch(() => false).then(() => setSpin(false));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (!colors) colors = 'bg-blue-600 hover:bg-blue-500 disabled:bg-blue-400';
|
|
||||||
return html`
|
|
||||||
<button type="button" class="inline-flex justify-center items-center gap-2 rounded px-2.5 py-0.5 text-sm font-semibold text-white shadow-sm ${colors} ${extraClass}"
|
|
||||||
ref=${ref} onclick=${cb} disabled=${disabled || spin} >
|
|
||||||
${title}
|
|
||||||
<${spin ? Icons.refresh : icon} class="w-4 ${spin ? 'animate-spin' : ''}" />
|
|
||||||
<//>`
|
|
||||||
};
|
|
||||||
|
|
||||||
function UploadFileButton({oncomplete, onprogress, onfileselect, url, title, colors, accept, extraClass}) {
|
|
||||||
const btn = useRef(null);
|
|
||||||
const input = useRef(null);
|
|
||||||
|
|
||||||
// Send a large file chunk by chunk
|
|
||||||
const sendFileData = function(url, fileName, fileData, chunkSize) {
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
const finish = ok => {
|
|
||||||
input.fn = null;
|
|
||||||
const res = oncomplete ? oncomplete(ok, fileName, fileData.length) : null;
|
|
||||||
if (res && typeof (res.catch) === 'function') {
|
|
||||||
res.catch(() => false).then(() => ok ? resolve() : reject());
|
|
||||||
} else {
|
|
||||||
ok ? resolve() : reject();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const sendChunk = function(offset) {
|
|
||||||
var chunk = fileData.subarray(offset, offset + chunkSize) || '';
|
|
||||||
var opts = {method: 'POST', body: chunk};
|
|
||||||
var fullUrl = url + '?offset=' + offset +
|
|
||||||
'&total=' + fileData.length +
|
|
||||||
'&file=' + encodeURIComponent(fileName);
|
|
||||||
onprogress && onprogress(offset, fileData.length, fileName);
|
|
||||||
fetch(fullUrl, opts)
|
|
||||||
.then(function(res) {
|
|
||||||
if (!res.ok) {
|
|
||||||
finish(false);
|
|
||||||
} else if (offset >= fileData.length) {
|
|
||||||
finish(true);
|
|
||||||
} else {
|
|
||||||
sendChunk(offset + chunk.length);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
sendChunk(0);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onchange = function(ev) {
|
|
||||||
if (!ev.target.files[0]) return;
|
|
||||||
let r = new FileReader(), f = ev.target.files[0];
|
|
||||||
if (onfileselect && !onfileselect(f.name)) {
|
|
||||||
ev.target.value = '';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
r.readAsArrayBuffer(f);
|
|
||||||
r.onload = function() {
|
|
||||||
input.fn = sendFileData(url, f.name, new Uint8Array(r.result), 2048);
|
|
||||||
ev.target.value = '';
|
|
||||||
ev.preventDefault();
|
|
||||||
btn.current && btn.current.base.click();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const onclick = function(ev) {
|
|
||||||
//if (!input.fn) input.current.click(); // No upload in progress, show file dialog
|
|
||||||
};
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<div class="inline-flex flex-col ${extraClass}">
|
|
||||||
<input class="hidden" type="file" ref=${input} onchange=${onchange} accept=${accept} />
|
|
||||||
<${Button} title=${title} icon=${Icons.download} onclick=${onclick} ref=${btn} colors=${colors} />
|
|
||||||
<//>`;
|
|
||||||
};
|
|
||||||
|
|
||||||
function Toggle({value, onclick, disabled}) {
|
|
||||||
const bg = !!value ? 'bg-blue-600' : 'bg-gray-200';
|
|
||||||
const tr = !!value ? 'translate-x-5' : 'translate-x-0';
|
|
||||||
return html`
|
|
||||||
<button type="button" onclick=${onclick} disabled=${disabled}
|
|
||||||
class="${bg} inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-0 ring-0"
|
|
||||||
role="switch" aria-checked=${!!value}>
|
|
||||||
<span aria-hidden="true" class="${tr} pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 focus:ring-0 transition duration-200 ease-in-out"></span>
|
|
||||||
</button>`;
|
|
||||||
};
|
|
||||||
|
|
||||||
function Header({topic, setTopic, url, setUrl, connected}) {
|
|
||||||
const forbiddenChars = ['$', '*', '+', '#', '/'];
|
|
||||||
const onClick = () => {
|
|
||||||
const isValidTopic = val => !forbiddenChars.some(char => val.includes(char));
|
|
||||||
if (isValidTopic(topic)) {
|
|
||||||
localStorage.setItem('topic', topic)
|
|
||||||
setTopic(topic);
|
|
||||||
window.location.reload();
|
|
||||||
} else {
|
|
||||||
setSaveResult('Error: The topic cannot contain these characters: ' + forbiddenChars);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<div class="top-0 py-2 border-b-2 bg-stone-100">
|
|
||||||
<div class="flex px-4">
|
|
||||||
<div class="flex grow gap-4">
|
|
||||||
<h1 class="text-2xl font-semibold">IoT Fleet Management Dashboard</h1>
|
|
||||||
<//>
|
|
||||||
<div class="flex gap-2 items-center">
|
|
||||||
<div class="flex w-96 align-center justify-between gap-2">
|
|
||||||
<span class=${LabelClass}>MQTT Server<//>
|
|
||||||
<input disabled=${!connected} value=${url}
|
|
||||||
onchange=${ev => setUrl(ev.target.value)} class=${InputClass} />
|
|
||||||
<//>
|
|
||||||
<div class="flex w-64 align-center justify-between gap-2">
|
|
||||||
<span class=${LabelClass}>Root Topic<//>
|
|
||||||
<input disabled=${!connected} value=${topic}
|
|
||||||
onchange=${ev => setTopic(ev.target.value)} class=${InputClass} />
|
|
||||||
<//>
|
|
||||||
<${Button} icon=${Icons.bolt} onclick=${onClick} title=${connected ? 'Disconnect' : 'Connect'} />
|
|
||||||
<//>
|
|
||||||
<//>
|
|
||||||
<//>`;
|
|
||||||
};
|
|
||||||
|
|
||||||
function Sidebar({devices, onclick}) {
|
|
||||||
const Td = props => html`
|
|
||||||
<td class="whitespace-nowrap border-b border-slate-200 py-2 px-4 pr-3 text-sm text-slate-900">${
|
|
||||||
props.text}</td>`;
|
|
||||||
|
|
||||||
const Device = ({d}) => html`
|
|
||||||
<div class="hover:bg-stone-100 cursor-pointer flex gap-3 px-4 py-2 justify-between"
|
|
||||||
onclick=${ev => onclick(d.id)}>
|
|
||||||
<span>${d.id}</span>
|
|
||||||
<span class="${BadgeClass} ${d.online ? Colors.green : Colors.red}"> ${d.online ? 'online' : 'offline'} <//>
|
|
||||||
<//>`;
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<div class="overflow-auto divide-y">
|
|
||||||
<div class="${TitleClass} flex items-center px-4 py-2 bg-stone-100">
|
|
||||||
Device List
|
|
||||||
<//>
|
|
||||||
${(devices ? devices : []).map(d => h(Device, {d}))}
|
|
||||||
<//>`;
|
|
||||||
};
|
|
||||||
|
|
||||||
function FirmwareStatus({title, info, children}) {
|
|
||||||
const state =
|
|
||||||
['UNAVAILABLE', 'FIRST_BOOT', 'NOT_COMMITTED',
|
|
||||||
'COMMITTED'][(info.status || 0) % 4];
|
|
||||||
const valid = info.status > 0;
|
|
||||||
return html`
|
|
||||||
<div class="bg-white divide-y border rounded">
|
|
||||||
<div class="${TitleClass} bg-white flex items-center px-4 py-2">
|
|
||||||
${title}
|
|
||||||
<//>
|
|
||||||
<div class="px-4 py-2 relative">
|
|
||||||
<div class="my-1">Status: ${state}<//>
|
|
||||||
<div class="my-1">CRC32: ${valid ? info.crc32.toString(16) : 'n/a'}<//>
|
|
||||||
<div class="my-1">Size: ${valid ? info.size : 'n/a'}<//>
|
|
||||||
<div class="my-1">Flashed at: ${
|
|
||||||
valid ? new Date(info.timestamp * 1000).toLocaleString() : 'n/a'}<//>
|
|
||||||
${children}
|
|
||||||
<//>
|
|
||||||
<//>`;
|
|
||||||
};
|
|
||||||
|
|
||||||
function FirmwareUpdatePanel({no, name, current, previous, updated_at, refresh}) {
|
|
||||||
const [color, setColor] = useState(Colors.green);
|
|
||||||
const [otaStatus, setOtaStatus] = useState('up-to-date');
|
|
||||||
const Descr = ({label, value}) => html`
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class=${LabelClass}>${label}<//>
|
|
||||||
<span class="text-sm">${value}<//>
|
|
||||||
<//>`;
|
|
||||||
const onprogress = (len, total) => {
|
|
||||||
setColor(Colors.info);
|
|
||||||
setOtaStatus(`uploading, ${parseInt(len * 100 /total)}% done...`);
|
|
||||||
}
|
|
||||||
const setparam = (key, val) => fetch('api/settings/set', {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({key, val}),
|
|
||||||
}).then(handleFetchError);
|
|
||||||
const onupload = function(ok, fileName, fileLength) {
|
|
||||||
if (ok) {
|
|
||||||
return setparam(`ecu.${no}.new`, fileName).then(refresh);
|
|
||||||
} else {
|
|
||||||
setColor(Colors.red), setOtaStatus('upload failed');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const onfileselect = function(fileName, fileLength) {
|
|
||||||
const ok = fileName.startsWith(name);
|
|
||||||
if (!ok) alert(`Firmware file name must be ${name}.VERSION.BIN_OR_HEX`);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
const update = rollback => new Promise(function(resolve, reject) {
|
|
||||||
const opts = {method: 'POST', body: JSON.stringify({no, rollback})};
|
|
||||||
const fail = () => (reject(), setOtaStatus('update error'), setColor(Colors.red));
|
|
||||||
const finish = () => fetch('api/ecu/update/end', opts)
|
|
||||||
.then(r => r.ok ? resolve() : reject())
|
|
||||||
.then(refresh);
|
|
||||||
const write = () => fetch('api/ecu/update/write', opts).then(r => {
|
|
||||||
if (!r.ok) fail();
|
|
||||||
//if (r.ok) r.json().then(r => console.log('Goo', r));
|
|
||||||
if (r.ok) r.json().then(r => r == 1 ? write() : finish());
|
|
||||||
});
|
|
||||||
fetch('api/ecu/update/begin', opts).then(r => r.ok ? write() : fail());
|
|
||||||
});
|
|
||||||
const onflash = ev => update(false);
|
|
||||||
const onrollback = ev => update(true);
|
|
||||||
|
|
||||||
useEffect(function() {
|
|
||||||
//setOtaStatus(anew ? 'update pending' : 'up-to-date');
|
|
||||||
//setColor(anew ? Colors.yellow : Colors.green);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<div class="divide-y border rounded bg-white">
|
|
||||||
<div class="px-4 py-2 flex justify-between items-center rounded">
|
|
||||||
<span class="${TitleClass}">Firmware Update<//>
|
|
||||||
<div class="flex gap-2"><span class=${LabelClass}>Status:</span><span class="${BadgeClass} ${color}">${otaStatus}<//><//>
|
|
||||||
<//>
|
|
||||||
<div class="p-4 flex flex-col gap-1">
|
|
||||||
<${Descr} label="Current firmware:" value=${current || 'n/a'} />
|
|
||||||
<${Descr} label="Updated at:" value=${updated_at || 'n/a'} />
|
|
||||||
<div class="flex items-center justify-between whitespace-nowrap">
|
|
||||||
<span class=${LabelClass}>Previous firmware:<//>
|
|
||||||
<span class="flex gap-1 items-center">
|
|
||||||
<span class="text-sm">${previous}<//>
|
|
||||||
<${Button} title="rollback" icon=${Icons.bolt} onclick=${onrollback}
|
|
||||||
extraClass="w-24" disabled=${!previous} />
|
|
||||||
<//>
|
|
||||||
<//>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class=${LabelClass}>New firmware:<//>
|
|
||||||
<span class="flex gap-1 align-center justify-between">
|
|
||||||
<${UploadFileButton} title="upload" url="api/fw/upload"
|
|
||||||
onfileselect=${onfileselect}
|
|
||||||
onprogress=${onprogress} oncomplete=${onupload} />
|
|
||||||
<${Button} title="flash" icon=${Icons.bolt} onclick=${onflash}
|
|
||||||
extraClass="w-24" disabled=${!previous} />
|
|
||||||
<//>
|
|
||||||
<//>
|
|
||||||
<//>
|
|
||||||
<//>`;
|
|
||||||
};
|
|
||||||
|
|
||||||
function DeviceSettingsPanel({device, publishFn, connected}) {
|
|
||||||
const [config, setConfig] = useState({});
|
|
||||||
const logOptions = [[0, 'Disable'], [1, 'Error'], [2, 'Info'], [3, 'Debug']];
|
|
||||||
|
|
||||||
const onSave = ev => publishFn('config.set', config).then(r => {
|
|
||||||
//setDeviceConfig(device.id, config);
|
|
||||||
}).catch(e => alert('Failure!'));
|
|
||||||
|
|
||||||
// To delete device, set an empty retained message
|
|
||||||
const onforget = function(ev) {
|
|
||||||
MqttClient.publish(device.topic, '', {retain: true});
|
|
||||||
location.reload();
|
|
||||||
};
|
|
||||||
const onloglevelchange = ev => setConfig(x => Object.assign({}, x, {log_level: parseInt(ev.target.value)}));
|
|
||||||
const onpinschange = ev => {
|
|
||||||
const pin_map = ev.target.value.split(/\s*,\s*/).map(x => parseInt(x));
|
|
||||||
setConfig(x => Object.assign({}, x, {
|
|
||||||
pin_map, // Send an updated pin map
|
|
||||||
pin_count: pin_map.length, // And pin count
|
|
||||||
pin_state:[] // Remove pin_state from the request, as pin_map change can invalidate it
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
//console.log('sp', device, config);
|
|
||||||
|
|
||||||
useEffect(() => setConfig(device.config) , [device]);
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<div class="divide-y border rounded bg-white">
|
|
||||||
<div class="px-4 py-2 flex justify-between items-center rounded ${TitleClass}">
|
|
||||||
<div class="flex gap-2 items-center"> Settings <//>
|
|
||||||
<//>
|
|
||||||
<div class="p-4 gap-3">
|
|
||||||
<div class="flex justify-between my-1">
|
|
||||||
<span class=${LabelClass}>Status<//>
|
|
||||||
<span class="${BadgeClass} ${device.online ? Colors.green : Colors.red}"> ${connected ? 'online' : 'offline'} <//>
|
|
||||||
<//>
|
|
||||||
<div class="flex justify-between my-1">
|
|
||||||
<span class=${LabelClass}>Device ID<//>
|
|
||||||
<span class="${LabelClass}">${device.id}<//>
|
|
||||||
<//>
|
|
||||||
<div class="grid grid-cols-2 my-1">
|
|
||||||
<span class="${LabelClass}">Log Level<//>
|
|
||||||
<select onchange=${onloglevelchange} class="w-full rounded font-normal border py-0.5 px-1 text-gray-600 focus:outline-none text-sm disabled:cursor-not-allowed" disabled=${!connected}>
|
|
||||||
${logOptions.map(v => html`<option value=${v[0]} selected=${v[0] == config.log_level}>${v[1]}<//>`) }
|
|
||||||
<//>
|
|
||||||
<//>
|
|
||||||
<div class="grid grid-cols-2 my-1">
|
|
||||||
<span class="${LabelClass}">Show Pins<//>
|
|
||||||
<div class="flex w-full items-center">
|
|
||||||
<input disabled=${!connected} value=${config.pin_map}
|
|
||||||
onchange=${onpinschange} class=${InputClass}
|
|
||||||
placeholder="comma-separated pin numbers" />
|
|
||||||
<//>
|
|
||||||
<//>
|
|
||||||
|
|
||||||
<div class="mt-3 flex justify-between gap-2">
|
|
||||||
<${Button} title="Forget this device"
|
|
||||||
disabled=${device.online || !connected} icon=${Icons.delete}
|
|
||||||
onclick=${onforget}/>
|
|
||||||
<${Button} icon=${Icons.save} onclick=${onSave} title="Save Settings" disabled=${!device.online} />
|
|
||||||
<//>
|
|
||||||
<//>
|
|
||||||
<//> `;
|
|
||||||
};
|
|
||||||
|
|
||||||
function DeviceControlPanel({device, config, setConfig, publishFn, connected}) {
|
|
||||||
const onclick = function(i) { // Send request to toggle pin i
|
|
||||||
let configCopy = Object.assign({}, config);
|
|
||||||
configCopy.pin_state[i] = !!configCopy.pin_state[i] ? 0 : 1;
|
|
||||||
return publishFn('config.set', configCopy).catch(e => alert('Failure!'));
|
|
||||||
};
|
|
||||||
|
|
||||||
const Pin = i => html`
|
|
||||||
<div class="inline-block my-1 bg-gray-100 rounded px-1 py-1">
|
|
||||||
<div class="flex align-center justify-between">
|
|
||||||
<span class="${LabelClass}">Pin ${config.pin_map[i]}<//>
|
|
||||||
<${Toggle} onclick=${ev => onclick(i)}
|
|
||||||
disabled=${!device.online || !connected}
|
|
||||||
value=${config.pin_state[i]} />
|
|
||||||
<//>
|
|
||||||
<//>`;
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<div class="divide-y border rounded bg-white xbg-slate-100 my-y">
|
|
||||||
<div class="px-4 py-2 flex justify-between items-center rounded ${TitleClass}">
|
|
||||||
<div class="flex gap-2 items-center">Pin Control Panel<//>
|
|
||||||
<//>
|
|
||||||
<div class="p-4 grid grid-cols-2 lg:grid-cols-3 gap-2">
|
|
||||||
${(config.pin_map || []).map((_, i) => Pin(i))}
|
|
||||||
<div><//>
|
|
||||||
<//>
|
|
||||||
<//> `;
|
|
||||||
};
|
|
||||||
|
|
||||||
function DeviceDashboard({device, setDeviceConfig, publishFn, connected}) {
|
|
||||||
const cfg = device && device.config ? device.config : DefaultDeviceConfig;
|
|
||||||
const [localConfig, setLocalConfig] = useState(cfg);
|
|
||||||
useEffect(() => setLocalConfig(cfg), [device]);
|
|
||||||
|
|
||||||
if (!device || !localConfig) {
|
|
||||||
return html`
|
|
||||||
<div class="flex grow text-gray-400 justify-center items-center text-xl">
|
|
||||||
No device selected. Click on a device on a sidebar
|
|
||||||
<//>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<div class="p-3 grid grid-cols-3 gap-2">
|
|
||||||
<${DeviceSettingsPanel} device=${device} config=${localConfig} setConfig=${setLocalConfig} publishFn=${publishFn} connected=${connected} />
|
|
||||||
<${DeviceControlPanel} device=${device} config=${localConfig} setConfig=${setLocalConfig} publishFn=${publishFn} connected=${connected} />
|
|
||||||
<${FirmwareUpdatePanel} deviceID=${device.id} publishFn=${publishFn}
|
|
||||||
disabled=${!device.online}
|
|
||||||
info=${[localConfig.crnt_fw, localConfig.prev_fw]} />
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const App = function() {
|
|
||||||
const [devices, setDevices] = useState([]);
|
|
||||||
const [currentDevID, setCurrentDevID] = useState(localStorage.getItem('currentDevID') || '');
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
const [url, setUrl] = useState(localStorage.getItem('url') || DefaultUrl);
|
|
||||||
const [topic, setTopic] = useState(localStorage.getItem('topic') || DefaultTopic);
|
|
||||||
const [error, setError] = useState(null);
|
|
||||||
const [connected, setConnected] = useState(false);
|
|
||||||
const responseHandlers = useRef({});
|
|
||||||
|
|
||||||
function addResponseHandler(correlationId, handler) {
|
|
||||||
responseHandlers[correlationId] = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeResponseHandler(correlationId) {
|
|
||||||
delete responseHandlers[correlationId];
|
|
||||||
}
|
|
||||||
|
|
||||||
const onRefresh = ev => window.location.reload();
|
|
||||||
|
|
||||||
const initConn = () => {
|
|
||||||
MqttClient = mqtt.connect(url, {connectTimeout: 5000, reconnectPeriod: 0});
|
|
||||||
|
|
||||||
MqttClient.on('connect', () => {
|
|
||||||
//console.log('Connected to the broker');
|
|
||||||
setLoading(false);
|
|
||||||
setError(null); // Reset error state upon successful connection
|
|
||||||
setConnected(true);
|
|
||||||
|
|
||||||
const statusTopic = topic + '/+/status'
|
|
||||||
const txTopic = topic + '/+/tx'
|
|
||||||
|
|
||||||
const subscribe = (topic) => {
|
|
||||||
MqttClient.subscribe(topic, (err) => {
|
|
||||||
if (err) {
|
|
||||||
console.error('Error subscribing to topic:', err);
|
|
||||||
setError('Error subscribing to topic');
|
|
||||||
} else {
|
|
||||||
//console.log('Successfully subscribed to ', topic);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
subscribe(statusTopic);
|
|
||||||
subscribe(txTopic);
|
|
||||||
});
|
|
||||||
|
|
||||||
MqttClient.on('message', (topic, message) => {
|
|
||||||
// console.log(`Received message from ${topic}: ${message.toString()}`);
|
|
||||||
if (message.length == 0) return;
|
|
||||||
let response;
|
|
||||||
try {
|
|
||||||
response = JSON.parse(message.toString());
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (topic.endsWith('/status')) {
|
|
||||||
let device = {topic: topic, id: topic.split('/')[1], config: DefaultDeviceConfig};
|
|
||||||
const params = response.params;
|
|
||||||
if (!params) {
|
|
||||||
console.error('Invalid response');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
device.online = params.status === 'online';
|
|
||||||
//setConnected(device.online);
|
|
||||||
if (device.online) {
|
|
||||||
device.config = params;
|
|
||||||
if (!device.config.pins) device.config.pins = [];
|
|
||||||
}
|
|
||||||
setDevice(device)
|
|
||||||
} else if (topic.endsWith('/tx')) {
|
|
||||||
if (!response.id) {
|
|
||||||
console.error('Invalid response');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const handler = responseHandlers[response.id];
|
|
||||||
if (handler) {
|
|
||||||
handler(response);
|
|
||||||
removeResponseHandler(response.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
MqttClient.on('error', (err) => {
|
|
||||||
console.error('Connection error:', err);
|
|
||||||
setError('Connection cannot be established.');
|
|
||||||
});
|
|
||||||
|
|
||||||
MqttClient.on('close', () => {
|
|
||||||
if (!connected) {
|
|
||||||
console.error('Failed to connect to the broker.');
|
|
||||||
setError('Connection cannot be established.');
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => initConn(), []);
|
|
||||||
|
|
||||||
const handlePublish = (methodName, parameters, timeout = 5000) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const randomIdGenerator = function(length) {
|
|
||||||
return Math.random().toString(36).substring(2, length + 2);
|
|
||||||
};
|
|
||||||
const randomID = randomIdGenerator(40);
|
|
||||||
const timeoutID = setTimeout(() => {
|
|
||||||
removeResponseHandler(randomID);
|
|
||||||
reject(new Error('Request timed out'));
|
|
||||||
}, timeout);
|
|
||||||
|
|
||||||
addResponseHandler(randomID, (messageData) => {
|
|
||||||
clearTimeout(timeoutID);
|
|
||||||
resolve(messageData);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (currentDevID) {
|
|
||||||
const rxTopic = topic + `/${currentDevID}/rx`;
|
|
||||||
const rpcPayload = {method: methodName, id: randomID};
|
|
||||||
if (parameters) {
|
|
||||||
rpcPayload.params = parameters;
|
|
||||||
}
|
|
||||||
MqttClient.publish(rxTopic, JSON.stringify(rpcPayload));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const getDeviceByID = (deviceID) => devices.find(d => d.id === deviceID);
|
|
||||||
|
|
||||||
const setDevice = (devData) => {
|
|
||||||
setDevices(prevDevices => {
|
|
||||||
const devIndex =
|
|
||||||
prevDevices.findIndex(device => device.id === devData.id);
|
|
||||||
if (devIndex !== -1) {
|
|
||||||
if (!devData.online && !devData.config) {
|
|
||||||
const updatedDevices = [...prevDevices];
|
|
||||||
updatedDevices[devIndex].online = false;
|
|
||||||
return updatedDevices;
|
|
||||||
} else {
|
|
||||||
return prevDevices.map(device => device.id === devData.id ? devData : device);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return [...prevDevices, devData];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const setDeviceConfig = (deviceID, config) => {
|
|
||||||
setDevices(prevDevices => {
|
|
||||||
return prevDevices.map(device => {
|
|
||||||
if (device.id === deviceID) {
|
|
||||||
return {...device, config: config};
|
|
||||||
}
|
|
||||||
return device;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDeviceClick = (deviceID) => {
|
|
||||||
const device = getDeviceByID(deviceID);
|
|
||||||
if (device) {
|
|
||||||
setCurrentDevID(device.id);
|
|
||||||
localStorage.setItem('currentDevID', device.id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return html`
|
|
||||||
<div class="min-h-screen bg-slate-100 flex flex-col">
|
|
||||||
<${Header}/>
|
|
||||||
<div class="flex-grow flex items-center justify-center">
|
|
||||||
<div class="bg-slate-300 p-8 rounded-lg shadow-md w-full max-w-md">
|
|
||||||
<h1 class="text-2xl font-bold text-gray-700 mb-4 text-center">Connection Error</h1>
|
|
||||||
<p class="text-gray-600 text-center mb-4">
|
|
||||||
Unable to connect to the MQTT broker.
|
|
||||||
</p>
|
|
||||||
<div class="text-center relative">
|
|
||||||
<${Button} title="Retry" onclick=${onRefresh}
|
|
||||||
icon=${Icons.refresh} class="absolute top-4 right-4" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<div class="h-full flex flex-col">
|
|
||||||
<${Header}
|
|
||||||
topic=${topic} setTopic=${setTopic} url=${url}
|
|
||||||
setUrl=${setUrl} connected=${connected}
|
|
||||||
/>
|
|
||||||
<div class="flex grow overflow-auto">
|
|
||||||
<div class="w-60 overflow-auto">
|
|
||||||
<${Sidebar} devices=${devices} onclick=${onDeviceClick} />
|
|
||||||
<//>
|
|
||||||
<div class="grow bg-gray-200">
|
|
||||||
<${DeviceDashboard}
|
|
||||||
device=${getDeviceByID(currentDevID)} connected=${connected}
|
|
||||||
setDeviceConfig=${setDeviceConfig} publishFn=${handlePublish} />
|
|
||||||
<//>
|
|
||||||
<//>
|
|
||||||
<//>`;
|
|
||||||
};
|
|
||||||
|
|
||||||
window.onload = () => render(h(App), document.body);
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#include "hal.h"
|
|
||||||
|
|
||||||
#define MAX_PIN_NO 144
|
|
||||||
|
|
||||||
// Mocked device pins
|
|
||||||
static bool s_pins[MAX_PIN_NO];
|
|
||||||
|
|
||||||
bool gpio_write(uint16_t pin, bool status) {
|
|
||||||
bool ok = false;
|
|
||||||
if (pin >= 0 && pin < MAX_PIN_NO) {
|
|
||||||
s_pins[pin] = status;
|
|
||||||
ok = true;
|
|
||||||
}
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool gpio_read(uint16_t pin) {
|
|
||||||
return (pin >= 0 && pin < MAX_PIN_NO) ? s_pins[pin] : false;
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
// Copyright (c) 2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
|
|
||||||
#include "net.h"
|
|
||||||
#include "hal.h"
|
|
||||||
|
|
||||||
// Handle interrupts, like Ctrl-C
|
|
||||||
static int s_signo;
|
|
||||||
static void signal_handler(int signo) {
|
|
||||||
s_signo = signo;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
struct mg_mgr mgr;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
// Parse command-line flags
|
|
||||||
for (i = 1; i < argc; i++) {
|
|
||||||
if (strcmp(argv[i], "-u") == 0 && argv[i + 1] != NULL) {
|
|
||||||
g_mqtt_server_url = argv[++i];
|
|
||||||
} else if (strcmp(argv[i], "-i") == 0 && argv[i + 1] != NULL) {
|
|
||||||
g_device_id = strdup(argv[++i]);
|
|
||||||
} else if (strcmp(argv[i], "-t") == 0 && argv[i + 1] != NULL) {
|
|
||||||
g_root_topic = argv[++i];
|
|
||||||
} else if (strcmp(argv[i], "-v") == 0 && argv[i + 1] != NULL) {
|
|
||||||
mg_log_set(atoi(argv[++i]));
|
|
||||||
} else {
|
|
||||||
MG_ERROR(("Unknown option: %s. Usage:", argv[i]));
|
|
||||||
MG_ERROR(
|
|
||||||
("%s [-u mqtt://SERVER:PORT] [-i DEVICE_ID] [-t TOPIC_NAME] [-v "
|
|
||||||
"DEBUG_LEVEL]",
|
|
||||||
argv[0], argv[i]));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
signal(SIGINT, signal_handler); // Setup signal handlers - exist event
|
|
||||||
signal(SIGTERM, signal_handler); // manager loop on SIGINT and SIGTERM
|
|
||||||
|
|
||||||
mg_log_set(MG_LL_DEBUG); // Set debug log level
|
|
||||||
mg_mgr_init(&mgr);
|
|
||||||
|
|
||||||
web_init(&mgr);
|
|
||||||
while (s_signo == 0) {
|
|
||||||
mg_mgr_poll(&mgr, 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
web_free();
|
|
||||||
mg_mgr_free(&mgr);
|
|
||||||
MG_INFO(("Exiting on signal %d", s_signo));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,334 +0,0 @@
|
|||||||
// Copyright (c) 2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
|
|
||||||
#include "net.h"
|
|
||||||
|
|
||||||
char *g_mqtt_server_url = MQTT_SERVER_URL;
|
|
||||||
char *g_root_topic = MQTT_ROOT_TOPIC;
|
|
||||||
char *g_device_id;
|
|
||||||
|
|
||||||
static uint8_t s_qos = 1; // MQTT QoS
|
|
||||||
static struct mg_connection *s_conn; // MQTT Client connection
|
|
||||||
static struct mg_rpc *s_rpc = NULL; // List of registered RPC methods
|
|
||||||
|
|
||||||
#define MAX_PINS 20
|
|
||||||
struct device_config {
|
|
||||||
int log_level; // Device logging level, 0-4
|
|
||||||
int pin_count; // Number of pins to handle
|
|
||||||
uint16_t pin_map[MAX_PINS]; // Pins to handle
|
|
||||||
bool pin_state[MAX_PINS]; // State of the GPIO pins
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct device_config s_device_config;
|
|
||||||
static uint64_t s_boot_timestamp = 0; // Updated by SNTP
|
|
||||||
|
|
||||||
uint64_t mg_now(void) {
|
|
||||||
return mg_millis() + s_boot_timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Device ID generation function. Create an ID that is unique
|
|
||||||
// for a given device, and does not change between device restarts.
|
|
||||||
static void set_device_id(void) {
|
|
||||||
char buf[15] = "";
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
unsigned long serial = 0;
|
|
||||||
if (GetVolumeInformationA("c:\\", NULL, 0, &serial, NULL, NULL, NULL, 0)) {
|
|
||||||
mg_snprintf(buf, sizeof(buf), "%lx", serial);
|
|
||||||
}
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
FILE *fp = popen(
|
|
||||||
"ioreg -l | grep IOPlatformSerialNumber | cut -d'\"' -f4 | tr -d $'\n'",
|
|
||||||
"r");
|
|
||||||
if (fp != NULL) {
|
|
||||||
fread(buf, 1, sizeof(buf), fp);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
#elif defined(__linux__)
|
|
||||||
struct mg_str id = mg_file_read(&mg_fs_posix, "/etc/machine-id");
|
|
||||||
if (id.buf != NULL) {
|
|
||||||
mg_snprintf(buf, sizeof(buf), "%s", id.buf);
|
|
||||||
free((void *) id.buf);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (buf[0] == '\0') mg_snprintf(buf, sizeof(buf), "%s", "MyDeviceID");
|
|
||||||
|
|
||||||
buf[sizeof(buf) - 1] = '\0';
|
|
||||||
g_device_id = strdup(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t print_fw_status(void (*out)(char, void *), void *ptr,
|
|
||||||
va_list *ap) {
|
|
||||||
int fw = va_arg(*ap, int);
|
|
||||||
return mg_xprintf(out, ptr, "{%m:%d,%m:%c%lx%c,%m:%u,%m:%u}",
|
|
||||||
MG_ESC("status"), mg_ota_status(fw), MG_ESC("crc32"), '"',
|
|
||||||
mg_ota_crc32(fw), '"', MG_ESC("size"), mg_ota_size(fw),
|
|
||||||
MG_ESC("timestamp"), mg_ota_timestamp(fw));
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t print_shorts(void (*out)(char, void *), void *ptr, va_list *ap) {
|
|
||||||
uint16_t *array = va_arg(*ap, uint16_t *);
|
|
||||||
int i, len = 0, num_elems = va_arg(*ap, int);
|
|
||||||
for (i = 0; i < num_elems; i++) {
|
|
||||||
len += mg_xprintf(out, ptr, "%s%hu", i ? "," : "", array[i]);
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t print_bools(void (*out)(char, void *), void *ptr, va_list *ap) {
|
|
||||||
bool *array = va_arg(*ap, bool *);
|
|
||||||
int i, len = 0, num_elems = va_arg(*ap, int);
|
|
||||||
for (i = 0; i < num_elems; i++) {
|
|
||||||
len += mg_xprintf(out, ptr, "%s%d", i ? "," : "", array[i]);
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void publish_status(struct mg_connection *c) {
|
|
||||||
char topic[100];
|
|
||||||
struct mg_mqtt_opts pub_opts;
|
|
||||||
struct mg_iobuf io = {0, 0, 0, 512};
|
|
||||||
|
|
||||||
// Print JSON notification into the io buffer
|
|
||||||
mg_xprintf(mg_pfn_iobuf, &io,
|
|
||||||
"{%m:%m,%m:{%m:%m,%m:%d,%m:%d,%m:[%M],%m:[%M],%m:%M,%m:%M}}", //
|
|
||||||
MG_ESC("method"), MG_ESC("status.notify"), MG_ESC("params"), //
|
|
||||||
MG_ESC("status"), MG_ESC("online"), //
|
|
||||||
MG_ESC(("log_level")), s_device_config.log_level, //
|
|
||||||
MG_ESC(("pin_count")), s_device_config.pin_count, //
|
|
||||||
MG_ESC(("pin_map")), print_shorts, s_device_config.pin_map,
|
|
||||||
s_device_config.pin_count, //
|
|
||||||
MG_ESC(("pin_state")), print_bools, s_device_config.pin_state,
|
|
||||||
s_device_config.pin_count, //
|
|
||||||
MG_ESC(("crnt_fw")), print_fw_status, MG_FIRMWARE_CURRENT, //
|
|
||||||
MG_ESC(("prev_fw")), print_fw_status, MG_FIRMWARE_PREVIOUS);
|
|
||||||
|
|
||||||
memset(&pub_opts, 0, sizeof(pub_opts));
|
|
||||||
mg_snprintf(topic, sizeof(topic), "%s/%s/status", g_root_topic, g_device_id);
|
|
||||||
pub_opts.topic = mg_str(topic);
|
|
||||||
pub_opts.message = mg_str_n((char *) io.buf, io.len);
|
|
||||||
pub_opts.qos = s_qos;
|
|
||||||
pub_opts.retain = true;
|
|
||||||
mg_mqtt_pub(c, &pub_opts);
|
|
||||||
mg_iobuf_free(&io);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void publish_response(struct mg_connection *c, char *buf, size_t len) {
|
|
||||||
struct mg_mqtt_opts pub_opts;
|
|
||||||
char topic[100];
|
|
||||||
mg_snprintf(topic, sizeof(topic), "%s/%s/tx", g_root_topic, g_device_id);
|
|
||||||
memset(&pub_opts, 0, sizeof(pub_opts));
|
|
||||||
pub_opts.topic = mg_str(topic);
|
|
||||||
pub_opts.message = mg_str_n(buf, len);
|
|
||||||
pub_opts.qos = s_qos;
|
|
||||||
mg_mqtt_pub(c, &pub_opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void subscribe(struct mg_connection *c) {
|
|
||||||
char *rx_topic = mg_mprintf("%s/%s/rx", g_root_topic, g_device_id);
|
|
||||||
struct mg_str subt = mg_str(rx_topic);
|
|
||||||
struct mg_mqtt_opts sub_opts;
|
|
||||||
memset(&sub_opts, 0, sizeof(sub_opts));
|
|
||||||
sub_opts.topic = subt;
|
|
||||||
sub_opts.qos = s_qos;
|
|
||||||
mg_mqtt_sub(c, &sub_opts);
|
|
||||||
MG_INFO(("%lu SUBSCRIBED to %.*s", c->id, (int) subt.len, subt.buf));
|
|
||||||
free(rx_topic);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rpc_config_set(struct mg_rpc_req *r) {
|
|
||||||
struct device_config dc = s_device_config;
|
|
||||||
dc.pin_count = (int) mg_json_get_long(r->frame, "$.params.pin_count", -1);
|
|
||||||
dc.log_level = (int) mg_json_get_long(r->frame, "$.params.log_level", -1);
|
|
||||||
|
|
||||||
if (dc.log_level < 0 || dc.log_level > MG_LL_VERBOSE) {
|
|
||||||
mg_rpc_err(r, -32602, "Log level must be from 0 to 4");
|
|
||||||
} else if (dc.pin_count <= 0 || dc.pin_count > MAX_PINS) {
|
|
||||||
mg_rpc_err(r, -32602, "Pin count must be from 1 to %d", MAX_PINS);
|
|
||||||
} else {
|
|
||||||
int i, val;
|
|
||||||
for (i = 0; i < dc.pin_count; i++) {
|
|
||||||
char path[50];
|
|
||||||
mg_snprintf(path, sizeof(path), "$.params.pin_map[%d]", i);
|
|
||||||
dc.pin_map[i] = (uint16_t) mg_json_get_long(r->frame, path, 0);
|
|
||||||
mg_snprintf(path, sizeof(path), "$.params.pin_state[%d]", i);
|
|
||||||
if ((val = (int) mg_json_get_long(r->frame, path, -1)) >= 0) {
|
|
||||||
gpio_write(dc.pin_map[i], val);
|
|
||||||
}
|
|
||||||
dc.pin_state[i] = gpio_read(dc.pin_map[i]);
|
|
||||||
// MG_INFO(("%d %d %d", i, dc.pin_map[i], dc.pin_state[i]));
|
|
||||||
}
|
|
||||||
mg_log_set(dc.log_level);
|
|
||||||
s_device_config = dc;
|
|
||||||
mg_rpc_ok(r, "true");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rpc_ota_commit(struct mg_rpc_req *r) {
|
|
||||||
if (mg_ota_commit()) {
|
|
||||||
mg_rpc_ok(r, "%m", MG_ESC("ok"));
|
|
||||||
} else {
|
|
||||||
mg_rpc_err(r, 1, "Failed to commit the firmware");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rpc_device_reset(struct mg_rpc_req *r) {
|
|
||||||
mg_rpc_ok(r, "%m", MG_ESC("ok"));
|
|
||||||
mg_timer_add(s_conn->mgr, 500, 0, (void (*)(void *)) mg_device_reset, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rpc_ota_rollback(struct mg_rpc_req *r) {
|
|
||||||
if (mg_ota_rollback()) {
|
|
||||||
mg_rpc_ok(r, "%m", MG_ESC("ok"));
|
|
||||||
} else {
|
|
||||||
mg_rpc_err(r, 1, "Failed to rollback to the previous firmware");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rpc_ota_upload(struct mg_rpc_req *r) {
|
|
||||||
long ofs = mg_json_get_long(r->frame, "$.params.offset", -1);
|
|
||||||
long tot = mg_json_get_long(r->frame, "$.params.total", -1);
|
|
||||||
int len = 0;
|
|
||||||
char *buf = mg_json_get_b64(r->frame, "$.params.chunk", &len);
|
|
||||||
if (buf == NULL) {
|
|
||||||
mg_rpc_err(r, 1, "Error processing the binary chunk.");
|
|
||||||
} else {
|
|
||||||
if (ofs < 0 || tot < 0) {
|
|
||||||
mg_rpc_err(r, 1, "offset and total not set");
|
|
||||||
} else if (ofs == 0 && mg_ota_begin((size_t) tot) == false) {
|
|
||||||
mg_rpc_err(r, 1, "mg_ota_begin(%ld) failed\n", tot);
|
|
||||||
} else if (len > 0 && mg_ota_write(buf, len) == false) {
|
|
||||||
mg_rpc_err(r, 1, "mg_ota_write(%lu) @%ld failed\n", len, ofs);
|
|
||||||
mg_ota_end();
|
|
||||||
} else if (len == 0 && mg_ota_end() == false) {
|
|
||||||
mg_rpc_err(r, 1, "mg_ota_end() failed\n", tot);
|
|
||||||
} else {
|
|
||||||
mg_rpc_ok(r, "%m", MG_ESC("ok"));
|
|
||||||
if (len == 0) { // Successful mg_ota_end() called, schedule device reboot
|
|
||||||
mg_timer_add(s_conn->mgr, 500, 0, (void (*)(void *)) mg_device_reset,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fn(struct mg_connection *c, int ev, void *ev_data) {
|
|
||||||
if (ev == MG_EV_OPEN) {
|
|
||||||
MG_INFO(("%lu CREATED", c->id));
|
|
||||||
// c->is_hexdumping = 1;
|
|
||||||
} else if (ev == MG_EV_CONNECT) {
|
|
||||||
MG_INFO(("Device %s is connected", g_device_id));
|
|
||||||
} else if (ev == MG_EV_ERROR) {
|
|
||||||
// On error, log error message
|
|
||||||
MG_ERROR(("%lu ERROR %s", c->id, (char *) ev_data));
|
|
||||||
} else if (ev == MG_EV_MQTT_OPEN) {
|
|
||||||
// MQTT connect is successful
|
|
||||||
MG_INFO(("%lu CONNECTED to %s", c->id, g_mqtt_server_url));
|
|
||||||
subscribe(c);
|
|
||||||
publish_status(c);
|
|
||||||
} else if (ev == MG_EV_MQTT_MSG) {
|
|
||||||
// When we get echo response, print it
|
|
||||||
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
|
||||||
struct mg_iobuf io = {0, 0, 0, 512};
|
|
||||||
struct mg_rpc_req r = {&s_rpc, NULL, mg_pfn_iobuf,
|
|
||||||
&io, NULL, {mm->data.buf, mm->data.len}};
|
|
||||||
size_t clipped_len = mm->data.len > 512 ? 512 : mm->data.len;
|
|
||||||
MG_INFO(("%lu RECEIVED %.*s <- %.*s", c->id, clipped_len, mm->data.buf,
|
|
||||||
mm->topic.len, mm->topic.buf));
|
|
||||||
mg_rpc_process(&r);
|
|
||||||
if (io.buf) {
|
|
||||||
publish_response(c, (char *) io.buf, io.len);
|
|
||||||
publish_status(c);
|
|
||||||
}
|
|
||||||
mg_iobuf_free(&io);
|
|
||||||
} else if (ev == MG_EV_CLOSE) {
|
|
||||||
MG_INFO(("%lu CLOSED", c->id));
|
|
||||||
s_conn = NULL; // Mark that we're closed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timer function - recreate client connection if it is closed
|
|
||||||
static void timer_reconnect(void *arg) {
|
|
||||||
struct mg_mgr *mgr = (struct mg_mgr *) arg;
|
|
||||||
if (s_conn == NULL) {
|
|
||||||
struct mg_mqtt_opts opts;
|
|
||||||
char topic[100], message[100];
|
|
||||||
mg_snprintf(topic, sizeof(topic), "%s/%s/status", g_root_topic,
|
|
||||||
g_device_id);
|
|
||||||
mg_snprintf(message, sizeof(message), "{%m:%m,%m:{%m:%m}}",
|
|
||||||
MG_ESC("method"), MG_ESC("status.notify"), MG_ESC("params"),
|
|
||||||
MG_ESC("status"), MG_ESC("offline"));
|
|
||||||
memset(&opts, 0, sizeof(opts));
|
|
||||||
opts.clean = true;
|
|
||||||
opts.qos = s_qos;
|
|
||||||
opts.topic = mg_str(topic);
|
|
||||||
opts.version = 4;
|
|
||||||
opts.keepalive = MQTT_KEEPALIVE_SEC;
|
|
||||||
opts.retain = true;
|
|
||||||
opts.message = mg_str(message);
|
|
||||||
s_conn = mg_mqtt_connect(mgr, g_mqtt_server_url, &opts, fn, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void timer_ping(void *arg) {
|
|
||||||
mg_mqtt_send_header(s_conn, MQTT_CMD_PINGREQ, 0, 0);
|
|
||||||
(void) arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SNTP connection event handler. When we get a response from an SNTP server,
|
|
||||||
// adjust s_boot_timestamp. We'll get a valid time from that point on
|
|
||||||
static void sntp_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
|
||||||
uint64_t *expiration_time = (uint64_t *) c->data;
|
|
||||||
if (ev == MG_EV_OPEN) {
|
|
||||||
*expiration_time = mg_millis() + 3000; // Store expiration time in 3s
|
|
||||||
} else if (ev == MG_EV_SNTP_TIME) {
|
|
||||||
uint64_t t = *(uint64_t *) ev_data;
|
|
||||||
s_boot_timestamp = t - mg_millis();
|
|
||||||
c->is_closing = 1;
|
|
||||||
} else if (ev == MG_EV_POLL) {
|
|
||||||
if (mg_millis() > *expiration_time) c->is_closing = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void timer_sntp(void *param) { // SNTP timer function. Sync up time
|
|
||||||
static uint64_t hourly_timer = 0;
|
|
||||||
if (s_boot_timestamp == 0 ||
|
|
||||||
mg_timer_expired(&hourly_timer, 3600000, mg_millis())) {
|
|
||||||
mg_sntp_connect(param, "udp://time.google.com:123", sntp_ev_handler, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void web_init(struct mg_mgr *mgr) {
|
|
||||||
int i, ping_interval_ms = MQTT_KEEPALIVE_SEC * 1000 - 500;
|
|
||||||
set_device_id();
|
|
||||||
s_device_config.log_level = (int) mg_log_level;
|
|
||||||
s_device_config.pin_count = 5;
|
|
||||||
s_device_config.pin_map[0] = 10;
|
|
||||||
s_device_config.pin_map[1] = 11;
|
|
||||||
s_device_config.pin_map[2] = 12;
|
|
||||||
s_device_config.pin_map[3] = 13;
|
|
||||||
s_device_config.pin_map[4] = 25;
|
|
||||||
for (i = 0; i < s_device_config.pin_count; i++) {
|
|
||||||
s_device_config.pin_state[i] = gpio_read(s_device_config.pin_map[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure JSON-RPC functions we're going to handle
|
|
||||||
mg_rpc_add(&s_rpc, mg_str("config.set"), rpc_config_set, NULL);
|
|
||||||
mg_rpc_add(&s_rpc, mg_str("ota.commit"), rpc_ota_commit, NULL);
|
|
||||||
mg_rpc_add(&s_rpc, mg_str("ota.rollback"), rpc_ota_rollback, NULL);
|
|
||||||
mg_rpc_add(&s_rpc, mg_str("ota.upload"), rpc_ota_upload, NULL);
|
|
||||||
mg_rpc_add(&s_rpc, mg_str("device.reset"), rpc_device_reset, NULL);
|
|
||||||
|
|
||||||
mg_timer_add(mgr, 3000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_reconnect,
|
|
||||||
mgr);
|
|
||||||
mg_timer_add(mgr, ping_interval_ms, MG_TIMER_REPEAT, timer_ping, mgr);
|
|
||||||
mg_timer_add(mgr, 2000, MG_TIMER_REPEAT, timer_sntp, mgr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void web_free(void) {
|
|
||||||
mg_rpc_del(&s_rpc, NULL); // Deallocate RPC handlers
|
|
||||||
free(g_device_id);
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
// Copyright (c) 2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "mongoose.h"
|
|
||||||
#include "hal.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MQTT_DASHBOARD 1
|
|
||||||
#define MQTT_KEEPALIVE_SEC 60
|
|
||||||
#define MQTT_SERVER_URL "mqtt://broker.hivemq.com:1883"
|
|
||||||
#define MQTT_ROOT_TOPIC "mg_mqtt_dashboard"
|
|
||||||
|
|
||||||
extern char *g_mqtt_server_url;
|
|
||||||
extern char *g_device_id;
|
|
||||||
extern char *g_root_topic;
|
|
||||||
|
|
||||||
void web_init(struct mg_mgr *mgr);
|
|
||||||
void web_free(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
NAME ?= $(notdir $(CURDIR))
|
|
||||||
|
|
||||||
build:
|
|
||||||
git clone --depth 1 https://github.com/mongoose-examples/$(NAME)
|
|
||||||
cp ./../../../mongoose.[ch] $(NAME)/source/
|
|
||||||
make -C $(NAME) build
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf $(NAME)
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
CFLAGS = -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion
|
|
||||||
CFLAGS += -Wformat-truncation -fno-common # -Wconversion is not SDK-friendly
|
|
||||||
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
|
|
||||||
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_mcu/devices/MIMXRT1021
|
|
||||||
CFLAGS += -Icmsis_mcu/devices/MIMXRT1021/drivers -DCPU_MIMXRT1021DAG5A
|
|
||||||
CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16 $(CFLAGS_EXTRA)
|
|
||||||
LDSCRIPT = link.ld
|
|
||||||
LDFLAGS ?= -T$(LDSCRIPT) -nostdlib -nostartfiles --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
|
||||||
|
|
||||||
SOURCES = main.c syscalls.c sysinit.c
|
|
||||||
SOURCES += cmsis_mcu/devices/MIMXRT1021/gcc/startup_MIMXRT1021.S # NXP startup file. Compiler-dependent!
|
|
||||||
CFLAGS += -D__ATOLLIC__ -D__STARTUP_CLEAR_BSS # Make startup code work as expected
|
|
||||||
|
|
||||||
# Mongoose options are defined in mongoose_config.h
|
|
||||||
SOURCES += mongoose.c net.c packed_fs.c
|
|
||||||
|
|
||||||
# Example specific build options. See README.md
|
|
||||||
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\" -DHTTPS_URL=\"https://0.0.0.0/\"
|
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
|
||||||
RM = cmd /C del /Q /F /S
|
|
||||||
else
|
|
||||||
RM = rm -rf
|
|
||||||
endif
|
|
||||||
|
|
||||||
all build example update: SOURCES += flash_image.c
|
|
||||||
all build example: firmware.bin
|
|
||||||
|
|
||||||
ram: LDSCRIPT = link_ram.ld
|
|
||||||
ram: firmware.bin
|
|
||||||
|
|
||||||
firmware.bin: firmware.elf
|
|
||||||
arm-none-eabi-objcopy -O binary $< $@
|
|
||||||
|
|
||||||
firmware.elf: cmsis_core cmsis_mcu $(SOURCES) hal.h link_ram.ld link.ld Makefile
|
|
||||||
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@
|
|
||||||
arm-none-eabi-size $@
|
|
||||||
|
|
||||||
flash: firmware.bin
|
|
||||||
# flash
|
|
||||||
|
|
||||||
cmsis_core: # ARM CMSIS core headers
|
|
||||||
git clone -q --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
|
|
||||||
cmsis_mcu:
|
|
||||||
curl -sL https://mcuxpresso.nxp.com/cmsis_pack/repo/NXP.MIMXRT1021_DFP.17.0.0.pack -o $@.zip
|
|
||||||
mkdir $@ && cd $@ && unzip -q ../$@.zip
|
|
||||||
mbedtls: # mbedTLS library
|
|
||||||
git clone --depth 1 -b v2.28.2 https://github.com/mbed-tls/mbedtls $@
|
|
||||||
|
|
||||||
ifeq ($(TLS), mbedtls)
|
|
||||||
CFLAGS += -DMG_TLS=MG_TLS_MBED -Wno-conversion -Imbedtls/include
|
|
||||||
CFLAGS += -DMBEDTLS_CONFIG_FILE=\"mbedtls_config.h\" mbedtls/library/*.c
|
|
||||||
firmware.elf: mbedtls
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Automated remote test. Requires env variable VCON_API_KEY set. See https://vcon.io/automated-firmware-tests/
|
|
||||||
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/4
|
|
||||||
update: firmware.bin
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @$<
|
|
||||||
|
|
||||||
update updateram: CFLAGS += -DUART_DEBUG=LPUART2
|
|
||||||
|
|
||||||
test: update
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
|
|
||||||
grep 'READY, IP:' /tmp/output.txt # Check for network init
|
|
||||||
|
|
||||||
|
|
||||||
updateram: ram
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @firmware.bin
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"init"}'
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"wm,e000edf0,a05f0003 wm,e000edfc,1 wm,e000ed0c,5fa0004"}'
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"init"}'
|
|
||||||
PC=`curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"rm,4"}' | jq -r .resp[5:]` && \
|
|
||||||
SP=`curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"rm,0"}' | jq -r .resp[5:]` && \
|
|
||||||
REQ="wm,e000ed08,0 wr,d,$$SP wr,f,$$PC" && \
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"'"$$REQ"'"}'
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"wm,e000edf0,a05f0001"}'
|
|
||||||
|
|
||||||
testram: updateram
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
|
|
||||||
grep 'READY, IP:' /tmp/output.txt # Check for network init
|
|
||||||
|
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) firmware.* *.su cmsis_core cmsis_mcu mbedtls *.zip
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020-2021 NXP
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define __DCD_DATA \
|
|
||||||
0xD2, 0x03, 0xE0, 0x41, 0xCC, 0x03, 0x5C, 0x04, 0x40, 0x0F, 0xC0, 0x68, \
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x6C, 0xFF, 0xFF, 0xFF, 0xFF, \
|
|
||||||
0x40, 0x0F, 0xC0, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x74, \
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x78, 0xFF, 0xFF, 0xFF, 0xFF, \
|
|
||||||
0x40, 0x0F, 0xC0, 0x7C, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x80, \
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0D, 0x80, 0x30, 0x00, 0x00, 0x20, 0x01, \
|
|
||||||
0x40, 0x0D, 0x81, 0x00, 0x10, 0x18, 0x10, 0x1B, 0x40, 0x0F, 0xC0, 0x14, \
|
|
||||||
0x00, 0x0A, 0x83, 0x40, 0x40, 0x1F, 0x80, 0x14, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x18, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x1C, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x24, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x28, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x2C, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x34, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x38, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x40, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x44, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x48, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x4C, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x50, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x58, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x5C, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x64, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x68, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x70, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x74, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x78, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x7C, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x84, 0x00, 0x00, 0x00, 0x10, 0x40, 0x1F, 0x80, 0x88, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x8C, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x90, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x94, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x98, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0xA0, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0xA4, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0xAC, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0xB0, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x81, 0x88, 0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0x8C, \
|
|
||||||
0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0x90, 0x00, 0x00, 0x00, 0xE1, \
|
|
||||||
0x40, 0x1F, 0x81, 0x94, 0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0x98, \
|
|
||||||
0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0x9C, 0x00, 0x00, 0x00, 0xE1, \
|
|
||||||
0x40, 0x1F, 0x81, 0xA0, 0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xA4, \
|
|
||||||
0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xA8, 0x00, 0x00, 0x00, 0xE1, \
|
|
||||||
0x40, 0x1F, 0x81, 0xAC, 0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xB0, \
|
|
||||||
0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xB4, 0x00, 0x00, 0x00, 0xE1, \
|
|
||||||
0x40, 0x1F, 0x81, 0xB8, 0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xBC, \
|
|
||||||
0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xC0, 0x00, 0x00, 0x00, 0xE1, \
|
|
||||||
0x40, 0x1F, 0x81, 0xC4, 0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xC8, \
|
|
||||||
0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xCC, 0x00, 0x00, 0x00, 0xE1, \
|
|
||||||
0x40, 0x1F, 0x81, 0xD0, 0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xD4, \
|
|
||||||
0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xD8, 0x00, 0x00, 0x00, 0xE1, \
|
|
||||||
0x40, 0x1F, 0x81, 0xDC, 0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xE0, \
|
|
||||||
0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xE4, 0x00, 0x00, 0x00, 0xE1, \
|
|
||||||
0x40, 0x1F, 0x81, 0xE8, 0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xEC, \
|
|
||||||
0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xF0, 0x00, 0x00, 0x00, 0xE1, \
|
|
||||||
0x40, 0x1F, 0x81, 0xF4, 0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xF8, \
|
|
||||||
0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x81, 0xFC, 0x00, 0x00, 0x00, 0xE1, \
|
|
||||||
0x40, 0x1F, 0x82, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x82, 0x04, \
|
|
||||||
0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x82, 0x08, 0x00, 0x00, 0x00, 0xE1, \
|
|
||||||
0x40, 0x1F, 0x82, 0x0C, 0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x82, 0x10, \
|
|
||||||
0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x82, 0x14, 0x00, 0x00, 0x00, 0xE1, \
|
|
||||||
0x40, 0x1F, 0x82, 0x18, 0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x82, 0x1C, \
|
|
||||||
0x00, 0x00, 0x00, 0xE1, 0x40, 0x1F, 0x82, 0x20, 0x00, 0x00, 0x00, 0xE1, \
|
|
||||||
0x40, 0x1F, 0x82, 0x24, 0x00, 0x00, 0x00, 0xE1, 0x40, 0x2F, 0x00, 0x00, \
|
|
||||||
0x10, 0x00, 0x00, 0x04, 0x40, 0x2F, 0x00, 0x08, 0x00, 0x00, 0x00, 0x81, \
|
|
||||||
0x40, 0x2F, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x81, 0x40, 0x2F, 0x00, 0x10, \
|
|
||||||
0x80, 0x00, 0x00, 0x1B, 0x40, 0x2F, 0x00, 0x14, 0x82, 0x00, 0x00, 0x1B, \
|
|
||||||
0x40, 0x2F, 0x00, 0x18, 0x84, 0x00, 0x00, 0x1B, 0x40, 0x2F, 0x00, 0x04, \
|
|
||||||
0x00, 0x00, 0x79, 0x88, 0x40, 0x2F, 0x00, 0x40, 0x00, 0x00, 0x0F, 0x07, \
|
|
||||||
0x40, 0x2F, 0x00, 0x44, 0x00, 0x65, 0x29, 0x22, 0x40, 0x2F, 0x00, 0x48, \
|
|
||||||
0x00, 0x01, 0x09, 0x20, 0x40, 0x2F, 0x00, 0x4C, 0x50, 0x21, 0x0A, 0x08, \
|
|
||||||
0x40, 0x2F, 0x00, 0x80, 0x00, 0x00, 0x00, 0x21, 0x40, 0x2F, 0x00, 0x84, \
|
|
||||||
0x00, 0x88, 0x88, 0x88, 0x40, 0x2F, 0x00, 0x94, 0x00, 0x00, 0x00, 0x02, \
|
|
||||||
0x40, 0x2F, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x90, \
|
|
||||||
0x80, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0F, \
|
|
||||||
0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, \
|
|
||||||
0xCC, 0x00, 0x14, 0x04, 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0C, 0xCF, 0x00, 0x0C, 0x1C, \
|
|
||||||
0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x14, 0x04, \
|
|
||||||
0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x9C, \
|
|
||||||
0xA5, 0x5A, 0x00, 0x0C, 0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, \
|
|
||||||
0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x1C, 0x04, 0x40, 0x2F, 0x00, 0xA0, \
|
|
||||||
0x00, 0x00, 0x00, 0x30, 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0A, 0xCF, 0x00, 0x0C, 0x1C, \
|
|
||||||
0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x0C, 0x04, \
|
|
||||||
0x40, 0x2F, 0x00, 0x4C, 0x50, 0x21, 0x0A, 0x09
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
#include "dcd.h" // pin settings for MIMXRT1020-EVK board
|
|
||||||
#include "fsl_flexspi.h" // peripheral structures
|
|
||||||
#include "fsl_romapi.h" // peripheral structures
|
|
||||||
#include "hal.h"
|
|
||||||
|
|
||||||
extern uint32_t __isr_vector[];
|
|
||||||
|
|
||||||
// RM 9.7.2
|
|
||||||
__attribute__((section(".dcd"), used))
|
|
||||||
const uint8_t __ivt_dcd_data[] = {__DCD_DATA};
|
|
||||||
|
|
||||||
// RM 9.7.1
|
|
||||||
__attribute__((section(".dat"), used)) const uint32_t __ivt_boot_data[] = {
|
|
||||||
FlexSPI_AMBA_BASE, // boot start location
|
|
||||||
8 * 1024 * 1024, // size
|
|
||||||
0, // Plugin flag
|
|
||||||
0Xffffffff // empty - extra data word
|
|
||||||
};
|
|
||||||
|
|
||||||
__attribute__((section(".ivt"), used)) const uint32_t __ivt[8] = {
|
|
||||||
0x412000d1, // header: 41 - version, 2000 size, d1 tag
|
|
||||||
(uint32_t) __isr_vector, // entry
|
|
||||||
0, // reserved
|
|
||||||
(uint32_t) __ivt_dcd_data, // dcd
|
|
||||||
(uint32_t) __ivt_boot_data, // boot data
|
|
||||||
(uint32_t) __ivt, // this is us - ivt absolute address
|
|
||||||
0, // csf absolute address
|
|
||||||
0, // reserved for HAB
|
|
||||||
};
|
|
||||||
|
|
||||||
#define __FLEXSPI_QSPI_LUT { \
|
|
||||||
[0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18), \
|
|
||||||
[1] = FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),\
|
|
||||||
[4 * 1 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x04),\
|
|
||||||
[4 * 3 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0x0),\
|
|
||||||
[4 * 5 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 0x18),\
|
|
||||||
[4 * 8 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xD8, RADDR_SDR, FLEXSPI_1PAD, 0x18),\
|
|
||||||
[4 * 9 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 0x18),\
|
|
||||||
[4 * 9 + 1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0x04, STOP, FLEXSPI_1PAD, 0x0),\
|
|
||||||
[4 * 11 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0x0),\
|
|
||||||
}
|
|
||||||
|
|
||||||
// MIMXRT1060-EVKB flash chip config: S25LP064A-JBLE
|
|
||||||
__attribute__((section(".cfg"), used))
|
|
||||||
const flexspi_nor_config_t __qspi_flash_cfg = {
|
|
||||||
.memConfig = {.tag = FLEXSPI_CFG_BLK_TAG,
|
|
||||||
.version = FLEXSPI_CFG_BLK_VERSION,
|
|
||||||
.readSampleClkSrc = 1, // ReadSampleClk_LoopbackFromDqsPad
|
|
||||||
.csHoldTime = 3,
|
|
||||||
.csSetupTime = 3,
|
|
||||||
.controllerMiscOption = BIT(4),
|
|
||||||
.deviceType = 1, // serial NOR
|
|
||||||
.sflashPadType = 4,
|
|
||||||
.serialClkFreq = 7, // 133MHz
|
|
||||||
.sflashA1Size = 8 * 1024 * 1024,
|
|
||||||
.lookupTable = __FLEXSPI_QSPI_LUT},
|
|
||||||
.pageSize = 256,
|
|
||||||
.sectorSize = 4 * 1024,
|
|
||||||
.ipcmdSerialClkFreq = 1,
|
|
||||||
.blockSize = 64 * 1024,
|
|
||||||
.isUniformBlockSize = false};
|
|
||||||
@@ -1,337 +0,0 @@
|
|||||||
// Copyright (c) 2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
// https://www.nxp.com/webapp/Download?colCode=IMXRT1020RM
|
|
||||||
// https://cache.nxp.com/secured/assets/documents/en/user-guide/MIMXRT1020EVKHUG.pdf
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "MIMXRT1021.h"
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define BIT(x) (1UL << (x))
|
|
||||||
#define SETBITS(R, CLEARMASK, SETMASK) (R) = ((R) & ~(CLEARMASK)) | (SETMASK)
|
|
||||||
#define PIN(bank, num) ((((bank) - '0') << 8) | (num))
|
|
||||||
#define PINNO(pin) (pin & 255)
|
|
||||||
#define PINBANK(pin) (pin >> 8)
|
|
||||||
|
|
||||||
// Use LED for blinking, GPIO_AD_B0_05. GPIO1.5 (schematics)
|
|
||||||
#define LED PIN('1', 5)
|
|
||||||
|
|
||||||
#ifndef UART_DEBUG
|
|
||||||
#define UART_DEBUG LPUART1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// No settable constants, see sysinit.c
|
|
||||||
#define SYS_FREQUENCY 500000000UL
|
|
||||||
|
|
||||||
static inline void spin(volatile uint32_t count) {
|
|
||||||
while (count--) (void) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum { CLOCK_OFF = 0U, CLOCK_ON_RUN = 1U, CLOCK_ON_RUN_WAIT = 3U };
|
|
||||||
static inline void clock_periph(uint32_t index, uint32_t shift, uint32_t val) {
|
|
||||||
volatile uint32_t *r = &CCM->CCGR0;
|
|
||||||
SETBITS(r[index], 3UL << shift, val << shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
// which peripheral feeds the pin
|
|
||||||
static inline void gpio_mux_config(uint16_t index, uint8_t af) {
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[index] = af;
|
|
||||||
}
|
|
||||||
|
|
||||||
// which pin feeds the peripheral (2nd stage)
|
|
||||||
static inline void periph_mux_config(uint16_t index, uint8_t in) {
|
|
||||||
IOMUXC->SELECT_INPUT[index] = in;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT };
|
|
||||||
enum { GPIO_OTYPE_PUSH_PULL, GPIO_OTYPE_OPEN_DRAIN };
|
|
||||||
enum { GPIO_SPEED_LOW, GPIO_SPEED_MEDIUM, GPIO_SPEED_MEDIUM_, GPIO_SPEED_HIGH };
|
|
||||||
enum { GPIO_PULL_NONE, GPIO_PULL_DOWN, GPIO_PULL_UP };
|
|
||||||
static inline GPIO_Type *gpio_bank(uint16_t pin) {
|
|
||||||
static const GPIO_Type *g[] = {NULL, GPIO1, GPIO2, GPIO3, NULL, GPIO5};
|
|
||||||
return (GPIO_Type *) g[PINBANK(pin)];
|
|
||||||
}
|
|
||||||
|
|
||||||
// pin driver/pull-up/down configuration (ignore "keeper")
|
|
||||||
static inline void gpio_pad_config(uint16_t index, uint8_t type, uint8_t speed,
|
|
||||||
uint8_t pull) {
|
|
||||||
bool dopull = pull > 0;
|
|
||||||
if (dopull) --pull;
|
|
||||||
IOMUXC->SW_PAD_CTL_PAD[index] =
|
|
||||||
IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_ODE(type) |
|
|
||||||
IOMUXC_SW_PAD_CTL_PAD_SRE(speed >= GPIO_SPEED_HIGH) |
|
|
||||||
IOMUXC_SW_PAD_CTL_PAD_PUE(1) | IOMUXC_SW_PAD_CTL_PAD_PKE(dopull) |
|
|
||||||
IOMUXC_SW_PAD_CTL_PAD_PUS(pull) | IOMUXC_SW_PAD_CTL_PAD_DSE(7);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
|
|
||||||
uint8_t speed, uint8_t pull) {
|
|
||||||
GPIO_Type *gpio = gpio_bank(pin);
|
|
||||||
uint8_t bit = (uint8_t) PINNO(pin);
|
|
||||||
uint32_t mask = (uint32_t) BIT(PINNO(pin));
|
|
||||||
|
|
||||||
clock_periph(4, CCM_CCGR4_CG1_SHIFT, CLOCK_ON_RUN_WAIT); // iomuxc_ipg_clk_s
|
|
||||||
switch (PINBANK(pin)) {
|
|
||||||
case 1:
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_00 + bit, 5);
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_00 + bit, type, speed,
|
|
||||||
pull);
|
|
||||||
clock_periph(1, CCM_CCGR1_CG13_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_00 + bit, 5);
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_00 + bit, type, speed,
|
|
||||||
pull);
|
|
||||||
clock_periph(0, CCM_CCGR0_CG15_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
gpio_mux_config(bit < 13
|
|
||||||
? kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_32 + bit
|
|
||||||
: kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_00 + bit - 13,
|
|
||||||
5);
|
|
||||||
gpio_pad_config(bit < 13
|
|
||||||
? kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_32 + bit
|
|
||||||
: kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_00 + bit - 13,
|
|
||||||
type, speed, pull);
|
|
||||||
clock_periph(2, CCM_CCGR2_CG13_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
// TODO(): support sw_mux
|
|
||||||
clock_periph(1, CCM_CCGR1_CG15_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpio->IMR &= ~mask;
|
|
||||||
if (mode == GPIO_MODE_INPUT) {
|
|
||||||
gpio->GDIR &= ~mask;
|
|
||||||
} else {
|
|
||||||
gpio->GDIR |= mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static inline void gpio_input(uint16_t pin) {
|
|
||||||
gpio_init(pin, GPIO_MODE_INPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM,
|
|
||||||
GPIO_PULL_NONE);
|
|
||||||
}
|
|
||||||
static inline void gpio_output(uint16_t pin) {
|
|
||||||
gpio_init(pin, GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM,
|
|
||||||
GPIO_PULL_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool gpio_read(uint16_t pin) {
|
|
||||||
GPIO_Type *gpio = gpio_bank(pin);
|
|
||||||
uint32_t mask = (uint32_t) BIT(PINNO(pin));
|
|
||||||
return gpio->DR & mask;
|
|
||||||
}
|
|
||||||
static inline void gpio_write(uint16_t pin, bool value) {
|
|
||||||
GPIO_Type *gpio = gpio_bank(pin);
|
|
||||||
uint32_t mask = (uint32_t) BIT(PINNO(pin));
|
|
||||||
if (value) {
|
|
||||||
gpio->DR |= mask;
|
|
||||||
} else {
|
|
||||||
gpio->DR &= ~mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static inline void gpio_toggle(uint16_t pin) {
|
|
||||||
gpio_write(pin, !gpio_read(pin));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 14.5 Table 14-4: uart_clk_root
|
|
||||||
// see sysinit.c for clocks, (14.7.9: defaults to PLL3/6/1 = 80MHz)
|
|
||||||
static inline void uart_init(LPUART_Type *uart, unsigned long baud) {
|
|
||||||
uint8_t af = 2; // Alternate function
|
|
||||||
uint16_t mr = 0, pr = 0, mt = 0, pt = 0; // pins
|
|
||||||
uint32_t freq = 80000000; // uart_clk_root frequency
|
|
||||||
if (uart == LPUART1)
|
|
||||||
mt = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_06,
|
|
||||||
pt = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_06,
|
|
||||||
mr = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_07,
|
|
||||||
pr = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_07;
|
|
||||||
if (uart == LPUART2)
|
|
||||||
mt = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_08,
|
|
||||||
pt = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_08,
|
|
||||||
mr = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_09,
|
|
||||||
pr = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_09;
|
|
||||||
|
|
||||||
if (uart == LPUART1) clock_periph(5, CCM_CCGR5_CG12_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
if (uart == LPUART2) clock_periph(0, CCM_CCGR0_CG14_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
clock_periph(4, CCM_CCGR4_CG1_SHIFT, CLOCK_ON_RUN_WAIT); // iomuxc_ipg_clk_s
|
|
||||||
gpio_mux_config(mt, af);
|
|
||||||
gpio_pad_config(pt, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(mr, af);
|
|
||||||
gpio_pad_config(pr, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
|
|
||||||
|
|
||||||
uart->GLOBAL |= LPUART_GLOBAL_RST_MASK; // reset, CTRL = 0, defaults
|
|
||||||
uart->GLOBAL &= ~LPUART_GLOBAL_RST_MASK;
|
|
||||||
SETBITS(uart->BAUD,
|
|
||||||
LPUART_BAUD_OSR_MASK | LPUART_BAUD_SBR_MASK | LPUART_BAUD_SBNS_MASK,
|
|
||||||
LPUART_BAUD_OSR(16 - 1) |
|
|
||||||
LPUART_BAUD_SBR(freq / (16 * baud))); // Rx sample at 16x
|
|
||||||
SETBITS(uart->CTRL,
|
|
||||||
LPUART_CTRL_PE_MASK | LPUART_CTRL_M_MASK | LPUART_CTRL_ILT_MASK |
|
|
||||||
LPUART_CTRL_IDLECFG_MASK,
|
|
||||||
LPUART_CTRL_IDLECFG(1) | LPUART_CTRL_ILT(1) |
|
|
||||||
LPUART_BAUD_SBNS(0)); // no parity, idle 2 chars after 1 stop bit
|
|
||||||
uart->CTRL |= LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void uart_write_byte(LPUART_Type *uart, uint8_t byte) {
|
|
||||||
uart->DATA = byte;
|
|
||||||
while ((uart->STAT & LPUART_STAT_TDRE_MASK) == 0) spin(1);
|
|
||||||
}
|
|
||||||
static inline void uart_write_buf(LPUART_Type *uart, char *buf, size_t len) {
|
|
||||||
while (len-- > 0) uart_write_byte(uart, *(uint8_t *) buf++);
|
|
||||||
}
|
|
||||||
static inline int uart_read_ready(LPUART_Type *uart) {
|
|
||||||
(void) uart;
|
|
||||||
return uart->STAT & LPUART_STAT_RDRF_MASK;
|
|
||||||
}
|
|
||||||
static inline uint8_t uart_read_byte(LPUART_Type *uart) {
|
|
||||||
return (uint8_t) (uart->DATA & 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void rng_init(void) {
|
|
||||||
clock_periph(6, CCM_CCGR6_CG6_SHIFT, CLOCK_ON_RUN_WAIT); // trng_clk
|
|
||||||
SETBITS(TRNG->MCTL,
|
|
||||||
TRNG_MCTL_PRGM_MASK | TRNG_MCTL_ERR_MASK | TRNG_MCTL_RST_DEF_MASK,
|
|
||||||
TRNG_MCTL_PRGM(1) | TRNG_MCTL_ERR(1) |
|
|
||||||
TRNG_MCTL_RST_DEF(1)); // reset to default values
|
|
||||||
SETBITS(TRNG->MCTL, TRNG_MCTL_PRGM_MASK | TRNG_MCTL_ERR_MASK,
|
|
||||||
TRNG_MCTL_PRGM(0)); // set to run mode
|
|
||||||
(void) TRNG->ENT[TRNG_ENT_COUNT - 1]; // start new entropy generation
|
|
||||||
(void) TRNG->ENT[0]; // defect workaround
|
|
||||||
}
|
|
||||||
static inline uint32_t rng_read(void) {
|
|
||||||
static uint8_t idx = 0;
|
|
||||||
while ((TRNG->MCTL & TRNG_MCTL_ENT_VAL_MASK) == 0) (void) 0;
|
|
||||||
uint32_t data = TRNG->ENT[idx++]; // read data
|
|
||||||
idx %= TRNG_ENT_COUNT; // stay within array limits
|
|
||||||
if (idx == 0) // we've just read TRNG_ENT_COUNT - 1
|
|
||||||
(void) TRNG->ENT[0]; // defect workaround
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - PHY has no xtal, XI driven from ENET_REF_CLK1 (labeled as ENET_TX_CLK
|
|
||||||
// (GPIO_AD_B0_08)), generated by the MCU
|
|
||||||
// - PHY RST connected to GPIO1.4 (GPIO_AD_B0_04); INTRP/NAND_TREE connected to
|
|
||||||
// GPIO1.22 (GPIO_AD_B1_06)
|
|
||||||
// - 37.4 REF_CLK1 is RMII mode reference clock for Rx, Tx, and SMI; it is I/O
|
|
||||||
// - 11.4.2 IOMUXC_GPR_GPR1 bit 17: ENET_REF_CLK_DIR --> 1 ENET_REF_CLK is
|
|
||||||
// output driven by ref_enetpll0
|
|
||||||
// - 14.6.1.3.4 Ethernet PLL (PLL6)
|
|
||||||
static inline void ethernet_init(void) {
|
|
||||||
gpio_init(PIN('1', 4), GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_MEDIUM, GPIO_PULL_UP); // set GPIO1.4 as GPIO (PHY \RST)
|
|
||||||
gpio_write(PIN('1', 4), 0); // reset PHY
|
|
||||||
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_08,
|
|
||||||
4); // set for ENET_REF_CLK1
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_08] |=
|
|
||||||
IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_ENET_RMII_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B0_08, so RMII clock is taken
|
|
||||||
// from ENET_REF_CLK1
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_08, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_09, 0); // set for RXDATA1
|
|
||||||
periph_mux_config(kIOMUXC_ENET_RX_DATA1_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B0_09
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_09, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_10, 0); // set for RXDATA0
|
|
||||||
periph_mux_config(kIOMUXC_ENET_RX_DATA0_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B0_10
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_10, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_11, 0); // set for CRS
|
|
||||||
periph_mux_config(kIOMUXC_ENET_RX_EN_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B0_11
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_11, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_12, 0); // set for RXERR
|
|
||||||
periph_mux_config(kIOMUXC_ENET_RX_ERR_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B0_12
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_12, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_13, 0); // set for TXEN
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_13, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_14, 0); // set for TXDATA0
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_14, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_15, 0); // set for TXDATA1
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_15, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_40, 4); // set for MDIO
|
|
||||||
periph_mux_config(kIOMUXC_ENET_MDIO_SELECT_INPUT,
|
|
||||||
2); // drive peripheral from EMC_40
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_40, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_41, 4); // set for MDC
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_41, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
|
|
||||||
|
|
||||||
gpio_init(PIN('1', 22), GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_MEDIUM,
|
|
||||||
GPIO_PULL_UP); // set GPIO1.22 as GPIO (PHY INTRP/NAND_TREE)
|
|
||||||
gpio_write(PIN('1', 22), 1); // prevent NAND_TREE
|
|
||||||
// 14.8.9 Use 500MHz reference and generate 50MHz. This is done at sysinit.c,
|
|
||||||
// as we use this source to clock the core
|
|
||||||
spin(10000); // keep PHY RST low for a while
|
|
||||||
gpio_write(PIN('1', 4), 1); // deassert RST
|
|
||||||
gpio_init(PIN('1', 22), GPIO_MODE_INPUT, 0, GPIO_SPEED_MEDIUM,
|
|
||||||
GPIO_PULL_UP); // setup IRQ (pulled-up)(not used)
|
|
||||||
|
|
||||||
IOMUXC_GPR->GPR1 |=
|
|
||||||
IOMUXC_GPR_GPR1_ENET_REF_CLK_DIR(1); // Set ENET_REF_CLK1 as output
|
|
||||||
clock_periph(1, CCM_CCGR1_CG5_SHIFT, CLOCK_ON_RUN_WAIT); // enet_ipg_clk
|
|
||||||
NVIC_EnableIRQ(ENET_IRQn); // Setup Ethernet IRQ handler
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper macro for MAC generation, byte reads not allowed
|
|
||||||
#define GENERATE_LOCALLY_ADMINISTERED_MAC() \
|
|
||||||
{ \
|
|
||||||
2, OCOTP->CFG0 & 255, (OCOTP->CFG0 >> 10) & 255, \
|
|
||||||
((OCOTP->CFG0 >> 19) ^ (OCOTP->CFG1 >> 19)) & 255, \
|
|
||||||
(OCOTP->CFG1 >> 10) & 255, OCOTP->CFG1 & 255 \
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void flash_init(void) { // QSPI in FlexSPI
|
|
||||||
// set pins
|
|
||||||
clock_periph(4, CCM_CCGR4_CG1_SHIFT, CLOCK_ON_RUN_WAIT); // iomuxc_ipg_clk_s
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_05, 1); // set for DQS
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_05] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_05, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_11, 1); // set for SS
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_11] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_11, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_07, 1); // set for SCLK
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_07] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPI_A_SCLK_SELECT_INPUT, 0); // drive peripheral from B1_07
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_07, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_08, 1); // set for DATA0
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_08] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPI_A_DATA0_SELECT_INPUT, 0); // drive peripheral from B1_08
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_08, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_10, 1); // set for DATA1
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_10] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPI_A_DATA1_SELECT_INPUT, 0); // drive peripheral from B1_10
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_10, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_09, 1); // set for DATA2
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_09] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPI_A_DATA2_SELECT_INPUT, 0); // drive peripheral from B1_09
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_09, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_06, 1); // set for DATA3
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_06] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPI_A_DATA3_SELECT_INPUT, 0); // drive peripheral from B1_06
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_06, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
// set FlexSPI clock
|
|
||||||
SETBITS(CCM->CSCMR1, CCM_CSCMR1_FLEXSPI_CLK_SEL_MASK | CCM_CSCMR1_FLEXSPI_PODF_MASK, CCM_CSCMR1_FLEXSPI_CLK_SEL(3) | CCM_CSCMR1_FLEXSPI_PODF(3)); // select PLL3 PFD0 /4
|
|
||||||
clock_periph(6, CCM_CCGR6_CG5_SHIFT, CLOCK_ON_RUN_WAIT); // enable
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
ENTRY(Reset_Handler);
|
|
||||||
MEMORY {
|
|
||||||
flash_hdr(rx) : ORIGIN = 0x60000000, LENGTH = 8k
|
|
||||||
flash_irq(rx) : ORIGIN = 0x60002000, LENGTH = 1k
|
|
||||||
flash_code(rx) : ORIGIN = 0x60002400, LENGTH = 8183k
|
|
||||||
|
|
||||||
itcram(rx) : ORIGIN = 0x00000000, LENGTH = 64k
|
|
||||||
dtcram(rw) : ORIGIN = 0x20000000, LENGTH = 64k
|
|
||||||
ocram(rw) : ORIGIN = 0x20200000, LENGTH = 128k
|
|
||||||
}
|
|
||||||
__StackTop = ORIGIN(dtcram) + LENGTH(dtcram);
|
|
||||||
|
|
||||||
/* TODO(): separate itcram and go back to using dtcram for data and bss when ota is finished */
|
|
||||||
|
|
||||||
SECTIONS {
|
|
||||||
.hdr : { FILL(0xff) ; KEEP(*(.cfg)) . = 0x1000 ; KEEP(*(.ivt)) . = 0x1020 ;
|
|
||||||
KEEP(*(.dat)) . = 0x1030 ; KEEP(*(.dcd)) . = 0x2000 ;} >flash_hdr
|
|
||||||
.irq : { KEEP(*(.isr_vector)) } > flash_irq
|
|
||||||
.text : { *(.text* .text.*) *(.rodata*) ; } > flash_code
|
|
||||||
.data : { __data_start__ = .; *(.data SORT(.data.*)) *(.iram) __data_end__ = .; } > itcram AT > flash_code
|
|
||||||
__etext = LOADADDR(.data);
|
|
||||||
.bss : { __bss_start__ = .; *(.bss SORT(.bss.*) COMMON) __bss_end__ = .; } > itcram
|
|
||||||
_end = .;
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
// Copyright (c) 2022-2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
|
|
||||||
#include "hal.h"
|
|
||||||
#include "mongoose.h"
|
|
||||||
#include "net.h"
|
|
||||||
|
|
||||||
#define BLINK_PERIOD_MS 1000 // LED blinking period in millis
|
|
||||||
|
|
||||||
static volatile uint64_t s_ticks; // Milliseconds since boot
|
|
||||||
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
|
|
||||||
s_ticks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t mg_millis(void) { // Let Mongoose use our uptime function
|
|
||||||
return s_ticks; // Return number of milliseconds since boot
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_random(void *buf, size_t len) { // Use on-board RNG
|
|
||||||
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
|
|
||||||
uint32_t r = rng_read();
|
|
||||||
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static void timer_fn(void *arg) {
|
|
||||||
gpio_toggle(LED); // Blink LED
|
|
||||||
struct mg_tcpip_if *ifp = arg; // And show
|
|
||||||
const char *names[] = {"down", "up", "req", "ready"}; // network stats
|
|
||||||
MG_INFO(("Ethernet: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u",
|
|
||||||
names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent,
|
|
||||||
ifp->ndrop, ifp->nerr));
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
gpio_output(LED); // Setup blue LED
|
|
||||||
uart_init(UART_DEBUG, 115200); // Initialise debug printf
|
|
||||||
ethernet_init(); // Initialise ethernet pins
|
|
||||||
MG_INFO(("Starting, CPU freq %g MHz", (double) SystemCoreClock / 1000000));
|
|
||||||
|
|
||||||
struct mg_mgr mgr; // Initialise
|
|
||||||
mg_mgr_init(&mgr); // Mongoose event manager
|
|
||||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
|
||||||
|
|
||||||
// Initialise Mongoose network stack
|
|
||||||
struct mg_tcpip_driver_imxrt_data driver_data = {.mdc_cr = 24, .phy_addr = 2};
|
|
||||||
struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(),
|
|
||||||
// Uncomment below for static configuration:
|
|
||||||
// .ip = mg_htonl(MG_U32(192, 168, 0, 223)),
|
|
||||||
// .mask = mg_htonl(MG_U32(255, 255, 255, 0)),
|
|
||||||
// .gw = mg_htonl(MG_U32(192, 168, 0, 1)),
|
|
||||||
.driver = &mg_tcpip_driver_imxrt,
|
|
||||||
.driver_data = &driver_data};
|
|
||||||
mg_tcpip_init(&mgr, &mif);
|
|
||||||
mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_fn, &mif);
|
|
||||||
|
|
||||||
MG_INFO(("MAC: %M. Waiting for IP...", mg_print_mac, mif.mac));
|
|
||||||
while (mif.state != MG_TCPIP_STATE_READY) {
|
|
||||||
mg_mgr_poll(&mgr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
MG_INFO(("Initialising application..."));
|
|
||||||
web_init(&mgr);
|
|
||||||
|
|
||||||
MG_INFO(("Starting event loop"));
|
|
||||||
for (;;) {
|
|
||||||
mg_mgr_poll(&mgr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// See https://mongoose.ws/documentation/#build-options
|
|
||||||
#define MG_ARCH MG_ARCH_NEWLIB
|
|
||||||
#define MG_OTA MG_OTA_FLASH
|
|
||||||
#define MG_DEVICE MG_DEVICE_RT1020
|
|
||||||
|
|
||||||
#define MG_ENABLE_TCPIP 1
|
|
||||||
#define MG_ENABLE_DRIVER_IMXRT 1
|
|
||||||
#define MG_IO_SIZE 256
|
|
||||||
#define MG_ENABLE_CUSTOM_MILLIS 1
|
|
||||||
#define MG_ENABLE_CUSTOM_RANDOM 1
|
|
||||||
#define MG_ENABLE_PACKED_FS 1
|
|
||||||
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
// Copyright (c) 2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
//
|
|
||||||
// This file contains essentials required by the CMSIS:
|
|
||||||
// uint32_t SystemCoreClock - holds the system core clock value
|
|
||||||
// SystemInit() - initialises the system, e.g. sets up clocks
|
|
||||||
|
|
||||||
#include "hal.h"
|
|
||||||
|
|
||||||
uint32_t SystemCoreClock = SYS_FREQUENCY;
|
|
||||||
|
|
||||||
// - 14.4, Figure 14-2: clock tree
|
|
||||||
// - 14.7.4: ARM_PODF defaults to /1
|
|
||||||
// - 14.7.5: AHB_PODF defaults to /1; PERIPH_CLK_SEL defaults to derive clock
|
|
||||||
// from pre_periph_clk_sel
|
|
||||||
// - 14.7.6: PRE_PERIPH_CLK_SEL defaults to derive clock from PLL2 PFD3.
|
|
||||||
// - (For 528MHz operation, we need to set it to derive clock from PLL2, but
|
|
||||||
// this chip max is 500 MHz).
|
|
||||||
// - 14.6.1.3.1 System PLL (PLL2); 13.3.2.2 PLLs; 14.6.1.4 Phase Fractional
|
|
||||||
// Dividers (PFD)
|
|
||||||
// - 14.8.2: PLL2 is powered off and bypassed to 24MHz
|
|
||||||
// - 14.8.11: PFD defaults to 18/16 but Figure 14-2 shows half the value
|
|
||||||
// ("divider")
|
|
||||||
// - For 500MHz operation, we need to set PRE_PERIPH_CLK_SEL to derive clock
|
|
||||||
// from divided PLL6
|
|
||||||
// - 14.8.9: configure PLL6 to generate a 500MHz clock
|
|
||||||
// - Datasheet 4.1.3: System frequency/Bus frequency max 500/125MHz respectively
|
|
||||||
// (AHB/IPG)
|
|
||||||
// - MCUXpresso: IPG_CLK_ROOT <= 125MHz; PERCLK_CLK_ROOT <= 62.5MHz
|
|
||||||
// - Datasheet 4.8.4.1.1/2: the processor clock frequency must exceed twice the
|
|
||||||
// ENET_RX_CLK/ENET_TX_CLK frequency.
|
|
||||||
// - Datasheet 4.8.4.2: no details for RMII (above is for MII), assumed 50MHz
|
|
||||||
// min processor clock
|
|
||||||
// - Datasheet 4.1.3, Table 11: "Overdrive" run mode requires 1.25V core voltage
|
|
||||||
// minimum
|
|
||||||
void SystemInit(void) { // Called automatically by startup code (ints masked)
|
|
||||||
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU
|
|
||||||
asm("DSB");
|
|
||||||
asm("ISB");
|
|
||||||
// 53.4.2: Disable watchdog after reset (unlocked)
|
|
||||||
RTWDOG->CS &= ~RTWDOG_CS_EN_MASK;
|
|
||||||
RTWDOG->TOVAL = 0xFFFF;
|
|
||||||
while (RTWDOG->CS & RTWDOG_CS_ULK_MASK) spin(1); // wait for lock
|
|
||||||
while ((RTWDOG->CS & RTWDOG_CS_RCS_MASK) == 0)
|
|
||||||
spin(1); // wait for new config
|
|
||||||
// Set VDD_SOC to 1.25V
|
|
||||||
SETBITS(DCDC->REG3, DCDC_REG3_TRG_MASK, DCDC_REG3_TRG(0x12));
|
|
||||||
while ((DCDC->REG0 & DCDC_REG0_STS_DC_OK_MASK) == 0)
|
|
||||||
spin(1); // Wait for DCDC_STS_DC_OK
|
|
||||||
// 14.8.9 Init 500MHz reference, clock the M7 core with it, generate 50MHz for
|
|
||||||
// ENET and RMII.
|
|
||||||
SETBITS(CCM_ANALOG->PLL_ENET, CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC_MASK,
|
|
||||||
CCM_ANALOG_PLL_ENET_BYPASS_MASK |
|
|
||||||
CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC(0)); // bypass to 24MHz osc
|
|
||||||
SETBITS(
|
|
||||||
CCM_ANALOG->PLL_ENET,
|
|
||||||
CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK | CCM_ANALOG_PLL_ENET_POWERDOWN_MASK,
|
|
||||||
CCM_ANALOG_PLL_ENET_DIV_SELECT(1) | CCM_ANALOG_PLL_ENET_ENABLE_MASK |
|
|
||||||
CCM_ANALOG_PLL_ENET_ENET_500M_REF_EN_MASK); // setup PLL
|
|
||||||
while ((CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_LOCK_MASK) == 0)
|
|
||||||
spin(1); // wait until it is stable
|
|
||||||
CCM_ANALOG->PLL_ENET &=
|
|
||||||
~CCM_ANALOG_PLL_ENET_BYPASS_MASK; // Disable Bypass (switch to PLL)
|
|
||||||
SETBITS(CCM->CBCDR, CCM_CBCDR_IPG_PODF_MASK,
|
|
||||||
CCM_CBCDR_IPG_PODF(3)); // Set IPG divider /4 (125MHz)
|
|
||||||
SETBITS(CCM->CSCMR1, CCM_CSCMR1_PERCLK_PODF_MASK,
|
|
||||||
CCM_CSCMR1_PERCLK_PODF(1)); // Set PERCLK divider /2 (62.5MHz)
|
|
||||||
SETBITS(CCM->CBCMR, CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK,
|
|
||||||
CCM_CBCMR_PRE_PERIPH_CLK_SEL(3)); // run from 500MHz clock
|
|
||||||
// 14.5 Table 14-4: uart_clk_root
|
|
||||||
// 14.4: uart_clk_root = PLL3/6 or OSC; CCM_CSCDR1 (14.7.9) defaults to
|
|
||||||
// PLL3/6/1; but ROM boot code fiddles with the divider (9.5.3 Table 9-7)
|
|
||||||
CCM_ANALOG->PLL_USB1 |= CCM_ANALOG_PLL_USB1_POWER_MASK; // Power PLL on
|
|
||||||
while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0)
|
|
||||||
spin(1); // wait until it is stable
|
|
||||||
CCM_ANALOG->PLL_USB1 &=
|
|
||||||
~CCM_ANALOG_PLL_USB1_BYPASS_MASK; // Disable Bypass (switch to PLL)
|
|
||||||
CCM->CSCDR1 &= ~(CCM_CSCDR1_UART_CLK_SEL_MASK | CCM_CSCDR1_UART_CLK_PODF_MASK);
|
|
||||||
rng_init(); // Initialise random number generator
|
|
||||||
// NXP startup code calls SystemInit BEFORE initializing RAM...
|
|
||||||
SysTick_Config(SYS_FREQUENCY / 1000); // Sys tick every 1ms
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "hal.h"
|
|
||||||
|
|
||||||
#define configUSE_PREEMPTION 1
|
|
||||||
#define configCPU_CLOCK_HZ SYS_FREQUENCY
|
|
||||||
#define configTICK_RATE_HZ 1000
|
|
||||||
#define configMAX_PRIORITIES 5
|
|
||||||
#define configUSE_16_BIT_TICKS 0
|
|
||||||
#define configUSE_TICK_HOOK 0
|
|
||||||
#define configUSE_IDLE_HOOK 0
|
|
||||||
#define configUSE_TIMERS 0
|
|
||||||
#define configUSE_CO_ROUTINES 0
|
|
||||||
#define configUSE_MALLOC_FAILED_HOOK 0
|
|
||||||
#define configMINIMAL_STACK_SIZE 128
|
|
||||||
#define configTOTAL_HEAP_SIZE (1024 * 32)
|
|
||||||
#define INCLUDE_vTaskDelay 1
|
|
||||||
#define INCLUDE_xTaskGetSchedulerState 1 // trying
|
|
||||||
|
|
||||||
#ifdef __NVIC_PRIO_BITS
|
|
||||||
#define configPRIO_BITS __NVIC_PRIO_BITS
|
|
||||||
#else
|
|
||||||
#define configPRIO_BITS 4
|
|
||||||
#endif
|
|
||||||
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
|
|
||||||
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
|
|
||||||
#define configKERNEL_INTERRUPT_PRIORITY \
|
|
||||||
(configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
|
|
||||||
|
|
||||||
#define configMAX_SYSCALL_INTERRUPT_PRIORITY \
|
|
||||||
(configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
|
|
||||||
|
|
||||||
#define configASSERT(expr) \
|
|
||||||
if (!(expr)) printf("FAILURE %s:%d: %s\n", __FILE__, __LINE__, #expr)
|
|
||||||
|
|
||||||
#define vPortSVCHandler SVC_Handler
|
|
||||||
#define xPortPendSVHandler PendSV_Handler
|
|
||||||
#define xPortSysTickHandler SysTick_Handler
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
CFLAGS = -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion
|
|
||||||
CFLAGS += -Wformat-truncation -fno-common # -Wconversion is not SDK-friendly
|
|
||||||
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
|
|
||||||
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_mcu/devices/MIMXRT1021
|
|
||||||
CFLAGS += -Icmsis_mcu/devices/MIMXRT1021/drivers -DCPU_MIMXRT1021DAG5A
|
|
||||||
CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16 $(CFLAGS_EXTRA)
|
|
||||||
LDSCRIPT = link.ld
|
|
||||||
LDFLAGS ?= -T$(LDSCRIPT) -nostdlib -nostartfiles --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
|
||||||
|
|
||||||
SOURCES = main.c syscalls.c sysinit.c
|
|
||||||
SOURCES += cmsis_mcu/devices/MIMXRT1021/gcc/startup_MIMXRT1021.S # NXP startup file. Compiler-dependent!
|
|
||||||
CFLAGS += -D__ATOLLIC__ -D__STARTUP_CLEAR_BSS # Make startup code work as expected
|
|
||||||
|
|
||||||
# FreeRTOS. RT1020 has a Cortex-M7 r1p2 core, FreeRTOS recommends using CM4F port for non-r0p1 CM7 micros
|
|
||||||
SOURCES += FreeRTOS-Kernel/portable/MemMang/heap_4.c
|
|
||||||
SOURCES += FreeRTOS-Kernel/portable/GCC/ARM_CM4F/port.c
|
|
||||||
CFLAGS += -IFreeRTOS-Kernel/include
|
|
||||||
CFLAGS += -IFreeRTOS-Kernel/portable/GCC/ARM_CM4F -Wno-conversion
|
|
||||||
|
|
||||||
# Mongoose options are defined in mongoose_config.h
|
|
||||||
SOURCES += mongoose.c net.c packed_fs.c
|
|
||||||
|
|
||||||
# Example specific build options. See README.md
|
|
||||||
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\"
|
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
|
||||||
RM = cmd /C del /Q /F /S
|
|
||||||
else
|
|
||||||
RM = rm -rf
|
|
||||||
endif
|
|
||||||
|
|
||||||
all build example update: SOURCES += flash_image.c
|
|
||||||
all build example: firmware.bin
|
|
||||||
|
|
||||||
ram: LDSCRIPT = link_ram.ld
|
|
||||||
ram: firmware.bin
|
|
||||||
|
|
||||||
firmware.bin: firmware.elf
|
|
||||||
arm-none-eabi-objcopy -O binary $< $@
|
|
||||||
|
|
||||||
firmware.elf: FreeRTOS-Kernel cmsis_core cmsis_mcu $(SOURCES) hal.h link_ram.ld link.ld mongoose_config.h
|
|
||||||
arm-none-eabi-gcc $(SOURCES) $(wildcard FreeRTOS-Kernel/*.c) $(CFLAGS) $(LDFLAGS) -o $@
|
|
||||||
|
|
||||||
flash: firmware.bin
|
|
||||||
# flash
|
|
||||||
|
|
||||||
cmsis_core: # ARM CMSIS core headers
|
|
||||||
git clone -q --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
|
|
||||||
cmsis_mcu:
|
|
||||||
curl -sL https://mcuxpresso.nxp.com/cmsis_pack/repo/NXP.MIMXRT1021_DFP.17.0.0.pack -o $@.zip
|
|
||||||
mkdir $@ && cd $@ && unzip -q ../$@.zip
|
|
||||||
FreeRTOS-Kernel: # FreeRTOS sources
|
|
||||||
git clone --depth 1 -b V10.5.0 https://github.com/FreeRTOS/FreeRTOS-Kernel $@
|
|
||||||
|
|
||||||
# Automated remote test. Requires env variable VCON_API_KEY set. See https://vcon.io/automated-firmware-tests/
|
|
||||||
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/4
|
|
||||||
update: firmware.bin
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @$<
|
|
||||||
|
|
||||||
update updateram: CFLAGS += -DUART_DEBUG=LPUART2
|
|
||||||
|
|
||||||
test: update
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
|
|
||||||
grep 'READY, IP:' /tmp/output.txt # Check for network init
|
|
||||||
|
|
||||||
|
|
||||||
updateram: ram
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @firmware.bin
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"init"}'
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"wm,e000edf0,a05f0003 wm,e000edfc,1 wm,e000ed0c,5fa0004"}'
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"init"}'
|
|
||||||
PC=`curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"rm,4"}' | jq -r .resp[5:]` && \
|
|
||||||
SP=`curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"rm,0"}' | jq -r .resp[5:]` && \
|
|
||||||
REQ="wm,e000ed08,0 wr,d,$$SP wr,f,$$PC" && \
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"'"$$REQ"'"}'
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"wm,e000edf0,a05f0001"}'
|
|
||||||
|
|
||||||
testram: updateram
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
|
|
||||||
grep 'READY, IP:' /tmp/output.txt # Check for network init
|
|
||||||
|
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) firmware.* *.su cmsis_core cmsis_mcu FreeRTOS-Kernel *.zip
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../rt1020-evk-make-baremetal-builtin/dcd.h
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../rt1020-evk-make-baremetal-builtin/flash_image.c
|
|
||||||
@@ -1,337 +0,0 @@
|
|||||||
// Copyright (c) 2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
// https://www.nxp.com/webapp/Download?colCode=IMXRT1020RM
|
|
||||||
// https://cache.nxp.com/secured/assets/documents/en/user-guide/MIMXRT1020EVKHUG.pdf
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "MIMXRT1021.h"
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define BIT(x) (1UL << (x))
|
|
||||||
#define SETBITS(R, CLEARMASK, SETMASK) (R) = ((R) & ~(CLEARMASK)) | (SETMASK)
|
|
||||||
#define PIN(bank, num) ((((bank) - '0') << 8) | (num))
|
|
||||||
#define PINNO(pin) (pin & 255)
|
|
||||||
#define PINBANK(pin) (pin >> 8)
|
|
||||||
|
|
||||||
// Use LED for blinking, GPIO_AD_B0_05. GPIO1.5 (schematics)
|
|
||||||
#define LED PIN('1', 5)
|
|
||||||
|
|
||||||
#ifndef UART_DEBUG
|
|
||||||
#define UART_DEBUG LPUART1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// No settable constants, see sysinit.c
|
|
||||||
#define SYS_FREQUENCY 500000000UL
|
|
||||||
|
|
||||||
static inline void spin(volatile uint32_t count) {
|
|
||||||
while (count--) (void) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum { CLOCK_OFF = 0U, CLOCK_ON_RUN = 1U, CLOCK_ON_RUN_WAIT = 3U };
|
|
||||||
static inline void clock_periph(uint32_t index, uint32_t shift, uint32_t val) {
|
|
||||||
volatile uint32_t *r = &CCM->CCGR0;
|
|
||||||
SETBITS(r[index], 3UL << shift, val << shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
// which peripheral feeds the pin
|
|
||||||
static inline void gpio_mux_config(uint16_t index, uint8_t af) {
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[index] = af;
|
|
||||||
}
|
|
||||||
|
|
||||||
// which pin feeds the peripheral (2nd stage)
|
|
||||||
static inline void periph_mux_config(uint16_t index, uint8_t in) {
|
|
||||||
IOMUXC->SELECT_INPUT[index] = in;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT };
|
|
||||||
enum { GPIO_OTYPE_PUSH_PULL, GPIO_OTYPE_OPEN_DRAIN };
|
|
||||||
enum { GPIO_SPEED_LOW, GPIO_SPEED_MEDIUM, GPIO_SPEED_MEDIUM_, GPIO_SPEED_HIGH };
|
|
||||||
enum { GPIO_PULL_NONE, GPIO_PULL_DOWN, GPIO_PULL_UP };
|
|
||||||
static inline GPIO_Type *gpio_bank(uint16_t pin) {
|
|
||||||
static const GPIO_Type *g[] = {NULL, GPIO1, GPIO2, GPIO3, NULL, GPIO5};
|
|
||||||
return (GPIO_Type *) g[PINBANK(pin)];
|
|
||||||
}
|
|
||||||
|
|
||||||
// pin driver/pull-up/down configuration (ignore "keeper")
|
|
||||||
static inline void gpio_pad_config(uint16_t index, uint8_t type, uint8_t speed,
|
|
||||||
uint8_t pull) {
|
|
||||||
bool dopull = pull > 0;
|
|
||||||
if (dopull) --pull;
|
|
||||||
IOMUXC->SW_PAD_CTL_PAD[index] =
|
|
||||||
IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_ODE(type) |
|
|
||||||
IOMUXC_SW_PAD_CTL_PAD_SRE(speed >= GPIO_SPEED_HIGH) |
|
|
||||||
IOMUXC_SW_PAD_CTL_PAD_PUE(1) | IOMUXC_SW_PAD_CTL_PAD_PKE(dopull) |
|
|
||||||
IOMUXC_SW_PAD_CTL_PAD_PUS(pull) | IOMUXC_SW_PAD_CTL_PAD_DSE(7);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
|
|
||||||
uint8_t speed, uint8_t pull) {
|
|
||||||
GPIO_Type *gpio = gpio_bank(pin);
|
|
||||||
uint8_t bit = (uint8_t) PINNO(pin);
|
|
||||||
uint32_t mask = (uint32_t) BIT(PINNO(pin));
|
|
||||||
|
|
||||||
clock_periph(4, CCM_CCGR4_CG1_SHIFT, CLOCK_ON_RUN_WAIT); // iomuxc_ipg_clk_s
|
|
||||||
switch (PINBANK(pin)) {
|
|
||||||
case 1:
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_00 + bit, 5);
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_00 + bit, type, speed,
|
|
||||||
pull);
|
|
||||||
clock_periph(1, CCM_CCGR1_CG13_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_00 + bit, 5);
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_00 + bit, type, speed,
|
|
||||||
pull);
|
|
||||||
clock_periph(0, CCM_CCGR0_CG15_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
gpio_mux_config(bit < 13
|
|
||||||
? kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_32 + bit
|
|
||||||
: kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_00 + bit - 13,
|
|
||||||
5);
|
|
||||||
gpio_pad_config(bit < 13
|
|
||||||
? kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_32 + bit
|
|
||||||
: kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_00 + bit - 13,
|
|
||||||
type, speed, pull);
|
|
||||||
clock_periph(2, CCM_CCGR2_CG13_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
// TODO(): support sw_mux
|
|
||||||
clock_periph(1, CCM_CCGR1_CG15_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpio->IMR &= ~mask;
|
|
||||||
if (mode == GPIO_MODE_INPUT) {
|
|
||||||
gpio->GDIR &= ~mask;
|
|
||||||
} else {
|
|
||||||
gpio->GDIR |= mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static inline void gpio_input(uint16_t pin) {
|
|
||||||
gpio_init(pin, GPIO_MODE_INPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM,
|
|
||||||
GPIO_PULL_NONE);
|
|
||||||
}
|
|
||||||
static inline void gpio_output(uint16_t pin) {
|
|
||||||
gpio_init(pin, GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM,
|
|
||||||
GPIO_PULL_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool gpio_read(uint16_t pin) {
|
|
||||||
GPIO_Type *gpio = gpio_bank(pin);
|
|
||||||
uint32_t mask = (uint32_t) BIT(PINNO(pin));
|
|
||||||
return gpio->DR & mask;
|
|
||||||
}
|
|
||||||
static inline void gpio_write(uint16_t pin, bool value) {
|
|
||||||
GPIO_Type *gpio = gpio_bank(pin);
|
|
||||||
uint32_t mask = (uint32_t) BIT(PINNO(pin));
|
|
||||||
if (value) {
|
|
||||||
gpio->DR |= mask;
|
|
||||||
} else {
|
|
||||||
gpio->DR &= ~mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static inline void gpio_toggle(uint16_t pin) {
|
|
||||||
gpio_write(pin, !gpio_read(pin));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 14.5 Table 14-4: uart_clk_root
|
|
||||||
// see sysinit.c for clocks, (14.7.9: defaults to PLL3/6/1 = 80MHz)
|
|
||||||
static inline void uart_init(LPUART_Type *uart, unsigned long baud) {
|
|
||||||
uint8_t af = 2; // Alternate function
|
|
||||||
uint16_t mr = 0, pr = 0, mt = 0, pt = 0; // pins
|
|
||||||
uint32_t freq = 80000000; // uart_clk_root frequency
|
|
||||||
if (uart == LPUART1)
|
|
||||||
mt = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_06,
|
|
||||||
pt = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_06,
|
|
||||||
mr = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_07,
|
|
||||||
pr = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_07;
|
|
||||||
if (uart == LPUART2)
|
|
||||||
mt = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_08,
|
|
||||||
pt = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_08,
|
|
||||||
mr = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_09,
|
|
||||||
pr = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_09;
|
|
||||||
|
|
||||||
if (uart == LPUART1) clock_periph(5, CCM_CCGR5_CG12_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
if (uart == LPUART2) clock_periph(0, CCM_CCGR0_CG14_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
clock_periph(4, CCM_CCGR4_CG1_SHIFT, CLOCK_ON_RUN_WAIT); // iomuxc_ipg_clk_s
|
|
||||||
gpio_mux_config(mt, af);
|
|
||||||
gpio_pad_config(pt, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(mr, af);
|
|
||||||
gpio_pad_config(pr, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
|
|
||||||
|
|
||||||
uart->GLOBAL |= LPUART_GLOBAL_RST_MASK; // reset, CTRL = 0, defaults
|
|
||||||
uart->GLOBAL &= ~LPUART_GLOBAL_RST_MASK;
|
|
||||||
SETBITS(uart->BAUD,
|
|
||||||
LPUART_BAUD_OSR_MASK | LPUART_BAUD_SBR_MASK | LPUART_BAUD_SBNS_MASK,
|
|
||||||
LPUART_BAUD_OSR(16 - 1) |
|
|
||||||
LPUART_BAUD_SBR(freq / (16 * baud))); // Rx sample at 16x
|
|
||||||
SETBITS(uart->CTRL,
|
|
||||||
LPUART_CTRL_PE_MASK | LPUART_CTRL_M_MASK | LPUART_CTRL_ILT_MASK |
|
|
||||||
LPUART_CTRL_IDLECFG_MASK,
|
|
||||||
LPUART_CTRL_IDLECFG(1) | LPUART_CTRL_ILT(1) |
|
|
||||||
LPUART_BAUD_SBNS(0)); // no parity, idle 2 chars after 1 stop bit
|
|
||||||
uart->CTRL |= LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void uart_write_byte(LPUART_Type *uart, uint8_t byte) {
|
|
||||||
uart->DATA = byte;
|
|
||||||
while ((uart->STAT & LPUART_STAT_TDRE_MASK) == 0) spin(1);
|
|
||||||
}
|
|
||||||
static inline void uart_write_buf(LPUART_Type *uart, char *buf, size_t len) {
|
|
||||||
while (len-- > 0) uart_write_byte(uart, *(uint8_t *) buf++);
|
|
||||||
}
|
|
||||||
static inline int uart_read_ready(LPUART_Type *uart) {
|
|
||||||
(void) uart;
|
|
||||||
return uart->STAT & LPUART_STAT_RDRF_MASK;
|
|
||||||
}
|
|
||||||
static inline uint8_t uart_read_byte(LPUART_Type *uart) {
|
|
||||||
return (uint8_t) (uart->DATA & 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void rng_init(void) {
|
|
||||||
clock_periph(6, CCM_CCGR6_CG6_SHIFT, CLOCK_ON_RUN_WAIT); // trng_clk
|
|
||||||
SETBITS(TRNG->MCTL,
|
|
||||||
TRNG_MCTL_PRGM_MASK | TRNG_MCTL_ERR_MASK | TRNG_MCTL_RST_DEF_MASK,
|
|
||||||
TRNG_MCTL_PRGM(1) | TRNG_MCTL_ERR(1) |
|
|
||||||
TRNG_MCTL_RST_DEF(1)); // reset to default values
|
|
||||||
SETBITS(TRNG->MCTL, TRNG_MCTL_PRGM_MASK | TRNG_MCTL_ERR_MASK,
|
|
||||||
TRNG_MCTL_PRGM(0)); // set to run mode
|
|
||||||
(void) TRNG->ENT[TRNG_ENT_COUNT - 1]; // start new entropy generation
|
|
||||||
(void) TRNG->ENT[0]; // defect workaround
|
|
||||||
}
|
|
||||||
static inline uint32_t rng_read(void) {
|
|
||||||
static uint8_t idx = 0;
|
|
||||||
while ((TRNG->MCTL & TRNG_MCTL_ENT_VAL_MASK) == 0) (void) 0;
|
|
||||||
uint32_t data = TRNG->ENT[idx++]; // read data
|
|
||||||
idx %= TRNG_ENT_COUNT; // stay within array limits
|
|
||||||
if (idx == 0) // we've just read TRNG_ENT_COUNT - 1
|
|
||||||
(void) TRNG->ENT[0]; // defect workaround
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - PHY has no xtal, XI driven from ENET_REF_CLK1 (labeled as ENET_TX_CLK
|
|
||||||
// (GPIO_AD_B0_08)), generated by the MCU
|
|
||||||
// - PHY RST connected to GPIO1.4 (GPIO_AD_B0_04); INTRP/NAND_TREE connected to
|
|
||||||
// GPIO1.22 (GPIO_AD_B1_06)
|
|
||||||
// - 37.4 REF_CLK1 is RMII mode reference clock for Rx, Tx, and SMI; it is I/O
|
|
||||||
// - 11.4.2 IOMUXC_GPR_GPR1 bit 17: ENET_REF_CLK_DIR --> 1 ENET_REF_CLK is
|
|
||||||
// output driven by ref_enetpll0
|
|
||||||
// - 14.6.1.3.4 Ethernet PLL (PLL6)
|
|
||||||
static inline void ethernet_init(void) {
|
|
||||||
gpio_init(PIN('1', 4), GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_MEDIUM, GPIO_PULL_UP); // set GPIO1.4 as GPIO (PHY \RST)
|
|
||||||
gpio_write(PIN('1', 4), 0); // reset PHY
|
|
||||||
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_08,
|
|
||||||
4); // set for ENET_REF_CLK1
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_08] |=
|
|
||||||
IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_ENET_RMII_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B0_08, so RMII clock is taken
|
|
||||||
// from ENET_REF_CLK1
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_08, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_09, 0); // set for RXDATA1
|
|
||||||
periph_mux_config(kIOMUXC_ENET_RX_DATA1_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B0_09
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_09, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_10, 0); // set for RXDATA0
|
|
||||||
periph_mux_config(kIOMUXC_ENET_RX_DATA0_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B0_10
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_10, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_11, 0); // set for CRS
|
|
||||||
periph_mux_config(kIOMUXC_ENET_RX_EN_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B0_11
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_11, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_12, 0); // set for RXERR
|
|
||||||
periph_mux_config(kIOMUXC_ENET_RX_ERR_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B0_12
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_12, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_13, 0); // set for TXEN
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_13, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_14, 0); // set for TXDATA0
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_14, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_15, 0); // set for TXDATA1
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_15, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_40, 4); // set for MDIO
|
|
||||||
periph_mux_config(kIOMUXC_ENET_MDIO_SELECT_INPUT,
|
|
||||||
2); // drive peripheral from EMC_40
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_40, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_41, 4); // set for MDC
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_41, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
|
|
||||||
|
|
||||||
gpio_init(PIN('1', 22), GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_MEDIUM,
|
|
||||||
GPIO_PULL_UP); // set GPIO1.22 as GPIO (PHY INTRP/NAND_TREE)
|
|
||||||
gpio_write(PIN('1', 22), 1); // prevent NAND_TREE
|
|
||||||
// 14.8.9 Use 500MHz reference and generate 50MHz. This is done at sysinit.c,
|
|
||||||
// as we use this source to clock the core
|
|
||||||
spin(10000); // keep PHY RST low for a while
|
|
||||||
gpio_write(PIN('1', 4), 1); // deassert RST
|
|
||||||
gpio_init(PIN('1', 22), GPIO_MODE_INPUT, 0, GPIO_SPEED_MEDIUM,
|
|
||||||
GPIO_PULL_UP); // setup IRQ (pulled-up)(not used)
|
|
||||||
|
|
||||||
IOMUXC_GPR->GPR1 |=
|
|
||||||
IOMUXC_GPR_GPR1_ENET_REF_CLK_DIR(1); // Set ENET_REF_CLK1 as output
|
|
||||||
clock_periph(1, CCM_CCGR1_CG5_SHIFT, CLOCK_ON_RUN_WAIT); // enet_ipg_clk
|
|
||||||
NVIC_EnableIRQ(ENET_IRQn); // Setup Ethernet IRQ handler
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper macro for MAC generation, byte reads not allowed
|
|
||||||
#define GENERATE_LOCALLY_ADMINISTERED_MAC() \
|
|
||||||
{ \
|
|
||||||
2, OCOTP->CFG0 & 255, (OCOTP->CFG0 >> 10) & 255, \
|
|
||||||
((OCOTP->CFG0 >> 19) ^ (OCOTP->CFG1 >> 19)) & 255, \
|
|
||||||
(OCOTP->CFG1 >> 10) & 255, OCOTP->CFG1 & 255 \
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void flash_init(void) { // QSPI in FlexSPI
|
|
||||||
// set pins
|
|
||||||
clock_periph(4, CCM_CCGR4_CG1_SHIFT, CLOCK_ON_RUN_WAIT); // iomuxc_ipg_clk_s
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_05, 1); // set for DQS
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_05] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_05, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_11, 1); // set for SS
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_11] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_11, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_07, 1); // set for SCLK
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_07] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPI_A_SCLK_SELECT_INPUT, 0); // drive peripheral from B1_07
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_07, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_08, 1); // set for DATA0
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_08] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPI_A_DATA0_SELECT_INPUT, 0); // drive peripheral from B1_08
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_08, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_10, 1); // set for DATA1
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_10] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPI_A_DATA1_SELECT_INPUT, 0); // drive peripheral from B1_10
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_10, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_09, 1); // set for DATA2
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_09] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPI_A_DATA2_SELECT_INPUT, 0); // drive peripheral from B1_09
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_09, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_06, 1); // set for DATA3
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_06] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPI_A_DATA3_SELECT_INPUT, 0); // drive peripheral from B1_06
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_06, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
// set FlexSPI clock
|
|
||||||
SETBITS(CCM->CSCMR1, CCM_CSCMR1_FLEXSPI_CLK_SEL_MASK | CCM_CSCMR1_FLEXSPI_PODF_MASK, CCM_CSCMR1_FLEXSPI_CLK_SEL(3) | CCM_CSCMR1_FLEXSPI_PODF(3)); // select PLL3 PFD0 /4
|
|
||||||
clock_periph(6, CCM_CCGR6_CG5_SHIFT, CLOCK_ON_RUN_WAIT); // enable
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
ENTRY(Reset_Handler);
|
|
||||||
MEMORY {
|
|
||||||
flash_hdr(rx) : ORIGIN = 0x60000000, LENGTH = 8k
|
|
||||||
flash_irq(rx) : ORIGIN = 0x60002000, LENGTH = 1k
|
|
||||||
flash_code(rx) : ORIGIN = 0x60002400, LENGTH = 8183k
|
|
||||||
|
|
||||||
itcram(rx) : ORIGIN = 0x00000000, LENGTH = 64k
|
|
||||||
dtcram(rw) : ORIGIN = 0x20000000, LENGTH = 64k
|
|
||||||
ocram(rw) : ORIGIN = 0x20200000, LENGTH = 128k
|
|
||||||
}
|
|
||||||
__StackTop = ORIGIN(dtcram) + LENGTH(dtcram);
|
|
||||||
|
|
||||||
SECTIONS {
|
|
||||||
.hdr : { FILL(0xff) ; KEEP(*(.cfg)) . = 0x1000 ; KEEP(*(.ivt)) . = 0x1020 ;
|
|
||||||
KEEP(*(.dat)) . = 0x1030 ; KEEP(*(.dcd)) . = 0x2000 ;} >flash_hdr
|
|
||||||
.irq : { KEEP(*(.isr_vector)) } > flash_irq
|
|
||||||
.text : { *(.text* .text.*) *(.rodata*) ; } > flash_code
|
|
||||||
.data : { __data_start__ = .; *(.data SORT(.data.*)) __data_end__ = .; } > dtcram AT > flash_code
|
|
||||||
__etext = LOADADDR(.data);
|
|
||||||
.bss : { __bss_start__ = .; *(.bss SORT(.bss.*) COMMON) __bss_end__ = .; } > dtcram
|
|
||||||
_end = .;
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
// Copyright (c) 2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
|
|
||||||
#include "hal.h"
|
|
||||||
#include "mongoose.h"
|
|
||||||
#include "net.h"
|
|
||||||
|
|
||||||
#define BLINK_PERIOD_MS 1000 // LED blinking period in millis
|
|
||||||
|
|
||||||
void mg_random(void *buf, size_t len) { // Use on-board RNG
|
|
||||||
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
|
|
||||||
uint32_t r = rng_read();
|
|
||||||
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void timer_fn(void *arg) {
|
|
||||||
struct mg_tcpip_if *ifp = arg; // And show
|
|
||||||
const char *names[] = {"down", "up", "req", "ready"}; // network stats
|
|
||||||
MG_INFO(("Ethernet: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u",
|
|
||||||
names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent,
|
|
||||||
ifp->ndrop, ifp->nerr));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void server(void *args) {
|
|
||||||
struct mg_mgr mgr; // Initialise Mongoose event manager
|
|
||||||
mg_mgr_init(&mgr); // and attach it to the interface
|
|
||||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
|
||||||
|
|
||||||
// Initialise Mongoose network stack
|
|
||||||
ethernet_init();
|
|
||||||
struct mg_tcpip_driver_imxrt_data driver_data = {.mdc_cr = 24, .phy_addr = 2};
|
|
||||||
struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(),
|
|
||||||
// Uncomment below for static configuration:
|
|
||||||
// .ip = mg_htonl(MG_U32(192, 168, 0, 223)),
|
|
||||||
// .mask = mg_htonl(MG_U32(255, 255, 255, 0)),
|
|
||||||
// .gw = mg_htonl(MG_U32(192, 168, 0, 1)),
|
|
||||||
.driver = &mg_tcpip_driver_imxrt,
|
|
||||||
.driver_data = &driver_data};
|
|
||||||
mg_tcpip_init(&mgr, &mif);
|
|
||||||
mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_fn, &mif);
|
|
||||||
|
|
||||||
MG_INFO(("MAC: %M. Waiting for IP...", mg_print_mac, mif.mac));
|
|
||||||
while (mif.state != MG_TCPIP_STATE_READY) {
|
|
||||||
mg_mgr_poll(&mgr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
MG_INFO(("Initialising application..."));
|
|
||||||
web_init(&mgr);
|
|
||||||
|
|
||||||
MG_INFO(("Starting event loop"));
|
|
||||||
for (;;) mg_mgr_poll(&mgr, 1); // Infinite event loop
|
|
||||||
(void) args;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void blinker(void *args) {
|
|
||||||
gpio_output(LED); // Setup blue LED
|
|
||||||
for (;;) {
|
|
||||||
gpio_toggle(LED);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(BLINK_PERIOD_MS));
|
|
||||||
}
|
|
||||||
(void) args;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
uart_init(UART_DEBUG, 115200); // Initialise UART
|
|
||||||
|
|
||||||
// Start tasks. NOTE: stack sizes are in 32-bit words
|
|
||||||
xTaskCreate(blinker, "blinker", 128, ":)", configMAX_PRIORITIES - 1, NULL);
|
|
||||||
xTaskCreate(server, "server", 2048, 0, configMAX_PRIORITIES - 1, NULL);
|
|
||||||
|
|
||||||
vTaskStartScheduler(); // This blocks
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <errno.h> // we are not using lwIP
|
|
||||||
|
|
||||||
// See https://mongoose.ws/documentation/#build-options
|
|
||||||
#define MG_ARCH MG_ARCH_FREERTOS
|
|
||||||
|
|
||||||
#define MG_ENABLE_TCPIP 1
|
|
||||||
#define MG_ENABLE_DRIVER_IMXRT 1
|
|
||||||
#define MG_IO_SIZE 256
|
|
||||||
#define MG_ENABLE_CUSTOM_RANDOM 1
|
|
||||||
#define MG_ENABLE_PACKED_FS 1
|
|
||||||
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
// Copyright (c) 2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
//
|
|
||||||
// This file contains essentials required by the CMSIS:
|
|
||||||
// uint32_t SystemCoreClock - holds the system core clock value
|
|
||||||
// SystemInit() - initialises the system, e.g. sets up clocks
|
|
||||||
|
|
||||||
#include "hal.h"
|
|
||||||
|
|
||||||
uint32_t SystemCoreClock = SYS_FREQUENCY;
|
|
||||||
|
|
||||||
// - 14.4, Figure 14-2: clock tree
|
|
||||||
// - 14.7.4: ARM_PODF defaults to /1
|
|
||||||
// - 14.7.5: AHB_PODF defaults to /1; PERIPH_CLK_SEL defaults to derive clock
|
|
||||||
// from pre_periph_clk_sel
|
|
||||||
// - 14.7.6: PRE_PERIPH_CLK_SEL defaults to derive clock from PLL2 PFD3.
|
|
||||||
// - (For 528MHz operation, we need to set it to derive clock from PLL2, but
|
|
||||||
// this chip max is 500 MHz).
|
|
||||||
// - 14.6.1.3.1 System PLL (PLL2); 13.3.2.2 PLLs; 14.6.1.4 Phase Fractional
|
|
||||||
// Dividers (PFD)
|
|
||||||
// - 14.8.2: PLL2 is powered off and bypassed to 24MHz
|
|
||||||
// - 14.8.11: PFD defaults to 18/16 but Figure 14-2 shows half the value
|
|
||||||
// ("divider")
|
|
||||||
// - For 500MHz operation, we need to set PRE_PERIPH_CLK_SEL to derive clock
|
|
||||||
// from divided PLL6
|
|
||||||
// - 14.8.9: configure PLL6 to generate a 500MHz clock
|
|
||||||
// - Datasheet 4.1.3: System frequency/Bus frequency max 500/125MHz respectively
|
|
||||||
// (AHB/IPG)
|
|
||||||
// - MCUXpresso: IPG_CLK_ROOT <= 125MHz; PERCLK_CLK_ROOT <= 62.5MHz
|
|
||||||
// - Datasheet 4.8.4.1.1/2: the processor clock frequency must exceed twice the
|
|
||||||
// ENET_RX_CLK/ENET_TX_CLK frequency.
|
|
||||||
// - Datasheet 4.8.4.2: no details for RMII (above is for MII), assumed 50MHz
|
|
||||||
// min processor clock
|
|
||||||
// - Datasheet 4.1.3, Table 11: "Overdrive" run mode requires 1.25V core voltage
|
|
||||||
// minimum
|
|
||||||
void SystemInit(void) { // Called automatically by startup code (ints masked)
|
|
||||||
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU
|
|
||||||
asm("DSB");
|
|
||||||
asm("ISB");
|
|
||||||
// 53.4.2: Disable watchdog after reset (unlocked)
|
|
||||||
RTWDOG->CS &= ~RTWDOG_CS_EN_MASK;
|
|
||||||
RTWDOG->TOVAL = 0xFFFF;
|
|
||||||
while (RTWDOG->CS & RTWDOG_CS_ULK_MASK) spin(1); // wait for lock
|
|
||||||
while ((RTWDOG->CS & RTWDOG_CS_RCS_MASK) == 0)
|
|
||||||
spin(1); // wait for new config
|
|
||||||
// Set VDD_SOC to 1.25V
|
|
||||||
SETBITS(DCDC->REG3, DCDC_REG3_TRG_MASK, DCDC_REG3_TRG(0x12));
|
|
||||||
while ((DCDC->REG0 & DCDC_REG0_STS_DC_OK_MASK) == 0)
|
|
||||||
spin(1); // Wait for DCDC_STS_DC_OK
|
|
||||||
// 14.8.9 Init 500MHz reference, clock the M7 core with it, generate 50MHz for
|
|
||||||
// ENET and RMII.
|
|
||||||
SETBITS(CCM_ANALOG->PLL_ENET, CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC_MASK,
|
|
||||||
CCM_ANALOG_PLL_ENET_BYPASS_MASK |
|
|
||||||
CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC(0)); // bypass to 24MHz osc
|
|
||||||
SETBITS(
|
|
||||||
CCM_ANALOG->PLL_ENET,
|
|
||||||
CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK | CCM_ANALOG_PLL_ENET_POWERDOWN_MASK,
|
|
||||||
CCM_ANALOG_PLL_ENET_DIV_SELECT(1) | CCM_ANALOG_PLL_ENET_ENABLE_MASK |
|
|
||||||
CCM_ANALOG_PLL_ENET_ENET_500M_REF_EN_MASK); // setup PLL
|
|
||||||
while ((CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_LOCK_MASK) == 0)
|
|
||||||
spin(1); // wait until it is stable
|
|
||||||
CCM_ANALOG->PLL_ENET &=
|
|
||||||
~CCM_ANALOG_PLL_ENET_BYPASS_MASK; // Disable Bypass (switch to PLL)
|
|
||||||
SETBITS(CCM->CBCDR, CCM_CBCDR_IPG_PODF_MASK,
|
|
||||||
CCM_CBCDR_IPG_PODF(3)); // Set IPG divider /4 (125MHz)
|
|
||||||
SETBITS(CCM->CSCMR1, CCM_CSCMR1_PERCLK_PODF_MASK,
|
|
||||||
CCM_CSCMR1_PERCLK_PODF(1)); // Set PERCLK divider /2 (62.5MHz)
|
|
||||||
SETBITS(CCM->CBCMR, CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK,
|
|
||||||
CCM_CBCMR_PRE_PERIPH_CLK_SEL(3)); // run from 500MHz clock
|
|
||||||
// 14.5 Table 14-4: uart_clk_root
|
|
||||||
// 14.4: uart_clk_root = PLL3/6 or OSC; CCM_CSCDR1 (14.7.9) defaults to
|
|
||||||
// PLL3/6/1; but ROM boot code fiddles with the divider (9.5.3 Table 9-7)
|
|
||||||
CCM_ANALOG->PLL_USB1 |= CCM_ANALOG_PLL_USB1_POWER_MASK; // Power PLL on
|
|
||||||
while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0)
|
|
||||||
spin(1); // wait until it is stable
|
|
||||||
CCM_ANALOG->PLL_USB1 &=
|
|
||||||
~CCM_ANALOG_PLL_USB1_BYPASS_MASK; // Disable Bypass (switch to PLL)
|
|
||||||
CCM->CSCDR1 &= ~(CCM_CSCDR1_UART_CLK_SEL_MASK | CCM_CSCDR1_UART_CLK_PODF_MASK);
|
|
||||||
rng_init(); // Initialise random number generator
|
|
||||||
// NXP startup code calls SystemInit BEFORE initializing RAM...
|
|
||||||
SysTick_Config(SYS_FREQUENCY / 1000); // Sys tick every 1ms
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
CFLAGS = -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion
|
|
||||||
CFLAGS += -Wformat-truncation -fno-common # -Wconversion is not SDK-friendly
|
|
||||||
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
|
|
||||||
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include -Icmsis_mcu/devices/MIMXRT1062
|
|
||||||
CFLAGS += -Icmsis_mcu/devices/MIMXRT1062/drivers -DCPU_MIMXRT1062DVL6B
|
|
||||||
CFLAGS += -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16 $(CFLAGS_EXTRA)
|
|
||||||
LDSCRIPT = link.ld
|
|
||||||
LDFLAGS ?= -T$(LDSCRIPT) -nostdlib -nostartfiles --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
|
||||||
|
|
||||||
SOURCES = main.c syscalls.c sysinit.c
|
|
||||||
SOURCES += cmsis_mcu/devices/MIMXRT1062/gcc/startup_MIMXRT1062.S # NXP startup file. Compiler-dependent!
|
|
||||||
CFLAGS += -D__ATOLLIC__ -D__STARTUP_CLEAR_BSS # Make startup code work as expected
|
|
||||||
|
|
||||||
# Mongoose options are defined in mongoose_config.h
|
|
||||||
SOURCES += mongoose.c net.c packed_fs.c
|
|
||||||
|
|
||||||
# Example specific build options. See README.md
|
|
||||||
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\" -DHTTPS_URL=\"https://0.0.0.0/\"
|
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
|
||||||
RM = cmd /C del /Q /F /S
|
|
||||||
else
|
|
||||||
RM = rm -rf
|
|
||||||
endif
|
|
||||||
|
|
||||||
all build example update: SOURCES += flash_image.c
|
|
||||||
all build example: firmware.bin
|
|
||||||
|
|
||||||
ram: LDSCRIPT = link_ram.ld
|
|
||||||
ram: firmware.bin
|
|
||||||
|
|
||||||
firmware.bin: firmware.elf
|
|
||||||
arm-none-eabi-objcopy -O binary $< $@
|
|
||||||
|
|
||||||
firmware.elf: cmsis_core cmsis_mcu $(SOURCES) hal.h link_ram.ld link.ld Makefile
|
|
||||||
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@
|
|
||||||
arm-none-eabi-size $@
|
|
||||||
|
|
||||||
flash: firmware.bin
|
|
||||||
# flash
|
|
||||||
|
|
||||||
cmsis_core: # ARM CMSIS core headers
|
|
||||||
git clone -q --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
|
|
||||||
cmsis_mcu:
|
|
||||||
curl -sL https://mcuxpresso.nxp.com/cmsis_pack/repo/NXP.MIMXRT1062_DFP.17.1.0.pack -o $@.zip
|
|
||||||
mkdir $@ && cd $@ && unzip -q ../$@.zip
|
|
||||||
mbedtls: # mbedTLS library
|
|
||||||
git clone --depth 1 -b v2.28.2 https://github.com/mbed-tls/mbedtls $@
|
|
||||||
|
|
||||||
ifeq ($(TLS), mbedtls)
|
|
||||||
CFLAGS += -DMG_TLS=MG_TLS_MBED -Wno-conversion -Imbedtls/include
|
|
||||||
CFLAGS += -DMBEDTLS_CONFIG_FILE=\"mbedtls_config.h\" mbedtls/library/*.c
|
|
||||||
firmware.elf: mbedtls
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Automated remote test. Requires env variable VCON_API_KEY set. See https://vcon.io/automated-firmware-tests/
|
|
||||||
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/13
|
|
||||||
update: firmware.bin
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @$<
|
|
||||||
|
|
||||||
update updateram: CFLAGS += -DUART_DEBUG=LPUART3
|
|
||||||
|
|
||||||
test: update
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
|
|
||||||
grep 'READY, IP:' /tmp/output.txt # Check for network init
|
|
||||||
|
|
||||||
|
|
||||||
updateram: ram
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @firmware.bin
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"init"}'
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"wm,e000edf0,a05f0003 wm,e000edfc,1 wm,e000ed0c,5fa0004"}'
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"init"}'
|
|
||||||
PC=`curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"rm,4"}' | jq -r .resp[5:]` && \
|
|
||||||
SP=`curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"rm,0"}' | jq -r .resp[5:]` && \
|
|
||||||
REQ="wm,e000ed08,0 wr,d,$$SP wr,f,$$PC" && \
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"'"$$REQ"'"}'
|
|
||||||
curl -su :$(VCON_API_KEY) $(DEVICE_URL)/rpc/swd.exec -d '{"req":"wm,e000edf0,a05f0001"}'
|
|
||||||
|
|
||||||
testram: updateram
|
|
||||||
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
|
|
||||||
grep 'READY, IP:' /tmp/output.txt # Check for network init
|
|
||||||
|
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) firmware.* *.su cmsis_core cmsis_mcu mbedtls *.zip
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020-2021 NXP
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define __DCD_DATA \
|
|
||||||
0xD2, 0x04, 0x10, 0x41, 0xCC, 0x03, 0x8C, 0x04, 0x40, 0x0F, 0xC0, 0x68, \
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x6C, 0xFF, 0xFF, 0xFF, 0xFF, \
|
|
||||||
0x40, 0x0F, 0xC0, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x74, \
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x78, 0xFF, 0xFF, 0xFF, 0xFF, \
|
|
||||||
0x40, 0x0F, 0xC0, 0x7C, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x80, \
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0D, 0x80, 0x30, 0x00, 0x00, 0x20, 0x01, \
|
|
||||||
0x40, 0x0D, 0x81, 0x00, 0x10, 0x1D, 0x10, 0x1B, 0x40, 0x0F, 0xC0, 0x14, \
|
|
||||||
0x00, 0x01, 0x0D, 0x40, 0x40, 0x1F, 0x80, 0x14, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x18, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x1C, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x24, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x28, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x2C, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x34, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x38, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x40, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x44, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x48, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x4C, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x50, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x58, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x5C, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x64, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x68, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x70, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x74, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x78, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x7C, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x84, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x88, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x8C, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x90, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x94, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x98, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0xA0, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0xA4, 0x00, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x1F, 0x80, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0xAC, \
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0xB0, 0x00, 0x00, 0x00, 0x10, \
|
|
||||||
0x40, 0x1F, 0x82, 0x04, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x08, \
|
|
||||||
0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x0C, 0x00, 0x01, 0x10, 0xF9, \
|
|
||||||
0x40, 0x1F, 0x82, 0x10, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x14, \
|
|
||||||
0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x18, 0x00, 0x01, 0x10, 0xF9, \
|
|
||||||
0x40, 0x1F, 0x82, 0x1C, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x20, \
|
|
||||||
0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x24, 0x00, 0x01, 0x10, 0xF9, \
|
|
||||||
0x40, 0x1F, 0x82, 0x28, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x2C, \
|
|
||||||
0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x30, 0x00, 0x01, 0x10, 0xF9, \
|
|
||||||
0x40, 0x1F, 0x82, 0x34, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x38, \
|
|
||||||
0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x3C, 0x00, 0x01, 0x10, 0xF9, \
|
|
||||||
0x40, 0x1F, 0x82, 0x40, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x44, \
|
|
||||||
0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x48, 0x00, 0x01, 0x10, 0xF9, \
|
|
||||||
0x40, 0x1F, 0x82, 0x4C, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x50, \
|
|
||||||
0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x54, 0x00, 0x01, 0x10, 0xF9, \
|
|
||||||
0x40, 0x1F, 0x82, 0x58, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x5C, \
|
|
||||||
0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x60, 0x00, 0x01, 0x10, 0xF9, \
|
|
||||||
0x40, 0x1F, 0x82, 0x64, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x68, \
|
|
||||||
0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x6C, 0x00, 0x01, 0x10, 0xF9, \
|
|
||||||
0x40, 0x1F, 0x82, 0x70, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x74, \
|
|
||||||
0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x78, 0x00, 0x01, 0x10, 0xF9, \
|
|
||||||
0x40, 0x1F, 0x82, 0x7C, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x80, \
|
|
||||||
0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x84, 0x00, 0x01, 0x10, 0xF9, \
|
|
||||||
0x40, 0x1F, 0x82, 0x88, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x8C, \
|
|
||||||
0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x90, 0x00, 0x01, 0x10, 0xF9, \
|
|
||||||
0x40, 0x1F, 0x82, 0x94, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x98, \
|
|
||||||
0x00, 0x01, 0x10, 0xF9, 0x40, 0x1F, 0x82, 0x9C, 0x00, 0x01, 0x10, 0xF9, \
|
|
||||||
0x40, 0x1F, 0x82, 0xA0, 0x00, 0x01, 0x10, 0xF9, 0x40, 0x2F, 0x00, 0x00, \
|
|
||||||
0x10, 0x00, 0x00, 0x04, 0x40, 0x2F, 0x00, 0x08, 0x00, 0x00, 0x00, 0x81, \
|
|
||||||
0x40, 0x2F, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x81, 0x40, 0x2F, 0x00, 0x10, \
|
|
||||||
0x80, 0x00, 0x00, 0x1B, 0x40, 0x2F, 0x00, 0x14, 0x82, 0x00, 0x00, 0x1B, \
|
|
||||||
0x40, 0x2F, 0x00, 0x18, 0x84, 0x00, 0x00, 0x1B, 0x40, 0x2F, 0x00, 0x1C, \
|
|
||||||
0x86, 0x00, 0x00, 0x1B, 0x40, 0x2F, 0x00, 0x20, 0x90, 0x00, 0x00, 0x21, \
|
|
||||||
0x40, 0x2F, 0x00, 0x24, 0xA0, 0x00, 0x00, 0x19, 0x40, 0x2F, 0x00, 0x28, \
|
|
||||||
0xA8, 0x00, 0x00, 0x17, 0x40, 0x2F, 0x00, 0x2C, 0xA9, 0x00, 0x00, 0x1B, \
|
|
||||||
0x40, 0x2F, 0x00, 0x30, 0x00, 0x00, 0x00, 0x21, 0x40, 0x2F, 0x00, 0x04, \
|
|
||||||
0x00, 0x00, 0x79, 0xA8, 0x40, 0x2F, 0x00, 0x40, 0x00, 0x00, 0x0F, 0x31, \
|
|
||||||
0x40, 0x2F, 0x00, 0x44, 0x00, 0x65, 0x29, 0x22, 0x40, 0x2F, 0x00, 0x48, \
|
|
||||||
0x00, 0x01, 0x09, 0x20, 0x40, 0x2F, 0x00, 0x4C, 0x50, 0x21, 0x0A, 0x08, \
|
|
||||||
0x40, 0x2F, 0x00, 0x80, 0x00, 0x00, 0x00, 0x21, 0x40, 0x2F, 0x00, 0x84, \
|
|
||||||
0x00, 0x88, 0x88, 0x88, 0x40, 0x2F, 0x00, 0x94, 0x00, 0x00, 0x00, 0x02, \
|
|
||||||
0x40, 0x2F, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x90, \
|
|
||||||
0x80, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0F, \
|
|
||||||
0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, \
|
|
||||||
0xCC, 0x00, 0x14, 0x04, 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0C, 0xCF, 0x00, 0x0C, 0x1C, \
|
|
||||||
0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x14, 0x04, \
|
|
||||||
0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x9C, \
|
|
||||||
0xA5, 0x5A, 0x00, 0x0C, 0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, \
|
|
||||||
0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x1C, 0x04, 0x40, 0x2F, 0x00, 0xA0, \
|
|
||||||
0x00, 0x00, 0x00, 0x33, 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, \
|
|
||||||
0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0A, 0xCF, 0x00, 0x0C, 0x1C, \
|
|
||||||
0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x0C, 0x04, \
|
|
||||||
0x40, 0x2F, 0x00, 0x4C, 0x50, 0x21, 0x0A, 0x09
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
#include "dcd.h" // pin settings for MIMXRT1060-EVKB board
|
|
||||||
#include "fsl_flexspi.h" // peripheral structures
|
|
||||||
#include "fsl_romapi.h" // peripheral structures
|
|
||||||
#include "hal.h"
|
|
||||||
|
|
||||||
extern uint32_t __isr_vector[];
|
|
||||||
|
|
||||||
// RM 9.7.2
|
|
||||||
__attribute__((section(".dcd"), used))
|
|
||||||
const uint8_t __ivt_dcd_data[] = {__DCD_DATA};
|
|
||||||
|
|
||||||
// RM 9.7.1
|
|
||||||
__attribute__((section(".dat"), used)) const uint32_t __ivt_boot_data[] = {
|
|
||||||
FlexSPI_AMBA_BASE, // boot start location
|
|
||||||
8 * 1024 * 1024, // size
|
|
||||||
0, // Plugin flag
|
|
||||||
0Xffffffff // empty - extra data word
|
|
||||||
};
|
|
||||||
|
|
||||||
__attribute__((section(".ivt"), used)) const uint32_t __ivt[8] = {
|
|
||||||
0x412000d1, // header: 41 - version, 2000 size, d1 tag
|
|
||||||
(uint32_t) __isr_vector, // entry
|
|
||||||
0, // reserved
|
|
||||||
(uint32_t) __ivt_dcd_data, // dcd
|
|
||||||
(uint32_t) __ivt_boot_data, // boot data
|
|
||||||
(uint32_t) __ivt, // this is us - ivt absolute address
|
|
||||||
0, // csf absolute address
|
|
||||||
0, // reserved for HAB
|
|
||||||
};
|
|
||||||
|
|
||||||
#define __FLEXSPI_QSPI_LUT { \
|
|
||||||
[0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18), \
|
|
||||||
[1] = FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),\
|
|
||||||
[4 * 1 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x04),\
|
|
||||||
[4 * 3 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0x0),\
|
|
||||||
[4 * 5 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 0x18),\
|
|
||||||
[4 * 8 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xD8, RADDR_SDR, FLEXSPI_1PAD, 0x18),\
|
|
||||||
[4 * 9 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 0x18),\
|
|
||||||
[4 * 9 + 1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0x04, STOP, FLEXSPI_1PAD, 0x0),\
|
|
||||||
[4 * 11 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0x0),\
|
|
||||||
}
|
|
||||||
|
|
||||||
// MIMXRT1060-EVKB flash chip config: IS25WP064AJBLE
|
|
||||||
__attribute__((section(".cfg"), used))
|
|
||||||
const flexspi_nor_config_t __qspi_flash_cfg = {
|
|
||||||
.memConfig = {.tag = FLEXSPI_CFG_BLK_TAG,
|
|
||||||
.version = FLEXSPI_CFG_BLK_VERSION,
|
|
||||||
.readSampleClkSrc = 1, // ReadSampleClk_LoopbackFromDqsPad
|
|
||||||
.csHoldTime = 3,
|
|
||||||
.csSetupTime = 3,
|
|
||||||
.controllerMiscOption = BIT(4),
|
|
||||||
.deviceType = 1, // serial NOR
|
|
||||||
.sflashPadType = 4,
|
|
||||||
.serialClkFreq = 7, // 120MHz
|
|
||||||
.sflashA1Size = 8 * 1024 * 1024,
|
|
||||||
.lookupTable = __FLEXSPI_QSPI_LUT},
|
|
||||||
.pageSize = 256,
|
|
||||||
.sectorSize = 4 * 1024,
|
|
||||||
.ipcmdSerialClkFreq = 1,
|
|
||||||
.blockSize = 64 * 1024,
|
|
||||||
.isUniformBlockSize = false};
|
|
||||||
@@ -1,356 +0,0 @@
|
|||||||
// Copyright (c) 2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
// https://cache.nxp.com/secured/assets/documents/en/reference-manual/IMXRT1060XRM.pdf
|
|
||||||
// https://cache.nxp.com/secured/assets/documents/en/user-guide/MIMXRT1060EVKBUM.pdf
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "MIMXRT1062.h"
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define BIT(x) (1UL << (x))
|
|
||||||
#define SETBITS(R, CLEARMASK, SETMASK) (R) = ((R) & ~(CLEARMASK)) | (SETMASK)
|
|
||||||
#define PIN(bank, num) ((((bank) - '0') << 8) | (num))
|
|
||||||
#define PINNO(pin) (pin & 255)
|
|
||||||
#define PINBANK(pin) (pin >> 8)
|
|
||||||
|
|
||||||
// Use LED for blinking, D8: GPIO_AD_B0_08. GPIO1.8 (schematics, RM)
|
|
||||||
#define LED PIN('1', 8)
|
|
||||||
|
|
||||||
#ifndef UART_DEBUG
|
|
||||||
#define UART_DEBUG LPUART1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// No settable constants, see sysinit.c
|
|
||||||
#define SYS_FREQUENCY 600000000UL
|
|
||||||
|
|
||||||
static inline void spin(volatile uint32_t count) {
|
|
||||||
while (count--) (void) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum { CLOCK_OFF = 0U, CLOCK_ON_RUN = 1U, CLOCK_ON_RUN_WAIT = 3U };
|
|
||||||
static inline void clock_periph(uint32_t index, uint32_t shift, uint32_t val) {
|
|
||||||
volatile uint32_t *r = &CCM->CCGR0;
|
|
||||||
SETBITS(r[index], 3UL << shift, val << shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
// which peripheral feeds the pin
|
|
||||||
static inline void gpio_mux_config(uint16_t index, uint8_t af) {
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[index] = af;
|
|
||||||
}
|
|
||||||
|
|
||||||
// which pin feeds the peripheral (2nd stage)
|
|
||||||
static inline void periph_mux_config(uint16_t index, uint8_t in) {
|
|
||||||
IOMUXC->SELECT_INPUT[index] = in;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT };
|
|
||||||
enum { GPIO_OTYPE_PUSH_PULL, GPIO_OTYPE_OPEN_DRAIN };
|
|
||||||
enum { GPIO_SPEED_LOW, GPIO_SPEED_MEDIUM, GPIO_SPEED_MEDIUM_, GPIO_SPEED_HIGH };
|
|
||||||
enum { GPIO_PULL_NONE, GPIO_PULL_DOWN, GPIO_PULL_UP };
|
|
||||||
static inline GPIO_Type *gpio_bank(uint16_t pin) {
|
|
||||||
static const GPIO_Type *g[] = {NULL, GPIO1, GPIO2, GPIO3, NULL, GPIO5};
|
|
||||||
return (GPIO_Type *) g[PINBANK(pin)];
|
|
||||||
}
|
|
||||||
|
|
||||||
// pin driver/pull-up/down configuration (ignore "keeper")
|
|
||||||
static inline void gpio_pad_config(uint16_t index, uint8_t type, uint8_t speed,
|
|
||||||
uint8_t pull) {
|
|
||||||
bool dopull = pull > 0;
|
|
||||||
if (dopull) --pull;
|
|
||||||
IOMUXC->SW_PAD_CTL_PAD[index] =
|
|
||||||
IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_ODE(type) |
|
|
||||||
IOMUXC_SW_PAD_CTL_PAD_SRE(speed >= GPIO_SPEED_HIGH) |
|
|
||||||
IOMUXC_SW_PAD_CTL_PAD_PUE(1) | IOMUXC_SW_PAD_CTL_PAD_PKE(dopull) |
|
|
||||||
IOMUXC_SW_PAD_CTL_PAD_PUS(pull) | IOMUXC_SW_PAD_CTL_PAD_DSE(7);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
|
|
||||||
uint8_t speed, uint8_t pull) {
|
|
||||||
GPIO_Type *gpio = gpio_bank(pin);
|
|
||||||
uint8_t bit = (uint8_t) PINNO(pin);
|
|
||||||
uint32_t mask = (uint32_t) BIT(PINNO(pin));
|
|
||||||
|
|
||||||
clock_periph(4, CCM_CCGR4_CG1_SHIFT, CLOCK_ON_RUN_WAIT); // iomuxc_ipg_clk_s
|
|
||||||
switch (PINBANK(pin)) {
|
|
||||||
case 1:
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_00 + bit, 5);
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_00 + bit, type, speed,
|
|
||||||
pull);
|
|
||||||
clock_periph(1, CCM_CCGR1_CG13_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 + bit, 5);
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_B1_00 + bit, type, speed,
|
|
||||||
pull);
|
|
||||||
clock_periph(0, CCM_CCGR0_CG15_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
gpio_mux_config(bit < 12 ? kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_00 + bit
|
|
||||||
: bit < 18
|
|
||||||
? kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B0_00 + bit - 12
|
|
||||||
: kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_32 + bit - 18,
|
|
||||||
5);
|
|
||||||
gpio_pad_config(bit < 12 ? kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_00 + bit
|
|
||||||
: bit < 18
|
|
||||||
? kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_00 + bit - 12
|
|
||||||
: kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_32 + bit - 18,
|
|
||||||
type, speed, pull);
|
|
||||||
clock_periph(2, CCM_CCGR2_CG13_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
// TODO(): support sw_mux
|
|
||||||
clock_periph(1, CCM_CCGR1_CG15_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpio->IMR &= ~mask;
|
|
||||||
if (mode == GPIO_MODE_INPUT) {
|
|
||||||
gpio->GDIR &= ~mask;
|
|
||||||
} else {
|
|
||||||
gpio->GDIR |= mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static inline void gpio_input(uint16_t pin) {
|
|
||||||
gpio_init(pin, GPIO_MODE_INPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM,
|
|
||||||
GPIO_PULL_NONE);
|
|
||||||
}
|
|
||||||
static inline void gpio_output(uint16_t pin) {
|
|
||||||
gpio_init(pin, GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM,
|
|
||||||
GPIO_PULL_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool gpio_read(uint16_t pin) {
|
|
||||||
GPIO_Type *gpio = gpio_bank(pin);
|
|
||||||
uint32_t mask = (uint32_t) BIT(PINNO(pin));
|
|
||||||
return gpio->DR & mask;
|
|
||||||
}
|
|
||||||
static inline void gpio_write(uint16_t pin, bool value) {
|
|
||||||
GPIO_Type *gpio = gpio_bank(pin);
|
|
||||||
uint32_t mask = (uint32_t) BIT(PINNO(pin));
|
|
||||||
if (value) {
|
|
||||||
gpio->DR |= mask;
|
|
||||||
} else {
|
|
||||||
gpio->DR &= ~mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static inline void gpio_toggle(uint16_t pin) {
|
|
||||||
gpio_write(pin, !gpio_read(pin));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 14.5 Table 14-4: uart_clk_root
|
|
||||||
// see sysinit.c for clocks, (14.7.9: defaults to pll3_80m = PLL3/6/1 = 80MHz)
|
|
||||||
static inline void uart_init(LPUART_Type *uart, unsigned long baud) {
|
|
||||||
uint8_t af = 2; // Alternate function
|
|
||||||
uint16_t mr = 0, pr = 0, mt = 0, pt = 0; // pins
|
|
||||||
uint32_t freq = 80000000; // uart_clk_root frequency
|
|
||||||
if (uart == LPUART1)
|
|
||||||
mt = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_12,
|
|
||||||
pt = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_12,
|
|
||||||
mr = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_13,
|
|
||||||
pr = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_13;
|
|
||||||
if (uart == LPUART3)
|
|
||||||
mt = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_06,
|
|
||||||
pt = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_06,
|
|
||||||
mr = kIOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_07,
|
|
||||||
pr = kIOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_07;
|
|
||||||
|
|
||||||
if (uart == LPUART1) clock_periph(5, CCM_CCGR5_CG12_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
if (uart == LPUART3) clock_periph(0, CCM_CCGR0_CG6_SHIFT, CLOCK_ON_RUN_WAIT);
|
|
||||||
clock_periph(4, CCM_CCGR4_CG1_SHIFT, CLOCK_ON_RUN_WAIT); // iomuxc_ipg_clk_s
|
|
||||||
gpio_mux_config(mt, af);
|
|
||||||
gpio_pad_config(pt, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(mr, af);
|
|
||||||
gpio_pad_config(pr, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
|
|
||||||
|
|
||||||
uart->GLOBAL |= LPUART_GLOBAL_RST_MASK; // reset, CTRL = 0, defaults
|
|
||||||
uart->GLOBAL &= ~LPUART_GLOBAL_RST_MASK;
|
|
||||||
SETBITS(uart->BAUD,
|
|
||||||
LPUART_BAUD_OSR_MASK | LPUART_BAUD_SBR_MASK | LPUART_BAUD_SBNS_MASK,
|
|
||||||
LPUART_BAUD_OSR(16 - 1) |
|
|
||||||
LPUART_BAUD_SBR(freq / (16 * baud))); // Rx sample at 16x
|
|
||||||
SETBITS(uart->CTRL,
|
|
||||||
LPUART_CTRL_PE_MASK | LPUART_CTRL_M_MASK | LPUART_CTRL_ILT_MASK |
|
|
||||||
LPUART_CTRL_IDLECFG_MASK,
|
|
||||||
LPUART_CTRL_IDLECFG(1) | LPUART_CTRL_ILT(1) |
|
|
||||||
LPUART_BAUD_SBNS(0)); // no parity, idle 2 chars after 1 stop bit
|
|
||||||
uart->CTRL |= LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void uart_write_byte(LPUART_Type *uart, uint8_t byte) {
|
|
||||||
uart->DATA = byte;
|
|
||||||
while ((uart->STAT & LPUART_STAT_TDRE_MASK) == 0) spin(1);
|
|
||||||
}
|
|
||||||
static inline void uart_write_buf(LPUART_Type *uart, char *buf, size_t len) {
|
|
||||||
while (len-- > 0) uart_write_byte(uart, *(uint8_t *) buf++);
|
|
||||||
}
|
|
||||||
static inline int uart_read_ready(LPUART_Type *uart) {
|
|
||||||
(void) uart;
|
|
||||||
return uart->STAT & LPUART_STAT_RDRF_MASK;
|
|
||||||
}
|
|
||||||
static inline uint8_t uart_read_byte(LPUART_Type *uart) {
|
|
||||||
return (uint8_t) (uart->DATA & 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void rng_init(void) {
|
|
||||||
clock_periph(6, CCM_CCGR6_CG6_SHIFT, CLOCK_ON_RUN_WAIT); // trng_clk
|
|
||||||
SETBITS(TRNG->MCTL,
|
|
||||||
TRNG_MCTL_PRGM_MASK | TRNG_MCTL_ERR_MASK | TRNG_MCTL_RST_DEF_MASK,
|
|
||||||
TRNG_MCTL_PRGM(1) | TRNG_MCTL_ERR(1) |
|
|
||||||
TRNG_MCTL_RST_DEF(1)); // reset to default values
|
|
||||||
SETBITS(TRNG->MCTL, TRNG_MCTL_PRGM_MASK | TRNG_MCTL_ERR_MASK,
|
|
||||||
TRNG_MCTL_PRGM(0)); // set to run mode
|
|
||||||
(void) TRNG->ENT[TRNG_ENT_COUNT - 1]; // start new entropy generation
|
|
||||||
(void) TRNG->ENT[0]; // defect workaround
|
|
||||||
}
|
|
||||||
static inline uint32_t rng_read(void) {
|
|
||||||
static uint8_t idx = 0;
|
|
||||||
while ((TRNG->MCTL & TRNG_MCTL_ENT_VAL_MASK) == 0) (void) 0;
|
|
||||||
uint32_t data = TRNG->ENT[idx++]; // read data
|
|
||||||
idx %= TRNG_ENT_COUNT; // stay within array limits
|
|
||||||
if (idx == 0) // we've just read TRNG_ENT_COUNT - 1
|
|
||||||
(void) TRNG->ENT[0]; // defect workaround
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - PHY has no xtal, XI driven from ENET_REF_CLK1 (labeled as ENET_TX_REF_CLK
|
|
||||||
// (GPIO_AD_B1_10)), generated by the MCU
|
|
||||||
// - PHY RST connected to GPIO1.9 (GPIO_AD_B0_09); INTRP/NAND_TREE connected to
|
|
||||||
// GPIO1.10 (GPIO_AD_B0_10)
|
|
||||||
// - 41.4 REF_CLK1 is RMII mode reference clock for Rx, Tx, and SMI; it is I/O
|
|
||||||
// - 11.3.2 IOMUXC_GPR_GPR1
|
|
||||||
// - bit 13: ENET1_CLK_SEL --> 0 ENET1 TX reference clock driven by
|
|
||||||
// ref_enetpll and output via ENET_REF_CLK1 (labeled as ENET_REF_CLK
|
|
||||||
// elsewhere)
|
|
||||||
// - bit 17: ENET1_TX_CLK_DIR --> 1 ENET1_TX_CLK output driver enabled
|
|
||||||
// - 14.6.1.3.6 Ethernet PLL (PLL6)
|
|
||||||
// - 14.8.14: configure PLL6 to generate 50MHz clocks for ENET and RMII.
|
|
||||||
static inline void ethernet_init(void) {
|
|
||||||
// setup PLL and clock ENET from it
|
|
||||||
SETBITS(CCM_ANALOG->PLL_ENET, CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC_MASK,
|
|
||||||
CCM_ANALOG_PLL_ENET_BYPASS_MASK |
|
|
||||||
CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC(0)); // bypass to 24MHz osc
|
|
||||||
SETBITS(
|
|
||||||
CCM_ANALOG->PLL_ENET,
|
|
||||||
CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK | CCM_ANALOG_PLL_ENET_POWERDOWN_MASK,
|
|
||||||
CCM_ANALOG_PLL_ENET_DIV_SELECT(1) | CCM_ANALOG_PLL_ENET_ENABLE_MASK);
|
|
||||||
while ((CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_LOCK_MASK) == 0)
|
|
||||||
spin(1); // wait until it is stable
|
|
||||||
CCM_ANALOG->PLL_ENET &= ~CCM_ANALOG_PLL_ENET_BYPASS_MASK;
|
|
||||||
|
|
||||||
gpio_init(PIN('1', 9), GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_MEDIUM, GPIO_PULL_UP); // set GPIO1.9 as GPIO (PHY \RST)
|
|
||||||
gpio_write(PIN('1', 9), 0); // reset PHY
|
|
||||||
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_B1_10,
|
|
||||||
6); // set for ENET_REF_CLK
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_B1_10] |=
|
|
||||||
IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_ENET_IPG_CLK_RMII_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B1_10, so RMII clock is taken
|
|
||||||
// from ENET_REF_CLK
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_B1_10, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
IOMUXC_GPR->GPR1 |=
|
|
||||||
IOMUXC_GPR_GPR1_ENET1_TX_CLK_DIR(1); // Set ENET_TX_CLK as output
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_B1_04, 3); // set for RXDATA0
|
|
||||||
periph_mux_config(kIOMUXC_ENET0_RXDATA_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B1_04
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_B1_04, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_B1_05, 3); // set for RXDATA1
|
|
||||||
periph_mux_config(kIOMUXC_ENET1_RXDATA_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B1_05
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_B1_05, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_B1_06, 3); // set for CRS
|
|
||||||
periph_mux_config(kIOMUXC_ENET_RXEN_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B1_06
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_B1_06, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_B1_07, 3); // set for TXDATA0
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_B1_07, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_B1_08, 3); // set for TXDATA1
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_B1_08, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_B1_09, 3); // set for TXEN
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_B1_09, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_B1_11, 3); // set for RXERR
|
|
||||||
periph_mux_config(kIOMUXC_ENET_RXERR_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from B0_12
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_B1_11, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_HIGH, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_40, 4); // set for MDC
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_40, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_41, 4); // set for MDIO
|
|
||||||
periph_mux_config(kIOMUXC_ENET_MDIO_SELECT_INPUT,
|
|
||||||
1); // drive peripheral from EMC_41
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_41, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_MEDIUM, GPIO_PULL_UP);
|
|
||||||
|
|
||||||
gpio_init(PIN('1', 10), GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL,
|
|
||||||
GPIO_SPEED_MEDIUM,
|
|
||||||
GPIO_PULL_UP); // set GPIO1.10 as GPIO (PHY INTRP/NAND_TREE)
|
|
||||||
gpio_write(PIN('1', 10), 1); // prevent NAND_TREE
|
|
||||||
spin(10000); // keep PHY RST low for a while
|
|
||||||
gpio_write(PIN('1', 9), 1); // deassert RST
|
|
||||||
gpio_init(PIN('1', 10), GPIO_MODE_INPUT, 0, GPIO_SPEED_MEDIUM,
|
|
||||||
GPIO_PULL_UP); // setup IRQ (pulled-up)(not used)
|
|
||||||
|
|
||||||
clock_periph(1, CCM_CCGR1_CG5_SHIFT, CLOCK_ON_RUN_WAIT); // enet_ipg_clk
|
|
||||||
NVIC_EnableIRQ(ENET_IRQn); // Setup Ethernet IRQ handler
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper macro for MAC generation, byte reads not allowed
|
|
||||||
#define GENERATE_LOCALLY_ADMINISTERED_MAC() \
|
|
||||||
{ \
|
|
||||||
2, OCOTP->CFG0 & 255, (OCOTP->CFG0 >> 10) & 255, \
|
|
||||||
((OCOTP->CFG0 >> 19) ^ (OCOTP->CFG1 >> 19)) & 255, \
|
|
||||||
(OCOTP->CFG1 >> 10) & 255, OCOTP->CFG1 & 255 \
|
|
||||||
}
|
|
||||||
// NOTE: You can fuse your own MAC and read it from OCOTP->MAC0, OCOTP->MAC1,
|
|
||||||
// OCOTP->MAC2
|
|
||||||
|
|
||||||
static inline void flash_init(void) { // QSPI in FlexSPI
|
|
||||||
// set pins
|
|
||||||
clock_periph(4, CCM_CCGR4_CG1_SHIFT, CLOCK_ON_RUN_WAIT); // iomuxc_ipg_clk_s
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_05, 1); // set for DQS
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_05] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPIA_DQS_SELECT_INPUT, 0); // drive peripheral from B1_05
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_05, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_06, 1); // set for SS
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_06] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_06, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_07, 1); // set for SCLK
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_07] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPIA_SCK_SELECT_INPUT, 0); // drive peripheral from B1_07
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_07, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_08, 1); // set for DATA0
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_08] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPIA_DATA0_SELECT_INPUT, 0); // drive peripheral from B1_08
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_08, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_09, 1); // set for DATA1
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_09] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPIA_DATA1_SELECT_INPUT, 0); // drive peripheral from B1_09
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_09, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_10, 1); // set for DATA2
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_10] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPIA_DATA2_SELECT_INPUT, 0); // drive peripheral from B1_10
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_10, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
gpio_mux_config(kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_11, 1); // set for DATA3
|
|
||||||
IOMUXC->SW_MUX_CTL_PAD[kIOMUXC_SW_MUX_CTL_PAD_GPIO_SD_B1_11] |= IOMUXC_SW_MUX_CTL_PAD_SION(1); // loop signal back from pin
|
|
||||||
periph_mux_config(kIOMUXC_FLEXSPIA_DATA3_SELECT_INPUT, 0); // drive peripheral from B1_11
|
|
||||||
gpio_pad_config(kIOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B1_11, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, GPIO_PULL_NONE);
|
|
||||||
// set FlexSPI clock
|
|
||||||
SETBITS(CCM->CSCMR1, CCM_CSCMR1_FLEXSPI_CLK_SEL_MASK | CCM_CSCMR1_FLEXSPI_PODF_MASK, CCM_CSCMR1_FLEXSPI_CLK_SEL(3) | CCM_CSCMR1_FLEXSPI_PODF(7)); // select PLL3 PFD0 /8
|
|
||||||
clock_periph(6, CCM_CCGR6_CG5_SHIFT, CLOCK_ON_RUN_WAIT); // enable
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
ENTRY(Reset_Handler);
|
|
||||||
MEMORY {
|
|
||||||
flash_hdr(rx) : ORIGIN = 0x60000000, LENGTH = 8k
|
|
||||||
flash_irq(rx) : ORIGIN = 0x60002000, LENGTH = 1k
|
|
||||||
flash_code(rx) : ORIGIN = 0x60002400, LENGTH = 8183k
|
|
||||||
|
|
||||||
itcram(rx) : ORIGIN = 0x00000000, LENGTH = 128k
|
|
||||||
dtcram(rw) : ORIGIN = 0x20000000, LENGTH = 128k
|
|
||||||
ocram(rw) : ORIGIN = 0x20200000, LENGTH = 256k /* Is this cached ? */
|
|
||||||
}
|
|
||||||
__StackTop = ORIGIN(dtcram) + LENGTH(dtcram);
|
|
||||||
|
|
||||||
/* TODO(): separate itcram and go back to using dtcram for data and bss when ota is finished */
|
|
||||||
|
|
||||||
SECTIONS {
|
|
||||||
.hdr : { FILL(0xff) ; KEEP(*(.cfg)) . = 0x1000 ; KEEP(*(.ivt)) . = 0x1020 ;
|
|
||||||
KEEP(*(.dat)) . = 0x1030 ; KEEP(*(.dcd)) . = 0x2000 ;} >flash_hdr
|
|
||||||
.irq : { KEEP(*(.isr_vector)) } > flash_irq
|
|
||||||
.text : { *(.text* .text.*) *(.rodata*) ; } > flash_code
|
|
||||||
.data : { __data_start__ = .; *(.data SORT(.data.*)) *(.iram) __data_end__ = .; } > itcram AT > flash_code
|
|
||||||
__etext = LOADADDR(.data);
|
|
||||||
.bss : { __bss_start__ = .; *(.bss SORT(.bss.*) COMMON) __bss_end__ = .; } > itcram
|
|
||||||
_end = .;
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
// Copyright (c) 2022-2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
|
|
||||||
#include "hal.h"
|
|
||||||
#include "mongoose.h"
|
|
||||||
#include "net.h"
|
|
||||||
|
|
||||||
#define BLINK_PERIOD_MS 1000 // LED blinking period in millis
|
|
||||||
|
|
||||||
static volatile uint64_t s_ticks; // Milliseconds since boot
|
|
||||||
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
|
|
||||||
s_ticks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t mg_millis(void) { // Let Mongoose use our uptime function
|
|
||||||
return s_ticks; // Return number of milliseconds since boot
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_random(void *buf, size_t len) { // Use on-board RNG
|
|
||||||
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
|
|
||||||
uint32_t r = rng_read();
|
|
||||||
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static void timer_fn(void *arg) {
|
|
||||||
gpio_toggle(LED); // Blink LED
|
|
||||||
struct mg_tcpip_if *ifp = arg; // And show
|
|
||||||
const char *names[] = {"down", "up", "req", "ready"}; // network stats
|
|
||||||
MG_INFO(("Ethernet: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u",
|
|
||||||
names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent,
|
|
||||||
ifp->ndrop, ifp->nerr));
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
gpio_output(LED); // Setup blue LED
|
|
||||||
uart_init(UART_DEBUG, 115200); // Initialise debug printf
|
|
||||||
ethernet_init(); // Initialise ethernet pins
|
|
||||||
MG_INFO(("Starting, CPU freq %g MHz", (double) SystemCoreClock / 1000000));
|
|
||||||
|
|
||||||
struct mg_mgr mgr; // Initialise
|
|
||||||
mg_mgr_init(&mgr); // Mongoose event manager
|
|
||||||
mg_log_set(MG_LL_DEBUG); // Set log level
|
|
||||||
|
|
||||||
// Initialise Mongoose network stack
|
|
||||||
struct mg_tcpip_driver_imxrt_data driver_data = {.mdc_cr = 24, .phy_addr = 2};
|
|
||||||
struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(),
|
|
||||||
// Uncomment below for static configuration:
|
|
||||||
// .ip = mg_htonl(MG_U32(192, 168, 0, 223)),
|
|
||||||
// .mask = mg_htonl(MG_U32(255, 255, 255, 0)),
|
|
||||||
// .gw = mg_htonl(MG_U32(192, 168, 0, 1)),
|
|
||||||
.driver = &mg_tcpip_driver_imxrt,
|
|
||||||
.driver_data = &driver_data};
|
|
||||||
mg_tcpip_init(&mgr, &mif);
|
|
||||||
mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_fn, &mif);
|
|
||||||
|
|
||||||
MG_INFO(("MAC: %M. Waiting for IP...", mg_print_mac, mif.mac));
|
|
||||||
while (mif.state != MG_TCPIP_STATE_READY) {
|
|
||||||
mg_mgr_poll(&mgr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
MG_INFO(("Initialising application..."));
|
|
||||||
web_init(&mgr);
|
|
||||||
|
|
||||||
MG_INFO(("Starting event loop"));
|
|
||||||
for (;;) {
|
|
||||||
mg_mgr_poll(&mgr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// See https://mongoose.ws/documentation/#build-options
|
|
||||||
#define MG_ARCH MG_ARCH_NEWLIB
|
|
||||||
#define MG_OTA MG_OTA_FLASH
|
|
||||||
#define MG_DEVICE MG_DEVICE_RT1060
|
|
||||||
|
|
||||||
#define MG_ENABLE_TCPIP 1
|
|
||||||
#define MG_ENABLE_DRIVER_IMXRT 1
|
|
||||||
#define MG_IO_SIZE 256
|
|
||||||
#define MG_ENABLE_CUSTOM_MILLIS 1
|
|
||||||
#define MG_ENABLE_CUSTOM_RANDOM 1
|
|
||||||
#define MG_ENABLE_PACKED_FS 1
|
|
||||||
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
// Copyright (c) 2023 Cesanta Software Limited
|
|
||||||
// All rights reserved
|
|
||||||
//
|
|
||||||
// This file contains essentials required by the CMSIS:
|
|
||||||
// uint32_t SystemCoreClock - holds the system core clock value
|
|
||||||
// SystemInit() - initialises the system, e.g. sets up clocks
|
|
||||||
|
|
||||||
#include "hal.h"
|
|
||||||
|
|
||||||
uint32_t SystemCoreClock = SYS_FREQUENCY;
|
|
||||||
|
|
||||||
// - 14.4, Figure 14-2: clock tree
|
|
||||||
// - 14.7.4: ARM_PODF defaults to /2; 9.5.3 Table 9-7: ROM agrees
|
|
||||||
// - 14.7.5: AHB_PODF defaults to /1; IPG_PODF defaults to /4; PERIPH_CLK_SEL
|
|
||||||
// defaults to derive clock from pre_periph_clk_sel
|
|
||||||
// - 9.5.3 Table 9-7: ROM changes IPG_PODF to /3
|
|
||||||
// - 14.7.6: PRE_PERIPH_CLK_SEL defaults to derive clock from divided
|
|
||||||
// PLL1; 9.5.3 Table 9-7: ROM agrees
|
|
||||||
// - (For 528MHz operation, we need to set it to derive clock from PLL2)
|
|
||||||
// - 14.7.7: PER_CLK defaults to IPG/1; 9.5.3 Table 9-7: ROM changes it to IPG/2
|
|
||||||
// - 14.6.1.3.1 ARM PLL (PLL1); 13.3.2.2 PLLs
|
|
||||||
// - 14.8.1: PLL1 is powered off and bypassed to 24MHz. Fout = 24MHz *
|
|
||||||
// div_select/2
|
|
||||||
// - 9.5.3 Table 9-7: ROM enables this PLL and sets it up
|
|
||||||
// - For 600MHz operation, we need to set PLL1 on
|
|
||||||
// - Datasheet 4.1.3: System frequency/Bus frequency max 600/150MHz respectively
|
|
||||||
// (AHB/IPG)
|
|
||||||
// - MCUXpresso: IPG_CLK_ROOT <= 150MHz; PERCLK_CLK_ROOT <= 75MHz
|
|
||||||
// - Datasheet 4.9.4.1.1/2: the processor clock frequency must exceed twice the
|
|
||||||
// ENET_RX_CLK/ENET_TX_CLK frequency.
|
|
||||||
// - Datasheet 4.9.4.2: no details for RMII (above is for MII), assumed 50MHz
|
|
||||||
// min processor clock
|
|
||||||
// - Datasheet 4.1.3, Table 10: "Overdrive" run mode requires 1.25V core voltage
|
|
||||||
// minimum; 528 MHz does not.
|
|
||||||
void SystemInit(void) { // Called automatically by startup code (ints masked)
|
|
||||||
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU
|
|
||||||
asm("DSB");
|
|
||||||
asm("ISB");
|
|
||||||
// 58.4.2: Disable watchdog after reset (unlocked)
|
|
||||||
RTWDOG->CS &= ~RTWDOG_CS_EN_MASK;
|
|
||||||
RTWDOG->TOVAL = 0xFFFF;
|
|
||||||
while (RTWDOG->CS & RTWDOG_CS_ULK_MASK) spin(1); // wait for lock
|
|
||||||
while ((RTWDOG->CS & RTWDOG_CS_RCS_MASK) == 0)
|
|
||||||
spin(1); // wait for new config
|
|
||||||
// Set VDD_SOC to 1.25V
|
|
||||||
SETBITS(DCDC->REG3, DCDC_REG3_TRG_MASK, DCDC_REG3_TRG(0x12));
|
|
||||||
while ((DCDC->REG0 & DCDC_REG0_STS_DC_OK_MASK) == 0)
|
|
||||||
spin(1); // Wait for DCDC_STS_DC_OK
|
|
||||||
// ROM fiddles with AHB divider, wait and then keep bits at 0 (expected)
|
|
||||||
while (CCM->CDHIPR & CCM_CDHIPR_AHB_PODF_BUSY_MASK) spin(1);
|
|
||||||
SETBITS(CCM->CBCDR, CCM_CBCDR_IPG_PODF_MASK | CCM_CBCDR_AHB_PODF_MASK,
|
|
||||||
CCM_CBCDR_IPG_PODF(3)); // keep AHB, set IPG divider /4 (150MHz)
|
|
||||||
SETBITS(CCM->CSCMR1, CCM_CSCMR1_PERCLK_PODF_MASK,
|
|
||||||
CCM_CSCMR1_PERCLK_PODF(1)); // Set PERCLK divider /2 (75MHz)
|
|
||||||
// Set clock to 600 MHz. Power PLL on and configure divider (ROM boot code
|
|
||||||
// fiddles with the PLL, bypass first)
|
|
||||||
CCM_ANALOG->PLL_ARM |= CCM_ANALOG_PLL_ARM_BYPASS_MASK;
|
|
||||||
SETBITS(CCM_ANALOG->PLL_ARM,
|
|
||||||
CCM_ANALOG_PLL_ARM_POWERDOWN_MASK |
|
|
||||||
CCM_ANALOG_PLL_ARM_SET_DIV_SELECT_MASK,
|
|
||||||
CCM_ANALOG_PLL_ARM_SET_DIV_SELECT(100));
|
|
||||||
while ((CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_LOCK_MASK) == 0)
|
|
||||||
spin(1); // wait until it is stable
|
|
||||||
CCM_ANALOG->PLL_ARM &=
|
|
||||||
~CCM_ANALOG_PLL_ARM_BYPASS_MASK; // Disable Bypass (switch to PLL)
|
|
||||||
// 14.5 Table 14-4: uart_clk_root
|
|
||||||
// 14.4: uart_clk_root = PLL3/6 or OSC; CCM_CSCDR1 (14.7.9) defaults to
|
|
||||||
// PLL3/6/1; but ROM boot code fiddles with the divider (9.5.3 Table 9-7)
|
|
||||||
CCM_ANALOG->PLL_USB1 |= CCM_ANALOG_PLL_USB1_POWER_MASK; // Power PLL on
|
|
||||||
while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0)
|
|
||||||
spin(1); // wait until it is stable
|
|
||||||
CCM_ANALOG->PLL_USB1 &=
|
|
||||||
~CCM_ANALOG_PLL_USB1_BYPASS_MASK; // Disable Bypass (switch to PLL)
|
|
||||||
CCM->CSCDR1 &=
|
|
||||||
~(CCM_CSCDR1_UART_CLK_SEL_MASK | CCM_CSCDR1_UART_CLK_PODF_MASK);
|
|
||||||
rng_init(); // Initialise random number generator
|
|
||||||
// NXP startup code calls SystemInit BEFORE initializing RAM...
|
|
||||||
SysTick_Config(SYS_FREQUENCY / 1000); // Sys tick every 1ms
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "hal.h"
|
|
||||||
|
|
||||||
#define configUSE_PREEMPTION 1
|
|
||||||
#define configCPU_CLOCK_HZ SYS_FREQUENCY
|
|
||||||
#define configTICK_RATE_HZ 1000
|
|
||||||
#define configMAX_PRIORITIES 5
|
|
||||||
#define configUSE_16_BIT_TICKS 0
|
|
||||||
#define configUSE_TICK_HOOK 0
|
|
||||||
#define configUSE_IDLE_HOOK 0
|
|
||||||
#define configUSE_TIMERS 0
|
|
||||||
#define configUSE_CO_ROUTINES 0
|
|
||||||
#define configUSE_MALLOC_FAILED_HOOK 0
|
|
||||||
#define configMINIMAL_STACK_SIZE 128
|
|
||||||
#define configTOTAL_HEAP_SIZE (1024 * 32)
|
|
||||||
#define INCLUDE_vTaskDelay 1
|
|
||||||
#define INCLUDE_xTaskGetSchedulerState 1 // trying
|
|
||||||
|
|
||||||
#ifdef __NVIC_PRIO_BITS
|
|
||||||
#define configPRIO_BITS __NVIC_PRIO_BITS
|
|
||||||
#else
|
|
||||||
#define configPRIO_BITS 4
|
|
||||||
#endif
|
|
||||||
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
|
|
||||||
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
|
|
||||||
#define configKERNEL_INTERRUPT_PRIORITY \
|
|
||||||
(configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
|
|
||||||
|
|
||||||
#define configMAX_SYSCALL_INTERRUPT_PRIORITY \
|
|
||||||
(configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
|
|
||||||
|
|
||||||
#define configASSERT(expr) \
|
|
||||||
if (!(expr)) printf("FAILURE %s:%d: %s\n", __FILE__, __LINE__, #expr)
|
|
||||||
|
|
||||||
#define vPortSVCHandler SVC_Handler
|
|
||||||
#define xPortPendSVHandler PendSV_Handler
|
|
||||||
//#define xPortSysTickHandler SysTick_Handler
|
|
||||||
Loaded 100 of 5150 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user