|
@@ -20,157 +20,870 @@
|
|
|
*/
|
|
|
|
|
|
/*
|
|
|
- This was original tested with Intel Galileo acting as the Client, with a
|
|
|
-laptop acting as a server using the server example provided in examples/server.
|
|
|
-Legacy Ardunio v1.86 was used to compile and program the Galileo
|
|
|
+Tested with:
|
|
|
+
|
|
|
+1) Intel Galileo acting as the Client, with a laptop acting as a server using
|
|
|
+ the server example provided in examples/server.
|
|
|
+ Legacy Arduino v1.86 was used to compile and program the Galileo
|
|
|
+
|
|
|
+2) Espressif ESP32 WiFi
|
|
|
+
|
|
|
+3) Arduino Due, Nano33 IoT, Nano RP-2040
|
|
|
*/
|
|
|
|
|
|
-#define USE_CERT_BUFFERS_2048
|
|
|
+/*
|
|
|
+ * Note to code editors: the Arduino client and server examples are edited in
|
|
|
+ * parallel for side-by-side comparison between examples.
|
|
|
+ */
|
|
|
+
|
|
|
+/* If you have a private include, define it here, otherwise edit WiFi params */
|
|
|
+#define MY_PRIVATE_CONFIG "/workspace/my_private_config.h"
|
|
|
+
|
|
|
+/* set REPEAT_CONNECTION to a non-zero value to continually run the example. */
|
|
|
+#define REPEAT_CONNECTION 0
|
|
|
+
|
|
|
+/* Edit this with your other TLS host server address to connect to: */
|
|
|
+#define WOLFSSL_TLS_SERVER_HOST "192.168.1.34"
|
|
|
+
|
|
|
+/* wolfssl TLS examples communicate on port 11111 */
|
|
|
+#define WOLFSSL_PORT 11111
|
|
|
+
|
|
|
+/* Choose a monitor serial baud rate: 9600, 14400, 19200, 57600, 74880, etc. */
|
|
|
+#define SERIAL_BAUD 115200
|
|
|
+
|
|
|
+/* We'll wait up to 2000 milliseconds to properly shut down connection */
|
|
|
+#define SHUTDOWN_DELAY_MS 2000
|
|
|
+
|
|
|
+/* Number of times to retry connection. */
|
|
|
+#define RECONNECT_ATTEMPTS 20
|
|
|
+
|
|
|
+/* Optional stress test. Define to consume memory until exhausted: */
|
|
|
+#define MEMORY_STRESS_TEST
|
|
|
+
|
|
|
+/* Choose client or server example, not both. */
|
|
|
+#define WOLFSSL_CLIENT_EXAMPLE
|
|
|
+/* #define WOLFSSL_SERVER_EXAMPLE */
|
|
|
+
|
|
|
+#if defined(MY_PRIVATE_CONFIG)
|
|
|
+ /* the /workspace directory may contain a private config
|
|
|
+ * excluded from GitHub with items such as WiFi passwords */
|
|
|
+ #include MY_PRIVATE_CONFIG
|
|
|
+ const char* ssid PROGMEM = CONFIG_ESP_WIFI_SSID;
|
|
|
+ const char* password PROGMEM = CONFIG_ESP_WIFI_PASSWORD;
|
|
|
+#else
|
|
|
+ /* when using WiFi capable boards: */
|
|
|
+ const char* ssid PROGMEM = "your_SSID";
|
|
|
+ const char* password PROGMEM = "your_PASSWORD";
|
|
|
+#endif
|
|
|
+
|
|
|
+#define BROADCAST_ADDRESS "255.255.255.255"
|
|
|
+
|
|
|
+/* There's an optional 3rd party NTPClient library by Fabrice Weinberg.
|
|
|
+ * If it is installed, uncomment define USE_NTP_LIB here: */
|
|
|
+/* #define USE_NTP_LIB */
|
|
|
+#ifdef USE_NTP_LIB
|
|
|
+ #include <NTPClient.h>
|
|
|
+#endif
|
|
|
+
|
|
|
#include <wolfssl.h>
|
|
|
+/* Important: make sure settings.h appears before any other wolfSSL headers */
|
|
|
+#include <wolfssl/wolfcrypt/settings.h>
|
|
|
+/* Reminder: settings.h includes user_settings.h
|
|
|
+ * For ALL project wolfSSL settings, see:
|
|
|
+ * [your path]/Arduino\libraries\wolfSSL\src\user_settings.h */
|
|
|
#include <wolfssl/ssl.h>
|
|
|
-#include <Ethernet.h>
|
|
|
#include <wolfssl/certs_test.h>
|
|
|
+#include <wolfssl/wolfcrypt/error-crypt.h>
|
|
|
+
|
|
|
+/* Define DEBUG_WOLFSSL in user_settings.h for more verbose logging. */
|
|
|
+#if defined(DEBUG_WOLFSSL)
|
|
|
+ #define PROGRESS_DOT F("")
|
|
|
+#else
|
|
|
+ #define PROGRESS_DOT F(".")
|
|
|
+#endif
|
|
|
+
|
|
|
+/* Convert a macro to a string */
|
|
|
+#define xstr(x) str(x)
|
|
|
+#define str(x) #x
|
|
|
+
|
|
|
+/* optional board-specific networking includes */
|
|
|
+#if defined(ESP32)
|
|
|
+ #define USING_WIFI
|
|
|
+ #include <WiFi.h>
|
|
|
+ #include <WiFiUdp.h>
|
|
|
+ #ifdef USE_NTP_LIB
|
|
|
+ WiFiUDP ntpUDP;
|
|
|
+ #endif
|
|
|
+ /* Ensure the F() flash macro is defined */
|
|
|
+ #ifndef F
|
|
|
+ #define F
|
|
|
+ #endif
|
|
|
+ WiFiClient client;
|
|
|
+
|
|
|
+#elif defined(ESP8266)
|
|
|
+ #define USING_WIFI
|
|
|
+ #include <ESP8266WiFi.h>
|
|
|
+ WiFiClient client;
|
|
|
+
|
|
|
+#elif defined(ARDUINO_SAM_DUE)
|
|
|
+ #include <SPI.h>
|
|
|
+ /* There's no WiFi/Ethernet on the Due. Requires Ethernet Shield.
|
|
|
+ /* Needs "Ethernet by Various" library to be installed. Tested with V2.0.2 */
|
|
|
+ #include <Ethernet.h>
|
|
|
+ EthernetClient client;
|
|
|
+
|
|
|
+#elif defined(ARDUINO_SAMD_NANO_33_IOT)
|
|
|
+ #define USING_WIFI
|
|
|
+ #include <SPI.h>
|
|
|
+ #include <WiFiNINA.h>
|
|
|
+ WiFiClient client;
|
|
|
+
|
|
|
+#elif defined(ARDUINO_ARCH_RP2040)
|
|
|
+ #define USING_WIFI
|
|
|
+ #include <SPI.h>
|
|
|
+ #include <WiFiNINA.h>
|
|
|
+ WiFiClient client;
|
|
|
|
|
|
+#elif defined(USING_WIFI)
|
|
|
+ #define USING_WIFI
|
|
|
+ #include <WiFi.h>
|
|
|
+ #include <WiFiUdp.h>
|
|
|
+ #ifdef USE_NTP_LIB
|
|
|
+ WiFiUDP ntpUDP;
|
|
|
+ #endif
|
|
|
+ WiFiClient client;
|
|
|
|
|
|
-const char host[] = "192.168.1.148"; /* server to connect to */
|
|
|
-const int port = 11111; /* port on server to connect to */
|
|
|
+/* TODO
|
|
|
+#elif defined(OTHER_BOARD)
|
|
|
+*/
|
|
|
+#else
|
|
|
+ #define USING_WIFI
|
|
|
+ WiFiClient client;
|
|
|
+
|
|
|
+#endif
|
|
|
|
|
|
-int EthernetSend(WOLFSSL* ssl, char* msg, int sz, void* ctx);
|
|
|
-int EthernetReceive(WOLFSSL* ssl, char* reply, int sz, void* ctx);
|
|
|
-int reconnect = 10;
|
|
|
+/* Only for syntax highlighters to show interesting options enabled: */
|
|
|
+#if defined(HAVE_SNI) \
|
|
|
+ || defined(HAVE_MAX_FRAGMENT) \
|
|
|
+ || defined(HAVE_TRUSTED_CA) \
|
|
|
+ || defined(HAVE_TRUNCATED_HMAC) \
|
|
|
+ || defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
|
|
|
+ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) \
|
|
|
+ || defined(HAVE_SUPPORTED_CURVES) \
|
|
|
+ || defined(HAVE_ALPN) \
|
|
|
+ || defined(HAVE_SESSION_TICKET) \
|
|
|
+ || defined(HAVE_SECURE_RENEGOTIATION) \
|
|
|
+ || defined(HAVE_SERVER_RENEGOTIATION_INFO)
|
|
|
+#endif
|
|
|
|
|
|
-EthernetClient client;
|
|
|
+const char host[] PROGMEM = WOLFSSL_TLS_SERVER_HOST; /* server to connect to */
|
|
|
+const int port PROGMEM = WOLFSSL_PORT; /* port on server to connect to */
|
|
|
+const int serial_baud PROGMEM = SERIAL_BAUD; /* local serial port to monitor */
|
|
|
|
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
|
WOLFSSL* ssl = NULL;
|
|
|
+char* wc_error_message = (char*)malloc(80 + 1);
|
|
|
+char errBuf[80];
|
|
|
+
|
|
|
+#if defined(MEMORY_STRESS_TEST)
|
|
|
+ #define MEMORY_STRESS_ITERATIONS 100
|
|
|
+ #define MEMORY_STRESS_BLOCK_SIZE 1024
|
|
|
+ #define MEMORY_STRESS_INITIAL (4*1024)
|
|
|
+ char* memory_stress[MEMORY_STRESS_ITERATIONS]; /* typically 1K per item */
|
|
|
+ int mem_ctr = 0;
|
|
|
+#endif
|
|
|
+
|
|
|
+static int EthernetSend(WOLFSSL* ssl, char* msg, int sz, void* ctx);
|
|
|
+static int EthernetReceive(WOLFSSL* ssl, char* reply, int sz, void* ctx);
|
|
|
+static int reconnect = RECONNECT_ATTEMPTS;
|
|
|
+static int lng_index PROGMEM = 0; /* 0 = English */
|
|
|
+
|
|
|
+#if defined(__arm__)
|
|
|
+ #include <malloc.h>
|
|
|
+ extern char _end;
|
|
|
+ extern "C" char *sbrk(int i);
|
|
|
+ char *ramstart=(char *)0x20070000;
|
|
|
+ char *ramend=(char *)0x20088000;
|
|
|
+#endif
|
|
|
+
|
|
|
+/*****************************************************************************/
|
|
|
+/* fail_wait - in case of unrecoverable error */
|
|
|
+/*****************************************************************************/
|
|
|
+int fail_wait(void) {
|
|
|
+ show_memory();
|
|
|
+
|
|
|
+ Serial.println(F("Failed. Halt."));
|
|
|
+ while (1) {
|
|
|
+ delay(1000);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************************************************/
|
|
|
+/* show_memory() to optionally view during debugging. */
|
|
|
+/*****************************************************************************/
|
|
|
+int show_memory(void)
|
|
|
+{
|
|
|
+#if defined(__arm__)
|
|
|
+ struct mallinfo mi = mallinfo();
|
|
|
+
|
|
|
+ char *heapend=sbrk(0);
|
|
|
+ register char * stack_ptr asm("sp");
|
|
|
+ #if defined(DEBUG_WOLFSSL_VERBOSE)
|
|
|
+ Serial.print(" arena=");
|
|
|
+ Serial.println(mi.arena);
|
|
|
+ Serial.print(" ordblks=");
|
|
|
+ Serial.println(mi.ordblks);
|
|
|
+ Serial.print(" uordblks=");
|
|
|
+ Serial.println(mi.uordblks);
|
|
|
+ Serial.print(" fordblks=");
|
|
|
+ Serial.println(mi.fordblks);
|
|
|
+ Serial.print(" keepcost=");
|
|
|
+ Serial.println(mi.keepcost);
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if defined(DEBUG_WOLFSSL) || defined(MEMORY_STRESS_TEST)
|
|
|
+ Serial.print("Estimated free memory: ");
|
|
|
+ Serial.print(stack_ptr - heapend + mi.fordblks);
|
|
|
+ Serial.println(F(" bytes"));
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if (0)
|
|
|
+ /* Experimental: not supported on all devices: */
|
|
|
+ Serial.print("RAM Start %lx\n", (unsigned long)ramstart);
|
|
|
+ Serial.print("Data/Bss end %lx\n", (unsigned long)&_end);
|
|
|
+ Serial.print("Heap End %lx\n", (unsigned long)heapend);
|
|
|
+ Serial.print("Stack Ptr %lx\n",(unsigned long)stack_ptr);
|
|
|
+ Serial.print("RAM End %lx\n", (unsigned long)ramend);
|
|
|
+
|
|
|
+ Serial.print("Heap RAM Used: ",mi.uordblks);
|
|
|
+ Serial.print("Program RAM Used ",&_end - ramstart);
|
|
|
+ Serial.print("Stack RAM Used ",ramend - stack_ptr);
|
|
|
+
|
|
|
+ Serial.print("Estimated Free RAM: %d\n\n",stack_ptr - heapend + mi.fordblks);
|
|
|
+ #endif
|
|
|
+#else
|
|
|
+ Serial.println(F("show_memory() not implemented for this platform"));
|
|
|
+#endif
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************************************************/
|
|
|
+/* EthernetSend() to send a message string. */
|
|
|
+/*****************************************************************************/
|
|
|
+int EthernetSend(WOLFSSL* ssl, char* message, int sz, void* ctx) {
|
|
|
+ int sent = 0;
|
|
|
+ (void)ssl;
|
|
|
+ (void)ctx;
|
|
|
+
|
|
|
+ sent = client.write((byte*)message, sz);
|
|
|
+ return sent;
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************************************************/
|
|
|
+/* EthernetReceive() to receive a reply string. */
|
|
|
+/*****************************************************************************/
|
|
|
+int EthernetReceive(WOLFSSL* ssl, char* reply, int sz, void* ctx) {
|
|
|
+ int ret = 0;
|
|
|
+ (void)ssl;
|
|
|
+ (void)ctx;
|
|
|
+
|
|
|
+ while (client.available() > 0 && ret < sz) {
|
|
|
+ reply[ret++] = client.read();
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************************************************/
|
|
|
+/* Arduino setup_hardware() */
|
|
|
+/*****************************************************************************/
|
|
|
+int setup_hardware(void) {
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+#if defined(ARDUINO_SAMD_NANO_33_IOT)
|
|
|
+ Serial.println(F("Detected known tested and working Arduino Nano 33 IoT"));
|
|
|
+#elif defined(ARDUINO_ARCH_RP2040)
|
|
|
+ Serial.println(F("Detected known tested and working Arduino RP-2040"));
|
|
|
+#elif defined(__arm__) && defined(ID_TRNG) && defined(TRNG)
|
|
|
+ /* need to manually turn on random number generator on Arduino Due, etc. */
|
|
|
+ pmc_enable_periph_clk(ID_TRNG);
|
|
|
+ trng_enable(TRNG);
|
|
|
+ Serial.println(F("Enabled ARM TRNG"));
|
|
|
+#endif
|
|
|
+
|
|
|
+ show_memory();
|
|
|
+ randomSeed(analogRead(0));
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************************************************/
|
|
|
+/* Arduino setup_datetime() */
|
|
|
+/* The device needs to have a valid date within the valid range of certs. */
|
|
|
+/*****************************************************************************/
|
|
|
+int setup_datetime(void) {
|
|
|
+ int ret = 0;
|
|
|
+ int ntp_tries = 20;
|
|
|
+
|
|
|
+ /* we need a date in the range of cert expiration */
|
|
|
+#ifdef USE_NTP_LIB
|
|
|
+ #if defined(ESP32)
|
|
|
+ NTPClient timeClient(ntpUDP, "pool.ntp.org");
|
|
|
+
|
|
|
+ timeClient.begin();
|
|
|
+ timeClient.update();
|
|
|
+ delay(1000);
|
|
|
+ while (!timeClient.isTimeSet() && (ntp_tries > 0)) {
|
|
|
+ timeClient.forceUpdate();
|
|
|
+ Serial.println(F("Waiting for NTP update"));
|
|
|
+ delay(2000);
|
|
|
+ ntp_tries--;
|
|
|
+ }
|
|
|
+ if (ntp_tries <= 0) {
|
|
|
+ Serial.println(F("Warning: gave up waiting on NTP"));
|
|
|
+ }
|
|
|
+ Serial.println(timeClient.getFormattedTime());
|
|
|
+ Serial.println(timeClient.getEpochTime());
|
|
|
+ #endif
|
|
|
+#endif
|
|
|
+
|
|
|
+#if defined(ESP32)
|
|
|
+ /* see esp32-hal-time.c */
|
|
|
+ ntp_tries = 5;
|
|
|
+ /* Replace "pool.ntp.org" with your preferred NTP server */
|
|
|
+ configTime(0, 0, "pool.ntp.org");
|
|
|
+
|
|
|
+ /* Wait for time to be set */
|
|
|
+ while ((time(nullptr) <= 100000) && ntp_tries > 0) {
|
|
|
+ Serial.println(F("Waiting for time to be set..."));
|
|
|
+ delay(2000);
|
|
|
+ ntp_tries--;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ return ret;
|
|
|
+} /* setup_datetime */
|
|
|
+
|
|
|
+/*****************************************************************************/
|
|
|
+/* Arduino setup_network() */
|
|
|
+/*****************************************************************************/
|
|
|
+int setup_network(void) {
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+#if defined(USING_WIFI)
|
|
|
+ int status = WL_IDLE_STATUS;
|
|
|
|
|
|
-void setup() {
|
|
|
+ if (WiFi.status() == WL_NO_MODULE) {
|
|
|
+ Serial.println("Communication with WiFi module failed!");
|
|
|
+ /* don't continue if no network */
|
|
|
+ while (true) ;
|
|
|
+ }
|
|
|
+
|
|
|
+ String fv = WiFi.firmwareVersion();
|
|
|
+ if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
|
|
|
+ Serial.println("Please upgrade the firmware");
|
|
|
+ }
|
|
|
+
|
|
|
+ /* The ESP8266 & ESP32 support both AP and STA. We'll use STA: */
|
|
|
+ #if defined(ESP8266) || defined(ESP32)
|
|
|
+ WiFi.mode(WIFI_STA);
|
|
|
+ #endif
|
|
|
+
|
|
|
+ Serial.print(F("Connecting to WiFi "));
|
|
|
+ Serial.print(ssid);
|
|
|
+ while (status != WL_CONNECTED) {
|
|
|
+ status = WiFi.begin(ssid, password);
|
|
|
+ delay(5000);
|
|
|
+ Serial.print(F("."));
|
|
|
+ }
|
|
|
+
|
|
|
+ Serial.println(F(" Connected!"));
|
|
|
+#else
|
|
|
+ /* Newer Ethernet shields have a
|
|
|
+ * MAC address printed on a sticker on the shield */
|
|
|
+ byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
|
|
+ IPAddress ip(192, 168, 1, 42);
|
|
|
+ IPAddress myDns(192, 168, 1, 1);
|
|
|
+ Ethernet.init(10); /* Most Arduino shields */
|
|
|
+ /* Ethernet.init(5); * MKR ETH Shield */
|
|
|
+ /* Ethernet.init(0); * Teensy 2.0 */
|
|
|
+ /* Ethernet.init(20); * Teensy++ 2.0 */
|
|
|
+ /* Ethernet.init(15); * ESP8266 with Adafruit FeatherWing Ethernet */
|
|
|
+ /* Ethernet.init(33); * ESP32 with Adafruit FeatherWing Ethernet */
|
|
|
+ Serial.println(F("Initialize Ethernet with DHCP:"));
|
|
|
+ if (Ethernet.begin(mac) == 0) {
|
|
|
+ Serial.println(F("Failed to configure Ethernet using DHCP"));
|
|
|
+ /* Check for Ethernet hardware present */
|
|
|
+ if (Ethernet.hardwareStatus() == EthernetNoHardware) {
|
|
|
+ Serial.println(F("Ethernet shield was not found."));
|
|
|
+ while (true) {
|
|
|
+ delay(1); /* do nothing */
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (Ethernet.linkStatus() == LinkOFF) {
|
|
|
+ Serial.println(F("Ethernet cable is not connected."));
|
|
|
+ }
|
|
|
+ /* try to configure using IP address instead of DHCP : */
|
|
|
+ Ethernet.begin(mac, ip, myDns);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Serial.print(F(" DHCP assigned IP "));
|
|
|
+ Serial.println(Ethernet.localIP());
|
|
|
+ }
|
|
|
+ /* We'll assume the Ethernet connection is ready to go. */
|
|
|
+#endif
|
|
|
+
|
|
|
+ Serial.println(F("********************************************************"));
|
|
|
+ Serial.print(F(" wolfSSL Example Client IP = "));
|
|
|
+#if defined(USING_WIFI)
|
|
|
+ Serial.println(WiFi.localIP());
|
|
|
+#else
|
|
|
+ Serial.println(Ethernet.localIP());
|
|
|
+#endif
|
|
|
+ Serial.print(F(" Configured Server Host to connect to: "));
|
|
|
+ Serial.println(host);
|
|
|
+ Serial.println(F("********************************************************"));
|
|
|
+ Serial.println(F("Setup network complete."));
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************************************************/
|
|
|
+/* Arduino setup_wolfssl() */
|
|
|
+/*****************************************************************************/
|
|
|
+int setup_wolfssl(void) {
|
|
|
+ int ret = 0;
|
|
|
WOLFSSL_METHOD* method;
|
|
|
- /* Initialize Return Code */
|
|
|
- int rc;
|
|
|
- Serial.begin(9600);
|
|
|
- /* Delay need to ensure connection to server */
|
|
|
- delay(4000);
|
|
|
|
|
|
- method = wolfTLSv1_2_client_method();
|
|
|
+ /* Show a revision of wolfssl user_settings.h file in use when available: */
|
|
|
+#if defined(WOLFSSL_USER_SETTINGS_ID)
|
|
|
+ Serial.print(F("WOLFSSL_USER_SETTINGS_ID: "));
|
|
|
+ Serial.println(F(WOLFSSL_USER_SETTINGS_ID));
|
|
|
+#else
|
|
|
+ Serial.println(F("No WOLFSSL_USER_SETTINGS_ID found."));
|
|
|
+#endif
|
|
|
+
|
|
|
+#if defined(NO_WOLFSSL_SERVER)
|
|
|
+ Serial.println(F("wolfSSL server code disabled to save space."));
|
|
|
+#endif
|
|
|
+#if defined(NO_WOLFSSL_CLIENT)
|
|
|
+ Serial.println(F("wolfSSL client code disabled to save space."));
|
|
|
+#endif
|
|
|
+
|
|
|
+#if defined(DEBUG_WOLFSSL)
|
|
|
+ wolfSSL_Debugging_ON();
|
|
|
+ Serial.println(F("wolfSSL Debugging is On!"));
|
|
|
+#else
|
|
|
+ Serial.println(F("wolfSSL Debugging is Off! (enable with DEBUG_WOLFSSL)"));
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* See ssl.c for TLS cache settings. Larger cache = use more RAM. */
|
|
|
+#if defined(NO_SESSION_CACHE)
|
|
|
+ Serial.println(F("wolfSSL TLS NO_SESSION_CACHE"));
|
|
|
+#elif defined(MICRO_SESSION_CACHEx)
|
|
|
+ Serial.println(F("wolfSSL TLS MICRO_SESSION_CACHE"));
|
|
|
+#elif defined(SMALL_SESSION_CACHE)
|
|
|
+ Serial.println(F("wolfSSL TLS SMALL_SESSION_CACHE"));
|
|
|
+#elif defined(MEDIUM_SESSION_CACHE)
|
|
|
+ Serial.println(F("wolfSSL TLS MEDIUM_SESSION_CACHE"));
|
|
|
+#elif defined(BIG_SESSION_CACHE)
|
|
|
+ Serial.println(F("wolfSSL TLS BIG_SESSION_CACHE"));
|
|
|
+#elif defined(HUGE_SESSION_CACHE)
|
|
|
+ Serial.println(F("wolfSSL TLS HUGE_SESSION_CACHE"));
|
|
|
+#elif defined(HUGE_SESSION_CACHE)
|
|
|
+ Serial.println(F("wolfSSL TLS HUGE_SESSION_CACHE"));
|
|
|
+#else
|
|
|
+ Serial.println(F("WARNING: Unknown or no TLS session cache setting."));
|
|
|
+ /* See wolfssl/src/ssl.c for amount of memory used.
|
|
|
+ * It is best on embedded devices to choose a TLS session cache size. */
|
|
|
+#endif
|
|
|
+
|
|
|
+ ret = wolfSSL_Init();
|
|
|
+ if (ret == WOLFSSL_SUCCESS) {
|
|
|
+ Serial.println("Successfully called wolfSSL_Init");
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Serial.println("ERROR: wolfSSL_Init failed");
|
|
|
+ }
|
|
|
+
|
|
|
+ /* See companion server example with wolfSSLv23_server_method here.
|
|
|
+ * method = wolfSSLv23_client_method()); SSL 3.0 - TLS 1.3.
|
|
|
+ * method = wolfTLSv1_2_client_method(); only TLS 1.2
|
|
|
+ * method = wolfTLSv1_3_client_method(); only TLS 1.3
|
|
|
+ *
|
|
|
+ * see Arduino\libraries\wolfssl\src\user_settings.h */
|
|
|
+
|
|
|
+ Serial.println("Here we go!");
|
|
|
+
|
|
|
+ method = wolfSSLv23_client_method();
|
|
|
if (method == NULL) {
|
|
|
- Serial.println("unable to get method");
|
|
|
- return;
|
|
|
+ Serial.println(F("unable to get wolfssl client method"));
|
|
|
+ fail_wait();
|
|
|
}
|
|
|
ctx = wolfSSL_CTX_new(method);
|
|
|
if (ctx == NULL) {
|
|
|
- Serial.println("unable to get ctx");
|
|
|
- return;
|
|
|
+ Serial.println(F("unable to get ctx"));
|
|
|
+ fail_wait();
|
|
|
}
|
|
|
- /* initialize wolfSSL using callback functions */
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************************************************/
|
|
|
+/* Arduino setup_certificates() */
|
|
|
+/*****************************************************************************/
|
|
|
+int setup_certificates(void) {
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ Serial.println(F("Initializing certificates..."));
|
|
|
+ show_memory();
|
|
|
+
|
|
|
+ /* Use built-in validation, No verification callback function: */
|
|
|
wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, 0);
|
|
|
- rc = wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_der_2048,\
|
|
|
- sizeof_ca_cert_der_2048,\
|
|
|
- WOLFSSL_FILETYPE_ASN1);
|
|
|
- Serial.print("\n\n Return code of load_verify is:");
|
|
|
- Serial.println(rc);
|
|
|
- Serial.println("");
|
|
|
- rc = wolfSSL_CTX_use_certificate_buffer(ctx, client_cert_der_2048,\
|
|
|
- sizeof_client_cert_der_2048,\
|
|
|
- WOLFSSL_FILETYPE_ASN1);
|
|
|
- Serial.print("\n\n Return code of use_certificate_buffer is:");
|
|
|
- Serial.println(rc);
|
|
|
- Serial.println("");
|
|
|
- rc = wolfSSL_CTX_use_PrivateKey_buffer(ctx, client_key_der_2048,\
|
|
|
- sizeof_client_key_der_2048,\
|
|
|
- WOLFSSL_FILETYPE_ASN1);
|
|
|
- Serial.print("\n\n Return code of use_PrivateKey_buffer is:");
|
|
|
- Serial.println(rc);
|
|
|
- Serial.println("");
|
|
|
+
|
|
|
+ /* Certificate */
|
|
|
+ Serial.println("Initializing certificates...");
|
|
|
+ ret = wolfSSL_CTX_use_certificate_buffer(ctx,
|
|
|
+ CTX_CLIENT_CERT,
|
|
|
+ CTX_CLIENT_CERT_SIZE,
|
|
|
+ CTX_CLIENT_CERT_TYPE);
|
|
|
+ if (ret == WOLFSSL_SUCCESS) {
|
|
|
+ Serial.print("Success: use certificate: ");
|
|
|
+ Serial.println(xstr(CTX_SERVER_CERT));
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Serial.println(F("Error: wolfSSL_CTX_use_certificate_buffer failed: "));
|
|
|
+ wc_ErrorString(ret, wc_error_message);
|
|
|
+ Serial.println(wc_error_message);
|
|
|
+ fail_wait();
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Setup private client key */
|
|
|
+ ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx,
|
|
|
+ CTX_CLIENT_KEY,
|
|
|
+ CTX_CLIENT_KEY_SIZE,
|
|
|
+ CTX_CLIENT_KEY_TYPE);
|
|
|
+ if (ret == WOLFSSL_SUCCESS) {
|
|
|
+ Serial.print("Success: use private key buffer: ");
|
|
|
+ Serial.println(xstr(CTX_SERVER_KEY));
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Serial.println(F("Error: wolfSSL_CTX_use_PrivateKey_buffer failed: "));
|
|
|
+ wc_ErrorString(ret, wc_error_message);
|
|
|
+ Serial.println(wc_error_message);
|
|
|
+ fail_wait();
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = wolfSSL_CTX_load_verify_buffer(ctx,
|
|
|
+ CTX_CA_CERT,
|
|
|
+ CTX_CA_CERT_SIZE,
|
|
|
+ CTX_CA_CERT_TYPE);
|
|
|
+ if (ret == WOLFSSL_SUCCESS) {
|
|
|
+ Serial.println(F("Success: load_verify CTX_CA_CERT"));
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Serial.println(F("Error: wolfSSL_CTX_load_verify_buffer failed: "));
|
|
|
+ wc_ErrorString(ret, wc_error_message);
|
|
|
+ Serial.println(wc_error_message);
|
|
|
+ fail_wait();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ return ret;
|
|
|
+} /* Arduino setup */
|
|
|
+
|
|
|
+/*****************************************************************************/
|
|
|
+/*****************************************************************************/
|
|
|
+/* Arduino setup() */
|
|
|
+/*****************************************************************************/
|
|
|
+/*****************************************************************************/
|
|
|
+void setup(void) {
|
|
|
+ Serial.begin(serial_baud);
|
|
|
+ while (!Serial) {
|
|
|
+ /* wait for serial port to connect. Needed for native USB port only */
|
|
|
+ }
|
|
|
+ Serial.println(F(""));
|
|
|
+ Serial.println(F(""));
|
|
|
+ Serial.println(F("wolfSSL TLS Client Example Startup."));
|
|
|
+
|
|
|
+ /* define DEBUG_WOLFSSL in wolfSSL user_settings.h for diagnostics */
|
|
|
+#if defined(DEBUG_WOLFSSL)
|
|
|
+ wolfSSL_Debugging_ON();
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Optionally pre-allocate a large block of memory for testing */
|
|
|
+#if defined(MEMORY_STRESS_TEST)
|
|
|
+ Serial.println(F("WARNING: Memory Stress Test Active!"));
|
|
|
+ Serial.print(F("Allocating extra memory: "));
|
|
|
+ Serial.print(MEMORY_STRESS_INITIAL);
|
|
|
+ Serial.println(F(" bytes..."));
|
|
|
+ memory_stress[mem_ctr] = (char*)malloc(MEMORY_STRESS_INITIAL);
|
|
|
+ show_memory();
|
|
|
+#endif
|
|
|
+
|
|
|
+ setup_hardware();
|
|
|
+
|
|
|
+ setup_datetime();
|
|
|
+
|
|
|
+ setup_network();
|
|
|
+
|
|
|
+ setup_wolfssl();
|
|
|
+
|
|
|
+ setup_certificates();
|
|
|
+
|
|
|
+ /* Initialize wolfSSL using callback functions. */
|
|
|
wolfSSL_SetIOSend(ctx, EthernetSend);
|
|
|
wolfSSL_SetIORecv(ctx, EthernetReceive);
|
|
|
- return;
|
|
|
-}
|
|
|
|
|
|
-int EthernetSend(WOLFSSL* ssl, char* msg, int sz, void* ctx) {
|
|
|
- int sent = 0;
|
|
|
- sent = client.write((byte*)msg, sz);
|
|
|
- return sent;
|
|
|
-}
|
|
|
+ Serial.println(F("Completed Arduino setup!"));
|
|
|
+ /* See companion wolfssl_server.ino code; server begins listening here
|
|
|
+ * https://github.com/wolfSSL/wolfssl/tree/master/IDE/ARDUINO/sketches/wolfssl_server
|
|
|
+ * Any other server will work. See also:
|
|
|
+ * https://github.com/wolfSSL/wolfssl/tree/master/examples/client
|
|
|
+ */
|
|
|
+ /* See companion wolfssl_server.ino code */
|
|
|
+ return;
|
|
|
+} /* Arduino setup */
|
|
|
|
|
|
-int EthernetReceive(WOLFSSL* ssl, char* reply, int sz, void* ctx) {
|
|
|
+/*****************************************************************************/
|
|
|
+/* wolfSSL error_check() */
|
|
|
+/*****************************************************************************/
|
|
|
+int error_check(int this_ret, bool halt_on_error,
|
|
|
+ const __FlashStringHelper* message) {
|
|
|
int ret = 0;
|
|
|
- while (client.available() > 0 && ret < sz) {
|
|
|
- reply[ret++] = client.read();
|
|
|
+ if (this_ret == WOLFSSL_SUCCESS) {
|
|
|
+ Serial.print(F("Success: "));
|
|
|
+ Serial.println(message);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Serial.print(F("ERROR: return = "));
|
|
|
+ Serial.print(this_ret);
|
|
|
+ Serial.print(F(": "));
|
|
|
+ Serial.println(message);
|
|
|
+ Serial.println(wc_GetErrorString(this_ret));
|
|
|
+ if (halt_on_error) {
|
|
|
+ fail_wait();
|
|
|
+ }
|
|
|
}
|
|
|
+ show_memory();
|
|
|
+
|
|
|
return ret;
|
|
|
+} /* error_check */
|
|
|
+
|
|
|
+/*****************************************************************************/
|
|
|
+/* wolfSSL error_check_ssl */
|
|
|
+/* Parameters: */
|
|
|
+/* ssl is the current WOLFSSL object pointer */
|
|
|
+/* halt_on_error set to true to suspend operations for critical error */
|
|
|
+/* message is expected to be a memory-efficient F("") macro string */
|
|
|
+/*****************************************************************************/
|
|
|
+int error_check_ssl(WOLFSSL* ssl, int this_ret, bool halt_on_error,
|
|
|
+ const __FlashStringHelper* message) {
|
|
|
+ int err = 0;
|
|
|
+
|
|
|
+ if (ssl == NULL) {
|
|
|
+ Serial.println(F("ssl is Null; Unable to allocate SSL object?"));
|
|
|
+#ifndef DEBUG_WOLFSSL
|
|
|
+ Serial.println(F("Define DEBUG_WOLFSSL in user_settings.h for more."));
|
|
|
+#else
|
|
|
+ Serial.println(F("See wolfssl/wolfcrypt/error-crypt.h for codes."));
|
|
|
+#endif
|
|
|
+ Serial.print(F("ERROR: "));
|
|
|
+ Serial.println(message);
|
|
|
+ show_memory();
|
|
|
+ if (halt_on_error) {
|
|
|
+ fail_wait();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ err = wolfSSL_get_error(ssl, this_ret);
|
|
|
+ if (err == WOLFSSL_SUCCESS) {
|
|
|
+ Serial.print(F("Success m: "));
|
|
|
+ Serial.println(message);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (err < 0) {
|
|
|
+ wolfSSL_ERR_error_string(err, errBuf);
|
|
|
+ Serial.print(F("WOLFSSL Error: "));
|
|
|
+ Serial.print(err);
|
|
|
+ Serial.print(F("; "));
|
|
|
+ Serial.println(errBuf);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Serial.println(F("Success: ssl object."));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
+/*****************************************************************************/
|
|
|
+/*****************************************************************************/
|
|
|
+/* Arduino loop() */
|
|
|
+/*****************************************************************************/
|
|
|
+/*****************************************************************************/
|
|
|
void loop() {
|
|
|
- int err = 0;
|
|
|
- int input = 0;
|
|
|
- int total_input = 0;
|
|
|
- char msg[32] = "hello wolfssl!";
|
|
|
- int msgSz = (int)strlen(msg);
|
|
|
- char errBuf[80];
|
|
|
char reply[80];
|
|
|
+ char msg[32] = "hello wolfssl!";
|
|
|
const char* cipherName;
|
|
|
+ int retry_shutdown = SHUTDOWN_DELAY_MS; /* max try, once per millisecond */
|
|
|
+ int total_input = 0;
|
|
|
+ int msgSz = 0;
|
|
|
+ int input = 0;
|
|
|
+ int ret = 0;
|
|
|
+ int err = 0;
|
|
|
+ msgSz = (int)strlen(msg);
|
|
|
+ Serial.println(F(""));
|
|
|
+ Serial.println(F("Starting Arduino loop() ..."));
|
|
|
+
|
|
|
if (reconnect) {
|
|
|
reconnect--;
|
|
|
- if (client.connect(host, port)) {
|
|
|
- Serial.print("Connected to ");
|
|
|
- Serial.println(host);
|
|
|
+ /* WiFi client returns true if connection succeeds, false if not. */
|
|
|
+ /* Wired client returns int (1,-1,-2,-3,-4) for connection status. */
|
|
|
+ Serial.print(F("Connecting to "));
|
|
|
+ Serial.print(host);
|
|
|
+ Serial.print(F(":"));
|
|
|
+ Serial.println(port);
|
|
|
+ /* can also use: IPAddress server(192,168,1,37); */
|
|
|
+ Serial.println(F("Here we go..."));
|
|
|
+ ret = client.connect(host, port);
|
|
|
+ Serial.println(F("Ok, checking..."));
|
|
|
+ if (ret > 0) {
|
|
|
+ Serial.println(F("Connected!"));
|
|
|
+
|
|
|
+ /* initialize wolfSSL */
|
|
|
+ ret = wolfSSL_Init();
|
|
|
+ error_check(ret, false, F("calling wolfSSL_Init") );
|
|
|
+
|
|
|
+ /* create secure connection object. see setup for ctx certs. */
|
|
|
+ Serial.println(F("Calling ssl = wolfSSL_new(ctx)"));
|
|
|
ssl = wolfSSL_new(ctx);
|
|
|
- if (ssl == NULL) {
|
|
|
- Serial.println("Unable to allocate SSL object");
|
|
|
- return;
|
|
|
- }
|
|
|
- err = wolfSSL_connect(ssl);
|
|
|
- if (err != WOLFSSL_SUCCESS) {
|
|
|
- err = wolfSSL_get_error(ssl, 0);
|
|
|
- wolfSSL_ERR_error_string(err, errBuf);
|
|
|
- Serial.print("TLS Connect Error: ");
|
|
|
- Serial.println(errBuf);
|
|
|
- }
|
|
|
- Serial.print("SSL version is ");
|
|
|
+ error_check_ssl(ssl, 0, true, F("Create WOLFSSL object from ctx"));
|
|
|
+
|
|
|
+ Serial.print(F("Connecting to wolfSSL TLS Secure Server..."));
|
|
|
+ do {
|
|
|
+ err = 0; /* reset error */
|
|
|
+ Serial.println(F("wolfSSL_connect ..."));
|
|
|
+ ret = wolfSSL_connect(ssl);
|
|
|
+ Serial.print("wolfSSL_connect return result =");
|
|
|
+ Serial.println(ret);
|
|
|
+ if ((ret != WOLFSSL_SUCCESS) && (ret != WC_PENDING_E)) {
|
|
|
+ Serial.println(F("Failed connection, checking error."));
|
|
|
+ err = error_check_ssl(ssl, ret, true,
|
|
|
+ F("Create WOLFSSL object from ctx"));
|
|
|
+ Serial.print("err =");
|
|
|
+ Serial.println(err);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ Serial.print(PROGRESS_DOT);
|
|
|
+ }
|
|
|
+ } while (err == WC_PENDING_E);
|
|
|
+
|
|
|
+ Serial.println();
|
|
|
+ Serial.println(F("Connected!"));
|
|
|
+ Serial.print(F("SSL version is "));
|
|
|
Serial.println(wolfSSL_get_version(ssl));
|
|
|
+
|
|
|
cipherName = wolfSSL_get_cipher(ssl);
|
|
|
- Serial.print("SSL cipher suite is ");
|
|
|
+ Serial.print(F("SSL cipher suite is "));
|
|
|
Serial.println(cipherName);
|
|
|
- if ((wolfSSL_write(ssl, msg, msgSz)) == msgSz) {
|
|
|
- Serial.print("Server response: ");
|
|
|
- /* wait for data */
|
|
|
- while (!client.available()) {}
|
|
|
+
|
|
|
+ /* see test.h
|
|
|
+ * TODO: test.h needs a little bit of Arduino work for these:
|
|
|
+ showPeerEx(ssl, lng_index);
|
|
|
+ showPeerPEM(ssl);
|
|
|
+ */
|
|
|
+
|
|
|
+ Serial.print(F("Sending secure message to server: "));
|
|
|
+ Serial.println(msg);
|
|
|
+ ret = wolfSSL_write(ssl, msg, msgSz);
|
|
|
+ if (ret == msgSz) {
|
|
|
+ Serial.print(F("Waiting for Server response..."));
|
|
|
+
|
|
|
+ while (!client.available()) {
|
|
|
+ /* wait for data */
|
|
|
+ delay(1); /* 1 ms delay */
|
|
|
+ }
|
|
|
+
|
|
|
+ Serial.print(F("Reading response.."));
|
|
|
/* read data */
|
|
|
- while (wolfSSL_pending(ssl)) {
|
|
|
- input = wolfSSL_read(ssl, reply, sizeof(reply) - 1);
|
|
|
- total_input += input;
|
|
|
- if (input < 0) {
|
|
|
- err = wolfSSL_get_error(ssl, 0);
|
|
|
- wolfSSL_ERR_error_string(err, errBuf);
|
|
|
- Serial.print("TLS Read Error: ");
|
|
|
- Serial.println(errBuf);
|
|
|
- break;
|
|
|
- }
|
|
|
- else if (input > 0) {
|
|
|
- reply[input] = '\0';
|
|
|
- Serial.print(reply);
|
|
|
+ do {
|
|
|
+ ret = wolfSSL_read(ssl, reply, sizeof(reply) - 1);
|
|
|
+ if (ret < 0) {
|
|
|
+ error_check_ssl(ssl, ret, false,
|
|
|
+ F("during TLS Read"));
|
|
|
}
|
|
|
else {
|
|
|
- Serial.println();
|
|
|
+ Serial.print(PROGRESS_DOT);
|
|
|
}
|
|
|
- }
|
|
|
- }
|
|
|
+ } while (err == WC_PENDING_E);
|
|
|
+ Serial.println();
|
|
|
+
|
|
|
+ Serial.println();
|
|
|
+ Serial.println(reply); /* typically: I hear you fa shizzle! */
|
|
|
+ Serial.println();
|
|
|
+
|
|
|
+ } /* wolfSSL_write message size matched */
|
|
|
else {
|
|
|
- err = wolfSSL_get_error(ssl, 0);
|
|
|
- wolfSSL_ERR_error_string(err, errBuf);
|
|
|
- Serial.print("TLS Write Error: ");
|
|
|
- Serial.println(errBuf);
|
|
|
+ error_check_ssl(ssl, ret, false,
|
|
|
+ F("during TLS Write"));
|
|
|
+ } /* any wolfSSL_write message size mismatch is an error */
|
|
|
+
|
|
|
+ Serial.print(F("Shutting down.."));
|
|
|
+ do {
|
|
|
+ delay(1);
|
|
|
+ Serial.print(PROGRESS_DOT);
|
|
|
+ retry_shutdown--;
|
|
|
+ ret = wolfSSL_shutdown(ssl);
|
|
|
+ } while ( (ret == WOLFSSL_SHUTDOWN_NOT_DONE)
|
|
|
+ && (retry_shutdown > 0)
|
|
|
+ ); /* There may be pending data, so wait until done. */
|
|
|
+ Serial.println();
|
|
|
+
|
|
|
+ if (retry_shutdown <= 0) {
|
|
|
+ /* if wolfSSL_free is called before properly shutting down the
|
|
|
+ * ssl object, undesired results may occur. */
|
|
|
+ Serial.println(F("Warning! Shutdown did not properly complete."));
|
|
|
}
|
|
|
- wolfSSL_shutdown(ssl);
|
|
|
+
|
|
|
wolfSSL_free(ssl);
|
|
|
client.stop();
|
|
|
- Serial.println("Connection complete.");
|
|
|
- reconnect = 0;
|
|
|
- }
|
|
|
+ Serial.println(F("Connection complete."));
|
|
|
+ if (REPEAT_CONNECTION) {
|
|
|
+ reconnect = RECONNECT_ATTEMPTS;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ reconnect = 0;
|
|
|
+ }
|
|
|
+ } /* client.connect(host, port) */
|
|
|
else {
|
|
|
- Serial.println("Trying to reconnect...");
|
|
|
+ Serial.println(F("Problem sending message. Trying to reconnect..."));
|
|
|
}
|
|
|
}
|
|
|
delay(1000);
|
|
|
-}
|
|
|
+ if ((reconnect > 0) && (REPEAT_CONNECTION)) {
|
|
|
+ Serial.println(F("Arduino loop repeating..."));
|
|
|
+ Serial.println();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ printf("wow");
|
|
|
+ Serial.println(F("Done!"));
|
|
|
+ while(1) {
|
|
|
+ /* wait forever */
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+#if defined(MEMORY_STRESS_TEST)
|
|
|
+ if (mem_ctr < MEMORY_STRESS_ITERATIONS) {
|
|
|
+ /* reminder: mem_ctr == 0 is MEMORY_STRESS_INITIAL allocation */
|
|
|
+ mem_ctr++;
|
|
|
+ Serial.print(F("Memory stress increment: "));
|
|
|
+ Serial.print(mem_ctr);
|
|
|
+ Serial.print(F(". Allocating addition memory (bytes): "));
|
|
|
+ Serial.println(MEMORY_STRESS_BLOCK_SIZE);
|
|
|
+ memory_stress[mem_ctr] = (char*)malloc(MEMORY_STRESS_BLOCK_SIZE);
|
|
|
+ show_memory();
|
|
|
+ }
|
|
|
+#endif
|
|
|
+} /* Arduino loop repeats */
|