Homemade Marklin - création d'un circuit intelligent

Bonjour à tous,

Voila j’ai terminé le programme qui permet d’activer la reconnaissance MFX pour Rocrail avec CC-Schnitte sans avoir besoin de la MS2.

Comme il n’est pas possible de télécharger un fichier .ino, j’ai copié le code ci-dessous.

J’ai écrit le code pour un ESP32 qui tourne sur une petite carte que j’ai réalisée avec un transceiver CAN MCP2562. Mais cela peut aussi fonctionner sur n’importe quel Arduino avec un module CAN MCP2515 en modifiant également la bibliothèque CAN dans le programme.

Pour ceux qui seraient intéressés, n’hésitez pas à poser toutes vos questions aux quelles j’essayerai de répondre. Je peux aussi fournir les fichiers Gerber de la carte (voir des cartes complètes).


/*
   rocrail_mfx_discovery

    Pogramme permettant la reconnaissance MFX
    et la mise a jour de la liste des locomotives dans Rocrail©


*/

#ifndef ARDUINO_ARCH_ESP32
#error "Select an ESP32 board"
#endif

#define PROJECT "rocrail_mfx_discovery"
#define VERSION "0.1"
#define AUTHOR "Christophe BOBILLE : [email protected]"


#include <ACAN_ESP32.h>  // https://github.com/pierremolinaro/acan-esp32.git

CANMessage frameIn;
CANMessage frameOut;

/* ----- CAN ----------------------*/
#define CAN_RX GPIO_NUM_22
#define CAN_TX GPIO_NUM_23
#define CAN_BITRATE 250UL * 1000UL // Marklin CAN baudrate = 250Kbit/s

uint32_t CAN_Id;
uint8_t  CAN_Len;
uint8_t  CAN_Command;
uint16_t CAN_Hash = 0x2f39;


String decToHex(uint8_t dec)
{
  auto convert = [](uint8_t x) ->char
  {
    char ch;
    if (x >= 10)
      return (char)(x + 55);
    else
      return (char)(x + 48);
  };
  String hex = "";
  hex += convert(dec / 16);
  hex += convert(dec % 16);
  return hex;
}

const byte nbLocos = 40;

class Loco
{
  private:

  public:
    Loco();
    uint8_t index;
    uint8_t locID[2];
    uint8_t UID[4];
    static uint8_t comptLoco;
};

uint8_t Loco::comptLoco = 4;
Loco::Loco() : index(255) {};

Loco* loco = new Loco[nbLocos];

uint8_t canSendDta[8];
bool err;

bool sendMsgCan(uint8_t CAN_Command, uint8_t length, uint8_t *canSendDta)
{

  CAN_Id = CAN_Command << 17 | CAN_Hash;
  frameOut.id = CAN_Id;
  frameOut.ext = 1;
  frameOut.len = length;
  frameOut.data[0] = canSendDta[0];
  frameOut.data[1] = canSendDta[1];
  frameOut.data[2] = canSendDta[2];
  frameOut.data[3] = canSendDta[3];
  frameOut.data[4] = canSendDta[4];
  frameOut.data[5] = canSendDta[5];
  frameOut.data[6] = canSendDta[6];
  frameOut.data[7] = canSendDta[7];
  err = ACAN_ESP32::can.tryToSend (frameOut);
  Serial.print("[ ]=> command 0x");
  Serial.println(decToHex(CAN_Command));
}


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

  Serial.printf("\nProject   :    %s", PROJECT);
  Serial.printf("\nVersion   :    %s", VERSION);
  Serial.printf("\nAuteur    :    %s", AUTHOR);
  Serial.printf("\nFichier   :    %s", __FILE__);
  Serial.printf("\nCompiled  :    %s", __DATE__);
  Serial.printf(" - %s\n\n", __TIME__);

  //--- Configure ESP32 CAN
  Serial.println("Configure ESP32 CAN");
  ACAN_ESP32_Settings settings(CAN_BITRATE);
  settings.mRxPin = CAN_RX;
  settings.mTxPin = CAN_TX;
  const uint32_t errorCode = ACAN_ESP32::can.begin(settings);
  if (errorCode == 0)
    Serial.println("Can configuration OK !\n");
  else
  {
    Serial.printf("Can configuration error 0x%x\n", errorCode);
    delay(1000);
    return;
  }

  //2.1  Commande : Système Arrêt
  delay(10);
  for (byte i = 0; i < 8; i++)
    canSendDta[i] = 0x00;
  err = sendMsgCan(0x00, 4, canSendDta);
  
  // Bootloader CAN
  delay(10);
  for (byte i = 0; i < 8; i++)
    canSendDta[i] = 0x00;
  canSendDta[4] = 0x11;
  err = sendMsgCan(0x1B, 5, canSendDta);


  //2.10  commande : Système MFX Définir le compteur de nouvelles inscriptions
  delay(10);
  for (byte i = 0; i < 8; i++)
    canSendDta[i] = 0x00;
  canSendDta[4] = 0x09; //Sous-CMD MFX
  canSendDta[5] = Loco::comptLoco & 0xFF00;
  canSendDta[6] = Loco::comptLoco & 0x00FF;
  err = sendMsgCan(0x00, 7, canSendDta);

  // 3.3 commande : MFX Verify (pour provoquer un UnBIND)
  /*
       Si un décodeur MFX lié recoit une combinaison erronee d'UID MFX et de SID MFX,
       un UnBIND est déclenche dans le decodeur de locomotive avec le SID MFX correspondant
  */
  delay(10);
  for (byte i = 0; i < 8; i++)
    canSendDta[i] = 0x00;
  err = sendMsgCan(0x03, 6, canSendDta);

  // 2.2 Commande : Système Go
  delay(10);
  for (byte i = 0; i < 8; i++)
    canSendDta[i] = 0x00;
  canSendDta[4] = 0x01; // Go a tous
  err = sendMsgCan(0x00, 5, canSendDta);

  //3.1  Ordre de mission : Locomotive Discovery
  delay(10);
  for (byte i = 0; i < 8; i++)
    canSendDta[i] = 0x00;
  canSendDta[0] = 0x20; // MFX protocole
  err = sendMsgCan(0x00, 1, canSendDta);

}


