349 lines
13 KiB
C++
349 lines
13 KiB
C++
|
|
|
|
/*********************************************************************
|
|
* Railuino - Hacking your Märklin
|
|
*
|
|
* Copyright (C) 2012 Joerg Pleumann
|
|
* Copyright (C) 2024 christophe bobille
|
|
*
|
|
* This example is free software; you can redistribute it and/or
|
|
* modify it under the terms of the Creative Commons Zero License,
|
|
* version 1.0, as published by the Creative Commons Organisation.
|
|
* This effectively puts the file into the public domain.
|
|
*
|
|
* This example is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* LICENSE file for more details.
|
|
*/
|
|
|
|
#ifndef TRACKCONTROLLER_H
|
|
#define TRACKCONTROLLER_H
|
|
|
|
#include <Arduino.h>
|
|
#include "TrackMessage.h"
|
|
#include "Config.h"
|
|
|
|
// ===================================================================
|
|
// === TrackController ===============================================
|
|
// ===================================================================
|
|
|
|
/**
|
|
* Controls things on and connected to the track: locomotives,
|
|
* turnouts and other accessories. While there are some low-level
|
|
* methods for dealing with messages, you will normally want to use
|
|
* the high-level methods that wrap most of the the nasty protocol
|
|
* details. When addressing something, you have to tell the system the
|
|
* type of address (or decoder) you are using by adding the proper
|
|
* protocol base address. For instance, DCC locomotive 42 is properly
|
|
* addressed as ADDR_DCC + 42.
|
|
*/
|
|
class TrackController
|
|
{
|
|
|
|
private:
|
|
/**
|
|
* Stores the hash of our controller. This must not conflict with
|
|
* hashes of other devices in the setup (most likely the MS2 and
|
|
* the connector box).
|
|
*/
|
|
uint16_t mHash;
|
|
/**
|
|
* Stores the debug flag. When debugging is on, all outgoing and
|
|
* incoming messages are printed to the Serial console.
|
|
*/
|
|
bool mDebug;
|
|
/**
|
|
* Holds the loopback flag. When loopback is on, messages are
|
|
* reflected by the CAN controller. No external communication
|
|
* takes place. This is helpful for some test cases.
|
|
*/
|
|
bool mLoopback;
|
|
|
|
uint64_t mTimeout;
|
|
|
|
public:
|
|
/**
|
|
* Creates a new TrackController with default values.
|
|
*/
|
|
TrackController();
|
|
|
|
/**
|
|
* Creates a new TrackController with modification of the default exchangeMessage timeout
|
|
*/
|
|
TrackController(uint64_t timeOut);
|
|
|
|
/**
|
|
* Creates a new TrackController with the given hash and debugging
|
|
* flag and changing the default exchangeMessage timeout.
|
|
* A zero hash will result in a unique hash begin generated.
|
|
*/
|
|
TrackController(uint16_t hash, bool debug, uint64_t timeOut);
|
|
|
|
/**
|
|
* Creates a new TrackController with the given hash and debugging
|
|
* flag. A zero hash will result in a unique hash begin generated.
|
|
*/
|
|
TrackController(uint16_t hash, bool debug, uint64_t timeOut, bool loopback);
|
|
/**
|
|
* Is called when a TrackController is being destroyed. Does the
|
|
* necessary cleanup. No need to call this manually.
|
|
*/
|
|
~TrackController();
|
|
|
|
/**
|
|
* Initializes the TrackController with the given values. This
|
|
* should be called before begin, otherwise it will not take
|
|
* effect. A zero hash will result in a unique hash begin
|
|
* generated.
|
|
*/
|
|
void init(uint16_t hash, bool debug, bool loopback, uint64_t timeOut = 1000);
|
|
|
|
/**
|
|
* Queries the hash used by the TrackController.
|
|
*/
|
|
uint16_t getHash();
|
|
|
|
/**
|
|
* Reflects whether the TrackController is in debug mode,
|
|
* where all messages are dumped to the Serial console.
|
|
*/
|
|
bool isDebug();
|
|
|
|
/**
|
|
* Reflects whether the TrackController is in debug mode,
|
|
* where all messages are reflected by the CAN controller.
|
|
*/
|
|
bool isLoopback();
|
|
|
|
/**
|
|
* Initializes the CAN hardware and starts receiving CAN
|
|
* messages. CAN messages are put into an internal buffer of
|
|
* limited size, so they don't get lost, but you have to take
|
|
* care of them in time. Otherwise the buffer might overflow.
|
|
* default CAN Rx pin is GPIO_NUM_5 and can_tx_pin is GPIO_NUM_4
|
|
*/
|
|
|
|
|
|
// void begin(const gpio_num_t can_rx_pin = GPIO_NUM_5,
|
|
// const gpio_num_t can_tx_pin = GPIO_NUM_4);
|
|
|
|
void begin(const byte can_rx_pin = 5,
|
|
const byte can_tx_pin = 4);
|
|
|
|
/**
|
|
* Generates a new hash and makes sure it does not conflict
|
|
* with those of other devices in the setup.
|
|
*/
|
|
void generateHash();
|
|
|
|
/**
|
|
* Stops receiving messages from the CAN hardware. Clears
|
|
* the internal buffer.
|
|
*/
|
|
// void end();
|
|
|
|
/**
|
|
* Sends a message and reports true on success. Internal method.
|
|
* Normally you don't want to use this, but the more convenient
|
|
* methods below instead.
|
|
*/
|
|
bool sendMessage(TrackMessage &message);
|
|
|
|
/**
|
|
* Receives an arbitrary message, if available, and reports true
|
|
* on success. Does not block. Internal method. Normally you
|
|
* don't want to use this, but the more convenient methods below
|
|
* instead.
|
|
*/
|
|
bool receiveMessage(TrackMessage &message);
|
|
|
|
/**
|
|
* Sends a message and waits for the corresponding response,
|
|
* returning true on success. Blocks until either a message with
|
|
* the same command ID and the response marker arrives or the
|
|
* timeout (in ms) expires. All non-matching messages are
|
|
* skipped. Internal method. Normally you don't want to use this,
|
|
* but the more convenient methods below instead. 'out' and 'in'
|
|
* may be the same object.
|
|
*/
|
|
bool exchangeMessage(TrackMessage &out, TrackMessage &in, uint16_t timeout);
|
|
|
|
/**
|
|
* Controls power on the track. When passing false, all
|
|
* locomotives will stop, but remember their previous directions
|
|
* and speeds. When passing true, all locomotives will regain
|
|
* their old directions and speeds. The system starts in
|
|
* stopped mode in order to avoid accidents. The return value
|
|
* reflects whether the call was successful.
|
|
*/
|
|
bool setPower(bool power);
|
|
|
|
/**
|
|
* Cette commande qui n'existait pas a l'origine a ete ajoutee
|
|
* a partir de la v-9.01
|
|
* Commande système (0x00, dans CAN-ID : 0x00)
|
|
* Arrêt d'urgence de la locomotive (0x02)
|
|
* Toutes les locomotives reçoivent l'ordre de s'arrêter (vitesse 0),
|
|
* y compris l'inertie de freinage. Le signal numérique reste sur les rails,
|
|
* mais aucune autre commande n'est envoyée sur les rails.
|
|
* L'énergie électrique reste disponible.
|
|
*/
|
|
// See https://streaming.maerklin.de/public-media/cs2/cs2CAN-Protokoll-2_0.pdf -> 2.3 Commande : System Halt
|
|
bool systemHalt(const uint16_t address);
|
|
|
|
/**
|
|
* Cette commande qui n'existait pas a l'origine a ete ajoutee
|
|
* a partir de la v-9.01
|
|
* Commande système (0x00, dans CAN-ID : 0x00)
|
|
* Arrêt d'urgence de la locomotive (0x03)
|
|
* Arrêt d'urgence ou arrêt immédiat de la locomotive, selon le protocole de voie.
|
|
* Il faut spécifier une locomotive déjà ciblée par une commande.
|
|
* Si cette locomotive n'est pas déjà dans le cycle, elle ne sera pas prise en compte par cette commande.
|
|
*/
|
|
|
|
/**
|
|
* This command, which didn't exist originally, has been added from v-9.01
|
|
* System command (0x00, in CAN-ID: 0x00)
|
|
* Locomotive emergency stop (0x03)
|
|
* Emergency stop or immediate stop of locomotive, depending on track protocol.
|
|
* A locomotive already targeted by a command must be specified.
|
|
* If this locomotive is not already in the cycle, it will not be taken into account by this command.
|
|
*/
|
|
// See https://streaming.maerklin.de/public-media/cs2/cs2CAN-Protokoll-2_0.pdf -> 2.4 Commande : Arrêt d'urgence de la locomotive
|
|
bool emergency(const uint16_t address);
|
|
|
|
/**
|
|
* Sets the direction of the given locomotive. Valid directions
|
|
* are those specified by the DIR_* constants. The return value
|
|
* reflects whether the call was successful.
|
|
*/
|
|
bool setLocoDirection(const uint16_t address, uint8_t direction);
|
|
|
|
/**
|
|
* Toggles the direction of the given locomotive. This normally
|
|
* includes a full stop.
|
|
*/
|
|
bool toggleLocoDirection(const uint16_t address);
|
|
|
|
/**
|
|
* Sets the speed of the given locomotive. Valid speeds are
|
|
* 0 to 1023 (inclusive), though the connector box will limit
|
|
* all speeds beyond 1000 to 1000. The return value reflects
|
|
* whether the call was successful.
|
|
*/
|
|
bool setLocoSpeed(const uint16_t address, uint16_t speed);
|
|
// bool accelerateLoco(uint16_t address);
|
|
// bool decelerateLoco(uint16_t address);
|
|
|
|
/**
|
|
* Sets the given function of the given locomotive (or simply a
|
|
* function decoder). Valid functions are 0 to 31, with 0
|
|
* normally denoting the head/backlight. Valid values are, again,
|
|
* 0 ("off") to 31, although not all protocols support values
|
|
* beyond 1 (which then means "on"). The return value reflects
|
|
* whether the call was successful.
|
|
*/
|
|
bool setLocoFunction(const uint16_t address, uint8_t function, uint8_t power);
|
|
|
|
/**
|
|
* Toggles the given function of the given locomotive. Valid
|
|
* functions are 0 to 31, with 0 normally denoting the
|
|
* head/backlight.
|
|
*/
|
|
bool toggleLocoFunction(const uint16_t address, uint8_t function);
|
|
|
|
/**
|
|
* Switches the given magnetic accessory. Valid position values
|
|
* are those denoted by the ACC_* constants. Valid power values
|
|
* are 0 ("off") to 31 (inclusive) although not all protocols
|
|
* support values beyond 1 (which then means "on"). The final
|
|
* parameter specifies the time (in ms) for which the accessory
|
|
* will be active. A time of 0 means the accessory will only be
|
|
* switched on. Some magnetic accessories must not be active for
|
|
* too long, because they might burn out. A good timeout for
|
|
* Marklin turnouts seems to be 20 ms. The return value reflects
|
|
* whether the call was successful.
|
|
*/
|
|
bool setAccessory(const uint16_t address, uint8_t position, uint8_t power, uint16_t time);
|
|
|
|
/**
|
|
* Switches a turnout. This is actually a convenience function
|
|
* around setAccessory() that uses default values for some
|
|
* parameters. The return value reflects whether the call was
|
|
* successful.
|
|
*/
|
|
bool setTurnout(const uint16_t address, bool straight);
|
|
|
|
/**
|
|
* Queries the direction of the given locomotive and writes it
|
|
* into the referenced byte. The return value indicates whether
|
|
* the call was successful and the direction is valid.
|
|
*/
|
|
bool getLocoDirection(const uint16_t address, uint8_t *direction);
|
|
|
|
/**
|
|
* Queries the speed of the given locomotive and writes it
|
|
* into the referenced byte. The return value indicates whether
|
|
* the call was successful and the speed is valid.
|
|
*/
|
|
|
|
bool getLocoSpeed(const uint16_t address, uint16_t *speed);
|
|
|
|
/**
|
|
* Queries the given function of the given locomotive and writes
|
|
* it into the referenced byte. The return value indicates
|
|
* whether the call was successful and the power is valid. Note
|
|
* that the call will not reflect the original power value sent
|
|
* to the function, but only 0 ("off") or 1 ("on").
|
|
*/
|
|
bool getLocoFunction(const uint16_t address, uint8_t function, uint8_t *power);
|
|
|
|
/**
|
|
* Queries the given magnetic accessory's state and and writes
|
|
* it into the referenced bytes. The return value indicates
|
|
* whether the call was successful and the bytes are valid. Note
|
|
* that the call will not reflect the original power value sent
|
|
* to the function, but only 0 ("off") or 1 ("on").
|
|
*/
|
|
bool getAccessory(const uint16_t address, uint8_t *position, uint8_t *power);
|
|
|
|
/**
|
|
* Writes the given value to the given config number of the given
|
|
* locomotive. The return value reflects whether the call was
|
|
* successful.
|
|
*/
|
|
/* -------------------------------------------------------------------
|
|
TrackController::writeConfig
|
|
|
|
See https://streaming.maerklin.de/public-media/cs2/cs2CAN-Protokoll-2_0.pdf -> 3.8 Commande : Écrire Config
|
|
|
|
------------------------------------------------------------------- */
|
|
bool writeConfig(const uint16_t address, uint16_t number, uint8_t value);
|
|
|
|
/**
|
|
* Reads the given config number of the given locomotive into the
|
|
* given value.
|
|
*/
|
|
|
|
//!\\ Les décodeurs MFX de première génération ne sont pas conçus pour cela et pourraient être endommagés
|
|
//!\\ First-generation MFX decoders are not designed for this purpose and could be damaged.
|
|
|
|
// See https://streaming.maerklin.de/public-media/cs2/cs2CAN-Protokoll-2_0.pdf -> 2.8 Befehl: Fast Read für mfx SID - Adresse
|
|
|
|
bool readConfig(const uint16_t address, uint16_t number, uint8_t *value);
|
|
|
|
/**
|
|
* Queries the software version of the track format processor.
|
|
*/
|
|
bool getVersion();
|
|
//bool getVersion(uint8_t *high, uint8_t *low);
|
|
|
|
/**
|
|
* Processes commands received on the serial or TCP port
|
|
*/
|
|
void handleUserCommands(String);
|
|
};
|
|
|
|
#endif // TRACKCONTROLLER_H
|
|
|