IOT : A LA DéCOUVERTE DU SYSTèME D'EXPLOITATION ZEPHYR

Zephyr est un OS temps réel, compact, destiné à l’Internet des objets. C’est un projet collaboratif de la Linux Foundation.

Dans cet article nous allons le tester sur une base PC à l’aide de l’émulateur qemu.

Présentation de Zephyr

Le kernel Zephyr est un noyau de taille réduite disponible à ce jour pour les architectures x86, ARM v7 (Cortex M) et ARC (Arduino).

Il est placé sous licence Apache v2.0.

Ses principales caractéristiques sont :

  • Espace d’adressage unique: l’OS est linké avec l’application
  • OS configurable pour ne retenir que les fonctionnalités nécessaires (configuration basée sur le système Kbuild du kernel Linux).
  • Ensemble de services système développé :
    • support du multithreading
    • mécanisme d’interruptions
    • synchronisation de threads par sémaphores
    • IPC entre threads par message queues et byte streams
    • allocation mémoire dynamique
    • gestion de l’énergie

Installation de l’environnement de développement

L’environnement de développement peut être :

  • Windows
  • Linux
  • MacOS.

Dans notre cas nous allons travailler sur Linux (Ubuntu 16.04 LTS) sur une machine 64 bits.

Installons tout d’abord les prérequis de la machine de développement :

cch@cch-acer:~$ sudo apt-get install git make gcc gcc-multilib g++ libc6-dev-i386 g++-multilib python3-ply
[sudo] Mot de passe de cch :
Lecture des listes de paquets... Fait
Construction de l'arbre des dépendances
Lecture des informations d'état... Fait
g++ is already the newest version (4:5.3.1-1ubuntu1).
g++ passé en « installé manuellement ».
gcc is already the newest version (4:5.3.1-1ubuntu1).
gcc passé en « installé manuellement ».
gcc-multilib is already the newest version (4:5.3.1-1ubuntu1).
git is already the newest version (1:2.7.4-0ubuntu1).
libc6-dev-i386 is already the newest version (2.23-0ubuntu3).
libc6-dev-i386 passé en « installé manuellement ».
make is already the newest version (4.1-6).
make passé en « installé manuellement ».
Les paquets suivants ont été installés automatiquement et ne sont plus nécessaires :
cryptsetup dropbear-bin dropbear-initramfs dropbear-run spawn-fcgi
Veuillez utiliser « sudo apt autoremove » pour les supprimer.
The following additional packages will be installed:
g++-5-multilib lib32stdc++-5-dev libx32stdc++-5-dev
Paquets suggérés :
lib32stdc++6-5-dbg libx32stdc++6-5-dbg python-ply-doc
Les NOUVEAUX paquets suivants seront installés :
g++-5-multilib g++-multilib lib32stdc++-5-dev libx32stdc++-5-dev python3-ply
0 mis à jour, 5 nouvellement installés, 0 à enlever et 68 non mis à jour.
Il est nécessaire de prendre 1 291 ko dans les archives.
Après cette opération, 19,5 Mo d'espace disque supplémentaires seront utilisés.
Souhaitez-vous continuer ? [O/n]
Réception de:1 http://fr.archive.ubuntu.com/ubuntu xenial/main amd64 lib32stdc++-5-dev amd64 5.3.1-14ubuntu2 [636 kB]
Réception de:2 http://fr.archive.ubuntu.com/ubuntu xenial/main amd64 libx32stdc++-5-dev amd64 5.3.1-14ubuntu2 [608 kB]
Réception de:3 http://fr.archive.ubuntu.com/ubuntu xenial/main amd64 g++-5-multilib amd64 5.3.1-14ubuntu2 [978 B]
Réception de:4 http://fr.archive.ubuntu.com/ubuntu xenial/main amd64 g++-multilib amd64 4:5.3.1-1ubuntu1 [940 B]
Réception de:5 http://fr.archive.ubuntu.com/ubuntu xenial/universe amd64 python3-ply all 3.7-1 [46,2 kB]
1 291 ko réceptionnés en 1s (720 ko/s)
Sélection du paquet lib32stdc++-5-dev précédemment désélectionné.
(Lecture de la base de données... 330559 fichiers et répertoires déjà installés.)
Préparation du dépaquetage de .../lib32stdc++-5-dev_5.3.1-14ubuntu2_amd64.deb ...
Dépaquetage de lib32stdc++-5-dev (5.3.1-14ubuntu2) ...
Sélection du paquet libx32stdc++-5-dev précédemment désélectionné.
Préparation du dépaquetage de .../libx32stdc++-5-dev_5.3.1-14ubuntu2_amd64.deb ...
Dépaquetage de libx32stdc++-5-dev (5.3.1-14ubuntu2) ...
Sélection du paquet g++-5-multilib précédemment désélectionné.
Préparation du dépaquetage de .../g++-5-multilib_5.3.1-14ubuntu2_amd64.deb ...
Dépaquetage de g++-5-multilib (5.3.1-14ubuntu2) ...
Sélection du paquet g++-multilib précédemment désélectionné.
Préparation du dépaquetage de .../g++-multilib_4%3a5.3.1-1ubuntu1_amd64.deb ...
Dépaquetage de g++-multilib (4:5.3.1-1ubuntu1) ...
Sélection du paquet python3-ply précédemment désélectionné.
Préparation du dépaquetage de .../python3-ply_3.7-1_all.deb ...
Dépaquetage de python3-ply (3.7-1) ...
Traitement des actions différées (« triggers ») pour man-db (2.7.5-1) ...
Paramétrage de lib32stdc++-5-dev (5.3.1-14ubuntu2) ...
Paramétrage de libx32stdc++-5-dev (5.3.1-14ubuntu2) ...
Paramétrage de g++-5-multilib (5.3.1-14ubuntu2) ...
Paramétrage de g++-multilib (4:5.3.1-1ubuntu1) ...
Paramétrage de python3-ply (3.7-1) ...
cch@cch-acer:~$

ll faut maintenant télécharger et installer le SDK à partir du répertoire dédié. L’installeur se présente sous la forme d’une archive auto extractible qui sera exécutée dans le répertoire de test /media/yocto-1504/IoT/zephyr.

cch@cch-acer:/media/yocto-1504/IoT/zephyr$ wget https://nexus.zephyrproject.org/content/repositories/releases/org/zephyrproject/zephyr-sdk/0.8-i686/zephyr-sdk-0.8-i686-setup.run
--2016-05-23 10:51:18--  https://nexus.zephyrproject.org/content/repositories/releases/org/zephyrproject/zephyr-sdk/0.8-i686/zephyr-sdk-0.8-i686-setup.run
Résolution de nexus.zephyrproject.org (nexus.zephyrproject.org)… 199.19.213.246
Connexion à nexus.zephyrproject.org (nexus.zephyrproject.org)|199.19.213.246|:443… connecté.
requête HTTP transmise, en attente de la réponse… 200 OK
Taille : 378809314 (361M) [application/octet-stream]
Enregistre : «zephyr-sdk-0.8-i686-setup.run»

zephyr-sdk-0.8-i686-setu 100%[==================================>] 361,26M   414KB/s    in 5m 16s  

2016-05-23 10:56:35 (1,14 MB/s) - «zephyr-sdk-0.8-i686-setup.run» enregistré [378809314/378809314]

cch@cch-acer:/media/yocto-1504/IoT/zephyr$ 

Lançons l’installation du SDK :

