diff --git a/CamParser.cpp b/CamParser.cpp
index 6ea26e5..a5b8227 100644
--- a/CamParser.cpp
+++ b/CamParser.cpp
@@ -1,31 +1,56 @@
+/*
+ * © 2023-2025, Barry Daniel
+ * © 2025 Chris Harlow
+ * All rights reserved.
+ *
+ * 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 .
+ */
-//sensorCAM parser.cpp version 3.03 Sep 2024
+//sensorCAM parser.cpp version 3.05 Jan 2025
+#include "DCCEXParser.h"
#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 ver=30177;
const int16_t ve =2899;
-VPIN EXSensorCAM::CAMBaseVpin = CAM_VPIN;
+// The CAMVPINS array will be filled by IO_EXSensorCam HAL drivers calling
+// the CamParser::addVpin() function.
+// The CAMBaseVpin is the one to be used when commands are given without a vpin.
+VPIN CamParser::CAMBaseVpin = 0; // no vpins yet known
+VPIN CamParser::CAMVPINS[] = {0,0,0,0}; // no vpins yet known
+int CamParser::vpcount=sizeof(CAMVPINS)/sizeof(CAMVPINS[0]);
+
+void CamParser::parse(Print * stream, byte & opcode, byte & paramCount, int16_t p[]) {
+ if (opcode!='N') return; // this is not for us.
+ if (parseN(stream,paramCount,p)) opcode=0; // we have consumed this
+ // If we fail, the caller will the =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);
+ if(p[1]>=100) CAMBaseVpin=p[1];
+ if(p[1]=100 && p[1]<400) { //limits to CAM# 1 to 3 for now
+ if(p[1]>=100 && p[1]<(vpcount*100)) { //limits to CAM# 1 to 3 for now
vpin=CAMVPINS[p[1]/100];
- EXSensorCAM::CAMBaseVpin=vpin;
+ 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 (CAMBaseVpin==0) return false; // no cam defined
// send UPPER case to sensorCAM to flag binary data from a DCCEX-CS parser
switch(paramCount) {
case 1: // produces '^'
- if((p[0] == ve) || (p[0] == ver) || (p[0] == 'V')) camop='^';
+ if((camop == 'V') || (p[0] == ve) || (p[0] == ver) ) camop='^';
if (STRCHR_P((const char *)F("EFGMQRVW^"),camop) == nullptr) return false;
if (camop=='Q') param3=10; // for activation state of all 10 banks of sensors
if (camop=='F') camop=']'; // for Reset/Finish webCAM.
break; // F Coded as ']' else conflicts with
case 2: //
- if (STRCHR_P((const char *)F("ABFILMNOPQRSTUV"),camop)==nullptr) return false;
+ if (STRCHR_P((const char *)F("ABFHILMNOPQRSTUV"),camop)==nullptr) return false;
param1=p[1];
break;
@@ -92,4 +117,23 @@ bool CamParser::parseN(Print * stream, byte paramCount, int16_t p[]) {
DIAG(F("CamParser: %d %c %d %d"),vpin,camop,param1,param3);
IODevice::writeAnalogue(vpin,param1,camop,param3);
return true;
+}
+
+void CamParser::addVpin(VPIN pin) {
+ // called by IO_EXSensorCam starting up a camera on a vpin
+ byte slot=255;
+ for (auto i=0;i.
+ */
+
+
#ifndef CamParser_H
#define CamParser_H
#include
@@ -5,7 +27,13 @@
class CamParser {
public:
- static bool parseN(Print * stream, byte paramCount, int16_t p[]);
+ static void parse(Print * stream, byte & opcode, byte & paramCount, int16_t p[]);
+ static void addVpin(VPIN pin);
+ private:
+ static bool parseN(Print * stream, byte paramCount, int16_t p[]);
+ static VPIN CAMBaseVpin;
+ static VPIN CAMVPINS[];
+ static int vpcount;
};
diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp
index 9a9a8a4..3174b5b 100644
--- a/DCCEXParser.cpp
+++ b/DCCEXParser.cpp
@@ -238,6 +238,7 @@ int16_t DCCEXParser::splitValues(int16_t result[MAX_COMMAND_PARAMS], byte *cmd,
extern __attribute__((weak)) void myFilter(Print * stream, byte & opcode, byte & paramCount, int16_t p[]);
FILTER_CALLBACK DCCEXParser::filterCallback = myFilter;
FILTER_CALLBACK DCCEXParser::filterRMFTCallback = 0;
+FILTER_CALLBACK DCCEXParser::filterCamParserCallback = 0;
AT_COMMAND_CALLBACK DCCEXParser::atCommandCallback = 0;
// deprecated
@@ -249,6 +250,10 @@ void DCCEXParser::setRMFTFilter(FILTER_CALLBACK filter)
{
filterRMFTCallback = filter;
}
+void DCCEXParser::setCamParserFilter(FILTER_CALLBACK filter)
+{
+ filterCamParserCallback = filter;
+}
void DCCEXParser::setAtCommandCallback(AT_COMMAND_CALLBACK callback)
{
atCommandCallback = callback;
@@ -304,6 +309,8 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
filterCallback(stream, opcode, params, p);
if (filterRMFTCallback && opcode!='\0')
filterRMFTCallback(stream, opcode, params, p);
+ if (filterCamParserCallback && opcode!='\0')
+ filterCamParserCallback(stream, opcode, params, p);
// Functions return from this switch if complete, break from switch implies error to send
switch (opcode)
@@ -898,15 +905,11 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
if (parseI(stream, params, p))
return;
break;
-#endif
-#ifndef IO_NO_HAL
- case 'N': // if not intercepted by EXRAIL
+ case 'N': // interface implemented in CamParser
+ break; // Will if not intercepted by filters
#ifndef DISABLE_VDPY
case '@': // JMRI saying "give me virtual LCD msgs"
diff --git a/DCCEXParser.h b/DCCEXParser.h
index 1ff8521..4c7553e 100644
--- a/DCCEXParser.h
+++ b/DCCEXParser.h
@@ -37,6 +37,7 @@ struct DCCEXParser
static void parseOne(Print * stream, byte * command, RingStream * ringStream);
static void setFilter(FILTER_CALLBACK filter);
static void setRMFTFilter(FILTER_CALLBACK filter);
+ static void setCamParserFilter(FILTER_CALLBACK filter);
static void setAtCommandCallback(AT_COMMAND_CALLBACK filter);
static const int MAX_COMMAND_PARAMS=10; // Must not exceed this
@@ -77,6 +78,7 @@ struct DCCEXParser
static void callback_Vbyte(int16_t result);
static FILTER_CALLBACK filterCallback;
static FILTER_CALLBACK filterRMFTCallback;
+ static FILTER_CALLBACK filterCamParserCallback;
static AT_COMMAND_CALLBACK atCommandCallback;
static bool funcmap(int16_t cab, byte value, byte fstart, byte fstop);
static void sendFlashList(Print * stream,const int16_t flashList[]);
diff --git a/IO_EXSensorCAM.h b/IO_EXSensorCAM.h
index f91248d..a8156eb 100644
--- a/IO_EXSensorCAM.h
+++ b/IO_EXSensorCAM.h
@@ -16,7 +16,10 @@
* You should have received a copy of the GNU General Public License
* along with CommandStation. If not, see .
*/
-#define driverVer 305
+#define driverVer 306
+// v306 Pass vpin to regeister it in CamParser.
+// Move base vpin to camparser.
+// No more need for config.h settings.
// v305 less debug & alpha ordered switch
// v304 static oldb0; t(##[,%%];
// v303 zipped with CS 5.2.76 and uploaded to repo (with debug)
@@ -35,23 +38,18 @@
* 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(EXSensorCAM 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);
- * }
+ * To create EX-SensorCAM devices,
+ * use HAL(EXSensorCAM, baseVpin, numpins, i2c_address) in myAutomation.h
+ * e.g.
+ * HAL(EXSensorCAM,700, 80, 0x11)
+ *
+ * or (deprecated) define them in myHal.cpp: with
+ * EXSensorCAM::create(baseVpin,num_vpins,i2c_address);
*
- * 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 DIGITALREFRESH 20000UL // min uSec delay between digital reads of digitalInputStates
#define SEND StringFormatter::send
#include "IODevice.h"
#include "I2CManager.h"
@@ -70,7 +68,7 @@ class EXSensorCAM : public IODevice {
new EXSensorCAM(vpin, nPins, i2cAddress);
}
- static VPIN CAMBaseVpin;
+
private:
// Constructor
@@ -81,6 +79,7 @@ class EXSensorCAM : public IODevice {
_nPins = nPins;
_I2CAddress = i2cAddress;
addDevice(this);
+ CamParser::addVpin(firstVpin);
}
//*************************
void _begin() {
diff --git a/version.h b/version.h
index 2ba389b..36c1338 100644
--- a/version.h
+++ b/version.h
@@ -3,7 +3,9 @@
#include "StringFormatter.h"
-#define VERSION "5.5.7"
+#define VERSION "5.5.8"
+// 5.5.8 - EXSensorCam clean up to match other filters and
+// - avoid need for config.h settings
// 5.5.7 - ESP32 bugfix packet buffer race (as 5.4.1)
// 5.5.6 - Fix ESP32 build bug caused by include reference loop
// 5.5.5 - Railcom implementation with IO_I2CRailcom driver