mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-26 12:14:56 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4236405b90 | ||
|
|
292c66e25c | ||
|
|
5aa6c15c76 | ||
|
|
1f89dc47cb | ||
|
|
31393128c8 | ||
|
|
232a18425a | ||
|
|
88e2eb2a49 | ||
|
|
e635d5f748 | ||
|
|
08a23cdb2f | ||
|
|
1ead940623 | ||
|
|
987f8bc949 | ||
|
|
6f096333d3 | ||
|
|
5a25111b20 | ||
|
|
c7cb16cafa | ||
|
|
a746a698b6 | ||
|
|
9a7f7255ff | ||
|
|
d3df6b8f4f | ||
|
|
fcffd17b11 | ||
|
|
7fc6be9f39 | ||
|
|
7362744ff8 | ||
|
|
f4d058155a | ||
|
|
b04612e80d | ||
|
|
5f00e4d34d | ||
|
|
e967feb091 | ||
|
|
0445b18bb9 | ||
|
|
99f1f749cf | ||
|
|
f4d16f1c47 | ||
|
|
68071d6caf | ||
|
|
44975da7db | ||
|
|
e4566518b2 | ||
|
|
c038cb5b96 | ||
|
|
d7eb3db60b | ||
|
|
44e781d7da | ||
|
|
0951d58c8f | ||
|
|
37c0ed0b49 | ||
|
|
556bf7b888 | ||
|
|
280be2eaea | ||
|
|
13f9357f8e | ||
|
|
56e015db0e | ||
|
|
1068fbf079 | ||
|
|
45f7afb3e1 | ||
|
|
0d3fc2b656 | ||
|
|
2dc66b2e3b | ||
|
|
0b9129d8f5 | ||
|
|
82d702fedc | ||
|
|
197be75677 | ||
|
|
3f9aff1b10 | ||
|
|
f5ed50fa88 | ||
|
|
645b52602f | ||
|
|
27a8e60e9a | ||
|
|
201ffa108b | ||
|
|
1661bd6691 | ||
|
|
d431f4bbc5 | ||
|
|
2b8e92a70d | ||
|
|
d70ab3cfa8 | ||
|
|
9402c6ad28 | ||
|
|
da5e8e9778 | ||
|
|
feedfdf810 | ||
|
|
6db0a502bf | ||
|
|
f07957d45e | ||
|
|
3d75d71767 | ||
|
|
b259bdeddd | ||
|
|
042465387f | ||
|
|
d09e4d648c | ||
|
|
754910ad5f | ||
|
|
977e080215 | ||
|
|
a9ac947c96 | ||
|
|
28e6ef1d63 | ||
|
|
b0f273157d | ||
|
|
49add531c4 | ||
|
|
8a1d2a5dca | ||
|
|
31c5883f5f | ||
|
|
c625fbb43d | ||
|
|
0f474e8d2a | ||
|
|
73813a8383 | ||
|
|
d8fb110b56 | ||
|
|
77e62626a9 | ||
|
|
24ee83f13d | ||
|
|
6791a36d85 | ||
|
|
c6a5a64e64 | ||
|
|
311062dc41 | ||
|
|
391ce1f009 | ||
|
|
9f6d99352a | ||
|
|
02b1d6260a | ||
|
|
e8ade14259 | ||
|
|
f0804dfed4 | ||
|
|
f506344ada | ||
|
|
ddca518cca | ||
|
|
21d3678fa7 | ||
|
|
3dd8d7d8e5 | ||
|
|
92aa538a84 | ||
|
|
557a5583e8 | ||
|
|
b00ddff7dd | ||
|
|
cc3b311ab0 | ||
|
|
6cedca5d76 | ||
|
|
d82452e00f | ||
|
|
57a5c0ba38 | ||
|
|
28c8519e5b | ||
|
|
cfcb7191ea | ||
|
|
6921227ec8 | ||
|
|
1c9991ee83 | ||
|
|
fd475fcfff | ||
|
|
f47f995e90 | ||
|
|
d93e943326 | ||
|
|
7ca9f2d5cd | ||
|
|
ff1d45a008 | ||
|
|
53f0a72362 | ||
|
|
3a47242219 | ||
|
|
5556568feb | ||
|
|
6011a15cd4 | ||
|
|
2c014778d9 | ||
|
|
0b2712f52f | ||
|
|
69f1acd823 | ||
|
|
c0f15d50d6 | ||
|
|
1d3fe51e8b | ||
|
|
d364d50c05 | ||
|
|
615d324b11 | ||
|
|
eb36b6755f | ||
|
|
40c28d3b21 | ||
|
|
e726282023 | ||
|
|
327f734e4f | ||
|
|
b361f64d4f | ||
|
|
b38d215b3d | ||
|
|
99aa498bc4 | ||
|
|
f14798dec9 | ||
|
|
65873f3dee | ||
|
|
fc98c88358 | ||
|
|
7c0440c148 | ||
|
|
ad051269ed | ||
|
|
497d8f25a1 | ||
|
|
eb142f26f2 | ||
|
|
b01989f041 | ||
|
|
84d89e80cd | ||
|
|
d059d2cda4 | ||
|
|
751413f050 | ||
|
|
ce5e28554f | ||
|
|
860be3f96c | ||
|
|
89fb3a3d6e | ||
|
|
474a07564c | ||
|
|
59b69a3b3b | ||
|
|
2553392e42 | ||
|
|
fcd6901558 | ||
|
|
716ffbb945 | ||
|
|
cd4b9aeafe | ||
|
|
5d712b6f54 | ||
|
|
754c68fccc | ||
|
|
858f4da0d1 | ||
|
|
90910a7a4f | ||
|
|
cd218b59f9 | ||
|
|
9625c49c95 | ||
|
|
2dfed10d2e | ||
|
|
a74d3737dc | ||
|
|
6c82a34aa0 | ||
|
|
320d5656ac | ||
|
|
a4a5778001 | ||
|
|
a80a003865 | ||
|
|
4607e46c6f | ||
|
|
0aa3e2e49c | ||
|
|
595bb36956 | ||
|
|
afdf7e6df3 | ||
|
|
3e1c7d7ef2 | ||
|
|
7ce7c3deb7 | ||
|
|
c9b390ec60 | ||
|
|
cc2b826356 | ||
|
|
0b2c493731 | ||
|
|
0d7bbc51e7 | ||
|
|
db81c30d24 | ||
|
|
41ea8de0d6 | ||
|
|
c4b5b37568 | ||
|
|
76e6b23a4f | ||
|
|
283e295a98 | ||
|
|
606009afb0 | ||
|
|
da303b8b4f | ||
|
|
d4048661ae | ||
|
|
47853547ca | ||
|
|
6ae9188af4 | ||
|
|
d958ec2ac8 | ||
|
|
07aac8e6e9 | ||
|
|
9a341c9032 | ||
|
|
21e8b08ed9 | ||
|
|
c41d477adc | ||
|
|
f8445a4c85 | ||
|
|
71f5be011b | ||
|
|
a39b7ddbac | ||
|
|
cab5c822c5 | ||
|
|
4056bd3c2d | ||
|
|
a985ae9c0a | ||
|
|
804a3bf380 | ||
|
|
a8bef96463 | ||
|
|
5e43a3f695 | ||
|
|
8e46e05e1b | ||
|
|
ec0e27dbb4 | ||
|
|
3f55d93b41 | ||
|
|
5418a8c28a | ||
|
|
e180192379 | ||
|
|
f498d69b7d | ||
|
|
dfae1b3f70 | ||
|
|
a9ebb55f95 | ||
|
|
abfac8aa40 | ||
|
|
78956ccf83 | ||
|
|
eed25f23f6 | ||
|
|
134ce56f80 | ||
|
|
28a4778187 | ||
|
|
c654c2e5e8 | ||
|
|
e580d4e637 | ||
|
|
2192914cbb | ||
|
|
ca6dee1777 | ||
|
|
6f3bdc5dca | ||
|
|
095cdcd69e | ||
|
|
f022633f29 | ||
|
|
1f85fcc9b0 | ||
|
|
a3ede75842 | ||
|
|
0defce37f0 | ||
|
|
4355b39b1e | ||
|
|
efec738c89 | ||
|
|
10c09a361b | ||
|
|
e3d1a69223 | ||
|
|
4b82253ae9 | ||
|
|
47a12c30ca | ||
|
|
613655767b | ||
|
|
1182027f1c | ||
|
|
e9421d557a | ||
|
|
bbc0c0df94 | ||
|
|
610e32714c | ||
|
|
7ab81d3805 | ||
|
|
9a1e41e1fa | ||
|
|
ae71d12f06 | ||
|
|
c25234df83 | ||
|
|
03284ba046 | ||
|
|
5fa433ecca | ||
|
|
ac2a4c700a | ||
|
|
eeb7b00f60 | ||
|
|
c8c540b453 | ||
|
|
a0585f75f7 | ||
|
|
637af1d392 | ||
|
|
fe6c31acc1 | ||
|
|
04cfcf751e | ||
|
|
51c51d49ad | ||
|
|
4271aa5b1f | ||
|
|
17ada1c894 | ||
|
|
2e14d125ba | ||
|
|
ce8fa4c24b | ||
|
|
cfe2e83e6b | ||
|
|
b17c62618d | ||
|
|
6b162a1193 | ||
|
|
6653530b63 | ||
|
|
aacae6444e | ||
|
|
b91fe12258 | ||
|
|
ae7ca00e69 | ||
|
|
0103f1f080 | ||
|
|
e8d29d54d6 | ||
|
|
092f2ce0b3 | ||
|
|
d89233276b | ||
|
|
7d797187e8 | ||
|
|
6edcc72364 | ||
|
|
250dfc1377 | ||
|
|
45489c1c87 | ||
|
|
09b250f189 | ||
|
|
a84465ddba | ||
|
|
3b95671442 | ||
|
|
52e66077a7 | ||
|
|
84bf4d21a3 | ||
|
|
04cfc510d0 | ||
|
|
d846e67ec1 | ||
|
|
9c60a1bc10 | ||
|
|
f06ac52a43 | ||
|
|
9e5fd43a2d | ||
|
|
8d50e7dc82 | ||
|
|
1e6b7bd2a6 | ||
|
|
8346be7a81 | ||
|
|
9dc5683fc2 | ||
|
|
e7cb82175a | ||
|
|
1ef0aa14c0 | ||
|
|
0b3f6d6aab | ||
|
|
0beef1d770 | ||
|
|
b944db30fd | ||
|
|
6cf3a3feaf | ||
|
|
9680b8ccb3 | ||
|
|
a88a11c243 | ||
|
|
7ff76f69a1 | ||
|
|
c2e4e6d221 | ||
|
|
60edc456a9 | ||
|
|
625f804130 | ||
|
|
7100aaedec | ||
|
|
c867dbc7b2 | ||
|
|
88097f1829 | ||
|
|
7cf4834336 | ||
|
|
b5355307a3 | ||
|
|
76f693e5d7 | ||
|
|
fb3b0ca6e3 | ||
|
|
3c71977e2e | ||
|
|
5574a2663a | ||
|
|
41960b4212 | ||
|
|
6a500b8d40 | ||
|
|
dcede59379 | ||
|
|
695153c527 | ||
|
|
c409cca20e | ||
|
|
a5a9204f83 | ||
|
|
25d42ad345 | ||
|
|
f70a407611 | ||
|
|
89f2e66c80 | ||
|
|
4562be52d4 | ||
|
|
ebd931f7af | ||
|
|
6a47ff6422 | ||
|
|
1237185bb4 | ||
|
|
d7fe819699 | ||
|
|
770ffd1483 | ||
|
|
9373e77636 | ||
|
|
cb5034548d | ||
|
|
f9ad870ff0 | ||
|
|
b538bc3871 | ||
|
|
e5b0528aca | ||
|
|
a12bd2271e | ||
|
|
15c5858732 | ||
|
|
dd4227f444 | ||
|
|
fe8a7d8db9 | ||
|
|
ec79ca71b2 | ||
|
|
7a1544e76a | ||
|
|
27ffc23664 | ||
|
|
8ef8ee91e9 | ||
|
|
571625f0c3 | ||
|
|
fc2d6eb6bb | ||
|
|
48800504be | ||
|
|
f94a019733 | ||
|
|
535d8b9e02 | ||
|
|
161d44ee04 | ||
|
|
7ea155b943 | ||
|
|
30acef2452 | ||
|
|
82b50fd3a5 | ||
|
|
9e5503dd04 | ||
|
|
2ec2ed62c8 | ||
|
|
274c11c3ec | ||
|
|
76c4bb556f | ||
|
|
40f484cc54 | ||
|
|
85b701b8c2 | ||
|
|
7e875ba89d | ||
|
|
c718d7999f | ||
|
|
d1472992da | ||
|
|
995f90aa49 | ||
|
|
a4c27618b4 | ||
|
|
05019529f1 | ||
|
|
1b5ab3261c | ||
|
|
6033555ac0 | ||
|
|
fd4e1975a3 | ||
|
|
124ac12150 | ||
|
|
8c1ffa3f5d | ||
|
|
f76a7e36e8 | ||
|
|
6484c4bc8b | ||
|
|
bba2421ba9 | ||
|
|
3c69c7feaf | ||
|
|
45b2ffe1af | ||
|
|
a57c0f4700 | ||
|
|
c33116166f | ||
|
|
50a2063e45 | ||
|
|
cd30cf2d6c | ||
|
|
419126652e | ||
|
|
06ab83dca6 | ||
|
|
313fddf722 | ||
|
|
f4def36ccb | ||
|
|
4be8f2ba93 | ||
|
|
881b282604 | ||
|
|
9675bfe07d | ||
|
|
443351e95a | ||
|
|
d4cd1c61ee | ||
|
|
75892cb523 | ||
|
|
63e0041644 | ||
|
|
70e2d8dd4e | ||
|
|
b2624f6055 | ||
|
|
0bb8144677 | ||
|
|
ad50447ec6 | ||
|
|
84de7437c6 | ||
|
|
419dd50255 | ||
|
|
9dea02e578 | ||
|
|
1c181e091e | ||
|
|
32782bab0e | ||
|
|
330783cb5a | ||
|
|
504b004e01 | ||
|
|
edb861da70 | ||
|
|
64ad15895f | ||
|
|
44b4944334 | ||
|
|
f9272d0959 | ||
|
|
a113e344a1 | ||
|
|
2d80f03f01 | ||
|
|
542fe9f029 | ||
|
|
a1992f5910 | ||
|
|
45a057b0c6 | ||
|
|
4a1a26e8b7 | ||
|
|
db35e6a427 | ||
|
|
7358ed25a5 | ||
|
|
0d385c29a3 | ||
|
|
51076e68c8 | ||
|
|
3270f1252b | ||
|
|
d8ee105e1e | ||
|
|
567fccd7ee | ||
|
|
f7f7319698 | ||
|
|
62a6b61fc9 | ||
|
|
1a87d9fa77 | ||
|
|
8131e30002 | ||
|
|
83c76bdafc | ||
|
|
cf1566e116 | ||
|
|
5d2c977029 | ||
|
|
823c0ef5fb | ||
|
|
aefc588e6e | ||
|
|
1949439d69 | ||
|
|
c131b8daf1 | ||
|
|
8a61969c8f | ||
|
|
3cf85770c7 | ||
|
|
310b339f0d | ||
|
|
229b7810df | ||
|
|
a686beb9a7 | ||
|
|
42c1bee8ea | ||
|
|
c289556775 | ||
|
|
941d2f2a3e |
No files matched your search
@@ -10,3 +10,4 @@
|
|||||||
- Compiler/IDE and SDK: ZZZ version _X.Y_
|
- Compiler/IDE and SDK: ZZZ version _X.Y_
|
||||||
- Target hardware/board: _?_
|
- Target hardware/board: _?_
|
||||||
- Connectivity chip/module: _?_
|
- Connectivity chip/module: _?_
|
||||||
|
- Target RTOS/OS (if applicable): _?_
|
||||||
+109
-80
@@ -1,41 +1,63 @@
|
|||||||
name: build
|
name: build
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
env:
|
||||||
|
IPV6: 0
|
||||||
jobs:
|
jobs:
|
||||||
linux:
|
linux:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
cc: [gcc, clang]
|
cc: [gcc, clang, g++, clang++]
|
||||||
target: [test, test++, valgrind]
|
target: [test, mip_test]
|
||||||
|
# target: [test]
|
||||||
ssl: [MBEDTLS, OPENSSL]
|
ssl: [MBEDTLS, OPENSSL]
|
||||||
name: linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }}
|
name: linux ${{ matrix.target }} CC=${{ matrix.cc }} SSL=${{ matrix.ssl }}
|
||||||
env:
|
env:
|
||||||
IPV6: 0
|
|
||||||
CC: ${{ matrix.cc }}
|
CC: ${{ matrix.cc }}
|
||||||
SSL: ${{ matrix.ssl }}
|
SSL: ${{ matrix.ssl }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Install packages
|
- run: ./test/setup_ga_network.sh
|
||||||
run: sudo apt-get update ; sudo apt-get install libmbedtls-dev valgrind
|
- run: sudo apt-get update ; sudo apt-get install libmbedtls-dev
|
||||||
- name: test
|
- run: make ${{ matrix.target }}
|
||||||
run: make ${{ matrix.target }}
|
s390:
|
||||||
- name: unamalgamated
|
runs-on: ubuntu-latest
|
||||||
run: make unamalgamated
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- run: sudo apt-get update && sudo apt-get install qemu binfmt-support qemu-user-static
|
||||||
|
- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||||
|
- run: make s390
|
||||||
|
armhf:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- run: sudo apt-get update && sudo apt-get install qemu binfmt-support qemu-user-static
|
||||||
|
- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||||
|
- run: make armhf
|
||||||
|
linux2:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- run: sudo apt-get update ; sudo apt-get install libmbedtls-dev valgrind
|
||||||
|
- run: make unamalgamated
|
||||||
|
- run: make valgrind
|
||||||
|
- run: make mg_prefix
|
||||||
examples:
|
examples:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- run: sudo apt-get install libmbedtls-dev libpcap-dev
|
- run: sudo apt -y install libmbedtls-dev libpcap-dev
|
||||||
- run: make clean examples
|
- run: make clean examples
|
||||||
- run: make clean test IPV6=0 MG_ENABLE_POLL=1
|
- run: make clean test MG_ENABLE_POLL=1
|
||||||
macos:
|
macos:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install jq mbedtls openssl
|
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install jq mbedtls openssl
|
||||||
- run: make test++ upload-coverage IPV6=0 ASAN_OPTIONS=
|
- run: make test upload-coverage SSL=OPENSSL ASAN_OPTIONS= OPENSSL=`echo /usr/local/Cellar/openssl*/*`
|
||||||
- run: make test SSL=OPENSSL IPV6=0 ASAN_OPTIONS= OPENSSL=`echo /usr/local/Cellar/openssl*/*`
|
- run: make test SSL=MBEDTLS ASAN_OPTIONS= MBEDTLS=`echo /usr/local/Cellar/mbedtls*/*`
|
||||||
|
#- run: make mip_test ASAN_OPTIONS=
|
||||||
- run: make mg_prefix
|
- run: make mg_prefix
|
||||||
windows:
|
windows:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -46,83 +68,90 @@ jobs:
|
|||||||
- run: make vc22
|
- run: make vc22
|
||||||
- run: make mingw
|
- run: make mingw
|
||||||
- run: make mingw++
|
- run: make mingw++
|
||||||
|
arduino-xiao:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- run: make arduino-xiao
|
||||||
arm:
|
arm:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- run: make arm
|
- run: make arm
|
||||||
|
riscv:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- run: make riscv
|
||||||
matrix_examples:
|
matrix_examples:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
example:
|
example:
|
||||||
- name: esp32/device-dashboard
|
- path: esp32/device-dashboard
|
||||||
path: esp32/device-dashboard
|
- path: esp32/uart-bridge
|
||||||
- name: esp8266
|
- path: esp8266/http-client-server
|
||||||
path: esp8266
|
- path: stm32/nucleo-h743zi-baremetal
|
||||||
- name: stm32-freertos-tcp
|
target: test
|
||||||
path: stm32/stm32-freertos-tcp
|
- path: stm32/stm32-freertos-tcp
|
||||||
- name: stm32-nucleo-f746z
|
- path: stm32/stm32-nucleo-f746z
|
||||||
path: stm32/stm32-nucleo-f746z
|
- path: stm32/stm32-nucleo-f746zg
|
||||||
- name: stm32-nucleo-f429z
|
- path: stm32/stm32-nucleo-f429z
|
||||||
path: stm32/stm32-nucleo-f429z
|
- path: stm32/stm32-nucleo-h743z
|
||||||
- name: stm32-nucleo-h743z
|
- path: stm32/nucleo-f429zi-baremetal
|
||||||
path: stm32/stm32-nucleo-h743z
|
target: test
|
||||||
- name: stm32-nucleo-f746zg-baremetal
|
- path: stm32/nucleo-f429zi-freertos-mip
|
||||||
path: stm32/nucleo-f746zg-baremetal
|
- path: stm32/nucleo-f429zi-usb-rndis
|
||||||
- name: nxp-mimxrt1020-azurertos
|
- path: stm32/nucleo-f746zg-baremetal
|
||||||
path: nxp/nxp-mimxrt1020-azurertos
|
- path: stm32/nucleo-f746zg-freertos-mip
|
||||||
- name: nxp-frdmk66f-freertos
|
- path: stm32/nucleo-f746zg-usb-rndis
|
||||||
path: nxp/nxp-frdmk66f-freertos
|
- path: nxp/nxp-mimxrt1020-azurertos
|
||||||
- name: nxp-lpcxpresso54s018m-freertos
|
- path: nxp/nxp-frdmk66f-freertos
|
||||||
path: nxp/nxp-lpcxpresso54s018m-freertos
|
- path: nxp/nxp-lpcxpresso54s018m-freertos
|
||||||
- name: nxp-mimxrt1020-freertos
|
- path: nxp/nxp-mimxrt1020-freertos
|
||||||
path: nxp/nxp-mimxrt1020-freertos
|
- path: nxp/nxp-evkbimxrt1050-lwip-freertos
|
||||||
- name: nxp-evkbimxrt1050-lwip-freertos
|
- path: nxp/nxp-evkmimxrt1020-lwip-freertos
|
||||||
path: nxp/nxp-evkbimxrt1050-lwip-freertos
|
- path: nxp/nxp-evkmimxrt1024-lwip-freertos
|
||||||
- name: nxp-evkmimxrt1020-lwip-freertos
|
- path: nxp/nxp-evkmimxrt1060-lwip-freertos
|
||||||
path: nxp/nxp-evkmimxrt1020-lwip-freertos
|
- path: nxp/nxp-evkmimxrt1064-lwip-freertos
|
||||||
- name: nxp-evkmimxrt1024-lwip-freertos
|
- path: nxp/nxp-evkmimxrt1160-cm7-lwip-freertos
|
||||||
path: nxp/nxp-evkmimxrt1024-lwip-freertos
|
- path: nxp/nxp-evkmimxrt1170-cm7-lwip-freertos
|
||||||
- name: nxp-evkmimxrt1060-lwip-freertos
|
- path: nxp/nxp-frdmk64f-lwip-freertos
|
||||||
path: nxp/nxp-evkmimxrt1060-lwip-freertos
|
- path: nxp/nxp-frdmk66f-lwip-freertos
|
||||||
- name: nxp-evkmimxrt1064-lwip-freertos
|
- path: nxp/nxp-lpcxpresso54018-lwip-freertos
|
||||||
path: nxp/nxp-evkmimxrt1064-lwip-freertos
|
- path: nxp/nxp-lpcxpresso54608-lwip-freertos
|
||||||
- name: nxp-evkmimxrt1160-cm7-lwip-freertos
|
- path: nxp/nxp-lpcxpresso54618-lwip-freertos
|
||||||
path: nxp/nxp-evkmimxrt1160-cm7-lwip-freertos
|
- path: nxp/nxp-lpcxpresso54628-lwip-freertos
|
||||||
- name: nxp-evkmimxrt1170-cm7-lwip-freertos
|
- path: nxp/nxp-twrk65f180m-lwip-freertos
|
||||||
path: nxp/nxp-evkmimxrt1170-cm7-lwip-freertos
|
- path: nxp/nxp-twrkv58f220m-lwip-freertos
|
||||||
- name: nxp-frdmk64f-lwip-freertos
|
- path: infineon/infineon-xmc4700_4800-lwip-rtx-rtos
|
||||||
path: nxp/nxp-frdmk64f-lwip-freertos
|
- path: ti/ti-ek-tm4c1294xl-http-server
|
||||||
- name: nxp-frdmk66f-lwip-freertos
|
- path: ti/ek-tm4c1294xl-baremetal
|
||||||
path: nxp/nxp-frdmk66f-lwip-freertos
|
- path: ti/ek-tm4c1294xl-freertos-mip
|
||||||
- name: nxp-lpcxpresso54018-lwip-freertos
|
- path: rp2040/pico-rmii
|
||||||
path: nxp/nxp-lpcxpresso54018-lwip-freertos
|
- path: rp2040/pico-rndis-dashboard
|
||||||
- name: nxp-lpcxpresso54608-lwip-freertos
|
- path: rp2040/pico-w
|
||||||
path: nxp/nxp-lpcxpresso54608-lwip-freertos
|
- path: rp2040/pico-w5500
|
||||||
- name: nxp-lpcxpresso54618-lwip-freertos
|
target: test
|
||||||
path: nxp/nxp-lpcxpresso54618-lwip-freertos
|
name: ${{ matrix.example.path }}
|
||||||
- name: nxp-lpcxpresso54628-lwip-freertos
|
|
||||||
path: nxp/nxp-lpcxpresso54628-lwip-freertos
|
|
||||||
- name: nxp-twrk65f180m-lwip-freertos
|
|
||||||
path: nxp/nxp-twrk65f180m-lwip-freertos
|
|
||||||
- name: nxp-twrkv58f220m-lwip-freertos
|
|
||||||
path: nxp/nxp-twrkv58f220m-lwip-freertos
|
|
||||||
- name: infineon-xmc4700_4800-lwip-rtx-rtos
|
|
||||||
path: infineon/infineon-xmc4700_4800-lwip-rtx-rtos
|
|
||||||
- name: ti
|
|
||||||
path: ti/ti-ek-tm4c1294xl-http-server
|
|
||||||
- name: nucleo_f746zg-zephyr-http-client
|
|
||||||
path: zephyr/http-client
|
|
||||||
- name: nucleo_f746zg-zephyr-http-server
|
|
||||||
path: zephyr/http-server
|
|
||||||
- name: nucleo_f746zg-zephyr-mqtt-aws-client
|
|
||||||
path: zephyr/mqtt-aws-client
|
|
||||||
- name: nucleo_f746zg-zephyr-websocket-server
|
|
||||||
path: zephyr/websocket-server
|
|
||||||
name: ${{ matrix.example.name }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: ${{ matrix.example.name }}
|
- run: sudo apt -y install gcc-arm-none-eabi
|
||||||
run: make -C examples/${{ matrix.example.path }} build
|
- name: ${{ matrix.example.path }}
|
||||||
|
run: make -C examples/${{ matrix.example.path }} ${{ matrix.example.target || 'build' }} VCON_API_KEY=${{secrets.VCON_API_KEY}}
|
||||||
|
zephyr_examples:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- 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
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
Copyright (c) 2004-2013 Sergey Lyubka
|
Copyright (c) 2004-2013 Sergey Lyubka
|
||||||
Copyright (c) 2013-2021 Cesanta Software Limited
|
Copyright (c) 2013-2023 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,40 +1,58 @@
|
|||||||
SRCS = mongoose.c test/unit_test.c test/packed_fs.c
|
SRCS = mongoose.c test/unit_test.c test/packed_fs.c
|
||||||
HDRS = $(wildcard src/*.h) $(wildcard mip/*.h)
|
HDRS = $(wildcard src/*.h) $(wildcard mip/*.h)
|
||||||
DEFS ?= -DMG_MAX_HTTP_HEADERS=7 -DMG_ENABLE_LINES -DMG_ENABLE_PACKED_FS=1 -DMG_ENABLE_SSI=1
|
DEFS ?= -DMG_MAX_HTTP_HEADERS=7 -DMG_ENABLE_LINES -DMG_ENABLE_PACKED_FS=1 -DMG_ENABLE_SSI=1
|
||||||
C_WARN ?= -Wmissing-prototypes -Wstrict-prototypes
|
WARN ?= -pedantic -W -Wall -Werror -Wshadow -Wdouble-promotion -fno-common -Wconversion -Wundef
|
||||||
WARN ?= -pedantic -W -Wall -Werror -Wshadow -Wdouble-promotion -fno-common -Wconversion -Wundef $(C_WARN)
|
|
||||||
OPTS ?= -O3 -g3
|
OPTS ?= -O3 -g3
|
||||||
VALGRIND_OPTS ?= -O0 -g3
|
|
||||||
INCS ?= -Isrc -I.
|
INCS ?= -Isrc -I.
|
||||||
SSL ?= MBEDTLS
|
SSL ?=
|
||||||
CWD ?= $(realpath $(CURDIR))
|
CWD ?= $(realpath $(CURDIR))
|
||||||
ENV ?= -e Tmp=. -e WINEDEBUG=-all
|
ENV ?= -e Tmp=. -e WINEDEBUG=-all
|
||||||
DOCKER ?= docker run --platform linux/amd64 --rm $(ENV) -v $(CWD):$(CWD) -w $(CWD)
|
DOCKER ?= docker run --platform linux/amd64 --rm $(ENV) -v $(CWD):$(CWD) -w $(CWD)
|
||||||
VCFLAGS = /nologo /W3 /O2 /MD /I. $(DEFS) $(TFLAGS)
|
VCFLAGS = /nologo /W3 /O2 /MD /I. $(DEFS) $(TFLAGS)
|
||||||
IPV6 ?= 1
|
IPV6 ?= 1
|
||||||
ASAN ?= -fsanitize=address,undefined -fno-sanitize-recover=all
|
ASAN ?= -fsanitize=address,undefined,alignment -fno-sanitize-recover=all -fno-omit-frame-pointer -fno-common
|
||||||
ASAN_OPTIONS ?= detect_leaks=1
|
ASAN_OPTIONS ?= detect_leaks=1
|
||||||
EXAMPLES := $(dir $(wildcard examples/*/Makefile)) examples/stm32/nucleo-f746zg-baremetal
|
EXAMPLES := $(dir $(wildcard examples/*/Makefile))
|
||||||
PREFIX ?= /usr/local
|
PREFIX ?= /usr/local
|
||||||
VERSION ?= $(shell cut -d'"' -f2 src/version.h)
|
VERSION ?= $(shell cut -d'"' -f2 src/version.h)
|
||||||
COMMON_CFLAGS ?= $(WARN) $(INCS) $(DEFS) -DMG_ENABLE_IPV6=$(IPV6) $(TFLAGS)
|
COMMON_CFLAGS ?= $(C_WARN) $(WARN) $(INCS) $(DEFS) -DMG_ENABLE_IPV6=$(IPV6) $(TFLAGS)
|
||||||
CFLAGS ?= $(OPTS) $(ASAN) $(COMMON_CFLAGS)
|
CFLAGS ?= $(OPTS) $(ASAN) $(COMMON_CFLAGS)
|
||||||
VALGRIND_CFLAGS ?= $(VALGRIND_OPTS) $(COMMON_CFLAGS)
|
VALGRIND_CFLAGS ?= $(OPTS) $(COMMON_CFLAGS)
|
||||||
VALGRIND_RUN ?= valgrind --tool=memcheck --gen-suppressions=all --leak-check=full --show-leak-kinds=all --leak-resolution=high --track-origins=yes --error-exitcode=1 --exit-on-first-error=yes
|
VALGRIND_RUN ?= valgrind --tool=memcheck --gen-suppressions=all --leak-check=full --show-leak-kinds=all --leak-resolution=high --track-origins=yes --error-exitcode=1 --exit-on-first-error=yes
|
||||||
.PHONY: examples test valgrind
|
.PHONY: examples test valgrind mip_test
|
||||||
|
|
||||||
|
ifeq "$(findstring ++,$(CC))" ""
|
||||||
|
# $(CC) does not end with ++, i.e. we're using C. Apply C flags
|
||||||
|
C_WARN ?= -Wmissing-prototypes -Wstrict-prototypes
|
||||||
|
else
|
||||||
|
# $(CC) ends with ++, i.e. we're using C++. Apply C++ flags
|
||||||
|
C_WARN ?= -Wno-deprecated
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq "$(SSL)" "MBEDTLS"
|
ifeq "$(SSL)" "MBEDTLS"
|
||||||
MBEDTLS ?= /usr/local
|
MBEDTLS ?= /usr/local
|
||||||
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS)/include -I/usr/include
|
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS)/include -I/usr/include
|
||||||
LDFLAGS ?= -L$(MBEDTLS)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
LDFLAGS ?= -L$(MBEDTLS)/lib -lmbedtls -lmbedcrypto -lmbedx509
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq "$(SSL)" "OPENSSL"
|
ifeq "$(SSL)" "OPENSSL"
|
||||||
OPENSSL ?= /usr/local
|
OPENSSL ?= /usr/local
|
||||||
CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include
|
CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include
|
||||||
LDFLAGS ?= -L$(OPENSSL)/lib -lssl -lcrypto
|
LDFLAGS ?= -L$(OPENSSL)/lib -lssl -lcrypto
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: mg_prefix unamalgamated unpacked test test++ arm examples vc98 vc17 vc22 mingw mingw++ linux linux++ fuzz
|
all:
|
||||||
|
$(MAKE) -C examples/http-server
|
||||||
|
|
||||||
|
tall: mg_prefix unamalgamated test mip_test arm examples vc98 vc17 vc22 mingw mingw++ fuzz
|
||||||
|
|
||||||
|
mip_test: test/mip_test.c mongoose.c mongoose.h Makefile mip_tap_test
|
||||||
|
$(CC) test/mip_test.c $(INCS) $(WARN) $(OPTS) $(C_WARN) $(ASAN) -o $@
|
||||||
|
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@
|
||||||
|
|
||||||
|
mip_tap_test: test/mip_tap_test.c mongoose.c mongoose.h Makefile
|
||||||
|
$(CC) test/mip_tap_test.c $(INCS) $(WARN) $(OPTS) $(C_WARN) $(ASAN) -o $@
|
||||||
|
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./$@
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
@for X in $(EXAMPLES); do test -f $$X/Makefile || continue; $(MAKE) -C $$X example || exit 1; done
|
@for X in $(EXAMPLES); do test -f $$X/Makefile || continue; $(MAKE) -C $$X example || exit 1; done
|
||||||
@@ -43,8 +61,8 @@ test/packed_fs.c: Makefile src/ssi.h test/fuzz.c test/data/a.txt
|
|||||||
$(CC) $(CFLAGS) test/pack.c -o pack
|
$(CC) $(CFLAGS) test/pack.c -o pack
|
||||||
$(RUN) ./pack Makefile src/ssi.h test/fuzz.c test/data/a.txt test/data/range.txt > $@
|
$(RUN) ./pack Makefile src/ssi.h test/fuzz.c test/data/a.txt test/data/range.txt > $@
|
||||||
|
|
||||||
DIR ?= test/data/
|
DIR ?= test/data
|
||||||
OUT ?= fs_packed.c
|
OUT ?= packed_fs.c
|
||||||
mkfs:
|
mkfs:
|
||||||
$(CC) $(CFLAGS) test/pack.c -o pack
|
$(CC) $(CFLAGS) test/pack.c -o pack
|
||||||
$(RUN) ./pack -s $(DIR) `find $(DIR) -type f` > $(OUT)
|
$(RUN) ./pack -s $(DIR) `find $(DIR) -type f` > $(OUT)
|
||||||
@@ -52,12 +70,7 @@ mkfs:
|
|||||||
|
|
||||||
# Check that all external (exported) symbols have "mg_" prefix
|
# Check that all external (exported) symbols have "mg_" prefix
|
||||||
mg_prefix: mongoose.c mongoose.h
|
mg_prefix: mongoose.c mongoose.h
|
||||||
$(CC) mongoose.c $(CFLAGS) -c -o /tmp/x.o && nm /tmp/x.o | grep ' T' | grep -v 'mg_' ; test $$? = 1
|
$(CC) mongoose.c $(CFLAGS) -c -o /tmp/x.o && nm /tmp/x.o | grep ' T ' | grep -v 'mg_' ; test $$? = 1
|
||||||
|
|
||||||
# C++ build
|
|
||||||
test++: test
|
|
||||||
test++: CC = g++
|
|
||||||
test++: C_WARN = -std=c++2a -Wno-vla -Wno-shadow -Wno-missing-field-initializers -Wno-deprecated
|
|
||||||
|
|
||||||
musl: test
|
musl: test
|
||||||
musl: ASAN =
|
musl: ASAN =
|
||||||
@@ -69,20 +82,18 @@ musl: RUN = $(DOCKER) mdashnet/cc1
|
|||||||
unamalgamated: $(HDRS) Makefile test/packed_fs.c
|
unamalgamated: $(HDRS) Makefile test/packed_fs.c
|
||||||
$(CC) src/*.c test/packed_fs.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -g -o unit_test
|
$(CC) src/*.c test/packed_fs.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -g -o unit_test
|
||||||
|
|
||||||
unpacked:
|
fuzz: ASAN = -fsanitize=fuzzer,signed-integer-overflow,address,undefined
|
||||||
$(CC) -I. mongoose.c test/unit_test.c -o $@
|
fuzz: mongoose.c mongoose.h Makefile test/fuzz.c
|
||||||
|
$(CC) test/fuzz.c $(OPTS) $(WARN) $(INCS) $(TFLAGS) $(ASAN) -o fuzzer
|
||||||
fuzzer: mongoose.c mongoose.h Makefile test/fuzz.c
|
|
||||||
clang++ mongoose.c test/fuzz.c $(WARN) $(INCS) $(TFLAGS) -DMG_ENABLE_LINES -fsanitize=fuzzer,signed-integer-overflow,address -Wno-deprecated -Wno-vla-extension -o $@
|
|
||||||
|
|
||||||
fuzz: fuzzer
|
|
||||||
$(RUN) ./fuzzer
|
$(RUN) ./fuzzer
|
||||||
|
|
||||||
unit_test: Makefile mongoose.h $(SRCS)
|
FUZZDATA ?= /tmp/fuzzdata
|
||||||
$(CC) $(SRCS) $(CFLAGS) $(LDFLAGS) -g -o unit_test
|
fuzz2: mongoose.c mongoose.h Makefile test/fuzz.c
|
||||||
|
$(CC) test/fuzz.c -DMAIN $(OPTS) $(WARN) $(ASAN) $(INCS) -o fuzzer
|
||||||
|
$(RUN) ./fuzzer $(FUZZDATA)
|
||||||
|
|
||||||
# make CC=/usr/local/opt/llvm\@8/bin/clang ASAN_OPTIONS=detect_leaks=1
|
test: Makefile mongoose.h $(SRCS)
|
||||||
test: unit_test
|
$(CC) $(SRCS) $(CFLAGS) $(LDFLAGS) -o unit_test
|
||||||
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./unit_test
|
ASAN_OPTIONS=$(ASAN_OPTIONS) $(RUN) ./unit_test
|
||||||
|
|
||||||
coverage: CFLAGS += -coverage
|
coverage: CFLAGS += -coverage
|
||||||
@@ -93,14 +104,21 @@ coverage: test
|
|||||||
upload-coverage: coverage
|
upload-coverage: coverage
|
||||||
curl -s https://codecov.io/bash | /bin/bash
|
curl -s https://codecov.io/bash | /bin/bash
|
||||||
|
|
||||||
valgrind_unit_test: Makefile mongoose.h $(SRCS)
|
valgrind: Makefile mongoose.h mongoose.c
|
||||||
$(CC) $(SRCS) $(VALGRIND_CFLAGS) $(LDFLAGS) -g -o valgrind_unit_test
|
$(CC) $(SRCS) $(VALGRIND_CFLAGS) $(LDFLAGS) -g -o unit_test
|
||||||
|
$(VALGRIND_RUN) ./unit_test
|
||||||
|
|
||||||
valgrind: valgrind_unit_test
|
armhf: ASAN=
|
||||||
$(VALGRIND_RUN) ./valgrind_unit_test
|
armhf: IPV6=0
|
||||||
|
armhf: CC = $(DOCKER) mdashnet/armhf cc
|
||||||
|
armhf: RUN = $(DOCKER) mdashnet/armhf
|
||||||
|
armhf: test
|
||||||
|
|
||||||
infer:
|
s390: ASAN=
|
||||||
infer run -- cc test/unit_test.c -c -W -Wall -Werror -Isrc -I. -O2 -DMG_ENABLE_MBEDTLS=1 -DMG_ENABLE_LINES -I/usr/local/Cellar/mbedtls/2.23.0/include -DMG_ENABLE_IPV6=1 -g -o /dev/null
|
s390: IPV6=0
|
||||||
|
s390: CC = $(DOCKER) mdashnet/s390 cc
|
||||||
|
s390: RUN = $(DOCKER) mdashnet/s390
|
||||||
|
s390: test
|
||||||
|
|
||||||
arm: DEFS += -DMG_ENABLE_FILE=0 -DMG_ENABLE_MIP=1 -DMG_ARCH=MG_ARCH_NEWLIB
|
arm: DEFS += -DMG_ENABLE_FILE=0 -DMG_ENABLE_MIP=1 -DMG_ARCH=MG_ARCH_NEWLIB
|
||||||
arm: mongoose.h $(SRCS)
|
arm: mongoose.h $(SRCS)
|
||||||
@@ -114,12 +132,10 @@ vc98: Makefile mongoose.h $(SRCS)
|
|||||||
$(DOCKER) mdashnet/vc98 wine cl $(SRCS) $(VCFLAGS) ws2_32.lib /Fe$@.exe
|
$(DOCKER) mdashnet/vc98 wine cl $(SRCS) $(VCFLAGS) ws2_32.lib /Fe$@.exe
|
||||||
$(DOCKER) mdashnet/vc98 wine $@.exe
|
$(DOCKER) mdashnet/vc98 wine $@.exe
|
||||||
|
|
||||||
# vc17: DEFS += -DMG_ENABLE_IPV6=1
|
|
||||||
vc17: Makefile mongoose.h $(SRCS)
|
vc17: Makefile mongoose.h $(SRCS)
|
||||||
$(DOCKER) mdashnet/vc17 wine64 cl $(SRCS) $(VCFLAGS) ws2_32.lib /Fe$@.exe
|
$(DOCKER) mdashnet/vc17 wine64 cl $(SRCS) $(VCFLAGS) ws2_32.lib /Fe$@.exe
|
||||||
$(DOCKER) mdashnet/vc17 wine64 $@.exe
|
$(DOCKER) mdashnet/vc17 wine64 $@.exe
|
||||||
|
|
||||||
# vc22: DEFS += -DMG_ENABLE_IPV6=$(IPV6)
|
|
||||||
vc22: Makefile mongoose.h $(SRCS)
|
vc22: Makefile mongoose.h $(SRCS)
|
||||||
$(DOCKER) mdashnet/vc22 wine64 cl $(SRCS) $(VCFLAGS) ws2_32.lib /Fe$@.exe
|
$(DOCKER) mdashnet/vc22 wine64 cl $(SRCS) $(VCFLAGS) ws2_32.lib /Fe$@.exe
|
||||||
$(DOCKER) mdashnet/vc22 wine64 $@.exe
|
$(DOCKER) mdashnet/vc22 wine64 $@.exe
|
||||||
@@ -128,18 +144,24 @@ mingw: Makefile mongoose.h $(SRCS)
|
|||||||
$(DOCKER) mdashnet/mingw x86_64-w64-mingw32-gcc $(SRCS) -W -Wall -Werror -I. $(DEFS) -lwsock32 -o $@.exe
|
$(DOCKER) mdashnet/mingw x86_64-w64-mingw32-gcc $(SRCS) -W -Wall -Werror -I. $(DEFS) -lwsock32 -o $@.exe
|
||||||
$(DOCKER) mdashnet/mingw wine64 $@.exe
|
$(DOCKER) mdashnet/mingw wine64 $@.exe
|
||||||
|
|
||||||
|
arduino: ENV = -v $(CWD)/arduino:/root
|
||||||
|
arduino:
|
||||||
|
curl -sL http://downloads.arduino.cc/arduino-1.8.19-linux64.tar.xz | unxz | tar -xf -
|
||||||
|
mv arduino-* $@
|
||||||
|
$(DOCKER) mdashnet/cc2 ./arduino/arduino --pref "boardsmanager.additional.urls=https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json" --save-prefs
|
||||||
|
$(DOCKER) mdashnet/cc2 ./arduino/arduino --pref "compiler.warning_level=all" --save-prefs
|
||||||
|
$(DOCKER) mdashnet/cc2 ./arduino/arduino --install-boards Seeeduino:samd
|
||||||
|
|
||||||
|
arduino-xiao: ENV = -v $(CWD)/arduino:/root
|
||||||
|
arduino-xiao: arduino
|
||||||
|
rm -rf tmp; mkdir tmp
|
||||||
|
cp examples/arduino/w5500/w5500.ino tmp/tmp.ino
|
||||||
|
cp mongoose.c mongoose.h examples/arduino/w5500/mongoose_custom.h tmp/
|
||||||
|
$(DOCKER) mdashnet/cc2 ./arduino/arduino --verbose --verify --board Seeeduino:samd:seeed_XIAO_m0 tmp/tmp.ino
|
||||||
|
|
||||||
mingw++: Makefile mongoose.h $(SRCS)
|
mingw++: Makefile mongoose.h $(SRCS)
|
||||||
$(DOCKER) mdashnet/mingw x86_64-w64-mingw32-g++ $(SRCS) -W -Wall -Werror -I. $(DEFS) -lwsock32 -o $@.exe
|
$(DOCKER) mdashnet/mingw x86_64-w64-mingw32-g++ $(SRCS) -W -Wall -Werror -I. $(DEFS) -lwsock32 -o $@.exe
|
||||||
|
|
||||||
linux: IPV6=0
|
|
||||||
linux: Makefile mongoose.h $(SRCS)
|
|
||||||
$(DOCKER) mdashnet/cc2 gcc $(SRCS) $(CFLAGS) $(LDFLAGS) -o unit_test_gcc
|
|
||||||
$(DOCKER) mdashnet/cc2 ./unit_test_gcc
|
|
||||||
|
|
||||||
linux++: CC = g++
|
|
||||||
linux++: WARN += -Wno-missing-field-initializers
|
|
||||||
linux++: linux
|
|
||||||
|
|
||||||
linux-libs: CFLAGS += -fPIC
|
linux-libs: CFLAGS += -fPIC
|
||||||
linux-libs: mongoose.o
|
linux-libs: mongoose.o
|
||||||
$(CC) mongoose.o $(LDFLAGS) -shared -o libmongoose.so.$(VERSION)
|
$(CC) mongoose.o $(LDFLAGS) -shared -o libmongoose.so.$(VERSION)
|
||||||
@@ -157,8 +179,8 @@ mongoose.c: Makefile $(wildcard src/*) $(wildcard mip/*.c)
|
|||||||
(cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c mip/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
|
(cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c mip/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
|
||||||
|
|
||||||
mongoose.h: $(HDRS) Makefile
|
mongoose.h: $(HDRS) Makefile
|
||||||
(cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/config.h src/str.h src/fmt.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h mip/mip.h | sed -e 's,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
|
(cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_*.h src/config.h src/str.h src/fmt.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h mip/mip.h mip/driver_*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(PROG) *.exe *.o *.dSYM unit_test* valgrind_unit_test* ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* test/packed_fs.c pack unpacked
|
rm -rf $(PROG) *.exe *.o *.dSYM *_test* ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* test/packed_fs.c pack arduino tmp
|
||||||
@for X in $(EXAMPLES); do $(MAKE) -C $$X clean; done
|
find examples -maxdepth 3 -name zephyr -prune -o -name Makefile -print | xargs dirname | xargs -n1 make clean -C
|
||||||
@@ -21,6 +21,11 @@ robust, and easy. Features include:
|
|||||||
- Source code is both ISO C and ISO C++ compliant
|
- Source code is both ISO C and ISO C++ compliant
|
||||||
- Works with any network stack with socket API, like LwIP or FreeRTOS-Plus-TCP
|
- Works with any network stack with socket API, like LwIP or FreeRTOS-Plus-TCP
|
||||||
- Very easy to integrate: just copy `mongoose.c` and `mongoose.h` files to your build tree
|
- Very easy to integrate: just copy `mongoose.c` and `mongoose.h` files to your build tree
|
||||||
|
- Optional built-in TCP/IP stack with drivers for bare metal or RTOS firmwares
|
||||||
|
- A full device dashboard
|
||||||
|
[bare metal example on Nucleo-F429ZI](examples/stm32/nucleo-f429zi-baremetal)
|
||||||
|
is only 6 files
|
||||||
|
- For comparison, a CubeIDE generated HTTP example is 400+ files
|
||||||
- Detailed [documentation](https://mongoose.ws/documentation/) and
|
- Detailed [documentation](https://mongoose.ws/documentation/) and
|
||||||
[tutorials](https://mongoose.ws/tutorials/)
|
[tutorials](https://mongoose.ws/tutorials/)
|
||||||
|
|
||||||
|
|||||||
+152
-168
@@ -42,7 +42,7 @@ into the source code tree
|
|||||||
|
|
||||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
struct mg_http_serve_opts opts = {.root_dir = "."}; // Serve local dir
|
struct mg_http_serve_opts opts = {.root_dir = "."}; // Serve local dir
|
||||||
if (ev == MG_EV_HTTP_MSG) mg_http_serve_dir(c, ev_data, &opts);
|
if (ev == MG_EV_HTTP_MSG) mg_http_serve_dir(c, (struct mg_http_message *)ev_data, &opts);
|
||||||
}
|
}
|
||||||
...
|
...
|
||||||
|
|
||||||
@@ -138,7 +138,8 @@ enum {
|
|||||||
MG_EV_RESOLVE, // Host name is resolved NULL
|
MG_EV_RESOLVE, // Host name is resolved NULL
|
||||||
MG_EV_CONNECT, // Connection established NULL
|
MG_EV_CONNECT, // Connection established NULL
|
||||||
MG_EV_ACCEPT, // Connection accepted NULL
|
MG_EV_ACCEPT, // Connection accepted NULL
|
||||||
MG_EV_READ, // Data received from socket struct mg_str *
|
MG_EV_TLS_HS, // TLS handshake succeeded NULL
|
||||||
|
MG_EV_READ, // Data received from socket long *bytes_read
|
||||||
MG_EV_WRITE, // Data written to socket long *bytes_written
|
MG_EV_WRITE, // Data written to socket long *bytes_written
|
||||||
MG_EV_CLOSE, // Connection closed NULL
|
MG_EV_CLOSE, // Connection closed NULL
|
||||||
MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message *
|
MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message *
|
||||||
@@ -192,6 +193,28 @@ struct mg_connection {
|
|||||||
|
|
||||||
## Best practices
|
## Best practices
|
||||||
|
|
||||||
|
- Debug log. To increase debug verbosity, call `mg_log_set()`:
|
||||||
|
```c
|
||||||
|
mg_log_set(MG_LL_DEBUG);
|
||||||
|
mg_mgr_init(&mgr);
|
||||||
|
```
|
||||||
|
The `MG_INFO()`, `MG_DEBUG()` logging macros use `putchar()` by default,
|
||||||
|
i.e. they use standard C `stdout` stream. That works fine on the traditional
|
||||||
|
OS. In the embedded environment, in order to see debug output, two ways
|
||||||
|
are possible: IO retargeting or Mongoose log redirection. IO retargeting
|
||||||
|
can already be implemented by an embedded SDK - for example ESP32 SDK
|
||||||
|
redirects `printf()` to the UART0. Otherwise, IO retargeting can be
|
||||||
|
implemented manually, see
|
||||||
|
[guide](https://github.com/cpq/bare-metal-programming-guide#redirect-printf-to-uart)
|
||||||
|
for more details.
|
||||||
|
The alternative way is to redirect Mongoose logs:
|
||||||
|
```c
|
||||||
|
void log_fn(char ch, void *param) {
|
||||||
|
output_a_single_character_to_UART(ch);
|
||||||
|
}
|
||||||
|
...
|
||||||
|
mg_log_set_fn(log_fn, param); // Use our custom log function
|
||||||
|
```
|
||||||
- If you need to perform any sort of initialisation of your connection,
|
- If you need to perform any sort of initialisation of your connection,
|
||||||
do it by catching `MG_EV_OPEN` event. That event is sent immediately
|
do it by catching `MG_EV_OPEN` event. That event is sent immediately
|
||||||
after a connection has been allocated and added to the event manager,
|
after a connection has been allocated and added to the event manager,
|
||||||
@@ -255,6 +278,18 @@ struct mg_connection {
|
|||||||
By default, IO buffer allocation size `MG_IO_SIZE` is 2048: change it to 512
|
By default, IO buffer allocation size `MG_IO_SIZE` is 2048: change it to 512
|
||||||
to trim run-time per-connection memory consumption.
|
to trim run-time per-connection memory consumption.
|
||||||
|
|
||||||
|
## Architecture diagram
|
||||||
|
|
||||||
|
In the Operating System environment, Mongoose uses BSD sockets API provided
|
||||||
|
by the OS's TCP/IP stack:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
In the embedded bare metal environment, Mongoose can utilise its own built-in
|
||||||
|
stack with network drivers - i.e. it can run directly on top of the hardware:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Build options
|
## Build options
|
||||||
|
|
||||||
Mongoose source code ships in two files:
|
Mongoose source code ships in two files:
|
||||||
@@ -266,20 +301,22 @@ files to the application's source tree. The `mongoose.c` and `mongoose.h` files
|
|||||||
are actually an amalgamation - non-amalgamated sources can be found at
|
are actually an amalgamation - non-amalgamated sources can be found at
|
||||||
https://github.com/cesanta/mongoose/tree/master/src
|
https://github.com/cesanta/mongoose/tree/master/src
|
||||||
|
|
||||||
Mongoose has two types of build constants (preprocessor definitions) that
|
Mongoose has 3 types of build constants (preprocessor definitions) that affect
|
||||||
affect the build: a target architecture, and tunables. In order to set the
|
the build: a target architecture/OS, target network stack, and tunables. In
|
||||||
option during build time, use the `-D OPTION` compiler flag:
|
order to set the option during build time, use the `-D OPTION` compiler flag:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ cc app0.c mongoose.c # Use defaults!
|
$ cc app.c mongoose.c # Use defaults!
|
||||||
$ cc app1.c mongoose.c -D MG_ENABLE_IPV6=1 # Build with IPv6 enabled
|
$ cc app.c mongoose.c -D MG_ENABLE_IPV6=1 # Build with IPv6 enabled
|
||||||
$ cc app2.c mongoose.c -D MG_ARCH=MG_ARCH_FREERTOS_LWIP # Set architecture
|
$ cc app.c mongoose.c -D MG_ARCH=MG_ARCH_RTX # Set architecture
|
||||||
$ cc app3.c mongoose.c -D MG_ENABLE_SSI=0 -D MG_IO_SIZE=8192 # Multiple options
|
$ cc app.c mongoose.c -D MG_ENABLE_SSI=0 -D MG_IO_SIZE=8192 # Multiple options
|
||||||
```
|
```
|
||||||
|
|
||||||
The list of supported architectures is defined in the [arch.h](https://github.com/cesanta/mongoose/blob/master/src/arch.h)
|
The list of supported architectures is defined in the
|
||||||
header file. Normally, there is no need to explicitly specify the architecture.
|
[arch.h](https://github.com/cesanta/mongoose/blob/master/src/arch.h) header
|
||||||
The architecture is guessed during the build, so setting it is not usually required.
|
file. Normally, there is no need to explicitly specify the architecture. The
|
||||||
|
architecture is guessed during the build, so setting it is not usually
|
||||||
|
required.
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
| ---- | ----------- |
|
| ---- | ----------- |
|
||||||
@@ -287,17 +324,26 @@ The architecture is guessed during the build, so setting it is not usually requi
|
|||||||
|MG_ARCH_WIN32 | Windows systems |
|
|MG_ARCH_WIN32 | Windows systems |
|
||||||
|MG_ARCH_ESP32 | Espressif's ESP32 |
|
|MG_ARCH_ESP32 | Espressif's ESP32 |
|
||||||
|MG_ARCH_ESP8266 | Espressif's ESP8266 |
|
|MG_ARCH_ESP8266 | Espressif's ESP8266 |
|
||||||
|MG_ARCH_FREERTOS_LWIP | All systems with FreeRTOS kernel and LwIP IP stack |
|
|MG_ARCH_FREERTOS | All systems with FreeRTOS kernel|
|
||||||
|MG_ARCH_FREERTOS_TCP | All systems with FreeRTOS kernel and FreeRTOS-Plus-TCP IP stack |
|
|
||||||
|MG_ARCH_AZURERTOS | Microsoft Azure RTOS |
|
|MG_ARCH_AZURERTOS | Microsoft Azure RTOS |
|
||||||
|MG_ARCH_RTX_LWIP | Keil RTX with LWIP TCP/IP stack |
|
|MG_ARCH_RTX | Keil RTX |
|
||||||
|MG_ARCH_RTX | Keil RTX with MDK TCP/IP stack |
|
|
||||||
|MG_ARCH_ZEPHYR | Zephyr RTOS |
|
|MG_ARCH_ZEPHYR | Zephyr RTOS |
|
||||||
|MG_ARCH_TIRTOS | TI RTOS |
|
|MG_ARCH_TIRTOS | TI RTOS |
|
||||||
|MG_ARCH_RP2040 | RP2040 SDK |
|
|MG_ARCH_RP2040 | RP2040 SDK |
|
||||||
|MG_ARCH_NEWLIB | Bare ARM GCC |
|
|MG_ARCH_NEWLIB | Bare ARM GCC |
|
||||||
|MG_ARCH_CUSTOM | A custom architecture, discussed in the next section |
|
|MG_ARCH_CUSTOM | A custom architecture, discussed in the next section |
|
||||||
|
|
||||||
|
The network stack constants are listed below. Note that if a network stack
|
||||||
|
is not specified, then it is assumed that the target architecture supports
|
||||||
|
standard BSD socket API.
|
||||||
|
|
||||||
|
| Name | Default | Description |
|
||||||
|
| ---- | -------- | ----------- |
|
||||||
|
|MG_ENABLE_LWIP | 0 | lwIP network stack |
|
||||||
|
|MG_ENABLE_FREERTOS_TCP | 0 | Amazon FreeRTOS-Plus-TCP network stack |
|
||||||
|
|MG_ENABLE_RL | 0 | Keil MDK network stack |
|
||||||
|
|MG_ENABLE_MIP | 0 | Built-in Mongoose network stack |
|
||||||
|
|
||||||
The other class of build constants is defined in
|
The other class of build constants is defined in
|
||||||
[src/config.h](https://github.com/cesanta/mongoose/blob/master/src/config.h)
|
[src/config.h](https://github.com/cesanta/mongoose/blob/master/src/config.h)
|
||||||
together with their default values. These are tunables that include/exclude
|
together with their default values. These are tunables that include/exclude
|
||||||
@@ -333,30 +379,33 @@ accordingly.
|
|||||||
|
|
||||||
## Custom build
|
## Custom build
|
||||||
|
|
||||||
A custom build should be used for cases which is not covered by the
|
A custom build should be used for cases not covered by the
|
||||||
existing architecture options (e.g., an embedded architecture that
|
existing architecture options (e.g., an embedded architecture that
|
||||||
uses some proprietary RTOS and network stack). In order to build on such
|
uses some proprietary RTOS and network stack). In order to build on such
|
||||||
systems, follow the outline below:
|
systems, follow the outline below:
|
||||||
|
|
||||||
1. Add `-DMG_ARCH=MG_ARCH_CUSTOM` to your build flags.
|
1. Add `-DMG_ARCH=MG_ARCH_CUSTOM` to your build flags.
|
||||||
2. Create a file called `mongoose_custom.h`, with defines and includes that
|
2. Create a file called `mongoose_custom.h`, with defines and includes that
|
||||||
are relevant to your platform. Mongoose uses `bool` type, `MG_DIRSEP` define,
|
are relevant to your platform. Mongoose uses `bool` type, `MG_DIRSEP` define,
|
||||||
and optionally other structures like `DIR *` depending on the functionality
|
and optionally other structures like `DIR *` depending on the functionality
|
||||||
you have enabled - see previous section. Below is an example:
|
you have enabled - see previous section. Below is an example:
|
||||||
|
```c
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
```c
|
#define MG_DIRSEP '/'
|
||||||
#include <stdbool.h>
|
#define MG_INT64_FMT "%lld"
|
||||||
#include <stdarg.h>
|
```
|
||||||
|
You can also add a `MG_ARCH` definition:
|
||||||
#define MG_DIRSEP '/'
|
```c
|
||||||
#define MG_INT64_FMT "%lld"
|
#define MG_ARCH MG_ARCH_CUSTOM
|
||||||
```
|
```
|
||||||
3. This step is optional, and only required if you intend to use a custom
|
3. This step is optional, and only required if you intend to use a custom
|
||||||
TCP/IP stack. To do that, you should:
|
TCP/IP stack. To do that, you should:
|
||||||
* Disable BSD socket API: in the `mongoose_custom.h`, add
|
* Disable BSD socket API: in the `mongoose_custom.h`, add
|
||||||
```c
|
```c
|
||||||
#define MG_ENABLE_SOCKET 0
|
#define MG_ENABLE_SOCKET 0
|
||||||
```
|
```
|
||||||
* Add an implementation of several internal API functions, like
|
* Add an implementation of several internal API functions, like
|
||||||
`mg_send()`, `mg_mgr_poll()`, etc. For the reference, take
|
`mg_send()`, `mg_mgr_poll()`, etc. For the reference, take
|
||||||
a look at the stub
|
a look at the stub
|
||||||
@@ -376,11 +425,11 @@ This example is a simple HTTP server that serves both static and dynamic content
|
|||||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_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/hello")) {
|
if (mg_http_match_uri(hm, "/api/hello")) { // On /api/hello requests,
|
||||||
mg_http_reply(c, 200, "", "%s\n", "hi"); // Serve dynamic content
|
mg_http_reply(c, 200, "", "{%Q:%d}\n", "status", 1); // Send dynamic JSON response
|
||||||
} else {
|
} else { // For all other URIs,
|
||||||
struct mg_http_serve_opts opts = {.root_dir = "."}; // Serve
|
struct mg_http_serve_opts opts = {.root_dir = "."}; // Serve files
|
||||||
mg_http_serve_dir(c, ev_data, &opts); // static content
|
mg_http_serve_dir(c, hm, &opts); // From root_dir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -649,7 +698,7 @@ mg_send(c, "hi", 2); // Append string "hi" to the output buffer
|
|||||||
|
|
||||||
```c
|
```c
|
||||||
int mg_printf(struct mg_connection *, const char *fmt, ...);
|
int mg_printf(struct mg_connection *, const char *fmt, ...);
|
||||||
int mg_vprintf(struct mg_connection *, const char *fmt, va_list ap);
|
int mg_vprintf(struct mg_connection *, const char *fmt, va_list *ap);
|
||||||
```
|
```
|
||||||
|
|
||||||
Same as `mg_send()`, but formats data using `printf()` semantics. Return
|
Same as `mg_send()`, but formats data using `printf()` semantics. Return
|
||||||
@@ -670,27 +719,6 @@ Usage example:
|
|||||||
mg_printf(c, "Hello, %s!", "world"); // Add "Hello, world!" to output buffer
|
mg_printf(c, "Hello, %s!", "world"); // Add "Hello, world!" to output buffer
|
||||||
```
|
```
|
||||||
|
|
||||||
### mg\_straddr
|
|
||||||
|
|
||||||
```c
|
|
||||||
char *mg_straddr(struct mg_addr *addr, char *buf, size_t len);
|
|
||||||
```
|
|
||||||
|
|
||||||
Write stringified IP address, associated with given connection to `buf` (maximum size `len`)
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- `addr` - A address pointer
|
|
||||||
- `buf` - A pointer to a buffer that will hold stringified address
|
|
||||||
- `len` - A buffer size
|
|
||||||
|
|
||||||
Return value: `buf` value
|
|
||||||
|
|
||||||
Usage example:
|
|
||||||
|
|
||||||
```c
|
|
||||||
char buf[100];
|
|
||||||
LOG(LL_INFO, ("%s", mg_straddr(&c->peer, buf, sizeof(buf))));
|
|
||||||
```
|
|
||||||
|
|
||||||
### mg\_wrapfd()
|
### mg\_wrapfd()
|
||||||
|
|
||||||
@@ -736,28 +764,22 @@ Return value: created socket, or `-1` on error
|
|||||||
|
|
||||||
Usage example: see [examples/multi-threaded](https://github.com/cesanta/mongoose/tree/master/examples/multi-threaded).
|
Usage example: see [examples/multi-threaded](https://github.com/cesanta/mongoose/tree/master/examples/multi-threaded).
|
||||||
|
|
||||||
### mg\_mgr\_wakeup()
|
### mg\_hello()
|
||||||
|
|
||||||
```c
|
```c
|
||||||
bool mg_mgr_wakeup(struct mg_connection *pipe, const void *buf, size_len len);
|
void mg_hello(const char *url);
|
||||||
```
|
```
|
||||||
|
|
||||||
Wake up an event manager that sleeps in `mg_mgr_poll()` call. This function
|
A convenience function that starts a simple web server on a given listening
|
||||||
must be called from a separate task/thread. A calling thread can pass
|
URL. This function does not return until a "/quit" request is received. A
|
||||||
some specific data to the IO thread via `buf`, `len`. The maximum value
|
server handles the following URIs:
|
||||||
of `len` is limited by a maximum UDP datagram size, which is 64KiB. If you need
|
|
||||||
to send a large data to the Mongoose thread, `malloc()` the data and send
|
- `/quit` - quit the server, and exit the function
|
||||||
a pointer to it, not the data itself. The receiving event handler can receive
|
- `/debug` - set debug level, expect `{"level": 3}` as a POST payload
|
||||||
a pointer, send a response, and call `free()`. Parameters:
|
- For all other URIs, `hi` is returned as a response
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- `pipe` - a special connection created by the `mg_mkpipe()` call
|
- `url` - a listening URL, for example `http://0.0.0.0:8000`
|
||||||
- `buf` - a data to send to the pipe connection. Use `""` if there is no data
|
|
||||||
- `len` - a data length
|
|
||||||
|
|
||||||
Return value: `true` if data has been sent, `false` otherwise
|
|
||||||
|
|
||||||
Usage example: see [examples/multi-threaded](https://github.com/cesanta/mongoose/tree/master/examples/multi-threaded).
|
|
||||||
|
|
||||||
|
|
||||||
## HTTP
|
## HTTP
|
||||||
@@ -996,12 +1018,13 @@ void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
|
|||||||
const struct mg_http_serve_opts *opts);
|
const struct mg_http_serve_opts *opts);
|
||||||
```
|
```
|
||||||
|
|
||||||
Serve static files according to the given options. Note that in order to
|
Serve static files according to the given options. Files can also be gzip compressed, including the directory index. All compressed files must end in `.gz` and there must not exist a file with the same name without the extension, otherwise it will take precedence; see [mg_http_serve_file()](#mg_http_serve_file)
|
||||||
enable SSI, set a `-DMG_ENABLE_SSI=1` build flag.
|
|
||||||
|
<span class="badge bg-warning">NOTE: </span> In order to enable SSI, you need to set the `-DMG_ENABLE_SSI=1` build flag.
|
||||||
|
|
||||||
<span class="badge bg-danger">NOTE: </span> Avoid double dots `..` in
|
<span class="badge bg-danger">NOTE: </span> Avoid double dots `..` in
|
||||||
the `root_dir`. If you need to
|
the `root_dir`. If you need to
|
||||||
reference an upper-level directory, use absolute path.
|
reference an upper-level directory, use an absolute path.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- `c` - Connection to use
|
- `c` - Connection to use
|
||||||
@@ -1033,7 +1056,7 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
|
|||||||
const char *path, struct mg_http_serve_opts *opts);
|
const char *path, struct mg_http_serve_opts *opts);
|
||||||
```
|
```
|
||||||
|
|
||||||
Serve static file.
|
Serve a static file. If a file with the filename specified in `path` does not exist, Mongoose tries appending `.gz`; and if such a file exists, it will serve it with a `Content-Encoding: gzip` header
|
||||||
|
|
||||||
<span class="badge bg-danger">NOTE: </span> `opts->root_dir` settings
|
<span class="badge bg-danger">NOTE: </span> `opts->root_dir` settings
|
||||||
is ignored by this function.
|
is ignored by this function.
|
||||||
@@ -1343,7 +1366,7 @@ Parameters:
|
|||||||
|
|
||||||
Return value: offset to the next chunk, or 0 if there are no more chunks.
|
Return value: offset to the next chunk, or 0 if there are no more chunks.
|
||||||
|
|
||||||
Usage example (or see [form upload tutorial](../tutorials/form-uploads/) ):
|
Usage example (or see [form upload tutorial](../tutorials/file-uploads/) ):
|
||||||
|
|
||||||
```c
|
```c
|
||||||
struct mg_http_part part;
|
struct mg_http_part part;
|
||||||
@@ -1403,18 +1426,50 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Websocket
|
## WebSocket
|
||||||
|
|
||||||
### struct mg\_ws\_message
|
### struct mg\_ws\_message
|
||||||
|
|
||||||
```c
|
```c
|
||||||
struct mg_ws_message {
|
struct mg_ws_message {
|
||||||
struct mg_str data; // Websocket message data
|
struct mg_str data; // WebSocket message data
|
||||||
uint8_t flags; // Websocket message flags
|
uint8_t flags; // WebSocket message flags
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Structure represents the WebSocket message.
|
This structure represents the WebSocket message, the `flags` element corresponds to the first byte as described in [RFC 6455 section 5.2](https://www.rfc-editor.org/rfc/rfc6455#section-5.2).
|
||||||
|
|
||||||
|
#### WebSocket message type:
|
||||||
|
|
||||||
|
To extract the message type from an incoming message, check the four LSBs in the `flags` element of the `struct mg_ws_message`.
|
||||||
|
|
||||||
|
Possible WebSocket message types:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define WEBSOCKET_OP_CONTINUE 0
|
||||||
|
#define WEBSOCKET_OP_TEXT 1
|
||||||
|
#define WEBSOCKET_OP_BINARY 2
|
||||||
|
#define WEBSOCKET_OP_CLOSE 8
|
||||||
|
#define WEBSOCKET_OP_PING 9
|
||||||
|
#define WEBSOCKET_OP_PONG 10
|
||||||
|
```
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Mongoose events handler
|
||||||
|
void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_WS_MSG) {
|
||||||
|
struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
|
||||||
|
msgtype = wm->flags & 0x0F;
|
||||||
|
if (msgtype == WEBSOCKET_OP_BINARY) {
|
||||||
|
// This is a binary data message
|
||||||
|
} else if (msgtype == WEBSOCKET_OP_TEXT) {
|
||||||
|
// This is a text data message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To send a message, use the proper message type as described in [RFC 6455 section 5.6](https://www.rfc-editor.org/rfc/rfc6455#section-5.6) for data frames. when calling [mg_ws_send()](#mg_ws_send) or [mg_ws_printf()](#mg_ws_printf-mg_ws_vprintf) below
|
||||||
|
|
||||||
### mg\_ws\_connect()
|
### mg\_ws\_connect()
|
||||||
|
|
||||||
@@ -1424,7 +1479,7 @@ struct mg_connection *mg_ws_connect(struct mg_mgr *mgr, const char *url,
|
|||||||
const char *fmt, ...);
|
const char *fmt, ...);
|
||||||
```
|
```
|
||||||
|
|
||||||
Create client Websocket connection.
|
Create client WebSocket connection.
|
||||||
|
|
||||||
Note: this function does not connect to peer, it allocates required resources and
|
Note: this function does not connect to peer, it allocates required resources and
|
||||||
starts the connect process. Once peer is really connected, the `MG_EV_CONNECT` event is
|
starts the connect process. Once peer is really connected, the `MG_EV_CONNECT` event is
|
||||||
@@ -1433,7 +1488,6 @@ Note: this function does not connect to peer, it allocates required resources an
|
|||||||
Parameters:
|
Parameters:
|
||||||
- `mgr` - Event manager to use
|
- `mgr` - Event manager to use
|
||||||
- `url` - Specifies remote URL, e.g. `http://google.com`
|
- `url` - Specifies remote URL, e.g. `http://google.com`
|
||||||
- `opts` - MQTT options, with client ID, QoS, etc
|
|
||||||
- `fn` - An event handler function
|
- `fn` - An event handler function
|
||||||
- `fn_data` - An arbitrary pointer, which will be passed as `fn_data` when an
|
- `fn_data` - An arbitrary pointer, which will be passed as `fn_data` when an
|
||||||
event handler is called. This pointer is also stored in a connection
|
event handler is called. This pointer is also stored in a connection
|
||||||
@@ -1457,9 +1511,9 @@ void mg_ws_upgrade(struct mg_connection *c, struct mg_http_message *,
|
|||||||
const char *fmt, ...);
|
const char *fmt, ...);
|
||||||
```
|
```
|
||||||
|
|
||||||
Upgrade given HTTP connection to Websocket. The `fmt` is a printf-like
|
Upgrade given HTTP connection to WebSocket. The `fmt` is a printf-like
|
||||||
format string for the extra HTTP headers returned to the client in a
|
format string for the extra HTTP headers returned to the client in a
|
||||||
Websocket handshake. Set `fmt` to `NULL` if no extra headers need to be passed.
|
WebSocket handshake. Set `fmt` to `NULL` if no extra headers need to be passed.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- `c` - Connection to use
|
- `c` - Connection to use
|
||||||
@@ -1486,27 +1540,16 @@ void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
size_t mg_ws_send(struct mg_connection *c, const void *buf, size_t len, int op);
|
size_t mg_ws_send(struct mg_connection *c, const void *buf, size_t len, int op);
|
||||||
```
|
```
|
||||||
|
|
||||||
Send data to websocket peer
|
Send data to WebSocket peer
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- `c` - Connection to use
|
- `c` - Connection to use
|
||||||
- `buf` - Data to send
|
- `buf` - Data to send
|
||||||
- `len` - Data size
|
- `len` - Data size
|
||||||
- `op` - Websocket message type
|
- `op` - WebSocket message type, see [WebSocket message type](#websocket-message-type) above
|
||||||
|
|
||||||
Return value: sent bytes count
|
Return value: sent bytes count
|
||||||
|
|
||||||
Possible Websocket message type:
|
|
||||||
|
|
||||||
```c
|
|
||||||
#define WEBSOCKET_OP_CONTINUE 0
|
|
||||||
#define WEBSOCKET_OP_TEXT 1
|
|
||||||
#define WEBSOCKET_OP_BINARY 2
|
|
||||||
#define WEBSOCKET_OP_CLOSE 8
|
|
||||||
#define WEBSOCKET_OP_PING 9
|
|
||||||
#define WEBSOCKET_OP_PONG 10
|
|
||||||
```
|
|
||||||
|
|
||||||
Usage example:
|
Usage example:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
@@ -1528,16 +1571,11 @@ size_t mg_ws_vprintf(struct mg_connection *, int op, const char *fmt, va_list *)
|
|||||||
|
|
||||||
Same as `mg_ws_send()`, but formats data using `printf()` semantics.
|
Same as `mg_ws_send()`, but formats data using `printf()` semantics.
|
||||||
|
|
||||||
<span class="badge bg-danger">NOTE: </span> See [mg\_ws\_send](#mg_ws_send)
|
|
||||||
for the list of possible Websocket message types
|
|
||||||
|
|
||||||
<span class="badge bg-danger">NOTE: </span> See [mg\_snprintf](#mg_snprintf-mg_vsnprintf)
|
|
||||||
for the list of supported format specifiers
|
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- `c` - Connection to use
|
- `c` - Connection to use
|
||||||
- `op` - Websocket message type
|
- `op` - WebSocket message type, see [WebSocket message type](#websocket-message-type) above
|
||||||
- `fmt` - format string in `printf` semantics
|
- `fmt` - format string in `printf` semantics. see [mg\_snprintf](#mg_snprintf-mg_vsnprintf)
|
||||||
|
for the list of supported format specifiers
|
||||||
|
|
||||||
Return value: sent bytes count
|
Return value: sent bytes count
|
||||||
|
|
||||||
@@ -2320,7 +2358,7 @@ Usage example:
|
|||||||
struct mg_str str1 = mg_str("hello");
|
struct mg_str str1 = mg_str("hello");
|
||||||
struct mg_str str2 = mg_strdup(str1);
|
struct mg_str str2 = mg_strdup(str1);
|
||||||
//...
|
//...
|
||||||
free(str2.ptr);
|
free((void *)str2.ptr);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -2561,6 +2599,8 @@ Supported format specifiers:
|
|||||||
- `q` - expect `char *`, outputs JSON-escaped string (extension)
|
- `q` - expect `char *`, outputs JSON-escaped string (extension)
|
||||||
- `Q` - expect `char *`, outputs double-quoted JSON-escaped string (extension)
|
- `Q` - expect `char *`, outputs double-quoted JSON-escaped string (extension)
|
||||||
- `H` - expect `int`, `void *`, outputs double-quoted hex string (extension)
|
- `H` - expect `int`, `void *`, outputs double-quoted hex string (extension)
|
||||||
|
- `I` - expect `int` (4 or 6), `void *`, outputs IP address (extension)
|
||||||
|
- `A` - expect `void *`, outputs hardware address (extension)
|
||||||
- `V` - expect `int`, `void *`, outputs double-quoted base64 string (extension)
|
- `V` - expect `int`, `void *`, outputs double-quoted base64 string (extension)
|
||||||
- `M` - expect `mg_pfn_t`, calls another print function (extension)
|
- `M` - expect `mg_pfn_t`, calls another print function (extension)
|
||||||
- `g`, `f` - expect `double`
|
- `g`, `f` - expect `double`
|
||||||
@@ -2589,6 +2629,8 @@ mg_snprintf(buf, sizeof(buf), "%05x", 123); // 00123
|
|||||||
mg_snprintf(buf, sizeof(buf), "%%-%3s", "a"); // %- a
|
mg_snprintf(buf, sizeof(buf), "%%-%3s", "a"); // %- a
|
||||||
mg_snprintf(buf, sizeof(buf), "hi, %Q", "a"); // hi, "a"
|
mg_snprintf(buf, sizeof(buf), "hi, %Q", "a"); // hi, "a"
|
||||||
mg_snprintf(buf, sizeof(buf), "r: %M, %d", f,1,2,7); // r: 3, 7
|
mg_snprintf(buf, sizeof(buf), "r: %M, %d", f,1,2,7); // r: 3, 7
|
||||||
|
mg_snprintf(buf, sizeof(buf), "%I", 4, "abcd"); // 97.98.99.100
|
||||||
|
mg_snprintf(buf, sizeof(buf), "%A", "abcdef"); // 61:62:63:64:65:66
|
||||||
|
|
||||||
// Printing sub-function for %M specifier. Grabs two int parameters
|
// Printing sub-function for %M specifier. Grabs two int parameters
|
||||||
size_t f(void (*out)(char, void *), void *ptr, va_list *ap) {
|
size_t f(void (*out)(char, void *), void *ptr, va_list *ap) {
|
||||||
@@ -2705,28 +2747,6 @@ if (mg_aton(mg_str("127.0.0.1"), &addr)) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### mg\_ntoa()
|
|
||||||
|
|
||||||
```c
|
|
||||||
char *mg_ntoa(const struct mg_addr *addr, char *buf, size_t len);
|
|
||||||
```
|
|
||||||
|
|
||||||
Stringify IP address `ipaddr` into a buffer `buf`, `len`
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- `addr` - Address to stringify
|
|
||||||
- `buf` - Pointer to output buffer
|
|
||||||
- `len` - Output buffer size
|
|
||||||
|
|
||||||
Return value: `buf` value
|
|
||||||
|
|
||||||
Usage example:
|
|
||||||
|
|
||||||
```c
|
|
||||||
char buf[100];
|
|
||||||
mg_ntoa(&c->peer, buf, sizeof(buf));
|
|
||||||
```
|
|
||||||
|
|
||||||
## JSON
|
## JSON
|
||||||
|
|
||||||
Note that Mongoose's printing functions support non-standard format specifiers `%Q` and `%M`,
|
Note that Mongoose's printing functions support non-standard format specifiers `%Q` and `%M`,
|
||||||
@@ -3801,7 +3821,7 @@ isn't default port for URL protocol
|
|||||||
Usage example:
|
Usage example:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
unsigned short port1 = mg_url_port("htts://myhost.com") // port1 is now 443 (default https port)
|
unsigned short port1 = mg_url_port("https://myhost.com") // port1 is now 443 (default https port)
|
||||||
unsigned short port2 = mg_url_port("127.0.0.1:567") // port2 is now 567
|
unsigned short port2 = mg_url_port("127.0.0.1:567") // port2 is now 567
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -3941,7 +3961,7 @@ Parameters:
|
|||||||
- `0` - Disable logging
|
- `0` - Disable logging
|
||||||
- `1` - Log errors only
|
- `1` - Log errors only
|
||||||
- `2` - Log errors and info messages
|
- `2` - Log errors and info messages
|
||||||
- `3` - Log errors, into and debug messages
|
- `3` - Log errors, info and debug messages
|
||||||
- `4` - Log everything
|
- `4` - Log everything
|
||||||
|
|
||||||
Return value: None
|
Return value: None
|
||||||
@@ -4150,39 +4170,3 @@ Usage example:
|
|||||||
```c
|
```c
|
||||||
mg_file_printf(&mg_fs_fat, "/test.txt", "%s\n", "hi");
|
mg_file_printf(&mg_fs_fat, "/test.txt", "%s\n", "hi");
|
||||||
```
|
```
|
||||||
|
|
||||||
### Packed filesystem
|
|
||||||
|
|
||||||
A packed filesystem allow to "pack" filesystem into a C file which then can
|
|
||||||
be compiled into the binary, forming a read-only file system.
|
|
||||||
This makes it possible to serve files on devices with no
|
|
||||||
filesystem. Even on devices with a filesystem, packing some files like Web UI
|
|
||||||
can be beneficial to be resilient to filesystem errors.
|
|
||||||
|
|
||||||
|
|
||||||
In order to use packed filesystem do the following:
|
|
||||||
|
|
||||||
1. Build **pack** tool from test/pack.c:
|
|
||||||
```sh
|
|
||||||
$ cc -o pack pack.c
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Convert list of files into single .c:
|
|
||||||
```sh
|
|
||||||
$ ./pack index.html style.css > packed_fs.c
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Build your app with `packed_fs.c`:
|
|
||||||
```sh
|
|
||||||
$ cc mongoose.c app.c packed_fs.c -DMG_ENABLE_PACKED_FS=1
|
|
||||||
```
|
|
||||||
|
|
||||||
<img src="images/packed.svg" alt="packed filesystem" />
|
|
||||||
|
|
||||||
4. In your application code:
|
|
||||||
```c
|
|
||||||
struct mg_http_serve_opts opts = {}; // Initialise empty options
|
|
||||||
opts.fs = &mg_fs_packed; // Use packed filesystem
|
|
||||||
opts.root_dir = "/"; // Set root directory
|
|
||||||
mg_http_serve_dir(c, hm, &opts); // Serve directory
|
|
||||||
```
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg viewBox="-5.229 8.358 512.162 263.062" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<image width="512.162" height="263.062" x="-5.229" y="8.358" style="" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAArkAAAFmCAYAAABp3oLTAAAAAXNSR0IArs4c6QAAIABJREFUeF7sXQdYFUcXva9TBQEr9t4ARewFNVbsGhG7wRI1UeyixhLRoGLsXZNYYu8NxQJ2FMGKBcWCSAdp0l79v7PPMe8nqEhRILvfh+B7u7MzZ2Z3ztw5914B8QePAI8AjwCPAI8AjwCPAI8Aj0ARQ0BQxNrDN4dHgEeAR4BHgEeAR4BHgEeAR4B4kssPAh4BHgEeAR4BHgEeAR4BHoEihwBPcotcl/IN4hHgEeAR4BHgEeAR4BHgEeBJLj8GeAR4BHgEeAR4BHgEeAR4BIocAjzJLUJdOmnSpIFxcTGW27fv/F0gEKiLUNP4pvAI8AjwCPAI8AjwCPAIfBECPMn9IrgK9snW1tYX79+/39rYxPh1N4duG4cMGbLewcEhqWDXmq8djwCPAI8AjwCPAI8Aj0DeI8CT3LzH9JuVWL9+/YfPX72s06qVPb18+UoTFR4RbN+23YlxY0Yu6NChQ+I3qxh/Yx4BHgEeAR4BHgEeAR6Br4wAT3K/MuD5eTsrG+ug9Ax1jV/d3EgpV9DVq9fp6pUrFBMVGdisRbMj/fsN2DZoUN8X+VkHvmweAR4BHgEeAR4BHgEegYKAAE9yC0Iv5FEdrKxsglIz1DXmL3AjIgHJpHqUnJREd+/cIW/v8xQVFfHStr6198iRwxY4Ojq+zqPb8sXwCPAI8AjwCPAI8AjwCBQ4BHiSW+C6JOcVsrJu8FiuEtea7jqLRAIRqVVqkojFJJNJSalUkN/Na3ThwlmKjAx7ZtfE7tTg4cPXDOrLW3Zzjjh/JY8AjwCPAI8AjwCPQEFFgCe5BbVnclAvKyubh2lKYZ3ZcxaQQEOkUROJxSKSy+WED4oZG5I8PZXu3r9HFy6cp5BXL17XqV372kjnkfOHDXN6moNb8pfwCPAI8AjwCPAI8AjwCBRIBHiSWyC7JWeVqmdl/SBDLao3a/Y8juASCUmtIRIKhKTRqEmjUZKABGRsbEzv3qXQ06eP6OqVi/Tgwf2whg3rew4Z4Lj8hx9+eJKzu/NX8QjwCPAI8AjwCPAI8AgUHAR4kltw+iLXNalnZX0/Qy2y0iW5GpBcoYg0GhVHdAUCAalUahKLxaQnk1BGeiqFvnlN3hfO0f17dyOq16zuPbj/9+4///zzw1xXiC+AR4BHgEeAR4BHgEeAR+AbIcCT3G8EfH7c9lMkl0hNarWKky/AwqtQKEggIJKIRSQSCUmjVtHz4Gd07rwXBT64H1q5UgUv5+FDfh8/fjxv2c2PzuLL5BHgEeAR4BHgEeARyFcEeJKbr/B+3cKzkitoLblauQKIrlKpJJFI8t6iC9Ir5qy8GAgymYwU8gwKCwuliz4X6Kafb2T5cqWv9e7b181t7tx7X7c1/N14BHgEeAR4BHgEeAR4BHKOAE9yc45dgbvSyso6MF0tqptZriAQCEmtVpJYLOTqrNEISKPRcORXrdaQSoXvxCQSibR/i0QkEhKFhLygS5cvUkDArQjz4qbnBjkNWjxnzozHBa7hfIV4BHgEeAR4BHgEeAR4BDIhwJPcIjQk6llZPZRrJHVmzZrLEVnO8UxNnNUWVlytJldLcrWHhvsO5BbyBcTWhX5XpVJxMgapVEwqlZzevHlDvtev0PWrlyNLlyxxxdGxr9vcuXMfFCHo+KbwCPAI8AjwCPAI8AgUMQR4kluEOrSelfUjhUZce+ZHSC5IrfZHa9EF8dXGGsMwYD9CsGIu/hhHijVEBoZ6XJzdmOgIunzxAt28cSNcX1//yvd9+6xesmTR9SIEId8UHgEeAR4BHgEeAR6BIoIAT3KLSEeiGfWsrB8rNOJaOSO5DAghZ92FBVir19WQQiHXOqgJ1Zx1Nzo6mi6cP093bgfEaTQq/8EDB3j89tuCC0UISr4pPAI8AjwCPAI8AjwChRwBnuQW8g7UrX49K+snCo24ZvZJLq6GZZcd+Fur14XDGrS8IpH4PelVEWmUpNaoSCKRklQsotDQ13TnTgD5eJ9P0NfT83Xo6rBq7arfvYoQpHxTvjICPj4+eqmpqabp6elikUgk0NPTSylfvvy7unXryr9yVfjb8QjwCPAI8AgUcgR4klvIO1C3+nWtrIOUGnGNLyG5SA6hpbpMyqAhlRqaXDERibhoDNDpqtVqEomFJBQKSKlQkFBAJJVKQYkpOSmBrl27QhcvXkxSKxT+ffr0XLt69YojRQhavin5gIC/v7/k8uXLTZ88edLh2bNnjRISEsySkpKMU1JS9BQKhVAgEKgNDQ3lUqk0w8TEJMXS0jKsevXqV6pVq3ZrzJgxvvlQJb5IHgEeAR4BHoEihABPcotQZ9arZ/1UQeLq2SW5ILiC905oILkagYYEpCYVtLhQ7Ko1nFMaky9oBAIuexq9TywhEuJ6LT02MJBR/Ns4juz6+fklJycnXOndo9uWtWvXHi1CEPNNyQME1q5da3vu3LnxT548qR8eHl4xOTm5uE6xiHWHIcXl7HsvFoeInBOSS6VSTbFixaIrVKjwxNra2qdz5857nJz4lNR50C3frIi7d+/WDQ0NbfjmzZsaISEhFeLi4iwSExMN09PTEQEmUU9PL8TY2DiqdOnSTytUqPDa0tLyjYODw5tvVmH+xjwCPAKFBgGe5Baarvp8RRnJRQgxaGoRRQG/ESpMyxkyO55lXSYXjIEjuYjGwJzUtFEa1NAxvA8/pj1H9U+UBqGQZFIJxcW9pUePHpDXmZPvMlKT73Xp1m3L5g3rtn++BfwZRRkBd3f3NidPnpwWGBhok5iYaPm+rSpjY+NQc3PzpyVKlHhXunTpRGNjY5WBgYEIx9u3bw0SEhKMo6KiikdGRprEx8eXUSgUxiC/GI9ly5aNsLa2vjlo0KC5gwcP5iN+FIIBpNFoBK9fvx7i4+Mz/PLlyy38/f2l0PmnpKQQiC3eO5BMoX/x7kK0FxxisViur6+fUKxYsYQqVaqE29raXm7WrNkRR0fHu4Wg2XwVc4jAw4cPpS9evCiRnJxsnJaWJhMIBCI9Pb1UExOTBAcHhyiBAO7R/MEj8BE+wwNTdBAAyVUKJJwlNzck90sRYRMSF3pMIuEc1lQqBSkyUunevTt07uzZjKioiBs9uzls3rbtj91fWj5/fuFGYOfOndW2b9++zM/Pr2lycnIpjUajNjMze1KtWrUXzZo1S6pXr16V+vXrNzQxMZEUK1aMS0qCMYRDLpdzP/Hx8fT8+XO6f/8+PXv27K2fn1/GmzdvDJOSkophzJUtWzasffv224YPH/57q1at4gs3YkWz9iC39+/fn3X27Nlpnp6eJkFBQVy/pqWlcWQW/a6vr096enrcb/Qr3ikIb5iRkcERYJyLv1mcbzMzs0g7Ozu/Ll26bHBxcTlTNJH7b7XqxIkTlrdu3er86NGjjmFhYSVjY2PNEhMTTdLS0vQVCoUEq1uZTKbU09NLNjIyijM3N48uV67cyyZNmpysUaPGw169eoX+txDjW/spBHhLbhEaH9Y29Z8qSVJ9husvpFKxUGFwJIPZ6x/N7T8hxPKm8bC44AcTEou7q4EVmNSkpyejlHfJdOeOP13wvpARGx15r327trsmT3bZYGdnh+C8/FGEEZg2bdqAw4cPz3n+/HltmPwtLCzu29vbB3Tr1q2Kra1tm/Lly5OhoSFHchixhSUPPxhPID7swP9BdGDxA0Hy9fUlLy+v9Js3b2pSUlL0oRG3tbW9MWzYMJexY8f6FWFYC13THj161Mvb23v1vn37yqPv4uLiOKJqampKlpaWVLVqVapSpQr3u0yZMoTFDsguDvR3QkIChYWF0evXr+np06cUHBycERYWpkpJSTHAOSYmJolNmjS57uzs/IuTk9PtQgcQX2Fyd3fv5+PjM/bx48e1oqOjS2ZkZIgwn2Cc4N0hEok0EokEc4ZGoVBIVSoVi3vJoWdgYJBYsmTJ6Dp16jy1t7f/c8aMGYd5WHkEeJJbhMZA/QYNgxQkrjF9+ixSKrHdB6lB/pNcQAjtLiMnDFKRSEhKhZJEYhEZ6EkpJeUdPX70kC6c96LwyDDfFi2bHRg6YMDWnj17JhehbuCbQkQ+Pj7iLVu2/H706NFBqamp5sWKFXtlZ2d3w9nZuXybNm1agNiwA5Y5zomR6WSyQJCNLbagYtvYgYGBdOTIETpw4IAa5EmlUglh1Rk6dKjrb7/9tp/vjG+PwNmzZ5ft3LlzyokTJzjCisWKubk5NWjQgNq0aUOtWrWimjVrcp9ppVUfP7DISUpKoocPH9KFCxfo2rVrbwIDAxWxsbGVcVX58uVfd+3adevgwYNXtmzZkn+vfPvu/2wNXF1dB3l7e4978uSJbVJSkh6ecbFYrDI0NBSUKlVKiHdFiRIlyNjYmIyMjLh5hi18sFiKiIhAWMuMd+/eCZVKpQSk2MTEJLVmzZq3O3fuvPHXX3/dzUsaPtsNRfYEnuQWoa5taNcoSEGSGlOmupJSoX5PPDkJbb5acrXaXW3mNLxg8H8cAkxYXDgyDYmFQhLAUY3wvYIeBj6gs+fO0Juw0KB2rdp4OjkNX9SnT/u4ItQd/9mm+Pj4mC5atGjb1atXu6Snp0urVKlyrWfPnqEDBgxwql27NkdoMVYYoXlvqeHGEJO+ALwP4+j9TgEjwex8kCWUk5iYCFJNhw8fpvPnz8sjIyOlJUqUiHV0dFy0bt26lf/ZjigADd+2bdu+rVu3Ovr7+3N9W7x4cWrRogV1796dmjdvTuXKlfuwwGH9qjsGuPfI+/7XhjbU/qDfU1NTKSQkhLy9veXHjx9/fPPmzdJJSUmlIHNo2rTppfHjx493dHTkddoFYBxkVYWNGzfa7NixY+n9+/ebvHv3zLine truncated
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 163 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg viewBox="-11.551 4.783 524.391 265.184" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<image width="524.391" height="265.184" style="" x="-11.551" y="4.783" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAr4AAAFjCAYAAADbzwgZAAAAAXNSR0IArs4c6QAAIABJREFUeF7sXQdYVEcXvVvYpQqiYsUWuyJgb7E3sJcQo7Fgxd4FrFhjrLF3FHuLDewFRMUGCip2QRQRFaV3dvf/zuDohh8EpAjyJh8fxH1v3syZ2Tdn7px7r4iEIiAgICAgICAgICAgICAgICAgUAAQEBWAPgpdFBAQEBAQEBAQEBAQEBAQEBAQIIH4CpNAQEBAQEBAQEBAQEBAQEBAoEAgIBDfAjHMQicFBAQEBAQEBAQEBAQEBAQEBOIrzAEBAQEBAQEBAQEBAQEBAQGBAoGAQHwLxDALnRQQEBAQEBAQEBAQEBAQEBAQiK8wBwQEBAQEBAQEBAQEBAQEBAQKBAIC8S0Qwyx0UkBAQEBAQEBAQEBAQEBAQEAgvgVgDhw/flxv5syZ66tWrRrcr1+/hT169AgrAN0WuiggICAgICAgICAgICAg8B8EBOJbACaEk5NT6YEDB/pLpVJp0aJFnjRp0vR4nz59lltZWX0oAN0XuiggICAgICAgICAgICAgwBAQiG8BmAhbt24tZ2Nj49utW3ed4sWLk4eHB717F/yscePG5/v06fO3lZXVqwIAg9BFAQEBAQEBAQEBAQGBAo6AQHwLwATYsmVLhWHDhj+bPM1e0qJFGwoJCSHf+z50yfUiBb4JfF7XzPzw4MED1lpZWb0pAHAIXRQQEBAQEBAQEBAQECigCAjEtwAM/I4dO34ZNGjIk/GT7ST1GzalxIRE0tHWpMjISHr69BGdPXuGAl48e1K3bh3n4cMHQwIRXABgEbooICAgICAgICAgICBQwBAQiG8BGPCtW7dWGjp0xGNGfBs1o4T4BFIpFSQRi0lbW5tiYiLp2dPHdOH8OfLze36/Vo0axwYPttnQv3+vtwUAHqGLAgICAgICAgICAgICBQQBgfgWgIF2cnKqMnDg4EfjJ9uJGzRsRgkJiUzdDeKbkJhAEpGItOQyUqiU9ND3AV29cpke+D54WrNmjTOD+vdZMHjwYMEJrgDME6GLAgICAgICAgICAj87AgLx/dlHmIi2b99ezdp66MPxk+1EjPgmJVFSkoJEIhFpSCWkVCpIpVQxJDQ1ZSRSqejJ06d0xf0yPX784H7FCsb7f/+t16YxY8Z8LABwCV0UEBAQEBAQEBAQEBD4SREQiO9POrDq3XJ0dKwxePAw3/GT7ahBo2YUG5dAYomYFAoFScUSUqmSSS+KWESkTEokbR0dUiqV5Of3jK5dcaW7d7weGhuXdu77x++LJ06cKMQBLgDzRuiigICAgICAgICAwM+GgEB8f7YRTaU/27dvN7G2HnZv4lR7qtegKcXGxzNrr3rB/6sUSpJIQISVjPRKxBKSSsQklRAFBLykixfPk7f3XS+jYkWODhrQd9OUKVNCCgB8QhcFBAQEBAQEBAQEBAR+EgQE4vuTDOS3urFli1PtYcOG+HDiG5eQkOrlmAww/v5nUqhUzAoMSYREIqagt0F0/twZuuN167Gevt7FP/v8NtPBwUGwABeAeSR0UUBAQEBAQEBAQCC/IyAQ3/w+ghlo//bt282srYfdTY/48qpEX5UPzDKMH8giJCIiOZzgFEkUHPyGPDyukdvlSz6G+voH/+xr9Y+Dg0NMBpojXCIgICAgICAgICAgICAg8EMQEIjvD4E9dx+6dauT+dChQ+5w4hsfn7rFV71Vqi8zAxIIIpUIxFdMKkggpGKSSsWkIZFQ8LtguuzmRrdv3nygrS073qVT+7+WLVsWnbs9FJ4mICAgICAgICAgICAgIJA+AgLxTR+jfH+Fo6NjncGDh3t9Jb6J6fTpq8lXxbTAKlKSiml+SakkpUr52SlOycivXC6noDdv6NatG3TZ9aynplxy2MLCYsOaNWsi8j14QgcEBAQEBAQEBAQEBAR+GgQE4vvTDGXaHeHEd9JUe6rboCnFx4P4pjX0IL1qxJdUJBKLSCSWkFKhYHcplEoSi0SMCCuTFMwRTltbi90XFRFCV69eVrlfdnuWpEhy69Wj2+xVq1a9KwAwC13MQQRUKpVIJFIX4eTgw4SqBQQEBAQEBAR+WgQE4vvTDu3XjjHiO8TGa8o0ezKv1+gz8c3+jmMySSUiksmkLB3y1SvuSIbxKDY25kgfq+7/LF++XIgCkf2w/zQ1qlQqDQ8Pj5qvXr2q8erVq9oBAQHmERERhWJjY2WJiYkiqVSqKFKkSHThwoUDy5Qpc7dSpUoPS5cufd/U1DTwpwFB6IiAgICAgICAQI4iIBDfHIU3b1SeW8QXvU1WRihZQgwdHS0KDw+lO163ydX10ovYmMgr7dq0W75t28YHeQMZoRV5AYFz587V8/Dw+NPT07P1y5cvSwUGBupHRkZKcZLAC481zcPwyWQyhaGhYXS5cuXCTE1NnzVo0GBno0aNXGrWrPkpL/RJaMP3IfDhwwe9z3OgelRUVOHo6OhCRKTU0dGJ0tPTCylcuPDLEiVKvK1ataqwif4+iIW7BAQKPAIC8S0AUyA3iS9EEkiBDCkEMsKBCMtlUoqOjmIE+NKliwEfQz6e69DJYvMux02eBQB+oYtpIODs7Nz4yJEjM93c3OoHBAQUA7kFsUUsaW1tbdLS0mI/0JBLpVJKSkqi6Ohoio2Npfj4ePaTmJisV9fX14+qXr36406dOu3r1q3bHhMTE0Fekw9mnq+vr+zt27fV7t+/3/7evXttnz17Vubt27eGMTExenFxcZpxcXESSFzkcnmSTCaL19TUjDI0NAyrUKHCm7p167qbmpperV69+p1ffvklPB90V2jidyDg7++vqVQq5UqlUpaUlKSUyWSYCwnGxsax31GdcIuAQJpCTwGanwiBXCW+KjGRCBZfJYnEYpKKYQBWMgKspanJJBDe3nfIze3yu48hwbfbtGq6YdeuXad+IriFrqSDwKVLl6oeOnRoyqlTpzq/fv26BAivjo4OFS5cmKpWrcp+qlevTuXKlQOhJU1NTRKLxZSQkEARERFsDj148ICeP39Ojx8/Jn9/fwoPT+Y9mpqaCSYmJj4DBw78a+TIkUeFwcibCLx48ULf3d29vbOz87gHDx5UDgoKMoqKivqPIQabIJlMxjqAsVfPMIl/09HRURYuXPhjrVq1nrVo0eJI69atjzRs2NA/b/ZYaFVGEbh8+XIFf3//On5+fi3evn1rFhQUZBgVFSWPj4+XiMVilba2dlKhQoXiSpQo8bp06dKe5cuXv161atVH9erVe5XRZwjXFWwEBItvARj/3CS+iUlKFutXJCZSJCYxCx4sdWI4yKmgARaTXFNGUVHR9OD+Xbrkejbs/bt3l5s1buJ46ND+EwVgOApsF2G5OXLkSJ9t27ZNffr0aTWFQiE2MDAgExMTRnR79OjB/jYyMmJW35TZBdWBAwmC9Rfk9/r16+Tu7k5XrlxhpDgqKooKFSoU2rFjxzODBg2a3bFjx+cFFvQ81vHg4GCdf//99zdnZ+fR169frx4eHq6DJsKiX6xYsYjixYtHFStWLL5s2bKKQoUKgdzCq5FiYmKkYWFh0qCgIMnHjx813r17p/n27VvdhIQEtobp6OhEmpmZPWnXrt2+Xr16CRb/PDbu6TXn2rVr5c6fP9//7t27HR8+fFguMDCwWGxsrDy9+zBvihQpEleuXLm31apVu9+oUaNDTZs2dRN0/+khV7A/F4hvARh/xPEdYWNzZ9IUWzKt04ASEpJyrNdiiZSSFElM5sDJC/S+mGhikZhFgED0B2SBQyxgRVIc+T54QBcvXIh+GeB/u3XrlhsO7tt9MMcaKFT8QxDw9fUtsWTJkvXHjx9vFR4ebgD5Qu3atal79+7UsWNHqlatGmloaHxOmZ0cVYQnT0mtwZA4YH7BEoyN1du3b+nJkye0a9cucnV1pTdv3rDPzM3NPW1sbCYOGTLk6g/puPDQLwicOXOmwbZt2xZfunSpwcePHxnhLVSoUJSJiUlE06ZNk8zNzUtWqlRJo2TJkkzqAmsv5gQKxhg/kLl8+PCB/Pz8YPVP8vDwiHzw4IE4ICBAH9dpa2tHt2jR4vaff/65uF+/fmcF+PM2Aq6urpWcnZ0nnTp1ysLf37885Eu86OnpJRQqVChGX18/XldXN0lHR0eB9SMqKkocFhYmiYiIkOFdkpCQIOHvC2yWqlWr9qRbt26OHTt23F2nTp2gvI2A0LofgYBAfH8E6rn8TGRuG24z5u6kybZkYlYvR4kvidkr6P97qFRLB/f502QyrCKxBPGBFfTk8SM6f/Fs7KuX/lcbNai7Z/DgQYe6dOkiZIPL5fmS3Y+7fft2xSVLlmw7ceJESxxZ6+npUf/+/alfv35kZmbGpAwgNbDepCxpWX1TOrtxYgQpxMmTJ2nnzp3MEoznVapU6fmQIUMm2dnZOWd334T6MobAypUrh+/bt2/q7du3K2HsDAwMEhs3bvxx9OjRhapVq6ZtbGzMSC7Gm2u906oZWST5vAgJCaE7d+7QoUOHkk6ePJn47t07xFWkihUr+ltZWW3p37//JsHhMWNjlJtX4fRn/fr105ydnQc+fvy4IieuhoaGH83NzRPMzMxkNWvWLAK5U6lSpdg7Aj8oOOnBqQ42u8+fPw++f/9+hI+Pj9zX19cgMjKSbYAgnTI1NfXp37//Ihsbm8Mikeirp2xudlR4Vp5EQCC+eXJYsrdR27btMrUZZeMNi29ts/o5Fs6MtVr8/wQX/8wWs/98BOuvilnlxBIRiZQq0pRrUFxCHPn7PafzZ08rnj9/+qBuXXPnoYMH/dOzZ8+P2YuKUFtuIHDt2rVf5syZs+fSpUsNMdY1atSg4cOHU6dOnahs2bKfZTBiZr1NrXxL7qB+PSxBLine truncated
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 158 KiB |
@@ -1,384 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 858.5 424.3" style="enable-background:new 0 0 858.5 424.3;" xml:space="preserve">
|
|
||||||
<style type="text/css">
|
|
||||||
.st0{fill:#9E9B83;}
|
|
||||||
.st1{fill:#9E8900;}
|
|
||||||
.st2{font-family:Arial;font-weight:bold;}
|
|
||||||
.st3{font-size:11px;}
|
|
||||||
.st4{display:none;fill:#576174;}
|
|
||||||
.st5{fill:#1F5F75;}
|
|
||||||
.st6{clip-path:url(#SVGID_3_);fill:#FFFFFF;fill-opacity:0.1;}
|
|
||||||
.st7{fill:#277691;}
|
|
||||||
.st8{fill:#FFFFFF;}
|
|
||||||
.st9{font-family:Arial;font-weight:bold;}
|
|
||||||
.st10{fill:#004219;}
|
|
||||||
.st11{clip-path:url(#SVGID_6_);fill:#FFFFFF;fill-opacity:0.1;}
|
|
||||||
.st12{fill:#005721;}
|
|
||||||
.st13{fill:url(#SVGID_7_);}
|
|
||||||
.st14{clip-path:url(#XMLID_13_);fill:#FFFFFF;fill-opacity:0.1;}
|
|
||||||
.st15{fill:#752E06;}
|
|
||||||
.st16{fill:#963B08;}
|
|
||||||
.st17{fill:#59008F;}
|
|
||||||
.st18{clip-path:url(#XMLID_15_);fill:#FFFFFF;fill-opacity:0.1;}
|
|
||||||
.st19{fill:#7300B8;}
|
|
||||||
.st20{fill:#FFDE00;}
|
|
||||||
.st21{fill:#576174;}
|
|
||||||
.st22{font-size:13px;}
|
|
||||||
.st23{fill:#8A8C8E;}
|
|
||||||
.st24{font-size:12px;}
|
|
||||||
.st25{opacity:0.69;}
|
|
||||||
.st26{fill:#B3B1B3;}
|
|
||||||
.st27{clip-path:url(#XMLID_17_);fill:#FFFFFF;fill-opacity:0.1;}
|
|
||||||
.st28{fill:#919091;}
|
|
||||||
.st29{fill:#BFBEBF;}
|
|
||||||
.st30{fill:#454445;}
|
|
||||||
.st31{font-size:9px;}
|
|
||||||
.st32{clip-path:url(#XMLID_19_);fill:#FFFFFF;fill-opacity:0.1;}
|
|
||||||
.st33{fill:#8695B3;}
|
|
||||||
.st34{fill:url(#SVGID_8_);}
|
|
||||||
.st35{font-size:18px;}
|
|
||||||
.st36{clip-path:url(#XMLID_20_);fill:#610041;fill-opacity:0.1;}
|
|
||||||
.st37{fill:#610041;}
|
|
||||||
.st38{clip-path:url(#XMLID_22_);fill:url(#SVGID_9_);fill-opacity:0.1;}
|
|
||||||
.st39{fill:none;stroke:#86005B;stroke-width:0.5;stroke-linecap:round;stroke-miterlimit:10;}
|
|
||||||
.st40{fill:none;stroke:#86005B;stroke-width:0.75;stroke-linecap:round;stroke-miterlimit:10;}
|
|
||||||
.st41{fill:url(#SVGID_10_);}
|
|
||||||
.st42{fill:url(#SVGID_11_);}
|
|
||||||
.st43{fill:#610042;}
|
|
||||||
.st44{fill:url(#SVGID_12_);}
|
|
||||||
</style>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path class="st0" d="M457.9,111.2l0.1,87.3c0,1.4-1.1,2.6-2.5,2.6h-76.3c-4.4-0.2-7.3-3.9-7.3-5.3l4.7-101.8
|
|
||||||
c0-1.4,0.8-7.4,2.2-7.4l54-0.1L457.9,111.2z"/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<text transform="matrix(1 0 0 1 383.2604 149.9447)" class="st1 st2 st3">packed_fs.c</text>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<rect x="84" y="25" class="st4" width="727.7" height="429.8"/>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path class="st5" d="M207.5,104.6v87.4c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6V84.5c0-1.4,1.1-2.5,2.5-2.5h58
|
|
||||||
L207.5,104.6z"/>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<path id="SVGID_1_" d="M205.5,102.6v87.4c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6v-57.5V82.5c0-1.4,1.1-2.5,2.5-2.5
|
|
||||||
h58L205.5,102.6z"/>
|
|
||||||
</defs>
|
|
||||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="122.1091" y1="136.2824" x2="205.5191" y2="136.2824">
|
|
||||||
<stop offset="0" style="stop-color:#45CFFF"/>
|
|
||||||
<stop offset="1" style="stop-color:#85DDFA"/>
|
|
||||||
</linearGradient>
|
|
||||||
<use xlink:href="#SVGID_1_" style="overflow:visible;fill:url(#SVGID_2_);"/>
|
|
||||||
<clipPath id="SVGID_3_">
|
|
||||||
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<path class="st6" d="M121.4,101.4c9.4,0.7,36.6,1.5,53.2,14.7c25,20,31.2,47.1,31.2,47.1l0.4,35.3l-84.8,0.2V101.4z"/>
|
|
||||||
</g>
|
|
||||||
<path class="st5" d="M205.9,104.4l-20.6,0c-1.4,0-2.6-1.2-2.6-2.6l0-21.8l22.9,22.7L205.9,104.4z"/>
|
|
||||||
<path class="st7" d="M205.7,102.8h-20.5c-1.4,0-2.5-1.1-2.5-2.5V79.9l0,0l22.9,22.7L205.7,102.8z"/>
|
|
||||||
<g>
|
|
||||||
<text transform="matrix(1 0 0 1 129.0689 92.8531)" class="st8 st9 st3">filex.y</text>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<path class="st10" d="M191.4,121.6V209c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6V101.4c0-1.4,1.1-2.5,2.5-2.5h58
|
|
||||||
L191.4,121.6z"/>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<path id="SVGID_4_" d="M189.4,119.6V207c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6v-57.5V99.4c0-1.4,1.1-2.5,2.5-2.5
|
|
||||||
h58L189.4,119.6z"/>
|
|
||||||
</defs>
|
|
||||||
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="106.0386" y1="153.2384" x2="189.4486" y2="153.2384">
|
|
||||||
<stop offset="0" style="stop-color:#00983A"/>
|
|
||||||
<stop offset="1" style="stop-color:#3A985D"/>
|
|
||||||
</linearGradient>
|
|
||||||
<use xlink:href="#SVGID_4_" style="overflow:visible;fill:url(#SVGID_5_);"/>
|
|
||||||
<clipPath id="SVGID_6_">
|
|
||||||
<use xlink:href="#SVGID_4_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<path class="st11" d="M105.3,118.3c9.4,0.7,36.6,1.5,53.2,14.7c25,20,31.2,47.1,31.2,47.1l0.4,35.3l-84.8,0.2V118.3z"/>
|
|
||||||
</g>
|
|
||||||
<path class="st10" d="M189.8,121.3l-20.6,0c-1.4,0-2.6-1.2-2.6-2.6l0-21.8l22.9,22.7L189.8,121.3z"/>
|
|
||||||
<path class="st12" d="M189.6,119.7h-20.5c-1.4,0-2.5-1.1-2.5-2.5V96.9l0,0l22.9,22.7L189.6,119.7z"/>
|
|
||||||
<g>
|
|
||||||
<text transform="matrix(1 0 0 1 113.9984 109.809)" class="st8 st9 st3">main.js</text>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="93.2369" y1="173.2516" x2="176.6469" y2="173.2516">
|
|
||||||
<stop offset="0" style="stop-color:#EA5B0C"/>
|
|
||||||
<stop offset="1" style="stop-color:#EA671E"/>
|
|
||||||
</linearGradient>
|
|
||||||
<path class="st13" d="M176.6,139.6V227c0,1.4-1.1,2.6-2.5,2.6H95.8c-1.4,0-2.5-1.1-2.5-2.6V119.5c0-1.4,1.1-2.5,2.5-2.5h58
|
|
||||||
L176.6,139.6z"/>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<path id="XMLID_2_" d="M174.6,137.6V225c0,1.4-1.1,2.6-2.5,2.6H93.8c-1.4,0-2.5-1.1-2.5-2.6v-57.5v-50.1c0-1.4,1.1-2.5,2.5-2.5
|
|
||||||
h58L174.6,137.6z"/>
|
|
||||||
</defs>
|
|
||||||
<linearGradient id="XMLID_12_" gradientUnits="userSpaceOnUse" x1="91.2369" y1="171.2516" x2="174.6469" y2="171.2516">
|
|
||||||
<stop offset="0" style="stop-color:#EA5B0C"/>
|
|
||||||
<stop offset="1" style="stop-color:#EA7B3D"/>
|
|
||||||
</linearGradient>
|
|
||||||
<use xlink:href="#XMLID_2_" style="overflow:visible;fill:url(#XMLID_12_);"/>
|
|
||||||
<clipPath id="XMLID_13_">
|
|
||||||
<use xlink:href="#XMLID_2_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<path class="st14" d="M90.5,136.3c9.4,0.7,36.6,1.5,53.2,14.7c25,20,31.2,47.1,31.2,47.1l0.4,35.3l-84.8,0.2V136.3z"/>
|
|
||||||
</g>
|
|
||||||
<path class="st15" d="M175,139.3l-20.6,0c-1.4,0-2.6-1.2-2.6-2.6l0-21.8l22.9,22.7L175,139.3z"/>
|
|
||||||
<path class="st16" d="M174.8,137.7h-20.5c-1.4,0-2.5-1.1-2.5-2.5v-20.3l0,0l22.9,22.7L174.8,137.7z"/>
|
|
||||||
<g>
|
|
||||||
<text transform="matrix(1 0 0 1 97.1967 127.8222)" class="st8 st9 st3">style.css</text>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<path class="st17" d="M164.6,157.7v87.4c0,1.4-1.1,2.6-2.5,2.6H83.8c-1.4,0-2.5-1.1-2.5-2.6V137.5c0-1.4,1.1-2.5,2.5-2.5h58
|
|
||||||
L164.6,157.7z"/>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<path id="XMLID_1_" d="M162.6,155.7v87.4c0,1.4-1.1,2.6-2.5,2.6H81.8c-1.4,0-2.5-1.1-2.5-2.6v-57.5v-50.1c0-1.4,1.1-2.5,2.5-2.5
|
|
||||||
h58L162.6,155.7z"/>
|
|
||||||
</defs>
|
|
||||||
<linearGradient id="XMLID_14_" gradientUnits="userSpaceOnUse" x1="79.2009" y1="189.3131" x2="162.6108" y2="189.3131">
|
|
||||||
<stop offset="0" style="stop-color:#A000FF"/>
|
|
||||||
<stop offset="1" style="stop-color:#C96EFF"/>
|
|
||||||
</linearGradient>
|
|
||||||
<use xlink:href="#XMLID_1_" style="overflow:visible;fill:url(#XMLID_14_);"/>
|
|
||||||
<clipPath id="XMLID_15_">
|
|
||||||
<use xlink:href="#XMLID_1_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<path class="st18" d="M78.5,154.4c9.4,0.7,36.6,1.5,53.2,14.7c25,20,31.2,47.1,31.2,47.1l0.4,35.3l-84.8,0.2V154.4z"/>
|
|
||||||
</g>
|
|
||||||
<path class="st17" d="M163,157.4l-20.6,0c-1.4,0-2.6-1.2-2.6-2.6l0-21.8l22.9,22.7L163,157.4z"/>
|
|
||||||
<path class="st19" d="M162.8,155.8h-20.5c-1.4,0-2.5-1.1-2.5-2.5V133l0,0l22.9,22.7L162.8,155.8z"/>
|
|
||||||
<g>
|
|
||||||
<text transform="matrix(1 0 0 1 83.1607 145.8838)" class="st8 st9 st3">index.html</text>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path class="st20" d="M455.2,108.2v87.4c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6V88.1c0-1.4,1.1-2.5,2.5-2.5h58
|
|
||||||
L455.2,108.2z"/>
|
|
||||||
<path class="st0" d="M455.3,110.3l-18.4,0c-1.4,0-2.5-1.1-2.5-2.5V87.5l0,0l20.9,20.7L455.3,110.3z"/>
|
|
||||||
<polygon class="st0" points="435.2,109.7 432.9,107.3 436.3,106.9 "/>
|
|
||||||
<path class="st1" d="M455.4,108.3h-20.5c-1.4,0-2.5-1.1-2.5-2.5V85.5l0,0l22.9,22.7L455.4,108.3z"/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<text transform="matrix(1 0 0 1 379.2604 144.9447)" class="st21 st9 st22">packed_fs.c</text>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<polygon class="st23" points="483.6,195.4 397.3,195.4 394.3,193.4 397.3,162.8 481.5,159.7 483.6,162.8 "/>
|
|
||||||
<rect x="394.3" y="159.8" class="st21" width="87.3" height="33.7"/>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<text transform="matrix(1 0 0 1 400.0845 171.7588)" class="st8 st9 st24">mg_unpack()</text>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<text transform="matrix(1 0 0 1 400.0845 186.935)" class="st8 st9 st24">mg_unlist()</text>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g class="st25">
|
|
||||||
<g>
|
|
||||||
<path class="st26" d="M467.7,256.6V344c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6V236.4c0-1.4,1.1-2.5,2.5-2.5h58
|
|
||||||
L467.7,256.6z"/>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<path id="XMLID_9_" d="M465.7,254.6V342c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6v-57.5v-50.1c0-1.4,1.1-2.5,2.5-2.5
|
|
||||||
h58L465.7,254.6z"/>
|
|
||||||
</defs>
|
|
||||||
<linearGradient id="XMLID_16_" gradientUnits="userSpaceOnUse" x1="382.3115" y1="288.2073" x2="465.7215" y2="288.2073">
|
|
||||||
<stop offset="0" style="stop-color:#D6D4D6"/>
|
|
||||||
<stop offset="1" style="stop-color:#FFFDFE"/>
|
|
||||||
</linearGradient>
|
|
||||||
<use xlink:href="#XMLID_9_" style="overflow:visible;fill:url(#XMLID_16_);"/>
|
|
||||||
<clipPath id="XMLID_17_">
|
|
||||||
<use xlink:href="#XMLID_9_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<path class="st27" d="M381.6,253.3c9.4,0.7,36.6,1.5,53.2,14.7c25,20,31.2,47.1,31.2,47.1l0.4,35.3l-84.8,0.2V253.3z"/>
|
|
||||||
</g>
|
|
||||||
<path class="st28" d="M466.1,256.3l-20.6,0c-1.4,0-2.6-1.2-2.6-2.6l0-21.8l22.9,22.7L466.1,256.3z"/>
|
|
||||||
<path class="st29" d="M465.9,254.7h-20.5c-1.4,0-2.5-1.1-2.5-2.5v-20.3l0,0l22.9,22.7L465.9,254.7z"/>
|
|
||||||
<text transform="matrix(1 0 0 1 386.2713 244.7779)" class="st30 st9 st31">mongoose.c</text>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<path class="st26" d="M455.7,276.6v87.4c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6V256.5c0-1.4,1.1-2.5,2.5-2.5h58
|
|
||||||
L455.7,276.6z"/>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<path id="XMLID_8_" d="M453.7,274.6v87.4c0,1.4-1.1,2.6-2.5,2.6h-78.3c-1.4,0-2.5-1.1-2.5-2.6v-57.5v-50.1
|
|
||||||
c0-1.4,1.1-2.5,2.5-2.5h58L453.7,274.6z"/>
|
|
||||||
</defs>
|
|
||||||
<linearGradient id="XMLID_18_" gradientUnits="userSpaceOnUse" x1="370.2755" y1="308.2689" x2="453.6855" y2="308.2689">
|
|
||||||
<stop offset="0" style="stop-color:#D6D4D6"/>
|
|
||||||
<stop offset="1" style="stop-color:#FFFDFE"/>
|
|
||||||
</linearGradient>
|
|
||||||
<use xlink:href="#XMLID_8_" style="overflow:visible;fill:url(#XMLID_18_);"/>
|
|
||||||
<clipPath id="XMLID_19_">
|
|
||||||
<use xlink:href="#XMLID_8_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<path class="st32" d="M369.6,273.3c9.4,0.7,36.6,1.5,53.2,14.7c25,20,31.2,47.1,31.2,47.1l0.4,35.3l-84.8,0.2V273.3z"/>
|
|
||||||
<use xlink:href="#XMLID_8_" style="overflow:visible;fill:none;stroke:#FFFDFE;stroke-width:0.25;stroke-miterlimit:10;"/>
|
|
||||||
</g>
|
|
||||||
<path class="st28" d="M454,276.4l-20.6,0c-1.4,0-2.6-1.2-2.6-2.6l0-21.8l22.9,22.7L454,276.4z"/>
|
|
||||||
<path class="st29" d="M453.8,274.8h-20.5c-1.4,0-2.5-1.1-2.5-2.5v-20.3l0,0l22.9,22.7L453.8,274.8z"/>
|
|
||||||
<text transform="matrix(1 0 0 1 379.2353 264.8395)" class="st30 st9 st31">app.c</text>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<polygon class="st33" points="342.3,123.3 351.1,141.7 342.3,160.7 234.8,160.9 234.8,122.6 "/>
|
|
||||||
<path class="st23" d="M347.4,145.4"/>
|
|
||||||
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="233.6667" y1="139.4088" x2="350.0318" y2="139.4088">
|
|
||||||
<stop offset="0" style="stop-color:#C1D5FF"/>
|
|
||||||
<stop offset="0.1995" style="stop-color:#BACDF6"/>
|
|
||||||
<stop offset="0.6001" style="stop-color:#B0C3EA"/>
|
|
||||||
<stop offset="1" style="stop-color:#ADC0E6"/>
|
|
||||||
</linearGradient>
|
|
||||||
<polygon class="st34" points="341.2,120.9 350,139.3 341.2,158.3 233.7,158.5 233.7,120.3 "/>
|
|
||||||
<text transform="matrix(1 0 0 1 262.9869 146.2633)" class="st8 st9 st35">PACK</text>
|
|
||||||
<polygon class="st33" points="234.8,160.9 233.7,158.5 238,158.7 "/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<path class="st23" d="M634.9,144.6L634.9,144.6z"/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<polygon class="st33" points="619.6,139.3 619.6,139.3 618.7,137.4 618.7,137.4 "/>
|
|
||||||
<path class="st23" d="M623.1,168.2L623.1,168.2z"/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<polygon class="st33" points="619.6,288.1 618.7,290 618.7,290 619.6,288.1 "/>
|
|
||||||
<path class="st23" d="M623.1,259.2L623.1,259.2z"/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<path class="st23" d="M617,282L617,282z"/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<path id="XMLID_10_" d="M722.7,276.5h-71.2c-11.6,0-21.1-9.4-21.1-21.1v-71.2c0-11.6,9.4-21.1,21.1-21.1h71.2
|
|
||||||
c11.6,0,21.1,9.4,21.1,21.1v71.2C743.8,267,734.4,276.5,722.7,276.5z"/>
|
|
||||||
</defs>
|
|
||||||
<use xlink:href="#XMLID_10_" style="overflow:visible;fill:#610041;"/>
|
|
||||||
<clipPath id="XMLID_20_">
|
|
||||||
<use xlink:href="#XMLID_10_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<path class="st36" d="M754.3,172.5c-2.7,8-17.3,30.9-65.8,30.8c-24.5,0-48.4-7.4-65.7-24.7l-12.1-12l69.3-64.6L754.3,172.5z"/>
|
|
||||||
</g>
|
|
||||||
<polygon class="st37" points="637.6,271.2 632.5,266.1 640.3,269.4 "/>
|
|
||||||
<polygon class="st37" points="738.3,169.9 734.6,166.2 736.4,171 "/>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<path id="XMLID_5_" d="M719.7,273.5h-71.2c-11.6,0-21.1-9.4-21.1-21.1v-71.2c0-11.6,9.4-21.1,21.1-21.1h71.2
|
|
||||||
c11.6,0,21.1,9.4,21.1,21.1v71.2C740.8,264,731.4,273.5,719.7,273.5z"/>
|
|
||||||
</defs>
|
|
||||||
<radialGradient id="XMLID_21_" cx="684.119" cy="216.7761" r="56.6929" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop offset="0" style="stop-color:#8B005D;stop-opacity:0.7"/>
|
|
||||||
<stop offset="1" style="stop-color:#8B005D"/>
|
|
||||||
</radialGradient>
|
|
||||||
<use xlink:href="#XMLID_5_" style="overflow:visible;fill:url(#XMLID_21_);"/>
|
|
||||||
<clipPath id="XMLID_22_">
|
|
||||||
<use xlink:href="#XMLID_5_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<radialGradient id="SVGID_9_" cx="678.486" cy="148.5836" r="90.2195" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop offset="0" style="stop-color:#8B005D"/>
|
|
||||||
<stop offset="1" style="stop-color:#FFFFFF"/>
|
|
||||||
</radialGradient>
|
|
||||||
<path class="st38" d="M750.3,168.5c-2.7,8-17.3,30.9-65.8,30.8c-24.5,0-48.4-7.4-65.7-24.7l-12.1-12L676,97.9L750.3,168.5z"/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<text transform="matrix(1 0 0 1 646.3768 216.49)" class="st8 st9 st35">APP.EXE</text>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path class="st8" d="M732,240.1c-0.3-1.4-0.8-2.7-1.4-3.9l1.7-2.3c-0.3-0.5-0.6-0.9-1-1.4c-0.3-0.5-0.7-0.9-1.1-1.3l-2.7,1
|
|
||||||
c-1-1-2.2-1.8-3.4-2.4l0-2.9c-1-0.4-2.1-0.8-3.2-1l-1.5,2.4c-1.4-0.2-2.8-0.2-4.1,0l-1.7-2.4c-1.1,0.2-2.1,0.6-3.1,1.1l0.2,2.9
|
|
||||||
c-0.6,0.3-1.2,0.7-1.7,1.1c-0.6,0.4-1.1,0.9-1.5,1.4l-2.7-0.9l-1.9,2.7l1.8,2.3c-0.6,1.3-1,2.6-1.1,4l-2.7,0.9
|
|
||||||
c-0.1,1.1,0,2.2,0.1,3.3l2.8,0.8c0.3,1.3,0.8,2.7,1.4,3.9l-1.7,2.3c0.3,0.5,0.6,0.9,1,1.4c0.3,0.4,0.7,0.9,1.1,1.3l2.7-1
|
|
||||||
c1,1,2.2,1.8,3.4,2.4l0,2.9c1,0.4,2.1,0.8,3.2,1l1.5-2.4c1.4,0.2,2.8,0.2,4.1,0l1.7,2.4c1.1-0.3,2.1-0.6,3.1-1.1l-0.2-2.9
|
|
||||||
c0.6-0.3,1.2-0.7,1.7-1.1c0.6-0.4,1.1-0.9,1.5-1.4l2.8,0.9c0.7-0.8,1.3-1.8,1.9-2.7L731,249c0.6-1.3,1-2.6,1.1-4l2.7-0.9
|
|
||||||
c0.1-1.1,0-2.2-0.1-3.3L732,240.1z M724,251c-4.6,3.5-11.1,2.6-14.6-2c-3.5-4.6-2.6-11.1,2-14.6s11.1-2.6,14.6,2
|
|
||||||
C729.5,241,728.6,247.5,724,251z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path class="st8" d="M700.5,249.3c-0.2-0.8-0.5-1.6-0.8-2.4l1-1.4c-0.2-0.3-0.4-0.6-0.6-0.8c-0.2-0.3-0.4-0.5-0.7-0.8l-1.6,0.6
|
|
||||||
c-0.6-0.6-1.3-1.1-2.1-1.4l0-1.7c-0.6-0.3-1.3-0.5-1.9-0.6l-0.9,1.4c-0.8-0.1-1.7-0.1-2.5,0l-1-1.4c-0.6,0.1-1.3,0.4-1.9,0.6
|
|
||||||
l0.1,1.7c-0.4,0.2-0.7,0.4-1,0.7c-0.3,0.3-0.6,0.5-0.9,0.8l-1.6-0.6l-1.1,1.6l1.1,1.4c-0.3,0.8-0.6,1.6-0.7,2.4l-1.6,0.5
|
|
||||||
c0,0.7,0,1.3,0.1,2l1.7,0.5c0.2,0.8,0.4,1.6,0.9,2.4l-1,1.4c0.2,0.3,0.4,0.6,0.6,0.8c0.2,0.3,0.4,0.5,0.7,0.8l1.6-0.6
|
|
||||||
c0.6,0.6,1.3,1.1,2.1,1.4l0,1.7c0.6,0.3,1.3,0.5,1.9,0.6l0.9-1.4c0.8,0.1,1.7,0.1,2.5,0l1,1.4c0.6-0.2,1.3-0.4,1.9-0.6l-0.1-1.7
|
|
||||||
c0.4-0.2,0.7-0.4,1-0.7c0.3-0.3,0.6-0.5,0.9-0.8l1.6,0.6c0.4-0.5,0.8-1.1,1.1-1.6l-1.1-1.4c0.3-0.8,0.6-1.6,0.7-2.4l1.6-0.5
|
|
||||||
c0-0.7,0-1.3-0.1-2L700.5,249.3z M694.5,254.2c-1.8,1.4-4.5,1-5.9-0.8c-1.4-1.8-1-4.5,0.8-5.9c1.8-1.4,4.5-1,5.9,0.8
|
|
||||||
C696.8,250.2,696.4,252.8,694.5,254.2z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<path class="st39" d="M708.9,234.5"/>
|
|
||||||
<path class="st39" d="M706.7,237.9"/>
|
|
||||||
<path class="st40" d="M705.7,242.7c0-1.7,0.4-3.4,1-4.9"/>
|
|
||||||
<path class="st40" d="M708.9,234.5c2.2-2.4,5.3-3.8,8.8-3.8"/>
|
|
||||||
<path class="st40" d="M687.4,247.3c1.1-1.4,2.7-2.2,4.6-2.2"/>
|
|
||||||
<path class="st39" d="M686.4,249.5"/>
|
|
||||||
<path class="st40" d="M686.2,250.9c0-0.5,0.1-1,0.2-1.4"/>
|
|
||||||
<path class="st39" d="M686.7,253.2"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<path class="st33" d="M611.7,174.2l-23,3.3l-13.1-9.6c-6.3-4.6-13.9-7.1-21.7-7l-55.5,0.1l-1.1-2.4h1.1l64.2-0.2h0.1l3.9,0h0.1
|
|
||||||
l3.2,2.4l19.2,14l0.2,0.2l23.4-3.3L611.7,174.2z"/>
|
|
||||||
<path class="st23" d="M595.9,145.5L595.9,145.5z"/>
|
|
||||||
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="497.2089" y1="147.636" x2="612.739" y2="147.636">
|
|
||||||
<stop offset="0" style="stop-color:#C1D5FF"/>
|
|
||||||
<stop offset="0.1995" style="stop-color:#BACDF6"/>
|
|
||||||
<stop offset="0.6001" style="stop-color:#B0C3EA"/>
|
|
||||||
<stop offset="1" style="stop-color:#ADC0E6"/>
|
|
||||||
</linearGradient>
|
|
||||||
<path class="st41" d="M612.7,171.7l-3,0.4l-20.3,2.8l-0.2-0.1l-13.6-9.9l0,0c-3.7-2.7-8.7-4.4-12.9-5.4c-2.9-0.7-6-1-9-1l-35.5,0.1
|
|
||||||
l-19.8,0.1h-1.1v-38.3l13.5,0.2l4,0l42.6,0.2l7.9,0c7,0,14,1.6,20.2,4.9c0,0,0,0,0,0c0.8,0.5,1.6,0.9,2.4,1.5l7.5,5.6l0.1,0.1l0,0
|
|
||||||
l15.4,11.3v0l0.1,3.2L612.7,171.7z"/>
|
|
||||||
<linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="597.6228" y1="138.4046" x2="598.5728" y2="138.4046">
|
|
||||||
<stop offset="0" style="stop-color:#C1D5FF"/>
|
|
||||||
<stop offset="0.1995" style="stop-color:#BACDF6"/>
|
|
||||||
<stop offset="0.6001" style="stop-color:#B0C3EA"/>
|
|
||||||
<stop offset="1" style="stop-color:#ADC0E6"/>
|
|
||||||
</linearGradient>
|
|
||||||
<polygon class="st42" points="598.6,139.3 598.6,139.4 597.6,137.4 597.7,137.5 "/>
|
|
||||||
<text transform="matrix(1 0 0 1 513.7678 146.3103)" class="st8 st9 st35">BUILD</text>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<path class="st33" d="M612.7,258.8l-0.1,2.2l-1.8-0.2l-20.3-2.8l-0.2,0.1l-13.6,9.9l0-0.1c-3.7,2.7-8.7,4.4-12.9,5.4
|
|
||||||
c-2.9,0.7-6,1-9,1l-35.5-0.1l-19.8-0.1h-1.1v35.4l-1.1,0.4l1.1,2.4l13.5-0.2l4,0l42.6-0.2l7.9-0.1c7,0,14-1.6,20.2-4.9c0,0,0,0,0,0
|
|
||||||
c0.8-0.5,1.6-0.9,2.4-1.5l7.5-5.6l0.1-0.1l0,0l15.4-11.3l1-0.9l1.9-26.7L612.7,258.8z"/>
|
|
||||||
<path class="st43" d="M593.5,272.5"/>
|
|
||||||
<g>
|
|
||||||
<path class="st23" d="M598.5,285L598.5,285z"/>
|
|
||||||
|
|
||||||
<linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="497.2089" y1="451.0054" x2="612.739" y2="451.0054" gradientTransform="matrix(1 0 0 -1 0 733.8616)">
|
|
||||||
<stop offset="0" style="stop-color:#C1D5FF"/>
|
|
||||||
<stop offset="0.1995" style="stop-color:#BACDF6"/>
|
|
||||||
<stop offset="0.6001" style="stop-color:#B0C3EA"/>
|
|
||||||
<stop offset="1" style="stop-color:#ADC0E6"/>
|
|
||||||
</linearGradient>
|
|
||||||
<path class="st44" d="M612.7,258.8l-3-0.4l-20.3-2.8l-0.2,0.1l-13.6,9.9l0,0c-3.7,2.7-8.7,4.4-12.9,5.4c-2.9,0.7-6,1-9,1
|
|
||||||
l-35.5-0.1l-19.8-0.1h-1.1v38.3l13.5-0.2l4,0l42.6-0.2l7.9,0c7,0,14-1.6,20.2-4.9c0,0,0,0,0,0c0.8-0.5,1.6-0.9,2.4-1.5l7.5-5.6
|
|
||||||
l0.1-0.1l0,0l15.4-11.3v0l0.1-3.2L612.7,258.8z"/>
|
|
||||||
<text transform="matrix(1 0 0 1 513.7682 298.0848)" class="st8 st9 st35">BUILD</text>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<path class="st33" d="M619.9,149.1"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 18 KiB |
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mongoose.c
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mongoose.h
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#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_MIP 1
|
||||||
|
#define mkdir(a, b) (-1)
|
||||||
|
//#define MG_ENABLE_LOG 0
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#include <SPI.h>
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
#define SS_PIN 3 // Slave select pin
|
||||||
|
struct mg_mgr mgr; // Mongoose event manager
|
||||||
|
struct mip_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 mip_if mif = {.mac = {2, 0, 1, 2, 3, 5}}; // MIP 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 = &mip_driver_w5500;
|
||||||
|
mif.driver_data = &spi;
|
||||||
|
mip_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", mip_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, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) mg_http_reply(c, 200, "", "ok\n");
|
||||||
|
},
|
||||||
|
&mgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
mg_mgr_poll(&mgr, 1);
|
||||||
|
}
|
||||||
@@ -3,15 +3,19 @@
|
|||||||
|
|
||||||
#include "mongoose.h"
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
#if !defined(MQTT_SERVER)
|
||||||
#define MQTT_SERVER "mqtt://broker.hivemq.com:1883"
|
#define MQTT_SERVER "mqtt://broker.hivemq.com:1883"
|
||||||
|
#endif
|
||||||
#define MQTT_PUBLISH_TOPIC "mg/my_device"
|
#define MQTT_PUBLISH_TOPIC "mg/my_device"
|
||||||
#define MQTT_SUBSCRIBE_TOPIC "mg/#"
|
#define MQTT_SUBSCRIBE_TOPIC "mg/#"
|
||||||
|
|
||||||
static time_t s_boot_timestamp = 0; // Updated by SNTP
|
static time_t s_boot_timestamp = 0; // Updated by SNTP
|
||||||
|
#ifndef DISABLE_ROUTING
|
||||||
static struct mg_connection *s_sntp_conn = NULL; // SNTP connection
|
static struct mg_connection *s_sntp_conn = NULL; // SNTP connection
|
||||||
|
#endif
|
||||||
|
|
||||||
// Define system time()
|
// Define a system time alternative
|
||||||
time_t time(time_t *tp) {
|
time_t ourtime(time_t *tp) {
|
||||||
time_t t = s_boot_timestamp + (time_t) (mg_millis() / 1000);
|
time_t t = s_boot_timestamp + (time_t) (mg_millis() / 1000);
|
||||||
if (tp != NULL) *tp = t;
|
if (tp != NULL) *tp = t;
|
||||||
return t;
|
return t;
|
||||||
@@ -76,7 +80,7 @@ static struct user *getuser(struct mg_http_message *hm) {
|
|||||||
static void send_notification(struct mg_mgr *mgr, const char *fmt, ...) {
|
static void send_notification(struct mg_mgr *mgr, const char *fmt, ...) {
|
||||||
struct mg_connection *c;
|
struct mg_connection *c;
|
||||||
for (c = mgr->conns; c != NULL; c = c->next) {
|
for (c = mgr->conns; c != NULL; c = c->next) {
|
||||||
if (c->label[0] == 'W') {
|
if (c->data[0] == 'W') {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
mg_ws_vprintf(c, WEBSOCKET_OP_TEXT, fmt, &ap);
|
mg_ws_vprintf(c, WEBSOCKET_OP_TEXT, fmt, &ap);
|
||||||
@@ -88,10 +92,12 @@ static void send_notification(struct mg_mgr *mgr, const char *fmt, ...) {
|
|||||||
// Send simulated metrics data to the dashboard, for chart rendering
|
// Send simulated metrics data to the dashboard, for chart rendering
|
||||||
static void timer_metrics_fn(void *param) {
|
static void timer_metrics_fn(void *param) {
|
||||||
send_notification(param, "{%Q:%Q,%Q:[%lu, %d]}", "name", "metrics", "data",
|
send_notification(param, "{%Q:%Q,%Q:[%lu, %d]}", "name", "metrics", "data",
|
||||||
(unsigned long) time(NULL),
|
(unsigned long) ourtime(NULL),
|
||||||
10 + (int) ((double) rand() * 10 / RAND_MAX));
|
10 + (int) ((double) rand() * 10 / RAND_MAX));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef DISABLE_ROUTING
|
||||||
|
|
||||||
// MQTT event handler function
|
// MQTT event handler function
|
||||||
static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data, void *fnd) {
|
static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data, void *fnd) {
|
||||||
if (ev == MG_EV_CONNECT && mg_url_is_ssl(s_config.url)) {
|
if (ev == MG_EV_CONNECT && mg_url_is_ssl(s_config.url)) {
|
||||||
@@ -103,6 +109,7 @@ static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data, void *fnd) {
|
|||||||
c->is_hexdumping = 1;
|
c->is_hexdumping = 1;
|
||||||
mg_mqtt_sub(s_mqtt, mg_str(s_config.sub), 2);
|
mg_mqtt_sub(s_mqtt, mg_str(s_config.sub), 2);
|
||||||
send_notification(c->mgr, "{%Q:%Q,%Q:null}", "name", "config", "data");
|
send_notification(c->mgr, "{%Q:%Q,%Q:null}", "name", "config", "data");
|
||||||
|
MG_INFO(("MQTT connected, server %s", MQTT_SERVER));
|
||||||
} else if (ev == MG_EV_MQTT_MSG) {
|
} else if (ev == MG_EV_MQTT_MSG) {
|
||||||
struct mg_mqtt_message *mm = ev_data;
|
struct mg_mqtt_message *mm = ev_data;
|
||||||
send_notification(c->mgr, "{%Q:%Q,%Q:{%Q: %.*Q, %Q: %.*Q, %Q: %d}}", "name",
|
send_notification(c->mgr, "{%Q:%Q,%Q:{%Q: %.*Q, %Q: %.*Q, %Q: %d}}", "name",
|
||||||
@@ -111,7 +118,7 @@ static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data, void *fnd) {
|
|||||||
"qos", (int) mm->qos);
|
"qos", (int) mm->qos);
|
||||||
} else if (ev == MG_EV_MQTT_CMD) {
|
} else if (ev == MG_EV_MQTT_CMD) {
|
||||||
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
||||||
MG_DEBUG(("cmd %d qos %d", mm->cmd, mm->qos));
|
MG_DEBUG(("%lu cmd %d qos %d", c->id, mm->cmd, mm->qos));
|
||||||
} else if (ev == MG_EV_CLOSE) {
|
} else if (ev == MG_EV_CLOSE) {
|
||||||
s_mqtt = NULL;
|
s_mqtt = NULL;
|
||||||
if (s_connected) {
|
if (s_connected) {
|
||||||
@@ -126,7 +133,8 @@ static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data, void *fnd) {
|
|||||||
static void timer_mqtt_fn(void *param) {
|
static void timer_mqtt_fn(void *param) {
|
||||||
struct mg_mgr *mgr = (struct mg_mgr *) param;
|
struct mg_mgr *mgr = (struct mg_mgr *) param;
|
||||||
if (s_mqtt == NULL) {
|
if (s_mqtt == NULL) {
|
||||||
struct mg_mqtt_opts opts = {0};
|
struct mg_mqtt_opts opts;
|
||||||
|
memset(&opts, 0, sizeof(opts));
|
||||||
s_mqtt = mg_mqtt_connect(mgr, s_config.url, &opts, mqtt_fn, NULL);
|
s_mqtt = mg_mqtt_connect(mgr, s_config.url, &opts, mqtt_fn, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +144,6 @@ static void timer_mqtt_fn(void *param) {
|
|||||||
static void sfn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
static void sfn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
if (ev == MG_EV_SNTP_TIME) {
|
if (ev == MG_EV_SNTP_TIME) {
|
||||||
uint64_t t = *(uint64_t *) ev_data;
|
uint64_t t = *(uint64_t *) ev_data;
|
||||||
MG_INFO(("%lu SNTP: %lld ms from epoch", c->id, t));
|
|
||||||
s_boot_timestamp = (time_t) ((t - mg_millis()) / 1000);
|
s_boot_timestamp = (time_t) ((t - mg_millis()) / 1000);
|
||||||
c->is_closing = 1;
|
c->is_closing = 1;
|
||||||
} else if (ev == MG_EV_CLOSE) {
|
} else if (ev == MG_EV_CLOSE) {
|
||||||
@@ -152,13 +159,17 @@ static void timer_sntp_fn(void *param) { // SNTP timer function. Sync up time
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// HTTP request handler function
|
// HTTP request handler function
|
||||||
void device_dashboard_fn(struct mg_connection *c, int ev, void *ev_data,
|
void device_dashboard_fn(struct mg_connection *c, int ev, void *ev_data,
|
||||||
void *fn_data) {
|
void *fn_data) {
|
||||||
if (ev == MG_EV_OPEN && c->is_listening) {
|
if (ev == MG_EV_OPEN && c->is_listening) {
|
||||||
mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_metrics_fn, c->mgr);
|
mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_metrics_fn, c->mgr);
|
||||||
|
#ifndef DISABLE_ROUTING
|
||||||
mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_mqtt_fn, c->mgr);
|
mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_mqtt_fn, c->mgr);
|
||||||
mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_sntp_fn, c->mgr);
|
mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_sntp_fn, c->mgr);
|
||||||
|
#endif
|
||||||
s_config.url = strdup(MQTT_SERVER);
|
s_config.url = strdup(MQTT_SERVER);
|
||||||
s_config.pub = strdup(MQTT_PUBLISH_TOPIC);
|
s_config.pub = strdup(MQTT_PUBLISH_TOPIC);
|
||||||
s_config.sub = strdup(MQTT_SUBSCRIBE_TOPIC);
|
s_config.sub = strdup(MQTT_SUBSCRIBE_TOPIC);
|
||||||
@@ -169,13 +180,22 @@ void device_dashboard_fn(struct mg_connection *c, int ev, void *ev_data,
|
|||||||
// u ? u->name : "NULL"));
|
// u ? u->name : "NULL"));
|
||||||
if (mg_http_match_uri(hm, "/api/hi")) {
|
if (mg_http_match_uri(hm, "/api/hi")) {
|
||||||
mg_http_reply(c, 200, "", "hi\n"); // Testing endpoint
|
mg_http_reply(c, 200, "", "hi\n"); // Testing endpoint
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/debug")) {
|
||||||
|
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);
|
||||||
} else if (u == NULL && mg_http_match_uri(hm, "/api/#")) {
|
} else if (u == NULL && mg_http_match_uri(hm, "/api/#")) {
|
||||||
// All URIs starting with /api/ must be authenticated
|
// All URIs starting with /api/ must be authenticated
|
||||||
mg_http_reply(c, 403, "", "Denied\n");
|
mg_http_reply(c, 403, "", "Denied\n");
|
||||||
} else if (mg_http_match_uri(hm, "/api/config/get")) {
|
} else if (mg_http_match_uri(hm, "/api/config/get")) {
|
||||||
|
#ifdef DISABLE_ROUTING
|
||||||
|
mg_http_reply(c, 200, NULL, "{%Q:%Q,%Q:%Q,%Q:%Q}\n", "url", s_config.url,
|
||||||
|
"pub", s_config.pub, "sub", s_config.sub);
|
||||||
|
#else
|
||||||
mg_http_reply(c, 200, NULL, "{%Q:%Q,%Q:%Q,%Q:%Q,%Q:%s}\n", "url",
|
mg_http_reply(c, 200, NULL, "{%Q:%Q,%Q:%Q,%Q:%Q,%Q:%s}\n", "url",
|
||||||
s_config.url, "pub", s_config.pub, "sub", s_config.sub,
|
s_config.url, "pub", s_config.pub, "sub", s_config.sub,
|
||||||
"connected", s_connected ? "true" : "false");
|
"connected", s_connected ? "true" : "false");
|
||||||
|
#endif
|
||||||
} else if (mg_http_match_uri(hm, "/api/config/set")) {
|
} else if (mg_http_match_uri(hm, "/api/config/set")) {
|
||||||
// Admins only
|
// Admins only
|
||||||
if (strcmp(u->name, "admin") == 0) {
|
if (strcmp(u->name, "admin") == 0) {
|
||||||
@@ -196,13 +216,14 @@ void device_dashboard_fn(struct mg_connection *c, int ev, void *ev_data,
|
|||||||
}
|
}
|
||||||
mg_http_reply(c, 200, "", "ok\n");
|
mg_http_reply(c, 200, "", "ok\n");
|
||||||
} else if (mg_http_match_uri(hm, "/api/watch")) {
|
} else if (mg_http_match_uri(hm, "/api/watch")) {
|
||||||
c->label[0] = 'W'; // Mark ourselves as a event listener
|
c->data[0] = 'W'; // Mark ourselves as a event listener
|
||||||
mg_ws_upgrade(c, hm, NULL);
|
mg_ws_upgrade(c, hm, NULL);
|
||||||
} else if (mg_http_match_uri(hm, "/api/login")) {
|
} else if (mg_http_match_uri(hm, "/api/login")) {
|
||||||
mg_http_reply(c, 200, NULL, "{%Q:%Q,%Q:%Q}\n", "user", u->name, "token",
|
mg_http_reply(c, 200, NULL, "{%Q:%Q,%Q:%Q}\n", "user", u->name, "token",
|
||||||
u->token);
|
u->token);
|
||||||
} else {
|
} else {
|
||||||
struct mg_http_serve_opts opts = {0};
|
struct mg_http_serve_opts opts;
|
||||||
|
memset(&opts, 0, sizeof(opts));
|
||||||
#if 1
|
#if 1
|
||||||
opts.root_dir = "/web_root";
|
opts.root_dir = "/web_root";
|
||||||
opts.fs = &mg_fs_packed;
|
opts.fs = &mg_fs_packed;
|
||||||
@@ -211,7 +232,8 @@ void device_dashboard_fn(struct mg_connection *c, int ev, void *ev_data,
|
|||||||
#endif
|
#endif
|
||||||
mg_http_serve_dir(c, ev_data, &opts);
|
mg_http_serve_dir(c, ev_data, &opts);
|
||||||
}
|
}
|
||||||
MG_DEBUG(("%.*s %.*s -> %.*s", (int) hm->method.len, hm->method.ptr,
|
MG_DEBUG(("%lu %.*s %.*s -> %.*s", c->id, (int) hm->method.len,
|
||||||
(int) hm->uri.len, hm->uri.ptr, (int) 3, &c->send.buf[9]));
|
hm->method.ptr, (int) hm->uri.len, hm->uri.ptr, (int) 3,
|
||||||
|
&c->send.buf[9]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2167
-966
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import {Component, h, html, render, useEffect, useState, useRef} from './preact.min.js';
|
import {Component, h, html, render, useEffect, useState, useRef} from './preact.min.js';
|
||||||
|
|
||||||
|
var devaddr = "address:port";
|
||||||
|
|
||||||
const MaxMetricsDataPoints = 50;
|
const MaxMetricsDataPoints = 50;
|
||||||
|
|
||||||
// This simple publish/subscribe is used to pass notifications that were
|
// This simple publish/subscribe is used to pass notifications that were
|
||||||
@@ -53,14 +55,14 @@ const Hero = props => html`
|
|||||||
using <code>curl</code> command-line utility:
|
using <code>curl</code> command-line utility:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div><code>curl -u admin:pass0 localhost:8000/api/config/get</code> </div>
|
<div><code>curl -u admin:pass0 ${devaddr}/api/config/get</code> </div>
|
||||||
<div><code>curl -u admin:pass0 localhost:8000/api/config/set -d 'pub=mg/topic'</code> </div>
|
<div><code>curl -u admin:pass0 ${devaddr}/api/config/set -d 'pub=mg/topic'</code> </div>
|
||||||
<div><code>curl -u admin:pass0 localhost:8000/api/message/send -d 'message=hello'</code> </div>
|
<div><code>curl -u admin:pass0 ${devaddr}/api/message/send -d 'message=hello'</code> </div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The device can send notifications to this dashboard at anytime. Notifications
|
The device can send notifications to this dashboard at anytime. Notifications
|
||||||
are sent over WebSocket at URI <code>/api/watch</code> as JSON strings: <code>{"name": "..", "data": ...}</code>
|
are sent over WebSocket at URI <code>/api/watch</code> as JSON strings: <code>{"name": "..", "data": ...}</code>
|
||||||
<div>Try <code>wscat --auth user1:pass1 --connect ws://localhost:8000/api/watch</code></div>
|
<div>Try <code>wscat --auth user1:pass1 --connect ws://${devaddr}/api/watch</code></div>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
@@ -186,7 +188,8 @@ const Messages = function(props) {
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
body: `message=${encodeURIComponent(txt)}`
|
body: `message=${encodeURIComponent(txt)}`
|
||||||
}).then(r => setTxt(''));
|
}).then(r => setTxt(''));
|
||||||
const connstatus = props.config.connected ? 'connected' : 'disconnected';
|
const routing = "connected" in props.config;
|
||||||
|
const connstatus = !routing ? 'This device has no MQTT functionality' : props.config.connected ? 'connected' : 'disconnected';
|
||||||
return html`
|
return html`
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h3 style="background: #30c040; color: #fff; padding: 0.4em;">MQTT messages</h3>
|
<h3 style="background: #30c040; color: #fff; padding: 0.4em;">MQTT messages</h3>
|
||||||
@@ -199,7 +202,7 @@ const Messages = function(props) {
|
|||||||
<div style="margin: 0.5em 0; display: flex">
|
<div style="margin: 0.5em 0; display: flex">
|
||||||
<span class="addon nowrap">Publish message:</span>
|
<span class="addon nowrap">Publish message:</span>
|
||||||
<input placeholder="type and press enter..." style="flex: 1 100%;"
|
<input placeholder="type and press enter..." style="flex: 1 100%;"
|
||||||
value=${txt} onchange=${sendmessage}
|
value=${txt} onchange=${sendmessage} disabled=${!routing}
|
||||||
oninput=${ev => setTxt(ev.target.value)} />
|
oninput=${ev => setTxt(ev.target.value)} />
|
||||||
</div>
|
</div>
|
||||||
<div class="msg">
|
<div class="msg">
|
||||||
@@ -341,7 +344,11 @@ const App = function(props) {
|
|||||||
const login = function(u) {
|
const login = function(u) {
|
||||||
document.cookie = `access_token=${u.token}; Secure, HttpOnly; SameSite=Lax; path=/; max-age=3600`;
|
document.cookie = `access_token=${u.token}; Secure, HttpOnly; SameSite=Lax; path=/; max-age=3600`;
|
||||||
setUser(u.user);
|
setUser(u.user);
|
||||||
watch();
|
if (location.search.substring(1) == 'nows') {
|
||||||
|
// If query string is ?nows, then do not connect to websocket. For debug.
|
||||||
|
} else {
|
||||||
|
watch(); // Connect to websocket, receive constant graph updates
|
||||||
|
}
|
||||||
return getconfig();
|
return getconfig();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -35,4 +35,4 @@ 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
|
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:
|
clean:
|
||||||
$(DOCKER) rm -rf build sdkconfig
|
test -d build && $(DOCKER) rm -rf build sdkconfig || true
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
THISDIR = $(realpath $(CURDIR))
|
THISDIR = $(realpath $(CURDIR))
|
||||||
ROOTDIR = $(realpath $(CURDIR)/../..)
|
ROOTDIR = $(realpath $(CURDIR)/../../..)
|
||||||
DOCKER ?= docker run --rm $(DA) -v $(ROOTDIR):$(ROOTDIR) -w $(THISDIR) docker.io/mdashnet/8266
|
DOCKER ?= docker run --rm $(DA) -v $(ROOTDIR):$(ROOTDIR) -w $(THISDIR) docker.io/mdashnet/8266
|
||||||
CMD ?= make -C src defconfig app
|
CMD ?= make -C src defconfig app
|
||||||
PORT ?= /dev/ttyUSB0
|
PORT ?= /dev/ttyUSB0
|
||||||
@@ -41,6 +41,5 @@ monitor: build
|
|||||||
.PHONY: build
|
.PHONY: build
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
clean: CMD = rm -rf src/build
|
test -d src/build && $(DOCKER) rm -rf src/build || true
|
||||||
clean: build
|
|
||||||
|
|
||||||
File renamed without changes.
File renamed without changes.
+1
-1
@@ -7,4 +7,4 @@
|
|||||||
# please read the ESP-IDF documents if you need to do this.
|
# please read the ESP-IDF documents if you need to do this.
|
||||||
#
|
#
|
||||||
|
|
||||||
COMPONENT_INCLUDES += ../../../../..
|
COMPONENT_INCLUDES += ../../../../../..
|
||||||
File renamed without changes.
@@ -0,0 +1 @@
|
|||||||
|
../../../../../mongoose.c
|
||||||
File renamed without changes.
@@ -0,0 +1,524 @@
|
|||||||
|
#
|
||||||
|
# Automatically generated file. DO NOT EDIT.
|
||||||
|
# Espressif IoT Development Framework (ESP-IDF) Project Configuration
|
||||||
|
#
|
||||||
|
CONFIG_IDF_TARGET_ESP8266=y
|
||||||
|
CONFIG_IDF_TARGET="esp8266"
|
||||||
|
|
||||||
|
#
|
||||||
|
# SDK tool configuration
|
||||||
|
#
|
||||||
|
CONFIG_SDK_TOOLPREFIX="xtensa-lx106-elf-"
|
||||||
|
CONFIG_SDK_PYTHON="python"
|
||||||
|
# CONFIG_SDK_MAKE_WARN_UNDEFINED_VARIABLES is not set
|
||||||
|
CONFIG_BOOTLOADER_INIT_SPI_FLASH=y
|
||||||
|
# CONFIG_BOOTLOADER_DISABLE_JTAG_IO is not set
|
||||||
|
# CONFIG_BOOTLOADER_FAST_BOOT is not set
|
||||||
|
# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set
|
||||||
|
# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set
|
||||||
|
# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set
|
||||||
|
CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y
|
||||||
|
# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set
|
||||||
|
# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set
|
||||||
|
CONFIG_LOG_BOOTLOADER_LEVEL=3
|
||||||
|
# CONFIG_BOOTLOADER_APP_TEST is not set
|
||||||
|
CONFIG_BOOTLOADER_STORE_OFFSET=0x0
|
||||||
|
CONFIG_ESPTOOLPY_PORT="/dev/ttyACM0"
|
||||||
|
CONFIG_ESPTOOLPY_BAUD_115200B=y
|
||||||
|
# CONFIG_ESPTOOLPY_BAUD_230400B is not set
|
||||||
|
# CONFIG_ESPTOOLPY_BAUD_921600B is not set
|
||||||
|
# CONFIG_ESPTOOLPY_BAUD_2MB is not set
|
||||||
|
# CONFIG_ESPTOOLPY_BAUD_OTHER is not set
|
||||||
|
CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200
|
||||||
|
CONFIG_ESPTOOLPY_BAUD=115200
|
||||||
|
CONFIG_ESPTOOLPY_COMPRESSED=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
|
||||||
|
# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set
|
||||||
|
# CONFIG_ESPTOOLPY_FLASHMODE_DIO is not set
|
||||||
|
# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set
|
||||||
|
CONFIG_ESPTOOLPY_FLASHMODE="dio"
|
||||||
|
CONFIG_SPI_FLASH_MODE=0x0
|
||||||
|
# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set
|
||||||
|
CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
|
||||||
|
# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set
|
||||||
|
# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
|
||||||
|
CONFIG_ESPTOOLPY_FLASHFREQ="40m"
|
||||||
|
CONFIG_SPI_FLASH_FREQ=0x0
|
||||||
|
# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
|
||||||
|
# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
|
||||||
|
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||||
|
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
|
||||||
|
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
|
||||||
|
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
|
||||||
|
CONFIG_SPI_FLASH_SIZE=0x400000
|
||||||
|
CONFIG_ESPTOOLPY_BEFORE_RESET=y
|
||||||
|
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
|
||||||
|
CONFIG_ESPTOOLPY_BEFORE="default_reset"
|
||||||
|
CONFIG_ESPTOOLPY_AFTER_HARD_RESET=y
|
||||||
|
# CONFIG_ESPTOOLPY_AFTER_SOFT_RESET is not set
|
||||||
|
# CONFIG_ESPTOOLPY_AFTER_NORESET is not set
|
||||||
|
CONFIG_ESPTOOLPY_AFTER="hard_reset"
|
||||||
|
# CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set
|
||||||
|
# CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set
|
||||||
|
# CONFIG_ESPTOOLPY_MONITOR_BAUD_74880B is not set
|
||||||
|
CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
|
||||||
|
# CONFIG_ESPTOOLPY_MONITOR_BAUD_230400B is not set
|
||||||
|
# CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B is not set
|
||||||
|
# CONFIG_ESPTOOLPY_MONITOR_BAUD_2MB is not set
|
||||||
|
# CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set
|
||||||
|
CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=74880
|
||||||
|
CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
|
||||||
|
CONFIG_PARTITION_TABLE_SINGLE_APP=y
|
||||||
|
# CONFIG_PARTITION_TABLE_TWO_OTA is not set
|
||||||
|
# CONFIG_PARTITION_TABLE_CUSTOM is not set
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||||
|
CONFIG_PARTITION_TABLE_OFFSET=0x8000
|
||||||
|
CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv"
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y
|
||||||
|
# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
|
||||||
|
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
|
||||||
|
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
|
||||||
|
# CONFIG_COMPILER_CXX_EXCEPTIONS is not set
|
||||||
|
CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
|
||||||
|
# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set
|
||||||
|
# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set
|
||||||
|
# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set
|
||||||
|
# CONFIG_COMPILER_STACK_CHECK is not set
|
||||||
|
# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set
|
||||||
|
CONFIG_APP_UPDATE_CHECK_APP_SUM=y
|
||||||
|
# CONFIG_APP_UPDATE_CHECK_APP_HASH is not set
|
||||||
|
CONFIG_APP_COMPILE_TIME_DATE=y
|
||||||
|
# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set
|
||||||
|
# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set
|
||||||
|
# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set
|
||||||
|
# CONFIG_ENABLE_COAP is not set
|
||||||
|
CONFIG_ESP_TLS_USING_MBEDTLS=y
|
||||||
|
# CONFIG_ESP_TLS_USING_WOLFSSL is not set
|
||||||
|
# CONFIG_ESP_TLS_SERVER is not set
|
||||||
|
# CONFIG_ESP_TLS_PSK_VERIFICATION is not set
|
||||||
|
# CONFIG_ESP_WOLFSSL_INTERNAL is not set
|
||||||
|
# CONFIG_WOLFSSL_DEBUG is not set
|
||||||
|
CONFIG_ESP8266_NMI_WDT=y
|
||||||
|
# CONFIG_ESP8266_XTAL_FREQ_40 is not set
|
||||||
|
CONFIG_ESP8266_XTAL_FREQ_26=y
|
||||||
|
CONFIG_ESP8266_XTAL_FREQ=26
|
||||||
|
# CONFIG_ESP8266_DEFAULT_CPU_FREQ_80 is not set
|
||||||
|
CONFIG_ESP8266_DEFAULT_CPU_FREQ_160=y
|
||||||
|
CONFIG_ESP8266_DEFAULT_CPU_FREQ_MHZ=160
|
||||||
|
CONFIG_ESP_FILENAME_MACRO_NO_PATH=y
|
||||||
|
# CONFIG_ESP_FILENAME_MACRO_RAW is not set
|
||||||
|
# CONFIG_ESP_FILENAME_MACRO_NULL is not set
|
||||||
|
CONFIG_USING_NEW_ETS_VPRINTF=y
|
||||||
|
# CONFIG_LINK_ETS_PRINTF_TO_IRAM is not set
|
||||||
|
CONFIG_ETS_PRINTF_EXIT_WHEN_FLASH_RW=y
|
||||||
|
# CONFIG_SOC_FULL_ICACHE is not set
|
||||||
|
CONFIG_SOC_IRAM_SIZE=0xC000
|
||||||
|
# CONFIG_DISABLE_ROM_UART_PRINT is not set
|
||||||
|
# CONFIG_ESP_PANIC_PRINT_HALT is not set
|
||||||
|
CONFIG_ESP_PANIC_PRINT_REBOOT=y
|
||||||
|
# CONFIG_ESP_PANIC_SILENT_REBOOT is not set
|
||||||
|
# CONFIG_ESP_PANIC_GDBSTUB is not set
|
||||||
|
CONFIG_RESET_REASON=y
|
||||||
|
CONFIG_WIFI_PPT_TASKSTACK_SIZE=5120
|
||||||
|
CONFIG_ESP8266_CORE_GLOBAL_DATA_LINK_IRAM=y
|
||||||
|
# CONFIG_ESP8266_OTA_FROM_OLD is not set
|
||||||
|
# CONFIG_ESP8266_BOOT_COPY_APP is not set
|
||||||
|
CONFIG_ESP8266_TIME_SYSCALL_USE_FRC1=y
|
||||||
|
# CONFIG_ESP8266_TIME_SYSCALL_USE_NONE is not set
|
||||||
|
# CONFIG_PM_ENABLE is not set
|
||||||
|
CONFIG_SCAN_AP_MAX=99
|
||||||
|
CONFIG_WIFI_TX_RATE_SEQUENCE_FROM_HIGH=y
|
||||||
|
# CONFIG_ESP8266_WIFI_QOS_ENABLED is not set
|
||||||
|
# CONFIG_ESP8266_WIFI_AMPDU_RX_ENABLED is not set
|
||||||
|
# CONFIG_ESP8266_WIFI_AMSDU_ENABLED is not set
|
||||||
|
CONFIG_ESP8266_WIFI_RX_BUFFER_NUM=16
|
||||||
|
CONFIG_ESP8266_WIFI_LEFT_CONTINUOUS_RX_BUFFER_NUM=16
|
||||||
|
CONFIG_ESP8266_WIFI_RX_PKT_NUM=7
|
||||||
|
CONFIG_ESP8266_WIFI_TX_PKT_NUM=6
|
||||||
|
CONFIG_ESP8266_WIFI_NVS_ENABLED=y
|
||||||
|
CONFIG_ESP8266_WIFI_CONNECT_OPEN_ROUTER_WHEN_PWD_IS_SET=y
|
||||||
|
CONFIG_ESP8266_WIFI_ENABLE_WPA3_SAE=y
|
||||||
|
# CONFIG_ESP8266_WIFI_DEBUG_LOG_ENABLE is not set
|
||||||
|
CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
|
||||||
|
# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set
|
||||||
|
CONFIG_ESP_PHY_INIT_DATA_VDD33_CONST=33
|
||||||
|
CONFIG_ESP8266_PHY_MAX_WIFI_TX_POWER=20
|
||||||
|
# CONFIG_ESP8266_HSPI_HIGH_THROUGHPUT is not set
|
||||||
|
CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
|
||||||
|
CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
|
||||||
|
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2048
|
||||||
|
CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584
|
||||||
|
CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584
|
||||||
|
CONFIG_ESP_CONSOLE_UART_DEFAULT=y
|
||||||
|
# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set
|
||||||
|
# CONFIG_ESP_CONSOLE_UART_NONE is not set
|
||||||
|
CONFIG_ESP_CONSOLE_UART_NUM=0
|
||||||
|
CONFIG_ESP_CONSOLE_UART_BAUDRATE=74880
|
||||||
|
# CONFIG_ESP_UART0_SWAP_IO is not set
|
||||||
|
CONFIG_ESP_TASK_WDT=y
|
||||||
|
CONFIG_ESP_TASK_WDT_PANIC=y
|
||||||
|
# CONFIG_ESP_TASK_WDT_TIMEOUT_13N is not set
|
||||||
|
# CONFIG_ESP_TASK_WDT_TIMEOUT_14N is not set
|
||||||
|
CONFIG_ESP_TASK_WDT_TIMEOUT_15N=y
|
||||||
|
CONFIG_ESP_TASK_WDT_TIMEOUT_S=15
|
||||||
|
# CONFIG_ESP_EVENT_LOOP_PROFILING is not set
|
||||||
|
CONFIG_ESP_EVENT_POST_FROM_ISR=y
|
||||||
|
CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
|
||||||
|
# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set
|
||||||
|
CONFIG_HTTP_BUF_SIZE=512
|
||||||
|
CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
|
||||||
|
CONFIG_HTTPD_MAX_URI_LEN=512
|
||||||
|
CONFIG_OTA_BUF_SIZE=256
|
||||||
|
# CONFIG_OTA_ALLOW_HTTP is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set
|
||||||
|
CONFIG_FATFS_CODEPAGE_437=y
|
||||||
|
# CONFIG_FATFS_CODEPAGE_720 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_737 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_771 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_775 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_850 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_852 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_855 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_857 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_860 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_861 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_862 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_863 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_864 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_865 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_866 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_869 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_932 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_936 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_949 is not set
|
||||||
|
# CONFIG_FATFS_CODEPAGE_950 is not set
|
||||||
|
CONFIG_FATFS_CODEPAGE=437
|
||||||
|
CONFIG_FATFS_LFN_NONE=y
|
||||||
|
# CONFIG_FATFS_LFN_HEAP is not set
|
||||||
|
# CONFIG_FATFS_LFN_STACK is not set
|
||||||
|
CONFIG_FATFS_FS_LOCK=0
|
||||||
|
CONFIG_FATFS_TIMEOUT_MS=10000
|
||||||
|
CONFIG_FATFS_PER_FILE_CACHE=y
|
||||||
|
CONFIG_FMB_COMM_MODE_TCP_EN=y
|
||||||
|
CONFIG_FMB_TCP_PORT_DEFAULT=502
|
||||||
|
CONFIG_FMB_TCP_PORT_MAX_CONN=5
|
||||||
|
CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20
|
||||||
|
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150
|
||||||
|
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200
|
||||||
|
CONFIG_FMB_QUEUE_LENGTH=20
|
||||||
|
CONFIG_FMB_PORT_TASK_STACK_SIZE=4096
|
||||||
|
CONFIG_FMB_SERIAL_BUF_SIZE=256
|
||||||
|
CONFIG_FMB_PORT_TASK_PRIO=10
|
||||||
|
CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT=y
|
||||||
|
CONFIG_FMB_CONTROLLER_SLAVE_ID=0x00112233
|
||||||
|
CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20
|
||||||
|
CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
|
||||||
|
CONFIG_FMB_CONTROLLER_STACK_SIZE=4096
|
||||||
|
CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20
|
||||||
|
CONFIG_FMB_TIMER_GROUP=0
|
||||||
|
CONFIG_FMB_TIMER_INDEX=0
|
||||||
|
# CONFIG_FMB_TIMER_ISR_IN_IRAM is not set
|
||||||
|
# CONFIG_DISABLE_FREERTOS is not set
|
||||||
|
CONFIG_FREERTOS_UNICORE=y
|
||||||
|
# CONFIG_FREERTOS_ENABLE_REENT is not set
|
||||||
|
CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF
|
||||||
|
CONFIG_FREERTOS_HZ=100
|
||||||
|
CONFIG_FREERTOS_MAX_HOOK=2
|
||||||
|
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1024
|
||||||
|
CONFIG_FREERTOS_ISR_STACKSIZE=512
|
||||||
|
# CONFIG_FREERTOS_EXTENED_HOOKS is not set
|
||||||
|
CONFIG_FREERTOS_GLOBAL_DATA_LINK_IRAM=y
|
||||||
|
# CONFIG_FREERTOS_CODE_LINK_TO_IRAM is not set
|
||||||
|
CONFIG_FREERTOS_TIMER_STACKSIZE=2048
|
||||||
|
CONFIG_TASK_SWITCH_FASTER=y
|
||||||
|
# CONFIG_USE_QUEUE_SETS is not set
|
||||||
|
# CONFIG_ENABLE_FREERTOS_SLEEP is not set
|
||||||
|
# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set
|
||||||
|
# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set
|
||||||
|
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
|
||||||
|
# CONFIG_HEAP_DISABLE_IRAM is not set
|
||||||
|
# CONFIG_HEAP_TRACING is not set
|
||||||
|
CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y
|
||||||
|
# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
|
||||||
|
# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
|
||||||
|
# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set
|
||||||
|
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
|
||||||
|
# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
|
||||||
|
# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
|
||||||
|
CONFIG_LOG_DEFAULT_LEVEL=3
|
||||||
|
CONFIG_LOG_COLORS=y
|
||||||
|
# CONFIG_LOG_SET_LEVEL is not set
|
||||||
|
CONFIG_LWIP_LOCAL_HOSTNAME="espressif"
|
||||||
|
CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
|
||||||
|
# CONFIG_LWIP_L2_TO_L3_COPY is not set
|
||||||
|
# CONFIG_LWIP_IRAM_OPTIMIZATION is not set
|
||||||
|
CONFIG_LWIP_TIMERS_ONDEMAND=y
|
||||||
|
CONFIG_LWIP_MAX_SOCKETS=10
|
||||||
|
# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
|
||||||
|
# CONFIG_LWIP_SO_LINGER is not set
|
||||||
|
CONFIG_LWIP_SO_REUSE=y
|
||||||
|
CONFIG_LWIP_SO_REUSE_RXTOALL=y
|
||||||
|
# CONFIG_LWIP_SO_RCVBUF is not set
|
||||||
|
# CONFIG_LWIP_NETBUF_RECVINFO is not set
|
||||||
|
CONFIG_LWIP_IP4_FRAG=y
|
||||||
|
CONFIG_LWIP_IP6_FRAG=y
|
||||||
|
# CONFIG_LWIP_IP4_REASSEMBLY is not set
|
||||||
|
# CONFIG_LWIP_IP6_REASSEMBLY is not set
|
||||||
|
# CONFIG_LWIP_IP_FORWARD is not set
|
||||||
|
# CONFIG_LWIP_STATS is not set
|
||||||
|
# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
|
||||||
|
CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
|
||||||
|
CONFIG_LWIP_GARP_TMR_INTERVAL=60
|
||||||
|
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
|
||||||
|
CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y
|
||||||
|
# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set
|
||||||
|
CONFIG_LWIP_DHCPS_LEASE_UNIT=60
|
||||||
|
CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8
|
||||||
|
# CONFIG_LWIP_AUTOIP is not set
|
||||||
|
# CONFIG_LWIP_IPV6_AUTOCONFIG is not set
|
||||||
|
CONFIG_LWIP_NETIF_LOOPBACK=y
|
||||||
|
CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
|
||||||
|
CONFIG_LWIP_MAX_ACTIVE_TCP=16
|
||||||
|
CONFIG_LWIP_MAX_LISTENING_TCP=16
|
||||||
|
CONFIG_LWIP_TCP_MAXRTX=12
|
||||||
|
CONFIG_LWIP_TCP_SYNMAXRTX=6
|
||||||
|
CONFIG_LWIP_TCP_MSS=1440
|
||||||
|
CONFIG_LWIP_TCP_TMR_INTERVAL=250
|
||||||
|
CONFIG_LWIP_TCP_MSL=60000
|
||||||
|
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=2880
|
||||||
|
CONFIG_LWIP_TCP_WND_DEFAULT=5760
|
||||||
|
CONFIG_LWIP_TCP_RECVMBOX_SIZE=6
|
||||||
|
CONFIG_LWIP_TCP_QUEUE_OOSEQ=y
|
||||||
|
# CONFIG_LWIP_TCP_SACK_OUT is not set
|
||||||
|
# CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
|
||||||
|
CONFIG_LWIP_TCP_OVERSIZE_MSS=y
|
||||||
|
# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set
|
||||||
|
# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set
|
||||||
|
CONFIG_LWIP_TCP_RTO_TIME=3000
|
||||||
|
CONFIG_LWIP_MAX_UDP_PCBS=16
|
||||||
|
CONFIG_LWIP_UDP_RECVMBOX_SIZE=6
|
||||||
|
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=2048
|
||||||
|
CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
|
||||||
|
# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set
|
||||||
|
CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF
|
||||||
|
# CONFIG_LWIP_PPP_SUPPORT is not set
|
||||||
|
CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3
|
||||||
|
CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5
|
||||||
|
# CONFIG_LWIP_MULTICAST_PING is not set
|
||||||
|
# CONFIG_LWIP_BROADCAST_PING is not set
|
||||||
|
CONFIG_LWIP_MAX_RAW_PCBS=16
|
||||||
|
# CONFIG_LWIP_IPV6 is not set
|
||||||
|
CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1
|
||||||
|
CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
|
||||||
|
CONFIG_LWIP_ESP_LWIP_ASSERT=y
|
||||||
|
# CONFIG_LWIP_DEBUG is not set
|
||||||
|
CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
|
# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
|
||||||
|
# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
|
||||||
|
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
|
||||||
|
CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
|
||||||
|
CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
|
||||||
|
# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set
|
||||||
|
# CONFIG_MBEDTLS_DEBUG is not set
|
||||||
|
CONFIG_MBEDTLS_HAVE_TIME=y
|
||||||
|
# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set
|
||||||
|
CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y
|
||||||
|
# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set
|
||||||
|
# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set
|
||||||
|
# CONFIG_MBEDTLS_TLS_DISABLED is not set
|
||||||
|
CONFIG_MBEDTLS_TLS_SERVER=y
|
||||||
|
CONFIG_MBEDTLS_TLS_CLIENT=y
|
||||||
|
CONFIG_MBEDTLS_TLS_ENABLED=y
|
||||||
|
# CONFIG_MBEDTLS_PSK_MODES is not set
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y
|
||||||
|
CONFIG_MBEDTLS_SSL_RENEGOTIATION=y
|
||||||
|
# CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set
|
||||||
|
CONFIG_MBEDTLS_SSL_PROTO_TLS1=y
|
||||||
|
CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y
|
||||||
|
CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y
|
||||||
|
# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set
|
||||||
|
CONFIG_MBEDTLS_SSL_ALPN=y
|
||||||
|
CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y
|
||||||
|
CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y
|
||||||
|
CONFIG_MBEDTLS_AES_C=y
|
||||||
|
# CONFIG_MBEDTLS_CAMELLIA_C is not set
|
||||||
|
# CONFIG_MBEDTLS_DES_C is not set
|
||||||
|
CONFIG_MBEDTLS_RC4_DISABLED=y
|
||||||
|
# CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set
|
||||||
|
# CONFIG_MBEDTLS_RC4_ENABLED is not set
|
||||||
|
# CONFIG_MBEDTLS_BLOWFISH_C is not set
|
||||||
|
# CONFIG_MBEDTLS_XTEA_C is not set
|
||||||
|
CONFIG_MBEDTLS_CCM_C=y
|
||||||
|
CONFIG_MBEDTLS_GCM_C=y
|
||||||
|
# CONFIG_MBEDTLS_RIPEMD160_C is not set
|
||||||
|
CONFIG_MBEDTLS_PEM_PARSE_C=y
|
||||||
|
CONFIG_MBEDTLS_PEM_WRITE_C=y
|
||||||
|
CONFIG_MBEDTLS_X509_CRL_PARSE_C=y
|
||||||
|
CONFIG_MBEDTLS_X509_CSR_PARSE_C=y
|
||||||
|
CONFIG_MBEDTLS_ECP_C=y
|
||||||
|
CONFIG_MBEDTLS_ECDH_C=y
|
||||||
|
CONFIG_MBEDTLS_ECDSA_C=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_NIST_OPTIM=y
|
||||||
|
# CONFIG_util_assert is not set
|
||||||
|
# CONFIG_ESP_SHA is not set
|
||||||
|
CONFIG_ESP_AES=y
|
||||||
|
CONFIG_ESP_MD5=y
|
||||||
|
CONFIG_ESP_ARC4=y
|
||||||
|
# CONFIG_ENABLE_MDNS is not set
|
||||||
|
CONFIG_MQTT_PROTOCOL_311=y
|
||||||
|
CONFIG_MQTT_TRANSPORT_SSL=y
|
||||||
|
CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
|
||||||
|
CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
|
||||||
|
# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set
|
||||||
|
# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set
|
||||||
|
# CONFIG_MQTT_CUSTOM_OUTBOX is not set
|
||||||
|
CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y
|
||||||
|
# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set
|
||||||
|
# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set
|
||||||
|
CONFIG_NEWLIB_NANO_FORMAT=y
|
||||||
|
# CONFIG_OPENSSL_DEBUG is not set
|
||||||
|
CONFIG_OPENSSL_ASSERT_DO_NOTHING=y
|
||||||
|
# CONFIG_OPENSSL_ASSERT_EXIT is not set
|
||||||
|
CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5
|
||||||
|
CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
|
||||||
|
CONFIG_PTHREAD_STACK_MIN=768
|
||||||
|
CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread"
|
||||||
|
CONFIG_SPIFFS_MAX_PARTITIONS=3
|
||||||
|
CONFIG_SPIFFS_CACHE=y
|
||||||
|
CONFIG_SPIFFS_CACHE_WR=y
|
||||||
|
# CONFIG_SPIFFS_CACHE_STATS is not set
|
||||||
|
CONFIG_SPIFFS_PAGE_CHECK=y
|
||||||
|
CONFIG_SPIFFS_GC_MAX_RUNS=10
|
||||||
|
# CONFIG_SPIFFS_GC_STATS is not set
|
||||||
|
CONFIG_SPIFFS_PAGE_SIZE=256
|
||||||
|
CONFIG_SPIFFS_OBJ_NAME_LEN=32
|
||||||
|
CONFIG_SPIFFS_USE_MAGIC=y
|
||||||
|
CONFIG_SPIFFS_USE_MAGIC_LENGTH=y
|
||||||
|
CONFIG_SPIFFS_META_LENGTH=4
|
||||||
|
CONFIG_SPIFFS_USE_MTIME=y
|
||||||
|
# CONFIG_SPIFFS_DBG is not set
|
||||||
|
# CONFIG_SPIFFS_API_DBG is not set
|
||||||
|
# CONFIG_SPIFFS_GC_DBG is not set
|
||||||
|
# CONFIG_SPIFFS_CACHE_DBG is not set
|
||||||
|
# CONFIG_SPIFFS_CHECK_DBG is not set
|
||||||
|
# CONFIG_SPIFFS_TEST_VISUALISATION is not set
|
||||||
|
CONFIG_IP_LOST_TIMER_INTERVAL=120
|
||||||
|
CONFIG_TCPIP_ADAPTER_GLOBAL_DATA_LINK_IRAM=y
|
||||||
|
CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y
|
||||||
|
CONFIG_VFS_SUPPORT_TERMIOS=y
|
||||||
|
CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
|
||||||
|
CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
|
||||||
|
# CONFIG_WL_SECTOR_SIZE_512 is not set
|
||||||
|
CONFIG_WL_SECTOR_SIZE_4096=y
|
||||||
|
CONFIG_WL_SECTOR_SIZE=4096
|
||||||
|
# CONFIG_ENABLE_UNIFIED_PROVISIONING is not set
|
||||||
|
CONFIG_LTM_FAST=y
|
||||||
|
CONFIG_WPA_MBEDTLS_CRYPTO=y
|
||||||
|
# CONFIG_WPA_DEBUG_PRINT is not set
|
||||||
|
# CONFIG_WPA_TESTING_OPTIONS is not set
|
||||||
|
# CONFIG_WPA_WPS_WARS is not set
|
||||||
|
# CONFIG_WPA_11KV_SUPPORT is not set
|
||||||
|
|
||||||
|
# Deprecated options for backward compatibility
|
||||||
|
CONFIG_TARGET_PLATFORM="esp8266"
|
||||||
|
CONFIG_TOOLPREFIX="xtensa-lx106-elf-"
|
||||||
|
# CONFIG_MAKE_WARN_UNDEFINED_VARIABLES is not set
|
||||||
|
CONFIG_FLASHMODE_QIO=y
|
||||||
|
# CONFIG_FLASHMODE_QOUT is not set
|
||||||
|
# CONFIG_FLASHMODE_DIO is not set
|
||||||
|
# CONFIG_FLASHMODE_DOUT is not set
|
||||||
|
# CONFIG_MONITOR_BAUD_9600B is not set
|
||||||
|
# CONFIG_MONITOR_BAUD_57600B is not set
|
||||||
|
# CONFIG_MONITOR_BAUD_74880B is not set
|
||||||
|
CONFIG_MONITOR_BAUD_115200B=y
|
||||||
|
# CONFIG_MONITOR_BAUD_230400B is not set
|
||||||
|
# CONFIG_MONITOR_BAUD_921600B is not set
|
||||||
|
# CONFIG_MONITOR_BAUD_2MB is not set
|
||||||
|
# CONFIG_MONITOR_BAUD_OTHER is not set
|
||||||
|
CONFIG_MONITOR_BAUD_OTHER_VAL=74880
|
||||||
|
CONFIG_MONITOR_BAUD=115200
|
||||||
|
CONFIG_OPTIMIZATION_LEVEL_DEBUG=y
|
||||||
|
# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set
|
||||||
|
CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y
|
||||||
|
# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set
|
||||||
|
# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set
|
||||||
|
# CONFIG_CXX_EXCEPTIONS is not set
|
||||||
|
CONFIG_STACK_CHECK_NONE=y
|
||||||
|
# CONFIG_STACK_CHECK_NORM is not set
|
||||||
|
# CONFIG_STACK_CHECK_STRONG is not set
|
||||||
|
# CONFIG_STACK_CHECK_ALL is not set
|
||||||
|
# CONFIG_STACK_CHECK is not set
|
||||||
|
# CONFIG_WARN_WRITE_STRINGS is not set
|
||||||
|
CONFIG_MAIN_TASK_STACK_SIZE=3584
|
||||||
|
CONFIG_CONSOLE_UART_DEFAULT=y
|
||||||
|
# CONFIG_CONSOLE_UART_CUSTOM is not set
|
||||||
|
# CONFIG_CONSOLE_UART_NONE is not set
|
||||||
|
CONFIG_CONSOLE_UART_NUM=0
|
||||||
|
CONFIG_CONSOLE_UART_BAUDRATE=74880
|
||||||
|
# CONFIG_UART0_SWAP_IO is not set
|
||||||
|
CONFIG_TASK_WDT=y
|
||||||
|
CONFIG_TASK_WDT_PANIC=y
|
||||||
|
CONFIG_TASK_WDT_TIMEOUT_S=15
|
||||||
|
CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150
|
||||||
|
CONFIG_MB_MASTER_DELAY_MS_CONVERT=200
|
||||||
|
CONFIG_MB_QUEUE_LENGTH=20
|
||||||
|
CONFIG_MB_SERIAL_TASK_STACK_SIZE=4096
|
||||||
|
CONFIG_MB_SERIAL_BUF_SIZE=256
|
||||||
|
CONFIG_MB_SERIAL_TASK_PRIO=10
|
||||||
|
CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT=y
|
||||||
|
CONFIG_MB_CONTROLLER_SLAVE_ID=0x00112233
|
||||||
|
CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT=20
|
||||||
|
CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
|
||||||
|
CONFIG_MB_CONTROLLER_STACK_SIZE=4096
|
||||||
|
CONFIG_MB_EVENT_QUEUE_TIMEOUT=20
|
||||||
|
CONFIG_MB_TIMER_GROUP=0
|
||||||
|
CONFIG_MB_TIMER_INDEX=0
|
||||||
|
# CONFIG_L2_TO_L3_COPY is not set
|
||||||
|
# CONFIG_USE_ONLY_LWIP_SELECT is not set
|
||||||
|
CONFIG_ESP_GRATUITOUS_ARP=y
|
||||||
|
CONFIG_GARP_TMR_INTERVAL=60
|
||||||
|
CONFIG_TCPIP_RECVMBOX_SIZE=32
|
||||||
|
CONFIG_TCP_MAXRTX=12
|
||||||
|
CONFIG_TCP_SYNMAXRTX=6
|
||||||
|
CONFIG_TCP_MSS=1440
|
||||||
|
CONFIG_TCP_MSL=60000
|
||||||
|
CONFIG_TCP_SND_BUF_DEFAULT=2880
|
||||||
|
CONFIG_TCP_WND_DEFAULT=5760
|
||||||
|
CONFIG_TCP_RECVMBOX_SIZE=6
|
||||||
|
CONFIG_TCP_QUEUE_OOSEQ=y
|
||||||
|
# CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
|
||||||
|
CONFIG_TCP_OVERSIZE_MSS=y
|
||||||
|
# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set
|
||||||
|
# CONFIG_TCP_OVERSIZE_DISABLE is not set
|
||||||
|
CONFIG_UDP_RECVMBOX_SIZE=6
|
||||||
|
CONFIG_TCPIP_TASK_STACK_SIZE=2048
|
||||||
|
CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
|
||||||
|
# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set
|
||||||
|
CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF
|
||||||
|
# CONFIG_PPP_SUPPORT is not set
|
||||||
|
CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5
|
||||||
|
CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
|
||||||
|
CONFIG_ESP32_PTHREAD_STACK_MIN=768
|
||||||
|
CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread"
|
||||||
|
CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y
|
||||||
|
CONFIG_SUPPORT_TERMIOS=y
|
||||||
|
# End of deprecated options
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../../mongoose.c
|
|
||||||
@@ -22,11 +22,6 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
MG_INFO(("Last chunk received, sending response"));
|
MG_INFO(("Last chunk received, sending response"));
|
||||||
mg_http_reply(c, 200, "", "ok (chunked)\n");
|
mg_http_reply(c, 200, "", "ok (chunked)\n");
|
||||||
}
|
}
|
||||||
} else if (ev == MG_EV_HTTP_MSG && mg_http_match_uri(hm, "/upload")) {
|
|
||||||
MG_INFO(("Got all %lu bytes!", (unsigned long) hm->body.len));
|
|
||||||
MG_INFO(("Query string: [%.*s]", (int) hm->query.len, hm->query.ptr));
|
|
||||||
// MG_INFO(("Body:\n%.*s", (int) hm->body.len, hm->body.ptr));
|
|
||||||
mg_http_reply(c, 200, "", "ok (%lu)\n", (unsigned long) hm->body.len);
|
|
||||||
} else if (ev == MG_EV_HTTP_MSG) {
|
} else if (ev == MG_EV_HTTP_MSG) {
|
||||||
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
||||||
mg_http_serve_dir(c, hm, &opts);
|
mg_http_serve_dir(c, hm, &opts);
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ static const uint64_t s_timeout_ms = 1500; // Connect timeout in milliseconds
|
|||||||
// Print HTTP response and signal that we're done
|
// Print HTTP response and signal that we're done
|
||||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
if (ev == MG_EV_OPEN) {
|
if (ev == MG_EV_OPEN) {
|
||||||
// Connection created. Store connect expiration time in c->label
|
// Connection created. Store connect expiration time in c->data
|
||||||
*(uint64_t *) c->label = mg_millis() + s_timeout_ms;
|
*(uint64_t *) c->data = mg_millis() + s_timeout_ms;
|
||||||
} else if (ev == MG_EV_POLL) {
|
} else if (ev == MG_EV_POLL) {
|
||||||
if (mg_millis() > *(uint64_t *) c->label &&
|
if (mg_millis() > *(uint64_t *) c->data &&
|
||||||
(c->is_connecting || c->is_resolving)) {
|
(c->is_connecting || c->is_resolving)) {
|
||||||
mg_error(c, "Connect timeout");
|
mg_error(c, "Connect timeout");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,14 +35,12 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
mg_http_printf_chunk(c, "ID PROTO TYPE LOCAL REMOTE\n");
|
mg_http_printf_chunk(c, "ID PROTO TYPE LOCAL REMOTE\n");
|
||||||
for (struct mg_connection *t = c->mgr->conns; t != NULL; t = t->next) {
|
for (struct mg_connection *t = c->mgr->conns; t != NULL; t = t->next) {
|
||||||
char loc[40], rem[40];
|
mg_http_printf_chunk(c, "%-3lu %4s %s %I %I\n", t->id,
|
||||||
mg_http_printf_chunk(c, "%-3lu %4s %s %-15s %s\n", t->id,
|
|
||||||
t->is_udp ? "UDP" : "TCP",
|
t->is_udp ? "UDP" : "TCP",
|
||||||
t->is_listening ? "LISTENING"
|
t->is_listening ? "LISTENING"
|
||||||
: t->is_accepted ? "ACCEPTED "
|
: t->is_accepted ? "ACCEPTED "
|
||||||
: "CONNECTED",
|
: "CONNECTED",
|
||||||
mg_straddr(&t->loc, loc, sizeof(loc)),
|
4, &t->loc.ip, 4, &t->rem.ip);
|
||||||
mg_straddr(&t->rem, rem, sizeof(rem)));
|
|
||||||
}
|
}
|
||||||
mg_http_printf_chunk(c, ""); // Don't forget the last empty chunk
|
mg_http_printf_chunk(c, ""); // Don't forget the last empty chunk
|
||||||
} else if (mg_http_match_uri(hm, "/api/f2/*")) {
|
} else if (mg_http_match_uri(hm, "/api/f2/*")) {
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
PROG ?= example
|
PROG ?= example
|
||||||
ROOT ?= $(realpath $(CURDIR)/../..)
|
ROOT ?= $(realpath $(CURDIR)/../..)
|
||||||
DEFS ?= -DMG_ENABLE_LINES=1 -DMG_ENABLE_IPV6=1 -DMG_ENABLE_SSI=1
|
DEFS ?= -DMG_ENABLE_LINES=1 -DMG_ENABLE_IPV6=1 -DMG_ENABLE_SSI=1 -DMG_HTTP_DIRLIST_TIME=1
|
||||||
CFLAGS ?= -I../.. -W -Wall $(DEFS) $(EXTRA)
|
CFLAGS ?= -I../.. -W -Wall $(DEFS) $(EXTRA)
|
||||||
VCFLAGS = /nologo /W3 /O2 /I../.. $(DEFS) $(EXTRA) /link /incremental:no /machine:IX86
|
VCFLAGS = /nologo /W3 /O2 /I../.. $(DEFS) $(EXTRA) /link /incremental:no /machine:IX86
|
||||||
VC98 = docker run -it --rm -e Tmp=. -v $(ROOT):$(ROOT) -w $(CURDIR) mdashnet/vc98
|
VC98 = docker run -it --rm -e Tmp=. -v $(ROOT):$(ROOT) -w $(CURDIR) mdashnet/vc98
|
||||||
LIN = docker run -it --rm -v $(ROOT):$(ROOT) -w $(CURDIR) mdashnet/cc2
|
|
||||||
|
|
||||||
all: $(PROG)
|
all: $(PROG)
|
||||||
$(RUN) ./$(PROG) $(ARGS)
|
$(RUN) ./$(PROG) $(ARGS)
|
||||||
@@ -16,11 +15,7 @@ mongoose.exe: main.c
|
|||||||
$(VC98) wine cl ../../mongoose.c main.c $(VCFLAGS) ws2_32.lib /out:$@
|
$(VC98) wine cl ../../mongoose.c main.c $(VCFLAGS) ws2_32.lib /out:$@
|
||||||
|
|
||||||
mingw:
|
mingw:
|
||||||
gcc ../../mongoose.c main.c -I../.. -W -Wall -DMG_ENABLE_IPV6=1 -DMG_ENABLE_LINES=1 -D_POSIX_C_SOURCE=200000L -lws2_32 -o mongoose.exe
|
gcc ../../mongoose.c main.c -I../.. -W -Wall $(DEFS) -D_POSIX_C_SOURCE=200000L -lws2_32 -o mongoose.exe
|
||||||
|
|
||||||
linux: example
|
|
||||||
#linux: CFLAGS += -O2 -fsanitize=address,undefined,shift,null,return,bounds,alignment,object-size,bool,enum -static-libasan
|
|
||||||
linux: CC = $(LIN) cc
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb mongoose mongoose_* mongoose.*
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb mongoose mongoose_* mongoose.*
|
||||||
@@ -30,7 +30,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
if (ev == MG_EV_OPEN) {
|
if (ev == MG_EV_OPEN) {
|
||||||
// c->is_hexdumping = 1;
|
// c->is_hexdumping = 1;
|
||||||
} else if (ev == MG_EV_WS_OPEN) {
|
} else if (ev == MG_EV_WS_OPEN) {
|
||||||
c->label[0] = 'W'; // Mark this connection as an established WS client
|
c->data[0] = 'W'; // Mark this connection as an established WS client
|
||||||
} else if (ev == MG_EV_HTTP_MSG) {
|
} else 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, "/websocket")) {
|
if (mg_http_match_uri(hm, "/websocket")) {
|
||||||
@@ -58,7 +58,7 @@ static void timer_fn(void *arg) {
|
|||||||
struct mg_mgr *mgr = (struct mg_mgr *) arg;
|
struct mg_mgr *mgr = (struct mg_mgr *) arg;
|
||||||
// Broadcast message to all connected websocket clients.
|
// Broadcast message to all connected websocket clients.
|
||||||
for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
|
for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) {
|
||||||
if (c->label[0] != 'W') continue;
|
if (c->data[0] != 'W') continue;
|
||||||
mg_ws_printf(c, WEBSOCKET_OP_TEXT, "{%Q:%Q,%Q:[%d,%d,%d]}", "method",
|
mg_ws_printf(c, WEBSOCKET_OP_TEXT, "{%Q:%Q,%Q:[%d,%d,%d]}", "method",
|
||||||
"notification1", "params", 1, 2, 3);
|
"notification1", "params", 1, 2, 3);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ var jsonrpc = function(url, onopen, onclose, onnotification) {
|
|||||||
ws.send(JSON.stringify(request));
|
ws.send(JSON.stringify(request));
|
||||||
console.log('sent', request);
|
console.log('sent', request);
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
setTimeout(JSONRPC_TIMEOUT_MS, function() {
|
setTimeout(function() {
|
||||||
if (pending[id] === undefined) return;
|
if (pending[id] === undefined) return;
|
||||||
log('Timing out frame ', JSON.stringify(request));
|
log('Timing out frame ', JSON.stringify(request));
|
||||||
delete (pending[id]);
|
delete (pending[id]);
|
||||||
reject();
|
reject();
|
||||||
});
|
}, JSONRPC_TIMEOUT_MS);
|
||||||
pending[id] = x => resolve(x);
|
pending[id] = x => resolve(x);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
struct mg_http_serve_opts opts = {.root_dir = NULL};
|
struct mg_http_serve_opts opts = {.root_dir = NULL};
|
||||||
mg_http_serve_file(c, hm, "log.txt", &opts);
|
mg_http_serve_file(c, hm, "log.txt", &opts);
|
||||||
} else if (mg_http_match_uri(hm, "/api/log/live")) {
|
} else if (mg_http_match_uri(hm, "/api/log/live")) {
|
||||||
c->label[0] = 'L'; // Mark that connection as live log listener
|
c->data[0] = 'L'; // Mark that connection as live log listener
|
||||||
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||||
} else {
|
} else {
|
||||||
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
|
||||||
@@ -34,7 +34,7 @@ static void log_message(const char *filename, const char *message) {
|
|||||||
static void broadcast_message(struct mg_mgr *mgr, const char *message) {
|
static void broadcast_message(struct mg_mgr *mgr, const char *message) {
|
||||||
struct mg_connection *c;
|
struct mg_connection *c;
|
||||||
for (c = mgr->conns; c != NULL; c = c->next) {
|
for (c = mgr->conns; c != NULL; c = c->next) {
|
||||||
if (c->label[0] == 'L') mg_http_printf_chunk(c, "%s", message);
|
if (c->data[0] == 'L') mg_http_printf_chunk(c, "%s", message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,22 @@
|
|||||||
PROG ?= example
|
PROG ?= example
|
||||||
DEFS ?= -DMG_ENABLE_LINES=1 -DMG_ENABLE_MIP=1 -DMG_ENABLE_SOCKET=0 -DMG_ENABLE_WINSOCK=0 -I../..
|
DEFS ?= -DMG_ENABLE_LINES=1 -DMG_ENABLE_MIP=1 -DMG_ENABLE_SOCKET=0 -DMG_ENABLE_PACKED_FS=1 -I../..
|
||||||
CFLAGS ?= -W -Wall
|
CFLAGS ?= -W -Wall $(EXTRA_CFLAGS)
|
||||||
LIBS ?= -lpcap
|
LIBS ?= -lpcap
|
||||||
|
SOURCES = main.c ../../mongoose.c ../device-dashboard/net.c ../device-dashboard/packed_fs.c
|
||||||
|
|
||||||
|
ifeq "$(SSL)" "MBEDTLS"
|
||||||
|
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -lmbedtls -lmbedcrypto -lmbedx509 -I$(MBEDTLS)/include -L$(MBEDTLS)/lib
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq "$(SSL)" "OPENSSL"
|
||||||
|
CFLAGS += -DMG_ENABLE_OPENSSL=1 -lssl -lcrypto -I$(OPENSSL)/include -L$(OPENSSL)/lib
|
||||||
|
endif
|
||||||
|
|
||||||
all: $(PROG)
|
all: $(PROG)
|
||||||
$(RUN) ./$(PROG) $(ARGS)
|
$(RUN) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
$(PROG): main.c
|
$(PROG): main.c
|
||||||
$(CC) main.c ../../mongoose.c $(CFLAGS) $(DEFS) -o $(PROG) $(LIBS)
|
$(CC) $(SOURCES) $(CFLAGS) $(DEFS) -o $(PROG) $(LIBS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
||||||
@@ -0,0 +1,246 @@
|
|||||||
|
# MIP TCP / IP stack over pcap
|
||||||
|
|
||||||
|
This example allows to use Mongoose's MIP built-in TCP/IP stack on systems
|
||||||
|
that support pcap API, i.e. have libpcap library installed. The application
|
||||||
|
opens an interface and uses `pcap_next_ex()` for reading packets from the
|
||||||
|
interface, and `pcap_inject()` to write packets to the interface.
|
||||||
|
|
||||||
|
NOTE: depending on the libcap implementation, the injected packets may
|
||||||
|
or may not be looped back to the interface's TCP/IP stack. If they are
|
||||||
|
not looped back, then it is necessary to create a separate interface that
|
||||||
|
is bridged to the target interface - see MacOS example below.
|
||||||
|
|
||||||
|
## MacOS setup
|
||||||
|
|
||||||
|
MacOS has support for `feth` (fake ethernet) interfaces. One can create a pair
|
||||||
|
of `feth` interfaces and interlink them. Once a `feth` interface is assigned
|
||||||
|
a peer and an IP address, anything that gets injected to it, appears on a
|
||||||
|
peer interface and vice versa.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ sudo ifconfig feth0 create
|
||||||
|
$ sudo ifconfig feth1 create
|
||||||
|
$ sudo ifconfig feth1 peer feth0 # Link two fake ethernet ifaces together
|
||||||
|
$ sudo ifconfig feth1 10.10 # Assign 10.0.0.10 to feth1
|
||||||
|
$ sudo ifconfig feth0 up
|
||||||
|
$ sudo ifconfig feth1 up
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we have two Ethernet interfaces, `feth0` and `feth1`, interlinked and
|
||||||
|
active. On your Mac, go to "System Preferences" / Sharing, enable "Internet
|
||||||
|
Sharing" and choose "Thunderbolt bridge". This enables DHCP on the `bridge0`
|
||||||
|
interface, which is bridge for all Thunderbolt devices, and adds necessary
|
||||||
|
routes to the WiFi interface. On my system it gets `192.168.2.1` IP address,
|
||||||
|
and serves `192.168.2/24` net. We should add one of our fake interfaces to
|
||||||
|
this bridge:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ sudo ifconfig bridge0 addm feth1
|
||||||
|
```
|
||||||
|
|
||||||
|
We can start an example using the `feth0`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ make -C examples/mip-pcap/ clean all ARGS="-i feth0"
|
||||||
|
...
|
||||||
|
2386718 3 mip.c:279:arp_cache_add ARP cache: added 0xc0a80201 @ 36:77:4d:be:e0:80
|
||||||
|
2386718 2 mip.c:300:onstatechange READY, IP: 192.168.2.17
|
||||||
|
```
|
||||||
|
|
||||||
|
The diagram of the setup is below:
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────► 192.168.2.1 bridge0
|
||||||
|
│ routing DHCP │
|
||||||
|
│ ┌──────────────────┴──────────────────┐
|
||||||
|
▼ │ │ 192.168.2.17
|
||||||
|
│ ┌─────────┐ fake ethernet pair ┌─────────┐
|
||||||
|
192.168.0.10 │ │ feth1 ├────────────┬───────┤ feth0 │
|
||||||
|
┌─────────┐ │ └─────────┘ │ └────┬────┘
|
||||||
|
│ en0 │ │ │ │
|
||||||
|
└────┬────┘ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
|
||||||
|
│ │ │ en1 │ │ en2 │ │ en3 │ │ mip-pcap
|
||||||
|
│ └────┬────┘ └────┬────┘ └────┬────┘ │
|
||||||
|
WiFi │ │ │ │ │
|
||||||
|
└──────┼───────────┼───────────┼──────┘
|
||||||
|
│ │ │ │
|
||||||
|
▼
|
||||||
|
Internet Thunderbolt Ethernet
|
||||||
|
```
|
||||||
|
|
||||||
|
## Linux setup
|
||||||
|
|
||||||
|
The quick and simple options are:
|
||||||
|
|
||||||
|
- Open your loopback device (probably `lo`), in which case MIP is only reachable from your machine, and MIP also sees echoes of its own traffic.
|
||||||
|
- Open your Ethernet/WiFi device (probably `eth0` or `enpXsY` for Ethernet), in which case MIP can access the network and the Internet but is not reachable from within your machine
|
||||||
|
- If you happen to have a virtual bridge interface (for linking several virtual machines together, for example) (probably `br0` or `virbr0`), you can open it, but it will behave as opening the underlying physical interface.
|
||||||
|
|
||||||
|
For best results, you should create a virtual interface, which you can use as is, attach to a virtual bridge, or forward/masquerade its traffic.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ sudo ip link add my0 type veth peer [name] my1
|
||||||
|
$ sudo ip link set my0 up
|
||||||
|
$ sudo ip link set my1 up
|
||||||
|
```
|
||||||
|
|
||||||
|
In some systems, like for example RHEL7, _name_ is mandatory; in others you might need not to add it, that is why we represented it here using square brackets.
|
||||||
|
|
||||||
|
### Use a virtual interface
|
||||||
|
|
||||||
|
This is similar to using the loopback device, MIP is only reachable from the hosting machine, but you can add forwarding and masquerading later. Once you have your virtual interface up and running with an IP address, you can configure any services on one end, let's say `my1`, while you open the other end, `my0` with MIP.
|
||||||
|
|
||||||
|
- Add an IP address to one end of the pipe
|
||||||
|
```sh
|
||||||
|
$ sudo ip addr add 192.168.0.1/24 dev my1
|
||||||
|
```
|
||||||
|
- Start your DHCP server at that interface serving that subnet, or otherwise configure MIP to use a fixed address within that subnet.
|
||||||
|
- Now start the example opening the other end of the virtual interface:
|
||||||
|
```sh
|
||||||
|
$ make -C examples/mip-pcap/ clean all ARGS="-i my0"
|
||||||
|
```
|
||||||
|
- In some systems, you will probably need superuser privileges to open the device:
|
||||||
|
```sh
|
||||||
|
$ sudo examples/mip-pcap/example -i my0
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
[DHCP server for 192.168.0.x]
|
||||||
|
192.168.0.1 192.168.0.x
|
||||||
|
┌─────────┐ virtual eth pair ┌─────────┐
|
||||||
|
│ my1 ├────────────────────┤ my0 │
|
||||||
|
└─────────┘ └────┬────┘
|
||||||
|
│
|
||||||
|
│
|
||||||
|
mip-pcap
|
||||||
|
```
|
||||||
|
|
||||||
|
As you can't access any other host than your workstation, you need to add any required services (as DNS) there, and configure Mongoose appropriately. This is a foundation, you can expand it by choosing one of the solutions that follow.
|
||||||
|
|
||||||
|
### Bridge to your network
|
||||||
|
|
||||||
|
We will attach one end of the virtual interface to a bridge, which will also be attached to your network interface. In this case, MIP will have access to your network (and through it, to the Internet) and will also be reachable from your own workstation and other hosts in your network. You don't need to add IP addresses as in the example above, unless you don't have a DHCP server in your network, in which case you will configure MIP for a fixed address in your subnet.
|
||||||
|
|
||||||
|
- If you don't already have a virtual bridge interface, as mentioned above, you'll have to create it and attach your network interface (NIC) to it. Your IP address has to be assigned to the bridge, instead of the NIC. If you are using DHCP, the client must run on the bridge interface instead of the NIC.
|
||||||
|
```sh
|
||||||
|
$ ip link add virbr0 type bridge
|
||||||
|
$ sudo ip link set virbr0 up
|
||||||
|
$ sudo ip addr del 10.1.0.10/24 dev enp9s0
|
||||||
|
$ sudo ip link set enp9s0 master virbr0
|
||||||
|
$ sudo ip addr add 10.1.0.10/24 dev virbr0
|
||||||
|
```
|
||||||
|
Check using `ifconfig`, and try to ping some host in your network
|
||||||
|
- Attach one end of the virtual interface to the bridge:
|
||||||
|
```sh
|
||||||
|
$ sudo ip link set my1 master virbr0
|
||||||
|
```
|
||||||
|
- If everything is fine, you'll see your interface pair state is UP:
|
||||||
|
```sh
|
||||||
|
$ ip link show master virbr0
|
||||||
|
2: enp9s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UP mode DEFAULT group default qlen 1000
|
||||||
|
link/ether 30:5a:3a:08:db:90 brd ff:ff:ff:ff:ff:ff
|
||||||
|
396: my1@my0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master virbr0 state UP mode DEFAULT group default qlen 1000
|
||||||
|
link/ether b6:ee:bc:53:f2:6e brd ff:ff:ff:ff:ff:ff
|
||||||
|
```
|
||||||
|
- Now start the example opening the other end of the virtual interface:
|
||||||
|
```sh
|
||||||
|
$ make -C examples/mip-pcap/ clean all ARGS="-i my0"
|
||||||
|
```
|
||||||
|
- In some systems, you will probably need superuser privileges to open the device:
|
||||||
|
```sh
|
||||||
|
$ sudo examples/mip-pcap/example -i my0
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
10.1.0.10
|
||||||
|
virbr0
|
||||||
|
│
|
||||||
|
┌──────────────────┴──────────────────┐
|
||||||
|
│ │ 10.1.0.x
|
||||||
|
│ ┌─────────┐ virtual eth pair ┌─────────┐
|
||||||
|
│ │ my1 ├────────────┬───────┤ my0 │
|
||||||
|
│ └─────────┘ │ └────┬────┘
|
||||||
|
│ │ │
|
||||||
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
|
||||||
|
│ │ vnet1 │ │ enp9s0 │ │ vnet2 │ │ mip-pcap
|
||||||
|
│ └────┬────┘ └────┬────┘ └────┬────┘ │
|
||||||
|
│ │ │ │ │
|
||||||
|
└──────┼───────────┼───────────┼──────┘
|
||||||
|
│ │ │
|
||||||
|
│
|
||||||
|
Ethernet [WiFi]
|
||||||
|
│ Local LAN 10.1.0.x
|
||||||
|
│ DHCP server, router
|
||||||
|
▼
|
||||||
|
Internet
|
||||||
|
```
|
||||||
|
|
||||||
|
If you have _Docker_ running, it may introduce firewall rules that will disrupt your bridging.
|
||||||
|
|
||||||
|
### Forward/Masquerade
|
||||||
|
|
||||||
|
Once you have your virtual interface up and running with an IP address, you can use your Linux to NAT and forward MIP traffic to another interface, for example the one that connects you to the Internet. In this case, MIP will have access to the Internet and will also be reachable from your own workstation; but not from any other hosts in your local network (if there is one). You can use this setup with a direct connection to the Internet or being part of a network, when you want to isolate MIP from the rest of your network.
|
||||||
|
|
||||||
|
- We assume you already have a firewall in place (you should); to configure masquerading and forwarding do:
|
||||||
|
```sh
|
||||||
|
$ sudo iptables -t nat -A POSTROUTING -o enp9s0 -j MASQUERADE
|
||||||
|
$ echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
|
||||||
|
```
|
||||||
|
Remember to use the proper network interface name
|
||||||
|
- Now start the example opening the other end of the virtual interface:
|
||||||
|
```sh
|
||||||
|
$ make -C examples/mip-pcap/ clean all ARGS="-i my0"
|
||||||
|
```
|
||||||
|
- In some systems, you will probably need superuser privileges to open the device:
|
||||||
|
```sh
|
||||||
|
$ sudo examples/mip-pcap/example -i my0
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
[DHCP server for 192.168.0.x]
|
||||||
|
┌────────────► 192.168.0.1 192.168.0.x
|
||||||
|
│ forwarding ┌─────────┐ virtual eth pair ┌─────────┐
|
||||||
|
│ masquerading │ my1 ├────────────────────┤ my0 │
|
||||||
|
│ └─────────┘ └────┬────┘
|
||||||
|
▼ │
|
||||||
|
Your IP (LAN / Public) │
|
||||||
|
┌─────────┐ mip-pcap
|
||||||
|
│ enp9s0 │
|
||||||
|
└────┬────┘
|
||||||
|
│
|
||||||
|
│
|
||||||
|
Ethernet
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Internet
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also use this setup if your NIC is part of a bridge (for example: you have virtual machines); in that case:
|
||||||
|
- use the bridge interface for masquerading, instead of the Ethernet (your IP now belongs to the virtual bridge, not the NIC):
|
||||||
|
```sh
|
||||||
|
$ sudo iptables -t nat -A POSTROUTING -o virbr0 -j MASQUERADE
|
||||||
|
$ echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
|
||||||
|
```
|
||||||
|
Remember to use the proper bridge interface name
|
||||||
|
|
||||||
|
```
|
||||||
|
[DHCP server for 192.168.0.x]
|
||||||
|
10.1.0.10 ◀──────────────► 192.168.0.1 192.168.0.x
|
||||||
|
virbr0 forwarding ┌─────────┐ virtual eth pair ┌─────────┐
|
||||||
|
│ masquerading │ my1 ├────────────────────┤ my0 │
|
||||||
|
│ └─────────┘ └────┬────┘
|
||||||
|
┌──────────────────┴──────────────────┐ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ mip-pcap
|
||||||
|
│ │ vnet1 │ │ enp9s0 │ │ vnet2 │ │
|
||||||
|
│ └────┬────┘ └────┬────┘ └────┬────┘ │
|
||||||
|
│ │ │ │ │
|
||||||
|
└──────┼───────────┼───────────┼──────┘
|
||||||
|
│ │ │
|
||||||
|
│
|
||||||
|
Ethernet [WiFi]
|
||||||
|
│ Local LAN 10.1.0.x
|
||||||
|
│ DHCP server, router
|
||||||
|
▼
|
||||||
|
Internet
|
||||||
|
```
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../test/data/ca.pem
|
||||||
+73
-52
@@ -6,73 +6,84 @@
|
|||||||
#include <pcap.h>
|
#include <pcap.h>
|
||||||
#include "mongoose.h"
|
#include "mongoose.h"
|
||||||
|
|
||||||
static struct mg_connection *s_sntp_conn = NULL;
|
#define MQTT_URL "mqtt://broker.hivemq.com:1883" // MQTT broker to connect to
|
||||||
|
#define MQTT_TOPIC "t/123" // Topic to subscribe to
|
||||||
|
|
||||||
|
#if MG_ARCH == MG_ARCH_WIN32
|
||||||
|
#define usleep(x) Sleep((x) / 1000)
|
||||||
|
#endif
|
||||||
|
|
||||||
static int s_signo;
|
static int s_signo;
|
||||||
void signal_handler(int signo) {
|
void signal_handler(int signo) {
|
||||||
s_signo = signo;
|
s_signo = signo;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SNTP client callback
|
static size_t pcap_tx(const void *buf, size_t len, struct mip_if *ifp) {
|
||||||
static void sfn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
int res = pcap_inject((pcap_t *) ifp->driver_data, buf, len);
|
||||||
if (ev == MG_EV_SNTP_TIME) {
|
|
||||||
int64_t t = *(int64_t *) ev_data;
|
|
||||||
MG_INFO(("Got SNTP time: %lld ms from epoch", t));
|
|
||||||
} else if (ev == MG_EV_CLOSE) {
|
|
||||||
s_sntp_conn = NULL;
|
|
||||||
}
|
|
||||||
(void) fn_data, (void) c;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called every 5 seconds. Increase that for production case.
|
|
||||||
static void timer_fn(void *arg) {
|
|
||||||
struct mg_mgr *mgr = (struct mg_mgr *) arg;
|
|
||||||
if (s_sntp_conn == NULL) s_sntp_conn = mg_sntp_connect(mgr, NULL, sfn, NULL);
|
|
||||||
if (s_sntp_conn != NULL) mg_sntp_request(s_sntp_conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fail(const char *fmt, ...) {
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vfprintf(stderr, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t pcap_tx(const void *data, size_t len, void *userdata) {
|
|
||||||
int res = pcap_inject((pcap_t *) userdata, data, len);
|
|
||||||
if (res == PCAP_ERROR) {
|
if (res == PCAP_ERROR) {
|
||||||
MG_ERROR(("pcap_inject: %d", res));
|
MG_ERROR(("pcap_inject: %d", res));
|
||||||
}
|
}
|
||||||
return len;
|
return res == PCAP_ERROR ? 0 : len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool pcap_status(void *userdata) {
|
static bool pcap_up(struct mip_if *ifp) {
|
||||||
return userdata ? true : false;
|
return ifp->driver_data ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t pcap_rx(void *buf, size_t len, void *userdata) {
|
static size_t pcap_rx(void *buf, size_t len, struct mip_if *ifp) {
|
||||||
size_t received = 0;
|
size_t received = 0;
|
||||||
struct pcap_pkthdr *hdr = NULL;
|
struct pcap_pkthdr *hdr = NULL;
|
||||||
const unsigned char *pkt = NULL;
|
const unsigned char *pkt = NULL;
|
||||||
if (pcap_next_ex((pcap_t *) userdata, &hdr, &pkt) == 1) {
|
usleep(1000); // Sleep 1 millisecond. This is to avoid 100% CPU
|
||||||
|
if (pcap_next_ex((pcap_t *) ifp->driver_data, &hdr, &pkt) == 1) {
|
||||||
received = hdr->len < len ? hdr->len : len;
|
received = hdr->len < len ? hdr->len : len;
|
||||||
memcpy(buf, pkt, received);
|
memcpy(buf, pkt, received);
|
||||||
}
|
}
|
||||||
return received;
|
return received;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fn2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
MG_DEBUG(("Got response (%d) %.*s...", (int) hm->message.len, 12,
|
||||||
|
hm->message.ptr));
|
||||||
|
c->is_closing = 1;
|
||||||
|
} else if (ev == MG_EV_CONNECT) {
|
||||||
|
mg_printf(c, "GET %s HTTP/1.1\r\n\r\n", mg_url_uri((char *) fn_data));
|
||||||
|
} else if (ev == MG_EV_CLOSE) {
|
||||||
|
free(fn_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
if (mg_http_match_uri(hm, "/api/debug")) {
|
||||||
|
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);
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/url")) {
|
||||||
|
char *url = mg_json_get_str(hm->body, "$.url");
|
||||||
|
if (url == NULL) {
|
||||||
|
mg_http_reply(c, 200, NULL, "no url, rl %d\r\n", (int) c->recv.len);
|
||||||
|
} else {
|
||||||
|
mg_http_connect(c->mgr, url, fn2, url);
|
||||||
|
mg_http_reply(c, 200, NULL, "ok\r\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mg_http_reply(c, 200, NULL, "%.*s\r\n", (int) hm->message.len,
|
||||||
|
hm->message.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void) ev_data, (void) fn_data;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
const char *iface = "lo0"; // Network iface
|
const char *iface = "lo0"; // Network iface
|
||||||
const char *mac = "aa:bb:cc:01:02:03"; // MAC address
|
const char *mac = "02:00:01:02:03:77"; // MAC address
|
||||||
const char *bpf = NULL; // "host x.x.x.x or ether host ff:ff:ff:ff:ff:ff";
|
const char *bpf = NULL; // "host x.x.x.x or ether host ff:ff:ff:ff:ff:ff";
|
||||||
char errbuf[PCAP_ERRBUF_SIZE] = "";
|
char errbuf[PCAP_ERRBUF_SIZE] = "";
|
||||||
|
|
||||||
struct mg_mgr mgr; // Event manager
|
|
||||||
mg_mgr_init(&mgr); // Initialise event manager
|
|
||||||
mg_log_set(MG_LL_DEBUG); // Set debug log level
|
|
||||||
mg_timer_add(&mgr, 3000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr);
|
|
||||||
|
|
||||||
// Parse options
|
// Parse options
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
if (strcmp(argv[i], "-i") == 0 && i + 1 < argc) {
|
if (strcmp(argv[i], "-i") == 0 && i + 1 < argc) {
|
||||||
@@ -81,8 +92,11 @@ int main(int argc, char *argv[]) {
|
|||||||
mac = argv[++i];
|
mac = argv[++i];
|
||||||
} else if (strcmp(argv[i], "-bpf") == 0 && i + 1 < argc) {
|
} else if (strcmp(argv[i], "-bpf") == 0 && i + 1 < argc) {
|
||||||
bpf = argv[++i];
|
bpf = argv[++i];
|
||||||
|
} else if (strcmp(argv[i], "-v") == 0 && i + 1 < argc) {
|
||||||
|
mg_log_set(atoi(argv[++i]));
|
||||||
} else {
|
} else {
|
||||||
return fail("unknown option %s", argv[i]);
|
MG_ERROR(("unknown option %s", argv[i]));
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,32 +111,39 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
pcap_freealldevs(devs);
|
pcap_freealldevs(devs);
|
||||||
}
|
}
|
||||||
fail("pcap_open_live: %s\n", errbuf);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
pcap_setnonblock(ph, 1, errbuf);
|
pcap_setnonblock(ph, 1, errbuf);
|
||||||
|
pcap_setdirection(ph, PCAP_D_IN);
|
||||||
|
|
||||||
// Apply BPF to reduce noise. Let in only broadcasts and our own traffic
|
// Apply BPF to reduce noise. Let in only broadcasts and our own traffic
|
||||||
if (bpf != NULL) {
|
if (bpf != NULL) {
|
||||||
struct bpf_program bpfp;
|
struct bpf_program bpfp;
|
||||||
if (pcap_compile(ph, &bpfp, bpf, 1, 0)) fail("compile \n");
|
if (pcap_compile(ph, &bpfp, bpf, 1, 0)) MG_ERROR(("BPF compile failed\n"));
|
||||||
pcap_setfilter(ph, &bpfp);
|
pcap_setfilter(ph, &bpfp);
|
||||||
pcap_freecode(&bpfp);
|
pcap_freecode(&bpfp);
|
||||||
}
|
}
|
||||||
MG_INFO(("Opened interface %s\n", iface));
|
|
||||||
|
|
||||||
|
MG_INFO(("Opened interface %s", iface));
|
||||||
signal(SIGINT, signal_handler);
|
signal(SIGINT, signal_handler);
|
||||||
signal(SIGTERM, signal_handler);
|
signal(SIGTERM, signal_handler);
|
||||||
|
|
||||||
struct mip_ipcfg ipcfg = {.ip = 0, .mask = 0, .gw = 0};
|
struct mg_mgr mgr; // Event manager
|
||||||
sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &ipcfg.mac[0], &ipcfg.mac[1],
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
&ipcfg.mac[2], &ipcfg.mac[3], &ipcfg.mac[4], &ipcfg.mac[5]);
|
mg_log_set(MG_LL_DEBUG); // Set log level
|
||||||
|
|
||||||
struct mip_driver driver = {
|
struct mip_driver driver = {.tx = pcap_tx, .up = pcap_up, .rx = pcap_rx};
|
||||||
.tx = pcap_tx, .status = pcap_status, .rx = pcap_rx};
|
struct mip_if mif = {.driver = &driver, .driver_data = ph};
|
||||||
|
sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mif.mac[0], &mif.mac[1],
|
||||||
mip_init(&mgr, &ipcfg, &driver, ph);
|
&mif.mac[2], &mif.mac[3], &mif.mac[4], &mif.mac[5]);
|
||||||
|
mip_init(&mgr, &mif);
|
||||||
MG_INFO(("Init done, starting main loop"));
|
MG_INFO(("Init done, starting main loop"));
|
||||||
|
|
||||||
while (s_signo == 0) mg_mgr_poll(&mgr, 1); // Infinite event loop
|
// extern void device_dashboard_fn(struct mg_connection *, int, void *, void
|
||||||
|
// *);
|
||||||
|
mg_http_listen(&mgr, "http://0.0.0.0:8000", fn, &mgr);
|
||||||
|
|
||||||
|
while (s_signo == 0) mg_mgr_poll(&mgr, 100); // Infinite event loop
|
||||||
|
|
||||||
mg_mgr_free(&mgr);
|
mg_mgr_free(&mgr);
|
||||||
pcap_close(ph);
|
pcap_close(ph);
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
PROG ?= example
|
||||||
|
DEFS ?= -DMG_ENABLE_LINES=1 -DMG_ENABLE_MIP=1 -DMG_ENABLE_SOCKET=0 -DMG_ENABLE_PACKED_FS=1 -I../..
|
||||||
|
CFLAGS ?= -W -Wall $(EXTRA_CFLAGS)
|
||||||
|
LIBS ?=
|
||||||
|
SOURCES = main.c ../../mongoose.c ../device-dashboard/net.c ../device-dashboard/packed_fs.c
|
||||||
|
|
||||||
|
ifeq "$(SSL)" "MBEDTLS"
|
||||||
|
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -lmbedtls -lmbedcrypto -lmbedx509 -I$(MBEDTLS)/include -L$(MBEDTLS)/lib
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq "$(SSL)" "OPENSSL"
|
||||||
|
CFLAGS += -DMG_ENABLE_OPENSSL=1 -lssl -lcrypto -I$(OPENSSL)/include -L$(OPENSSL)/lib
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(RUN) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
$(PROG): main.c
|
||||||
|
$(CC) $(SOURCES) $(CFLAGS) $(DEFS) -o $(PROG) $(LIBS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
# MIP TCP / IP stack on a tap interface
|
||||||
|
|
||||||
|
This example allows the use of Mongoose's MIP built-in TCP/IP stack in systems that support a TUN/TAP device. The application opens a TAP device and uses the standard socket interface to read and write on it.
|
||||||
|
|
||||||
|
The interface can be created by the example itself, but it will also disappear when the example exits. Since we usually need to do something before, like setting up a DHCP server or establishing some connections to the rest of the world, we'll manually create a specific TAP interface and the example will open it; this way, we can have everything setup in advance.
|
||||||
|
|
||||||
|
## Linux setup
|
||||||
|
|
||||||
|
Create a TAP interface; you can use it as is, attach it to a virtual bridge, or forward/masquerade its traffic.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ sudo ip tuntap add dev tap0 mode tap
|
||||||
|
$ sudo ip link set tap0 up
|
||||||
|
```
|
||||||
|
|
||||||
|
In some systems, you might need superuser privileges to open the device with the example. In others, you can add `user yourusername` or `group yourgroup` at creation time, to grant access to it.
|
||||||
|
|
||||||
|
### Use as a virtual interface
|
||||||
|
|
||||||
|
In this scenario, MIP is only reachable from the hosting machine, but you can add forwarding and masquerading later. Once you have your TAP interface up and running with an IP address, you can configure any services on it.
|
||||||
|
|
||||||
|
- Add an IP address
|
||||||
|
```sh
|
||||||
|
$ sudo ip addr add 192.168.0.1/24 dev tap0
|
||||||
|
```
|
||||||
|
- Start your DHCP server at that interface serving that subnet, or otherwise configure MIP to use a fixed address within that subnet.
|
||||||
|
- Now start the example opening the very same TAP interface:
|
||||||
|
```sh
|
||||||
|
$ make -C examples/mip-tap/ clean all
|
||||||
|
```
|
||||||
|
If you are using a different interface name than `tap0`, add `ARGS="-i ifcname"`, and use the proper interface name
|
||||||
|
|
||||||
|
```
|
||||||
|
[DHCP server for 192.168.0.x]
|
||||||
|
192.168.0.1 192.168.0.x
|
||||||
|
┌─────────┐
|
||||||
|
│ tap0 ├──────────────────── mip-tap
|
||||||
|
└─────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
As you can't access any other host than your workstation, you need to add any required services (as DNS) there, and configure Mongoose appropriately. This is a foundation, you can expand it by choosing one of the solutions that follow.
|
||||||
|
|
||||||
|
### Bridge to your network
|
||||||
|
|
||||||
|
If you happen to have a virtual bridge interface (for linking several virtual machines together, for example) (probably `br0` or `virbr0`), we can take advantage of it.
|
||||||
|
|
||||||
|
We will attach one end of the virtual interface to a bridge, which will also be attached to your network interface. In this case, MIP will have access to your network (and through it, to the Internet) and will also be reachable from your own workstation and other hosts in your network. You don't need to add IP addresses as in the example above, unless you don't have a DHCP server in your network, in which case you will configure MIP for a fixed address in your subnet.
|
||||||
|
|
||||||
|
- If you don't already have a virtual bridge interface, as mentioned above, you'll have to create it and attach your network interface (NIC) to it. Your IP address has to be assigned to the bridge, instead of the NIC. If you are using DHCP, the client must run on the bridge interface instead of the NIC.
|
||||||
|
```sh
|
||||||
|
$ ip link add virbr0 type bridge
|
||||||
|
$ sudo ip link set virbr0 up
|
||||||
|
$ sudo ip addr del 10.1.0.10/24 dev enp9s0
|
||||||
|
$ sudo ip link set enp9s0 master virbr0
|
||||||
|
$ sudo ip addr add 10.1.0.10/24 dev virbr0
|
||||||
|
```
|
||||||
|
Check using `ifconfig`, and try to ping some host in your network
|
||||||
|
- Attach the TAP interface to the bridge:
|
||||||
|
```sh
|
||||||
|
$ sudo ip link set tap0 master virbr0
|
||||||
|
```
|
||||||
|
- You won't see your interface state is UP until it is open, but you can check you see something like this:
|
||||||
|
```sh
|
||||||
|
$ ip link show master virbr0
|
||||||
|
2: enp9s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UP mode DEFAULT group default qlen 1000
|
||||||
|
link/ether 30:5a:3a:08:db:90 brd ff:ff:ff:ff:ff:ff
|
||||||
|
6: tap0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN mode DEFAULT group default qlen 1000
|
||||||
|
link/ether 66:91:e2:5f:d7:ed brd ff:ff:ff:ff:ff:ff
|
||||||
|
```
|
||||||
|
- Now start the example
|
||||||
|
```sh
|
||||||
|
$ make -C examples/mip-tap/ clean all
|
||||||
|
```
|
||||||
|
If you are using a different interface name than `tap0`, add `ARGS="-i ifcname"`, and use the proper interface name
|
||||||
|
- Now if everything is fine, besides the example working, you'll see your interface state is UP:
|
||||||
|
```sh
|
||||||
|
$ ip link show master virbr0
|
||||||
|
2: enp9s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UP mode DEFAULT group default qlen 1000
|
||||||
|
link/ether 30:5a:3a:08:db:90 brd ff:ff:ff:ff:ff:ff
|
||||||
|
6: tap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UP mode DEFAULT group default qlen 1000
|
||||||
|
link/ether 66:91:e2:5f:d7:ed brd ff:ff:ff:ff:ff:ff
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
10.1.0.10
|
||||||
|
virbr0
|
||||||
|
│
|
||||||
|
┌──────────────────┴──────────────────┐
|
||||||
|
│ │ 10.1.0.x
|
||||||
|
│ ┌────────┐ │
|
||||||
|
│ │ tap0 ├─────────────┼─────── mip-tap
|
||||||
|
│ └────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||||
|
│ │ vnet1 │ │ enp9s0 │ │ vnet2 │ │
|
||||||
|
│ └────┬────┘ └────┬────┘ └────┬────┘ │
|
||||||
|
│ │ │ │ │
|
||||||
|
└──────┼───────────┼───────────┼──────┘
|
||||||
|
│ │ │
|
||||||
|
│
|
||||||
|
Ethernet [WiFi]
|
||||||
|
│ Local LAN 10.1.0.x
|
||||||
|
│ DHCP server, router
|
||||||
|
▼
|
||||||
|
Internet
|
||||||
|
```
|
||||||
|
|
||||||
|
If you have _Docker_ running, it may introduce firewall rules that will disrupt your bridging.
|
||||||
|
|
||||||
|
### Forward/Masquerade
|
||||||
|
|
||||||
|
Once you have your virtual interface up and running with an IP address, you can use your Linux to NAT and forward MIP traffic to another interface, for example the one that connects you to the Internet. In this case, MIP will have access to the Internet and will also be reachable from your own workstation; but not from any other hosts in your local network (if there is one). You can use this setup with a direct connection to the Internet or being part of a network, when you want to isolate MIP from the rest of your network.
|
||||||
|
|
||||||
|
- We assume you already have a firewall in place (you should); to configure masquerading and forwarding do:
|
||||||
|
```sh
|
||||||
|
$ sudo iptables -t nat -A POSTROUTING -o enp9s0 -j MASQUERADE
|
||||||
|
$ echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
|
||||||
|
```
|
||||||
|
Remember to use the proper network interface name
|
||||||
|
- Now start the example
|
||||||
|
```sh
|
||||||
|
$ make -C examples/mip-tap/ clean all
|
||||||
|
```
|
||||||
|
If you are using a different interface name than `tap0`, add `ARGS="-i ifcname"`, and use the proper interface name
|
||||||
|
|
||||||
|
```
|
||||||
|
[DHCP server for 192.168.0.x]
|
||||||
|
┌────────────► 192.168.0.1 192.168.0.x
|
||||||
|
│ forwarding ┌─────────┐
|
||||||
|
│ masquerading │ tap0 ├──────────────────── mip-tap
|
||||||
|
│ └─────────┘
|
||||||
|
▼
|
||||||
|
Your IP (LAN / Public)
|
||||||
|
┌─────────┐
|
||||||
|
│ enp9s0 │
|
||||||
|
└────┬────┘
|
||||||
|
│
|
||||||
|
│
|
||||||
|
Ethernet
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Internet
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also use this setup if your NIC is part of a bridge (for example: you have virtual machines); in that case:
|
||||||
|
- use the bridge interface for masquerading, instead of the Ethernet (your IP now belongs to the virtual bridge, not the NIC):
|
||||||
|
```sh
|
||||||
|
$ sudo iptables -t nat -A POSTROUTING -o virbr0 -j MASQUERADE
|
||||||
|
$ echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
|
||||||
|
```
|
||||||
|
Remember to use the proper bridge interface name
|
||||||
|
|
||||||
|
```
|
||||||
|
[DHCP server for 192.168.0.x]
|
||||||
|
10.1.0.10 ◀──────────────► 192.168.0.1 192.168.0.x
|
||||||
|
virbr0 forwarding ┌─────────┐
|
||||||
|
│ masquerading │ tap0 ├──────────────────── mip-tap
|
||||||
|
│ └─────────┘
|
||||||
|
┌──────────────────┴──────────────────┐
|
||||||
|
│ │
|
||||||
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||||
|
│ │ vnet1 │ │ enp9s0 │ │ vnet2 │ │
|
||||||
|
│ └────┬────┘ └────┬────┘ └────┬────┘ │
|
||||||
|
│ │ │ │ │
|
||||||
|
└──────┼───────────┼───────────┼──────┘
|
||||||
|
│ │ │
|
||||||
|
│
|
||||||
|
Ethernet [WiFi]
|
||||||
|
│ Local LAN 10.1.0.x
|
||||||
|
│ DHCP server, router
|
||||||
|
▼
|
||||||
|
Internet
|
||||||
|
```
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../test/data/ca.pem
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
// Copyright (c) 2022 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
//
|
||||||
|
// example using MIP and a TUN/TAP interface
|
||||||
|
|
||||||
|
static const char *s_listening_address = "http://0.0.0.0:8000";
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#ifndef __OpenBSD__
|
||||||
|
#include <linux/if.h>
|
||||||
|
#include <linux/if_tun.h>
|
||||||
|
#else
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_tun.h>
|
||||||
|
#include <net/if_types.h>
|
||||||
|
#endif
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static int s_signo;
|
||||||
|
void signal_handler(int signo) {
|
||||||
|
s_signo = signo;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t tap_tx(const void *buf, size_t len, struct mip_if *ifp) {
|
||||||
|
ssize_t res = write(*(int*) ifp->driver_data, buf, len);
|
||||||
|
if (res < 0) {
|
||||||
|
MG_ERROR(("tap_tx failed: %d", errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (size_t) res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool tap_up(struct mip_if *ifp) {
|
||||||
|
return ifp->driver_data ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t tap_rx(void *buf, size_t len, struct mip_if *ifp) {
|
||||||
|
ssize_t received = read(*(int *) ifp->driver_data, buf, len);
|
||||||
|
usleep(1); // This is to avoid 100% CPU
|
||||||
|
if (received < 0) return 0;
|
||||||
|
return (size_t) received;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
const char *iface = "tap0"; // Network iface
|
||||||
|
const char *mac = "02:00:01:02:03:77"; // MAC address
|
||||||
|
|
||||||
|
// Parse options
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
if (strcmp(argv[i], "-i") == 0 && i + 1 < argc) {
|
||||||
|
iface = argv[++i];
|
||||||
|
} else if (strcmp(argv[i], "-mac") == 0 && i + 1 < argc) {
|
||||||
|
mac = argv[++i];
|
||||||
|
} else if (strcmp(argv[i], "-v") == 0 && i + 1 < argc) {
|
||||||
|
mg_log_set(atoi(argv[++i]));
|
||||||
|
} else {
|
||||||
|
MG_ERROR(("unknown option %s", argv[i]));
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open network interface
|
||||||
|
#ifndef __OpenBSD__
|
||||||
|
const char* tuntap_device = "/dev/net/tun";
|
||||||
|
#else
|
||||||
|
const char* tuntap_device = "/dev/tap0";
|
||||||
|
#endif
|
||||||
|
int fd = open(tuntap_device, O_RDWR);
|
||||||
|
struct ifreq ifr;
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
strncpy(ifr.ifr_name, iface, IFNAMSIZ);
|
||||||
|
#ifndef __OpenBSD__
|
||||||
|
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||||
|
if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) {
|
||||||
|
MG_ERROR(("Failed to setup TAP interface: %s", ifr.ifr_name));
|
||||||
|
abort(); // return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ifr.ifr_flags = (short)(IFF_UP | IFF_BROADCAST | IFF_MULTICAST);
|
||||||
|
if (ioctl(fd, TUNSIFMODE, (void *) &ifr) < 0) {
|
||||||
|
MG_ERROR(("Failed to setup TAP interface: %s", ifr.ifr_name));
|
||||||
|
abort(); // return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); // Non-blocking mode
|
||||||
|
|
||||||
|
MG_INFO(("Opened TAP interface: %s", iface));
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
signal(SIGTERM, signal_handler);
|
||||||
|
|
||||||
|
struct mg_mgr mgr; // Event manager
|
||||||
|
mg_mgr_init(&mgr); // Initialise event manager
|
||||||
|
|
||||||
|
struct mip_driver driver = {.tx = tap_tx, .up = tap_up, .rx = tap_rx};
|
||||||
|
struct mip_if mif = {.driver = &driver, .driver_data = &fd};
|
||||||
|
sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mif.mac[0], &mif.mac[1],
|
||||||
|
&mif.mac[2], &mif.mac[3], &mif.mac[4], &mif.mac[5]);
|
||||||
|
mip_init(&mgr, &mif);
|
||||||
|
MG_INFO(("Init done, starting main loop"));
|
||||||
|
|
||||||
|
// Start infinite event loop
|
||||||
|
MG_INFO(("Mongoose version : v%s", MG_VERSION));
|
||||||
|
MG_INFO(("Listening on : %s", s_listening_address));
|
||||||
|
|
||||||
|
extern void device_dashboard_fn(struct mg_connection *, int, void *, void *);
|
||||||
|
mg_http_listen(&mgr, s_listening_address, device_dashboard_fn, &mgr);
|
||||||
|
|
||||||
|
while (s_signo == 0) mg_mgr_poll(&mgr, 100); // Infinite event loop
|
||||||
|
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
close(fd);
|
||||||
|
printf("Exiting on signal %d\n", s_signo);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -55,13 +55,13 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
MG_INFO(("Connected to %s", s_url));
|
MG_INFO(("Connected to %s", s_url));
|
||||||
MG_INFO(("Subscribing to %s", s_rx_topic));
|
MG_INFO(("Subscribing to %s", s_rx_topic));
|
||||||
mg_mqtt_sub(c, topic, s_qos);
|
mg_mqtt_sub(c, topic, s_qos);
|
||||||
c->label[0] = 'X'; // Set a label that we're logged in
|
c->data[0] = 'X'; // Set a label that we're logged in
|
||||||
} else if (ev == MG_EV_MQTT_MSG) {
|
} else if (ev == MG_EV_MQTT_MSG) {
|
||||||
// When we receive MQTT message, print it
|
// When we receive MQTT message, print it
|
||||||
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
||||||
MG_INFO(("Received on %.*s : %.*s", (int) mm->topic.len, mm->topic.ptr,
|
MG_INFO(("Received on %.*s : %.*s", (int) mm->topic.len, mm->topic.ptr,
|
||||||
(int) mm->data.len, mm->data.ptr));
|
(int) mm->data.len, mm->data.ptr));
|
||||||
} else if (ev == MG_EV_POLL && c->label[0] == 'X') {
|
} else if (ev == MG_EV_POLL && c->data[0] == 'X') {
|
||||||
static unsigned long prev_second;
|
static unsigned long prev_second;
|
||||||
unsigned long now_second = (*(unsigned long *) ev_data) / 1000;
|
unsigned long now_second = (*(unsigned long *) ev_data) / 1000;
|
||||||
if (now_second != prev_second) {
|
if (now_second != prev_second) {
|
||||||
|
|||||||
@@ -108,6 +108,12 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case MQTT_CMD_PINGREQ: {
|
||||||
|
// The server must send a PINGRESP packet in response to a PINGREQ packet [MQTT-3.12.4-1]
|
||||||
|
MG_INFO(("PINGREQ %p -> PINGRESP", c->fd));
|
||||||
|
mg_mqtt_send_header(c, MQTT_CMD_PINGRESP, 0, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (ev == MG_EV_ACCEPT) {
|
} else if (ev == MG_EV_ACCEPT) {
|
||||||
// c->is_hexdumping = 1;
|
// c->is_hexdumping = 1;
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
include(pico-sdk/pico_sdk_init.cmake)
|
||||||
|
|
||||||
|
project(pico_rmii_ethernet)
|
||||||
|
|
||||||
|
# initialize the Pico SDK
|
||||||
|
pico_sdk_init()
|
||||||
|
|
||||||
|
add_compile_definitions(
|
||||||
|
MIP_DEBUG=1
|
||||||
|
MG_ENABLE_PACKED_FS=1
|
||||||
|
MG_ENABLE_MIP=1
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(firmware
|
||||||
|
driver_rp2040_rmii.c
|
||||||
|
main.c
|
||||||
|
mongoose.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# enable usb output, disable uart output
|
||||||
|
pico_enable_stdio_usb(firmware 1)
|
||||||
|
pico_enable_stdio_uart(firmware 0)
|
||||||
|
|
||||||
|
target_link_libraries(firmware hardware_pio hardware_dma pico_stdlib)
|
||||||
|
|
||||||
|
# create map/bin/hex file etc.
|
||||||
|
pico_add_extra_outputs(firmware)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
SDK_VERSION ?= 1.4.0
|
||||||
|
SDK_REPO ?= https://github.com/raspberrypi/pico-sdk
|
||||||
|
|
||||||
|
all example:
|
||||||
|
true
|
||||||
|
|
||||||
|
build: pico-sdk
|
||||||
|
test -d build || mkdir build
|
||||||
|
cd build && cmake .. && make
|
||||||
|
|
||||||
|
pico-sdk:
|
||||||
|
git clone --depth 1 -b $(SDK_VERSION) $(SDK_REPO) $@
|
||||||
|
cd $@ && git submodule update --init
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf pico-sdk build
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
|
||||||
|
# RMII with the PIO in an RP2040 for 10Mbps Ethernet
|
||||||
|
|
||||||
|
- Full-duplex 10Mbps
|
||||||
|
- RMII Tx implemented with a PIO state machine and single-buffer DMA transfers
|
||||||
|
- Once the DMA starts sending to the PIO, subsequent attempts to tx will block
|
||||||
|
- RMII Rx implemented with a PIO state machine and ping-pong buffer DMA transfers
|
||||||
|
- PIO code handles the CSR_DV signal, stops and raises an IRQ on frame ending. CRC is calculated later for minimum dead time between frames
|
||||||
|
- SMI implemented with a PIO state machine
|
||||||
|
- The RP2040 is clocked from the LAN8720 and works at 50MHz
|
||||||
|
- CRC calculation uses a fast table-based algorithm that doesn't require much storage (nibble calculation)
|
||||||
|
|
||||||
|
## Hardware connections
|
||||||
|
|
||||||
|
You can change most pins at will, bear in mind that each function requires consecutive pins, see main.c
|
||||||
|
The RETCLK (should be REFCLK...) pin can go to either GPIO20 or GPIO22
|
||||||
|
|
||||||
|
| LAN8720 | | Raspberry Pi Pico | |
|
||||||
|
| ----------- | ----------- |----------------- | -- |
|
||||||
|
| 1,2 | VCC | 3V3 | 36 |
|
||||||
|
| 3,4 | GND | GND | 38 |
|
||||||
|
| 5 | MDC | GPIO15 | 20 |
|
||||||
|
| 6 | MDIO | GPIO14 | 19 |
|
||||||
|
| 7 | CRS | GPIO8 | 11 |
|
||||||
|
| 8 | nINT / RETCLK | GPIO20 | 26 |
|
||||||
|
| 9 | RX1 | GPIO7 | 10 |
|
||||||
|
| 10 | RX0 | GPIO6 | 9 |
|
||||||
|
| 11 | TX0 | GPIO10 | 14 |
|
||||||
|
| 12 | TX-EN | GPIO12 | 16 |
|
||||||
|
| 13 |
|
||||||
|
| 14| TX1 | GPIO11 | 15 |
|
||||||
|
|
||||||
|
|
||||||
|
## Build and run
|
||||||
|
|
||||||
|
Clone Mongoose repo, go to this example, and build it:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/cesanta/mongoose
|
||||||
|
cd mongoose/examples/rp2040/pico-rmii
|
||||||
|
make build
|
||||||
|
```
|
||||||
|
|
||||||
|
This will generate a firmware file: `build/firmware.uf2`. Reboot your Pico board in bootloader mode, and copy it to the RPI disk.
|
||||||
|
|
||||||
|
Attach to the serial console, wait a couple of seconds, then plug in your Ethernet cable:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ picocom /dev/ttyACM0 -i -b 115200 --imap=lfcrlf
|
||||||
|
6213 1 mongoose.c:6757:onstatechange Link up
|
||||||
|
6217 3 mongoose.c:6840:tx_dhcp_discover DHCP discover sent
|
||||||
|
621b 3 mongoose.c:6723:arp_cache_add ARP cache: added 192.168.69.2 @ 52:54:...
|
||||||
|
6222 2 mongoose.c:6749:onstatechange READY, IP: 192.168.69.243
|
||||||
|
6227 2 mongoose.c:6750:onstatechange GW: 192.168.69.1
|
||||||
|
622b 2 mongoose.c:6752:onstatechange Lease: 21600 sec
|
||||||
|
```
|
||||||
|
|
||||||
|
Note the acquired IP address printed (you can also check your DHCP server). Point your browser to that address, or run curl, you should see an "ok" message:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ curl 192.168.69.243
|
||||||
|
ok
|
||||||
|
```
|
||||||
@@ -0,0 +1,366 @@
|
|||||||
|
// Copyright (c) 2022 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hardware/dma.h"
|
||||||
|
#include "hardware/pio.h"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
#include "driver_rp2040_rmii.h"
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
#define RXSM 0
|
||||||
|
#define TXSM 1
|
||||||
|
#define SMITXSM 2
|
||||||
|
#define SMIRXSM 0 // pio1
|
||||||
|
|
||||||
|
static uint smi_wr_addr, smi_rd_addr;
|
||||||
|
static int dma_rx;
|
||||||
|
static int dma_tx;
|
||||||
|
|
||||||
|
static dma_channel_config dmacfg_rx;
|
||||||
|
static dma_channel_config dmacfg_tx;
|
||||||
|
|
||||||
|
// Max frame size with VLAN tag + CRC and excluding preamble
|
||||||
|
#define ETH_PKT_SIZE 1522
|
||||||
|
|
||||||
|
static uint8_t s_rxbuf[2][ETH_PKT_SIZE]; // ping-pong buffer
|
||||||
|
static uint8_t s_txbuf[ETH_PKT_SIZE];
|
||||||
|
static struct mip_if *s_ifp; // MIP interface
|
||||||
|
|
||||||
|
#define rmii_tx_wrap_target 0
|
||||||
|
#define rmii_tx_wrap 8
|
||||||
|
|
||||||
|
static const uint16_t rmii_tx_program_instructions[] = {
|
||||||
|
// .wrap_target
|
||||||
|
0xe000, // 0: set pins, 0 side 0
|
||||||
|
0x80a0, // 1: pull block side 0
|
||||||
|
0xe03d, // 2: set x, 29 side 0
|
||||||
|
0xf101, // 3: set pins, 1 side 1 [1]
|
||||||
|
0x1144, // 4: jmp x--, 4 side 1 [1]
|
||||||
|
0xf103, // 5: set pins, 3 side 1 [1]
|
||||||
|
0x7002, // 6: out pins, 2 side 1
|
||||||
|
0x10e6, // 7: jmp !osre, 6 side 1
|
||||||
|
// .wrap
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pio_program rmii_tx_program = {
|
||||||
|
.instructions = rmii_tx_program_instructions,
|
||||||
|
.length = 9,
|
||||||
|
.origin = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline pio_sm_config rmii_tx_program_get_default_config(uint addr) {
|
||||||
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
|
sm_config_set_wrap(&c, addr + rmii_tx_wrap_target, addr + rmii_tx_wrap);
|
||||||
|
sm_config_set_sideset(&c, 1, false, false);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rmii_tx_init(PIO pio, uint sm, uint addr, uint gpio) {
|
||||||
|
pio_sm_config c = rmii_tx_program_get_default_config(addr);
|
||||||
|
pio_gpio_init(pio, gpio);
|
||||||
|
pio_gpio_init(pio, gpio + 1);
|
||||||
|
pio_gpio_init(pio, gpio + 2);
|
||||||
|
sm_config_set_out_pins(&c, gpio, 2);
|
||||||
|
sm_config_set_set_pins(&c, gpio, 2);
|
||||||
|
sm_config_set_sideset_pins(&c, gpio + 2);
|
||||||
|
pio_sm_set_consecutive_pindirs(pio, sm, gpio, 3, true);
|
||||||
|
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||||
|
sm_config_set_out_shift(&c, true, true, 8); // pull bytes, LSB first, auto
|
||||||
|
sm_config_set_clkdiv(&c,
|
||||||
|
5); // Run at 50/5 = 10MHz (2x 2-bit nibble data rate)
|
||||||
|
pio_sm_init(pio, sm, addr, &c);
|
||||||
|
pio_sm_set_enabled(pio, sm, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define rmii_rx_wrap_target 0
|
||||||
|
#define rmii_rx_wrap 10
|
||||||
|
|
||||||
|
static const uint16_t rmii_rx_program_instructions[] = {
|
||||||
|
// .wrap_target
|
||||||
|
0x2122, // 0: wait 0 pin, 2 [1]
|
||||||
|
0x21a2, // 1: wait 1 pin, 2 [1]
|
||||||
|
0x21a0, // 2: wait 1 pin, 0 [1]
|
||||||
|
0x2121, // 3: wait 0 pin, 1 [1]
|
||||||
|
0x21a1, // 4: wait 1 pin, 1 [1]
|
||||||
|
0x4002, // 5: in pins, 2
|
||||||
|
0x00c5, // 6: jmp pin, 5
|
||||||
|
0x4002, // 7: in pins, 2
|
||||||
|
0x00c5, // 8: jmp pin, 5
|
||||||
|
0xa0c3, // 9: mov isr, null
|
||||||
|
0xc020, // 10: irq wait 0
|
||||||
|
// .wrap
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pio_program rmii_rx_program = {
|
||||||
|
.instructions = rmii_rx_program_instructions,
|
||||||
|
.length = 11,
|
||||||
|
.origin = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline pio_sm_config rmii_rx_program_get_default_config(uint addr) {
|
||||||
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
|
sm_config_set_wrap(&c, addr + rmii_rx_wrap_target, addr + rmii_rx_wrap);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rmii_rx_init(PIO pio, uint sm, uint addr, uint gpio) {
|
||||||
|
pio_sm_config c = rmii_rx_program_get_default_config(addr);
|
||||||
|
pio_gpio_init(pio, gpio);
|
||||||
|
pio_gpio_init(pio, gpio + 1);
|
||||||
|
pio_gpio_init(pio, gpio + 2);
|
||||||
|
sm_config_set_in_pins(&c, gpio);
|
||||||
|
pio_sm_set_consecutive_pindirs(pio, sm, gpio, 3, false);
|
||||||
|
sm_config_set_jmp_pin(&c, gpio + 2);
|
||||||
|
sm_config_set_in_shift(&c, true, true, 8); // push bytes, LSB first, auto
|
||||||
|
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
|
||||||
|
sm_config_set_clkdiv(&c,
|
||||||
|
5); // Run at 50/5 = 10MHz (2x 2-bit nibble data rate)
|
||||||
|
pio_sm_init(pio, sm, addr, &c);
|
||||||
|
pio_sm_set_enabled(pio, sm, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define smi_wr_wrap_target 0
|
||||||
|
#define smi_wr_wrap 4
|
||||||
|
|
||||||
|
static const uint16_t smi_wr_program_instructions[] = {
|
||||||
|
// .wrap_target
|
||||||
|
0xe03f, // 0: set x, 31 side 0
|
||||||
|
0xe101, // 1: set pins, 1 side 0 [1]
|
||||||
|
0x1141, // 2: jmp x--, 1 side 1 [1]
|
||||||
|
0x6101, // 3: out pins, 1 side 0 [1]
|
||||||
|
0x1103, // 4: jmp 3 side 1 [1]
|
||||||
|
// .wrap
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pio_program smi_wr_program = {
|
||||||
|
.instructions = smi_wr_program_instructions,
|
||||||
|
.length = 5,
|
||||||
|
.origin = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline pio_sm_config smi_wr_program_get_default_config(uint addr) {
|
||||||
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
|
sm_config_set_wrap(&c, addr + smi_wr_wrap_target, addr + smi_wr_wrap);
|
||||||
|
sm_config_set_sideset(&c, 1, false, false);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define smi_rd_wrap_target 13
|
||||||
|
#define smi_rd_wrap 13
|
||||||
|
|
||||||
|
static const uint16_t smi_rd_program_instructions[] = {
|
||||||
|
0xe03f, // 0: set x, 31 side 0
|
||||||
|
0xe101, // 1: set pins, 1 side 0 [1]
|
||||||
|
0x1141, // 2: jmp x--, 1 side 1 [1]
|
||||||
|
0xf02d, // 3: set x, 13 side 1
|
||||||
|
0x6101, // 4: out pins, 1 side 0 [1]
|
||||||
|
0x1144, // 5: jmp x--, 4 side 1 [1]
|
||||||
|
0xe180, // 6: set pindirs, 0 side 0 [1]
|
||||||
|
0xf101, // 7: set pins, 1 side 1 [1]
|
||||||
|
0xa142, // 8: nop side 0 [1]
|
||||||
|
0xf12f, // 9: set x, 15 side 1 [1]
|
||||||
|
0xa042, // 10: nop side 0
|
||||||
|
0x4001, // 11: in pins, 1 side 0
|
||||||
|
0x114a, // 12: jmp x--, 10 side 1 [1]
|
||||||
|
// .wrap_target
|
||||||
|
0xf081, // 13: set pindirs, 1 side 1
|
||||||
|
// .wrap
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pio_program smi_rd_program = {
|
||||||
|
.instructions = smi_rd_program_instructions,
|
||||||
|
.length = 14,
|
||||||
|
.origin = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline pio_sm_config smi_rd_program_get_default_config(uint addr) {
|
||||||
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
|
sm_config_set_wrap(&c, addr + smi_rd_wrap_target, addr + smi_rd_wrap);
|
||||||
|
sm_config_set_sideset(&c, 1, false, false);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void smi_wr_init(PIO pio, uint sm, uint addr, uint gpio) {
|
||||||
|
pio_gpio_init(pio, gpio);
|
||||||
|
pio_gpio_init(pio, gpio + 1);
|
||||||
|
pio_sm_config c = smi_wr_program_get_default_config(addr);
|
||||||
|
sm_config_set_out_pins(&c, gpio, 1);
|
||||||
|
sm_config_set_set_pins(&c, gpio, 1);
|
||||||
|
sm_config_set_sideset_pins(&c, gpio + 1);
|
||||||
|
pio_sm_set_consecutive_pindirs(pio, sm, gpio, 2, true);
|
||||||
|
sm_config_set_out_shift(&c, false, true,
|
||||||
|
16); // pull half-words, MSB first, auto
|
||||||
|
sm_config_set_clkdiv(&c, 6); // Run at 50/6 = <10MHz (4x data rate)
|
||||||
|
pio_sm_init(pio, sm, addr, &c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void smi_rd_init(PIO pio, uint sm, uint addr, uint gpio) {
|
||||||
|
pio_gpio_init(pio, gpio);
|
||||||
|
pio_gpio_init(pio, gpio + 1);
|
||||||
|
pio_sm_config c = smi_rd_program_get_default_config(addr);
|
||||||
|
sm_config_set_in_pins(&c, gpio);
|
||||||
|
sm_config_set_out_pins(&c, gpio, 1);
|
||||||
|
sm_config_set_set_pins(&c, gpio, 1);
|
||||||
|
sm_config_set_sideset_pins(&c, gpio + 1);
|
||||||
|
pio_sm_set_consecutive_pindirs(pio, sm, gpio, 2, true);
|
||||||
|
sm_config_set_out_shift(&c, false, true,
|
||||||
|
16); // pull half-words, MSB first, auto
|
||||||
|
sm_config_set_in_shift(&c, false, true,
|
||||||
|
16); // push half-words, MSB first, auto
|
||||||
|
sm_config_set_clkdiv(&c, 6); // Run at 50/6 = <10MHz (4x data rate)
|
||||||
|
pio_sm_init(pio, sm, addr, &c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t crc_calc(const uint8_t *data, int length) {
|
||||||
|
static const uint32_t crclut[16] = {
|
||||||
|
// table for polynomial 0xEDB88320 (reflected)
|
||||||
|
0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC, 0x76DC4190, 0x6B6B51F4,
|
||||||
|
0x4DB26158, 0x5005713C, 0xEDB88320, 0xF00F9344, 0xD6D6A3E8, 0xCB61B38C,
|
||||||
|
0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 0xBDBDF21C};
|
||||||
|
uint32_t crc = 0xFFFFFFFF;
|
||||||
|
while (--length >= 0) {
|
||||||
|
uint8_t byte = *data++;
|
||||||
|
crc = crclut[(crc ^ byte) & 0x0F] ^ (crc >> 4);
|
||||||
|
crc = crclut[(crc ^ (byte >> 4)) & 0x0F] ^ (crc >> 4);
|
||||||
|
}
|
||||||
|
return ~crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eth_write_phy(int addr, int reg, int val, uint8_t gpio) {
|
||||||
|
uint16_t op = 0x5002 | (addr << 7) | (reg << 2); // b0101aaaaarrrrr10
|
||||||
|
smi_wr_init(pio0, SMITXSM, smi_wr_addr, gpio);
|
||||||
|
pio_sm_put(pio0, SMITXSM, op << 16);
|
||||||
|
pio_sm_put(pio0, SMITXSM, (uint16_t) val << 16);
|
||||||
|
pio_sm_set_enabled(pio0, SMITXSM, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t eth_read_phy(uint addr, uint reg, uint8_t gpio) {
|
||||||
|
uint16_t op = 0x6000 | (addr << 7) | (reg << 2); // b0110aaaaarrrrr00
|
||||||
|
smi_rd_init(pio1, SMIRXSM, smi_rd_addr, gpio);
|
||||||
|
pio_sm_put(pio1, SMIRXSM, op << 16);
|
||||||
|
pio_sm_set_enabled(pio1, SMIRXSM, true);
|
||||||
|
uint16_t val = (uint16_t) pio_sm_get_blocking(pio1, SMIRXSM);
|
||||||
|
pio_sm_set_enabled(pio1, SMIRXSM, false);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rx_irq(void);
|
||||||
|
|
||||||
|
static bool mip_driver_rp2040_rmii_init(struct mip_if *ifp) {
|
||||||
|
struct mip_driver_rp2040_rmii_data *d =
|
||||||
|
(struct mip_driver_rp2040_rmii_data *) ifp->driver_data;
|
||||||
|
uint rx_sm_addr, tx_sm_addr;
|
||||||
|
s_ifp = ifp;
|
||||||
|
if (ifp->queue.len == 0) ifp->queue.len = 8192;
|
||||||
|
rx_sm_addr = pio_add_program(pio0, &rmii_rx_program);
|
||||||
|
tx_sm_addr = pio_add_program(pio0, &rmii_tx_program);
|
||||||
|
smi_wr_addr = pio_add_program(pio0, &smi_wr_program);
|
||||||
|
smi_rd_addr = pio_add_program(pio1, &smi_rd_program);
|
||||||
|
|
||||||
|
dma_tx = dma_claim_unused_channel(true);
|
||||||
|
dmacfg_tx = dma_channel_get_default_config(dma_tx);
|
||||||
|
channel_config_set_read_increment(&dmacfg_tx, true); // read from memory
|
||||||
|
channel_config_set_write_increment(&dmacfg_tx, false); // write to FIFO
|
||||||
|
channel_config_set_dreq(&dmacfg_tx, pio_get_dreq(pio0, TXSM, true));
|
||||||
|
channel_config_set_transfer_data_size(&dmacfg_tx,
|
||||||
|
DMA_SIZE_8); // transfer bytes
|
||||||
|
rmii_tx_init(pio0, TXSM, tx_sm_addr, d->tx0);
|
||||||
|
|
||||||
|
eth_write_phy(d->phy_addr, 4, 0x61,
|
||||||
|
d->mdio); // Auto Negotiation Advertisement Register: enable
|
||||||
|
// only 10BASE-T full and half duplex (two-pair), use
|
||||||
|
// IEEE 802.3 format
|
||||||
|
sleep_us(31); // give some time for PIO to work (64 bits @2.5MHz = 25.6 us)
|
||||||
|
eth_write_phy(d->phy_addr, 0, 0x1000,
|
||||||
|
d->mdio); // Basic Control Register: enable Auto-Negotiation
|
||||||
|
sleep_us(31);
|
||||||
|
|
||||||
|
dma_rx = dma_claim_unused_channel(true);
|
||||||
|
dmacfg_rx = dma_channel_get_default_config(dma_rx);
|
||||||
|
channel_config_set_read_increment(&dmacfg_rx, false); // read from FIFO
|
||||||
|
channel_config_set_write_increment(&dmacfg_rx,
|
||||||
|
true); // write to memory, increment
|
||||||
|
channel_config_set_dreq(&dmacfg_rx, pio_get_dreq(pio0, RXSM, false));
|
||||||
|
channel_config_set_transfer_data_size(&dmacfg_rx,
|
||||||
|
DMA_SIZE_8); // transfer bytes
|
||||||
|
dma_channel_configure(dma_rx, &dmacfg_rx, s_rxbuf[0],
|
||||||
|
((uint8_t *) &pio0->rxf[RXSM]) + 3, ETH_PKT_SIZE, true);
|
||||||
|
pio_set_irq0_source_enabled(pio0, pis_interrupt0,
|
||||||
|
true); // enable SM0 on PIO0_IRQ_0
|
||||||
|
irq_set_exclusive_handler(7, rx_irq); // set handler for PIO0_IRQ_0
|
||||||
|
irq_set_enabled(7, true); // enable it
|
||||||
|
rmii_rx_init(pio0, RXSM, rx_sm_addr, d->rx0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t mip_driver_rp2040_rmii_tx(const void *buf, size_t len,
|
||||||
|
struct mip_if *ifp) {
|
||||||
|
dma_channel_wait_for_finish_blocking(dma_tx);
|
||||||
|
memset(s_txbuf, 0, 60); // pre-pad
|
||||||
|
memcpy(s_txbuf, buf, len);
|
||||||
|
if (len < 60) len = 60; // pad
|
||||||
|
uint32_t crc = crc_calc(s_txbuf, len); // host is little-endian
|
||||||
|
memcpy(s_txbuf + len, (uint8_t *) &crc, 4);
|
||||||
|
len += 4;
|
||||||
|
sleep_us(10); // enforce IFG in case software has been lightning fast...
|
||||||
|
dma_channel_configure(dma_tx, &dmacfg_tx, ((uint8_t *) &pio0->txf[TXSM]) + 3,
|
||||||
|
s_txbuf, len, true);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t s_rxno;
|
||||||
|
|
||||||
|
// The max amount of time we should keep the PIO state machine stopped is the
|
||||||
|
// IFG time (10us) and that includes irq latency
|
||||||
|
static void rx_irq(void) {
|
||||||
|
dma_channel_hw_t *hw = dma_channel_hw_addr(dma_rx);
|
||||||
|
uint32_t rxno =
|
||||||
|
(s_rxno + 1) &
|
||||||
|
1; // 2 buffers, switch to the available one as fast as possible
|
||||||
|
size_t len = ETH_PKT_SIZE - hw->transfer_count;
|
||||||
|
dma_channel_abort(dma_rx);
|
||||||
|
dma_channel_set_write_addr(dma_rx, s_rxbuf[rxno], true); // restart DMA
|
||||||
|
pio_interrupt_clear(pio0,
|
||||||
|
0); // ACK PIO IRQ so the state machine resumes receiving
|
||||||
|
// NOTE(scaprile) Here we could check addressing to avoid queuing frames not
|
||||||
|
// for us, or we can defer that for later as we do with CRC The max amount of
|
||||||
|
// time we can linger here is what it takes for the other buffer to fill
|
||||||
|
// (<8us) and that includes irq chaining
|
||||||
|
if (len >= 64 && len <= ETH_PKT_SIZE)
|
||||||
|
mip_qwrite(s_rxbuf[s_rxno], len, s_ifp);
|
||||||
|
s_rxno = rxno;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t mip_driver_rp2040_rmii_rx(void *buf, size_t buflen, struct mip_if *ifp) {
|
||||||
|
size_t len = mip_qread(buf, ifp);
|
||||||
|
if (len == 0) return 0;
|
||||||
|
len -= 4; // exclude CRC from frame length
|
||||||
|
uint32_t crc = crc_calc(buf, len); // calculate CRC and compare
|
||||||
|
// NOTE(scaprile) Here we could check addressing to avoid delivering frames
|
||||||
|
// not for us, though MIP already does that (now ?)
|
||||||
|
if (memcmp(&((uint8_t *) buf)[len], &crc,
|
||||||
|
sizeof(crc))) // host is little-endian
|
||||||
|
return 0;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mip_driver_rp2040_rmii_up(struct mip_if *ifp) {
|
||||||
|
struct mip_driver_rp2040_rmii_data *d =
|
||||||
|
(struct mip_driver_rp2040_rmii_data *) ifp->driver_data;
|
||||||
|
uint32_t bsr =
|
||||||
|
eth_read_phy(d->phy_addr, 1, d->mdio); // Basic Status Register
|
||||||
|
return (bsr & (1 << 2)) ? 1 : 0; // check Link Status flag
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mip_driver mip_driver_rp2040_rmii = {
|
||||||
|
mip_driver_rp2040_rmii_init,
|
||||||
|
mip_driver_rp2040_rmii_tx,
|
||||||
|
mip_driver_rp2040_rmii_rx,
|
||||||
|
mip_driver_rp2040_rmii_up,
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct mip_driver_rp2040_rmii_data {
|
||||||
|
uint8_t rx0; // RX0, RX1, CRS_DV; consecutive GPIO pins
|
||||||
|
uint8_t tx0; // TX0, TX1, TX-EN; consecutive GPIO pins
|
||||||
|
uint8_t mdio; // MDIO, MDC; consecutive GPIO pins
|
||||||
|
uint8_t phy_addr; // PHY address
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct mip_driver mip_driver_rp2040_rmii;
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright (c) 2022 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "hardware/clocks.h"
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
#include "driver_rp2040_rmii.h"
|
||||||
|
|
||||||
|
#define CLKREFPIN 20 // either 20 or 22
|
||||||
|
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
mg_http_reply(c, 200, "", "ok\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
// use the RMII reference clock (50MHz) as our system clock
|
||||||
|
clock_configure_gpin(clk_sys, CLKREFPIN, 50 * MHZ, 50 * MHZ);
|
||||||
|
sleep_ms(100);
|
||||||
|
stdio_init_all();
|
||||||
|
|
||||||
|
struct mg_mgr mgr; // Initialise Mongoose event manager
|
||||||
|
mg_mgr_init(&mgr); // and attach it to the MIP interface
|
||||||
|
mg_log_set(MG_LL_DEBUG); // Set log level
|
||||||
|
|
||||||
|
MG_INFO(("Init MIP"));
|
||||||
|
// Initialise Mongoose network stack and specific driver
|
||||||
|
// Set consecutive GPIOs for RMII (tx and rx) and SMI function groups
|
||||||
|
struct mip_driver_rp2040_rmii_data driver_data = {
|
||||||
|
// see driver_rp2040_rmii.h
|
||||||
|
.rx0 = 6, // 6, 7, 8 : RX0, RX1, CRS_DV
|
||||||
|
.tx0 = 10, // 10, 11, 12 : TX0, TX1, TX-EN
|
||||||
|
.mdio = 14, // 14, 15 : MDIO, MDC
|
||||||
|
.phy_addr = 1 // check your hardware, LAN8722 is 0 or 1
|
||||||
|
};
|
||||||
|
// Specify MAC address, either set use_dhcp or enter a static config.
|
||||||
|
// For static configuration, specify IP/mask/GW in network byte order
|
||||||
|
struct mip_if mif = {
|
||||||
|
.mac = {2, 0, 1, 2, 3, 5},
|
||||||
|
.ip = 0,
|
||||||
|
.driver = &mip_driver_rp2040_rmii,
|
||||||
|
.driver_data = &driver_data,
|
||||||
|
};
|
||||||
|
mip_init(&mgr, &mif);
|
||||||
|
mg_http_listen(&mgr, "http://0.0.0.0", fn, NULL); // HTTP listener
|
||||||
|
MG_INFO(("Init done, starting main loop"));
|
||||||
|
|
||||||
|
for (;;) mg_mgr_poll(&mgr, 0); // Infinite event loop
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mongoose.c
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../../mongoose.h
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
include(pico-sdk/pico_sdk_init.cmake)
|
||||||
|
|
||||||
|
project(firmware)
|
||||||
|
pico_sdk_init()
|
||||||
|
|
||||||
|
add_executable(firmware
|
||||||
|
main.c
|
||||||
|
../../../mongoose.c
|
||||||
|
../../device-dashboard/net.c
|
||||||
|
../../device-dashboard/packed_fs.c
|
||||||
|
pico-sdk//lib/tinyusb/examples/device/net_lwip_webserver/src/usb_descriptors.c
|
||||||
|
pico-sdk/lib/tinyusb/lib/networking/rndis_reports.c)
|
||||||
|
|
||||||
|
target_include_directories(firmware PUBLIC
|
||||||
|
.
|
||||||
|
../../..
|
||||||
|
pico-sdk/lib/tinyusb/lib/networking)
|
||||||
|
|
||||||
|
target_link_libraries(firmware pico_stdlib hardware_spi tinyusb_device)
|
||||||
|
pico_add_extra_outputs(firmware)
|
||||||
|
|
||||||
|
pico_enable_stdio_usb(firmware 0) # Route stdio
|
||||||
|
pico_enable_stdio_uart(firmware 1) # to the UART
|
||||||
|
|
||||||
|
# Mongoose build flags
|
||||||
|
add_definitions(-DMG_ENABLE_MIP=1)
|
||||||
|
add_definitions(-DMG_ENABLE_PACKED_FS=1)
|
||||||
|
add_definitions(-DMG_ENABLE_FILE=0)
|
||||||
|
add_definitions(-DDISABLE_ROUTING=1)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
SDK_VERSION ?= 1.4.0
|
||||||
|
SDK_REPO ?= https://github.com/raspberrypi/pico-sdk
|
||||||
|
|
||||||
|
example:
|
||||||
|
true
|
||||||
|
|
||||||
|
all build: pico-sdk
|
||||||
|
test -d build || mkdir build
|
||||||
|
cd build && cmake .. && make
|
||||||
|
|
||||||
|
pico-sdk:
|
||||||
|
git clone --depth 1 -b $(SDK_VERSION) $(SDK_REPO) $@
|
||||||
|
cd $@ && git submodule update --init
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf pico-sdk build
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
# Device Dashboard via RNDIS on an RP2040
|
||||||
|
|
||||||
|
Your headless Raspberry Pi Pico-based hardware can also have a device dashboard on a web browser when you connect it to your computer via USB
|
||||||
|
|
||||||
|
## Build and run
|
||||||
|
|
||||||
|
Clone Mongoose repo, go to this example, and build it:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/cesanta/mongoose
|
||||||
|
cd mongoose/examples/rp2040/pico-rndis-dashboard
|
||||||
|
make build
|
||||||
|
```
|
||||||
|
|
||||||
|
This will generate a firmware file: `build/firmware.uf2`. Reboot your Pico board in bootloader mode, and copy it to the RPI disk.
|
||||||
|
|
||||||
|
The device will reboot, register as a USB RNDIS device, and add a network to your computer.
|
||||||
|
Run a browser, and open 192.168.3.1, you should see a device dashboard
|
||||||
|
|
||||||
|
Note: USB stdio in the Pico-SDK is done in background with TinyUSB and an interrupt to hide it from the user and periodically call tusb_task(). When we use TinyUSB, that code is removed from the compilation list; so this example uses UART stdio (UART 0) to keep things simple and focused on the RNDIS example. If you want to see the console output, connect an USB-to-UART or a low-voltage-TTL-to-RS-232 adapter to GPIO0
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
// Copyright (c) 2022 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
|
static struct mip_if *s_ifp;
|
||||||
|
|
||||||
|
const uint8_t tud_network_mac_address[6] = {2, 2, 0x84, 0x6A, 0x96, 0};
|
||||||
|
|
||||||
|
static void blink_cb(void *arg) { // Blink periodically
|
||||||
|
gpio_put(PICO_DEFAULT_LED_PIN, !gpio_get_out_level(PICO_DEFAULT_LED_PIN));
|
||||||
|
(void) arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tud_network_recv_cb(const uint8_t *buf, uint16_t len) {
|
||||||
|
mip_qwrite((void *) buf, len, s_ifp);
|
||||||
|
// MG_INFO(("RECV %hu", len));
|
||||||
|
// mg_hexdump(buf, len);
|
||||||
|
tud_network_recv_renew();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tud_network_init_cb(void) {}
|
||||||
|
|
||||||
|
uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) {
|
||||||
|
// MG_INFO(("SEND %hu", arg));
|
||||||
|
memcpy(dst, ref, arg);
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t usb_tx(const void *buf, size_t len, struct mip_if *ifp) {
|
||||||
|
if (!tud_ready()) return 0;
|
||||||
|
while (!tud_network_can_xmit(len)) tud_task();
|
||||||
|
tud_network_xmit((void *) buf, len);
|
||||||
|
(void) ifp;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool usb_up(struct mip_if *ifp) {
|
||||||
|
(void) ifp;
|
||||||
|
return tud_inited() && tud_ready() && tud_connected();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_dta) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) return mg_http_reply(c, 200, "", "ok\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
gpio_init(PICO_DEFAULT_LED_PIN);
|
||||||
|
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
||||||
|
stdio_init_all();
|
||||||
|
|
||||||
|
struct mg_mgr mgr; // Initialise Mongoose event manager
|
||||||
|
mg_mgr_init(&mgr); // and attach it to the MIP interface
|
||||||
|
mg_timer_add(&mgr, 500, MG_TIMER_REPEAT, blink_cb, &mgr);
|
||||||
|
|
||||||
|
struct mip_driver driver = {.tx = usb_tx, .rx = mip_driver_rx, .up = usb_up};
|
||||||
|
struct mip_if mif = {.mac = {2, 0, 1, 2, 3, 0x77},
|
||||||
|
.ip = mg_htonl(MG_U32(192, 168, 3, 1)),
|
||||||
|
.mask = mg_htonl(MG_U32(255, 255, 255, 0)),
|
||||||
|
.enable_dhcp_server = true,
|
||||||
|
.driver = &driver,
|
||||||
|
.queue.len = 4096};
|
||||||
|
s_ifp = &mif;
|
||||||
|
mip_init(&mgr, &mif);
|
||||||
|
tusb_init();
|
||||||
|
|
||||||
|
MG_INFO(("Initialising application..."));
|
||||||
|
extern void device_dashboard_fn(struct mg_connection *, int, void *, void *);
|
||||||
|
mg_http_listen(&mgr, "http://0.0.0.0", device_dashboard_fn, &mgr);
|
||||||
|
|
||||||
|
MG_INFO(("Starting event loop"));
|
||||||
|
for (;;) {
|
||||||
|
mg_mgr_poll(&mgr, 0);
|
||||||
|
tud_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#pragma once
|
||||||
|
#define SIZEOF_ETH_HDR 14
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CFG_TUD_ECM_RNDIS 1
|
||||||
|
#if 0
|
||||||
|
#define CFG_TUD_MSC 1 // This enables mass storage
|
||||||
|
#define CFG_TUD_MSC_EP_BUFSIZE 512 // Also Add msc_disk.c and descritprs
|
||||||
|
#endif
|
||||||
|
#define CFG_TUD_NCM 0
|
||||||
|
#define BOARD_DEVICE_RHPORT_NUM 0
|
||||||
|
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
|
||||||
|
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
|
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
|
||||||
|
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
|
||||||
|
*
|
||||||
|
* Auto ProductID layout's Bitmap:
|
||||||
|
* [MSB] NET | VENDOR | MIDI | HID | MSC | CDC [LSB]
|
||||||
|
*/
|
||||||
|
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
|
||||||
|
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
|
||||||
|
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) | _PID_MAP(ECM_RNDIS, 5) | _PID_MAP(NCM, 5) )
|
||||||
|
|
||||||
|
// String Descriptor Index
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
STRID_LANGID = 0,
|
||||||
|
STRID_MANUFACTURER,
|
||||||
|
STRID_PRODUCT,
|
||||||
|
STRID_SERIAL,
|
||||||
|
STRID_INTERFACE,
|
||||||
|
STRID_MAC
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ITF_NUM_CDC = 0,
|
||||||
|
ITF_NUM_CDC_DATA,
|
||||||
|
ITF_NUM_TOTAL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
#if CFG_TUD_ECM_RNDIS
|
||||||
|
CONFIG_ID_RNDIS = 0,
|
||||||
|
CONFIG_ID_ECM = 1,
|
||||||
|
#else
|
||||||
|
CONFIG_ID_NCM = 0,
|
||||||
|
#endif
|
||||||
|
CONFIG_ID_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Device Descriptors
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
tusb_desc_device_t const desc_device =
|
||||||
|
{
|
||||||
|
.bLength = sizeof(tusb_desc_device_t),
|
||||||
|
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||||
|
.bcdUSB = 0x0200,
|
||||||
|
|
||||||
|
// Use Interface Association Descriptor (IAD) device class
|
||||||
|
.bDeviceClass = TUSB_CLASS_MISC,
|
||||||
|
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||||
|
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||||
|
|
||||||
|
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||||
|
|
||||||
|
.idVendor = 0xCafe,
|
||||||
|
.idProduct = USB_PID,
|
||||||
|
.bcdDevice = 0x0101,
|
||||||
|
|
||||||
|
.iManufacturer = STRID_MANUFACTURER,
|
||||||
|
.iProduct = STRID_PRODUCT,
|
||||||
|
.iSerialNumber = STRID_SERIAL,
|
||||||
|
|
||||||
|
.bNumConfigurations = CONFIG_ID_COUNT // multiple configurations
|
||||||
|
};
|
||||||
|
|
||||||
|
// Invoked when received GET DEVICE DESCRIPTOR
|
||||||
|
// Application return pointer to descriptor
|
||||||
|
uint8_t const * tud_descriptor_device_cb(void)
|
||||||
|
{
|
||||||
|
return (uint8_t const *) &desc_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Configuration Descriptor
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
#define MAIN_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_RNDIS_DESC_LEN)
|
||||||
|
#define ALT_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_ECM_DESC_LEN)
|
||||||
|
#define NCM_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_NCM_DESC_LEN)
|
||||||
|
|
||||||
|
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
|
||||||
|
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
|
||||||
|
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
|
||||||
|
#define EPNUM_NET_NOTIF 0x81
|
||||||
|
#define EPNUM_NET_OUT 0x02
|
||||||
|
#define EPNUM_NET_IN 0x82
|
||||||
|
|
||||||
|
#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
|
||||||
|
// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
|
||||||
|
// e.g EP1 OUT & EP1 IN cannot exist together
|
||||||
|
#define EPNUM_NET_NOTIF 0x81
|
||||||
|
#define EPNUM_NET_OUT 0x02
|
||||||
|
#define EPNUM_NET_IN 0x83
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define EPNUM_NET_NOTIF 0x81
|
||||||
|
#define EPNUM_NET_OUT 0x02
|
||||||
|
#define EPNUM_NET_IN 0x82
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CFG_TUD_ECM_RNDIS
|
||||||
|
|
||||||
|
static uint8_t const rndis_configuration[] =
|
||||||
|
{
|
||||||
|
// Config number (index+1), interface count, string index, total length, attribute, power in mA
|
||||||
|
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_RNDIS+1, ITF_NUM_TOTAL, 0, MAIN_CONFIG_TOTAL_LEN, 0, 100),
|
||||||
|
|
||||||
|
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
||||||
|
TUD_RNDIS_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, EPNUM_NET_NOTIF, 8, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE),
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t const ecm_configuration[] =
|
||||||
|
{
|
||||||
|
// Config number (index+1), interface count, string index, total length, attribute, power in mA
|
||||||
|
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_ECM+1, ITF_NUM_TOTAL, 0, ALT_CONFIG_TOTAL_LEN, 0, 100),
|
||||||
|
|
||||||
|
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
|
||||||
|
TUD_CDC_ECM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static uint8_t const ncm_configuration[] =
|
||||||
|
{
|
||||||
|
// Config number (index+1), interface count, string index, total length, attribute, power in mA
|
||||||
|
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_NCM+1, ITF_NUM_TOTAL, 0, NCM_CONFIG_TOTAL_LEN, 0, 100),
|
||||||
|
|
||||||
|
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
|
||||||
|
TUD_CDC_NCM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Configuration array: RNDIS and CDC-ECM
|
||||||
|
// - Windows only works with RNDIS
|
||||||
|
// - MacOS only works with CDC-ECM
|
||||||
|
// - Linux will work on both
|
||||||
|
static uint8_t const * const configuration_arr[2] =
|
||||||
|
{
|
||||||
|
#if CFG_TUD_ECM_RNDIS
|
||||||
|
[CONFIG_ID_RNDIS] = rndis_configuration,
|
||||||
|
[CONFIG_ID_ECM ] = ecm_configuration
|
||||||
|
#else
|
||||||
|
[CONFIG_ID_NCM ] = ncm_configuration
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
||||||
|
// Application return pointer to descriptor
|
||||||
|
// Descriptor contents must exist long enough for transfer to complete
|
||||||
|
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
|
||||||
|
{
|
||||||
|
return (index < CONFIG_ID_COUNT) ? configuration_arr[index] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// String Descriptors
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// array of pointer to string descriptors
|
||||||
|
static char const* string_desc_arr [] =
|
||||||
|
{
|
||||||
|
[STRID_LANGID] = (const char[]) { 0x09, 0x04 }, // supported language is English (0x0409)
|
||||||
|
[STRID_MANUFACTURER] = "TinyUSB", // Manufacturer
|
||||||
|
[STRID_PRODUCT] = "TinyUSB Device", // Product
|
||||||
|
[STRID_SERIAL] = "123456", // Serial
|
||||||
|
[STRID_INTERFACE] = "TinyUSB Network Interface" // Interface Description
|
||||||
|
|
||||||
|
// STRID_MAC index is handled separately
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint16_t _desc_str[32];
|
||||||
|
|
||||||
|
// Invoked when received GET STRING DESCRIPTOR request
|
||||||
|
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
||||||
|
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||||
|
{
|
||||||
|
(void) langid;
|
||||||
|
|
||||||
|
unsigned int chr_count = 0;
|
||||||
|
|
||||||
|
if (STRID_LANGID == index)
|
||||||
|
{
|
||||||
|
memcpy(&_desc_str[1], string_desc_arr[STRID_LANGID], 2);
|
||||||
|
chr_count = 1;
|
||||||
|
}
|
||||||
|
else if (STRID_MAC == index)
|
||||||
|
{
|
||||||
|
// Convert MAC address into UTF-16
|
||||||
|
|
||||||
|
for (unsigned i=0; i<sizeof(tud_network_mac_address); i++)
|
||||||
|
{
|
||||||
|
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 4) & 0xf];
|
||||||
|
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 0) & 0xf];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
||||||
|
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
||||||
|
|
||||||
|
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
|
||||||
|
|
||||||
|
const char* str = string_desc_arr[index];
|
||||||
|
|
||||||
|
// Cap at max char
|
||||||
|
chr_count = (uint8_t) strlen(str);
|
||||||
|
if ( chr_count > (TU_ARRAY_SIZE(_desc_str) - 1)) chr_count = TU_ARRAY_SIZE(_desc_str) - 1;
|
||||||
|
|
||||||
|
// Convert ASCII string into UTF-16
|
||||||
|
for (unsigned int i=0; i<chr_count; i++)
|
||||||
|
{
|
||||||
|
_desc_str[1+i] = str[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// first byte is length (including header), second byte is string type
|
||||||
|
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
|
||||||
|
|
||||||
|
return _desc_str;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
NAME = raspberry-pi-pico-w
|
||||||
|
|
||||||
|
$(NAME):
|
||||||
|
git clone --depth 1 https://github.com/mongoose-examples/$(NAME)
|
||||||
|
|
||||||
|
build: | $(NAME)
|
||||||
|
cp ./../../../mongoose.[ch] $(NAME)
|
||||||
|
cp ./../../device-dashboard/packed_fs.c $(NAME)
|
||||||
|
cp ./../../device-dashboard/net.c $(NAME)
|
||||||
|
make -C $(NAME) build
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(NAME)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
include(pico-sdk/pico_sdk_init.cmake)
|
||||||
|
|
||||||
|
project(firmware)
|
||||||
|
pico_sdk_init()
|
||||||
|
|
||||||
|
add_executable(firmware
|
||||||
|
main.c
|
||||||
|
../../../mongoose.c
|
||||||
|
../../device-dashboard/net.c
|
||||||
|
../../device-dashboard/packed_fs.c)
|
||||||
|
target_include_directories(firmware PUBLIC ../../..)
|
||||||
|
target_link_libraries(firmware pico_stdlib hardware_spi)
|
||||||
|
pico_add_extra_outputs(firmware)
|
||||||
|
|
||||||
|
# Enable USB output. Comment out in order to use UART
|
||||||
|
pico_enable_stdio_usb(firmware 0)
|
||||||
|
pico_enable_stdio_uart(firmware 1)
|
||||||
|
|
||||||
|
# Mongoose build flags
|
||||||
|
add_definitions(-DMG_ENABLE_MIP=1)
|
||||||
|
add_definitions(-DMG_ENABLE_PACKED_FS=1)
|
||||||
|
add_definitions(-DMG_ENABLE_FILE=0)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
SDK_VERSION ?= 1.4.0
|
||||||
|
SDK_REPO ?= https://github.com/raspberrypi/pico-sdk
|
||||||
|
|
||||||
|
all example build build/firmware.uf2: pico-sdk main.c
|
||||||
|
test -d build || mkdir build
|
||||||
|
cd build && cmake .. && make
|
||||||
|
|
||||||
|
pico-sdk:
|
||||||
|
git clone --depth 1 -b $(SDK_VERSION) $(SDK_REPO) $@
|
||||||
|
cd $@ && git submodule update --init
|
||||||
|
|
||||||
|
# Requires env variable VCON_API_KEY set
|
||||||
|
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/3
|
||||||
|
test: update
|
||||||
|
curl --fail -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
|
||||||
|
grep 'Ethernet: up' /tmp/output.txt
|
||||||
|
grep 'MQTT connected' /tmp/output.txt
|
||||||
|
|
||||||
|
update: build/firmware.uf2
|
||||||
|
curl --fail -su :$(VCON_API_KEY) $(DEVICE_URL)/ota?uf2=1 --data-binary @$<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf pico-sdk build
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
# RP2040 with W5500 Ethernet module
|
||||||
|
|
||||||
|
This repository demonstrates how to use RP2040 with W5500 Ethernet module,
|
||||||
|
to implement networking. In this example, a very simple HTTP server is
|
||||||
|
implemented. See [other examples](../..) for more functionality.
|
||||||
|
|
||||||
|
## RP2040 Pico wiring
|
||||||
|
|
||||||
|
The W5500 module uses SPI for communication. The following pins are used
|
||||||
|
by this example (modify `main.c` if you use a different pinout):
|
||||||
|
|
||||||
|
```c
|
||||||
|
enum { LED = 25, SPI_CS = 17, SPI_CLK = 18, SPI_TX = 19, SPI_RX = 16 };
|
||||||
|
```
|
||||||
|
|
||||||
|
On a breadboard, it might look like this:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Pinout reference
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Build and run
|
||||||
|
|
||||||
|
Clone Mongoose repo, go to this example, and build it:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/cesanta/mongoose
|
||||||
|
cd mongoose/examples/ro2040/pico-w5500
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
The above will make a firmware in `build/example.uf2`. Reboot your Pico
|
||||||
|
board in bootloader mode, and copy `example.uf2` to the RPI disk.
|
||||||
|
|
||||||
|
Attach serial console. Then, plug in Ethernet cable:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cu -l /dev/cu.usb* -s 115200
|
||||||
|
4653 2 main.c:79:main Ethernet: down
|
||||||
|
520b 2 main.c:79:main Ethernet: down
|
||||||
|
5dc3 2 main.c:79:main Ethernet: down
|
||||||
|
6593 1 mongoose.c:6757:onstatechange Link up
|
||||||
|
659a 3 mongoose.c:6840:tx_dhcp_discover DHCP discover sent
|
||||||
|
667b 3 mongoose.c:6723:arp_cache_add ARP cache: added 192.168.0.1 @ 90:5c:44:55:19:8b
|
||||||
|
667d 2 mongoose.c:6749:onstatechange READY, IP: 192.168.0.24
|
||||||
|
667e 2 mongoose.c:6750:onstatechange GW: 192.168.0.1
|
||||||
|
6680 2 mongoose.c:6752:onstatechange Lease: 86062 sec
|
||||||
|
697b 2 main.c:79:main Ethernet: up
|
||||||
|
7533 2 main.c:79:main Ethernet: up
|
||||||
|
```
|
||||||
|
|
||||||
|
Note the aquired IP address printed. Run a browser, and type that IP address
|
||||||
|
in the address field. You should see an "ok" message in a browser:
|
||||||
|
|
||||||
|

|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 336 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 351 KiB |
@@ -0,0 +1,71 @@
|
|||||||
|
// Copyright (c) 2023 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "hardware/spi.h"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
enum { BLINK_PERIOD_MS = 1000 };
|
||||||
|
enum { LED = 25, SPI_CS = 17, SPI_CLK = 18, SPI_TX = 19, SPI_RX = 16 }; // Pins
|
||||||
|
|
||||||
|
static void spi_begin(void *spi) { gpio_put(SPI_CS, 0); }
|
||||||
|
static void spi_end(void *spi) { gpio_put(SPI_CS, 1); }
|
||||||
|
static uint8_t spi_txn(void *spi, uint8_t byte) {
|
||||||
|
uint8_t result = 0;
|
||||||
|
spi_write_read_blocking(spi0, &byte, &result, 1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timer_cb(void *arg) {
|
||||||
|
gpio_put(PICO_DEFAULT_LED_PIN, !gpio_get_out_level(PICO_DEFAULT_LED_PIN));
|
||||||
|
bool up = ((struct mip_if *) arg)->state == MIP_STATE_READY;
|
||||||
|
MG_INFO(("Ethernet: %s", up ? "up" : "down")); // Show network status
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
stdio_init_all();
|
||||||
|
MG_INFO(("Starting ..."));
|
||||||
|
|
||||||
|
// Init LED
|
||||||
|
gpio_init(LED);
|
||||||
|
gpio_set_dir(LED, GPIO_OUT);
|
||||||
|
|
||||||
|
// Init SPI pins
|
||||||
|
spi_init(spi0, 500 * 1000);
|
||||||
|
gpio_set_function(SPI_RX, GPIO_FUNC_SPI); // MISO
|
||||||
|
gpio_set_function(SPI_TX, GPIO_FUNC_SPI); // MOSI
|
||||||
|
gpio_set_function(SPI_CLK, GPIO_FUNC_SPI); // CLK
|
||||||
|
gpio_init(SPI_CS); // CS
|
||||||
|
gpio_set_dir(SPI_CS, GPIO_OUT); // Set CS it to output
|
||||||
|
gpio_put(SPI_CS, 1); // And drive CS high (inactive)
|
||||||
|
|
||||||
|
// Init Mongoose
|
||||||
|
struct mip_spi spi = {NULL, spi_begin, spi_end, spi_txn};
|
||||||
|
struct mip_if mif = {.mac = {2, 0, 1, 2, 3, 5},
|
||||||
|
.driver = &mip_driver_w5500,
|
||||||
|
.driver_data = &spi};
|
||||||
|
struct mg_mgr mgr; // Declare event manager
|
||||||
|
mg_mgr_init(&mgr); // Init event manager
|
||||||
|
mg_log_set(MG_LL_DEBUG); // Set DEBUG log level
|
||||||
|
mip_init(&mgr, &mif); // Init TCP/IP stack
|
||||||
|
mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_cb, &mif);
|
||||||
|
|
||||||
|
MG_INFO(("Waiting until network is up..."));
|
||||||
|
while (mif.state != MIP_STATE_READY) {
|
||||||
|
mg_mgr_poll(&mgr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_INFO(("Initialising application..."));
|
||||||
|
extern void device_dashboard_fn(struct mg_connection *, int, void *, void *);
|
||||||
|
mg_http_listen(&mgr, "http://0.0.0.0", device_dashboard_fn, &mgr);
|
||||||
|
|
||||||
|
MG_INFO(("Starting event loop"));
|
||||||
|
for (;;) {
|
||||||
|
mg_mgr_poll(&mgr, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
PROG ?= example
|
||||||
|
CFLAGS ?= -W -Wall -Wextra -O2 $(EXTRA_CFLAGS)
|
||||||
|
SSL ?= MBEDTLS
|
||||||
|
|
||||||
|
ifeq "$(SSL)" "MBEDTLS"
|
||||||
|
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -lmbedtls -lmbedcrypto -lmbedx509 -L$(MBEDTLS)/lib -I$(MBEDTLS)/include
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq "$(SSL)" "OPENSSL"
|
||||||
|
CFLAGS += -DMG_ENABLE_OPENSSL=1 -lssl -lcrypto -L$(OPENSSL)/lib -I$(OPENSSL)/include
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(PROG)
|
||||||
|
$(RUN) ./$(PROG) $(ARGS)
|
||||||
|
|
||||||
|
$(PROG): main.c
|
||||||
|
$(CC) ../../mongoose.c -I../.. $(CFLAGS) -o $(PROG) main.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PROG) _CL* *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb mbedtls
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# SMTP client example
|
||||||
|
|
||||||
|
This example shows how to send emails using Mongoose.
|
||||||
|
Before running this example, open main.c and modify settings at the top
|
||||||
|
of the file.
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../test/data/ca.pem
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static const char *server =
|
||||||
|
"tcp://mail.domain.com:587"; // Change this! Your mail server and port
|
||||||
|
static const char *user = "aaa@domain.com"; // Change this! Your mail account
|
||||||
|
static const char *pass = "xxxxxxxxxxxxxx"; // Change this! Your mail password
|
||||||
|
static const char *to = "bbb@domain.com"; // Change this! Destination email
|
||||||
|
|
||||||
|
static const char *from = "My Mail Sender";
|
||||||
|
static const char *subj = "Test email from Mongoose library!";
|
||||||
|
static const char *mesg = "Hi!\nThis is a test message.\nBye.";
|
||||||
|
|
||||||
|
static bool s_quit;
|
||||||
|
|
||||||
|
enum { EHLO, STARTTLS, STARTTLS_WAIT, AUTH, FROM, TO, DATA, BODY, QUIT, END };
|
||||||
|
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
uint8_t *state = (uint8_t *) c->data;
|
||||||
|
if (ev == MG_EV_OPEN) {
|
||||||
|
// c->is_hexdumping = 1;
|
||||||
|
} else if (ev == MG_EV_READ) {
|
||||||
|
if (c->recv.len > 0 && c->recv.buf[c->recv.len - 1] == '\n') {
|
||||||
|
MG_INFO(("<-- %.*s", (int) c->recv.len - 2, c->recv.buf));
|
||||||
|
c->recv.len = 0;
|
||||||
|
if (*state == EHLO) {
|
||||||
|
mg_printf(c, "EHLO myname\r\n");
|
||||||
|
*state = STARTTLS;
|
||||||
|
} else if (*state == STARTTLS) {
|
||||||
|
mg_printf(c, "STARTTLS\r\n");
|
||||||
|
*state = STARTTLS_WAIT;
|
||||||
|
} else if (*state == STARTTLS_WAIT) {
|
||||||
|
struct mg_tls_opts opts = {.ca = "ca.pem"};
|
||||||
|
mg_tls_init(c, &opts);
|
||||||
|
*state = AUTH;
|
||||||
|
} else if (*state == AUTH) {
|
||||||
|
char a[100], b[300] = "";
|
||||||
|
size_t n = mg_snprintf(a, sizeof(a), "%c%s%c%s", 0, user, 0, pass);
|
||||||
|
mg_base64_encode((uint8_t *) a, n, b);
|
||||||
|
mg_printf(c, "AUTH PLAIN %s\r\n", b);
|
||||||
|
*state = FROM;
|
||||||
|
} else if (*state == FROM) {
|
||||||
|
mg_printf(c, "MAIL FROM: <%s>\r\n", user);
|
||||||
|
*state = TO;
|
||||||
|
} else if (*state == TO) {
|
||||||
|
mg_printf(c, "RCPT TO: <%s>\r\n", to);
|
||||||
|
*state = DATA;
|
||||||
|
} else if (*state == DATA) {
|
||||||
|
mg_printf(c, "DATA\r\n");
|
||||||
|
*state = BODY;
|
||||||
|
} else if (*state == BODY) {
|
||||||
|
mg_printf(c, "From: %s <%s>\r\n", from, user); // Mail header
|
||||||
|
mg_printf(c, "Subject: %s\r\n", subj); // Mail header
|
||||||
|
mg_printf(c, "\r\n"); // End of headers
|
||||||
|
mg_printf(c, "%s\r\n", mesg); // Mail body
|
||||||
|
mg_printf(c, ".\r\n"); // End of body
|
||||||
|
*state = QUIT;
|
||||||
|
} else if (*state == QUIT) {
|
||||||
|
mg_printf(c, "QUIT\r\n");
|
||||||
|
*state = END;
|
||||||
|
} else {
|
||||||
|
c->is_draining = 1;
|
||||||
|
MG_INFO(("end"));
|
||||||
|
}
|
||||||
|
MG_INFO(("--> %.*s", (int) c->send.len - 2, c->send.buf));
|
||||||
|
}
|
||||||
|
} else if (ev == MG_EV_CLOSE) {
|
||||||
|
s_quit = true;
|
||||||
|
} else if (ev == MG_EV_TLS_HS) {
|
||||||
|
MG_INFO(("TLS handshake done! Sending EHLO again"));
|
||||||
|
mg_printf(c, "EHLO myname\r\n");
|
||||||
|
}
|
||||||
|
(void) fn_data, (void) ev_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_mgr mgr;
|
||||||
|
mg_mgr_init(&mgr);
|
||||||
|
// mg_log_set(MG_LL_VERBOSE);
|
||||||
|
mg_connect(&mgr, server, fn, NULL);
|
||||||
|
while (s_quit == false) mg_mgr_poll(&mgr, 1000);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -55,7 +55,7 @@ static void handshake(struct mg_connection *c) {
|
|||||||
}
|
}
|
||||||
mg_iobuf_del(r, 0, 2 + r->buf[1]);
|
mg_iobuf_del(r, 0, 2 + r->buf[1]);
|
||||||
mg_send(c, reply, sizeof(reply));
|
mg_send(c, reply, sizeof(reply));
|
||||||
c->label[0] = STATE_REQUEST;
|
c->data[0] = STATE_REQUEST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,15 +146,15 @@ static void request(struct mg_connection *c) {
|
|||||||
}
|
}
|
||||||
mg_send(c, r->buf + 3, addr_len + 1 + 2);
|
mg_send(c, r->buf + 3, addr_len + 1 + 2);
|
||||||
mg_iobuf_del(r, 0, 6 + addr_len); // Remove request from the input stream
|
mg_iobuf_del(r, 0, 6 + addr_len); // Remove request from the input stream
|
||||||
c->label[0] = STATE_ESTABLISHED; // Mark ourselves as connected
|
c->data[0] = STATE_ESTABLISHED; // Mark ourselves as connected
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
if (ev == MG_EV_READ) {
|
if (ev == MG_EV_READ) {
|
||||||
// We use the first label byte as a state
|
// We use the first label byte as a state
|
||||||
if (c->label[0] == STATE_HANDSHAKE) handshake(c);
|
if (c->data[0] == STATE_HANDSHAKE) handshake(c);
|
||||||
if (c->label[0] == STATE_REQUEST) request(c);
|
if (c->data[0] == STATE_REQUEST) request(c);
|
||||||
if (c->label[0] == STATE_ESTABLISHED) exchange(c);
|
if (c->data[0] == STATE_ESTABLISHED) exchange(c);
|
||||||
} else if (ev == MG_EV_CLOSE) {
|
} else if (ev == MG_EV_CLOSE) {
|
||||||
disband(c);
|
disband(c);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
CFLAGS ?= -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion \
|
||||||
|
-Wformat-truncation -fno-common -Wconversion \
|
||||||
|
-g3 -Os -ffunction-sections -fdata-sections -I. \
|
||||||
|
-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 $(EXTRA_CFLAGS)
|
||||||
|
LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
||||||
|
SOURCES = boot.c main.c syscalls.c
|
||||||
|
|
||||||
|
# Add Mongoose-specific flags and source files
|
||||||
|
CFLAGS += -I../../.. -DMG_ARCH=MG_ARCH_NEWLIB -DMG_ENABLE_CUSTOM_MILLIS=1 -DMG_ENABLE_MIP=1 -DMG_ENABLE_PACKED_FS=1
|
||||||
|
SOURCES += ../../../mongoose.c ../../device-dashboard/net.c ../../device-dashboard/packed_fs.c
|
||||||
|
|
||||||
|
all build example: firmware.bin
|
||||||
|
|
||||||
|
firmware.bin: firmware.elf
|
||||||
|
arm-none-eabi-objcopy -O binary $< $@
|
||||||
|
|
||||||
|
firmware.elf: $(SOURCES) mcu.h
|
||||||
|
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
# Note: on "unknown chip id" flash error, wire BOOT0 to VDD and st-flash erase
|
||||||
|
flash: firmware.bin
|
||||||
|
st-flash --reset write $< 0x8000000
|
||||||
|
|
||||||
|
# Requires env variable VCON_API_KEY set
|
||||||
|
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/2
|
||||||
|
test: update
|
||||||
|
curl --fail -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
|
||||||
|
grep 'Ethernet: up' /tmp/output.txt
|
||||||
|
grep 'MQTT connected' /tmp/output.txt
|
||||||
|
|
||||||
|
update: firmware.bin
|
||||||
|
curl --fail -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @$<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -rf firmware.* *.su
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# Baremetal webserver on NUCLEO-F429ZI
|
||||||
|
|
||||||
|
This firmware uses MIP, an experimental TCP/IP stack of the Mongoose Network Library,
|
||||||
|
which implements the following:
|
||||||
|
|
||||||
|
- A complete [HTTP device dashboard](../../device-dashboard) with:
|
||||||
|
- User authentication
|
||||||
|
- Real-time device data graph
|
||||||
|
- Coninfiguration display and update
|
||||||
|
- MQTT communication with a remote MQTT server
|
||||||
|
- No dependencies: no HAL, no CMSIS, no RTOS
|
||||||
|
- Hand-written [mcu.h](mcu.h) header based on a [datasheet](https://www.st.com/resource/en/reference_manual/rm0090-stm32f405415-stm32f407417-stm32f427437-and-stm32f429439-advanced-armbased-32bit-mcus-stmicroelectronics.pdf)
|
||||||
|
- Interrupt-driven [Ethernet driver](../../../drivers/mip_driver_stm32.c)
|
||||||
|
- Blue LED blinky, based on SysTick interrupt
|
||||||
|
- User button handler, turns off/on green LED, based on EXTI, interrupt-driven
|
||||||
|
- HardFault handler that blinks red LED
|
||||||
|
- Debug log on UART3 (st-link)
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- [GNU make](http://mongoose.ws/tutorials/tools/#gnu-make)
|
||||||
|
- [ARM GCC](http://mongoose.ws/tutorials/tools/#arm-gcc)
|
||||||
|
- [stlink](http://mongoose.ws/tutorials/tools/#stlink) for flashing
|
||||||
|
|
||||||
|
The links above will send you to tutorials on how to install each of those tools in your workstation for Linux, Mac, and Windows.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Plugin your Nucleo board into USB, and attach an Ethernet cable.
|
||||||
|
To build and flash:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ make clean flash
|
||||||
|
```
|
||||||
|
|
||||||
|
To see debug log, use any serial monitor program like `picocom` at 115200 bps and configure it to insert carriage returns after line feeds:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ picocom /dev/ttyACM0 -i -b 115200 --imap=lfcrlf
|
||||||
|
```
|
||||||
|
|
||||||
|
There is also a [detailed tutorial on this example](https://mongoose.ws/tutorials/stm32/nucleo-f746zg-baremetal/) but for the NUCLEO-F746ZG board
|
||||||
|
|
||||||
|
For more details and benchmark data on MIP, check the [F746ZG example](../nucleo-f746zg-baremetal/)
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
// Copyright (c) 2022 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
// Startup code
|
||||||
|
__attribute__((naked, noreturn)) void _reset(void) {
|
||||||
|
// Initialise memory
|
||||||
|
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++;
|
||||||
|
|
||||||
|
// Call main()
|
||||||
|
extern void main(void);
|
||||||
|
main();
|
||||||
|
for (;;) (void) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((weak)) DefaultIRQHandler(void) {
|
||||||
|
for (;;) (void) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WEAK_ALIAS __attribute__((weak, alias("DefaultIRQHandler")))
|
||||||
|
|
||||||
|
WEAK_ALIAS void NMI_Handler(void);
|
||||||
|
WEAK_ALIAS void HardFault_Handler(void);
|
||||||
|
WEAK_ALIAS void MemManage_Handler(void);
|
||||||
|
WEAK_ALIAS void BusFault_Handler(void);
|
||||||
|
WEAK_ALIAS void UsageFault_Handler(void);
|
||||||
|
WEAK_ALIAS void SVC_Handler(void);
|
||||||
|
WEAK_ALIAS void DebugMon_Handler(void);
|
||||||
|
WEAK_ALIAS void PendSV_Handler(void);
|
||||||
|
WEAK_ALIAS void SysTick_Handler(void);
|
||||||
|
|
||||||
|
WEAK_ALIAS void WWDG_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void PVD_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TAMP_STAMP_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void RTC_WKUP_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void FLASH_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void RCC_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void EXTI0_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void EXTI1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void EXTI2_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void EXTI3_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void EXTI4_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void EXTI9_5_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void EXTI15_10_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream0_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream2_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream3_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream4_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream5_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream6_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void ADC_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN1_TX_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN1_RX0_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN1_RX1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN1_SCE_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM1_BRK_TIM9_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM1_UP_TIM10_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM1_TRG_COM_TIM11_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM1_CC_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM2_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM3_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM4_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void I2C1_EV_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void I2C1_ER_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void I2C2_EV_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void I2C2_ER_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SPI1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SPI2_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void USART1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void USART2_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void USART3_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void RTC_Alarm_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void OTG_FS_WKUP_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM8_BRK_TIM12_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM8_UP_TIM13_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM8_TRG_COM_TIM14_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM8_CC_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream7_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void FMC_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SDMMC1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM5_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SPI3_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void UART4_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void UART5_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM6_DAC_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM7_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream0_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream2_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream3_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream4_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void ETH_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void ETH_WKUP_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN2_TX_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN2_RX0_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN2_RX1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN2_SCE_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void OTG_FS_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream5_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream6_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream7_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void USART6_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void I2C3_EV_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void I2C3_ER_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void OTG_HS_EP1_OUT_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void OTG_HS_EP1_IN_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void OTG_HS_WKUP_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void OTG_HS_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DCMI_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void RNG_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void FPU_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void UART7_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void UART8_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SPI4_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SPI5_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SPI6_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SAI1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void LTDC_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void LTDC_ER_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2D_IRQHandler(void);
|
||||||
|
|
||||||
|
// IRQ table
|
||||||
|
extern void _estack();
|
||||||
|
__attribute__((section(".vectors"))) void (*tab[16 + 91])(void) = {
|
||||||
|
// Cortex interrupts
|
||||||
|
_estack, _reset, NMI_Handler, HardFault_Handler, MemManage_Handler,
|
||||||
|
BusFault_Handler, UsageFault_Handler, 0, 0, 0, 0, SVC_Handler,
|
||||||
|
DebugMon_Handler, 0, PendSV_Handler, SysTick_Handler,
|
||||||
|
|
||||||
|
// Interrupts from peripherals
|
||||||
|
WWDG_IRQHandler, PVD_IRQHandler, TAMP_STAMP_IRQHandler, RTC_WKUP_IRQHandler,
|
||||||
|
FLASH_IRQHandler, RCC_IRQHandler, EXTI0_IRQHandler, EXTI1_IRQHandler,
|
||||||
|
EXTI2_IRQHandler, EXTI3_IRQHandler, EXTI4_IRQHandler,
|
||||||
|
DMA1_Stream0_IRQHandler, DMA1_Stream1_IRQHandler, DMA1_Stream2_IRQHandler,
|
||||||
|
DMA1_Stream3_IRQHandler, DMA1_Stream4_IRQHandler, DMA1_Stream5_IRQHandler,
|
||||||
|
DMA1_Stream6_IRQHandler, ADC_IRQHandler, CAN1_TX_IRQHandler,
|
||||||
|
CAN1_RX0_IRQHandler, CAN1_RX1_IRQHandler, CAN1_SCE_IRQHandler,
|
||||||
|
EXTI9_5_IRQHandler, TIM1_BRK_TIM9_IRQHandler, TIM1_UP_TIM10_IRQHandler,
|
||||||
|
TIM1_TRG_COM_TIM11_IRQHandler, TIM1_CC_IRQHandler, TIM2_IRQHandler,
|
||||||
|
TIM3_IRQHandler, TIM4_IRQHandler, I2C1_EV_IRQHandler, I2C1_ER_IRQHandler,
|
||||||
|
I2C2_EV_IRQHandler, I2C2_ER_IRQHandler, SPI1_IRQHandler, SPI2_IRQHandler,
|
||||||
|
USART1_IRQHandler, USART2_IRQHandler, USART3_IRQHandler,
|
||||||
|
EXTI15_10_IRQHandler, RTC_Alarm_IRQHandler, OTG_FS_WKUP_IRQHandler,
|
||||||
|
TIM8_BRK_TIM12_IRQHandler, TIM8_UP_TIM13_IRQHandler,
|
||||||
|
TIM8_TRG_COM_TIM14_IRQHandler, TIM8_CC_IRQHandler, DMA1_Stream7_IRQHandler,
|
||||||
|
FMC_IRQHandler, SDMMC1_IRQHandler, TIM5_IRQHandler, SPI3_IRQHandler,
|
||||||
|
UART4_IRQHandler, UART5_IRQHandler, TIM6_DAC_IRQHandler, TIM7_IRQHandler,
|
||||||
|
DMA2_Stream0_IRQHandler, DMA2_Stream1_IRQHandler, DMA2_Stream2_IRQHandler,
|
||||||
|
DMA2_Stream3_IRQHandler, DMA2_Stream4_IRQHandler, ETH_IRQHandler,
|
||||||
|
ETH_WKUP_IRQHandler, CAN2_TX_IRQHandler, CAN2_RX0_IRQHandler,
|
||||||
|
CAN2_RX1_IRQHandler, CAN2_SCE_IRQHandler, OTG_FS_IRQHandler,
|
||||||
|
DMA2_Stream5_IRQHandler, DMA2_Stream6_IRQHandler, DMA2_Stream7_IRQHandler,
|
||||||
|
USART6_IRQHandler, I2C3_EV_IRQHandler, I2C3_ER_IRQHandler,
|
||||||
|
OTG_HS_EP1_OUT_IRQHandler, OTG_HS_EP1_IN_IRQHandler, OTG_HS_WKUP_IRQHandler,
|
||||||
|
OTG_HS_IRQHandler, DCMI_IRQHandler, 0, RNG_IRQHandler, FPU_IRQHandler,
|
||||||
|
UART7_IRQHandler, UART8_IRQHandler, SPI4_IRQHandler, SPI5_IRQHandler,
|
||||||
|
SPI6_IRQHandler, SAI1_IRQHandler, LTDC_IRQHandler, LTDC_ER_IRQHandler,
|
||||||
|
DMA2D_IRQHandler};
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
ENTRY(_reset);
|
||||||
|
MEMORY {
|
||||||
|
flash(rx) : ORIGIN = 0x08000000, LENGTH = 2048k
|
||||||
|
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 192k /* remaining 64k in a separate address space */
|
||||||
|
}
|
||||||
|
_estack = ORIGIN(sram) + LENGTH(sram); /* stack points to end of SRAM */
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
.vectors : { KEEP(*(.vectors)) } > flash
|
||||||
|
.text : { *(.text*) } > flash
|
||||||
|
.rodata : { *(.rodata*) } > flash
|
||||||
|
|
||||||
|
.data : {
|
||||||
|
_sdata = .; /* for init_ram() */
|
||||||
|
*(.first_data)
|
||||||
|
*(.data SORT(.data.*))
|
||||||
|
_edata = .; /* for init_ram() */
|
||||||
|
} > sram AT > flash
|
||||||
|
_sidata = LOADADDR(.data);
|
||||||
|
|
||||||
|
.bss : {
|
||||||
|
_sbss = .; /* for init_ram() */
|
||||||
|
*(.bss SORT(.bss.*) COMMON)
|
||||||
|
_ebss = .; /* for init_ram() */
|
||||||
|
} > sram
|
||||||
|
|
||||||
|
. = ALIGN(8);
|
||||||
|
_end = .; /* for cmsis_gcc.h and init_ram() */
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
// Copyright (c) 2022 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include "mcu.h"
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
#define LED1 PIN('B', 0) // On-board LED pin (green)
|
||||||
|
#define LED2 PIN('B', 7) // On-board LED pin (blue)
|
||||||
|
#define LED3 PIN('B', 14) // On-board LED pin (red)
|
||||||
|
#define BTN1 PIN('C', 13) // On-board user button
|
||||||
|
#define BLINK_PERIOD_MS 1000 // LED blinking period in millis
|
||||||
|
|
||||||
|
static uint64_t s_ticks, s_exti; // Counters, increased by IRQ handlers
|
||||||
|
|
||||||
|
uint64_t mg_millis(void) { // Declare our own uptime function
|
||||||
|
return s_ticks; // Return number of milliseconds since boot
|
||||||
|
}
|
||||||
|
|
||||||
|
void HardFault_Handler(void) { // Escalated fault handler
|
||||||
|
gpio_output(LED3); // Setup red LED
|
||||||
|
for (;;) spin(2999999), gpio_toggle(LED3); // Blink LED infinitely
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
|
||||||
|
s_ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EXTI15_10_IRQHandler(void) { // External interrupt handler
|
||||||
|
s_exti++;
|
||||||
|
if (EXTI->PR & BIT(PINNO(BTN1))) EXTI->PR = BIT(PINNO(BTN1));
|
||||||
|
gpio_write(LED1, gpio_read(BTN1)); // No debounce. Turn LED if button pressed
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timer_cb(void *arg) {
|
||||||
|
gpio_toggle(LED2); // Blink LED
|
||||||
|
bool up = ((struct mip_if *) arg)->state == MIP_STATE_READY;
|
||||||
|
MG_INFO(("Ethernet: %s", up ? "up" : "down")); // Show network status
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
clock_init(); // Set clock to 180MHz
|
||||||
|
systick_init(SYS_FREQUENCY / 1000); // Increment s_ticks every ms
|
||||||
|
gpio_output(LED1); // Setup green LED
|
||||||
|
gpio_output(LED2); // Setup blue LED
|
||||||
|
gpio_input(BTN1); // Set button to input
|
||||||
|
irq_exti_attach(BTN1); // Attach BTN1 to exti
|
||||||
|
uart_init(UART1, 115200); // Initialise debug printf
|
||||||
|
|
||||||
|
MG_INFO(("Starting, CPU freq %g MHz", (double) SYS_FREQUENCY / 1000000));
|
||||||
|
|
||||||
|
// Initialise Ethernet. Enable MAC GPIO pins, see
|
||||||
|
// https://www.farnell.com/datasheets/2014265.pdf section 6.10
|
||||||
|
uint16_t pins[] = {PIN('A', 1), PIN('A', 2), PIN('A', 7),
|
||||||
|
PIN('B', 13), PIN('C', 1), PIN('C', 4),
|
||||||
|
PIN('C', 5), PIN('G', 11), PIN('G', 13)};
|
||||||
|
for (size_t i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) {
|
||||||
|
gpio_init(pins[i], GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_INSANE,
|
||||||
|
GPIO_PULL_NONE, 11);
|
||||||
|
}
|
||||||
|
nvic_enable_irq(61); // Setup Ethernet IRQ handler
|
||||||
|
RCC->APB2ENR |= BIT(14); // Enable SYSCFG
|
||||||
|
SYSCFG->PMC |= BIT(23); // Use RMII. Goes first!
|
||||||
|
RCC->AHB1ENR |= BIT(25) | BIT(26) | BIT(27); // Enable Ethernet clocks
|
||||||
|
RCC->AHB1RSTR |= BIT(25); // ETHMAC force reset
|
||||||
|
RCC->AHB1RSTR &= ~BIT(25); // ETHMAC release reset
|
||||||
|
|
||||||
|
struct mg_mgr mgr; // Initialise Mongoose event manager
|
||||||
|
mg_mgr_init(&mgr); // and attach it to the MIP interface
|
||||||
|
mg_log_set(MG_LL_DEBUG); // Set log level
|
||||||
|
|
||||||
|
// Initialise Mongoose network stack
|
||||||
|
// Specify MAC address, and IP/mask/GW in network byte order for static
|
||||||
|
// IP configuration. If IP/mask/GW are unset, DHCP is going to be used
|
||||||
|
struct mip_driver_stm32_data driver_data = {.mdc_cr = 4}; // driver_stm32.h
|
||||||
|
struct mip_if mif = {.mac = {2, 0, 1, 2, 3, 5},
|
||||||
|
.driver = &mip_driver_stm32,
|
||||||
|
.driver_data = &driver_data};
|
||||||
|
mip_init(&mgr, &mif);
|
||||||
|
mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_cb, &mif);
|
||||||
|
|
||||||
|
MG_INFO(("Waiting until network is up..."));
|
||||||
|
while (mif.state != MIP_STATE_READY) {
|
||||||
|
mg_mgr_poll(&mgr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_INFO(("Initialising application..."));
|
||||||
|
extern void device_dashboard_fn(struct mg_connection *, int, void *, void *);
|
||||||
|
mg_http_listen(&mgr, "http://0.0.0.0", device_dashboard_fn, &mgr);
|
||||||
|
|
||||||
|
MG_INFO(("Starting event loop"));
|
||||||
|
for (;;) {
|
||||||
|
mg_mgr_poll(&mgr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
// Copyright (c) 2022 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
// https://www.st.com/resource/en/reference_manual/dm00031020-stm32f405-415-stm32f407-417-stm32f427-437-and-stm32f429-439-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#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) - 'A') << 8) | (num))
|
||||||
|
#define PINNO(pin) (pin & 255)
|
||||||
|
#define PINBANK(pin) (pin >> 8)
|
||||||
|
|
||||||
|
// 6.3.3: APB1 clock <= 45MHz; APB2 clock <= 90MHz
|
||||||
|
// 3.5.1, Table 11: configure flash latency (WS) in accordance to clock freq
|
||||||
|
// 33.4: The AHB clock must be at least 25 MHz when Ethernet is used
|
||||||
|
enum { APB1_PRE = 5 /* AHB clock / 4 */, APB2_PRE = 4 /* AHB clock / 2 */ };
|
||||||
|
enum { PLL_HSI = 16, PLL_M = 8, PLL_N = 180, PLL_P = 2 }; // Run at 180 Mhz
|
||||||
|
#define FLASH_LATENCY 5
|
||||||
|
#define SYS_FREQUENCY ((PLL_HSI * PLL_N / PLL_M / PLL_P) * 1000000)
|
||||||
|
#define APB2_FREQUENCY (SYS_FREQUENCY / (BIT(APB2_PRE - 3)))
|
||||||
|
#define APB1_FREQUENCY (SYS_FREQUENCY / (BIT(APB1_PRE - 3)))
|
||||||
|
|
||||||
|
static inline void spin(volatile uint32_t count) {
|
||||||
|
while (count--) asm("nop");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rcc {
|
||||||
|
volatile uint32_t CR, PLLCFGR, CFGR, CIR, AHB1RSTR, AHB2RSTR, AHB3RSTR,
|
||||||
|
RESERVED0, APB1RSTR, APB2RSTR, RESERVED1[2], AHB1ENR, AHB2ENR, AHB3ENR,
|
||||||
|
RESERVED2, APB1ENR, APB2ENR, RESERVED3[2], AHB1LPENR, AHB2LPENR,
|
||||||
|
AHB3LPENR, RESERVED4, APB1LPENR, APB2LPENR, RESERVED5[2], BDCR, CSR,
|
||||||
|
RESERVED6[2], SSCGR, PLLI2SCFGR;
|
||||||
|
};
|
||||||
|
#define RCC ((struct rcc *) 0x40023800)
|
||||||
|
|
||||||
|
struct pwr {
|
||||||
|
volatile uint32_t CR, CSR;
|
||||||
|
};
|
||||||
|
#define PWR ((struct pwr *) 0x40007000)
|
||||||
|
|
||||||
|
struct nvic {
|
||||||
|
volatile uint32_t ISER[8], RESERVED0[24], ICER[8], RSERVED1[24], ISPR[8],
|
||||||
|
RESERVED2[24], ICPR[8], RESERVED3[24], IABR[8], RESERVED4[56], IP[240],
|
||||||
|
RESERVED5[644], STIR;
|
||||||
|
};
|
||||||
|
#define NVIC ((struct nvic *) 0xe000e100)
|
||||||
|
static inline void nvic_set_prio(int irq, uint32_t prio) {
|
||||||
|
NVIC->IP[irq] = prio << 4;
|
||||||
|
}
|
||||||
|
static inline void nvic_enable_irq(int irq) {
|
||||||
|
NVIC->ISER[irq >> 5] = (uint32_t) (1 << (irq & 31));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct systick {
|
||||||
|
volatile uint32_t CTRL, LOAD, VAL, CALIB;
|
||||||
|
};
|
||||||
|
#define SYSTICK ((struct systick *) 0xe000e010) // 2.2.2
|
||||||
|
static inline void systick_init(uint32_t ticks) {
|
||||||
|
if ((ticks - 1) > 0xffffff) return; // Systick timer is 24 bit
|
||||||
|
SYSTICK->LOAD = ticks - 1;
|
||||||
|
SYSTICK->VAL = 0;
|
||||||
|
SYSTICK->CTRL = BIT(0) | BIT(1) | BIT(2); // Enable systick
|
||||||
|
}
|
||||||
|
|
||||||
|
struct flash {
|
||||||
|
volatile uint32_t ACR, KEYR, OPTKEYR, SR, CR, AR, RESERVED, OBR, WRPR;
|
||||||
|
};
|
||||||
|
#define FLASH ((struct flash *) 0x40023c00)
|
||||||
|
|
||||||
|
struct scb {
|
||||||
|
volatile uint32_t CPUID, ICSR, VTOR, AIRCR, SCR, CCR, SHPR[3], SHCSR, CFSR,
|
||||||
|
HFSR, DFSR, MMFAR, BFAR, AFSR, ID_PFR[2], ID_DFR, ID_AFR, ID_MFR[4],
|
||||||
|
ID_ISAR[5], RESERVED0[1], CLIDR, CTR, CCSIDR, CSSELR, CPACR,
|
||||||
|
RESERVED3[93], STIR, RESERVED4[15], MVFR0, MVFR1, MVFR2, RESERVED5[1],
|
||||||
|
ICIALLU, RESERVED6[1], ICIMVAU, DCIMVAC, DCISW, DCCMVAU, DCCMVAC, DCCSW,
|
||||||
|
DCCIMVAC, DCCISW, RESERVED7[6], ITCMCR, DTCMCR, AHBPCR, CACR, AHBSCR,
|
||||||
|
RESERVED8[1], ABFSR;
|
||||||
|
};
|
||||||
|
#define SCB ((struct scb *) 0xe000ed00)
|
||||||
|
|
||||||
|
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG };
|
||||||
|
enum { GPIO_OTYPE_PUSH_PULL, GPIO_OTYPE_OPEN_DRAIN };
|
||||||
|
enum { GPIO_SPEED_LOW, GPIO_SPEED_MEDIUM, GPIO_SPEED_HIGH, GPIO_SPEED_INSANE };
|
||||||
|
enum { GPIO_PULL_NONE, GPIO_PULL_UP, GPIO_PULL_DOWN };
|
||||||
|
|
||||||
|
struct gpio {
|
||||||
|
volatile uint32_t MODER, OTYPER, OSPEEDR, PUPDR, IDR, ODR, BSRR, LCKR, AFR[2];
|
||||||
|
};
|
||||||
|
#define GPIO(N) ((struct gpio *) (0x40020000 + 0x400 * (N)))
|
||||||
|
|
||||||
|
static struct gpio *gpio_bank(uint16_t pin) { return GPIO(PINBANK(pin)); }
|
||||||
|
static inline void gpio_toggle(uint16_t pin) {
|
||||||
|
struct gpio *gpio = gpio_bank(pin);
|
||||||
|
uint32_t mask = BIT(PINNO(pin));
|
||||||
|
gpio->BSRR = mask << (gpio->ODR & mask ? 16 : 0);
|
||||||
|
}
|
||||||
|
static inline int gpio_read(uint16_t pin) {
|
||||||
|
return gpio_bank(pin)->IDR & BIT(PINNO(pin)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
static inline void gpio_write(uint16_t pin, bool val) {
|
||||||
|
struct gpio *gpio = gpio_bank(pin);
|
||||||
|
gpio->BSRR = BIT(PINNO(pin)) << (val ? 0 : 16);
|
||||||
|
}
|
||||||
|
static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
|
||||||
|
uint8_t speed, uint8_t pull, uint8_t af) {
|
||||||
|
struct gpio *gpio = gpio_bank(pin);
|
||||||
|
uint8_t n = (uint8_t) (PINNO(pin));
|
||||||
|
RCC->AHB1ENR |= BIT(PINBANK(pin)); // Enable GPIO clock
|
||||||
|
SETBITS(gpio->OTYPER, 1UL << n, ((uint32_t) type) << n);
|
||||||
|
SETBITS(gpio->OSPEEDR, 3UL << (n * 2), ((uint32_t) speed) << (n * 2));
|
||||||
|
SETBITS(gpio->PUPDR, 3UL << (n * 2), ((uint32_t) pull) << (n * 2));
|
||||||
|
SETBITS(gpio->AFR[n >> 3], 15UL << ((n & 7) * 4),
|
||||||
|
((uint32_t) af) << ((n & 7) * 4));
|
||||||
|
SETBITS(gpio->MODER, 3UL << (n * 2), ((uint32_t) mode) << (n * 2));
|
||||||
|
}
|
||||||
|
static inline void gpio_input(uint16_t pin) {
|
||||||
|
gpio_init(pin, GPIO_MODE_INPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH,
|
||||||
|
GPIO_PULL_NONE, 0);
|
||||||
|
}
|
||||||
|
static inline void gpio_output(uint16_t pin) {
|
||||||
|
gpio_init(pin, GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH,
|
||||||
|
GPIO_PULL_NONE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct syscfg {
|
||||||
|
volatile uint32_t MEMRMP, PMC, EXTICR[4], RESERVED[2], CMPCR;
|
||||||
|
};
|
||||||
|
#define SYSCFG ((struct syscfg *) 0x40013800)
|
||||||
|
|
||||||
|
struct exti {
|
||||||
|
volatile uint32_t IMR, EMR, RTSR, FTSR, SWIER, PR;
|
||||||
|
};
|
||||||
|
#define EXTI ((struct exti *) 0x40013c00)
|
||||||
|
|
||||||
|
static inline void irq_exti_attach(uint16_t pin) {
|
||||||
|
uint8_t bank = (uint8_t) (PINBANK(pin)), n = (uint8_t) (PINNO(pin));
|
||||||
|
RCC->APB2ENR |= BIT(14); // Enable SYSCFG
|
||||||
|
SYSCFG->EXTICR[n / 4] &= ~(15UL << ((n % 4) * 4));
|
||||||
|
SYSCFG->EXTICR[n / 4] |= (uint32_t) (bank << ((n % 4) * 4));
|
||||||
|
EXTI->IMR |= BIT(n);
|
||||||
|
EXTI->RTSR |= BIT(n);
|
||||||
|
EXTI->FTSR |= BIT(n);
|
||||||
|
int irqvec = n < 5 ? 6 + n : n < 10 ? 23 : 40; // IRQ vector index, 10.1.2
|
||||||
|
nvic_set_prio(irqvec, 3);
|
||||||
|
nvic_enable_irq(irqvec);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct uart {
|
||||||
|
volatile uint32_t SR, DR, BRR, CR1, CR2, CR3, GTPR;
|
||||||
|
};
|
||||||
|
#define UART1 ((struct uart *) 0x40011000)
|
||||||
|
#define UART2 ((struct uart *) 0x40004400)
|
||||||
|
#define UART3 ((struct uart *) 0x40004800)
|
||||||
|
|
||||||
|
static inline void uart_init(struct uart *uart, unsigned long baud) {
|
||||||
|
// https://www.st.com/resource/en/datasheet/stm32f429zi.pdf
|
||||||
|
uint8_t af = 7; // Alternate function
|
||||||
|
uint16_t rx = 0, tx = 0; // pins
|
||||||
|
uint32_t freq = 0; // Bus frequency. UART1 is on APB2, rest on APB1
|
||||||
|
|
||||||
|
if (uart == UART1) freq = APB2_FREQUENCY, RCC->APB2ENR |= BIT(4);
|
||||||
|
if (uart == UART2) freq = APB1_FREQUENCY, RCC->APB1ENR |= BIT(17);
|
||||||
|
if (uart == UART3) freq = APB1_FREQUENCY, RCC->APB1ENR |= BIT(18);
|
||||||
|
|
||||||
|
if (uart == UART1) tx = PIN('A', 9), rx = PIN('A', 10);
|
||||||
|
if (uart == UART2) tx = PIN('A', 2), rx = PIN('A', 3);
|
||||||
|
if (uart == UART3) tx = PIN('D', 8), rx = PIN('D', 9);
|
||||||
|
|
||||||
|
gpio_init(tx, GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, 0, af);
|
||||||
|
gpio_init(rx, GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, 0, af);
|
||||||
|
uart->CR1 = 0; // Disable this UART
|
||||||
|
uart->BRR = freq / baud; // Set baud rate
|
||||||
|
uart->CR1 |= BIT(13) | BIT(2) | BIT(3); // Set UE, RE, TE
|
||||||
|
}
|
||||||
|
static inline void uart_write_byte(struct uart *uart, uint8_t byte) {
|
||||||
|
uart->DR = byte;
|
||||||
|
while ((uart->SR & BIT(7)) == 0) spin(1);
|
||||||
|
}
|
||||||
|
static inline void uart_write_buf(struct uart *uart, char *buf, size_t len) {
|
||||||
|
while (len-- > 0) uart_write_byte(uart, *(uint8_t *) buf++);
|
||||||
|
}
|
||||||
|
static inline int uart_read_ready(struct uart *uart) {
|
||||||
|
return uart->SR & BIT(5); // If RXNE bit is set, data is ready
|
||||||
|
}
|
||||||
|
static inline uint8_t uart_read_byte(struct uart *uart) {
|
||||||
|
return (uint8_t) (uart->DR & 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void clock_init(void) { // Set clock frequency
|
||||||
|
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU
|
||||||
|
asm("DSB");
|
||||||
|
asm("ISB");
|
||||||
|
FLASH->ACR |= FLASH_LATENCY | BIT(8) |
|
||||||
|
BIT(9); // Flash latency, prefetch, Icache, Dcache
|
||||||
|
RCC->PLLCFGR &= ~((BIT(17) - 1)); // Clear PLL multipliers
|
||||||
|
RCC->PLLCFGR |= (((PLL_P - 2) / 2) & 3) << 16; // Set PLL_P
|
||||||
|
RCC->PLLCFGR |= PLL_M | (PLL_N << 6); // Set PLL_M and PLL_N
|
||||||
|
RCC->CR |= BIT(24); // Enable PLL
|
||||||
|
while ((RCC->CR & BIT(25)) == 0) spin(1); // Wait until done
|
||||||
|
RCC->CFGR = (APB1_PRE << 10) | (APB2_PRE << 13); // Set prescalers
|
||||||
|
RCC->CFGR |= 2; // Set clock source to PLL
|
||||||
|
while ((RCC->CFGR & 12) == 0) spin(1); // Wait until done
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "mcu.h"
|
||||||
|
|
||||||
|
int _fstat(int fd, struct stat *st) {
|
||||||
|
if (fd < 0) return -1;
|
||||||
|
st->st_mode = S_IFCHR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *_sbrk(int incr) {
|
||||||
|
extern char _end;
|
||||||
|
static unsigned char *heap = NULL;
|
||||||
|
unsigned char *prev_heap;
|
||||||
|
if (heap == NULL) heap = (unsigned char *) &_end;
|
||||||
|
prev_heap = heap;
|
||||||
|
heap += 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(UART1, 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "mcu.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 * 98)
|
||||||
|
#define INCLUDE_vTaskDelay 1
|
||||||
|
|
||||||
|
#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
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
CFLAGS ?= -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion \
|
||||||
|
-Wformat-truncation -fno-common -Wconversion \
|
||||||
|
-g3 -Os -ffunction-sections -fdata-sections \
|
||||||
|
-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
|
||||||
|
-I. -Icmsis -I../../../ $(EXTRA_CFLAGS)
|
||||||
|
LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
||||||
|
SOURCES = main.c startup.c syscalls.c ../../../mongoose.c
|
||||||
|
|
||||||
|
FREERTOS_VERSION ?= V10.5.0
|
||||||
|
FREERTOS_REPO ?= https://github.com/FreeRTOS/FreeRTOS-Kernel
|
||||||
|
|
||||||
|
build example: firmware.bin
|
||||||
|
|
||||||
|
firmware.elf: FreeRTOS-Kernel $(SOURCES)
|
||||||
|
arm-none-eabi-gcc -o $@ $(SOURCES) $(CFLAGS) \
|
||||||
|
-IFreeRTOS-Kernel/include \
|
||||||
|
-IFreeRTOS-Kernel/portable/GCC/ARM_CM4F \
|
||||||
|
-Wno-conversion \
|
||||||
|
$(wildcard FreeRTOS-Kernel/*.c) \
|
||||||
|
FreeRTOS-Kernel/portable/MemMang/heap_4.c \
|
||||||
|
FreeRTOS-Kernel/portable/GCC/ARM_CM4F/port.c \
|
||||||
|
$(LDFLAGS)
|
||||||
|
|
||||||
|
firmware.bin: firmware.elf
|
||||||
|
arm-none-eabi-objcopy -O binary $< $@
|
||||||
|
|
||||||
|
flash: firmware.bin
|
||||||
|
st-flash --reset write firmware.bin 0x8000000
|
||||||
|
|
||||||
|
FreeRTOS-Kernel:
|
||||||
|
git clone --depth 1 -b $(FREERTOS_VERSION) $(FREERTOS_REPO) $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf firmware.* FreeRTOS-Kernel
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# MIP webserver over FreeRTOS on NUCLEO-F429ZI
|
||||||
|
|
||||||
|
This firmware uses MIP, an experimental TCP/IP stack of the Mongoose Network Library, running as a FreeRTOS task.
|
||||||
|
It implements the following:
|
||||||
|
|
||||||
|
- Minimal elementary web server, as simple as possible
|
||||||
|
- Interrupt-driven [Ethernet driver](../../../drivers/mip_driver_stm32.c)
|
||||||
|
- Basic HAL header [mcu.h](mcu.h) based on CMSIS
|
||||||
|
- Blue LED blinky, based on another FreeRTOS task
|
||||||
|
- Debug log on UART3 (st-link)
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- [GNU make](http://mongoose.ws/tutorials/tools/#gnu-make)
|
||||||
|
- [ARM GCC](http://mongoose.ws/tutorials/tools/#arm-gcc)
|
||||||
|
- [stlink](http://mongoose.ws/tutorials/tools/#stlink) for flashing
|
||||||
|
|
||||||
|
The links above will send you to tutorials on how to install each of those tools in your workstation for Linux, Mac, and Windows.
|
||||||
|
|
||||||
|
You'll also need _git_ so the Makefile can clone the FreeRTOS-Kernel repository. We assume you have it since you got to get this repository somehow. If you don't, and don't want to install it, just get the proper [FreeRTOS-Kernel](https://github.com/FreeRTOS/FreeRTOS-Kernel) version (see the Makefile) from its repository, as you did with the Mongoose repository.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Plugin your Nucleo board into USB, and attach an Ethernet cable.
|
||||||
|
To build and flash:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ make clean flash
|
||||||
|
```
|
||||||
|
|
||||||
|
To see debug log, use any serial monitor program like `picocom` at 115200 bps and configure it to insert carriage returns after line feeds:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ picocom /dev/ttyACM0 -i -b 115200 --imap=lfcrlf
|
||||||
|
```
|
||||||
|
|
||||||
|
There is also a [detailed tutorial on this example](http://mongoose.ws/tutorials/stm32/nucleo-f429zi-freertos-mip/)
|
||||||
|
|
||||||
|
For more details and benchmark data on MIP, check the [F746ZG example](../nucleo-f746zg-baremetal/)
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
/**************************************************************************//**
|
||||||
|
* @file cmsis_compiler.h
|
||||||
|
* @brief CMSIS compiler generic header file
|
||||||
|
* @version V5.0.4
|
||||||
|
* @date 10. January 2018
|
||||||
|
******************************************************************************/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2018 Arm Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CMSIS_COMPILER_H
|
||||||
|
#define __CMSIS_COMPILER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arm Compiler 4/5
|
||||||
|
*/
|
||||||
|
#if defined ( __CC_ARM )
|
||||||
|
#include "cmsis_armcc.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arm Compiler 6 (armclang)
|
||||||
|
*/
|
||||||
|
#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
|
||||||
|
#include "cmsis_armclang.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GNU Compiler
|
||||||
|
*/
|
||||||
|
#elif defined ( __GNUC__ )
|
||||||
|
#include "cmsis_gcc.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IAR Compiler
|
||||||
|
*/
|
||||||
|
#elif defined ( __ICCARM__ )
|
||||||
|
#include <cmsis_iccarm.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TI Arm Compiler
|
||||||
|
*/
|
||||||
|
#elif defined ( __TI_ARM__ )
|
||||||
|
#include <cmsis_ccs.h>
|
||||||
|
|
||||||
|
#ifndef __ASM
|
||||||
|
#define __ASM __asm
|
||||||
|
#endif
|
||||||
|
#ifndef __INLINE
|
||||||
|
#define __INLINE inline
|
||||||
|
#endif
|
||||||
|
#ifndef __STATIC_INLINE
|
||||||
|
#define __STATIC_INLINE static inline
|
||||||
|
#endif
|
||||||
|
#ifndef __STATIC_FORCEINLINE
|
||||||
|
#define __STATIC_FORCEINLINE __STATIC_INLINE
|
||||||
|
#endif
|
||||||
|
#ifndef __NO_RETURN
|
||||||
|
#define __NO_RETURN __attribute__((noreturn))
|
||||||
|
#endif
|
||||||
|
#ifndef __USED
|
||||||
|
#define __USED __attribute__((used))
|
||||||
|
#endif
|
||||||
|
#ifndef __WEAK
|
||||||
|
#define __WEAK __attribute__((weak))
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED
|
||||||
|
#define __PACKED __attribute__((packed))
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED_STRUCT
|
||||||
|
#define __PACKED_STRUCT struct __attribute__((packed))
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED_UNION
|
||||||
|
#define __PACKED_UNION union __attribute__((packed))
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32 /* deprecated */
|
||||||
|
struct __attribute__((packed)) T_UINT32 { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT16_WRITE
|
||||||
|
__PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };
|
||||||
|
#define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void*)(addr))->v) = (val))
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT16_READ
|
||||||
|
__PACKED_STRUCT T_UINT16_READ { uint16_t v; };
|
||||||
|
#define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32_WRITE
|
||||||
|
__PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32_READ
|
||||||
|
__PACKED_STRUCT T_UINT32_READ { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __ALIGNED
|
||||||
|
#define __ALIGNED(x) __attribute__((aligned(x)))
|
||||||
|
#endif
|
||||||
|
#ifndef __RESTRICT
|
||||||
|
#warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored.
|
||||||
|
#define __RESTRICT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TASKING Compiler
|
||||||
|
*/
|
||||||
|
#elif defined ( __TASKING__ )
|
||||||
|
/*
|
||||||
|
* The CMSIS functions have been implemented as intrinsics in the compiler.
|
||||||
|
* Please use "carm -?i" to get an up to date list of all intrinsics,
|
||||||
|
* Including the CMSIS ones.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASM
|
||||||
|
#define __ASM __asm
|
||||||
|
#endif
|
||||||
|
#ifndef __INLINE
|
||||||
|
#define __INLINE inline
|
||||||
|
#endif
|
||||||
|
#ifndef __STATIC_INLINE
|
||||||
|
#define __STATIC_INLINE static inline
|
||||||
|
#endif
|
||||||
|
#ifndef __STATIC_FORCEINLINE
|
||||||
|
#define __STATIC_FORCEINLINE __STATIC_INLINE
|
||||||
|
#endif
|
||||||
|
#ifndef __NO_RETURN
|
||||||
|
#define __NO_RETURN __attribute__((noreturn))
|
||||||
|
#endif
|
||||||
|
#ifndef __USED
|
||||||
|
#define __USED __attribute__((used))
|
||||||
|
#endif
|
||||||
|
#ifndef __WEAK
|
||||||
|
#define __WEAK __attribute__((weak))
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED
|
||||||
|
#define __PACKED __packed__
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED_STRUCT
|
||||||
|
#define __PACKED_STRUCT struct __packed__
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED_UNION
|
||||||
|
#define __PACKED_UNION union __packed__
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32 /* deprecated */
|
||||||
|
struct __packed__ T_UINT32 { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT16_WRITE
|
||||||
|
__PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };
|
||||||
|
#define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT16_READ
|
||||||
|
__PACKED_STRUCT T_UINT16_READ { uint16_t v; };
|
||||||
|
#define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32_WRITE
|
||||||
|
__PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32_READ
|
||||||
|
__PACKED_STRUCT T_UINT32_READ { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __ALIGNED
|
||||||
|
#define __ALIGNED(x) __align(x)
|
||||||
|
#endif
|
||||||
|
#ifndef __RESTRICT
|
||||||
|
#warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored.
|
||||||
|
#define __RESTRICT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* COSMIC Compiler
|
||||||
|
*/
|
||||||
|
#elif defined ( __CSMC__ )
|
||||||
|
#include <cmsis_csm.h>
|
||||||
|
|
||||||
|
#ifndef __ASM
|
||||||
|
#define __ASM _asm
|
||||||
|
#endif
|
||||||
|
#ifndef __INLINE
|
||||||
|
#define __INLINE inline
|
||||||
|
#endif
|
||||||
|
#ifndef __STATIC_INLINE
|
||||||
|
#define __STATIC_INLINE static inline
|
||||||
|
#endif
|
||||||
|
#ifndef __STATIC_FORCEINLINE
|
||||||
|
#define __STATIC_FORCEINLINE __STATIC_INLINE
|
||||||
|
#endif
|
||||||
|
#ifndef __NO_RETURN
|
||||||
|
// NO RETURN is automatically detected hence no warning here
|
||||||
|
#define __NO_RETURN
|
||||||
|
#endif
|
||||||
|
#ifndef __USED
|
||||||
|
#warning No compiler specific solution for __USED. __USED is ignored.
|
||||||
|
#define __USED
|
||||||
|
#endif
|
||||||
|
#ifndef __WEAK
|
||||||
|
#define __WEAK __weak
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED
|
||||||
|
#define __PACKED @packed
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED_STRUCT
|
||||||
|
#define __PACKED_STRUCT @packed struct
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED_UNION
|
||||||
|
#define __PACKED_UNION @packed union
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32 /* deprecated */
|
||||||
|
@packed struct T_UINT32 { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT16_WRITE
|
||||||
|
__PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };
|
||||||
|
#define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT16_READ
|
||||||
|
__PACKED_STRUCT T_UINT16_READ { uint16_t v; };
|
||||||
|
#define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32_WRITE
|
||||||
|
__PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32_READ
|
||||||
|
__PACKED_STRUCT T_UINT32_READ { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __ALIGNED
|
||||||
|
#warning No compiler specific solution for __ALIGNED. __ALIGNED is ignored.
|
||||||
|
#define __ALIGNED(x)
|
||||||
|
#endif
|
||||||
|
#ifndef __RESTRICT
|
||||||
|
#warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored.
|
||||||
|
#define __RESTRICT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error Unknown compiler.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __CMSIS_COMPILER_H */
|
||||||
|
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,39 @@
|
|||||||
|
/**************************************************************************//**
|
||||||
|
* @file cmsis_version.h
|
||||||
|
* @brief CMSIS Core(M) Version definitions
|
||||||
|
* @version V5.0.2
|
||||||
|
* @date 19. April 2017
|
||||||
|
******************************************************************************/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2017 ARM Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined ( __ICCARM__ )
|
||||||
|
#pragma system_include /* treat file as system include file for MISRA check */
|
||||||
|
#elif defined (__clang__)
|
||||||
|
#pragma clang system_header /* treat file as system include file */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __CMSIS_VERSION_H
|
||||||
|
#define __CMSIS_VERSION_H
|
||||||
|
|
||||||
|
/* CMSIS Version definitions */
|
||||||
|
#define __CM_CMSIS_VERSION_MAIN ( 5U) /*!< [31:16] CMSIS Core(M) main version */
|
||||||
|
#define __CM_CMSIS_VERSION_SUB ( 1U) /*!< [15:0] CMSIS Core(M) sub version */
|
||||||
|
#define __CM_CMSIS_VERSION ((__CM_CMSIS_VERSION_MAIN << 16U) | \
|
||||||
|
__CM_CMSIS_VERSION_SUB ) /*!< CMSIS Core(M) version number */
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,270 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @file mpu_armv7.h
|
||||||
|
* @brief CMSIS MPU API for Armv7-M MPU
|
||||||
|
* @version V5.0.4
|
||||||
|
* @date 10. January 2018
|
||||||
|
******************************************************************************/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017-2018 Arm Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined ( __ICCARM__ )
|
||||||
|
#pragma system_include /* treat file as system include file for MISRA check */
|
||||||
|
#elif defined (__clang__)
|
||||||
|
#pragma clang system_header /* treat file as system include file */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARM_MPU_ARMV7_H
|
||||||
|
#define ARM_MPU_ARMV7_H
|
||||||
|
|
||||||
|
#define ARM_MPU_REGION_SIZE_32B ((uint8_t)0x04U) ///!< MPU Region Size 32 Bytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_64B ((uint8_t)0x05U) ///!< MPU Region Size 64 Bytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_128B ((uint8_t)0x06U) ///!< MPU Region Size 128 Bytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_256B ((uint8_t)0x07U) ///!< MPU Region Size 256 Bytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_512B ((uint8_t)0x08U) ///!< MPU Region Size 512 Bytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_1KB ((uint8_t)0x09U) ///!< MPU Region Size 1 KByte
|
||||||
|
#define ARM_MPU_REGION_SIZE_2KB ((uint8_t)0x0AU) ///!< MPU Region Size 2 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_4KB ((uint8_t)0x0BU) ///!< MPU Region Size 4 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_8KB ((uint8_t)0x0CU) ///!< MPU Region Size 8 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_16KB ((uint8_t)0x0DU) ///!< MPU Region Size 16 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_32KB ((uint8_t)0x0EU) ///!< MPU Region Size 32 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_64KB ((uint8_t)0x0FU) ///!< MPU Region Size 64 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_128KB ((uint8_t)0x10U) ///!< MPU Region Size 128 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_256KB ((uint8_t)0x11U) ///!< MPU Region Size 256 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_512KB ((uint8_t)0x12U) ///!< MPU Region Size 512 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_1MB ((uint8_t)0x13U) ///!< MPU Region Size 1 MByte
|
||||||
|
#define ARM_MPU_REGION_SIZE_2MB ((uint8_t)0x14U) ///!< MPU Region Size 2 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_4MB ((uint8_t)0x15U) ///!< MPU Region Size 4 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_8MB ((uint8_t)0x16U) ///!< MPU Region Size 8 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_16MB ((uint8_t)0x17U) ///!< MPU Region Size 16 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_32MB ((uint8_t)0x18U) ///!< MPU Region Size 32 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_64MB ((uint8_t)0x19U) ///!< MPU Region Size 64 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_128MB ((uint8_t)0x1AU) ///!< MPU Region Size 128 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_256MB ((uint8_t)0x1BU) ///!< MPU Region Size 256 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_512MB ((uint8_t)0x1CU) ///!< MPU Region Size 512 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_1GB ((uint8_t)0x1DU) ///!< MPU Region Size 1 GByte
|
||||||
|
#define ARM_MPU_REGION_SIZE_2GB ((uint8_t)0x1EU) ///!< MPU Region Size 2 GBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_4GB ((uint8_t)0x1FU) ///!< MPU Region Size 4 GBytes
|
||||||
|
|
||||||
|
#define ARM_MPU_AP_NONE 0U ///!< MPU Access Permission no access
|
||||||
|
#define ARM_MPU_AP_PRIV 1U ///!< MPU Access Permission privileged access only
|
||||||
|
#define ARM_MPU_AP_URO 2U ///!< MPU Access Permission unprivileged access read-only
|
||||||
|
#define ARM_MPU_AP_FULL 3U ///!< MPU Access Permission full access
|
||||||
|
#define ARM_MPU_AP_PRO 5U ///!< MPU Access Permission privileged access read-only
|
||||||
|
#define ARM_MPU_AP_RO 6U ///!< MPU Access Permission read-only access
|
||||||
|
|
||||||
|
/** MPU Region Base Address Register Value
|
||||||
|
*
|
||||||
|
* \param Region The region to be configured, number 0 to 15.
|
||||||
|
* \param BaseAddress The base address for the region.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_RBAR(Region, BaseAddress) \
|
||||||
|
(((BaseAddress) & MPU_RBAR_ADDR_Msk) | \
|
||||||
|
((Region) & MPU_RBAR_REGION_Msk) | \
|
||||||
|
(MPU_RBAR_VALID_Msk))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attributes
|
||||||
|
*
|
||||||
|
* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral.
|
||||||
|
* \param IsShareable Region is shareable between multiple bus masters.
|
||||||
|
* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache.
|
||||||
|
* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable) \
|
||||||
|
((((TypeExtField ) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk) | \
|
||||||
|
(((IsShareable ) << MPU_RASR_S_Pos) & MPU_RASR_S_Msk) | \
|
||||||
|
(((IsCacheable ) << MPU_RASR_C_Pos) & MPU_RASR_C_Msk) | \
|
||||||
|
(((IsBufferable ) << MPU_RASR_B_Pos) & MPU_RASR_B_Msk))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Region Attribute and Size Register Value
|
||||||
|
*
|
||||||
|
* \param DisableExec Instruction access disable bit, 1= disable instruction fetches.
|
||||||
|
* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode.
|
||||||
|
* \param AccessAttributes Memory access attribution, see \ref ARM_MPU_ACCESS_.
|
||||||
|
* \param SubRegionDisable Sub-region disable field.
|
||||||
|
* \param Size Region size of the region to be configured, for example 4K, 8K.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_RASR_EX(DisableExec, AccessPermission, AccessAttributes, SubRegionDisable, Size) \
|
||||||
|
((((DisableExec ) << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) | \
|
||||||
|
(((AccessPermission) << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) | \
|
||||||
|
(((AccessAttributes) ) & (MPU_RASR_TEX_Msk | MPU_RASR_S_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Region Attribute and Size Register Value
|
||||||
|
*
|
||||||
|
* \param DisableExec Instruction access disable bit, 1= disable instruction fetches.
|
||||||
|
* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode.
|
||||||
|
* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral.
|
||||||
|
* \param IsShareable Region is shareable between multiple bus masters.
|
||||||
|
* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache.
|
||||||
|
* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy.
|
||||||
|
* \param SubRegionDisable Sub-region disable field.
|
||||||
|
* \param Size Region size of the region to be configured, for example 4K, 8K.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) \
|
||||||
|
ARM_MPU_RASR_EX(DisableExec, AccessPermission, ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable), SubRegionDisable, Size)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attribute for strongly ordered memory.
|
||||||
|
* - TEX: 000b
|
||||||
|
* - Shareable
|
||||||
|
* - Non-cacheable
|
||||||
|
* - Non-bufferable
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_ACCESS_ORDERED ARM_MPU_ACCESS_(0U, 1U, 0U, 0U)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attribute for device memory.
|
||||||
|
* - TEX: 000b (if non-shareable) or 010b (if shareable)
|
||||||
|
* - Shareable or non-shareable
|
||||||
|
* - Non-cacheable
|
||||||
|
* - Bufferable (if shareable) or non-bufferable (if non-shareable)
|
||||||
|
*
|
||||||
|
* \param IsShareable Configures the device memory as shareable or non-shareable.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_ACCESS_DEVICE(IsShareable) ((IsShareable) ? ARM_MPU_ACCESS_(0U, 1U, 0U, 1U) : ARM_MPU_ACCESS_(2U, 0U, 0U, 0U))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attribute for normal memory.
|
||||||
|
* - TEX: 1BBb (reflecting outer cacheability rules)
|
||||||
|
* - Shareable or non-shareable
|
||||||
|
* - Cacheable or non-cacheable (reflecting inner cacheability rules)
|
||||||
|
* - Bufferable or non-bufferable (reflecting inner cacheability rules)
|
||||||
|
*
|
||||||
|
* \param OuterCp Configures the outer cache policy.
|
||||||
|
* \param InnerCp Configures the inner cache policy.
|
||||||
|
* \param IsShareable Configures the memory as shareable or non-shareable.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_ACCESS_NORMAL(OuterCp, InnerCp, IsShareable) ARM_MPU_ACCESS_((4U | (OuterCp)), IsShareable, ((InnerCp) & 2U), ((InnerCp) & 1U))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attribute non-cacheable policy.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_CACHEP_NOCACHE 0U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attribute write-back, write and read allocate policy.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_CACHEP_WB_WRA 1U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attribute write-through, no write allocate policy.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_CACHEP_WT_NWA 2U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attribute write-back, no write allocate policy.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_CACHEP_WB_NWA 3U
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct for a single MPU Region
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t RBAR; //!< The region base address register value (RBAR)
|
||||||
|
uint32_t RASR; //!< The region attribute and size register value (RASR) \ref MPU_RASR
|
||||||
|
} ARM_MPU_Region_t;
|
||||||
|
|
||||||
|
/** Enable the MPU.
|
||||||
|
* \param MPU_Control Default access permissions for unconfigured regions.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control)
|
||||||
|
{
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
|
MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk;
|
||||||
|
#ifdef SCB_SHCSR_MEMFAULTENA_Msk
|
||||||
|
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Disable the MPU.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void ARM_MPU_Disable(void)
|
||||||
|
{
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
|
#ifdef SCB_SHCSR_MEMFAULTENA_Msk
|
||||||
|
SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
|
||||||
|
#endif
|
||||||
|
MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Clear and disable the given MPU region.
|
||||||
|
* \param rnr Region number to be cleared.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr)
|
||||||
|
{
|
||||||
|
MPU->RNR = rnr;
|
||||||
|
MPU->RASR = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Configure an MPU region.
|
||||||
|
* \param rbar Value for RBAR register.
|
||||||
|
* \param rsar Value for RSAR register.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rbar, uint32_t rasr)
|
||||||
|
{
|
||||||
|
MPU->RBAR = rbar;
|
||||||
|
MPU->RASR = rasr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Configure the given MPU region.
|
||||||
|
* \param rnr Region number to be configured.
|
||||||
|
* \param rbar Value for RBAR register.
|
||||||
|
* \param rsar Value for RSAR register.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void ARM_MPU_SetRegionEx(uint32_t rnr, uint32_t rbar, uint32_t rasr)
|
||||||
|
{
|
||||||
|
MPU->RNR = rnr;
|
||||||
|
MPU->RBAR = rbar;
|
||||||
|
MPU->RASR = rasr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Memcopy with strictly ordered memory access, e.g. for register targets.
|
||||||
|
* \param dst Destination data is copied to.
|
||||||
|
* \param src Source data is copied from.
|
||||||
|
* \param len Amount of data words to be copied.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void orderedCpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0U; i < len; ++i)
|
||||||
|
{
|
||||||
|
dst[i] = src[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Load the given number of MPU regions from a table.
|
||||||
|
* \param table Pointer to the MPU configuration table.
|
||||||
|
* \param cnt Amount of regions to be configured.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void ARM_MPU_Load(ARM_MPU_Region_t const* table, uint32_t cnt)
|
||||||
|
{
|
||||||
|
const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U;
|
||||||
|
while (cnt > MPU_TYPE_RALIASES) {
|
||||||
|
orderedCpy(&(MPU->RBAR), &(table->RBAR), MPU_TYPE_RALIASES*rowWordSize);
|
||||||
|
table += MPU_TYPE_RALIASES;
|
||||||
|
cnt -= MPU_TYPE_RALIASES;
|
||||||
|
}
|
||||||
|
orderedCpy(&(MPU->RBAR), &(table->RBAR), cnt*rowWordSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,104 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @file system_stm32f4xx.h
|
||||||
|
* @author MCD Application Team
|
||||||
|
* @brief CMSIS Cortex-M4 Device System Source File for STM32F4xx devices.
|
||||||
|
******************************************************************************
|
||||||
|
* @attention
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 STMicroelectronics.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This software is licensed under terms that can be found in the LICENSE file
|
||||||
|
* in the root directory of this software component.
|
||||||
|
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup CMSIS
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup stm32f4xx_system
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Define to prevent recursive inclusion
|
||||||
|
*/
|
||||||
|
#ifndef __SYSTEM_STM32F4XX_H
|
||||||
|
#define __SYSTEM_STM32F4XX_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @addtogroup STM32F4xx_System_Includes
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/** @addtogroup STM32F4xx_System_Exported_types
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/* This variable is updated in three ways:
|
||||||
|
1) by calling CMSIS function SystemCoreClockUpdate()
|
||||||
|
2) by calling HAL API function HAL_RCC_GetSysClockFreq()
|
||||||
|
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
|
||||||
|
Note: If you use this function to configure the system clock; then there
|
||||||
|
is no need to call the 2 first functions listed above, since SystemCoreClock
|
||||||
|
variable is updated automatically.
|
||||||
|
*/
|
||||||
|
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
|
||||||
|
|
||||||
|
extern const uint8_t AHBPrescTable[16]; /*!< AHB prescalers table values */
|
||||||
|
extern const uint8_t APBPrescTable[8]; /*!< APB prescalers table values */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup STM32F4xx_System_Exported_Constants
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup STM32F4xx_System_Exported_Macros
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup STM32F4xx_System_Exported_Functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern void SystemInit(void);
|
||||||
|
extern void SystemCoreClockUpdate(void);
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*__SYSTEM_STM32F4XX_H */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
ENTRY(_reset);
|
||||||
|
MEMORY {
|
||||||
|
flash(rx) : ORIGIN = 0x08000000, LENGTH = 2048k
|
||||||
|
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 192k /* remaining 64k in a separate address space */
|
||||||
|
}
|
||||||
|
_estack = ORIGIN(sram) + LENGTH(sram); /* stack points to end of SRAM */
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
.vectors : { KEEP(*(.vectors)) } > flash
|
||||||
|
.text : { *(.text*) } > flash
|
||||||
|
.rodata : { *(.rodata*) } > flash
|
||||||
|
|
||||||
|
.data : {
|
||||||
|
_sdata = .; /* .data section start */
|
||||||
|
*(.first_data)
|
||||||
|
*(.data SORT(.data.*))
|
||||||
|
_edata = .; /* .data section end */
|
||||||
|
} > sram AT > flash
|
||||||
|
_sidata = LOADADDR(.data);
|
||||||
|
|
||||||
|
.bss : {
|
||||||
|
_sbss = .; /* .bss section start */
|
||||||
|
*(.bss SORT(.bss.*) COMMON)
|
||||||
|
_ebss = .; /* .bss section end */
|
||||||
|
} > sram
|
||||||
|
|
||||||
|
. = ALIGN(8);
|
||||||
|
_end = .; /* for cmsis_gcc.h */
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
// Copyright (c) 2022 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include "mcu.h"
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
// HTTP server event handler function
|
||||||
|
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||||
|
if (mg_http_match_uri(hm, "/api/debug")) {
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
mg_http_reply(c, 200, "", "%s\n", "hi");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void) fn_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ethernet_init(void) {
|
||||||
|
// Initialise Ethernet. Enable MAC GPIO pins, see
|
||||||
|
// https://www.farnell.com/datasheets/2014265.pdf section 6.10
|
||||||
|
uint16_t pins[] = {PIN('A', 1), PIN('A', 2), PIN('A', 7),
|
||||||
|
PIN('B', 13), PIN('C', 1), PIN('C', 4),
|
||||||
|
PIN('C', 5), PIN('G', 11), PIN('G', 13)};
|
||||||
|
for (size_t i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) {
|
||||||
|
gpio_init(pins[i], GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_INSANE,
|
||||||
|
GPIO_PULL_NONE, 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
NVIC_EnableIRQ(61); // Setup Ethernet IRQ handler
|
||||||
|
RCC->APB2ENR |= BIT(14); // Enable SYSCFG
|
||||||
|
SYSCFG->PMC |= BIT(23); // Use RMII. Goes first!
|
||||||
|
RCC->AHB1ENR |= BIT(25) | BIT(26) | BIT(27); // Enable Ethernet clocks
|
||||||
|
RCC->AHB1RSTR |= BIT(25); // ETHMAC force reset
|
||||||
|
RCC->AHB1RSTR &= ~BIT(25); // ETHMAC release reset
|
||||||
|
}
|
||||||
|
|
||||||
|
static void server(void *args) {
|
||||||
|
struct mg_mgr mgr; // Initialise Mongoose event manager
|
||||||
|
mg_mgr_init(&mgr); // and attach it to the MIP interface
|
||||||
|
mg_log_set(MG_LL_DEBUG); // Set log level
|
||||||
|
|
||||||
|
// Initialise Mongoose network stack
|
||||||
|
// Specify MAC address, and IP/mask/GW in network byte order for static
|
||||||
|
// IP configuration. If IP/mask/GW are unset, DHCP is going to be used
|
||||||
|
MG_INFO(("Initializing Ethernet driver"));
|
||||||
|
ethernet_init();
|
||||||
|
struct mip_driver_stm32_data driver_data = {.mdc_cr = 4}; // See driver_stm32.h
|
||||||
|
struct mip_if mif = {
|
||||||
|
.mac = {2, 0, 1, 2, 3, 5},
|
||||||
|
.driver = &mip_driver_stm32,
|
||||||
|
.driver_data = &driver_data,
|
||||||
|
};
|
||||||
|
mip_init(&mgr, &mif);
|
||||||
|
|
||||||
|
MG_INFO(("Starting Mongoose v%s", MG_VERSION)); // Tell the world
|
||||||
|
mg_http_listen(&mgr, "http://0.0.0.0", fn, &mgr); // Web listener
|
||||||
|
while (args == NULL) mg_mgr_poll(&mgr, 1000); // Infinite event loop
|
||||||
|
mg_mgr_free(&mgr); // Unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blinker(void *args) {
|
||||||
|
uint16_t led = PIN('B', 7);
|
||||||
|
gpio_init(led, GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_MEDIUM,
|
||||||
|
GPIO_PULL_NONE, 0);
|
||||||
|
for (;;) {
|
||||||
|
gpio_toggle(led);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(750));
|
||||||
|
MG_INFO(("blink %s, RAM: %u", (char *) args, xPortGetFreeHeapSize()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
clock_init(); // Set clock to max of 180 MHz
|
||||||
|
systick_init(SYS_FREQUENCY / 1000); // Tick every 1 ms
|
||||||
|
uart_init(UART3, 115200); // Initialise UART
|
||||||
|
xTaskCreate(blinker, "blinker", 128, ":)", configMAX_PRIORITIES - 1, NULL);
|
||||||
|
xTaskCreate(server, "server", 2048, 0, configMAX_PRIORITIES - 1, NULL);
|
||||||
|
vTaskStartScheduler(); // This blocks
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
// Copyright (c) 2022 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
// https://www.st.com/resource/en/reference_manual/dm00031020-stm32f405-415-stm32f407-417-stm32f427-437-and-stm32f429-439-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "stm32f429xx.h"
|
||||||
|
|
||||||
|
#define BIT(x) (1UL << (x))
|
||||||
|
#define SETBITS(R, CLEARMASK, SETMASK) (R) = ((R) & ~(CLEARMASK)) | (SETMASK)
|
||||||
|
#define PIN(bank, num) ((((bank) - 'A') << 8) | (num))
|
||||||
|
#define PINNO(pin) (pin & 255)
|
||||||
|
#define PINBANK(pin) (pin >> 8)
|
||||||
|
|
||||||
|
// 6.3.3: APB1 clock <= 45MHz; APB2 clock <= 90MHz
|
||||||
|
// 3.5.1, Table 11: configure flash latency (WS) in accordance to clock freq
|
||||||
|
// 33.4: The AHB clock must be at least 25 MHz when Ethernet is used
|
||||||
|
enum { APB1_PRE = 5 /* AHB clock / 4 */, APB2_PRE = 4 /* AHB clock / 2 */ };
|
||||||
|
enum { PLL_HSI = 16, PLL_M = 8, PLL_N = 180, PLL_P = 2 }; // Run at 180 Mhz
|
||||||
|
#define FLASH_LATENCY 5
|
||||||
|
#define SYS_FREQUENCY ((PLL_HSI * PLL_N / PLL_M / PLL_P) * 1000000)
|
||||||
|
#define APB2_FREQUENCY (SYS_FREQUENCY / (BIT(APB2_PRE - 3)))
|
||||||
|
#define APB1_FREQUENCY (SYS_FREQUENCY / (BIT(APB1_PRE - 3)))
|
||||||
|
|
||||||
|
static inline void spin(volatile uint32_t count) {
|
||||||
|
while (count--) asm("nop");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void systick_init(uint32_t ticks) {
|
||||||
|
if ((ticks - 1) > 0xffffff) return; // Systick timer is 24 bit
|
||||||
|
SysTick->LOAD = ticks - 1;
|
||||||
|
SysTick->VAL = 0;
|
||||||
|
SysTick->CTRL = BIT(0) | BIT(1) | BIT(2); // Enable systick
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GPIO(bank) ((GPIO_TypeDef *) (GPIOA_BASE + 0x400 * (bank)))
|
||||||
|
|
||||||
|
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG };
|
||||||
|
enum { GPIO_OTYPE_PUSH_PULL, GPIO_OTYPE_OPEN_DRAIN };
|
||||||
|
enum { GPIO_SPEED_LOW, GPIO_SPEED_MEDIUM, GPIO_SPEED_HIGH, GPIO_SPEED_INSANE };
|
||||||
|
enum { GPIO_PULL_NONE, GPIO_PULL_UP, GPIO_PULL_DOWN };
|
||||||
|
|
||||||
|
static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
|
||||||
|
uint8_t speed, uint8_t pull, uint8_t af) {
|
||||||
|
GPIO_TypeDef *gpio = GPIO(PINBANK(pin)); // GPIO bank
|
||||||
|
uint8_t n = (uint8_t) (PINNO(pin));
|
||||||
|
RCC->AHB1ENR |= BIT(PINBANK(pin)); // Enable GPIO clock
|
||||||
|
SETBITS(gpio->OTYPER, 1UL << n, ((uint32_t) type) << n);
|
||||||
|
SETBITS(gpio->OSPEEDR, 3UL << (n * 2), ((uint32_t) speed) << (n * 2));
|
||||||
|
SETBITS(gpio->PUPDR, 3UL << (n * 2), ((uint32_t) pull) << (n * 2));
|
||||||
|
SETBITS(gpio->AFR[n >> 3], 15UL << ((n & 7) * 4),
|
||||||
|
((uint32_t) af) << ((n & 7) * 4));
|
||||||
|
SETBITS(gpio->MODER, 3UL << (n * 2), ((uint32_t) mode) << (n * 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static inline void gpio_set_mode(uint16_t pin, uint8_t mode) {
|
||||||
|
GPIO_TypeDef *gpio = GPIO(PINBANK(pin)); // GPIO bank
|
||||||
|
int n = PINNO(pin); // Pin number
|
||||||
|
RCC->AHB1ENR |= BIT(PINBANK(pin)); // Enable GPIO clock
|
||||||
|
gpio->MODER &= ~(3U << (n * 2)); // Clear existing setting
|
||||||
|
gpio->MODER |= (mode & 3) << (n * 2); // Set new mode
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void gpio_set_speed(uint16_t pin, uint8_t speed) {
|
||||||
|
GPIO_TypeDef *gpio = GPIO(PINBANK(pin)); // GPIO bank
|
||||||
|
int n = PINNO(pin); // Pin number
|
||||||
|
//gpio->OSPEEDR &= ~(3UL << (n * 2));
|
||||||
|
//gpio->OSPEEDR |= ~(((uint32_t) speed) << (n * 2));
|
||||||
|
SETBITS(gpio->OSPEEDR, 3UL << (n * 2), ((uint32_t) speed) << (n * 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void gpio_set_af(uint16_t pin, uint8_t af) {
|
||||||
|
GPIO_TypeDef *gpio = GPIO(PINBANK(pin)); // GPIO bank
|
||||||
|
int n = PINNO(pin); // Pin number
|
||||||
|
//gpio->AFR[n >> 3] &= ~(15UL << ((n & 7) * 4));
|
||||||
|
//gpio->AFR[n >> 3] |= ((uint32_t) af_num) << ((n & 7) * 4);
|
||||||
|
SETBITS(gpio->AFR[n >> 3], 15UL << ((n & 7) * 4),
|
||||||
|
((uint32_t) af) << ((n & 7) * 4));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void gpio_write(uint16_t pin, bool val) {
|
||||||
|
GPIO_TypeDef *gpio = GPIO(PINBANK(pin));
|
||||||
|
gpio->BSRR = (1U << PINNO(pin)) << (val ? 0 : 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void gpio_toggle(uint16_t pin) {
|
||||||
|
GPIO_TypeDef *gpio = GPIO(PINBANK(pin)); // GPIO bank
|
||||||
|
uint32_t mask = BIT(PINNO(pin));
|
||||||
|
gpio->BSRR |= mask << (gpio->ODR & mask ? 16 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UART1 USART1
|
||||||
|
#define UART2 USART2
|
||||||
|
#define UART3 USART3
|
||||||
|
|
||||||
|
static inline void uart_init(USART_TypeDef *uart, unsigned long baud) {
|
||||||
|
// https://www.st.com/resource/en/datasheet/stm32f429zi.pdf
|
||||||
|
uint8_t af = 7; // Alternate function
|
||||||
|
uint16_t rx = 0, tx = 0; // pins
|
||||||
|
uint32_t freq = 0; // Bus frequency. UART1 is on APB2, rest on APB1
|
||||||
|
|
||||||
|
if (uart == UART1) freq = APB2_FREQUENCY, RCC->APB2ENR |= BIT(4);
|
||||||
|
if (uart == UART2) freq = APB1_FREQUENCY, RCC->APB1ENR |= BIT(17);
|
||||||
|
if (uart == UART3) freq = APB1_FREQUENCY, RCC->APB1ENR |= BIT(18);
|
||||||
|
|
||||||
|
if (uart == UART1) tx = PIN('A', 9), rx = PIN('A', 10);
|
||||||
|
if (uart == UART2) tx = PIN('A', 2), rx = PIN('A', 3);
|
||||||
|
if (uart == UART3) tx = PIN('D', 8), rx = PIN('D', 9);
|
||||||
|
|
||||||
|
gpio_init(tx, GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, 0, af);
|
||||||
|
gpio_init(rx, GPIO_MODE_AF, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH, 0, af);
|
||||||
|
uart->CR1 = 0; // Disable this UART
|
||||||
|
uart->BRR = freq / baud; // Set baud rate
|
||||||
|
uart->CR1 |= BIT(13) | BIT(2) | BIT(3); // Set UE, RE, TE
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void uart_write_byte(USART_TypeDef *uart, uint8_t byte) {
|
||||||
|
uart->DR = byte;
|
||||||
|
while ((uart->SR & BIT(7)) == 0) spin(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void uart_write_buf(USART_TypeDef *uart, char *buf, size_t len) {
|
||||||
|
while (len-- > 0) uart_write_byte(uart, *(uint8_t *) buf++);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int uart_read_ready(USART_TypeDef *uart) {
|
||||||
|
return uart->SR & BIT(5); // If RXNE bit is set, data is ready
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t uart_read_byte(USART_TypeDef *uart) {
|
||||||
|
return (uint8_t) (uart->DR & 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void clock_init(void) { // Set clock frequency
|
||||||
|
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU
|
||||||
|
FLASH->ACR |= FLASH_LATENCY | BIT(8) |
|
||||||
|
BIT(9); // Flash latency, prefetch, Icache, Dcache
|
||||||
|
RCC->PLLCFGR &= ~((BIT(17) - 1)); // Clear PLL multipliers
|
||||||
|
RCC->PLLCFGR |= (((PLL_P - 2) / 2) & 3) << 16; // Set PLL_P
|
||||||
|
RCC->PLLCFGR |= PLL_M | (PLL_N << 6); // Set PLL_M and PLL_N
|
||||||
|
RCC->CR |= BIT(24); // Enable PLL
|
||||||
|
while ((RCC->CR & BIT(25)) == 0) spin(1); // Wait until done
|
||||||
|
RCC->CFGR = (APB1_PRE << 10) | (APB2_PRE << 13); // Set prescalers
|
||||||
|
RCC->CFGR |= 2; // Set clock source to PLL
|
||||||
|
while ((RCC->CFGR & 12) == 0) spin(1); // Wait until done
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define MG_ARCH MG_ARCH_FREERTOS
|
||||||
|
#define MG_ENABLE_MIP 1
|
||||||
|
#define MG_IO_SIZE 256
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
// Startup code
|
||||||
|
__attribute__((naked, noreturn)) void _reset(void) {
|
||||||
|
// Initialise memory
|
||||||
|
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++;
|
||||||
|
|
||||||
|
// Call main()
|
||||||
|
extern void main(void);
|
||||||
|
main();
|
||||||
|
for (;;) (void) 0; // Infinite loop
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((weak)) DefaultIRQHandler(void) {
|
||||||
|
for (;;) (void) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WEAK_ALIAS __attribute__((weak, alias("DefaultIRQHandler")))
|
||||||
|
|
||||||
|
WEAK_ALIAS void NMI_Handler(void);
|
||||||
|
WEAK_ALIAS void HardFault_Handler(void);
|
||||||
|
WEAK_ALIAS void MemManage_Handler(void);
|
||||||
|
WEAK_ALIAS void BusFault_Handler(void);
|
||||||
|
WEAK_ALIAS void UsageFault_Handler(void);
|
||||||
|
WEAK_ALIAS void SVC_Handler(void);
|
||||||
|
WEAK_ALIAS void DebugMon_Handler(void);
|
||||||
|
WEAK_ALIAS void PendSV_Handler(void);
|
||||||
|
WEAK_ALIAS void SysTick_Handler(void);
|
||||||
|
|
||||||
|
WEAK_ALIAS void WWDG_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void PVD_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TAMP_STAMP_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void RTC_WKUP_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void FLASH_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void RCC_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void EXTI0_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void EXTI1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void EXTI2_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void EXTI3_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void EXTI4_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void EXTI9_5_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void EXTI15_10_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream0_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream2_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream3_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream4_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream5_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream6_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void ADC_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN1_TX_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN1_RX0_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN1_RX1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN1_SCE_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM1_BRK_TIM9_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM1_UP_TIM10_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM1_TRG_COM_TIM11_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM1_CC_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM2_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM3_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM4_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void I2C1_EV_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void I2C1_ER_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void I2C2_EV_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void I2C2_ER_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SPI1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SPI2_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void USART1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void USART2_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void USART3_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void RTC_Alarm_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void OTG_FS_WKUP_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM8_BRK_TIM12_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM8_UP_TIM13_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM8_TRG_COM_TIM14_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM8_CC_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA1_Stream7_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void FMC_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SDMMC1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM5_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SPI3_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void UART4_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void UART5_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM6_DAC_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void TIM7_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream0_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream2_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream3_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream4_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void ETH_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void ETH_WKUP_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN2_TX_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN2_RX0_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN2_RX1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void CAN2_SCE_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void OTG_FS_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream5_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream6_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2_Stream7_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void USART6_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void I2C3_EV_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void I2C3_ER_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void OTG_HS_EP1_OUT_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void OTG_HS_EP1_IN_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void OTG_HS_WKUP_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void OTG_HS_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DCMI_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void RNG_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void FPU_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void UART7_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void UART8_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SPI4_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SPI5_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SPI6_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void SAI1_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void LTDC_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void LTDC_ER_IRQHandler(void);
|
||||||
|
WEAK_ALIAS void DMA2D_IRQHandler(void);
|
||||||
|
|
||||||
|
// IRQ table
|
||||||
|
extern void _estack();
|
||||||
|
__attribute__((section(".vectors"))) void (*tab[16 + 91])(void) = {
|
||||||
|
// Cortex interrupts
|
||||||
|
_estack, _reset, NMI_Handler, HardFault_Handler,
|
||||||
|
MemManage_Handler, BusFault_Handler, UsageFault_Handler, 0, 0, 0, 0,
|
||||||
|
SVC_Handler, DebugMon_Handler, 0, PendSV_Handler, SysTick_Handler,
|
||||||
|
|
||||||
|
// Interrupts from peripherals
|
||||||
|
WWDG_IRQHandler, PVD_IRQHandler, TAMP_STAMP_IRQHandler, RTC_WKUP_IRQHandler,
|
||||||
|
FLASH_IRQHandler, RCC_IRQHandler, EXTI0_IRQHandler, EXTI1_IRQHandler,
|
||||||
|
EXTI2_IRQHandler, EXTI3_IRQHandler, EXTI4_IRQHandler,
|
||||||
|
DMA1_Stream0_IRQHandler, DMA1_Stream1_IRQHandler, DMA1_Stream2_IRQHandler,
|
||||||
|
DMA1_Stream3_IRQHandler, DMA1_Stream4_IRQHandler, DMA1_Stream5_IRQHandler,
|
||||||
|
DMA1_Stream6_IRQHandler, ADC_IRQHandler, CAN1_TX_IRQHandler,
|
||||||
|
CAN1_RX0_IRQHandler, CAN1_RX1_IRQHandler, CAN1_SCE_IRQHandler,
|
||||||
|
EXTI9_5_IRQHandler, TIM1_BRK_TIM9_IRQHandler, TIM1_UP_TIM10_IRQHandler,
|
||||||
|
TIM1_TRG_COM_TIM11_IRQHandler, TIM1_CC_IRQHandler, TIM2_IRQHandler,
|
||||||
|
TIM3_IRQHandler, TIM4_IRQHandler, I2C1_EV_IRQHandler, I2C1_ER_IRQHandler,
|
||||||
|
I2C2_EV_IRQHandler, I2C2_ER_IRQHandler, SPI1_IRQHandler, SPI2_IRQHandler,
|
||||||
|
USART1_IRQHandler, USART2_IRQHandler, USART3_IRQHandler,
|
||||||
|
EXTI15_10_IRQHandler, RTC_Alarm_IRQHandler, OTG_FS_WKUP_IRQHandler,
|
||||||
|
TIM8_BRK_TIM12_IRQHandler, TIM8_UP_TIM13_IRQHandler,
|
||||||
|
TIM8_TRG_COM_TIM14_IRQHandler, TIM8_CC_IRQHandler, DMA1_Stream7_IRQHandler,
|
||||||
|
FMC_IRQHandler, SDMMC1_IRQHandler, TIM5_IRQHandler, SPI3_IRQHandler,
|
||||||
|
UART4_IRQHandler, UART5_IRQHandler, TIM6_DAC_IRQHandler, TIM7_IRQHandler,
|
||||||
|
DMA2_Stream0_IRQHandler, DMA2_Stream1_IRQHandler, DMA2_Stream2_IRQHandler,
|
||||||
|
DMA2_Stream3_IRQHandler, DMA2_Stream4_IRQHandler, ETH_IRQHandler,
|
||||||
|
ETH_WKUP_IRQHandler, CAN2_TX_IRQHandler, CAN2_RX0_IRQHandler,
|
||||||
|
CAN2_RX1_IRQHandler, CAN2_SCE_IRQHandler, OTG_FS_IRQHandler,
|
||||||
|
DMA2_Stream5_IRQHandler, DMA2_Stream6_IRQHandler, DMA2_Stream7_IRQHandler,
|
||||||
|
USART6_IRQHandler, I2C3_EV_IRQHandler, I2C3_ER_IRQHandler,
|
||||||
|
OTG_HS_EP1_OUT_IRQHandler, OTG_HS_EP1_IN_IRQHandler, OTG_HS_WKUP_IRQHandler,
|
||||||
|
OTG_HS_IRQHandler, DCMI_IRQHandler, 0, RNG_IRQHandler, FPU_IRQHandler,
|
||||||
|
UART7_IRQHandler, UART8_IRQHandler, SPI4_IRQHandler, SPI5_IRQHandler,
|
||||||
|
SPI6_IRQHandler, SAI1_IRQHandler, LTDC_IRQHandler, LTDC_ER_IRQHandler,
|
||||||
|
DMA2D_IRQHandler};
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#include "mcu.h"
|
||||||
|
|
||||||
|
int _write(int fd, char *ptr, int len) {
|
||||||
|
(void) fd, (void) ptr, (void) len;
|
||||||
|
if (fd == 1) uart_write_buf(UART3, ptr, (size_t) len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _fstat(int fd, struct stat *st) {
|
||||||
|
(void) fd, (void) st;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *_sbrk(int incr) {
|
||||||
|
extern char _end;
|
||||||
|
static unsigned char *heap = NULL;
|
||||||
|
unsigned char *prev_heap;
|
||||||
|
if (heap == NULL) heap = (unsigned char *) &_end;
|
||||||
|
prev_heap = heap;
|
||||||
|
heap += incr;
|
||||||
|
return prev_heap;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _close(int fd) {
|
||||||
|
(void) fd;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _isatty(int fd) {
|
||||||
|
(void) fd;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _read(int fd, char *ptr, int len) {
|
||||||
|
(void) fd, (void) ptr, (void) len;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _lseek(int fd, int ptr, int dir) {
|
||||||
|
(void) fd, (void) ptr, (void) dir;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
CFLAGS ?= -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion \
|
||||||
|
-Wformat-truncation -fno-common -Wconversion \
|
||||||
|
-g3 -Os -ffunction-sections -fdata-sections \
|
||||||
|
-I. -Iinclude -I../../.. \
|
||||||
|
-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 $(EXTRA_CFLAGS)
|
||||||
|
LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
||||||
|
SOURCES = main.c startup.c syscalls.c ../../../mongoose.c
|
||||||
|
|
||||||
|
TINYUSB_VERSION ?= 0.14.0
|
||||||
|
TINYUSB_REPO ?= https://github.com/hathach/tinyusb
|
||||||
|
SOURCES += tinyusb/src/tusb.c \
|
||||||
|
tinyusb/src/common/tusb_fifo.c \
|
||||||
|
tinyusb/src/device/usbd.c \
|
||||||
|
tinyusb/src/device/usbd_control.c \
|
||||||
|
tinyusb/src/class/net/ecm_rndis_device.c \
|
||||||
|
tinyusb/src/class/net/ncm_device.c \
|
||||||
|
tinyusb/src/portable/synopsys/dwc2/dcd_dwc2.c \
|
||||||
|
tinyusb/lib/networking/rndis_reports.c \
|
||||||
|
usb_descriptors.c
|
||||||
|
CFLAGS += -Itinyusb/src -Itinyusb/lib/networking
|
||||||
|
CFLAGS += -DMG_ARCH=MG_ARCH_NEWLIB -DMG_ENABLE_MIP=1 -DMG_ENABLE_PACKED_FS=1 -DMG_IO_SIZE=512 -DMG_ENABLE_CUSTOM_MILLIS=1
|
||||||
|
CFLAGS += -DSTM32F429xx
|
||||||
|
CFLAGS += -Wno-conversion -Wno-sign-conversion
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
RM = cmd /C del /Q /F
|
||||||
|
else
|
||||||
|
RM = rm -f
|
||||||
|
endif
|
||||||
|
|
||||||
|
all build example: firmware.bin
|
||||||
|
|
||||||
|
tinyusb:
|
||||||
|
git clone --depth 1 -b $(TINYUSB_VERSION) $(TINYUSB_REPO) $@
|
||||||
|
|
||||||
|
$(SOURCES): tinyusb
|
||||||
|
|
||||||
|
firmware.elf: $(SOURCES)
|
||||||
|
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
firmware.bin: firmware.elf
|
||||||
|
arm-none-eabi-objcopy -O binary $< $@
|
||||||
|
|
||||||
|
flash: firmware.bin
|
||||||
|
st-flash --reset write firmware.bin 0x8000000
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) firmware.*
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
/**************************************************************************//**
|
||||||
|
* @file cmsis_compiler.h
|
||||||
|
* @brief CMSIS compiler generic header file
|
||||||
|
* @version V5.0.4
|
||||||
|
* @date 10. January 2018
|
||||||
|
******************************************************************************/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2018 Arm Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CMSIS_COMPILER_H
|
||||||
|
#define __CMSIS_COMPILER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arm Compiler 4/5
|
||||||
|
*/
|
||||||
|
#if defined ( __CC_ARM )
|
||||||
|
#include "cmsis_armcc.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arm Compiler 6 (armclang)
|
||||||
|
*/
|
||||||
|
#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
|
||||||
|
#include "cmsis_armclang.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GNU Compiler
|
||||||
|
*/
|
||||||
|
#elif defined ( __GNUC__ )
|
||||||
|
#include "cmsis_gcc.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IAR Compiler
|
||||||
|
*/
|
||||||
|
#elif defined ( __ICCARM__ )
|
||||||
|
#include <cmsis_iccarm.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TI Arm Compiler
|
||||||
|
*/
|
||||||
|
#elif defined ( __TI_ARM__ )
|
||||||
|
#include <cmsis_ccs.h>
|
||||||
|
|
||||||
|
#ifndef __ASM
|
||||||
|
#define __ASM __asm
|
||||||
|
#endif
|
||||||
|
#ifndef __INLINE
|
||||||
|
#define __INLINE inline
|
||||||
|
#endif
|
||||||
|
#ifndef __STATIC_INLINE
|
||||||
|
#define __STATIC_INLINE static inline
|
||||||
|
#endif
|
||||||
|
#ifndef __STATIC_FORCEINLINE
|
||||||
|
#define __STATIC_FORCEINLINE __STATIC_INLINE
|
||||||
|
#endif
|
||||||
|
#ifndef __NO_RETURN
|
||||||
|
#define __NO_RETURN __attribute__((noreturn))
|
||||||
|
#endif
|
||||||
|
#ifndef __USED
|
||||||
|
#define __USED __attribute__((used))
|
||||||
|
#endif
|
||||||
|
#ifndef __WEAK
|
||||||
|
#define __WEAK __attribute__((weak))
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED
|
||||||
|
#define __PACKED __attribute__((packed))
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED_STRUCT
|
||||||
|
#define __PACKED_STRUCT struct __attribute__((packed))
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED_UNION
|
||||||
|
#define __PACKED_UNION union __attribute__((packed))
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32 /* deprecated */
|
||||||
|
struct __attribute__((packed)) T_UINT32 { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT16_WRITE
|
||||||
|
__PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };
|
||||||
|
#define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void*)(addr))->v) = (val))
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT16_READ
|
||||||
|
__PACKED_STRUCT T_UINT16_READ { uint16_t v; };
|
||||||
|
#define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32_WRITE
|
||||||
|
__PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32_READ
|
||||||
|
__PACKED_STRUCT T_UINT32_READ { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __ALIGNED
|
||||||
|
#define __ALIGNED(x) __attribute__((aligned(x)))
|
||||||
|
#endif
|
||||||
|
#ifndef __RESTRICT
|
||||||
|
#warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored.
|
||||||
|
#define __RESTRICT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TASKING Compiler
|
||||||
|
*/
|
||||||
|
#elif defined ( __TASKING__ )
|
||||||
|
/*
|
||||||
|
* The CMSIS functions have been implemented as intrinsics in the compiler.
|
||||||
|
* Please use "carm -?i" to get an up to date list of all intrinsics,
|
||||||
|
* Including the CMSIS ones.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASM
|
||||||
|
#define __ASM __asm
|
||||||
|
#endif
|
||||||
|
#ifndef __INLINE
|
||||||
|
#define __INLINE inline
|
||||||
|
#endif
|
||||||
|
#ifndef __STATIC_INLINE
|
||||||
|
#define __STATIC_INLINE static inline
|
||||||
|
#endif
|
||||||
|
#ifndef __STATIC_FORCEINLINE
|
||||||
|
#define __STATIC_FORCEINLINE __STATIC_INLINE
|
||||||
|
#endif
|
||||||
|
#ifndef __NO_RETURN
|
||||||
|
#define __NO_RETURN __attribute__((noreturn))
|
||||||
|
#endif
|
||||||
|
#ifndef __USED
|
||||||
|
#define __USED __attribute__((used))
|
||||||
|
#endif
|
||||||
|
#ifndef __WEAK
|
||||||
|
#define __WEAK __attribute__((weak))
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED
|
||||||
|
#define __PACKED __packed__
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED_STRUCT
|
||||||
|
#define __PACKED_STRUCT struct __packed__
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED_UNION
|
||||||
|
#define __PACKED_UNION union __packed__
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32 /* deprecated */
|
||||||
|
struct __packed__ T_UINT32 { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT16_WRITE
|
||||||
|
__PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };
|
||||||
|
#define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT16_READ
|
||||||
|
__PACKED_STRUCT T_UINT16_READ { uint16_t v; };
|
||||||
|
#define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32_WRITE
|
||||||
|
__PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32_READ
|
||||||
|
__PACKED_STRUCT T_UINT32_READ { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __ALIGNED
|
||||||
|
#define __ALIGNED(x) __align(x)
|
||||||
|
#endif
|
||||||
|
#ifndef __RESTRICT
|
||||||
|
#warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored.
|
||||||
|
#define __RESTRICT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* COSMIC Compiler
|
||||||
|
*/
|
||||||
|
#elif defined ( __CSMC__ )
|
||||||
|
#include <cmsis_csm.h>
|
||||||
|
|
||||||
|
#ifndef __ASM
|
||||||
|
#define __ASM _asm
|
||||||
|
#endif
|
||||||
|
#ifndef __INLINE
|
||||||
|
#define __INLINE inline
|
||||||
|
#endif
|
||||||
|
#ifndef __STATIC_INLINE
|
||||||
|
#define __STATIC_INLINE static inline
|
||||||
|
#endif
|
||||||
|
#ifndef __STATIC_FORCEINLINE
|
||||||
|
#define __STATIC_FORCEINLINE __STATIC_INLINE
|
||||||
|
#endif
|
||||||
|
#ifndef __NO_RETURN
|
||||||
|
// NO RETURN is automatically detected hence no warning here
|
||||||
|
#define __NO_RETURN
|
||||||
|
#endif
|
||||||
|
#ifndef __USED
|
||||||
|
#warning No compiler specific solution for __USED. __USED is ignored.
|
||||||
|
#define __USED
|
||||||
|
#endif
|
||||||
|
#ifndef __WEAK
|
||||||
|
#define __WEAK __weak
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED
|
||||||
|
#define __PACKED @packed
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED_STRUCT
|
||||||
|
#define __PACKED_STRUCT @packed struct
|
||||||
|
#endif
|
||||||
|
#ifndef __PACKED_UNION
|
||||||
|
#define __PACKED_UNION @packed union
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32 /* deprecated */
|
||||||
|
@packed struct T_UINT32 { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT16_WRITE
|
||||||
|
__PACKED_STRUCT T_UINT16_WRITE { uint16_t v; };
|
||||||
|
#define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val))
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT16_READ
|
||||||
|
__PACKED_STRUCT T_UINT16_READ { uint16_t v; };
|
||||||
|
#define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32_WRITE
|
||||||
|
__PACKED_STRUCT T_UINT32_WRITE { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val))
|
||||||
|
#endif
|
||||||
|
#ifndef __UNALIGNED_UINT32_READ
|
||||||
|
__PACKED_STRUCT T_UINT32_READ { uint32_t v; };
|
||||||
|
#define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v)
|
||||||
|
#endif
|
||||||
|
#ifndef __ALIGNED
|
||||||
|
#warning No compiler specific solution for __ALIGNED. __ALIGNED is ignored.
|
||||||
|
#define __ALIGNED(x)
|
||||||
|
#endif
|
||||||
|
#ifndef __RESTRICT
|
||||||
|
#warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored.
|
||||||
|
#define __RESTRICT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error Unknown compiler.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __CMSIS_COMPILER_H */
|
||||||
|
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,39 @@
|
|||||||
|
/**************************************************************************//**
|
||||||
|
* @file cmsis_version.h
|
||||||
|
* @brief CMSIS Core(M) Version definitions
|
||||||
|
* @version V5.0.2
|
||||||
|
* @date 19. April 2017
|
||||||
|
******************************************************************************/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2017 ARM Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined ( __ICCARM__ )
|
||||||
|
#pragma system_include /* treat file as system include file for MISRA check */
|
||||||
|
#elif defined (__clang__)
|
||||||
|
#pragma clang system_header /* treat file as system include file */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __CMSIS_VERSION_H
|
||||||
|
#define __CMSIS_VERSION_H
|
||||||
|
|
||||||
|
/* CMSIS Version definitions */
|
||||||
|
#define __CM_CMSIS_VERSION_MAIN ( 5U) /*!< [31:16] CMSIS Core(M) main version */
|
||||||
|
#define __CM_CMSIS_VERSION_SUB ( 1U) /*!< [15:0] CMSIS Core(M) sub version */
|
||||||
|
#define __CM_CMSIS_VERSION ((__CM_CMSIS_VERSION_MAIN << 16U) | \
|
||||||
|
__CM_CMSIS_VERSION_SUB ) /*!< CMSIS Core(M) version number */
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,270 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @file mpu_armv7.h
|
||||||
|
* @brief CMSIS MPU API for Armv7-M MPU
|
||||||
|
* @version V5.0.4
|
||||||
|
* @date 10. January 2018
|
||||||
|
******************************************************************************/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017-2018 Arm Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined ( __ICCARM__ )
|
||||||
|
#pragma system_include /* treat file as system include file for MISRA check */
|
||||||
|
#elif defined (__clang__)
|
||||||
|
#pragma clang system_header /* treat file as system include file */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARM_MPU_ARMV7_H
|
||||||
|
#define ARM_MPU_ARMV7_H
|
||||||
|
|
||||||
|
#define ARM_MPU_REGION_SIZE_32B ((uint8_t)0x04U) ///!< MPU Region Size 32 Bytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_64B ((uint8_t)0x05U) ///!< MPU Region Size 64 Bytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_128B ((uint8_t)0x06U) ///!< MPU Region Size 128 Bytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_256B ((uint8_t)0x07U) ///!< MPU Region Size 256 Bytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_512B ((uint8_t)0x08U) ///!< MPU Region Size 512 Bytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_1KB ((uint8_t)0x09U) ///!< MPU Region Size 1 KByte
|
||||||
|
#define ARM_MPU_REGION_SIZE_2KB ((uint8_t)0x0AU) ///!< MPU Region Size 2 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_4KB ((uint8_t)0x0BU) ///!< MPU Region Size 4 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_8KB ((uint8_t)0x0CU) ///!< MPU Region Size 8 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_16KB ((uint8_t)0x0DU) ///!< MPU Region Size 16 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_32KB ((uint8_t)0x0EU) ///!< MPU Region Size 32 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_64KB ((uint8_t)0x0FU) ///!< MPU Region Size 64 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_128KB ((uint8_t)0x10U) ///!< MPU Region Size 128 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_256KB ((uint8_t)0x11U) ///!< MPU Region Size 256 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_512KB ((uint8_t)0x12U) ///!< MPU Region Size 512 KBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_1MB ((uint8_t)0x13U) ///!< MPU Region Size 1 MByte
|
||||||
|
#define ARM_MPU_REGION_SIZE_2MB ((uint8_t)0x14U) ///!< MPU Region Size 2 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_4MB ((uint8_t)0x15U) ///!< MPU Region Size 4 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_8MB ((uint8_t)0x16U) ///!< MPU Region Size 8 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_16MB ((uint8_t)0x17U) ///!< MPU Region Size 16 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_32MB ((uint8_t)0x18U) ///!< MPU Region Size 32 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_64MB ((uint8_t)0x19U) ///!< MPU Region Size 64 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_128MB ((uint8_t)0x1AU) ///!< MPU Region Size 128 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_256MB ((uint8_t)0x1BU) ///!< MPU Region Size 256 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_512MB ((uint8_t)0x1CU) ///!< MPU Region Size 512 MBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_1GB ((uint8_t)0x1DU) ///!< MPU Region Size 1 GByte
|
||||||
|
#define ARM_MPU_REGION_SIZE_2GB ((uint8_t)0x1EU) ///!< MPU Region Size 2 GBytes
|
||||||
|
#define ARM_MPU_REGION_SIZE_4GB ((uint8_t)0x1FU) ///!< MPU Region Size 4 GBytes
|
||||||
|
|
||||||
|
#define ARM_MPU_AP_NONE 0U ///!< MPU Access Permission no access
|
||||||
|
#define ARM_MPU_AP_PRIV 1U ///!< MPU Access Permission privileged access only
|
||||||
|
#define ARM_MPU_AP_URO 2U ///!< MPU Access Permission unprivileged access read-only
|
||||||
|
#define ARM_MPU_AP_FULL 3U ///!< MPU Access Permission full access
|
||||||
|
#define ARM_MPU_AP_PRO 5U ///!< MPU Access Permission privileged access read-only
|
||||||
|
#define ARM_MPU_AP_RO 6U ///!< MPU Access Permission read-only access
|
||||||
|
|
||||||
|
/** MPU Region Base Address Register Value
|
||||||
|
*
|
||||||
|
* \param Region The region to be configured, number 0 to 15.
|
||||||
|
* \param BaseAddress The base address for the region.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_RBAR(Region, BaseAddress) \
|
||||||
|
(((BaseAddress) & MPU_RBAR_ADDR_Msk) | \
|
||||||
|
((Region) & MPU_RBAR_REGION_Msk) | \
|
||||||
|
(MPU_RBAR_VALID_Msk))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attributes
|
||||||
|
*
|
||||||
|
* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral.
|
||||||
|
* \param IsShareable Region is shareable between multiple bus masters.
|
||||||
|
* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache.
|
||||||
|
* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable) \
|
||||||
|
((((TypeExtField ) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk) | \
|
||||||
|
(((IsShareable ) << MPU_RASR_S_Pos) & MPU_RASR_S_Msk) | \
|
||||||
|
(((IsCacheable ) << MPU_RASR_C_Pos) & MPU_RASR_C_Msk) | \
|
||||||
|
(((IsBufferable ) << MPU_RASR_B_Pos) & MPU_RASR_B_Msk))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Region Attribute and Size Register Value
|
||||||
|
*
|
||||||
|
* \param DisableExec Instruction access disable bit, 1= disable instruction fetches.
|
||||||
|
* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode.
|
||||||
|
* \param AccessAttributes Memory access attribution, see \ref ARM_MPU_ACCESS_.
|
||||||
|
* \param SubRegionDisable Sub-region disable field.
|
||||||
|
* \param Size Region size of the region to be configured, for example 4K, 8K.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_RASR_EX(DisableExec, AccessPermission, AccessAttributes, SubRegionDisable, Size) \
|
||||||
|
((((DisableExec ) << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) | \
|
||||||
|
(((AccessPermission) << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) | \
|
||||||
|
(((AccessAttributes) ) & (MPU_RASR_TEX_Msk | MPU_RASR_S_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Region Attribute and Size Register Value
|
||||||
|
*
|
||||||
|
* \param DisableExec Instruction access disable bit, 1= disable instruction fetches.
|
||||||
|
* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode.
|
||||||
|
* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral.
|
||||||
|
* \param IsShareable Region is shareable between multiple bus masters.
|
||||||
|
* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache.
|
||||||
|
* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy.
|
||||||
|
* \param SubRegionDisable Sub-region disable field.
|
||||||
|
* \param Size Region size of the region to be configured, for example 4K, 8K.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) \
|
||||||
|
ARM_MPU_RASR_EX(DisableExec, AccessPermission, ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable), SubRegionDisable, Size)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attribute for strongly ordered memory.
|
||||||
|
* - TEX: 000b
|
||||||
|
* - Shareable
|
||||||
|
* - Non-cacheable
|
||||||
|
* - Non-bufferable
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_ACCESS_ORDERED ARM_MPU_ACCESS_(0U, 1U, 0U, 0U)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attribute for device memory.
|
||||||
|
* - TEX: 000b (if non-shareable) or 010b (if shareable)
|
||||||
|
* - Shareable or non-shareable
|
||||||
|
* - Non-cacheable
|
||||||
|
* - Bufferable (if shareable) or non-bufferable (if non-shareable)
|
||||||
|
*
|
||||||
|
* \param IsShareable Configures the device memory as shareable or non-shareable.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_ACCESS_DEVICE(IsShareable) ((IsShareable) ? ARM_MPU_ACCESS_(0U, 1U, 0U, 1U) : ARM_MPU_ACCESS_(2U, 0U, 0U, 0U))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attribute for normal memory.
|
||||||
|
* - TEX: 1BBb (reflecting outer cacheability rules)
|
||||||
|
* - Shareable or non-shareable
|
||||||
|
* - Cacheable or non-cacheable (reflecting inner cacheability rules)
|
||||||
|
* - Bufferable or non-bufferable (reflecting inner cacheability rules)
|
||||||
|
*
|
||||||
|
* \param OuterCp Configures the outer cache policy.
|
||||||
|
* \param InnerCp Configures the inner cache policy.
|
||||||
|
* \param IsShareable Configures the memory as shareable or non-shareable.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_ACCESS_NORMAL(OuterCp, InnerCp, IsShareable) ARM_MPU_ACCESS_((4U | (OuterCp)), IsShareable, ((InnerCp) & 2U), ((InnerCp) & 1U))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attribute non-cacheable policy.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_CACHEP_NOCACHE 0U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attribute write-back, write and read allocate policy.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_CACHEP_WB_WRA 1U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attribute write-through, no write allocate policy.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_CACHEP_WT_NWA 2U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MPU Memory Access Attribute write-back, no write allocate policy.
|
||||||
|
*/
|
||||||
|
#define ARM_MPU_CACHEP_WB_NWA 3U
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct for a single MPU Region
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t RBAR; //!< The region base address register value (RBAR)
|
||||||
|
uint32_t RASR; //!< The region attribute and size register value (RASR) \ref MPU_RASR
|
||||||
|
} ARM_MPU_Region_t;
|
||||||
|
|
||||||
|
/** Enable the MPU.
|
||||||
|
* \param MPU_Control Default access permissions for unconfigured regions.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control)
|
||||||
|
{
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
|
MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk;
|
||||||
|
#ifdef SCB_SHCSR_MEMFAULTENA_Msk
|
||||||
|
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Disable the MPU.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void ARM_MPU_Disable(void)
|
||||||
|
{
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
|
#ifdef SCB_SHCSR_MEMFAULTENA_Msk
|
||||||
|
SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
|
||||||
|
#endif
|
||||||
|
MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Clear and disable the given MPU region.
|
||||||
|
* \param rnr Region number to be cleared.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr)
|
||||||
|
{
|
||||||
|
MPU->RNR = rnr;
|
||||||
|
MPU->RASR = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Configure an MPU region.
|
||||||
|
* \param rbar Value for RBAR register.
|
||||||
|
* \param rsar Value for RSAR register.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rbar, uint32_t rasr)
|
||||||
|
{
|
||||||
|
MPU->RBAR = rbar;
|
||||||
|
MPU->RASR = rasr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Configure the given MPU region.
|
||||||
|
* \param rnr Region number to be configured.
|
||||||
|
* \param rbar Value for RBAR register.
|
||||||
|
* \param rsar Value for RSAR register.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void ARM_MPU_SetRegionEx(uint32_t rnr, uint32_t rbar, uint32_t rasr)
|
||||||
|
{
|
||||||
|
MPU->RNR = rnr;
|
||||||
|
MPU->RBAR = rbar;
|
||||||
|
MPU->RASR = rasr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Memcopy with strictly ordered memory access, e.g. for register targets.
|
||||||
|
* \param dst Destination data is copied to.
|
||||||
|
* \param src Source data is copied from.
|
||||||
|
* \param len Amount of data words to be copied.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void orderedCpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0U; i < len; ++i)
|
||||||
|
{
|
||||||
|
dst[i] = src[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Load the given number of MPU regions from a table.
|
||||||
|
* \param table Pointer to the MPU configuration table.
|
||||||
|
* \param cnt Amount of regions to be configured.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void ARM_MPU_Load(ARM_MPU_Region_t const* table, uint32_t cnt)
|
||||||
|
{
|
||||||
|
const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U;
|
||||||
|
while (cnt > MPU_TYPE_RALIASES) {
|
||||||
|
orderedCpy(&(MPU->RBAR), &(table->RBAR), MPU_TYPE_RALIASES*rowWordSize);
|
||||||
|
table += MPU_TYPE_RALIASES;
|
||||||
|
cnt -= MPU_TYPE_RALIASES;
|
||||||
|
}
|
||||||
|
orderedCpy(&(MPU->RBAR), &(table->RBAR), cnt*rowWordSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Loaded 100 of 273 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user