From c6ce44ffcd86a94b812cea049716b109f8c0dbc0 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 11 Sep 2023 11:28:12 +0700 Subject: [PATCH] Fix network and SSL client issues. --- README.md | 65 +- .../{EthernetClient.ino => ESP32/ESP32.ino} | 88 +- .../EthernetClient/ESP8266/ESP8266.ino | 170 +++ .../ESP32_SIMA7670.ino} | 0 .../ESP6266_SIMA7600/ESP8266_SIMA7600.ino | 206 ++++ .../WiFiClient.ino => Generic/Generic.ino} | 77 +- keywords.txt | 2 + library.json | 2 +- library.properties | 2 +- src/ESP_Mail_Client.cpp | 2 +- src/ESP_Mail_Client.h | 26 +- src/ESP_Mail_Client_Version.h | 4 +- src/ESP_Mail_Const.h | 36 +- src/ESP_Mail_Error.h | 2 +- src/ESP_Mail_FS.h | 2 +- src/ESP_Mail_IMAP.h | 9 +- src/ESP_Mail_SMTP.h | 7 +- src/ESP_Mail_TCPClient.h | 140 ++- src/README.md | 33 + src/SSLClient/Custom_ESP_SSLClient_FS.h | 8 - src/SSLClient/ESP_SSLClient.h | 4 +- src/SSLClient/ESP_SSLClient_FS.h | 2 +- src/SSLClient/client/BSSL_SSL_Client.cpp | 4 +- src/SSLClient/client/BSSL_SSL_Client.h | 10 +- src/extras/Build_Options.h | 2 +- src/extras/ESP8266_Supports.h | 52 - src/extras/MB_Time.h | 12 +- .../{Networks_Provider.h => Networks.h} | 107 +- src/extras/RFC2047.cpp | 2 +- src/extras/RFC2047.h | 8 +- src/extras/mb_print/mb_print.c | 1048 ----------------- src/extras/mb_print/mb_print.h | 108 -- 32 files changed, 751 insertions(+), 1489 deletions(-) rename examples/SMTP/External_Client/EthernetClient/{EthernetClient.ino => ESP32/ESP32.ino} (68%) create mode 100644 examples/SMTP/External_Client/EthernetClient/ESP8266/ESP8266.ino rename examples/SMTP/External_Client/GSMClient/{GSMClient.ino => ESP32_SIMA7670/ESP32_SIMA7670.ino} (100%) create mode 100644 examples/SMTP/External_Client/GSMClient/ESP6266_SIMA7600/ESP8266_SIMA7600.ino rename examples/SMTP/External_Client/{WiFiClient/WiFiClient.ino => Generic/Generic.ino} (64%) delete mode 100644 src/extras/ESP8266_Supports.h rename src/extras/{Networks_Provider.h => Networks.h} (70%) delete mode 100644 src/extras/mb_print/mb_print.c delete mode 100644 src/extras/mb_print/mb_print.h diff --git a/README.md b/README.md index 79d584f9..d141e4ac 100644 --- a/README.md +++ b/README.md @@ -755,9 +755,9 @@ This library supports external netwoking devices e.g. WiFi modules, Ethernet mod Since v3.4.0, the Arduino Clients can be used with this library without additional external SSL Client required. -No additional setup needed, only pass the Arduino Client to the function `setClient` or pass the TinyGSMClient and TinyGSM modem to the function `setGSMClient`. +No additional setup needed, only pass the Arduino Client to the function `setClient` or pass the TinyGSMClient and TinyGSM modem to the function `setGSMClient` or pass the Ethernet client and mac address to the function `setEthernetClient`. -Two callback functions required (except for using `setGSMClient`) for network connection (with disconnection) and sending connecting status back to the Mail Client. +Two callback functions are required (except for `setGSMClient` and `setEthernetClient`) for network connection (with disconnection) and sending connecting status back to the Mail Client. If device has on-board WiFi and supports native (SDK) Ethernet, these two native networks will be auto detectd and used. @@ -982,68 +982,18 @@ The below example will use ESP32 and W5500 and Ethernet client library to connec #define WIZNET_SCLK_PIN 18 // Connect W5500 SCLK pin to GPIO 18 of ESP32 -EthernetClient eth_client; - uint8_t Eth_MAC[] = {0x02, 0xF0, 0x0D, 0xBE, 0xEF, 0x01}; -SMTPSession smtp; +SMTPSession smtp; -Session_Config config; +EthernetClient eth_client; -// Callback function to get the Email sending status void smtpCallback(SMTP_Status status); -void ResetEthernet() -{ - Serial.println("Resetting WIZnet W5500 Ethernet Board... "); - pinMode(WIZNET_RESET_PIN, OUTPUT); - digitalWrite(WIZNET_RESET_PIN, HIGH); - delay(200); - digitalWrite(WIZNET_RESET_PIN, LOW); - delay(50); - digitalWrite(WIZNET_RESET_PIN, HIGH); - delay(200); -} - -void networkConnection() -{ - - Ethernet.init(WIZNET_CS_PIN); - - ResetEthernet(); - - Serial.println("Starting Ethernet connection..."); - Ethernet.begin(Eth_MAC); - - unsigned long to = millis(); - - while (Ethernet.linkStatus() == LinkOFF || millis() - to < 2000) - { - delay(100); - } - - if (Ethernet.linkStatus() == LinkON) - { - Serial.print("Connected with IP "); - Serial.println(Ethernet.localIP()); - } - else - { - Serial.println("Can't connect"); - } -} - -void networkStatusRequestCallback() -{ - smtp.setNetworkStatus(Ethernet.linkStatus() == LinkON); -} - void setup() { Serial.begin(115200); - networkConnection(); - config.server.host_name = "smtp.gmail.com"; //for gmail.com config.server.port = 587; // requires connection upgrade via STARTTLS config.login.email = "your Email address"; //set to empty for no SMTP Authentication @@ -1066,12 +1016,7 @@ void setup() // Set the message content message.text.content = "This is simple plain text message"; - // Set the callback function for connection upgrade - smtp.networkStatusRequestCallback(networkStatusRequestCallback); - - smtp.networkConnectionRequestCallback(networkConnection); - - smtp.setClient(ð_client); + smtp.setEthernetClient(ð_client, Eth_MAC, WIZNET_CS_PIN, WIZNET_RESET_PIN); // Set debug option smtp.debug(1); diff --git a/examples/SMTP/External_Client/EthernetClient/EthernetClient.ino b/examples/SMTP/External_Client/EthernetClient/ESP32/ESP32.ino similarity index 68% rename from examples/SMTP/External_Client/EthernetClient/EthernetClient.ino rename to examples/SMTP/External_Client/EthernetClient/ESP32/ESP32.ino index ec9fd07e..ac26ef38 100644 --- a/examples/SMTP/External_Client/EthernetClient/EthernetClient.ino +++ b/examples/SMTP/External_Client/EthernetClient/ESP32/ESP32.ino @@ -6,28 +6,22 @@ * Github: https://github.com/mobizt/ESP-Mail-Client * * Copyright (c) 2023 mobizt -*/ + */ /** * This example shows how to send Email using EthernetClient. * * This example used ESP32 and WIZnet W5500 Ethernet module. * - * For ESP32 and LAN8720 see examples/SMTP/Ethernet/ESP32/Send_Text.ino - * - * ESP32 Arduino SDK native Ethernet using ETH.h is currently support Ethernet PHY chips - * + * For ESP32 and LAN8720 see examples/SMTP/Ethernet/ESP32/Send_Text.ino. + * + * ESP32 Arduino SDK native Ethernet using ETH.h is currently support Ethernet PHY chips included the following * LAN8720, TLK101, RTL8201, DP83848, DM9051, KSZ8041 and KSZ8081. - * - * For ESP8266, the native Ethernet is currently supported ENC28J60, W5100 and W5500. - * - * You do not need to set external Client with native Ethernet support PHY/MAC chips. - * * */ /** Note for library update from v2.x.x to v3.x.x. - * + * * Struct data names changed * * "ESP_Mail_Session" changes to "Session_Config" @@ -69,57 +63,21 @@ const int analog_pin = 34; uint8_t Eth_MAC[] = {0x02, 0xF0, 0x0D, 0xBE, 0xEF, 0x01}; +/** +IPAddress localIP(192, 168, 1, 104); +IPAddress subnet(255, 255, 0, 0); +IPAddress gateway(192, 168, 1, 1); +IPAddress dnsServer(8, 8, 8, 8); +bool optional = false; // Use this static IP only no DHCP +ESP_Mail_StaticIP staIP(localIP, subnet, gateway, dnsServer, optional); +*/ + SMTPSession smtp; EthernetClient eth_client; void smtpCallback(SMTP_Status status); -void ResetEthernet() -{ - Serial.println("Resetting WIZnet W5500 Ethernet Board... "); - pinMode(WIZNET_RESET_PIN, OUTPUT); - digitalWrite(WIZNET_RESET_PIN, HIGH); - delay(200); - digitalWrite(WIZNET_RESET_PIN, LOW); - delay(50); - digitalWrite(WIZNET_RESET_PIN, HIGH); - delay(200); -} - -void networkConnection() -{ - - Ethernet.init(WIZNET_CS_PIN); - - ResetEthernet(); - - Serial.println("Starting Ethernet connection..."); - Ethernet.begin(Eth_MAC); - - unsigned long to = millis(); - - while (Ethernet.linkStatus() == LinkOFF || millis() - to < 2000) - { - delay(100); - } - - if (Ethernet.linkStatus() == LinkON) - { - Serial.print("Connected with IP "); - Serial.println(Ethernet.localIP()); - } - else - { - Serial.println("Can't connect"); - } -} - -void networkStatusRequestCallback() -{ - smtp.setNetworkStatus(Ethernet.linkStatus() == LinkON); -} - void sendEmail() { @@ -142,11 +100,8 @@ void sendEmail() message.text.content = "This is simple plain text message"; - smtp.setClient(ð_client); - - smtp.networkConnectionRequestCallback(networkConnection); - - smtp.networkStatusRequestCallback(networkStatusRequestCallback); + /* Assign the pointer to global defined Ethernet Client object */ + smtp.setEthernetClient(ð_client, Eth_MAC, WIZNET_CS_PIN, WIZNET_RESET_PIN); // The staIP can be assigned to the fifth param if (!smtp.connect(&config)) { @@ -172,17 +127,6 @@ void setup() Serial.println(); - networkConnection(); - - /* - For internal NTP client - For times east of the Prime Meridian use 0-12 - For times west of the Prime Meridian add 12 to the offset. - Ex. American/Denver GMT would be -6. 6 + 12 = 18 - See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets - */ - MailClient.setUDPClient(&udp_client, 0 /* GMT offset */); - smtp.debug(1); smtp.callback(smtpCallback); diff --git a/examples/SMTP/External_Client/EthernetClient/ESP8266/ESP8266.ino b/examples/SMTP/External_Client/EthernetClient/ESP8266/ESP8266.ino new file mode 100644 index 00000000..90bb4624 --- /dev/null +++ b/examples/SMTP/External_Client/EthernetClient/ESP8266/ESP8266.ino @@ -0,0 +1,170 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt + */ + +/** + * This example shows how to send Email using EthernetClient. + * + * This example used ESP8266 and WIZnet W5500 Ethernet module. + * + * For ESP8266 native Ethernet usage without external Ethernet client required, see examples/SMTP/Ethernet/ESP8266/Send_Text.ino. + * + * To use external Ethernet client with ESP8266 as in this example, the following macro in src/Custom_ESP_Mail_FS.h or build flag + * should be assigned to disable the native internet inclusion that conflicts with Ethernet.h + * + * ESP_MAIL_DISABLE_NATIVE_ETHERNET + * + */ + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include + +#include + +#include + +#define SMTP_HOST "smtp.gmail.com" +#define SMTP_PORT 587 + +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" +#define RECIPIENT_EMAIL "" + +#define WIZNET_RESET_PIN 5 // Connect W5500 Reset pin to GPIO 5 (D1) of ESP8266 (-1 for no reset pin assigned) +#define WIZNET_CS_PIN 4 // Connect W5500 CS pin to GPIO 4 (D2) of ESP8266 +#define WIZNET_MISO_PIN 12 // Connect W5500 MISO pin to GPIO 12 (D6) of ESP8266 +#define WIZNET_MOSI_PIN 13 // Connect W5500 MOSI pin to GPIO 13 (D7) of ESP8266 +#define WIZNET_SCLK_PIN 14 // Connect W5500 SCLK pin to GPIO 14 (D5) of ESP8266 + +unsigned long sentMillis = 0; + +const int analog_pin = 34; + +uint8_t Eth_MAC[] = {0x02, 0xF0, 0x0D, 0xBE, 0xEF, 0x01}; + +/** +IPAddress localIP(192, 168, 1, 104); +IPAddress subnet(255, 255, 0, 0); +IPAddress gateway(192, 168, 1, 1); +IPAddress dnsServer(8, 8, 8, 8); +bool optional = false; // Use this static IP only no DHCP +ESP_Mail_StaticIP staIP(localIP, subnet, gateway, dnsServer, optional); +*/ + +SMTPSession smtp; + +EthernetClient eth_client; + +void smtpCallback(SMTP_Status status); + +void sendEmail() +{ + + Session_Config config; + + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + config.login.user_domain = F("127.0.0.1"); + + SMTP_Message message; + + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending plain text Email"); + + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + message.text.content = "This is simple plain text message"; + + /* Assign the pointer to global defined Ethernet Client object */ + smtp.setEthernetClient(ð_client, Eth_MAC, WIZNET_CS_PIN, WIZNET_RESET_PIN); // The staIP can be assigned to the fifth param + + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void setup() +{ + + Serial.begin(115200); + + Serial.println(); + + smtp.debug(1); + + smtp.callback(smtpCallback); +} + +void loop() +{ + if (millis() - sentMillis > 120000 || sentMillis == 0) + { + sentMillis = millis(); + sendEmail(); + } +} + +void smtpCallback(SMTP_Status status) +{ + Serial.println(status.info()); + + if (status.success()) + { + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + SMTP_Result result = smtp.sendingResult.getItem(i); + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/examples/SMTP/External_Client/GSMClient/GSMClient.ino b/examples/SMTP/External_Client/GSMClient/ESP32_SIMA7670/ESP32_SIMA7670.ino similarity index 100% rename from examples/SMTP/External_Client/GSMClient/GSMClient.ino rename to examples/SMTP/External_Client/GSMClient/ESP32_SIMA7670/ESP32_SIMA7670.ino diff --git a/examples/SMTP/External_Client/GSMClient/ESP6266_SIMA7600/ESP8266_SIMA7600.ino b/examples/SMTP/External_Client/GSMClient/ESP6266_SIMA7600/ESP8266_SIMA7600.ino new file mode 100644 index 00000000..0a8a65a9 --- /dev/null +++ b/examples/SMTP/External_Client/GSMClient/ESP6266_SIMA7600/ESP8266_SIMA7600.ino @@ -0,0 +1,206 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt + */ + +// This example used SIM7600x, ESP8266 and TinyGSMClient. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +// To allow TinyGSM library integration, the following macro should be defined in src/ESP_Mail_FS.h or +// your custom config file src/Custom_ESP_Mail_FS.h. +// #define TINY_GSM_MODEM_SIM7600 + + +#include + +#define ESP8266_RX_PIN 14 //ESP8266 GPIO 14 connected to SIM7600 Pin 71 (TX) +#define ESP8266_TX_PIN 12 //ESP8266 GPIO 12 connected to SIM7600 Pin 68 (RX) +#define ESP8266_PWR_PIN 5 //ESP8266 GPIO 5 connected to SIM7600 Pin 3 (PWRKEY) +#define ESP8266_RESET 4 //ESP8266 GPIO 4 connected to SIM7600 Pin 4 (RESET) +#define UART_BAUD 115200 + +SoftwareSerial softSerial; + +#define TINY_GSM_MODEM_SIM7600 + +// Set serial for debug console (to the Serial Monitor, default speed 115200) +#define SerialMon Serial + +// Set serial for AT commands (to the module) +#define SerialAT softSerial + + +// See all AT commands, if wanted +// #define DUMP_AT_COMMANDS + +// Define the serial console for debug prints, if needed +#define TINY_GSM_DEBUG SerialMon + +#define TINY_GSM_USE_GPRS true +#define TINY_GSM_USE_WIFI false + +// set GSM PIN, if any +#define GSM_PIN "" + +// Your GPRS credentials, if any +const char apn[] = "YourAPN"; +const char gprsUser[] = ""; +const char gprsPass[] = ""; + + +#include +#include + +TinyGsm modem(SerialAT); + +TinyGsmClient gsm_client(modem); + +#define SMTP_HOST "" +#define SMTP_PORT esp_mail_smtp_port_587 +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" +#define RECIPIENT_EMAIL "" + +SMTPSession smtp; + +void smtpCallback(SMTP_Status status); + +void setup() +{ + + SerialMon.begin(115200); + + smtp.debug(1); + + smtp.callback(smtpCallback); + + delay(10); + pinMode(BAT_EN, OUTPUT); + digitalWrite(BAT_EN, HIGH); + + // A7670 Reset + pinMode(RESET, OUTPUT); + digitalWrite(RESET, LOW); + delay(100); + digitalWrite(RESET, HIGH); + delay(3000); + digitalWrite(RESET, LOW); + + pinMode(PWR_PIN, OUTPUT); + digitalWrite(PWR_PIN, LOW); + delay(100); + digitalWrite(PWR_PIN, HIGH); + delay(1000); + digitalWrite(PWR_PIN, LOW); + + DBG("Wait..."); + + delay(3000); + + SerialAT.begin(UART_BAUD, SERIAL_8N1, ESP8266_RX_PIN, ESP8266_TX_PIN); + + // Restart takes quite some time + // To skip it, call init() instead of restart() + DBG("Initializing modem..."); + if (!modem.init()) + { + DBG("Failed to restart modem, delaying 10s and retrying"); + return; + } + + /* + 2 Automatic + 13 GSM Only + 14 WCDMA Only + 38 LTE Only + */ + modem.setNetworkMode(38); + if (modem.waitResponse(10000L) != 1) + { + DBG(" setNetworkMode faill"); + } + + String name = modem.getModemName(); + DBG("Modem Name:", name); + + String modemInfo = modem.getModemInfo(); + DBG("Modem Info:", modemInfo); + + Session_Config config; + + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + config.login.user_domain = F("127.0.0.1"); + + SMTP_Message message; + + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending plain text Email using GSM module"); + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + message.text.content = "This is simple plain text message"; + + smtp.setGSMClient(&gsm_client, &modem, GSM_PIN, apn, gprsUser, gprsPass); + + smtp.connect(&config); + + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); +} + +void loop() +{ +} + +void smtpCallback(SMTP_Status status) +{ + Serial.println(status.info()); + + if (status.success()) + { + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + SMTP_Result result = smtp.sendingResult.getItem(i); + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/examples/SMTP/External_Client/WiFiClient/WiFiClient.ino b/examples/SMTP/External_Client/Generic/Generic.ino similarity index 64% rename from examples/SMTP/External_Client/WiFiClient/WiFiClient.ino rename to examples/SMTP/External_Client/Generic/Generic.ino index 6e80e110..7fa29d26 100644 --- a/examples/SMTP/External_Client/WiFiClient/WiFiClient.ino +++ b/examples/SMTP/External_Client/Generic/Generic.ino @@ -9,7 +9,7 @@ * Copyright (c) 2023 mobizt */ -// This example shows how to send Email using external WiFiClient. +// This example shows how to send Email with external network Client. /** Note for library update from v2.x.x to v3.x.x. * @@ -30,23 +30,8 @@ */ #include -#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) -#include -#elif defined(ESP8266) -#include -#elif __has_include() -#include -#elif __has_include() -#include -#elif __has_include() -#include -#endif - #include -#define WIFI_SSID "" -#define WIFI_PASSWORD "" - #define SMTP_HOST "" #define SMTP_PORT esp_mail_smtp_port_587 #define AUTHOR_EMAIL "" @@ -55,65 +40,33 @@ SMTPSession smtp; -WiFiClient wifi_client; - -#if defined(ARDUINO_RASPBERRY_PI_PICO_W) -WiFiMulti multi; -#endif +// Your network client class object e.g. WiFiClient, EthernetClient and GSMClient +NetworkClient net_client; -void smtpCallback(SMTP_Status status); - -void networkStatusRequestCallback() +void networkConnection() { - smtp.setNetworkStatus(WiFi.status() == WL_CONNECTED); + // Neywork connection code here } -void networkConnectionRequestCallback() +// Define the callback function to handle server status acknowledgement +void networkStatusRequestCallback() { - Serial.println(); - -#if defined(ARDUINO_RASPBERRY_PI_PICO_W) - multi.addAP(WIFI_SSID, WIFI_PASSWORD); - multi.run(); -#else - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); -#endif - - Serial.print("Connecting to Wi-Fi"); - -#if defined(ARDUINO_RASPBERRY_PI_PICO_W) - unsigned long ms = millis(); -#endif - - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(300); -#if defined(ARDUINO_RASPBERRY_PI_PICO_W) - if (millis() - ms > 10000) - break; -#endif - } - Serial.println(); - Serial.print("Connected with IP: "); - Serial.println(WiFi.localIP()); - Serial.println(); + // Set the network status based on your network client + fbdo.setNetworkStatus(true /* or false */); } +void smtpCallback(SMTP_Status status); + + void setup() { Serial.begin(115200); - networkConnectionRequestCallback(); + networkConnection(); MailClient.networkReconnect(true); -#if defined(ARDUINO_RASPBERRY_PI_PICO_W) - MailClient.clearAP(); - MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); -#endif - smtp.debug(1); smtp.callback(smtpCallback); @@ -128,11 +81,11 @@ void setup() config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); - smtp.setClient(&wifi_client); + smtp.setClient(&net_client); smtp.networkStatusRequestCallback(networkStatusRequestCallback); - smtp.networkConnectionRequestCallback(networkConnectionRequestCallback); + smtp.networkConnectionRequestCallback(networkConnection); smtp.connect(&config); diff --git a/keywords.txt b/keywords.txt index 86c05804..b191147a 100644 --- a/keywords.txt +++ b/keywords.txt @@ -25,6 +25,7 @@ SMTP_Result KEYWORD1 IMAP_MSG_Item KEYWORD1 Content_Transfer_Encoding KEYWORD1 MessageList KEYWORD1 +ESP_Mail_StaticIP KEYWORD1 ############################################### # Methods and Functions (KEYWORD2) @@ -142,6 +143,7 @@ getUID KEYWORD2 setTCPTimeout KEYWORD2 setClient KEYWORD2 setGSMClient KEYWORD2 +setEthernetClient KEYWORD2 connectionRequestCallback KEYWORD2 connectionUpgradeRequestCallback KEYWORD2 networkConnectionRequestCallback KEYWORD2 diff --git a/library.json b/library.json index 6f195398..cb62f82e 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "ESP Mail Client", - "version": "3.4.9", + "version": "3.4.10", "keywords": "communication, email, imap, smtp, esp32, esp8266, samd, arduino", "description": "Arduino E-Mail Client Library to send, read and get incoming email notification for ESP32, ESP8266 and SAMD21 devices. The library also supported other Arduino Devices using Clients interfaces e.g. WiFiClient, EthernetClient, and GSMClient.", "repository": { diff --git a/library.properties b/library.properties index 80b2d2c7..e50094db 100644 --- a/library.properties +++ b/library.properties @@ -1,6 +1,6 @@ name=ESP Mail Client -version=3.4.9 +version=3.4.10 author=Mobizt diff --git a/src/ESP_Mail_Client.cpp b/src/ESP_Mail_Client.cpp index 4c58543a..caaf1a17 100644 --- a/src/ESP_Mail_Client.cpp +++ b/src/ESP_Mail_Client.cpp @@ -4,7 +4,7 @@ #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #include "ESP_Mail_Client_Version.h" -#if !VALID_VERSION_CHECK(30409) +#if !VALID_VERSION_CHECK(30410) #error "Mixed versions compilation." #endif diff --git a/src/ESP_Mail_Client.h b/src/ESP_Mail_Client.h index 69099a49..6734c14b 100644 --- a/src/ESP_Mail_Client.h +++ b/src/ESP_Mail_Client.h @@ -2,7 +2,7 @@ #define ESP_MAIL_CLIENT_H #include "ESP_Mail_Client_Version.h" -#if !VALID_VERSION_CHECK(30409) +#if !VALID_VERSION_CHECK(30410) #error "Mixed versions compilation." #endif @@ -733,7 +733,7 @@ class SMTP_Message /* The field that contains the parent's references (if any) and followed by the parent's message ID (if any) of the message to which this one is a reply */ MB_String references; - + /* The timestamp value to replace in text */ esp_mail_timestamp_value_t timestamp; @@ -1740,6 +1740,17 @@ class IMAPSession */ void setGSMClient(Client *client, void *modem, const char *pin, const char *apn, const char *user, const char *password); + /** Assign external Ethernet Client. + * + * @param client The pointer to Ethernet client object. + * @param macAddress The Ethernet MAC address. + * @param csPin The Ethernet module SPI chip select pin. + * @param resetPin The Ethernet module reset pin. + * @param staticIP (Optional) The pointer to ESP_Mail_StaticIP object which has these IPAddress in its constructor i.e. + * ipAddress, netMask, defaultGateway, dnsServer and optional. + */ + void setEthernetClient(Client *client, uint8_t macAddress[6], int csPin, int resetPin, ESP_Mail_StaticIP *staticIP = nullptr); + /** Assign the callback function to handle the network connection for custom Client. * * @param networkConnectionCB The function that handles the network connection. @@ -2583,6 +2594,17 @@ class SMTPSession */ void setGSMClient(Client *client, void *modem, const char *pin, const char *apn, const char *user, const char *password); + /** Assign external Ethernet Client. + * + * @param client The pointer to Ethernet client object. + * @param macAddress The Ethernet MAC address. + * @param csPin The Ethernet module SPI chip select pin. + * @param resetPin The Ethernet module reset pin. + * @param staticIP (Optional) The pointer to ESP_Mail_StaticIP object which has these IPAddress in its constructor i.e. + * ipAddress, netMask, defaultGateway, dnsServer and optional. + */ + void setEthernetClient(Client *client, uint8_t macAddress[6], int csPin, int resetPin, ESP_Mail_StaticIP *staticIP = nullptr); + /** Assign the callback function to handle the network connection for custom Client. * * @param networkConnectionCB The function that handles the network connection. diff --git a/src/ESP_Mail_Client_Version.h b/src/ESP_Mail_Client_Version.h index 21cd038f..cf30551e 100644 --- a/src/ESP_Mail_Client_Version.h +++ b/src/ESP_Mail_Client_Version.h @@ -3,8 +3,8 @@ #ifndef ESP_MAIL_VERSION -#define ESP_MAIL_VERSION "3.4.9" -#define ESP_MAIL_VERSION_NUM 30409 +#define ESP_MAIL_VERSION "3.4.10" +#define ESP_MAIL_VERSION_NUM 30410 /* The inconsistent file version checking to prevent mixed versions compilation. */ #define VALID_VERSION_CHECK(ver) (ver == ESP_MAIL_VERSION_NUM) diff --git a/src/ESP_Mail_Const.h b/src/ESP_Mail_Const.h index 195ab0b1..5fb57821 100644 --- a/src/ESP_Mail_Const.h +++ b/src/ESP_Mail_Const.h @@ -1,4 +1,4 @@ -// Created August 20, 2023 +// Created September 11, 2023 #pragma once @@ -6,7 +6,7 @@ #define ESP_MAIL_CONST_H #include "ESP_Mail_Client_Version.h" -#if !VALID_VERSION_CHECK(30409) +#if !VALID_VERSION_CHECK(30410) #error "Mixed versions compilation." #endif @@ -34,8 +34,7 @@ #define FPSTR #endif -#include "extras/Networks_Provider.h" -#include "extras/ESP8266_Supports.h" +#include "./extras/Networks.h" #if defined(ESP8266) #if __has_include() @@ -73,6 +72,28 @@ #endif +typedef struct esp_mail_client_static_address +{ + friend class ESP_Mail_TCPClient; + +public: + esp_mail_client_static_address(IPAddress ipAddress, IPAddress netMask, IPAddress defaultGateway, IPAddress dnsServer, bool optional) + { + this->ipAddress = ipAddress; + this->netMask = netMask; + this->defaultGateway = defaultGateway; + this->dnsServer = dnsServer; + this->optional = optional; + }; + +private: + IPAddress ipAddress; + IPAddress netMask; + IPAddress defaultGateway; + IPAddress dnsServer; + bool optional = false; +} ESP_Mail_StaticIP; + typedef enum { esp_mail_cert_type_undefined = -1, @@ -87,8 +108,9 @@ typedef enum { esp_mail_client_type_undefined, esp_mail_client_type_internal_basic_client, - esp_mail_client_type_external_basic_client, - esp_mail_client_type_external_gsm_client + esp_mail_client_type_external_generic_client, + esp_mail_client_type_external_gsm_client, + esp_mail_client_type_external_ethernet_client } esp_mail_client_type; @@ -837,7 +859,7 @@ struct esp_mail_smtp_command_t struct esp_mail_timestamp_value_t { - /* The time format of timestamp to inject into subject or content as using in strftime C++ function */ + /* The time format of timestamp to inject into subject or content as using in strftime C++ function */ MB_String format; /* The tag that will be replaced with current timestamp */ MB_String tag; diff --git a/src/ESP_Mail_Error.h b/src/ESP_Mail_Error.h index 172e7f8d..8eabffc0 100644 --- a/src/ESP_Mail_Error.h +++ b/src/ESP_Mail_Error.h @@ -7,7 +7,7 @@ #define ESP_MAIL_ERROR_H #include "ESP_Mail_Client_Version.h" -#if !VALID_VERSION_CHECK(30409) +#if !VALID_VERSION_CHECK(30410) #error "Mixed versions compilation." #endif diff --git a/src/ESP_Mail_FS.h b/src/ESP_Mail_FS.h index b9c9755d..913f5de8 100644 --- a/src/ESP_Mail_FS.h +++ b/src/ESP_Mail_FS.h @@ -6,7 +6,7 @@ #define ESP_MAIL_CONFIG_H #include "ESP_Mail_Client_Version.h" -#if !VALID_VERSION_CHECK(30409) +#if !VALID_VERSION_CHECK(30410) #error "Mixed versions compilation." #endif diff --git a/src/ESP_Mail_IMAP.h b/src/ESP_Mail_IMAP.h index ddfdbed0..c5cd924d 100644 --- a/src/ESP_Mail_IMAP.h +++ b/src/ESP_Mail_IMAP.h @@ -3,7 +3,7 @@ #define ESP_MAIL_IMAP_H #include "ESP_Mail_Client_Version.h" -#if !VALID_VERSION_CHECK(30409) +#if !VALID_VERSION_CHECK(30410) #error "Mixed versions compilation." #endif @@ -4887,7 +4887,7 @@ bool IMAPSession::connect(bool &ssl) unsigned long dataMs = millis(); while (client.connected() && client.available() == 0 && millis() - dataMs < 2000) { - yield_impl(); + yield_impl(); } int chunkBufSize = client.available(); @@ -4996,6 +4996,11 @@ void IMAPSession::setGSMClient(Client *client, void *modem, const char *pin, con this->client.setGSMClient(client, modem, pin, apn, user, password); } +void IMAPSession::setEthernetClient(Client *client, uint8_t macAddress[6], int csPin, int resetPin, ESP_Mail_StaticIP *staticIP) +{ + this->client.setEthernetClient(client, macAddress, csPin, resetPin, staticIP); +} + void IMAPSession::networkConnectionRequestCallback(NetworkConnectionRequestCallback networkConnectionCB) { this->client.networkConnectionRequestCallback(networkConnectionCB); diff --git a/src/ESP_Mail_SMTP.h b/src/ESP_Mail_SMTP.h index 8371e95c..bae26b2a 100644 --- a/src/ESP_Mail_SMTP.h +++ b/src/ESP_Mail_SMTP.h @@ -3,7 +3,7 @@ #define ESP_MAIL_SMTP_H #include "ESP_Mail_Client_Version.h" -#if !VALID_VERSION_CHECK(30409) +#if !VALID_VERSION_CHECK(30410) #error "Mixed versions compilation." #endif @@ -3571,6 +3571,11 @@ void SMTPSession::setGSMClient(Client *client, void *modem, const char *pin, con this->client.setGSMClient(client, modem, pin, apn, user, password); } +void SMTPSession::setEthernetClient(Client *client, uint8_t macAddress[6], int csPin, int resetPin, ESP_Mail_StaticIP *staticIP) +{ + this->client.setEthernetClient(client, macAddress, csPin, resetPin, staticIP); +} + void SMTPSession::networkConnectionRequestCallback(NetworkConnectionRequestCallback networkConnectionCB) { this->client.networkConnectionRequestCallback(networkConnectionCB); diff --git a/src/ESP_Mail_TCPClient.h b/src/ESP_Mail_TCPClient.h index 9302f6d4..d8961039 100644 --- a/src/ESP_Mail_TCPClient.h +++ b/src/ESP_Mail_TCPClient.h @@ -1,8 +1,8 @@ /** * - * The Network Upgradable Arduino Secure TCP Client Class, ESP_Mail_TCPClient.h v1.0.1 + * The Network Upgradable Arduino Secure TCP Client Class, ESP_Mail_TCPClient.h v1.0.2 * - * Created August 27, 2023 + * Created September 11, 2023 * * The MIT License (MIT) * Copyright (c) 2023 K. Suwatchai (Mobizt) @@ -30,7 +30,7 @@ #define ESP_MAIL_TCPCLIENT_H #include "ESP_Mail_Client_Version.h" -#if !VALID_VERSION_CHECK(30409) +#if !VALID_VERSION_CHECK(30410) #error "Mixed versions compilation." #endif @@ -87,7 +87,7 @@ class ESP_Mail_TCPClient { clear(); _basic_client = client; - _client_type = esp_mail_client_type_external_basic_client; + _client_type = esp_mail_client_type_external_generic_client; } /** Assign TinyGsm Clients. @@ -102,16 +102,35 @@ class ESP_Mail_TCPClient void setGSMClient(Client *client, void *modem = nullptr, const char *pin = nullptr, const char *apn = nullptr, const char *user = nullptr, const char *password = nullptr) { #if defined(ESP_MAIL_GSM_MODEM_IS_AVAILABLE) + _client_type = esp_mail_client_type_external_gsm_client; + _basic_client = client; + _modem = modem; _pin = pin; _apn = apn; _user = user; _password = password; - _modem = modem; - _client_type = esp_mail_client_type_external_gsm_client; - _basic_client = client; #endif } + /** Assign external Ethernet Client. + * + * @param client The pointer to Ethernet client object. + * @param macAddress The Ethernet MAC address. + * @param csPin The Ethernet module SPI chip select pin. + * @param resetPin The Ethernet module reset pin. + * @param staticIP (Optional) The pointer to ESP_Mail_StaticIP object which has these IPAddress in its constructor i.e. + * ipAddress, netMask, defaultGateway, dnsServer and optional. + */ + void setEthernetClient(Client *client, uint8_t macAddress[6], int csPin, int resetPin, ESP_Mail_StaticIP *staticIP = nullptr) + { + _client_type = esp_mail_client_type_external_ethernet_client; + _basic_client = client; + _ethernet_mac = macAddress; + _ethernet_cs_pin = csPin; + _ethernet_reset_pin = resetPin; + _static_ip = staticIP; + }; + /** * Set Root CA certificate to verify. * @param caCert The certificate. @@ -339,15 +358,23 @@ class ESP_Mail_TCPClient if (!_network_status) gprsConnect(); } - else if (WiFI_CONNECTED || ethLinkUp()) - _network_status = true; - else if (_client_type == esp_mail_client_type_external_basic_client) + else if (_client_type == esp_mail_client_type_external_ethernet_client) + { + if (!ethernetConnected()) + ethernetConnect(); + } + // also check the native network before calling external cb + else if (_client_type == esp_mail_client_type_internal_basic_client || WiFI_CONNECTED || ethLinkUp()) + _network_status = WiFI_CONNECTED || ethLinkUp(); + else if (_client_type == esp_mail_client_type_external_generic_client) { if (!_network_status_cb) _last_error = 1; else _network_status_cb(); } + else + _network_status = false; return _network_status; } @@ -358,7 +385,7 @@ class ESP_Mail_TCPClient void networkReconnect() { - if (_client_type == esp_mail_client_type_external_basic_client) + if (_client_type == esp_mail_client_type_external_generic_client) { #if defined(ESP_MAIL_HAS_WIFI_DISCONNECT) // We can reconnect WiFi when device connected via built-in WiFi that supports reconnect @@ -411,16 +438,16 @@ class ESP_Mail_TCPClient { bool rdy = true; #if !defined(ESP_MAIL_WIFI_IS_AVAILABLE) - if (_client_type == esp_mail_client_type_external_basic_client && + if (_client_type == esp_mail_client_type_external_generic_client && (!_network_connection_cb || !_network_status_cb)) rdy = false; - else if (_client_type != esp_mail_client_type_external_basic_client || + else if (_client_type != esp_mail_client_type_external_generic_client || _client_type != esp_mail_client_type_external_gsm_client) rdy = false; #else // assume external client is WiFiClient and network status request callback is not required // when device was connected to network using on board WiFi - if (_client_type == esp_mail_client_type_external_basic_client && + if (_client_type == esp_mail_client_type_external_generic_client && (!_network_connection_cb || (!_network_status_cb && !WiFI_CONNECTED && !ethLinkUp()))) { rdy = false; @@ -508,7 +535,7 @@ class ESP_Mail_TCPClient if (!_basic_client) { - if (_client_type == esp_mail_client_type_external_basic_client) + if (_client_type == esp_mail_client_type_external_generic_client) { _last_error = 1; return false; @@ -984,6 +1011,85 @@ class ESP_Mail_TCPClient return false; } + bool ethernetConnect() + { + bool ret = false; + +#if defined(ESP_MAIL_ETHERNET_MODULE_IS_AVAILABLE) + + if (_ethernet_cs_pin > -1) + Ethernet.init(_ethernet_cs_pin); + + if (_ethernet_reset_pin > -1) + { + +#if !defined(SILENT_MODE) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP)) + if (_debug_level > 0) + esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR("Resetting Ethernet Board..."), esp_mail_debug_tag_type_info, true, false); +#endif + + pinMode(_ethernet_reset_pin, OUTPUT); + digitalWrite(_ethernet_reset_pin, HIGH); + delay(200); + digitalWrite(_ethernet_reset_pin, LOW); + delay(50); + digitalWrite(_ethernet_reset_pin, HIGH); + delay(200); + } + +#if !defined(SILENT_MODE) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP)) + if (_debug_level > 0) + esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR("Starting Ethernet connection..."), esp_mail_debug_tag_type_info, true, false); +#endif + if (_static_ip) + { + + if (_static_ip->optional == false) + Ethernet.begin(_ethernet_mac, _static_ip->ipAddress, _static_ip->dnsServer, _static_ip->defaultGateway, _static_ip->netMask); + else if (!Ethernet.begin(_ethernet_mac)) + { + Ethernet.begin(_ethernet_mac, _static_ip->ipAddress, _static_ip->dnsServer, _static_ip->defaultGateway, _static_ip->netMask); + } + } + else + Ethernet.begin(_ethernet_mac); + + unsigned long to = millis(); + + while (Ethernet.linkStatus() == LinkOFF && millis() - to < 2000) + { + delay(100); + } + + ret = ethernetConnected(); + +#if !defined(SILENT_MODE) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP)) + if (_debug_level > 0) + { + if (ret) + { + MB_String s = MBSTRING_FLASH_MCR("Connected with IP "); + s += Ethernet.localIP().toString(); + esp_mail_debug_print_tag(s.c_str(), esp_mail_debug_tag_type_info, true, false); + } + else + esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR("Can't connect"), esp_mail_debug_tag_type_error, true, false); + } +#endif + +#endif + + return ret; + } + + bool ethernetConnected() + { +#if defined(ESP_MAIL_ETHERNET_MODULE_IS_AVAILABLE) + _network_status = Ethernet.linkStatus() == LinkON; +#endif + return _network_status; + } + int setOption(int option, int *value) { #if defined(ESP32) && defined(ESP_MAIL_WIFI_IS_AVAILABLE) @@ -1063,6 +1169,10 @@ class ESP_Mail_TCPClient MB_FS *_mbfs = nullptr; Client *_basic_client = nullptr; esp_mail_wifi_credentials_t *_wifi_multi = nullptr; + int _ethernet_reset_pin = -1; + int _ethernet_cs_pin = -1; + uint8_t *_ethernet_mac = nullptr; + ESP_Mail_StaticIP *_static_ip = nullptr; #if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) Session_Config *_session_config = nullptr; #endif diff --git a/src/README.md b/src/README.md index 8fe31587..bc2fc7a4 100644 --- a/src/README.md +++ b/src/README.md @@ -405,6 +405,23 @@ void setGSMClient(Client *client, void *modem, const char *pin, const char *apn, ``` +#### Assign external Ethernet Client. + +param **`client`** The pointer to Ethernet client object. + +param **`macAddress`** The Ethernet MAC address. + +param **`csPin`** The Ethernet module SPI chip select pin. + +param **`resetPin`** The Ethernet module reset pin. + +param **`staticIP`** (Optional) The pointer to `ESP_Mail_StaticIP` object which included these IPAddress properties ipAddress, netMask, defaultGateway and dnsServer. + +```cpp + void setEthernetClient(Client *client, uint8_t macAddress[6], int csPin, int resetPin, ESP_Mail_StaticIP *staticIP = nullptr); + + + #### Assign the callback function to handle the network connection for custom Client. param **`networkConnectionCB`** The function that handles the network connection. @@ -1356,7 +1373,23 @@ void setGSMClient(Client *client, void *modem, const char *pin, const char *apn, ``` +#### Assign external Ethernet Client. +param **`client`** The pointer to Ethernet client object. + +param **`macAddress`** The Ethernet MAC address. + +param **`csPin`** The Ethernet module SPI chip select pin. + +param **`resetPin`** The Ethernet module reset pin. + +param **`staticIP`** (Optional) The pointer to `ESP_Mail_StaticIP` object which included these IPAddress properties ipAddress, netMask, defaultGateway and dnsServer. + +```cpp + void setEthernetClient(Client *client, uint8_t macAddress[6], int csPin, int resetPin, ESP_Mail_StaticIP *staticIP = nullptr); + + + #### Assign the callback function to handle the network connection for custom Client. param **`networkConnectionCB`** The function that handles the network connection. diff --git a/src/SSLClient/Custom_ESP_SSLClient_FS.h b/src/SSLClient/Custom_ESP_SSLClient_FS.h index 1f28bdb0..279d59e8 100644 --- a/src/SSLClient/Custom_ESP_SSLClient_FS.h +++ b/src/SSLClient/Custom_ESP_SSLClient_FS.h @@ -2,20 +2,12 @@ #ifndef CUSTOM_ESP_SSLCLIENT_FS_H #define CUSTOM_ESP_SSLCLIENT_FS_H -#include "../ESP_Mail_FS.h" #if defined(ESP_MAIL_DISABLE_SSL) #undef USE_LIB_SSL_ENGINE #undef USE_EMBED_SSL_ENGINE #endif -#if defined(ESP_MAIL_USE_PSRAM) -#if !defined(ESP_SSLCLIENT_USE_PSRAM) -#define ESP_SSLCLIENT_USE_PSRAM -#endif -#else -#undef ESP_SSLCLIENT_USE_PSRAM -#endif #undef ESP_SSLCLIENT_ENABLE_DEBUG #undef ESP_SSLCLIENT_ENABLE_SSL_ERROR_STRING diff --git a/src/SSLClient/ESP_SSLClient.h b/src/SSLClient/ESP_SSLClient.h index a77b0808..58ae1d40 100644 --- a/src/SSLClient/ESP_SSLClient.h +++ b/src/SSLClient/ESP_SSLClient.h @@ -1,8 +1,8 @@ /** * - * The ESP SSL Client Class, ESP_SSLClient.h v2.1.6 + * The ESP SSL Client Class, ESP_SSLClient.h v2.1.7 * - * Created August 27, 2023 + * Created September 2, 2023 * * The MIT License (MIT) * Copyright (c) 2023 K. Suwatchai (Mobizt) diff --git a/src/SSLClient/ESP_SSLClient_FS.h b/src/SSLClient/ESP_SSLClient_FS.h index d8787dd1..cacae8c1 100644 --- a/src/SSLClient/ESP_SSLClient_FS.h +++ b/src/SSLClient/ESP_SSLClient_FS.h @@ -34,7 +34,7 @@ #define ESP_SSLCLIENT_USE_PSRAM #if defined __has_include -#if __has_include() +#if __has_include("Custom_ESP_SSLClient_FS.h") #include "Custom_ESP_SSLClient_FS.h" #endif #endif diff --git a/src/SSLClient/client/BSSL_SSL_Client.cpp b/src/SSLClient/client/BSSL_SSL_Client.cpp index 2b90a185..2d976292 100644 --- a/src/SSLClient/client/BSSL_SSL_Client.cpp +++ b/src/SSLClient/client/BSSL_SSL_Client.cpp @@ -1,7 +1,7 @@ /** - * BSSL_SSL_Client library v1.0.11 for Arduino devices. + * BSSL_SSL_Client library v1.0.12 for Arduino devices. * - * Created August 27, 2003 + * Created September 2, 2003 * * This work contains codes based on WiFiClientSecure from Earle F. Philhower and SSLClient from OSU OPEnS Lab. * diff --git a/src/SSLClient/client/BSSL_SSL_Client.h b/src/SSLClient/client/BSSL_SSL_Client.h index 98a42685..5196de1d 100644 --- a/src/SSLClient/client/BSSL_SSL_Client.h +++ b/src/SSLClient/client/BSSL_SSL_Client.h @@ -1,7 +1,7 @@ /** - * BSSL_SSL_Client library v1.0.11 for Arduino devices. + * BSSL_SSL_Client library v1.0.12 for Arduino devices. * - * Created August 27, 2003 + * Created September 2, 2003 * * This work contains codes based on WiFiClientSecure from Earle F. Philhower and SSLClient from OSU OPEnS Lab. * @@ -273,15 +273,15 @@ class BSSL_SSL_Client : public Client // store whether to enable debug logging int _debug_level = 0; - bool _is_connected; + bool _is_connected = false; // store the index of where we are writing in the buffer // so we can send our records all at once to prevent // weird timing issues - size_t _write_idx; + size_t _write_idx = 0; // store the last BearSSL state so we can print changes to the console - unsigned _bssl_last_state; + unsigned int _bssl_last_state = 0; bool _secure = false; diff --git a/src/extras/Build_Options.h b/src/extras/Build_Options.h index a2251f89..9f070596 100644 --- a/src/extras/Build_Options.h +++ b/src/extras/Build_Options.h @@ -37,7 +37,6 @@ #if defined(DISABLE_SD) #undef ESP_MAIL_DEFAULT_SD_FS #undef ESP_MAIL_CARD_TYPE_SD_MMC -#undef ESP_MAIL_DEFAULT_FLASH_FS #endif #if defined(DISABLE_FLASH) @@ -49,4 +48,5 @@ #undef ESP_MAIL_DEFAULT_DEBUG_PORT #endif + #endif \ No newline at end of file diff --git a/src/extras/ESP8266_Supports.h b/src/extras/ESP8266_Supports.h deleted file mode 100644 index 5604690c..00000000 --- a/src/extras/ESP8266_Supports.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef ESP8266_SUPPORTS_H -#define ESP8266_SUPPORTS_H -#include -#include "MB_MCU.h" -#if defined(ESP8266) || defined(MB_ARDUINO_PICO) - -#include - -//__GNUC__ -//__GNUC_MINOR__ -//__GNUC_PATCHLEVEL__ - -#ifdef __GNUC__ -#if __GNUC__ > 4 || __GNUC__ == 10 -#if defined(ARDUINO_ESP8266_GIT_VER) -#if ARDUINO_ESP8266_GIT_VER > 0 -#define ESP8266_CORE_SDK_V3_X_X -#endif -#endif -#endif -#endif - -#if defined __has_include - -#if __has_include() -#include -#endif - -#if __has_include()&& defined(ENABLE_ESP8266_ENC28J60_ETH) -#define INC_ENC28J60_LWIP -#include -#endif - -#if __has_include() && defined(ENABLE_ESP8266_W5100_ETH) -#define INC_W5100_LWIP -#include -#endif - -#if __has_include()&& defined(ENABLE_ESP8266_W5500_ETH) -#define INC_W5500_LWIP -#include -#endif - -#if defined(MB_ARDUINO_PICO) - -#endif - -#endif - -#endif - -#endif \ No newline at end of file diff --git a/src/extras/MB_Time.h b/src/extras/MB_Time.h index 73d84ac2..68dc7abe 100644 --- a/src/extras/MB_Time.h +++ b/src/extras/MB_Time.h @@ -1,8 +1,8 @@ #ifndef MB_Time_H #define MB_Time_H -#include "ESP_Mail_Client_Version.h" -#if !VALID_VERSION_CHECK(30409) +#include "./ESP_Mail_Client_Version.h" +#if !VALID_VERSION_CHECK(30410) #error "Mixed versions compilation." #endif @@ -36,7 +36,7 @@ */ #include -#include "Networks_Provider.h" +#include "./extras/Networks.h" #define ESP_TIME_DEFAULT_TS 1577836800 #define ESP_TIME_NON_TS -1000 @@ -54,8 +54,8 @@ #define MB_STRING_USE_PSRAM #endif -#include "MB_String.h" -#include "MB_MCU.h" +#include "./extras/MB_String.h" +#include "./extras/MB_MCU.h" #if defined(ESP8266) #include "user_interface.h" @@ -395,7 +395,7 @@ class MB_Time s.clear(); } - // 9Safe) Get base timestamp + // (Safe) Get base timestamp void getBaseTime() { diff --git a/src/extras/Networks_Provider.h b/src/extras/Networks.h similarity index 70% rename from src/extras/Networks_Provider.h rename to src/extras/Networks.h index fd523be6..cb7a3b79 100644 --- a/src/extras/Networks_Provider.h +++ b/src/extras/Networks.h @@ -1,18 +1,13 @@ -#ifndef ESP_MAIL_NETWORKS_PROVIDER_H -#define ESP_MAIL_NETWORKS_PROVIDER_H +#ifndef ESP_MAIL_NETWORKS_H +#define ESP_MAIL_NETWORKS_H -#include "../ESP_Mail_FS.h" +#include "./ESP_Mail_FS.h" -#include "../ESP_Mail_Client_Version.h" -#if !VALID_VERSION_CHECK(30409) +#include "./ESP_Mail_Client_Version.h" +#if !VALID_VERSION_CHECK(30410) #error "Mixed versions compilation." #endif -#if __has_include() -#include -#endif - -#include "ESP8266_Supports.h" // Renesas devices #if defined(ARDUINO_UNOWIFIR4) || defined(ARDUINO_MINIMA) || defined(ARDUINO_PORTENTA_C33) @@ -22,6 +17,85 @@ #define ESP_MAIL_STRSEP strsep #endif +#if __has_include() +#include +#endif + +#if defined(ESP8266) || defined(MB_ARDUINO_PICO) + +#include + +//__GNUC__ +//__GNUC_MINOR__ +//__GNUC_PATCHLEVEL__ + +#ifdef __GNUC__ +#if __GNUC__ > 4 || __GNUC__ == 10 +#if defined(ARDUINO_ESP8266_GIT_VER) +#if ARDUINO_ESP8266_GIT_VER > 0 +#define ESP8266_CORE_SDK_V3_X_X +#endif +#endif +#endif +#endif + +#endif + +#if !defined(ESP_MAIL_DISABLE_NATIVE_ETHERNET) + +#if defined(ESP32) && __has_include() +#include +#define ESP_MAIL_ETH_IS_AVAILABLE +#elif defined(ESP8266) && defined(ESP8266_CORE_SDK_V3_X_X) + +#if __has_include() +#include +#endif + +#if __has_include()&& defined(ENABLE_ESP8266_ENC28J60_ETH) +#define INC_ENC28J60_LWIP +#include +#endif + +#if __has_include() && defined(ENABLE_ESP8266_W5100_ETH) +#define INC_W5100_LWIP +#include +#endif + +#if __has_include()&& defined(ENABLE_ESP8266_W5500_ETH) +#define INC_W5500_LWIP +#include +#endif + +#if defined(MB_ARDUINO_PICO) + +#endif + +#if defined(INC_ENC28J60_LWIP) && defined(INC_W5100_LWIP) && defined(INC_W5500_LWIP) +#define ESP_MAIL_ETH_IS_AVAILABLE +#endif + +#endif + +#endif + +#if __has_include() +#if defined(ESP8266) +#undef MAX_SOCK_NUM + +#if defined(ESP_MAIL_DISABLE_NATIVE_ETHERNET) +#include +#define ESP_MAIL_ETHERNET_MODULE_IS_AVAILABLE +#endif + +#undef MAX_SOCK_NUM +#elif !defined(ARDUINO_NANO_RP2040_CONNECT) +#include +#define ESP_MAIL_ETHERNET_MODULE_IS_AVAILABLE +#endif + +#endif + #if defined(ESP32) || defined(ESP8266) || defined(ARDUINO_RASPBERRY_PI_PICO_W) || \ defined(ARDUINO_UNOWIFIR4) || defined(ARDUINO_PORTENTA_C33) || \ defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) || \ @@ -73,19 +147,6 @@ #endif -#if !defined(ESP_MAIL_DISABLE_NATIVE_ETHERNET) - -#if defined(ESP32) && __has_include() -#include -#define ESP_MAIL_ETH_IS_AVAILABLE -#elif defined(ESP8266) && defined(ESP8266_CORE_SDK_V3_X_X) -#if defined(INC_ENC28J60_LWIP) || defined(INC_W5100_LWIP) || defined(INC_W5500_LWIP) -#define ESP_MAIL_ETH_IS_AVAILABLE -#endif -#endif - -#endif - #if defined(TINY_GSM_MODEM_SIM800) || \ defined(TINY_GSM_MODEM_SIM808) || \ defined(TINY_GSM_MODEM_SIM868) || \ diff --git a/src/extras/RFC2047.cpp b/src/extras/RFC2047.cpp index 95e5ac14..107cd5c2 100644 --- a/src/extras/RFC2047.cpp +++ b/src/extras/RFC2047.cpp @@ -2,7 +2,7 @@ #define RFC2047_CPP #include "ESP_Mail_Client_Version.h" -#if !VALID_VERSION_CHECK(30409) +#if !VALID_VERSION_CHECK(30410) #error "Mixed versions compilation." #endif diff --git a/src/extras/RFC2047.h b/src/extras/RFC2047.h index baadaa67..50b82b44 100644 --- a/src/extras/RFC2047.h +++ b/src/extras/RFC2047.h @@ -4,14 +4,14 @@ #define RFC2047_H #include "ESP_Mail_Client_Version.h" -#if !VALID_VERSION_CHECK(30409) +#if !VALID_VERSION_CHECK(30410) #error "Mixed versions compilation." #endif #include -#include "ESP_Mail_FS.h" -#include "MB_FS.h" -#include "Networks_Provider.h" +#include "./ESP_Mail_FS.h" +#include "./extras/MB_FS.h" +#include "./extras/Networks.h" #if defined(ESP32) #if defined(BOARD_HAS_PSRAM) && defined(ESP_Mail_USE_PSRAM) diff --git a/src/extras/mb_print/mb_print.c b/src/extras/mb_print/mb_print.c deleted file mode 100644 index 1a595f4f..00000000 --- a/src/extras/mb_print/mb_print.c +++ /dev/null @@ -1,1048 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// \author (c) Marco Paland (info@paland.com) -// 2014-2019, PALANDesign Hannover, Germany -// -// \license The MIT License (MIT) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on -// embedded systems with a very limited resources. These routines are thread -// safe and reentrant! -// Use this instead of the bloated standard/newlib printf cause these use -// malloc for printf (and may not be thread safe). -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef MB_PRINT_C -#define MB_PRINT_C - -#include -#include - -#include "mb_print.h" - -// define this globally (e.g. gcc -DMB_PRINT_INCLUDE_CONFIG_H ...) to include the -// printf_config.h header file -// default: undefined -#ifdef MB_PRINT_INCLUDE_CONFIG_H -#include "printf_config.h" -#endif - -// 'ntoa' conversion buffer size, this must be big enough to hold one converted -// numeric number including padded zeros (dynamically created on stack) -// default: 32 byte -#ifndef MB_PRINT_NTOA_BUFFER_SIZE -#define MB_PRINT_NTOA_BUFFER_SIZE 32U -#endif - -// 'ftoa' conversion buffer size, this must be big enough to hold one converted -// float number including padded zeros (dynamically created on stack) -// default: 32 byte -#ifndef MB_PRINT_FTOA_BUFFER_SIZE -#define MB_PRINT_FTOA_BUFFER_SIZE 32U -#endif - -// support for the floating point type (%f) -// default: activated -#ifndef MB_PRINT_DISABLE_SUPPORT_FLOAT -#define MB_PRINT_SUPPORT_FLOAT -#endif - -// support for exponential floating point notation (%e/%g) -// default: activated -#ifndef MB_PRINT_DISABLE_SUPPORT_EXPONENTIAL -#define MB_PRINT_SUPPORT_EXPONENTIAL -#endif - -// define the default floating point precision -// default: 6 digits -#ifndef MB_PRINT_DEFAULT_FLOAT_PRECISION -#define MB_PRINT_DEFAULT_FLOAT_PRECISION 6U -#endif - -// define the largest float suitable to print with %f -// default: 1e9 -#ifndef MB_PRINT_MAX_FLOAT -#define MB_PRINT_MAX_FLOAT 1e9 -#endif - -// support for the long long types (%llu or %p) -// default: activated -#ifndef MB_PRINT_DISABLE_SUPPORT_LONG_LONG -#define MB_PRINT_SUPPORT_LONG_LONG -#endif - -// support for the ptrdiff_t type (%t) -// ptrdiff_t is normally defined in as long or long long type -// default: activated -#ifndef MB_PRINT_DISABLE_SUPPORT_PTRDIFF_T -#define MB_PRINT_SUPPORT_PTRDIFF_T -#endif - -/////////////////////////////////////////////////////////////////////////////// - -// internal flag definitions -#define MB_PRINT_FLAGS_ZEROPAD (1U << 0U) -#define MB_PRINT_FLAGS_LEFT (1U << 1U) -#define MB_PRINT_FLAGS_PLUS (1U << 2U) -#define MB_PRINT_FLAGS_SPACE (1U << 3U) -#define MB_PRINT_FLAGS_HASH (1U << 4U) -#define MB_PRINT_FLAGS_UPPERCASE (1U << 5U) -#define MB_PRINT_FLAGS_CHAR (1U << 6U) -#define MB_PRINT_FLAGS_SHORT (1U << 7U) -#define MB_PRINT_FLAGS_LONG (1U << 8U) -#define MB_PRINT_FLAGS_LONG_LONG (1U << 9U) -#define MB_PRINT_FLAGS_PRECISION (1U << 10U) -#define MB_PRINT_FLAGS_ADAPT_EXP (1U << 11U) - -// import float.h for DBL_MAX -#if defined(MB_PRINT_SUPPORT_FLOAT) -#include -#endif - -// output function type -typedef void (*mb_print_out_fn_type)(char character, void *buffer, size_t idx, size_t maxlen); - -// wrapper (used as buffer) for output function type -typedef struct -{ - void (*fct)(char character, void *arg); - void *arg; -} mb_print_out_fn_wrap_type; - -// internal buffer output -static inline void mb_print_out_buffer(char character, void *buffer, size_t idx, size_t maxlen) -{ - if (idx < maxlen) - { - ((char *)buffer)[idx] = character; - } -} - -// internal null output -static inline void mb_print_out_null(char character, void *buffer, size_t idx, size_t maxlen) -{ - (void)character; - (void)buffer; - (void)idx; - (void)maxlen; -} - -// internal _putchar wrapper -static inline void mb_print_out_char(char character, void *buffer, size_t idx, size_t maxlen) -{ - (void)buffer; - (void)idx; - (void)maxlen; - if (character) - { - mb_print_putchar(character); - } -} - -// internal output function wrapper -static inline void mb_print_out_fn(char character, void *buffer, size_t idx, size_t maxlen) -{ - (void)idx; - (void)maxlen; - if (character) - { - // buffer is the output fct pointer - ((mb_print_out_fn_wrap_type *)buffer)->fct(character, ((mb_print_out_fn_wrap_type *)buffer)->arg); - } -} - -// internal secure strlen -// \return The length of the string (excluding the terminating 0) limited by 'maxsize' -static inline unsigned int mb_print_strlen(const char *str, size_t maxsize) -{ - const char *s; - for (s = str; *s && maxsize--; ++s) - ; - return (unsigned int)(s - str); -} - -// internal test if char is a digit (0-9) -// \return true if char is a digit -static inline bool mb_print_is_digit(char ch) -{ - return (ch >= '0') && (ch <= '9'); -} - -// internal ASCII string to unsigned int conversion -static unsigned int mb_print_atoi(const char **str) -{ - unsigned int i = 0U; - while (mb_print_is_digit(**str)) - { - i = i * 10U + (unsigned int)(*((*str)++) - '0'); - } - return i; -} - -// output the specified string in reverse, taking care of any zero-padding -static size_t mb_print_out_rev(mb_print_out_fn_type out, char *buffer, size_t idx, size_t maxlen, const char *buf, size_t len, unsigned int width, unsigned int flags) -{ - const size_t start_idx = idx; - - // pad spaces up to given width - if (!(flags & MB_PRINT_FLAGS_LEFT) && !(flags & MB_PRINT_FLAGS_ZEROPAD)) - { - for (size_t i = len; i < width; i++) - { - out(' ', buffer, idx++, maxlen); - } - } - - // reverse string - while (len) - { - out(buf[--len], buffer, idx++, maxlen); - } - - // append pad spaces up to given width - if (flags & MB_PRINT_FLAGS_LEFT) - { - while (idx - start_idx < width) - { - out(' ', buffer, idx++, maxlen); - } - } - - return idx; -} - -// internal itoa format -static size_t mb_print_itoa_format(mb_print_out_fn_type out, char *buffer, size_t idx, size_t maxlen, char *buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) -{ - // pad leading zeros - if (!(flags & MB_PRINT_FLAGS_LEFT)) - { - if (width && (flags & MB_PRINT_FLAGS_ZEROPAD) && (negative || (flags & (MB_PRINT_FLAGS_PLUS | MB_PRINT_FLAGS_SPACE)))) - { - width--; - } - while ((len < prec) && (len < MB_PRINT_NTOA_BUFFER_SIZE)) - { - buf[len++] = '0'; - } - while ((flags & MB_PRINT_FLAGS_ZEROPAD) && (len < width) && (len < MB_PRINT_NTOA_BUFFER_SIZE)) - { - buf[len++] = '0'; - } - } - - // handle hash - if (flags & MB_PRINT_FLAGS_HASH) - { - if (!(flags & MB_PRINT_FLAGS_PRECISION) && len && ((len == prec) || (len == width))) - { - len--; - if (len && (base == 16U)) - { - len--; - } - } - if ((base == 16U) && !(flags & MB_PRINT_FLAGS_UPPERCASE) && (len < MB_PRINT_NTOA_BUFFER_SIZE)) - { - buf[len++] = 'x'; - } - else if ((base == 16U) && (flags & MB_PRINT_FLAGS_UPPERCASE) && (len < MB_PRINT_NTOA_BUFFER_SIZE)) - { - buf[len++] = 'X'; - } - else if ((base == 2U) && (len < MB_PRINT_NTOA_BUFFER_SIZE)) - { - buf[len++] = 'b'; - } - if (len < MB_PRINT_NTOA_BUFFER_SIZE) - { - buf[len++] = '0'; - } - } - - if (len < MB_PRINT_NTOA_BUFFER_SIZE) - { - if (negative) - { - buf[len++] = '-'; - } - else if (flags & MB_PRINT_FLAGS_PLUS) - { - buf[len++] = '+'; // ignore the space if the '+' exists - } - else if (flags & MB_PRINT_FLAGS_SPACE) - { - buf[len++] = ' '; - } - } - - return mb_print_out_rev(out, buffer, idx, maxlen, buf, len, width, flags); -} - -// internal itoa for 'long' type -static size_t mb_print_itoa_long(mb_print_out_fn_type out, char *buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) -{ - char buf[MB_PRINT_NTOA_BUFFER_SIZE]; - size_t len = 0U; - - // no hash for 0 values - if (!value) - { - flags &= ~MB_PRINT_FLAGS_HASH; - } - - // write if precision != 0 and value is != 0 - if (!(flags & MB_PRINT_FLAGS_PRECISION) || value) - { - do - { - const char digit = (char)(value % base); - buf[len++] = digit < 10 ? '0' + digit : (flags & MB_PRINT_FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; - value /= base; - } while (value && (len < MB_PRINT_NTOA_BUFFER_SIZE)); - } - - return mb_print_itoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); -} - -// internal itoa for 'long long' type -#if defined(MB_PRINT_SUPPORT_LONG_LONG) -static size_t mb_print_itoa_long_long(mb_print_out_fn_type out, char *buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) -{ - char buf[MB_PRINT_NTOA_BUFFER_SIZE]; - size_t len = 0U; - - // no hash for 0 values - if (!value) - { - flags &= ~MB_PRINT_FLAGS_HASH; - } - - // write if precision != 0 and value is != 0 - if (!(flags & MB_PRINT_FLAGS_PRECISION) || value) - { - do - { - const char digit = (char)(value % base); - buf[len++] = digit < 10 ? '0' + digit : (flags & MB_PRINT_FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; - value /= base; - } while (value && (len < MB_PRINT_NTOA_BUFFER_SIZE)); - } - - return mb_print_itoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); -} -#endif // MB_PRINT_SUPPORT_LONG_LONG - -#if defined(MB_PRINT_SUPPORT_FLOAT) - -#if defined(MB_PRINT_SUPPORT_EXPONENTIAL) -// forward declaration so that mb_print_ftoa can switch to exp notation for values > MB_PRINT_MAX_FLOAT -static size_t mb_print_ftoa_exp(mb_print_out_fn_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags); -#endif - -// internal ftoa for fixed decimal floating point -static size_t mb_print_ftoa(mb_print_out_fn_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) -{ - char buf[MB_PRINT_FTOA_BUFFER_SIZE]; - size_t len = 0U; - double diff = 0.0; - - // powers of 10 - static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; - - // test for special values - if (value != value) - return mb_print_out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); - if (value < -DBL_MAX) - return mb_print_out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); - if (value > DBL_MAX) - return mb_print_out_rev(out, buffer, idx, maxlen, (flags & MB_PRINT_FLAGS_PLUS) ? "fni+" : "fni", (flags & MB_PRINT_FLAGS_PLUS) ? 4U : 3U, width, flags); - - // test for very large values - // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad - if ((value > MB_PRINT_MAX_FLOAT) || (value < -MB_PRINT_MAX_FLOAT)) - { -#if defined(MB_PRINT_SUPPORT_EXPONENTIAL) - return mb_print_ftoa_exp(out, buffer, idx, maxlen, value, prec, width, flags); -#else - return 0U; -#endif - } - - // test for negative - bool negative = false; - if (value < 0) - { - negative = true; - value = 0 - value; - } - - // set default precision, if not set explicitly - if (!(flags & MB_PRINT_FLAGS_PRECISION)) - { - prec = MB_PRINT_DEFAULT_FLOAT_PRECISION; - } - // limit precision to 9, cause a prec >= 10 can lead to overflow errors - while ((len < MB_PRINT_FTOA_BUFFER_SIZE) && (prec > 9U)) - { - buf[len++] = '0'; - prec--; - } - - int whole = (int)value; - double tmp = (value - whole) * pow10[prec]; - unsigned long frac = (unsigned long)tmp; - diff = tmp - frac; - - if (diff > 0.5) - { - ++frac; - // handle rollover, e.g. case 0.99 with prec 1 is 1.0 - if (frac >= pow10[prec]) - { - frac = 0; - ++whole; - } - } - else if (diff < 0.5) - { - } - else if ((frac == 0U) || (frac & 1U)) - { - // if halfway, round up if odd OR if last digit is 0 - ++frac; - } - - if (prec == 0U) - { - diff = value - (double)whole; - if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) - { - // exactly 0.5 and ODD, then round up - // 1.5 -> 2, but 2.5 -> 2 - ++whole; - } - } - else - { - unsigned int count = prec; - // now do fractional part, as an unsigned number - while (len < MB_PRINT_FTOA_BUFFER_SIZE) - { - --count; - buf[len++] = (char)(48U + (frac % 10U)); - if (!(frac /= 10U)) - { - break; - } - } - // add extra 0s - while ((len < MB_PRINT_FTOA_BUFFER_SIZE) && (count-- > 0U)) - { - buf[len++] = '0'; - } - if (len < MB_PRINT_FTOA_BUFFER_SIZE) - { - // add decimal - buf[len++] = '.'; - } - } - - // do whole part, number is reversed - while (len < MB_PRINT_FTOA_BUFFER_SIZE) - { - buf[len++] = (char)(48 + (whole % 10)); - if (!(whole /= 10)) - { - break; - } - } - - // pad leading zeros - if (!(flags & MB_PRINT_FLAGS_LEFT) && (flags & MB_PRINT_FLAGS_ZEROPAD)) - { - if (width && (negative || (flags & (MB_PRINT_FLAGS_PLUS | MB_PRINT_FLAGS_SPACE)))) - { - width--; - } - while ((len < width) && (len < MB_PRINT_FTOA_BUFFER_SIZE)) - { - buf[len++] = '0'; - } - } - - if (len < MB_PRINT_FTOA_BUFFER_SIZE) - { - if (negative) - { - buf[len++] = '-'; - } - else if (flags & MB_PRINT_FLAGS_PLUS) - { - buf[len++] = '+'; // ignore the space if the '+' exists - } - else if (flags & MB_PRINT_FLAGS_SPACE) - { - buf[len++] = ' '; - } - } - - return mb_print_out_rev(out, buffer, idx, maxlen, buf, len, width, flags); -} - -#if defined(MB_PRINT_SUPPORT_EXPONENTIAL) -// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse -static size_t mb_print_ftoa_exp(mb_print_out_fn_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) -{ - // check for NaN and special values - if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) - { - return mb_print_ftoa(out, buffer, idx, maxlen, value, prec, width, flags); - } - - // determine the sign - const bool negative = value < 0; - if (negative) - { - value = -value; - } - - // default precision - if (!(flags & MB_PRINT_FLAGS_PRECISION)) - { - prec = MB_PRINT_DEFAULT_FLOAT_PRECISION; - } - - // determine the decimal exponent - // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) - union - { - uint64_t U; - double F; - } conv; - - conv.F = value; - int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 - conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) - // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 - int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); - // now we want to compute 10^expval but we want to be sure it won't overflow - exp2 = (int)(expval * 3.321928094887362 + 0.5); - const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; - const double z2 = z * z; - conv.U = (uint64_t)(exp2 + 1023) << 52U; - // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex - conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); - // correct for rounding errors - if (value < conv.F) - { - expval--; - conv.F /= 10; - } - - // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters - unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; - - // in "%g" mode, "prec" is the number of *significant figures* not decimals - if (flags & MB_PRINT_FLAGS_ADAPT_EXP) - { - // do we want to fall-back to "%f" mode? - if ((value >= 1e-4) && (value < 1e6)) - { - if ((int)prec > expval) - { - prec = (unsigned)((int)prec - expval - 1); - } - else - { - prec = 0; - } - flags |= MB_PRINT_FLAGS_PRECISION; // make sure mb_print_ftoa respects precision - // no characters in exponent - minwidth = 0U; - expval = 0; - } - else - { - // we use one sigfig for the whole part - if ((prec > 0) && (flags & MB_PRINT_FLAGS_PRECISION)) - { - --prec; - } - } - } - - // will everything fit? - unsigned int fwidth = width; - if (width > minwidth) - { - // we didn't fall-back so subtract the characters required for the exponent - fwidth -= minwidth; - } - else - { - // not enough characters, so go back to default sizing - fwidth = 0U; - } - if ((flags & MB_PRINT_FLAGS_LEFT) && minwidth) - { - // if we're padding on the right, DON'T pad the floating part - fwidth = 0U; - } - - // rescale the float value - if (expval) - { - value /= conv.F; - } - - // output the floating part - const size_t start_idx = idx; - idx = mb_print_ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~MB_PRINT_FLAGS_ADAPT_EXP); - - // output the exponent part - if (minwidth) - { - // output the exponential symbol - out((flags & MB_PRINT_FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); - // output the exponent value - idx = mb_print_itoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth - 1, MB_PRINT_FLAGS_ZEROPAD | MB_PRINT_FLAGS_PLUS); - // might need to right-pad spaces - if (flags & MB_PRINT_FLAGS_LEFT) - { - while (idx - start_idx < width) - out(' ', buffer, idx++, maxlen); - } - } - return idx; -} -#endif // MB_PRINT_SUPPORT_EXPONENTIAL -#endif // MB_PRINT_SUPPORT_FLOAT - -// internal vsnprintf -static int mb_print_vsnprintf_int(mb_print_out_fn_type out, char *buffer, const size_t maxlen, const char *format, va_list va) -{ - unsigned int flags, width, precision, n; - size_t idx = 0U; - - if (!buffer) - { - // use null output function - out = mb_print_out_null; - } - - while (*format) - { - // format specifier? %[flags][width][.precision][length] - if (*format != '%') - { - // no - out(*format, buffer, idx++, maxlen); - format++; - continue; - } - else - { - // yes, evaluate it - format++; - } - - // evaluate flags - flags = 0U; - do - { - switch (*format) - { - case '0': - flags |= MB_PRINT_FLAGS_ZEROPAD; - format++; - n = 1U; - break; - case '-': - flags |= MB_PRINT_FLAGS_LEFT; - format++; - n = 1U; - break; - case '+': - flags |= MB_PRINT_FLAGS_PLUS; - format++; - n = 1U; - break; - case ' ': - flags |= MB_PRINT_FLAGS_SPACE; - format++; - n = 1U; - break; - case '#': - flags |= MB_PRINT_FLAGS_HASH; - format++; - n = 1U; - break; - default: - n = 0U; - break; - } - } while (n); - - // evaluate width field - width = 0U; - if (mb_print_is_digit(*format)) - { - width = mb_print_atoi(&format); - } - else if (*format == '*') - { - const int w = va_arg(va, int); - if (w < 0) - { - flags |= MB_PRINT_FLAGS_LEFT; // reverse padding - width = (unsigned int)-w; - } - else - { - width = (unsigned int)w; - } - format++; - } - - // evaluate precision field - precision = 0U; - if (*format == '.') - { - flags |= MB_PRINT_FLAGS_PRECISION; - format++; - if (mb_print_is_digit(*format)) - { - precision = mb_print_atoi(&format); - } - else if (*format == '*') - { - const int prec = (int)va_arg(va, int); - precision = prec > 0 ? (unsigned int)prec : 0U; - format++; - } - } - - // evaluate length field - switch (*format) - { - case 'l': - flags |= MB_PRINT_FLAGS_LONG; - format++; - if (*format == 'l') - { - flags |= MB_PRINT_FLAGS_LONG_LONG; - format++; - } - break; - case 'h': - flags |= MB_PRINT_FLAGS_SHORT; - format++; - if (*format == 'h') - { - flags |= MB_PRINT_FLAGS_CHAR; - format++; - } - break; -#if defined(MB_PRINT_SUPPORT_PTRDIFF_T) - case 't': - flags |= (sizeof(ptrdiff_t) == sizeof(long) ? MB_PRINT_FLAGS_LONG : MB_PRINT_FLAGS_LONG_LONG); - format++; - break; -#endif - case 'j': - flags |= (sizeof(intmax_t) == sizeof(long) ? MB_PRINT_FLAGS_LONG : MB_PRINT_FLAGS_LONG_LONG); - format++; - break; - case 'z': - flags |= (sizeof(size_t) == sizeof(long) ? MB_PRINT_FLAGS_LONG : MB_PRINT_FLAGS_LONG_LONG); - format++; - break; - default: - break; - } - - // evaluate specifier - switch (*format) - { - case 'd': - case 'i': - case 'u': - case 'x': - case 'X': - case 'o': - case 'b': - { - // set the base - unsigned int base; - if (*format == 'x' || *format == 'X') - { - base = 16U; - } - else if (*format == 'o') - { - base = 8U; - } - else if (*format == 'b') - { - base = 2U; - } - else - { - base = 10U; - flags &= ~MB_PRINT_FLAGS_HASH; // no hash for dec format - } - // uppercase - if (*format == 'X') - { - flags |= MB_PRINT_FLAGS_UPPERCASE; - } - - // no plus or space flag for u, x, X, o, b - if ((*format != 'i') && (*format != 'd')) - { - flags &= ~(MB_PRINT_FLAGS_PLUS | MB_PRINT_FLAGS_SPACE); - } - - // ignore '0' flag when precision is given - if (flags & MB_PRINT_FLAGS_PRECISION) - { - flags &= ~MB_PRINT_FLAGS_ZEROPAD; - } - - // convert the integer - if ((*format == 'i') || (*format == 'd')) - { - // signed - if (flags & MB_PRINT_FLAGS_LONG_LONG) - { -#if defined(MB_PRINT_SUPPORT_LONG_LONG) - const long long value = va_arg(va, long long); - idx = mb_print_itoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); -#endif - } - else if (flags & MB_PRINT_FLAGS_LONG) - { - const long value = va_arg(va, long); - idx = mb_print_itoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); - } - else - { - const int value = (flags & MB_PRINT_FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & MB_PRINT_FLAGS_SHORT) ? (short int)va_arg(va, int) - : va_arg(va, int); - idx = mb_print_itoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); - } - } - else - { - // unsigned - if (flags & MB_PRINT_FLAGS_LONG_LONG) - { -#if defined(MB_PRINT_SUPPORT_LONG_LONG) - idx = mb_print_itoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags); -#endif - } - else if (flags & MB_PRINT_FLAGS_LONG) - { - idx = mb_print_itoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags); - } - else - { - const unsigned int value = (flags & MB_PRINT_FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & MB_PRINT_FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) - : va_arg(va, unsigned int); - idx = mb_print_itoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); - } - } - format++; - break; - } -#if defined(MB_PRINT_SUPPORT_FLOAT) - case 'f': - case 'F': - if (*format == 'F') - flags |= MB_PRINT_FLAGS_UPPERCASE; - idx = mb_print_ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); - format++; - break; -#if defined(MB_PRINT_SUPPORT_EXPONENTIAL) - case 'e': - case 'E': - case 'g': - case 'G': - if ((*format == 'g') || (*format == 'G')) - flags |= MB_PRINT_FLAGS_ADAPT_EXP; - if ((*format == 'E') || (*format == 'G')) - flags |= MB_PRINT_FLAGS_UPPERCASE; - idx = mb_print_ftoa_exp(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); - format++; - break; -#endif // MB_PRINT_SUPPORT_EXPONENTIAL -#endif // MB_PRINT_SUPPORT_FLOAT - case 'c': - { - unsigned int l = 1U; - // pre padding - if (!(flags & MB_PRINT_FLAGS_LEFT)) - { - while (l++ < width) - { - out(' ', buffer, idx++, maxlen); - } - } - // char output - out((char)va_arg(va, int), buffer, idx++, maxlen); - // post padding - if (flags & MB_PRINT_FLAGS_LEFT) - { - while (l++ < width) - { - out(' ', buffer, idx++, maxlen); - } - } - format++; - break; - } - - case 's': - { - const char *p = va_arg(va, char *); - unsigned int l = mb_print_strlen(p, precision ? precision : (size_t)-1); - // pre padding - if (flags & MB_PRINT_FLAGS_PRECISION) - { - l = (l < precision ? l : precision); - } - if (!(flags & MB_PRINT_FLAGS_LEFT)) - { - while (l++ < width) - { - out(' ', buffer, idx++, maxlen); - } - } - // string output - while ((*p != 0) && (!(flags & MB_PRINT_FLAGS_PRECISION) || precision--)) - { - out(*(p++), buffer, idx++, maxlen); - } - // post padding - if (flags & MB_PRINT_FLAGS_LEFT) - { - while (l++ < width) - { - out(' ', buffer, idx++, maxlen); - } - } - format++; - break; - } - - case 'p': - { - width = sizeof(void *) * 2U; - flags |= MB_PRINT_FLAGS_ZEROPAD | MB_PRINT_FLAGS_UPPERCASE; -#if defined(MB_PRINT_SUPPORT_LONG_LONG) - const bool is_ll = sizeof(uintptr_t) == sizeof(long long); - if (is_ll) - { - idx = mb_print_itoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void *), false, 16U, precision, width, flags); - } - else - { -#endif - idx = mb_print_itoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void *)), false, 16U, precision, width, flags); -#if defined(MB_PRINT_SUPPORT_LONG_LONG) - } -#endif - format++; - break; - } - - case '%': - out('%', buffer, idx++, maxlen); - format++; - break; - - default: - out(*format, buffer, idx++, maxlen); - format++; - break; - } - } - - // termination - out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); - - // return written chars without terminating \0 - return (int)idx; -} - -/////////////////////////////////////////////////////////////////////////////// - -int mb_print_printf(const char *format, ...) -{ - va_list va; - va_start(va, format); - char buffer[1]; - const int ret = mb_print_vsnprintf_int(mb_print_out_char, buffer, (size_t)-1, format, va); - va_end(va); - return ret; -} - -int mb_print_sprintf(char *buffer, const char *format, ...) -{ - va_list va; - va_start(va, format); - const int ret = mb_print_vsnprintf_int(mb_print_out_buffer, buffer, (size_t)-1, format, va); - va_end(va); - return ret; -} - -int mb_print_snprintf_(char *buffer, size_t count, const char *format, ...) -{ - va_list va; - va_start(va, format); - const int ret = mb_print_vsnprintf_int(mb_print_out_buffer, buffer, count, format, va); - va_end(va); - return ret; -} - -int mb_print_vprintf(const char *format, va_list va) -{ - char buffer[1]; - return mb_print_vsnprintf_int(mb_print_out_char, buffer, (size_t)-1, format, va); -} - -int mb_print_vsnprintf_(char *buffer, size_t count, const char *format, va_list va) -{ - return mb_print_vsnprintf_int(mb_print_out_buffer, buffer, count, format, va); -} - -int mb_print_fnprintf(void (*out)(char character, void *arg), void *arg, const char *format, ...) -{ - va_list va; - va_start(va, format); - const mb_print_out_fn_wrap_type out_fct_wrap = {out, arg}; - const int ret = mb_print_vsnprintf_int(mb_print_out_fn, (char *)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va); - va_end(va); - return ret; -} - -#endif \ No newline at end of file diff --git a/src/extras/mb_print/mb_print.h b/src/extras/mb_print/mb_print.h deleted file mode 100644 index 5ec3727b..00000000 --- a/src/extras/mb_print/mb_print.h +++ /dev/null @@ -1,108 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// \author (c) Marco Paland (info@paland.com) -// 2014-2019, PALANDesign Hannover, Germany -// -// \license The MIT License (MIT) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on -// embedded systems with a very limited resources. -// Use this instead of bloated standard/newlib printf. -// These routines are thread safe and reentrant. -// -/////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#ifndef _PRINTF_H_ -#define _PRINTF_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * Output a character to a custom device like UART, used by the printf() function - * This function is declared here only. You have to write your custom implementation somewhere - * \param character Character to output - */ - void mb_print_putchar(char character) __attribute__((used)); - - /** - * Tiny printf implementation - * You have to implement _putchar if you use printf() - * To avoid conflicts with the regular printf() API it is overridden by macro defines - * and internal underscore-appended functions like printf_() are used - * \param format A string that specifies the format of the output - * \return The number of characters that are written into the array, not counting the terminating null character - */ - int mb_print_printf(const char *format, ...) __attribute__((used)); - - /** - * Tiny sprintf implementation - * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! - * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! - * \param format A string that specifies the format of the output - * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character - */ - int mb_print_sprintf(char *buffer, const char *format, ...) __attribute__((used)); - - /** - * Tiny snprintf/vsnprintf implementation - * \param buffer A pointer to the buffer where to store the formatted string - * \param count The maximum number of characters to store in the buffer, including a terminating null character - * \param format A string that specifies the format of the output - * \param va A value identifying a variable arguments list - * \return The number of characters that COULD have been written into the buffer, not counting the terminating - * null character. A value equal or larger than count indicates truncation. Only when the returned value - * is non-negative and less than count, the string has been completely written. - */ -#define mb_print_snprintf mb_print_snprintf_ -#define mb_print_vsnprintf mb_print_vsnprintf_ - int mb_print_snprintf_(char *buffer, size_t count, const char *format, ...) __attribute__((used)); - int mb_print_vsnprintf_(char *buffer, size_t count, const char *format, va_list va) __attribute__((used)); - - /** - * Tiny vprintf implementation - * \param format A string that specifies the format of the output - * \param va A value identifying a variable arguments list - * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character - */ - int mb_print_vprintf(const char *format, va_list va) __attribute__((used)); - - /** - * printf with output function - * You may use this as dynamic alternative to printf() with its fixed _putchar() output - * \param out An output function which takes one character and an argument pointer - * \param arg An argument pointer for user data passed to output function - * \param format A string that specifies the format of the output - * \return The number of characters that are sent to the output function, not counting the terminating null character - */ - int mb_print_fnprintf(void (*out)(char character, void *arg), void *arg, const char *format, ...) __attribute__((used)); - -#ifdef __cplusplus -} -#endif - -#endif // _PRINTF_H_ \ No newline at end of file