diff --git a/.github/workflows/c-cpp-cmake.yml b/.github/workflows/c-cpp-cmake.yml new file mode 100644 index 0000000..66a5cda --- /dev/null +++ b/.github/workflows/c-cpp-cmake.yml @@ -0,0 +1,17 @@ +name: C/C++ CI + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: build.sh + run: ./build.sh \ No newline at end of file diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 0000000..b7c9311 --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,54 @@ +name: Unit Tests + +on: + pull_request: + # Only run workflow if a file in these paths is modified + paths: + - ".github/workflows/unit-tests.yml" + - "ArduinoCore-API/test/**" + - "ArduinoCore-API/api/**" + + push: + paths: + - ".github/workflows/unit-tests.yml" + - "ArduinoCore-API/test/**" + - "ArduinoCore-API/api/**" + +jobs: + test: + name: Run unit tests + runs-on: ubuntu-latest + + env: + COVERAGE_DATA_PATH: extras/coverage-data/coverage.info + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Relax some warings + # run: echo 'add_compile_options(-Wno-unused-function)' >> ArduinoCore-API/test/CMakeLists.txt + # run: echo 'add_compile_options(-Wno-error=all)' >> ArduinoCore-API/test/CMakeLists.txt + # run: echo 'add_compile_options(-Wno-error=unused-function)' >> ArduinoCore-API/test/CMakeLists.txt + run: sed -i 's/-Werror//g' ArduinoCore-API/test/CMakeLists.txt + + + # See: https://github.com/arduino/cpp-test-action/blob/main/README.md + - uses: arduino/cpp-test-action@main + with: + source-path: ArduinoCore-API/test + build-path: ArduinoCore-API/test/build + runtime-path: ArduinoCore-API/test/build/bin/test-ArduinoCore-API + coverage-exclude-paths: | + - '*/test/*' + - '/usr/*' + coverage-data-path: ${{ env.COVERAGE_DATA_PATH }} + + # Temporary excluded to prevent token requirement + # See: https://github.com/codecov/codecov-action/blob/master/README.md + #- name: Code coverage + # uses: codecov/codecov-action@v3 + # with: + # token: ${{ secrets.CODECOV_TOKEN }} + # files: ${{ env.COVERAGE_DATA_PATH }} + # fail_ci_if_error: true \ No newline at end of file diff --git a/.gitignore b/.gitignore index 62d8fa5..28566d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -/build -.* +build/ +.vscode + diff --git a/ArduinoCore-API/api/ArduinoAPI.h b/ArduinoCore-API/api/ArduinoAPI.h index 72bab93..a7d8c0b 100644 --- a/ArduinoCore-API/api/ArduinoAPI.h +++ b/ArduinoCore-API/api/ArduinoAPI.h @@ -9,7 +9,7 @@ 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 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public @@ -20,8 +20,8 @@ #ifndef ARDUINO_API_H #define ARDUINO_API_H -// version 1.2.0 -#define ARDUINO_API_VERSION 10200 +// version 1.5.2 +#define ARDUINO_API_VERSION 10502 #include "Binary.h" @@ -32,7 +32,7 @@ #include "Printable.h" #include "PluggableUSB.h" #include "Server.h" -#include "WString.h" +#include "String.h" #include "Stream.h" #include "Udp.h" #include "USBAPI.h" @@ -46,9 +46,10 @@ #include #include -#ifdef __cplusplus // Misc Arduino core functions #include "Common.h" + +#ifdef __cplusplus // Compatibility layer for older code #include "Compat.h" #endif diff --git a/ArduinoCore-API/api/CanMsg.cpp b/ArduinoCore-API/api/CanMsg.cpp new file mode 100644 index 0000000..f4f93ce --- /dev/null +++ b/ArduinoCore-API/api/CanMsg.cpp @@ -0,0 +1,46 @@ +/* + CanMsg.cpp - Library for CAN message handling + Copyright (c) 2023 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "CanMsg.h" + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +namespace arduino +{ + +/************************************************************************************** + * STATIC CONST DEFINITION + **************************************************************************************/ + +uint8_t const CanMsg::MAX_DATA_LENGTH; +uint32_t const CanMsg::CAN_EFF_FLAG; +uint32_t const CanMsg::CAN_SFF_MASK; +uint32_t const CanMsg::CAN_EFF_MASK; + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +} /* arduino */ diff --git a/ArduinoCore-API/api/CanMsg.h b/ArduinoCore-API/api/CanMsg.h new file mode 100644 index 0000000..a8e32e5 --- /dev/null +++ b/ArduinoCore-API/api/CanMsg.h @@ -0,0 +1,156 @@ +/* + CanMsg.h - Library for CAN message handling + Copyright (c) 2023 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARDUINOCORE_API_CAN_MSG_H_ +#define ARDUINOCORE_API_CAN_MSG_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include +#include + +#include "Print.h" +#include "Printable.h" +#include "Common.h" + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +namespace arduino +{ + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class CanMsg : public Printable +{ +public: + static uint8_t constexpr MAX_DATA_LENGTH = 8; + + static uint32_t constexpr CAN_EFF_FLAG = 0x80000000U; + static uint32_t constexpr CAN_SFF_MASK = 0x000007FFU; /* standard frame format (SFF) */ + static uint32_t constexpr CAN_EFF_MASK = 0x1FFFFFFFU; /* extended frame format (EFF) */ + + + CanMsg(uint32_t const can_id, uint8_t const can_data_len, uint8_t const * can_data_ptr) + : id{can_id} + , data_length{min(can_data_len, MAX_DATA_LENGTH)} + , data{0} + { + if (data_length && can_data_ptr) + memcpy(data, can_data_ptr, data_length); + } + + CanMsg() : CanMsg(0, 0, nullptr) { } + + CanMsg(CanMsg const & other) + { + id = other.id; + data_length = other.data_length; + if (data_length > 0) + memcpy(data, other.data, data_length); + } + + virtual ~CanMsg() { } + + CanMsg & operator = (CanMsg const & other) + { + if (this != &other) + { + id = other.id; + data_length = other.data_length; + if (data_length > 0) + memcpy(data, other.data, data_length); + } + return (*this); + } + + virtual size_t printTo(Print & p) const override + { + char buf[20] = {0}; + size_t len = 0; + + /* Print the header. */ + if (isStandardId()) + len = snprintf(buf, sizeof(buf), "[%03" PRIX32 "] (%d) : ", getStandardId(), data_length); + else + len = snprintf(buf, sizeof(buf), "[%08" PRIX32 "] (%d) : ", getExtendedId(), data_length); + size_t n = p.write(buf, len); + + /* Print the data. */ + for (size_t d = 0; d < data_length; d++) + { + len = snprintf(buf, sizeof(buf), "%02X", data[d]); + n += p.write(buf, len); + } + + /* Wrap up. */ + return n; + } + + + uint32_t getStandardId() const { + return (id & CAN_SFF_MASK); + } + uint32_t getExtendedId() const { + return (id & CAN_EFF_MASK); + } + bool isStandardId() const { + return ((id & CAN_EFF_FLAG) == 0); + } + bool isExtendedId() const { + return ((id & CAN_EFF_FLAG) == CAN_EFF_FLAG); + } + + + /* + * CAN ID semantics (mirroring definition by linux/can.h): + * |- Bit 31 : frame format flag (0 = standard 11 bit, 1 = extended 29 bit) + * |- Bit 30 : reserved (future remote transmission request flag) + * |- Bit 29 : reserved (future error frame flag) + * |- Bit 0-28 : CAN identifier (11/29 bit) + */ + uint32_t id; + uint8_t data_length; + uint8_t data[MAX_DATA_LENGTH]; +}; + +/************************************************************************************** + * FREE FUNCTIONS + **************************************************************************************/ + +inline uint32_t CanStandardId(uint32_t const id) { + return (id & CanMsg::CAN_SFF_MASK); +} + +inline uint32_t CanExtendedId(uint32_t const id) { + return (CanMsg::CAN_EFF_FLAG | (id & CanMsg::CAN_EFF_MASK)); +} + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +} /* arduino */ + +#endif /* ARDUINOCORE_API_CAN_MSG_H_ */ diff --git a/ArduinoCore-API/api/CanMsgRingbuffer.cpp b/ArduinoCore-API/api/CanMsgRingbuffer.cpp new file mode 100644 index 0000000..56abbac --- /dev/null +++ b/ArduinoCore-API/api/CanMsgRingbuffer.cpp @@ -0,0 +1,74 @@ +/* + CanMsgRingbuffer.cpp - Library for CAN message handling + Copyright (c) 2023 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "CanMsgRingbuffer.h" + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +namespace arduino +{ + +/************************************************************************************** + * CTOR/DTOR + **************************************************************************************/ + +CanMsgRingbuffer::CanMsgRingbuffer() +: _head{0} +, _tail{0} +, _num_elems{0} +{ +} + +/************************************************************************************** + * PUBLIC MEMBER FUNCTIONS + **************************************************************************************/ + +void CanMsgRingbuffer::enqueue(CanMsg const & msg) +{ + if (isFull()) + return; + + _buf[_head] = msg; + _head = next(_head); + _num_elems = _num_elems + 1; +} + +CanMsg CanMsgRingbuffer::dequeue() +{ + if (isEmpty()) + return CanMsg(); + + CanMsg const msg = _buf[_tail]; + _tail = next(_tail); + _num_elems = _num_elems - 1; + + return msg; +} + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +} /* arduino */ diff --git a/ArduinoCore-API/api/CanMsgRingbuffer.h b/ArduinoCore-API/api/CanMsgRingbuffer.h new file mode 100644 index 0000000..9eb6baf --- /dev/null +++ b/ArduinoCore-API/api/CanMsgRingbuffer.h @@ -0,0 +1,72 @@ +/* + CanMsgRingbuffer.h - Library for CAN message handling + Copyright (c) 2023 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARDUINOCORE_API_CAN_MSG_RING_BUFFER_H_ +#define ARDUINOCORE_API_CAN_MSG_RING_BUFFER_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +#include "CanMsg.h" + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +namespace arduino +{ + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class CanMsgRingbuffer +{ +public: + static size_t constexpr RING_BUFFER_SIZE = 32U; + + CanMsgRingbuffer(); + + inline bool isFull() const { return (_num_elems == RING_BUFFER_SIZE); } + void enqueue(CanMsg const & msg); + + inline bool isEmpty() const { return (_num_elems == 0); } + CanMsg dequeue(); + + inline size_t available() const { return _num_elems; } + +private: + CanMsg _buf[RING_BUFFER_SIZE]; + volatile size_t _head; + volatile size_t _tail; + volatile size_t _num_elems; + + inline size_t next(size_t const idx) const { return ((idx + 1) % RING_BUFFER_SIZE); } +}; + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +} /* arduino */ + +#endif /* ARDUINOCORE_API_CAN_MSG_RING_BUFFER_H_ */ diff --git a/ArduinoCore-API/api/Common.cpp b/ArduinoCore-API/api/Common.cpp index 74daccb..8299247 100644 --- a/ArduinoCore-API/api/Common.cpp +++ b/ArduinoCore-API/api/Common.cpp @@ -1,7 +1,23 @@ +/* + Common.cpp - Common function implementations + Copyright (c) 2017 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + #include "Common.h" -extern "C" { - #include "stdlib.h" -} /* C++ prototypes */ long map(long x, long in_min, long in_max, long out_min, long out_max) @@ -9,30 +25,5 @@ long map(long x, long in_min, long in_max, long out_min, long out_max) return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } -// void randomSeed(unsigned long seed) -// { -// if (seed != 0) { -// srandom(seed); -// } -// } - -// long random(long howbig) -// { -// if (howbig == 0) { -// return 0; -// } -// return random() % howbig; -// } - -// long random(long howsmall, long howbig) -// { -// if (howsmall >= howbig) { -// return howsmall; -// } -// long diff = howbig - howsmall; -// return random(diff) + howsmall; -// } - - uint16_t makeWord(uint16_t w) { return w; } uint16_t makeWord(uint8_t h, uint8_t l) { return (h << 8) | l; } \ No newline at end of file diff --git a/ArduinoCore-API/api/Common.h b/ArduinoCore-API/api/Common.h index 3e5f21c..9b28f40 100644 --- a/ArduinoCore-API/api/Common.h +++ b/ArduinoCore-API/api/Common.h @@ -1,6 +1,25 @@ +/* + Common.h - Common definitions for Arduino core + Copyright (c) 2017 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + #pragma once #include -#include +#include #ifdef __cplusplus extern "C"{ @@ -17,10 +36,11 @@ typedef enum { } PinStatus; typedef enum { - INPUT = 0x0, - OUTPUT = 0x1, - INPUT_PULLUP = 0x2, - INPUT_PULLDOWN = 0x3, + INPUT = 0x0, + OUTPUT = 0x1, + INPUT_PULLUP = 0x2, + INPUT_PULLDOWN = 0x3, + OUTPUT_OPENDRAIN = 0x4, } PinMode; typedef enum { @@ -66,20 +86,16 @@ typedef void (*voidFuncPtrParam)(void*); #define bitSet(value, bit) ((value) |= (1UL << (bit))) #define bitClear(value, bit) ((value) &= ~(1UL << (bit))) #define bitToggle(value, bit) ((value) ^= (1UL << (bit))) -#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) +#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet((value), (bit)) : bitClear((value), (bit))) #ifndef bit #define bit(b) (1UL << (b)) #endif -#ifdef SKIP_LEGACY_TYPES /* TODO: request for removal */ -#else -// Keep these legacy types as they expected to be defined by Arduino.h and may be used by user code typedef bool boolean; typedef uint8_t byte; typedef uint16_t word; -#endif void init(void); void initVariant(void); @@ -90,7 +106,7 @@ int atexit(void (*func)()) __attribute__((weak)); int main() __attribute__((weak)); #ifdef EXTENDED_PIN_MODE -// Platforms who wnat to declare more than 256 pins need to define EXTENDED_PIN_MODE globally +// Platforms who want to declare more than 256 pins need to define EXTENDED_PIN_MODE globally typedef uint32_t pin_size_t; #else typedef uint8_t pin_size_t; @@ -117,10 +133,8 @@ void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus void attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback, PinStatus mode, void* param); void detachInterrupt(pin_size_t interruptNumber); -void setup(void)__attribute__((weak)); -void loop(void)__attribute__((weak)); - -long map(long, long, long, long, long); +void setup(void); +void loop(void); #ifdef __cplusplus } // extern "C" @@ -155,27 +169,9 @@ long map(long, long, long, long, long); #ifdef __cplusplus -// // WMath prototypes -// long random(long); -// long random(long, long); -// void randomSeed(unsigned long); - -static long random(long max){ - return rand() % max; -} - -static long random(long min, long max){ - long tmp = rand() % (max- min); - return tmp + min; -} - -static void randomSeed(unsigned seed){ - srand(seed); -} - /* C++ prototypes */ uint16_t makeWord(uint16_t w); -uint16_t makeWord(uint8_t h, uint8_t l); +uint16_t makeWord(byte h, byte l); #define word(...) makeWord(__VA_ARGS__) @@ -185,5 +181,10 @@ unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 10 void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0); void noTone(uint8_t _pin); +// WMath prototypes +long random(long); +long random(long, long); +void randomSeed(unsigned long); +long map(long, long, long, long, long); #endif // __cplusplus diff --git a/ArduinoCore-API/api/Compat.h b/ArduinoCore-API/api/Compat.h index a99d7d6..564170c 100644 --- a/ArduinoCore-API/api/Compat.h +++ b/ArduinoCore-API/api/Compat.h @@ -1,3 +1,22 @@ +/* + Compat.h - Compatibility layer for Arduino API + Copyright (c) 2018 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + #ifndef __COMPAT_H__ #define __COMPAT_H__ @@ -5,11 +24,11 @@ namespace arduino { inline void pinMode(pin_size_t pinNumber, int mode) { pinMode(pinNumber, (PinMode)mode); -} +}; inline void digitalWrite(pin_size_t pinNumber, int status) { digitalWrite(pinNumber, (PinStatus)status); -} +}; } diff --git a/ArduinoCore-API/api/DMAPool.h b/ArduinoCore-API/api/DMAPool.h new file mode 100644 index 0000000..815f5d3 --- /dev/null +++ b/ArduinoCore-API/api/DMAPool.h @@ -0,0 +1,316 @@ +/* + This file is part of the Arduino_AdvancedAnalog library. + Copyright (c) 2023-2024 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __DMA_POOL_H__ +#define __DMA_POOL_H__ + +#include +#include + +namespace arduino { + +#if defined(__DCACHE_PRESENT) +#define __CACHE_LINE_SIZE__ __SCB_DCACHE_LINE_SIZE +#elif defined(__cpp_lib_hardware_interference_size) +#define __CACHE_LINE_SIZE__ std::hardware_constructive_interference_size +#else // No cache. +#define __CACHE_LINE_SIZE__ alignof(int) +#endif + +// Single-producer, single-consumer, lock-free bounded Queue. +template class SPSCQueue { + private: + size_t capacity; + std::atomic head; + std::atomic tail; + std::unique_ptr buff; + + public: + SPSCQueue(size_t size=0): + capacity(0), tail(0), head(0), buff(nullptr) { + if (size) { + T *mem = new T[size + 1]; + if (mem) { + buff.reset(mem); + capacity = size + 1; + } + } + } + + void reset() { + tail = head = 0; + } + + size_t empty() { + return tail == head; + } + + operator bool() const { + return buff.get() != nullptr; + } + + bool push(T data) { + size_t curr = head.load(std::memory_order_relaxed); + size_t next = (curr + 1) % capacity; + if (!buff || (next == tail.load(std::memory_order_acquire))) { + return false; + } + buff[curr] = data; + head.store(next, std::memory_order_release); + return true; + } + + T pop(bool peek=false) { + size_t curr = tail.load(std::memory_order_relaxed); + if (!buff || (curr == head.load(std::memory_order_acquire))) { + return nullptr; + } + T data = buff[curr]; + if (!peek) { + size_t next = (curr + 1) % capacity; + tail.store(next, std::memory_order_release); + } + return data; + } +}; + +enum { + DMA_BUFFER_READ = (1 << 0), + DMA_BUFFER_WRITE = (1 << 1), + DMA_BUFFER_DISCONT = (1 << 2), + DMA_BUFFER_INTRLVD = (1 << 3), +} DMABufferFlags; + +// Forward declaration of DMAPool class. +template class DMAPool; + +template class DMABuffer { + private: + DMAPool *pool; + size_t n_samples; + size_t n_channels; + T *ptr; + uint32_t ts; + uint32_t flags; + + public: + DMABuffer(DMAPool *pool=nullptr, size_t samples=0, size_t channels=0, T *mem=nullptr): + pool(pool), n_samples(samples), n_channels(channels), ptr(mem), ts(0), flags(0) { + } + + T *data() { + return ptr; + } + + size_t size() { + return n_samples * n_channels; + } + + size_t bytes() { + return n_samples * n_channels * sizeof(T); + } + + void flush() { + #if __DCACHE_PRESENT + if (ptr) { + SCB_CleanDCache_by_Addr(data(), bytes()); + } + #endif + } + + void invalidate() { + #if __DCACHE_PRESENT + if (ptr) { + SCB_InvalidateDCache_by_Addr(data(), bytes()); + } + #endif + } + + uint32_t timestamp() { + return ts; + } + + void timestamp(uint32_t ts) { + this->ts = ts; + } + + uint32_t channels() { + return n_channels; + } + + void release() { + if (pool && ptr) { + pool->free(this, flags); + } + } + + void set_flags(uint32_t f) { + flags |= f; + } + + bool get_flags(uint32_t f=0xFFFFFFFFU) { + return flags & f; + } + + void clr_flags(uint32_t f=0xFFFFFFFFU) { + flags &= (~f); + } + + T& operator[](size_t i) { + assert(ptr && i < size()); + return ptr[i]; + } + + const T& operator[](size_t i) const { + assert(ptr && i < size()); + return ptr[i]; + } + + operator bool() const { + return (ptr != nullptr); + } +}; + +template class DMAPool { + private: + uint8_t *mem; + bool managed; + SPSCQueue*> wqueue; + SPSCQueue*> rqueue; + + // Allocates dynamic aligned memory. + // Note this memory must be free'd with aligned_free. + static void *aligned_malloc(size_t size) { + void **ptr, *stashed; + size_t offset = A - 1 + sizeof(void *); + if ((A % 2) || !((stashed = ::malloc(size + offset)))) { + return nullptr; + } + ptr = (void **) (((uintptr_t) stashed + offset) & ~(A - 1)); + ptr[-1] = stashed; + return ptr; + } + + // Frees dynamic aligned memory allocated with aligned_malloc. + static void aligned_free(void *ptr) { + if (ptr != nullptr) { + ::free(((void **) ptr)[-1]); + } + } + + public: + DMAPool(size_t n_samples, size_t n_channels, size_t n_buffers, void *mem_in=nullptr): + mem((uint8_t *) mem_in), managed(mem_in==nullptr), wqueue(n_buffers), rqueue(n_buffers) { + // Round up to the next multiple of the alignment. + size_t bufsize = (((n_samples * n_channels * sizeof(T)) + (A-1)) & ~(A-1)); + if (bufsize && rqueue && wqueue) { + if (mem == nullptr) { + // Allocate an aligned memory block for the DMA buffers' memory. + mem = (uint8_t *) aligned_malloc(n_buffers * bufsize); + if (!mem) { + // Failed to allocate memory. + return; + } + } + // Allocate the DMA buffers, initialize them using aligned + // pointers from the pool, and add them to the write queue. + for (size_t i=0; i *buf = new DMABuffer( + this, n_samples, n_channels, (T *) &mem[i * bufsize] + ); + if (buf == nullptr) { + break; + } + wqueue.push(buf); + } + } + } + + ~DMAPool() { + while (readable()) { + delete alloc(DMA_BUFFER_READ); + } + + while (writable()) { + delete alloc(DMA_BUFFER_WRITE); + } + + if (mem && managed) { + aligned_free(mem); + } + } + + bool writable() { + return !(wqueue.empty()); + } + + bool readable() { + return !(rqueue.empty()); + } + + void flush() { + while (readable()) { + DMABuffer *buf = alloc(DMA_BUFFER_READ); + if (buf) { + buf->release(); + } + } + } + + DMABuffer *alloc(uint32_t flags) { + DMABuffer *buf = nullptr; + if (flags & DMA_BUFFER_READ) { + // Get a DMA buffer from the read/ready queue. + buf = rqueue.pop(); + } else { + // Get a DMA buffer from the write/free queue. + buf = wqueue.pop(); + } + if (buf) { + buf->clr_flags(DMA_BUFFER_READ | DMA_BUFFER_WRITE); + buf->set_flags(flags); + } + return buf; + } + + void free(DMABuffer *buf, uint32_t flags=0) { + if (buf == nullptr) { + return; + } + if (flags == 0) { + flags = buf->get_flags(); + } + if (flags & DMA_BUFFER_READ) { + // Return the DMA buffer to the write/free queue. + buf->clr_flags(); + wqueue.push(buf); + } else { + // Return the DMA buffer to the read/ready queue. + rqueue.push(buf); + } + } + +}; + +} // namespace arduino + +using arduino::DMAPool; +using arduino::DMABuffer; +using arduino::SPSCQueue; +#endif //__DMA_POOL_H__ diff --git a/ArduinoCore-API/api/HardwareCAN.h b/ArduinoCore-API/api/HardwareCAN.h new file mode 100644 index 0000000..57d9d58 --- /dev/null +++ b/ArduinoCore-API/api/HardwareCAN.h @@ -0,0 +1,118 @@ +/* + HardwareCAN.h - CAN bus interface for Arduino core + Copyright (c) 2023 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARDUINOCORE_API_HARDWARECAN_H +#define ARDUINOCORE_API_HARDWARECAN_H + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "CanMsg.h" +#include "CanMsgRingbuffer.h" + +/************************************************************************************** + * TYPEDEF + **************************************************************************************/ + +enum class CanBitRate : int +{ + BR_125k = 125000, + BR_250k = 250000, + BR_500k = 500000, + BR_1000k = 1000000, +}; + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +namespace arduino +{ + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class HardwareCAN +{ +public: + virtual ~HardwareCAN() {} + + + /** + * Initialize the CAN controller. + * + * @param can_bitrate the bus bit rate + * @return true if initialization succeeded and the controller is operational + */ + virtual bool begin(CanBitRate const can_bitrate) = 0; + + /** + * Disable the CAN controller. + * + * Whether any messages that are buffered will be sent is _implementation defined_. + */ + virtual void end() = 0; + + /** + * Enqueue a message for transmission to the CAN bus. + * + * This call returns when the message has been enqueued for transmission. + * Due to bus arbitration and error recovery there may be a substantial delay + * before the message is actually sent. + * + * An implementation must ensure that all messages with the same CAN priority + * are sent in the order in which they are enqueued. + * + * It is _implementation defined_ whether multiple messages can be enqueued + * for transmission, and if messages with higher CAN priority can preempt the + * transmission of previously enqueued messages. The default configuration for + * and implementation should not allow multiple messages to be enqueued. + * + * @param msg the message to send + * @return 1 if the message was enqueued, an _implementation defined_ error code < 0 if there was an error + * @todo define specific error codes, especially "message already pending" + */ + virtual int write(CanMsg const &msg) = 0; + + /** + * Determine if any messages have been received and buffered. + * + * @return the number of unread messages that have been received + */ + virtual size_t available() = 0; + + /** + * Returns the first message received, or an empty message if none are available. + * + * Messages must be returned in the order received. + * + * @return the first message in the receive buffer + */ + virtual CanMsg read() = 0; +}; + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +} /* arduino */ + +#endif /* ARDUINOCORE_API_HARDWARECAN_H */ diff --git a/ArduinoCore-API/api/HardwareI2C.h b/ArduinoCore-API/api/HardwareI2C.h index 4a8e5f9..98c6bfd 100644 --- a/ArduinoCore-API/api/HardwareI2C.h +++ b/ArduinoCore-API/api/HardwareI2C.h @@ -1,4 +1,5 @@ /* + HardwareI2C.h - Hardware I2C interface for Arduino Copyright (c) 2016 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or @@ -8,8 +9,8 @@ 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 Lesser General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software diff --git a/ArduinoCore-API/api/HardwareSPI.h b/ArduinoCore-API/api/HardwareSPI.h index c5652c8..6be2b92 100644 --- a/ArduinoCore-API/api/HardwareSPI.h +++ b/ArduinoCore-API/api/HardwareSPI.h @@ -1,4 +1,5 @@ /* + HardwareSPI.h - Hardware SPI interface for Arduino Copyright (c) 2018 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or @@ -8,8 +9,8 @@ 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 Lesser General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software @@ -33,33 +34,42 @@ typedef enum { SPI_MODE3 = 3, } SPIMode; +// Platforms should define SPI_HAS_PERIPHERAL_MODE if SPI peripheral +// mode is supported, to allow applications to check whether peripheral +// mode is available or not. +typedef enum { + SPI_CONTROLLER = 0, + SPI_PERIPHERAL = 1, +} SPIBusMode; + class SPISettings { public: - SPISettings(uint32_t clock, BitOrder bitOrder, SPIMode dataMode) { + SPISettings(uint32_t clock, BitOrder bitOrder, SPIMode dataMode, SPIBusMode busMode = SPI_CONTROLLER) { if (__builtin_constant_p(clock)) { - init_AlwaysInline(clock, bitOrder, dataMode); + init_AlwaysInline(clock, bitOrder, dataMode, busMode); } else { - init_MightInline(clock, bitOrder, dataMode); + init_MightInline(clock, bitOrder, dataMode, busMode); } } - SPISettings(uint32_t clock, BitOrder bitOrder, int dataMode) { + SPISettings(uint32_t clock, BitOrder bitOrder, int dataMode, SPIBusMode busMode = SPI_CONTROLLER) { if (__builtin_constant_p(clock)) { - init_AlwaysInline(clock, bitOrder, (SPIMode)dataMode); + init_AlwaysInline(clock, bitOrder, (SPIMode)dataMode, busMode); } else { - init_MightInline(clock, bitOrder, (SPIMode)dataMode); + init_MightInline(clock, bitOrder, (SPIMode)dataMode, busMode); } } // Default speed set to 4MHz, SPI mode set to MODE 0 and Bit order set to MSB first. - SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); } + SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0, SPI_CONTROLLER); } bool operator==(const SPISettings& rhs) const { if ((this->clockFreq == rhs.clockFreq) && (this->bitOrder == rhs.bitOrder) && - (this->dataMode == rhs.dataMode)) { + (this->dataMode == rhs.dataMode) && + (this->busMode == rhs.busMode)) { return true; } return false; @@ -79,22 +89,27 @@ class SPISettings { BitOrder getBitOrder() const { return (bitOrder); } + SPIBusMode getBusMode() const { + return busMode; + } private: - void init_MightInline(uint32_t clock, BitOrder bitOrder, SPIMode dataMode) { - init_AlwaysInline(clock, bitOrder, dataMode); + void init_MightInline(uint32_t clock, BitOrder bitOrder, SPIMode dataMode, SPIBusMode busMode) { + init_AlwaysInline(clock, bitOrder, dataMode, busMode); } // Core developer MUST use an helper function in beginTransaction() to use this data - void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, SPIMode dataMode) __attribute__((__always_inline__)) { + void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, SPIMode dataMode, SPIBusMode busMode) __attribute__((__always_inline__)) { this->clockFreq = clock; this->dataMode = dataMode; this->bitOrder = bitOrder; + this->busMode = busMode; } uint32_t clockFreq; SPIMode dataMode; BitOrder bitOrder; + SPIBusMode busMode; friend class HardwareSPI; }; @@ -124,4 +139,7 @@ class HardwareSPI virtual void end() = 0; }; +// Alias SPIClass to HardwareSPI since it's already the defacto standard for SPI class name +typedef HardwareSPI SPIClass; + } diff --git a/ArduinoCore-API/api/HardwareSerial.h b/ArduinoCore-API/api/HardwareSerial.h index e8f0657..b687cdf 100644 --- a/ArduinoCore-API/api/HardwareSerial.h +++ b/ArduinoCore-API/api/HardwareSerial.h @@ -1,4 +1,5 @@ /* + HardwareSerial.h - Hardware serial interface for Arduino Copyright (c) 2016 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or @@ -8,8 +9,8 @@ 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 Lesser General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software diff --git a/ArduinoCore-API/api/IPAddress.cpp b/ArduinoCore-API/api/IPAddress.cpp index 649c3a2..05b41bc 100644 --- a/ArduinoCore-API/api/IPAddress.cpp +++ b/ArduinoCore-API/api/IPAddress.cpp @@ -17,42 +17,125 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include #include "IPAddress.h" #include "Print.h" using namespace arduino; -IPAddress::IPAddress() +IPAddress::IPAddress() : IPAddress(IPv4) {} + +IPAddress::IPAddress(IPType ip_type) { - _address.dword = 0; + _type = ip_type; + memset(_address.bytes, 0, sizeof(_address.bytes)); } IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) { - _address.bytes[0] = first_octet; - _address.bytes[1] = second_octet; - _address.bytes[2] = third_octet; - _address.bytes[3] = fourth_octet; + _type = IPv4; + memset(_address.bytes, 0, sizeof(_address.bytes)); + _address.bytes[IPADDRESS_V4_BYTES_INDEX] = first_octet; + _address.bytes[IPADDRESS_V4_BYTES_INDEX + 1] = second_octet; + _address.bytes[IPADDRESS_V4_BYTES_INDEX + 2] = third_octet; + _address.bytes[IPADDRESS_V4_BYTES_INDEX + 3] = fourth_octet; +} + +IPAddress::IPAddress(uint8_t o1, uint8_t o2, uint8_t o3, uint8_t o4, uint8_t o5, uint8_t o6, uint8_t o7, uint8_t o8, uint8_t o9, uint8_t o10, uint8_t o11, uint8_t o12, uint8_t o13, uint8_t o14, uint8_t o15, uint8_t o16) { + _type = IPv6; + _address.bytes[0] = o1; + _address.bytes[1] = o2; + _address.bytes[2] = o3; + _address.bytes[3] = o4; + _address.bytes[4] = o5; + _address.bytes[5] = o6; + _address.bytes[6] = o7; + _address.bytes[7] = o8; + _address.bytes[8] = o9; + _address.bytes[9] = o10; + _address.bytes[10] = o11; + _address.bytes[11] = o12; + _address.bytes[12] = o13; + _address.bytes[13] = o14; + _address.bytes[14] = o15; + _address.bytes[15] = o16; } IPAddress::IPAddress(uint32_t address) { - _address.dword = address; + // IPv4 only + _type = IPv4; + memset(_address.bytes, 0, sizeof(_address.bytes)); + _address.dword[IPADDRESS_V4_DWORD_INDEX] = address; + + // NOTE on conversion/comparison and uint32_t: + // These conversions are host platform dependent. + // There is a defined integer representation of IPv4 addresses, + // based on network byte order (will be the value on big endian systems), + // e.g. http://2398766798 is the same as http://142.250.70.206, + // However on little endian systems the octets 0x83, 0xFA, 0x46, 0xCE, + // in that order, will form the integer (uint32_t) 3460758158 . +} + +IPAddress::IPAddress(const uint8_t *address) : IPAddress(IPv4, address) {} + +IPAddress::IPAddress(IPType ip_type, const uint8_t *address) +{ + _type = ip_type; + if (ip_type == IPv4) { + memset(_address.bytes, 0, sizeof(_address.bytes)); + memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address, sizeof(uint32_t)); + } else { + memcpy(_address.bytes, address, sizeof(_address.bytes)); + } +} + +IPAddress::IPAddress(const char *address) +{ + fromString(address); } -IPAddress::IPAddress(const uint8_t *address) +String IPAddress::toString4() const { - ::memcpy(_address.bytes, address, sizeof(_address.bytes)); + char szRet[16]; + snprintf(szRet, sizeof(szRet), "%u.%u.%u.%u", _address.bytes[IPADDRESS_V4_BYTES_INDEX], _address.bytes[IPADDRESS_V4_BYTES_INDEX + 1], _address.bytes[IPADDRESS_V4_BYTES_INDEX + 2], _address.bytes[IPADDRESS_V4_BYTES_INDEX + 3]); + return String(szRet); } -bool IPAddress::fromString(const char *address) +String IPAddress::toString6() const +{ + char szRet[40]; + snprintf(szRet, sizeof(szRet), "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3], + _address.bytes[4], _address.bytes[5], _address.bytes[6], _address.bytes[7], + _address.bytes[8], _address.bytes[9], _address.bytes[10], _address.bytes[11], + _address.bytes[12], _address.bytes[13], _address.bytes[14], _address.bytes[15]); + return String(szRet); +} + +String IPAddress::toString() const +{ + if (_type == IPv4) { + return toString4(); + } else { + return toString6(); + } +} + +bool IPAddress::fromString(const char *address) { + if (!fromString4(address)) { + return fromString6(address); + } + return true; +} + +bool IPAddress::fromString4(const char *address) { // TODO: add support for "a", "a.b", "a.b.c" formats int16_t acc = -1; // Accumulator uint8_t dots = 0; + memset(_address.bytes, 0, sizeof(_address.bytes)); while (*address) { char c = *address++; @@ -67,14 +150,14 @@ bool IPAddress::fromString(const char *address) else if (c == '.') { if (dots == 3) { - // Too much dots (there must be 3 dots) + // Too many dots (there must be 3 dots) return false; } if (acc < 0) { /* No value between dots, e.g. '1..' */ return false; } - _address.bytes[dots++] = acc; + _address.bytes[IPADDRESS_V4_BYTES_INDEX + dots++] = acc; acc = -1; } else @@ -92,44 +175,194 @@ bool IPAddress::fromString(const char *address) /* No value between dots, e.g. '1..' */ return false; } - _address.bytes[3] = acc; + _address.bytes[IPADDRESS_V4_BYTES_INDEX + 3] = acc; + _type = IPv4; + return true; +} + +bool IPAddress::fromString6(const char *address) { + uint32_t acc = 0; // Accumulator + int colons = 0, double_colons = -1; + + while (*address) + { + char c = tolower(*address++); + if (isalnum(c) && c <= 'f') { + if (c >= 'a') + c -= 'a' - '0' - 10; + acc = acc * 16 + (c - '0'); + if (acc > 0xffff) + // Value out of range + return false; + } + else if (c == ':') { + if (*address == ':') { + if (double_colons >= 0) { + // :: allowed once + return false; + } + if (*address != '\0' && *(address + 1) == ':') { + // ::: not allowed + return false; + } + // remember location + double_colons = colons + !!acc; + address++; + } else if (*address == '\0') { + // can't end with a single colon + return false; + } + if (colons == 7) + // too many separators + return false; + _address.bytes[colons * 2] = acc >> 8; + _address.bytes[colons * 2 + 1] = acc & 0xff; + colons++; + acc = 0; + } + else + // Invalid char + return false; + } + + if (double_colons == -1 && colons != 7) { + // Too few separators + return false; + } + if (double_colons > -1 && colons > 6) { + // Too many segments (double colon must be at least one zero field) + return false; + } + _address.bytes[colons * 2] = acc >> 8; + _address.bytes[colons * 2 + 1] = acc & 0xff; + colons++; + + if (double_colons != -1) { + for (int i = colons * 2 - double_colons * 2 - 1; i >= 0; i--) + _address.bytes[16 - colons * 2 + double_colons * 2 + i] = _address.bytes[double_colons * 2 + i]; + for (int i = double_colons * 2; i < 16 - colons * 2 + double_colons * 2; i++) + _address.bytes[i] = 0; + } + + _type = IPv6; return true; } IPAddress& IPAddress::operator=(const uint8_t *address) { - ::memcpy(_address.bytes, address, sizeof(_address.bytes)); + // IPv4 only conversion from byte pointer + _type = IPv4; + memset(_address.bytes, 0, sizeof(_address.bytes)); + memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address, sizeof(uint32_t)); + return *this; +} + +IPAddress& IPAddress::operator=(const char *address) +{ + fromString(address); return *this; } IPAddress& IPAddress::operator=(uint32_t address) { - _address.dword = address; + // IPv4 conversion + // See note on conversion/comparison and uint32_t + _type = IPv4; + memset(_address.bytes, 0, sizeof(_address.bytes)); + _address.dword[IPADDRESS_V4_DWORD_INDEX] = address; return *this; } +bool IPAddress::operator==(const IPAddress& addr) const { + return (addr._type == _type) + && (memcmp(addr._address.bytes, _address.bytes, sizeof(_address.bytes)) == 0); +} + bool IPAddress::operator==(const uint8_t* addr) const { - return ::memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; + // IPv4 only comparison to byte pointer + // Can't support IPv6 as we know our type, but not the length of the pointer + return _type == IPv4 && memcmp(addr, &_address.bytes[IPADDRESS_V4_BYTES_INDEX], sizeof(uint32_t)) == 0; +} + +uint8_t IPAddress::operator[](int index) const { + if (_type == IPv4) { + return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index]; + } + return _address.bytes[index]; +} + +uint8_t& IPAddress::operator[](int index) { + if (_type == IPv4) { + return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index]; + } + return _address.bytes[index]; } size_t IPAddress::printTo(Print& p) const { size_t n = 0; + + if (_type == IPv6) { + // IPv6 IETF canonical format: compress left-most longest run of two or more zero fields, lower case + int8_t longest_start = -1; + int8_t longest_length = 1; + int8_t current_start = -1; + int8_t current_length = 0; + for (int8_t f = 0; f < 8; f++) { + if (_address.bytes[f * 2] == 0 && _address.bytes[f * 2 + 1] == 0) { + if (current_start == -1) { + current_start = f; + current_length = 1; + } else { + current_length++; + } + if (current_length > longest_length) { + longest_start = current_start; + longest_length = current_length; + } + } else { + current_start = -1; + } + } + for (int f = 0; f < 8; f++) { + if (f < longest_start || f >= longest_start + longest_length) { + uint8_t c1 = _address.bytes[f * 2] >> 4; + uint8_t c2 = _address.bytes[f * 2] & 0xf; + uint8_t c3 = _address.bytes[f * 2 + 1] >> 4; + uint8_t c4 = _address.bytes[f * 2 + 1] & 0xf; + if (c1 > 0) { + n += p.print((char)(c1 < 10 ? '0' + c1 : 'a' + c1 - 10)); + } + if (c1 > 0 || c2 > 0) { + n += p.print((char)(c2 < 10 ? '0' + c2 : 'a' + c2 - 10)); + } + if (c1 > 0 || c2 > 0 || c3 > 0) { + n += p.print((char)(c3 < 10 ? '0' + c3 : 'a' + c3 - 10)); + } + n += p.print((char)(c4 < 10 ? '0' + c4 : 'a' + c4 - 10)); + if (f < 7) { + n += p.print(':'); + } + } else if (f == longest_start) { + if (longest_start == 0) { + n += p.print(':'); + } + n += p.print(':'); + } + } + return n; + } + + // IPv4 for (int i =0; i < 3; i++) { - n += p.print(_address.bytes[i], DEC); + n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + i], DEC); n += p.print('.'); } - n += p.print(_address.bytes[3], DEC); + n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + 3], DEC); return n; } -String IPAddress::toString(bool includeZone) const { - char s[30]; - snprintf(s, sizeof(s), "%d.%d.%d.%d", _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3]); - return String(s); -} - - +const IPAddress arduino::IN6ADDR_ANY(IPv6); const IPAddress arduino::INADDR_NONE(0,0,0,0); diff --git a/ArduinoCore-API/api/IPAddress.h b/ArduinoCore-API/api/IPAddress.h index 65062be..31a2d06 100644 --- a/ArduinoCore-API/api/IPAddress.h +++ b/ArduinoCore-API/api/IPAddress.h @@ -21,9 +21,12 @@ #include #include "Printable.h" -#include "WString.h" +#include "String.h" -// forward declartions of global name space friend classes +#define IPADDRESS_V4_BYTES_INDEX 12 +#define IPADDRESS_V4_DWORD_INDEX 3 + +// forward declarations of global name space friend classes class EthernetClass; class DhcpClass; class DNSClient; @@ -32,47 +35,70 @@ namespace arduino { // A class to make it easier to handle and pass around IP addresses +enum IPType { + IPv4, + IPv6 +}; + class IPAddress : public Printable { private: union { - uint8_t bytes[4]; // IPv4 address - uint32_t dword; + uint8_t bytes[16]; + uint32_t dword[4]; } _address; + IPType _type; // Access the raw byte array containing the address. Because this returns a pointer // to the internal structure rather than a copy of the address this function should only // be used when you know that the usage of the returned uint8_t* will be transient and not // stored. - uint8_t* raw_address() { return _address.bytes; }; + uint8_t* raw_address() { return _type == IPv4 ? &_address.bytes[IPADDRESS_V4_BYTES_INDEX] : _address.bytes; } public: // Constructors + + // Default IPv4 IPAddress(); + IPAddress(IPType ip_type); IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); + IPAddress(uint8_t o1, uint8_t o2, uint8_t o3, uint8_t o4, uint8_t o5, uint8_t o6, uint8_t o7, uint8_t o8, uint8_t o9, uint8_t o10, uint8_t o11, uint8_t o12, uint8_t o13, uint8_t o14, uint8_t o15, uint8_t o16); + // IPv4; see implementation note IPAddress(uint32_t address); + // Default IPv4 IPAddress(const uint8_t *address); + IPAddress(IPType ip_type, const uint8_t *address); + // If IPv4 fails tries IPv6 see fromString function + IPAddress(const char *address); bool fromString(const char *address); bool fromString(const String &address) { return fromString(address.c_str()); } - // Overloaded cast operator to allow IPAddress objects to be used where a pointer - // to a four-byte uint8_t array is expected - operator uint32_t() const { return _address.dword; }; - bool operator==(const IPAddress& addr) const { return _address.dword == addr._address.dword; }; - bool operator!=(const IPAddress& addr) const { return _address.dword != addr._address.dword; }; + // Overloaded cast operator to allow IPAddress objects to be used where a uint32_t is expected + // NOTE: IPv4 only; see implementation note + operator uint32_t() const { return _type == IPv4 ? _address.dword[IPADDRESS_V4_DWORD_INDEX] : 0; }; + + bool operator==(const IPAddress& addr) const; + bool operator!=(const IPAddress& addr) const { return !(*this == addr); }; + + // NOTE: IPv4 only; we don't know the length of the pointer bool operator==(const uint8_t* addr) const; // Overloaded index operator to allow getting and setting individual octets of the address - uint8_t operator[](int index) const { return _address.bytes[index]; }; - uint8_t& operator[](int index) { return _address.bytes[index]; }; + uint8_t operator[](int index) const; + uint8_t& operator[](int index); // Overloaded copy operators to allow initialisation of IPAddress objects from other types + // NOTE: IPv4 only IPAddress& operator=(const uint8_t *address); + // NOTE: IPv4 only; see implementation note IPAddress& operator=(uint32_t address); + // If IPv4 fails tries IPv6 see fromString function + IPAddress& operator=(const char *address); virtual size_t printTo(Print& p) const; + String toString() const; - String toString(bool includeZone = false) const; + IPType type() const { return _type; } friend class UDP; friend class Client; @@ -81,7 +107,16 @@ class IPAddress : public Printable { friend ::EthernetClass; friend ::DhcpClass; friend ::DNSClient; + +protected: + bool fromString4(const char *address); + bool fromString6(const char *address); + String toString4() const; + String toString6() const; }; +extern const IPAddress IN6ADDR_ANY; extern const IPAddress INADDR_NONE; } + +using arduino::IPAddress; \ No newline at end of file diff --git a/ArduinoCore-API/api/Interrupts.h b/ArduinoCore-API/api/Interrupts.h index e306fc7..c3e37ad 100644 --- a/ArduinoCore-API/api/Interrupts.h +++ b/ArduinoCore-API/api/Interrupts.h @@ -1,3 +1,22 @@ +/* + Interrupts.h - Arduino interrupt management functions + Copyright (c) 2018 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + #ifndef W_INTERRUPTS_CPP #define W_INTERRUPTS_CPP #ifdef __cplusplus diff --git a/ArduinoCore-API/api/Print.cpp b/ArduinoCore-API/api/Print.cpp index f1e8246..4a6e942 100644 --- a/ArduinoCore-API/api/Print.cpp +++ b/ArduinoCore-API/api/Print.cpp @@ -1,4 +1,5 @@ /* + Print.cpp - Base class that provides print() and println() Copyright (c) 2014 Arduino. All right reserved. This library is free software; you can redistribute it and/or @@ -8,8 +9,8 @@ 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 Lesser General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software diff --git a/ArduinoCore-API/api/Print.h b/ArduinoCore-API/api/Print.h index 43b67e7..601e576 100644 --- a/ArduinoCore-API/api/Print.h +++ b/ArduinoCore-API/api/Print.h @@ -1,4 +1,5 @@ /* + Print.h - Base class that provides print() and println() Copyright (c) 2016 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or @@ -8,8 +9,8 @@ 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 Lesser General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software @@ -21,7 +22,7 @@ #include #include // for size_t -#include "WString.h" +#include "String.h" #include "Printable.h" #define DEC 10 @@ -49,7 +50,8 @@ class Print virtual size_t write(uint8_t) = 0; size_t write(const char *str) { if (str == NULL) return 0; - return write((const uint8_t *)str, ::strlen(str)); + int len = strlen(str); + return write((const uint8_t *)str, len); } virtual size_t write(const uint8_t *buffer, size_t size); size_t write(const char *buffer, size_t size) { @@ -57,7 +59,7 @@ class Print } // default to zero, meaning "a single write may block" - // should be overriden by subclasses with buffering + // should be overridden by subclasses with buffering virtual int availableForWrite() { return 0; } size_t print(const __FlashStringHelper *); @@ -93,4 +95,4 @@ class Print }; } -using namespace arduino; \ No newline at end of file +using arduino::Print; \ No newline at end of file diff --git a/ArduinoCore-API/api/Printable.h b/ArduinoCore-API/api/Printable.h index 972866e..850c8d2 100644 --- a/ArduinoCore-API/api/Printable.h +++ b/ArduinoCore-API/api/Printable.h @@ -1,4 +1,5 @@ /* + Printable.h - Interface for classes that can be printed via Print Copyright (c) 2016 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or @@ -8,8 +9,8 @@ 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 Lesser General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software diff --git a/ArduinoCore-API/api/RingBuffer.h b/ArduinoCore-API/api/RingBuffer.h index 833350d..b69c20d 100644 --- a/ArduinoCore-API/api/RingBuffer.h +++ b/ArduinoCore-API/api/RingBuffer.h @@ -1,4 +1,5 @@ /* + RingBuffer.h - Ring buffer implementation Copyright (c) 2014 Arduino. All right reserved. This library is free software; you can redistribute it and/or @@ -8,8 +9,8 @@ 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 Lesser General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software @@ -77,7 +78,7 @@ void RingBufferN::store_char( uint8_t c ) { _aucBuffer[_iHead] = c ; _iHead = nextIndex(_iHead); - _numElems++; + _numElems = _numElems + 1; } } @@ -97,7 +98,7 @@ int RingBufferN::read_char() uint8_t value = _aucBuffer[_iTail]; _iTail = nextIndex(_iTail); - _numElems--; + _numElems = _numElems - 1; return value; } @@ -138,4 +139,4 @@ bool RingBufferN::isFull() } #endif /* _RING_BUFFER_ */ -#endif /* __cplusplus */ \ No newline at end of file +#endif /* __cplusplus */ diff --git a/ArduinoCore-API/api/Stream.cpp b/ArduinoCore-API/api/Stream.cpp index b8bb6c6..f6f9bda 100644 --- a/ArduinoCore-API/api/Stream.cpp +++ b/ArduinoCore-API/api/Stream.cpp @@ -86,7 +86,7 @@ int Stream::peekNextDigit(LookaheadMode lookahead, bool detectDecimal) // Public Methods ////////////////////////////////////////////////////////////// -void Stream::setTimeout(size_t timeout) // sets the maximum number of milliseconds to wait +void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait { _timeout = timeout; } @@ -94,7 +94,7 @@ void Stream::setTimeout(size_t timeout) // sets the maximum number of milliseco // find returns true if the target string is found bool Stream::find(const char *target) { - return findUntil(target, ::strlen(target), NULL, 0); + return findUntil(target, strlen(target), NULL, 0); } // reads data from the stream until the target string of given length is found @@ -107,7 +107,7 @@ bool Stream::find(const char *target, size_t length) // as find but search ends if the terminator string is found bool Stream::findUntil(const char *target, const char *terminator) { - return findUntil(target, ::strlen(target), terminator, strlen(terminator)); + return findUntil(target, strlen(target), terminator, strlen(terminator)); } // reads data from the stream until the target string of the given length is found @@ -162,9 +162,9 @@ float Stream::parseFloat(LookaheadMode lookahead, char ignore) { bool isNegative = false; bool isFraction = false; - long value = 0; + double value = 0.0; int c; - float fraction = 1.0; + double fraction = 1.0; c = peekNextDigit(lookahead, true); // ignore non numeric leading characters @@ -179,9 +179,12 @@ float Stream::parseFloat(LookaheadMode lookahead, char ignore) else if (c == '.') isFraction = true; else if(c >= '0' && c <= '9') { // is c a digit? - value = value * 10 + c - '0'; - if(isFraction) - fraction *= 0.1; + if(isFraction) { + fraction *= 0.1; + value = value + fraction * (c - '0'); + } else { + value = value * 10 + c - '0'; + } } read(); // consume the character we got with peek c = timedPeek(); @@ -190,10 +193,8 @@ float Stream::parseFloat(LookaheadMode lookahead, char ignore) if(isNegative) value = -value; - if(isFraction) - return value * fraction; - else - return value; + + return value; } // read characters from stream into buffer diff --git a/ArduinoCore-API/api/Stream.h b/ArduinoCore-API/api/Stream.h index 10dcb4b..e81c71b 100644 --- a/ArduinoCore-API/api/Stream.h +++ b/ArduinoCore-API/api/Stream.h @@ -24,7 +24,7 @@ #include #include "Print.h" -// compatability macros for testing +// compatibility macros for testing /* #define getInt() parseInt() #define getInt(ignore) parseInt(ignore) @@ -50,8 +50,8 @@ enum LookaheadMode{ class Stream : public Print { protected: - size_t _timeout; // number of milliseconds to wait for the next char before aborting timed read - size_t _startMillis; // used for timeout measurement + unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read + unsigned long _startMillis; // used for timeout measurement int timedRead(); // private method to read stream with timeout int timedPeek(); // private method to peek stream with timeout int peekNextDigit(LookaheadMode lookahead, bool detectDecimal); // returns the next numeric digit in the stream or -1 if timeout @@ -65,8 +65,8 @@ class Stream : public Print // parsing methods - virtual void setTimeout(size_t timeout); // sets maximum milliseconds to wait for stream data, default is 1 second - virtual size_t getTimeout(void) { return _timeout; } + void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second + unsigned long getTimeout(void) { return _timeout; } bool find(const char *target); // reads data from the stream until the target string is found bool find(const uint8_t *target) { return find ((const char *)target); } @@ -94,8 +94,8 @@ class Stream : public Print float parseFloat(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR); // float version of parseInt - virtual size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer - virtual size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); } + size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer + size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); } // terminates if length characters have been read or timeout (see setTimeout) // returns the number of characters placed in the buffer (0 means no valid data found) @@ -128,4 +128,6 @@ class Stream : public Print #undef NO_IGNORE_CHAR -} \ No newline at end of file +} + +using arduino::Stream; \ No newline at end of file diff --git a/ArduinoCore-API/api/WString.cpp b/ArduinoCore-API/api/String.cpp similarity index 82% rename from ArduinoCore-API/api/WString.cpp rename to ArduinoCore-API/api/String.cpp index c6c5b8b..4f17637 100644 --- a/ArduinoCore-API/api/WString.cpp +++ b/ArduinoCore-API/api/String.cpp @@ -19,7 +19,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "WString.h" +#include "String.h" #include "Common.h" #include "itoa.h" #include "deprecated-avr-comp/avr/dtostrf.h" @@ -45,6 +45,12 @@ String::String(const char *cstr) if (cstr) copy(cstr, strlen(cstr)); } +String::String(const char *cstr, unsigned int length) +{ + init(); + if (cstr) copy(cstr, length); +} + String::String(const String &value) { init(); @@ -57,18 +63,15 @@ String::String(const __FlashStringHelper *pstr) *this = pstr; } -#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) String::String(String &&rval) + : buffer(rval.buffer) + , capacity(rval.capacity) + , len(rval.len) { - init(); - move(rval); -} -String::String(StringSumHelper &&rval) -{ - init(); - move(rval); + rval.buffer = NULL; + rval.capacity = 0; + rval.len = 0; } -#endif String::String(char c) { @@ -160,25 +163,25 @@ void String::invalidate(void) capacity = len = 0; } -unsigned char String::reserve(unsigned int size) +bool String::reserve(unsigned int size) { if (buffer && capacity >= size) return 1; if (changeBuffer(size)) { if (len == 0) buffer[0] = 0; - return 1; + return true; } - return 0; + return false; } -unsigned char String::changeBuffer(unsigned int maxStrLen) +bool String::changeBuffer(unsigned int maxStrLen) { char *newbuffer = (char *)realloc(buffer, maxStrLen + 1); if (newbuffer) { buffer = newbuffer; capacity = maxStrLen; - return 1; + return true; } - return 0; + return false; } /*********************************************/ @@ -192,7 +195,8 @@ String & String::copy(const char *cstr, unsigned int length) return *this; } len = length; - strcpy(buffer, cstr); + memcpy(buffer, cstr, length); + buffer[len] = '\0'; return *this; } @@ -207,57 +211,43 @@ String & String::copy(const __FlashStringHelper *pstr, unsigned int length) return *this; } -#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) void String::move(String &rhs) { - if (buffer) { - if (rhs && capacity >= rhs.len) { - strcpy(buffer, rhs.buffer); - len = rhs.len; - rhs.len = 0; - return; - } else { - free(buffer); - } + if (this != &rhs) + { + free(buffer); + + buffer = rhs.buffer; + len = rhs.len; + capacity = rhs.capacity; + + rhs.buffer = NULL; + rhs.len = 0; + rhs.capacity = 0; } - buffer = rhs.buffer; - capacity = rhs.capacity; - len = rhs.len; - rhs.buffer = NULL; - rhs.capacity = 0; - rhs.len = 0; } -#endif String & String::operator = (const String &rhs) { if (this == &rhs) return *this; - + if (rhs.buffer) copy(rhs.buffer, rhs.len); else invalidate(); - - return *this; -} -#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) -String & String::operator = (String &&rval) -{ - if (this != &rval) move(rval); return *this; } -String & String::operator = (StringSumHelper &&rval) +String & String::operator = (String &&rval) { - if (this != &rval) move(rval); + move(rval); return *this; } -#endif String & String::operator = (const char *cstr) { if (cstr) copy(cstr, strlen(cstr)); else invalidate(); - + return *this; } @@ -273,95 +263,93 @@ String & String::operator = (const __FlashStringHelper *pstr) /* concat */ /*********************************************/ -unsigned char String::concat(const String &s) +bool String::concat(const String &s) { return concat(s.buffer, s.len); } -unsigned char String::concat(const char *cstr, unsigned int length) +bool String::concat(const char *cstr, unsigned int length) { unsigned int newlen = len + length; - if (!cstr) return 0; - if (length == 0) return 1; - if (!reserve(newlen)) return 0; - strcpy(buffer + len, cstr); + if (!cstr) return false; + if (length == 0) return true; + if (!reserve(newlen)) return false; + memcpy(buffer + len, cstr, length); len = newlen; - return 1; + buffer[len] = '\0'; + return true; } -unsigned char String::concat(const char *cstr) +bool String::concat(const char *cstr) { - if (!cstr) return 0; + if (!cstr) return false; return concat(cstr, strlen(cstr)); } -unsigned char String::concat(char c) +bool String::concat(char c) { - char buf[2]; - buf[0] = c; - buf[1] = 0; - return concat(buf, 1); + return concat(&c, 1); } -unsigned char String::concat(unsigned char num) +bool String::concat(unsigned char num) { char buf[1 + 3 * sizeof(unsigned char)]; itoa(num, buf, 10); - return concat(buf, strlen(buf)); + return concat(buf); } -unsigned char String::concat(int num) +bool String::concat(int num) { char buf[2 + 3 * sizeof(int)]; itoa(num, buf, 10); - return concat(buf, strlen(buf)); + return concat(buf); } -unsigned char String::concat(unsigned int num) +bool String::concat(unsigned int num) { char buf[1 + 3 * sizeof(unsigned int)]; utoa(num, buf, 10); - return concat(buf, strlen(buf)); + return concat(buf); } -unsigned char String::concat(long num) +bool String::concat(long num) { char buf[2 + 3 * sizeof(long)]; ltoa(num, buf, 10); - return concat(buf, strlen(buf)); + return concat(buf); } -unsigned char String::concat(unsigned long num) +bool String::concat(unsigned long num) { char buf[1 + 3 * sizeof(unsigned long)]; ultoa(num, buf, 10); - return concat(buf, strlen(buf)); + return concat(buf); } -unsigned char String::concat(float num) +bool String::concat(float num) { char buf[20]; char* string = dtostrf(num, 4, 2, buf); - return concat(string, strlen(string)); + return concat(string); } -unsigned char String::concat(double num) +bool String::concat(double num) { char buf[20]; char* string = dtostrf(num, 4, 2, buf); - return concat(string, strlen(string)); + return concat(string); } -unsigned char String::concat(const __FlashStringHelper * str) +bool String::concat(const __FlashStringHelper * str) { - if (!str) return 0; + if (!str) return false; int length = strlen_P((const char *) str); - if (length == 0) return 1; + if (length == 0) return true; unsigned int newlen = len + length; - if (!reserve(newlen)) return 0; + if (!reserve(newlen)) return false; strcpy_P(buffer + len, (const char *) str); len = newlen; - return 1; + return true; } /*********************************************/ @@ -378,7 +366,7 @@ StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs) StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr) { StringSumHelper &a = const_cast(lhs); - if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate(); + if (!cstr || !a.concat(cstr)) a.invalidate(); return a; } @@ -462,53 +450,53 @@ int String::compareTo(const String &s) const int String::compareTo(const char *cstr) const { if (!buffer || !cstr) { - if (cstr && !*cstr) return 0 - *(unsigned char *)cstr; + if (cstr && *cstr) return 0 - *(unsigned char *)cstr; if (buffer && len > 0) return *(unsigned char *)buffer; return 0; } return strcmp(buffer, cstr); } -unsigned char String::equals(const String &s2) const +bool String::equals(const String &s2) const { return (len == s2.len && compareTo(s2) == 0); } -unsigned char String::equals(const char *cstr) const +bool String::equals(const char *cstr) const { if (len == 0) return (cstr == NULL || *cstr == 0); if (cstr == NULL) return buffer[0] == 0; return strcmp(buffer, cstr) == 0; } -unsigned char String::equalsIgnoreCase( const String &s2 ) const +bool String::equalsIgnoreCase( const String &s2 ) const { - if (this == &s2) return 1; - if (len != s2.len) return 0; - if (len == 0) return 1; + if (this == &s2) return true; + if (len != s2.len) return false; + if (len == 0) return true; const char *p1 = buffer; const char *p2 = s2.buffer; while (*p1) { - if (tolower(*p1++) != tolower(*p2++)) return 0; - } - return 1; + if (tolower(*p1++) != tolower(*p2++)) return false; + } + return true; } -unsigned char String::startsWith( const String &s2 ) const +bool String::startsWith( const String &s2 ) const { - if (len < s2.len) return 0; + if (len < s2.len) return false; return startsWith(s2, 0); } -unsigned char String::startsWith( const String &s2, unsigned int offset ) const +bool String::startsWith( const String &s2, unsigned int offset ) const { - if (offset > len - s2.len || !buffer || !s2.buffer) return 0; + if (offset > len - s2.len || !buffer || !s2.buffer) return false; return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0; } -unsigned char String::endsWith( const String &s2 ) const +bool String::endsWith( const String &s2 ) const { - if ( len < s2.len || !buffer || !s2.buffer) return 0; + if ( len < s2.len || !buffer || !s2.buffer) return false; return strcmp(&buffer[len - s2.len], s2.buffer) == 0; } @@ -521,7 +509,7 @@ char String::charAt(unsigned int loc) const return operator[](loc); } -void String::setCharAt(unsigned int loc, char c) +void String::setCharAt(unsigned int loc, char c) { if (loc < len) buffer[loc] = c; } @@ -629,10 +617,7 @@ String String::substring(unsigned int left, unsigned int right) const String out; if (left >= len) return out; if (right > len) right = len; - char temp = buffer[right]; // save the replaced character - buffer[right] = '\0'; - out = buffer + left; // pointer arithmetic - buffer[right] = temp; //restore character + out.copy(buffer + left, right - left); return out; } @@ -661,9 +646,9 @@ void String::replace(const String& find, const String& replace) } } else if (diff < 0) { unsigned int size = len; // compute size needed for result + diff = 0 - diff; while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { readFrom = foundAt + find.len; - diff = 0 - diff; size -= diff; } if (size == len) return; diff --git a/ArduinoCore-API/api/WString.h b/ArduinoCore-API/api/String.h similarity index 72% rename from ArduinoCore-API/api/WString.h rename to ArduinoCore-API/api/String.h index e310d4a..0bafd35 100644 --- a/ArduinoCore-API/api/WString.h +++ b/ArduinoCore-API/api/String.h @@ -42,11 +42,7 @@ namespace arduino { // -std=c++0x class __FlashStringHelper; -#ifndef IS_DESKTOP -# define F(string_literal) (reinterpret_cast(PSTR(string_literal))) -#else -# define F(string_literal) string_literal -#endif +#define F(string_literal) (reinterpret_cast(PSTR(string_literal))) // An inherited class for holding the result of a concatenation. These // result objects are assumed to be writable by subsequent concatenations. @@ -72,12 +68,11 @@ class String // fails, the string will be marked as invalid (i.e. "if (s)" will // be false). String(const char *cstr = ""); + String(const char *cstr, unsigned int length); + String(const uint8_t *cstr, unsigned int length) : String((const char*)cstr, length) {} String(const String &str); String(const __FlashStringHelper *str); - #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) String(String &&rval); - String(StringSumHelper &&rval); - #endif explicit String(char c); explicit String(unsigned char, unsigned char base=10); explicit String(int, unsigned char base=10); @@ -92,8 +87,9 @@ class String // return true on success, false on failure (in which case, the string // is left unchanged). reserve(0), if successful, will validate an // invalid string (i.e., "if (s)" will be true afterwards) - unsigned char reserve(unsigned int size); + bool reserve(unsigned int size); inline unsigned int length(void) const {return len;} + inline bool isEmpty(void) const { return length() == 0; } // creates a copy of the assigned value. if the value is null or // invalid, or if the memory allocation fails, the string will be @@ -101,27 +97,26 @@ class String String & operator = (const String &rhs); String & operator = (const char *cstr); String & operator = (const __FlashStringHelper *str); - #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) String & operator = (String &&rval); - String & operator = (StringSumHelper &&rval); - #endif // concatenate (works w/ built-in types) // returns true on success, false on failure (in which case, the string // is left unchanged). if the argument is null or invalid, the - // concatenation is considered unsucessful. - unsigned char concat(const String &str); - unsigned char concat(const char *cstr); - unsigned char concat(char c); - unsigned char concat(unsigned char num); - unsigned char concat(int num); - unsigned char concat(unsigned int num); - unsigned char concat(long num); - unsigned char concat(unsigned long num); - unsigned char concat(float num); - unsigned char concat(double num); - unsigned char concat(const __FlashStringHelper * str); + // concatenation is considered unsuccessful. + bool concat(const String &str); + bool concat(const char *cstr); + bool concat(const char *cstr, unsigned int length); + bool concat(const uint8_t *cstr, unsigned int length) {return concat((const char*)cstr, length);} + bool concat(char c); + bool concat(unsigned char num); + bool concat(int num); + bool concat(unsigned int num); + bool concat(long num); + bool concat(unsigned long num); + bool concat(float num); + bool concat(double num); + bool concat(const __FlashStringHelper * str); // if there's not enough memory for the concatenated value, the string // will be left unchanged (but this isn't signalled in any way) @@ -153,35 +148,35 @@ class String operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } int compareTo(const String &s) const; int compareTo(const char *cstr) const; - unsigned char equals(const String &s) const; - unsigned char equals(const char *cstr) const; - - friend unsigned char operator == (const String &a, const String &b) { return a.equals(b); } - friend unsigned char operator == (const String &a, const char *b) { return a.equals(b); } - friend unsigned char operator == (const char *a, const String &b) { return b == a; } - friend unsigned char operator < (const String &a, const String &b) { return a.compareTo(b) < 0; } - friend unsigned char operator < (const String &a, const char *b) { return a.compareTo(b) < 0; } - friend unsigned char operator < (const char *a, const String &b) { return b.compareTo(a) > 0; } - - friend unsigned char operator != (const String &a, const String &b) { return !(a == b); } - friend unsigned char operator != (const String &a, const char *b) { return !(a == b); } - friend unsigned char operator != (const char *a, const String &b) { return !(a == b); } - friend unsigned char operator > (const String &a, const String &b) { return b < a; } - friend unsigned char operator > (const String &a, const char *b) { return b < a; } - friend unsigned char operator > (const char *a, const String &b) { return b < a; } - friend unsigned char operator <= (const String &a, const String &b) { return !(b < a); } - friend unsigned char operator <= (const String &a, const char *b) { return !(b < a); } - friend unsigned char operator <= (const char *a, const String &b) { return !(b < a); } - friend unsigned char operator >= (const String &a, const String &b) { return !(a < b); } - friend unsigned char operator >= (const String &a, const char *b) { return !(a < b); } - friend unsigned char operator >= (const char *a, const String &b) { return !(a < b); } - - unsigned char equalsIgnoreCase(const String &s) const; - unsigned char startsWith( const String &prefix) const; - unsigned char startsWith(const String &prefix, unsigned int offset) const; - unsigned char endsWith(const String &suffix) const; - - // character acccess + bool equals(const String &s) const; + bool equals(const char *cstr) const; + + friend bool operator == (const String &a, const String &b) { return a.equals(b); } + friend bool operator == (const String &a, const char *b) { return a.equals(b); } + friend bool operator == (const char *a, const String &b) { return b == a; } + friend bool operator < (const String &a, const String &b) { return a.compareTo(b) < 0; } + friend bool operator < (const String &a, const char *b) { return a.compareTo(b) < 0; } + friend bool operator < (const char *a, const String &b) { return b.compareTo(a) > 0; } + + friend bool operator != (const String &a, const String &b) { return !(a == b); } + friend bool operator != (const String &a, const char *b) { return !(a == b); } + friend bool operator != (const char *a, const String &b) { return !(a == b); } + friend bool operator > (const String &a, const String &b) { return b < a; } + friend bool operator > (const String &a, const char *b) { return b < a; } + friend bool operator > (const char *a, const String &b) { return b < a; } + friend bool operator <= (const String &a, const String &b) { return !(b < a); } + friend bool operator <= (const String &a, const char *b) { return !(b < a); } + friend bool operator <= (const char *a, const String &b) { return !(b < a); } + friend bool operator >= (const String &a, const String &b) { return !(a < b); } + friend bool operator >= (const String &a, const char *b) { return !(a < b); } + friend bool operator >= (const char *a, const String &b) { return !(a < b); } + + bool equalsIgnoreCase(const String &s) const; + bool startsWith( const String &prefix) const; + bool startsWith(const String &prefix, unsigned int offset) const; + bool endsWith(const String &suffix) const; + + // character access char charAt(unsigned int index) const; void setCharAt(unsigned int index, char c); char operator [] (unsigned int index) const; @@ -228,15 +223,12 @@ class String protected: void init(void); void invalidate(void); - unsigned char changeBuffer(unsigned int maxStrLen); - unsigned char concat(const char *cstr, unsigned int length); + bool changeBuffer(unsigned int maxStrLen); // copy and move String & copy(const char *cstr, unsigned int length); String & copy(const __FlashStringHelper *pstr, unsigned int length); - #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) void move(String &rhs); - #endif }; class StringSumHelper : public String @@ -256,5 +248,8 @@ class StringSumHelper : public String } // namespace arduino +using arduino::__FlashStringHelper; +using arduino::String; + #endif // __cplusplus #endif // __ARDUINO_STRINGS__ diff --git a/ArduinoCore-API/api/USBAPI.h b/ArduinoCore-API/api/USBAPI.h index 5adfacf..ba5e87c 100644 --- a/ArduinoCore-API/api/USBAPI.h +++ b/ArduinoCore-API/api/USBAPI.h @@ -27,7 +27,7 @@ namespace arduino { //================================================================================ // Low level API -typedef struct __attribute__((packed)) USBSetupStruct +typedef struct __attribute__((packed)) { union { uint8_t bmRequestType; diff --git a/ArduinoCore-API/api/Udp.h b/ArduinoCore-API/api/Udp.h index 53f89f9..20117a6 100644 --- a/ArduinoCore-API/api/Udp.h +++ b/ArduinoCore-API/api/Udp.h @@ -48,10 +48,10 @@ class UDP : public Stream { // Sending UDP packets - // Start building up a packet to send to the remote host specific in ip and port + // Start building up a packet to send to the remote host specified in ip and port // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port virtual int beginPacket(IPAddress ip, uint16_t port) =0; - // Start building up a packet to send to the remote host specific in host and port + // Start building up a packet to send to the remote host specified in host and port // Returns 1 if successful, 0 if there was a problem resolving the hostname or port virtual int beginPacket(const char *host, uint16_t port) =0; // Finish off this packet and send it @@ -89,4 +89,4 @@ class UDP : public Stream { } -using namespace arduino; +using arduino::UDP; \ No newline at end of file diff --git a/ArduinoCore-API/api/WCharacter.h b/ArduinoCore-API/api/WCharacter.h index 68c0e79..d050842 100644 --- a/ArduinoCore-API/api/WCharacter.h +++ b/ArduinoCore-API/api/WCharacter.h @@ -63,14 +63,14 @@ inline bool isAlpha(int c) // that fits into the ASCII character set. inline bool isAscii(int c) { - return ( isascii (c) == 0 ? false : true); + return ((c & ~0x7f) != 0 ? false : true ); } // Checks for a blank character, that is, a space or a tab. inline bool isWhitespace(int c) { - return ( isblank (c) == 0 ? false : true); + return ( c == '\t' || c == ' '); } @@ -98,7 +98,7 @@ inline bool isGraph(int c) // Checks for a lower-case character. inline bool isLowerCase(int c) { - return (islower (c) == 0 ? false : true); + return ( c >= 'a' && c <= 'z' ); } @@ -113,7 +113,7 @@ inline bool isPrintable(int c) // or an alphanumeric character. inline bool isPunct(int c) { - return ( ispunct (c) == 0 ? false : true); + return ( isPrintable(c) && !isSpace(c) && !isAlphaNumeric(c) ); } @@ -145,7 +145,7 @@ inline bool isHexadecimalDigit(int c) // ASCII character set, by clearing the high-order bits. inline int toAscii(int c) { - return toascii (c); + return (c & 0x7f); } diff --git a/ArduinoCore-API/api/deprecated-avr-comp/avr/dtostrf.c.impl b/ArduinoCore-API/api/deprecated-avr-comp/avr/dtostrf.c.impl index 96987a8..f410886 100644 --- a/ArduinoCore-API/api/deprecated-avr-comp/avr/dtostrf.c.impl +++ b/ArduinoCore-API/api/deprecated-avr-comp/avr/dtostrf.c.impl @@ -29,9 +29,12 @@ char *dtostrf (double val, signed char width, unsigned char prec, char *sout) { asm(".global _printf_float"); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" char fmt[20]; sprintf(fmt, "%%%d.%df", width, prec); sprintf(sout, fmt, val); return sout; +#pragma GCC diagnostic pop } diff --git a/ArduinoCore-API/api/deprecated-avr-comp/avr/interrupt.h b/ArduinoCore-API/api/deprecated-avr-comp/avr/interrupt.h index 950509d..a2873cf 100644 --- a/ArduinoCore-API/api/deprecated-avr-comp/avr/interrupt.h +++ b/ArduinoCore-API/api/deprecated-avr-comp/avr/interrupt.h @@ -19,5 +19,5 @@ /* Empty file. This file is here to allow compatibility with sketches (made for AVR) - that includes + that include */ diff --git a/ArduinoCore-API/api/deprecated-avr-comp/avr/pgmspace.h b/ArduinoCore-API/api/deprecated-avr-comp/avr/pgmspace.h index 95897d7..a80e4a5 100644 --- a/ArduinoCore-API/api/deprecated-avr-comp/avr/pgmspace.h +++ b/ArduinoCore-API/api/deprecated-avr-comp/avr/pgmspace.h @@ -30,7 +30,9 @@ #include #define PROGMEM +#define __ATTR_PROGMEM__ #define PGM_P const char * +#define PGM_VOID_P const void * #define PSTR(str) (str) #define _SFR_BYTE(n) (n) diff --git a/ArduinoCore-API/api/deprecated/Client.h b/ArduinoCore-API/api/deprecated/Client.h index 5f8d4be..84981c7 100644 --- a/ArduinoCore-API/api/deprecated/Client.h +++ b/ArduinoCore-API/api/deprecated/Client.h @@ -18,7 +18,7 @@ // including Client.h is deprecated, for all future projects use Arduino.h instead -// This include is added for compatibility, it will be remove on the next +// This include is added for compatibility, it will be removed on the next // major release of the API #include "../Client.h" diff --git a/ArduinoCore-API/api/deprecated/HardwareSerial.h b/ArduinoCore-API/api/deprecated/HardwareSerial.h index 19d77c7..0ed7d7a 100644 --- a/ArduinoCore-API/api/deprecated/HardwareSerial.h +++ b/ArduinoCore-API/api/deprecated/HardwareSerial.h @@ -18,7 +18,7 @@ // including HardwareSerial.h is deprecated, for all future projects use Arduino.h instead -// This include is added for compatibility, it will be remove on the next +// This include is added for compatibility, it will be removed on the next // major release of the API #include "../HardwareSerial.h" diff --git a/ArduinoCore-API/api/deprecated/IPAddress.h b/ArduinoCore-API/api/deprecated/IPAddress.h index bf7fb7f..4c03574 100644 --- a/ArduinoCore-API/api/deprecated/IPAddress.h +++ b/ArduinoCore-API/api/deprecated/IPAddress.h @@ -18,7 +18,7 @@ // including IPAddress.h is deprecated, for all future projects use Arduino.h instead -// This include is added for compatibility, it will be remove on the next +// This include is added for compatibility, it will be removed on the next // major release of the API #include "../IPAddress.h" diff --git a/ArduinoCore-API/api/deprecated/Print.h b/ArduinoCore-API/api/deprecated/Print.h index 2ac088d..a0d1bd1 100644 --- a/ArduinoCore-API/api/deprecated/Print.h +++ b/ArduinoCore-API/api/deprecated/Print.h @@ -18,7 +18,7 @@ // including Print.h is deprecated, for all future projects use Arduino.h instead -// This include is added for compatibility, it will be remove on the next +// This include is added for compatibility, it will be removed on the next // major release of the API #include "../Print.h" diff --git a/ArduinoCore-API/api/deprecated/Printable.h b/ArduinoCore-API/api/deprecated/Printable.h index bd72126..b6888c1 100644 --- a/ArduinoCore-API/api/deprecated/Printable.h +++ b/ArduinoCore-API/api/deprecated/Printable.h @@ -18,7 +18,7 @@ // including Printable.h is deprecated, for all future projects use Arduino.h instead -// This include is added for compatibility, it will be remove on the next +// This include is added for compatibility, it will be removed on the next // major release of the API #include "../Printable.h" diff --git a/ArduinoCore-API/api/deprecated/Server.h b/ArduinoCore-API/api/deprecated/Server.h index f3b02c1..65b544b 100644 --- a/ArduinoCore-API/api/deprecated/Server.h +++ b/ArduinoCore-API/api/deprecated/Server.h @@ -18,7 +18,7 @@ // including Server.h is deprecated, for all future projects use Arduino.h instead -// This include is added for compatibility, it will be remove on the next +// This include is added for compatibility, it will be removed on the next // major release of the API #include "../Server.h" diff --git a/ArduinoCore-API/api/deprecated/Stream.h b/ArduinoCore-API/api/deprecated/Stream.h index aa5dc8e..4118ccb 100644 --- a/ArduinoCore-API/api/deprecated/Stream.h +++ b/ArduinoCore-API/api/deprecated/Stream.h @@ -18,7 +18,7 @@ // including Stream.h is deprecated, for all future projects use Arduino.h instead -// This include is added for compatibility, it will be remove on the next +// This include is added for compatibility, it will be removed on the next // major release of the API #include "../Stream.h" diff --git a/ArduinoCore-API/api/deprecated/Udp.h b/ArduinoCore-API/api/deprecated/Udp.h index 5698060..f03a64b 100644 --- a/ArduinoCore-API/api/deprecated/Udp.h +++ b/ArduinoCore-API/api/deprecated/Udp.h @@ -18,7 +18,7 @@ // including Udp.h is deprecated, for all future projects use Arduino.h instead -// This include is added for compatibility, it will be remove on the next +// This include is added for compatibility, it will be removed on the next // major release of the API #include "../Udp.h" diff --git a/ArduinoCore-API/api/deprecated/WString.h b/ArduinoCore-API/api/deprecated/WString.h index 072323e..1a3a79f 100644 --- a/ArduinoCore-API/api/deprecated/WString.h +++ b/ArduinoCore-API/api/deprecated/WString.h @@ -18,7 +18,7 @@ // including WString.h is deprecated, for all future projects use Arduino.h instead -// This include is added for compatibility, it will be remove on the next +// This include is added for compatibility, it will be removed on the next // major release of the API #include "../String.h" diff --git a/ArduinoCore-API/api/itoa.h b/ArduinoCore-API/api/itoa.h index 55b2849..c207783 100644 --- a/ArduinoCore-API/api/itoa.h +++ b/ArduinoCore-API/api/itoa.h @@ -1,4 +1,5 @@ /* + itoa.h - Integer to ASCII conversion Copyright (c) 2016 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or @@ -8,8 +9,8 @@ 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 Lesser General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software diff --git a/ArduinoCore-API/test/.gitignore b/ArduinoCore-API/test/.gitignore new file mode 100644 index 0000000..faa6a97 --- /dev/null +++ b/ArduinoCore-API/test/.gitignore @@ -0,0 +1,19 @@ +build +### CMake ### +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps + +### CMake Patch ### +CMakeUserPresets.json + +# External projects +*-prefix/ diff --git a/ArduinoCore-API/test/CMakeLists.txt b/ArduinoCore-API/test/CMakeLists.txt index 65e15c4..d805024 100644 --- a/ArduinoCore-API/test/CMakeLists.txt +++ b/ArduinoCore-API/test/CMakeLists.txt @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + ########################################################################## cmake_minimum_required(VERSION 2.8) @@ -6,11 +8,20 @@ cmake_minimum_required(VERSION 2.8) project(test-ArduinoCore-API) +Include(FetchContent) + +FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v3.4.0 +) + +FetchContent_MakeAvailable(Catch2) + ########################################################################## -include_directories(../api) +include_directories(..) include_directories(include) -include_directories(external/catch/v2.13.1/include) ########################################################################## @@ -25,16 +36,31 @@ set(TEST_TARGET ${CMAKE_PROJECT_NAME}) ########################################################################## set(TEST_SRCS + src/CanMsg/test_CanMsg.cpp + src/CanMsg/test_CanMsg_CopyCtor.cpp + src/CanMsg/test_CanExtendedId.cpp + src/CanMsg/test_CanStandardId.cpp + src/CanMsg/test_isExtendedId.cpp + src/CanMsg/test_isStandardId.cpp + src/CanMsg/test_operator_assignment.cpp + src/CanMsg/test_printTo.cpp + src/CanMsgRingbuffer/test_available.cpp src/Common/test_makeWord.cpp src/Common/test_map.cpp src/Common/test_max.cpp src/Common/test_min.cpp + src/IPAddress/test_toString.cpp src/IPAddress/test_fromString.cpp + src/IPAddress/test_fromString6.cpp src/IPAddress/test_IPAddress.cpp + src/IPAddress/test_IPAddress6.cpp src/IPAddress/test_operator_assignment.cpp src/IPAddress/test_operator_comparison.cpp + src/IPAddress/test_operator_comparison6.cpp src/IPAddress/test_operator_parentheses.cpp + src/IPAddress/test_operator_parentheses6.cpp src/IPAddress/test_printTo.cpp + src/IPAddress/test_printTo6.cpp src/Print/test_clearWriteError.cpp src/Print/test_getWriteError.cpp src/Print/test_print.cpp @@ -66,6 +92,7 @@ set(TEST_SRCS src/String/test_indexOf.cpp src/String/test_lastIndexOf.cpp src/String/test_length.cpp + src/String/test_move.cpp src/String/test_remove.cpp src/String/test_replace.cpp src/String/test_String.cpp @@ -75,6 +102,7 @@ set(TEST_SRCS src/String/test_toLowerCase.cpp src/String/test_toUpperCase.cpp src/String/test_trim.cpp + src/WCharacter/test_isAscii.cpp src/WCharacter/test_isControl.cpp src/WCharacter/test_isDigit.cpp src/WCharacter/test_isHexadecimalDigit.cpp @@ -83,9 +111,12 @@ set(TEST_SRCS src/WCharacter/test_isSpace.cpp src/WCharacter/test_isUpperCase.cpp src/WCharacter/test_isWhitespace.cpp + src/WCharacter/test_toAscii.cpp ) set(TEST_DUT_SRCS + ../api/CanMsg.cpp + ../api/CanMsgRingbuffer.cpp ../api/Common.cpp ../api/IPAddress.cpp ../api/String.cpp @@ -96,7 +127,6 @@ set(TEST_DUT_SRCS ########################################################################## set(TEST_TARGET_SRCS - src/main.cpp src/dtostrf.cpp src/itoa.cpp src/MillisFake.cpp @@ -112,8 +142,8 @@ add_compile_definitions(HOST) add_compile_options(-Wall -Wextra -Wpedantic -Werror) add_compile_options(-Wno-cast-function-type) -set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "--coverage") -set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "--coverage -Wno-deprecated-copy") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -Wno-deprecated-copy") ########################################################################## @@ -122,5 +152,7 @@ add_executable( ${TEST_TARGET_SRCS} ) +target_link_libraries( ${TEST_TARGET} Catch2WithMain ) + ########################################################################## diff --git a/ArduinoCore-API/test/external/catch/v2.13.1/include/catch.hpp b/ArduinoCore-API/test/external/catch/v2.13.1/include/catch.hpp deleted file mode 100644 index 94e20c2..0000000 --- a/ArduinoCore-API/test/external/catch/v2.13.1/include/catch.hpp +++ /dev/null @@ -1,17802 +0,0 @@ -/* - * Catch v2.13.1 - * Generated: 2020-09-07 12:12:38.090364 - * ---------------------------------------------------------- - * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -// start catch.hpp - - -#define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 13 -#define CATCH_VERSION_PATCH 1 - -#ifdef __clang__ -# pragma clang system_header -#elif defined __GNUC__ -# pragma GCC system_header -#endif - -// start catch_suppress_warnings.h - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(push) -# pragma warning(disable: 161 1682) -# else // __ICC -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wpadded" -# pragma clang diagnostic ignored "-Wswitch-enum" -# pragma clang diagnostic ignored "-Wcovered-switch-default" -# endif -#elif defined __GNUC__ - // Because REQUIREs trigger GCC's -Wparentheses, and because still - // supported version of g++ have only buggy support for _Pragmas, - // Wparentheses have to be suppressed globally. -# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details - -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-variable" -# pragma GCC diagnostic ignored "-Wpadded" -#endif -// end catch_suppress_warnings.h -#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) -# define CATCH_IMPL -# define CATCH_CONFIG_ALL_PARTS -#endif - -// In the impl file, we want to have access to all parts of the headers -// Can also be used to sanely support PCHs -#if defined(CATCH_CONFIG_ALL_PARTS) -# define CATCH_CONFIG_EXTERNAL_INTERFACES -# if defined(CATCH_CONFIG_DISABLE_MATCHERS) -# undef CATCH_CONFIG_DISABLE_MATCHERS -# endif -# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) -# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER -# endif -#endif - -#if !defined(CATCH_CONFIG_IMPL_ONLY) -// start catch_platform.h - -#ifdef __APPLE__ -# include -# if TARGET_OS_OSX == 1 -# define CATCH_PLATFORM_MAC -# elif TARGET_OS_IPHONE == 1 -# define CATCH_PLATFORM_IPHONE -# endif - -#elif defined(linux) || defined(__linux) || defined(__linux__) -# define CATCH_PLATFORM_LINUX - -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) -# define CATCH_PLATFORM_WINDOWS -#endif - -// end catch_platform.h - -#ifdef CATCH_IMPL -# ifndef CLARA_CONFIG_MAIN -# define CLARA_CONFIG_MAIN_NOT_DEFINED -# define CLARA_CONFIG_MAIN -# endif -#endif - -// start catch_user_interfaces.h - -namespace Catch { - unsigned int rngSeed(); -} - -// end catch_user_interfaces.h -// start catch_tag_alias_autoregistrar.h - -// start catch_common.h - -// start catch_compiler_capabilities.h - -// Detect a number of compiler features - by compiler -// The following features are defined: -// -// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? -// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? -// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? -// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? -// **************** -// Note to maintainers: if new toggles are added please document them -// in configuration.md, too -// **************** - -// In general each macro has a _NO_ form -// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. -// Many features, at point of detection, define an _INTERNAL_ macro, so they -// can be combined, en-mass, with the _NO_ forms later. - -#ifdef __cplusplus - -# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) -# define CATCH_CPP14_OR_GREATER -# endif - -# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -# define CATCH_CPP17_OR_GREATER -# endif - -#endif - -#if defined(__cpp_lib_uncaught_exceptions) -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -#endif - -// We have to avoid both ICC and Clang, because they try to mask themselves -// as gcc, and we want only GCC in this block -#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) - -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) - -#endif - -#if defined(__clang__) - -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) - -// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug -// which results in calls to destructors being emitted for each temporary, -// without a matching initialization. In practice, this can result in something -// like `std::string::~string` being called on an uninitialized value. -// -// For example, this code will likely segfault under IBM XL: -// ``` -// REQUIRE(std::string("12") + "34" == "1234") -// ``` -// -// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. -# if !defined(__ibmxl__) -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ -# endif - -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") - -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) - -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) - -#endif // __clang__ - -//////////////////////////////////////////////////////////////////////////////// -// Assume that non-Windows platforms support posix signals by default -#if !defined(CATCH_PLATFORM_WINDOWS) - #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS -#endif - -//////////////////////////////////////////////////////////////////////////////// -// We know some environments not to support full POSIX signals -#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) - #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -#endif - -#ifdef __OS400__ -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# define CATCH_CONFIG_COLOUR_NONE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Android somehow still does not support std::to_string -#if defined(__ANDROID__) -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING -# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Not all Windows environments support SEH properly -#if defined(__MINGW32__) -# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH -#endif - -//////////////////////////////////////////////////////////////////////////////// -// PS4 -#if defined(__ORBIS__) -# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Cygwin -#ifdef __CYGWIN__ - -// Required for some versions of Cygwin to declare gettimeofday -// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin -# define _BSD_SOURCE -// some versions of cygwin (most) do not support std::to_string. Use the libstd check. -// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 -# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ - && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) - -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING - -# endif -#endif // __CYGWIN__ - -//////////////////////////////////////////////////////////////////////////////// -// Visual C++ -#if defined(_MSC_VER) - -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) - -# if _MSC_VER >= 1900 // Visual Studio 2015 or newer -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -# endif - -// Universal Windows platform does not support SEH -// Or console colours (or console at all...) -# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) -# define CATCH_CONFIG_COLOUR_NONE -# else -# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH -# endif - -// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ -// _MSVC_TRADITIONAL == 0 means new conformant preprocessor -// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor -# if !defined(__clang__) // Handle Clang masquerading for msvc -# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) -# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -# endif // MSVC_TRADITIONAL -# endif // __clang__ - -#endif // _MSC_VER - -#if defined(_REENTRANT) || defined(_MSC_VER) -// Enable async processing, as -pthread is specified or no additional linking is required -# define CATCH_INTERNAL_CONFIG_USE_ASYNC -#endif // _MSC_VER - -//////////////////////////////////////////////////////////////////////////////// -// Check if we are compiled with -fno-exceptions or equivalent -#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) -# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED -#endif - -//////////////////////////////////////////////////////////////////////////////// -// DJGPP -#ifdef __DJGPP__ -# define CATCH_INTERNAL_CONFIG_NO_WCHAR -#endif // __DJGPP__ - -//////////////////////////////////////////////////////////////////////////////// -// Embarcadero C++Build -#if defined(__BORLANDC__) - #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN -#endif - -//////////////////////////////////////////////////////////////////////////////// - -// Use of __COUNTER__ is suppressed during code analysis in -// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly -// handled by it. -// Otherwise all supported compilers support COUNTER macro, -// but user still might want to turn it off -#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) - #define CATCH_INTERNAL_CONFIG_COUNTER -#endif - -//////////////////////////////////////////////////////////////////////////////// - -// RTX is a special version of Windows that is real time. -// This means that it is detected as Windows, but does not provide -// the same set of capabilities as real Windows does. -#if defined(UNDER_RTSS) || defined(RTX64_BUILD) - #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH - #define CATCH_INTERNAL_CONFIG_NO_ASYNC - #define CATCH_CONFIG_COLOUR_NONE -#endif - -#if !defined(_GLIBCXX_USE_C99_MATH_TR1) -#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER -#endif - -// Various stdlib support checks that require __has_include -#if defined(__has_include) - // Check if string_view is available and usable - #if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW - #endif - - // Check if optional is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) - - // Check if byte is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # include - # if __cpp_lib_byte > 0 - # define CATCH_INTERNAL_CONFIG_CPP17_BYTE - # endif - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) - - // Check if variant is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # if defined(__clang__) && (__clang_major__ < 8) - // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 - // fix should be in clang 8, workaround in libstdc++ 8.2 - # include - # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) - # define CATCH_CONFIG_NO_CPP17_VARIANT - # else - # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT - # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) - # else - # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT - # endif // defined(__clang__) && (__clang_major__ < 8) - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) -#endif // defined(__has_include) - -#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) -# define CATCH_CONFIG_COUNTER -#endif -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) -# define CATCH_CONFIG_WINDOWS_SEH -#endif -// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_CONFIG_POSIX_SIGNALS -#endif -// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. -#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) -# define CATCH_CONFIG_WCHAR -#endif - -#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) -# define CATCH_CONFIG_CPP11_TO_STRING -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) -# define CATCH_CONFIG_CPP17_OPTIONAL -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) -# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) -# define CATCH_CONFIG_CPP17_STRING_VIEW -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) -# define CATCH_CONFIG_CPP17_VARIANT -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) -# define CATCH_CONFIG_CPP17_BYTE -#endif - -#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) -# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE -#endif - -#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) -# define CATCH_CONFIG_NEW_CAPTURE -#endif - -#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -# define CATCH_CONFIG_DISABLE_EXCEPTIONS -#endif - -#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) -# define CATCH_CONFIG_POLYFILL_ISNAN -#endif - -#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) -# define CATCH_CONFIG_USE_ASYNC -#endif - -#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) -# define CATCH_CONFIG_ANDROID_LOGWRITE -#endif - -#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) -# define CATCH_CONFIG_GLOBAL_NEXTAFTER -#endif - -// Even if we do not think the compiler has that warning, we still have -// to provide a macro that can be used by the code. -#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION -#endif -#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS -#endif - -// The goal of this macro is to avoid evaluation of the arguments, but -// still have the compiler warn on problems inside... -#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) -#endif - -#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) -# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#elif defined(__clang__) && (__clang_major__ < 5) -# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#endif - -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#endif - -#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -#define CATCH_TRY if ((true)) -#define CATCH_CATCH_ALL if ((false)) -#define CATCH_CATCH_ANON(type) if ((false)) -#else -#define CATCH_TRY try -#define CATCH_CATCH_ALL catch (...) -#define CATCH_CATCH_ANON(type) catch (type) -#endif - -#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) -#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#endif - -// end catch_compiler_capabilities.h -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) -#ifdef CATCH_CONFIG_COUNTER -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) -#else -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) -#endif - -#include -#include -#include - -// We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy {}; -std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); - -namespace Catch { - - struct CaseSensitive { enum Choice { - Yes, - No - }; }; - - class NonCopyable { - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable && ) = delete; - NonCopyable& operator = ( NonCopyable const& ) = delete; - NonCopyable& operator = ( NonCopyable && ) = delete; - - protected: - NonCopyable(); - virtual ~NonCopyable(); - }; - - struct SourceLineInfo { - - SourceLineInfo() = delete; - SourceLineInfo( char const* _file, std::size_t _line ) noexcept - : file( _file ), - line( _line ) - {} - - SourceLineInfo( SourceLineInfo const& other ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo( SourceLineInfo&& ) noexcept = default; - SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; - - bool empty() const noexcept { return file[0] == '\0'; } - bool operator == ( SourceLineInfo const& other ) const noexcept; - bool operator < ( SourceLineInfo const& other ) const noexcept; - - char const* file; - std::size_t line; - }; - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - - // Bring in operator<< from global namespace into Catch namespace - // This is necessary because the overload of operator<< above makes - // lookup stop at namespace Catch - using ::operator<<; - - // Use this in variadic streaming macros to allow - // >> +StreamEndStop - // as well as - // >> stuff +StreamEndStop - struct StreamEndStop { - std::string operator+() const; - }; - template - T const& operator + ( T const& value, StreamEndStop ) { - return value; - } -} - -#define CATCH_INTERNAL_LINEINFO \ - ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) - -// end catch_common.h -namespace Catch { - - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - }; - -} // end namespace Catch - -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION - -// end catch_tag_alias_autoregistrar.h -// start catch_test_registry.h - -// start catch_interfaces_testcase.h - -#include - -namespace Catch { - - class TestSpec; - - struct ITestInvoker { - virtual void invoke () const = 0; - virtual ~ITestInvoker(); - }; - - class TestCase; - struct IConfig; - - struct ITestCaseRegistry { - virtual ~ITestCaseRegistry(); - virtual std::vector const& getAllTests() const = 0; - virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; - }; - - bool isThrowSafe( TestCase const& testCase, IConfig const& config ); - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - -} - -// end catch_interfaces_testcase.h -// start catch_stringref.h - -#include -#include -#include -#include - -namespace Catch { - - /// A non-owning string class (similar to the forthcoming std::string_view) - /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. - class StringRef { - public: - using size_type = std::size_t; - using const_iterator = const char*; - - private: - static constexpr char const* const s_empty = ""; - - char const* m_start = s_empty; - size_type m_size = 0; - - public: // construction - constexpr StringRef() noexcept = default; - - StringRef( char const* rawChars ) noexcept; - - constexpr StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - {} - - StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) - {} - - explicit operator std::string() const { - return std::string(m_start, m_size); - } - - public: // operators - auto operator == ( StringRef const& other ) const noexcept -> bool; - auto operator != (StringRef const& other) const noexcept -> bool { - return !(*this == other); - } - - auto operator[] ( size_type index ) const noexcept -> char { - assert(index < m_size); - return m_start[index]; - } - - public: // named queries - constexpr auto empty() const noexcept -> bool { - return m_size == 0; - } - constexpr auto size() const noexcept -> size_type { - return m_size; - } - - // Returns the current start pointer. If the StringRef is not - // null-terminated, throws std::domain_exception - auto c_str() const -> char const*; - - public: // substrings and searches - // Returns a substring of [start, start + length). - // If start + length > size(), then the substring is [start, size()). - // If start > size(), then the substring is empty. - auto substr( size_type start, size_type length ) const noexcept -> StringRef; - - // Returns the current start pointer. May not be null-terminated. - auto data() const noexcept -> char const*; - - constexpr auto isNullTerminated() const noexcept -> bool { - return m_start[m_size] == '\0'; - } - - public: // iterators - constexpr const_iterator begin() const { return m_start; } - constexpr const_iterator end() const { return m_start + m_size; } - }; - - auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; - auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - - constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { - return StringRef( rawChars, size ); - } -} // namespace Catch - -constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { - return Catch::StringRef( rawChars, size ); -} - -// end catch_stringref.h -// start catch_preprocessor.hpp - - -#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ -#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) - -#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ -// MSVC needs more evaluations -#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) -#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) -#else -#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) -#endif - -#define CATCH_REC_END(...) -#define CATCH_REC_OUT - -#define CATCH_EMPTY() -#define CATCH_DEFER(id) id CATCH_EMPTY() - -#define CATCH_REC_GET_END2() 0, CATCH_REC_END -#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 -#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 -#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT -#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) -#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) - -#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) - -#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) - -// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, -// and passes userdata as the first parameter to each invocation, -// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) -#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) - -#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) - -#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) -#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ -#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ -#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF -#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) -#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ -#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) -#else -// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF -#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) -#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ -#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) -#endif - -#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ -#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) - -#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) - -#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) -#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) -#else -#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) -#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) -#endif - -#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ - CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) - -#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) -#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) -#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) -#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) -#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) -#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) -#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) -#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) -#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) -#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) -#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) - -#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N - -#define INTERNAL_CATCH_TYPE_GEN\ - template struct TypeList {};\ - template\ - constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ - template class...> struct TemplateTypeList{};\ - template class...Cs>\ - constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ - template\ - struct append;\ - template\ - struct rewrap;\ - template class, typename...>\ - struct create;\ - template class, typename>\ - struct convert;\ - \ - template \ - struct append { using type = T; };\ - template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ - struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ - template< template class L1, typename...E1, typename...Rest>\ - struct append, TypeList, Rest...> { using type = L1; };\ - \ - template< template class Container, template class List, typename...elems>\ - struct rewrap, List> { using type = TypeList>; };\ - template< template class Container, template class List, class...Elems, typename...Elements>\ - struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ - \ - template