mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-23 16:16:13 +01:00
Compare commits
7 Commits
42abf5c912
...
6439100b74
Author | SHA1 | Date | |
---|---|---|---|
|
6439100b74 | ||
|
28d60d4984 | ||
|
6e9a3ebfb4 | ||
|
a30311caed | ||
|
faf9f76c42 | ||
|
dba5e88d04 | ||
|
7a9dee9bed |
|
@ -162,6 +162,7 @@ const int16_t HASH_KEYWORD_T='T';
|
||||||
const int16_t HASH_KEYWORD_X='X';
|
const int16_t HASH_KEYWORD_X='X';
|
||||||
const int16_t HASH_KEYWORD_LCN = 15137;
|
const int16_t HASH_KEYWORD_LCN = 15137;
|
||||||
const int16_t HASH_KEYWORD_HAL = 10853;
|
const int16_t HASH_KEYWORD_HAL = 10853;
|
||||||
|
const int16_t HASH_KEYWORD_HBRIDGE=-20585;
|
||||||
const int16_t HASH_KEYWORD_SHOW = -21309;
|
const int16_t HASH_KEYWORD_SHOW = -21309;
|
||||||
const int16_t HASH_KEYWORD_ANIN = -10424;
|
const int16_t HASH_KEYWORD_ANIN = -10424;
|
||||||
const int16_t HASH_KEYWORD_ANOUT = -26399;
|
const int16_t HASH_KEYWORD_ANOUT = -26399;
|
||||||
|
@ -917,6 +918,9 @@ bool DCCEXParser::parseT(Print *stream, int16_t params, int16_t p[])
|
||||||
if (params == 3 && p[1] == HASH_KEYWORD_VPIN) { // <T id VPIN n>
|
if (params == 3 && p[1] == HASH_KEYWORD_VPIN) { // <T id VPIN n>
|
||||||
if (!VpinTurnout::create(p[0], p[2])) return false;
|
if (!VpinTurnout::create(p[0], p[2])) return false;
|
||||||
} else
|
} else
|
||||||
|
if (params == 5 && p[1] == HASH_KEYWORD_HBRIDGE) { // <T id HBRIDGE pin1 pin2 delay>
|
||||||
|
if (!HBridgeTurnout::create(p[0], p[2], p[3], p[4])) return false;
|
||||||
|
} else
|
||||||
if (params >= 3 && p[1] == HASH_KEYWORD_DCC) {
|
if (params >= 3 && p[1] == HASH_KEYWORD_DCC) {
|
||||||
// <T id DCC addr subadd> 0<=addr<=511, 0<=subadd<=3 (like <a> command).<T>
|
// <T id DCC addr subadd> 0<=addr<=511, 0<=subadd<=3 (like <a> command).<T>
|
||||||
if (params==4 && p[2]>=0 && p[2]<512 && p[3]>=0 && p[3]<4) { // <T id DCC n m>
|
if (params==4 && p[2]>=0 && p[2]<512 && p[3]>=0 && p[3]<4) { // <T id DCC n m>
|
||||||
|
|
|
@ -239,6 +239,15 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OPCODE_HBRIDGETURNOUT: {
|
||||||
|
VPIN id=operand;
|
||||||
|
VPIN pin1=getOperand(progCounter, 1);
|
||||||
|
VPIN pin2=getOperand(progCounter, 2);
|
||||||
|
uint16_t delay=getOperand(progCounter, 3);
|
||||||
|
setTurnoutHiddenState(HBridgeTurnout::create(id,pin1, pin2, delay));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case OPCODE_AUTOSTART:
|
case OPCODE_AUTOSTART:
|
||||||
// automatically create a task from here at startup.
|
// automatically create a task from here at startup.
|
||||||
// Removed if (progCounter>0) check 4.2.31 because
|
// Removed if (progCounter>0) check 4.2.31 because
|
||||||
|
|
|
@ -51,7 +51,8 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,
|
||||||
OPCODE_POM,
|
OPCODE_POM,
|
||||||
OPCODE_START,OPCODE_SETLOCO,OPCODE_SENDLOCO,OPCODE_FORGET,
|
OPCODE_START,OPCODE_SETLOCO,OPCODE_SENDLOCO,OPCODE_FORGET,
|
||||||
OPCODE_PAUSE, OPCODE_RESUME,OPCODE_POWEROFF,OPCODE_POWERON,
|
OPCODE_PAUSE, OPCODE_RESUME,OPCODE_POWEROFF,OPCODE_POWERON,
|
||||||
OPCODE_ONCLOSE, OPCODE_ONTHROW, OPCODE_SERVOTURNOUT, OPCODE_PINTURNOUT,
|
OPCODE_ONCLOSE, OPCODE_ONTHROW, OPCODE_SERVOTURNOUT,
|
||||||
|
OPCODE_PINTURNOUT, OPCODE_HBRIDGETURNOUT,
|
||||||
OPCODE_PRINT,OPCODE_DCCACTIVATE,
|
OPCODE_PRINT,OPCODE_DCCACTIVATE,
|
||||||
OPCODE_ONACTIVATE,OPCODE_ONDEACTIVATE,
|
OPCODE_ONACTIVATE,OPCODE_ONDEACTIVATE,
|
||||||
OPCODE_ROSTER,OPCODE_KILLALL,
|
OPCODE_ROSTER,OPCODE_KILLALL,
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
#undef FWD
|
#undef FWD
|
||||||
#undef GREEN
|
#undef GREEN
|
||||||
#undef HAL
|
#undef HAL
|
||||||
|
#undef HBRIDGE_TURNOUT
|
||||||
#undef IF
|
#undef IF
|
||||||
#undef IFAMBER
|
#undef IFAMBER
|
||||||
#undef IFCLOSED
|
#undef IFCLOSED
|
||||||
|
@ -187,6 +188,7 @@
|
||||||
#define FWD(speed)
|
#define FWD(speed)
|
||||||
#define GREEN(signal_id)
|
#define GREEN(signal_id)
|
||||||
#define HAL(haltype,params...)
|
#define HAL(haltype,params...)
|
||||||
|
#define HBRIDGE_TURNOUT(id,pin1,pin2,dly,description...)
|
||||||
#define IF(sensor_id)
|
#define IF(sensor_id)
|
||||||
#define IFAMBER(signal_id)
|
#define IFAMBER(signal_id)
|
||||||
#define IFCLOSED(turnout_id)
|
#define IFCLOSED(turnout_id)
|
||||||
|
|
|
@ -174,6 +174,8 @@ void RMFT2::printMessage(uint16_t id) {
|
||||||
#define TURNOUT(id,addr,subaddr,description...) O_DESC(id,description)
|
#define TURNOUT(id,addr,subaddr,description...) O_DESC(id,description)
|
||||||
#undef TURNOUTL
|
#undef TURNOUTL
|
||||||
#define TURNOUTL(id,addr,description...) O_DESC(id,description)
|
#define TURNOUTL(id,addr,description...) O_DESC(id,description)
|
||||||
|
#undef HBRIDGE_TURNOUT
|
||||||
|
#define HBRIDGE_TURNOUT(id,pin1,pin2,delay_ms,description...) O_DESC(id,description)
|
||||||
#undef PIN_TURNOUT
|
#undef PIN_TURNOUT
|
||||||
#define PIN_TURNOUT(id,pin,description...) O_DESC(id,description)
|
#define PIN_TURNOUT(id,pin,description...) O_DESC(id,description)
|
||||||
#undef SERVO_TURNOUT
|
#undef SERVO_TURNOUT
|
||||||
|
@ -293,6 +295,7 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = {
|
||||||
#define FWD(speed) OPCODE_FWD,V(speed),
|
#define FWD(speed) OPCODE_FWD,V(speed),
|
||||||
#define GREEN(signal_id) OPCODE_GREEN,V(signal_id),
|
#define GREEN(signal_id) OPCODE_GREEN,V(signal_id),
|
||||||
#define HAL(haltype,params...)
|
#define HAL(haltype,params...)
|
||||||
|
#define HBRIDGE_TURNOUT(id,pin1,pin2,delay,description...) OPCODE_HBRIDGETURNOUT,V(id),OPCODE_PAD,V(pin1),OPCODE_PAD,V(pin2),OPCODE_PAD,V(delay),
|
||||||
#define IF(sensor_id) OPCODE_IF,V(sensor_id),
|
#define IF(sensor_id) OPCODE_IF,V(sensor_id),
|
||||||
#define IFAMBER(signal_id) OPCODE_IFAMBER,V(signal_id),
|
#define IFAMBER(signal_id) OPCODE_IFAMBER,V(signal_id),
|
||||||
#define IFCLOSED(turnout_id) OPCODE_IFCLOSED,V(turnout_id),
|
#define IFCLOSED(turnout_id) OPCODE_IFCLOSED,V(turnout_id),
|
||||||
|
|
115
IO_ScheduledPin.h
Normal file
115
IO_ScheduledPin.h
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* © 2023, Sergei Kotlyachkov. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of DCC++EX API
|
||||||
|
*
|
||||||
|
* This is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* It 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
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef IO_SCHEDULED_PIN_H
|
||||||
|
#define IO_SCHEDULED_PIN_H
|
||||||
|
|
||||||
|
#include "IODevice.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bounces back single Arduino Pin to specified state after set period of time.
|
||||||
|
*
|
||||||
|
* It will establish itself as owner of the pin over ArduinoPins class that typically responds to it and
|
||||||
|
* activates itself during loop() phase. It restores scheduled state and does not try again until
|
||||||
|
* another write()
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
* Create: ScheduledPin::create(5, LOW, 20000);
|
||||||
|
*
|
||||||
|
* Then, when neeeded, just call:
|
||||||
|
* IODevice::write(5, HIGH); // this will call fastWriteDigital(5, HIGH)
|
||||||
|
*
|
||||||
|
* In 20 milliseconds, it will also call fastWriteDigital(5, LOW)
|
||||||
|
*
|
||||||
|
* In edge case where write() is called twice before responding in the loop,
|
||||||
|
* the schedule will restart and double the bounce back time.
|
||||||
|
*/
|
||||||
|
class ScheduledPin : public IODevice {
|
||||||
|
private:
|
||||||
|
int _scheduledValue;
|
||||||
|
uint32_t _durationMicros;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Static function to handle create calls.
|
||||||
|
static void create(VPIN pin, int scheduledValue, uint32_t durationMicros) {
|
||||||
|
new ScheduledPin(pin, scheduledValue, durationMicros);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Constructor.
|
||||||
|
ScheduledPin(VPIN pin, int scheduledValue, uint32_t durationMicros) : IODevice(pin, 1) {
|
||||||
|
_scheduledValue = scheduledValue;
|
||||||
|
_durationMicros = durationMicros;
|
||||||
|
// Typically returned device will be ArduinoPins
|
||||||
|
IODevice* controlledDevice = IODevice::findDevice(pin);
|
||||||
|
if (controlledDevice != NULL) {
|
||||||
|
addDevice(this, controlledDevice);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DIAG(F("ScheduledPin Controlled device not found for VPIN:%d"), pin);
|
||||||
|
_deviceState = DEVSTATE_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Device-specific initialisation
|
||||||
|
void _begin() override {
|
||||||
|
#ifdef DIAG_IO
|
||||||
|
_display();
|
||||||
|
#endif
|
||||||
|
pinMode(_firstVpin, OUTPUT);
|
||||||
|
ArduinoPins::fastWriteDigital(_firstVpin, _scheduledValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _write(VPIN vpin, int value) override {
|
||||||
|
if (_deviceState == DEVSTATE_FAILED) return;
|
||||||
|
if (vpin != _firstVpin) {
|
||||||
|
#ifdef DIAG_IO
|
||||||
|
DIAG(F("ScheduledPin Error VPIN:%u not equal to %u"), vpin, _firstVpin);
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#ifdef DIAG_IO
|
||||||
|
DIAG(F("ScheduledPin Write VPIN:%u Value:%d Micros:%l"), vpin, value, micros());
|
||||||
|
#endif
|
||||||
|
unsigned long currentMicros = micros();
|
||||||
|
delayUntil(currentMicros + _durationMicros);
|
||||||
|
ArduinoPins::fastWriteDigital(_firstVpin, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void _loop(unsigned long currentMicros) {
|
||||||
|
if (_deviceState == DEVSTATE_FAILED) return;
|
||||||
|
#ifdef DIAG_IO
|
||||||
|
DIAG(F("ScheduledPin Bounce VPIN:%u Value:%d Micros:%l"), _firstVpin, _scheduledValue, micros());
|
||||||
|
#endif
|
||||||
|
ArduinoPins::fastWriteDigital(_firstVpin, _scheduledValue);
|
||||||
|
delayUntil(currentMicros + 0x7fffffff); // Largest time in the future! Effectively disable _loop calls.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display information about the device, and perhaps its current condition (e.g. active, disabled etc).
|
||||||
|
void _display() {
|
||||||
|
DIAG(F("ScheduledPin Configured:%u Value:%d Duration:%l"), (int)_firstVpin,
|
||||||
|
_scheduledValue, _durationMicros);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IO_SCHEDULED_PIN_H
|
82
README.md
82
README.md
|
@ -1,77 +1,39 @@
|
||||||
# What is DCC++ EX?
|
# What is DCC-EX?
|
||||||
DCC++ EX is the organization maintaining several codebases that together represent a fully open source DCC system. Currently, this includes the following:
|
DCC-EX is a team of dedicated enthusiasts producing open source DCC & DC solutions for you to run your complete model railroad layout. Our easy to use, do-it-yourself, and free open source products run on off-the-shelf Arduino technology and are supported by numerous third party hardware and apps like JMRI, Engine Driver, wiThrottle, Rocrail and more.
|
||||||
|
|
||||||
* [CommandStation-EX](https://github.com/DCC-EX/CommandStation-EX/releases) - the latest take on the DCC++ command station for controlling your trains. Runs on an Arduino board, and includes advanced features such as a WiThrottle server implementation, turnout operation, general purpose inputs and outputs (I/O), and JMRI integration.
|
Currently, our products include the following:
|
||||||
* [exWebThrottle](https://github.com/DCC-EX/exWebThrottle) - a simple web based controller for your DCC++ command station.
|
|
||||||
* [BaseStation-installer](https://github.com/DCC-EX/BaseStation-Installer) - an installer executable that takes care of downloading and installing DCC++ firmware onto your hardware setup.
|
|
||||||
* [BaseStation-Classic](https://github.com/DCC-EX/BaseStation-Classic) - the original DCC++ software, packaged in a stable release. No active development, bug fixes only.
|
|
||||||
|
|
||||||
A basic DCC++ EX hardware setup can use easy to find, widely avalable Arduino boards that you can assemble yourself.
|
* [EX-CommandStation](https://github.com/DCC-EX/CommandStation-EX/releases)
|
||||||
|
* [EX-WebThrottle](https://github.com/DCC-EX/exWebThrottle)
|
||||||
Both CommandStation-EX and BaseStation-Classic support much of the NMRA Digital Command Control (DCC) [standards](http://www.nmra.org/dcc-working-group "NMRA DCC Working Group"), including:
|
* [EX-Installer](https://github.com/DCC-EX/EX-Installer)
|
||||||
|
* [EX-MotoShield8874](https://dcc-ex.com/reference/hardware/motorboards/ex-motor-shield-8874.html#gsc.tab=0)
|
||||||
* simultaneous control of multiple locomotives
|
* [EX-DCCInspector](https://github.com/DCC-EX/DCCInspector-EX)
|
||||||
* 2-byte and 4-byte locomotive addressing
|
* [EX-Toolbox](https://github.com/DCC-EX/EX-Toolbox)
|
||||||
* 28 or 128-step speed throttling
|
* [EX-Turntable](https://github.com/DCC-EX/EX-Turntable)
|
||||||
* Activate/de-activate all accessory function addresses 0-2048
|
* [EX-IOExpander](https://github.com/DCC-EX/EX-IOExpander)
|
||||||
* Control of all cab functions F0-F28 and F29-F68
|
* [EX-FastClock](https://github.com/DCC-EX/EX-FastClock)
|
||||||
* Main Track: Write configuration variable bytes and set/clear specific configuration variable (CV) bits (aka Programming on Main or POM)
|
* [DCCEXProtocol](https://github.com/DCC-EX/DCCEXProtocol)
|
||||||
* Programming Track: Same as the main track with the addition of reading configuration variable bytes
|
|
||||||
* And many more custom features. see [What's new in CommandStation-EX?](#whats-new-in-commandstation-ex)
|
|
||||||
|
|
||||||
|
Details of these projects can be found on [our web site](https://dcc-ex.com/).
|
||||||
|
|
||||||
# What’s in this Repository?
|
# What’s in this Repository?
|
||||||
|
|
||||||
This repository, CommandStation-EX, contains a complete DCC++ EX Commmand Station sketch designed for compiling and uploading into an Arduino Uno, Mega, or Nano.
|
This repository, CommandStation-EX, contains a complete DCC-EX *EX-CommmandStation* sketch designed for compiling and uploading into an Arduino Uno, Mega, or Nano.
|
||||||
|
|
||||||
To utilize this sketch, you can use the following:
|
To utilize this sketch, you can use the following:
|
||||||
|
|
||||||
1. (beginner) our [automated installer](https://github.com/DCC-EX/BaseStation-Installer)
|
1. (recommended for all levels of user) our [automated installer](https://github.com/DCC-EX/EX-Installer)
|
||||||
2. (intermediate) download the latest version from the [releases page](https://github.com/DCC-EX/CommandStation-EX/releases)
|
2. (intermediate) download the latest version from the [releases page](https://github.com/DCC-EX/CommandStation-EX/releases)
|
||||||
3. (advanced) use git clone on this repository
|
3. (advanced) use git clone on this repository
|
||||||
|
|
||||||
Not using the installer? Open the file "CommandStation-EX.ino" in the
|
Refer to [our web site](https://https://dcc-ex.com/ex-commandstation/get-started/index.html#/) for the hardware required for this project.
|
||||||
Arduino IDE. Please do not rename the folder containing the sketch
|
|
||||||
code, nor add any files in that folder. The Arduino IDE relies on the
|
|
||||||
structure and name of the folder to properly display and compile the
|
|
||||||
code. Rename or copy config.example.h to config.h. If you do not have
|
|
||||||
the standard setup, you must edit config.h according to the help texts
|
|
||||||
in config.h.
|
|
||||||
|
|
||||||
## What's new in CommandStation-EX?
|
**We seriously recommend using the EX-Installer**, however if you choose not to use the installer...
|
||||||
|
|
||||||
* WiThrottle server built in. Connect Engine Driver or WiThrottle clients directly to your Command Station (or through JMRI as before)
|
* Open the file ``CommandStation-EX.ino`` in the Arduino IDE or Visual Studio Code (VSC). Please do not rename the folder containing the sketch code, nor add any files in that folder. The Arduino IDE relies on the structure and name of the folder to properly display and compile the code.
|
||||||
* WiFi and Ethernet shield support
|
* Rename or copy ``config.example.h`` to ``config.h``.
|
||||||
* No more jumpers or soldering!
|
* You must edit ``config.h`` according to the help texts in ``config.h``.
|
||||||
* Direct support for all the most popular motor control boards including single pin (Arduino) or dual pin (IBT_2) type PWM inputs without the need for an adapter circuit
|
|
||||||
* I2C Display support (LCD and OLED)
|
|
||||||
* Improved short circuit detection and automatic reset from an overload
|
|
||||||
* Current reading, sensing and ACK detection settings in milliAmps instead of just pin readings
|
|
||||||
* Improved adherence to the NMRA DCC specification
|
|
||||||
* Complete support for all the old commands and front ends like JMRI
|
|
||||||
* Railcom cutout (beta)
|
|
||||||
* Simpler, modular, faster code with an API Library for developers for easy expansion
|
|
||||||
* New features and functions in JMRI
|
|
||||||
* Ability to join MAIN and PROG tracks into one MAIN track to run your locos
|
|
||||||
* "Drive-Away" feature - Throttles with support, like Engine Driver, can allow a loco to be programmed on a usable, electrically isolated programming track and then drive off onto the main track
|
|
||||||
* Diagnostic commands to test decoders that aren't reading or writing correctly
|
|
||||||
* Support for Uno, Nano, Mega, Nano Every and Teensy microcontrollers
|
|
||||||
* User Functions: Filter regular commands (like a turnout or output command) and pass it to your own function or accessory
|
|
||||||
* Support for LCN (layout control nodes)
|
|
||||||
* mySetup.h file that acts like an Autoexec.Bat command to send startup commands to the CS
|
|
||||||
* High Accuracty Waveform option for rock steady DCC signals
|
|
||||||
* New current response outputs current in mA, overlimit current, and maximum board capable current. Support for new current meter in JMRI
|
|
||||||
* USB Browser based EX-WebThrottle
|
|
||||||
* New, simpler, function control command
|
|
||||||
* Number of locos discovery command `<#>`
|
|
||||||
* Emergency stop command <!>
|
|
||||||
* Release cabs from memory command <-> all cabs, <- CAB> for just one loco address
|
|
||||||
* Automatic slot (register) management
|
|
||||||
* Automation (coming soon)
|
|
||||||
|
|
||||||
NOTE: DCC-EX is a major rewrite to the code. We started over and rebuilt it from the ground up! For what that means, you can read [HERE](https://dcc-ex.com/about/rewrite.html).
|
|
||||||
|
|
||||||
# More information
|
# More information
|
||||||
You can learn more at the [DCC++ EX website](https://dcc-ex.com/)
|
You can learn more at the [DCC-EX website](https://dcc-ex.com/)
|
||||||
|
|
||||||
- November 14, 2020
|
|
||||||
|
|
104
Turnouts.cpp
104
Turnouts.cpp
|
@ -36,6 +36,10 @@
|
||||||
#include "LCN.h"
|
#include "LCN.h"
|
||||||
#ifdef EESTOREDEBUG
|
#ifdef EESTOREDEBUG
|
||||||
#include "DIAG.h"
|
#include "DIAG.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IO_NO_HAL
|
||||||
|
#include "IO_ScheduledPin.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -187,6 +191,10 @@
|
||||||
// VPIN turnout
|
// VPIN turnout
|
||||||
tt = VpinTurnout::load(&turnoutData);
|
tt = VpinTurnout::load(&turnoutData);
|
||||||
break;
|
break;
|
||||||
|
case TURNOUT_HBRIDGE:
|
||||||
|
// HBRIDGE turnout
|
||||||
|
tt = HBridgeTurnout::load(&turnoutData);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// If we find anything else, then we don't know what it is or how long it is,
|
// If we find anything else, then we don't know what it is or how long it is,
|
||||||
// so we can't go any further through the EEPROM!
|
// so we can't go any further through the EEPROM!
|
||||||
|
@ -477,6 +485,102 @@
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************************
|
||||||
|
* HBridgeTurnout - Turnout controlled through a pair of HAL pins.
|
||||||
|
* Typically connected to Motor H-Bridge. Delay is used to quickly turn on/off power.
|
||||||
|
*************************************************************************************/
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
HBridgeTurnout::HBridgeTurnout(uint16_t id, VPIN pin1, VPIN pin2, uint16_t millisDelay, bool closed) :
|
||||||
|
Turnout(id, TURNOUT_HBRIDGE, closed)
|
||||||
|
{
|
||||||
|
_hbridgeTurnoutData.pin1 = pin1;
|
||||||
|
_hbridgeTurnoutData.pin2 = pin2;
|
||||||
|
_hbridgeTurnoutData.millisDelay = millisDelay;
|
||||||
|
#ifndef IO_NO_HAL
|
||||||
|
// HARD LIMIT to maximum 0.5 second to avoid burning the coil
|
||||||
|
// Also note 1000x multiplier because ScheduledPin works with microSeconds.
|
||||||
|
ScheduledPin::create(pin1, LOW, 1000*min(millisDelay, 500));
|
||||||
|
ScheduledPin::create(pin2, LOW, 1000*min(millisDelay, 500));
|
||||||
|
#else
|
||||||
|
DIAG(F("H-Brdige Turnout %d will be disabled because HAL is off"), id);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create function
|
||||||
|
/* static */ Turnout *HBridgeTurnout::create(uint16_t id, VPIN pin1, VPIN pin2, uint16_t millisDelay, bool closed) {
|
||||||
|
Turnout *tt = get(id);
|
||||||
|
if (tt) {
|
||||||
|
// Object already exists, check if it is usable
|
||||||
|
if (tt->isType(TURNOUT_HBRIDGE)) {
|
||||||
|
// Yes, so set parameters
|
||||||
|
HBridgeTurnout *hbt = (HBridgeTurnout *)tt;
|
||||||
|
hbt->_hbridgeTurnoutData.pin1 = pin1;
|
||||||
|
hbt->_hbridgeTurnoutData.pin2 = pin2;
|
||||||
|
hbt->_hbridgeTurnoutData.millisDelay = millisDelay;
|
||||||
|
// Don't touch the _closed parameter, retain the original value.
|
||||||
|
return tt;
|
||||||
|
} else {
|
||||||
|
// Incompatible object, delete and recreate
|
||||||
|
remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tt = (Turnout *)new HBridgeTurnout(id, pin1, pin2, millisDelay, closed);
|
||||||
|
return tt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load a VPIN turnout definition from EEPROM. The common Turnout data has already been read at this point.
|
||||||
|
/* static */ Turnout *HBridgeTurnout::load(struct TurnoutData *turnoutData) {
|
||||||
|
#ifndef DISABLE_EEPROM
|
||||||
|
HBridgeTurnoutData hbridgeTurnoutData;
|
||||||
|
// Read class-specific data from EEPROM
|
||||||
|
EEPROM.get(EEStore::pointer(), hbridgeTurnoutData);
|
||||||
|
EEStore::advance(sizeof(hbridgeTurnoutData));
|
||||||
|
|
||||||
|
// Create new object
|
||||||
|
HBridgeTurnout *tt = new HBridgeTurnout(turnoutData->id, hbridgeTurnoutData.pin1,
|
||||||
|
hbridgeTurnoutData.pin2, hbridgeTurnoutData.millisDelay, turnoutData->closed);
|
||||||
|
|
||||||
|
return tt;
|
||||||
|
#else
|
||||||
|
(void)turnoutData;
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report 1 for thrown, 0 for closed.
|
||||||
|
void HBridgeTurnout::print(Print *stream) {
|
||||||
|
StringFormatter::send(stream, F("<H %d HBRIDGE %d %d %d>\n"), _turnoutData.id, _hbridgeTurnoutData.pin1, _hbridgeTurnoutData.pin2,
|
||||||
|
!_turnoutData.closed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HBridgeTurnout::turnUpDown(VPIN pin) {
|
||||||
|
// HBridge turnouts require very small, prescribed time to keep pin1 or pin2 in HIGH state.
|
||||||
|
// Otherwise internal coil of the turnout will burn.
|
||||||
|
// If HAL is disabled (and therefore SchedulePin class), we can not turn this on,
|
||||||
|
// otherwise coil will burn and device will be lost.
|
||||||
|
#ifndef IO_NO_HAL
|
||||||
|
IODevice::write(pin, HIGH);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HBridgeTurnout::setClosedInternal(bool close) {
|
||||||
|
turnUpDown(close ? _hbridgeTurnoutData.pin2 : _hbridgeTurnoutData.pin1);
|
||||||
|
_turnoutData.closed = close;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HBridgeTurnout::save() {
|
||||||
|
#ifndef DISABLE_EEPROM
|
||||||
|
// Write turnout definition and current position to EEPROM
|
||||||
|
// First write common servo data, then
|
||||||
|
// write the servo-specific data
|
||||||
|
EEPROM.put(EEStore::pointer(), _turnoutData);
|
||||||
|
EEStore::advance(sizeof(_turnoutData));
|
||||||
|
EEPROM.put(EEStore::pointer(), _hbridgeTurnoutData);
|
||||||
|
EEStore::advance(sizeof(_hbridgeTurnoutData));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************************************
|
/*************************************************************************************
|
||||||
* LCNTurnout - Turnout controlled by Loconet
|
* LCNTurnout - Turnout controlled by Loconet
|
||||||
|
|
36
Turnouts.h
36
Turnouts.h
|
@ -37,6 +37,7 @@ enum {
|
||||||
TURNOUT_SERVO = 2,
|
TURNOUT_SERVO = 2,
|
||||||
TURNOUT_VPIN = 3,
|
TURNOUT_VPIN = 3,
|
||||||
TURNOUT_LCN = 4,
|
TURNOUT_LCN = 4,
|
||||||
|
TURNOUT_HBRIDGE = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*************************************************************************************
|
/*************************************************************************************
|
||||||
|
@ -284,6 +285,41 @@ protected:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*************************************************************************************
|
||||||
|
* HBridgeTurnout - Turnout controlled through a pair of HAL pins.
|
||||||
|
*
|
||||||
|
* Hard limited to maximum 0.5 second to avoid burning the coil
|
||||||
|
* Typical millisDelay should be within between 50 and 100
|
||||||
|
*************************************************************************************/
|
||||||
|
class HBridgeTurnout : public Turnout {
|
||||||
|
private:
|
||||||
|
// HBridgeTurnoutData contains data specific to this subclass that is
|
||||||
|
// written to EEPROM when the turnout is saved.
|
||||||
|
struct HBridgeTurnoutData {
|
||||||
|
VPIN pin1;
|
||||||
|
VPIN pin2;
|
||||||
|
uint16_t millisDelay;
|
||||||
|
} _hbridgeTurnoutData; // 6 bytes
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
HBridgeTurnout(uint16_t id, VPIN pin1, VPIN pin2, uint16_t millisDelay, bool closed);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Create function
|
||||||
|
static Turnout *create(uint16_t id, VPIN pin1, VPIN pin2, uint16_t millisDelay, bool closed=true);
|
||||||
|
|
||||||
|
// Load a HBRIDGE turnout definition from EEPROM. The common Turnout data has already been read at this point.
|
||||||
|
static Turnout *load(struct TurnoutData *turnoutData);
|
||||||
|
void print(Print *stream) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool setClosedInternal(bool close) override;
|
||||||
|
void save() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void turnUpDown(VPIN pin);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/*************************************************************************************
|
/*************************************************************************************
|
||||||
* LCNTurnout - Turnout controlled by Loconet
|
* LCNTurnout - Turnout controlled by Loconet
|
||||||
|
|
|
@ -36,6 +36,11 @@ const unsigned long LOOP_TIMEOUT = 2000;
|
||||||
bool WifiInterface::connected = false;
|
bool WifiInterface::connected = false;
|
||||||
Stream * WifiInterface::wifiStream;
|
Stream * WifiInterface::wifiStream;
|
||||||
|
|
||||||
|
#ifndef WIFI_AT_CHECK_TIMEOUT
|
||||||
|
// Some ESP32 AT firmware versions take time to initialize and do not respond to AT commands right away.
|
||||||
|
#define WIFI_AT_CHECK_TIMEOUT 2000
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef WIFI_CONNECT_TIMEOUT
|
#ifndef WIFI_CONNECT_TIMEOUT
|
||||||
// Tested how long it takes to FAIL an unknown SSID on firmware 1.7.4.
|
// Tested how long it takes to FAIL an unknown SSID on firmware 1.7.4.
|
||||||
// The ES should fail a connect in 15 seconds, we don't want to fail BEFORE that
|
// The ES should fail a connect in 15 seconds, we don't want to fail BEFORE that
|
||||||
|
@ -192,7 +197,7 @@ wifiSerialState WifiInterface::setup2(const FSH* SSid, const FSH* password,
|
||||||
}
|
}
|
||||||
|
|
||||||
StringFormatter::send(wifiStream, F("AT\r\n")); // Is something here that understands AT?
|
StringFormatter::send(wifiStream, F("AT\r\n")); // Is something here that understands AT?
|
||||||
if(!checkForOK(200, true))
|
if(!checkForOK(WIFI_AT_CHECK_TIMEOUT, true))
|
||||||
return WIFI_NOAT; // No AT compatible WiFi module here
|
return WIFI_NOAT; // No AT compatible WiFi module here
|
||||||
|
|
||||||
StringFormatter::send(wifiStream, F("ATE1\r\n")); // Turn on the echo, se we can see what's happening
|
StringFormatter::send(wifiStream, F("ATE1\r\n")); // Turn on the echo, se we can see what's happening
|
||||||
|
|
Loading…
Reference in New Issue
Block a user