Reorganisation fichiers
This commit is contained in:
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user