From 2bc67678dc0be68d8224f45a19dad41019cfb4fa Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 25 Aug 2020 17:48:51 +0200 Subject: [PATCH 01/11] Show current platform while running unittests --- exe/arduino_ci_remote.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exe/arduino_ci_remote.rb b/exe/arduino_ci_remote.rb index 12ab224e..5241eb72 100755 --- a/exe/arduino_ci_remote.rb +++ b/exe/arduino_ci_remote.rb @@ -227,7 +227,7 @@ def perform_unit_tests(file_config) config.allowable_unittest_files(cpp_library.test_files).each do |unittest_path| unittest_name = unittest_path.basename.to_s compilers.each do |gcc_binary| - attempt_multiline("Unit testing #{unittest_name} with #{gcc_binary}") do + attempt_multiline("Unit testing #{unittest_name} with #{gcc_binary} for #{p}") do exe = cpp_library.build_for_test_with_configuration( unittest_path, config.aux_libraries_for_unittest, From 90dc7476111ca90f248836a68597a3d18360ac91 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 25 Aug 2020 17:57:23 +0200 Subject: [PATCH 02/11] Make SPI.h work on non-AVR unittests The SPI library contains some code to read the SPCR register to determine the byte order of 16-bit transfers, presumably because there is no official Arduino API to set it, so sketches had to rely on setting this register directly. By reading it, the SPI unittest implementation can detect how to emulate multibyte transfers. However, this register is only defined by avr/io.h when the unittest emulates an AVR platform, so this code would fail to compile on other platforms. This adds a preprocessor guard around this code, defaulting to the lsb-first, which is also the hardware and Arduino default. This fixes #140. --- cpp/arduino/SPI.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cpp/arduino/SPI.h b/cpp/arduino/SPI.h index f10cd201..e22be357 100644 --- a/cpp/arduino/SPI.h +++ b/cpp/arduino/SPI.h @@ -94,10 +94,14 @@ class SPIClass: public ObservableDataStream { uint16_t transfer16(uint16_t data) { union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out; in.val = data; + #if defined(SPCR) && defined(DORD) if (!(SPCR & (1 << DORD))) { out.msb = transfer(in.msb); out.lsb = transfer(in.lsb); - } else { + } + else + #endif + { out.lsb = transfer(in.lsb); out.msb = transfer(in.msb); } From ec1de7efc282f1695cd18aaaea25053c160b4640 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 26 Aug 2020 10:49:43 +0200 Subject: [PATCH 03/11] Do not include SPI/Wire from Arduino.h This is not done on a regular Arduino either, so this needlessly pollutes the namespace and might cause issues in some rare cases. This also changes one testcase that uses SPI to include SPI.h, since it previously relied on Arduino.h to do so. --- SampleProjects/TestSomething/test/godmode.cpp | 1 + cpp/arduino/Arduino.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/SampleProjects/TestSomething/test/godmode.cpp b/SampleProjects/TestSomething/test/godmode.cpp index e6c69502..15c13f3c 100644 --- a/SampleProjects/TestSomething/test/godmode.cpp +++ b/SampleProjects/TestSomething/test/godmode.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "fibonacciClock.h" GodmodeState* state = GODMODE(); diff --git a/cpp/arduino/Arduino.h b/cpp/arduino/Arduino.h index e107126e..4cec73ad 100644 --- a/cpp/arduino/Arduino.h +++ b/cpp/arduino/Arduino.h @@ -14,8 +14,6 @@ Where possible, variable names from the Arduino library are used to avoid confli #include "Print.h" #include "Stream.h" #include "HardwareSerial.h" -#include "SPI.h" -#include "Wire.h" typedef bool boolean; typedef uint8_t byte; From e7a08f984bff23ef39754a8b374307448dbf8cba Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 25 Aug 2020 20:38:51 +0200 Subject: [PATCH 04/11] Complete and fix defines for various boards This adds relevant defines that identify the architecture and board currently compiled for. Most of these are usually set by the platform's platform.txt and boards.txt, except for the __AVR* defines that are set by avr-gcc internally. This only adds extra defines, except for the Arduino Due, which previously incorrectly identified as an ATmega328p. This seems to fix part of #89. --- misc/default.yml | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/misc/default.yml b/misc/default.yml index 67d7f87f..9fa60041 100644 --- a/misc/default.yml +++ b/misc/default.yml @@ -22,7 +22,10 @@ platforms: gcc: features: defines: + - __AVR__ - __AVR_ATmega328P__ + - ARDUINO_ARCH_AVR + - ARDUINO_AVR_UNO warnings: flags: due: @@ -31,7 +34,9 @@ platforms: gcc: features: defines: - - __AVR_ATmega328__ + - __SAM3X8E__ + - ARDUINO_ARCH_SAM + - ARDUINO_SAM_DUE warnings: flags: zero: @@ -40,8 +45,9 @@ platforms: gcc: features: defines: - - __SAMD21G18A__ - - ARDUINO_SAMD_ZERO + - __SAMD21G18A__ + - ARDUINO_ARCH_SAMD + - ARDUINO_SAMD_ZERO warnings: flags: esp32: @@ -50,6 +56,9 @@ platforms: gcc: features: defines: + - ESP32 + - ARDUINO_ARCH_ESP32 + - ARDUINO_FEATHER_ESP32 warnings: flags: esp8266: @@ -58,6 +67,9 @@ platforms: gcc: features: defines: + - ESP8266 + - ARDUINO_ARCH_ESP8266 + - ARDUINO_ESP8266_ESP12 warnings: flags: leonardo: @@ -66,7 +78,10 @@ platforms: gcc: features: defines: + - __AVR__ - __AVR_ATmega32U4__ + - ARDUINO_ARCH_AVR + - ARDUINO_AVR_LEONARDO warnings: flags: trinket: @@ -75,6 +90,10 @@ platforms: gcc: features: defines: + - __AVR__ + - __AVR_ATtiny85__ + - ARDUINO_ARCH_AVR + - ARDUINO_AVR_TRINKET5 warnings: flags: gemma: @@ -83,6 +102,10 @@ platforms: gcc: features: defines: + - __AVR__ + - __AVR_ATtiny85__ + - ARDUINO_ARCH_AVR + - ARDUINO_AVR_GEMMA warnings: flags: m4: @@ -91,6 +114,10 @@ platforms: gcc: features: defines: + - __SAMD51__ + - __SAMD51J19A__ + - ARDUINO_ARCH_SAMD + - ARDUINO_METRO_M4 warnings: flags: mega2560: @@ -99,7 +126,10 @@ platforms: gcc: features: defines: + - __AVR__ - __AVR_ATmega2560__ + - ARDUINO_ARCH_AVR + - ARDUINO_AVR_MEGA2560 warnings: flags: cplayClassic: @@ -108,6 +138,10 @@ platforms: gcc: features: defines: + - __AVR__ + - __AVR_ATmega32U4__ + - ARDUINO_ARCH_AVR + - ARDUINO_AVR_CIRCUITPLAY warnings: flags: cplayExpress: @@ -116,6 +150,9 @@ platforms: gcc: features: defines: + - __SAMD21G18A__ + - ARDUINO_ARCH_SAMD + - ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS warnings: flags: From 545d609712c30a63d20c3289120f9c26753e30d4 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 26 Aug 2020 11:18:41 +0200 Subject: [PATCH 05/11] Only include avr/io.h if __AVR__ is defined When this file is included, but no MCU type (e.g. `__AVR_ATmega328p__`) is defined, a warning is generated and only a partial set of AVR-specific macros is defined. When using a non-AVR target, no warning should be generated and none of these AVR-specific macros shoudl be made available, so this only includes avr/io.h from `Godmode.h` when `__AVR__` is defined, and do not include it from `avr/pgmspace.h` at all, since it is not actually needed there. This introduces a small compatibility issue: Until recently, `__AVR__` was never defined when running unittests. All included boards now do so, but if anyone has defined custom AVR boards without defining `__AVR__` in their `.arduino-ci.yaml` file, those would no longer work. This is easy enough to fix, though, just add the `__AVR__` define. --- cpp/arduino/Godmode.h | 2 ++ cpp/arduino/avr/pgmspace.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/arduino/Godmode.h b/cpp/arduino/Godmode.h index 12fa1b51..925054d8 100644 --- a/cpp/arduino/Godmode.h +++ b/cpp/arduino/Godmode.h @@ -1,6 +1,8 @@ #pragma once #include "ArduinoDefines.h" +#if defined(__AVR__) #include +#endif #include "WString.h" #include "PinHistory.h" diff --git a/cpp/arduino/avr/pgmspace.h b/cpp/arduino/avr/pgmspace.h index 6b21287b..725eef73 100644 --- a/cpp/arduino/avr/pgmspace.h +++ b/cpp/arduino/avr/pgmspace.h @@ -14,7 +14,6 @@ out = externs.map {|l| l.split("(")[0].split(" ")[-1].gsub("*", "") }.uniq out.each { |l| puts d(l) } */ -#include #include #define PROGMEM From 13d55eeb1befc8bf69c1c584d02a7db4fc1eb69b Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 26 Aug 2020 11:00:58 +0200 Subject: [PATCH 06/11] Allow specifying NUM_SERIAL_PORTS explicitly For AVR-based unittests, this was autodetected based on the registers defined in `avr/io.h`, just like on an actual build. For non-AVR targets, `NUM_SERIAL_PORTS` would always be 0. Now, any existing define on the compiler commandline (i.e. from `.arduino-ci.yaml`) takes precedence over any autodetected value. --- cpp/arduino/Godmode.h | 22 ++++++++++++---------- cpp/arduino/HardwareSerial.h | 8 ++++---- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/cpp/arduino/Godmode.h b/cpp/arduino/Godmode.h index 925054d8..6887769b 100644 --- a/cpp/arduino/Godmode.h +++ b/cpp/arduino/Godmode.h @@ -20,16 +20,18 @@ unsigned long micros(); #define MOCK_PINS_COUNT 256 -#if defined(UBRR3H) - #define NUM_SERIAL_PORTS 4 -#elif defined(UBRR2H) - #define NUM_SERIAL_PORTS 3 -#elif defined(UBRR1H) - #define NUM_SERIAL_PORTS 2 -#elif defined(UBRRH) || defined(UBRR0H) - #define NUM_SERIAL_PORTS 1 -#else - #define NUM_SERIAL_PORTS 0 +#if (!defined NUM_SERIAL_PORTS) + #if defined(UBRR3H) + #define NUM_SERIAL_PORTS 4 + #elif defined(UBRR2H) + #define NUM_SERIAL_PORTS 3 + #elif defined(UBRR1H) + #define NUM_SERIAL_PORTS 2 + #elif defined(UBRRH) || defined(UBRR0H) + #define NUM_SERIAL_PORTS 1 + #else + #define NUM_SERIAL_PORTS 0 + #endif #endif class GodmodeState { diff --git a/cpp/arduino/HardwareSerial.h b/cpp/arduino/HardwareSerial.h index d4ea97f9..68c2010c 100644 --- a/cpp/arduino/HardwareSerial.h +++ b/cpp/arduino/HardwareSerial.h @@ -44,19 +44,19 @@ class HardwareSerial : public StreamTape operator bool() { return true; } }; -#if defined(UBRRH) || defined(UBRR0H) +#if NUM_SERIAL_PORTS >= 1 extern HardwareSerial Serial; #define HAVE_HWSERIAL0 #endif -#if defined(UBRR1H) +#if NUM_SERIAL_PORTS >= 2 extern HardwareSerial Serial1; #define HAVE_HWSERIAL1 #endif -#if defined(UBRR2H) +#if NUM_SERIAL_PORTS >= 3 extern HardwareSerial Serial2; #define HAVE_HWSERIAL2 #endif -#if defined(UBRR3H) +#if NUM_SERIAL_PORTS >= 4 extern HardwareSerial Serial3; #define HAVE_HWSERIAL3 #endif From 819b9e560be6698f47edd990c1d0ca59b38c41ff Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 26 Aug 2020 11:16:12 +0200 Subject: [PATCH 07/11] Specify NUM_SERIAL_PORTS for non-AVR targets For AVR-targets, this value is autodetected based on the MCU type, but for other targets it must be explicitly specified. --- misc/default.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/misc/default.yml b/misc/default.yml index 9fa60041..1bef2e27 100644 --- a/misc/default.yml +++ b/misc/default.yml @@ -37,6 +37,7 @@ platforms: - __SAM3X8E__ - ARDUINO_ARCH_SAM - ARDUINO_SAM_DUE + - NUM_SERIAL_PORTS=4 warnings: flags: zero: @@ -48,6 +49,8 @@ platforms: - __SAMD21G18A__ - ARDUINO_ARCH_SAMD - ARDUINO_SAMD_ZERO + # This also has SerialUSB, which is not included here. + - NUM_SERIAL_PORTS=2 warnings: flags: esp32: @@ -59,6 +62,7 @@ platforms: - ESP32 - ARDUINO_ARCH_ESP32 - ARDUINO_FEATHER_ESP32 + - NUM_SERIAL_PORTS=3 warnings: flags: esp8266: @@ -70,6 +74,7 @@ platforms: - ESP8266 - ARDUINO_ARCH_ESP8266 - ARDUINO_ESP8266_ESP12 + - NUM_SERIAL_PORTS=2 warnings: flags: leonardo: @@ -118,6 +123,8 @@ platforms: - __SAMD51J19A__ - ARDUINO_ARCH_SAMD - ARDUINO_METRO_M4 + # Serial is actually USB virtual serial, not HardwareSerial + - NUM_SERIAL_PORTS=2 warnings: flags: mega2560: @@ -153,6 +160,8 @@ platforms: - __SAMD21G18A__ - ARDUINO_ARCH_SAMD - ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS + # Serial is actually an alias of SerialUSB, not a HardwareSerial + - NUM_SERIAL_PORTS=2 warnings: flags: From 36b4d8c0bb685ab8cb44677316e001cf1076161c Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 26 Aug 2020 10:30:44 +0200 Subject: [PATCH 08/11] Fix pgm_read_ptr_near/far This was missing one level of pointer indirection, making any use of these functions fail at compiletime. --- cpp/arduino/avr/pgmspace.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/arduino/avr/pgmspace.h b/cpp/arduino/avr/pgmspace.h index 725eef73..b3b5a319 100644 --- a/cpp/arduino/avr/pgmspace.h +++ b/cpp/arduino/avr/pgmspace.h @@ -33,13 +33,13 @@ out.each { |l| puts d(l) } #define pgm_read_word_near(address_short) (* (const uint16_t *) (address_short) ) #define pgm_read_dword_near(address_short) (* (const uint32_t *) (address_short) ) #define pgm_read_float_near(address_short) (* (const float *) (address_short) ) -#define pgm_read_ptr_near(address_short) (* (const void *) (address_short) ) +#define pgm_read_ptr_near(address_short) (* (const void **) (address_short) ) #define pgm_read_byte_far(address_long) (* (const uint8_t *) (address_long) ) #define pgm_read_word_far(address_long) (* (const uint16_t *) (address_long) ) #define pgm_read_dword_far(address_long) (* (const uint32_t *) (address_long) ) #define pgm_read_float_far(address_long) (* (const float *) (address_long) ) -#define pgm_read_ptr_far(address_long) (* (const void *) (address_long) ) +#define pgm_read_ptr_far(address_long) (* (const void **) (address_long) ) #define pgm_read_byte(address_short) pgm_read_byte_near(address_short) #define pgm_read_word(address_short) pgm_read_word_near(address_short) From 9e9d15437fb39cf629cbb59e984d79f4081af00e Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 26 Aug 2020 10:23:36 +0200 Subject: [PATCH 09/11] Replace _P macros with inline functions Previously, functions like memcpy_P were replaced by their non-progmem version using macros. However, these macros added a :: prefix, presumably to allow e.g. memcpy_P to be used in a context where a (namespace or class) local version of memcpy is defined. Adding the :: makes sure the global version is used. However, if the actual invocation of e.g. memcpy_P also uses this prefix (e.g. `return ::memcpy_P(...)`, to disambiguate when a local version of `memcpy_P` is also defined), this results in a double prefix and compilation failure. To fix this, this commit replaces the wrapper macros with inline functions that call the non-progmem version normally. These inline functions were mostly mechanically generated from the original avr/pgmspace.h documentation, removing some AVR-specific functions that do not have a standard equivalent and adding som casts here and there (where the progmem version returns `char*` and the regular version `const char*`). --- cpp/arduino/avr/pgmspace.h | 93 ++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/cpp/arduino/avr/pgmspace.h b/cpp/arduino/avr/pgmspace.h index b3b5a319..5225363c 100644 --- a/cpp/arduino/avr/pgmspace.h +++ b/cpp/arduino/avr/pgmspace.h @@ -15,6 +15,7 @@ out.each { |l| puts d(l) } */ #include +#include #define PROGMEM @@ -26,6 +27,11 @@ out.each { |l| puts d(l) } #define PGM_VOID_P const void * #endif +// These are normally 32-bit, but here use (u)intptr_t to ensure a pointer can +// always be safely cast to these types. +typedef intptr_t int_farptr_t; +typedef uintptr_t uint_farptr_t; + // everything's a no-op #define PSTR(s) ((const char *)(s)) @@ -49,46 +55,47 @@ out.each { |l| puts d(l) } #define pgm_get_far_address(var) ( (uint_farptr_t) (&(var)) ) -#define memchr_P(...) ::memchr(__VA_ARGS__) -#define memcmp_P(...) ::memcmp(__VA_ARGS__) -#define memccpy_P(...) ::memccpy(__VA_ARGS__) -#define memcpy_P(...) ::memcpy(__VA_ARGS__) -#define memmem_P(...) ::memmem(__VA_ARGS__) -#define memrchr_P(...) ::memrchr(__VA_ARGS__) -#define strcat_P(...) ::strcat(__VA_ARGS__) -#define strchr_P(...) ::strchr(__VA_ARGS__) -#define strchrnul_P(...) ::strchrnul(__VA_ARGS__) -#define strcmp_P(...) ::strcmp(__VA_ARGS__) -#define strcpy_P(...) ::strcpy(__VA_ARGS__) -#define strcasecmp_P(...) ::strcasecmp(__VA_ARGS__) -#define strcasestr_P(...) ::strcasestr(__VA_ARGS__) -#define strcspn_P(...) ::strcspn(__VA_ARGS__) -#define strlcat_P(...) ::strlcat(__VA_ARGS__) -#define strlcpy_P(...) ::strlcpy(__VA_ARGS__) -#define strnlen_P(...) ::strnlen(__VA_ARGS__) -#define strncmp_P(...) ::strncmp(__VA_ARGS__) -#define strncasecmp_P(...) ::strncasecmp(__VA_ARGS__) -#define strncat_P(...) ::strncat(__VA_ARGS__) -#define strncpy_P(...) ::strncpy(__VA_ARGS__) -#define strpbrk_P(...) ::strpbrk(__VA_ARGS__) -#define strrchr_P(...) ::strrchr(__VA_ARGS__) -#define strsep_P(...) ::strsep(__VA_ARGS__) -#define strspn_P(...) ::strspn(__VA_ARGS__) -#define strstr_P(...) ::strstr(__VA_ARGS__) -#define strtok_P(...) ::strtok(__VA_ARGS__) -#define strtok_P(...) ::strtok(__VA_ARGS__) -#define strlen_P(...) ::strlen(__VA_ARGS__) -#define strnlen_P(...) ::strnlen(__VA_ARGS__) -#define memcpy_P(...) ::memcpy(__VA_ARGS__) -#define strcpy_P(...) ::strcpy(__VA_ARGS__) -#define strncpy_P(...) ::strncpy(__VA_ARGS__) -#define strcat_P(...) ::strcat(__VA_ARGS__) -#define strlcat_P(...) ::strlcat(__VA_ARGS__) -#define strncat_P(...) ::strncat(__VA_ARGS__) -#define strcmp_P(...) ::strcmp(__VA_ARGS__) -#define strncmp_P(...) ::strncmp(__VA_ARGS__) -#define strcasecmp_P(...) ::strcasecmp(__VA_ARGS__) -#define strncasecmp_P(...) ::strncasecmp(__VA_ARGS__) -#define strstr_P(...) ::strstr(__VA_ARGS__) -#define strlcpy_P(...) ::strlcpy(__VA_ARGS__) -#define memcmp_P(...) ::memcmp(__VA_ARGS__) +inline const void * memchr_P(const void *s, int val, size_t len) { return memchr(s, val, len); } +inline int memcmp_P(const void *s1, const void *s2, size_t len) { return memcmp(s1, s2, len); } +inline void *memccpy_P(void *dest, const void *src, int val, size_t len) { return memccpy(dest, src, val, len); } +inline void *memcpy_P(void *dest, const void *src, size_t n) { return memcpy(dest, src, n); } +inline void *memmem_P(const void *s1, size_t len1, const void *s2, size_t len2) { return memmem(s1, len1, s2, len2); } +inline const void *memrchr_P(const void *src, int val, size_t len) { return memrchr(src, val, len); } +inline char *strcat_P(char *dest, const char *src) { return strcat(dest, src); } +inline const char *strchr_P(const char *s, int val) { return strchr(s, val); } +inline const char *strchrnul_P(const char *s, int c) { return strchrnul(s, c); } +inline int strcmp_P(const char *s1, const char *s2) { return strcmp(s1, s2); } +inline char *strcpy_P(char *dest, const char *src) { return strcpy(dest, src); } +inline int strcasecmp_P(const char *s1, const char *s2) { return strcasecmp(s1, s2); } +inline char *strcasestr_P(const char *s1, const char *s2) { return (char*)strcasestr(s1, s2); } +inline size_t strcspn_P(const char *s, const char *reject) { return strcspn(s, reject); } +// strlcat and strlcpy are AVR-specific and not entirely trivial to reimplement using strncat it seems +//inline size_t strlcat_P(char *dst, const char *src, size_t siz) { return strlcat(dst, src, siz); } +//inline size_t strlcpy_P(char *dst, const char *src, size_t siz) { return strlcpy(dst, src, siz); } +//inline size_t strlcat_PF(char *dst, uint_farptr_t src, size_t n) { return strlcat(dst, (const char*)src, n); } +//inline size_t strlcpy_PF(char *dst, uint_farptr_t src, size_t siz) { return strlcpy(dst, (const char*)src, siz); } +inline int strncmp_P(const char *s1, const char *s2, size_t n) { return strncmp(s1, s2, n); } +inline int strncasecmp_P(const char *s1, const char *s2, size_t n) { return strncasecmp(s1, s2, n); } +inline char *strncat_P(char *dest, const char *src, size_t len) { return strncat(dest, src, len); } +inline char *strncpy_P(char *dest, const char *src, size_t n) { return strncpy(dest, src, n); } +inline char *strpbrk_P(const char *s, const char *accept) { return (char*)strpbrk(s, accept); } +inline const char *strrchr_P(const char *s, int val) { return strrchr(s, val); } +inline char *strsep_P(char **sp, const char *delim) { return strsep(sp, delim); } +inline size_t strspn_P(const char *s, const char *accept) { return strspn(s, accept); } +inline char *strstr_P(const char *s1, const char *s2) { return (char*)strstr(s1, s2); } +inline char *strtok_P(char *s, const char * delim) { return strtok(s, delim); } +inline char *strtok_r_P(char *string, const char *delim, char **last) { return strtok_r(string, delim, last); } +inline size_t strlen_PF(uint_farptr_t s) { return strlen((char*)s); } +inline size_t strnlen_P(uint_farptr_t s, size_t len) { return strnlen((char*)s, len); } +inline void *memcpy_PF(void *dest, uint_farptr_t src, size_t n) { return memcpy(dest, (const char*)src, n); } +inline char *strcpy_PF(char *dst, uint_farptr_t src) { return strcpy(dst, (const char*)src); } +inline char *strncpy_PF(char *dst, uint_farptr_t src, size_t n) { return strncpy(dst, (const char*)src, n); } +inline char *strcat_PF(char *dst, uint_farptr_t src) { return strcat(dst, (const char*)src); } +inline char *strncat_PF(char *dst, uint_farptr_t src, size_t n) { return strncat(dst, (const char*)src, n); } +inline int strcmp_PF(const char *s1, uint_farptr_t s2) { return strcmp(s1, (const char*)s2); } +inline int strncmp_PF(const char *s1, uint_farptr_t s2, size_t n) { return strncmp(s1, (const char*)s2, n); } +inline int strcasecmp_PF(const char *s1, uint_farptr_t s2) { return strcasecmp(s1, (const char*)s2); } +inline int strncasecmp_PF(const char *s1, uint_farptr_t s2, size_t n) { return strncasecmp(s1, (const char*)s2, n); } +inline char *strstr_PF(const char *s1, uint_farptr_t s2) { return (char*)strstr(s1, (const char*)s2); } +inline int memcmp_PF(const void *s1, uint_farptr_t s2, size_t len) { return memcmp(s1, (const char*)s2, len); } +inline size_t strlen_P(const char *src) { return strlen(src); } From fdfa1340566dd3225ad96e828b0cced7f42d0660 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 26 Aug 2020 10:30:11 +0200 Subject: [PATCH 10/11] Mock stdio.h progmem functions --- cpp/arduino/avr/pgmspace.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/cpp/arduino/avr/pgmspace.h b/cpp/arduino/avr/pgmspace.h index 5225363c..eb7050ad 100644 --- a/cpp/arduino/avr/pgmspace.h +++ b/cpp/arduino/avr/pgmspace.h @@ -15,7 +15,9 @@ out.each { |l| puts d(l) } */ #include +#include #include +#include #define PROGMEM @@ -99,3 +101,21 @@ inline int strncasecmp_PF(const char *s1, uint_farptr_t s2, size_t n) { return s inline char *strstr_PF(const char *s1, uint_farptr_t s2) { return (char*)strstr(s1, (const char*)s2); } inline int memcmp_PF(const void *s1, uint_farptr_t s2, size_t len) { return memcmp(s1, (const char*)s2, len); } inline size_t strlen_P(const char *src) { return strlen(src); } + +// These are normally defined by stdio.h on AVR, but we cannot override that +// include file (at least not without no longer being able to include the +// original as well), so just define these here. It seems likely that any +// sketch that uses these progmem-stdio functions will also include pgmspace.h +inline int vfprintf_P(FILE *stream, const char *__fmt, va_list __ap) { return vfprintf(stream, __fmt, __ap); } +inline int printf_P(const char *__fmt, ...) { va_list args; va_start(args, __fmt); return vprintf(__fmt, args); va_end(args); } +inline int sprintf_P(char *s, const char *__fmt, ...) { va_list args; va_start(args, __fmt); return sprintf(s, __fmt, args); va_end(args); } +inline int snprintf_P(char *s, size_t __n, const char *__fmt, ...) { va_list args; va_start(args, __fmt); return vsnprintf(s, __n, __fmt, args); va_end(args); } +inline int vsprintf_P(char *s, const char *__fmt, va_list ap) { return vsprintf(s, __fmt, ap); } +inline int vsnprintf_P(char *s, size_t __n, const char *__fmt, va_list ap) { return vsnprintf(s, __n, __fmt, ap); } +inline int fprintf_P(FILE *stream, const char *__fmt, ...) { va_list args; va_start(args, __fmt); return vfprintf(stream, __fmt, args); va_end(args); } +inline int fputs_P(const char *str, FILE *__stream) { return fputs(str, __stream); } +inline int puts_P(const char *str) { return puts(str); } +inline int vfscanf_P(FILE *stream, const char *__fmt, va_list __ap) { return vfscanf(stream, __fmt, __ap); } +inline int fscanf_P(FILE *stream, const char *__fmt, ...) { va_list args; va_start(args, __fmt); return vfscanf(stream, __fmt, args); va_end(args); } +inline int scanf_P(const char *__fmt, ...) { va_list args; va_start(args, __fmt); return vscanf(__fmt, args); va_end(args); } +inline int sscanf_P(const char *buf, const char *__fmt, ...) { va_list args; va_start(args, __fmt); return vsscanf(buf, __fmt, args); va_end(args); } From a8b73e6cad641f3bca9fa691140b2a78c9891646 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 6 Nov 2020 12:09:21 +0100 Subject: [PATCH 11/11] Remove some functions from pgmspace.h that break on cygwin Somehow, these functions cannot be found when compiling the test build under cygwin, even though it seems they should be available. To at least allow the rest of the fixes in this series to be merged, disable these functions for now. Since these are mostly uncommon functions that are unlikely to be used in actual Arduino code, this should probably not cause much problems for now. --- cpp/arduino/avr/pgmspace.h | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/cpp/arduino/avr/pgmspace.h b/cpp/arduino/avr/pgmspace.h index eb7050ad..cab19057 100644 --- a/cpp/arduino/avr/pgmspace.h +++ b/cpp/arduino/avr/pgmspace.h @@ -59,17 +59,11 @@ typedef uintptr_t uint_farptr_t; inline const void * memchr_P(const void *s, int val, size_t len) { return memchr(s, val, len); } inline int memcmp_P(const void *s1, const void *s2, size_t len) { return memcmp(s1, s2, len); } -inline void *memccpy_P(void *dest, const void *src, int val, size_t len) { return memccpy(dest, src, val, len); } inline void *memcpy_P(void *dest, const void *src, size_t n) { return memcpy(dest, src, n); } -inline void *memmem_P(const void *s1, size_t len1, const void *s2, size_t len2) { return memmem(s1, len1, s2, len2); } -inline const void *memrchr_P(const void *src, int val, size_t len) { return memrchr(src, val, len); } inline char *strcat_P(char *dest, const char *src) { return strcat(dest, src); } inline const char *strchr_P(const char *s, int val) { return strchr(s, val); } -inline const char *strchrnul_P(const char *s, int c) { return strchrnul(s, c); } inline int strcmp_P(const char *s1, const char *s2) { return strcmp(s1, s2); } inline char *strcpy_P(char *dest, const char *src) { return strcpy(dest, src); } -inline int strcasecmp_P(const char *s1, const char *s2) { return strcasecmp(s1, s2); } -inline char *strcasestr_P(const char *s1, const char *s2) { return (char*)strcasestr(s1, s2); } inline size_t strcspn_P(const char *s, const char *reject) { return strcspn(s, reject); } // strlcat and strlcpy are AVR-specific and not entirely trivial to reimplement using strncat it seems //inline size_t strlcat_P(char *dst, const char *src, size_t siz) { return strlcat(dst, src, siz); } @@ -77,18 +71,14 @@ inline size_t strcspn_P(const char *s, const char *reject) { return strcspn(s, r //inline size_t strlcat_PF(char *dst, uint_farptr_t src, size_t n) { return strlcat(dst, (const char*)src, n); } //inline size_t strlcpy_PF(char *dst, uint_farptr_t src, size_t siz) { return strlcpy(dst, (const char*)src, siz); } inline int strncmp_P(const char *s1, const char *s2, size_t n) { return strncmp(s1, s2, n); } -inline int strncasecmp_P(const char *s1, const char *s2, size_t n) { return strncasecmp(s1, s2, n); } inline char *strncat_P(char *dest, const char *src, size_t len) { return strncat(dest, src, len); } inline char *strncpy_P(char *dest, const char *src, size_t n) { return strncpy(dest, src, n); } inline char *strpbrk_P(const char *s, const char *accept) { return (char*)strpbrk(s, accept); } inline const char *strrchr_P(const char *s, int val) { return strrchr(s, val); } -inline char *strsep_P(char **sp, const char *delim) { return strsep(sp, delim); } inline size_t strspn_P(const char *s, const char *accept) { return strspn(s, accept); } inline char *strstr_P(const char *s1, const char *s2) { return (char*)strstr(s1, s2); } inline char *strtok_P(char *s, const char * delim) { return strtok(s, delim); } -inline char *strtok_r_P(char *string, const char *delim, char **last) { return strtok_r(string, delim, last); } inline size_t strlen_PF(uint_farptr_t s) { return strlen((char*)s); } -inline size_t strnlen_P(uint_farptr_t s, size_t len) { return strnlen((char*)s, len); } inline void *memcpy_PF(void *dest, uint_farptr_t src, size_t n) { return memcpy(dest, (const char*)src, n); } inline char *strcpy_PF(char *dst, uint_farptr_t src) { return strcpy(dst, (const char*)src); } inline char *strncpy_PF(char *dst, uint_farptr_t src, size_t n) { return strncpy(dst, (const char*)src, n); } @@ -96,12 +86,26 @@ inline char *strcat_PF(char *dst, uint_farptr_t src) { return strcat(dst, (const inline char *strncat_PF(char *dst, uint_farptr_t src, size_t n) { return strncat(dst, (const char*)src, n); } inline int strcmp_PF(const char *s1, uint_farptr_t s2) { return strcmp(s1, (const char*)s2); } inline int strncmp_PF(const char *s1, uint_farptr_t s2, size_t n) { return strncmp(s1, (const char*)s2, n); } -inline int strcasecmp_PF(const char *s1, uint_farptr_t s2) { return strcasecmp(s1, (const char*)s2); } -inline int strncasecmp_PF(const char *s1, uint_farptr_t s2, size_t n) { return strncasecmp(s1, (const char*)s2, n); } inline char *strstr_PF(const char *s1, uint_farptr_t s2) { return (char*)strstr(s1, (const char*)s2); } inline int memcmp_PF(const void *s1, uint_farptr_t s2, size_t len) { return memcmp(s1, (const char*)s2, len); } inline size_t strlen_P(const char *src) { return strlen(src); } +// TODO: These functions cannot be found on the CYGWIN test build for +// some reason, so disable them for now. Most of these are less common +// and/or GNU-specific addons anyway +//inline void *memccpy_P(void *dest, const void *src, int val, size_t len) { return memccpy(dest, src, val, len); } +//inline void *memmem_P(const void *s1, size_t len1, const void *s2, size_t len2) { return memmem(s1, len1, s2, len2); } +//inline const void *memrchr_P(const void *src, int val, size_t len) { return memrchr(src, val, len); } +//inline const char *strchrnul_P(const char *s, int c) { return strchrnul(s, c); } +//inline int strcasecmp_P(const char *s1, const char *s2) { return strcasecmp(s1, s2); } +//inline char *strcasestr_P(const char *s1, const char *s2) { return (char*)strcasestr(s1, s2); } +//inline int strncasecmp_P(const char *s1, const char *s2, size_t n) { return strncasecmp(s1, s2, n); } +//inline char *strsep_P(char **sp, const char *delim) { return strsep(sp, delim); } +//inline char *strtok_r_P(char *string, const char *delim, char **last) { return strtok_r(string, delim, last); } +//inline int strcasecmp_PF(const char *s1, uint_farptr_t s2) { return strcasecmp(s1, (const char*)s2); } +//inline int strncasecmp_PF(const char *s1, uint_farptr_t s2, size_t n) { return strncasecmp(s1, (const char*)s2, n); } +//inline size_t strnlen_P(uint_farptr_t s, size_t len) { return strnlen((char*)s, len); } + // These are normally defined by stdio.h on AVR, but we cannot override that // include file (at least not without no longer being able to include the // original as well), so just define these here. It seems likely that any