From 7840c24e21435dc20881eb5d29f21ee48845173b Mon Sep 17 00:00:00 2001 From: Asbelos Date: Tue, 22 Nov 2022 09:21:23 +0000 Subject: [PATCH] More EXRAIL mem clean --- EXRAIL2.cpp | 91 ++++++++++++++++++++++++++++++++++------------------- EXRAIL2.h | 6 +++- FSH.h | 26 +++++++-------- 3 files changed, 76 insertions(+), 47 deletions(-) diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp index 3565c80..072fb5b 100644 --- a/EXRAIL2.cpp +++ b/EXRAIL2.cpp @@ -92,12 +92,35 @@ LookList * RMFT2::onRedLookup=NULL; LookList * RMFT2::onAmberLookup=NULL; LookList * RMFT2::onGreenLookup=NULL; - - #define GET_OPCODE GETHIGHFLASH(RMFT2::RouteCode,progCounter) -#define GET_OPERAND(n) GETHIGHFLASHW(RMFT2::RouteCode,progCounter+1+(n*3)) #define SKIPOP progCounter+=3 +// RouteCodeFar is a far pointer to flash on anything other than a uno/nano where it is just a near pointer to flash +uint32_t RMFT2::RouteCodeFar; + +uint16_t RMFT2::getOperand2(uint32_t farAddr) { + #if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) + // AVR_MEGA memory uses far pointers + return pgm_read_word_far(farAddr); + #elif defined(ARDUINO_ARCH_AVR) + // UNO/NANO have no far memory + return pgm_read_word_near(farAddr); + #else + // other cpus dont care but may be averse to reading an int16_tr at an odd byte boundary. + const byte * op=farAddr; + return *op | (*(op+1) << 8); + #endif + } + +// getOperand instance version, uses progCounter from instance. +uint16_t RMFT2::getOperand(byte n) { + return getOperand(progCounter,n); +} + +// getOperand static version, must be provided prog counter from loop etc. +uint16_t RMFT2::getOperand(int progCounter,byte n) { + return getOperand2(RouteCodeFar+progCounter+1+(n*3)); +} LookList::LookList(int16_t size) { m_size=size; @@ -138,18 +161,16 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) { for (progCounter=0;; SKIPOP) { byte opcode=GET_OPCODE; if (opcode==OPCODE_ENDEXRAIL) break; - if (opcode==op1 || opcode==op2 || opcode==op3) list->add(GET_OPERAND(0),progCounter); + if (opcode==op1 || opcode==op2 || opcode==op3) list->add(getOperand(progCounter,0),progCounter); } return list; } /* static */ void RMFT2::begin() { - #if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) - // AVR_MEGA memory position for diagnostic only - DIAG(F("EXRAIL RouteAddr=%l"),pgm_get_far_address(RMFT2::RouteCode)); - #endif - + RouteCodeFar=GETFARPTR(RMFT2::RouteCode); + DIAG(F("EXRAIL RouteAddr=%l"),RouteCodeFar); + bool saved_diag=diag; diag=true; DCCEXParser::setRMFTFilter(RMFT2::ComandFilter); @@ -177,7 +198,7 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) { for (progCounter=0;; SKIPOP){ byte opcode=GET_OPCODE; if (opcode==OPCODE_ENDEXRAIL) break; - VPIN operand=GET_OPERAND(0); + VPIN operand=getOperand(progCounter,0); switch (opcode) { case OPCODE_AT: @@ -202,25 +223,25 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) { case OPCODE_TURNOUT: { VPIN id=operand; - int addr=GET_OPERAND(1); - byte subAddr=GET_OPERAND(2); + int addr=getOperand(progCounter,1); + byte subAddr=getOperand(progCounter,2); setTurnoutHiddenState(DCCTurnout::create(id,addr,subAddr)); break; } case OPCODE_SERVOTURNOUT: { VPIN id=operand; - VPIN pin=GET_OPERAND(1); - int activeAngle=GET_OPERAND(2); - int inactiveAngle=GET_OPERAND(3); - int profile=GET_OPERAND(4); + VPIN pin=getOperand(progCounter,1); + int activeAngle=getOperand(progCounter,2); + int inactiveAngle=getOperand(progCounter,3); + int profile=getOperand(progCounter,4); setTurnoutHiddenState(ServoTurnout::create(id,pin,activeAngle,inactiveAngle,profile)); break; } case OPCODE_PINTURNOUT: { VPIN id=operand; - VPIN pin=GET_OPERAND(1); + VPIN pin=getOperand(progCounter,1); setTurnoutHiddenState(VpinTurnout::create(id,pin)); break; } @@ -564,7 +585,7 @@ void RMFT2::loop2() { if (delayTime!=0 && millis()-delayStart < delayTime) return; byte opcode = GET_OPCODE; - int16_t operand = GET_OPERAND(0); + int16_t operand = getOperand(0); // skipIf will get set to indicate a failing IF condition bool skipIf=false; @@ -630,13 +651,13 @@ void RMFT2::loop2() { case OPCODE_ATGTE: // wait for analog sensor>= value timeoutFlag=false; - if (IODevice::readAnalogue(operand) >= (int)(GET_OPERAND(1))) break; + if (IODevice::readAnalogue(operand) >= (int)(getOperand(1))) break; delayMe(50); return; case OPCODE_ATLT: // wait for analog sensor < value timeoutFlag=false; - if (IODevice::readAnalogue(operand) < (int)(GET_OPERAND(1))) break; + if (IODevice::readAnalogue(operand) < (int)(getOperand(1))) break; delayMe(50); return; @@ -647,7 +668,7 @@ void RMFT2::loop2() { case OPCODE_ATTIMEOUT2: if (readSensor(operand)) break; // success without timeout - if (millis()-timeoutStart > 100*GET_OPERAND(1)) { + if (millis()-timeoutStart > 100*getOperand(1)) { timeoutFlag=true; break; // and drop through } @@ -690,7 +711,7 @@ void RMFT2::loop2() { break; case OPCODE_POM: - if (loco) DCC::writeCVByteMain(loco, operand, GET_OPERAND(1)); + if (loco) DCC::writeCVByteMain(loco, operand, getOperand(1)); break; case OPCODE_POWEROFF: @@ -724,11 +745,11 @@ void RMFT2::loop2() { break; case OPCODE_IFGTE: // do next operand if sensor>= value - skipIf=IODevice::readAnalogue(operand)<(int)(GET_OPERAND(1)); + skipIf=IODevice::readAnalogue(operand)<(int)(getOperand(1)); break; case OPCODE_IFLT: // do next operand if sensor< value - skipIf=IODevice::readAnalogue(operand)>=(int)(GET_OPERAND(1)); + skipIf=IODevice::readAnalogue(operand)>=(int)(getOperand(1)); break; case OPCODE_IFNOT: // do next operand if sensor not set @@ -811,11 +832,11 @@ void RMFT2::loop2() { } case OPCODE_XFON: - DCC::setFn(operand,GET_OPERAND(1),true); + DCC::setFn(operand,getOperand(1),true); break; case OPCODE_XFOFF: - DCC::setFn(operand,GET_OPERAND(1),false); + DCC::setFn(operand,getOperand(1),false); break; case OPCODE_DCCACTIVATE: { @@ -907,7 +928,7 @@ void RMFT2::loop2() { case OPCODE_SENDLOCO: // cab, route { - int newPc=sequenceLookup->find(GET_OPERAND(1)); + int newPc=sequenceLookup->find(getOperand(1)); if (newPc<0) break; RMFT2* newtask=new RMFT2(newPc); // create new task newtask->loco=operand; @@ -925,7 +946,7 @@ void RMFT2::loop2() { case OPCODE_SERVO: // OPCODE_SERVO,V(vpin),OPCODE_PAD,V(position),OPCODE_PAD,V(profile),OPCODE_PAD,V(duration) - IODevice::writeAnalogue(operand,GET_OPERAND(1),GET_OPERAND(2),GET_OPERAND(3)); + IODevice::writeAnalogue(operand,getOperand(1),getOperand(2),getOperand(3)); break; case OPCODE_WAITFOR: // OPCODE_SERVO,V(pin) @@ -1139,19 +1160,23 @@ void RMFT2::thrungeString(uint32_t strfar, thrunger mode, byte id) { } if (!stream) return; + #if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) // if mega stream it out for (;;strfar++) { char c=pgm_read_byte_far(strfar); if (c=='\0') break; stream->write(c); } - // else other CPUs - // stream.print((FSH *)strfar) - + #else + // UNO/NANO CPUs dont have high memory + // 32 bit cpus dont care anyway + stream.print((FSH *)strfar) + #endif + // and decide what to do next switch (mode) { case thrunge_print: - StringFormatter::send(&Serial,F(" *>/n")); + StringFormatter::send(&Serial,F(" *>\n")); break; // TODO more serials for SAMx case thrunge_serial4: stream=&Serial4; break; case thrunge_parse: @@ -1161,7 +1186,7 @@ void RMFT2::thrungeString(uint32_t strfar, thrunger mode, byte id) { // TODO CommandDistributor::broadcastText(buffer->getString()); break; case thrunge_lcd: - LCD(id,F("%s%"),buffer->getString()); + LCD(id,F("%s"),buffer->getString()); break; default: break; diff --git a/EXRAIL2.h b/EXRAIL2.h index 8d8223b..61d128f 100644 --- a/EXRAIL2.h +++ b/EXRAIL2.h @@ -141,6 +141,8 @@ private: static LookList* LookListLoader(OPCODE op1, OPCODE op2=OPCODE_ENDEXRAIL,OPCODE op3=OPCODE_ENDEXRAIL); static void handleEvent(const FSH* reason,LookList* handlers, int16_t id); + static uint16_t getOperand(int progCounter,byte n); + static uint16_t getOperand2(uint32_t farAddr); static RMFT2 * loopTask; static RMFT2 * pausingTask; void delayMe(long millisecs); @@ -153,6 +155,7 @@ private: void printMessage(uint16_t id); // Built by RMFTMacros.h void printMessage2(const FSH * msg); void thrungeString(uint32_t strfar, thrunger mode, byte id=0); + uint16_t getOperand(byte n); static bool diag; static const HIGHFLASH byte RouteCode[]; @@ -166,7 +169,8 @@ private: static LookList * onRedLookup; static LookList * onAmberLookup; static LookList * onGreenLookup; - + // RouteCodeFar is a far pointer to RouteCode flash on anything other than a uno/nano where it is just a near pointer to flash + static uint32_t RouteCodeFar; // Local variables - exist for each instance/task RMFT2 *next; // loop chain diff --git a/FSH.h b/FSH.h index aa0516a..fd1df6d 100644 --- a/FSH.h +++ b/FSH.h @@ -43,23 +43,25 @@ #include #ifdef ARDUINO_ARCH_AVR // AVR devices have flash memory mapped differently -// progmem can be accessed by _near functions +// progmem can be accessed by _near functions or _far typedef __FlashStringHelper FSH; #define FLASH PROGMEM #define GETFLASH(addr) pgm_read_byte_near(addr) -#define GETFLASHW(addr) pgm_read_word_near(addr) + #if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) // AVR_MEGA memory deliberately placed at end of link may need _far functions #define HIGHFLASH __attribute__((section(".fini2"))) -#define GETHIGHFLASH(data,offset) pgm_read_byte_far(pgm_get_far_address(data)+offset) -#define GETHIGHFLASHW(data,offset) pgm_read_word_far(pgm_get_far_address(data)+offset) +#define GETFARPTR(data) pgm_get_far_address(data) +#define GETHIGHFLASH(data,offset) pgm_read_byte_far(GETFARPTR(data)+offset) +#define GETHIGHFLASHW(data,offset) pgm_read_word_far(GETFARPTR(data)+offset) #else // AVR_UNO/NANO runtime does not support _far functions so just use _near equivalent // as there is no progmem above 32kb anyway. -#define HIGHFLASH FLASH -#define GETHIGHFLASH(data,offset) pgm_read_byte_near(((byte*)data)+(offset)) -#define GETHIGHFLASHW(data,offset) pgm_read_word_near(((byte*)data)+(offset)) +#define HIGHFLASH PROGMEM +#define GETFARPTR(data) ((const byte *)(data)) +#define GETHIGHFLASH(data,offset) pgm_read_byte_near(GETFARPTR(data)+(offset)) +#define GETHIGHFLASHW(data,offset) pgm_read_word_near(GETFARPTR(data)+(offset)) #endif #else @@ -71,11 +73,9 @@ typedef __FlashStringHelper FSH; typedef char FSH; #define FLASH #define HIGHFLASH -#define GETFLASH(addr) (*(const unsigned char *)(addr)) -#define GETFLASHW(addr) ((*(const unsigned int8_t *)(addr)) | ((*(const unsigned int8_t *)(addr+1)) << 8)) -#define GETHIGHFLASH(data,offset) GETFLASH(((byte*)data)+(offset)) -#define GETHIGHFLASHW(data,offset) GETFLASHW(((byte*)data)+(offset)) -//#define strlen_P strlen -//#define strcpy_P strcpy +#define GETFARPTR(data) ((const byte *)(data)) +#define GETFLASH(addr) (*(const byte *)(addr)) +#define GETHIGHFLASH(data,offset) (*(const byte *)(GETFARPTR(data)+offset)) +#define GETHIGHFLASHW(data,offset) (*(const uint16_t *)(GETFARPTR(data)+offset)) #endif #endif \ No newline at end of file