cch@cch-acer:/media/yocto-1504/IoT/zephyr$ ./zephyr-sdk-0.8-i686-setup.run
Verifying archive integrity... All good.
Uncompressing SDK for Zephyr  100%  
Enter target directory for SDK (default: /opt/zephyr-sdk/): /media/yocto-1504/IoT/zephyr/zephyr-sdk
Installing SDK to /media/yocto-1504/IoT/zephyr/zephyr-sdk
Creating directory /media/yocto-1504/IoT/zephyr/zephyr-sdk
Success
 [*] Installing x86 tools... 
 [*] Installing arm tools... 
 [*] Installing arc tools... 
 [*] Installing iamcu tools... 
 [*] Installing mips tools... 
 [*] Installing nios2 tools... 
 [*] Installing additional host tools... 
Success installing SDK. SDK is ready to be used.

On remarque que l’installation concerne les outils pour toutes les architectures supportées. Le SDK installé, nous pouvons maintenant télécharger le code de Zephyr.

cch@cch-acer:/media/yocto-1504/IoT/zephyr$ git clone https://gerrit.zephyrproject.org/r/zephyr zephyr-project
Clonage dans 'zephyr-project'...
remote: Counting objects: 3026, done
remote: Finding sources: 100% (35/35)
remote: Total 68647 (delta 0), reused 68626 (delta 0)
Réception d'objets: 100% (68647/68647), 22.50 MiB | 331.00 KiB/s, fait.
Résolution des deltas: 100% (45258/45258), fait.
Vérification de la connectivité... fait.
cch@cch-acer:/media/yocto-1504/IoT/zephyr$ ls
zephyr-project  zephyr-sdk  zephyr-sdk-0.8-i686-setup.run

Allons voir le code source téléchargé. Au 1er coup d’oeil on constate une similitude avec le code kernel Linux (en plus léger). Ceci est confirmé avec la présence du système de configuration et de compilation Kbuild, pour lequel on retrouve des fichiers de configuration Kconfig et des fichiers Makefile similaires à ceux de Linux.

Le répertoire samples offre divers programmes d’exemple qui vont nous servir à réaliser les 1ers tests.

Compilation et test des exemples

Avant de lancer la 1ère compilation, nous devons définir correctement l’environnement :

cch@cch-acer:/media/yocto-1504/IoT/zephyr$ export ZEPHYR_GCC_VARIANT=zephyr
cch@cch-acer:/media/yocto-1504/IoT/zephyr$ export ZEPHYR_SDK_INSTALL_DIR=/media/yocto-1504/IoT/zephyr/zephyr-sdk
cch@cch-acer:/media/yocto-1504/IoT/zephyr$ cd zephyr-project
cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project$ source zephyr-env.sh
cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project$ env | grep ZEPHYR
ZEPHYR_SDK_INSTALL_DIR=/media/yocto-1504/IoT/zephyr/zephyr-sdk
ZEPHYR_BASE=/media/yocto-1504/IoT/zephyr/zephyr-project
ZEPHYR_GCC_VARIANT=zephyr

Hello world

Commençons par le traditionnel Hello world.

Tout d’abord positionnons nous dans le répertoire des sources correspondant :

cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project$ cd $ZEPHYR_BASE/samples/hello_world/microkernel

Nous pouvons obtenir de l’aide sur les différentes options de compilation à l’aide de make help :

cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/hello_world/microkernel$ make help
Cleaning targets:
  clean		  - Remove most generated files but keep configuration and backup files
  mrproper	  - Remove all generated files + config + various backup files
  distclean	  - mrproper + remove editor backup and patch files
  pristine	  - Remove the output directory with all generated files

Configuration targets:

  run 

Other generic targets:
  all		  - Build all targets marked with [*]
* zephyr	  - Build a zephyr application
  qemu		  - Build a zephyr application and run it in qemu
  flash		  - Build and flash an application
  debug		  - Build and debug an application using GDB

Supported Boards:

  To build an image for one of the supported boards below, run:

  make BOARD=
  in the application directory.

  To flash the image (if supported), run:

  make BOARD= flash

  make BOARD=altera_max10             - Build for altera_max10
  make BOARD=arduino_101              - Build for arduino_101
  make BOARD=arduino_101_factory      - Build for arduino_101_factory
  make BOARD=arduino_101_sss          - Build for arduino_101_sss
  make BOARD=arduino_101_sss_factory  - Build for arduino_101_sss_factory
  make BOARD=arduino_due              - Build for arduino_due
  make BOARD=basic_cortex_m3          - Build for basic_cortex_m3
  make BOARD=basic_minuteia           - Build for basic_minuteia
  make BOARD=frdm_k64f                - Build for frdm_k64f
  make BOARD=galileo                  - Build for galileo
  make BOARD=minnowboard              - Build for minnowboard
  make BOARD=nucleo_f103rb            - Build for nucleo_f103rb
  make BOARD=olimexino_stm32          - Build for olimexino_stm32
  make BOARD=qemu_cortex_m3           - Build for qemu_cortex_m3
  make BOARD=qemu_x86                 - Build for qemu_x86
  make BOARD=qemu_x86_iamcu           - Build for qemu_x86_iamcu
  make BOARD=quark_d2000_crb          - Build for quark_d2000_crb
  make BOARD=quark_se_devboard        - Build for quark_se_devboard
  make BOARD=quark_se_sss_devboard    - Build for quark_se_sss_devboard
  make BOARD=stm32_mini_a15           - Build for stm32_mini_a15


Build flags:

  make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build
  make V=2   [targets] 2 => give reason for rebuild of target
  make O=dir [targets] Locate all output files in "dir", including .config
  make C=1   [targets] Check all c source with $CHECK (sparse by default)
  make C=2   [targets] Force check of all c source with $CHECK
  make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections
  make W=n   [targets] Enable extra gcc checks, n=1,2,3 where
		1: warnings which may be relevant and do not occur too often
		2: warnings which occur quite often but may still be relevant
		3: more obscure warnings, can most likely be ignored
		Multiple levels can be combined with W=12 or W=123

Execute "make" or "make all" to build all targets marked with [*] 

On retrouve des options liées à l’utilisation de Kbuild telle que make V=1 pour avoir un build verbeux, make O=dir pour générer une compilation out of tree.

make BOARD= permet de sélectionner la machine cible désirée. Nous ferons ces premiers essais sous qemu donc nous choisissons la machine qemu_x86.

cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/hello_world/microkernel$ make BOARD=qemu_x86
Using /media/yocto-1504/IoT/zephyr/zephyr-project/boards/qemu_x86/qemu_x86_defconfig as base
Merging /media/yocto-1504/IoT/zephyr/zephyr-project/kernel/configs/micro.config
Merging prj.conf
#
# configuration written to .config
#
make[1] : on entre dans le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project »
make[2] : on entre dans le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project/samples/hello_world/microkernel/outdir »
  GEN     ./Makefile
