-
Notifications
You must be signed in to change notification settings - Fork 1
/
XpressNetMaster.h
285 lines (238 loc) · 12.4 KB
/
XpressNetMaster.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/*
XpressNetMaster.h - library for XpressNet Master protocoll
Copyright (c) 2023 Philipp Gahtow All right reserved.
Notice:
Support for XPressNet v4.1
Change History:
- timing issue when change to the next slot
- add busy request for loco
- narrow conversation compiler warning
- speed up transmission window (Callbyte) and adjust timing
- add MultiMaus full Support for F13 to F20
- add unknown message return
- add UART RX interrupt
- add UART TX Buffer with interrupt control
- fix MultiMaus CV read and write in Master Mode
- fix speed step setting
- add ack request answer in slave mode
- add feedback return to all clients
- add POM write byte and bit
- fix slave ack return
- add support for RAW Data in-/output
- add inside 'AddBusySlot' a skip if already busy by this slot
- adjust init client mode power setting
- add support ESP8266 with RS485SoftwareSerial
- fix sending long Adresses missing the two highest bits of the High bytes are set to "1" (0xC000)
- fix hanging in CV-Prog
- fix Accessory Decoder operation request Byte 2
- fix Locomotive speed and direction operation (0xE4) Speed Steps
- fix range CV# Adr to uint16_t
- add software serial support for ESP8266 and ESP32
- add internal power function
- add support for XpressNet v4.0 with switch up to 2048
- fix SWSERIAL_PARITY_MARK to PARITY_MARK because they change the name!
- remove blocking Interrups while tx on ESP8266 and ESP32
*/
// ensure this library description is only included once
#ifndef XpressNetMaster_h
#define XpressNetMaster_h
//CONFIG:
#define XNetVersion 0x40 //System Bus Version
#define XNetID 0x10 //Zentrale: 0x00 = LZ100; 0x01 = LH200; 0x10 = ROCO MultiMaus; 0x02 = other;
// include types & constants of Wiring core API
#if defined(WIRING)
#include <Wiring.h>
#elif ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
/* From the ATMega datasheet: */
//--------------------------------------------------------------------------------------------
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //Arduino MEGA
#define SERIAL_PORT_1
#undef SERIAL_PORT_0
#elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__) //Sanguino (other pins!)
#define SERIAL_PORT_1
#undef SERIAL_PORT_0
#else //others Arduino UNO
#define SERIAL_PORT_0
#undef SERIAL_PORT_1
#endif
//--------------------------------------------------------------------------------------------
//only for Debug:
//#define XNetSerial Serial //Debugging Serial
//#define XNetDEBUG //Put out the messages
//#define XNetDEBUGTime //Put out the microseconds
//--------------------------------------------------------------------------------------------
/*An XpressNet device designed to work with XpressNet V3 and later systems must be designed so that it
begins its transmission within 110 microseconds of receiving its transmission window. (older X-Bus
based systems required this transmission to begin with in 40 microseconds.) Command stations must be
designed to accept transmissions received up to 120 microseconds after transmitting the window. The
difference is to provide a design tolerance between the different types of devices.
Under normal conditions an XpressNet device must be designed to be able to handle the receipt of its
next transmission window between 400 microseconds and 500 milliseconds after the receipt of the last window. */
#if defined(ESP8266) || defined(ESP32)
#define XNetTransmissionWindow 3000 //wait longer = slower, because software serial interrupt
#else
#define XNetTransmissionWindow 500 //max time to wait until data will be received
#endif
//XpressNet Buffer length (send and receive):
#define XNetBufferSize 5 //max Data Pakets (max: 4 Bit = 16!)
//XpressNet Mode (Master/Slave)
#define XNetSlaveCycle 0xFF //max (255) cycles to Stay in SLAVE MODE when no CallByte is received
//Fahrstufen:
#define Loco14 0x00 //FFF = 000 = 14 speed step
#define Loco27 0x01 //FFF = 001 = 27 speed step
#define Loco28 0x02 //FFF = 010 = 28 speed step
#define Loco128 0x04 //FFF = 100 = 128 speed step
// XPressnet Call Bytes.
// broadcast to everyone, we save the incoming data and process it later.
#define GENERAL_BROADCAST 0x60 //0x160
#define FB_BROADCAST 0xA0 //0x1A0
#define MY_ADDRESS 0x5F //only for SLAVE-MODE Adr=31 (0x5F) or Adr=26 (0x5A)!
#define ACK_REQ 0x9A //Acknowledge-Anforderungen beantworten mit 0x20 0x20
// certain global XPressnet status indicators
#define csNormal 0x00 // Normal Operation Resumed ist eingeschaltet
#define csEmergencyStop 0x01 // Der Nothalt ist eingeschaltet
#define csTrackVoltageOff 0x02 // Die Gleisspannung ist abgeschaltet
#define csShortCircuit 0x04 // Kurzschluss
#define csServiceMode 0x08 // Der Programmiermodus ist aktiv - Service Mode
//XpressNet Befehl, with max. 7 data bytes!
#define XNetCallByte 0 //CallByte
#define XNetheader 1 //Header
#define XNetdata1 2 //Databyte1
#define XNetdata2 3 //Databyte2
#define XNetdata3 4 //Databyte3
#define XNetdata4 5 //Databyte4
#define XNetdata5 6 //Databyte5
#define XNetdata6 7 //Databyte6
#define XNetdata7 8 //Databyte7
#define XNetCRC 9 //Checksumme
#define XNetBufferMaxData 10 //max Bytes over all for each Paket
typedef struct //Msg Seicher
{
uint8_t length; //Speicher für Datenlänge
uint8_t data[XNetBufferMaxData]; //zu sendende Daten
} XNetMessage;
typedef struct //Buffer
{
XNetMessage msg[XNetBufferSize];
uint8_t get; //position we are with reading
uint8_t put; //position we are with writing
uint8_t pos; //byte position for write
} XNetBuffer;
// library interface description
class XpressNetMasterClass
{
// user-accessible "public" interface
public:
XpressNetMasterClass(void); //Constuctor
#if defined(ESP8266) || defined(ESP32)
void setup(uint8_t FStufen, uint8_t XNetPort, uint8_t XControl, bool XnModeAuto = true); //Initialisierung Serial
#else
void setup(uint8_t FStufen, uint8_t XControl, bool XnModeAuto = true); //Initialisierung Serial
#endif
bool update(void); //Set new Data on the Dataline
bool getOperationModeMaster(void); //gibt TRUE zurück wenn aktuelle Master Mode aktiv ist!
void setPower(byte Power); //Zustand Gleisspannung Melden
void setBCFeedback(byte data1, byte data2); //Rückmeldedaten an Clients verteilen
//Control Loco
void ReqLocoBusy(uint16_t Adr); //Lok Adresse besetzt melden
void SetLocoBusy(uint8_t UserOps, uint16_t Adr); //Lok besetzt melden
void getStatus(); //Staus der Zentrale erfragen
void getLocoInfo(uint16_t Adr); //Slave Modus Lok Informationen erfragen!
void getLocoFkt(uint16_t Adr); //Slave Modus Lok Funktionen erfragen!
void SetLocoInfo(uint8_t UserOps, uint8_t Speed, uint8_t F0, uint8_t F1); //Lokinfo an XNet Melden
void SetLocoInfo(uint8_t UserOps, uint8_t Steps, uint8_t Speed, uint8_t F0, uint8_t F1); //Lokinfo an XNet Melden
void SetFktStatus(uint8_t UserOps, uint8_t F4, uint8_t F5); //LokFkt an XNet Melden
void SetLocoInfoMM(uint8_t UserOps, uint8_t Steps, uint8_t Speed, uint8_t F0, uint8_t F1, uint8_t F2, uint8_t F3);
void SetTrntStatus(uint8_t UserOps, uint16_t Address, uint8_t Data); // data=0000 00AA A=Weichenausgang1+2 (Aktive/Inaktive);
void SetTrntPos(uint16_t Address, uint8_t state, uint8_t active); //Änderung der Weichenlage
void setSpeed(uint16_t Adr, uint8_t Steps, uint8_t Speed);
void setFunc0to4(uint16_t Adr, uint8_t G1); //Gruppe 1: 0 0 0 F0 F4 F3 F2 F1
void setFunc5to8(uint16_t Adr, uint8_t G2); //Gruppe 2: 0 0 0 0 F8 F7 F6 F5
void setFunc9to12(uint16_t Adr, uint8_t G3); //Gruppe 3: 0 0 0 0 F12 F11 F10 F9
void setFunc13to20(uint16_t Adr, uint8_t G4); //Gruppe 4: F20 F19 F18 F17 F16 F15 F14 F13
void setFunc21to28(uint16_t Adr, uint8_t G5); //Gruppe 5: F28 F27 F26 F25 F24 F23 F22 F21
void setCVReadValue(uint8_t cvAdr, uint8_t value); //return a CV data read
void setCVNack(void); //no ACK
void setCVNackSC(void); //no ACK Short Circuit
// public only for easy access by interrupt handlers
static inline void handle_RX_interrupt(); //Serial RX Interrupt bearbeiten
static inline void handle_TX_interrupt(); //Serial TX Interrupt bearbeiten
// library-accessible "private" interface
private:
//Variables:
bool XModeAuto; //ON = Automatische Umschaltung Master/Slave-Mode; OFF = Slave Mode only
uint8_t XNetSlaveMode; // > 0 then we are working in SLAVE MODE
uint8_t XNetSlaveInit; //send initialize sequence
byte Railpower; //Data of the actual Power State
byte Fahrstufe; //Standard für Fahrstufe
byte MAX485_CONTROL; //Port for send or receive control
uint8_t XNetAdr; //Adresse des Abzufragenden XNet Device
unsigned long XSendCount; //Zeit: Call Byte ausgesendet, data received
XNetBuffer XNetRXBuffer; //Read Buffer
byte callByteParity (byte me); // calculate the parity bit
uint8_t CallByteInquiry;
uint8_t RequestAck;
uint8_t DirectedOps;
uint16_t SlotLokUse[32]; //store loco to DirectedOps
void SetBusy(uint8_t Slot); //send busy message to slot that doesn't use
void AddBusySlot(uint8_t UserOps, uint16_t Adr); //add loco to slot
void XNetRXclear(uint8_t b); //Clear a spezial RX Message
//Functions:
void unknown(void); //unbekannte Anfrage
void getNextXNetAdr(void); //NÄCHSTE Adr of XNet Device
bool XNetCheckXOR(void); //Checks the XOR
void XNetAnalyseReceived(void); //work on received data
//Serial send and receive:
#if defined(__AVR__)
static XpressNetMasterClass *active_object; //aktuelle aktive Object for interrupt handler
#endif
XNetBuffer XNetTXBuffer;
void XNetsend(byte *dataString, byte byteCount); //Sende Datenarray out NOW!
uint16_t XNetReadBuffer(void); //read out next Buffer Data
void getXOR (uint8_t *data, byte length); // calculate the XOR
void XNetSendData(void); //Sendet Daten aus dem Buffer mittels Interrupt
void XNetSendNext(void); //Recursives sende weiterer Daten aus dem Buffer
void XNetReceive(void); //Speichern der eingelesenen Daten
uint16_t XNetCVAdr; //CV Adr that was read
uint8_t XNetCVvalue; //read CV Value
uint16_t SlaveRequestLocoInfo = 0; //Lok that we request for Lokdata
uint16_t SlaveRequestLocoFkt = 0; //Lok that we request for Lok funktions
};
#if defined (__cplusplus)
extern "C" {
#endif
extern void notifyXNetPower(uint8_t State) __attribute__((weak));
extern uint8_t getPowerState() __attribute__((weak)); //give Back Actual Power State
//Fahrbefehl:
extern void notifyXNetgiveLocoInfo(uint8_t UserOps, uint16_t Address) __attribute__((weak));
extern void notifyXNetLocoDrive14(uint16_t Address, uint8_t Speed) __attribute__((weak));
extern void notifyXNetLocoDrive27(uint16_t Address, uint8_t Speed) __attribute__((weak));
extern void notifyXNetLocoDrive28(uint16_t Address, uint8_t Speed) __attribute__((weak));
extern void notifyXNetLocoDrive128(uint16_t Address, uint8_t Speed) __attribute__((weak));
//Funktionsbefehl:
extern void notifyXNetgiveLocoFunc(uint8_t UserOps, uint16_t Address) __attribute__((weak));
extern void notifyXNetLocoFunc1(uint16_t Address, uint8_t Func1) __attribute__((weak));//Gruppe1 0 0 0 F0 F4 F3 F2 F1
extern void notifyXNetLocoFunc2(uint16_t Address, uint8_t Func2) __attribute__((weak));//Gruppe2 0000 F8 F7 F6 F5
extern void notifyXNetLocoFunc3(uint16_t Address, uint8_t Func3) __attribute__((weak));//Gruppe3 0000 F12 F11 F10 F9
extern void notifyXNetLocoFuncX(uint16_t Address, uint8_t group, uint8_t Func) __attribute__((weak));//Gruppe4 F20-F13, Gruppe5 F28-F21, .....
//Weichenbefehl:
extern void notifyXNetTrntInfo(uint8_t UserOps, uint16_t Address, uint8_t data) __attribute__((weak));// data=0000 000N N=Nibble N0-(0,1); N1-(2,3);
extern void notifyXNetTrnt(uint16_t Address, uint8_t data) __attribute__((weak));// data=0000 000A A=Weichenausgang (Aktive/Inaktive);
//Rückmeldung:
extern void notifyXNetFeedback(uint16_t Address, uint8_t data) __attribute__((weak));// data=0000 000A A=Weichenausgang (Aktive/Inaktive);
//CV:
extern void notifyXNetDirectCV(uint16_t CV, uint8_t data) __attribute__((weak));
extern void notifyXNetDirectReadCV(uint16_t cvAdr) __attribute__((weak));
//POM:
extern void notifyXNetPOMwriteByte (uint16_t Adr, uint16_t CV, uint8_t data) __attribute__((weak));
extern void notifyXNetPOMwriteBit (uint16_t Adr, uint16_t CV, uint8_t data) __attribute__((weak));
//MultiMaus:
extern void notifyXNetgiveLocoMM(uint8_t UserOps, uint16_t Address) __attribute__((weak));
#if defined (__cplusplus)
}
#endif
#endif