diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 21a9d3d..5342c6d 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -41,6 +41,14 @@ #include "DCCTimer.h" #include "EXRAIL2.h" +// This macro can't be created easily as a portable function because the +// flashlist requires a far pointer for high flash access. +#define SENDFLASHLIST(stream,flashList) \ + for (int16_t i=0;;i+=sizeof(flashList[0])) { \ + int16_t value=GETHIGHFLASHW(flashList,i); \ + if (value==0) break; \ + StringFormatter::send(stream,F(" %d"),value); \ + } // These keywords are used in the <1> command. The number is what you get if you use the keyword as a parameter. @@ -568,8 +576,8 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) StringFormatter::send(stream, F(" #ifdef EXRAIL_ACTIVE - sendFlashList(stream,RMFT2::routeIdList); - sendFlashList(stream,RMFT2::automationIdList); + SENDFLASHLIST(stream,RMFT2::routeIdList) + SENDFLASHLIST(stream,RMFT2::automationIdList) #endif } else { // @@ -588,7 +596,9 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) case HASH_KEYWORD_R: // returns rosters StringFormatter::send(stream, F("\n")); } -void DCCEXParser::sendFlashList(Print * stream,const int16_t flashList[]) { - for (int16_t i=0;;i++) { - int16_t value=GETFLASHW(flashList+i); - if (value==0) return; - StringFormatter::send(stream,F(" %d"),value); - } -} - bool DCCEXParser::parseZ(Print *stream, int16_t params, int16_t p[]) { diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp index 9095de8..9809f28 100644 --- a/EXRAIL2.cpp +++ b/EXRAIL2.cpp @@ -91,8 +91,10 @@ LookList * RMFT2::onRedLookup=NULL; LookList * RMFT2::onAmberLookup=NULL; LookList * RMFT2::onGreenLookup=NULL; -#define GET_OPCODE GETFLASH(RMFT2::RouteCode+progCounter) -#define GET_OPERAND(n) GETFLASHW(RMFT2::RouteCode+progCounter+1+(n*3)) + + +#define GET_OPCODE GETHIGHFLASH(RMFT2::RouteCode,progCounter) +#define GET_OPERAND(n) GETHIGHFLASHW(RMFT2::RouteCode,progCounter+1+(n*3)) #define SKIPOP progCounter+=3 @@ -141,6 +143,8 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) { } /* static */ void RMFT2::begin() { + bool saved_diag=diag; + diag=true; DCCEXParser::setRMFTFilter(RMFT2::ComandFilter); for (int f=0;fsetHidden(GETFLASH(getTurnoutDescription(t->getId()))==0x01); } char RMFT2::getRouteType(int16_t id) { - for (int16_t i=0;;i++) { - int16_t rid= GETFLASHW(routeIdList+i); + for (int16_t i=0;;i+=2) { + int16_t rid= GETHIGHFLASHW(routeIdList,i); if (rid==id) return 'R'; if (rid==0) break; } - for (int16_t i=0;;i++) { - int16_t rid= GETFLASHW(automationIdList+i); + for (int16_t i=0;;i+=2) { + int16_t rid= GETHIGHFLASHW(automationIdList,i); if (rid==id) return 'A'; if (rid==0) break; } @@ -304,7 +310,7 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) { // do the signals // flags[n] represents the state of the nth signal in the table for (int sigslot=0;;sigslot++) { - VPIN sigid=GETFLASHW(RMFT2::SignalDefinitions+sigslot*4); + VPIN sigid=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigslot*8); if (sigid==0) break; // end of signal list byte flag=flags[sigslot] & SIGNAL_MASK; // obtain signal flags for this id StringFormatter::send(stream,F("\n%S[%d]"), @@ -982,8 +988,8 @@ void RMFT2::kill(const FSH * reason, int operand) { } int16_t RMFT2::getSignalSlot(int16_t id) { - for (int sigpos=0;;sigpos+=4) { - int16_t sigid=GETFLASHW(RMFT2::SignalDefinitions+sigpos); + for (int sigslot=0;;sigslot++) { + int16_t sigid=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigslot*8); if (sigid==0) { // end of signal list DIAG(F("EXRAIL Signal %d not defined"), id); return -1; @@ -993,9 +999,10 @@ int16_t RMFT2::getSignalSlot(int16_t id) { // but for a servo signal it will also have SERVO_SIGNAL_FLAG set. if ((sigid & SIGNAL_ID_MASK)!= id) continue; // keep looking - return sigpos/4; // relative slot in signals table + return sigslot; // relative slot in signals table } } + /* static */ void RMFT2::doSignal(int16_t id,char rag) { if (diag) DIAG(F(" doSignal %d %x"),id,rag); @@ -1012,11 +1019,11 @@ int16_t RMFT2::getSignalSlot(int16_t id) { setFlag(sigslot,rag,SIGNAL_MASK); // Correct signal definition found, get the rag values - int16_t sigpos=sigslot*4; - VPIN sigid=GETFLASHW(RMFT2::SignalDefinitions+sigpos); - VPIN redpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+1); - VPIN amberpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+2); - VPIN greenpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+3); + int16_t sigpos=sigslot*8; + VPIN sigid=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos); + VPIN redpin=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+2); + VPIN amberpin=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+4); + VPIN greenpin=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+6); if (diag) DIAG(F("signal %d %d %d %d %d"),sigid,id,redpin,amberpin,greenpin); VPIN sigtype=sigid & ~SIGNAL_ID_MASK; diff --git a/EXRAIL2.h b/EXRAIL2.h index 323ae57..d20ca4b 100644 --- a/EXRAIL2.h +++ b/EXRAIL2.h @@ -114,9 +114,9 @@ class LookList { // Throttle Info Access functions built by exrail macros static const byte rosterNameCount; - static const int16_t FLASH routeIdList[]; - static const int16_t FLASH automationIdList[]; - static const int16_t FLASH rosterIdList[]; + static const int16_t HIGHFLASH routeIdList[]; + static const int16_t HIGHFLASH automationIdList[]; + static const int16_t HIGHFLASH rosterIdList[]; static const FSH * getRouteDescription(int16_t id); static char getRouteType(int16_t id); static const FSH * getTurnoutDescription(int16_t id); @@ -150,8 +150,8 @@ private: void printMessage2(const FSH * msg); static bool diag; - static const FLASH byte RouteCode[]; - static const FLASH int16_t SignalDefinitions[]; + static const HIGHFLASH byte RouteCode[]; + static const HIGHFLASH int16_t SignalDefinitions[]; static byte flags[MAX_FLAGS]; static LookList * sequenceLookup; static LookList * onThrowLookup; diff --git a/EXRAILMacros.h b/EXRAILMacros.h index d5424c6..5d893c9 100644 --- a/EXRAILMacros.h +++ b/EXRAILMacros.h @@ -73,14 +73,14 @@ void exrailHalSetup() { #include "EXRAIL2MacroReset.h" #undef ROUTE #define ROUTE(id, description) id, -const int16_t FLASH RMFT2::routeIdList[]= { +const int16_t HIGHFLASH RMFT2::routeIdList[]= { #include "myAutomation.h" 0}; // Pass 2a create throttle automation list #include "EXRAIL2MacroReset.h" #undef AUTOMATION #define AUTOMATION(id, description) id, -const int16_t FLASH RMFT2::automationIdList[]= { +const int16_t HIGHFLASH RMFT2::automationIdList[]= { #include "myAutomation.h" 0}; @@ -158,7 +158,7 @@ const byte RMFT2::rosterNameCount=0 #include "EXRAIL2MacroReset.h" #undef ROSTER #define ROSTER(cabid,name,funcmap...) cabid, -const int16_t FLASH RMFT2::rosterIdList[]={ +const int16_t HIGHFLASH RMFT2::rosterIdList[]={ #include "myAutomation.h" 0}; @@ -198,7 +198,7 @@ const FSH * RMFT2::getRosterFunctions(int16_t id) { #undef VIRTUAL_SIGNAL #define VIRTUAL_SIGNAL(id) id,0,0,0, -const FLASH int16_t RMFT2::SignalDefinitions[] = { +const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = { #include "myAutomation.h" 0,0,0,0 }; @@ -323,7 +323,7 @@ const FLASH int16_t RMFT2::SignalDefinitions[] = { // Build RouteCode const int StringMacroTracker2=__COUNTER__; -const FLASH byte RMFT2::RouteCode[] = { +const HIGHFLASH byte RMFT2::RouteCode[] = { #include "myAutomation.h" OPCODE_ENDTASK,0,0,OPCODE_ENDEXRAIL,0,0 }; diff --git a/FSH.h b/FSH.h index ea54554..0b39c5c 100644 --- a/FSH.h +++ b/FSH.h @@ -34,32 +34,48 @@ * PROGMEM use FLASH instead * pgm_read_byte_near use GETFLASH instead. * pgm_read_word_near use GETFLASHW instead. + * + * Also: + * HIGHFLASH - PROGMEM forced to end of link so needs far pointers. + * GETHIGHFLASH,GETHIGHFLASHW to access them * */ #include -#if defined(ARDUINO_ARCH_MEGAAVR) +#ifdef ARDUINO_ARCH_AVR +// AVR devices have flash memory mapped differently +// progmem can be accessed by _near functions +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) +#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)) +#endif + +#else +// Non-AVR Flat-memory devices have no need of this support so can be remapped to normal memory access #ifdef F #undef F #endif #define F(str) (str) typedef char FSH; -#define GETFLASH(addr) (*(const unsigned char *)(addr)) -#define GETFLASHW(addr) (*(const unsigned short *)(addr)) #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 -#elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32) -typedef __FlashStringHelper FSH; -#define GETFLASH(addr) pgm_read_byte(addr) -#define GETFLASHW(addr) (*(const unsigned int8_t *)(addr)) | ((*(const unsigned int8_t *)(addr+1)) << 8) -#ifdef FLASH - #undef FLASH -#endif -#define FLASH PROGMEM -#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 +#endif \ No newline at end of file diff --git a/WiThrottle.cpp b/WiThrottle.cpp index 3df56db..a7b94b0 100644 --- a/WiThrottle.cpp +++ b/WiThrottle.cpp @@ -216,8 +216,8 @@ void WiThrottle::parse(RingStream * stream, byte * cmdx) { StringFormatter::send(stream,F("PRT]\\[Routes}|{Route]\\[Set}|{2]\\[Handoff}|{4\nPRL")); for (byte pass=0;pass<2;pass++) { // first pass automations, second pass routes. - for (int ix=0;;ix++) { - int16_t id=GETFLASHW((pass?RMFT2::automationIdList:RMFT2::routeIdList)+ix); + for (int ix=0;;ix+=2) { + int16_t id=GETHIGHFLASHW((pass?RMFT2::automationIdList:RMFT2::routeIdList),ix); if (id==0) break; const FSH * desc=RMFT2::getRouteDescription(id); StringFormatter::send(stream,F("]\\[%c%d}|{%S}|{%c"), @@ -297,8 +297,8 @@ void WiThrottle::parse(RingStream * stream, byte * cmdx) { StringFormatter::send(stream,F("PPA%x\n"),TrackManager::getMainPower()==POWERMODE::ON); #ifdef EXRAIL_ACTIVE StringFormatter::send(stream,F("RL%d"), RMFT2::rosterNameCount); - for (int16_t r=0;r