scripts/kconfig/conf --silentoldconfig Kconfig
  Using /media/yocto-1504/IoT/zephyr/zephyr-project as source for kernel
  GEN     ./Makefile
  CHK     include/generated/version.h
  UPD     include/generated/version.h
  HOSTCC  scripts/gen_idt/gen_idt.o
  HOSTLD  scripts/gen_idt/gen_idt
  CHK     misc/generated/configs.c
  UPD     misc/generated/configs.c
  CHK     include/generated/offsets.h
  UPD     include/generated/offsets.h
  CHK     misc/generated/sysgen/prj.mdef
  UPD     misc/generated/sysgen/prj.mdef
  LD      lib/crypto/built-in.o
  LD      lib/libc/minimal/source/stdlib/built-in.o
  CC      lib/libc/minimal/source/stdout/fprintf.o
  CC      lib/libc/minimal/source/stdout/prf.o
  CC      lib/libc/minimal/source/stdout/sprintf.o
  CC      lib/libc/minimal/source/stdout/stdout_console.o
  LD      lib/libc/minimal/source/stdout/built-in.o
  CC      lib/libc/minimal/source/string/string.o
  LD      lib/libc/minimal/source/string/built-in.o
  LD      lib/libc/minimal/source/built-in.o
  LD      lib/libc/minimal/built-in.o
  LD      lib/libc/built-in.o
  LD      lib/built-in.o
  CC      kernel/microkernel/k_task.o
  CC      kernel/microkernel/k_idle.o
  CC      kernel/microkernel/k_init.o
  CC      kernel/microkernel/k_command_packet.o
  CC      kernel/microkernel/k_move_data.o
  CC      kernel/microkernel/k_ticker.o
  CC      kernel/microkernel/k_memory_map.o
  CC      kernel/microkernel/k_memory_pool.o
  CC      kernel/microkernel/k_irq.o
  CC      kernel/microkernel/k_nop.o
  CC      kernel/microkernel/k_offload.o
  CC      kernel/microkernel/k_event.o
  CC      kernel/microkernel/k_mailbox.o
  CC      kernel/microkernel/k_mutex.o
  CC      kernel/microkernel/k_fifo.o
  CC      kernel/microkernel/k_semaphore.o
  CC      kernel/microkernel/k_timer.o
  CC      kernel/microkernel/k_pipe_buffer.o
  CC      kernel/microkernel/k_pipe.o
  CC      kernel/microkernel/k_pipe_get.o
  CC      kernel/microkernel/k_pipe_put.o
  CC      kernel/microkernel/k_pipe_util.o
  CC      kernel/microkernel/k_pipe_xfer.o
  CC      kernel/microkernel/k_nano.o
  CC      kernel/microkernel/k_server.o
  LD      kernel/microkernel/built-in.o
  CC      kernel/nanokernel/nano_fiber.o
  CC      kernel/nanokernel/nano_lifo.o
  CC      kernel/nanokernel/nano_fifo.o
  CC      kernel/nanokernel/nano_stack.o
  CC      kernel/nanokernel/nano_sys_clock.o
  CC      kernel/nanokernel/nano_context.o
  CC      kernel/nanokernel/nano_init.o
  CC      kernel/nanokernel/nano_sema.o
  CC      kernel/nanokernel/version.o
  CC      kernel/nanokernel/device.o
  CC      kernel/nanokernel/errno.o
  LD      kernel/nanokernel/built-in.o
  LD      kernel/built-in.o
  CC      misc/printk.o
  LD      misc/debug/built-in.o
  CC      misc/generated/configs.o
  CC      misc/generated/sysgen/kernel_main.o
  LD      misc/generated/sysgen/built-in.o
  LD      misc/generated/built-in.o
  LD      misc/built-in.o
  LD      net/built-in.o
  CC      boards/qemu_x86/board.o
  LD      boards/qemu_x86/built-in.o
  LD      boards/built-in.o
  AS      arch/x86/core/i386_sysV_abi/intstub.o
  AS      arch/x86/core/i386_sysV_abi/swap.o
  CC      arch/x86/core/i386_sysV_abi/thread.o
  LD      arch/x86/core/i386_sysV_abi/built-in.o
  CC      arch/x86/core/fatal.o
  CC      arch/x86/core/cpuhalt.o
  CC      arch/x86/core/msr.o
  CC      arch/x86/core/dynamic.o
  CC      arch/x86/core/intconnect.o
  CC      arch/x86/core/excconnect.o
  CC      arch/x86/core/sys_fatal_error_handler.o
  AS      arch/x86/core/crt0.o
  CC      arch/x86/core/atomic.o
  AS      arch/x86/core/cache_s.o
  CC      arch/x86/core/cache.o
  AS      arch/x86/core/excstub.o
  CC      arch/x86/core/strtask.o
  LD      arch/x86/core/built-in.o
  CC      arch/x86/soc/ia32/soc.o
  LD      arch/x86/soc/ia32/built-in.o
  LD      arch/x86/built-in.o
  LD      arch/built-in.o
  CC      drivers/console/uart_console.o
  LD      drivers/console/built-in.o
  CC      drivers/interrupt_controller/i8259.o
  CC      drivers/interrupt_controller/system_apic.o
  CC      drivers/interrupt_controller/loapic_intr.o
  CC      drivers/interrupt_controller/ioapic_intr.o
  LD      drivers/interrupt_controller/built-in.o
  LD      drivers/random/built-in.o
  CC      drivers/serial/uart_ns16550.o
  LD      drivers/serial/built-in.o
  CC      drivers/timer/hpet.o
  CC      drivers/timer/sys_clock_init.o
  LD      drivers/timer/built-in.o
  LD      drivers/built-in.o
  CC      samples/hello_world/microkernel/src/main.o
  LD      samples/hello_world/microkernel/src/built-in.o
  LINK    zephyr.lnk
  SIDT    staticIdt.o
  LINK    zephyr.elf
  BIN     zephyr.bin
make[2] : on quitte le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project/samples/hello_world/microkernel/outdir »
make[1] : on quitte le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project »

La compilation a lieu par défaut dans le répertoire outdir et nous y trouvons les fichiers zephyr.elf et zephyr.strip qui constituent le résultat final.

zephyr.elf est l’exécutable au format ELF et zephyr.strip est le même exécutable strippé.

cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/hello_world/microkernel$ file outdir/zephyr.elf
outdir/zephyr.elf: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped
cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/hello_world/microkernel$ file outdir/zephyr.strip
outdir/zephyr.strip: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, stripped
cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/hello_world/microkernel$

Nous pouvons maintenant tester l’application dans qemu :

cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/hello_world/microkernel$ make BOARD=qemu_x86 qemu
make[1] : on entre dans le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project »
make[2] : on entre dans le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project/samples/hello_world/microkernel/outdir »
  Using /media/yocto-1504/IoT/zephyr/zephyr-project as source for kernel
  GEN     ./Makefile
  CHK     include/generated/version.h
  CHK     misc/generated/configs.c
  CHK     include/generated/offsets.h
  CHK     misc/generated/sysgen/prj.mdef
To exit from QEMU enter: 'CTRL+a, x'
[QEMU] CPU: qemu32
Hello World!

On obtient bien le message Hello World attendu. L’image strippé occupe 18 kilo octets.

Synchronisation

Prenons un exemple un peu plus consistant, qui comporte 2 tâches et des problèmes de synchronisation basé sur des sémaphores.

Les 2 tâches écrivent Hello World sur la console, mais l’accès à la console est réglé par 2 sémaphores.

Analyse du code et de la chaine de compilation

Regardons le code :

/* hello.c - Hello World demo */

/*
 * Copyright (c) 2012-2014 Wind River Systems, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include 

#if defined(CONFIG_STDOUT_CONSOLE)
#include 
#define PRINT           printf
#else
#include 
#define PRINT           printk
#endif

/*
 * Microkernel version of hello world demo has two tasks that utilize
 * semaphores and sleeps to take turns printing a greeting message at
 * a controlled rate.
 */


/* specify delay between greetings (in ms); compute equivalent in ticks */

#define SLEEPTIME  500
#define SLEEPTICKS (SLEEPTIME * sys_clock_ticks_per_sec / 1000)

/*
 *
 * @param taskname    task identification string
 * @param mySem       task's own semaphore
 * @param otherSem    other task's semaphore
 *
 */
