LaBox, Une Centrale DCC polyvalente et abordable (1)

Genèse du projet et première version logicielle

. Par : Thierry. URL : https://www.locoduino.org/spip.php?article337

LaBox est un projet collaboratif basé sur une spécification évolutive. Il s’agit d’une centrale DCC capable d’alimenter une voie principale ou une voie de programmation, (mais une seule à la fois), à l’aide d’un unique pont en H. LaBox peut être commandée via une liaison série (JMRI, IDE Monitor, liaison série radio) ou à l’aide d’une application smartphone (WiThrottle, Engine Driver, Z21) en mode Station (via la box Internet) ou en mode Point d’Accès (accessible partout dans les expositions et les clubs sans Wi-Fi).

Un écran OLED affiche les commandes des trains, tandis qu’une interface utilisateur simple avec seulement 3 boutons permet d’effectuer diverses actions, telles que la recherche automatique de l’adresse DCC d’une locomotive posée sur la voie.

LaBox est équipée d’un connecteur de sortie vers les rails, d’une prise d’alimentation unique (12 à 19V) compatible avec les réseaux à l’échelle N ou HO, ainsi que d’une interface CAN pour les commandes via réseau CAN. Cette centrale offre une solution complète et économique.

Son logiciel est issu de DCC++ dont on vous rebat les oreilles depuis des années...

Présentation de la série d’articles ...

Un peu d’histoire.

Dès son lancement, LOCODUINO a joué un rôle essentiel dans la diffusion et l’évolution du logiciel DCC++ pour Arduino, initialement conçu par Gregg E. Berman. (voir l’article Réalisation de centrales DCC avec le logiciel libre DCC++ (1)).

Notre collègue Thierry l’a transformé en la bibliothèque DCCpp, comme décrit dans l’article Bibliothèque DCCpp. Sur notre site, vous trouverez de nombreuses réalisations de centrales DCC en mode DIY, notamment dans l’article Réalisation de centrales DCC avec le logiciel libre DCC++ (3) et grâce aux contributions de notre communauté.

Par ailleurs, nous avons vu l’émergence d’applications gratuites sur smartphones telles que WiThrottle (iOS), Engine Driver (Android), et Z21 (iOS et Android), qui sont des postes de conduite individuels pour le logiciel JMRI ou la centrale Z21 de ROCO et FLEISCHMANN. L’idée était de les utiliser pour commander en Wi-Fi une centrale DCC de LOCODUINO.

Avec l’avènement des microcontrôleurs intégrant le Wi-Fi vers les années 2020 (ESP8266 puis ESP32), un projet d’envergure a vu le jour, décrit en détail sur le (Forum LOCODUINO).

LaBox vise à offrir une plateforme simple et abordable de centrale DCC, contrôlable de diverses manières : via un ou plusieurs smartphones, une liaison série, ainsi que des organes de gestion et de rétro-signalisation via un bus CAN.

Cette série d’articles a pour objectif de présenter les informations actualisées pour la construction de cette centrale, en éliminant les informations obsolètes. Cette synthèse sera continuellement mise à jour à chaque évolution.
Ce premier article se concentre sur la genèse du logiciel, en particulier sur les évolutions de DCCpp, tandis que les articles suivants aborderont le matériel, le logiciel à utiliser aujourd’hui et le mode d’emploi.
Une réalisation compatible Railcom (de Lenz) est également prévue.

Nous vous souhaitons une agréable lecture !

Cahier des charges :

Figure 1
Figure 1
La carte Labox, avec l’ESP32 à gauche, l’écran Oled à droite, et les boutons de couleur en bas.

