1455 Zeilen
45 KiB
C

//Z21 LAN and WiFi
//Kommunikation mit der Z21 Library!
//
//Copyright (c) by Philipp Gahtow, year 2021
/*
* Changes:
* - Add change für WLAN für multi Paket - meherer Abfragen vom Client
* - Add change via LAN für multi Paket
* - Add store for source IP
* - Change State Report of Volt, mA and temp
* - Change Ethernet Big UDP handel at packet length = 0
* - Update ESP Wifi setup
* - add new function to request WiFi conf data
* - remove while in Serial read for WiFi
*/
//----------------------------------------------
#if defined(LAN) || defined(WIFI) || defined(ESP_WIFI)
extern void Z21LANreceive();
// buffers for receiving and sending data
#define Z21_UDP_TX_MAX_SIZE 20 //--> Z21 LocoNet tunnel DATA has 20 Byte!
#define Z21_BIG_UDP_MIN_SIZE 4 //--> smallest packet length in a BIG UDP Packet that we can handle
//----------------------------------------------
#if defined(Z21DISPLAY) && defined(BOOSTER_INT_MAINCURRENT)
extern void DisplayUpdateRailData(uint16_t inAm, float volt, float temp);
#endif
#if defined(Z21DISPLAY)
extern boolean DisplayReady;
extern void DisplayConfigData();
extern uint8_t DisplayCounter; //for animation
extern void DisplayDataTransmission(bool active);
#if defined(ESP_WIFI)
uint8_t ESPLastConnetionState;
#endif
#endif
//----------------------------------------------
//Wenn zwei Kommunikationsschnittstellen aktiv sind wird LAN hinten angestellt:
#if defined(LAN) && defined(WIFI)
#define Z21_Eth_offset WLANmaxIP //shift LAN client behind WiFi client
#else
#define Z21_Eth_offset 0
#endif
//----------------------------------------------
#if defined(BOOSTER_INT_MAINCURRENT)
float temp = 0;
#ifdef DALLASTEMPSENSE
#define DALLAS_Temp_Int 10000 //Intervall to request the temperatur
unsigned long temp_timer = 0;
#endif
#endif
//----------------------------------------------
#if defined(ESP_WIFI)
/*
IPAddress Ip(192,168,0,111);
IPAddress Gw(192,168,0,111);
IPAddress Sb(255,255,255,0);
*/
//client ssid and pw stored in EEPROM!
String ssid = "";
String pass = "";
//AP ssid and pw read out from EEPROM:
String ssidAP = "";
String passAP = "";
byte kanalAP = 3;
#endif
//----------------------------------------------
#if defined(LAN) || defined(ESP_WIFI)
typedef struct //Rückmeldung des Status der Programmierung
{
byte IP0; //client IP-Adresse
byte IP1;
byte IP2;
byte IP3;
byte time; //aktive Zeit
unsigned int port; //source Port
} listofIP;
listofIP mem[LANmaxIP];
byte storedIP = 0; //speicher für IPs
#endif
//----------------------------------------------
unsigned long IPpreviousMillis = 0; // will store last time of IP decount updated and SystemInfo update
//--------------------------------------------------------------------------------------------
#if defined(WIFI)
byte outData[Z21_UDP_TX_MAX_SIZE]; //store received Serial to send via UDP
byte outDcount = 0; //position writing out data
byte sendTOO = 0xFF; //memIP to whom to send the data
byte listofWLANHash[WLANmaxIP+LANmaxIP];
#define WLAN_Config_Size 10 //num of config data that we can request from the ESP Modul
#if defined(Z21DISPLAY)
extern void DisplayUpdateRailPower(bool clear);
IPAddress WLANlocalIP; //0xE4 = Client IP
String WLANssid = "[not defined]"; //0xE5 = Client SSID Name
float ESPSwVer = 0.0; //0xE8 = ESP Sw Version
uint8_t ESPsoftAPStationNum = 0; //0xE9 = AP Client Connected
int WLAN_Signal = 0xFF; //0xEA = WLAN client Signal - 31 = "not connected"
#endif
//--------------------------------------------------------------------------------------------
#if defined(DEBUG_WLAN_CONFIG) || defined(Z21DATADEBUG)
void WLANConfDebug(uint8_t id, String s) {
//Report ESP config data: ---------------------------------------------------
String list[WLAN_Config_Size] = {F("WiFi-AP"),F("SSIP-AP"),F("PASS-AP"),F("CHAN-AP"),F("WiFi-CL"),F("SSIP-CL"),F("PASS-CL"),F("ESP-S88"),F("ESP-Ver"),F("AP-CLNum")};
//request each singel value:
if (id < WLAN_Config_Size) {
Debug.print(list[id]);
Debug.print(": ");
Debug.println(s);
}
}
#endif
//--------------------------------------------------------------------------------------------
//Request init data from ESP Modul
void WLANRequest(uint8_t id) {
WLAN.write(id);
delay(5); //wait for answer...
while (WLAN.available() > 0) {
Z21LANreceive();
}
}
//--------------------------------------------------------------------------------------------
//init ESP8266 serial interface
void WLANSetup() {
WLAN.begin(WIFISerialBaud); //UDP to Serial Kommunikation
WLAN.setTimeout(3); //sets the maximum milliseconds to wait for serial data
byte b1 = 0;
#if defined(DEBUG)
Debug.print(F("WiFi "));
Debug.print(WIFISerialBaud);
Debug.print(F("b start.."));
#endif
byte timeout = 80; //try to init at least
do {
#if defined(DEBUG)
Debug.print(".");
#endif
WLAN.println(); //let device Flush old Data!
delay(50); //wait for ESP8266 to answer a receive!
while (WLAN.available() > 0) {
b1 = WLAN.read();
#if defined(DEBUG)
if (b1 == 0xFA)
Debug.print("OK");
#endif
}
timeout--;
}
while (b1 != 0xFA && timeout > 0);
if (timeout == 0 || b1 != 0xFA) { //Error - no ESP module found!
#if defined(DEBUG)
Debug.println("FAIL");
#endif
}
else {
//Continue config setting for ESP
#if defined(DEBUG)
Debug.println();
#endif
//Setting S88:
#if defined(DEBUG)
Debug.print(F("Set ESP S88..."));
#endif
WLAN.write(0xFE); //Send start Bit for Initial Settings
#if defined(S88N)
WLAN.write(S88Module);
#else
WLAN.write(0xFE);
#endif
delay(5); //wait for answer...
if (WLAN.available() > 0) {
Z21LANreceive();
}
#if defined(DEBUG_WLAN_CONFIG)
//request all values:
for (byte counter = 0; counter < WLAN_Config_Size; counter++) {
delay(10); //wait for answer...
WLANRequest(0xE0 | (counter & 0x0F));
}
#else
//request only used ones:
#if defined(Z21DISPLAY)
#if defined(DEBUG)
Debug.println(F("Request..."));
#endif
WLANRequest(0xE8); //ESP Sw Version
WLANRequest(0xE5); //Client SSID Name
WLANRequest(0xE4); //Client IP
#endif
WLANRequest(0xEB); //Read all client Hash
#endif
}
}
#endif
//--------------------------------------------------------------------------------------------
#if defined(ESP_WIFI)
/**********************************************************************************/
//s = String that will be saved,
//laenge = Index to length byte,
//start = index to the first letter
void EEPROMwrite (String s, uint16_t laenge, uint16_t start) {
byte len = s.length();
FIXSTORAGE.FIXMODE(laenge,len);
for (uint16_t i = start; i < (start+len); i++) {
FIXSTORAGE.FIXMODE(i,s[i-start]);
}
FIXSTORAGE.commit();
}
/**********************************************************************************/
//laenge = Index to length byte,
//start = index to the first letter
String EEPROMread (uint16_t laenge, uint16_t start) {
String s = "";
byte len = FIXSTORAGE.read(laenge);
if (len < EEStringMaxSize) {
for (uint16_t i = start; i < (start+len); i++) {
s += char(FIXSTORAGE.read(i));
}
}
return s;
}
/**********************************************************************************/
boolean tryWifiClient() {
WiFi.disconnect();
if ( (ssid.length() > 0) && (pass.length() > 7) ) {
//check first if we see this SSID
byte available_networks = WiFi.scanNetworks();
for (int network = 0; network < available_networks; network++) {
if (WiFi.SSID(network) == ssid.c_str()) {
WiFi.begin(ssid.c_str(), pass.c_str());
return true;
}
}
}
return false;
}
/**********************************************************************************/
void ESPSetup() {
#if defined(ESP32)
WiFi.mode(WIFI_MODE_APSTA);
#else
WiFi.mode(WIFI_AP_STA); //AP & client
#endif
// read eeprom for ssid and pass:
//--------------WIFI CLIENT---------------
ssid = EEPROMread(EEssidLength, EEssidBegin);
pass = EEPROMread(EEpassLength, EEpassBegin);
//--------------ACCESS POINT-------------
ssidAP = EEPROMread(EEssidAPLength, EEssidAPBegin);
passAP = EEPROMread(EEpassAPLength, EEpassAPBegin);
if ((ssidAP.length() > 32) || (ssidAP.length() == 0) || (passAP.length() > 32) || (passAP.length() == 0) ) { //request is OK?
#if defined(DEBUG)
Debug.println(F("Reset to default!"));
#endif
ssidAP = SssidAP;
passAP = SpassAP;
kanalAP = SkanalAP;
/*
#if defined(ESP32)
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&myMutex);
#endif
*/
EEPROMwrite (ssidAP, EEssidAPLength, EEssidAPBegin);
EEPROMwrite (passAP, EEpassAPLength, EEpassAPBegin);
FIXSTORAGE.FIXMODE(EEkanalAP, kanalAP);
FIXSTORAGE.commit();
/*
#if defined(ESP32)
portEXIT_CRITICAL(&myMutex);
#endif
*/
}
else {
kanalAP = FIXSTORAGE.read(EEkanalAP);
if ((kanalAP < 1) || (kanalAP > 13))
kanalAP = SkanalAP;
}
WiFi.softAPConfig(AP_ip, AP_ip, AP_sb); //set the default IP for Z21
#if defined(ESP32_MCU)
WiFi.softAP(ssidAP.c_str(), passAP.c_str() ); //Start AcessPoint, ignore Channel parameter!
#else
WiFi.softAP(ssidAP.c_str(), passAP.c_str(), kanalAP, false, 8); //Start AcessPoint with max 8 number of clients
#endif
//don't hide SSID and max simultaneous connected stations set to eight!
#if defined(DEBUG)
Debug.print(F("AP Name: "));
Debug.println(ssidAP);
Debug.print(F("Pw: "));
Debug.println(passAP);
Debug.print(F("IP: "));
Debug.println(WiFi.softAPIP());
#endif
#if defined(DEBUG)
Debug.print("Client: ");
Debug.println(ssid.c_str());
Debug.print("PW: ");
Debug.println(pass.c_str());
#endif
if (tryWifiClient()) { //Try to connect to WiFi
#if defined(DEBUG)
Debug.print(ssid);
Debug.println(F(" gefunden!"));
//Debug.print(F("IP: "));
//Debug.println(WiFi.localIP());
#endif
}
else {
//Change WiFi Mode, to remove blocking OTA handel, when not connected:
WiFi.mode(WIFI_AP); //AP & client
#if defined(DEBUG)
Debug.print(F("Connect fail to "));
Debug.println(ssid);
#endif
}
#if defined(Z21DISPLAY)
if (Railpower == csNormal) {
DisplayCounter = 0xFF;
DisplayConfigData(); //rewrite config data to Display
}
#endif
}
#endif
//-------------------------------------------------------------------------------------------
#if defined(WIFI)
void WLANEvent() {
//receive WLAN data:
if (WLAN.available() > 0) { //Empfang Z21 UDP Packet over Serial from ESP
outData[outDcount] = WLAN.read(); //read
if (sendTOO == 0xFF) {
sendTOO = outData[outDcount]; //Ziel IP/client read out
}
else {
outDcount++;
if (outData[0] <= outDcount) { //1. Byte gibt länge der Daten an!
if (sendTOO <= WLANmaxIP) { //Ziel in range?
//read Data:
#if defined(Z21DATADEBUG)
Debug.print(sendTOO);
Debug.print(F(" Z21 RX: "));
for (byte i = 0; i < outData[0]; i++) {
Debug.print(outData[i], HEX);
Debug.print(" ");
}
Debug.println(F("WLAN ok")); //Accept
#endif
if (outData[0] >= Z21_BIG_UDP_MIN_SIZE) { //Check if there is really Data in?
z21.receive(sendTOO, outData);
}
else if (outData[0] == 0x02) { //length == 2, then ESP report client IP-Hash
listofWLANHash[sendTOO] = outData[1];
#if defined(Z21DATADEBUG)
Debug.print(sendTOO + 1);
Debug.print(F(" Z21 Client Hash: "));
Debug.println(outData[1], HEX);
#endif
}
else {
#if defined(Z21DATADEBUG)
Debug.println("Length ERROR!");
WLAN.println(); //new sync!
#endif
}
outData[1] = sendTOO; //Store Client that send the DATA
}
#if defined(Z21DATADEBUG)
else {
Debug.print(F("Z21 EE ")); //Fail
Debug.println(sendTOO, HEX);
WLAN.println(); //new sync!
}
#endif
//Reset to read next data:
outDcount = 0;
sendTOO = 0xFF;
} //END of Data received "normal"!
else if ((outDcount >= Z21_UDP_TX_MAX_SIZE) || (sendTOO == 'E' && outData[0] == 'E') || (outData[outDcount-2] == 'E' && outData[outDcount-1] == 'E')) {
#if defined(Z21DATADEBUG)
Debug.write(sendTOO); //Fail?
for (byte i = 0; i < outDcount; i++)
Debug.write(outData[i]);
Debug.print(F(" FLUSH "));
Debug.print(outDcount);
Debug.println(" Data!");
#endif
WLAN.println(); //new sync!
//WLAN.flush(); //clear
outDcount = 0; //reset read buffer
sendTOO = 0xFF;
}
else if ((sendTOO == 'O' && outData[0] == 'K') || (outData[outDcount-2] == 'O' && outData[outDcount-1] == 'K')) { //keine valied Data!
#if defined(Z21DATADEBUG)
Debug.println(F("Z21 OK"));
#endif
outDcount = 0; //reset read buffer
sendTOO = 0xFF;
}
else if (sendTOO > WLANmaxIP) {
#if defined(Z21DATADEBUG)
Debug.print(F("Z21 Error: 0x"));
Debug.println(sendTOO, HEX);
#endif
outDcount = 0; //reset read buffer
sendTOO = 0xFF;
}
return; //just count the Data byte that we had read!
} // ENDE Z21 Data
//----------------------------------------------
/*ESP System Config:
** 0xE0 = AP IP
** 0xE1 = AP SSID Name
** 0xE2 = AP Password
** 0xE3 = AP Channel
** 0xE4 = Client IP
** 0xE5 = Client SSID Name
** 0xE6 = Client Password
** 0xE7 = S88 Module
** 0xE8 = ESP Sw Version
** 0xE9 = AP Client Connected
* 0xEA = WLAN RSSI
* 0xEB = IP-HASH clients
* 0xEC = reserved
* 0xED = reserved
* 0xEF = reserved
* 0xFE = Set S88 Module
* 0xFA = Z21 "OK"!
* 0xFB = ERROR "EE" Fail
*/
//receive config of Serial WLAN ESP8266:
if ((sendTOO & 0xF0) == 0xE0) {
if ((sendTOO & 0x0F) < WLAN_Config_Size) {
String data = WLAN.readStringUntil('\n');
#if defined(DEBUG_WLAN_CONFIG) || defined(Z21DATADEBUG)
WLANConfDebug(sendTOO & 0x0F, data);
#endif
#if defined(Z21DISPLAY)
switch (sendTOO) {
case 0xE4: WLANlocalIP.fromString(data); //Client IP
if (Railpower ==csNormal) {
DisplayCounter = 0xFF;
DisplayConfigData();
}
break;
case 0xE5: WLANssid = data; //Client SSID Name
if (Railpower ==csNormal) {
DisplayCounter = 0xFF;
DisplayConfigData();
}
break;
case 0xE8: ESPSwVer = data.toFloat(); break; //ESP Sw Version
case 0xE9: ESPsoftAPStationNum = data.toInt(); //AP Client Connected
}
#endif
}
else if (sendTOO == 0xEA) { //WLAN RSSI
if (WLAN.available() > 0) {
#if defined(Z21DISPLAY)
//WLAN Signal RSSI is reported:
WLAN_Signal = WLAN.read();
if ((WLAN_Signal >> 7) == 1) { // >= 128
WLAN_Signal = (256 - WLAN_Signal) * -1; //make it negativ (db)
}
#if defined(Z21SYSTEMDATADEBUG)
Debug.print(F(" WLAN-Signal: "));
Debug.println(WLAN_Signal); //read
#endif
IPpreviousMillis = 0; //reset counter to update display now!
#else
WLAN.read(); //empty buffer, data not in use!
#endif
}
}
else if (sendTOO == 0xEB) { //IP-HASH clients
byte HashData = 0x00;
byte ClientCount = 0;
#if defined(Z21DEBUG)
Debug.print(F("Report Clients: "));
#endif
while (WLAN.available() > 0) {
HashData = WLAN.read();
if (HashData != 0x00) {
listofWLANHash[ClientCount] = HashData;
ClientCount++;
#if defined(Z21DEBUG)
Debug.print(ClientCount);
Debug.print(F(" IPHash: "));
Debug.print(HashData, HEX);
Debug.print(F("; "));
#endif
}
}
#if defined(Z21DEBUG)
if (ClientCount == 0)
Debug.print(F(" none!"));
Debug.println();
#endif
}
outDcount = 0; //reset read buffer
sendTOO = 0xFF;
} //ENDE WLAN Config
else if (sendTOO == 0xFA) { //Quittung!
#if defined(Z21DATADEBUG)
Debug.println(F("Z21 OK"));
#endif
outDcount = 0; //reset read buffer
sendTOO = 0xFF;
}
else if (sendTOO == 0xFB) { //ERROR!
#if defined(Z21DATADEBUG)
Debug.println(F("Z21 ERROR"));
#endif
outDcount = 0; //reset read buffer
sendTOO = 0xFF;
}
//Set S88 Module
else if (sendTOO == 0xFE) {
if (WLAN.available() > 0) {
uint8_t Module = WLAN.read();
#if defined(S88N)
if (Module <= S88MAXMODULE) { // && sendTOO >= 0
S88Module = Module;
#if defined(REPORT)
Debug.print(F("Set S88 Module: "));
Debug.println(S88Module);
#endif
if (FIXSTORAGE.read(EES88Moduls) != S88Module) {
FIXSTORAGE.FIXMODE(EES88Moduls, S88Module);
SetupS88();
WLANSetup();
}
}
#else
WLAN.write(0xFE);
WLAN.write(0xFE); //kein S88 aktiv!
#endif
outDcount = 0; //reset read buffer
sendTOO = 0xFF;
}
}
} //ENDE if wlan available
else {
//no data - stream is over!
outDcount = 0; //reset read buffer
sendTOO = 0xFF;
}
}
#endif
//--------------------------------------------------------------------------------------------
#if defined(LAN) || defined(ESP_WIFI)
byte Z21addIP (byte ip0, byte ip1, byte ip2, byte ip3, unsigned int port) {
//suche ob IP schon vorhanden?
for (byte i = 0; i < storedIP; i++) {
if (mem[i].IP0 == ip0 && mem[i].IP1 == ip1 && mem[i].IP2 == ip2 && mem[i].IP3 == ip3) {
mem[i].time = ActTimeIP; //setzte Zeit
mem[i].port = port; //update port!
return i+1;
}
}
if (storedIP >= LANmaxIP) {
for (byte i = 0; i < storedIP; i++) {
if (mem[i].time == 0) { //Abgelaufende IP, dort eintragen!
mem[i].IP0 = ip0;
mem[i].IP1 = ip1;
mem[i].IP2 = ip2;
mem[i].IP3 = ip3;
mem[i].port = port;
mem[i].time = ActTimeIP; //setzte Zeit
return i+1;
}
}
return 0; //keine freien IPs (never reach here!)
}
mem[storedIP].IP0 = ip0;
mem[storedIP].IP1 = ip1;
mem[storedIP].IP2 = ip2;
mem[storedIP].IP3 = ip3;
mem[storedIP].port = port;
mem[storedIP].time = ActTimeIP; //setzte Zeit
storedIP++;
return storedIP;
}
#endif
//--------------------------------------------------------------------------------------------
void Z21LANreceive() {
//-------------------------------------------------------------------------------------------
//receive LAN data or we run on ESP MCU:
#if defined(LAN) || defined(ESP_WIFI)
byte packetSize = Udp.parsePacket();
if(packetSize) { //packetSize
IPAddress remote = Udp.remoteIP();
byte packetBuffer[packetSize];
Udp.read(packetBuffer,packetSize); // read the packet into packetBufffer
if (packetSize == packetBuffer[0]) { //normal:
#if defined(Z21DATADEBUG)
Debug.print(Z21addIP(remote[0], remote[1], remote[2], remote[3], Udp.remotePort()) + Z21_Eth_offset);
Debug.print(" Z21 RX: ");
for (byte i = 0; i < packetBuffer[0]; i++) {
Debug.print(packetBuffer[i], HEX);
Debug.print(" ");
}
Debug.println();
#endif
z21.receive(Z21addIP(remote[0], remote[1], remote[2], remote[3], Udp.remotePort()) + Z21_Eth_offset, packetBuffer);
}
else { //kombiniertes UDP Paket:
#if defined(Z21DATADEBUG)
Debug.print(packetSize);
Debug.print(F(" BIG Z21 RX: "));
for (byte i = 0; i < packetSize; i++) {
Debug.print(packetBuffer[i], HEX);
Debug.print(" ");
}
Debug.println();
#endif
byte readpos = 0; //data length position des aktuellen Paket
//durchlaufe alle Pakete:
do {
//check if packet length is not empty and okay?
if (packetBuffer[readpos] >= Z21_BIG_UDP_MIN_SIZE) {
byte pBuffer[packetBuffer[readpos]]; //make a array of packet length
for (byte i = 0; i < packetBuffer[readpos]; i++) //fill up array with packet
pBuffer[i] = packetBuffer[readpos + i];
#if defined(Z21DATADEBUG)
Debug.print("#-- "); //Big UDP = in one Packet!
Debug.print(Z21addIP(remote[0], remote[1], remote[2], remote[3], Udp.remotePort()) + Z21_Eth_offset);
Debug.print(F(" Z21 RX: "));
for (byte i = 0; i < pBuffer[0]; i++) {
Debug.print(pBuffer[i], HEX);
Debug.print(" ");
}
Debug.println();
#endif
z21.receive(Z21addIP(remote[0], remote[1], remote[2], remote[3], Udp.remotePort()) + Z21_Eth_offset, pBuffer);
readpos = packetBuffer[readpos] + readpos; //bestimme position des nächsten Paket
}
else {
#if defined(Z21DATADEBUG)
Debug.print("Length ERROR! ");
Debug.println(packetBuffer[readpos]);
#endif
break; //Stop here!
}
}
while(readpos < packetSize);
}
}
#endif
#if defined(WIFI)
WLANEvent();
#endif
//----------------------------------------------
//Nutzungszeit IP's bestimmen und update SystemInfo
unsigned long currentMillis = millis();
if((currentMillis - IPpreviousMillis) >= IPinterval) {
IPpreviousMillis = currentMillis;
#if defined(LAN) || defined(ESP_WIFI)
for (byte i = 0; i < storedIP; i++) {
if (mem[i].time > 0) {
mem[i].time--; //Zeit herrunterrechnen
#if defined(Z21DATADEBUG)
if (mem[i].time == 0) {
Debug.print(i + Z21_Eth_offset + 1);
Debug.println(F(" LAN client timed out"));
}
#endif
}
}
#endif
//interval:
#if defined(BOOSTER_INT_MAINCURRENT)
notifyz21getSystemInfo(0); //SysInfo an alle BC Clients senden!
#endif
}
//----------------------------------------------
#if defined(Z21DISPLAY) && defined(ESP_WIFI)
if (ESPLastConnetionState != WiFi.status()) {
ESPLastConnetionState = WiFi.status();
if (Railpower ==csNormal) { //Update data on Display
DisplayCounter = 0xFF;
DisplayConfigData();
}
}
#endif
//----------------------------------------------
}
//--------------------------------------------------------------------------------------------
#if defined(S88N)
//Ask for Feedback data of group index:
void notifyz21S88Data(uint8_t gIndex) {
//S88sendon = 'i';
reportS88Data(gIndex);
}
#endif
//--------------------------------------------------------------------------------------------
void notifyz21RailPower(uint8_t State)
{
if (Railpower != State) {
#if defined(Z21DEBUG)
Debug.print(F("z21 "));
#endif
globalPower(State);
}
}
//--------------------------------------------------------------------------------------------
void notifyz21LocoState(uint16_t Adr, uint8_t data[])
{
#if defined(DCC)
AllLocoData(Adr, data);
#endif
#if defined(LOCONET) && !defined(LnSLOTSRV)
LNGetSetLocoSlot(Adr, true); //send status to LocoNet
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21LocoFkt(uint16_t Adr, uint8_t state, uint8_t fkt)
{
#if defined(DCC)
dcc.setLocoFunc(Adr, state, fkt);
#endif
#if defined(LOCONET) && defined(DCC)
if (fkt <= 4) {
byte DIRF = dcc.getFunktion0to4(Adr) | (dcc.getLocoDir(Adr) << 5);
sendLNDIRF(Adr, DIRF);
}
else if (fkt >= 5 && fkt <= 8)
sendLNSND(Adr, dcc.getFunktion5to8(Adr));
else if (fkt >= 9 && fkt <= 12)
sendLNF3 (Adr, dcc.getFunktion9to12(Adr));
else if (fkt >= 13 && fkt <= 20)
sendLNF4 (Adr, dcc.getFunktion13to20(Adr));
else if (fkt >= 21 && fkt <= 28)
sendLNF5 (Adr, dcc.getFunktion21to28(Adr));
#endif
#if defined(XPRESSNET) && defined(DCC)
if (fkt <= 4)
XpressNet.setFunc0to4(Adr, dcc.getFunktion0to4(Adr));
else if (fkt >= 5 && fkt <= 8)
XpressNet.setFunc5to8(Adr, dcc.getFunktion5to8(Adr));
else if (fkt >= 9 && fkt <= 12)
XpressNet.setFunc9to12(Adr, dcc.getFunktion9to12(Adr));
else if (fkt >= 13 && fkt <= 20)
XpressNet.setFunc13to20(Adr, dcc.getFunktion13to20(Adr));
else if (fkt >= 21 && fkt <= 28)
XpressNet.setFunc21to28(Adr, dcc.getFunktion21to28(Adr));
XpressNet.ReqLocoBusy(Adr); //Lok wird nicht von LokMaus gesteuert!
#endif
#if defined(Z21DEBUG) && defined(DCC)
Debug.print("Z21 A:");
Debug.print(Adr);
Debug.print(" Dir: ");
Debug.print(dcc.getLocoDir(Adr), BIN);
if (fkt <= 4) {
Debug.print(", F1:");
Debug.println(dcc.getFunktion0to4(Adr), BIN);
}
else if (fkt >= 5 && fkt <= 8) {
Debug.print(", F2:");
Debug.println(dcc.getFunktion5to8(Adr), BIN);
}
else if (fkt >= 9 && fkt <= 12) {
Debug.print(", F3:");
Debug.println(dcc.getFunktion9to12(Adr), BIN);
}
else if (fkt >= 13 && fkt <= 20) {
Debug.print(", F4:");
Debug.println(dcc.getFunktion13to20(Adr), BIN);
}
else if (fkt >= 21 && fkt <= 28) {
Debug.print(", F5:");
Debug.println(dcc.getFunktion21to28(Adr), BIN);
}
else if (fkt >= 29 && fkt <= 31) {
Debug.print(", F6:");
Debug.println(dcc.getFunktion29to31(Adr), BIN);
}
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21LocoFkt0to4(uint16_t Adr, uint8_t fkt)
{
#if defined(DCC)
dcc.setFunctions0to4(Adr, fkt);
#endif
#if defined(LOCONET) && defined(DCC)
sendLNDIRF(Adr, fkt | (dcc.getLocoDir(Adr) << 5));
#endif
#if defined(XPRESSNET)
XpressNet.setFunc0to4(Adr, fkt);
XpressNet.ReqLocoBusy(Adr); //Lok wird nicht von LokMaus gesteuert!
#endif
#if defined(Z21DEBUG) && defined(DCC)
Debug.print("Z21 A:");
Debug.print(Adr);
Debug.print(", F0-4:");
Debug.println(dcc.getFunktion0to4(Adr), BIN);
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21LocoFkt5to8(uint16_t Adr, uint8_t fkt)
{
#if defined(DCC)
dcc.setFunctions5to8(Adr, fkt);
#endif
#if defined(LOCONET)
sendLNSND(Adr, fkt);
#endif
#if defined(XPRESSNET)
XpressNet.setFunc5to8(Adr, fkt);
XpressNet.ReqLocoBusy(Adr); //Lok wird nicht von LokMaus gesteuert!
#endif
#if defined(Z21DEBUG) && defined(DCC)
Debug.print("Z21 A:");
Debug.print(Adr);
Debug.print(", F5-8:");
Debug.println(dcc.getFunktion5to8(Adr), BIN);
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21LocoFkt9to12(uint16_t Adr, uint8_t fkt)
{
#if defined(DCC)
dcc.setFunctions9to12(Adr, fkt);
#endif
#if defined(LOCONET)
sendLNF3 (Adr, fkt);
#endif
#if defined(XPRESSNET)
XpressNet.setFunc9to12(Adr, fkt);
XpressNet.ReqLocoBusy(Adr); //Lok wird nicht von LokMaus gesteuert!
#endif
#if defined(Z21DEBUG) && defined(DCC)
Debug.print("Z21 A:");
Debug.print(Adr);
Debug.print(", F9-12:");
Debug.println(dcc.getFunktion9to12(Adr), BIN);
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21LocoFkt13to20(uint16_t Adr, uint8_t fkt)
{
#if defined(DCC)
dcc.setFunctions13to20(Adr, fkt);
#endif
#if defined(LOCONET)
sendLNF4 (Adr, fkt);
#endif
#if defined(XPRESSNET)
XpressNet.setFunc13to20(Adr, fkt);
XpressNet.ReqLocoBusy(Adr); //Lok wird nicht von LokMaus gesteuert!
#endif
#if defined(Z21DEBUG) && defined(DCC)
Debug.print("Z21 A:");
Debug.print(Adr);
Debug.print(", F13-20:");
Debug.println(dcc.getFunktion13to20(Adr), BIN);
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21LocoFkt21to28(uint16_t Adr, uint8_t fkt)
{
#if defined(DCC)
dcc.setFunctions21to28(Adr, fkt);
#endif
#if defined(LOCONET)
sendLNF5 (Adr, fkt);
#endif
#if defined(XPRESSNET)
XpressNet.setFunc21to28(Adr, fkt);
XpressNet.ReqLocoBusy(Adr); //Lok wird nicht von LokMaus gesteuert!
#endif
#if defined(Z21DEBUG) && defined(DCC)
Debug.print("Z21 A:");
Debug.print(Adr);
Debug.print(", F21-28:");
Debug.println(dcc.getFunktion21to28(Adr), BIN);
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21LocoFkt29to36(uint16_t Adr, uint8_t fkt)
{
#if defined(DCC)
dcc.setFunctions29to36(Adr, fkt);
#endif
#if defined(Z21DEBUG)
Debug.print("Z21 A:");
Debug.print(Adr);
Debug.print(", F29-36:");
Debug.println(fkt, BIN);
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21LocoFkt37to44(uint16_t Adr, uint8_t fkt)
{
#if defined(DCC)
dcc.setFunctions37to44(Adr, fkt);
#endif
#if defined(Z21DEBUG)
Debug.print("Z21 A:");
Debug.print(Adr);
Debug.print(", F37-44:");
Debug.println(fkt, BIN);
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21LocoFkt45to52(uint16_t Adr, uint8_t fkt)
{
#if defined(DCC)
dcc.setFunctions45to52(Adr, fkt);
#endif
#if defined(Z21DEBUG)
Debug.print("Z21 A:");
Debug.print(Adr);
Debug.print(", F45-52:");
Debug.println(fkt, BIN);
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21LocoFkt53to60(uint16_t Adr, uint8_t fkt)
{
#if defined(DCC)
dcc.setFunctions53to60(Adr, fkt);
#endif
#if defined(Z21DEBUG)
Debug.print("Z21 A:");
Debug.print(Adr);
Debug.print(", F53-60:");
Debug.println(fkt, BIN);
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21LocoFkt61to68(uint16_t Adr, uint8_t fkt)
{
#if defined(DCC)
dcc.setFunctions61to68(Adr, fkt);
#endif
#if defined(Z21DEBUG)
Debug.print("Z21 A:");
Debug.print(Adr);
Debug.print(", F61-68:");
Debug.println(fkt, BIN);
#endif
}
//--------------------------------------------------------------------------------------------
//Binärzustandsadressen von 29 bis 32767
void notifyz21LocoFktExt(uint16_t Adr, uint8_t low, uint8_t high)
{
#if defined(DCC)
dcc.setLocoFuncBinary(Adr, low, high);
#endif
#if defined(Z21DEBUG)
Debug.print("Z21 A:");
Debug.print(Adr);
Debug.print(", F");
Debug.print((high << 7) + (low & 0x7F));
Debug.print(": ");
Debug.println(low >> 7); //Zustand
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21LocoSpeed(uint16_t Adr, uint8_t speed, uint8_t steps)
{
if (Adr == 0) {
#if defined(Z21DEBUG)
Debug.print(F("Z21 A:"));
Debug.print(Adr);
Debug.println(F(" ERROR not a loco!"));
#endif
return;
}
#if defined(LOCONET)
switch (steps) {
case 14: sendLNSPD(Adr, map(speed, 0, 14, 0, 128)); break;
case 28: sendLNSPD(Adr, map(speed, 0, 28, 0, 128)); break;
default: sendLNSPD(Adr, speed);
}
#endif
#if defined(XPRESSNET)
XpressNet.setSpeed(Adr, steps, speed);
XpressNet.ReqLocoBusy(Adr); //Lok wird nicht von LokMaus gesteuert!
#endif
switch (steps) {
case 14: dcc.setSpeed14(Adr, speed); break;
case 28: dcc.setSpeed28(Adr, speed); break;
default: dcc.setSpeed128(Adr, speed);
}
#if defined(Z21DEBUG)
Debug.print(F("Z21 A:"));
Debug.print(Adr);
Debug.print(", S");
Debug.print(steps);
Debug.print(":");
Debug.println(speed, BIN);
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21Accessory(uint16_t Adr, bool state, bool active)
{
#if defined(DCC)
dcc.setBasicAccessoryPos(Adr, state, active);
#endif
}
//--------------------------------------------------------------------------------------------
uint8_t notifyz21AccessoryInfo(uint16_t Adr)
//return state of the Address (left/right = true/false)
{
#if defined(DCC)
#if defined(Z21DEBUG)
Debug.print("Z21 GetAccInfo: ");
Debug.print(Adr);
Debug.print("-");
Debug.println(dcc.getBasicAccessoryInfo(Adr));
#endif
return dcc.getBasicAccessoryInfo(Adr);
#else
return 0x00;
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21ExtAccessory(uint16_t Adr, byte state)
{
#if defined(DCC)
dcc.setExtAccessoryPos(Adr, state);
#endif
#if defined(Z21DEBUG)
Debug.print("Z21 SetExtAcc: ");
Debug.print(Adr);
Debug.print("-");
Debug.println(state);
#endif
}
#if defined(LOCONET)
//--------------------------------------------------------------------------------------------
uint8_t notifyz21LNdispatch(uint16_t Adr)
//return the Slot that was dispatched, 0xFF at error!
{
#if defined(Z21DEBUG)
Debug.print("Z21 LNdispatch: ");
Debug.println(Adr);
#endif
return LNdispatch(Adr);
}
//--------------------------------------------------------------------------------------------
void notifyz21LNSendPacket(uint8_t *data, uint8_t length)
{
#if defined(LnDEB)
Debug.print(F("LOCONET_FROM_LAN "));
#endif
LNSendPacket (data, length, Z21bcLocoNet_s, false); //Report nicht an Z21 Library!
LNdecode(false); //verarbeite empfangene Daten, aber nicht als Z21 RX!
}
//--------------------------------------------------------------------------------------------
void notifyz21LNdetector(uint8_t client, uint8_t typ, uint16_t Adr) {
#if defined(Z21DEBUG)
Debug.print(F("LAN_LOCONET_DETECTOR 0x"));
Debug.print(Adr);
Debug.print("-");
Debug.print(typ, HEX);
#endif
if (typ == 0x80) { //SIC Abfrage
byte data[4];
data[0] = 0x01; //Typ
data[1] = Adr & 0xFF;
data[2] = Adr >> 8;
data[3] = dcc.getBasicAccessoryInfo(Adr); //Zustand Rückmelder
#if defined(Z21DEBUG)
Debug.print(F(" State: "));
Debug.println(data[3], BIN);
#endif
z21.setLNDetector(client, data, 4);
}
#if defined(Z21DEBUG)
else Debug.println();
#endif
}
#endif //LOCONET
/*
//--------------------------------------------------------------------------------------------
void notifyz21CANdetector(uint8_t client, uint8_t typ, uint16_t ID) {
#if defined(Z21DEBUG)
Debug.print(F("CAN_DETECTOR "));
Debug.print(typ);
Debug.print("=");
Debug.println(ID);
#endif
}
//z21.setCANDetector(uint16_t NID, uint16_t Adr, uint8_t port, uint8_t typ, uint16_t v1, uint16_t v2);
*/
//--------------------------------------------------------------------------------------------
//read out the current of the booster main
void notifyz21getSystemInfo(uint8_t client) {
#if defined(BOOSTER_INT_MAINCURRENT)
uint16_t inAm = getRailmA();
uint16_t volt = getRailVolt();
#ifdef DALLASTEMPSENSE
if((millis() - temp_timer) >= DALLAS_Temp_Int) { //á 10 sec.
temp = sensors.getTempCByIndex(0);
sensors.requestTemperatures(); // Send the command to get temperatures
temp_timer = millis();
}
#elif defined(MEGA_MCU)
temp = analogRead(TempPin);
#if defined(AREF_1V1)
temp = (1024-temp) / (temp / 34.5);
#else
temp = (1024-temp) / (temp / 11.5);
#endif
#endif
#if defined(Z21SYSTEMDATADEBUG)
Debug.print("mA: ");
Debug.print(inAm);
Debug.print("(");
Debug.print(VAmpINT); //Volt on VAmpIntPin
Debug.print(")_V");
#if defined(VoltIntPin) //ESP8266 has only one ADC for current sense!
Debug.print(analogRead(VoltIntPin));
Debug.print(":");
#endif
Debug.print(volt); //Rail Voltage: Rail:100k - Sense - 4,7k - GND
Debug.print("_T:");
Debug.println(temp);
#endif
#if defined(Z21DISPLAY)
DisplayUpdateRailData(inAm,volt,temp);
#endif
z21.sendSystemInfo(client, inAm, volt, temp); //report System State to z21 client
//(12-22V): 20V=0x4e20, 21V=0x5208, 22V=0x55F0
#else
z21.sendSystemInfo(client, 0, 0, 0); //report zero System State to z21 client
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21CVREAD(uint8_t cvAdrMSB, uint8_t cvAdrLSB)
{
unsigned int cvAdr = cvAdrMSB << 8 | cvAdrLSB;
#if defined(Z21DEBUG)
Debug.print(F("Z21 read CV#"));
Debug.println(cvAdr+1);
#endif
#if defined(DCC)
dcc.opsReadDirectCV(cvAdr); //read cv
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21CVWRITE(uint8_t cvAdrMSB, uint8_t cvAdrLSB, uint8_t value)
{
unsigned int cvAdr = cvAdrMSB << 8 | cvAdrLSB;
#if defined(Z21DEBUG)
Debug.print(F("Z21 set CV#"));
Debug.print(cvAdr+1);
Debug.print(" - ");
Debug.println(value);
#endif
#if defined(DCC)
dcc.opsProgDirectCV(cvAdr,value); //return value from DCC via 'notifyCVVerify'
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21CVPOMWRITEBYTE(uint16_t Adr, uint16_t cvAdr, uint8_t value)
{
#if defined(RCDEB)
Debug.print(F("Z21 POM Byte A"));
Debug.print(Adr);
Debug.print(F(" set CV#"));
Debug.print(cvAdr+1);
Debug.print(" - ");
Debug.println(value);
#endif
#if defined(DCC)
dcc.opsProgramCV(Adr, cvAdr, value); //set decoder byte
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21CVPOMWRITEBIT(uint16_t Adr, uint16_t cvAdr, uint8_t value)
{
#if defined(RCDEB)
Debug.print(F("Z21 POM Bit A"));
Debug.print(Adr);
Debug.print(F(" set CV#"));
Debug.print(cvAdr+1);
Debug.print(" - ");
Debug.println(value);
#endif
#if defined(DCC)
dcc.opsPOMwriteBit(Adr, cvAdr, value); //set decoder bit
#endif
}
//--------------------------------------------------------------------------------------------
void notifyz21CVPOMREADBYTE (uint16_t Adr, uint16_t cvAdr)
{
#if defined(DCCGLOBALDETECTOR) && defined(DCC)
#if defined(RCDEB)
Debug.print(F("Z21 POM A"));
Debug.print(Adr);
Debug.print(" read CV#");
Debug.println(cvAdr+1);
#endif
RailcomCVAdr = cvAdr;
#if defined(MEGA_MCU)
RailComStart(); //Start Reading Data!
#endif
#else
z21.setCVNack(); //Antwort: LAN_X_CV_NACK
#endif
#if defined(DCC)
dcc.opsPOMreadCV(Adr, cvAdr); //get decoder value
#endif
}
//--------------------------------------------------------------------------------------------
//Information to DCC Libray via EEPROM (50 to 75) over RailCom, ProgModus, etc.
void notifyz21UpdateConf() {
FIXSTORAGE.FIXMODE(EEPROMDCCPROPERTY, (FIXSTORAGE.read(EEPROMDCCPROPERTY) & 0xFC) | 0x02); //Ausgabeformat nur DCC (Ausgabeformat (0x00) DCC+MM, (0x02) nur DCC, (0x03) nur MM)
#if defined(ESP_WIFI)
FIXSTORAGE.commit();
#endif
#if defined(Z21DEBUG)
Debug.println("Z21 Conf: ");
Debug.print(F("RailCom: ")); //RailCom: 0=aus/off, 1=ein/on
Debug.print(FIXSTORAGE.read(EEPROMRailCom), HEX);
Debug.print(F(", PWR-B: ")); //Power-Button: 0=Gleisspannung aus, 1=Nothalt
Debug.print(FIXSTORAGE.read(52), HEX);
Debug.print(F(", Prog-R: ")); //Auslese-Modus: 0=Nichts, 1=Bit, 2=Byte, 3=Beides
Debug.print(FIXSTORAGE.read(EEPROMProgReadMode), HEX);
Debug.print(F(", RstP(s): "));
Debug.print(FIXSTORAGE.read(EEPROMRSTsRepeat));
Debug.print(F(", RstP(f): "));
Debug.print(FIXSTORAGE.read(EEPROMRSTcRepeat));
Debug.print(F(", ProgP: "));
Debug.print(FIXSTORAGE.read(EEPROMProgRepeat));
Debug.print(F(", MainV: "));
Debug.print(word(FIXSTORAGE.read(73),FIXSTORAGE.read(72)));
Debug.print(F(", ProgV: "));
Debug.println(word(FIXSTORAGE.read(75),FIXSTORAGE.read(74)));
#endif
#if defined(DCC)
dcc.loadEEPROMconfig(); //Update values!
#endif
}
//--------------------------------------------------------------------------------------------
//Information Abfrage Z21 Library
uint8_t notifyz21ClientHash(uint8_t client) {
byte HashIP = 0x00;
#if defined(LAN) || defined(ESP_WIFI)
if (client < Z21_Eth_offset) { //Prüfe über Offset ob WiFi or LAN
#endif
#if defined(WIFI)
//get Client IP-Hash from WiFi
HashIP = listofWLANHash[client - 1];
#endif
#if defined(LAN) || defined(ESP_WIFI)
}
else {
//get Client IP-Hash from Ethernet Interface
byte cl = client - Z21_Eth_offset - 1; //senden ohne Offset!
HashIP = mem[cl].IP0 ^ mem[cl].IP1 ^ mem[cl].IP2 ^ mem[cl].IP3; //make Hash from IP
}
#endif
#if defined(Z21DEBUG)
Debug.print(client);
Debug.print(F(" IPHash: "));
Debug.print(HashIP, HEX);
Debug.print(F(" BC: "));
Debug.println(FIXSTORAGE.read(0x200 | HashIP), BIN);
#endif
return HashIP; //not found!
}
//--------------------------------------------------------------------------------------------
//bug fix for enc28 Ethernet shield with UIP Library - need to do this after each packet!
#if defined (LAN) && defined (ENC28)
void restartENC28() {
Udp.stop(); // added for enc28
#if defined(Z21SYSTEMDATADEBUG)
Debug.print("restart connection: ");// added for enc28
Debug.println(Udp.begin(z21Port) ? "success" : "failed");// added for enc28
#else
Udp.begin(z21Port);
#endif
}
#endif
//--------------------------------------------------------------------------------------------
void notifyz21EthSend(uint8_t client, uint8_t *data)
{
#if defined(Z21DATADEBUG)
Debug.print(client);
Debug.print(F(" Z21 TX: "));
for (byte i = 0; i < data[0]; i++) {
Debug.print(data[i], HEX);
Debug.print(" ");
}
Debug.println();
#endif
if (client == 0) { //all stored
#if defined(LAN) || defined(ESP_WIFI)
for (byte i = 0; i < storedIP; i++) {
if (mem[i].time > 0) { //noch aktiv?
IPAddress ip(mem[i].IP0, mem[i].IP1, mem[i].IP2, mem[i].IP3);
Udp.beginPacket(ip, mem[i].port); //Broadcast
Udp.write(data, data[0]);
Udp.endPacket();
#if defined (LAN) && defined (ENC28)
restartENC28(); //fix bug!
#endif
}
}
#endif
#if defined(WIFI)
WLAN.write(client);
WLAN.write(data, data[0]);
#endif
}
else {
#if defined(LAN) || defined(ESP_WIFI)
if (client < Z21_Eth_offset) { //Prüfe über Offset ob WiFi or LAN
#endif
#if defined(WIFI)
WLAN.write(client);
WLAN.write(data, data[0]);
#endif
#if defined(LAN) || defined(ESP_WIFI)
}
else {
byte cl = client - Z21_Eth_offset - 1; //senden ohne Offset!
IPAddress ip(mem[cl].IP0, mem[cl].IP1, mem[cl].IP2, mem[cl].IP3);
Udp.beginPacket(ip, mem[cl].port); //no Broadcast
Udp.write(data, data[0]);
Udp.endPacket();
}
#endif
}
#if defined (LAN) && defined (ENC28)
restartENC28(); //fix bug!
#endif
}
//---------------------------------
#endif