void helloLoop(const char *taskname, ksem_t mySem, ksem_t otherSem)
{
	while (1) {
		task_sem_take(mySem, TICKS_UNLIMITED);

		/* say "hello" */
		PRINT("%s: Hello World!\n", taskname);

		/* wait a while, then let other task have a turn */
		task_sleep(SLEEPTICKS);
		task_sem_give(otherSem);
	}
}

void taskA(void)
{
	/* taskA gives its own semaphore, allowing it to say hello right away */
	task_sem_give(TASKASEM);

	/* invoke routine that allows task to ping-pong hello messages with taskB */
	helloLoop(__func__, TASKASEM, TASKBSEM);
}

void taskB(void)
{
	/* invoke routine that allows task to ping-pong hello messages with taskA */
	helloLoop(__func__, TASKBSEM, TASKASEM);
}

Nous voyons que le code manipule 2 tâches taskA et taskB qui se synchronisent à l’aide des sémaphores TASKASEM et TASKBSEM. Par contre nous remarquons que ni les tâches ni les sémaphores ne sont définis explicitement.

Ces objets systèmes sont en fait créés par le fichier prj.mdef :

% Application       : Hello demo

% TASK NAME  PRIO ENTRY STACK GROUPS
% ==================================
  TASK TASKA    7 taskA  1024 [EXE]
  TASK TASKB    7 taskB  1024 [EXE]

% SEMA NAME
% =============
  SEMA TASKASEM
  SEMA TASKBSEM

On peut remarquer que ce fichier définit également la priorité des tâches ainsi que la taille de leur stack.

Enfin explorons le fichier prj.conf qui définit la configuration du kernel retenue :

CONFIG_STDOUT_CONSOLE=y

C’est le fichier Makefile qui fait le lien entre ces divers éléments, en se basant sur ${ZEPHYR_BASE}/Makefile.inc :

MDEF_FILE = prj.mdef
KERNEL_TYPE = micro
BOARD ?= qemu_x86
CONF_FILE = prj.conf

include ${ZEPHYR_BASE}/Makefile.inc

Analyse du déroulement de la compilation

Lançons la compilation et étudions quelques points supplémentaires (comme la board par défaut est qemu_x86, on peut se dispenser de la définir lorsque l’on lance make) :

cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/hello_world/microkernel$ cd ../../synchronization/microkernel/
cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/synchronization/microkernel$ make
Using /media/yocto-1504/IoT/zephyr/zephyr-project/boards/qemu_x86/qemu_x86_defconfig as base
Merging /media/yocto-1504/IoT/zephyr/zephyr-project/kernel/configs/micro.config
Merging prj.conf
#
# configuration written to .config
#
make[1] : on entre dans le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project »
make[2] : on entre dans le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project/samples/synchronization/microkernel/outdir »
  GEN     ./Makefile
scripts/kconfig/conf --silentoldconfig Kconfig
  Using /media/yocto-1504/IoT/zephyr/zephyr-project as source for kernel
  GEN     ./Makefile
  CHK     include/generated/version.h
  UPD     include/generated/version.h
  HOSTCC  scripts/gen_idt/gen_idt.o
  HOSTLD  scripts/gen_idt/gen_idt
  CHK     misc/generated/configs.c
  UPD     misc/generated/configs.c
  CHK     include/generated/offsets.h
  UPD     include/generated/offsets.h
  CHK     misc/generated/sysgen/prj.mdef
  UPD     misc/generated/sysgen/prj.mdef
  LD      lib/crypto/built-in.o
  LD      lib/libc/minimal/source/stdlib/built-in.o
  CC      lib/libc/minimal/source/stdout/fprintf.o
  CC      lib/libc/minimal/source/stdout/prf.o
  CC      lib/libc/minimal/source/stdout/sprintf.o
  CC      lib/libc/minimal/source/stdout/stdout_console.o
  LD      lib/libc/minimal/source/stdout/built-in.o
  CC      lib/libc/minimal/source/string/string.o
  LD      lib/libc/minimal/source/string/built-in.o
  LD      lib/libc/minimal/source/built-in.o
  LD      lib/libc/minimal/built-in.o
  LD      lib/libc/built-in.o
  LD      lib/built-in.o
  CC      kernel/microkernel/k_task.o
  CC      kernel/microkernel/k_idle.o
  CC      kernel/microkernel/k_init.o
  CC      kernel/microkernel/k_command_packet.o
  CC      kernel/microkernel/k_move_data.o
  CC      kernel/microkernel/k_ticker.o
  CC      kernel/microkernel/k_memory_map.o
  CC      kernel/microkernel/k_memory_pool.o
  CC      kernel/microkernel/k_irq.o
  CC      kernel/microkernel/k_nop.o
  CC      kernel/microkernel/k_offload.o
  CC      kernel/microkernel/k_event.o
  CC      kernel/microkernel/k_mailbox.o
  CC      kernel/microkernel/k_mutex.o
  CC      kernel/microkernel/k_fifo.o
  CC      kernel/microkernel/k_semaphore.o
  CC      kernel/microkernel/k_timer.o
  CC      kernel/microkernel/k_pipe_buffer.o
  CC      kernel/microkernel/k_pipe.o
  CC      kernel/microkernel/k_pipe_get.o
  CC      kernel/microkernel/k_pipe_put.o
  CC      kernel/microkernel/k_pipe_util.o
  CC      kernel/microkernel/k_pipe_xfer.o
  CC      kernel/microkernel/k_nano.o
  CC      kernel/microkernel/k_server.o
  LD      kernel/microkernel/built-in.o
  CC      kernel/nanokernel/nano_fiber.o
  CC      kernel/nanokernel/nano_lifo.o
  CC      kernel/nanokernel/nano_fifo.o
  CC      kernel/nanokernel/nano_stack.o
  CC      kernel/nanokernel/nano_sys_clock.o
  CC      kernel/nanokernel/nano_context.o
  CC      kernel/nanokernel/nano_init.o
  CC      kernel/nanokernel/nano_sema.o
  CC      kernel/nanokernel/version.o
  CC      kernel/nanokernel/device.o
  CC      kernel/nanokernel/errno.o
  LD      kernel/nanokernel/built-in.o
  LD      kernel/built-in.o
  CC      misc/printk.o
  LD      misc/debug/built-in.o
  CC      misc/generated/configs.o
  CC      misc/generated/sysgen/kernel_main.o
  LD      misc/generated/sysgen/built-in.o
  LD      misc/generated/built-in.o
  LD      misc/built-in.o
  LD      net/built-in.o
  CC      boards/qemu_x86/board.o
  LD      boards/qemu_x86/built-in.o
  LD      boards/built-in.o
  AS      arch/x86/core/i386_sysV_abi/intstub.o
  AS      arch/x86/core/i386_sysV_abi/swap.o
  CC      arch/x86/core/i386_sysV_abi/thread.o
  LD      arch/x86/core/i386_sysV_abi/built-in.o
  CC      arch/x86/core/fatal.o
  CC      arch/x86/core/cpuhalt.o
  CC      arch/x86/core/msr.o
  CC      arch/x86/core/dynamic.o
  CC      arch/x86/core/intconnect.o
  CC      arch/x86/core/excconnect.o
  CC      arch/x86/core/sys_fatal_error_handler.o
  AS      arch/x86/core/crt0.o
  CC      arch/x86/core/atomic.o
  AS      arch/x86/core/cache_s.o
  CC      arch/x86/core/cache.o
  AS      arch/x86/core/excstub.o
  CC      arch/x86/core/strtask.o
  LD      arch/x86/core/built-in.o
  CC      arch/x86/soc/ia32/soc.o
  LD      arch/x86/soc/ia32/built-in.o
  LD      arch/x86/built-in.o
  LD      arch/built-in.o
  CC      drivers/console/uart_console.o
  LD      drivers/console/built-in.o
  CC      drivers/interrupt_controller/i8259.o
  CC      drivers/interrupt_controller/system_apic.o
  CC      drivers/interrupt_controller/loapic_intr.o
  CC      drivers/interrupt_controller/ioapic_intr.o
  LD      drivers/interrupt_controller/built-in.o
  LD      drivers/random/built-in.o
  CC      drivers/serial/uart_ns16550.o
  LD      drivers/serial/built-in.o
  CC      drivers/timer/hpet.o
  CC      drivers/timer/sys_clock_init.o
  LD      drivers/timer/built-in.o
  LD      drivers/built-in.o
  CC      samples/synchronization/microkernel/src/main.o
  LD      samples/synchronization/microkernel/src/built-in.o
  LINK    zephyr.lnk
  SIDT    staticIdt.o
  LINK    zephyr.elf
  BIN     zephyr.bin