void loop()
{
  if (ACAN_ESP32::can.receive (frameIn))
  {
    if (frameIn.id >> 16 == 0x03 && frameIn.len == 5)
    {
      Serial.printf("Frame ID     0x");
      Serial.println(frameIn.id, HEX);
      Serial.printf("Frame length %d\n", frameIn.len);
      for (byte i = 0; i < frameIn.len; i++)
      {
        Serial.printf("  Data [");
        Serial.print(i);
        Serial.print("] = 0x");
        Serial.print(frameIn.data[i], HEX);
      }
      Serial.printf("\n");

      byte i;
      bool stop = false;
      for (i = 0; i < nbLocos; i++)
      {
        if (loco[i].UID[0] == frameIn.data[0]
            && loco[i].UID[1] == frameIn.data[1]
            && loco[i].UID[2] == frameIn.data[2]
            && loco[i].UID[3] == frameIn.data[3])
        {
          byte address0 = loco[i].locID[0];
          byte address1 = loco[i].locID[1];

          // MFX Bind
          delay(10);
          for (byte i = 0; i < 8; i++)
            canSendDta[i] = 0x00;
          canSendDta[0] = loco[i].UID[0];
          canSendDta[1] = loco[i].UID[1];
          canSendDta[2] = loco[i].UID[2];
          canSendDta[3] = loco[i].UID[3];
          canSendDta[4] = loco[i].locID[0];
          canSendDta[5] = loco[i].locID[1];
          err = sendMsgCan(0x02, 6, canSendDta);
          delay(10);
          stop = true;
        }
        if (stop)
          break;
      }

      if (i == nbLocos) // Pas de locos trouve
      {
        for (i = 0; i < nbLocos; i++)
        {
          if (loco[i].index == 255)
          {
            Loco::comptLoco++;
            loco[i].index = i;
            loco[i].UID[0] = frameIn.data[0];
            loco[i].UID[1] = frameIn.data[1];
            loco[i].UID[2] = frameIn.data[2];
            loco[i].UID[3] = frameIn.data[3];
            loco[i].locID[0] = Loco::comptLoco & 0xFF00;
            loco[i].locID[1] = Loco::comptLoco & 0x00FF;
            Serial.printf("Creation dans la liste Loc-ID = %d\n", Loco::comptLoco);

            // MFX Bind
            delay(10);
            for (byte i = 0; i < 8; i++)
              canSendDta[i] = 0x00;
            canSendDta[0] = loco[i].UID[0];
            canSendDta[1] = loco[i].UID[1];
            canSendDta[2] = loco[i].UID[2];
            canSendDta[3] = loco[i].UID[3];
            canSendDta[4] = loco[i].locID[0];
            canSendDta[5] = loco[i].locID[1];
            err = sendMsgCan(0x02, 6, canSendDta);

            // MFX Verify
            delay(10);
            err = sendMsgCan(0x03, 6, canSendDta);
            
            goto end;
          }
        }
end:
        Serial.println("Exit");
      }
    }
  }
}