Décodeurs S88 CAN vers Rocrail au travers d’une passerelle CAN/TCP

C’était quand même tordu. En Ethernet, pas besoin de vérifier que le serveur est connecté mais en WiFi oui ! Mais si tu mets le code, ça ne fonctionne plus en Ethernet **#@@&grrrrrrHummmmMerde :cyclone: :umbrella: :snowflake: :zap: :zap: :fire: :comet: :hammer_and_wrench:

Voici donc la modif lignes 282 et 283

#if defined(WIFI)
      if (!client || !client.connected())
        client = server.available();
#endif`

Une condition qui n’écrit ce morceau de code que si le WiFi est sélectionné.

Je comprends des fois qu’on puisse haïr l’informatique !

Bien à toi.

Christophe

1 « J'aime »

Christophe,

J’ai flashé avec succès les 2 platines filles Pico. Par contre maintenant quand je les branche ensemble (bus can par RJ comme prévu), elles s’annoncent toutes les deux en “Noeud 0” et du coup les infos se télescopent. Avant d’être flasher, la 2éme s’annonçait bien en “Noeud 1”.

Peux tu me dire où est la subtilité pour les différencier STP ?

Merci à toi.

Bruno.

Ligne 25 du programme, il faut changer en 0x01, 0x02 etc…

const uint16_t thisHash = 0x00; // Identifiant unique du module (UID)

Christophe

2 « J'aime »

Cà m’a travaillé cette nuit de devoir retourner dans le programme pour changer les identifiants. Et ce n’est pas sans risque d’erreur.

Aussi, dans les évolutions du décodeur, je mettrai un dip switch à 4 ou à 8 positions pour différencier chaque décodeur. C’est un peu rudimentaire mais ça a l’avantage d’être simple et très économique. Et finalement, c’est ce principe qu’a retenu notre marque préférée sur ses propres décodeurs !!!

Christophe

Au fait Bruno, tu penses bien à mettre le cavalier pour le 120Ω du CAN sur chacune des cartes à l’extrémité du bus CAN !

Christophe

Chacune des cartes ? Pas uniquement la dernière ?

Bruno.

Bonne idée Christophe :wink:

Bruno

Oui ma formulation n’est pas forcément claire. Une résistance sur la première carte, une autre résistance sur la dernière carte et rien sur les autres qui sont entre les deux

Christophe

Bonjour Christophe,

Ca marche, l’ensemble des détecteurs des 2 platines remontent bien vers Rocrail avec 2 N° de nœud.

Etapes suivantes pour moi : Affecter les détecteurs dans Rocrail et commencer à câbler les platines d’isolation. Pour ce faire j’ai imprimé des “mini rack” pour faciliter la fixation et gagner de la place.

                            
       

Bruno.

1 « J'aime »

@bilouteman76 Super cool ! Si avec ça vous ne faites pas @Jerome et toi des adeptes de la rétro-signalisation en CAN, je rentre au monastère.

Christophe

2 « J'aime »

Bonjour Christophe & Bruno (@bilouteman76),

Le fonctionnement des décodeurs Pico est désormais validé chez moi aussi ! Je n’ai pas essayé la passerelle en WiFi, celle en Ethernet que j’ai me convient. Tout fonctionne des la mise sous tension, “as it should be”.

Par contre Christophe, le code v.0.5.5 des Pico Decoder posté sur ton GitHub a toujours un While Serial actif, il faut aussi commenter les lignes 41 a 46. Pourras-tu corriger a l’occasion ?

Un grand merci pour votre aide en tout cas !

1 « J'aime »

Merci @Jerome Modif faite, v 0.5.6 à jour sur Github.

Que deviendrais-je sans toi et Bruno ?

Il y a vraiment des moments où c’est un plaisir de partager.

Christophe

2 « J'aime »

@bobyAndCo @bilouteman76

Une petite contribution de ma part…elle concerne la MaJ des états d’occupation au lancement de RocRail. Christophe a concu le code de la passerelle CAN/TCP de telle sorte que les messages d’occupation ne soient remontés de la passerelle vers RocRail en TCP que si un changement d’état d’un (ou plusieurs) capteur(s) est signalé par l’un des décodeurs Pico - cf la ligne 247 du code V0.5.7:

 if (module[idModule].value != (uint16_t)frameIn.data16[0])