make[2] : on quitte le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project/samples/synchronization/microkernel/outdir »
make[1] : on quitte le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project »

Étudions tout d’abord la configuration.

cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/synchronization/microkernel$ make
Using /media/yocto-1504/IoT/zephyr/zephyr-project/boards/qemu_x86/qemu_x86_defconfig as base
Merging /media/yocto-1504/IoT/zephyr/zephyr-project/kernel/configs/micro.config
Merging prj.conf
...

Celle ci est le résultat de plusieurs éléments :

  • une configuration de base liée à la Board : /media/yocto-1504/IoT/zephyr/zephyr-project/boards/qemu_x86/qemu_x86_defconfig
  • une configuration supplémentaire liée à la nature du kernel, nano ou micro : /media/yocto-1504/IoT/zephyr/zephyr-project/kernel/configs/micro.config. Ici c’est un micro kernel tel que défini dans le Makefile
  • enfin la configuration spécifique au projet du fichier prj.conf, qui définit la configuration propre à l’application

Le fichier qemu_x86_defconfig définit les variables de configuration propres à la carte retenue :

CONFIG_X86=y
CONFIG_SOC_IA32=y
CONFIG_BOARD_QEMU_X86=y
CONFIG_CPU_MINUTEIA=y
CONFIG_IA32_LEGACY_IO_PORTS=y
CONFIG_HPET_TIMER=y
CONFIG_HPET_TIMER_IRQ=2
CONFIG_HPET_TIMER_LEGACY_EMULATION=y
CONFIG_HPET_TIMER_RISING_EDGE=y
CONFIG_PIC_DISABLE=y
CONFIG_LOAPIC=y
CONFIG_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_UART_NS16550=y
CONFIG_UART_CONSOLE=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000

Le fichier micro.config sélectionne un kernel de type micro :


CONFIG_MICROKERNEL=y

Enfin le fichier prj.conf sélectionne la console :

CONFIG_STDOUT_CONSOLE=y

Au final le fichier de configuration globale outdir/.config résume la configuration finale du kernel Zephyr.

#
# Automatically generated file; DO NOT EDIT.
# Zephyr Kernel Configuration
#
# CONFIG_ARC is not set
# CONFIG_ARM is not set
CONFIG_X86=y
# CONFIG_NIOS2 is not set
# CONFIG_SYS_POWER_LOW_POWER_STATE_SUPPORTED is not set
# CONFIG_SYS_POWER_DEEP_SLEEP_SUPPORTED is not set
CONFIG_ARCH="x86"
CONFIG_SOC="ia32"
CONFIG_BOARD="qemu_x86"
CONFIG_ARCH_DEFCONFIG="arch/x86/defconfig"
# CONFIG_IRQ_OFFLOAD is not set
# CONFIG_XIP is not set
# CONFIG_SOC_ATOM is not set
CONFIG_SOC_IA32=y
# CONFIG_SOC_QUARK_D2000 is not set
# CONFIG_SOC_QUARK_SE is not set
# CONFIG_SOC_QUARK_X1000 is not set

#
# x86 Options
#

#
# x86 Core Options
#
CONFIG_NESTED_INTERRUPTS=y
CONFIG_EXCEPTION_DEBUG=y

#
# Memory Layout Options
#
CONFIG_IDT_NUM_VECTORS=256
CONFIG_MAX_IRQ_LINES=128
CONFIG_PHYS_LOAD_ADDR=0x00100000
CONFIG_PHYS_RAM_ADDR=0x00400000
CONFIG_RAM_SIZE=192
# CONFIG_GDT_DYNAMIC is not set
# CONFIG_DEBUG_IRQS is not set
CONFIG_CPU_MINUTEIA=y
CONFIG_CPU_HAS_FPU=y

#
# Processor Capabilities
#
# CONFIG_X86_IAMCU is not set

#
# Floating Point Options
#
# CONFIG_FLOAT is not set
CONFIG_ISA_IA32=y
CONFIG_IA32_LEGACY_IO_PORTS=y
# CONFIG_CMOV is not set
CONFIG_CACHE_LINE_SIZE_DETECT=y
CONFIG_CACHE_LINE_SIZE=0
# CONFIG_CACHE_FLUSHING is not set

#
# Platform Capabilities
#
CONFIG_NUM_DYNAMIC_STUBS=0
CONFIG_NUM_DYNAMIC_EXC_STUBS=0
CONFIG_NUM_DYNAMIC_EXC_NOERR_STUBS=0
CONFIG_PIC_DISABLE=y
# CONFIG_BOARD_BASIC_MINUTEIA is not set
CONFIG_BOARD_QEMU_X86=y

#
# Board Options
#
# CONFIG_NANOKERNEL is not set
CONFIG_MICROKERNEL=y

#
# General Kernel Options
#
CONFIG_SYS_CLOCK_TICKS_PER_SEC=100
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000
CONFIG_SYS_CLOCK_EXISTS=y
# CONFIG_INIT_STACKS is not set
# CONFIG_RING_BUFFER is not set
# CONFIG_KERNEL_EVENT_LOGGER is not set
# CONFIG_THREAD_MONITOR is not set
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT=40
CONFIG_KERNEL_INIT_PRIORITY_DEVICE=50

#
# Security Options
#
# CONFIG_STACK_CANARIES is not set

#
# Nanokernel Options
#
# CONFIG_BUILD_TIMESTAMP is not set
# CONFIG_INT_LATENCY_BENCHMARK is not set
CONFIG_MAIN_STACK_SIZE=1024
CONFIG_ISR_STACK_SIZE=2048
# CONFIG_THREAD_CUSTOM_DATA is not set
# CONFIG_NANO_TIMEOUTS is not set
# CONFIG_NANO_TIMERS is not set
CONFIG_NANOKERNEL_TICKLESS_IDLE_SUPPORTED=y
CONFIG_ERRNO=y
# CONFIG_ATOMIC_OPERATIONS_C is not set
# CONFIG_NANO_WORKQUEUE is not set

#
# Microkernel Options
#
CONFIG_MICROKERNEL_SERVER_STACK_SIZE=1024
CONFIG_MICROKERNEL_SERVER_PRIORITY=0
CONFIG_PRIORITY_CEILING=0
CONFIG_COMMAND_STACK_SIZE=64
CONFIG_NUM_COMMAND_PACKETS=16
CONFIG_NUM_TIMER_PACKETS=10
CONFIG_NUM_TASK_PRIORITIES=16
# CONFIG_WORKLOAD_MONITOR is not set
CONFIG_MAX_NUM_TASK_IRQS=0

