Compare commits

..
137 Commits
Author SHA1 Message Date
Sergey Lyubka 32406b678b Increase sntp test timeout 2021-07-22 23:03:20 +01:00
Sergey Lyubka 55e2077a46 Use mg_fopen only on win32 2021-07-22 22:46:33 +01:00
Sergey Lyubka a771d6a19d Add unicode filename 2021-07-22 20:16:50 +01:00
Sergey Lyubka 0d5d7bb26f Keep directory listing compile-time option 2021-07-21 11:05:27 +01:00
Sergey Lyubka 3808dd3222 Update issue template 2021-07-21 10:31:48 +01:00
Sergey Lyubka 8fc94e12af Add enable_dirlist to mg_http_serve_opts 2021-07-20 17:22:41 +01:00
Sergey Lyubka 824e33ef8a Merge pull request #1319 from ignacionr/patch-1
The sanitiser pointed out this problem
2021-07-20 16:46:30 +01:00
Sergey Lyubka 655f9a9f79 Add Content-Type header to the SSI files 2021-07-20 11:33:38 +01:00
Ignacio Rodríguez 6ac6aa521c The sanitiser pointed out this problem
And I believe it's right. Other-side-close should be done only for the 'A' (proxy-client-side) connection.
2021-07-20 00:04:05 -05:00
Sergey Lyubka 3982e065c8 Fix #1315, fix #1317 - use #ifndef instead of #pragma once for compilers that do not support #pragma once 2021-07-19 09:04:18 +01:00
Sergey Lyubka 497b8027f5 Fix #1314 - expose local port for listeners 2021-07-19 08:47:38 +01:00
Sergey Lyubka 89757388c7 Disable SSL v1.1 2021-07-16 12:10:48 +01:00
Sergey Lyubka 77fae5c562 Fix #1298 - shadowing struct mg_str constructor 2021-07-15 02:18:32 +01:00
Sergey Lyubka 80fcba91c8 Fix #1297 - %p warning 2021-07-14 04:00:27 +01:00
Sergey Lyubka 39d64be581 Fix FD_CLOEXEC setting 2021-07-13 22:49:36 +01:00
Sergey Lyubka 2bfd30ab4b Fix mac test 2021-07-13 20:49:19 +01:00
Sergey Lyubka 60004eb209 Fix mac test 2021-07-13 20:01:46 +01:00
Sergey Lyubka db11897d71 Fix #1302 - set FD_CLOEXEC on sockets 2021-07-13 19:32:31 +01:00
Sergey Lyubka 5e466f9037 Fix #1294 - add more common mime types 2021-07-13 19:24:46 +01:00
Sergey Lyubka 6b2698a503 Squash warning in mg_random() 2021-07-13 18:07:38 +01:00
Sergey Lyubka 4788db7e00 Fix #1301 - use correct openssl version conditional for SSL_use_certificate_chain_file() 2021-07-13 18:05:57 +01:00
Sergey Lyubka d9680df510 Support mbedtls 3.x.x 2021-07-13 17:28:07 +01:00
Sergey Lyubka f20ee1f305 Open HTTP and HTTPS ports 2021-07-13 14:40:52 +01:00
cpq 302bf865f9 Fix #1310 - wrap _CRT_SECURE_NO_WARNINGS into #ifndef 2021-07-13 07:13:06 +01:00
Sergey Lyubka 03929dcdaa Merge pull request #1306 from SimonNitzsche/patch-1
Fixed typo on README
2021-07-13 07:06:30 +01:00
cpq 89af2e9638 Merge branch 'master' of github.com:cesanta/mongoose 2021-07-13 06:58:52 +01:00
cpq 015586950f Fix #1305 - add #ifdef __cplusplus for C++ linkage 2021-07-13 06:58:34 +01:00
Simon Nitzsche 9df261a0eb Fixed typo on README
Added a dot to "etc" on the README
2021-07-04 17:40:18 +02:00
Sergey Lyubka a2a3c84450 Merge pull request #1303 from Jasper-Ben/master
Makefile: change curly brackets to round brackets
2021-07-02 18:28:53 +01:00
novlean 6611348ebf added customers references 2021-07-01 15:02:51 +01:00
Jasper Orschulko e69ee90acf Makefile: change curly brackets to round brackets
Esthetic change which replaces the curly brackets introduced by me in
commit b6ee9e637b with round brackets.
2021-06-30 21:46:58 +02:00
Sergey Lyubka 8f3554d08a Merge pull request #1295 from Jasper-Ben/add_linux_lib_targets
Add static and dynamic lib targets to Makefile
2021-06-21 11:35:43 +01:00
Jasper Orschulko b6ee9e637b Makefile: add static and dynamic lib targets 2021-06-21 11:51:42 +02:00
cpq f46453f80f Squash warnings 2021-06-10 19:37:03 +01:00
cpq 3deafaea7f Extend mg_mqtt_{pub,sub} by adding qos and retain 2021-06-10 19:27:19 +01:00
cpq a15d518571 Add mg_mqtt_pubex 2021-06-10 19:15:50 +01:00
cpq 886a29d659 Fix #1292 - allow requests with missing protocol version, responses with no reason fields 2021-05-29 10:07:05 +01:00
cpq e69de57def Optimise mg_iobuf_append() 2021-05-29 09:46:50 +01:00
cpq 9d68e20dcc Fix #1288 - better mg_iobuf_append allocation strategy 2021-05-29 09:44:07 +01:00
cpq c0a8546330 Add MG_ARCH_FREERTOS_LWIP 2021-05-28 23:49:26 +01:00
cpq 4c0002e28a Separate examples job 2021-05-28 19:05:10 +01:00
cpq 7c37d75bf4 Squash even more warnings 2021-05-28 18:57:47 +01:00
cpq 879261981f Squash more warnings 2021-05-28 18:54:39 +01:00
cpq 838b0bcd27 Squash more warnings 2021-05-28 18:45:35 +01:00
cpq 736b8ad7b7 Fix #1285 - __builtin___snprintf_chk warning. Tighten test flags and refactor the code to squash all warnings 2021-05-28 18:30:42 +01:00
cpq db27fae40e Update issue template 2021-05-24 10:18:44 +01:00
cpq 594111a255 Update issue template 2021-05-24 10:16:33 +01:00
cpq 53a46a2739 Change issue template 2021-05-24 09:53:39 +01:00
Sergey Lyubka eef7a55904 Merge pull request #1290 from lnksz/patch-1
Propose an issue template
2021-05-24 09:49:35 +01:00
Kristóf Havasi a68fa5e6e0 Propose an issue template
As it is in the discussion of raised issues to have some extra iteration because of architecture, library version, and other meta information, an issue template could save these extra rounds and possibly reduce the number of duplicates by highlighting where one can check for answers.

This is just a sketch based on what notifications I got from mongoose in the past months. Feel free to change it.
2021-05-23 22:44:16 +02:00
cpq 7c0d126edc Build with -DMG_ENABLE_FS=1 2021-05-19 08:10:38 +01:00
cpq 1a5e3d3151 Fix #1286 2021-05-19 00:19:21 +01:00
cpq 95ff6c56af Update readme 2021-05-19 00:15:45 +01:00
cpq e2ef392633 Update readme 2021-05-19 00:14:27 +01:00
cpq dbc2356768 FreeRTOS-Plus-TCP fixes 2021-05-19 00:00:32 +01:00
cpq 47e5e984df stm32f7 example starts on real h/w, with plus-TCP driver 2021-05-17 17:36:57 +01:00
cpq 0f32f50c50 Add missing files 2021-05-13 22:05:00 +01:00
cpq 606cc1f538 Build w/semihosting support 2021-05-13 22:04:29 +01:00
cpq 2bb11888d5 Build w/semihosting support 2021-05-13 22:03:46 +01:00
cpq 09b1d6aa72 Running two blinkers 2021-05-13 15:05:09 +01:00
cpq 72f0489ec2 Using nucleo-f746zg. Moved 3party libs to test/. Using headers from ST 2021-05-13 14:56:14 +01:00
cpq 7b39973065 docs 2021-05-12 11:44:15 +01:00
cpq 30b64483fd docs 2021-05-12 11:39:46 +01:00
cpq 5369fb0376 Remove low-level lwip stubs 2021-05-12 11:06:19 +01:00
cpq 5fe34fd6c3 Remove MG_ENABLE_MGOS 2021-05-12 11:05:05 +01:00
Sergey Lyubka 0fbdda4d2e Merge pull request #1284 from cesanta/stm32
Stm32
2021-05-12 10:28:43 +01:00
cpq a98e980c8f Nits to have tests pass 2021-05-12 09:25:21 +01:00
cpq 2b836504ab rename 2021-05-12 08:44:16 +01:00
cpq 0de3f0d985 f1 build works 2021-05-12 08:43:34 +01:00
cpq 151e375091 FreeRTOS w/blink works 2021-05-11 20:44:14 +01:00
cpq c44549bfa5 Blinky works 2021-05-11 18:05:03 +01:00
cpq d6852f5e74 First stab 2021-05-11 09:12:06 +01:00
novlean 9173034b96 Update README.md 2021-05-04 17:03:53 +01:00
novlean 2888ab1f52 Merge pull request #1277 from cesanta/novlean-patch-1
more typos + some fixes
2021-05-04 17:02:55 +01:00
novlean 26b5416641 more typos + some fixes 2021-05-04 17:02:46 +01:00
novlean 8bcac7e955 Merge pull request #1276 from cesanta/novlean-patch-1
fixed typo + added few things
2021-05-04 16:54:28 +01:00
novlean ea25e8129c fixed typo + added few things 2021-05-04 16:54:16 +01:00
cpq 26cb44f9d9 Typo in readme 2021-05-04 13:55:45 +01:00
cpq 7a37a44433 Update README 2021-05-04 13:53:17 +01:00
cpq a752f3f8c7 Update README 2021-05-04 13:46:44 +01:00
Sergey Lyubka 946e07644c Merge pull request #1275 from panosto/master
Corrected small typo in docs
2021-04-29 19:26:46 +01:00
Panagiotis 497b26a249 Corrected small typo in docs 2021-04-29 18:16:33 +02:00
cpq 79aad7fabf Put Range support back 2021-04-29 11:00:57 +01:00
cpq 7851930ac3 Fix #1256 2021-04-29 09:50:33 +01:00
cpq 758572872d Fix #1255 2021-04-29 09:26:37 +01:00
cpq 111551477a Integrate #1266 2021-04-29 09:17:24 +01:00
cpq 31c9e3fb7e Make mg_random() weak, see #1269 2021-04-29 09:09:21 +01:00
cpq 7061b7202f Integrate 1265 2021-04-29 08:49:23 +01:00
novlean d88b6a3c95 Update README.md 2021-04-28 17:07:39 +01:00
novlean cea2a62ee0 Added Schneider Electric case study & testimonial 2021-04-28 17:06:27 +01:00
cpq 35a8b8e8e8 TLS nits, more DNS logging 2021-04-22 15:21:16 +01:00
cpq 1b8624f135 Better log trace 2021-04-13 21:02:05 +01:00
cpq e217066bf6 Squash warning 2021-04-13 19:42:47 +01:00
cpq 5430408218 Merge branch 'master' of github.com:cesanta/mongoose 2021-04-09 16:55:16 +01:00
cpq d2744063a0 Remove unused MG_SWAPxx macros 2021-04-09 16:55:12 +01:00
Sergey Lyubka 03356616ef Merge pull request #1259 from mcottrell1/fix-msvc-compile-errors
fixed msvc errors around VLAs when using TLS
2021-04-09 16:54:23 +01:00
Mark Cottrell 6ce2e48dd3 fixed msvc errors around VLAs 2021-04-09 08:11:16 -07:00
novlean 16a7ba6bf0 Added 4 new sections
Why Mongoose
Used to implement
Case Studies
Testimonials
2021-03-25 17:50:56 +00:00
cpq e9d122f231 Stricter checks for mg_url_*() 2021-03-24 15:49:35 +00:00
cpq 0ae5c61759 More comments 2021-03-23 14:02:24 +00:00
cpq 691460c5fc Add linux target to http-server example 2021-03-22 11:30:48 +00:00
cpq ab1c924388 Better check in mg_iobuf_resize() 2021-03-22 11:30:29 +00:00
cpq 05050eba38 Squash warning in mg_random 2021-03-22 11:29:59 +00:00
cpq 912dd518bf Tests for mg_to64() 2021-03-21 16:18:44 +00:00
cpq e0395a9907 Merge branch 'master' of github.com:cesanta/mongoose 2021-03-21 16:14:56 +00:00
cpq 0051f23e12 Even stricted check in mg_to64() 2021-03-21 16:14:44 +00:00
novlean a9bb8fa9fc Update README.md 2021-03-19 14:02:23 +00:00
novlean 09f5d2fdae Merge pull request #1247 from cesanta/novlean-patch-1
added video call offer
2021-03-19 14:01:45 +00:00
novlean 006a9d914c added video call offer 2021-03-19 14:01:30 +00:00
cpq 9009cbc528 Adjust recv.len after stripping chunked body 2021-03-19 13:13:24 +00:00
cpq a1862986b8 Better docstring for file upload example 2021-03-18 12:23:03 +00:00
cpq cc2989a848 Merge branch 'master' of github.com:cesanta/mongoose 2021-03-18 12:01:32 +00:00
cpq 4deb95776f Remove multipart example code 2021-03-18 11:59:23 +00:00
Sergey Lyubka f195b27884 Merge pull request #1245 from panosto/mbedtls_parse_crt_and_key_from_buffer
mbedtls parse cert and key from buffer
2021-03-18 08:51:04 +00:00
panosto 5036a71334 mbedtls parse cert and key from buffer 2021-03-17 15:23:45 +01:00
cpq 531c47b47c mg_to64 overflow protection 2021-03-17 13:46:50 +00:00
cpq 4dbb2da78f Add form-upload example 2021-03-17 13:28:36 +00:00
cpq 41c1e0f08d Squash truncation warning 2021-03-17 12:22:19 +00:00
cpq e7b1905e49 Add -Wno-error=format-truncation for test++ build 2021-03-17 12:15:46 +00:00
cpq e00265f855 Add -Wno-error=format-truncation for linux++ build 2021-03-17 12:11:05 +00:00
cpq cd36708b6d Fix tests 2021-03-17 07:46:39 +00:00
cpq 5bd22cb5e4 Add mg_http_next_multipart() 2021-03-17 07:43:29 +00:00
cpq bc00d5159a Add mg_http_next_part 2021-03-15 13:20:53 +00:00
cpq bcb0874477 Add file upload code example 2021-03-15 09:36:27 +00:00
cpq 5326e8d212 Update docs 2021-03-15 09:18:02 +00:00
cpq 4528cc28ef Add sizep param to mg_file_read() 2021-03-15 09:16:34 +00:00
cpq 381d7cce54 Do not call setsockopts() on a listening connection 2021-03-13 12:36:00 +00:00
cpq 2594e7b37a Stricter MG_ARCH_CUSTOM and type conversions in sock.c 2021-03-13 12:34:26 +00:00
Sergey Lyubka 4356b953ca Merge pull request #1238 from cesanta/novlean-patch-1
Fixed typos
2021-03-11 13:16:06 +00:00
cpq e788853156 Fix typos 2021-03-11 13:15:53 +00:00
novlean 91ed6de166 Fixed typos 2021-03-11 13:01:45 +00:00
novlean cf3aafc32e added . 2021-03-11 10:16:17 +00:00
cpq c2d7ff8179 Update readme 2021-03-10 13:44:32 +00:00
cpq e5eaa1c633 Update readme 2021-03-10 13:42:46 +00:00
cpq 6366c832b0 Add struct mg_http_serve_opts::extra_headers 2021-03-10 07:56:14 +00:00
cpq f326cbedbe Fix doc example 2021-03-09 17:44:15 +00:00
cpq 5b272c2b5c Bump HEAD to 7.3 2021-03-09 11:38:37 +00:00
174 changed files with 86283 additions and 1958 deletions

No files matched your search

+11
View File
@@ -0,0 +1,11 @@
- My goal is: _describe_
- My actions were: _describe_
- My expectation was: _describe_
- The result I saw: _provide logs or description_
- My question is: _your question_
# Environment
- mongoose version: _X.Y_
- OS: _?_
- Compiler/IDE: _?_
+13 -2
View File
@@ -11,6 +11,12 @@ jobs:
run: make test test++ IPV6=0 run: make test test++ IPV6=0
- name: openssl - name: openssl
run: make test SSL=OPENSSL IPV6=0 run: make test SSL=OPENSSL IPV6=0
examples:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install packages
run: sudo apt-get install libmbedtls-dev
- name: examples - name: examples
run: make ex run: make ex
macos: macos:
@@ -22,7 +28,7 @@ jobs:
- name: make - name: make
run: make test++ upload-coverage IPV6=0 run: make test++ upload-coverage IPV6=0
- name: openssl - name: openssl
run: make test SSL=OPENSSL IPV6=0 run: make test SSL=OPENSSL IPV6=0 OPENSSL=`echo /usr/local/Cellar/openssl*/*`
- name: exports - name: exports
run: make mg_prefix run: make mg_prefix
windows: windows:
@@ -37,4 +43,9 @@ jobs:
run: make mingw run: make mingw
- name: mingw++ - name: mingw++
run: make mingw++ run: make mingw++
arm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: arm
run: make arm
+31 -12
View File
@@ -1,32 +1,34 @@
SRCS = $(wildcard src/*.c) SRCS = $(wildcard src/*.c)
HDRS = $(wildcard src/*.h) HDRS = $(wildcard src/*.h)
DEFS ?= -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES -DMG_ENABLE_DIRECTORY_LISTING=1 -DMG_ENABLE_SSI=1 DEFS ?= -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES -DMG_ENABLE_DIRECTORY_LISTING=1 -DMG_ENABLE_SSI=1
CFLAGS ?= -W -Wall -Werror -Isrc -I. -O0 -g $(DEFS) $(TFLAGS) $(EXTRA) WARN ?= -W -Wall -Werror -Wshadow -Wdouble-promotion -fno-common -Wconversion
OPTS ?= -O3 -g3
INCS ?= -Isrc -I.
CFLAGS ?= $(OPTS) $(WARN) $(INCS) $(DEFS) $(TFLAGS) $(EXTRA)
SSL ?= MBEDTLS SSL ?= MBEDTLS
CDIR ?= $(realpath $(CURDIR)) CDIR ?= $(realpath $(CURDIR))
VC98 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/vc98 VC98 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/vc98
VC2017 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/vc2017 VC2017 = docker run --rm -e WINEDEBUG=-all -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/vc2017
MINGW = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/mingw MINGW = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/mingw
GCC = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) mdashnet/cc2 GCC = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) mdashnet/cc2
ARM = docker run -v $(CDIR):$(CDIR) -w $(CDIR) mdashnet/armgcc
VCFLAGS = /nologo /W3 /O2 /I. $(DEFS) $(TFLAGS) VCFLAGS = /nologo /W3 /O2 /I. $(DEFS) $(TFLAGS)
CLANG ?= clang # /usr/local/opt/llvm\@9/bin/clang CLANG ?= clang # /usr/local/opt/llvm\@9/bin/clang
IPV6 ?= 1 IPV6 ?= 1
ASAN_OPTIONS ?= ASAN_OPTIONS ?=
EXAMPLES := $(wildcard examples/*) EXAMPLES := $(wildcard examples/*)
EXAMPLE_TARGET ?= example EXAMPLE_TARGET ?= example
PREFIX ?= /usr/local
SOVERSION = 7.2
.PHONY: ex test .PHONY: ex test
ifeq "$(SSL)" "MBEDTLS" ifeq "$(SSL)" "MBEDTLS"
MBEDTLS_DIR ?= $(shell brew --cellar mbedtls) MBEDTLS ?= /usr
MBEDTLS_VER ?= $(shell brew info mbedtls --json | jq -j .[0].installed[0].version)
MBEDTLS ?= $(MBEDTLS_DIR)/$(MBEDTLS_VER)
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_DIR ?= $(shell brew --cellar openssl) OPENSSL ?= /usr
OPENSSL_VER ?= $(shell brew info openssl --json | jq -j .[0].installed[0].version)
OPENSSL ?= $(OPENSSL_DIR)/$(OPENSSL_VER)
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
@@ -41,13 +43,13 @@ mg_prefix: mongoose.c mongoose.h
$(CLANG) mongoose.c $(CFLAGS) -c -o /tmp/x.o && nm /tmp/x.o | grep ' T' | grep -v 'mg_' ; test $$? = 1 $(CLANG) mongoose.c $(CFLAGS) -c -o /tmp/x.o && nm /tmp/x.o | grep ' T' | grep -v 'mg_' ; test $$? = 1
# C++ build # C++ build
test++: CLANG = g++ -Wno-deprecated -Wno-missing-field-initializers test++: CLANG = g++
test++: unamalgamated test++: WARN += -Wno-shadow -Wno-missing-field-initializers -Wno-deprecated
test++: test
# Make sure we can build from an unamalgamated sources # Make sure we can build from an unamalgamated sources
unamalgamated: $(SRCS) $(HDRS) Makefile unamalgamated: $(SRCS) $(HDRS) Makefile
$(CLANG) src/*.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -g -o unit_test $(CLANG) src/*.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -g -o unit_test
fuzz: mongoose.c mongoose.h Makefile test/fuzz.c fuzz: mongoose.c mongoose.h Makefile test/fuzz.c
$(CLANG) mongoose.c test/fuzz.c $(CFLAGS) -DMG_ENABLE_LINES -DMG_ENABLE_LOG=0 -fsanitize=fuzzer,signed-integer-overflow,address $(LDFLAGS) -g -o fuzzer $(CLANG) mongoose.c test/fuzz.c $(CFLAGS) -DMG_ENABLE_LINES -DMG_ENABLE_LOG=0 -fsanitize=fuzzer,signed-integer-overflow,address $(LDFLAGS) -g -o fuzzer
$(DEBUGGER) ./fuzzer $(DEBUGGER) ./fuzzer
@@ -92,14 +94,31 @@ linux: Makefile mongoose.c mongoose.h test/unit_test.c
$(GCC) $(CC) mongoose.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -o unit_test_gcc $(GCC) $(CC) mongoose.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -o unit_test_gcc
$(GCC) ./unit_test_gcc $(GCC) ./unit_test_gcc
linux++: CC = g++ -Wno-missing-field-initializers linux++: CC = g++
linux++: WARN += -Wno-missing-field-initializers
linux++: linux linux++: linux
linux-libs: CFLAGS += -fPIC
linux-libs: mongoose.o
$(CC) mongoose.o $(LDFLAGS) -shared -o libmongoose.so.$(SOVERSION)
$(AR) rcs libmongoose.a mongoose.o
install: linux-libs
install -Dm644 libmongoose.a libmongoose.so.$(SOVERSION) $(DESTDIR)$(PREFIX)/lib
ln -s libmongoose.so.$(SOVERSION) $(DESTDIR)$(PREFIX)/lib/libmongoose.so
install -Dm644 mongoose.h $(DESTDIR)$(PREFIX)/include/mongoose.h
uninstall:
rm -rf $(DESTDIR)$(PREFIX)/lib/libmongoose.a $(DESTDIR)$(PREFIX)/lib/libmongoose.so.$(SOVERSION) $(DESTDIR)$(PREFIX)/include/mongoose.h $(DESTDIR)$(PREFIX)/lib/libmongoose.so
arm: Makefile mongoose.c mongoose.h test/unit_test.c
$(ARM) arm-none-eabi-gcc mongoose.c -c -Itest -DMG_ARCH=MG_ARCH_CUSTOM $(OPTS) $(WARN) $(INCS) -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES -DMG_ENABLE_DIRECTORY_LISTING=0 -DMG_ENABLE_SSI=1
mongoose.c: $(SRCS) Makefile mongoose.c: $(SRCS) Makefile
(cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/private.h src/*.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/private.h src/*.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 src/version.h ; cat src/arch.h src/arch_*.h src/config.h src/str.h src/log.h src/timer.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/ws.h src/sntp.h src/mqtt.h src/dns.h | sed -e 's,#include ".*,,' -e 's,^#pragma once,,')> $@ (cat src/license.h src/version.h ; cat src/arch.h src/arch_*.h src/config.h src/str.h src/log.h src/timer.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/ws.h src/sntp.h src/mqtt.h src/dns.h | sed -e 's,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
clean: EXAMPLE_TARGET = clean clean: EXAMPLE_TARGET = clean
clean: ex clean: ex
+67 -49
View File
@@ -1,75 +1,93 @@
# Mongoose - Embedded Web Server / Embedded Networking Library # Mongoose - Embedded Web Server / Embedded Networking Library
![License: GPLv2](https://img.shields.io/badge/license-GPL_2-green.svg "License") [![License: GPLv2/Commercial](https://img.shields.io/badge/License-GPLv2%20or%20Commercial-green.svg)](https://opensource.org/licenses/gpl-2.0.php)
[![Build Status]( https://github.com/cesanta/mongoose/workflows/build/badge.svg)](https://github.com/cesanta/mongoose/actions) [![Build Status]( https://github.com/cesanta/mongoose/workflows/build/badge.svg)](https://github.com/cesanta/mongoose/actions)
[![Code Coverage](https://codecov.io/gh/cesanta/mongoose/branch/master/graph/badge.svg)](https://codecov.io/gh/cesanta/mongoose) [![Code Coverage](https://codecov.io/gh/cesanta/mongoose/branch/master/graph/badge.svg)](https://codecov.io/gh/cesanta/mongoose)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/mongoose.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:mongoose) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/mongoose.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:mongoose)
Mongoose is a networking library for C/C++. It implements event-driven Mongoose is a networking library for C/C++. It implements event-driven
non-blocking APIs for TCP, UDP, HTTP, WebSocket, MQTT. It has been designed non-blocking APIs for TCP, UDP, HTTP, WebSocket, MQTT. It is designed for
for connecting devices and bringing them online. On the market since 2004, used connecting devices and bringing them online. On the market since 2004, used by
by vast number of open source and commercial products - it even runs on the vast number of open source and commercial products - it even runs on the
International Space Station! Mongoose makes embedded network programming fast, International Space Station! Mongoose makes embedded network programming fast,
robust, and easy. robust, and easy. Features include:
- [Download Mongoose Source Code here](https://www.cesanta.com/download.html) - Cross-platform: works on Linux/UNIX, MacOS, Windows, Android, FreeRTOS, etc.
- [Read Mongoose documentation](https://cesanta.com/docs/) - Supported embedded architectures: ESP32, NRF52, STM32, NXP, and more
- Built-in protocols: plain TCP/UDP, HTTP, MQTT, Websocket
- SSL/TLS support: mbedTLS, OpenSSL or custom (via API)
- Asynchronous DNS resolver
- Tiny static and run-time footprint
- Source code is both ISO C and ISO C++ compliant
- 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
- Detailed [documentation](https://cesanta.com/docs/)
Connectivity is vital for software and embedded devices, but there are many
pitfalls to consider when embedding a web server. This white paper breaks down
on the top 9 things to avoid when embedding a web server.
- [Download “9 Things NOT to do when embedding a web server” white paper here](https://www.cesanta.com/whitepaper.html) # Commercial use
- Mongoose is used by hundreds of businesses, from Fortune500 giants like
Siemens, Schneider Electric, Broadcom, Bosch, Google, Samsung, Qualcomm, Caterpillar to the small businesses
- Used to solve a wide range of business needs, like implementing Web UI
interface on devices, RESTful API services, telemetry data exchange, remote
control for a product, remote software updates, remote monitoring, and others
- Deployed to hundreds of millions devices in production environment worldwide
- See [Case Studies](https://cesanta.com/case-studies.html) from our respected
customers like Schneider Electric (industrial automation), Broadcom (semiconductors), Schenck Process
(industrial engineering), and others
- See [Testimonials](https://cesanta.com/testimonials.html) from engineers that
integrated Mongoose in their commercial products
- We provide [commercial licensing](https://cesanta.com/licensing.html),
[support](https://cesanta.com/support.html), consultancy and integration
assistance - don't hesitate to
[contact us](https://www.cesanta.com/contact.html)
# Looking for a pre-compiled Mongoose web server Windows or Mac binary?
- [Download pre-compiled Mongoose web server binary](https://mongoose.ws/)
# Looking for a complete IoT solution? Check out # Security
- [VCON](https://vcon.io) - Arduino compatible MCU modules with built-in firmware OTA updates
- [Mongoose OS](https://mongoose-os.com) - open source embedded operating system for low-power connected microcontrollers. Secure, designed for commercial Internet of Things products
# Support We take security seriously:
- [Study Mongoose examples](https://github.com/cesanta/mongoose/tree/master/examples) 1. Mongoose repository runs a
- [Support Forum - ask your technical questions here](https://forum.cesanta.com/c/mongoose-library/6) [continuous integration test powered by GitHub](https://github.com/cesanta/mongoose/actions),
- [Commercial licensing and support available](https://www.cesanta.com/licensing.html) which runs through hundreds of unit tests on every commit to the repository.
- [Check out latest releases](https://github.com/cesanta/mongoose/releases) Our [unit tests](https://github.com/cesanta/mongoose/tree/master/test)
are built with modern address sanitizer technologies, which help to find
security vulnerabilities early
2. Mongoose repository is integrated into Google's
[oss-fuzz continuous fuzzer](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:mongoose)
which scans for potential vulnerabilities continuously
3. We receive periodic vulnerability reports from the independent security
groups like
[Cisco Talos](https://www.cisco.com/c/en/us/products/security/talos.html),
[Microsoft Security Response Center](https://www.microsoft.com/en-us/msrc),
[MITRE Corporation](https://www.mitre.org/),
[Compass Security](https://www.compass-security.com/en/) and others.
In case of the vulnerability found, we act according to the industry best
practice: hold on to the publication, fix the software and notify all our
customers that have an appropriate subscription
4. Some of our customers (for example NASA)
have specific security requirements and run independent security audits,
of which we get notified and in case of any issue, act similar to (3).
# Features # Supplement software
* Cross-platform: works on Linux/UNIX, MacOS, Windows, Android, FreeRTOS, etc This software is often used together with Mongoose:
* Supported embedded architectures: ESP32, ESP8266, TI, NRF52, STM32, PIC32, NXP, and more - [mjson](https://github.com/cesanta/mjson) - a JSON parser. Used to implement
* Builtin protocols: plain TCP/UDP, HTTP, MQTT, Websocket RESTful APIs that use JSON, or implement data exchange (e.g. over MQTT
* SSL/TLS support: mbedTLS, OpenSSL or custom (via API) or Websocket) that use JSON for data encapsulation
* Asynchronous DNS resolver - [elk](https://github.com/cesanta/elk) - a tiny JavaScript interpreter.
* Tiny static and run-time footprint Used to implement scripting support for customers
* Source code is both ISO C and ISO C++ compliant
* Very easy to integrate: just copy
[mongoose.c](https://raw.githubusercontent.com/cesanta/mongoose/master/mongoose.c) and
[mongoose.h](https://raw.githubusercontent.com/cesanta/mongoose/master/mongoose.h)
files to your build tree
# Licensing
Mongoose is released under Commercial and [GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) open source licenses. # Precompiled web server binary
Commercial Projects: [Contact us for commercial license.](https://www.cesanta.com/contact.html) We have built a ready-to-go, precompiled web server binary for Windows
and Mac. It is a great tool for sharing your files or website. It has
a unique feature - an ability to share your local files via a global URL.
# Dashboard Example Interested? Go to [download](https://mongoose.ws/)
Mongoose is often used to implement device dashboards and real-time
data exchange over Websocket. Here is a dashboard example that illustrates
the functionality:
![](http://www.cesanta.com/images/dashboard.png)
[Developing a new product? Contact us today to discuss how Mongoose can help.](https://www.cesanta.com/contact.html)
# Contributions # Contributions
Contributions are welcome! Please follow the guidelines below: Contributions are welcome! Please follow the guidelines below:
- Sign [Cesanta CLA](https://cesanta.com/cla.html) and send GitHub pull request - Sign [Cesanta CLA](https://cesanta.com/cla.html) and send GitHub pull request
- When making pull requests, please make sure that it has only one commit, - Make sure that PRs have only one commit, and deal with one issue only
and imlements/fixes only one piece of functionality
+123 -77
View File
@@ -6,24 +6,23 @@
Mongoose is a networking library for C/C++. It implements an event-driven, Mongoose is a networking library for C/C++. It implements an event-driven,
non-blocking APIs for TCP, UDP, HTTP, WebSocket, MQTT. It has been designed non-blocking APIs for TCP, UDP, HTTP, WebSocket, MQTT. It has been designed
for connecting devices and bringing them online. On the market since 2004, used for connecting devices and bringing them online. On the market since 2004, used
by vast number of open source and commercial products - it even runs on the by a vast number of open source and commercial products - it even runs on the
International Space Station! Mongoose makes embedded network programming fast, International Space Station! Mongoose makes embedded network programming fast,
robust, and easy. robust, and easy.
## Features ## Features
* Cross-platform: works on Linux/UNIX, MacOS, QNX, eCos, Windows, Android, * Works on Linux/UNIX, MacOS, Windows, QNX, eCos, Android and other
iPhone, FreeRTOS, etc * Works on embedded hardware: STM32, ESP32, NXP, Xilinx, and other
* Supported hardware platforms: TI CC3200, TI MSP432, NRF52, STM32, PIC32, ESP8266, ESP32 and more * Built-in protocols:
* Builtin protocols:
- plain TCP, plain UDP, SSL/TLS (over TCP, one-way or two-way) - plain TCP, plain UDP, SSL/TLS (over TCP, one-way or two-way)
- HTTP client, HTTP server - HTTP client, HTTP server
- WebSocket client, WebSocket server - WebSocket client, WebSocket server
- MQTT client - MQTT client, MQTT server
- DNS client, async DNS resolver - DNS client, async DNS resolver
* Single-threaded, asynchronous, non-blocking core with simple event-based API * Single-threaded, asynchronous, non-blocking core with simple event-based API
* Native support for [LWIP embedded TCP/IP stack](https://en.wikipedia.org/wiki/LwIP) * Support for LWIP and FreeRTOS-Plus-TCP stacks
* Tiny static and run-time footprint * Tiny static and run-time footprint
* Source code is both ISO C and ISO C++ compliant * Source code is both ISO C and ISO C++ compliant
* Very easy to integrate: just copy * Very easy to integrate: just copy
@@ -50,7 +49,7 @@ Mongoose's internals.
An application that uses mongoose should follow a standard pattern of An application that uses mongoose should follow a standard pattern of
event-driven application: event-driven application:
1. Declare and initialise an event manager: 1. Declare and initialize an event manager:
```c ```c
struct mg_mgr mgr; struct mg_mgr mgr;
@@ -90,7 +89,7 @@ Each connection has a send and receive buffer:
- `struct mg_connection::recv` - data received from a peer - `struct mg_connection::recv` - data received from a peer
When data arrives, Mongoose appends received data to the `recv` and triggers an When data arrives, Mongoose appends received data to the `recv` and triggers an
`MG_EV_RECV` event. The user may send data back by calling one of the output `MG_EV_READ` event. The user may send data back by calling one of the output
functions, like `mg_send()` or `mg_printf()`. Output functions append data to functions, like `mg_send()` or `mg_printf()`. Output functions append data to
the `send` buffer. When Mongoose successfully writes data to the socket, it the `send` buffer. When Mongoose successfully writes data to the socket, it
discards data from struct `mg_connection::send` and sends an `MG_EV_SEND` discards data from struct `mg_connection::send` and sends an `MG_EV_SEND`
@@ -106,7 +105,7 @@ what an event handler function looks like:
```c ```c
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) {
switch (ev) { switch (ev) {
/* Event handler code that defines behavior of the connection */ /* Event handler code that defines behaviour of the connection */
... ...
} }
} }
@@ -114,9 +113,9 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
- `struct mg_connection *c` - a connection that received an event - `struct mg_connection *c` - a connection that received an event
- `int ev` - an event number, defined in mongoose.h. For example, when data - `int ev` - an event number, defined in mongoose.h. For example, when data
arrives on an inbound connection, ev would be `MG_EV_RECV` arrives on an inbound connection, ev would be `MG_EV_READ`
- `void *ev_data` - points to the event-specific data, and it has a different - `void *ev_data` - points to the event-specific data, and it has a different
meaning for different events. For example, for an `MG_EV_RECV` event, meaning for different events. For example, for an `MG_EV_READ` event,
`ev_data` `ev_data`
is an `int *` pointing to the number of bytes received from a remote is an `int *` pointing to the number of bytes received from a remote
peer and saved into the `c->recv` IO buffer. The exact meaning of `ev_data` is peer and saved into the `c->recv` IO buffer. The exact meaning of `ev_data` is
@@ -127,7 +126,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
## Events ## Events
Below is the list of events trigged by Mongoose, taken as-is from `mongoose.h`. Below is the list of events triggered by Mongoose, taken as-is from `mongoose.h`.
For each event, a comment describes a meaning of the `ev_data` pointer passed For each event, a comment describes a meaning of the `ev_data` pointer passed
to an event handler: to an event handler:
@@ -193,41 +192,62 @@ Mongoose source code ships in two files:
- [mongoose.c](https://github.com/cesanta/mongoose/blob/master/mongoose.c) - implementation - [mongoose.c](https://github.com/cesanta/mongoose/blob/master/mongoose.c) - implementation
Therefore to integrate Mongoose into an application, simply copy these two Therefore to integrate Mongoose into an application, simply copy these two
files to the application's source tree. files to the application's source tree. The `mongoose.c` and `mongoose.h` files
are, actually, an amalgamation - a non-amalgamated sources can be found at
https://github.com/cesanta/mongoose/tree/master/src
The `mongoose.c` and `mongoose.h` files are, actually, an amalgamation - Mongoose have two types of build constants (preprocessor definitions) that
a non-amalgamated sources can be found at https://github.com/cesanta/mongoose/tree/master/src affect the build: a target architecture, and tunables. In order to set the
option during build time, use the `-D OPTION` compiler flag:
Mongoose source code uses a bunch of build constants defined at
https://github.com/cesanta/mongoose/blob/master/src/config.h, together with
their default values.
In order to change the constant during build time, use the `-D
<PREPROCESSOR_FLAG>` compiler option. For example, to disable both MQTT,
compile the application `my_app.c` like this (assumed UNIX system):
```sh ```sh
$ cc my_app.c mongoose.c -D MG_MQTT_ENABLE=0 $ cc app0.c mongoose.c # Use defaults!
$ cc app1.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 app3.c mongoose.c -D MG_ENABLE_FS=0 -D MG_ENABLE_LOG=0 # Multiple options
``` ```
The list of supported
architectures is defined in the
[arch.h](https://github.com/cesanta/mongoose/blob/master/src/arch.h) header
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 |
| ---- | ----------- |
|MG_ARCH_UNIX | All UNIX-like systems like Linux, MacOS, FreeBSD, etc |
|MG_ARCH_WIN32 | Windows systems |
|MG_ARCH_ESP32 | Espressif's ESP32 |
|MG_ARCH_ESP8266 | Espressif's ESP8266 |
|MG_ARCH_FREERTOS_LWIP | All systems with FreeRTOS kernel and LwIP IP stack |
|MG_ARCH_FREERTOS_TCP | All systems with FreeRTOS kernel and FreeRTOS-Plus-TCP IP stack |
|MG_ARCH_CUSTOM | A custom architecture, discussed in the next section |
The other class of build constants is defined in
[src/config.h](https://github.com/cesanta/mongoose/blob/master/src/config.h)
together with their default values. They are tunables that include/exclude
a certain functionality or change relevant parameters.
Here is a list of build constants and their default values: Here is a list of build constants and their default values:
| Name | Default | Description | | Name | Default | Description |
| ---- | ------- | ----------- | | ---- | ------- | ----------- |
|`MG_ENABLE_LWIP` | 0 | Use LWIP low-level API instead of BSD sockets | |MG_ENABLE_SOCKET | 1 | Use BSD socket low-level API |
|`MG_ENABLE_SOCKET` | 1 | Use BSD socket low-level API | |MG_ENABLE_MBEDTLS | 0 | Enable Mbed TLS library |
|`MG_ENABLE_MBEDTLS` | 0 | Enable Mbed TLS library | |MG_ENABLE_OPENSSL | 0 | Enable OpenSSL library |
|`MG_ENABLE_OPENSSL` | 0 | Enable OpenSSL library | |MG_ENABLE_FS | 1 | Enable API that use filesystem, like `mg_http_send_file()` |
|`MG_ENABLE_FS` | 1 | Enable API that use filesystem, like `mg_http_send_file()` | |MG_ENABLE_IPV6 | 0 | Enable IPv6 |
|`MG_ENABLE_IPV6` | 0 | Enable IPv6 | |MG_ENABLE_LOG | 1 | Enable `LOG()` macro |
|`MG_ENABLE_LOG` | 1 | Enable `LOG()` macro | |MG_ENABLE_MD5 | 0 | Use native MD5 implementation |
|`MG_ENABLE_MD5` | 0 | Use native MD5 implementation | |MG_ENABLE_DIRECTORY_LISTING | 0 | Enable directory listing for HTTP server |
|`MG_ENABLE_DIRECTORY_LISTING` | 0 | Enable directory listing for HTTP server | |MG_ENABLE_SOCKETPAIR | 0 | Enable `mg_socketpair()` for multi-threading |
|`MG_ENABLE_SOCKETPAIR` | 0 | Enable `mg_socketpair()` for multi-threading | |MG_ENABLE_SSI | 0 | Enable serving SSI files by `mg_http_serve_dir()` |
|`MG_ENABLE_SSI` | 0 | Enable serving SSI files by `mg_http_serve_dir()` | |MG_IO_SIZE | 512 | Granularity of the send/recv IO buffer growth |
|`MG_IO_SIZE` | 512 | Granularity of the send/recv IO buffer growth | |MG_MAX_RECV_BUF_SIZE | (3 * 1024 * 1024) | Maximum recv buffer size |
|`MG_MAX_RECV_BUF_SIZE` | (3 * 1024 * 1024) | Maximum recv buffer size | |MG_MAX_HTTP_HEADERS | 40 | Maximum number of HTTP headers |
|`MG_MAX_HTTP_HEADERS` | 40 | Maximum number of HTTP headers |
NOTE: `MG_IO_SIZE` controls the maximum UDP message size, see NOTE: `MG_IO_SIZE` controls the maximum UDP message size, see
https://github.com/cesanta/mongoose/issues/907 for details. If application https://github.com/cesanta/mongoose/issues/907 for details. If application
@@ -235,25 +255,27 @@ uses large UDP messages, increase the `MG_IO_SIZE` limit accordingly.
## Custom build ## Custom build
It is possible to use Mongoose on an architecture that is not yet supported A custom build should be used for cases which is not covered by the
by the current codebase. In order to do so, follow these steps: existing architecture options. For example, an embedded architecture that
uses some proprietary RTOS and network stack. In order to build on such
systems, follow the guideline outlined below:
1. Create a file called `mongoose_custom.h`, with defines and includes that 1. Add `-DMG_ARCH=MG_ARCH_CUSTOM` to your build flags.
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 ```c
#include <dirent.h> // For DIR *
#include <stdbool.h> // For bool #include <stdbool.h> // For bool
#include <sys/time.h> // For gettimeofday() #include <stdarg.h>
#include <unistd.h> // For usleep()
#define MG_DIRSEP '/' #define MG_DIRSEP '/'
#define MG_INT64_FMT "%lld"
#define MG_ENABLE_SOCKET 0 // Disable BSD socket API, implement your own #define MG_ENABLE_SOCKET 0 // Disable BSD socket API, implement your own
``` ```
2. Add `-DMG_ARCH=MG_ARCH_CUSTOM` to your build flags.
3. This step is optional. If you have disabled BSD socket API, your build is 3. This step is optional. If you have disabled BSD socket API, your build is
going to fail due to several undefined symbols. Create `mongoose_custom.c` going to fail due to several undefined symbols. Create `mongoose_custom.c`
and implement the following functions (take a look at `src/sock.c` for the and implement the following functions (take a look at `src/sock.c` for the
@@ -320,7 +342,7 @@ This example is a simple TCP echo server that listens on port 1234:
static const char *s_listening_address = "tcp://0.0.0.0:1234"; static const char *s_listening_address = "tcp://0.0.0.0:1234";
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_RECV) { if (ev == MG_EV_READ) {
mg_send(c, c->recv.buf, c->recv.len); // Echo received data back mg_send(c, c->recv.buf, c->recv.len); // Echo received data back
mg_iobuf_delete(&c->recv, c->recv.len); // And discard it mg_iobuf_delete(&c->recv, c->recv.len); // And discard it
} }
@@ -361,20 +383,21 @@ with some housekeeping information.
struct mg_connection { struct mg_connection {
struct mg_connection *next; // Linkage in struct mg_mgr :: connections struct mg_connection *next; // Linkage in struct mg_mgr :: connections
struct mg_mgr *mgr; // Our container struct mg_mgr *mgr; // Our container
struct mg_addr peer; // Remote peer address struct mg_addr peer; // Remote address. For listeners, local address
void *fd; // Connected socket, or LWIP data void *fd; // Connected socket, or LWIP data
unsigned long id; // Auto-incrementing unique connection ID
struct mg_iobuf recv; // Incoming data struct mg_iobuf recv; // Incoming data
struct mg_iobuf send; // Outgoing data struct mg_iobuf send; // Outgoing data
mg_event_handler_t fn; // User-specified event handler function mg_event_handler_t fn; // User-specified event handler function
void *fn_data; // User-speficied function parameter void *fn_data; // User-specified function parameter
mg_event_handler_t pfn; // Protocol-specific handler function mg_event_handler_t pfn; // Protocol-specific handler function
void *pfn_data; // Protocol-specific function parameter void *pfn_data; // Protocol-specific function parameter
char label[32]; // Arbitrary label char label[50]; // Arbitrary label
void *tls; // TLS specific data void *tls; // TLS specific data
unsigned is_listening : 1; // Listening connection unsigned is_listening : 1; // Listening connection
unsigned is_client : 1; // Outbound (client) connection unsigned is_client : 1; // Outbound (client) connection
unsigned is_accepted : 1; // Accepted (server) connection unsigned is_accepted : 1; // Accepted (server) connection
unsigned is_resolving : 1; // Non-blocking DNS resolv is in progress unsigned is_resolving : 1; // Non-blocking DNS resolve is in progress
unsigned is_connecting : 1; // Non-blocking connect is in progress unsigned is_connecting : 1; // Non-blocking connect is in progress
unsigned is_tls : 1; // TLS-enabled connection unsigned is_tls : 1; // TLS-enabled connection
unsigned is_tls_hs : 1; // TLS handshake is in progress unsigned is_tls_hs : 1; // TLS handshake is in progress
@@ -389,7 +412,7 @@ struct mg_connection {
``` ```
A connection - either a listening connection, or an accepted connection, A connection - either a listening connection, or an accepted connection,
or an outbout connection. or an outbound connection.
### mg\_mgr_init() ### mg\_mgr_init()
@@ -397,7 +420,7 @@ or an outbout connection.
void mg_mgr_init(struct mg_mgr *); void mg_mgr_init(struct mg_mgr *);
``` ```
Initialise event manager structure: set a list of active connections to NULL, Initialize event manager structure: set a list of active connections to NULL,
set DNS server and timeout to their default values, etc. set DNS server and timeout to their default values, etc.
@@ -408,7 +431,7 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms);
``` ```
Perform a single poll iteration. For each connection in the `mgr->conns` list, Perform a single poll iteration. For each connection in the `mgr->conns` list,
- See if there is incoming data. If it is, read it into the `c->recv` buffer, send `MG_EV_RECV` event - See if there is incoming data. If it is, read it into the `c->recv` buffer, send `MG_EV_READ` event
- See if there is data in the `c->send` buffer, and write it, send `MG_EV_WRITE` event - See if there is data in the `c->send` buffer, and write it, send `MG_EV_WRITE` event
- If a connection is listening, accept an incoming connection if any, and send `MG_EV_ACCEPT` event to it - If a connection is listening, accept an incoming connection if any, and send `MG_EV_ACCEPT` event to it
- Send `MG_EV_POLL` event - Send `MG_EV_POLL` event
@@ -454,7 +477,7 @@ struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data); mg_event_handler_t fn, void *fn_data);
``` ```
Create an outbout connection, append this connection to `mgr->conns`. Create an outbound connection, append this connection to `mgr->conns`.
- `url` - specifies remote IP address/port to connect to, e.g. `http://a.com` - `url` - specifies remote IP address/port to connect to, e.g. `http://a.com`
- `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
@@ -530,7 +553,7 @@ by `buf`, and `len` specifies number of bytes currently stored.
int mg_iobuf_init(struct mg_iobuf *io, size_t size); int mg_iobuf_init(struct mg_iobuf *io, size_t size);
``` ```
Initialise IO buffer, allocate `size` bytes. Return 1 on success, Initialize IO buffer, allocate `size` bytes. Return 1 on success,
0 on allocation failure. 0 on allocation failure.
@@ -687,7 +710,8 @@ Write a chunk of data in chunked encoding format.
```c ```c
struct mg_http_serve_opts { struct mg_http_serve_opts {
const char *root_dir; // Web root directory, must be non-NULL const char *root_dir; // Web root directory, must be non-NULL
const char *ssi_pattern; // SSI filename pattern, e.g. #.shtml const char *ssi_pattern; // SSI file name pattern, e.g. #.shtml
const char *extra_headers; // Extra HTTP headers to add in responses
}; };
void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm, void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm,
const struct mg_http_serve_opts *opts); const struct mg_http_serve_opts *opts);
@@ -730,7 +754,7 @@ parameter.
- `fmt` - a format string for the HTTP body, in a printf semantics - `fmt` - a format string for the HTTP body, in a printf semantics
### mg\_http\_header() ### mg\_http\_get\_header()
```c ```c
struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name); struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name);
@@ -828,6 +852,25 @@ void mg_http_bauth(struct mg_connection *, const char *user, const char *pass);
Write a Basic `Authorization` header to the output buffer. Write a Basic `Authorization` header to the output buffer.
### mg\_http\_next_\multipart()
```c
// Parameter for mg_http_next_multipart
struct mg_http_part {
struct mg_str name; // Form field name
struct mg_str filename; // Filename for file uploads
struct mg_str body; // Part contents
};
size_t mg_http_next_multipart(struct mg_str body, size_t offset, struct mg_http_part *part);
```
Parse the multipart chunk in the `body` at a given `offset`. An initial
`offset` should be 0. Fill up parameters in the provided `part`, which could be
NULL. Return offset to the next chunk, or 0 if there are no more chunks.
See `form-upload` example for a usage example.
## Websocket ## Websocket
@@ -934,40 +977,38 @@ Create client MQTT connection.
```c ```c
void mg_mqtt_pub(struct mg_connection *, struct mg_str *topic, void mg_mqtt_pub(struct mg_connection *, struct mg_str *topic,
struct mg_str *data); struct mg_str *data, int qos, bool retain);
``` ```
Publish message `data` to the topic `topic`. Publish message `data` to the topic `topic` with given QoS and retain flag.
### mg\_mqtt\_sub() ### mg\_mqtt\_sub()
```c ```c
void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic); void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic, int qos);
``` ```
Subscribe to topic `topic`. Subscribe to topic `topic` with given QoS.
### mg\_mqtt\_next\_sub() ### mg\_mqtt\_next\_sub()
```c ```c
int mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, size_t mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, uint8_t *qos, size_t pos);
uint8_t *qos, int pos);
``` ```
Traverse list of subscribed topics. Traverse list of subscribed topics.
Used to implement MQTT server when `MQTT_CMD_SUBSCRIBE` is received. Used to implement MQTT server when `MQTT_CMD_SUBSCRIBE` is received.
Return next position. Initial position `pos` should be 4. Example: Return next position, or 0 when done. Initial position `pos` should be 4. Example:
```c ```c
if (ev == MG_EV_MQTT_CMD) { 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;
if (mm->cmd == MQTT_CMD_SUBSCRIBE) { if (mm->cmd == MQTT_CMD_SUBSCRIBE) {
int pos = 4; size_t pos = 4;
uint8_t qos; uint8_t qos;
struct mg_str topic; struct mg_str topic;
while ((pos = mg_mqtt_next_sub(mm, &topic, &qos, pos)) > 0) { while ((pos = mg_mqtt_next_sub(mm, &topic, &qos, pos)) > 0) {
LOG(LL_INFO, ("SUB [%.*s]", c->id, (int) topic.len, topic.ptr)); LOG(LL_INFO, ("SUB [%.*s]", (int) topic.len, topic.ptr));
} }
} }
} }
@@ -976,8 +1017,7 @@ if (ev == MG_EV_MQTT_CMD) {
### mg\_mqtt\_next\_unsub() ### mg\_mqtt\_next\_unsub()
```c ```c
int mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, size_t mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, size_t pos);
int pos);
``` ```
Same as `mg_mqtt_next_sub()`, but for unsubscribed topics. The difference Same as `mg_mqtt_next_sub()`, but for unsubscribed topics. The difference
@@ -1001,6 +1041,11 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts);
Initialise TLS on a given connection. Initialise TLS on a given connection.
IMPORTANT: mbedTLS implementation uses `mg_random` as RNG. The `mg_random`
is defined as weak, therefore it is possible to override Mongoose's `mg_random`
with a custom implementation. Just create your own `mg_random` function:
`void mg_random(void *buf, size_t len)`.
## Timers ## Timers
@@ -1014,7 +1059,7 @@ struct mg_timer {
#define MG_TIMER_REPEAT 1 // Call function periodically, otherwise run once #define MG_TIMER_REPEAT 1 // Call function periodically, otherwise run once
#define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set #define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set
void (*fn)(void *); // Function to call void (*fn)(void *); // Function to call
void *arg; // Function agrument void *arg; // Function argument
unsigned long expire; // Expiration timestamp in milliseconds unsigned long expire; // Expiration timestamp in milliseconds
struct mg_timer *next; // Linkage in g_timers list struct mg_timer *next; // Linkage in g_timers list
}; };
@@ -1034,7 +1079,7 @@ Setup a timer.
- `fn` - function to invoke - `fn` - function to invoke
- `fn_data` - function argument - `fn_data` - function argument
A timer gets initialised and linked into the `g_timers` list: A timer gets initialized and linked into the `g_timers` list:
```c ```c
struct mg_timer *g_timers; struct mg_timer *g_timers;
@@ -1063,11 +1108,12 @@ past the timer's expiration time.
### mg\_file\_read() ### mg\_file\_read()
```c ```c
char *mg_file_read(const char *path); char *mg_file_read(const char *path, size_t *sizep);
``` ```
Read file contents into a nul-terminated malloc-ed string. It is a caller's Read file contents into a nul-terminated malloc-ed string. It is a caller's
responsibility to free() a returned pointer. responsibility to free() a returned pointer. If `sizep` is not NULL, it will
return a file size in bytes.
### mg\_file\_size() ### mg\_file\_size()
@@ -1120,7 +1166,7 @@ The glob pattern matching rules are as follows:
- `?` matches any single character - `?` matches any single character
- `*` matches zero or more characters except `/` - `*` matches zero or more characters except `/`
- `#` matches zero or more characters - `#` matches zero or more characters
- any other caracter matches itself - any other character matches itself
### mg\_next\_comma\_entry() ### mg\_next\_comma\_entry()
@@ -1178,7 +1224,7 @@ char *mg_hex(const void *buf, int len, char *dst);
Hex-encode binary data `buf`, `len` into a buffer `dst` and nul-terminate it. Hex-encode binary data `buf`, `len` into a buffer `dst` and nul-terminate it.
The output buffer must be at least 2 x `len` + 1 big. The output buffer must be at least 2 x `len` + 1 big.
Return value: `dst` pointer. The encoded characters are lowecase, Return value: `dst` pointer. The encoded characters are lowercase,
for example `mg_hex("hi", 2, buf)` outputs `6869` and 0 byte, 5 bytes overall. for example `mg_hex("hi", 2, buf)` outputs `6869` and 0 byte, 5 bytes overall.
+2 -2
View File
@@ -143,8 +143,8 @@ static void broadcast_mjpeg_frame(struct mg_mgr *mgr) {
size_t nfiles = sizeof(files) / sizeof(files[0]); size_t nfiles = sizeof(files) / sizeof(files[0]);
static size_t i; static size_t i;
const char *path = files[i++ % nfiles]; const char *path = files[i++ % nfiles];
size_t size = mg_file_size(path); size_t size = 0;
char *data = mg_file_read(path); // Read next file char *data = mg_file_read(path, &size); // Read next file
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] != 'S') continue; // Skip non-stream connections if (c->label[0] != 'S') continue; // Skip non-stream connections
+10
View File
@@ -0,0 +1,10 @@
PROG ?= example
all: $(PROG)
$(DEBUGGER) ./$(PROG)
$(PROG):
$(CC) ../../mongoose.c -I../.. $(CFLAGS) $(EXTRA) -o $(PROG) main.c
clean:
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb log.txt
+53
View File
@@ -0,0 +1,53 @@
// Copyright (c) 2021 Cesanta Software Limited
// All rights reserved
#include "mongoose.h"
// HTTP request handler function. It implements the following endpoints:
// /upload - prints all submitted form elements
// all other URI - serves web_root/ directory
//
// ///////////////// IMPORTANT //////////////////////////
//
// Mongoose has a limit on input buffer, which also limits maximum upload size.
// It is controlled by the MG_MAX_RECV_BUF_SIZE constant, which is set by
// default to (3 * 1024 * 1024), i.e. 3 megabytes.
// Use -DMG_MAX_RECV_BUF_SIZE=NEW_LIMIT to override it.
//
// Also, consider changing -DMG_IO_SIZE=SOME_BIG_VALUE to increase IO buffer
// increment when reading data.
static void cb(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;
LOG(LL_INFO, ("New request to: [%.*s], body size: %lu", (int) hm->uri.len,
hm->uri.ptr, (unsigned long) hm->body.len));
if (mg_http_match_uri(hm, "/upload")) {
struct mg_http_part part;
size_t ofs = 0;
while ((ofs = mg_http_next_multipart(hm->body, ofs, &part)) > 0) {
LOG(LL_INFO,
("Chunk name: [%.*s] filename: [%.*s] length: %lu bytes",
(int) part.name.len, part.name.ptr, (int) part.filename.len,
part.filename.ptr, (unsigned long) part.body.len));
}
mg_http_reply(c, 200, "", "Thank you!");
} else {
struct mg_http_serve_opts opts = {.root_dir = "web_root"};
mg_http_serve_dir(c, ev_data, &opts);
}
}
}
int main(void) {
struct mg_mgr mgr;
struct mg_timer t1;
mg_mgr_init(&mgr);
mg_log_set("3");
mg_http_listen(&mgr, "http://localhost:8000", cb, NULL);
for (;;) mg_mgr_poll(&mgr, 50);
mg_mgr_free(&mgr);
return 0;
}
+40
View File
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>example</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
#container { margin-right: auto; margin-left: auto; max-width: 480px; }
#info { background: #e0f0f0; border-radius: .5em; padding: 2em; }
#wrapper { margin-top: 1em; }
form * { margin: 0.2em 0; }
</style>
</head>
<body>
<div id="container">
<div id="info">
Mongoose always buffers a full HTTP message before invoking
MG_EV_HTTP_MSG event. Big POST request require of lot
of RAM to buffer everything. Therefore, standard form uploads
should be used only when Mongoose runs on a system with lots of RAM.
Otherwise, please see <code>file-updload</code> example, how
a big file could be uploaded to a device with little RAM.
<br/><br/>
In this example, a standard HTML form upload is used, which uses
<code>multipart-form-data</code> encoding with
several variables and file upload. On a server side, a
<code>mg_http_next_multipart()</code> API is used to iterate over
all submitted form elements and print their payload.
</div>
<div id="wrapper">
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="text" name="field1" value="type some text here" /> <br/>
<input type="file" name="file1" /> </br>
<button type="submit">submit form</button>
</form>
</div>
</div>
</body>
</html>
+7 -1
View File
@@ -1,5 +1,7 @@
PROG ?= example PROG ?= example
CFLAGS ?= -DMG_ENABLE_LINES $(EXTRA) CFLAGS ?= -DMG_ENABLE_LINES $(EXTRA)
ROOT ?= $(realpath $(CURDIR)/../..)
LIN = docker run -it --rm -v $(ROOT):$(ROOT) -w $(CURDIR) mdashnet/cc2
ifneq ($(MBEDTLS),) ifneq ($(MBEDTLS),)
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS)/include -I/usr/include CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS)/include -I/usr/include
@@ -14,9 +16,13 @@ endif
all: $(PROG) all: $(PROG)
$(DEBUGGER) ./$(PROG) $(ARGS) $(DEBUGGER) ./$(PROG) $(ARGS)
$(PROG): main.c $(PROG): main.c
$(CC) ../../mongoose.c -I../.. -W -Wall $(CFLAGS) -o $(PROG) main.c $(CC) ../../mongoose.c -I../.. -W -Wall $(CFLAGS) -o $(PROG) main.c
linux: all
linux: CFLAGS += -O2 -g -fsanitize=address,undefined,shift,null,return,bounds,alignment,object-size,bool,enum -static-libasan
linux: CC = $(LIN) cc
linux: DEBUGGER = $(LIN)
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
+1 -1
View File
@@ -12,7 +12,7 @@
#include "mongoose.h" #include "mongoose.h"
// The very first web page in history. You can replace it from command line // The very first web page in history. You can replace it from command line
static const char *s_url = "http://info.cern.ch"; static const char *s_url = "http://info.cern.ch//foo";
// 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) {
+4 -2
View File
@@ -1,9 +1,11 @@
PROG ?= example PROG ?= example
ifeq "$(MBEDTLS_DIR)" "" ifneq ($(MBEDTLS_DIR),)
else
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS_DIR)/include -I/usr/include CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS_DIR)/include -I/usr/include
CFLAGS += -L$(MBEDTLS_DIR)/lib -lmbedtls -lmbedcrypto -lmbedx509 CFLAGS += -L$(MBEDTLS_DIR)/lib -lmbedtls -lmbedcrypto -lmbedx509
else ifneq ($(OPENSSL_DIR),)
CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL_DIR)/include
CFLAGS += -L$(OPENSSL_DIR)/lib -lssl -lcrypto
endif endif
all: $(PROG) all: $(PROG)
+13 -10
View File
@@ -2,24 +2,26 @@
// All rights reserved // All rights reserved
// //
// HTTP server example. This server serves both static and dynamic content. // HTTP server example. This server serves both static and dynamic content.
// It opens two ports: plain HTTP on port 8000 and HTTP on port 8443.
// It implements the following endpoints: // It implements the following endpoints:
// /api/f1 - respond with JSON string {"result": 123} // /api/f1 - respond with JSON string {"result": 123}
// /api/f2/:id - wildcard example, respond with JSON string {"result": "URI"} // /api/f2/:id - wildcard example, respond with JSON string {"result": "URI"}
// any other URI serves static files from s_web_directory // any other URI serves static files from s_root_dir
// //
// To enable SSL/TLS (using self-signed certificates in PEM files), // To enable SSL/TLS (using self-signed certificates in PEM files),
// 1. Change s_listen_on from http:// to https:// // 1. make MBEDTLS_DIR=/path/to/your/mbedtls/installation
// 2. make MBEDTLS_DIR=/path/to/your/mbedtls/installation // 2. curl -k https://127.0.0.1:8443
// 3. curl -k https://127.0.0.1:8000
#include "mongoose.h" #include "mongoose.h"
static const char *s_listen_on = "http://0.0.0.0:8000"; static const char *s_http_addr = "http://0.0.0.0:8000"; // HTTP port
static const char *s_web_directory = "."; static const char *s_https_addr = "https://0.0.0.0:8443"; // HTTPS port
static const char *s_root_dir = ".";
// We use the same event handler function for HTTP and HTTPS connections
// fn_data is NULL for plain HTTP, and non-NULL for HTTPS
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_ACCEPT && mg_url_is_ssl(s_listen_on)) { if (ev == MG_EV_ACCEPT && fn_data != NULL) {
// If s_listen_on URL is https://, tell listening connection to use TLS
struct mg_tls_opts opts = { struct mg_tls_opts opts = {
//.ca = "ca.pem", // Uncomment to enable two-way SSL //.ca = "ca.pem", // Uncomment to enable two-way SSL
.cert = "server.pem", // Certificate PEM file .cert = "server.pem", // Certificate PEM file
@@ -34,7 +36,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
mg_http_reply(c, 200, "", "{\"result\": \"%.*s\"}\n", (int) hm->uri.len, mg_http_reply(c, 200, "", "{\"result\": \"%.*s\"}\n", (int) hm->uri.len,
hm->uri.ptr); hm->uri.ptr);
} else { } else {
struct mg_http_serve_opts opts = {.root_dir = s_web_directory}; struct mg_http_serve_opts opts = {.root_dir = s_root_dir};
mg_http_serve_dir(c, ev_data, &opts); mg_http_serve_dir(c, ev_data, &opts);
} }
} }
@@ -45,7 +47,8 @@ int main(void) {
struct mg_mgr mgr; // Event manager struct mg_mgr mgr; // Event manager
mg_log_set("2"); // Set to 3 to enable debug mg_log_set("2"); // Set to 3 to enable debug
mg_mgr_init(&mgr); // Initialise event manager mg_mgr_init(&mgr); // Initialise event manager
mg_http_listen(&mgr, s_listen_on, fn, NULL); // Create HTTP listener mg_http_listen(&mgr, s_http_addr, fn, NULL); // Create HTTP listener
mg_http_listen(&mgr, s_https_addr, fn, (void *) 1); // HTTPS listener
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
return 0; return 0;
+1 -1
View File
@@ -64,7 +64,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} }
} else if (ev == MG_EV_CLOSE) { } else if (ev == MG_EV_CLOSE) {
if (c2 != NULL) c2->is_closing = 1; if (c->label[0] != 'B' && c2 != NULL) c2->is_closing = 1;
c->fn_data = NULL; c->fn_data = NULL;
} }
} }
+7 -1
View File
@@ -3,7 +3,8 @@ ROOT ?= $(realpath $(CURDIR)/../..)
DEFS ?= -DMG_ENABLE_LINES=1 -DMG_ENABLE_DIRECTORY_LISTING=1 -DMG_ENABLE_SSI=1 DEFS ?= -DMG_ENABLE_LINES=1 -DMG_ENABLE_DIRECTORY_LISTING=1 -DMG_ENABLE_SSI=1
CFLAGS ?= -I../.. -W -Wall -DMG_ENABLE_IPV6=1 $(DEFS) $(EXTRA) CFLAGS ?= -I../.. -W -Wall -DMG_ENABLE_IPV6=1 $(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 --rm -e Tmp=. -v $(ROOT):$(ROOT) -w $(CURDIR) docker.io/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)
$(DEBUGGER) ./$(PROG) $(ARGS) $(DEBUGGER) ./$(PROG) $(ARGS)
@@ -14,5 +15,10 @@ $(PROG): main.c Makefile
mongoose.exe: main.c 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:$@
linux: all
linux: CFLAGS += -O2 -fsanitize=address,undefined,shift,null,return,bounds,alignment,object-size,bool,enum -static-libasan
#linux: CC = $(LIN) cc
#linux: DEBUGGER = $(LIN)
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.*
+17 -4
View File
@@ -1,6 +1,7 @@
// Copyright (c) 2020 Cesanta Software Limited // Copyright (c) 2020 Cesanta Software Limited
// All rights reserved // All rights reserved
#include <signal.h>
#include "mongoose.h" #include "mongoose.h"
static const char *s_debug_level = "2"; static const char *s_debug_level = "2";
@@ -9,9 +10,18 @@ static const char *s_listening_address = "http://localhost:8000";
static const char *s_enable_hexdump = "no"; static const char *s_enable_hexdump = "no";
static const char *s_ssi_pattern = "#.shtml"; static const char *s_ssi_pattern = "#.shtml";
// Handle interrupts, like Ctrl-C
static int s_signo;
static void signal_handler(int signo) {
s_signo = signo;
}
// Event handler for the listening connection.
// Simply serve static files from `s_root_dir`
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void cb(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_serve_opts opts = {s_root_dir, s_ssi_pattern}; struct mg_http_serve_opts opts = {.root_dir = s_root_dir,
.ssi_pattern = s_ssi_pattern};
mg_http_serve_dir(c, ev_data, &opts); mg_http_serve_dir(c, ev_data, &opts);
} }
(void) fn_data; (void) fn_data;
@@ -19,8 +29,8 @@ static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
static void usage(const char *prog) { static void usage(const char *prog) {
fprintf(stderr, fprintf(stderr,
"Mongoose v.%s, built " __DATE__ " " __TIME__ "Mongoose v.%s\n"
"\nUsage: %s OPTIONS\n" "Usage: %s OPTIONS\n"
" -H yes|no - enable traffic hexdump, default: '%s'\n" " -H yes|no - enable traffic hexdump, default: '%s'\n"
" -S GLOB - glob pattern for SSI files, default: '%s'\n" " -S GLOB - glob pattern for SSI files, default: '%s'\n"
" -d DIR - directory to serve, default: '%s'\n" " -d DIR - directory to serve, default: '%s'\n"
@@ -54,6 +64,8 @@ int main(int argc, char *argv[]) {
} }
// Initialise stuff // Initialise stuff
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
mg_log_set(s_debug_level); mg_log_set(s_debug_level);
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
if ((c = mg_http_listen(&mgr, s_listening_address, cb, &mgr)) == NULL) { if ((c = mg_http_listen(&mgr, s_listening_address, cb, &mgr)) == NULL) {
@@ -65,7 +77,8 @@ int main(int argc, char *argv[]) {
// Start infinite event loop // Start infinite event loop
LOG(LL_INFO, ("Starting Mongoose v%s, serving [%s]", MG_VERSION, s_root_dir)); LOG(LL_INFO, ("Starting Mongoose v%s, serving [%s]", MG_VERSION, s_root_dir));
for (;;) mg_mgr_poll(&mgr, 1000); while (s_signo == 0) mg_mgr_poll(&mgr, 1000);
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
LOG(LL_INFO, ("Exiting on signal %d", s_signo));
return 0; return 0;
} }
+2 -2
View File
@@ -29,9 +29,9 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
// MQTT connect is successful // MQTT connect is successful
struct mg_str topic = mg_str(s_topic), data = mg_str("hello"); struct mg_str topic = mg_str(s_topic), data = mg_str("hello");
LOG(LL_INFO, ("CONNECTED to %s", s_url)); LOG(LL_INFO, ("CONNECTED to %s", s_url));
mg_mqtt_sub(c, &topic); mg_mqtt_sub(c, &topic, 1);
LOG(LL_INFO, ("SUBSCRIBED to %.*s", (int) topic.len, topic.ptr)); LOG(LL_INFO, ("SUBSCRIBED to %.*s", (int) topic.len, topic.ptr));
mg_mqtt_pub(c, &topic, &data); mg_mqtt_pub(c, &topic, &data, 1, false);
LOG(LL_INFO, ("PUBSLISHED %.*s -> %.*s", (int) data.len, data.ptr, LOG(LL_INFO, ("PUBSLISHED %.*s -> %.*s", (int) data.len, data.ptr,
(int) topic.len, topic.ptr)); (int) topic.len, topic.ptr));
} else if (ev == MG_EV_MQTT_MSG) { } else if (ev == MG_EV_MQTT_MSG) {
+1 -1
View File
@@ -55,7 +55,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
mm->data.ptr, (int) mm->topic.len, mm->topic.ptr)); mm->data.ptr, (int) mm->topic.len, mm->topic.ptr));
for (struct sub *sub = s_subs; sub != NULL; sub = sub->next) { for (struct sub *sub = s_subs; sub != NULL; sub = sub->next) {
if (mg_strcmp(mm->topic, sub->topic) != 0) continue; if (mg_strcmp(mm->topic, sub->topic) != 0) continue;
mg_mqtt_pub(sub->c, &mm->topic, &mm->data); mg_mqtt_pub(sub->c, &mm->topic, &mm->data, 1, false);
} }
break; break;
} }
Whitespace-only changes.
@@ -0,0 +1,620 @@
/**
******************************************************************************
* @file stm32f7xx_hal.c
* @author MCD Application Team
* @brief HAL module driver.
* This is the common part of the HAL initialization
*
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
The common HAL driver contains a set of generic and common APIs that can be
used by the PPP peripheral drivers and the user to start using the HAL.
[..]
The HAL contains two APIs' categories:
(+) Common HAL APIs
(+) Services HAL APIs
@endverbatim
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f7xx_hal.h"
/** @addtogroup STM32F7xx_HAL_Driver
* @{
*/
/** @defgroup HAL HAL
* @brief HAL module driver.
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @addtogroup HAL_Private_Constants
* @{
*/
/**
* @brief STM32F7xx HAL Driver version number V1.2.9
*/
#define __STM32F7xx_HAL_VERSION_MAIN (0x01) /*!< [31:24] main version */
#define __STM32F7xx_HAL_VERSION_SUB1 (0x02) /*!< [23:16] sub1 version */
#define __STM32F7xx_HAL_VERSION_SUB2 (0x09) /*!< [15:8] sub2 version */
#define __STM32F7xx_HAL_VERSION_RC (0x00) /*!< [7:0] release candidate */
#define __STM32F7xx_HAL_VERSION ((__STM32F7xx_HAL_VERSION_MAIN << 24)\
|(__STM32F7xx_HAL_VERSION_SUB1 << 16)\
|(__STM32F7xx_HAL_VERSION_SUB2 << 8 )\
|(__STM32F7xx_HAL_VERSION_RC))
#define IDCODE_DEVID_MASK ((uint32_t)0x00000FFF)
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Exported variables ---------------------------------------------------------*/
/** @addtogroup HAL_Exported_Variables
* @{
*/
__IO uint32_t uwTick;
uint32_t uwTickPrio = (1UL << __NVIC_PRIO_BITS); /* Invalid PRIO */
HAL_TickFreqTypeDef uwTickFreq = HAL_TICK_FREQ_DEFAULT; /* 1KHz */
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup HAL_Exported_Functions HAL Exported Functions
* @{
*/
/** @defgroup HAL_Exported_Functions_Group1 Initialization and de-initialization Functions
* @brief Initialization and de-initialization functions
*
@verbatim
===============================================================================
##### Initialization and Configuration functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Initializes the Flash interface the NVIC allocation and initial clock
configuration. It initializes the systick also when timeout is needed
and the backup domain when enabled.
(+) De-Initializes common part of the HAL.
(+) Configure the time base source to have 1ms time base with a dedicated
Tick interrupt priority.
(++) SysTick timer is used by default as source of time base, but user
can eventually implement his proper time base source (a general purpose
timer for example or other time source), keeping in mind that Time base
duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
handled in milliseconds basis.
(++) Time base configuration function (HAL_InitTick ()) is called automatically
at the beginning of the program after reset by HAL_Init() or at any time
when clock is configured, by HAL_RCC_ClockConfig().
(++) Source of time base is configured to generate interrupts at regular
time intervals. Care must be taken if HAL_Delay() is called from a
peripheral ISR process, the Tick interrupt line must have higher priority
(numerically lower) than the peripheral interrupt. Otherwise the caller
ISR process will be blocked.
(++) functions affecting time base configurations are declared as __weak
to make override possible in case of other implementations in user file.
@endverbatim
* @{
*/
/**
* @brief This function is used to initialize the HAL Library; it must be the first
* instruction to be executed in the main program (before to call any other
* HAL function), it performs the following:
* Configure the Flash prefetch, and instruction cache through ART accelerator.
* Configures the SysTick to generate an interrupt each 1 millisecond,
* which is clocked by the HSI (at this stage, the clock is not yet
* configured and thus the system is running from the internal HSI at 16 MHz).
* Set NVIC Group Priority to 4.
* Calls the HAL_MspInit() callback function defined in user file
* "stm32f7xx_hal_msp.c" to do the global low level hardware initialization
*
* @note SysTick is used as time base for the HAL_Delay() function, the application
* need to ensure that the SysTick time base is always set to 1 millisecond
* to have correct HAL operation.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_Init(void)
{
/* Configure Instruction cache through ART accelerator */
#if (ART_ACCLERATOR_ENABLE != 0)
__HAL_FLASH_ART_ENABLE();
#endif /* ART_ACCLERATOR_ENABLE */
/* Configure Flash prefetch */
#if (PREFETCH_ENABLE != 0U)
__HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif /* PREFETCH_ENABLE */
/* Set Interrupt Group Priority */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
HAL_InitTick(TICK_INT_PRIORITY);
/* Init the low level hardware */
HAL_MspInit();
/* Return function status */
return HAL_OK;
}
/**
* @brief This function de-Initializes common part of the HAL and stops the systick.
* This function is optional.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DeInit(void)
{
/* Reset of all peripherals */
__HAL_RCC_APB1_FORCE_RESET();
__HAL_RCC_APB1_RELEASE_RESET();
__HAL_RCC_APB2_FORCE_RESET();
__HAL_RCC_APB2_RELEASE_RESET();
__HAL_RCC_AHB1_FORCE_RESET();
__HAL_RCC_AHB1_RELEASE_RESET();
__HAL_RCC_AHB2_FORCE_RESET();
__HAL_RCC_AHB2_RELEASE_RESET();
__HAL_RCC_AHB3_FORCE_RESET();
__HAL_RCC_AHB3_RELEASE_RESET();
/* De-Init the low level hardware */
HAL_MspDeInit();
/* Return function status */
return HAL_OK;
}
/**
* @brief Initialize the MSP.
* @retval None
*/
__weak void HAL_MspInit(void)
{
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_MspInit could be implemented in the user file
*/
}
/**
* @brief DeInitializes the MSP.
* @retval None
*/
__weak void HAL_MspDeInit(void)
{
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_MspDeInit could be implemented in the user file
*/
}
/**
* @brief This function configures the source of the time base.
* The time source is configured to have 1ms time base with a dedicated
* Tick interrupt priority.
* @note This function is called automatically at the beginning of program after
* reset by HAL_Init() or at any time when clock is reconfigured by HAL_RCC_ClockConfig().
* @note In the default implementation, SysTick timer is the source of time base.
* It is used to generate interrupts at regular time intervals.
* Care must be taken if HAL_Delay() is called from a peripheral ISR process,
* The SysTick interrupt must have higher priority (numerically lower)
* than the peripheral interrupt. Otherwise the caller ISR process will be blocked.
* The function is declared as __weak to be overwritten in case of other
* implementation in user file.
* @param TickPriority Tick interrupt priority.
* @retval HAL status
*/
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
/* Configure the SysTick to have interrupt in 1ms time basis*/
if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
{
return HAL_ERROR;
}
/* Configure the SysTick IRQ priority */
if (TickPriority < (1UL << __NVIC_PRIO_BITS))
{
HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
uwTickPrio = TickPriority;
}
else
{
return HAL_ERROR;
}
/* Return function status */
return HAL_OK;
}
/**
* @}
*/
/** @defgroup HAL_Exported_Functions_Group2 HAL Control functions
* @brief HAL Control functions
*
@verbatim
===============================================================================
##### HAL Control functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Provide a tick value in millisecond
(+) Provide a blocking delay in millisecond
(+) Suspend the time base source interrupt
(+) Resume the time base source interrupt
(+) Get the HAL API driver version
(+) Get the device identifier
(+) Get the device revision identifier
(+) Enable/Disable Debug module during SLEEP mode
(+) Enable/Disable Debug module during STOP mode
(+) Enable/Disable Debug module during STANDBY mode
@endverbatim
* @{
*/
/**
* @brief This function is called to increment a global variable "uwTick"
* used as application time base.
* @note In the default implementation, this variable is incremented each 1ms
* in SysTick ISR.
* @note This function is declared as __weak to be overwritten in case of other
* implementations in user file.
* @retval None
*/
__weak void HAL_IncTick(void)
{
uwTick += uwTickFreq;
}
/**
* @brief Provides a tick value in millisecond.
* @note This function is declared as __weak to be overwritten in case of other
* implementations in user file.
* @retval tick value
*/
__weak uint32_t HAL_GetTick(void)
{
return uwTick;
}
/**
* @brief This function returns a tick priority.
* @retval tick priority
*/
uint32_t HAL_GetTickPrio(void)
{
return uwTickPrio;
}
/**
* @brief Set new tick Freq.
* @retval Status
*/
HAL_StatusTypeDef HAL_SetTickFreq(HAL_TickFreqTypeDef Freq)
{
HAL_StatusTypeDef status = HAL_OK;
HAL_TickFreqTypeDef prevTickFreq;
assert_param(IS_TICKFREQ(Freq));
if (uwTickFreq != Freq)
{
/* Back up uwTickFreq frequency */
prevTickFreq = uwTickFreq;
/* Update uwTickFreq global variable used by HAL_InitTick() */
uwTickFreq = Freq;
/* Apply the new tick Freq */
status = HAL_InitTick(uwTickPrio);
if (status != HAL_OK)
{
/* Restore previous tick frequency */
uwTickFreq = prevTickFreq;
}
}
return status;
}
/**
* @brief Return tick frequency.
* @retval tick period in Hz
*/
HAL_TickFreqTypeDef HAL_GetTickFreq(void)
{
return uwTickFreq;
}
/**
* @brief This function provides minimum delay (in milliseconds) based
* on variable incremented.
* @note In the default implementation , SysTick timer is the source of time base.
* It is used to generate interrupts at regular time intervals where uwTick
* is incremented.
* @note This function is declared as __weak to be overwritten in case of other
* implementations in user file.
* @param Delay specifies the delay time length, in milliseconds.
* @retval None
*/
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;
/* Add a freq to guarantee minimum wait */
if (wait < HAL_MAX_DELAY)
{
wait += (uint32_t)(uwTickFreq);
}
while ((HAL_GetTick() - tickstart) < wait)
{
}
}
/**
* @brief Suspend Tick increment.
* @note In the default implementation , SysTick timer is the source of time base. It is
* used to generate interrupts at regular time intervals. Once HAL_SuspendTick()
* is called, the SysTick interrupt will be disabled and so Tick increment
* is suspended.
* @note This function is declared as __weak to be overwritten in case of other
* implementations in user file.
* @retval None
*/
__weak void HAL_SuspendTick(void)
{
/* Disable SysTick Interrupt */
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;
}
/**
* @brief Resume Tick increment.
* @note In the default implementation , SysTick timer is the source of time base. It is
* used to generate interrupts at regular time intervals. Once HAL_ResumeTick()
* is called, the SysTick interrupt will be enabled and so Tick increment
* is resumed.
* @note This function is declared as __weak to be overwritten in case of other
* implementations in user file.
* @retval None
*/
__weak void HAL_ResumeTick(void)
{
/* Enable SysTick Interrupt */
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;
}
/**
* @brief Returns the HAL revision
* @retval version : 0xXYZR (8bits for each decimal, R for RC)
*/
uint32_t HAL_GetHalVersion(void)
{
return __STM32F7xx_HAL_VERSION;
}
/**
* @brief Returns the device revision identifier.
* @retval Device revision identifier
*/
uint32_t HAL_GetREVID(void)
{
return((DBGMCU->IDCODE) >> 16U);
}
/**
* @brief Returns the device identifier.
* @retval Device identifier
*/
uint32_t HAL_GetDEVID(void)
{
return((DBGMCU->IDCODE) & IDCODE_DEVID_MASK);
}
/**
* @brief Returns first word of the unique device identifier (UID based on 96 bits)
* @retval Device identifier
*/
uint32_t HAL_GetUIDw0(void)
{
return(READ_REG(*((uint32_t *)UID_BASE)));
}
/**
* @brief Returns second word of the unique device identifier (UID based on 96 bits)
* @retval Device identifier
*/
uint32_t HAL_GetUIDw1(void)
{
return(READ_REG(*((uint32_t *)(UID_BASE + 4U))));
}
/**
* @brief Returns third word of the unique device identifier (UID based on 96 bits)
* @retval Device identifier
*/
uint32_t HAL_GetUIDw2(void)
{
return(READ_REG(*((uint32_t *)(UID_BASE + 8U))));
}
/**
* @brief Enable the Debug Module during SLEEP mode
* @retval None
*/
void HAL_DBGMCU_EnableDBGSleepMode(void)
{
SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_SLEEP);
}
/**
* @brief Disable the Debug Module during SLEEP mode
* @retval None
*/
void HAL_DBGMCU_DisableDBGSleepMode(void)
{
CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_SLEEP);
}
/**
* @brief Enable the Debug Module during STOP mode
* @retval None
*/
void HAL_DBGMCU_EnableDBGStopMode(void)
{
SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STOP);
}
/**
* @brief Disable the Debug Module during STOP mode
* @retval None
*/
void HAL_DBGMCU_DisableDBGStopMode(void)
{
CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STOP);
}
/**
* @brief Enable the Debug Module during STANDBY mode
* @retval None
*/
void HAL_DBGMCU_EnableDBGStandbyMode(void)
{
SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STANDBY);
}
/**
* @brief Disable the Debug Module during STANDBY mode
* @retval None
*/
void HAL_DBGMCU_DisableDBGStandbyMode(void)
{
CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STANDBY);
}
/**
* @brief Enables the I/O Compensation Cell.
* @note The I/O compensation cell can be used only when the device supply
* voltage ranges from 2.4 to 3.6 V.
* @retval None
*/
void HAL_EnableCompensationCell(void)
{
SYSCFG->CMPCR |= SYSCFG_CMPCR_CMP_PD;
}
/**
* @brief Power-down the I/O Compensation Cell.
* @note The I/O compensation cell can be used only when the device supply
* voltage ranges from 2.4 to 3.6 V.
* @retval None
*/
void HAL_DisableCompensationCell(void)
{
SYSCFG->CMPCR &= (uint32_t)~((uint32_t)SYSCFG_CMPCR_CMP_PD);
}
/**
* @brief Enables the FMC Memory Mapping Swapping.
*
* @note SDRAM is accessible at 0x60000000
* and NOR/RAM is accessible at 0xC0000000
*
* @retval None
*/
void HAL_EnableFMCMemorySwapping(void)
{
SYSCFG->MEMRMP |= SYSCFG_MEMRMP_SWP_FMC_0;
}
/**
* @brief Disables the FMC Memory Mapping Swapping
*
* @note SDRAM is accessible at 0xC0000000 (default mapping)
* and NOR/RAM is accessible at 0x60000000 (default mapping)
*
* @retval None
*/
void HAL_DisableFMCMemorySwapping(void)
{
SYSCFG->MEMRMP &= (uint32_t)~((uint32_t)SYSCFG_MEMRMP_SWP_FMC);
}
#if defined (STM32F765xx) || defined (STM32F767xx) || defined (STM32F769xx) || defined (STM32F777xx) || defined (STM32F779xx)
/**
* @brief Enable the Internal FLASH Bank Swapping.
*
* @note This function can be used only for STM32F77xx/STM32F76xx devices.
*
* @note Flash Bank2 mapped at 0x08000000 (AXI) (aliased at 0x00200000 (TCM))
* and Flash Bank1 mapped at 0x08100000 (AXI) (aliased at 0x00300000 (TCM))
*
* @retval None
*/
void HAL_EnableMemorySwappingBank(void)
{
SET_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_SWP_FB);
}
/**
* @brief Disable the Internal FLASH Bank Swapping.
*
* @note This function can be used only for STM32F77xx/STM32F76xx devices.
*
* @note The default state : Flash Bank1 mapped at 0x08000000 (AXI) (aliased at 0x00200000 (TCM))
* and Flash Bank2 mapped at 0x08100000 (AXI)( aliased at 0x00300000 (TCM))
*
* @retval None
*/
void HAL_DisableMemorySwappingBank(void)
{
CLEAR_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_SWP_FB);
}
#endif /* STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,276 @@
/**
******************************************************************************
* @file stm32f7xx_hal.h
* @author MCD Application Team
* @brief This file contains all the functions prototypes for the HAL
* module driver.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F7xx_HAL_H
#define __STM32F7xx_HAL_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f7xx_hal_conf.h"
/** @addtogroup STM32F7xx_HAL_Driver
* @{
*/
/** @addtogroup HAL
* @{
*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup HAL_Exported_Constants HAL Exported Constants
* @{
*/
/** @defgroup HAL_TICK_FREQ Tick Frequency
* @{
*/
typedef enum
{
HAL_TICK_FREQ_10HZ = 100U,
HAL_TICK_FREQ_100HZ = 10U,
HAL_TICK_FREQ_1KHZ = 1U,
HAL_TICK_FREQ_DEFAULT = HAL_TICK_FREQ_1KHZ
} HAL_TickFreqTypeDef;
/**
* @}
*/
/** @defgroup SYSCFG_BootMode Boot Mode
* @{
*/
#define SYSCFG_MEM_BOOT_ADD0 ((uint32_t)0x00000000U)
#define SYSCFG_MEM_BOOT_ADD1 SYSCFG_MEMRMP_MEM_BOOT
/**
* @}
*/
/**
* @}
*/
/* Exported macro ------------------------------------------------------------*/
/** @defgroup HAL_Exported_Macros HAL Exported Macros
* @{
*/
/** @brief Freeze/Unfreeze Peripherals in Debug mode
*/
#define __HAL_DBGMCU_FREEZE_TIM2() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_TIM2_STOP))
#define __HAL_DBGMCU_FREEZE_TIM3() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_TIM3_STOP))
#define __HAL_DBGMCU_FREEZE_TIM4() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_TIM4_STOP))
#define __HAL_DBGMCU_FREEZE_TIM5() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_TIM5_STOP))
#define __HAL_DBGMCU_FREEZE_TIM6() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_TIM6_STOP))
#define __HAL_DBGMCU_FREEZE_TIM7() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_TIM7_STOP))
#define __HAL_DBGMCU_FREEZE_TIM12() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_TIM12_STOP))
#define __HAL_DBGMCU_FREEZE_TIM13() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_TIM13_STOP))
#define __HAL_DBGMCU_FREEZE_TIM14() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_TIM14_STOP))
#define __HAL_DBGMCU_FREEZE_LPTIM1() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_LPTIM1_STOP))
#define __HAL_DBGMCU_FREEZE_RTC() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_RTC_STOP))
#define __HAL_DBGMCU_FREEZE_WWDG() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_WWDG_STOP))
#define __HAL_DBGMCU_FREEZE_IWDG() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_IWDG_STOP))
#define __HAL_DBGMCU_FREEZE_I2C1_TIMEOUT() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_I2C1_SMBUS_TIMEOUT))
#define __HAL_DBGMCU_FREEZE_I2C2_TIMEOUT() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_I2C2_SMBUS_TIMEOUT))
#define __HAL_DBGMCU_FREEZE_I2C3_TIMEOUT() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_I2C3_SMBUS_TIMEOUT))
#define __HAL_DBGMCU_FREEZE_I2C4_TIMEOUT() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_I2C4_SMBUS_TIMEOUT))
#define __HAL_DBGMCU_FREEZE_CAN1() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_CAN1_STOP))
#define __HAL_DBGMCU_FREEZE_CAN2() (DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_CAN2_STOP))
#define __HAL_DBGMCU_FREEZE_TIM1() (DBGMCU->APB2FZ |= (DBGMCU_APB2_FZ_DBG_TIM1_STOP))
#define __HAL_DBGMCU_FREEZE_TIM8() (DBGMCU->APB2FZ |= (DBGMCU_APB2_FZ_DBG_TIM8_STOP))
#define __HAL_DBGMCU_FREEZE_TIM9() (DBGMCU->APB2FZ |= (DBGMCU_APB2_FZ_DBG_TIM9_STOP))
#define __HAL_DBGMCU_FREEZE_TIM10() (DBGMCU->APB2FZ |= (DBGMCU_APB2_FZ_DBG_TIM10_STOP))
#define __HAL_DBGMCU_FREEZE_TIM11() (DBGMCU->APB2FZ |= (DBGMCU_APB2_FZ_DBG_TIM11_STOP))
#define __HAL_DBGMCU_UNFREEZE_TIM2() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_TIM2_STOP))
#define __HAL_DBGMCU_UNFREEZE_TIM3() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_TIM3_STOP))
#define __HAL_DBGMCU_UNFREEZE_TIM4() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_TIM4_STOP))
#define __HAL_DBGMCU_UNFREEZE_TIM5() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_TIM5_STOP))
#define __HAL_DBGMCU_UNFREEZE_TIM6() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_TIM6_STOP))
#define __HAL_DBGMCU_UNFREEZE_TIM7() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_TIM7_STOP))
#define __HAL_DBGMCU_UNFREEZE_TIM12() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_TIM12_STOP))
#define __HAL_DBGMCU_UNFREEZE_TIM13() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_TIM13_STOP))
#define __HAL_DBGMCU_UNFREEZE_TIM14() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_TIM14_STOP))
#define __HAL_DBGMCU_UNFREEZE_LPTIM1() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_LPTIM1_STOP))
#define __HAL_DBGMCU_UNFREEZE_RTC() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_RTC_STOP))
#define __HAL_DBGMCU_UNFREEZE_WWDG() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_WWDG_STOP))
#define __HAL_DBGMCU_UNFREEZE_IWDG() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_IWDG_STOP))
#define __HAL_DBGMCU_UNFREEZE_I2C1_TIMEOUT() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_I2C1_SMBUS_TIMEOUT))
#define __HAL_DBGMCU_UNFREEZE_I2C2_TIMEOUT() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_I2C2_SMBUS_TIMEOUT))
#define __HAL_DBGMCU_UNFREEZE_I2C3_TIMEOUT() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_I2C3_SMBUS_TIMEOUT))
#define __HAL_DBGMCU_UNFREEZE_I2C4_TIMEOUT() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_I2C4_SMBUS_TIMEOUT))
#define __HAL_DBGMCU_UNFREEZE_CAN1() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_CAN1_STOP))
#define __HAL_DBGMCU_UNFREEZE_CAN2() (DBGMCU->APB1FZ &= ~(DBGMCU_APB1_FZ_DBG_CAN2_STOP))
#define __HAL_DBGMCU_UNFREEZE_TIM1() (DBGMCU->APB2FZ &= ~(DBGMCU_APB2_FZ_DBG_TIM1_STOP))
#define __HAL_DBGMCU_UNFREEZE_TIM8() (DBGMCU->APB2FZ &= ~(DBGMCU_APB2_FZ_DBG_TIM8_STOP))
#define __HAL_DBGMCU_UNFREEZE_TIM9() (DBGMCU->APB2FZ &= ~(DBGMCU_APB2_FZ_DBG_TIM9_STOP))
#define __HAL_DBGMCU_UNFREEZE_TIM10() (DBGMCU->APB2FZ &= ~(DBGMCU_APB2_FZ_DBG_TIM10_STOP))
#define __HAL_DBGMCU_UNFREEZE_TIM11() (DBGMCU->APB2FZ &= ~(DBGMCU_APB2_FZ_DBG_TIM11_STOP))
/** @brief FMC (NOR/RAM) mapped at 0x60000000 and SDRAM mapped at 0xC0000000
*/
#define __HAL_SYSCFG_REMAPMEMORY_FMC() (SYSCFG->MEMRMP &= ~(SYSCFG_MEMRMP_SWP_FMC))
/** @brief FMC/SDRAM mapped at 0x60000000 (NOR/RAM) mapped at 0xC0000000
*/
#define __HAL_SYSCFG_REMAPMEMORY_FMC_SDRAM() do {SYSCFG->MEMRMP &= ~(SYSCFG_MEMRMP_SWP_FMC);\
SYSCFG->MEMRMP |= (SYSCFG_MEMRMP_SWP_FMC_0);\
}while(0);
/**
* @brief Return the memory boot mapping as configured by user.
* @retval The boot mode as configured by user. The returned value can be one
* of the following values:
* @arg @ref SYSCFG_MEM_BOOT_ADD0
* @arg @ref SYSCFG_MEM_BOOT_ADD1
*/
#define __HAL_SYSCFG_GET_BOOT_MODE() READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_MEM_BOOT)
#if defined (STM32F765xx) || defined (STM32F767xx) || defined (STM32F769xx) || defined (STM32F777xx) || defined (STM32F779xx)
/** @brief SYSCFG Break Cortex-M7 Lockup lock.
* Enable and lock the connection of Cortex-M7 LOCKUP (Hardfault) output to TIM1/8 Break input.
* @note The selected configuration is locked and can be unlocked only by system reset.
*/
#define __HAL_SYSCFG_BREAK_LOCKUP_LOCK() SET_BIT(SYSCFG->CBR, SYSCFG_CBR_CLL)
/** @brief SYSCFG Break PVD lock.
* Enable and lock the PVD connection to Timer1/8 Break input, as well as the PVDE and PLS[2:0] in the PWR_CR1 register.
* @note The selected configuration is locked and can be unlocked only by system reset.
*/
#define __HAL_SYSCFG_BREAK_PVD_LOCK() SET_BIT(SYSCFG->CBR, SYSCFG_CBR_PVDL)
#endif /* STM32F765xx || STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */
/**
* @}
*/
/** @defgroup HAL_Private_Macros HAL Private Macros
* @{
*/
#define IS_TICKFREQ(FREQ) (((FREQ) == HAL_TICK_FREQ_10HZ) || \
((FREQ) == HAL_TICK_FREQ_100HZ) || \
((FREQ) == HAL_TICK_FREQ_1KHZ))
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup HAL_Exported_Functions
* @{
*/
/** @addtogroup HAL_Exported_Functions_Group1
* @{
*/
/* Initialization and Configuration functions ******************************/
HAL_StatusTypeDef HAL_Init(void);
HAL_StatusTypeDef HAL_DeInit(void);
void HAL_MspInit(void);
void HAL_MspDeInit(void);
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority);
/**
* @}
*/
/* Exported variables ---------------------------------------------------------*/
/** @addtogroup HAL_Exported_Variables
* @{
*/
extern __IO uint32_t uwTick;
extern uint32_t uwTickPrio;
extern HAL_TickFreqTypeDef uwTickFreq;
/**
* @}
*/
/** @addtogroup HAL_Exported_Functions_Group2
* @{
*/
/* Peripheral Control functions ************************************************/
void HAL_IncTick(void);
void HAL_Delay(uint32_t Delay);
uint32_t HAL_GetTick(void);
uint32_t HAL_GetTickPrio(void);
HAL_StatusTypeDef HAL_SetTickFreq(HAL_TickFreqTypeDef Freq);
HAL_TickFreqTypeDef HAL_GetTickFreq(void);
void HAL_SuspendTick(void);
void HAL_ResumeTick(void);
uint32_t HAL_GetHalVersion(void);
uint32_t HAL_GetREVID(void);
uint32_t HAL_GetDEVID(void);
uint32_t HAL_GetUIDw0(void);
uint32_t HAL_GetUIDw1(void);
uint32_t HAL_GetUIDw2(void);
void HAL_DBGMCU_EnableDBGSleepMode(void);
void HAL_DBGMCU_DisableDBGSleepMode(void);
void HAL_DBGMCU_EnableDBGStopMode(void);
void HAL_DBGMCU_DisableDBGStopMode(void);
void HAL_DBGMCU_EnableDBGStandbyMode(void);
void HAL_DBGMCU_DisableDBGStandbyMode(void);
void HAL_EnableCompensationCell(void);
void HAL_DisableCompensationCell(void);
void HAL_EnableFMCMemorySwapping(void);
void HAL_DisableFMCMemorySwapping(void);
#if defined (STM32F765xx) || defined (STM32F767xx) || defined (STM32F769xx) || defined (STM32F777xx) || defined (STM32F779xx)
void HAL_EnableMemorySwappingBank(void);
void HAL_DisableMemorySwappingBank(void);
#endif /* STM32F765xx || STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */
/**
* @}
*/
/**
* @}
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup HAL_Private_Variables HAL Private Variables
* @{
*/
/**
* @}
*/
/* Private constants ---------------------------------------------------------*/
/** @defgroup HAL_Private_Constants HAL Private Constants
* @{
*/
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __STM32F7xx_HAL_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,305 @@
#pragma once
#define HAL_ETH_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_CORTEX_MODULE_ENABLED
#define HAL_GPIO_MODULE_ENABLED
#include "stm32f7xx.h"
#include "stm32f7xx_hal_cortex.h"
#include "stm32f7xx_hal_def.h"
#include "stm32f7xx_hal_rcc.h"
#include "stm32f7xx_hal_gpio.h"
#define UID_BASE 0x1FF0F420UL
#define __HAL_FLASH_ART_ENABLE() SET_BIT(FLASH->ACR, FLASH_ACR_ARTEN)
#define __HAL_FLASH_PREFETCH_BUFFER_ENABLE() (FLASH->ACR |= FLASH_ACR_PRFTEN)
#define assert_param(expr) ((void) 0U)
#define HAL_MODULE_ENABLED
#define HAL_ADC_MODULE_ENABLED
#define HAL_CAN_MODULE_ENABLED
#define HAL_CEC_MODULE_ENABLED
#define HAL_CRC_MODULE_ENABLED
#define HAL_CRYP_MODULE_ENABLED
#define HAL_DAC_MODULE_ENABLED
#define HAL_DCMI_MODULE_ENABLED
#define HAL_DMA_MODULE_ENABLED
#define HAL_DMA2D_MODULE_ENABLED
#define HAL_ETH_MODULE_ENABLED
#define HAL_FLASH_MODULE_ENABLED
//#define HAL_NAND_MODULE_ENABLED
#define HAL_NOR_MODULE_ENABLED
#define HAL_SRAM_MODULE_ENABLED
#define HAL_SDRAM_MODULE_ENABLED
#define HAL_HASH_MODULE_ENABLED
#define HAL_GPIO_MODULE_ENABLED
#define HAL_I2C_MODULE_ENABLED
//#define HAL_I2S_MODULE_ENABLED
//#define HAL_IWDG_MODULE_ENABLED
#define HAL_LPTIM_MODULE_ENABLED
#define HAL_LTDC_MODULE_ENABLED
#define HAL_PWR_MODULE_ENABLED
#define HAL_QSPI_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_RNG_MODULE_ENABLED
#define HAL_RTC_MODULE_ENABLED
//#define HAL_SAI_MODULE_ENABLED
#define HAL_SD_MODULE_ENABLED
#define HAL_SPI_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED
#define HAL_UART_MODULE_ENABLED
#define HAL_USART_MODULE_ENABLED
#define HAL_IRDA_MODULE_ENABLED
#define HAL_SMARTCARD_MODULE_ENABLED
//#define HAL_WWDG_MODULE_ENABLED
#define HAL_CORTEX_MODULE_ENABLED
//#define HAL_PCD_MODULE_ENABLED
//#define HAL_HCD_MODULE_ENABLED
/* ########################## HSE/HSI Values adaptation ##################### */
/**
* @brief Adjust the value of External High Speed oscillator (HSE) used in your
* application. This value is used by the RCC HAL module to compute the system
* frequency (when HSE is used as system clock source, directly or through the
* PLL).
*/
#if !defined(HSE_VALUE)
#define HSE_VALUE \
((uint32_t) 25000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#if !defined(HSE_STARTUP_TIMEOUT)
#define HSE_STARTUP_TIMEOUT \
((uint32_t) 5000) /*!< Time out for HSE start up, in ms */
#endif /* HSE_STARTUP_TIMEOUT */
/**
* @brief Internal High Speed oscillator (HSI) value.
* This value is used by the RCC HAL module to compute the system
* frequency (when HSI is used as system clock source, directly or through the
* PLL).
*/
#if !defined(HSI_VALUE)
#define HSI_VALUE \
((uint32_t) 16000000) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
/**
* @brief Internal Low Speed oscillator (LSI) value.
*/
#if !defined(LSI_VALUE)
#define LSI_VALUE ((uint32_t) 40000)
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz \
The real value may vary depending on the variations \
in voltage and temperature. */
/**
* @brief External Low Speed oscillator (LSE) value.
*/
#if !defined(LSE_VALUE)
#define LSE_VALUE \
((uint32_t) 32768) /*!< Value of the External Low Speed oscillator in Hz */
#endif /* LSE_VALUE */
/**
* @brief External clock source for I2S peripheral
* This value is used by the I2S HAL module to compute the I2S clock
* source frequency, this source is inserted directly through I2S_CKIN pad.
*/
#if !defined(EXTERNAL_CLOCK_VALUE)
#define EXTERNAL_CLOCK_VALUE \
((uint32_t) 12288000) /*!< Value of the Internal oscillator in Hz*/
#endif /* EXTERNAL_CLOCK_VALUE */
/* Tip: To avoid modifying this file each time you need to use different HSE,
=== you can define the HSE value in your toolchain compiler preprocessor. */
/* ########################### System Configuration ######################### */
/**
* @brief This is the HAL system configuration section
*/
#define VDD_VALUE ((uint32_t) 3300) /*!< Value of VDD in mv */
#define TICK_INT_PRIORITY ((uint32_t) 0x0F) /*!< tick interrupt priority */
#define USE_RTOS 0
#define ART_ACCLERATOR_ENABLE 1 /* To enable instruction cache and prefetch */
/* ########################## Assert Selection ############################## */
/**
* @brief Uncomment the line below to expanse the "assert_param" macro in the
* HAL drivers code
*/
/* #define USE_FULL_ASSERT 1 */
/* ################## Ethernet peripheral configuration ##################### */
/* Section 1 : Ethernet peripheral configuration */
/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */
#define MAC_ADDR0 2
#define MAC_ADDR1 0
#define MAC_ADDR2 0
#define MAC_ADDR3 0
#define MAC_ADDR4 0
#define MAC_ADDR5 0
/* Definition of the Ethernet driver buffers size and count */
#define ETH_RX_BUF_SIZE \
ETH_MAX_PACKET_SIZE /* buffer size for receive */
#define ETH_TX_BUF_SIZE \
ETH_MAX_PACKET_SIZE /* buffer size for transmit */
#define ETH_RXBUFNB ((uint32_t) 8) /* 8 Rx buffers of size ETH_RX_BUF_SIZE */
#define ETH_TXBUFNB ((uint32_t) 4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
/* Section 2: PHY configuration section */
/* DP83848 PHY Address*/
#define DP83848_PHY_ADDRESS 0x01
/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
#define PHY_RESET_DELAY ((uint32_t) 0x000000FF)
/* PHY Configuration delay */
#define PHY_CONFIG_DELAY ((uint32_t) 0x00000FFF)
#define PHY_READ_TO ((uint32_t) 0x0000FFFF)
#define PHY_WRITE_TO ((uint32_t) 0x0000FFFF)
/* Section 3: Common PHY Registers */
#define PHY_BCR ((uint16_t) 0x00) /*!< Transceiver Basic Control Register */
#define PHY_BSR ((uint16_t) 0x01) /*!< Transceiver Basic Status Register */
#define PHY_RESET ((uint16_t) 0x8000) /*!< PHY Reset */
#define PHY_LOOPBACK ((uint16_t) 0x4000) /*!< Select loop-back mode */
#define PHY_FULLDUPLEX_100M \
((uint16_t) 0x2100) /*!< Set the full-duplex mode at 100 Mb/s */
#define PHY_HALFDUPLEX_100M \
((uint16_t) 0x2000) /*!< Set the half-duplex mode at 100 Mb/s */
#define PHY_FULLDUPLEX_10M \
((uint16_t) 0x0100) /*!< Set the full-duplex mode at 10 Mb/s */
#define PHY_HALFDUPLEX_10M \
((uint16_t) 0x0000) /*!< Set the half-duplex mode at 10 Mb/s */
#define PHY_AUTONEGOTIATION \
((uint16_t) 0x1000) /*!< Enable auto-negotiation function */
#define PHY_RESTART_AUTONEGOTIATION \
((uint16_t) 0x0200) /*!< Restart auto-negotiation function */
#define PHY_POWERDOWN \
((uint16_t) 0x0800) /*!< Select the power down mode */
#define PHY_ISOLATE \
((uint16_t) 0x0400) /*!< Isolate PHY from MII */
#define PHY_AUTONEGO_COMPLETE \
((uint16_t) 0x0020) /*!< Auto-Negotiation process completed */
#define PHY_LINKED_STATUS \
((uint16_t) 0x0004) /*!< Valid link established */
#define PHY_JABBER_DETECTION \
((uint16_t) 0x0002) /*!< Jabber condition detected */
/* Section 4: Extended PHY Registers */
#define PHY_SR \
((uint16_t) 0x10) /*!< PHY status register Offset */
#define PHY_MICR \
((uint16_t) 0x11) /*!< MII Interrupt Control Register */
#define PHY_MISR \
((uint16_t) 0x12) /*!< MII Interrupt Status and Misc. Control Register */
#define PHY_LINK_STATUS \
((uint16_t) 0x0001) /*!< PHY Link mask */
#define PHY_SPEED_STATUS \
((uint16_t) 0x0002) /*!< PHY Speed mask */
#define PHY_DUPLEX_STATUS \
((uint16_t) 0x0004) /*!< PHY Duplex mask */
#define PHY_MICR_INT_EN \
((uint16_t) 0x0002) /*!< PHY Enable interrupts */
#define PHY_MICR_INT_OE \
((uint16_t) 0x0001) /*!< PHY Enable output interrupt events */
#define PHY_MISR_LINK_INT_EN \
((uint16_t) 0x0020) /*!< Enable Interrupt on change of link status */
#define PHY_LINK_INTERRUPT \
((uint16_t) 0x2000) /*!< PHY link status interrupt mask */
#if 0
#define HAL_ETH_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_CORTEX_MODULE_ENABLED
#define HAL_GPIO_MODULE_ENABLED
#include "stm32f7xx.h"
#include "stm32f7xx_hal_cortex.h"
#include "stm32f7xx_hal_def.h"
#include "stm32f7xx_hal_rcc.h"
#define UID_BASE 0x1FF0F420UL
#define __HAL_FLASH_ART_ENABLE() SET_BIT(FLASH->ACR, FLASH_ACR_ARTEN)
#define __HAL_FLASH_PREFETCH_BUFFER_ENABLE() (FLASH->ACR |= FLASH_ACR_PRFTEN)
#define ETH_RXBUFNB 3
#define ETH_TXBUFNB 2
#define ETH_RX_BUF_SIZE (ipconfigNETWORK_MTU + 36)
#define ETH_TX_BUF_SIZE (ipconfigNETWORK_MTU + 36)
#define assert_param(expr) ((void) 0U)
#define LAN8742A_PHY_ADDRESS 0x00
#define PHY_RESET_DELAY ((uint32_t)0x00000FFF)
#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF)
#define PHY_READ_TO ((uint32_t)0x0000FFFF)
#define PHY_WRITE_TO ((uint32_t)0x0000FFFF)
#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */
#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */
#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */
#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */
#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */
#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */
#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */
#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */
#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */
#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */
#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */
#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */
#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */
#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */
#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */
#define PHY_SR ((uint16_t)0x1F) /*!< PHY special control/ status register Offset */
#define PHY_SPEED_STATUS ((uint16_t)0x0004) /*!< PHY Speed mask */
#define PHY_DUPLEX_STATUS ((uint16_t)0x0010) /*!< PHY Duplex mask */
#define PHY_ISFR ((uint16_t)0x1D) /*!< PHY Interrupt Source Flag register Offset */
#define PHY_ISFR_INT4 ((uint16_t)0x0010) /*!< PHY Link down inturrupt */
#if !defined(HSE_VALUE)
#define HSE_VALUE \
((uint32_t) 8000000U) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#if !defined(HSE_STARTUP_TIMEOUT)
#define HSE_STARTUP_TIMEOUT \
((uint32_t) 100U) /*!< Time out for HSE start up, in ms */
#endif /* HSE_STARTUP_TIMEOUT */
#if !defined(HSI_VALUE)
#define HSI_VALUE \
((uint32_t) 16000000U) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
#if !defined(LSI_VALUE)
#define LSI_VALUE ((uint32_t) 32000U) /*!< LSI Typical Value in Hz*/
#endif
#if !defined(LSE_VALUE)
#define LSE_VALUE \
((uint32_t) 32768U) /*!< Value of the External Low Speed oscillator in Hz */
#endif /* LSE_VALUE */
#if !defined(LSE_STARTUP_TIMEOUT)
#define LSE_STARTUP_TIMEOUT \
((uint32_t) 5000U) /*!< Time out for LSE start up, in ms */
#endif /* LSE_STARTUP_TIMEOUT */
#if !defined(EXTERNAL_CLOCK_VALUE)
#define EXTERNAL_CLOCK_VALUE \
((uint32_t) 12288000U) /*!< Value of the Internal oscillator in Hz*/
#endif /* EXTERNAL_CLOCK_VALUE */
#define VDD_VALUE ((uint32_t) 3300U) /*!< Value of VDD in mv */
#define TICK_INT_PRIORITY ((uint32_t) 0x0FU) /*!< tick interrupt priority */
#define USE_RTOS 0U
#define PREFETCH_ENABLE 1U
#define ART_ACCLERATOR_ENABLE 1U /* To enable instruction cache and prefetch \
*/
#endif
@@ -0,0 +1,505 @@
/**
******************************************************************************
* @file stm32f7xx_hal_cortex.c
* @author MCD Application Team
* @brief CORTEX HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the CORTEX:
* + Initialization and de-initialization functions
* + Peripheral Control functions
*
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
*** How to configure Interrupts using CORTEX HAL driver ***
===========================================================
[..]
This section provides functions allowing to configure the NVIC interrupts (IRQ).
The Cortex-M4 exceptions are managed by CMSIS functions.
(#) Configure the NVIC Priority Grouping using HAL_NVIC_SetPriorityGrouping()
function according to the following table.
(#) Configure the priority of the selected IRQ Channels using HAL_NVIC_SetPriority().
(#) Enable the selected IRQ Channels using HAL_NVIC_EnableIRQ().
(#) please refer to programming manual for details in how to configure priority.
-@- When the NVIC_PRIORITYGROUP_0 is selected, IRQ preemption is no more possible.
The pending IRQ priority will be managed only by the sub priority.
-@- IRQ priority order (sorted by highest to lowest priority):
(+@) Lowest preemption priority
(+@) Lowest sub priority
(+@) Lowest hardware priority (IRQ number)
[..]
*** How to configure Systick using CORTEX HAL driver ***
========================================================
[..]
Setup SysTick Timer for time base.
(+) The HAL_SYSTICK_Config() function calls the SysTick_Config() function which
is a CMSIS function that:
(++) Configures the SysTick Reload register with value passed as function parameter.
(++) Configures the SysTick IRQ priority to the lowest value (0x0F).
(++) Resets the SysTick Counter register.
(++) Configures the SysTick Counter clock source to be Core Clock Source (HCLK).
(++) Enables the SysTick Interrupt.
(++) Starts the SysTick Counter.
(+) You can change the SysTick Clock source to be HCLK_Div8 by calling the macro
__HAL_CORTEX_SYSTICKCLK_CONFIG(SYSTICK_CLKSOURCE_HCLK_DIV8) just after the
HAL_SYSTICK_Config() function call. The __HAL_CORTEX_SYSTICKCLK_CONFIG() macro is defined
inside the stm32f7xx_hal_cortex.h file.
(+) You can change the SysTick IRQ priority by calling the
HAL_NVIC_SetPriority(SysTick_IRQn,...) function just after the HAL_SYSTICK_Config() function
call. The HAL_NVIC_SetPriority() call the NVIC_SetPriority() function which is a CMSIS function.
(+) To adjust the SysTick time base, use the following formula:
Reload Value = SysTick Counter Clock (Hz) x Desired Time base (s)
(++) Reload Value is the parameter to be passed for HAL_SYSTICK_Config() function
(++) Reload Value should not exceed 0xFFFFFF
@endverbatim
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f7xx_hal.h"
/** @addtogroup STM32F7xx_HAL_Driver
* @{
*/
/** @defgroup CORTEX CORTEX
* @brief CORTEX HAL module driver
* @{
*/
#ifdef HAL_CORTEX_MODULE_ENABLED
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup CORTEX_Exported_Functions CORTEX Exported Functions
* @{
*/
/** @defgroup CORTEX_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
==============================================================================
##### Initialization and de-initialization functions #####
==============================================================================
[..]
This section provides the CORTEX HAL driver functions allowing to configure Interrupts
Systick functionalities
@endverbatim
* @{
*/
/**
* @brief Sets the priority grouping field (preemption priority and subpriority)
* using the required unlock sequence.
* @param PriorityGroup The priority grouping bits length.
* This parameter can be one of the following values:
* @arg NVIC_PRIORITYGROUP_0: 0 bits for preemption priority
* 4 bits for subpriority
* @arg NVIC_PRIORITYGROUP_1: 1 bits for preemption priority
* 3 bits for subpriority
* @arg NVIC_PRIORITYGROUP_2: 2 bits for preemption priority
* 2 bits for subpriority
* @arg NVIC_PRIORITYGROUP_3: 3 bits for preemption priority
* 1 bits for subpriority
* @arg NVIC_PRIORITYGROUP_4: 4 bits for preemption priority
* 0 bits for subpriority
* @note When the NVIC_PriorityGroup_0 is selected, IRQ preemption is no more possible.
* The pending IRQ priority will be managed only by the subpriority.
* @retval None
*/
void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
{
/* Check the parameters */
assert_param(IS_NVIC_PRIORITY_GROUP(PriorityGroup));
/* Set the PRIGROUP[10:8] bits according to the PriorityGroup parameter value */
NVIC_SetPriorityGrouping(PriorityGroup);
}
/**
* @brief Sets the priority of an interrupt.
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f7xxxx.h))
* @param PreemptPriority The preemption priority for the IRQn channel.
* This parameter can be a value between 0 and 15
* A lower priority value indicates a higher priority
* @param SubPriority the subpriority level for the IRQ channel.
* This parameter can be a value between 0 and 15
* A lower priority value indicates a higher priority.
* @retval None
*/
void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)
{
uint32_t prioritygroup = 0x00;
/* Check the parameters */
assert_param(IS_NVIC_SUB_PRIORITY(SubPriority));
assert_param(IS_NVIC_PREEMPTION_PRIORITY(PreemptPriority));
prioritygroup = NVIC_GetPriorityGrouping();
NVIC_SetPriority(IRQn, NVIC_EncodePriority(prioritygroup, PreemptPriority, SubPriority));
}
/**
* @brief Enables a device specific interrupt in the NVIC interrupt controller.
* @note To configure interrupts priority correctly, the NVIC_PriorityGroupConfig()
* function should be called before.
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f7xxxx.h))
* @retval None
*/
void HAL_NVIC_EnableIRQ(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Enable interrupt */
NVIC_EnableIRQ(IRQn);
}
/**
* @brief Disables a device specific interrupt in the NVIC interrupt controller.
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f7xxxx.h))
* @retval None
*/
void HAL_NVIC_DisableIRQ(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Disable interrupt */
NVIC_DisableIRQ(IRQn);
}
/**
* @brief Initiates a system reset request to reset the MCU.
* @retval None
*/
void HAL_NVIC_SystemReset(void)
{
/* System Reset */
NVIC_SystemReset();
}
/**
* @brief Initializes the System Timer and its interrupt, and starts the System Tick Timer.
* Counter is in free running mode to generate periodic interrupts.
* @param TicksNumb Specifies the ticks Number of ticks between two interrupts.
* @retval status: - 0 Function succeeded.
* - 1 Function failed.
*/
uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb)
{
return SysTick_Config(TicksNumb);
}
/**
* @}
*/
/** @defgroup CORTEX_Exported_Functions_Group2 Peripheral Control functions
* @brief Cortex control functions
*
@verbatim
==============================================================================
##### Peripheral Control functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to control the CORTEX
(NVIC, SYSTICK, MPU) functionalities.
@endverbatim
* @{
*/
#if (__MPU_PRESENT == 1)
/**
* @brief Disables the MPU
* @retval None
*/
void HAL_MPU_Disable(void)
{
/* Make sure outstanding transfers are done */
__DMB();
/* Disable fault exceptions */
SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
/* Disable the MPU and clear the control register*/
MPU->CTRL = 0;
}
/**
* @brief Enables the MPU
* @param MPU_Control Specifies the control mode of the MPU during hard fault,
* NMI, FAULTMASK and privileged access to the default memory
* This parameter can be one of the following values:
* @arg MPU_HFNMI_PRIVDEF_NONE
* @arg MPU_HARDFAULT_NMI
* @arg MPU_PRIVILEGED_DEFAULT
* @arg MPU_HFNMI_PRIVDEF
* @retval None
*/
void HAL_MPU_Enable(uint32_t MPU_Control)
{
/* Enable the MPU */
MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk;
/* Enable fault exceptions */
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
/* Ensure MPU setting take effects */
__DSB();
__ISB();
}
/**
* @brief Initializes and configures the Region and the memory to be protected.
* @param MPU_Init Pointer to a MPU_Region_InitTypeDef structure that contains
* the initialization and configuration information.
* @retval None
*/
void HAL_MPU_ConfigRegion(MPU_Region_InitTypeDef *MPU_Init)
{
/* Check the parameters */
assert_param(IS_MPU_REGION_NUMBER(MPU_Init->Number));
assert_param(IS_MPU_REGION_ENABLE(MPU_Init->Enable));
/* Set the Region number */
MPU->RNR = MPU_Init->Number;
if ((MPU_Init->Enable) != RESET)
{
/* Check the parameters */
assert_param(IS_MPU_INSTRUCTION_ACCESS(MPU_Init->DisableExec));
assert_param(IS_MPU_REGION_PERMISSION_ATTRIBUTE(MPU_Init->AccessPermission));
assert_param(IS_MPU_TEX_LEVEL(MPU_Init->TypeExtField));
assert_param(IS_MPU_ACCESS_SHAREABLE(MPU_Init->IsShareable));
assert_param(IS_MPU_ACCESS_CACHEABLE(MPU_Init->IsCacheable));
assert_param(IS_MPU_ACCESS_BUFFERABLE(MPU_Init->IsBufferable));
assert_param(IS_MPU_SUB_REGION_DISABLE(MPU_Init->SubRegionDisable));
assert_param(IS_MPU_REGION_SIZE(MPU_Init->Size));
MPU->RBAR = MPU_Init->BaseAddress;
MPU->RASR = ((uint32_t)MPU_Init->DisableExec << MPU_RASR_XN_Pos) |
((uint32_t)MPU_Init->AccessPermission << MPU_RASR_AP_Pos) |
((uint32_t)MPU_Init->TypeExtField << MPU_RASR_TEX_Pos) |
((uint32_t)MPU_Init->IsShareable << MPU_RASR_S_Pos) |
((uint32_t)MPU_Init->IsCacheable << MPU_RASR_C_Pos) |
((uint32_t)MPU_Init->IsBufferable << MPU_RASR_B_Pos) |
((uint32_t)MPU_Init->SubRegionDisable << MPU_RASR_SRD_Pos) |
((uint32_t)MPU_Init->Size << MPU_RASR_SIZE_Pos) |
((uint32_t)MPU_Init->Enable << MPU_RASR_ENABLE_Pos);
}
else
{
MPU->RBAR = 0x00;
MPU->RASR = 0x00;
}
}
#endif /* __MPU_PRESENT */
/**
* @brief Gets the priority grouping field from the NVIC Interrupt Controller.
* @retval Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field)
*/
uint32_t HAL_NVIC_GetPriorityGrouping(void)
{
/* Get the PRIGROUP[10:8] field value */
return NVIC_GetPriorityGrouping();
}
/**
* @brief Gets the priority of an interrupt.
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f7xxxx.h))
* @param PriorityGroup the priority grouping bits length.
* This parameter can be one of the following values:
* @arg NVIC_PRIORITYGROUP_0: 0 bits for preemption priority
* 4 bits for subpriority
* @arg NVIC_PRIORITYGROUP_1: 1 bits for preemption priority
* 3 bits for subpriority
* @arg NVIC_PRIORITYGROUP_2: 2 bits for preemption priority
* 2 bits for subpriority
* @arg NVIC_PRIORITYGROUP_3: 3 bits for preemption priority
* 1 bits for subpriority
* @arg NVIC_PRIORITYGROUP_4: 4 bits for preemption priority
* 0 bits for subpriority
* @param pPreemptPriority Pointer on the Preemptive priority value (starting from 0).
* @param pSubPriority Pointer on the Subpriority value (starting from 0).
* @retval None
*/
void HAL_NVIC_GetPriority(IRQn_Type IRQn, uint32_t PriorityGroup, uint32_t *pPreemptPriority, uint32_t *pSubPriority)
{
/* Check the parameters */
assert_param(IS_NVIC_PRIORITY_GROUP(PriorityGroup));
/* Get priority for Cortex-M system or device specific interrupts */
NVIC_DecodePriority(NVIC_GetPriority(IRQn), PriorityGroup, pPreemptPriority, pSubPriority);
}
/**
* @brief Sets Pending bit of an external interrupt.
* @param IRQn External interrupt number
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f7xxxx.h))
* @retval None
*/
void HAL_NVIC_SetPendingIRQ(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Set interrupt pending */
NVIC_SetPendingIRQ(IRQn);
}
/**
* @brief Gets Pending Interrupt (reads the pending register in the NVIC
* and returns the pending bit for the specified interrupt).
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f7xxxx.h))
* @retval status: - 0 Interrupt status is not pending.
* - 1 Interrupt status is pending.
*/
uint32_t HAL_NVIC_GetPendingIRQ(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Return 1 if pending else 0 */
return NVIC_GetPendingIRQ(IRQn);
}
/**
* @brief Clears the pending bit of an external interrupt.
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f7xxxx.h))
* @retval None
*/
void HAL_NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Clear pending interrupt */
NVIC_ClearPendingIRQ(IRQn);
}
/**
* @brief Gets active interrupt ( reads the active register in NVIC and returns the active bit).
* @param IRQn External interrupt number
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f7xxxx.h))
* @retval status: - 0 Interrupt status is not pending.
* - 1 Interrupt status is pending.
*/
uint32_t HAL_NVIC_GetActive(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Return 1 if active else 0 */
return NVIC_GetActive(IRQn);
}
/**
* @brief Configures the SysTick clock source.
* @param CLKSource specifies the SysTick clock source.
* This parameter can be one of the following values:
* @arg SYSTICK_CLKSOURCE_HCLK_DIV8: AHB clock divided by 8 selected as SysTick clock source.
* @arg SYSTICK_CLKSOURCE_HCLK: AHB clock selected as SysTick clock source.
* @retval None
*/
void HAL_SYSTICK_CLKSourceConfig(uint32_t CLKSource)
{
/* Check the parameters */
assert_param(IS_SYSTICK_CLK_SOURCE(CLKSource));
if (CLKSource == SYSTICK_CLKSOURCE_HCLK)
{
SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK;
}
else
{
SysTick->CTRL &= ~SYSTICK_CLKSOURCE_HCLK;
}
}
/**
* @brief This function handles SYSTICK interrupt request.
* @retval None
*/
void HAL_SYSTICK_IRQHandler(void)
{
HAL_SYSTICK_Callback();
}
/**
* @brief SYSTICK callback.
* @retval None
*/
__weak void HAL_SYSTICK_Callback(void)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_SYSTICK_Callback could be implemented in the user file
*/
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_CORTEX_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,406 @@
/**
******************************************************************************
* @file stm32f7xx_hal_cortex.h
* @author MCD Application Team
* @brief Header file of CORTEX HAL module.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F7xx_HAL_CORTEX_H
#define __STM32F7xx_HAL_CORTEX_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f7xx_hal_def.h"
/** @addtogroup STM32F7xx_HAL_Driver
* @{
*/
/** @addtogroup CORTEX
* @{
*/
/* Exported types ------------------------------------------------------------*/
/** @defgroup CORTEX_Exported_Types Cortex Exported Types
* @{
*/
#if (__MPU_PRESENT == 1)
/** @defgroup CORTEX_MPU_Region_Initialization_Structure_definition MPU Region Initialization Structure Definition
* @brief MPU Region initialization structure
* @{
*/
typedef struct
{
uint8_t Enable; /*!< Specifies the status of the region.
This parameter can be a value of @ref CORTEX_MPU_Region_Enable */
uint8_t Number; /*!< Specifies the number of the region to protect.
This parameter can be a value of @ref CORTEX_MPU_Region_Number */
uint32_t BaseAddress; /*!< Specifies the base address of the region to protect. */
uint8_t Size; /*!< Specifies the size of the region to protect.
This parameter can be a value of @ref CORTEX_MPU_Region_Size */
uint8_t SubRegionDisable; /*!< Specifies the number of the subregion protection to disable.
This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFF */
uint8_t TypeExtField; /*!< Specifies the TEX field level.
This parameter can be a value of @ref CORTEX_MPU_TEX_Levels */
uint8_t AccessPermission; /*!< Specifies the region access permission type.
This parameter can be a value of @ref CORTEX_MPU_Region_Permission_Attributes */
uint8_t DisableExec; /*!< Specifies the instruction access status.
This parameter can be a value of @ref CORTEX_MPU_Instruction_Access */
uint8_t IsShareable; /*!< Specifies the shareability status of the protected region.
This parameter can be a value of @ref CORTEX_MPU_Access_Shareable */
uint8_t IsCacheable; /*!< Specifies the cacheable status of the region protected.
This parameter can be a value of @ref CORTEX_MPU_Access_Cacheable */
uint8_t IsBufferable; /*!< Specifies the bufferable status of the protected region.
This parameter can be a value of @ref CORTEX_MPU_Access_Bufferable */
}MPU_Region_InitTypeDef;
/**
* @}
*/
#endif /* __MPU_PRESENT */
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup CORTEX_Exported_Constants CORTEX Exported Constants
* @{
*/
/** @defgroup CORTEX_Preemption_Priority_Group CORTEX Preemption Priority Group
* @{
*/
#define NVIC_PRIORITYGROUP_0 ((uint32_t)0x00000007U) /*!< 0 bits for pre-emption priority
4 bits for subpriority */
#define NVIC_PRIORITYGROUP_1 ((uint32_t)0x00000006U) /*!< 1 bits for pre-emption priority
3 bits for subpriority */
#define NVIC_PRIORITYGROUP_2 ((uint32_t)0x00000005U) /*!< 2 bits for pre-emption priority
2 bits for subpriority */
#define NVIC_PRIORITYGROUP_3 ((uint32_t)0x00000004U) /*!< 3 bits for pre-emption priority
1 bits for subpriority */
#define NVIC_PRIORITYGROUP_4 ((uint32_t)0x00000003U) /*!< 4 bits for pre-emption priority
0 bits for subpriority */
/**
* @}
*/
/** @defgroup CORTEX_SysTick_clock_source CORTEX _SysTick clock source
* @{
*/
#define SYSTICK_CLKSOURCE_HCLK_DIV8 ((uint32_t)0x00000000U)
#define SYSTICK_CLKSOURCE_HCLK ((uint32_t)0x00000004U)
/**
* @}
*/
#if (__MPU_PRESENT == 1)
/** @defgroup CORTEX_MPU_HFNMI_PRIVDEF_Control MPU HFNMI and PRIVILEGED Access control
* @{
*/
#define MPU_HFNMI_PRIVDEF_NONE ((uint32_t)0x00000000U)
#define MPU_HARDFAULT_NMI ((uint32_t)0x00000002U)
#define MPU_PRIVILEGED_DEFAULT ((uint32_t)0x00000004U)
#define MPU_HFNMI_PRIVDEF ((uint32_t)0x00000006U)
/**
* @}
*/
/** @defgroup CORTEX_MPU_Region_Enable CORTEX MPU Region Enable
* @{
*/
#define MPU_REGION_ENABLE ((uint8_t)0x01U)
#define MPU_REGION_DISABLE ((uint8_t)0x00U)
/**
* @}
*/
/** @defgroup CORTEX_MPU_Instruction_Access CORTEX MPU Instruction Access
* @{
*/
#define MPU_INSTRUCTION_ACCESS_ENABLE ((uint8_t)0x00U)
#define MPU_INSTRUCTION_ACCESS_DISABLE ((uint8_t)0x01U)
/**
* @}
*/
/** @defgroup CORTEX_MPU_Access_Shareable CORTEX MPU Instruction Access Shareable
* @{
*/
#define MPU_ACCESS_SHAREABLE ((uint8_t)0x01U)
#define MPU_ACCESS_NOT_SHAREABLE ((uint8_t)0x00U)
/**
* @}
*/
/** @defgroup CORTEX_MPU_Access_Cacheable CORTEX MPU Instruction Access Cacheable
* @{
*/
#define MPU_ACCESS_CACHEABLE ((uint8_t)0x01U)
#define MPU_ACCESS_NOT_CACHEABLE ((uint8_t)0x00U)
/**
* @}
*/
/** @defgroup CORTEX_MPU_Access_Bufferable CORTEX MPU Instruction Access Bufferable
* @{
*/
#define MPU_ACCESS_BUFFERABLE ((uint8_t)0x01U)
#define MPU_ACCESS_NOT_BUFFERABLE ((uint8_t)0x00U)
/**
* @}
*/
/** @defgroup CORTEX_MPU_TEX_Levels MPU TEX Levels
* @{
*/
#define MPU_TEX_LEVEL0 ((uint8_t)0x00U)
#define MPU_TEX_LEVEL1 ((uint8_t)0x01U)
#define MPU_TEX_LEVEL2 ((uint8_t)0x02U)
/**
* @}
*/
/** @defgroup CORTEX_MPU_Region_Size CORTEX MPU Region Size
* @{
*/
#define MPU_REGION_SIZE_32B ((uint8_t)0x04U)
#define MPU_REGION_SIZE_64B ((uint8_t)0x05U)
#define MPU_REGION_SIZE_128B ((uint8_t)0x06U)
#define MPU_REGION_SIZE_256B ((uint8_t)0x07U)
#define MPU_REGION_SIZE_512B ((uint8_t)0x08U)
#define MPU_REGION_SIZE_1KB ((uint8_t)0x09U)
#define MPU_REGION_SIZE_2KB ((uint8_t)0x0AU)
#define MPU_REGION_SIZE_4KB ((uint8_t)0x0BU)
#define MPU_REGION_SIZE_8KB ((uint8_t)0x0CU)
#define MPU_REGION_SIZE_16KB ((uint8_t)0x0DU)
#define MPU_REGION_SIZE_32KB ((uint8_t)0x0EU)
#define MPU_REGION_SIZE_64KB ((uint8_t)0x0FU)
#define MPU_REGION_SIZE_128KB ((uint8_t)0x10U)
#define MPU_REGION_SIZE_256KB ((uint8_t)0x11U)
#define MPU_REGION_SIZE_512KB ((uint8_t)0x12U)
#define MPU_REGION_SIZE_1MB ((uint8_t)0x13U)
#define MPU_REGION_SIZE_2MB ((uint8_t)0x14U)
#define MPU_REGION_SIZE_4MB ((uint8_t)0x15U)
#define MPU_REGION_SIZE_8MB ((uint8_t)0x16U)
#define MPU_REGION_SIZE_16MB ((uint8_t)0x17U)
#define MPU_REGION_SIZE_32MB ((uint8_t)0x18U)
#define MPU_REGION_SIZE_64MB ((uint8_t)0x19U)
#define MPU_REGION_SIZE_128MB ((uint8_t)0x1AU)
#define MPU_REGION_SIZE_256MB ((uint8_t)0x1BU)
#define MPU_REGION_SIZE_512MB ((uint8_t)0x1CU)
#define MPU_REGION_SIZE_1GB ((uint8_t)0x1DU)
#define MPU_REGION_SIZE_2GB ((uint8_t)0x1EU)
#define MPU_REGION_SIZE_4GB ((uint8_t)0x1FU)
/**
* @}
*/
/** @defgroup CORTEX_MPU_Region_Permission_Attributes CORTEX MPU Region Permission Attributes
* @{
*/
#define MPU_REGION_NO_ACCESS ((uint8_t)0x00U)
#define MPU_REGION_PRIV_RW ((uint8_t)0x01U)
#define MPU_REGION_PRIV_RW_URO ((uint8_t)0x02U)
#define MPU_REGION_FULL_ACCESS ((uint8_t)0x03U)
#define MPU_REGION_PRIV_RO ((uint8_t)0x05U)
#define MPU_REGION_PRIV_RO_URO ((uint8_t)0x06U)
/**
* @}
*/
/** @defgroup CORTEX_MPU_Region_Number CORTEX MPU Region Number
* @{
*/
#define MPU_REGION_NUMBER0 ((uint8_t)0x00U)
#define MPU_REGION_NUMBER1 ((uint8_t)0x01U)
#define MPU_REGION_NUMBER2 ((uint8_t)0x02U)
#define MPU_REGION_NUMBER3 ((uint8_t)0x03U)
#define MPU_REGION_NUMBER4 ((uint8_t)0x04U)
#define MPU_REGION_NUMBER5 ((uint8_t)0x05U)
#define MPU_REGION_NUMBER6 ((uint8_t)0x06U)
#define MPU_REGION_NUMBER7 ((uint8_t)0x07U)
/**
* @}
*/
#endif /* __MPU_PRESENT */
/**
* @}
*/
/* Exported Macros -----------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup CORTEX_Exported_Functions
* @{
*/
/** @addtogroup CORTEX_Exported_Functions_Group1
* @{
*/
/* Initialization and de-initialization functions *****************************/
void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup);
void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority);
void HAL_NVIC_EnableIRQ(IRQn_Type IRQn);
void HAL_NVIC_DisableIRQ(IRQn_Type IRQn);
void HAL_NVIC_SystemReset(void);
uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb);
/**
* @}
*/
/** @addtogroup CORTEX_Exported_Functions_Group2
* @{
*/
/* Peripheral Control functions ***********************************************/
#if (__MPU_PRESENT == 1)
void HAL_MPU_Enable(uint32_t MPU_Control);
void HAL_MPU_Disable(void);
void HAL_MPU_ConfigRegion(MPU_Region_InitTypeDef *MPU_Init);
#endif /* __MPU_PRESENT */
uint32_t HAL_NVIC_GetPriorityGrouping(void);
void HAL_NVIC_GetPriority(IRQn_Type IRQn, uint32_t PriorityGroup, uint32_t* pPreemptPriority, uint32_t* pSubPriority);
uint32_t HAL_NVIC_GetPendingIRQ(IRQn_Type IRQn);
void HAL_NVIC_SetPendingIRQ(IRQn_Type IRQn);
void HAL_NVIC_ClearPendingIRQ(IRQn_Type IRQn);
uint32_t HAL_NVIC_GetActive(IRQn_Type IRQn);
void HAL_SYSTICK_CLKSourceConfig(uint32_t CLKSource);
void HAL_SYSTICK_IRQHandler(void);
void HAL_SYSTICK_Callback(void);
/**
* @}
*/
/**
* @}
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup CORTEX_Private_Macros CORTEX Private Macros
* @{
*/
#define IS_NVIC_PRIORITY_GROUP(GROUP) (((GROUP) == NVIC_PRIORITYGROUP_0) || \
((GROUP) == NVIC_PRIORITYGROUP_1) || \
((GROUP) == NVIC_PRIORITYGROUP_2) || \
((GROUP) == NVIC_PRIORITYGROUP_3) || \
((GROUP) == NVIC_PRIORITYGROUP_4))
#define IS_NVIC_PREEMPTION_PRIORITY(PRIORITY) ((PRIORITY) < 0x10U)
#define IS_NVIC_SUB_PRIORITY(PRIORITY) ((PRIORITY) < 0x10U)
#define IS_NVIC_DEVICE_IRQ(IRQ) ((IRQ) >= 0x00)
#define IS_SYSTICK_CLK_SOURCE(SOURCE) (((SOURCE) == SYSTICK_CLKSOURCE_HCLK) || \
((SOURCE) == SYSTICK_CLKSOURCE_HCLK_DIV8))
#if (__MPU_PRESENT == 1)
#define IS_MPU_REGION_ENABLE(STATE) (((STATE) == MPU_REGION_ENABLE) || \
((STATE) == MPU_REGION_DISABLE))
#define IS_MPU_INSTRUCTION_ACCESS(STATE) (((STATE) == MPU_INSTRUCTION_ACCESS_ENABLE) || \
((STATE) == MPU_INSTRUCTION_ACCESS_DISABLE))
#define IS_MPU_ACCESS_SHAREABLE(STATE) (((STATE) == MPU_ACCESS_SHAREABLE) || \
((STATE) == MPU_ACCESS_NOT_SHAREABLE))
#define IS_MPU_ACCESS_CACHEABLE(STATE) (((STATE) == MPU_ACCESS_CACHEABLE) || \
((STATE) == MPU_ACCESS_NOT_CACHEABLE))
#define IS_MPU_ACCESS_BUFFERABLE(STATE) (((STATE) == MPU_ACCESS_BUFFERABLE) || \
((STATE) == MPU_ACCESS_NOT_BUFFERABLE))
#define IS_MPU_TEX_LEVEL(TYPE) (((TYPE) == MPU_TEX_LEVEL0) || \
((TYPE) == MPU_TEX_LEVEL1) || \
((TYPE) == MPU_TEX_LEVEL2))
#define IS_MPU_REGION_PERMISSION_ATTRIBUTE(TYPE) (((TYPE) == MPU_REGION_NO_ACCESS) || \
((TYPE) == MPU_REGION_PRIV_RW) || \
((TYPE) == MPU_REGION_PRIV_RW_URO) || \
((TYPE) == MPU_REGION_FULL_ACCESS) || \
((TYPE) == MPU_REGION_PRIV_RO) || \
((TYPE) == MPU_REGION_PRIV_RO_URO))
#define IS_MPU_REGION_NUMBER(NUMBER) (((NUMBER) == MPU_REGION_NUMBER0) || \
((NUMBER) == MPU_REGION_NUMBER1) || \
((NUMBER) == MPU_REGION_NUMBER2) || \
((NUMBER) == MPU_REGION_NUMBER3) || \
((NUMBER) == MPU_REGION_NUMBER4) || \
((NUMBER) == MPU_REGION_NUMBER5) || \
((NUMBER) == MPU_REGION_NUMBER6) || \
((NUMBER) == MPU_REGION_NUMBER7))
#define IS_MPU_REGION_SIZE(SIZE) (((SIZE) == MPU_REGION_SIZE_32B) || \
((SIZE) == MPU_REGION_SIZE_64B) || \
((SIZE) == MPU_REGION_SIZE_128B) || \
((SIZE) == MPU_REGION_SIZE_256B) || \
((SIZE) == MPU_REGION_SIZE_512B) || \
((SIZE) == MPU_REGION_SIZE_1KB) || \
((SIZE) == MPU_REGION_SIZE_2KB) || \
((SIZE) == MPU_REGION_SIZE_4KB) || \
((SIZE) == MPU_REGION_SIZE_8KB) || \
((SIZE) == MPU_REGION_SIZE_16KB) || \
((SIZE) == MPU_REGION_SIZE_32KB) || \
((SIZE) == MPU_REGION_SIZE_64KB) || \
((SIZE) == MPU_REGION_SIZE_128KB) || \
((SIZE) == MPU_REGION_SIZE_256KB) || \
((SIZE) == MPU_REGION_SIZE_512KB) || \
((SIZE) == MPU_REGION_SIZE_1MB) || \
((SIZE) == MPU_REGION_SIZE_2MB) || \
((SIZE) == MPU_REGION_SIZE_4MB) || \
((SIZE) == MPU_REGION_SIZE_8MB) || \
((SIZE) == MPU_REGION_SIZE_16MB) || \
((SIZE) == MPU_REGION_SIZE_32MB) || \
((SIZE) == MPU_REGION_SIZE_64MB) || \
((SIZE) == MPU_REGION_SIZE_128MB) || \
((SIZE) == MPU_REGION_SIZE_256MB) || \
((SIZE) == MPU_REGION_SIZE_512MB) || \
((SIZE) == MPU_REGION_SIZE_1GB) || \
((SIZE) == MPU_REGION_SIZE_2GB) || \
((SIZE) == MPU_REGION_SIZE_4GB))
#define IS_MPU_SUB_REGION_DISABLE(SUBREGION) ((SUBREGION) < (uint16_t)0x00FFU)
#endif /* __MPU_PRESENT */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __STM32F7xx_HAL_CORTEX_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,219 @@
/**
******************************************************************************
* @file stm32f7xx_hal_def.h
* @author MCD Application Team
* @brief This file contains HAL common defines, enumeration, macros and
* structures definitions.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F7xx_HAL_DEF
#define __STM32F7xx_HAL_DEF
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f7xx.h"
#include "Legacy/stm32_hal_legacy.h"
#include <stddef.h>
/* Exported types ------------------------------------------------------------*/
/**
* @brief HAL Status structures definition
*/
typedef enum
{
HAL_OK = 0x00U,
HAL_ERROR = 0x01U,
HAL_BUSY = 0x02U,
HAL_TIMEOUT = 0x03U
} HAL_StatusTypeDef;
/**
* @brief HAL Lock structures definition
*/
typedef enum
{
HAL_UNLOCKED = 0x00U,
HAL_LOCKED = 0x01U
} HAL_LockTypeDef;
/* Exported macro ------------------------------------------------------------*/
#define UNUSED(X) (void)X /* To avoid gcc/g++ warnings */
#define HAL_MAX_DELAY 0xFFFFFFFFU
#define HAL_IS_BIT_SET(REG, BIT) (((REG) & (BIT)) == (BIT))
#define HAL_IS_BIT_CLR(REG, BIT) (((REG) & (BIT)) == 0U)
#define __HAL_LINKDMA(__HANDLE__, __PPP_DMA_FIELD__, __DMA_HANDLE__) \
do{ \
(__HANDLE__)->__PPP_DMA_FIELD__ = &(__DMA_HANDLE__); \
(__DMA_HANDLE__).Parent = (__HANDLE__); \
} while(0)
/** @brief Reset the Handle's State field.
* @param __HANDLE__ specifies the Peripheral Handle.
* @note This macro can be used for the following purpose:
* - When the Handle is declared as local variable; before passing it as parameter
* to HAL_PPP_Init() for the first time, it is mandatory to use this macro
* to set to 0 the Handle's "State" field.
* Otherwise, "State" field may have any random value and the first time the function
* HAL_PPP_Init() is called, the low level hardware initialization will be missed
* (i.e. HAL_PPP_MspInit() will not be executed).
* - When there is a need to reconfigure the low level hardware: instead of calling
* HAL_PPP_DeInit() then HAL_PPP_Init(), user can make a call to this macro then HAL_PPP_Init().
* In this later function, when the Handle's "State" field is set to 0, it will execute the function
* HAL_PPP_MspInit() which will reconfigure the low level hardware.
* @retval None
*/
#define __HAL_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = 0U)
#if (USE_RTOS == 1U)
/* Reserved for future use */
#error "USE_RTOS should be 0 in the current HAL release"
#else
#define __HAL_LOCK(__HANDLE__) \
do{ \
if((__HANDLE__)->Lock == HAL_LOCKED) \
{ \
return HAL_BUSY; \
} \
else \
{ \
(__HANDLE__)->Lock = HAL_LOCKED; \
} \
}while (0U)
#define __HAL_UNLOCK(__HANDLE__) \
do{ \
(__HANDLE__)->Lock = HAL_UNLOCKED; \
}while (0U)
#endif /* USE_RTOS */
#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
#ifndef __weak
#define __weak __attribute__((weak))
#endif
#ifndef __packed
#define __packed __attribute__((packed))
#endif
#elif defined ( __GNUC__ ) && !defined (__CC_ARM) /* GNU Compiler */
#ifndef __weak
#define __weak __attribute__((weak))
#endif /* __weak */
#ifndef __packed
#define __packed __attribute__((__packed__))
#endif /* __packed */
#endif /* __GNUC__ */
/* Macro to get variable aligned on 4-bytes, for __ICCARM__ the directive "#pragma data_alignment=4" must be used instead */
#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
#ifndef __ALIGN_BEGIN
#define __ALIGN_BEGIN
#endif
#ifndef __ALIGN_END
#define __ALIGN_END __attribute__ ((aligned (4)))
#endif
#elif defined ( __GNUC__ ) && !defined (__CC_ARM) /* GNU Compiler */
#ifndef __ALIGN_END
#define __ALIGN_END __attribute__ ((aligned (4)))
#endif /* __ALIGN_END */
#ifndef __ALIGN_BEGIN
#define __ALIGN_BEGIN
#endif /* __ALIGN_BEGIN */
#else
#ifndef __ALIGN_END
#define __ALIGN_END
#endif /* __ALIGN_END */
#ifndef __ALIGN_BEGIN
#if defined (__CC_ARM) /* ARM Compiler V5*/
#define __ALIGN_BEGIN __align(4)
#elif defined (__ICCARM__) /* IAR Compiler */
#define __ALIGN_BEGIN
#endif /* __CC_ARM */
#endif /* __ALIGN_BEGIN */
#endif /* __GNUC__ */
/* Macro to get variable aligned on 32-bytes,needed for cache maintenance purpose */
#if defined (__GNUC__) /* GNU Compiler */
#define ALIGN_32BYTES(buf) buf __attribute__ ((aligned (32)))
#elif defined (__ICCARM__) /* IAR Compiler */
#define ALIGN_32BYTES(buf) _Pragma("data_alignment=32") buf
#elif defined (__CC_ARM) /* ARM Compiler */
#define ALIGN_32BYTES(buf) __align(32) buf
#endif
/**
* @brief __RAM_FUNC definition
*/
#if defined ( __CC_ARM ) || (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
/* ARM Compiler V4/V5 and V6
--------------------------
RAM functions are defined using the toolchain options.
Functions that are executed in RAM should reside in a separate source module.
Using the 'Options for File' dialog you can simply change the 'Code / Const'
area of a module to a memory space in physical RAM.
Available memory areas are declared in the 'Target' tab of the 'Options for Target'
dialog.
*/
#define __RAM_FUNC
#elif defined ( __ICCARM__ )
/* ICCARM Compiler
---------------
RAM functions are defined using a specific toolchain keyword "__ramfunc".
*/
#define __RAM_FUNC __ramfunc
#elif defined ( __GNUC__ )
/* GNU Compiler
------------
RAM functions are defined using a specific toolchain attribute
"__attribute__((section(".RamFunc")))".
*/
#define __RAM_FUNC __attribute__((section(".RamFunc")))
#endif
/**
* @brief __NOINLINE definition
*/
#if defined ( __CC_ARM ) || (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)) || defined ( __GNUC__ )
/* ARM V4/V5 and V6 & GNU Compiler
-------------------------------
*/
#define __NOINLINE __attribute__ ( (noinline) )
#elif defined ( __ICCARM__ )
/* ICCARM Compiler
---------------
*/
#define __NOINLINE _Pragma("optimize = no_inline")
#endif
#ifdef __cplusplus
}
#endif
#endif /* ___STM32F7xx_HAL_DEF */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,531 @@
/**
******************************************************************************
* @file stm32f7xx_hal_gpio.c
* @author MCD Application Team
* @brief GPIO HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the General Purpose Input/Output (GPIO) peripheral:
* + Initialization and de-initialization functions
* + IO operation functions
*
@verbatim
==============================================================================
##### GPIO Peripheral features #####
==============================================================================
[..]
Subject to the specific hardware characteristics of each I/O port listed in the datasheet, each
port bit of the General Purpose IO (GPIO) Ports, can be individually configured by software
in several modes:
(+) Input mode
(+) Analog mode
(+) Output mode
(+) Alternate function mode
(+) External interrupt/event lines
[..]
During and just after reset, the alternate functions and external interrupt
lines are not active and the I/O ports are configured in input floating mode.
[..]
All GPIO pins have weak internal pull-up and pull-down resistors, which can be
activated or not.
[..]
In Output or Alternate mode, each IO can be configured on open-drain or push-pull
type and the IO speed can be selected depending on the VDD value.
[..]
All ports have external interrupt/event capability. To use external interrupt
lines, the port must be configured in input mode. All available GPIO pins are
connected to the 16 external interrupt/event lines from EXTI0 to EXTI15.
[..]
The external interrupt/event controller consists of up to 23 edge detectors
(16 lines are connected to GPIO) for generating event/interrupt requests (each
input line can be independently configured to select the type (interrupt or event)
and the corresponding trigger event (rising or falling or both). Each line can
also be masked independently.
##### How to use this driver #####
==============================================================================
[..]
(#) Enable the GPIO AHB clock using the following function: __HAL_RCC_GPIOx_CLK_ENABLE().
(#) Configure the GPIO pin(s) using HAL_GPIO_Init().
(++) Configure the IO mode using "Mode" member from GPIO_InitTypeDef structure
(++) Activate Pull-up, Pull-down resistor using "Pull" member from GPIO_InitTypeDef
structure.
(++) In case of Output or alternate function mode selection: the speed is
configured through "Speed" member from GPIO_InitTypeDef structure.
(++) In alternate mode is selection, the alternate function connected to the IO
is configured through "Alternate" member from GPIO_InitTypeDef structure.
(++) Analog mode is required when a pin is to be used as ADC channel
or DAC output.
(++) In case of external interrupt/event selection the "Mode" member from
GPIO_InitTypeDef structure select the type (interrupt or event) and
the corresponding trigger event (rising or falling or both).
(#) In case of external interrupt/event mode selection, configure NVIC IRQ priority
mapped to the EXTI line using HAL_NVIC_SetPriority() and enable it using
HAL_NVIC_EnableIRQ().
(#) To get the level of a pin configured in input mode use HAL_GPIO_ReadPin().
(#) To set/reset the level of a pin configured in output mode use
HAL_GPIO_WritePin()/HAL_GPIO_TogglePin().
(#) To lock pin configuration until next reset use HAL_GPIO_LockPin().
(#) During and just after reset, the alternate functions are not
active and the GPIO pins are configured in input floating mode (except JTAG
pins).
(#) The LSE oscillator pins OSC32_IN and OSC32_OUT can be used as general purpose
(PC14 and PC15, respectively) when the LSE oscillator is off. The LSE has
priority over the GPIO function.
(#) The HSE oscillator pins OSC_IN/OSC_OUT can be used as
general purpose PH0 and PH1, respectively, when the HSE oscillator is off.
The HSE has priority over the GPIO function.
@endverbatim
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f7xx_hal.h"
/** @addtogroup STM32F7xx_HAL_Driver
* @{
*/
/** @defgroup GPIO GPIO
* @brief GPIO HAL module driver
* @{
*/
#ifdef HAL_GPIO_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @addtogroup GPIO_Private_Constants GPIO Private Constants
* @{
*/
#define GPIO_MODE ((uint32_t)0x00000003U)
#define EXTI_MODE ((uint32_t)0x10000000U)
#define GPIO_MODE_IT ((uint32_t)0x00010000U)
#define GPIO_MODE_EVT ((uint32_t)0x00020000U)
#define RISING_EDGE ((uint32_t)0x00100000U)
#define FALLING_EDGE ((uint32_t)0x00200000U)
#define GPIO_OUTPUT_TYPE ((uint32_t)0x00000010U)
#define GPIO_NUMBER ((uint32_t)16U)
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup GPIO_Exported_Functions GPIO Exported Functions
* @{
*/
/** @defgroup GPIO_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
===============================================================================
##### Initialization and de-initialization functions #####
===============================================================================
[..]
This section provides functions allowing to initialize and de-initialize the GPIOs
to be ready for use.
@endverbatim
* @{
*/
/**
* @brief Initializes the GPIOx peripheral according to the specified parameters in the GPIO_Init.
* @param GPIOx where x can be (A..K) to select the GPIO peripheral.
* @param GPIO_Init pointer to a GPIO_InitTypeDef structure that contains
* the configuration information for the specified GPIO peripheral.
* @retval None
*/
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
{
uint32_t position = 0x00;
uint32_t ioposition = 0x00;
uint32_t iocurrent = 0x00;
uint32_t temp = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Init->Pin));
assert_param(IS_GPIO_MODE(GPIO_Init->Mode));
assert_param(IS_GPIO_PULL(GPIO_Init->Pull));
/* Configure the port pins */
for(position = 0; position < GPIO_NUMBER; position++)
{
/* Get the IO position */
ioposition = ((uint32_t)0x01) << position;
/* Get the current IO position */
iocurrent = (uint32_t)(GPIO_Init->Pin) & ioposition;
if(iocurrent == ioposition)
{
/*--------------------- GPIO Mode Configuration ------------------------*/
/* In case of Output or Alternate function mode selection */
if((GPIO_Init->Mode == GPIO_MODE_OUTPUT_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_PP) ||
(GPIO_Init->Mode == GPIO_MODE_OUTPUT_OD) || (GPIO_Init->Mode == GPIO_MODE_AF_OD))
{
/* Check the Speed parameter */
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
/* Configure the IO Speed */
temp = GPIOx->OSPEEDR;
temp &= ~(GPIO_OSPEEDER_OSPEEDR0 << (position * 2));
temp |= (GPIO_Init->Speed << (position * 2));
GPIOx->OSPEEDR = temp;
/* Configure the IO Output Type */
temp = GPIOx->OTYPER;
temp &= ~(GPIO_OTYPER_OT_0 << position) ;
temp |= (((GPIO_Init->Mode & GPIO_OUTPUT_TYPE) >> 4) << position);
GPIOx->OTYPER = temp;
}
/* Activate the Pull-up or Pull down resistor for the current IO */
temp = GPIOx->PUPDR;
temp &= ~(GPIO_PUPDR_PUPDR0 << (position * 2));
temp |= ((GPIO_Init->Pull) << (position * 2));
GPIOx->PUPDR = temp;
/* In case of Alternate function mode selection */
if((GPIO_Init->Mode == GPIO_MODE_AF_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_OD))
{
/* Check the Alternate function parameter */
assert_param(IS_GPIO_AF(GPIO_Init->Alternate));
/* Configure Alternate function mapped with the current IO */
temp = GPIOx->AFR[position >> 3];
temp &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * 4)) ;
temp |= ((uint32_t)(GPIO_Init->Alternate) << (((uint32_t)position & (uint32_t)0x07) * 4));
GPIOx->AFR[position >> 3] = temp;
}
/* Configure IO Direction mode (Input, Output, Alternate or Analog) */
temp = GPIOx->MODER;
temp &= ~(GPIO_MODER_MODER0 << (position * 2));
temp |= ((GPIO_Init->Mode & GPIO_MODE) << (position * 2));
GPIOx->MODER = temp;
/*--------------------- EXTI Mode Configuration ------------------------*/
/* Configure the External Interrupt or event for the current IO */
if((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE)
{
/* Enable SYSCFG Clock */
__HAL_RCC_SYSCFG_CLK_ENABLE();
temp = SYSCFG->EXTICR[position >> 2];
temp &= ~(((uint32_t)0x0F) << (4 * (position & 0x03)));
temp |= ((uint32_t)(GPIO_GET_INDEX(GPIOx)) << (4 * (position & 0x03)));
SYSCFG->EXTICR[position >> 2] = temp;
/* Clear EXTI line configuration */
temp = EXTI->IMR;
temp &= ~((uint32_t)iocurrent);
if((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT)
{
temp |= iocurrent;
}
EXTI->IMR = temp;
temp = EXTI->EMR;
temp &= ~((uint32_t)iocurrent);
if((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT)
{
temp |= iocurrent;
}
EXTI->EMR = temp;
/* Clear Rising Falling edge configuration */
temp = EXTI->RTSR;
temp &= ~((uint32_t)iocurrent);
if((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE)
{
temp |= iocurrent;
}
EXTI->RTSR = temp;
temp = EXTI->FTSR;
temp &= ~((uint32_t)iocurrent);
if((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE)
{
temp |= iocurrent;
}
EXTI->FTSR = temp;
}
}
}
}
/**
* @brief De-initializes the GPIOx peripheral registers to their default reset values.
* @param GPIOx where x can be (A..K) to select the GPIO peripheral.
* @param GPIO_Pin specifies the port bit to be written.
* This parameter can be one of GPIO_PIN_x where x can be (0..15).
* @retval None
*/
void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin)
{
uint32_t position;
uint32_t ioposition = 0x00;
uint32_t iocurrent = 0x00;
uint32_t tmp = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
/* Configure the port pins */
for(position = 0; position < GPIO_NUMBER; position++)
{
/* Get the IO position */
ioposition = ((uint32_t)0x01) << position;
/* Get the current IO position */
iocurrent = (GPIO_Pin) & ioposition;
if(iocurrent == ioposition)
{
/*------------------------- EXTI Mode Configuration --------------------*/
tmp = SYSCFG->EXTICR[position >> 2];
tmp &= (((uint32_t)0x0F) << (4 * (position & 0x03)));
if(tmp == ((uint32_t)(GPIO_GET_INDEX(GPIOx)) << (4 * (position & 0x03))))
{
/* Clear EXTI line configuration */
EXTI->IMR &= ~((uint32_t)iocurrent);
EXTI->EMR &= ~((uint32_t)iocurrent);
/* Clear Rising Falling edge configuration */
EXTI->RTSR &= ~((uint32_t)iocurrent);
EXTI->FTSR &= ~((uint32_t)iocurrent);
/* Configure the External Interrupt or event for the current IO */
tmp = ((uint32_t)0x0F) << (4 * (position & 0x03));
SYSCFG->EXTICR[position >> 2] &= ~tmp;
}
/*------------------------- GPIO Mode Configuration --------------------*/
/* Configure IO Direction in Input Floating Mode */
GPIOx->MODER &= ~(GPIO_MODER_MODER0 << (position * 2));
/* Configure the default Alternate Function in current IO */
GPIOx->AFR[position >> 3] &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * 4)) ;
/* Deactivate the Pull-up and Pull-down resistor for the current IO */
GPIOx->PUPDR &= ~(GPIO_PUPDR_PUPDR0 << (position * 2));
/* Configure the default value IO Output Type */
GPIOx->OTYPER &= ~(GPIO_OTYPER_OT_0 << position) ;
/* Configure the default value for IO Speed */
GPIOx->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 << (position * 2));
}
}
}
/**
* @}
*/
/** @defgroup GPIO_Exported_Functions_Group2 IO operation functions
* @brief GPIO Read and Write
*
@verbatim
===============================================================================
##### IO operation functions #####
===============================================================================
@endverbatim
* @{
*/
/**
* @brief Reads the specified input port pin.
* @param GPIOx where x can be (A..K) to select the GPIO peripheral.
* @param GPIO_Pin specifies the port bit to read.
* This parameter can be GPIO_PIN_x where x can be (0..15).
* @retval The input port pin value.
*/
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
GPIO_PinState bitstatus;
/* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
if((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET)
{
bitstatus = GPIO_PIN_SET;
}
else
{
bitstatus = GPIO_PIN_RESET;
}
return bitstatus;
}
/**
* @brief Sets or clears the selected data port bit.
*
* @note This function uses GPIOx_BSRR register to allow atomic read/modify
* accesses. In this way, there is no risk of an IRQ occurring between
* the read and the modify access.
*
* @param GPIOx where x can be (A..K) to select the GPIO peripheral.
* @param GPIO_Pin specifies the port bit to be written.
* This parameter can be one of GPIO_PIN_x where x can be (0..15).
* @param PinState specifies the value to be written to the selected bit.
* This parameter can be one of the GPIO_PinState enum values:
* @arg GPIO_PIN_RESET: to clear the port pin
* @arg GPIO_PIN_SET: to set the port pin
* @retval None
*/
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
{
/* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
assert_param(IS_GPIO_PIN_ACTION(PinState));
if(PinState != GPIO_PIN_RESET)
{
GPIOx->BSRR = GPIO_Pin;
}
else
{
GPIOx->BSRR = (uint32_t)GPIO_Pin << 16;
}
}
/**
* @brief Toggles the specified GPIO pins.
* @param GPIOx Where x can be (A..I) to select the GPIO peripheral.
* @param GPIO_Pin Specifies the pins to be toggled.
* @retval None
*/
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
uint32_t odr;
/* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
/* get current Output Data Register value */
odr = GPIOx->ODR;
/* Set selected pins that were at low level, and reset ones that were high */
GPIOx->BSRR = ((odr & GPIO_Pin) << GPIO_NUMBER) | (~odr & GPIO_Pin);
}
/**
* @brief Locks GPIO Pins configuration registers.
* @note The locked registers are GPIOx_MODER, GPIOx_OTYPER, GPIOx_OSPEEDR,
* GPIOx_PUPDR, GPIOx_AFRL and GPIOx_AFRH.
* @note The configuration of the locked GPIO pins can no longer be modified
* until the next reset.
* @param GPIOx where x can be (A..F) to select the GPIO peripheral for STM32F7 family
* @param GPIO_Pin specifies the port bit to be locked.
* This parameter can be any combination of GPIO_PIN_x where x can be (0..15).
* @retval None
*/
HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
__IO uint32_t tmp = GPIO_LCKR_LCKK;
/* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
/* Apply lock key write sequence */
tmp |= GPIO_Pin;
/* Set LCKx bit(s): LCKK='1' + LCK[15-0] */
GPIOx->LCKR = tmp;
/* Reset LCKx bit(s): LCKK='0' + LCK[15-0] */
GPIOx->LCKR = GPIO_Pin;
/* Set LCKx bit(s): LCKK='1' + LCK[15-0] */
GPIOx->LCKR = tmp;
/* Read LCKR register. This read is mandatory to complete key lock sequence */
tmp = GPIOx->LCKR;
/* Read again in order to confirm lock is active */
if((GPIOx->LCKR & GPIO_LCKR_LCKK) != RESET)
{
return HAL_OK;
}
else
{
return HAL_ERROR;
}
}
/**
* @brief This function handles EXTI interrupt request.
* @param GPIO_Pin Specifies the pins connected EXTI line
* @retval None
*/
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
/**
* @brief EXTI line detection callbacks.
* @param GPIO_Pin Specifies the pins connected EXTI line
* @retval None
*/
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(GPIO_Pin);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_GPIO_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,309 @@
/**
******************************************************************************
* @file stm32f7xx_hal_gpio.h
* @author MCD Application Team
* @brief Header file of GPIO HAL module.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F7xx_HAL_GPIO_H
#define __STM32F7xx_HAL_GPIO_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f7xx_hal_def.h"
/** @addtogroup STM32F7xx_HAL_Driver
* @{
*/
/** @addtogroup GPIO
* @{
*/
/* Exported types ------------------------------------------------------------*/
/** @defgroup GPIO_Exported_Types GPIO Exported Types
* @{
*/
/**
* @brief GPIO Init structure definition
*/
typedef struct
{
uint32_t Pin; /*!< Specifies the GPIO pins to be configured.
This parameter can be any value of @ref GPIO_pins_define */
uint32_t Mode; /*!< Specifies the operating mode for the selected pins.
This parameter can be a value of @ref GPIO_mode_define */
uint32_t Pull; /*!< Specifies the Pull-up or Pull-Down activation for the selected pins.
This parameter can be a value of @ref GPIO_pull_define */
uint32_t Speed; /*!< Specifies the speed for the selected pins.
This parameter can be a value of @ref GPIO_speed_define */
uint32_t Alternate; /*!< Peripheral to be connected to the selected pins.
This parameter can be a value of @ref GPIO_Alternate_function_selection */
}GPIO_InitTypeDef;
/**
* @brief GPIO Bit SET and Bit RESET enumeration
*/
typedef enum
{
GPIO_PIN_RESET = 0,
GPIO_PIN_SET
}GPIO_PinState;
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup GPIO_Exported_Constants GPIO Exported Constants
* @{
*/
/** @defgroup GPIO_pins_define GPIO pins define
* @{
*/
#define GPIO_PIN_0 ((uint16_t)0x0001U) /* Pin 0 selected */
#define GPIO_PIN_1 ((uint16_t)0x0002U) /* Pin 1 selected */
#define GPIO_PIN_2 ((uint16_t)0x0004U) /* Pin 2 selected */
#define GPIO_PIN_3 ((uint16_t)0x0008U) /* Pin 3 selected */
#define GPIO_PIN_4 ((uint16_t)0x0010U) /* Pin 4 selected */
#define GPIO_PIN_5 ((uint16_t)0x0020U) /* Pin 5 selected */
#define GPIO_PIN_6 ((uint16_t)0x0040U) /* Pin 6 selected */
#define GPIO_PIN_7 ((uint16_t)0x0080U) /* Pin 7 selected */
#define GPIO_PIN_8 ((uint16_t)0x0100U) /* Pin 8 selected */
#define GPIO_PIN_9 ((uint16_t)0x0200U) /* Pin 9 selected */
#define GPIO_PIN_10 ((uint16_t)0x0400U) /* Pin 10 selected */
#define GPIO_PIN_11 ((uint16_t)0x0800U) /* Pin 11 selected */
#define GPIO_PIN_12 ((uint16_t)0x1000U) /* Pin 12 selected */
#define GPIO_PIN_13 ((uint16_t)0x2000U) /* Pin 13 selected */
#define GPIO_PIN_14 ((uint16_t)0x4000U) /* Pin 14 selected */
#define GPIO_PIN_15 ((uint16_t)0x8000U) /* Pin 15 selected */
#define GPIO_PIN_All ((uint16_t)0xFFFFU) /* All pins selected */
#define GPIO_PIN_MASK ((uint32_t)0x0000FFFFU) /* PIN mask for assert test */
/**
* @}
*/
/** @defgroup GPIO_mode_define GPIO mode define
* @brief GPIO Configuration Mode
* Elements values convention: 0xX0yz00YZ
* - X : GPIO mode or EXTI Mode
* - y : External IT or Event trigger detection
* - z : IO configuration on External IT or Event
* - Y : Output type (Push Pull or Open Drain)
* - Z : IO Direction mode (Input, Output, Alternate or Analog)
* @{
*/
#define GPIO_MODE_INPUT ((uint32_t)0x00000000U) /*!< Input Floating Mode */
#define GPIO_MODE_OUTPUT_PP ((uint32_t)0x00000001U) /*!< Output Push Pull Mode */
#define GPIO_MODE_OUTPUT_OD ((uint32_t)0x00000011U) /*!< Output Open Drain Mode */
#define GPIO_MODE_AF_PP ((uint32_t)0x00000002U) /*!< Alternate Function Push Pull Mode */
#define GPIO_MODE_AF_OD ((uint32_t)0x00000012U) /*!< Alternate Function Open Drain Mode */
#define GPIO_MODE_ANALOG ((uint32_t)0x00000003U) /*!< Analog Mode */
#define GPIO_MODE_IT_RISING ((uint32_t)0x10110000U) /*!< External Interrupt Mode with Rising edge trigger detection */
#define GPIO_MODE_IT_FALLING ((uint32_t)0x10210000U) /*!< External Interrupt Mode with Falling edge trigger detection */
#define GPIO_MODE_IT_RISING_FALLING ((uint32_t)0x10310000U) /*!< External Interrupt Mode with Rising/Falling edge trigger detection */
#define GPIO_MODE_EVT_RISING ((uint32_t)0x10120000U) /*!< External Event Mode with Rising edge trigger detection */
#define GPIO_MODE_EVT_FALLING ((uint32_t)0x10220000U) /*!< External Event Mode with Falling edge trigger detection */
#define GPIO_MODE_EVT_RISING_FALLING ((uint32_t)0x10320000U) /*!< External Event Mode with Rising/Falling edge trigger detection */
/**
* @}
*/
/** @defgroup GPIO_speed_define GPIO speed define
* @brief GPIO Output Maximum frequency
* @{
*/
#define GPIO_SPEED_FREQ_LOW ((uint32_t)0x00000000U) /*!< Low speed */
#define GPIO_SPEED_FREQ_MEDIUM ((uint32_t)0x00000001U) /*!< Medium speed */
#define GPIO_SPEED_FREQ_HIGH ((uint32_t)0x00000002U) /*!< Fast speed */
#define GPIO_SPEED_FREQ_VERY_HIGH ((uint32_t)0x00000003U) /*!< High speed */
/**
* @}
*/
/** @defgroup GPIO_pull_define GPIO pull define
* @brief GPIO Pull-Up or Pull-Down Activation
* @{
*/
#define GPIO_NOPULL ((uint32_t)0x00000000U) /*!< No Pull-up or Pull-down activation */
#define GPIO_PULLUP ((uint32_t)0x00000001U) /*!< Pull-up activation */
#define GPIO_PULLDOWN ((uint32_t)0x00000002U) /*!< Pull-down activation */
/**
* @}
*/
/**
* @}
*/
/* Exported macro ------------------------------------------------------------*/
/** @defgroup GPIO_Exported_Macros GPIO Exported Macros
* @{
*/
/**
* @brief Checks whether the specified EXTI line flag is set or not.
* @param __EXTI_LINE__ specifies the EXTI line flag to check.
* This parameter can be GPIO_PIN_x where x can be(0..15)
* @retval The new state of __EXTI_LINE__ (SET or RESET).
*/
#define __HAL_GPIO_EXTI_GET_FLAG(__EXTI_LINE__) (EXTI->PR & (__EXTI_LINE__))
/**
* @brief Clears the EXTI's line pending flags.
* @param __EXTI_LINE__ specifies the EXTI lines flags to clear.
* This parameter can be any combination of GPIO_PIN_x where x can be (0..15)
* @retval None
*/
#define __HAL_GPIO_EXTI_CLEAR_FLAG(__EXTI_LINE__) (EXTI->PR = (__EXTI_LINE__))
/**
* @brief Checks whether the specified EXTI line is asserted or not.
* @param __EXTI_LINE__ specifies the EXTI line to check.
* This parameter can be GPIO_PIN_x where x can be(0..15)
* @retval The new state of __EXTI_LINE__ (SET or RESET).
*/
#define __HAL_GPIO_EXTI_GET_IT(__EXTI_LINE__) (EXTI->PR & (__EXTI_LINE__))
/**
* @brief Clears the EXTI's line pending bits.
* @param __EXTI_LINE__ specifies the EXTI lines to clear.
* This parameter can be any combination of GPIO_PIN_x where x can be (0..15)
* @retval None
*/
#define __HAL_GPIO_EXTI_CLEAR_IT(__EXTI_LINE__) (EXTI->PR = (__EXTI_LINE__))
/**
* @brief Generates a Software interrupt on selected EXTI line.
* @param __EXTI_LINE__ specifies the EXTI line to check.
* This parameter can be GPIO_PIN_x where x can be(0..15)
* @retval None
*/
#define __HAL_GPIO_EXTI_GENERATE_SWIT(__EXTI_LINE__) (EXTI->SWIER |= (__EXTI_LINE__))
/**
* @}
*/
/* Include GPIO HAL Extension module */
#include "stm32f7xx_hal_gpio_ex.h"
/* Exported functions --------------------------------------------------------*/
/** @addtogroup GPIO_Exported_Functions
* @{
*/
/** @addtogroup GPIO_Exported_Functions_Group1
* @{
*/
/* Initialization and de-initialization functions *****************************/
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);
/**
* @}
*/
/** @addtogroup GPIO_Exported_Functions_Group2
* @{
*/
/* IO operation functions *****************************************************/
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
/**
* @}
*/
/**
* @}
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @defgroup GPIO_Private_Constants GPIO Private Constants
* @{
*/
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup GPIO_Private_Macros GPIO Private Macros
* @{
*/
#define IS_GPIO_PIN_ACTION(ACTION) (((ACTION) == GPIO_PIN_RESET) || ((ACTION) == GPIO_PIN_SET))
#define IS_GPIO_PIN(__PIN__) ((((uint32_t)(__PIN__) & GPIO_PIN_MASK) != 0x00U))
#define IS_GPIO_MODE(MODE) (((MODE) == GPIO_MODE_INPUT) ||\
((MODE) == GPIO_MODE_OUTPUT_PP) ||\
((MODE) == GPIO_MODE_OUTPUT_OD) ||\
((MODE) == GPIO_MODE_AF_PP) ||\
((MODE) == GPIO_MODE_AF_OD) ||\
((MODE) == GPIO_MODE_IT_RISING) ||\
((MODE) == GPIO_MODE_IT_FALLING) ||\
((MODE) == GPIO_MODE_IT_RISING_FALLING) ||\
((MODE) == GPIO_MODE_EVT_RISING) ||\
((MODE) == GPIO_MODE_EVT_FALLING) ||\
((MODE) == GPIO_MODE_EVT_RISING_FALLING) ||\
((MODE) == GPIO_MODE_ANALOG))
#define IS_GPIO_SPEED(SPEED) (((SPEED) == GPIO_SPEED_LOW) || ((SPEED) == GPIO_SPEED_MEDIUM) || \
((SPEED) == GPIO_SPEED_FAST) || ((SPEED) == GPIO_SPEED_HIGH))
#define IS_GPIO_PULL(PULL) (((PULL) == GPIO_NOPULL) || ((PULL) == GPIO_PULLUP) || \
((PULL) == GPIO_PULLDOWN))
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup GPIO_Private_Functions GPIO Private Functions
* @{
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __STM32F7xx_HAL_GPIO_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,658 @@
/**
******************************************************************************
* @file stm32f7xx_hal_gpio_ex.h
* @author MCD Application Team
* @brief Header file of GPIO HAL Extension module.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F7xx_HAL_GPIO_EX_H
#define __STM32F7xx_HAL_GPIO_EX_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f7xx_hal_def.h"
/** @addtogroup STM32F7xx_HAL_Driver
* @{
*/
/** @defgroup GPIOEx GPIOEx
* @{
*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup GPIOEx_Exported_Constants GPIO Exported Constants
* @{
*/
/** @defgroup GPIO_Alternate_function_selection GPIO Alternate Function Selection
* @{
*/
/*--------------- STM32F74xxx/STM32F75xxx/STM32F76xxx/STM32F77xxx -------------*/
#if defined (STM32F745xx) || defined (STM32F746xx) || defined (STM32F756xx) || defined (STM32F765xx) || defined (STM32F767xx) ||\
defined (STM32F769xx) || defined (STM32F777xx) || defined (STM32F779xx) || defined (STM32F750xx)
/**
* @brief AF 0 selection
*/
#define GPIO_AF0_RTC_50Hz ((uint8_t)0x00U) /* RTC_50Hz Alternate Function mapping */
#define GPIO_AF0_MCO ((uint8_t)0x00U) /* MCO (MCO1 and MCO2) Alternate Function mapping */
#define GPIO_AF0_SWJ ((uint8_t)0x00U) /* SWJ (SWD and JTAG) Alternate Function mapping */
#define GPIO_AF0_TRACE ((uint8_t)0x00U) /* TRACE Alternate Function mapping */
/**
* @brief AF 1 selection
*/
#define GPIO_AF1_TIM1 ((uint8_t)0x01U) /* TIM1 Alternate Function mapping */
#define GPIO_AF1_TIM2 ((uint8_t)0x01U) /* TIM2 Alternate Function mapping */
#if defined (STM32F765xx) || defined(STM32F767xx) || defined(STM32F769xx) || defined(STM32F777xx) || defined(STM32F779xx)
#define GPIO_AF1_UART5 ((uint8_t)0x01U) /* UART5 Alternate Function mapping */
#define GPIO_AF1_I2C4 ((uint8_t)0x01U) /* I2C4 Alternate Function mapping */
#endif /* STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */
/**
* @brief AF 2 selection
*/
#define GPIO_AF2_TIM3 ((uint8_t)0x02U) /* TIM3 Alternate Function mapping */
#define GPIO_AF2_TIM4 ((uint8_t)0x02U) /* TIM4 Alternate Function mapping */
#define GPIO_AF2_TIM5 ((uint8_t)0x02U) /* TIM5 Alternate Function mapping */
/**
* @brief AF 3 selection
*/
#define GPIO_AF3_TIM8 ((uint8_t)0x03U) /* TIM8 Alternate Function mapping */
#define GPIO_AF3_TIM9 ((uint8_t)0x03U) /* TIM9 Alternate Function mapping */
#define GPIO_AF3_TIM10 ((uint8_t)0x03U) /* TIM10 Alternate Function mapping */
#define GPIO_AF3_TIM11 ((uint8_t)0x03U) /* TIM11 Alternate Function mapping */
#define GPIO_AF3_LPTIM1 ((uint8_t)0x03U) /* LPTIM1 Alternate Function mapping */
#define GPIO_AF3_CEC ((uint8_t)0x03U) /* CEC Alternate Function mapping */
#if defined (STM32F765xx) || defined(STM32F767xx) || defined(STM32F769xx) || defined(STM32F777xx) || defined(STM32F779xx)
#define GPIO_AF3_DFSDM1 ((uint8_t)0x03U) /* DFSDM1 Alternate Function mapping */
#endif /* STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */
/**
* @brief AF 4 selection
*/
#define GPIO_AF4_I2C1 ((uint8_t)0x04U) /* I2C1 Alternate Function mapping */
#define GPIO_AF4_I2C2 ((uint8_t)0x04U) /* I2C2 Alternate Function mapping */
#define GPIO_AF4_I2C3 ((uint8_t)0x04U) /* I2C3 Alternate Function mapping */
#define GPIO_AF4_I2C4 ((uint8_t)0x04U) /* I2C4 Alternate Function mapping */
#define GPIO_AF4_CEC ((uint8_t)0x04U) /* CEC Alternate Function mapping */
#if defined (STM32F765xx) || defined(STM32F767xx) || defined(STM32F769xx) || defined(STM32F777xx) || defined(STM32F779xx)
#define GPIO_AF4_USART1 ((uint8_t)0x04) /* USART1 Alternate Function mapping */
#endif /* STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */
/**
* @brief AF 5 selection
*/
#define GPIO_AF5_SPI1 ((uint8_t)0x05U) /* SPI1 Alternate Function mapping */
#define GPIO_AF5_SPI2 ((uint8_t)0x05U) /* SPI2/I2S2 Alternate Function mapping */
#define GPIO_AF5_SPI3 ((uint8_t)0x05U) /* SPI3/I2S3 Alternate Function mapping */
#define GPIO_AF5_SPI4 ((uint8_t)0x05U) /* SPI4 Alternate Function mapping */
#define GPIO_AF5_SPI5 ((uint8_t)0x05U) /* SPI5 Alternate Function mapping */
#define GPIO_AF5_SPI6 ((uint8_t)0x05U) /* SPI6 Alternate Function mapping */
/**
* @brief AF 6 selection
*/
#define GPIO_AF6_SPI3 ((uint8_t)0x06U) /* SPI3/I2S3 Alternate Function mapping */
#define GPIO_AF6_SAI1 ((uint8_t)0x06U) /* SAI1 Alternate Function mapping */
#if defined (STM32F765xx) || defined(STM32F767xx) || defined(STM32F769xx) || defined(STM32F777xx) || defined(STM32F779xx)
#define GPIO_AF6_UART4 ((uint8_t)0x06U) /* UART4 Alternate Function mapping */
#define GPIO_AF6_DFSDM1 ((uint8_t)0x06U) /* DFSDM1 Alternate Function mapping */
#endif /* STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */
/**
* @brief AF 7 selection
*/
#define GPIO_AF7_USART1 ((uint8_t)0x07U) /* USART1 Alternate Function mapping */
#define GPIO_AF7_USART2 ((uint8_t)0x07U) /* USART2 Alternate Function mapping */
#define GPIO_AF7_USART3 ((uint8_t)0x07U) /* USART3 Alternate Function mapping */
#define GPIO_AF7_UART5 ((uint8_t)0x07U) /* UART5 Alternate Function mapping */
#define GPIO_AF7_SPDIFRX ((uint8_t)0x07U) /* SPDIF-RX Alternate Function mapping */
#define GPIO_AF7_SPI2 ((uint8_t)0x07U) /* SPI2 Alternate Function mapping */
#define GPIO_AF7_SPI3 ((uint8_t)0x07U) /* SPI3 Alternate Function mapping */
#if defined (STM32F765xx) || defined(STM32F767xx) || defined(STM32F769xx) || defined(STM32F777xx) || defined(STM32F779xx)
#define GPIO_AF7_SPI6 ((uint8_t)0x07U) /* SPI6 Alternate Function mapping */
#define GPIO_AF7_DFSDM1 ((uint8_t)0x07U) /* DFSDM1 Alternate Function mapping */
#endif /* STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */
/**
* @brief AF 8 selection
*/
#define GPIO_AF8_UART4 ((uint8_t)0x08U) /* UART4 Alternate Function mapping */
#define GPIO_AF8_UART5 ((uint8_t)0x08U) /* UART5 Alternate Function mapping */
#define GPIO_AF8_USART6 ((uint8_t)0x08U) /* USART6 Alternate Function mapping */
#define GPIO_AF8_UART7 ((uint8_t)0x08U) /* UART7 Alternate Function mapping */
#define GPIO_AF8_UART8 ((uint8_t)0x08U) /* UART8 Alternate Function mapping */
#define GPIO_AF8_SPDIFRX ((uint8_t)0x08U) /* SPIDIF-RX Alternate Function mapping */
#define GPIO_AF8_SAI2 ((uint8_t)0x08U) /* SAI2 Alternate Function mapping */
#if defined (STM32F765xx) || defined(STM32F767xx) || defined(STM32F769xx) || defined(STM32F777xx) || defined(STM32F779xx)
#define GPIO_AF8_SPI6 ((uint8_t)0x08U) /* SPI6 Alternate Function mapping */
#endif /* STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */
/**
* @brief AF 9 selection
*/
#define GPIO_AF9_CAN1 ((uint8_t)0x09U) /* CAN1 Alternate Function mapping */
#define GPIO_AF9_CAN2 ((uint8_t)0x09U) /* CAN2 Alternate Function mapping */
#define GPIO_AF9_TIM12 ((uint8_t)0x09U) /* TIM12 Alternate Function mapping */
#define GPIO_AF9_TIM13 ((uint8_t)0x09U) /* TIM13 Alternate Function mapping */
#define GPIO_AF9_TIM14 ((uint8_t)0x09U) /* TIM14 Alternate Function mapping */
#define GPIO_AF9_QUADSPI ((uint8_t)0x09U) /* QUADSPI Alternate Function mapping */
#if defined(STM32F746xx) || defined(STM32F756xx) || defined(STM32F767xx) || defined(STM32F769xx) || defined(STM32F777xx) || defined(STM32F779xx) || defined(STM32F750xx)
#define GPIO_AF9_LTDC ((uint8_t)0x09U) /* LCD-TFT Alternate Function mapping */
#endif /* STM32F746xx || STM32F756xx || STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx || STM32F750xx */
#if defined(STM32F746xx) || defined(STM32F756xx) || defined(STM32F765xx) || defined(STM32F765xx) || defined(STM32F767xx) || defined(STM32F769xx) || defined(STM32F777xx) || defined(STM32F779xx) || defined(STM32F750xx)
#define GPIO_AF9_FMC ((uint8_t)0x09U) /* FMC Alternate Function mapping */
#endif /* STM32F746xx || STM32F756xx || STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx || STM32F750xx */
/**
* @brief AF 10 selection
*/
#define GPIO_AF10_OTG_FS ((uint8_t)0xAU) /* OTG_FS Alternate Function mapping */
#define GPIO_AF10_OTG_HS ((uint8_t)0xAU) /* OTG_HS Alternate Function mapping */
#define GPIO_AF10_QUADSPI ((uint8_t)0xAU) /* QUADSPI Alternate Function mapping */
#define GPIO_AF10_SAI2 ((uint8_t)0xAU) /* SAI2 Alternate Function mapping */
#if defined (STM32F765xx) || defined(STM32F767xx) || defined(STM32F769xx) || defined(STM32F777xx) || defined(STM32F779xx)
#define GPIO_AF10_DFSDM1 ((uint8_t)0x0AU) /* DFSDM1 Alternate Function mapping */
#define GPIO_AF10_SDMMC2 ((uint8_t)0x0AU) /* SDMMC2 Alternate Function mapping */
#define GPIO_AF10_LTDC ((uint8_t)0x0AU) /* LCD-TFT Alternate Function mapping */
#endif /* STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */
/**
* @brief AF 11 selection
*/
#define GPIO_AF11_ETH ((uint8_t)0x0BU) /* ETHERNET Alternate Function mapping */
#if defined(STM32F765xx) || defined (STM32F767xx) || defined (STM32F769xx) || defined (STM32F777xx) || defined (STM32F779xx)
#define GPIO_AF11_CAN3 ((uint8_t)0x0BU) /* CAN3 Alternate Function mapping */
#define GPIO_AF11_SDMMC2 ((uint8_t)0x0BU) /* SDMMC2 Alternate Function mapping */
#define GPIO_AF11_I2C4 ((uint8_t)0x0BU) /* I2C4 Alternate Function mapping */
#endif /* STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */
/**
* @brief AF 12 selection
*/
#define GPIO_AF12_FMC ((uint8_t)0xCU) /* FMC Alternate Function mapping */
#define GPIO_AF12_OTG_HS_FS ((uint8_t)0xCU) /* OTG HS configured in FS, Alternate Function mapping */
#define GPIO_AF12_SDMMC1 ((uint8_t)0xCU) /* SDMMC1 Alternate Function mapping */
#if defined(STM32F765xx) || defined (STM32F767xx) || defined (STM32F769xx) || defined (STM32F777xx) || defined (STM32F779xx)
#define GPIO_AF12_MDIOS ((uint8_t)0xCU) /* SDMMC1 Alternate Function mapping */
#define GPIO_AF12_UART7 ((uint8_t)0xCU) /* UART7 Alternate Function mapping */
#endif /* STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */
/**
* @brief AF 13 selection
*/
#define GPIO_AF13_DCMI ((uint8_t)0x0DU) /* DCMI Alternate Function mapping */
#if defined (STM32F769xx) || defined (STM32F779xx)
#define GPIO_AF13_DSI ((uint8_t)0x0DU) /* DSI Alternate Function mapping */
#endif /* STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */
#if defined(STM32F746xx) || defined(STM32F756xx) || defined(STM32F767xx) || defined(STM32F769xx) || defined(STM32F777xx) || defined(STM32F779xx) || defined(STM32F750xx)
#define GPIO_AF13_LTDC ((uint8_t)0x0DU) /* LTDC Alternate Function mapping */
/**
* @brief AF 14 selection
*/
#define GPIO_AF14_LTDC ((uint8_t)0x0EU) /* LCD-TFT Alternate Function mapping */
#endif /* STM32F746xx || STM32F756xx || STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx || STM32F750xx */
/**
* @brief AF 15 selection
*/
#define GPIO_AF15_EVENTOUT ((uint8_t)0x0FU) /* EVENTOUT Alternate Function mapping */
#endif /* STM32F745xx || STM32F746xx || STM32F756xx || STM32F765xx || STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx */
/*----------------------------------------------------------------------------*/
/*---------------------------- STM32F72xxx/STM32F73xxx -----------------------*/
#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F732xx) || defined(STM32F733xx) || defined(STM32F730xx)
/**
* @brief AF 0 selection
*/
#define GPIO_AF0_RTC_50Hz ((uint8_t)0x00U) /* RTC_50Hz Alternate Function mapping */
#define GPIO_AF0_MCO ((uint8_t)0x00U) /* MCO (MCO1 and MCO2) Alternate Function mapping */
#define GPIO_AF0_SWJ ((uint8_t)0x00U) /* SWJ (SWD and JTAG) Alternate Function mapping */
#define GPIO_AF0_TRACE ((uint8_t)0x00U) /* TRACE Alternate Function mapping */
/**
* @brief AF 1 selection
*/
#define GPIO_AF1_TIM1 ((uint8_t)0x01U) /* TIM1 Alternate Function mapping */
#define GPIO_AF1_TIM2 ((uint8_t)0x01U) /* TIM2 Alternate Function mapping */
/**
* @brief AF 2 selection
*/
#define GPIO_AF2_TIM3 ((uint8_t)0x02U) /* TIM3 Alternate Function mapping */
#define GPIO_AF2_TIM4 ((uint8_t)0x02U) /* TIM4 Alternate Function mapping */
#define GPIO_AF2_TIM5 ((uint8_t)0x02U) /* TIM5 Alternate Function mapping */
/**
* @brief AF 3 selection
*/
#define GPIO_AF3_TIM8 ((uint8_t)0x03U) /* TIM8 Alternate Function mapping */
#define GPIO_AF3_TIM9 ((uint8_t)0x03U) /* TIM9 Alternate Function mapping */
#define GPIO_AF3_TIM10 ((uint8_t)0x03U) /* TIM10 Alternate Function mapping */
#define GPIO_AF3_TIM11 ((uint8_t)0x03U) /* TIM11 Alternate Function mapping */
#define GPIO_AF3_LPTIM1 ((uint8_t)0x03U) /* LPTIM1 Alternate Function mapping */
/**
* @brief AF 4 selection
*/
#define GPIO_AF4_I2C1 ((uint8_t)0x04U) /* I2C1 Alternate Function mapping */
#define GPIO_AF4_I2C2 ((uint8_t)0x04U) /* I2C2 Alternate Function mapping */
#define GPIO_AF4_I2C3 ((uint8_t)0x04U) /* I2C3 Alternate Function mapping */
/**
* @brief AF 5 selection
*/
#define GPIO_AF5_SPI1 ((uint8_t)0x05U) /* SPI1 Alternate Function mapping */
#define GPIO_AF5_SPI2 ((uint8_t)0x05U) /* SPI2/I2S2 Alternate Function mapping */
#define GPIO_AF5_SPI3 ((uint8_t)0x05U) /* SPI3/I2S3 Alternate Function mapping */
#define GPIO_AF5_SPI4 ((uint8_t)0x05U) /* SPI4 Alternate Function mapping */
#define GPIO_AF5_SPI5 ((uint8_t)0x05U) /* SPI5 Alternate Function mapping */
/**
* @brief AF 6 selection
*/
#define GPIO_AF6_SPI3 ((uint8_t)0x06U) /* SPI3/I2S3 Alternate Function mapping */
#define GPIO_AF6_SAI1 ((uint8_t)0x06U) /* SAI1 Alternate Function mapping */
/**
* @brief AF 7 selection
*/
#define GPIO_AF7_USART1 ((uint8_t)0x07U) /* USART1 Alternate Function mapping */
#define GPIO_AF7_USART2 ((uint8_t)0x07U) /* USART2 Alternate Function mapping */
#define GPIO_AF7_USART3 ((uint8_t)0x07U) /* USART3 Alternate Function mapping */
#define GPIO_AF7_UART5 ((uint8_t)0x07U) /* UART5 Alternate Function mapping */
#define GPIO_AF7_SPI2 ((uint8_t)0x07U) /* SPI2 Alternate Function mapping */
#define GPIO_AF7_SPI3 ((uint8_t)0x07U) /* SPI3 Alternate Function mapping */
/**
* @brief AF 8 selection
*/
#define GPIO_AF8_UART4 ((uint8_t)0x08U) /* UART4 Alternate Function mapping */
#define GPIO_AF8_UART5 ((uint8_t)0x08U) /* UART5 Alternate Function mapping */
#define GPIO_AF8_USART6 ((uint8_t)0x08U) /* USART6 Alternate Function mapping */
#define GPIO_AF8_UART7 ((uint8_t)0x08U) /* UART7 Alternate Function mapping */
#define GPIO_AF8_UART8 ((uint8_t)0x08U) /* UART8 Alternate Function mapping */
#define GPIO_AF8_SAI2 ((uint8_t)0x08U) /* SAI2 Alternate Function mapping */
/**
* @brief AF 9 selection
*/
#define GPIO_AF9_CAN1 ((uint8_t)0x09U) /* CAN1 Alternate Function mapping */
#define GPIO_AF9_TIM12 ((uint8_t)0x09U) /* TIM12 Alternate Function mapping */
#define GPIO_AF9_TIM13 ((uint8_t)0x09U) /* TIM13 Alternate Function mapping */
#define GPIO_AF9_TIM14 ((uint8_t)0x09U) /* TIM14 Alternate Function mapping */
#define GPIO_AF9_QUADSPI ((uint8_t)0x09U) /* QUADSPI Alternate Function mapping */
/**
* @brief AF 10 selection
*/
#define GPIO_AF10_OTG_FS ((uint8_t)0xAU) /* OTG_FS Alternate Function mapping */
#define GPIO_AF10_OTG_HS ((uint8_t)0xAU) /* OTG_HS Alternate Function mapping */
#define GPIO_AF10_QUADSPI ((uint8_t)0xAU) /* QUADSPI Alternate Function mapping */
#define GPIO_AF10_SAI2 ((uint8_t)0xAU) /* SAI2 Alternate Function mapping */
#define GPIO_AF10_SDMMC2 ((uint8_t)0x0AU) /* SDMMC2 Alternate Function mapping */
/**
* @brief AF 11 selection
*/
#define GPIO_AF11_SDMMC2 ((uint8_t)0x0BU) /* SDMMC2 Alternate Function mapping */
/**
* @brief AF 12 selection
*/
#define GPIO_AF12_FMC ((uint8_t)0xCU) /* FMC Alternate Function mapping */
#define GPIO_AF12_OTG_HS_FS ((uint8_t)0xCU) /* OTG HS configured in FS, Alternate Function mapping */
#define GPIO_AF12_SDMMC1 ((uint8_t)0xCU) /* SDMMC1 Alternate Function mapping */
/**
* @brief AF 13 selection
*/
#define GPIO_AF13_RNG ((uint8_t)0x0DU) /* RNG Alternate Function mapping */
/**
* @brief AF 15 selection
*/
#define GPIO_AF15_EVENTOUT ((uint8_t)0x0FU) /* EVENTOUT Alternate Function mapping */
#endif /* STM32F722xx || STM32F723xx || STM32F732xx || STM32F733xx || STM32F730xx */
/*----------------------------------------------------------------------------*/
/**
* @}
*/
/**
* @}
*/
/* Exported macro ------------------------------------------------------------*/
/** @defgroup GPIOEx_Exported_Macros GPIO Exported Macros
* @{
*/
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup GPIOEx_Exported_Functions GPIO Exported Functions
* @{
*/
/**
* @}
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @defgroup GPIOEx_Private_Constants GPIO Private Constants
* @{
*/
/**
* @brief GPIO pin available on the platform
*/
/* Defines the available pins per GPIOs */
#define GPIOA_PIN_AVAILABLE GPIO_PIN_All
#define GPIOB_PIN_AVAILABLE GPIO_PIN_All
#define GPIOC_PIN_AVAILABLE GPIO_PIN_All
#define GPIOD_PIN_AVAILABLE GPIO_PIN_All
#define GPIOE_PIN_AVAILABLE GPIO_PIN_All
#define GPIOF_PIN_AVAILABLE GPIO_PIN_All
#define GPIOG_PIN_AVAILABLE GPIO_PIN_All
#define GPIOI_PIN_AVAILABLE GPIO_PIN_All
#define GPIOJ_PIN_AVAILABLE GPIO_PIN_All
#define GPIOH_PIN_AVAILABLE GPIO_PIN_All
#define GPIOK_PIN_AVAILABLE (GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | \
GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7)
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup GPIOEx_Private_Macros GPIO Private Macros
* @{
*/
/** @defgroup GPIOEx_Get_Port_Index GPIO Get Port Index
* @{
*/
#if defined (STM32F745xx) || defined (STM32F746xx) || defined (STM32F756xx) || defined (STM32F765xx) ||\
defined (STM32F767xx) || defined (STM32F769xx) || defined (STM32F777xx) || defined (STM32F779xx) ||\
defined (STM32F750xx)
#define GPIO_GET_INDEX(__GPIOx__) (uint8_t)(((__GPIOx__) == (GPIOA))? 0U :\
((__GPIOx__) == (GPIOB))? 1U :\
((__GPIOx__) == (GPIOC))? 2U :\
((__GPIOx__) == (GPIOD))? 3U :\
((__GPIOx__) == (GPIOE))? 4U :\
((__GPIOx__) == (GPIOF))? 5U :\
((__GPIOx__) == (GPIOG))? 6U :\
((__GPIOx__) == (GPIOH))? 7U :\
((__GPIOx__) == (GPIOI))? 8U :\
((__GPIOx__) == (GPIOJ))? 9U : 10U)
#endif /* STM32F745xx || STM32F746xx || STM32F756xx || STM32F765xx || STM32F767xx || STM32F769xx || STM32F777xx || STM32F779xx || STM32F750xx */
#if defined (STM32F722xx) || defined (STM32F723xx) || defined (STM32F732xx) || defined (STM32F733xx) || defined (STM32F730xx)
#define GPIO_GET_INDEX(__GPIOx__) (uint8_t)(((__GPIOx__) == (GPIOA))? 0U :\
((__GPIOx__) == (GPIOB))? 1U :\
((__GPIOx__) == (GPIOC))? 2U :\
((__GPIOx__) == (GPIOD))? 3U :\
((__GPIOx__) == (GPIOE))? 4U :\
((__GPIOx__) == (GPIOF))? 5U :\
((__GPIOx__) == (GPIOG))? 6U :\
((__GPIOx__) == (GPIOH))? 7U : 8U)
#endif /* STM32F722xx || STM32F723xx || STM32F732xx || STM32F733xx || STM32F730xx */
/**
* @}
*/
#define IS_GPIO_PIN_AVAILABLE(__INSTANCE__,__PIN__) \
((((__INSTANCE__) == GPIOA) && (((__PIN__) & (GPIOA_PIN_AVAILABLE)) != 0) && (((__PIN__) | (GPIOA_PIN_AVAILABLE)) == (GPIOA_PIN_AVAILABLE))) || \
(((__INSTANCE__) == GPIOB) && (((__PIN__) & (GPIOB_PIN_AVAILABLE)) != 0) && (((__PIN__) | (GPIOB_PIN_AVAILABLE)) == (GPIOB_PIN_AVAILABLE))) || \
(((__INSTANCE__) == GPIOC) && (((__PIN__) & (GPIOC_PIN_AVAILABLE)) != 0) && (((__PIN__) | (GPIOC_PIN_AVAILABLE)) == (GPIOC_PIN_AVAILABLE))) || \
(((__INSTANCE__) == GPIOD) && (((__PIN__) & (GPIOD_PIN_AVAILABLE)) != 0) && (((__PIN__) | (GPIOD_PIN_AVAILABLE)) == (GPIOD_PIN_AVAILABLE))) || \
(((__INSTANCE__) == GPIOE) && (((__PIN__) & (GPIOE_PIN_AVAILABLE)) != 0) && (((__PIN__) | (GPIOE_PIN_AVAILABLE)) == (GPIOE_PIN_AVAILABLE))) || \
(((__INSTANCE__) == GPIOF) && (((__PIN__) & (GPIOF_PIN_AVAILABLE)) != 0) && (((__PIN__) | (GPIOF_PIN_AVAILABLE)) == (GPIOF_PIN_AVAILABLE))) || \
(((__INSTANCE__) == GPIOG) && (((__PIN__) & (GPIOG_PIN_AVAILABLE)) != 0) && (((__PIN__) | (GPIOG_PIN_AVAILABLE)) == (GPIOG_PIN_AVAILABLE))) || \
(((__INSTANCE__) == GPIOI) && (((__PIN__) & (GPIOI_PIN_AVAILABLE)) != 0) && (((__PIN__) | (GPIOI_PIN_AVAILABLE)) == (GPIOI_PIN_AVAILABLE))) || \
(((__INSTANCE__) == GPIOJ) && (((__PIN__) & (GPIOJ_PIN_AVAILABLE)) != 0) && (((__PIN__) | (GPIOJ_PIN_AVAILABLE)) == (GPIOJ_PIN_AVAILABLE))) || \
(((__INSTANCE__) == GPIOK) && (((__PIN__) & (GPIOK_PIN_AVAILABLE)) != 0) && (((__PIN__) | (GPIOK_PIN_AVAILABLE)) == (GPIOK_PIN_AVAILABLE))) || \
(((__INSTANCE__) == GPIOH) && (((__PIN__) & (GPIOH_PIN_AVAILABLE)) != 0) && (((__PIN__) | (GPIOH_PIN_AVAILABLE)) == (GPIOH_PIN_AVAILABLE))))
/** @defgroup GPIOEx_IS_Alternat_function_selection GPIO Check Alternate Function
* @{
*/
#if defined(STM32F756xx) || defined(STM32F746xx) || defined(STM32F750xx)
#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF1_TIM1) || \
((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \
((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF1_TIM2) || \
((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \
((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF3_TIM8) || \
((AF) == GPIO_AF3_TIM9) || ((AF) == GPIO_AF3_TIM10) || \
((AF) == GPIO_AF3_TIM11) || ((AF) == GPIO_AF3_LPTIM1) || \
((AF) == GPIO_AF3_CEC) || ((AF) == GPIO_AF4_CEC) || \
((AF) == GPIO_AF4_I2C1) || ((AF) == GPIO_AF4_I2C2) || \
((AF) == GPIO_AF4_I2C3) || ((AF) == GPIO_AF4_I2C4) || \
((AF) == GPIO_AF5_SPI1) || ((AF) == GPIO_AF5_SPI2) || \
((AF) == GPIO_AF5_SPI3) || ((AF) == GPIO_AF5_SPI4) || \
((AF) == GPIO_AF5_SPI5) || ((AF) == GPIO_AF5_SPI6) || \
((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF6_SAI1) || \
((AF) == GPIO_AF7_SPI3) || ((AF) == GPIO_AF7_SPI2) || \
((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \
((AF) == GPIO_AF7_USART3) || ((AF) == GPIO_AF7_UART5) || \
((AF) == GPIO_AF7_SPDIFRX) || ((AF) == GPIO_AF8_SPDIFRX) || \
((AF) == GPIO_AF8_SAI2) || ((AF) == GPIO_AF8_USART6) || \
((AF) == GPIO_AF8_UART4) || ((AF) == GPIO_AF8_UART5) || \
((AF) == GPIO_AF8_UART7) || ((AF) == GPIO_AF8_UART8) || \
((AF) == GPIO_AF9_CAN1) || ((AF) == GPIO_AF9_CAN2) || \
((AF) == GPIO_AF9_TIM12) || ((AF) == GPIO_AF9_TIM12) || \
((AF) == GPIO_AF9_TIM14) || ((AF) == GPIO_AF9_QUADSPI) || \
((AF) == GPIO_AF9_LTDC) || ((AF) == GPIO_AF10_OTG_FS) || \
((AF) == GPIO_AF10_OTG_HS) || ((AF) == GPIO_AF10_SAI2) || \
((AF) == GPIO_AF10_QUADSPI) || ((AF) == GPIO_AF11_ETH) || \
((AF) == GPIO_AF12_OTG_HS_FS) || ((AF) == GPIO_AF12_SDMMC1) || \
((AF) == GPIO_AF12_FMC) || ((AF) == GPIO_AF15_EVENTOUT) || \
((AF) == GPIO_AF13_DCMI) || ((AF) == GPIO_AF14_LTDC))
#elif defined(STM32F745xx)
#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF1_TIM1) || \
((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \
((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF1_TIM2) || \
((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \
((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF3_TIM8) || \
((AF) == GPIO_AF3_TIM9) || ((AF) == GPIO_AF3_TIM10) || \
((AF) == GPIO_AF3_TIM11) || ((AF) == GPIO_AF3_LPTIM1) || \
((AF) == GPIO_AF3_CEC) || ((AF) == GPIO_AF4_CEC) || \
((AF) == GPIO_AF4_I2C1) || ((AF) == GPIO_AF4_I2C2) || \
((AF) == GPIO_AF4_I2C3) || ((AF) == GPIO_AF4_I2C4) || \
((AF) == GPIO_AF5_SPI1) || ((AF) == GPIO_AF5_SPI2) || \
((AF) == GPIO_AF5_SPI3) || ((AF) == GPIO_AF5_SPI4) || \
((AF) == GPIO_AF5_SPI5) || ((AF) == GPIO_AF5_SPI6) || \
((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF6_SAI1) || \
((AF) == GPIO_AF7_SPI3) || ((AF) == GPIO_AF7_SPI2) || \
((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \
((AF) == GPIO_AF7_USART3) || ((AF) == GPIO_AF7_UART5) || \
((AF) == GPIO_AF7_SPDIFRX) || ((AF) == GPIO_AF8_SPDIFRX) || \
((AF) == GPIO_AF8_SAI2) || ((AF) == GPIO_AF8_USART6) || \
((AF) == GPIO_AF8_UART4) || ((AF) == GPIO_AF8_UART5) || \
((AF) == GPIO_AF8_UART7) || ((AF) == GPIO_AF8_UART8) || \
((AF) == GPIO_AF9_CAN1) || ((AF) == GPIO_AF9_CAN2) || \
((AF) == GPIO_AF9_TIM12) || ((AF) == GPIO_AF9_TIM12) || \
((AF) == GPIO_AF9_TIM14) || ((AF) == GPIO_AF9_QUADSPI) || \
((AF) == GPIO_AF13_DCMI) || ((AF) == GPIO_AF10_OTG_FS) || \
((AF) == GPIO_AF10_OTG_HS) || ((AF) == GPIO_AF10_SAI2) || \
((AF) == GPIO_AF10_QUADSPI) || ((AF) == GPIO_AF11_ETH) || \
((AF) == GPIO_AF12_OTG_HS_FS) || ((AF) == GPIO_AF12_SDMMC1) || \
((AF) == GPIO_AF12_FMC) || ((AF) == GPIO_AF15_EVENTOUT))
#elif defined(STM32F767xx) || defined(STM32F777xx)
#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF1_TIM1) || \
((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \
((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF1_TIM2) || \
((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \
((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF3_TIM8) || \
((AF) == GPIO_AF3_TIM9) || ((AF) == GPIO_AF3_TIM10) || \
((AF) == GPIO_AF3_TIM11) || ((AF) == GPIO_AF3_LPTIM1) || \
((AF) == GPIO_AF3_CEC) || ((AF) == GPIO_AF4_CEC) || \
((AF) == GPIO_AF4_I2C1) || ((AF) == GPIO_AF4_I2C2) || \
((AF) == GPIO_AF4_I2C3) || ((AF) == GPIO_AF4_I2C4) || \
((AF) == GPIO_AF5_SPI1) || ((AF) == GPIO_AF5_SPI2) || \
((AF) == GPIO_AF5_SPI3) || ((AF) == GPIO_AF5_SPI4) || \
((AF) == GPIO_AF5_SPI5) || ((AF) == GPIO_AF5_SPI6) || \
((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF6_SAI1) || \
((AF) == GPIO_AF7_SPI3) || ((AF) == GPIO_AF7_SPI2) || \
((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \
((AF) == GPIO_AF7_USART3) || ((AF) == GPIO_AF7_UART5) || \
((AF) == GPIO_AF7_SPDIFRX) || ((AF) == GPIO_AF8_SPDIFRX) || \
((AF) == GPIO_AF8_SAI2) || ((AF) == GPIO_AF8_USART6) || \
((AF) == GPIO_AF8_UART4) || ((AF) == GPIO_AF8_UART5) || \
((AF) == GPIO_AF8_UART7) || ((AF) == GPIO_AF8_UART8) || \
((AF) == GPIO_AF9_CAN1) || ((AF) == GPIO_AF9_CAN2) || \
((AF) == GPIO_AF9_TIM12) || ((AF) == GPIO_AF9_TIM12) || \
((AF) == GPIO_AF9_TIM14) || ((AF) == GPIO_AF9_QUADSPI) || \
((AF) == GPIO_AF10_OTG_FS) || ((AF) == GPIO_AF9_LTDC) || \
((AF) == GPIO_AF10_OTG_HS) || ((AF) == GPIO_AF10_SAI2) || \
((AF) == GPIO_AF10_QUADSPI) || ((AF) == GPIO_AF11_ETH) || \
((AF) == GPIO_AF10_SDMMC2) || ((AF) == GPIO_AF11_SDMMC2) || \
((AF) == GPIO_AF11_CAN3) || ((AF) == GPIO_AF12_OTG_HS_FS) || \
((AF) == GPIO_AF12_SDMMC1) || ((AF) == GPIO_AF12_FMC) || \
((AF) == GPIO_AF15_EVENTOUT) || ((AF) == GPIO_AF13_DCMI) || \
((AF) == GPIO_AF14_LTDC))
#elif defined(STM32F769xx) || defined(STM32F779xx)
#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF1_TIM1) || \
((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \
((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF1_TIM2) || \
((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \
((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF3_TIM8) || \
((AF) == GPIO_AF3_TIM9) || ((AF) == GPIO_AF3_TIM10) || \
((AF) == GPIO_AF3_TIM11) || ((AF) == GPIO_AF3_LPTIM1) || \
((AF) == GPIO_AF3_CEC) || ((AF) == GPIO_AF4_CEC) || \
((AF) == GPIO_AF4_I2C1) || ((AF) == GPIO_AF4_I2C2) || \
((AF) == GPIO_AF4_I2C3) || ((AF) == GPIO_AF4_I2C4) || \
((AF) == GPIO_AF5_SPI1) || ((AF) == GPIO_AF5_SPI2) || \
((AF) == GPIO_AF5_SPI3) || ((AF) == GPIO_AF5_SPI4) || \
((AF) == GPIO_AF5_SPI5) || ((AF) == GPIO_AF5_SPI6) || \
((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF6_SAI1) || \
((AF) == GPIO_AF7_SPI3) || ((AF) == GPIO_AF7_SPI2) || \
((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \
((AF) == GPIO_AF7_USART3) || ((AF) == GPIO_AF7_UART5) || \
((AF) == GPIO_AF7_SPDIFRX) || ((AF) == GPIO_AF8_SPDIFRX) || \
((AF) == GPIO_AF8_SAI2) || ((AF) == GPIO_AF8_USART6) || \
((AF) == GPIO_AF8_UART4) || ((AF) == GPIO_AF8_UART5) || \
((AF) == GPIO_AF8_UART7) || ((AF) == GPIO_AF8_UART8) || \
((AF) == GPIO_AF9_CAN1) || ((AF) == GPIO_AF9_CAN2) || \
((AF) == GPIO_AF9_TIM12) || ((AF) == GPIO_AF9_TIM12) || \
((AF) == GPIO_AF9_TIM14) || ((AF) == GPIO_AF9_QUADSPI) || \
((AF) == GPIO_AF9_LTDC) || ((AF) == GPIO_AF10_OTG_FS) || \
((AF) == GPIO_AF10_OTG_HS) || ((AF) == GPIO_AF10_SAI2) || \
((AF) == GPIO_AF10_QUADSPI) || ((AF) == GPIO_AF11_ETH) || \
((AF) == GPIO_AF10_SDMMC2) || ((AF) == GPIO_AF11_SDMMC2) || \
((AF) == GPIO_AF11_CAN3) || ((AF) == GPIO_AF12_OTG_HS_FS) || \
((AF) == GPIO_AF12_SDMMC1) || ((AF) == GPIO_AF12_FMC) || \
((AF) == GPIO_AF15_EVENTOUT) || ((AF) == GPIO_AF13_DCMI) || \
((AF) == GPIO_AF14_LTDC) || ((AF) == GPIO_AF13_DSI))
#elif defined(STM32F765xx)
#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF1_TIM1) || \
((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \
((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF1_TIM2) || \
((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \
((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF3_TIM8) || \
((AF) == GPIO_AF3_TIM9) || ((AF) == GPIO_AF3_TIM10) || \
((AF) == GPIO_AF3_TIM11) || ((AF) == GPIO_AF3_LPTIM1) || \
((AF) == GPIO_AF3_CEC) || ((AF) == GPIO_AF4_CEC) || \
((AF) == GPIO_AF4_I2C1) || ((AF) == GPIO_AF4_I2C2) || \
((AF) == GPIO_AF4_I2C3) || ((AF) == GPIO_AF4_I2C4) || \
((AF) == GPIO_AF5_SPI1) || ((AF) == GPIO_AF5_SPI2) || \
((AF) == GPIO_AF5_SPI3) || ((AF) == GPIO_AF5_SPI4) || \
((AF) == GPIO_AF5_SPI5) || ((AF) == GPIO_AF5_SPI6) || \
((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF6_SAI1) || \
((AF) == GPIO_AF7_SPI3) || ((AF) == GPIO_AF7_SPI2) || \
((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \
((AF) == GPIO_AF7_USART3) || ((AF) == GPIO_AF7_UART5) || \
((AF) == GPIO_AF7_SPDIFRX) || ((AF) == GPIO_AF8_SPDIFRX) || \
((AF) == GPIO_AF8_SAI2) || ((AF) == GPIO_AF8_USART6) || \
((AF) == GPIO_AF8_UART4) || ((AF) == GPIO_AF8_UART5) || \
((AF) == GPIO_AF8_UART7) || ((AF) == GPIO_AF8_UART8) || \
((AF) == GPIO_AF9_CAN1) || ((AF) == GPIO_AF9_CAN2) || \
((AF) == GPIO_AF9_TIM12) || ((AF) == GPIO_AF9_TIM12) || \
((AF) == GPIO_AF9_TIM14) || ((AF) == GPIO_AF9_QUADSPI) || \
((AF) == GPIO_AF10_OTG_HS) || ((AF) == GPIO_AF10_SAI2) || \
((AF) == GPIO_AF10_QUADSPI) || ((AF) == GPIO_AF11_ETH) || \
((AF) == GPIO_AF10_SDMMC2) || ((AF) == GPIO_AF11_SDMMC2) || \
((AF) == GPIO_AF11_CAN3) || ((AF) == GPIO_AF12_OTG_HS_FS) || \
((AF) == GPIO_AF12_SDMMC1) || ((AF) == GPIO_AF12_FMC) || \
((AF) == GPIO_AF15_EVENTOUT) || ((AF) == GPIO_AF13_DCMI) || \
((AF) == GPIO_AF10_OTG_FS))
#elif defined (STM32F722xx) || defined (STM32F723xx) || defined (STM32F732xx) || defined (STM32F733xx) || defined (STM32F730xx)
#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF1_TIM1) || \
((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \
((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF1_TIM2) || \
((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \
((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF3_TIM8) || \
((AF) == GPIO_AF3_TIM9) || ((AF) == GPIO_AF3_TIM10) || \
((AF) == GPIO_AF3_TIM11) || ((AF) == GPIO_AF3_LPTIM1) || \
((AF) == GPIO_AF4_I2C1) || ((AF) == GPIO_AF4_I2C2) || \
((AF) == GPIO_AF4_I2C3) || ((AF) == GPIO_AF5_SPI1) || \
((AF) == GPIO_AF5_SPI2) || ((AF) == GPIO_AF5_SPI3) || \
((AF) == GPIO_AF5_SPI4) || ((AF) == GPIO_AF5_SPI5) || \
((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF6_SAI1) || \
((AF) == GPIO_AF7_SPI3) || ((AF) == GPIO_AF7_SPI2) || \
((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \
((AF) == GPIO_AF7_USART3) || ((AF) == GPIO_AF7_UART5) || \
((AF) == GPIO_AF8_SAI2) || ((AF) == GPIO_AF8_USART6) || \
((AF) == GPIO_AF8_UART4) || ((AF) == GPIO_AF8_UART5) || \
((AF) == GPIO_AF8_UART7) || ((AF) == GPIO_AF8_UART8) || \
((AF) == GPIO_AF9_CAN1) || ((AF) == GPIO_AF9_TIM12) || \
((AF) == GPIO_AF9_TIM12) || ((AF) == GPIO_AF9_TIM14) || \
((AF) == GPIO_AF9_QUADSPI) || ((AF) == GPIO_AF10_OTG_HS) || \
((AF) == GPIO_AF10_SAI2) || ((AF) == GPIO_AF10_QUADSPI) || \
((AF) == GPIO_AF10_SDMMC2) || ((AF) == GPIO_AF11_SDMMC2) || \
((AF) == GPIO_AF12_OTG_HS_FS) || ((AF) == GPIO_AF12_SDMMC1) || \
((AF) == GPIO_AF12_FMC) || ((AF) == GPIO_AF15_EVENTOUT) || \
((AF) == GPIO_AF10_OTG_FS))
#endif /* STM32F756xx || STM32F746xx || STM32F750xx */
/**
* @}
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup GPIOEx_Private_Functions GPIO Private Functions
* @{
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __STM32F7xx_HAL_GPIO_EX_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+95
View File
@@ -0,0 +1,95 @@
# FreeRTOS/{FreeRTOS-Kernel V10.4.3,FreeRTOS-Plus-TCP V2.3.2}
PROG = firmware
ARCH = stm32f7
PROJECT_ROOT_PATH = $(realpath $(CURDIR)/../..)
DOCKER ?= docker run -it --rm -v $(PROJECT_ROOT_PATH):$(PROJECT_ROOT_PATH) -w $(CURDIR) mdashnet/armgcc
FREERTOS_KERNEL_PATH ?= $(PROJECT_ROOT_PATH)/test/freertos-kernel
FREERTOS_PLUS_TCP_PATH ?= $(PROJECT_ROOT_PATH)/test/freertos-tcp
MONGOOSE_FLAGS = -DMG_ARCH=MG_ARCH_FREERTOS_TCP -DMG_ENABLE_FS=1
MCU_FLAGS = -mcpu=cortex-m7 -mthumb -mfloat-abi=softfp -mfpu=vfpv4
#-mcpu=cortex-m7 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard
INCLUDES = -I$(PROJECT_ROOT_PATH) -I$(ARCH) -I$(FREERTOS_KERNEL_PATH)/include -I$(FREERTOS_PLUS_TCP_PATH)/include
INCLUDES += -I$(FREERTOS_PLUS_TCP_PATH)/tools/tcp_utilities/include
INCLUDES += -I$(FREERTOS_PLUS_TCP_PATH)/../Utilities/include
#INCLUDES += -IH2
#INCLUDES += -I/Users/lsm/src/htibosch/plus/stm32F7/ST_Library/include
INCLUDES += -IHAL
INCLUDES += -I$(FREERTOS_PLUS_TCP_PATH)/portable/Compiler/GCC
INCLUDES += -I$(FREERTOS_PLUS_TCP_PATH)/portable/NetworkInterface/STM32Fxx
INCLUDES += -I$(FREERTOS_PLUS_TCP_PATH)/portable/NetworkInterface/include
NETFLAGS = -DSTM32F7xx -DSTM32F746xx -Wno-sign-compare -Wno-unused-function #-Wno-cpp
CFLAGS = -g3 -O0 -W -Wall $(MCU_FLAGS)
CFLAGS += $(INCLUDES) $(MONGOOSE_FLAGS) $(NETFLAGS) $(EXTRA)
LINKFLAGS = -T$(ARCH)/link.ld -mcpu=cortex-m7 -mthumb -nostartfiles --specs rdimon.specs -Wl,--gc-sections
SOURCES = main.c $(PROJECT_ROOT_PATH)/mongoose.c
SOURCES += $(wildcard HAL/*.c)
#SOURCES += -I$(realpath $(FREERTOS_KERNEL_PATH)/../../stm32F7/ST_Library/sources)/
# FreeRTOS kernel sources
SOURCES += $(wildcard $(FREERTOS_KERNEL_PATH)/*.c)
SOURCES += $(FREERTOS_KERNEL_PATH)/portable/MemMang/heap_5.c
SOURCES += $(FREERTOS_KERNEL_PATH)/portable/GCC/ARM_CM7/r0p1/port.c
# FreeRTOS TCP stack sources
SOURCES += $(FREERTOS_PLUS_TCP_PATH)/FreeRTOS_ARP.c
SOURCES += $(FREERTOS_PLUS_TCP_PATH)/FreeRTOS_DHCP.c
SOURCES += $(FREERTOS_PLUS_TCP_PATH)/FreeRTOS_DNS.c
SOURCES += $(FREERTOS_PLUS_TCP_PATH)/FreeRTOS_IP.c
SOURCES += $(FREERTOS_PLUS_TCP_PATH)/FreeRTOS_Sockets.c
SOURCES += $(FREERTOS_PLUS_TCP_PATH)/FreeRTOS_Stream_Buffer.c
SOURCES += $(FREERTOS_PLUS_TCP_PATH)/FreeRTOS_TCP_IP.c
SOURCES += $(FREERTOS_PLUS_TCP_PATH)/FreeRTOS_TCP_WIN.c
SOURCES += $(FREERTOS_PLUS_TCP_PATH)/FreeRTOS_UDP_IP.c
SOURCES += $(FREERTOS_PLUS_TCP_PATH)/portable/NetworkInterface/Common/phyHandling.c
SOURCES += $(FREERTOS_PLUS_TCP_PATH)/portable/BufferManagement/BufferAllocation_1.c
SOURCES += $(FREERTOS_PLUS_TCP_PATH)/portable/NetworkInterface/STM32Fxx/NetworkInterface.c
SOURCES += $(FREERTOS_PLUS_TCP_PATH)/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.c
OBJECTS = obj/boot.o $(SOURCES:%.c=obj/%.o)
all: $(PROG).hex
$(PROG).bin: $(PROG).elf
$(DOCKER) arm-none-eabi-objcopy -O binary $< $@
$(PROG).hex: $(PROG).bin
$(DOCKER) arm-none-eabi-objcopy -I binary -O ihex --change-address 0x8000000 $< $@
$(PROG).elf: $(OBJECTS) Makefile
$(DOCKER) arm-none-eabi-gcc $(OBJECTS) $(LINKFLAGS) -o $@
$(DOCKER) arm-none-eabi-size -A $@
obj/%.o: %.c
@mkdir -p $(dir $@)
$(DOCKER) arm-none-eabi-gcc $(CFLAGS) -c $< -o $@
obj/boot.o: $(ARCH)/boot.s
@mkdir -p $(dir $@)
$(DOCKER) arm-none-eabi-as -g3 --warn --fatal-warnings $(MCU_FLAGS) $< -o $@
flash: $(PROG).bin
st-flash --reset write $< 0x8000000
openocd:
openocd -f openocd.cfg
ELF ?= $(PROG).elf
gdb: #$(PROG).elf
arm-none-eabi-gdb \
-ex 'set confirm off' \
-ex 'target extended-remote :3333' \
-ex 'monitor arm semihosting enable' \
-ex 'monitor reset halt' \
-ex 'load' \
-ex 'monitor reset init' \
-ex '$(GDBCMD)' \
-ex 'r' \
$(ELF)
clean:
@rm -rf *.{bin,elf,map,lst,tgz,zip,hex} obj
+3
View File
@@ -0,0 +1,3 @@
# Mongoose with STM32, FreeRTOS kernel and FreeRTOS-TCP network stack
The `-DMG_ARCH=MG_ARCH_FREERTOS_TCP` compilation flag enables FreeRTOS+TCP support.
+143
View File
@@ -0,0 +1,143 @@
// Copyright (c) 2021 Cesanta Software Limited
// All rights reserved
#include "device.h"
#include "mongoose.h"
static const char *s_debug_level = "4";
static const char *s_listening_address = "http://0.0.0.0:80";
// Event handler for the listening connection.
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_HTTP_MSG) {
#if MG_ENABLE_FS
struct mg_http_serve_opts opts = {.root_dir = "/"};
mg_http_serve_dir(c, ev_data, &opts);
#else
mg_http_reply(c, 200, "", "hello, %s!\n", "world");
#endif
}
(void) fn_data;
(void) ev_data;
}
static void server(void *args) {
struct mg_mgr mgr;
mg_log_set(s_debug_level);
mg_mgr_init(&mgr);
LOG(LL_INFO, ("Starting Mongoose v%s", MG_VERSION)); // Tell the world
mg_http_listen(&mgr, s_listening_address, cb, &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 pin = ((char *) args)[0] == '1' ? LED2 : LED3;
int ms = pin == LED2 ? 3750 : 5130;
for (;;) {
gpio_toggle(pin);
vTaskDelay(pdMS_TO_TICKS(ms));
LOG(LL_INFO, ("blink %s, RAM: %u", (char *) args, xPortGetFreeHeapSize()));
}
}
// Start Mongoose server when network is ready
void vApplicationIPNetworkEventHook(eIPCallbackEvent_t ev) {
static bool mongoose_started = false;
LOG(LL_INFO, ("FreeRTOS net event %d, up: %d", ev, eNetworkUp));
if (ev == eNetworkUp && mongoose_started == false) {
xTaskCreate(server, "server", 8192, NULL, configMAX_PRIORITIES - 1, NULL);
mongoose_started = true;
}
}
static void init_heap(void) {
extern uint32_t _end, _estack;
uint8_t *ptr = (uint8_t *) ((((uint32_t) &_end) + 7) & ~7U);
uint32_t len = (uint32_t)((char *) &_estack - (char *) &_end);
HeapRegion_t regions[] = {{ptr, len}, {NULL, 0}};
vPortDefineHeapRegions(regions);
}
int main(void) {
init_hardware();
init_heap();
// Initialise networking task. Can be done before scheduler is started
static const uint8_t macaddr[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
static const uint8_t ipaddr[4] = {192, 168, 0, 77};
static const uint8_t netmask[4] = {255, 255, 255, 0};
static const uint8_t dnsaddr[4] = {8, 8, 8, 8};
static const uint8_t gwaddr[4] = {192, 168, 0, 1};
FreeRTOS_IPInit(ipaddr, netmask, gwaddr, dnsaddr, macaddr);
xTaskCreate(blinker, "blinker", 512, "1", configMAX_PRIORITIES - 1, NULL);
xTaskCreate(blinker, "blinker", 512, "2", configMAX_PRIORITIES - 1, NULL);
vTaskStartScheduler(); // This blocks
return 0; // Unreachable
}
// Stubs for FreeRTOS-TCP network interface
uint32_t ulApplicationGetNextSequenceNumber(uint32_t a, uint16_t b, uint32_t c,
uint16_t d) {
return a ^ b ^ c ^ d;
}
BaseType_t xApplicationGetRandomNumber(uint32_t *p) {
*p = 0;
return 1;
}
uint32_t SystemCoreClock = 216000000;
uint32_t HAL_RCC_GetHCLKFreq(void) {
return SystemCoreClock;
}
uint32_t HAL_GetTick(void) {
return configTICK_RATE_HZ;
}
#include "stm32f7xx_hal_conf.h"
#include "stm32fxx_hal_eth.h"
void HAL_ETH_MspInit( ETH_HandleTypeDef* heth ) {
GPIO_InitTypeDef GPIO_InitStructure;
if (heth->Instance == ETH) {
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14;
HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0);
HAL_NVIC_EnableIRQ(ETH_IRQn);
__HAL_RCC_ETH_CLK_ENABLE();
HAL_NVIC_SetPriorityGrouping( NVIC_PRIORITYGROUP_4 );
}
}
int vLoggingPrintf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
char buf[100];
int n = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
write(1, buf, n);
return n;
}
void *_sbrk(ptrdiff_t incr) {
(void) incr;
return NULL;
}
+4
View File
@@ -0,0 +1,4 @@
source [find interface/stlink-v2-1.cfg]
transport select hla_swd
source [find target/stm32f7x.cfg]
reset_config srst_only srst_nogate
@@ -0,0 +1,68 @@
#pragma once
#define configUSE_PREEMPTION 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#define configCPU_CLOCK_HZ ((unsigned long) 216000000)
#define configSYSTICK_CLOCK_HZ (configCPU_CLOCK_HZ / 8)
#define configTICK_RATE_HZ 250
#define configMAX_PRIORITIES 5
#define configMINIMAL_STACK_SIZE 512
#define configMAX_TASK_NAME_LEN 16
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_TASK_NOTIFICATIONS 1
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 0
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 1
#define configUSE_TIMERS 0
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
#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 4
#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 configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 0
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTimerPendFunctionCall 0
#define INCLUDE_eTaskGetState 1
#define INCLUDE_pcTaskGetTaskName 1
#define INCLUDE_xTaskGetSchedulerState 1
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
@@ -0,0 +1,45 @@
#pragma once
#define FREERTOS_IP_CONFIG_H
#ifndef ipconfigHAS_DEBUG_PRINTF
#define ipconfigHAS_DEBUG_PRINTF 1
#endif
#if (ipconfigHAS_DEBUG_PRINTF == 1)
#define FreeRTOS_debug_printf(X) vLoggingPrintf X
#endif
#ifndef ipconfigHAS_PRINTF
#define ipconfigHAS_PRINTF 1
#endif
#if (ipconfigHAS_PRINTF == 1)
#define FreeRTOS_printf(X) vLoggingPrintf X
#endif
#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN
#define ipconfigREPLY_TO_INCOMING_PINGS 1
#define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM (1)
#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM (1)
#define ipconfigZERO_COPY_RX_DRIVER (1)
#define ipconfigZERO_COPY_TX_DRIVER (1)
#define ipconfigIP_TASK_PRIORITY 4
#define niEMAC_HANDLER_TASK_PRIORITY 5
#define ipconfigIPERF_PRIORITY_IPERF_TASK 6
#define ipconfigIP_TASK_STACK_SIZE_WORDS (configMINIMAL_STACK_SIZE * 5)
extern UBaseType_t uxRand();
#define ipconfigRAND32() uxRand()
#define ipconfigUSE_NETWORK_EVENT_HOOK 1
#define ipconfigUSE_DHCP 0
#define ipconfigDHCP_REGISTER_HOSTNAME 0
#define ipconfigDHCP_USES_UNICAST 1
#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD (pdMS_TO_TICKS(30000))
#define ipconfigARP_CACHE_ENTRIES 6
#define ipconfigMAX_ARP_RETRANSMISSIONS (5)
#define ipconfigMAX_ARP_AGE 150
#define ipconfigINCLUDE_FULL_INET_ADDR 0
#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 20
#define ipconfigEVENT_QUEUE_LENGTH (ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5)
#define ipconfigUDP_TIME_TO_LIVE 128
#define ipconfigTCP_TIME_TO_LIVE 128
#define ipconfigUSE_TCP 1
#define ipconfigSUPPORT_SELECT_FUNCTION 1
#define ipconfigUSE_TCP_WIN 0
#define ipconfigNETWORK_MTU 1500
@@ -0,0 +1,44 @@
.cpu cortex-m7
.fpu softvfp
.syntax unified
.thumb
.section .vectortab,"a",%progbits
// Cortex-M7 interrupt handlers
.word _estack // 0 Stack top address
.word _reset // 1 Reset
.word pass // 2 NMI
.word halt // 3 Hard Fault
.word halt // 4 MM Fault
.word halt // 5 Bus Fault
.word halt // 6 Usage Fault
.word 0 // 7 RESERVED
.word 0 // 8 RESERVED
.word 0 // 9 RESERVED
.word 0 // 10 RESERVED
.word SVC_Handler // 11 SV call
.word halt // 12 Debug reserved
.word 0 // 13 RESERVED
.word PendSV_Handler // 14 PendSV
.word SysTick_Handler // 15 SysTick
// 98 STM32 handlers
.word halt,halt,halt,halt,halt,halt,halt,halt,halt,halt
.word halt,halt,halt,halt,halt,halt,halt,halt,halt,halt
.word halt,halt,halt,halt,halt,halt,halt,halt,halt,halt
.word halt,halt,halt,halt,halt,halt,halt,halt,halt,halt
.word halt,halt,halt,halt,halt,halt,halt,halt,halt,halt
.word halt,halt,halt,halt,halt,halt,halt,halt,halt,halt
.word halt,ETH_IRQHandler,halt,halt,halt,halt,halt,halt,halt,halt
.word halt,halt,halt,halt,halt,halt,halt,halt,halt,halt
.word halt,halt,halt,halt,halt,halt,halt,halt,halt,halt
.word halt,halt,halt,halt,halt,halt,halt,halt
.section .text
.global _reset
_reset:
ldr sp, =_estack
bl main
b .
halt: b .
pass: bx lr
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,87 @@
/**************************************************************************//**
* @file core_cmFunc.h
* @brief CMSIS Cortex-M Core Function Access Header File
* @version V4.30
* @date 20. October 2015
******************************************************************************/
/* Copyright (c) 2009 - 2015 ARM LIMITED
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
*
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef __CORE_CMFUNC_H
#define __CORE_CMFUNC_H
/* ########################### Core Function Access ########################### */
/** \ingroup CMSIS_Core_FunctionInterface
\defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions
@{
*/
/*------------------ RealView Compiler -----------------*/
#if defined ( __CC_ARM )
#include "cmsis_armcc.h"
/*------------------ ARM Compiler V6 -------------------*/
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#include "cmsis_armcc_V6.h"
/*------------------ GNU Compiler ----------------------*/
#elif defined ( __GNUC__ )
#include "cmsis_gcc.h"
/*------------------ ICC Compiler ----------------------*/
#elif defined ( __ICCARM__ )
#include <cmsis_iar.h>
/*------------------ TI CCS Compiler -------------------*/
#elif defined ( __TMS470__ )
#include <cmsis_ccs.h>
/*------------------ 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.
*/
/*------------------ COSMIC Compiler -------------------*/
#elif defined ( __CSMC__ )
#include <cmsis_csm.h>
#endif
/*@} end of CMSIS_Core_RegAccFunctions */
#endif /* __CORE_CMFUNC_H */
@@ -0,0 +1,87 @@
/**************************************************************************//**
* @file core_cmInstr.h
* @brief CMSIS Cortex-M Core Instruction Access Header File
* @version V4.30
* @date 20. October 2015
******************************************************************************/
/* Copyright (c) 2009 - 2015 ARM LIMITED
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
*
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef __CORE_CMINSTR_H
#define __CORE_CMINSTR_H
/* ########################## Core Instruction Access ######################### */
/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface
Access to dedicated instructions
@{
*/
/*------------------ RealView Compiler -----------------*/
#if defined ( __CC_ARM )
#include "cmsis_armcc.h"
/*------------------ ARM Compiler V6 -------------------*/
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#include "cmsis_armcc_V6.h"
/*------------------ GNU Compiler ----------------------*/
#elif defined ( __GNUC__ )
#include "cmsis_gcc.h"
/*------------------ ICC Compiler ----------------------*/
#elif defined ( __ICCARM__ )
#include <cmsis_iar.h>
/*------------------ TI CCS Compiler -------------------*/
#elif defined ( __TMS470__ )
#include <cmsis_ccs.h>
/*------------------ 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.
*/
/*------------------ COSMIC Compiler -------------------*/
#elif defined ( __CSMC__ )
#include <cmsis_csm.h>
#endif
/*@}*/ /* end of group CMSIS_Core_InstructionInterface */
#endif /* __CORE_CMINSTR_H */
@@ -0,0 +1,96 @@
/**************************************************************************//**
* @file core_cmSimd.h
* @brief CMSIS Cortex-M SIMD Header File
* @version V4.30
* @date 20. October 2015
******************************************************************************/
/* Copyright (c) 2009 - 2015 ARM LIMITED
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
*
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef __CORE_CMSIMD_H
#define __CORE_CMSIMD_H
#ifdef __cplusplus
extern "C" {
#endif
/* ################### Compiler specific Intrinsics ########################### */
/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics
Access to dedicated SIMD instructions
@{
*/
/*------------------ RealView Compiler -----------------*/
#if defined ( __CC_ARM )
#include "cmsis_armcc.h"
/*------------------ ARM Compiler V6 -------------------*/
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#include "cmsis_armcc_V6.h"
/*------------------ GNU Compiler ----------------------*/
#elif defined ( __GNUC__ )
#include "cmsis_gcc.h"
/*------------------ ICC Compiler ----------------------*/
#elif defined ( __ICCARM__ )
#include <cmsis_iar.h>
/*------------------ TI CCS Compiler -------------------*/
#elif defined ( __TMS470__ )
#include <cmsis_ccs.h>
/*------------------ 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.
*/
/*------------------ COSMIC Compiler -------------------*/
#elif defined ( __CSMC__ )
#include <cmsis_csm.h>
#endif
/*@} end of group CMSIS_SIMD_intrinsics */
#ifdef __cplusplus
}
#endif
#endif /* __CORE_CMSIMD_H */
@@ -0,0 +1,135 @@
// Copyright (c) 2018-2021 Cesanta Software Limited
// All rights reserved
// https://www.st.com/resource/en/reference_manual/dm00124865-stm32f75xxx-and-stm32f74xxx-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf
// Memory map: 2.2.2
#include "stm32f746xx.h"
//#include "stm32f7xx_hal.h"
#include "string.h"
#define BIT(x) ((uint32_t) 1 << (x))
#define PIN(bank, num) ((((bank) - 'A') << 8) | (num))
static inline void spin(uint32_t count) {
while (count--) asm("nop");
}
static inline GPIO_TypeDef *gpio_bank(uint16_t pin) {
return (GPIO_TypeDef *) (0x40020000 + 0x400 * (pin >> 8));
}
static inline void gpio_on(uint16_t pin) {
gpio_bank(pin)->ODR |= BIT(pin & 255);
}
static inline void gpio_off(uint16_t pin) {
gpio_bank(pin)->ODR &= ~BIT(pin & 255);
}
static inline void gpio_toggle(uint16_t pin) {
gpio_bank(pin)->ODR ^= BIT(pin & 255);
}
enum { GPIO_IN, GPIO_OUT, GPIO_AF, GPIO_ANALOG };
enum { GPIO_PP, GPIO_OD };
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_bank(pin);
uint8_t n = pin & 255;
gpio->MODER &= ~(3 << (n * 2));
gpio->MODER |= (mode << (n * 2));
gpio->OTYPER &= ~(1 << n);
gpio->OTYPER |= (type << n);
gpio->OSPEEDR &= ~(3 << (n * 2));
gpio->OSPEEDR |= (speed << (n * 2));
gpio->PUPDR &= ~(3 << (n * 2));
gpio->PUPDR |= (pull << (n * 2));
if (n < 8) {
gpio->AFR[0] &= 15 << (n * 4);
gpio->AFR[0] |= af << (n * 4);
} else {
gpio->AFR[1] &= 15 << (n * 4);
gpio->AFR[1] |= af << (n * 4);
}
}
static inline void init_clock(void) {
RCC->CR |= RCC_CR_HSEBYP | RCC_CR_HSEON; // Start HSE
while ((RCC->CR & RCC_CR_HSERDY) == 0) (void) 0;
#define PLL_M 8 // 8MHz HSE down-to 1MHz PLL input
#define PLL_N 432 // 432 MHz VCO output
#define PLL_P 2 // 216 MHz PLL output
#define PLL_Q 9 // 48 MHz (USB)
RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) - 1) << 16) |
(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
RCC->CR |= RCC_CR_PLLON; // Enable the main PLL
FLASH->ACR = FLASH_ACR_ARTEN | FLASH_ACR_PRFTEN | FLASH_ACR_LATENCY_4WS;
// Configure AHB/APB prescalers
// AHB Prescaler = /1 -> 216 MHz
// APB1 Prescaler = /4 -> 54 MHz
// APB2 Prescaler = /2 -> 108 MHz
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
while ((RCC->CR & RCC_CR_PLLRDY) == 0) (void) 0;
RCC->CFGR &= ~RCC_CFGR_SW; // Select the main PLL
RCC->CFGR |= RCC_CFGR_SW_PLL; // as system clock source
while ((RCC->CFGR & RCC_CFGR_SWS) == 0) (void) 0;
// Ethernet clock
RCC->AHB1ENR |= RCC_AHB1ENR_ETHMACEN;
RCC->AHB1ENR |= RCC_AHB1ENR_ETHMACTXEN;
RCC->AHB1ENR |= RCC_AHB1ENR_ETHMACRXEN;
}
#define delay(ms) vTaskDelay(pdMS_TO_TICKS(ms))
#define LED1 PIN('B', 0) // On-board LED pin
#define LED2 PIN('B', 7) // On-board LED pin
#define LED3 PIN('B', 14) // On-board LED pin
static inline void led_toggle(void) {
gpio_toggle(LED2);
}
static inline void init_ram(void) {
extern uint32_t _sbss, _ebss;
extern uint32_t _sdata, _edata, _sidata;
memset(&_sbss, 0, ((char *) &_ebss - (char *) &_sbss));
memcpy(&_sdata, &_sidata, ((char *) &_edata - (char *) &_sdata));
}
static inline void init_hardware(void) {
init_ram();
init_clock();
RCC->AHB1ENR |= BIT(0) | BIT(1) | BIT(2) | BIT(6); // Init GPIO banks A,B,C,G
gpio_init(LED1, GPIO_OUT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_NONE, 0);
gpio_init(LED2, GPIO_OUT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_NONE, 0);
gpio_init(LED3, GPIO_OUT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_NONE, 0);
gpio_on(LED2);
#if 0
uint16_t a1 = PIN('A', 1), a2 = PIN('A', 2), a7 = PIN('A', 7);
gpio_init(a1, GPIO_AF, GPIO_PP, GPIO_SPEED_INSANE, GPIO_PULL_NONE, 11);
gpio_init(a2, GPIO_AF, GPIO_PP, GPIO_SPEED_INSANE, GPIO_PULL_NONE, 11);
gpio_init(a7, GPIO_AF, GPIO_PP, GPIO_SPEED_INSANE, GPIO_PULL_NONE, 11);
uint16_t b13 = PIN('B', 13);
gpio_init(b13, GPIO_AF, GPIO_PP, GPIO_SPEED_INSANE, GPIO_PULL_NONE, 11);
uint16_t c1 = PIN('C', 1), c4 = PIN('C', 4), c5 = PIN('C', 5);
gpio_init(c1, GPIO_AF, GPIO_PP, GPIO_SPEED_INSANE, GPIO_PULL_NONE, 11);
gpio_init(c4, GPIO_AF, GPIO_PP, GPIO_SPEED_INSANE, GPIO_PULL_NONE, 11);
gpio_init(c5, GPIO_AF, GPIO_PP, GPIO_SPEED_INSANE, GPIO_PULL_NONE, 11);
uint16_t g2 = PIN('G', 2), g11 = PIN('G', 11), g13 = PIN('G', 13),
g14 = PIN('G', 14);
gpio_init(g2, GPIO_AF, GPIO_PP, GPIO_SPEED_INSANE, GPIO_PULL_NONE, 11);
gpio_init(g11, GPIO_AF, GPIO_PP, GPIO_SPEED_INSANE, GPIO_PULL_NONE, 11);
gpio_init(g13, GPIO_AF, GPIO_PP, GPIO_SPEED_INSANE, GPIO_PULL_NONE, 11);
gpio_init(g14, GPIO_AF, GPIO_PP, GPIO_SPEED_INSANE, GPIO_PULL_NONE, 11);
HAL_Init();
HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0);
HAL_NVIC_EnableIRQ(ETH_IRQn);
#endif
}
@@ -0,0 +1,32 @@
ENTRY(_reset);
MEMORY {
ram(rwx) : ORIGIN = 0x20000000, LENGTH = 307k
rom(rx) : ORIGIN = 0x08000000, LENGTH = 1024k
}
_estack = ORIGIN(ram) + LENGTH(ram); /* boot.s and init_heap() */
SECTIONS {
.vectortab : { KEEP(*(.vectortab)) } > rom
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.data : {
_sdata = .; /* for init_ram() */
*(.first_data)
*(.data SORT(.data.*))
_edata = .; /* for init_ram() */
} > ram AT > rom
_sidata = LOADADDR(.data);
.bss : {
_sbss = .; /* for init_ram() */
__bss_start__ = _sbss; /* for libc */
*(.bss SORT(.bss.*) COMMON)
_ebss = .; /* for init_ram() */
__bss_end__ = _ebss; /* for libc */
} > ram
. = ALIGN(8);
end = .; /* for syscalls.c */
_end = .; /* for cmsis_gcc.h and init_ram() */
__end__ = .; /* for libc */
}
@@ -0,0 +1,248 @@
/*
* FreeRTOS Kernel V10.4.3
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if ( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
* not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
#define portDONT_DISCARD __attribute__( ( used ) )
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#define portYIELD() \
{ \
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\
/* Barriers are normally not required but do ensure the code is completely \
* within the specified behaviour for the architecture. */ \
__asm volatile ( "dsb" ::: "memory" ); \
__asm volatile ( "isb" ); \
}
#define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/* Critical section management. */
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vPortSetBASEPRI( x )
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 )
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
* not necessary for to use this port. They are defined so the common demo files
* (which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )
/*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Generic helper function. */
__attribute__( ( always_inline ) ) static inline uint8_t ucPortCountLeadingZeros( uint32_t ulBitmap )
{
uint8_t ucReturn;
__asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" );
return ucReturn;
}
/* Check the configuration. */
#if ( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) ucPortCountLeadingZeros( ( uxReadyPriorities ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif
/* portNOP() is not required by this port. */
#define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE inline __attribute__( ( always_inline ) )
#endif
portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm volatile ( "mrs %0, ipsr" : "=r" ( ulCurrentInterrupt )::"memory" );
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
__asm volatile
(
" mov %0, %1 \n"\
" cpsid i \n"\
" msr basepri, %0 \n"\
" isb \n"\
" dsb \n"\
" cpsie i \n"\
: "=r" ( ulNewBASEPRI ) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulOriginalBASEPRI, ulNewBASEPRI;
__asm volatile
(
" mrs %0, basepri \n"\
" mov %1, %2 \n"\
" cpsid i \n"\
" msr basepri, %1 \n"\
" isb \n"\
" dsb \n"\
" cpsie i \n"\
: "=r" ( ulOriginalBASEPRI ), "=r" ( ulNewBASEPRI ) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
/* This return will not be reached but is necessary to prevent compiler
* warnings. */
return ulOriginalBASEPRI;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
{
__asm volatile
(
" msr basepri, %0 "::"r" ( ulNewMaskValue ) : "memory"
);
}
/*-----------------------------------------------------------*/
#define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" )
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,220 @@
/**
******************************************************************************
* @file stm32f7xx.h
* @author MCD Application Team
* @brief CMSIS STM32F7xx Device Peripheral Access Layer Header File.
*
* The file is the unique include file that the application programmer
* is using in the C source code, usually in main.c. This file contains:
* - Configuration section that allows to select:
* - The STM32F7xx device used in the target application
* - To use or not the peripheral’s drivers in application code(i.e.
* code will be based on direct access to peripheral’s registers
* rather than drivers API), this option is controlled by
* "#define USE_HAL_DRIVER"
*
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32f7xx
* @{
*/
#ifndef __STM32F7xx_H
#define __STM32F7xx_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** @addtogroup Library_configuration_section
* @{
*/
/**
* @brief STM32 Family
*/
#if !defined (STM32F7)
#define STM32F7
#endif /* STM32F7 */
/* Uncomment the line below according to the target STM32 device used in your
application
*/
#if !defined (STM32F756xx) && !defined (STM32F746xx) && !defined (STM32F745xx) && !defined (STM32F765xx) && \
!defined (STM32F767xx) && !defined (STM32F769xx) && !defined (STM32F777xx) && !defined (STM32F779xx) && \
!defined (STM32F722xx) && !defined (STM32F723xx) && !defined (STM32F732xx) && !defined (STM32F733xx) && \
!defined (STM32F730xx) && !defined (STM32F750xx)
/* #define STM32F756xx */ /*!< STM32F756VG, STM32F756ZG, STM32F756ZG, STM32F756IG, STM32F756BG,
STM32F756NG Devices */
/* #define STM32F746xx */ /*!< STM32F746VE, STM32F746VG, STM32F746ZE, STM32F746ZG, STM32F746IE, STM32F746IG,
STM32F746BE, STM32F746BG, STM32F746NE, STM32F746NG Devices */
/* #define STM32F745xx */ /*!< STM32F745VE, STM32F745VG, STM32F745ZG, STM32F745ZE, STM32F745IE, STM32F745IG Devices */
/* #define STM32F765xx */ /*!< STM32F765BI, STM32F765BG, STM32F765NI, STM32F765NG, STM32F765II, STM32F765IG,
STM32F765ZI, STM32F765ZG, STM32F765VI, STM32F765VG Devices */
/* #define STM32F767xx */ /*!< STM32F767BG, STM32F767BI, STM32F767IG, STM32F767II, STM32F767NG, STM32F767NI,
STM32F767VG, STM32F767VI, STM32F767ZG, STM32F767ZI Devices */
/* #define STM32F769xx */ /*!< STM32F769AG, STM32F769AI, STM32F769BG, STM32F769BI, STM32F769IG, STM32F769II,
STM32F769NG, STM32F769NI, STM32F768AI Devices */
/* #define STM32F777xx */ /*!< STM32F777VI, STM32F777ZI, STM32F777II, STM32F777BI, STM32F777NI Devices */
/* #define STM32F779xx */ /*!< STM32F779II, STM32F779BI, STM32F779NI, STM32F779AI, STM32F778AI Devices */
/* #define STM32F722xx */ /*!< STM32F722IE, STM32F722ZE, STM32F722VE, STM32F722RE, STM32F722IC, STM32F722ZC,
STM32F722VC, STM32F722RC Devices */
/* #define STM32F723xx */ /*!< STM32F723IE, STM32F723ZE, STM32F723VE, STM32F723IC, STM32F723ZC, STM32F723VC Devices */
/* #define STM32F732xx */ /*!< STM32F732IE, STM32F732ZE, STM32F732VE, STM32F732RE Devices */
/* #define STM32F733xx */ /*!< STM32F733IE, STM32F733ZE, STM32F733VE Devices */
/* #define STM32F730xx */ /*!< STM32F730R, STM32F730V, STM32F730Z, STM32F730I Devices */
/* #define STM32F750xx */ /*!< STM32F750V, STM32F750Z, STM32F750N Devices */
#endif
/* Tip: To avoid modifying this file each time you need to switch between these
devices, you can define the device in your toolchain compiler preprocessor.
*/
#if !defined (USE_HAL_DRIVER)
/**
* @brief Comment the line below if you will not use the peripherals drivers.
In this case, these drivers will not be included and the application code will
be based on direct access to peripherals registers
*/
/*#define USE_HAL_DRIVER */
#endif /* USE_HAL_DRIVER */
/**
* @brief CMSIS Device version number V1.2.6
*/
#define __STM32F7_CMSIS_VERSION_MAIN (0x01) /*!< [31:24] main version */
#define __STM32F7_CMSIS_VERSION_SUB1 (0x02) /*!< [23:16] sub1 version */
#define __STM32F7_CMSIS_VERSION_SUB2 (0x06) /*!< [15:8] sub2 version */
#define __STM32F7_CMSIS_VERSION_RC (0x00) /*!< [7:0] release candidate */
#define __STM32F7_CMSIS_VERSION ((__STM32F7_CMSIS_VERSION_MAIN << 24)\
|(__STM32F7_CMSIS_VERSION_SUB1 << 16)\
|(__STM32F7_CMSIS_VERSION_SUB2 << 8 )\
|(__STM32F7_CMSIS_VERSION_RC))
/**
* @}
*/
/** @addtogroup Device_Included
* @{
*/
#if defined(STM32F722xx)
#include "stm32f722xx.h"
#elif defined(STM32F723xx)
#include "stm32f723xx.h"
#elif defined(STM32F732xx)
#include "stm32f732xx.h"
#elif defined(STM32F733xx)
#include "stm32f733xx.h"
#elif defined(STM32F756xx)
#include "stm32f756xx.h"
#elif defined(STM32F746xx)
#include "stm32f746xx.h"
#elif defined(STM32F745xx)
#include "stm32f745xx.h"
#elif defined(STM32F765xx)
#include "stm32f765xx.h"
#elif defined(STM32F767xx)
#include "stm32f767xx.h"
#elif defined(STM32F769xx)
#include "stm32f769xx.h"
#elif defined(STM32F777xx)
#include "stm32f777xx.h"
#elif defined(STM32F779xx)
#include "stm32f779xx.h"
#elif defined(STM32F730xx)
#include "stm32f730xx.h"
#elif defined(STM32F750xx)
#include "stm32f750xx.h"
#else
#error "Please select first the target STM32F7xx device used in your application (in stm32f7xx.h file)"
#endif
/**
* @}
*/
/** @addtogroup Exported_types
* @{
*/
typedef enum
{
RESET = 0U,
SET = !RESET
} FlagStatus, ITStatus;
typedef enum
{
DISABLE = 0U,
ENABLE = !DISABLE
} FunctionalState;
#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))
typedef enum
{
SUCCESS = 0U,
ERROR = !SUCCESS
} ErrorStatus;
/**
* @}
*/
/** @addtogroup Exported_macro
* @{
*/
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT))
#define READ_BIT(REG, BIT) ((REG) & (BIT))
#define CLEAR_REG(REG) ((REG) = (0x0))
#define WRITE_REG(REG, VAL) ((REG) = (VAL))
#define READ_REG(REG) ((REG))
#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))
#define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL)))
/**
* @}
*/
#ifdef USE_HAL_DRIVER
#include "stm32f7xx_hal.h"
#endif /* USE_HAL_DRIVER */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __STM32F7xx_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
@@ -0,0 +1,122 @@
/**
******************************************************************************
* @file system_stm32f7xx.h
* @author MCD Application Team
* @brief CMSIS Cortex-M7 Device System Source File for STM32F7xx devices.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without
*modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*notice, this list of conditions and the following disclaimer in the
*documentation and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
*LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
*CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
*SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
*INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
*CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
*ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32f7xx_system
* @{
*/
/**
* @brief Define to prevent recursive inclusion
*/
#ifndef __SYSTEM_STM32F7XX_H
#define __SYSTEM_STM32F7XX_H
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup STM32F7xx_System_Includes
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F7xx_System_Exported_Variables
* @{
*/
/* The SystemCoreClock 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 STM32F7xx_System_Exported_Constants
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F7xx_System_Exported_Macros
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F7xx_System_Exported_Functions
* @{
*/
extern void SystemInit(void);
extern void SystemCoreClockUpdate(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /*__SYSTEM_STM32F7XX_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+2 -2
View File
@@ -32,8 +32,8 @@ static void broadcast_mjpeg_frame(struct mg_mgr *mgr) {
size_t nfiles = sizeof(files) / sizeof(files[0]); size_t nfiles = sizeof(files) / sizeof(files[0]);
static size_t i; static size_t i;
const char *path = files[i++ % nfiles]; const char *path = files[i++ % nfiles];
size_t size = mg_file_size(path); size_t size = 0;
char *data = mg_file_read(path); // Read next file char *data = mg_file_read(path, &size); // Read next file
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] != 'S') continue; // Skip non-stream connections if (c->label[0] != 'S') continue; // Skip non-stream connections
+763 -697
View File
File diff suppressed because it is too large. Load diff
+282 -164
View File
@@ -14,8 +14,15 @@
// //
// Alternatively, you can license this software under a commercial // Alternatively, you can license this software under a commercial
// license, as set out in <https://www.cesanta.com/license>. // license, as set out in <https://www.cesanta.com/license>.
#pragma once
#define MG_VERSION "7.2" #ifndef MONGOOSE_H
#define MONGOOSE_H
#define MG_VERSION "7.3"
#ifdef __cplusplus
extern "C" {
#endif
#define MG_ARCH_CUSTOM 0 #define MG_ARCH_CUSTOM 0
@@ -23,54 +30,20 @@
#define MG_ARCH_WIN32 2 #define MG_ARCH_WIN32 2
#define MG_ARCH_ESP32 3 #define MG_ARCH_ESP32 3
#define MG_ARCH_ESP8266 4 #define MG_ARCH_ESP8266 4
#define MG_ARCH_CC3100 5 #define MG_ARCH_FREERTOS_TCP 5
#define MG_ARCH_CC3200 6 #define MG_ARCH_FREERTOS_LWIP 6
#define MG_ARCH_CC3220 7
#define MG_ARCH_MSP432 8
#define MG_ARCH_TM4C129 9
#define MG_ARCH_MBED 10
#define MG_ARCH_WINCE 11
#define MG_ARCH_NXP_LPC 12
#define MG_ARCH_NXP_KINETIS 13
#define MG_ARCH_NRF51 14
#define MG_ARCH_NRF52 15
#define MG_ARCH_PIC32 16
#define MG_ARCH_RS14100 17
#define MG_ARCH_STM32 18
#define MG_ARCH_FREERTOS 19
#if !defined(MG_ARCH) #if !defined(MG_ARCH)
#if defined(TARGET_IS_MSP432P4XX) || defined(__MSP432P401R__) #if defined(__unix__) || defined(__APPLE__)
#define MG_ARCH MG_ARCH_MSP432
#elif defined(cc3200) || defined(TARGET_IS_CC3200)
#define MG_ARCH MG_ARCH_CC3200
#elif defined(cc3220) || defined(TARGET_IS_CC3220)
#define MG_ARCH MG_ARCH_CC3220
#elif defined(__unix__) || defined(__APPLE__)
#define MG_ARCH MG_ARCH_UNIX #define MG_ARCH MG_ARCH_UNIX
#elif defined(WINCE)
#define MG_ARCH MG_ARCH_WINCE
#elif defined(_WIN32) #elif defined(_WIN32)
#define MG_ARCH MG_ARCH_WIN32 #define MG_ARCH MG_ARCH_WIN32
#elif defined(__MBED__)
#define MG_ARCH MG_ARCH_MBED
#elif defined(__USE_LPCOPEN)
#define MG_ARCH MG_ARCH_NXP_LPC
#elif defined(FRDM_K64F) || defined(FREEDOM)
#define MG_ARCH MG_ARCH_NXP_KINETIS
#elif defined(PIC32)
#define MG_ARCH MG_ARCH_PIC32
#elif defined(ICACHE_FLASH) || defined(ICACHE_RAM_ATTR) #elif defined(ICACHE_FLASH) || defined(ICACHE_RAM_ATTR)
#define MG_ARCH MG_ARCH_ESP8266 #define MG_ARCH MG_ARCH_ESP8266
#elif defined(ESP_PLATFORM) #elif defined(ESP_PLATFORM)
#define MG_ARCH MG_ARCH_ESP32 #define MG_ARCH MG_ARCH_ESP32
#elif defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || \ #elif defined(FREERTOS_IP_H)
defined(TARGET_IS_TM4C129_RA2) #define MG_ARCH MG_ARCH_FREERTOS_TCP
#define MG_ARCH MG_ARCH_TM4C129
#elif defined(RS14100)
#define MG_ARCH MG_ARCH_RS14100
#elif defined(STM32)
#define MG_ARCH MG_ARCH_STM32
#endif #endif
#if !defined(MG_ARCH) #if !defined(MG_ARCH)
@@ -78,23 +51,13 @@
#endif #endif
#endif // !defined(MG_ARCH) #endif // !defined(MG_ARCH)
#define WIN32_LEAN_AND_MEAN #if !defined(PRINTF_LIKE)
#define _CRT_SECURE_NO_WARNINGS #if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__)
#define _WINSOCK_DEPRECATED_NO_WARNINGS #define PRINTF_LIKE(f, a) __attribute__((format(printf, f, a)))
#else
// Standard C headers #define PRINTF_LIKE(f, a)
#include <ctype.h> #endif
#include <errno.h> #endif
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#if MG_ARCH == MG_ARCH_CUSTOM #if MG_ARCH == MG_ARCH_CUSTOM
#include <mongoose_custom.h> #include <mongoose_custom.h>
@@ -106,20 +69,25 @@
#if !defined(PRINTF_LIKE)
#if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__)
#define PRINTF_LIKE(f, a) __attribute__((format(printf, f, a)))
#else
#define PRINTF_LIKE(f, a)
#endif
#endif
#if MG_ARCH == MG_ARCH_ESP32 #if MG_ARCH == MG_ARCH_ESP32
#include <ctype.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <netdb.h> #include <netdb.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#define MG_DIRSEP '/' #define MG_DIRSEP '/'
#define MG_INT64_FMT "%lld" #define MG_INT64_FMT "%lld"
#ifndef MG_PATH_MAX #ifndef MG_PATH_MAX
@@ -131,28 +99,102 @@
#if MG_ARCH == MG_ARCH_ESP8266 #if MG_ARCH == MG_ARCH_ESP8266
#include <ctype.h>
#include <dirent.h> #include <dirent.h>
#include <esp_system.h> #include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <netdb.h> #include <netdb.h>
#include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <esp_system.h>
#define MG_DIRSEP '/' #define MG_DIRSEP '/'
#define MG_INT64_FMT "%lld" #define MG_INT64_FMT "%lld"
#endif #endif
#if MG_ARCH == MG_ARCH_FREERTOS #if MG_ARCH == MG_ARCH_FREERTOS_LWIP
#include <FreeRTOS.h>
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#if defined(__GNUC__)
#include <sys/time.h>
#else
typedef long suseconds_t;
struct timeval {
time_t tv_sec;
suseconds_t tv_usec;
};
#endif
#if MG_ENABLE_FS
#include <sys/stat.h>
#endif
#include <FreeRTOS.h>
#include <task.h> #include <task.h>
#include <FreeRTOS_IP.h> #include <lwip/sockets.h>
#include <FreeRTOS_Sockets.h>
#include <stdbool.h>
#define MG_INT64_FMT "%lld" #define MG_INT64_FMT "%lld"
#define MG_DIRSEP '/' #define MG_DIRSEP '/'
// Re-route calloc/free to the FreeRTOS's functions, don't use stdlib
static inline void *mg_calloc(int cnt, size_t size) {
void *p = pvPortMalloc(cnt * size);
if (p != NULL) memset(p, 0, size);
return p;
}
#define calloc(a, b) mg_calloc((a), (b))
#define free(a) vPortFree(a)
#define malloc(a) pvPortMalloc(a)
#define gmtime_r(a, b) gmtime(a)
#endif // MG_ARCH == MG_ARCH_FREERTOS_LWIP
#if MG_ARCH == MG_ARCH_FREERTOS_TCP
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if MG_ENABLE_FS
#include <sys/stat.h>
#endif
#include <FreeRTOS.h>
#include <FreeRTOS_IP.h>
#include <FreeRTOS_Sockets.h>
#include <task.h>
#define MG_INT64_FMT "%lld"
#define MG_DIRSEP '/'
// Why FreeRTOS-TCP did not implement a clean BSD API, but its own thing
// with FreeRTOS_ prefix, is beyond me
#define IPPROTO_TCP FREERTOS_IPPROTO_TCP #define IPPROTO_TCP FREERTOS_IPPROTO_TCP
#define IPPROTO_UDP FREERTOS_IPPROTO_UDP #define IPPROTO_UDP FREERTOS_IPPROTO_UDP
#define AF_INET FREERTOS_AF_INET #define AF_INET FREERTOS_AF_INET
@@ -163,9 +205,7 @@
#define SOL_SOCKET 0 #define SOL_SOCKET 0
#define SO_REUSEADDR 0 #define SO_REUSEADDR 0
#define sockaddr_in freertos_sockaddr #define sockaddr_in freertos_sockaddr
struct sockaddr { #define sockaddr freertos_sockaddr
uint8_t sa_len, sa_family;
};
#define accept(a, b, c) FreeRTOS_accept((a), (b), (c)) #define accept(a, b, c) FreeRTOS_accept((a), (b), (c))
#define connect(a, b, c) FreeRTOS_connect((a), (b), (c)) #define connect(a, b, c) FreeRTOS_connect((a), (b), (c))
#define bind(a, b, c) FreeRTOS_bind((a), (b), (c)) #define bind(a, b, c) FreeRTOS_bind((a), (b), (c))
@@ -180,48 +220,72 @@ struct sockaddr {
#define closesocket(x) FreeRTOS_closesocket(x) #define closesocket(x) FreeRTOS_closesocket(x)
#define gethostbyname(x) FreeRTOS_gethostbyname(x) #define gethostbyname(x) FreeRTOS_gethostbyname(x)
#include <ff_stdio.h> // Re-route calloc/free to the FreeRTOS's functions, don't use stdlib
static inline void *mg_calloc(int cnt, size_t size) {
#undef FILE void *p = pvPortMalloc(cnt * size);
#define FILE FF_FILE if (p != NULL) memset(p, 0, size);
//#define SEEK_SET FF_SEEK_SET return p;
//#define SEEK_END FF_SEEK_END
#define stat(a, b) ff_stat((a), (b))
#define fopen(a, b) ff_fopen((a), (b))
#define fclose(a) ff_fclose(a)
#define fread(a, b, c, d) ff_fread((a), (b), (c), (d))
#define fwrite(a, b, c, d) ff_fwrite((a), (b), (c), (d))
#define vfprintf ff_vfprintf
#define fprintf ff_fprintf
#define remove(a) ff_remove(a)
#define rename(a, b) ff_rename((a), (b), 1)
static inline int ff_vfprintf(FF_FILE *fp, const char *fmt, va_list ap) {
char *buf = NULL;
int n = mg_vasprintf(&buf, 0, fmt, ap);
if (buf != NULL) ff_fwrite(buf, 1, n, fp), free(buf);
return n;
} }
#define calloc(a, b) mg_calloc((a), (b))
#define free(a) vPortFree(a)
#define malloc(a) pvPortMalloc(a)
#define gmtime_r(a, b) gmtime(a)
#if !defined(__GNUC__)
// copied from GCC on ARM; for some reason useconds are signed
typedef long suseconds_t;
struct timeval {
time_t tv_sec;
suseconds_t tv_usec;
};
#endif #endif
#ifndef EINPROGRESS
#define EINPROGRESS pdFREERTOS_ERRNO_EINPROGRESS
#endif
#ifndef EWOULDBLOCK
#define EWOULDBLOCK pdFREERTOS_ERRNO_EWOULDBLOCK
#endif
#ifndef EAGAIN
#define EAGAIN pdFREERTOS_ERRNO_EAGAIN
#endif
#ifndef EINTR
#define EINTR pdFREERTOS_ERRNO_EINTR
#endif
#endif // MG_ARCH == MG_ARCH_FREERTOS_TCP
#if MG_ARCH == MG_ARCH_UNIX #if MG_ARCH == MG_ARCH_UNIX
#define _DARWIN_UNLIMITED_SELECT 1 #define _DARWIN_UNLIMITED_SELECT 1
#include <arpa/inet.h> #include <arpa/inet.h>
#include <ctype.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <limits.h>
#include <netdb.h> #include <netdb.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <signal.h> #include <signal.h>
#include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h> #include <sys/select.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#define MG_DIRSEP '/' #define MG_DIRSEP '/'
#define MG_ENABLE_POSIX 1 #define MG_ENABLE_POSIX 1
#define MG_INT64_FMT "%" PRId64 #define MG_INT64_FMT "%" PRId64
@@ -231,6 +295,31 @@ static inline int ff_vfprintf(FF_FILE *fp, const char *fmt, va_list ap) {
#if MG_ARCH == MG_ARCH_WIN32 #if MG_ARCH == MG_ARCH_WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#endif
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#if defined(_MSC_VER) && _MSC_VER < 1700 #if defined(_MSC_VER) && _MSC_VER < 1700
#define __func__ "" #define __func__ ""
typedef __int64 int64_t; typedef __int64 int64_t;
@@ -258,6 +347,7 @@ typedef enum { false = 0, true = 1 } bool;
#define strdup(x) _strdup(x) #define strdup(x) _strdup(x)
#endif #endif
typedef unsigned suseconds_t;
typedef int socklen_t; typedef int socklen_t;
#define MG_DIRSEP '\\' #define MG_DIRSEP '\\'
#ifndef PATH_MAX #ifndef PATH_MAX
@@ -270,6 +360,7 @@ typedef int socklen_t;
#define EWOULDBLOCK WSAEWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK
#endif #endif
#define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX) #define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX)
#define fopen(a, b) mg_fopen((a), (b))
#ifndef va_copy #ifndef va_copy
#ifdef __va_copy #ifdef __va_copy
#define va_copy __va_copy #define va_copy __va_copy
@@ -283,16 +374,28 @@ typedef int socklen_t;
#define MG_INT64_FMT "%I64d" #define MG_INT64_FMT "%I64d"
static __inline FILE *mg_fopen(const char *path, const char *mode) {
wchar_t b1[PATH_MAX], b2[10];
MultiByteToWideChar(CP_UTF8, 0, path, -1, b1, sizeof(b1) / sizeof(b1[0]));
MultiByteToWideChar(CP_UTF8, 0, mode, -1, b2, sizeof(b2) / sizeof(b2[0]));
return _wfopen(b1, b2);
}
// https://lgtm.com/rules/2154840805/ -gmtime, localtime, ctime and asctime
static __inline struct tm *gmtime_r(time_t *t, struct tm *tm) {
(void) tm;
return gmtime(t);
}
static __inline struct tm *localtime_r(time_t *t, struct tm *tm) {
(void) tm;
return localtime(t);
}
#endif #endif
#ifndef MG_ENABLE_LWIP #ifndef MG_ENABLE_SOCKET
#define MG_ENABLE_LWIP 0
#endif
#if MG_ENABLE_LWIP
#define MG_ENABLE_SOCKET 0
#elif !defined(MG_ENABLE_SOCKET)
#define MG_ENABLE_SOCKET 1 #define MG_ENABLE_SOCKET 1
#endif #endif
@@ -320,14 +423,15 @@ typedef int socklen_t;
#define MG_ENABLE_LOG 1 #define MG_ENABLE_LOG 1
#endif #endif
#ifndef MG_ENABLE_MGOS
#define MG_ENABLE_MGOS 0
#endif
#ifndef MG_ENABLE_MD5 #ifndef MG_ENABLE_MD5
#define MG_ENABLE_MD5 0 #define MG_ENABLE_MD5 0
#endif #endif
// Set MG_ENABLE_WINSOCK=0 for Win32 builds with external IP stack (like LWIP)
#ifndef MG_ENABLE_WINSOCK
#define MG_ENABLE_WINSOCK 1
#endif
#ifndef MG_ENABLE_DIRECTORY_LISTING #ifndef MG_ENABLE_DIRECTORY_LISTING
#define MG_ENABLE_DIRECTORY_LISTING 0 #define MG_ENABLE_DIRECTORY_LISTING 0
#endif #endif
@@ -366,6 +470,9 @@ struct mg_str {
#define MG_NULL_STR \ #define MG_NULL_STR \
{ NULL, 0 } { NULL, 0 }
// Using macro to avoid shadowing C++ struct constructor, see #1298
#define mg_str(s) mg_str_s(s)
struct mg_str mg_str(const char *s); struct mg_str mg_str(const char *s);
struct mg_str mg_str_n(const char *s, size_t n); struct mg_str mg_str_n(const char *s, size_t n);
int mg_lower(const char *s); int mg_lower(const char *s);
@@ -382,9 +489,6 @@ const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle);
#if MG_ENABLE_MGOS
#include <common/cs_dbg.h>
#else
#if MG_ENABLE_LOG #if MG_ENABLE_LOG
#define LOG(level, args) \ #define LOG(level, args) \
do { \ do { \
@@ -394,27 +498,28 @@ enum { LL_NONE, LL_ERROR, LL_INFO, LL_DEBUG, LL_VERBOSE_DEBUG };
bool mg_log_prefix(int ll, const char *file, int line, const char *fname); bool mg_log_prefix(int ll, const char *file, int line, const char *fname);
void mg_log(const char *fmt, ...) PRINTF_LIKE(1, 2); void mg_log(const char *fmt, ...) PRINTF_LIKE(1, 2);
void mg_log_set(const char *spec); void mg_log_set(const char *spec);
void mg_log_set_callback(void (*fn)(const void *, int, void *), void *param); void mg_log_set_callback(void (*fn)(const void *, size_t, void *), void *param);
#else #else
#define LOG(level, args) #define LOG(level, args) (void) 0
#endif #define mg_log_set(x) (void) (x)
#endif #endif
struct mg_timer { struct mg_timer {
int period_ms; // Timer period in milliseconds unsigned long period_ms; // Timer period in milliseconds
int flags; // Possible flags values below unsigned flags; // Possible flags values below
#define MG_TIMER_REPEAT 1 // Call function periodically, otherwise run once #define MG_TIMER_REPEAT 1 // Call function periodically, otherwise run once
#define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set #define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set
void (*fn)(void *); // Function to call void (*fn)(void *); // Function to call
void *arg; // Function agrument void *arg; // Function argument
unsigned long expire; // Expiration timestamp in milliseconds unsigned long expire; // Expiration timestamp in milliseconds
struct mg_timer *next; // Linkage in g_timers list struct mg_timer *next; // Linkage in g_timers list
}; };
extern struct mg_timer *g_timers; // Global list of timers extern struct mg_timer *g_timers; // Global list of timers
void mg_timer_init(struct mg_timer *, int ms, int, void (*fn)(void *), void *); void mg_timer_init(struct mg_timer *, unsigned long ms, unsigned,
void (*fn)(void *), void *);
void mg_timer_free(struct mg_timer *); void mg_timer_free(struct mg_timer *);
void mg_timer_poll(unsigned long uptime_ms); void mg_timer_poll(unsigned long uptime_ms);
@@ -422,20 +527,33 @@ void mg_timer_poll(unsigned long uptime_ms);
char *mg_file_read(const char *path); // WEAK symbol makes it possible to define a "default" function implementation,
// which could be overridden by the user who can define a function with the
// same name without linking conflict
#if !defined(WEAK)
#if (defined(__GNUC__) || defined(__clang__) || \
defined(__TI_COMPILER_VERSION__)) && \
!defined(_WIN32) && !defined(__CYGWIN__)
#define WEAK __attribute__((weak))
#else
#define WEAK
#endif
#endif
char *mg_file_read(const char *path, size_t *size);
int64_t mg_file_size(const char *path); int64_t mg_file_size(const char *path);
bool mg_file_write(const char *path, const void *buf, size_t len); bool mg_file_write(const char *path, const void *buf, size_t len);
bool mg_file_printf(const char *path, const char *fmt, ...); bool mg_file_printf(const char *path, const char *fmt, ...);
void mg_random(void *buf, size_t len); void mg_random(void *buf, size_t len) WEAK;
bool mg_globmatch(const char *pattern, int plen, const char *s, int n); bool mg_globmatch(const char *pattern, size_t plen, const char *s, size_t n);
bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v); bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v);
uint16_t mg_ntohs(uint16_t net); uint16_t mg_ntohs(uint16_t net);
uint32_t mg_ntohl(uint32_t net); uint32_t mg_ntohl(uint32_t net);
uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len); uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len);
char *mg_hexdump(const void *buf, size_t len); char *mg_hexdump(const void *buf, size_t len);
char *mg_hex(const void *buf, int len, char *dst); char *mg_hex(const void *buf, size_t len, char *dst);
void mg_unhex(const char *buf, int len, unsigned char *to); void mg_unhex(const char *buf, size_t len, unsigned char *to);
unsigned long mg_unhexn(const char *s, int len); unsigned long mg_unhexn(const char *s, size_t len);
int mg_asprintf(char **buf, size_t size, const char *fmt, ...); int mg_asprintf(char **buf, size_t size, const char *fmt, ...);
int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap); int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap);
int64_t mg_to64(struct mg_str str); int64_t mg_to64(struct mg_str str);
@@ -450,26 +568,11 @@ typedef struct _stati64 mg_stat_t;
typedef struct stat mg_stat_t; typedef struct stat mg_stat_t;
#endif #endif
int mg_stat(const char *path, mg_stat_t *); int mg_stat(const char *path, mg_stat_t *);
FILE *mg_fopen(const char *fp, const char *mode);
#endif #endif
#define mg_htons(x) mg_ntohs(x) #define mg_htons(x) mg_ntohs(x)
#define mg_htonl(x) mg_ntohl(x) #define mg_htonl(x) mg_ntohl(x)
#define MG_SWAP16(x) ((((x) >> 8) & 255) | ((x & 255) << 8))
#define MG_SWAP32(x) \
(((x) >> 24) | (((x) &0xff0000) >> 8) | (((x) &0xff00) << 8) | ((x) << 24))
#if !defined(WEAK)
#if (defined(__GNUC__) || defined(__clang__) || \
defined(__TI_COMPILER_VERSION__)) && \
!defined(_WIN32) && !defined(__CYGWIN__)
#define WEAK __attribute__((weak))
#else
#define WEAK
#endif
#endif
// Expands to a string representation of its argument: e.g. // Expands to a string representation of its argument: e.g.
// MG_STRINGIFY_LITERAL(5) expands to "5" // MG_STRINGIFY_LITERAL(5) expands to "5"
#if !defined(_MSC_VER) || _MSC_VER >= 1900 #if !defined(_MSC_VER) || _MSC_VER >= 1900
@@ -477,7 +580,12 @@ FILE *mg_fopen(const char *fp, const char *mode);
#else #else
#define MG_STRINGIFY_LITERAL(x) #x #define MG_STRINGIFY_LITERAL(x) #x
#endif #endif
// Expands to a string representation of its argument, which can be a macro:
// #define FOO 123
// MG_STRINGIFY_MACRO(FOO) // Expands to 123
#define MG_STRINGIFY_MACRO(x) MG_STRINGIFY_LITERAL(x)
// Linked list management macros
#define LIST_ADD_HEAD(type_, head_, elem_) \ #define LIST_ADD_HEAD(type_, head_, elem_) \
do { \ do { \
(elem_)->next = (*head_); \ (elem_)->next = (*head_); \
@@ -498,11 +606,6 @@ FILE *mg_fopen(const char *fp, const char *mode);
*h = (elem_)->next; \ *h = (elem_)->next; \
} while (0) } while (0)
// Expands to a string representation of its argument, which can be a macro:
// #define FOO 123
// MG_STRINGIFY_MACRO(FOO) // Expands to 123
#define MG_STRINGIFY_MACRO(x) MG_STRINGIFY_LITERAL(x)
unsigned short mg_url_port(const char *url); unsigned short mg_url_port(const char *url);
@@ -574,7 +677,7 @@ enum {
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_READ, // Data received from socket struct mg_str *
MG_EV_WRITE, // Data written to socket int *num_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 *
MG_EV_HTTP_CHUNK, // HTTP chunk (partial msg) struct mg_http_message * MG_EV_HTTP_CHUNK, // HTTP chunk (partial msg) struct mg_http_message *
@@ -613,7 +716,7 @@ struct mg_mgr {
int dnstimeout; // DNS resolve timeout in milliseconds int dnstimeout; // DNS resolve timeout in milliseconds
unsigned long nextid; // Next connection ID unsigned long nextid; // Next connection ID
void *userdata; // Arbitrary user data pointer void *userdata; // Arbitrary user data pointer
#if MG_ARCH == MG_ARCH_FREERTOS #if MG_ARCH == MG_ARCH_FREERTOS_TCP
SocketSet_t ss; // NOTE(lsm): referenced from socket struct SocketSet_t ss; // NOTE(lsm): referenced from socket struct
#endif #endif
}; };
@@ -621,13 +724,13 @@ struct mg_mgr {
struct mg_connection { struct mg_connection {
struct mg_connection *next; // Linkage in struct mg_mgr :: connections struct mg_connection *next; // Linkage in struct mg_mgr :: connections
struct mg_mgr *mgr; // Our container struct mg_mgr *mgr; // Our container
struct mg_addr peer; // Remote peer address struct mg_addr peer; // Remote address. For listeners, local address
void *fd; // Connected socket, or LWIP data void *fd; // Connected socket, or LWIP data
unsigned long id; // Auto-incrementing unique connection ID unsigned long id; // Auto-incrementing unique connection ID
struct mg_iobuf recv; // Incoming data struct mg_iobuf recv; // Incoming data
struct mg_iobuf send; // Outgoing data struct mg_iobuf send; // Outgoing data
mg_event_handler_t fn; // User-specified event handler function mg_event_handler_t fn; // User-specified event handler function
void *fn_data; // User-speficied function parameter void *fn_data; // User-specified function parameter
mg_event_handler_t pfn; // Protocol-specific handler function mg_event_handler_t pfn; // Protocol-specific handler function
void *pfn_data; // Protocol-specific function parameter void *pfn_data; // Protocol-specific function parameter
char label[50]; // Arbitrary label char label[50]; // Arbitrary label
@@ -635,7 +738,7 @@ struct mg_connection {
unsigned is_listening : 1; // Listening connection unsigned is_listening : 1; // Listening connection
unsigned is_client : 1; // Outbound (client) connection unsigned is_client : 1; // Outbound (client) connection
unsigned is_accepted : 1; // Accepted (server) connection unsigned is_accepted : 1; // Accepted (server) connection
unsigned is_resolving : 1; // Non-blocking DNS resolv is in progress unsigned is_resolving : 1; // Non-blocking DNS resolution is in progress
unsigned is_connecting : 1; // Non-blocking connect is in progress unsigned is_connecting : 1; // Non-blocking connect is in progress
unsigned is_tls : 1; // TLS-enabled connection unsigned is_tls : 1; // TLS-enabled connection
unsigned is_tls_hs : 1; // TLS handshake is in progress unsigned is_tls_hs : 1; // TLS handshake is in progress
@@ -656,7 +759,7 @@ struct mg_connection *mg_listen(struct mg_mgr *, const char *url,
mg_event_handler_t fn, void *fn_data); mg_event_handler_t fn, void *fn_data);
struct mg_connection *mg_connect(struct mg_mgr *, const char *url, struct mg_connection *mg_connect(struct mg_mgr *, const char *url,
mg_event_handler_t fn, void *fn_data); mg_event_handler_t fn, void *fn_data);
int mg_send(struct mg_connection *, const void *, size_t); bool mg_send(struct mg_connection *, const void *, size_t);
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);
char *mg_straddr(struct mg_connection *, char *, size_t); char *mg_straddr(struct mg_connection *, char *, size_t);
@@ -689,7 +792,15 @@ struct mg_http_message {
// Parameter for mg_http_serve_dir() // Parameter for mg_http_serve_dir()
struct mg_http_serve_opts { struct mg_http_serve_opts {
const char *root_dir; // Web root directory, must be non-NULL const char *root_dir; // Web root directory, must be non-NULL
const char *ssi_pattern; // SSI filename pattern, e.g. #.shtml const char *ssi_pattern; // SSI file name pattern, e.g. #.shtml
const char *extra_headers; // Extra HTTP headers to add in responses
};
// Parameter for mg_http_next_multipart
struct mg_http_part {
struct mg_str name; // Form field name
struct mg_str filename; // Filename for file uploads
struct mg_str body; // Part contents
}; };
int mg_http_parse(const char *s, size_t len, struct mg_http_message *); int mg_http_parse(const char *s, size_t len, struct mg_http_message *);
@@ -709,14 +820,16 @@ void mg_http_reply(struct mg_connection *, int status_code, const char *headers,
const char *body_fmt, ...); const char *body_fmt, ...);
struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name); struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name);
void mg_http_event_handler(struct mg_connection *c, int ev); void mg_http_event_handler(struct mg_connection *c, int ev);
int mg_http_get_var(const struct mg_str *, const char *name, char *, int); int mg_http_get_var(const struct mg_str *, const char *name, char *, size_t);
int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form); int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form);
int mg_url_encode(const char *s, size_t n, char *buf, size_t len); size_t mg_url_encode(const char *s, size_t n, char *buf, size_t len);
void mg_http_creds(struct mg_http_message *, char *user, int, char *pass, int); void mg_http_creds(struct mg_http_message *, char *, size_t, char *, size_t);
bool mg_http_match_uri(const struct mg_http_message *, const char *glob); bool mg_http_match_uri(const struct mg_http_message *, const char *glob);
int mg_http_upload(struct mg_connection *, struct mg_http_message *hm, int mg_http_upload(struct mg_connection *, struct mg_http_message *hm,
const char *dir); const char *dir);
void mg_http_bauth(struct mg_connection *, const char *user, const char *pass); void mg_http_bauth(struct mg_connection *, const char *user, const char *pass);
struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v);
size_t mg_http_next_multipart(struct mg_str, size_t, struct mg_http_part *);
void mg_http_serve_ssi(struct mg_connection *c, const char *root, void mg_http_serve_ssi(struct mg_connection *c, const char *root,
@@ -732,11 +845,11 @@ struct mg_tls_opts {
struct mg_str srvname; // If not empty, enables server name verification struct mg_str srvname; // If not empty, enables server name verification
}; };
int mg_tls_init(struct mg_connection *, struct mg_tls_opts *); void mg_tls_init(struct mg_connection *, struct mg_tls_opts *);
int mg_tls_free(struct mg_connection *); void mg_tls_free(struct mg_connection *);
int mg_tls_send(struct mg_connection *, const void *buf, size_t len, int *fail); long mg_tls_send(struct mg_connection *, const void *buf, size_t len);
int mg_tls_recv(struct mg_connection *, void *buf, size_t len, int *fail); long mg_tls_recv(struct mg_connection *, void *buf, size_t len);
int mg_tls_handshake(struct mg_connection *); void mg_tls_handshake(struct mg_connection *);
#define WEBSOCKET_OP_CONTINUE 0 #define WEBSOCKET_OP_CONTINUE 0
@@ -819,16 +932,16 @@ struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url,
mg_event_handler_t fn, void *fn_data); mg_event_handler_t fn, void *fn_data);
struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url, struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data); mg_event_handler_t fn, void *fn_data);
void mg_mqtt_pub(struct mg_connection *, struct mg_str *topic, void mg_mqtt_pub(struct mg_connection *c, struct mg_str *topic,
struct mg_str *data); struct mg_str *data, int qos, bool retain);
void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic); void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic, int qos);
int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m); int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m);
void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags, void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
uint32_t len); uint32_t len);
int mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, size_t mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic,
uint8_t *qos, int pos); uint8_t *qos, size_t pos);
int mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, size_t mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic,
int pos); size_t pos);
void mg_mqtt_ping(struct mg_connection *); void mg_mqtt_ping(struct mg_connection *);
void mg_mqtt_pong(struct mg_connection *); void mg_mqtt_pong(struct mg_connection *);
void mg_mqtt_disconnect(struct mg_connection *); void mg_mqtt_disconnect(struct mg_connection *);
@@ -871,3 +984,8 @@ bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs, size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
bool is_question, struct mg_dns_rr *); bool is_question, struct mg_dns_rr *);
size_t mg_dns_decode_name(const uint8_t *, size_t, size_t, char *, size_t); size_t mg_dns_decode_name(const uint8_t *, size_t, size_t, char *, size_t);
#ifdef __cplusplus
}
#endif
#endif // MONGOOSE_H
+16 -67
View File
@@ -5,54 +5,20 @@
#define MG_ARCH_WIN32 2 #define MG_ARCH_WIN32 2
#define MG_ARCH_ESP32 3 #define MG_ARCH_ESP32 3
#define MG_ARCH_ESP8266 4 #define MG_ARCH_ESP8266 4
#define MG_ARCH_CC3100 5 #define MG_ARCH_FREERTOS_TCP 5
#define MG_ARCH_CC3200 6 #define MG_ARCH_FREERTOS_LWIP 6
#define MG_ARCH_CC3220 7
#define MG_ARCH_MSP432 8
#define MG_ARCH_TM4C129 9
#define MG_ARCH_MBED 10
#define MG_ARCH_WINCE 11
#define MG_ARCH_NXP_LPC 12
#define MG_ARCH_NXP_KINETIS 13
#define MG_ARCH_NRF51 14
#define MG_ARCH_NRF52 15
#define MG_ARCH_PIC32 16
#define MG_ARCH_RS14100 17
#define MG_ARCH_STM32 18
#define MG_ARCH_FREERTOS 19
#if !defined(MG_ARCH) #if !defined(MG_ARCH)
#if defined(TARGET_IS_MSP432P4XX) || defined(__MSP432P401R__) #if defined(__unix__) || defined(__APPLE__)
#define MG_ARCH MG_ARCH_MSP432
#elif defined(cc3200) || defined(TARGET_IS_CC3200)
#define MG_ARCH MG_ARCH_CC3200
#elif defined(cc3220) || defined(TARGET_IS_CC3220)
#define MG_ARCH MG_ARCH_CC3220
#elif defined(__unix__) || defined(__APPLE__)
#define MG_ARCH MG_ARCH_UNIX #define MG_ARCH MG_ARCH_UNIX
#elif defined(WINCE)
#define MG_ARCH MG_ARCH_WINCE
#elif defined(_WIN32) #elif defined(_WIN32)
#define MG_ARCH MG_ARCH_WIN32 #define MG_ARCH MG_ARCH_WIN32
#elif defined(__MBED__)
#define MG_ARCH MG_ARCH_MBED
#elif defined(__USE_LPCOPEN)
#define MG_ARCH MG_ARCH_NXP_LPC
#elif defined(FRDM_K64F) || defined(FREEDOM)
#define MG_ARCH MG_ARCH_NXP_KINETIS
#elif defined(PIC32)
#define MG_ARCH MG_ARCH_PIC32
#elif defined(ICACHE_FLASH) || defined(ICACHE_RAM_ATTR) #elif defined(ICACHE_FLASH) || defined(ICACHE_RAM_ATTR)
#define MG_ARCH MG_ARCH_ESP8266 #define MG_ARCH MG_ARCH_ESP8266
#elif defined(ESP_PLATFORM) #elif defined(ESP_PLATFORM)
#define MG_ARCH MG_ARCH_ESP32 #define MG_ARCH MG_ARCH_ESP32
#elif defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || \ #elif defined(FREERTOS_IP_H)
defined(TARGET_IS_TM4C129_RA2) #define MG_ARCH MG_ARCH_FREERTOS_TCP
#define MG_ARCH MG_ARCH_TM4C129
#elif defined(RS14100)
#define MG_ARCH MG_ARCH_RS14100
#elif defined(STM32)
#define MG_ARCH MG_ARCH_STM32
#endif #endif
#if !defined(MG_ARCH) #if !defined(MG_ARCH)
@@ -60,34 +26,6 @@
#endif #endif
#endif // !defined(MG_ARCH) #endif // !defined(MG_ARCH)
#define WIN32_LEAN_AND_MEAN
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
// Standard C headers
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#if MG_ARCH == MG_ARCH_CUSTOM
#include <mongoose_custom.h>
#endif
#include "arch_esp32.h"
#include "arch_esp8266.h"
#include "arch_freertos.h"
#include "arch_unix.h"
#include "arch_win32.h"
#if !defined(PRINTF_LIKE) #if !defined(PRINTF_LIKE)
#if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__) #if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__)
#define PRINTF_LIKE(f, a) __attribute__((format(printf, f, a))) #define PRINTF_LIKE(f, a) __attribute__((format(printf, f, a)))
@@ -95,3 +33,14 @@
#define PRINTF_LIKE(f, a) #define PRINTF_LIKE(f, a)
#endif #endif
#endif #endif
#if MG_ARCH == MG_ARCH_CUSTOM
#include <mongoose_custom.h>
#endif
#include "arch_esp32.h"
#include "arch_esp8266.h"
#include "arch_freertos_lwip.h"
#include "arch_freertos_tcp.h"
#include "arch_unix.h"
#include "arch_win32.h"
+12
View File
@@ -2,9 +2,21 @@
#if MG_ARCH == MG_ARCH_ESP32 #if MG_ARCH == MG_ARCH_ESP32
#include <ctype.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <netdb.h> #include <netdb.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#define MG_DIRSEP '/' #define MG_DIRSEP '/'
#define MG_INT64_FMT "%lld" #define MG_INT64_FMT "%lld"
#ifndef MG_PATH_MAX #ifndef MG_PATH_MAX
+15 -1
View File
@@ -2,11 +2,25 @@
#if MG_ARCH == MG_ARCH_ESP8266 #if MG_ARCH == MG_ARCH_ESP8266
#include <ctype.h>
#include <dirent.h> #include <dirent.h>
#include <esp_system.h> #include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <netdb.h> #include <netdb.h>
#include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <esp_system.h>
#define MG_DIRSEP '/' #define MG_DIRSEP '/'
#define MG_INT64_FMT "%lld" #define MG_INT64_FMT "%lld"
+44
View File
@@ -0,0 +1,44 @@
#pragma once
#if MG_ARCH == MG_ARCH_FREERTOS_LWIP
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#if defined(__GNUC__)
#include <sys/time.h>
#else
typedef long suseconds_t;
struct timeval {
time_t tv_sec;
suseconds_t tv_usec;
};
#endif
#if MG_ENABLE_FS
#include <sys/stat.h>
#endif
#include <FreeRTOS.h>
#include <task.h>
#include <lwip/sockets.h>
#define MG_INT64_FMT "%lld"
#define MG_DIRSEP '/'
// Re-route calloc/free to the FreeRTOS's functions, don't use stdlib
static inline void *mg_calloc(int cnt, size_t size) {
void *p = pvPortMalloc(cnt * size);
if (p != NULL) memset(p, 0, size);
return p;
}
#define calloc(a, b) mg_calloc((a), (b))
#define free(a) vPortFree(a)
#define malloc(a) pvPortMalloc(a)
#define gmtime_r(a, b) gmtime(a)
#endif // MG_ARCH == MG_ARCH_FREERTOS_LWIP
+54 -29
View File
@@ -1,16 +1,32 @@
#pragma once #pragma once
#if MG_ARCH == MG_ARCH_FREERTOS #if MG_ARCH == MG_ARCH_FREERTOS_TCP
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if MG_ENABLE_FS
#include <sys/stat.h>
#endif
#include <FreeRTOS.h> #include <FreeRTOS.h>
#include <task.h>
#include <FreeRTOS_IP.h> #include <FreeRTOS_IP.h>
#include <FreeRTOS_Sockets.h> #include <FreeRTOS_Sockets.h>
#include <stdbool.h> #include <task.h>
#define MG_INT64_FMT "%lld" #define MG_INT64_FMT "%lld"
#define MG_DIRSEP '/' #define MG_DIRSEP '/'
// Why FreeRTOS-TCP did not implement a clean BSD API, but its own thing
// with FreeRTOS_ prefix, is beyond me
#define IPPROTO_TCP FREERTOS_IPPROTO_TCP #define IPPROTO_TCP FREERTOS_IPPROTO_TCP
#define IPPROTO_UDP FREERTOS_IPPROTO_UDP #define IPPROTO_UDP FREERTOS_IPPROTO_UDP
#define AF_INET FREERTOS_AF_INET #define AF_INET FREERTOS_AF_INET
@@ -21,9 +37,7 @@
#define SOL_SOCKET 0 #define SOL_SOCKET 0
#define SO_REUSEADDR 0 #define SO_REUSEADDR 0
#define sockaddr_in freertos_sockaddr #define sockaddr_in freertos_sockaddr
struct sockaddr { #define sockaddr freertos_sockaddr
uint8_t sa_len, sa_family;
};
#define accept(a, b, c) FreeRTOS_accept((a), (b), (c)) #define accept(a, b, c) FreeRTOS_accept((a), (b), (c))
#define connect(a, b, c) FreeRTOS_connect((a), (b), (c)) #define connect(a, b, c) FreeRTOS_connect((a), (b), (c))
#define bind(a, b, c) FreeRTOS_bind((a), (b), (c)) #define bind(a, b, c) FreeRTOS_bind((a), (b), (c))
@@ -38,27 +52,38 @@ struct sockaddr {
#define closesocket(x) FreeRTOS_closesocket(x) #define closesocket(x) FreeRTOS_closesocket(x)
#define gethostbyname(x) FreeRTOS_gethostbyname(x) #define gethostbyname(x) FreeRTOS_gethostbyname(x)
#include <ff_stdio.h> // Re-route calloc/free to the FreeRTOS's functions, don't use stdlib
static inline void *mg_calloc(int cnt, size_t size) {
#undef FILE void *p = pvPortMalloc(cnt * size);
#define FILE FF_FILE if (p != NULL) memset(p, 0, size);
//#define SEEK_SET FF_SEEK_SET return p;
//#define SEEK_END FF_SEEK_END
#define stat(a, b) ff_stat((a), (b))
#define fopen(a, b) ff_fopen((a), (b))
#define fclose(a) ff_fclose(a)
#define fread(a, b, c, d) ff_fread((a), (b), (c), (d))
#define fwrite(a, b, c, d) ff_fwrite((a), (b), (c), (d))
#define vfprintf ff_vfprintf
#define fprintf ff_fprintf
#define remove(a) ff_remove(a)
#define rename(a, b) ff_rename((a), (b), 1)
static inline int ff_vfprintf(FF_FILE *fp, const char *fmt, va_list ap) {
char *buf = NULL;
int n = mg_vasprintf(&buf, 0, fmt, ap);
if (buf != NULL) ff_fwrite(buf, 1, n, fp), free(buf);
return n;
} }
#define calloc(a, b) mg_calloc((a), (b))
#define free(a) vPortFree(a)
#define malloc(a) pvPortMalloc(a)
#define gmtime_r(a, b) gmtime(a)
#if !defined(__GNUC__)
// copied from GCC on ARM; for some reason useconds are signed
typedef long suseconds_t;
struct timeval {
time_t tv_sec;
suseconds_t tv_usec;
};
#endif #endif
#ifndef EINPROGRESS
#define EINPROGRESS pdFREERTOS_ERRNO_EINPROGRESS
#endif
#ifndef EWOULDBLOCK
#define EWOULDBLOCK pdFREERTOS_ERRNO_EWOULDBLOCK
#endif
#ifndef EAGAIN
#define EAGAIN pdFREERTOS_ERRNO_EAGAIN
#endif
#ifndef EINTR
#define EINTR pdFREERTOS_ERRNO_EINTR
#endif
#endif // MG_ARCH == MG_ARCH_FREERTOS_TCP
+13
View File
@@ -5,17 +5,30 @@
#define _DARWIN_UNLIMITED_SELECT 1 #define _DARWIN_UNLIMITED_SELECT 1
#include <arpa/inet.h> #include <arpa/inet.h>
#include <ctype.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <limits.h>
#include <netdb.h> #include <netdb.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <signal.h> #include <signal.h>
#include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h> #include <sys/select.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#define MG_DIRSEP '/' #define MG_DIRSEP '/'
#define MG_ENABLE_POSIX 1 #define MG_ENABLE_POSIX 1
#define MG_INT64_FMT "%" PRId64 #define MG_INT64_FMT "%" PRId64
+45
View File
@@ -2,6 +2,31 @@
#if MG_ARCH == MG_ARCH_WIN32 #if MG_ARCH == MG_ARCH_WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#endif
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#if defined(_MSC_VER) && _MSC_VER < 1700 #if defined(_MSC_VER) && _MSC_VER < 1700
#define __func__ "" #define __func__ ""
typedef __int64 int64_t; typedef __int64 int64_t;
@@ -29,6 +54,7 @@ typedef enum { false = 0, true = 1 } bool;
#define strdup(x) _strdup(x) #define strdup(x) _strdup(x)
#endif #endif
typedef unsigned suseconds_t;
typedef int socklen_t; typedef int socklen_t;
#define MG_DIRSEP '\\' #define MG_DIRSEP '\\'
#ifndef PATH_MAX #ifndef PATH_MAX
@@ -41,6 +67,7 @@ typedef int socklen_t;
#define EWOULDBLOCK WSAEWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK
#endif #endif
#define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX) #define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX)
#define fopen(a, b) mg_fopen((a), (b))
#ifndef va_copy #ifndef va_copy
#ifdef __va_copy #ifdef __va_copy
#define va_copy __va_copy #define va_copy __va_copy
@@ -54,4 +81,22 @@ typedef int socklen_t;
#define MG_INT64_FMT "%I64d" #define MG_INT64_FMT "%I64d"
static __inline FILE *mg_fopen(const char *path, const char *mode) {
wchar_t b1[PATH_MAX], b2[10];
MultiByteToWideChar(CP_UTF8, 0, path, -1, b1, sizeof(b1) / sizeof(b1[0]));
MultiByteToWideChar(CP_UTF8, 0, mode, -1, b2, sizeof(b2) / sizeof(b2[0]));
return _wfopen(b1, b2);
}
// https://lgtm.com/rules/2154840805/ -gmtime, localtime, ctime and asctime
static __inline struct tm *gmtime_r(time_t *t, struct tm *tm) {
(void) tm;
return gmtime(t);
}
static __inline struct tm *localtime_r(time_t *t, struct tm *tm) {
(void) tm;
return localtime(t);
}
#endif #endif
+10 -10
View File
@@ -31,16 +31,16 @@ static int mg_b64rev(int c) {
} }
int mg_base64_update(unsigned char ch, char *to, int n) { int mg_base64_update(unsigned char ch, char *to, int n) {
unsigned char rem = (n & 3) % 3; int rem = (n & 3) % 3;
if (rem == 0) { if (rem == 0) {
to[n] = mg_b64idx(ch >> 2); to[n] = (char) mg_b64idx(ch >> 2);
to[++n] = (ch & 3) << 4; to[++n] = (char) ((ch & 3) << 4);
} else if (rem == 1) { } else if (rem == 1) {
to[n] = mg_b64idx(to[n] | (ch >> 4)); to[n] = (char) mg_b64idx(to[n] | (ch >> 4));
to[++n] = (ch & 15) << 2; to[++n] = (char) ((ch & 15) << 2);
} else { } else {
to[n] = mg_b64idx(to[n] | (ch >> 6)); to[n] = (char) mg_b64idx(to[n] | (ch >> 6));
to[++n] = mg_b64idx(ch & 63); to[++n] = (char) mg_b64idx(ch & 63);
n++; n++;
} }
return n; return n;
@@ -71,10 +71,10 @@ int mg_base64_decode(const char *src, int n, char *dst) {
int a = mg_b64rev(src[0]), b = mg_b64rev(src[1]), c = mg_b64rev(src[2]), int a = mg_b64rev(src[0]), b = mg_b64rev(src[1]), c = mg_b64rev(src[2]),
d = mg_b64rev(src[3]); d = mg_b64rev(src[3]);
if (a == 64 || a < 0 || b == 64 || b < 0 || c < 0 || d < 0) return 0; if (a == 64 || a < 0 || b == 64 || b < 0 || c < 0 || d < 0) return 0;
dst[len++] = (a << 2) | (b >> 4); dst[len++] = (char) ((a << 2) | (b >> 4));
if (src[2] != '=') { if (src[2] != '=') {
dst[len++] = (b << 4) | (c >> 2); dst[len++] = (char) ((b << 4) | (c >> 2));
if (src[3] != '=') dst[len++] = (c << 6) | d; if (src[3] != '=') dst[len++] = (char) ((c << 6) | d);
} }
src += 4; src += 4;
} }
+6 -11
View File
@@ -1,12 +1,6 @@
#pragma once #pragma once
#ifndef MG_ENABLE_LWIP #ifndef MG_ENABLE_SOCKET
#define MG_ENABLE_LWIP 0
#endif
#if MG_ENABLE_LWIP
#define MG_ENABLE_SOCKET 0
#elif !defined(MG_ENABLE_SOCKET)
#define MG_ENABLE_SOCKET 1 #define MG_ENABLE_SOCKET 1
#endif #endif
@@ -34,14 +28,15 @@
#define MG_ENABLE_LOG 1 #define MG_ENABLE_LOG 1
#endif #endif
#ifndef MG_ENABLE_MGOS
#define MG_ENABLE_MGOS 0
#endif
#ifndef MG_ENABLE_MD5 #ifndef MG_ENABLE_MD5
#define MG_ENABLE_MD5 0 #define MG_ENABLE_MD5 0
#endif #endif
// Set MG_ENABLE_WINSOCK=0 for Win32 builds with external IP stack (like LWIP)
#ifndef MG_ENABLE_WINSOCK
#define MG_ENABLE_WINSOCK 1
#endif
#ifndef MG_ENABLE_DIRECTORY_LISTING #ifndef MG_ENABLE_DIRECTORY_LISTING
#define MG_ENABLE_DIRECTORY_LISTING 0 #define MG_ENABLE_DIRECTORY_LISTING 0
#endif #endif
+14 -11
View File
@@ -70,11 +70,10 @@ size_t mg_dns_parse_name(const uint8_t *s, size_t n, size_t ofs, char *dst,
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs, size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
bool is_question, struct mg_dns_rr *rr) { bool is_question, struct mg_dns_rr *rr) {
const struct mg_dns_header *h = (struct mg_dns_header *) buf;
const uint8_t *s = buf + ofs, *e = &buf[len]; const uint8_t *s = buf + ofs, *e = &buf[len];
memset(rr, 0, sizeof(*rr)); memset(rr, 0, sizeof(*rr));
if (len < sizeof(*h)) return 0; // Too small, headers dont fit if (len < sizeof(struct mg_dns_header)) return 0; // Too small
if (len > 512) return 0; // Too large, we don't expect that if (len > 512) return 0; // Too large, we don't expect that
if (s >= e) return 0; // Overflow if (s >= e) return 0; // Overflow
@@ -82,15 +81,15 @@ size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
return 0; return 0;
s += rr->nlen + 4; s += rr->nlen + 4;
if (s > e) return 0; if (s > e) return 0;
rr->atype = ((uint16_t) s[-4] << 8) | s[-3]; rr->atype = (uint16_t)(((uint16_t) s[-4] << 8) | s[-3]);
rr->aclass = ((uint16_t) s[-2] << 8) | s[-1]; rr->aclass = (uint16_t)(((uint16_t) s[-2] << 8) | s[-1]);
if (is_question) return rr->nlen + 4; if (is_question) return (size_t)(rr->nlen + 4);
s += 6; s += 6;
if (s > e) return 0; if (s > e) return 0;
rr->alen = ((uint16_t) s[-2] << 8) | s[-1]; rr->alen = (uint16_t)(((uint16_t) s[-2] << 8) | s[-1]);
if (s + rr->alen > e) return 0; if (s + rr->alen > e) return 0;
return rr->nlen + rr->alen + 10; return (size_t)(rr->nlen + rr->alen + 10);
} }
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) { bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
@@ -242,14 +241,18 @@ static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms,
} else if ((d = (struct dns_data *) calloc(1, sizeof(*d))) == NULL) { } else if ((d = (struct dns_data *) calloc(1, sizeof(*d))) == NULL) {
mg_error(c, "resolve OOM"); mg_error(c, "resolve OOM");
} else { } else {
d->txnid = s_reqs ? s_reqs->txnid + 1 : 1; #if MG_ENABLE_LOG
char buf[100];
#endif
d->txnid = s_reqs ? (uint16_t)(s_reqs->txnid + 1) : 1;
d->next = s_reqs; d->next = s_reqs;
s_reqs = d; s_reqs = d;
d->expire = mg_millis() + ms; d->expire = mg_millis() + (unsigned long) ms;
d->c = c; d->c = c;
c->is_resolving = 1; c->is_resolving = 1;
LOG(LL_VERBOSE_DEBUG, ("%lu resolving %.*s, txnid %hu", c->id, LOG(LL_VERBOSE_DEBUG,
(int) name->len, name->ptr, d->txnid)); ("%lu resolving %.*s @ %s, txnid %hu", c->id, (int) name->len,
name->ptr, mg_ntoa(&dnsc->c->peer, buf, sizeof(buf)), d->txnid));
mg_dns_send(dnsc->c, name, d->txnid, ipv6); mg_dns_send(dnsc->c, name, d->txnid, ipv6);
} }
} }
+1 -1
View File
@@ -13,7 +13,7 @@ enum {
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_READ, // Data received from socket struct mg_str *
MG_EV_WRITE, // Data written to socket int *num_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 *
MG_EV_HTTP_CHUNK, // HTTP chunk (partial msg) struct mg_http_message * MG_EV_HTTP_CHUNK, // HTTP chunk (partial msg) struct mg_http_message *
+310 -103
View File
@@ -1,6 +1,6 @@
#include "http.h"
#include "arch.h" #include "arch.h"
#include "base64.h" #include "base64.h"
#include "http.h"
#include "log.h" #include "log.h"
#include "net.h" #include "net.h"
#include "private.h" #include "private.h"
@@ -10,7 +10,56 @@
#include "ws.h" #include "ws.h"
// Multipart POST example: // Multipart POST example:
// https://gist.github.com/cpq/b8dd247571e6ee9c54ef7e8dfcfecf48 // --xyz
// Content-Disposition: form-data; name="val"
//
// abcdef
// --xyz
// Content-Disposition: form-data; name="foo"; filename="a.txt"
// Content-Type: text/plain
//
// hello world
//
// --xyz--
size_t mg_http_next_multipart(struct mg_str body, size_t ofs,
struct mg_http_part *part) {
struct mg_str cd = mg_str_n("Content-Disposition", 19);
const char *s = body.ptr;
size_t b = ofs, h1, h2, b1, b2, max = body.len;
// Init part params
if (part != NULL) part->name = part->filename = part->body = mg_str_n(0, 0);
// Skip boundary
while (b + 2 < max && s[b] != '\r' && s[b + 1] != '\n') b++;
if (b <= ofs || b + 2 >= max) return 0;
// LOG(LL_INFO, ("B: %zu %zu [%.*s]", ofs, b - ofs, (int) (b - ofs), s));
// Skip headers
h1 = h2 = b + 2;
for (;;) {
while (h2 + 2 < max && s[h2] != '\r' && s[h2 + 1] != '\n') h2++;
if (h2 == h1) break;
if (h2 + 2 >= max) return 0;
// LOG(LL_INFO, ("Header: [%.*s]", (int) (h2 - h1), &s[h1]));
if (part != NULL && h1 + cd.len + 2 < h2 && s[h1 + cd.len] == ':' &&
mg_ncasecmp(&s[h1], cd.ptr, cd.len) == 0) {
struct mg_str v = mg_str_n(&s[h1 + cd.len + 2], h2 - (h1 + cd.len + 2));
part->name = mg_http_get_header_var(v, mg_str_n("name", 4));
part->filename = mg_http_get_header_var(v, mg_str_n("filename", 8));
}
h1 = h2 = h2 + 2;
}
b1 = b2 = h2 + 2;
while (b2 + 2 + (b - ofs) + 2 < max && !(s[b2] == '\r' && s[b2 + 1] == '\n' &&
memcmp(&s[b2 + 2], s, b - ofs) == 0))
b2++;
if (b2 + 2 >= max) return 0;
if (part != NULL) part->body = mg_str_n(&s[b1], b2 - b1);
// LOG(LL_INFO, ("Body: [%.*s]", (int) (b2 - b1), &s[b1]));
return b2 + 2;
}
void mg_http_bauth(struct mg_connection *c, const char *user, void mg_http_bauth(struct mg_connection *c, const char *user,
const char *pass) { const char *pass) {
@@ -18,16 +67,20 @@ void mg_http_bauth(struct mg_connection *c, const char *user,
size_t need = c->send.len + 36 + (u.len + p.len) * 2; size_t need = c->send.len + 36 + (u.len + p.len) * 2;
if (c->send.size < need) mg_iobuf_resize(&c->send, need); if (c->send.size < need) mg_iobuf_resize(&c->send, need);
if (c->send.size >= need) { if (c->send.size >= need) {
size_t i, n = 0; int i, n = 0;
char *buf = (char *) &c->send.buf[c->send.len + 21]; char *buf = (char *) &c->send.buf[c->send.len + 21];
memcpy(&buf[-21], "Authorization: Basic ", 21); // DON'T use mg_send! memcpy(&buf[-21], "Authorization: Basic ", 21); // DON'T use mg_send!
for (i = 0; i < u.len; i++) n = mg_base64_update(u.ptr[i], buf, n); for (i = 0; i < (int) u.len; i++) {
n = mg_base64_update(((unsigned char *) u.ptr)[i], buf, n);
}
if (p.len > 0) { if (p.len > 0) {
n = mg_base64_update(':', buf, n); n = mg_base64_update(':', buf, n);
for (i = 0; i < p.len; i++) n = mg_base64_update(p.ptr[i], buf, n); for (i = 0; i < (int) p.len; i++) {
n = mg_base64_update(((unsigned char *) p.ptr)[i], buf, n);
}
} }
n = mg_base64_final(buf, n); n = mg_base64_final(buf, n);
c->send.len += 21 + n + 2; c->send.len += 21 + (size_t) n + 2;
memcpy(&c->send.buf[c->send.len - 2], "\r\n", 2); memcpy(&c->send.buf[c->send.len - 2], "\r\n", 2);
} else { } else {
LOG(LL_ERROR, ("%lu %s cannot resize iobuf %d->%d ", c->id, c->label, LOG(LL_ERROR, ("%lu %s cannot resize iobuf %d->%d ", c->id, c->label,
@@ -36,7 +89,7 @@ void mg_http_bauth(struct mg_connection *c, const char *user,
} }
int mg_http_get_var(const struct mg_str *buf, const char *name, char *dst, int mg_http_get_var(const struct mg_str *buf, const char *name, char *dst,
int dst_len) { size_t dst_len) {
const char *p, *e, *s; const char *p, *e, *s;
size_t name_len; size_t name_len;
int len; int len;
@@ -105,7 +158,7 @@ static const char *skip(const char *s, const char *e, const char *d,
struct mg_str *v) { struct mg_str *v) {
v->ptr = s; v->ptr = s;
while (s < e && *s != '\n' && strchr(d, *s) == NULL) s++; while (s < e && *s != '\n' && strchr(d, *s) == NULL) s++;
v->len = s - v->ptr; v->len = (size_t)(s - v->ptr);
while (s < e && strchr(d, *s) != NULL) s++; while (s < e && strchr(d, *s) != NULL) s++;
return s; return s;
} }
@@ -147,7 +200,7 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
hm->message.ptr = hm->head.ptr = s; hm->message.ptr = hm->head.ptr = s;
hm->body.ptr = end; hm->body.ptr = end;
hm->head.len = req_len; hm->head.len = (size_t) req_len;
hm->chunk.ptr = end; hm->chunk.ptr = end;
hm->message.len = hm->body.len = (size_t) ~0; // Set body length to infinite hm->message.len = hm->body.len = (size_t) ~0; // Set body length to infinite
@@ -156,21 +209,21 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
s = skip(s, end, " ", &hm->uri); s = skip(s, end, " ", &hm->uri);
s = skip(s, end, "\r\n", &hm->proto); s = skip(s, end, "\r\n", &hm->proto);
// Sanity check // Sanity check. Allow protocol/reason to be empty
if (hm->method.len == 0 || hm->uri.len == 0 || hm->proto.len == 0) return -1; if (hm->method.len == 0 || hm->uri.len == 0) return -1;
// If URI contains '?' character, setup query string // If URI contains '?' character, setup query string
if ((qs = (const char *) memchr(hm->uri.ptr, '?', hm->uri.len)) != NULL) { if ((qs = (const char *) memchr(hm->uri.ptr, '?', hm->uri.len)) != NULL) {
hm->query.ptr = qs + 1; hm->query.ptr = qs + 1;
hm->query.len = &hm->uri.ptr[hm->uri.len] - (qs + 1); hm->query.len = (size_t)(&hm->uri.ptr[hm->uri.len] - (qs + 1));
hm->uri.len = qs - hm->uri.ptr; hm->uri.len = (size_t)(qs - hm->uri.ptr);
} }
mg_http_parse_headers(s, end, hm->headers, mg_http_parse_headers(s, end, hm->headers,
sizeof(hm->headers) / sizeof(hm->headers[0])); sizeof(hm->headers) / sizeof(hm->headers[0]));
if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) { if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) {
hm->body.len = (size_t) mg_to64(*cl); hm->body.len = (size_t) mg_to64(*cl);
hm->message.len = req_len + hm->body.len; hm->message.len = (size_t) req_len + hm->body.len;
} }
// mg_http_parse() is used to parse both HTTP requests and HTTP // mg_http_parse() is used to parse both HTTP requests and HTTP
@@ -190,14 +243,14 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
mg_vcasecmp(&hm->method, "PUT") != 0 && mg_vcasecmp(&hm->method, "PUT") != 0 &&
mg_vcasecmp(&hm->method, "POST") != 0) { mg_vcasecmp(&hm->method, "POST") != 0) {
hm->body.len = 0; hm->body.len = 0;
hm->message.len = req_len; hm->message.len = (size_t) req_len;
} }
// The 204 (No content) responses also have 0 body length // The 204 (No content) responses also have 0 body length
if (hm->body.len == (size_t) ~0 && is_response && if (hm->body.len == (size_t) ~0 && is_response &&
mg_vcasecmp(&hm->uri, "204") == 0) { mg_vcasecmp(&hm->uri, "204") == 0) {
hm->body.len = 0; hm->body.len = 0;
hm->message.len = req_len; hm->message.len = (size_t) req_len;
} }
return req_len; return req_len;
@@ -208,7 +261,7 @@ static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt,
char mem[256], *buf = mem; char mem[256], *buf = mem;
int len = mg_vasprintf(&buf, sizeof(mem), fmt, ap); int len = mg_vasprintf(&buf, sizeof(mem), fmt, ap);
mg_printf(c, "%X\r\n", len); mg_printf(c, "%X\r\n", len);
mg_send(c, buf, len); mg_send(c, buf, len > 0 ? (size_t) len : 0);
mg_send(c, "\r\n", 2); mg_send(c, "\r\n", 2);
if (buf != mem) free(buf); if (buf != mem) free(buf);
} }
@@ -221,11 +274,82 @@ void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) {
} }
void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) { void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) {
mg_printf(c, "%X\r\n", len); mg_printf(c, "%lX\r\n", (unsigned long) len);
mg_send(c, buf, len); mg_send(c, buf, len);
mg_send(c, "\r\n", 2); mg_send(c, "\r\n", 2);
} }
// clang-format off
static const char *mg_http_status_code_str(int status_code) {
switch (status_code) {
case 100: return "Continue";
case 101: return "Switching Protocols";
case 102: return "Processing";
case 200: return "OK";
case 201: return "Created";
case 202: return "Accepted";
case 203: return "Non-authoritative Information";
case 204: return "No Content";
case 205: return "Reset Content";
case 206: return "Partial Content";
case 207: return "Multi-Status";
case 208: return "Already Reported";
case 226: return "IM Used";
case 300: return "Multiple Choices";
case 301: return "Moved Permanently";
case 302: return "Found";
case 303: return "See Other";
case 304: return "Not Modified";
case 305: return "Use Proxy";
case 307: return "Temporary Redirect";
case 308: return "Permanent Redirect";
case 400: return "Bad Request";
case 401: return "Unauthorized";
case 402: return "Payment Required";
case 403: return "Forbidden";
case 404: return "Not Found";
case 405: return "Method Not Allowed";
case 406: return "Not Acceptable";
case 407: return "Proxy Authentication Required";
case 408: return "Request Timeout";
case 409: return "Conflict";
case 410: return "Gone";
case 411: return "Length Required";
case 412: return "Precondition Failed";
case 413: return "Payload Too Large";
case 414: return "Request-URI Too Long";
case 415: return "Unsupported Media Type";
case 416: return "Requested Range Not Satisfiable";
case 417: return "Expectation Failed";
case 418: return "I'm a teapot";
case 421: return "Misdirected Request";
case 422: return "Unprocessable Entity";
case 423: return "Locked";
case 424: return "Failed Dependency";
case 426: return "Upgrade Required";
case 428: return "Precondition Required";
case 429: return "Too Many Requests";
case 431: return "Request Header Fields Too Large";
case 444: return "Connection Closed Without Response";
case 451: return "Unavailable For Legal Reasons";
case 499: return "Client Closed Request";
case 500: return "Internal Server Error";
case 501: return "Not Implemented";
case 502: return "Bad Gateway";
case 503: return "Service Unavailable";
case 504: return "Gateway Timeout";
case 505: return "HTTP Version Not Supported";
case 506: return "Variant Also Negotiates";
case 507: return "Insufficient Storage";
case 508: return "Loop Detected";
case 510: return "Not Extended";
case 511: return "Network Authentication Required";
case 599: return "Network Connect Timeout Error";
default: return "OK";
}
}
// clang-format on
void mg_http_reply(struct mg_connection *c, int code, const char *headers, void mg_http_reply(struct mg_connection *c, int code, const char *headers,
const char *fmt, ...) { const char *fmt, ...) {
char mem[100], *buf = mem; char mem[100], *buf = mem;
@@ -234,9 +358,9 @@ void mg_http_reply(struct mg_connection *c, int code, const char *headers,
va_start(ap, fmt); va_start(ap, fmt);
len = mg_vasprintf(&buf, sizeof(mem), fmt, ap); len = mg_vasprintf(&buf, sizeof(mem), fmt, ap);
va_end(ap); va_end(ap);
mg_printf(c, "HTTP/1.1 %d OK\r\n%sContent-Length: %d\r\n\r\n", code, mg_printf(c, "HTTP/1.1 %d %s\r\n%sContent-Length: %d\r\n\r\n", code,
headers == NULL ? "" : headers, len); mg_http_status_code_str(code), headers == NULL ? "" : headers, len);
mg_send(c, buf, len); mg_send(c, buf, len > 0 ? (size_t) len : 0);
if (buf != mem) free(buf); if (buf != mem) free(buf);
} }
@@ -268,14 +392,14 @@ int mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, name); snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, name);
LOG(LL_DEBUG, LOG(LL_DEBUG,
("%p %d bytes @ %d [%s]", c->fd, (int) hm->body.len, (int) oft, name)); ("%p %d bytes @ %d [%s]", c->fd, (int) hm->body.len, (int) oft, name));
if ((fp = mg_fopen(path, oft == 0 ? "wb" : "ab")) == NULL) { if ((fp = fopen(path, oft == 0 ? "wb" : "ab")) == NULL) {
mg_http_reply(c, 400, "", "fopen(%s): %d", name, errno); mg_http_reply(c, 400, "", "fopen(%s): %d", name, errno);
return -2; return -2;
} else { } else {
fwrite(hm->body.ptr, 1, hm->body.len, fp); fwrite(hm->body.ptr, 1, hm->body.len, fp);
fclose(fp); fclose(fp);
mg_http_reply(c, 200, "", ""); mg_http_reply(c, 200, "", "");
return hm->body.len; return (int) hm->body.len;
} }
} }
} }
@@ -308,46 +432,53 @@ static const char *guess_content_type(const char *filename) {
} * t, types[] = { } * t, types[] = {
MIME_ENTRY("html", "text/html; charset=utf-8"), MIME_ENTRY("html", "text/html; charset=utf-8"),
MIME_ENTRY("htm", "text/html; charset=utf-8"), MIME_ENTRY("htm", "text/html; charset=utf-8"),
MIME_ENTRY("shtml", "text/html; charset=utf-8"), MIME_ENTRY("css", "text/css; charset=utf-8"),
MIME_ENTRY("css", "text/css"), MIME_ENTRY("js", "text/javascript; charset=utf-8"),
MIME_ENTRY("js", "text/javascript"),
MIME_ENTRY("mjs", "text/javascript"),
MIME_ENTRY("json", "application/json"),
MIME_ENTRY("ico", "image/x-icon"),
MIME_ENTRY("gif", "image/gif"), MIME_ENTRY("gif", "image/gif"),
MIME_ENTRY("jpg", "image/jpeg"),
MIME_ENTRY("jpeg", "image/jpeg"),
MIME_ENTRY("png", "image/png"), MIME_ENTRY("png", "image/png"),
MIME_ENTRY("svg", "image/svg+xml"), MIME_ENTRY("woff", "font/woff"),
MIME_ENTRY("txt", "text/plain; charset=utf-8"),
MIME_ENTRY("wav", "audio/wav"),
MIME_ENTRY("mp3", "audio/mpeg"),
MIME_ENTRY("mid", "audio/mid"),
MIME_ENTRY("ogg", "application/ogg"),
MIME_ENTRY("xml", "application/xml"),
MIME_ENTRY("ttf", "font/ttf"), MIME_ENTRY("ttf", "font/ttf"),
MIME_ENTRY("json", "application/json"), MIME_ENTRY("aac", "audio/aac"),
MIME_ENTRY("xsl", "application/xml"), MIME_ENTRY("avi", "video/x-msvideo"),
MIME_ENTRY("azw", "application/vnd.amazon.ebook"),
MIME_ENTRY("bin", "application/octet-stream"),
MIME_ENTRY("bmp", "image/bmp"),
MIME_ENTRY("bz", "application/x-bzip"),
MIME_ENTRY("bz2", "application/x-bzip2"),
MIME_ENTRY("csv", "text/csv"),
MIME_ENTRY("doc", "application/msword"), MIME_ENTRY("doc", "application/msword"),
MIME_ENTRY("epub", "application/epub+zip"),
MIME_ENTRY("exe", "application/octet-stream"), MIME_ENTRY("exe", "application/octet-stream"),
MIME_ENTRY("zip", "application/zip"),
MIME_ENTRY("xls", "application/excel"),
MIME_ENTRY("tgz", "application/tar-gz"),
MIME_ENTRY("tar", "application/tar"),
MIME_ENTRY("gz", "application/gzip"), MIME_ENTRY("gz", "application/gzip"),
MIME_ENTRY("ico", "image/x-icon"),
MIME_ENTRY("json", "application/json"),
MIME_ENTRY("mid", "audio/mid"),
MIME_ENTRY("mjs", "text/javascript"),
MIME_ENTRY("mov", "video/quicktime"),
MIME_ENTRY("mp3", "audio/mpeg"),
MIME_ENTRY("mp4", "video/mp4"),
MIME_ENTRY("mpeg", "video/mpeg"),
MIME_ENTRY("mpg", "video/mpeg"),
MIME_ENTRY("ogg", "application/ogg"),
MIME_ENTRY("pdf", "application/pdf"),
MIME_ENTRY("rar", "application/rar"), MIME_ENTRY("rar", "application/rar"),
MIME_ENTRY("rtf", "application/rtf"), MIME_ENTRY("rtf", "application/rtf"),
MIME_ENTRY("pdf", "application/pdf"), MIME_ENTRY("shtml", "text/html; charset=utf-8"),
MIME_ENTRY("mpg", "video/mpeg"), MIME_ENTRY("svg", "image/svg+xml"),
MIME_ENTRY("webm", "video/webm"), MIME_ENTRY("tar", "application/tar"),
MIME_ENTRY("mpeg", "video/mpeg"), MIME_ENTRY("tgz", "application/tar-gz"),
MIME_ENTRY("mov", "video/quicktime"), MIME_ENTRY("txt", "text/plain; charset=utf-8"),
MIME_ENTRY("mp4", "video/mp4"),
MIME_ENTRY("avi", "video/x-msvideo"),
MIME_ENTRY("csv", "text/csv"),
MIME_ENTRY("bmp", "image/bmp"),
MIME_ENTRY("bin", "application/octet-stream"),
MIME_ENTRY("wasm", "application/wasm"), MIME_ENTRY("wasm", "application/wasm"),
MIME_ENTRY("wav", "audio/wav"),
MIME_ENTRY("weba", "audio/webm"),
MIME_ENTRY("webm", "video/webm"),
MIME_ENTRY("webp", "image/webp"),
MIME_ENTRY("xls", "application/excel"),
MIME_ENTRY("xml", "application/xml"),
MIME_ENTRY("xsl", "application/xml"),
MIME_ENTRY("zip", "application/zip"),
MIME_ENTRY("3gp", "video/3gpp"),
MIME_ENTRY("7z", "application/x-7z-compressed"),
{NULL, 0, NULL}, {NULL, 0, NULL},
}; };
@@ -359,26 +490,78 @@ static const char *guess_content_type(const char *filename) {
return "text/plain; charset=utf-8"; return "text/plain; charset=utf-8";
} }
static int getrange(struct mg_str *s, int64_t *a, int64_t *b) {
size_t i, numparsed = 0;
LOG(LL_INFO, ("%.*s", (int) s->len, s->ptr));
for (i = 0; i + 6 < s->len; i++) {
if (memcmp(&s->ptr[i], "bytes=", 6) == 0) {
struct mg_str p = mg_str_n(s->ptr + i + 6, s->len - i - 6);
if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++;
*a = mg_to64(p);
// LOG(LL_INFO, ("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed));
while (p.len && p.ptr[0] >= '0' && p.ptr[0] <= '9') p.ptr++, p.len--;
if (p.len && p.ptr[0] == '-') p.ptr++, p.len--;
*b = mg_to64(p);
if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++;
// LOG(LL_INFO, ("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed));
break;
}
}
return (int) numparsed;
}
void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
const char *path, const char *mime, const char *hdrs) { const char *path, const char *mime, const char *hdrs) {
struct mg_str *inm = mg_http_get_header(hm, "If-None-Match"); struct mg_str *inm = mg_http_get_header(hm, "If-None-Match");
mg_stat_t st; mg_stat_t st;
char etag[64]; char etag[64];
FILE *fp = mg_fopen(path, "rb"); FILE *fp = fopen(path, "rb");
if (fp == NULL || mg_stat(path, &st) != 0 || if (fp == NULL || mg_stat(path, &st) != 0 ||
mg_http_etag(etag, sizeof(etag), &st) != etag) { mg_http_etag(etag, sizeof(etag), &st) != etag) {
LOG(LL_DEBUG, LOG(LL_DEBUG, ("404 [%.*s] [%s] %p", (int) hm->uri.len, hm->uri.ptr, path,
("404 [%.*s] [%s] %p", (int) hm->uri.len, hm->uri.ptr, path, fp)); (void *) fp));
mg_http_reply(c, 404, "", "%s", "Not found\n"); mg_http_reply(c, 404, "", "%s", "Not found\n");
if (fp != NULL) fclose(fp); if (fp != NULL) fclose(fp);
} else if (inm != NULL && mg_vcasecmp(inm, etag) == 0) { } else if (inm != NULL && mg_vcasecmp(inm, etag) == 0) {
fclose(fp); fclose(fp);
mg_printf(c, "HTTP/1.1 304 Not Modified\r\nContent-Length: 0\r\n\r\n"); mg_printf(c, "HTTP/1.1 304 Not Modified\r\nContent-Length: 0\r\n\r\n");
} else { } else {
int n, status = 200;
char range[100] = "";
int64_t r1 = 0, r2 = 0, cl = st.st_size;
// Handle Range header
struct mg_str *rh = mg_http_get_header(hm, "Range");
if (rh != NULL && (n = getrange(rh, &r1, &r2)) > 0 && r1 >= 0 && r2 >= 0) {
// If range is specified like "400-", set second limit to content len
if (n == 1) r2 = cl - 1;
if (r1 > r2 || r2 >= cl) {
status = 416;
cl = 0;
snprintf(range, sizeof(range),
"Content-Range: bytes */" MG_INT64_FMT "\r\n",
(int64_t) st.st_size);
} else {
status = 206;
cl = r2 - r1 + 1;
snprintf(range, sizeof(range),
"Content-Range: bytes " MG_INT64_FMT "-" MG_INT64_FMT
"/" MG_INT64_FMT "\r\n",
r1, r1 + cl - 1, (int64_t) st.st_size);
#if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L || \
_XOPEN_SOURCE >= 600
fseeko(fp, (off_t) r1, SEEK_SET);
#else
fseek(fp, (long) r1, SEEK_SET);
#endif
}
}
mg_printf(c, mg_printf(c,
"HTTP/1.1 200 OK\r\nContent-Type: %s\r\n" "HTTP/1.1 %d %s\r\nContent-Type: %s\r\n"
"Etag: %s\r\nContent-Length: " MG_INT64_FMT "\r\n%s\r\n", "Etag: %s\r\nContent-Length: " MG_INT64_FMT "\r\n%s%s\r\n",
mime, etag, (int64_t) st.st_size, hdrs ? hdrs : ""); status, mg_http_status_code_str(status), mime, etag, cl, range,
hdrs ? hdrs : "");
if (mg_vcasecmp(&hm->method, "HEAD") == 0) { if (mg_vcasecmp(&hm->method, "HEAD") == 0) {
fclose(fp); fclose(fp);
} else { } else {
@@ -389,7 +572,7 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm,
} }
#if MG_ARCH == MG_ARCH_ESP32 || MG_ARCH == MG_ARCH_ESP8266 || \ #if MG_ARCH == MG_ARCH_ESP32 || MG_ARCH == MG_ARCH_ESP8266 || \
MG_ARCH == MG_ARCH_FREERTOS MG_ARCH == MG_ARCH_FREERTOS_TCP
char *realpath(const char *src, char *dst) { char *realpath(const char *src, char *dst) {
int len = strlen(src); int len = strlen(src);
if (len > MG_PATH_MAX - 1) len = MG_PATH_MAX - 1; if (len > MG_PATH_MAX - 1) len = MG_PATH_MAX - 1;
@@ -403,7 +586,7 @@ char *realpath(const char *src, char *dst) {
// Allow user to override this function // Allow user to override this function
bool mg_is_dir(const char *path) WEAK; bool mg_is_dir(const char *path) WEAK;
bool mg_is_dir(const char *path) { bool mg_is_dir(const char *path) {
#if MG_ARCH == MG_ARCH_FREERTOS #if MG_ARCH == MG_ARCH_FREERTOS_TCP && defined(MG_ENABLE_FF)
struct FF_STAT st; struct FF_STAT st;
return (ff_stat(path, &st) == 0) && (st.st_mode & FF_IFDIR); return (ff_stat(path, &st) == 0) && (st.st_mode & FF_IFDIR);
#else #else
@@ -471,7 +654,7 @@ DIR *opendir(const char *name) {
if (name == NULL) { if (name == NULL) {
SetLastError(ERROR_BAD_ARGUMENTS); SetLastError(ERROR_BAD_ARGUMENTS);
} else if ((d = (DIR *) malloc(sizeof(*d))) == NULL) { } else if ((d = (DIR *) calloc(1, sizeof(*d))) == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY); SetLastError(ERROR_NOT_ENOUGH_MEMORY);
} else { } else {
to_wchar(name, wpath, sizeof(wpath) / sizeof(wpath[0])); to_wchar(name, wpath, sizeof(wpath) / sizeof(wpath[0]));
@@ -528,6 +711,7 @@ static void printdirentry(struct mg_connection *c, const char *name,
char size[64], mod[64], path[MG_PATH_MAX]; char size[64], mod[64], path[MG_PATH_MAX];
int is_dir = S_ISDIR(stp->st_mode), n = 0; int is_dir = S_ISDIR(stp->st_mode), n = 0;
const char *slash = is_dir ? "/" : ""; const char *slash = is_dir ? "/" : "";
struct tm t;
if (is_dir) { if (is_dir) {
snprintf(size, sizeof(size), "%s", "[DIR]"); snprintf(size, sizeof(size), "%s", "[DIR]");
@@ -542,8 +726,8 @@ static void printdirentry(struct mg_connection *c, const char *name,
snprintf(size, sizeof(size), "%.1fG", (double) stp->st_size / 1073741824); snprintf(size, sizeof(size), "%.1fG", (double) stp->st_size / 1073741824);
} }
} }
strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&stp->st_mtime)); strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime_r(&stp->st_mtime, &t));
n = mg_url_encode(name, strlen(name), path, sizeof(path)); n = (int) mg_url_encode(name, strlen(name), path, sizeof(path));
mg_printf(c, mg_printf(c,
" <tr><td><a href=\"%.*s%s\">%s%s</a></td>" " <tr><td><a href=\"%.*s%s\">%s%s</a></td>"
"<td>%s</td><td>%s</td></tr>\n", "<td>%s</td><td>%s</td></tr>\n",
@@ -551,7 +735,7 @@ static void printdirentry(struct mg_connection *c, const char *name,
} }
static void listdir(struct mg_connection *c, struct mg_http_message *hm, static void listdir(struct mg_connection *c, struct mg_http_message *hm,
char *dir) { struct mg_http_serve_opts *opts, char *dir) {
char path[MG_PATH_MAX], *p = &dir[strlen(dir) - 1], tmp[10]; char path[MG_PATH_MAX], *p = &dir[strlen(dir) - 1], tmp[10];
struct dirent *dp; struct dirent *dp;
DIR *dirp; DIR *dirp;
@@ -582,10 +766,12 @@ static void listdir(struct mg_connection *c, struct mg_http_message *hm,
while (p > dir && *p != '/') *p-- = '\0'; while (p > dir && *p != '/') *p-- = '\0';
if ((dirp = (opendir(dir))) != NULL) { if ((dirp = (opendir(dir))) != NULL) {
size_t off, n; size_t off, n;
mg_printf(c, "%s\r\n", mg_printf(c,
"HTTP/1.1 200 OK\r\n" "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=utf-8\r\n" "Content-Type: text/html; charset=utf-8\r\n"
"Content-Length: \r\n"); "%s"
"Content-Length: \r\n\r\n",
opts->extra_headers == NULL ? "" : opts->extra_headers);
off = c->send.len; // Start of body off = c->send.len; // Start of body
mg_printf(c, mg_printf(c,
"<!DOCTYPE html><html><head><title>Index of %.*s</title>%s%s" "<!DOCTYPE html><html><head><title>Index of %.*s</title>%s%s"
@@ -620,7 +806,9 @@ static void listdir(struct mg_connection *c, struct mg_http_message *hm,
"</tbody><tfoot><tr><td colspan=\"3\"><hr></td></tr></tfoot>" "</tbody><tfoot><tr><td colspan=\"3\"><hr></td></tr></tfoot>"
"</table><address>Mongoose v.%s</address></body></html>\n", "</table><address>Mongoose v.%s</address></body></html>\n",
MG_VERSION); MG_VERSION);
n = snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) (c->send.len - off)); n = (size_t) snprintf(tmp, sizeof(tmp), "%lu",
(unsigned long) (c->send.len - off));
if (n > sizeof(tmp)) n = 0;
memcpy(c->send.buf + off - 10, tmp, n); // Set content length memcpy(c->send.buf + off - 10, tmp, n); // Set content length
} else { } else {
mg_http_reply(c, 400, "", "Cannot open dir"); mg_http_reply(c, 400, "", "Cannot open dir");
@@ -668,19 +856,19 @@ void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
mg_http_reply(c, 404, "", "Invalid URI [%.*s]\n", (int) hm->uri.len, mg_http_reply(c, 404, "", "Invalid URI [%.*s]\n", (int) hm->uri.len,
hm->uri.ptr); hm->uri.ptr);
} else { } else {
FILE *fp = mg_fopen(t2, "r"); FILE *fp = fopen(t2, "r");
#if MG_ENABLE_SSI #if MG_ENABLE_SSI
if (is_index && fp == NULL) { if (is_index && fp == NULL) {
char *p = t2 + strlen(t2); char *p = t2 + strlen(t2);
while (p > t2 && p[-1] != '/') p--; while (p > t2 && p[-1] != '/') p--;
strncpy(p, "index.shtml", &t2[sizeof(t2)] - p - 2); strncpy(p, "index.shtml", (size_t)(&t2[sizeof(t2)] - p - 2));
t2[sizeof(t2) - 1] = '\0'; t2[sizeof(t2) - 1] = '\0';
fp = mg_fopen(t2, "r"); fp = fopen(t2, "r");
} }
#endif #endif
if (is_index && fp == NULL) { if (is_index && fp == NULL) {
#if MG_ENABLE_DIRECTORY_LISTING #if MG_ENABLE_DIRECTORY_LISTING
listdir(c, hm, t2); listdir(c, hm, opts, t2);
#else #else
mg_http_reply(c, 403, "", "%s", "Directory listing not supported"); mg_http_reply(c, 403, "", "%s", "Directory listing not supported");
#endif #endif
@@ -692,7 +880,8 @@ void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
mg_http_serve_ssi(c, t1, t2); mg_http_serve_ssi(c, t1, t2);
#endif #endif
} else { } else {
mg_http_serve_file(c, hm, t2, guess_content_type(t2), NULL); mg_http_serve_file(c, hm, t2, guess_content_type(t2),
opts->extra_headers);
} }
if (fp != NULL) fclose(fp); if (fp != NULL) fclose(fp);
} }
@@ -705,7 +894,7 @@ static bool mg_is_url_safe(int c) {
(c >= 'A' && c <= 'Z') || c == '.' || c == '_' || c == '-' || c == '~'; (c >= 'A' && c <= 'Z') || c == '.' || c == '_' || c == '-' || c == '~';
} }
int mg_url_encode(const char *s, size_t sl, char *buf, size_t len) { size_t mg_url_encode(const char *s, size_t sl, char *buf, size_t len) {
size_t i, n = 0; size_t i, n = 0;
for (i = 0; i < sl; i++) { for (i = 0; i < sl; i++) {
int c = *(unsigned char *) &s[i]; int c = *(unsigned char *) &s[i];
@@ -721,14 +910,14 @@ int mg_url_encode(const char *s, size_t sl, char *buf, size_t len) {
return n; return n;
} }
void mg_http_creds(struct mg_http_message *hm, char *user, int userlen, void mg_http_creds(struct mg_http_message *hm, char *user, size_t userlen,
char *pass, int passlen) { char *pass, size_t passlen) {
struct mg_str *v = mg_http_get_header(hm, "Authorization"); struct mg_str *v = mg_http_get_header(hm, "Authorization");
user[0] = pass[0] = '\0'; user[0] = pass[0] = '\0';
if (v != NULL && v->len > 6 && memcmp(v->ptr, "Basic ", 6) == 0) { if (v != NULL && v->len > 6 && memcmp(v->ptr, "Basic ", 6) == 0) {
char buf[256]; char buf[256];
int n = mg_base64_decode(v->ptr + 6, (int) v->len - 6, buf); int n = mg_base64_decode(v->ptr + 6, (int) v->len - 6, buf);
const char *p = (const char *) memchr(buf, ':', n); const char *p = (const char *) memchr(buf, ':', n > 0 ? (size_t) n : 0);
if (p != NULL) { if (p != NULL) {
snprintf(user, userlen, "%.*s", (int) (p - buf), buf); snprintf(user, userlen, "%.*s", (int) (p - buf), buf);
snprintf(pass, passlen, "%.*s", n - (int) (p - buf) - 1, p + 1); snprintf(pass, passlen, "%.*s", n - (int) (p - buf) - 1, p + 1);
@@ -736,20 +925,34 @@ void mg_http_creds(struct mg_http_message *hm, char *user, int userlen,
} else if (v != NULL && v->len > 7 && memcmp(v->ptr, "Bearer ", 7) == 0) { } else if (v != NULL && v->len > 7 && memcmp(v->ptr, "Bearer ", 7) == 0) {
snprintf(pass, passlen, "%.*s", (int) v->len - 7, v->ptr + 7); snprintf(pass, passlen, "%.*s", (int) v->len - 7, v->ptr + 7);
} else if ((v = mg_http_get_header(hm, "Cookie")) != NULL) { } else if ((v = mg_http_get_header(hm, "Cookie")) != NULL) {
size_t i; struct mg_str t = mg_http_get_header_var(*v, mg_str_n("access_token", 12));
for (i = 0; i < v->len - 13; i++) { if (t.len > 0) snprintf(pass, passlen, "%.*s", (int) t.len, t.ptr);
if (memcmp(&v->ptr[i], "access_token=", 13) == 0) {
const char *p2 = v->ptr + i + 13, *p3 = p2;
while (p2 < &v->ptr[v->len] && p2[0] != ';' && p2[0] != ' ') p2++;
snprintf(pass, passlen, "%.*s", (int) (p2 - p3), p3);
break;
}
}
} else { } else {
mg_http_get_var(&hm->query, "access_token", pass, passlen); mg_http_get_var(&hm->query, "access_token", pass, passlen);
} }
} }
static struct mg_str stripquotes(struct mg_str s) {
return s.len > 1 && s.ptr[0] == '"' && s.ptr[s.len - 1] == '"'
? mg_str_n(s.ptr + 1, s.len - 2)
: s;
}
struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v) {
size_t i;
for (i = 0; i + v.len + 2 < s.len; i++) {
if (s.ptr[i + v.len] == '=' && memcmp(&s.ptr[i], v.ptr, v.len) == 0) {
const char *p = &s.ptr[i + v.len + 1], *b = p, *x = &s.ptr[s.len];
int q = p < x && *p == '"' ? 1 : 0;
while (p < x && (q ? p == b || *p != '"' : *p != ';' && *p != ' ')) p++;
// LOG(LL_INFO, ("[%.*s] [%.*s] [%.*s]", (int) s.len, s.ptr, (int) v.len,
// v.ptr, (int) (p - b), b));
return stripquotes(mg_str_n(b, (size_t)(p - b + q)));
}
}
return mg_str_n(NULL, 0);
}
bool mg_http_match_uri(const struct mg_http_message *hm, const char *glob) { bool mg_http_match_uri(const struct mg_http_message *hm, const char *glob) {
return mg_globmatch(glob, strlen(glob), hm->uri.ptr, hm->uri.len); return mg_globmatch(glob, strlen(glob), hm->uri.ptr, hm->uri.len);
} }
@@ -768,7 +971,7 @@ static size_t get_chunk_length(const char *buf, size_t len, size_t *ll) {
// Walk through all chunks in the chunked body. For each chunk, fire // Walk through all chunks in the chunked body. For each chunk, fire
// an MG_EV_HTTP_CHUNK event. // an MG_EV_HTTP_CHUNK event.
static void walkchunks(struct mg_connection *c, struct mg_http_message *hm, static void walkchunks(struct mg_connection *c, struct mg_http_message *hm,
int reqlen) { size_t reqlen) {
size_t off = 0, bl, ll; size_t off = 0, bl, ll;
while (off + reqlen < c->recv.len) { while (off + reqlen < c->recv.len) {
char *buf = (char *) &c->recv.buf[reqlen]; char *buf = (char *) &c->recv.buf[reqlen];
@@ -784,15 +987,17 @@ static void walkchunks(struct mg_connection *c, struct mg_http_message *hm,
// Zero chunk - last one. Prepare body - cut off chunk lengths // Zero chunk - last one. Prepare body - cut off chunk lengths
off = bl = 0; off = bl = 0;
while (off + reqlen < c->recv.len) { while (off + reqlen < c->recv.len) {
char *buf = (char *) &c->recv.buf[reqlen]; char *buf2 = (char *) &c->recv.buf[reqlen];
size_t memo = c->recv.len; size_t memo2 = c->recv.len;
size_t cl = get_chunk_length(&buf[off], memo - reqlen - off, &ll); size_t cl2 = get_chunk_length(&buf2[off], memo2 - reqlen - off, &ll);
size_t n = cl < ll + 2 ? 0 : cl - ll - 2; size_t n = cl < ll + 2 ? 0 : cl2 - ll - 2;
if (cl <= 5) break; memmove(buf2 + bl, buf2 + off + ll, n);
memmove(buf + bl, buf + off + ll, n);
bl += n; bl += n;
off += cl; off += cl2;
if (cl2 <= 5) break;
} }
// LOG(LL_INFO, ("BL->%d del %d off %d", (int) bl, (int) del, (int) off));
c->recv.len -= off - bl;
// Set message length to indicate we've received // Set message length to indicate we've received
// everything, to fire MG_EV_HTTP_MSG // everything, to fire MG_EV_HTTP_MSG
hm->message.len = bl + reqlen; hm->message.len = bl + reqlen;
@@ -817,8 +1022,10 @@ void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm) {
} }
{ {
const char *end = &ch.ptr[ch.len]; const char *end = &ch.ptr[ch.len];
size_t n = end - (char *) c->recv.buf; size_t n = (size_t)(end - (char *) c->recv.buf);
if (c->recv.len > n) memmove((char *) ch.ptr, end, c->recv.len - n); if (c->recv.len > n) {
memmove((char *) ch.ptr, end, (size_t)(c->recv.len - n));
}
// LOG(LL_INFO, ("DELETING CHUNK: %zu %zu %zu\n%.*s", c->recv.len, n, // LOG(LL_INFO, ("DELETING CHUNK: %zu %zu %zu\n%.*s", c->recv.len, n,
// ch.len, (int) ch.len, ch.ptr)); // ch.len, (int) ch.len, ch.ptr));
} }
@@ -833,22 +1040,22 @@ static void http_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
bool is_chunked = n > 0 && mg_is_chunked(&hm); bool is_chunked = n > 0 && mg_is_chunked(&hm);
if (ev == MG_EV_CLOSE) { if (ev == MG_EV_CLOSE) {
hm.message.len = c->recv.len; hm.message.len = c->recv.len;
hm.body.len = hm.message.len - (hm.body.ptr - hm.message.ptr); hm.body.len = hm.message.len - (size_t)(hm.body.ptr - hm.message.ptr);
} else if (is_chunked) { } else if (is_chunked && n > 0) {
walkchunks(c, &hm, n); walkchunks(c, &hm, (size_t) n);
} }
// LOG(LL_INFO, // LOG(LL_INFO,
//("---->%d %d\n%.*s", n, is_chunked, (int) c->recv.len, c->recv.buf)); //("---->%d %d\n%.*s", n, is_chunked, (int) c->recv.len, c->recv.buf));
if (n < 0 && ev == MG_EV_READ) { if (n < 0 && ev == MG_EV_READ) {
LOG(LL_ERROR, ("%lu HTTP parse error", c->id)); mg_error(c, "HTTP parse:\n%.*s", (int) c->recv.len, c->recv.buf);
c->is_closing = 1;
break; break;
} else if (n > 0 && (size_t) c->recv.len >= hm.message.len) { } else if (n > 0 && (size_t) c->recv.len >= hm.message.len) {
mg_call(c, MG_EV_HTTP_MSG, &hm); mg_call(c, MG_EV_HTTP_MSG, &hm);
mg_iobuf_delete(&c->recv, hm.message.len); mg_iobuf_delete(&c->recv, hm.message.len);
} else { } else {
if (n > 0 && !is_chunked) { if (n > 0 && !is_chunked) {
hm.chunk = mg_str_n((char *) &c->recv.buf[n], c->recv.len - n); hm.chunk =
mg_str_n((char *) &c->recv.buf[n], c->recv.len - (size_t) n);
mg_call(c, MG_EV_HTTP_CHUNK, &hm); mg_call(c, MG_EV_HTTP_CHUNK, &hm);
} }
break; break;
+14 -4
View File
@@ -24,7 +24,15 @@ struct mg_http_message {
// Parameter for mg_http_serve_dir() // Parameter for mg_http_serve_dir()
struct mg_http_serve_opts { struct mg_http_serve_opts {
const char *root_dir; // Web root directory, must be non-NULL const char *root_dir; // Web root directory, must be non-NULL
const char *ssi_pattern; // SSI filename pattern, e.g. #.shtml const char *ssi_pattern; // SSI file name pattern, e.g. #.shtml
const char *extra_headers; // Extra HTTP headers to add in responses
};
// Parameter for mg_http_next_multipart
struct mg_http_part {
struct mg_str name; // Form field name
struct mg_str filename; // Filename for file uploads
struct mg_str body; // Part contents
}; };
int mg_http_parse(const char *s, size_t len, struct mg_http_message *); int mg_http_parse(const char *s, size_t len, struct mg_http_message *);
@@ -44,11 +52,13 @@ void mg_http_reply(struct mg_connection *, int status_code, const char *headers,
const char *body_fmt, ...); const char *body_fmt, ...);
struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name); struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name);
void mg_http_event_handler(struct mg_connection *c, int ev); void mg_http_event_handler(struct mg_connection *c, int ev);
int mg_http_get_var(const struct mg_str *, const char *name, char *, int); int mg_http_get_var(const struct mg_str *, const char *name, char *, size_t);
int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form); int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form);
int mg_url_encode(const char *s, size_t n, char *buf, size_t len); size_t mg_url_encode(const char *s, size_t n, char *buf, size_t len);
void mg_http_creds(struct mg_http_message *, char *user, int, char *pass, int); void mg_http_creds(struct mg_http_message *, char *, size_t, char *, size_t);
bool mg_http_match_uri(const struct mg_http_message *, const char *glob); bool mg_http_match_uri(const struct mg_http_message *, const char *glob);
int mg_http_upload(struct mg_connection *, struct mg_http_message *hm, int mg_http_upload(struct mg_connection *, struct mg_http_message *hm,
const char *dir); const char *dir);
void mg_http_bauth(struct mg_connection *, const char *user, const char *pass); void mg_http_bauth(struct mg_connection *, const char *user, const char *pass);
struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v);
size_t mg_http_next_multipart(struct mg_str, size_t, struct mg_http_part *);
+21 -6
View File
@@ -3,18 +3,29 @@
#include <string.h> #include <string.h>
// Not using memset for zeroing memory, cause it can be dropped by compiler
// See https://github.com/cesanta/mongoose/pull/1265
static void zeromem(volatile unsigned char *buf, size_t len) {
if (buf != NULL) {
while (len--) *buf++ = 0;
}
}
int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) { int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
int ok = 1; int ok = 1;
if (new_size == 0) { if (new_size == 0) {
zeromem(io->buf, io->size);
free(io->buf); free(io->buf);
io->buf = NULL; io->buf = NULL;
io->len = io->size = 0; io->len = io->size = 0;
} else if (new_size != io->size) { } else if (new_size != io->size) {
// NOTE(lsm): do not use realloc here. Use malloc/free only, to ease the // NOTE(lsm): do not use realloc here. Use calloc/free only, to ease the
// porting to some obscure platforms like FreeRTOS // porting to some obscure platforms like FreeRTOS
void *p = malloc(new_size); void *p = calloc(1, new_size);
if (p != NULL) { if (p != NULL) {
memcpy(p, io->buf, io->size < new_size ? io->size : new_size); size_t len = new_size < io->len ? new_size : io->len;
if (len > 0) memcpy(p, io->buf, len);
zeromem(io->buf, io->size);
free(io->buf); free(io->buf);
io->buf = (unsigned char *) p; io->buf = (unsigned char *) p;
io->size = new_size; io->size = new_size;
@@ -33,10 +44,13 @@ int mg_iobuf_init(struct mg_iobuf *io, size_t size) {
size_t mg_iobuf_append(struct mg_iobuf *io, const void *buf, size_t len, size_t mg_iobuf_append(struct mg_iobuf *io, const void *buf, size_t len,
size_t chunk_size) { size_t chunk_size) {
size_t new_size = io->len + len + chunk_size; size_t new_size = io->len + len;
new_size -= new_size % chunk_size; if (new_size > io->size) {
if (new_size != io->size) mg_iobuf_resize(io, new_size); new_size += chunk_size; // Make sure that io->size
new_size -= new_size % chunk_size; // is aligned by chunk_size boundary
mg_iobuf_resize(io, new_size); // Attempt to realloc
if (new_size != io->size) len = 0; // Realloc failure, append nothing if (new_size != io->size) len = 0; // Realloc failure, append nothing
}
if (buf != NULL) memmove(io->buf + io->len, buf, len); if (buf != NULL) memmove(io->buf + io->len, buf, len);
io->len += len; io->len += len;
return len; return len;
@@ -45,6 +59,7 @@ size_t mg_iobuf_append(struct mg_iobuf *io, const void *buf, size_t len,
size_t mg_iobuf_delete(struct mg_iobuf *io, size_t len) { size_t mg_iobuf_delete(struct mg_iobuf *io, size_t len) {
if (len > io->len) len = 0; if (len > io->len) len = 0;
memmove(io->buf, io->buf + len, io->len - len); memmove(io->buf, io->buf + len, io->len - len);
zeromem(io->buf + io->len - len, len);
io->len -= len; io->len -= len;
return len; return len;
} }
+10 -7
View File
@@ -4,13 +4,13 @@
#if MG_ENABLE_MGOS #if MG_ENABLE_MGOS
#else #else
#if MG_ENABLE_LOG #if MG_ENABLE_LOG
static void mg_log_stdout(const void *buf, int len, void *userdata) { static void mg_log_stdout(const void *buf, size_t len, void *userdata) {
(void) userdata; (void) userdata;
fwrite(buf, 1, len, stdout); fwrite(buf, 1, len, stdout);
} }
static const char *s_spec = "2"; static const char *s_spec = "2";
static void (*s_fn)(const void *, int, void *) = mg_log_stdout; static void (*s_fn)(const void *, size_t, void *) = mg_log_stdout;
static void *s_fn_param = NULL; static void *s_fn_param = NULL;
void mg_log_set(const char *spec) { void mg_log_set(const char *spec) {
@@ -23,9 +23,12 @@ bool mg_log_prefix(int level, const char *file, int line, const char *fname) {
int max = LL_INFO; int max = LL_INFO;
struct mg_str k, v, s = mg_str(s_spec); struct mg_str k, v, s = mg_str(s_spec);
const char *p = strrchr(file, '/'); const char *p = strrchr(file, '/');
p = p == NULL ? file : p + 1;
if (s_fn == NULL) return false; if (s_fn == NULL) return false;
if (p == NULL) p = strrchr(file, '\\');
p = p == NULL ? file : p + 1;
while (mg_next_comma_entry(&s, &k, &v)) { while (mg_next_comma_entry(&s, &k, &v)) {
if (v.len == 0) max = atoi(k.ptr); if (v.len == 0) max = atoi(k.ptr);
if (v.len > 0 && strncmp(p, k.ptr, k.len) == 0) max = atoi(v.ptr); if (v.len > 0 && strncmp(p, k.ptr, k.len) == 0) max = atoi(v.ptr);
@@ -34,7 +37,7 @@ bool mg_log_prefix(int level, const char *file, int line, const char *fname) {
if (level <= max) { if (level <= max) {
char timebuf[21], buf[50] = ""; char timebuf[21], buf[50] = "";
time_t t = time(NULL); time_t t = time(NULL);
struct tm *tm = gmtime(&t); struct tm tmp, *tm = gmtime_r(&t, &tmp);
int n, tag; int n, tag;
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm); strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm);
tag = level == LL_ERROR ? 'E' : level == LL_INFO ? 'I' : ' '; tag = level == LL_ERROR ? 'E' : level == LL_INFO ? 'I' : ' ';
@@ -56,14 +59,14 @@ void mg_log(const char *fmt, ...) {
va_start(ap, fmt); va_start(ap, fmt);
len = mg_vasprintf(&buf, sizeof(mem), fmt, ap); len = mg_vasprintf(&buf, sizeof(mem), fmt, ap);
va_end(ap); va_end(ap);
s_fn(buf, len, s_fn_param); s_fn(buf, len > 0 ? (size_t) len : 0, s_fn_param);
s_fn("\n", 1, s_fn_param); s_fn("\n", 1, s_fn_param);
if (buf != mem) free(buf); if (buf != mem) free(buf);
} }
void mg_log_set_callback(void (*fn)(const void *, int, void *), void *param) { void mg_log_set_callback(void (*fn)(const void *, size_t, void *), void *fnd) {
s_fn = fn; s_fn = fn;
s_fn_param = param; s_fn_param = fnd;
} }
#endif #endif
#endif #endif
+3 -6
View File
@@ -3,9 +3,6 @@
#include "arch.h" #include "arch.h"
#include "config.h" #include "config.h"
#if MG_ENABLE_MGOS
#include <common/cs_dbg.h>
#else
#if MG_ENABLE_LOG #if MG_ENABLE_LOG
#define LOG(level, args) \ #define LOG(level, args) \
do { \ do { \
@@ -15,8 +12,8 @@ enum { LL_NONE, LL_ERROR, LL_INFO, LL_DEBUG, LL_VERBOSE_DEBUG };
bool mg_log_prefix(int ll, const char *file, int line, const char *fname); bool mg_log_prefix(int ll, const char *file, int line, const char *fname);
void mg_log(const char *fmt, ...) PRINTF_LIKE(1, 2); void mg_log(const char *fmt, ...) PRINTF_LIKE(1, 2);
void mg_log_set(const char *spec); void mg_log_set(const char *spec);
void mg_log_set_callback(void (*fn)(const void *, int, void *), void *param); void mg_log_set_callback(void (*fn)(const void *, size_t, void *), void *param);
#else #else
#define LOG(level, args) #define LOG(level, args) (void) 0
#endif #define mg_log_set(x) (void) (x)
#endif #endif
-197
View File
@@ -1,197 +0,0 @@
#include "dns.h"
#include "log.h"
#include "net.h"
#include "private.h"
#include "tls.h"
#include "url.h"
#if MG_ENABLE_LWIP
#include <lwip/tcp.h>
#include <lwip/udp.h>
static void tcp_error_cb(void *arg, err_t err) {
struct mg_connection *c = (struct mg_connection *) arg;
mg_error(c, "%p err %ld", c->fd, err);
}
static err_t connect_cb(void *arg, struct tcp_pcb *pcb, err_t err) {
struct mg_connection *c = (struct mg_connection *) arg;
LOG(LL_DEBUG, ("err %ld, arg %p, pcb %p", err, arg, pcb));
c->is_connecting = 0;
if (err != ERR_OK) mg_error(c, "%p err %d", c->fd, err);
return err;
}
static err_t tcp_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbuf *p,
err_t err) {
struct mg_connection *c = (struct mg_connection *) arg;
LOG(LL_DEBUG,
("err %ld, pbuf %p/%d, io.len %d, io.size %d", err, p,
p == NULL ? 0 : (int) p->len, (int) c->recv.len, (int) c->recv.size));
if (err == ERR_OK && p != NULL) {
#if 0
if (s->io.size < s->io.len + p->len) {
char *buf = realloc(s->io.buf, s->io.len + p->len);
if (buf != NULL) {
s->io.buf = buf;
s->io.size = s->io.len + p->len;
} else {
return ERR_MEM;
}
}
// MLOG(LL_DEBUG, " --> cpy, %p %p", s->io.buf, p->payload);
memcpy(s->io.buf + s->io.len, p->payload, p->len);
s->io.len += p->len;
#endif
tcp_recved(pcb, p->len);
pbuf_free(p);
return err;
} else {
// rmsock(s);
return ERR_ABRT;
}
}
static void udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
const ip_addr_t *addr, uint16_t port) {
LOG(LL_DEBUG,
("%p %p pbuf %p/%d port %hu", arg, pcb, p, p == NULL ? 0 : p->len, port));
}
static err_t tcp_sent_cb(void *arg, struct tcp_pcb *pcb, uint16_t len) {
LOG(LL_DEBUG, ("%p %d", pcb, (int) len));
return ERR_OK;
}
#if 0
static int ll_write(struct mg_connection *c, const void *buf, int len,
int *fail) {
int n = c->is_tls ? mg_tls_send(c, buf, len, fail)
: mg_sock_send(c, buf, len, fail);
LOG(*fail ? LL_ERROR : LL_VERBOSE_DEBUG,
("%p %c%c%c %d/%d %d", c->fd, c->is_tls ? 'T' : 't',
c->is_udp ? 'U' : 'u', c->is_connecting ? 'C' : 'c', n, len,
MG_SOCK_ERRNO));
if (n > 0 && c->is_hexdumping) mg_hexdump(c, "->", buf, n);
return n;
}
#endif
int mg_send(struct mg_connection *c, const void *buf, size_t len) {
if (c->is_udp) {
struct udp_pcb *pcb = (struct udp_pcb *) c->fd;
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
if (p != NULL) {
// p->payload = (void *) buf;
memcpy(p->payload, buf, len);
err_t err = udp_send(pcb, p);
pbuf_free(p);
LOG(LL_DEBUG,
("%lu UDP %d bytes -> %x:%hu, err %ld", c->id, (int) len,
(unsigned) *(uint32_t *) &pcb->remote_ip, pcb->remote_port, err));
if (err != ERR_OK) mg_error(c, "%p err %d", c->fd, err);
} else {
mg_error(c, "%p pbuf OOM", c->fd);
}
} else if (c->is_connecting) {
mg_iobuf_append(&c->send, buf, len, MG_IO_SIZE);
} else {
}
#if 0
int fail, n = c->is_udp
? ll_write(c, buf, (SOCKET) len, &fail)
: mg_iobuf_append(&c->send, buf, len, MG_IO_SIZE);
return n;
#endif
return 0;
}
static struct mg_connection *mg_mkconn(const char *url) {
struct mg_connection *c = (struct mg_connection *) calloc(1, sizeof(*c));
typedef void *(*new_t)(void);
int is_udp = strncmp(url, "udp:", 4) == 0;
if (c == NULL) {
LOG(LL_ERROR, ("%s %s", url, "OOM"));
} else if ((c->fd = (is_udp ? (new_t) udp_new : (new_t) tcp_new)()) == NULL) {
LOG(LL_ERROR, ("%s new", url));
free(c);
c = NULL;
} else {
c->is_udp = is_udp;
}
return c;
}
struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data) {
struct mg_connection *c = mg_mkconn(url);
struct mg_str host = mg_url_host(url);
if (c == NULL) return c;
c->next = mgr->conns;
mgr->conns = c;
// mg_set_non_blocking_mode((SOCKET) c->fd);
c->is_client = 1;
c->peer.port = mg_htons(mg_url_port(url));
c->fn = fn;
c->fn_data = fn_data;
c->is_hexdumping = 1;
if (c->is_udp) {
udp_bind(c->fd, IP_ADDR_ANY, 0);
udp_recv(c->fd, udp_recv_cb, c);
} else {
tcp_arg(c->fd, c);
tcp_err(c->fd, tcp_error_cb);
tcp_sent(c->fd, tcp_sent_cb);
tcp_recv(c->fd, tcp_recv_cb);
tcp_bind(c->fd, IP_ADDR_ANY, 0);
tcp_nagle_disable((struct tcp_pcb *) c->fd);
}
LOG(LL_DEBUG, ("%lu -> %s %s", c->id, url, c->is_udp ? "UDP" : "TCP"));
mg_resolve(mgr, c, &host, mgr->dnstimeout);
return c;
}
void mg_connect_resolved(struct mg_connection *c) {
char buf[40];
ip_addr_t ipaddr;
memcpy(&ipaddr, &c->peer.ip, sizeof(ipaddr));
mg_call(c, MG_EV_RESOLVE, NULL);
LOG(LL_DEBUG, ("%lu resolved to %s", c->id, mg_straddr(c, buf, sizeof(buf))));
err_t err = c->is_udp ? udp_connect((struct udp_pcb *) c->fd, &ipaddr,
mg_ntohs(c->peer.port))
: tcp_connect((struct tcp_pcb *) c->fd, &ipaddr,
mg_ntohs(c->peer.port), connect_cb);
if (c->is_udp) c->is_connecting = 0;
if (err != ERR_OK) mg_error(c, "%p failed, err %d", c->fd, err);
}
static err_t accept_cb(void *arg, struct tcp_pcb *pcb, err_t e) {
LOG(LL_DEBUG, ("%p err %ld, pcb %p", arg, e, pcb));
return ERR_OK;
}
struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data) {
struct mg_connection *c = mg_mkconn(url);
struct mg_str host = mg_url_host(url);
uint16_t port = mg_url_port(url);
uint32_t ipaddr;
err_t err;
if (c == NULL) return c;
mg_aton(host.ptr, &ipaddr);
if (!mg_vcasecmp(&host, "localhost")) ipaddr = mg_htonl(0x7f000001);
if ((err = tcp_bind(c->fd, (ip_addr_t *) &ipaddr, port)) != ERR_OK) {
mg_error(c, "%p tcp_bind(%x:%hu) -> %ld", c->fd, ipaddr, port, err);
} else {
tcp_listen(c->fd);
tcp_accept(c->fd, accept_cb);
}
return c;
}
void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
LOG(LL_DEBUG, ("%p %d", mgr, ms));
mg_usleep(200 * 1000);
mg_timer_poll(mg_millis());
}
#endif
+29 -28
View File
@@ -1,8 +1,8 @@
#include "mqtt.h"
#include "arch.h" #include "arch.h"
#include "base64.h" #include "base64.h"
#include "event.h" #include "event.h"
#include "log.h" #include "log.h"
#include "mqtt.h"
#include "private.h" #include "private.h"
#include "url.h" #include "url.h"
#include "util.h" #include "util.h"
@@ -20,14 +20,14 @@ enum { MQTT_OK, MQTT_INCOMPLETE, MQTT_MALFORMED };
void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags, void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags,
uint32_t len) { uint32_t len) {
uint8_t buf[1 + sizeof(len)], *vlen = &buf[1]; uint8_t buf[1 + sizeof(len)], *vlen = &buf[1];
buf[0] = (cmd << 4) | flags; buf[0] = (uint8_t)((cmd << 4) | flags);
do { do {
*vlen = len % 0x80; *vlen = len % 0x80;
len /= 0x80; len /= 0x80;
if (len > 0) *vlen |= 0x80; if (len > 0) *vlen |= 0x80;
vlen++; vlen++;
} while (len > 0 && vlen < &buf[sizeof(buf)]); } while (len > 0 && vlen < &buf[sizeof(buf)]);
mg_send(c, buf, vlen - buf); mg_send(c, buf, (size_t)(vlen - buf));
} }
static void mg_send_u16(struct mg_connection *c, uint16_t value) { static void mg_send_u16(struct mg_connection *c, uint16_t value) {
@@ -37,7 +37,7 @@ static void mg_send_u16(struct mg_connection *c, uint16_t value) {
static void mqtt_login(struct mg_connection *c, const char *url, static void mqtt_login(struct mg_connection *c, const char *url,
struct mg_mqtt_opts *opts) { struct mg_mqtt_opts *opts) {
uint32_t total_len = 7 + 1 + 2 + 2; uint32_t total_len = 7 + 1 + 2 + 2;
uint16_t flags = (opts->qos & 3) << 3; uint16_t flags = (uint16_t)(((uint16_t) opts->qos & 3) << 3);
struct mg_str user = mg_url_user(url); struct mg_str user = mg_url_user(url);
struct mg_str pass = mg_url_pass(url); struct mg_str pass = mg_url_pass(url);
@@ -82,8 +82,8 @@ static void mqtt_login(struct mg_connection *c, const char *url,
} }
void mg_mqtt_pub(struct mg_connection *c, struct mg_str *topic, void mg_mqtt_pub(struct mg_connection *c, struct mg_str *topic,
struct mg_str *data) { struct mg_str *data, int qos, bool retain) {
uint8_t flags = MQTT_QOS(1); uint8_t flags = (uint8_t)(((qos & 3) << 1) | (retain ? 1 : 0));
uint32_t total_len = 2 + (uint32_t) topic->len + (uint32_t) data->len; uint32_t total_len = 2 + (uint32_t) topic->len + (uint32_t) data->len;
LOG(LL_DEBUG, ("%lu [%.*s] -> [%.*s]", c->id, (int) topic->len, LOG(LL_DEBUG, ("%lu [%.*s] -> [%.*s]", c->id, (int) topic->len,
(char *) topic->ptr, (int) data->len, (char *) data->ptr)); (char *) topic->ptr, (int) data->len, (char *) data->ptr));
@@ -99,17 +99,17 @@ void mg_mqtt_pub(struct mg_connection *c, struct mg_str *topic,
mg_send(c, data->ptr, data->len); mg_send(c, data->ptr, data->len);
} }
void mg_mqtt_sub(struct mg_connection *c, struct mg_str *topic) { void mg_mqtt_sub(struct mg_connection *c, struct mg_str *topic, int qos) {
static uint16_t s_id; static uint16_t s_id;
uint8_t qos = 1; uint8_t qos_ = qos & 3;
uint32_t total_len = 2 + (uint32_t) topic->len + 2 + 1; uint32_t total_len = 2 + (uint32_t) topic->len + 2 + 1;
mg_mqtt_send_header(c, MQTT_CMD_SUBSCRIBE, (uint8_t) MQTT_QOS(qos), mg_mqtt_send_header(c, MQTT_CMD_SUBSCRIBE, (uint8_t) MQTT_QOS(qos_),
total_len); total_len);
if (++s_id == 0) ++s_id; if (++s_id == 0) ++s_id;
mg_send_u16(c, mg_htons(s_id)); mg_send_u16(c, mg_htons(s_id));
mg_send_u16(c, mg_htons((uint16_t) topic->len)); mg_send_u16(c, mg_htons((uint16_t) topic->len));
mg_send(c, topic->ptr, topic->len); mg_send(c, topic->ptr, topic->len);
mg_send(c, &qos, sizeof(qos)); mg_send(c, &qos_, sizeof(qos_));
} }
int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) { int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) {
@@ -119,21 +119,21 @@ int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) {
memset(m, 0, sizeof(*m)); memset(m, 0, sizeof(*m));
m->dgram.ptr = (char *) buf; m->dgram.ptr = (char *) buf;
if (len < 2) return MQTT_INCOMPLETE; if (len < 2) return MQTT_INCOMPLETE;
m->cmd = buf[0] >> 4; m->cmd = (uint8_t)(buf[0] >> 4);
m->qos = (buf[0] >> 1) & 3; m->qos = (buf[0] >> 1) & 3;
n = len_len = 0; n = len_len = 0;
p = (uint8_t *) buf + 1; p = (uint8_t *) buf + 1;
while ((size_t)(p - buf) < len) { while ((size_t)(p - buf) < len) {
lc = *((uint8_t *) p++); lc = *((uint8_t *) p++);
n += (lc & 0x7f) << 7 * len_len; n += (uint32_t)((lc & 0x7f) << 7 * len_len);
len_len++; len_len++;
if (!(lc & 0x80)) break; if (!(lc & 0x80)) break;
if (len_len >= 4) return MQTT_MALFORMED; if (len_len >= 4) return MQTT_MALFORMED;
} }
end = p + n; end = p + n;
if (lc & 0x80 || end > buf + len) return MQTT_INCOMPLETE; if (lc & 0x80 || end > buf + len) return MQTT_INCOMPLETE;
m->dgram.len = end - buf; m->dgram.len = (size_t)(end - buf);
switch (m->cmd) { switch (m->cmd) {
case MQTT_CMD_CONNACK: case MQTT_CMD_CONNACK:
@@ -146,28 +146,28 @@ int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) {
case MQTT_CMD_PUBCOMP: case MQTT_CMD_PUBCOMP:
case MQTT_CMD_SUBACK: case MQTT_CMD_SUBACK:
if (p + 2 > end) return MQTT_MALFORMED; if (p + 2 > end) return MQTT_MALFORMED;
m->id = (p[0] << 8) | p[1]; m->id = (uint16_t)((((uint16_t) p[0]) << 8) | p[1]);
break; break;
case MQTT_CMD_SUBSCRIBE: { case MQTT_CMD_SUBSCRIBE: {
if (p + 2 > end) return MQTT_MALFORMED; if (p + 2 > end) return MQTT_MALFORMED;
m->id = (p[0] << 8) | p[1]; m->id = (uint16_t)((((uint16_t) p[0]) << 8) | p[1]);
p += 2; p += 2;
break; break;
} }
case MQTT_CMD_PUBLISH: { case MQTT_CMD_PUBLISH: {
if (p + 2 > end) return MQTT_MALFORMED; if (p + 2 > end) return MQTT_MALFORMED;
m->topic.len = (p[0] << 8) | p[1]; m->topic.len = (uint16_t)((((uint16_t) p[0]) << 8) | p[1]);
m->topic.ptr = (char *) p + 2; m->topic.ptr = (char *) p + 2;
p += 2 + m->topic.len; p += 2 + m->topic.len;
if (p > end) return MQTT_MALFORMED; if (p > end) return MQTT_MALFORMED;
if (m->qos > 0) { if (m->qos > 0) {
if (p + 2 > end) return MQTT_MALFORMED; if (p + 2 > end) return MQTT_MALFORMED;
m->id = (p[0] << 8) | p[1]; m->id = (uint16_t)((((uint16_t) p[0]) << 8) | p[1]);
p += 2; p += 2;
} }
if (p > end) return MQTT_MALFORMED; if (p > end) return MQTT_MALFORMED;
m->data.ptr = (char *) p; m->data.ptr = (char *) p;
m->data.len = end - p; m->data.len = (size_t)(end - p);
break; break;
} }
default: default:
@@ -176,28 +176,29 @@ int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m) {
return MQTT_OK; return MQTT_OK;
} }
static int mg_mqtt_next_topic(struct mg_mqtt_message *msg, struct mg_str *topic, static size_t mg_mqtt_next_topic(struct mg_mqtt_message *msg,
uint8_t *qos, int pos) { struct mg_str *topic, uint8_t *qos,
size_t pos) {
unsigned char *buf = (unsigned char *) msg->dgram.ptr + pos; unsigned char *buf = (unsigned char *) msg->dgram.ptr + pos;
int new_pos; size_t new_pos;
if ((size_t) pos >= msg->dgram.len) return -1; if (pos >= msg->dgram.len) return 0;
topic->len = buf[0] << 8 | buf[1]; topic->len = (size_t)(((unsigned) buf[0]) << 8 | buf[1]);
topic->ptr = (char *) buf + 2; topic->ptr = (char *) buf + 2;
new_pos = pos + 2 + topic->len + (qos == NULL ? 0 : 1); new_pos = pos + 2 + topic->len + (qos == NULL ? 0 : 1);
if ((size_t) new_pos > msg->dgram.len) return -1; if ((size_t) new_pos > msg->dgram.len) return 0;
if (qos != NULL) *qos = buf[2 + topic->len]; if (qos != NULL) *qos = buf[2 + topic->len];
return new_pos; return new_pos;
} }
int mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, size_t mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic,
uint8_t *qos, int pos) { uint8_t *qos, size_t pos) {
uint8_t tmp; uint8_t tmp;
return mg_mqtt_next_topic(msg, topic, qos == NULL ? &tmp : qos, pos); return mg_mqtt_next_topic(msg, topic, qos == NULL ? &tmp : qos, pos);
} }
int mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, size_t mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic,
int pos) { size_t pos) {
return mg_mqtt_next_topic(msg, topic, NULL, pos); return mg_mqtt_next_topic(msg, topic, NULL, pos);
} }
+7 -7
View File
@@ -47,16 +47,16 @@ struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url,
mg_event_handler_t fn, void *fn_data); mg_event_handler_t fn, void *fn_data);
struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url, struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data); mg_event_handler_t fn, void *fn_data);
void mg_mqtt_pub(struct mg_connection *, struct mg_str *topic, void mg_mqtt_pub(struct mg_connection *c, struct mg_str *topic,
struct mg_str *data); struct mg_str *data, int qos, bool retain);
void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic); void mg_mqtt_sub(struct mg_connection *, struct mg_str *topic, int qos);
int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m); int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m);
void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags, void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
uint32_t len); uint32_t len);
int mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, size_t mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic,
uint8_t *qos, int pos); uint8_t *qos, size_t pos);
int mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, size_t mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic,
int pos); size_t pos);
void mg_mqtt_ping(struct mg_connection *); void mg_mqtt_ping(struct mg_connection *);
void mg_mqtt_pong(struct mg_connection *); void mg_mqtt_pong(struct mg_connection *);
void mg_mqtt_disconnect(struct mg_connection *); void mg_mqtt_disconnect(struct mg_connection *);
+10 -9
View File
@@ -1,11 +1,11 @@
#include "log.h"
#include "net.h" #include "net.h"
#include "log.h"
#include "util.h" #include "util.h"
int mg_vprintf(struct mg_connection *c, const char *fmt, va_list ap) { int mg_vprintf(struct mg_connection *c, const char *fmt, va_list ap) {
char mem[256], *buf = mem; char mem[256], *buf = mem;
int len = mg_vasprintf(&buf, sizeof(mem), fmt, ap); int len = mg_vasprintf(&buf, sizeof(mem), fmt, ap);
len = mg_send(c, buf, len); len = mg_send(c, buf, len > 0 ? (size_t) len : 0);
if (buf != mem) free(buf); if (buf != mem) free(buf);
return len; return len;
} }
@@ -56,7 +56,7 @@ static bool mg_aton4(struct mg_str str, struct mg_addr *addr) {
if (str.ptr[i] >= '0' && str.ptr[i] <= '9') { if (str.ptr[i] >= '0' && str.ptr[i] <= '9') {
int octet = data[num_dots] * 10 + (str.ptr[i] - '0'); int octet = data[num_dots] * 10 + (str.ptr[i] - '0');
if (octet > 255) return false; if (octet > 255) return false;
data[num_dots] = octet; data[num_dots] = (uint8_t) octet;
} else if (str.ptr[i] == '.') { } else if (str.ptr[i] == '.') {
if (num_dots >= 3 || i == 0 || str.ptr[i - 1] == '.') return false; if (num_dots >= 3 || i == 0 || str.ptr[i - 1] == '.') return false;
num_dots++; num_dots++;
@@ -115,24 +115,25 @@ void mg_mgr_free(struct mg_mgr *mgr) {
struct mg_connection *c; struct mg_connection *c;
for (c = mgr->conns; c != NULL; c = c->next) c->is_closing = 1; for (c = mgr->conns; c != NULL; c = c->next) c->is_closing = 1;
mg_mgr_poll(mgr, 0); mg_mgr_poll(mgr, 0);
#if MG_ARCH == MG_ARCH_FREERTOS #if MG_ARCH == MG_ARCH_FREERTOS_TCP
FreeRTOS_DeleteSocketSet(mgr->ss); FreeRTOS_DeleteSocketSet(mgr->ss);
#endif #endif
LOG(LL_INFO, ("All connections closed")); LOG(LL_INFO, ("All connections closed"));
} }
void mg_mgr_init(struct mg_mgr *mgr) { void mg_mgr_init(struct mg_mgr *mgr) {
#ifdef _WIN32 memset(mgr, 0, sizeof(*mgr));
WSADATA data; #if defined(_WIN32) && MG_ENABLE_WINSOCK
WSAStartup(MAKEWORD(2, 2), &data); // clang-format off
#elif MG_ARCH == MG_ARCH_FREERTOS { WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); }
// clang-format on
#elif MG_ARCH == MG_ARCH_FREERTOS_TCP
mgr->ss = FreeRTOS_CreateSocketSet(); mgr->ss = FreeRTOS_CreateSocketSet();
#elif defined(__unix) || defined(__unix__) || defined(__APPLE__) #elif defined(__unix) || defined(__unix__) || defined(__APPLE__)
// Ignore SIGPIPE signal, so if client cancels the request, it // Ignore SIGPIPE signal, so if client cancels the request, it
// won't kill the whole process. // won't kill the whole process.
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
#endif #endif
memset(mgr, 0, sizeof(*mgr));
mgr->dnstimeout = 3000; mgr->dnstimeout = 3000;
mgr->dns4.url = "udp://8.8.8.8:53"; mgr->dns4.url = "udp://8.8.8.8:53";
mgr->dns6.url = "udp://[2001:4860:4860::8888]:53"; mgr->dns6.url = "udp://[2001:4860:4860::8888]:53";
+5 -5
View File
@@ -24,7 +24,7 @@ struct mg_mgr {
int dnstimeout; // DNS resolve timeout in milliseconds int dnstimeout; // DNS resolve timeout in milliseconds
unsigned long nextid; // Next connection ID unsigned long nextid; // Next connection ID
void *userdata; // Arbitrary user data pointer void *userdata; // Arbitrary user data pointer
#if MG_ARCH == MG_ARCH_FREERTOS #if MG_ARCH == MG_ARCH_FREERTOS_TCP
SocketSet_t ss; // NOTE(lsm): referenced from socket struct SocketSet_t ss; // NOTE(lsm): referenced from socket struct
#endif #endif
}; };
@@ -32,13 +32,13 @@ struct mg_mgr {
struct mg_connection { struct mg_connection {
struct mg_connection *next; // Linkage in struct mg_mgr :: connections struct mg_connection *next; // Linkage in struct mg_mgr :: connections
struct mg_mgr *mgr; // Our container struct mg_mgr *mgr; // Our container
struct mg_addr peer; // Remote peer address struct mg_addr peer; // Remote address. For listeners, local address
void *fd; // Connected socket, or LWIP data void *fd; // Connected socket, or LWIP data
unsigned long id; // Auto-incrementing unique connection ID unsigned long id; // Auto-incrementing unique connection ID
struct mg_iobuf recv; // Incoming data struct mg_iobuf recv; // Incoming data
struct mg_iobuf send; // Outgoing data struct mg_iobuf send; // Outgoing data
mg_event_handler_t fn; // User-specified event handler function mg_event_handler_t fn; // User-specified event handler function
void *fn_data; // User-speficied function parameter void *fn_data; // User-specified function parameter
mg_event_handler_t pfn; // Protocol-specific handler function mg_event_handler_t pfn; // Protocol-specific handler function
void *pfn_data; // Protocol-specific function parameter void *pfn_data; // Protocol-specific function parameter
char label[50]; // Arbitrary label char label[50]; // Arbitrary label
@@ -46,7 +46,7 @@ struct mg_connection {
unsigned is_listening : 1; // Listening connection unsigned is_listening : 1; // Listening connection
unsigned is_client : 1; // Outbound (client) connection unsigned is_client : 1; // Outbound (client) connection
unsigned is_accepted : 1; // Accepted (server) connection unsigned is_accepted : 1; // Accepted (server) connection
unsigned is_resolving : 1; // Non-blocking DNS resolv is in progress unsigned is_resolving : 1; // Non-blocking DNS resolution is in progress
unsigned is_connecting : 1; // Non-blocking connect is in progress unsigned is_connecting : 1; // Non-blocking connect is in progress
unsigned is_tls : 1; // TLS-enabled connection unsigned is_tls : 1; // TLS-enabled connection
unsigned is_tls_hs : 1; // TLS handshake is in progress unsigned is_tls_hs : 1; // TLS handshake is in progress
@@ -67,7 +67,7 @@ struct mg_connection *mg_listen(struct mg_mgr *, const char *url,
mg_event_handler_t fn, void *fn_data); mg_event_handler_t fn, void *fn_data);
struct mg_connection *mg_connect(struct mg_mgr *, const char *url, struct mg_connection *mg_connect(struct mg_mgr *, const char *url,
mg_event_handler_t fn, void *fn_data); mg_event_handler_t fn, void *fn_data);
int mg_send(struct mg_connection *, const void *, size_t); bool mg_send(struct mg_connection *, const void *, size_t);
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);
char *mg_straddr(struct mg_connection *, char *, size_t); char *mg_straddr(struct mg_connection *, char *, size_t);
-11
View File
@@ -1,12 +1 @@
void mg_connect_resolved(struct mg_connection *); void mg_connect_resolved(struct mg_connection *);
#if MG_ARCH == MG_ARCH_FREERTOS
static inline void *mg_calloc(int cnt, size_t size) {
void *p = pvPortMalloc(size);
if (p != NULL) memset(p, 0, size);
return p;
}
#define calloc(a, b) mg_calloc((a), (b))
#define malloc(a) pvPortMalloc(a)
#define free(a) vPortFree(a)
#endif
+3 -3
View File
@@ -22,8 +22,8 @@ int mg_sntp_parse(const unsigned char *buf, size_t len, struct timeval *tv) {
} else { } else {
uint32_t *data = (uint32_t *) &buf[40]; uint32_t *data = (uint32_t *) &buf[40];
tv->tv_sec = mg_ntohl(data[0]) - SNTP_TIME_OFFSET; tv->tv_sec = mg_ntohl(data[0]) - SNTP_TIME_OFFSET;
tv->tv_usec = mg_ntohl(data[1]); tv->tv_usec = (suseconds_t) mg_ntohl(data[1]);
s_sntmp_next = tv->tv_sec + SNTP_INTERVAL_SEC; s_sntmp_next = (unsigned long) (tv->tv_sec + SNTP_INTERVAL_SEC);
res = 0; res = 0;
} }
return res; return res;
@@ -39,7 +39,7 @@ static void sntp_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
} }
c->recv.len = 0; // Clear receive buffer c->recv.len = 0; // Clear receive buffer
} else if (ev == MG_EV_RESOLVE) { } else if (ev == MG_EV_RESOLVE) {
mg_sntp_send(c, time(NULL)); mg_sntp_send(c, (unsigned long) time(NULL));
} else if (ev == MG_EV_CLOSE) { } else if (ev == MG_EV_CLOSE) {
// mg_fn_del(c, sntp_cb); // mg_fn_del(c, sntp_cb);
} }
+165 -147
View File
@@ -10,25 +10,41 @@
#include "util.h" #include "util.h"
#if MG_ENABLE_SOCKET #if MG_ENABLE_SOCKET
#if defined(_WIN32) #if defined(_WIN32) && MG_ENABLE_WINSOCK
#define MG_SOCK_ERRNO WSAGetLastError() #define MG_SOCK_ERRNO WSAGetLastError()
#define FD(C_) ((SOCKET)(C_)->fd)
#ifndef SO_EXCLUSIVEADDRUSE #ifndef SO_EXCLUSIVEADDRUSE
#define SO_EXCLUSIVEADDRUSE ((int) (~SO_REUSEADDR)) #define SO_EXCLUSIVEADDRUSE ((int) (~SO_REUSEADDR))
#endif #endif
#elif MG_ARCH == MG_ARCH_FREERTOS #elif MG_ARCH == MG_ARCH_FREERTOS_TCP
#define MG_SOCK_ERRNO errno #define MG_SOCK_ERRNO errno
typedef Socket_t SOCKET; typedef Socket_t SOCKET;
#define FD(C_) ((long) (C_)->fd)
#define INVALID_SOCKET FREERTOS_INVALID_SOCKET #define INVALID_SOCKET FREERTOS_INVALID_SOCKET
#else #else
#define MG_SOCK_ERRNO errno #define MG_SOCK_ERRNO errno
#ifndef closesocket
#define closesocket(x) close(x) #define closesocket(x) close(x)
#endif
#define INVALID_SOCKET (-1) #define INVALID_SOCKET (-1)
typedef int SOCKET; typedef int SOCKET;
#define FD(C_) ((SOCKET)(long) (C_)->fd)
#endif #endif
union _su {
SOCKET s;
void *ptr;
};
#define FD(c_) ptr2sock((c_)->fd)
static SOCKET ptr2sock(void *ptr) {
union _su u = {0};
u.ptr = ptr;
return u.s;
}
static void *sock2ptr(SOCKET s) {
union _su u = {s};
return u.ptr;
}
#ifndef MSG_NONBLOCKING #ifndef MSG_NONBLOCKING
#define MSG_NONBLOCKING 0 #define MSG_NONBLOCKING 0
#endif #endif
@@ -57,61 +73,32 @@ static union usa tousa(struct mg_addr *a) {
return usa; return usa;
} }
static int mg_sock_failed(void) { static bool mg_sock_would_block(void) {
int err = MG_SOCK_ERRNO; int err = MG_SOCK_ERRNO;
return err != EINPROGRESS && err != EWOULDBLOCK return err == EINPROGRESS || err == EWOULDBLOCK
#ifndef WINCE #ifndef WINCE
&& err != EAGAIN && err != EINTR || err == EAGAIN || err == EINTR
#endif #endif
#ifdef _WIN32 #if defined(_WIN32) && MG_ENABLE_WINSOCK
&& err != WSAEINTR && err != WSAEWOULDBLOCK || err == WSAEINTR || err == WSAEWOULDBLOCK
#endif #endif
; ;
} }
static struct mg_connection *alloc_conn(struct mg_mgr *mgr, int is_client, static struct mg_connection *alloc_conn(struct mg_mgr *mgr, bool is_client,
SOCKET fd) { SOCKET fd) {
struct mg_connection *c = (struct mg_connection *) calloc(1, sizeof(*c)); struct mg_connection *c = (struct mg_connection *) calloc(1, sizeof(*c));
if (c != NULL) { if (c != NULL) {
c->is_client = is_client; c->is_client = is_client;
c->fd = (void *) (long) fd; c->fd = sock2ptr(fd);
c->mgr = mgr; c->mgr = mgr;
c->id = ++mgr->nextid; c->id = ++mgr->nextid;
} }
return c; return c;
} }
static int mg_sock_recv(struct mg_connection *c, void *buf, int len, static long mg_sock_send(struct mg_connection *c, const void *buf, size_t len) {
int *fail) { long n = 0;
int n = 0;
if (c->is_udp) {
union usa usa;
socklen_t slen = sizeof(usa.sin);
#if MG_ENABLE_IPV6
if (c->peer.is_ip6) slen = sizeof(usa.sin6);
#endif
n = recvfrom(FD(c), (char *) buf, len, 0, &usa.sa, &slen);
if (n > 0) {
if (c->peer.is_ip6) {
#if MG_ENABLE_IPV6
memcpy(c->peer.ip6, &usa.sin6.sin6_addr, sizeof(c->peer.ip6));
c->peer.port = usa.sin6.sin6_port;
#endif
} else {
c->peer.ip = *(uint32_t *) &usa.sin.sin_addr;
c->peer.port = usa.sin.sin_port;
}
}
} else {
n = recv(FD(c), (char *) buf, len, MSG_NONBLOCKING);
}
*fail = (n == 0) || (n < 0 && mg_sock_failed());
return n;
}
static int mg_sock_send(struct mg_connection *c, const void *buf, int len,
int *fail) {
int n = 0;
if (c->is_udp) { if (c->is_udp) {
union usa usa = tousa(&c->peer); union usa usa = tousa(&c->peer);
socklen_t slen = sizeof(usa.sin); socklen_t slen = sizeof(usa.sin);
@@ -122,78 +109,41 @@ static int mg_sock_send(struct mg_connection *c, const void *buf, int len,
} else { } else {
n = send(FD(c), (char *) buf, len, MSG_NONBLOCKING); n = send(FD(c), (char *) buf, len, MSG_NONBLOCKING);
} }
*fail = (n == 0) || (n < 0 && mg_sock_failed()); return n == 0 ? -1 : n < 0 && mg_sock_would_block() ? 0 : n;
return n;
} }
static int ll_read(struct mg_connection *c, void *buf, int len, int *fail) { bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
int n = c->is_tls ? mg_tls_recv(c, buf, len, fail) return c->is_udp ? mg_sock_send(c, buf, len) > 0
: mg_sock_recv(c, buf, len, fail); : mg_iobuf_append(&c->send, buf, len, MG_IO_SIZE);
LOG(*fail ? LL_DEBUG : LL_VERBOSE_DEBUG,
("%lu %c%c%c %d/%d %d %d", c->id, c->is_tls ? 'T' : 't',
c->is_udp ? 'U' : 'u', c->is_connecting ? 'C' : 'c', n, len,
MG_SOCK_ERRNO, *fail));
if (n > 0 && c->is_hexdumping) {
char *s = mg_hexdump(buf, n);
LOG(LL_INFO, ("\n-- %lu %s %s %d\n%s--", c->id, c->label, "<-", n, s));
free(s);
}
return n;
}
static int ll_write(struct mg_connection *c, const void *buf, int len,
int *fail) {
int n = c->is_tls ? mg_tls_send(c, buf, len, fail)
: mg_sock_send(c, buf, len, fail);
LOG(*fail ? LL_ERROR : LL_VERBOSE_DEBUG,
("%lu %c%c%c %d/%d %d", c->id, c->is_tls ? 'T' : 't',
c->is_udp ? 'U' : 'u', c->is_connecting ? 'C' : 'c', n, len,
MG_SOCK_ERRNO));
if (n > 0 && c->is_hexdumping) {
char *s = mg_hexdump(buf, len);
LOG(LL_INFO, ("\n-- %lu %s %s %d\n%s--", c->id, c->label, "->", len, s));
free(s);
}
return n;
}
int mg_send(struct mg_connection *c, const void *buf, size_t len) {
int fail, n = c->is_udp
? ll_write(c, buf, (SOCKET) len, &fail)
: (int) mg_iobuf_append(&c->send, buf, len, MG_IO_SIZE);
if (len > 0 && n == 0) fail = 1;
return n;
} }
static void mg_set_non_blocking_mode(SOCKET fd) { static void mg_set_non_blocking_mode(SOCKET fd) {
#ifdef _WIN32 #if defined(_WIN32) && MG_ENABLE_WINSOCK
unsigned long on = 1; unsigned long on = 1;
ioctlsocket(fd, FIONBIO, &on); ioctlsocket(fd, FIONBIO, &on);
#elif MG_ARCH == MG_ARCH_FREERTOS #elif MG_ARCH == MG_ARCH_FREERTOS_TCP
const BaseType_t off = 0; const BaseType_t off = 0;
setsockopt(fd, 0, FREERTOS_SO_RCVTIMEO, &off, sizeof(off)); setsockopt(fd, 0, FREERTOS_SO_RCVTIMEO, &off, sizeof(off));
setsockopt(fd, 0, FREERTOS_SO_SNDTIMEO, &off, sizeof(off)); setsockopt(fd, 0, FREERTOS_SO_SNDTIMEO, &off, sizeof(off));
#else #else
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK, FD_CLOEXEC);
#endif #endif
} }
SOCKET mg_open_listener(const char *url) { SOCKET mg_open_listener(const char *url, struct mg_addr *addr) {
struct mg_addr addr;
SOCKET fd = INVALID_SOCKET; SOCKET fd = INVALID_SOCKET;
memset(addr, 0, sizeof(*addr));
memset(&addr, 0, sizeof(addr)); addr->port = mg_htons(mg_url_port(url));
addr.port = mg_htons(mg_url_port(url)); if (!mg_aton(mg_url_host(url), addr)) {
if (!mg_aton(mg_url_host(url), &addr)) {
LOG(LL_ERROR, ("invalid listening URL: %s", url)); LOG(LL_ERROR, ("invalid listening URL: %s", url));
} else { } else {
union usa usa = tousa(&addr); union usa usa = tousa(addr);
int on = 1, af = AF_INET; int on = 1, af = AF_INET;
int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM; int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM;
int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
socklen_t slen = sizeof(usa.sin); socklen_t slen = sizeof(usa.sin);
#if MG_ENABLE_IPV6 #if MG_ENABLE_IPV6
if (addr.is_ip6) af = AF_INET6, slen = sizeof(usa.sin6); if (addr->is_ip6) af = AF_INET6, slen = sizeof(usa.sin6);
#endif #endif
if ((fd = socket(af, type, proto)) != INVALID_SOCKET && if ((fd = socket(af, type, proto)) != INVALID_SOCKET &&
@@ -217,57 +167,121 @@ SOCKET mg_open_listener(const char *url) {
bind(fd, &usa.sa, slen) == 0 && bind(fd, &usa.sa, slen) == 0 &&
// NOTE(lsm): FreeRTOS uses backlog value as a connection limit // NOTE(lsm): FreeRTOS uses backlog value as a connection limit
(type == SOCK_DGRAM || listen(fd, 128) == 0)) { (type == SOCK_DGRAM || listen(fd, 128) == 0)) {
// In case port was set to 0, get the real port number
if (getsockname(fd, &usa.sa, &slen) == 0) {
addr->port = usa.sin.sin_port;
#if MG_ENABLE_IPV6
if (addr->is_ip6) addr->port = usa.sin6.sin6_port;
#endif
}
mg_set_non_blocking_mode(fd); mg_set_non_blocking_mode(fd);
} else if (fd != INVALID_SOCKET) { } else if (fd != INVALID_SOCKET) {
LOG(LL_ERROR, ("Failed to listen on %s, errno %d", url, MG_SOCK_ERRNO));
closesocket(fd); closesocket(fd);
fd = INVALID_SOCKET; fd = INVALID_SOCKET;
} }
} }
if (fd == INVALID_SOCKET) {
LOG(LL_ERROR, ("Failed to listen on %s, errno %d", url, MG_SOCK_ERRNO));
}
return fd; return fd;
} }
static void read_conn(struct mg_connection *c, static long mg_sock_recv(struct mg_connection *c, void *buf, size_t len) {
int (*fn)(struct mg_connection *, void *, int, int *)) { long n = 0;
unsigned char *buf; if (c->is_udp) {
int rc, len, fail; union usa usa;
socklen_t slen = sizeof(usa.sin);
// NOTE(lsm): do only one iteration of reads, cause some systems #if MG_ENABLE_IPV6
// (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data if (c->peer.is_ip6) slen = sizeof(usa.sin6);
if (c->recv.size - c->recv.len < MG_IO_SIZE && #endif
c->recv.size < MG_MAX_RECV_BUF_SIZE && n = recvfrom(FD(c), (char *) buf, len, 0, &usa.sa, &slen);
!mg_iobuf_resize(&c->recv, c->recv.size + MG_IO_SIZE)) { if (n > 0) {
c->is_closing = 1; if (c->peer.is_ip6) {
} #if MG_ENABLE_IPV6
buf = c->recv.buf + c->recv.len; memcpy(c->peer.ip6, &usa.sin6.sin6_addr, sizeof(c->peer.ip6));
len = (int) (c->recv.size - c->recv.len); c->peer.port = usa.sin6.sin6_port;
rc = fn(c, buf, len, &fail); #endif
if (rc > 0) {
struct mg_str evd = mg_str_n((char *) buf, rc);
c->recv.len += rc;
mg_call(c, MG_EV_READ, &evd);
} else { } else {
if (fail) c->is_closing = 1; c->peer.ip = *(uint32_t *) &usa.sin.sin_addr;
c->peer.port = usa.sin.sin_port;
}
}
} else {
n = recv(FD(c), (char *) buf, len, MSG_NONBLOCKING);
}
return n == 0 ? -1 : n < 0 && mg_sock_would_block() ? 0 : n;
}
// NOTE(lsm): do only one iteration of reads, cause some systems
// (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data
static void read_conn(struct mg_connection *c) {
if (c->recv.len >= MG_MAX_RECV_BUF_SIZE) {
mg_error(c, "max_recv_buf_size reached");
} else if (c->recv.size - c->recv.len < MG_IO_SIZE &&
!mg_iobuf_resize(&c->recv, c->recv.size + MG_IO_SIZE)) {
mg_error(c, "oom");
} else {
char *buf = (char *) &c->recv.buf[c->recv.len];
size_t len = c->recv.size - c->recv.len;
long n = c->is_tls ? mg_tls_recv(c, buf, len) : mg_sock_recv(c, buf, len);
LOG(n > 0 ? LL_VERBOSE_DEBUG : LL_DEBUG,
("%-3lu %d%d%d%d%d%d%d%d%d%d%d%d%d%d %7ld %ld/%ld err %d", c->id,
c->is_listening, c->is_client, c->is_accepted, c->is_resolving,
c->is_connecting, c->is_tls, c->is_tls_hs, c->is_udp, c->is_websocket,
c->is_hexdumping, c->is_draining, c->is_closing, c->is_readable,
c->is_writable, (long) c->recv.len, n, (long) len, MG_SOCK_ERRNO));
if (n == 0) {
// Do nothing
} else if (n < 0) {
c->is_closing = 1; // Error, or normal termination
} else if (n > 0) {
struct mg_str evd = mg_str_n(buf, (size_t) n);
if (c->is_hexdumping) {
char *s = mg_hexdump(buf, (size_t) n);
LOG(LL_INFO, ("\n-- %lu %s %s %ld\n%s", c->id, c->label, "<-", n, s));
free(s);
}
c->recv.len += (size_t) n;
mg_call(c, MG_EV_READ, &evd);
}
} }
} }
static int write_conn(struct mg_connection *c) { static void write_conn(struct mg_connection *c) {
int fail, rc = ll_write(c, c->send.buf, (SOCKET) c->send.len, &fail); char *buf = (char *) c->send.buf;
if (rc > 0) { size_t len = c->send.len;
mg_iobuf_delete(&c->send, rc); long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_sock_send(c, buf, len);
LOG(n > 0 ? LL_VERBOSE_DEBUG : LL_DEBUG,
("%-3lu %d%d%d%d%d%d%d%d%d%d%d%d%d%d %7ld %ld err %d", c->id,
c->is_listening, c->is_client, c->is_accepted, c->is_resolving,
c->is_connecting, c->is_tls, c->is_tls_hs, c->is_udp, c->is_websocket,
c->is_hexdumping, c->is_draining, c->is_closing, c->is_readable,
c->is_writable, (long) c->send.len, n, MG_SOCK_ERRNO));
if (n == 0) {
// Do nothing
} else if (n < 0) {
c->is_closing = 1; // Error, or normal termination
} else if (n > 0) {
// Hexdump before deleting
if (c->is_hexdumping) {
char *s = mg_hexdump(buf, (size_t) n);
LOG(LL_INFO, ("\n-- %lu %s %s %ld\n%s", c->id, c->label, "<-", n, s));
free(s);
}
mg_iobuf_delete(&c->send, (size_t) n);
if (c->send.len == 0) mg_iobuf_resize(&c->send, 0); if (c->send.len == 0) mg_iobuf_resize(&c->send, 0);
mg_call(c, MG_EV_WRITE, &rc); mg_call(c, MG_EV_WRITE, &n);
} else if (fail) { // if (c->send.len == 0) mg_iobuf_resize(&c->send, 0);
c->is_closing = 1;
} }
return rc;
} }
static void close_conn(struct mg_connection *c) { static void close_conn(struct mg_connection *c) {
// Unlink this connection from the list // Unlink this connection from the list
LIST_DELETE(struct mg_connection, &c->mgr->conns, c);
mg_resolve_cancel(c); mg_resolve_cancel(c);
LIST_DELETE(struct mg_connection, &c->mgr->conns, c);
if (c == c->mgr->dns4.c) c->mgr->dns4.c = NULL; if (c == c->mgr->dns4.c) c->mgr->dns4.c = NULL;
if (c == c->mgr->dns6.c) c->mgr->dns6.c = NULL; if (c == c->mgr->dns6.c) c->mgr->dns6.c = NULL;
mg_call(c, MG_EV_CLOSE, NULL); mg_call(c, MG_EV_CLOSE, NULL);
@@ -275,7 +289,7 @@ static void close_conn(struct mg_connection *c) {
LOG(LL_DEBUG, ("%lu closed", c->id)); LOG(LL_DEBUG, ("%lu closed", c->id));
if (FD(c) != INVALID_SOCKET) { if (FD(c) != INVALID_SOCKET) {
closesocket(FD(c)); closesocket(FD(c));
#if MG_ARCH == MG_ARCH_FREERTOS #if MG_ARCH == MG_ARCH_FREERTOS_TCP
FreeRTOS_FD_CLR(c->fd, c->mgr->ss, eSELECT_ALL); FreeRTOS_FD_CLR(c->fd, c->mgr->ss, eSELECT_ALL);
#endif #endif
} }
@@ -287,8 +301,8 @@ static void close_conn(struct mg_connection *c) {
} }
static void setsockopts(struct mg_connection *c) { static void setsockopts(struct mg_connection *c) {
#if MG_ARCH == MG_ARCH_FREERTOS #if MG_ARCH == MG_ARCH_FREERTOS_TCP
FreeRTOS_FD_SET(c->fd, c->mgr->ss, eSELECT_READ | eSELECT_EXCEPT); (void) c;
#else #else
int on = 1; int on = 1;
#if !defined(SOL_TCP) #if !defined(SOL_TCP)
@@ -316,12 +330,12 @@ static void setsockopts(struct mg_connection *c) {
void mg_connect_resolved(struct mg_connection *c) { void mg_connect_resolved(struct mg_connection *c) {
char buf[40]; char buf[40];
int type = c->is_udp ? SOCK_DGRAM : SOCK_STREAM; int type = c->is_udp ? SOCK_DGRAM : SOCK_STREAM;
int af = AF_INET; int rc, af = AF_INET;
#if MG_ENABLE_IPV6 #if MG_ENABLE_IPV6
if (c->peer.is_ip6) af = AF_INET6; if (c->peer.is_ip6) af = AF_INET6;
#endif #endif
mg_straddr(c, buf, sizeof(buf)); mg_straddr(c, buf, sizeof(buf));
c->fd = (void *) (long) socket(af, type, 0); c->fd = sock2ptr(socket(af, type, 0));
if (FD(c) == INVALID_SOCKET) { if (FD(c) == INVALID_SOCKET) {
mg_error(c, "socket(): %d", MG_SOCK_ERRNO); mg_error(c, "socket(): %d", MG_SOCK_ERRNO);
return; return;
@@ -331,19 +345,16 @@ void mg_connect_resolved(struct mg_connection *c) {
mg_call(c, MG_EV_RESOLVE, NULL); mg_call(c, MG_EV_RESOLVE, NULL);
if (type == SOCK_STREAM) { if (type == SOCK_STREAM) {
union usa usa = tousa(&c->peer); union usa usa = tousa(&c->peer);
socklen_t slen = socklen_t slen = sizeof(usa.sin);
#if MG_ENABLE_IPV6 #if MG_ENABLE_IPV6
c->peer.is_ip6 ? sizeof(usa.sin6) : if (c->peer.is_ip6) slen = sizeof(usa.sin6);
#endif #endif
sizeof(usa.sin); if ((rc = connect(FD(c), &usa.sa, slen)) == 0 || mg_sock_would_block()) {
int rc = connect(FD(c), &usa.sa, slen);
int fail = rc < 0 && mg_sock_failed() ? MG_SOCK_ERRNO : 0;
if (fail) {
mg_error(c, "connect: %d", MG_SOCK_ERRNO);
} else {
setsockopts(c); setsockopts(c);
if (rc != 0) c->is_connecting = 1;
} else {
mg_error(c, "connect: %d", MG_SOCK_ERRNO);
} }
if (rc < 0) c->is_connecting = 1;
} }
} }
@@ -372,8 +383,8 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
SOCKET fd = accept(FD(lsn), &usa.sa, &sa_len); SOCKET fd = accept(FD(lsn), &usa.sa, &sa_len);
if (fd == INVALID_SOCKET) { if (fd == INVALID_SOCKET) {
LOG(LL_ERROR, ("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERRNO)); LOG(LL_ERROR, ("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERRNO));
#if !defined(_WIN32) #if (!defined(_WIN32) && (MG_ARCH != MG_ARCH_FREERTOS_TCP))
} else if (fd >= FD_SETSIZE) { } else if ((long) fd >= FD_SETSIZE) {
LOG(LL_ERROR, ("%ld > %ld", (long) fd, (long) FD_SETSIZE)); LOG(LL_ERROR, ("%ld > %ld", (long) fd, (long) FD_SETSIZE));
closesocket(fd); closesocket(fd);
#endif #endif
@@ -451,30 +462,33 @@ bool mg_socketpair(int *s1, int *s2) {
struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url, struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data) { mg_event_handler_t fn, void *fn_data) {
struct mg_connection *c = NULL; struct mg_connection *c = NULL;
int is_udp = strncmp(url, "udp:", 4) == 0; bool is_udp = strncmp(url, "udp:", 4) == 0;
SOCKET fd = mg_open_listener(url); struct mg_addr addr;
SOCKET fd = mg_open_listener(url, &addr);
if (fd == INVALID_SOCKET) { if (fd == INVALID_SOCKET) {
} else if ((c = alloc_conn(mgr, 0, fd)) == NULL) { } else if ((c = alloc_conn(mgr, 0, fd)) == NULL) {
LOG(LL_ERROR, ("OOM %s", url)); LOG(LL_ERROR, ("OOM %s", url));
closesocket(fd); closesocket(fd);
} else { } else {
c->fd = (void *) (long) fd; memcpy(&c->peer, &addr, sizeof(struct mg_addr));
c->fd = sock2ptr(fd);
c->is_listening = 1; c->is_listening = 1;
c->is_udp = is_udp; c->is_udp = is_udp;
setsockopts(c);
LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c); LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
c->fn = fn; c->fn = fn;
c->fn_data = fn_data; c->fn_data = fn_data;
LOG(LL_INFO, ("%lu accepting on %s", c->id, url)); LOG(LL_INFO,
("%lu accepting on %s (port %u)", c->id, url, mg_ntohs(c->peer.port)));
} }
return c; return c;
} }
static void mg_iotest(struct mg_mgr *mgr, int ms) { static void mg_iotest(struct mg_mgr *mgr, int ms) {
#if MG_ARCH == MG_ARCH_FREERTOS #if MG_ARCH == MG_ARCH_FREERTOS_TCP
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) {
FreeRTOS_FD_CLR(c->fd, mgr->ss, eSELECT_WRITE); if (c->is_closing || c->is_resolving || FD(c) == INVALID_SOCKET) continue;
FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_READ | eSELECT_EXCEPT);
if (c->is_connecting || (c->send.len > 0 && c->is_tls_hs == 0)) if (c->is_connecting || (c->send.len > 0 && c->is_tls_hs == 0))
FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_WRITE); FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_WRITE);
} }
@@ -483,6 +497,8 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) {
EventBits_t bits = FreeRTOS_FD_ISSET(c->fd, mgr->ss); EventBits_t bits = FreeRTOS_FD_ISSET(c->fd, mgr->ss);
c->is_readable = bits & (eSELECT_READ | eSELECT_EXCEPT) ? 1 : 0; c->is_readable = bits & (eSELECT_READ | eSELECT_EXCEPT) ? 1 : 0;
c->is_writable = bits & eSELECT_WRITE ? 1 : 0; c->is_writable = bits & eSELECT_WRITE ? 1 : 0;
FreeRTOS_FD_CLR(c->fd, mgr->ss,
eSELECT_READ | eSELECT_EXCEPT | eSELECT_WRITE);
} }
#else #else
struct timeval tv = {ms / 1000, (ms % 1000) * 1000}; struct timeval tv = {ms / 1000, (ms % 1000) * 1000};
@@ -523,8 +539,10 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) {
static void connect_conn(struct mg_connection *c) { static void connect_conn(struct mg_connection *c) {
int rc = 0; int rc = 0;
#if MG_ARCH != MG_ARCH_FREERTOS_TCP
socklen_t len = sizeof(rc); socklen_t len = sizeof(rc);
if (getsockopt(FD(c), SOL_SOCKET, SO_ERROR, (char *) &rc, &len)) rc = 1; if (getsockopt(FD(c), SOL_SOCKET, SO_ERROR, (char *) &rc, &len)) rc = 1;
#endif
if (rc == EAGAIN || rc == EWOULDBLOCK) rc = 0; if (rc == EAGAIN || rc == EWOULDBLOCK) rc = 0;
c->is_connecting = 0; c->is_connecting = 0;
if (rc) { if (rc) {
@@ -561,7 +579,7 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
} else if (c->is_tls_hs) { } else if (c->is_tls_hs) {
if ((c->is_readable || c->is_writable)) mg_tls_handshake(c); if ((c->is_readable || c->is_writable)) mg_tls_handshake(c);
} else { } else {
if (c->is_readable) read_conn(c, ll_read); if (c->is_readable) read_conn(c);
if (c->is_writable) write_conn(c); if (c->is_writable) write_conn(c);
} }
+10 -8
View File
@@ -9,16 +9,17 @@
#if MG_ENABLE_SSI #if MG_ENABLE_SSI
static char *mg_ssi(const char *path, const char *root, int depth) { static char *mg_ssi(const char *path, const char *root, int depth) {
struct mg_iobuf b = {NULL, 0, 0}; struct mg_iobuf b = {NULL, 0, 0};
FILE *fp = mg_fopen(path, "rb"); FILE *fp = fopen(path, "rb");
if (fp != NULL) { if (fp != NULL) {
char buf[BUFSIZ], arg[sizeof(buf)]; char buf[BUFSIZ], arg[sizeof(buf)];
int ch, intag = 0; int ch, intag = 0;
size_t len = 0, align = MG_IO_SIZE; size_t len = 0, align = MG_IO_SIZE;
while ((ch = fgetc(fp)) != EOF) { while ((ch = fgetc(fp)) != EOF) {
if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') { if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') {
buf[len++] = ch & 0xff; buf[len++] = (char) (ch & 0xff);
if (sscanf(buf, "<!--#include file=\"%[^\"]", arg)) { if (sscanf(buf, "<!--#include file=\"%[^\"]", arg)) {
char tmp[MG_PATH_MAX], *p = (char *) path + strlen(path), *data; char tmp[MG_PATH_MAX + BUFSIZ + 10],
*p = (char *) path + strlen(path), *data;
while (p > path && p[-1] != MG_DIRSEP && p[-1] != '/') p--; while (p > path && p[-1] != MG_DIRSEP && p[-1] != '/') p--;
snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg); snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg);
if (depth < MG_MAX_SSI_DEPTH && if (depth < MG_MAX_SSI_DEPTH &&
@@ -29,7 +30,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
LOG(LL_ERROR, ("%s: file=%s error or too deep", path, arg)); LOG(LL_ERROR, ("%s: file=%s error or too deep", path, arg));
} }
} else if (sscanf(buf, "<!--#include virtual=\"%[^\"]", arg)) { } else if (sscanf(buf, "<!--#include virtual=\"%[^\"]", arg)) {
char tmp[MG_PATH_MAX], *data; char tmp[MG_PATH_MAX + BUFSIZ + 10], *data;
snprintf(tmp, sizeof(tmp), "%s%s", root, arg); snprintf(tmp, sizeof(tmp), "%s%s", root, arg);
if (depth < MG_MAX_SSI_DEPTH && if (depth < MG_MAX_SSI_DEPTH &&
(data = mg_ssi(tmp, root, depth + 1)) != NULL) { (data = mg_ssi(tmp, root, depth + 1)) != NULL) {
@@ -49,7 +50,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
intag = 1; intag = 1;
if (len > 0) mg_iobuf_append(&b, buf, len, align); if (len > 0) mg_iobuf_append(&b, buf, len, align);
len = 0; len = 0;
buf[len++] = ch & 0xff; buf[len++] = (char) (ch & 0xff);
} else if (intag) { } else if (intag) {
if (len == 5 && strncmp(buf, "<!--#", 5) != 0) { if (len == 5 && strncmp(buf, "<!--#", 5) != 0) {
intag = 0; intag = 0;
@@ -57,9 +58,9 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
LOG(LL_ERROR, ("%s: SSI tag is too large", path)); LOG(LL_ERROR, ("%s: SSI tag is too large", path));
len = 0; len = 0;
} }
buf[len++] = ch & 0xff; buf[len++] = (char) (ch & 0xff);
} else { } else {
buf[len++] = ch & 0xff; buf[len++] = (char) (ch & 0xff);
if (len >= sizeof(buf)) { if (len >= sizeof(buf)) {
mg_iobuf_append(&b, buf, len, align); mg_iobuf_append(&b, buf, len, align);
len = 0; len = 0;
@@ -77,8 +78,9 @@ static char *mg_ssi(const char *path, const char *root, int depth) {
void mg_http_serve_ssi(struct mg_connection *c, const char *root, void mg_http_serve_ssi(struct mg_connection *c, const char *root,
const char *fullpath) { const char *fullpath) {
const char *headers = "Content-Type: text/html; charset=utf-8\r\n";
char *data = mg_ssi(fullpath, root, 0); char *data = mg_ssi(fullpath, root, 0);
mg_http_reply(c, 200, "", "%s", data == NULL ? "" : data); mg_http_reply(c, 200, headers, "%s", data == NULL ? "" : data);
free(data); free(data);
} }
#endif #endif
+2 -2
View File
@@ -1,7 +1,7 @@
#include "str.h" #include "str.h"
#include <stdlib.h> #include <stdlib.h>
struct mg_str mg_str(const char *s) { struct mg_str mg_str_s(const char *s) {
struct mg_str str = {s, s == NULL ? 0 : strlen(s)}; struct mg_str str = {s, s == NULL ? 0 : strlen(s)};
return str; return str;
} }
@@ -44,7 +44,7 @@ int mg_vcasecmp(const struct mg_str *str1, const char *str2) {
struct mg_str mg_strdup(const struct mg_str s) { struct mg_str mg_strdup(const struct mg_str s) {
struct mg_str r = {NULL, 0}; struct mg_str r = {NULL, 0};
if (s.len > 0 && s.ptr != NULL) { if (s.len > 0 && s.ptr != NULL) {
char *sc = (char *) malloc(s.len + 1); char *sc = (char *) calloc(1, s.len + 1);
if (sc != NULL) { if (sc != NULL) {
memcpy(sc, s.ptr, s.len); memcpy(sc, s.ptr, s.len);
sc[s.len] = '\0'; sc[s.len] = '\0';
+3
View File
@@ -11,6 +11,9 @@ struct mg_str {
#define MG_NULL_STR \ #define MG_NULL_STR \
{ NULL, 0 } { NULL, 0 }
// Using macro to avoid shadowing C++ struct constructor, see #1298
#define mg_str(s) mg_str_s(s)
struct mg_str mg_str(const char *s); struct mg_str mg_str(const char *s);
struct mg_str mg_str_n(const char *s, size_t n); struct mg_str mg_str_n(const char *s, size_t n);
int mg_lower(const char *s); int mg_lower(const char *s);
+2 -2
View File
@@ -6,8 +6,8 @@
struct mg_timer *g_timers; struct mg_timer *g_timers;
void mg_timer_init(struct mg_timer *t, int ms, int flags, void (*fn)(void *), void mg_timer_init(struct mg_timer *t, unsigned long ms, unsigned flags,
void *arg) { void (*fn)(void *), void *arg) {
struct mg_timer tmp = {ms, flags, fn, arg, 0UL, g_timers}; struct mg_timer tmp = {ms, flags, fn, arg, 0UL, g_timers};
*t = tmp; *t = tmp;
g_timers = t; g_timers = t;
+5 -4
View File
@@ -1,18 +1,19 @@
#pragma once #pragma once
struct mg_timer { struct mg_timer {
int period_ms; // Timer period in milliseconds unsigned long period_ms; // Timer period in milliseconds
int flags; // Possible flags values below unsigned flags; // Possible flags values below
#define MG_TIMER_REPEAT 1 // Call function periodically, otherwise run once #define MG_TIMER_REPEAT 1 // Call function periodically, otherwise run once
#define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set #define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set
void (*fn)(void *); // Function to call void (*fn)(void *); // Function to call
void *arg; // Function agrument void *arg; // Function argument
unsigned long expire; // Expiration timestamp in milliseconds unsigned long expire; // Expiration timestamp in milliseconds
struct mg_timer *next; // Linkage in g_timers list struct mg_timer *next; // Linkage in g_timers list
}; };
extern struct mg_timer *g_timers; // Global list of timers extern struct mg_timer *g_timers; // Global list of timers
void mg_timer_init(struct mg_timer *, int ms, int, void (*fn)(void *), void *); void mg_timer_init(struct mg_timer *, unsigned long ms, unsigned,
void (*fn)(void *), void *);
void mg_timer_free(struct mg_timer *); void mg_timer_free(struct mg_timer *);
void mg_timer_poll(unsigned long uptime_ms); void mg_timer_poll(unsigned long uptime_ms);
+87 -69
View File
@@ -16,6 +16,12 @@
#endif #endif
#endif #endif
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
#define RNG , rng_get, NULL
#else
#define RNG
#endif
// Different versions have those in different files, so declare here // Different versions have those in different files, so declare here
EXTERN_C int mbedtls_net_recv(void *, unsigned char *, size_t); EXTERN_C int mbedtls_net_recv(void *, unsigned char *, size_t);
EXTERN_C int mbedtls_net_send(void *, const unsigned char *, size_t); EXTERN_C int mbedtls_net_send(void *, const unsigned char *, size_t);
@@ -29,7 +35,7 @@ struct mg_tls {
mbedtls_pk_context pk; // Private key context mbedtls_pk_context pk; // Private key context
}; };
int mg_tls_handshake(struct mg_connection *c) { void mg_tls_handshake(struct mg_connection *c) {
struct mg_tls *tls = (struct mg_tls *) c->tls; struct mg_tls *tls = (struct mg_tls *) c->tls;
int rc; int rc;
mbedtls_ssl_set_bio(&tls->ssl, &c->fd, mbedtls_net_send, mbedtls_net_recv, 0); mbedtls_ssl_set_bio(&tls->ssl, &c->fd, mbedtls_net_send, mbedtls_net_recv, 0);
@@ -44,7 +50,6 @@ int mg_tls_handshake(struct mg_connection *c) {
} else { } else {
mg_error(c, "TLS handshake: -%#x", -rc); // Error mg_error(c, "TLS handshake: -%#x", -rc); // Error
} }
return rc == 0;
} }
static int mbed_rng(void *ctx, unsigned char *buf, size_t len) { static int mbed_rng(void *ctx, unsigned char *buf, size_t len) {
@@ -54,32 +59,48 @@ static int mbed_rng(void *ctx, unsigned char *buf, size_t len) {
} }
static void debug_cb(void *c, int lev, const char *s, int n, const char *s2) { static void debug_cb(void *c, int lev, const char *s, int n, const char *s2) {
n = strlen(s2) - 1; n = (int) strlen(s2) - 1;
LOG(LL_VERBOSE_DEBUG, ("%p %.*s", ((struct mg_connection *) c)->fd, n, s2)); LOG(LL_VERBOSE_DEBUG, ("%p %.*s", ((struct mg_connection *) c)->fd, n, s2));
(void) s; (void) s;
(void) c; (void) c;
(void) lev; (void) lev;
} }
int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { #if MBEDTLS_VERSION_NUMBER >= 0x03000000
static int rng_get(void *p_rng, unsigned char *buf, size_t len) {
(void) p_rng;
mg_random(buf, len);
return 0;
}
#endif
void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls)); struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
int rc = 0; int rc = 0;
const char *ca = opts->ca == NULL ? "-" const char *ca = opts->ca == NULL ? "-"
: opts->ca[0] == '-' ? "(emb)" : opts->ca[0] == '-' ? "(emb)"
: opts->ca; : opts->ca;
const char *cert = opts->cert == NULL ? "-"
: opts->cert[0] == '-' ? "(emb)"
: opts->cert;
const char *certkey = opts->certkey == NULL ? "-"
: opts->certkey[0] == '-' ? "(emb)"
: opts->certkey;
if (tls == NULL) { if (tls == NULL) {
mg_error(c, "TLS OOM"); mg_error(c, "TLS OOM");
goto fail; goto fail;
} }
LOG(LL_DEBUG, ("%lu Setting TLS, CA: %s, cert: %s, key: %s", c->id, ca, LOG(LL_DEBUG, ("%lu Setting TLS, CA: %s, cert: %s, key: %s", c->id, ca,
opts->cert == NULL ? "null" : opts->cert, cert, certkey));
opts->certkey == NULL ? "null" : opts->certkey));
mbedtls_ssl_init(&tls->ssl); mbedtls_ssl_init(&tls->ssl);
mbedtls_ssl_config_init(&tls->conf); mbedtls_ssl_config_init(&tls->conf);
mbedtls_x509_crt_init(&tls->ca);
mbedtls_x509_crt_init(&tls->cert);
mbedtls_pk_init(&tls->pk);
mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c); mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c);
#if !defined(ESP_PLATFORM) //#if !defined(ESP_PLATFORM)
mbedtls_debug_set_threshold(5); // mbedtls_debug_set_threshold(5);
#endif //#endif
if ((rc = mbedtls_ssl_config_defaults( if ((rc = mbedtls_ssl_config_defaults(
&tls->conf, &tls->conf,
c->is_client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER, c->is_client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
@@ -100,7 +121,6 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
goto fail; goto fail;
} }
#else #else
mbedtls_x509_crt_init(&tls->ca);
rc = opts->ca[0] == '-' rc = opts->ca[0] == '-'
? mbedtls_x509_crt_parse(&tls->ca, (uint8_t *) opts->ca, ? mbedtls_x509_crt_parse(&tls->ca, (uint8_t *) opts->ca,
strlen(opts->ca) + 1) strlen(opts->ca) + 1)
@@ -112,23 +132,32 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL); mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL);
#endif #endif
if (opts->srvname.len > 0) { if (opts->srvname.len > 0) {
char buf[opts->srvname.len + 1]; char mem[128], *buf = mem;
sprintf(buf, "%.*s", (int) opts->srvname.len, opts->srvname.ptr); mg_asprintf(&buf, sizeof(mem), "%.*s", (int) opts->srvname.len, opts->srvname.ptr);
mbedtls_ssl_set_hostname(&tls->ssl, buf); mbedtls_ssl_set_hostname(&tls->ssl, buf);
if (buf != mem) free(buf);
} }
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
} }
if (opts->cert != NULL && opts->cert[0] != '\0') { if (opts->cert != NULL && opts->cert[0] != '\0') {
const char *key = opts->certkey; const char *key = opts->certkey;
if (key == NULL) key = opts->cert; if (key == NULL) {
mbedtls_x509_crt_init(&tls->cert); key = opts->cert;
mbedtls_pk_init(&tls->pk); certkey = cert;
if ((rc = mbedtls_x509_crt_parse_file(&tls->cert, opts->cert)) != 0) { }
mg_error(c, "parse(%s) err %#x", opts->cert, -rc); rc = opts->cert[0] == '-'
? mbedtls_x509_crt_parse(&tls->cert, (uint8_t *) opts->cert,
strlen(opts->cert) + 1)
: mbedtls_x509_crt_parse_file(&tls->cert, opts->cert);
if (rc != 0) {
mg_error(c, "parse(%s) err %#x", cert, -rc);
goto fail; goto fail;
} }
if ((rc = mbedtls_pk_parse_keyfile(&tls->pk, key, NULL)) != 0) { rc = key[0] == '-' ? mbedtls_pk_parse_key(&tls->pk, (uint8_t *) key,
mg_error(c, "tls key(%s) %#x", key, -rc); strlen(key) + 1, NULL, 0 RNG)
: mbedtls_pk_parse_keyfile(&tls->pk, key, NULL RNG);
if (rc != 0) {
mg_error(c, "tls key(%s) %#x", certkey, -rc);
goto fail; goto fail;
} }
rc = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->cert, &tls->pk); rc = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->cert, &tls->pk);
@@ -147,39 +176,35 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) { if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
mg_tls_handshake(c); mg_tls_handshake(c);
} }
return 1; return;
fail: fail:
c->is_closing = 1; c->is_closing = 1;
free(tls); free(tls);
return 0;
} }
int mg_tls_recv(struct mg_connection *c, void *buf, size_t len, int *fail) { long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
struct mg_tls *tls = (struct mg_tls *) c->tls; struct mg_tls *tls = (struct mg_tls *) c->tls;
int n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len); long n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len);
*fail = (n == 0) || (n < 0 && n != MBEDTLS_ERR_SSL_WANT_READ); return n == 0 ? -1 : n == MBEDTLS_ERR_SSL_WANT_READ ? 0 : n;
return n;
} }
int mg_tls_send(struct mg_connection *c, const void *buf, size_t len, long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
int *fail) {
struct mg_tls *tls = (struct mg_tls *) c->tls; struct mg_tls *tls = (struct mg_tls *) c->tls;
int n = mbedtls_ssl_write(&tls->ssl, (unsigned char *) buf, len); long n = mbedtls_ssl_write(&tls->ssl, (unsigned char *) buf, len);
*fail = (n == 0) || (n < 0 && n != MBEDTLS_ERR_SSL_WANT_WRITE); return n == 0 ? -1 : n == MBEDTLS_ERR_SSL_WANT_WRITE ? 0 : n;
return n;
} }
int mg_tls_free(struct mg_connection *c) { void mg_tls_free(struct mg_connection *c) {
struct mg_tls *tls = (struct mg_tls *) c->tls; struct mg_tls *tls = (struct mg_tls *) c->tls;
if (tls == NULL) return 0; if (tls == NULL) return;
free(tls->cafile); free(tls->cafile);
mbedtls_x509_crt_free(&tls->ca);
mbedtls_x509_crt_free(&tls->cert);
mbedtls_ssl_free(&tls->ssl); mbedtls_ssl_free(&tls->ssl);
mbedtls_pk_free(&tls->pk); mbedtls_pk_free(&tls->pk);
mbedtls_x509_crt_free(&tls->ca);
mbedtls_x509_crt_free(&tls->cert);
mbedtls_ssl_config_free(&tls->conf); mbedtls_ssl_config_free(&tls->conf);
free(tls); free(tls);
return 1; c->tls = NULL;
} }
#elif MG_ENABLE_OPENSSL ///////////////////////////////////////// OPENSSL #elif MG_ENABLE_OPENSSL ///////////////////////////////////////// OPENSSL
@@ -207,7 +232,7 @@ static int mg_tls_err(struct mg_tls *tls, int res) {
return err; return err;
} }
int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls)); struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
const char *id = "mongoose"; const char *id = "mongoose";
static unsigned char s_initialised = 0; static unsigned char s_initialised = 0;
@@ -232,11 +257,13 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
mg_error(c, "SSL_new"); mg_error(c, "SSL_new");
goto fail; goto fail;
} }
SSL_set_session_id_context(tls->ssl, (const uint8_t *) id, strlen(id)); SSL_set_session_id_context(tls->ssl, (const uint8_t *) id,
(unsigned) strlen(id));
// Disable deprecated protocols // Disable deprecated protocols
SSL_set_options(tls->ssl, SSL_OP_NO_SSLv2); SSL_set_options(tls->ssl, SSL_OP_NO_SSLv2);
SSL_set_options(tls->ssl, SSL_OP_NO_SSLv3); SSL_set_options(tls->ssl, SSL_OP_NO_SSLv3);
SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1); SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1);
SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1_1);
#ifdef MG_ENABLE_OPENSSL_NO_COMPRESSION #ifdef MG_ENABLE_OPENSSL_NO_COMPRESSION
SSL_set_options(tls->ssl, SSL_OP_NO_COMPRESSION); SSL_set_options(tls->ssl, SSL_OP_NO_COMPRESSION);
#endif #endif
@@ -261,7 +288,7 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
} else if ((rc = SSL_use_PrivateKey_file(tls->ssl, key, 1)) != 1) { } else if ((rc = SSL_use_PrivateKey_file(tls->ssl, key, 1)) != 1) {
mg_error(c, "Invalid SSL key, err %d", mg_tls_err(tls, rc)); mg_error(c, "Invalid SSL key, err %d", mg_tls_err(tls, rc));
goto fail; goto fail;
#if OPENSSL_VERSION_NUMBER > 0x10002000L #if OPENSSL_VERSION_NUMBER > 0x10100000L
} else if ((rc = SSL_use_certificate_chain_file(tls->ssl, opts->cert)) != } else if ((rc = SSL_use_certificate_chain_file(tls->ssl, opts->cert)) !=
1) { 1) {
mg_error(c, "Invalid CA, err %d", mg_tls_err(tls, rc)); mg_error(c, "Invalid CA, err %d", mg_tls_err(tls, rc));
@@ -276,9 +303,10 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
} }
if (opts->ciphers != NULL) SSL_set_cipher_list(tls->ssl, opts->ciphers); if (opts->ciphers != NULL) SSL_set_cipher_list(tls->ssl, opts->ciphers);
if (opts->srvname.len > 0) { if (opts->srvname.len > 0) {
char buf[opts->srvname.len + 1]; char mem[128], *buf = mem;
sprintf(buf, "%.*s", (int) opts->srvname.len, opts->srvname.ptr); mg_asprintf(&buf, sizeof(mem), "%.*s", (int) opts->srvname.len, opts->srvname.ptr);
SSL_set_tlsext_host_name(tls->ssl, buf); SSL_set_tlsext_host_name(tls->ssl, buf);
if (buf != mem) free(buf);
} }
c->tls = tls; c->tls = tls;
c->is_tls = 1; c->is_tls = 1;
@@ -288,75 +316,65 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
} }
c->is_hexdumping = 1; c->is_hexdumping = 1;
LOG(LL_DEBUG, ("%lu SSL %s OK", c->id, c->is_accepted ? "accept" : "client")); LOG(LL_DEBUG, ("%lu SSL %s OK", c->id, c->is_accepted ? "accept" : "client"));
return 1; return;
fail: fail:
c->is_closing = 1; c->is_closing = 1;
free(tls); free(tls);
return 0;
} }
int mg_tls_handshake(struct mg_connection *c) { void mg_tls_handshake(struct mg_connection *c) {
struct mg_tls *tls = (struct mg_tls *) c->tls; struct mg_tls *tls = (struct mg_tls *) c->tls;
int rc; int rc;
SSL_set_fd(tls->ssl, (long) c->fd); SSL_set_fd(tls->ssl, (int) (long) c->fd);
rc = c->is_client ? SSL_connect(tls->ssl) : SSL_accept(tls->ssl); rc = c->is_client ? SSL_connect(tls->ssl) : SSL_accept(tls->ssl);
if (rc == 1) { if (rc == 1) {
LOG(LL_DEBUG, ("%lu success", c->id)); LOG(LL_DEBUG, ("%lu success", c->id));
c->is_tls_hs = 0; c->is_tls_hs = 0;
return 1;
} else { } else {
int code; int code;
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
code = mg_tls_err(tls, rc); code = mg_tls_err(tls, rc);
if (code != 0) mg_error(c, "tls hs: rc %d, err %d", rc, code); if (code != 0) mg_error(c, "tls hs: rc %d, err %d", rc, code);
return 0;
} }
} }
int mg_tls_free(struct mg_connection *c) { void mg_tls_free(struct mg_connection *c) {
struct mg_tls *tls = (struct mg_tls *) c->tls; struct mg_tls *tls = (struct mg_tls *) c->tls;
if (tls == NULL) return 0; if (tls == NULL) return;
SSL_free(tls->ssl); SSL_free(tls->ssl);
SSL_CTX_free(tls->ctx); SSL_CTX_free(tls->ctx);
free(tls); free(tls);
return 1; c->tls = NULL;
} }
int mg_tls_recv(struct mg_connection *c, void *buf, size_t len, int *fail) { long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
struct mg_tls *tls = (struct mg_tls *) c->tls; struct mg_tls *tls = (struct mg_tls *) c->tls;
int n = SSL_read(tls->ssl, buf, len); int n = SSL_read(tls->ssl, buf, (int) len);
*fail = (n == 0) || (n < 0 && mg_tls_err(tls, n) != 0); return n == 0 ? -1 : n < 0 && mg_tls_err(tls, n) == 0 ? 0 : n;
return n;
} }
int mg_tls_send(struct mg_connection *c, const void *buf, size_t len, long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
int *fail) {
struct mg_tls *tls = (struct mg_tls *) c->tls; struct mg_tls *tls = (struct mg_tls *) c->tls;
int n = SSL_write(tls->ssl, buf, len); int n = SSL_write(tls->ssl, buf, (int) len);
*fail = (n == 0) || (n < 0 && mg_tls_err(tls, n) != 0); return n == 0 ? -1 : n < 0 && mg_tls_err(tls, n) == 0 ? 0 : n;
return n;
} }
#else ////////////////////////////////////////// NO TLS #else ////////////////////////////////////////// NO TLS
int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
(void) opts; (void) opts;
mg_error(c, "TLS is not enabled"); mg_error(c, "TLS is not enabled");
return 0;
} }
int mg_tls_handshake(struct mg_connection *c) { void mg_tls_handshake(struct mg_connection *c) {
return c != NULL; (void) c;
} }
int mg_tls_free(struct mg_connection *c) { void mg_tls_free(struct mg_connection *c) {
return c != NULL; (void) c;
} }
int mg_tls_recv(struct mg_connection *c, void *buf, size_t len, int *fail) { long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
*fail = 1;
return c == NULL || buf == NULL || len == 0 ? 0 : -1; return c == NULL || buf == NULL || len == 0 ? 0 : -1;
} }
int mg_tls_send(struct mg_connection *c, const void *buf, size_t len, long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
int *fail) {
*fail = 1;
return c == NULL || buf == NULL || len == 0 ? 0 : -1; return c == NULL || buf == NULL || len == 0 ? 0 : -1;
} }
+5 -5
View File
@@ -9,8 +9,8 @@ struct mg_tls_opts {
struct mg_str srvname; // If not empty, enables server name verification struct mg_str srvname; // If not empty, enables server name verification
}; };
int mg_tls_init(struct mg_connection *, struct mg_tls_opts *); void mg_tls_init(struct mg_connection *, struct mg_tls_opts *);
int mg_tls_free(struct mg_connection *); void mg_tls_free(struct mg_connection *);
int mg_tls_send(struct mg_connection *, const void *buf, size_t len, int *fail); long mg_tls_send(struct mg_connection *, const void *buf, size_t len);
int mg_tls_recv(struct mg_connection *, void *buf, size_t len, int *fail); long mg_tls_recv(struct mg_connection *, void *buf, size_t len);
int mg_tls_handshake(struct mg_connection *); void mg_tls_handshake(struct mg_connection *);
+13 -12
View File
@@ -2,7 +2,7 @@
#include "url.h" #include "url.h"
struct url { struct url {
int key, user, pass, host, port, uri, end; size_t key, user, pass, host, port, uri, end;
}; };
int mg_url_is_ssl(const char *url) { int mg_url_is_ssl(const char *url) {
@@ -12,23 +12,23 @@ int mg_url_is_ssl(const char *url) {
} }
static struct url urlparse(const char *url) { static struct url urlparse(const char *url) {
int i; size_t i;
struct url u; struct url u;
memset(&u, 0, sizeof(u)); memset(&u, 0, sizeof(u));
for (i = 0; url[i] != '\0'; i++) { for (i = 0; url[i] != '\0'; i++) {
if (i > 0 && url[i - 1] == '/' && url[i] == '/') { if (i > 0 && u.host == 0 && url[i - 1] == '/' && url[i] == '/') {
u.host = i + 1; u.host = i + 1;
u.port = 0; u.port = 0;
} else if (url[i] == ']') { } else if (url[i] == ']') {
u.port = 0; // IPv6 URLs, like http://[::1]/bar u.port = 0; // IPv6 URLs, like http://[::1]/bar
} else if (url[i] == ':') { } else if (url[i] == ':' && u.port == 0) {
u.port = i + 1; u.port = i + 1;
} else if (url[i] == '@') { } else if (url[i] == '@' && u.user == 0 && u.pass == 0) {
u.user = u.host; u.user = u.host;
u.pass = u.port; u.pass = u.port;
u.host = i + 1; u.host = i + 1;
u.port = 0; u.port = 0;
} else if (u.host && !u.uri && url[i] == '/') { } else if (u.host && u.uri == 0 && url[i] == '/') {
u.uri = i; u.uri = i;
} }
} }
@@ -41,8 +41,9 @@ static struct url urlparse(const char *url) {
struct mg_str mg_url_host(const char *url) { struct mg_str mg_url_host(const char *url) {
struct url u = urlparse(url); struct url u = urlparse(url);
int n = size_t n = u.port ? u.port - u.host - 1
u.port ? u.port - u.host - 1 : u.uri ? u.uri - u.host : u.end - u.host; : u.uri ? u.uri - u.host
: u.end - u.host;
struct mg_str s = mg_str_n(url + u.host, n); struct mg_str s = mg_str_n(url + u.host, n);
if (s.len > 2 && s.ptr[0] == '[' && s.ptr[s.len - 1] == ']') { if (s.len > 2 && s.ptr[0] == '[' && s.ptr[s.len - 1] == ']') {
s.len -= 2; s.len -= 2;
@@ -63,7 +64,7 @@ unsigned short mg_url_port(const char *url) {
if (memcmp(url, "wss:", 4) == 0 || memcmp(url, "https:", 6) == 0) port = 443; if (memcmp(url, "wss:", 4) == 0 || memcmp(url, "https:", 6) == 0) port = 443;
if (memcmp(url, "mqtt:", 5) == 0) port = 1883; if (memcmp(url, "mqtt:", 5) == 0) port = 1883;
if (memcmp(url, "mqtts:", 6) == 0) port = 8883; if (memcmp(url, "mqtts:", 6) == 0) port = 8883;
if (u.port) port = atoi(url + u.port); if (u.port) port = (unsigned short) atoi(url + u.port);
return port; return port;
} }
@@ -71,7 +72,7 @@ struct mg_str mg_url_user(const char *url) {
struct url u = urlparse(url); struct url u = urlparse(url);
struct mg_str s = mg_str(""); struct mg_str s = mg_str("");
if (u.user && (u.pass || u.host)) { if (u.user && (u.pass || u.host)) {
int n = u.pass ? u.pass - u.user - 1 : u.host - u.user - 1; size_t n = u.pass ? u.pass - u.user - 1 : u.host - u.user - 1;
s = mg_str_n(url + u.user, n); s = mg_str_n(url + u.user, n);
} }
return s; return s;
@@ -79,9 +80,9 @@ struct mg_str mg_url_user(const char *url) {
struct mg_str mg_url_pass(const char *url) { struct mg_str mg_url_pass(const char *url) {
struct url u = urlparse(url); struct url u = urlparse(url);
struct mg_str s = mg_str(""); struct mg_str s = mg_str_n("", 0UL);
if (u.pass && u.host) { if (u.pass && u.host) {
int n = u.host - u.pass - 1; size_t n = u.host - u.pass - 1;
s = mg_str_n(url + u.pass, n); s = mg_str_n(url + u.pass, n);
} }
return s; return s;
+67 -65
View File
@@ -1,4 +1,5 @@
#include "config.h" #include "config.h" // Must go first - important for test++
#include "util.h" #include "util.h"
#if MG_ENABLE_FS #if MG_ENABLE_FS
@@ -12,19 +13,8 @@ int mg_stat(const char *path, mg_stat_t *st) {
#endif #endif
} }
FILE *mg_fopen(const char *path, const char *mode) {
#ifdef _WIN32
wchar_t b1[MG_PATH_MAX], b2[10];
MultiByteToWideChar(CP_UTF8, 0, path, -1, b1, sizeof(b1) / sizeof(b1[0]));
MultiByteToWideChar(CP_UTF8, 0, mode, -1, b2, sizeof(b2) / sizeof(b2[0]));
return _wfopen(b1, b2);
#else
return fopen(path, mode);
#endif
}
int64_t mg_file_size(const char *path) { int64_t mg_file_size(const char *path) {
#if MG_ARCH == MG_ARCH_FREERTOS #if MG_ARCH == MG_ARCH_FREERTOS_TCP && defined(MG_ENABLE_FF)
struct FF_STAT st; struct FF_STAT st;
return ff_stat(path, &st) == 0 ? st.st_size : 0; return ff_stat(path, &st) == 0 ? st.st_size : 0;
#else #else
@@ -33,18 +23,19 @@ int64_t mg_file_size(const char *path) {
#endif #endif
} }
char *mg_file_read(const char *path) { char *mg_file_read(const char *path, size_t *sizep) {
FILE *fp; FILE *fp;
char *data = NULL; char *data = NULL;
size_t size = (size_t) mg_file_size(path); size_t size = (size_t) mg_file_size(path);
if ((fp = mg_fopen(path, "rb")) != NULL) { if ((fp = fopen(path, "rb")) != NULL) {
data = (char *) malloc(size + 1); data = (char *) calloc(1, size + 1);
if (data != NULL) { if (data != NULL) {
if (fread(data, 1, size, fp) != size) { if (fread(data, 1, size, fp) != size) {
free(data); free(data);
data = NULL; data = NULL;
} else { } else {
data[size] = '\0'; data[size] = '\0';
if (sizep != NULL) *sizep = size;
} }
} }
fclose(fp); fclose(fp);
@@ -57,7 +48,7 @@ bool mg_file_write(const char *path, const void *buf, size_t len) {
FILE *fp; FILE *fp;
char tmp[MG_PATH_MAX]; char tmp[MG_PATH_MAX];
snprintf(tmp, sizeof(tmp), "%s.%d", path, rand()); snprintf(tmp, sizeof(tmp), "%s.%d", path, rand());
fp = mg_fopen(tmp, "wb"); fp = fopen(tmp, "wb");
if (fp != NULL) { if (fp != NULL) {
result = fwrite(buf, 1, len, fp) == len; result = fwrite(buf, 1, len, fp) == len;
fclose(fp); fclose(fp);
@@ -74,36 +65,38 @@ bool mg_file_write(const char *path, const void *buf, size_t len) {
bool mg_file_printf(const char *path, const char *fmt, ...) { bool mg_file_printf(const char *path, const char *fmt, ...) {
char tmp[256], *buf = tmp; char tmp[256], *buf = tmp;
bool result; bool result;
size_t len; int len;
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
len = mg_vasprintf(&buf, sizeof(tmp), fmt, ap); len = mg_vasprintf(&buf, sizeof(tmp), fmt, ap);
va_end(ap); va_end(ap);
result = mg_file_write(path, buf, len); result = mg_file_write(path, buf, len > 0 ? (size_t) len : 0);
if (buf != tmp) free(buf); if (buf != tmp) free(buf);
return result; return result;
} }
#endif #endif // MG_ENABLE_FS
void mg_random(void *buf, size_t len) { void mg_random(void *buf, size_t len) {
bool done = false; bool done = false;
#if MG_ENABLE_FS unsigned char *p = (unsigned char *) buf;
FILE *fp = mg_fopen("/dev/urandom", "rb"); #if MG_ARCH == MG_ARCH_ESP32
while (len--) *p++ = (unsigned char) (esp_random() & 255);
#elif MG_ARCH == MG_ARCH_WIN32
#elif MG_ARCH_UNIX && MG_ENABLE_FS
FILE *fp = fopen("/dev/urandom", "rb");
if (fp != NULL) { if (fp != NULL) {
fread(buf, 1, len, fp); if (fread(buf, 1, len, fp) == len) done = true;
fclose(fp); fclose(fp);
done = true;
} }
#endif #endif
if (!done) {
// Fallback to a pseudo random gen // Fallback to a pseudo random gen
size_t i; if (!done) {
for (i = 0; i < len; i++) ((unsigned char *) buf)[i] = rand() % 0xff; while (len--) *p++ = (unsigned char) (rand() & 255);
} }
} }
bool mg_globmatch(const char *s1, int n1, const char *s2, int n2) { bool mg_globmatch(const char *s1, size_t n1, const char *s2, size_t n2) {
int i = 0, j = 0, ni = 0, nj = 0; size_t i = 0, j = 0, ni = 0, nj = 0;
while (i < n1 || j < n2) { while (i < n1 || j < n2) {
if (i < n1 && j < n2 && (s1[i] == '?' || s2[j] == s1[i])) { if (i < n1 && j < n2 && (s1[i] == '?' || s2[j] == s1[i])) {
i++, j++; i++, j++;
@@ -118,21 +111,22 @@ bool mg_globmatch(const char *s1, int n1, const char *s2, int n2) {
return true; return true;
} }
static int mg_nextcommaentry(const char *s, int slen, int ofs, int *koff, static size_t mg_nce(const char *s, size_t n, size_t ofs, size_t *koff,
int *klen, int *voff, int *vlen) { size_t *klen, size_t *voff, size_t *vlen) {
int kvlen, kl; size_t kvlen, kl;
for (kvlen = 0; ofs + kvlen < slen && s[ofs + kvlen] != ',';) kvlen++; for (kvlen = 0; ofs + kvlen < n && s[ofs + kvlen] != ',';) kvlen++;
for (kl = 0; kl < kvlen && s[ofs + kl] != '=';) kl++; for (kl = 0; kl < kvlen && s[ofs + kl] != '=';) kl++;
if (koff != NULL) *koff = ofs; if (koff != NULL) *koff = ofs;
if (klen != NULL) *klen = kl; if (klen != NULL) *klen = kl;
if (voff != NULL) *voff = kl < kvlen ? ofs + kl + 1 : 0; if (voff != NULL) *voff = kl < kvlen ? ofs + kl + 1 : 0;
if (vlen != NULL) *vlen = kl < kvlen ? kvlen - kl - 1 : 0; if (vlen != NULL) *vlen = kl < kvlen ? kvlen - kl - 1 : 0;
return ofs >= slen ? slen : ofs + kvlen + 1; ofs += kvlen + 1;
return ofs > n ? n : ofs;
} }
bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v) { bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v) {
int koff, klen, voff, vlen; size_t koff = 0, klen = 0, voff = 0, vlen = 0;
int off = mg_nextcommaentry(s->ptr, s->len, 0, &koff, &klen, &voff, &vlen); size_t off = mg_nce(s->ptr, s->len, 0, &koff, &klen, &voff, &vlen);
if (k != NULL) *k = mg_str_n(s->ptr + koff, klen); if (k != NULL) *k = mg_str_n(s->ptr + koff, klen);
if (v != NULL) *v = mg_str_n(s->ptr + voff, vlen); if (v != NULL) *v = mg_str_n(s->ptr + voff, vlen);
*s = mg_str_n(s->ptr + off, s->len - off); *s = mg_str_n(s->ptr + off, s->len - off);
@@ -142,45 +136,47 @@ bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v) {
uint32_t mg_ntohl(uint32_t net) { uint32_t mg_ntohl(uint32_t net) {
uint8_t data[4] = {0, 0, 0, 0}; uint8_t data[4] = {0, 0, 0, 0};
memcpy(&data, &net, sizeof(data)); memcpy(&data, &net, sizeof(data));
return ((uint32_t) data[3] << 0) | ((uint32_t) data[2] << 8) | return (((uint32_t) data[3]) << 0) | (((uint32_t) data[2]) << 8) |
((uint32_t) data[1] << 16) | ((uint32_t) data[0] << 24); (((uint32_t) data[1]) << 16) | (((uint32_t) data[0]) << 24);
} }
uint16_t mg_ntohs(uint16_t net) { uint16_t mg_ntohs(uint16_t net) {
uint8_t data[2] = {0, 0}; uint8_t data[2] = {0, 0};
memcpy(&data, &net, sizeof(data)); memcpy(&data, &net, sizeof(data));
return ((uint16_t) data[1] << 0) | ((uint32_t) data[0] << 8); return (uint16_t)((uint16_t) data[1] | (((uint16_t) data[0]) << 8));
} }
char *mg_hexdump(const void *buf, size_t len) { char *mg_hexdump(const void *buf, size_t len) {
const unsigned char *p = (const unsigned char *) buf; const unsigned char *p = (const unsigned char *) buf;
size_t i, idx, n = 0, ofs = 0, dlen = len * 5 + 100; size_t i, idx, n = 0, ofs = 0, dlen = len * 5 + 100;
char ascii[17] = "", *dst = (char *) malloc(dlen); char ascii[17] = "", *dst = (char *) calloc(1, dlen);
if (dst == NULL) return dst; if (dst == NULL) return dst;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
idx = i % 16; idx = i % 16;
if (idx == 0) { if (idx == 0) {
if (i > 0 && dlen > n) n += snprintf(dst + n, dlen - n, " %s\n", ascii); if (i > 0 && dlen > n)
if (dlen > n) n += snprintf(dst + n, dlen - n, "%04x ", (int) (i + ofs)); n += (size_t) snprintf(dst + n, dlen - n, " %s\n", ascii);
if (dlen > n)
n += (size_t) snprintf(dst + n, dlen - n, "%04x ", (int) (i + ofs));
} }
if (dlen < n) break; if (dlen < n) break;
n += snprintf(dst + n, dlen - n, " %02x", p[i]); n += (size_t) snprintf(dst + n, dlen - n, " %02x", p[i]);
ascii[idx] = p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i]; ascii[idx] = (char) (p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i]);
ascii[idx + 1] = '\0'; ascii[idx + 1] = '\0';
} }
while (i++ % 16) { while (i++ % 16) {
if (n < dlen) n += snprintf(dst + n, dlen - n, "%s", " "); if (n < dlen) n += (size_t) snprintf(dst + n, dlen - n, "%s", " ");
} }
if (n < dlen) n += snprintf(dst + n, dlen - n, " %s\n", ascii); if (n < dlen) n += (size_t) snprintf(dst + n, dlen - n, " %s\n", ascii);
if (n > dlen - 1) n = dlen - 1; if (n > dlen - 1) n = dlen - 1;
dst[n] = '\0'; dst[n] = '\0';
return dst; return dst;
} }
char *mg_hex(const void *buf, int len, char *to) { char *mg_hex(const void *buf, size_t len, char *to) {
const unsigned char *p = (const unsigned char *) buf; const unsigned char *p = (const unsigned char *) buf;
static const char *hex = "0123456789abcdef"; static const char *hex = "0123456789abcdef";
int i = 0; size_t i = 0;
for (; len--; p++) { for (; len--; p++) {
to[i++] = hex[p[0] >> 4]; to[i++] = hex[p[0] >> 4];
to[i++] = hex[p[0] & 0x0f]; to[i++] = hex[p[0] & 0x0f];
@@ -189,19 +185,20 @@ char *mg_hex(const void *buf, int len, char *to) {
return to; return to;
} }
unsigned long mg_unhexn(const char *s, int len) { static unsigned char mg_unhex_nimble(unsigned char c) {
return (c >= '0' && c <= '9') ? (unsigned char) (c - '0')
: (c >= 'A' && c <= 'F') ? (unsigned char) (c - '7')
: (unsigned char) (c - 'W');
}
unsigned long mg_unhexn(const char *s, size_t len) {
unsigned long i = 0, v = 0; unsigned long i = 0, v = 0;
for (i = 0; i < (unsigned long) len; i++) { for (i = 0; i < len; i++) v <<= 4, v |= mg_unhex_nimble(((uint8_t *) s)[i]);
int c = s[i];
if (i > 0) v <<= 4;
v |= (c >= '0' && c <= '9') ? c - '0'
: (c >= 'A' && c <= 'F') ? c - '7' : c - 'W';
}
return v; return v;
} }
void mg_unhex(const char *buf, int len, unsigned char *to) { void mg_unhex(const char *buf, size_t len, unsigned char *to) {
int i; size_t i;
for (i = 0; i < len; i += 2) { for (i = 0; i < len; i += 2) {
to[i >> 1] = (unsigned char) mg_unhexn(&buf[i], 2); to[i >> 1] = (unsigned char) mg_unhexn(&buf[i], 2);
} }
@@ -225,7 +222,7 @@ int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap) {
free(*buf); free(*buf);
if (size == 0) size = 5; if (size == 0) size = 5;
size *= 2; size *= 2;
if ((*buf = (char *) malloc(size)) == NULL) { if ((*buf = (char *) calloc(1, size)) == NULL) {
len = -1; len = -1;
break; break;
} }
@@ -239,11 +236,11 @@ int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap) {
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} else if (len >= (int) size) { } else if (len >= (int) size) {
/// Standard-compliant code path. Allocate a buffer that is large enough /// Standard-compliant code path. Allocate a buffer that is large enough
if ((*buf = (char *) malloc(len + 1)) == NULL) { if ((*buf = (char *) calloc(1, (size_t) len + 1)) == NULL) {
len = -1; // LCOV_EXCL_LINE len = -1; // LCOV_EXCL_LINE
} else { // LCOV_EXCL_LINE } else { // LCOV_EXCL_LINE
va_copy(ap_copy, ap); va_copy(ap_copy, ap);
len = vsnprintf(*buf, len + 1, fmt, ap_copy); len = vsnprintf(*buf, (size_t) len + 1, fmt, ap_copy);
va_end(ap_copy); va_end(ap_copy);
} }
} }
@@ -261,11 +258,12 @@ int mg_asprintf(char **buf, size_t size, const char *fmt, ...) {
} }
int64_t mg_to64(struct mg_str str) { int64_t mg_to64(struct mg_str str) {
int64_t result = 0, neg = 1; int64_t result = 0, neg = 1, max = 922337203685477570 /* INT64_MAX/10-10 */;
size_t i = 0; size_t i = 0;
while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++; while (i < str.len && (str.ptr[i] == ' ' || str.ptr[i] == '\t')) i++;
if (i < str.len && str.ptr[i] == '-') neg = -1, i++; if (i < str.len && str.ptr[i] == '-') neg = -1, i++;
while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') { while (i < str.len && str.ptr[i] >= '0' && str.ptr[i] <= '9') {
if (result > max) return 0;
result *= 10; result *= 10;
result += (str.ptr[i] - '0'); result += (str.ptr[i] - '0');
i++; i++;
@@ -301,6 +299,8 @@ double mg_time(void) {
((int64_t) ftime.dwHighDateTime << 32)) / ((int64_t) ftime.dwHighDateTime << 32)) /
10000000.0) - 10000000.0) -
11644473600; 11644473600;
#elif MG_ARCH == MG_ARCH_FREERTOS_TCP
return mg_millis() / 1000.0;
#else #else
struct timeval tv; struct timeval tv;
if (gettimeofday(&tv, NULL /* tz */) != 0) return 0; if (gettimeofday(&tv, NULL /* tz */) != 0) return 0;
@@ -313,8 +313,10 @@ void mg_usleep(unsigned long usecs) {
Sleep(usecs / 1000); Sleep(usecs / 1000);
#elif MG_ARCH == MG_ARCH_ESP8266 #elif MG_ARCH == MG_ARCH_ESP8266
ets_delay_us(usecs); ets_delay_us(usecs);
#elif MG_ARCH == MG_ARCH_FREERTOS_TCP || MG_ARCH == MG_ARCH_FREERTOS_LWIP
vTaskDelay(pdMS_TO_TICKS(usecs / 1000));
#else #else
usleep(usecs); usleep((useconds_t) usecs);
#endif #endif
} }
@@ -324,13 +326,13 @@ unsigned long mg_millis(void) {
#elif MG_ARCH == MG_ARCH_ESP32 #elif MG_ARCH == MG_ARCH_ESP32
return esp_timer_get_time() / 1000; return esp_timer_get_time() / 1000;
#elif MG_ARCH == MG_ARCH_ESP8266 #elif MG_ARCH == MG_ARCH_ESP8266
// return system_get_time() / 1000;
return xTaskGetTickCount() * portTICK_PERIOD_MS; return xTaskGetTickCount() * portTICK_PERIOD_MS;
#elif MG_ARCH == MG_ARCH_FREERTOS #elif MG_ARCH == MG_ARCH_FREERTOS_TCP || MG_ARCH == MG_ARCH_FREERTOS_LWIP
return xTaskGetTickCount() * portTICK_PERIOD_MS; return xTaskGetTickCount() * portTICK_PERIOD_MS;
#else #else
struct timespec ts; struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts); clock_gettime(CLOCK_REALTIME, &ts);
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000; return (unsigned long) ((uint64_t) ts.tv_sec * 1000 +
(uint64_t) ts.tv_nsec / 1000000);
#endif #endif
} }
+24 -26
View File
@@ -3,20 +3,33 @@
#include "arch.h" #include "arch.h"
#include "str.h" #include "str.h"
char *mg_file_read(const char *path); // WEAK symbol makes it possible to define a "default" function implementation,
// which could be overridden by the user who can define a function with the
// same name without linking conflict
#if !defined(WEAK)
#if (defined(__GNUC__) || defined(__clang__) || \
defined(__TI_COMPILER_VERSION__)) && \
!defined(_WIN32) && !defined(__CYGWIN__)
#define WEAK __attribute__((weak))
#else
#define WEAK
#endif
#endif
char *mg_file_read(const char *path, size_t *size);
int64_t mg_file_size(const char *path); int64_t mg_file_size(const char *path);
bool mg_file_write(const char *path, const void *buf, size_t len); bool mg_file_write(const char *path, const void *buf, size_t len);
bool mg_file_printf(const char *path, const char *fmt, ...); bool mg_file_printf(const char *path, const char *fmt, ...);
void mg_random(void *buf, size_t len); void mg_random(void *buf, size_t len) WEAK;
bool mg_globmatch(const char *pattern, int plen, const char *s, int n); bool mg_globmatch(const char *pattern, size_t plen, const char *s, size_t n);
bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v); bool mg_next_comma_entry(struct mg_str *s, struct mg_str *k, struct mg_str *v);
uint16_t mg_ntohs(uint16_t net); uint16_t mg_ntohs(uint16_t net);
uint32_t mg_ntohl(uint32_t net); uint32_t mg_ntohl(uint32_t net);
uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len); uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len);
char *mg_hexdump(const void *buf, size_t len); char *mg_hexdump(const void *buf, size_t len);
char *mg_hex(const void *buf, int len, char *dst); char *mg_hex(const void *buf, size_t len, char *dst);
void mg_unhex(const char *buf, int len, unsigned char *to); void mg_unhex(const char *buf, size_t len, unsigned char *to);
unsigned long mg_unhexn(const char *s, int len); unsigned long mg_unhexn(const char *s, size_t len);
int mg_asprintf(char **buf, size_t size, const char *fmt, ...); int mg_asprintf(char **buf, size_t size, const char *fmt, ...);
int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap); int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap);
int64_t mg_to64(struct mg_str str); int64_t mg_to64(struct mg_str str);
@@ -31,26 +44,11 @@ typedef struct _stati64 mg_stat_t;
typedef struct stat mg_stat_t; typedef struct stat mg_stat_t;
#endif #endif
int mg_stat(const char *path, mg_stat_t *); int mg_stat(const char *path, mg_stat_t *);
FILE *mg_fopen(const char *fp, const char *mode);
#endif #endif
#define mg_htons(x) mg_ntohs(x) #define mg_htons(x) mg_ntohs(x)
#define mg_htonl(x) mg_ntohl(x) #define mg_htonl(x) mg_ntohl(x)
#define MG_SWAP16(x) ((((x) >> 8) & 255) | ((x & 255) << 8))
#define MG_SWAP32(x) \
(((x) >> 24) | (((x) &0xff0000) >> 8) | (((x) &0xff00) << 8) | ((x) << 24))
#if !defined(WEAK)
#if (defined(__GNUC__) || defined(__clang__) || \
defined(__TI_COMPILER_VERSION__)) && \
!defined(_WIN32) && !defined(__CYGWIN__)
#define WEAK __attribute__((weak))
#else
#define WEAK
#endif
#endif
// Expands to a string representation of its argument: e.g. // Expands to a string representation of its argument: e.g.
// MG_STRINGIFY_LITERAL(5) expands to "5" // MG_STRINGIFY_LITERAL(5) expands to "5"
#if !defined(_MSC_VER) || _MSC_VER >= 1900 #if !defined(_MSC_VER) || _MSC_VER >= 1900
@@ -58,7 +56,12 @@ FILE *mg_fopen(const char *fp, const char *mode);
#else #else
#define MG_STRINGIFY_LITERAL(x) #x #define MG_STRINGIFY_LITERAL(x) #x
#endif #endif
// Expands to a string representation of its argument, which can be a macro:
// #define FOO 123
// MG_STRINGIFY_MACRO(FOO) // Expands to 123
#define MG_STRINGIFY_MACRO(x) MG_STRINGIFY_LITERAL(x)
// Linked list management macros
#define LIST_ADD_HEAD(type_, head_, elem_) \ #define LIST_ADD_HEAD(type_, head_, elem_) \
do { \ do { \
(elem_)->next = (*head_); \ (elem_)->next = (*head_); \
@@ -78,8 +81,3 @@ FILE *mg_fopen(const char *fp, const char *mode);
while (*h != (elem_)) h = &(*h)->next; \ while (*h != (elem_)) h = &(*h)->next; \
*h = (elem_)->next; \ *h = (elem_)->next; \
} while (0) } while (0)
// Expands to a string representation of its argument, which can be a macro:
// #define FOO 123
// MG_STRINGIFY_MACRO(FOO) // Expands to 123
#define MG_STRINGIFY_MACRO(x) MG_STRINGIFY_LITERAL(x)
+9 -2
View File
@@ -1,2 +1,9 @@
#pragma once
#define MG_VERSION "7.2" #ifndef MONGOOSE_H
#define MONGOOSE_H
#define MG_VERSION "7.3"
#ifdef __cplusplus
extern "C" {
#endif
+14 -7
View File
@@ -54,7 +54,7 @@ static size_t ws_process(uint8_t *buf, size_t len, struct ws_msg *msg) {
} else if (len >= 10 + mask_len) { } else if (len >= 10 + mask_len) {
msg->header_len = 10 + mask_len; msg->header_len = 10 + mask_len;
msg->data_len = msg->data_len =
(int) (((uint64_t) mg_ntohl(*(uint32_t *) &buf[2])) << 32) + (size_t)(((uint64_t) mg_ntohl(*(uint32_t *) &buf[2])) << 32) +
mg_ntohl(*(uint32_t *) &buf[6]); mg_ntohl(*(uint32_t *) &buf[6]);
} }
} }
@@ -124,7 +124,7 @@ static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data,
c->is_websocket = 1; c->is_websocket = 1;
mg_call(c, MG_EV_WS_OPEN, &hm); mg_call(c, MG_EV_WS_OPEN, &hm);
} }
mg_iobuf_delete(&c->recv, n); mg_iobuf_delete(&c->recv, (size_t) n);
} else { } else {
return; // A request is not yet received return; // A request is not yet received
} }
@@ -134,6 +134,9 @@ static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data,
char *s = (char *) c->recv.buf + msg.header_len; char *s = (char *) c->recv.buf + msg.header_len;
struct mg_ws_message m = {{s, msg.data_len}, msg.flags}; struct mg_ws_message m = {{s, msg.data_len}, msg.flags};
switch (msg.flags & WEBSOCKET_FLAGS_MASK_OP) { switch (msg.flags & WEBSOCKET_FLAGS_MASK_OP) {
case WEBSOCKET_OP_CONTINUE:
mg_call(c, MG_EV_WS_CTL, &m);
break;
case WEBSOCKET_OP_PING: case WEBSOCKET_OP_PING:
LOG(LL_DEBUG, ("%s", "WS PONG")); LOG(LL_DEBUG, ("%s", "WS PONG"));
mg_ws_send(c, s, msg.data_len, WEBSOCKET_OP_PONG); mg_ws_send(c, s, msg.data_len, WEBSOCKET_OP_PONG);
@@ -142,15 +145,19 @@ static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data,
case WEBSOCKET_OP_PONG: case WEBSOCKET_OP_PONG:
mg_call(c, MG_EV_WS_CTL, &m); mg_call(c, MG_EV_WS_CTL, &m);
break; break;
case WEBSOCKET_OP_TEXT:
case WEBSOCKET_OP_BINARY:
mg_call(c, MG_EV_WS_MSG, &m);
break;
case WEBSOCKET_OP_CLOSE: case WEBSOCKET_OP_CLOSE:
LOG(LL_ERROR, ("%lu Got WS CLOSE", c->id)); LOG(LL_ERROR, ("%lu Got WS CLOSE", c->id));
mg_call(c, MG_EV_WS_CTL, &m); mg_call(c, MG_EV_WS_CTL, &m);
c->is_closing = 1; c->is_closing = 1;
return;
default: {
mg_call(c, MG_EV_WS_MSG, &m);
break; break;
} default:
// Per RFC6455, close conn when an unknown op is recvd
mg_error(c, "unknown WS op %d", msg.flags & WEBSOCKET_FLAGS_MASK_OP);
break;
} }
mg_iobuf_delete(&c->recv, msg.header_len + msg.data_len); mg_iobuf_delete(&c->recv, msg.header_len + msg.data_len);
} }
@@ -188,7 +195,7 @@ struct mg_connection *mg_ws_connect(struct mg_mgr *mgr, const char *url,
"Sec-WebSocket-Key: %s\r\n" "Sec-WebSocket-Key: %s\r\n"
"\r\n", "\r\n",
mg_url_uri(url), (int) host.len, host.ptr, n1, buf1, key); mg_url_uri(url), (int) host.len, host.ptr, n1, buf1, key);
mg_send(c, buf2, n2); mg_send(c, buf2, n2 > 0 ? (size_t) n2 : 0);
if (buf1 != mem1) free(buf1); if (buf1 != mem1) free(buf1);
if (buf2 != mem2) free(buf2); if (buf2 != mem2) free(buf2);
c->pfn = mg_ws_cb; c->pfn = mg_ws_cb;
+1
View File
@@ -0,0 +1 @@
secret
+1
View File
@@ -0,0 +1 @@
є
+361
View File
@@ -0,0 +1,361 @@
/*
* FreeRTOS Kernel V10.4.3
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#include "FreeRTOS.h"
#include "task.h"
#include "croutine.h"
/* Remove the whole file is co-routines are not being used. */
#if ( configUSE_CO_ROUTINES != 0 )
/*
* Some kernel aware debuggers require data to be viewed to be global, rather
* than file scope.
*/
#ifdef portREMOVE_STATIC_QUALIFIER
#define static
#endif
/* Lists for ready and blocked co-routines. --------------------*/
static List_t pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */
static List_t xDelayedCoRoutineList1; /*< Delayed co-routines. */
static List_t xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
static List_t * pxDelayedCoRoutineList = NULL; /*< Points to the delayed co-routine list currently being used. */
static List_t * pxOverflowDelayedCoRoutineList = NULL; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
static List_t xPendingReadyCoRoutineList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */
/* Other file private variables. --------------------------------*/
CRCB_t * pxCurrentCoRoutine = NULL;
static UBaseType_t uxTopCoRoutineReadyPriority = 0;
static TickType_t xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0;
/* The initial state of the co-routine when it is created. */
#define corINITIAL_STATE ( 0 )
/*
* Place the co-routine represented by pxCRCB into the appropriate ready queue
* for the priority. It is inserted at the end of the list.
*
* This macro accesses the co-routine ready lists and therefore must not be
* used from within an ISR.
*/
#define prvAddCoRoutineToReadyQueue( pxCRCB ) \
{ \
if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority ) \
{ \
uxTopCoRoutineReadyPriority = pxCRCB->uxPriority; \
} \
vListInsertEnd( ( List_t * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) ); \
}
/*
* Utility to ready all the lists used by the scheduler. This is called
* automatically upon the creation of the first co-routine.
*/
static void prvInitialiseCoRoutineLists( void );
/*
* Co-routines that are readied by an interrupt cannot be placed directly into
* the ready lists (there is no mutual exclusion). Instead they are placed in
* in the pending ready list in order that they can later be moved to the ready
* list by the co-routine scheduler.
*/
static void prvCheckPendingReadyList( void );
/*
* Macro that looks at the list of co-routines that are currently delayed to
* see if any require waking.
*
* Co-routines are stored in the queue in the order of their wake time -
* meaning once one co-routine has been found whose timer has not expired
* we need not look any further down the list.
*/
static void prvCheckDelayedList( void );
/*-----------------------------------------------------------*/
BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode,
UBaseType_t uxPriority,
UBaseType_t uxIndex )
{
BaseType_t xReturn;
CRCB_t * pxCoRoutine;
/* Allocate the memory that will store the co-routine control block. */
pxCoRoutine = ( CRCB_t * ) pvPortMalloc( sizeof( CRCB_t ) );
if( pxCoRoutine )
{
/* If pxCurrentCoRoutine is NULL then this is the first co-routine to
* be created and the co-routine data structures need initialising. */
if( pxCurrentCoRoutine == NULL )
{
pxCurrentCoRoutine = pxCoRoutine;
prvInitialiseCoRoutineLists();
}
/* Check the priority is within limits. */
if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
{
uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
}
/* Fill out the co-routine control block from the function parameters. */
pxCoRoutine->uxState = corINITIAL_STATE;
pxCoRoutine->uxPriority = uxPriority;
pxCoRoutine->uxIndex = uxIndex;
pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
/* Initialise all the other co-routine control block parameters. */
vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
/* Set the co-routine control block as a link back from the ListItem_t.
* This is so we can get back to the containing CRCB from a generic item
* in a list. */
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
/* Event lists are always in priority order. */
listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), ( ( TickType_t ) configMAX_CO_ROUTINE_PRIORITIES - ( TickType_t ) uxPriority ) );
/* Now the co-routine has been initialised it can be added to the ready
* list at the correct priority. */
prvAddCoRoutineToReadyQueue( pxCoRoutine );
xReturn = pdPASS;
}
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
return xReturn;
}
/*-----------------------------------------------------------*/
void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay,
List_t * pxEventList )
{
TickType_t xTimeToWake;
/* Calculate the time to wake - this may overflow but this is
* not a problem. */
xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
/* We must remove ourselves from the ready list before adding
* ourselves to the blocked list as the same list item is used for
* both lists. */
( void ) uxListRemove( ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
/* The list item will be inserted in wake time order. */
listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
if( xTimeToWake < xCoRoutineTickCount )
{
/* Wake time has overflowed. Place this item in the
* overflow list. */
vListInsert( ( List_t * ) pxOverflowDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
}
else
{
/* The wake time has not overflowed, so we can use the
* current block list. */
vListInsert( ( List_t * ) pxDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
}
if( pxEventList )
{
/* Also add the co-routine to an event list. If this is done then the
* function must be called with interrupts disabled. */
vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
}
}
/*-----------------------------------------------------------*/
static void prvCheckPendingReadyList( void )
{
/* Are there any co-routines waiting to get moved to the ready list? These
* are co-routines that have been readied by an ISR. The ISR cannot access
* the ready lists itself. */
while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE )
{
CRCB_t * pxUnblockedCRCB;
/* The pending ready list can be accessed by an ISR. */
portDISABLE_INTERRUPTS();
{
pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyCoRoutineList ) );
( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
}
portENABLE_INTERRUPTS();
( void ) uxListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
prvAddCoRoutineToReadyQueue( pxUnblockedCRCB );
}
}
/*-----------------------------------------------------------*/
static void prvCheckDelayedList( void )
{
CRCB_t * pxCRCB;
xPassedTicks = xTaskGetTickCount() - xLastTickCount;
while( xPassedTicks )
{
xCoRoutineTickCount++;
xPassedTicks--;
/* If the tick count has overflowed we need to swap the ready lists. */
if( xCoRoutineTickCount == 0 )
{
List_t * pxTemp;
/* Tick count has overflowed so we need to swap the delay lists. If there are
* any items in pxDelayedCoRoutineList here then there is an error! */
pxTemp = pxDelayedCoRoutineList;
pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
pxOverflowDelayedCoRoutineList = pxTemp;
}
/* See if this tick has made a timeout expire. */
while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE )
{
pxCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList );
if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )
{
/* Timeout not yet expired. */
break;
}
portDISABLE_INTERRUPTS();
{
/* The event could have occurred just before this critical
* section. If this is the case then the generic list item will
* have been moved to the pending ready list and the following
* line is still valid. Also the pvContainer parameter will have
* been set to NULL so the following lines are also valid. */
( void ) uxListRemove( &( pxCRCB->xGenericListItem ) );
/* Is the co-routine waiting on an event also? */
if( pxCRCB->xEventListItem.pxContainer )
{
( void ) uxListRemove( &( pxCRCB->xEventListItem ) );
}
}
portENABLE_INTERRUPTS();
prvAddCoRoutineToReadyQueue( pxCRCB );
}
}
xLastTickCount = xCoRoutineTickCount;
}
/*-----------------------------------------------------------*/
void vCoRoutineSchedule( void )
{
/* Only run a co-routine after prvInitialiseCoRoutineLists() has been
* called. prvInitialiseCoRoutineLists() is called automatically when a
* co-routine is created. */
if( pxDelayedCoRoutineList != NULL )
{
/* See if any co-routines readied by events need moving to the ready lists. */
prvCheckPendingReadyList();
/* See if any delayed co-routines have timed out. */
prvCheckDelayedList();
/* Find the highest priority queue that contains ready co-routines. */
while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
{
if( uxTopCoRoutineReadyPriority == 0 )
{
/* No more co-routines to check. */
return;
}
--uxTopCoRoutineReadyPriority;
}
/* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
* of the same priority get an equal share of the processor time. */
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
/* Call the co-routine. */
( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
}
}
/*-----------------------------------------------------------*/
static void prvInitialiseCoRoutineLists( void )
{
UBaseType_t uxPriority;
for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
{
vListInitialise( ( List_t * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
}
vListInitialise( ( List_t * ) &xDelayedCoRoutineList1 );
vListInitialise( ( List_t * ) &xDelayedCoRoutineList2 );
vListInitialise( ( List_t * ) &xPendingReadyCoRoutineList );
/* Start with pxDelayedCoRoutineList using list1 and the
* pxOverflowDelayedCoRoutineList using list2. */
pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
}
/*-----------------------------------------------------------*/
BaseType_t xCoRoutineRemoveFromEventList( const List_t * pxEventList )
{
CRCB_t * pxUnblockedCRCB;
BaseType_t xReturn;
/* This function is called from within an interrupt. It can only access
* event lists and the pending ready list. This function assumes that a
* check has already been made to ensure pxEventList is not empty. */
pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
vListInsertEnd( ( List_t * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) );
if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
{
xReturn = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
return xReturn;
}
#endif /* configUSE_CO_ROUTINES == 0 */
+771
View File
@@ -0,0 +1,771 @@
/*
* FreeRTOS Kernel V10.4.3
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/* Standard includes. */
#include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
* all the API functions to use the MPU wrappers. That should only be done when
* task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "event_groups.h"
/* Lint e961, e750 and e9021 are suppressed as a MISRA exception justified
* because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
* for the header files above, but not in this file, in order to generate the
* correct privileged Vs unprivileged linkage and placement. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021 See comment above. */
/* The following bit fields convey control information in a task's event list
* item value. It is important they don't clash with the
* taskEVENT_LIST_ITEM_VALUE_IN_USE definition. */
#if configUSE_16_BIT_TICKS == 1
#define eventCLEAR_EVENTS_ON_EXIT_BIT 0x0100U
#define eventUNBLOCKED_DUE_TO_BIT_SET 0x0200U
#define eventWAIT_FOR_ALL_BITS 0x0400U
#define eventEVENT_BITS_CONTROL_BYTES 0xff00U
#else
#define eventCLEAR_EVENTS_ON_EXIT_BIT 0x01000000UL
#define eventUNBLOCKED_DUE_TO_BIT_SET 0x02000000UL
#define eventWAIT_FOR_ALL_BITS 0x04000000UL
#define eventEVENT_BITS_CONTROL_BYTES 0xff000000UL
#endif
typedef struct EventGroupDef_t
{
EventBits_t uxEventBits;
List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxEventGroupNumber;
#endif
#if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */
#endif
} EventGroup_t;
/*-----------------------------------------------------------*/
/*
* Test the bits set in uxCurrentEventBits to see if the wait condition is met.
* The wait condition is defined by xWaitForAllBits. If xWaitForAllBits is
* pdTRUE then the wait condition is met if all the bits set in uxBitsToWaitFor
* are also set in uxCurrentEventBits. If xWaitForAllBits is pdFALSE then the
* wait condition is met if any of the bits set in uxBitsToWait for are also set
* in uxCurrentEventBits.
*/
static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xWaitForAllBits ) PRIVILEGED_FUNCTION;
/*-----------------------------------------------------------*/
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer )
{
EventGroup_t * pxEventBits;
/* A StaticEventGroup_t object must be provided. */
configASSERT( pxEventGroupBuffer );
#if ( configASSERT_DEFINED == 1 )
{
/* Sanity check that the size of the structure used to declare a
* variable of type StaticEventGroup_t equals the size of the real
* event group structure. */
volatile size_t xSize = sizeof( StaticEventGroup_t );
configASSERT( xSize == sizeof( EventGroup_t ) );
} /*lint !e529 xSize is referenced if configASSERT() is defined. */
#endif /* configASSERT_DEFINED */
/* The user has provided a statically allocated event group - use it. */
pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 !e9087 EventGroup_t and StaticEventGroup_t are deliberately aliased for data hiding purposes and guaranteed to have the same size and alignment requirement - checked by configASSERT(). */
if( pxEventBits != NULL )
{
pxEventBits->uxEventBits = 0;
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
/* Both static and dynamic allocation can be used, so note that
* this event group was created statically in case the event group
* is later deleted. */
pxEventBits->ucStaticallyAllocated = pdTRUE;
}
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
traceEVENT_GROUP_CREATE( pxEventBits );
}
else
{
/* xEventGroupCreateStatic should only ever be called with
* pxEventGroupBuffer pointing to a pre-allocated (compile time
* allocated) StaticEventGroup_t variable. */
traceEVENT_GROUP_CREATE_FAILED();
}
return pxEventBits;
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
/*-----------------------------------------------------------*/
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
EventGroupHandle_t xEventGroupCreate( void )
{
EventGroup_t * pxEventBits;
/* Allocate the event group. Justification for MISRA deviation as
* follows: pvPortMalloc() always ensures returned memory blocks are
* aligned per the requirements of the MCU stack. In this case
* pvPortMalloc() must return a pointer that is guaranteed to meet the
* alignment requirements of the EventGroup_t structure - which (if you
* follow it through) is the alignment requirements of the TickType_t type
* (EventBits_t being of TickType_t itself). Therefore, whenever the
* stack alignment requirements are greater than or equal to the
* TickType_t alignment requirements the cast is safe. In other cases,
* where the natural word size of the architecture is less than
* sizeof( TickType_t ), the TickType_t variables will be accessed in two
* or more reads operations, and the alignment requirements is only that
* of each individual read. */
pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); /*lint !e9087 !e9079 see comment above. */
if( pxEventBits != NULL )
{
pxEventBits->uxEventBits = 0;
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
{
/* Both static and dynamic allocation can be used, so note this
* event group was allocated statically in case the event group is
* later deleted. */
pxEventBits->ucStaticallyAllocated = pdFALSE;
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
traceEVENT_GROUP_CREATE( pxEventBits );
}
else
{
traceEVENT_GROUP_CREATE_FAILED(); /*lint !e9063 Else branch only exists to allow tracing and does not generate code if trace macros are not defined. */
}
return pxEventBits;
}
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
/*-----------------------------------------------------------*/
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
const EventBits_t uxBitsToWaitFor,
TickType_t xTicksToWait )
{
EventBits_t uxOriginalBitValue, uxReturn;
EventGroup_t * pxEventBits = xEventGroup;
BaseType_t xAlreadyYielded;
BaseType_t xTimeoutOccurred = pdFALSE;
configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
configASSERT( uxBitsToWaitFor != 0 );
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
}
#endif
vTaskSuspendAll();
{
uxOriginalBitValue = pxEventBits->uxEventBits;
( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet );
if( ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor )
{
/* All the rendezvous bits are now set - no need to block. */
uxReturn = ( uxOriginalBitValue | uxBitsToSet );
/* Rendezvous always clear the bits. They will have been cleared
* already unless this is the only task in the rendezvous. */
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
xTicksToWait = 0;
}
else
{
if( xTicksToWait != ( TickType_t ) 0 )
{
traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor );
/* Store the bits that the calling task is waiting for in the
* task's event list item so the kernel knows when a match is
* found. Then enter the blocked state. */
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS ), xTicksToWait );
/* This assignment is obsolete as uxReturn will get set after
* the task unblocks, but some compilers mistakenly generate a
* warning about uxReturn being returned without being set if the
* assignment is omitted. */
uxReturn = 0;
}
else
{
/* The rendezvous bits were not set, but no block time was
* specified - just return the current event bit value. */
uxReturn = pxEventBits->uxEventBits;
xTimeoutOccurred = pdTRUE;
}
}
}
xAlreadyYielded = xTaskResumeAll();
if( xTicksToWait != ( TickType_t ) 0 )
{
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* The task blocked to wait for its required bits to be set - at this
* point either the required bits were set or the block time expired. If
* the required bits were set they will have been stored in the task's
* event list item, and they should now be retrieved then cleared. */
uxReturn = uxTaskResetEventItemValue();
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
{
/* The task timed out, just return the current event bit value. */
taskENTER_CRITICAL();
{
uxReturn = pxEventBits->uxEventBits;
/* Although the task got here because it timed out before the
* bits it was waiting for were set, it is possible that since it
* unblocked another task has set the bits. If this is the case
* then it needs to clear the bits before exiting. */
if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor )
{
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();
xTimeoutOccurred = pdTRUE;
}
else
{
/* The task unblocked because the bits were set. */
}
/* Control bits might be set as the task had blocked should not be
* returned. */
uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
}
traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred );
/* Prevent compiler warnings when trace macros are not used. */
( void ) xTimeoutOccurred;
return uxReturn;
}
/*-----------------------------------------------------------*/
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait )
{
EventGroup_t * pxEventBits = xEventGroup;
EventBits_t uxReturn, uxControlBits = 0;
BaseType_t xWaitConditionMet, xAlreadyYielded;
BaseType_t xTimeoutOccurred = pdFALSE;
/* Check the user is not attempting to wait on the bits used by the kernel
* itself, and that at least one bit is being requested. */
configASSERT( xEventGroup );
configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
configASSERT( uxBitsToWaitFor != 0 );
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
}
#endif
vTaskSuspendAll();
{
const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;
/* Check to see if the wait condition is already met or not. */
xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );
if( xWaitConditionMet != pdFALSE )
{
/* The wait condition has already been met so there is no need to
* block. */
uxReturn = uxCurrentEventBits;
xTicksToWait = ( TickType_t ) 0;
/* Clear the wait bits if requested to do so. */
if( xClearOnExit != pdFALSE )
{
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else if( xTicksToWait == ( TickType_t ) 0 )
{
/* The wait condition has not been met, but no block time was
* specified, so just return the current value. */
uxReturn = uxCurrentEventBits;
xTimeoutOccurred = pdTRUE;
}
else
{
/* The task is going to block to wait for its required bits to be
* set. uxControlBits are used to remember the specified behaviour of
* this call to xEventGroupWaitBits() - for use when the event bits
* unblock the task. */
if( xClearOnExit != pdFALSE )
{
uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( xWaitForAllBits != pdFALSE )
{
uxControlBits |= eventWAIT_FOR_ALL_BITS;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Store the bits that the calling task is waiting for in the
* task's event list item so the kernel knows when a match is
* found. Then enter the blocked state. */
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );
/* This is obsolete as it will get set after the task unblocks, but
* some compilers mistakenly generate a warning about the variable
* being returned without being set if it is not done. */
uxReturn = 0;
traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );
}
}
xAlreadyYielded = xTaskResumeAll();
if( xTicksToWait != ( TickType_t ) 0 )
{
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* The task blocked to wait for its required bits to be set - at this
* point either the required bits were set or the block time expired. If
* the required bits were set they will have been stored in the task's
* event list item, and they should now be retrieved then cleared. */
uxReturn = uxTaskResetEventItemValue();
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
{
taskENTER_CRITICAL();
{
/* The task timed out, just return the current event bit value. */
uxReturn = pxEventBits->uxEventBits;
/* It is possible that the event bits were updated between this
* task leaving the Blocked state and running again. */
if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE )
{
if( xClearOnExit != pdFALSE )
{
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
xTimeoutOccurred = pdTRUE;
}
taskEXIT_CRITICAL();
}
else
{
/* The task unblocked because the bits were set. */
}
/* The task blocked so control bits may have been set. */
uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
}
traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );
/* Prevent compiler warnings when trace macros are not used. */
( void ) xTimeoutOccurred;
return uxReturn;
}
/*-----------------------------------------------------------*/
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear )
{
EventGroup_t * pxEventBits = xEventGroup;
EventBits_t uxReturn;
/* Check the user is not attempting to clear the bits used by the kernel
* itself. */
configASSERT( xEventGroup );
configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
taskENTER_CRITICAL();
{
traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear );
/* The value returned is the event group value prior to the bits being
* cleared. */
uxReturn = pxEventBits->uxEventBits;
/* Clear the bits. */
pxEventBits->uxEventBits &= ~uxBitsToClear;
}
taskEXIT_CRITICAL();
return uxReturn;
}
/*-----------------------------------------------------------*/
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear )
{
BaseType_t xReturn;
traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear );
xReturn = xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ); /*lint !e9087 Can't avoid cast to void* as a generic callback function not specific to this use case. Callback casts back to original type so safe. */
return xReturn;
}
#endif /* if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */
/*-----------------------------------------------------------*/
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
{
UBaseType_t uxSavedInterruptStatus;
EventGroup_t const * const pxEventBits = xEventGroup;
EventBits_t uxReturn;
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
{
uxReturn = pxEventBits->uxEventBits;
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
return uxReturn;
} /*lint !e818 EventGroupHandle_t is a typedef used in other functions to so can't be pointer to const. */
/*-----------------------------------------------------------*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet )
{
ListItem_t * pxListItem, * pxNext;
ListItem_t const * pxListEnd;
List_t const * pxList;
EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits;
EventGroup_t * pxEventBits = xEventGroup;
BaseType_t xMatchFound = pdFALSE;
/* Check the user is not attempting to set the bits used by the kernel
* itself. */
configASSERT( xEventGroup );
configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
pxList = &( pxEventBits->xTasksWaitingForBits );
pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
vTaskSuspendAll();
{
traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet );
pxListItem = listGET_HEAD_ENTRY( pxList );
/* Set the bits. */
pxEventBits->uxEventBits |= uxBitsToSet;
/* See if the new bit value should unblock any tasks. */
while( pxListItem != pxListEnd )
{
pxNext = listGET_NEXT( pxListItem );
uxBitsWaitedFor = listGET_LIST_ITEM_VALUE( pxListItem );
xMatchFound = pdFALSE;
/* Split the bits waited for from the control bits. */
uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES;
uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES;
if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 )
{
/* Just looking for single bit being set. */
if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 )
{
xMatchFound = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor )
{
/* All bits are set. */
xMatchFound = pdTRUE;
}
else
{
/* Need all bits to be set, but not all the bits were set. */
}
if( xMatchFound != pdFALSE )
{
/* The bits match. Should the bits be cleared on exit? */
if( ( uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT ) != ( EventBits_t ) 0 )
{
uxBitsToClear |= uxBitsWaitedFor;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Store the actual event flag value in the task's event list
* item before removing the task from the event list. The
* eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows
* that is was unblocked due to its required bits matching, rather
* than because it timed out. */
vTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );
}
/* Move onto the next list item. Note pxListItem->pxNext is not
* used here as the list item may have been removed from the event list
* and inserted into the ready/pending reading list. */
pxListItem = pxNext;
}
/* Clear any bits that matched when the eventCLEAR_EVENTS_ON_EXIT_BIT
* bit was set in the control word. */
pxEventBits->uxEventBits &= ~uxBitsToClear;
}
( void ) xTaskResumeAll();
return pxEventBits->uxEventBits;
}
/*-----------------------------------------------------------*/
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
{
EventGroup_t * pxEventBits = xEventGroup;
const List_t * pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
vTaskSuspendAll();
{
traceEVENT_GROUP_DELETE( xEventGroup );
while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )
{
/* Unblock the task, returning 0 as the event list is being deleted
* and cannot therefore have any bits set. */
configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
}
#if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
{
/* The event group can only have been allocated dynamically - free
* it again. */
vPortFree( pxEventBits );
}
#elif ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
{
/* The event group could have been allocated statically or
* dynamically, so check before attempting to free the memory. */
if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE )
{
vPortFree( pxEventBits );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
}
( void ) xTaskResumeAll();
}
/*-----------------------------------------------------------*/
/* For internal use only - execute a 'set bits' command that was pended from
* an interrupt. */
void vEventGroupSetBitsCallback( void * pvEventGroup,
const uint32_t ulBitsToSet )
{
( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */
}
/*-----------------------------------------------------------*/
/* For internal use only - execute a 'clear bits' command that was pended from
* an interrupt. */
void vEventGroupClearBitsCallback( void * pvEventGroup,
const uint32_t ulBitsToClear )
{
( void ) xEventGroupClearBits( pvEventGroup, ( EventBits_t ) ulBitsToClear ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */
}
/*-----------------------------------------------------------*/
static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xWaitForAllBits )
{
BaseType_t xWaitConditionMet = pdFALSE;
if( xWaitForAllBits == pdFALSE )
{
/* Task only has to wait for one bit within uxBitsToWaitFor to be
* set. Is one already set? */
if( ( uxCurrentEventBits & uxBitsToWaitFor ) != ( EventBits_t ) 0 )
{
xWaitConditionMet = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
/* Task has to wait for all the bits in uxBitsToWaitFor to be set.
* Are they set already? */
if( ( uxCurrentEventBits & uxBitsToWaitFor ) == uxBitsToWaitFor )
{
xWaitConditionMet = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
return xWaitConditionMet;
}
/*-----------------------------------------------------------*/
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
BaseType_t * pxHigherPriorityTaskWoken )
{
BaseType_t xReturn;
traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet );
xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ); /*lint !e9087 Can't avoid cast to void* as a generic callback function not specific to this use case. Callback casts back to original type so safe. */
return xReturn;
}
#endif /* if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */
/*-----------------------------------------------------------*/
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxEventGroupGetNumber( void * xEventGroup )
{
UBaseType_t xReturn;
EventGroup_t const * pxEventBits = ( EventGroup_t * ) xEventGroup; /*lint !e9087 !e9079 EventGroupHandle_t is a pointer to an EventGroup_t, but EventGroupHandle_t is kept opaque outside of this file for data hiding purposes. */
if( xEventGroup == NULL )
{
xReturn = 0;
}
else
{
xReturn = pxEventBits->uxEventGroupNumber;
}
return xReturn;
}
#endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/
#if ( configUSE_TRACE_FACILITY == 1 )
void vEventGroupSetNumber( void * xEventGroup,
UBaseType_t uxEventGroupNumber )
{
( ( EventGroup_t * ) xEventGroup )->uxEventGroupNumber = uxEventGroupNumber; /*lint !e9087 !e9079 EventGroupHandle_t is a pointer to an EventGroup_t, but EventGroupHandle_t is kept opaque outside of this file for data hiding purposes. */
}
#endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,32 @@
/*
* FreeRTOS Kernel V10.4.3
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef _MSC_VER /* Visual Studio doesn't support #warning. */
#warning The name of this file has changed to stack_macros.h. Please update your code accordingly. This source file (which has the original name) will be removed in future released.
#endif
#include "stack_macros.h"
+417
View File
@@ -0,0 +1,417 @@
/*
* FreeRTOS Kernel V10.4.3
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file atomic.h
* @brief FreeRTOS atomic operation support.
*
* This file implements atomic functions by disabling interrupts globally.
* Implementations with architecture specific atomic instructions can be
* provided under each compiler directory.
*/
#ifndef ATOMIC_H
#define ATOMIC_H
#ifndef INC_FREERTOS_H
#error "include FreeRTOS.h must appear in source files before include atomic.h"
#endif
/* Standard includes. */
#include <stdint.h>
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/*
* Port specific definitions -- entering/exiting critical section.
* Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h
*
* Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with
* ATOMIC_ENTER_CRITICAL().
*
*/
#if defined( portSET_INTERRUPT_MASK_FROM_ISR )
/* Nested interrupt scheme is supported in this port. */
#define ATOMIC_ENTER_CRITICAL() \
UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR()
#define ATOMIC_EXIT_CRITICAL() \
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType )
#else
/* Nested interrupt scheme is NOT supported in this port. */
#define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL()
#define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL()
#endif /* portSET_INTERRUPT_MASK_FROM_ISR() */
/*
* Port specific definition -- "always inline".
* Inline is compiler specific, and may not always get inlined depending on your
* optimization level. Also, inline is considered as performance optimization
* for atomic. Thus, if portFORCE_INLINE is not provided by portmacro.h,
* instead of resulting error, simply define it away.
*/
#ifndef portFORCE_INLINE
#define portFORCE_INLINE
#endif
#define ATOMIC_COMPARE_AND_SWAP_SUCCESS 0x1U /**< Compare and swap succeeded, swapped. */
#define ATOMIC_COMPARE_AND_SWAP_FAILURE 0x0U /**< Compare and swap failed, did not swap. */
/*----------------------------- Swap && CAS ------------------------------*/
/**
* Atomic compare-and-swap
*
* @brief Performs an atomic compare-and-swap operation on the specified values.
*
* @param[in, out] pulDestination Pointer to memory location from where value is
* to be loaded and checked.
* @param[in] ulExchange If condition meets, write this value to memory.
* @param[in] ulComparand Swap condition.
*
* @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped.
*
* @note This function only swaps *pulDestination with ulExchange, if previous
* *pulDestination value equals ulComparand.
*/
static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32( uint32_t volatile * pulDestination,
uint32_t ulExchange,
uint32_t ulComparand )
{
uint32_t ulReturnValue;
ATOMIC_ENTER_CRITICAL();
{
if( *pulDestination == ulComparand )
{
*pulDestination = ulExchange;
ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;
}
else
{
ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE;
}
}
ATOMIC_EXIT_CRITICAL();
return ulReturnValue;
}
/*-----------------------------------------------------------*/
/**
* Atomic swap (pointers)
*
* @brief Atomically sets the address pointed to by *ppvDestination to the value
* of *pvExchange.
*
* @param[in, out] ppvDestination Pointer to memory location from where a pointer
* value is to be loaded and written back to.
* @param[in] pvExchange Pointer value to be written to *ppvDestination.
*
* @return The initial value of *ppvDestination.
*/
static portFORCE_INLINE void * Atomic_SwapPointers_p32( void * volatile * ppvDestination,
void * pvExchange )
{
void * pReturnValue;
ATOMIC_ENTER_CRITICAL();
{
pReturnValue = *ppvDestination;
*ppvDestination = pvExchange;
}
ATOMIC_EXIT_CRITICAL();
return pReturnValue;
}
/*-----------------------------------------------------------*/
/**
* Atomic compare-and-swap (pointers)
*
* @brief Performs an atomic compare-and-swap operation on the specified pointer
* values.
*
* @param[in, out] ppvDestination Pointer to memory location from where a pointer
* value is to be loaded and checked.
* @param[in] pvExchange If condition meets, write this value to memory.
* @param[in] pvComparand Swap condition.
*
* @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped.
*
* @note This function only swaps *ppvDestination with pvExchange, if previous
* *ppvDestination value equals pvComparand.
*/
static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32( void * volatile * ppvDestination,
void * pvExchange,
void * pvComparand )
{
uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE;
ATOMIC_ENTER_CRITICAL();
{
if( *ppvDestination == pvComparand )
{
*ppvDestination = pvExchange;
ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;
}
}
ATOMIC_EXIT_CRITICAL();
return ulReturnValue;
}
/*----------------------------- Arithmetic ------------------------------*/
/**
* Atomic add
*
* @brief Atomically adds count to the value of the specified pointer points to.
*
* @param[in,out] pulAddend Pointer to memory location from where value is to be
* loaded and written back to.
* @param[in] ulCount Value to be added to *pulAddend.
*
* @return previous *pulAddend value.
*/
static portFORCE_INLINE uint32_t Atomic_Add_u32( uint32_t volatile * pulAddend,
uint32_t ulCount )
{
uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulAddend;
*pulAddend += ulCount;
}
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
}
/*-----------------------------------------------------------*/
/**
* Atomic subtract
*
* @brief Atomically subtracts count from the value of the specified pointer
* pointers to.
*
* @param[in,out] pulAddend Pointer to memory location from where value is to be
* loaded and written back to.
* @param[in] ulCount Value to be subtract from *pulAddend.
*
* @return previous *pulAddend value.
*/
static portFORCE_INLINE uint32_t Atomic_Subtract_u32( uint32_t volatile * pulAddend,
uint32_t ulCount )
{
uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulAddend;
*pulAddend -= ulCount;
}
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
}
/*-----------------------------------------------------------*/
/**
* Atomic increment
*
* @brief Atomically increments the value of the specified pointer points to.
*
* @param[in,out] pulAddend Pointer to memory location from where value is to be
* loaded and written back to.
*
* @return *pulAddend value before increment.
*/
static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pulAddend )
{
uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulAddend;
*pulAddend += 1;
}
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
}
/*-----------------------------------------------------------*/
/**
* Atomic decrement
*
* @brief Atomically decrements the value of the specified pointer points to
*
* @param[in,out] pulAddend Pointer to memory location from where value is to be
* loaded and written back to.
*
* @return *pulAddend value before decrement.
*/
static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pulAddend )
{
uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulAddend;
*pulAddend -= 1;
}
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
}
/*----------------------------- Bitwise Logical ------------------------------*/
/**
* Atomic OR
*
* @brief Performs an atomic OR operation on the specified values.
*
* @param [in, out] pulDestination Pointer to memory location from where value is
* to be loaded and written back to.
* @param [in] ulValue Value to be ORed with *pulDestination.
*
* @return The original value of *pulDestination.
*/
static portFORCE_INLINE uint32_t Atomic_OR_u32( uint32_t volatile * pulDestination,
uint32_t ulValue )
{
uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulDestination;
*pulDestination |= ulValue;
}
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
}
/*-----------------------------------------------------------*/
/**
* Atomic AND
*
* @brief Performs an atomic AND operation on the specified values.
*
* @param [in, out] pulDestination Pointer to memory location from where value is
* to be loaded and written back to.
* @param [in] ulValue Value to be ANDed with *pulDestination.
*
* @return The original value of *pulDestination.
*/
static portFORCE_INLINE uint32_t Atomic_AND_u32( uint32_t volatile * pulDestination,
uint32_t ulValue )
{
uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulDestination;
*pulDestination &= ulValue;
}
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
}
/*-----------------------------------------------------------*/
/**
* Atomic NAND
*
* @brief Performs an atomic NAND operation on the specified values.
*
* @param [in, out] pulDestination Pointer to memory location from where value is
* to be loaded and written back to.
* @param [in] ulValue Value to be NANDed with *pulDestination.
*
* @return The original value of *pulDestination.
*/
static portFORCE_INLINE uint32_t Atomic_NAND_u32( uint32_t volatile * pulDestination,
uint32_t ulValue )
{
uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulDestination;
*pulDestination = ~( ulCurrent & ulValue );
}
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
}
/*-----------------------------------------------------------*/
/**
* Atomic XOR
*
* @brief Performs an atomic XOR operation on the specified values.
*
* @param [in, out] pulDestination Pointer to memory location from where value is
* to be loaded and written back to.
* @param [in] ulValue Value to be XORed with *pulDestination.
*
* @return The original value of *pulDestination.
*/
static portFORCE_INLINE uint32_t Atomic_XOR_u32( uint32_t volatile * pulDestination,
uint32_t ulValue )
{
uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulDestination;
*pulDestination ^= ulValue;
}
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
}
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* ATOMIC_H */
+751
View File
@@ -0,0 +1,751 @@
/*
* FreeRTOS Kernel V10.4.3
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef CO_ROUTINE_H
#define CO_ROUTINE_H
#ifndef INC_FREERTOS_H
#error "include FreeRTOS.h must appear in source files before include croutine.h"
#endif
#include "list.h"
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* Used to hide the implementation of the co-routine control block. The
* control block structure however has to be included in the header due to
* the macro implementation of the co-routine functionality. */
typedef void * CoRoutineHandle_t;
/* Defines the prototype to which co-routine functions must conform. */
typedef void (* crCOROUTINE_CODE)( CoRoutineHandle_t,
UBaseType_t );
typedef struct corCoRoutineControlBlock
{
crCOROUTINE_CODE pxCoRoutineFunction;
ListItem_t xGenericListItem; /*< List item used to place the CRCB in ready and blocked queues. */
ListItem_t xEventListItem; /*< List item used to place the CRCB in event lists. */
UBaseType_t uxPriority; /*< The priority of the co-routine in relation to other co-routines. */
UBaseType_t uxIndex; /*< Used to distinguish between co-routines when multiple co-routines use the same co-routine function. */
uint16_t uxState; /*< Used internally by the co-routine implementation. */
} CRCB_t; /* Co-routine control block. Note must be identical in size down to uxPriority with TCB_t. */
/**
* croutine. h
* <pre>
* BaseType_t xCoRoutineCreate(
* crCOROUTINE_CODE pxCoRoutineCode,
* UBaseType_t uxPriority,
* UBaseType_t uxIndex
* );
* </pre>
*
* Create a new co-routine and add it to the list of co-routines that are
* ready to run.
*
* @param pxCoRoutineCode Pointer to the co-routine function. Co-routine
* functions require special syntax - see the co-routine section of the WEB
* documentation for more information.
*
* @param uxPriority The priority with respect to other co-routines at which
* the co-routine will run.
*
* @param uxIndex Used to distinguish between different co-routines that
* execute the same function. See the example below and the co-routine section
* of the WEB documentation for further information.
*
* @return pdPASS if the co-routine was successfully created and added to a ready
* list, otherwise an error code defined with ProjDefs.h.
*
* Example usage:
* <pre>
* // Co-routine to be created.
* void vFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
* {
* // Variables in co-routines must be declared static if they must maintain value across a blocking call.
* // This may not be necessary for const variables.
* static const char cLedToFlash[ 2 ] = { 5, 6 };
* static const TickType_t uxFlashRates[ 2 ] = { 200, 400 };
*
* // Must start every co-routine with a call to crSTART();
* crSTART( xHandle );
*
* for( ;; )
* {
* // This co-routine just delays for a fixed period, then toggles
* // an LED. Two co-routines are created using this function, so
* // the uxIndex parameter is used to tell the co-routine which
* // LED to flash and how int32_t to delay. This assumes xQueue has
* // already been created.
* vParTestToggleLED( cLedToFlash[ uxIndex ] );
* crDELAY( xHandle, uxFlashRates[ uxIndex ] );
* }
*
* // Must end every co-routine with a call to crEND();
* crEND();
* }
*
* // Function that creates two co-routines.
* void vOtherFunction( void )
* {
* uint8_t ucParameterToPass;
* TaskHandle_t xHandle;
*
* // Create two co-routines at priority 0. The first is given index 0
* // so (from the code above) toggles LED 5 every 200 ticks. The second
* // is given index 1 so toggles LED 6 every 400 ticks.
* for( uxIndex = 0; uxIndex < 2; uxIndex++ )
* {
* xCoRoutineCreate( vFlashCoRoutine, 0, uxIndex );
* }
* }
* </pre>
* \defgroup xCoRoutineCreate xCoRoutineCreate
* \ingroup Tasks
*/
BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode,
UBaseType_t uxPriority,
UBaseType_t uxIndex );
/**
* croutine. h
* <pre>
* void vCoRoutineSchedule( void );
* </pre>
*
* Run a co-routine.
*
* vCoRoutineSchedule() executes the highest priority co-routine that is able
* to run. The co-routine will execute until it either blocks, yields or is
* preempted by a task. Co-routines execute cooperatively so one
* co-routine cannot be preempted by another, but can be preempted by a task.
*
* If an application comprises of both tasks and co-routines then
* vCoRoutineSchedule should be called from the idle task (in an idle task
* hook).
*
* Example usage:
* <pre>
* // This idle task hook will schedule a co-routine each time it is called.
* // The rest of the idle task will execute between co-routine calls.
* void vApplicationIdleHook( void )
* {
* vCoRoutineSchedule();
* }
*
* // Alternatively, if you do not require any other part of the idle task to
* // execute, the idle task hook can call vCoRoutineSchedule() within an
* // infinite loop.
* void vApplicationIdleHook( void )
* {
* for( ;; )
* {
* vCoRoutineSchedule();
* }
* }
* </pre>
* \defgroup vCoRoutineSchedule vCoRoutineSchedule
* \ingroup Tasks
*/
void vCoRoutineSchedule( void );
/**
* croutine. h
* <pre>
* crSTART( CoRoutineHandle_t xHandle );
* </pre>
*
* This macro MUST always be called at the start of a co-routine function.
*
* Example usage:
* <pre>
* // Co-routine to be created.
* void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
* {
* // Variables in co-routines must be declared static if they must maintain value across a blocking call.
* static int32_t ulAVariable;
*
* // Must start every co-routine with a call to crSTART();
* crSTART( xHandle );
*
* for( ;; )
* {
* // Co-routine functionality goes here.
* }
*
* // Must end every co-routine with a call to crEND();
* crEND();
* }
* </pre>
* \defgroup crSTART crSTART
* \ingroup Tasks
*/
#define crSTART( pxCRCB ) \
switch( ( ( CRCB_t * ) ( pxCRCB ) )->uxState ) { \
case 0:
/**
* croutine. h
* <pre>
* crEND();
* </pre>
*
* This macro MUST always be called at the end of a co-routine function.
*
* Example usage:
* <pre>
* // Co-routine to be created.
* void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
* {
* // Variables in co-routines must be declared static if they must maintain value across a blocking call.
* static int32_t ulAVariable;
*
* // Must start every co-routine with a call to crSTART();
* crSTART( xHandle );
*
* for( ;; )
* {
* // Co-routine functionality goes here.
* }
*
* // Must end every co-routine with a call to crEND();
* crEND();
* }
* </pre>
* \defgroup crSTART crSTART
* \ingroup Tasks
*/
#define crEND() }
/*
* These macros are intended for internal use by the co-routine implementation
* only. The macros should not be used directly by application writers.
*/
#define crSET_STATE0( xHandle ) \
( ( CRCB_t * ) ( xHandle ) )->uxState = ( __LINE__ * 2 ); return; \
case ( __LINE__ * 2 ):
#define crSET_STATE1( xHandle ) \
( ( CRCB_t * ) ( xHandle ) )->uxState = ( ( __LINE__ * 2 ) + 1 ); return; \
case ( ( __LINE__ * 2 ) + 1 ):
/**
* croutine. h
* <pre>
* crDELAY( CoRoutineHandle_t xHandle, TickType_t xTicksToDelay );
* </pre>
*
* Delay a co-routine for a fixed period of time.
*
* crDELAY can only be called from the co-routine function itself - not
* from within a function called by the co-routine function. This is because
* co-routines do not maintain their own stack.
*
* @param xHandle The handle of the co-routine to delay. This is the xHandle
* parameter of the co-routine function.
*
* @param xTickToDelay The number of ticks that the co-routine should delay
* for. The actual amount of time this equates to is defined by
* configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant portTICK_PERIOD_MS
* can be used to convert ticks to milliseconds.
*
* Example usage:
* <pre>
* // Co-routine to be created.
* void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
* {
* // Variables in co-routines must be declared static if they must maintain value across a blocking call.
* // This may not be necessary for const variables.
* // We are to delay for 200ms.
* static const xTickType xDelayTime = 200 / portTICK_PERIOD_MS;
*
* // Must start every co-routine with a call to crSTART();
* crSTART( xHandle );
*
* for( ;; )
* {
* // Delay for 200ms.
* crDELAY( xHandle, xDelayTime );
*
* // Do something here.
* }
*
* // Must end every co-routine with a call to crEND();
* crEND();
* }
* </pre>
* \defgroup crDELAY crDELAY
* \ingroup Tasks
*/
#define crDELAY( xHandle, xTicksToDelay ) \
if( ( xTicksToDelay ) > 0 ) \
{ \
vCoRoutineAddToDelayedList( ( xTicksToDelay ), NULL ); \
} \
crSET_STATE0( ( xHandle ) );
/**
* <pre>
* crQUEUE_SEND(
* CoRoutineHandle_t xHandle,
* QueueHandle_t pxQueue,
* void *pvItemToQueue,
* TickType_t xTicksToWait,
* BaseType_t *pxResult
* )
* </pre>
*
* The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
* equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
*
* crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
* xQueueSend() and xQueueReceive() can only be used from tasks.
*
* crQUEUE_SEND can only be called from the co-routine function itself - not
* from within a function called by the co-routine function. This is because
* co-routines do not maintain their own stack.
*
* See the co-routine section of the WEB documentation for information on
* passing data between tasks and co-routines and between ISR's and
* co-routines.
*
* @param xHandle The handle of the calling co-routine. This is the xHandle
* parameter of the co-routine function.
*
* @param pxQueue The handle of the queue on which the data will be posted.
* The handle is obtained as the return value when the queue is created using
* the xQueueCreate() API function.
*
* @param pvItemToQueue A pointer to the data being posted onto the queue.
* The number of bytes of each queued item is specified when the queue is
* created. This number of bytes is copied from pvItemToQueue into the queue
* itself.
*
* @param xTickToDelay The number of ticks that the co-routine should block
* to wait for space to become available on the queue, should space not be
* available immediately. The actual amount of time this equates to is defined
* by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant
* portTICK_PERIOD_MS can be used to convert ticks to milliseconds (see example
* below).
*
* @param pxResult The variable pointed to by pxResult will be set to pdPASS if
* data was successfully posted onto the queue, otherwise it will be set to an
* error defined within ProjDefs.h.
*
* Example usage:
* <pre>
* // Co-routine function that blocks for a fixed period then posts a number onto
* // a queue.
* static void prvCoRoutineFlashTask( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
* {
* // Variables in co-routines must be declared static if they must maintain value across a blocking call.
* static BaseType_t xNumberToPost = 0;
* static BaseType_t xResult;
*
* // Co-routines must begin with a call to crSTART().
* crSTART( xHandle );
*
* for( ;; )
* {
* // This assumes the queue has already been created.
* crQUEUE_SEND( xHandle, xCoRoutineQueue, &xNumberToPost, NO_DELAY, &xResult );
*
* if( xResult != pdPASS )
* {
* // The message was not posted!
* }
*
* // Increment the number to be posted onto the queue.
* xNumberToPost++;
*
* // Delay for 100 ticks.
* crDELAY( xHandle, 100 );
* }
*
* // Co-routines must end with a call to crEND().
* crEND();
* }
* </pre>
* \defgroup crQUEUE_SEND crQUEUE_SEND
* \ingroup Tasks
*/
#define crQUEUE_SEND( xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult ) \
{ \
*( pxResult ) = xQueueCRSend( ( pxQueue ), ( pvItemToQueue ), ( xTicksToWait ) ); \
if( *( pxResult ) == errQUEUE_BLOCKED ) \
{ \
crSET_STATE0( ( xHandle ) ); \
*pxResult = xQueueCRSend( ( pxQueue ), ( pvItemToQueue ), 0 ); \
} \
if( *pxResult == errQUEUE_YIELD ) \
{ \
crSET_STATE1( ( xHandle ) ); \
*pxResult = pdPASS; \
} \
}
/**
* croutine. h
* <pre>
* crQUEUE_RECEIVE(
* CoRoutineHandle_t xHandle,
* QueueHandle_t pxQueue,
* void *pvBuffer,
* TickType_t xTicksToWait,
* BaseType_t *pxResult
* )
* </pre>
*
* The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
* equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
*
* crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
* xQueueSend() and xQueueReceive() can only be used from tasks.
*
* crQUEUE_RECEIVE can only be called from the co-routine function itself - not
* from within a function called by the co-routine function. This is because
* co-routines do not maintain their own stack.
*
* See the co-routine section of the WEB documentation for information on
* passing data between tasks and co-routines and between ISR's and
* co-routines.
*
* @param xHandle The handle of the calling co-routine. This is the xHandle
* parameter of the co-routine function.
*
* @param pxQueue The handle of the queue from which the data will be received.
* The handle is obtained as the return value when the queue is created using
* the xQueueCreate() API function.
*
* @param pvBuffer The buffer into which the received item is to be copied.
* The number of bytes of each queued item is specified when the queue is
* created. This number of bytes is copied into pvBuffer.
*
* @param xTickToDelay The number of ticks that the co-routine should block
* to wait for data to become available from the queue, should data not be
* available immediately. The actual amount of time this equates to is defined
* by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant
* portTICK_PERIOD_MS can be used to convert ticks to milliseconds (see the
* crQUEUE_SEND example).
*
* @param pxResult The variable pointed to by pxResult will be set to pdPASS if
* data was successfully retrieved from the queue, otherwise it will be set to
* an error code as defined within ProjDefs.h.
*
* Example usage:
* <pre>
* // A co-routine receives the number of an LED to flash from a queue. It
* // blocks on the queue until the number is received.
* static void prvCoRoutineFlashWorkTask( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
* {
* // Variables in co-routines must be declared static if they must maintain value across a blocking call.
* static BaseType_t xResult;
* static UBaseType_t uxLEDToFlash;
*
* // All co-routines must start with a call to crSTART().
* crSTART( xHandle );
*
* for( ;; )
* {
* // Wait for data to become available on the queue.
* crQUEUE_RECEIVE( xHandle, xCoRoutineQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
*
* if( xResult == pdPASS )
* {
* // We received the LED to flash - flash it!
* vParTestToggleLED( uxLEDToFlash );
* }
* }
*
* crEND();
* }
* </pre>
* \defgroup crQUEUE_RECEIVE crQUEUE_RECEIVE
* \ingroup Tasks
*/
#define crQUEUE_RECEIVE( xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult ) \
{ \
*( pxResult ) = xQueueCRReceive( ( pxQueue ), ( pvBuffer ), ( xTicksToWait ) ); \
if( *( pxResult ) == errQUEUE_BLOCKED ) \
{ \
crSET_STATE0( ( xHandle ) ); \
*( pxResult ) = xQueueCRReceive( ( pxQueue ), ( pvBuffer ), 0 ); \
} \
if( *( pxResult ) == errQUEUE_YIELD ) \
{ \
crSET_STATE1( ( xHandle ) ); \
*( pxResult ) = pdPASS; \
} \
}
/**
* croutine. h
* <pre>
* crQUEUE_SEND_FROM_ISR(
* QueueHandle_t pxQueue,
* void *pvItemToQueue,
* BaseType_t xCoRoutinePreviouslyWoken
* )
* </pre>
*
* The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
* co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
* functions used by tasks.
*
* crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
* pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
* xQueueReceiveFromISR() can only be used to pass data between a task and and
* ISR.
*
* crQUEUE_SEND_FROM_ISR can only be called from an ISR to send data to a queue
* that is being used from within a co-routine.
*
* See the co-routine section of the WEB documentation for information on
* passing data between tasks and co-routines and between ISR's and
* co-routines.
*
* @param xQueue The handle to the queue on which the item is to be posted.
*
* @param pvItemToQueue A pointer to the item that is to be placed on the
* queue. The size of the items the queue will hold was defined when the
* queue was created, so this many bytes will be copied from pvItemToQueue
* into the queue storage area.
*
* @param xCoRoutinePreviouslyWoken This is included so an ISR can post onto
* the same queue multiple times from a single interrupt. The first call
* should always pass in pdFALSE. Subsequent calls should pass in
* the value returned from the previous call.
*
* @return pdTRUE if a co-routine was woken by posting onto the queue. This is
* used by the ISR to determine if a context switch may be required following
* the ISR.
*
* Example usage:
* <pre>
* // A co-routine that blocks on a queue waiting for characters to be received.
* static void vReceivingCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
* {
* char cRxedChar;
* BaseType_t xResult;
*
* // All co-routines must start with a call to crSTART().
* crSTART( xHandle );
*
* for( ;; )
* {
* // Wait for data to become available on the queue. This assumes the
* // queue xCommsRxQueue has already been created!
* crQUEUE_RECEIVE( xHandle, xCommsRxQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
*
* // Was a character received?
* if( xResult == pdPASS )
* {
* // Process the character here.
* }
* }
*
* // All co-routines must end with a call to crEND().
* crEND();
* }
*
* // An ISR that uses a queue to send characters received on a serial port to
* // a co-routine.
* void vUART_ISR( void )
* {
* char cRxedChar;
* BaseType_t xCRWokenByPost = pdFALSE;
*
* // We loop around reading characters until there are none left in the UART.
* while( UART_RX_REG_NOT_EMPTY() )
* {
* // Obtain the character from the UART.
* cRxedChar = UART_RX_REG;
*
* // Post the character onto a queue. xCRWokenByPost will be pdFALSE
* // the first time around the loop. If the post causes a co-routine
* // to be woken (unblocked) then xCRWokenByPost will be set to pdTRUE.
* // In this manner we can ensure that if more than one co-routine is
* // blocked on the queue only one is woken by this ISR no matter how
* // many characters are posted to the queue.
* xCRWokenByPost = crQUEUE_SEND_FROM_ISR( xCommsRxQueue, &cRxedChar, xCRWokenByPost );
* }
* }
* </pre>
* \defgroup crQUEUE_SEND_FROM_ISR crQUEUE_SEND_FROM_ISR
* \ingroup Tasks
*/
#define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) \
xQueueCRSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( xCoRoutinePreviouslyWoken ) )
/**
* croutine. h
* <pre>
* crQUEUE_SEND_FROM_ISR(
* QueueHandle_t pxQueue,
* void *pvBuffer,
* BaseType_t * pxCoRoutineWoken
* )
* </pre>
*
* The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
* co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
* functions used by tasks.
*
* crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
* pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
* xQueueReceiveFromISR() can only be used to pass data between a task and and
* ISR.
*
* crQUEUE_RECEIVE_FROM_ISR can only be called from an ISR to receive data
* from a queue that is being used from within a co-routine (a co-routine
* posted to the queue).
*
* See the co-routine section of the WEB documentation for information on
* passing data between tasks and co-routines and between ISR's and
* co-routines.
*
* @param xQueue The handle to the queue on which the item is to be posted.
*
* @param pvBuffer A pointer to a buffer into which the received item will be
* placed. The size of the items the queue will hold was defined when the
* queue was created, so this many bytes will be copied from the queue into
* pvBuffer.
*
* @param pxCoRoutineWoken A co-routine may be blocked waiting for space to become
* available on the queue. If crQUEUE_RECEIVE_FROM_ISR causes such a
* co-routine to unblock *pxCoRoutineWoken will get set to pdTRUE, otherwise
* *pxCoRoutineWoken will remain unchanged.
*
* @return pdTRUE an item was successfully received from the queue, otherwise
* pdFALSE.
*
* Example usage:
* <pre>
* // A co-routine that posts a character to a queue then blocks for a fixed
* // period. The character is incremented each time.
* static void vSendingCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
* {
* // cChar holds its value while this co-routine is blocked and must therefore
* // be declared static.
* static char cCharToTx = 'a';
* BaseType_t xResult;
*
* // All co-routines must start with a call to crSTART().
* crSTART( xHandle );
*
* for( ;; )
* {
* // Send the next character to the queue.
* crQUEUE_SEND( xHandle, xCoRoutineQueue, &cCharToTx, NO_DELAY, &xResult );
*
* if( xResult == pdPASS )
* {
* // The character was successfully posted to the queue.
* }
* else
* {
* // Could not post the character to the queue.
* }
*
* // Enable the UART Tx interrupt to cause an interrupt in this
* // hypothetical UART. The interrupt will obtain the character
* // from the queue and send it.
* ENABLE_RX_INTERRUPT();
*
* // Increment to the next character then block for a fixed period.
* // cCharToTx will maintain its value across the delay as it is
* // declared static.
* cCharToTx++;
* if( cCharToTx > 'x' )
* {
* cCharToTx = 'a';
* }
* crDELAY( 100 );
* }
*
* // All co-routines must end with a call to crEND().
* crEND();
* }
*
* // An ISR that uses a queue to receive characters to send on a UART.
* void vUART_ISR( void )
* {
* char cCharToTx;
* BaseType_t xCRWokenByPost = pdFALSE;
*
* while( UART_TX_REG_EMPTY() )
* {
* // Are there any characters in the queue waiting to be sent?
* // xCRWokenByPost will automatically be set to pdTRUE if a co-routine
* // is woken by the post - ensuring that only a single co-routine is
* // woken no matter how many times we go around this loop.
* if( crQUEUE_RECEIVE_FROM_ISR( pxQueue, &cCharToTx, &xCRWokenByPost ) )
* {
* SEND_CHARACTER( cCharToTx );
* }
* }
* }
* </pre>
* \defgroup crQUEUE_RECEIVE_FROM_ISR crQUEUE_RECEIVE_FROM_ISR
* \ingroup Tasks
*/
#define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) \
xQueueCRReceiveFromISR( ( pxQueue ), ( pvBuffer ), ( pxCoRoutineWoken ) )
/*
* This function is intended for internal use by the co-routine macros only.
* The macro nature of the co-routine implementation requires that the
* prototype appears here. The function should not be used by application
* writers.
*
* Removes the current co-routine from its ready list and places it in the
* appropriate delayed list.
*/
void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay,
List_t * pxEventList );
/*
* This function is intended for internal use by the queue implementation only.
* The function should not be used by application writers.
*
* Removes the highest priority co-routine from the event list and places it in
* the pending ready list.
*/
BaseType_t xCoRoutineRemoveFromEventList( const List_t * pxEventList );
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* CO_ROUTINE_H */
@@ -0,0 +1,279 @@
/*
* FreeRTOS Kernel V10.4.3
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef DEPRECATED_DEFINITIONS_H
#define DEPRECATED_DEFINITIONS_H
/* Each FreeRTOS port has a unique portmacro.h header file. Originally a
* pre-processor definition was used to ensure the pre-processor found the correct
* portmacro.h file for the port being used. That scheme was deprecated in favour
* of setting the compiler's include path such that it found the correct
* portmacro.h file - removing the need for the constant and allowing the
* portmacro.h file to be located anywhere in relation to the port being used. The
* definitions below remain in the code for backward compatibility only. New
* projects should not use them. */
#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT
#include "..\..\Source\portable\owatcom\16bitdos\pc\portmacro.h"
typedef void ( __interrupt __far * pxISR )();
#endif
#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT
#include "..\..\Source\portable\owatcom\16bitdos\flsh186\portmacro.h"
typedef void ( __interrupt __far * pxISR )();
#endif
#ifdef GCC_MEGA_AVR
#include "../portable/GCC/ATMega323/portmacro.h"
#endif
#ifdef IAR_MEGA_AVR
#include "../portable/IAR/ATMega323/portmacro.h"
#endif
#ifdef MPLAB_PIC24_PORT
#include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h"
#endif
#ifdef MPLAB_DSPIC_PORT
#include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h"
#endif
#ifdef MPLAB_PIC18F_PORT
#include "../../Source/portable/MPLAB/PIC18F/portmacro.h"
#endif
#ifdef MPLAB_PIC32MX_PORT
#include "../../Source/portable/MPLAB/PIC32MX/portmacro.h"
#endif
#ifdef _FEDPICC
#include "libFreeRTOS/Include/portmacro.h"
#endif
#ifdef SDCC_CYGNAL
#include "../../Source/portable/SDCC/Cygnal/portmacro.h"
#endif
#ifdef GCC_ARM7
#include "../../Source/portable/GCC/ARM7_LPC2000/portmacro.h"
#endif
#ifdef GCC_ARM7_ECLIPSE
#include "portmacro.h"
#endif
#ifdef ROWLEY_LPC23xx
#include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h"
#endif
#ifdef IAR_MSP430
#include "..\..\Source\portable\IAR\MSP430\portmacro.h"
#endif
#ifdef GCC_MSP430
#include "../../Source/portable/GCC/MSP430F449/portmacro.h"
#endif
#ifdef ROWLEY_MSP430
#include "../../Source/portable/Rowley/MSP430F449/portmacro.h"
#endif
#ifdef ARM7_LPC21xx_KEIL_RVDS
#include "..\..\Source\portable\RVDS\ARM7_LPC21xx\portmacro.h"
#endif
#ifdef SAM7_GCC
#include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h"
#endif
#ifdef SAM7_IAR
#include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h"
#endif
#ifdef SAM9XE_IAR
#include "..\..\Source\portable\IAR\AtmelSAM9XE\portmacro.h"
#endif
#ifdef LPC2000_IAR
#include "..\..\Source\portable\IAR\LPC2000\portmacro.h"
#endif
#ifdef STR71X_IAR
#include "..\..\Source\portable\IAR\STR71x\portmacro.h"
#endif
#ifdef STR75X_IAR
#include "..\..\Source\portable\IAR\STR75x\portmacro.h"
#endif
#ifdef STR75X_GCC
#include "..\..\Source\portable\GCC\STR75x\portmacro.h"
#endif
#ifdef STR91X_IAR
#include "..\..\Source\portable\IAR\STR91x\portmacro.h"
#endif
#ifdef GCC_H8S
#include "../../Source/portable/GCC/H8S2329/portmacro.h"
#endif
#ifdef GCC_AT91FR40008
#include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h"
#endif
#ifdef RVDS_ARMCM3_LM3S102
#include "../../Source/portable/RVDS/ARM_CM3/portmacro.h"
#endif
#ifdef GCC_ARMCM3_LM3S102
#include "../../Source/portable/GCC/ARM_CM3/portmacro.h"
#endif
#ifdef GCC_ARMCM3
#include "../../Source/portable/GCC/ARM_CM3/portmacro.h"
#endif
#ifdef IAR_ARM_CM3
#include "../../Source/portable/IAR/ARM_CM3/portmacro.h"
#endif
#ifdef IAR_ARMCM3_LM
#include "../../Source/portable/IAR/ARM_CM3/portmacro.h"
#endif
#ifdef HCS12_CODE_WARRIOR
#include "../../Source/portable/CodeWarrior/HCS12/portmacro.h"
#endif
#ifdef MICROBLAZE_GCC
#include "../../Source/portable/GCC/MicroBlaze/portmacro.h"
#endif
#ifdef TERN_EE
#include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h"
#endif
#ifdef GCC_HCS12
#include "../../Source/portable/GCC/HCS12/portmacro.h"
#endif
#ifdef GCC_MCF5235
#include "../../Source/portable/GCC/MCF5235/portmacro.h"
#endif
#ifdef COLDFIRE_V2_GCC
#include "../../../Source/portable/GCC/ColdFire_V2/portmacro.h"
#endif
#ifdef COLDFIRE_V2_CODEWARRIOR
#include "../../Source/portable/CodeWarrior/ColdFire_V2/portmacro.h"
#endif
#ifdef GCC_PPC405
#include "../../Source/portable/GCC/PPC405_Xilinx/portmacro.h"
#endif
#ifdef GCC_PPC440
#include "../../Source/portable/GCC/PPC440_Xilinx/portmacro.h"
#endif
#ifdef _16FX_SOFTUNE
#include "..\..\Source\portable\Softune\MB96340\portmacro.h"
#endif
#ifdef BCC_INDUSTRIAL_PC_PORT
/* A short file name has to be used in place of the normal
* FreeRTOSConfig.h when using the Borland compiler. */
#include "frconfig.h"
#include "..\portable\BCC\16BitDOS\PC\prtmacro.h"
typedef void ( __interrupt __far * pxISR )();
#endif
#ifdef BCC_FLASH_LITE_186_PORT
/* A short file name has to be used in place of the normal
* FreeRTOSConfig.h when using the Borland compiler. */
#include "frconfig.h"
#include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h"
typedef void ( __interrupt __far * pxISR )();
#endif
#ifdef __GNUC__
#ifdef __AVR32_AVR32A__
#include "portmacro.h"
#endif
#endif
#ifdef __ICCAVR32__
#ifdef __CORE__
#if __CORE__ == __AVR32A__
#include "portmacro.h"
#endif
#endif
#endif
#ifdef __91467D
#include "portmacro.h"
#endif
#ifdef __96340
#include "portmacro.h"
#endif
#ifdef __IAR_V850ES_Fx3__
#include "../../Source/portable/IAR/V850ES/portmacro.h"
#endif
#ifdef __IAR_V850ES_Jx3__
#include "../../Source/portable/IAR/V850ES/portmacro.h"
#endif
#ifdef __IAR_V850ES_Jx3_L__
#include "../../Source/portable/IAR/V850ES/portmacro.h"
#endif
#ifdef __IAR_V850ES_Jx2__
#include "../../Source/portable/IAR/V850ES/portmacro.h"
#endif
#ifdef __IAR_V850ES_Hx2__
#include "../../Source/portable/IAR/V850ES/portmacro.h"
#endif
#ifdef __IAR_78K0R_Kx3__
#include "../../Source/portable/IAR/78K0R/portmacro.h"
#endif
#ifdef __IAR_78K0R_Kx3L__
#include "../../Source/portable/IAR/78K0R/portmacro.h"
#endif
#endif /* DEPRECATED_DEFINITIONS_H */
+775
View File
@@ -0,0 +1,775 @@
/*
* FreeRTOS Kernel V10.4.3
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef EVENT_GROUPS_H
#define EVENT_GROUPS_H
#ifndef INC_FREERTOS_H
#error "include FreeRTOS.h" must appear in source files before "include event_groups.h"
#endif
/* FreeRTOS includes. */
#include "timers.h"
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/**
* An event group is a collection of bits to which an application can assign a
* meaning. For example, an application may create an event group to convey
* the status of various CAN bus related events in which bit 0 might mean "A CAN
* message has been received and is ready for processing", bit 1 might mean "The
* application has queued a message that is ready for sending onto the CAN
* network", and bit 2 might mean "It is time to send a SYNC message onto the
* CAN network" etc. A task can then test the bit values to see which events
* are active, and optionally enter the Blocked state to wait for a specified
* bit or a group of specified bits to be active. To continue the CAN bus
* example, a CAN controlling task can enter the Blocked state (and therefore
* not consume any processing time) until either bit 0, bit 1 or bit 2 are
* active, at which time the bit that was actually active would inform the task
* which action it had to take (process a received message, send a message, or
* send a SYNC).
*
* The event groups implementation contains intelligence to avoid race
* conditions that would otherwise occur were an application to use a simple
* variable for the same purpose. This is particularly important with respect
* to when a bit within an event group is to be cleared, and when bits have to
* be set and then tested atomically - as is the case where event groups are
* used to create a synchronisation point between multiple tasks (a
* 'rendezvous').
*
* \defgroup EventGroup
*/
/**
* event_groups.h
*
* Type by which event groups are referenced. For example, a call to
* xEventGroupCreate() returns an EventGroupHandle_t variable that can then
* be used as a parameter to other event group functions.
*
* \defgroup EventGroupHandle_t EventGroupHandle_t
* \ingroup EventGroup
*/
struct EventGroupDef_t;
typedef struct EventGroupDef_t * EventGroupHandle_t;
/*
* The type that holds event bits always matches TickType_t - therefore the
* number of bits it holds is set by configUSE_16_BIT_TICKS (16 bits if set to 1,
* 32 bits if set to 0.
*
* \defgroup EventBits_t EventBits_t
* \ingroup EventGroup
*/
typedef TickType_t EventBits_t;
/**
* event_groups.h
* <pre>
* EventGroupHandle_t xEventGroupCreate( void );
* </pre>
*
* Create a new event group.
*
* Internally, within the FreeRTOS implementation, event groups use a [small]
* block of memory, in which the event group's structure is stored. If an event
* groups is created using xEventGropuCreate() then the required memory is
* automatically dynamically allocated inside the xEventGroupCreate() function.
* (see https://www.FreeRTOS.org/a00111.html). If an event group is created
* using xEventGropuCreateStatic() then the application writer must instead
* provide the memory that will get used by the event group.
* xEventGroupCreateStatic() therefore allows an event group to be created
* without using any dynamic memory allocation.
*
* Although event groups are not related to ticks, for internal implementation
* reasons the number of bits available for use in an event group is dependent
* on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If
* configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit
* 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has
* 24 usable bits (bit 0 to bit 23). The EventBits_t type is used to store
* event bits within an event group.
*
* @return If the event group was created then a handle to the event group is
* returned. If there was insufficient FreeRTOS heap available to create the
* event group then NULL is returned. See https://www.FreeRTOS.org/a00111.html
*
* Example usage:
* <pre>
* // Declare a variable to hold the created event group.
* EventGroupHandle_t xCreatedEventGroup;
*
* // Attempt to create the event group.
* xCreatedEventGroup = xEventGroupCreate();
*
* // Was the event group created successfully?
* if( xCreatedEventGroup == NULL )
* {
* // The event group was not created because there was insufficient
* // FreeRTOS heap available.
* }
* else
* {
* // The event group was created.
* }
* </pre>
* \defgroup xEventGroupCreate xEventGroupCreate
* \ingroup EventGroup
*/
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
EventGroupHandle_t xEventGroupCreate( void ) PRIVILEGED_FUNCTION;
#endif
/**
* event_groups.h
* <pre>
* EventGroupHandle_t xEventGroupCreateStatic( EventGroupHandle_t * pxEventGroupBuffer );
* </pre>
*
* Create a new event group.
*
* Internally, within the FreeRTOS implementation, event groups use a [small]
* block of memory, in which the event group's structure is stored. If an event
* groups is created using xEventGropuCreate() then the required memory is
* automatically dynamically allocated inside the xEventGroupCreate() function.
* (see https://www.FreeRTOS.org/a00111.html). If an event group is created
* using xEventGropuCreateStatic() then the application writer must instead
* provide the memory that will get used by the event group.
* xEventGroupCreateStatic() therefore allows an event group to be created
* without using any dynamic memory allocation.
*
* Although event groups are not related to ticks, for internal implementation
* reasons the number of bits available for use in an event group is dependent
* on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If
* configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit
* 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has
* 24 usable bits (bit 0 to bit 23). The EventBits_t type is used to store
* event bits within an event group.
*
* @param pxEventGroupBuffer pxEventGroupBuffer must point to a variable of type
* StaticEventGroup_t, which will be then be used to hold the event group's data
* structures, removing the need for the memory to be allocated dynamically.
*
* @return If the event group was created then a handle to the event group is
* returned. If pxEventGroupBuffer was NULL then NULL is returned.
*
* Example usage:
* <pre>
* // StaticEventGroup_t is a publicly accessible structure that has the same
* // size and alignment requirements as the real event group structure. It is
* // provided as a mechanism for applications to know the size of the event
* // group (which is dependent on the architecture and configuration file
* // settings) without breaking the strict data hiding policy by exposing the
* // real event group internals. This StaticEventGroup_t variable is passed
* // into the xSemaphoreCreateEventGroupStatic() function and is used to store
* // the event group's data structures
* StaticEventGroup_t xEventGroupBuffer;
*
* // Create the event group without dynamically allocating any memory.
* xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
* </pre>
*/
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer ) PRIVILEGED_FUNCTION;
#endif
/**
* event_groups.h
* <pre>
* EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
* const EventBits_t uxBitsToWaitFor,
* const BaseType_t xClearOnExit,
* const BaseType_t xWaitForAllBits,
* const TickType_t xTicksToWait );
* </pre>
*
* [Potentially] block to wait for one or more bits to be set within a
* previously created event group.
*
* This function cannot be called from an interrupt.
*
* @param xEventGroup The event group in which the bits are being tested. The
* event group must have previously been created using a call to
* xEventGroupCreate().
*
* @param uxBitsToWaitFor A bitwise value that indicates the bit or bits to test
* inside the event group. For example, to wait for bit 0 and/or bit 2 set
* uxBitsToWaitFor to 0x05. To wait for bits 0 and/or bit 1 and/or bit 2 set
* uxBitsToWaitFor to 0x07. Etc.
*
* @param xClearOnExit If xClearOnExit is set to pdTRUE then any bits within
* uxBitsToWaitFor that are set within the event group will be cleared before
* xEventGroupWaitBits() returns if the wait condition was met (if the function
* returns for a reason other than a timeout). If xClearOnExit is set to
* pdFALSE then the bits set in the event group are not altered when the call to
* xEventGroupWaitBits() returns.
*
* @param xWaitForAllBits If xWaitForAllBits is set to pdTRUE then
* xEventGroupWaitBits() will return when either all the bits in uxBitsToWaitFor
* are set or the specified block time expires. If xWaitForAllBits is set to
* pdFALSE then xEventGroupWaitBits() will return when any one of the bits set
* in uxBitsToWaitFor is set or the specified block time expires. The block
* time is specified by the xTicksToWait parameter.
*
* @param xTicksToWait The maximum amount of time (specified in 'ticks') to wait
* for one/all (depending on the xWaitForAllBits value) of the bits specified by
* uxBitsToWaitFor to become set.
*
* @return The value of the event group at the time either the bits being waited
* for became set, or the block time expired. Test the return value to know
* which bits were set. If xEventGroupWaitBits() returned because its timeout
* expired then not all the bits being waited for will be set. If
* xEventGroupWaitBits() returned because the bits it was waiting for were set
* then the returned value is the event group value before any bits were
* automatically cleared in the case that xClearOnExit parameter was set to
* pdTRUE.
*
* Example usage:
* <pre>
#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
*
* void aFunction( EventGroupHandle_t xEventGroup )
* {
* EventBits_t uxBits;
* const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
*
* // Wait a maximum of 100ms for either bit 0 or bit 4 to be set within
* // the event group. Clear the bits before exiting.
* uxBits = xEventGroupWaitBits(
* xEventGroup, // The event group being tested.
* BIT_0 | BIT_4, // The bits within the event group to wait for.
* pdTRUE, // BIT_0 and BIT_4 should be cleared before returning.
* pdFALSE, // Don't wait for both bits, either bit will do.
* xTicksToWait ); // Wait a maximum of 100ms for either bit to be set.
*
* if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
* {
* // xEventGroupWaitBits() returned because both bits were set.
* }
* else if( ( uxBits & BIT_0 ) != 0 )
* {
* // xEventGroupWaitBits() returned because just BIT_0 was set.
* }
* else if( ( uxBits & BIT_4 ) != 0 )
* {
* // xEventGroupWaitBits() returned because just BIT_4 was set.
* }
* else
* {
* // xEventGroupWaitBits() returned because xTicksToWait ticks passed
* // without either BIT_0 or BIT_4 becoming set.
* }
* }
* </pre>
* \defgroup xEventGroupWaitBits xEventGroupWaitBits
* \ingroup EventGroup
*/
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
/**
* event_groups.h
* <pre>
* EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
* </pre>
*
* Clear bits within an event group. This function cannot be called from an
* interrupt.
*
* @param xEventGroup The event group in which the bits are to be cleared.
*
* @param uxBitsToClear A bitwise value that indicates the bit or bits to clear
* in the event group. For example, to clear bit 3 only, set uxBitsToClear to
* 0x08. To clear bit 3 and bit 0 set uxBitsToClear to 0x09.
*
* @return The value of the event group before the specified bits were cleared.
*
* Example usage:
* <pre>
#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
*
* void aFunction( EventGroupHandle_t xEventGroup )
* {
* EventBits_t uxBits;
*
* // Clear bit 0 and bit 4 in xEventGroup.
* uxBits = xEventGroupClearBits(
* xEventGroup, // The event group being updated.
* BIT_0 | BIT_4 );// The bits being cleared.
*
* if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
* {
* // Both bit 0 and bit 4 were set before xEventGroupClearBits() was
* // called. Both will now be clear (not set).
* }
* else if( ( uxBits & BIT_0 ) != 0 )
* {
* // Bit 0 was set before xEventGroupClearBits() was called. It will
* // now be clear.
* }
* else if( ( uxBits & BIT_4 ) != 0 )
* {
* // Bit 4 was set before xEventGroupClearBits() was called. It will
* // now be clear.
* }
* else
* {
* // Neither bit 0 nor bit 4 were set in the first place.
* }
* }
* </pre>
* \defgroup xEventGroupClearBits xEventGroupClearBits
* \ingroup EventGroup
*/
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION;
/**
* event_groups.h
* <pre>
* BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
* </pre>
*
* A version of xEventGroupClearBits() that can be called from an interrupt.
*
* Setting bits in an event group is not a deterministic operation because there
* are an unknown number of tasks that may be waiting for the bit or bits being
* set. FreeRTOS does not allow nondeterministic operations to be performed
* while interrupts are disabled, so protects event groups that are accessed
* from tasks by suspending the scheduler rather than disabling interrupts. As
* a result event groups cannot be accessed directly from an interrupt service
* routine. Therefore xEventGroupClearBitsFromISR() sends a message to the
* timer task to have the clear operation performed in the context of the timer
* task.
*
* @param xEventGroup The event group in which the bits are to be cleared.
*
* @param uxBitsToClear A bitwise value that indicates the bit or bits to clear.
* For example, to clear bit 3 only, set uxBitsToClear to 0x08. To clear bit 3
* and bit 0 set uxBitsToClear to 0x09.
*
* @return If the request to execute the function was posted successfully then
* pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned
* if the timer service queue was full.
*
* Example usage:
* <pre>
#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
*
* // An event group which it is assumed has already been created by a call to
* // xEventGroupCreate().
* EventGroupHandle_t xEventGroup;
*
* void anInterruptHandler( void )
* {
* // Clear bit 0 and bit 4 in xEventGroup.
* xResult = xEventGroupClearBitsFromISR(
* xEventGroup, // The event group being updated.
* BIT_0 | BIT_4 ); // The bits being set.
*
* if( xResult == pdPASS )
* {
* // The message was posted successfully.
* }
* }
* </pre>
* \defgroup xEventGroupClearBitsFromISR xEventGroupClearBitsFromISR
* \ingroup EventGroup
*/
#if ( configUSE_TRACE_FACILITY == 1 )
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION;
#else
#define xEventGroupClearBitsFromISR( xEventGroup, uxBitsToClear ) \
xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL )
#endif
/**
* event_groups.h
* <pre>
* EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
* </pre>
*
* Set bits within an event group.
* This function cannot be called from an interrupt. xEventGroupSetBitsFromISR()
* is a version that can be called from an interrupt.
*
* Setting bits in an event group will automatically unblock tasks that are
* blocked waiting for the bits.
*
* @param xEventGroup The event group in which the bits are to be set.
*
* @param uxBitsToSet A bitwise value that indicates the bit or bits to set.
* For example, to set bit 3 only, set uxBitsToSet to 0x08. To set bit 3
* and bit 0 set uxBitsToSet to 0x09.
*
* @return The value of the event group at the time the call to
* xEventGroupSetBits() returns. There are two reasons why the returned value
* might have the bits specified by the uxBitsToSet parameter cleared. First,
* if setting a bit results in a task that was waiting for the bit leaving the
* blocked state then it is possible the bit will be cleared automatically
* (see the xClearBitOnExit parameter of xEventGroupWaitBits()). Second, any
* unblocked (or otherwise Ready state) task that has a priority above that of
* the task that called xEventGroupSetBits() will execute and may change the
* event group value before the call to xEventGroupSetBits() returns.
*
* Example usage:
* <pre>
#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
*
* void aFunction( EventGroupHandle_t xEventGroup )
* {
* EventBits_t uxBits;
*
* // Set bit 0 and bit 4 in xEventGroup.
* uxBits = xEventGroupSetBits(
* xEventGroup, // The event group being updated.
* BIT_0 | BIT_4 );// The bits being set.
*
* if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
* {
* // Both bit 0 and bit 4 remained set when the function returned.
* }
* else if( ( uxBits & BIT_0 ) != 0 )
* {
* // Bit 0 remained set when the function returned, but bit 4 was
* // cleared. It might be that bit 4 was cleared automatically as a
* // task that was waiting for bit 4 was removed from the Blocked
* // state.
* }
* else if( ( uxBits & BIT_4 ) != 0 )
* {
* // Bit 4 remained set when the function returned, but bit 0 was
* // cleared. It might be that bit 0 was cleared automatically as a
* // task that was waiting for bit 0 was removed from the Blocked
* // state.
* }
* else
* {
* // Neither bit 0 nor bit 4 remained set. It might be that a task
* // was waiting for both of the bits to be set, and the bits were
* // cleared as the task left the Blocked state.
* }
* }
* </pre>
* \defgroup xEventGroupSetBits xEventGroupSetBits
* \ingroup EventGroup
*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet ) PRIVILEGED_FUNCTION;
/**
* event_groups.h
* <pre>
* BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken );
* </pre>
*
* A version of xEventGroupSetBits() that can be called from an interrupt.
*
* Setting bits in an event group is not a deterministic operation because there
* are an unknown number of tasks that may be waiting for the bit or bits being
* set. FreeRTOS does not allow nondeterministic operations to be performed in
* interrupts or from critical sections. Therefore xEventGroupSetBitsFromISR()
* sends a message to the timer task to have the set operation performed in the
* context of the timer task - where a scheduler lock is used in place of a
* critical section.
*
* @param xEventGroup The event group in which the bits are to be set.
*
* @param uxBitsToSet A bitwise value that indicates the bit or bits to set.
* For example, to set bit 3 only, set uxBitsToSet to 0x08. To set bit 3
* and bit 0 set uxBitsToSet to 0x09.
*
* @param pxHigherPriorityTaskWoken As mentioned above, calling this function
* will result in a message being sent to the timer daemon task. If the
* priority of the timer daemon task is higher than the priority of the
* currently running task (the task the interrupt interrupted) then
* *pxHigherPriorityTaskWoken will be set to pdTRUE by
* xEventGroupSetBitsFromISR(), indicating that a context switch should be
* requested before the interrupt exits. For that reason
* *pxHigherPriorityTaskWoken must be initialised to pdFALSE. See the
* example code below.
*
* @return If the request to execute the function was posted successfully then
* pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned
* if the timer service queue was full.
*
* Example usage:
* <pre>
#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
*
* // An event group which it is assumed has already been created by a call to
* // xEventGroupCreate().
* EventGroupHandle_t xEventGroup;
*
* void anInterruptHandler( void )
* {
* BaseType_t xHigherPriorityTaskWoken, xResult;
*
* // xHigherPriorityTaskWoken must be initialised to pdFALSE.
* xHigherPriorityTaskWoken = pdFALSE;
*
* // Set bit 0 and bit 4 in xEventGroup.
* xResult = xEventGroupSetBitsFromISR(
* xEventGroup, // The event group being updated.
* BIT_0 | BIT_4 // The bits being set.
* &xHigherPriorityTaskWoken );
*
* // Was the message posted successfully?
* if( xResult == pdPASS )
* {
* // If xHigherPriorityTaskWoken is now set to pdTRUE then a context
* // switch should be requested. The macro used is port specific and
* // will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() -
* // refer to the documentation page for the port being used.
* portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
* }
* }
* </pre>
* \defgroup xEventGroupSetBitsFromISR xEventGroupSetBitsFromISR
* \ingroup EventGroup
*/
#if ( configUSE_TRACE_FACILITY == 1 )
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
BaseType_t * pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
#else
#define xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken ) \
xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken )
#endif
/**
* event_groups.h
* <pre>
* EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
* const EventBits_t uxBitsToSet,
* const EventBits_t uxBitsToWaitFor,
* TickType_t xTicksToWait );
* </pre>
*
* Atomically set bits within an event group, then wait for a combination of
* bits to be set within the same event group. This functionality is typically
* used to synchronise multiple tasks, where each task has to wait for the other
* tasks to reach a synchronisation point before proceeding.
*
* This function cannot be used from an interrupt.
*
* The function will return before its block time expires if the bits specified
* by the uxBitsToWait parameter are set, or become set within that time. In
* this case all the bits specified by uxBitsToWait will be automatically
* cleared before the function returns.
*
* @param xEventGroup The event group in which the bits are being tested. The
* event group must have previously been created using a call to
* xEventGroupCreate().
*
* @param uxBitsToSet The bits to set in the event group before determining
* if, and possibly waiting for, all the bits specified by the uxBitsToWait
* parameter are set.
*
* @param uxBitsToWaitFor A bitwise value that indicates the bit or bits to test
* inside the event group. For example, to wait for bit 0 and bit 2 set
* uxBitsToWaitFor to 0x05. To wait for bits 0 and bit 1 and bit 2 set
* uxBitsToWaitFor to 0x07. Etc.
*
* @param xTicksToWait The maximum amount of time (specified in 'ticks') to wait
* for all of the bits specified by uxBitsToWaitFor to become set.
*
* @return The value of the event group at the time either the bits being waited
* for became set, or the block time expired. Test the return value to know
* which bits were set. If xEventGroupSync() returned because its timeout
* expired then not all the bits being waited for will be set. If
* xEventGroupSync() returned because all the bits it was waiting for were
* set then the returned value is the event group value before any bits were
* automatically cleared.
*
* Example usage:
* <pre>
* // Bits used by the three tasks.
#define TASK_0_BIT ( 1 << 0 )
#define TASK_1_BIT ( 1 << 1 )
#define TASK_2_BIT ( 1 << 2 )
*
#define ALL_SYNC_BITS ( TASK_0_BIT | TASK_1_BIT | TASK_2_BIT )
*
* // Use an event group to synchronise three tasks. It is assumed this event
* // group has already been created elsewhere.
* EventGroupHandle_t xEventBits;
*
* void vTask0( void *pvParameters )
* {
* EventBits_t uxReturn;
* TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
*
* for( ;; )
* {
* // Perform task functionality here.
*
* // Set bit 0 in the event flag to note this task has reached the
* // sync point. The other two tasks will set the other two bits defined
* // by ALL_SYNC_BITS. All three tasks have reached the synchronisation
* // point when all the ALL_SYNC_BITS are set. Wait a maximum of 100ms
* // for this to happen.
* uxReturn = xEventGroupSync( xEventBits, TASK_0_BIT, ALL_SYNC_BITS, xTicksToWait );
*
* if( ( uxReturn & ALL_SYNC_BITS ) == ALL_SYNC_BITS )
* {
* // All three tasks reached the synchronisation point before the call
* // to xEventGroupSync() timed out.
* }
* }
* }
*
* void vTask1( void *pvParameters )
* {
* for( ;; )
* {
* // Perform task functionality here.
*
* // Set bit 1 in the event flag to note this task has reached the
* // synchronisation point. The other two tasks will set the other two
* // bits defined by ALL_SYNC_BITS. All three tasks have reached the
* // synchronisation point when all the ALL_SYNC_BITS are set. Wait
* // indefinitely for this to happen.
* xEventGroupSync( xEventBits, TASK_1_BIT, ALL_SYNC_BITS, portMAX_DELAY );
*
* // xEventGroupSync() was called with an indefinite block time, so
* // this task will only reach here if the synchronisation was made by all
* // three tasks, so there is no need to test the return value.
* }
* }
*
* void vTask2( void *pvParameters )
* {
* for( ;; )
* {
* // Perform task functionality here.
*
* // Set bit 2 in the event flag to note this task has reached the
* // synchronisation point. The other two tasks will set the other two
* // bits defined by ALL_SYNC_BITS. All three tasks have reached the
* // synchronisation point when all the ALL_SYNC_BITS are set. Wait
* // indefinitely for this to happen.
* xEventGroupSync( xEventBits, TASK_2_BIT, ALL_SYNC_BITS, portMAX_DELAY );
*
* // xEventGroupSync() was called with an indefinite block time, so
* // this task will only reach here if the synchronisation was made by all
* // three tasks, so there is no need to test the return value.
* }
* }
*
* </pre>
* \defgroup xEventGroupSync xEventGroupSync
* \ingroup EventGroup
*/
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
const EventBits_t uxBitsToWaitFor,
TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
/**
* event_groups.h
* <pre>
* EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup );
* </pre>
*
* Returns the current value of the bits in an event group. This function
* cannot be used from an interrupt.
*
* @param xEventGroup The event group being queried.
*
* @return The event group bits at the time xEventGroupGetBits() was called.
*
* \defgroup xEventGroupGetBits xEventGroupGetBits
* \ingroup EventGroup
*/
#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 )
/**
* event_groups.h
* <pre>
* EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup );
* </pre>
*
* A version of xEventGroupGetBits() that can be called from an ISR.
*
* @param xEventGroup The event group being queried.
*
* @return The event group bits at the time xEventGroupGetBitsFromISR() was called.
*
* \defgroup xEventGroupGetBitsFromISR xEventGroupGetBitsFromISR
* \ingroup EventGroup
*/
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION;
/**
* event_groups.h
* <pre>
* void xEventGroupDelete( EventGroupHandle_t xEventGroup );
* </pre>
*
* Delete an event group that was previously created by a call to
* xEventGroupCreate(). Tasks that are blocked on the event group will be
* unblocked and obtain 0 as the event group's value.
*
* @param xEventGroup The event group being deleted.
*/
void vEventGroupDelete( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION;
/* For internal use only. */
void vEventGroupSetBitsCallback( void * pvEventGroup,
const uint32_t ulBitsToSet ) PRIVILEGED_FUNCTION;
void vEventGroupClearBitsCallback( void * pvEventGroup,
const uint32_t ulBitsToClear ) PRIVILEGED_FUNCTION;
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxEventGroupGetNumber( void * xEventGroup ) PRIVILEGED_FUNCTION;
void vEventGroupSetNumber( void * xEventGroup,
UBaseType_t uxEventGroupNumber ) PRIVILEGED_FUNCTION;
#endif
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* EVENT_GROUPS_H */
+417
View File
@@ -0,0 +1,417 @@
/*
* FreeRTOS Kernel V10.4.3
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* This is the list implementation used by the scheduler. While it is tailored
* heavily for the schedulers needs, it is also available for use by
* application code.
*
* list_ts can only store pointers to list_item_ts. Each ListItem_t contains a
* numeric value (xItemValue). Most of the time the lists are sorted in
* descending item value order.
*
* Lists are created already containing one list item. The value of this
* item is the maximum possible that can be stored, it is therefore always at
* the end of the list and acts as a marker. The list member pxHead always
* points to this marker - even though it is at the tail of the list. This
* is because the tail contains a wrap back pointer to the true head of
* the list.
*
* In addition to it's value, each list item contains a pointer to the next
* item in the list (pxNext), a pointer to the list it is in (pxContainer)
* and a pointer to back to the object that contains it. These later two
* pointers are included for efficiency of list manipulation. There is
* effectively a two way link between the object containing the list item and
* the list item itself.
*
*
* \page ListIntroduction List Implementation
* \ingroup FreeRTOSIntro
*/
#ifndef LIST_H
#define LIST_H
#ifndef INC_FREERTOS_H
#error "FreeRTOS.h must be included before list.h"
#endif
/*
* The list structure members are modified from within interrupts, and therefore
* by rights should be declared volatile. However, they are only modified in a
* functionally atomic way (within critical sections of with the scheduler
* suspended) and are either passed by reference into a function or indexed via
* a volatile variable. Therefore, in all use cases tested so far, the volatile
* qualifier can be omitted in order to provide a moderate performance
* improvement without adversely affecting functional behaviour. The assembly
* instructions generated by the IAR, ARM and GCC compilers when the respective
* compiler's options were set for maximum optimisation has been inspected and
* deemed to be as intended. That said, as compiler technology advances, and
* especially if aggressive cross module optimisation is used (a use case that
* has not been exercised to any great extend) then it is feasible that the
* volatile qualifier will be needed for correct optimisation. It is expected
* that a compiler removing essential code because, without the volatile
* qualifier on the list structure members and with aggressive cross module
* optimisation, the compiler deemed the code unnecessary will result in
* complete and obvious failure of the scheduler. If this is ever experienced
* then the volatile qualifier can be inserted in the relevant places within the
* list structures by simply defining configLIST_VOLATILE to volatile in
* FreeRTOSConfig.h (as per the example at the bottom of this comment block).
* If configLIST_VOLATILE is not defined then the preprocessor directives below
* will simply #define configLIST_VOLATILE away completely.
*
* To use volatile list structure members then add the following line to
* FreeRTOSConfig.h (without the quotes):
* "#define configLIST_VOLATILE volatile"
*/
#ifndef configLIST_VOLATILE
#define configLIST_VOLATILE
#endif /* configSUPPORT_CROSS_MODULE_OPTIMISATION */
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* Macros that can be used to place known values within the list structures,
* then check that the known values do not get corrupted during the execution of
* the application. These may catch the list data structures being overwritten in
* memory. They will not catch data errors caused by incorrect configuration or
* use of FreeRTOS.*/
#if ( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
/* Define the macros to do nothing. */
#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
#define listFIRST_LIST_INTEGRITY_CHECK_VALUE
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )
#define listTEST_LIST_ITEM_INTEGRITY( pxItem )
#define listTEST_LIST_INTEGRITY( pxList )
#else /* if ( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 ) */
/* Define macros that add new members into the list structures. */
#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue1;
#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue2;
#define listFIRST_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue1;
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue2;
/* Define macros that set the new structure members to known values. */
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ) ( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ) ( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
/* Define macros that will assert if one of the structure members does not
* contain its expected value. */
#define listTEST_LIST_ITEM_INTEGRITY( pxItem ) configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
#define listTEST_LIST_INTEGRITY( pxList ) configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
#endif /* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES */
/*
* Definition of the only type of object that a list can contain.
*/
struct xLIST;
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */
void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */
struct xLIST * configLIST_VOLATILE pxContainer; /*< Pointer to the list in which this list item is placed (if any). */
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
};
typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */
struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE TickType_t xItemValue;
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
/*
* Definition of the type of queue used by the scheduler.
*/
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
volatile UBaseType_t uxNumberOfItems;
ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
} List_t;
/*
* Access macro to set the owner of a list item. The owner of a list item
* is the object (usually a TCB) that contains the list item.
*
* \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
* \ingroup LinkedList
*/
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
/*
* Access macro to get the owner of a list item. The owner of a list item
* is the object (usually a TCB) that contains the list item.
*
* \page listGET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
* \ingroup LinkedList
*/
#define listGET_LIST_ITEM_OWNER( pxListItem ) ( ( pxListItem )->pvOwner )
/*
* Access macro to set the value of the list item. In most cases the value is
* used to sort the list in descending order.
*
* \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE
* \ingroup LinkedList
*/
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) )
/*
* Access macro to retrieve the value of the list item. The value can
* represent anything - for example the priority of a task, or the time at
* which a task should be unblocked.
*
* \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
* \ingroup LinkedList
*/
#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue )
/*
* Access macro to retrieve the value of the list item at the head of a given
* list.
*
* \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
* \ingroup LinkedList
*/
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
/*
* Return the list item at the head of the list.
*
* \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY
* \ingroup LinkedList
*/
#define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext )
/*
* Return the next list item.
*
* \page listGET_NEXT listGET_NEXT
* \ingroup LinkedList
*/
#define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext )
/*
* Return the list item that marks the end of the list
*
* \page listGET_END_MARKER listGET_END_MARKER
* \ingroup LinkedList
*/
#define listGET_END_MARKER( pxList ) ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
/*
* Access macro to determine if a list contains any items. The macro will
* only have the value true if the list is empty.
*
* \page listLIST_IS_EMPTY listLIST_IS_EMPTY
* \ingroup LinkedList
*/
#define listLIST_IS_EMPTY( pxList ) ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
/*
* Access macro to return the number of items in the list.
*/
#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems )
/*
* Access function to obtain the owner of the next entry in a list.
*
* The list member pxIndex is used to walk through a list. Calling
* listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list
* and returns that entry's pxOwner parameter. Using multiple calls to this
* function it is therefore possible to move through every item contained in
* a list.
*
* The pxOwner parameter of a list item is a pointer to the object that owns
* the list item. In the scheduler this is normally a task control block.
* The pxOwner parameter effectively creates a two way link between the list
* item and its owner.
*
* @param pxTCB pxTCB is set to the address of the owner of the next list item.
* @param pxList The list from which the next item owner is to be returned.
*
* \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY
* \ingroup LinkedList
*/
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \
{ \
List_t * const pxConstList = ( pxList ); \
/* Increment the index to the next item and return the item, ensuring */ \
/* we don't return the marker used at the end of the list. */ \
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \
{ \
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
} \
( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \
}
/*
* Access function to obtain the owner of the first entry in a list. Lists
* are normally sorted in ascending item value order.
*
* This function returns the pxOwner member of the first item in the list.
* The pxOwner parameter of a list item is a pointer to the object that owns
* the list item. In the scheduler this is normally a task control block.
* The pxOwner parameter effectively creates a two way link between the list
* item and its owner.
*
* @param pxList The list from which the owner of the head item is to be
* returned.
*
* \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY
* \ingroup LinkedList
*/
#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( ( &( ( pxList )->xListEnd ) )->pxNext->pvOwner )
/*
* Check to see if a list item is within a list. The list item maintains a
* "container" pointer that points to the list it is in. All this macro does
* is check to see if the container and the list match.
*
* @param pxList The list we want to know if the list item is within.
* @param pxListItem The list item we want to know if is in the list.
* @return pdTRUE if the list item is in the list, otherwise pdFALSE.
*/
#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( ( pxListItem )->pxContainer == ( pxList ) ) ? ( pdTRUE ) : ( pdFALSE ) )
/*
* Return the list a list item is contained within (referenced from).
*
* @param pxListItem The list item being queried.
* @return A pointer to the List_t object that references the pxListItem
*/
#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pxContainer )
/*
* This provides a crude means of knowing if a list has been initialised, as
* pxList->xListEnd.xItemValue is set to portMAX_DELAY by the vListInitialise()
* function.
*/
#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )
/*
* Must be called before a list is used! This initialises all the members
* of the list structure and inserts the xListEnd item into the list as a
* marker to the back of the list.
*
* @param pxList Pointer to the list being initialised.
*
* \page vListInitialise vListInitialise
* \ingroup LinkedList
*/
void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION;
/*
* Must be called before a list item is used. This sets the list container to
* null so the item does not think that it is already contained in a list.
*
* @param pxItem Pointer to the list item being initialised.
*
* \page vListInitialiseItem vListInitialiseItem
* \ingroup LinkedList
*/
void vListInitialiseItem( ListItem_t * const pxItem ) PRIVILEGED_FUNCTION;
/*
* Insert a list item into a list. The item will be inserted into the list in
* a position determined by its item value (descending item value order).
*
* @param pxList The list into which the item is to be inserted.
*
* @param pxNewListItem The item that is to be placed in the list.
*
* \page vListInsert vListInsert
* \ingroup LinkedList
*/
void vListInsert( List_t * const pxList,
ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;
/*
* Insert a list item into a list. The item will be inserted in a position
* such that it will be the last item within the list returned by multiple
* calls to listGET_OWNER_OF_NEXT_ENTRY.
*
* The list member pxIndex is used to walk through a list. Calling
* listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list.
* Placing an item in a list using vListInsertEnd effectively places the item
* in the list position pointed to by pxIndex. This means that every other
* item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before
* the pxIndex parameter again points to the item being inserted.
*
* @param pxList The list into which the item is to be inserted.
*
* @param pxNewListItem The list item to be inserted into the list.
*
* \page vListInsertEnd vListInsertEnd
* \ingroup LinkedList
*/
void vListInsertEnd( List_t * const pxList,
ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;
/*
* Remove an item from a list. The list item has a pointer to the list that
* it is in, so only the list item need be passed into the function.
*
* @param uxListRemove The item to be removed. The item will remove itself from
* the list pointed to by it's pxContainer parameter.
*
* @return The number of items that remain in the list after the list item has
* been removed.
*
* \page uxListRemove uxListRemove
* \ingroup LinkedList
*/
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) PRIVILEGED_FUNCTION;
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* ifndef LIST_H */
@@ -0,0 +1,821 @@
/*
* FreeRTOS Kernel V10.4.3
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* Message buffers build functionality on top of FreeRTOS stream buffers.
* Whereas stream buffers are used to send a continuous stream of data from one
* task or interrupt to another, message buffers are used to send variable
* length discrete messages from one task or interrupt to another. Their
* implementation is light weight, making them particularly suited for interrupt
* to task and core to core communication scenarios.
*
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
* implementation (so also the message buffer implementation, as message buffers
* are built on top of stream buffers) assumes there is only one task or
* interrupt that will write to the buffer (the writer), and only one task or
* interrupt that will read from the buffer (the reader). It is safe for the
* writer and reader to be different tasks or interrupts, but, unlike other
* FreeRTOS objects, it is not safe to have multiple different writers or
* multiple different readers. If there are to be multiple different writers
* then the application writer must place each call to a writing API function
* (such as xMessageBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function
* (such as xMessageBufferRead()) inside a critical section and set the receive
* timeout to 0.
*
* Message buffers hold variable length messages. To enable that, when a
* message is written to the message buffer an additional sizeof( size_t ) bytes
* are also written to store the message's length (that happens internally, with
* the API function). sizeof( size_t ) is typically 4 bytes on a 32-bit
* architecture, so writing a 10 byte message to a message buffer on a 32-bit
* architecture will actually reduce the available space in the message buffer
* by 14 bytes (10 byte are used by the message, and 4 bytes to hold the length
* of the message).
*/
#ifndef FREERTOS_MESSAGE_BUFFER_H
#define FREERTOS_MESSAGE_BUFFER_H
#ifndef INC_FREERTOS_H
#error "include FreeRTOS.h must appear in source files before include message_buffer.h"
#endif
/* Message buffers are built onto of stream buffers. */
#include "stream_buffer.h"
/* *INDENT-OFF* */
#if defined( __cplusplus )
extern "C" {
#endif
/* *INDENT-ON* */
/**
* Type by which message buffers are referenced. For example, a call to
* xMessageBufferCreate() returns an MessageBufferHandle_t variable that can
* then be used as a parameter to xMessageBufferSend(), xMessageBufferReceive(),
* etc.
*/
typedef void * MessageBufferHandle_t;
/*-----------------------------------------------------------*/
/**
* message_buffer.h
*
* <pre>
* MessageBufferHandle_t xMessageBufferCreate( size_t xBufferSizeBytes );
* </pre>
*
* Creates a new message buffer using dynamically allocated memory. See
* xMessageBufferCreateStatic() for a version that uses statically allocated
* memory (memory that is allocated at compile time).
*
* configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 or left undefined in
* FreeRTOSConfig.h for xMessageBufferCreate() to be available.
*
* @param xBufferSizeBytes The total number of bytes (not messages) the message
* buffer will be able to hold at any one time. When a message is written to
* the message buffer an additional sizeof( size_t ) bytes are also written to
* store the message's length. sizeof( size_t ) is typically 4 bytes on a
* 32-bit architecture, so on most 32-bit architectures a 10 byte message will
* take up 14 bytes of message buffer space.
*
* @return If NULL is returned, then the message buffer cannot be created
* because there is insufficient heap memory available for FreeRTOS to allocate
* the message buffer data structures and storage area. A non-NULL value being
* returned indicates that the message buffer has been created successfully -
* the returned value should be stored as the handle to the created message
* buffer.
*
* Example use:
* <pre>
*
* void vAFunction( void )
* {
* MessageBufferHandle_t xMessageBuffer;
* const size_t xMessageBufferSizeBytes = 100;
*
* // Create a message buffer that can hold 100 bytes. The memory used to hold
* // both the message buffer structure and the messages themselves is allocated
* // dynamically. Each message added to the buffer consumes an additional 4
* // bytes which are used to hold the lengh of the message.
* xMessageBuffer = xMessageBufferCreate( xMessageBufferSizeBytes );
*
* if( xMessageBuffer == NULL )
* {
* // There was not enough heap memory space available to create the
* // message buffer.
* }
* else
* {
* // The message buffer was created successfully and can now be used.
* }
*
* </pre>
* \defgroup xMessageBufferCreate xMessageBufferCreate
* \ingroup MessageBufferManagement
*/
#define xMessageBufferCreate( xBufferSizeBytes ) \
( MessageBufferHandle_t ) xStreamBufferGenericCreate( xBufferSizeBytes, ( size_t ) 0, pdTRUE )
/**
* message_buffer.h
*
* <pre>
* MessageBufferHandle_t xMessageBufferCreateStatic( size_t xBufferSizeBytes,
* uint8_t *pucMessageBufferStorageArea,
* StaticMessageBuffer_t *pxStaticMessageBuffer );
* </pre>
* Creates a new message buffer using statically allocated memory. See
* xMessageBufferCreate() for a version that uses dynamically allocated memory.
*
* @param xBufferSizeBytes The size, in bytes, of the buffer pointed to by the
* pucMessageBufferStorageArea parameter. When a message is written to the
* message buffer an additional sizeof( size_t ) bytes are also written to store
* the message's length. sizeof( size_t ) is typically 4 bytes on a 32-bit
* architecture, so on most 32-bit architecture a 10 byte message will take up
* 14 bytes of message buffer space. The maximum number of bytes that can be
* stored in the message buffer is actually (xBufferSizeBytes - 1).
*
* @param pucMessageBufferStorageArea Must point to a uint8_t array that is at
* least xBufferSizeBytes + 1 big. This is the array to which messages are
* copied when they are written to the message buffer.
*
* @param pxStaticMessageBuffer Must point to a variable of type
* StaticMessageBuffer_t, which will be used to hold the message buffer's data
* structure.
*
* @return If the message buffer is created successfully then a handle to the
* created message buffer is returned. If either pucMessageBufferStorageArea or
* pxStaticmessageBuffer are NULL then NULL is returned.
*
* Example use:
* <pre>
*
* // Used to dimension the array used to hold the messages. The available space
* // will actually be one less than this, so 999.
#define STORAGE_SIZE_BYTES 1000
*
* // Defines the memory that will actually hold the messages within the message
* // buffer.
* static uint8_t ucStorageBuffer[ STORAGE_SIZE_BYTES ];
*
* // The variable used to hold the message buffer structure.
* StaticMessageBuffer_t xMessageBufferStruct;
*
* void MyFunction( void )
* {
* MessageBufferHandle_t xMessageBuffer;
*
* xMessageBuffer = xMessageBufferCreateStatic( sizeof( ucBufferStorage ),
* ucBufferStorage,
* &xMessageBufferStruct );
*
* // As neither the pucMessageBufferStorageArea or pxStaticMessageBuffer
* // parameters were NULL, xMessageBuffer will not be NULL, and can be used to
* // reference the created message buffer in other message buffer API calls.
*
* // Other code that uses the message buffer can go here.
* }
*
* </pre>
* \defgroup xMessageBufferCreateStatic xMessageBufferCreateStatic
* \ingroup MessageBufferManagement
*/
#define xMessageBufferCreateStatic( xBufferSizeBytes, pucMessageBufferStorageArea, pxStaticMessageBuffer ) \
( MessageBufferHandle_t ) xStreamBufferGenericCreateStatic( xBufferSizeBytes, 0, pdTRUE, pucMessageBufferStorageArea, pxStaticMessageBuffer )
/**
* message_buffer.h
*
* <pre>
* size_t xMessageBufferSend( MessageBufferHandle_t xMessageBuffer,
* const void *pvTxData,
* size_t xDataLengthBytes,
* TickType_t xTicksToWait );
* </pre>
*
* Sends a discrete message to the message buffer. The message can be any
* length that fits within the buffer's free space, and is copied into the
* buffer.
*
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
* implementation (so also the message buffer implementation, as message buffers
* are built on top of stream buffers) assumes there is only one task or
* interrupt that will write to the buffer (the writer), and only one task or
* interrupt that will read from the buffer (the reader). It is safe for the
* writer and reader to be different tasks or interrupts, but, unlike other
* FreeRTOS objects, it is not safe to have multiple different writers or
* multiple different readers. If there are to be multiple different writers
* then the application writer must place each call to a writing API function
* (such as xMessageBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function
* (such as xMessageBufferRead()) inside a critical section and set the receive
* block time to 0.
*
* Use xMessageBufferSend() to write to a message buffer from a task. Use
* xMessageBufferSendFromISR() to write to a message buffer from an interrupt
* service routine (ISR).
*
* @param xMessageBuffer The handle of the message buffer to which a message is
* being sent.
*
* @param pvTxData A pointer to the message that is to be copied into the
* message buffer.
*
* @param xDataLengthBytes The length of the message. That is, the number of
* bytes to copy from pvTxData into the message buffer. When a message is
* written to the message buffer an additional sizeof( size_t ) bytes are also
* written to store the message's length. sizeof( size_t ) is typically 4 bytes
* on a 32-bit architecture, so on most 32-bit architecture setting
* xDataLengthBytes to 20 will reduce the free space in the message buffer by 24
* bytes (20 bytes of message data and 4 bytes to hold the message length).
*
* @param xTicksToWait The maximum amount of time the calling task should remain
* in the Blocked state to wait for enough space to become available in the
* message buffer, should the message buffer have insufficient space when
* xMessageBufferSend() is called. The calling task will never block if
* xTicksToWait is zero. The block time is specified in tick periods, so the
* absolute time it represents is dependent on the tick frequency. The macro
* pdMS_TO_TICKS() can be used to convert a time specified in milliseconds into
* a time specified in ticks. Setting xTicksToWait to portMAX_DELAY will cause
* the task to wait indefinitely (without timing out), provided
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. Tasks do not use any
* CPU time when they are in the Blocked state.
*
* @return The number of bytes written to the message buffer. If the call to
* xMessageBufferSend() times out before there was enough space to write the
* message into the message buffer then zero is returned. If the call did not
* time out then xDataLengthBytes is returned.
*
* Example use:
* <pre>
* void vAFunction( MessageBufferHandle_t xMessageBuffer )
* {
* size_t xBytesSent;
* uint8_t ucArrayToSend[] = { 0, 1, 2, 3 };
* char *pcStringToSend = "String to send";
* const TickType_t x100ms = pdMS_TO_TICKS( 100 );
*
* // Send an array to the message buffer, blocking for a maximum of 100ms to
* // wait for enough space to be available in the message buffer.
* xBytesSent = xMessageBufferSend( xMessageBuffer, ( void * ) ucArrayToSend, sizeof( ucArrayToSend ), x100ms );
*
* if( xBytesSent != sizeof( ucArrayToSend ) )
* {
* // The call to xMessageBufferSend() times out before there was enough
* // space in the buffer for the data to be written.
* }
*
* // Send the string to the message buffer. Return immediately if there is
* // not enough space in the buffer.
* xBytesSent = xMessageBufferSend( xMessageBuffer, ( void * ) pcStringToSend, strlen( pcStringToSend ), 0 );
*
* if( xBytesSent != strlen( pcStringToSend ) )
* {
* // The string could not be added to the message buffer because there was
* // not enough free space in the buffer.
* }
* }
* </pre>
* \defgroup xMessageBufferSend xMessageBufferSend
* \ingroup MessageBufferManagement
*/
#define xMessageBufferSend( xMessageBuffer, pvTxData, xDataLengthBytes, xTicksToWait ) \
xStreamBufferSend( ( StreamBufferHandle_t ) xMessageBuffer, pvTxData, xDataLengthBytes, xTicksToWait )
/**
* message_buffer.h
*
* <pre>
* size_t xMessageBufferSendFromISR( MessageBufferHandle_t xMessageBuffer,
* const void *pvTxData,
* size_t xDataLengthBytes,
* BaseType_t *pxHigherPriorityTaskWoken );
* </pre>
*
* Interrupt safe version of the API function that sends a discrete message to
* the message buffer. The message can be any length that fits within the
* buffer's free space, and is copied into the buffer.
*
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
* implementation (so also the message buffer implementation, as message buffers
* are built on top of stream buffers) assumes there is only one task or
* interrupt that will write to the buffer (the writer), and only one task or
* interrupt that will read from the buffer (the reader). It is safe for the
* writer and reader to be different tasks or interrupts, but, unlike other
* FreeRTOS objects, it is not safe to have multiple different writers or
* multiple different readers. If there are to be multiple different writers
* then the application writer must place each call to a writing API function
* (such as xMessageBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function
* (such as xMessageBufferRead()) inside a critical section and set the receive
* block time to 0.
*
* Use xMessageBufferSend() to write to a message buffer from a task. Use
* xMessageBufferSendFromISR() to write to a message buffer from an interrupt
* service routine (ISR).
*
* @param xMessageBuffer The handle of the message buffer to which a message is
* being sent.
*
* @param pvTxData A pointer to the message that is to be copied into the
* message buffer.
*
* @param xDataLengthBytes The length of the message. That is, the number of
* bytes to copy from pvTxData into the message buffer. When a message is
* written to the message buffer an additional sizeof( size_t ) bytes are also
* written to store the message's length. sizeof( size_t ) is typically 4 bytes
* on a 32-bit architecture, so on most 32-bit architecture setting
* xDataLengthBytes to 20 will reduce the free space in the message buffer by 24
* bytes (20 bytes of message data and 4 bytes to hold the message length).
*
* @param pxHigherPriorityTaskWoken It is possible that a message buffer will
* have a task blocked on it waiting for data. Calling
* xMessageBufferSendFromISR() can make data available, and so cause a task that
* was waiting for data to leave the Blocked state. If calling
* xMessageBufferSendFromISR() causes a task to leave the Blocked state, and the
* unblocked task has a priority higher than the currently executing task (the
* task that was interrupted), then, internally, xMessageBufferSendFromISR()
* will set *pxHigherPriorityTaskWoken to pdTRUE. If
* xMessageBufferSendFromISR() sets this value to pdTRUE, then normally a
* context switch should be performed before the interrupt is exited. This will
* ensure that the interrupt returns directly to the highest priority Ready
* state task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it
* is passed into the function. See the code example below for an example.
*
* @return The number of bytes actually written to the message buffer. If the
* message buffer didn't have enough free space for the message to be stored
* then 0 is returned, otherwise xDataLengthBytes is returned.
*
* Example use:
* <pre>
* // A message buffer that has already been created.
* MessageBufferHandle_t xMessageBuffer;
*
* void vAnInterruptServiceRoutine( void )
* {
* size_t xBytesSent;
* char *pcStringToSend = "String to send";
* BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
*
* // Attempt to send the string to the message buffer.
* xBytesSent = xMessageBufferSendFromISR( xMessageBuffer,
* ( void * ) pcStringToSend,
* strlen( pcStringToSend ),
* &xHigherPriorityTaskWoken );
*
* if( xBytesSent != strlen( pcStringToSend ) )
* {
* // The string could not be added to the message buffer because there was
* // not enough free space in the buffer.
* }
*
* // If xHigherPriorityTaskWoken was set to pdTRUE inside
* // xMessageBufferSendFromISR() then a task that has a priority above the
* // priority of the currently executing task was unblocked and a context
* // switch should be performed to ensure the ISR returns to the unblocked
* // task. In most FreeRTOS ports this is done by simply passing
* // xHigherPriorityTaskWoken into portYIELD_FROM_ISR(), which will test the
* // variables value, and perform the context switch if necessary. Check the
* // documentation for the port in use for port specific instructions.
* portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
* }
* </pre>
* \defgroup xMessageBufferSendFromISR xMessageBufferSendFromISR
* \ingroup MessageBufferManagement
*/
#define xMessageBufferSendFromISR( xMessageBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken ) \
xStreamBufferSendFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken )
/**
* message_buffer.h
*
* <pre>
* size_t xMessageBufferReceive( MessageBufferHandle_t xMessageBuffer,
* void *pvRxData,
* size_t xBufferLengthBytes,
* TickType_t xTicksToWait );
* </pre>
*
* Receives a discrete message from a message buffer. Messages can be of
* variable length and are copied out of the buffer.
*
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
* implementation (so also the message buffer implementation, as message buffers
* are built on top of stream buffers) assumes there is only one task or
* interrupt that will write to the buffer (the writer), and only one task or
* interrupt that will read from the buffer (the reader). It is safe for the
* writer and reader to be different tasks or interrupts, but, unlike other
* FreeRTOS objects, it is not safe to have multiple different writers or
* multiple different readers. If there are to be multiple different writers
* then the application writer must place each call to a writing API function
* (such as xMessageBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function
* (such as xMessageBufferRead()) inside a critical section and set the receive
* block time to 0.
*
* Use xMessageBufferReceive() to read from a message buffer from a task. Use
* xMessageBufferReceiveFromISR() to read from a message buffer from an
* interrupt service routine (ISR).
*
* @param xMessageBuffer The handle of the message buffer from which a message
* is being received.
*
* @param pvRxData A pointer to the buffer into which the received message is
* to be copied.
*
* @param xBufferLengthBytes The length of the buffer pointed to by the pvRxData
* parameter. This sets the maximum length of the message that can be received.
* If xBufferLengthBytes is too small to hold the next message then the message
* will be left in the message buffer and 0 will be returned.
*
* @param xTicksToWait The maximum amount of time the task should remain in the
* Blocked state to wait for a message, should the message buffer be empty.
* xMessageBufferReceive() will return immediately if xTicksToWait is zero and
* the message buffer is empty. The block time is specified in tick periods, so
* the absolute time it represents is dependent on the tick frequency. The
* macro pdMS_TO_TICKS() can be used to convert a time specified in milliseconds
* into a time specified in ticks. Setting xTicksToWait to portMAX_DELAY will
* cause the task to wait indefinitely (without timing out), provided
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. Tasks do not use any
* CPU time when they are in the Blocked state.
*
* @return The length, in bytes, of the message read from the message buffer, if
* any. If xMessageBufferReceive() times out before a message became available
* then zero is returned. If the length of the message is greater than
* xBufferLengthBytes then the message will be left in the message buffer and
* zero is returned.
*
* Example use:
* <pre>
* void vAFunction( MessageBuffer_t xMessageBuffer )
* {
* uint8_t ucRxData[ 20 ];
* size_t xReceivedBytes;
* const TickType_t xBlockTime = pdMS_TO_TICKS( 20 );
*
* // Receive the next message from the message buffer. Wait in the Blocked
* // state (so not using any CPU processing time) for a maximum of 100ms for
* // a message to become available.
* xReceivedBytes = xMessageBufferReceive( xMessageBuffer,
* ( void * ) ucRxData,
* sizeof( ucRxData ),
* xBlockTime );
*
* if( xReceivedBytes > 0 )
* {
* // A ucRxData contains a message that is xReceivedBytes long. Process
* // the message here....
* }
* }
* </pre>
* \defgroup xMessageBufferReceive xMessageBufferReceive
* \ingroup MessageBufferManagement
*/
#define xMessageBufferReceive( xMessageBuffer, pvRxData, xBufferLengthBytes, xTicksToWait ) \
xStreamBufferReceive( ( StreamBufferHandle_t ) xMessageBuffer, pvRxData, xBufferLengthBytes, xTicksToWait )
/**
* message_buffer.h
*
* <pre>
* size_t xMessageBufferReceiveFromISR( MessageBufferHandle_t xMessageBuffer,
* void *pvRxData,
* size_t xBufferLengthBytes,
* BaseType_t *pxHigherPriorityTaskWoken );
* </pre>
*
* An interrupt safe version of the API function that receives a discrete
* message from a message buffer. Messages can be of variable length and are
* copied out of the buffer.
*
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
* implementation (so also the message buffer implementation, as message buffers
* are built on top of stream buffers) assumes there is only one task or
* interrupt that will write to the buffer (the writer), and only one task or
* interrupt that will read from the buffer (the reader). It is safe for the
* writer and reader to be different tasks or interrupts, but, unlike other
* FreeRTOS objects, it is not safe to have multiple different writers or
* multiple different readers. If there are to be multiple different writers
* then the application writer must place each call to a writing API function
* (such as xMessageBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function
* (such as xMessageBufferRead()) inside a critical section and set the receive
* block time to 0.
*
* Use xMessageBufferReceive() to read from a message buffer from a task. Use
* xMessageBufferReceiveFromISR() to read from a message buffer from an
* interrupt service routine (ISR).
*
* @param xMessageBuffer The handle of the message buffer from which a message
* is being received.
*
* @param pvRxData A pointer to the buffer into which the received message is
* to be copied.
*
* @param xBufferLengthBytes The length of the buffer pointed to by the pvRxData
* parameter. This sets the maximum length of the message that can be received.
* If xBufferLengthBytes is too small to hold the next message then the message
* will be left in the message buffer and 0 will be returned.
*
* @param pxHigherPriorityTaskWoken It is possible that a message buffer will
* have a task blocked on it waiting for space to become available. Calling
* xMessageBufferReceiveFromISR() can make space available, and so cause a task
* that is waiting for space to leave the Blocked state. If calling
* xMessageBufferReceiveFromISR() causes a task to leave the Blocked state, and
* the unblocked task has a priority higher than the currently executing task
* (the task that was interrupted), then, internally,
* xMessageBufferReceiveFromISR() will set *pxHigherPriorityTaskWoken to pdTRUE.
* If xMessageBufferReceiveFromISR() sets this value to pdTRUE, then normally a
* context switch should be performed before the interrupt is exited. That will
* ensure the interrupt returns directly to the highest priority Ready state
* task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it is
* passed into the function. See the code example below for an example.
*
* @return The length, in bytes, of the message read from the message buffer, if
* any.
*
* Example use:
* <pre>
* // A message buffer that has already been created.
* MessageBuffer_t xMessageBuffer;
*
* void vAnInterruptServiceRoutine( void )
* {
* uint8_t ucRxData[ 20 ];
* size_t xReceivedBytes;
* BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
*
* // Receive the next message from the message buffer.
* xReceivedBytes = xMessageBufferReceiveFromISR( xMessageBuffer,
* ( void * ) ucRxData,
* sizeof( ucRxData ),
* &xHigherPriorityTaskWoken );
*
* if( xReceivedBytes > 0 )
* {
* // A ucRxData contains a message that is xReceivedBytes long. Process
* // the message here....
* }
*
* // If xHigherPriorityTaskWoken was set to pdTRUE inside
* // xMessageBufferReceiveFromISR() then a task that has a priority above the
* // priority of the currently executing task was unblocked and a context
* // switch should be performed to ensure the ISR returns to the unblocked
* // task. In most FreeRTOS ports this is done by simply passing
* // xHigherPriorityTaskWoken into portYIELD_FROM_ISR(), which will test the
* // variables value, and perform the context switch if necessary. Check the
* // documentation for the port in use for port specific instructions.
* portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
* }
* </pre>
* \defgroup xMessageBufferReceiveFromISR xMessageBufferReceiveFromISR
* \ingroup MessageBufferManagement
*/
#define xMessageBufferReceiveFromISR( xMessageBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken ) \
xStreamBufferReceiveFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken )
/**
* message_buffer.h
*
* <pre>
* void vMessageBufferDelete( MessageBufferHandle_t xMessageBuffer );
* </pre>
*
* Deletes a message buffer that was previously created using a call to
* xMessageBufferCreate() or xMessageBufferCreateStatic(). If the message
* buffer was created using dynamic memory (that is, by xMessageBufferCreate()),
* then the allocated memory is freed.
*
* A message buffer handle must not be used after the message buffer has been
* deleted.
*
* @param xMessageBuffer The handle of the message buffer to be deleted.
*
*/
#define vMessageBufferDelete( xMessageBuffer ) \
vStreamBufferDelete( ( StreamBufferHandle_t ) xMessageBuffer )
/**
* message_buffer.h
* <pre>
* BaseType_t xMessageBufferIsFull( MessageBufferHandle_t xMessageBuffer ) );
* </pre>
*
* Tests to see if a message buffer is full. A message buffer is full if it
* cannot accept any more messages, of any size, until space is made available
* by a message being removed from the message buffer.
*
* @param xMessageBuffer The handle of the message buffer being queried.
*
* @return If the message buffer referenced by xMessageBuffer is full then
* pdTRUE is returned. Otherwise pdFALSE is returned.
*/
#define xMessageBufferIsFull( xMessageBuffer ) \
xStreamBufferIsFull( ( StreamBufferHandle_t ) xMessageBuffer )
/**
* message_buffer.h
* <pre>
* BaseType_t xMessageBufferIsEmpty( MessageBufferHandle_t xMessageBuffer ) );
* </pre>
*
* Tests to see if a message buffer is empty (does not contain any messages).
*
* @param xMessageBuffer The handle of the message buffer being queried.
*
* @return If the message buffer referenced by xMessageBuffer is empty then
* pdTRUE is returned. Otherwise pdFALSE is returned.
*
*/
#define xMessageBufferIsEmpty( xMessageBuffer ) \
xStreamBufferIsEmpty( ( StreamBufferHandle_t ) xMessageBuffer )
/**
* message_buffer.h
* <pre>
* BaseType_t xMessageBufferReset( MessageBufferHandle_t xMessageBuffer );
* </pre>
*
* Resets a message buffer to its initial empty state, discarding any message it
* contained.
*
* A message buffer can only be reset if there are no tasks blocked on it.
*
* @param xMessageBuffer The handle of the message buffer being reset.
*
* @return If the message buffer was reset then pdPASS is returned. If the
* message buffer could not be reset because either there was a task blocked on
* the message queue to wait for space to become available, or to wait for a
* a message to be available, then pdFAIL is returned.
*
* \defgroup xMessageBufferReset xMessageBufferReset
* \ingroup MessageBufferManagement
*/
#define xMessageBufferReset( xMessageBuffer ) \
xStreamBufferReset( ( StreamBufferHandle_t ) xMessageBuffer )
/**
* message_buffer.h
* <pre>
* size_t xMessageBufferSpaceAvailable( MessageBufferHandle_t xMessageBuffer ) );
* </pre>
* Returns the number of bytes of free space in the message buffer.
*
* @param xMessageBuffer The handle of the message buffer being queried.
*
* @return The number of bytes that can be written to the message buffer before
* the message buffer would be full. When a message is written to the message
* buffer an additional sizeof( size_t ) bytes are also written to store the
* message's length. sizeof( size_t ) is typically 4 bytes on a 32-bit
* architecture, so if xMessageBufferSpacesAvailable() returns 10, then the size
* of the largest message that can be written to the message buffer is 6 bytes.
*
* \defgroup xMessageBufferSpaceAvailable xMessageBufferSpaceAvailable
* \ingroup MessageBufferManagement
*/
#define xMessageBufferSpaceAvailable( xMessageBuffer ) \
xStreamBufferSpacesAvailable( ( StreamBufferHandle_t ) xMessageBuffer )
#define xMessageBufferSpacesAvailable( xMessageBuffer ) \
xStreamBufferSpacesAvailable( ( StreamBufferHandle_t ) xMessageBuffer ) /* Corrects typo in original macro name. */
/**
* message_buffer.h
* <pre>
* size_t xMessageBufferNextLengthBytes( MessageBufferHandle_t xMessageBuffer ) );
* </pre>
* Returns the length (in bytes) of the next message in a message buffer.
* Useful if xMessageBufferReceive() returned 0 because the size of the buffer
* passed into xMessageBufferReceive() was too small to hold the next message.
*
* @param xMessageBuffer The handle of the message buffer being queried.
*
* @return The length (in bytes) of the next message in the message buffer, or 0
* if the message buffer is empty.
*
* \defgroup xMessageBufferNextLengthBytes xMessageBufferNextLengthBytes
* \ingroup MessageBufferManagement
*/
#define xMessageBufferNextLengthBytes( xMessageBuffer ) \
xStreamBufferNextMessageLengthBytes( ( StreamBufferHandle_t ) xMessageBuffer ) PRIVILEGED_FUNCTION;
/**
* message_buffer.h
*
* <pre>
* BaseType_t xMessageBufferSendCompletedFromISR( MessageBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
* </pre>
*
* For advanced users only.
*
* The sbSEND_COMPLETED() macro is called from within the FreeRTOS APIs when
* data is sent to a message buffer or stream buffer. If there was a task that
* was blocked on the message or stream buffer waiting for data to arrive then
* the sbSEND_COMPLETED() macro sends a notification to the task to remove it
* from the Blocked state. xMessageBufferSendCompletedFromISR() does the same
* thing. It is provided to enable application writers to implement their own
* version of sbSEND_COMPLETED(), and MUST NOT BE USED AT ANY OTHER TIME.
*
* See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for
* additional information.
*
* @param xStreamBuffer The handle of the stream buffer to which data was
* written.
*
* @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be
* initialised to pdFALSE before it is passed into
* xMessageBufferSendCompletedFromISR(). If calling
* xMessageBufferSendCompletedFromISR() removes a task from the Blocked state,
* and the task has a priority above the priority of the currently running task,
* then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a
* context switch should be performed before exiting the ISR.
*
* @return If a task was removed from the Blocked state then pdTRUE is returned.
* Otherwise pdFALSE is returned.
*
* \defgroup xMessageBufferSendCompletedFromISR xMessageBufferSendCompletedFromISR
* \ingroup StreamBufferManagement
*/
#define xMessageBufferSendCompletedFromISR( xMessageBuffer, pxHigherPriorityTaskWoken ) \
xStreamBufferSendCompletedFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pxHigherPriorityTaskWoken )
/**
* message_buffer.h
*
* <pre>
* BaseType_t xMessageBufferReceiveCompletedFromISR( MessageBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
* </pre>
*
* For advanced users only.
*
* The sbRECEIVE_COMPLETED() macro is called from within the FreeRTOS APIs when
* data is read out of a message buffer or stream buffer. If there was a task
* that was blocked on the message or stream buffer waiting for data to arrive
* then the sbRECEIVE_COMPLETED() macro sends a notification to the task to
* remove it from the Blocked state. xMessageBufferReceiveCompletedFromISR()
* does the same thing. It is provided to enable application writers to
* implement their own version of sbRECEIVE_COMPLETED(), and MUST NOT BE USED AT
* ANY OTHER TIME.
*
* See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for
* additional information.
*
* @param xStreamBuffer The handle of the stream buffer from which data was
* read.
*
* @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be
* initialised to pdFALSE before it is passed into
* xMessageBufferReceiveCompletedFromISR(). If calling
* xMessageBufferReceiveCompletedFromISR() removes a task from the Blocked state,
* and the task has a priority above the priority of the currently running task,
* then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a
* context switch should be performed before exiting the ISR.
*
* @return If a task was removed from the Blocked state then pdTRUE is returned.
* Otherwise pdFALSE is returned.
*
* \defgroup xMessageBufferReceiveCompletedFromISR xMessageBufferReceiveCompletedFromISR
* \ingroup StreamBufferManagement
*/
#define xMessageBufferReceiveCompletedFromISR( xMessageBuffer, pxHigherPriorityTaskWoken ) \
xStreamBufferReceiveCompletedFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pxHigherPriorityTaskWoken )
/* *INDENT-OFF* */
#if defined( __cplusplus )
} /* extern "C" */
#endif
/* *INDENT-ON* */
#endif /* !defined( FREERTOS_MESSAGE_BUFFER_H ) */
@@ -0,0 +1,257 @@
/*
* FreeRTOS Kernel V10.4.3
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* When the MPU is used the standard (non MPU) API functions are mapped to
* equivalents that start "MPU_", the prototypes for which are defined in this
* header files. This will cause the application code to call the MPU_ version
* which wraps the non-MPU version with privilege promoting then demoting code,
* so the kernel code always runs will full privileges.
*/
#ifndef MPU_PROTOTYPES_H
#define MPU_PROTOTYPES_H
/* MPU versions of tasks.h API functions. */
BaseType_t MPU_xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint16_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask ) FREERTOS_SYSTEM_CALL;
TaskHandle_t MPU_xTaskCreateStatic( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
StackType_t * const puxStackBuffer,
StaticTask_t * const pxTaskBuffer ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskDelete( TaskHandle_t xTaskToDelete ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskDelay( const TickType_t xTicksToDelay ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,
const TickType_t xTimeIncrement ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTaskAbortDelay( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL;
UBaseType_t MPU_uxTaskPriorityGet( const TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL;
eTaskState MPU_eTaskGetState( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskGetInfo( TaskHandle_t xTask,
TaskStatus_t * pxTaskStatus,
BaseType_t xGetFreeStackSpace,
eTaskState eState ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskPrioritySet( TaskHandle_t xTask,
UBaseType_t uxNewPriority ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskSuspend( TaskHandle_t xTaskToSuspend ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskResume( TaskHandle_t xTaskToResume ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskStartScheduler( void ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskSuspendAll( void ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTaskResumeAll( void ) FREERTOS_SYSTEM_CALL;
TickType_t MPU_xTaskGetTickCount( void ) FREERTOS_SYSTEM_CALL;
UBaseType_t MPU_uxTaskGetNumberOfTasks( void ) FREERTOS_SYSTEM_CALL;
char * MPU_pcTaskGetName( TaskHandle_t xTaskToQuery ) FREERTOS_SYSTEM_CALL;
TaskHandle_t MPU_xTaskGetHandle( const char * pcNameToQuery ) FREERTOS_SYSTEM_CALL;
UBaseType_t MPU_uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL;
configSTACK_DEPTH_TYPE MPU_uxTaskGetStackHighWaterMark2( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskSetApplicationTaskTag( TaskHandle_t xTask,
TaskHookFunction_t pxHookFunction ) FREERTOS_SYSTEM_CALL;
TaskHookFunction_t MPU_xTaskGetApplicationTaskTag( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet,
BaseType_t xIndex,
void * pvValue ) FREERTOS_SYSTEM_CALL;
void * MPU_pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery,
BaseType_t xIndex ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTaskCallApplicationTaskHook( TaskHandle_t xTask,
void * pvParameter ) FREERTOS_SYSTEM_CALL;
TaskHandle_t MPU_xTaskGetIdleTaskHandle( void ) FREERTOS_SYSTEM_CALL;
UBaseType_t MPU_uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray,
const UBaseType_t uxArraySize,
uint32_t * const pulTotalRunTime ) FREERTOS_SYSTEM_CALL;
uint32_t MPU_ulTaskGetIdleRunTimeCounter( void ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskList( char * pcWriteBuffer ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskGetRunTimeStats( char * pcWriteBuffer ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTaskGenericNotify( TaskHandle_t xTaskToNotify,
UBaseType_t uxIndexToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t * pulPreviousNotificationValue ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTaskGenericNotifyWait( UBaseType_t uxIndexToWaitOn,
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t * pulNotificationValue,
TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
uint32_t MPU_ulTaskGenericNotifyTake( UBaseType_t uxIndexToWaitOn,
BaseType_t xClearCountOnExit,
TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTaskGenericNotifyStateClear( TaskHandle_t xTask,
UBaseType_t uxIndexToClear ) FREERTOS_SYSTEM_CALL;
uint32_t MPU_ulTaskGenericNotifyValueClear( TaskHandle_t xTask,
UBaseType_t uxIndexToClear,
uint32_t ulBitsToClear ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTaskIncrementTick( void ) FREERTOS_SYSTEM_CALL;
TaskHandle_t MPU_xTaskGetCurrentTaskHandle( void ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut,
TickType_t * const pxTicksToWait ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskMissedYield( void ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTaskGetSchedulerState( void ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) FREERTOS_SYSTEM_CALL;
/* MPU versions of queue.h API functions. */
BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue,
const void * const pvItemToQueue,
TickType_t xTicksToWait,
const BaseType_t xCopyPosition ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xQueueReceive( QueueHandle_t xQueue,
void * const pvBuffer,
TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xQueuePeek( QueueHandle_t xQueue,
void * const pvBuffer,
TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xQueueSemaphoreTake( QueueHandle_t xQueue,
TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL;
UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL;
void MPU_vQueueDelete( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL;
QueueHandle_t MPU_xQueueCreateMutex( const uint8_t ucQueueType ) FREERTOS_SYSTEM_CALL;
QueueHandle_t MPU_xQueueCreateMutexStatic( const uint8_t ucQueueType,
StaticQueue_t * pxStaticQueue ) FREERTOS_SYSTEM_CALL;
QueueHandle_t MPU_xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount,
const UBaseType_t uxInitialCount ) FREERTOS_SYSTEM_CALL;
QueueHandle_t MPU_xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount,
const UBaseType_t uxInitialCount,
StaticQueue_t * pxStaticQueue ) FREERTOS_SYSTEM_CALL;
TaskHandle_t MPU_xQueueGetMutexHolder( QueueHandle_t xSemaphore ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xQueueTakeMutexRecursive( QueueHandle_t xMutex,
TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) FREERTOS_SYSTEM_CALL;
void MPU_vQueueAddToRegistry( QueueHandle_t xQueue,
const char * pcName ) FREERTOS_SYSTEM_CALL;
void MPU_vQueueUnregisterQueue( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL;
const char * MPU_pcQueueGetName( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL;
QueueHandle_t MPU_xQueueGenericCreate( const UBaseType_t uxQueueLength,
const UBaseType_t uxItemSize,
const uint8_t ucQueueType ) FREERTOS_SYSTEM_CALL;
QueueHandle_t MPU_xQueueGenericCreateStatic( const UBaseType_t uxQueueLength,
const UBaseType_t uxItemSize,
uint8_t * pucQueueStorage,
StaticQueue_t * pxStaticQueue,
const uint8_t ucQueueType ) FREERTOS_SYSTEM_CALL;
QueueSetHandle_t MPU_xQueueCreateSet( const UBaseType_t uxEventQueueLength ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore,
QueueSetHandle_t xQueueSet ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore,
QueueSetHandle_t xQueueSet ) FREERTOS_SYSTEM_CALL;
QueueSetMemberHandle_t MPU_xQueueSelectFromSet( QueueSetHandle_t xQueueSet,
const TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xQueueGenericReset( QueueHandle_t xQueue,
BaseType_t xNewQueue ) FREERTOS_SYSTEM_CALL;
void MPU_vQueueSetQueueNumber( QueueHandle_t xQueue,
UBaseType_t uxQueueNumber ) FREERTOS_SYSTEM_CALL;
UBaseType_t MPU_uxQueueGetQueueNumber( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL;
uint8_t MPU_ucQueueGetQueueType( QueueHandle_t xQueue ) FREERTOS_SYSTEM_CALL;
/* MPU versions of timers.h API functions. */
TimerHandle_t MPU_xTimerCreate( const char * const pcTimerName,
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction ) FREERTOS_SYSTEM_CALL;
TimerHandle_t MPU_xTimerCreateStatic( const char * const pcTimerName,
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction,
StaticTimer_t * pxTimerBuffer ) FREERTOS_SYSTEM_CALL;
void * MPU_pvTimerGetTimerID( const TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
void MPU_vTimerSetTimerID( TimerHandle_t xTimer,
void * pvNewID ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTimerIsTimerActive( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
TaskHandle_t MPU_xTimerGetTimerDaemonTaskHandle( void ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTimerPendFunctionCall( PendedFunction_t xFunctionToPend,
void * pvParameter1,
uint32_t ulParameter2,
TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
const char * MPU_pcTimerGetName( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
void MPU_vTimerSetReloadMode( TimerHandle_t xTimer,
const UBaseType_t uxAutoReload ) FREERTOS_SYSTEM_CALL;
UBaseType_t MPU_uxTimerGetReloadMode( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
TickType_t MPU_xTimerGetPeriod( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
TickType_t MPU_xTimerGetExpiryTime( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTimerCreateTimerTask( void ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTimerGenericCommand( TimerHandle_t xTimer,
const BaseType_t xCommandID,
const TickType_t xOptionalValue,
BaseType_t * const pxHigherPriorityTaskWoken,
const TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
/* MPU versions of event_group.h API functions. */
EventGroupHandle_t MPU_xEventGroupCreate( void ) FREERTOS_SYSTEM_CALL;
EventGroupHandle_t MPU_xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer ) FREERTOS_SYSTEM_CALL;
EventBits_t MPU_xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
EventBits_t MPU_xEventGroupClearBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear ) FREERTOS_SYSTEM_CALL;
EventBits_t MPU_xEventGroupSetBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet ) FREERTOS_SYSTEM_CALL;
EventBits_t MPU_xEventGroupSync( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
const EventBits_t uxBitsToWaitFor,
TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
void MPU_vEventGroupDelete( EventGroupHandle_t xEventGroup ) FREERTOS_SYSTEM_CALL;
UBaseType_t MPU_uxEventGroupGetNumber( void * xEventGroup ) FREERTOS_SYSTEM_CALL;
/* MPU versions of message/stream_buffer.h API functions. */
size_t MPU_xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
const void * pvTxData,
size_t xDataLengthBytes,
TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
size_t MPU_xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
void * pvRxData,
size_t xBufferLengthBytes,
TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
size_t MPU_xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL;
void MPU_vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xStreamBufferReset( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL;
size_t MPU_xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL;
size_t MPU_xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer,
size_t xTriggerLevel ) FREERTOS_SYSTEM_CALL;
StreamBufferHandle_t MPU_xStreamBufferGenericCreate( size_t xBufferSizeBytes,
size_t xTriggerLevelBytes,
BaseType_t xIsMessageBuffer ) FREERTOS_SYSTEM_CALL;
StreamBufferHandle_t MPU_xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes,
size_t xTriggerLevelBytes,
BaseType_t xIsMessageBuffer,
uint8_t * const pucStreamBufferStorageArea,
StaticStreamBuffer_t * const pxStaticStreamBuffer ) FREERTOS_SYSTEM_CALL;
#endif /* MPU_PROTOTYPES_H */
Loaded 100 of 174 files, more files were not shown because too many files have changed in this diff. Show more