Compte-tenu des échanges fructueux sur le forum, résumés ci-dessus, LaBox se décrit comme suit :

  • Une centrale conforme à la norme DCC donc capable d’émettre toutes les commandes DCC avec un courant généré jusqu’à 4A maximum sur les rails avec une détection de court-circuit. Au delà de 4A on pourra adjoindre un booster plus puissant dont il existe des réalisations fonctionnelles.
  • Fonctionnement sur la voie principale et la voie de programmation, mais une seule à la fois puisqu’il n’y a qu’une seule sortie DCC.
  • Connexion des smartphones en poste de pilotage au serveur Wifi (ESP32) en mode point d’accès (ne nécessite pas de box internet avec login et password, ce qui est plus pratique dans les expos), ou en mode station via un routeur internet.
  • Donc la centrale contient des traducteurs de commandes non-DCC++ en commandes DCC++.
  • Compatibilité avec le protocole de commande de DCC++ qui peut-être échangé soit sur une liaison série (filaire ou radio), soit avec un PC et une application de type JMRI ou RocRail.
  • Choix des adresses des locos (courtes et longues selon NMRA) au clavier de WiThrottle et mémorisé d’une fois sur l’autre.
  • Possibilité de piloter au moins 2 locos en même temps avec (au moins) 1 ou 2 smartphones reliés en Wifi (applications WiThrottle, Engine Driver ou Z21) ou autant de manettes sans fil.
  • Selon l’application smartphone, par sécurité, la loco s’arrête automatiquement en cas d’appel téléphonique et lorsque l’application n’est plus en premier plan ou le smartphone mis en veille. Sans impact sur LaBox.
  • Marche avant et arrière (avec passage par la vitesse 0)
  • Fonctions des locos (Lumière et F1..F28) supportées.
  • Reconnaissance de l’adresse DCC d’une loco posée seule sur les rails.
  • Une interface CAN pour permettre un pilotage des locos (ralentir, s’arrêter, repartir...) par un bloc système ou un gestionnaire alimenté par une rétro signalisation. Cette interface associée à un jeu de messages CAN permettant de nombreuses fonctions et de nombreux projets de modules externes.
  • L’intégration d’un gestionnaire de circulation dans cette centrale n’est pas envisagé pour des raisons de puissance limitée du contrôleur ESP32, mais de petits automatismes et des fonctions passerelles semblent envisageables.
  • Configuration de la centrale à l’aide d’une interface utilisateur simple.

Génèse du logiciel :

DCCpp
Lors de la définition des composants logiciels, le choix s’est porté tout naturellement sur ce que nous connaissions le mieux : DCCpp, la version bibliothèque LOCODUINO du DCC++ de Gregg E Berman. La version originale permet via la norme DCC de piloter les trains, de piloter des accessoires et de lire et d’écrire des CVs de configuration. DCC++ ajoute à la norme la possibilité de manipuler les broches de l’Arduino permettant ainsi de piloter des feux ou des aiguillages en analogique, ou de réagir à l’activation d’un bouton ou d’un capteur. Tout cela se fait avec une syntaxe texte. Par exemple mettre le courant sur la voie se dit <1>. Lire l’adresse de la loco <R 1 0 0>, etc... La bibliothèque DCCpp a ajouté à cette commande par du texte la possibilité de faire les mêmes choses mais directement par une fonction. Par exemple, plutôt que de construire une chaîne de caractères contenant <1>, puis de demander à DCC++ de la décoder pour allumer le courant, on peut maintenant directement appeler DCC::powerOn() . Ne pas passer par du texte rend les choses plus faciles à coder et plus rapides à exécuter. Ont aussi été ajoutées la lecture et l’écriture de CVs sur la voie principale pour les cas où il n’y a pas de voie de programmation.
Tout comme sa source DCCpp, le projet LaBox est une bibliothèque, auquel doit s’ajouter un fichier ino, nommé opportunément LaBox.ino !
Notez que DCCpp, disponible sur notre Github, reste tout à fait dans l’air du temps et peut encore rendre bien des services pour des petites centrales, comme celles proposées par LOCODUINO depuis des années maintenant.