#
# Timer API Options
#
CONFIG_TIMESLICING=y
CONFIG_TIMESLICE_SIZE=0
CONFIG_TIMESLICE_PRIORITY=0
# CONFIG_OBJECT_MONITOR is not set

#
# Power Management
#
# CONFIG_SYS_POWER_MANAGEMENT is not set

#
# Device Drivers
#
CONFIG_CONSOLE=y
CONFIG_CONSOLE_HAS_DRIVER=y
# CONFIG_CONSOLE_HANDLER is not set
CONFIG_UART_CONSOLE=y
CONFIG_UART_CONSOLE_ON_DEV_NAME="UART_0"
CONFIG_UART_CONSOLE_INIT_PRIORITY=60
# CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS is not set
# CONFIG_RAM_CONSOLE is not set
# CONFIG_IPM_CONSOLE_SENDER is not set
# CONFIG_IPM_CONSOLE_RECEIVER is not set
# CONFIG_UART_PIPE is not set
CONFIG_SERIAL=y

#
# Capabilities
#
CONFIG_SERIAL_HAS_DRIVER=y
# CONFIG_UART_INTERRUPT_DRIVEN is not set
# CONFIG_UART_LINE_CTRL is not set
# CONFIG_UART_DRV_CMD is not set

#
# Serial Drivers
#
CONFIG_UART_NS16550=y
# CONFIG_UART_NS16550_PCI is not set
# CONFIG_UART_NS16550_DLF is not set
CONFIG_UART_NS16550_PORT_0=y
CONFIG_UART_NS16550_PORT_0_NAME="UART_0"
CONFIG_UART_NS16550_PORT_0_IRQ_PRI=3
CONFIG_UART_NS16550_PORT_0_BAUD_RATE=115200
CONFIG_UART_NS16550_PORT_0_OPTIONS=0
CONFIG_UART_NS16550_PORT_1=y
CONFIG_UART_NS16550_PORT_1_NAME="UART_1"
CONFIG_UART_NS16550_PORT_1_IRQ_PRI=3
CONFIG_UART_NS16550_PORT_1_BAUD_RATE=115200
CONFIG_UART_NS16550_PORT_1_OPTIONS=0
# CONFIG_UART_K20 is not set
# CONFIG_UART_STELLARIS is not set

#
# Interrupt Controllers
#
CONFIG_LOAPIC=y
CONFIG_LOAPIC_BASE_ADDRESS=0xFEE00000
# CONFIG_LOAPIC_SPURIOUS_VECTOR is not set
CONFIG_IOAPIC=y
# CONFIG_IOAPIC_DEBUG is not set
CONFIG_IOAPIC_BASE_ADDRESS=0xFEC00000
CONFIG_IOAPIC_NUM_RTES=24
# CONFIG_MVIC is not set

#
# Timer Drivers
#
CONFIG_HPET_TIMER=y
CONFIG_HPET_TIMER_LEGACY_EMULATION=y
# CONFIG_HPET_TIMER_DEBUG is not set
CONFIG_HPET_TIMER_BASE_ADDRESS=0xFED00000
CONFIG_HPET_TIMER_IRQ=2
CONFIG_HPET_TIMER_IRQ_PRIORITY=4
# CONFIG_HPET_TIMER_FALLING_EDGE is not set
CONFIG_HPET_TIMER_RISING_EDGE=y
# CONFIG_HPET_TIMER_LEVEL_HIGH is not set
# CONFIG_HPET_TIMER_LEVEL_LOW is not set
# CONFIG_LOAPIC_TIMER is not set
# CONFIG_SYSTEM_CLOCK_DISABLE is not set
CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME=y
CONFIG_SYSTEM_CLOCK_INIT_PRIORITY=0

#
# Random Generation Configuration
#
# CONFIG_RANDOM_GENERATOR is not set
# CONFIG_TEST_RANDOM_GENERATOR is not set
# CONFIG_GROVE is not set
# CONFIG_PCI is not set
# CONFIG_GPIO is not set
# CONFIG_SHARED_IRQ is not set
# CONFIG_SPI is not set
# CONFIG_I2C is not set
# CONFIG_PWM is not set
# CONFIG_PINMUX is not set
# CONFIG_ADC is not set
CONFIG_ADC_INIT_PRIORITY=80
CONFIG_ADC_0_NAME="ADC_0"
CONFIG_ADC_0_IRQ_PRI=2
# CONFIG_RTC is not set
# CONFIG_WATCHDOG is not set
# CONFIG_CLOCK_CONTROL is not set
# CONFIG_IPM is not set
# CONFIG_AIO_COMPARATOR is not set
# CONFIG_QMSI_BUILTIN is not set
# CONFIG_QMSI_LIBRARY is not set
# CONFIG_QMSI is not set
# CONFIG_FLASH is not set
# CONFIG_SENSOR is not set
# CONFIG_COUNTER is not set

#
# Networking
#
# CONFIG_BLUETOOTH is not set
# CONFIG_NETWORKING is not set
# CONFIG_NET_BUF is not set

#
# Compile and Link Features
#
CONFIG_KERNEL_BIN_NAME="zephyr"
# CONFIG_HAVE_CUSTOM_LINKER_SCRIPT is not set
# CONFIG_VERSION_HEADER is not set
CONFIG_CROSS_COMPILE=""
# CONFIG_GDB_INFO is not set
# CONFIG_LINK_WHOLE_ARCHIVE is not set
CONFIG_COMPILER_OPT=""
CONFIG_TOOLCHAIN_VARIANT=""
# CONFIG_CPLUSPLUS is not set
CONFIG_MINIMAL_LIBC=y
# CONFIG_NEWLIB_LIBC is not set
# CONFIG_MINIMAL_LIBC_EXTENDED is not set

#
# Debugging Options
#
# CONFIG_DEBUG is not set
# CONFIG_TASK_DEBUG is not set
# CONFIG_STACK_USAGE is not set
CONFIG_PRINTK=y
CONFIG_STDOUT_CONSOLE=y
# CONFIG_EARLY_CONSOLE is not set
# CONFIG_ASSERT is not set
# CONFIG_DEBUG_TRACING_KERNEL_OBJECTS is not set

#
# Safe memory access
#
# CONFIG_MEM_SAFE is not set
# CONFIG_DEBUGGER_OWNS_FATAL_PROG_EXC_HANDLERS is not set
# CONFIG_DEBUG_INFO is not set
# CONFIG_GDB_SERVER is not set

#
# Logging Options
#
# CONFIG_SYS_LOG is not set

#
# System Monitoring Options
#
# CONFIG_PERFORMANCE_METRICS is not set

#
# Boot Options
#
# CONFIG_BOOTLOADER_KEXEC is not set
CONFIG_BOOTLOADER_UNKNOWN=y
# CONFIG_REBOOT is not set

#
# Cryptography
#
# CONFIG_TINYCRYPT is not set

Notons également que suite à la configuration la compilation concerne divers éléments dont les principaux sont relatifs :

  • au kernel
  • à l’architecture
  • à la board
  • aux drivers des périphériques sélectionnés
  • et enfin à l’application elle même.

Exécution

Lançons l’exécution pour constater l’alternat des 2 tâches qui ont même priorité :

cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/synchronization/microkernel$ make qemu
make[1] : on entre dans le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project »
make[2] : on entre dans le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project/samples/synchronization/microkernel/outdir »
  Using /media/yocto-1504/IoT/zephyr/zephyr-project as source for kernel
  GEN     ./Makefile
  CHK     include/generated/version.h
  CHK     misc/generated/configs.c
  CHK     include/generated/offsets.h
  CHK     misc/generated/sysgen/prj.mdef
