/*
* © 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.06 Jan 2025
#include "DCCEXParser.h"
#include "CamParser.h"
#include "FSH.h"
const int16_t ver=30177;
const int16_t ve =2899;
// 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}; // determines max # CAM's
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) CAMBaseVpin=p[1];
if(p[1]<=vpcount && p[1]>0) CAMBaseVpin=CAMVPINS[p[1]-1];
DIAG(F("CAM base Vpin: %c %d "),p[0],CAMBaseVpin);
return true;
}
if (camop<100) { //switch CAM# if p[1] dictates
if(p[1]>=100 && p[1]<=(vpcount*100+99)) { //limits to CAM# 1 to 4 for now
vpin=CAMVPINS[p[1]/100-1];
CAMBaseVpin=vpin;
DIAG(F("switching to CAM %d baseVpin:%d"),p[1]/100,vpin);
p[1]=p[1]%100; //strip off CAM #
}
}
if (CAMBaseVpin==0) {DIAG(F(""));
return false; // cam not defined
}
// send UPPER case to sensorCAM to flag binary data from a DCCEX-CS parser
switch(paramCount) {
case 1: // produces '^'
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("ABFHILMNOPQRSTUV"),camop)==nullptr) return false;
param1=p[1];
break;
case 3: // or
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;
camop=p[0];
param1 = p[1];
param3 = p[2];
break;
case 4: //
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;
}
void CamParser::addVpin(VPIN pin) {
// called by IO_EXSensorCam starting up a camera on a vpin
byte slot=255;
for (auto i=0;i