Using latest git and arduino IDE.
I use PROGMEM strings and a debug define that places debug messages into progmem, however this does not seem to work when combined with templated classes.
The error is the same as this issue: https://github.com/esp8266/Arduino/issues/2078
i define my debug as
#define DEBUG(_1, ...) { TEST.printf_P( PSTR(_1) ,##__VA_ARGS__); }
and a const char as
const char testString[] PROGMEM = "Test String";
Individually they both compile. i.e. if the debug define is enabled but i do not use testString. it works, and vice versa. but if i use both
In file included from /Users/amelvin/Documents/Arduino/templatesketch/templatesketch.ino:2:0:
test.h:7: error: testString causes a section type conflict with __c
const char testString[] PROGMEM = "Test String";
^
In file included from /Applications/Arduino.app/Contents/Java/hardware/esp8266com/esp8266/cores/esp8266/Arduino.h:240:0,
from /var/folders/nv/8j3v5v0s18v7p4249kv8qbz80000gq/T/arduino_build_216642/sketch/templatesketch.ino.cpp:1:
/Applications/Arduino.app/Contents/Java/hardware/esp8266com/esp8266/cores/esp8266/pgmspace.h:21:51: note: '__c' was declared here
#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];}))
^
/var/folders/nv/8j3v5v0s18v7p4249kv8qbz80000gq/T/arduino_build_216642/sketch/test.h:11:41: note: in expansion of macro 'PSTR'
#define DEBUG(_1, ...) { TEST.printf_P( PSTR(_1) ,##__VA_ARGS__); }
^
/var/folders/nv/8j3v5v0s18v7p4249kv8qbz80000gq/T/arduino_build_216642/sketch/test.hpp:5:3: note: in expansion of macro 'DEBUG'
DEBUG("abc");
^
exit status 1
testString causes a section type conflict with __c
A full working example can be found here
https://gist.github.com/sticilface/9a6410978d7235a469c1e154c1c4c396
I found the first one, but I'm not sure i follow. As long as i don't use the debug define it works. so it can link even when the progmem is used inside a templated class. or is that where the second one enters the picture and you can't use PROGMEM and FPSTR inside same file?
Ok got it to work. Need to move the implementation of the PROGMEM string from the .h file to a .cpp file, and extern it in the header. Then it compiles fine.
in .h:
namespace ESPmanagerinternals {
extern const char key_networks[];
}
in .cpp
const char ESPmanagerinternals::key_networks[] PROGMEM = "networks";
I have recently encountered this problem and I may have a solution. 馃槃
The background of my issue is that, I have been using custom debug logging macros, something like:
DEBUG_LOG("Blah blah %d ...", ValueX);
I have so many of them and the string literals starts to eat up the RAM, obviously transit to PROGMEM is the solution.
And I want to leverage on my use of logging macro to reduce the effort, by converting:
#define DEBUG_LOG(...) Serial.printf(__VA_ARGS__)
to
#define DEBUG_LOG(fmt, ...) \
{ static const char pfmt[] PROGMEM = fmt; Serial.printf_P(pfmt, ## __VA_ARGS__); }
And I encountered the infamous error "pfmt causes a section type conflict with pfmt", because I have debug logs in both "regular" functions and template functions.
The solution of extracting each and every log string into a global static variable is not acceptable to me - not only too much transitional effort, but also increase the maintenance overhead and reduce the usability. (Imagine the scenario you see a debug log line, and wants to look at the relevant code. With inline string you just do a single search. With extracted variable, you first find the variable, and you have to search the variable name again to locate the source...)
The post here gave me an idea of the root cause, and then I dug out "eagle.app.v6.common.ld" with an interesting line:
.irom0.text : ALIGN(4)
{
...
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text .irom.text.*)
...
}
The .irom.text.* gave me an idea:
PROGMEM translates to ICACHE_RODATA_ATTR translates to __attribute__((section(".irom.text"))).irom.text.template to hold all flash strings from template code?.irom.text.* specificationSo I tried the following:
#define PROGMEM_T __attribute__((section(".irom.text.template")))
#define DEBUG_LOG_T(fmt, ...) \
{ static const char pfmt[] PROGMEM_T = fmt; Serial.printf_P(pfmt, ## __VA_ARGS__); }
And for all debug log states in template method I switched from:
DEBUG_LOG("Blah blah %d ...", ValueX);
to
DEBUG_LOG_T("Blah blah %d ...", ValueX);
And the code compiles and runs perfectly fine! 馃槅
It is still a little more work than just changing the macro, but with a reasonable cost, at least it allows to use inline flash string in log statements.
Most helpful comment
I have recently encountered this problem and I may have a solution. 馃槃
Background
The background of my issue is that, I have been using custom debug logging macros, something like:
I have so many of them and the string literals starts to eat up the RAM, obviously transit to PROGMEM is the solution.
And I want to leverage on my use of logging macro to reduce the effort, by converting:
to
And I encountered the infamous error "pfmt causes a section type conflict with pfmt", because I have debug logs in both "regular" functions and template functions.
The solution of extracting each and every log string into a global static variable is not acceptable to me - not only too much transitional effort, but also increase the maintenance overhead and reduce the usability. (Imagine the scenario you see a debug log line, and wants to look at the relevant code. With inline string you just do a single search. With extracted variable, you first find the variable, and you have to search the variable name again to locate the source...)
Reasoning
The post here gave me an idea of the root cause, and then I dug out "eagle.app.v6.common.ld" with an interesting line:
The
.irom.text.*gave me an idea:PROGMEMtranslates toICACHE_RODATA_ATTRtranslates to__attribute__((section(".irom.text"))).irom.text.templateto hold all flash strings from template code?.irom.text.*specificationSolution
So I tried the following:
And for all debug log states in template method I switched from:
to
And the code compiles and runs perfectly fine! 馃槅
It is still a little more work than just changing the macro, but with a reasonable cost, at least it allows to use inline flash string in log statements.