mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2025-07-29 02:13:45 +02:00
Compare commits
111 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8853b23f88 | ||
|
79ce71c2f9 | ||
|
e3cbaf5f24 | ||
|
250c372f5c | ||
|
a9c31eb1ae | ||
|
f8fb08e331 | ||
|
50fcbc088a | ||
|
e2263b1e75 | ||
|
5eabe934b8 | ||
|
8f1ed21aa3 | ||
|
2443e5903c | ||
|
a88454dded | ||
|
c292f210a4 | ||
|
cc4de0ad14 | ||
|
1fab0f586b | ||
|
c15d5048b5 | ||
|
ec2295219d | ||
|
d3ef5f53ae | ||
|
1941402c52 | ||
|
7206e46273 | ||
|
f24bcd6819 | ||
|
cb64725b42 | ||
|
129d1c2039 | ||
|
52e8a93945 | ||
|
88949358b4 | ||
|
38be1d6152 | ||
|
29a4ad0072 | ||
|
a473f6ae5c | ||
|
915af8d981 | ||
|
6eeaacdf90 | ||
|
766f88166c | ||
|
afd08dafc1 | ||
|
7851e7099c | ||
|
04403bbf5e | ||
|
55cce0ef99 | ||
|
dc4fa57dc6 | ||
|
75eefc7677 | ||
|
79763a3bb8 | ||
|
3fa805c0e7 | ||
|
ba8f625fb0 | ||
|
ac37228942 | ||
|
90487d2d83 | ||
|
1807fe5c5f | ||
|
6abb65c1f4 | ||
|
971732fce8 | ||
|
8a03b889a3 | ||
|
e12c3fc295 | ||
|
de8f9396f7 | ||
|
f75a6b47f9 | ||
|
bc1398d3c4 | ||
|
0988340ff8 | ||
|
c7af43c70b | ||
|
79a76e95b6 | ||
|
6766d95344 | ||
|
fb3265a413 | ||
|
93fc674e74 | ||
|
ebfde7cc81 | ||
|
4a2513d576 | ||
|
a01d36c8e5 | ||
|
4583761d03 | ||
|
45a7efc935 | ||
|
d924916381 | ||
|
9ec4f2d62a | ||
|
58d4618868 | ||
|
9fdd251a7b | ||
|
5984abe133 | ||
|
87cc8afdf9 | ||
|
7cef3dad2e | ||
|
7a68b0106d | ||
|
ea85a33e03 | ||
|
05da109144 | ||
|
38b5c0cae2 | ||
|
1b1d8fceb4 | ||
|
bb63a559ad | ||
|
fafaa7a1e1 | ||
|
bce5acc8d0 | ||
|
b3d02350f2 | ||
|
7b2647ad81 | ||
|
67c8366512 | ||
|
ebbe698e51 | ||
|
107e9d1d62 | ||
|
9b4c374cd4 | ||
|
d721ed5184 | ||
|
9073aadab7 | ||
|
d9a7eeeef3 | ||
|
1d6e6ec10e | ||
|
bded5d3588 | ||
|
87481209ec | ||
|
dbe682e5ba | ||
|
83e4e4f6ee | ||
|
45eb7c80b6 | ||
|
b541614a19 | ||
|
4756e767cf | ||
|
9ef0189ae8 | ||
|
e866fd1bd7 | ||
|
51491ac1e0 | ||
|
48524b1175 | ||
|
dc200aab75 | ||
|
3954e058c7 | ||
|
5d0da81377 | ||
|
6a5a8acd17 | ||
|
c27aa3a2d2 | ||
|
d12714d51e | ||
|
1baff001f4 | ||
|
ca7d728b81 | ||
|
c4f45ddc36 | ||
|
b8b9b6d354 | ||
|
8197e2bffa | ||
|
813ad7e6a4 | ||
|
a7d0042403 | ||
|
2651934a75 |
@@ -27,7 +27,8 @@
|
||||
/*
|
||||
* © 2020,2021 Chris Harlow, Harald Barth, David Cutting,
|
||||
* Fred Decker, Gregor Baues, Anthony W - Dayton All rights reserved.
|
||||
*
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -58,15 +59,18 @@ void setup()
|
||||
// Responsibility 1: Start the usb connection for diagnostics
|
||||
// This is normally Serial but uses SerialUSB on a SAMD processor
|
||||
Serial.begin(115200);
|
||||
|
||||
|
||||
DIAG(F("License GPLv3 fsf.org (c) dcc-ex.com"));
|
||||
|
||||
CONDITIONAL_LCD_START {
|
||||
// This block is still executed for DIAGS if LCD not in use
|
||||
LCD(0,F("DCC++ EX v%S"),F(VERSION));
|
||||
LCD(1,F("Starting"));
|
||||
LCD(1,F("Lic GPLv3"));
|
||||
}
|
||||
|
||||
// Start the WiFi interface on a MEGA, Uno cannot currently handle WiFi
|
||||
|
||||
// Responsibility 2: Start all the communications before the DCC engine
|
||||
// Start the WiFi interface on a MEGA, Uno cannot currently handle WiFi
|
||||
// Start Ethernet if it exists
|
||||
#if WIFI_ON
|
||||
WifiInterface::setup(WIFI_SERIAL_LINK_SPEED, F(WIFI_SSID), F(WIFI_PASSWORD), F(WIFI_HOSTNAME), IP_PORT, WIFI_CHANNEL);
|
||||
#endif // WIFI_ON
|
||||
@@ -79,12 +83,9 @@ void setup()
|
||||
// Note: this provides DCC with two motor drivers, main and prog, which handle the motor shield(s)
|
||||
// Standard supported devices have pre-configured macros but custome hardware installations require
|
||||
// detailed pin mappings and may also require modified subclasses of the MotorDriver to implement specialist logic.
|
||||
|
||||
// STANDARD_MOTOR_SHIELD, POLOLU_MOTOR_SHIELD, FIREBOX_MK1, FIREBOX_MK1S are pre defined in MotorShields.h
|
||||
DCC::begin(MOTOR_SHIELD_TYPE);
|
||||
|
||||
|
||||
DCC::begin(MOTOR_SHIELD_TYPE);
|
||||
|
||||
#if defined(RMFT_ACTIVE)
|
||||
RMFT::begin();
|
||||
#endif
|
||||
|
127
DCC.cpp
127
DCC.cpp
@@ -126,7 +126,7 @@ void DCC::setFunctionInternal(int cab, byte byte1, byte byte2) {
|
||||
if (byte1!=0) b[nB++] = byte1;
|
||||
b[nB++] = byte2;
|
||||
|
||||
DCCWaveform::mainTrack.schedulePacket(b, nB, 3); // send packet 3 times
|
||||
DCCWaveform::mainTrack.schedulePacket(b, nB, 0);
|
||||
}
|
||||
|
||||
uint8_t DCC::getThrottleSpeed(int cab) {
|
||||
@@ -137,12 +137,12 @@ uint8_t DCC::getThrottleSpeed(int cab) {
|
||||
|
||||
bool DCC::getThrottleDirection(int cab) {
|
||||
int reg=lookupSpeedTable(cab);
|
||||
if (reg<0) return false ;
|
||||
if (reg<0) return true;
|
||||
return (speedTable[reg].speedCode & 0x80) !=0;
|
||||
}
|
||||
|
||||
// Set function to value on or off
|
||||
void DCC::setFn( int cab, byte functionNumber, bool on) {
|
||||
void DCC::setFn( int cab, int16_t functionNumber, bool on) {
|
||||
if (cab<=0 ) return;
|
||||
|
||||
if (functionNumber>28) {
|
||||
@@ -159,7 +159,7 @@ void DCC::setFn( int cab, byte functionNumber, bool on) {
|
||||
else {
|
||||
b[nB++] = 0b11000000; // Binary State Control Instruction long form
|
||||
b[nB++] = (functionNumber & 0x7F) | (on ? 0x80 : 0); // low order bits and state flag
|
||||
b[nB++] = functionNumber >>8 ; // high order bits
|
||||
b[nB++] = functionNumber >>7 ; // high order bits
|
||||
}
|
||||
DCCWaveform::mainTrack.schedulePacket(b, nB, 4);
|
||||
return;
|
||||
@@ -183,7 +183,7 @@ void DCC::setFn( int cab, byte functionNumber, bool on) {
|
||||
// Change function according to how button was pressed,
|
||||
// typically in WiThrottle.
|
||||
// Returns new state or -1 if nothing was changed.
|
||||
int DCC::changeFn( int cab, byte functionNumber, bool pressed) {
|
||||
int DCC::changeFn( int cab, int16_t functionNumber, bool pressed) {
|
||||
int funcstate = -1;
|
||||
if (cab<=0 || functionNumber>28) return funcstate;
|
||||
int reg = lookupSpeedTable(cab);
|
||||
@@ -213,7 +213,7 @@ int DCC::changeFn( int cab, byte functionNumber, bool pressed) {
|
||||
return funcstate;
|
||||
}
|
||||
|
||||
int DCC::getFn( int cab, byte functionNumber) {
|
||||
int DCC::getFn( int cab, int16_t functionNumber) {
|
||||
if (cab<=0 || functionNumber>28) return -1; // unknown
|
||||
int reg = lookupSpeedTable(cab);
|
||||
if (reg<0) return -1;
|
||||
@@ -224,7 +224,7 @@ int DCC::getFn( int cab, byte functionNumber) {
|
||||
|
||||
// Set the group flag to say we have touched the particular group.
|
||||
// A group will be reminded only if it has been touched.
|
||||
void DCC::updateGroupflags(byte & flags, int functionNumber) {
|
||||
void DCC::updateGroupflags(byte & flags, int16_t functionNumber) {
|
||||
byte groupMask;
|
||||
if (functionNumber<=4) groupMask=FN_GROUP_1;
|
||||
else if (functionNumber<=8) groupMask=FN_GROUP_2;
|
||||
@@ -398,10 +398,6 @@ const ackOp FLASH READ_CV_PROG[] = {
|
||||
|
||||
const ackOp FLASH LOCO_ID_PROG[] = {
|
||||
BASELINE,
|
||||
SETCV, (ackOp)1,
|
||||
SETBIT, (ackOp)7,
|
||||
V0,WACK,NAKFAIL, // test CV 1 bit 7 is a zero... NAK means no loco found
|
||||
|
||||
SETCV, (ackOp)19, // CV 19 is consist setting
|
||||
SETBYTE, (ackOp)0,
|
||||
VB, WACK, ITSKIP, // ignore consist if cv19 is zero (no consist)
|
||||
@@ -691,9 +687,31 @@ byte DCC::ackManagerBitNum;
|
||||
bool DCC::ackReceived;
|
||||
bool DCC::ackManagerRejoin;
|
||||
|
||||
CALLBACK_STATE DCC::callbackState=READY;
|
||||
|
||||
ACK_CALLBACK DCC::ackManagerCallback;
|
||||
|
||||
void DCC::ackManagerSetup(int cv, byte byteValueOrBitnum, ackOp const program[], ACK_CALLBACK callback) {
|
||||
if (!DCCWaveform::progTrack.canMeasureCurrent()) {
|
||||
callback(-2);
|
||||
return;
|
||||
}
|
||||
|
||||
ackManagerRejoin=DCCWaveform::progTrackSyncMain;
|
||||
if (ackManagerRejoin ) {
|
||||
// Change from JOIN must zero resets packet.
|
||||
setProgTrackSyncMain(false);
|
||||
DCCWaveform::progTrack.sentResetsSincePacket = 0;
|
||||
}
|
||||
|
||||
DCCWaveform::progTrack.autoPowerOff=false;
|
||||
if (DCCWaveform::progTrack.getPowerMode() == POWERMODE::OFF) {
|
||||
DCCWaveform::progTrack.autoPowerOff=true; // power off afterwards
|
||||
if (Diag::ACK) DIAG(F("Auto Prog power on"));
|
||||
DCCWaveform::progTrack.setPowerMode(POWERMODE::ON);
|
||||
DCCWaveform::progTrack.sentResetsSincePacket = 0;
|
||||
}
|
||||
|
||||
ackManagerCv = cv;
|
||||
ackManagerProg = program;
|
||||
ackManagerByte = byteValueOrBitnum;
|
||||
@@ -703,8 +721,7 @@ void DCC::ackManagerSetup(int cv, byte byteValueOrBitnum, ackOp const program[]
|
||||
|
||||
void DCC::ackManagerSetup(int wordval, ackOp const program[], ACK_CALLBACK callback) {
|
||||
ackManagerWord=wordval;
|
||||
ackManagerProg = program;
|
||||
ackManagerCallback = callback;
|
||||
ackManagerSetup(0, 0, program, callback);
|
||||
}
|
||||
|
||||
const byte RESET_MIN=8; // tuning of reset counter before sending message
|
||||
@@ -723,21 +740,9 @@ void DCC::ackManagerLoop() {
|
||||
// (typically waiting for a reset counter or ACK waiting, or when all finished.)
|
||||
switch (opcode) {
|
||||
case BASELINE:
|
||||
ackManagerRejoin=DCCWaveform::progTrackSyncMain;
|
||||
if (!DCCWaveform::progTrack.canMeasureCurrent()) {
|
||||
callback(-2);
|
||||
return;
|
||||
}
|
||||
setProgTrackSyncMain(false);
|
||||
if (DCCWaveform::progTrack.getPowerMode() == POWERMODE::OFF) {
|
||||
if (Diag::ACK) DIAG(F("Auto Prog power on"));
|
||||
DCCWaveform::progTrack.setPowerMode(POWERMODE::ON);
|
||||
DCCWaveform::progTrack.sentResetsSincePacket = 0;
|
||||
DCCWaveform::progTrack.autoPowerOff=true;
|
||||
return;
|
||||
}
|
||||
if (checkResets(DCCWaveform::progTrack.autoPowerOff ? 20 : 3)) return;
|
||||
if (checkResets(DCCWaveform::progTrack.autoPowerOff || ackManagerRejoin ? 20 : 3)) return;
|
||||
DCCWaveform::progTrack.setAckBaseline();
|
||||
callbackState=READY;
|
||||
break;
|
||||
case W0: // write 0 bit
|
||||
case W1: // write 1 bit
|
||||
@@ -748,6 +753,7 @@ void DCC::ackManagerLoop() {
|
||||
byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction };
|
||||
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS);
|
||||
DCCWaveform::progTrack.setAckPending();
|
||||
callbackState=AFTER_WRITE;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -758,6 +764,7 @@ void DCC::ackManagerLoop() {
|
||||
byte message[] = {cv1(WRITE_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte};
|
||||
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS);
|
||||
DCCWaveform::progTrack.setAckPending();
|
||||
callbackState=AFTER_WRITE;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -888,21 +895,65 @@ void DCC::ackManagerLoop() {
|
||||
ackManagerProg++;
|
||||
}
|
||||
}
|
||||
void DCC::callback(int value) {
|
||||
ackManagerProg=NULL; // no more steps to execute
|
||||
if (DCCWaveform::progTrack.autoPowerOff) {
|
||||
if (Diag::ACK) DIAG(F("Auto Prog power off"));
|
||||
DCCWaveform::progTrack.doAutoPowerOff();
|
||||
}
|
||||
|
||||
// Restore <1 JOIN> to state before BASELINE
|
||||
setProgTrackSyncMain(ackManagerRejoin);
|
||||
void DCC::callback(int value) {
|
||||
static unsigned long callbackStart;
|
||||
// We are about to leave programming mode
|
||||
// Rule 1: If we have written to a decoder we must maintain power for 100mS
|
||||
// Rule 2: If we are re-joining the main track we must power off for 30mS
|
||||
|
||||
switch (callbackState) {
|
||||
case AFTER_WRITE: // first attempt to callback after a write operation
|
||||
if (!ackManagerRejoin && !DCCWaveform::progTrack.autoPowerOff) {
|
||||
callbackState=READY;
|
||||
break;
|
||||
} // lines 906-910 added. avoid wait after write. use 1 PROG
|
||||
callbackStart=millis();
|
||||
callbackState=WAITING_100;
|
||||
if (Diag::ACK) DIAG(F("Stable 100mS"));
|
||||
break;
|
||||
|
||||
case WAITING_100: // waiting for 100mS
|
||||
if (millis()-callbackStart < 100) break;
|
||||
// stable after power maintained for 100mS
|
||||
|
||||
// If we are going to power off anyway, it doesnt matter
|
||||
// but if we will keep the power on, we must off it for 30mS
|
||||
if (DCCWaveform::progTrack.autoPowerOff) callbackState=READY;
|
||||
else { // Need to cycle power off and on
|
||||
DCCWaveform::progTrack.setPowerMode(POWERMODE::OFF);
|
||||
callbackStart=millis();
|
||||
callbackState=WAITING_30;
|
||||
if (Diag::ACK) DIAG(F("OFF 30mS"));
|
||||
}
|
||||
break;
|
||||
|
||||
case WAITING_30: // waiting for 30mS with power off
|
||||
if (millis()-callbackStart < 30) break;
|
||||
//power has been off for 30mS
|
||||
DCCWaveform::progTrack.setPowerMode(POWERMODE::ON);
|
||||
callbackState=READY;
|
||||
break;
|
||||
|
||||
case READY: // ready after read, or write after power delay and off period.
|
||||
// power off if we powered it on
|
||||
if (DCCWaveform::progTrack.autoPowerOff) {
|
||||
if (Diag::ACK) DIAG(F("Auto Prog power off"));
|
||||
DCCWaveform::progTrack.doAutoPowerOff();
|
||||
}
|
||||
// Restore <1 JOIN> to state before BASELINE
|
||||
if (ackManagerRejoin) {
|
||||
setProgTrackSyncMain(true);
|
||||
if (Diag::ACK) DIAG(F("Auto JOIN"));
|
||||
}
|
||||
|
||||
if (Diag::ACK) DIAG(F("Callback(%d)"),value);
|
||||
(ackManagerCallback)( value);
|
||||
ackManagerProg=NULL; // no more steps to execute
|
||||
if (Diag::ACK) DIAG(F("Callback(%d)"),value);
|
||||
(ackManagerCallback)( value);
|
||||
}
|
||||
}
|
||||
|
||||
void DCC::displayCabList(Print * stream) {
|
||||
void DCC::displayCabList(Print * stream) {
|
||||
|
||||
int used=0;
|
||||
for (int reg = 0; reg < MAX_LOCOS; reg++) {
|
||||
|
19
DCC.h
19
DCC.h
@@ -54,6 +54,14 @@ enum ackOp : byte
|
||||
SKIPTARGET = 0xFF // jump to target
|
||||
};
|
||||
|
||||
enum CALLBACK_STATE : byte {
|
||||
AFTER_WRITE, // Start callback sequence after something was written to the decoder
|
||||
WAITING_100, // Waiting for 100mS of stable power
|
||||
WAITING_30, // waiting to 30ms of power off gap.
|
||||
READY, // Ready to complete callback
|
||||
};
|
||||
|
||||
|
||||
// Allocations with memory implications..!
|
||||
// Base system takes approx 900 bytes + 8 per loco. Turnouts, Sensors etc are dynamically created
|
||||
#ifdef ARDUINO_AVR_UNO
|
||||
@@ -76,10 +84,10 @@ public:
|
||||
static void writeCVByteMain(int cab, int cv, byte bValue);
|
||||
static void writeCVBitMain(int cab, int cv, byte bNum, bool bValue);
|
||||
static void setFunction(int cab, byte fByte, byte eByte);
|
||||
static void setFn(int cab, byte functionNumber, bool on);
|
||||
static int changeFn(int cab, byte functionNumber, bool pressed);
|
||||
static int getFn(int cab, byte functionNumber);
|
||||
static void updateGroupflags(byte &flags, int functionNumber);
|
||||
static void setFn(int cab, int16_t functionNumber, bool on);
|
||||
static int changeFn(int cab, int16_t functionNumber, bool pressed);
|
||||
static int getFn(int cab, int16_t functionNumber);
|
||||
static void updateGroupflags(byte &flags, int16_t functionNumber);
|
||||
static void setAccessory(int aAdd, byte aNum, bool activate);
|
||||
static bool writeTextPacket(byte *b, int nBytes);
|
||||
static void setProgTrackSyncMain(bool on); // when true, prog track becomes driveable
|
||||
@@ -141,12 +149,13 @@ private:
|
||||
static bool ackReceived;
|
||||
static bool ackManagerRejoin;
|
||||
static ACK_CALLBACK ackManagerCallback;
|
||||
static CALLBACK_STATE callbackState;
|
||||
static void ackManagerSetup(int cv, byte bitNumOrbyteValue, ackOp const program[], ACK_CALLBACK callback);
|
||||
static void ackManagerSetup(int wordval, ackOp const program[], ACK_CALLBACK callback);
|
||||
static void ackManagerLoop();
|
||||
static bool checkResets( uint8_t numResets);
|
||||
static const int PROG_REPEATS = 8; // repeats of programming commands (some decoders need at least 8 to be reliable)
|
||||
|
||||
|
||||
// NMRA codes #
|
||||
static const byte SET_SPEED = 0x3f;
|
||||
static const byte WRITE_BYTE_MAIN = 0xEC;
|
||||
|
21
DCCEX.h
21
DCCEX.h
@@ -1,3 +1,24 @@
|
||||
/*
|
||||
* (c) 2020 Chris Harlow. All rights reserved.
|
||||
* (c) 2021 Fred Decker. All rights reserved.
|
||||
* (c) 2020 Harald Barth. All rights reserved.
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* It is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// This include is intended to visually simplify the .ino for the end users.
|
||||
// If there were any #ifdefs required they are much better handled in here.
|
||||
|
||||
|
@@ -578,7 +578,11 @@ bool DCCEXParser::parseZ(Print *stream, int16_t params, int16_t p[])
|
||||
}
|
||||
return true;
|
||||
|
||||
case 3: // <Z ID PIN INVERT>
|
||||
case 3: // <Z ID PIN IFLAG>
|
||||
if (p[0] < 0 ||
|
||||
p[1] > 255 || p[1] <= 1 || // Pins 0 and 1 are Serial to USB
|
||||
p[2] < 0 || p[2] > 7 )
|
||||
return false;
|
||||
if (!Output::create(p[0], p[1], p[2], 1))
|
||||
return false;
|
||||
StringFormatter::send(stream, F("<O>\n"));
|
||||
|
@@ -72,10 +72,13 @@ INTERRUPT_CALLBACK interruptHandler=0;
|
||||
}
|
||||
|
||||
bool DCCTimer::isPWMPin(byte pin) {
|
||||
(void) pin;
|
||||
return false; // TODO what are the relevant pins?
|
||||
}
|
||||
|
||||
void DCCTimer::setPWM(byte pin, bool high) {
|
||||
(void) pin;
|
||||
(void) high;
|
||||
// TODO what are the relevant pins?
|
||||
}
|
||||
|
||||
@@ -97,12 +100,15 @@ INTERRUPT_CALLBACK interruptHandler=0;
|
||||
|
||||
bool DCCTimer::isPWMPin(byte pin) {
|
||||
//Teensy: digitalPinHasPWM, todo
|
||||
(void) pin;
|
||||
return false; // TODO what are the relevant pins?
|
||||
}
|
||||
|
||||
void DCCTimer::setPWM(byte pin, bool high) {
|
||||
// TODO what are the relevant pins?
|
||||
}
|
||||
(void) pin;
|
||||
(void) high;
|
||||
}
|
||||
|
||||
void DCCTimer::getSimulatedMacAddress(byte mac[6]) {
|
||||
#if defined(__IMXRT1062__) //Teensy 4.0 and Teensy 4.1
|
||||
|
20
DCCTimer.h
20
DCCTimer.h
@@ -1,3 +1,23 @@
|
||||
/*
|
||||
* (c) 2021 Mike S. All rights reserved.
|
||||
* (c) 2021 Fred Decker. All rights reserved.
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* It is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DCCTimer_h
|
||||
#define DCCTimer_h
|
||||
#include "Arduino.h"
|
||||
|
@@ -31,7 +31,10 @@ DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false);
|
||||
bool DCCWaveform::progTrackSyncMain=false;
|
||||
bool DCCWaveform::progTrackBoosted=false;
|
||||
int DCCWaveform::progTripValue=0;
|
||||
|
||||
volatile uint8_t DCCWaveform::numAckGaps=0;
|
||||
volatile uint8_t DCCWaveform::numAckSamples=0;
|
||||
uint8_t DCCWaveform::trailingEdgeCounter=0;
|
||||
|
||||
void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver) {
|
||||
mainTrack.motorDriver=mainDriver;
|
||||
progTrack.motorDriver=progDriver;
|
||||
@@ -290,13 +293,15 @@ void DCCWaveform::setAckPending() {
|
||||
ackPulseDuration=0;
|
||||
ackDetected=false;
|
||||
ackCheckStart=millis();
|
||||
numAckSamples=0;
|
||||
numAckGaps=0;
|
||||
ackPending=true; // interrupt routines will now take note
|
||||
}
|
||||
|
||||
byte DCCWaveform::getAck() {
|
||||
if (ackPending) return (2); // still waiting
|
||||
if (Diag::ACK) DIAG(F("%S after %dmS max=%d/%dmA pulse=%duS"),ackDetected?F("ACK"):F("NO-ACK"), ackCheckDuration,
|
||||
ackMaxCurrent,motorDriver->raw2mA(ackMaxCurrent), ackPulseDuration);
|
||||
if (Diag::ACK) DIAG(F("%S after %dmS max=%d/%dmA pulse=%duS samples=%d gaps=%d"),ackDetected?F("ACK"):F("NO-ACK"), ackCheckDuration,
|
||||
ackMaxCurrent,motorDriver->raw2mA(ackMaxCurrent), ackPulseDuration, numAckSamples, numAckGaps);
|
||||
if (ackDetected) return (1); // Yes we had an ack
|
||||
return(0); // pending set off but not detected means no ACK.
|
||||
}
|
||||
@@ -310,10 +315,15 @@ void DCCWaveform::checkAck() {
|
||||
}
|
||||
|
||||
int current=motorDriver->getCurrentRaw();
|
||||
numAckSamples++;
|
||||
if (current > ackMaxCurrent) ackMaxCurrent=current;
|
||||
// An ACK is a pulse lasting between minAckPulseDuration and maxAckPulseDuration uSecs (refer @haba)
|
||||
|
||||
if (current>ackThreshold) {
|
||||
if (trailingEdgeCounter > 0) {
|
||||
numAckGaps++;
|
||||
trailingEdgeCounter = 0;
|
||||
}
|
||||
if (ackPulseStart==0) ackPulseStart=micros(); // leading edge of pulse detected
|
||||
return;
|
||||
}
|
||||
@@ -321,9 +331,21 @@ void DCCWaveform::checkAck() {
|
||||
// not in pulse
|
||||
if (ackPulseStart==0) return; // keep waiting for leading edge
|
||||
|
||||
// if we reach to this point, we have
|
||||
// detected trailing edge of pulse
|
||||
ackPulseDuration=micros()-ackPulseStart;
|
||||
|
||||
if (trailingEdgeCounter == 0) {
|
||||
ackPulseDuration=micros()-ackPulseStart;
|
||||
}
|
||||
|
||||
// but we do not trust it yet and return (which will force another
|
||||
// measurement) and first the third time around with low current
|
||||
// the ack detection will be finalized.
|
||||
if (trailingEdgeCounter < 2) {
|
||||
trailingEdgeCounter++;
|
||||
return;
|
||||
}
|
||||
trailingEdgeCounter = 0;
|
||||
|
||||
if (ackPulseDuration>=minAckPulseDuration && ackPulseDuration<=maxAckPulseDuration) {
|
||||
ackCheckDuration=millis()-ackCheckStart;
|
||||
ackDetected=true;
|
||||
|
@@ -161,8 +161,11 @@ class DCCWaveform {
|
||||
unsigned int ackPulseDuration; // micros
|
||||
unsigned long ackPulseStart; // micros
|
||||
|
||||
unsigned int minAckPulseDuration = 2000; // micros
|
||||
unsigned int minAckPulseDuration = 4000; // micros
|
||||
unsigned int maxAckPulseDuration = 8500; // micros
|
||||
|
||||
|
||||
volatile static uint8_t numAckGaps;
|
||||
volatile static uint8_t numAckSamples;
|
||||
static uint8_t trailingEdgeCounter;
|
||||
};
|
||||
#endif
|
||||
|
22
DisplayInterface.cpp
Normal file
22
DisplayInterface.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* © 2021, Chris Harlow, Neil McKechnie. All rights reserved.
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* It is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "DisplayInterface.h"
|
||||
|
||||
DisplayInterface *DisplayInterface::lcdDisplay = 0;
|
35
DisplayInterface.h
Normal file
35
DisplayInterface.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* © 2021, Chris Harlow, Neil McKechnie. All rights reserved.
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* It is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef DisplayInterface_h
|
||||
#define DisplayInterface_h
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// Definition of base class for displays. The base class does nothing.
|
||||
class DisplayInterface : public Print {
|
||||
public:
|
||||
virtual DisplayInterface* loop2(bool force) { (void)force; return NULL; };
|
||||
virtual void setRow(byte line) { (void)line; };
|
||||
virtual void clear() {};
|
||||
virtual size_t write(uint8_t c) { (void)c; return 0; };
|
||||
|
||||
static DisplayInterface *lcdDisplay;
|
||||
};
|
||||
|
||||
#endif
|
25
EEStore.h
25
EEStore.h
@@ -1,3 +1,22 @@
|
||||
/*
|
||||
* (c) 2020 Chris Harlow. All rights reserved.
|
||||
* (c) 2020 Harald Barth. All rights reserved.
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* It is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef EEStore_h
|
||||
#define EEStore_h
|
||||
|
||||
@@ -14,9 +33,9 @@ extern ExternalEEPROM EEPROM;
|
||||
|
||||
struct EEStoreData{
|
||||
char id[sizeof(EESTORE_ID)];
|
||||
int nTurnouts;
|
||||
int nSensors;
|
||||
int nOutputs;
|
||||
uint16_t nTurnouts;
|
||||
uint16_t nSensors;
|
||||
uint16_t nOutputs;
|
||||
};
|
||||
|
||||
struct EEStore{
|
||||
|
@@ -68,6 +68,16 @@ EthernetInterface::EthernetInterface()
|
||||
DIAG(F("Ethernet shield not found"));
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long startmilli = millis();
|
||||
while ((millis() - startmilli) < 5500) // Loop to give time to check for cable connection
|
||||
{
|
||||
if (Ethernet.linkStatus() == LinkON)
|
||||
break;
|
||||
DIAG(F("Ethernet waiting for link (1sec) "));
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
if (Ethernet.linkStatus() == LinkOFF) {
|
||||
DIAG(F("Ethernet cable not connected"));
|
||||
return;
|
||||
|
23
FSH.h
23
FSH.h
@@ -1,3 +1,21 @@
|
||||
/*
|
||||
* (c) 2021 Fred Decker. All rights reserved.
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* It is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef FSH_h
|
||||
#define FSH_h
|
||||
|
||||
@@ -11,6 +29,7 @@
|
||||
* __FlashStringHelper Use FSH instead.
|
||||
* PROGMEM use FLASH instead
|
||||
* pgm_read_byte_near use GETFLASH instead.
|
||||
* pgm_read_word_near use GETFLASHW instead.
|
||||
*
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
@@ -21,10 +40,14 @@
|
||||
#define F(str) (str)
|
||||
typedef char FSH;
|
||||
#define GETFLASH(addr) (*(const unsigned char *)(addr))
|
||||
#define GETFLASHW(addr) (*(const unsigned short *)(addr))
|
||||
#define FLASH
|
||||
#define strlen_P strlen
|
||||
#define strcpy_P strcpy
|
||||
#else
|
||||
typedef __FlashStringHelper FSH;
|
||||
#define GETFLASH(addr) pgm_read_byte_near(addr)
|
||||
#define GETFLASHW(addr) pgm_read_word_near(addr)
|
||||
#define FLASH PROGMEM
|
||||
#endif
|
||||
#endif
|
||||
|
@@ -1 +1 @@
|
||||
#define GITHUB_SHA "e7e8e84"
|
||||
#define GITHUB_SHA "e3cbaf5"
|
||||
|
@@ -73,6 +73,7 @@ void LCDDisplay::loop() {
|
||||
|
||||
LCDDisplay *LCDDisplay::loop2(bool force) {
|
||||
if (!lcdDisplay) return NULL;
|
||||
|
||||
unsigned long currentMillis = millis();
|
||||
|
||||
if (!force) {
|
||||
@@ -159,4 +160,4 @@ void LCDDisplay::moveToNextRow() {
|
||||
void LCDDisplay::skipBlankRows() {
|
||||
while (!done && rowBuffer[rowNext][0] == 0)
|
||||
moveToNextRow();
|
||||
}
|
||||
}
|
||||
|
30
LCDDisplay.h
30
LCDDisplay.h
@@ -19,6 +19,7 @@
|
||||
#ifndef LCDDisplay_h
|
||||
#define LCDDisplay_h
|
||||
#include <Arduino.h>
|
||||
#include "DisplayInterface.h"
|
||||
|
||||
#if __has_include ( "config.h")
|
||||
#include "config.h"
|
||||
@@ -29,43 +30,44 @@
|
||||
#define MAX_MSG_SIZE 16
|
||||
#endif
|
||||
|
||||
// Set default scroll mode (overridable in config.h)
|
||||
#if !defined(SCROLLMODE)
|
||||
#define SCROLLMODE 1
|
||||
#endif
|
||||
|
||||
// This class is created in LCDisplay_Implementation.h
|
||||
|
||||
class LCDDisplay : public Print {
|
||||
class LCDDisplay : public DisplayInterface {
|
||||
public:
|
||||
static const int MAX_LCD_ROWS = 8;
|
||||
static const int MAX_LCD_COLS = MAX_MSG_SIZE;
|
||||
static const long LCD_SCROLL_TIME = 3000; // 3 seconds
|
||||
|
||||
static LCDDisplay* lcdDisplay;
|
||||
LCDDisplay();
|
||||
void interfake(int p1, int p2, int p3);
|
||||
|
||||
// Internally handled functions
|
||||
static void loop();
|
||||
LCDDisplay* loop2(bool force);
|
||||
void setRow(byte line);
|
||||
void clear();
|
||||
|
||||
virtual size_t write(uint8_t b);
|
||||
using Print::write;
|
||||
size_t write(uint8_t b);
|
||||
|
||||
protected:
|
||||
uint8_t lcdRows;
|
||||
uint8_t lcdCols;
|
||||
|
||||
private:
|
||||
void moveToNextRow();
|
||||
void skipBlankRows();
|
||||
|
||||
// Relay functions to the live driver
|
||||
void clearNative();
|
||||
void displayNative();
|
||||
void setRowNative(byte line);
|
||||
void writeNative(char b);
|
||||
// Relay functions to the live driver in the subclass
|
||||
virtual void clearNative() = 0;
|
||||
virtual void setRowNative(byte line) = 0;
|
||||
virtual size_t writeNative(uint8_t b) = 0;
|
||||
|
||||
unsigned long lastScrollTime = 0;
|
||||
int8_t hotRow = 0;
|
||||
int8_t hotCol = 0;
|
||||
int8_t topRow = 0;
|
||||
uint8_t lcdRows;
|
||||
uint8_t lcdCols;
|
||||
int8_t slot = 0;
|
||||
int8_t rowFirst = -1;
|
||||
int8_t rowNext = 0;
|
||||
|
@@ -27,29 +27,27 @@
|
||||
|
||||
#ifndef LCD_Implementation_h
|
||||
#define LCD_Implementation_h
|
||||
#include <Wire.h>
|
||||
#include "LCDDisplay.h"
|
||||
#include "SSD1306Ascii.h"
|
||||
#include "LiquidCrystal_I2C.h"
|
||||
|
||||
LCDDisplay * LCDDisplay::lcdDisplay=0;
|
||||
|
||||
// Implement the LCDDisplay shim class as a singleton.
|
||||
// Notice that the LCDDisplay class declaration (LCDDisplay.h) is independent of the library
|
||||
// but the implementation is compiled here with dependencies on LCDDriver which is
|
||||
// specific to the library in use.
|
||||
// Thats the workaround to the drivers not all implementing a common interface.
|
||||
|
||||
#if defined(OLED_DRIVER)
|
||||
#include "LCD_OLED.h"
|
||||
#define CONDITIONAL_LCD_START for (LCDDisplay * dummy=new LCDDisplay();dummy!=NULL; dummy=dummy->loop2(true))
|
||||
// The DisplayInterface class implements a displayy handler with no code (null device);
|
||||
// The LCDDisplay class sub-classes DisplayInterface to provide the common display code;
|
||||
// Then LCDDisplay class is subclassed to the specific device type classes:
|
||||
// SSD1306AsciiWire for I2C OLED driver with SSD1306 or SH1106 controllers;
|
||||
// LiquidCrystal_I2C for I2C LCD driver for HD44780 with PCF8574 'backpack'.
|
||||
|
||||
#if defined(OLED_DRIVER)
|
||||
#define CONDITIONAL_LCD_START for (DisplayInterface * dummy=new SSD1306AsciiWire(OLED_DRIVER);dummy!=NULL; dummy=dummy->loop2(true))
|
||||
|
||||
#elif defined(LCD_DRIVER)
|
||||
#define CONDITIONAL_LCD_START for (DisplayInterface * dummy=new LiquidCrystal_I2C(LCD_DRIVER);dummy!=NULL; dummy=dummy->loop2(true))
|
||||
|
||||
#elif defined(LCD_DRIVER)
|
||||
#include "LCD_LCD.h"
|
||||
#define CONDITIONAL_LCD_START for (LCDDisplay * dummy=new LCDDisplay();dummy!=NULL; dummy=dummy->loop2(true))
|
||||
|
||||
#else
|
||||
#include "LCD_NONE.h"
|
||||
#define CONDITIONAL_LCD_START if (true) /* NO LCD CONFIG, but do the LCD macros to get DIAGS */
|
||||
#else
|
||||
// Create null display handler just in case someone calls lcdDisplay->something without checking if lcdDisplay is NULL!
|
||||
#define CONDITIONAL_LCD_START { new DisplayInterface(); }
|
||||
#endif
|
||||
|
||||
#endif // LCD_Implementation_h
|
||||
|
18
LCN.h
18
LCN.h
@@ -1,3 +1,21 @@
|
||||
/*
|
||||
* (c) 2021 Fred Decker. All rights reserved.
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* It is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef LCN_h
|
||||
#define LCN_h
|
||||
#include <Arduino.h>
|
||||
|
@@ -20,7 +20,7 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "LiquidCrystal_I2C.h"
|
||||
#include "I2CManager.h"
|
||||
#include "DIAG.h"
|
||||
|
||||
// When the display powers up, it is configured as follows:
|
||||
//
|
||||
@@ -44,30 +44,30 @@
|
||||
LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t lcd_cols,
|
||||
uint8_t lcd_rows) {
|
||||
_Addr = lcd_Addr;
|
||||
_cols = lcd_cols;
|
||||
_rows = lcd_rows;
|
||||
_backlightval = LCD_NOBACKLIGHT;
|
||||
}
|
||||
lcdRows = lcd_rows;
|
||||
lcdCols = lcd_cols;
|
||||
|
||||
void LiquidCrystal_I2C::init() { init_priv(); }
|
||||
_backlightval = 0;
|
||||
|
||||
void LiquidCrystal_I2C::init_priv() {
|
||||
I2CManager.begin();
|
||||
I2CManager.setClock(100000L); // PCF8574 is spec'd to 100kHz.
|
||||
|
||||
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
begin(_cols, _rows);
|
||||
if (I2CManager.exists(lcd_Addr)) {
|
||||
DIAG(F("%dx%d LCD configured on I2C:x%x"), (int)lcd_cols, (int)lcd_rows, (int)lcd_Addr);
|
||||
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
begin();
|
||||
backlight();
|
||||
lcdDisplay = this;
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::begin(uint8_t cols, uint8_t lines) {
|
||||
if (lines > 1) {
|
||||
void LiquidCrystal_I2C::begin() {
|
||||
if (lcdRows > 1) {
|
||||
_displayfunction |= LCD_2LINE;
|
||||
}
|
||||
_numlines = lines;
|
||||
(void)cols; // Suppress compiler warning.
|
||||
|
||||
// according to datasheet, we need at least 40ms after power rises above 2.7V
|
||||
// before sending commands. Arduino can turn on way befer 4.5V so we'll allow
|
||||
// before sending commands. Arduino can turn on way before 4.5V so we'll allow
|
||||
// 100 milliseconds after pulling both RS and R/W and backlight pin low
|
||||
expanderWrite(
|
||||
_backlightval); // reset expander and turn backlight off (Bit 8 =1)
|
||||
@@ -78,19 +78,19 @@ void LiquidCrystal_I2C::begin(uint8_t cols, uint8_t lines) {
|
||||
// figure 24, pg 46
|
||||
|
||||
// we start in 8bit mode, try to set 4 bit mode
|
||||
write4bits(0x03 << 4);
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// second try
|
||||
write4bits(0x03 << 4);
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// third go!
|
||||
write4bits(0x03 << 4);
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// finally, set to 4-bit interface
|
||||
write4bits(0x02 << 4);
|
||||
write4bits(0x02);
|
||||
|
||||
// set # lines, font size, etc.
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
@@ -108,27 +108,21 @@ void LiquidCrystal_I2C::begin(uint8_t cols, uint8_t lines) {
|
||||
// set the entry mode
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
|
||||
setCursor(0, 0);
|
||||
setRowNative(0);
|
||||
}
|
||||
|
||||
/********** high level commands, for the user! */
|
||||
void LiquidCrystal_I2C::clear() {
|
||||
void LiquidCrystal_I2C::clearNative() {
|
||||
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes 1.52ms
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::setCursor(uint8_t col, uint8_t row) {
|
||||
void LiquidCrystal_I2C::setRowNative(byte row) {
|
||||
int row_offsets[] = {0x00, 0x40, 0x14, 0x54};
|
||||
if (row > _numlines) {
|
||||
row = _numlines - 1; // we count rows starting w/0
|
||||
if (row > lcdRows) {
|
||||
row = lcdRows - 1; // we count rows starting w/0
|
||||
}
|
||||
command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
|
||||
}
|
||||
|
||||
// Turn the display on/off (quickly)
|
||||
void LiquidCrystal_I2C::noDisplay() {
|
||||
_displaycontrol &= ~LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
command(LCD_SETDDRAMADDR | (row_offsets[row]));
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::display() {
|
||||
@@ -138,7 +132,7 @@ void LiquidCrystal_I2C::display() {
|
||||
|
||||
// Turn the (optional) backlight off/on
|
||||
void LiquidCrystal_I2C::noBacklight(void) {
|
||||
_backlightval = LCD_NOBACKLIGHT;
|
||||
_backlightval &= ~LCD_BACKLIGHT;
|
||||
expanderWrite(0);
|
||||
}
|
||||
|
||||
@@ -147,7 +141,7 @@ void LiquidCrystal_I2C::backlight(void) {
|
||||
expanderWrite(0);
|
||||
}
|
||||
|
||||
size_t LiquidCrystal_I2C::write(uint8_t value) {
|
||||
size_t LiquidCrystal_I2C::writeNative(uint8_t value) {
|
||||
send(value, Rs);
|
||||
return 1;
|
||||
}
|
||||
@@ -194,25 +188,32 @@ inline void LiquidCrystal_I2C::command(uint8_t value) {
|
||||
// a single I2C transmission.
|
||||
void LiquidCrystal_I2C::send(uint8_t value, uint8_t mode) {
|
||||
mode |= _backlightval;
|
||||
uint8_t highnib = (value & 0xf0) | mode;
|
||||
uint8_t lownib = ((value << 4) & 0xf0) | mode;
|
||||
uint8_t highnib = (((value >> 4) & 0x0f) << BACKPACK_DATA_BITS) | mode;
|
||||
uint8_t lownib = ((value & 0x0f) << BACKPACK_DATA_BITS) | mode;
|
||||
// Send both nibbles
|
||||
byte buffer[] = {(byte)(highnib|En), highnib, (byte)(lownib|En), lownib};
|
||||
I2CManager.write(_Addr, buffer, sizeof(buffer));
|
||||
uint8_t len = 0;
|
||||
outputBuffer[len++] = highnib|En;
|
||||
outputBuffer[len++] = highnib;
|
||||
outputBuffer[len++] = lownib|En;
|
||||
outputBuffer[len++] = lownib;
|
||||
I2CManager.write(_Addr, outputBuffer, len);
|
||||
}
|
||||
|
||||
// write 4 bits to the HD44780 LCD controller.
|
||||
// write 4 data bits to the HD44780 LCD controller.
|
||||
void LiquidCrystal_I2C::write4bits(uint8_t value) {
|
||||
uint8_t _data = value | _backlightval;
|
||||
uint8_t _data = ((value & 0x0f) << BACKPACK_DATA_BITS) | _backlightval;
|
||||
// Enable must be set/reset for at least 450ns. This is well within the
|
||||
// I2C clock cycle time of 2.5us at 400kHz. Data is clocked in to the
|
||||
// HD44780 on the trailing edge of the Enable pin.
|
||||
byte buffer[] = {(byte)(_data|En), _data};
|
||||
I2CManager.write(_Addr, buffer, sizeof(buffer));
|
||||
uint8_t len = 0;
|
||||
outputBuffer[len++] = _data|En;
|
||||
outputBuffer[len++] = _data;
|
||||
I2CManager.write(_Addr, outputBuffer, len);
|
||||
}
|
||||
|
||||
// write a byte to the PCF8574 I2C interface. We don't need to set
|
||||
// the enable pin for this.
|
||||
void LiquidCrystal_I2C::expanderWrite(uint8_t value) {
|
||||
I2CManager.write(_Addr, 1, value | _backlightval);
|
||||
outputBuffer[0] = value | _backlightval;
|
||||
I2CManager.write(_Addr, outputBuffer, 1);
|
||||
}
|
@@ -22,13 +22,13 @@
|
||||
#define LiquidCrystal_I2C_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "LCDDisplay.h"
|
||||
#include "I2CManager.h"
|
||||
|
||||
// commands
|
||||
#define LCD_CLEARDISPLAY 0x01
|
||||
#define LCD_RETURNHOME 0x02
|
||||
#define LCD_ENTRYMODESET 0x04
|
||||
#define LCD_DISPLAYCONTROL 0x08
|
||||
#define LCD_CURSORSHIFT 0x10
|
||||
#define LCD_FUNCTIONSET 0x20
|
||||
#define LCD_SETCGRAMADDR 0x40
|
||||
#define LCD_SETDDRAMADDR 0x80
|
||||
@@ -41,46 +41,39 @@
|
||||
|
||||
// flags for display on/off control
|
||||
#define LCD_DISPLAYON 0x04
|
||||
#define LCD_DISPLAYOFF 0x00
|
||||
#define LCD_CURSORON 0x02
|
||||
#define LCD_CURSOROFF 0x00
|
||||
#define LCD_BLINKON 0x01
|
||||
#define LCD_BLINKOFF 0x00
|
||||
|
||||
// flags for display/cursor shift
|
||||
#define LCD_DISPLAYMOVE 0x08
|
||||
#define LCD_CURSORMOVE 0x00
|
||||
#define LCD_MOVERIGHT 0x04
|
||||
#define LCD_MOVELEFT 0x00
|
||||
|
||||
// flags for function set
|
||||
#define LCD_8BITMODE 0x10
|
||||
#define LCD_4BITMODE 0x00
|
||||
#define LCD_2LINE 0x08
|
||||
#define LCD_1LINE 0x00
|
||||
#define LCD_5x10DOTS 0x04
|
||||
#define LCD_5x8DOTS 0x00
|
||||
|
||||
// flags for backlight control
|
||||
#define LCD_BACKLIGHT 0x08
|
||||
#define LCD_NOBACKLIGHT 0x00
|
||||
// Bit mapping onto PCF8574 port
|
||||
#define BACKPACK_Rs_BIT 0
|
||||
#define BACKPACK_Rw_BIT 1
|
||||
#define BACKPACK_En_BIT 2
|
||||
#define BACKPACK_BACKLIGHT_BIT 3
|
||||
#define BACKPACK_DATA_BITS 4 // Bits 4-7
|
||||
// Equivalent mask bits
|
||||
#define LCD_BACKLIGHT (1 << BACKPACK_BACKLIGHT_BIT) // Backlight enable
|
||||
#define En (1 << BACKPACK_En_BIT) // Enable bit
|
||||
#define Rw (1 << BACKPACK_Rw_BIT) // Read/Write bit
|
||||
#define Rs (1 << BACKPACK_Rs_BIT) // Register select bit
|
||||
|
||||
#define En 0b00000100 // Enable bit
|
||||
#define Rw 0b00000010 // Read/Write bit
|
||||
#define Rs 0b00000001 // Register select bit
|
||||
|
||||
class LiquidCrystal_I2C : public Print {
|
||||
class LiquidCrystal_I2C : public LCDDisplay {
|
||||
public:
|
||||
LiquidCrystal_I2C(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows);
|
||||
void begin(uint8_t cols, uint8_t rows);
|
||||
void clear();
|
||||
void noDisplay();
|
||||
void begin();
|
||||
void clearNative();
|
||||
void setRowNative(byte line);
|
||||
size_t writeNative(uint8_t c);
|
||||
|
||||
void display();
|
||||
void noBacklight();
|
||||
void backlight();
|
||||
|
||||
void setCursor(uint8_t, uint8_t);
|
||||
virtual size_t write(uint8_t);
|
||||
void command(uint8_t);
|
||||
void init();
|
||||
|
||||
@@ -93,10 +86,9 @@ private:
|
||||
uint8_t _displayfunction;
|
||||
uint8_t _displaycontrol;
|
||||
uint8_t _displaymode;
|
||||
uint8_t _numlines;
|
||||
uint8_t _cols;
|
||||
uint8_t _rows;
|
||||
uint8_t _backlightval;
|
||||
|
||||
uint8_t outputBuffer[4];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -1,3 +1,24 @@
|
||||
/*
|
||||
* (c) 2020 Chris Harlow. All rights reserved.
|
||||
* (c) 2021 Fred Decker. All rights reserved.
|
||||
* (c) 2020 Harald Barth. All rights reserved.
|
||||
* (c) 2020 Anthony W - Dayton. All rights reserved.
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* It is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef MotorDrivers_h
|
||||
#define MotorDrivers_h
|
||||
#include <Arduino.h>
|
||||
@@ -61,5 +82,9 @@
|
||||
#define IBT_2_WITH_ARDUINO F("IBT_2_WITH_ARDUINO_SHIELD"), \
|
||||
new MotorDriver(4, 5, 6, UNUSED_PIN, A5, 41.54, 5000, UNUSED_PIN), \
|
||||
new MotorDriver(11, 13, UNUSED_PIN, UNUSED_PIN, A1, 2.99, 2000, UNUSED_PIN)
|
||||
// YFROBOT Motor Shield (V3.1)
|
||||
#define YFROBOT_MOTOR_SHIELD F("YFROBOT_MOTOR_SHIELD"), \
|
||||
new MotorDriver(5, 4, UNUSED_PIN, UNUSED_PIN, A0, 2.99, 2000, UNUSED_PIN), \
|
||||
new MotorDriver(6, 7, UNUSED_PIN, UNUSED_PIN, A1, 2.99, 2000, UNUSED_PIN)
|
||||
|
||||
#endif
|
||||
|
53
Outputs.cpp
53
Outputs.cpp
@@ -100,14 +100,14 @@ void Output::activate(int s){
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Output* Output::get(int n){
|
||||
Output* Output::get(uint16_t n){
|
||||
Output *tt;
|
||||
for(tt=firstOutput;tt!=NULL && tt->data.id!=n;tt=tt->nextOutput);
|
||||
return(tt);
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Output::remove(int n){
|
||||
bool Output::remove(uint16_t n){
|
||||
Output *tt,*pp=NULL;
|
||||
|
||||
for(tt=firstOutput;tt!=NULL && tt->data.id!=n;pp=tt,tt=tt->nextOutput);
|
||||
@@ -127,17 +127,46 @@ bool Output::remove(int n){
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Output::load(){
|
||||
struct OutputData data;
|
||||
struct BrokenOutputData bdata;
|
||||
Output *tt;
|
||||
bool isBroken=1;
|
||||
|
||||
for(int i=0;i<EEStore::eeStore->data.nOutputs;i++){
|
||||
EEPROM.get(EEStore::pointer(),data);
|
||||
tt=create(data.id,data.pin,data.iFlag);
|
||||
tt->data.oStatus=bitRead(tt->data.iFlag,1)?bitRead(tt->data.iFlag,2):data.oStatus; // restore status to EEPROM value is bit 1 of iFlag=0, otherwise set to value of bit 2 of iFlag
|
||||
digitalWrite(tt->data.pin,tt->data.oStatus ^ bitRead(tt->data.iFlag,0));
|
||||
pinMode(tt->data.pin,OUTPUT);
|
||||
tt->num=EEStore::pointer();
|
||||
EEStore::advance(sizeof(tt->data));
|
||||
// This is a scary kluge. As we have two formats in EEPROM due to an
|
||||
// earlier bug, we don't know which we encounter now. So we guess
|
||||
// that if in all entries this byte has value of 7 or lower this is
|
||||
// an iFlag and thus the broken format. Otherwise it would be a pin
|
||||
// id. If someone uses only pins 0 to 7 of their arduino, they
|
||||
// loose. This is (if you look at an arduino) however unlikely.
|
||||
|
||||
for(uint16_t i=0;i<EEStore::eeStore->data.nOutputs;i++){
|
||||
EEPROM.get(EEStore::pointer()+ i*sizeof(struct BrokenOutputData),bdata);
|
||||
if (bdata.iFlag > 7) { // it's a pin and not an iFlag!
|
||||
isBroken=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( isBroken ) {
|
||||
for(uint16_t i=0;i<EEStore::eeStore->data.nOutputs;i++){
|
||||
EEPROM.get(EEStore::pointer(),bdata);
|
||||
tt=create(bdata.id,bdata.pin,bdata.iFlag);
|
||||
tt->data.oStatus=bitRead(tt->data.iFlag,1)?bitRead(tt->data.iFlag,2):bdata.oStatus; // restore status to EEPROM value is bit 1 of iFlag=0, otherwise set to value of bit 2 of iFlag
|
||||
digitalWrite(tt->data.pin,tt->data.oStatus ^ bitRead(tt->data.iFlag,0));
|
||||
pinMode(tt->data.pin,OUTPUT);
|
||||
tt->num=EEStore::pointer();
|
||||
EEStore::advance(sizeof(struct BrokenOutputData));
|
||||
}
|
||||
} else {
|
||||
struct OutputData data;
|
||||
|
||||
for(uint16_t i=0;i<EEStore::eeStore->data.nOutputs;i++){
|
||||
EEPROM.get(EEStore::pointer(),data);
|
||||
tt=create(data.id,data.pin,data.iFlag);
|
||||
tt->data.oStatus=bitRead(tt->data.iFlag,1)?bitRead(tt->data.iFlag,2):data.oStatus; // restore status to EEPROM value is bit 1 of iFlag=0, otherwise set to value of bit 2 of iFlag
|
||||
digitalWrite(tt->data.pin,tt->data.oStatus ^ bitRead(tt->data.iFlag,0));
|
||||
pinMode(tt->data.pin,OUTPUT);
|
||||
tt->num=EEStore::pointer();
|
||||
EEStore::advance(sizeof(struct OutputData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +189,7 @@ void Output::store(){
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Output *Output::create(int id, int pin, int iFlag, int v){
|
||||
Output *Output::create(uint16_t id, uint8_t pin, uint8_t iFlag, uint8_t v){
|
||||
Output *tt;
|
||||
|
||||
if(firstOutput==NULL){
|
||||
|
23
Outputs.h
23
Outputs.h
@@ -23,25 +23,34 @@
|
||||
|
||||
struct OutputData {
|
||||
uint8_t oStatus;
|
||||
uint8_t id;
|
||||
uint16_t id;
|
||||
uint8_t pin;
|
||||
uint8_t iFlag;
|
||||
};
|
||||
|
||||
struct BrokenOutputData {
|
||||
uint8_t oStatus;
|
||||
uint8_t id;
|
||||
uint8_t pin;
|
||||
uint8_t iFlag;
|
||||
};
|
||||
|
||||
class Output{
|
||||
public:
|
||||
|
||||
public:
|
||||
void activate(int s);
|
||||
static Output* get(int);
|
||||
static bool remove(int);
|
||||
static Output* get(uint16_t);
|
||||
static bool remove(uint16_t);
|
||||
static void load();
|
||||
static void store();
|
||||
static Output *create(int, int, int, int=0);
|
||||
static Output *create(uint16_t, uint8_t, uint8_t, uint8_t=0);
|
||||
static Output *firstOutput;
|
||||
struct OutputData data;
|
||||
Output *nextOutput;
|
||||
static void printAll(Print *);
|
||||
private:
|
||||
int num; // Chris has no idea what this is all about!
|
||||
|
||||
private:
|
||||
int num; // EEPROM pointer (Chris has no idea what this is all about!)
|
||||
|
||||
}; // Output
|
||||
|
||||
|
@@ -1,5 +1,21 @@
|
||||
|
||||
|
||||
/*
|
||||
* (c) 2020 Chris Harlow. All rights reserved.
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* It is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*!
|
||||
* @file PWMServoDriver.cpp
|
||||
*
|
||||
@@ -16,11 +32,7 @@
|
||||
*
|
||||
* @section author Author
|
||||
* Chris Harlow (TPL)
|
||||
* original by Limor Fried/Ladyada (Adafruit Industries).
|
||||
*
|
||||
* @section license License
|
||||
*
|
||||
* BSD license, all text above must be included in any redistribution
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include "PWMServoDriver.h"
|
||||
|
@@ -1,3 +1,21 @@
|
||||
/*
|
||||
* (c) 2020 Chris Harlow. All rights reserved.
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* It is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*!
|
||||
* @file PWMServoDriver.h
|
||||
*
|
||||
|
27
README.md
27
README.md
@@ -12,11 +12,13 @@ Both CommandStation-EX and BaseStation-Classic support much of the NMRA Digital
|
||||
|
||||
* simultaneous control of multiple locomotives
|
||||
* 2-byte and 4-byte locomotive addressing
|
||||
* 128-step speed throttling
|
||||
* 28 or 128-step speed throttling
|
||||
* Activate/de-activate all accessory function addresses 0-2048
|
||||
* Control of all cab functions F0-F28
|
||||
* Control of all cab functions F0-F28 and F29-F68
|
||||
* Main Track: Write configuration variable bytes and set/clear specific configuration variable (CV) bits (aka Programming on Main or POM)
|
||||
* Programming Track: Same as the main track with the addition of reading configuration variable bytes
|
||||
* And manu more custom features. see [What's new in CommandStation-EX?](#whats-new-in-commandstation-ex)
|
||||
|
||||
|
||||
# What’s in this Repository?
|
||||
|
||||
@@ -38,11 +40,11 @@ in config.h.
|
||||
|
||||
## What's new in CommandStation-EX?
|
||||
|
||||
* WiThrottle server built in. Connect Engine Driver or WiThrottle clients directly to your Command Station
|
||||
* WiThrottle server built in. Connect Engine Driver or WiThrottle clients directly to your Command Station (or through JMRI as before)
|
||||
* WiFi and Ethernet shield support
|
||||
* No more jumpers or soldering!
|
||||
* Direct support for all the most popular motor control boards
|
||||
* I2C Display support
|
||||
* Direct support for all the most popular motor control boards including single pin (Arduino) or dual pin (IBT_2) type PWM inputs without the need for an adapter circuit
|
||||
* I2C Display support (LCD and OLED)
|
||||
* Improved short circuit detection and automatic reset from an overload
|
||||
* Current reading, sensing and ACK detection settings in milliAmps instead of just pin readings
|
||||
* Improved adherence to the NMRA DCC specification
|
||||
@@ -50,6 +52,21 @@ in config.h.
|
||||
* Railcom cutout (beta)
|
||||
* Simpler, modular, faster code with an API Library for developers for easy expansion
|
||||
* New features and functions in JMRI
|
||||
* Ability to join MAIN and PROG tracks into one MAIN track to run your locos
|
||||
* "Drive-Away" feature - Throttles with support, like Engine Driver, can allow a loco to be programmed on a usable, electrically isolated programming track and then drive off onto the main track
|
||||
* Diagnostic commands to test decoders that aren't reading or writing correctly
|
||||
* Support for Uno, Nano, Mega, Nano Every and Teensy microcontrollers
|
||||
* User Functions: Filter regular commands (like a turnout or output command) and pass it to your own function or accessory
|
||||
* Support for LCN (layout control nodes)
|
||||
* mySetup.h file that acts like an Autoexec.Bat command to send startup commands to the CS
|
||||
* High Accuracty Waveform option for rock steady DCC signals
|
||||
* New current response outputs current in mA, overlimit current, and maximum board capable current. Support for new current meter in JMRI
|
||||
* USB Browser based EX-WebThrottle
|
||||
* New, simpler, function control command
|
||||
* Number of locos discovery command `<#>`
|
||||
* Emergency stop command <!>
|
||||
* Release cabs from memory command <-> all cabs, <- CAB> for just one loco address
|
||||
* Automatic slot (register) management
|
||||
* Automation (coming soon)
|
||||
|
||||
NOTE: DCC-EX is a major rewrite to the code. We started over and rebuilt it from the ground up! For what that means to you, click [HERE](notes/rewrite.md).
|
||||
|
85
Release_Notes/release_notes_v3.0.0.md
Normal file
85
Release_Notes/release_notes_v3.0.0.md
Normal file
@@ -0,0 +1,85 @@
|
||||
|
||||
|
||||
The DCC-EX Team is pleased to release CommandStation-EX-v3.0.0 as a Production Release. This release is a major re-write of earlier versions. We've re-architected the code-base so that it can better handle new features going forward. Download the compressed files here:
|
||||
|
||||
**Downloads (zip and tar.gz) below. These are named without version number in the folder name to make the Arduino IDE happy.**
|
||||
|
||||
[CommandStation-EX.zip](https://github.com/DCC-EX/CommandStation-EX/files/5611333/CommandStation-EX.zip)
|
||||
[CommandStation-EX.tar.gz](https://github.com/DCC-EX/CommandStation-EX/files/5611335/CommandStation-EX.tar.gz)
|
||||
|
||||
|
||||
**Known Bugs:**
|
||||
- **Consisting through JMRI** - currently does not work in this release. A number of testers were able to develop a work around. If interested enter a Support Ticket.
|
||||
- **Wi-Fi** - works, but can be challenging to use if you want to switch between AP mode and STA station mode.
|
||||
- **Pololu Motor Shield** - is supported with this release, but the user may have to play around with some timings to enable programming mode due to limitation in its current sensing circuitry
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.0:**
|
||||
- **WiFi Support** - AP and station modes supported. Auto-detection of an ESP8266 WiFi module with AT firmware on a Mega's serial port. Connection to JMRI and WiThrottle clients.
|
||||
- **Withrottle Integrations** - Act as a host for four WiThrottle clients concurrently.
|
||||
- **Add LCD/OLED support** - OLED supported on Mega only
|
||||
- **Improved CV programming routines** - checks for length of CV pulse, and breaks out of the wait state once it has received an ACK, now reading one CV per second.
|
||||
- **Improved current sensing** - rewrote current sensing routines for safer operation. Current thresholds based on milliamps, not magic numbers
|
||||
- **Individual track power control** - Ability to toggle power on either or both tracks, and to "JOIN" the tracks and make them output the same waveform for multiple power districts.
|
||||
- **Single or Dual-Pin PWM output** - Allows control of H-bridges with PH/EN or dual PWM inputs
|
||||
- **New, simpler function command** - ```<F>``` command allows setting functions based on their number, not based on a code as in ```<f>```
|
||||
- **Function reminders** - Function reminders are sent in addition to speed reminders
|
||||
- **Functions to F28** - All NMRA functions are now supported
|
||||
- **Filters and user functions** - Ability to filter commands in the parser and execute custom code based on them
|
||||
- **Diagnostic ```<D>``` commands** - See documentation for a full list of new diagnostic commands
|
||||
- **Rewrote DCC++ Parser** - more efficient operation, accepts multi-char input and uses less RAM
|
||||
- **Rewritten waveform generator** - capable of using any pin for DCC waveform out, eliminating the need for jumpers
|
||||
- **Rewritten packet generator** - Simplify and make smaller, remove idea of "registers" from original code
|
||||
- **Add free RAM messages** - Free RAM messages are now printed whenever there is a decerase in available RAM
|
||||
- **Fix EEPROM bugs**
|
||||
- **Number of locos discovery command** - ```<#>``` command
|
||||
- **Support for more locomotives** - 20 locomotives on an UNO and 50 an a Mega.
|
||||
- **Automatic slot managment** - slot variable in throttle/function commands are ignored and slot management is taken care of automatically. ```<!>``` command added to release locos from memory.
|
||||
|
||||
|
||||
**Key Contributors**
|
||||
|
||||
**Project Lead**
|
||||
- Fred Decker - Holly Springs, North Carolina, USA (FlightRisk)
|
||||
|
||||
**CommandStation-EX Developers**
|
||||
- Chris Harlow - Bournemouth, UK (UKBloke)
|
||||
- Harald Barth - Stockholm, Sweden (Haba)
|
||||
- Fred Decker - Holly Springs, North Carolina, USA (FlightRisk)
|
||||
- Dave Cutting - Logan, Utah, USA (Dave Cutting/ David Cutting)
|
||||
- M Steve Todd - - Engine Driver and JMRI Interface
|
||||
- Scott Catalanno - Pennsylvania
|
||||
- Gregor Baues - Île-de-France, France (grbba)
|
||||
|
||||
**exInstaller Software**
|
||||
- Anthony W - Dayton, Ohio, USA (Dex, Dex++)
|
||||
|
||||
**Website and Documentation**
|
||||
- Mani Kumar - Bangalor, India (Mani / Mani Kumar)
|
||||
- Fred Decker - Holly Springs, North Carolina, USA (FlightRisk)
|
||||
- Dave Cutting - Logan, Utah, USA (Dave Cutting/ David Cutting)
|
||||
- Roger Beschizza - Dorset, UK (Roger Beschizza)
|
||||
- Keith Ledbetter - Chicago, Illinois, USA (Keith Ledbetter)
|
||||
-Kevin Smith - (KCSmith)
|
||||
|
||||
**Beta Testing / Release Management / Support**
|
||||
- Larry Dribin - Release Management
|
||||
- Keith Ledbetter
|
||||
- BradVan der Elst
|
||||
- Andrew Pye
|
||||
- Mike Bowers
|
||||
- Randy McKenzie
|
||||
- Roberto Bravin
|
||||
- Sim Brigden
|
||||
- Alan Lautenslager
|
||||
- Martin Bafver
|
||||
- Mário André Silva
|
||||
- Anthony Kochevar
|
||||
- Gajanatha Kobbekaduwe
|
||||
- Sumner Patterson
|
||||
- Paul - Virginia, USA
|
||||
|
||||
**Downloads (zip and tar.gz) below. These are named without version number in the folder name to make the Arduino IDE happy.**
|
||||
|
||||
[CommandStation-EX.zip](https://github.com/DCC-EX/CommandStation-EX/files/5611333/CommandStation-EX.zip)
|
||||
[CommandStation-EX.tar.gz](https://github.com/DCC-EX/CommandStation-EX/files/5611335/CommandStation-EX.tar.gz)
|
||||
|
206
Release_Notes/release_notes_v3.1.0.md
Normal file
206
Release_Notes/release_notes_v3.1.0.md
Normal file
@@ -0,0 +1,206 @@
|
||||
The DCC-EX Team is pleased to release CommandStation-EX-v3.1.0 as a Production Release. Release v3.1.0 is a minor release that adds additional features and fixes a number of bugs. With the number of new features, this could have easily been a major release. The team is continually improving the architecture of DCC++EX to make it more flexible and optimizing the code so as to get more performance from the Arduino (and other) microprocessors. This release includes all of the Point Releases from v3.0.1 to v3.0.16.
|
||||
|
||||
**Downloads (zip and tar.gz) below. These are named without version number in the folder name to make the Arduino IDE happy.**
|
||||
|
||||
[CommandStation-EX.zip](https://github.com/DCC-EX/CommandStation-EX/releases/download/v3.1.0-Prod/CommandStation-EX.zip)
|
||||
[CommandStation-EX.tar.gz](https://github.com/DCC-EX/CommandStation-EX/releases/download/v3.1.0-Prod/CommandStation-EX.tar.gz)
|
||||
|
||||
**Known Issues**
|
||||
|
||||
- **Wi-Fi** - works, but requires sending <AT> commands from a serial monitor if you want to switch between AP mode and STA station mode after initial setup
|
||||
- **Pololu Motor Shield** - is supported with this release, but the user may have to adjust timings to enable programming mode due to limitation in its current sensing circuitry
|
||||
|
||||
#### Summary of key features and/or bug fixes by Point Release
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.16**
|
||||
|
||||
- Ignore CV1 bit 7 read if rejected by a non NMRA compliant decoder when identifying loco id
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.15**
|
||||
|
||||
- Send function commands just once instead of repeating them 4 times
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.14**
|
||||
|
||||
- Add feature to tolerate decoders that incorrectly have gaps in their ACK pulse
|
||||
- Provide proper track power management when joining and unjoining tracks with <1 JOIN>
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.13**
|
||||
|
||||
- Fix for CAB Functions greater than 127
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.12**
|
||||
|
||||
- Fixed clear screen issue for nanoEvery and nanoWifi
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.11**
|
||||
|
||||
- Reorganized files for support of 128 speed steps
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.10**
|
||||
|
||||
- Added Support for the Teensy 3.2, 3.5, 3.6, 4.0 and 4.1 MCUs
|
||||
- No functional change just changes to avoid complier warnings for Teensy/nanoEvery
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.9**
|
||||
|
||||
- Rearranges serial newlines for the benefit of JMRI
|
||||
- Major update for efficiencies in displays (LCD, OLED)
|
||||
- Add I2C Support functions
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.8**
|
||||
|
||||
- Wraps <* *> around DIAGS for the benefit of JMRI
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.7**
|
||||
|
||||
- Implemented support for older 28 apeed step decoders - Option to turn on 28 step speed decoders in addition to 128. If set, all locos will use 28 steps.
|
||||
- Improved overload messages with raw values (relative to offset)
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.6**
|
||||
|
||||
- Prevent compiler warning about deprecated B constants
|
||||
- Fix Bug that did not let us transmit 5 byte sized packets - 5 Byte commands like PoM (programming on main) were not being sent correctly
|
||||
- Support for Huge function numbers (DCC BinaryStateControl) - Support Functions beyond F28
|
||||
- <!> ESTOP all - New command to emergency stop all locos on the main track
|
||||
- <- [cab]> estop and forget cab/all cabs - Stop and remove loco from the CS. Stops the repeating throttle messages
|
||||
- `<D RESET>` command to reboot Arduino
|
||||
- Automatic sensor offset detect
|
||||
- Improved startup msgs from Motor Drivers (accuracy and auto sense factors)
|
||||
- Drop post-write verify - No need to double check CV writes. Writes are now even faster.
|
||||
- Allow current sense pin set to UNUSED_PIN - No need to ground an unused analog current pin. Produce startup warning and callback -2 for prog track cmds.
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.5**
|
||||
|
||||
- Fix Fn Key startup with loco ID and fix state change for F16-28
|
||||
- Removed ethernet mac config and made it automatic
|
||||
- Show wifi ip and port on lcd
|
||||
- Auto load config.example.h with warning
|
||||
- Dropped example .ino files
|
||||
- Corrected .ino comments
|
||||
- Add Pololu fault pin handling
|
||||
- Waveform speed/simplicity improvements
|
||||
- Improved pin speed in waveform
|
||||
- Portability to nanoEvery and UnoWifiRev2 CPUs
|
||||
- Analog read speed improvements
|
||||
- Drop need for DIO2 library
|
||||
- Improved current check code
|
||||
- Linear command
|
||||
- Removed need for ArduinoTimers files
|
||||
- Removed option to choose different timer
|
||||
- Added EX-RAIL hooks for automation in future version
|
||||
- Fixed Turnout list
|
||||
- Allow command keywords in mixed case
|
||||
- Dropped unused memstream
|
||||
- PWM pin accuracy if requirements met
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.4**
|
||||
|
||||
- "Drive-Away" Feature - added so that throttles like Engine Driver can allow a loco to be programmed on a usable, electrically isolated programming track and then drive off onto the main track
|
||||
- WiFi Startup Fixes
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.3**
|
||||
|
||||
- Command to write loco address and clear consist
|
||||
- Command will allow for consist address
|
||||
- Startup commands implemented
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.2:**
|
||||
|
||||
- Create new output for current in mA for `<c>` command - New current response outputs current in mA, overlimit current, and maximum board capable current
|
||||
- Simultaneously update JMRI to handle new current meter
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.1:**
|
||||
|
||||
- Add back fix for jitter
|
||||
- Add Turnouts, Outputs and Sensors to `<s>` command output
|
||||
|
||||
**CommandStation-EX V3.0.0:**
|
||||
|
||||
**Release v3.0.0 was a major rewrite if earlier versions of DCC++. The code base was re-architeced and core changes were made to the Waveform generator to reduce overhead and make better use of Arduino.** **Summary of the key new features added in Release v3.0.0 include:**
|
||||
|
||||
- **New USB Browser Based Throttle** - WebThrottle-EX is a full front-end to controller to control the CS to run trains.
|
||||
- **WiFi Support** - AP and station modes supported. Auto-detection of an ESP8266 WiFi module with AT firmware on a Mega's serial port. Connection to JMRI and WiThrottle clients.
|
||||
- **Withrottle Integrations** - Act as a host for up to four WiThrottle clients concurrently.
|
||||
- **Add LCD/OLED support** - OLED supported on Mega only
|
||||
- **Improved CV programming routines** - checks for length of CV pulse, and breaks out of the wait state once it has received an ACK, now reading one CV per second.
|
||||
- **Improved current sensing** - rewrote current sensing routines for safer operation. Current thresholds based on milliamps, not magic numbers
|
||||
- **Individual track power control** - Ability to toggle power on either or both tracks, and to "JOIN" the tracks and make them output the same waveform for multiple power districts.
|
||||
- **Single or Dual-Pin PWM output** - Allows control of H-bridges with PH/EN or dual PWM inputs
|
||||
- **New, simpler function command** - `<F>` command allows setting functions based on their number, not based on a code as in `<f>`
|
||||
- **Function reminders** - Function reminders are sent in addition to speed reminders
|
||||
- **Functions to F28** - All NMRA functions are now supported
|
||||
- **Filters and user functions** - Ability to filter commands in the parser and execute custom code based on them. (ex: Redirect Turnout commands via NRF24)
|
||||
- **Diagnostic `<D>` commands** - See documentation for a full list of new diagnostic commands
|
||||
- **Rewrote DCC++ Parser** - more efficient operation, accepts multi-char input and uses less RAM
|
||||
- **Rewritten waveform generator** - capable of using any pin for DCC waveform out, eliminating the need for jumpers
|
||||
- **Rewritten packet generator** - Simplify and make smaller, remove idea of "registers" from original code
|
||||
- **Add free RAM messages** - Free RAM messages are now printed whenever there is a decerase in available RAM
|
||||
- **Fix EEPROM bugs**
|
||||
- **Number of locos discovery command** - `<#>` command
|
||||
- **Support for more locomotives** - 20 locomotives on an UNO and 50 an a Mega.
|
||||
- **Automatic slot management** - slot variable in throttle/function commands are ignored and slot management is taken care of automatically. `<->` and `<- CAB>` commands added to release locos from memory and stop packets to the track.
|
||||
|
||||
**Key Contributors**
|
||||
|
||||
**Project Lead**
|
||||
|
||||
- Fred Decker - Holly Springs, North Carolina, USA (FlightRisk)
|
||||
|
||||
**CommandStation-EX Developers**
|
||||
|
||||
- Chris Harlow - Bournemouth, UK (UKBloke)
|
||||
- Harald Barth - Stockholm, Sweden (Haba)
|
||||
- Neil McKechnie - Worcestershire, UK (NeilMck)
|
||||
- Fred Decker - Holly Springs, North Carolina, USA (FlightRisk)
|
||||
- Dave Cutting - Logan, Utah, USA (Dave Cutting/ David Cutting)
|
||||
- M Steve Todd -
|
||||
- Scott Catalano - Pennsylvania
|
||||
- Gregor Baues - Île-de-France, France (grbba)
|
||||
|
||||
**Engine Driver and JMRI Interface**
|
||||
|
||||
- M Steve Todd
|
||||
|
||||
**exInstaller Software**
|
||||
|
||||
- Anthony W - Dayton, Ohio, USA (Dex, Dex++)
|
||||
|
||||
**Website and Documentation**
|
||||
|
||||
- Mani Kumar - Bangalor, India (Mani / Mani Kumar)
|
||||
- Fred Decker - Holly Springs, North Carolina, USA (FlightRisk)
|
||||
- Dave Cutting - Logan, Utah, USA (Dave Cutting/ David Cutting)
|
||||
- Roger Beschizza - Dorset, UK (Roger Beschizza)
|
||||
- Keith Ledbetter - Chicago, Illinois, USA (Keith Ledbetter)
|
||||
- Kevin Smith - Rochester Hills, Michigan USA (KC Smith)
|
||||
|
||||
**WebThrotle-EX**
|
||||
|
||||
- Fred Decker - Holly Springs, NC (FlightRisk/FrightRisk)
|
||||
- Mani Kumar - Bangalor, India (Mani /Mani Kumar)
|
||||
- Matt H - Somewhere in Europe
|
||||
|
||||
**Beta Testing / Release Management / Support**
|
||||
|
||||
- Larry Dribin - Release Management
|
||||
- Kevin Smith - Rochester Hills, Michigan USA (KC Smith)
|
||||
- Keith Ledbetter
|
||||
- BradVan der Elst
|
||||
- Andrew Pye
|
||||
- Mike Bowers
|
||||
- Randy McKenzie
|
||||
- Roberto Bravin
|
||||
- Sim Brigden
|
||||
- Alan Lautenslager
|
||||
- Martin Bafver
|
||||
- Mário André Silva
|
||||
- Anthony Kochevar
|
||||
- Gajanatha Kobbekaduwe
|
||||
- Sumner Patterson
|
||||
- Paul - Virginia, USA
|
||||
|
||||
**Downloads (zip and tar.gz) below. These are named without version number in the folder name to make the Arduino IDE happy.**
|
||||
|
||||
[CommandStation-EX.zip](https://github.com/DCC-EX/CommandStation-EX/releases/download/v3.1.0-Prod/CommandStation-EX.zip)
|
||||
[CommandStation-EX.tar.gz](https://github.com/DCC-EX/CommandStation-EX/releases/download/v3.1.0-Prod/CommandStation-EX.tar.gz)
|
391
SSD1306Ascii.cpp
391
SSD1306Ascii.cpp
@@ -1,6 +1,8 @@
|
||||
/* Based on Arduino SSD1306Ascii Library, Copyright (C) 2015 by William Greiman
|
||||
* Modifications (C) 2021 Neil McKechnie
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@@ -19,90 +21,375 @@
|
||||
#include "I2CManager.h"
|
||||
#include "FSH.h"
|
||||
|
||||
//==============================================================================
|
||||
// SSD1306/SSD1106 I2C command bytes
|
||||
//------------------------------------------------------------------------------
|
||||
/** Set Lower Column Start Address for Page Addressing Mode. */
|
||||
static const uint8_t SSD1306_SETLOWCOLUMN = 0x00;
|
||||
/** Set Higher Column Start Address for Page Addressing Mode. */
|
||||
static const uint8_t SSD1306_SETHIGHCOLUMN = 0x10;
|
||||
/** Set Memory Addressing Mode. */
|
||||
static const uint8_t SSD1306_MEMORYMODE = 0x20;
|
||||
/** Set display RAM display start line register from 0 - 63. */
|
||||
static const uint8_t SSD1306_SETSTARTLINE = 0x40;
|
||||
/** Set Display Contrast to one of 256 steps. */
|
||||
static const uint8_t SSD1306_SETCONTRAST = 0x81;
|
||||
/** Enable or disable charge pump. Follow with 0X14 enable, 0X10 disable. */
|
||||
static const uint8_t SSD1306_CHARGEPUMP = 0x8D;
|
||||
/** Set Segment Re-map between data column and the segment driver. */
|
||||
static const uint8_t SSD1306_SEGREMAP = 0xA0;
|
||||
/** Resume display from GRAM content. */
|
||||
static const uint8_t SSD1306_DISPLAYALLON_RESUME = 0xA4;
|
||||
/** Force display on regardless of GRAM content. */
|
||||
static const uint8_t SSD1306_DISPLAYALLON = 0xA5;
|
||||
/** Set Normal Display. */
|
||||
static const uint8_t SSD1306_NORMALDISPLAY = 0xA6;
|
||||
/** Set Inverse Display. */
|
||||
static const uint8_t SSD1306_INVERTDISPLAY = 0xA7;
|
||||
/** Set Multiplex Ratio from 16 to 63. */
|
||||
static const uint8_t SSD1306_SETMULTIPLEX = 0xA8;
|
||||
/** Set Display off. */
|
||||
static const uint8_t SSD1306_DISPLAYOFF = 0xAE;
|
||||
/** Set Display on. */
|
||||
static const uint8_t SSD1306_DISPLAYON = 0xAF;
|
||||
/**Set GDDRAM Page Start Address. */
|
||||
static const uint8_t SSD1306_SETSTARTPAGE = 0xB0;
|
||||
/** Set COM output scan direction normal. */
|
||||
static const uint8_t SSD1306_COMSCANINC = 0xC0;
|
||||
/** Set COM output scan direction reversed. */
|
||||
static const uint8_t SSD1306_COMSCANDEC = 0xC8;
|
||||
/** Set Display Offset. */
|
||||
static const uint8_t SSD1306_SETDISPLAYOFFSET = 0xD3;
|
||||
/** Sets COM signals pin configuration to match the OLED panel layout. */
|
||||
static const uint8_t SSD1306_SETCOMPINS = 0xDA;
|
||||
/** This command adjusts the VCOMH regulator output. */
|
||||
static const uint8_t SSD1306_SETVCOMDETECT = 0xDB;
|
||||
/** Set Display Clock Divide Ratio/ Oscillator Frequency. */
|
||||
static const uint8_t SSD1306_SETDISPLAYCLOCKDIV = 0xD5;
|
||||
/** Set Pre-charge Period */
|
||||
static const uint8_t SSD1306_SETPRECHARGE = 0xD9;
|
||||
/** Deactivate scroll */
|
||||
static const uint8_t SSD1306_DEACTIVATE_SCROLL = 0x2E;
|
||||
/** No Operation Command. */
|
||||
static const uint8_t SSD1306_NOP = 0xE3;
|
||||
//------------------------------------------------------------------------------
|
||||
/** Set Pump voltage value: (30H~33H) 6.4, 7.4, 8.0 (POR), 9.0. */
|
||||
static const uint8_t SH1106_SET_PUMP_VOLTAGE = 0x30;
|
||||
/** First byte of set charge pump mode */
|
||||
static const uint8_t SH1106_SET_PUMP_MODE = 0xAD;
|
||||
/** Second byte charge pump on. */
|
||||
static const uint8_t SH1106_PUMP_ON = 0x8B;
|
||||
/** Second byte charge pump off. */
|
||||
static const uint8_t SH1106_PUMP_OFF = 0x8A;
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Maximum number of bytes we can send per transmission is 32.
|
||||
const uint8_t FLASH SSD1306AsciiWire::blankPixels[32] =
|
||||
// Sequence of blank pixels, to optimise clearing screen.
|
||||
// Send a maximum of 30 pixels per transmission.
|
||||
const uint8_t FLASH SSD1306AsciiWire::blankPixels[30] =
|
||||
{0x40, // First byte specifies data mode
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
|
||||
//==============================================================================
|
||||
// SSD1306AsciiWire Method Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
void SSD1306AsciiWire::clear() {
|
||||
clear(0, displayWidth() - 1, 0, displayRows() - 1);
|
||||
|
||||
// Constructor
|
||||
SSD1306AsciiWire::SSD1306AsciiWire(int width, int height) {
|
||||
// Set size in characters in base class
|
||||
lcdRows = height / 8;
|
||||
lcdCols = width / 6;
|
||||
|
||||
I2CManager.begin();
|
||||
I2CManager.setClock(400000L); // Set max supported I2C speed
|
||||
for (byte address = 0x3c; address <= 0x3d; address++) {
|
||||
if (I2CManager.exists(address)) {
|
||||
// Device found
|
||||
DIAG(F("%dx%d OLED display configured on I2C:x%x"), width, height, address);
|
||||
if (width == 132)
|
||||
begin(&SH1106_132x64, address);
|
||||
else if (height == 32)
|
||||
begin(&Adafruit128x32, address);
|
||||
else
|
||||
begin(&Adafruit128x64, address);
|
||||
// Set singleton address
|
||||
lcdDisplay = this;
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
DIAG(F("OLED display not found"));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void SSD1306AsciiWire::clear(uint8_t columnStart, uint8_t columnEnd,
|
||||
uint8_t rowStart, uint8_t rowEnd) {
|
||||
|
||||
/* Clear screen by writing blank pixels. */
|
||||
void SSD1306AsciiWire::clearNative() {
|
||||
const int maxBytes = sizeof(blankPixels); // max number of bytes sendable over Wire
|
||||
// Ensure only rows on display will be cleared.
|
||||
if (rowEnd >= displayRows()) rowEnd = displayRows() - 1;
|
||||
for (uint8_t r = rowStart; r <= rowEnd; r++) {
|
||||
setCursor(columnStart, r); // Position at start of row to be erased
|
||||
for (uint8_t c = columnStart; c <= columnEnd; c += maxBytes-1) {
|
||||
uint8_t len = min((uint8_t)(columnEnd-c+1), maxBytes-1) + 1;
|
||||
I2CManager.write_P(m_i2cAddr, blankPixels, len); // Write up to 31 blank columns
|
||||
for (uint8_t r = 0; r <= m_displayHeight/8 - 1; r++) {
|
||||
setRowNative(r); // Position at start of row to be erased
|
||||
for (uint8_t c = 0; c <= m_displayWidth - 1; c += maxBytes-1) {
|
||||
uint8_t len = min(m_displayWidth-c, maxBytes-1) + 1;
|
||||
I2CManager.write_P(m_i2cAddr, blankPixels, len); // Write a number of blank columns
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Initialise device
|
||||
void SSD1306AsciiWire::begin(const DevType* dev, uint8_t i2cAddr) {
|
||||
m_i2cAddr = i2cAddr;
|
||||
m_col = 0;
|
||||
m_row = 0;
|
||||
#ifdef __AVR__
|
||||
const uint8_t* table = (const uint8_t*)pgm_read_word(&dev->initcmds);
|
||||
#else // __AVR__
|
||||
const uint8_t* table = dev->initcmds;
|
||||
#endif // __AVR
|
||||
uint8_t size = readFontByte(&dev->initSize);
|
||||
m_displayWidth = readFontByte(&dev->lcdWidth);
|
||||
m_displayHeight = readFontByte(&dev->lcdHeight);
|
||||
m_colOffset = readFontByte(&dev->colOffset);
|
||||
const uint8_t* table = (const uint8_t*)GETFLASHW(&dev->initcmds);
|
||||
uint8_t size = GETFLASH(&dev->initSize);
|
||||
m_displayWidth = GETFLASH(&dev->lcdWidth);
|
||||
m_displayHeight = GETFLASH(&dev->lcdHeight);
|
||||
m_colOffset = GETFLASH(&dev->colOffset);
|
||||
I2CManager.write_P(m_i2cAddr, table, size);
|
||||
if (m_displayHeight == 32)
|
||||
I2CManager.write(m_i2cAddr, 5, 0, // Set command mode
|
||||
SSD1306_SETMULTIPLEX, 0x1F, // ratio 32
|
||||
SSD1306_SETCOMPINS, 0x02); // sequential COM pins, disable remap
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void SSD1306AsciiWire::setContrast(uint8_t value) {
|
||||
I2CManager.write(m_i2cAddr, 2,
|
||||
0x00, // Set to command mode
|
||||
SSD1306_SETCONTRAST, value);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void SSD1306AsciiWire::setCursor(uint8_t col, uint8_t row) {
|
||||
if (row < displayRows() && col < m_displayWidth) {
|
||||
|
||||
// Set cursor position (by text line)
|
||||
void SSD1306AsciiWire::setRowNative(uint8_t line) {
|
||||
// Calculate pixel position from line number
|
||||
uint8_t row = line*8;
|
||||
if (row < m_displayHeight) {
|
||||
m_row = row;
|
||||
m_col = col + m_colOffset;
|
||||
I2CManager.write(m_i2cAddr, 4,
|
||||
0x00, // Set to command mode
|
||||
SSD1306_SETLOWCOLUMN | (col & 0XF),
|
||||
SSD1306_SETHIGHCOLUMN | (col >> 4),
|
||||
SSD1306_SETSTARTPAGE | m_row);
|
||||
m_col = m_colOffset;
|
||||
// Build output buffer for I2C
|
||||
uint8_t len = 0;
|
||||
outputBuffer[len++] = 0x00; // Set to command mode
|
||||
outputBuffer[len++] = SSD1306_SETLOWCOLUMN | (m_col & 0XF);
|
||||
outputBuffer[len++] = SSD1306_SETHIGHCOLUMN | (m_col >> 4);
|
||||
outputBuffer[len++] = SSD1306_SETSTARTPAGE | (m_row/8);
|
||||
I2CManager.write(m_i2cAddr, outputBuffer, len);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void SSD1306AsciiWire::setFont(const uint8_t* font) {
|
||||
m_font = font;
|
||||
m_fontFirstChar = readFontByte(m_font + FONT_FIRST_CHAR);
|
||||
m_fontCharCount = readFontByte(m_font + FONT_CHAR_COUNT);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
size_t SSD1306AsciiWire::write(uint8_t ch) {
|
||||
const uint8_t* base = m_font + FONT_WIDTH_TABLE;
|
||||
|
||||
// Write a character to the OLED
|
||||
size_t SSD1306AsciiWire::writeNative(uint8_t ch) {
|
||||
const uint8_t* base = m_font;
|
||||
|
||||
if (ch < m_fontFirstChar || ch >= (m_fontFirstChar + m_fontCharCount))
|
||||
return 0;
|
||||
// Check if character would be partly or wholly off the display
|
||||
if (m_col + fontWidth > m_displayWidth)
|
||||
return 0;
|
||||
#if defined(NOLOWERCASE)
|
||||
// Adjust if lowercase is missing
|
||||
if (ch >= 'a') {
|
||||
if (ch <= 'z')
|
||||
ch = ch - 'a' + 'A'; // Capitalise
|
||||
else
|
||||
ch -= 26; // Allow for missing lowercase letters
|
||||
}
|
||||
#endif
|
||||
ch -= m_fontFirstChar;
|
||||
base += fontWidth * ch;
|
||||
uint8_t buffer[1+fontWidth+letterSpacing];
|
||||
buffer[0] = 0x40; // set SSD1306 controller to data mode
|
||||
// Build output buffer for I2C
|
||||
outputBuffer[0] = 0x40; // set SSD1306 controller to data mode
|
||||
uint8_t bufferPos = 1;
|
||||
// Copy character pixel columns
|
||||
for (uint8_t i = 0; i < fontWidth; i++)
|
||||
buffer[bufferPos++] = readFontByte(base++);
|
||||
outputBuffer[bufferPos++] = GETFLASH(base++);
|
||||
// Add blank pixels between letters
|
||||
for (uint8_t i = 0; i < letterSpacing; i++)
|
||||
buffer[bufferPos++] = 0;
|
||||
outputBuffer[bufferPos++] = 0;
|
||||
|
||||
// Write the data to I2C display
|
||||
I2CManager.write(m_i2cAddr, buffer, bufferPos);
|
||||
I2CManager.write(m_i2cAddr, outputBuffer, bufferPos);
|
||||
m_col += fontWidth + letterSpacing;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// this section is based on https://github.com/adafruit/Adafruit_SSD1306
|
||||
|
||||
/** Initialization commands for a 128x32 or 128x64 SSD1306 oled display. */
|
||||
const uint8_t FLASH SSD1306AsciiWire::Adafruit128xXXinit[] = {
|
||||
// Init sequence for Adafruit 128x32/64 OLED module
|
||||
0x00, // Set to command mode
|
||||
SSD1306_DISPLAYOFF,
|
||||
SSD1306_SETDISPLAYCLOCKDIV, 0x80, // the suggested ratio 0x80
|
||||
SSD1306_SETMULTIPLEX, 0x3F, // ratio 64 (initially)
|
||||
SSD1306_SETDISPLAYOFFSET, 0x0, // no offset
|
||||
SSD1306_SETSTARTLINE | 0x0, // line #0
|
||||
SSD1306_CHARGEPUMP, 0x14, // internal vcc
|
||||
SSD1306_MEMORYMODE, 0x02, // page mode
|
||||
SSD1306_SEGREMAP | 0x1, // column 127 mapped to SEG0
|
||||
SSD1306_COMSCANDEC, // column scan direction reversed
|
||||
SSD1306_SETCOMPINS, 0X12, // set COM pins
|
||||
SSD1306_SETCONTRAST, 0x7F, // contrast level 127
|
||||
SSD1306_SETPRECHARGE, 0xF1, // pre-charge period (1, 15)
|
||||
SSD1306_SETVCOMDETECT, 0x40, // vcomh regulator level
|
||||
SSD1306_DISPLAYALLON_RESUME,
|
||||
SSD1306_NORMALDISPLAY,
|
||||
SSD1306_DISPLAYON
|
||||
};
|
||||
|
||||
/** Initialize a 128x32 SSD1306 oled display. */
|
||||
const DevType FLASH SSD1306AsciiWire::Adafruit128x32 = {
|
||||
Adafruit128xXXinit,
|
||||
sizeof(Adafruit128xXXinit),
|
||||
128,
|
||||
32,
|
||||
0
|
||||
};
|
||||
|
||||
/** Initialize a 128x64 oled display. */
|
||||
const DevType FLASH SSD1306AsciiWire::Adafruit128x64 = {
|
||||
Adafruit128xXXinit,
|
||||
sizeof(Adafruit128xXXinit),
|
||||
128,
|
||||
64,
|
||||
0
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
// This section is based on https://github.com/stanleyhuangyc/MultiLCD
|
||||
|
||||
/** Initialization commands for a 128x64 SH1106 oled display. */
|
||||
const uint8_t FLASH SSD1306AsciiWire::SH1106_132x64init[] = {
|
||||
0x00, // Set to command mode
|
||||
SSD1306_DISPLAYOFF,
|
||||
SSD1306_SETDISPLAYCLOCKDIV, 0X80, // set osc division
|
||||
SSD1306_SETMULTIPLEX, 0x3F, // ratio 64
|
||||
SSD1306_SETDISPLAYOFFSET, 0X00, // set display offset
|
||||
SSD1306_SETSTARTPAGE | 0X0, // set page address
|
||||
SSD1306_SETSTARTLINE | 0x0, // set start line
|
||||
SH1106_SET_PUMP_MODE, SH1106_PUMP_ON, // set charge pump enable
|
||||
SSD1306_SEGREMAP | 0X1, // set segment remap
|
||||
SSD1306_COMSCANDEC, // Com scan direction
|
||||
SSD1306_SETCOMPINS, 0X12, // set COM pins
|
||||
SSD1306_SETCONTRAST, 0x80, // 128
|
||||
SSD1306_SETPRECHARGE, 0X1F, // set pre-charge period
|
||||
SSD1306_SETVCOMDETECT, 0x40, // set vcomh
|
||||
SH1106_SET_PUMP_VOLTAGE | 0X2, // 8.0 volts
|
||||
SSD1306_NORMALDISPLAY, // normal / reverse
|
||||
SSD1306_DISPLAYON
|
||||
};
|
||||
|
||||
/** Initialize a 132x64 oled SH1106 display. */
|
||||
const DevType FLASH SSD1306AsciiWire::SH1106_132x64 = {
|
||||
SH1106_132x64init,
|
||||
sizeof(SH1106_132x64init),
|
||||
128,
|
||||
64,
|
||||
2 // SH1106 is a 132x64 controller but most OLEDs are only attached
|
||||
// to columns 2-129.
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Font characters, 5x7 pixels, 0x61 characters starting at 0x20.
|
||||
// Lower case characters optionally omitted.
|
||||
const uint8_t FLASH SSD1306AsciiWire::System5x7[] = {
|
||||
|
||||
// Fixed width; char width table not used !!!!
|
||||
// or with lowercase character omitted.
|
||||
|
||||
// font data
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, // (space)
|
||||
0x00, 0x00, 0x5F, 0x00, 0x00, // !
|
||||
0x00, 0x07, 0x00, 0x07, 0x00, // "
|
||||
0x14, 0x7F, 0x14, 0x7F, 0x14, // #
|
||||
0x24, 0x2A, 0x7F, 0x2A, 0x12, // $
|
||||
0x23, 0x13, 0x08, 0x64, 0x62, // %
|
||||
0x36, 0x49, 0x55, 0x22, 0x50, // &
|
||||
0x00, 0x05, 0x03, 0x00, 0x00, // '
|
||||
0x00, 0x1C, 0x22, 0x41, 0x00, // (
|
||||
0x00, 0x41, 0x22, 0x1C, 0x00, // )
|
||||
0x08, 0x2A, 0x1C, 0x2A, 0x08, // *
|
||||
0x08, 0x08, 0x3E, 0x08, 0x08, // +
|
||||
0x00, 0x50, 0x30, 0x00, 0x00, // ,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, // -
|
||||
0x00, 0x60, 0x60, 0x00, 0x00, // .
|
||||
0x20, 0x10, 0x08, 0x04, 0x02, // /
|
||||
0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
|
||||
0x00, 0x42, 0x7F, 0x40, 0x00, // 1
|
||||
0x42, 0x61, 0x51, 0x49, 0x46, // 2
|
||||
0x21, 0x41, 0x45, 0x4B, 0x31, // 3
|
||||
0x18, 0x14, 0x12, 0x7F, 0x10, // 4
|
||||
0x27, 0x45, 0x45, 0x45, 0x39, // 5
|
||||
0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
|
||||
0x01, 0x71, 0x09, 0x05, 0x03, // 7
|
||||
0x36, 0x49, 0x49, 0x49, 0x36, // 8
|
||||
0x06, 0x49, 0x49, 0x29, 0x1E, // 9
|
||||
0x00, 0x36, 0x36, 0x00, 0x00, // :
|
||||
0x00, 0x56, 0x36, 0x00, 0x00, // ;
|
||||
0x00, 0x08, 0x14, 0x22, 0x41, // <
|
||||
0x14, 0x14, 0x14, 0x14, 0x14, // =
|
||||
0x41, 0x22, 0x14, 0x08, 0x00, // >
|
||||
0x02, 0x01, 0x51, 0x09, 0x06, // ?
|
||||
0x32, 0x49, 0x79, 0x41, 0x3E, // @
|
||||
0x7E, 0x11, 0x11, 0x11, 0x7E, // A
|
||||
0x7F, 0x49, 0x49, 0x49, 0x36, // B
|
||||
0x3E, 0x41, 0x41, 0x41, 0x22, // C
|
||||
0x7F, 0x41, 0x41, 0x22, 0x1C, // D
|
||||
0x7F, 0x49, 0x49, 0x49, 0x41, // E
|
||||
0x7F, 0x09, 0x09, 0x01, 0x01, // F
|
||||
0x3E, 0x41, 0x41, 0x51, 0x32, // G
|
||||
0x7F, 0x08, 0x08, 0x08, 0x7F, // H
|
||||
0x00, 0x41, 0x7F, 0x41, 0x00, // I
|
||||
0x20, 0x40, 0x41, 0x3F, 0x01, // J
|
||||
0x7F, 0x08, 0x14, 0x22, 0x41, // K
|
||||
0x7F, 0x40, 0x40, 0x40, 0x40, // L
|
||||
0x7F, 0x02, 0x04, 0x02, 0x7F, // M
|
||||
0x7F, 0x04, 0x08, 0x10, 0x7F, // N
|
||||
0x3E, 0x41, 0x41, 0x41, 0x3E, // O
|
||||
0x7F, 0x09, 0x09, 0x09, 0x06, // P
|
||||
0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
|
||||
0x7F, 0x09, 0x19, 0x29, 0x46, // R
|
||||
0x46, 0x49, 0x49, 0x49, 0x31, // S
|
||||
0x01, 0x01, 0x7F, 0x01, 0x01, // T
|
||||
0x3F, 0x40, 0x40, 0x40, 0x3F, // U
|
||||
0x1F, 0x20, 0x40, 0x20, 0x1F, // V
|
||||
0x7F, 0x20, 0x18, 0x20, 0x7F, // W
|
||||
0x63, 0x14, 0x08, 0x14, 0x63, // X
|
||||
0x03, 0x04, 0x78, 0x04, 0x03, // Y
|
||||
0x61, 0x51, 0x49, 0x45, 0x43, // Z
|
||||
0x00, 0x00, 0x7F, 0x41, 0x41, // [
|
||||
0x02, 0x04, 0x08, 0x10, 0x20, // "\"
|
||||
0x41, 0x41, 0x7F, 0x00, 0x00, // ]
|
||||
0x04, 0x02, 0x01, 0x02, 0x04, // ^
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, // _
|
||||
0x00, 0x01, 0x02, 0x04, 0x00, // `
|
||||
#ifndef NOLOWERCASE
|
||||
0x20, 0x54, 0x54, 0x54, 0x78, // a
|
||||
0x7F, 0x48, 0x44, 0x44, 0x38, // b
|
||||
0x38, 0x44, 0x44, 0x44, 0x20, // c
|
||||
0x38, 0x44, 0x44, 0x48, 0x7F, // d
|
||||
0x38, 0x54, 0x54, 0x54, 0x18, // e
|
||||
0x08, 0x7E, 0x09, 0x01, 0x02, // f
|
||||
0x08, 0x14, 0x54, 0x54, 0x3C, // g
|
||||
0x7F, 0x08, 0x04, 0x04, 0x78, // h
|
||||
0x00, 0x44, 0x7D, 0x40, 0x00, // i
|
||||
0x20, 0x40, 0x44, 0x3D, 0x00, // j
|
||||
0x00, 0x7F, 0x10, 0x28, 0x44, // k
|
||||
0x00, 0x41, 0x7F, 0x40, 0x00, // l
|
||||
0x7C, 0x04, 0x18, 0x04, 0x78, // m
|
||||
0x7C, 0x08, 0x04, 0x04, 0x78, // n
|
||||
0x38, 0x44, 0x44, 0x44, 0x38, // o
|
||||
0x7C, 0x14, 0x14, 0x14, 0x08, // p
|
||||
0x08, 0x14, 0x14, 0x18, 0x7C, // q
|
||||
0x7C, 0x08, 0x04, 0x04, 0x08, // r
|
||||
0x48, 0x54, 0x54, 0x54, 0x20, // s
|
||||
0x04, 0x3F, 0x44, 0x40, 0x20, // t
|
||||
0x3C, 0x40, 0x40, 0x20, 0x7C, // u
|
||||
0x1C, 0x20, 0x40, 0x20, 0x1C, // v
|
||||
0x3C, 0x40, 0x30, 0x40, 0x3C, // w
|
||||
0x44, 0x28, 0x10, 0x28, 0x44, // x
|
||||
0x0C, 0x50, 0x50, 0x50, 0x3C, // y
|
||||
0x44, 0x64, 0x54, 0x4C, 0x44, // z
|
||||
#endif
|
||||
0x00, 0x08, 0x36, 0x41, 0x00, // {
|
||||
0x00, 0x00, 0x7F, 0x00, 0x00, // |
|
||||
0x00, 0x41, 0x36, 0x08, 0x00, // }
|
||||
0x08, 0x08, 0x2A, 0x1C, 0x08, // ->
|
||||
0x08, 0x1C, 0x2A, 0x08, 0x08, // <-
|
||||
0x00, 0x06, 0x09, 0x09, 0x06 // degree symbol
|
||||
|
||||
};
|
||||
|
126
SSD1306Ascii.h
126
SSD1306Ascii.h
@@ -1,6 +1,8 @@
|
||||
/* Based on Arduino SSD1306Ascii Library, Copyright (C) 2015 by William Greiman
|
||||
* Modifications (C) 2021 Neil McKechnie
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@@ -20,78 +22,88 @@
|
||||
#define SSD1306Ascii_h
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "SSD1306font.h"
|
||||
#include "SSD1306init.h"
|
||||
#include "FSH.h"
|
||||
#include "LCDDisplay.h"
|
||||
|
||||
class SSD1306AsciiWire : public Print {
|
||||
#include "I2CManager.h"
|
||||
#include "DIAG.h"
|
||||
|
||||
// Uncomment to remove lower-case letters to save 108 bytes of flash
|
||||
//#define NOLOWERCASE
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Device initialization structure.
|
||||
|
||||
struct DevType {
|
||||
/* Pointer to initialization command bytes. */
|
||||
const uint8_t* initcmds;
|
||||
/* Number of initialization bytes */
|
||||
const uint8_t initSize;
|
||||
/* Width of the display in pixels */
|
||||
const uint8_t lcdWidth;
|
||||
/** Height of the display in pixels. */
|
||||
const uint8_t lcdHeight;
|
||||
/* Column offset RAM to display. Used to pick start column of SH1106. */
|
||||
const uint8_t colOffset;
|
||||
};
|
||||
|
||||
// Constructor
|
||||
class SSD1306AsciiWire : public LCDDisplay {
|
||||
public:
|
||||
using Print::write;
|
||||
SSD1306AsciiWire() {}
|
||||
|
||||
// Constructor
|
||||
SSD1306AsciiWire(int width, int height);
|
||||
|
||||
// Initialize the display controller.
|
||||
void begin(const DevType* dev, uint8_t i2cAddr);
|
||||
|
||||
// Clear the display and set the cursor to (0, 0).
|
||||
void clear();
|
||||
// Clear a region of the display.
|
||||
void clear(uint8_t c0, uint8_t c1, uint8_t r0, uint8_t r1);
|
||||
// The current column in pixels.
|
||||
inline uint8_t col() const { return m_col; }
|
||||
// The display hight in pixels.
|
||||
inline uint8_t displayHeight() const { return m_displayHeight; }
|
||||
// The display height in rows with eight pixels to a row.
|
||||
inline uint8_t displayRows() const { return m_displayHeight / 8; }
|
||||
// The display width in pixels.
|
||||
inline uint8_t displayWidth() const { return m_displayWidth; }
|
||||
// Set the cursor position to (0, 0).
|
||||
inline void home() { setCursor(0, 0); }
|
||||
void clearNative();
|
||||
|
||||
// Set cursor to start of specified text line
|
||||
void setRowNative(byte line);
|
||||
|
||||
// Initialize the display controller.
|
||||
void init(const DevType* dev);
|
||||
// the current row number with eight pixels to a row.
|
||||
inline uint8_t row() const { return m_row; }
|
||||
/**
|
||||
* @brief Set the display contrast.
|
||||
*
|
||||
* @param[in] value The contrast level in th range 0 to 255.
|
||||
*/
|
||||
void setContrast(uint8_t value);
|
||||
/**
|
||||
* @brief Set the cursor position.
|
||||
*
|
||||
* @param[in] col The column number in pixels.
|
||||
* @param[in] row the row number in eight pixel rows.
|
||||
*/
|
||||
void setCursor(uint8_t col, uint8_t row);
|
||||
/**
|
||||
* @brief Set the current font.
|
||||
*
|
||||
* @param[in] font Pointer to a font table.
|
||||
*/
|
||||
void setFont(const uint8_t* font);
|
||||
/**
|
||||
* @brief Display a character.
|
||||
*
|
||||
* @param[in] c The character to display.
|
||||
* @return one for success else zero.
|
||||
*/
|
||||
size_t write(uint8_t c);
|
||||
|
||||
// Write one character to OLED
|
||||
size_t writeNative(uint8_t c);
|
||||
|
||||
// Display characteristics / initialisation
|
||||
static const DevType FLASH Adafruit128x32;
|
||||
static const DevType FLASH Adafruit128x64;
|
||||
static const DevType FLASH SH1106_132x64;
|
||||
|
||||
private:
|
||||
uint8_t m_col; // Cursor column.
|
||||
uint8_t m_row; // Cursor RAM row.
|
||||
uint8_t m_displayWidth; // Display width.
|
||||
uint8_t m_displayHeight; // Display height.
|
||||
uint8_t m_colOffset; // Column offset RAM to SEG.
|
||||
const uint8_t* m_font = NULL; // Current font.
|
||||
// Cursor column.
|
||||
uint8_t m_col;
|
||||
// Cursor RAM row.
|
||||
uint8_t m_row;
|
||||
// Display width.
|
||||
uint8_t m_displayWidth;
|
||||
// Display height.
|
||||
uint8_t m_displayHeight;
|
||||
// Column offset RAM to SEG.
|
||||
uint8_t m_colOffset = 0;
|
||||
// Current font.
|
||||
const uint8_t* const m_font = System5x7;
|
||||
|
||||
// Only fixed size 5x7 fonts in a 6x8 cell are supported.
|
||||
const uint8_t fontWidth = 5;
|
||||
const uint8_t fontHeight = 7;
|
||||
const uint8_t letterSpacing = 1;
|
||||
uint8_t m_fontFirstChar;
|
||||
uint8_t m_fontCharCount;
|
||||
static const uint8_t fontWidth = 5;
|
||||
static const uint8_t fontHeight = 7;
|
||||
static const uint8_t letterSpacing = 1;
|
||||
static const uint8_t m_fontFirstChar = 0x20;
|
||||
static const uint8_t m_fontCharCount = 0x61;
|
||||
|
||||
uint8_t m_i2cAddr;
|
||||
|
||||
uint8_t outputBuffer[fontWidth+letterSpacing+1];
|
||||
|
||||
static const uint8_t blankPixels[];
|
||||
|
||||
static const uint8_t System5x7[];
|
||||
static const uint8_t FLASH Adafruit128xXXinit[];
|
||||
static const uint8_t FLASH SH1106_132x64init[];
|
||||
};
|
||||
|
||||
#endif // SSD1306Ascii_h
|
||||
|
180
SSD1306font.h
180
SSD1306font.h
@@ -1,180 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* System5x7
|
||||
*
|
||||
*
|
||||
* File Name : System5x7.h
|
||||
* Date : 28 Oct 2008
|
||||
* Font size in bytes : 470
|
||||
* Font width : 5
|
||||
* Font height : 7
|
||||
* Font first char : 32
|
||||
* Font last char : 127
|
||||
* Font used chars : 94
|
||||
*
|
||||
* The font data are defined as
|
||||
*
|
||||
* struct _FONT_ {
|
||||
* uint16_t font_Size_in_Bytes_over_all_included_Size_it_self;
|
||||
* uint8_t font_Width_in_Pixel_for_fixed_drawing;
|
||||
* uint8_t font_Height_in_Pixel_for_all_characters;
|
||||
* unit8_t font_First_Char;
|
||||
* uint8_t font_Char_Count;
|
||||
*
|
||||
* uint8_t font_Char_Widths[font_Last_Char - font_First_Char +1];
|
||||
* // for each character the separate width in pixels,
|
||||
* // characters < 128 have an implicit virtual right empty row
|
||||
*
|
||||
* uint8_t font_data[];
|
||||
* // bit field of all characters
|
||||
*/
|
||||
|
||||
#ifndef SSD1306font_H
|
||||
#define SSD1306font_H
|
||||
|
||||
#define SYSTEM5x7_WIDTH 5
|
||||
#define SYSTEM5x7_HEIGHT 7
|
||||
|
||||
#ifdef __AVR__
|
||||
#include <avr/pgmspace.h>
|
||||
/** declare a font for AVR. */
|
||||
#define GLCDFONTDECL(_n) static const uint8_t __attribute__((progmem)) _n[]
|
||||
#define readFontByte(addr) pgm_read_byte(addr)
|
||||
#else // __AVR__
|
||||
/** declare a font. */
|
||||
#define GLCDFONTDECL(_n) static const uint8_t _n[]
|
||||
/** Fake read from flash. */
|
||||
#define readFontByte(addr) (*(const unsigned char *)(addr))
|
||||
#endif // __AVR__
|
||||
//------------------------------------------------------------------------------
|
||||
// Font Indices
|
||||
/** No longer used Big Endian length field. Now indicates font type.
|
||||
*
|
||||
* 00 00 (fixed width font with 1 padding pixel on right and below)
|
||||
*
|
||||
* 00 01 (fixed width font with no padding pixels)
|
||||
*/
|
||||
#define FONT_LENGTH 0
|
||||
/** Maximum character width. */
|
||||
#define FONT_WIDTH 2
|
||||
/** Font hight in pixels */
|
||||
#define FONT_HEIGHT 3
|
||||
/** Ascii value of first character */
|
||||
#define FONT_FIRST_CHAR 4
|
||||
/** count of characters in font. */
|
||||
#define FONT_CHAR_COUNT 5
|
||||
/** Offset to width table. */
|
||||
#define FONT_WIDTH_TABLE 6
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
GLCDFONTDECL(System5x7) = {
|
||||
0x0, 0x0, // size of zero indicates fixed width font,
|
||||
0x05, // width
|
||||
0x07, // height
|
||||
0x20, // first char
|
||||
0x61, // char count
|
||||
|
||||
// Fixed width; char width table not used !!!!
|
||||
|
||||
// font data
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, // (space)
|
||||
0x00, 0x00, 0x5F, 0x00, 0x00, // !
|
||||
0x00, 0x07, 0x00, 0x07, 0x00, // "
|
||||
0x14, 0x7F, 0x14, 0x7F, 0x14, // #
|
||||
0x24, 0x2A, 0x7F, 0x2A, 0x12, // $
|
||||
0x23, 0x13, 0x08, 0x64, 0x62, // %
|
||||
0x36, 0x49, 0x55, 0x22, 0x50, // &
|
||||
0x00, 0x05, 0x03, 0x00, 0x00, // '
|
||||
0x00, 0x1C, 0x22, 0x41, 0x00, // (
|
||||
0x00, 0x41, 0x22, 0x1C, 0x00, // )
|
||||
0x08, 0x2A, 0x1C, 0x2A, 0x08, // *
|
||||
0x08, 0x08, 0x3E, 0x08, 0x08, // +
|
||||
0x00, 0x50, 0x30, 0x00, 0x00, // ,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, // -
|
||||
0x00, 0x60, 0x60, 0x00, 0x00, // .
|
||||
0x20, 0x10, 0x08, 0x04, 0x02, // /
|
||||
0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
|
||||
0x00, 0x42, 0x7F, 0x40, 0x00, // 1
|
||||
0x42, 0x61, 0x51, 0x49, 0x46, // 2
|
||||
0x21, 0x41, 0x45, 0x4B, 0x31, // 3
|
||||
0x18, 0x14, 0x12, 0x7F, 0x10, // 4
|
||||
0x27, 0x45, 0x45, 0x45, 0x39, // 5
|
||||
0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
|
||||
0x01, 0x71, 0x09, 0x05, 0x03, // 7
|
||||
0x36, 0x49, 0x49, 0x49, 0x36, // 8
|
||||
0x06, 0x49, 0x49, 0x29, 0x1E, // 9
|
||||
0x00, 0x36, 0x36, 0x00, 0x00, // :
|
||||
0x00, 0x56, 0x36, 0x00, 0x00, // ;
|
||||
0x00, 0x08, 0x14, 0x22, 0x41, // <
|
||||
0x14, 0x14, 0x14, 0x14, 0x14, // =
|
||||
0x41, 0x22, 0x14, 0x08, 0x00, // >
|
||||
0x02, 0x01, 0x51, 0x09, 0x06, // ?
|
||||
0x32, 0x49, 0x79, 0x41, 0x3E, // @
|
||||
0x7E, 0x11, 0x11, 0x11, 0x7E, // A
|
||||
0x7F, 0x49, 0x49, 0x49, 0x36, // B
|
||||
0x3E, 0x41, 0x41, 0x41, 0x22, // C
|
||||
0x7F, 0x41, 0x41, 0x22, 0x1C, // D
|
||||
0x7F, 0x49, 0x49, 0x49, 0x41, // E
|
||||
0x7F, 0x09, 0x09, 0x01, 0x01, // F
|
||||
0x3E, 0x41, 0x41, 0x51, 0x32, // G
|
||||
0x7F, 0x08, 0x08, 0x08, 0x7F, // H
|
||||
0x00, 0x41, 0x7F, 0x41, 0x00, // I
|
||||
0x20, 0x40, 0x41, 0x3F, 0x01, // J
|
||||
0x7F, 0x08, 0x14, 0x22, 0x41, // K
|
||||
0x7F, 0x40, 0x40, 0x40, 0x40, // L
|
||||
0x7F, 0x02, 0x04, 0x02, 0x7F, // M
|
||||
0x7F, 0x04, 0x08, 0x10, 0x7F, // N
|
||||
0x3E, 0x41, 0x41, 0x41, 0x3E, // O
|
||||
0x7F, 0x09, 0x09, 0x09, 0x06, // P
|
||||
0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
|
||||
0x7F, 0x09, 0x19, 0x29, 0x46, // R
|
||||
0x46, 0x49, 0x49, 0x49, 0x31, // S
|
||||
0x01, 0x01, 0x7F, 0x01, 0x01, // T
|
||||
0x3F, 0x40, 0x40, 0x40, 0x3F, // U
|
||||
0x1F, 0x20, 0x40, 0x20, 0x1F, // V
|
||||
0x7F, 0x20, 0x18, 0x20, 0x7F, // W
|
||||
0x63, 0x14, 0x08, 0x14, 0x63, // X
|
||||
0x03, 0x04, 0x78, 0x04, 0x03, // Y
|
||||
0x61, 0x51, 0x49, 0x45, 0x43, // Z
|
||||
0x00, 0x00, 0x7F, 0x41, 0x41, // [
|
||||
0x02, 0x04, 0x08, 0x10, 0x20, // "\"
|
||||
0x41, 0x41, 0x7F, 0x00, 0x00, // ]
|
||||
0x04, 0x02, 0x01, 0x02, 0x04, // ^
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, // _
|
||||
0x00, 0x01, 0x02, 0x04, 0x00, // `
|
||||
0x20, 0x54, 0x54, 0x54, 0x78, // a
|
||||
0x7F, 0x48, 0x44, 0x44, 0x38, // b
|
||||
0x38, 0x44, 0x44, 0x44, 0x20, // c
|
||||
0x38, 0x44, 0x44, 0x48, 0x7F, // d
|
||||
0x38, 0x54, 0x54, 0x54, 0x18, // e
|
||||
0x08, 0x7E, 0x09, 0x01, 0x02, // f
|
||||
0x08, 0x14, 0x54, 0x54, 0x3C, // g
|
||||
0x7F, 0x08, 0x04, 0x04, 0x78, // h
|
||||
0x00, 0x44, 0x7D, 0x40, 0x00, // i
|
||||
0x20, 0x40, 0x44, 0x3D, 0x00, // j
|
||||
0x00, 0x7F, 0x10, 0x28, 0x44, // k
|
||||
0x00, 0x41, 0x7F, 0x40, 0x00, // l
|
||||
0x7C, 0x04, 0x18, 0x04, 0x78, // m
|
||||
0x7C, 0x08, 0x04, 0x04, 0x78, // n
|
||||
0x38, 0x44, 0x44, 0x44, 0x38, // o
|
||||
0x7C, 0x14, 0x14, 0x14, 0x08, // p
|
||||
0x08, 0x14, 0x14, 0x18, 0x7C, // q
|
||||
0x7C, 0x08, 0x04, 0x04, 0x08, // r
|
||||
0x48, 0x54, 0x54, 0x54, 0x20, // s
|
||||
0x04, 0x3F, 0x44, 0x40, 0x20, // t
|
||||
0x3C, 0x40, 0x40, 0x20, 0x7C, // u
|
||||
0x1C, 0x20, 0x40, 0x20, 0x1C, // v
|
||||
0x3C, 0x40, 0x30, 0x40, 0x3C, // w
|
||||
0x44, 0x28, 0x10, 0x28, 0x44, // x
|
||||
0x0C, 0x50, 0x50, 0x50, 0x3C, // y
|
||||
0x44, 0x64, 0x54, 0x4C, 0x44, // z
|
||||
0x00, 0x08, 0x36, 0x41, 0x00, // {
|
||||
0x00, 0x00, 0x7F, 0x00, 0x00, // |
|
||||
0x00, 0x41, 0x36, 0x08, 0x00, // }
|
||||
0x08, 0x08, 0x2A, 0x1C, 0x08, // ->
|
||||
0x08, 0x1C, 0x2A, 0x08, 0x08, // <-
|
||||
0x00, 0x06, 0x09, 0x09, 0x06 // degree symbol
|
||||
|
||||
};
|
||||
|
||||
#endif
|
207
SSD1306init.h
207
SSD1306init.h
@@ -1,207 +0,0 @@
|
||||
/* Based on Arduino SSD1306Ascii Library, Copyright (C) 2015 by William Greiman
|
||||
* Modifications (C) 2021 Neil McKechnie
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This Library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SSD1306Ascii Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @file SSD1306init.h
|
||||
* @brief Display controller initialization commands.
|
||||
*/
|
||||
#ifndef SSD1306init_h
|
||||
#define SSD1306init_h
|
||||
//------------------------------------------------------------------------------
|
||||
#ifndef __AVR__
|
||||
/** Handle AVR flash addressing. */
|
||||
#define MEM_TYPE
|
||||
#else // __AVR__
|
||||
#define MEM_TYPE __attribute__ ((progmem))
|
||||
#endif // __AVR__
|
||||
//------------------------------------------------------------------------------
|
||||
/** Set Lower Column Start Address for Page Addressing Mode. */
|
||||
#define SSD1306_SETLOWCOLUMN 0x00
|
||||
/** Set Higher Column Start Address for Page Addressing Mode. */
|
||||
#define SSD1306_SETHIGHCOLUMN 0x10
|
||||
/** Set Memory Addressing Mode. */
|
||||
#define SSD1306_MEMORYMODE 0x20
|
||||
/** Set display RAM display start line register from 0 - 63. */
|
||||
#define SSD1306_SETSTARTLINE 0x40
|
||||
/** Set Display Contrast to one of 256 steps. */
|
||||
#define SSD1306_SETCONTRAST 0x81
|
||||
/** Enable or disable charge pump. Follow with 0X14 enable, 0X10 disable. */
|
||||
#define SSD1306_CHARGEPUMP 0x8D
|
||||
/** Set Segment Re-map between data column and the segment driver. */
|
||||
#define SSD1306_SEGREMAP 0xA0
|
||||
/** Resume display from GRAM content. */
|
||||
#define SSD1306_DISPLAYALLON_RESUME 0xA4
|
||||
/** Force display on regardless of GRAM content. */
|
||||
#define SSD1306_DISPLAYALLON 0xA5
|
||||
/** Set Normal Display. */
|
||||
#define SSD1306_NORMALDISPLAY 0xA6
|
||||
/** Set Inverse Display. */
|
||||
#define SSD1306_INVERTDISPLAY 0xA7
|
||||
/** Set Multiplex Ratio from 16 to 63. */
|
||||
#define SSD1306_SETMULTIPLEX 0xA8
|
||||
/** Set Display off. */
|
||||
#define SSD1306_DISPLAYOFF 0xAE
|
||||
/** Set Display on. */
|
||||
#define SSD1306_DISPLAYON 0xAF
|
||||
/**Set GDDRAM Page Start Address. */
|
||||
#define SSD1306_SETSTARTPAGE 0XB0
|
||||
/** Set COM output scan direction normal. */
|
||||
#define SSD1306_COMSCANINC 0xC0
|
||||
/** Set COM output scan direction reversed. */
|
||||
#define SSD1306_COMSCANDEC 0xC8
|
||||
/** Set Display Offset. */
|
||||
#define SSD1306_SETDISPLAYOFFSET 0xD3
|
||||
/** Sets COM signals pin configuration to match the OLED panel layout. */
|
||||
#define SSD1306_SETCOMPINS 0xDA
|
||||
/** This command adjusts the VCOMH regulator output. */
|
||||
#define SSD1306_SETVCOMDETECT 0xDB
|
||||
/** Set Display Clock Divide Ratio/ Oscillator Frequency. */
|
||||
#define SSD1306_SETDISPLAYCLOCKDIV 0xD5
|
||||
/** Set Pre-charge Period */
|
||||
#define SSD1306_SETPRECHARGE 0xD9
|
||||
/** Deactivate scroll */
|
||||
#define SSD1306_DEACTIVATE_SCROLL 0x2E
|
||||
/** No Operation Command. */
|
||||
#define SSD1306_NOP 0XE3
|
||||
//------------------------------------------------------------------------------
|
||||
/** Set Pump voltage value: (30H~33H) 6.4, 7.4, 8.0 (POR), 9.0. */
|
||||
#define SH1106_SET_PUMP_VOLTAGE 0X30
|
||||
/** First byte of set charge pump mode */
|
||||
#define SH1106_SET_PUMP_MODE 0XAD
|
||||
/** Second byte charge pump on. */
|
||||
#define SH1106_PUMP_ON 0X8B
|
||||
/** Second byte charge pump off. */
|
||||
#define SH1106_PUMP_OFF 0X8A
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* @struct DevType
|
||||
* @brief Device initialization structure.
|
||||
*/
|
||||
struct DevType {
|
||||
/**
|
||||
* Pointer to initialization command bytes.
|
||||
*/
|
||||
const uint8_t* initcmds;
|
||||
/**
|
||||
* Number of initialization bytes.
|
||||
*/
|
||||
const uint8_t initSize;
|
||||
/**
|
||||
* Width of the diaplay in pixels.
|
||||
*/
|
||||
const uint8_t lcdWidth;
|
||||
/**
|
||||
* Height of the display in pixels.
|
||||
*/
|
||||
const uint8_t lcdHeight;
|
||||
/**
|
||||
* Column offset RAM to display. Used to pick start column of SH1106.
|
||||
*/
|
||||
const uint8_t colOffset;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
// this section is based on https://github.com/adafruit/Adafruit_SSD1306
|
||||
/** Initialization commands for a 128x32 SSD1306 oled display. */
|
||||
static const uint8_t MEM_TYPE Adafruit128x32init[] = {
|
||||
// Init sequence for Adafruit 128x32 OLED module
|
||||
0x00, // Set to command mode
|
||||
SSD1306_DISPLAYOFF,
|
||||
SSD1306_SETDISPLAYCLOCKDIV, 0x80, // the suggested ratio 0x80
|
||||
SSD1306_SETMULTIPLEX, 0x1F, // ratio 32
|
||||
SSD1306_SETDISPLAYOFFSET, 0x0, // no offset
|
||||
SSD1306_SETSTARTLINE | 0x0, // line #0
|
||||
SSD1306_CHARGEPUMP, 0x14, // internal vcc
|
||||
SSD1306_MEMORYMODE, 0x02, // page mode
|
||||
SSD1306_SEGREMAP | 0x1, // column 127 mapped to SEG0
|
||||
SSD1306_COMSCANDEC, // column scan direction reversed
|
||||
SSD1306_SETCOMPINS, 0x02, // sequential COM pins, disable remap
|
||||
SSD1306_SETCONTRAST, 0x7F, // contrast level 127
|
||||
SSD1306_SETPRECHARGE, 0xF1, // pre-charge period (1, 15)
|
||||
SSD1306_SETVCOMDETECT, 0x40, // vcomh regulator level
|
||||
SSD1306_DISPLAYALLON_RESUME,
|
||||
SSD1306_NORMALDISPLAY,
|
||||
SSD1306_DISPLAYON
|
||||
};
|
||||
/** Initialize a 128x32 SSD1306 oled display. */
|
||||
static const DevType MEM_TYPE Adafruit128x32 = {
|
||||
Adafruit128x32init,
|
||||
sizeof(Adafruit128x32init),
|
||||
128,
|
||||
32,
|
||||
0
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
// This section is based on https://github.com/adafruit/Adafruit_SSD1306
|
||||
/** Initialization commands for a 128x64 SSD1306 oled display. */
|
||||
static const uint8_t MEM_TYPE Adafruit128x64init[] = {
|
||||
// Init sequence for Adafruit 128x64 OLED module
|
||||
0x00, // Set to command mode
|
||||
SSD1306_DISPLAYOFF,
|
||||
SSD1306_SETDISPLAYCLOCKDIV, 0x80, // the suggested ratio 0x80
|
||||
SSD1306_SETMULTIPLEX, 0x3F, // ratio 64
|
||||
SSD1306_SETDISPLAYOFFSET, 0x0, // no offset
|
||||
SSD1306_SETSTARTLINE | 0x0, // line #0
|
||||
SSD1306_CHARGEPUMP, 0x14, // internal vcc
|
||||
SSD1306_MEMORYMODE, 0x02, // page mode
|
||||
SSD1306_SEGREMAP | 0x1, // column 127 mapped to SEG0
|
||||
SSD1306_COMSCANDEC, // column scan direction reversed
|
||||
SSD1306_SETCOMPINS, 0x12, // alt COM pins, disable remap
|
||||
SSD1306_SETCONTRAST, 0x7F, // contrast level 127
|
||||
SSD1306_SETPRECHARGE, 0xF1, // pre-charge period (1, 15)
|
||||
SSD1306_SETVCOMDETECT, 0x40, // vcomh regulator level
|
||||
SSD1306_DISPLAYALLON_RESUME,
|
||||
SSD1306_NORMALDISPLAY,
|
||||
SSD1306_DISPLAYON
|
||||
};
|
||||
/** Initialize a 128x64 oled display. */
|
||||
static const DevType MEM_TYPE Adafruit128x64 = {
|
||||
Adafruit128x64init,
|
||||
sizeof(Adafruit128x64init),
|
||||
128,
|
||||
64,
|
||||
0
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
// This section is based on https://github.com/stanleyhuangyc/MultiLCD
|
||||
/** Initialization commands for a 128x64 SH1106 oled display. */
|
||||
static const uint8_t MEM_TYPE SH1106_128x64init[] = {
|
||||
0x00, // Set to command mode
|
||||
SSD1306_DISPLAYOFF,
|
||||
SSD1306_SETSTARTPAGE | 0X0, // set page address
|
||||
SSD1306_SETCONTRAST, 0x80, // 128
|
||||
SSD1306_SEGREMAP | 0X1, // set segment remap
|
||||
SSD1306_NORMALDISPLAY, // normal / reverse
|
||||
SSD1306_SETMULTIPLEX, 0x3F, // ratio 64
|
||||
SH1106_SET_PUMP_MODE, SH1106_PUMP_ON, // set charge pump enable
|
||||
SH1106_SET_PUMP_VOLTAGE | 0X2, // 8.0 volts
|
||||
SSD1306_COMSCANDEC, // Com scan direction
|
||||
SSD1306_SETDISPLAYOFFSET, 0X00, // set display offset
|
||||
SSD1306_SETDISPLAYCLOCKDIV, 0X80, // set osc division
|
||||
SSD1306_SETPRECHARGE, 0X1F, // set pre-charge period
|
||||
SSD1306_SETCOMPINS, 0X12, // set COM pins
|
||||
SSD1306_SETVCOMDETECT, 0x40, // set vcomh
|
||||
SSD1306_DISPLAYON
|
||||
};
|
||||
/** Initialize a 128x64 oled SH1106 display. */
|
||||
static const DevType MEM_TYPE SH1106_128x64 = {
|
||||
SH1106_128x64init,
|
||||
sizeof(SH1106_128x64init),
|
||||
128,
|
||||
64,
|
||||
2 // SH1106 is a 132x64 controller. Use middle 128 columns.
|
||||
};
|
||||
#endif // SSD1306init_h
|
@@ -184,7 +184,7 @@ void Sensor::load(){
|
||||
struct SensorData data;
|
||||
Sensor *tt;
|
||||
|
||||
for(int i=0;i<EEStore::eeStore->data.nSensors;i++){
|
||||
for(uint16_t i=0;i<EEStore::eeStore->data.nSensors;i++){
|
||||
EEPROM.get(EEStore::pointer(),data);
|
||||
tt=create(data.snum,data.pin,data.pullUp);
|
||||
EEStore::advance(sizeof(tt->data));
|
||||
|
@@ -39,7 +39,6 @@ bool Turnout::activate(int n,bool state){
|
||||
Turnout * tt=get(n);
|
||||
if (tt==NULL) return false;
|
||||
tt->activate(state);
|
||||
EEStore::store();
|
||||
turnoutlistHash++;
|
||||
return true;
|
||||
}
|
||||
@@ -68,7 +67,9 @@ void Turnout::activate(bool state) {
|
||||
PWMServoDriver::setServo(data.tStatus & STATUS_PWMPIN, (data.inactiveAngle+(state?data.moveAngle:0)));
|
||||
else
|
||||
DCC::setAccessory(data.address,data.subAddress, state);
|
||||
EEStore::store();
|
||||
// Save state if stored in EEPROM
|
||||
if (EEStore::eeStore->data.nTurnouts > 0 && num > 0)
|
||||
EEPROM.put(num, data.tStatus);
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -102,11 +103,12 @@ void Turnout::load(){
|
||||
struct TurnoutData data;
|
||||
Turnout *tt;
|
||||
|
||||
for(int i=0;i<EEStore::eeStore->data.nTurnouts;i++){
|
||||
for(uint16_t i=0;i<EEStore::eeStore->data.nTurnouts;i++){
|
||||
EEPROM.get(EEStore::pointer(),data);
|
||||
if (data.tStatus & STATUS_PWM) tt=create(data.id,data.tStatus & STATUS_PWMPIN, data.inactiveAngle,data.moveAngle);
|
||||
else tt=create(data.id,data.address,data.subAddress);
|
||||
tt->data.tStatus=data.tStatus;
|
||||
tt->num=EEStore::pointer()+offsetof(TurnoutData,tStatus); // Save pointer to status byte within EEPROM
|
||||
EEStore::advance(sizeof(tt->data));
|
||||
#ifdef EESTOREDEBUG
|
||||
tt->print(tt);
|
||||
@@ -126,6 +128,7 @@ void Turnout::store(){
|
||||
#ifdef EESTOREDEBUG
|
||||
tt->print(tt);
|
||||
#endif
|
||||
tt->num=EEStore::pointer()+offsetof(TurnoutData,tStatus); // Save pointer to tstatus byte within EEPROM
|
||||
EEPROM.put(EEStore::pointer(),tt->data);
|
||||
EEStore::advance(sizeof(tt->data));
|
||||
tt=tt->nextTurnout;
|
||||
|
@@ -54,6 +54,8 @@ class Turnout {
|
||||
#ifdef EESTOREDEBUG
|
||||
void print(Turnout *tt);
|
||||
#endif
|
||||
private:
|
||||
int num; // EEPROM address of tStatus in TurnoutData struct, or zero if not stored.
|
||||
}; // Turnout
|
||||
|
||||
#endif
|
||||
|
@@ -1,3 +1,22 @@
|
||||
/*
|
||||
* (c) 2021 Fred Decker. All rights reserved.
|
||||
* (c) 2020 Chris Harlow. All rights reserved.
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* It is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef WifiInboundHandler_h
|
||||
#define WifiInboundHandler_h
|
||||
|
||||
|
@@ -171,16 +171,16 @@ wifiSerialState WifiInterface::setup2(const FSH* SSid, const FSH* password,
|
||||
#ifdef DONT_TOUCH_WIFI_CONF
|
||||
DIAG(F("DONT_TOUCH_WIFI_CONF was set: Using existing config"));
|
||||
#else
|
||||
StringFormatter::send(wifiStream, F("AT+CWMODE=1\r\n")); // configure as "station" = WiFi client
|
||||
checkForOK(1000, true); // Not always OK, sometimes "no change"
|
||||
|
||||
// Older ES versions have AT+CWJAP, newer ones have AT+CWJAP_CUR and AT+CWHOSTNAME
|
||||
StringFormatter::send(wifiStream, F("AT+CWJAP?\r\n"));
|
||||
if (checkForOK(2000, true)) {
|
||||
StringFormatter::send(wifiStream, F("AT+CWJAP_CUR?\r\n"));
|
||||
if (!(checkForOK(2000, true))) {
|
||||
oldCmd=true;
|
||||
while (wifiStream->available()) StringFormatter::printEscape( wifiStream->read()); /// THIS IS A DIAG IN DISGUISE
|
||||
}
|
||||
|
||||
StringFormatter::send(wifiStream, F("AT+CWMODE%s=1\r\n"), oldCmd ? "" : "_CUR"); // configure as "station" = WiFi client
|
||||
checkForOK(1000, true); // Not always OK, sometimes "no change"
|
||||
|
||||
const char *yourNetwork = "Your network ";
|
||||
if (strncmp_P(yourNetwork, (const char*)SSid, 13) == 0 || strncmp_P("", (const char*)SSid, 13) == 0) {
|
||||
if (strncmp_P(yourNetwork, (const char*)password, 13) == 0) {
|
||||
@@ -199,40 +199,40 @@ wifiSerialState WifiInterface::setup2(const FSH* SSid, const FSH* password,
|
||||
} else {
|
||||
// SSID was configured, so we assume station (client) mode.
|
||||
if (oldCmd) {
|
||||
// AT command early version supports CWJAP/CWSAP
|
||||
StringFormatter::send(wifiStream, F("AT+CWJAP=\"%S\",\"%S\"\r\n"), SSid, password);
|
||||
ipOK = checkForOK(WIFI_CONNECT_TIMEOUT, true);
|
||||
// AT command early version supports CWJAP/CWSAP
|
||||
StringFormatter::send(wifiStream, F("AT+CWJAP=\"%S\",\"%S\"\r\n"), SSid, password);
|
||||
ipOK = checkForOK(WIFI_CONNECT_TIMEOUT, true);
|
||||
} else {
|
||||
// later version supports CWJAP_CUR
|
||||
StringFormatter::send(wifiStream, F("AT+CWHOSTNAME=\"%S\"\r\n"), hostname); // Set Host name for Wifi Client
|
||||
checkForOK(2000, true); // dont care if not supported
|
||||
checkForOK(2000, true); // dont care if not supported
|
||||
|
||||
StringFormatter::send(wifiStream, F("AT+CWJAP_CUR=\"%S\",\"%S\"\r\n"), SSid, password);
|
||||
ipOK = checkForOK(WIFI_CONNECT_TIMEOUT, true);
|
||||
ipOK = checkForOK(WIFI_CONNECT_TIMEOUT, true);
|
||||
}
|
||||
|
||||
if (ipOK) {
|
||||
// But we really only have the ESSID and password correct
|
||||
// But we really only have the ESSID and password correct
|
||||
// Let's check for IP (via DHCP)
|
||||
ipOK = false;
|
||||
StringFormatter::send(wifiStream, F("AT+CIFSR\r\n"));
|
||||
if (checkForOK(5000, F("+CIFSR:STAIP"), true,false))
|
||||
if (!checkForOK(1000, F("0.0.0.0"), true,false))
|
||||
ipOK = true;
|
||||
StringFormatter::send(wifiStream, F("AT+CIFSR\r\n"));
|
||||
if (checkForOK(5000, F("+CIFSR:STAIP"), true,false))
|
||||
if (!checkForOK(1000, F("0.0.0.0"), true,false))
|
||||
ipOK = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ipOK) {
|
||||
// If we have not managed to get this going in station mode, go for AP mode
|
||||
|
||||
// StringFormatter::send(wifiStream, F("AT+RST\r\n"));
|
||||
// checkForOK(1000, true); // Not always OK, sometimes "no change"
|
||||
// StringFormatter::send(wifiStream, F("AT+RST\r\n"));
|
||||
// checkForOK(1000, true); // Not always OK, sometimes "no change"
|
||||
|
||||
int i=0;
|
||||
do {
|
||||
// configure as AccessPoint. Try really hard as this is the
|
||||
// last way out to get any Wifi connectivity.
|
||||
StringFormatter::send(wifiStream, F("AT+CWMODE=2\r\n"));
|
||||
// last way out to get any Wifi connectivity.
|
||||
StringFormatter::send(wifiStream, F("AT+CWMODE%s=2\r\n"), oldCmd ? "" : "_CUR");
|
||||
} while (!checkForOK(1000+i*500, true) && i++<10);
|
||||
|
||||
while (wifiStream->available()) StringFormatter::printEscape( wifiStream->read()); /// THIS IS A DIAG IN DISGUISE
|
||||
@@ -262,7 +262,7 @@ wifiSerialState WifiInterface::setup2(const FSH* SSid, const FSH* password,
|
||||
oldCmd ? "" : "_CUR", macTail, macTail, channel);
|
||||
} else {
|
||||
// password configured by user
|
||||
StringFormatter::send(wifiStream, F("AT+CWSAP%s=\"DCCEX_%s\",\"%S\",%d,4\r\n"), oldCmd ? "" : "_CUR",
|
||||
StringFormatter::send(wifiStream, F("AT+CWSAP%s=\"DCCEX_%s\",\"%S\",%d,4\r\n"), oldCmd ? "" : "_CUR",
|
||||
macTail, password, channel);
|
||||
}
|
||||
} while (!checkForOK(WIFI_CONNECT_TIMEOUT, true) && i++<2); // do twice if necessary but ignore failure as AP mode may still be ok
|
||||
|
@@ -1,7 +1,23 @@
|
||||
/**********************************************************************
|
||||
/*
|
||||
* COPYRIGHT (c) 2020 Fred Decker
|
||||
*
|
||||
* This file is part of CommandStation-EX
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* It is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
config.h
|
||||
COPYRIGHT (c) 2020 Fred Decker
|
||||
/**********************************************************************
|
||||
|
||||
The configuration file for DCC-EX Command Station
|
||||
|
||||
@@ -60,7 +76,7 @@ The configuration file for DCC-EX Command Station
|
||||
// is set (recommended), that password will be used for AP mode.
|
||||
// The AP mode password must be at least 8 characters long.
|
||||
//
|
||||
// Your SSID may not conain ``"'' (double quote, ASCII 0x22).
|
||||
// Your SSID may not contain ``"'' (double quote, ASCII 0x22).
|
||||
#define WIFI_SSID "Your network name"
|
||||
//
|
||||
// WIFI_PASSWORD is the network password for your home network or if
|
||||
|
241
release_notes.md
241
release_notes.md
@@ -1,139 +1,206 @@
|
||||
The DCC-EX Team is pleased to release CommandStation-EX-v3.0.0 as a Production Release. This release is a major re-write of earlier versions. We've re-architected the code-base so that it can better handle new features going forward.
|
||||
The DCC-EX Team is pleased to release CommandStation-EX-v3.1.0 as a Production Release. Release v3.1.0 is a minor release that adds additional features and fixes a number of bugs. With the number of new features, this could have easily been a major release. The team is continually improving the architecture of DCC++EX to make it more flexible and optimizing the code so as to get more performance from the Arduino (and other) microprocessors. This release includes all of the Point Releases from v3.0.1 to v3.0.16.
|
||||
|
||||
**Known Bugs:**
|
||||
- **Consisting through JMRI** - currently does not work in this release. You may use the <M> command to do this manually.
|
||||
- **Wi-Fi** - works, but can be challenging to use if you want to switch between AP mode and STA station mode.
|
||||
- **Pololu Motor Shield** - is supported with this release, but the user may have to play around with some timings to enable programming mode due to limitation in its current sensing circuitry
|
||||
**Downloads (zip and tar.gz) below. These are named without version number in the folder name to make the Arduino IDE happy.**
|
||||
|
||||
[CommandStation-EX.zip](https://github.com/DCC-EX/CommandStation-EX/releases/download/v3.1.0-Prod/CommandStation-EX.zip)
|
||||
[CommandStation-EX.tar.gz](https://github.com/DCC-EX/CommandStation-EX/releases/download/v3.1.0-Prod/CommandStation-EX.tar.gz)
|
||||
|
||||
**Known Issues**
|
||||
|
||||
- **Wi-Fi** - works, but requires sending <AT> commands from a serial monitor if you want to switch between AP mode and STA station mode after initial setup
|
||||
- **Pololu Motor Shield** - is supported with this release, but the user may have to adjust timings to enable programming mode due to limitation in its current sensing circuitry
|
||||
|
||||
#### Summary of key features and/or bug fixes by Point Release
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.16**
|
||||
|
||||
- Ignore CV1 bit 7 read if rejected by a non NMRA compliant decoder when identifying loco id
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.15**
|
||||
|
||||
- Send function commands just once instead of repeating them 4 times
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.14**
|
||||
|
||||
- Add feature to tolerate decoders that incorrectly have gaps in their ACK pulse
|
||||
- Provide proper track power management when joining and unjoining tracks with <1 JOIN>
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.13**
|
||||
|
||||
- Fix for CAB Functions greater than 127
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.12**
|
||||
|
||||
- Fixed clear screen issue for nanoEvery and nanoWifi
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.11**
|
||||
|
||||
- Reorganized files for support of 128 speed steps
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.10**
|
||||
|
||||
- Added Support for the Teensy 3.2, 3.5, 3.6, 4.0 and 4.1 MCUs
|
||||
- No functional change just changes to avoid complier warnings for Teensy/nanoEvery
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.9**
|
||||
|
||||
- Rearranges serial newlines for the benefit of JMRI
|
||||
- Major update for efficiencies in displays (LCD, OLED)
|
||||
- Add I2C Support functions
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.8**
|
||||
|
||||
- Wraps <* *> around DIAGS for the benefit of JMRI
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.7**
|
||||
- **Support for 28 Speed steps** - Option to turn on 28 step speed decoders in addition to 128. If set, all locos will use 28 steps.
|
||||
- **Improved overload messages with raw values (relative to offset)**
|
||||
|
||||
- Implemented support for older 28 apeed step decoders - Option to turn on 28 step speed decoders in addition to 128. If set, all locos will use 28 steps.
|
||||
- Improved overload messages with raw values (relative to offset)
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.6**
|
||||
|
||||
- **Prevent compiler warning about deprecated B constants**
|
||||
- **Fix Bug that did not let us transmit 5 byte sized packets** - 5 Byte commands like PoM (programming on main) were not being sent correctly
|
||||
- **Huge function numbers (DCC BinaryStateControl)** - Support Functions beyond F28
|
||||
- **<!> ESTOP all** - New command to emergency stop all locos on the main track
|
||||
- **<- [cab]> estop and forget cab/all cabs** - Stop and remove loco from the CS. Stops the repeating throttle messages
|
||||
- **``<D RESET>`` command to reboot arduino**
|
||||
- **Automatic sensor offset detect** -
|
||||
- **Improved startup msgs from Motor Drivers (accuracy and auto sense factors)** -
|
||||
- **Drop post-write verify** - No need to double check CV writes. Writes are now even faster.
|
||||
- **Allow current sene pin set to UNUSED_PIN** - No need to ground an unused analog current pin. Produce startup warning and callback -2 for prog track cmds.
|
||||
- Prevent compiler warning about deprecated B constants
|
||||
- Fix Bug that did not let us transmit 5 byte sized packets - 5 Byte commands like PoM (programming on main) were not being sent correctly
|
||||
- Support for Huge function numbers (DCC BinaryStateControl) - Support Functions beyond F28
|
||||
- <!> ESTOP all - New command to emergency stop all locos on the main track
|
||||
- <- [cab]> estop and forget cab/all cabs - Stop and remove loco from the CS. Stops the repeating throttle messages
|
||||
- `<D RESET>` command to reboot Arduino
|
||||
- Automatic sensor offset detect
|
||||
- Improved startup msgs from Motor Drivers (accuracy and auto sense factors)
|
||||
- Drop post-write verify - No need to double check CV writes. Writes are now even faster.
|
||||
- Allow current sense pin set to UNUSED_PIN - No need to ground an unused analog current pin. Produce startup warning and callback -2 for prog track cmds.
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.5**
|
||||
- **Fix Fn Key startup with loco ID and fix state change for F16-28**
|
||||
- removed ethernet mac config and made it automatic
|
||||
- show wifi ip and port on lcd
|
||||
- auto load config.example.h with warningh
|
||||
- dropped example .ino files
|
||||
- corrected .ino comments
|
||||
- pololu fault pin handling
|
||||
- waveform speed/simplicity improvements
|
||||
- improved pin speed in waveform
|
||||
- portability to nanoEvery and UnoWifiRev2 CPUs
|
||||
- analog read speed improvements
|
||||
- drop need for DIO2 library
|
||||
- improved current check code
|
||||
- linear <a> command
|
||||
- removed need for ArduinoTimers files
|
||||
- removed <D DCC SLOW>
|
||||
- Removed option to choose different timer
|
||||
- Added EX-RAIL hooks for later
|
||||
- fixed Turnout list
|
||||
- allow command keywords in mixed case
|
||||
- dropped unused memstream
|
||||
- PWM pin accuracy if requirements met.
|
||||
|
||||
- Fix Fn Key startup with loco ID and fix state change for F16-28
|
||||
- Removed ethernet mac config and made it automatic
|
||||
- Show wifi ip and port on lcd
|
||||
- Auto load config.example.h with warning
|
||||
- Dropped example .ino files
|
||||
- Corrected .ino comments
|
||||
- Add Pololu fault pin handling
|
||||
- Waveform speed/simplicity improvements
|
||||
- Improved pin speed in waveform
|
||||
- Portability to nanoEvery and UnoWifiRev2 CPUs
|
||||
- Analog read speed improvements
|
||||
- Drop need for DIO2 library
|
||||
- Improved current check code
|
||||
- Linear command
|
||||
- Removed need for ArduinoTimers files
|
||||
- Removed option to choose different timer
|
||||
- Added EX-RAIL hooks for automation in future version
|
||||
- Fixed Turnout list
|
||||
- Allow command keywords in mixed case
|
||||
- Dropped unused memstream
|
||||
- PWM pin accuracy if requirements met
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.4**
|
||||
- **"Drive-Away" Feature added so that throttles like Engine Driver can allow a loco to be programmed on a usable, electrically isolated programming track and then drive off onto the main track.
|
||||
- **WiFi Startup Fixes**
|
||||
|
||||
|
||||
- "Drive-Away" Feature - added so that throttles like Engine Driver can allow a loco to be programmed on a usable, electrically isolated programming track and then drive off onto the main track
|
||||
- WiFi Startup Fixes
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.3**
|
||||
- **<W addr> command to write loco address and clear consist**
|
||||
- **<R> command will allow for consist address**
|
||||
- **Startup commands implemented**
|
||||
|
||||
|
||||
- Command to write loco address and clear consist
|
||||
- Command will allow for consist address
|
||||
- Startup commands implemented
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.2:**
|
||||
- **Create new output for current in mA for ``<c>`` command** - New current response outputs current in mA, overlimit current, and maximum board capable current
|
||||
- **Simultaneously update JMRI to handle new current meter**
|
||||
|
||||
- Create new output for current in mA for `<c>` command - New current response outputs current in mA, overlimit current, and maximum board capable current
|
||||
- Simultaneously update JMRI to handle new current meter
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.1:**
|
||||
- **Add back fix for jitter**
|
||||
- **Add Turnouts, Outputs and Sensors to ```<s>``` command output**
|
||||
|
||||
**Summary of the key new features added to CommandStation-EX V3.0.0:**
|
||||
- Add back fix for jitter
|
||||
- Add Turnouts, Outputs and Sensors to `<s>` command output
|
||||
|
||||
- **New USB Browser Based Throttle** - WebThrottle-EX is a full front-end to controller to control the CS to run trains.
|
||||
- **WiFi Support** - AP and station modes supported. Auto-detection of an ESP8266 WiFi module with AT firmware on a Mega's serial port. Connection to JMRI and WiThrottle clients.
|
||||
- **Withrottle Integrations** - Act as a host for up to four WiThrottle clients concurrently.
|
||||
- **Add LCD/OLED support** - OLED supported on Mega only
|
||||
- **Improved CV programming routines** - checks for length of CV pulse, and breaks out of the wait state once it has received an ACK, now reading one CV per second.
|
||||
- **Improved current sensing** - rewrote current sensing routines for safer operation. Current thresholds based on milliamps, not magic numbers
|
||||
- **Individual track power control** - Ability to toggle power on either or both tracks, and to "JOIN" the tracks and make them output the same waveform for multiple power districts.
|
||||
- **Single or Dual-Pin PWM output** - Allows control of H-bridges with PH/EN or dual PWM inputs
|
||||
- **New, simpler function command** - ```<F>``` command allows setting functions based on their number, not based on a code as in ```<f>```
|
||||
- **Function reminders** - Function reminders are sent in addition to speed reminders
|
||||
- **Functions to F28** - All NMRA functions are now supported
|
||||
- **Filters and user functions** - Ability to filter commands in the parser and execute custom code based on them. (ex: Redirect Turnout commands via NRF24)
|
||||
- **Diagnostic ```<D>``` commands** - See documentation for a full list of new diagnostic commands
|
||||
- **Rewrote DCC++ Parser** - more efficient operation, accepts multi-char input and uses less RAM
|
||||
- **Rewritten waveform generator** - capable of using any pin for DCC waveform out, eliminating the need for jumpers
|
||||
- **Rewritten packet generator** - Simplify and make smaller, remove idea of "registers" from original code
|
||||
- **Add free RAM messages** - Free RAM messages are now printed whenever there is a decerase in available RAM
|
||||
- **Fix EEPROM bugs**
|
||||
- **Number of locos discovery command** - ```<#>``` command
|
||||
- **Support for more locomotives** - 20 locomotives on an UNO and 50 an a Mega.
|
||||
- **Automatic slot managment** - slot variable in throttle/function commands are ignored and slot management is taken care of automatically. ```<!>``` command added to release locos from memory.
|
||||
**CommandStation-EX V3.0.0:**
|
||||
|
||||
**Release v3.0.0 was a major rewrite if earlier versions of DCC++. The code base was re-architeced and core changes were made to the Waveform generator to reduce overhead and make better use of Arduino.** **Summary of the key new features added in Release v3.0.0 include:**
|
||||
|
||||
- **New USB Browser Based Throttle** - WebThrottle-EX is a full front-end to controller to control the CS to run trains.
|
||||
- **WiFi Support** - AP and station modes supported. Auto-detection of an ESP8266 WiFi module with AT firmware on a Mega's serial port. Connection to JMRI and WiThrottle clients.
|
||||
- **Withrottle Integrations** - Act as a host for up to four WiThrottle clients concurrently.
|
||||
- **Add LCD/OLED support** - OLED supported on Mega only
|
||||
- **Improved CV programming routines** - checks for length of CV pulse, and breaks out of the wait state once it has received an ACK, now reading one CV per second.
|
||||
- **Improved current sensing** - rewrote current sensing routines for safer operation. Current thresholds based on milliamps, not magic numbers
|
||||
- **Individual track power control** - Ability to toggle power on either or both tracks, and to "JOIN" the tracks and make them output the same waveform for multiple power districts.
|
||||
- **Single or Dual-Pin PWM output** - Allows control of H-bridges with PH/EN or dual PWM inputs
|
||||
- **New, simpler function command** - `<F>` command allows setting functions based on their number, not based on a code as in `<f>`
|
||||
- **Function reminders** - Function reminders are sent in addition to speed reminders
|
||||
- **Functions to F28** - All NMRA functions are now supported
|
||||
- **Filters and user functions** - Ability to filter commands in the parser and execute custom code based on them. (ex: Redirect Turnout commands via NRF24)
|
||||
- **Diagnostic `<D>` commands** - See documentation for a full list of new diagnostic commands
|
||||
- **Rewrote DCC++ Parser** - more efficient operation, accepts multi-char input and uses less RAM
|
||||
- **Rewritten waveform generator** - capable of using any pin for DCC waveform out, eliminating the need for jumpers
|
||||
- **Rewritten packet generator** - Simplify and make smaller, remove idea of "registers" from original code
|
||||
- **Add free RAM messages** - Free RAM messages are now printed whenever there is a decerase in available RAM
|
||||
- **Fix EEPROM bugs**
|
||||
- **Number of locos discovery command** - `<#>` command
|
||||
- **Support for more locomotives** - 20 locomotives on an UNO and 50 an a Mega.
|
||||
- **Automatic slot management** - slot variable in throttle/function commands are ignored and slot management is taken care of automatically. `<->` and `<- CAB>` commands added to release locos from memory and stop packets to the track.
|
||||
|
||||
**Key Contributors**
|
||||
|
||||
**Project Lead**
|
||||
|
||||
- Fred Decker - Holly Springs, North Carolina, USA (FlightRisk)
|
||||
|
||||
**CommandStation-EX Developers**
|
||||
|
||||
- Chris Harlow - Bournemouth, UK (UKBloke)
|
||||
- Harald Barth - Stockholm, Sweden (Haba)
|
||||
- Neil McKechnie - Worcestershire, UK (NeilMck)
|
||||
- Fred Decker - Holly Springs, North Carolina, USA (FlightRisk)
|
||||
- Dave Cutting - Logan, Utah, USA (Dave Cutting/ David Cutting)
|
||||
- M Steve Todd - - Engine Driver and JMRI Interface
|
||||
- Scott Catalanno - Pennsylvania
|
||||
- M Steve Todd -
|
||||
- Scott Catalano - Pennsylvania
|
||||
- Gregor Baues - Île-de-France, France (grbba)
|
||||
|
||||
**Engine Driver and JMRI Interface**
|
||||
|
||||
- M Steve Todd
|
||||
|
||||
**exInstaller Software**
|
||||
|
||||
- Anthony W - Dayton, Ohio, USA (Dex, Dex++)
|
||||
|
||||
**Website and Documentation**
|
||||
|
||||
- Mani Kumar - Bangalor, India (Mani / Mani Kumar)
|
||||
- Fred Decker - Holly Springs, North Carolina, USA (FlightRisk)
|
||||
- Dave Cutting - Logan, Utah, USA (Dave Cutting/ David Cutting)
|
||||
- Roger Beschizza - Dorset, UK (Roger Beschizza)
|
||||
- Keith Ledbetter - Chicago, Illinois, USA (Keith Ledbetter)
|
||||
- Kevin Smith - (KCSmith)
|
||||
- Kevin Smith - Rochester Hills, Michigan USA (KC Smith)
|
||||
|
||||
**WebThrotle-EX**
|
||||
|
||||
- Fred Decker - Holly Springs, NC (FlightRisk/FrightRisk)
|
||||
- Mani Kumar - Bangalor, India (Mani /Mani Kumar)
|
||||
- Matt H - Somewhere in Europe
|
||||
|
||||
|
||||
|
||||
**Beta Testing / Release Management / Support**
|
||||
- Larry Dribin - Release Management
|
||||
- Keith Ledbetter
|
||||
- BradVan der Elst
|
||||
- Andrew Pye
|
||||
- Mike Bowers
|
||||
|
||||
- Larry Dribin - Release Management
|
||||
- Kevin Smith - Rochester Hills, Michigan USA (KC Smith)
|
||||
- Keith Ledbetter
|
||||
- BradVan der Elst
|
||||
- Andrew Pye
|
||||
- Mike Bowers
|
||||
- Randy McKenzie
|
||||
- Roberto Bravin
|
||||
- Sim Brigden
|
||||
- Alan Lautenslager
|
||||
- Martin Bafver
|
||||
- Mário André Silva
|
||||
- Anthony Kochevar
|
||||
- Gajanatha Kobbekaduwe
|
||||
- Sumner Patterson
|
||||
- Martin Bafver
|
||||
- Mário André Silva
|
||||
- Anthony Kochevar
|
||||
- Gajanatha Kobbekaduwe
|
||||
- Sumner Patterson
|
||||
- Paul - Virginia, USA
|
||||
|
||||
**Downloads (zip and tar.gz) below. These are named without version number in the folder name to make the Arduino IDE happy.**
|
||||
|
||||
[CommandStation-EX.zip](https://github.com/DCC-EX/CommandStation-EX/releases/download/v3.1.0-Prod/CommandStation-EX.zip)
|
||||
[CommandStation-EX.tar.gz](https://github.com/DCC-EX/CommandStation-EX/releases/download/v3.1.0-Prod/CommandStation-EX.tar.gz)
|
||||
|
16
version.h
16
version.h
@@ -3,7 +3,21 @@
|
||||
|
||||
#include "StringFormatter.h"
|
||||
|
||||
#define VERSION "3.0.11"
|
||||
|
||||
#define VERSION "3.1.7"
|
||||
// 3.1.7 Bugfix: Unknown locos should have speed forward
|
||||
// 3.1.6 Make output ID two bytes and guess format/size of registered outputs found in EEPROM
|
||||
// 3.1.5 Fix LCD corruption on power-up
|
||||
// 3.1.4 Refactor OLED and LCD drivers and remove unused code
|
||||
// 3.1.3 Add a loop delay to give more time for sensing an Ethernet cable connection
|
||||
// 3.1.2 Eliminate wait after write when prog is joined or prog power is off
|
||||
// 3.1.1 SH1106 OLED Display Offset Fix
|
||||
// 3.0.16 Ignore CV1 bit 7 read rejected by decoder when identifying loco id.
|
||||
// 3.0.15 only send function commands once, not 4 times
|
||||
// 3.0.14 gap in ack tolerant fix, prog track power management over join fix.
|
||||
// 3.0.13 Functions>127 fix
|
||||
// 3.0.12 Fix HOSTNAME function for STA mode for WiFi
|
||||
// 3.0.11 28 speedstep support
|
||||
// 3.0.10 Teensy Support
|
||||
// 3.0.9 rearranges serial newlines for the benefit of JMRI.
|
||||
// 3.0.8 Includes <* *> wraps around DIAGs for the benefit of JMRI.
|
||||
|
Reference in New Issue
Block a user