Le “probleme” en l’état actuel, c’est qu’au lancement de RocRail, tous les rails de contacts / blocks sont signalés libres jusqu’a qu’un convoi se déplace et déclanche une nouvelle occupation sur sa route. La, tout se met a jour comme prévu.

Alors, ce que je propose, c’est de la programmation niveau scolaire, et je m’en excuse d’avance, mais cela fonctionne ! En gros, j’ai scindé la tache CanReceive avec une condition liée a la durée depuis la mise sous tension du dispositif décodeurs/passerelle - durée fixée ici a 50s, mais elle peut etre plus courte. Donc, en gros, pendant 50s, l’ESP32 de la passerelle travaille comme un boeuf et mitraille RocRail de messages TCP puis, passé ce délai, c’est une notification TCP vers RocRail par exception comme prévue a l’origine. Je suis certain qu’il y a moyen de faire beaucoup plus efficace & élégant, mais hey il n’y a que le résultat qui compte ! :sweat_smile:

void CANReceiveTask(void \*pvParameters)

{
CANMessage frameIn;
Message message;

while (true)
{
if (ACAN_ESP32::can.receive(frameIn))
{
uint16_t idModule = frameIn.id;


    if (time_top + 50000 > millis())
    {
    message.module = idModule;
    for (byte i = 0; i < 16; i++)
        {
          message.sensor = i;
          message.value = ((frameIn.data16[0] & (1 << i)) >> i);
          xQueueSend(canToTcpQueue, &message, portMAX_DELAY);
        }
    module[idModule].value = frameIn.data16[0];
    }
    else
    {
        if (module[idModule].value != (uint16_t)frameIn.data16[0])
        {
        Serial.printf("Received from node %d value %d\n", idModule, frameIn.data16[0]);
        message.module = idModule;
              for (byte i = 0; i < 16; i++)
              {
                message.sensor = i;
                message.value = ((frameIn.data16[0] & (1 << i)) >> i);
                xQueueSend(canToTcpQueue, &message, portMAX_DELAY);
              }
        module[idModule].value = frameIn.data16[0];
        }
    }   
} 
vTaskDelay(1 / portTICK_PERIOD_MS);
}
} // end CANReceiveTask

On déclarera donc simplement la variable “time_top” dans le Void Set Up pour l’initialisation de l’horloge:

// Create queues
  canToTcpQueue = xQueueCreate(50, sizeof(CANMessage));
  tcpToCanQueue = xQueueCreate(50, BUFFER_SIZE * sizeof(byte));
  debugQueue = xQueueCreate(50, sizeof(CANMessage)); // Create debug queue

time_top = millis();

  // Create tasks
  xTaskCreatePinnedToCore(CANReceiveTask, "CANReceiveTask", 4 * 1024, NULL, 3, NULL, 1); // priority 3 on core 0
  xTaskCreatePinnedToCore(TCPSendTask, "TCPSendTask", 4 * 1024, NULL, 5, NULL, 0);       // priority 5 on core 1
#if defined(ETHERNET)
  xTaskCreatePinnedToCore(ethernetMonitorTask, "Ethernet Monitor", 4 * 1024, NULL, 1, NULL, 1); // priority 1 on core 1
#elif defined(WIFI)
  xTaskCreatePinnedToCore(wifiMonitorTask, "WiFi Monitor", 4 * 1024, NULL, 1, NULL, 0); // priority 1 on core 1
#endif


} // end setup

Par ailleurs, Christophe (@bobyAndCo), en inspectant le code de la passerelle je m’interrogais sur les déclarations des lignes de code 57 & 58:

const uint8_t NBRE_MODULES = 2;
Module module[NBRE_MODULES]; 

Doit-on comprendre que le code, en l’état, est prévu pour 2 décodeurs Pico maximum ? (et donc 32 contacts). Ou bien je n’ai rien compris ?

Bonjour @Jerome

Tu peux utiliser de nombreux décodeurs Pico. Dans cette configuration CAN comme celle-ci, il est possible de disposer jusqu’à plus de 100 nœuds sur le bus.

Chaque nœud devant avoir un ID distinct des autres comme précisé plus haut à Bruno.

Il suffit donc d’adapter le code au nombre de modules installés comme ci-dessous (et rien de plus)

const uint8_t NBRE_MODULES = 100; // Pour 100 decodeurs Pico sur le grand reseau de Jerome
Module module[NBRE_MODULES];