To exit from QEMU enter: 'CTRL+a, x'
[QEMU] CPU: qemu32
taskA: Hello World!
taskB: Hello World!
taskA: Hello World!
taskB: Hello World!
taskA: Hello World!
taskB: Hello World!
taskA: Hello World!
taskB: Hello World!
taskA: Hello World!
taskB: Hello World!
taskA: Hello World!
taskB: Hello World!
QEMU: Terminated
make[2] : on quitte le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project/samples/synchronization/microkernel/outdir »
make[1] : on quitte le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project »

Synchronisation en C++

Zephyr supporte l’utilisation du C++. Pour l’illustrer prenons l’exemple cpp_synchronisation qui réalise exactement la même chose que l’exemple précédent, mais cette fois avec du code C++.

Le fichier source devient :

/*
 * Copyright (c) 2015-2016 Wind River Systems, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file C++ Synchronization demo.  Uses basic C++ functionality.
 */

#if defined(CONFIG_STDOUT_CONSOLE)
#include 
#define PRINT           printf
#else
#include 
#define PRINT           printk
#endif

/**
 * @class semaphore the basic pure virtual semaphore class
 */
class semaphore {
public:
	virtual int wait(void) = 0;
	virtual int wait(int timeout) = 0;
	virtual void give(void) = 0;
};

/* specify delay between greetings (in ms); compute equivalent in ticks */

#define SLEEPTIME  500
#define SLEEPTICKS (SLEEPTIME * sys_clock_ticks_per_sec / 1000)

/*
 * Microkernel version of C++ synchronization demo has two tasks that utilize
 * semaphores and sleeps to take turns printing a greeting message at
 * a controlled rate.
 */

#include 

/*
 * @class task_semaphore
 * @brief miscrokernel task semaphore
 *
 * Class derives from the pure virtual semaphore class and
 * implements it's methods for the microkernel semaphore
 */
class task_semaphore: public semaphore {
protected:
	struct _k_sem_struct _sema_internal;
	ksem_t sema;
public:
	task_semaphore();
	virtual ~task_semaphore() {}
	virtual int wait(void);
	virtual int wait(int timeout);
	virtual void give(void);
};

/*
 * @brief task_semaphore basic constructor
 */
task_semaphore::task_semaphore(): _sema_internal(__K_SEMAPHORE_DEFAULT)
{
	PRINT("Create semaphore %p\n", this);
	sema = (ksem_t)&_sema_internal;
}

/*
 * @brief wait for a semaphore
 *
 * Test a semaphore to see if it has been signaled.  If the signal
 * count is greater than zero, it is decremented.
 *
 * @return RC_OK on success, RC_FAIL on error
 */
int task_semaphore::wait(void)
{
	return task_sem_take(sema, TICKS_UNLIMITED);
}

/*
 * @brief wait for a semaphore within a specified timeout
 * Test a semaphore to see if it has been signaled.  If the signal
 * count is greater than zero, it is decremented. The function
 * waits for the specified timeout
 *
 * @param timeout the specified timeout in ticks
 *
 * @return RC_OK on success, RC_FAIL on error or RC_TIME on timeout
 */
int task_semaphore::wait(int timeout)
{
	return task_sem_take(sema, timeout);
}

/**
 *
 * @brief Signal a semaphore
 *
 * This routine signals the specified semaphore.
 *
 * @return N/A
 */
void task_semaphore::give(void)
{
	task_sem_give(sema);
}

/*
 *
 * @param taskname    task identification string
 * @param mySem       task's own semaphore
 * @param otherSem    other task's semaphore
 *
 */
void hello_loop(const char *taskname,
	       task_semaphore& my_sem,
	       task_semaphore& other_sem)
{
	while (1) {
		my_sem.wait();

		/* say "hello" */
		PRINT("%s: Hello World!\n", taskname);

		/* wait a while, then let other task have a turn */
		task_sleep(SLEEPTICKS);
		other_sem.give();
	}
}

/* two tasks synchronization semaphores */
task_semaphore sem_a;
task_semaphore sem_b;

extern "C" void task_a(void)
{
	/* taskA gives its own semaphore, allowing it to say hello right away */
	sem_a.give();

	/* invoke routine that allows task to ping-pong hello messages with taskB */
	hello_loop(__FUNCTION__, sem_a, sem_b);
}

extern "C" void task_b(void)
{
	/* invoke routine that allows task to ping-pong hello messages with taskA */
	hello_loop(__FUNCTION__, sem_b, sem_a);
}

Le fichier prj.mdef est modifié pour étendre la stack, C++ oblige.

% Application       : C++ demo

% TASK NAME  PRIO ENTRY STACK GROUPS
% ==================================
  TASK TASKA    7 task_a  2048 [EXE]
  TASK TASKB    7 task_b  2048 [EXE]

% SEMA NAME
% =============
  SEMA TASKASEM
  SEMA TASKBSEM

tandis que le fichier prj.conf active le support du C++ et supprime la redirection de stdout sur la console (printk sera utilisé au lieu de printf) :

CONFIG_COMPILER_OPT="-O0"
CONFIG_CPLUSPLUS=y

Après compilation nous pouvons lancer l’exécution :

cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/synchronization/microkernel$ cd ../../cpp_synchronization/microkernel/
cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/cpp_synchronization/microkernel$ make qemu
make[1] : on entre dans le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project »
make[2] : on entre dans le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project/samples/cpp_synchronization/microkernel/outdir »
  Using /media/yocto-1504/IoT/zephyr/zephyr-project as source for kernel
  GEN     ./Makefile
  CHK     include/generated/version.h
  CHK     misc/generated/configs.c
  CHK     include/generated/offsets.h
  CHK     misc/generated/sysgen/prj.mdef
To exit from QEMU enter: 'CTRL+a, x'
[QEMU] CPU: qemu32
Create semaphore 00104aec
Create semaphore 00104b00
task_a: Hello World!
task_b: Hello World!
task_a: Hello World!
task_b: Hello World!
task_a: Hello World!
task_b: Hello World!
task_a: Hello World!
task_b: Hello World!
QEMU: Terminated
make[2] : on quitte le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project/samples/cpp_synchronization/microkernel/outdir »
make[1] : on quitte le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project »

Cela fonctionne parfaitement donc les adeptes du C++ pourront utiliser leur langage favori. La taille de l’image strippée est de 20 kilo octets.

Réseau : echo_server et echo_client

Comme indiqué dans le fichier README du répertoire samples/net, nous allons travailler avec 2 terminaux initialisés avec l’environnement Zephyr.

cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/net$ 
cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/net$ cat README
Description of various IP stack test applications
=================================================

echo_server
-----------

The echo server test implements a network server that listens
UDP sockets. If that socket receives data, the server reverses
the data and sends it back.

The echo client can be running in the host system in which
case you need to use SLIP to connect to qemu. This usage scenario
is described in net/ip/tools/README file. This is the default
if you type "make qemu" in echo_server test application directory.
The network IP stack hooks right under IP stack (network level)
and sends the IP packet to host using SLIP. The layer 2 is the
SLIP layer in this case, no radio layer is simulated or used.

The echo server qemu instance can also be running against echo
client that is running in another qemu. For this you need two
terminal windows. In terminal 1 go to echo_server directory
and type "make server". This will start the echo server and setup
qemu pipes in suitable way and it will also start monitor application
that will store the transferred network traffic into pcap file
for later analysis. Then in terminal 2 go to echo_client directory and
type "make client". This will start the echo client that will
start to send data to the server and verify that it has received
the data back correctly. In the two qemu case we are simulating
the whole radio network meaning that the saved pcap file will
contain 802.15.4 network packets.


