Initialisation depot
This commit is contained in:
101
ESP32/DCC-Loco/include/AccessoryOutputs.h
Normal file
101
ESP32/DCC-Loco/include/AccessoryOutputs.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* @file AccessoryOutputs.h
|
||||
* @brief Accessory Output Controller (N-channel MOSFETs)
|
||||
*
|
||||
* Controls 2 N-channel MOSFET outputs for accessories like smoke generators,
|
||||
* sound modules, or other low-side switched loads.
|
||||
*/
|
||||
|
||||
#ifndef ACCESSORY_OUTPUTS_H
|
||||
#define ACCESSORY_OUTPUTS_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
enum AccessoryMode {
|
||||
ACC_OFF = 0, // Always off
|
||||
ACC_ON = 1, // Always on
|
||||
ACC_FUNCTION = 2, // Controlled by DCC function
|
||||
ACC_PWM = 3, // PWM control
|
||||
ACC_BLINK = 4, // Blinking mode
|
||||
ACC_SPEED_DEPENDENT = 5 // Output follows speed
|
||||
};
|
||||
|
||||
class AccessoryOutputs {
|
||||
public:
|
||||
AccessoryOutputs();
|
||||
|
||||
/**
|
||||
* @brief Initialize accessory outputs
|
||||
* @param output1Pin GPIO for accessory output 1 (N-FET gate)
|
||||
* @param output2Pin GPIO for accessory output 2 (N-FET gate)
|
||||
* @return true if successful
|
||||
*/
|
||||
bool begin(uint8_t output1Pin, uint8_t output2Pin);
|
||||
|
||||
/**
|
||||
* @brief Set output mode
|
||||
* @param outputNum Output number (1 or 2)
|
||||
* @param mode Accessory mode
|
||||
*/
|
||||
void setMode(uint8_t outputNum, AccessoryMode mode);
|
||||
|
||||
/**
|
||||
* @brief Set PWM duty cycle for output
|
||||
* @param outputNum Output number (1 or 2)
|
||||
* @param dutyCycle Duty cycle (0-255)
|
||||
*/
|
||||
void setPWM(uint8_t outputNum, uint8_t dutyCycle);
|
||||
|
||||
/**
|
||||
* @brief Map DCC function to output
|
||||
* @param outputNum Output number (1 or 2)
|
||||
* @param functionNum DCC function number (0-28)
|
||||
*/
|
||||
void mapFunction(uint8_t outputNum, uint8_t functionNum);
|
||||
|
||||
/**
|
||||
* @brief Update function state
|
||||
* @param functionNum Function number (0-28)
|
||||
* @param state Function state (true = on)
|
||||
*/
|
||||
void setFunctionState(uint8_t functionNum, bool state);
|
||||
|
||||
/**
|
||||
* @brief Set speed for speed-dependent mode
|
||||
* @param speed Speed value (0-126)
|
||||
*/
|
||||
void setSpeed(uint8_t speed);
|
||||
|
||||
/**
|
||||
* @brief Update outputs (call regularly from loop)
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* @brief Direct output control
|
||||
* @param outputNum Output number (1 or 2)
|
||||
* @param state Output state (true = on)
|
||||
*/
|
||||
void setOutput(uint8_t outputNum, bool state);
|
||||
|
||||
private:
|
||||
uint8_t pins[2];
|
||||
AccessoryMode modes[2];
|
||||
uint8_t pwmValues[2];
|
||||
uint8_t mappedFunctions[2];
|
||||
bool functionStates[29]; // F0-F28
|
||||
uint8_t currentSpeed;
|
||||
|
||||
// PWM channels
|
||||
const uint8_t pwmChannels[2] = {2, 3};
|
||||
const uint32_t pwmFrequency = 1000; // 1 kHz
|
||||
const uint8_t pwmResolution = 8;
|
||||
|
||||
// Blink timing
|
||||
unsigned long lastBlinkUpdate;
|
||||
bool blinkState;
|
||||
|
||||
void updateOutput(uint8_t outputNum);
|
||||
};
|
||||
|
||||
#endif // ACCESSORY_OUTPUTS_H
|
||||
100
ESP32/DCC-Loco/include/CVManager.h
Normal file
100
ESP32/DCC-Loco/include/CVManager.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @file CVManager.h
|
||||
* @brief Configuration Variable (CV) Manager
|
||||
*
|
||||
* Manages NMRA-compliant Configuration Variables stored in non-volatile memory.
|
||||
* Supports programming track operations and service mode programming.
|
||||
*/
|
||||
|
||||
#ifndef CV_MANAGER_H
|
||||
#define CV_MANAGER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Preferences.h>
|
||||
|
||||
// Standard DCC CVs
|
||||
#define CV_PRIMARY_ADDRESS 1 // Short address (1-127)
|
||||
#define CV_VSTART 2 // Start voltage
|
||||
#define CV_ACCEL_RATE 3 // Acceleration rate
|
||||
#define CV_DECEL_RATE 4 // Deceleration rate
|
||||
#define CV_VHIGH 5 // Max voltage
|
||||
#define CV_VMID 6 // Mid voltage
|
||||
#define CV_VERSION_ID 7 // Manufacturer version
|
||||
#define CV_MANUFACTURER_ID 8 // Manufacturer ID
|
||||
#define CV_TOTAL_PWM_PERIOD 9 // PWM period
|
||||
#define CV_EMF_FEEDBACK_CUTOUT 10 // EMF feedback cutout
|
||||
#define CV_PACKET_TIMEOUT 11 // Packet timeout
|
||||
#define CV_EXTENDED_ADDRESS_HIGH 17 // Long address high byte
|
||||
#define CV_EXTENDED_ADDRESS_LOW 18 // Long address low byte
|
||||
#define CV_CONSIST_ADDRESS 19 // Consist address
|
||||
#define CV_CONFIG_DATA_1 29 // Configuration data
|
||||
|
||||
// Custom CVs for this decoder
|
||||
#define CV_MOTOR_KP 50 // Motor PID Kp
|
||||
#define CV_MOTOR_KI 51 // Motor PID Ki
|
||||
#define CV_MOTOR_KD 52 // Motor PID Kd
|
||||
#define CV_RAILCOM_ENABLE 53 // RailCom enable
|
||||
#define CV_LOAD_COMP_ENABLE 54 // Load compensation enable
|
||||
#define CV_LED_BRIGHTNESS 55 // LED brightness
|
||||
#define CV_ACCESSORY_1_MODE 56 // Accessory output 1 mode
|
||||
#define CV_ACCESSORY_2_MODE 57 // Accessory output 2 mode
|
||||
|
||||
#define MAX_CV_NUMBER 1024
|
||||
|
||||
class CVManager {
|
||||
public:
|
||||
CVManager();
|
||||
|
||||
/**
|
||||
* @brief Initialize CV manager and load from NVS
|
||||
* @return true if successful
|
||||
*/
|
||||
bool begin();
|
||||
|
||||
/**
|
||||
* @brief Read CV value
|
||||
* @param cvNumber CV number (1-1024)
|
||||
* @param defaultValue Default value if CV not set
|
||||
* @return CV value
|
||||
*/
|
||||
uint8_t readCV(uint16_t cvNumber, uint8_t defaultValue = 0);
|
||||
|
||||
/**
|
||||
* @brief Write CV value
|
||||
* @param cvNumber CV number (1-1024)
|
||||
* @param value Value to write
|
||||
* @return true if successful
|
||||
*/
|
||||
bool writeCV(uint16_t cvNumber, uint8_t value);
|
||||
|
||||
/**
|
||||
* @brief Reset all CVs to factory defaults
|
||||
*/
|
||||
void resetToDefaults();
|
||||
|
||||
/**
|
||||
* @brief Get locomotive address from CVs
|
||||
* @return Locomotive address (1-10239)
|
||||
*/
|
||||
uint16_t getLocoAddress();
|
||||
|
||||
/**
|
||||
* @brief Set locomotive address in CVs
|
||||
* @param address Address to set (1-10239)
|
||||
*/
|
||||
void setLocoAddress(uint16_t address);
|
||||
|
||||
/**
|
||||
* @brief Check if using extended (long) address
|
||||
* @return true if using long address
|
||||
*/
|
||||
bool isLongAddress();
|
||||
|
||||
private:
|
||||
Preferences preferences;
|
||||
|
||||
void setDefaultCVs();
|
||||
String getCVKey(uint16_t cvNumber);
|
||||
};
|
||||
|
||||
#endif // CV_MANAGER_H
|
||||
82
ESP32/DCC-Loco/include/ConfigServer.h
Normal file
82
ESP32/DCC-Loco/include/ConfigServer.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @file ConfigServer.h
|
||||
* @brief WiFi/Bluetooth Configuration Server
|
||||
*
|
||||
* Provides WebSocket-based configuration interface over WiFi or Bluetooth.
|
||||
* Allows reading/writing CVs, testing outputs, and monitoring decoder status.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_SERVER_H
|
||||
#define CONFIG_SERVER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include "CVManager.h"
|
||||
|
||||
class ConfigServer {
|
||||
public:
|
||||
ConfigServer(CVManager& cvManager);
|
||||
|
||||
/**
|
||||
* @brief Initialize configuration server
|
||||
* @param ssid WiFi SSID (nullptr for AP mode with default name)
|
||||
* @param password WiFi password
|
||||
* @param useAP true for AP mode, false for station mode
|
||||
* @return true if successful
|
||||
*/
|
||||
bool begin(const char* ssid = nullptr, const char* password = nullptr, bool useAP = true);
|
||||
|
||||
/**
|
||||
* @brief Stop configuration server
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* @brief Check if configuration mode is active
|
||||
*/
|
||||
bool isActive() const { return active; }
|
||||
|
||||
/**
|
||||
* @brief Update server (call from loop)
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* @brief Set decoder status callback
|
||||
* Function signature: void callback(JsonObject& status)
|
||||
*/
|
||||
typedef void (*StatusCallback)(JsonObject& status);
|
||||
void setStatusCallback(StatusCallback callback);
|
||||
|
||||
private:
|
||||
CVManager& cvMgr;
|
||||
AsyncWebServer* server;
|
||||
AsyncWebSocket* ws;
|
||||
bool active;
|
||||
|
||||
StatusCallback statusCallback;
|
||||
unsigned long lastStatusUpdate;
|
||||
|
||||
void setupWebSocket();
|
||||
void setupHTTPRoutes();
|
||||
void handleWebSocketMessage(void* arg, uint8_t* data, size_t len);
|
||||
void handleWebSocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client,
|
||||
AwsEventType type, void* arg, uint8_t* data, size_t len);
|
||||
|
||||
void handleReadCV(AsyncWebSocketClient* client, JsonObject& json);
|
||||
void handleWriteCV(AsyncWebSocketClient* client, JsonObject& json);
|
||||
void handleGetStatus(AsyncWebSocketClient* client);
|
||||
void handleTestOutput(AsyncWebSocketClient* client, JsonObject& json);
|
||||
void handleReset(AsyncWebSocketClient* client);
|
||||
|
||||
void sendResponse(AsyncWebSocketClient* client, const char* type,
|
||||
bool success, const char* message = nullptr);
|
||||
void broadcastStatus();
|
||||
|
||||
String getDefaultAPName();
|
||||
};
|
||||
|
||||
#endif // CONFIG_SERVER_H
|
||||
100
ESP32/DCC-Loco/include/DCCDecoder.h
Normal file
100
ESP32/DCC-Loco/include/DCCDecoder.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @file DCCDecoder.h
|
||||
* @brief DCC Signal Decoder for locomotive control
|
||||
*
|
||||
* Decodes DCC packets from the track signal, extracts speed and function commands,
|
||||
* and manages locomotive addressing (short/long address support).
|
||||
*/
|
||||
|
||||
#ifndef DCC_DECODER_H
|
||||
#define DCC_DECODER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// DCC Timing constants (in microseconds)
|
||||
#define DCC_ONE_BIT_MIN 52
|
||||
#define DCC_ONE_BIT_MAX 64
|
||||
#define DCC_ZERO_BIT_MIN 95
|
||||
#define DCC_ZERO_BIT_MAX 9900
|
||||
|
||||
// Maximum packet size
|
||||
#define MAX_DCC_PACKET_SIZE 6
|
||||
|
||||
class DCCDecoder {
|
||||
public:
|
||||
DCCDecoder();
|
||||
|
||||
/**
|
||||
* @brief Initialize the DCC decoder
|
||||
* @param dccPin GPIO pin for DCC signal input
|
||||
* @return true if initialization successful
|
||||
*/
|
||||
bool begin(uint8_t dccPin);
|
||||
|
||||
/**
|
||||
* @brief Process DCC signal (call frequently from loop or ISR)
|
||||
*/
|
||||
void process();
|
||||
|
||||
/**
|
||||
* @brief Get current speed value (0-126, 0=stop, 1=emergency stop)
|
||||
* @return Current speed
|
||||
*/
|
||||
uint8_t getSpeed() const { return currentSpeed; }
|
||||
|
||||
/**
|
||||
* @brief Get current direction
|
||||
* @return true = forward, false = reverse
|
||||
*/
|
||||
bool getDirection() const { return direction; }
|
||||
|
||||
/**
|
||||
* @brief Get function state (F0-F28)
|
||||
* @param functionNum Function number (0-28)
|
||||
* @return Function state (true = on)
|
||||
*/
|
||||
bool getFunction(uint8_t functionNum) const;
|
||||
|
||||
/**
|
||||
* @brief Check if decoder has received valid packets recently
|
||||
* @return true if signal is valid
|
||||
*/
|
||||
bool hasValidSignal() const;
|
||||
|
||||
/**
|
||||
* @brief Set locomotive address
|
||||
* @param address Locomotive address (1-10239)
|
||||
*/
|
||||
void setAddress(uint16_t address);
|
||||
|
||||
/**
|
||||
* @brief Get current locomotive address
|
||||
*/
|
||||
uint16_t getAddress() const { return locoAddress; }
|
||||
|
||||
private:
|
||||
static void IRAM_ATTR dccISR();
|
||||
static DCCDecoder* instance;
|
||||
|
||||
void decodeDCCPacket();
|
||||
void processSpeedPacket(uint8_t* data, uint8_t len);
|
||||
void processFunctionPacket(uint8_t* data, uint8_t len);
|
||||
|
||||
uint8_t dccInputPin;
|
||||
uint16_t locoAddress;
|
||||
uint8_t currentSpeed;
|
||||
bool direction;
|
||||
uint32_t functions; // Bit field for F0-F28
|
||||
|
||||
// Packet assembly
|
||||
uint8_t packetBuffer[MAX_DCC_PACKET_SIZE];
|
||||
uint8_t packetIndex;
|
||||
uint8_t bitCount;
|
||||
bool assemblingPacket;
|
||||
|
||||
// Timing
|
||||
unsigned long lastBitTime;
|
||||
unsigned long lastValidPacket;
|
||||
};
|
||||
|
||||
#endif // DCC_DECODER_H
|
||||
108
ESP32/DCC-Loco/include/LEDController.h
Normal file
108
ESP32/DCC-Loco/include/LEDController.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @file LEDController.h
|
||||
* @brief WS2812 LED Controller for lighting effects
|
||||
*
|
||||
* Controls WS2812 addressable LEDs for headlights, taillights, and other effects.
|
||||
* Supports direction-based lighting and function-controlled effects.
|
||||
*/
|
||||
|
||||
#ifndef LED_CONTROLLER_H
|
||||
#define LED_CONTROLLER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <FastLED.h>
|
||||
|
||||
#define MAX_LEDS 16
|
||||
#define DEFAULT_BRIGHTNESS 128
|
||||
|
||||
enum LightMode {
|
||||
LIGHT_OFF = 0,
|
||||
LIGHT_ON = 1,
|
||||
LIGHT_BLINK = 2,
|
||||
LIGHT_PULSE = 3,
|
||||
LIGHT_DIRECTION_FRONT = 4, // On when moving forward
|
||||
LIGHT_DIRECTION_REAR = 5 // On when moving backward
|
||||
};
|
||||
|
||||
class LEDController {
|
||||
public:
|
||||
LEDController();
|
||||
|
||||
/**
|
||||
* @brief Initialize LED controller
|
||||
* @param ledPin GPIO pin for WS2812 data
|
||||
* @param numLeds Number of LEDs in the strip
|
||||
* @return true if successful
|
||||
*/
|
||||
bool begin(uint8_t ledPin, uint8_t numLeds);
|
||||
|
||||
/**
|
||||
* @brief Update LED states (call regularly from loop)
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* @brief Set LED mode for a specific LED
|
||||
* @param ledIndex LED index (0-based)
|
||||
* @param mode Light mode
|
||||
*/
|
||||
void setLEDMode(uint8_t ledIndex, LightMode mode);
|
||||
|
||||
/**
|
||||
* @brief Set LED color
|
||||
* @param ledIndex LED index
|
||||
* @param r Red (0-255)
|
||||
* @param g Green (0-255)
|
||||
* @param b Blue (0-255)
|
||||
*/
|
||||
void setLEDColor(uint8_t ledIndex, uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
/**
|
||||
* @brief Set global brightness
|
||||
* @param brightness Brightness (0-255)
|
||||
*/
|
||||
void setBrightness(uint8_t brightness);
|
||||
|
||||
/**
|
||||
* @brief Set direction for directional lights
|
||||
* @param forward true = forward, false = reverse
|
||||
*/
|
||||
void setDirection(bool forward);
|
||||
|
||||
/**
|
||||
* @brief Map function to LED
|
||||
* @param functionNum Function number (0-28)
|
||||
* @param ledIndex LED index
|
||||
* @param mode Light mode when function is active
|
||||
*/
|
||||
void mapFunctionToLED(uint8_t functionNum, uint8_t ledIndex, LightMode mode);
|
||||
|
||||
/**
|
||||
* @brief Update function state
|
||||
* @param functionNum Function number
|
||||
* @param state Function state (true = on)
|
||||
*/
|
||||
void setFunctionState(uint8_t functionNum, bool state);
|
||||
|
||||
private:
|
||||
CRGB leds[MAX_LEDS];
|
||||
uint8_t numLEDs;
|
||||
uint8_t dataPin;
|
||||
bool direction;
|
||||
|
||||
struct LEDConfig {
|
||||
LightMode mode;
|
||||
CRGB color;
|
||||
uint8_t mappedFunction; // 255 = no function mapping
|
||||
};
|
||||
|
||||
LEDConfig ledConfig[MAX_LEDS];
|
||||
bool functionStates[29]; // F0-F28
|
||||
|
||||
unsigned long lastUpdate;
|
||||
uint16_t effectCounter;
|
||||
|
||||
void updateLED(uint8_t ledIndex);
|
||||
};
|
||||
|
||||
#endif // LED_CONTROLLER_H
|
||||
114
ESP32/DCC-Loco/include/MotorDriver.h
Normal file
114
ESP32/DCC-Loco/include/MotorDriver.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* @file MotorDriver.h
|
||||
* @brief TB67H450FNG Motor Driver Controller
|
||||
*
|
||||
* Controls the TB67H450FNG H-bridge motor driver with PWM speed control,
|
||||
* direction control, and optional load compensation/BEMF feedback.
|
||||
*/
|
||||
|
||||
#ifndef MOTOR_DRIVER_H
|
||||
#define MOTOR_DRIVER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// TB67H450FNG control pins
|
||||
// IN1 and IN2 control direction and brake
|
||||
// PWM controls speed
|
||||
|
||||
class MotorDriver {
|
||||
public:
|
||||
MotorDriver();
|
||||
|
||||
/**
|
||||
* @brief Initialize motor driver
|
||||
* @param in1Pin GPIO for IN1 (Motor phase A)
|
||||
* @param in2Pin GPIO for IN2 (Motor phase B)
|
||||
* @param pwmPin GPIO for PWM speed control
|
||||
* @param currentSensePin ADC pin for current sensing (optional, 255 = disabled)
|
||||
* @return true if successful
|
||||
*/
|
||||
bool begin(uint8_t in1Pin, uint8_t in2Pin, uint8_t pwmPin, uint8_t currentSensePin = 255);
|
||||
|
||||
/**
|
||||
* @brief Set motor speed and direction
|
||||
* @param speed Speed value (0-126, DCC format: 0=stop, 1=emergency stop, 2-127=speed)
|
||||
* @param forward Direction (true=forward, false=reverse)
|
||||
*/
|
||||
void setSpeed(uint8_t speed, bool forward);
|
||||
|
||||
/**
|
||||
* @brief Emergency stop
|
||||
*/
|
||||
void emergencyStop();
|
||||
|
||||
/**
|
||||
* @brief Update motor control (call regularly for load compensation)
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* @brief Enable/disable load compensation
|
||||
* @param enable true to enable
|
||||
*/
|
||||
void setLoadCompensation(bool enable);
|
||||
|
||||
/**
|
||||
* @brief Get motor current (if current sensing enabled)
|
||||
* @return Current in mA
|
||||
*/
|
||||
uint16_t getMotorCurrent();
|
||||
|
||||
/**
|
||||
* @brief Set PID parameters for load compensation
|
||||
* @param kp Proportional gain
|
||||
* @param ki Integral gain
|
||||
* @param kd Derivative gain
|
||||
*/
|
||||
void setPIDParameters(float kp, float ki, float kd);
|
||||
|
||||
/**
|
||||
* @brief Set acceleration rate
|
||||
* @param rate Rate value (0-255, higher = faster)
|
||||
*/
|
||||
void setAccelRate(uint8_t rate);
|
||||
|
||||
/**
|
||||
* @brief Set deceleration rate
|
||||
* @param rate Rate value (0-255, higher = faster)
|
||||
*/
|
||||
void setDecelRate(uint8_t rate);
|
||||
|
||||
private:
|
||||
uint8_t pinIN1;
|
||||
uint8_t pinIN2;
|
||||
uint8_t pinPWM;
|
||||
uint8_t pinCurrentSense;
|
||||
|
||||
uint8_t targetSpeed;
|
||||
uint8_t currentSpeed;
|
||||
bool targetDirection;
|
||||
bool loadCompensationEnabled;
|
||||
|
||||
// Acceleration/deceleration
|
||||
uint8_t accelRate;
|
||||
uint8_t decelRate;
|
||||
unsigned long lastSpeedUpdate;
|
||||
|
||||
// Load compensation (PID)
|
||||
float Kp, Ki, Kd;
|
||||
float integral;
|
||||
float lastError;
|
||||
uint16_t targetCurrent;
|
||||
|
||||
// PWM settings
|
||||
const uint8_t pwmChannel = 0;
|
||||
const uint32_t pwmFrequency = 20000; // 20 kHz
|
||||
const uint8_t pwmResolution = 8; // 8-bit (0-255)
|
||||
|
||||
void applyMotorControl();
|
||||
void updateAcceleration();
|
||||
void updateLoadCompensation();
|
||||
uint16_t readCurrent();
|
||||
};
|
||||
|
||||
#endif // MOTOR_DRIVER_H
|
||||
93
ESP32/DCC-Loco/include/RailCom.h
Normal file
93
ESP32/DCC-Loco/include/RailCom.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @file RailCom.h
|
||||
* @brief RailCom Feedback Controller
|
||||
*
|
||||
* Implements RailCom channel 1 and 2 for bidirectional communication
|
||||
* with the command station. Sends locomotive address and status information.
|
||||
*/
|
||||
|
||||
#ifndef RAILCOM_H
|
||||
#define RAILCOM_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// RailCom timing (in microseconds)
|
||||
#define RAILCOM_CHANNEL1_START 26
|
||||
#define RAILCOM_CHANNEL1_END 177
|
||||
#define RAILCOM_CHANNEL2_START 193
|
||||
#define RAILCOM_CHANNEL2_END 454
|
||||
|
||||
// RailCom 4bit to 8bit encoding table
|
||||
#define RAILCOM_4BIT_TO_8BIT_SIZE 16
|
||||
|
||||
class RailCom {
|
||||
public:
|
||||
RailCom();
|
||||
|
||||
/**
|
||||
* @brief Initialize RailCom
|
||||
* @param txPin GPIO for RailCom transmit (UART TX)
|
||||
* @param cutoutDetectPin GPIO to detect DCC cutout (optional, 255 = disabled)
|
||||
* @return true if successful
|
||||
*/
|
||||
bool begin(uint8_t txPin, uint8_t cutoutDetectPin = 255);
|
||||
|
||||
/**
|
||||
* @brief Enable/disable RailCom
|
||||
* @param enable true to enable
|
||||
*/
|
||||
void setEnabled(bool enable);
|
||||
|
||||
/**
|
||||
* @brief Check if RailCom is enabled
|
||||
*/
|
||||
bool isEnabled() const { return enabled; }
|
||||
|
||||
/**
|
||||
* @brief Send RailCom data during cutout window
|
||||
* This should be called when DCC cutout is detected
|
||||
*/
|
||||
void sendRailComData();
|
||||
|
||||
/**
|
||||
* @brief Set locomotive address for RailCom reporting
|
||||
* @param address Locomotive address
|
||||
*/
|
||||
void setAddress(uint16_t address);
|
||||
|
||||
/**
|
||||
* @brief Set decoder state information
|
||||
* @param speed Current speed
|
||||
* @param direction Current direction
|
||||
*/
|
||||
void setDecoderState(uint8_t speed, bool direction);
|
||||
|
||||
/**
|
||||
* @brief Update RailCom (call regularly from loop)
|
||||
*/
|
||||
void update();
|
||||
|
||||
private:
|
||||
uint8_t txPin;
|
||||
uint8_t cutoutPin;
|
||||
bool enabled;
|
||||
|
||||
uint16_t locoAddress;
|
||||
uint8_t currentSpeed;
|
||||
bool currentDirection;
|
||||
|
||||
HardwareSerial* railcomSerial;
|
||||
|
||||
// RailCom encoding
|
||||
uint8_t encode4to8(uint8_t data);
|
||||
void sendChannel1();
|
||||
void sendChannel2();
|
||||
|
||||
// Timing
|
||||
unsigned long lastCutoutTime;
|
||||
bool inCutout;
|
||||
|
||||
static const uint8_t railcom4to8[16];
|
||||
};
|
||||
|
||||
#endif // RAILCOM_H
|
||||
Reference in New Issue
Block a user