This tutorial demonstrates how Mongoose Library can be used to implement a device dashboard runnning on the Zephyr OS. The full source code is at https://github.com/cesanta/mongoose/tree/master/examples/zephyr/device-dashboard
This tutorial is an example following on the device dashboard tutorial. You should read and follow that tutorial first.
This example uses the Zephyr freestanding application format, the
zephyrproject directory will be cloned on a separate directory and the project structure inside the example directory will follow this format:
src/- the directory that includes the application code
src/main.c- main application file, contains Mongoose logic and Zephyr network ready detection code
src/mongoose.c- Mongoose Library source code
src/mongoose.h- Mongoose Library header file
src/net.c- the common code for this example
src/packed_fs.c- a packed filesystem containing the web files to be served
CMakeLists.txt- a standard Zephyr project component, describes what files will be compiled
prj.conf- a standard Zephyr project component, contains configuration values
Makefile- mainly invokes Docker to call the Zephyr utilities
Build the project
It is assumed that you're using Linux or Mac as a workstation, you have Docker installed, and your user is able to run it. If in doubt, check it:
$ docker ps
Start a terminal in the project directory; clone the Mongoose Library repo,
and run the
make zephyr command:
$ git clone https://github.com/cesanta/mongoose $ cd mongoose/examples/zephyr/device-dashboard $ make zephyr
This takes several minutes, but you only need to run
make zephyr once. It clones the Zephyr repo and populates the
zephyrproject directory, then you can try other Zephyr examples by just running
make build. If you run
make zephyr again, it will update the repo, so call it from time to time to keep it up to date.
The default board is an x86 machine that can be simulated with QEMU, see the code README for details on playing with it. To build for a real board we need to specify which board we are going to build for. You can get a list of the supported boards and their names here, this is a list of the ones we tried:
|Board||Zephyr name and link to their info|
make build BOARD=yourboardname.
$ make build BOARD=nucleo_f746zg
- Once the build succeeds, run
make flash. The Makefile shares the USB bus with the Docker container, this works well with ST-Link and J-Link devices. If this does not work for you, pass the necessary Docker parameters inside
SHAREUSB(e.g.: make flash SHAREUSB=something). If you are using the standard debugger for your board, it will just work. If you are using another option like for example reflashing your ST-Link to a J-Link, you might need to add a
--runnerparameter, read the Zephyr documentation.
- The generated ELF file is at build/zephyr
- Now open a second terminal, this will be our serial console where Zephyr and Mongoose will log their activities. Run a serial port software (we use minicom; make sure you configure it at the proper speed, many boards use 115200bps). Check your board/devtool's device name, for ST-Link and J-Link it is usually
$ minicom -D /dev/ttyACM0
- You can run
make cleanto clean up the build files but keep the configuration files, which speeds the next build
- If you do major changes (e.g.: compiling for a different board), run
make pristineto clean up everything under the build directory.
Try it out
Start a browser on
IP_ADDRESS is the
board's IP address printed on the serial console. You should see a login screen.
From here on, please go to the device dashboard tutorial and repeat some of the steps depicted there
As the network is initialized by Zephyr (we configured it for that), the
main() function has two blocks:
- Wait until the netwok is ready (DHCP has assigned us an IP address)
- Run Mongoose
Wait for the network to come up
Zephyr will start calling our main() function right from the start, so we need to wait until we have a valid address before opening sockets.
We declare a semaphore and write a simple event handler that will be called by the Zephyr network manager. This function will release the semaphore.
On our main() function then we register that callback function and block on the semaphore:
Next goes Mongoose. As we commented, it should be run after network initialization is complete. The logic is standard; we initialize the event manager, start a listener on port 8000, and fall into an infinite event loop:
For this example we've chosen to embed all the web files in a packed filesystem, more information on the embedded filesystem tutorial
We have covered those aspects that are specific to the Zephyr implementation, for the details on the application and the UI, please see the device dashboard tutorial.
- Mongoose needs a large stack, allocates memory to perform its tasks, and interacts with Zephyr through its socket API. The following is a set of configuration options that generally apply to most Mongoose examples:
CONFIG_NET_SOCKETS=y CONFIG_NET_SOCKETS_POLL_MAX=32 CONFIG_POSIX_MAX_FDS=32 CONFIG_NET_CONNECTION_MANAGER=y CONFIG_ISR_STACK_SIZE=2048 CONFIG_MAIN_STACK_SIZE=8192 CONFIG_IDLE_STACK_SIZE=1024 CONFIG_MINIMAL_LIBC_RAND=y CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE=32768
- Since in this example we'll be using several connections simultaneously, we need to tell Zephyr so. Even though we are using the socket interface, we need to set the configuration options that increase the number of connections (and contexts) available: