Reorganisation fichiers
This commit is contained in:
197
PacoMouseCYD/Platformio/Arduino.old/XPT2046.ino
Normal file
197
PacoMouseCYD/Platformio/Arduino.old/XPT2046.ino
Normal file
@@ -0,0 +1,197 @@
|
||||
/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
|
||||
Simple XPT2046 SPI/Bitbang interface for PacoMouseCYD
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "XPT2046.h"
|
||||
|
||||
|
||||
#define Z_THRESHOLD 300
|
||||
#define MSEC_THRESHOLD 4
|
||||
|
||||
XPT2046_TS::XPT2046_TS(uint8_t mosiPin, uint8_t misoPin, uint8_t clkPin, uint8_t csPin) :
|
||||
_mosiPin(mosiPin), _misoPin(misoPin), _clkPin(clkPin), _csPin(csPin) {
|
||||
cal = TouchCalibration{0, 4095, 0, 4095, 0}; // other initializations, if required
|
||||
_msraw = millis();
|
||||
#ifdef USE_XPT2046_SPI
|
||||
hspi = new SPIClass(HSPI); // XPT2046 connected to HSPI in CYD 2.4"
|
||||
hspi->begin();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void XPT2046_TS::begin(uint16_t width, uint16_t height) {
|
||||
pinMode(_csPin, OUTPUT);
|
||||
digitalWrite(_csPin, HIGH);
|
||||
#ifdef USE_XPT2046_BITBANG
|
||||
pinMode(_clkPin, OUTPUT); // init all pins in bitbang mode only (CYD 2.8")
|
||||
digitalWrite(_clkPin, LOW);
|
||||
pinMode(_mosiPin, OUTPUT);
|
||||
pinMode(_misoPin, INPUT);
|
||||
#endif
|
||||
_width = width;
|
||||
_height = height;
|
||||
}
|
||||
|
||||
|
||||
void XPT2046_TS::setCalibration(uint16_t xMin, uint16_t xMax, uint16_t yMin, uint16_t yMax) {
|
||||
cal.xMin = xMin;
|
||||
cal.xMax = xMax;
|
||||
cal.yMin = yMin;
|
||||
cal.yMax = yMax;
|
||||
}
|
||||
|
||||
|
||||
TouchCalibration XPT2046_TS::getCalibration() {
|
||||
return cal;
|
||||
}
|
||||
|
||||
|
||||
void XPT2046_TS::setRotation(uint8_t n) {
|
||||
cal.rotation = n % 4;
|
||||
}
|
||||
|
||||
|
||||
bool XPT2046_TS::touched() {
|
||||
update();
|
||||
return (_zraw > Z_THRESHOLD);
|
||||
}
|
||||
|
||||
|
||||
TSPoint XPT2046_TS::getTouch() {
|
||||
update();
|
||||
uint16_t x = map(_xraw, cal.xMin, cal.xMax, 0, _width);
|
||||
uint16_t y = map(_yraw, cal.yMin, cal.yMax, 0, _height);
|
||||
if ((x >= _width) || (x <= 0) || (y >= _height) || (y <= 0))
|
||||
_zraw = 0;
|
||||
return TSPoint{x, y, _zraw};
|
||||
}
|
||||
|
||||
|
||||
void XPT2046_TS::readData(uint16_t *x, uint16_t *y, uint16_t *z) {
|
||||
update();
|
||||
*x = _xraw; // read raw data
|
||||
*y = _yraw;
|
||||
*z = _zraw;
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_XPT2046_BITBANG
|
||||
uint16_t XPT2046_TS::readSPI(byte command) {
|
||||
uint16_t result = 0;
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
digitalWrite(_mosiPin, command & (1 << i)); // send command
|
||||
digitalWrite(_clkPin, HIGH);
|
||||
delayMicroseconds(7);
|
||||
digitalWrite(_clkPin, LOW);
|
||||
delayMicroseconds(7);
|
||||
}
|
||||
for (int i = 11; i >= 0; i--) { // read data
|
||||
digitalWrite(_clkPin, HIGH);
|
||||
delayMicroseconds(7);
|
||||
digitalWrite(_clkPin, LOW);
|
||||
delayMicroseconds(7);
|
||||
result |= (digitalRead(_misoPin) << i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void XPT2046_TS::update() {
|
||||
int t;
|
||||
uint32_t now = millis();
|
||||
if (now - _msraw < MSEC_THRESHOLD)
|
||||
return;
|
||||
digitalWrite(_csPin, LOW);
|
||||
readSPI(0xB0);
|
||||
readSPI(0xB0);
|
||||
readSPI(0xB0);
|
||||
int z1 = readSPI(0xB0);
|
||||
_zraw = z1 + 4095;
|
||||
readSPI(0xC0);
|
||||
readSPI(0xC0);
|
||||
readSPI(0xC0);
|
||||
int z2 = readSPI(0xC0);
|
||||
_zraw -= z2;
|
||||
readSPI(0x90);
|
||||
readSPI(0x90);
|
||||
readSPI(0x90);
|
||||
_xraw = readSPI(0x90);
|
||||
readSPI(0xD0);
|
||||
readSPI(0xD0);
|
||||
readSPI(0xD0);
|
||||
_yraw = readSPI(0xD0);
|
||||
digitalWrite(_csPin, HIGH);
|
||||
_msraw = now;
|
||||
switch (cal.rotation) {
|
||||
case 0:
|
||||
t = 4095 - _yraw;
|
||||
_yraw = _xraw;
|
||||
_xraw = t;
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
t = _xraw;
|
||||
_xraw = _yraw;
|
||||
_yraw = 4095 - t;
|
||||
break;
|
||||
default:
|
||||
_xraw = 4095 - _xraw;
|
||||
_yraw = 4095 - _yraw;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_XPT2046_SPI
|
||||
void XPT2046_TS::update() {
|
||||
int t;
|
||||
uint32_t now = millis();
|
||||
if (now - _msraw < MSEC_THRESHOLD)
|
||||
return;
|
||||
hspi->beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(_csPin, LOW);
|
||||
hspi->transfer(0xB0);
|
||||
hspi->transfer16(0xB0);
|
||||
hspi->transfer16(0xB0);
|
||||
hspi->transfer16(0xB0);
|
||||
int z1 = hspi->transfer16(0xC0) >> 3;
|
||||
_zraw = z1 + 4095;
|
||||
hspi->transfer16(0xC0);
|
||||
hspi->transfer16(0xC0);
|
||||
hspi->transfer16(0xC0);
|
||||
int z2 = hspi->transfer16(0x90) >> 3;
|
||||
_zraw -= z2;
|
||||
hspi->transfer16(0x90);
|
||||
hspi->transfer16(0x90);
|
||||
hspi->transfer16(0x90);
|
||||
_xraw = hspi->transfer16(0xD0) >> 3;
|
||||
hspi->transfer16(0xD0);
|
||||
hspi->transfer16(0xD0);
|
||||
hspi->transfer16(0xD0);
|
||||
_yraw = hspi->transfer16(0x0) >> 3;
|
||||
digitalWrite(_csPin, HIGH);
|
||||
hspi->endTransaction();
|
||||
_msraw = now;
|
||||
switch (cal.rotation) {
|
||||
case 0:
|
||||
_xraw = 4095 - _xraw;
|
||||
break;
|
||||
case 1:
|
||||
t = _yraw;
|
||||
_yraw = _xraw;
|
||||
_xraw = t;
|
||||
break;
|
||||
case 2:
|
||||
_yraw = 4095 - _yraw;
|
||||
break;
|
||||
default:
|
||||
t = _yraw;
|
||||
_yraw = 4095 - _xraw;
|
||||
_xraw = 4095 - t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
411
PacoMouseCYD/Platformio/Arduino.old/accessories.ino
Normal file
411
PacoMouseCYD/Platformio/Arduino.old/accessories.ino
Normal file
@@ -0,0 +1,411 @@
|
||||
|
||||
/**
|
||||
* @file accessories.ino
|
||||
* @brief Accessory FIFO and control functions for PacoMouseCYD throttle.
|
||||
* @author F. Cañada
|
||||
* @date 2025-2026
|
||||
* @copyright https://usuaris.tinet.cat/fmco/
|
||||
*
|
||||
* This file contains functions to manage accessory commands using a FIFO buffer,
|
||||
* and to send accessory commands to the model train system.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// API Documentation
|
||||
////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* @brief Initializes the accessory FIFO buffer.
|
||||
*
|
||||
* Resets FIFO indices and state to empty.
|
||||
*/
|
||||
void initFIFO();
|
||||
|
||||
/**
|
||||
* @brief Reads the next accessory command from the FIFO.
|
||||
* @return The next accessory command in the FIFO.
|
||||
*/
|
||||
unsigned int readFIFO();
|
||||
|
||||
/**
|
||||
* @brief Writes an accessory command to the FIFO.
|
||||
* @param FAdr The accessory address.
|
||||
* @param pos The position or state to set.
|
||||
*/
|
||||
void writeFIFO(uint16_t FAdr, uint8_t pos);
|
||||
|
||||
/**
|
||||
* @brief Processes and sends accessory commands from the FIFO.
|
||||
*
|
||||
* Handles timing and state transitions for accessory activation and deactivation.
|
||||
*/
|
||||
void sendAccessoryFIFO();
|
||||
|
||||
/**
|
||||
* @brief Adds an accessory command to the FIFO for later execution.
|
||||
* @param FAdr The accessory address.
|
||||
* @param pos The position or state to set.
|
||||
*/
|
||||
void moveAccessory(uint16_t FAdr, uint8_t pos);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// End API Documentation
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** ACCESSORY FIFO *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void initFIFO() {
|
||||
lastInFIFO = 0;
|
||||
firstOutFIFO = 0;
|
||||
cntFIFO = 0;
|
||||
stateFIFO = FIFO_EMPTY;
|
||||
}
|
||||
|
||||
|
||||
unsigned int readFIFO () {
|
||||
firstOutFIFO = (firstOutFIFO + 1 ) & 0x1F; // next one (hardcoded)
|
||||
cntFIFO--;
|
||||
return (accessoryFIFO[firstOutFIFO]);
|
||||
}
|
||||
|
||||
|
||||
void writeFIFO (uint16_t FAdr, uint8_t pos) {
|
||||
lastInFIFO = (lastInFIFO + 1 ) & 0x1F; // next one (hardcoded)
|
||||
cntFIFO++;
|
||||
if (pos > 0)
|
||||
FAdr |= 0x8000;
|
||||
accessoryFIFO[lastInFIFO] = FAdr; // save in FIFO
|
||||
}
|
||||
|
||||
|
||||
void sendAccessoryFIFO () {
|
||||
switch (stateFIFO) {
|
||||
case FIFO_ACC_CDU: // wait for CDU recharge
|
||||
case FIFO_EMPTY:
|
||||
if (cntFIFO > 0) { // activate accessory from FIFO
|
||||
lastAccessory = readFIFO();
|
||||
sendAccessory(lastAccessory & 0x7FFF, bitRead(lastAccessory, 15), true);
|
||||
setTimer(TMR_ACCESSORY, TIME_ACC_ON, TMR_ONESHOT);
|
||||
stateFIFO = FIFO_ACC_ON;
|
||||
DEBUG_MSG("Moving acc. %d-%d", lastAccessory & 0x7FFF, lastAccessory >> 15);
|
||||
}
|
||||
else
|
||||
stateFIFO = FIFO_EMPTY;
|
||||
break;
|
||||
case FIFO_ACC_ON: // deactivate accessory
|
||||
sendAccessory(lastAccessory & 0x7FFF, bitRead(lastAccessory, 15), false);
|
||||
setTimer(TMR_ACCESSORY, TIME_ACC_CDU, TMR_ONESHOT);
|
||||
stateFIFO = FIFO_ACC_CDU;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** ACCESSORY *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void moveAccessory(uint16_t FAdr, uint8_t pos) {
|
||||
writeFIFO(FAdr, pos); // put accessory in FIFO
|
||||
if (stateFIFO == FIFO_EMPTY) // if not pending accessories, force sending now
|
||||
sendAccessoryFIFO();
|
||||
}
|
||||
|
||||
void setAccAspect(uint16_t FAdr, uint16_t FAdr2, uint8_t aspect, uint16_t outs) {
|
||||
uint8_t pos;
|
||||
pos = aspect * 4;
|
||||
if (FAdr > 0) {
|
||||
if (bitRead(outs, pos)) {
|
||||
moveAccessory(FAdr, 0);
|
||||
}
|
||||
else {
|
||||
if (bitRead(outs, pos + 1))
|
||||
moveAccessory(FAdr, 1);
|
||||
}
|
||||
}
|
||||
if (FAdr2 > 0) {
|
||||
if (bitRead(outs, pos + 2)) {
|
||||
moveAccessory(FAdr2, 0);
|
||||
}
|
||||
else {
|
||||
if (bitRead(outs, pos + 3))
|
||||
moveAccessory(FAdr2, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** PANEL *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void deleteAccPanelElement(uint8_t pos) {
|
||||
accPanel[pos].type = ACC_UNDEF;
|
||||
accPanel[pos].currAspect = 0;
|
||||
accPanel[pos].addr = 0;
|
||||
accPanel[pos].addr2 = 0;
|
||||
accPanel[pos].activeOutput = 0;
|
||||
accPanel[pos].accName[0] = '\0';
|
||||
}
|
||||
|
||||
void loadDefaultAccPanel() {
|
||||
uint8_t n;
|
||||
for (n = 0; n < 16; n++) { // Default panel is all blank with only a keypad button
|
||||
deleteAccPanelElement(n);
|
||||
}
|
||||
accPanel[15].type = ACC_KEYPAD;
|
||||
}
|
||||
|
||||
|
||||
void updateAccPanel() {
|
||||
uint8_t n, type, aspect;
|
||||
|
||||
snprintf(panelNameBuf, PANEL_LNG + 1, panelNamesBuf[currPanel]);
|
||||
for (n = 0; n < 16; n++) {
|
||||
type = accPanel[n].type;
|
||||
aspect = accPanel[n].currAspect;
|
||||
snprintf(accNamesBuf[n], ACC_LNG + 1, accPanel[n].accName);
|
||||
fncData[FNC_ACC0 + n].num = accDef[type].num;
|
||||
fncData[FNC_ACC0 + n].idIcon = accDef[type].icon[aspect].fncIcon;
|
||||
fncData[FNC_ACC0 + n].color = accDef[type].icon[aspect].color;
|
||||
fncData[FNC_ACC0 + n].colorOn = accDef[type].icon[aspect].colorOn;
|
||||
fncData[FNC_ACC0 + n].backgnd = (type == ACC_UNDEF) ? COLOR_WHITE : COLOR_LIGHTGREY;
|
||||
buttonData[BUT_ACC_0 + n].backgnd = (type == ACC_UNDEF) ? COLOR_WHITE : COLOR_LIGHTGREY;
|
||||
}
|
||||
}
|
||||
|
||||
void saveCurrentAspects() {
|
||||
uint8_t n;
|
||||
for (n = 0; n < 16; n++)
|
||||
savedAspect[currPanel][n] = accPanel[n].currAspect;
|
||||
}
|
||||
|
||||
void getLastAspects() {
|
||||
uint8_t n;
|
||||
for (n = 0; n < 16; n++)
|
||||
accPanel[n].currAspect = savedAspect[currPanel][n];
|
||||
}
|
||||
|
||||
void deleteLastAspects() {
|
||||
uint8_t n;
|
||||
for (n = 0; n < 16; n++)
|
||||
accPanel[n].currAspect = 0;
|
||||
}
|
||||
|
||||
void initLastAspects() {
|
||||
uint8_t i, j;
|
||||
for (i = 0; i < 16; i++)
|
||||
for (j = 0; j < 16; j++)
|
||||
savedAspect[i][j] = 0;;
|
||||
}
|
||||
|
||||
void populateAccPanel() {
|
||||
loadDefaultAccPanel(); // Load panel data
|
||||
if (sdDetected) {
|
||||
if (loadAccPanel(SD))
|
||||
getLastAspects();
|
||||
else
|
||||
deleteLastAspects();
|
||||
}
|
||||
else {
|
||||
if (loadAccPanel(LittleFS))
|
||||
getLastAspects();
|
||||
else
|
||||
deleteLastAspects();
|
||||
}
|
||||
updateAccPanel();
|
||||
}
|
||||
|
||||
void accPanelClick(uint8_t pos) {
|
||||
uint16_t addr, outs;
|
||||
uint8_t type, aspect;
|
||||
currPanelAcc = pos;
|
||||
if (editAccessory) {
|
||||
paramChild = pos;
|
||||
type = accPanel[pos].type;
|
||||
fncData[FNC_ACC_TYPE].num = accDef[type].num;
|
||||
fncData[FNC_ACC_TYPE].idIcon = accDef[type].icon[0].fncIcon;
|
||||
fncData[FNC_ACC_TYPE].color = accDef[type].icon[0].color;
|
||||
fncData[FNC_ACC_TYPE].colorOn = accDef[type].icon[0].colorOn;
|
||||
encoderValue = type;
|
||||
encoderMax = ACC_MAX - 1;
|
||||
openWindow(WIN_ACC_TYPE);
|
||||
}
|
||||
else {
|
||||
type = accPanel[pos].type;
|
||||
switch (type) {
|
||||
case ACC_UNDEF:
|
||||
break;
|
||||
case ACC_KEYPAD:
|
||||
openWindow(WIN_ACC_CTRL);
|
||||
break;
|
||||
default:
|
||||
addr = accPanel[pos].addr;
|
||||
outs = accPanel[pos].activeOutput;
|
||||
switch (accDef[type].aspects) {
|
||||
case 2:
|
||||
aspect = (accPanel[pos].currAspect > 0) ? 0 : 1;
|
||||
accPanel[pos].currAspect = aspect;
|
||||
fncData[FNC_ACC0 + pos].idIcon = accDef[type].icon[aspect].fncIcon;
|
||||
fncData[FNC_ACC0 + pos].color = accDef[type].icon[aspect].color;
|
||||
fncData[FNC_ACC0 + pos].colorOn = accDef[type].icon[aspect].colorOn;
|
||||
setAccAspect(addr, 0, aspect, outs);
|
||||
newEvent(OBJ_BUTTON, BUT_ACC_0 + pos, EVNT_DRAW);
|
||||
break;
|
||||
case 3:
|
||||
currAccAspects = 3;
|
||||
winData[WIN_ACC_ASPECT].x = 30;
|
||||
winData[WIN_ACC_ASPECT].w = 180;
|
||||
buttonData[BUT_ACC_ASPECT0].x = 50;
|
||||
buttonData[BUT_ACC_ASPECT1].x = 100;
|
||||
buttonData[BUT_ACC_ASPECT2].x = 150;
|
||||
fncData[FNC_ASPECT0].x = 54;
|
||||
fncData[FNC_ASPECT0].idIcon = accDef[type].icon[0].fncIcon;
|
||||
fncData[FNC_ASPECT0].color = accDef[type].icon[0].color;
|
||||
fncData[FNC_ASPECT0].colorOn = accDef[type].icon[0].colorOn;
|
||||
fncData[FNC_ASPECT1].x = 104;
|
||||
fncData[FNC_ASPECT1].idIcon = accDef[type].icon[1].fncIcon;
|
||||
fncData[FNC_ASPECT1].color = accDef[type].icon[1].color;
|
||||
fncData[FNC_ASPECT1].colorOn = accDef[type].icon[1].colorOn;
|
||||
fncData[FNC_ASPECT2].x = 154;
|
||||
fncData[FNC_ASPECT2].idIcon = accDef[type].icon[2].fncIcon;
|
||||
fncData[FNC_ASPECT2].color = accDef[type].icon[2].color;
|
||||
fncData[FNC_ASPECT2].colorOn = accDef[type].icon[2].colorOn;
|
||||
openWindow(WIN_ACC_ASPECT);
|
||||
break;
|
||||
case 4:
|
||||
currAccAspects = 4;
|
||||
winData[WIN_ACC_ASPECT].x = 5;
|
||||
winData[WIN_ACC_ASPECT].w = 230;
|
||||
buttonData[BUT_ACC_ASPECT0].x = 25;
|
||||
buttonData[BUT_ACC_ASPECT1].x = 75;
|
||||
buttonData[BUT_ACC_ASPECT2].x = 125;
|
||||
buttonData[BUT_ACC_ASPECT3].x = 175;
|
||||
fncData[FNC_ASPECT0].x = 29;
|
||||
fncData[FNC_ASPECT0].idIcon = accDef[type].icon[0].fncIcon;
|
||||
fncData[FNC_ASPECT0].color = accDef[type].icon[0].color;
|
||||
fncData[FNC_ASPECT0].colorOn = accDef[type].icon[0].colorOn;
|
||||
fncData[FNC_ASPECT1].x = 79;
|
||||
fncData[FNC_ASPECT1].idIcon = accDef[type].icon[1].fncIcon;
|
||||
fncData[FNC_ASPECT1].color = accDef[type].icon[1].color;
|
||||
fncData[FNC_ASPECT1].colorOn = accDef[type].icon[1].colorOn;
|
||||
fncData[FNC_ASPECT2].x = 129;
|
||||
fncData[FNC_ASPECT2].idIcon = accDef[type].icon[2].fncIcon;
|
||||
fncData[FNC_ASPECT2].color = accDef[type].icon[2].color;
|
||||
fncData[FNC_ASPECT2].colorOn = accDef[type].icon[2].colorOn;
|
||||
fncData[FNC_ASPECT3].x = 179;
|
||||
fncData[FNC_ASPECT3].idIcon = accDef[type].icon[3].fncIcon;
|
||||
fncData[FNC_ASPECT3].color = accDef[type].icon[3].color;
|
||||
fncData[FNC_ASPECT3].colorOn = accDef[type].icon[3].colorOn;
|
||||
openWindow(WIN_ACC_ASPECT);
|
||||
break;
|
||||
default:
|
||||
buttonData[BUT_ACC_0 + pos].backgnd = COLOR_BLACK;
|
||||
drawObject(OBJ_BUTTON, BUT_ACC_0 + pos);
|
||||
buttonData[BUT_ACC_0 + pos].backgnd = COLOR_LIGHTGREY;
|
||||
setAccAspect(addr, 0, 0, outs);
|
||||
newEvent(OBJ_BUTTON, BUT_ACC_0 + pos, EVNT_DRAW);
|
||||
delay(80);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void accAspectClick(uint8_t aspect) {
|
||||
uint16_t addr, addr2, outs;
|
||||
uint8_t type;
|
||||
type = accPanel[currPanelAcc].type;
|
||||
accPanel[currPanelAcc].currAspect = aspect;
|
||||
fncData[FNC_ACC0 + currPanelAcc].idIcon = accDef[type].icon[aspect].fncIcon;
|
||||
fncData[FNC_ACC0 + currPanelAcc].color = accDef[type].icon[aspect].color;
|
||||
fncData[FNC_ACC0 + currPanelAcc].colorOn = accDef[type].icon[aspect].colorOn;
|
||||
addr = accPanel[currPanelAcc].addr;
|
||||
addr2 = accPanel[currPanelAcc].addr2;
|
||||
outs = accPanel[currPanelAcc].activeOutput;
|
||||
setAccAspect(addr, addr2, aspect, outs);
|
||||
}
|
||||
|
||||
|
||||
void accTypeClick() {
|
||||
uint8_t index, n;
|
||||
index = encoderValue;
|
||||
switch (index) {
|
||||
case ACC_UNDEF:
|
||||
alertWindow(ERR_ASK_SURE);
|
||||
break;
|
||||
case ACC_KEYPAD:
|
||||
editAccessory = false;
|
||||
winData[WIN_ACCESSORY].backgnd = COLOR_WHITE;
|
||||
deleteAccPanelElement(paramChild);
|
||||
accPanel[paramChild].type = ACC_KEYPAD;
|
||||
updateAccPanel();
|
||||
updateSpeedHID(); // set encoder
|
||||
closeWindow(WIN_ACC_TYPE);
|
||||
break;
|
||||
default:
|
||||
if (index != accPanel[paramChild].type) {
|
||||
currAccEdit.type = (accType)index;
|
||||
currAccEdit.addr = 0;
|
||||
currAccEdit.addr2 = 0;
|
||||
currAccEdit.currAspect = 0;
|
||||
currAccEdit.activeOutput = accOutDefault[index];
|
||||
currAccEdit.accName[0] = '\0';
|
||||
}
|
||||
else {
|
||||
currAccEdit = accPanel[paramChild];
|
||||
}
|
||||
snprintf(accKeybName, ACC_LNG + 1, currAccEdit.accName);
|
||||
snprintf(accKeybAddr1, ADDR_LNG + 1, "%d", currAccEdit.addr);
|
||||
snprintf(accKeybAddr2, ADDR_LNG + 1, "%d", currAccEdit.addr2);
|
||||
for (n = 0; n < 4; n++) {
|
||||
fncData[FNC_EDIT_ASPECT0 + n].idIcon = accDef[index].icon[n].fncIcon;
|
||||
fncData[FNC_EDIT_ASPECT0 + n].color = accDef[index].icon[n].color;
|
||||
fncData[FNC_EDIT_ASPECT0 + n].colorOn = accDef[index].icon[n].colorOn;
|
||||
}
|
||||
accOutUpdate();
|
||||
closeWindow(WIN_ACC_TYPE);
|
||||
openWindow(WIN_ACC_EDIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void accOutUpdate() {
|
||||
uint8_t n;
|
||||
for (n = 0; n < 16; n += 2) {
|
||||
buttonData[BUT_ACC_OUT0 + n].backgnd = bitRead(currAccEdit.activeOutput, n) ? COLOR_RED : COLOR_LIGHTBLACK;
|
||||
buttonData[BUT_ACC_OUT0 + n + 1].backgnd = bitRead(currAccEdit.activeOutput, n + 1) ? COLOR_GREEN : COLOR_LIGHTBLACK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void accOutClick(uint8_t out) {
|
||||
uint8_t outR, outG;
|
||||
outR = out & 0xFE;
|
||||
outG = out | 0x01;
|
||||
currAccEdit.activeOutput ^= bit(out);
|
||||
if (bitRead(out, 0)) { // green
|
||||
if (bitRead(currAccEdit.activeOutput, outG))
|
||||
bitClear(currAccEdit.activeOutput, outR);
|
||||
}
|
||||
else { // red
|
||||
if (bitRead(currAccEdit.activeOutput, outR))
|
||||
bitClear(currAccEdit.activeOutput, outG);
|
||||
}
|
||||
accOutUpdate();
|
||||
newEvent(OBJ_BUTTON, BUT_ACC_OUT0 + outR, EVNT_DRAW);
|
||||
newEvent(OBJ_BUTTON, BUT_ACC_OUT0 + outG, EVNT_DRAW);
|
||||
}
|
||||
|
||||
|
||||
void updateAccChange() {
|
||||
accPanel[paramChild] = currAccEdit;
|
||||
updateAccPanel();
|
||||
accPanelChanged = true;
|
||||
}
|
||||
1012
PacoMouseCYD/Platformio/Arduino.old/ecos.ino
Normal file
1012
PacoMouseCYD/Platformio/Arduino.old/ecos.ino
Normal file
File diff suppressed because it is too large
Load Diff
238
PacoMouseCYD/Platformio/Arduino.old/encoder.ino
Normal file
238
PacoMouseCYD/Platformio/Arduino.old/encoder.ino
Normal file
@@ -0,0 +1,238 @@
|
||||
|
||||
/**
|
||||
* @file encoder.ino
|
||||
* @brief Rotary encoder and button handling for PacoMouseCYD throttle.
|
||||
* @author F. Cañada
|
||||
* @date 2025-2026
|
||||
* @copyright https://usuaris.tinet.cat/fmco/
|
||||
*
|
||||
* This file contains interrupt service routines and functions for reading and processing
|
||||
* rotary encoder and button input, including debouncing and value management.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// API Documentation
|
||||
////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* @brief Interrupt Service Routine for the encoder.
|
||||
*
|
||||
* Sets a flag indicating the encoder needs service.
|
||||
*/
|
||||
void IRAM_ATTR encoderISR();
|
||||
|
||||
/**
|
||||
* @brief Handles encoder state changes and updates encoder value.
|
||||
*/
|
||||
void encoderService();
|
||||
|
||||
/**
|
||||
* @brief Reads the encoder button and updates its state.
|
||||
*/
|
||||
void readButtons();
|
||||
|
||||
/**
|
||||
* @brief Processes encoder movement and updates UI or state accordingly.
|
||||
*/
|
||||
void controlEncoder();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// End API Documentation
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** ENCODER *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
IRAM_ATTR void encoderISR () { // Encoder interrupt
|
||||
encoderNeedService = true;
|
||||
}
|
||||
|
||||
|
||||
void encoderService () { // Encoder interrupt service
|
||||
encoderNeedService = false;
|
||||
lastTimeEncoder = millis();
|
||||
outA = digitalRead (ENCODER_A);
|
||||
outB = digitalRead (ENCODER_B);
|
||||
if (outA != copyOutA) { // evitamos rebotes
|
||||
copyOutA = outA;
|
||||
if (copyOutB == 0x80) {
|
||||
copyOutB = outB;
|
||||
}
|
||||
else {
|
||||
if ( outB != copyOutB) {
|
||||
copyOutB = 0x80;
|
||||
if (outA == outB) // comprueba sentido de giro
|
||||
encoderValue = (encoderValue < encoderMax) ? ++encoderValue : encoderMax ; // CW, hasta maximo
|
||||
else
|
||||
encoderValue = (encoderValue > 0) ? --encoderValue : 0; // CCW, hasta 0
|
||||
encoderChange = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void readButtons () {
|
||||
byte inputButton;
|
||||
|
||||
timeButtons = millis(); // lee cada cierto tiempo
|
||||
inputButton = digitalRead (ENCODER_SW); // comprueba cambio en boton del encoder
|
||||
if (statusSwitch != inputButton) {
|
||||
statusSwitch = inputButton;
|
||||
if (statusSwitch == LOW)
|
||||
switchOn = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void controlEncoder() { // encoder movement
|
||||
encoderChange = false;
|
||||
aliveAndKicking();
|
||||
DEBUG_MSG("Encoder: %d", encoderValue);
|
||||
switch (objStack[lastWinStack].objID) {
|
||||
case WIN_SSID:
|
||||
scrSSID = encoderValue;
|
||||
scanWiFiFill();
|
||||
drawObject(OBJ_TXT, TXT_SSID1);
|
||||
drawObject(OBJ_TXT, TXT_SSID2);
|
||||
drawObject(OBJ_TXT, TXT_SSID3);
|
||||
drawObject(OBJ_TXT, TXT_SSID4);
|
||||
drawObject(OBJ_TXT, TXT_SSID5);
|
||||
drawObject(OBJ_TXT, TXT_SSID6);
|
||||
break;
|
||||
case WIN_THROTTLE:
|
||||
case WIN_SPEEDO:
|
||||
case WIN_STA_PLAY:
|
||||
updateMySpeed();
|
||||
break;
|
||||
case WIN_CHG_FUNC:
|
||||
fncData[FNC_CHG].idIcon = encoderValue * 2;
|
||||
drawObject(OBJ_FNC, FNC_CHG);
|
||||
break;
|
||||
case WIN_SEL_LOCO:
|
||||
populateLocoList();
|
||||
drawObject(OBJ_TXT, TXT_SEL_ADDR1);
|
||||
drawObject(OBJ_TXT, TXT_SEL_NAME1);
|
||||
drawObject(OBJ_TXT, TXT_SEL_ADDR2);
|
||||
drawObject(OBJ_TXT, TXT_SEL_NAME2);
|
||||
drawObject(OBJ_TXT, TXT_SEL_ADDR3);
|
||||
drawObject(OBJ_TXT, TXT_SEL_NAME3);
|
||||
drawObject(OBJ_TXT, TXT_SEL_ADDR4);
|
||||
drawObject(OBJ_TXT, TXT_SEL_NAME4);
|
||||
drawObject(OBJ_TXT, TXT_SEL_ADDR5);
|
||||
drawObject(OBJ_TXT, TXT_SEL_NAME5);
|
||||
drawObject(OBJ_TXT, TXT_SEL_ADDR6);
|
||||
drawObject(OBJ_TXT, TXT_SEL_NAME6);
|
||||
break;
|
||||
case WIN_STEAM:
|
||||
showSpeedSteam((encoderValue << 1) + 240);
|
||||
break;
|
||||
case WIN_ACC_TYPE:
|
||||
fncData[FNC_ACC_TYPE].num = accDef[encoderValue].num;
|
||||
fncData[FNC_ACC_TYPE].idIcon = accDef[encoderValue].icon[0].fncIcon;
|
||||
fncData[FNC_ACC_TYPE].color = accDef[encoderValue].icon[0].color;
|
||||
fncData[FNC_ACC_TYPE].colorOn = accDef[encoderValue].icon[0].colorOn;
|
||||
drawObject(OBJ_FNC, FNC_ACC_TYPE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void controlSwitch() { // encoder switch
|
||||
uint16_t value, value2, txtID;
|
||||
uint32_t delta, dist;
|
||||
char msg[NAME_LNG + 1];
|
||||
switchOn = false;
|
||||
aliveAndKicking();
|
||||
DEBUG_MSG("Encoder Switch");
|
||||
switch (objStack[lastWinStack].objID) {
|
||||
case WIN_SSID:
|
||||
snprintf (wifiSetting.ssid, 32, WiFi.SSID(scrSSID).c_str()); //saveSSID(scrSSID);
|
||||
DEBUG_MSG("New SSID: %s", wifiSetting.ssid);
|
||||
eepromChanged = true;
|
||||
closeWindow(WIN_SSID);
|
||||
openWindow(WIN_WIFI);
|
||||
break;
|
||||
case WIN_THROTTLE:
|
||||
case WIN_STA_PLAY:
|
||||
if (encoderValue > 0) {
|
||||
encoderValue = 0;
|
||||
if (stopMode > 0)
|
||||
locoData[myLocoData].mySpeed = 1;
|
||||
else
|
||||
locoData[myLocoData].mySpeed = 0;
|
||||
locoOperationSpeed();
|
||||
}
|
||||
else {
|
||||
locoData[myLocoData].myDir ^= 0x80;
|
||||
changeDirection();
|
||||
}
|
||||
updateSpeedDir();
|
||||
break;
|
||||
case WIN_CHG_FUNC:
|
||||
fncData[FNC_F0 + paramChild].idIcon = fncData[FNC_CHG].idIcon;
|
||||
closeWindow(WIN_CHG_FUNC);
|
||||
break;
|
||||
case WIN_SEL_LOCO:
|
||||
releaseLoco();
|
||||
txtID = (encoderValue > 5) ? 5 : encoderValue;
|
||||
if (useID) {
|
||||
value2 = (encoderValue > 5) ? encoderValue - 5 : 0;
|
||||
value = sortedLocoStack[value2 + txtID];
|
||||
}
|
||||
else {
|
||||
value = atoi(txtData[TXT_SEL_ADDR1 + txtID].buf);
|
||||
}
|
||||
//value = atoi(txtData[TXT_SEL_ADDR1 + txtID].buf);
|
||||
DEBUG_MSG("Selected Loco %d", value);
|
||||
closeWindow(WIN_SEL_LOCO);
|
||||
getNewLoco(value);
|
||||
break;
|
||||
case WIN_SPEEDO:
|
||||
switch (speedoPhase) { //enum speedo {SPD_WAIT, SPD_BEGIN, SPD_COUNT, SPD_ARRIVE, SPD_END};
|
||||
case SPD_WAIT:
|
||||
if (getCurrentStep() > 0) {
|
||||
speedoStartTime = millis();
|
||||
setSpeedoPhase(SPD_BEGIN);
|
||||
getLabelTxt(LBL_MEASURE, msg);
|
||||
snprintf(spdSpeedBuf, NAME_LNG + 1, "%s", msg);
|
||||
drawObject(OBJ_TXT, TXT_SPEEDO_SPD);
|
||||
setTimer(TMR_SPEEDO, 5, TMR_ONESHOT);
|
||||
}
|
||||
else {
|
||||
locoData[myLocoData].myDir ^= 0x80;
|
||||
changeDirection();
|
||||
updateSpeedDir();
|
||||
}
|
||||
break;
|
||||
case SPD_BEGIN:
|
||||
case SPD_COUNT:
|
||||
speedoEndTime = millis();
|
||||
setSpeedoPhase(SPD_ARRIVE);
|
||||
setTimer(TMR_SPEEDO, 5, TMR_ONESHOT);
|
||||
dist = speedoLength * 36 * speedoScale;
|
||||
delta = (speedoEndTime - speedoStartTime) * 10;
|
||||
speedoSpeed = dist / delta;
|
||||
snprintf(spdSpeedBuf, NAME_LNG + 1, "%d km/h", speedoSpeed);
|
||||
drawObject(OBJ_TXT, TXT_SPEEDO_SPD);
|
||||
break;
|
||||
case SPD_ARRIVE:
|
||||
break;
|
||||
case SPD_END:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case WIN_STEAM:
|
||||
steamThrottleStop();
|
||||
currentSteamSpeed = 0;
|
||||
locoData[myLocoData].mySpeed = 0;
|
||||
locoOperationSpeed();
|
||||
break;
|
||||
case WIN_ACC_TYPE:
|
||||
accTypeClick();
|
||||
break;
|
||||
}
|
||||
}
|
||||
1615
PacoMouseCYD/Platformio/Arduino.old/events.ino
Normal file
1615
PacoMouseCYD/Platformio/Arduino.old/events.ino
Normal file
File diff suppressed because it is too large
Load Diff
417
PacoMouseCYD/Platformio/Arduino.old/file.ino
Normal file
417
PacoMouseCYD/Platformio/Arduino.old/file.ino
Normal file
@@ -0,0 +1,417 @@
|
||||
/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
|
||||
*/
|
||||
|
||||
|
||||
bool checkName(char *fileName) {
|
||||
bool result;
|
||||
uint16_t lng;
|
||||
result = false;
|
||||
lng = strlen(fileName);
|
||||
if (lng > 4) {
|
||||
if ((fileName[lng - 4] == '.') && (fileName[lng - 3] == 'c') && (fileName[lng - 2] == 's') && (fileName[lng - 1] == 'v'))
|
||||
return true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool saveLocoData(fs::FS &fs, uint16_t pos) { // save loco data in .csv file
|
||||
char field[30];
|
||||
uint16_t cnt;
|
||||
bool dataOK, isDir;
|
||||
File myFile;
|
||||
dataOK = false;
|
||||
myFile = fs.open("/loco");
|
||||
if (myFile) {
|
||||
isDir = myFile.isDirectory();
|
||||
myFile.close();
|
||||
if (!isDir)
|
||||
return dataOK;
|
||||
DEBUG_MSG("/loco is a directory");
|
||||
}
|
||||
else {
|
||||
DEBUG_MSG("Directory /loco not found. Creating...")
|
||||
fs.mkdir("/loco");
|
||||
}
|
||||
sprintf (field, "/loco/%d.csv", locoData[pos].myAddr.address);
|
||||
myFile = fs.open(field, FILE_WRITE);
|
||||
if (myFile) {
|
||||
DEBUG_MSG("File %s opened for writting", field);
|
||||
getLabelTxt(LBL_NAME, field); // Header
|
||||
myFile.print(field);
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
getLabelTxt(LBL_IMAGE, field);
|
||||
myFile.print(field);
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
getLabelTxt(LBL_VMAX, field);
|
||||
myFile.print(field);
|
||||
for (cnt = 0; cnt < 29; cnt++) {
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
myFile.print('F');
|
||||
myFile.print(cnt);
|
||||
}
|
||||
myFile.print("\r\n");
|
||||
myFile.print(locoData[pos].myName); // Loco data
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
myFile.print(locoData[pos].myLocoID);
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
myFile.print(locoData[pos].myVmax);
|
||||
for (cnt = 0; cnt < 29; cnt++) {
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
myFile.print(locoData[pos].myFuncIcon[cnt] >> 1);
|
||||
}
|
||||
myFile.print("\r\n");
|
||||
myFile.close();
|
||||
dataOK = true;
|
||||
}
|
||||
return dataOK;
|
||||
}
|
||||
|
||||
|
||||
void deleteLocoData (fs::FS &fs, uint16_t num)
|
||||
{
|
||||
char line[200];
|
||||
sprintf (line, "/loco/%d.csv", num);
|
||||
if (fs.remove(line)) {
|
||||
DEBUG_MSG("File %s deleted", line);
|
||||
}
|
||||
else {
|
||||
DEBUG_MSG("File %s delete failed", line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool readLocoData(fs::FS &fs, uint16_t num, uint16_t pos) { // read loco data from .csv file
|
||||
char line[200];
|
||||
bool dataOK;
|
||||
uint16_t n;
|
||||
File myFile;
|
||||
dataOK = false;
|
||||
sprintf (line, "/loco/%d.csv", num);
|
||||
myFile = fs.open(line);
|
||||
if (myFile) {
|
||||
if (readCSV(myFile, line, sizeof(line), false)) { // skip header line
|
||||
if (readCSV(myFile, locoData[pos].myName, sizeof(locoData[pos].myName), true)) { // read data field: Name
|
||||
if (readCSV(myFile, line, sizeof(line), true)) { // read data field: Picture
|
||||
locoData[pos].myLocoID = atoi(line);
|
||||
if (readCSV(myFile, line, sizeof(line), true)) {
|
||||
locoData[pos].myVmax = atoi(line);
|
||||
DEBUG_MSG("%d %s %d %d", num, locoData[pos].myName, locoData[pos].myLocoID, locoData[pos].myVmax)
|
||||
for (n = 0; n < 29; n++) {
|
||||
if (!readCSV(myFile, line, sizeof(line), true)) { // read data field: Functions
|
||||
myFile.close();
|
||||
return false;
|
||||
}
|
||||
locoData[pos].myFuncIcon[n] = (uint8_t)(atoi(line) << 1);
|
||||
//DEBUG_MSG("Func: %d - %d", n, locoData[pos].myFuncIcon[n])
|
||||
}
|
||||
locoData[pos].myAddr.address = num;
|
||||
dataOK = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
myFile.close();
|
||||
}
|
||||
return dataOK;
|
||||
}
|
||||
|
||||
|
||||
bool readCSV(File & f, char* line, uint16_t maxLen, bool getField) {
|
||||
uint16_t n; // read field or line from CSV file
|
||||
char chr;
|
||||
n = 0;
|
||||
yield();
|
||||
while (n < maxLen) {
|
||||
chr = f.read();
|
||||
switch (chr) {
|
||||
case 0:
|
||||
line[n] = '\0';
|
||||
return false; // EOF
|
||||
break;
|
||||
case '\r':
|
||||
line[n] = '\0';
|
||||
break;
|
||||
case '\n':
|
||||
line[n] = '\0';
|
||||
return true;
|
||||
break;
|
||||
case ',':
|
||||
case ';':
|
||||
if (getField) {
|
||||
line[n] = '\0';
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
line[n++] = chr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false; // too long
|
||||
}
|
||||
|
||||
|
||||
void loadLocoFiles(fs::FS &fs, const char * dirname) {
|
||||
uint16_t pos, adr;
|
||||
char nameFile[50];
|
||||
File myFile;
|
||||
if (wifiSetting.protocol == CLIENT_ECOS)
|
||||
return;
|
||||
File root = fs.open(dirname);
|
||||
if (!root) {
|
||||
//DEBUG_MSG("Failed to open directory %s", dirname);
|
||||
return;
|
||||
}
|
||||
if (!root.isDirectory()) {
|
||||
//DEBUG_MSG("%s Not a directory", dirname);
|
||||
return;
|
||||
}
|
||||
pos = 0;
|
||||
File file = root.openNextFile();
|
||||
while (file) {
|
||||
if (! file.isDirectory()) {
|
||||
if (pos < LOCOS_IN_STACK) {
|
||||
sprintf(nameFile, "%s", file.name());
|
||||
adr = atoi(nameFile);
|
||||
//DEBUG_MSG("%d %s", adr, nameFile);
|
||||
if (readLocoData(fs, adr, pos++))
|
||||
pushLoco(adr);
|
||||
}
|
||||
}
|
||||
file = root.openNextFile();
|
||||
}
|
||||
}
|
||||
|
||||
void initImageList() {
|
||||
uint16_t n, maxImg;
|
||||
uint16_t pos, id;
|
||||
char nameFile[50];
|
||||
File myFile;
|
||||
|
||||
for (n = 0; n < MAX_LOCO_IMAGE; n++) // add to list system images
|
||||
locoImages[n] = (n < (MAX_SYS_LPIC - 1)) ? n + 1 : 0;
|
||||
if (wifiSetting.protocol != CLIENT_ECOS) {
|
||||
if (sdDetected) { // add to list user images from SD
|
||||
File root = SD.open("/image");
|
||||
if (root) {
|
||||
if (root.isDirectory()) {
|
||||
pos = MAX_SYS_LPIC - 1;
|
||||
File file = root.openNextFile();
|
||||
while (file) {
|
||||
if (! file.isDirectory()) {
|
||||
if (pos < MAX_LOCO_IMAGE) {
|
||||
sprintf(nameFile, "%s", file.name());
|
||||
id = atoi(nameFile);
|
||||
if (id >= 1000) {
|
||||
locoImages[pos++] = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
file = root.openNextFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
locoImageIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
void populateImageList() {
|
||||
uint16_t n;
|
||||
for (n = 0; n < 6; n++)
|
||||
lpicData[LPIC_SEL_IMG1 + n].id = locoImages[locoImageIndex + n];
|
||||
}
|
||||
|
||||
|
||||
bool saveCurrAccPanel(fs::FS &fs) {
|
||||
char field[30];
|
||||
uint16_t cnt;
|
||||
bool dataOK, isDir;
|
||||
File myFile;
|
||||
dataOK = false;
|
||||
myFile = fs.open("/acc");
|
||||
if (myFile) {
|
||||
isDir = myFile.isDirectory();
|
||||
myFile.close();
|
||||
if (!isDir)
|
||||
return dataOK;
|
||||
DEBUG_MSG("/acc is a directory");
|
||||
}
|
||||
else {
|
||||
DEBUG_MSG("Directory /acc not found. Creating...")
|
||||
fs.mkdir("/acc");
|
||||
}
|
||||
sprintf (field, "/acc/%d.csv", currPanel);
|
||||
myFile = fs.open(field, FILE_WRITE);
|
||||
if (myFile) {
|
||||
DEBUG_MSG("File %s opened for writting", field);
|
||||
getLabelTxt(LBL_ACC_TYPE, field); // Header
|
||||
myFile.print(field);
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
getLabelTxt(LBL_ACC_ADDR, field);
|
||||
myFile.print(field);
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
getLabelTxt(LBL_ACC_ADDR, field);
|
||||
myFile.print(field);
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
getLabelTxt(LBL_ACC_NAME, field);
|
||||
myFile.print(field);
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
getLabelTxt(LBL_BITS, field);
|
||||
myFile.print(field);
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
myFile.print("\r\n");
|
||||
for (cnt = 0; cnt < 16; cnt++) {
|
||||
myFile.print(accPanel[cnt].type); // Acc data
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
myFile.print(accPanel[cnt].addr);
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
myFile.print(accPanel[cnt].addr2);
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
myFile.print(accPanel[cnt].accName);
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
myFile.print(accPanel[cnt].activeOutput);
|
||||
myFile.print(CSV_FILE_DELIMITER);
|
||||
myFile.print("\r\n");
|
||||
}
|
||||
myFile.close();
|
||||
dataOK = true;
|
||||
}
|
||||
return dataOK;
|
||||
}
|
||||
|
||||
|
||||
bool loadAccPanel(fs::FS & fs) {
|
||||
char line[200];
|
||||
bool dataOK;
|
||||
uint16_t cnt = 0;
|
||||
File myFile;
|
||||
dataOK = false;
|
||||
sprintf (line, "/acc/%d.csv", currPanel);
|
||||
myFile = fs.open(line);
|
||||
if (myFile) {
|
||||
if (readCSV(myFile, line, sizeof(line), false)) { // skip header line
|
||||
for (cnt = 0; cnt < 16; cnt++) {
|
||||
readCSV(myFile, line, sizeof(line), true);
|
||||
accPanel[cnt].type = (accType)atoi(line);
|
||||
readCSV(myFile, line, sizeof(line), true);
|
||||
accPanel[cnt].addr = atoi(line);
|
||||
readCSV(myFile, line, sizeof(line), true);
|
||||
accPanel[cnt].addr2 = atoi(line);
|
||||
readCSV(myFile, line, sizeof(line), true);
|
||||
snprintf(accPanel[cnt].accName, ACC_LNG + 1, line);
|
||||
readCSV(myFile, line, sizeof(line), false);
|
||||
accPanel[cnt].activeOutput = atoi(line);
|
||||
DEBUG_MSG("Line %d: %d, %d, %d, \"%s\", %d", cnt, accPanel[cnt].type, accPanel[cnt].addr, accPanel[cnt].addr2, accPanel[cnt].accName, accPanel[cnt].activeOutput)
|
||||
}
|
||||
}
|
||||
myFile.close();
|
||||
dataOK = true;
|
||||
}
|
||||
return dataOK;
|
||||
}
|
||||
|
||||
|
||||
bool saveAccPanelNames(fs::FS & fs) {
|
||||
char field[30];
|
||||
uint16_t cnt;
|
||||
bool dataOK, isDir;
|
||||
File myFile;
|
||||
dataOK = false;
|
||||
myFile = fs.open("/acc");
|
||||
if (myFile) {
|
||||
isDir = myFile.isDirectory();
|
||||
myFile.close();
|
||||
if (!isDir)
|
||||
return dataOK;
|
||||
DEBUG_MSG("/acc is a directory");
|
||||
}
|
||||
else {
|
||||
DEBUG_MSG("Directory /acc not found. Creating...")
|
||||
fs.mkdir("/acc");
|
||||
}
|
||||
sprintf (field, "/acc/panel.csv");
|
||||
myFile = fs.open(field, FILE_WRITE);
|
||||
if (myFile) {
|
||||
DEBUG_MSG("File %s opened for writting", field);
|
||||
getLabelTxt(LBL_NAME, field); // Header
|
||||
myFile.print(field);
|
||||
myFile.print("\r\n");
|
||||
for (cnt = 0; cnt < 16; cnt++) {
|
||||
myFile.print(panelNamesBuf[cnt]); // Panel names
|
||||
myFile.print("\r\n");
|
||||
}
|
||||
myFile.close();
|
||||
dataOK = true;
|
||||
}
|
||||
return dataOK;
|
||||
}
|
||||
|
||||
|
||||
bool loadAccPanelNames(fs::FS & fs) {
|
||||
char line[200];
|
||||
bool dataOK;
|
||||
uint16_t n;
|
||||
File myFile;
|
||||
dataOK = false;
|
||||
sprintf (line, "/acc/panel.csv");
|
||||
myFile = fs.open(line);
|
||||
if (myFile) {
|
||||
if (readCSV(myFile, line, sizeof(line), false)) { // skip header line
|
||||
for (n = 0; n < 16; n++) {
|
||||
if (readCSV(myFile, line, sizeof(line), true)) { // read data field
|
||||
snprintf(panelNamesBuf[n], PANEL_LNG + 1, line);
|
||||
DEBUG_MSG("%s", panelNamesBuf[n])
|
||||
}
|
||||
}
|
||||
}
|
||||
myFile.close();
|
||||
}
|
||||
else {
|
||||
for (n = 0; n < 16; n++) // default names
|
||||
snprintf(panelNamesBuf[n], PANEL_LNG + 1, "Panel %d", n);
|
||||
}
|
||||
return dataOK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
|
||||
Serial.printf("Listing directory: %s\n", dirname);
|
||||
|
||||
File root = fs.open(dirname);
|
||||
if (!root) {
|
||||
Serial.println("Failed to open directory");
|
||||
return;
|
||||
}
|
||||
if (!root.isDirectory()) {
|
||||
Serial.println("Not a directory");
|
||||
return;
|
||||
}
|
||||
|
||||
File file = root.openNextFile();
|
||||
while (file) {
|
||||
if (file.isDirectory()) {
|
||||
Serial.print(" DIR : ");
|
||||
Serial.println(file.name());
|
||||
if (levels) {
|
||||
listDir(fs, file.path(), levels - 1);
|
||||
}
|
||||
} else {
|
||||
Serial.print(" FILE: ");
|
||||
Serial.print(file.name());
|
||||
Serial.print(" SIZE: ");
|
||||
Serial.println(file.size());
|
||||
}
|
||||
file = root.openNextFile();
|
||||
}
|
||||
}
|
||||
*/
|
||||
1116
PacoMouseCYD/Platformio/Arduino.old/gui.ino
Normal file
1116
PacoMouseCYD/Platformio/Arduino.old/gui.ino
Normal file
File diff suppressed because it is too large
Load Diff
1260
PacoMouseCYD/Platformio/Arduino.old/lnet.ino
Normal file
1260
PacoMouseCYD/Platformio/Arduino.old/lnet.ino
Normal file
File diff suppressed because it is too large
Load Diff
1733
PacoMouseCYD/Platformio/Arduino.old/main.ino
Normal file
1733
PacoMouseCYD/Platformio/Arduino.old/main.ino
Normal file
File diff suppressed because it is too large
Load Diff
104
PacoMouseCYD/Platformio/Arduino.old/play.ino
Normal file
104
PacoMouseCYD/Platformio/Arduino.old/play.ino
Normal file
@@ -0,0 +1,104 @@
|
||||
/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** STATION RUN - MODEL TRAIN GAME FOR KIDS *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void updateStationTime (uint16_t seconds) {
|
||||
snprintf(staTimeBuf, ACC_LNG + 1, "%d:%02d", seconds / 60, seconds % 60);
|
||||
}
|
||||
|
||||
void updateStationTarget() {
|
||||
staStations = staLevel + 4;
|
||||
if (staStartTime < 10)
|
||||
staStartTime = 10;
|
||||
staTime = staStartTime + ((staLevel - 1) * 10);
|
||||
}
|
||||
|
||||
void newStationCounters (bool ini) {
|
||||
if (ini) {
|
||||
staStars = 0;
|
||||
staLevel = 1;
|
||||
randomSeed(millis());
|
||||
}
|
||||
staCurrStation = 0;
|
||||
updateStationTarget();
|
||||
}
|
||||
|
||||
uint8_t newStation(byte last) {
|
||||
uint8_t station; // genera numero estacion sin repetir la ultima
|
||||
do {
|
||||
station = random (0, staMaxStations);
|
||||
} while (station == last);
|
||||
return (station);
|
||||
}
|
||||
|
||||
void updateTargetStations() {
|
||||
snprintf(staStationsBuf, ACC_LNG + 1, "%d", staStations);
|
||||
}
|
||||
|
||||
void updateCountStations() {
|
||||
snprintf(staStationsBuf, ACC_LNG + 1, "%d/%d", staCurrStation, staStations);
|
||||
}
|
||||
|
||||
void updateStationLevel() {
|
||||
snprintf(staLevelBuf, ADDR_LNG + 1, "%d", staLevel);
|
||||
}
|
||||
|
||||
void updateStationStars() {
|
||||
snprintf(staStarsBuf, ADDR_LNG + 1, "%d", staStars);
|
||||
}
|
||||
|
||||
void setNewTarget() {
|
||||
uint16_t pos;
|
||||
staLastStation = newStation(staLastStation);
|
||||
iconData[ICON_STA_TARGET].color = staColors[staLastStation];
|
||||
pos = iconData[ICON_STA_TRAIN].x;
|
||||
iconData[ICON_STA_TRAIN].x = iconData[ICON_STA_TARGET].x;
|
||||
iconData[ICON_STA_TARGET].x = pos;
|
||||
iconData[ICON_STA_PIN].x = pos + 8;
|
||||
}
|
||||
|
||||
void clickTargetStation() {
|
||||
encoderValue = 0;
|
||||
locoData[myLocoData].mySpeed = 0;
|
||||
locoOperationSpeed();
|
||||
updateSpeedDir();
|
||||
staCurrStation++;
|
||||
if (staCurrStation == staStations) {
|
||||
stopTimer(TMR_STA_RUN);
|
||||
staLevel++;
|
||||
updateStationLevel();
|
||||
newStationCounters(false);
|
||||
updateTargetStations();
|
||||
updateStationTime(staTime);
|
||||
closeWindow(WIN_STA_PLAY);
|
||||
openWindow(WIN_STA_STARS); // well done!
|
||||
}
|
||||
else {
|
||||
updateCountStations();
|
||||
setNewTarget();
|
||||
newEvent(OBJ_WIN, WIN_STA_PLAY, EVNT_DRAW);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t staGetTurnoutAdr(uint16_t eeAdr, uint16_t defAdr) {
|
||||
uint16_t adr;
|
||||
adr = (EEPROM.read(eeAdr) << 8) + EEPROM.read(eeAdr + 1);
|
||||
if (adr > 2048)
|
||||
adr = defAdr;
|
||||
return adr;
|
||||
}
|
||||
|
||||
void updateTurnoutButtons() {
|
||||
uint16_t n, icon;
|
||||
for (n = 0; n < 4; n++) {
|
||||
if (staTurnoutPos[n])
|
||||
fncData[FNC_STA_ACC0 + n].idIcon = bitRead(staTurnoutDef, n) ? FNC_TURNRD_OFF : FNC_TURNLD_OFF;
|
||||
else
|
||||
fncData[FNC_STA_ACC0 + n].idIcon = bitRead(staTurnoutDef, n) ? FNC_TURNRS_OFF : FNC_TURNLS_OFF;
|
||||
fncData[FNC_STA_ACC0 + n].colorOn = staTurnoutPos[n] ? COLOR_RED : COLOR_GREEN;
|
||||
}
|
||||
}
|
||||
399
PacoMouseCYD/Platformio/Arduino.old/steam.ino
Normal file
399
PacoMouseCYD/Platformio/Arduino.old/steam.ino
Normal file
@@ -0,0 +1,399 @@
|
||||
/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** STEAM THROTTLE *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void initSteamThrottle () {
|
||||
uint16_t n;
|
||||
if (oldSteamLoco != locoData[myLocoData].myAddr.address) {
|
||||
oldSteamLoco = locoData[myLocoData].myAddr.address;
|
||||
steamPressure = 80;
|
||||
waterLevelBoiler = 80;
|
||||
waterLevelTender = 350;
|
||||
oldPressure = 0;
|
||||
oldLevelBoiler = 0;
|
||||
oldLevelTender = 0;
|
||||
barData[BAR_JOHNSON].value = STEAM_JOHNSON_NEUTRAL; // neutral position
|
||||
barData[BAR_BRAKE].value = 0;
|
||||
steamDir = locoData[myLocoData].myDir;
|
||||
for (n = 0; n < MAX_LIMIT; n++)
|
||||
steamSpeedLimit[n] = LIMIT_NONE;
|
||||
}
|
||||
currentSteamTime = millis();
|
||||
steamTimeSpeed = currentSteamTime;
|
||||
steamTimeSteam = currentSteamTime;
|
||||
steamTimeWater = currentSteamTime;
|
||||
steamTimeLoad = currentSteamTime;
|
||||
steamTimeSmoke = currentSteamTime;
|
||||
shovelCoal = false;
|
||||
setFirebox();
|
||||
endWaterInjection();
|
||||
endTenderFill();
|
||||
setTimer(TMR_STEAM, 5, TMR_ONESHOT);
|
||||
changeSmoke = STEAM_SMOKE_FAST;
|
||||
oldPressure = 0;
|
||||
oldSpeedSteam = 305;
|
||||
encoderMax = 31; // set throttle to current speed
|
||||
updateSteamThrottle();
|
||||
if (steamDir != locoData[myLocoData].myDir) { // check Johnson bar position
|
||||
steamDir = locoData[myLocoData].myDir;
|
||||
barData[BAR_JOHNSON].value = 6 - barData[BAR_JOHNSON].value;
|
||||
}
|
||||
}
|
||||
|
||||
void updateSteamThrottle() {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
case CLIENT_XNET:
|
||||
if (bitRead(locoData[myLocoData].mySteps, 2)) { // 0..127
|
||||
currentSteamSpeed = locoData[myLocoData].mySpeed;
|
||||
encoderValue = currentSteamSpeed >> 2;
|
||||
}
|
||||
else {
|
||||
if (bitRead(locoData[myLocoData].mySteps, 1)) { // 0..31
|
||||
encoderValue = (locoData[myLocoData].mySpeed & 0x0F) << 1;
|
||||
if (bitRead(locoData[myLocoData].mySpeed, 4))
|
||||
bitSet(encoderValue, 0);
|
||||
currentSteamSpeed = (encoderValue > 3) ? (encoderValue << 2) + (encoderValue >> 3) : 0;
|
||||
}
|
||||
else { // 0..15
|
||||
encoderValue = locoData[myLocoData].mySpeed & 0x0F;
|
||||
encoderValue = (encoderValue > 1) ? encoderValue << 1 : 0;
|
||||
currentSteamSpeed = (encoderValue << 2) + (encoderValue >> 3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
case CLIENT_ECOS:
|
||||
currentSteamSpeed = locoData[myLocoData].mySpeed;
|
||||
encoderValue = currentSteamSpeed >> 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void steamProcess() {
|
||||
uint16_t value, newSpeed, mappedThrottle, jFactor;
|
||||
|
||||
steamSpeedLimit[LIMIT_THROTTLE] = (encoderValue << 2) + (encoderValue >> 3); // Read Throtle Speed (0..31 -> 0..127)
|
||||
|
||||
steamSpeedLimit[LIMIT_JOHNSON] = LIMIT_NONE;
|
||||
switch (barData[BAR_JOHNSON].value) { // Read Johnson Bar
|
||||
case 0: // full reverse
|
||||
jFactor = 3;
|
||||
changeSpeed = 80;
|
||||
steamDir = 0x00;
|
||||
break;
|
||||
case 1:
|
||||
jFactor = 2;
|
||||
changeSpeed = 200;
|
||||
steamDir = 0x00;
|
||||
break;
|
||||
case 2:
|
||||
jFactor = 1;
|
||||
changeSpeed = 500;
|
||||
steamDir = 0x00;
|
||||
break;
|
||||
case STEAM_JOHNSON_NEUTRAL: // Neutral position of Johnson Bar
|
||||
jFactor = 1;
|
||||
changeSpeed = 1000;
|
||||
steamSpeedLimit[LIMIT_JOHNSON] = 0;
|
||||
break;
|
||||
case 4:
|
||||
jFactor = 1;
|
||||
changeSpeed = 500;
|
||||
steamDir = 0x80;
|
||||
break;
|
||||
case 5:
|
||||
jFactor = 2;
|
||||
changeSpeed = 200;
|
||||
steamDir = 0x80;
|
||||
break;
|
||||
case 6: // full forward
|
||||
jFactor = 3;
|
||||
changeSpeed = 80;
|
||||
steamDir = 0x80;
|
||||
break;
|
||||
}
|
||||
|
||||
if (steamDir != locoData[myLocoData].myDir) { // Check direction
|
||||
locoData[myLocoData].myDir = steamDir;
|
||||
changeDirection();
|
||||
DEBUG_MSG("STEAM: Change direction")
|
||||
}
|
||||
|
||||
value = steamSpeedLimit[LIMIT_THROTTLE];
|
||||
changeSteam = 10000 - ((value * 9) * jFactor); // Steam timeout: 6571 to 10000
|
||||
changeWater = 14000 - ((value * 27) * jFactor); // Water timeout: 3713 to 14000
|
||||
if (barData[BAR_BRAKE].value > 0) { // Brake bar: 300, 150, 100
|
||||
changeSpeed = 300 / barData[BAR_BRAKE].value;
|
||||
}
|
||||
currentSteamTime = millis();
|
||||
|
||||
if (currentSteamTime > (steamTimeWater + changeWater)) { // Water consumption
|
||||
steamTimeWater = currentSteamTime;
|
||||
if (waterLevelBoiler > 0) {
|
||||
waterLevelBoiler--;
|
||||
DEBUG_MSG("Boiler Level: %d", waterLevelBoiler)
|
||||
}
|
||||
}
|
||||
if (waterLevelBoiler < 10) { // Stop loco if not enough water
|
||||
steamSpeedLimit[LIMIT_WATER] = 0;
|
||||
steamThrottleStop();
|
||||
}
|
||||
else {
|
||||
steamSpeedLimit[LIMIT_WATER] = LIMIT_NONE;
|
||||
}
|
||||
|
||||
if (currentSteamTime > (steamTimeSteam + changeSteam)) { // Steam consumption
|
||||
steamTimeSteam = currentSteamTime;
|
||||
if (steamPressure > 0)
|
||||
steamPressure--;
|
||||
}
|
||||
|
||||
if (steamPressure < 50) { // Limit speed based on steam level
|
||||
value = (steamPressure < 20) ? 0 : map(steamPressure, 20, 50, 20, 120);
|
||||
steamSpeedLimit[LIMIT_PRESSURE] = value;
|
||||
}
|
||||
else {
|
||||
steamSpeedLimit[LIMIT_PRESSURE] = LIMIT_NONE;
|
||||
}
|
||||
|
||||
if (currentSteamTime > (steamTimeLoad + STEAM_LOAD_TIME)) { // Load coal and water
|
||||
steamTimeLoad = currentSteamTime;
|
||||
if (shovelCoal) { // Fire open for shoveling coal
|
||||
if (steamPressure > 96) {
|
||||
shovelCoal = false;
|
||||
setFirebox();
|
||||
newEvent(OBJ_FNC, FNC_ST_FIRE, EVNT_DRAW);
|
||||
}
|
||||
else {
|
||||
if (steamPressure < 20) // slowly pressure up at beginning
|
||||
steamPressure += 1;
|
||||
else
|
||||
steamPressure += 2;
|
||||
}
|
||||
}
|
||||
if (waterInjection) { // Water injector open
|
||||
if (waterLevelTender > 0) { // Inject water with water from tender
|
||||
if (waterLevelBoiler > 95) {
|
||||
endWaterInjection();
|
||||
}
|
||||
else {
|
||||
waterLevelBoiler += 2;
|
||||
waterLevelTender--;
|
||||
}
|
||||
steamSpeedLimit[LIMIT_TENDER] = LIMIT_NONE;
|
||||
}
|
||||
else {
|
||||
endWaterInjection(); // Stop locomotive if tender empty
|
||||
steamSpeedLimit[LIMIT_TENDER] = 0;
|
||||
steamThrottleStop();
|
||||
}
|
||||
}
|
||||
if (fillTender) {
|
||||
if ((waterLevelTender > 495) || (currentSteamSpeed != 0)) { // Only fill tender when stopped
|
||||
endTenderFill();
|
||||
}
|
||||
else {
|
||||
waterLevelTender++;
|
||||
if (waterLevelTender > 6) // Minimum level to run again
|
||||
steamSpeedLimit[LIMIT_TENDER] = LIMIT_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentSteamTime > (steamTimeSmoke + changeSmoke)) { // Chimney smoke
|
||||
steamTimeSmoke = currentSteamTime;
|
||||
if (currentSteamSpeed > 0) {
|
||||
fncData[FNC_ST_SMOKE].state = !fncData[FNC_ST_SMOKE].state;
|
||||
changeSmoke = map(currentSteamSpeed, 0, 127, STEAM_SMOKE_SLOW, STEAM_SMOKE_FAST);
|
||||
}
|
||||
else {
|
||||
fncData[FNC_ST_SMOKE].state = false;
|
||||
changeSmoke = STEAM_SMOKE_SLOW + STEAM_SMOKE_SLOW;
|
||||
}
|
||||
newEvent(OBJ_FNC, FNC_ST_SMOKE, EVNT_DRAW);
|
||||
}
|
||||
|
||||
if (barData[BAR_BRAKE].value > 0) { // Braking
|
||||
value = barData[BAR_BRAKE].value * 8;
|
||||
value = (currentSteamSpeed > value) ? (currentSteamSpeed - value) : 0;
|
||||
steamSpeedLimit[LIMIT_BRAKE] = value;
|
||||
}
|
||||
else {
|
||||
steamSpeedLimit[LIMIT_BRAKE] = LIMIT_NONE;
|
||||
}
|
||||
|
||||
targetSpeedSteam = LIMIT_NONE; // Find lower limit
|
||||
for (value = 0; value < MAX_LIMIT; value++) {
|
||||
if (steamSpeedLimit[value] < targetSpeedSteam)
|
||||
targetSpeedSteam = steamSpeedLimit[value];
|
||||
}
|
||||
|
||||
newSpeed = currentSteamSpeed;
|
||||
if (currentSteamTime > (steamTimeSpeed + changeSpeed)) { // Speed acceleration
|
||||
steamTimeSpeed = currentSteamTime;
|
||||
//DEBUG_MSG("Target: %d Current: %d New: %d", targetSpeedSteam, currentSteamSpeed, newSpeed)
|
||||
if (targetSpeedSteam > currentSteamSpeed) {
|
||||
newSpeed = currentSteamSpeed + 1;
|
||||
DEBUG_MSG("Inc New: %d", newSpeed)
|
||||
}
|
||||
if (targetSpeedSteam < currentSteamSpeed) {
|
||||
newSpeed = currentSteamSpeed - 1;
|
||||
DEBUG_MSG("Dec New: %d", newSpeed)
|
||||
}
|
||||
//DEBUG_MSG("New acc: %d", newSpeed)
|
||||
}
|
||||
|
||||
|
||||
if (currentSteamSpeed != newSpeed) { // changes in speed
|
||||
DEBUG_MSG("Step: %d - New: %d LIMITS ", currentSteamSpeed, newSpeed)
|
||||
#ifdef DEBUG
|
||||
for (value = 0; value < MAX_LIMIT; value++) {
|
||||
Serial.print(steamSpeedLimit[value]);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
currentSteamSpeed = newSpeed;
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
case CLIENT_XNET:
|
||||
if (bitRead(locoData[myLocoData].mySteps, 2)) { // 128 steps
|
||||
mappedThrottle = (currentSteamSpeed > 1) ? currentSteamSpeed : 0;
|
||||
}
|
||||
else {
|
||||
if (bitRead(locoData[myLocoData].mySteps, 1)) { // 28 steps
|
||||
if (currentSteamSpeed > 15) {
|
||||
mappedThrottle = currentSteamSpeed >> 3;
|
||||
bitWrite(mappedThrottle, 4, bitRead(currentSteamSpeed, 2));
|
||||
}
|
||||
else {
|
||||
mappedThrottle = 0;
|
||||
}
|
||||
}
|
||||
else { // 14 steps
|
||||
mappedThrottle = (currentSteamSpeed > 15) ? currentSteamSpeed >> 3 : 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
case CLIENT_ECOS:
|
||||
mappedThrottle = (currentSteamSpeed > 1) ? currentSteamSpeed : 0;
|
||||
break;
|
||||
}
|
||||
locoData[myLocoData].mySpeed = mappedThrottle;
|
||||
locoOperationSpeed();
|
||||
DEBUG_MSG("Steam step: %d", currentSteamSpeed)
|
||||
if ((currentSteamSpeed > 0) && (changeSmoke > STEAM_SMOKE_SLOW)) { // initial chuff
|
||||
changeSmoke = 0;
|
||||
fncData[FNC_ST_SMOKE].state = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((oldLevelTender / 10) != (waterLevelTender / 10)) {
|
||||
oldLevelTender = waterLevelTender;
|
||||
barData[BAR_TENDER].value = waterLevelTender;
|
||||
newEvent(OBJ_BAR, BAR_TENDER, EVNT_DRAW);
|
||||
}
|
||||
|
||||
value = waterLevelBoiler / 2;
|
||||
if (oldLevelBoiler != value ) {
|
||||
oldLevelBoiler = value;
|
||||
barData[BAR_WATER].value = value;
|
||||
newEvent(OBJ_BAR, BAR_WATER, EVNT_DRAW);
|
||||
}
|
||||
|
||||
value = steamPressure * 270 / 100;
|
||||
if (oldPressure != value) {
|
||||
showPressure(value);
|
||||
DEBUG_MSG("Pressure: %d", steamPressure)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void startWaterInjection () {
|
||||
waterInjection = true;
|
||||
fncData[FNC_ST_WATER].colorOn = COLOR_DARKGREEN;
|
||||
drawObject(OBJ_FNC, FNC_ST_WATER);
|
||||
}
|
||||
|
||||
|
||||
void endWaterInjection () {
|
||||
waterInjection = false;
|
||||
fncData[FNC_ST_WATER].colorOn = COLOR_RED;
|
||||
drawObject(OBJ_FNC, FNC_ST_WATER);
|
||||
}
|
||||
|
||||
|
||||
void startTenderFill() {
|
||||
fillTender = true;
|
||||
//fncData[FNC_ST_TENDER].color = COLOR_RED;
|
||||
fncData[FNC_ST_TENDER].colorOn = COLOR_DARKGREEN;
|
||||
drawObject(OBJ_FNC, FNC_ST_TENDER);
|
||||
}
|
||||
|
||||
|
||||
void endTenderFill() {
|
||||
fillTender = false;
|
||||
//fncData[FNC_ST_TENDER].color = COLOR_WHITE;
|
||||
fncData[FNC_ST_TENDER].colorOn = COLOR_RED;
|
||||
drawObject(OBJ_FNC, FNC_ST_TENDER);
|
||||
}
|
||||
|
||||
|
||||
void setFirebox() {
|
||||
if (shovelCoal) {
|
||||
fncData[FNC_ST_FIRE].idIcon = FNC_FIRE_OP_OFF;
|
||||
fncData[FNC_ST_FIRE].color = COLOR_ORANGE;
|
||||
fncData[FNC_ST_FIRE].colorOn = COLOR_YELLOW;
|
||||
}
|
||||
else {
|
||||
fncData[FNC_ST_FIRE].idIcon = FNC_FIRE_CL_OFF;
|
||||
fncData[FNC_ST_FIRE].color = COLOR_SILVER;
|
||||
fncData[FNC_ST_FIRE].colorOn = COLOR_RED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void steamThrottleStop() { // set controls for stop
|
||||
if (encoderValue > 0) {
|
||||
encoderValue = 0;
|
||||
showSpeedSteam(240);
|
||||
}
|
||||
if (barData[BAR_JOHNSON].value != STEAM_JOHNSON_NEUTRAL) {
|
||||
barData[BAR_JOHNSON].value = STEAM_JOHNSON_NEUTRAL; // Neutral
|
||||
drawObject(OBJ_BAR, BAR_JOHNSON);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void showPressure(uint16_t angle) {
|
||||
tft.setPivot(140, 105); // Set pivot to center of manometer in TFT screen
|
||||
sprite.setColorDepth(8); // Create an 8bpp Sprite
|
||||
sprite.createSprite(19, 19); // 8bpp requires 19 * 19 = 361 bytes
|
||||
sprite.setPivot(9, 9); // Set pivot relative to top left corner of Sprite
|
||||
sprite.fillSprite(COLOR_WHITE); // Fill the Sprite with background
|
||||
sprite.pushRotated(oldPressure);
|
||||
oldPressure = angle;
|
||||
sprite.drawBitmap(0, 0, needle_bar, 19, 19, COLOR_BLUE);
|
||||
sprite.pushRotated(angle);
|
||||
sprite.deleteSprite();
|
||||
}
|
||||
|
||||
void showSpeedSteam(uint16_t angle) {
|
||||
tft.setPivot(120, 170); // Set pivot to center of bar in TFT screen
|
||||
sprite.setColorDepth(8); // Create an 8bpp Sprite
|
||||
sprite.createSprite(83, 15); // 8bpp requires 83 * 15 = 1245 bytes
|
||||
sprite.setPivot(76, 7); // Set pivot relative to top left corner of Sprite
|
||||
sprite.fillSprite(COLOR_BLACK); // Fill the Sprite with background
|
||||
sprite.pushRotated(oldSpeedSteam);
|
||||
oldSpeedSteam = angle;
|
||||
sprite.drawBitmap(0, 0, speed_steam, 83, 15, COLOR_RED);
|
||||
sprite.pushRotated(angle);
|
||||
tft.drawArc(120, 170, 27, 22, 315, 45, COLOR_RED, COLOR_BLACK, false);
|
||||
sprite.deleteSprite();
|
||||
}
|
||||
842
PacoMouseCYD/Platformio/Arduino.old/system.ino
Normal file
842
PacoMouseCYD/Platformio/Arduino.old/system.ino
Normal file
@@ -0,0 +1,842 @@
|
||||
/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** SYSTEM SUPPORT *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void initPins() {
|
||||
// Set all chip selects high to avoid bus contention during initialisation of each peripheral
|
||||
digitalWrite(TFT_CS, HIGH); // TFT screen chip select
|
||||
digitalWrite(SD_CS, HIGH); // SD card chips select
|
||||
digitalWrite(XPT2046_CS, HIGH); // Touch screen chips select
|
||||
pinMode (SW_BOOT, INPUT); // Button BOOT
|
||||
pinMode (ENCODER_A, INPUT); // Encoder
|
||||
pinMode (ENCODER_B, INPUT);
|
||||
pinMode (ENCODER_SW, INPUT);
|
||||
#if (USE_RGB_LED == PRESENT)
|
||||
pinMode(RGB_LED_R, OUTPUT); // RGB LED
|
||||
pinMode(RGB_LED_G, OUTPUT);
|
||||
pinMode(RGB_LED_B, OUTPUT);
|
||||
setColorRGB(0); // turn off RGB LED
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void setBacklight (uint8_t value) { // set PWM backlight
|
||||
#if (ESP_ARDUINO_VERSION_MAJOR > 2)
|
||||
// Code for version 3.x
|
||||
ledcWrite(TFT_BL, value);
|
||||
#else
|
||||
// Code for version 2.x
|
||||
ledcWrite(LEDC_CHANNEL_0, value);
|
||||
#endif
|
||||
currBacklight = value;
|
||||
}
|
||||
|
||||
void setRotationDisplay(uint8_t pos) { // Rotate display and touchscreen
|
||||
tft.setRotation(pos);
|
||||
touchscreen.setRotation((pos + XPT_ROTATION) & 0x03);
|
||||
}
|
||||
|
||||
void aliveAndKicking() {
|
||||
setTimer (TMR_BLIGHT, INACT_TIME, TMR_ONESHOT); // reset timeout and restore backlight
|
||||
if (currBacklight != backlight)
|
||||
setBacklight(backlight);
|
||||
}
|
||||
|
||||
#if (USE_RGB_LED == PRESENT)
|
||||
void setColorRGB (uint16_t color) { // set color of RGB LED
|
||||
int state;
|
||||
state = (color & 0x04) ? LOW : HIGH;
|
||||
digitalWrite(RGB_LED_G, state);
|
||||
state = (color & 0x02) ? LOW : HIGH;
|
||||
digitalWrite(RGB_LED_R, state);
|
||||
state = (color & 0x01) ? LOW : HIGH;
|
||||
digitalWrite(RGB_LED_B, state);
|
||||
DEBUG_MSG("Color: %d", color & 0x07)
|
||||
}
|
||||
#endif
|
||||
|
||||
initResult initSequence() { // Performs init sequence
|
||||
char label[MAX_LABEL_LNG];
|
||||
char chr;
|
||||
int n;
|
||||
initResult result;
|
||||
result = INIT_OK;
|
||||
delay(500);
|
||||
drawObject(OBJ_ICON, ICON_SDCARD); // detecting SD card
|
||||
if (sdDetected) {
|
||||
sprintf (FileName, "/image/logo.bmp");
|
||||
if (tft.width() == 240)
|
||||
drawBmp (FileName, 0, 180);
|
||||
else
|
||||
drawBmp (FileName, 40, 260);
|
||||
loadLocoFiles(SD, "/loco"); // load loco data & panel names from SD file
|
||||
loadAccPanelNames(SD);
|
||||
}
|
||||
else {
|
||||
if (LittleFS.begin(false)) {
|
||||
loadLocoFiles(LittleFS, "/loco"); // load loco data & panel names from FS file
|
||||
loadAccPanelNames(LittleFS);
|
||||
}
|
||||
else {
|
||||
DEBUG_MSG("LittleFS Mount Failed. Formating....");
|
||||
LittleFS.format();
|
||||
}
|
||||
drawObject(OBJ_ICON, ICON_NO_SD);
|
||||
result = INIT_NO_SD;
|
||||
DEBUG_MSG("Total: %ul Used: %ul", LittleFS.totalBytes(), LittleFS.usedBytes())
|
||||
}
|
||||
populateAccPanel(); // load first accessory panel
|
||||
barData[BAR_INIT].value = 10;
|
||||
drawObject(OBJ_BAR, BAR_INIT);
|
||||
drawObject(OBJ_ICON, ICON_WIFI); // connecting to WiFi network
|
||||
drawObject(OBJ_DRAWSTR, DSTR_INIT_STAT);
|
||||
drawObject(OBJ_LABEL, LBL_CONNECT);
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(wifiSetting.ssid, wifiSetting.password);
|
||||
n = 0;
|
||||
while ((WiFi.status() != WL_CONNECTED) && n < 80) { // tries to connect to router in 20 seconds
|
||||
n += 2;
|
||||
barData[BAR_INIT].value = 10 + n;
|
||||
drawObject(OBJ_BAR, BAR_INIT);
|
||||
delay(500);
|
||||
DEBUG_MSG(".");
|
||||
}
|
||||
barData[BAR_INIT].value = 90;
|
||||
drawObject(OBJ_BAR, BAR_INIT);
|
||||
if (WiFi.status() == WL_CONNECTED) { // Connect to server with current protocol
|
||||
drawObject(OBJ_DRAWSTR, DSTR_INIT_STAT); // show Protocol
|
||||
getLabelTxt(LBL_SEL_Z21 + wifiSetting.protocol, label);
|
||||
tft.drawString(label, 20, 120, GFXFF);
|
||||
DEBUG_MSG("Channel: %d", WiFi.channel());
|
||||
DEBUG_MSG("IP address: %u.%u.%u.%u", WiFi.localIP().operator[](0), WiFi.localIP().operator[](1), WiFi.localIP().operator[](2), WiFi.localIP().operator[](3));
|
||||
DEBUG_MSG("%s", WiFi.macAddress().c_str())
|
||||
useID = false;
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
WiFi.setSleep(false);
|
||||
Udp.begin(z21Port);
|
||||
//wifiSetting.port = z21Port;
|
||||
DEBUG_MSG("Now listening UDP port %d", z21Port);
|
||||
getStatusZ21(); // every x seconds
|
||||
getSerialNumber();
|
||||
delay(500);
|
||||
setBroadcastFlags (0x00000013); // Broadcasts and info messages concerning driving and switching, report changes on feedback bus & fast clock
|
||||
getStatusZ21();
|
||||
//askZ21begin (LAN_GET_BROADCASTFLAGS);
|
||||
//sendUDP (0x04);
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
if (!Client.connect(wifiSetting.CS_IP, wifiSetting.port)) {
|
||||
DEBUG_MSG("Connection to Loconet over TCP/IP failed");
|
||||
result = INIT_NO_CONNECT;
|
||||
}
|
||||
else {
|
||||
Client.setNoDelay(true);
|
||||
rcvStrPhase = WAIT_TOKEN;
|
||||
getTypeCS();
|
||||
}
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
if (!Client.connect(wifiSetting.CS_IP, XnetPort)) {
|
||||
DEBUG_MSG("Connection to Xpressnet failed");
|
||||
result = INIT_NO_CONNECT;
|
||||
}
|
||||
else {
|
||||
wifiSetting.port = XnetPort;
|
||||
Client.setNoDelay(true);
|
||||
rxIndice = FRAME1;
|
||||
getVersionXnet(); // pide la version del Xpressnet
|
||||
getStatusXnet(); // pide estado de la central
|
||||
}
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
useID = true;
|
||||
if (!Client.connect(wifiSetting.CS_IP, ECoSPort)) {
|
||||
DEBUG_MSG("Connection to ECoS failed");
|
||||
result = INIT_NO_CONNECT;
|
||||
}
|
||||
else {
|
||||
wifiSetting.port = ECoSPort;
|
||||
Client.setNoDelay(true);
|
||||
requestViews();
|
||||
requestLocoList();
|
||||
waitWifiData(500);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
drawObject(OBJ_ICON, ICON_NO_WIFI);
|
||||
result = INIT_NO_WIFI;
|
||||
}
|
||||
barData[BAR_INIT].value = 95;
|
||||
drawObject(OBJ_BAR, BAR_INIT);
|
||||
drawObject(OBJ_ICON, ICON_INIT_LOCO); // fill image list
|
||||
initImageList();
|
||||
barData[BAR_INIT].value = 100;
|
||||
drawObject(OBJ_BAR, BAR_INIT);
|
||||
setTimer (TMR_END_LOGO, 7, TMR_ONESHOT); // Wait for answer
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool notLocked () { // check if not locked
|
||||
if (lockOptions & ((1 << LOCK_SEL_LOCO) | (1 << LOCK_TURNOUT) | (1 << LOCK_PROG)))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool notLockedOption (byte opt) { // check if option not locked
|
||||
if (lockOptions & (1 << opt))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** TOUCHSCREEN *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void calibrateTouchscreen(uint16_t colorIn, uint16_t colorOut, uint16_t bg) {
|
||||
uint16_t TS_TOP, TS_BOT, TS_LEFT, TS_RT;
|
||||
uint16_t x, y, z;
|
||||
TSPoint p;
|
||||
TS_TOP = 4095;
|
||||
TS_BOT = 0;
|
||||
TS_LEFT = 4095;
|
||||
TS_RT = 0;
|
||||
tft.fillScreen(bg);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
tft.fillCircle(0, 0, 15, bg); // delete touch corners points
|
||||
tft.fillCircle(tft.width(), 0, 15, bg);
|
||||
tft.fillCircle(0, tft.height(), 15, bg);
|
||||
tft.fillCircle(tft.width(), tft.height(), 15, bg);
|
||||
DEBUG_MSG("Calibrate step: %d", i)
|
||||
switch (i) { // show current touch corner point
|
||||
case 0:
|
||||
tft.fillCircle(0, 0, 15, colorOut);
|
||||
tft.fillCircle(0, 0, 7, colorIn);
|
||||
break;
|
||||
case 1:
|
||||
tft.fillCircle(tft.width(), 0, 15, colorOut);
|
||||
tft.fillCircle(tft.width(), 0, 7, colorIn);
|
||||
break;
|
||||
case 2:
|
||||
tft.fillCircle(0, tft.height(), 15, colorOut);
|
||||
tft.fillCircle(0, tft.height(), 7, colorIn);
|
||||
break;
|
||||
case 3:
|
||||
tft.fillCircle(tft.width(), tft.height(), 15, colorOut);
|
||||
tft.fillCircle(tft.width(), tft.height(), 7, colorIn);
|
||||
break;
|
||||
}
|
||||
while (touchscreen.touched()) // wait to release
|
||||
delay(0);
|
||||
DEBUG_MSG("Pen released")
|
||||
while (!touchscreen.touched()) // wait to touch
|
||||
delay(0);
|
||||
DEBUG_MSG("Pen touched")
|
||||
touchscreen.readData(&x, &y, &z);
|
||||
if (x < TS_LEFT) {
|
||||
TS_LEFT = x;
|
||||
}
|
||||
if (y < TS_TOP) {
|
||||
TS_TOP = y;
|
||||
}
|
||||
if (x > TS_RT) {
|
||||
TS_RT = x;
|
||||
}
|
||||
if (y > TS_BOT) {
|
||||
TS_BOT = y;
|
||||
}
|
||||
}
|
||||
tft.fillCircle(tft.width(), tft.height(), 15, bg); // delete last touch corner point
|
||||
touchscreen.setCalibration(TS_LEFT, TS_RT, TS_TOP, TS_BOT);
|
||||
DEBUG_MSG("xMin: %d, xMax: %d, yMin: %d, yMax: %d", TS_LEFT, TS_RT, TS_TOP, TS_BOT);
|
||||
}
|
||||
|
||||
|
||||
void showClockData(uint16_t txtFocus) {
|
||||
uint16_t n;
|
||||
for (n = 0; n < 3; n++)
|
||||
txtData[TXT_HOUR + n].backgnd = COLOR_BACKGROUND;
|
||||
txtData[txtFocus].backgnd = COLOR_YELLOW; // select focus on selected field
|
||||
keybData[KEYB_CLOCK].idTextbox = txtFocus;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** WIFI *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void scanWiFi() {
|
||||
networks = 0;
|
||||
while (networks == 0) {
|
||||
WiFi.disconnect(true); //DISCONNECT WITH TRUE (SHUOLD TURN OFF THE RADIO)
|
||||
delay(1000);
|
||||
WiFi.mode(WIFI_STA); //CALLING THE WIFI MODE AS STATION
|
||||
WiFi.scanDelete();
|
||||
networks = WiFi.scanNetworks();
|
||||
DEBUG_MSG("Networks: %d", networks);
|
||||
if ((networks > 0) && (networks < 32768)) {
|
||||
encoderMax = networks - 1;
|
||||
encoderValue = 0;
|
||||
scrSSID = 0;
|
||||
}
|
||||
else
|
||||
networks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void scanWiFiFill() {
|
||||
uint16_t n, line;
|
||||
n = (scrSSID > 5) ? scrSSID - 5 : 0;
|
||||
snprintf (ssidName1, SSID_LNG, WiFi.SSID(n).c_str());
|
||||
snprintf (ssidName2, SSID_LNG, WiFi.SSID(n + 1).c_str());
|
||||
snprintf (ssidName3, SSID_LNG, WiFi.SSID(n + 2).c_str());
|
||||
snprintf (ssidName4, SSID_LNG, WiFi.SSID(n + 3).c_str());
|
||||
snprintf (ssidName5, SSID_LNG, WiFi.SSID(n + 4).c_str());
|
||||
snprintf (ssidName6, SSID_LNG, WiFi.SSID(n + 5).c_str());
|
||||
line = (scrSSID > 5) ? 5 : scrSSID;
|
||||
for (n = 0; n < 6; n++) {
|
||||
txtData[TXT_SSID1 + n].backgnd = (n == line) ? COLOR_BLUE : COLOR_BLACK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void wifiAnalyzer() {
|
||||
int16_t n, i;
|
||||
char txt[10];
|
||||
for (n = 0; n < 14; n++) {
|
||||
ap_count[n] = 0;
|
||||
max_rssi[n] = RSSI_FLOOR;
|
||||
}
|
||||
n = WiFi.scanNetworks();
|
||||
drawObject(OBJ_DRAWSTR, DSTR_WIFI_SCAN);
|
||||
drawObject(OBJ_LABEL, LBL_SSID_SCAN);
|
||||
drawObject(OBJ_FNC, FNC_SCAN_RESET);
|
||||
tft.setFreeFont(FSSB6);
|
||||
if ((n > 0) && (n < 32768)) {
|
||||
for (i = 0; i < n; i++) {
|
||||
int32_t channel = WiFi.channel(i);
|
||||
int32_t rssi = WiFi.RSSI(i);
|
||||
uint16_t color = channel_color[channel - 1];
|
||||
int height = constrain(map(rssi, RSSI_FLOOR, RSSI_CEILING, 1, GRAPH_HEIGHT), 1, GRAPH_HEIGHT);
|
||||
// channel stat
|
||||
ap_count[channel - 1]++;
|
||||
if (rssi > max_rssi[channel - 1]) {
|
||||
max_rssi[channel - 1] = rssi;
|
||||
}
|
||||
tft.drawLine((channel * CHANNEL_WIDTH) + GRAPH_OFFSET, GRAPH_BASELINE - height, ((channel - 1) * CHANNEL_WIDTH) + GRAPH_OFFSET, GRAPH_BASELINE + 1, color);
|
||||
tft.drawLine((channel * CHANNEL_WIDTH) + GRAPH_OFFSET, GRAPH_BASELINE - height, ((channel + 1) * CHANNEL_WIDTH) + GRAPH_OFFSET, GRAPH_BASELINE + 1, color);
|
||||
// Print SSID, signal strengh and if not encrypted
|
||||
tft.setTextColor(color);
|
||||
tft.setTextDatum(MC_DATUM);
|
||||
tft.drawString(WiFi.SSID(i), (channel * CHANNEL_WIDTH) + GRAPH_OFFSET, GRAPH_BASELINE - 10 - height, GFXFF);
|
||||
// rest for WiFi routine?
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
else {
|
||||
tft.setFreeFont(FSSB9);
|
||||
tft.setTextColor(COLOR_WHITE);
|
||||
tft.drawString("SSID = 0", 120 + GRAPH_OFFSET, 120, GFXFF);
|
||||
}
|
||||
tft.setFreeFont(FSSB6);
|
||||
tft.setTextDatum(TC_DATUM);
|
||||
for (i = 1; i < 15; i++) {
|
||||
tft.setTextColor(channel_color[i - 1]);
|
||||
snprintf(txt, 10, "%d", i);
|
||||
tft.drawString(txt, (i * CHANNEL_WIDTH) + GRAPH_OFFSET, GRAPH_BASELINE + 12, GFXFF);
|
||||
if (ap_count[i - 1] > 0) {
|
||||
snprintf(txt, 10, "(%d)", ap_count[i - 1]);
|
||||
tft.drawString(txt, (i * CHANNEL_WIDTH) + GRAPH_OFFSET, GRAPH_BASELINE + 24, GFXFF);
|
||||
}
|
||||
}
|
||||
setTimer(TMR_SCAN, 50, TMR_ONESHOT);
|
||||
}
|
||||
|
||||
|
||||
void wifiProcess() {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
processZ21();
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
processXnet();
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
processLnet();
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
ECoSProcess();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void waitWifiData(uint32_t ms) {
|
||||
uint32_t now;
|
||||
now = millis();
|
||||
while ((millis() - now) < ms)
|
||||
wifiProcess();
|
||||
}
|
||||
|
||||
|
||||
void setProtocolData() {
|
||||
uint16_t n;
|
||||
useID = false;
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
snprintf(keybProtoBuf, PWD_LNG, "Z21");
|
||||
snprintf(keybPortBuf, 6, "%d", z21Port);
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
if (wifiSetting.serverType)
|
||||
snprintf(keybProtoBuf, PWD_LNG, "LBServer");
|
||||
else
|
||||
snprintf(keybProtoBuf, PWD_LNG, "Loconet Binary");
|
||||
snprintf(keybPortBuf, 6, "%d", wifiSetting.port);
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
snprintf(keybProtoBuf, PWD_LNG, "Xpressnet LAN");
|
||||
snprintf(keybPortBuf, 6, "%d", XnetPort);
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
useID = true;
|
||||
snprintf(keybProtoBuf, PWD_LNG, "ECoS");
|
||||
snprintf(keybPortBuf, 6, "%d", ECoSPort);
|
||||
break;
|
||||
}
|
||||
for (n = 0; n < 5; n++)
|
||||
txtData[TXT_IP1 + n].backgnd = COLOR_BACKGROUND;
|
||||
txtData[TXT_IP1].backgnd = COLOR_YELLOW; // select focus on first IP byte
|
||||
keybData[KEYB_IP].idTextbox = TXT_IP1;
|
||||
}
|
||||
|
||||
void setOptionsData() {
|
||||
switchData[SW_OPT_ADR].state = false; // show disable all as default
|
||||
switchData[SW_OPT_ADR].colorKnob = COLOR_BACKGROUND;
|
||||
radioData[RAD_CSTATION].value = radioData[RAD_CSTATION].num;
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
switchData[SW_OPT_ADR].colorKnob = COLOR_WHITE;
|
||||
switchData[SW_OPT_ADR].state = (shortAddress == 99) ? true : false;
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
radioData[RAD_CSTATION].value = typeCmdStation;
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** PROTOCOL COMMON *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void infoLocomotora (unsigned int loco) {
|
||||
DEBUG_MSG("Info Loco % d", loco)
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
infoLocomotoraZ21 (loco);
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
infoLocomotoraXnet (loco);
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
infoLocomotoraLnet (loco);
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
infoLocomotoraECoS (loco); // ID
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void locoOperationSpeed() {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
locoOperationSpeedZ21();
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
locoOperationSpeedXnet();
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
locoOperationSpeedLnet();
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
locoOperationSpeedECoS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void changeDirection() {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
locoOperationSpeedZ21();
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
locoOperationSpeedXnet();
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
changeDirectionF0F4Lnet();
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
changeDirectionECoS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void funcOperations (uint8_t fnc) {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
funcOperationsZ21 (fnc);
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
funcOperationsXnet (fnc);
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
funcOperationsLnet (fnc);
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
funcOperationsECoS(fnc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
byte getCurrentStep() {
|
||||
byte value;
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
value = getCurrentStepZ21();
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
value = getCurrentStepXnet();
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
value = getCurrentStepLnet();
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
value = getCurrentStepECoS();
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void releaseLoco() {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_LNET:
|
||||
doDispatchGet = false;
|
||||
doDispatchPut = false;
|
||||
liberaSlot(); // pasa slot actual a COMMON
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
releaseLocoECoS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sendAccessory(unsigned int FAdr, int pair, bool activate) {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
setAccessoryZ21(FAdr, pair, activate);
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
setAccessoryXnet(FAdr, activate, pair);
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
lnetRequestSwitch (FAdr, activate, pair);
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
setAccessoryECoS(FAdr, pair, activate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void resumeOperations() {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
resumeOperationsZ21();
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
resumeOperationsXnet();
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
resumeOperationsLnet();
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
resumeOperationsECoS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void emergencyOff() {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
emergencyOffZ21();
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
emergencyOffXnet();
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
emergencyOffLnet();
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
emergencyOffECoS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void togglePower() {
|
||||
if (isTrackOff())
|
||||
resumeOperations(); // Track Power On
|
||||
else
|
||||
emergencyOff(); // Track Power Off
|
||||
}
|
||||
|
||||
|
||||
bool isTrackOff() {
|
||||
bool state;
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
state = (csStatus & csTrackVoltageOff) ? true : false;
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
state = (csStatus & csEmergencyOff) ? true : false;
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
state = (bitRead(mySlot.trk, 0)) ? false : true;
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
state = (csStatus > 0) ? false : true;
|
||||
break;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
void getStatusCS() {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
getStatusZ21();
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
getStatusXnet();
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
getTypeCS(); // workaround, not defined for Lnet
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
getStatusECoS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void setTime(byte hh, byte mm, byte rate) {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
setTimeZ21(hh, mm, rate);
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
setTimeXnet(hh, mm, rate);
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
setTimeLnet(hh, mm, rate);
|
||||
break;
|
||||
// ECoS not supported
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void readCV (unsigned int adr, byte stepPrg) {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
readCVZ21(adr, stepPrg);
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
readCVXnet(adr, stepPrg);
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
readCVLnet(adr, stepPrg);
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
readCVECoS(adr, stepPrg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void writeCV (unsigned int adr, unsigned int data, byte stepPrg) {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
writeCVZ21(adr, data, stepPrg);
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
writeCVXnet(adr, data, stepPrg);
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
writeCVLnet(adr, data, stepPrg);
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
writeCVECoS(adr, data, stepPrg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void exitProgramming() {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
if (csStatus & csProgrammingModeActive)
|
||||
resumeOperationsZ21();
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
if (csStatus & csServiceMode)
|
||||
resumeOperationsXnet();
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
exitProgrammingECoS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** CV PROGRAMMING *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void endProg() { // Fin de programcion/lectura CV
|
||||
DEBUG_MSG("END PROG: CVData - % d Step: % d", CVdata, progStepCV);
|
||||
if (CVdata > 255) {
|
||||
if (progStepCV == PRG_RD_CV29) // Si buscaba direccion, muestra CV1 en lugar de CV29
|
||||
CVaddress = 1;
|
||||
showDataCV();
|
||||
}
|
||||
else {
|
||||
switch (progStepCV) {
|
||||
case PRG_CV:
|
||||
showDataCV();
|
||||
break;
|
||||
case PRG_RD_CV29:
|
||||
cv29 = (byte) CVdata;
|
||||
if (bitRead(cv29, 5)) {
|
||||
CVaddress = 17; // Long address
|
||||
readCV(CVaddress, PRG_RD_CV17);
|
||||
}
|
||||
else {
|
||||
CVaddress = 1; // Short address
|
||||
readCV(CVaddress, PRG_RD_CV1);
|
||||
}
|
||||
break;
|
||||
case PRG_RD_CV1:
|
||||
decoAddress = CVdata;
|
||||
showDirCV();
|
||||
break;
|
||||
case PRG_RD_CV17:
|
||||
cv17 = (byte) CVdata;
|
||||
CVaddress = 18;
|
||||
readCV(CVaddress, PRG_RD_CV18);
|
||||
break;
|
||||
case PRG_RD_CV18:
|
||||
cv18 = (byte) CVdata;
|
||||
decoAddress = ((cv17 & 0x3F) << 8) | cv18;
|
||||
showDirCV();
|
||||
break;
|
||||
case PRG_WR_CV17: // Long address
|
||||
CVaddress = 18;
|
||||
writeCV(CVaddress, lowByte(decoAddress), PRG_WR_CV18);
|
||||
break;
|
||||
case PRG_WR_CV18:
|
||||
bitSet(cv29, 5);
|
||||
CVaddress = 29;
|
||||
writeCV(CVaddress, cv29, PRG_WR_CV29);
|
||||
break;
|
||||
case PRG_WR_CV1: // short address
|
||||
bitClear(cv29, 5);
|
||||
CVaddress = 29;
|
||||
writeCV(CVaddress, cv29, PRG_WR_CV29);
|
||||
break;
|
||||
case PRG_WR_CV29:
|
||||
showDirCV();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void showDataCV() { // muestra valor de la CV
|
||||
progStepCV = PRG_IDLE;
|
||||
enterCVdata = (CVdata > 255) ? false : true;
|
||||
setStatusCV(); // show error / manufacturer / CV / pom
|
||||
setFieldsCV();
|
||||
setBitsCV();
|
||||
if (isWindow(WIN_ALERT))
|
||||
closeWindow(WIN_ALERT);
|
||||
if (isWindow(WIN_PROG_CV)) {
|
||||
showFieldsCV();
|
||||
newEvent(OBJ_TXT, TXT_CV_STATUS, EVNT_DRAW);
|
||||
}
|
||||
if (wifiSetting.protocol == CLIENT_LNET)
|
||||
progUhli(UHLI_PRG_END);
|
||||
}
|
||||
|
||||
|
||||
void showDirCV() { // muestra direccion de la locomotora segun sus CV
|
||||
progStepCV = PRG_IDLE;
|
||||
setStatusCV(); // show error / manufacturer / CV / pom
|
||||
setFieldsCV();
|
||||
setBitsCV();
|
||||
if (isWindow(WIN_ALERT))
|
||||
closeWindow(WIN_ALERT);
|
||||
sprintf(locoEditAddr, " % d", decoAddress);
|
||||
openWindow(WIN_PROG_ADDR);
|
||||
if (wifiSetting.protocol == CLIENT_LNET)
|
||||
progUhli(UHLI_PRG_END);
|
||||
if (wifiSetting.protocol != CLIENT_ECOS)
|
||||
pushLoco(decoAddress); // mete esta loco en el stack
|
||||
}
|
||||
|
||||
|
||||
void readBasicCV (uint16_t num) {
|
||||
closeWindow(WIN_READ_CV);
|
||||
if (num == 1) {
|
||||
readCV(29, PRG_RD_CV29);
|
||||
}
|
||||
else {
|
||||
CVaddress = num;
|
||||
readCV(num, PRG_CV);
|
||||
}
|
||||
alertWindow(ERR_CV);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** EEPROM *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void saveCalibrationValues() {
|
||||
TouchCalibration cal;
|
||||
cal = touchscreen.getCalibration();
|
||||
EEPROM.write (EE_XMIN_H, highByte(cal.xMin));
|
||||
EEPROM.write (EE_XMIN_L, lowByte(cal.xMin));
|
||||
EEPROM.write (EE_XMAX_H, highByte(cal.xMax));
|
||||
EEPROM.write (EE_XMAX_L, lowByte(cal.xMax));
|
||||
EEPROM.write (EE_YMIN_H, highByte(cal.yMin));
|
||||
EEPROM.write (EE_YMIN_L, lowByte(cal.yMin));
|
||||
EEPROM.write (EE_YMAX_H, highByte(cal.yMax));
|
||||
EEPROM.write (EE_YMAX_L, lowByte(cal.yMax));
|
||||
EEPROM.commit();
|
||||
}
|
||||
885
PacoMouseCYD/Platformio/Arduino.old/window.ino
Normal file
885
PacoMouseCYD/Platformio/Arduino.old/window.ino
Normal file
@@ -0,0 +1,885 @@
|
||||
/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** WINDOW OBJECTS *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void openWindow(uint16_t id) {
|
||||
uint16_t n;
|
||||
char buf[MAX_LABEL_LNG];
|
||||
switch (id) {
|
||||
case WIN_LOGO:
|
||||
createObject(OBJ_WIN, WIN_LOGO);
|
||||
createObject(OBJ_DRAWSTR, DSTR_INIT);
|
||||
createObject(OBJ_LABEL, LBL_PACO_TXT);
|
||||
posObjStack1 = createObject(OBJ_LABEL, LBL_INIT);
|
||||
createObject(OBJ_ICON, ICON_PACO);
|
||||
createObject(OBJ_BAR, BAR_INIT);
|
||||
drawWindow(WIN_LOGO);
|
||||
break;
|
||||
case WIN_CALIBRATE:
|
||||
createObject(OBJ_WIN, WIN_CALIBRATE);
|
||||
posObjStack2 = createObject(OBJ_LABEL, LBL_CAL);
|
||||
posObjStack1 = createObject(OBJ_LABEL, LBL_PRESS);
|
||||
newEvent(OBJ_WIN, WIN_CALIBRATE, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_SSID:
|
||||
createObject(OBJ_WIN, WIN_SSID);
|
||||
createObject(OBJ_ICON, ICON_WIFI_SSID);
|
||||
createObject(OBJ_BUTTON, BUT_SSID_CLOSE);
|
||||
posObjStack1 = createObject(OBJ_LABEL, LBL_SCAN);
|
||||
drawWindow(WIN_SSID);
|
||||
scanWiFi();
|
||||
objStack[posObjStack1].objID = LBL_SSID_SCAN;
|
||||
createObject(OBJ_TXT, TXT_SSID1);
|
||||
createObject(OBJ_TXT, TXT_SSID2);
|
||||
createObject(OBJ_TXT, TXT_SSID3);
|
||||
createObject(OBJ_TXT, TXT_SSID4);
|
||||
createObject(OBJ_TXT, TXT_SSID5);
|
||||
createObject(OBJ_TXT, TXT_SSID6);
|
||||
scanWiFiFill();
|
||||
newEvent(OBJ_WIN, WIN_SSID, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_WIFI:
|
||||
snprintf(ssidName, SSID_LNG, "%s", wifiSetting.ssid);
|
||||
snprintf(keybPwdHideBuf, 9, "********");
|
||||
snprintf(keybIP1Buf, 4, "%d", wifiSetting.CS_IP[0]);
|
||||
snprintf(keybIP2Buf, 4, "%d", wifiSetting.CS_IP[1]);
|
||||
snprintf(keybIP3Buf, 4, "%d", wifiSetting.CS_IP[2]);
|
||||
snprintf(keybIP4Buf, 4, "%d", wifiSetting.CS_IP[3]);
|
||||
setProtocolData();
|
||||
createObject(OBJ_WIN, WIN_WIFI);
|
||||
createObject(OBJ_ICON, ICON_WIFI_CFG);
|
||||
createObject(OBJ_LABEL, LBL_SSID);
|
||||
createObject(OBJ_TXT, TXT_SSID);
|
||||
createObject(OBJ_LABEL, LBL_PWD_HIDE);
|
||||
createObject(OBJ_TXT, TXT_PWD_HIDE);
|
||||
createObject(OBJ_LABEL, LBL_IP);
|
||||
createObject(OBJ_TXT, TXT_IP1);
|
||||
createObject(OBJ_TXT, TXT_IP2);
|
||||
createObject(OBJ_TXT, TXT_IP3);
|
||||
createObject(OBJ_TXT, TXT_IP4);
|
||||
createObject(OBJ_LABEL, LBL_PORT);
|
||||
createObject(OBJ_TXT, TXT_PORT);
|
||||
createObject(OBJ_KEYBOARD, KEYB_IP);
|
||||
createObject(OBJ_LABEL, LBL_PROTOCOL);
|
||||
createObject(OBJ_TXT, TXT_PROTOCOL);
|
||||
createObject(OBJ_BUTTON, BUT_WIFI_OK);
|
||||
newEvent(OBJ_WIN, WIN_WIFI, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_WIFI_PWD:
|
||||
snprintf(keybPwdBuf, PWD_LNG, wifiSetting.password);
|
||||
createObject(OBJ_WIN, WIN_WIFI_PWD);
|
||||
createObject(OBJ_TXT, TXT_PWD);
|
||||
createObject(OBJ_KEYBOARD, KEYB_PWD);
|
||||
createObject(OBJ_BUTTON, BUT_PWD_OK);
|
||||
createObject(OBJ_BUTTON, BUT_PWD_CNCL);
|
||||
newEvent(OBJ_WIN, WIN_WIFI_PWD, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_PROTOCOL:
|
||||
radioData[RAD_PROTOCOL].value = wifiSetting.protocol - CLIENT_Z21;
|
||||
if (wifiSetting.protocol == CLIENT_LNET)
|
||||
radioData[RAD_PROTOCOL_LN].value = (wifiSetting.serverType) ? 0 : 1;
|
||||
else
|
||||
radioData[RAD_PROTOCOL_LN].value = radioData[RAD_PROTOCOL_LN].num;
|
||||
createObject(OBJ_WIN, WIN_PROTOCOL);
|
||||
createObject(OBJ_RADIO, RAD_PROTOCOL);
|
||||
createObject(OBJ_RADIO, RAD_PROTOCOL_LN);
|
||||
createObject(OBJ_LABEL, LBL_SEL_PROT);
|
||||
createObject(OBJ_LABEL, LBL_SEL_Z21);
|
||||
createObject(OBJ_LABEL, LBL_SEL_XNET);
|
||||
createObject(OBJ_LABEL, LBL_SEL_ECOS);
|
||||
createObject(OBJ_LABEL, LBL_SEL_LNET);
|
||||
createObject(OBJ_LABEL, LBL_SEL_LBSERVER);
|
||||
createObject(OBJ_LABEL, LBL_SEL_BINARY);
|
||||
createObject(OBJ_BUTTON, BUT_PROT_OK);
|
||||
createObject(OBJ_BUTTON, BUT_OPTIONS);
|
||||
newEvent(OBJ_WIN, WIN_PROTOCOL, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_THROTTLE:
|
||||
iconData[ICON_LOK_EDIT].bitmap = (wifiSetting.protocol == CLIENT_ECOS) ? info24 : wrench;
|
||||
createObject(OBJ_WIN, WIN_THROTTLE);
|
||||
createObject(OBJ_ICON, ICON_MENU);
|
||||
createObject(OBJ_ICON, ICON_POWER);
|
||||
createObject(OBJ_ICON, ICON_FNEXT);
|
||||
createObject(OBJ_ICON, ICON_LOK_EDIT);
|
||||
createObject(OBJ_FNC, FNC_ACC_PANEL);
|
||||
//createObject(OBJ_ICON, ICON_FWD);
|
||||
//createObject(OBJ_ICON, ICON_REV);
|
||||
createObject(OBJ_TXT, TXT_CLOCK);
|
||||
createObject(OBJ_TXT, TXT_LOCO_NAME);
|
||||
createObject(OBJ_TXT, TXT_LOCO_ADDR);
|
||||
createObject(OBJ_LPIC, LPIC_MAIN);
|
||||
createObject(OBJ_GAUGE, GAUGE_SPEED);
|
||||
createObject(OBJ_LABEL, LBL_KMH);
|
||||
createObject(OBJ_FNC, FNC_FX0);
|
||||
createObject(OBJ_FNC, FNC_FX1);
|
||||
createObject(OBJ_FNC, FNC_FX2);
|
||||
createObject(OBJ_FNC, FNC_FX3);
|
||||
createObject(OBJ_FNC, FNC_FX4);
|
||||
createObject(OBJ_FNC, FNC_FX5);
|
||||
createObject(OBJ_FNC, FNC_FX6);
|
||||
createObject(OBJ_FNC, FNC_FX7);
|
||||
createObject(OBJ_FNC, FNC_FX8);
|
||||
createObject(OBJ_FNC, FNC_FX9);
|
||||
newEvent(OBJ_WIN, WIN_THROTTLE, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_CONFIG:
|
||||
buttonData[BUT_CFG_I_LANG].objID = DSTR_ENGLISH + currLanguage;
|
||||
lastLanguage = currLanguage;
|
||||
createObject(OBJ_WIN, WIN_CONFIG);
|
||||
createObject(OBJ_DRAWSTR, DSTR_CFG_MENU);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_I_LANG);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_T_LANG);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_I_SCR);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_T_SCR);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_I_SPD);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_T_SPD);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_I_WIFI);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_T_WIFI);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_I_FCLK);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_T_FCLK);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_I_LOCK);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_T_LOCK);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_I_ABOUT);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_T_ABOUT);
|
||||
createObject(OBJ_ICON, ICON_CFG_EXIT);
|
||||
newEvent(OBJ_WIN, WIN_CONFIG, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_SCREEN:
|
||||
barData[BAR_BLIGHT].value = backlight;
|
||||
switchData[SW_ROTATE].state = (locationUSB == USB_UP);
|
||||
createObject(OBJ_WIN, WIN_SCREEN);
|
||||
createObject(OBJ_ICON, ICON_BLIGHT);
|
||||
createObject(OBJ_BAR, BAR_BLIGHT);
|
||||
createObject(OBJ_SWITCH, SW_ROTATE);
|
||||
createObject(OBJ_LABEL, LBL_SCR_ROTATE);
|
||||
createObject(OBJ_BUTTON, BUT_CFG_TOUCH);
|
||||
createObject(OBJ_BUTTON, BUT_SCR_OK);
|
||||
createObject(OBJ_BUTTON, BUT_SCR_CNCL);
|
||||
newEvent(OBJ_WIN, WIN_SCREEN, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_SPEED:
|
||||
switchData[SW_SHUNTING].state = shuntingMode;
|
||||
radioData[RAD_STOP_MODE].value = (stopMode > 0) ? 1 : 0;
|
||||
createObject(OBJ_WIN, WIN_SPEED);
|
||||
createObject(OBJ_LABEL, LBL_SHUNTING);
|
||||
createObject(OBJ_SWITCH, SW_SHUNTING);
|
||||
createObject(OBJ_RADIO, RAD_STOP_MODE);
|
||||
createObject(OBJ_ICON, ICON_STOP);
|
||||
createObject(OBJ_LABEL, LBL_STOP_0);
|
||||
createObject(OBJ_LABEL, LBL_STOP_E);
|
||||
createObject(OBJ_BUTTON, BUT_SPD_OK);
|
||||
newEvent(OBJ_WIN, WIN_SPEED, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_SET_CLOCK:
|
||||
snprintf(keybHourBuf, 3, "%d", clockHour);
|
||||
snprintf(keybMinBuf, 3, "%d", clockMin);
|
||||
snprintf(keybRateBuf, 4, "%d", clockRate);
|
||||
showClockData(TXT_HOUR);
|
||||
createObject(OBJ_WIN, WIN_SET_CLOCK);
|
||||
createObject(OBJ_DRAWSTR, DSTR_CLOCK);
|
||||
createObject(OBJ_CHAR, CHAR_CLK_COLON);
|
||||
createObject(OBJ_ICON, ICON_SET_CLOCK);
|
||||
createObject(OBJ_TXT, TXT_HOUR);
|
||||
createObject(OBJ_TXT, TXT_MIN);
|
||||
createObject(OBJ_TXT, TXT_RATE);
|
||||
createObject(OBJ_LABEL, LBL_RATE);
|
||||
createObject(OBJ_KEYBOARD, KEYB_CLOCK);
|
||||
createObject(OBJ_BUTTON, BUT_CLOCK_OK);
|
||||
createObject(OBJ_BUTTON, BUT_CLOCK_CNCL);
|
||||
newEvent(OBJ_WIN, WIN_SET_CLOCK, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_LOCK:
|
||||
switchData[SW_LOCK_LOK].state = (bitRead(lockOptions, LOCK_SEL_LOCO)) ? true : false;
|
||||
switchData[SW_LOCK_ACC].state = (bitRead(lockOptions, LOCK_TURNOUT)) ? true : false;
|
||||
switchData[SW_LOCK_PRG].state = (bitRead(lockOptions, LOCK_PROG)) ? true : false;
|
||||
createObject(OBJ_WIN, WIN_LOCK);
|
||||
createObject(OBJ_SWITCH, SW_LOCK_LOK);
|
||||
createObject(OBJ_SWITCH, SW_LOCK_ACC);
|
||||
createObject(OBJ_SWITCH, SW_LOCK_PRG);
|
||||
createObject(OBJ_LABEL, LBL_LOCK_LOK);
|
||||
createObject(OBJ_LABEL, LBL_LOCK_ACC);
|
||||
createObject(OBJ_LABEL, LBL_LOCK_PRG);
|
||||
createObject(OBJ_BUTTON, BUT_LOCK);
|
||||
newEvent(OBJ_WIN, WIN_LOCK, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_ABOUT:
|
||||
snprintf (aboutPacoMouseCYD, PWD_LNG + 1, "v%s.%s%s", VER_H, VER_L, VER_R);
|
||||
snprintf (aboutIP, PWD_LNG + 1, "IP: %u.%u.%u.%u", WiFi.localIP().operator[](0), WiFi.localIP().operator[](1), WiFi.localIP().operator[](2), WiFi.localIP().operator[](3));
|
||||
snprintf (aboutMAC, PWD_LNG + 1, "MAC: %s", WiFi.macAddress().c_str());
|
||||
createObject(OBJ_WIN, WIN_ABOUT);
|
||||
createObject(OBJ_DRAWSTR, DSTR_ABOUT);
|
||||
createObject(OBJ_LABEL, LBL_PACO_TXT);
|
||||
createObject(OBJ_ICON, ICON_ABOUT_PACO);
|
||||
createObject(OBJ_TXT, TXT_ABOUT);
|
||||
createObject(OBJ_TXT, TXT_ABOUT_IP);
|
||||
createObject(OBJ_TXT, TXT_ABOUT_MAC);
|
||||
createObject(OBJ_LABEL, LBL_PACO_WEB);
|
||||
newEvent(OBJ_WIN, WIN_ABOUT, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_LOK_EDIT:
|
||||
snprintf (locoEditName, NAME_LNG + 1, "%s", locoData[myLocoData].myName );
|
||||
sprintf (locoEditAddr, "%d", locoData[myLocoData].myAddr.address);
|
||||
sprintf (locoEditID, "%d", locoData[myLocoData].myLocoID);
|
||||
sprintf (locoEditVmax, "%d", locoData[myLocoData].myVmax);
|
||||
lpicData[LPIC_LOK_EDIT].id = locoData[myLocoData].myLocoID;
|
||||
for (n = 0; n < 29; n++)
|
||||
fncData[FNC_F0 + n].idIcon = locoData[myLocoData].myFuncIcon[n];
|
||||
createObject(OBJ_WIN, WIN_LOK_EDIT);
|
||||
createObject(OBJ_LABEL, LBL_ADDR);
|
||||
createObject(OBJ_LABEL, LBL_IMAGE);
|
||||
createObject(OBJ_LABEL, LBL_NAME);
|
||||
createObject(OBJ_LABEL, LBL_VMAX);
|
||||
createObject(OBJ_LPIC, LPIC_LOK_EDIT);
|
||||
createObject(OBJ_TXT, TXT_EDIT_ADDR);
|
||||
createObject(OBJ_TXT, TXT_EDIT_NAME);
|
||||
createObject(OBJ_TXT, TXT_EDIT_IMAGE);
|
||||
createObject(OBJ_TXT, TXT_EDIT_VMAX);
|
||||
createObject(OBJ_BUTTON, BUT_EDIT_FUNC);
|
||||
createObject(OBJ_BUTTON, BUT_EDIT_CNCL);
|
||||
if (wifiSetting.protocol != CLIENT_ECOS) {
|
||||
createObject(OBJ_BUTTON, BUT_EDIT_OK);
|
||||
if ((locoData[myLocoData].mySpeed < 2) && (countLocoInStack() > 1)) // stopped and remaining locos in stack
|
||||
createObject(OBJ_BUTTON, BUT_EDIT_DEL);
|
||||
}
|
||||
newEvent(OBJ_WIN, WIN_LOK_EDIT, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_EDIT_NAME:
|
||||
snprintf(keybNameBuf, NAME_LNG + 1, locoData[myLocoData].myName);
|
||||
txtData[TXT_NAME].maxLength = NAME_LNG;
|
||||
createObject(OBJ_WIN, WIN_EDIT_NAME);
|
||||
createObject(OBJ_TXT, TXT_NAME);
|
||||
createObject(OBJ_KEYBOARD, KEYB_NAME);
|
||||
createObject(OBJ_BUTTON, BUT_NAME_OK);
|
||||
createObject(OBJ_BUTTON, BUT_NAME_CNCL);
|
||||
newEvent(OBJ_WIN, WIN_EDIT_NAME, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_FUNC:
|
||||
createObject(OBJ_WIN, WIN_FUNC);
|
||||
for (n = 0; n < 29; n++)
|
||||
createObject(OBJ_FNC, FNC_F0 + n);
|
||||
createObject(OBJ_LABEL, LBL_ADDR);
|
||||
createObject(OBJ_TXT, TXT_EDIT_ADDR);
|
||||
createObject(OBJ_LABEL, LBL_EDIT_FUNC);
|
||||
if (wifiSetting.protocol != CLIENT_ECOS)
|
||||
createObject(OBJ_BUTTON, BUT_FNC_OK);
|
||||
createObject(OBJ_BUTTON, BUT_FNC_CNCL);
|
||||
newEvent(OBJ_WIN, WIN_FUNC, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_CHG_FUNC:
|
||||
createObject(OBJ_WIN, WIN_CHG_FUNC);
|
||||
createObject(OBJ_FNC, FNC_CHG);
|
||||
createObject(OBJ_TXT, TXT_EDIT_FNC);
|
||||
newEvent(OBJ_WIN, WIN_CHG_FUNC, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_VMAX:
|
||||
createObject(OBJ_WIN, WIN_VMAX);
|
||||
createObject(OBJ_TXT, TXT_KEYB_VMAX);
|
||||
createObject(OBJ_KEYBOARD, KEYB_VMAX);
|
||||
newEvent(OBJ_WIN, WIN_VMAX, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_SEL_LOCO:
|
||||
createObject(OBJ_WIN, WIN_SEL_LOCO);
|
||||
createObject(OBJ_DRAWSTR, DSTR_SELLOK);
|
||||
posObjStack1 = createObject(OBJ_ICON, ICON_LAST_UP);
|
||||
prepareLocoList();
|
||||
createObject(OBJ_ICON, ICON_SEL_LOK);
|
||||
if (wifiSetting.protocol != CLIENT_ECOS)
|
||||
createObject(OBJ_FNC, FNC_SEL_KEYPAD);
|
||||
createObject(OBJ_TXT, TXT_SEL_ADDR1);
|
||||
createObject(OBJ_TXT, TXT_SEL_NAME1);
|
||||
createObject(OBJ_TXT, TXT_SEL_ADDR2);
|
||||
createObject(OBJ_TXT, TXT_SEL_NAME2);
|
||||
createObject(OBJ_TXT, TXT_SEL_ADDR3);
|
||||
createObject(OBJ_TXT, TXT_SEL_NAME3);
|
||||
createObject(OBJ_TXT, TXT_SEL_ADDR4);
|
||||
createObject(OBJ_TXT, TXT_SEL_NAME4);
|
||||
createObject(OBJ_TXT, TXT_SEL_ADDR5);
|
||||
createObject(OBJ_TXT, TXT_SEL_NAME5);
|
||||
createObject(OBJ_TXT, TXT_SEL_ADDR6);
|
||||
createObject(OBJ_TXT, TXT_SEL_NAME6);
|
||||
newEvent(OBJ_WIN, WIN_SEL_LOCO, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_ENTER_ADDR:
|
||||
locoKeybAddr[0] = '\0';
|
||||
createObject(OBJ_WIN, WIN_ENTER_ADDR);
|
||||
createObject(OBJ_TXT, TXT_KEYB_ADDR);
|
||||
createObject(OBJ_KEYBOARD, KEYB_ADDR);
|
||||
newEvent(OBJ_WIN, WIN_ENTER_ADDR, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_SEL_IMAGE:
|
||||
createObject(OBJ_WIN, WIN_SEL_IMAGE);
|
||||
createObject(OBJ_LABEL, LBL_SEL_IMAGE);
|
||||
createObject(OBJ_BUTTON, BUT_IMAGE_CNCL);
|
||||
drawWindow(WIN_SEL_IMAGE);
|
||||
populateImageList();
|
||||
createObject(OBJ_LPIC, LPIC_SEL_IMG1);
|
||||
createObject(OBJ_LPIC, LPIC_SEL_IMG2);
|
||||
createObject(OBJ_LPIC, LPIC_SEL_IMG3);
|
||||
createObject(OBJ_LPIC, LPIC_SEL_IMG4);
|
||||
createObject(OBJ_LPIC, LPIC_SEL_IMG5);
|
||||
createObject(OBJ_LPIC, LPIC_SEL_IMG6);
|
||||
createObject(OBJ_ICON, ICON_PREV_IMAGE);
|
||||
createObject(OBJ_ICON, ICON_NEXT_IMAGE);
|
||||
newEvent(OBJ_WIN, WIN_SEL_IMAGE, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_MENU:
|
||||
createObject(OBJ_WIN, WIN_MENU);
|
||||
createObject(OBJ_BUTTON, BUT_MENU_I_DRIVE);
|
||||
createObject(OBJ_BUTTON, BUT_MENU_T_DRIVE);
|
||||
createObject(OBJ_BUTTON, BUT_MENU_I_ACC);
|
||||
createObject(OBJ_BUTTON, BUT_MENU_T_ACC);
|
||||
createObject(OBJ_BUTTON, BUT_MENU_I_CV);
|
||||
createObject(OBJ_BUTTON, BUT_MENU_T_CV);
|
||||
createObject(OBJ_BUTTON, BUT_MENU_I_CFG);
|
||||
createObject(OBJ_BUTTON, BUT_MENU_T_CFG);
|
||||
createObject(OBJ_BUTTON, BUT_MENU_I_UTILS);
|
||||
createObject(OBJ_BUTTON, BUT_MENU_T_UTILS);
|
||||
createObject(OBJ_DRAWSTR, DSTR_MENU);
|
||||
newEvent(OBJ_WIN, WIN_MENU, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_OPTIONS:
|
||||
setOptionsData();
|
||||
createObject(OBJ_WIN, WIN_OPTIONS);
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
//createObject(OBJ_SWITCH, SW_OPT_TT_OFFSET);
|
||||
//createObject(OBJ_LABEL, LBL_OPT_TT_OFFSET);
|
||||
createObject(OBJ_SWITCH, SW_OPT_ADR);
|
||||
createObject(OBJ_LABEL, LBL_OPT_ADR);
|
||||
break;
|
||||
case CLIENT_XNET:
|
||||
//createObject(OBJ_SWITCH, SW_OPT_TT_OFFSET);
|
||||
//createObject(OBJ_LABEL, LBL_OPT_TT_OFFSET);
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
switchData[SW_OPT_DISCOVER].state = (autoIdentifyCS > 0) ? true : false;
|
||||
createObject(OBJ_SWITCH, SW_OPT_DISCOVER);
|
||||
createObject(OBJ_LABEL, LBL_OPT_DISCOVER);
|
||||
createObject(OBJ_RADIO, RAD_CSTATION);
|
||||
createObject(OBJ_LABEL, LBL_OPT_IB2);
|
||||
createObject(OBJ_LABEL, LBL_OPT_UHLI);
|
||||
createObject(OBJ_LABEL, LBL_OPT_DIG);
|
||||
break;
|
||||
case CLIENT_ECOS:
|
||||
break;
|
||||
}
|
||||
createObject(OBJ_BUTTON, BUT_OPT_OK);
|
||||
newEvent(OBJ_WIN, WIN_OPTIONS, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_SPEEDO:
|
||||
speedoSpeed = 0;
|
||||
speedoPhase = SPD_WAIT;
|
||||
setSpeedoPhase(SPD_WAIT);
|
||||
setTextSpeedo();
|
||||
snprintf(spdLengthBuf, NAME_LNG + 1, "%d", speedoLength);
|
||||
snprintf(spdSpeedBuf, NAME_LNG + 1, "%d km/h", speedoSpeed);
|
||||
iconData[ICON_SPEEDO_LOK].x = 40 + (speedoPhase * 32);
|
||||
drawStrData[DSTR_SPEEDO_BLANK].x = 40 + (speedoPhase * 32);
|
||||
lpicData[LPIC_SPEEDO].id = locoData[myLocoData].myLocoID;
|
||||
createObject(OBJ_WIN, WIN_SPEEDO);
|
||||
createObject(OBJ_LPIC, LPIC_SPEEDO);
|
||||
createObject(OBJ_LABEL, LBL_SCALE);
|
||||
createObject(OBJ_LABEL, LBL_MM);
|
||||
createObject(OBJ_GAUGE, GAUGE_SPEEDO);
|
||||
createObject(OBJ_FNC, FNC_SPEEDO_DIR);
|
||||
createObject(OBJ_DRAWSTR, DSTR_SPEEDO_BLANK);
|
||||
createObject(OBJ_DRAWSTR, DSTR_SPEEDO_TRK);
|
||||
createObject(OBJ_ICON, ICON_SPEEDO_LOK);
|
||||
createObject(OBJ_ICON, ICON_SPEEDO_RADAR);
|
||||
createObject(OBJ_BUTTON, BUT_SPEEDO_CNCL);
|
||||
createObject(OBJ_BUTTON, BUT_SPEEDO_CV);
|
||||
createObject(OBJ_TXT, TXT_SPEEDO_SCALE);
|
||||
createObject(OBJ_TXT, TXT_SPEEDO_LNG);
|
||||
createObject(OBJ_TXT, TXT_SPEEDO_SPD);
|
||||
newEvent(OBJ_WIN, WIN_SPEEDO, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_SPEEDO_LNG:
|
||||
snprintf(speedoKeybLng, PORT_LNG + 1, "%d", speedoLength);
|
||||
createObject(OBJ_WIN, WIN_SPEEDO_LNG);
|
||||
createObject(OBJ_TXT, TXT_EDIT_LNG);
|
||||
createObject(OBJ_KEYBOARD, KEYB_LNG);
|
||||
newEvent(OBJ_WIN, WIN_SPEEDO_LNG, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_SPEEDO_SCALE:
|
||||
setTextSpeedo();
|
||||
createObject(OBJ_WIN, WIN_SPEEDO_SCALE);
|
||||
createObject(OBJ_TXT, TXT_EDIT_SCALE);
|
||||
createObject(OBJ_TXT, TXT_NUM_SCALE);
|
||||
createObject(OBJ_KEYBOARD, KEYB_SCALE);
|
||||
createObject(OBJ_BUTTON, BUT_SPEEDO_H0);
|
||||
createObject(OBJ_BUTTON, BUT_SPEEDO_N);
|
||||
createObject(OBJ_BUTTON, BUT_SPEEDO_TT);
|
||||
createObject(OBJ_BUTTON, BUT_SPEEDO_Z);
|
||||
createObject(OBJ_BUTTON, BUT_SPEEDO_0);
|
||||
newEvent(OBJ_WIN, WIN_SPEEDO_SCALE, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_READ_CV:
|
||||
createObject(OBJ_WIN, WIN_READ_CV);
|
||||
createObject(OBJ_DRAWSTR, DSTR_CFG_MENU);
|
||||
createObject(OBJ_BUTTON, BUT_CV_ADDR);
|
||||
createObject(OBJ_BUTTON, BUT_CV_SPD_L);
|
||||
createObject(OBJ_BUTTON, BUT_CV_SPD_M);
|
||||
createObject(OBJ_BUTTON, BUT_CV_SPD_H);
|
||||
createObject(OBJ_BUTTON, BUT_CV_ACC);
|
||||
createObject(OBJ_BUTTON, BUT_CV_DEC);
|
||||
createObject(OBJ_BUTTON, BUT_CV_CFG);
|
||||
createObject(OBJ_BUTTON, BUT_CV_MAN);
|
||||
newEvent(OBJ_WIN, WIN_READ_CV, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_PROG_CV:
|
||||
//buttonData[BUT_CV_LNCV].backgnd = (wifiSetting.protocol == CLIENT_LNET) ? COLOR_CREAM : COLOR_LIGHTBLACK;
|
||||
setFieldsCV();
|
||||
setBitsCV();
|
||||
setStatusCV();
|
||||
switchData[SW_POM].state = modeProg;
|
||||
createObject(OBJ_WIN, WIN_PROG_CV);
|
||||
createObject(OBJ_LABEL, LBL_CV);
|
||||
createObject(OBJ_LABEL, LBL_POM);
|
||||
createObject(OBJ_LABEL, LBL_BITS);
|
||||
createObject(OBJ_SWITCH, SW_POM);
|
||||
createObject(OBJ_BUTTON, BUT_CV_READ);
|
||||
createObject(OBJ_BUTTON, BUT_CV_CNCL);
|
||||
if (wifiSetting.protocol == CLIENT_LNET)
|
||||
createObject(OBJ_BUTTON, BUT_CV_LNCV);
|
||||
createObject(OBJ_KEYBOARD, KEYB_CV);
|
||||
createObject(OBJ_CHAR, CHAR_CV_EQUAL);
|
||||
createObject(OBJ_BUTTON, BUT_CV_0);
|
||||
createObject(OBJ_BUTTON, BUT_CV_1);
|
||||
createObject(OBJ_BUTTON, BUT_CV_2);
|
||||
createObject(OBJ_BUTTON, BUT_CV_3);
|
||||
createObject(OBJ_BUTTON, BUT_CV_4);
|
||||
createObject(OBJ_BUTTON, BUT_CV_5);
|
||||
createObject(OBJ_BUTTON, BUT_CV_6);
|
||||
createObject(OBJ_BUTTON, BUT_CV_7);
|
||||
createObject(OBJ_TXT, TXT_CV);
|
||||
createObject(OBJ_TXT, TXT_CV_VAL);
|
||||
createObject(OBJ_TXT, TXT_CV_STATUS);
|
||||
newEvent(OBJ_WIN, WIN_PROG_CV, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_PROG_ADDR:
|
||||
getLabelTxt(LBL_CV_ADDR, buf);
|
||||
snprintf(cvStatusBuf, PWD_LNG + 1, "%s", buf);
|
||||
createObject(OBJ_WIN, WIN_PROG_ADDR);
|
||||
createObject(OBJ_TXT, TXT_CV_STATUS);
|
||||
createObject(OBJ_ICON, ICON_ADDR);
|
||||
createObject(OBJ_TXT, TXT_CV_ADDR);
|
||||
createObject(OBJ_KEYBOARD, KEYB_CV_ADDR);
|
||||
createObject(OBJ_BUTTON, BUT_ADDR_CNCL);
|
||||
newEvent(OBJ_WIN, WIN_PROG_ADDR, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_PROG_LNCV:
|
||||
setFieldsLNCV();
|
||||
createObject(OBJ_WIN, WIN_PROG_LNCV);
|
||||
createObject(OBJ_KEYBOARD, KEYB_LNCV);
|
||||
createObject(OBJ_LABEL, LBL_LNCV_ART);
|
||||
createObject(OBJ_LABEL, LBL_LNCV_MOD);
|
||||
createObject(OBJ_LABEL, LBL_LNCV_NUM);
|
||||
createObject(OBJ_BUTTON, BUT_LNCV_FIND);
|
||||
createObject(OBJ_BUTTON, BUT_LNCV_CNCL);
|
||||
createObject(OBJ_TXT, TXT_LNCV_ART);
|
||||
createObject(OBJ_TXT, TXT_LNCV_MOD);
|
||||
createObject(OBJ_TXT, TXT_LNCV_ADR);
|
||||
createObject(OBJ_TXT, TXT_LNCV_VAL);
|
||||
createObject(OBJ_CHAR, CHAR_LNCV_EQUAL);
|
||||
newEvent(OBJ_WIN, WIN_PROG_LNCV, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_STEAM:
|
||||
fncData[FNC_ST_SMOKE].state = false;
|
||||
createObject(OBJ_WIN, WIN_STEAM);
|
||||
createObject(OBJ_DRAWSTR, DSTR_STEAM);
|
||||
createObject(OBJ_ICON, ICON_POWER);
|
||||
createObject(OBJ_ICON, ICON_MANOMETER);
|
||||
createObject(OBJ_ICON, ICON_STEAM_EDIT);
|
||||
createObject(OBJ_BUTTON, BUT_STEAM_CNCL);
|
||||
createObject(OBJ_FNC, FNC_ST_WATER);
|
||||
createObject(OBJ_FNC, FNC_ST_TENDER);
|
||||
createObject(OBJ_FNC, FNC_ST_WHISTLE);
|
||||
createObject(OBJ_FNC, FNC_ST_FIRE);
|
||||
createObject(OBJ_FNC, FNC_ST_SMOKE);
|
||||
createObject(OBJ_BAR, BAR_JOHNSON);
|
||||
createObject(OBJ_BAR, BAR_WATER);
|
||||
createObject(OBJ_BAR, BAR_TENDER);
|
||||
createObject(OBJ_BAR, BAR_BRAKE);
|
||||
newEvent(OBJ_WIN, WIN_STEAM, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_UTIL:
|
||||
createObject(OBJ_WIN, WIN_UTIL);
|
||||
createObject(OBJ_BUTTON, BUT_UTL_I_SPEEDO);
|
||||
createObject(OBJ_BUTTON, BUT_UTL_T_SPEEDO);
|
||||
createObject(OBJ_BUTTON, BUT_UTL_I_STEAM);
|
||||
createObject(OBJ_BUTTON, BUT_UTL_T_STEAM);
|
||||
createObject(OBJ_BUTTON, BUT_UTL_I_SCAN);
|
||||
createObject(OBJ_BUTTON, BUT_UTL_T_SCAN);
|
||||
createObject(OBJ_BUTTON, BUT_UTL_I_STA);
|
||||
createObject(OBJ_BUTTON, BUT_UTL_T_STA);
|
||||
createObject(OBJ_ICON, ICON_UTL_EXIT);
|
||||
createObject(OBJ_DRAWSTR, DSTR_UTL_MENU);
|
||||
newEvent(OBJ_WIN, WIN_UTIL, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_ACCESSORY:
|
||||
editAccessory = false;
|
||||
winData[WIN_ACCESSORY].backgnd = COLOR_WHITE;
|
||||
updateAccPanel();
|
||||
createObject(OBJ_WIN, WIN_ACCESSORY);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_0);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_1);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_2);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_3);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_4);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_5);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_6);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_7);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_8);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_9);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_10);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_11);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_12);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_13);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_14);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_15);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_CNCL);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_EDIT);
|
||||
createObject(OBJ_TXT, TXT_ACC_0);
|
||||
createObject(OBJ_TXT, TXT_ACC_1);
|
||||
createObject(OBJ_TXT, TXT_ACC_2);
|
||||
createObject(OBJ_TXT, TXT_ACC_3);
|
||||
createObject(OBJ_TXT, TXT_ACC_4);
|
||||
createObject(OBJ_TXT, TXT_ACC_5);
|
||||
createObject(OBJ_TXT, TXT_ACC_6);
|
||||
createObject(OBJ_TXT, TXT_ACC_7);
|
||||
createObject(OBJ_TXT, TXT_ACC_8);
|
||||
createObject(OBJ_TXT, TXT_ACC_9);
|
||||
createObject(OBJ_TXT, TXT_ACC_10);
|
||||
createObject(OBJ_TXT, TXT_ACC_11);
|
||||
createObject(OBJ_TXT, TXT_ACC_12);
|
||||
createObject(OBJ_TXT, TXT_ACC_13);
|
||||
createObject(OBJ_TXT, TXT_ACC_14);
|
||||
createObject(OBJ_TXT, TXT_ACC_15);
|
||||
createObject(OBJ_TXT, TXT_PANEL);
|
||||
newEvent(OBJ_WIN, WIN_ACCESSORY, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_PANELS:
|
||||
createObject(OBJ_WIN, WIN_PANELS);
|
||||
createObject(OBJ_TXT, TXT_PANEL0);
|
||||
createObject(OBJ_TXT, TXT_PANEL1);
|
||||
createObject(OBJ_TXT, TXT_PANEL2);
|
||||
createObject(OBJ_TXT, TXT_PANEL3);
|
||||
createObject(OBJ_TXT, TXT_PANEL4);
|
||||
createObject(OBJ_TXT, TXT_PANEL5);
|
||||
createObject(OBJ_TXT, TXT_PANEL6);
|
||||
createObject(OBJ_TXT, TXT_PANEL7);
|
||||
createObject(OBJ_TXT, TXT_PANEL8);
|
||||
createObject(OBJ_TXT, TXT_PANEL9);
|
||||
createObject(OBJ_TXT, TXT_PANEL10);
|
||||
createObject(OBJ_TXT, TXT_PANEL11);
|
||||
createObject(OBJ_TXT, TXT_PANEL12);
|
||||
createObject(OBJ_TXT, TXT_PANEL13);
|
||||
createObject(OBJ_TXT, TXT_PANEL14);
|
||||
createObject(OBJ_TXT, TXT_PANEL15);
|
||||
newEvent(OBJ_WIN, WIN_PANELS, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_PANEL_NAME:
|
||||
snprintf(keybNameBuf, PANEL_LNG + 1, panelNameBuf);
|
||||
txtData[TXT_NAME].maxLength = PANEL_LNG;
|
||||
createObject(OBJ_WIN, WIN_PANEL_NAME);
|
||||
createObject(OBJ_TXT, TXT_NAME);
|
||||
createObject(OBJ_KEYBOARD, KEYB_NAME);
|
||||
createObject(OBJ_BUTTON, BUT_NAME_OK);
|
||||
createObject(OBJ_BUTTON, BUT_NAME_CNCL);
|
||||
newEvent(OBJ_WIN, WIN_PANEL_NAME, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_ACC_CTRL:
|
||||
snprintf(accKeybAddr, ADDR_LNG + 1, "%d", myTurnout);
|
||||
createObject(OBJ_WIN, WIN_ACC_CTRL);
|
||||
createObject(OBJ_TXT, TXT_ACC_ADDR);
|
||||
createObject(OBJ_KEYBOARD, KEYB_ACC);
|
||||
createObject(OBJ_ICON, ICON_KEYB_ACC);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_RED);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_GREEN);
|
||||
newEvent(OBJ_WIN, WIN_ACC_CTRL, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_ACC_ASPECT:
|
||||
createObject(OBJ_WIN, WIN_ACC_ASPECT);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_ASPECT0);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_ASPECT1);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_ASPECT2);
|
||||
if (currAccAspects == 4)
|
||||
createObject(OBJ_BUTTON, BUT_ACC_ASPECT3);
|
||||
newEvent(OBJ_WIN, WIN_ACC_ASPECT, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_ACC_TYPE:
|
||||
createObject(OBJ_WIN, WIN_ACC_TYPE);
|
||||
createObject(OBJ_LABEL, LBL_ACC_TYPE);
|
||||
createObject(OBJ_FNC, FNC_ACC_TYPE);
|
||||
newEvent(OBJ_WIN, WIN_ACC_TYPE, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_ACC_EDIT:
|
||||
n = accDef[currAccEdit.type].aspects;
|
||||
winData[WIN_ACC_EDIT].h = 130 + (n * 40);
|
||||
buttonData[BUT_TYPE_OK].y = 93 + (n * 40);
|
||||
buttonData[BUT_TYPE_CNCL].y = 93 + (n * 40);
|
||||
iconData[ICON_TYPE_OK].y = 97 + (n * 40);
|
||||
iconData[ICON_TYPE_CNCL].y = 97 + (n * 40);
|
||||
createObject(OBJ_WIN, WIN_ACC_EDIT);
|
||||
createObject(OBJ_LABEL, LBL_ACC_NAME);
|
||||
createObject(OBJ_LABEL, LBL_ACC_ADDR);
|
||||
createObject(OBJ_TXT, TXT_ACC_NAME);
|
||||
createObject(OBJ_TXT, TXT_ACC_ADDR1);
|
||||
createObject(OBJ_FNC, FNC_EDIT_ASPECT0);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT0);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT1);
|
||||
if (n > 1) {
|
||||
createObject(OBJ_FNC, FNC_EDIT_ASPECT1);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT4);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT5);
|
||||
}
|
||||
if (n > 2) {
|
||||
createObject(OBJ_TXT, TXT_ACC_ADDR2);
|
||||
createObject(OBJ_ICON, ICON_PLUS_ONE);
|
||||
createObject(OBJ_FNC, FNC_EDIT_ASPECT2);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT2);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT3);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT6);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT7);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT8);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT9);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT10);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT11);
|
||||
}
|
||||
if (n > 3) {
|
||||
createObject(OBJ_FNC, FNC_EDIT_ASPECT3);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT12);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT13);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT14);
|
||||
createObject(OBJ_BUTTON, BUT_ACC_OUT15);
|
||||
}
|
||||
createObject(OBJ_BUTTON, BUT_TYPE_OK);
|
||||
createObject(OBJ_BUTTON, BUT_TYPE_CNCL);
|
||||
newEvent(OBJ_WIN, WIN_ACC_EDIT, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_ACC_NAME:
|
||||
snprintf(keybNameBuf, ACC_LNG + 1, accKeybName);
|
||||
txtData[TXT_NAME].maxLength = ACC_LNG;
|
||||
createObject(OBJ_WIN, WIN_ACC_NAME);
|
||||
createObject(OBJ_TXT, TXT_NAME);
|
||||
createObject(OBJ_KEYBOARD, KEYB_NAME);
|
||||
createObject(OBJ_BUTTON, BUT_NAME_OK);
|
||||
createObject(OBJ_BUTTON, BUT_NAME_CNCL);
|
||||
newEvent(OBJ_WIN, WIN_ACC_NAME, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_ACC_ADDR1:
|
||||
snprintf(accKeybAdrEdit, ADDR_LNG + 1, "%d", currAccEdit.addr);
|
||||
createObject(OBJ_WIN, WIN_ACC_ADDR1);
|
||||
createObject(OBJ_TXT, TXT_ACC_EDIT);
|
||||
createObject(OBJ_KEYBOARD, KEYB_ACC_ADDR);
|
||||
newEvent(OBJ_WIN, WIN_ACC_ADDR1, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_ACC_ADDR2:
|
||||
snprintf(accKeybAdrEdit, ADDR_LNG + 1, "%d", currAccEdit.addr2);
|
||||
createObject(OBJ_WIN, WIN_ACC_ADDR2);
|
||||
createObject(OBJ_TXT, TXT_ACC_EDIT);
|
||||
createObject(OBJ_KEYBOARD, KEYB_ACC_ADDR);
|
||||
newEvent(OBJ_WIN, WIN_ACC_ADDR2, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_WIFI_SCAN:
|
||||
setTimer(TMR_SCAN, 5, TMR_ONESHOT);
|
||||
createObject(OBJ_WIN, WIN_WIFI_SCAN);
|
||||
createObject(OBJ_DRAWSTR, DSTR_WIFI_SCAN);
|
||||
createObject(OBJ_LABEL, LBL_SSID_SCAN);
|
||||
createObject(OBJ_FNC, FNC_SCAN_RESET);
|
||||
newEvent(OBJ_WIN, WIN_WIFI_SCAN, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_STA_RUN:
|
||||
updateStationTime(staTime);
|
||||
updateStationLevel();
|
||||
updateStationStars();
|
||||
updateTargetStations();
|
||||
createObject(OBJ_WIN, WIN_STA_RUN);
|
||||
createObject(OBJ_LABEL, LBL_STA_RUN);
|
||||
createObject(OBJ_LABEL, LBL_STA_LEVEL);
|
||||
createObject(OBJ_LABEL, LBL_STA_INSTR);
|
||||
createObject(OBJ_FNC, FNC_STA_STARS);
|
||||
createObject(OBJ_ICON, ICON_STA_CLOCK);
|
||||
createObject(OBJ_ICON, ICON_STA_STATION);
|
||||
createObject(OBJ_ICON, ICON_STA_EDIT);
|
||||
createObject(OBJ_BUTTON, BUT_STA_START);
|
||||
createObject(OBJ_BUTTON, BUT_STA_CNCL);
|
||||
createObject(OBJ_TXT, TXT_STA_LEVEL);
|
||||
createObject(OBJ_TXT, TXT_STA_STARS);
|
||||
createObject(OBJ_TXT, TXT_STA_STATION);
|
||||
createObject(OBJ_TXT, TXT_STA_CLOCK);
|
||||
newEvent(OBJ_WIN, WIN_STA_RUN, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_STA_PLAY:
|
||||
updateTurnoutButtons();
|
||||
fncData[FNC_STA_RAYO].state = isTrackOff();
|
||||
createObject(OBJ_WIN, WIN_STA_PLAY);
|
||||
createObject(OBJ_DRAWSTR, DSTR_STATION_PLAY);
|
||||
createObject(OBJ_ICON, ICON_STA_TARGET);
|
||||
createObject(OBJ_ICON, ICON_STA_TRAIN);
|
||||
createObject(OBJ_ICON, ICON_STA_PIN);
|
||||
createObject(OBJ_ICON, ICON_STA_TIME);
|
||||
createObject(OBJ_ICON, ICON_STA_COUNT);
|
||||
createObject(OBJ_TXT, TXT_STA_TIME);
|
||||
createObject(OBJ_TXT, TXT_STA_COUNT);
|
||||
createObject(OBJ_TXT, TXT_STA_STARC);
|
||||
createObject(OBJ_GAUGE, GAUGE_STATION);
|
||||
createObject(OBJ_FNC, FNC_STA_DIR);
|
||||
createObject(OBJ_FNC, FNC_STA_STARC);
|
||||
createObject(OBJ_FNC, FNC_STA_RAYO);
|
||||
createObject(OBJ_BUTTON, BUT_STA_STOP);
|
||||
switch (staMaxTurnout) {
|
||||
case 1:
|
||||
fncData[FNC_STA_ACC0].x = 104;
|
||||
buttonData[BUT_STA_ACC0].x = 100;
|
||||
createObject(OBJ_BUTTON, BUT_STA_ACC0);
|
||||
break;
|
||||
case 2:
|
||||
fncData[FNC_STA_ACC0].x = 54;
|
||||
fncData[FNC_STA_ACC1].x = 154;
|
||||
buttonData[BUT_STA_ACC0].x = 50;
|
||||
buttonData[BUT_STA_ACC1].x = 150;
|
||||
createObject(OBJ_BUTTON, BUT_STA_ACC0);
|
||||
createObject(OBJ_BUTTON, BUT_STA_ACC1);
|
||||
break;
|
||||
case 3:
|
||||
fncData[FNC_STA_ACC0].x = 40;
|
||||
fncData[FNC_STA_ACC1].x = 104;
|
||||
fncData[FNC_STA_ACC2].x = 168;
|
||||
buttonData[BUT_STA_ACC0].x = 36;
|
||||
buttonData[BUT_STA_ACC1].x = 100;
|
||||
buttonData[BUT_STA_ACC2].x = 164;
|
||||
createObject(OBJ_BUTTON, BUT_STA_ACC0);
|
||||
createObject(OBJ_BUTTON, BUT_STA_ACC1);
|
||||
createObject(OBJ_BUTTON, BUT_STA_ACC2);
|
||||
break;
|
||||
default:
|
||||
fncData[FNC_STA_ACC0].x = 20;
|
||||
fncData[FNC_STA_ACC1].x = 76;
|
||||
fncData[FNC_STA_ACC2].x = 132;
|
||||
fncData[FNC_STA_ACC3].x = 188;
|
||||
buttonData[BUT_STA_ACC0].x = 16;
|
||||
buttonData[BUT_STA_ACC1].x = 72;
|
||||
buttonData[BUT_STA_ACC2].x = 128;
|
||||
buttonData[BUT_STA_ACC3].x = 184;
|
||||
createObject(OBJ_BUTTON, BUT_STA_ACC0);
|
||||
createObject(OBJ_BUTTON, BUT_STA_ACC1);
|
||||
createObject(OBJ_BUTTON, BUT_STA_ACC2);
|
||||
createObject(OBJ_BUTTON, BUT_STA_ACC3);
|
||||
break;
|
||||
}
|
||||
newEvent(OBJ_WIN, WIN_STA_PLAY, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_STA_STARS:
|
||||
createObject(OBJ_WIN, WIN_STA_STARS);
|
||||
if (staCurrTime > 0) {
|
||||
staStars++;
|
||||
createObject(OBJ_FNC, FNC_STA_STAR1);
|
||||
if (staCurrTime > 10) { // time remaining
|
||||
staStars++;
|
||||
createObject(OBJ_FNC, FNC_STA_STAR2);
|
||||
createObject(OBJ_LABEL, LBL_STA_EXCEL);
|
||||
}
|
||||
else {
|
||||
createObject(OBJ_LABEL, LBL_STA_GREAT);
|
||||
}
|
||||
updateStationStars();
|
||||
}
|
||||
else {
|
||||
createObject(OBJ_ICON, ICON_STA_TIMEOUT);
|
||||
createObject(OBJ_LABEL, LBL_STA_TIMEOUT);
|
||||
}
|
||||
newEvent(OBJ_WIN, WIN_STA_STARS, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_STA_EDIT:
|
||||
snprintf(staStartTimeBuf, IP_LNG + 1, "%d", staStartTime);
|
||||
snprintf(staStatNumBuf, IP_LNG + 1, "%d", staMaxStations);
|
||||
snprintf(staTurnNumBuf, IP_LNG + 1, "%d", staMaxTurnout);
|
||||
snprintf(staTurnout1Buf, ADDR_LNG + 1, "%d", staTurnoutAdr1);
|
||||
snprintf(staTurnout2Buf, ADDR_LNG + 1, "%d", staTurnoutAdr2);
|
||||
snprintf(staTurnout3Buf, ADDR_LNG + 1, "%d", staTurnoutAdr3);
|
||||
snprintf(staTurnout4Buf, ADDR_LNG + 1, "%d", staTurnoutAdr4);
|
||||
for (n = 0; n < 8; n++)
|
||||
switchData[SW_STA_OR1 + n].state = bitRead(staTurnoutDef, n);
|
||||
createObject(OBJ_WIN, WIN_STA_EDIT);
|
||||
createObject(OBJ_LABEL, LBL_STA_STATIONS);
|
||||
createObject(OBJ_LABEL, LBL_STA_TURNOUTS);
|
||||
createObject(OBJ_LABEL, LBL_STA_TIME);
|
||||
createObject(OBJ_LABEL, LBL_STA_DESC);
|
||||
createObject(OBJ_TXT, TXT_STA_STARTTIME);
|
||||
createObject(OBJ_TXT, TXT_STA_STATNUM);
|
||||
createObject(OBJ_TXT, TXT_STA_TURNNUM);
|
||||
createObject(OBJ_TXT, TXT_STA_TURNOUT1);
|
||||
createObject(OBJ_TXT, TXT_STA_TURNOUT2);
|
||||
createObject(OBJ_TXT, TXT_STA_TURNOUT3);
|
||||
createObject(OBJ_TXT, TXT_STA_TURNOUT4);
|
||||
createObject(OBJ_BUTTON, BUT_STA_EDIT);
|
||||
createObject(OBJ_SWITCH, SW_STA_OR1);
|
||||
createObject(OBJ_SWITCH, SW_STA_OR2);
|
||||
createObject(OBJ_SWITCH, SW_STA_OR3);
|
||||
createObject(OBJ_SWITCH, SW_STA_OR4);
|
||||
createObject(OBJ_SWITCH, SW_STA_INV1);
|
||||
createObject(OBJ_SWITCH, SW_STA_INV2);
|
||||
createObject(OBJ_SWITCH, SW_STA_INV3);
|
||||
createObject(OBJ_SWITCH, SW_STA_INV4);
|
||||
createObject(OBJ_BUTTON, BUT_STA_STAM);
|
||||
createObject(OBJ_BUTTON, BUT_STA_STAP);
|
||||
createObject(OBJ_BUTTON, BUT_STA_TURNM);
|
||||
createObject(OBJ_BUTTON, BUT_STA_TURNP);
|
||||
newEvent(OBJ_WIN, WIN_STA_EDIT, EVNT_DRAW);
|
||||
break;
|
||||
case WIN_STA_KEYB:
|
||||
createObject(OBJ_WIN, WIN_STA_KEYB);
|
||||
createObject(OBJ_KEYBOARD, KEYB_STA);
|
||||
newEvent(OBJ_WIN, WIN_STA_KEYB, EVNT_DRAW);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void alertWindow(byte err) {
|
||||
errType = err;
|
||||
createObject(OBJ_WIN, WIN_ALERT);
|
||||
switch (err) {
|
||||
case ERR_SERV:
|
||||
createObject(OBJ_ICON, ICON_WARNING);
|
||||
createObject(OBJ_ICON, ICON_WARNING_ON);
|
||||
createObject(OBJ_LABEL, LBL_SERVICE);
|
||||
break;
|
||||
case ERR_CHG_WIFI:
|
||||
createObject(OBJ_ICON, ICON_INFO);
|
||||
createObject(OBJ_LABEL, LBL_CHG_WIFI);
|
||||
break;
|
||||
case ERR_FULL:
|
||||
createObject(OBJ_ICON, ICON_WARNING);
|
||||
createObject(OBJ_ICON, ICON_WARNING_ON);
|
||||
createObject(OBJ_LABEL, LBL_STACK_FULL);
|
||||
break;
|
||||
case ERR_STOP:
|
||||
createObject(OBJ_ICON, ICON_ESTOP);
|
||||
createObject(OBJ_LABEL, LBL_ESTOP);
|
||||
break;
|
||||
case ERR_WAIT:
|
||||
case ERR_CV:
|
||||
barData[BAR_WAIT].value = 0;
|
||||
setTimer(TMR_WAIT, 5, TMR_ONESHOT);
|
||||
if (err == ERR_WAIT)
|
||||
createObject(OBJ_ICON, ICON_WAIT);
|
||||
else
|
||||
createObject(OBJ_ICON, ICON_WAIT_CV);
|
||||
createObject(OBJ_BAR, BAR_WAIT);
|
||||
break;
|
||||
case ERR_ASK_SURE:
|
||||
createObject(OBJ_ICON, ICON_WARNING);
|
||||
createObject(OBJ_ICON, ICON_WARNING_ON);
|
||||
createObject(OBJ_LABEL, LBL_ASK_SURE);
|
||||
createObject(OBJ_BUTTON, BUT_SURE_OK);
|
||||
createObject(OBJ_BUTTON, BUT_SURE_CNCL);
|
||||
break;
|
||||
}
|
||||
newEvent(OBJ_WIN, WIN_ALERT, EVNT_DRAW);
|
||||
}
|
||||
648
PacoMouseCYD/Platformio/Arduino.old/xnet.ino
Normal file
648
PacoMouseCYD/Platformio/Arduino.old/xnet.ino
Normal file
@@ -0,0 +1,648 @@
|
||||
/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
|
||||
|
||||
This software and associated files are a DIY project that is not intended for commercial use.
|
||||
This software uses libraries with different licenses, follow all their different terms included.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
|
||||
|
||||
Sources are only provided for building and uploading to the device.
|
||||
You are not allowed to modify the source code or fork/publish this project.
|
||||
Commercial use is forbidden.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** XPRESSNET LAN SOPORTE *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void showErrorXnet() { // muestra pantalla de error
|
||||
if (csStatus & csEmergencyOff) {
|
||||
iconData[ICON_POWER].color = COLOR_RED;
|
||||
setTimer (TMR_POWER, 5, TMR_PERIODIC); // Flash power icon
|
||||
if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
|
||||
newEvent(OBJ_ICON, ICON_POWER, EVNT_DRAW);
|
||||
if (isWindow(WIN_STA_PLAY)) {
|
||||
fncData[FNC_STA_RAYO].state = true;
|
||||
newEvent(OBJ_FNC, FNC_STA_RAYO, EVNT_DRAW);
|
||||
}
|
||||
}
|
||||
if (csStatus & csServiceMode) {
|
||||
if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
|
||||
alertWindow(ERR_SERV);
|
||||
}
|
||||
if (csStatus & csEmergencyStop) {
|
||||
if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
|
||||
alertWindow(ERR_STOP);
|
||||
}
|
||||
}
|
||||
|
||||
void showNormalOpsXnet() {
|
||||
stopTimer (TMR_POWER);
|
||||
iconData[ICON_POWER].color = COLOR_GREEN;
|
||||
if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
|
||||
newEvent(OBJ_ICON, ICON_POWER, EVNT_DRAW);
|
||||
if (isWindow(WIN_STA_PLAY)) {
|
||||
fncData[FNC_STA_RAYO].state = false;
|
||||
newEvent(OBJ_FNC, FNC_STA_RAYO, EVNT_DRAW);
|
||||
}
|
||||
if (isWindow(WIN_ALERT)) {
|
||||
switch (errType) {
|
||||
case ERR_SERV:
|
||||
case ERR_STOP:
|
||||
case ERR_CV:
|
||||
closeWindow(WIN_ALERT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t addrXnet(uint16_t adr) {
|
||||
if (adr > 99) // Comprueba si es direccion larga
|
||||
adr |= 0xC000;
|
||||
return adr;
|
||||
}
|
||||
|
||||
|
||||
bool isRecentMM () { // Comprueba central Multimaus reciente
|
||||
if ((xnetCS == 0x10) && (highVerMM > 0) && (lowVerMM > 0x02))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** XPRESSNET LAN MESSAGES *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void getStatusXnet () {
|
||||
headerXN (0x21); // Command station status request (0x21,0x24,0x05)
|
||||
dataXN (0x24);
|
||||
sendXN();
|
||||
}
|
||||
|
||||
|
||||
void getVersionXnet () {
|
||||
headerXN (0x21); // Command station software version (0x21,0x21,0x00)
|
||||
dataXN (0x21);
|
||||
sendXN();
|
||||
}
|
||||
|
||||
void versionMultimaus() {
|
||||
headerXN (0xF1); // Multimaus software version (0xF1,0x0A,XOR)
|
||||
dataXN (0x0A);
|
||||
sendXN();
|
||||
}
|
||||
|
||||
|
||||
void getResultsXnet() {
|
||||
headerXN (0x21); // Request for Service Mode results (0x21,0x10,0x31)
|
||||
dataXN (0x10);
|
||||
sendXN();
|
||||
//getResultsSM = false;
|
||||
}
|
||||
|
||||
|
||||
void resumeOperationsXnet () {
|
||||
headerXN (0x21); // Resume operations request (0x21,0x81,0xA0)
|
||||
dataXN (0x81);
|
||||
sendXN();
|
||||
}
|
||||
|
||||
|
||||
void emergencyOffXnet() {
|
||||
headerXN (0x21); // Stop operations request (emergency off)(0x21,0x80,0xA1)
|
||||
dataXN (0x80);
|
||||
sendXN();
|
||||
}
|
||||
|
||||
|
||||
void infoLocomotoraXnet (unsigned int loco) { // Locomotive information request (0xE3,0x00,ADRH,ADRL,XOR)
|
||||
uint16_t adr;
|
||||
adr = addrXnet(loco);
|
||||
headerXN (0xE3);
|
||||
dataXN (0x00);
|
||||
dataXN (highByte(adr));
|
||||
dataXN (lowByte (adr));
|
||||
sendXN();
|
||||
if ((xnetVersion > 0x35) || (xnetCS == 0x10)) {
|
||||
headerXN (0xE3);
|
||||
if (xnetCS == 0x10)
|
||||
dataXN (0xF0); // Locomotive function F13..F20 info MM (0xE3,0xF0,ADRH,ADRL,XOR)
|
||||
else
|
||||
dataXN (0x09); // Locomotive function F13..F28 info v3.6 (0xE3,0x09,ADRH,ADRL,XOR)
|
||||
dataXN (highByte(adr));
|
||||
dataXN (lowByte (adr));
|
||||
sendXN();
|
||||
}
|
||||
getInfoLoco = false;
|
||||
}
|
||||
|
||||
|
||||
void locoOperationSpeedXnet() { // Locomotive speed and direction operations (0xE4,ID,ADRH,ADRL,SPD,XOR)
|
||||
uint16_t adr;
|
||||
adr = addrXnet(locoData[myLocoData].myAddr.address);
|
||||
headerXN (0xE4);
|
||||
if (bitRead(locoData[myLocoData].mySteps, 2)) { // 128 steps
|
||||
dataXN (0x13);
|
||||
}
|
||||
else {
|
||||
if (bitRead(locoData[myLocoData].mySteps, 1)) { // 28 steps
|
||||
dataXN (0x12);
|
||||
}
|
||||
else {
|
||||
dataXN (0x10); // 14 steps
|
||||
}
|
||||
}
|
||||
dataXN (highByte(adr));
|
||||
dataXN (lowByte(adr));
|
||||
dataXN (locoData[myLocoData].mySpeed | locoData[myLocoData].myDir);
|
||||
sendXN();
|
||||
bitClear(locoData[myLocoData].mySteps, 3); // currently operated by me
|
||||
updateSpeedDir();
|
||||
}
|
||||
|
||||
|
||||
void funcOperationsXnet (byte fnc) { // Function operation instructions (0xE4,ID,ADRH,ADRL,GRP,XOR)
|
||||
byte grp, grpID;
|
||||
uint16_t adr;
|
||||
adr = addrXnet(locoData[myLocoData].myAddr.address);
|
||||
if (fnc > 20) {
|
||||
grpID = 0x28; // F21..F28
|
||||
grp = ((locoData[myLocoData].myFunc.xFunc[2] >> 5) & 0x07);
|
||||
grp |= (locoData[myLocoData].myFunc.xFunc[3] << 3);
|
||||
}
|
||||
else {
|
||||
if (fnc > 12) {
|
||||
if (xnetCS == 0x10)
|
||||
grpID = 0xF3; // F13..F20 MM (0xE4,0xF3,ADH,ADL,F13F20,XOR)
|
||||
else
|
||||
grpID = 0x23; // F13..F20
|
||||
grp = ((locoData[myLocoData].myFunc.xFunc[1] >> 5) & 0x07);
|
||||
grp |= (locoData[myLocoData].myFunc.xFunc[2] << 3);
|
||||
}
|
||||
else {
|
||||
if (fnc > 8) {
|
||||
grpID = 0x22; // F9..F12
|
||||
grp = ((locoData[myLocoData].myFunc.xFunc[1] >> 1) & 0x0F);
|
||||
}
|
||||
else {
|
||||
if (fnc > 4) {
|
||||
grpID = 0x21; // F5..F8
|
||||
grp = ((locoData[myLocoData].myFunc.xFunc[0] >> 5) & 0x07);
|
||||
if (bitRead(locoData[myLocoData].myFunc.xFunc[1], 0))
|
||||
grp |= 0x08;
|
||||
}
|
||||
else {
|
||||
grpID = 0x20; // F0..F4
|
||||
grp = ((locoData[myLocoData].myFunc.xFunc[0] >> 1) & 0x0F);
|
||||
if (bitRead(locoData[myLocoData].myFunc.xFunc[0], 0))
|
||||
grp |= 0x10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
headerXN (0xE4);
|
||||
dataXN (grpID);
|
||||
dataXN (highByte(adr));
|
||||
dataXN (lowByte(adr));
|
||||
dataXN (grp);
|
||||
sendXN();
|
||||
bitClear(locoData[myLocoData].mySteps, 3); // currently operated by me
|
||||
}
|
||||
|
||||
|
||||
byte getCurrentStepXnet() {
|
||||
byte currStep;
|
||||
if (bitRead(locoData[myLocoData].mySteps, 2)) { // 128 steps -> 0..126
|
||||
if (locoData[myLocoData].mySpeed > 1)
|
||||
return (locoData[myLocoData].mySpeed - 1);
|
||||
}
|
||||
else {
|
||||
if (bitRead(locoData[myLocoData].mySteps, 1)) { // 28 steps -> 0..28 '---04321' -> '---43210'
|
||||
currStep = (locoData[myLocoData].mySpeed << 1) & 0x1F;
|
||||
bitWrite(currStep, 0, bitRead(locoData[myLocoData].mySpeed, 4));
|
||||
if (currStep > 3)
|
||||
return (currStep - 3);
|
||||
}
|
||||
else { // 14 steps -> 0..14
|
||||
if (locoData[myLocoData].mySpeed > 1)
|
||||
return (locoData[myLocoData].mySpeed - 1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
void setAccessoryXnet (unsigned int direccion, bool activa, byte posicion) { // 1..1024
|
||||
byte adr, dato;
|
||||
direccion--; // 000000AAAAAAAABB
|
||||
adr = (direccion >> 2) & 0x00FF; // AAAAAAAA
|
||||
dato = ((direccion & 0x0003) << 1) | 0x80; // 1000xBBx
|
||||
if (posicion > 0)
|
||||
dato |= 0x01;
|
||||
if (activa) { // 1000dBBD
|
||||
dato |= 0x08;
|
||||
}
|
||||
headerXN (0x52); // Accessory Decoder operation request (0x52,AAAAAAAA,1000dBBD,XOR)
|
||||
dataXN (adr);
|
||||
dataXN (dato);
|
||||
sendXN();
|
||||
}
|
||||
|
||||
|
||||
void setTimeXnet(byte hh, byte mm, byte rate) {
|
||||
clockHour = hh;
|
||||
clockMin = mm;
|
||||
clockRate = rate;
|
||||
if (rate > 0) {
|
||||
headerXN (0x24); // set clock
|
||||
dataXN (0x2B);
|
||||
dataXN (hh);
|
||||
dataXN (mm);
|
||||
dataXN (rate);
|
||||
sendXN ();
|
||||
/*
|
||||
headerXN (0x21); // start clock
|
||||
dataXN (0x2C);
|
||||
sendXN (0x07);
|
||||
*/
|
||||
}
|
||||
else {
|
||||
headerXN (0x21); // recommended for rate=0. stop clock
|
||||
dataXN (0x2D);
|
||||
sendXN ();
|
||||
}
|
||||
}
|
||||
|
||||
void readCVXnet (unsigned int adr, byte stepPrg) {
|
||||
if (!modeProg) { // Read only in Direct mode
|
||||
if (isRecentMM()) {
|
||||
headerXN (0x23); // Multimaus v1.03
|
||||
dataXN (0x15);
|
||||
adr--;
|
||||
dataXN (highByte(adr) & 0x03);
|
||||
dataXN (lowByte(adr));
|
||||
sendXN();
|
||||
lastCV = lowByte(adr) + 1;
|
||||
}
|
||||
else {
|
||||
headerXN (0x22);
|
||||
if (xnetVersion > 0x35)
|
||||
dataXN (0x18 | (highByte(adr) & 0x03)); // v3.6 & up CV1..CV1024
|
||||
else
|
||||
dataXN (0x15); // v3.0 CV1..CV256
|
||||
dataXN (lowByte(adr));
|
||||
sendXN();
|
||||
lastCV = lowByte(adr);
|
||||
}
|
||||
getResultsSM = true;
|
||||
infoTimer = millis();
|
||||
progStepCV = stepPrg;
|
||||
//DEBUG_MSG("Read CV %d", adr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void writeCVXnet (unsigned int adr, unsigned int data, byte stepPrg) {
|
||||
uint16_t adrLoco;
|
||||
if (modeProg) {
|
||||
headerXN (0xE6); // Operations Mode Programming byte mode write request (0xE6,0x30,ADRH,ADRL,0xEC+C,CV,DATA,XOR)
|
||||
dataXN (0x30);
|
||||
adrLoco = addrXnet(locoData[myLocoData].myAddr.address);
|
||||
dataXN (highByte(adrLoco));
|
||||
dataXN (lowByte(adrLoco));
|
||||
adr--;
|
||||
dataXN (0xEC | (highByte(adr) & 0x03));
|
||||
dataXN (lowByte(adr));
|
||||
dataXN(data);
|
||||
sendXN();
|
||||
}
|
||||
else {
|
||||
if (isRecentMM()) {
|
||||
headerXN (0x24); // Multimaus v1.03
|
||||
dataXN (0x16);
|
||||
adr--;
|
||||
dataXN (highByte(adr) & 0x03);
|
||||
dataXN (lowByte(adr));
|
||||
dataXN(data);
|
||||
sendXN();
|
||||
lastCV = lowByte(adr) + 1;
|
||||
}
|
||||
else {
|
||||
headerXN (0x23);
|
||||
if (xnetVersion > 0x35)
|
||||
dataXN (0x1C | (highByte(adr) & 0x03)); // v3.6 & up CV1..CV1024
|
||||
else
|
||||
dataXN (0x16); // v3.0 CV1..CV256
|
||||
dataXN (lowByte(adr));
|
||||
dataXN(data);
|
||||
sendXN();
|
||||
lastCV = lowByte(adr);
|
||||
}
|
||||
getResultsSM = true;
|
||||
infoTimer = millis();
|
||||
}
|
||||
progStepCV = stepPrg;
|
||||
//DEBUG_MSG("Write CV%d = %d", adr, data);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** XPRESSNET LAN DECODE *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void headerXN (byte header) {
|
||||
txBytes = HEADER; // coloca header en el buffer
|
||||
txXOR = header;
|
||||
txBuffer[txBytes++] = header;
|
||||
txBuffer[FRAME1] = 0xFF;
|
||||
txBuffer[FRAME2] = 0xFE;
|
||||
}
|
||||
|
||||
|
||||
void dataXN (byte dato) {
|
||||
txBuffer[txBytes++] = dato; // coloca dato en el buffer
|
||||
txXOR ^= dato;
|
||||
}
|
||||
|
||||
|
||||
void sendXN () {
|
||||
bool recvAnswer;
|
||||
txBuffer[txBytes++] = txXOR; // coloca XOR byte en el buffer
|
||||
#ifdef DEBUG
|
||||
Serial.print(F("TX: "));
|
||||
for (uint8_t x = 0; x < txBytes; x++) {
|
||||
uint8_t val = txBuffer[x];
|
||||
if (val < 16)
|
||||
Serial.print('0');
|
||||
Serial.print(val, HEX);
|
||||
Serial.print(' ');
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
Client.write((byte *)&txBuffer[FRAME1], txBytes); // envia paquete xpressnet
|
||||
timeoutXnet = millis();
|
||||
recvAnswer = false;
|
||||
while ((millis() - timeoutXnet < 500) && (!recvAnswer)) // wait answer for 500ms
|
||||
recvAnswer = xnetReceive();
|
||||
}
|
||||
|
||||
|
||||
bool xnetReceive() {
|
||||
bool getAnswer;
|
||||
getAnswer = false;
|
||||
while (Client.available()) {
|
||||
rxData = Client.read();
|
||||
//DEBUG_MSG("%d-%02X", rxIndice, rxData);
|
||||
switch (rxIndice) {
|
||||
case FRAME1:
|
||||
rxBufferXN[FRAME1] = rxData;
|
||||
if (rxData == 0xFF) // 0xFF... Posible inicio de paquete
|
||||
rxIndice = FRAME2;
|
||||
break;
|
||||
case FRAME2:
|
||||
rxBufferXN[FRAME2] = rxData;
|
||||
switch (rxData) {
|
||||
case 0xFF: // 0xFF 0xFF... FRAME2 puede ser FRAME1 (inicio de otro paquete)
|
||||
break;
|
||||
case 0xFE: // 0xFF 0xFE... Inicio paquete correcto
|
||||
case 0xFD: // 0xFF 0xFD... Inicio paquete de broadcast correcto
|
||||
rxIndice = HEADER;
|
||||
rxXOR = 0;
|
||||
break;
|
||||
default: // 0xFF 0xXX... No es inicio de paquete
|
||||
rxIndice = FRAME1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rxBufferXN[rxIndice++] = rxData;
|
||||
rxXOR ^= rxData;
|
||||
if (((rxBufferXN[HEADER] & 0x0F) + 4) == rxIndice) { // si se han recibido todos los datos indicados en el paquete
|
||||
if (rxXOR == 0) { // si el paquete es correcto
|
||||
rxBytes = rxIndice;
|
||||
#ifdef DEBUG
|
||||
Serial.print(F("RX: "));
|
||||
for (uint8_t x = 0; x < rxBytes; x++) {
|
||||
uint8_t val = rxBufferXN[x];
|
||||
if (val < 16)
|
||||
Serial.print('0');
|
||||
Serial.print(val, HEX);
|
||||
Serial.print(' ');
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
procesaXN(); // nuevo paquete recibido, procesarlo
|
||||
getAnswer = true;
|
||||
}
|
||||
rxIndice = FRAME1; // proximo paquete
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return getAnswer;
|
||||
}
|
||||
|
||||
void processXnet () { // procesa Xpressnet
|
||||
xnetReceive();
|
||||
if (getInfoLoco && (csStatus == csNormalOps))
|
||||
infoLocomotoraXnet(addrXnet(locoData[myLocoData].myAddr.address));
|
||||
if (millis() - infoTimer > 1000UL) { // Cada segundo
|
||||
infoTimer = millis();
|
||||
if (getResultsSM) // Resultados de CV pendientes
|
||||
getResultsXnet(); // pide resultados
|
||||
else {
|
||||
if (bitRead(locoData[myLocoData].mySteps, 3)) // Loco controlada por otro mando
|
||||
getInfoLoco = true; // pide info locomotora
|
||||
if (askMultimaus) { // pide info Multimaus
|
||||
askMultimaus = false;
|
||||
versionMultimaus();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (progFinished) { // fin de lectura/programacion CV
|
||||
progFinished = false;
|
||||
endProg();
|
||||
}
|
||||
if (millis() - pingTimer > XNET_PING_INTERVAL) { // Refresca para mantener la conexion
|
||||
pingTimer = millis();
|
||||
getStatusXnet(); // pide estado de la central
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void procesaXN () {
|
||||
byte n, longitud, modulo, dato;
|
||||
uint16_t adr;
|
||||
|
||||
switch (rxBufferXN[HEADER]) { // segun el header byte
|
||||
case 0x61:
|
||||
switch (rxBufferXN[DATA1]) {
|
||||
case 0x01: // Normal operation resumed (0x61,0x01,0x60)
|
||||
csStatus = csNormalOps;
|
||||
showNormalOpsXnet();
|
||||
break;
|
||||
case 0x08: // Z21 LAN_X_BC_TRACK_SHORT_CIRCUIT (0x61,0x08,XOR)
|
||||
case 0x00: // Track power off (0x61,0x00,0x61)
|
||||
csStatus |= csEmergencyOff;
|
||||
showErrorXnet();
|
||||
break;
|
||||
case 0x02: // Service mode entry (0x61,0x02,0x63)
|
||||
csStatus |= csServiceMode;
|
||||
if (!getResultsSM) // show 'Service Mode' if we aren't programming CV
|
||||
showErrorXnet();
|
||||
break;
|
||||
case 0x12: // Programming info. "shortcircuit" (0x61,0x12,XOR)
|
||||
case 0x13: // Programming info. "Data byte not found" (0x61,0x13,XOR)
|
||||
CVdata = 0x0600;
|
||||
getResultsSM = false;
|
||||
progFinished = true;
|
||||
break;
|
||||
case 0x81: // Command station busy response (0x61,0x81,XOR)
|
||||
break;
|
||||
case 0x1F: // Programming info. "Command station busy" (0x61,0x1F,XOR)
|
||||
getResultsSM = true;
|
||||
infoTimer = millis();
|
||||
break;
|
||||
case 0x82: // Instruction not supported by command station (0x61,0x82,XOR)
|
||||
getResultsSM = false;
|
||||
if (csStatus & csServiceMode) {
|
||||
CVdata = 0x0600;
|
||||
progFinished = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x81:
|
||||
if (rxBufferXN[DATA1] == 0) { // Emergency Stop (0x81,0x00,0x81)
|
||||
csStatus |= csEmergencyStop;
|
||||
showErrorXnet();
|
||||
}
|
||||
break;
|
||||
case 0x62:
|
||||
if (rxBufferXN[DATA1] == 0x22) { // Command station status indication response (0x62,0x22,DATA,XOR)
|
||||
csStatus = rxBufferXN[DATA2] & (csEmergencyStop | csEmergencyOff | csServiceMode) ;
|
||||
if ((xnetCS >= 0x10) && (rxBufferXN[DATA2] & csProgrammingModeActive)) // Multimaus/Z21 Service Mode
|
||||
csStatus |= csServiceMode;
|
||||
if (csStatus == csNormalOps)
|
||||
showNormalOpsXnet();
|
||||
else
|
||||
showErrorXnet();
|
||||
}
|
||||
break;
|
||||
case 0x63:
|
||||
switch (rxBufferXN[DATA1]) {
|
||||
case 0x03: // Broadcast "Modellzeit" (0x63,0x03,dddhhhhh,s0mmmmmm,XOR) (v4.0)
|
||||
clockHour = rxBufferXN[DATA2] & 0x1F;
|
||||
clockMin = rxBufferXN[DATA3] & 0x3F;
|
||||
clockRate = !bitRead(rxBufferXN[DATA3], 7);
|
||||
updateFastClock();
|
||||
break;
|
||||
case 0x14: // Service Mode response for Direct CV mode (0x63,0x1x,CV,DATA,XOR)
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
case 0x17:
|
||||
if (rxBufferXN[DATA2] == lastCV) { // comprobar CV (DR5000)
|
||||
lastCV ^= 0x55;
|
||||
getResultsSM = false;
|
||||
CVdata = rxBufferXN[DATA3];
|
||||
progFinished = true;
|
||||
}
|
||||
break;
|
||||
case 0x21: // Command station software version (0x63,0x21,VER,ID,XOR)
|
||||
xnetVersion = rxBufferXN[DATA2];
|
||||
xnetCS = rxBufferXN[DATA3];
|
||||
if (xnetCS == 0x10)
|
||||
askMultimaus = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xE3:
|
||||
if (rxBufferXN[DATA1] == 0x40) { // Locomotive is being operated by another device response (0xE3,0x40,ADRH,ADRL,XOR)
|
||||
adr = addrXnet(locoData[myLocoData].myAddr.address);
|
||||
if ((rxBufferXN[DATA3] == lowByte(adr)) && (rxBufferXN[DATA2] == highByte(adr))) { // DR5000 workaround
|
||||
bitSet(locoData[myLocoData].mySteps, 3);
|
||||
}
|
||||
}
|
||||
if (rxBufferXN[DATA1] == 0x52) { // Locomotive function info F13..F28 (0xE3,0x52,FNC,FNC,XOR)
|
||||
locoData[myLocoData].myFunc.Bits &= 0xE0001FFF;
|
||||
locoData[myLocoData].myFunc.Bits |= ((unsigned long)rxBufferXN[DATA2] << 13);
|
||||
locoData[myLocoData].myFunc.Bits |= ((unsigned long)rxBufferXN[DATA3] << 21);
|
||||
updateFuncState(isWindow(WIN_THROTTLE));
|
||||
}
|
||||
break;
|
||||
case 0xE4:
|
||||
if ((rxBufferXN[DATA1] & 0xF0) == 0x00) { // Locomotive information normal locomotive (0xE4,ID,SPD,FKTA,FKTB,XOR)
|
||||
locoData[myLocoData].mySteps = rxBufferXN[DATA1]; // '0000BFFF'
|
||||
locoData[myLocoData].myDir = rxBufferXN[DATA2] & 0x80; // 'RVVVVVVV'
|
||||
locoData[myLocoData].mySpeed = rxBufferXN[DATA2] & 0x7F;
|
||||
locoData[myLocoData].myFunc.Bits &= 0xFFFFE000; // '000FFFFF','FFFFFFFF'
|
||||
locoData[myLocoData].myFunc.Bits |= ((unsigned long)rxBufferXN[DATA4] << 5);
|
||||
locoData[myLocoData].myFunc.xFunc[0] |= ((rxBufferXN[DATA3] & 0x0F) << 1);
|
||||
bitWrite(locoData[myLocoData].myFunc.xFunc[0], 0, bitRead(rxBufferXN[DATA3], 4));
|
||||
updateFuncState(isWindow(WIN_THROTTLE));
|
||||
if (isWindow(WIN_THROTTLE) || isWindow(WIN_SPEEDO))
|
||||
updateSpeedHID();
|
||||
}
|
||||
break;
|
||||
case 0xE7:
|
||||
if ((rxBufferXN[DATA1] & 0xF0) == 0x00) { // Locomotive function info F13..F20 MM (0xE7,STP,SPD,FNC,FNC,FNC,0x00,0x00,XOR)
|
||||
locoData[myLocoData].mySteps = rxBufferXN[DATA1]; // '0000BFFF'
|
||||
locoData[myLocoData].myDir = rxBufferXN[DATA2] & 0x80; // 'RVVVVVVV'
|
||||
locoData[myLocoData].mySpeed = rxBufferXN[DATA2] & 0x7F;
|
||||
locoData[myLocoData].myFunc.Bits &= 0xFE00000;
|
||||
locoData[myLocoData].myFunc.Bits |= ((unsigned long)rxBufferXN[DATA5] << 13);
|
||||
locoData[myLocoData].myFunc.Bits |= ((unsigned long)rxBufferXN[DATA4] << 5);
|
||||
locoData[myLocoData].myFunc.xFunc[0] |= ((rxBufferXN[DATA3] & 0x0F) << 1);
|
||||
bitWrite(locoData[myLocoData].myFunc.xFunc[0], 0, bitRead(rxBufferXN[DATA3], 4));
|
||||
updateFuncState(isWindow(WIN_THROTTLE));
|
||||
if (isWindow(WIN_THROTTLE) || isWindow(WIN_SPEEDO))
|
||||
updateSpeedHID();
|
||||
}
|
||||
break;
|
||||
case 0xF3:
|
||||
if (rxBufferXN[DATA1] == 0x0A) { // Multimaus firmware version (0xF3,0x0A,VERH,VERL,XOR)
|
||||
highVerMM = rxBufferXN[DATA2];
|
||||
lowVerMM = rxBufferXN[DATA3];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ((rxBufferXN[HEADER] & 0xF0) == 0x40) { // Feedback broadcast / Accessory decoder information response (0x4X,MOD,DATA,...,XOR)
|
||||
/*
|
||||
for (n = HEADER; n < (rxBytes - 2); n += 2) {
|
||||
modulo = rxBufferXN[n + 1];
|
||||
dato = rxBufferXN[n + 2];
|
||||
if (modulo == miModulo) { // Si es mi desvio guarda su posicion
|
||||
if (bitRead(dato, 4) == bitRead(miAccPos, 1)) {
|
||||
if (bitRead(miAccPos, 0))
|
||||
myPosTurnout = (dato >> 2) & 0x03;
|
||||
else
|
||||
myPosTurnout = dato & 0x03;
|
||||
if (scrOLED == SCR_TURNOUT)
|
||||
updateOLED = true;
|
||||
}
|
||||
}
|
||||
#ifdef USE_AUTOMATION
|
||||
for (byte n = 0; n < MAX_AUTO_SEQ; n++) {
|
||||
if ((automation[n].opcode & OPC_AUTO_MASK) == OPC_AUTO_FBK) {
|
||||
if (modulo == automation[n].param) {
|
||||
unsigned int nibble = (dato & 0x10) ? 0x0F : 0xF0;
|
||||
automation[n].value &= nibble;
|
||||
nibble = (dato & 0x10) ? (dato << 4) : (dato & 0x0F);
|
||||
automation[n].value |= nibble;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
modulo++;
|
||||
if (modulo == Shuttle.moduleA) // shuttle contacts
|
||||
updateShuttleStatus(&Shuttle.statusA, dato);
|
||||
if (modulo == Shuttle.moduleB)
|
||||
updateShuttleStatus(&Shuttle.statusB, dato);
|
||||
}
|
||||
*/
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
585
PacoMouseCYD/Platformio/Arduino.old/z21.ino
Normal file
585
PacoMouseCYD/Platformio/Arduino.old/z21.ino
Normal file
@@ -0,0 +1,585 @@
|
||||
/**
|
||||
* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
|
||||
*
|
||||
* This software and associated files are a DIY project that is not intended for commercial use.
|
||||
* This software uses libraries with different licenses, follow all their different terms included.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
|
||||
*
|
||||
* Sources are only provided for building and uploading to the device.
|
||||
* You are not allowed to modify the source code or fork/publish this project.
|
||||
* Commercial use is forbidden.
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** Z21 SOPORTE *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void readCVZ21 (unsigned int adr, byte stepPrg) {
|
||||
if (!modeProg) {
|
||||
askZ21begin (LAN_X_Header);
|
||||
askZ21data (0x23);
|
||||
askZ21data (0x11);
|
||||
adr--;
|
||||
askZ21data ((adr >> 8) & 0xFF);
|
||||
askZ21data (adr & 0xFF);
|
||||
askZ21xor ();
|
||||
sendUDP (0x09);
|
||||
waitResultCV = true;
|
||||
lastCV = lowByte(adr);
|
||||
progStepCV = stepPrg;
|
||||
DEBUG_MSG("Read CV %d", adr + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void writeCVZ21 (unsigned int adr, unsigned int data, byte stepPrg) {
|
||||
byte Adr_MSB;
|
||||
if (modeProg) {
|
||||
askZ21begin (LAN_X_Header);
|
||||
askZ21data (0xE6);
|
||||
askZ21data (0x30);
|
||||
Adr_MSB = locoData[myLocoData].myAddr.adr[1] & 0x3F;
|
||||
if (locoData[myLocoData].myAddr.address & 0x3F80)
|
||||
Adr_MSB |= 0xC0;
|
||||
askZ21data (Adr_MSB);
|
||||
askZ21data (locoData[myLocoData].myAddr.adr[0]);
|
||||
adr--;
|
||||
askZ21data (0xEC | ((adr >> 8) & 0x03));
|
||||
askZ21data (adr & 0xFF);
|
||||
askZ21data (data);
|
||||
askZ21xor ();
|
||||
sendUDP (0x0C);
|
||||
}
|
||||
else {
|
||||
askZ21begin (LAN_X_Header);
|
||||
askZ21data (0x24);
|
||||
askZ21data (0x12);
|
||||
adr--;
|
||||
askZ21data ((adr >> 8) & 0xFF);
|
||||
askZ21data (adr & 0xFF);
|
||||
askZ21data (data);
|
||||
askZ21xor ();
|
||||
sendUDP (0x0A);
|
||||
waitResultCV = true;
|
||||
lastCV = lowByte(adr);
|
||||
|
||||
}
|
||||
progStepCV = stepPrg;
|
||||
DEBUG_MSG("Write CV%d = %d", adr + 1, data);
|
||||
}
|
||||
|
||||
|
||||
void showErrorZ21() { // muestra pantalla de error
|
||||
if (csStatus & csTrackVoltageOff) {
|
||||
iconData[ICON_POWER].color = COLOR_RED;
|
||||
setTimer (TMR_POWER, 5, TMR_PERIODIC); // Flash power icon
|
||||
if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
|
||||
newEvent(OBJ_ICON, ICON_POWER, EVNT_DRAW);
|
||||
if (isWindow(WIN_STA_PLAY)) {
|
||||
fncData[FNC_STA_RAYO].state = true;
|
||||
newEvent(OBJ_FNC, FNC_STA_RAYO, EVNT_DRAW);
|
||||
}
|
||||
}
|
||||
if (csStatus & csProgrammingModeActive) {
|
||||
if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
|
||||
alertWindow(ERR_SERV);
|
||||
}
|
||||
if (csStatus & csEmergencyStop) {
|
||||
if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
|
||||
alertWindow(ERR_STOP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void showNormalOpsZ21() {
|
||||
stopTimer (TMR_POWER);
|
||||
iconData[ICON_POWER].color = COLOR_GREEN;
|
||||
if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
|
||||
newEvent(OBJ_ICON, ICON_POWER, EVNT_DRAW);
|
||||
if (isWindow(WIN_STA_PLAY)) {
|
||||
fncData[FNC_STA_RAYO].state = false;
|
||||
newEvent(OBJ_FNC, FNC_STA_RAYO, EVNT_DRAW);
|
||||
}
|
||||
if (isWindow(WIN_ALERT)) {
|
||||
switch (errType) {
|
||||
case ERR_SERV:
|
||||
case ERR_STOP:
|
||||
case ERR_CV:
|
||||
closeWindow(WIN_ALERT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setTimeZ21(byte hh, byte mm, byte rate) {
|
||||
clockHour = hh;
|
||||
clockMin = mm;
|
||||
clockRate = rate;
|
||||
askZ21begin (LAN_FAST_CLOCK_CONTROL); // set clock
|
||||
if (rate > 0) {
|
||||
askZ21data (0x24);
|
||||
askZ21data (0x2B);
|
||||
askZ21data (hh);
|
||||
askZ21data (mm);
|
||||
askZ21data (rate);
|
||||
askZ21xor ();
|
||||
sendUDP (0x0A);
|
||||
askZ21begin (LAN_FAST_CLOCK_CONTROL);
|
||||
askZ21data (0x21); // start clock
|
||||
askZ21data (0x2C);
|
||||
askZ21xor ();
|
||||
sendUDP (0x07);
|
||||
}
|
||||
else {
|
||||
askZ21data (0x21); // recommended for rate=0. stop clock
|
||||
askZ21data (0x2D);
|
||||
askZ21xor ();
|
||||
sendUDP (0x07);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** Z21 DECODE *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void processZ21() {
|
||||
int len, packetSize;
|
||||
|
||||
packetSize = Udp.parsePacket(); // z21 UDP packet
|
||||
if (packetSize) {
|
||||
len = Udp.read(packetBuffer, packetSize); // read the packet into packetBufffer
|
||||
ReceiveZ21 (len, packetBuffer); // decode received packet
|
||||
}
|
||||
delay(0);
|
||||
if (millis() - infoTimer > 1000UL) { // Cada segundo
|
||||
infoTimer = millis();
|
||||
pingTimer++;
|
||||
if (pingTimer >= Z21_PING_INTERVAL) {
|
||||
pingTimer = 0;
|
||||
if (!(csStatus & csProgrammingModeActive))
|
||||
getStatusZ21();
|
||||
}
|
||||
/*
|
||||
battery = ESP.getVcc (); // Read VCC voltage
|
||||
if (battery < LowBattADC)
|
||||
lowBATT = true;
|
||||
*/
|
||||
}
|
||||
if (progFinished) { // fin de lectura/programacion CV
|
||||
progFinished = false;
|
||||
endProg();
|
||||
}
|
||||
delay(0);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
void setBroadcastFlags (unsigned long bFlags) {
|
||||
askZ21begin (LAN_SET_BROADCASTFLAGS);
|
||||
askZ21data (bFlags & 0xFF);
|
||||
askZ21data ((bFlags >> 8) & 0xFF);
|
||||
askZ21data ((bFlags >> 16) & 0xFF);
|
||||
askZ21data ((bFlags >> 24) & 0xFF);
|
||||
sendUDP (0x08);
|
||||
}
|
||||
|
||||
void resumeOperationsZ21 () { // LAN_X_SET_TRACK_POWER_ON
|
||||
askZ21begin (LAN_X_Header);
|
||||
askZ21data (0x21);
|
||||
askZ21data (0x81);
|
||||
askZ21xor ();
|
||||
sendUDP (0x07);
|
||||
}
|
||||
|
||||
|
||||
void emergencyOffZ21() { // LAN_X_SET_TRACK_POWER_OFF
|
||||
askZ21begin (LAN_X_Header);
|
||||
askZ21data (0x21);
|
||||
askZ21data (0x80);
|
||||
askZ21xor ();
|
||||
sendUDP (0x07);
|
||||
}
|
||||
|
||||
|
||||
void getStatusZ21 () {
|
||||
askZ21begin (LAN_X_Header);
|
||||
askZ21data (0x21);
|
||||
askZ21data (0x24);
|
||||
askZ21xor ();
|
||||
sendUDP (0x07);
|
||||
}
|
||||
|
||||
void getSerialNumber () {
|
||||
askZ21begin (LAN_GET_SERIAL_NUMBER);
|
||||
sendUDP (0x04);
|
||||
}
|
||||
|
||||
void infoLocomotoraZ21 (unsigned int Adr) {
|
||||
byte Adr_MSB;
|
||||
askZ21begin (LAN_X_Header);
|
||||
askZ21data (0xE3);
|
||||
askZ21data (0xF0);
|
||||
Adr_MSB = (Adr >> 8) & 0x3F;
|
||||
if (Adr & 0x3F80)
|
||||
Adr_MSB |= 0xC0;
|
||||
askZ21data (Adr_MSB);
|
||||
askZ21data (Adr & 0xFF);
|
||||
askZ21xor ();
|
||||
sendUDP (0x09);
|
||||
}
|
||||
|
||||
void locoOperationSpeedZ21() {
|
||||
byte Adr_MSB;
|
||||
DEBUG_MSG("Loco Operations")
|
||||
askZ21begin (LAN_X_Header);
|
||||
askZ21data (0xE4);
|
||||
if (bitRead(locoData[myLocoData].mySteps, 2)) { // 128 steps
|
||||
askZ21data (0x13);
|
||||
}
|
||||
else {
|
||||
if (bitRead(locoData[myLocoData].mySteps, 1)) { // 28 steps
|
||||
askZ21data (0x12);
|
||||
}
|
||||
else {
|
||||
askZ21data (0x10); // 14 steps
|
||||
}
|
||||
}
|
||||
Adr_MSB = locoData[myLocoData].myAddr.adr[1] & 0x3F;
|
||||
if (locoData[myLocoData].myAddr.address & 0x3F80)
|
||||
Adr_MSB |= 0xC0;
|
||||
askZ21data (Adr_MSB);
|
||||
askZ21data (locoData[myLocoData].myAddr.adr[0]);
|
||||
askZ21data (locoData[myLocoData].mySpeed | locoData[myLocoData].myDir);
|
||||
askZ21xor ();
|
||||
sendUDP (0x0A);
|
||||
bitClear(locoData[myLocoData].mySteps, 3); // currently operated by me
|
||||
updateSpeedDir();
|
||||
}
|
||||
|
||||
|
||||
byte getCurrentStepZ21() {
|
||||
byte currStep;
|
||||
DEBUG_MSG("Get Steps: %02X - Speed: %02X", locoData[myLocoData].mySteps, locoData[myLocoData].mySpeed);
|
||||
if (bitRead(locoData[myLocoData].mySteps, 2)) { // 128 steps -> 0..126
|
||||
if (locoData[myLocoData].mySpeed > 1)
|
||||
return (locoData[myLocoData].mySpeed - 1);
|
||||
}
|
||||
else {
|
||||
if (bitRead(locoData[myLocoData].mySteps, 1)) { // 28 steps -> 0..28 '---04321' -> '---43210'
|
||||
currStep = (locoData[myLocoData].mySpeed << 1) & 0x1F;
|
||||
bitWrite(currStep, 0, bitRead(locoData[myLocoData].mySpeed, 4));
|
||||
if (currStep > 3)
|
||||
return (currStep - 3);
|
||||
}
|
||||
else { // 14 steps -> 0..14
|
||||
if (locoData[myLocoData].mySpeed > 1)
|
||||
return (locoData[myLocoData].mySpeed - 1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
void funcOperationsZ21 (byte fnc) {
|
||||
byte Adr_MSB;
|
||||
askZ21begin (LAN_X_Header);
|
||||
askZ21data (0xE4);
|
||||
askZ21data (0xF8);
|
||||
Adr_MSB = locoData[myLocoData].myAddr.adr[1] & 0x3F;
|
||||
if (locoData[myLocoData].myAddr.address & 0x3F80)
|
||||
Adr_MSB |= 0xC0;
|
||||
askZ21data (Adr_MSB);
|
||||
askZ21data (locoData[myLocoData].myAddr.adr[0]);
|
||||
if (bitRead(locoData[myLocoData].myFunc.Bits, fnc))
|
||||
askZ21data (fnc | 0x40);
|
||||
else
|
||||
askZ21data (fnc);
|
||||
askZ21xor ();
|
||||
sendUDP (0x0A);
|
||||
bitClear(locoData[myLocoData].mySteps, 3); // currently operated by me
|
||||
}
|
||||
|
||||
|
||||
void infoDesvio (unsigned int FAdr) {
|
||||
FAdr--;
|
||||
askZ21begin (LAN_X_Header);
|
||||
askZ21data (0x43);
|
||||
askZ21data ((FAdr >> 8) & 0xFF);
|
||||
askZ21data (FAdr & 0xFF);
|
||||
askZ21xor ();
|
||||
sendUDP (0x08);
|
||||
}
|
||||
|
||||
|
||||
void setAccessoryZ21 (unsigned int FAdr, int pair, bool active) {
|
||||
byte db2;
|
||||
FAdr--;
|
||||
askZ21begin (LAN_X_Header);
|
||||
askZ21data (0x53);
|
||||
askZ21data ((FAdr >> 8) & 0xFF);
|
||||
askZ21data (FAdr & 0xFF);
|
||||
db2 = active ? 0x88 : 0x80;
|
||||
if (pair > 0)
|
||||
db2 |= 0x01;
|
||||
askZ21data (db2); // '10Q0A00P'
|
||||
askZ21xor ();
|
||||
sendUDP (0x09);
|
||||
}
|
||||
|
||||
|
||||
void getFeedbackInfo (byte group) {
|
||||
askZ21begin (LAN_RMBUS_GETDATA);
|
||||
askZ21data (group);
|
||||
sendUDP (0x05);
|
||||
}
|
||||
|
||||
|
||||
void ReceiveZ21 (int len, byte * packet) { // get UDP packet, maybe more than one!!
|
||||
int DataLen, isPacket;
|
||||
#ifdef DEBUG____X
|
||||
Serial.print("\nRX Length: ");
|
||||
Serial.println (len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
Serial.print(packet[i], HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
isPacket = 1;
|
||||
while (isPacket) {
|
||||
DataLen = (packet[DATA_LENH] << 8) + packet[DATA_LENL];
|
||||
DecodeZ21 (DataLen, packet);
|
||||
if (DataLen >= len) {
|
||||
isPacket = 0;
|
||||
}
|
||||
else {
|
||||
packet = packet + DataLen;
|
||||
len = len - DataLen;
|
||||
}
|
||||
delay(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DecodeZ21 (int len, byte * packet) { // decode z21 UDP packets
|
||||
int Header, DataLen;
|
||||
unsigned int FAdr;
|
||||
byte group;
|
||||
|
||||
Header = (packet[DATA_HEADERH] << 8) + packet[DATA_HEADERL];
|
||||
switch (Header) {
|
||||
case LAN_GET_SERIAL_NUMBER:
|
||||
break;
|
||||
case LAN_GET_CODE: // FW 1.28
|
||||
break;
|
||||
case LAN_GET_HWINFO:
|
||||
break;
|
||||
case LAN_GET_BROADCASTFLAGS:
|
||||
break;
|
||||
case LAN_GET_LOCOMODE:
|
||||
break;
|
||||
case LAN_GET_TURNOUTMODE:
|
||||
break;
|
||||
case LAN_RMBUS_DATACHANGED:
|
||||
/*
|
||||
if (Shuttle.moduleA > 0) { // only check shuttle contacts
|
||||
if ((packet[4] == 0x01) && (Shuttle.moduleA > 10))
|
||||
Shuttle.statusA = packet[Shuttle.moduleA - 6];
|
||||
if ((packet[4] == 0x00) && (Shuttle.moduleA < 11))
|
||||
Shuttle.statusA = packet[Shuttle.moduleA + 4];
|
||||
}
|
||||
if (Shuttle.moduleB > 0) {
|
||||
if ((packet[4] == 0x01) && (Shuttle.moduleB > 10))
|
||||
Shuttle.statusB = packet[Shuttle.moduleB - 6];
|
||||
if ((packet[4] == 0x00) && (Shuttle.moduleB < 11))
|
||||
Shuttle.statusB = packet[Shuttle.moduleB + 4];
|
||||
}
|
||||
#ifdef USE_AUTOMATION
|
||||
for (byte n = 0; n < MAX_AUTO_SEQ; n++) {
|
||||
if ((automation[n].opcode & OPC_AUTO_MASK) == OPC_AUTO_FBK) {
|
||||
if ((packet[4] == 0x01) && (automation[n].param > 9))
|
||||
automation[n].value = packet[automation[n].param - 5];
|
||||
if ((packet[4] == 0x00) && (automation[n].param < 10))
|
||||
automation[n].value = packet[automation[n].param + 5];
|
||||
DEBUG_MSG("RBUS %d", automation[n].value)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
break;
|
||||
case LAN_SYSTEMSTATE_DATACHANGED:
|
||||
csStatus = packet[16] & (csEmergencyStop | csTrackVoltageOff | csProgrammingModeActive); // CentralState
|
||||
if (packet[16] & csShortCircuit)
|
||||
csStatus |= csTrackVoltageOff;
|
||||
break;
|
||||
case LAN_RAILCOM_DATACHANGED:
|
||||
break;
|
||||
|
||||
case LAN_LOCONET_Z21_TX: // a message has been written to the LocoNet bus by the Z21.
|
||||
case LAN_LOCONET_Z21_RX: // a message has been received by the Z21 from the LocoNet bus.
|
||||
case LAN_LOCONET_FROM_LAN: // another LAN client has written a message to the LocoNet bus via the Z21.
|
||||
switch (packet[4]) {
|
||||
case 0x83:
|
||||
csStatus = csNormalOps; // OPC_GPON
|
||||
showNormalOpsZ21();
|
||||
break;
|
||||
case 0x82:
|
||||
csStatus |= csTrackVoltageOff; // OPC_GPOFF
|
||||
showErrorZ21();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case LAN_LOCONET_DETECTOR:
|
||||
break;
|
||||
case LAN_FAST_CLOCK_DATA: // fast clock data FW 1.43
|
||||
if (packet[8] & 0x80) { // Stop flag
|
||||
clockRate = 0;
|
||||
}
|
||||
else {
|
||||
clockHour = packet[6] & 0x1F;
|
||||
clockMin = packet[7] & 0x3F;
|
||||
clockRate = packet[9] & 0x3F;
|
||||
updateFastClock();
|
||||
}
|
||||
DEBUG_MSG("Clock: %d:%d %d", clockHour, clockMin, clockRate);
|
||||
break;
|
||||
|
||||
case LAN_X_Header:
|
||||
switch (packet[XHEADER]) {
|
||||
case 0x43: // LAN_X_TURNOUT_INFO
|
||||
FAdr = (packet[DB0] << 8) + packet[DB1] + 1;
|
||||
/*
|
||||
if (FAdr == myTurnout) {
|
||||
myPosTurnout = packet[DB2] & 0x03;
|
||||
if (scrOLED == SCR_TURNOUT)
|
||||
updateOLED = true;
|
||||
}
|
||||
*/
|
||||
break;
|
||||
case 0x61:
|
||||
switch (packet[DB0]) {
|
||||
case 0x01: // LAN_X_BC_TRACK_POWER_ON
|
||||
csStatus = csNormalOps;
|
||||
showNormalOpsZ21();
|
||||
break;
|
||||
case 0x08: // LAN_X_BC_TRACK_SHORT_CIRCUIT
|
||||
csStatus |= csShortCircuit;
|
||||
case 0x00: // LAN_X_BC_TRACK_POWER_OFF
|
||||
csStatus |= csTrackVoltageOff;
|
||||
showErrorZ21();
|
||||
break;
|
||||
case 0x02: // LAN_X_BC_PROGRAMMING_MODE
|
||||
csStatus |= csProgrammingModeActive;
|
||||
if (!waitResultCV)
|
||||
showErrorZ21();
|
||||
break;
|
||||
case 0x12: // LAN_X_CV_NACK_SC
|
||||
case 0x13: // LAN_X_CV_NACK
|
||||
CVdata = 0x0600;
|
||||
waitResultCV = false;
|
||||
progFinished = true;
|
||||
break;
|
||||
case 0x82: // LAN_X_UNKNOWN_COMMAND
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x62:
|
||||
switch (packet[DB0]) {
|
||||
case 0x22: // LAN_X_STATUS_CHANGED
|
||||
csStatus = packet[DB1] & (csEmergencyStop | csTrackVoltageOff | csProgrammingModeActive);
|
||||
if (packet[DB1] & csShortCircuit)
|
||||
csStatus |= csTrackVoltageOff;
|
||||
if (csStatus == csNormalOps)
|
||||
showNormalOpsZ21();
|
||||
else
|
||||
showErrorZ21();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x64:
|
||||
if (packet[DB0] == 0x14) { // LAN_X_CV_RESULT
|
||||
if (packet[DB2] == lastCV) {
|
||||
lastCV ^= 0x55;
|
||||
CVdata = packet[DB3];
|
||||
waitResultCV = false;
|
||||
progFinished = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x81:
|
||||
if (packet[DB0] == 0) { // LAN_X_BC_STOPPED
|
||||
csStatus |= csEmergencyStop;
|
||||
showErrorZ21();
|
||||
}
|
||||
break;
|
||||
case 0xEF: // LAN_X_LOCO_INFO
|
||||
DEBUG_MSG("RX: Loco data")
|
||||
FAdr = ((packet[DB0] << 8) + packet[DB1]) & 0x3FFF;
|
||||
if (FAdr == locoData[myLocoData].myAddr.address) {
|
||||
locoData[myLocoData].mySteps = packet[DB2]; // '0000BFFF'
|
||||
locoData[myLocoData].myDir = packet[DB3] & 0x80; // 'RVVVVVVV'
|
||||
locoData[myLocoData].mySpeed = packet[DB3] & 0x7F;
|
||||
locoData[myLocoData].myFunc.Bits &= 0xE0000000; // '000FFFFF','FFFFFFFF'
|
||||
locoData[myLocoData].myFunc.xFunc[0] |= ((packet[DB4] & 0x0F) << 1);
|
||||
bitWrite(locoData[myLocoData].myFunc.xFunc[0], 0, bitRead(packet[DB4], 4));
|
||||
locoData[myLocoData].myFunc.Bits |= (unsigned long)(packet[DB5] << 5);
|
||||
locoData[myLocoData].myFunc.Bits |= (unsigned long)(packet[DB6] << 13);
|
||||
locoData[myLocoData].myFunc.Bits |= (unsigned long)(packet[DB7] << 21);
|
||||
updateFuncState(isWindow(WIN_THROTTLE));
|
||||
if (isWindow(WIN_THROTTLE) || isWindow(WIN_SPEEDO))
|
||||
updateSpeedHID(); // set encoder
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: // Header other
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void askZ21begin (unsigned int header) {
|
||||
OutData[DATA_HEADERL] = header & 0xFF;
|
||||
OutData[DATA_HEADERH] = header >> 8;
|
||||
OutPos = XHEADER;
|
||||
OutXOR = 0;
|
||||
}
|
||||
|
||||
|
||||
void askZ21data (byte data) {
|
||||
OutData[OutPos++] = data;
|
||||
OutXOR ^= data;
|
||||
}
|
||||
|
||||
void askZ21xor () {
|
||||
OutData[OutPos] = OutXOR;
|
||||
}
|
||||
|
||||
|
||||
void sendUDP (int len) {
|
||||
OutData[DATA_LENL] = len & 0xFF;
|
||||
OutData[DATA_LENH] = len >> 8;
|
||||
Udp.beginPacket(wifiSetting.CS_IP, z21Port);
|
||||
Udp.write(OutData, len);
|
||||
Udp.endPacket();
|
||||
delay(0);
|
||||
#ifdef DEBUG___X
|
||||
Serial.print("TX: ");
|
||||
for (int i = 0; i < len; i++) {
|
||||
Serial.print(OutData[i], HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user