mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-22 23:56:13 +01:00
Add files via upload
This commit is contained in:
parent
77e6e48d78
commit
d06d3ec77e
165
CamParser.cpp
165
CamParser.cpp
|
@ -1,71 +1,94 @@
|
|||
#include "CamParser.h"
|
||||
#include "FSH.h"
|
||||
#include "IO_EXSensorCAM.h"
|
||||
|
||||
|
||||
VPIN EXSensorCAM::CAMBaseVpin = 0;
|
||||
|
||||
bool CamParser::parseN(Print * stream, byte paramCount, int16_t p[])
|
||||
{
|
||||
(void)stream; // probably unused parameter
|
||||
// DIAG(F("cam (%d) %c %d %d %d"),paramCount,p[0],p[1],p[2],p[3]);
|
||||
|
||||
//if (EXSensorCAM::CAMBaseVpin==0) return false; // no cam found
|
||||
if (paramCount == 0) return false;
|
||||
VPIN vpin=EXSensorCAM::CAMBaseVpin;
|
||||
byte camop=p[0]; // cam oprerator (F is special)
|
||||
if (camop!='F') camop=p[0]+0x20; // lower case the oprerator
|
||||
int16_t param1;
|
||||
int16_t param2;
|
||||
|
||||
switch(paramCount) {
|
||||
case 0:
|
||||
return false;
|
||||
|
||||
case 1:
|
||||
if (strchr_P((const char *)F("egrvwxFimt"),camop) == nullptr) return false;
|
||||
param1=0;
|
||||
param2=0;
|
||||
break;
|
||||
|
||||
case 2: //<N code val>
|
||||
if(camop=='c'){
|
||||
EXSensorCAM::CAMBaseVpin=p[1];
|
||||
DIAG(F("CAM base vpin: %c %d "),p[0],p[1]);
|
||||
return true;
|
||||
}
|
||||
if (strchr_P((const char *)F("oalnrsuvimt"),camop) == nullptr) return false;
|
||||
|
||||
param1 = p[1];
|
||||
param2 = 0;
|
||||
break;
|
||||
|
||||
case 3: //<N vpin rowY colx >
|
||||
if (p[1]>236 || p[1]<0) return false;
|
||||
if (p[2]>316 || p[2]<0) return false;
|
||||
|
||||
camop='A'; // sepcial case in IO_SensorCAM
|
||||
vpin = p[0];
|
||||
param1 = p[1];
|
||||
param2 = p[2];
|
||||
break;
|
||||
|
||||
case 4: //<N a id row col>
|
||||
if (camop!='a') return false;//must start with 'a'
|
||||
|
||||
if (p[1]>80 || p[1]<0) return false;
|
||||
if (p[2]>236 || p[2]<0) return false;
|
||||
if (p[3]>316 || p[3]<0) return false;
|
||||
|
||||
camop=128+p[1]; // sensor id in camop
|
||||
param1=p[2]; // row
|
||||
param2=p[3]; // col
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
DIAG(F("Cam: %d %d %c %d"),vpin,param1,camop,param2);
|
||||
IODevice::writeAnalogue(vpin,param1,camop,param2);
|
||||
return true;
|
||||
}
|
||||
|
||||
//sensorCAM parser.cpp version 3.01 Aug 2024
|
||||
#include "CamParser.h"
|
||||
#include "FSH.h"
|
||||
#include "IO_EXSensorCAM.h"
|
||||
|
||||
#ifndef SENSORCAM_VPIN //define CAM vpin (700?) in config.h
|
||||
#define SENSORCAM_VPIN 0
|
||||
#endif
|
||||
#define CAM_VPIN SENSORCAM_VPIN
|
||||
#ifndef SENSORCAM2_VPIN
|
||||
#define SENSORCAM2_VPIN CAM_VPIN
|
||||
#endif
|
||||
#ifndef SENSORCAM3_VPIN
|
||||
#define SENSORCAM3_VPIN 0
|
||||
#endif
|
||||
const int CAMVPINS[] = {CAM_VPIN,SENSORCAM_VPIN,SENSORCAM2_VPIN,SENSORCAM3_VPIN};
|
||||
const int16_t version=9914;
|
||||
const int16_t ver=30177;
|
||||
const int16_t ve =2899;
|
||||
|
||||
VPIN EXSensorCAM::CAMBaseVpin = CAM_VPIN;
|
||||
|
||||
bool CamParser::parseN(Print * stream, byte paramCount, int16_t p[]) {
|
||||
(void)stream; // probably unused parameter
|
||||
VPIN vpin=EXSensorCAM::CAMBaseVpin; //use current CAM selection
|
||||
|
||||
if (paramCount==0) {
|
||||
DIAG(F("vpin:%d EXSensorCAMs defined at Vpins #1@ %d #2@ %d #3@ %d"),vpin,CAMVPINS[1],CAMVPINS[2],CAMVPINS[3]);
|
||||
return true;
|
||||
}
|
||||
uint8_t camop=p[0]; // cam oprerator
|
||||
int16_t param1=0;
|
||||
int16_t param3=9999; // =0 could invoke parameter changes. & -1 gives later errors
|
||||
|
||||
if(camop=='C'){
|
||||
if(p[1]>=100) EXSensorCAM::CAMBaseVpin=p[1];
|
||||
if(p[1]<4) EXSensorCAM::CAMBaseVpin=CAMVPINS[p[1]];
|
||||
DIAG(F("CAM base Vpin: %c %d "),p[0],EXSensorCAM::CAMBaseVpin);
|
||||
return true;
|
||||
}
|
||||
if (camop<100) { //switch CAM# if p[1] dictates
|
||||
if(p[1]>=100 && p[1]<400) { //limits to CAM# 1 to 3 for now
|
||||
vpin=CAMVPINS[p[1]/100];
|
||||
EXSensorCAM::CAMBaseVpin=vpin;
|
||||
DIAG(F("switching to CAM %d baseVpin:%d"),p[1]/100,vpin);
|
||||
p[1]=p[1]%100; //strip off CAM #
|
||||
}
|
||||
}
|
||||
if (EXSensorCAM::CAMBaseVpin==0) return false; // no cam defined
|
||||
|
||||
if((p[0] == ve) || (p[0] == ver) || (p[0] == version)) camop='^';
|
||||
// send UPPER case to sensorCAM to flag binary data from a DCCEX-CS parser
|
||||
switch(paramCount) {
|
||||
case 1: //<N ver> produces '^'
|
||||
if (strchr_P((const char *)F("EFGMRVW^"),camop) == nullptr) return false;
|
||||
if (camop=='F') camop=']'; //<NF> for Reset/Finish webCAM.
|
||||
break; // Coded as ']' else conflicts with <Nf %%>
|
||||
|
||||
case 2: //<N camop p1>
|
||||
if (strchr_P((const char *)F("ABFILMNOPRSTUV^"),camop)==nullptr) return false;
|
||||
param1=p[1];
|
||||
break;
|
||||
|
||||
case 3: //<N vpin rowY colx > or <N cmd p1 p2>
|
||||
camop=p[0];
|
||||
if (p[0]>=100) { //vpin - i.e. NOT 'A' through 'Z'
|
||||
if (p[1]>236 || p[1]<0) return false; //row
|
||||
if (p[2]>316 || p[2]<0) return false; //column
|
||||
camop=0x80; // special 'a' case for IO_SensorCAM
|
||||
vpin = p[0];
|
||||
}else if (strchr_P((const char *)F("IJMNT"),camop) == nullptr) return false;
|
||||
param1 = p[1];
|
||||
param3 = p[2];
|
||||
break;
|
||||
|
||||
case 4: //<N a id row col>
|
||||
if (camop!='A') return false; //must start with 'a'
|
||||
if (p[3]>316 || p[3]<0) return false;
|
||||
if (p[2]>236 || p[2]<0) return false;
|
||||
if (p[1]>97 || p[1]<0) return false; //treat as bsNo.
|
||||
vpin = vpin + (p[1]/10)*8 + p[1]%10; //translate p[1]
|
||||
camop=0x80; // special 'a' case for IO_SensorCAM
|
||||
param1=p[2]; // row
|
||||
param3=p[3]; // col
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
DIAG(F("CamParser: %d %c %d %d"),vpin,camop,param1,param3);
|
||||
IODevice::writeAnalogue(vpin,param1,camop,param3);
|
||||
return true;
|
||||
}
|
619
IO_EXSensorCAM.h
619
IO_EXSensorCAM.h
|
@ -1,208 +1,411 @@
|
|||
/* 12/MAY/24
|
||||
* © 2022, Peter Cole. All rights reserved.
|
||||
* © 2023, Barry Daniel ESP32 revision
|
||||
* © 2024, Harald Barth. All rights reserved.
|
||||
*
|
||||
* This file is part of EX-CommandStation
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The IO_EXSensorCAM.h device driver can integrate with the sensorCAM device.
|
||||
* This device driver will configure the device on startup, along with
|
||||
* interacting with the device for all input/output duties.
|
||||
*
|
||||
* To create EX-SensorCAM devices, define them in myAutomation.h:
|
||||
*
|
||||
* // HAL(EXSensorCAM,vpin, num_vpins, i2c_address);
|
||||
* HAL(EXSensorCAM,700, 80, 0x11)
|
||||
*
|
||||
* The total number of pins cannot exceed 80 because of the communications
|
||||
* packet format. The number of analogue inputs cannot exceed 16 because of a
|
||||
* limit on the maximum I2C packet size of 32 bytes (in the Wire library).
|
||||
*/
|
||||
|
||||
#ifndef IO_EX_EXSENSORCAM_H
|
||||
#define IO_EX_EXSENSORCAM_H
|
||||
|
||||
#include "DIAG.h"
|
||||
#include "FSH.h"
|
||||
#include "I2CManager.h"
|
||||
#include "IODevice.h"
|
||||
#include "CamParser.h"
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
* IODevice subclass for EX-SensorCAM.
|
||||
*/
|
||||
class EXSensorCAM : public IODevice {
|
||||
public:
|
||||
static void create(VPIN vpin, int nPins, I2CAddress i2cAddress) {
|
||||
if (checkNoOverlap(vpin, nPins, i2cAddress))
|
||||
new EXSensorCAM(vpin, nPins, i2cAddress);
|
||||
}
|
||||
static VPIN CAMBaseVpin;
|
||||
private:
|
||||
// Constructor
|
||||
EXSensorCAM(VPIN firstVpin, int nPins, I2CAddress i2cAddress) {
|
||||
_firstVpin = firstVpin;
|
||||
if (CAMBaseVpin==0) CAMBaseVpin=_firstVpin;
|
||||
// Number of pins cannot exceed 80.
|
||||
if (nPins > 80) nPins = 80;
|
||||
_nPins = nPins;
|
||||
_I2CAddress = i2cAddress;
|
||||
addDevice(this);
|
||||
}
|
||||
|
||||
void _begin() {
|
||||
// Initialise EX-SensorCAM device
|
||||
I2CManager.begin();
|
||||
|
||||
if (!I2CManager.exists(_I2CAddress)) {
|
||||
DIAG(F("EX-SensorCAM I2C:%s device not found"), _I2CAddress.toString());
|
||||
_deviceState = DEVSTATE_FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
_i2crb.setRequestParams(_I2CAddress, _inputBuffer, sizeof(_inputBuffer),
|
||||
_outputBuffer, sizeof(_outputBuffer));
|
||||
_outputBuffer[0]='V';
|
||||
_i2crb.writeLen=1;
|
||||
I2CManager.queueRequest(&_i2crb);
|
||||
_deviceState = DEVSTATE_SCANNING;
|
||||
}
|
||||
|
||||
|
||||
// Main loop, collect any input and reissue poll cmd
|
||||
void _loop(unsigned long currentMicros) override {
|
||||
if (_deviceState == DEVSTATE_FAILED) return; // If device failed, return
|
||||
|
||||
if (_i2crb.isBusy()) return; // If I2C operation still in progress, return
|
||||
|
||||
processInput();
|
||||
if (_deviceState == DEVSTATE_FAILED) return; // If device failed, return
|
||||
|
||||
|
||||
// is it time to request another set of pins?
|
||||
if (currentMicros - _lastDigitalRead > _digitalRefresh) return;
|
||||
|
||||
// Issue new read request for digital states.
|
||||
_lastDigitalRead = currentMicros;
|
||||
_outputBuffer[0] = 'Q'; // query sensor states
|
||||
_i2crb.writeLen = 1;
|
||||
I2CManager.queueRequest(&_i2crb);
|
||||
_deviceState = DEVSTATE_SCANNING;
|
||||
}
|
||||
|
||||
// Obtain the a block of 8 sensors as an analog value.
|
||||
// can be used to track poisition in sequention pin blocks
|
||||
int _readAnalogue(VPIN vpin) override {
|
||||
if (_deviceState == DEVSTATE_FAILED) return 0;
|
||||
return _digitalInputStates[(vpin - _firstVpin) / 8];
|
||||
}
|
||||
|
||||
// Obtain a sensor state
|
||||
int _read(VPIN vpin) override {
|
||||
if (_deviceState == DEVSTATE_FAILED) return 0;
|
||||
int pin = vpin - _firstVpin;
|
||||
return bitRead(_digitalInputStates[pin / 8], pin % 8);
|
||||
}
|
||||
|
||||
// Used to write a command from the parseN function.
|
||||
// note parameter names changed to suit use in this scenario
|
||||
// but the function signature remians as per IO_DEVICE
|
||||
// _writeAnalogue(VPIN vpin, int value, uint8_t profile, uint16_t duration) override {
|
||||
void _writeAnalogue(VPIN vpin, int p1, uint8_t opcode, uint16_t p2) override {
|
||||
if (_deviceState == DEVSTATE_FAILED) return; // If device failed, return
|
||||
_i2crb.wait();
|
||||
// opcodes are lower case as-entered by user through CamParser.
|
||||
// except as follows: (to avoid adding more base functions to IO_DEVICE)
|
||||
// <N a bsno row col> is passed in here as opcode=128+bsNo, p1=row, p2=col
|
||||
// so p0 is reverse engineered from the opcode
|
||||
// <N vpin row col> is passed with opcode 'A' p1=row, p2=col
|
||||
// and is converted to 'a' and the P0 bsNo obtained from the VPIN.
|
||||
uint16_t p0 =0;
|
||||
|
||||
if (opcode>=128) { // <N a bsNo row col>
|
||||
p0=opcode & 0x7f; // get bSno from opcode
|
||||
opcode='a'; // and revert to correct code
|
||||
}
|
||||
else if (opcode=='A') { // <N vpin row col>
|
||||
p0=vpin - _firstVpin;
|
||||
opcode='a';
|
||||
}
|
||||
|
||||
_outputBuffer[0]=opcode;
|
||||
_outputBuffer[1]=p0 & 0xFF;
|
||||
_outputBuffer[2]=p0 >> 8;
|
||||
_outputBuffer[3]=p1 & 0xFF;
|
||||
_outputBuffer[4]=(p1 >> 8) & 0xFF;
|
||||
_outputBuffer[5]=p2 & 0xFF;
|
||||
_outputBuffer[6]=p2 >> 8;
|
||||
I2CManager.queueRequest(&_i2crb);
|
||||
}
|
||||
|
||||
// This function is invoked when an I/O operation on the requestBlock
|
||||
// completes.
|
||||
void processInput() {
|
||||
if (_deviceState != DEVSTATE_SCANNING) return;
|
||||
// some input was pending
|
||||
uint8_t status = _i2crb.status;
|
||||
if (status != I2C_STATUS_OK) {
|
||||
reportError(status);
|
||||
return;
|
||||
}
|
||||
|
||||
_deviceState = DEVSTATE_NORMAL;
|
||||
|
||||
if (_inputBuffer[0] == 'Q') { // all sensors
|
||||
memcpy(_digitalInputStates, _inputBuffer + 1,
|
||||
sizeof(_digitalInputStates));
|
||||
return;
|
||||
}
|
||||
if (_inputBuffer[0] == 'V') { // version response
|
||||
memcpy(_version, _inputBuffer + 1, sizeof(_version));
|
||||
_display();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Display device information and status.
|
||||
void _display() override {
|
||||
DIAG(F("EX-SensorCAM I2C:%s v%d.%d.%d Vpins %u-%u %S"),
|
||||
_I2CAddress.toString(), _version[0], _version[1], _version[2],
|
||||
(int)_firstVpin, (int)_firstVpin + _nPins - 1,
|
||||
_deviceState == DEVSTATE_FAILED ? F("OFFLINE") : F(""));
|
||||
}
|
||||
|
||||
// Helper function for error handling
|
||||
void reportError(uint8_t status, bool fail = true) {
|
||||
DIAG(F("EX-SensorCAM I2C:%s Error:%d (%S)"), _I2CAddress.toString(), status,
|
||||
I2CManager.getErrorMessage(status));
|
||||
if (fail) _deviceState = DEVSTATE_FAILED;
|
||||
}
|
||||
|
||||
uint8_t _numDigitalPins = 80;
|
||||
uint8_t _version[3];
|
||||
uint8_t _digitalInputStates[10];
|
||||
I2CRB _i2crb;
|
||||
byte _inputBuffer[12];
|
||||
byte _outputBuffer[8];
|
||||
|
||||
unsigned long _lastDigitalRead = 0;
|
||||
const unsigned long _digitalRefresh =
|
||||
10000UL; // Delay refreshing digital inputs for 10ms
|
||||
};
|
||||
|
||||
#endif
|
||||
/* 2024/08/14
|
||||
* © 2024, Barry Daniel ESP32-CAM revision
|
||||
*
|
||||
* This file is part of EX-CommandStation
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define driverVer 301
|
||||
// v301 improved 'f' and 'p' code and driver version calc. Correct bsNo calc. for 'a'
|
||||
// v300 stripped & revised without expander functionality. Needs sensorCAM.h v300 AND CamParser.cpp
|
||||
// v222 uses '@'for EXIORDD read. handles <NB $> and <NN $ ##>
|
||||
// v216 includes 'j' command and uses CamParser rather than myFilter.h Incompatible with v203 senorCAM
|
||||
// v203 added pvtThreshold to 'i' output
|
||||
// v201 deleted code for compatibility with CAM pre v171. Needs CAM ver201 with o06 only
|
||||
// v200 rewrite reduces need for double reads of ESP32 slave CAM. Deleted ESP32CAP.
|
||||
// Inompatible with pre-v170 sensorCAM, unless set S06 to 0 and S07 to 1 (o06 & l07 say)
|
||||
/*
|
||||
* The IO_EXSensorCAM.h device driver can integrate with the sensorCAM device.
|
||||
* It is modelled on the IO_EXIOExpander.h device driver to include specific needs of the ESP32 sensorCAM
|
||||
* This device driver will configure the device on startup, along with CamParser.cpp
|
||||
* interacting with the sensorCAM device for all input/output duties.
|
||||
*
|
||||
* #include "CamParser.h" in DCCEXParser.cpp
|
||||
* #include "IO_EXSensorCAM.h" in IODevice.h
|
||||
* To create EX-SensorCAM devices, define them in myHal.cpp: with
|
||||
* EXSensorCAM::create(baseVpin,num_vpins,i2c_address) or
|
||||
♠ * alternatively use HAL(baseVpin,numpins,i2c_address) in myAutomation.h
|
||||
* also #define SENSORCAM_VPIN baseVpin in config.h
|
||||
*
|
||||
* void halSetup() {
|
||||
* // EXSensorCAM::create(vpin, num_vpins, i2c_address);
|
||||
* EXSensorCAM::create(700, 80, 0x11);
|
||||
* }
|
||||
*
|
||||
* I2C packet size of 32 bytes (in the Wire library).
|
||||
*/
|
||||
# define DIGITALREFRESH 20000UL // min uSec delay between digital reads of digitalInputStates
|
||||
#ifndef IO_EX_EXSENSORCAM_H
|
||||
#define IO_EX_EXSENSORCAM_H
|
||||
|
||||
#define Sp Serial.print
|
||||
|
||||
#include "IODevice.h"
|
||||
#include "I2CManager.h"
|
||||
#include "DIAG.h"
|
||||
#include "FSH.h"
|
||||
#include "CamParser.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
* IODevice subclass for EX-SensorCAM.
|
||||
*/
|
||||
class EXSensorCAM : public IODevice {
|
||||
public:
|
||||
|
||||
static void create(VPIN vpin, int nPins, I2CAddress i2cAddress) {
|
||||
if (checkNoOverlap(vpin, nPins, i2cAddress))
|
||||
new EXSensorCAM(vpin, nPins, i2cAddress);
|
||||
}
|
||||
|
||||
static VPIN CAMBaseVpin;
|
||||
|
||||
private:
|
||||
// Constructor
|
||||
EXSensorCAM(VPIN firstVpin, int nPins, I2CAddress i2cAddress) {
|
||||
_firstVpin = firstVpin;
|
||||
// Number of pins cannot exceed 255 (1 byte) because of I2C message structure.
|
||||
if (nPins > 80) nPins = 80;
|
||||
_nPins = nPins;
|
||||
_I2CAddress = i2cAddress;
|
||||
addDevice(this);
|
||||
}
|
||||
//*************************
|
||||
|
||||
void _begin() {
|
||||
uint8_t status;
|
||||
// Initialise EX-SensorCAM device
|
||||
I2CManager.begin();
|
||||
if (!I2CManager.exists(_I2CAddress)) {
|
||||
DIAG(F("EX-SensorCAM I2C:%s device not found"), _I2CAddress.toString());
|
||||
_deviceState = DEVSTATE_FAILED;
|
||||
return;
|
||||
}else {
|
||||
uint8_t commandBuffer[4]={EXIOINIT,(uint8_t)_nPins,(uint8_t)(_firstVpin & 0xFF),(uint8_t)(_firstVpin>>8)};
|
||||
status = I2CManager.read(_I2CAddress,_inputBuf,sizeof(_inputBuf),commandBuffer,sizeof(commandBuffer));
|
||||
//EXIOINIT needed to trigger and send firstVpin to CAM
|
||||
|
||||
if (status == I2C_STATUS_OK) {
|
||||
// Attempt to get version, non-blocking results in poor placement of response. Can be blocking here!
|
||||
commandBuffer[0] = '^'; //new version code
|
||||
|
||||
status = I2CManager.read(_I2CAddress, _inputBuf, sizeof(_inputBuf), commandBuffer, 1);
|
||||
// for ESP32 CAM, read again for good immediate response version data
|
||||
status = I2CManager.read(_I2CAddress, _inputBuf, sizeof(_inputBuf), commandBuffer, 1);
|
||||
|
||||
if (status == I2C_STATUS_OK) {
|
||||
_majorVer= _inputBuf[1]/10;
|
||||
_minorVer= _inputBuf[1]%10;
|
||||
_patchVer= _inputBuf[2];
|
||||
DIAG(F("EX-SensorCAM device found, I2C:%s, Version v%d.%d.%d"),
|
||||
_I2CAddress.toString(),_majorVer, _minorVer,_patchVer);
|
||||
}
|
||||
}
|
||||
if (status != I2C_STATUS_OK)
|
||||
reportError(status);
|
||||
}
|
||||
}
|
||||
//*************************
|
||||
// Digital input pin configuration, used to enable on EX-IOExpander device and set pullups if requested.
|
||||
// Configuration isn't done frequently so we can use blocking I2C calls here, and so buffers can
|
||||
// be allocated from the stack to reduce RAM allocation.
|
||||
bool _configure(VPIN vpin, ConfigTypeEnum configType, int paramCount, int params[]) override {
|
||||
if(_verPrint) DIAG(F("_configure() driver IO_EXSensorCAM v0.%d.%d vpin: %d "), driverVer/100,driverVer%100,vpin);
|
||||
_verPrint=false; //only give driver versions once
|
||||
if (paramCount != 1) return false;
|
||||
return true; //at least confirm that CAM is (always) configured (no vpin check!)
|
||||
}
|
||||
//*************************
|
||||
// Analogue input pin configuration, used to enable an EX-IOExpander device.
|
||||
int _configureAnalogIn(VPIN vpin) override {
|
||||
DIAG(F("_configureAnalogIn() IO_EXSensorCAM vpin %d"),vpin);
|
||||
return true; // NOTE: use of EXRAIL IFGTE() etc use "analog" reads.
|
||||
}
|
||||
//*************************
|
||||
// Main loop, collect both digital and "analog" pin states continuously (faster sensor/input reads)
|
||||
void _loop(unsigned long currentMicros) override {
|
||||
if (_deviceState == DEVSTATE_FAILED) return;
|
||||
// Request block is used for "analogue" (cmd. data) and digital reads from the sensorCAM, which
|
||||
// are performed on a cyclic basis. Writes are performed synchronously as and when requested.
|
||||
if (_readState != RDS_IDLE) { //expecting a return packet
|
||||
if (_i2crb.isBusy()) return; // If I2C operation still in progress, return
|
||||
uint8_t status = _i2crb.status;
|
||||
if (status == I2C_STATUS_OK) { // If device request ok, read input data
|
||||
//apparently the above checks do not guarantee a good packet! error rate about 1 pkt per 1000
|
||||
//there should be a packet in _CAMresponseBuff[32]
|
||||
if ((_CAMresponseBuff[0] & 0x60) >= 0x60) { //Buff[0] seems to have ascii cmd header (bit6 high) (o06)
|
||||
int error = processIncomingPkt( _CAMresponseBuff, _CAMresponseBuff[0]); // '~' 'i' 'm' 'n' 't' etc
|
||||
if (error>0) DIAG(F("CAM packet header(0x%x) not recognised"),_CAMresponseBuff[0]);
|
||||
}else{ // Header not valid - typically replaced by bank 0 data! To avoid any bad response set S06 to 0
|
||||
// versions of sensorCAM.h after v300 should return header of '@'(0x40) (not 0xE6) followed by
|
||||
// digitalInputStates sensor state array
|
||||
}
|
||||
}else reportError(status, false); // report i2c eror but don't go offline.
|
||||
_readState = RDS_IDLE;
|
||||
}
|
||||
|
||||
// If we're not doing anything now, check to see if a new state table transfer, or for 't' repeat, is due.
|
||||
if (_readState == RDS_IDLE) { //check if time for digitalRefresh
|
||||
if ( currentMicros - _lastDigitalRead > _digitalRefresh) {
|
||||
// Issue new read request for digital states.
|
||||
|
||||
_readCommandBuffer[0] = '@'; //start new read of digitalInputStates Table // non-blocking read
|
||||
I2CManager.read(_I2CAddress,_CAMresponseBuff, 32,_readCommandBuffer, 1, &_i2crb);
|
||||
_lastDigitalRead = currentMicros;
|
||||
_readState = RDS_DIGITAL;
|
||||
|
||||
}else{ //slip in a repeat <NT n> if pending
|
||||
if (currentMicros - _lasttStateRead > _tStateRefresh) // Delay for "analog" command repetitions
|
||||
if (_savedCmd[2]>1) { //repeat a 't' command
|
||||
for (int i=0;i<7;i++) _readCommandBuffer[i] =_savedCmd[i];
|
||||
int errors = ioESP32(_I2CAddress, _CAMresponseBuff, 32, _readCommandBuffer, 7);
|
||||
_lasttStateRead = currentMicros;
|
||||
_savedCmd[2] -= 1; //decrement repeats
|
||||
if (errors==0) return;
|
||||
DIAG(F("ioESP32 error %d header 0x%x"),errors,_CAMresponseBuff[0]);
|
||||
_readState = RDS_TSTATE; //this should stop further cmd requests until packet read (or timeout)
|
||||
}
|
||||
} //end repeat 't'
|
||||
}
|
||||
}
|
||||
//*************************
|
||||
// Obtain the bank of 8 sensors as an "analog" value
|
||||
// can be used to track the position through a sequential sensor bank
|
||||
int _readAnalogue(VPIN vpin) override {
|
||||
if (_deviceState == DEVSTATE_FAILED) return 0;
|
||||
return _digitalInputStates[(vpin - _firstVpin) / 8];
|
||||
}
|
||||
//*************************
|
||||
// Obtain the correct digital sensor input value
|
||||
int _read(VPIN vpin) override {
|
||||
if (_deviceState == DEVSTATE_FAILED) return 0;
|
||||
int pin = vpin - _firstVpin;
|
||||
return bitRead(_digitalInputStates[pin / 8], pin % 8);
|
||||
}
|
||||
//*************************
|
||||
// Write digital value.
|
||||
void _write(VPIN vpin, int value) override {
|
||||
DIAG(F("**_write() vpin %d = %d"),vpin,value);
|
||||
return ;
|
||||
}
|
||||
//*************************
|
||||
// i2cAddr of ESP32 CAM
|
||||
// rBuff buffer for return packet
|
||||
// inbytes number of bytes to request from CAM
|
||||
// outBuff holds outbytes to be sent to CAM
|
||||
int ioESP32(uint8_t i2cAddr,uint8_t *rBuf,int inbytes,uint8_t *outBuff,int outbytes) {
|
||||
uint8_t status = _i2crb.status;
|
||||
|
||||
while( _i2crb.status != I2C_STATUS_OK){status = _i2crb.status;} //wait until bus free
|
||||
|
||||
status = I2CManager.read(i2cAddr, rBuf, inbytes, outBuff, outbytes);
|
||||
|
||||
if (status != I2C_STATUS_OK){
|
||||
DIAG(F("EX-SensorCAM I2C:%s Error:%d %S"), _I2CAddress.toString(), status, I2CManager.getErrorMessage(status));
|
||||
reportError(status); return status;
|
||||
}
|
||||
return 0; // 0 for no error != 0 for error number.
|
||||
}
|
||||
//*************************
|
||||
//function to interpret packet from sensorCAM.ino
|
||||
//i2cAddr to identify CAM# (if # >1)
|
||||
//rBuf contains packet of up to 32 bytes usually with (ascii) cmd header in rBuf[0]
|
||||
//sensorCmd command header byte from CAM (in rBuf[0]?)
|
||||
int processIncomingPkt(uint8_t *rBuf,uint8_t sensorCmd) {
|
||||
int k;
|
||||
int b;
|
||||
int x;
|
||||
// if (sensorCmd <= '~') DIAG(F("processIncomingPkt %c %d %d %d"),rBuf[0],rBuf[1],rBuf[2],rBuf[3]);
|
||||
switch (sensorCmd){
|
||||
case '`': //response to request for digitalInputStates[] table '@'=>'`'
|
||||
memcpy(_digitalInputStates, rBuf+1, digitalBytesNeeded);
|
||||
break;
|
||||
|
||||
case EXIORDY: //some commands give back acknowledgement only
|
||||
break;
|
||||
|
||||
case CAMERR: //cmd format error code from CAM
|
||||
DIAG(F("CAM cmd error 0xFE 0x%x"),rBuf[1]);
|
||||
break;
|
||||
|
||||
case '~': //information from '^' version request <N ve[r]>
|
||||
DIAG(F("EX-SensorCAM device found, I2C:%s,CAM Version v%d.%d.%d vpins %u-%u"),
|
||||
_I2CAddress.toString(), rBuf[1]/10, rBuf[1]%10, rBuf[2],(int) _firstVpin, (int) _firstVpin +_nPins-1);
|
||||
DIAG(F("IO_EXSensorCAM driver v0.%d.%d vpin: %d "), driverVer/100,driverVer%100,_firstVpin);
|
||||
break;
|
||||
|
||||
case 'i': //information from i%%
|
||||
k=256*rBuf[5]+rBuf[4];
|
||||
DIAG(F("(i%%%%[,$$]) Info: Sensor 0%o(%d) enabled:%d status:%d row=%d x=%d Twin=0%o pvtThreshold=%d A~%d")
|
||||
,rBuf[1],rBuf[1],rBuf[3],rBuf[2],rBuf[6],k,rBuf[7],rBuf[9],int(rBuf[8])*16);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
DIAG(F("(m$[,##]) Min/max: $ frames min2flip (trip) %d, maxSensors 0%o, minSensors 0%o, nLED %d,"
|
||||
" threshold %d, TWOIMAGE_MAXBS 0%o"),rBuf[1],rBuf[3],rBuf[2],rBuf[4],rBuf[5],rBuf[6]);
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
DIAG(F("(n$[,##]) Nominate: $ nLED %d, ## minSensors 0%o (maxSensors 0%o threshold %d)")
|
||||
,rBuf[4],rBuf[2],rBuf[3],rBuf[5]);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
DIAG(F("(f %%%%) frame header 'f' for 0%o - showing Quarter sample (1 row) only"), rBuf[1]);
|
||||
/*if(rBuf[2]==0)*/ { Sp("<n bsNo "); Sp(rBuf[1]/8);Sp("/");Sp(rBuf[1]%8);Sp("\n"); }
|
||||
Sp("<n row:"); Sp(rBuf[2]);Sp(" Ref bytes" );
|
||||
for(k=3;k<15;k++) { Sp(" "); Sp(rBuf[k]>>4,HEX); Sp(rBuf[k]&15,HEX); if(k%3==2)Sp(" "); }
|
||||
Sp(" latest grab ->");
|
||||
for(k=16;k<28;k++){ Sp(" "); Sp(rBuf[k]>>4,HEX); Sp(rBuf[k]&15,HEX); if(k%3==0)Sp(" "); }
|
||||
Sp(" n>\n");
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
b=rBuf[1]-2;
|
||||
if(b<4) { Sp("<n (p%%) Bank empty n>\n"); break; }
|
||||
Sp("<n (p%%) Bank:"); Sp((0x7F&rBuf[2])/8); Sp(" ");
|
||||
for (int j=2; j<b; j+=3) {
|
||||
if(0x7F&rBuf[j] < 8) Sp(" S[0"); else Sp(" S[");
|
||||
Sp(0x7F&rBuf[j],OCT);Sp("]: r=");Sp(rBuf[j+1]);Sp(" x=");Sp(rBuf[j+2] + 2*(rBuf[j] & 0x80));
|
||||
}
|
||||
Sp(" n>\n");
|
||||
break;
|
||||
|
||||
case 't': //threshold etc. from t## //bad pkt if 't' FF's
|
||||
if(rBuf[1]==0xFF) {Serial.println("<n bad CAM 't' packet: 74 FF n>");_savedCmd[2] +=1; return 0;}
|
||||
Sp("<n (t[##[,%%]]) Threshold:");Sp(rBuf[1]);Sp(" sensor S00:");Sp("-");k=rBuf[2]&0x7F;if(k>99)k=99;Sp(k);
|
||||
if(rBuf[2]>127) Sp("##* ");
|
||||
else{
|
||||
if(rBuf[2]>rBuf[1]) Sp("-?* ");
|
||||
else Sp("--* ");
|
||||
}
|
||||
for(int i=3;i<31;i+=2){
|
||||
uint8_t valu=rBuf[i]; //get bsn
|
||||
if(valu==80) break; //80 = end flag
|
||||
else{
|
||||
if((valu&0x7F)<8) Sp("0"); Sp(valu&0x7F,OCT);Sp(':');
|
||||
if(valu>=128) Sp("?-");
|
||||
else {if(rBuf[i+1]>=128) Sp("oo");else Sp("--");}
|
||||
valu=rBuf[i+1]; k=valu&0x7F;
|
||||
if(k>99) k=99; Sp(k);
|
||||
if(valu<128) Sp("--* "); else Sp("##* ");
|
||||
}
|
||||
}
|
||||
Serial.print(" >\n");
|
||||
break;
|
||||
|
||||
default: //header not a recognised cmd character
|
||||
DIAG(F("CAM packet header not valid (0x%x) (0x%x) (0x%x)"),rBuf[0],rBuf[1],rBuf[2]);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//*************************
|
||||
// Write (analogue) 8bit (command) values. Write the parameters to the sensorCAM
|
||||
void _writeAnalogue(VPIN vpin, int16_t param1, uint8_t camop, uint16_t param3) override {
|
||||
uint8_t outputBuffer[7];
|
||||
int errors=0;
|
||||
outputBuffer[0] = camop;
|
||||
int pin = vpin - _firstVpin;
|
||||
|
||||
if(camop >= 0x80) { //case "a" (4p) also (3p) e.g. <N 713 210 310>
|
||||
camop=param1; //put row (0-236) in expected place
|
||||
param1=param3; //put column in expected place
|
||||
outputBuffer[0] = 'A';
|
||||
pin = (pin/8)*10 + pin%8; //restore bsNo.
|
||||
}
|
||||
if (_deviceState == DEVSTATE_FAILED) return;
|
||||
|
||||
outputBuffer[1] = pin; //vpin => bsn
|
||||
outputBuffer[2] = param1 & 0xFF;
|
||||
outputBuffer[3] = param1 >> 8;
|
||||
outputBuffer[4] = camop; //command code
|
||||
outputBuffer[5] = param3 & 0xFF;
|
||||
outputBuffer[6] = param3 >> 8;
|
||||
|
||||
if(camop=='B'){ //then 'b'(b%) cmd - can totally deal with that here. (but can't do b%,# (brightSF))
|
||||
if(param1>97) return;
|
||||
if(param1>9) param1 = param1/10; //accept a bsNo
|
||||
uint8_t b=_digitalInputStates[param1];
|
||||
char str[] = "11111111";
|
||||
for (int i=0;i<8;i++) if(((b<<i)&0x80) == 0) str[i]='0';
|
||||
DIAG(F("(b $) Bank: %d occupancy status byte: 0x%x%x (sensors S%d7->0) %s"), param1,b>>4,b&15,param1,str );
|
||||
return;
|
||||
}
|
||||
if (outputBuffer[4]=='T') { //then 't' cmd
|
||||
if(param1<31) { //repeated calls if param < 31
|
||||
//for (int i=0;i<7;i++) _savedCmd[i]=outputBuffer[i];
|
||||
memcpy( _savedCmd, outputBuffer, 8);
|
||||
}else _savedCmd[2] = 0; //no repeats if ##>30
|
||||
}else _savedCmd[2] = 0; //no repeats unless 't'
|
||||
|
||||
_lasttStateRead = micros(); //don't repeat until _tStateRefresh mSec
|
||||
|
||||
errors = ioESP32(_I2CAddress, _CAMresponseBuff, 32 , outputBuffer, 7); //send to esp32-CAM
|
||||
if (errors==0) return;
|
||||
else { // if (_CAMresponseBuff[0] != EXIORDY) //can't be sure what is inBuff[0] !
|
||||
DIAG(F("ioESP32 i2c error %d header 0x%x"),errors,_CAMresponseBuff[0]);
|
||||
}
|
||||
}
|
||||
//*************************
|
||||
// Display device information and status.
|
||||
void _display() override {
|
||||
DIAG(F("EX-SensorCAM I2C:%s v%d.%d.%d Vpins %u-%u %S"),
|
||||
_I2CAddress.toString(), _majorVer, _minorVer, _patchVer,
|
||||
(int)_firstVpin, (int)_firstVpin+_nPins-1,
|
||||
_deviceState == DEVSTATE_FAILED ? F("OFFLINE") : F(""));
|
||||
}
|
||||
//*************************
|
||||
// Helper function for error handling
|
||||
void reportError(uint8_t status, bool fail=true) {
|
||||
DIAG(F("EX-SensorCAM I2C:%s Error:%d (%S)"), _I2CAddress.toString(),
|
||||
status, I2CManager.getErrorMessage(status));
|
||||
if (fail) _deviceState = DEVSTATE_FAILED;
|
||||
}
|
||||
//*************************
|
||||
uint8_t _numDigitalPins = 80;
|
||||
size_t digitalBytesNeeded=10;
|
||||
uint8_t _CAMresponseBuff[34];
|
||||
|
||||
uint8_t _majorVer = 0;
|
||||
uint8_t _minorVer = 0;
|
||||
uint8_t _patchVer = 0;
|
||||
|
||||
uint8_t _digitalInputStates[10];
|
||||
I2CRB _i2crb;
|
||||
uint8_t _inputBuf[12];
|
||||
byte _outputBuffer[8];
|
||||
|
||||
bool _verPrint=true;
|
||||
|
||||
uint8_t _readCommandBuffer[8];
|
||||
uint8_t _savedCmd[8]; //for repeat 't' command
|
||||
//uint8_t _digitalPinBytes = 10; // Size of allocated memory buffer (may be longer than needed)
|
||||
|
||||
enum {RDS_IDLE, RDS_DIGITAL, RDS_TSTATE}; // Read operation states
|
||||
uint8_t _readState = RDS_IDLE;
|
||||
//uint8_t cmdBuffer[7]={0,0,0,0,0,0,0};
|
||||
unsigned long _lastDigitalRead = 0;
|
||||
unsigned long _lasttStateRead = 0;
|
||||
unsigned long _digitalRefresh = DIGITALREFRESH; // Delay refreshing digital inputs for 10ms
|
||||
const unsigned long _tStateRefresh = 120000UL; // Delay refreshing repeat "tState" inputs
|
||||
|
||||
enum {
|
||||
EXIOINIT = 0xE0, // Flag to initialise setup procedure
|
||||
EXIORDY = 0xE1, // Flag we have completed setup procedure, also for EX-IO to ACK setup
|
||||
CAMERR = 0xFE
|
||||
};
|
||||
};
|
||||
#endif
|
622
config.example.h
622
config.example.h
|
@ -1,327 +1,295 @@
|
|||
/*
|
||||
* © 2022 Paul M. Antoine
|
||||
* © 2021 Neil McKechnie
|
||||
* © 2020-2023 Harald Barth
|
||||
* © 2020-2021 Fred Decker
|
||||
* © 2020-2021 Chris Harlow
|
||||
* © 2023 Nathan Kellenicki
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
The configuration file for DCC-EX Command Station
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// If you want to add your own motor driver definition(s), add them here
|
||||
// For example MY_SHIELD with display name "MINE":
|
||||
// (remove comment start and end marker if you want to edit and use that)
|
||||
/*
|
||||
#define MY_SHIELD F("MINE"), \
|
||||
new MotorDriver( 3, 12, UNUSED_PIN, 9, A0, 5.08, 3000, A4), \
|
||||
new MotorDriver(11, 13, UNUSED_PIN, 8, A1, 5.08, 1500, A5)
|
||||
*/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE: Before connecting these boards and selecting one in this software
|
||||
// check the quick install guides!!! Some of these boards require a voltage
|
||||
// generating resistor on the current sense pin of the device. Failure to select
|
||||
// the correct resistor could damage the sense pin on your Arduino or destroy
|
||||
// the device.
|
||||
//
|
||||
// DEFINE MOTOR_SHIELD_TYPE BELOW. THESE ARE EXAMPLES. FULL LIST IN MotorDrivers.h
|
||||
//
|
||||
// STANDARD_MOTOR_SHIELD : Arduino Motor shield Rev3 based on the L298 with 18V 2A per channel
|
||||
// POLOLU_MOTOR_SHIELD : Pololu MC33926 Motor Driver (not recommended for prog track)
|
||||
// FUNDUMOTO_SHIELD : Fundumoto Shield, no current sensing (not recommended, no short protection)
|
||||
// FIREBOX_MK1 : The Firebox MK1
|
||||
// FIREBOX_MK1S : The Firebox MK1S
|
||||
// IBT_2_WITH_ARDUINO : Arduino Motor Shield for PROG and IBT-2 for MAIN
|
||||
// EX8874_SHIELD : DCC-EX TI DRV8874 based motor shield
|
||||
// |
|
||||
// +-----------------------v
|
||||
//
|
||||
#define MOTOR_SHIELD_TYPE STANDARD_MOTOR_SHIELD
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// If you want to restrict the maximum current LOWER than what your
|
||||
// motor shield can provide, you can do that here. For example if you
|
||||
// have a motor shield that can provide 5A and your power supply can
|
||||
// only provide 2.5A then you should restict the maximum current to
|
||||
// 2.25A (90% of 2.5A) so that DCC-EX does shut off the track before
|
||||
// your PS does shut DCC-EX. MAX_CURRENT is in mA so for this example
|
||||
// it would be 2250, adjust the number according to your PS. If your
|
||||
// PS has a higher rating than your motor shield you do not need this.
|
||||
// You can use this as well if you are cautious and your trains do not
|
||||
// need full current.
|
||||
// #define MAX_CURRENT 2250
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The IP port to talk to a WIFI or Ethernet shield.
|
||||
//
|
||||
#define IP_PORT 2560
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// NOTE: Only supported on Arduino Mega
|
||||
// Set to false if you not even want it on the Arduino Mega
|
||||
//
|
||||
#define ENABLE_WIFI true
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DEFINE WiFi Parameters (only in effect if WIFI is on)
|
||||
//
|
||||
// If DONT_TOUCH_WIFI_CONF is set, all WIFI config will be done with
|
||||
// the <+> commands and this sketch will not change anything over
|
||||
// AT commands and the other WIFI_* defines below do not have any effect.
|
||||
//#define DONT_TOUCH_WIFI_CONF
|
||||
//
|
||||
// WIFI_SSID is the network name IF you want to use your existing home network.
|
||||
// Do NOT change this if you want to use the WiFi in Access Point (AP) mode.
|
||||
//
|
||||
// If you do NOT set the WIFI_SSID and do NOT set the WIFI_PASSWORD,
|
||||
// then the WiFi chip will first try to connect to the previously
|
||||
// configured network and if that fails fall back to Access Point mode.
|
||||
// The SSID of the AP will be automatically set to DCCEX_*.
|
||||
// If you DO set the WIFI_SSID then the WiFi chip will try to connect
|
||||
// to that (home) network in station (client) mode. If a WIFI_PASSWORD
|
||||
// is set (recommended), that password will be used for AP mode.
|
||||
// The AP mode password must be at least 8 characters long.
|
||||
//
|
||||
// Your SSID may not contain ``"'' (double quote, ASCII 0x22).
|
||||
#define WIFI_SSID "Your network name"
|
||||
//
|
||||
// WIFI_PASSWORD is the network password for your home network or if
|
||||
// you want to change the password from default AP mode password
|
||||
// to the AP password you want.
|
||||
// Your password may not contain ``"'' (double quote, ASCII 0x22).
|
||||
#define WIFI_PASSWORD "Your network passwd"
|
||||
//
|
||||
// WIFI_HOSTNAME: You probably don't need to change this
|
||||
#define WIFI_HOSTNAME "dccex"
|
||||
//
|
||||
// WIFI_CHANNEL: If the line "#define ENABLE_WIFI true" is uncommented,
|
||||
// WiFi will be enabled (Mega only). The default channel is set to "1" whether
|
||||
// this line exists or not. If you need to use an alternate channel (we recommend
|
||||
// using only 1,6, or 11) you may change it here.
|
||||
#define WIFI_CHANNEL 1
|
||||
//
|
||||
// WIFI_FORCE_AP: If you'd like to specify your own WIFI_SSID in AP mode, set this
|
||||
// true. Otherwise it is assumed that you'd like to connect to an existing network
|
||||
// with that SSID.
|
||||
#define WIFI_FORCE_AP false
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ENABLE_ETHERNET: Set to true if you have an Arduino Ethernet card (wired). This
|
||||
// is not for Wifi. You will then need the Arduino Ethernet library as well
|
||||
//
|
||||
//#define ENABLE_ETHERNET true
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DEFINE STATIC IP ADDRESS *OR* COMMENT OUT TO USE DHCP
|
||||
//
|
||||
//#define IP_ADDRESS { 192, 168, 1, 200 }
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DEFINE LCD SCREEN USAGE BY THE BASE STATION
|
||||
//
|
||||
// Note: This feature requires an I2C enabled LCD screen using a Hitachi HD44780
|
||||
// controller and a commonly available PCF8574 based I2C 'backpack'.
|
||||
// To enable, uncomment one of the #define lines below
|
||||
|
||||
// define LCD_DRIVER for I2C address 0x27, 16 cols, 2 rows
|
||||
// #define LCD_DRIVER 0x27,16,2
|
||||
|
||||
//OR define OLED_DRIVER width,height[,address] in pixels (address auto detected if not supplied)
|
||||
// 128x32 or 128x64 I2C SSD1306-based devices are supported.
|
||||
// Use 132,64 for a SH1106-based I2C device with a 128x64 display.
|
||||
// #define OLED_DRIVER 0x3c,128,32
|
||||
|
||||
// Define scroll mode as 0, 1 or 2
|
||||
// * #define SCROLLMODE 0 is scroll continuous (fill screen if poss),
|
||||
// * #define SCROLLMODE 1 is by page (alternate between pages),
|
||||
// * #define SCROLLMODE 2 is by row (move up 1 row at a time).
|
||||
#define SCROLLMODE 1
|
||||
|
||||
// In order to avoid wasting memory the current scroll buffer is limited
|
||||
// to 8 lines. Some users wishing to display additional information
|
||||
// such as TrackManager power states have requested additional rows aware
|
||||
// of the warning that this will take extra RAM. if you wish to include additional rows
|
||||
// uncomment the following #define and set the number of lines you need.
|
||||
//#define MAX_CHARACTER_ROWS 12
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// DISABLE EEPROM
|
||||
//
|
||||
// If you do not need the EEPROM at all, you can disable all the code that saves
|
||||
// data in the EEPROM. You might want to do that if you are in a Arduino UNO
|
||||
// and want to use the EXRAIL automation. Otherwise you do not have enough RAM
|
||||
// to do that. Of course, then none of the EEPROM related commands work.
|
||||
//
|
||||
// EEPROM does not work on ESP32. So on ESP32, EEPROM will always be disabled,
|
||||
// at least until it works.
|
||||
//
|
||||
// #define DISABLE_EEPROM
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// DISABLE PROG
|
||||
//
|
||||
// If you do not need programming capability, you can disable all programming related
|
||||
// commands. You might want to do that if you are using an Arduino UNO and still want
|
||||
// to use EXRAIL automation, as the Uno is lacking in RAM and Flash to run both.
|
||||
//
|
||||
// Note this disables all programming functionality, including EXRAIL.
|
||||
//
|
||||
// #define DISABLE_PROG
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// DISABLE / ENABLE VDPY
|
||||
//
|
||||
// The Virtual display "VDPY" feature is by default enabled everywhere
|
||||
// but on Uno and Nano. If you think you can fit it (for example
|
||||
// having disabled some of the features above) you can enable it with
|
||||
// ENABLE_VDPY. You can even disable it on all other CPUs with
|
||||
// DISABLE_VDPY
|
||||
//
|
||||
// #define DISABLE_VDPY
|
||||
// #define ENABLE_VDPY
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// DISABLE / ENABLE DIAG
|
||||
//
|
||||
// To diagose different errors, you can turn on differnet messages. This costs
|
||||
// program memory which we do not have enough on the Uno and Nano, so it is
|
||||
// by default DISABLED on those. If you think you can fit it (for example
|
||||
// having disabled some of the features above) you can enable it with
|
||||
// ENABLE_DIAG. You can even disable it on all other CPUs with
|
||||
// DISABLE_DIAG
|
||||
//
|
||||
// #define DISABLE_DIAG
|
||||
// #define ENABLE_DIAG
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// REDEFINE WHERE SHORT/LONG ADDR break is. According to NMRA the last short address
|
||||
// is 127 and the first long address is 128. There are manufacturers which have
|
||||
// another view. Lenz CS for example have considered addresses long from 100. If
|
||||
// you want to change to that mode, do
|
||||
//#define HIGHEST_SHORT_ADDR 99
|
||||
// If you want to run all your locos addressed long format, you could even do a
|
||||
//#define HIGHEST_SHORT_ADDR 0
|
||||
// We do not support to use the same address, for example 100(long) and 100(short)
|
||||
// at the same time, there must be a border.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// Some newer 32bit microcontrollers boot very quickly, so powering on I2C and other
|
||||
// peripheral devices at the same time may result in the CommandStation booting too
|
||||
// quickly to detect them.
|
||||
// To work around this, uncomment the STARTUP_DELAY line below and set a value in
|
||||
// milliseconds that works for your environment, default is 3000 (3 seconds).
|
||||
// #define STARTUP_DELAY 3000
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DEFINE TURNOUTS/ACCESSORIES FOLLOW NORM RCN-213
|
||||
//
|
||||
// According to norm RCN-213 a DCC packet with a 1 is closed/straight
|
||||
// and one with a 0 is thrown/diverging. In DCC++ Classic, and in previous
|
||||
// versions of DCC++EX, a turnout throw command was implemented in the packet as
|
||||
// '1' and a close command as '0'. The #define below makes the states
|
||||
// match with the norm. But we don't want to cause havoc on existent layouts,
|
||||
// so we define this only for new installations. If you don't want this,
|
||||
// don't add it to your config.h.
|
||||
//#define DCC_TURNOUTS_RCN_213
|
||||
|
||||
// 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 reverse 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
|
||||
//
|
||||
// HANDLING MULTIPLE SERIAL THROTTLES
|
||||
// The command station always operates with the default Serial port.
|
||||
// Diagnostics are only emitted on the default serial port and not broadcast.
|
||||
// Other serial throttles may be added to the Serial1, Serial2, Serial3, Serial4,
|
||||
// Serial5, and Serial6 ports which may or may not exist on your CPU. (Mega has 3,
|
||||
// SAMD/SAMC and STM32 have up to 6.)
|
||||
// To monitor a throttle on one or more serial ports, uncomment the defines below.
|
||||
// NOTE: do not define here the WiFi shield serial port or your wifi will not work.
|
||||
//
|
||||
//#define SERIAL1_COMMANDS
|
||||
//#define SERIAL2_COMMANDS
|
||||
//#define SERIAL3_COMMANDS
|
||||
//#define SERIAL4_COMMANDS
|
||||
//#define SERIAL5_COMMANDS
|
||||
//#define SERIAL6_COMMANDS
|
||||
//
|
||||
// BLUETOOTH SERIAL ON ESP32
|
||||
// On ESP32 you have the possibility to use the builtin BT serial to connect to
|
||||
// the CS.
|
||||
//
|
||||
// The CS shows up as a pairable BT Clasic device. Name is "DCCEX-hexnumber".
|
||||
// BT is as an additional serial port, debug messages are still sent over USB,
|
||||
// not BT serial.
|
||||
//
|
||||
// If you enable this there are some implications:
|
||||
// 1. WiFi will sleep more (as WiFi and BT share the radio. So WiFi performance
|
||||
// may suffer
|
||||
// 2. The app will be bigger that 1.2MB, so the default partition scheme will not
|
||||
// work any more. You need to choose a partition scheme with 2MB (or bigger).
|
||||
// For example "NO OTA (2MB APP, 2MB SPIFFS)" in the Arduino IDE.
|
||||
// 3. There is no securuity (PIN) implemented. Everyone in radio range can pair
|
||||
// with your CS.
|
||||
//
|
||||
//#define SERIAL_BT_COMMANDS
|
||||
|
||||
// BOOSTER PIN INPUT ON ESP32
|
||||
// On ESP32 you have the possibility to define a pin as booster input
|
||||
// Arduio pin D2 is GPIO 26 on ESPDuino32
|
||||
//
|
||||
//#define BOOSTER_INPUT 26
|
||||
|
||||
// SABERTOOTH
|
||||
//
|
||||
// This is a very special option and only useful if you happen to have a
|
||||
// sabertooth motor controller from dimension engineering configured to
|
||||
// take commands from and ESP32 via serial at 9600 baud from GPIO17 (TX)
|
||||
// and GPIO16 (RX, currently unused).
|
||||
// The number defined is the DCC address for which speed controls are sent
|
||||
// to the sabertooth controller _as_well_. Default: Undefined.
|
||||
//
|
||||
//#define SABERTOOTH 1
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
* © 2022 Paul M. Antoine
|
||||
* © 2021 Neil McKechnie
|
||||
* © 2020-2023 Harald Barth
|
||||
* © 2020-2021 Fred Decker
|
||||
* © 2020-2021 Chris Harlow
|
||||
* © 2023 Nathan Kellenicki
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
The configuration file for DCC-EX Command Station
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// If you want to add your own motor driver definition(s), add them here
|
||||
// For example MY_SHIELD with display name "MINE":
|
||||
// (remove comment start and end marker if you want to edit and use that)
|
||||
/*
|
||||
#define MY_SHIELD F("MINE"), \
|
||||
new MotorDriver( 3, 12, UNUSED_PIN, 9, A0, 5.08, 3000, A4), \
|
||||
new MotorDriver(11, 13, UNUSED_PIN, 8, A1, 5.08, 1500, A5)
|
||||
*/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE: Before connecting these boards and selecting one in this software
|
||||
// check the quick install guides!!! Some of these boards require a voltage
|
||||
// generating resistor on the current sense pin of the device. Failure to select
|
||||
// the correct resistor could damage the sense pin on your Arduino or destroy
|
||||
// the device.
|
||||
//
|
||||
// DEFINE MOTOR_SHIELD_TYPE BELOW. THESE ARE EXAMPLES. FULL LIST IN MotorDrivers.h
|
||||
//
|
||||
// STANDARD_MOTOR_SHIELD : Arduino Motor shield Rev3 based on the L298 with 18V 2A per channel
|
||||
// POLOLU_MOTOR_SHIELD : Pololu MC33926 Motor Driver (not recommended for prog track)
|
||||
// FUNDUMOTO_SHIELD : Fundumoto Shield, no current sensing (not recommended, no short protection)
|
||||
// FIREBOX_MK1 : The Firebox MK1
|
||||
// FIREBOX_MK1S : The Firebox MK1S
|
||||
// IBT_2_WITH_ARDUINO : Arduino Motor Shield for PROG and IBT-2 for MAIN
|
||||
// EX8874_SHIELD : DCC-EX TI DRV8874 based motor shield
|
||||
// |
|
||||
// +-----------------------v
|
||||
//
|
||||
#define MOTOR_SHIELD_TYPE STANDARD_MOTOR_SHIELD
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// If you want to restrict the maximum current LOWER than what your
|
||||
// motor shield can provide, you can do that here. For example if you
|
||||
// have a motor shield that can provide 5A and your power supply can
|
||||
// only provide 2.5A then you should restict the maximum current to
|
||||
// 2.25A (90% of 2.5A) so that DCC-EX does shut off the track before
|
||||
// your PS does shut DCC-EX. MAX_CURRENT is in mA so for this example
|
||||
// it would be 2250, adjust the number according to your PS. If your
|
||||
// PS has a higher rating than your motor shield you do not need this.
|
||||
// You can use this as well if you are cautious and your trains do not
|
||||
// need full current.
|
||||
// #define MAX_CURRENT 2250
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The IP port to talk to a WIFI or Ethernet shield.
|
||||
//
|
||||
#define IP_PORT 2560
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// NOTE: Only supported on Arduino Mega
|
||||
// Set to false if you not even want it on the Arduino Mega
|
||||
//
|
||||
#define ENABLE_WIFI false //true
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DEFINE WiFi Parameters (only in effect if WIFI is on)
|
||||
//
|
||||
// If DONT_TOUCH_WIFI_CONF is set, all WIFI config will be done with
|
||||
// the <+> commands and this sketch will not change anything over
|
||||
// AT commands and the other WIFI_* defines below do not have any effect.
|
||||
//#define DONT_TOUCH_WIFI_CONF
|
||||
//
|
||||
// WIFI_SSID is the network name IF you want to use your existing home network.
|
||||
// Do NOT change this if you want to use the WiFi in Access Point (AP) mode.
|
||||
//
|
||||
// If you do NOT set the WIFI_SSID and do NOT set the WIFI_PASSWORD,
|
||||
// then the WiFi chip will first try to connect to the previously
|
||||
// configured network and if that fails fall back to Access Point mode.
|
||||
// The SSID of the AP will be automatically set to DCCEX_*.
|
||||
// If you DO set the WIFI_SSID then the WiFi chip will try to connect
|
||||
// to that (home) network in station (client) mode. If a WIFI_PASSWORD
|
||||
// is set (recommended), that password will be used for AP mode.
|
||||
// The AP mode password must be at least 8 characters long.
|
||||
//
|
||||
// Your SSID may not contain ``"'' (double quote, ASCII 0x22).
|
||||
#define WIFI_SSID "Your network name"
|
||||
//
|
||||
// WIFI_PASSWORD is the network password for your home network or if
|
||||
// you want to change the password from default AP mode password
|
||||
// to the AP password you want.
|
||||
// Your password may not contain ``"'' (double quote, ASCII 0x22).
|
||||
#define WIFI_PASSWORD "Your network passwd"
|
||||
//
|
||||
// WIFI_HOSTNAME: You probably don't need to change this
|
||||
#define WIFI_HOSTNAME "dccex"
|
||||
//
|
||||
// WIFI_CHANNEL: If the line "#define ENABLE_WIFI true" is uncommented,
|
||||
// WiFi will be enabled (Mega only). The default channel is set to "1" whether
|
||||
// this line exists or not. If you need to use an alternate channel (we recommend
|
||||
// using only 1,6, or 11) you may change it here.
|
||||
#define WIFI_CHANNEL 1
|
||||
//
|
||||
// WIFI_FORCE_AP: If you'd like to specify your own WIFI_SSID in AP mode, set this
|
||||
// true. Otherwise it is assumed that you'd like to connect to an existing network
|
||||
// with that SSID.
|
||||
#define WIFI_FORCE_AP false
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ENABLE_ETHERNET: Set to true if you have an Arduino Ethernet card (wired). This
|
||||
// is not for Wifi. You will then need the Arduino Ethernet library as well
|
||||
//
|
||||
//#define ENABLE_ETHERNET true
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DEFINE STATIC IP ADDRESS *OR* COMMENT OUT TO USE DHCP
|
||||
//
|
||||
//#define IP_ADDRESS { 192, 168, 1, 200 }
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DEFINE LCD SCREEN USAGE BY THE BASE STATION
|
||||
//
|
||||
// Note: This feature requires an I2C enabled LCD screen using a Hitachi HD44780
|
||||
// controller and a commonly available PCF8574 based I2C 'backpack'.
|
||||
// To enable, uncomment one of the #define lines below
|
||||
|
||||
// define LCD_DRIVER for I2C address 0x27, 16 cols, 2 rows
|
||||
// #define LCD_DRIVER 0x27,16,2
|
||||
|
||||
//OR define OLED_DRIVER width,height[,address] in pixels (address auto detected if not supplied)
|
||||
// 128x32 or 128x64 I2C SSD1306-based devices are supported.
|
||||
// Use 132,64 for a SH1106-based I2C device with a 128x64 display.
|
||||
// #define OLED_DRIVER 0x3c,128,32
|
||||
|
||||
// Define scroll mode as 0, 1 or 2
|
||||
// * #define SCROLLMODE 0 is scroll continuous (fill screen if poss),
|
||||
// * #define SCROLLMODE 1 is by page (alternate between pages),
|
||||
// * #define SCROLLMODE 2 is by row (move up 1 row at a time).
|
||||
#define SCROLLMODE 1
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// DISABLE EEPROM
|
||||
//
|
||||
// If you do not need the EEPROM at all, you can disable all the code that saves
|
||||
// data in the EEPROM. You might want to do that if you are in a Arduino UNO
|
||||
// and want to use the EXRAIL automation. Otherwise you do not have enough RAM
|
||||
// to do that. Of course, then none of the EEPROM related commands work.
|
||||
//
|
||||
// EEPROM does not work on ESP32. So on ESP32, EEPROM will always be disabled,
|
||||
// at least until it works.
|
||||
//
|
||||
// #define DISABLE_EEPROM
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// DISABLE PROG
|
||||
//
|
||||
// If you do not need programming capability, you can disable all programming related
|
||||
// commands. You might want to do that if you are using an Arduino UNO and still want
|
||||
// to use EXRAIL automation, as the Uno is lacking in RAM and Flash to run both.
|
||||
//
|
||||
// Note this disables all programming functionality, including EXRAIL.
|
||||
//
|
||||
// #define DISABLE_PROG
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// REDEFINE WHERE SHORT/LONG ADDR break is. According to NMRA the last short address
|
||||
// is 127 and the first long address is 128. There are manufacturers which have
|
||||
// another view. Lenz CS for example have considered addresses long from 100. If
|
||||
// you want to change to that mode, do
|
||||
//#define HIGHEST_SHORT_ADDR 99
|
||||
// If you want to run all your locos addressed long format, you could even do a
|
||||
//#define HIGHEST_SHORT_ADDR 0
|
||||
// We do not support to use the same address, for example 100(long) and 100(short)
|
||||
// at the same time, there must be a border.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DEFINE TURNOUTS/ACCESSORIES FOLLOW NORM RCN-213
|
||||
//
|
||||
// According to norm RCN-213 a DCC packet with a 1 is closed/straight
|
||||
// and one with a 0 is thrown/diverging. In DCC++ Classic, and in previous
|
||||
// versions of DCC++EX, a turnout throw command was implemented in the packet as
|
||||
// '1' and a close command as '0'. The #define below makes the states
|
||||
// match with the norm. But we don't want to cause havoc on existent layouts,
|
||||
// so we define this only for new installations. If you don't want this,
|
||||
// don't add it to your config.h.
|
||||
//#define DCC_TURNOUTS_RCN_213
|
||||
|
||||
// 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 reverse 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
|
||||
//
|
||||
// HANDLING MULTIPLE SERIAL THROTTLES
|
||||
// The command station always operates with the default Serial port.
|
||||
// Diagnostics are only emitted on the default serial port and not broadcast.
|
||||
// Other serial throttles may be added to the Serial1, Serial2, Serial3, Serial4,
|
||||
// Serial5, and Serial6 ports which may or may not exist on your CPU. (Mega has 3,
|
||||
// SAMD/SAMC and STM32 have up to 6.)
|
||||
// To monitor a throttle on one or more serial ports, uncomment the defines below.
|
||||
// NOTE: do not define here the WiFi shield serial port or your wifi will not work.
|
||||
//
|
||||
//#define SERIAL1_COMMANDS
|
||||
//#define SERIAL2_COMMANDS
|
||||
//#define SERIAL3_COMMANDS
|
||||
//#define SERIAL4_COMMANDS
|
||||
//#define SERIAL5_COMMANDS
|
||||
//#define SERIAL6_COMMANDS
|
||||
//
|
||||
// BLUETOOTH SERIAL ON ESP32
|
||||
// On ESP32 you have the possibility to use the builtin BT serial to connect to
|
||||
// the CS.
|
||||
//
|
||||
// The CS shows up as a pairable BT Clasic device. Name is "DCCEX-hexnumber".
|
||||
// BT is as an additional serial port, debug messages are still sent over USB,
|
||||
// not BT serial.
|
||||
//
|
||||
// If you enable this there are some implications:
|
||||
// 1. WiFi will sleep more (as WiFi and BT share the radio. So WiFi performance
|
||||
// may suffer
|
||||
// 2. The app will be bigger that 1.2MB, so the default partition scheme will not
|
||||
// work any more. You need to choose a partition scheme with 2MB (or bigger).
|
||||
// For example "NO OTA (2MB APP, 2MB SPIFFS)" in the Arduino IDE.
|
||||
// 3. There is no securuity (PIN) implemented. Everyone in radio range can pair
|
||||
// with your CS.
|
||||
//
|
||||
//#define SERIAL_BT_COMMANDS
|
||||
|
||||
// SABERTOOTH
|
||||
//
|
||||
// This is a very special option and only useful if you happen to have a
|
||||
// sabertooth motor controller from dimension engineering configured to
|
||||
// take commands from and ESP32 via serial at 9600 baud from GPIO17 (TX)
|
||||
// and GPIO16 (RX, currently unused).
|
||||
// The number defined is the DCC address for which speed controls are sent
|
||||
// to the sabertooth controller _as_well_. Default: Undefined.
|
||||
//
|
||||
//#define SABERTOOTH 1
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SENSORCAM
|
||||
// ESP32-CAM based video sensors require #define to use appropriate base vpin number.
|
||||
#define SENSORCAM_VPIN 700
|
||||
// For shortcut to vPin number, define CAM for ex-rail use e.g. AT(CAM 012) for S12 etc.
|
||||
#define CAM SENSORCAM_VPIN+
|
||||
|
||||
//#define SENSORCAM2_VPIN 600 //define other CAM's if installed.
|
||||
//#define CAM2 SENSORCAM2_VPIN+ //for EX-RAIL commands e.g. IFLT(CAM2 020,1)1
|
||||
//
|
||||
// For smoother power-up, define a STARTUP_DELAY to allow CAM to initialise ref images
|
||||
#define STARTUP_DELAY 5000 // up to 20sec. CS delay
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
362
myHal.cpp
Normal file
362
myHal.cpp
Normal file
|
@ -0,0 +1,362 @@
|
|||
// 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.
|
||||
//
|
||||
|
||||
// The #if directive prevent compile errors for Uno and Nano by excluding the
|
||||
// HAL directives from the build.
|
||||
#if !defined(IO_NO_HAL)
|
||||
|
||||
// Include devices you need.
|
||||
#include "IODevice.h"
|
||||
//#include "IO_HALDisplay.h" // Auxiliary display devices (LCD/OLED)
|
||||
//#include "IO_HCSR04.h" // Ultrasonic range sensor
|
||||
//#include "IO_VL53L0X.h" // Laser time-of-flight sensor
|
||||
//#include "IO_DFPlayer.h" // MP3 sound player
|
||||
//#include "IO_TouchKeypad.h // Touch keypad with 16 keys
|
||||
//#include "IO_EXTurntable.h" // Turntable-EX turntable controller
|
||||
//#include "IO_EXFastClock.h" // FastClock driver
|
||||
#include "IO_EXSensorCAM.h" // sensorCAM driver
|
||||
|
||||
//==========================================================================
|
||||
// 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() {
|
||||
|
||||
I2CManager.setClock(100000);
|
||||
|
||||
//=======================================================================
|
||||
// The following directives define auxiliary display devices.
|
||||
// These can be defined in addition to the system display (display
|
||||
// number 0) that is defined in config.h.
|
||||
// A write to a line which is beyond the length of the screen will overwrite
|
||||
// the bottom line, unless the line number is 255 in which case the
|
||||
// screen contents will scroll up before the text is written to the
|
||||
// bottom line.
|
||||
//=======================================================================
|
||||
//
|
||||
// Create a 128x32 OLED display device as display number 1
|
||||
// (line 0 is written by EX-RAIL 'SCREEN(1, 0, "text")').
|
||||
|
||||
//HALDisplay<OLED>::create(1, 0x3d, 128, 32);
|
||||
|
||||
// Create a 20x4 LCD display device as display number 2
|
||||
// (line 0 is written by EX-RAIL 'SCREEN(2, 0, "text")').
|
||||
|
||||
// HALDisplay<LiquidCrystal>(2, 0x27, 20, 4);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// User Add-ins
|
||||
//=======================================================================
|
||||
// User add-ins can be created when you want to do something that
|
||||
// can't be done in EX-RAIL but does not merit a HAL driver. The
|
||||
// user add-in is a C++ function that is executed periodically by the
|
||||
// HAL subsystem.
|
||||
|
||||
// Example: The function will be executed once per second and will display,
|
||||
// on screen #3, the first eight entries (assuming an 8-line display)
|
||||
// from the loco speed table.
|
||||
|
||||
// Put the following block of code in myHal.cpp OUTSIDE of the
|
||||
// halSetup() function:
|
||||
//
|
||||
// void updateLocoScreen() {
|
||||
// for (int i=0; i<8; i++) {
|
||||
// if (DCC::speedTable[i].loco > 0) {
|
||||
// int speed = DCC::speedTable[i].speedCode;
|
||||
// char direction = (speed & 0x80) ? 'R' : 'F';
|
||||
// speed = speed & 0x7f;
|
||||
// if (speed > 0) speed = speed - 1;
|
||||
// SCREEN(3, i, F("Loco:%4d %3d %c"), DCC::speedTable[i].loco,
|
||||
// speed, direction);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Put the following line INSIDE the halSetup() function:
|
||||
//
|
||||
// UserAddin::create(updateLocoScreen, 1000);
|
||||
//
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// 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 a PCF8575 16-port I2C GPIO Extender module.
|
||||
//=======================================================================
|
||||
// The parameters are:
|
||||
// First Vpin=200
|
||||
// Number of VPINs=16 (numbered 200-215)
|
||||
// I2C address of module=0x23
|
||||
|
||||
//PCF8575::create(200, 16, 0x23);
|
||||
|
||||
|
||||
// Alternative form using INT pin (see above)
|
||||
|
||||
//PCF8575::create(200, 16, 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. ANOUT(10000,23,0,0) will play the 23rd mp3 file.
|
||||
// ANOUT(10000,23,30,0) 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. ANOUT(10001,30,0,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);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 16-pad capacitative touch key pad based on TP229 IC.
|
||||
//=======================================================================
|
||||
// Parameters below:
|
||||
// 11000 = first VPIN allocated
|
||||
// 16 = number of VPINs allocated
|
||||
// 25 = local GPIO pin number for clock signal
|
||||
// 24 = local GPIO pin number for data signal
|
||||
//
|
||||
// Pressing the key pads numbered 1-16 cause each of the nominated digital VPINs
|
||||
// (11000-11015 in this case) to be activated.
|
||||
|
||||
// TouchKeypad::create(11000, 16, 25, 24);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines an EX-Turntable turntable instance.
|
||||
//=======================================================================
|
||||
// EXTurntable::create(VPIN, Number of VPINs, I2C Address)
|
||||
//
|
||||
// The parameters are:
|
||||
// VPIN=600
|
||||
// Number of VPINs=1 (Note there is no reason to change this)
|
||||
// I2C address=0x60
|
||||
//
|
||||
// Note that the I2C address is defined in the EX-Turntable code, and 0x60 is the default.
|
||||
|
||||
//EXTurntable::create(600, 1, 0x60);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines an EX-IOExpander instance.
|
||||
//=======================================================================
|
||||
// EXIOExpander::create(VPIN, Number of VPINs, I2C Address)
|
||||
//
|
||||
// The parameters are:
|
||||
// VPIN=an available Vpin
|
||||
// Number of VPINs=pin count (must match device in use as per documentation)
|
||||
// I2C address=an available I2C address (default 0x65)
|
||||
//
|
||||
// Note that the I2C address is defined in the EX-IOExpander code, and 0x65 is the default.
|
||||
// The example is for an Arduino Nano.
|
||||
|
||||
// EXIOExpander::create(800, 18, 0x65);
|
||||
|
||||
EXIOExpander::create(800, 18, 0x65); // NanoEXIOExpander::create(820, 18, 0x75); // Nano
|
||||
//EXSensorCAM::create(840, 18, 0x85); // Nano
|
||||
//EXIOExpander::create(880, 18, 0x95); // Nano
|
||||
//EXIOExpander::create(780, 18, 0xA5); // Nanoc
|
||||
//EXIOExpander::create(600, 18, 0xB5); // Nano
|
||||
//EXIOExpander::create(500, 18, 0xC5); // Nano
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines a rotary encoder instance.
|
||||
//=======================================================================
|
||||
// The parameters are:
|
||||
// firstVpin = First available Vpin to allocate
|
||||
// numPins= Number of Vpins to allocate, can be either 1 or 2
|
||||
// i2cAddress = Available I2C address (default 0x70)
|
||||
|
||||
//RotaryEncoder::create(firstVpin, numPins, i2cAddress);
|
||||
//RotaryEncoder::create(700, 1, 0x70);
|
||||
//RotaryEncoder::create(701, 2, 0x71);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines an EX-FastClock instance.
|
||||
//=======================================================================
|
||||
// EXFastCLock::create(I2C Address)
|
||||
//
|
||||
// The parameters are:
|
||||
//
|
||||
// I2C address=0x55 (decimal 85)
|
||||
//
|
||||
// Note that the I2C address is defined in the EX-FastClock code, and 0x55 is the default.
|
||||
|
||||
|
||||
// EXFastClock::create(0x55);
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines an ESP32-CAM instance.
|
||||
//=======================================================================
|
||||
// EXSensorCAM::create(VPIN, Number of VPINs, I2C Address)
|
||||
//
|
||||
// The parameters are:
|
||||
// VPIN=an available Vpin as start of block of consecutive sensors (up to 80)
|
||||
// #define SENSORCAM_VPIN0 #00 in config.h if not using 700.
|
||||
// Number of VPINs=pin count (must not exceed 80)
|
||||
// I2C address=an available I2C address (default 0x11)
|
||||
// #define ESP32CAP 0x13 in config.h to raise allowable ESP32 range of addresses
|
||||
// Note that the I2C address (0x11) is the default in the sensorCAM code
|
||||
//
|
||||
// EXSensorCAM::create(700, 80, 0x11);
|
||||
EXSensorCAM::create(700, 80, 0x11); //preference is now to use HAL(700 80 0x11) in myAutomation.h
|
||||
//EXSensorCAM::create(600, 80, 0x12); //alternate or second CAM device address creation
|
||||
}
|
||||
|
||||
#endif
|
|
@ -26,6 +26,7 @@
|
|||
//#include "IO_EXFastClock.h" // FastClock driver
|
||||
//#include "IO_PCA9555.h" // 16-bit I/O expander (NXP & Texas Instruments).
|
||||
//#include "IO_I2CDFPlayer.h" // DFPlayer over I2C
|
||||
#include "IO_EXSensorCAM.h" // sensorCAM driver
|
||||
|
||||
//==========================================================================
|
||||
// The function halSetup() is invoked from CS if it exists within the build.
|
||||
|
@ -35,6 +36,8 @@
|
|||
|
||||
void halSetup() {
|
||||
|
||||
//I2CManager.setClock(100000);
|
||||
|
||||
//=======================================================================
|
||||
// The following directives define auxiliary display devices.
|
||||
// These can be defined in addition to the system display (display
|
||||
|
@ -303,7 +306,14 @@ void halSetup() {
|
|||
// Note that the I2C address is defined in the EX-IOExpander code, and 0x65 is the default.
|
||||
// The example is for an Arduino Nano.
|
||||
|
||||
|
||||
|
||||
//EXIOExpander::create(800, 18, 0x65);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//=======================================================================
|
||||
|
@ -332,7 +342,23 @@ void halSetup() {
|
|||
|
||||
|
||||
// EXFastClock::create(0x55);
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// The following directive defines an ESP32-CAM instance.
|
||||
//=======================================================================
|
||||
// EXSensorCAM::create(VPIN, Number of VPINs, I2C Address)
|
||||
//
|
||||
// The parameters are:
|
||||
// VPIN=an available Vpin as start of block of consecutive sensors (up to 80)
|
||||
// #define SENSORCAM_VPIN0 #00 in config.h if not using 700.
|
||||
// Number of VPINs=pin count (must not exceed 80)
|
||||
// I2C address=an available I2C address (default 0x11)
|
||||
// #define ESP32CAP 0x13 in config.h to raise allowable ESP32 range of addresses
|
||||
// Note that the I2C address (0x11) is the default in the sensorCAM code
|
||||
//
|
||||
// EXSensorCAM::create(700, 80, 0x11);
|
||||
EXSensorCAM::create(700, 80, 0x11); //preference is now to use HAL(700 80 0x11) in myAutomation.h
|
||||
//EXSensorCAM::create(600, 80, 0x12); //alternate or second CAM device address creation
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
26
mySetup.h
Normal file
26
mySetup.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
// setup for sensorCAM on an ESP32-CAM NUMDigitalPins <= 80
|
||||
// assume 700 is first vpin (set with ...CREATE(700,80,0x11)
|
||||
// the optional SETUP operations below initiate jmri monitoring of sensors for any change of state
|
||||
// Mostly only useful during debug of initial system but load up CS with extra work. Use judiciously
|
||||
// id vPin
|
||||
SETUP("<Z 100 700 0>"); // set up for control OUTPUT on vpin #00
|
||||
// start of up to 80 sensors numbered bsNo's 100 to 197 (OCT) (0/0 to 9/7)
|
||||
SETUP("<S 100 700 0>"); // first sensor (S00) (reference)
|
||||
SETUP("<S 101 701 0>");
|
||||
SETUP("<S 102 702 0>");
|
||||
// as many as you want. You can add later manually with CS native commands
|
||||
SETUP("<S 107 707 0>");
|
||||
SETUP("<S 110 708 0>"); // Note: suggested id is b/s format (~OCT); vpin is DEC.
|
||||
SETUP("<S 111 709 0>"); // myFilter.cpp REQUIRES this relationship for bsNo to vPin conversion
|
||||
SETUP("<S 112 710 0>");
|
||||
SETUP("<S 113 711 0>");
|
||||
SETUP("<S 114 712 0>");
|
||||
//etc. // can create a bulk set of sensors with c++ code so:
|
||||
//for(uint16_t b=2; b<=9;b++) for(uint16_t s=0;s<8;s++) Sensor::create(100+b*10+s,700+b*8+s,1);
|
||||
//SETUP("<S 120 716 0>");
|
||||
SETUP("<S 121 717 0>");
|
||||
SETUP("<S 122 718 0>");
|
||||
//SETUP("<S 123 719 0>");
|
||||
//
|
||||
SETUP("<S 181 765 0>");
|
||||
SETUP("<S 191 773 0>");
|
Loading…
Reference in New Issue
Block a user