├── .gitignore
├── .gitmodules
├── .travis.yml
├── LICENSE
├── README.md
├── datasheets
├── MB1137.pdf
├── STM32F429 Reference Manual.pdf
├── rfc5905.pdf
└── stm32f429zi.pdf
├── firmware
├── .gitignore
├── Makefile
├── build
├── cfg
│ ├── board.c
│ ├── board.h
│ ├── ch_lwip_bindings.mk
│ ├── chconf.h
│ ├── halconf.h
│ ├── lwipopts.h
│ └── mcuconf.h
├── config.h
├── debug
├── debug_udp.c
├── flash
├── gnss.c
├── gnss.h
├── gnss_parse.c
├── ip_link.c
├── ip_link.h
├── main.c
├── main.h
├── ntpd.c
├── ntpd.h
├── openocd.cfg
├── tools
│ ├── .gitignore
│ ├── flash.wav
│ ├── ntptest.c
│ ├── udp_bc_rx.py
│ └── udp_debug_rx.py
├── watchdog.c
├── watchdog.h
└── web
│ ├── .gitignore
│ ├── build
│ ├── htsrc
│ ├── d3.v4.min.js
│ ├── favicon.png
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── mithril.min.js
│ ├── web.c
│ ├── web.h
│ ├── web_paths.c
│ └── web_paths.h
├── hardware
├── build
├── gnss_receiver.png
└── gnss_receiver.yaml
└── images
├── gnss_receiver.png
├── maximum_rate.png
├── ntpq.png
└── web_status.png
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *~
3 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "firmware/ChibiOS"]
2 | path = firmware/ChibiOS
3 | url = https://github.com/ChibiOS/ChibiOS.git
4 | [submodule "firmware/lwIP"]
5 | path = firmware/lwIP
6 | url = https://git.savannah.gnu.org/git/lwip/
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # Use barebones Travis image
2 | language: c
3 |
4 | # Only grab latest git commit (no need for history)
5 | git:
6 | depth: 1
7 |
8 | # Cache the compilers folder so we don't have to download and unpack it for every build
9 | cache:
10 | directories:
11 | - $HOME/compilers/
12 |
13 | # Download and unpack the latest GNU ARM Embedded Toolchain if it's not already there
14 | # Also add the gcc/bin folder to $PATH
15 | install:
16 | - export GCC_DIR=$HOME/compilers/gcc-arm-none-eabi-9-2020-q2-update
17 | - export GCC_ARCHIVE=$HOME/gcc-arm-none-eabi-9-2020-q2-update-x86_64-linux.tar.bz2
18 | - export GCC_URL=https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2020q2/gcc-arm-none-eabi-9-2020-q2-update-x86_64-linux.tar.bz2
19 | - if [ ! -e $GCC_DIR/bin/arm-none-eabi-gcc ]; then wget -nv $GCC_URL -O $GCC_ARCHIVE; tar xfj $GCC_ARCHIVE -C $HOME/compilers; fi
20 | - export PATH=$PATH:$GCC_DIR/bin
21 |
22 | # Command to run tests
23 | script: cd firmware/ && ./build -M -w
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NTP Server [](https://travis-ci.org/philcrump/stm32-ntp-server)
2 |
3 | This project is an embedded NTPv4 server using the ChibiOS (20.3.x) and lwIP (2.1.x) software stacks.
4 |
5 | The hardware components are:
6 |
7 | * ST STM32F429ZI ARM Cortex-M4 Development Board - [Product Link](https://www.st.com/en/evaluation-tools/nucleo-f429zi.html)
8 | * ublox MAX-M8Q GNSS Receiver Breakout Board - [Product Link](https://store.uputronics.com/index.php?route=product/product&product_id=84) (+ suitable antenna)
9 |
10 | ## GNSS Time Sync
11 |
12 | The GNSS receiver is configured to send the current time over serial, and on the next rising edge of the timepulse signal the RTC is set to (time+1s). The STM32 RTC only counts in milliseconds, so there is always up to +/-1ms of jitter. (Future work may include using a GPT to measure sub-millisecond precision from last timepulse edge.)
13 |
14 | Despite this, simple observation through `ntpq -p` stats against a known-good remote Stratum 1 NTP server shows favourable characteristics:
15 |
16 |
17 |
18 |
19 |
20 | ## Clock Holdover
21 |
22 | The 32.768KHz crystal oscillator on the ST board is specified to 20ppm of tolerance. This has been measured in this application as <1 millisecond of drift per minute. The holdover time is therefore set to 10 minutes by default to allow up to 10ms of drift before the NTP server marks itself as Stratum 16 ("Unsynchronised"). (Future work may use the calibration routines of the STM32 RTC during periods of GNSS lock to improve this.)
23 |
24 | ## Status Webpage
25 |
26 | The software hosts a webpage showing the current status of the GNSS and NTP subsystems on port 80:
27 |
28 |
29 |
30 |
31 |
32 | ## NTP Request Rate Performance
33 |
34 | The firmware takes \~72µs to service each NTP request, with \~36µs of this spent in the service function.
35 |
36 | This equates to a maximum capability of \~12,000 reqs / second. No effort has been taken to optimise this so greater performance would be possible, however this is far in excess of what is required for the author's application.
37 |
38 | The firmware lights up LED2 on the ST board when in the NTP service function, this causes a single brief flash for each request, and also allows us to observe the timing performance in hardware (HIGH == in service function):
39 |
40 |
41 |
42 |
43 |
44 | If you're after a high-performance embedded NTP server appliance then I can personally recommend the [LeoNTP Time Server](https://store.uputronics.com/index.php?route=product/product&product_id=92), hand-coded in PIC assembly to capably saturate 100Mb/s ethernet at 110,000 reqs / second with sub-µs jitter.
45 |
46 | ## Software Configuration
47 |
48 | `firmware/config.h` contains config directives.
49 |
50 | * `GNSS_AID_` directives supply a position and it's standard deviation error to the GNSS Receiver to aid the initial position fix. If these are wrong then the GNSS receiver may fail to get a fix. Comment them out to disable.
51 |
52 | * `NTPD_STRATUM_DEMOTE_TIMER_PERIOD` Sets the time period after last timepulse sync that the NTP server will advertise Stratum 1 (GPS-synced) before dropping to Stratum 16 (Unsynchronized).
53 |
54 | * `NTPD_STATUS_DEMOTE_TIMER_PERIOD` Sets the time period after last timepulse sync that the Webpage will show 'In Lock' before dropping to 'Holdover'. Does not affect NTP output.
55 |
56 | ## Software Compilation
57 |
58 | This toolchain is designed for Linux.
59 |
60 | You must have `arm-none-eabi-gcc` from [GNU ARM embedded toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads) in your path.
61 |
62 | Running `firmware/build -M` will pack the web files and then compile all source files in parallel. The final linker stage can take a few seconds. Running without the `-M` flag will remove parallel compilation and may help errors to be more readable.
63 |
64 | ## Flashing
65 |
66 | `firmware/flash` will flash a compiled firmware image. This first looks for a connected BlackMagic JTAG probe, and if unsuccessful will drop back to `st-flash` from [st-utils](https://github.com/stlink-org/stlink) to flash over the ST-Link USB.
67 |
68 | `firmware/build -MF` will build, and if successful also attempt to flash.
69 |
70 | ## Wiring
71 |
72 | The pins used on the STM32F429ZI are:
73 |
74 | * PC10 (TXD)
75 | * PC11 (RXD)
76 | * PC12 is configured to trigger synchronisation of the RTC on the rising edge of the GNSS Timepulse
77 |
78 | These are broken out in the first 3 pins of CN11 which is the unpopulated 0.1" pads in the upper left of the board. Power supply pins are available a few rows further down.
79 |
80 | Wiring is shown below for direct 3.3V attachment. Some GNSS receivers have an integrated 3.3V regulator and so the Vcc must be fed from a 5V pin. The IO signals are still 3.3V.
81 |
82 |
83 |
84 |
85 |
86 | # Copyright
87 |
88 | GPLv3 licensed. © Phil Crump - phil@philcrump.co.uk
89 |
90 | Derivations from other license-compatible works are acknowledged in the source.
--------------------------------------------------------------------------------
/datasheets/MB1137.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philcrump/stm32-ntp-server/0ff2c3581a8918b2f62c3641bfe897db4cfd1f44/datasheets/MB1137.pdf
--------------------------------------------------------------------------------
/datasheets/STM32F429 Reference Manual.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philcrump/stm32-ntp-server/0ff2c3581a8918b2f62c3641bfe897db4cfd1f44/datasheets/STM32F429 Reference Manual.pdf
--------------------------------------------------------------------------------
/datasheets/rfc5905.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philcrump/stm32-ntp-server/0ff2c3581a8918b2f62c3641bfe897db4cfd1f44/datasheets/rfc5905.pdf
--------------------------------------------------------------------------------
/datasheets/stm32f429zi.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philcrump/stm32-ntp-server/0ff2c3581a8918b2f62c3641bfe897db4cfd1f44/datasheets/stm32f429zi.pdf
--------------------------------------------------------------------------------
/firmware/.gitignore:
--------------------------------------------------------------------------------
1 | builds/
2 |
--------------------------------------------------------------------------------
/firmware/Makefile:
--------------------------------------------------------------------------------
1 | ##############################################################################
2 | # Build global options
3 | # NOTE: Can be overridden externally.
4 | #
5 |
6 | # Compiler options here.
7 | ifeq ($(USE_OPT),)
8 | USE_OPT = -Og -ggdb -fomit-frame-pointer -falign-functions=16 -specs=nosys.specs
9 | endif
10 |
11 | # C specific options here (added to USE_OPT).
12 | ifeq ($(USE_COPT),)
13 | USE_COPT =
14 | endif
15 |
16 | # C++ specific options here (added to USE_OPT).
17 | ifeq ($(USE_CPPOPT),)
18 | USE_CPPOPT = -fno-rtti
19 | endif
20 |
21 | # Enable this if you want the linker to remove unused code and data.
22 | ifeq ($(USE_LINK_GC),)
23 | USE_LINK_GC = yes
24 | endif
25 |
26 | # Linker extra options here.
27 | ifeq ($(USE_LDOPT),)
28 | USE_LDOPT =
29 | endif
30 |
31 | # Enable this if you want link time optimizations (LTO).
32 | ifeq ($(USE_LTO),)
33 | USE_LTO = yes
34 | endif
35 |
36 | # Enable this if you want to see the full log while compiling.
37 | ifeq ($(USE_VERBOSE_COMPILE),)
38 | USE_VERBOSE_COMPILE = no
39 | endif
40 |
41 | # If enabled, this option makes the build process faster by not compiling
42 | # modules not used in the current configuration.
43 | ifeq ($(USE_SMART_BUILD),)
44 | USE_SMART_BUILD = yes
45 | endif
46 |
47 | #
48 | # Build global options
49 | ##############################################################################
50 |
51 | ##############################################################################
52 | # Architecture or project specific options
53 | #
54 |
55 | # Stack size to be allocated to the Cortex-M process stack. This stack is
56 | # the stack used by the main() thread.
57 | ifeq ($(USE_PROCESS_STACKSIZE),)
58 | USE_PROCESS_STACKSIZE = 0x400
59 | endif
60 |
61 | # Stack size to the allocated to the Cortex-M main/exceptions stack. This
62 | # stack is used for processing interrupts and exceptions.
63 | ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
64 | USE_EXCEPTIONS_STACKSIZE = 0x400
65 | endif
66 |
67 | # Enables the use of FPU (no, softfp, hard).
68 | ifeq ($(USE_FPU),)
69 | USE_FPU = no
70 | endif
71 |
72 | # FPU-related options.
73 | ifeq ($(USE_FPU_OPT),)
74 | USE_FPU_OPT = -mfloat-abi=$(USE_FPU) -mfpu=fpv4-sp-d16
75 | endif
76 |
77 | #
78 | # Architecture or project specific options
79 | ##############################################################################
80 |
81 | ##############################################################################
82 | # Project, target, sources and paths
83 | #
84 |
85 | # Define project name here
86 | PROJECT = $(TARGET_FILENAME)
87 |
88 | # Target settings.
89 | MCU = cortex-m4
90 |
91 | # Imported source files and paths.
92 | CHIBIOS := ChibiOS
93 | LWIP := lwIP
94 | CONFDIR := ./cfg
95 | BUILDDIR := ./builds
96 | DEPDIR := $(BUILDDIR)/.dep
97 |
98 | # Board files
99 | BOARDSRC = $(CONFDIR)/board.c
100 | BOARDINC = $(CONFDIR)
101 |
102 | # Licensing files.
103 | include $(CHIBIOS)/os/license/license.mk
104 | # Startup files.
105 | include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk
106 | # HAL-OSAL files (optional).
107 | include $(CHIBIOS)/os/hal/hal.mk
108 | include $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/platform.mk
109 | include $(CHIBIOS)/os/hal/osal/rt-nil/osal.mk
110 | # RTOS files (optional).
111 | include $(CHIBIOS)/os/rt/rt.mk
112 | include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk
113 | # chprintf
114 | include $(CHIBIOS)/os/hal/lib/streams/streams.mk
115 | # lwIP
116 | # include $(CHIBIOS)/os/various/lwip_bindings/lwip.mk
117 | include $(CONFDIR)/ch_lwip_bindings.mk
118 |
119 | # Define linker script file here
120 | LDSCRIPT= $(STARTUPLD)/STM32F429xI.ld
121 |
122 | # C sources that can be compiled in ARM or THUMB mode depending on the global
123 | # setting.
124 | CSRC = $(ALLCSRC) \
125 | $(BOARDSRC) \
126 | $(CHIBIOS)/os/various/evtimer.c \
127 | watchdog.c \
128 | ip_link.c \
129 | ntpd.c \
130 | gnss.c \
131 | gnss_parse.c \
132 | web/web.c \
133 | web/web_paths.c \
134 | main.c
135 |
136 | # C++ sources that can be compiled in ARM or THUMB mode depending on the global
137 | # setting.
138 | CPPSRC = $(ALLCPPSRC)
139 |
140 | # List ASM source files here.
141 | ASMSRC = $(ALLASMSRC)
142 |
143 | # List ASM with preprocessor source files here.
144 | ASMXSRC = $(ALLXASMSRC)
145 |
146 | # Inclusion directories.
147 | INCDIR = $(CONFDIR) $(ALLINC) $(TESTINC)
148 |
149 | # Define C warning options here.
150 | CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes
151 |
152 | # Define C++ warning options here.
153 | CPPWARN = -Wall -Wextra -Wundef
154 |
155 | #
156 | # Project, target, sources and paths
157 | ##############################################################################
158 |
159 | ##############################################################################
160 | # Start of user section
161 | #
162 |
163 | # List all user C define here, like -D_DEBUG=1
164 | UDEFS =
165 |
166 | # Define ASM defines here
167 | UADEFS =
168 |
169 | # List all user directories here
170 | UINCDIR =
171 |
172 | # List the user directory to look for the libraries here
173 | ULIBDIR =
174 |
175 | # List all user libraries here
176 | ULIBS = -lm
177 |
178 | #
179 | # End of user section
180 | ##############################################################################
181 |
182 | ##############################################################################
183 | # Common rules
184 | #
185 |
186 | RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk
187 | include $(RULESPATH)/arm-none-eabi.mk
188 | include $(RULESPATH)/rules.mk
189 |
190 | #
191 | # Common rules
192 | ##############################################################################
193 |
194 | ##############################################################################
195 | # Custom rules
196 | #
197 |
198 | #
199 | # Custom rules
200 | ##############################################################################
201 |
--------------------------------------------------------------------------------
/firmware/build:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source_dir="$(cd $(dirname ${BASH_SOURCE[0]}) && pwd)"
4 | cd "${source_dir}"
5 |
6 | COLOUR_GREEN='\033[0;32m'
7 | COLOUR_YELLOW='\033[1;33m'
8 | COLOUR_PURPLE='\033[0;35m'
9 | COLOUR_RED='\033[0;31m'
10 | COLOUR_OFF='\033[0;00m'
11 | CLEAR_LINE='\033[2K'
12 |
13 | _ERROR_="${COLOUR_RED}[ERROR]${COLOUR_OFF}"
14 | _INFO_="${COLOUR_PURPLE}[INFO]${COLOUR_OFF}"
15 | _DEBUG_="${COLOUR_YELLOW}[DEBUG]${COLOUR_OFF}"
16 |
17 | opt_verbose=false
18 | opt_flash=false
19 | opt_debug=false
20 | opt_asm=false
21 | opt_werror=false
22 | opt_sound=false
23 | opt_mthread=false
24 |
25 | hyphenjoin() {
26 | str=""
27 | while [ $# -gt 0 ]
28 | do
29 | str="$str$1-"
30 | shift
31 | done
32 | if [ ! -z "$str" ]
33 | then
34 | str="${str::-1}"
35 | fi
36 | echo "$str"
37 | }
38 |
39 | gccversion() {
40 | echo "$(arm-none-eabi-gcc -dumpversion)"
41 | }
42 |
43 | githash() {
44 | githash="$(git describe --dirty --always)"
45 | # Mark as dirty if untracked files exist
46 | if [ -z "$(echo "${githash}" | grep "dirty")" ] && [ ! -z "$(git status --porcelain | grep "^??")" ]; then
47 | githash="${githash}-dirty"
48 | fi
49 | echo $githash
50 | }
51 |
52 | githash_x32() {
53 | githash_x32="0x$(git describe --always)"
54 | # Set lowest nibble to 0xf if dirty, 0x0 otherwise.
55 | if [ ! -z "$(githash | grep "dirty")" ]; then
56 | githash_x32="${githash_x32}f"
57 | else
58 | githash_x32="${githash_x32}0"
59 | fi
60 | echo $githash_x32
61 | }
62 |
63 | #device_name="STM32F042K6"
64 | #device_ram=$((6*1024))
65 | #device_flash=$((32*1024))
66 |
67 | #device_name="STM32F746NG"
68 | #device_ram=$((240*1024)) # Main bank
69 | #device_flash=$((1024*1024))
70 |
71 | device_name="STM32F429ZI"
72 | device_ram=$((112*1024)) # Main bank
73 | device_flash=$((1024*1024))
74 |
75 | size_binary() {
76 | size=`arm-none-eabi-size -A -d $1`;
77 |
78 | size_text=`echo "$size" | grep '\.text' | grep -o -E '[0-9]+' | sed -n 1p`;
79 | size_rodata=`echo "$size" | grep '\.rodata' | grep -o -E '[0-9]+' | sed -n 1p`;
80 | size_data=`echo "$size" | grep '\.data' | grep -o -E '[0-9]+' | sed -n 1p`;
81 | size_bss=`echo "$size" | grep '\.bss' | grep -o -E '[0-9]+' | sed -n 1p`;
82 | size_heap=`echo "$size" | grep '\.heap' | grep -o -E '[0-9]+' | sed -n 1p`;
83 |
84 | size_flash=$(($size_text+$size_data+$size_rodata));
85 | size_static=$(($size_data+$size_bss));
86 | size_ram=$(($size_static+$size_heap));
87 | size_fdata=$(($size_data+$size_rodata));
88 |
89 | printf "$_INFO_ Device Resources (%s)\n" ${device_name};
90 | printf " RAM: % 6s B / % 6s B\n" ${size_ram} ${device_ram};
91 | printf " - Static: % 6s B\n" ${size_static};
92 | printf " - Heap: % 6s B\n" ${size_heap};
93 | printf " Flash: % 6s B / % 6s B (%2s%%)\n" ${size_flash} ${device_flash} $(((100*$size_flash)/$device_flash));
94 | printf " - Code: % 6s B\n" ${size_text};
95 | printf " - Data: % 6s B\n" ${size_fdata};
96 | }
97 |
98 | asmdump() {
99 | arm-none-eabi-objdump -DSlx ${1} > ${1}.asm
100 | printf "$_INFO_$COLOUR_GREEN Extracted assembly$COLOUR_OFF [${1}.asm]\n"
101 | }
102 |
103 | ## Read Flags
104 | OPTIND=1
105 | while getopts ":vDFmwSM" opt; do
106 | case "$opt" in
107 | v) # Verbose
108 | opt_verbose=true
109 | ;;
110 | D) # Debug
111 | opt_debug=true
112 | ;;
113 | F) # Flash
114 | opt_flash=true
115 | ;;
116 | m) # ASM
117 | opt_asm=true
118 | ;;
119 | w) # Werror
120 | opt_werror=true
121 | ;;
122 | S) # Flash Sound
123 | opt_sound=true
124 | ;;
125 | M) # Multithread Compile
126 | opt_mthread=true
127 | ;;
128 | ?) # Illegal Option
129 | echo -e "$_ERROR_ Illegal option '$OPTARG'"
130 | exit 3
131 | ;;
132 | esac
133 | done
134 | for i in `seq 2 $OPTIND`; do shift; done
135 |
136 | githash_var=`githash`
137 | filename="$(hyphenjoin "stm32ntpd" "${githash_var}")"
138 | mkdir -p "builds/"
139 |
140 | flags="TARGET_FILENAME=\"${filename}\" GITVERSION=\"${githash_var}\" GITVERSION_X32=\"`githash_x32`\""
141 | printf "$_INFO_ Using ARM-GCC version: `gccversion`\n";
142 | printf "$_INFO_ Firmware version: ${githash_var}\n";
143 |
144 | if $opt_verbose; then
145 | printf "$_INFO_ Compile Verbosely:$COLOUR_YELLOW ON $COLOUR_OFF\n";
146 | flags+=" USE_VERBOSE_COMPILE=yes";
147 | fi
148 |
149 | if $opt_werror; then
150 | printf "$_INFO_ Compiler treat Warnings as Errors:$COLOUR_RED ON $COLOUR_OFF\n";
151 | flags+=" WERROR=1";
152 | fi
153 |
154 | if $opt_mthread; then
155 | mthreads=`nproc`
156 | printf "$_INFO_ Multithread build enabled, threads: ${mthreads}$COLOUR_OFF\n";
157 | flags+=" -j${mthreads}";
158 | fi
159 |
160 | if [ -f web/build ]; then
161 | web/build;
162 | fi
163 |
164 | printf "$_INFO_ Compiling..\n";
165 | make ${flags} \
166 | && {
167 | printf "$_INFO_$COLOUR_GREEN Build successful$COLOUR_OFF [builds/${filename}.elf]\n"
168 | } || {
169 | printf "$_ERROR_$COLOUR_RED There were errors in the build process$COLOUR_OFF\n" \
170 | && exit 1
171 | }
172 | size_binary "builds/${filename}.elf"
173 |
174 | if $opt_asm; then asmdump "builds/${filename}.elf"; fi
175 |
176 | if $opt_debug;
177 | then
178 | ./debug "builds/${filename}";
179 | elif $opt_flash;
180 | then
181 | fflags=""
182 | if $opt_sound; then fflags+=" -S"; fi
183 | ./flash ${fflags} "builds/${filename}";
184 | fi
185 |
--------------------------------------------------------------------------------
/firmware/cfg/board.c:
--------------------------------------------------------------------------------
1 | /*
2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | /*
18 | * This file has been automatically generated using ChibiStudio board
19 | * generator plugin. Do not edit manually.
20 | */
21 |
22 | #include "hal.h"
23 | #include "stm32_gpio.h"
24 |
25 | /*===========================================================================*/
26 | /* Driver local definitions. */
27 | /*===========================================================================*/
28 |
29 | /*===========================================================================*/
30 | /* Driver exported variables. */
31 | /*===========================================================================*/
32 |
33 | /*===========================================================================*/
34 | /* Driver local variables and types. */
35 | /*===========================================================================*/
36 |
37 | /**
38 | * @brief Type of STM32 GPIO port setup.
39 | */
40 | typedef struct {
41 | uint32_t moder;
42 | uint32_t otyper;
43 | uint32_t ospeedr;
44 | uint32_t pupdr;
45 | uint32_t odr;
46 | uint32_t afrl;
47 | uint32_t afrh;
48 | } gpio_setup_t;
49 |
50 | /**
51 | * @brief Type of STM32 GPIO initialization data.
52 | */
53 | typedef struct {
54 | #if STM32_HAS_GPIOA || defined(__DOXYGEN__)
55 | gpio_setup_t PAData;
56 | #endif
57 | #if STM32_HAS_GPIOB || defined(__DOXYGEN__)
58 | gpio_setup_t PBData;
59 | #endif
60 | #if STM32_HAS_GPIOC || defined(__DOXYGEN__)
61 | gpio_setup_t PCData;
62 | #endif
63 | #if STM32_HAS_GPIOD || defined(__DOXYGEN__)
64 | gpio_setup_t PDData;
65 | #endif
66 | #if STM32_HAS_GPIOE || defined(__DOXYGEN__)
67 | gpio_setup_t PEData;
68 | #endif
69 | #if STM32_HAS_GPIOF || defined(__DOXYGEN__)
70 | gpio_setup_t PFData;
71 | #endif
72 | #if STM32_HAS_GPIOG || defined(__DOXYGEN__)
73 | gpio_setup_t PGData;
74 | #endif
75 | #if STM32_HAS_GPIOH || defined(__DOXYGEN__)
76 | gpio_setup_t PHData;
77 | #endif
78 | #if STM32_HAS_GPIOI || defined(__DOXYGEN__)
79 | gpio_setup_t PIData;
80 | #endif
81 | #if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
82 | gpio_setup_t PJData;
83 | #endif
84 | #if STM32_HAS_GPIOK || defined(__DOXYGEN__)
85 | gpio_setup_t PKData;
86 | #endif
87 | } gpio_config_t;
88 |
89 | /**
90 | * @brief STM32 GPIO static initialization data.
91 | */
92 | static const gpio_config_t gpio_default_config = {
93 | #if STM32_HAS_GPIOA
94 | {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR,
95 | VAL_GPIOA_ODR, VAL_GPIOA_AFRL, VAL_GPIOA_AFRH},
96 | #endif
97 | #if STM32_HAS_GPIOB
98 | {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR,
99 | VAL_GPIOB_ODR, VAL_GPIOB_AFRL, VAL_GPIOB_AFRH},
100 | #endif
101 | #if STM32_HAS_GPIOC
102 | {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR,
103 | VAL_GPIOC_ODR, VAL_GPIOC_AFRL, VAL_GPIOC_AFRH},
104 | #endif
105 | #if STM32_HAS_GPIOD
106 | {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR,
107 | VAL_GPIOD_ODR, VAL_GPIOD_AFRL, VAL_GPIOD_AFRH},
108 | #endif
109 | #if STM32_HAS_GPIOE
110 | {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR,
111 | VAL_GPIOE_ODR, VAL_GPIOE_AFRL, VAL_GPIOE_AFRH},
112 | #endif
113 | #if STM32_HAS_GPIOF
114 | {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR,
115 | VAL_GPIOF_ODR, VAL_GPIOF_AFRL, VAL_GPIOF_AFRH},
116 | #endif
117 | #if STM32_HAS_GPIOG
118 | {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR,
119 | VAL_GPIOG_ODR, VAL_GPIOG_AFRL, VAL_GPIOG_AFRH},
120 | #endif
121 | #if STM32_HAS_GPIOH
122 | {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR,
123 | VAL_GPIOH_ODR, VAL_GPIOH_AFRL, VAL_GPIOH_AFRH},
124 | #endif
125 | #if STM32_HAS_GPIOI
126 | {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR,
127 | VAL_GPIOI_ODR, VAL_GPIOI_AFRL, VAL_GPIOI_AFRH},
128 | #endif
129 | #if STM32_HAS_GPIOJ
130 | {VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR,
131 | VAL_GPIOJ_ODR, VAL_GPIOJ_AFRL, VAL_GPIOJ_AFRH},
132 | #endif
133 | #if STM32_HAS_GPIOK
134 | {VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR,
135 | VAL_GPIOK_ODR, VAL_GPIOK_AFRL, VAL_GPIOK_AFRH}
136 | #endif
137 | };
138 |
139 | /*===========================================================================*/
140 | /* Driver local functions. */
141 | /*===========================================================================*/
142 |
143 | static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) {
144 |
145 | gpiop->OTYPER = config->otyper;
146 | gpiop->OSPEEDR = config->ospeedr;
147 | gpiop->PUPDR = config->pupdr;
148 | gpiop->ODR = config->odr;
149 | gpiop->AFRL = config->afrl;
150 | gpiop->AFRH = config->afrh;
151 | gpiop->MODER = config->moder;
152 | }
153 |
154 | static void stm32_gpio_init(void) {
155 |
156 | /* Enabling GPIO-related clocks, the mask comes from the
157 | registry header file.*/
158 | rccResetAHB1(STM32_GPIO_EN_MASK);
159 | rccEnableAHB1(STM32_GPIO_EN_MASK, true);
160 |
161 | /* Initializing all the defined GPIO ports.*/
162 | #if STM32_HAS_GPIOA
163 | gpio_init(GPIOA, &gpio_default_config.PAData);
164 | #endif
165 | #if STM32_HAS_GPIOB
166 | gpio_init(GPIOB, &gpio_default_config.PBData);
167 | #endif
168 | #if STM32_HAS_GPIOC
169 | gpio_init(GPIOC, &gpio_default_config.PCData);
170 | #endif
171 | #if STM32_HAS_GPIOD
172 | gpio_init(GPIOD, &gpio_default_config.PDData);
173 | #endif
174 | #if STM32_HAS_GPIOE
175 | gpio_init(GPIOE, &gpio_default_config.PEData);
176 | #endif
177 | #if STM32_HAS_GPIOF
178 | gpio_init(GPIOF, &gpio_default_config.PFData);
179 | #endif
180 | #if STM32_HAS_GPIOG
181 | gpio_init(GPIOG, &gpio_default_config.PGData);
182 | #endif
183 | #if STM32_HAS_GPIOH
184 | gpio_init(GPIOH, &gpio_default_config.PHData);
185 | #endif
186 | #if STM32_HAS_GPIOI
187 | gpio_init(GPIOI, &gpio_default_config.PIData);
188 | #endif
189 | #if STM32_HAS_GPIOJ
190 | gpio_init(GPIOJ, &gpio_default_config.PJData);
191 | #endif
192 | #if STM32_HAS_GPIOK
193 | gpio_init(GPIOK, &gpio_default_config.PKData);
194 | #endif
195 | }
196 |
197 | /*===========================================================================*/
198 | /* Driver interrupt handlers. */
199 | /*===========================================================================*/
200 |
201 | /*===========================================================================*/
202 | /* Driver exported functions. */
203 | /*===========================================================================*/
204 |
205 | /**
206 | * @brief Early initialization code.
207 | * @details GPIO ports and system clocks are initialized before everything
208 | * else.
209 | */
210 | void __early_init(void) {
211 |
212 | stm32_gpio_init();
213 | stm32_clock_init();
214 | }
215 |
216 | #if HAL_USE_SDC || defined(__DOXYGEN__)
217 | /**
218 | * @brief SDC card detection.
219 | */
220 | bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
221 |
222 | (void)sdcp;
223 | /* TODO: Fill the implementation.*/
224 | return true;
225 | }
226 |
227 | /**
228 | * @brief SDC card write protection detection.
229 | */
230 | bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
231 |
232 | (void)sdcp;
233 | /* TODO: Fill the implementation.*/
234 | return false;
235 | }
236 | #endif /* HAL_USE_SDC */
237 |
238 | #if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
239 | /**
240 | * @brief MMC_SPI card detection.
241 | */
242 | bool mmc_lld_is_card_inserted(MMCDriver *mmcp) {
243 |
244 | (void)mmcp;
245 | /* TODO: Fill the implementation.*/
246 | return true;
247 | }
248 |
249 | /**
250 | * @brief MMC_SPI card write protection detection.
251 | */
252 | bool mmc_lld_is_write_protected(MMCDriver *mmcp) {
253 |
254 | (void)mmcp;
255 | /* TODO: Fill the implementation.*/
256 | return false;
257 | }
258 | #endif
259 |
260 | /**
261 | * @brief Board-specific initialization code.
262 | * @todo Add your board-specific code, if any.
263 | */
264 | void boardInit(void) {
265 |
266 | }
267 |
--------------------------------------------------------------------------------
/firmware/cfg/ch_lwip_bindings.mk:
--------------------------------------------------------------------------------
1 | # List of the required lwIP files.
2 | #LWIPDIR = $(CHIBIOS)/ext/lwip/src
3 | LWIPDIR = $(LWIP)/src
4 |
5 | # The various blocks of files are outlined in Filelists.mk.
6 | include $(LWIPDIR)/Filelists.mk
7 |
8 | LWBINDSRC = \
9 | $(CHIBIOS)/os/various/lwip_bindings/lwipthread.c \
10 | $(CHIBIOS)/os/various/lwip_bindings/arch/sys_arch.c
11 |
12 |
13 | # Add blocks of files from Filelists.mk as required for enabled options
14 | LWSRC_REQUIRED = $(COREFILES) $(CORE4FILES) $(APIFILES) $(LWBINDSRC) $(NETIFFILES)
15 | LWSRC_EXTRAS ?= $(SNTPFILES)
16 |
17 | LWINC = \
18 | $(CHIBIOS)/os/various/lwip_bindings \
19 | $(LWIPDIR)/include
20 |
21 | # Shared variables
22 | ALLCSRC += $(LWSRC_REQUIRED) $(LWSRC_EXTRAS)
23 | ALLINC += $(LWINC) \
24 | $(CHIBIOS)/os/various
25 |
--------------------------------------------------------------------------------
/firmware/cfg/chconf.h:
--------------------------------------------------------------------------------
1 | /*
2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | /**
18 | * @file rt/templates/chconf.h
19 | * @brief Configuration file template.
20 | * @details A copy of this file must be placed in each project directory, it
21 | * contains the application specific kernel settings.
22 | *
23 | * @addtogroup config
24 | * @details Kernel related settings and hooks.
25 | * @{
26 | */
27 |
28 | #ifndef CHCONF_H
29 | #define CHCONF_H
30 |
31 | #define _CHIBIOS_RT_CONF_
32 | #define _CHIBIOS_RT_CONF_VER_6_1_
33 |
34 | /*===========================================================================*/
35 | /* Phil's Additions */
36 |
37 | #if defined(CHPRINTF_USE_FLOAT)
38 | #undef CHPRINTF_USE_FLOAT
39 | #endif
40 | #define CHPRINTF_USE_FLOAT TRUE
41 |
42 |
43 | /*===========================================================================*/
44 | /**
45 | * @name System timers settings
46 | * @{
47 | */
48 | /*===========================================================================*/
49 |
50 | /**
51 | * @brief System time counter resolution.
52 | * @note Allowed values are 16 or 32 bits.
53 | */
54 | #if !defined(CH_CFG_ST_RESOLUTION)
55 | #define CH_CFG_ST_RESOLUTION 32
56 | #endif
57 |
58 | /**
59 | * @brief System tick frequency.
60 | * @details Frequency of the system timer that drives the system ticks. This
61 | * setting also defines the system tick time unit.
62 | */
63 | #if !defined(CH_CFG_ST_FREQUENCY)
64 | #define CH_CFG_ST_FREQUENCY 10000
65 | #endif
66 |
67 | /**
68 | * @brief Time intervals data size.
69 | * @note Allowed values are 16, 32 or 64 bits.
70 | */
71 | #if !defined(CH_CFG_INTERVALS_SIZE)
72 | #define CH_CFG_INTERVALS_SIZE 32
73 | #endif
74 |
75 | /**
76 | * @brief Time types data size.
77 | * @note Allowed values are 16 or 32 bits.
78 | */
79 | #if !defined(CH_CFG_TIME_TYPES_SIZE)
80 | #define CH_CFG_TIME_TYPES_SIZE 32
81 | #endif
82 |
83 | /**
84 | * @brief Time delta constant for the tick-less mode.
85 | * @note If this value is zero then the system uses the classic
86 | * periodic tick. This value represents the minimum number
87 | * of ticks that is safe to specify in a timeout directive.
88 | * The value one is not valid, timeouts are rounded up to
89 | * this value.
90 | */
91 | #if !defined(CH_CFG_ST_TIMEDELTA)
92 | #define CH_CFG_ST_TIMEDELTA 2
93 | #endif
94 |
95 | /** @} */
96 |
97 | /*===========================================================================*/
98 | /**
99 | * @name Kernel parameters and options
100 | * @{
101 | */
102 | /*===========================================================================*/
103 |
104 | /**
105 | * @brief Round robin interval.
106 | * @details This constant is the number of system ticks allowed for the
107 | * threads before preemption occurs. Setting this value to zero
108 | * disables the preemption for threads with equal priority and the
109 | * round robin becomes cooperative. Note that higher priority
110 | * threads can still preempt, the kernel is always preemptive.
111 | * @note Disabling the round robin preemption makes the kernel more compact
112 | * and generally faster.
113 | * @note The round robin preemption is not supported in tickless mode and
114 | * must be set to zero in that case.
115 | */
116 | #if !defined(CH_CFG_TIME_QUANTUM)
117 | #define CH_CFG_TIME_QUANTUM 0
118 | #endif
119 |
120 | /**
121 | * @brief Idle thread automatic spawn suppression.
122 | * @details When this option is activated the function @p chSysInit()
123 | * does not spawn the idle thread. The application @p main()
124 | * function becomes the idle thread and must implement an
125 | * infinite loop.
126 | */
127 | #if !defined(CH_CFG_NO_IDLE_THREAD)
128 | #define CH_CFG_NO_IDLE_THREAD FALSE
129 | #endif
130 |
131 | /** @} */
132 |
133 | /*===========================================================================*/
134 | /**
135 | * @name Performance options
136 | * @{
137 | */
138 | /*===========================================================================*/
139 |
140 | /**
141 | * @brief OS optimization.
142 | * @details If enabled then time efficient rather than space efficient code
143 | * is used when two possible implementations exist.
144 | *
145 | * @note This is not related to the compiler optimization options.
146 | * @note The default is @p TRUE.
147 | */
148 | #if !defined(CH_CFG_OPTIMIZE_SPEED)
149 | #define CH_CFG_OPTIMIZE_SPEED TRUE
150 | #endif
151 |
152 | /** @} */
153 |
154 | /*===========================================================================*/
155 | /**
156 | * @name Subsystem options
157 | * @{
158 | */
159 | /*===========================================================================*/
160 |
161 | /**
162 | * @brief Time Measurement APIs.
163 | * @details If enabled then the time measurement APIs are included in
164 | * the kernel.
165 | *
166 | * @note The default is @p TRUE.
167 | */
168 | #if !defined(CH_CFG_USE_TM)
169 | #define CH_CFG_USE_TM TRUE
170 | #endif
171 |
172 | /**
173 | * @brief Threads registry APIs.
174 | * @details If enabled then the registry APIs are included in the kernel.
175 | *
176 | * @note The default is @p TRUE.
177 | */
178 | #if !defined(CH_CFG_USE_REGISTRY)
179 | #define CH_CFG_USE_REGISTRY TRUE
180 | #endif
181 |
182 | /**
183 | * @brief Threads synchronization APIs.
184 | * @details If enabled then the @p chThdWait() function is included in
185 | * the kernel.
186 | *
187 | * @note The default is @p TRUE.
188 | */
189 | #if !defined(CH_CFG_USE_WAITEXIT)
190 | #define CH_CFG_USE_WAITEXIT TRUE
191 | #endif
192 |
193 | /**
194 | * @brief Semaphores APIs.
195 | * @details If enabled then the Semaphores APIs are included in the kernel.
196 | *
197 | * @note The default is @p TRUE.
198 | */
199 | #if !defined(CH_CFG_USE_SEMAPHORES)
200 | #define CH_CFG_USE_SEMAPHORES TRUE
201 | #endif
202 |
203 | /**
204 | * @brief Semaphores queuing mode.
205 | * @details If enabled then the threads are enqueued on semaphores by
206 | * priority rather than in FIFO order.
207 | *
208 | * @note The default is @p FALSE. Enable this if you have special
209 | * requirements.
210 | * @note Requires @p CH_CFG_USE_SEMAPHORES.
211 | */
212 | #if !defined(CH_CFG_USE_SEMAPHORES_PRIORITY)
213 | #define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE
214 | #endif
215 |
216 | /**
217 | * @brief Mutexes APIs.
218 | * @details If enabled then the mutexes APIs are included in the kernel.
219 | *
220 | * @note The default is @p TRUE.
221 | */
222 | #if !defined(CH_CFG_USE_MUTEXES)
223 | #define CH_CFG_USE_MUTEXES TRUE
224 | #endif
225 |
226 | /**
227 | * @brief Enables recursive behavior on mutexes.
228 | * @note Recursive mutexes are heavier and have an increased
229 | * memory footprint.
230 | *
231 | * @note The default is @p FALSE.
232 | * @note Requires @p CH_CFG_USE_MUTEXES.
233 | */
234 | #if !defined(CH_CFG_USE_MUTEXES_RECURSIVE)
235 | #define CH_CFG_USE_MUTEXES_RECURSIVE FALSE
236 | #endif
237 |
238 | /**
239 | * @brief Conditional Variables APIs.
240 | * @details If enabled then the conditional variables APIs are included
241 | * in the kernel.
242 | *
243 | * @note The default is @p TRUE.
244 | * @note Requires @p CH_CFG_USE_MUTEXES.
245 | */
246 | #if !defined(CH_CFG_USE_CONDVARS)
247 | #define CH_CFG_USE_CONDVARS TRUE
248 | #endif
249 |
250 | /**
251 | * @brief Conditional Variables APIs with timeout.
252 | * @details If enabled then the conditional variables APIs with timeout
253 | * specification are included in the kernel.
254 | *
255 | * @note The default is @p TRUE.
256 | * @note Requires @p CH_CFG_USE_CONDVARS.
257 | */
258 | #if !defined(CH_CFG_USE_CONDVARS_TIMEOUT)
259 | #define CH_CFG_USE_CONDVARS_TIMEOUT TRUE
260 | #endif
261 |
262 | /**
263 | * @brief Events Flags APIs.
264 | * @details If enabled then the event flags APIs are included in the kernel.
265 | *
266 | * @note The default is @p TRUE.
267 | */
268 | #if !defined(CH_CFG_USE_EVENTS)
269 | #define CH_CFG_USE_EVENTS TRUE
270 | #endif
271 |
272 | /**
273 | * @brief Events Flags APIs with timeout.
274 | * @details If enabled then the events APIs with timeout specification
275 | * are included in the kernel.
276 | *
277 | * @note The default is @p TRUE.
278 | * @note Requires @p CH_CFG_USE_EVENTS.
279 | */
280 | #if !defined(CH_CFG_USE_EVENTS_TIMEOUT)
281 | #define CH_CFG_USE_EVENTS_TIMEOUT TRUE
282 | #endif
283 |
284 | /**
285 | * @brief Synchronous Messages APIs.
286 | * @details If enabled then the synchronous messages APIs are included
287 | * in the kernel.
288 | *
289 | * @note The default is @p TRUE.
290 | */
291 | #if !defined(CH_CFG_USE_MESSAGES)
292 | #define CH_CFG_USE_MESSAGES TRUE
293 | #endif
294 |
295 | /**
296 | * @brief Synchronous Messages queuing mode.
297 | * @details If enabled then messages are served by priority rather than in
298 | * FIFO order.
299 | *
300 | * @note The default is @p FALSE. Enable this if you have special
301 | * requirements.
302 | * @note Requires @p CH_CFG_USE_MESSAGES.
303 | */
304 | #if !defined(CH_CFG_USE_MESSAGES_PRIORITY)
305 | #define CH_CFG_USE_MESSAGES_PRIORITY FALSE
306 | #endif
307 |
308 | /**
309 | * @brief Dynamic Threads APIs.
310 | * @details If enabled then the dynamic threads creation APIs are included
311 | * in the kernel.
312 | *
313 | * @note The default is @p TRUE.
314 | * @note Requires @p CH_CFG_USE_WAITEXIT.
315 | * @note Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS.
316 | */
317 | #if !defined(CH_CFG_USE_DYNAMIC)
318 | #define CH_CFG_USE_DYNAMIC TRUE
319 | #endif
320 |
321 | /** @} */
322 |
323 | /*===========================================================================*/
324 | /**
325 | * @name OSLIB options
326 | * @{
327 | */
328 | /*===========================================================================*/
329 |
330 | /**
331 | * @brief Mailboxes APIs.
332 | * @details If enabled then the asynchronous messages (mailboxes) APIs are
333 | * included in the kernel.
334 | *
335 | * @note The default is @p TRUE.
336 | * @note Requires @p CH_CFG_USE_SEMAPHORES.
337 | */
338 | #if !defined(CH_CFG_USE_MAILBOXES)
339 | #define CH_CFG_USE_MAILBOXES TRUE
340 | #endif
341 |
342 | /**
343 | * @brief Core Memory Manager APIs.
344 | * @details If enabled then the core memory manager APIs are included
345 | * in the kernel.
346 | *
347 | * @note The default is @p TRUE.
348 | */
349 | #if !defined(CH_CFG_USE_MEMCORE)
350 | #define CH_CFG_USE_MEMCORE TRUE
351 | #endif
352 |
353 | /**
354 | * @brief Managed RAM size.
355 | * @details Size of the RAM area to be managed by the OS. If set to zero
356 | * then the whole available RAM is used. The core memory is made
357 | * available to the heap allocator and/or can be used directly through
358 | * the simplified core memory allocator.
359 | *
360 | * @note In order to let the OS manage the whole RAM the linker script must
361 | * provide the @p __heap_base__ and @p __heap_end__ symbols.
362 | * @note Requires @p CH_CFG_USE_MEMCORE.
363 | */
364 | #if !defined(CH_CFG_MEMCORE_SIZE)
365 | #define CH_CFG_MEMCORE_SIZE 0
366 | #endif
367 |
368 | /**
369 | * @brief Heap Allocator APIs.
370 | * @details If enabled then the memory heap allocator APIs are included
371 | * in the kernel.
372 | *
373 | * @note The default is @p TRUE.
374 | * @note Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or
375 | * @p CH_CFG_USE_SEMAPHORES.
376 | * @note Mutexes are recommended.
377 | */
378 | #if !defined(CH_CFG_USE_HEAP)
379 | #define CH_CFG_USE_HEAP TRUE
380 | #endif
381 |
382 | /**
383 | * @brief Memory Pools Allocator APIs.
384 | * @details If enabled then the memory pools allocator APIs are included
385 | * in the kernel.
386 | *
387 | * @note The default is @p TRUE.
388 | */
389 | #if !defined(CH_CFG_USE_MEMPOOLS)
390 | #define CH_CFG_USE_MEMPOOLS TRUE
391 | #endif
392 |
393 | /**
394 | * @brief Objects FIFOs APIs.
395 | * @details If enabled then the objects FIFOs APIs are included
396 | * in the kernel.
397 | *
398 | * @note The default is @p TRUE.
399 | */
400 | #if !defined(CH_CFG_USE_OBJ_FIFOS)
401 | #define CH_CFG_USE_OBJ_FIFOS TRUE
402 | #endif
403 |
404 | /**
405 | * @brief Pipes APIs.
406 | * @details If enabled then the pipes APIs are included
407 | * in the kernel.
408 | *
409 | * @note The default is @p TRUE.
410 | */
411 | #if !defined(CH_CFG_USE_PIPES)
412 | #define CH_CFG_USE_PIPES TRUE
413 | #endif
414 |
415 | /**
416 | * @brief Objects Caches APIs.
417 | * @details If enabled then the objects caches APIs are included
418 | * in the kernel.
419 | *
420 | * @note The default is @p TRUE.
421 | */
422 | #if !defined(CH_CFG_USE_OBJ_CACHES)
423 | #define CH_CFG_USE_OBJ_CACHES TRUE
424 | #endif
425 |
426 | /**
427 | * @brief Delegate threads APIs.
428 | * @details If enabled then the delegate threads APIs are included
429 | * in the kernel.
430 | *
431 | * @note The default is @p TRUE.
432 | */
433 | #if !defined(CH_CFG_USE_DELEGATES)
434 | #define CH_CFG_USE_DELEGATES TRUE
435 | #endif
436 |
437 | /**
438 | * @brief Jobs Queues APIs.
439 | * @details If enabled then the jobs queues APIs are included
440 | * in the kernel.
441 | *
442 | * @note The default is @p TRUE.
443 | */
444 | #if !defined(CH_CFG_USE_JOBS)
445 | #define CH_CFG_USE_JOBS TRUE
446 | #endif
447 |
448 | /** @} */
449 |
450 | /*===========================================================================*/
451 | /**
452 | * @name Objects factory options
453 | * @{
454 | */
455 | /*===========================================================================*/
456 |
457 | /**
458 | * @brief Objects Factory APIs.
459 | * @details If enabled then the objects factory APIs are included in the
460 | * kernel.
461 | *
462 | * @note The default is @p FALSE.
463 | */
464 | #if !defined(CH_CFG_USE_FACTORY)
465 | #define CH_CFG_USE_FACTORY TRUE
466 | #endif
467 |
468 | /**
469 | * @brief Maximum length for object names.
470 | * @details If the specified length is zero then the name is stored by
471 | * pointer but this could have unintended side effects.
472 | */
473 | #if !defined(CH_CFG_FACTORY_MAX_NAMES_LENGTH)
474 | #define CH_CFG_FACTORY_MAX_NAMES_LENGTH 8
475 | #endif
476 |
477 | /**
478 | * @brief Enables the registry of generic objects.
479 | */
480 | #if !defined(CH_CFG_FACTORY_OBJECTS_REGISTRY)
481 | #define CH_CFG_FACTORY_OBJECTS_REGISTRY TRUE
482 | #endif
483 |
484 | /**
485 | * @brief Enables factory for generic buffers.
486 | */
487 | #if !defined(CH_CFG_FACTORY_GENERIC_BUFFERS)
488 | #define CH_CFG_FACTORY_GENERIC_BUFFERS TRUE
489 | #endif
490 |
491 | /**
492 | * @brief Enables factory for semaphores.
493 | */
494 | #if !defined(CH_CFG_FACTORY_SEMAPHORES)
495 | #define CH_CFG_FACTORY_SEMAPHORES TRUE
496 | #endif
497 |
498 | /**
499 | * @brief Enables factory for mailboxes.
500 | */
501 | #if !defined(CH_CFG_FACTORY_MAILBOXES)
502 | #define CH_CFG_FACTORY_MAILBOXES TRUE
503 | #endif
504 |
505 | /**
506 | * @brief Enables factory for objects FIFOs.
507 | */
508 | #if !defined(CH_CFG_FACTORY_OBJ_FIFOS)
509 | #define CH_CFG_FACTORY_OBJ_FIFOS TRUE
510 | #endif
511 |
512 | /**
513 | * @brief Enables factory for Pipes.
514 | */
515 | #if !defined(CH_CFG_FACTORY_PIPES) || defined(__DOXYGEN__)
516 | #define CH_CFG_FACTORY_PIPES TRUE
517 | #endif
518 |
519 | /** @} */
520 |
521 | /*===========================================================================*/
522 | /**
523 | * @name Debug options
524 | * @{
525 | */
526 | /*===========================================================================*/
527 |
528 | /**
529 | * @brief Debug option, kernel statistics.
530 | *
531 | * @note The default is @p FALSE.
532 | */
533 | #if !defined(CH_DBG_STATISTICS)
534 | #define CH_DBG_STATISTICS FALSE
535 | #endif
536 |
537 | /**
538 | * @brief Debug option, system state check.
539 | * @details If enabled the correct call protocol for system APIs is checked
540 | * at runtime.
541 | *
542 | * @note The default is @p FALSE.
543 | */
544 | #if !defined(CH_DBG_SYSTEM_STATE_CHECK)
545 | #define CH_DBG_SYSTEM_STATE_CHECK FALSE
546 | #endif
547 |
548 | /**
549 | * @brief Debug option, parameters checks.
550 | * @details If enabled then the checks on the API functions input
551 | * parameters are activated.
552 | *
553 | * @note The default is @p FALSE.
554 | */
555 | #if !defined(CH_DBG_ENABLE_CHECKS)
556 | #define CH_DBG_ENABLE_CHECKS FALSE
557 | #endif
558 |
559 | /**
560 | * @brief Debug option, consistency checks.
561 | * @details If enabled then all the assertions in the kernel code are
562 | * activated. This includes consistency checks inside the kernel,
563 | * runtime anomalies and port-defined checks.
564 | *
565 | * @note The default is @p FALSE.
566 | */
567 | #if !defined(CH_DBG_ENABLE_ASSERTS)
568 | #define CH_DBG_ENABLE_ASSERTS FALSE
569 | #endif
570 |
571 | /**
572 | * @brief Debug option, trace buffer.
573 | * @details If enabled then the trace buffer is activated.
574 | *
575 | * @note The default is @p CH_DBG_TRACE_MASK_DISABLED.
576 | */
577 | #if !defined(CH_DBG_TRACE_MASK)
578 | #define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_DISABLED
579 | #endif
580 |
581 | /**
582 | * @brief Trace buffer entries.
583 | * @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is
584 | * different from @p CH_DBG_TRACE_MASK_DISABLED.
585 | */
586 | #if !defined(CH_DBG_TRACE_BUFFER_SIZE)
587 | #define CH_DBG_TRACE_BUFFER_SIZE 128
588 | #endif
589 |
590 | /**
591 | * @brief Debug option, stack checks.
592 | * @details If enabled then a runtime stack check is performed.
593 | *
594 | * @note The default is @p FALSE.
595 | * @note The stack check is performed in a architecture/port dependent way.
596 | * It may not be implemented or some ports.
597 | * @note The default failure mode is to halt the system with the global
598 | * @p panic_msg variable set to @p NULL.
599 | */
600 | #if !defined(CH_DBG_ENABLE_STACK_CHECK)
601 | #define CH_DBG_ENABLE_STACK_CHECK FALSE
602 | #endif
603 |
604 | /**
605 | * @brief Debug option, stacks initialization.
606 | * @details If enabled then the threads working area is filled with a byte
607 | * value when a thread is created. This can be useful for the
608 | * runtime measurement of the used stack.
609 | *
610 | * @note The default is @p FALSE.
611 | */
612 | #if !defined(CH_DBG_FILL_THREADS)
613 | #define CH_DBG_FILL_THREADS FALSE
614 | #endif
615 |
616 | /**
617 | * @brief Debug option, threads profiling.
618 | * @details If enabled then a field is added to the @p thread_t structure that
619 | * counts the system ticks occurred while executing the thread.
620 | *
621 | * @note The default is @p FALSE.
622 | * @note This debug option is not currently compatible with the
623 | * tickless mode.
624 | */
625 | #if !defined(CH_DBG_THREADS_PROFILING)
626 | #define CH_DBG_THREADS_PROFILING FALSE
627 | #endif
628 |
629 | /** @} */
630 |
631 | /*===========================================================================*/
632 | /**
633 | * @name Kernel hooks
634 | * @{
635 | */
636 | /*===========================================================================*/
637 |
638 | /**
639 | * @brief System structure extension.
640 | * @details User fields added to the end of the @p ch_system_t structure.
641 | */
642 | #define CH_CFG_SYSTEM_EXTRA_FIELDS \
643 | /* Add threads custom fields here.*/
644 |
645 | /**
646 | * @brief System initialization hook.
647 | * @details User initialization code added to the @p chSysInit() function
648 | * just before interrupts are enabled globally.
649 | */
650 | #define CH_CFG_SYSTEM_INIT_HOOK() { \
651 | /* Add threads initialization code here.*/ \
652 | }
653 |
654 | /**
655 | * @brief Threads descriptor structure extension.
656 | * @details User fields added to the end of the @p thread_t structure.
657 | */
658 | #define CH_CFG_THREAD_EXTRA_FIELDS \
659 | /* Add threads custom fields here.*/
660 |
661 | /**
662 | * @brief Threads initialization hook.
663 | * @details User initialization code added to the @p _thread_init() function.
664 | *
665 | * @note It is invoked from within @p _thread_init() and implicitly from all
666 | * the threads creation APIs.
667 | */
668 | #define CH_CFG_THREAD_INIT_HOOK(tp) { \
669 | /* Add threads initialization code here.*/ \
670 | }
671 |
672 | /**
673 | * @brief Threads finalization hook.
674 | * @details User finalization code added to the @p chThdExit() API.
675 | */
676 | #define CH_CFG_THREAD_EXIT_HOOK(tp) { \
677 | /* Add threads finalization code here.*/ \
678 | }
679 |
680 | /**
681 | * @brief Context switch hook.
682 | * @details This hook is invoked just before switching between threads.
683 | */
684 | #define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) { \
685 | /* Context switch code here.*/ \
686 | }
687 |
688 | /**
689 | * @brief ISR enter hook.
690 | */
691 | #define CH_CFG_IRQ_PROLOGUE_HOOK() { \
692 | /* IRQ prologue code here.*/ \
693 | }
694 |
695 | /**
696 | * @brief ISR exit hook.
697 | */
698 | #define CH_CFG_IRQ_EPILOGUE_HOOK() { \
699 | /* IRQ epilogue code here.*/ \
700 | }
701 |
702 | /**
703 | * @brief Idle thread enter hook.
704 | * @note This hook is invoked within a critical zone, no OS functions
705 | * should be invoked from here.
706 | * @note This macro can be used to activate a power saving mode.
707 | */
708 | #define CH_CFG_IDLE_ENTER_HOOK() { \
709 | /* Idle-enter code here.*/ \
710 | }
711 |
712 | /**
713 | * @brief Idle thread leave hook.
714 | * @note This hook is invoked within a critical zone, no OS functions
715 | * should be invoked from here.
716 | * @note This macro can be used to deactivate a power saving mode.
717 | */
718 | #define CH_CFG_IDLE_LEAVE_HOOK() { \
719 | /* Idle-leave code here.*/ \
720 | }
721 |
722 | /**
723 | * @brief Idle Loop hook.
724 | * @details This hook is continuously invoked by the idle thread loop.
725 | */
726 | #define CH_CFG_IDLE_LOOP_HOOK() { \
727 | /* Idle loop code here.*/ \
728 | }
729 |
730 | /**
731 | * @brief System tick event hook.
732 | * @details This hook is invoked in the system tick handler immediately
733 | * after processing the virtual timers queue.
734 | */
735 | #define CH_CFG_SYSTEM_TICK_HOOK() { \
736 | /* System tick event code here.*/ \
737 | }
738 |
739 | /**
740 | * @brief System halt hook.
741 | * @details This hook is invoked in case to a system halting error before
742 | * the system is halted.
743 | */
744 | #define CH_CFG_SYSTEM_HALT_HOOK(reason) { \
745 | /* System halt code here.*/ \
746 | }
747 |
748 | /**
749 | * @brief Trace hook.
750 | * @details This hook is invoked each time a new record is written in the
751 | * trace buffer.
752 | */
753 | #define CH_CFG_TRACE_HOOK(tep) { \
754 | /* Trace code here.*/ \
755 | }
756 |
757 | /** @} */
758 |
759 | /*===========================================================================*/
760 | /* Port-specific settings (override port settings defaulted in chcore.h). */
761 | /*===========================================================================*/
762 |
763 | #endif /* CHCONF_H */
764 |
765 | /** @} */
766 |
--------------------------------------------------------------------------------
/firmware/cfg/halconf.h:
--------------------------------------------------------------------------------
1 | /*
2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | /**
18 | * @file templates/halconf.h
19 | * @brief HAL configuration header.
20 | * @details HAL configuration file, this file allows to enable or disable the
21 | * various device drivers from your application. You may also use
22 | * this file in order to override the device drivers default settings.
23 | *
24 | * @addtogroup HAL_CONF
25 | * @{
26 | */
27 |
28 | #ifndef HALCONF_H
29 | #define HALCONF_H
30 |
31 | #define _CHIBIOS_HAL_CONF_
32 | #define _CHIBIOS_HAL_CONF_VER_7_1_
33 |
34 | #include "mcuconf.h"
35 |
36 | /**
37 | * @brief Enables the PAL subsystem.
38 | */
39 | #if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
40 | #define HAL_USE_PAL TRUE
41 | #endif
42 |
43 | /**
44 | * @brief Enables the ADC subsystem.
45 | */
46 | #if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
47 | #define HAL_USE_ADC FALSE
48 | #endif
49 |
50 | /**
51 | * @brief Enables the CAN subsystem.
52 | */
53 | #if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
54 | #define HAL_USE_CAN FALSE
55 | #endif
56 |
57 | /**
58 | * @brief Enables the cryptographic subsystem.
59 | */
60 | #if !defined(HAL_USE_CRY) || defined(__DOXYGEN__)
61 | #define HAL_USE_CRY FALSE
62 | #endif
63 |
64 | /**
65 | * @brief Enables the DAC subsystem.
66 | */
67 | #if !defined(HAL_USE_DAC) || defined(__DOXYGEN__)
68 | #define HAL_USE_DAC FALSE
69 | #endif
70 |
71 | /**
72 | * @brief Enables the EFlash subsystem.
73 | */
74 | #if !defined(HAL_USE_EFL) || defined(__DOXYGEN__)
75 | #define HAL_USE_EFL FALSE
76 | #endif
77 |
78 | /**
79 | * @brief Enables the GPT subsystem.
80 | */
81 | #if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
82 | #define HAL_USE_GPT FALSE
83 | #endif
84 |
85 | /**
86 | * @brief Enables the I2C subsystem.
87 | */
88 | #if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
89 | #define HAL_USE_I2C FALSE
90 | #endif
91 |
92 | /**
93 | * @brief Enables the I2S subsystem.
94 | */
95 | #if !defined(HAL_USE_I2S) || defined(__DOXYGEN__)
96 | #define HAL_USE_I2S FALSE
97 | #endif
98 |
99 | /**
100 | * @brief Enables the ICU subsystem.
101 | */
102 | #if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
103 | #define HAL_USE_ICU FALSE
104 | #endif
105 |
106 | /**
107 | * @brief Enables the MAC subsystem.
108 | */
109 | #if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
110 | #define HAL_USE_MAC TRUE
111 | #endif
112 |
113 | /**
114 | * @brief Enables the MMC_SPI subsystem.
115 | */
116 | #if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
117 | #define HAL_USE_MMC_SPI FALSE
118 | #endif
119 |
120 | /**
121 | * @brief Enables the PWM subsystem.
122 | */
123 | #if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
124 | #define HAL_USE_PWM FALSE
125 | #endif
126 |
127 | /**
128 | * @brief Enables the RTC subsystem.
129 | */
130 | #if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
131 | #define HAL_USE_RTC TRUE
132 | #endif
133 |
134 | /**
135 | * @brief Enables the SDC subsystem.
136 | */
137 | #if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
138 | #define HAL_USE_SDC FALSE
139 | #endif
140 |
141 | /**
142 | * @brief Enables the SERIAL subsystem.
143 | */
144 | #if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
145 | #define HAL_USE_SERIAL TRUE
146 | #endif
147 |
148 | /**
149 | * @brief Enables the SERIAL over USB subsystem.
150 | */
151 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
152 | #define HAL_USE_SERIAL_USB FALSE
153 | #endif
154 |
155 | /**
156 | * @brief Enables the SIO subsystem.
157 | */
158 | #if !defined(HAL_USE_SIO) || defined(__DOXYGEN__)
159 | #define HAL_USE_SIO FALSE
160 | #endif
161 |
162 | /**
163 | * @brief Enables the SPI subsystem.
164 | */
165 | #if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
166 | #define HAL_USE_SPI FALSE
167 | #endif
168 |
169 | /**
170 | * @brief Enables the TRNG subsystem.
171 | */
172 | #if !defined(HAL_USE_TRNG) || defined(__DOXYGEN__)
173 | #define HAL_USE_TRNG FALSE
174 | #endif
175 |
176 | /**
177 | * @brief Enables the UART subsystem.
178 | */
179 | #if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
180 | #define HAL_USE_UART FALSE
181 | #endif
182 |
183 | /**
184 | * @brief Enables the USB subsystem.
185 | */
186 | #if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
187 | #define HAL_USE_USB FALSE
188 | #endif
189 |
190 | /**
191 | * @brief Enables the WDG subsystem.
192 | */
193 | #if !defined(HAL_USE_WDG) || defined(__DOXYGEN__)
194 | #define HAL_USE_WDG TRUE
195 | #endif
196 |
197 | /**
198 | * @brief Enables the WSPI subsystem.
199 | */
200 | #if !defined(HAL_USE_WSPI) || defined(__DOXYGEN__)
201 | #define HAL_USE_WSPI FALSE
202 | #endif
203 |
204 | /*===========================================================================*/
205 | /* PAL driver related settings. */
206 | /*===========================================================================*/
207 |
208 | /**
209 | * @brief Enables synchronous APIs.
210 | * @note Disabling this option saves both code and data space.
211 | */
212 | #if !defined(PAL_USE_CALLBACKS) || defined(__DOXYGEN__)
213 | #define PAL_USE_CALLBACKS TRUE
214 | #endif
215 |
216 | /**
217 | * @brief Enables synchronous APIs.
218 | * @note Disabling this option saves both code and data space.
219 | */
220 | #if !defined(PAL_USE_WAIT) || defined(__DOXYGEN__)
221 | #define PAL_USE_WAIT FALSE
222 | #endif
223 |
224 | /*===========================================================================*/
225 | /* ADC driver related settings. */
226 | /*===========================================================================*/
227 |
228 | /**
229 | * @brief Enables synchronous APIs.
230 | * @note Disabling this option saves both code and data space.
231 | */
232 | #if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
233 | #define ADC_USE_WAIT TRUE
234 | #endif
235 |
236 | /**
237 | * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
238 | * @note Disabling this option saves both code and data space.
239 | */
240 | #if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
241 | #define ADC_USE_MUTUAL_EXCLUSION TRUE
242 | #endif
243 |
244 | /*===========================================================================*/
245 | /* CAN driver related settings. */
246 | /*===========================================================================*/
247 |
248 | /**
249 | * @brief Sleep mode related APIs inclusion switch.
250 | */
251 | #if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
252 | #define CAN_USE_SLEEP_MODE TRUE
253 | #endif
254 |
255 | /**
256 | * @brief Enforces the driver to use direct callbacks rather than OSAL events.
257 | */
258 | #if !defined(CAN_ENFORCE_USE_CALLBACKS) || defined(__DOXYGEN__)
259 | #define CAN_ENFORCE_USE_CALLBACKS FALSE
260 | #endif
261 |
262 | /*===========================================================================*/
263 | /* CRY driver related settings. */
264 | /*===========================================================================*/
265 |
266 | /**
267 | * @brief Enables the SW fall-back of the cryptographic driver.
268 | * @details When enabled, this option, activates a fall-back software
269 | * implementation for algorithms not supported by the underlying
270 | * hardware.
271 | * @note Fall-back implementations may not be present for all algorithms.
272 | */
273 | #if !defined(HAL_CRY_USE_FALLBACK) || defined(__DOXYGEN__)
274 | #define HAL_CRY_USE_FALLBACK FALSE
275 | #endif
276 |
277 | /**
278 | * @brief Makes the driver forcibly use the fall-back implementations.
279 | */
280 | #if !defined(HAL_CRY_ENFORCE_FALLBACK) || defined(__DOXYGEN__)
281 | #define HAL_CRY_ENFORCE_FALLBACK FALSE
282 | #endif
283 |
284 | /*===========================================================================*/
285 | /* DAC driver related settings. */
286 | /*===========================================================================*/
287 |
288 | /**
289 | * @brief Enables synchronous APIs.
290 | * @note Disabling this option saves both code and data space.
291 | */
292 | #if !defined(DAC_USE_WAIT) || defined(__DOXYGEN__)
293 | #define DAC_USE_WAIT TRUE
294 | #endif
295 |
296 | /**
297 | * @brief Enables the @p dacAcquireBus() and @p dacReleaseBus() APIs.
298 | * @note Disabling this option saves both code and data space.
299 | */
300 | #if !defined(DAC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
301 | #define DAC_USE_MUTUAL_EXCLUSION TRUE
302 | #endif
303 |
304 | /*===========================================================================*/
305 | /* I2C driver related settings. */
306 | /*===========================================================================*/
307 |
308 | /**
309 | * @brief Enables the mutual exclusion APIs on the I2C bus.
310 | */
311 | #if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
312 | #define I2C_USE_MUTUAL_EXCLUSION TRUE
313 | #endif
314 |
315 | /*===========================================================================*/
316 | /* MAC driver related settings. */
317 | /*===========================================================================*/
318 |
319 | /**
320 | * @brief Enables the zero-copy API.
321 | */
322 | #if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
323 | #define MAC_USE_ZERO_COPY FALSE
324 | #endif
325 |
326 | /**
327 | * @brief Enables an event sources for incoming packets.
328 | */
329 | #if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
330 | #define MAC_USE_EVENTS TRUE
331 | #endif
332 |
333 | /*===========================================================================*/
334 | /* MMC_SPI driver related settings. */
335 | /*===========================================================================*/
336 |
337 | /**
338 | * @brief Delays insertions.
339 | * @details If enabled this options inserts delays into the MMC waiting
340 | * routines releasing some extra CPU time for the threads with
341 | * lower priority, this may slow down the driver a bit however.
342 | * This option is recommended also if the SPI driver does not
343 | * use a DMA channel and heavily loads the CPU.
344 | */
345 | #if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
346 | #define MMC_NICE_WAITING TRUE
347 | #endif
348 |
349 | /*===========================================================================*/
350 | /* SDC driver related settings. */
351 | /*===========================================================================*/
352 |
353 | /**
354 | * @brief Number of initialization attempts before rejecting the card.
355 | * @note Attempts are performed at 10mS intervals.
356 | */
357 | #if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
358 | #define SDC_INIT_RETRY 100
359 | #endif
360 |
361 | /**
362 | * @brief Include support for MMC cards.
363 | * @note MMC support is not yet implemented so this option must be kept
364 | * at @p FALSE.
365 | */
366 | #if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
367 | #define SDC_MMC_SUPPORT FALSE
368 | #endif
369 |
370 | /**
371 | * @brief Delays insertions.
372 | * @details If enabled this options inserts delays into the MMC waiting
373 | * routines releasing some extra CPU time for the threads with
374 | * lower priority, this may slow down the driver a bit however.
375 | */
376 | #if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
377 | #define SDC_NICE_WAITING TRUE
378 | #endif
379 |
380 | /**
381 | * @brief OCR initialization constant for V20 cards.
382 | */
383 | #if !defined(SDC_INIT_OCR_V20) || defined(__DOXYGEN__)
384 | #define SDC_INIT_OCR_V20 0x50FF8000U
385 | #endif
386 |
387 | /**
388 | * @brief OCR initialization constant for non-V20 cards.
389 | */
390 | #if !defined(SDC_INIT_OCR) || defined(__DOXYGEN__)
391 | #define SDC_INIT_OCR 0x80100000U
392 | #endif
393 |
394 | /*===========================================================================*/
395 | /* SERIAL driver related settings. */
396 | /*===========================================================================*/
397 |
398 | /**
399 | * @brief Default bit rate.
400 | * @details Configuration parameter, this is the baud rate selected for the
401 | * default configuration.
402 | */
403 | #if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
404 | #define SERIAL_DEFAULT_BITRATE 38400
405 | #endif
406 |
407 | /**
408 | * @brief Serial buffers size.
409 | * @details Configuration parameter, you can change the depth of the queue
410 | * buffers depending on the requirements of your application.
411 | * @note The default is 16 bytes for both the transmission and receive
412 | * buffers.
413 | */
414 | #if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
415 | #define SERIAL_BUFFERS_SIZE 16
416 | #endif
417 |
418 | /*===========================================================================*/
419 | /* SERIAL_USB driver related setting. */
420 | /*===========================================================================*/
421 |
422 | /**
423 | * @brief Serial over USB buffers size.
424 | * @details Configuration parameter, the buffer size must be a multiple of
425 | * the USB data endpoint maximum packet size.
426 | * @note The default is 256 bytes for both the transmission and receive
427 | * buffers.
428 | */
429 | #if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__)
430 | #define SERIAL_USB_BUFFERS_SIZE 256
431 | #endif
432 |
433 | /**
434 | * @brief Serial over USB number of buffers.
435 | * @note The default is 2 buffers.
436 | */
437 | #if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__)
438 | #define SERIAL_USB_BUFFERS_NUMBER 2
439 | #endif
440 |
441 | /*===========================================================================*/
442 | /* SPI driver related settings. */
443 | /*===========================================================================*/
444 |
445 | /**
446 | * @brief Enables synchronous APIs.
447 | * @note Disabling this option saves both code and data space.
448 | */
449 | #if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
450 | #define SPI_USE_WAIT TRUE
451 | #endif
452 |
453 | /**
454 | * @brief Enables circular transfers APIs.
455 | * @note Disabling this option saves both code and data space.
456 | */
457 | #if !defined(SPI_USE_CIRCULAR) || defined(__DOXYGEN__)
458 | #define SPI_USE_CIRCULAR FALSE
459 | #endif
460 |
461 | /**
462 | * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
463 | * @note Disabling this option saves both code and data space.
464 | */
465 | #if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
466 | #define SPI_USE_MUTUAL_EXCLUSION TRUE
467 | #endif
468 |
469 | /**
470 | * @brief Handling method for SPI CS line.
471 | * @note Disabling this option saves both code and data space.
472 | */
473 | #if !defined(SPI_SELECT_MODE) || defined(__DOXYGEN__)
474 | #define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
475 | #endif
476 |
477 | /*===========================================================================*/
478 | /* UART driver related settings. */
479 | /*===========================================================================*/
480 |
481 | /**
482 | * @brief Enables synchronous APIs.
483 | * @note Disabling this option saves both code and data space.
484 | */
485 | #if !defined(UART_USE_WAIT) || defined(__DOXYGEN__)
486 | #define UART_USE_WAIT FALSE
487 | #endif
488 |
489 | /**
490 | * @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs.
491 | * @note Disabling this option saves both code and data space.
492 | */
493 | #if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
494 | #define UART_USE_MUTUAL_EXCLUSION FALSE
495 | #endif
496 |
497 | /*===========================================================================*/
498 | /* USB driver related settings. */
499 | /*===========================================================================*/
500 |
501 | /**
502 | * @brief Enables synchronous APIs.
503 | * @note Disabling this option saves both code and data space.
504 | */
505 | #if !defined(USB_USE_WAIT) || defined(__DOXYGEN__)
506 | #define USB_USE_WAIT FALSE
507 | #endif
508 |
509 | /*===========================================================================*/
510 | /* WSPI driver related settings. */
511 | /*===========================================================================*/
512 |
513 | /**
514 | * @brief Enables synchronous APIs.
515 | * @note Disabling this option saves both code and data space.
516 | */
517 | #if !defined(WSPI_USE_WAIT) || defined(__DOXYGEN__)
518 | #define WSPI_USE_WAIT TRUE
519 | #endif
520 |
521 | /**
522 | * @brief Enables the @p wspiAcquireBus() and @p wspiReleaseBus() APIs.
523 | * @note Disabling this option saves both code and data space.
524 | */
525 | #if !defined(WSPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
526 | #define WSPI_USE_MUTUAL_EXCLUSION TRUE
527 | #endif
528 |
529 | #endif /* HALCONF_H */
530 |
531 | /** @} */
532 |
--------------------------------------------------------------------------------
/firmware/cfg/mcuconf.h:
--------------------------------------------------------------------------------
1 | /*
2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #ifndef MCUCONF_H
18 | #define MCUCONF_H
19 |
20 | /*
21 | * STM32F4xx drivers configuration.
22 | * The following settings override the default settings present in
23 | * the various device driver implementation headers.
24 | * Note that the settings for each driver only have effect if the whole
25 | * driver is enabled in halconf.h.
26 | *
27 | * IRQ priorities:
28 | * 15...0 Lowest...Highest.
29 | *
30 | * DMA priorities:
31 | * 0...3 Lowest...Highest.
32 | */
33 |
34 | #define STM32F4xx_MCUCONF
35 |
36 | /*
37 | * HAL driver system settings.
38 | */
39 | #define STM32_NO_INIT FALSE
40 | #define STM32_HSI_ENABLED TRUE
41 | #define STM32_LSI_ENABLED TRUE
42 | #define STM32_HSE_ENABLED TRUE
43 | #define STM32_LSE_ENABLED TRUE
44 | #define STM32_CLOCK48_REQUIRED TRUE
45 | #define STM32_SW STM32_SW_PLL
46 | #define STM32_PLLSRC STM32_PLLSRC_HSE
47 | #define STM32_PLLM_VALUE 8
48 | #define STM32_PLLN_VALUE 336
49 | #define STM32_PLLP_VALUE 2
50 | #define STM32_PLLQ_VALUE 7
51 | #define STM32_HPRE STM32_HPRE_DIV1
52 | #define STM32_PPRE1 STM32_PPRE1_DIV4
53 | #define STM32_PPRE2 STM32_PPRE2_DIV2
54 | #define STM32_RTCSEL STM32_RTCSEL_LSE
55 | #define STM32_RTCPRE_VALUE 8
56 | #define STM32_MCO1SEL STM32_MCO1SEL_HSI
57 | #define STM32_MCO1PRE STM32_MCO1PRE_DIV1
58 | #define STM32_MCO2SEL STM32_MCO2SEL_SYSCLK
59 | #define STM32_MCO2PRE STM32_MCO2PRE_DIV5
60 | #define STM32_I2SSRC STM32_I2SSRC_CKIN
61 | #define STM32_PLLI2SN_VALUE 192
62 | #define STM32_PLLI2SR_VALUE 5
63 | #define STM32_PVD_ENABLE FALSE
64 | #define STM32_PLS STM32_PLS_LEV0
65 | #define STM32_BKPRAM_ENABLE FALSE
66 |
67 | /*
68 | * IRQ system settings.
69 | */
70 | #define STM32_IRQ_EXTI0_PRIORITY 6
71 | #define STM32_IRQ_EXTI1_PRIORITY 6
72 | #define STM32_IRQ_EXTI2_PRIORITY 6
73 | #define STM32_IRQ_EXTI3_PRIORITY 6
74 | #define STM32_IRQ_EXTI4_PRIORITY 6
75 | #define STM32_IRQ_EXTI5_9_PRIORITY 6
76 | #define STM32_IRQ_EXTI10_15_PRIORITY 6
77 | #define STM32_IRQ_EXTI16_PRIORITY 6
78 | #define STM32_IRQ_EXTI17_PRIORITY 15
79 | #define STM32_IRQ_EXTI18_PRIORITY 6
80 | #define STM32_IRQ_EXTI19_PRIORITY 6
81 | #define STM32_IRQ_EXTI20_PRIORITY 6
82 | #define STM32_IRQ_EXTI21_PRIORITY 15
83 | #define STM32_IRQ_EXTI22_PRIORITY 15
84 |
85 | /*
86 | * ADC driver system settings.
87 | */
88 | #define STM32_ADC_ADCPRE ADC_CCR_ADCPRE_DIV4
89 | #define STM32_ADC_USE_ADC1 FALSE
90 | #define STM32_ADC_USE_ADC2 FALSE
91 | #define STM32_ADC_USE_ADC3 FALSE
92 | #define STM32_ADC_ADC1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4)
93 | #define STM32_ADC_ADC2_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
94 | #define STM32_ADC_ADC3_DMA_STREAM STM32_DMA_STREAM_ID(2, 1)
95 | #define STM32_ADC_ADC1_DMA_PRIORITY 2
96 | #define STM32_ADC_ADC2_DMA_PRIORITY 2
97 | #define STM32_ADC_ADC3_DMA_PRIORITY 2
98 | #define STM32_ADC_IRQ_PRIORITY 6
99 | #define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 6
100 | #define STM32_ADC_ADC2_DMA_IRQ_PRIORITY 6
101 | #define STM32_ADC_ADC3_DMA_IRQ_PRIORITY 6
102 |
103 | /*
104 | * CAN driver system settings.
105 | */
106 | #define STM32_CAN_USE_CAN1 FALSE
107 | #define STM32_CAN_USE_CAN2 FALSE
108 | #define STM32_CAN_CAN1_IRQ_PRIORITY 11
109 | #define STM32_CAN_CAN2_IRQ_PRIORITY 11
110 |
111 | /*
112 | * DAC driver system settings.
113 | */
114 | #define STM32_DAC_DUAL_MODE FALSE
115 | #define STM32_DAC_USE_DAC1_CH1 FALSE
116 | #define STM32_DAC_USE_DAC1_CH2 FALSE
117 | #define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10
118 | #define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10
119 | #define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2
120 | #define STM32_DAC_DAC1_CH2_DMA_PRIORITY 2
121 | #define STM32_DAC_DAC1_CH1_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
122 | #define STM32_DAC_DAC1_CH2_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
123 |
124 | /*
125 | * GPT driver system settings.
126 | */
127 | #define STM32_GPT_USE_TIM1 FALSE
128 | #define STM32_GPT_USE_TIM2 FALSE
129 | #define STM32_GPT_USE_TIM3 FALSE
130 | #define STM32_GPT_USE_TIM4 FALSE
131 | #define STM32_GPT_USE_TIM5 FALSE
132 | #define STM32_GPT_USE_TIM6 FALSE
133 | #define STM32_GPT_USE_TIM7 FALSE
134 | #define STM32_GPT_USE_TIM8 FALSE
135 | #define STM32_GPT_USE_TIM9 FALSE
136 | #define STM32_GPT_USE_TIM11 FALSE
137 | #define STM32_GPT_USE_TIM12 FALSE
138 | #define STM32_GPT_USE_TIM14 FALSE
139 | #define STM32_GPT_TIM1_IRQ_PRIORITY 7
140 | #define STM32_GPT_TIM2_IRQ_PRIORITY 7
141 | #define STM32_GPT_TIM3_IRQ_PRIORITY 7
142 | #define STM32_GPT_TIM4_IRQ_PRIORITY 7
143 | #define STM32_GPT_TIM5_IRQ_PRIORITY 7
144 | #define STM32_GPT_TIM6_IRQ_PRIORITY 7
145 | #define STM32_GPT_TIM7_IRQ_PRIORITY 7
146 | #define STM32_GPT_TIM8_IRQ_PRIORITY 7
147 | #define STM32_GPT_TIM9_IRQ_PRIORITY 7
148 | #define STM32_GPT_TIM11_IRQ_PRIORITY 7
149 | #define STM32_GPT_TIM12_IRQ_PRIORITY 7
150 | #define STM32_GPT_TIM14_IRQ_PRIORITY 7
151 |
152 | /*
153 | * I2C driver system settings.
154 | */
155 | #define STM32_I2C_USE_I2C1 FALSE
156 | #define STM32_I2C_USE_I2C2 FALSE
157 | #define STM32_I2C_USE_I2C3 FALSE
158 | #define STM32_I2C_BUSY_TIMEOUT 50
159 | #define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
160 | #define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
161 | #define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
162 | #define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
163 | #define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
164 | #define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
165 | #define STM32_I2C_I2C1_IRQ_PRIORITY 5
166 | #define STM32_I2C_I2C2_IRQ_PRIORITY 5
167 | #define STM32_I2C_I2C3_IRQ_PRIORITY 5
168 | #define STM32_I2C_I2C1_DMA_PRIORITY 3
169 | #define STM32_I2C_I2C2_DMA_PRIORITY 3
170 | #define STM32_I2C_I2C3_DMA_PRIORITY 3
171 | #define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
172 |
173 | /*
174 | * I2S driver system settings.
175 | */
176 | #define STM32_I2S_USE_SPI2 FALSE
177 | #define STM32_I2S_USE_SPI3 FALSE
178 | #define STM32_I2S_SPI2_IRQ_PRIORITY 10
179 | #define STM32_I2S_SPI3_IRQ_PRIORITY 10
180 | #define STM32_I2S_SPI2_DMA_PRIORITY 1
181 | #define STM32_I2S_SPI3_DMA_PRIORITY 1
182 | #define STM32_I2S_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
183 | #define STM32_I2S_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
184 | #define STM32_I2S_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
185 | #define STM32_I2S_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
186 | #define STM32_I2S_DMA_ERROR_HOOK(i2sp) osalSysHalt("DMA failure")
187 |
188 | /*
189 | * ICU driver system settings.
190 | */
191 | #define STM32_ICU_USE_TIM1 FALSE
192 | #define STM32_ICU_USE_TIM2 FALSE
193 | #define STM32_ICU_USE_TIM3 FALSE
194 | #define STM32_ICU_USE_TIM4 FALSE
195 | #define STM32_ICU_USE_TIM5 FALSE
196 | #define STM32_ICU_USE_TIM8 FALSE
197 | #define STM32_ICU_USE_TIM9 FALSE
198 | #define STM32_ICU_TIM1_IRQ_PRIORITY 7
199 | #define STM32_ICU_TIM2_IRQ_PRIORITY 7
200 | #define STM32_ICU_TIM3_IRQ_PRIORITY 7
201 | #define STM32_ICU_TIM4_IRQ_PRIORITY 7
202 | #define STM32_ICU_TIM5_IRQ_PRIORITY 7
203 | #define STM32_ICU_TIM8_IRQ_PRIORITY 7
204 | #define STM32_ICU_TIM9_IRQ_PRIORITY 7
205 |
206 | /*
207 | * MAC driver system settings.
208 | */
209 | #define STM32_MAC_TRANSMIT_BUFFERS 2
210 | #define STM32_MAC_RECEIVE_BUFFERS 4
211 | #define STM32_MAC_BUFFERS_SIZE 1522
212 | #define STM32_MAC_PHY_TIMEOUT 100
213 | #define STM32_MAC_ETH1_CHANGE_PHY_STATE TRUE
214 | #define STM32_MAC_ETH1_IRQ_PRIORITY 13
215 | #define STM32_MAC_IP_CHECKSUM_OFFLOAD 0
216 |
217 | /*
218 | * PWM driver system settings.
219 | */
220 | #define STM32_PWM_USE_ADVANCED FALSE
221 | #define STM32_PWM_USE_TIM1 FALSE
222 | #define STM32_PWM_USE_TIM2 FALSE
223 | #define STM32_PWM_USE_TIM3 FALSE
224 | #define STM32_PWM_USE_TIM4 FALSE
225 | #define STM32_PWM_USE_TIM5 FALSE
226 | #define STM32_PWM_USE_TIM8 FALSE
227 | #define STM32_PWM_USE_TIM9 FALSE
228 | #define STM32_PWM_TIM1_IRQ_PRIORITY 7
229 | #define STM32_PWM_TIM2_IRQ_PRIORITY 7
230 | #define STM32_PWM_TIM3_IRQ_PRIORITY 7
231 | #define STM32_PWM_TIM4_IRQ_PRIORITY 7
232 | #define STM32_PWM_TIM5_IRQ_PRIORITY 7
233 | #define STM32_PWM_TIM8_IRQ_PRIORITY 7
234 | #define STM32_PWM_TIM9_IRQ_PRIORITY 7
235 |
236 | /*
237 | * SDC driver system settings.
238 | */
239 | #define STM32_SDC_SDIO_DMA_PRIORITY 3
240 | #define STM32_SDC_SDIO_IRQ_PRIORITY 9
241 | #define STM32_SDC_WRITE_TIMEOUT_MS 1000
242 | #define STM32_SDC_READ_TIMEOUT_MS 1000
243 | #define STM32_SDC_CLOCK_ACTIVATION_DELAY 10
244 | #define STM32_SDC_SDIO_UNALIGNED_SUPPORT TRUE
245 | #define STM32_SDC_SDIO_DMA_STREAM STM32_DMA_STREAM_ID(2, 3)
246 |
247 | /*
248 | * SERIAL driver system settings.
249 | */
250 | #define STM32_SERIAL_USE_USART1 FALSE
251 | #define STM32_SERIAL_USE_USART2 FALSE
252 | #define STM32_SERIAL_USE_USART3 TRUE
253 | #define STM32_SERIAL_USE_UART4 FALSE
254 | #define STM32_SERIAL_USE_UART5 FALSE
255 | #define STM32_SERIAL_USE_USART6 FALSE
256 | #define STM32_SERIAL_USE_UART7 FALSE
257 | #define STM32_SERIAL_USE_UART8 FALSE
258 | #define STM32_SERIAL_USART1_PRIORITY 12
259 | #define STM32_SERIAL_USART2_PRIORITY 12
260 | #define STM32_SERIAL_USART3_PRIORITY 12
261 | #define STM32_SERIAL_UART4_PRIORITY 12
262 | #define STM32_SERIAL_UART5_PRIORITY 12
263 | #define STM32_SERIAL_USART6_PRIORITY 12
264 | #define STM32_SERIAL_UART7_PRIORITY 12
265 | #define STM32_SERIAL_UART8_PRIORITY 12
266 |
267 | /*
268 | * SPI driver system settings.
269 | */
270 | #define STM32_SPI_USE_SPI1 FALSE
271 | #define STM32_SPI_USE_SPI2 FALSE
272 | #define STM32_SPI_USE_SPI3 FALSE
273 | #define STM32_SPI_USE_SPI4 FALSE
274 | #define STM32_SPI_USE_SPI5 FALSE
275 | #define STM32_SPI_USE_SPI6 FALSE
276 | #define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0)
277 | #define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3)
278 | #define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
279 | #define STM32_SPI_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
280 | #define STM32_SPI_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
281 | #define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
282 | #define STM32_SPI_SPI4_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0)
283 | #define STM32_SPI_SPI4_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 1)
284 | #define STM32_SPI_SPI5_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3)
285 | #define STM32_SPI_SPI5_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 4)
286 | #define STM32_SPI_SPI6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 6)
287 | #define STM32_SPI_SPI6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5)
288 | #define STM32_SPI_SPI1_DMA_PRIORITY 1
289 | #define STM32_SPI_SPI2_DMA_PRIORITY 1
290 | #define STM32_SPI_SPI3_DMA_PRIORITY 1
291 | #define STM32_SPI_SPI4_DMA_PRIORITY 1
292 | #define STM32_SPI_SPI5_DMA_PRIORITY 1
293 | #define STM32_SPI_SPI6_DMA_PRIORITY 1
294 | #define STM32_SPI_SPI1_IRQ_PRIORITY 10
295 | #define STM32_SPI_SPI2_IRQ_PRIORITY 10
296 | #define STM32_SPI_SPI3_IRQ_PRIORITY 10
297 | #define STM32_SPI_SPI4_IRQ_PRIORITY 10
298 | #define STM32_SPI_SPI5_IRQ_PRIORITY 10
299 | #define STM32_SPI_SPI6_IRQ_PRIORITY 10
300 | #define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
301 |
302 | /*
303 | * ST driver system settings.
304 | */
305 | #define STM32_ST_IRQ_PRIORITY 8
306 | #define STM32_ST_USE_TIMER 2
307 |
308 | /*
309 | * UART driver system settings.
310 | */
311 | #define STM32_UART_USE_USART1 FALSE
312 | #define STM32_UART_USE_USART2 FALSE
313 | #define STM32_UART_USE_USART3 FALSE
314 | #define STM32_UART_USE_UART4 FALSE
315 | #define STM32_UART_USE_UART5 FALSE
316 | #define STM32_UART_USE_USART6 FALSE
317 | #define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5)
318 | #define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
319 | #define STM32_UART_USART2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
320 | #define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
321 | #define STM32_UART_USART3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 1)
322 | #define STM32_UART_USART3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
323 | #define STM32_UART_UART4_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
324 | #define STM32_UART_UART4_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
325 | #define STM32_UART_UART5_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
326 | #define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
327 | #define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
328 | #define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
329 | #define STM32_UART_USART1_IRQ_PRIORITY 12
330 | #define STM32_UART_USART2_IRQ_PRIORITY 12
331 | #define STM32_UART_USART3_IRQ_PRIORITY 12
332 | #define STM32_UART_UART4_IRQ_PRIORITY 12
333 | #define STM32_UART_UART5_IRQ_PRIORITY 12
334 | #define STM32_UART_USART6_IRQ_PRIORITY 12
335 | #define STM32_UART_USART1_DMA_PRIORITY 0
336 | #define STM32_UART_USART2_DMA_PRIORITY 0
337 | #define STM32_UART_USART3_DMA_PRIORITY 0
338 | #define STM32_UART_UART4_DMA_PRIORITY 0
339 | #define STM32_UART_UART5_DMA_PRIORITY 0
340 | #define STM32_UART_USART6_DMA_PRIORITY 0
341 | #define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure")
342 |
343 | /*
344 | * USB driver system settings.
345 | */
346 | #define STM32_USB_USE_OTG1 FALSE
347 | #define STM32_USB_USE_OTG2 FALSE
348 | #define STM32_USB_OTG1_IRQ_PRIORITY 14
349 | #define STM32_USB_OTG2_IRQ_PRIORITY 14
350 | #define STM32_USB_OTG1_RX_FIFO_SIZE 512
351 | #define STM32_USB_OTG2_RX_FIFO_SIZE 1024
352 | #define STM32_USB_OTG_THREAD_PRIO LOWPRIO
353 | #define STM32_USB_OTG_THREAD_STACK_SIZE 128
354 | #define STM32_USB_OTGFIFO_FILL_BASEPRI 0
355 |
356 | /*
357 | * WDG driver system settings.
358 | */
359 | #define STM32_WDG_USE_IWDG TRUE
360 |
361 | #endif /* MCUCONF_H */
362 |
--------------------------------------------------------------------------------
/firmware/config.h:
--------------------------------------------------------------------------------
1 | #ifndef __NTPD_CONFIG_H__
2 | #define __NTPD_CONFIG_H__
3 |
4 | #define GNSS_AID_POSITION
5 | #define GNSS_AID_POS_LATITUDE (51.2500 / 1e-7)
6 | #define GNSS_AID_POS_LONGITUDE (-0.5946 / 1e-7)
7 | #define GNSS_AID_POS_ALTITUDE (60 / 1e-2) // 60m
8 | #define GNSS_AID_POS_STDDEV (199 / 1e-5) // 199km
9 |
10 | #define NTPD_STRATUM_DEMOTE_TIMER_PERIOD TIME_S2I(10*60) // 10 minutes
11 |
12 | #define NTPD_STATUS_DEMOTE_TIMER_PERIOD TIME_MS2I(1200) // 10 minutes
13 |
14 | #endif /* __NTPD_CONFIG_H__ */
--------------------------------------------------------------------------------
/firmware/debug:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source_dir="$(cd $(dirname ${BASH_SOURCE[0]}) && pwd)"
4 | cd "$source_dir"
5 |
6 | COLOUR_GREEN='\033[0;32m'
7 | COLOUR_YELLOW='\033[1;33m'
8 | COLOUR_PURPLE='\033[0;35m'
9 | COLOUR_RED='\033[0;31m'
10 | COLOUR_OFF='\033[0;00m'
11 | CLEAR_LINE='\033[2K'
12 |
13 | _ERROR_="${COLOUR_RED}[ERROR]${COLOUR_OFF}"
14 | _INFO_="${COLOUR_PURPLE}[INFO]${COLOUR_OFF}"
15 | _DEBUG_="${COLOUR_YELLOW}[DEBUG]${COLOUR_OFF}"
16 |
17 | flashtool="arm-none-eabi-gdb"
18 | programmer=false
19 |
20 | locate_black_magic() {
21 | probe="`ls 2>/dev/null -Ub1 -- /dev/serial/by-id/usb-Black_Sphere_Technologies_Black_Magic_Probe_*-if00 | head -n 1`"
22 | if ! [ -z "$probe" ]
23 | then
24 | echo "$probe"
25 | return 0
26 | fi
27 | return 1
28 | }
29 | debug_target() {
30 | $flashtool -q \
31 | -ex 'file '$binary \
32 | -ex 'target extended-remote '$programmer \
33 | -ex 'monitor tpwr $programmer_power' \
34 | -ex 'monitor swdp_scan' \
35 | -ex 'attach 1' \
36 | -ex 'set mem inaccessible-by-default off' \
37 | -ex 'load '$binary \
38 | -ex 'compare-sections'
39 | }
40 |
41 | debug_target_st-util() {
42 | $flashtool -q \
43 | -ex 'file '$binary \
44 | -ex 'set remote hardware-breakpoint-limit 8'\
45 | -ex 'set remote hardware-watchpoint-limit 4'\
46 | -ex 'set remotetimeout 10000' \
47 | -ex 'set remote interrupt-on-connect off' \
48 | -ex 'set mem inaccessible-by-default off' \
49 | -ex 'target extended-remote localhost:4242' \
50 | -ex 'load '$binary
51 | }
52 |
53 | debug_target_openocd() {
54 | $flashtool -q \
55 | -ex 'file '$binary \
56 | -ex 'set remote hardware-breakpoint-limit 8'\
57 | -ex 'set remote hardware-watchpoint-limit 4'\
58 | -ex 'set remotetimeout 10000' \
59 | -ex 'set remote interrupt-on-connect off' \
60 | -ex 'set mem inaccessible-by-default off' \
61 | -ex 'target extended-remote localhost:3333' \
62 | -ex 'load '$binary
63 | }
64 |
65 | binary="${1}.elf"
66 |
67 | if [ "$binary" == ".elf" ]; then
68 | binary="$(ls -t builds/*.elf | head -1)"
69 | echo -e "$_INFO_ Most recent build selected: ${binary}"
70 | fi
71 |
72 | if [[ ! -f $binary ]]; then
73 | echo -e "$_ERROR_ Binary $binary not found!"
74 | exit 1
75 | fi
76 |
77 | if programmer="`locate_black_magic`";
78 | then
79 | debug_target;
80 | else
81 | debug_target_openocd;
82 | fi
83 |
--------------------------------------------------------------------------------
/firmware/debug_udp.c:
--------------------------------------------------------------------------------
1 | #include "main.h"
2 |
3 | #include
4 |
5 | #include
6 |
7 | typedef struct {
8 | bool waiting;
9 | uint8_t rawFrame[64];
10 | mutex_t mutex;
11 | condition_variable_t condition;
12 | } udp_tx_queue_t;
13 |
14 | static udp_tx_queue_t udp_tx_queue =
15 | {
16 | .waiting = false,
17 | .mutex = _MUTEX_DATA(udp_tx_queue.mutex),
18 | .condition = _CONDVAR_DATA(udp_tx_queue.condition)
19 | };
20 |
21 | static struct udp_pcb *debug_udp_tx_pcb_ptr = NULL;
22 | static struct pbuf *debug_udp_pbuf_ptr;
23 |
24 | static void _udp_tx(void *arg)
25 | {
26 | (void)arg;
27 |
28 | if(debug_udp_tx_pcb_ptr == NULL)
29 | {
30 | debug_udp_tx_pcb_ptr = udp_new();
31 | }
32 |
33 | udp_sendto(debug_udp_tx_pcb_ptr, debug_udp_pbuf_ptr, IP_ADDR_BROADCAST, 11234);
34 | }
35 |
36 |
37 | THD_FUNCTION(debug_udp_thread, arg)
38 | {
39 | (void)arg;
40 |
41 | chRegSetThreadName("debug_udp");
42 |
43 | while(true)
44 | {
45 | watchdog_feed(WATCHDOG_DOG_IPSRVS);
46 | chMtxLock(&udp_tx_queue.mutex);
47 |
48 | while(!udp_tx_queue.waiting)
49 | {
50 | watchdog_feed(WATCHDOG_DOG_IPSRVS);
51 |
52 | if(chCondWaitTimeout(&udp_tx_queue.condition, TIME_MS2I(100)) == MSG_TIMEOUT)
53 | {
54 | /* Re-acquire Mutex */
55 | chMtxLock(&udp_tx_queue.mutex);
56 | }
57 | }
58 |
59 | debug_pbuf_payload_ptr[4] = 0xFF;
60 | memcpy(&(debug_pbuf_payload_ptr[5]), udp_tx_queue.rawFrame, 64);
61 |
62 | udp_tx_queue.waiting = false;
63 | chMtxUnlock(&udp_tx_queue.mutex);
64 |
65 | if(app_ip_link_status() != APP_IP_LINK_STATUS_BOUND)
66 | {
67 | /* Discard packet */
68 | continue;
69 | }
70 |
71 | rtcGetTime(&RTCD1, &debug_datetime);
72 | *(uint32_t *)(&debug_pbuf_payload_ptr[0]) = debug_datetime.millisecond;
73 |
74 | tcpip_callback(_udp_tx, NULL);
75 |
76 | watchdog_feed(WATCHDOG_DOG_IPSRVS);
77 | chThdSleepMilliseconds(10);
78 | }
79 | };
--------------------------------------------------------------------------------
/firmware/flash:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source_dir="$(cd $(dirname ${BASH_SOURCE[0]}) && pwd)"
4 | cd "$source_dir"
5 |
6 | COLOUR_GREEN='\033[0;32m'
7 | COLOUR_YELLOW='\033[1;33m'
8 | COLOUR_PURPLE='\033[0;35m'
9 | COLOUR_RED='\033[0;31m'
10 | COLOUR_OFF='\033[0;00m'
11 | CLEAR_LINE='\033[2K'
12 |
13 | _ERROR_="${COLOUR_RED}[ERROR]${COLOUR_OFF}"
14 | _INFO_="${COLOUR_PURPLE}[INFO]${COLOUR_OFF}"
15 | _DEBUG_="${COLOUR_YELLOW}[DEBUG]${COLOUR_OFF}"
16 |
17 | opt_sound=false;
18 | opt_power=false;
19 |
20 | flashtool="arm-none-eabi-gdb"
21 | programmer=false
22 |
23 | locate_black_magic() {
24 | probe="`ls 2>/dev/null -Ub1 -- /dev/serial/by-id/usb-Black_Sphere_Technologies_Black_Magic_Probe_*-if00 | head -n 1`";
25 | if ! [ -z "$probe" ];
26 | then
27 | echo "$probe";
28 | return 0;
29 | fi
30 | return 1;
31 | }
32 |
33 | flash_target() {
34 | programmer_power="disable"
35 | if $opt_power; then
36 | programmer_power="enable";
37 | fi
38 |
39 | flash_cmd="$flashtool -q --batch \
40 | -ex 'file '$binary \
41 | -ex 'target extended-remote '$programmer \
42 | -ex 'monitor tpwr '$programmer_power \
43 | -ex 'monitor swdp_scan' \
44 | -ex 'attach 1' \
45 | -ex 'load '$binary \
46 | -ex 'compare-sections'";
47 |
48 | flash_out=`eval $flash_cmd 2>&1`;
49 | echo ${flash_out} | grep -vqE 'warning|fail|Error|MIS-MATCHED|"monitor" command not supported by this target';
50 | if [[ $? -eq 0 ]]; then
51 | printf "${flash_out}\n"
52 | return 0;
53 | else
54 | printf "${flash_out}\n"
55 | return 1;
56 | fi
57 | }
58 |
59 | playsound() {
60 | if hash aplay 2>/dev/null
61 | then
62 | aplay -q $@;
63 | elif hash play 2>/dev/null
64 | then
65 | play -q $@;
66 | else
67 | printf "$_ERROR_ No WAV player detected\n";
68 | fi
69 | }
70 |
71 | check_linux_serial_permissions() {
72 | # For Linux - check user has permissions to the serial port (required for Black Magic Probe)
73 | if [ ${host_platform} == "linux" ]; then
74 | groups $USER | grep -q 'dialout'
75 | if [[ ! $? -eq 0 ]]; then
76 | printf "$_ERROR_ Current user is not in dialout group, you'll need this to use the programmer!\n";
77 | printf " * eg. for Ubuntu/Debian: 'sudo gpasswd --add "$USER" dialout'\n";
78 | exit 1
79 | fi
80 | fi
81 | }
82 |
83 | ## Read Flags
84 | OPTIND=1
85 | while getopts ":SP" opt; do
86 | case "$opt" in
87 | S) # Sound
88 | opt_sound=true
89 | ;;
90 | P) # Sound
91 | opt_power=true
92 | ;;
93 | ?) # Illegal Option
94 | echo -e "$_ERROR_ Illegal option '$OPTARG'"
95 | exit 3
96 | ;;
97 | esac
98 | done
99 | for i in `seq 2 $OPTIND`; do shift; done
100 |
101 | binary="${1}.elf"
102 |
103 | if [ "$binary" == ".elf" ];
104 | then
105 | binary="$(ls -t builds/*.elf | head -1)"
106 | if [[ ! -f $binary ]]; then
107 | echo -e "$_ERROR_ No suitable builds found!"
108 | exit 1
109 | fi
110 | echo -e "$_INFO_ Most recent build selected"
111 | else
112 | if [[ ! -f $binary ]]; then
113 | echo -e "$_ERROR_ Binary $binary not found!"
114 | exit 1
115 | fi
116 | fi
117 |
118 | echo -e "$_INFO_ - File: ${binary}"
119 |
120 | if [ `date "+%Y-%m-%d"` == `date -r ${binary} "+%Y-%m-%d"` ];
121 | then
122 | echo -e "$_INFO_ - Compiled today `date -r ${binary} "+%H:%M:%S"`";
123 | else
124 | echo -e "$_INFO_ - Compiled `date -r ${binary} "+%Y-%m-%d %H:%M:%S"`";
125 | fi
126 |
127 | if programmer="`locate_black_magic`";
128 | then
129 | printf "$_INFO_ Black Magic Probe found. Flashing..\n";
130 | flash_target \
131 | && {
132 | printf "$_INFO_$COLOUR_GREEN Device Flash successful$COLOUR_OFF\n"
133 | if $opt_sound; then playsound tools/flash.wav; fi
134 | } || {
135 | printf "$_ERROR_$COLOUR_RED Device Flash Failed$COLOUR_OFF\n" \
136 | && exit 1
137 | }
138 | else
139 | printf "$_INFO_ ${COLOUR_YELLOW}Black Magic Probe not found, trying ST-Link..${COLOUR_OFF}\n"
140 | binary=builds/"$(basename "$binary" .elf).bin"
141 | printf "$_INFO_ Using bin file with st-flash: ${binary}\n"
142 | st-flash write $binary 0x8000000 \
143 | && {
144 | printf "$_INFO_$COLOUR_GREEN Device Flash successful$COLOUR_OFF\n"
145 | if $opt_sound; then playsound tools/flash.wav; fi
146 | } || {
147 | printf "$_ERROR_$COLOUR_RED Device Flash Failed$COLOUR_OFF\n" \
148 | && exit 1
149 | }
150 | fi
151 |
--------------------------------------------------------------------------------
/firmware/gnss.c:
--------------------------------------------------------------------------------
1 | #include "main.h"
2 |
3 | #include
4 | #include
5 |
6 | #include
7 |
8 | gnss_status_t gnss_status = { 0 };
9 |
10 | int32_t gnss_aid_position_latitude = GNSS_AID_POS_LATITUDE;
11 | int32_t gnss_aid_position_longitude = GNSS_AID_POS_LONGITUDE;
12 | int32_t gnss_aid_position_altitude = GNSS_AID_POS_ALTITUDE;
13 | int32_t gnss_aid_position_stddev = GNSS_AID_POS_STDDEV;
14 |
15 | void gnss_parse(uint8_t *buffer);
16 |
17 | static const SerialConfig serial_gnss_config = {
18 | .speed = 9600,
19 | .cr2 = USART_CR2_CPOL
20 | };
21 |
22 | static uint16_t ubx_crc(const uint8_t *input, uint16_t len)
23 | {
24 | uint8_t a = 0;
25 | uint8_t b = 0;
26 | uint32_t i;
27 | for(i = 0; i < len; i++)
28 | {
29 | a = a + input[i];
30 | b = b + a;
31 | }
32 | return (a << 8) | b;
33 | }
34 |
35 | static bool ubx_crc_verify(const uint8_t *buffer, int32_t buffer_size)
36 | {
37 | uint16_t ck = ubx_crc(&buffer[2], (buffer_size-4));
38 |
39 | return (((ck >> 8) & 0xFF) == buffer[buffer_size-2]) && ((ck & 0xFF) == buffer[buffer_size-1]);
40 | }
41 |
42 | static void uart_send_blocking_len_ubx(const uint8_t *_buff, uint16_t len)
43 | {
44 | uint16_t checksum;
45 | uint8_t checksum_u8[2];
46 | checksum = ubx_crc(&_buff[2], (len-2));
47 | checksum_u8[0] = (checksum >> 8) & 0xFF;
48 | checksum_u8[1] = checksum & 0xFF;
49 |
50 | sdWrite(&SD3, _buff, len);
51 | sdWrite(&SD3, checksum_u8, 2);
52 | }
53 |
54 | const uint8_t enable_galileo[] = { 0xb5, 0x62,
55 | 0x06, 0x3e,
56 | 0x3c, 0x00, // Length: 60 bytes
57 | 0x00, 0x00, 0xff, 0x07,
58 | // GPS min max res x1 x2 x3, x4
59 | 0x00, 0x0A, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01,
60 | // SBAS min max res x1 x2 x3 x4
61 | 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x01,
62 | // GAL min max res x1 x2 x3, x4
63 | 0x02, 0x04, 0x08, 0x00, 0x01, 0x00, 0x01, 0x01,
64 | // BEI min max res x1 x2 x3, x4
65 | 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
66 | // IMES min max res x1 x2 x3, x4
67 | 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03,
68 | // QZSS min max res x1 x2 x3, x4
69 | 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x05,
70 | // GLO min max res x1 x2 x3, x4
71 | 0x06, 0x0A, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01,
72 | };
73 |
74 | const uint8_t disable_nmea_gpgga[] = {0xb5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
75 | const uint8_t disable_nmea_gpgll[] = {0xb5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
76 | const uint8_t disable_nmea_gpgsa[] = {0xb5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
77 | const uint8_t disable_nmea_gpgsv[] = {0xb5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
78 | const uint8_t disable_nmea_gprmc[] = {0xb5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
79 | const uint8_t disable_nmea_gpvtg[] = {0xb5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
80 |
81 | const uint8_t enable_navpvt[] = {0xb5, 0x62, 0x06, 0x01, 0x08, 0x00, 0x01, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00};
82 | const uint8_t enable_navsat[] = {0xb5, 0x62, 0x06, 0x01, 0x08, 0x00, 0x01, 0x35, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00};
83 |
84 | uint8_t gnss_aid_position_msg[] =
85 | {
86 | 0x13, 0x40, // UBX-MGA-INI
87 | 0x14, 0x00, // Length
88 | 0x01, // Type: UBX-MGA-INI-POS_LLH
89 | 0x00, // Version: 0
90 | 0x00, 0x00, // Reserved
91 | 0x00, 0x00, 0x00, 0x00, // Latitude 1e-7
92 | 0x00, 0x00, 0x00, 0x00, // Longitude 1e-7
93 | 0x00, 0x00, 0x00, 0x00, // Altitude cm
94 | 0x00, 0x00, 0x00, 0x00 // Std Dev cm
95 | };
96 |
97 | static void gnss_configure(void)
98 | {
99 | /* Enable Galileo */
100 | uart_send_blocking_len_ubx(enable_galileo, sizeof(enable_galileo));
101 |
102 | /* Disable NMEA Outputs */
103 | uart_send_blocking_len_ubx(disable_nmea_gpgga, sizeof(disable_nmea_gpgga));
104 | uart_send_blocking_len_ubx(disable_nmea_gpgll, sizeof(disable_nmea_gpgll));
105 | uart_send_blocking_len_ubx(disable_nmea_gpgsa, sizeof(disable_nmea_gpgsa));
106 | uart_send_blocking_len_ubx(disable_nmea_gpgsv, sizeof(disable_nmea_gpgsv));
107 | uart_send_blocking_len_ubx(disable_nmea_gprmc, sizeof(disable_nmea_gprmc));
108 | uart_send_blocking_len_ubx(disable_nmea_gpvtg, sizeof(disable_nmea_gpvtg));
109 |
110 | /* Enable UBX Outputs */
111 | uart_send_blocking_len_ubx(enable_navpvt, sizeof(enable_navpvt));
112 | uart_send_blocking_len_ubx(enable_navsat, sizeof(enable_navsat));
113 |
114 | #ifdef GNSS_AID_POSITION
115 | memcpy(&gnss_aid_position_msg[8], &gnss_aid_position_latitude, sizeof(int32_t));
116 | memcpy(&gnss_aid_position_msg[12], &gnss_aid_position_longitude, sizeof(int32_t));
117 | memcpy(&gnss_aid_position_msg[16], &gnss_aid_position_altitude, sizeof(int32_t));
118 | memcpy(&gnss_aid_position_msg[20], &gnss_aid_position_stddev, sizeof(int32_t));
119 |
120 | uart_send_blocking_len_ubx(gnss_aid_position_msg, sizeof(gnss_aid_position_msg));
121 | #endif
122 | }
123 |
124 | static uint8_t buffer[1024];
125 |
126 | static const uint8_t msg_header[2] = { 0xb5, 0x62 };
127 | static uint32_t response_index = 0;
128 | static uint32_t response_length = 0;
129 | static void gnss_ubx_rx(uint8_t response_byte)
130 | {
131 | if(response_index < 2 && response_byte == msg_header[response_index])
132 | {
133 | /* Header */
134 | buffer[response_index] = response_byte;
135 | response_index++;
136 | }
137 | else if(response_index >= 2 && response_index < 5)
138 | {
139 | /* Message Class, ID, first byte of length */
140 | buffer[response_index] = response_byte;
141 | response_index++;
142 | }
143 | else if(response_index == 5)
144 | {
145 | /* Final Length byte */
146 | buffer[response_index] = response_byte;
147 | response_length = buffer[5] << 8 | buffer[4];
148 | response_index++;
149 | }
150 | else if(response_index > 5 && response_index < (6+2+response_length-1))
151 | {
152 | /* Data payload and first byte of checksum */
153 | buffer[response_index] = response_byte;
154 | response_index++;
155 | }
156 | else if(response_index == (6+2+response_length-1))
157 | {
158 | /* Last byte of checksum */
159 | buffer[response_index] = response_byte;
160 |
161 | if(ubx_crc_verify(buffer, (6+2+response_length)))
162 | {
163 | gnss_parse(buffer);
164 | }
165 |
166 | response_index = 0;
167 | }
168 | else
169 | {
170 | response_index = 0;
171 | }
172 | }
173 |
174 | bool pps_set_time = false;
175 | RTCDateTime time_set_timespec;
176 |
177 | /* To be copied over on PPS pulse */
178 | struct tm time_ref_candidate_tm;
179 | uint32_t time_ref_candidate_tm_ms;
180 | uint32_t time_ref_candidate_s;
181 | uint32_t time_ref_candidate_f;
182 |
183 | /* Copied over to on PPS pulse */
184 | struct tm time_ref_tm = { 0 };
185 | uint32_t time_ref_tm_ms = 0;
186 | uint32_t time_ref_s = 0;
187 | uint32_t time_ref_f = 0;
188 |
189 | extern RTCDateTime time_ref_timespec;
190 |
191 | static virtual_timer_t status_demote_timer;
192 | static virtual_timer_t stratum_demote_timer;
193 |
194 | static void cb_status_demote(void *arg)
195 | {
196 | (void)arg;
197 |
198 | ntpd_status.status = NTPD_IN_HOLDOVER;
199 | }
200 |
201 | static void cb_stratum_demote(void *arg)
202 | {
203 | (void)arg;
204 |
205 | ntpd_status.status = NTPD_DEGRADED;
206 | ntpd_status.stratum = 16;
207 | }
208 |
209 | void pps_set_time_cb(void *arg)
210 | {
211 | (void)arg;
212 |
213 | if(!pps_set_time)
214 | {
215 | return;
216 | }
217 |
218 | rtcSetTime(&RTCD1, &time_set_timespec);
219 |
220 | RTCD1.rtc->CR &= ~RTC_CR_ALRAIE;
221 | RTCD1.rtc->CR &= ~RTC_CR_ALRAE;
222 |
223 | pps_set_time = false;
224 |
225 | time_ref_tm = time_ref_candidate_tm;
226 | time_ref_tm_ms = time_ref_candidate_tm_ms;
227 | time_ref_s = time_ref_candidate_s;
228 | time_ref_f = time_ref_candidate_f;
229 |
230 | ntpd_status.status = NTPD_IN_LOCK;
231 | ntpd_status.stratum = 1;
232 |
233 | /* Reset stratum demote timer */
234 | chSysLockFromISR();
235 | chVTSetI(&status_demote_timer, NTPD_STATUS_DEMOTE_TIMER_PERIOD, cb_status_demote, NULL);
236 | chVTSetI(&stratum_demote_timer, NTPD_STRATUM_DEMOTE_TIMER_PERIOD, cb_stratum_demote, NULL);
237 | chSysUnlockFromISR();
238 | }
239 |
240 |
241 | static uint8_t gnss_input_buffer[512];
242 |
243 | THD_FUNCTION(gnss_thread, arg)
244 | {
245 | (void)arg;
246 |
247 | chRegSetThreadName("gnss");
248 |
249 | /* Start GNSS UART */
250 | sdStart(&SD3, &serial_gnss_config);
251 |
252 | /* Register for DATA IN event */
253 | event_listener_t serial_gnss_listener;
254 | chEvtRegisterMaskWithFlags(chnGetEventSource(&SD3),
255 | &serial_gnss_listener,
256 | EVENT_MASK(1),
257 | CHN_INPUT_AVAILABLE);
258 |
259 | gnss_configure();
260 |
261 | /* Set up timer to drop stratum */
262 | chVTSet(&stratum_demote_timer, NTPD_STRATUM_DEMOTE_TIMER_PERIOD, cb_stratum_demote, NULL);
263 |
264 | palEnableLineEvent(LINE_GNSS_PPS, PAL_EVENT_MODE_RISING_EDGE);
265 | palSetLineCallback(LINE_GNSS_PPS, pps_set_time_cb, NULL);
266 |
267 | uint32_t i;
268 | uint32_t read_length;
269 |
270 | eventflags_t flags;
271 | while(true)
272 | {
273 | if(0 != chEvtWaitOneTimeout(EVENT_MASK(1), TIME_MS2I(100)))
274 | {
275 | /* Event Received */
276 | flags = chEvtGetAndClearFlags(&serial_gnss_listener);
277 | if (flags & CHN_INPUT_AVAILABLE)
278 | {
279 | /* Data available read here.*/
280 | read_length = sdReadTimeout(&SD3, gnss_input_buffer, sizeof(gnss_input_buffer), TIME_IMMEDIATE);
281 |
282 | i = 0;
283 | while(read_length--)
284 | {
285 | gnss_ubx_rx(gnss_input_buffer[i++]);
286 | }
287 | }
288 | }
289 |
290 | //watchdog_feed(WATCHDOG_DOG_GNSS);
291 | }
292 | };
--------------------------------------------------------------------------------
/firmware/gnss.h:
--------------------------------------------------------------------------------
1 | #ifndef __GNSS_H__
2 | #define __GNSS_H__
3 |
4 | typedef struct {
5 | uint8_t gnss_id;
6 | uint8_t sv_id;
7 | uint8_t cn0;
8 | int8_t elevation;
9 | int16_t azimuth;
10 | int16_t psr_res;
11 | uint32_t flags;
12 | } __attribute__((packed)) gnss_status_sv_t;
13 | /* packet to allow memcpy from ubx */
14 |
15 | typedef struct {
16 | bool fix;
17 | uint32_t time_accuracy_ns;
18 | int32_t time_nanosecond;
19 |
20 | uint64_t gnss_timestamp;
21 | int32_t lat;
22 | int32_t lon;
23 | int32_t alt;
24 | uint32_t h_acc;
25 | uint32_t v_acc;
26 |
27 | gnss_status_sv_t svs[32];
28 | uint8_t svs_count;
29 | uint8_t svs_acquired_count;
30 | uint8_t svs_locked_count;
31 | uint8_t svs_nav_count;
32 | } gnss_status_t;
33 |
34 | extern gnss_status_t gnss_status;
35 |
36 | THD_FUNCTION(gnss_thread, arg);
37 |
38 | #endif /* __GNSS_H__ */
--------------------------------------------------------------------------------
/firmware/gnss_parse.c:
--------------------------------------------------------------------------------
1 | #include "main.h"
2 |
3 | #include "lwip/def.h"
4 |
5 | #include
6 |
7 | typedef struct
8 | {
9 | uint32_t itow;
10 | uint16_t year;
11 | uint8_t month; // jan = 1
12 | uint8_t day;
13 | uint8_t hour; // 24
14 | uint8_t min;
15 | uint8_t sec;
16 | uint8_t valid;
17 | uint32_t tAcc;
18 | int32_t nano;
19 | uint8_t fixtype;
20 | uint8_t flags;
21 | uint8_t flags2;
22 | uint8_t numsv;
23 | // 1e-7 mm mm
24 | int32_t lon, lat, height, hMSL;
25 | // mm mm
26 | uint32_t hAcc, vAcc;
27 | // mm/s mm/s mm/s mm/s
28 | int32_t velN, velE, velD, gSpeed; // millimeters
29 | } __attribute__((packed)) nav_pvt_t;
30 |
31 | typedef struct
32 | {
33 | uint32_t itow;
34 | uint8_t version;
35 | uint8_t num_svs;
36 | uint8_t _reserved1;
37 | uint8_t _reserved2;
38 | } __attribute__((packed)) nav_sat_header_t;
39 |
40 | typedef struct
41 | {
42 | uint8_t gnss_id;
43 | uint8_t sv_id;
44 | uint8_t cn0;
45 | int8_t elevation;
46 | int16_t azimuth;
47 | int16_t psr_res;
48 | uint32_t flags;
49 | } __attribute__((packed)) nav_sat_sv_t;
50 |
51 | extern bool pps_set_time;
52 | extern RTCDateTime time_set_timespec;
53 |
54 | extern struct tm time_ref_candidate_tm;
55 | extern uint32_t time_ref_candidate_tm_ms;
56 | extern uint32_t time_ref_candidate_s;
57 | extern uint32_t time_ref_candidate_f;
58 |
59 | static virtual_timer_t cancel_pps_set_timer;
60 |
61 | static void cb_cancel_pps_set(void *arg)
62 | {
63 | (void)arg;
64 |
65 | pps_set_time = false;
66 | }
67 |
68 | void gnss_parse(uint8_t *buffer)
69 | {
70 | if(buffer[2] == 0x01 && buffer[3] == 0x07) /* NAV-PVT */
71 | {
72 | nav_pvt_t *pvt = (nav_pvt_t *)(&buffer[6]);
73 |
74 | struct tm tm;
75 | memset(&tm, 0, sizeof(tm));
76 | tm.tm_year = pvt->year - 1900;
77 | tm.tm_mon = pvt->month - 1;
78 | tm.tm_mday = pvt->day;
79 | tm.tm_hour = pvt->hour;
80 | tm.tm_min = pvt->min;
81 | tm.tm_sec = pvt->sec;
82 |
83 | gnss_status.fix = (pvt->fixtype == 0x03) || (pvt->fixtype == 0x04);
84 | gnss_status.time_accuracy_ns = pvt->tAcc;
85 |
86 | gnss_status.gnss_timestamp = mktime(&tm);
87 | gnss_status.lat = pvt->lat;
88 | gnss_status.lon = pvt->lon;
89 | gnss_status.alt = pvt->height;
90 | gnss_status.h_acc = pvt->hAcc;
91 | gnss_status.v_acc = pvt->vAcc;
92 |
93 | if(gnss_status.fix)
94 | {
95 | pps_set_time = false;
96 | rtcConvertStructTmToDateTime(&tm, 0, &time_set_timespec);
97 | /* Don't set time in the 1.5s before midnight - TODO: Handle rollover properly instead */
98 | if(time_set_timespec.millisecond < 86398500)
99 | {
100 | /* Next second */
101 | time_set_timespec.millisecond += 1000;
102 |
103 | /* Set candidate reference timestamps */
104 | rtcConvertDateTimeToStructTm(&time_set_timespec, &time_ref_candidate_tm, &time_ref_candidate_tm_ms);
105 | time_ref_candidate_s = htonl((uint32_t)mktime(&time_ref_candidate_tm) - DIFF_SEC_1970_2036);
106 | time_ref_candidate_f = htonl((NTP_MS_TO_FS_U32 * time_ref_candidate_tm_ms));
107 |
108 | pps_set_time = true;
109 | /* Set up timer to cancel if the PPS is overdue (>1000ms after we've received this) */
110 | chVTSet(&cancel_pps_set_timer, TIME_MS2I(1000), cb_cancel_pps_set, NULL);
111 | }
112 | }
113 | }
114 | else if(buffer[2] == 0x01 && buffer[3] == 0x35) /* NAV-SAT */
115 | {
116 | nav_sat_header_t *sat_header = (nav_sat_header_t *)(&buffer[6]);
117 |
118 | /* Copy SVs into status struct */
119 | memcpy((void *)gnss_status.svs, &buffer[6+8], (sat_header->num_svs * 12));
120 | gnss_status.svs_count = sat_header->num_svs;
121 |
122 | nav_sat_sv_t *sat_sv;
123 |
124 | gnss_status.svs_acquired_count = 0;
125 | gnss_status.svs_locked_count = 0;
126 | gnss_status.svs_nav_count = 0;
127 |
128 | for(uint32_t i = 0; i < sat_header->num_svs; i++)
129 | {
130 | sat_sv = (nav_sat_sv_t *)(&buffer[6+8+(12*i)]);
131 |
132 | if((sat_sv->flags & 0x7) >= 2)
133 | {
134 | /* SV acquired */
135 | gnss_status.svs_acquired_count++;
136 | }
137 |
138 | if((sat_sv->flags & 0x7) >= 4)
139 | {
140 | /* SV locked (note: acquired are included) */
141 | gnss_status.svs_locked_count++;
142 | }
143 |
144 | if(((sat_sv->flags & 0x8) >> 3) == 1)
145 | {
146 | /* Used in navigation solution */
147 | gnss_status.svs_nav_count++;
148 | }
149 | }
150 | }
151 | }
--------------------------------------------------------------------------------
/firmware/ip_link.c:
--------------------------------------------------------------------------------
1 | #include "main.h"
2 |
3 | #include
4 |
5 | static struct netif* _ip_netif_ptr = NULL;
6 |
7 | static bool _ip_link_is_up = false;
8 |
9 | uint32_t app_ip_link_status(void)
10 | {
11 | if(_ip_link_is_up && _ip_netif_ptr != NULL)
12 | {
13 | if(netif_dhcp_data(_ip_netif_ptr)->state == 10) // DHCP_STATE_BOUND = 10
14 | {
15 | return APP_IP_LINK_STATUS_BOUND;
16 | }
17 | else
18 | {
19 | return APP_IP_LINK_STATUS_UPBUTNOIP;
20 | }
21 | }
22 | else
23 | {
24 | return APP_IP_LINK_STATUS_DOWN;
25 | }
26 | }
27 |
28 | void ip_link_up_cb(void *p)
29 | {
30 | _ip_netif_ptr = (struct netif*)p;
31 |
32 | dhcp_start(_ip_netif_ptr);
33 |
34 | _ip_link_is_up = true;
35 | palSetLine(LINE_LED1);
36 | }
37 |
38 | void ip_link_down_cb(void *p)
39 | {
40 | _ip_netif_ptr = (struct netif*)p;
41 |
42 | dhcp_stop(_ip_netif_ptr);
43 |
44 | _ip_link_is_up = false;
45 | palClearLine(LINE_LED1);
46 | }
--------------------------------------------------------------------------------
/firmware/ip_link.h:
--------------------------------------------------------------------------------
1 | #ifndef __IP_LINK_H__
2 | #define __IP_LINK_H__
3 |
4 | #define APP_IP_LINK_STATUS_DOWN 0
5 | #define APP_IP_LINK_STATUS_UPBUTNOIP 1
6 | #define APP_IP_LINK_STATUS_BOUND 2
7 |
8 | uint32_t app_ip_link_status(void);
9 |
10 | void ip_link_up_cb(void *p);
11 | void ip_link_down_cb(void *p);
12 |
13 | #endif /* __IP_LINK_H__ */
--------------------------------------------------------------------------------
/firmware/main.c:
--------------------------------------------------------------------------------
1 | #include "main.h"
2 |
3 | #include
4 |
5 | #include "lwipthread.h"
6 |
7 | static THD_WORKING_AREA(watchdog_service_wa, 128);
8 | static THD_WORKING_AREA(ntpd_wa, 4096);
9 | static THD_WORKING_AREA(gnss_wa, 128);
10 |
11 | static uint8_t _macAddress[] = {0xC2, 0xAF, 0x51, 0x03, 0xCF, 0x47};
12 | static const lwipthread_opts_t lwip_opts = {
13 | .macaddress = _macAddress,
14 | .address = 0,
15 | .netmask = 0,
16 | .gateway = 0,
17 | .addrMode = NET_ADDRESS_DHCP,
18 | .ourHostName = "stm32ntpd",
19 | .link_up_cb = ip_link_up_cb,
20 | .link_down_cb = ip_link_down_cb
21 | };
22 |
23 | int main(void)
24 | {
25 | halInit();
26 | chSysInit();
27 |
28 | /* For some really weird reason the ethernet peripheral requires the PLL SAI clock to be on (both STM32F4 & STM32F7) */
29 | // Enable PLLSAI
30 | RCC->CR |= RCC_CR_PLLSAION;
31 | // Wait for PLLSAI to lock
32 | while(!(RCC->CR & RCC_CR_PLLSAIRDY)); // wait for PLLSAI to lock
33 |
34 | /* Set up watchdog */
35 | watchdog_init();
36 | chThdCreateStatic(watchdog_service_wa, sizeof(watchdog_service_wa), HIGHPRIO, watchdog_service_thread, NULL);
37 |
38 | /* Set up IP stack */
39 | lwipInit(&lwip_opts);
40 |
41 | web_init();
42 |
43 | /* NTPD Thread */
44 | chThdCreateStatic(ntpd_wa, sizeof(ntpd_wa), NORMALPRIO, ntpd_thread, NULL);
45 |
46 | /* GNSS Thread */
47 | chThdCreateStatic(gnss_wa, sizeof(gnss_wa), LOWPRIO, gnss_thread, NULL);
48 |
49 | while(true)
50 | {
51 | watchdog_feed(WATCHDOG_DOG_MAIN);
52 | chThdSleepMilliseconds(100);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/firmware/main.h:
--------------------------------------------------------------------------------
1 | #ifndef __MAIN_H__
2 | #define __MAIN_H__
3 |
4 | #include "ch.h"
5 | #include "hal.h"
6 |
7 | #define MIN(x,y) ((x) < (y) ? (x) : (y))
8 | #define MAX(x,y) ((x) > (y) ? (x) : (y))
9 |
10 | /* Round up N to the next multiple of S */
11 | #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
12 |
13 | /* Mark binary constants as known GCC extension to suppress warning */
14 | #define GCC_BINARY(x) (__extension__ (x))
15 |
16 | #define _token_concat(x,y) x##y
17 | #define token_concat(x,y) _token_concat(x,y)
18 |
19 | #define nibble_to_hex(i) ((i) <= 9 ? '0' + (i) : 'A' - 10 + (i))
20 |
21 | #define ITERATOR_DEF() uint8_t iterator = 0
22 | #define ITERATOR_VAR() iterator < 1 ? "/" : iterator < 2 ? "-" : "\\"
23 | #define ITERATOR_INC() iterator = iterator < 2 ? iterator + 1 : 0
24 |
25 | #include "config.h"
26 |
27 | #include "watchdog.h"
28 | #include "ip_link.h"
29 | #include "ntpd.h"
30 | #include "gnss.h"
31 | #include "web/web.h"
32 |
33 | #endif /* __MAIN_H__ */
--------------------------------------------------------------------------------
/firmware/ntpd.c:
--------------------------------------------------------------------------------
1 | #include "main.h"
2 |
3 | #include "lwip/api.h"
4 | #include "lwip/netif.h"
5 |
6 | #include
7 |
8 | ntpd_status_t ntpd_status = {
9 | .status = NTPD_UNSYNC,
10 | .requests_count = 0,
11 | .stratum = 16
12 | };
13 |
14 | typedef struct
15 | {
16 | uint8_t li_vn_mode;
17 |
18 | uint8_t stratum;
19 | uint8_t poll;
20 | uint8_t precision;
21 |
22 | uint32_t rootDelay;
23 |
24 | uint16_t rootDispersion_s;
25 | uint16_t rootDispersion_f;
26 |
27 | uint32_t refId;
28 |
29 | uint32_t refTm_s;
30 | uint32_t refTm_f;
31 |
32 | uint32_t origTm_s;
33 | uint32_t origTm_f;
34 |
35 | uint32_t rxTm_s;
36 | uint32_t rxTm_f;
37 |
38 | uint32_t txTm_s;
39 | uint32_t txTm_f;
40 |
41 | } ntp_packet_t;
42 |
43 | /* From GNSS PPS */
44 | extern uint32_t time_ref_s;
45 | extern uint32_t time_ref_f;
46 |
47 | THD_FUNCTION(ntpd_thread, arg)
48 | {
49 | (void)arg;
50 | struct netconn *conn;
51 | struct netbuf *buf;
52 | err_t err;
53 | uint16_t buf_data_len;
54 |
55 | ntp_packet_t *ntp_packet_ptr;
56 | RTCDateTime ntpd_datetime;
57 | struct tm tm_;
58 | uint32_t tm_ms_;
59 |
60 | chRegSetThreadName("ntpd");
61 |
62 | /* Create a new UDP connection handle */
63 | conn = netconn_new(NETCONN_UDP);
64 | if(conn == NULL)
65 | {
66 | chThdExit(MSG_RESET);
67 | }
68 |
69 | netconn_bind(conn, IP_ADDR_ANY, 123);
70 |
71 | while (true)
72 | {
73 | err = netconn_recv(conn, &buf);
74 | if (err == ERR_OK)
75 | {
76 | palSetLine(LINE_LED2);
77 |
78 | netbuf_data(buf, (void **)&ntp_packet_ptr, &buf_data_len);
79 |
80 | if(buf_data_len < 48 || buf_data_len > 2048)
81 | {
82 | netbuf_delete(buf);
83 | continue;
84 | }
85 |
86 | ntp_packet_ptr->li_vn_mode = (0 << 6) | (4 << 3) | (4); // Leap Warning: None, Version: NTPv4, Mode: 4 - Server
87 |
88 | ntp_packet_ptr->stratum = ntpd_status.stratum;
89 | ntp_packet_ptr->poll = 5; // 32s
90 | ntp_packet_ptr->precision = -10; // ~1ms
91 |
92 | ntp_packet_ptr->rootDelay = 0; // Delay from GPS clock is ~zero
93 | ntp_packet_ptr->rootDispersion_s = 0;
94 | ntp_packet_ptr->rootDispersion_f = htonl(NTP_MS_TO_FS_U16 * 1.0); // 1ms
95 | ntp_packet_ptr->refId = ('G') | ('P' << 8) | ('S' << 16) | ('\0' << 24);
96 |
97 | /* Move client's transmit timestamp into origin fields */
98 | ntp_packet_ptr->origTm_s = ntp_packet_ptr->txTm_s;
99 | ntp_packet_ptr->origTm_f = ntp_packet_ptr->txTm_f;
100 |
101 | ntp_packet_ptr->refTm_s = time_ref_s;
102 | ntp_packet_ptr->refTm_f = time_ref_f;
103 |
104 | rtcGetTime(&RTCD1, &ntpd_datetime);
105 | rtcConvertDateTimeToStructTm(&ntpd_datetime, &tm_, &tm_ms_);
106 |
107 | ntp_packet_ptr->rxTm_s = htonl(mktime(&tm_) - DIFF_SEC_1970_2036);
108 | ntp_packet_ptr->rxTm_f = htonl((NTP_MS_TO_FS_U32 * tm_ms_));
109 |
110 | /* Copy into transmit timestamp fields */
111 | ntp_packet_ptr->txTm_s = ntp_packet_ptr->rxTm_s;
112 | ntp_packet_ptr->txTm_f = ntp_packet_ptr->rxTm_f;
113 |
114 | netconn_send(conn, buf);
115 | netbuf_delete(buf);
116 |
117 | ntpd_status.requests_count++;
118 |
119 | palClearLine(LINE_LED2);
120 | }
121 | }
122 | };
--------------------------------------------------------------------------------
/firmware/ntpd.h:
--------------------------------------------------------------------------------
1 | #ifndef __NTPD_H__
2 | #define __NTPD_H__
3 |
4 | #define NTP_MS_TO_FS_U32 (4294967296.0 / 1000.0)
5 | #define NTP_MS_TO_FS_U16 (65536.0 / 1000.0)
6 |
7 | /* Number of seconds between 1970 and Feb 7, 2036 06:28:16 UTC (epoch 1) */
8 | #define DIFF_SEC_1970_2036 ((uint32_t)2085978496L)
9 |
10 | typedef enum {
11 | NTPD_UNSYNC = 0,
12 | NTPD_IN_LOCK = 1,
13 | NTPD_IN_HOLDOVER = 2,
14 | NTPD_DEGRADED = 3
15 | } ntpd_status_status_t;
16 |
17 | typedef struct {
18 | ntpd_status_status_t status;
19 | uint32_t requests_count;
20 | uint8_t stratum;
21 | } ntpd_status_t;
22 |
23 | extern ntpd_status_t ntpd_status;
24 |
25 | THD_FUNCTION(ntpd_thread, arg);
26 |
27 | #endif /* __NTPD_H__ */
--------------------------------------------------------------------------------
/firmware/openocd.cfg:
--------------------------------------------------------------------------------
1 | source [find interface/stlink-v2-1.cfg]
2 | source [find target/stm32f4x.cfg]
3 | init
4 | $_TARGETNAME configure -rtos ChibiOS
--------------------------------------------------------------------------------
/firmware/tools/.gitignore:
--------------------------------------------------------------------------------
1 | ntptest
2 |
--------------------------------------------------------------------------------
/firmware/tools/flash.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philcrump/stm32-ntp-server/0ff2c3581a8918b2f62c3641bfe897db4cfd1f44/firmware/tools/flash.wav
--------------------------------------------------------------------------------
/firmware/tools/ntptest.c:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * To compile: $ gcc ntptest.c -lm -o ntptest
4 | *
5 | * (C) 2014 David Lettier. http://www.lettier.com/
6 | * (C) 2020 Phil Crump
7 | *
8 | */
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | #define SHORTNTPFS_TO_MS (1000.0 / 65536.0)
24 |
25 | #define NTPFS_TO_MS (1000.0 / 4294967296.0)
26 | #define NTPFS_TO_US (1000000.0 / 4294967296.0)
27 | #define NTP_NS_TO_FS (4294967296.0 / 1000000000.0 )
28 | #define DIFF_SEC_1970_2036 ((uint32_t)2085978496L)
29 |
30 | #define NTP_SEC_FRAC_TO_S64(s, f) ((int64_t)(((uint64_t)(s) << 32) | (uint32_t)(f)))
31 | #define NTP_TIMESTAMP_TO_S64(t) NTP_SEC_FRAC_TO_S64(ntohl((t).sec), ntohl((t).frac))
32 |
33 | #define NTP_TIMESTAMP_DELTA 2208988800ull
34 |
35 | #define LI(packet) (uint8_t) ((packet.li_vn_mode & 0xC0) >> 6) // (li & 11 000 000) >> 6
36 | #define VN(packet) (uint8_t) ((packet.li_vn_mode & 0x38) >> 3) // (vn & 00 111 000) >> 3
37 | #define MODE(packet) (uint8_t) ((packet.li_vn_mode & 0x07) >> 0) // (mode & 00 000 111) >> 0
38 |
39 | int portno = 123; // NTP UDP port number.
40 |
41 | // Structure that defines the 48 byte NTP packet protocol.
42 |
43 | typedef struct
44 | {
45 |
46 | uint8_t li_vn_mode; // Eight bits. li, vn, and mode.
47 | // li. Two bits. Leap indicator.
48 | // vn. Three bits. Version number of the protocol.
49 | // mode. Three bits. Client will pick mode 3 for client.
50 |
51 | uint8_t stratum; // Eight bits. Stratum level of the local clock.
52 | uint8_t poll; // Eight bits. Maximum interval between successive messages.
53 | int8_t precision; // Eight bits. Precision of the local clock.
54 |
55 | uint16_t rootDelay_s; // 16 bits. Total round trip delay time seconds.
56 | uint16_t rootDelay_f; // 16 bits. Total round trip delay time fraction of a second.
57 |
58 | uint16_t rootDispersion_s; // 16 bits. Max error aloud from primary clock source seconds.
59 | uint16_t rootDispersion_f; // 16 bits. Max error aloud from primary clock source fraction of a second.
60 |
61 | uint32_t refId; // 32 bits. Reference clock identifier.
62 |
63 | uint32_t refTm_s; // 32 bits. Reference time-stamp seconds.
64 | uint32_t refTm_f; // 32 bits. Reference time-stamp fraction of a second.
65 |
66 | uint32_t origTm_s; // 32 bits. Originate time-stamp seconds.
67 | uint32_t origTm_f; // 32 bits. Originate time-stamp fraction of a second.
68 |
69 | uint32_t rxTm_s; // 32 bits. Received time-stamp seconds.
70 | uint32_t rxTm_f; // 32 bits. Received time-stamp fraction of a second.
71 |
72 | uint32_t txTm_s; // 32 bits and the most important field the client cares about. Transmit time-stamp seconds.
73 | uint32_t txTm_f; // 32 bits. Transmit time-stamp fraction of a second.
74 |
75 | } ntp_packet; // Total: 384 bits or 48 bytes.
76 |
77 | void error( char* msg )
78 | {
79 | perror( msg ); // Print the error message to stderr.
80 | exit( 0 ); // Quit the process.
81 | }
82 |
83 | int main( int argc, char* argv[ ] )
84 | {
85 | int sockfd, n; // Socket file descriptor and the n return result from writing/reading from the socket.
86 | char target_name[128];
87 |
88 | if(argc != 2)
89 | {
90 | printf("Usage: ./ntptest \n");
91 | return 1;
92 | }
93 |
94 | strncpy(target_name, argv[1], 127);
95 |
96 | if(strlen(target_name) < 1)
97 | {
98 | printf("Usage: ./ntptest \n");
99 | return 1;
100 | }
101 |
102 | printf("Target: %s\n", target_name);
103 |
104 | ntp_packet packet;
105 | memset( &packet, 0, sizeof( ntp_packet ) );
106 | //li = 0, vn = 3, and mode = 3.
107 | *((char *)&packet + 0) = 0x1b; // Represents 27 in base 10 or 00011011 in base 2.
108 |
109 | // Create a UDP socket, convert the host-name to an IP address, set the port number,
110 | // connect to the server, send the packet, and then read in the return packet.
111 |
112 | struct sockaddr_in serv_addr; // Server address data structure.
113 | struct hostent *server; // Server data structure.
114 |
115 | sockfd = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); // Create a UDP socket.
116 |
117 | if ( sockfd < 0 )
118 | error( "ERROR opening socket" );
119 |
120 | server = gethostbyname(target_name); // Convert URL to IP.
121 |
122 | if ( server == NULL )
123 | error( "ERROR, no such host" );
124 |
125 | bzero( ( char* ) &serv_addr, sizeof( serv_addr ) );
126 | serv_addr.sin_family = AF_INET;
127 |
128 | // Copy the server's IP address to the server address structure.
129 | bcopy( ( char* )server->h_addr, ( char* ) &serv_addr.sin_addr.s_addr, server->h_length );
130 |
131 | // Convert the port number integer to network big-endian style and save it to the server address structure.
132 | serv_addr.sin_port = htons(123);
133 |
134 | // Call up the server using its IP address and port number.
135 | if ( connect( sockfd, ( struct sockaddr * ) &serv_addr, sizeof( serv_addr) ) < 0 )
136 | error( "ERROR connecting" );
137 |
138 | // Set Origin timestamp in packet
139 | struct timespec tv;
140 | clock_gettime(CLOCK_REALTIME, &tv);
141 | packet.txTm_s = htonl( (int32_t)(tv.tv_sec - DIFF_SEC_1970_2036) );
142 | packet.txTm_f = htonl( tv.tv_nsec * NTP_NS_TO_FS );
143 |
144 | // Send it the NTP packet it wants. If n == -1, it failed.
145 | n = write( sockfd, ( char* ) &packet, sizeof( ntp_packet ) );
146 |
147 | if ( n < 0 )
148 | error( "ERROR writing to socket" );
149 |
150 | // Wait and receive the packet back from the server. If n == -1, it failed.
151 | n = read( sockfd, ( char* ) &packet, sizeof( ntp_packet ) );
152 |
153 | // Set Received Timestamp
154 | clock_gettime(CLOCK_REALTIME, &tv);
155 |
156 | if ( n < 0 )
157 | error( "ERROR reading from socket" );
158 |
159 | // Convert all fields from network byte order back to host byte order
160 | packet.refId = ntohl( packet.refId );
161 |
162 | packet.refTm_s = ntohl( packet.refTm_s );
163 | packet.refTm_f = ntohl( packet.refTm_f );
164 |
165 | packet.origTm_s = ntohl( packet.origTm_s );
166 | packet.origTm_f = ntohl( packet.origTm_f );
167 |
168 | packet.rxTm_s = ntohl( packet.rxTm_s );
169 | packet.rxTm_f = ntohl( packet.rxTm_f );
170 |
171 | packet.txTm_s = ntohl( packet.txTm_s );
172 | packet.txTm_f = ntohl( packet.txTm_f );
173 |
174 | packet.rootDelay_s = ntohl( packet.rootDelay_s );
175 | packet.rootDelay_f = ntohl( packet.rootDelay_f );
176 |
177 | packet.rootDispersion_s = ntohl( packet.rootDispersion_s );
178 | packet.rootDispersion_f = ntohl( packet.rootDispersion_f );
179 |
180 | packet.refId = ntohl( packet.refId );
181 |
182 | // Extract the 32 bits that represent the time-stamp seconds (since NTP epoch) from when the packet left the server.
183 | // Subtract 70 years worth of seconds from the seconds since 1900.
184 | // This leaves the seconds since the UNIX epoch of 1970.
185 | // (1900)------------------(1970)**************************************(Time Packet Left the Server)
186 |
187 | time_t txTm = ( time_t ) ( packet.txTm_s - NTP_TIMESTAMP_DELTA );
188 |
189 | char gpsRefId[5];
190 | strncpy(gpsRefId, (char *)&(packet.refId), 4);
191 | gpsRefId[4] = '\0';
192 |
193 | printf(" - Server Stratum: %"PRIu8"\n", packet.stratum);
194 | printf(" - Reference Identifier: %s\n", gpsRefId);
195 | printf(" - Reference Sync Timestamp: %"PRIu32".%"PRIu32"\n", packet.refTm_s, packet.refTm_f);
196 | float precision_raw = pow(2, packet.precision);
197 | printf(" - Server Clock Precision: ");
198 | if(precision_raw < 1e-7)
199 | {
200 | printf("%.1fns\n", precision_raw * 1e9);
201 | }
202 | else if(precision_raw < 1e-4)
203 | {
204 | printf("%.3fus\n", precision_raw * 1e6);
205 | }
206 | else
207 | {
208 | printf("%.3fms\n", precision_raw * 1e3);
209 | }
210 | printf(" - Server Clock Root Delay: %.2fms\n", (1000 * packet.rootDelay_s) + (SHORTNTPFS_TO_MS * packet.rootDelay_f));
211 | printf(" - Server Clock Dispersion: %.2fms\n", (1000 * packet.rootDispersion_s) + (SHORTNTPFS_TO_MS * packet.rootDispersion_f));
212 | printf("\n");
213 | printf(" - Client Origin Timestamp: %"PRIu32".%"PRIu32"\n", packet.origTm_s, packet.origTm_f);
214 | printf(" - Server Received Timestamp: %"PRIu32".%"PRIu32"\n", packet.rxTm_s, packet.rxTm_f);
215 | printf(" - Server Transmitted Timestamp: %"PRIu32".%"PRIu32"\n", packet.txTm_s, packet.txTm_f);
216 | printf(" - [Client Received Timestamp]: %"PRIu32".%"PRIu32"\n", (int32_t)(tv.tv_sec - DIFF_SEC_1970_2036), (uint32_t)(tv.tv_nsec * NTP_NS_TO_FS ));
217 | printf("\n");
218 | printf(" - - Client -> Server: %+.3fms\n", (1000 * (packet.rxTm_s - packet.origTm_s)) + NTPFS_TO_MS * (packet.rxTm_f - packet.origTm_f));
219 | printf(" - - Server Internal Delay: %+.3fms\n", NTPFS_TO_MS * (packet.txTm_f - packet.rxTm_f));
220 | printf(" - - Server -> Client: %+.3fms\n", NTPFS_TO_MS * ((int64_t)(tv.tv_nsec * NTP_NS_TO_FS ) - packet.txTm_f));
221 | printf("\n");
222 |
223 | int64_t t1, t2, t3, t4, offset;
224 |
225 | t2 = NTP_SEC_FRAC_TO_S64(packet.rxTm_s, packet.rxTm_f);
226 | t1 = NTP_SEC_FRAC_TO_S64(packet.origTm_s, packet.origTm_f);
227 | t3 = NTP_SEC_FRAC_TO_S64((int32_t)(tv.tv_sec - DIFF_SEC_1970_2036), (uint32_t)(tv.tv_nsec * NTP_NS_TO_FS ));
228 | t4 = NTP_SEC_FRAC_TO_S64(packet.txTm_s, packet.txTm_f);
229 | /* Clock offset calculation according to RFC 4330 */
230 | offset = ((t2 - t1) + (t3 - t4)) / 2;
231 |
232 | int32_t sec = (int32_t)((uint64_t)offset >> 32);
233 | int32_t frac = (uint32_t)((uint64_t)offset);
234 |
235 | printf(" - SNTP Calculated Clock Offset: %+.3fms\n", (sec * 1000) + (NTPFS_TO_MS * frac));
236 |
237 | return 0;
238 | }
239 |
--------------------------------------------------------------------------------
/firmware/tools/udp_bc_rx.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import socket
4 | from time import time, sleep
5 |
6 | #UDP_IP = '192.168.100.195'
7 | UDP_IP = ''
8 | UDP_PORT = 11236
9 |
10 | class bcolors:
11 | HEADER = '\033[95m'
12 | OKBLUE = '\033[94m'
13 | OKGREEN = '\033[92m'
14 | WARNING = '\033[93m'
15 | FAIL = '\033[91m'
16 | OFF = '\033[0m'
17 | BOLD = '\033[1m'
18 | UNDERLINE = '\033[4m'
19 |
20 | send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
21 | #send_sock.settimeout(1.0)
22 |
23 | #sock = socket.socket(socket.AF_INET, # Internet
24 | # socket.SOCK_DGRAM) # UDP
25 | send_sock.bind((UDP_IP, UDP_PORT))
26 |
27 | start_time = 0
28 | az_received = 0
29 |
30 | while True:
31 |
32 | data, addr = send_sock.recvfrom(1024) # buffer size is 1024 bytes
33 |
34 | print("RX!", "".join("%02x" % b for b in data))
35 | print("".join("%c" % b for b in data))
36 | #ts = int.from_bytes(data[0:4], byteorder='little', signed=False)
37 | #print(f"TS: %d" % (ts))
38 |
39 | #if data[4] == 0xFF:
40 | # # ADC Packet
41 | # joystick_el_raw = int.from_bytes(data[5:9], byteorder='little', signed=False)
42 | # joystick_az_raw = int.from_bytes(data[9:13], byteorder='little', signed=False)
43 |
44 | # print(f"[Joystick] Elevation: 0x%08X, Azimuth: 0x%08X" % (joystick_el_raw, joystick_az_raw))
45 |
--------------------------------------------------------------------------------
/firmware/tools/udp_debug_rx.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import socket
4 | from time import time, sleep
5 |
6 | #UDP_IP = '192.168.100.195'
7 | UDP_IP = '10.42.0.10'
8 | UDP_PORT = 123
9 |
10 | class bcolors:
11 | HEADER = '\033[95m'
12 | OKBLUE = '\033[94m'
13 | OKGREEN = '\033[92m'
14 | WARNING = '\033[93m'
15 | FAIL = '\033[91m'
16 | OFF = '\033[0m'
17 | BOLD = '\033[1m'
18 | UNDERLINE = '\033[4m'
19 |
20 | send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
21 | send_sock.settimeout(1.0)
22 |
23 | #sock = socket.socket(socket.AF_INET, # Internet
24 | # socket.SOCK_DGRAM) # UDP
25 | #sock.bind((UDP_IP, UDP_PORT))
26 |
27 | start_time = 0
28 | az_received = 0
29 |
30 | while True:
31 |
32 | MESSAGE = bytearray.fromhex('0102030405')
33 | #MESSAGE.extend((SPEED.to_bytes(2, byteorder='little', signed=True)))
34 | send_sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
35 |
36 | data, addr = send_sock.recvfrom(1024) # buffer size is 1024 bytes
37 |
38 | print("RX!", "".join("%02x" % b for b in data))
39 | ts = int.from_bytes(data[0:4], byteorder='little', signed=False)
40 | print(f"TS: %d" % (ts))
41 |
42 | if data[4] == 0xFF:
43 | # ADC Packet
44 | joystick_el_raw = int.from_bytes(data[5:9], byteorder='little', signed=False)
45 | joystick_az_raw = int.from_bytes(data[9:13], byteorder='little', signed=False)
46 |
47 | print(f"[Joystick] Elevation: 0x%08X, Azimuth: 0x%08X" % (joystick_el_raw, joystick_az_raw))
48 |
49 | #else:
50 | # print(hex(sid))
51 |
52 | #send_sock.close()
53 | sleep(1)
--------------------------------------------------------------------------------
/firmware/watchdog.c:
--------------------------------------------------------------------------------
1 | #include "main.h"
2 |
3 | static const WDGConfig wdg_cfg = {
4 | // 40 KHz input clock from LSI
5 | .pr = STM32_IWDG_PR_256, // Prescaler = 256 => 156.25Hz
6 | .rlr = STM32_IWDG_RL(79), // Reload value = 79 (slightly over 500ms),
7 | };
8 |
9 | static bool wdg_initialised = false;
10 | static uint32_t mask = WATCHDOG_MASK;
11 | static uint32_t fed = 0;
12 |
13 | void watchdog_init(void)
14 | {
15 | if(wdg_initialised)
16 | {
17 | return;
18 | }
19 |
20 | wdgStart(&WDGD1, &wdg_cfg);
21 | wdg_initialised = true;
22 | }
23 |
24 | THD_FUNCTION(watchdog_service_thread, arg)
25 | {
26 | (void)arg;
27 |
28 | /* Should have been init-ed by main(), but let's make sure */
29 | watchdog_init();
30 |
31 | while(1)
32 | {
33 | if((mask & fed) == mask)
34 | {
35 | fed = 0;
36 |
37 | // Feed the hardware dog
38 | wdgReset(&WDGD1);
39 | }
40 |
41 | chThdSleepMilliseconds(20);
42 | }
43 | }
44 |
45 | /* To be called by other threads */
46 | void watchdog_feed(uint32_t dog)
47 | {
48 | fed |= ((1 << dog) & 0xFFFFFFFF);
49 | }
--------------------------------------------------------------------------------
/firmware/watchdog.h:
--------------------------------------------------------------------------------
1 | #ifndef __WATCHDOG_H__
2 | #define __WATCHDOG_H__
3 |
4 | #define WATCHDOG_DOG_MAIN 0
5 | #define WATCHDOG_DOG_NTPD 1
6 |
7 |
8 | #define WATCHDOG_MASK ((1 << WATCHDOG_DOG_MAIN) \
9 | | (0 << WATCHDOG_DOG_NTPD))
10 |
11 | void watchdog_init(void);
12 |
13 | THD_FUNCTION(watchdog_service_thread, arg);
14 |
15 | void watchdog_feed(uint32_t dog);
16 |
17 | #endif /* __WATCHDOG_H__ */
--------------------------------------------------------------------------------
/firmware/web/.gitignore:
--------------------------------------------------------------------------------
1 | htdist/
2 |
--------------------------------------------------------------------------------
/firmware/web/build:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | source_dir="$(cd $(dirname ${BASH_SOURCE[0]}) && pwd)"
4 | cd $source_dir
5 |
6 | COLOUR_GREEN='\033[0;32m'
7 | COLOUR_YELLOW='\033[1;33m'
8 | COLOUR_PURPLE='\033[0;35m'
9 | COLOUR_RED='\033[0;31m'
10 | COLOUR_OFF='\033[0;00m'
11 | CLEAR_LINE='\033[2K'
12 |
13 | _ERROR_="${COLOUR_RED}[ERROR]${COLOUR_OFF}"
14 | _INFO_="${COLOUR_PURPLE}[INFO]${COLOUR_OFF}"
15 | _DEBUG_="${COLOUR_YELLOW}[DEBUG]${COLOUR_OFF}"
16 |
17 | opt_verbose=false
18 |
19 | printf_v() {
20 | if $opt_verbose;
21 | then
22 | printf $1;
23 | fi
24 | }
25 | printf_nv() {
26 | if ! $opt_verbose;
27 | then
28 | printf $1;
29 | fi
30 | }
31 |
32 | ## Read Flags
33 | OPTIND=1
34 | while getopts ":v" opt; do
35 | case "$opt" in
36 | v) # Debug
37 | opt_verbose=true
38 | ;;
39 | ?) # Illegal Option
40 | echo -e "$_ERROR_ Illegal option '$OPTARG'"
41 | exit 3
42 | ;;
43 | esac
44 | done
45 | for i in `seq 2 $OPTIND`; do shift; done
46 |
47 | printf "$_INFO_ Packing web files.. ";
48 | printf_v "\n"
49 |
50 | printf_v "Clearing htdist/..\n"
51 | rm -fr htdist/
52 | cp -r htsrc/ htdist/
53 |
54 | printf_v "Compressing files..\n"
55 | for file in $(find htdist/ -type f)
56 | do
57 | gzip -9 $file
58 | done
59 |
60 | printf_v "Packing headers..\n"
61 | for file in $(find htdist/ -type f -name *.gz)
62 | do
63 | file_path=${file%/*}
64 | file_basename=$(basename $file)
65 | file_headername=${file_basename//./_}.h
66 | pushd $file_path > /dev/null
67 | xxd -i $file_basename > "${file_headername}"
68 | rm $file_basename
69 | popd > /dev/null
70 | printf_v " - ${file_basename}\n"
71 | done
72 | printf_nv "${COLOUR_GREEN}OK${COLOUR_OFF}\n";
--------------------------------------------------------------------------------
/firmware/web/htsrc/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philcrump/stm32-ntp-server/0ff2c3581a8918b2f62c3641bfe897db4cfd1f44/firmware/web/htsrc/favicon.png
--------------------------------------------------------------------------------
/firmware/web/htsrc/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: "Open Sans", Arial, sans-serif;
3 | font-size: 16px;
4 | }
5 | h1, #footer {
6 | text-align: center;
7 | }
8 | #footer {
9 | padding-top: 14px;
10 | padding-bottom: 14px;
11 | font-size: 14px;
12 | font-weight: 500;
13 | color: #666;
14 | }
15 | #gnss-ui-table {
16 | width: 100%;
17 | }
18 | #gnss-svs-table {
19 | font-size: 11px;
20 | }
21 | #gnss-svs-table tr td {
22 | padding-left: 3px;
23 | padding-right: 3px;
24 | padding-bottom: 0px;
25 | }
26 | .Orbits {
27 | background: #FFF;
28 | margin-top:1em;
29 | margin-left:2em;
30 | margin-bottom:1em;
31 | }
32 |
33 | .Orbits .Variables {
34 | display:inline-block;
35 | vertical-align:top;
36 | width:28em;
37 | height:44em;
38 | overflow:auto;
39 | position:relative;
40 | }
41 |
42 | .Orbits .Variables table {
43 | font-family:'Roboto Mono',monospace;
44 | color:#000;
45 | border-spacing:.5em;
46 | display:block;
47 | position:absolute;
48 | left:50%;
49 | transform:translateX(-50%);
50 | }
51 |
52 | .Orbits .Variables table tr {
53 | text-align:center;
54 | }
55 |
56 | .Orbits .Variables table td {
57 | font-size:.85em;
58 | }
59 |
60 | #Orbits-Drawing {
61 | display:inline-block;
62 | vertical-align:top;
63 | margin-top:.5em;
64 | width: 350px;
65 | height: 350px;
66 | }
67 |
68 | #Orbits-Drawing .sats-label {
69 | font-size:12px;
70 | fill:#454545;
71 | font-weight:bold;
72 | stroke:transparent;
73 | }
74 |
75 | #Orbits-Drawing .satellite circle {
76 | stroke-width:2px;
77 | }
78 |
79 | #Orbits-Drawing svg {
80 | font-family:sans-serif;
81 | font-size:10px;
82 | text-anchor:middle;
83 | fill:none;
84 | stroke:#000;
85 | width:100%;
86 | height:100%;
87 | }
--------------------------------------------------------------------------------
/firmware/web/htsrc/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | STM32 NTP Server
10 |
11 |
12 |
13 |
14 |
15 |
16 | STM32 NTP Server
17 |
18 |
19 |
20 |
21 | GNSS Receiver
22 |
23 | NTP Server
24 |
25 |
26 |
27 |
28 |
29 |
34 |
35 |
36 |
37 |
38 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/firmware/web/htsrc/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const doc_gnss_ui = document.getElementById("gnss-ui");
4 | const doc_gnss_svs_ui = document.getElementById("gnss-svs-ui");
5 | const doc_ntpd_ui = document.getElementById("ntpd-ui");
6 |
7 | var status_svs = [];
8 | var status_gnss = {};
9 | var status_ntpd = {};
10 |
11 | const gnss_lookup_letter = {
12 | 0: "G",
13 | 2: "E",
14 | 3: "C",
15 | 6: "R"
16 | }
17 |
18 | const gnss_lookup_name = {
19 | 0: "GPS",
20 | 1: "SBAS",
21 | 2: "GAL",
22 | 3: "BDS",
23 | 4: "IMES",
24 | 5: "QZSS",
25 | 6: "GLO"
26 | }
27 |
28 | const gnss_lookup_colour = {
29 | 0: "green",
30 | 2: "blue",
31 | 3: "red",
32 | 6: "yellow"
33 | }
34 |
35 | function ts_ms_to_string(ts, ts_ms)
36 | {
37 | return (new Date((ts * 1000) + ts_ms)).toLocaleString();
38 | }
39 |
40 | var gnss_ui = {
41 | view: function()
42 | {
43 | return m("div", [
44 | m("p", m("b", "Status: "), `${status_gnss.fix ? "Locked" : "Searching.."}`),
45 | m("p", m("b", "Time: "), `${ts_ms_to_string(status_gnss.ts, status_gnss.ts_ms)}`),
46 | m("p", m("b", "Position: "), `${status_gnss.lat}°, ${status_gnss.lon}°, ${status_gnss.alt}m`),
47 | m("p", m("b", "SVs: "), `${status_gnss.svs_locked} locked, ${status_gnss.svs_nav} used in soln.`),
48 | m("p", m("b", "Timepulse Accuracy: "), `${status_gnss.fix ? `+/- ${status_gnss.time_accuracy_ns}ns` : "N/A"}`),
49 | ]);
50 | }
51 | }
52 |
53 | m.mount(doc_gnss_ui, gnss_ui);
54 |
55 |
56 | var gnss_svs_ui = {
57 | view: function()
58 | {
59 | return m("table", {id: 'gnss-svs-table'},
60 | m("tr", [
61 | m("th", "GNSS"),
62 | m("th", "SV"),
63 | m("th", "C/N0"),
64 | m("th", "Used in soln.")
65 | ]),
66 | status_svs.map(function(sv_obj) {
67 | return m("tr", [
68 | m("td", gnss_lookup_name[sv_obj.gnss] || "??"),
69 | m("td", `${gnss_lookup_letter[sv_obj.gnss] || ""}${sv_obj.sv}`),
70 | m("td", sv_obj.cn0),
71 | m("td", `${sv_obj.nav ? "Y" : "N"}`)
72 | ]);
73 | })
74 | );
75 | }
76 | }
77 |
78 | m.mount(doc_gnss_svs_ui, gnss_svs_ui);
79 |
80 | const ntpd_status_lookup_string = {
81 | 0: "Unsynchronized",
82 | 1: "In Lock",
83 | 2: "In Holdover",
84 | 3: "Degraded (Holdover expired)"
85 | }
86 |
87 | var ntpd_ui = {
88 | view: function()
89 | {
90 | return m("div", [
91 | m("p", m("b", "Status: "), `${ntpd_status_lookup_string[status_ntpd.status] || "??"}`),
92 | m("p", m("b", "Reported Stratum: "), `${status_ntpd.stratum}`),
93 | m("p", m("b", "Requests: "), `${status_ntpd.requests_count}`),
94 | ]);
95 | }
96 | }
97 |
98 | m.mount(doc_ntpd_ui, ntpd_ui);
99 |
100 | function status_update()
101 | {
102 | m.request({
103 | method: "GET",
104 | url: "/api/status"
105 | })
106 | .then(function(result)
107 | {
108 | //console.log(result);
109 | status_gnss = result.gnss;
110 | status_svs = result.svs;
111 | status_ntpd = result.ntpd;
112 |
113 | drawSVsPolar();
114 | });
115 | }
116 |
117 | status_update();
118 | setInterval(status_update, 1000);
119 |
120 |
121 | /* SVs Polar Projection derived from https://github.com/berthubert/galmon */
122 | /* (C) AHU Holding BV - bert@hubertnet.nl - https://berthub.eu/ */
123 |
124 | function flippedStereographic(x, y) {
125 | var cx = Math.cos(x), cy = Math.cos(y), k = 1 / (1 + cx * cy);
126 | return [k * cy * Math.sin(x), -k * Math.sin(y)];
127 | }
128 |
129 | function drawSVsPolar()
130 | {
131 | var sats = d3.select("#Orbits-Drawing").html("").append("svg");
132 |
133 | const width = 350; //sats.clientWidth;
134 | const height = 350; //sats.clientHeight;
135 |
136 | sats.attr("width", width);
137 | sats.attr("height", height);
138 |
139 | var projection = d3.geoProjection(flippedStereographic)
140 | .scale(width * 0.40)
141 | .clipAngle(130)
142 | .rotate([0, -90])
143 | .translate([width / 2 + 0.5, height / 2 + 0.5])
144 | .precision(1);
145 |
146 | var path = d3.geoPath().projection(projection);
147 |
148 | sats.append("path")
149 | .datum(d3.geoCircle().center([0, 90]).radius(90))
150 | .attr("stroke-width", 1.5)
151 | .attr("d", path);
152 |
153 | sats.append("path")
154 | .datum(d3.geoGraticule())
155 | .attr("stroke-width", 0.15)
156 | .attr("d", path);
157 | // .attr("fill", "none").attr("stroke", "black").attr("width", "100%").attr("height", "100%");
158 |
159 |
160 | sats.append("g")
161 | .selectAll("line")
162 | .data(d3.range(360))
163 | .enter().append("line")
164 | .each(function(d) {
165 | var p0 = projection([d, 0]),
166 | p1 = projection([d, d % 10 ? -1 : -2]);
167 |
168 | d3.select(this)
169 | .attr("x1", p0[0])
170 | .attr("y1", p0[1])
171 | .attr("x2", p1[0])
172 | .attr("y2", p1[1]);
173 | });
174 |
175 | /* Azimuth Labels */
176 | sats.append("g")
177 | .attr("fill", "black")
178 | .attr("stroke", "none")
179 | .selectAll("text")
180 | .data(d3.range(0, 360, 90))
181 | .enter().append("text")
182 | .each(function(d) {
183 | var p = projection([d, -4]);
184 | d3.select(this).attr("x", p[0]).attr("y", p[1]);
185 | })
186 | .attr("dy", "0.35em")
187 | .text(function(d) { return d === 0 ? "N" : d === 90 ? "E" : d === 180 ? "S" : d === 270 ? "W" : d + "°"; })
188 | .attr("font-weight", "bold")
189 | .attr("font-size", 14);
190 |
191 | /* Elevation Labels */
192 | sats.append("g")
193 | .attr("fill", "#A3ACA9")
194 | .attr("stroke", "none")
195 | .selectAll("text")
196 | .data(d3.range(10, 91, 10))
197 | .enter().append("text")
198 | .each(function(d) {
199 | var p = projection([0, d]);
200 | d3.select(this).attr("x", p[0]).attr("y", p[1]);
201 | })
202 | .attr("dy", "-0.4em")
203 | .text(function(d) { return d + "°"; });
204 |
205 | sats.select('g.satellites').remove();
206 |
207 | let points = sats
208 | .insert("g")
209 | .attr("class", "satellites")
210 | .selectAll('g.satellite')
211 | .data(status_svs)
212 | .enter()
213 | .append('g')
214 | .attr("transform", function(d) {
215 | var p = projection([d.az, d.el]);
216 | return 'translate(' + p[0] + ', ' + p[1] + ')';
217 | });
218 |
219 | points
220 | .attr('class', 'satellite')
221 | .append("circle")
222 | .attr("stroke", function(d) {
223 | return d.cn0 > 0 ? "transparent" : d[5];
224 | })
225 | .attr("r", function(d) {
226 | return d.cn0 > 0 ? d.cn0*0.125 : 3;
227 | })
228 | .attr("fill", function(d) {
229 | return d.cn0 > 0 ? (gnss_lookup_colour[d.gnss] || "transparent") : "transparent";
230 | });
231 |
232 | points
233 | .attr("r", 50)
234 | .append("text")
235 | .attr("class", "sats-label")
236 | .attr('dy', function(d) {
237 | return d.cn0 > 0 ? `${10+(d.cn0/8)}px` : "1.3em";
238 | })
239 | .attr('dx', function(d) {
240 | return d.cn0 > 0 ? `${3+(d.cn0/8)}px` : "0.7em";
241 | })
242 | .text(function(d){return `${gnss_lookup_letter[d.gnss] || "?"}${d.sv}`});
243 | }
--------------------------------------------------------------------------------
/firmware/web/htsrc/mithril.min.js:
--------------------------------------------------------------------------------
1 | !function(){"use strict";function e(e,t,n,r,o,l){return{tag:e,key:t,attrs:n,children:r,text:o,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0}}e.normalize=function(t){return Array.isArray(t)?e("[",void 0,void 0,e.normalizeChildren(t),void 0,void 0):null==t||"boolean"==typeof t?null:"object"==typeof t?t:e("#",void 0,void 0,String(t),void 0,void 0)},e.normalizeChildren=function(t){var n=[];if(t.length){for(var r=null!=t[0]&&null!=t[0].key,o=1;o0&&(i.className=l.join(" ")),r[e]={tag:o,attrs:i}}(i),a):(a.tag=i,a)}if(i.trust=function(t){return null==t&&(t=""),e("<",void 0,void 0,t,void 0,void 0)},i.fragment=function(){var n=t.apply(0,arguments);return n.tag="[",n.children=e.normalizeChildren(n.children),n},(a=function(e){if(!(this instanceof a))throw new Error("Promise must be called with `new`");if("function"!=typeof e)throw new TypeError("executor must be a function");var t=this,n=[],r=[],o=s(n,!0),l=s(r,!1),i=t._instance={resolvers:n,rejectors:r},u="function"==typeof setImmediate?setImmediate:setTimeout;function s(e,o){return function a(s){var f;try{if(!o||null==s||"object"!=typeof s&&"function"!=typeof s||"function"!=typeof(f=s.then))u(function(){o||0!==e.length||console.error("Possible unhandled promise rejection:",s);for(var t=0;t0||e(n)}}var r=n(l);try{e(n(o),r)}catch(e){r(e)}}c(e)}).prototype.then=function(e,t){var n,r,o=this._instance;function l(e,t,l,i){t.push(function(t){if("function"!=typeof e)l(t);else try{n(e(t))}catch(e){r&&r(e)}}),"function"==typeof o.retry&&i===o.state&&o.retry()}var i=new a(function(e,t){n=e,r=t});return l(e,o.resolvers,n,!0),l(t,o.rejectors,r,!1),i},a.prototype.catch=function(e){return this.then(null,e)},a.prototype.finally=function(e){return this.then(function(t){return a.resolve(e()).then(function(){return t})},function(t){return a.resolve(e()).then(function(){return a.reject(t)})})},a.resolve=function(e){return e instanceof a?e:new a(function(t){t(e)})},a.reject=function(e){return new a(function(t,n){n(e)})},a.all=function(e){return new a(function(t,n){var r=e.length,o=0,l=[];if(0===e.length)t([]);else for(var i=0;i'+t.children+"",i=i.firstChild):i.innerHTML=t.children,t.dom=i.firstChild,t.domSize=i.childNodes.length,t.instance=[];for(var a,u=r.createDocumentFragment();a=i.firstChild;)t.instance.push(a),u.appendChild(a);w(e,u,o)}function h(e,t,n,r,o,l){if(t!==n&&(null!=t||null!=n))if(null==t||0===t.length)s(e,n,0,n.length,r,o,l);else if(null==n||0===n.length)x(e,t,0,t.length);else{var i=null!=t[0]&&null!=t[0].key,a=null!=n[0]&&null!=n[0].key,u=0,f=0;if(!i)for(;f=f&&C>=u&&(w=t[S],b=n[C],w.key===b.key);)w!==b&&p(e,w,b,r,o,l),null!=b.dom&&(o=b.dom),S--,C--;for(;S>=f&&C>=u&&(d=t[f],h=n[u],d.key===h.key);)f++,u++,d!==h&&p(e,d,h,r,y(t,f,o),l);for(;S>=f&&C>=u&&u!==C&&d.key===b.key&&w.key===h.key;)g(e,w,E=y(t,f,o)),w!==h&&p(e,w,h,r,E,l),++u<=--C&&g(e,d,o),d!==b&&p(e,d,b,r,o,l),null!=b.dom&&(o=b.dom),f++,w=t[--S],b=n[C],d=t[f],h=n[u];for(;S>=f&&C>=u&&w.key===b.key;)w!==b&&p(e,w,b,r,o,l),null!=b.dom&&(o=b.dom),C--,w=t[--S],b=n[C];if(u>C)x(e,t,f,S+1);else if(f>S)s(e,n,u,C+1,r,o,l);else{var j,z,A=o,O=C-u+1,N=new Array(O),T=0,P=0,$=2147483647,I=0;for(P=0;P=u;P--){null==j&&(j=v(t,f,S+1));var L=j[(b=n[P]).key];null!=L&&($=L<$?L:-1,N[P-u]=L,w=t[L],t[L]=null,w!==b&&p(e,w,b,r,o,l),null!=b.dom&&(o=b.dom),I++)}if(o=A,I!==S-f+1&&x(e,t,f,S+1),0===I)s(e,n,u,C+1,r,o,l);else if(-1===$)for(T=(z=function(e){for(var t=[0],n=0,r=0,o=0,l=m.length=e.length,o=0;o>>1)+(r>>>1)+(n&r&1);e[t[a]]0&&(m[o]=t[n-1]),t[n]=o)}}for(n=t.length,r=t[n-1];n-- >0;)t[n]=r,r=m[r];return m.length=0,t}(N)).length-1,P=C;P>=u;P--)h=n[P],-1===N[P-u]?c(e,h,r,l,o):z[T]===P-u?T--:g(e,h,o),null!=h.dom&&(o=n[P].dom);else for(P=C;P>=u;P--)h=n[P],-1===N[P-u]&&c(e,h,r,l,o),null!=h.dom&&(o=n[P].dom)}}else{var R=t.lengthR&&x(e,t,u,t.length),n.length>R&&s(e,n,u,n.length,r,o,l)}}}function p(t,n,r,o,i,u){var s=n.tag;if(s===r.tag){if(r.state=n.state,r.events=n.events,function(e,t){do{if(null!=e.attrs&&"function"==typeof e.attrs.onbeforeupdate){var n=a.call(e.attrs.onbeforeupdate,e,t);if(void 0!==n&&!n)break}if("string"!=typeof e.tag&&"function"==typeof e.state.onbeforeupdate){var n=a.call(e.state.onbeforeupdate,e,t);if(void 0!==n&&!n)break}return!1}while(0);return e.dom=t.dom,e.domSize=t.domSize,e.instance=t.instance,e.attrs=t.attrs,e.children=t.children,e.text=t.text,!0}(r,n))return;if("string"==typeof s)switch(null!=r.attrs&&_(r.attrs,r,o),s){case"#":!function(e,t){e.children.toString()!==t.children.toString()&&(e.dom.nodeValue=t.children),t.dom=e.dom}(n,r);break;case"<":!function(e,t,n,r,o){t.children!==n.children?(E(e,t),d(e,n,r,o)):(n.dom=t.dom,n.domSize=t.domSize,n.instance=t.instance)}(t,n,r,u,i);break;case"[":!function(e,t,n,r,o,l){h(e,t.children,n.children,r,o,l);var i=0,a=n.children;if(n.dom=null,null!=a){for(var u=0;u-1||null!=e.attrs&&e.attrs.is||"href"!==t&&"list"!==t&&"form"!==t&&"width"!==t&&"height"!==t)&&t in e.dom}var N=/[A-Z]/g;function T(e){return"-"+e.toLowerCase()}function P(e){return"-"===e[0]&&"-"===e[1]?e:"cssFloat"===e?"float":e.replace(N,T)}function $(e,t,n){if(t===n);else if(null==n)e.style.cssText="";else if("object"!=typeof n)e.style.cssText=n;else if(null==t||"object"!=typeof t)for(var r in e.style.cssText="",n)null!=(o=n[r])&&e.style.setProperty(P(r),String(o));else{for(var r in n){var o;null!=(o=n[r])&&(o=String(o))!==String(t[r])&&e.style.setProperty(P(r),o)}for(var r in t)null!=t[r]&&null==n[r]&&e.style.removeProperty(P(r))}}function I(){this._=n}function L(e,t,n){if(null!=e.events){if(e.events[t]===n)return;null==n||"function"!=typeof n&&"object"!=typeof n?(null!=e.events[t]&&e.dom.removeEventListener(t.slice(2),e.events,!1),e.events[t]=void 0):(null==e.events[t]&&e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=n)}else null==n||"function"!=typeof n&&"object"!=typeof n||(e.events=new I,e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=n)}function R(e,t,n){"function"==typeof e.oninit&&a.call(e.oninit,t),"function"==typeof e.oncreate&&n.push(a.bind(e.oncreate,t))}function _(e,t,n){"function"==typeof e.onupdate&&n.push(a.bind(e.onupdate,t))}return I.prototype=Object.create(null),I.prototype.handleEvent=function(e){var t,n=this["on"+e.type];"function"==typeof n?t=n.call(e.currentTarget,e):"function"==typeof n.handleEvent&&n.handleEvent(e),this._&&!1!==e.redraw&&(0,this._)(),!1===t&&(e.preventDefault(),e.stopPropagation())},function(t,r,o){if(!t)throw new TypeError("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.");var l=[],i=u(),a=t.namespaceURI;null==t.vnodes&&(t.textContent=""),r=e.normalizeChildren(Array.isArray(r)?r:[r]);var s=n;try{n="function"==typeof o?o:void 0,h(t,t.vnodes,r,l,null,"http://www.w3.org/1999/xhtml"===a?void 0:a)}finally{n=s}t.vnodes=r,null!=i&&u()!==i&&"function"==typeof i.focus&&i.focus();for(var c=0;c=0&&(o.splice(l,2),t(n,[],u)),null!=r&&(o.push(n,r),t(n,e(r),u))},redraw:u}}(u,requestAnimationFrame,console),c=function(e){if("[object Object]"!==Object.prototype.toString.call(e))return"";var t=[];for(var n in e)r(n,e[n]);return t.join("&");function r(e,n){if(Array.isArray(n))for(var o=0;o=0&&(v+=e.slice(n,o)),s>=0&&(v+=(n<0?"?":"&")+u.slice(s,h));var m=c(a);return m&&(v+=(n<0&&s<0?"?":"&")+m),r>=0&&(v+=e.slice(r)),d>=0&&(v+=(r<0?"":"&")+u.slice(d)),v},h=function(e,t,n){var r=0;function o(e){return new t(e)}function l(e){return function(r,l){"string"!=typeof r?(l=r,r=r.url):null==l&&(l={});var i=new t(function(t,n){e(d(r,l.params),l,function(e){if("function"==typeof l.type)if(Array.isArray(e))for(var n=0;n=200&&e.target.status<300||304===e.target.status||/^file:\/\//i.test(t),a=e.target.response;if("json"===c?e.target.responseType||"function"==typeof n.extract||(a=JSON.parse(e.target.responseText)):c&&"text"!==c||null==a&&(a=e.target.responseText),"function"==typeof n.extract?(a=n.extract(e.target,n),i=!0):"function"==typeof n.deserialize&&(a=n.deserialize(a)),i)r(a);else{try{l=e.target.responseText}catch(e){l=a}var u=new Error(l);u.code=e.target.status,u.response=a,o(u)}}catch(e){o(e)}},"function"==typeof n.config&&(f=n.config(f,n,t)||f)!==h&&(l=f.abort,f.abort=function(){d=!0,l.call(this)}),null==u?f.send():"function"==typeof n.serialize?f.send(n.serialize(u)):u instanceof e.FormData?f.send(u):f.send(JSON.stringify(u))}),jsonp:l(function(t,n,o,l){var i=n.callbackName||"_mithril_"+Math.round(1e16*Math.random())+"_"+r++,a=e.document.createElement("script");e[i]=function(t){delete e[i],a.parentNode.removeChild(a),o(t)},a.onerror=function(){delete e[i],a.parentNode.removeChild(a),l(new Error("JSONP request failed"))},a.src=t+(t.indexOf("?")<0?"?":"&")+encodeURIComponent(n.callbackKey||"callback")+"="+encodeURIComponent(i),e.document.documentElement.appendChild(a)})}}(window,a,s.redraw),p=s,v=function(){return i.apply(this,arguments)};v.m=i,v.trust=i.trust,v.fragment=i.fragment,v.mount=p.mount;var m=i,y=a,g=function(e){if(""===e||null==e)return{};"?"===e.charAt(0)&&(e=e.slice(1));for(var t=e.split("&"),n={},r={},o=0;o-1&&u.pop();for(var c=0;c1&&"/"===l[l.length-1]&&(l=l.slice(0,-1))):l="/",{path:l,params:t<0?{}:g(e.slice(t+1,r))}},b=function(e){var t=w(e),n=Object.keys(t.params),r=[],o=new RegExp("^"+t.path.replace(/:([^\/.-]+)(\.{3}|\.(?!\.)|-)?|[\\^$*+.()|\[\]{}]/g,function(e,t,n){return null==t?"\\"+e:(r.push({k:t,r:"..."===n}),"..."===n?"(.*)":"."===n?"([^/]+)\\.":"([^/]+)"+(n||""))})+"$");return function(e){for(var l=0;l
15 |
16 | static char packet_buffer[WEB_MAX_PACKET_SIZE];
17 | static char url_buffer[WEB_MAX_PATH_SIZE];
18 | /**
19 | * @brief Decodes an URL sting.
20 | * @note The string is terminated by a zero or a separator.
21 | *
22 | * @param[in] url encoded URL string
23 | * @param[out] buf buffer for the processed string
24 | * @param[in] max max number of chars to copy into the buffer
25 | * @return The conversion status.
26 | * @retval false string converted.
27 | * @retval true the string was not valid or the buffer overflowed
28 | *
29 | * @notapi
30 | */
31 | #define HEXTOI(x) (isdigit(x) ? (x) - '0' : (x) - 'a' + 10)
32 | static bool decode_url(const char *url, char *buf, size_t max)
33 | {
34 | while (true) {
35 | int h, l;
36 | unsigned char c = *url++;
37 |
38 | switch (c) {
39 | case 0:
40 | case '\r':
41 | case '\n':
42 | case '\t':
43 | case ' ':
44 | case '?':
45 | *buf = 0;
46 | return true;
47 | case '.':
48 | if (max <= 1)
49 | return false;
50 |
51 | h = *(url + 1);
52 | if (h == '.')
53 | return false;
54 |
55 | break;
56 | case '%':
57 | if (max <= 1)
58 | return false;
59 |
60 | h = tolower((int)*url++);
61 | if (h == 0)
62 | return false;
63 | if (!isxdigit(h))
64 | return false;
65 |
66 | l = tolower((int)*url++);
67 | if (l == 0)
68 | return false;
69 | if (!isxdigit(l))
70 | return false;
71 |
72 | c = (char)((HEXTOI(h) << 4) | HEXTOI(l));
73 | break;
74 | default:
75 | if (max <= 1)
76 | return false;
77 |
78 | if (!isalnum(c) && (c != '_') && (c != '-') && (c != '+') &&
79 | (c != '/'))
80 | return false;
81 |
82 | break;
83 | }
84 |
85 | *buf++ = c;
86 | max--;
87 | }
88 | }
89 |
90 | static void http_server_serve(struct netconn *conn)
91 | {
92 | struct netbuf *inbuf;
93 | err_t err;
94 | u16_t packetlen;
95 |
96 | /* Read the data from the port, blocking if nothing yet there.
97 | We assume the request (the part we care about) is in one netbuf */
98 | err = netconn_recv(conn, &inbuf);
99 |
100 | if(err != ERR_OK)
101 | {
102 | netconn_close(conn);
103 | netbuf_delete(inbuf);
104 | return;
105 | }
106 |
107 | packetlen = netbuf_len(inbuf);
108 | /* Check we've got room for the packet */
109 | if(packetlen >= WEB_MAX_PACKET_SIZE)
110 | {
111 | /* We haven't, fail */
112 | netconn_close(conn);
113 | netbuf_delete(inbuf);
114 | return;
115 | }
116 | netbuf_copy(inbuf, packet_buffer, WEB_MAX_PACKET_SIZE);
117 |
118 | /* Is this an HTTP GET command? (only check the first 5 chars, since
119 | there are other formats for GET, and we're keeping it very simple )*/
120 | if(packetlen>=5 && (0 == memcmp("GET /", packet_buffer, 5)))
121 | {
122 | if(!decode_url(packet_buffer + (4 * sizeof(char)), url_buffer, WEB_MAX_PATH_SIZE))
123 | {
124 | /* URL decode failed.*/
125 | netconn_close(conn);
126 | netbuf_delete(inbuf);
127 | return;
128 | }
129 |
130 | web_paths_get(conn, url_buffer);
131 | }
132 |
133 | /* Close the connection (server closes in HTTP) */
134 | netconn_close(conn);
135 |
136 | /* Delete the buffer (netconn_recv gives us ownership,
137 | so we have to make sure to deallocate the buffer) */
138 | netbuf_delete(inbuf);
139 | }
140 |
141 | /**
142 | * Stack area for the http thread.
143 | */
144 | THD_WORKING_AREA(wa_http_server, WEB_THREAD_STACK_SIZE);
145 |
146 | /**
147 | * HTTP server thread.
148 | */
149 | THD_FUNCTION(http_server, p) {
150 | struct netconn *conn, *newconn;
151 | err_t err;
152 |
153 | (void)p;
154 | chRegSetThreadName("http");
155 |
156 | conn = netconn_new(NETCONN_TCP);
157 | if(conn == NULL)
158 | {
159 | chThdExit(MSG_RESET);
160 | }
161 |
162 | netconn_bind(conn, IP_ADDR_ANY, WEB_THREAD_PORT);
163 |
164 | netconn_listen(conn);
165 |
166 | /* Goes to the final priority after initialization.*/
167 | chThdSetPriority(WEB_THREAD_PRIORITY);
168 |
169 | while (true) {
170 | err = netconn_accept(conn, &newconn);
171 | if (err != ERR_OK)
172 | continue;
173 | http_server_serve(newconn);
174 | netconn_delete(newconn);
175 | }
176 | }
177 |
178 | void web_init(void)
179 | {
180 | chThdCreateStatic(wa_http_server, sizeof(wa_http_server), NORMALPRIO + 1, http_server, NULL);
181 | }
182 |
183 | /** @} */
184 |
--------------------------------------------------------------------------------
/firmware/web/web.h:
--------------------------------------------------------------------------------
1 | /*
2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | /**
18 | * @file web.h
19 | * @brief HTTP server wrapper thread macros and structures.
20 | * @addtogroup WEB_THREAD
21 | * @{
22 | */
23 |
24 | #ifndef WEB_H
25 | #define WEB_H
26 |
27 | #ifndef WEB_THREAD_STACK_SIZE
28 | #define WEB_THREAD_STACK_SIZE 1024
29 | #endif
30 |
31 | #ifndef WEB_THREAD_PORT
32 | #define WEB_THREAD_PORT 80
33 | #endif
34 |
35 | #ifndef WEB_THREAD_PRIORITY
36 | #define WEB_THREAD_PRIORITY (LOWPRIO + 2)
37 | #endif
38 |
39 | #ifndef WEB_MAX_PACKET_SIZE
40 | #define WEB_MAX_PACKET_SIZE 2048
41 | #endif
42 |
43 | #ifndef WEB_MAX_PATH_SIZE
44 | #define WEB_MAX_PATH_SIZE 128
45 | #endif
46 |
47 | #ifndef WEB_MAX_POSTBODY_SIZE
48 | #define WEB_MAX_POSTBODY_SIZE 128
49 | #endif
50 |
51 | void web_init(void);
52 |
53 | #endif /* WEB_H */
54 |
55 | /** @} */
56 |
--------------------------------------------------------------------------------
/firmware/web/web_paths.c:
--------------------------------------------------------------------------------
1 | #include "../main.h"
2 |
3 | #include "lwip/api.h"
4 | #include "lwip/netif.h"
5 |
6 | #include
7 | #include
8 | #include "chprintf.h"
9 |
10 | static char http_response[4096];
11 |
12 | static const char http_robots_txt_hdr[] = "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n";
13 | static const char http_robots_txt_body[] = "User-agent: *\r\nDisallow: /";
14 | static void web_path_robots_txt(struct netconn *conn);
15 |
16 | /* 403 - Forbidden */
17 | //static const char http_403_json_hdr[] = "HTTP/1.0 HTTP/1.0 403 Forbidden\r\nContent-type: application/javascript\r\n\r\n";
18 | //static const char http_403_hdr[] = "HTTP/1.0 HTTP/1.0 403 Forbidden\r\nContent-type: text/html\r\n\r\n";
19 | //static const char http_403_body[] = "Forbidden ";
20 |
21 | /* 404 - File Not Found */
22 | static const char http_404_hdr[] = "HTTP/1.0 404 Not Found\r\nContent-type: text/html\r\n\r\n";
23 | static const char http_404_body[] = "Path not found ";
24 | static void web_path_404(struct netconn *conn);
25 |
26 | /* HTML */
27 | //static const char http_html_hdr[] = "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n";
28 | static const char http_html_gz_hdr[] = "HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-type: text/html\r\n\r\n";
29 | #include "htdist/index_html_gz.h"
30 | static void web_path_index_html(struct netconn *conn);
31 |
32 | /* CSS */
33 | //static const char http_css_hdr[] = "HTTP/1.0 200 OK\r\nContent-type: text/css\r\n\r\n";
34 | static const char http_css_gz_hdr[] = "HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-type: text/css\r\n\r\n";
35 | #include "htdist/index_css_gz.h"
36 | static void web_path_index_css(struct netconn *conn);
37 |
38 | /* Javascript */
39 | //static const char http_javascript_hdr[] = "HTTP/1.0 200 OK\r\nContent-type: application/javascript\r\n\r\n";
40 | static const char http_javascript_gz_hdr[] = "HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-type: application/javascript\r\n\r\n";
41 | #include "htdist/index_js_gz.h"
42 | static void web_path_index_js(struct netconn *conn);
43 | #include "htdist/mithril_min_js_gz.h"
44 | static void web_path_mithril_min_js(struct netconn *conn);
45 | #include "htdist/d3_v4_min_js_gz.h"
46 | static void web_path_d3_v4_min_js(struct netconn *conn);
47 |
48 | /* JSON API */
49 | static const char http_json_hdr[] = "HTTP/1.0 200 OK\r\nContent-type: application/json\r\n\r\n";
50 | static void web_path_api_status(struct netconn *conn);
51 |
52 | /* PNG Image */
53 | static const char http_png_gz_hdr[] = "HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-type: image/png\r\n\r\n";
54 | #include "htdist/favicon_png_gz.h"
55 | static void web_path_favicon_png(struct netconn *conn);
56 |
57 | /* Binary Files */
58 | //static const char http_binary_hdr[] = "HTTP/1.0 200 OK\r\nContent-Type:application/octet-stream\r\n\r\n";
59 | //static const char http_binary_gz_hdr[] = "HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Type:application/octet-stream\r\n\r\n";
60 |
61 | void web_paths_get(struct netconn *conn, char *url_buffer)
62 | {
63 | if(strcmp("/", url_buffer) == 0 || strcmp("/index.html", url_buffer) == 0)
64 | {
65 | web_path_index_html(conn);
66 | }
67 | else if(strcmp("/api/status", url_buffer) == 0)
68 | {
69 | web_path_api_status(conn);
70 | }
71 | else if(strcmp("/index.css", url_buffer) == 0)
72 | {
73 | web_path_index_css(conn);
74 | }
75 | else if(strcmp("/index.js", url_buffer) == 0)
76 | {
77 | web_path_index_js(conn);
78 | }
79 | else if(strcmp("/mithril.min.js", url_buffer) == 0)
80 | {
81 | web_path_mithril_min_js(conn);
82 | }
83 | else if(strcmp("/d3.v4.min.js", url_buffer) == 0)
84 | {
85 | web_path_d3_v4_min_js(conn);
86 | }
87 | else if(strcmp("/favicon.png", url_buffer) == 0)
88 | {
89 | web_path_favicon_png(conn);
90 | }
91 | else if(strcmp("/robots.txt", url_buffer) == 0)
92 | {
93 | web_path_robots_txt(conn);
94 | }
95 | else
96 | {
97 | web_path_404(conn);
98 | }
99 | }
100 |
101 | static void web_path_404(struct netconn *conn)
102 | {
103 | netconn_write(conn, http_404_hdr, sizeof(http_404_hdr)-1, NETCONN_NOCOPY);
104 | netconn_write(conn, http_404_body, sizeof(http_404_body), NETCONN_NOCOPY);
105 | }
106 |
107 | static void web_path_index_html(struct netconn *conn)
108 | {
109 | netconn_write(conn, http_html_gz_hdr, sizeof(http_html_gz_hdr)-1, NETCONN_NOCOPY);
110 | netconn_write(conn, index_html_gz, index_html_gz_len, NETCONN_NOCOPY);
111 | }
112 |
113 | static void web_path_robots_txt(struct netconn *conn)
114 | {
115 | netconn_write(conn, http_robots_txt_hdr, sizeof(http_robots_txt_hdr)-1, NETCONN_NOCOPY);
116 | netconn_write(conn, http_robots_txt_body, sizeof(http_robots_txt_body)-1, NETCONN_NOCOPY);
117 | }
118 |
119 | static void web_path_index_css(struct netconn *conn)
120 | {
121 | netconn_write(conn, http_css_gz_hdr, sizeof(http_css_gz_hdr)-1, NETCONN_NOCOPY);
122 | netconn_write(conn, index_css_gz, index_css_gz_len, NETCONN_NOCOPY);
123 | }
124 |
125 | static void web_path_index_js(struct netconn *conn)
126 | {
127 | netconn_write(conn, http_javascript_gz_hdr, sizeof(http_javascript_gz_hdr)-1, NETCONN_NOCOPY);
128 | netconn_write(conn, index_js_gz, index_js_gz_len, NETCONN_NOCOPY);
129 | }
130 |
131 | static void web_path_mithril_min_js(struct netconn *conn)
132 | {
133 | netconn_write(conn, http_javascript_gz_hdr, sizeof(http_javascript_gz_hdr)-1, NETCONN_NOCOPY);
134 | netconn_write(conn, mithril_min_js_gz, mithril_min_js_gz_len, NETCONN_NOCOPY);
135 | }
136 |
137 | static void web_path_d3_v4_min_js(struct netconn *conn)
138 | {
139 | netconn_write(conn, http_javascript_gz_hdr, sizeof(http_javascript_gz_hdr)-1, NETCONN_NOCOPY);
140 | netconn_write(conn, d3_v4_min_js_gz, d3_v4_min_js_gz_len, NETCONN_NOCOPY);
141 | }
142 |
143 | static void web_path_favicon_png(struct netconn *conn)
144 | {
145 | netconn_write(conn, http_png_gz_hdr, sizeof(http_png_gz_hdr)-1, NETCONN_NOCOPY);
146 | netconn_write(conn, favicon_png_gz, favicon_png_gz_len, NETCONN_NOCOPY);
147 | }
148 |
149 |
150 | static void web_path_api_status(struct netconn *conn)
151 | {
152 | int str_ptr;
153 |
154 | netconn_write(conn, http_json_hdr, sizeof(http_json_hdr)-1, NETCONN_NOCOPY);
155 |
156 | RTCDateTime time_get_timespec;
157 | rtcGetTime(&RTCD1, &time_get_timespec);
158 | struct tm _tm;
159 | uint32_t _tm_ms;
160 | rtcConvertDateTimeToStructTm(&time_get_timespec, &_tm, &_tm_ms);
161 | uint32_t _ts = (uint32_t)mktime(&_tm);
162 |
163 | str_ptr = chsnprintf(http_response, 4096,
164 | "{"
165 | );
166 |
167 | str_ptr += chsnprintf(&http_response[str_ptr], (4096 - str_ptr),
168 | "\"gnss\": { \
169 | \"ts\": %ld \
170 | ,\"ts_ms\": %ld ",
171 | _ts,
172 | _tm_ms
173 | );
174 |
175 | str_ptr += chsnprintf(&http_response[str_ptr], (4096 - str_ptr),
176 | ",\"fix\": %s \
177 | ,\"time_accuracy_ns\": %ld \
178 | ,\"lat\": %.4f \
179 | ,\"lon\": %.4f \
180 | ,\"alt\": %.1f \
181 | ,\"svs_locked\": %d \
182 | ,\"svs_nav\": %d }",
183 | gnss_status.fix ? "true" : "false",
184 | gnss_status.time_accuracy_ns,
185 | ((float)gnss_status.lat * 1e-7),
186 | ((float)gnss_status.lon * 1e-7),
187 | ((float)gnss_status.alt * 1e-3),
188 | gnss_status.svs_locked_count,
189 | gnss_status.svs_nav_count
190 | );
191 |
192 | str_ptr += chsnprintf(&http_response[str_ptr], (4096 - str_ptr),
193 | ",\"svs\": ["
194 | );
195 |
196 | for(uint32_t i = 0; i < gnss_status.svs_count; i++)
197 | {
198 | if((gnss_status.svs[i].flags & 0x7) < 4 // Not time-synchronized
199 | || gnss_status.svs[i].cn0 < 5)
200 | {
201 | continue;
202 | }
203 |
204 | str_ptr += chsnprintf(&http_response[str_ptr], (4096 - str_ptr),
205 | "{ \"gnss\": %d, \"sv\": %d, \"cn0\": %d, \"el\": %d, \"az\": %d, \"nav\": %s },",
206 | gnss_status.svs[i].gnss_id,
207 | gnss_status.svs[i].sv_id,
208 | gnss_status.svs[i].cn0,
209 | gnss_status.svs[i].elevation,
210 | gnss_status.svs[i].azimuth,
211 | (((gnss_status.svs[i].flags & 0x8) >> 3) == 1) ? "true" : "false"
212 | );
213 | }
214 |
215 | if(http_response[str_ptr-1] == ',')
216 | {
217 | /* Overwrite tailing comma */
218 | http_response[str_ptr-1] = ']';
219 | }
220 | else
221 | {
222 | str_ptr += chsnprintf(&http_response[str_ptr], (4096 - str_ptr),
223 | "]"
224 | );
225 | }
226 |
227 | str_ptr += chsnprintf(&http_response[str_ptr], (4096 - str_ptr),
228 | ",\"ntpd\": { \
229 | \"status\": %ld, \
230 | \"requests_count\": %ld, \
231 | \"stratum\": %d \
232 | }",
233 | ntpd_status.status,
234 | ntpd_status.requests_count,
235 | ntpd_status.stratum
236 | );
237 |
238 | str_ptr += chsnprintf(&http_response[str_ptr], (4096 - str_ptr),
239 | "}"
240 | );
241 |
242 | netconn_write(conn, http_response, str_ptr, NETCONN_NOFLAG);
243 | }
244 |
--------------------------------------------------------------------------------
/firmware/web/web_paths.h:
--------------------------------------------------------------------------------
1 | #ifndef WEB_PATHS_H
2 | #define WEB_PATHS_H
3 |
4 | void web_paths_get(struct netconn *conn, char *url_buffer);
5 |
6 | void web_paths_post(struct netconn *conn, char *url_buffer, char *postbody_buffer);
7 |
8 | #endif /* WEB_PATHS_H */
--------------------------------------------------------------------------------
/hardware/build:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | wireviz *.yaml;
4 | rm *.html *.bom.tsv *.gv *.svg;
5 |
--------------------------------------------------------------------------------
/hardware/gnss_receiver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philcrump/stm32-ntp-server/0ff2c3581a8918b2f62c3641bfe897db4cfd1f44/hardware/gnss_receiver.png
--------------------------------------------------------------------------------
/hardware/gnss_receiver.yaml:
--------------------------------------------------------------------------------
1 | connectors:
2 | X1:
3 | type: STM32F429ZI Nucleo Board
4 | subtype: CN11
5 | pinout: [PC10 (TXD), PC11 (RXD), PC12 (TP), PD2, VDD, E5V, BT0, GND, PF6, NC, PF7, 3V3, PA13, NRST, PA14, 3V3, PA15, 5V, GND, GND, "..."]
6 | X2:
7 | type: Uputronics MAX-M8Q GNSS Breakout Board
8 | pinout: [SDA, SCL, TXD, RXD, TP, "-", GND, VCC]
9 |
10 | cables:
11 | W1:
12 | length: 0.25
13 | colors: [BU, WH, YE, RD, BK]
14 |
15 | connections:
16 | -
17 | - X1: [1,2,3,19,16]
18 | - W1: [1,2,3,5,4]
19 | - X2: [4,3,5,7,8]
--------------------------------------------------------------------------------
/images/gnss_receiver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philcrump/stm32-ntp-server/0ff2c3581a8918b2f62c3641bfe897db4cfd1f44/images/gnss_receiver.png
--------------------------------------------------------------------------------
/images/maximum_rate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philcrump/stm32-ntp-server/0ff2c3581a8918b2f62c3641bfe897db4cfd1f44/images/maximum_rate.png
--------------------------------------------------------------------------------
/images/ntpq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philcrump/stm32-ntp-server/0ff2c3581a8918b2f62c3641bfe897db4cfd1f44/images/ntpq.png
--------------------------------------------------------------------------------
/images/web_status.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/philcrump/stm32-ntp-server/0ff2c3581a8918b2f62c3641bfe897db4cfd1f44/images/web_status.png
--------------------------------------------------------------------------------