mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2025-07-29 18:33:44 +02:00
Compare commits
21 Commits
v3.2.0rc2
...
RCN213-fix
Author | SHA1 | Date | |
---|---|---|---|
|
fd43a9b88b | ||
|
f05b3d1730 | ||
|
a2f8a8ec91 | ||
|
746350b846 | ||
|
97f3450621 | ||
|
2be3e276f9 | ||
|
88fa5ad37c | ||
|
106fb612dc | ||
|
53113e981d | ||
|
d7fd9e1538 | ||
|
197228c3b0 | ||
|
620dcbf925 | ||
|
82f121c8ef | ||
|
6c98f90151 | ||
|
c90ea0c6df | ||
|
d08f14be3b | ||
|
fb97ba11de | ||
|
ee5db61349 | ||
|
b384d6c14d | ||
|
58fe81bf06 | ||
|
0e78cf6e55 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,6 +10,7 @@ config.h
|
||||
.vscode/extensions.json
|
||||
mySetup.h
|
||||
mySetup.cpp
|
||||
myHal.cpp
|
||||
myAutomation.h
|
||||
myFilter.cpp
|
||||
myAutomation.h
|
||||
|
@@ -88,16 +88,9 @@ void setup()
|
||||
// Start RMFT (ignored if no automnation)
|
||||
RMFT::begin();
|
||||
|
||||
// Link to and call mySetup() function (if defined in the build in mySetup.cpp).
|
||||
// The contents will depend on the user's system hardware configuration.
|
||||
// The mySetup.cpp file is a standard C++ module so has access to all of the DCC++EX APIs.
|
||||
extern __attribute__((weak)) void mySetup();
|
||||
if (mySetup) {
|
||||
mySetup();
|
||||
}
|
||||
|
||||
// Invoke any DCC++EX commands in the form "SETUP("xxxx");"" found in optional file mySetup.h.
|
||||
// This can be used to create turnouts, outputs, sensors etc. throught the normal text commands.
|
||||
// This can be used to create turnouts, outputs, sensors etc. through the normal text commands.
|
||||
#if __has_include ( "mySetup.h")
|
||||
#define SETUP(cmd) serialParser.parse(F(cmd))
|
||||
#include "mySetup.h"
|
||||
|
@@ -368,7 +368,7 @@ void DCCEXParser::parse(Print *stream, byte *com, RingStream * ringStream)
|
||||
|| ((p[activep] & 0x01) != p[activep]) // invalid activate 0|1
|
||||
) break;
|
||||
// Honour the configuration option (config.h) which allows the <a> command to be reversed
|
||||
#ifdef DCC_ACCESSORY_RCN_213
|
||||
#ifdef DCC_ACCESSORY_COMMAND_REVERSE
|
||||
DCC::setAccessory(address, subaddress,p[activep]==0);
|
||||
#else
|
||||
DCC::setAccessory(address, subaddress,p[activep]==1);
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#ifndef EthernetInterface_h
|
||||
#define EthernetInterface_h
|
||||
|
||||
#include "defines.h")
|
||||
#include "defines.h"
|
||||
#include "DCCEXParser.h"
|
||||
#include <Arduino.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
@@ -1 +1 @@
|
||||
#define GITHUB_SHA "37904b5"
|
||||
#define GITHUB_SHA "a2f8a8e"
|
||||
|
@@ -107,11 +107,16 @@
|
||||
* the loop() function is called, and may be adequate under some circumstances.
|
||||
* The advantage of NOT using interrupts is that the impact of I2C upon the DCC waveform (when accurate timing mode isn't in use)
|
||||
* becomes almost zero.
|
||||
* This mechanism is under evaluation and should not be relied upon as yet.
|
||||
*
|
||||
*/
|
||||
|
||||
// Uncomment following line to enable Wire library instead of native I2C drivers
|
||||
//#define I2C_USE_WIRE
|
||||
|
||||
// Uncomment following line to disable the use of interrupts by the native I2C drivers.
|
||||
//#define I2C_NO_INTERRUPTS
|
||||
|
||||
// Default to use interrupts within the native I2C drivers.
|
||||
#ifndef I2C_NO_INTERRUPTS
|
||||
#define I2C_USE_INTERRUPTS
|
||||
#endif
|
||||
|
@@ -129,6 +129,10 @@ uint8_t I2CManagerClass::read(uint8_t i2cAddress, uint8_t *readBuffer, uint8_t r
|
||||
/***************************************************************************
|
||||
* checkForTimeout() function, called from isBusy() and wait() to cancel
|
||||
* requests that are taking too long to complete.
|
||||
* This function doesn't fully work as intended so is not currently called.
|
||||
* Instead we check for an I2C hang-up and report an error from
|
||||
* I2CRB::wait(), but we aren't able to recover from the hang-up. Such faults
|
||||
* may be caused by an I2C wire short for example.
|
||||
***************************************************************************/
|
||||
void I2CManagerClass::checkForTimeout() {
|
||||
unsigned long currentMicros = micros();
|
||||
@@ -163,7 +167,10 @@ void I2CManagerClass::loop() {
|
||||
#if !defined(I2C_USE_INTERRUPTS)
|
||||
handleInterrupt();
|
||||
#endif
|
||||
checkForTimeout();
|
||||
// Timeout is now reported in I2CRB::wait(), not here.
|
||||
// I've left the code, commented out, as a reminder to look at this again
|
||||
// in the future.
|
||||
//checkForTimeout();
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
@@ -175,6 +182,9 @@ void I2CManagerClass::handleInterrupt() {
|
||||
// Update hardware state machine
|
||||
I2C_handleInterrupt();
|
||||
|
||||
// Enable interrupts to minimise effect on other interrupt code
|
||||
interrupts();
|
||||
|
||||
// Check if current request has completed. If there's a current request
|
||||
// and state isn't active then state contains the completion status of the request.
|
||||
if (state != I2C_STATE_ACTIVE && currentRequest != NULL) {
|
||||
|
76
IODevice.cpp
76
IODevice.cpp
@@ -28,6 +28,10 @@
|
||||
#define USE_FAST_IO
|
||||
#endif
|
||||
|
||||
// Link to halSetup function. If not defined, the function reference will be NULL.
|
||||
extern __attribute__((weak)) void halSetup();
|
||||
extern __attribute__((weak)) void mySetup(); // Deprecated function name, output warning if it's declared
|
||||
|
||||
//==================================================================================================================
|
||||
// Static methods
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
@@ -57,6 +61,16 @@ void IODevice::begin() {
|
||||
dev->_begin();
|
||||
}
|
||||
_initPhase = false;
|
||||
|
||||
// Check for presence of deprecated mySetup() function, and output warning.
|
||||
if (mySetup)
|
||||
DIAG(F("WARNING: mySetup() function should be renamed to halSetup()"));
|
||||
|
||||
// Call user's halSetup() function (if defined in the build in myHal.cpp).
|
||||
// The contents will depend on the user's system hardware configuration.
|
||||
// The myHal.cpp file is a standard C++ module so has access to all of the DCC++EX APIs.
|
||||
if (halSetup)
|
||||
halSetup();
|
||||
}
|
||||
|
||||
// Overarching static loop() method for the IODevice subsystem. Works through the
|
||||
@@ -148,6 +162,33 @@ void IODevice::_display() {
|
||||
bool IODevice::configure(VPIN vpin, ConfigTypeEnum configType, int paramCount, int params[]) {
|
||||
IODevice *dev = findDevice(vpin);
|
||||
if (dev) return dev->_configure(vpin, configType, paramCount, params);
|
||||
#ifdef DIAG_IO
|
||||
DIAG(F("IODevice::configure(): Vpin ID %d not found!"), (int)vpin);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read value from virtual pin.
|
||||
int IODevice::read(VPIN vpin) {
|
||||
for (IODevice *dev = _firstDevice; dev != 0; dev = dev->_nextDevice) {
|
||||
if (dev->owns(vpin))
|
||||
return dev->_read(vpin);
|
||||
}
|
||||
#ifdef DIAG_IO
|
||||
DIAG(F("IODevice::read(): Vpin %d not found!"), (int)vpin);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read analogue value from virtual pin.
|
||||
int IODevice::readAnalogue(VPIN vpin) {
|
||||
for (IODevice *dev = _firstDevice; dev != 0; dev = dev->_nextDevice) {
|
||||
if (dev->owns(vpin))
|
||||
return dev->_readAnalogue(vpin);
|
||||
}
|
||||
#ifdef DIAG_IO
|
||||
DIAG(F("IODevice::readAnalogue(): Vpin %d not found!"), (int)vpin);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -258,48 +299,22 @@ bool IODevice::owns(VPIN id) {
|
||||
return (id >= _firstVpin && id < _firstVpin + _nPins);
|
||||
}
|
||||
|
||||
// Read value from virtual pin.
|
||||
int IODevice::read(VPIN vpin) {
|
||||
for (IODevice *dev = _firstDevice; dev != 0; dev = dev->_nextDevice) {
|
||||
if (dev->owns(vpin))
|
||||
return dev->_read(vpin);
|
||||
}
|
||||
#ifdef DIAG_IO
|
||||
DIAG(F("IODevice::read(): Vpin %d not found!"), (int)vpin);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read analogue value from virtual pin.
|
||||
int IODevice::readAnalogue(VPIN vpin) {
|
||||
for (IODevice *dev = _firstDevice; dev != 0; dev = dev->_nextDevice) {
|
||||
if (dev->owns(vpin))
|
||||
return dev->_readAnalogue(vpin);
|
||||
}
|
||||
#ifdef DIAG_IO
|
||||
DIAG(F("IODevice::readAnalogue(): Vpin %d not found!"), (int)vpin);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#else // !defined(IO_NO_HAL)
|
||||
|
||||
// Minimal implementations of public HAL interface, to support Arduino pin I/O and nothing more.
|
||||
|
||||
void IODevice::begin() { DIAG(F("NO HAL CONFIGURED!")); }
|
||||
bool IODevice::configure(VPIN pin, ConfigTypeEnum, int, int p[]) {
|
||||
bool IODevice::configure(VPIN pin, ConfigTypeEnum configType, int nParams, int p[]) {
|
||||
if (configType!=CONFIGURE_INPUT || nParams!=1 || pin >= NUM_DIGITAL_PINS) return false;
|
||||
#ifdef DIAG_IO
|
||||
DIAG(F("Arduino _configurePullup Pin:%d Val:%d"), pin, p[0]);
|
||||
#endif
|
||||
if (p[0]) {
|
||||
pinMode(pin, INPUT_PULLUP);
|
||||
} else {
|
||||
pinMode(pin, INPUT);
|
||||
}
|
||||
pinMode(pin, p[0] ? INPUT_PULLUP : INPUT);
|
||||
return true;
|
||||
}
|
||||
void IODevice::write(VPIN vpin, int value) {
|
||||
if (vpin >= NUM_DIGITAL_PINS) return;
|
||||
digitalWrite(vpin, value);
|
||||
pinMode(vpin, OUTPUT);
|
||||
}
|
||||
@@ -307,6 +322,7 @@ void IODevice::writeAnalogue(VPIN, int, uint8_t, uint16_t) {}
|
||||
bool IODevice::isBusy(VPIN) { return false; }
|
||||
bool IODevice::hasCallback(VPIN) { return false; }
|
||||
int IODevice::read(VPIN vpin) {
|
||||
if (vpin >= NUM_DIGITAL_PINS) return 0;
|
||||
return !digitalRead(vpin); // Return inverted state (5v=0, 0v=1)
|
||||
}
|
||||
int IODevice::readAnalogue(VPIN vpin) {
|
||||
|
@@ -47,11 +47,15 @@ void DCCAccessoryDecoder::_begin() {
|
||||
// Device-specific write function. State 1=closed, 0=thrown. Adjust for RCN-213 compliance
|
||||
void DCCAccessoryDecoder::_write(VPIN id, int state) {
|
||||
int packedAddress = _packedAddress + id - _firstVpin;
|
||||
#ifdef DIAG_IO
|
||||
DIAG(F("DCC Write Linear Address:%d State:%d"), packedAddress, state);
|
||||
#endif
|
||||
#if !defined(DCC_ACCESSORY_RCN_213)
|
||||
#if defined(HAL_ACCESSORY_COMMAND_REVERSE)
|
||||
state = !state;
|
||||
#ifdef DIAG_IO
|
||||
DIAG(F("DCC Write Linear Address:%d State:%d (inverted)"), packedAddress, state);
|
||||
#endif
|
||||
#else
|
||||
#ifdef DIAG_IO
|
||||
DIAG(F("DCC Write Linear Address:%d State:%d"), packedAddress, state);
|
||||
#endif
|
||||
#endif
|
||||
DCC::setAccessory(ADDRESS(packedAddress), SUBADDRESS(packedAddress), state);
|
||||
}
|
||||
|
@@ -75,7 +75,7 @@ private:
|
||||
if (immediate) {
|
||||
uint8_t buffer[1];
|
||||
I2CManager.read(_I2CAddress, buffer, 1);
|
||||
_portInputState = ((uint16_t)buffer) & 0xff;
|
||||
_portInputState = buffer[0];
|
||||
} else {
|
||||
requestBlock.wait(); // Wait for preceding operation to complete
|
||||
// Issue new request to read GPIO register
|
||||
@@ -86,7 +86,7 @@ private:
|
||||
// This function is invoked when an I/O operation on the requestBlock completes.
|
||||
void _processCompletion(uint8_t status) override {
|
||||
if (status == I2C_STATUS_OK)
|
||||
_portInputState = ((uint16_t)inputBuffer[0]) & 0xff;
|
||||
_portInputState = inputBuffer[0];
|
||||
else
|
||||
_portInputState = 0xff;
|
||||
}
|
||||
|
@@ -720,10 +720,10 @@ void RMFT2::kill(const FSH * reason, int operand) {
|
||||
byte opcode=GET_OPCODE;
|
||||
if (opcode==OPCODE_ENDEXRAIL) return;
|
||||
if (opcode!=OPCODE_SIGNAL) continue;
|
||||
byte redpin=GET_OPERAND(0);
|
||||
VPIN redpin=GET_OPERAND(0);
|
||||
if (redpin!=id)continue;
|
||||
byte amberpin=GET_OPERAND(1);
|
||||
byte greenpin=GET_OPERAND(2);
|
||||
VPIN amberpin=GET_OPERAND(1);
|
||||
VPIN greenpin=GET_OPERAND(2);
|
||||
// If amberpin is zero, synthesise amber from red+green
|
||||
IODevice::write(redpin,red || (amber && (amberpin==0)));
|
||||
if (amberpin) IODevice::write(amberpin,amber);
|
||||
|
170
SSD1306Ascii.cpp
170
SSD1306Ascii.cpp
@@ -89,28 +89,93 @@ const uint8_t FLASH SSD1306AsciiWire::blankPixels[30] =
|
||||
{0x40, // First byte specifies data mode
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
// this section is based on https://github.com/adafruit/Adafruit_SSD1306
|
||||
|
||||
/** Initialization commands for a 128x32 or 128x64 SSD1306 oled display. */
|
||||
const uint8_t FLASH SSD1306AsciiWire::Adafruit128xXXinit[] = {
|
||||
// Init sequence for Adafruit 128x32/64 OLED module
|
||||
0x00, // Set to command mode
|
||||
SSD1306_DISPLAYOFF,
|
||||
SSD1306_SETDISPLAYCLOCKDIV, 0x80, // the suggested ratio 0x80
|
||||
SSD1306_SETMULTIPLEX, 0x3F, // ratio 64 (initially)
|
||||
SSD1306_SETDISPLAYOFFSET, 0x0, // no offset
|
||||
SSD1306_SETSTARTLINE | 0x0, // line #0
|
||||
SSD1306_CHARGEPUMP, 0x14, // internal vcc
|
||||
SSD1306_MEMORYMODE, 0x02, // page mode
|
||||
SSD1306_SEGREMAP | 0x1, // column 127 mapped to SEG0
|
||||
SSD1306_COMSCANDEC, // column scan direction reversed
|
||||
SSD1306_SETCOMPINS, 0X12, // set COM pins
|
||||
SSD1306_SETCONTRAST, 0x7F, // contrast level 127
|
||||
SSD1306_SETPRECHARGE, 0xF1, // pre-charge period (1, 15)
|
||||
SSD1306_SETVCOMDETECT, 0x40, // vcomh regulator level
|
||||
SSD1306_DISPLAYALLON_RESUME,
|
||||
SSD1306_NORMALDISPLAY,
|
||||
SSD1306_DISPLAYON
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// This section is based on https://github.com/stanleyhuangyc/MultiLCD
|
||||
|
||||
/** Initialization commands for a 128x64 SH1106 oled display. */
|
||||
const uint8_t FLASH SSD1306AsciiWire::SH1106_132x64init[] = {
|
||||
0x00, // Set to command mode
|
||||
SSD1306_DISPLAYOFF,
|
||||
SSD1306_SETDISPLAYCLOCKDIV, 0X80, // set osc division
|
||||
SSD1306_SETMULTIPLEX, 0x3F, // ratio 64
|
||||
SSD1306_SETDISPLAYOFFSET, 0X00, // set display offset
|
||||
SSD1306_SETSTARTPAGE | 0X0, // set page address
|
||||
SSD1306_SETSTARTLINE | 0x0, // set start line
|
||||
SH1106_SET_PUMP_MODE, SH1106_PUMP_ON, // set charge pump enable
|
||||
SSD1306_SEGREMAP | 0X1, // set segment remap
|
||||
SSD1306_COMSCANDEC, // Com scan direction
|
||||
SSD1306_SETCOMPINS, 0X12, // set COM pins
|
||||
SSD1306_SETCONTRAST, 0x80, // 128
|
||||
SSD1306_SETPRECHARGE, 0X1F, // set pre-charge period
|
||||
SSD1306_SETVCOMDETECT, 0x40, // set vcomh
|
||||
SH1106_SET_PUMP_VOLTAGE | 0X2, // 8.0 volts
|
||||
SSD1306_NORMALDISPLAY, // normal / reverse
|
||||
SSD1306_DISPLAYON
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// SSD1306AsciiWire Method Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Constructor
|
||||
SSD1306AsciiWire::SSD1306AsciiWire(int width, int height) {
|
||||
m_displayWidth = width;
|
||||
m_displayHeight = height;
|
||||
// Set size in characters in base class
|
||||
lcdRows = height / 8;
|
||||
lcdCols = width / 6;
|
||||
m_col = 0;
|
||||
m_row = 0;
|
||||
m_colOffset = 0;
|
||||
|
||||
I2CManager.begin();
|
||||
I2CManager.setClock(400000L); // Set max supported I2C speed
|
||||
for (byte address = 0x3c; address <= 0x3d; address++) {
|
||||
if (I2CManager.exists(address)) {
|
||||
m_i2cAddr = address;
|
||||
if (m_displayWidth==132 && m_displayHeight==64) {
|
||||
// SH1106 display. This uses 128x64 centered within a 132x64 OLED.
|
||||
m_colOffset = 2;
|
||||
I2CManager.write_P(address, SH1106_132x64init, sizeof(SH1106_132x64init));
|
||||
} else if (m_displayWidth==128 && (m_displayHeight==64 || m_displayHeight==32)) {
|
||||
// SSD1306 128x64 or 128x32
|
||||
I2CManager.write_P(address, Adafruit128xXXinit, sizeof(Adafruit128xXXinit));
|
||||
if (m_displayHeight == 32)
|
||||
I2CManager.write(address, 5, 0, // Set command mode
|
||||
SSD1306_SETMULTIPLEX, 0x1F, // ratio 32
|
||||
SSD1306_SETCOMPINS, 0x02); // sequential COM pins, disable remap
|
||||
} else {
|
||||
DIAG(F("OLED configuration option not recognised"));
|
||||
return;
|
||||
}
|
||||
// Device found
|
||||
DIAG(F("%dx%d OLED display configured on I2C:x%x"), width, height, address);
|
||||
if (width == 132)
|
||||
begin(&SH1106_132x64, address);
|
||||
else if (height == 32)
|
||||
begin(&Adafruit128x32, address);
|
||||
else
|
||||
begin(&Adafruit128x64, address);
|
||||
// Set singleton address
|
||||
lcdDisplay = this;
|
||||
clear();
|
||||
@@ -132,23 +197,6 @@ void SSD1306AsciiWire::clearNative() {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise device
|
||||
void SSD1306AsciiWire::begin(const DevType* dev, uint8_t i2cAddr) {
|
||||
m_i2cAddr = i2cAddr;
|
||||
m_col = 0;
|
||||
m_row = 0;
|
||||
const uint8_t* table = (const uint8_t*)GETFLASHW(&dev->initcmds);
|
||||
uint8_t size = GETFLASH(&dev->initSize);
|
||||
m_displayWidth = GETFLASH(&dev->lcdWidth);
|
||||
m_displayHeight = GETFLASH(&dev->lcdHeight);
|
||||
m_colOffset = GETFLASH(&dev->colOffset);
|
||||
I2CManager.write_P(m_i2cAddr, table, size);
|
||||
if (m_displayHeight == 32)
|
||||
I2CManager.write(m_i2cAddr, 5, 0, // Set command mode
|
||||
SSD1306_SETMULTIPLEX, 0x1F, // ratio 32
|
||||
SSD1306_SETCOMPINS, 0x02); // sequential COM pins, disable remap
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Set cursor position (by text line)
|
||||
@@ -209,82 +257,6 @@ size_t SSD1306AsciiWire::writeNative(uint8_t ch) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// this section is based on https://github.com/adafruit/Adafruit_SSD1306
|
||||
|
||||
/** Initialization commands for a 128x32 or 128x64 SSD1306 oled display. */
|
||||
const uint8_t FLASH SSD1306AsciiWire::Adafruit128xXXinit[] = {
|
||||
// Init sequence for Adafruit 128x32/64 OLED module
|
||||
0x00, // Set to command mode
|
||||
SSD1306_DISPLAYOFF,
|
||||
SSD1306_SETDISPLAYCLOCKDIV, 0x80, // the suggested ratio 0x80
|
||||
SSD1306_SETMULTIPLEX, 0x3F, // ratio 64 (initially)
|
||||
SSD1306_SETDISPLAYOFFSET, 0x0, // no offset
|
||||
SSD1306_SETSTARTLINE | 0x0, // line #0
|
||||
SSD1306_CHARGEPUMP, 0x14, // internal vcc
|
||||
SSD1306_MEMORYMODE, 0x02, // page mode
|
||||
SSD1306_SEGREMAP | 0x1, // column 127 mapped to SEG0
|
||||
SSD1306_COMSCANDEC, // column scan direction reversed
|
||||
SSD1306_SETCOMPINS, 0X12, // set COM pins
|
||||
SSD1306_SETCONTRAST, 0x7F, // contrast level 127
|
||||
SSD1306_SETPRECHARGE, 0xF1, // pre-charge period (1, 15)
|
||||
SSD1306_SETVCOMDETECT, 0x40, // vcomh regulator level
|
||||
SSD1306_DISPLAYALLON_RESUME,
|
||||
SSD1306_NORMALDISPLAY,
|
||||
SSD1306_DISPLAYON
|
||||
};
|
||||
|
||||
/** Initialize a 128x32 SSD1306 oled display. */
|
||||
const DevType FLASH SSD1306AsciiWire::Adafruit128x32 = {
|
||||
Adafruit128xXXinit,
|
||||
sizeof(Adafruit128xXXinit),
|
||||
128,
|
||||
32,
|
||||
0
|
||||
};
|
||||
|
||||
/** Initialize a 128x64 oled display. */
|
||||
const DevType FLASH SSD1306AsciiWire::Adafruit128x64 = {
|
||||
Adafruit128xXXinit,
|
||||
sizeof(Adafruit128xXXinit),
|
||||
128,
|
||||
64,
|
||||
0
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
// This section is based on https://github.com/stanleyhuangyc/MultiLCD
|
||||
|
||||
/** Initialization commands for a 128x64 SH1106 oled display. */
|
||||
const uint8_t FLASH SSD1306AsciiWire::SH1106_132x64init[] = {
|
||||
0x00, // Set to command mode
|
||||
SSD1306_DISPLAYOFF,
|
||||
SSD1306_SETDISPLAYCLOCKDIV, 0X80, // set osc division
|
||||
SSD1306_SETMULTIPLEX, 0x3F, // ratio 64
|
||||
SSD1306_SETDISPLAYOFFSET, 0X00, // set display offset
|
||||
SSD1306_SETSTARTPAGE | 0X0, // set page address
|
||||
SSD1306_SETSTARTLINE | 0x0, // set start line
|
||||
SH1106_SET_PUMP_MODE, SH1106_PUMP_ON, // set charge pump enable
|
||||
SSD1306_SEGREMAP | 0X1, // set segment remap
|
||||
SSD1306_COMSCANDEC, // Com scan direction
|
||||
SSD1306_SETCOMPINS, 0X12, // set COM pins
|
||||
SSD1306_SETCONTRAST, 0x80, // 128
|
||||
SSD1306_SETPRECHARGE, 0X1F, // set pre-charge period
|
||||
SSD1306_SETVCOMDETECT, 0x40, // set vcomh
|
||||
SH1106_SET_PUMP_VOLTAGE | 0X2, // 8.0 volts
|
||||
SSD1306_NORMALDISPLAY, // normal / reverse
|
||||
SSD1306_DISPLAYON
|
||||
};
|
||||
|
||||
/** Initialize a 132x64 oled SH1106 display. */
|
||||
const DevType FLASH SSD1306AsciiWire::SH1106_132x64 = {
|
||||
SH1106_132x64init,
|
||||
sizeof(SH1106_132x64init),
|
||||
128,
|
||||
64,
|
||||
2 // SH1106 is a 132x64 controller but most OLEDs are only attached
|
||||
// to columns 2-129.
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
@@ -32,21 +32,6 @@
|
||||
//#define NOLOWERCASE
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Device initialization structure.
|
||||
|
||||
struct DevType {
|
||||
/* Pointer to initialization command bytes. */
|
||||
const uint8_t* initcmds;
|
||||
/* Number of initialization bytes */
|
||||
const uint8_t initSize;
|
||||
/* Width of the display in pixels */
|
||||
const uint8_t lcdWidth;
|
||||
/** Height of the display in pixels. */
|
||||
const uint8_t lcdHeight;
|
||||
/* Column offset RAM to display. Used to pick start column of SH1106. */
|
||||
const uint8_t colOffset;
|
||||
};
|
||||
|
||||
// Constructor
|
||||
class SSD1306AsciiWire : public LCDDisplay {
|
||||
public:
|
||||
@@ -55,25 +40,17 @@ class SSD1306AsciiWire : public LCDDisplay {
|
||||
SSD1306AsciiWire(int width, int height);
|
||||
|
||||
// Initialize the display controller.
|
||||
void begin(const DevType* dev, uint8_t i2cAddr);
|
||||
void begin(uint8_t i2cAddr);
|
||||
|
||||
// Clear the display and set the cursor to (0, 0).
|
||||
void clearNative() override;
|
||||
|
||||
// Set cursor to start of specified text line
|
||||
void setRowNative(byte line) override;
|
||||
|
||||
// Initialize the display controller.
|
||||
void init(const DevType* dev);
|
||||
|
||||
// Write one character to OLED
|
||||
size_t writeNative(uint8_t c) override;
|
||||
|
||||
// Display characteristics / initialisation
|
||||
static const DevType FLASH Adafruit128x32;
|
||||
static const DevType FLASH Adafruit128x64;
|
||||
static const DevType FLASH SH1106_132x64;
|
||||
|
||||
bool isBusy() override { return requestBlock.isBusy(); }
|
||||
|
||||
private:
|
||||
|
@@ -141,10 +141,20 @@ The configuration file for DCC-EX Command Station
|
||||
// don't add it to your config.h.
|
||||
//#define DCC_TURNOUTS_RCN_213
|
||||
|
||||
// The following #define likewise inverts the behaviour of the <a> command
|
||||
// for triggering DCC Accessory Decoders, so that <a addr subaddr 0> generates a
|
||||
// By default, the driver which defines a DCC accessory decoder
|
||||
// does send out the same state change on the DCC packet as it
|
||||
// receives. This means a VPIN state=1 sends D=1 (close turnout
|
||||
// or signal green) in the DCC packet. This can be reversed if
|
||||
// necessary.
|
||||
//#define HAL_ACCESSORY_COMMAND_REVERSE
|
||||
|
||||
// If you have issues with that the direction of the accessory commands is
|
||||
// reversed (for example when converting from another CS to DCC-EX) then
|
||||
// you can use this to revese the sense of all accessory commmands sent
|
||||
// over DCC++. This #define likewise inverts the behaviour of the <a> command
|
||||
// for triggering DCC Accessory Decoders, so that <a addr subaddr 0> generates a
|
||||
// DCC packet with D=1 (close turnout) and <a addr subaddr 1> generates D=0
|
||||
// (throw turnout).
|
||||
//#define DCC_ACCESSORY_RCN_213
|
||||
//#define DCC_ACCESSORY_COMMAND_REVERSE
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
161
myHal.cpp_example.txt
Normal file
161
myHal.cpp_example.txt
Normal file
@@ -0,0 +1,161 @@
|
||||
// Sample myHal.cpp file.
|
||||
//
|
||||
// To use this file, copy it to myHal.cpp and uncomment the directives and/or
|
||||
// edit them to satisfy your requirements. If you only want to use up to
|
||||
// two MCP23017 GPIO Expander modules and/or up to two PCA9685 Servo modules,
|
||||
// then you don't need this file as DCC++EX configures these for free!
|
||||
|
||||
// Note that if the file has a .cpp extension it WILL be compiled into the build
|
||||
// and the halSetup() function WILL be invoked.
|
||||
//
|
||||
// To prevent this, temporarily rename the file to myHal.txt or similar.
|
||||
//
|
||||
|
||||
// Include devices you need.
|
||||
#include "IODevice.h"
|
||||
#include "IO_HCSR04.h" // Ultrasonic range sensor
|
||||
#include "IO_VL53L0X.h" // Laser time-of-flight sensor
|
||||
#include "IO_DFPlayer.h" // MP3 sound player
|
||||
|
||||
|
||||
//==========================================================================
|
||||
// The function halSetup() is invoked from CS if it exists within the build.
|
||||
// The setup calls are included between the open and close braces "{ ... }".
|
||||
// Comments (lines preceded by "//") are optional.
|
||||
//==========================================================================
|
||||
|
||||
void halSetup() {
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines a PCA9685 PWM Servo driver module.
|
||||
//=======================================================================
|
||||
// The parameters are:
|
||||
// First Vpin=100
|
||||
// Number of VPINs=16 (numbered 100-115)
|
||||
// I2C address of module=0x40
|
||||
|
||||
//PCA9685::create(100, 16, 0x40);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines an MCP23017 16-port I2C GPIO Extender module.
|
||||
//=======================================================================
|
||||
// The parameters are:
|
||||
// First Vpin=196
|
||||
// Number of VPINs=16 (numbered 196-211)
|
||||
// I2C address of module=0x22
|
||||
|
||||
//MCP23017::create(196, 16, 0x22);
|
||||
|
||||
|
||||
// Alternative form, which allows the INT pin of the module to request a scan
|
||||
// by pulling Arduino pin 40 to ground. Means that the I2C isn't being polled
|
||||
// all the time, only when a change takes place. Multiple modules' INT pins
|
||||
// may be connected to the same Arduino pin.
|
||||
|
||||
//MCP23017::create(196, 16, 0x22, 40);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines an MCP23008 8-port I2C GPIO Extender module.
|
||||
//=======================================================================
|
||||
// The parameters are:
|
||||
// First Vpin=300
|
||||
// Number of VPINs=8 (numbered 300-307)
|
||||
// I2C address of module=0x22
|
||||
|
||||
//MCP23008::create(300, 8, 0x22);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines a PCF8574 8-port I2C GPIO Extender module.
|
||||
//=======================================================================
|
||||
// The parameters are:
|
||||
// First Vpin=200
|
||||
// Number of VPINs=8 (numbered 200-207)
|
||||
// I2C address of module=0x23
|
||||
|
||||
//PCF8574::create(200, 8, 0x23);
|
||||
|
||||
|
||||
// Alternative form using INT pin (see above)
|
||||
|
||||
//PCF8574::create(200, 8, 0x23, 40);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines an HCSR04 ultrasonic ranging module.
|
||||
//=======================================================================
|
||||
// The parameters are:
|
||||
// Vpin=2000 (only one VPIN per directive)
|
||||
// Number of VPINs=1
|
||||
// Arduino pin connected to TRIG=30
|
||||
// Arduino pin connected to ECHO=31
|
||||
// Minimum trigger range=20cm (VPIN goes to 1 when <20cm)
|
||||
// Maximum trigger range=25cm (VPIN goes to 0 when >25cm)
|
||||
// Note: Multiple devices can be configured by using a different ECHO pin
|
||||
// for each one. The TRIG pin can be shared between multiple devices.
|
||||
// Be aware that the 'ping' of one device may be received by another
|
||||
// device and position them accordingly!
|
||||
|
||||
//HCSR04::create(2000, 30, 31, 20, 25);
|
||||
//HCSR04::create(2001, 30, 32, 20, 25);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines a single VL53L0X Time-of-Flight range sensor.
|
||||
//=======================================================================
|
||||
// The parameters are:
|
||||
// VPIN=5000
|
||||
// Number of VPINs=1
|
||||
// I2C address=0x29 (default for this chip)
|
||||
// Minimum trigger range=200mm (VPIN goes to 1 when <20cm)
|
||||
// Maximum trigger range=250mm (VPIN goes to 0 when >25cm)
|
||||
|
||||
//VL53L0X::create(5000, 1, 0x29, 200, 250);
|
||||
|
||||
// For multiple VL53L0X modules, add another parameter which is a VPIN connected to the
|
||||
// module's XSHUT pin. This allows the modules to be configured, at start,
|
||||
// with distinct I2C addresses. In this case, the address 0x29 is only used during
|
||||
// initialisation to configure each device in turn with the desired unique I2C address.
|
||||
// The examples below have the modules' XSHUT pins connected to the first two pins of
|
||||
// the first MCP23017 module (164 and 165), but Arduino pins may be used instead.
|
||||
// The first module here is given I2C address 0x30 and the second is 0x31.
|
||||
|
||||
//VL53L0X::create(5000, 1, 0x30, 200, 250, 164);
|
||||
//VL53L0X::create(5001, 1, 0x31, 200, 250, 165);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// Play mp3 files from a Micro-SD card, using a DFPlayer MP3 Module.
|
||||
//=======================================================================
|
||||
// Parameters:
|
||||
// 10000 = first VPIN allocated.
|
||||
// 10 = number of VPINs allocated.
|
||||
// Serial1 = name of serial port (usually Serial1 or Serial2).
|
||||
// With these parameters, up to 10 files may be played on pins 10000-10009.
|
||||
// Play is started from EX-RAIL with SET(10000) for first mp3 file, SET(10001)
|
||||
// for second file, etc. Play may also be initiated by writing an analogue
|
||||
// value to the first pin, e.g. SERVO(10000,23,0) will play the 23rd mp3 file.
|
||||
// SERVO(10000,23,30) will do the same thing, as well as setting the volume to
|
||||
// 30 (maximum value).
|
||||
// Play is stopped by RESET(10000) (or any other allocated VPIN).
|
||||
// Volume may also be set by writing an analogue value to the second pin for the player,
|
||||
// e.g. SERVO(10001,30,0) sets volume to maximum (30).
|
||||
// The EX-RAIL script may check for completion of play by calling WAITFOR(pin), which will only proceed to the
|
||||
// following line when the player is no longer busy.
|
||||
// E.g.
|
||||
// SEQUENCE(1)
|
||||
// AT(164) // Wait for sensor attached to pin 164 to activate
|
||||
// SET(10003) // Play fourth MP3 file
|
||||
// LCD(4, "Playing") // Display message on LCD/OLED
|
||||
// WAITFOR(10003) // Wait for playing to finish
|
||||
// LCD(4, " ") // Clear LCD/OLED line
|
||||
// FOLLOW(1) // Go back to start
|
||||
|
||||
// DFPlayer::create(10000, 10, Serial1);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,214 +0,0 @@
|
||||
// Sample mySetup.cpp file.
|
||||
//
|
||||
// To use this file, copy it to mySetup.cpp and uncomment the directives and/or
|
||||
// edit them to satisfy your requirements.
|
||||
|
||||
// Note that if the file has a .cpp extension it WILL be compiled into the build
|
||||
// and the mySetup() function WILL be invoked.
|
||||
//
|
||||
// To prevent this, temporarily rename it to mySetup.txt or similar.
|
||||
//
|
||||
|
||||
#include "IODevice.h"
|
||||
#include "Turnouts.h"
|
||||
#include "Sensors.h"
|
||||
#include "IO_HCSR04.h"
|
||||
#include "IO_VL53L0X.h"
|
||||
|
||||
|
||||
// The #if directive prevent compile errors for Uno and Nano by excluding the
|
||||
// HAL directives from the build.
|
||||
#if !defined(IO_NO_HAL)
|
||||
|
||||
|
||||
// Examples of statically defined HAL directives (alternative to the create() call).
|
||||
// These have to be outside of the mySetup() function.
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines a PCA9685 PWM Servo driver module.
|
||||
//=======================================================================
|
||||
// The parameters are:
|
||||
// First Vpin=100
|
||||
// Number of VPINs=16 (numbered 100-115)
|
||||
// I2C address of module=0x40
|
||||
|
||||
//PCA9685 pwmModule1(100, 16, 0x40);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines an MCP23017 16-port I2C GPIO Extender module.
|
||||
//=======================================================================
|
||||
// The parameters are:
|
||||
// First Vpin=196
|
||||
// Number of VPINs=16 (numbered 196-211)
|
||||
// I2C address of module=0x22
|
||||
|
||||
//MCP23017 gpioModule2(196, 16, 0x22);
|
||||
|
||||
|
||||
// Alternative form, which allows the INT pin of the module to request a scan
|
||||
// by pulling Arduino pin 40 to ground. Means that the I2C isn't being polled
|
||||
// all the time, only when a change takes place. Multiple modules' INT pins
|
||||
// may be connected to the same Arduino pin.
|
||||
|
||||
//MCP23017 gpioModule2(196, 16, 0x22, 40);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines an MCP23008 8-port I2C GPIO Extender module.
|
||||
//=======================================================================
|
||||
// The parameters are:
|
||||
// First Vpin=300
|
||||
// Number of VPINs=8 (numbered 300-307)
|
||||
// I2C address of module=0x22
|
||||
|
||||
//MCP23008 gpioModule3(300, 8, 0x22);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines a PCF8574 8-port I2C GPIO Extender module.
|
||||
//=======================================================================
|
||||
// The parameters are:
|
||||
// First Vpin=200
|
||||
// Number of VPINs=8 (numbered 200-207)
|
||||
// I2C address of module=0x23
|
||||
|
||||
//PCF8574 gpioModule4(200, 8, 0x23);
|
||||
|
||||
|
||||
// Alternative form using INT pin (see above)
|
||||
|
||||
//PCF8574 gpioModule4(200, 8, 0x23, 40);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines an HCSR04 ultrasonic ranging module.
|
||||
//=======================================================================
|
||||
// The parameters are:
|
||||
// Vpin=2000 (only one VPIN per directive)
|
||||
// Number of VPINs=1
|
||||
// Arduino pin connected to TRIG=30
|
||||
// Arduino pin connected to ECHO=31
|
||||
// Minimum trigger range=20cm (VPIN goes to 1 when <20cm)
|
||||
// Maximum trigger range=25cm (VPIN goes to 0 when >25cm)
|
||||
// Note: Multiple devices can be configured by using a different ECHO pin
|
||||
// for each one. The TRIG pin can be shared between multiple devices.
|
||||
// Be aware that the 'ping' of one device may be received by another
|
||||
// device and position them accordingly!
|
||||
|
||||
//HCSR04 sonarModule1(2000, 30, 31, 20, 25);
|
||||
//HCSR04 sonarModule2(2001, 30, 32, 20, 25);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines a single VL53L0X Time-of-Flight range sensor.
|
||||
//=======================================================================
|
||||
// The parameters are:
|
||||
// VPIN=5000
|
||||
// Number of VPINs=1
|
||||
// I2C address=0x29 (default for this chip)
|
||||
// Minimum trigger range=200mm (VPIN goes to 1 when <20cm)
|
||||
// Maximum trigger range=250mm (VPIN goes to 0 when >25cm)
|
||||
|
||||
//VL53L0X tofModule1(5000, 1, 0x29, 200, 250);
|
||||
|
||||
// For multiple VL53L0X modules, add another parameter which is a VPIN connected to the
|
||||
// module's XSHUT pin. This allows the modules to be configured, at start,
|
||||
// with distinct I2C addresses. In this case, the address 0x29 is only used during
|
||||
// initialisation to configure each device in turn with the desired unique I2C address.
|
||||
// The examples below have the modules' XSHUT pins connected to the first two pins of
|
||||
// the first MCP23017 module (164 and 165), but Arduino pins may be used instead.
|
||||
// The first module here is given I2C address 0x30 and the second is 0x31.
|
||||
|
||||
//VL53L0X tofModule1(5000, 1, 0x30, 200, 250, 164);
|
||||
//VL53L0X tofModule2(5001, 1, 0x31, 200, 250, 165);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The function mySetup() is invoked from CS if it exists within the build.
|
||||
// It is called just before mysetup.h is executed, so things set up within here can be
|
||||
// referenced by commands in mySetup.h.
|
||||
//=======================================================================
|
||||
|
||||
void mySetup() {
|
||||
|
||||
// Alternative way of creating a module driver, which has to be within the mySetup() function
|
||||
// The other devices can also be created in this way. The parameter lists for the
|
||||
// create() function are identical to the parameter lists for the declarations.
|
||||
|
||||
//MCP23017::create(196, 16, 0x22);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// Creating a Turnout
|
||||
//=======================================================================
|
||||
// Parameters: same as <T> command for Servo turnouts
|
||||
// ID and VPIN are 100, sonar moves between positions 102 and 490 with slow profile.
|
||||
// Profile may be Instant, Fast, Medium, Slow or Bounce.
|
||||
|
||||
//ServoTurnout::create(100, 100, 490, 102, PCA9685::Slow);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// DCC Accessory turnout
|
||||
//=======================================================================
|
||||
// Parameters: same as <T> command for DCC Accessory turnouts
|
||||
// ID=3000
|
||||
// Decoder address=23
|
||||
// Decoder subaddress = 1
|
||||
|
||||
//DCCTurnout::create(3000, 23, 1);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// Creating a Sensor
|
||||
//=======================================================================
|
||||
// Parameters: As for the <S> command,
|
||||
// id = 164,
|
||||
// Vpin = 164 (configured above as pin 0 of an MCP23017)
|
||||
// Pullup enable = 1 (enabled)
|
||||
|
||||
//Sensor::create(164, 164, 1);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// Way of creating lots of identical sensors in a range
|
||||
//=======================================================================
|
||||
|
||||
//for (int i=165; i<180; i++)
|
||||
// Sensor::create(i, i, 1);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// Play mp3 files from a Micro-SD card, using a DFPlayer MP3 Module.
|
||||
//=======================================================================
|
||||
// Parameters:
|
||||
// 10000 = first VPIN allocated.
|
||||
// 10 = number of VPINs allocated.
|
||||
// Serial1 = name of serial port (usually Serial1 or Serial2).
|
||||
// With these parameters, up to 10 files may be played on pins 10000-10009.
|
||||
// Play is started from EX-RAIL with SET(10000) for first mp3 file, SET(10001)
|
||||
// for second file, etc. Play may also be initiated by writing an analogue
|
||||
// value to the first pin, e.g. SERVO(10000,23,0) will play the 23rd mp3 file.
|
||||
// SERVO(10000,23,30) will do the same thing, as well as setting the volume to
|
||||
// 30 (maximum value).
|
||||
// Play is stopped by RESET(10000) (or any other allocated VPIN).
|
||||
// Volume may also be set by writing an analogue value to the second pin for the player,
|
||||
// e.g. SERVO(10001,30,0) sets volume to maximum (30).
|
||||
// The EX-RAIL script may check for completion of play by calling WAITFOR(pin), which will only proceed to the
|
||||
// following line when the player is no longer busy.
|
||||
// E.g.
|
||||
// SEQUENCE(1)
|
||||
// AT(164) // Wait for sensor attached to pin 164 to activate
|
||||
// SET(10003) // Play fourth MP3 file
|
||||
// LCD(4, "Playing") // Display message on LCD/OLED
|
||||
// WAITFOR(10003) // Wait for playing to finish
|
||||
// LCD(4, " ") // Clear LCD/OLED line
|
||||
// FOLLOW(1) // Go back to start
|
||||
|
||||
// DFPlayer::create(10000, 10, Serial1);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "StringFormatter.h"
|
||||
|
||||
#define VERSION "3.2.0 rc2"
|
||||
#define VERSION "3.2.0 rc5"
|
||||
// 3.2.0 Major functional and non-functional changes.
|
||||
// New HAL added for I/O (digital and analogue inputs and outputs, servos etc).
|
||||
// Support for MCP23008, MCP23017 and PCF9584 I2C GPIO Extender modules.
|
||||
|
Reference in New Issue
Block a user