From 16cf83dc4178f3bb766332ff7b4e638f9491622e Mon Sep 17 00:00:00 2001 From: slaff Date: Wed, 24 Jul 2024 13:20:05 +0200 Subject: [PATCH 01/34] Possible DnsServer memory leak reported by coverity (#2870) --- Sming/Components/Network/src/Network/DnsServer.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Sming/Components/Network/src/Network/DnsServer.cpp b/Sming/Components/Network/src/Network/DnsServer.cpp index 5479e5e072..3e8c8e24ad 100644 --- a/Sming/Components/Network/src/Network/DnsServer.cpp +++ b/Sming/Components/Network/src/Network/DnsServer.cpp @@ -84,9 +84,6 @@ void DnsServer::onReceive(pbuf* buf, IpAddress remoteIP, uint16_t remotePort) } unsigned requestLen = pbuf_copy_partial(buf, buffer, buf->tot_len, 0); - if(requestLen != buf->tot_len) { - return; - } debug_hex(DBG, "< DNS", buffer, requestLen); @@ -97,8 +94,6 @@ void DnsServer::onReceive(pbuf* buf, IpAddress remoteIP, uint16_t remotePort) } delete[] buffer; - - UdpConnection::onReceive(buf, remoteIP, remotePort); } size_t DnsServer::processQuestion(char* buffer, size_t requestLen) From f8d10e61e9be7b38e186e659226936cae7f9f46b Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 7 Aug 2024 06:22:10 +0100 Subject: [PATCH 02/34] Add `PrintBuffer` classes (#2873) Using ArduinoJson to serialize directly to a file stream performs poorly because writes are done byte-by-byte. This issue is mentioned under [performance](https://arduinojson.org/v6/api/json/serializejson/). The mentioned [ArduinoStreamUtils](https://github.com/bblanchon/ArduinoStreamUtils) library is a bit hefty and doesn't particular fit with the existing Sming stream classes. This PR adds a very simple `PrintBuffer` class which operates on a `Print` output and can be employed very easily if additional generic buffering is required. Note that there is little benefit to using this with other memory-based streams so best left to the library or application to decide when its appropriate. --- Sming/Core/Data/Buffer/PrintBuffer.cpp | 43 +++++ Sming/Core/Data/Buffer/PrintBuffer.h | 155 ++++++++++++++++++ docs/source/framework/core/data/buffering.rst | 15 ++ 3 files changed, 213 insertions(+) create mode 100644 Sming/Core/Data/Buffer/PrintBuffer.cpp create mode 100644 Sming/Core/Data/Buffer/PrintBuffer.h create mode 100644 docs/source/framework/core/data/buffering.rst diff --git a/Sming/Core/Data/Buffer/PrintBuffer.cpp b/Sming/Core/Data/Buffer/PrintBuffer.cpp new file mode 100644 index 0000000000..33b63a1e8f --- /dev/null +++ b/Sming/Core/Data/Buffer/PrintBuffer.cpp @@ -0,0 +1,43 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * PrintBuffer.cpp + * + ****/ + +#include "PrintBuffer.h" + +size_t BasePrintBuffer::write(uint8_t c) +{ + buffer[writeOffset++] = c; + if(writeOffset == bufferSize) { + flush(); + } + return 1; +} + +size_t BasePrintBuffer::write(const uint8_t* data, size_t size) +{ + size_t written{0}; + while(size != 0) { + auto copySize = std::min(bufferSize - writeOffset, size); + memcpy(&buffer[writeOffset], data, copySize); + writeOffset += copySize; + written += copySize; + data += copySize; + size -= copySize; + if(writeOffset == bufferSize) { + flush(); + } + } + return written; +} + +void BasePrintBuffer::flush() +{ + output.write(buffer, writeOffset); + writeOffset = 0; +} diff --git a/Sming/Core/Data/Buffer/PrintBuffer.h b/Sming/Core/Data/Buffer/PrintBuffer.h new file mode 100644 index 0000000000..09d683d1b9 --- /dev/null +++ b/Sming/Core/Data/Buffer/PrintBuffer.h @@ -0,0 +1,155 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * PrintBuffer.h + * + ****/ + +#pragma once + +#include +#include + +/** + * @brief Generic write-through buffer class + * @ingroup stream + * @note Call flush() at end of write operation to ensure all data is output + * This is done automatically when the buffer is destroyed. + */ +class BasePrintBuffer : public Print +{ +public: + /** + * @brief Create buffer + * @param output Destination stream + * @param buffer buffer to use + * @param size Size of buffer + */ + BasePrintBuffer(Print& output, uint8_t buffer[], size_t bufferSize) + : output(output), buffer(buffer), bufferSize(bufferSize) + { + } + + ~BasePrintBuffer() + { + flush(); + } + + size_t write(uint8_t c) override; + + size_t write(const uint8_t* data, size_t size) override; + + /** + * @brief Write any buffered content to output + */ + void flush(); + +private: + Print& output; + uint8_t* buffer; + size_t bufferSize; + size_t writeOffset{}; +}; + +/** + * @brief Write-through buffer using stack only + * @tparam size Size of buffer + * + * Example usage: + * + * FileStream stream("file.txt", File::ReadWrite); + * { + * StaticPrintBuffer<256> buffer(stream); + * writeSomeData(buffer); + * } // Buffer flushed and destroyed when it goes out of scope + */ +template class StaticPrintBuffer : public BasePrintBuffer +{ +public: + /** + * @brief Construct a stack-based buffer + * @param output Print destination + */ + StaticPrintBuffer(Print& output) : BasePrintBuffer(output, buffer, size) + { + } + +private: + uint8_t buffer[size]; +}; + +/** + * @brief Write-through buffer using heap storage + * + * Example usage: + * + * FileStream stream("file.txt", File::ReadWrite); + * { + * HeapPrintBuffer buffer(stream, 512); + * writeSomeData(buffer); + * } // Buffer flushed and destroyed when it goes out of scope + */ +class HeapPrintBuffer : public BasePrintBuffer +{ +public: + /** + * @brief Construct a stack-based buffer + * @param output Print destination + * @param size Buffer size + */ + HeapPrintBuffer(Print& output, size_t size) : HeapPrintBuffer(output, new uint8_t[size], size) + { + } + +private: + HeapPrintBuffer(Print& output, uint8_t* buffer, size_t size) : BasePrintBuffer(output, buffer, size), buffer(buffer) + { + } + + std::unique_ptr buffer; +}; + +/** + * @brief Write-through buffer using heap storage and owned stream pointer + * + * Example usage: + * + * auto stream = std::make_unique("file.txt", File::ReadWrite); + * auto bufferedStream = new DynamicPrintBuffer(std::move(stream), 512); + * + * // write to bufferedStream as required via callbacks, etc. + * ... + * + * // This destroys both buffer *and* the file stream + * delete bufferedStream; + */ +class DynamicPrintBuffer : public BasePrintBuffer +{ +public: + /** + * @brief Construct a stack-based buffer + * @param output Print destination, will take ownership of this + * @param size Buffer size + */ + DynamicPrintBuffer(std::unique_ptr&& output, size_t size) + : DynamicPrintBuffer(output.release(), new uint8_t[size], size) + { + } + + ~DynamicPrintBuffer() + { + flush(); + } + +private: + DynamicPrintBuffer(Print* output, uint8_t* buffer, size_t size) + : BasePrintBuffer(*output, buffer, size), output(output), buffer(buffer) + { + } + + std::unique_ptr output; + std::unique_ptr buffer; +}; diff --git a/docs/source/framework/core/data/buffering.rst b/docs/source/framework/core/data/buffering.rst new file mode 100644 index 0000000000..fe5d1054d8 --- /dev/null +++ b/docs/source/framework/core/data/buffering.rst @@ -0,0 +1,15 @@ +Buffering +========= + +In general, writing efficiently to files is best done in chunks, such as by building a line of data in a :cpp:class:`String` and writing it in one go. + +Sming offers a simple write-through buffering mechanism which can be used where necessary. The :library:`ArduinoJson` can benefit greatly from this. + +.. doxygenclass:: StaticPrintBuffer + :members: + +.. doxygenclass:: HeapPrintBuffer + :members: + +.. doxygenclass:: DynamicPrintBuffer + :members: From 07bc4121b35ea5ed83c6359cafca479b664153d7 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 13 Aug 2024 15:22:42 +0100 Subject: [PATCH 03/34] Translate common host errno values to standard IFS errors (#2874) Rather than return system error values, translate errors such as 'file not found' to standard IFS code, for consistency with embedded builds. --- Sming/Components/IFS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sming/Components/IFS b/Sming/Components/IFS index e57c5c9359..d30afecbd6 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit e57c5c93591fa062fa879bd61cfd13d2b104b529 +Subproject commit d30afecbd6e55fa9d2af9d905dcc1edb8564b4d8 From daa4db6608f47bbd24c5b28fc768249c3f98eaa5 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 16 Aug 2024 07:35:34 +0100 Subject: [PATCH 04/34] Add string escaping to JSON formatter (#2875) JSON does not support multiline text so control characters must be escaped. This PR adds a generic `escapeControls` function to the `Formatter` classes, which is used by `Format::json::escape()`. --- Sming/Core/Data/Format/Formatter.cpp | 98 +++++++++++++++++++++++++++ Sming/Core/Data/Format/Formatter.h | 7 ++ Sming/Core/Data/Format/Json.cpp | 3 +- tests/HostTests/include/modules.h | 1 + tests/HostTests/modules/Formatter.cpp | 30 ++++++++ 5 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 Sming/Core/Data/Format/Formatter.cpp create mode 100644 tests/HostTests/modules/Formatter.cpp diff --git a/Sming/Core/Data/Format/Formatter.cpp b/Sming/Core/Data/Format/Formatter.cpp new file mode 100644 index 0000000000..f519306f6f --- /dev/null +++ b/Sming/Core/Data/Format/Formatter.cpp @@ -0,0 +1,98 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Formatter.cpp + * + * @author mikee47 Aug 2024 + * + ****/ + +#include "Formatter.h" + +namespace +{ +/** + * @brief Get character used for standard escapes + * @param c Code to be escaped + * @retval char Corresponding character, NUL if there isn't a standard escape + */ +char escapeChar(char c) +{ + switch(c) { + case '\0': + return '0'; + case '\'': + return '\''; + case '\"': + return '"'; + case '\?': + return '?'; + case '\\': + return '\\'; + case '\a': + return 'a'; + case '\b': + return 'b'; + case '\f': + return 'f'; + case '\n': + return 'n'; + case '\r': + return 'r'; + case '\t': + return 't'; + case '\v': + return 'v'; + default: + return '\0'; + } +} + +} // namespace + +namespace Format +{ +unsigned escapeControls(String& value) +{ + // Count number of extra characters we'll need to insert + unsigned extra{0}; + for(auto& c : value) { + if(escapeChar(c)) { + extra += 1; // "\" + } else if(uint8_t(c) < 0x20) { + extra += 3; // "\xnn" + } + } + if(extra == 0) { + return 0; + } + auto len = value.length(); + if(!value.setLength(len + extra)) { + return 0; + } + char* out = value.begin(); + const char* in = out; + memmove(out + extra, in, len); + in += extra; + while(len--) { + uint8_t c = *in++; + auto esc = escapeChar(c); + if(esc) { + *out++ = '\\'; + *out++ = esc; + } else if(c < 0x20) { + *out++ = '\\'; + *out++ = 'x'; + *out++ = hexchar(uint8_t(c) >> 4); + *out++ = hexchar(uint8_t(c) & 0x0f); + } else { + *out++ = c; + } + } + return extra; +} + +} // namespace Format diff --git a/Sming/Core/Data/Format/Formatter.h b/Sming/Core/Data/Format/Formatter.h index 993e0dd61c..9b45322165 100644 --- a/Sming/Core/Data/Format/Formatter.h +++ b/Sming/Core/Data/Format/Formatter.h @@ -17,6 +17,13 @@ namespace Format { +/** + * @brief Escape standard control codes such as `\n` (below ASCII 0x20) + * @param value String to be modified + * @retval unsigned Number of control characters found and replaced + */ +unsigned escapeControls(String& value); + /** * @brief Virtual class to perform format-specific String adjustments */ diff --git a/Sming/Core/Data/Format/Json.cpp b/Sming/Core/Data/Format/Json.cpp index d2f15f46ca..536bb017df 100644 --- a/Sming/Core/Data/Format/Json.cpp +++ b/Sming/Core/Data/Format/Json.cpp @@ -63,11 +63,10 @@ bool IsValidUtf8(const char* str, unsigned length) * * This can occur if filenames become corrupted, so here we just * substitute an underscore _ for anything which fails to match UTF8. - * - * TODO: Perform ANSI -> UTF8 conversion? */ void Json::escape(String& value) const { + escapeControls(value); if(!IsValidUtf8(value.c_str(), value.length())) { debug_w("Invalid UTF8: %s", value.c_str()); for(unsigned i = 0; i < value.length(); ++i) { diff --git a/tests/HostTests/include/modules.h b/tests/HostTests/include/modules.h index d29f54e112..037dedb112 100644 --- a/tests/HostTests/include/modules.h +++ b/tests/HostTests/include/modules.h @@ -29,6 +29,7 @@ XX(CStringArray) \ XX(Stream) \ XX(TemplateStream) \ + XX(Formatter) \ XX(Serial) \ XX(ObjectMap) \ XX_NET(Base64) \ diff --git a/tests/HostTests/modules/Formatter.cpp b/tests/HostTests/modules/Formatter.cpp new file mode 100644 index 0000000000..38fbd0bbca --- /dev/null +++ b/tests/HostTests/modules/Formatter.cpp @@ -0,0 +1,30 @@ +#include +#include + +class FormatterTest : public TestGroup +{ +public: + FormatterTest() : TestGroup(_F("Formatter")) + { + } + + void execute() override + { + DEFINE_FSTR_LOCAL(text1, "A JSON\ntest string\twith escapes\x12\0\n" + "Worth maybe \xc2\xa3" + "0.53.") + DEFINE_FSTR_LOCAL(text1b, "A JSON\\ntest string\\twith escapes\\x12\\0\\n" + "Worth maybe \xc2\xa3" + "0.53.") + + Serial << text1 << endl; + String s(text1); + Format::json.escape(s); + REQUIRE_EQ(s, text1b); + } +}; + +void REGISTER_TEST(Formatter) +{ + registerGroup(); +} From 3378a0c20dc614d4515855e6ba556cacc1aa7c1d Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 24 Aug 2024 06:25:20 +0100 Subject: [PATCH 05/34] Fix conflict with stdc++ `operator delete[](void*, size_t)` (#2877) --- Sming/Arch/Esp8266/Components/heap/alloc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sming/Arch/Esp8266/Components/heap/alloc.cpp b/Sming/Arch/Esp8266/Components/heap/alloc.cpp index 67e5b1ccbd..ba4e59a96c 100644 --- a/Sming/Arch/Esp8266/Components/heap/alloc.cpp +++ b/Sming/Arch/Esp8266/Components/heap/alloc.cpp @@ -46,7 +46,7 @@ void operator delete(void* ptr, size_t) free(ptr); } -void operator delete[](void* ptr, size_t) +void __attribute__((weak)) operator delete[](void* ptr, size_t) { free(ptr); } From 4fff8a8384cb9a32e46627637da8cf4b78ce9270 Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 31 Aug 2024 13:13:06 +0100 Subject: [PATCH 06/34] `dtostrf_p` doesn't handle advertised range (#2879) Code indicates range of +/- 4294967040.0 but that isn't achievable using `ltoa` (signed) call. --- Sming/System/stringconversion.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sming/System/stringconversion.cpp b/Sming/System/stringconversion.cpp index 43cb89cb81..9432a46ee8 100644 --- a/Sming/System/stringconversion.cpp +++ b/Sming/System/stringconversion.cpp @@ -160,7 +160,7 @@ char *dtostrf_p(double floatVar, int minStringWidthIncDecimalPoint, int numDigit int_part = (unsigned long) floatVar; //print the int part into num - char* s = ltoa(int_part, buf, 10); + char* s = ultoa(int_part, buf, 10); //adjust end pointer buf += strlen(s); //go to end of string @@ -171,7 +171,7 @@ char *dtostrf_p(double floatVar, int minStringWidthIncDecimalPoint, int numDigit *buf++ = '.'; // print the decimal point //print the fraction part into temp - s = ltoa( ((floatVar - int_part) * mult), temp, 10); + s = ultoa( ((floatVar - int_part) * mult), temp, 10); i = processedFracLen - strlen(s) + 1; From 2d332434fced170542777d8fdfe2338ebb0d2420 Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 31 Aug 2024 13:13:56 +0100 Subject: [PATCH 07/34] Add `EEXIST` to common host errors, don't fail when creating directories (#2878) Calling `mkdir` when a directory exists returns `EEXIST` error, which we want to map to `IFS::Error::Exists`. In `makeDirectories` call, it's not an error if an intermediate directory exists, otherwise the whole call will fail. --- Sming/Components/IFS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sming/Components/IFS b/Sming/Components/IFS index d30afecbd6..50bd7363e4 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit d30afecbd6e55fa9d2af9d905dcc1edb8564b4d8 +Subproject commit 50bd7363e4373a3c2a59f7dae695f6f93f5aa51b From 6caca47a776ba3997218e60403a45b882adf0eaf Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 31 Aug 2024 13:15:07 +0100 Subject: [PATCH 08/34] Include unicode formatting support for JSON escapes (#2880) This PR improves on #2875 for JSON string formatting, updating the `escapeControls` function to handle unicode escaping correctly. The check for valid UTF8 has been removed. That's erroneous and got in there because of my lack of understanding about how JSON is encoded. It's fundamentally UNICODE, so characters outside of standard ASCII must all be encoded using `\uNNNN` escapes. That ensures output is always valid JSON, even if string input is garbage. The `escapeControls` function has a `options` parameter which makes it a lot more useful for various escaping requirements. This is also more efficient as the input string requires only two passes for both escaping and quoting: the first pass establishes the new string length, the buffer is re-allocated then the modified string produced. --- Sming/Core/Data/Format/Formatter.cpp | 54 ++++++++++++++--------- Sming/Core/Data/Format/Formatter.h | 13 +++++- Sming/Core/Data/Format/Json.cpp | 62 ++++++--------------------- Sming/Core/Data/Format/Json.h | 1 + tests/HostTests/modules/Formatter.cpp | 44 ++++++++++++++----- 5 files changed, 92 insertions(+), 82 deletions(-) diff --git a/Sming/Core/Data/Format/Formatter.cpp b/Sming/Core/Data/Format/Formatter.cpp index f519306f6f..546900a25a 100644 --- a/Sming/Core/Data/Format/Formatter.cpp +++ b/Sming/Core/Data/Format/Formatter.cpp @@ -12,26 +12,25 @@ #include "Formatter.h" -namespace +namespace Format { /** * @brief Get character used for standard escapes * @param c Code to be escaped + * @param options * @retval char Corresponding character, NUL if there isn't a standard escape */ -char escapeChar(char c) +char escapeChar(char c, Options options) { switch(c) { case '\0': - return '0'; - case '\'': - return '\''; + return options[Option::unicode] ? '\0' : '0'; case '\"': - return '"'; - case '\?': - return '?'; + return options[Option::doublequote] ? c : '\0'; + case '\'': + return options[Option::singlequote] ? c : '\0'; case '\\': - return '\\'; + return options[Option::backslash] ? c : '\0'; case '\a': return 'a'; case '\b': @@ -51,19 +50,22 @@ char escapeChar(char c) } } -} // namespace - -namespace Format -{ -unsigned escapeControls(String& value) +unsigned escapeControls(String& value, Options options) { // Count number of extra characters we'll need to insert unsigned extra{0}; for(auto& c : value) { - if(escapeChar(c)) { + if(escapeChar(c, options)) { extra += 1; // "\" + } else if(options[Option::unicode]) { + if(uint8_t(c) < 0x20 || (c & 0x80)) { + extra += 5; // "\uNNNN" + } } else if(uint8_t(c) < 0x20) { extra += 3; // "\xnn" + } else if((c & 0x80) && options[Option::utf8]) { + // Characters such as £ (0xa3) are escaped to 0xc2 0xa3 in UTF-8 + extra += 1; // 0xc2 } } if(extra == 0) { @@ -79,18 +81,28 @@ unsigned escapeControls(String& value) in += extra; while(len--) { uint8_t c = *in++; - auto esc = escapeChar(c); + auto esc = escapeChar(c, options); if(esc) { *out++ = '\\'; - *out++ = esc; - } else if(c < 0x20) { + c = esc; + } else if(options[Option::unicode]) { + if(uint8_t(c) < 0x20 || (c & 0x80)) { + *out++ = '\\'; + *out++ = 'u'; + *out++ = '0'; + *out++ = '0'; + *out++ = hexchar(uint8_t(c) >> 4); + c = hexchar(uint8_t(c) & 0x0f); + } + } else if(uint8_t(c) < 0x20) { *out++ = '\\'; *out++ = 'x'; *out++ = hexchar(uint8_t(c) >> 4); - *out++ = hexchar(uint8_t(c) & 0x0f); - } else { - *out++ = c; + c = hexchar(uint8_t(c) & 0x0f); + } else if((c & 0x80) && options[Option::utf8]) { + *out++ = 0xc2; } + *out++ = c; } return extra; } diff --git a/Sming/Core/Data/Format/Formatter.h b/Sming/Core/Data/Format/Formatter.h index 9b45322165..45e59aeb84 100644 --- a/Sming/Core/Data/Format/Formatter.h +++ b/Sming/Core/Data/Format/Formatter.h @@ -14,15 +14,26 @@ #include #include +#include namespace Format { +enum class Option { + unicode, //< Use unicode escapes \uNNNN, otherwise hex \xNN + utf8, ///< Convert extended ASCII to UTF8 + doublequote, + singlequote, + backslash, +}; +using Options = BitSet; + /** * @brief Escape standard control codes such as `\n` (below ASCII 0x20) * @param value String to be modified + * @param options * @retval unsigned Number of control characters found and replaced */ -unsigned escapeControls(String& value); +unsigned escapeControls(String& value, Options options); /** * @brief Virtual class to perform format-specific String adjustments diff --git a/Sming/Core/Data/Format/Json.cpp b/Sming/Core/Data/Format/Json.cpp index 536bb017df..522e96757a 100644 --- a/Sming/Core/Data/Format/Json.cpp +++ b/Sming/Core/Data/Format/Json.cpp @@ -17,46 +17,6 @@ namespace Format { Json json; -namespace -{ -bool IsValidUtf8(const char* str, unsigned length) -{ - if(str == nullptr) { - return true; - } - - unsigned i = 0; - while(i < length) { - char c = str[i++]; - if((c & 0x80) == 0) { - continue; - } - - if(i >= length) { - return false; // incomplete multibyte char - } - - if(c & 0x20) { - c = str[i++]; - if((c & 0xC0) != 0x80) { - return false; // malformed trail byte or out of range char - } - if(i >= length) { - return false; // incomplete multibyte char - } - } - - c = str[i++]; - if((c & 0xC0) != 0x80) { - return false; // malformed trail byte - } - } - - return true; -} - -} // namespace - /* * Check for invalid characters and replace them - can break browser * operation otherwise. @@ -66,17 +26,19 @@ bool IsValidUtf8(const char* str, unsigned length) */ void Json::escape(String& value) const { - escapeControls(value); - if(!IsValidUtf8(value.c_str(), value.length())) { - debug_w("Invalid UTF8: %s", value.c_str()); - for(unsigned i = 0; i < value.length(); ++i) { - char& c = value[i]; - if(c < 0x20 || uint8_t(c) > 127) - c = '_'; - } - } + escapeControls(value, Option::unicode | Option::doublequote | Option::backslash); +} - value.replace("\"", "\\\""); +void Json::quote(String& value) const +{ + escape(value); + auto len = value.length(); + if(value.setLength(len + 2)) { + auto s = value.begin(); + memmove(s + 1, s, len); + s[0] = '"'; + s[len + 1] = '"'; + } } } // namespace Format diff --git a/Sming/Core/Data/Format/Json.h b/Sming/Core/Data/Format/Json.h index 2c7f35f983..4abd2a7ee4 100644 --- a/Sming/Core/Data/Format/Json.h +++ b/Sming/Core/Data/Format/Json.h @@ -20,6 +20,7 @@ class Json : public Standard { public: void escape(String& value) const override; + void quote(String& value) const override; MimeType mimeType() const override { diff --git a/tests/HostTests/modules/Formatter.cpp b/tests/HostTests/modules/Formatter.cpp index 38fbd0bbca..0e0593f4e7 100644 --- a/tests/HostTests/modules/Formatter.cpp +++ b/tests/HostTests/modules/Formatter.cpp @@ -10,17 +10,41 @@ class FormatterTest : public TestGroup void execute() override { + // Note: \xa3 is unicode for £ DEFINE_FSTR_LOCAL(text1, "A JSON\ntest string\twith escapes\x12\0\n" - "Worth maybe \xc2\xa3" - "0.53.") - DEFINE_FSTR_LOCAL(text1b, "A JSON\\ntest string\\twith escapes\\x12\\0\\n" - "Worth maybe \xc2\xa3" - "0.53.") - - Serial << text1 << endl; - String s(text1); - Format::json.escape(s); - REQUIRE_EQ(s, text1b); + "Worth \"maybe\" \xa3 0.53. Yen \xa5 5bn.") + + TEST_CASE("JSON") + { + DEFINE_FSTR_LOCAL(text1b, "A JSON\\ntest string\\twith escapes\\u0012\\u0000\\n" + "Worth \\\"maybe\\\" \\u00a3 0.53. Yen \\u00a5 5bn.") + + Serial << text1 << endl; + String s(text1); + Format::json.escape(s); + REQUIRE_EQ(s, text1b); + + s = text1; + Format::json.quote(s); + String quoted = String('"') + text1b + '"'; + REQUIRE_EQ(s, quoted); + } + + TEST_CASE("C++") + { + DEFINE_FSTR_LOCAL( + text1a, "A JSON\\ntest string\\twith escapes\\x12\\0\\nWorth \\\"maybe\\\" \xa3 0.53. Yen \xa5 5bn.") + String s(text1); + Format::escapeControls(s, Format::Option::doublequote | Format::Option::backslash); + REQUIRE_EQ(s, text1a); + + DEFINE_FSTR_LOCAL( + text1b, + "A JSON\\ntest string\\twith escapes\\x12\\0\\nWorth \\\"maybe\\\" \xc2\xa3 0.53. Yen \xc2\xa5 5bn.") + s = text1; + Format::escapeControls(s, Format::Option::utf8 | Format::Option::doublequote | Format::Option::backslash); + REQUIRE_EQ(s, text1b); + } } }; From 1e39a56ea574719f689ddc07c75107b0fc6bebad Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 31 Aug 2024 13:16:11 +0100 Subject: [PATCH 09/34] Revise `bodyToStringParser` to use MemoryDataStream (#2881) Better dynamic memory reallocation and avoids conversion to MemoryDataStream at end anyway. Still has the weakness that the decode is unbounded so bad actors can kill system with large POST. --- .../Network/src/Network/Http/HttpBodyParser.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Sming/Components/Network/src/Network/Http/HttpBodyParser.cpp b/Sming/Components/Network/src/Network/Http/HttpBodyParser.cpp index e5cd17aa1d..27923700a4 100644 --- a/Sming/Components/Network/src/Network/Http/HttpBodyParser.cpp +++ b/Sming/Components/Network/src/Network/Http/HttpBodyParser.cpp @@ -16,6 +16,7 @@ #include "HttpBodyParser.h" #include +#include /* * Content is received in chunks which we need to reassemble into name=value pairs. @@ -103,11 +104,11 @@ size_t formUrlParser(HttpRequest& request, const char* at, int length) size_t bodyToStringParser(HttpRequest& request, const char* at, int length) { - auto data = static_cast(request.args); + auto data = static_cast(request.args); if(length == PARSE_DATASTART) { delete data; - data = new String(); + data = new MemoryDataStream(); request.args = data; return 0; } @@ -118,15 +119,10 @@ size_t bodyToStringParser(HttpRequest& request, const char* at, int length) } if(length == PARSE_DATAEND || length < 0) { - request.setBody(std::move(*data)); - delete data; + request.setBody(data); request.args = nullptr; return 0; } - if(!data->concat(at, length)) { - return 0; - } - - return length; + return data->write(at, length); } From c79add624b9507422f1612cd705c1904d0ec55e9 Mon Sep 17 00:00:00 2001 From: slaff Date: Mon, 16 Sep 2024 09:24:52 +0200 Subject: [PATCH 10/34] Remove official support for older ESP32 IDF versions: 4.3, 4.4 and 5.0. (#2882) It is highly recommended to upgrade to version 5.2 if not done yet. Co-authored-by: Slavey Karadzhov --- .github/workflows/ci-esp32.yml | 17 ++--------------- .github/workflows/library.yml | 13 +------------ Sming/Arch/Esp32/README.rst | 6 +++--- Sming/Arch/Esp32/app.mk | 4 ++-- 4 files changed, 8 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci-esp32.yml b/.github/workflows/ci-esp32.yml index 21e3d98dab..7425093506 100644 --- a/.github/workflows/ci-esp32.yml +++ b/.github/workflows/ci-esp32.yml @@ -15,20 +15,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] variant: [esp32, esp32s2, esp32c3, esp32s3, esp32c2] - idf_version: ["4.4", "5.0", "5.2"] - include: - - os: ubuntu-latest - variant: esp32 - idf_version: "4.3" - exclude: - - variant: esp32c2 - idf_version: "4.4" - - os: macos-latest - idf_version: "4.4" - - os: macos-latest - idf_version: "5.0" - - os: windows-latest - idf_version: "5.0" + idf_version: ["5.2"] concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ toJson(matrix) }} @@ -58,7 +45,7 @@ jobs: - name: Setup python uses: actions/setup-python@v5 with: - python-version: ${{ matrix.idf_version == '4.3' && '3.8' || '3.12' }} + python-version: '3.12' - name: Fix permissions if: matrix.os != 'windows-latest' diff --git a/.github/workflows/library.yml b/.github/workflows/library.yml index 7a02c305b6..fa9c35a995 100644 --- a/.github/workflows/library.yml +++ b/.github/workflows/library.yml @@ -23,7 +23,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] variant: [esp8266, host, esp32, esp32s2, esp32c3, esp32s3, esp32c2, rp2040] - idf_version: ["4.4", ""] # "" denotes default, currently 5.2 + idf_version: [""] # "" denotes default, currently 5.2 toolchain: [gcc] include: - variant: esp8266 @@ -50,17 +50,6 @@ jobs: arch: Esp32 - variant: rp2040 arch: Rp2040 - exclude: - - variant: esp32c2 - idf_version: "4.4" - - variant: esp8266 - idf_version: "4.4" - - variant: host - idf_version: "4.4" - - variant: rp2040 - idf_version: "4.4" - - os: macos-latest - idf_version: "4.4" concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ toJson(matrix) }} diff --git a/Sming/Arch/Esp32/README.rst b/Sming/Arch/Esp32/README.rst index da97dc290f..f2c60083c6 100644 --- a/Sming/Arch/Esp32/README.rst +++ b/Sming/Arch/Esp32/README.rst @@ -116,9 +116,9 @@ See :component-esp32:`esp32` for further details. IDF versions ------------ -Sming currently supports IDF versions 4.3, 4.4, 5.0 and 5.2. -The recommended version is 5.2. -This is installed by default. +Sming currently supports IDF versions 5.2. This is installed by default. +Older versions 4.3, 4.4 and 5.0 are no longer officially supported. If you use one of the old versions, please, consider upgrading to 5.2. + A different version can be installed if necessary:: diff --git a/Sming/Arch/Esp32/app.mk b/Sming/Arch/Esp32/app.mk index f06d8165a6..5447ac34d1 100644 --- a/Sming/Arch/Esp32/app.mk +++ b/Sming/Arch/Esp32/app.mk @@ -25,9 +25,9 @@ endif .PHONY: application application: $(TARGET_BIN) ifeq ($(IDF_VERSION),v4.3) - @printf "\033[47;1;31mWARNING! ESP-IDF 4.3 reached 'End of Life' in December 2023.\033[0m Upgrade to v5.2 recommended.\n" + @printf "\033[47;1;31mWARNING! ESP-IDF 4.3 reached 'End of Life' in December 2023.\033[0m Please upgrade to v5.2.\n" else ifeq ($(IDF_VERSION),v4.4) - @printf "\033[47;1;31mWARNING! ESP-IDF 4.4 support ends August 2024!\033[0m Upgrade to v5.2 recommended.\n" + @printf "\033[47;1;31mWARNING! ESP-IDF 4.4 support has ended in August 2024!\033[0m Please upgrade to v5.2.\n" else ifeq ($(IDF_VERSION),v5.0) @printf "\033[47;1;34mNOTE! ESP-IDF 5.0 not recommended for new designs.\033[0m Please consider upgrading to v5.2.\n" endif From 3cb6f28a9ac13ff8d47adf30d68f06c6314a6a83 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 16 Sep 2024 10:37:13 +0100 Subject: [PATCH 11/34] Fix MallocCount for MinGW (#2884) MinGW defines aliases in stdlib.h for `realloc` and `free` which require wrapping. --- Sming/Components/malloc_count/component.mk | 5 +++++ Sming/Components/malloc_count/malloc_count.cpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/Sming/Components/malloc_count/component.mk b/Sming/Components/malloc_count/component.mk index 7089c0962f..5579848cd1 100644 --- a/Sming/Components/malloc_count/component.mk +++ b/Sming/Components/malloc_count/component.mk @@ -29,6 +29,11 @@ MC_WRAP_FUNCS += \ pvPortZallocIram \ vPortFree endif +ifeq ($(SMING_ARCH)$(UNAME),HostWindows) +MC_WRAP_FUNCS += \ + __mingw_realloc \ + __mingw_free +endif EXTRA_LDFLAGS := $(call UndefWrap,$(MC_WRAP_FUNCS)) diff --git a/Sming/Components/malloc_count/malloc_count.cpp b/Sming/Components/malloc_count/malloc_count.cpp index 6766a8e46b..d886933dee 100644 --- a/Sming/Components/malloc_count/malloc_count.cpp +++ b/Sming/Components/malloc_count/malloc_count.cpp @@ -364,6 +364,11 @@ extern "C" void WRAP(free)(void*) __attribute__((alias("mc_free"))); using namespace MallocCount; +#ifdef __WIN32 +extern "C" void* WRAP(__mingw_realloc)(void*, size_t) __attribute__((alias("mc_realloc"))); +extern "C" void WRAP(__mingw_free)(void*) __attribute__((alias("mc_free"))); +#endif + #ifdef ARCH_ESP8266 extern "C" void* WRAP(pvPortMalloc)(size_t) __attribute__((alias("mc_malloc"))); From e6ed3d9f7f844cbcef872796df33ef3e41e15db6 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 23 Sep 2024 08:40:33 +0100 Subject: [PATCH 12/34] Fix build warnings/errors in C++20 (#2883) **FlashString static initialisation** The `Object` copy and move constructors are deleted as a precaution as these objects should not be copied. C++20 doesn't like this so they're only compiled for C++17 and earlier. **std:is_pod deprecated** Use std::is_standard_layout instead (only one instance to correct). **Volatile** C++20 deprecates many uses of `volatile` which may be implemented in an ambiguous (non-deterministic) way. Largely these uses are concerned with threaded applications. A general web search turns up plenty of articles on this. One argument is related to code like this: ```c++ volatile int num; ++num; // Is this atomic? Or a read, followed by load? ``` So we should identify all such cases and code them more explicitly. The FIFO/FILO classes define `numberOfElements` as volatile but I can see no reason why this needs to be the case. **Volatile bitwise operations** C++23 will, it seems, de-deprecate use of volatile for bitwise operations. This is discussed here https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2327r1.pdf. See also https://github.com/earlephilhower/arduino-pico/issues/1379 These are genuine uses of volatile as values are used both in interrupt and task context. Some of these actually need to be atomic, and the assumption is probably that `x |= n` does that. Hence the ambiguity. These are the core Sming files affected: * Sming/Arch/Esp8266/Components/driver/i2s.cpp * Sming/Arch/Esp8266/Components/spi_flash/iram_precache.cpp * Sming/Arch/Esp8266/Components/gdbstub/appcode/gdb_hooks.cpp * Sming/Arch/Esp8266/Components/gdbstub/gdbstub.cpp * Sming/Arch/Esp8266/Components/gdbstub/gdbuart.cpp * Sming/Arch/Esp8266/Core/Digital.cpp There will be many others in libraries. Solution: Rather than attempting to 'correct' the code and introduce bugs - risks identified in the above paper - it is safer to just silence this particular warning. This has been done in the main Sming `build.mk` file so it's easy to revert if required. This is the `volatile` warning which covers other uses as well - future GCC revisions may add some granularity to this. **FIFO / FILO uses int instead of unsigned** No warnings but using `int` for the count makes no sense. Not related to C++20 but since we're modifying the classes anyway may as well do it here. --- Sming/Components/FlashString | 2 +- .../Storage/src/include/Storage/Partition.h | 2 +- Sming/Wiring/FIFO.h | 20 +++++++++---------- Sming/Wiring/FILO.h | 20 +++++++++---------- Sming/build.mk | 5 +++++ 5 files changed, 27 insertions(+), 22 deletions(-) diff --git a/Sming/Components/FlashString b/Sming/Components/FlashString index 79eb493406..ee011c39a8 160000 --- a/Sming/Components/FlashString +++ b/Sming/Components/FlashString @@ -1 +1 @@ -Subproject commit 79eb493406c3138cb20abf92d8afd5e357f4f715 +Subproject commit ee011c39a8aa75fefd6dd6f5eb48deb8d7feda4b diff --git a/Sming/Components/Storage/src/include/Storage/Partition.h b/Sming/Components/Storage/src/include/Storage/Partition.h index 7069c55c78..98c6b9cf5a 100644 --- a/Sming/Components/Storage/src/include/Storage/Partition.h +++ b/Sming/Components/Storage/src/include/Storage/Partition.h @@ -281,7 +281,7 @@ class Partition bool read(storage_size_t offset, void* dst, size_t size); template - typename std::enable_if::value, bool>::type read(storage_size_t offset, T& value) + typename std::enable_if::value, bool>::type read(storage_size_t offset, T& value) { return read(offset, &value, sizeof(value)); } diff --git a/Sming/Wiring/FIFO.h b/Sming/Wiring/FIFO.h index ffd6df5728..8a2d6e53be 100644 --- a/Sming/Wiring/FIFO.h +++ b/Sming/Wiring/FIFO.h @@ -21,10 +21,10 @@ #include "Countable.h" -template class FIFO : public Countable +template class FIFO : public Countable { public: - const int size; // speculative feature, in case it's needed + const unsigned size; // speculative feature, in case it's needed FIFO(); @@ -60,18 +60,18 @@ template class FIFO : public Countable } protected: - volatile int numberOfElements; - int nextIn; - int nextOut; + unsigned numberOfElements; + unsigned nextIn; + unsigned nextOut; T raw[rawSize]; }; -template FIFO::FIFO() : size(rawSize) +template FIFO::FIFO() : size(rawSize) { flush(); } -template bool FIFO::enqueue(T element) +template bool FIFO::enqueue(T element) { if(full()) { return false; @@ -85,7 +85,7 @@ template bool FIFO::enqueue(T element) return true; } -template T FIFO::dequeue() +template T FIFO::dequeue() { T item; numberOfElements--; @@ -95,12 +95,12 @@ template T FIFO::dequeue() return item; } -template T FIFO::peek() const +template T FIFO::peek() const { return raw[nextOut]; } -template void FIFO::flush() +template void FIFO::flush() { nextIn = nextOut = numberOfElements = 0; } diff --git a/Sming/Wiring/FILO.h b/Sming/Wiring/FILO.h index 15253633a8..88d9e800a8 100644 --- a/Sming/Wiring/FILO.h +++ b/Sming/Wiring/FILO.h @@ -20,10 +20,10 @@ #include "Countable.h" -template class FILO : public Countable +template class FILO : public Countable { public: - const int size; // speculative feature, in case it's needed + const unsigned size; // speculative feature, in case it's needed FILO(); @@ -59,18 +59,18 @@ template class FILO : public Countable } private: - volatile int numberOfElements; - int nextIn; - int nextOut; + unsigned numberOfElements; + unsigned nextIn; + unsigned nextOut; T raw[rawSize]; }; -template FILO::FILO() : size(rawSize) +template FILO::FILO() : size(rawSize) { flush(); } -template bool FILO::push(T element) +template bool FILO::push(T element) { if(count() >= rawSize) { return false; @@ -79,7 +79,7 @@ template bool FILO::push(T element) return true; } -template T FILO::pop() +template T FILO::pop() { if(numberOfElements > 0) { return raw[--numberOfElements]; @@ -87,7 +87,7 @@ template T FILO::pop() return raw[0]; } -template T FILO::peek() const +template T FILO::peek() const { if(numberOfElements > 0) { return raw[numberOfElements - 1]; @@ -95,7 +95,7 @@ template T FILO::peek() const return raw[0]; } -template void FILO::flush() +template void FILO::flush() { nextIn = nextOut = numberOfElements = 0; } diff --git a/Sming/build.mk b/Sming/build.mk index 9b8d4c7c37..b4d50a34f9 100644 --- a/Sming/build.mk +++ b/Sming/build.mk @@ -239,6 +239,11 @@ COMPILER_VERSION_FULL := $(shell LANG=C $(CC) -v 2>&1 | $(AWK) -F " version " '/ COMPILER_NAME := $(word 1,$(COMPILER_VERSION_FULL)) COMPILER_VERSION := $(word 2,$(COMPILER_VERSION_FULL)) +# Use of bitwise assignment for volatile registers is deprecated in C++20 but de-deprecated in C++23 +ifeq ($(COMPILER_NAME)-$(SMING_CXX_STD),gcc-c++20) +CXXFLAGS += -Wno-volatile +endif + ifndef USE_CLANG # Required to access peripheral registers using structs # e.g. `uint32_t value: 8` sitting at a byte or word boundary will be 'optimised' to From c34d7472b43f5c8cd45320da1ecbe7e3d3860d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berthold=20H=C3=B6llmann?= Date: Wed, 25 Sep 2024 12:32:55 +0200 Subject: [PATCH 13/34] Improved checking for uninstalled tools for unsupported linux distributions. (#2887) - Support for linux platforms not providing apt or dnf. Installation script searches for required tools and list missing. --- Sming/Arch/Esp32/Tools/install.sh | 6 ++++ Tools/install.sh | 60 ++++++++++++++++++++++++++++--- samples/Basic_Serial/.gitignore | 1 + 3 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 samples/Basic_Serial/.gitignore diff --git a/Sming/Arch/Esp32/Tools/install.sh b/Sming/Arch/Esp32/Tools/install.sh index 0a872db39d..3ead67befc 100755 --- a/Sming/Arch/Esp32/Tools/install.sh +++ b/Sming/Arch/Esp32/Tools/install.sh @@ -31,6 +31,12 @@ case $DIST in darwin) ;; + *) + check_for_installed_tools dfu-util bison flex gperf + check_for_installed_files "/usr/include/ffi.h" "/usr/include/ssl/ssl.h" + PACKAGES=() + ;; + esac $PKG_INSTALL "${PACKAGES[@]}" diff --git a/Tools/install.sh b/Tools/install.sh index 4b85fd5dd1..f43d0cd56b 100755 --- a/Tools/install.sh +++ b/Tools/install.sh @@ -84,6 +84,47 @@ source "$(dirname "${BASH_SOURCE[0]}")/export.sh" export WGET="wget --no-verbose" +# Scripts for checking for required resources + +abort () { + echo "ABORTING" + if [ $sourced = 1 ]; then + return 1 + else + exit 1 + fi +} + +check_for_installed_tools() { + REQUIRED_TOOLS=( "$@" ) + echo -e "Checking for installed tools.\nRequired tools: ${REQUIRED_TOOLS[*]}" + TOOLS_MISSING=0 + for TOOL in "${REQUIRED_TOOLS[@]}"; do + if ! command -v "$TOOL" > /dev/null ; then + TOOLS_MISSING=1 + echo "Install required tool $TOOL" + fi + done + if [ $TOOLS_MISSING != 0 ]; then + abort + fi +} + +check_for_installed_files() { + REQUIRED_FILES=( "$@" ) + echo -e "Checking for installed files.\nRequired files: ${REQUIRED_FILES[*]}" + FILES_MISSING=0 + for FILE in "${REQUIRED_FILES[@]}"; do + if ! [ -f "$FILE" ]; then + FILES_MISSING=1 + echo "Install required FILE $FILE" + fi + done + if [ $FILES_MISSING != 0 ]; then + abort + fi +} + # Installers put downloaded archives here DOWNLOADS="downloads" mkdir -p $DOWNLOADS @@ -100,11 +141,18 @@ elif [ -n "$(command -v dnf)" ]; then PKG_INSTALL="sudo dnf install -y" else echo "Unsupported distribution" - if [ $sourced = 1 ]; then - return 1 - else - exit 1 - fi + check_for_installed_tools \ + ccache \ + cmake \ + curl \ + git \ + make \ + ninja \ + unzip \ + g++ \ + python3 \ + pip3 \ + wget fi # Common install @@ -183,9 +231,11 @@ case $DIST in esac +if [ "$(/usr/bin/python -c 'import sys;print(sys.version_info[0])')" != 3 ]; then if [ "$DIST" != "darwin" ]; then sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 100 fi +fi set -e diff --git a/samples/Basic_Serial/.gitignore b/samples/Basic_Serial/.gitignore new file mode 100644 index 0000000000..bb97907eef --- /dev/null +++ b/samples/Basic_Serial/.gitignore @@ -0,0 +1 @@ +/files/ From 360826a75e98f1b6a941c707e5742eb52da21a87 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 18 Oct 2024 08:45:12 +0100 Subject: [PATCH 14/34] Fix esp8266 pwm (#2889) Fix bug introduced in #2752 where PWM doesn't initialise GPIO correctly. See #2888. --- Sming/Arch/Esp32/Core/peripheral.h | 846 ------------------------ Sming/Arch/Esp32/Core/pins_arduino.h | 2 - Sming/Arch/Esp8266/Core/HardwarePWM.cpp | 21 +- 3 files changed, 20 insertions(+), 849 deletions(-) delete mode 100644 Sming/Arch/Esp32/Core/peripheral.h diff --git a/Sming/Arch/Esp32/Core/peripheral.h b/Sming/Arch/Esp32/Core/peripheral.h deleted file mode 100644 index be157e6e34..0000000000 --- a/Sming/Arch/Esp32/Core/peripheral.h +++ /dev/null @@ -1,846 +0,0 @@ -#pragma once - -#if 0 - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ESP8266_REG(addr) *((volatile uint32_t*)(0x60000000 + (addr))) -#define ESP8266_DREG(addr) *((volatile uint32_t*)(0x3FF00000 + (addr))) -#define ESP8266_CLOCK 80000000UL - -//CPU Register -#define CPU2X ESP8266_DREG(0x14) //when bit 0 is set, F_CPU = 160MHz - -//OTP Registers -#define MAC0 ESP8266_DREG(0x50) -#define MAC1 ESP8266_DREG(0x54) -#define CHIPID ESP8266_DREG(0x58) - -//GPIO (0-15) Control Registers -#define GPO ESP8266_REG(0x300) //GPIO_OUT R/W (Output Level) -#define GPOS ESP8266_REG(0x304) //GPIO_OUT_SET WO -#define GPOC ESP8266_REG(0x308) //GPIO_OUT_CLR WO -#define GPE ESP8266_REG(0x30C) //GPIO_ENABLE R/W (Enable) -#define GPES ESP8266_REG(0x310) //GPIO_ENABLE_SET WO -#define GPEC ESP8266_REG(0x314) //GPIO_ENABLE_CLR WO -#define GPI ESP8266_REG(0x318) //GPIO_IN RO (Read Input Level) -#define GPIE ESP8266_REG(0x31C) //GPIO_STATUS R/W (Interrupt Enable) -#define GPIES ESP8266_REG(0x320) //GPIO_STATUS_SET WO -#define GPIEC ESP8266_REG(0x324) //GPIO_STATUS_CLR WO - -#define GPOP(p) ((GPO & (1 << ((p)&0xF))) != 0) -#define GPEP(p) ((GPE & (1 << ((p)&0xF))) != 0) -#define GPIP(p) ((GPI & (1 << ((p)&0xF))) != 0) -#define GPIEP(p) ((GPIE & (1 << ((p)&0xF))) != 0) - -//GPIO (0-15) PIN Control Registers -#define GPC(p) ESP8266_REG(0x328 + ((p & 0xF) * 4)) -#define GPC0 ESP8266_REG(0x328) //GPIO_PIN0 -#define GPC1 ESP8266_REG(0x32C) //GPIO_PIN1 -#define GPC2 ESP8266_REG(0x330) //GPIO_PIN2 -#define GPC3 ESP8266_REG(0x334) //GPIO_PIN3 -#define GPC4 ESP8266_REG(0x338) //GPIO_PIN4 -#define GPC5 ESP8266_REG(0x33C) //GPIO_PIN5 -#define GPC6 ESP8266_REG(0x340) //GPIO_PIN6 -#define GPC7 ESP8266_REG(0x344) //GPIO_PIN7 -#define GPC8 ESP8266_REG(0x348) //GPIO_PIN8 -#define GPC9 ESP8266_REG(0x34C) //GPIO_PIN9 -#define GPC10 ESP8266_REG(0x350) //GPIO_PIN10 -#define GPC11 ESP8266_REG(0x354) //GPIO_PIN11 -#define GPC12 ESP8266_REG(0x358) //GPIO_PIN12 -#define GPC13 ESP8266_REG(0x35C) //GPIO_PIN13 -#define GPC14 ESP8266_REG(0x360) //GPIO_PIN14 -#define GPC15 ESP8266_REG(0x364) //GPIO_PIN15 - -//GPIO (0-15) PIN Control Bits -#define GPCWE 10 //WAKEUP_ENABLE (can be 1 only when INT_TYPE is high or low) -#define GPCI 7 //INT_TYPE (3bits) 0:disable,1:rising,2:falling,3:change,4:low,5:high -#define GPCD 2 //DRIVER 0:normal,1:open drain -#define GPCS 0 //SOURCE 0:GPIO_DATA,1:SigmaDelta - -#define GPMUX ESP8266_REG(0x800) -//GPIO (0-15) PIN Function Registers -#define GPF0 ESP8266_REG(0x834) -#define GPF1 ESP8266_REG(0x818) -#define GPF2 ESP8266_REG(0x838) -#define GPF3 ESP8266_REG(0x814) -#define GPF4 ESP8266_REG(0x83C) -#define GPF5 ESP8266_REG(0x840) -#define GPF6 ESP8266_REG(0x81C) -#define GPF7 ESP8266_REG(0x820) -#define GPF8 ESP8266_REG(0x824) -#define GPF9 ESP8266_REG(0x828) -#define GPF10 ESP8266_REG(0x82C) -#define GPF11 ESP8266_REG(0x830) -#define GPF12 ESP8266_REG(0x804) -#define GPF13 ESP8266_REG(0x808) -#define GPF14 ESP8266_REG(0x80C) -#define GPF15 ESP8266_REG(0x810) - -extern const uint8_t esp8266_gpioToFn[16]; -#define GPF(p) ESP8266_REG(0x800 + esp8266_gpioToFn[(p & 0xF)]) - -//GPIO (0-15) PIN Function Bits -#define GPFSOE 0 //Sleep OE -#define GPFSS 1 //Sleep Sel -#define GPFSPD 2 //Sleep Pulldown -#define GPFSPU 3 //Sleep Pullup -#define GPFFS0 4 //Function Select bit 0 -#define GPFFS1 5 //Function Select bit 1 -#define GPFPD 6 //Pulldown -#define GPFPU 7 //Pullup -#define GPFFS2 8 //Function Select bit 2 -#define GPFFS(f) (((((f)&4) != 0) << GPFFS2) | ((((f)&2) != 0) << GPFFS1) | ((((f)&1) != 0) << GPFFS0)) -#define GPFFS_GPIO(p) (((p) == 0 || (p) == 2 || (p) == 4 || (p) == 5) ? 0 : ((p) == 16) ? 1 : 3) -#define GPFFS_BUS(p) \ - (((p) == 1 || (p) == 3) ? 0 \ - : ((p) == 2 || (p) == 12 || (p) == 13 || (p) == 14 || (p) == 15) ? 2 : ((p) == 0) ? 4 : 1) - -//GPIO 16 Control Registers -#define GP16O ESP8266_REG(0x768) -#define GP16E ESP8266_REG(0x774) -#define GP16I ESP8266_REG(0x78C) - -//GPIO 16 PIN Control Register -#define GP16C ESP8266_REG(0x790) -#define GPC16 GP16C - -//GPIO 16 PIN Function Register -#define GP16F ESP8266_REG(0x7A0) -#define GPF16 GP16F - -//GPIO 16 PIN Function Bits -#define GP16FFS0 0 //Function Select bit 0 -#define GP16FFS1 1 //Function Select bit 1 -#define GP16FPD 3 //Pulldown -#define GP16FSPD 5 //Sleep Pulldown -#define GP16FFS2 6 //Function Select bit 2 -#define GP16FFS(f) (((f)&0x03) | (((f)&0x04) << 4)) - -//Timer 1 Registers (23bit CountDown Timer) -#define T1L ESP8266_REG(0x600) //Load Value (Starting Value of Counter) 23bit (0-8388607) -#define T1V ESP8266_REG(0x604) //(RO) Current Value -#define T1C ESP8266_REG(0x608) //Control Register -#define T1I ESP8266_REG(0x60C) //Interrupt Status Register (1bit) write to clear -//edge interrupt enable register -#define TEIE ESP8266_DREG(0x04) -#define TEIE1 0x02 //bit for timer 1 - -//Timer 2 Registers (32bit CountUp Timer) -#define T2L ESP8266_REG(0x620) //Load Value (Starting Value of Counter) -#define T2V ESP8266_REG(0x624) //(RO) Current Value -#define T2C ESP8266_REG(0x628) //Control Register -#define T2I ESP8266_REG(0x62C) //Interrupt Status Register (1bit) write to clear -#define T2A ESP8266_REG(0x630) //Alarm Value - -//Timer Control Bits -#define TCIS 8 //Interrupt Status -#define TCTE 7 //Timer Enable -#define TCAR 6 //AutoReload (restart timer when condition is reached) -#define TCPD 2 //Prescale Divider (2bit) 0:1(12.5ns/tick), 1:16(0.2us/tick), 2/3:256(3.2us/tick) -#define TCIT 0 //Interrupt Type 0:edge, 1:level - -//RTC Registers -#define RTCSV ESP8266_REG(0x704) //RTC SLEEP COUNTER Target Value -#define RTCCV ESP8266_REG(0x71C) //RTC SLEEP COUNTER Value -#define RTCIS ESP8266_REG(0x720) //RTC INT Status -#define RTCIC ESP8266_REG(0x724) //RTC INT Clear -#define RTCIE ESP8266_REG(0x728) //RTC INT Enable - -#define RTC_USER_MEM ((volatile uint32_t*)0x60001200) - -//IO SWAP Register -#define IOSWAP ESP8266_DREG(0x28) -#define IOSWAPU 0 //Swaps UART -#define IOSWAPS 1 //Swaps SPI -#define IOSWAPU0 2 //Swaps UART 0 pins (u0rxd <-> u0cts), (u0txd <-> u0rts) -#define IOSWAPU1 3 //Swaps UART 1 pins (u1rxd <-> u1cts), (u1txd <-> u1rts) -#define IOSWAPHS 5 //Sets HSPI with higher prio -#define IOSWAP2HS 6 //Sets Two SPI Masters on HSPI -#define IOSWAP2CS 7 //Sets Two SPI Masters on CSPI - -//UART INT Status -#define UIS ESP8266_DREG(0x20020) -#define UIS0 0 -#define UIS1 2 - -//UART 0 Registers -#define U0F ESP8266_REG(0x000) //UART FIFO -#define U0IR ESP8266_REG(0x004) //INT_RAW -#define U0IS ESP8266_REG(0x008) //INT_STATUS -#define U0IE ESP8266_REG(0x00c) //INT_ENABLE -#define U0IC ESP8266_REG(0x010) //INT_CLEAR -#define U0D ESP8266_REG(0x014) //CLKDIV -#define U0A ESP8266_REG(0x018) //AUTOBAUD -#define U0S ESP8266_REG(0x01C) //STATUS -#define U0C0 ESP8266_REG(0x020) //CONF0 -#define U0C1 ESP8266_REG(0x024) //CONF1 -#define U0LP ESP8266_REG(0x028) //LOW_PULSE -#define U0HP ESP8266_REG(0x02C) //HIGH_PULSE -#define U0PN ESP8266_REG(0x030) //PULSE_NUM -#define U0DT ESP8266_REG(0x078) //DATE -#define U0ID ESP8266_REG(0x07C) //ID - -//UART 1 Registers -#define U1F ESP8266_REG(0xF00) //UART FIFO -#define U1IR ESP8266_REG(0xF04) //INT_RAW -#define U1IS ESP8266_REG(0xF08) //INT_STATUS -#define U1IE ESP8266_REG(0xF0c) //INT_ENABLE -#define U1IC ESP8266_REG(0xF10) //INT_CLEAR -#define U1D ESP8266_REG(0xF14) //CLKDIV -#define U1A ESP8266_REG(0xF18) //AUTOBAUD -#define U1S ESP8266_REG(0xF1C) //STATUS -#define U1C0 ESP8266_REG(0xF20) //CONF0 -#define U1C1 ESP8266_REG(0xF24) //CONF1 -#define U1LP ESP8266_REG(0xF28) //LOW_PULSE -#define U1HP ESP8266_REG(0xF2C) //HIGH_PULSE -#define U1PN ESP8266_REG(0xF30) //PULSE_NUM -#define U1DT ESP8266_REG(0xF78) //DATE -#define U1ID ESP8266_REG(0xF7C) //ID - -//UART(uart) Registers -#define USF(u) ESP8266_REG(0x000 + (0xF00 * (u & 1))) //UART FIFO -#define USIR(u) ESP8266_REG(0x004 + (0xF00 * (u & 1))) //INT_RAW -#define USIS(u) ESP8266_REG(0x008 + (0xF00 * (u & 1))) //INT_STATUS -#define USIE(u) ESP8266_REG(0x00c + (0xF00 * (u & 1))) //INT_ENABLE -#define USIC(u) ESP8266_REG(0x010 + (0xF00 * (u & 1))) //INT_CLEAR -#define USD(u) ESP8266_REG(0x014 + (0xF00 * (u & 1))) //CLKDIV -#define USA(u) ESP8266_REG(0x018 + (0xF00 * (u & 1))) //AUTOBAUD -#define USS(u) ESP8266_REG(0x01C + (0xF00 * (u & 1))) //STATUS -#define USC0(u) ESP8266_REG(0x020 + (0xF00 * (u & 1))) //CONF0 -#define USC1(u) ESP8266_REG(0x024 + (0xF00 * (u & 1))) //CONF1 -#define USLP(u) ESP8266_REG(0x028 + (0xF00 * (u & 1))) //LOW_PULSE -#define USHP(u) ESP8266_REG(0x02C + (0xF00 * (u & 1))) //HIGH_PULSE -#define USPN(u) ESP8266_REG(0x030 + (0xF00 * (u & 1))) //PULSE_NUM -#define USDT(u) ESP8266_REG(0x078 + (0xF00 * (u & 1))) //DATE -#define USID(u) ESP8266_REG(0x07C + (0xF00 * (u & 1))) //ID - -//UART INT Registers Bits -#define UITO 8 //RX FIFO TimeOut -#define UIBD 7 //Break Detected -#define UICTS 6 //CTS Changed -#define UIDSR 5 //DSR Change -#define UIOF 4 //RX FIFO OverFlow -#define UIFR 3 //Frame Error -#define UIPE 2 //Parity Error -#define UIFE 1 //TX FIFO Empty -#define UIFF 0 //RX FIFO Full - -//UART STATUS Registers Bits -#define USTX 31 //TX PIN Level -#define USRTS 30 //RTS PIN Level -#define USDTR 39 //DTR PIN Level -#define USTXC 16 //TX FIFO COUNT (8bit) -#define USRXD 15 //RX PIN Level -#define USCTS 14 //CTS PIN Level -#define USDSR 13 //DSR PIN Level -#define USRXC 0 //RX FIFO COUNT (8bit) - -//UART CONF0 Registers Bits -#define UCDTRI 24 //Invert DTR -#define UCRTSI 23 //Invert RTS -#define UCTXI 22 //Invert TX -#define UCDSRI 21 //Invert DSR -#define UCCTSI 20 //Invert CTS -#define UCRXI 19 //Invert RX -#define UCTXRST 18 //Reset TX FIFO -#define UCRXRST 17 //Reset RX FIFO -#define UCTXHFE 15 //TX Hardware Flow Enable -#define UCLBE 14 //LoopBack Enable -#define UCBRK 8 //Send Break on the TX line -#define UCSWDTR 7 //Set this bit to assert DTR -#define UCSWRTS 6 //Set this bit to assert RTS -#define UCSBN 4 //StopBits Count (2bit) 0:disable, 1:1bit, 2:1.5bit, 3:2bit -#define UCBN 2 //DataBits Count (2bin) 0:5bit, 1:6bit, 2:7bit, 3:8bit -#define UCPAE 1 //Parity Enable -#define UCPA 0 //Parity 0:even, 1:odd - -//UART CONF1 Registers Bits -#define UCTOE 31 //RX TimeOut Enable -#define UCTOT 24 //RX TimeOut Threshold (7bit) -#define UCRXHFE 23 //RX Hardware Flow Enable -#define UCRXHFT 16 //RX Hardware Flow Threshold (7bit) -#define UCFET 8 //TX FIFO Empty Threshold (7bit) -#define UCFFT 0 //RX FIFO Full Threshold (7bit) - -//SPI_READY -#define SPIRDY ESP8266_DREG(0x0C) -#define SPI_BUSY 9 //wait SPI idle - -//SPI0 Registers (SPI0 is used for the flash) -#define SPI0CMD ESP8266_REG(0x200) -#define SPI0A ESP8266_REG(0x204) -#define SPI0C ESP8266_REG(0x208) -#define SPI0C1 ESP8266_REG(0x20C) -#define SPI0RS ESP8266_REG(0x210) -#define SPI0C2 ESP8266_REG(0x214) -#define SPI0CLK ESP8266_REG(0x218) -#define SPI0U ESP8266_REG(0x21C) -#define SPI0U1 ESP8266_REG(0x220) -#define SPI0U2 ESP8266_REG(0x224) -#define SPI0WS ESP8266_REG(0x228) -#define SPI0P ESP8266_REG(0x22C) -#define SPI0S ESP8266_REG(0x230) -#define SPI0S1 ESP8266_REG(0x234) -#define SPI0S2 ESP8266_REG(0x238) -#define SPI0S3 ESP8266_REG(0x23C) -#define SPI0W0 ESP8266_REG(0x240) -#define SPI0W1 ESP8266_REG(0x244) -#define SPI0W2 ESP8266_REG(0x248) -#define SPI0W3 ESP8266_REG(0x24C) -#define SPI0W4 ESP8266_REG(0x250) -#define SPI0W5 ESP8266_REG(0x254) -#define SPI0W6 ESP8266_REG(0x258) -#define SPI0W7 ESP8266_REG(0x25C) -#define SPI0W8 ESP8266_REG(0x260) -#define SPI0W9 ESP8266_REG(0x264) -#define SPI0W10 ESP8266_REG(0x268) -#define SPI0W11 ESP8266_REG(0x26C) -#define SPI0W12 ESP8266_REG(0x270) -#define SPI0W13 ESP8266_REG(0x274) -#define SPI0W14 ESP8266_REG(0x278) -#define SPI0W15 ESP8266_REG(0x27C) -#define SPI0E3 ESP8266_REG(0x2FC) -#define SPI0W(p) ESP8266_REG(0x240 + ((p & 0xF) * 4)) - -//SPI1 Registers -#define SPI1CMD ESP8266_REG(0x100) -#define SPI1A ESP8266_REG(0x104) -#define SPI1C ESP8266_REG(0x108) -#define SPI1C1 ESP8266_REG(0x10C) -#define SPI1RS ESP8266_REG(0x110) -#define SPI1C2 ESP8266_REG(0x114) -#define SPI1CLK ESP8266_REG(0x118) -#define SPI1U ESP8266_REG(0x11C) -#define SPI1U1 ESP8266_REG(0x120) -#define SPI1U2 ESP8266_REG(0x124) -#define SPI1WS ESP8266_REG(0x128) -#define SPI1P ESP8266_REG(0x12C) -#define SPI1S ESP8266_REG(0x130) -#define SPI1S1 ESP8266_REG(0x134) -#define SPI1S2 ESP8266_REG(0x138) -#define SPI1S3 ESP8266_REG(0x13C) -#define SPI1W0 ESP8266_REG(0x140) -#define SPI1W1 ESP8266_REG(0x144) -#define SPI1W2 ESP8266_REG(0x148) -#define SPI1W3 ESP8266_REG(0x14C) -#define SPI1W4 ESP8266_REG(0x150) -#define SPI1W5 ESP8266_REG(0x154) -#define SPI1W6 ESP8266_REG(0x158) -#define SPI1W7 ESP8266_REG(0x15C) -#define SPI1W8 ESP8266_REG(0x160) -#define SPI1W9 ESP8266_REG(0x164) -#define SPI1W10 ESP8266_REG(0x168) -#define SPI1W11 ESP8266_REG(0x16C) -#define SPI1W12 ESP8266_REG(0x170) -#define SPI1W13 ESP8266_REG(0x174) -#define SPI1W14 ESP8266_REG(0x178) -#define SPI1W15 ESP8266_REG(0x17C) -#define SPI1E0 ESP8266_REG(0x1F0) -#define SPI1E1 ESP8266_REG(0x1F4) -#define SPI1E2 ESP8266_REG(0x1F8) -#define SPI1E3 ESP8266_REG(0x1FC) -#define SPI1W(p) ESP8266_REG(0x140 + ((p & 0xF) * 4)) - -//SPI0, SPI1 & I2S Interrupt Register -#define SPIIR ESP8266_DREG(0x20) -#define SPII0 4 //SPI0 Interrupt -#define SPII1 7 //SPI1 Interrupt -#define SPII2 9 //I2S Interrupt - -//SPI CMD -#define SPICMDREAD (1 << 31) //SPI_FLASH_READ -#define SPICMDWREN (1 << 30) //SPI_FLASH_WREN -#define SPICMDWRDI (1 << 29) //SPI_FLASH_WRDI -#define SPICMDRDID (1 << 28) //SPI_FLASH_RDID -#define SPICMDRDSR (1 << 27) //SPI_FLASH_RDSR -#define SPICMDWRSR (1 << 26) //SPI_FLASH_WRSR -#define SPICMDPP (1 << 25) //SPI_FLASH_PP -#define SPICMDSE (1 << 24) //SPI_FLASH_SE -#define SPICMDBE (1 << 23) //SPI_FLASH_BE -#define SPICMDCE (1 << 22) //SPI_FLASH_CE -#define SPICMDDP (1 << 21) //SPI_FLASH_DP -#define SPICMDRES (1 << 20) //SPI_FLASH_RES -#define SPICMDHPM (1 << 19) //SPI_FLASH_HPM -#define SPICMDUSR (1 << 18) //SPI_FLASH_USR -#define SPIBUSY (1 << 18) //SPI_USR - -//SPI CTRL (SPIxC) -#define SPICWBO (1 << 26) //SPI_WR_BIT_ODER -#define SPICRBO (1 << 25) //SPI_RD_BIT_ODER -#define SPICQIO (1 << 24) //SPI_QIO_MODE -#define SPICDIO (1 << 23) //SPI_DIO_MODE -#define SPIC2BSE (1 << 22) //SPI_TWO_BYTE_STATUS_EN -#define SPICWPR (1 << 21) //SPI_WP_REG -#define SPICQOUT (1 << 20) //SPI_QOUT_MODE -#define SPICSHARE (1 << 19) //SPI_SHARE_BUS -#define SPICHOLD (1 << 18) //SPI_HOLD_MODE -#define SPICAHB (1 << 17) //SPI_ENABLE_AHB -#define SPICSSTAAI (1 << 16) //SPI_SST_AAI -#define SPICRESANDRES (1 << 15) //SPI_RESANDRES -#define SPICDOUT (1 << 14) //SPI_DOUT_MODE -#define SPICFASTRD (1 << 13) //SPI_FASTRD_MODE - -//SPI CTRL1 (SPIxC1) -#define SPIC1TCSH 0xF //SPI_T_CSH -#define SPIC1TCSH_S 28 //SPI_T_CSH_S -#define SPIC1TRES 0xFFF //SPI_T_RES -#define SPIC1TRES_S 16 //SPI_T_RES_S -#define SPIC1BTL 0xFFFF //SPI_BUS_TIMER_LIMIT -#define SPIC1BTL_S 0 //SPI_BUS_TIMER_LIMIT_S - -//SPI Status (SPIxRS) -#define SPIRSEXT 0xFF //SPI_STATUS_EXT -#define SPIRSEXT_S 24 //SPI_STATUS_EXT_S -#define SPIRSWB 0xFF //SPI_WB_MODE -#define SPIRSWB_S 16 //SPI_WB_MODE_S -#define SPIRSSP (1 << 7) //SPI_FLASH_STATUS_PRO_FLAG -#define SPIRSTBP (1 << 5) //SPI_FLASH_TOP_BOT_PRO_FLAG -#define SPIRSBP2 (1 << 4) //SPI_FLASH_BP2 -#define SPIRSBP1 (1 << 3) //SPI_FLASH_BP1 -#define SPIRSBP0 (1 << 2) //SPI_FLASH_BP0 -#define SPIRSWRE (1 << 1) //SPI_FLASH_WRENABLE_FLAG -#define SPIRSBUSY (1 << 0) //SPI_FLASH_BUSY_FLAG - -//SPI CTRL2 (SPIxC2) -#define SPIC2CSDN 0xF //SPI_CS_DELAY_NUM -#define SPIC2CSDN_S 28 //SPI_CS_DELAY_NUM_S -#define SPIC2CSDM 0x3 //SPI_CS_DELAY_MODE -#define SPIC2CSDM_S 26 //SPI_CS_DELAY_MODE_S -#define SPIC2MOSIDN 0x7 //SPI_MOSI_DELAY_NUM -#define SPIC2MOSIDN_S 23 //SPI_MOSI_DELAY_NUM_S -#define SPIC2MOSIDM 0x3 //SPI_MOSI_DELAY_MODE -#define SPIC2MOSIDM_S 21 //SPI_MOSI_DELAY_MODE_S -#define SPIC2MISODN 0x7 //SPI_MISO_DELAY_NUM -#define SPIC2MISODN_S 18 //SPI_MISO_DELAY_NUM_S -#define SPIC2MISODM 0x3 //SPI_MISO_DELAY_MODE -#define SPIC2MISODM_S 16 //SPI_MISO_DELAY_MODE_S -#define SPIC2CKOHM 0xF //SPI_CK_OUT_HIGH_MODE -#define SPIC2CKOHM_S 12 //SPI_CK_OUT_HIGH_MODE_S -#define SPIC2CKOLM 0xF //SPI_CK_OUT_LOW_MODE -#define SPIC2CKOLM_S 8 //SPI_CK_OUT_LOW_MODE_S -#define SPIC2HT 0xF //SPI_HOLD_TIME -#define SPIC2HT_S 4 //SPI_HOLD_TIME_S -#define SPIC2ST 0xF //SPI_SETUP_TIME -#define SPIC2ST_S 0 //SPI_SETUP_TIME_S - -//SPI CLK (SPIxCLK) -#define SPICLK_EQU_SYSCLK (1 << 31) //SPI_CLK_EQU_SYSCLK -#define SPICLKDIVPRE 0x1FFF //SPI_CLKDIV_PRE -#define SPICLKDIVPRE_S 18 //SPI_CLKDIV_PRE_S -#define SPICLKCN 0x3F //SPI_CLKCNT_N -#define SPICLKCN_S 12 //SPI_CLKCNT_N_S -#define SPICLKCH 0x3F //SPI_CLKCNT_H -#define SPICLKCH_S 6 //SPI_CLKCNT_H_S -#define SPICLKCL 0x3F //SPI_CLKCNT_L -#define SPICLKCL_S 0 //SPI_CLKCNT_L_S - -//SPI Phases (SPIxU) -#define SPIUCOMMAND (1 << 31) //COMMAND pahse, SPI_USR_COMMAND -#define SPIUADDR (1 << 30) //ADDRESS phase, SPI_FLASH_USR_ADDR -#define SPIUDUMMY (1 << 29) //DUMMY phase, SPI_FLASH_USR_DUMMY -#define SPIUMISO (1 << 28) //MISO phase, SPI_FLASH_USR_DIN -#define SPIUMOSI (1 << 27) //MOSI phase, SPI_FLASH_DOUT -#define SPIUDUMMYIDLE (1 << 26) //SPI_USR_DUMMY_IDLE -#define SPIUMOSIH (1 << 25) //MOSI phase uses W8-W15, SPI_USR_DOUT_HIGHPART -#define SPIUMISOH (1 << 24) //MISO pahse uses W8-W15, SPI_USR_DIN_HIGHPART -#define SPIUPREPHOLD (1 << 23) //SPI_USR_PREP_HOLD -#define SPIUCMDHOLD (1 << 22) //SPI_USR_CMD_HOLD -#define SPIUADDRHOLD (1 << 21) //SPI_USR_ADDR_HOLD -#define SPIUDUMMYHOLD (1 << 20) //SPI_USR_DUMMY_HOLD -#define SPIUMISOHOLD (1 << 19) //SPI_USR_DIN_HOLD -#define SPIUMOSIHOLD (1 << 18) //SPI_USR_DOUT_HOLD -#define SPIUHOLDPOL (1 << 17) //SPI_USR_HOLD_POL -#define SPIUSIO (1 << 16) //SPI_SIO -#define SPIUFWQIO (1 << 15) //SPI_FWRITE_QIO -#define SPIUFWDIO (1 << 14) //SPI_FWRITE_DIO -#define SPIUFWQUAD (1 << 13) //SPI_FWRITE_QUAD -#define SPIUFWDUAL (1 << 12) //SPI_FWRITE_DUAL -#define SPIUWRBYO (1 << 11) //SPI_WR_BYTE_ORDER -#define SPIURDBYO (1 << 10) //SPI_RD_BYTE_ORDER -#define SPIUAHBEM 0x3 //SPI_AHB_ENDIAN_MODE -#define SPIUAHBEM_S 8 //SPI_AHB_ENDIAN_MODE_S -#define SPIUSME (1 << 7) //SPI Master Edge (0:falling, 1:rising), SPI_CK_OUT_EDGE -#define SPIUSSE (1 << 6) //SPI Slave Edge (0:falling, 1:rising), SPI_CK_I_EDGE -#define SPIUCSSETUP (1 << 5) //SPI_CS_SETUP -#define SPIUCSHOLD (1 << 4) //SPI_CS_HOLD -#define SPIUAHBUCMD (1 << 3) //SPI_AHB_USR_COMMAND -#define SPIUAHBUCMD4B (1 << 1) //SPI_AHB_USR_COMMAND_4BYTE -#define SPIUDUPLEX (1 << 0) //SPI_DOUTDIN - -//SPI Phase Length Locations -#define SPILCOMMAND 28 //4 bit in SPIxU2 default 7 (8bit) -#define SPILADDR 26 //6 bit in SPIxU1 default:23 (24bit) -#define SPILDUMMY 0 //8 bit in SPIxU1 default:0 (0 cycles) -#define SPILMISO 8 //9 bit in SPIxU1 default:0 (1bit) -#define SPILMOSI 17 //9 bit in SPIxU1 default:0 (1bit) -//SPI Phase Length Masks -#define SPIMCOMMAND 0xF -#define SPIMADDR 0x3F -#define SPIMDUMMY 0xFF -#define SPIMMISO 0x1FF -#define SPIMMOSI 0x1FF - -//SPI Slave (SPIxS) -#define SPISSRES (1 << 31) //SYNC RESET, SPI_SYNC_RESET -#define SPISE (1 << 30) //Slave Enable, SPI_SLAVE_MODE -#define SPISBE (1 << 29) //WR/RD BUF enable, SPI_SLV_WR_RD_BUF_EN -#define SPISSE (1 << 28) //STA enable, SPI_SLV_WR_RD_STA_EN -#define SPISCD (1 << 27) //CMD define, SPI_SLV_CMD_DEFINE -#define SPISTRCNT 0xF //SPI_TRANS_CNT -#define SPISTRCNT_S 23 //SPI_TRANS_CNT_S -#define SPISSLS 0x7 //SPI_SLV_LAST_STATE -#define SPISSLS_S 20 //SPI_SLV_LAST_STATE_S -#define SPISSLC 0x7 //SPI_SLV_LAST_COMMAND -#define SPISSLC_S 17 //SPI_SLV_LAST_COMMAND_S -#define SPISCSIM 0x3 //SPI_CS_I_MODE -#define SPIDCSIM_S 10 //SPI_CS_I_MODE_S -#define SPISTRIE (1 << 9) //TRANS interrupt enable -#define SPISWSIE (1 << 8) //WR_STA interrupt enable -#define SPISRSIE (1 << 7) //RD_STA interrupt enable -#define SPISWBIE (1 << 6) //WR_BUF interrupt enable -#define SPISRBIE (1 << 5) //RD_BUF interrupt enable -#define SPISTRIS (1 << 4) //TRANS interrupt status -#define SPISWSIS (1 << 3) //WR_STA interrupt status -#define SPISRSIS (1 << 2) //RD_STA interrupt status -#define SPISWBIS (1 << 1) //WR_BUF interrupt status -#define SPISRBIS (1 << 0) //RD_BUF interrupt status - -//SPI Slave1 (SPIxS1) -#define SPIS1LSTA 27 //5 bit in SPIxS1 default:0 (1bit), SPI_SLV_STATUS_BITLEN -#define SPIS1FE (1 << 26) //SPI_SLV_STATUS_FAST_EN -#define SPIS1RSTA (1 << 25) //default:0 enable STA read from Master, SPI_SLV_STATUS_READBACK -#define SPIS1LBUF 16 //9 bit in SPIxS1 default:0 (1bit), SPI_SLV_BUF_BITLEN -#define SPIS1LRBA 10 //6 bit in SPIxS1 default:0 (1bit), SPI_SLV_RD_ADDR_BITLEN -#define SPIS1LWBA 4 //6 bit in SPIxS1 default:0 (1bit), SPI_SLV_WR_ADDR_BITLEN -#define SPIS1WSDE (1 << 3) //SPI_SLV_WRSTA_DUMMY_EN -#define SPIS1RSDE (1 << 2) //SPI_SLV_RDSTA_DUMMY_EN -#define SPIS1WBDE (1 << 1) //SPI_SLV_WRBUF_DUMMY_EN -#define SPIS1RBDE (1 << 0) //SPI_SLV_RDBUF_DUMMY_EN - -//SPI Slave2 (SPIxS2) -#define SPIS2WBDL 0xFF //SPI_SLV_WRBUF_DUMMY_CYCLELEN -#define SPIS2WBDL_S 24 //SPI_SLV_WRBUF_DUMMY_CYCLELEN_S -#define SPIS2RBDL 0xFF //SPI_SLV_RDBUF_DUMMY_CYCLELEN -#define SPIS2RBDL_S 16 //SPI_SLV_RDBUF_DUMMY_CYCLELEN_S -#define SPIS2WSDL 0xFF //SPI_SLV_WRSTA_DUMMY_CYCLELEN -#define SPIS2WSDL_S 8 //SPI_SLV_WRSTA_DUMMY_CYCLELEN_S -#define SPIS2RSDL 0xFF //SPI_SLV_RDSTA_DUMMY_CYCLELEN -#define SPIS2RSDL_S 0 //SPI_SLV_RDSTA_DUMMY_CYCLELEN_S - -//SPI Slave3 (SPIxS3) -#define SPIS3WSCV 0xFF //SPI_SLV_WRSTA_CMD_VALUE -#define SPIS3WSCV_S 24 //SPI_SLV_WRSTA_CMD_VALUE_S -#define SPIS3RSCV 0xFF //SPI_SLV_RDSTA_CMD_VALUE -#define SPIS3RSCV_S 16 //SPI_SLV_RDSTA_CMD_VALUE_S -#define SPIS3WBCV 0xFF //SPI_SLV_WRBUF_CMD_VALUE -#define SPIS3WBCV_S 8 //SPI_SLV_WRBUF_CMD_VALUE_S -#define SPIS3RBCV 0xFF //SPI_SLV_RDBUF_CMD_VALUE -#define SPIS3RBCV_S 0 //SPI_SLV_RDBUF_CMD_VALUE_S - -//SPI EXT0 (SPIxE0) -#define SPIE0TPPEN (1 << 31) //SPI_T_PP_ENA -#define SPIE0TPPS 0xF //SPI_T_PP_SHIFT -#define SPIE0TPPS_S 16 //SPI_T_PP_SHIFT_S -#define SPIE0TPPT 0xFFF //SPI_T_PP_TIME -#define SPIE0TPPT_S 0 //SPI_T_PP_TIME_S - -//SPI EXT1 (SPIxE1) -#define SPIE1TEREN (1 << 31) //SPI_T_ERASE_ENA -#define SPIE1TERS 0xF //SPI_T_ERASE_SHIFT -#define SPIE1TERS_S 16 //SPI_T_ERASE_SHIFT_S -#define SPIE1TERT 0xFFF //SPI_T_ERASE_TIME -#define SPIE1TERT_S 0 //SPI_T_ERASE_TIME_S - -//SPI EXT2 (SPIxE2) -#define SPIE2ST 0x7 //SPI_ST -#define SPIE2ST_S 0 //SPI_ST_S - -//SPI EXT3 (SPIxE3) -#define SPIE2IHEN 0x3 //SPI_INT_HOLD_ENA -#define SPIE2IHEN_S 0 //SPI_INT_HOLD_ENA_S - -//SLC (DMA) Registers -#define SLCC0 ESP8266_REG(0xB00) //SLC_CONF0 -#define SLCIR ESP8266_REG(0xB04) //SLC_INT_RAW -#define SLCIS ESP8266_REG(0xB08) //SLC_INT_STATUS -#define SLCIE ESP8266_REG(0xB0C) //SLC_INT_ENA -#define SLCIC ESP8266_REG(0xB10) //SLC_INT_CLR -#define SLCRXS ESP8266_REG(0xB14) //SLC_RX_STATUS -#define SLCRXP ESP8266_REG(0xB18) //SLC_RX_FIFO_PUSH -#define SLCTXS ESP8266_REG(0xB1C) //SLC_TX_STATUS -#define SLCTXP ESP8266_REG(0xB20) //SLC_TX_FIFO_POP -#define SLCRXL ESP8266_REG(0xB24) //SLC_RX_LINK -#define SLCTXL ESP8266_REG(0xB28) //SLC_TX_LINK -#define SLCIVTH ESP8266_REG(0xB2C) //SLC_INTVEC_TOHOST -#define SLCT0 ESP8266_REG(0xB30) //SLC_TOKEN0 -#define SLCT1 ESP8266_REG(0xB34) //SLC_TOKEN1 -#define SLCC1 ESP8266_REG(0xB38) //SLC_CONF1 -#define SLCS0 ESP8266_REG(0xB3C) //SLC_STATE0 -#define SLCS1 ESP8266_REG(0xB40) //SLC_STATE1 -#define SLCBC ESP8266_REG(0xB44) //SLC_BRIDGE_CONF -#define SLCRXEDA ESP8266_REG(0xB48) //SLC_RX_EOF_DES_ADDR -#define SLCTXEDA ESP8266_REG(0xB4C) //SLC_TX_EOF_DES_ADDR -#define SLCRXEBDA ESP8266_REG(0xB50) //SLC_RX_EOF_BFR_DES_ADDR -#define SLCAT ESP8266_REG(0xB54) //SLC_AHB_TEST -#define SLCSS ESP8266_REG(0xB58) //SLC_SDIO_ST -#define SLCRXDC ESP8266_REG(0xB5C) //SLC_RX_DSCR_CONF -#define SLCTXD ESP8266_REG(0xB60) //SLC_TXLINK_DSCR -#define SLCTXDB0 ESP8266_REG(0xB64) //SLC_TXLINK_DSCR_BF0 -#define SLCTXDB1 ESP8266_REG(0xB68) //SLC_TXLINK_DSCR_BF1 -#define SLCRXD ESP8266_REG(0xB6C) //SLC_RXLINK_DSCR -#define SLCRXDB0 ESP8266_REG(0xB70) //SLC_RXLINK_DSCR_BF0 -#define SLCRXDB1 ESP8266_REG(0xB74) //SLC_RXLINK_DSCR_BF1 -#define SLCDT ESP8266_REG(0xB78) //SLC_DATE -#define SLCID ESP8266_REG(0xB7C) //SLC_ID -#define SLCHIR ESP8266_REG(0xB88) //SLC_HOST_INTR_RAW -#define SLCHC0 ESP8266_REG(0xB94) //SLC_HOST_CONF_W0 -#define SLCHC1 ESP8266_REG(0xB98) //SLC_HOST_CONF_W1 -#define SLCHIS ESP8266_REG(0xB9C) //SLC_HOST_INTR_ST -#define SLCHC2 ESP8266_REG(0xBA0) //SLC_HOST_CONF_W2 -#define SLCHC3 ESP8266_REG(0xBA4) //SLC_HOST_CONF_W3 -#define SLCHC4 ESP8266_REG(0xBA8) //SLC_HOST_CONF_W4 -#define SLCHIC ESP8266_REG(0xBB0) //SLC_HOST_INTR_CLR -#define SLCHIE ESP8266_REG(0xBB4) //SLC_HOST_INTR_ENA -#define SLCHC5 ESP8266_REG(0xBBC) //SLC_HOST_CONF_W5 - -//SLC (DMA) CONF0 -#define SLCMM (0x3) //SLC_MODE -#define SLCM (12) //SLC_MODE_S -#define SLCDTBE (1 << 9) //SLC_DATA_BURST_EN -#define SLCDBE (1 << 8) //SLC_DSCR_BURST_EN -#define SLCRXNRC (1 << 7) //SLC_RX_NO_RESTART_CLR -#define SLCRXAW (1 << 6) //SLC_RX_AUTO_WRBACK -#define SLCRXLT (1 << 5) //SLC_RX_LOOP_TEST -#define SLCTXLT (1 << 4) //SLC_TX_LOOP_TEST -#define SLCAR (1 << 3) //SLC_AHBM_RST -#define SLCAFR (1 << 2) //SLC_AHBM_FIFO_RST -#define SLCRXLR (1 << 1) //SLC_RXLINK_RST -#define SLCTXLR (1 << 0) //SLC_TXLINK_RST - -//SLC (DMA) INT -#define SLCITXDE (1 << 21) //SLC_TX_DSCR_EMPTY_INT -#define SLCIRXDER (1 << 20) //SLC_RX_DSCR_ERR_INT -#define SLCITXDER (1 << 19) //SLC_TX_DSCR_ERR_INT -#define SLCITH (1 << 18) //SLC_TOHOST_INT -#define SLCIRXEOF (1 << 17) //SLC_RX_EOF_INT -#define SLCIRXD (1 << 16) //SLC_RX_DONE_INT -#define SLCITXEOF (1 << 15) //SLC_TX_EOF_INT -#define SLCITXD (1 << 14) //SLC_TX_DONE_INT -#define SLCIT0 (1 << 13) //SLC_TOKEN1_1TO0_INT -#define SLCIT1 (1 << 12) //SLC_TOKEN0_1TO0_INT -#define SLCITXO (1 << 11) //SLC_TX_OVF_INT -#define SLCIRXU (1 << 10) //SLC_RX_UDF_INT -#define SLCITXS (1 << 9) //SLC_TX_START_INT -#define SLCIRXS (1 << 8) //SLC_RX_START_INT -#define SLCIFH7 (1 << 7) //SLC_FRHOST_BIT7_INT -#define SLCIFH6 (1 << 6) //SLC_FRHOST_BIT6_INT -#define SLCIFH5 (1 << 5) //SLC_FRHOST_BIT5_INT -#define SLCIFH4 (1 << 4) //SLC_FRHOST_BIT4_INT -#define SLCIFH3 (1 << 3) //SLC_FRHOST_BIT3_INT -#define SLCIFH2 (1 << 2) //SLC_FRHOST_BIT2_INT -#define SLCIFH1 (1 << 1) //SLC_FRHOST_BIT1_INT -#define SLCIFH0 (1 << 0) //SLC_FRHOST_BIT0_INT - -//SLC (DMA) RX_STATUS -#define SLCRXE (1 << 1) //SLC_RX_EMPTY -#define SLCRXF (1 << 0) //SLC_RX_FULL - -//SLC (DMA) TX_STATUS -#define SLCTXE (1 << 1) //SLC_TX_EMPTY -#define SLCTXF (1 << 0) //SLC_TX_FULL - -//SLC (DMA) RX_FIFO_PUSH -#define SLCRXFP (1 << 16) //SLC_RXFIFO_PUSH -#define SLCRXWDM (0x1FF) //SLC_RXFIFO_WDATA -#define SLCRXWD (0) //SLC_RXFIFO_WDATA_S - -//SLC (DMA) TX_FIFO_POP -#define SLCTXFP (1 << 16) //SLC_TXFIFO_POP -#define SLCTXRDM (0x7FF) //SLC_TXFIFO_RDATA -#define SLCTXRD (0) //SLC_TXFIFO_RDATA_S - -//SLC (DMA) RX_LINK -#define SLCRXLP (1 << 31) //SLC_RXLINK_PARK -#define SLCRXLRS (1 << 30) //SLC_RXLINK_RESTART -#define SLCRXLS (1 << 29) //SLC_RXLINK_START -#define SLCRXLE (1 << 28) //SLC_RXLINK_STOP -#define SLCRXLAM (0xFFFF) //SLC_RXLINK_DESCADDR_MASK -#define SLCRXLA (0) //SLC_RXLINK_ADDR_S - -//SLC (DMA) TX_LINK -#define SLCTXLP (1 << 31) //SLC_TXLINK_PARK -#define SLCTXLRS (1 << 30) //SLC_TXLINK_RESTART -#define SLCTXLS (1 << 29) //SLC_TXLINK_START -#define SLCTXLE (1 << 28) //SLC_TXLINK_STOP -#define SLCTXLAM (0xFFFF) //SLC_TXLINK_DESCADDR_MASK -#define SLCTXLA (0) //SLC_TXLINK_ADDR_S - -//SLC (DMA) TOKENx -#define SLCTM (0xFFF) //SLC_TOKENx_MASK -#define SLCTT (16) //SLC_TOKENx_S -#define SLCTIM (1 << 14) //SLC_TOKENx_LOCAL_INC_MORE -#define SLCTI (1 << 13) //SLC_TOKENx_LOCAL_INC -#define SLCTW (1 << 12) //SLC_TOKENx_LOCAL_WR -#define SLCTDM (0xFFF) //SLC_TOKENx_LOCAL_WDATA -#define SLCTD (0) //SLC_TOKENx_LOCAL_WDATA_S - -//SLC (DMA) BRIDGE_CONF -#define SLCBFMEM (0xF) //SLC_FIFO_MAP_ENA -#define SLCBFME (8) //SLC_FIFO_MAP_ENA_S -#define SLCBTEEM (0x3F) //SLC_TXEOF_ENA -#define SLCBTEE (0) //SLC_TXEOF_ENA_S - -//SLC (DMA) AHB_TEST -#define SLCATAM (0x3) //SLC_AHB_TESTADDR -#define SLCATA (4) //SLC_AHB_TESTADDR_S -#define SLCATMM (0x7) //SLC_AHB_TESTMODE -#define SLCATM (0) //SLC_AHB_TESTMODE_S - -//SLC (DMA) SDIO_ST -#define SLCSBM (0x7) //SLC_BUS_ST -#define SLCSB (12) //SLC_BUS_ST_S -#define SLCSW (1 << 8) //SLC_SDIO_WAKEUP -#define SLCSFM (0xF) //SLC_FUNC_ST -#define SLCSF (4) //SLC_FUNC_ST_S -#define SLCSCM (0x7) //SLC_CMD_ST -#define SLCSC (0) //SLC_CMD_ST_S - -//SLC (DMA) RX_DSCR_CONF -#define SLCBRXFE (1 << 20) //SLC_RX_FILL_EN -#define SLCBRXEM (1 << 19) //SLC_RX_EOF_MODE -#define SLCBRXFM (1 << 18) //SLC_RX_FILL_MODE -#define SLCBINR (1 << 17) //SLC_INFOR_NO_REPLACE -#define SLCBTNR (1 << 16) //SLC_TOKEN_NO_REPLACE -#define SLCBPICM (0xFFFF) //SLC_POP_IDLE_CNT -#define SLCBPIC (0) //SLC_POP_IDLE_CNT_S - -// I2S Registers -#define i2c_bbpll 0x67 -#define i2c_bbpll_hostid 4 -#define i2c_bbpll_en_audio_clock_out 4 -#define i2c_bbpll_en_audio_clock_out_msb 7 -#define i2c_bbpll_en_audio_clock_out_lsb 7 -#define I2S_CLK_ENABLE() i2c_writeReg_Mask_def(i2c_bbpll, i2c_bbpll_en_audio_clock_out, 1) -#define I2SBASEFREQ (160000000L) - -#define I2STXF ESP8266_REG(0xe00) //I2STXFIFO (32bit) -#define I2SRXF ESP8266_REG(0xe04) //I2SRXFIFO (32bit) -#define I2SC ESP8266_REG(0xe08) //I2SCONF -#define I2SIR ESP8266_REG(0xe0C) //I2SINT_RAW -#define I2SIS ESP8266_REG(0xe10) //I2SINT_ST -#define I2SIE ESP8266_REG(0xe14) //I2SINT_ENA -#define I2SIC ESP8266_REG(0xe18) //I2SINT_CLR -#define I2ST ESP8266_REG(0xe1C) //I2STIMING -#define I2SFC ESP8266_REG(0xe20) //I2S_FIFO_CONF -#define I2SRXEN ESP8266_REG(0xe24) //I2SRXEOF_NUM (32bit) -#define I2SCSD ESP8266_REG(0xe28) //I2SCONF_SIGLE_DATA (32bit) -#define I2SCC ESP8266_REG(0xe2C) //I2SCONF_CHAN - -// I2S CONF -#define I2SBDM (0x3F) //I2S_BCK_DIV_NUM -#define I2SBD (22) //I2S_BCK_DIV_NUM_S -#define I2SCDM (0x3F) //I2S_CLKM_DIV_NUM -#define I2SCD (16) //I2S_CLKM_DIV_NUM_S -#define I2SBMM (0xF) //I2S_BITS_MOD -#define I2SBM (12) //I2S_BITS_MOD_S -#define I2SRMS (1 << 11) //I2S_RECE_MSB_SHIFT -#define I2STMS (1 << 10) //I2S_TRANS_MSB_SHIFT -#define I2SRXS (1 << 9) //I2S_I2S_RX_START -#define I2STXS (1 << 8) //I2S_I2S_TX_START -#define I2SMR (1 << 7) //I2S_MSB_RIGHT -#define I2SRF (1 << 6) //I2S_RIGHT_FIRST -#define I2SRSM (1 << 5) //I2S_RECE_SLAVE_MOD -#define I2STSM (1 << 4) //I2S_TRANS_SLAVE_MOD -#define I2SRXFR (1 << 3) //I2S_I2S_RX_FIFO_RESET -#define I2STXFR (1 << 2) //I2S_I2S_TX_FIFO_RESET -#define I2SRXR (1 << 1) //I2S_I2S_RX_RESET -#define I2STXR (1 << 0) //I2S_I2S_TX_RESET -#define I2SRST (0xF) //I2S_I2S_RESET_MASK - -//I2S INT -#define I2SITXRE (1 << 5) //I2S_I2S_TX_REMPTY_INT -#define I2SITXWF (1 << 4) //I2S_I2S_TX_WFULL_INT -#define I2SIRXRE (1 << 3) //I2S_I2S_RX_REMPTY_INT -#define I2SIRXWF (1 << 2) //I2S_I2S_RX_WFULL_INT -#define I2SITXPD (1 << 1) //I2S_I2S_TX_PUT_DATA_INT -#define I2SIRXTD (1 << 0) //I2S_I2S_RX_TAKE_DATA_INT - -//I2S TIMING -#define I2STBII (1 << 22) //I2S_TRANS_BCK_IN_INV -#define I2SRDS (1 << 21) //I2S_RECE_DSYNC_SW -#define I2STDS (1 << 20) //I2S_TRANS_DSYNC_SW -#define I2SRBODM (0x3) //I2S_RECE_BCK_OUT_DELAY -#define I2SRBOD (18) //I2S_RECE_BCK_OUT_DELAY_S -#define I2SRWODM (0x3) //I2S_RECE_WS_OUT_DELAY -#define I2SRWOD (16) //I2S_RECE_WS_OUT_DELAY_S -#define I2STSODM (0x3) //I2S_TRANS_SD_OUT_DELAY -#define I2STSOD (14) //I2S_TRANS_SD_OUT_DELAY_S -#define I2STWODM (0x3) //I2S_TRANS_WS_OUT_DELAY -#define I2STWOD (12) //I2S_TRANS_WS_OUT_DELAY_S -#define I2STBODM (0x3) //I2S_TRANS_BCK_OUT_DELAY -#define I2STBOD (10) //I2S_TRANS_BCK_OUT_DELAY_S -#define I2SRSIDM (0x3) //I2S_RECE_SD_IN_DELAY -#define I2SRSID (8) //I2S_RECE_SD_IN_DELAY_S -#define I2SRWIDM (0x3) //I2S_RECE_WS_IN_DELAY -#define I2SRWID (6) //I2S_RECE_WS_IN_DELAY_S -#define I2SRBIDM (0x3) //I2S_RECE_BCK_IN_DELAY -#define I2SRBID (4) //I2S_RECE_BCK_IN_DELAY_S -#define I2STWIDM (0x3) //I2S_TRANS_WS_IN_DELAY -#define I2STWID (2) //I2S_TRANS_WS_IN_DELAY_S -#define I2STBIDM (0x3) //I2S_TRANS_BCK_IN_DELAY -#define I2STBID (0) //I2S_TRANS_BCK_IN_DELAY_S - -//I2S FIFO CONF -#define I2SRXFMM (0x7) //I2S_I2S_RX_FIFO_MOD -#define I2SRXFM (16) //I2S_I2S_RX_FIFO_MOD_S -#define I2STXFMM (0x7) //I2S_I2S_TX_FIFO_MOD -#define I2STXFM (13) //I2S_I2S_TX_FIFO_MOD_S -#define I2SDE (1 << 12) //I2S_I2S_DSCR_EN -#define I2STXDNM (0x3F) //I2S_I2S_TX_DATA_NUM -#define I2STXDN (6) //I2S_I2S_TX_DATA_NUM_S -#define I2SRXDNM (0x3F) //I2S_I2S_RX_DATA_NUM -#define I2SRXDN (0) //I2S_I2S_RX_DATA_NUM_S - -//I2S CONF CHAN -#define I2SRXCMM (0x3) //I2S_RX_CHAN_MOD -#define I2SRXCM (3) //I2S_RX_CHAN_MOD_S -#define I2STXCMM (0x7) //I2S_TX_CHAN_MOD -#define I2STXCM (0) //I2S_TX_CHAN_MOD_S - -/** - Random Number Generator 32bit - http://esp8266-re.foogod.com/wiki/Random_Number_Generator -**/ -#define RANDOM_REG32 ESP8266_DREG(0x20E44) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/Sming/Arch/Esp32/Core/pins_arduino.h b/Sming/Arch/Esp32/Core/pins_arduino.h index 04af3f5be1..e459d5bd5a 100644 --- a/Sming/Arch/Esp32/Core/pins_arduino.h +++ b/Sming/Arch/Esp32/Core/pins_arduino.h @@ -12,8 +12,6 @@ #pragma once -#include "peripheral.h" - #define EXTERNAL_NUM_INTERRUPTS 16 #define NUM_DIGITAL_PINS 40 #define NUM_ANALOG_INPUTS 16 diff --git a/Sming/Arch/Esp8266/Core/HardwarePWM.cpp b/Sming/Arch/Esp8266/Core/HardwarePWM.cpp index 13aa43764a..1483df469e 100644 --- a/Sming/Arch/Esp8266/Core/HardwarePWM.cpp +++ b/Sming/Arch/Esp8266/Core/HardwarePWM.cpp @@ -33,6 +33,25 @@ extern const uint8_t esp8266_pinmuxOffset[]; +static const uint8_t gpioPinFunc[]{ + FUNC_GPIO0, // + FUNC_GPIO1, // + FUNC_GPIO2, // + FUNC_GPIO3, // + FUNC_GPIO4, // + FUNC_GPIO5, // + FUNC_GPIO6, // + FUNC_GPIO7, // + FUNC_GPIO8, // + FUNC_GPIO9, // + FUNC_GPIO10, // + FUNC_GPIO11, // + FUNC_GPIO12, // + FUNC_GPIO13, // + FUNC_GPIO14, // + FUNC_GPIO15, // +}; + HardwarePWM::HardwarePWM(uint8_t* pins, uint8_t noOfPins) : channel_count(noOfPins) { if(noOfPins == 0) { @@ -49,7 +68,7 @@ HardwarePWM::HardwarePWM(uint8_t* pins, uint8_t noOfPins) : channel_count(noOfPi continue; } ioInfo[pinCount][0] = PERIPHS_IO_MUX + esp8266_pinmuxOffset[pin]; - ioInfo[pinCount][1] = esp8266_gpioToFn[pin]; + ioInfo[pinCount][1] = gpioPinFunc[pin]; ioInfo[pinCount][2] = pin; pwmDutyInit[pinCount] = 0; // Start with zero output channels[pinCount] = pin; From 166d5fe025125fc2d1a11febe49a7faa1f65fef5 Mon Sep 17 00:00:00 2001 From: slaff Date: Fri, 18 Oct 2024 09:50:26 +0200 Subject: [PATCH 15/34] Fixed typos reported by codespell. (#2890) --- docs/source/information/develop/ci.rst | 2 +- docs/source/upgrading/5.1-5.2.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/information/develop/ci.rst b/docs/source/information/develop/ci.rst index 1a0b1350f6..e10ef07edf 100644 --- a/docs/source/information/develop/ci.rst +++ b/docs/source/information/develop/ci.rst @@ -97,7 +97,7 @@ To evaluate how much would be removed run this command (it's safe):: python clean-tools.py scan -To perform 'dry-run' of a clean operation, without actually deleteing anything:: +To perform 'dry-run' of a clean operation, without actually deleting anything:: python clean-tools.py clean diff --git a/docs/source/upgrading/5.1-5.2.rst b/docs/source/upgrading/5.1-5.2.rst index 55cbc7a831..523fb5177c 100644 --- a/docs/source/upgrading/5.1-5.2.rst +++ b/docs/source/upgrading/5.1-5.2.rst @@ -18,7 +18,7 @@ The procedure has therefore been revised to use installation scripts instead of The initial installation step to bootstrap the installation remains unchanged: The ``choco-install.cmd`` script is fetched from the Sming ``develop`` branch and executed. The custom choco scripts have been replaced with scripted logic. -Installation of toolchains is done as a separate step as it does not require administrative priviledges. +Installation of toolchains is done as a separate step as it does not require administrative privileges. The documentation at https://sming.readthedocs.io/en/latest/getting-started/windows/index.html has been updated to reflect these changes. From 389259019a2fca6b9cf2d354e9e41f6d10c3d179 Mon Sep 17 00:00:00 2001 From: Mike Date: Sun, 20 Oct 2024 07:41:29 +0100 Subject: [PATCH 16/34] Add `JSON streaming parser` and `configuration database` libraries (#2892) This PR adds an initial release of the `ConfigDB` library which arose from discussion #2871. The library does not use `ArduinoJson` but instead a streaming parser which is a useful addition and well suited to parsing and filtering large data sets. --- .gitmodules | 8 ++++++++ Sming/Libraries/ConfigDB | 1 + Sming/Libraries/JsonStreamingParser | 1 + 3 files changed, 10 insertions(+) create mode 160000 Sming/Libraries/ConfigDB create mode 160000 Sming/Libraries/JsonStreamingParser diff --git a/.gitmodules b/.gitmodules index a1404fb3cd..cbd4b056cb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -213,6 +213,10 @@ path = Sming/Libraries/Arduino_TensorFlowLite url = https://github.com/slaff/Arduino_TensorFlowLite.git ignore = dirty +[submodule "Libraries.ConfigDB"] + path = Sming/Libraries/ConfigDB + url = https://github.com/mikee47/ConfigDB + ignore = dirty [submodule "Libraries.CS5460"] path = Sming/Libraries/CS5460/CS5460 url = https://github.com/xxzl0130/CS5460.git @@ -281,6 +285,10 @@ path = Sming/Libraries/ITEADLIB_Arduino_Nextion url = https://github.com/itead/ITEADLIB_Arduino_Nextion.git ignore = dirty +[submodule "Libraries.JsonStreamingParser"] + path = Sming/Libraries/JsonStreamingParser + url = https://github.com/mikee47/JsonStreamingParser + ignore = dirty [submodule "Libraries.libsodium"] path = Sming/Libraries/libsodium/libsodium url = https://github.com/jedisct1/libsodium.git diff --git a/Sming/Libraries/ConfigDB b/Sming/Libraries/ConfigDB new file mode 160000 index 0000000000..034ec0b691 --- /dev/null +++ b/Sming/Libraries/ConfigDB @@ -0,0 +1 @@ +Subproject commit 034ec0b69195c6e3ff5babb404786c8071edbd06 diff --git a/Sming/Libraries/JsonStreamingParser b/Sming/Libraries/JsonStreamingParser new file mode 160000 index 0000000000..46c8271829 --- /dev/null +++ b/Sming/Libraries/JsonStreamingParser @@ -0,0 +1 @@ +Subproject commit 46c8271829c685c912b8926a6630c676080f4f9e From 2c08c851efda1b2e284c1de34e182e31ba179b6c Mon Sep 17 00:00:00 2001 From: slaff Date: Thu, 24 Oct 2024 11:02:43 +0200 Subject: [PATCH 17/34] Allow installation on Ubuntu 24.04 (#2893) Ubuntu 24.04 is not allowing the overwriting of system python packages. In such cases it is recommended to create virtual environment and activate it to avoid conflicts with the python packages coming from the OS. --- Tools/export.sh | 6 ++++++ Tools/install.sh | 13 ++++++++++++- Tools/requirements.txt | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Tools/export.sh b/Tools/export.sh index 602bc4423a..b619427169 100755 --- a/Tools/export.sh +++ b/Tools/export.sh @@ -30,6 +30,12 @@ if [ -z "$SMING_HOME" ]; then fi # Common + +# Python Virtual Environment +if [ -f ~/.venvs/Sming/bin/activate ]; then + source ~/.venvs/Sming/bin/activate +fi + export PYTHON=${PYTHON:=$(which python3)} # Esp8266 diff --git a/Tools/install.sh b/Tools/install.sh index f43d0cd56b..94136ed286 100755 --- a/Tools/install.sh +++ b/Tools/install.sh @@ -125,6 +125,15 @@ check_for_installed_files() { fi } +install_venv() { + echo + echo "!!! Trying to install Python Virtual Environment !!!" + mkdir -p ~/.venvs/ + python3 -m venv ~/.venvs/Sming + source ~/.venvs/Sming/bin/activate + eval "$1" +} + # Installers put downloaded archives here DOWNLOADS="downloads" mkdir -p $DOWNLOADS @@ -243,7 +252,9 @@ if [ -f "/usr/bin/clang-format-8" ]; then sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-8 100 fi -python3 -m pip install --upgrade pip protobuf -r "$SMING_HOME/../Tools/requirements.txt" +PYTHON_INSTALL_CMD="python3 -m pip install --upgrade pip -r \"$SMING_HOME/../Tools/requirements.txt\"" + +eval "$PYTHON_INSTALL_CMD" || $PKG_INSTALL python3-venv && install_venv "$PYTHON_INSTALL_CMD" install() { diff --git a/Tools/requirements.txt b/Tools/requirements.txt index 2dacbee54b..018c3fc615 100644 --- a/Tools/requirements.txt +++ b/Tools/requirements.txt @@ -1,3 +1,4 @@ +protobuf pyserial jsonschema kconfiglib From 66a258b854389fbe2135779ec033f7056c600f3e Mon Sep 17 00:00:00 2001 From: slaff Date: Fri, 25 Oct 2024 13:43:29 +0200 Subject: [PATCH 18/34] Add env var SMING_TOOLCHAINS to allow easier change of toolchains installation folder (#2894) --- Tools/export.sh | 11 +++++++---- docs/source/getting-started/config.rst | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Tools/export.sh b/Tools/export.sh index b619427169..3a6f885d06 100755 --- a/Tools/export.sh +++ b/Tools/export.sh @@ -38,15 +38,18 @@ fi export PYTHON=${PYTHON:=$(which python3)} +# Toolchain paths +export SMING_TOOLCHAINS=${SMING_TOOLCHAINS:=/opt} + # Esp8266 -export ESP_HOME=${ESP_HOME:=/opt/esp-quick-toolchain} +export ESP_HOME=${ESP_HOME:=$SMING_TOOLCHAINS/esp-quick-toolchain} # Esp32 -export IDF_PATH=${IDF_PATH:=/opt/esp-idf} -export IDF_TOOLS_PATH=${IDF_TOOLS_PATH:=/opt/esp32} +export IDF_PATH=${IDF_PATH:=$SMING_TOOLCHAINS/esp-idf} +export IDF_TOOLS_PATH=${IDF_TOOLS_PATH:=$SMING_TOOLCHAINS/esp32} # Rp2040 -export PICO_TOOLCHAIN_PATH=${PICO_TOOLCHAIN_PATH:=/opt/rp2040} +export PICO_TOOLCHAIN_PATH=${PICO_TOOLCHAIN_PATH:=$SMING_TOOLCHAINS/rp2040} # Provide non-apple CLANG (e.g. for rbpf library) if [ -n "$GITHUB_ACTIONS" ] && [ "$(uname)" = "Darwin" ]; then diff --git a/docs/source/getting-started/config.rst b/docs/source/getting-started/config.rst index 28b4089475..7157afc439 100644 --- a/docs/source/getting-started/config.rst +++ b/docs/source/getting-started/config.rst @@ -11,11 +11,21 @@ and integrated development environments (IDEs) work correctly. You can find a list of these in :source:`Tools/export.sh`. -For Linux and WSL2, append values to your ``~/.bashrc`` file:: +For Linux and WSL2, append :envvar:`SMING_HOME` to your ``~/.bashrc`` file:: # All architectures export SMING_HOME=/opt/sming/Sming - + +:envvar:`SMING_HOME` is the only mandatory environmental variable. + +If you want to change the location where the toolchain will be downloaded and installed you can append the values below:: + + # Specifies a common toolchains directory + export SMING_TOOLCHAINS=/opt + +The :envvar:`SMING_TOOLCHAINS` is optional. As are the ones below. You can append them to your ``~/.bashrc`` file only +if you need to change the location of the installed toolchains:: + # Esp8266 export ESP_HOME=/opt/esp-quick-toolchain From 0447ab4be23e77c1120444ef463125061bd7de58 Mon Sep 17 00:00:00 2001 From: Peter Jakobs Date: Mon, 28 Oct 2024 11:15:17 +0100 Subject: [PATCH 19/34] Catch situations where mqttClient::connect is called with an empty clientName. --- Sming/Components/Network/src/Network/Mqtt/MqttClient.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sming/Components/Network/src/Network/Mqtt/MqttClient.cpp b/Sming/Components/Network/src/Network/Mqtt/MqttClient.cpp index be7e8896a7..0d9bd1bc7b 100644 --- a/Sming/Components/Network/src/Network/Mqtt/MqttClient.cpp +++ b/Sming/Components/Network/src/Network/Mqtt/MqttClient.cpp @@ -199,11 +199,16 @@ bool MqttClient::setWill(const String& topic, const String& message, uint8_t fla bool MqttClient::connect(const Url& url, const String& clientName) { this->url = url; + bool useSsl{url.Scheme == URI_SCHEME_MQTT_SECURE}; if(!useSsl && url.Scheme != URI_SCHEME_MQTT) { debug_e("Only mqtt and mqtts protocols are allowed"); return false; } + if(clientName == "") { + debug_e("clientName cannot be empty"); + return false; + } if(getConnectionState() != eTCS_Ready) { close(); From 78e70fe4a264e19c0f04d62bf50c083ffc42477c Mon Sep 17 00:00:00 2001 From: Peter Jakobs Date: Thu, 31 Oct 2024 12:35:08 +0100 Subject: [PATCH 20/34] Fixed network scan on ESP32 (#2906) --- .../Components/Network/Arch/Esp32/Platform/StationImpl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp index 1c4af61451..bbaddc46c9 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp @@ -418,12 +418,12 @@ void StationImpl::staticScanCompleted(wifi_event_sta_scan_done_t* event, uint8_t if(station.scanCompletedCallback) { uint16_t number = event->number; wifi_ap_record_t ap_info[number]; - uint16_t ap_count{0}; + memset(ap_info, 0, sizeof(ap_info)); ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info)); - ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count)); + // TODO: Handle hidden APs - for(unsigned i = 0; (i < event->number) && (i < ap_count); i++) { + for(unsigned i = 0; i < number; i++) { list.addElement(new BssInfoImpl(&ap_info[i])); } station.scanCompletedCallback(true, list); From 20b4865d7c9f1d81b1522cf1269356b0c4c90d17 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 31 Oct 2024 20:23:32 +0000 Subject: [PATCH 21/34] Update documentation for `clang-format` (#2907) This PR updates the Sming coding style documentation as discussed in https://github.com/SmingHub/Sming/pull/2898#issuecomment-2441279933 and https://github.com/SmingHub/Sming/pull/2904#discussion_r1824291374. Sming requires version 8 which is generally no longer available in the standard repositories for recent GNU/Linux distributions. Different versions of clang-format produce different output with the same configuration. This is such a common problem that a kind soul has provided standalone builds here https://github.com/muttleyxd/clang-tools-static-binaries/releases. The default name of the clang-format executable has been changed to `clang-format-8`. This is because `clang-format` is now very unlikely to be the default installed version, and so avoids the subtle issues with running the wrong version. --- Sming/build.mk | 2 +- .../information/develop/clang-tools.rst | 42 +++++++++++++------ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/Sming/build.mk b/Sming/build.mk index b4d50a34f9..2dc96401f2 100644 --- a/Sming/build.mk +++ b/Sming/build.mk @@ -140,7 +140,7 @@ CMAKE ?= cmake # clang-format command DEBUG_VARS += CLANG_FORMAT -CLANG_FORMAT ?= clang-format +CLANG_FORMAT ?= clang-format-8 # more tools DEBUG_VARS += AWK diff --git a/docs/source/information/develop/clang-tools.rst b/docs/source/information/develop/clang-tools.rst index 683a89bfc5..41e5606794 100644 --- a/docs/source/information/develop/clang-tools.rst +++ b/docs/source/information/develop/clang-tools.rst @@ -15,16 +15,25 @@ Note that *clang-format* is part of the main **Clang** project, whilst *clang-ti found in **clang-tools-extra**. -Installation +clang-format ------------ -In Ubuntu you should be able to install them using the following command:: +Installation +~~~~~~~~~~~~ - sudo apt-get install clang-format clang-tidy +Sming requires version 8 which is generally no longer available in the standard repositories for recent GNU/Linux distributions. +You can find standalone builds at https://github.com/muttleyxd/clang-tools-static-binaries/releases. + +For example: + +``` +export CLANG_FORMAT=/opt/clang-format-8 +wget https://github.com/muttleyxd/clang-tools-static-binaries/releases/download/master-32d3ac78/clang-format-8_linux-amd64 -O /opt/clang-format-8 +chmod +x $CLANG_FORMAT +``` + +You should persist the definition for :envvar:`CLANG_FORMAT` as Sming uses this when running the ``make cs`` commands (see below). -See the the `download `__ page -of the Clang project for installation instructions for other operating -systems. .. important:: @@ -37,10 +46,6 @@ systems. You should install the same version on your development computer. - -clang-format ------------- - Rules ~~~~~ @@ -57,6 +62,8 @@ IDE integration There are multiple existing integrations for IDEs. You can find details in the `ClangFormat documentation `__. +For VS Code/Codium install the **clang-format** extension and configure the path with the location of the **clang-format-8** executable. + For the Eclipse IDE we recommend installing the `CppStyle plugin `__. You can configure your IDE to auto-format the code on "Save" using the @@ -114,12 +121,23 @@ C, C++ or header file or a selection in it and run the ``Format`` command clang-tidy ---------- -Configuration -~~~~~~~~~~~~~ +Installation +~~~~~~~~~~~~ No specific version is required but generally you should aim to use the most recent version available in your distribution. Version 17.0.6 was used at time of writing these notes. +In Ubuntu you should be able install using the following command:: + + sudo apt-get install clang-tidy + +See the the `download `__ page +of the Clang project for installation instructions for other operating +systems. + +Configuration +~~~~~~~~~~~~~ + The default tool configuration is defined in the `.clang-tidy `__ file, located in the root directory of the framework. From 9054e946779c2b35106be334a1b1467a2030f1cf Mon Sep 17 00:00:00 2001 From: Peter Jakobs Date: Mon, 4 Nov 2024 10:05:33 +0100 Subject: [PATCH 22/34] HardwarePWM Esp32 - added assert for max pwm channels (#2904) --- Sming/Arch/Esp32/Components/driver/include/driver/pwm.h | 7 ++----- Sming/Arch/Esp32/Core/HardwarePWM.cpp | 7 +++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Sming/Arch/Esp32/Components/driver/include/driver/pwm.h b/Sming/Arch/Esp32/Components/driver/include/driver/pwm.h index 570369049a..5b6e1c79b2 100644 --- a/Sming/Arch/Esp32/Components/driver/include/driver/pwm.h +++ b/Sming/Arch/Esp32/Components/driver/include/driver/pwm.h @@ -10,9 +10,6 @@ #pragma once -#ifdef SOC_LEDC_CHANNEL_NUM +#include + #define PWM_CHANNEL_NUM_MAX SOC_LEDC_CHANNEL_NUM -#else -// this should not happen if the correct esp32 includes are used, just to be absolutely sure -#define PWM_CHANNEL_NUM_MAX 8 -#endif diff --git a/Sming/Arch/Esp32/Core/HardwarePWM.cpp b/Sming/Arch/Esp32/Core/HardwarePWM.cpp index fcc387dc34..0b1a74f583 100644 --- a/Sming/Arch/Esp32/Core/HardwarePWM.cpp +++ b/Sming/Arch/Esp32/Core/HardwarePWM.cpp @@ -140,11 +140,10 @@ uint32_t maxDuty(ledc_timer_bit_t bits) HardwarePWM::HardwarePWM(uint8_t* pins, uint8_t no_of_pins) : channel_count(no_of_pins) { - debug_d("starting HardwarePWM init"); + assert(no_of_pins > 0 && no_of_pins <= SOC_LEDC_CHANNEL_NUM); + no_of_pins = std::min(uint8_t(SOC_LEDC_CHANNEL_NUM), no_of_pins); + periph_module_enable(PERIPH_LEDC_MODULE); - if((no_of_pins == 0) || (no_of_pins > SOC_LEDC_CHANNEL_NUM)) { - return; - } for(uint8_t i = 0; i < no_of_pins; i++) { channels[i] = pins[i]; From 6d94935b18801fa02fff35320fedc426b4993bd1 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 5 Nov 2024 14:54:22 +0000 Subject: [PATCH 23/34] Implement HardwarePWM class for Rp2040 and update Basic PWM sample (#2908) --- Sming/Arch/Esp32/Core/HardwarePWM.cpp | 18 +-- Sming/Arch/Esp8266/Core/HardwarePWM.cpp | 20 +-- Sming/Arch/Host/Core/HardwarePWM.cpp | 20 +-- .../Components/driver/include/driver/pwm.h | 86 +---------- Sming/Arch/Rp2040/Core/HardwarePWM.cpp | 135 +++++++++++++++++ Sming/Arch/Rp2040/Core/HardwarePWM.cpp.todo | 136 ------------------ Sming/Core/HardwarePWM.cpp | 26 ++++ Sming/Core/HardwarePWM.h | 50 +++++-- samples/Basic_HwPWM/app/application.cpp | 65 +++++---- samples/Basic_HwPWM/component.mk | 1 - 10 files changed, 259 insertions(+), 298 deletions(-) create mode 100644 Sming/Arch/Rp2040/Core/HardwarePWM.cpp delete mode 100644 Sming/Arch/Rp2040/Core/HardwarePWM.cpp.todo create mode 100644 Sming/Core/HardwarePWM.cpp diff --git a/Sming/Arch/Esp32/Core/HardwarePWM.cpp b/Sming/Arch/Esp32/Core/HardwarePWM.cpp index 0b1a74f583..183accf984 100644 --- a/Sming/Arch/Esp32/Core/HardwarePWM.cpp +++ b/Sming/Arch/Esp32/Core/HardwarePWM.cpp @@ -138,7 +138,7 @@ uint32_t maxDuty(ledc_timer_bit_t bits) } //namespace -HardwarePWM::HardwarePWM(uint8_t* pins, uint8_t no_of_pins) : channel_count(no_of_pins) +HardwarePWM::HardwarePWM(const uint8_t* pins, uint8_t no_of_pins) : channel_count(no_of_pins) { assert(no_of_pins > 0 && no_of_pins <= SOC_LEDC_CHANNEL_NUM); no_of_pins = std::min(uint8_t(SOC_LEDC_CHANNEL_NUM), no_of_pins); @@ -206,17 +206,7 @@ HardwarePWM::~HardwarePWM() } } -uint8_t HardwarePWM::getChannel(uint8_t pin) -{ - for(uint8_t i = 0; i < channel_count; i++) { - if(channels[i] == pin) { - return i; - } - } - return -1; -} - -uint32_t HardwarePWM::getDutyChan(uint8_t chan) +uint32_t HardwarePWM::getDutyChan(uint8_t chan) const { // esp32 defines the frequency / period per timer return (chan == PWM_BAD_CHANNEL) ? 0 : ledc_get_duty(pinToGroup(chan), pinToChannel(chan)); @@ -245,7 +235,7 @@ bool HardwarePWM::setDutyChan(uint8_t chan, uint32_t duty, bool update) return false; } -uint32_t HardwarePWM::getPeriod() +uint32_t HardwarePWM::getPeriod() const { // Sming does not know how to handle different frequencies for channels: this will require an extended interface. // For now, just report the period for group 0 channel 0. @@ -268,7 +258,7 @@ void HardwarePWM::update() // ledc_update_duty(); } -uint32_t HardwarePWM::getFrequency(uint8_t pin) +uint32_t HardwarePWM::getFrequency(uint8_t pin) const { return ledc_get_freq(pinToGroup(pin), pinToTimer(pin)); } diff --git a/Sming/Arch/Esp8266/Core/HardwarePWM.cpp b/Sming/Arch/Esp8266/Core/HardwarePWM.cpp index 1483df469e..50919441ad 100644 --- a/Sming/Arch/Esp8266/Core/HardwarePWM.cpp +++ b/Sming/Arch/Esp8266/Core/HardwarePWM.cpp @@ -52,7 +52,7 @@ static const uint8_t gpioPinFunc[]{ FUNC_GPIO15, // }; -HardwarePWM::HardwarePWM(uint8_t* pins, uint8_t noOfPins) : channel_count(noOfPins) +HardwarePWM::HardwarePWM(const uint8_t* pins, uint8_t noOfPins) : channel_count(noOfPins) { if(noOfPins == 0) { return; @@ -85,19 +85,7 @@ HardwarePWM::~HardwarePWM() // There is no function in the SDK to stop PWM output, yet. } -uint8_t HardwarePWM::getChannel(uint8_t pin) -{ - for(uint8_t i = 0; i < channel_count; i++) { - if(channels[i] == pin) { - return i; - } - } - - debug_d("getChannel: can't find pin %d", pin); - return PWM_BAD_CHANNEL; -} - -uint32_t HardwarePWM::getDutyChan(uint8_t chan) +uint32_t HardwarePWM::getDutyChan(uint8_t chan) const { return (chan == PWM_BAD_CHANNEL) ? 0 : pwm_get_duty(chan); } @@ -120,7 +108,7 @@ bool HardwarePWM::setDutyChan(uint8_t chan, uint32_t duty, bool update) return false; } -uint32_t HardwarePWM::getPeriod() +uint32_t HardwarePWM::getPeriod() const { return pwm_get_period(); } @@ -137,7 +125,7 @@ void HardwarePWM::update() pwm_start(); } -uint32_t HardwarePWM::getFrequency(uint8_t pin) +uint32_t HardwarePWM::getFrequency(uint8_t pin) const { (void)pin; auto period = pwm_get_period(); diff --git a/Sming/Arch/Host/Core/HardwarePWM.cpp b/Sming/Arch/Host/Core/HardwarePWM.cpp index cf5d2de430..4c867c2ee4 100644 --- a/Sming/Arch/Host/Core/HardwarePWM.cpp +++ b/Sming/Arch/Host/Core/HardwarePWM.cpp @@ -25,36 +25,36 @@ #include -HardwarePWM::HardwarePWM(uint8_t* pins, uint8_t no_of_pins) : channel_count(no_of_pins) +HardwarePWM::HardwarePWM(const uint8_t*, uint8_t no_of_pins) : channel_count(no_of_pins) { } HardwarePWM::~HardwarePWM() = default; -uint8_t HardwarePWM::getChannel(uint8_t pin) -{ - return PWM_BAD_CHANNEL; -} - -uint32_t HardwarePWM::getDutyChan(uint8_t chan) +uint32_t HardwarePWM::getDutyChan(uint8_t) const { return 0; } -bool HardwarePWM::setDutyChan(uint8_t chan, uint32_t duty, bool update) +bool HardwarePWM::setDutyChan(uint8_t, uint32_t, bool) { return false; } -uint32_t HardwarePWM::getPeriod() +uint32_t HardwarePWM::getPeriod() const { return 0; } -void HardwarePWM::setPeriod(uint32_t period) +void HardwarePWM::setPeriod(uint32_t) { } void HardwarePWM::update() { } + +uint32_t HardwarePWM::getFrequency(uint8_t) const +{ + return 0; +} diff --git a/Sming/Arch/Rp2040/Components/driver/include/driver/pwm.h b/Sming/Arch/Rp2040/Components/driver/include/driver/pwm.h index 8eb9f2560e..b55397e352 100644 --- a/Sming/Arch/Rp2040/Components/driver/include/driver/pwm.h +++ b/Sming/Arch/Rp2040/Components/driver/include/driver/pwm.h @@ -1,88 +1,8 @@ #pragma once -#if defined(__cplusplus) -extern "C" { -#endif - -// #include - -#define PWM_CHANNEL_NUM_MAX 16 - -/** - * @defgroup pwm_driver PWM driver - * @ingroup drivers - * @{ - */ - -/** - * @fn void pwm_init(uint32 period, uint32 *duty,uint32 pwm_channel_num,uint32 (*pin_info_list)[3]) - * @brief Initialize PWM function, including GPIO selection, period and duty cycle - * @param period PWM period - * @param duty duty cycle of each output - * @param pwm_channel_num PWM channel number - * @param pin_info_list Array containing an entry for each channel giving - * @note This API can be called only once. - * - * Example: - * - * uint32 io_info[][3] = { - * {PWM_0_OUT_IO_MUX, PWM_0_OUT_IO_FUNC, PWM_0_OUT_IO_NUM}, - * {PWM_1_OUT_IO_MUX, PWM_1_OUT_IO_FUNC, PWM_1_OUT_IO_NUM}, - * {PWM_2_OUT_IO_MUX, PWM_2_OUT_IO_FUNC, PWM_2_OUT_IO_NUM} - * }; - * - * pwm_init(light_param.pwm_period, light_param.pwm_duty, 3, io_info); - * - */ - /** - * @fn void pwm_start(void) - * @brief Starts PWM + * @brief Maximum number of active PWM channels. * - * This function needs to be called after PWM configuration is changed. + * The Pico has 8 PWM 'slices', each of which can drive two outputs. */ - -/** - * @fn void pwm_set_duty(uint32 duty, uint8 channel) - * @brief Sets duty cycle of a PWM output - * @param duty The time that high-level single will last, duty cycle will be (duty*45)/(period*1000) - * @param channel PWM channel, which depends on how many PWM channels are used - * - * Set the time that high-level signal will last. - * The range of duty depends on PWM period. Its maximum value of which can be Period * 1000 / 45. - * - * For example, for 1-KHz PWM, the duty range is 0 ~ 22222. - */ - -/** - * @fn uint32 pwm_get_duty(uint8 channel) - * @brief Get duty cycle of PWM output - * @param channel PWM channel, which depends on how many PWM channels are used - * @retval uint32 Duty cycle of PWM output - * - * Duty cycle will be (duty*45) / (period*1000). - */ - -/** - * @fn void pwm_set_period(uint32 period) - * @brief Set PWM period - * @param period PWM period in us. For example, 1-KHz PWM period = 1000us. - */ - -/** - * @fn uint32 pwm_get_period(void) - * @brief Get PWM period - * @retval uint32 Return PWM period in us. - */ - -/** - * @fn uint32 get_pwm_version(void) - * @brief Get version information of PWM - * @retval uint32 PWM version - */ - -/** @} */ - -#if defined(__cplusplus) -} -#endif +#define PWM_CHANNEL_NUM_MAX 16 diff --git a/Sming/Arch/Rp2040/Core/HardwarePWM.cpp b/Sming/Arch/Rp2040/Core/HardwarePWM.cpp new file mode 100644 index 0000000000..ba92f59be2 --- /dev/null +++ b/Sming/Arch/Rp2040/Core/HardwarePWM.cpp @@ -0,0 +1,135 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Rp2040/Core/HardwarePWM.cpp + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Note on use of divisor + * ---------------------- + * + * Divisor is 8:4 fractional value, so 1 <= int <= 255, 0 <= frac <= 15 + * Simplest way to use full range is to factor calculations by 16. + * + * Using default CSR_PH_CORRECT=0: + * + * F_PWM = 16 * F_SYS / (TOP + 1) / DIV + * + */ + +#define PWM_FREQ_DEFAULT 1000 + +HardwarePWM::HardwarePWM(const uint8_t* pins, uint8_t noOfPins) : channel_count(noOfPins) +{ + assert(noOfPins > 0 && noOfPins <= PWM_CHANNEL_NUM_MAX); + noOfPins = std::min(uint8_t(PWM_CHANNEL_NUM_MAX), noOfPins); + std::copy_n(pins, noOfPins, channels); + setPeriod(1e6 / PWM_FREQ_DEFAULT); + + for(unsigned i = 0; i < noOfPins; ++i) { + auto pin = channels[i]; + gpio_set_function(pin, GPIO_FUNC_PWM); + gpio_set_dir(pin, GPIO_OUT); + } +} + +HardwarePWM::~HardwarePWM() +{ + for(unsigned i = 0; i < channel_count; ++i) { + auto slice_num = pwm_gpio_to_slice_num(channels[i]); + pwm_set_enabled(slice_num, false); + } +} + +uint32_t HardwarePWM::getDutyChan(uint8_t chan) const +{ + if(chan >= channel_count) { + return 0; + } + auto pin = channels[chan]; + auto slice_num = pwm_gpio_to_slice_num(pin); + auto value = pwm_hw->slice[slice_num].cc; + value >>= pwm_gpio_to_channel(pin) ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB; + return value & 0xffff; +} + +bool HardwarePWM::setDutyChan(uint8_t chan, uint32_t duty, bool) +{ + if(chan >= channel_count) { + return false; + } + auto pin = channels[chan]; + duty = std::min(duty, maxduty); + pwm_set_gpio_level(pin, duty); + return true; +} + +uint32_t HardwarePWM::getPeriod() const +{ + // All channels configured with same clock + auto slice_num = pwm_gpio_to_slice_num(channels[0]); + uint32_t top = pwm_hw->slice[slice_num].top; + uint32_t div = pwm_hw->slice[slice_num].div; + return muldiv(62500ULL, (top + 1) * div, clock_get_hz(clk_sys)); +} + +void HardwarePWM::setPeriod(uint32_t period) +{ + const uint32_t topMax{0xffff}; + const uint32_t divMin{0x10}; // 1.0 + const uint32_t divMax{0xfff}; // INT + FRAC + auto sysFreq = clock_get_hz(clk_sys); + // Calculate divisor assuming maximum value for TOP: ensure value is rounded UP + uint32_t div = ((uint64_t(period) * sysFreq / 62500) + topMax) / (topMax + 1); + uint32_t top; + if(div > divMax) { + // Period too big, set to maximum + top = topMax; + div = divMax; + } else { + if(div < divMin) { + // Period is very small, set div to minimum + div = divMin; + } + top = (uint64_t(period) * sysFreq / 62500 / div) - 1; + } + + debug_d("[PWM] %s(%u): div %u, top %u", __FUNCTION__, period, div, top); + + pwm_config cfg = pwm_get_default_config(); + cfg.div = div; + cfg.top = top; + + for(unsigned i = 0; i < channel_count; ++i) { + auto pin = channels[i]; + auto slice_num = pwm_gpio_to_slice_num(pin); + pwm_init(slice_num, &cfg, true); + } + + maxduty = top; +} + +void HardwarePWM::update() +{ + // Not implemented +} + +uint32_t HardwarePWM::getFrequency(uint8_t pin) const +{ + auto slice_num = pwm_gpio_to_slice_num(pin); + auto top = pwm_hw->slice[slice_num].top; + auto div = pwm_hw->slice[slice_num].div; + return 16UL * clock_get_hz(clk_sys) / (div * (top + 1)); +} diff --git a/Sming/Arch/Rp2040/Core/HardwarePWM.cpp.todo b/Sming/Arch/Rp2040/Core/HardwarePWM.cpp.todo deleted file mode 100644 index 6def2d36fd..0000000000 --- a/Sming/Arch/Rp2040/Core/HardwarePWM.cpp.todo +++ /dev/null @@ -1,136 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * HardwarePWM.cpp - * - * Original Author: https://github.com/hrsavla - * - * This HardwarePWM library enables Sming framework user to use ESP SDK PWM API - * Period of PWM is fixed to 1000us / Frequency = 1khz - * Duty at 100% = 22222. Duty at 0% = 0 - * You can use function setPeriod() to change frequency/period. - * Calculate the max duty as per the formulae give in ESP8266 SDK - * Max Duty = (Period * 1000) / 45 - * - * PWM can be generated on up to 8 pins (ie All pins except pin 16) - * Created on August 17, 2015, 2:27 PM - * - * See also ESP8266 Technical Reference, Chapter 12: - * http://espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf - * - */ - -#include -#include "ESP8266EX.h" - -#include - -#define PERIOD_TO_MAX_DUTY(x) (x * 25) - -HardwarePWM::HardwarePWM(uint8* pins, uint8 no_of_pins) : channel_count(no_of_pins) -{ - if(no_of_pins > 0) { - uint32 io_info[PWM_CHANNEL_NUM_MAX][3]; // pin information - uint32 pwm_duty_init[PWM_CHANNEL_NUM_MAX]; // pwm duty - for(uint8 i = 0; i < no_of_pins; i++) { - io_info[i][0] = EspDigitalPins[pins[i]].mux; - io_info[i][1] = EspDigitalPins[pins[i]].gpioFunc; - io_info[i][2] = EspDigitalPins[pins[i]].id; - pwm_duty_init[i] = 0; // Start with zero output - channels[i] = pins[i]; - } - const int initial_period = 1000; - pwm_init(initial_period, pwm_duty_init, no_of_pins, io_info); - update(); - maxduty = PERIOD_TO_MAX_DUTY(initial_period); // for period of 1000 - } -} - -HardwarePWM::~HardwarePWM() -{ - // There is no function in the SDK to stop PWM output, yet. -} - -/* Function Name: getChannel - * Description: This function is used to get channel number for given pin - * Parameters: pin - Esp8266 pin number - */ -uint8 HardwarePWM::getChannel(uint8 pin) -{ - for(uint8 i = 0; i < channel_count; i++) { - if(channels[i] == pin) { - //debugf("getChannel %d is %d", pin, i); - return i; - } - } - //debugf("getChannel: can't find pin %d", pin); - return PWM_BAD_CHANNEL; -} - -/* Function Name: getDutyChan - * Description: This function is used to get the duty cycle number for a given channel - * Parameters: chan -Esp8266 channel number - */ -uint32 HardwarePWM::getDutyChan(uint8 chan) -{ - if(chan == PWM_BAD_CHANNEL) { - return 0; - } else { - return pwm_get_duty(chan); - } -} - -/* Function Name: setDutyChan - * Description: This function is used to set the pwm duty cycle for a given channel. If parameter 'update' is false - * then you have to call update() later to update duties. - * Parameters: chan - channel number - * duty - duty cycle value - * update - update PWM output - */ -bool HardwarePWM::setDutyChan(uint8 chan, uint32 duty, bool update) -{ - if(chan == PWM_BAD_CHANNEL) { - return false; - } else if(duty <= maxduty) { - pwm_set_duty(duty, chan); - if(update) { - this->update(); - } - return true; - } else { - debugf("Duty cycle value too high for current period."); - return false; - } -} - -/* Function Name: getPeriod - * Description: This function is used to get Period of PWM. - * Period / frequency will remain same for all pins. - * - */ -uint32 HardwarePWM::getPeriod() -{ - return pwm_get_period(); -} - -/* Function Name: setPeriod - * Description: This function is used to set Period of PWM. - * Period / frequency will remain same for all pins. - */ -void HardwarePWM::setPeriod(uint32 period) -{ - maxduty = PERIOD_TO_MAX_DUTY(period); - pwm_set_period(period); - update(); -} - -/* Function Name: update - * Description: This function is used to actually update the PWM. - */ -void HardwarePWM::update() -{ - pwm_start(); -} diff --git a/Sming/Core/HardwarePWM.cpp b/Sming/Core/HardwarePWM.cpp new file mode 100644 index 0000000000..72603e2907 --- /dev/null +++ b/Sming/Core/HardwarePWM.cpp @@ -0,0 +1,26 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * HardwarePWM.cpp + * + * Common code for all architectures + * + */ + +#include "HardwarePWM.h" +#include + +uint8_t HardwarePWM::getChannel(uint8_t pin) const +{ + for(unsigned i = 0; i < channel_count; ++i) { + if(channels[i] == pin) { + return i; + } + } + + debug_d("[HWPWM] getChannel: can't find pin %u", pin); + return PWM_BAD_CHANNEL; +} diff --git a/Sming/Core/HardwarePWM.h b/Sming/Core/HardwarePWM.h index fe1d6d501d..77d7887c52 100644 --- a/Sming/Core/HardwarePWM.h +++ b/Sming/Core/HardwarePWM.h @@ -32,7 +32,30 @@ #define PWM_BAD_CHANNEL 0xff ///< Invalid PWM channel -/// Hardware pulse width modulation +/** + * @brief Basic pulse width modulation support. + * + * PERIOD: A full PWM cycle has a duration, measured in hardware timer counts + * DUTY: The 'ON' portion of a PWM cycle measured in hardware timer counts + * + * These values differ between architectures. + * + * DUTY is always <= PERIOD. + * If DUTY == 0 then output is OFF. + * If DUTY == PERIOD then output is ON. + * Intermediate values produce a proportional output, PERCENT = 100 * DUTY / PERIOD. + * + * Producing an analogue voltage from such a PWM output requires a suitable filter + * with characteristics tuned to the specific PWM frequency in use. + * A single-pole R/C filter with R*C = PERIOD (in seconds) is often sufficient. + * + * Note: Devices such as servo motors use the digital signal directly. + * + * Note: The Esp8266 has no PWM hardware and uses an interrupt-based approach (software PWM). + * + * Note: Esp32 and Rp2040 hardware offers more capability which requires use of SDK calls + * or direct hardware access. To avoid resource conflicts avoid using this class in those cases. + */ class HardwarePWM { public: @@ -40,7 +63,8 @@ class HardwarePWM * @param pins Pointer to array of pins to control * @param no_of_pins Quantity of elements in array of pins */ - HardwarePWM(uint8_t* pins, uint8_t no_of_pins); + HardwarePWM(const uint8_t* pins, uint8_t no_of_pins); + virtual ~HardwarePWM(); /** @brief Set PWM duty cycle @@ -64,7 +88,7 @@ class HardwarePWM /** @brief Set PWM duty cycle * @param pin GPIO to set - * @param duty Value of duty cycle to set pin to + * @param duty Value of duty cycle (timer ticks) to set pin to * @param update Update PWM output * @retval bool True on success * @note This function is used to set the pwm duty cycle for a given pin. If parameter 'update' is false @@ -78,13 +102,13 @@ class HardwarePWM /** @brief Get PWM duty cycle * @param chan Channel to get duty cycle for - * @retval uint32_t Value of PWM duty cycle + * @retval uint32_t Value of PWM duty cycle in timer ticks */ - uint32_t getDutyChan(uint8_t chan); + uint32_t getDutyChan(uint8_t chan) const; /** @brief Get PWM duty cycle * @param pin GPIO to get duty cycle for - * @retval uint32_t Value of PWM duty cycle + * @retval uint32_t Value of PWM duty cycle in timer ticks */ uint32_t getDuty(uint8_t pin) { @@ -93,27 +117,27 @@ class HardwarePWM } /** @brief Set PWM period - * @param period PWM period + * @param period PWM period in microseconds * @note All PWM pins share the same period */ void setPeriod(uint32_t period); /** @brief Get PWM period - * @retval uint32_t Value of PWM period + * @retval uint32_t Value of PWM period in microseconds */ - uint32_t getPeriod(); + uint32_t getPeriod() const; /** @brief Get channel number for a pin * @param pin GPIO to interrogate * @retval uint8_t Channel of GPIO */ - uint8_t getChannel(uint8_t pin); + uint8_t getChannel(uint8_t pin) const; /** @brief Get the maximum duty cycle value - * @retval uint32_t Maximum permissible duty cycle + * @retval uint32_t Maximum permissible duty cycle in timer ticks * @note Attempt to set duty of a pin above this value will fail */ - uint32_t getMaxDuty() + uint32_t getMaxDuty() const { return maxduty; } @@ -126,7 +150,7 @@ class HardwarePWM * @param pin GPIO to get frequency for * @retval uint32_t Value of Frequency */ - uint32_t getFrequency(uint8_t pin); + uint32_t getFrequency(uint8_t pin) const; private: uint8_t channel_count; diff --git a/samples/Basic_HwPWM/app/application.cpp b/samples/Basic_HwPWM/app/application.cpp index b1c29c4784..2ac094036a 100644 --- a/samples/Basic_HwPWM/app/application.cpp +++ b/samples/Basic_HwPWM/app/application.cpp @@ -18,26 +18,38 @@ #include #include -#define LED_PIN 2 - namespace { // List of pins that you want to connect to pwm -uint8_t pins[]{ +const uint8_t pins[] +{ +#if defined(ARCH_ESP32) +#define LED_PIN 3 + LED_PIN, 4, 5, 18, 19, 4, +#elif defined(ARCH_RP2040) +#define LED_PIN PICO_DEFAULT_LED_PIN + LED_PIN, 2, 3, 4, 5, 6, 7, 8, +#else +#define LED_PIN 2 LED_PIN, 4, 5, 0, 15, 13, 12, 14, +#endif }; -HardwarePWM HW_pwm(pins, ARRAY_SIZE(pins)); -SimpleTimer procTimer; +const uint8_t defaultDutyPercent[]{ + 50, 95, 50, 85, 10, 30, 60, 80, +}; -const int maxDuty = HW_pwm.getMaxDuty(); +HardwarePWM pwm(pins, ARRAY_SIZE(pins)); +uint32_t maxDuty; + +SimpleTimer procTimer; void doPWM() { static bool countUp = true; - static int duty; + static uint32_t duty; - const int increment = maxDuty / 50; + const uint32_t increment = maxDuty / 50; if(countUp) { duty += increment; @@ -45,15 +57,14 @@ void doPWM() duty = maxDuty; countUp = false; } + } else if(duty <= increment) { + duty = 0; + countUp = true; } else { duty -= increment; - if(duty <= 0) { - duty = 0; - countUp = true; - } } - HW_pwm.analogWrite(LED_PIN, duty); + pwm.analogWrite(LED_PIN, duty); } } // namespace @@ -69,17 +80,21 @@ void init() WifiAccessPoint.enable(false); #endif - // Setting PWM values on 8 different pins - HW_pwm.analogWrite(4, maxDuty); - HW_pwm.analogWrite(5, maxDuty / 2); - HW_pwm.analogWrite(0, maxDuty); - HW_pwm.analogWrite(2, maxDuty / 2); - HW_pwm.analogWrite(15, 0); - HW_pwm.analogWrite(13, maxDuty / 3); - HW_pwm.analogWrite(12, 2 * maxDuty / 3); - HW_pwm.analogWrite(14, maxDuty); - - Serial.println(_F("PWM output set on all 8 Pins. Kindly check...\r\n" - "Now LED_PIN will go from 0 to VCC to 0 in cycles.")); + // Change PWM frequency if required: period is in microseconds + // pwm.setPeriod(100); + + maxDuty = pwm.getMaxDuty(); + auto period = pwm.getPeriod(); + auto freq = pwm.getFrequency(LED_PIN); + + Serial << _F("PWM period = ") << period << _F("us, freq = ") << freq << _F(", max. duty = ") << maxDuty << endl; + + // Set default PWM values + for(unsigned i = 0; i < ARRAY_SIZE(pins); ++i) { + pwm.analogWrite(pins[i], maxDuty * defaultDutyPercent[i] / 100); + } + + Serial << _F("PWM output set on all ") << ARRAY_SIZE(pins) << _F(" Pins. Kindly check...") << endl + << _F("Now LED (pin ") << LED_PIN << _F(") will go from 0 to VCC to 0 in cycles.") << endl; procTimer.initializeMs<100>(doPWM).start(); } diff --git a/samples/Basic_HwPWM/component.mk b/samples/Basic_HwPWM/component.mk index be6ff9c63a..99a419fcc1 100644 --- a/samples/Basic_HwPWM/component.mk +++ b/samples/Basic_HwPWM/component.mk @@ -1,4 +1,3 @@ -COMPONENT_SOC := esp8266 DISABLE_NETWORK := 1 # Uncomment the line below if you want to use Espressif's PWM library. From 502e304ab573689d5ff68d58fc13683dfb97a71c Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 25 Nov 2024 13:18:06 +0000 Subject: [PATCH 24/34] Fix esp32 event callback serialisation (#2913) This PR addresses the issue raised in #2912 by pushing events into the tcpip thread for handling. Network applications therefore 'live' in the tcpip task and the **Sming** task is created only for non-networked applications. Sming uses a separate event callback queue instead of the IDF one. - Use custom queue for sming messaging - Serialise idf messages to sming queue in networking code - Use idle task watchdogs instead of custom one - Push task callbacks to tcpip thread in network builds - Fix stack sizes. Network builds just use default size for event task stack - Use heap for initial partition table load. Not enough room on event task stack for this. - Add a semaphore to `smg_uart_write` so debug output doesn't get garbled between tasks (e.g. wifi). --- Sming/Arch/Esp32/Components/driver/uart.cpp | 24 ++ Sming/Arch/Esp32/Components/esp32/README.rst | 14 - .../Arch/Esp32/Components/esp32/component.mk | 14 +- .../Esp32/Components/esp32/sdk/config/common | 6 +- .../Esp32/Components/esp32/sdk/config/debug | 3 + .../Esp32/Components/esp32/src/event_loop.cpp | 115 -------- .../Esp32/Components/esp32/src/startup.cpp | 63 +---- .../Esp32/Components/esp32/src/system.cpp | 5 +- .../Arch/Esp32/Components/esp32/src/tasks.cpp | 103 ++++++-- .../Esp32/Components/spi_flash/flashmem.cpp | 3 +- Sming/Arch/Esp32/README.rst | 34 ++- .../Network/Arch/Esp32/Network/DM9051.cpp | 1 + .../Network/Arch/Esp32/Network/W5500.cpp | 1 + .../Arch/Esp32/Platform/AccessPointImpl.cpp | 4 - .../Arch/Esp32/Platform/AccessPointImpl.h | 15 +- .../Arch/Esp32/Platform/EmbeddedEthernet.cpp | 1 + .../Arch/Esp32/Platform/IdfService.cpp | 6 +- .../Arch/Esp32/Platform/StationImpl.cpp | 250 ++++++++---------- .../Network/Arch/Esp32/Platform/StationImpl.h | 36 ++- .../Arch/Esp32/Platform/WifiEventsImpl.cpp | 112 +------- .../Arch/Esp32/Platform/WifiEventsImpl.h | 90 ++++++- .../Network/Arch/Esp32/Platform/init.cpp | 109 +++++++- Sming/Components/Storage/src/Device.cpp | 7 +- Sming/Platform/System.cpp | 7 +- docs/source/upgrading/5.2-6.0.rst | 12 + 25 files changed, 497 insertions(+), 538 deletions(-) delete mode 100644 Sming/Arch/Esp32/Components/esp32/src/event_loop.cpp create mode 100644 docs/source/upgrading/5.2-6.0.rst diff --git a/Sming/Arch/Esp32/Components/driver/uart.cpp b/Sming/Arch/Esp32/Components/driver/uart.cpp index d608381f97..c30691e960 100644 --- a/Sming/Arch/Esp32/Components/driver/uart.cpp +++ b/Sming/Arch/Esp32/Components/driver/uart.cpp @@ -191,6 +191,28 @@ smg_uart_t* get_standard_uart(smg_uart_t* uart) return is_standard_uart(uart) ? uart : nullptr; } +class Lock +{ +public: + Lock() + { + if(!mutex) { + mutex = xSemaphoreCreateMutex(); + } + xSemaphoreTake(mutex, portMAX_DELAY); + } + + ~Lock() + { + xSemaphoreGive(mutex); + } + +private: + static SemaphoreHandle_t mutex; +}; + +SemaphoreHandle_t Lock::mutex; + #if UART_ID_SERIAL_USB_JTAG /** @@ -544,6 +566,8 @@ size_t smg_uart_write(smg_uart_t* uart, const void* buffer, size_t size) auto buf = static_cast(buffer); + Lock lock; + while(written < size) { // If TX buffer not in use or it's empty then write directly to hardware FIFO if(uart->tx_buffer == nullptr || uart->tx_buffer->isEmpty()) { diff --git a/Sming/Arch/Esp32/Components/esp32/README.rst b/Sming/Arch/Esp32/Components/esp32/README.rst index a545642fff..cc5acddda0 100644 --- a/Sming/Arch/Esp32/Components/esp32/README.rst +++ b/Sming/Arch/Esp32/Components/esp32/README.rst @@ -45,20 +45,6 @@ or if multiple versions are installed. By default, the most current version will Location of ESP-IDF python. -.. envvar:: CREATE_EVENT_TASK - - default: disabled - - .. warning:: - - This setting is provided for debugging purposes ONLY. - - Sming uses a custom event loop to ensure that timer and task callbacks are all executed in the same - thread context. - - Sometimes this behaviour can cause issues with IDF code. - Setting this to 1 will create the event loop in a separate thread, which is standard IDF behaviour. - Background ---------- diff --git a/Sming/Arch/Esp32/Components/esp32/component.mk b/Sming/Arch/Esp32/Components/esp32/component.mk index b7f21017a9..eaf4804398 100644 --- a/Sming/Arch/Esp32/Components/esp32/component.mk +++ b/Sming/Arch/Esp32/Components/esp32/component.mk @@ -8,11 +8,7 @@ COMPONENT_INCDIRS := src/include include # Applications can provide file with custom SDK configuration settings CACHE_VARS += SDK_CUSTOM_CONFIG -COMPONENT_RELINK_VARS += DISABLE_NETWORK DISABLE_WIFI CREATE_EVENT_TASK - -ifeq ($(CREATE_EVENT_TASK),1) -COMPONENT_CPPFLAGS += -DCREATE_EVENT_TASK -endif +COMPONENT_RELINK_VARS += DISABLE_NETWORK DISABLE_WIFI ifneq (,$(filter v4.%,$(IDF_VERSION))) IDF_VERSION_4x := 1 @@ -392,14 +388,6 @@ EXTRA_LDFLAGS := \ $(call LinkerScript,rom.api) \ $(call LinkerScript,rom.libgcc) \ $(call LinkerScript,rom.newlib-nano) \ - $(call Wrap,\ - esp_event_loop_create_default \ - esp_event_handler_register \ - esp_event_handler_unregister \ - esp_event_handler_instance_register \ - esp_event_handler_instance_unregister \ - esp_event_post \ - esp_event_isr_post) \ $(LDFLAGS_$(ESP_VARIANT)) \ $(call Undef,$(SDK_UNDEF_SYMBOLS)) \ $(call Wrap,$(SDK_WRAP_SYMBOLS)) diff --git a/Sming/Arch/Esp32/Components/esp32/sdk/config/common b/Sming/Arch/Esp32/Components/esp32/sdk/config/common index e5b5711631..8e4c40ba18 100644 --- a/Sming/Arch/Esp32/Components/esp32/sdk/config/common +++ b/Sming/Arch/Esp32/Components/esp32/sdk/config/common @@ -15,7 +15,7 @@ CONFIG_COMPILER_OPTIMIZATION_SIZE=y # Mandatory LWIP changes -CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=8192 +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=16384 CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=n # Ethernet @@ -39,7 +39,6 @@ CONFIG_BT_NIMBLE_MESH=n CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=n # Mandatory Sming framework changes -CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=16384 CONFIG_ESP_TASK_WDT_TIMEOUT_S=8 # Required by HardwareSPI library @@ -58,8 +57,5 @@ CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n # Don't change provided flash configuration information CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=n -# We'll handle WDT initialisation ourselves thankyouverymuch -CONFIG_ESP_TASK_WDT_INIT=n - # Issues with dual-core CPU, see #2653 CONFIG_FREERTOS_UNICORE=y diff --git a/Sming/Arch/Esp32/Components/esp32/sdk/config/debug b/Sming/Arch/Esp32/Components/esp32/sdk/config/debug index c74a1e37de..82e37ffe44 100644 --- a/Sming/Arch/Esp32/Components/esp32/sdk/config/debug +++ b/Sming/Arch/Esp32/Components/esp32/sdk/config/debug @@ -27,3 +27,6 @@ CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y CONFIG_FREERTOS_USE_TRACE_FACILITY=y CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y + +# Watchdog +CONFIG_ESP_TASK_WDT_PANIC=y diff --git a/Sming/Arch/Esp32/Components/esp32/src/event_loop.cpp b/Sming/Arch/Esp32/Components/esp32/src/event_loop.cpp deleted file mode 100644 index 583d611290..0000000000 --- a/Sming/Arch/Esp32/Components/esp32/src/event_loop.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * event_loop.cpp - * - * This code replaces the standard IDF event loop with our own, *without* associated task. - * This not only reduces the system overhead but avoids the need for additional synchronisation - * management because WiFi events, etc. are all called in the context of the main Sming task. - */ - -#include -#include - -namespace -{ -esp_event_loop_handle_t sming_event_loop; -} - -esp_event_loop_handle_t sming_create_event_loop() -{ - esp_event_loop_args_t loop_args = { - .queue_size = CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE, -#ifdef CREATE_EVENT_TASK - .task_name = "sys_evt", - .task_priority = ESP_TASKD_EVENT_PRIO, - .task_stack_size = ESP_TASKD_EVENT_STACK, -#endif - }; - - ESP_ERROR_CHECK(esp_event_loop_create(&loop_args, &sming_event_loop)); - - return sming_event_loop; -} - -namespace -{ -#define WRAP(name) esp_err_t __wrap_##name - -extern "C" { - -WRAP(esp_event_loop_create_default)() -{ - return ESP_ERR_INVALID_STATE; -} - -WRAP(esp_event_handler_register) -(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void* event_handler_arg) -{ - if(sming_event_loop == nullptr) { - return ESP_ERR_INVALID_STATE; - } - - return esp_event_handler_register_with(sming_event_loop, event_base, event_id, event_handler, event_handler_arg); -} - -WRAP(esp_event_handler_unregister) -(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler) -{ - if(sming_event_loop == nullptr) { - return ESP_ERR_INVALID_STATE; - } - - return esp_event_handler_unregister_with(sming_event_loop, event_base, event_id, event_handler); -} - -WRAP(esp_event_handler_instance_register) -(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void* event_handler_arg, - esp_event_handler_instance_t* instance) -{ - if(sming_event_loop == nullptr) { - return ESP_ERR_INVALID_STATE; - } - - return esp_event_handler_instance_register_with(sming_event_loop, event_base, event_id, event_handler, - event_handler_arg, instance); -} - -WRAP(esp_event_handler_instance_unregister) -(esp_event_base_t event_base, int32_t event_id, esp_event_handler_instance_t context) -{ - if(sming_event_loop == nullptr) { - return ESP_ERR_INVALID_STATE; - } - - return esp_event_handler_instance_unregister_with(sming_event_loop, event_base, event_id, context); -} - -WRAP(esp_event_post) -(esp_event_base_t event_base, int32_t event_id, void* event_data, size_t event_data_size, TickType_t ticks_to_wait) -{ - if(sming_event_loop == nullptr) { - return ESP_ERR_INVALID_STATE; - } - - return esp_event_post_to(sming_event_loop, event_base, event_id, event_data, event_data_size, ticks_to_wait); -} - -#if CONFIG_ESP_EVENT_POST_FROM_ISR -IRAM_ATTR WRAP(esp_event_isr_post)(esp_event_base_t event_base, int32_t event_id, void* event_data, - size_t event_data_size, BaseType_t* task_unblocked) -{ - if(sming_event_loop == nullptr) { - return ESP_ERR_INVALID_STATE; - } - - return esp_event_isr_post_to(sming_event_loop, event_base, event_id, event_data, event_data_size, task_unblocked); -} -#endif - -} // extern "C" - -} // namespace diff --git a/Sming/Arch/Esp32/Components/esp32/src/startup.cpp b/Sming/Arch/Esp32/Components/esp32/src/startup.cpp index 5ea2d72358..d47f2eefe7 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/startup.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/startup.cpp @@ -10,8 +10,6 @@ #include #include -#include -#include #include #include #include @@ -20,73 +18,30 @@ #include extern void init(); -extern esp_event_loop_handle_t sming_create_event_loop(); extern void esp_network_initialise(); +extern void start_sming_task_loop(); -namespace -{ -void main(void*) +extern "C" void __wrap_esp_newlib_init_global_stdio(const char*) { - int err; - (void)err; -#if ESP_IDF_VERSION_MAJOR < 5 - err = esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true); -#else - esp_task_wdt_config_t twdt_config{ - .timeout_ms = 8000, - .trigger_panic = true, - }; - err = esp_task_wdt_init(&twdt_config); -#endif - assert(err == ESP_OK); - - err = esp_task_wdt_add(nullptr); - assert(err == ESP_OK); +} +extern "C" void app_main(void) +{ hw_timer_init(); smg_uart_detach_all(); esp_log_set_vprintf(m_vprintf); - auto loop = sming_create_event_loop(); - #ifndef DISABLE_WIFI esp_network_initialise(); #endif System.initialize(); Storage::initialize(); - init(); - - constexpr unsigned maxEventLoopInterval{1000 / portTICK_PERIOD_MS}; - while(true) { - esp_task_wdt_reset(); -#ifdef CREATE_EVENT_TASK - vTaskDelay(100); -#else - esp_event_loop_run(loop, maxEventLoopInterval); -#endif - } -} -} // namespace - -extern "C" void __wrap_esp_newlib_init_global_stdio(const char*) -{ -} - -extern void sming_create_task(TaskFunction_t); - -extern "C" void app_main(void) -{ -#if defined(SOC_ESP32) && !CONFIG_FREERTOS_UNICORE - constexpr unsigned core_id{1}; -#else - constexpr unsigned core_id{0}; -#endif + // Application gets called outside main thread at startup + // Things like smartconfig won't work if called via task queue + init(); -#if ESP_IDF_VERSION_MAJOR < 5 - esp_task_wdt_delete(xTaskGetIdleTaskHandleForCPU(core_id)); -#endif - xTaskCreatePinnedToCore(main, "Sming", ESP_TASKD_EVENT_STACK, nullptr, ESP_TASKD_EVENT_PRIO, nullptr, core_id); + start_sming_task_loop(); } diff --git a/Sming/Arch/Esp32/Components/esp32/src/system.cpp b/Sming/Arch/Esp32/Components/esp32/src/system.cpp index a13039592f..5977deb7d9 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/system.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/system.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #if ESP_IDF_VERSION_MAJOR >= 5 @@ -75,7 +75,8 @@ void system_restart(void) void system_soft_wdt_feed(void) { - esp_task_wdt_reset(); + // Allow the IDLE task to run + vTaskDelay(1); } void system_soft_wdt_stop(void) diff --git a/Sming/Arch/Esp32/Components/esp32/src/tasks.cpp b/Sming/Arch/Esp32/Components/esp32/src/tasks.cpp index c265a30a94..0e2e06b0fb 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/tasks.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/tasks.cpp @@ -1,30 +1,48 @@ #include "include/esp_tasks.h" -#include +#include #include +#ifndef DISABLE_NETWORK +#include +#endif + namespace { -ESP_EVENT_DEFINE_BASE(TaskEvt); - os_task_t taskCallback; +QueueHandle_t eventQueue; -} // namespace +#ifdef DISABLE_NETWORK -bool system_os_task(os_task_t callback, uint8_t prio, os_event_t*, uint8_t) +void sming_task_loop(void*) { - auto handler = [](void*, esp_event_base_t, int32_t event_id, void* event_data) { - assert(taskCallback != nullptr); + os_event_t evt; + while(xQueueReceive(eventQueue, &evt, portMAX_DELAY) == pdTRUE) { + taskCallback(&evt); + } +} - os_event_t ev{os_signal_t(event_id), 0}; - if(event_data != nullptr) { - ev.par = *static_cast(event_data); - } +#else - taskCallback(&ev); - }; +tcpip_callback_msg* callbackMessage; +volatile bool eventQueueFlag; - if(callback == nullptr) { - debug_e("TQ: Callback missing"); +void tcpip_message_handler(void*) +{ + eventQueueFlag = false; + os_event_t evt; + while(xQueueReceive(eventQueue, &evt, 0) == pdTRUE) { + taskCallback(&evt); + } +} + +#endif + +} // namespace + +bool system_os_task(os_task_t callback, uint8_t prio, os_event_t* queue, uint8_t qlen) +{ + if(callback == nullptr || queue == nullptr || qlen == 0) { + debug_e("TQ: Bad parameters"); return false; } @@ -38,29 +56,64 @@ bool system_os_task(os_task_t callback, uint8_t prio, os_event_t*, uint8_t) return false; } - auto err = esp_event_handler_instance_register(TaskEvt, ESP_EVENT_ANY_ID, handler, nullptr, nullptr); - if(err != ESP_OK) { - debug_e("TQ: Failed to register handler"); + eventQueue = xQueueCreate(qlen, sizeof(os_event_t)); + if(eventQueue == nullptr) { return false; } taskCallback = callback; - debug_i("TQ: Registered %s", TaskEvt); - return true; } +void start_sming_task_loop() +{ +#ifdef DISABLE_NETWORK + +#if defined(SOC_ESP32) && !CONFIG_FREERTOS_UNICORE + constexpr unsigned core_id{1}; +#else + constexpr unsigned core_id{0}; +#endif + xTaskCreatePinnedToCore(sming_task_loop, "Sming", CONFIG_LWIP_TCPIP_TASK_STACK_SIZE, nullptr, + CONFIG_LWIP_TCPIP_TASK_PRIO, nullptr, core_id); + +#else + + callbackMessage = tcpip_callbackmsg_new(tcpip_callback_fn(tcpip_message_handler), nullptr); + +#endif +} + bool IRAM_ATTR system_os_post(uint8_t prio, os_signal_t sig, os_param_t par) { if(prio != USER_TASK_PRIO_1) { return false; } - esp_err_t err; - if(par == 0) { - err = esp_event_isr_post(TaskEvt, sig, nullptr, 0, nullptr); + + os_event_t ev{sig, par}; + BaseType_t woken; + auto res = xQueueSendToBackFromISR(eventQueue, &ev, &woken); + if(res != pdTRUE) { + return false; + } + +#ifndef DISABLE_NETWORK + if(!callbackMessage) { + // Message loop not yet active + return true; + } + // If queue isn't empty and we haven't already asked for a tcpip callback, do that now + if(xQueueIsQueueEmptyFromISR(eventQueue) == pdFALSE && !eventQueueFlag) { + eventQueueFlag = true; + auto err = tcpip_callbackmsg_trycallback_fromisr(callbackMessage); + woken = (err == ERR_NEED_SCHED); } else { - err = esp_event_isr_post(TaskEvt, sig, &par, sizeof(par), nullptr); + woken = false; } - return (err == ESP_OK); +#endif + + portYIELD_FROM_ISR_ARG(woken); + + return true; } diff --git a/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp b/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp index 87791b92a0..6c9738297f 100644 --- a/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp +++ b/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -40,7 +39,7 @@ uint32_t flashmem_read(void* to, flash_addr_t fromaddr, uint32_t size) bool flashmem_erase_sector(flash_sector_t sector_id) { - esp_task_wdt_reset(); + system_soft_wdt_feed(); debug_d("flashmem_erase_sector(0x%08x)", sector_id); diff --git a/Sming/Arch/Esp32/README.rst b/Sming/Arch/Esp32/README.rst index f2c60083c6..4c4e21242e 100644 --- a/Sming/Arch/Esp32/README.rst +++ b/Sming/Arch/Esp32/README.rst @@ -117,12 +117,11 @@ IDF versions ------------ Sming currently supports IDF versions 5.2. This is installed by default. -Older versions 4.3, 4.4 and 5.0 are no longer officially supported. If you use one of the old versions, please, consider upgrading to 5.2. - +Older versions 4.3, 4.4 and 5.0 are no longer supported. A different version can be installed if necessary:: - INSTALL_IDF_VER=4.4 $SMING_HOME/../Tools/install.sh esp32 + INSTALL_IDF_VER=5.3 $SMING_HOME/../Tools/install.sh esp32 The installation script creates a soft-link in ``/opt/esp-idf`` pointing to the last version installed. Use the `IDF_PATH` environment variable or change the soft-link to select which one to use. @@ -136,6 +135,35 @@ See `ESP-IDF Versions AccessPointImpl::getStations() const return std::unique_ptr(new StationListImpl); } -void AccessPointImpl::onSystemReady() -{ -} - } // namespace Network } // namespace SmingInternal diff --git a/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.h b/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.h index 7135dbe47a..a976e5efb2 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.h +++ b/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.h @@ -20,14 +20,9 @@ namespace SmingInternal { namespace Network { -class AccessPointImpl : public AccessPointClass, protected ISystemReadyHandler +class AccessPointImpl : public AccessPointClass { public: - AccessPointImpl() - { - System.onReady(this); - } - void enable(bool enabled, bool save) override; bool isEnabled() const override; bool config(const String& ssid, String password, WifiAuthMode mode, bool hidden, int channel, @@ -43,14 +38,6 @@ class AccessPointImpl : public AccessPointClass, protected ISystemReadyHandler String getPassword() const override; std::unique_ptr getStations() const override; - // Called from WifiEventsImpl - void eventHandler(esp_event_base_t base, int32_t id, void* data) - { - } - -protected: - void onSystemReady() override; - private: esp_netif_obj* apNetworkInterface{nullptr}; }; diff --git a/Sming/Components/Network/Arch/Esp32/Platform/EmbeddedEthernet.cpp b/Sming/Components/Network/Arch/Esp32/Platform/EmbeddedEthernet.cpp index fe8ba597e3..92a00afd7e 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/EmbeddedEthernet.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/EmbeddedEthernet.cpp @@ -26,6 +26,7 @@ bool EmbeddedEthernet::begin([[maybe_unused]] const Config& config) #else esp_netif_init(); + esp_event_loop_create_default(); esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); netif = esp_netif_new(&cfg); diff --git a/Sming/Components/Network/Arch/Esp32/Platform/IdfService.cpp b/Sming/Components/Network/Arch/Esp32/Platform/IdfService.cpp index 7dce438f48..19af0a1ac8 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/IdfService.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/IdfService.cpp @@ -9,6 +9,7 @@ ****/ #include +#include #include #include #include @@ -54,10 +55,9 @@ void IdfService::enableEventCallback(bool enable) auto handler = [](void* arg, esp_event_base_t, int32_t event_id, void*) { auto service = static_cast(arg); service->state = Event(event_id); - if(!service->eventCallback) { - return; + if(service->eventCallback) { + System.queueCallback([service, event_id]() { service->eventCallback(Event(event_id)); }); } - service->eventCallback(Event(event_id)); }; if(enable) { diff --git a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp index bbaddc46c9..10e1569164 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp @@ -75,45 +75,56 @@ class BssInfoImpl : public BssInfo } }; -void StationImpl::eventHandler(esp_event_base_t base, int32_t id, [[maybe_unused]] void* data) +void StationImpl::dispatchStaStart() { - if(base == WIFI_EVENT) { - bool allowAutoConnect{true}; #ifdef ENABLE_WPS - if(wpsConfig != nullptr) { - wpsEventHandler(id, data); - allowAutoConnect = false; - } + if(wpsConfig) { + return; + } #endif + #ifdef ENABLE_SMART_CONFIG - if(smartConfigEventInfo) { - allowAutoConnect = false; - } + if(smartConfigEventInfo) { + return; + } #endif - switch(id) { - case WIFI_EVENT_STA_START: - if(allowAutoConnect && getAutoConnect()) { - connectionStatus = eSCS_Connecting; - esp_wifi_connect(); - } - break; - case WIFI_EVENT_STA_DISCONNECTED: { - connectionStatus = eSCS_ConnectionFailed; - break; - } - default:; - } - } else if(base == IP_EVENT) { - switch(id) { - case IP_EVENT_STA_GOT_IP: - connectionStatus = eSCS_GotIP; - break; - case IP_EVENT_STA_LOST_IP: - connectionStatus = eSCS_Connecting; - break; - default:; - } + + if(getAutoConnect()) { + connectionStatus = eSCS_Connecting; + esp_wifi_connect(); + } +} + +void StationImpl::dispatchStaDisconnected(const wifi_event_sta_disconnected_t&) +{ + connectionStatus = eSCS_ConnectionFailed; + +#ifdef ENABLE_WPS + if(wpsConfig == nullptr) { + return; } + + if(wpsConfig->ignoreDisconnects) { + return; + } + if(wpsConfig->numRetries < WpsConfig::maxRetryAttempts) { + esp_wifi_connect(); + ++wpsConfig->numRetries; + return; + } + + if(wpsConfigure(wpsConfig->credIndex + 1)) { + esp_wifi_connect(); + return; + } + + debug_e("[WPS] Failed to connect!"); + if(wpsCallback(WpsStatus::Failed)) { + // try to reconnect with old config + wpsConfigStop(); + esp_wifi_connect(); + } +#endif } void StationImpl::enable(bool enabled, bool save) @@ -394,29 +405,27 @@ bool StationImpl::startScan(ScanCompletedDelegate scanCompleted) return false; } - auto eventHandler = [](void* arg, esp_event_base_t, int32_t id, void* data) { - wifi_event_sta_scan_done_t* event = reinterpret_cast(data); - staticScanCompleted(event, event->status); - }; - - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_SCAN_DONE, eventHandler, nullptr)); if(esp_wifi_scan_start(nullptr, false) != ESP_OK) { - auto connectHandler = [](void*, esp_event_base_t, int32_t, void*) { esp_wifi_scan_start(nullptr, false); }; - - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, connectHandler, nullptr)); - debug_e("startScan failed"); + return false; } return true; } -void StationImpl::staticScanCompleted(wifi_event_sta_scan_done_t* event, uint8_t status) +void StationImpl::dispatchStaConnected(const wifi_event_sta_connected_t&) +{ + if(scanCompletedCallback) { + esp_wifi_scan_start(nullptr, false); + } +} + +void StationImpl::dispatchScanDone(const wifi_event_sta_scan_done_t& event) { BssList list; - if(status == OK) { + if(event.status == OK) { if(station.scanCompletedCallback) { - uint16_t number = event->number; + uint16_t number = event.number; wifi_ap_record_t ap_info[number]; memset(ap_info, 0, sizeof(ap_info)); @@ -431,28 +440,22 @@ void StationImpl::staticScanCompleted(wifi_event_sta_scan_done_t* event, uint8_t debug_i("scan completed: %u found", list.count()); } else { - debug_e("scan failed %u", status); + debug_e("scan failed %u", event.status); if(station.scanCompletedCallback) { station.scanCompletedCallback(false, list); } } } -void StationImpl::onSystemReady() -{ -} - #ifdef ENABLE_SMART_CONFIG -void StationImpl::internalSmartConfig(smartconfig_event_t event_id, void* pdata) +void StationImpl::smartConfigEventHandler(void*, esp_event_base_t, int32_t event_id, void* data) { - if(!smartConfigEventInfo) { + if(!station.smartConfigEventInfo) { debug_e("[SC] ERROR! eventInfo null"); return; } - auto& evt = *smartConfigEventInfo; - SmartConfigEvent event; switch(event_id) { case SC_EVENT_SCAN_DONE: @@ -469,11 +472,12 @@ void StationImpl::internalSmartConfig(smartconfig_event_t event_id, void* pdata) break; case SC_EVENT_GOT_SSID_PSWD: { debugf("[SC] GOT_SSID_PSWD"); - auto cfg = static_cast(pdata); + auto cfg = static_cast(data); assert(cfg != nullptr); if(cfg == nullptr) { return; } + auto& evt = *station.smartConfigEventInfo; evt.ssid = reinterpret_cast(cfg->ssid); evt.password = reinterpret_cast(cfg->password); evt.bssidSet = cfg->bssid_set; @@ -487,26 +491,23 @@ void StationImpl::internalSmartConfig(smartconfig_event_t event_id, void* pdata) return; } - if(smartConfigCallback && !smartConfigCallback(event, evt)) { - return; - } - - switch(event_id) { - case SC_EVENT_GOT_SSID_PSWD: - StationClass::config(evt.ssid, evt.password, true, true); - connect(); - break; - case SC_EVENT_SEND_ACK_DONE: - smartConfigStop(); - break; - default:; - } -} + System.queueCallback([event]() { + auto& evt = *station.smartConfigEventInfo; + if(station.smartConfigCallback && !station.smartConfigCallback(event, evt)) { + return; + } -void StationImpl::smartConfigEventHandler(void* arg, esp_event_base_t, int32_t id, void* data) -{ - auto self = static_cast(arg); - return self->internalSmartConfig(smartconfig_event_t(id), data); + switch(event) { + case SCE_Link: + station.config({evt.ssid, evt.password}); + station.connect(); + break; + case SCE_LinkOver: + station.smartConfigStop(); + break; + default:; + } + }); } bool StationImpl::smartConfigStart(SmartConfigType sctype, SmartConfigDelegate callback) @@ -552,81 +553,50 @@ void StationImpl::smartConfigStop() #ifdef ENABLE_WPS -void StationImpl::wpsEventHandler(int32_t event_id, void* event_data) +void StationImpl::dispatchStaWpsErFailed() { - switch(event_id) { - case WIFI_EVENT_STA_DISCONNECTED: - debug_w("WIFI_EVENT_STA_DISCONNECTED"); - if(wpsConfig->ignoreDisconnects) { - break; - } - if(wpsConfig->numRetries < WpsConfig::maxRetryAttempts) { - esp_wifi_connect(); - ++wpsConfig->numRetries; - break; - } - - if(wpsConfigure(wpsConfig->credIndex + 1)) { - esp_wifi_connect(); - break; - } - - debug_e("[WPS] Failed to connect!"); - if(wpsCallback(WpsStatus::Failed)) { - // try to reconnect with old config - wpsConfigStop(); - esp_wifi_connect(); - } - break; - - case WIFI_EVENT_STA_WPS_ER_SUCCESS: { - debug_i("WIFI_EVENT_STA_WPS_ER_SUCCESS"); - - if(!wpsCallback(WpsStatus::Success)) { - return; - } - - if(event_data != nullptr) { - /* If multiple AP credentials are received from WPS, connect with first one */ - wpsConfig->creds = *static_cast(event_data); - wpsConfigure(0); - } - /* - * If only one AP credential is received from WPS, there will be no event data and - * esp_wifi_set_config() is already called by WPS modules for backward compatibility - * with legacy apps. So directly attempt connection here. - */ + debug_e("WIFI_EVENT_STA_WPS_ER_FAILED"); + if(wpsCallback(WpsStatus::Failed)) { + // Try to reconnect with old config wpsConfigStop(); esp_wifi_connect(); - break; } +} - case WIFI_EVENT_STA_WPS_ER_FAILED: { - debug_e("WIFI_EVENT_STA_WPS_ER_FAILED"); - if(wpsCallback(WpsStatus::Failed)) { - // Try to reconnect with old config - wpsConfigStop(); - esp_wifi_connect(); - } - break; +void StationImpl::dispatchStaWpsErTimeout() +{ + debug_e("WIFI_EVENT_STA_WPS_ER_TIMEOUT"); + if(wpsCallback(WpsStatus::Timeout)) { + // Try to reconnect with old config + wpsConfigStop(); + esp_wifi_connect(); } +} - case WIFI_EVENT_STA_WPS_ER_TIMEOUT: - debug_e("WIFI_EVENT_STA_WPS_ER_TIMEOUT"); - if(wpsCallback(WpsStatus::Timeout)) { - // Try to reconnect with old config - wpsConfigStop(); - esp_wifi_connect(); - } - break; +void StationImpl::dispatchStaWpsErPin() +{ + debug_e("WIFI_EVENT_STA_WPS_ER_PIN (not implemented)"); +} - case WIFI_EVENT_STA_WPS_ER_PIN: - debug_e("WIFI_EVENT_STA_WPS_ER_PIN (not implemented)"); - break; +void StationImpl::dispatchWpsErSuccess(const wifi_event_sta_wps_er_success_t& event) +{ + debug_i("WIFI_EVENT_STA_WPS_ER_SUCCESS"); - default: - break; + if(!wpsCallback(WpsStatus::Success)) { + return; } + + /* If multiple AP credentials are received from WPS, connect with first one */ + wpsConfig->creds = event; + wpsConfigure(0); + + /* + * If only one AP credential is received from WPS, there will be no event data and + * esp_wifi_set_config() is already called by WPS modules for backward compatibility + * with legacy apps. So directly attempt connection here. + */ + wpsConfigStop(); + esp_wifi_connect(); } bool StationImpl::wpsConfigure(uint8_t credIndex) diff --git a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h index 2fe46a9361..570088aa01 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h +++ b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h @@ -25,14 +25,9 @@ namespace SmingInternal { namespace Network { -class StationImpl : public StationClass, protected ISystemReadyHandler +class StationImpl : public StationClass { public: - StationImpl() - { - System.onReady(this); - } - void enable(bool enabled, bool save) override; bool isEnabled() const override; bool config(const Config& cfg) override; @@ -67,21 +62,36 @@ class StationImpl : public StationClass, protected ISystemReadyHandler void wpsConfigStop() override; #endif - // Called from WifiEventsImpl - void eventHandler(esp_event_base_t base, int32_t id, void* data); + // Called from network event handler (init.cpp) + void dispatchStaStart(); + void dispatchStaConnected(const wifi_event_sta_connected_t& event); + void dispatchStaDisconnected(const wifi_event_sta_disconnected_t& event); + + void dispatchStaGotIp(const ip_event_got_ip_t&) + { + connectionStatus = eSCS_GotIP; + } + + void dispatchStaLostIp() + { + connectionStatus = eSCS_Connecting; + } + + void dispatchScanDone(const wifi_event_sta_scan_done_t& event); -protected: - void onSystemReady() override; +#ifdef ENABLE_WPS + void dispatchStaWpsErFailed(); + void dispatchStaWpsErTimeout(); + void dispatchStaWpsErPin(); + void dispatchWpsErSuccess(const wifi_event_sta_wps_er_success_t& event); +#endif private: - static void staticScanCompleted(wifi_event_sta_scan_done_t* event, uint8_t status); #ifdef ENABLE_WPS - void wpsEventHandler(int32_t event_id, void* event_data); bool wpsCallback(WpsStatus status); bool wpsConfigure(uint8_t credIndex); #endif #ifdef ENABLE_SMART_CONFIG - void internalSmartConfig(smartconfig_event_t event, void* pdata); static void smartConfigEventHandler(void* arg, esp_event_base_t base, int32_t id, void* data); #endif diff --git a/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.cpp b/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.cpp index d6ff95efbe..4073b132b7 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.cpp @@ -9,119 +9,11 @@ #include "WifiEventsImpl.h" #include "StationImpl.h" -#include WifiEventsClass& WifiEvents{SmingInternal::Network::events}; -namespace SmingInternal -{ -namespace Network +namespace SmingInternal::Network { WifiEventsImpl events; -ip_addr_t ip(esp_ip4_addr_t ip) -{ - ip_addr_t r = IPADDR4_INIT(ip.addr); - return r; -} - -void WifiEventsImpl::eventHandler(esp_event_base_t base, int32_t id, void* data) -{ - if(base == WIFI_EVENT) { - switch(id) { - case WIFI_EVENT_STA_START: - break; - case WIFI_EVENT_STA_CONNECTED: { - wifi_event_sta_connected_t* event = reinterpret_cast(data); - debugf("connect to ssid %s, channel %d\n", event->ssid, event->channel); - if(onSTAConnect) { - String ssid(reinterpret_cast(event->ssid), event->ssid_len); - onSTAConnect(ssid, event->bssid, event->channel); - } - break; - } - case WIFI_EVENT_STA_DISCONNECTED: { - wifi_event_sta_disconnected_t* event = reinterpret_cast(data); - debugf("disconnect from ssid %s, reason %d\n", event->ssid, event->reason); - if(onSTADisconnect) { - String ssid(reinterpret_cast(event->ssid), event->ssid_len); - auto reason = WifiDisconnectReason(event->reason); - onSTADisconnect(ssid, event->bssid, reason); - } - break; - } - case WIFI_EVENT_STA_AUTHMODE_CHANGE: { - wifi_event_sta_authmode_change_t* event = reinterpret_cast(data); - auto oldMode = WifiAuthMode(event->old_mode); - auto newMode = WifiAuthMode(event->new_mode); - debugf("mode: %d -> %d\n", oldMode, newMode); - - if((oldMode != AUTH_OPEN) && (newMode == AUTH_OPEN)) { - // CVE-2020-12638 workaround. - // TODO: Remove this workaround once ESP-IDF has the proper fix. - debugf("Potential downgrade attack. Reconnecting WiFi. See CVE-2020-12638 for more details\n"); - WifiStation.disconnect(); - WifiStation.connect(); - break; - } - - if(onSTAAuthModeChange) { - onSTAAuthModeChange(oldMode, newMode); - } - break; - } - case WIFI_EVENT_AP_STACONNECTED: { - wifi_event_ap_staconnected_t* event = reinterpret_cast(data); - debugf("station: " MACSTR " join, AID = %d\n", MAC2STR(event->mac), event->aid); - if(onSOFTAPConnect) { - onSOFTAPConnect(event->mac, event->aid); - } - break; - } - case WIFI_EVENT_AP_STADISCONNECTED: { - wifi_event_ap_stadisconnected_t* event = reinterpret_cast(data); - debugf("station: " MACSTR "leave, AID = %d\n", MAC2STR(event->mac), event->aid); - if(onSOFTAPDisconnect) { - onSOFTAPDisconnect(event->mac, event->aid); - } - break; - } - case WIFI_EVENT_AP_PROBEREQRECVED: { - wifi_event_ap_probe_req_rx_t* event = reinterpret_cast(data); - if(onSOFTAPProbeReqRecved) { - onSOFTAPProbeReqRecved(event->rssi, event->mac); - } - break; - } - - default: - break; - - } // switch id - } else if(base == IP_EVENT) { - switch(id) { - case IP_EVENT_STA_GOT_IP: { - ip_event_got_ip_t* event = reinterpret_cast(data); - debugf("ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR "\n", IP2STR(&event->ip_info.ip), - IP2STR(&event->ip_info.netmask), IP2STR(&event->ip_info.gw)); - if(onSTAGotIP) { - onSTAGotIP(ip(event->ip_info.ip), ip(event->ip_info.netmask), ip(event->ip_info.gw)); - } - break; - } - case IP_EVENT_STA_LOST_IP: { - // TODO: ESP32 station lost IP and the IP is reset to 0 - break; - } - case IP_EVENT_AP_STAIPASSIGNED: { - // TODO: ESP32 soft-AP assign an IP to a connected station - break; - } - default: - break; - } // switch id - } -} - -} // namespace Network -} // namespace SmingInternal +} // namespace SmingInternal::Network diff --git a/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.h b/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.h index 99886ae9f9..c460bdbea6 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.h +++ b/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.h @@ -13,17 +13,95 @@ #include #include #include +#include +#include -namespace SmingInternal -{ -namespace Network +namespace SmingInternal::Network { class WifiEventsImpl : public WifiEventsClass { public: - void eventHandler(esp_event_base_t base, int32_t id, void* data); + void dispatchStaStart() + { + } + + void dispatchStaConnected(const wifi_event_sta_connected_t& event) + { + debugf("connect to ssid %s, channel %d\n", event.ssid, event.channel); + if(onSTAConnect) { + String ssid(reinterpret_cast(event.ssid), event.ssid_len); + onSTAConnect(ssid, event.bssid, event.channel); + } + } + + void dispatchStaDisconnected(const wifi_event_sta_disconnected_t& event) + { + debugf("disconnect from ssid %s, reason %d\n", event.ssid, event.reason); + if(onSTADisconnect) { + String ssid(reinterpret_cast(event.ssid), event.ssid_len); + auto reason = WifiDisconnectReason(event.reason); + onSTADisconnect(ssid, event.bssid, reason); + } + } + + void dispatchStaAuthmodeChange(const wifi_event_sta_authmode_change_t& event) + { + auto oldMode = WifiAuthMode(event.old_mode); + auto newMode = WifiAuthMode(event.new_mode); + debugf("mode: %d -> %d\n", oldMode, newMode); + + if(onSTAAuthModeChange) { + onSTAAuthModeChange(oldMode, newMode); + } + } + + void dispatchApStaConnected(const wifi_event_ap_staconnected_t& event) + { + debugf("station: " MACSTR " join, AID = %d\n", MAC2STR(event.mac), event.aid); + if(onSOFTAPConnect) { + onSOFTAPConnect(event.mac, event.aid); + } + } + + void dispatchApStaDisconnected(const wifi_event_ap_stadisconnected_t& event) + { + debugf("station: " MACSTR "leave, AID = %d\n", MAC2STR(event.mac), event.aid); + if(onSOFTAPDisconnect) { + onSOFTAPDisconnect(event.mac, event.aid); + } + } + + void dispatchApProbeReqReceived(const wifi_event_ap_probe_req_rx_t& event) + { + if(onSOFTAPProbeReqRecved) { + onSOFTAPProbeReqRecved(event.rssi, event.mac); + } + } + + void dispatchStaGotIp(const ip_event_got_ip_t& event) + { + debugf("ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR "\n", IP2STR(&event.ip_info.ip), IP2STR(&event.ip_info.netmask), + IP2STR(&event.ip_info.gw)); + if(onSTAGotIP) { + auto ip = [](esp_ip4_addr_t ip) -> IpAddress { + ip_addr_t r = IPADDR4_INIT(ip.addr); + return IpAddress{r}; + }; + onSTAGotIP(ip(event.ip_info.ip), ip(event.ip_info.netmask), ip(event.ip_info.gw)); + } + } + + void dispatchStaLostIp() + { + // TODO: ESP32 station lost IP and the IP is reset to 0 + } + + void dispatchApStaIpAssigned() + { + // TODO: ESP32 soft-AP assign an IP to a connected station + } }; extern WifiEventsImpl events; -} // namespace Network -} // namespace SmingInternal + +} // namespace SmingInternal::Network diff --git a/Sming/Components/Network/Arch/Esp32/Platform/init.cpp b/Sming/Components/Network/Arch/Esp32/Platform/init.cpp index 8bd40c46d9..14f446cfac 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/init.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/init.cpp @@ -13,6 +13,107 @@ #include #include +namespace +{ +void eventHandler(void*, esp_event_base_t base, int32_t id, void* data) +{ + /* + * This handler is called from the wifi task, but events should only be handled in the Sming task thread. + * We need to interpret the associated data and take a copy for the queue. + * Each event is then passed to an explicit handler method. + */ + + using namespace SmingInternal::Network; + debugf("event %s|%d\n", base, id); + + if(base == WIFI_EVENT) { + switch(id) { +#ifdef ENABLE_WPS + case WIFI_EVENT_STA_WPS_ER_SUCCESS: + System.queueCallback([event = *static_cast(data)]() { + station.dispatchWpsErSuccess(event); + }); + break; + case WIFI_EVENT_STA_WPS_ER_FAILED: + System.queueCallback([](void*) { station.dispatchStaWpsErFailed(); }); + break; + case WIFI_EVENT_STA_WPS_ER_TIMEOUT: + System.queueCallback([](void*) { station.dispatchStaWpsErTimeout(); }); + break; + case WIFI_EVENT_STA_WPS_ER_PIN: + System.queueCallback([](void*) { station.dispatchStaWpsErPin(); }); + break; +#endif + case WIFI_EVENT_SCAN_DONE: + System.queueCallback( + [event = *static_cast(data)]() { station.dispatchScanDone(event); }); + break; + case WIFI_EVENT_STA_START: + System.queueCallback([](void*) { + station.dispatchStaStart(); + events.dispatchStaStart(); + }); + break; + case WIFI_EVENT_STA_CONNECTED: + System.queueCallback([event = *static_cast(data)]() { + station.dispatchStaConnected(event); + events.dispatchStaConnected(event); + }); + break; + case WIFI_EVENT_STA_DISCONNECTED: + System.queueCallback([event = *static_cast(data)]() { + station.dispatchStaDisconnected(event); + events.dispatchStaDisconnected(event); + }); + break; + case WIFI_EVENT_STA_AUTHMODE_CHANGE: + System.queueCallback([event = *static_cast(data)]() { + events.dispatchStaAuthmodeChange(event); + }); + break; + case WIFI_EVENT_AP_STACONNECTED: + System.queueCallback([event = *static_cast(data)]() { + events.dispatchApStaConnected(event); + }); + break; + case WIFI_EVENT_AP_STADISCONNECTED: + System.queueCallback([event = *static_cast(data)]() { + events.dispatchApStaDisconnected(event); + }); + break; + case WIFI_EVENT_AP_PROBEREQRECVED: + System.queueCallback([event = *static_cast(data)]() { + events.dispatchApProbeReqReceived(event); + }); + break; + default: + break; + } + } else if(base == IP_EVENT) { + switch(id) { + case IP_EVENT_STA_GOT_IP: + System.queueCallback([event = *static_cast(data)]() { + station.dispatchStaGotIp(event); + events.dispatchStaGotIp(event); + }); + break; + case IP_EVENT_STA_LOST_IP: + System.queueCallback([](void*) { + station.dispatchStaLostIp(); + events.dispatchStaLostIp(); + }); + break; + case IP_EVENT_AP_STAIPASSIGNED: + System.queueCallback([](void*) { events.dispatchApStaIpAssigned(); }); + break; + default: + break; + } + } +} + +} // namespace + // Called from startup void esp_network_initialise() { @@ -30,13 +131,7 @@ void esp_network_initialise() * Initialise default WiFi stack */ esp_netif_init(); - auto eventHandler = [](void*, esp_event_base_t base, int32_t id, void* data) -> void { - using namespace SmingInternal::Network; - debugf("event %s|%d\n", base, id); - station.eventHandler(base, id, data); - accessPoint.eventHandler(base, id, data); - events.eventHandler(base, id, data); - }; + esp_event_loop_create_default(); ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, eventHandler, nullptr)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, eventHandler, nullptr)); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); diff --git a/Sming/Components/Storage/src/Device.cpp b/Sming/Components/Storage/src/Device.cpp index a1d5560f0f..5036d86735 100644 --- a/Sming/Components/Storage/src/Device.cpp +++ b/Sming/Components/Storage/src/Device.cpp @@ -55,8 +55,11 @@ Device::~Device() bool Device::loadPartitions(Device& source, uint32_t tableOffset) { constexpr size_t maxEntries = ESP_PARTITION_TABLE_MAX_LEN / sizeof(esp_partition_info_t); - esp_partition_info_t buffer[maxEntries]; - if(!source.read(tableOffset, buffer, sizeof(buffer))) { + auto buffer = std::make_unique(maxEntries); + if(!buffer) { + return false; + } + if(!source.read(tableOffset, buffer.get(), ESP_PARTITION_TABLE_MAX_LEN)) { debug_e("[Partition] Failed to read partition table at offset 0x%08x", tableOffset); return false; } diff --git a/Sming/Platform/System.cpp b/Sming/Platform/System.cpp index 7e826a426c..7ef1ee6098 100644 --- a/Sming/Platform/System.cpp +++ b/Sming/Platform/System.cpp @@ -14,11 +14,6 @@ SystemClass System; SystemState SystemClass::state = eSS_None; -#ifdef ARCH_ESP32 -#undef TASK_QUEUE_LENGTH -#define TASK_QUEUE_LENGTH 0 -#define taskQueue nullptr -#else #ifdef TASK_QUEUE_LENGTH static_assert(TASK_QUEUE_LENGTH >= 8, "Task queue too small"); #else @@ -28,8 +23,8 @@ static_assert(TASK_QUEUE_LENGTH >= 8, "Task queue too small"); */ #define TASK_QUEUE_LENGTH 10 #endif + os_event_t SystemClass::taskQueue[TASK_QUEUE_LENGTH]; -#endif #ifdef ENABLE_TASK_COUNT volatile uint8_t SystemClass::taskCount; diff --git a/docs/source/upgrading/5.2-6.0.rst b/docs/source/upgrading/5.2-6.0.rst new file mode 100644 index 0000000000..c6e8182d79 --- /dev/null +++ b/docs/source/upgrading/5.2-6.0.rst @@ -0,0 +1,12 @@ +From v5.2 to 6.0 +================ + +.. highlight:: c++ + +**Esp32 task scheduling** + +Sming is a single-threaded framework, so does not impose any requirements on application code to be thread-safe. +However, code could be executed from one of several tasks (wifi, tcpip or Sming) which is a reliability concern. + +With PR#2913 this has been fixed and all Sming code now runs in the same task context. +This has largely be achieved by using a separate callback queue for Sming rather than using the IDF mechanism. From 7b3ef4f315873ae2a4e22daddd607f9bc87f88d8 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 26 Nov 2024 10:49:09 +0000 Subject: [PATCH 25/34] Fix esp32 multicore lockup (#2916) This PR fixes the broken IPC calling interrupts on esp32 chips. Closes #2653. Cause is due to an incorrect linker flag which resulted in critical high-level interrupt handling code from the ESP IDF not getting linked. Testing also revealed a race condition during access point initialisation. The `Basic_Wifi` sample first initialises the access point, then the station. Shortly after startup, some internal structure for the access point gets invalidated and causes an access violation. It appears to be related to calling `esp_wifi_start` twice. --- Sming/Arch/Esp32/Components/esp32/sdk/esp_system.mk | 6 +++--- .../Network/Arch/Esp32/Platform/AccessPointImpl.cpp | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Sming/Arch/Esp32/Components/esp32/sdk/esp_system.mk b/Sming/Arch/Esp32/Components/esp32/sdk/esp_system.mk index ec7f205e94..f18108c391 100644 --- a/Sming/Arch/Esp32/Components/esp32/sdk/esp_system.mk +++ b/Sming/Arch/Esp32/Components/esp32/sdk/esp_system.mk @@ -12,10 +12,10 @@ ifndef CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE SDK_UNDEF_SYMBOLS += start_app_other_cores endif -# ld_include_panic_highint_hdl is added as an undefined symbol because otherwise the -# linker will ignore panic_highint_hdl.S as it has no other files depending on any +# ld_include_highint_hdl is added as an undefined symbol because otherwise the +# linker will ignore highint_hdl.S as it has no other files depending on any # symbols in it. -SDK_UNDEF_SYMBOLS += ld_include_panic_highint_hdl +SDK_UNDEF_SYMBOLS += ld_include_highint_hdl # IDF 5.2 SDK_WRAP_SYMBOLS += esp_newlib_init_global_stdio diff --git a/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.cpp b/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.cpp index ae783d746f..2b69133aaf 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.cpp @@ -57,7 +57,7 @@ void AccessPointImpl::enable(bool enabled, bool save) } } ESP_ERROR_CHECK(esp_wifi_set_storage(save ? WIFI_STORAGE_FLASH : WIFI_STORAGE_RAM)); - ESP_ERROR_CHECK(esp_wifi_set_mode((wifi_mode_t)mode)); + ESP_ERROR_CHECK(esp_wifi_set_mode(mode)); } bool AccessPointImpl::isEnabled() const @@ -88,10 +88,13 @@ bool AccessPointImpl::config(const String& ssid, String password, WifiAuthMode m config.ap.authmode = (wifi_auth_mode_t)mode; config.ap.max_connection = 8; + bool enabled = isEnabled(); enable(true, false); ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &config)); - ESP_ERROR_CHECK(esp_wifi_start()); + if(enabled) { + System.queueCallback(esp_wifi_start); + } return true; } From cae7bf3316a8d3d612a0c278f78dae45d52fa786 Mon Sep 17 00:00:00 2001 From: slaff Date: Tue, 26 Nov 2024 12:54:36 +0100 Subject: [PATCH 26/34] Add Message-ID header in email when not set. (#2915) Google Mail and others started requesting Message-ID header to be present, otherwise messages are blocked/getting marked as spam. --- Sming/Components/Network/src/Network/SmtpClient.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sming/Components/Network/src/Network/SmtpClient.cpp b/Sming/Components/Network/src/Network/SmtpClient.cpp index 477436c6d5..0bad31c808 100644 --- a/Sming/Components/Network/src/Network/SmtpClient.cpp +++ b/Sming/Components/Network/src/Network/SmtpClient.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -296,6 +297,12 @@ void SmtpClient::sendMailHeaders(MailMessage* mail) mail->stream = std::make_unique(mail->stream.release()); } + if(!mail->headers.contains(F("Message-ID"))) { + Uuid uuid; + uuid.generate(); + mail->headers[F("Message-ID")] = "<" + uuid.toString() + "@" + url.Host + ">"; + } + if(!mail->attachments.isEmpty()) { MultipartStream* mStream = new MultipartStream(MultipartStream::Producer(&SmtpClient::multipartProducer, this)); MultipartStream::BodyPart text; From 5e50be411f13164d4ba9060676df792eea2dd3c2 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 2 Dec 2024 08:33:49 +0000 Subject: [PATCH 27/34] Update pico SDK to v2.1.0 with RP2350 support (#2918) --- .github/workflows/ci.yml | 4 +- .gitmodules | 2 +- .../Rp2040/Components/driver/hw_timer.cpp | 16 +- .../driver/include/driver/hw_timer.h | 13 +- .../Rp2040/Components/driver/os_timer.cpp | 8 +- Sming/Arch/Rp2040/Components/driver/uart.cpp | 10 +- Sming/Arch/Rp2040/Components/libc/src/heap.c | 16 -- .../Arch/Rp2040/Components/libc/src/heap.cpp | 58 ++++ .../libc/src/include/sys/pgmspace.h | 4 + .../Rp2040/Components/picotool/README.rst | 8 +- .../Rp2040/Components/picotool/component.mk | 45 ++- .../Arch/Rp2040/Components/picotool/picotool | 2 +- .../Rp2040/Components/picotool/picotool.patch | 28 ++ .../Rp2040/Components/rp2040/component.mk | 41 ++- .../Components/rp2040/cyw43-driver.patch | 256 ++++++++---------- Sming/Arch/Rp2040/Components/rp2040/pico-sdk | 2 +- .../Rp2040/Components/rp2040/pico-sdk.patch | 68 ++--- .../Components/rp2040/sdk/CMakeLists.txt | 20 +- .../Components/rp2040/sdk/pico_bit_ops.mk | 2 + .../Components/rp2040/sdk/pico_divider.mk | 2 + .../Components/rp2040/sdk/pico_float.mk | 6 +- .../Components/rp2040/sdk/pico_int64_ops.mk | 2 + .../Components/rp2040/sdk/pico_mem_ops.mk | 2 + Sming/Arch/Rp2040/Components/rp2040/src/clk.c | 39 +-- .../Rp2040/Components/rp2040/src/startup.cpp | 14 +- .../Rp2040/Components/rp2040/src/wifi.cpp | 21 ++ .../Rp2040/Components/sming-arch/component.mk | 1 + .../Rp2040/Components/spi_flash/flashmem.cpp | 37 ++- Sming/Arch/Rp2040/Components/uf2/component.mk | 34 +-- .../Rp2040/Components/uf2/uf2families.json | 184 ++++++++++++- Sming/Arch/Rp2040/Platform/RTC.cpp | 74 +++-- Sming/Arch/Rp2040/README.rst | 30 +- Sming/Arch/Rp2040/app.mk | 12 +- Sming/Arch/Rp2040/build.mk | 20 +- Sming/Arch/Rp2040/rp2350-pindefs.txt | 52 ++++ Sming/Arch/Rp2040/rp2350-soc.json | 62 +++++ Sming/Components/malloc_count/component.mk | 1 - .../Components/malloc_count/malloc_count.cpp | 2 +- Sming/Libraries/USB | 2 +- Tools/ci/scanlog.py | 5 +- samples/Basic_IFS/app/application.cpp | 2 +- samples/Basic_IFS/basic_ifs_Rp2040.hw | 2 +- 42 files changed, 828 insertions(+), 381 deletions(-) delete mode 100644 Sming/Arch/Rp2040/Components/libc/src/heap.c create mode 100644 Sming/Arch/Rp2040/Components/libc/src/heap.cpp create mode 100644 Sming/Arch/Rp2040/Components/picotool/picotool.patch create mode 100644 Sming/Arch/Rp2040/rp2350-pindefs.txt create mode 100644 Sming/Arch/Rp2040/rp2350-soc.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b33ec55ea..133dd9a13e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - variant: [esp8266, host, rp2040] + variant: [esp8266, host, rp2040, rp2350] toolchain: [gcc] include: - variant: esp8266 @@ -31,6 +31,8 @@ jobs: toolchain: gcc64 - variant: rp2040 arch: Rp2040 + - variant: rp2350 + arch: Rp2040 concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ toJson(matrix) }} diff --git a/.gitmodules b/.gitmodules index cbd4b056cb..7a6bfa13a3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -122,7 +122,7 @@ [submodule "Rp2040.picotool"] path = Sming/Arch/Rp2040/Components/picotool/picotool - url = https://github.com/mikee47/picotool + url = https://github.com/raspberrypi/picotool ignore = dirty [submodule "Rp2040.Sdk"] diff --git a/Sming/Arch/Rp2040/Components/driver/hw_timer.cpp b/Sming/Arch/Rp2040/Components/driver/hw_timer.cpp index 0c8f44c741..03556d271e 100644 --- a/Sming/Arch/Rp2040/Components/driver/hw_timer.cpp +++ b/Sming/Arch/Rp2040/Components/driver/hw_timer.cpp @@ -18,7 +18,7 @@ namespace { void IRAM_ATTR timer1_isr() { - hw_clear_bits(&timer_hw->intr, BIT(0)); + hw_clear_bits(&timer_hw->intr, BIT(0)); auto& p = hw_timer_private; if(p.timer1_callback != nullptr) { p.timer1_callback(p.timer1_arg); @@ -33,20 +33,22 @@ void IRAM_ATTR timer1_isr() void IRAM_ATTR hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void* arg) { (void)source_type; + auto irq_num = TIMER_ALARM_IRQ_NUM(HW_TIMER_NUM, 0); + irq_set_enabled(irq_num, false); auto& p = hw_timer_private; - irq_set_enabled(TIMER_IRQ_0, false); p.timer1_callback = callback; p.timer1_arg = arg; - irq_set_exclusive_handler(TIMER_IRQ_0, timer1_isr); + irq_set_exclusive_handler(irq_num, timer1_isr); hw_set_bits(&timer_hw->inte, BIT(0)); - irq_set_enabled(TIMER_IRQ_0, true); + irq_set_enabled(irq_num, true); } void hw_timer1_detach_interrupt() { hw_clear_bits(&timer_hw->inte, BIT(0)); - irq_set_enabled(TIMER_IRQ_0, false); - irq_remove_handler(TIMER_IRQ_0, timer1_isr); + auto irq_num = TIMER_ALARM_IRQ_NUM(HW_TIMER_NUM, 0); + irq_set_enabled(irq_num, false); + irq_remove_handler(irq_num, timer1_isr); } void IRAM_ATTR hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load) @@ -59,5 +61,5 @@ void IRAM_ATTR hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr void hw_timer_init() { - // hardware_alarm_claim(0); + timer_hardware_alarm_claim(HW_TIMER_INST, 0); } diff --git a/Sming/Arch/Rp2040/Components/driver/include/driver/hw_timer.h b/Sming/Arch/Rp2040/Components/driver/include/driver/hw_timer.h index b94d5b4e34..101382027d 100644 --- a/Sming/Arch/Rp2040/Components/driver/include/driver/hw_timer.h +++ b/Sming/Arch/Rp2040/Components/driver/include/driver/hw_timer.h @@ -11,7 +11,7 @@ #pragma once #include -#include +#include #ifdef __cplusplus extern "C" { @@ -19,6 +19,9 @@ extern "C" { #define HW_TIMER_BASE_CLK 1000000U +#define HW_TIMER_NUM 0 +#define HW_TIMER_INST TIMER_INSTANCE(HW_TIMER_NUM) + /** * @defgroup hw_timer Hardware Timer Driver * @ingroup drivers @@ -36,7 +39,7 @@ extern "C" { */ __forceinline uint32_t IRAM_ATTR hw_timer_ticks() { - return timer_hw->timerawl; + return timer_time_us_32(HW_TIMER_INST); } /************************************* @@ -116,7 +119,7 @@ __forceinline void IRAM_ATTR hw_timer1_write(uint32_t ticks) { ticks <<= hw_timer_private.timer1_clkdiv; hw_timer_private.timer1_ticks = ticks; - timer_hw->alarm[0] = hw_timer_ticks() + ticks; + HW_TIMER_INST->alarm[0] = hw_timer_ticks() + ticks; } /** @@ -124,7 +127,7 @@ __forceinline void IRAM_ATTR hw_timer1_write(uint32_t ticks) */ __forceinline void IRAM_ATTR hw_timer1_disable() { - timer_hw->armed = BIT(0); + HW_TIMER_INST->armed = BIT(0); } /** @@ -133,7 +136,7 @@ __forceinline void IRAM_ATTR hw_timer1_disable() */ __forceinline uint32_t hw_timer1_read() { - int time = hw_timer_ticks() - timer_hw->alarm[0]; + int time = hw_timer_ticks() - HW_TIMER_INST->alarm[0]; return (time > 0) ? (time >> hw_timer_private.timer1_clkdiv) : 0; } diff --git a/Sming/Arch/Rp2040/Components/driver/os_timer.cpp b/Sming/Arch/Rp2040/Components/driver/os_timer.cpp index b524d56ceb..d43afb6cfd 100644 --- a/Sming/Arch/Rp2040/Components/driver/os_timer.cpp +++ b/Sming/Arch/Rp2040/Components/driver/os_timer.cpp @@ -75,16 +75,16 @@ void IRAM_ATTR timer_schedule() if(timer_list == nullptr) { debug_tmr("cancel"); // Cancel hardware timer - timer_hw->armed = BIT(1); + HW_TIMER_INST->armed = BIT(1); return; } constexpr int TIMER2_MIN_US{50}; auto now = hw_timer2_read(); if(int(timer_list->timer_expire - now) < TIMER2_MIN_US) { - timer_hw->alarm[1] = now + TIMER2_MIN_US; + HW_TIMER_INST->alarm[1] = now + TIMER2_MIN_US; } else { - timer_hw->alarm[1] = timer_list->timer_expire; + HW_TIMER_INST->alarm[1] = timer_list->timer_expire; } } @@ -95,7 +95,7 @@ os_timer_t* find_expired_timer() } // Using Timer2 hardware to schedule software timers - if(timer_hw->armed & BIT(1)) { + if(HW_TIMER_INST->armed & BIT(1)) { return nullptr; } diff --git a/Sming/Arch/Rp2040/Components/driver/uart.cpp b/Sming/Arch/Rp2040/Components/driver/uart.cpp index c277d41037..9d4867f742 100644 --- a/Sming/Arch/Rp2040/Components/driver/uart.cpp +++ b/Sming/Arch/Rp2040/Components/driver/uart.cpp @@ -13,6 +13,12 @@ #include #include +#ifdef ARCH_RP2040 +#define UART_FUNCSEL_NUM(gpio) GPIO_FUNC_UART +#else +#define UART_FUNCSEL_NUM(gpio) ((gpio) & 0x2 ? GPIO_FUNC_UART_AUX : GPIO_FUNC_UART) +#endif + namespace { using uart_dev_t = uart_hw_t; @@ -721,7 +727,7 @@ bool smg_uart_set_pins(smg_uart_t* uart, int tx_pin, int rx_pin) if(uart->tx_pin != UART_PIN_DEFAULT) { gpio_set_function(uart->tx_pin, GPIO_FUNC_NULL); } - gpio_set_function(tx_pin, GPIO_FUNC_UART); + gpio_set_function(tx_pin, UART_FUNCSEL_NUM(tx_pin)); uart->tx_pin = tx_pin; } @@ -729,7 +735,7 @@ bool smg_uart_set_pins(smg_uart_t* uart, int tx_pin, int rx_pin) if(uart->rx_pin != UART_PIN_DEFAULT) { gpio_set_function(uart->rx_pin, GPIO_FUNC_NULL); } - gpio_set_function(rx_pin, GPIO_FUNC_UART); + gpio_set_function(rx_pin, UART_FUNCSEL_NUM(rx_pin)); uart->rx_pin = rx_pin; } diff --git a/Sming/Arch/Rp2040/Components/libc/src/heap.c b/Sming/Arch/Rp2040/Components/libc/src/heap.c deleted file mode 100644 index de274e3b4e..0000000000 --- a/Sming/Arch/Rp2040/Components/libc/src/heap.c +++ /dev/null @@ -1,16 +0,0 @@ -/* - * heap.c - */ - -#include "include/heap.h" -#include - -uint32_t system_get_free_heap_size(void) -{ - // These are set by linker - extern char __end__; - extern char __StackLimit; - uint32_t maxHeap = (uint32_t)&__StackLimit - (uint32_t)&__end__; - struct mallinfo m = mallinfo(); - return maxHeap - m.uordblks; -} diff --git a/Sming/Arch/Rp2040/Components/libc/src/heap.cpp b/Sming/Arch/Rp2040/Components/libc/src/heap.cpp new file mode 100644 index 0000000000..1074e9d8ac --- /dev/null +++ b/Sming/Arch/Rp2040/Components/libc/src/heap.cpp @@ -0,0 +1,58 @@ +/* + * heap.c + */ + +#include "include/heap.h" +#include +#include +#include + +extern "C" uint32_t system_get_free_heap_size(void) +{ + // These are set by linker + extern char __end__; + extern char __StackLimit; + uint32_t maxHeap = (uint32_t)&__StackLimit - (uint32_t)&__end__; + struct mallinfo m = mallinfo(); + return maxHeap - m.uordblks; +} + +void* operator new(size_t size) +{ + return malloc(size); +} + +void* operator new(size_t size, const std::nothrow_t&) +{ + return malloc(size); +} + +void* operator new[](size_t size) +{ + return malloc(size); +} + +void* operator new[](size_t size, const std::nothrow_t&) +{ + return malloc(size); +} + +void operator delete(void* ptr) +{ + free(ptr); +} + +void operator delete[](void* ptr) +{ + free(ptr); +} + +void operator delete(void* ptr, size_t) +{ + free(ptr); +} + +void operator delete[](void* ptr, size_t) +{ + free(ptr); +} diff --git a/Sming/Arch/Rp2040/Components/libc/src/include/sys/pgmspace.h b/Sming/Arch/Rp2040/Components/libc/src/include/sys/pgmspace.h index a04deaa0c9..895eb8774d 100644 --- a/Sming/Arch/Rp2040/Components/libc/src/include/sys/pgmspace.h +++ b/Sming/Arch/Rp2040/Components/libc/src/include/sys/pgmspace.h @@ -21,7 +21,11 @@ extern "C" { /** * @brief Simple check to determine if a pointer refers to flash memory */ +#ifdef XIP_END +#define isFlashPtr(ptr) ((uint32_t)(ptr) >= XIP_BASE && (uint32_t)(ptr) < XIP_END) +#else #define isFlashPtr(ptr) ((uint32_t)(ptr) >= XIP_MAIN_BASE && (uint32_t)(ptr) < XIP_NOALLOC_BASE) +#endif #define PROGMEM STORE_ATTR ICACHE_RODATA_ATTR #define PROGMEM_PSTR PROGMEM diff --git a/Sming/Arch/Rp2040/Components/picotool/README.rst b/Sming/Arch/Rp2040/Components/picotool/README.rst index e887b5d13e..b16fb5ed6a 100644 --- a/Sming/Arch/Rp2040/Components/picotool/README.rst +++ b/Sming/Arch/Rp2040/Components/picotool/README.rst @@ -3,4 +3,10 @@ Picotool Picotool is a tool for inspecting RP2040 binaries, and interacting with RP2040 devices when they are in BOOTSEL mode. -Note for full documentation see https://rptl.io/pico-get-started Appendix B. +See https://rptl.io/pico-get-started Appendix B for an introduction to this tool. + +Sming builds picotool from source and uses it to read back flash memory with build targets such as ``make readpart``. + +The tool can be invoked directly like this:: + + make picotool CMD="info -a" diff --git a/Sming/Arch/Rp2040/Components/picotool/component.mk b/Sming/Arch/Rp2040/Components/picotool/component.mk index 9e2ea04f85..f7e18a3241 100644 --- a/Sming/Arch/Rp2040/Components/picotool/component.mk +++ b/Sming/Arch/Rp2040/Components/picotool/component.mk @@ -33,10 +33,49 @@ $(COMPONENT_RULE)$(PICOTOOL): $(Q) mkdir -p $(@D) $(Q) cd $(@D) && $(CMAKE) $(PICOTOOL_CMAKE_OPTIONS) $(PICOTOOL_SRC) && $(MAKE) +##@Flashing + +.PHONY: picotool +picotool: ##Pass options to picotool, e.g. `make picotool -- help` + $(Q) $(PICOTOOL) $(CMD) + +comma := , +XIP_BASE := 0x10000000 + +define CalcHex +$$(printf "0x%x" $$(( $1 ))) +endef + +define RangeStart +$(call CalcHex,$(XIP_BASE) + $(firstword $(subst $(comma), ,$1))) +endef + +define RangeEnd +$(call CalcHex,$(XIP_BASE) + $(firstword $(subst $(comma), ,$1)) + $(word 2,$(subst $(comma), ,$1))) +endef + +# Read flash memory into file +# $1 -> `Offset,Size` chunk +# $2 -> Output filename +define ReadFlash + $(info ReadFlash $1,$2) + $(Q) $(PICOTOOL) save -r $(call RangeStart,$1) $(call RangeEnd,$1) $2 -t bin +endef # Read flash manufacturer ID and determine actual size define ReadFlashID $(info ReadFlashID) - $(Q) $(PICOTOOL) info -a $(TARGET_BIN) - # $(PICOTOOL) help info - endef + $(Q) $(PICOTOOL) info -a +endef + +# Erase a region of Flash +# $1 -> Offset,Size +define EraseFlashRegion + $(info EraseFlashRegion $1) + $(Q) $(PICOTOOL) erase -r $(call RangeStart,$1) $(call RangeEnd,$1) +endef + +# Erase flash memory contents +define EraseFlash + $(Q) $(PICOTOOL) erase -a +endef diff --git a/Sming/Arch/Rp2040/Components/picotool/picotool b/Sming/Arch/Rp2040/Components/picotool/picotool index 5d6df39033..df21059f7c 160000 --- a/Sming/Arch/Rp2040/Components/picotool/picotool +++ b/Sming/Arch/Rp2040/Components/picotool/picotool @@ -1 +1 @@ -Subproject commit 5d6df39033c7166ea6e76cbde1ff0c0240a4bba4 +Subproject commit df21059f7ca6f1babc7f1f3b92122cacffc85951 diff --git a/Sming/Arch/Rp2040/Components/picotool/picotool.patch b/Sming/Arch/Rp2040/Components/picotool/picotool.patch new file mode 100644 index 0000000000..dbfcf4c51d --- /dev/null +++ b/Sming/Arch/Rp2040/Components/picotool/picotool.patch @@ -0,0 +1,28 @@ +diff --git a/lib/whereami/whereami.c b/lib/whereami/whereami.c +index d052e14..940736e 100644 +--- a/lib/whereami/whereami.c ++++ b/lib/whereami/whereami.c +@@ -60,8 +60,9 @@ extern "C" { + #if defined(_MSC_VER) + #pragma warning(push, 3) + #endif ++#undef _WIN32_WINNT ++#define _WIN32_WINNT _WIN32_WINNT_WINXP + #include +-#include + #if defined(_MSC_VER) + #pragma warning(pop) + #endif +diff --git a/picoboot_connection/picoboot_connection.c b/picoboot_connection/picoboot_connection.c +index 265608c..e487714 100644 +--- a/picoboot_connection/picoboot_connection.c ++++ b/picoboot_connection/picoboot_connection.c +@@ -9,6 +9,8 @@ + #include + #include + ++#define static_assert _Static_assert ++ + #include "picoboot_connection.h" + #include "boot/bootrom_constants.h" + #include "pico/stdio_usb/reset_interface.h" diff --git a/Sming/Arch/Rp2040/Components/rp2040/component.mk b/Sming/Arch/Rp2040/Components/rp2040/component.mk index 4c03455044..50fdec72b9 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/component.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/component.mk @@ -6,10 +6,16 @@ else export PICO_SDK_PATH := $(COMPONENT_PATH)/pico-sdk endif +ifeq ($(SMING_SOC),rp2350) +PICO_VARIANT=pico2 +else +PICO_VARIANT=pico +endif + ifeq ($(DISABLE_WIFI),1) -export PICO_BOARD ?= pico +export PICO_BOARD ?= $(PICO_VARIANT) else -export PICO_BOARD ?= pico_w +export PICO_BOARD ?= $(PICO_VARIANT)_w COMPONENT_DEPENDS += uzlib endif @@ -35,29 +41,33 @@ ifeq ($(ENABLE_BOOTSEL),1) COMPONENT_CXXFLAGS += -DENABLE_BOOTSEL=1 endif +# Functions which are wrapped by the SDK WRAPPED_FUNCTIONS := $(foreach c,$(wildcard $(COMPONENT_PATH)/sdk/*.mk),$(eval include $c)) EXTRA_LDFLAGS := \ $(call Wrap,$(WRAPPED_FUNCTIONS)) \ + -Wl,--whole-archive -lpico -Wl,--no-whole-archive \ -T memmap_default.ld SDK_INTERFACES := \ boards \ - common/pico_base \ + common/pico_base_headers \ common/pico_binary_info \ - common/pico_bit_ops \ - common/pico_divider \ + common/pico_bit_ops_headers \ + common/pico_divider_headers \ common/pico_sync \ common/pico_time \ common/pico_util \ - rp2040/hardware_regs \ - rp2040/hardware_structs \ + $(RP_VARIANT)/hardware_regs \ + $(RP_VARIANT)/hardware_structs \ rp2_common/hardware_adc \ rp2_common/hardware_gpio \ - rp2_common/pico_platform \ + $(RP_VARIANT)/pico_platform \ + rp2_common/boot_bootrom_headers \ rp2_common/hardware_base \ + rp2_common/hardware_boot_lock \ rp2_common/hardware_sync \ rp2_common/hardware_divider \ rp2_common/hardware_timer \ @@ -73,17 +83,25 @@ SDK_INTERFACES := \ rp2_common/hardware_rtc \ rp2_common/hardware_pll \ rp2_common/hardware_spi \ + rp2_common/hardware_sync_spin_lock \ rp2_common/hardware_vreg \ rp2_common/hardware_watchdog \ rp2_common/hardware_xosc \ + rp2_common/pico_aon_timer \ rp2_common/pico_async_context \ rp2_common/pico_bootrom \ rp2_common/pico_double \ rp2_common/pico_int64_ops \ rp2_common/pico_float \ + rp2_common/pico_flash \ + rp2_common/pico_mem_ops \ rp2_common/pico_multicore \ + rp2_common/pico_platform_compiler \ + rp2_common/pico_platform_panic \ + rp2_common/pico_platform_sections \ rp2_common/pico_rand \ rp2_common/pico_runtime \ + rp2_common/pico_runtime_init \ rp2_common/pico_unique_id \ rp2_common/pico_cyw43_arch \ rp2_common/pico_cyw43_driver @@ -105,10 +123,10 @@ COMPONENT_INCDIRS += $(PICO_BASE_DIR) LIBDIRS += \ $(PICO_SDK_PATH)/src/rp2_common/pico_standard_link \ + $(PICO_SDK_PATH)/src/rp2_common/pico_crt0/$(RP_VARIANT) \ $(PICO_BUILD_DIR) EXTRA_LIBS += \ - pico \ m \ stdc++ \ gcc @@ -116,7 +134,8 @@ EXTRA_LIBS += \ RP2040_CMAKE_OPTIONS := \ -G Ninja \ -DCMAKE_MAKE_PROGRAM=$(NINJA) \ - -DCMAKE_BUILD_TYPE=$(if $(subst 1,,$(PICO_DEBUG)),RelWithDebInfo,Debug) + -DCMAKE_BUILD_TYPE=$(if $(subst 1,,$(PICO_DEBUG)),RelWithDebInfo,Debug) \ + -DPICO_VARIANT=$(RP_VARIANT) ifeq ($(ENABLE_CCACHE),1) RP2040_CMAKE_OPTIONS += \ @@ -126,7 +145,7 @@ endif COMPONENT_PREREQUISITES := $(PICO_CONFIG) -BOOTLOADER := $(PICO_BUILD_DIR)/pico-sdk/src/rp2_common/boot_stage2/bs2_default_padded_checksummed.S +BOOTLOADER := $(PICO_BUILD_DIR)/pico-sdk/src/$(RP_VARIANT)/boot_stage2/bs2_default_padded_checksummed.S DEBUG_VARS += CYW43_FIRMWARE CYW43_FIRMWARE := $(COMPONENT_BUILD_BASE)/cyw43-fw.gz diff --git a/Sming/Arch/Rp2040/Components/rp2040/cyw43-driver.patch b/Sming/Arch/Rp2040/Components/rp2040/cyw43-driver.patch index c7edc5b93e..ff93702411 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/cyw43-driver.patch +++ b/Sming/Arch/Rp2040/Components/rp2040/cyw43-driver.patch @@ -1,8 +1,8 @@ diff --git a/src/cyw43_ctrl.c b/src/cyw43_ctrl.c -index edec1f3..de03c73 100644 +index cc9973e..ab76673 100644 --- a/src/cyw43_ctrl.c +++ b/src/cyw43_ctrl.c -@@ -296,13 +296,17 @@ static const char *const cyw43_async_event_name_table[89] = { +@@ -288,13 +288,17 @@ static const char *const cyw43_async_event_name_table[89] = { [CYW43_EV_SET_SSID] = "SET_SSID", [CYW43_EV_JOIN] = "JOIN", [CYW43_EV_AUTH] = "AUTH", @@ -21,20 +21,10 @@ index edec1f3..de03c73 100644 [CYW43_EV_ASSOC_REQ_IE] = "ASSOC_REQ_IE", [CYW43_EV_ASSOC_RESP_IE] = "ASSOC_RESP_IE", diff --git a/src/cyw43_ll.c b/src/cyw43_ll.c -index 604335c..4aeb629 100644 +index 033eec2..11f08d5 100644 --- a/src/cyw43_ll.c +++ b/src/cyw43_ll.c -@@ -54,9 +54,6 @@ - #include "cyw43_sdio.h" - #endif - --#define CYW43_FLASH_BLOCK_SIZE (512) --uint32_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks); -- - struct pbuf; - uint16_t pbuf_copy_partial(const struct pbuf *p, void *dataptr, uint16_t len, uint16_t offset); - -@@ -68,10 +65,6 @@ extern bool enable_spi_packet_dumping; +@@ -65,11 +65,6 @@ extern bool enable_spi_packet_dumping; #define CYW43_RAM_SIZE (512 * 1024) @@ -42,160 +32,146 @@ index 604335c..4aeb629 100644 -#include CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE - -#define CYW43_CLM_ADDR (fw_data + ALIGN_UINT(CYW43_WIFI_FW_LEN, 512)) - #define VERIFY_FIRMWARE_DOWNLOAD (0) - +- #define ALIGN_UINT(val, align) (((val) + (align) - 1) & ~((align) - 1)) -@@ -357,58 +350,31 @@ static void cyw43_write_backplane(cyw43_int_t *self, uint32_t addr, size_t size, - cyw43_set_backplane_window(self, CHIPCOMMON_BASE_ADDRESS); + + // Configure the padding needed for data sent to cyw43_write_bytes(). +@@ -101,18 +96,6 @@ static inline void cyw43_put_le32(uint8_t *buf, uint32_t x) { + buf[3] = x >> 24; } --static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t raw_len, int from_storage, uintptr_t source) { -- // round up len to simplify download -- size_t len = (raw_len + 255) & ~255; +-#if CYW43_RESOURCE_VERIFY_DOWNLOAD +-static void cyw43_xxd(size_t len, const uint8_t *buf) { +- for (size_t i = 0; i < len; ++i) { +- CYW43_PRINTF(" %02x", buf[i]); +- if (i % 32 == 31) { +- CYW43_PRINTF("\n"); +- } +- } +- CYW43_PRINTF("\n"); +-} +-#endif - -- CYW43_VDEBUG("writing %lu bytes to 0x%lx\n", (uint32_t)len, (uint32_t)addr); + /*******************************************************************************/ + // CYW43 constants and types + +@@ -409,10 +392,6 @@ static int cyw43_check_valid_chipset_firmware(cyw43_int_t *self, size_t len, uin + } + + static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t len, uintptr_t source) { +- // The calls to cyw43_write_bytes() (and cyw43_read_bytes()) require data sizes that +- // are aligned to a certain amount. +- assert(CYW43_WRITE_BYTES_PAD(len) == len); - -- uint32_t block_size = CYW43_BUS_MAX_BLOCK_SIZE; -- if (from_storage) { -- // reused the spid_buf to copy the data (must be larger than 512 storage block size) -- block_size = sizeof(self->spid_buf); -- CYW43_DEBUG("data comes from external storage via buffer of size %u\n", (unsigned int)block_size); -+static uint32_t storage_get_chunksize() -+{ -+ const uint32_t chunkTag = 0x4b4e4843; // "CHNK" -+ struct chunk_t { -+ uint32_t tag; -+ uint32_t length; -+ }; -+ struct chunk_t chunk; -+ int res = cyw43_storage_read(&chunk, sizeof(chunk)); -+ if (res != sizeof(chunk)) { -+ CYW43_WARN("Bad chunk header %d\n", res); -+ return 0; - } -+ if (chunk.tag != chunkTag) { -+ CYW43_WARN("Bad chunk tag %08x\n", chunk.tag); -+ return 0; -+ } -+ CYW43_DEBUG("Chunk %u bytes\n", chunk.length); -+ return chunk.length; -+} + CYW43_VDEBUG("writing %u bytes to 0x%x\n", (uint32_t)len, (uint32_t)addr); + + uint32_t block_size = CYW43_BUS_MAX_BLOCK_SIZE; +@@ -431,12 +410,18 @@ static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t len, + uint32_t dest_addr = addr + offset; + assert(((dest_addr & BACKPLANE_ADDR_MASK) + sz) <= (BACKPLANE_ADDR_MASK + 1)); + cyw43_set_backplane_window(self, dest_addr); +- const uint8_t *src = (const uint8_t *)source + offset; ++ const uint8_t *src; ++ if (source) { ++ src = (const uint8_t *)source + offset; ++ } else { ++ cyw43_storage_read(self->spid_buf, sz); ++ src = self->spid_buf; ++ } + dest_addr &= BACKPLANE_ADDR_MASK; + #if CYW43_USE_SPI + dest_addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + #endif +- int ret = cyw43_write_bytes(self, BACKPLANE_FUNCTION, dest_addr, sz, src); ++ int ret = cyw43_write_bytes(self, BACKPLANE_FUNCTION, dest_addr, CYW43_WRITE_BYTES_PAD(sz), src); + if (ret != 0) { + + return CYW43_FAIL_FAST_CHECK(ret); +@@ -449,42 +434,6 @@ static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t len, + CYW43_VDEBUG("done dnload; dt = %u us; speed = %u kbytes/sec\n", (unsigned int)dt, (unsigned int)(len * 1000 / dt)); + #endif -- if (addr == 0) { -- // check that firmware is actually there +- #if CYW43_RESOURCE_VERIFY_DOWNLOAD - -- // get the last bit of the firmware -- const uint8_t *b; -- uint32_t fw_end; -- if (from_storage) { -- // get the last aligned-1024 bytes -- uint32_t last_bl = (raw_len - 1) / CYW43_FLASH_BLOCK_SIZE; -- storage_read_blocks(self->spid_buf, source + last_bl - 1, 2); -- fw_end = raw_len - (last_bl - 1) * CYW43_FLASH_BLOCK_SIZE; -- b = self->spid_buf; -- } else { -- // get the last 800 bytes -- fw_end = 800; -- b = (const uint8_t *)source + raw_len - fw_end; -- } +- // Verification of 380k takes about 40ms using a 512-byte transfer size +- const size_t verify_block_size = CYW43_BUS_MAX_BLOCK_SIZE; +- uint8_t buf[verify_block_size]; - -- // get length of trailer -- fw_end -= 16; // skip DVID trailer -- uint32_t trail_len = b[fw_end - 2] | b[fw_end - 1] << 8; -- int found = -1; -- if (trail_len < 500 && b[fw_end - 3] == '\0') { -- for (int i = 80; i < (int)trail_len; ++i) { -- if (strncmp((const char *)&b[fw_end - 3 - i], "Version: ", 9) == 0) { -- found = i; -- break; -- } -- } -- } +- #if CYW43_VERBOSE_DEBUG +- t_start = cyw43_hal_ticks_us(); +- #endif - -- if (found == -1) { -- CYW43_WARN("could not find valid firmware\n"); +- for (size_t offset = 0; offset < len; offset += verify_block_size) { +- size_t sz = verify_block_size; +- if (offset + sz > len) { +- sz = len - offset; +- } +- uint32_t dest_addr = addr + offset; +- assert(((dest_addr & BACKPLANE_ADDR_MASK) + sz) <= (BACKPLANE_ADDR_MASK + 1)); +- cyw43_set_backplane_window(self, dest_addr); +- cyw43_read_bytes(self, BACKPLANE_FUNCTION, dest_addr & BACKPLANE_ADDR_MASK, sz, buf); +- const uint8_t *src = (const uint8_t *)source + offset; +- if (memcmp(buf, src, sz) != 0) { +- CYW43_WARN("fail verify at address 0x%08x:\n", (unsigned int)dest_addr); +- cyw43_xxd(sz, src); +- cyw43_xxd(sz, buf); - return CYW43_FAIL_FAST_CHECK(-CYW43_EIO); - } -+static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t len, int from_storage, uintptr_t source) { -+ CYW43_VDEBUG("writing %lu bytes to 0x%lx\n", (uint32_t)len, (uint32_t)addr); - -- // print wifi firmware version info -- CYW43_DEBUG("%s\n", &b[fw_end - 3 - found]); - } -+ const uint32_t block_size = CYW43_BUS_MAX_BLOCK_SIZE; - - #if VERIFY_FIRMWARE_DOWNLOAD - uint32_t t_start = cyw43_hal_ticks_us(); -@@ -426,7 +392,7 @@ static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t raw_ - cyw43_set_backplane_window(self, dest_addr); - const uint8_t *src; - if (from_storage) { -- storage_read_blocks(self->spid_buf, source + offset / CYW43_FLASH_BLOCK_SIZE, block_size / CYW43_FLASH_BLOCK_SIZE); -+ cyw43_storage_read(self->spid_buf, sz); - src = self->spid_buf; - } else { - src = (const uint8_t *)source + offset; -@@ -443,6 +409,10 @@ static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t raw_ - } +- +- #if CYW43_VERBOSE_DEBUG +- t_end = cyw43_hal_ticks_us(); +- dt = t_end - t_start; +- CYW43_VDEBUG("done verify; dt = %u us; speed = %u kbytes/sec\n", (unsigned int)dt, (unsigned int)(len * 1000 / dt)); +- #endif +- +- #endif // CYW43_RESOURCE_VERIFY_DOWNLOAD +- + return 0; + } - #if VERIFY_FIRMWARE_DOWNLOAD -+ if(from_storage) { -+ cyw43_storage_cleanup(); -+ storage_get_chunksize(); -+ } - uint32_t t_end = cyw43_hal_ticks_us(); - uint32_t dt = t_end - t_start; - CYW43_VDEBUG("done dnload; dt = %u us; speed = %u kbytes/sec\n", (unsigned int)dt, (unsigned int)(len * 1000 / dt)); -@@ -464,7 +434,7 @@ static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t raw_ - cyw43_read_bytes(self, BACKPLANE_FUNCTION, dest_addr & BACKPLANE_ADDR_MASK, sz, buf); - const uint8_t *src; - if (from_storage) { -- storage_read_blocks(self->spid_buf, source + offset / CYW43_FLASH_BLOCK_SIZE, verify_block_size / CYW43_FLASH_BLOCK_SIZE); -+ cyw43_storage_read(self->spid_buf, verify_block_size); - src = self->spid_buf; - } else { - src = (const uint8_t *)source + offset; -@@ -1372,8 +1342,8 @@ void cyw43_ll_bus_sleep(cyw43_ll_t *self_in, bool can_sleep) { +@@ -1374,7 +1323,7 @@ void cyw43_ll_bus_sleep(cyw43_ll_t *self_in, bool can_sleep) { #define CLM_CHUNK_LEN 1024 + 512 #endif -static void cyw43_clm_load(cyw43_int_t *self, const uint8_t *clm_ptr, size_t clm_len) { -- // Reuse spid_buf but be careful to start at the right offset in it +static void cyw43_clm_load(cyw43_int_t *self, size_t clm_len) { -+ // Reuse spid_buf but be careful to start at the right offset in i + // Reuse spid_buf but be careful to start at the right offset in it uint8_t *buf = &self->spid_buf[SDPCM_HEADER_LEN + 16]; - const size_t clm_dload_chunk_len = CLM_CHUNK_LEN; -@@ -1398,7 +1368,7 @@ static void cyw43_clm_load(cyw43_int_t *self, const uint8_t *clm_ptr, size_t clm +@@ -1400,7 +1349,7 @@ static void cyw43_clm_load(cyw43_int_t *self, const uint8_t *clm_ptr, size_t clm *(uint32_t *)(buf + 12) = len; *(uint32_t *)(buf + 16) = 0; #pragma GCC diagnostic pop - memcpy(buf + 20, clm_ptr + off, len); + cyw43_storage_read(buf + 20, len); - CYW43_VDEBUG("clm data send %lu/%zu\n", off + len, clm_len); + CYW43_VDEBUG("clm data send %u/%u\n", off + len, clm_len); -@@ -1654,12 +1624,9 @@ alp_set: +@@ -1656,14 +1605,11 @@ alp_set: cyw43_write_backplane(self, SOCSRAM_BANKX_INDEX, 4, 0x3); cyw43_write_backplane(self, SOCSRAM_BANKX_PDA, 4, 0); -- // Take firmware from the address space -- cyw43_download_resource(self, 0x00000000, CYW43_WIFI_FW_LEN, 0, fw_data); -- /* - // Take firmware from storage block device -- cyw43_download_resource(self, 0x00000000, CYW43_WIFI_FW_LEN, 1, 0x100 + 0x1000); -- */ +- // Check that valid chipset firmware exists at the given source address. +- int ret = cyw43_check_valid_chipset_firmware(self, CYW43_WIFI_FW_LEN, fw_data); +- if (ret != 0) { +- return ret; +- } ++ // Take firmware from storage block device + cyw43_storage_init(); -+ cyw43_download_resource(self, 0x00000000, storage_get_chunksize(), 1, 0); - size_t wifi_nvram_len = ALIGN_UINT(sizeof(wifi_nvram_4343), 64); - const uint8_t *wifi_nvram_data = wifi_nvram_4343; -@@ -1776,9 +1743,11 @@ f2_ready: + // Download the main WiFi firmware blob to the 43xx device. +- ret = cyw43_download_resource(self, 0x00000000, CYW43_WRITE_BYTES_PAD(CYW43_WIFI_FW_LEN), fw_data); ++ int ret = cyw43_download_resource(self, 0x00000000, cyw43_storage_get_chunksize(), 0); + if (ret != 0) { + return ret; + } +@@ -1784,9 +1730,11 @@ f2_ready: // Load the CLM data; it sits just after main firmware CYW43_VDEBUG("cyw43_clm_load start\n"); - cyw43_clm_load(self, (const uint8_t *)CYW43_CLM_ADDR, CYW43_CLM_LEN); -+ cyw43_clm_load(self, storage_get_chunksize()); ++ cyw43_clm_load(self, cyw43_storage_get_chunksize()); CYW43_VDEBUG("cyw43_clm_load done\n"); + cyw43_storage_cleanup(); @@ -203,18 +179,23 @@ index 604335c..4aeb629 100644 cyw43_write_iovar_u32(self, "bus:txglom", 0, WWD_STA_INTERFACE); // tx glomming off cyw43_write_iovar_u32(self, "apsta", 1, WWD_STA_INTERFACE); // apsta on -@@ -1882,6 +1851,10 @@ int cyw43_ll_wifi_on(cyw43_ll_t *self_in, uint32_t country) { +@@ -1890,10 +1838,14 @@ int cyw43_ll_wifi_on(cyw43_ll_t *self_in, uint32_t country) { cyw43_delay_ms(50); #ifndef NDEBUG + // Get and print firmware version + memcpy(buf, "ver\x00", 4); + cyw43_do_ioctl(self, SDPCM_GET, WLC_GET_VAR, 128, buf, WWD_STA_INTERFACE); -+ CYW43_DEBUG("%s", buf); ++ CYW43_DEBUG("CYW43 ver %s", buf); // Get and print CLM version memcpy(buf, "clmver\x00", 7); cyw43_do_ioctl(self, SDPCM_GET, WLC_GET_VAR, 128, buf, WWD_STA_INTERFACE); -@@ -1911,8 +1884,8 @@ int cyw43_ll_wifi_on(cyw43_ll_t *self_in, uint32_t country) { +- CYW43_DEBUG("%s\n", buf); ++ CYW43_DEBUG("CYW43 clmver %s\n", buf); + #endif + + // Set antenna to chip antenna +@@ -1919,8 +1871,8 @@ int cyw43_ll_wifi_on(cyw43_ll_t *self_in, uint32_t country) { CLR_EV(buf, 19); // roam attempt occurred CLR_EV(buf, 20); // tx fail CLR_EV(buf, 40); // radio @@ -225,7 +206,7 @@ index 604335c..4aeb629 100644 #undef CLR_EV memcpy(buf, "bsscfg:event_msgs", 18); diff --git a/src/cyw43_ll.h b/src/cyw43_ll.h -index 2750238..c281093 100644 +index b5c1ead..6e4ea30 100644 --- a/src/cyw43_ll.h +++ b/src/cyw43_ll.h @@ -67,15 +67,19 @@ @@ -248,12 +229,13 @@ index 2750238..c281093 100644 #define CYW43_EV_CSA_COMPLETE_IND (80) #define CYW43_EV_ASSOC_REQ_IE (87) #define CYW43_EV_ASSOC_RESP_IE (88) -@@ -318,6 +322,11 @@ uint32_t cyw43_ll_read_backplane_reg(cyw43_ll_t *self_in, uint32_t addr); +@@ -316,6 +320,12 @@ uint32_t cyw43_ll_read_backplane_reg(cyw43_ll_t *self_in, uint32_t addr); int cyw43_ll_write_backplane_mem(cyw43_ll_t *self_in, uint32_t addr, uint32_t len, const uint8_t *buf); int cyw43_ll_read_backplane_mem(cyw43_ll_t *self_in, uint32_t addr, uint32_t len, uint8_t *buf); +// Sming framework methods for accessing partition storage +int cyw43_storage_init(); ++uint32_t cyw43_storage_get_chunksize(); +uint32_t cyw43_storage_read(void *dest, uint32_t length); +void cyw43_storage_cleanup(void); + diff --git a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk index 263a6680aa..95ea6acad1 160000 --- a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk +++ b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk @@ -1 +1 @@ -Subproject commit 263a6680aaf590b3c48f55645f30d1b96d168832 +Subproject commit 95ea6acad131124694cda1c162c52cd30e0aece0 diff --git a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch index f559e5fb88..c9373bb0ad 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch +++ b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch @@ -1,58 +1,26 @@ -diff --git a/src/common/pico_util/queue.c b/src/common/pico_util/queue.c -index a5c8e18..c3b8a91 100644 ---- a/src/common/pico_util/queue.c -+++ b/src/common/pico_util/queue.c -@@ -41,7 +41,7 @@ static inline uint16_t inc_index(queue_t *q, uint16_t index) { - return index; - } +diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_default.ld b/src/rp2_common/pico_crt0/rp2040/memmap_default.ld +index 5125401..6ba0d2f 100644 +--- a/src/rp2_common/pico_crt0/rp2040/memmap_default.ld ++++ b/src/rp2_common/pico_crt0/rp2040/memmap_default.ld +@@ -255,7 +255,7 @@ SECTIONS --static bool queue_add_internal(queue_t *q, const void *data, bool block) { -+static bool __not_in_flash_func(queue_add_internal)(queue_t *q, const void *data, bool block) { - do { - uint32_t save = spin_lock_blocking(q->core.spin_lock); - if (queue_get_level_unsafe(q) != q->element_count) { -@@ -94,7 +94,7 @@ static bool queue_peek_internal(queue_t *q, void *data, bool block) { - } while (true); - } - --bool queue_try_add(queue_t *q, const void *data) { -+bool __not_in_flash_func(queue_try_add)(queue_t *q, const void *data) { - return queue_add_internal(q, data, false); - } - -diff --git a/src/rp2_common/hardware_base/include/hardware/address_mapped.h b/src/rp2_common/hardware_base/include/hardware/address_mapped.h -index 8e92d8b..da5feac 100644 ---- a/src/rp2_common/hardware_base/include/hardware/address_mapped.h -+++ b/src/rp2_common/hardware_base/include/hardware/address_mapped.h -@@ -105,12 +105,12 @@ __force_inline static uint32_t xip_alias_check_addr(const void *addr) { - #define xip_nocache_noalloc_alias_untyped(addr) ((void *)(XIP_NOCACHE_NOALLOC_BASE | xip_alias_check_addr(addr))) - - // Typed conversion alias pointer generation macros --#define hw_set_alias(p) ((typeof(p))hw_set_alias_untyped(p)) --#define hw_clear_alias(p) ((typeof(p))hw_clear_alias_untyped(p)) --#define hw_xor_alias(p) ((typeof(p))hw_xor_alias_untyped(p)) --#define xip_noalloc_alias(p) ((typeof(p))xip_noalloc_alias_untyped(p)) --#define xip_nocache_alias(p) ((typeof(p))xip_nocache_alias_untyped(p)) --#define xip_nocache_noalloc_alias(p) ((typeof(p))xip_nocache_noalloc_alias_untyped(p)) -+#define hw_set_alias(p) ((__typeof__(p))hw_set_alias_untyped(p)) -+#define hw_clear_alias(p) ((__typeof__(p))hw_clear_alias_untyped(p)) -+#define hw_xor_alias(p) ((__typeof__(p))hw_xor_alias_untyped(p)) -+#define xip_noalloc_alias(p) ((__typeof__(p))xip_noalloc_alias_untyped(p)) -+#define xip_nocache_alias(p) ((__typeof__(p))xip_nocache_alias_untyped(p)) -+#define xip_nocache_noalloc_alias(p) ((__typeof__(p))xip_nocache_noalloc_alias_untyped(p)) + .flash_end : { + KEEP(*(.embedded_end_block*)) +- PROVIDE(__flash_binary_end = .); ++ __flash_binary_end = .; + } > FLASH - /*! \brief Atomically set the specified bits to 1 in a HW register - * \ingroup hardware_base -diff --git a/src/rp2_common/pico_standard_link/memmap_default.ld b/src/rp2_common/pico_standard_link/memmap_default.ld -index e85b327..cf826c6 100644 ---- a/src/rp2_common/pico_standard_link/memmap_default.ld -+++ b/src/rp2_common/pico_standard_link/memmap_default.ld -@@ -231,7 +231,7 @@ SECTIONS - } > SCRATCH_Y + /* stack limit is poorly named, but historically is maximum heap ptr */ +diff --git a/src/rp2_common/pico_crt0/rp2350/memmap_default.ld b/src/rp2_common/pico_crt0/rp2350/memmap_default.ld +index bce316d..05c1beb 100644 +--- a/src/rp2_common/pico_crt0/rp2350/memmap_default.ld ++++ b/src/rp2_common/pico_crt0/rp2350/memmap_default.ld +@@ -269,7 +269,7 @@ SECTIONS .flash_end : { + KEEP(*(.embedded_end_block*)) - PROVIDE(__flash_binary_end = .); + __flash_binary_end = .; - } > FLASH + } > FLASH =0xaa /* stack limit is poorly named, but historically is maximum heap ptr */ diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/CMakeLists.txt b/Sming/Arch/Rp2040/Components/rp2040/sdk/CMakeLists.txt index 7081f49973..80bfa74b9e 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/sdk/CMakeLists.txt +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/CMakeLists.txt @@ -1,7 +1,12 @@ cmake_minimum_required(VERSION 3.12) -set(PICO_PLATFORM "rp2040") -set(PICO_COMPILER "pico_arm_gcc") +if (PICO_VARIANT STREQUAL "rp2350") + set(PICO_COMPILER "pico_arm_cortex_m33_gcc") + set(PICO_PLATFORM "rp2350-arm-s") +else() + set(PICO_COMPILER "pico_arm_cortex_m0plus_gcc") + set(PICO_PLATFORM "rp2040") +endif() set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) @@ -19,6 +24,8 @@ set(SKIP_PICO_STDIO_UART 1) set(SKIP_PICO_STDIO_USB 1) set(SKIP_TINYUSB 1) +set(PICO_NO_PICOTOOL 1) + # Initialize the SDK pico_sdk_init() @@ -31,6 +38,7 @@ target_compile_definitions(pico PUBLIC PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64 PICO_DIVIDER_IN_RAM=1 PICO_MEM_IN_RAM=1 + PICO_CXX_DISABLE_ALLOCATION_OVERRIDES=1 ) pico_set_program_name(pico "Sming") @@ -40,7 +48,7 @@ include_directories(BEFORE ${pico_lib_SOURCE_DIR}) target_link_libraries(pico hardware_adc - hardware_base + hardware_boot_lock hardware_claim hardware_clocks hardware_divider @@ -63,15 +71,21 @@ target_link_libraries(pico hardware_vreg hardware_watchdog hardware_xosc + pico_aon_timer pico_bit_ops pico_divider pico_double pico_fix + pico_flash pico_float pico_int64_ops pico_mem_ops pico_multicore + pico_platform_compiler + pico_platform_panic + pico_platform_sections pico_runtime + pico_runtime_init pico_standard_link pico_unique_id pico_audio_i2s diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_bit_ops.mk b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_bit_ops.mk index a0ec0d43df..b25898865e 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_bit_ops.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_bit_ops.mk @@ -1,5 +1,6 @@ # pico_bit_ops +ifeq ($(SMING_SOC),rp2040) WRAPPED_FUNCTIONS += \ __clzsi2 \ __clzdi2 \ @@ -7,3 +8,4 @@ WRAPPED_FUNCTIONS += \ __ctzdi2 \ __popcountsi2 \ __popcountdi2 +endif diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_divider.mk b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_divider.mk index 8578a4ccf2..a8f3244744 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_divider.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_divider.mk @@ -1,5 +1,6 @@ # pico_divider +ifeq ($(SMING_SOC),rp2040) WRAPPED_FUNCTIONS += \ __aeabi_idiv \ __aeabi_idivmod \ @@ -7,3 +8,4 @@ WRAPPED_FUNCTIONS += \ __aeabi_uidiv \ __aeabi_uidivmod \ __aeabi_uldivmod +endif diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_float.mk b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_float.mk index e45345f639..ef47c520ad 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_float.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_float.mk @@ -1,5 +1,6 @@ # pico_float +ifeq ($(SMING_SOC),rp2040) WRAPPED_FUNCTIONS += \ __aeabi_fadd \ __aeabi_fdiv \ @@ -24,7 +25,10 @@ WRAPPED_FUNCTIONS += \ __aeabi_f2uiz \ __aeabi_f2ulz \ __aeabi_f2d \ - sqrtf \ + sqrtf +endif + +WRAPPED_FUNCTIONS += \ cosf \ sinf \ tanf \ diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_int64_ops.mk b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_int64_ops.mk index 83f39e1492..ce6c395606 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_int64_ops.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_int64_ops.mk @@ -1,4 +1,6 @@ # pico_int64_ops +ifeq ($(SMING_SOC),rp2040) WRAPPED_FUNCTIONS += \ __aeabi_lmul +endif diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_mem_ops.mk b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_mem_ops.mk index 6244c18b5d..9815650161 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_mem_ops.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_mem_ops.mk @@ -1,5 +1,6 @@ # pico_mem_ops +ifeq ($(SMING_SOC),rp2040) WRAPPED_FUNCTIONS += \ memcpy \ memset \ @@ -9,3 +10,4 @@ WRAPPED_FUNCTIONS += \ __aeabi_memset4 \ __aeabi_memcpy8 \ __aeabi_memset8 +endif diff --git a/Sming/Arch/Rp2040/Components/rp2040/src/clk.c b/Sming/Arch/Rp2040/Components/rp2040/src/clk.c index 6abc297851..2724fd0393 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/src/clk.c +++ b/Sming/Arch/Rp2040/Components/rp2040/src/clk.c @@ -25,38 +25,6 @@ uint32_t IRAM_ATTR esp_get_ccount() return ((1 + ovf) << 24) - systick_hw->cvr; } -/*! \brief Check if a given system clock frequency is valid/attainable - * \ingroup pico_stdlib - * - * \param freq_khz Requested frequency - * \param vco_freq_out On success, the voltage controller oscillator frequeucny to be used by the SYS PLL - * \param post_div1_out On success, The first post divider for the SYS PLL - * \param post_div2_out On success, The second post divider for the SYS PLL. - * @return true if the frequency is possible and the output parameters have been written. - */ -static bool check_sys_clock_khz(uint32_t freq_khz, uint* vco_out, uint* postdiv1_out, uint* postdiv_out) -{ - uint crystal_freq_khz = clock_get_hz(clk_ref) / 1000; - for(uint fbdiv = 320; fbdiv >= 16; fbdiv--) { - uint vco = fbdiv * crystal_freq_khz; - if(vco < 400000 || vco > 1600000) { - continue; - } - for(uint postdiv1 = 7; postdiv1 >= 1; postdiv1--) { - for(uint postdiv2 = postdiv1; postdiv2 >= 1; postdiv2--) { - uint out = vco / (postdiv1 * postdiv2); - if(out == freq_khz && (vco % (postdiv1 * postdiv2)) == 0) { - *vco_out = vco * 1000; - *postdiv1_out = postdiv1; - *postdiv_out = postdiv2; - return true; - } - } - } - } - return false; -} - // Fix the peripheral clocks but allow system (CPU) to be varied independently using PLL void system_init_clocks() { @@ -85,10 +53,17 @@ void system_init_clocks() // Initialise systick for use by esp_get_ccount() exception_set_exclusive_handler(SYSTICK_EXCEPTION, systick_overflow_isr); +#ifdef SOC_RP2350 + systick_hw->csr = (1 << M33_SYST_CSR_CLKSOURCE_LSB) // Processor CLK source + | M33_SYST_CSR_TICKINT_BITS // Enable overflow ISR + | M33_SYST_CSR_ENABLE_BITS; // ENABLE + systick_hw->rvr = M33_SYST_RVR_BITS; // Reload value when counter hits 0 +#else systick_hw->csr = (1 << M0PLUS_SYST_CSR_CLKSOURCE_LSB) // Processor CLK source | M0PLUS_SYST_CSR_TICKINT_BITS // Enable overflow ISR | M0PLUS_SYST_CSR_ENABLE_BITS; // ENABLE systick_hw->rvr = M0PLUS_SYST_RVR_BITS; // Reload value when counter hits 0 +#endif } bool system_update_cpu_freq(uint8_t mhz) diff --git a/Sming/Arch/Rp2040/Components/rp2040/src/startup.cpp b/Sming/Arch/Rp2040/Components/rp2040/src/startup.cpp index ab6e329416..77d50b6e13 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/src/startup.cpp +++ b/Sming/Arch/Rp2040/Components/rp2040/src/startup.cpp @@ -57,8 +57,14 @@ bool __noinline IRAM_ATTR get_bootsel_button() // } - // Read input (low when BOOTSEL pressed) - bool button_state = !(sio_hw->gpio_hi_in & BIT(CS_PIN_INDEX)); + // The HI GPIO registers in SIO can observe and control the 6 QSPI pins. + // Note the button pulls the pin *low* when pressed. +#ifdef SOC_RP2040 +#define CS_BIT (1u << 1) +#else +#define CS_BIT SIO_GPIO_HI_IN_QSPI_CSN_BITS +#endif + bool button_state = !(sio_hw->gpio_hi_in & CS_BIT); // Re-enable chip select hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl, GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB, @@ -88,15 +94,11 @@ void check_bootsel() } // namespace -extern void system_init_rtc(); - extern "C" int main(void) { extern void system_init_clocks(); system_init_clocks(); - system_init_rtc(); - system_soft_wdt_restart(); // Initialise hardware timers diff --git a/Sming/Arch/Rp2040/Components/rp2040/src/wifi.cpp b/Sming/Arch/Rp2040/Components/rp2040/src/wifi.cpp index d048995da7..1615997c0f 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/src/wifi.cpp +++ b/Sming/Arch/Rp2040/Components/rp2040/src/wifi.cpp @@ -122,6 +122,27 @@ uint32_t cyw43_storage_read(void* dest, uint32_t length) return length; } +uint32_t cyw43_storage_get_chunksize() +{ + const uint32_t chunkTag = 0x4b4e4843; // "CHNK" + struct chunk_t { + uint32_t tag; + uint32_t length; + }; + struct chunk_t chunk; + int res = cyw43_storage_read(&chunk, sizeof(chunk)); + if(res != sizeof(chunk)) { + debug_e("[CYW43] Bad chunk header %d\n", res); + return 0; + } + if(chunk.tag != chunkTag) { + debug_e("[CYW43] Bad chunk tag %08x\n", chunk.tag); + return 0; + } + debug_d("[CYW43] Chunk %u bytes\n", chunk.length); + return chunk.length; +} + void cyw43_storage_cleanup() { decompressor.reset(); diff --git a/Sming/Arch/Rp2040/Components/sming-arch/component.mk b/Sming/Arch/Rp2040/Components/sming-arch/component.mk index 95761ca116..1395bfdfa5 100644 --- a/Sming/Arch/Rp2040/Components/sming-arch/component.mk +++ b/Sming/Arch/Rp2040/Components/sming-arch/component.mk @@ -12,6 +12,7 @@ COMPONENT_DEPENDS := \ libc \ rp2040 \ uf2 \ + picotool \ driver \ gdbstub \ spi_flash diff --git a/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp b/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp index 36917e6ffa..fe25a3566a 100644 --- a/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp +++ b/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp @@ -13,9 +13,15 @@ #include #include #include +#include + +#ifdef SOC_RP2350 +#include +#include +#else #include #include -#include +#endif #define FLASHCMD_READ_SFDP 0x5a #define FLASHCMD_READ_JEDEC_ID 0x9f @@ -305,11 +311,33 @@ bool flashmem_erase_sector(flash_sector_t sector_id) return true; } +/* + DOUT/DUAL, ///< Two bits per clock for Data, 1-bit for Command and Address + DIO, ///< Two bits per clock for Address and Data, 1-bit for Command + QOUT/QUAD, ///< Four bits per clock for Data, 1-bit for Command and Address + QIO, ///< Four bits per clock for Address and Data, 1-bit for Command +*/ SPIFlashInfo flashmem_get_info() { SPIFlashInfo info{}; info.size = flashmem_get_size_type(); +#ifdef SOC_RP2350 + uint32_t rfmt = qmi_hw->m[0].rfmt; + auto data_width = (rfmt & QMI_M0_RFMT_DATA_WIDTH_BITS) >> QMI_M0_RFMT_DATA_WIDTH_LSB; + auto addr_width = (rfmt & QMI_M0_RFMT_ADDR_WIDTH_BITS) >> QMI_M0_RFMT_ADDR_WIDTH_LSB; + + switch(data_width) { + case 2: + info.mode = (addr_width == QMI_M0_RFMT_ADDR_WIDTH_VALUE_D) ? MODE_DIO : MODE_DOUT; + break; + case 4: + info.mode = (addr_width == QMI_M0_RFMT_ADDR_WIDTH_VALUE_Q) ? MODE_QIO : MODE_QOUT; + break; + default: + info.mode = MODE_SLOW_READ; + } +#else // Flash mode uint32_t ctrlr0 = ssi_hw->ctrlr0; auto ssi_frame_format = (ctrlr0 & SSI_CTRLR0_SPI_FRF_BITS) >> SSI_CTRLR0_SPI_FRF_LSB; @@ -326,6 +354,7 @@ SPIFlashInfo flashmem_get_info() default: info.mode = MODE_SLOW_READ; } +#endif return info; } @@ -376,11 +405,7 @@ uint32_t spi_flash_get_id(void) flash_addr_t flashmem_get_address(const void* memptr) { - auto addr = uint32_t(memptr); - if(addr < XIP_BASE || addr >= XIP_NOALLOC_BASE) { - return 0; - } - return addr - XIP_BASE; + return isFlashPtr(memptr) ? (uint32_t(memptr) - XIP_BASE) : 0; } void flashmem_sfdp_read(uint32_t addr, void* buffer, size_t count) diff --git a/Sming/Arch/Rp2040/Components/uf2/component.mk b/Sming/Arch/Rp2040/Components/uf2/component.mk index a2f33922a9..21d4d52ec4 100644 --- a/Sming/Arch/Rp2040/Components/uf2/component.mk +++ b/Sming/Arch/Rp2040/Components/uf2/component.mk @@ -8,6 +8,11 @@ COMPONENT_DOCFILES := \ DEBUG_VARS += UF2CONV_PY UF2CONV_PY := $(COMPONENT_PATH)/uf2conv.py +ifeq ($(SMING_SOC),rp2350) +UF2_FAMILY := "rp2xxx_absolute" +else +UF2_FAMILY := "rp2040" +endif # Invoke uf2conv utility # $1 -> Parameters @@ -17,19 +22,12 @@ else Uf2Conv = $(PYTHON) $(UF2CONV_PY) $(if $V,--verbose) $1 endif - -# Read flash manufacturer ID and determine actual size -define ReadFlashID - $(info Reading Flash ID) - $(call Uf2Conv,--list --verbose) -endef - # Write file contents to Flash # $1 -> List of `Offset=File` chunks define WriteFlash $(if $1,\ $(info WriteFlash $1) \ - $(call Uf2Conv,--upload $1 --output $(OUT_BASE)/flash.uf2) + $(call Uf2Conv,--family $(UF2_FAMILY) --upload $1 --output $(OUT_BASE)/flash.uf2) ) endef @@ -41,23 +39,3 @@ define VerifyFlash $(info ** NOT IMPLEMENTED **) ) endef - -# Read flash memory into file -# $1 -> `Offset,Size` chunk -# $2 -> Output filename -define ReadFlash - $(info ReadFlash $1,$2) - $(info ** NOT IMPLEMENTED **) -endef - -# Erase a region of Flash -# $1 -> Offset,Size -define EraseFlashRegion - $(info EraseFlashRegion $1) - $(info ** NOT IMPLEMENTED **) -endef - -# Erase flash memory contents -define EraseFlash - $(info ** NOT IMPLEMENTED **) -endef diff --git a/Sming/Arch/Rp2040/Components/uf2/uf2families.json b/Sming/Arch/Rp2040/Components/uf2/uf2families.json index 42b5bbc2a2..26812b97b8 100644 --- a/Sming/Arch/Rp2040/Components/uf2/uf2families.json +++ b/Sming/Arch/Rp2040/Components/uf2/uf2families.json @@ -34,6 +34,11 @@ "short_name": "STM32WL", "description": "ST STM32WLxx" }, + { + "id": "0x22e0d6fc", + "short_name": "RTL8710B", + "description": "Realtek AmebaZ RTL8710B" + }, { "id": "0x2abc77ec", "short_name": "LPC55", @@ -49,6 +54,11 @@ "short_name": "GD32F350", "description": "GD32F350" }, + { + "id": "0x3379CFE2", + "short_name": "RTL8720D", + "description": "Realtek AmebaD RTL8720D" + }, { "id": "0x04240bdf", "short_name": "STM32L5", @@ -64,6 +74,11 @@ "short_name": "MIMXRT10XX", "description": "NXP i.MX RT10XX" }, + { + "id": "0x51e903a8", + "short_name": "XR809", + "description": "Xradiotech 809" + }, { "id": "0x53b80f00", "short_name": "STM32F7", @@ -77,7 +92,7 @@ { "id": "0x57755a57", "short_name": "STM32F4", - "description": "ST STM32F401" + "description": "ST STM32F4xx" }, { "id": "0x5a18069b", @@ -94,16 +109,31 @@ "short_name": "STM32F1", "description": "ST STM32F103" }, + { + "id": "0x621e937a", + "short_name": "NRF52833", + "description": "Nordic NRF52833" + }, { "id": "0x647824b6", "short_name": "STM32F0", "description": "ST STM32F0xx" }, + { + "id": "0x675a40b0", + "short_name": "BK7231U", + "description": "Beken 7231U/7231T" + }, { "id": "0x68ed2b88", "short_name": "SAMD21", "description": "Microchip (Atmel) SAMD21" }, + { + "id": "0x6a82cc42", + "short_name": "BK7251", + "description": "Beken 7251/7252" + }, { "id": "0x6b846188", "short_name": "STM32F3", @@ -114,6 +144,11 @@ "short_name": "STM32F407", "description": "ST STM32F407" }, + { + "id": "0x4e8f1c5d", + "short_name": "STM32H5", + "description": "ST STM32H5xx" + }, { "id": "0x6db66082", "short_name": "STM32H7", @@ -124,6 +159,11 @@ "short_name": "STM32WB", "description": "ST STM32WBxx" }, + { + "id": "0x7b3ef230", + "short_name": "BK7231N", + "description": "Beken 7231N" + }, { "id": "0x7eab61ed", "short_name": "ESP8266", @@ -139,11 +179,21 @@ "short_name": "STM32F407VG", "description": "ST STM32F407VG" }, + { + "id": "0x9fffd543", + "short_name": "RTL8710A", + "description": "Realtek Ameba1 RTL8710A" + }, { "id": "0xada52840", "short_name": "NRF52840", "description": "Nordic NRF52840" }, + { + "id": "0x820d9a5f", + "short_name": "NRF52820", + "description": "Nordic NRF52820_xxAA" + }, { "id": "0xbfdd4eee", "short_name": "ESP32S2", @@ -159,14 +209,144 @@ "short_name": "ESP32C3", "description": "ESP32-C3" }, + { + "id": "0x2b88d29c", + "short_name": "ESP32C2", + "description": "ESP32-C2" + }, + { + "id": "0x332726f6", + "short_name": "ESP32H2", + "description": "ESP32-H2" + }, + { + "id": "0x540ddf62", + "short_name": "ESP32C6", + "description": "ESP32-C6" + }, + { + "id": "0x3d308e94", + "short_name": "ESP32P4", + "description": "ESP32-P4" + }, + { + "id": "0xf71c0343", + "short_name": "ESP32C5", + "description": "ESP32-C5" + }, + { + "id": "0x77d850c4", + "short_name": "ESP32C61", + "description": "ESP32-C61" + }, + { + "id": "0xde1270b7", + "short_name": "BL602", + "description": "Boufallo 602" + }, + { + "id": "0xe08f7564", + "short_name": "RTL8720C", + "description": "Realtek AmebaZ2 RTL8720C" + }, { "id": "0xe48bff56", "short_name": "RP2040", "description": "Raspberry Pi RP2040" }, + { + "id": "0xe48bff57", + "short_name": "RP2XXX_ABSOLUTE", + "description": "Raspberry Pi Microcontrollers: Absolute (unpartitioned) download" + }, + { + "id": "0xe48bff58", + "short_name": "RP2XXX_DATA", + "description": "Raspberry Pi Microcontrollers: Data partition download" + }, + { + "id": "0xe48bff59", + "short_name": "RP2350_ARM_S", + "description": "Raspberry Pi RP2350, Secure Arm image" + }, + { + "id": "0xe48bff5a", + "short_name": "RP2350_RISCV", + "description": "Raspberry Pi RP2350, RISC-V image" + }, + { + "id": "0xe48bff5b", + "short_name": "RP2350_ARM_NS", + "description": "Raspberry Pi RP2350, Non-secure Arm image" + }, { "id": "0x00ff6919", "short_name": "STM32L4", "description": "ST STM32L4xx" + }, + { + "id": "0x9af03e33", + "short_name": "GD32VF103", + "description": "GigaDevice GD32VF103" + }, + { + "id": "0x4f6ace52", + "short_name": "CSK4", + "description": "LISTENAI CSK300x/400x" + }, + { + "id": "0x6e7348a8", + "short_name": "CSK6", + "description": "LISTENAI CSK60xx" + }, + { + "id": "0x11de784a", + "short_name": "M0SENSE", + "description": "M0SENSE BL702" + }, + { + "id": "0x4b684d71", + "short_name": "MaixPlay-U4", + "description": "Sipeed MaixPlay-U4(BL618)" + }, + { + "id": "0x9517422f", + "short_name": "RZA1LU", + "description": "Renesas RZ/A1LU (R7S7210xx)" + }, + { + "id": "0x2dc309c5", + "short_name": "STM32F411xE", + "description": "ST STM32F411xE" + }, + { + "id": "0x06d1097b", + "short_name": "STM32F411xC", + "description": "ST STM32F411xC" + }, + { + "id": "0x72721d4e", + "short_name": "NRF52832xxAA", + "description": "Nordic NRF52832xxAA" + }, + { + "id": "0x6f752678", + "short_name": "NRF52832xxAB", + "description": "Nordic NRF52832xxAB" + }, + { + "id": "0xa0c97b8e", + "short_name": "AT32F415", + "description": "ArteryTek AT32F415" + }, + { + "id": "0x699b62ec", + "short_name": "CH32V", + "description": "WCH CH32V2xx and CH32V3xx" + }, + { + "id": "0x7be8976d", + "short_name": "RA4M1", + "description": "Renesas RA4M1" } -] \ No newline at end of file +] diff --git a/Sming/Arch/Rp2040/Platform/RTC.cpp b/Sming/Arch/Rp2040/Platform/RTC.cpp index 07a317b173..07c14c7ed8 100644 --- a/Sming/Arch/Rp2040/Platform/RTC.cpp +++ b/Sming/Arch/Rp2040/Platform/RTC.cpp @@ -9,66 +9,62 @@ ****/ #include -#include -#include #include - -extern "C" int settimeofday(const struct timeval*, const struct timezone*); +#include RtcClass RTC; -#define NS_PER_SECOND 1000000000 +#define NS_PER_SECOND 1'000'000'000 +#define US_PER_SECOND 1'000'000 + +RtcClass::RtcClass() = default; -void system_init_rtc() +namespace { - rtc_init(); - datetime_t t{.year = 1970, .month = 1, .day = 1}; - rtc_set_datetime(&t); +int64_t epoch_sys_time_us; } -RtcClass::RtcClass() = default; - -uint64_t RtcClass::getRtcNanoseconds() +extern "C" int _gettimeofday(struct timeval* tv, void*) { - return uint64_t(getRtcSeconds()) * NS_PER_SECOND; + if(tv) { + auto us_since_epoch = epoch_sys_time_us + time_us_64(); + *tv = { + .tv_sec = time_t(us_since_epoch / US_PER_SECOND), + .tv_usec = suseconds_t(us_since_epoch % US_PER_SECOND), + }; + } + return 0; } -uint32_t RtcClass::getRtcSeconds() +extern "C" int settimeofday(const struct timeval* tv, const struct timezone*) { - datetime_t t; - if(!rtc_get_datetime(&t)) { - return 0; + if(tv) { + auto us_since_epoch = tv->tv_sec * US_PER_SECOND + tv->tv_usec; + epoch_sys_time_us = us_since_epoch - time_us_64(); } + return 0; +} - DateTime dt; - dt.setTime(t.sec, t.min, t.hour, t.day, t.month - 1, t.year); +uint64_t RtcClass::getRtcNanoseconds() +{ + return uint64_t(epoch_sys_time_us + time_us_64()) * 1000ULL; +} - return time_t(dt); +uint32_t RtcClass::getRtcSeconds() +{ + return (epoch_sys_time_us + time_us_64()) / US_PER_SECOND; } bool RtcClass::setRtcNanoseconds(uint64_t nanoseconds) { - return setRtcSeconds(nanoseconds / NS_PER_SECOND); + auto us_since_epoch = nanoseconds / 1000; + epoch_sys_time_us = us_since_epoch - get_absolute_time(); + return true; } bool RtcClass::setRtcSeconds(uint32_t seconds) { - struct timeval tv { - seconds - }; - settimeofday(&tv, nullptr); - - DateTime dt{seconds}; - - datetime_t t = { - .year = int16_t(dt.Year), - .month = int8_t(1 + dt.Month), - .day = int8_t(dt.Day), - .dotw = int8_t(dt.DayofWeek), - .hour = int8_t(dt.Hour), - .min = int8_t(dt.Minute), - .sec = int8_t(dt.Second), - }; - - return rtc_set_datetime(&t); + auto us_since_epoch = int64_t(seconds) * US_PER_SECOND; + epoch_sys_time_us = us_since_epoch - time_us_64(); + return true; } diff --git a/Sming/Arch/Rp2040/README.rst b/Sming/Arch/Rp2040/README.rst index 3897680c39..de9dfe5a19 100644 --- a/Sming/Arch/Rp2040/README.rst +++ b/Sming/Arch/Rp2040/README.rst @@ -3,11 +3,13 @@ Sming RP2040 Architecture .. highlight:: bash -Support building Sming for the `Raspberry Pi RP2040 SOC -`__. +Support building Sming for the `Raspberry Pi Pico-series Microcontrollers `__. +At time of writing this includes both RP2040 and RP2350 devices. -Testing so far has been limited to the Rasperry Pi Pico, but there are lots of other boards available. -Configure this using the :envvar:`PICO_BOARD` setting. The default is ``pico`` (or ``pico_w`` if networking is enabled). +Testing has been limited to the Rasperry Pi Pico development boards, but there are lots of others available. +Configure this using the :envvar:`PICO_BOARD` setting. +The default is ``pico`` (or ``pico_w`` if networking is enabled). +Support for the new ``pico2`` boards is provided using :envvar:`SMING_SOC=rp2350 `. You can find the `full list here `__. Special mention to the arduino-pico project https://github.com/earlephilhower/arduino-pico. @@ -41,7 +43,8 @@ The following features are tested and working: - USB supported using the :library:`USB` library, both host and device modes. - HardwareSPI via :library:`HardwareSPI` for fully asynchronous SPI communications (host mode only). -Not yet implemented: +Limited or no support is provided for the following items. +In many cases best use of the hardware is made using the Pico SDK API directly. PWM Hardware can drive up to 16 outputs and measure input frequency/duty cycle. @@ -51,13 +54,14 @@ I2C RTC Can wake from deep sleep but requires an external clock (e.g. 32kHz crystal) and appropriate API. (Setting and reading the time is implemented.) + Note that the RP2350 does not have an RTC. Sming uses the Always-On timer api to support both devices. Low-power modes Deep sleep / suspend / power-saving PIO (Programmable I/O) - A killer feature for the RP2040. + A killer feature for the RP2 series. Uses range from simple glue logic to I2S, etc. Crash/exception handling & serial debugging - RP2040 supports JTAG debugging but requires extra hardware. + RP2 devices support JTAG debugging but requires extra hardware. Serial debugging is often enough and easier to set up. Requires GDB stub plus implementing crash handler callbacks, etc. Multi-boot / OTA updates. @@ -66,8 +70,13 @@ Multi-boot / OTA updates. Adding RP2040 support to rBoot may work, however the Pico typically has only 2MByte flash which is quite restrictive. It is also necessary to compile images at different addresses as there is no windowed XIP (eXecute In Place) capability. See :library:`FlashIP` library for a basic method of OTA. + Note that the Pico2 boards have 4MByte flash and partition table support which requires integrating with Sming. Bluetooth - The SDK supports this but has not yet been integrated into Sming. + The SDK supports bluetooth for the CYW43439 BT/WiFi SoC which the Pico-W boards (and other) use. + This has not yet been integrated into Sming. +RISCV (RP2350) + Sming builds ARM code but these devices also support RISCV. + This will require an additional toolchain and compile options. Installation @@ -144,10 +153,7 @@ Once the file has finished sending the RP2040 reboots itself into normal operati The RP2040 can also be programmed via JTAG debugging but this requires additional hardware and setup. -.. note:: - - The RP2040 bootloader does not include support for reading flash memory via mass storage, - so commands such as ``make verifyflash`` won't work at present. +Commands such as ``make readmap`` use :component-rp2040:`picotool` and require the device to be in BOOT mode. Dual-core support diff --git a/Sming/Arch/Rp2040/app.mk b/Sming/Arch/Rp2040/app.mk index 97bd3ab590..e1c19d9882 100644 --- a/Sming/Arch/Rp2040/app.mk +++ b/Sming/Arch/Rp2040/app.mk @@ -8,9 +8,19 @@ LDFLAGS += \ -Wl,--build-id=none \ --specs=nosys.specs \ - -mcpu=cortex-m0plus \ -mthumb +ifeq ($(SMING_SOC),rp2350) +LDFLAGS += \ + -mcpu=cortex-m33 \ + -march=armv8-m.main+fp+dsp \ + -mfloat-abi=softfp +else +LDFLAGS += \ + -mcpu=cortex-m0plus \ + -march=armv6-m +endif + ifneq ($(COMPILER_VERSION_MAJOR),10) LDFLAGS += -Wl,--no-warn-rwx-segments endif diff --git a/Sming/Arch/Rp2040/build.mk b/Sming/Arch/Rp2040/build.mk index d3ccb6622f..08d421e887 100644 --- a/Sming/Arch/Rp2040/build.mk +++ b/Sming/Arch/Rp2040/build.mk @@ -7,11 +7,27 @@ CPPFLAGS += \ -DARCH_RP2040 \ -DARDUINO_ARCH_RP2040 \ - -march=armv6-m \ - -mcpu=cortex-m0plus \ + -DPICO_NO_HARDWARE=0 \ + -DPICO_ON_DEVICE=1 \ + -DPICO_32BIT=1 \ -mthumb \ -nostdlib +ifeq ($(SMING_SOC),rp2350) +RP_VARIANT = rp2350 +CPPFLAGS += \ + -mcpu=cortex-m33 \ + -march=armv8-m.main+fp+dsp \ + -mfloat-abi=softfp \ + -mcmse \ + -DPICO_RP2350 +else +RP_VARIANT = rp2040 +CPPFLAGS += \ + -mcpu=cortex-m0plus \ + -DPICO_RP2040 +endif + CXXFLAGS += \ -fno-threadsafe-statics \ -fno-use-cxa-atexit diff --git a/Sming/Arch/Rp2040/rp2350-pindefs.txt b/Sming/Arch/Rp2040/rp2350-pindefs.txt new file mode 100644 index 0000000000..e8940b933e --- /dev/null +++ b/Sming/Arch/Rp2040/rp2350-pindefs.txt @@ -0,0 +1,52 @@ +[io_mux] +gpio f0 f1 f2 f3 f4 ff5 ff6 ff7 ff8 f9 f10 f11 notes +0 - SPI0_RX UART0_TX I2C0_SDA PWM0_A SIO PIO0 PIO1 PIO2 XIP_CS1n USB_OVCUR_DET - +1 - SPI0_CSn UART0_RX I2C0_SCL PWM0_B SIO PIO0 PIO1 PIO2 TRACECLK USB_VBUS_DET - +2 - SPI0_SCK UART0_CTS I2C1_SDA PWM1_A SIO PIO0 PIO1 PIO2 TRACEDATA0 USB_VBUS_EN UART0_TX +3 - SPI0_TX UART0_RTS I2C1_SCL PWM1_B SIO PIO0 PIO1 PIO2 TRACEDATA1 USB_OVCUR_DET UART0_RX +4 - SPI0_RX UART1_TX I2C0_SDA PWM2_A SIO PIO0 PIO1 PIO2 TRACEDATA2 USB_VBUS_DET - +5 - SPI0_CSn UART1_RX I2C0_SCL PWM2_B SIO PIO0 PIO1 PIO2 TRACEDATA3 USB_VBUS_EN - +6 - SPI0_SCK UART1_CTS I2C1_SDA PWM3_A SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET UART1_TX +7 - SPI0_TX UART1_RTS I2C1_SCL PWM3_B SIO PIO0 PIO1 PIO2 - USB_VBUS_DET UART1_RX +8 - SPI1_RX UART1_TX I2C0_SDA PWM4_A SIO PIO0 PIO1 PIO2 XIP_CS1n USB_VBUS_EN - +9 - SPI1_CSn UART1_RX I2C0_SCL PWM4_B SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET - +10 - SPI1_SCK UART1_CTS I2C1_SDA PWM5_A SIO PIO0 PIO1 PIO2 - USB_VBUS_DET UART1_TX +11 - SPI1_TX UART1_RTS I2C1_SCL PWM5_B SIO PIO0 PIO1 PIO2 - USB_VBUS_EN UART1_RX +12 HSTX SPI1_RX UART0_TX I2C0_SDA PWM6_A SIO PIO0 PIO1 PIO2 CLOCK_GPIN0 USB_OVCUR_DET - +13 HSTX SPI1_CSn UART0_RX I2C0_SCL PWM6_B SIO PIO0 PIO1 PIO2 CLOCK_GPOUT0 USB_VBUS_DET - +14 HSTX SPI1_SCK UART0_CTS I2C1_SDA PWM7_A SIO PIO0 PIO1 PIO2 CLOCK_GPIN1 USB_VBUS_EN UART0_TX +15 HSTX SPI1_TX UART0_RTS I2C1_SCL PWM7_B SIO PIO0 PIO1 PIO2 CLOCK_GPOUT1 USB_OVCUR_DET UART0_RX +16 HSTX SPI0_RX UART0_TX I2C0_SDA PWM0_A SIO PIO0 PIO1 PIO2 - USB_VBUS_DET - +17 HSTX SPI0_CSn UART0_RX I2C0_SCL PWM0_B SIO PIO0 PIO1 PIO2 - USB_VBUS_EN - +18 HSTX SPI0_SCK UART0_CTS I2C1_SDA PWM1_A SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET UART0_TX +19 HSTX SPI0_TX UART0_RTS I2C1_SCL PWM1_B SIO PIO0 PIO1 PIO2 XIP_CS1n USB_VBUS_DET UART0_RX +20 - SPI0_RX UART1_TX I2C0_SDA PWM2_A SIO PIO0 PIO1 PIO2 CLOCK_GPIN0 USB_VBUS_EN - +21 - SPI0_CSn UART1_RX I2C0_SCL PWM2_B SIO PIO0 PIO1 PIO2 CLOCK_GPOUT0 USB_OVCUR_DET - +22 - SPI0_SCK UART1_CTS I2C1_SDA PWM3_A SIO PIO0 PIO1 PIO2 CLOCK_GPIN1 USB_VBUS_DET UART1_TX +23 - SPI0_TX UART1_RTS I2C1_SCL PWM3_B SIO PIO0 PIO1 PIO2 CLOCK_GPOUT1 USB_VBUS_EN UART1_RX +24 - SPI1_RX UART1_TX I2C0_SDA PWM4_A SIO PIO0 PIO1 PIO2 CLOCK_GPOUT2 USB_OVCUR_DET - +25 - SPI1_CSn UART1_RX I2C0_SCL PWM4_B SIO PIO0 PIO1 PIO2 CLOCK_GPOUT3 USB_VBUS_DET - +26 - SPI1_SCK UART1_CTS I2C1_SDA PWM5_A SIO PIO0 PIO1 PIO2 - USB_VBUS_EN UART1_TX +27 - SPI1_TX UART1_RTS I2C1_SCL PWM5_B SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET UART1_RX +28 - SPI1_RX UART0_TX I2C0_SDA PWM6_A SIO PIO0 PIO1 PIO2 - USB_VBUS_DET - +29 - SPI1_CSn UART0_RX I2C0_SCL PWM6_B SIO PIO0 PIO1 PIO2 - USB_VBUS_EN - + +# IOs 30 through 47 are QFN-80 only +30 - SPI1_SCK UART0_CTS I2C1_SDA PWM7_A SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET UART0_TX +31 - SPI1_TX UART0_RTS I2C1_SCL PWM7_B SIO PIO0 PIO1 PIO2 - USB_VBUS_DET UART0_RX +32 - SPI0_RX UART0_TX I2C0_SDA PWM8_A SIO PIO0 PIO1 PIO2 - USB_VBUS_EN - +33 - SPI0_CSn UART0_RX I2C0_SCL PWM8_B SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET - +34 - SPI0_SCK UART0_CTS I2C1_SDA PWM9_A SIO PIO0 PIO1 PIO2 - USB_VBUS_DET UART0_TX +35 - SPI0_TX UART0_RTS I2C1_SCL PWM9_B SIO PIO0 PIO1 PIO2 - USB_VBUS_EN UART0_RX +36 - SPI0_RX UART1_TX I2C0_SDA PWM10_A SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET - +37 - SPI0_CSn UART1_RX I2C0_SCL PWM10_B SIO PIO0 PIO1 PIO2 - USB_VBUS_DET - +38 - SPI0_SCK UART1_CTS I2C1_SDA PWM11_A SIO PIO0 PIO1 PIO2 - USB_VBUS_EN UART1_TX +39 - SPI0_TX UART1_RTS I2C1_SCL PWM11_B SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET UART1_RX +40 - SPI1_RX UART1_TX I2C0_SDA PWM8_A SIO PIO0 PIO1 PIO2 - USB_VBUS_DET - +41 - SPI1_CSn UART1_RX I2C0_SCL PWM8_B SIO PIO0 PIO1 PIO2 - USB_VBUS_EN - +42 - SPI1_SCK UART1_CTS I2C1_SDA PWM9_A SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET UART1_TX +43 - SPI1_TX UART1_RTS I2C1_SCL PWM9_B SIO PIO0 PIO1 PIO2 - USB_VBUS_DET UART1_RX +44 - SPI1_RX UART0_TX I2C0_SDA PWM10_A SIO PIO0 PIO1 PIO2 - USB_VBUS_EN - +45 - SPI1_CSn UART0_RX I2C0_SCL PWM10_B SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET - +46 - SPI1_SCK UART0_CTS I2C1_SDA PWM11_A SIO PIO0 PIO1 PIO2 - USB_VBUS_DET UART0_TX +47 - SPI1_TX UART0_RTS I2C1_SCL PWM11_B SIO PIO0 PIO1 PIO2 XIP_CS1n USB_VBUS_EN UART0_RX diff --git a/Sming/Arch/Rp2040/rp2350-soc.json b/Sming/Arch/Rp2040/rp2350-soc.json new file mode 100644 index 0000000000..bbd9c6cfe8 --- /dev/null +++ b/Sming/Arch/Rp2040/rp2350-soc.json @@ -0,0 +1,62 @@ +{ + "variant": "rp2350", + "name": "RP2350", + "peripherals": { + "CLOCK": { + "sigmask": "{name}.+" + }, + "SPI[0-1]": { + "sigmask": "{name}.+" + }, + "UART0": { + "sigmask": "{name}.+", + "default": { + "TXD": [ + "UART0_TX", + 0 + ], + "RXD": [ + "UART0_RX", + 1 + ] + } + }, + "UART1": { + "sigmask": "{name}.+", + "default": { + "TXD": [ + "UART1_TX", + 4 + ], + "RXD": [ + "UART1_RX", + 5 + ] + } + }, + "I2C[0-1]": { + "sigmask": "{name}.+" + }, + "PIO[0-2]": { + "sigmask": "{name}.+" + }, + "PWM[0-9]": { + "sigmask": "{name}.+" + }, + "SIO": { + "sigmask": "{name}.+" + }, + "USB": { + "sigmask": "{name}.+" + }, + "HSTX": { + "sigmask": "{name}" + }, + "XIP": { + "sigmask": "{name}.+" + }, + "TRACE": { + "sigmask": "{name}.+" + } + } +} \ No newline at end of file diff --git a/Sming/Components/malloc_count/component.mk b/Sming/Components/malloc_count/component.mk index 5579848cd1..abc46923f8 100644 --- a/Sming/Components/malloc_count/component.mk +++ b/Sming/Components/malloc_count/component.mk @@ -21,7 +21,6 @@ MC_WRAP_FUNCS := \ strdup ifeq ($(SMING_ARCH),Esp8266) MC_WRAP_FUNCS += \ - realloc \ pvPortMalloc \ pvPortCalloc \ pvPortRealloc \ diff --git a/Sming/Components/malloc_count/malloc_count.cpp b/Sming/Components/malloc_count/malloc_count.cpp index d886933dee..5f50e85b0a 100644 --- a/Sming/Components/malloc_count/malloc_count.cpp +++ b/Sming/Components/malloc_count/malloc_count.cpp @@ -378,7 +378,7 @@ extern "C" void* WRAP(pvPortZalloc)(size_t) __attribute__((alias("mc_zalloc"))); extern "C" void* WRAP(pvPortZallocIram)(size_t) __attribute__((alias("mc_zalloc"))); extern "C" void WRAP(vPortFree)(void*) __attribute__((alias("mc_free"))); -#else +#elif !defined(ARCH_RP2040) void* operator new(size_t size) { diff --git a/Sming/Libraries/USB b/Sming/Libraries/USB index df65917eb6..0717652a30 160000 --- a/Sming/Libraries/USB +++ b/Sming/Libraries/USB @@ -1 +1 @@ -Subproject commit df65917eb6b796dbf1137f93ac0190d777403a7c +Subproject commit 0717652a3095a3091d5bb56ed683474b2d72f0bf diff --git a/Tools/ci/scanlog.py b/Tools/ci/scanlog.py index 73821602b8..bdd196320a 100644 --- a/Tools/ci/scanlog.py +++ b/Tools/ci/scanlog.py @@ -327,7 +327,6 @@ def get_args(cmd: str): def print_diff(log1: Log, log2: Log): for job1 in log1.jobs: - job_printed = False try: job2 = next(job for job in log2.jobs if job.name == job1.name) except StopIteration: @@ -364,9 +363,7 @@ def print_diff(log1: Log, log2: Log): data[name] = f'{v2-v1:+}' diff_table.append(data) - if not job_printed: - print(f'{job1.name}:') - job_printed = True + print(f'{job1.name}: {target}') print_table(diff_table) if table2.rows: diff --git a/samples/Basic_IFS/app/application.cpp b/samples/Basic_IFS/app/application.cpp index 7f8b01064f..8602249330 100644 --- a/samples/Basic_IFS/app/application.cpp +++ b/samples/Basic_IFS/app/application.cpp @@ -284,7 +284,7 @@ bool initFileSystem() for(auto part : unit.partitions()) { Serial << part << endl; } - auto part = *unit.partitions().begin(); + auto part = Storage::findDefaultPartition(Storage::Partition::SubType::Data::fat); auto fatfs = IFS::createFatFilesystem(part); if(fatfs && fatfs->mount() == FS_OK) { getFileSystem()->setVolume(3, fatfs); diff --git a/samples/Basic_IFS/basic_ifs_Rp2040.hw b/samples/Basic_IFS/basic_ifs_Rp2040.hw index 004bc45534..53b0f9bde0 100644 --- a/samples/Basic_IFS/basic_ifs_Rp2040.hw +++ b/samples/Basic_IFS/basic_ifs_Rp2040.hw @@ -8,7 +8,7 @@ ], "partitions": { "rom0": { - "size": "320K" + "size": "428K" }, "lfs1": { "size": "932K", From 4a691cf2d8a9b4dccda54bb7a9bb304da0ed64e8 Mon Sep 17 00:00:00 2001 From: slaff Date: Wed, 4 Dec 2024 11:56:57 +0100 Subject: [PATCH 28/34] Small changes related to Pi Pico text. (#2919) --- README.md | 2 +- Sming/Arch/Rp2040/README.rst | 4 ++-- docs/source/index.rst | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b35dca3b58..d97c030130 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Sming Sming is an asynchronous embedded C++ framework with superb performance and multiple network features. -Sming is [open source](LICENSE), modular and supports [multiple architectures](https://sming.readthedocs.io/en/latest/features.html) including ESP8266, ESP32 and RP2040. +Sming is [open source](LICENSE), modular and supports [multiple architectures](https://sming.readthedocs.io/en/latest/features.html) including ESP8266, ESP32 and Raspberry Pi Pico (both RP2040 and RP2350). [![Examples](https://github.com/SmingHub/Sming/wiki/images/small/combine.png)](https://github.com/SmingHub/Sming/wiki/examples) diff --git a/Sming/Arch/Rp2040/README.rst b/Sming/Arch/Rp2040/README.rst index de9dfe5a19..cf7fc1ae97 100644 --- a/Sming/Arch/Rp2040/README.rst +++ b/Sming/Arch/Rp2040/README.rst @@ -1,5 +1,5 @@ -Sming RP2040 Architecture -========================= +Sming Raspberry Pi Pico Architecture +==================================== .. highlight:: bash diff --git a/docs/source/index.rst b/docs/source/index.rst index 20ca4cb497..f9936d2f39 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -9,7 +9,7 @@ Sming is an asynchronous embedded C++ framework with superb performance and mult Sming is open source, modular and supports :doc:`multiple architectures `: :doc:`ESP8266 `, :doc:`ESP32 `, -:doc:`RP2040 `, +:doc:`Raspberry Pi Pico-series (both RP2040 and RP2350) `, and :doc:`Host Emulation `. |samples|_ From 3dc8cb0032e1490f3511ea3d180778efa7198540 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 12 Dec 2024 15:58:34 +0000 Subject: [PATCH 29/34] Increase default `main` task stack size to 16K (#2920) User's `init` function is called in main task. After initialisation this task is destroyed and Sming continues to run either in `tiT` task or `Sming` task, depending on whether networking is enabled. --- Sming/Arch/Esp32/Components/esp32/sdk/config/common | 1 + 1 file changed, 1 insertion(+) diff --git a/Sming/Arch/Esp32/Components/esp32/sdk/config/common b/Sming/Arch/Esp32/Components/esp32/sdk/config/common index 8e4c40ba18..6a20aa0afa 100644 --- a/Sming/Arch/Esp32/Components/esp32/sdk/config/common +++ b/Sming/Arch/Esp32/Components/esp32/sdk/config/common @@ -39,6 +39,7 @@ CONFIG_BT_NIMBLE_MESH=n CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=n # Mandatory Sming framework changes +CONFIG_ESP_MAIN_TASK_STACK_SIZE=16384 CONFIG_ESP_TASK_WDT_TIMEOUT_S=8 # Required by HardwareSPI library From c1d5b9dd20a0bb714d7110860c7b960b68fa9720 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 12 Dec 2024 16:21:29 +0000 Subject: [PATCH 30/34] vscode can't find esp32 debugger as `IDF_TOOLS_PATH` isn't defined (#2921) --- Tools/ide/common/sming.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Tools/ide/common/sming.py b/Tools/ide/common/sming.py index c86f48354b..ac666a0482 100644 --- a/Tools/ide/common/sming.py +++ b/Tools/ide/common/sming.py @@ -49,7 +49,6 @@ def subst_path(self, path, prefix=''): path = self.replace(path, 'SMING_HOME', prefix) path = self.replace(path, 'ESP_HOME', prefix) path = self.replace(path, 'IDF_PATH', prefix) - path = self.replace(path, 'IDF_TOOLS_PATH', prefix) return path def isWsl(self): From e21f8c764624e11e03d52e12cb62c4e8b9afcdc0 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 13 Dec 2024 08:46:19 +0000 Subject: [PATCH 31/34] Add `TaskStat::setOutput` (#2923) This PR supports switching the output of TaskStat at runtime. This allows monitoring of freeRTOS task usage for esp32 devices. Useful for switching output between standard serial and USB serial. --- .../Esp32/Services/Profiling/TaskStat.cpp | 23 +++++++++++-------- .../Esp8266/Services/Profiling/TaskStat.cpp | 4 ++-- .../Arch/Host/Services/Profiling/TaskStat.cpp | 4 ++-- .../Rp2040/Services/Profiling/TaskStat.cpp | 4 ++-- Sming/Services/Profiling/TaskStat.h | 10 +++++++- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/Sming/Arch/Esp32/Services/Profiling/TaskStat.cpp b/Sming/Arch/Esp32/Services/Profiling/TaskStat.cpp index ddc127cd17..7042e433e7 100644 --- a/Sming/Arch/Esp32/Services/Profiling/TaskStat.cpp +++ b/Sming/Arch/Esp32/Services/Profiling/TaskStat.cpp @@ -27,7 +27,7 @@ struct TaskStat::Info { #endif }; -TaskStat::TaskStat(Print& out) : out(out) +TaskStat::TaskStat(Print& out) : out(&out) { #if CONFIG_FREERTOS_USE_TRACE_FACILITY && CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS taskInfo = std::make_unique(2); @@ -38,13 +38,16 @@ TaskStat::~TaskStat() = default; bool TaskStat::update() { + if(!out) { + return false; + } #if CONFIG_FREERTOS_USE_TRACE_FACILITY && CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS // Get current task states auto& info = taskInfo[endIndex]; info.count = uxTaskGetSystemState(info.status, maxTasks, &info.runTime); if(info.count == 0) { - out.println(_F("[TaskStat] uxTaskGetSystemState returned 0")); + out->println(_F("[TaskStat] uxTaskGetSystemState returned 0")); return false; } @@ -79,7 +82,7 @@ bool TaskStat::update() // Calculate totalElapsedTime in units of run time stats clock period. uint32_t totalElapsedTime = endInfo.runTime - startInfo.runTime; if(totalElapsedTime == 0) { - out.println(_F("[TaskStat] Run time was 0: Have you set CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS?")); + out->println(_F("[TaskStat] Run time was 0: Have you set CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS?")); return false; } @@ -87,8 +90,8 @@ bool TaskStat::update() PSTR_ARRAY(hdrfmt, "# | Core | Prio | Handle | Run Time | % Time | Name"); PSTR_ARRAY(datfmt, "%-3u | %c | %4u | %08x | %8u | %3u%% | %s\r\n"); - out.println(); - out.println(hdrfmt); + out->println(); + out->println(hdrfmt); // Match each task in startInfo.status to those in the endInfo.status for(unsigned i = 0; i < startInfo.count; i++) { int k = -1; @@ -108,27 +111,27 @@ bool TaskStat::update() #if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID coreId = status.xCoreID; #endif - out.printf(datfmt, status.xTaskNumber, (coreId == CONFIG_FREERTOS_NO_AFFINITY) ? '-' : ('0' + coreId), - status.uxCurrentPriority, status.xHandle, taskElapsedTime, percentageTime, status.pcTaskName); + out->printf(datfmt, status.xTaskNumber, (coreId == CONFIG_FREERTOS_NO_AFFINITY) ? '-' : ('0' + coreId), + status.uxCurrentPriority, status.xHandle, taskElapsedTime, percentageTime, status.pcTaskName); } } // Print unmatched tasks for(unsigned i = 0; i < startInfo.count; i++) { if(!startMatched[i]) { - out.printf("Deleted: %s\r\n", startInfo.status[i].pcTaskName); + out->printf("Deleted: %s\r\n", startInfo.status[i].pcTaskName); } } for(unsigned i = 0; i < endInfo.count; i++) { if(!endMatched[i]) { - out.printf("Created: %s\r\n", endInfo.status[i].pcTaskName); + out->printf("Created: %s\r\n", endInfo.status[i].pcTaskName); } } return true; #else - out.println("[TaskStat] Tracing disabled"); + out->println("[TaskStat] Tracing disabled"); return false; #endif } diff --git a/Sming/Arch/Esp8266/Services/Profiling/TaskStat.cpp b/Sming/Arch/Esp8266/Services/Profiling/TaskStat.cpp index 80280f3547..1b226b3060 100644 --- a/Sming/Arch/Esp8266/Services/Profiling/TaskStat.cpp +++ b/Sming/Arch/Esp8266/Services/Profiling/TaskStat.cpp @@ -15,7 +15,7 @@ namespace Profiling struct TaskStat::Info { }; -TaskStat::TaskStat(Print& out) : out(out) +TaskStat::TaskStat(Print& out) : out(&out) { } @@ -23,7 +23,7 @@ TaskStat::~TaskStat() = default; bool TaskStat::update() { - out.println("[TaskStat] Not Implemented"); + out->println("[TaskStat] Not Implemented"); return false; } diff --git a/Sming/Arch/Host/Services/Profiling/TaskStat.cpp b/Sming/Arch/Host/Services/Profiling/TaskStat.cpp index 80280f3547..1b226b3060 100644 --- a/Sming/Arch/Host/Services/Profiling/TaskStat.cpp +++ b/Sming/Arch/Host/Services/Profiling/TaskStat.cpp @@ -15,7 +15,7 @@ namespace Profiling struct TaskStat::Info { }; -TaskStat::TaskStat(Print& out) : out(out) +TaskStat::TaskStat(Print& out) : out(&out) { } @@ -23,7 +23,7 @@ TaskStat::~TaskStat() = default; bool TaskStat::update() { - out.println("[TaskStat] Not Implemented"); + out->println("[TaskStat] Not Implemented"); return false; } diff --git a/Sming/Arch/Rp2040/Services/Profiling/TaskStat.cpp b/Sming/Arch/Rp2040/Services/Profiling/TaskStat.cpp index 80280f3547..1b226b3060 100644 --- a/Sming/Arch/Rp2040/Services/Profiling/TaskStat.cpp +++ b/Sming/Arch/Rp2040/Services/Profiling/TaskStat.cpp @@ -15,7 +15,7 @@ namespace Profiling struct TaskStat::Info { }; -TaskStat::TaskStat(Print& out) : out(out) +TaskStat::TaskStat(Print& out) : out(&out) { } @@ -23,7 +23,7 @@ TaskStat::~TaskStat() = default; bool TaskStat::update() { - out.println("[TaskStat] Not Implemented"); + out->println("[TaskStat] Not Implemented"); return false; } diff --git a/Sming/Services/Profiling/TaskStat.h b/Sming/Services/Profiling/TaskStat.h index 141435bf27..f0fe609671 100644 --- a/Sming/Services/Profiling/TaskStat.h +++ b/Sming/Services/Profiling/TaskStat.h @@ -47,8 +47,16 @@ class TaskStat */ bool update(); + /** + * @brief Change the output stream + */ + void setOutput(Print& out) + { + this->out = &out; + } + private: - Print& out; + Print* out; static constexpr size_t maxTasks{32}; struct Info; std::unique_ptr taskInfo; From 75ddc8f360075ad558b6c3b8948ce18fdef854d2 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 13 Dec 2024 08:47:25 +0000 Subject: [PATCH 32/34] Add USB host support for esp32s2(s3), support OTG dual-mode (#2922) This PR updates the USB library to enable Host support for esp32s2 and s3 (untested). This is by switching ot the synopsis DWC2 driver. The basic CDC, HID and MSC interfaces work OK but isochronous are transfers not yet supported. (I'd like this for attaching a USB DAC.) In addition, the OTG hardware (for rp2040 and esp32s2) supports dual-mode operation and this PR allows the operation mode to be selected at run time. The application still needs to decide which mode is required: this can be as simple as connecting a GPIO input to the ID pin. Mode switching between two OTG hosts is more complex and involves session negotiation support which hasn't been investigated yet. **Disconnection events** The esp32s2 doesn't report when devices are disconnected in host mode. There's an open issue for this in tinyusb https://github.com/hathach/tinyusb/issues/564. There's a reference to the IDF regarding [self-powered devices](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/peripherals/usb_device.html#self-powered-device) which states that a separate GPIO is required to sense VBUS for disconnect events. A quick look at the IDF usb code suggests that it handles this using polling and a debounce timer. However, there is a separate disconnect interrupt which requires only a few lines of code to enable and seems to work reliably. Doubtless there will be further host improvements in the future but this is pretty functional as-is. --- .../Arch/Esp32/Components/driver/include/driver/hw_timer.h | 3 +++ Sming/Arch/Esp32/Components/esp32/component.mk | 7 ++++++- Sming/Libraries/USB | 2 +- samples/Basic_IFS/app/application.cpp | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h b/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h index 1979b45072..623bc5de29 100644 --- a/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h +++ b/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h @@ -15,11 +15,14 @@ #include #include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" #if CONFIG_ESP_TIMER_IMPL_TG0_LAC #include #else #include #endif +#pragma GCC diagnostic pop #ifdef __cplusplus extern "C" { diff --git a/Sming/Arch/Esp32/Components/esp32/component.mk b/Sming/Arch/Esp32/Components/esp32/component.mk index eaf4804398..66ed206cba 100644 --- a/Sming/Arch/Esp32/Components/esp32/component.mk +++ b/Sming/Arch/Esp32/Components/esp32/component.mk @@ -117,7 +117,8 @@ SDK_INCDIRS := \ esp_netif/include \ esp_eth/include \ esp_wifi/include \ - lwip/include/apps/sntp + lwip/include/apps/sntp \ + usb/include ifdef IDF_VERSION_4x SDK_INCDIRS += \ @@ -262,6 +263,10 @@ SDK_COMPONENTS := \ soc \ spi_flash +ifneq (,$(filter esp32s2 esp32s3,$(SMING_SOC))) +SDK_COMPONENTS += usb +endif + ifdef IDF_VERSION_43 SDK_COMPONENTS += $(ESP_VARIANT) else diff --git a/Sming/Libraries/USB b/Sming/Libraries/USB index 0717652a30..6af107fbe2 160000 --- a/Sming/Libraries/USB +++ b/Sming/Libraries/USB @@ -1 +1 @@ -Subproject commit 0717652a3095a3091d5bb56ed683474b2d72f0bf +Subproject commit 6af107fbe25f7a8cb154ccea6ce9fb69e34dc60b diff --git a/samples/Basic_IFS/app/application.cpp b/samples/Basic_IFS/app/application.cpp index 8602249330..acaf936a8f 100644 --- a/samples/Basic_IFS/app/application.cpp +++ b/samples/Basic_IFS/app/application.cpp @@ -246,7 +246,7 @@ bool initFileSystem() #endif #ifdef ENABLE_USB_STORAGE - USB::begin(); + USB::begin(true); USB::MSC::onMount([](auto inst) { usbStorage.begin(inst); usbStorage.enumerate([](auto& unit, const USB::MSC::Inquiry& inquiry) { From 6ce7268d54ff7a8399356a67808f6038ac326659 Mon Sep 17 00:00:00 2001 From: slaff Date: Thu, 19 Dec 2024 10:30:29 +0100 Subject: [PATCH 33/34] Don't overwrite the message variable. (#2924) --- samples/HttpServer_WebSockets/app/application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/HttpServer_WebSockets/app/application.cpp b/samples/HttpServer_WebSockets/app/application.cpp index 2d0a059c4c..056973520c 100644 --- a/samples/HttpServer_WebSockets/app/application.cpp +++ b/samples/HttpServer_WebSockets/app/application.cpp @@ -66,8 +66,8 @@ void wsMessageReceived(WebsocketConnection& socket, const String& message) Serial.println(message); if(message == _F("shutdown")) { - String message(F("The server is shutting down...")); - socket.broadcast(message); + String reply(F("The server is shutting down...")); + socket.broadcast(reply); shutdownServer(); return; } From e31ee0bffbff00a74e2807c63a2da3c3e9206f23 Mon Sep 17 00:00:00 2001 From: slaff Date: Fri, 27 Dec 2024 07:34:03 +0100 Subject: [PATCH 34/34] Preparation for v6.0.0 release. (#2925) --- README.md | 4 ++-- Sming/Core/SmingVersion.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d97c030130..0c78eb68fa 100644 --- a/README.md +++ b/README.md @@ -29,14 +29,14 @@ You can also try Sming without installing anything locally. We have an [interact The purpose of Sming is to simplify the creation of embedded applications. The documentation will help you get started in no time. -- [**Documentation for version 5.2.0**](https://sming.readthedocs.io/en/stable) - current stable version. +- [**Documentation for version 6.0.0**](https://sming.readthedocs.io/en/stable) - current stable version. - [Documentation for latest](https://sming.readthedocs.io/en/latest) - development version. ## Releases ### Stable -- [Sming V5.2.0](https://github.com/SmingHub/Sming/releases/tag/5.2.0) - great new features, performance and stability improvements. +- [Sming V6.0.0](https://github.com/SmingHub/Sming/releases/tag/6.0.0) - great new features, performance and stability improvements. ### Development diff --git a/Sming/Core/SmingVersion.h b/Sming/Core/SmingVersion.h index 6e6ad945c4..802c1a3e1d 100644 --- a/Sming/Core/SmingVersion.h +++ b/Sming/Core/SmingVersion.h @@ -5,8 +5,8 @@ * */ -#define SMING_MAJOR_VERSION 5 -#define SMING_MINOR_VERSION 2 +#define SMING_MAJOR_VERSION 6 +#define SMING_MINOR_VERSION 0 #define SMING_PATCH_VERSION 0 #define SMING_PRE_RELEASE ""