HMI (Human Machine Interface)
La partie écran/boutons constitue un ensemble de classes dédiées et à part : le HMI.
Il permet de gérer l’écran Oled pour la configuration et l’affichage des données de pilotage. Outre les infos générales, l’affichage peut montrer jusqu’à trois engins moteurs avec indication de la vitesse, de la direction et de l’allumage des feux ou non.
L’écran sert également à afficher un menu manipulé par les trois boutons physiques (haut, bas, valider). Ce menu permet de configurer l’écran des engins moteurs, ou d’accéder à l’option permettant de récupérer l’adresse de la loco présente sur les rails. Bien sûr ce menu est configurable dans LaBox et permet d’ajouter des options si nécessaire.

Figure 2
L’écran de Labox affiche le logo, puis l’écran de connexion, pour finir par un résumé des informations importantes de Labox : Wifi, consommation...

ESP32
DCC++ et donc DCCpp, ont été conçus pour fonctionner sur un Arduino UNO ou un Mega2560. Nous l’avons nous même beaucoup utilisé sur des Arduino Nano, copie conforme du Uno dans un format plus petit de ticket de métro (pour ceux qui s’en rappellent...). Mais il a été décidé assez vite pour LaBox de bénéficier d’un microcontrôleur plus puissant, l’ESP32, à peu près au format d’un Nano. Doté de plus de mémoire, de la compatibilité avec Wifi et Bluetooth, et plus rapide, il nous permettrait d’aller plus loin dans l’écriture du logiciel et ne pas être dès le départ du projet aux limites du matériel, notamment la mémoire.
Pendant que notre collègue Cedric Bellec réalisait HMI je me suis penché sur le premier problème : la non compatibilité de DCCpp avec l’ESP32. Le mode de fonctionnement très bas-niveau du noyau de génération des trames DCC de DCC++ imposait de réécrire au moins partiellement ce mécanisme, en particulier la gestion des interruptions toujours particulière à un type de matériel.
Le temps de trouver une solution satisfaisante, et DCCpp est devenue compatible ESP32 !

Intégration
C’était le premier pas. L’arrivée en parallèle de HMI a permis enfin de compiler et installer le programme sur la centrale, de voir le logo LOCODUINO sur l’écran, et de voir tourner les roues de quelques locos.
Entre temps, Dominique (collégial je vous dis...) a adapté du code internet pour que la centrale discute en Wifi avec l’application WiThrottle gratuite sur iOS destinée à la base à piloter le logiciel JMRI. Suite à cette intégration, j’ai découvert EngineDriver sur Android qui fonctionne avec exactement le même protocole, et j’ai fait en sorte de gommer les petites différences pour que ça marche. Nous avions donc une centrale disposant d’un clavier sommaire, et d’une application iOS/Android pour la piloter et faire avancer les locos !

Ecrans application EngineDriver
Figure 3
WiThrottle sur iPhone. EngineDriver sur Android est très proche. Configuration du Wifi et pilotage de la loco 18.

Performances
Contrairement à nous, l’ESP32 dispose de deux cœurs, deux processeurs indépendants dans la même puce qui peuvent fonctionner simultanément et indépendamment sans ralentir l’autre.

Figure 4
Extrait du datasheet de l’ESP32, synoptique de la puce où l’on voit bien au centre les deux cœurs Xtensa 32 bits de la puce ESP32-WROOM-32 présente sur notre carte Devkit v3.

Le langage et surtout le système sous jacent permettent aussi de lancer plusieurs taches sur le même cœur, mais LaBox n’utilise pas cette possibilité. Mais que ce soit sur deux cœurs ou pas, ce fonctionnement, dit ’multi-tache’, ’multi-coeur’ ou ’multi-thread’, impose de prendre en compte l’accès simultané aux données lorsque nécessaire.
J’ai donné au premier cœur, le cœur 1, toute la mécanique de création du signal DCC. En clair tout DCC++, y compris l’analyse des ordres textuels donnés par la liaison série, mais aussi toute l’interface HMI liée au petit écran et aux trois boutons.
Le second cœur, le cœur 0 (oui, je sais...) a été dédié à la communication avec l’extérieur : Wifi bien sûr, mais aussi liaison série ou http. Le seul point de jonction entre les deux parties du programme restant l’écriture des messages reçus dans des tampons côté cœur Wifi, et la lecture de ces messages côté cœur DCC. Le but de donner un cœur juste pour les communications est de s’assurer qu’aucun message de commande venu de l’extérieur ne sera perdu à cause d’un traitement en DCC ou d’un rafraichissement de l’écran.
Lancer une tache sur le second cœur est possible grâce à une fonction fournie par l’environnement de développement de l’ESP32 :