On peut mettre ici une valeur (bien) supérieure aux nombre de nœuds réellement présents. Le programme va simplement réaliser des boucles plus longues sans besoin et donc tourner moins vite de quelques dizaines de nano secondes à chaque boucle.

Comme la vitesse du bus CAN est réglée à 1Mbps, la longueur totale du bus ne doit pas dépasser 30 mètres (ce qui est déjà pas mal non ?).

Ligne 107 du code

static const uint32_t DESIRED_BIT_RATE = 1000UL * 1000UL; // CAN baudrate = 1000 Kbit/s

De mémoire, à 500Kbps, il est possible d’atteindre 100 mètres et 500 mètres en 125Kbps. Je rappelle que la vitesse de bus CAN retenue par Marklin est 250Kbps.

Bien faire attention que TOUS les nœuds du bus doivent être réglés sur la même vitesse.

Il ne devrait pourtant pas y avoir de problème ici.

Dans la passerelle (ESP32) l’état des différents décodeurs Pico est initialisée à 0, ce qui sur 16 bits (16 entrées sur le Pico) revient à ceci

module[idModule].value = 0000000000000000 // en binaire

Les Pico eux envoient leurs états toutes les 100 millisecondes qu’il y ait changement ou non. Donc la valeur réelle des Pico est forcement prise en compte par l’ESP32.

Je penche plus pour un envoi trop rapide par l’ESP32 au démarrage avant que Rocrail n’ait réussi à enregistrer cette valeur. L’ESP se dit, “moi j’ai fais mon boulot” sans s’occuper si Rocrail à reçu.

Je crois qu’il faut une tempo au lancement de l’ESP32 qui permettrait à Rocrail d’être en position parfaite pour la réception. Ce serait en effet plus élégant.

Je regarderai cela un de ces jours mais si ça fonctionne comme tu as fait, comme tu dis, c’est l’essentiel.

Christophe

Merci pour cette réponse très complète et claire Christophe.

A priori, sur mon grand réseau futur, j’aurai besoin de 4 ou 5 décodeurs de 16 contacts, déployés sur 30 mètres (tour de pièce). Donc, à priori, je serai loin d’exploiter les capacités maximales du système !

N’interprète surtout pas mes questions comme une remise en question de l’excellent boulot que tu as fais, j’aime juste comprendre un minimum ce que je fais pour être en mesure de me dépatouiller seul :grinning_face_with_smiling_eyes:

C’est exactement comme cela que je le reçois :smiling_face_with_sunglasses:

Christophe

Bonjour Messieurs ,

Je suis vos échange avec intérêt sur l’initialisation des détecteurs au lancement de Rocrail.

Je suis étonné que Rocrail ne sauvegarde pas le dernier état connu des détecteurs en fin de session.

Je cherche, pour le moment je ne trouve pas. Affaire à suivre , bonne journée à vous deux.

Bruno.

Bonjour Bruno (@bilouteman76 )

Je ne sais pas ou tu en es concernant l’installation de ton réseau, et de tes rails de contacts en particulier. J’attire ton attention sur cette question que j’avais posé a l’époque (dans l’autre sujet non dédié!):

J’avais mis ces diodes Schottky sur chaque rail de contact avec une boucle ouverte sous le plan pour me permettre de fermer ou non le circuit de cette diode et ainsi parer à toutes les éventualités (je n’étais pas sur que cela allait fonctionner au moment du montage de mes rails). Ici, le circuit de la diode étant fermé avec des fiches:

Au départ, je connectais le B de mes détecteurs au courant traction, ce qui semble assez naturel. Dans ce cas, l’utilisation d’une diode de Schottky résultait en une détection d’occupation permanente. Cela générait aussi pas mal d’étincelles lors du passage de la loco sur le rail de contact. J’ai alors essayé avec le + d’une alimentation DC 5V avec le (-) relié aux autres masses (notamment celle des rails). Dans ce cas, plus de détection de contact permanent avec la diode, et plus d’étincelles.

J’ai effectivement pu constater qu’avec certaine locos, la présence de la diode permet d’éviter des plantages (expérimentations en fermant/ouvrant la boucle que j’avais prévu). Cette diode est un plus, et est compatible avec ces petites détecteurs faits maison, à la condition que la tension du courant utilisé dans le circuit primaire (celui qui alimente la LED) soit faible.

Voila, je partage mon expérience. Si c’est trop tard pour que tu puisses mettre ces diodes, ce n’est pas la fin du monde. Mais c’est un plus…

Bien a toi,
J