echo_client
-----------

The echo client test implements a network client that will
send UDP data to the echo server. The client verifies that
it has received data to the sent message and that the data
is correct.

The echo server can be running in the host system in which case
you need to use SLIP to connect to qemu. This usage scenario
is described in net/ip/tools/README file. This is the default
if you type "make qemu" in echo_client test application directory.
The network IP stack hooks right under IP stack (network level)
and sends the IP packet to host using SLIP. The layer 2 is the
SLIP layer in this case, no radio layer is simulated or used.

The echo client qemu instance can also be running against echo
server that is running in another qemu. This test scenario is
described in echo_server chapter above.

Dans le 1er terminal compilons puis lançons le programme echo_server :

cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/net/echo_server$ make server
rm -f /tmp/ip-stack-server.in /tmp/ip-stack-server.out /tmp/ip-stack-client.in \
      /tmp/ip-stack-client.out
mkfifo /tmp/ip-stack-server.in
mkfifo /tmp/ip-stack-server.out
ln /tmp/ip-stack-server.in /tmp/ip-stack-client.out
ln /tmp/ip-stack-server.out /tmp/ip-stack-client.in
make[1] : on entre dans le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project »
make[2] : on entre dans le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project/samples/net/echo_server/outdir »
  Using /media/yocto-1504/IoT/zephyr/zephyr-project as source for kernel
  GEN     ./Makefile
  CHK     include/generated/version.h
  CHK     misc/generated/configs.c
  CHK     include/generated/offsets.h
To exit from QEMU enter: 'CTRL+a, x'
[QEMU] CPU: qemu32
net: net_tx_fiber (0010f1e0): Starting TX fiber (stack 1024 bytes)
net: net_rx_fiber (0010f5e0): Starting RX fiber (stack 1024 bytes)
net: net_timer_fiber (0010ebe0): Starting net timer fiber (stack 1536 bytes)
net: net_driver_slip_open (0010e7e0): Initialized slip driver
init_app: run echo server
net: net_set_mac (0010e7e0): MAC 5e:25:e2:15:1:1
net: net_set_mac (0010e7e0): Tentative link-local IPv6 address fe80::5c25:e2ff:fe15:101

Le programme exécuté dans la machine virtuelle 1 se met en attente de connexion, en utilisant le driver SLIP. La connexion entre machine client et serveuse se fait au travers des FIFOS /tmp/ip-stack-server.in et /tmp/ip-stack-server.out de l’hôte.

Depuis le 2nd terminal compilons puis lançons le client :

cch@cch-acer:/media/yocto-1504/IoT/zephyr/zephyr-project/samples/net/echo_client$ make client
make[1] : on entre dans le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project »
make[2] : on entre dans le répertoire « /media/yocto-1504/IoT/zephyr/zephyr-project/samples/net/echo_client/outdir »
  Using /media/yocto-1504/IoT/zephyr/zephyr-project as source for kernel
  GEN     ./Makefile
  CHK     include/generated/version.h
  CHK     misc/generated/configs.c
  CHK     include/generated/offsets.h
To exit from QEMU enter: 'CTRL+a, x'
[QEMU] CPU: qemu32
net: net_tx_fiber (0010f820): Starting TX fiber (stack 1024 bytes)
net: net_rx_fiber (0010fc20): Starting RX fiber (stack 1024 bytes)
net: net_timer_fiber (0010f220): Starting net timer fiber (stack 1536 bytes)
net: net_driver_slip_open (0010ee20): Initialized slip driver
init_app: run mcast tester
net: net_set_mac (0010ee20): MAC c1:1e:47:15:2:2
net: net_set_mac (0010ee20): Tentative link-local IPv6 address fe80::c31e:47ff:fe15:202

Lorsque la connexion est établie le client envoie ses premiers paquets :

sending: Sending packet
send_packet: Trying to send 0x0010a1c0 buflen 932 datalen 884
send_packet: sent 884 bytes
Unicast sent 884 bytes
Waiting packet
net: net_tx_fiber (0010f820): Sending (buf 0010a1c0, len 932) to IP stack
net: net_driver_slip_send (0010f820): Sending 932 bytes, application data 884 bytes
net: net_rx_fiber (0010fc20): Received buf 0010b240
net: udp_packet_receive (0010fc20): packet received context 0010bfa0 len 932 appdata 0010b288 appdatalen 884
wait_reply: received 884 bytes

qui sont reçus et renvoyés par le serveur :

net: net_rx_fiber (0010f5e0): Received buf 0010a6a0
net: udp_packet_receive (0010f5e0): packet received context 0010b960 len 932 appdata 0010a6e8 appdatalen 884
receive: unicast received 884 bytes data
net: net_driver_slip_send (0010d800): Sending 932 bytes, application data 884 bytes

et ainsi de suite :

sending: Sending packet
send_packet: Trying to send 0x0010a740 buflen 82 datalen 34
send_packet: sent 34 bytes
Unicast sent 34 bytes
Waiting packet
net: net_tx_fiber (0010f820): Sending (buf 0010a740, len 82) to IP stack
net: net_driver_slip_send (0010f820): Sending 82 bytes, application data 34 bytes
net: net_rx_fiber (0010fc20): Received buf 0010b7c0
net: udp_packet_receive (0010fc20): packet received context 0010bfa0 len 82 appdata 0010b808 appdatalen 34
wait_reply: received 34 bytes

net: net_rx_fiber (0010f5e0): Received buf 0010ac20
net: udp_packet_receive (0010f5e0): packet received context 0010b960 len 82 appdata 0010ac68 appdatalen 34
receive: unicast received 34 bytes data
net: net_driver_slip_send (0010d800): Sending 82 bytes, application data 34 bytes

La communication fonctionne correctement.

Si l’on regarde les fichiers Makefile situés dans les répertoires samples/net/echo_server et samples/net/echo_client on constate que pour ces exemples on utilise un kernel de type nano.

# Makefile - echo server that is used in testing
#
# Copyright (c) 2015 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

NET_IFACE ?= slip
MDEF_FILE = prj.mdef
KERNEL_TYPE ?= nano
BOARD ?= qemu_x86
CONF_FILE ?= prj_$(NET_IFACE).conf

include $(ZEPHYR_BASE)/Makefile.inc

ifeq ($(CONFIG_NETWORKING_WITH_BT), y)
QEMU_EXTRA_FLAGS = -serial unix:/tmp/bt-server-bredr
else
include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack
endif
Ce kernel de type nano, qui en fait sert de base au kernel de type micro, vise les architectures très contraintes et permet une économie de ressources au prix de fonctionnalités moins élaborées. L’utilisation d’un kernel nano permet de réduire la taille du kernel jusqu’à 2 kilo octets ! Pour plus de détail sur les 2 types de kernel nous pourrons nous référer aux Kernel Fundamentals.

Partager cet article

Partager sur facebook
Partager sur twitter
Partager sur linkedin
Partager sur pinterest
Partager sur print
Partager sur email

UN BLOG DE

CIO Systèmes Embarqués – 1 Rue de la Presse, 42 000 Saint-Étienne – contact@ciose.fr – 04 77 93 34 32 

CIO  Systèmes Embarqués est le nom commercial de la SAS CIO Informatique Industrielle 

CIO Informatique Industrielle © 1991-2020 v3.0

Mentions Légales