TaskHandle_t Task1;

xTaskCreatePinnedToCore(
    Task1code,   // Fonction de la tache.
    "ReceiveCommands",     // nom de la tache.
    10000,       // Taille de la pile dédiée à cette tache
    NULL,        // Paramètres à envoyer à Task1Code()
    1,           // Priorité de la tache.
    &Task1,      // Variable qui va servir à désigner la tache.
    0);    // Attacher la tache au dernier cœur disponible..

Il faut fournir au second cœur (le 0 du dernier argument) une fonction à exécuter encore et toujours, à la manière du loop() du cœur principal. Ici la fonction est Task1code() . La taille de la pile associée à cette fonction doit être donnée, ici 10k. Le niveau de priorité est fixé à 1, sachant que seule sur son cœur la priorité de la tâche importe peu.

L’échange entre les deux cœurs des messages reçus par le monde extérieur est assuré par une classe CircularBuffer dont le rôle est de recueillir les octets dans un buffer circulaire, c’est à dire que les nouveaux octets arrivent à la queue du buffer, tandis que les octets lus sont retirés de la tête, à la manière d’une file d’attente dans un magasin où les nouveaux arrivés s’entassent au bout de la queue, tandis que le plus ancien est le prochain à en sortir. Un autre buffer, de texte celui là, est aussi concerné, c’est la classe MessageStack. C’est à ces endroits que le conflit entre les deux cœurs doit être géré.
Le C++ dispose de différentes manières de gérer l’accès simultané à des données par plusieurs tâches. J’ai employé un sémaphore, parfaitement adapté à un programme à destination ferroviaire ! En réalité, il s’agit d’un Mutex, version réduite du sémaphore. Pour un Mutex, une et une seule tache peut accéder aux données qu’il bloque, tandis qu’un sémaphore peut en autoriser plusieurs.
Un sémaphore doit être déclaré,
SemaphoreHandle_t xSemaphore; // semaphore d'exclusion mutuelle
alloué dès le lancement de LaBox, mais dans sa variante Mutex,
xSemaphore = xSemaphoreCreateMutex();
puis activé ou désactivé selon que l’accès est permis ou interdit.
Si l’on prend comme exemple une fonction de la classe, elle devrait s’écrire :

void CircularBuffer::function()
{
	// Blocage du sémaphore
	byte semaphoreTaken = this->xSemaphore == NULL?1:0;
	if (this->xSemaphore != NULL)
		if (xSemaphoreTake(this->xSemaphore, (TickType_t)100) == pdTRUE)
			semaphoreTaken = 1;
	if (semaphoreTaken == 1)
	{
		// Partie utile !
	}

	// Déblocage
	xSemaphoreGive(this->xSemaphore);
}

Cette activation/désactivation est assez lourde à faire un peu partout, dans toutes les fonctions d’accès aux données de la classe, alors j’ai utilisé la capacité du C à définir une macro :

#define START_SEMAPHORE()	\
	{ \
		byte semaphoreTaken = this->xSemaphore == NULL?1:0; \
		if (this->xSemaphore != NULL) \
			if (xSemaphoreTake(this->xSemaphore, (TickType_t)100) == pdTRUE) \
				semaphoreTaken = 1; \
		if (semaphoreTaken == 1)

#define END_SEMAPHORE()	\
		xSemaphoreGive(this->xSemaphore); \
	}

#endif

Notez le ’\’ à la fin de chaque ligne pour signifier que la macro n’est pas terminée.
Ce qui réduit notre fonction à :

void CircularBuffer::function()
{
	START_SEMAPHORE()
	{
		// Partie utile !
	}
	END_SEMAPHORE()
}

Rappelez vous que pour le ’C’, une macro n’est qu’une chaine de caractères qui sera remplacée par son contenu au moment de la compilation, ce qui va donner exactement le code original de la fonction function() vu plus haut !
Si un cœur tente de lire ou d’écrire dans une zone protégée alors que le sémaphore est levé, son exécution stoppe sur xSemaphoreTake() jusqu’à la libération du sémaphore. Il reprend alors le cours de son exécution. Simple non ? On pourrait penser que seule l’écriture doit être bloquée, mais si la lecture se fait alors qu’une écriture a commencé, on risque d’avoir une lecture partielle dangereuse. Mieux vaut tout bloquer. Les temps d’exécution sont tellement courts que cela ne représente pas de danger particulier.
Si vous vous souvenez, une interruption est en pratique une fonction qui est appelée après un événement matériel. Ce peut être un changement d’état d’une broche, ou comme dans notre cas un timer précis qui permet de cadencer le lancement de cette fonction à intervalle régulier. Ces interruptions utilisées pour la génération du signal DCC ne sont pas concernées par le blocage puisqu’elles n’accèdent pas à ces données partagées, et que même si le cœur DCC est en attente à cause d’une tentative de lecture, l’interruption sera quand même lancée et donc le signal DCC bien délivré.

Z21
L’ergonomie de EngineDriver (je n’avais pas d’iPhone à l’époque, mais j’ai pu voir depuis que ce n’était pas mieux...) ne me plaisant pas plus que ça, j’ai cherché des alternatives sur Android. C’est là que j’ai pu récupérer tout à fait légalement (https://www.z21.eu/media/Kwc_Basic_...) le protocole employé par l’application elle aussi gratuite Fleischman/Roco pour discuter avec sa centrale z21/Z21. Cette application utilisant une liaison Wifi UDP, par opposition au mode TCP utilisé par WiThrottle, une nouvelle partie Wifi a dû être ajoutée à LaBox. Elle a été intégrée au noyau de gestion du Wifi.

Figure 5
Application Fleischmann/Roco pour la centrale z21

Throttles
Une fois le protocole à peu près codé, et rodé, le code source de LaBox m’est apparu comme dispersé, filandreux, comment dire... spaghetti ? Des bouts de code étaient éparpillés pour gérer la connexion, la découverte de clients Wifis, les boucles d’interrogation pour traiter les messages reçus des applications...
J’ai décidé de mettre en application le côté objet du C++ et de créer des classes pour chaque type de "donneur d’ordre" dérivées d’une classe de base Throttle. Ce que j’appelle comme ça, ce sont les différents moyens de piloter DCC++, que ce soit par des commandes texte comme la liaison série, ou des instructions directes de l’API DCC++ comme WiThrottle et Z21. Il y aura une classe ’chapeau’ Throttles (notez le ’s’) qui est là pour gérer la liste de toutes les Throttle de LaBox. Par exemple, pour le setup de l’application, on va demander à Throttles de faire son setup(), et lui va parcourir toutes les Throttle et leur demander de faire leur setup(). Ainsi le code des différentes Throttle reste indépendant et les modifications à y apporter n’impactent ni DCC++, ni le LaBox.ino .
Lorsque le code des Throttle a été assez stable, j’ai ajouté une Throttle de plus pour permettre une certaine automatisation du pilotage, c’est la classe ThrottleAutomation. Avec elle, il est possible de fixer un ou plusieurs automatismes à déclencher quand on veut. Par exemple, un va-et-vient déclenché par un bouton, ou qui tourne à l’infini sur une expo avec des capteurs... On va voir que l’idée avait déjà germé ailleurs.

LaBox.ino

Du fait de son état de bibliothèque, LaBox devait disposer d’un programme .ino . Le but d’une bibliothèque est de cacher au maximum ses mécanismes internes, et de demander au fichier ino de simplement fixer les conditions de travail de la bibliothèque.

Voyons son contenu :

/*************************************************************
project: <LaBox>
author: <Locoduino/Thierry Paris>
description: <LaBox Wifi Controller sample>
*************************************************************/

#include "LaBox.h"

#if !defined(USE_TEXTCOMMAND) || !defined(USE_WIFI)
#error To be able to compile this sample, the lines #define USE_TEXTCOMMAND and #define USE_WIFI_EXTERNSSID or USE_WIFI_LOCALSSID must be uncommented in DCCpp.h
#endif

Le début du fichier, comprend principalement l’appel de la bibliothèque avec LaBox.h, et un message pour s’assurer qu’elle est bien configurée pour LaBox, avec une ligne de commande texte et un Wifi activés.

// WIFI

#ifdef USE_WIFI_EXTERNSSID
const char* ssid = "WIFI_SSID";
const char* password = "*******";

IPAddress ip      (192,   168,  0,  200);   // fix IP of the server in client mode
IPAddress gateway (192,   168,  0,  1);     // WiFi router's IP. If you are in AP mode, it's the ESP IP. If you are in client, it's your own gateway
IPAddress subnet  (255,   255,  255,  0);    // Subnet mask
IPAddress dns     (192,   168,  0,  1);     // DNS server, generally, the WiFi access point is a DNS server, but we can define another one.

#endif
#ifdef USE_WIFI_LOCALSSID
const char* ssid = "Locoduino LaBox";
const char* password = "";
#endif

Viennent ensuite les constantes pour le Wifi dans ses différentes configuration.

//--------------------------- HMI client -------------------------------------
hmi boxHMI(&Wire);
//----------------------------------------------------------------------------

int dccPPPort = 2560;
int wifiPort = 44444;

Quelques variables globales dont une instance de la classe hmi dont la classe de base est Adafruit_SSD1306. Le constructeur de cette classe de pilotage physique de l’écran a besoin de l’adresse d’une instance de Wire, la classe de l’interface I2C de l’ESP32 qui relie le micro contrôleur et l’écran.
Là aussi sont déclarés les ports réseau utilisés pour les communications Wifi.

// SERIAL
 
SERIAL_INTERFACE(Serial, Normal);
ThrottleSerial throttleSerial("Serial", SERIAL_INTERFACE_INSTANCE(Normal));

ThrottleWifiJMRI throttleWifiJMRI;

ThrottleWifi throttleWifi1("Z21 - 1", Z21_UDPPORT);
MessageConverterZ21 converter1;
ThrottleWifi throttleWifi2("Z21 - 2", Z21_UDPPORT);
MessageConverterZ21 converter2;
ThrottleWifi throttleWifi3("Z21 - 3", Z21_UDPPORT);
MessageConverterZ21 converter3;

ThrottleWifi throttleWifi4("WiThrottle - 1", wifiPort);
MessageConverterWiThrottle converterWT1;
ThrottleWifi throttleWifi5("WiThrottle - 2", wifiPort);
MessageConverterWiThrottle converterWT2;
ThrottleWifi throttleWifi6("WiThrottle - 3", wifiPort);
MessageConverterWiThrottle converterWT3;

Dans LaBox, les Throttles doivent être déclarés une fois pour toute au lancement de l’application. J’ai donc déclaré ici huit Throttles :

  • La Throttle de base, la liaison série qui permet de recevoir des ordres textes, soit à partir de la console série de l’IDE, ou par exemple d’une manette extérieure via une commande radio.
  • Une Throttle Wifi dédiée à JMRI. Je n’ai pas pu la tester faute d’installation JMRI fontionnelle...
  • Trois Throttles dédiées à l’application Z21 qui sont de ’simples’ ThrottleWifi, chacune associées à une classe MessageConverterZ21 destinées à transformer les messages Z21 reçus par Wifi en commande DCC++.
  • Trois Throttles dédiées cette fois à WiThrottle/EngineDriver, là encore des ThrottleWifi bien sûr, mais associées cette fois à des MessageConvertWiThrottle.

Toutes les Throttles peuvent fonctionner simultanément. On peut donc en théorie (je n’ai pas testé..) piloter des locos via 6 applis téléphone, plus la liaison série, et le tout en même temps ! J’ai au moins testé avec un iPhone 6 sans carte sim équipé de WiThrottle, une tablette avec l’appli Z21, et mon téléphone perso avec l’appli Z21. Tout ça marche ensemble, et les commandes passées via la console de l’IDE fonctionnent encore !

void setup()
{
  Serial.begin(115200);

  // setup led !
  pinMode(PIN_LEDBUILTIN, OUTPUT);
  digitalWrite(PIN_LEDBUILTIN, HIGH);

  Serial.print("LaBox ");
  Serial.println(LABOX_LIBRARY_VERSION);

Commençons le setup(). Au début, les initialisations de base : vitesse de la liaison série, config de la broche de la Led embarquée sur l’ESP32, affichage de la version du soft sur la console. On allume aussi la led pour montrer que le setup est en cours...

  //----------- Start HMI -------------
  boxHMI.begin();
  
  //Locomotives::debugLocomotivesSet();

  //----------- Start Wifi
#ifdef USE_WIFI_LOCALSSID
  ThrottleWifi::connectWifi(ssid, password);
#else
  ThrottleWifi::connectWifi(ssid, password, ip, gateway, subnet, dns);
#endif

  throttleSerial.begin();

  // For JMRI connection
  throttleWifiJMRI.begin();

  // For DCCpp syntax applications like DCCpp cab or RTDrive+
  //throttleWifi0.begin(TCP);

  // Z21 applications
  throttleWifi1.begin(&converter1);
  throttleWifi2.begin(&converter2);
  throttleWifi3.begin(&converter3);

  // WiThrottle protocol (WiThrottle and Engine Driver apps)
  throttleWifi4.begin(&converterWT1);
  throttleWifi5.begin(&converterWT2);
  throttleWifi6.begin(&converterWT3);

On va ensuite initialiser le HMI, se connecter au Wifi, puis initialiser une par une les différentes Throttles.

  DCCpp::begin();

  // configuration pour L6203 La Box
  DCCpp::beginMain(UNDEFINED_PIN, 33, 32, 36);
  DCCpp::setResendFunctions(false);

  digitalWrite(PIN_LEDBUILTIN, LOW);
}

On initialise enfin la partie DCCpp, pour terminer avec l’extinction de la led : fin du setup !

void loop()
{
  boxHMI.update();
  DCCpp::loop();
}

Le loop() quant à lui se révèle très simple : mise à jour du HMI qui va gérer les événements boutons et l’écran, et loop() de DCCpp pour traiter les messages arrivés depuis la précédente loop() ! Nul besoin de boucler sur les Throttles, c’est Task1Code() qui va s’en occuper.

Problèmes...

Michel -aka msport- est intervenu en testant le signal DCC obtenu par LaBox V1 avec un DCC sniffer proposé par la communauté DCC-EX et un matériel de son crû. Le rapport de validité des trames était pour le moins décevant. Presque tous les timings étaient en dehors des normes fixées par la norme DCC du NMRA, et nous ne devions le bon pilotage des locos qu’à la tolérance sans doute assez grande des décodeurs DCC embarqués.
D’autre part, impossible de faire marcher la lecture/écriture de CV. Même si notre centrale disposait avec HMI d’une option pour lire l’adresse de la loco, c’est à dire la CV 1, là encore les timings étaient sans doute hors norme. On verra qu’avec la version 2, j’ai peut être aussi trouvé la cause de tout ça dans la version 1 ! Mais ça, c’est une autre histoire, dans le prochain article sur le logiciel...

En attendant, même si le voyage valait bien un article et même si DCCpp est toujours valable sur les microcontrolleurs AVR, n’utilisez pas cette version telle quelle, la suivante, déjà disponible, sera bien meilleure et vraiment fonctionnelle ! Patience !

La suite de la lecture si trouve dans l’article LaBox, Une Centrale DCC polyvalente et abordable (2) où vous trouverez une réalisation détaillée et fortement simplifiée par l’utilisation d’un circuit imprimé pré-équipé des composants CMS, et le logiciel CommandStation-EX-LaBox qui lui est dédié.