| 
 | 1 | +/****************************************************************************************************************************  | 
 | 2 | +  Async_AdvancedWebServer_MemoryIssues_Send_CString.ino - Dead simple AsyncWebServer for STM32 LAN8720 or built-in LAN8742A Ethernet  | 
 | 3 | +
  | 
 | 4 | +  For Portenta_H7 (STM32H7) with Vision-Shield Ethernet  | 
 | 5 | +
  | 
 | 6 | +  Portenta_H7_AsyncWebServer is a library for the Portenta_H7 with with Vision-Shield Ethernet  | 
 | 7 | +
  | 
 | 8 | +  Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer)  | 
 | 9 | +  Built by Khoi Hoang https://github.com/khoih-prog/Portenta_H7_AsyncWebServer  | 
 | 10 | +  Licensed under GPLv3 license  | 
 | 11 | +
  | 
 | 12 | +  Copyright (c) 2015, Majenko Technologies  | 
 | 13 | +  All rights reserved.  | 
 | 14 | +
  | 
 | 15 | +  Redistribution and use in source and binary forms, with or without modification,  | 
 | 16 | +  are permitted provided that the following conditions are met:  | 
 | 17 | +
  | 
 | 18 | +  Redistributions of source code must retain the above copyright notice, this  | 
 | 19 | +  list of conditions and the following disclaimer.  | 
 | 20 | +
  | 
 | 21 | +  Redistributions in binary form must reproduce the above copyright notice, this  | 
 | 22 | +  list of conditions and the following disclaimer in the documentation and/or  | 
 | 23 | +  other materials provided with the distribution.  | 
 | 24 | +
  | 
 | 25 | +  Neither the name of Majenko Technologies nor the names of its  | 
 | 26 | +  contributors may be used to endorse or promote products derived from  | 
 | 27 | +  this software without specific prior written permission.  | 
 | 28 | +
  | 
 | 29 | +  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND  | 
 | 30 | +  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED  | 
 | 31 | +  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  | 
 | 32 | +  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  | 
 | 33 | +  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES  | 
 | 34 | +  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  | 
 | 35 | +  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON  | 
 | 36 | +  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT  | 
 | 37 | +  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS  | 
 | 38 | +  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  | 
 | 39 | + *****************************************************************************************************************************/  | 
 | 40 | + | 
 | 41 | +#if !( defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) )  | 
 | 42 | +  #error For Portenta_H7 only  | 
 | 43 | +#endif  | 
 | 44 | + | 
 | 45 | +#define _PORTENTA_H7_ATCP_LOGLEVEL_     1  | 
 | 46 | +#define _PORTENTA_H7_AWS_LOGLEVEL_      1  | 
 | 47 | + | 
 | 48 | +#define USE_ETHERNET_PORTENTA_H7        true  | 
 | 49 | + | 
 | 50 | +#include <Portenta_Ethernet.h>  | 
 | 51 | +#include <Ethernet.h>  | 
 | 52 | +#warning Using Portenta_Ethernet lib for Portenta_H7.  | 
 | 53 | + | 
 | 54 | +#include <Portenta_H7_AsyncWebServer.h>  | 
 | 55 | + | 
 | 56 | +#include "SDRAM.h"  | 
 | 57 | + | 
 | 58 | +// Enter a MAC address and IP address for your controller below.  | 
 | 59 | +#define NUMBER_OF_MAC      20  | 
 | 60 | + | 
 | 61 | +byte mac[][NUMBER_OF_MAC] =  | 
 | 62 | +{  | 
 | 63 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x01 },  | 
 | 64 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x02 },  | 
 | 65 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x03 },  | 
 | 66 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x04 },  | 
 | 67 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x05 },  | 
 | 68 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x06 },  | 
 | 69 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x07 },  | 
 | 70 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x08 },  | 
 | 71 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x09 },  | 
 | 72 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0A },  | 
 | 73 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0B },  | 
 | 74 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0C },  | 
 | 75 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0D },  | 
 | 76 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0E },  | 
 | 77 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x0F },  | 
 | 78 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x10 },  | 
 | 79 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x11 },  | 
 | 80 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x12 },  | 
 | 81 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x13 },  | 
 | 82 | +  { 0xDE, 0xAD, 0xBE, 0xEF, 0x32, 0x14 },  | 
 | 83 | +};  | 
 | 84 | +// Select the IP address according to your local network  | 
 | 85 | +IPAddress ip(192, 168, 2, 232);  | 
 | 86 | + | 
 | 87 | +AsyncWebServer    server(80);  | 
 | 88 | + | 
 | 89 | +int reqCount = 0;                // number of requests received  | 
 | 90 | + | 
 | 91 | +#define LED_OFF             HIGH  | 
 | 92 | +#define LED_ON              LOW  | 
 | 93 | + | 
 | 94 | + | 
 | 95 | +#define BUFFER_SIZE         768 // a little larger in case required for header shift (destructive send)  | 
 | 96 | +char temp[BUFFER_SIZE];  | 
 | 97 | + | 
 | 98 | +void handleRoot(AsyncWebServerRequest *request)  | 
 | 99 | +{  | 
 | 100 | +  digitalWrite(LED_BUILTIN, LED_ON);  | 
 | 101 | + | 
 | 102 | +  int sec = millis() / 1000;  | 
 | 103 | +  int min = sec / 60;  | 
 | 104 | +  int hr = min / 60;  | 
 | 105 | +  int day = hr / 24;  | 
 | 106 | + | 
 | 107 | +  snprintf(temp, BUFFER_SIZE - 1,  | 
 | 108 | +           "<html>\  | 
 | 109 | +<head>\  | 
 | 110 | +<meta http-equiv='refresh' content='5'/>\  | 
 | 111 | +<title>AsyncWebServer-%s</title>\  | 
 | 112 | +<style>\  | 
 | 113 | +body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\  | 
 | 114 | +</style>\  | 
 | 115 | +</head>\  | 
 | 116 | +<body>\  | 
 | 117 | +<h2>AsyncWebServer_Portenta_H7!</h2>\  | 
 | 118 | +<h3>running on %s</h3>\  | 
 | 119 | +<p>Uptime: %d d %02d:%02d:%02d</p>\  | 
 | 120 | +<img src=\"/test.svg\" />\  | 
 | 121 | +</body>\  | 
 | 122 | +</html>", BOARD_NAME, BOARD_NAME, day, hr % 24, min % 60, sec % 60);  | 
 | 123 | + | 
 | 124 | +  request->send(200, "text/html", temp, false);  | 
 | 125 | + | 
 | 126 | +  digitalWrite(LED_BUILTIN, LED_OFF);  | 
 | 127 | +}  | 
 | 128 | + | 
 | 129 | +void handleNotFound(AsyncWebServerRequest *request)  | 
 | 130 | +{  | 
 | 131 | +  digitalWrite(LED_BUILTIN, LED_ON);  | 
 | 132 | +  String message = "File Not Found\n\n";  | 
 | 133 | + | 
 | 134 | +  message += "URI: ";  | 
 | 135 | +  message += request->url();  | 
 | 136 | +  message += "\nMethod: ";  | 
 | 137 | +  message += (request->method() == HTTP_GET) ? "GET" : "POST";  | 
 | 138 | +  message += "\nArguments: ";  | 
 | 139 | +  message += request->args();  | 
 | 140 | +  message += "\n";  | 
 | 141 | + | 
 | 142 | +  for (uint8_t i = 0; i < request->args(); i++)  | 
 | 143 | +  {  | 
 | 144 | +    message += " " + request->argName(i) + ": " + request->arg(i) + "\n";  | 
 | 145 | +  }  | 
 | 146 | + | 
 | 147 | +  request->send(404, "text/plain", message);  | 
 | 148 | +  digitalWrite(LED_BUILTIN, LED_OFF);  | 
 | 149 | +}  | 
 | 150 | + | 
 | 151 | +void PrintHeapData(String hIn){  | 
 | 152 | +  mbed_stats_heap_t heap_stats;  | 
 | 153 | +    | 
 | 154 | +  Serial.print("HEAP DATA - ");  | 
 | 155 | +  Serial.print(hIn);  | 
 | 156 | + | 
 | 157 | +  mbed_stats_heap_get(&heap_stats);  | 
 | 158 | +  Serial.print("  Cur heap: ");  | 
 | 159 | +  Serial.print(heap_stats.current_size);  | 
 | 160 | +  Serial.print("  Res Size: ");  | 
 | 161 | +  Serial.print(heap_stats.reserved_size);  | 
 | 162 | +  Serial.print("  Max heap: ");  | 
 | 163 | +  Serial.println(heap_stats.max_size);  | 
 | 164 | +}  | 
 | 165 | + | 
 | 166 | + | 
 | 167 | +char *cStr;  | 
 | 168 | + | 
 | 169 | + | 
 | 170 | +void drawGraph(AsyncWebServerRequest *request)   | 
 | 171 | +{  | 
 | 172 | +  char temp[80];  | 
 | 173 | + | 
 | 174 | +  cStr[0] = '\0';  | 
 | 175 | + | 
 | 176 | +  strcat(cStr, "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"1810\" height=\"150\">\n");  | 
 | 177 | +  strcat(cStr, "<rect width=\"1810\" height=\"150\" fill=\"rgb(250, 230, 210)\" stroke-width=\"2\" stroke=\"rgb(0, 0, 0)\" />\n");  | 
 | 178 | +  strcat(cStr, "<g stroke=\"blue\">\n");  | 
 | 179 | +  int y = rand() % 130;  | 
 | 180 | + | 
 | 181 | +  for (int x = 10; x < 5000; x += 10)  | 
 | 182 | +  {  | 
 | 183 | +    int y2 = rand() % 130;  | 
 | 184 | +    sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"2\" />\n", x, 140 - y, x + 10, 140 - y2);  | 
 | 185 | +    strcat(cStr, temp);  | 
 | 186 | +    y = y2;  | 
 | 187 | +  }  | 
 | 188 | +    | 
 | 189 | +  strcat(cStr, "</g>\n</svg>\n");  | 
 | 190 | + | 
 | 191 | +  PrintHeapData("Pre Send");  | 
 | 192 | + | 
 | 193 | +  Serial.print("Out String Length=");  | 
 | 194 | +  Serial.println(strlen(cStr));  | 
 | 195 | + | 
 | 196 | +  request->send(200, "image/svg+xml", cStr, false);  | 
 | 197 | + | 
 | 198 | +  PrintHeapData("Post Send");  | 
 | 199 | +}  | 
 | 200 | + | 
 | 201 | + | 
 | 202 | +void setup()  | 
 | 203 | +{  | 
 | 204 | +  pinMode(LED_BUILTIN, OUTPUT);  | 
 | 205 | +  digitalWrite(LED_BUILTIN, LED_OFF);  | 
 | 206 | + | 
 | 207 | +  Serial.begin(115200);  | 
 | 208 | +  while (!Serial && millis() < 5000);  | 
 | 209 | + | 
 | 210 | +  delay(200);  | 
 | 211 | + | 
 | 212 | +  Serial.print("\nStart Async_AdvancedWebServer_MemoryIssues_Send_CString on "); Serial.print(BOARD_NAME);  | 
 | 213 | +  Serial.print(" with "); Serial.println(SHIELD_TYPE);  | 
 | 214 | +  Serial.println(PORTENTA_H7_ASYNC_TCP_VERSION);  | 
 | 215 | +  Serial.println(PORTENTA_H7_ASYNC_WEBSERVER_VERSION);  | 
 | 216 | + | 
 | 217 | +  SDRAM.begin();  | 
 | 218 | + | 
 | 219 | +  cStr = (char *)SDRAM.malloc(100000);    // make a little larger than required  | 
 | 220 | + | 
 | 221 | +  if (cStr == NULL) {  | 
 | 222 | +    Serial.println("Unable top Allocate RAM");  | 
 | 223 | +    for(;;);  | 
 | 224 | +  }  | 
 | 225 | + | 
 | 226 | +  ///////////////////////////////////  | 
 | 227 | + | 
 | 228 | +  // start the ethernet connection and the server  | 
 | 229 | +  // Use random mac  | 
 | 230 | +  uint16_t index = millis() % NUMBER_OF_MAC;  | 
 | 231 | + | 
 | 232 | +  // Use Static IP  | 
 | 233 | +  //Ethernet.begin(mac[index], ip);  | 
 | 234 | +  // Use DHCP dynamic IP and random mac  | 
 | 235 | +  Ethernet.begin(mac[index]);  | 
 | 236 | + | 
 | 237 | +  if (Ethernet.hardwareStatus() == EthernetNoHardware)  | 
 | 238 | +  {  | 
 | 239 | +    Serial.println("No Ethernet found. Stay here forever");  | 
 | 240 | + | 
 | 241 | +    while (true)  | 
 | 242 | +    {  | 
 | 243 | +      delay(1); // do nothing, no point running without Ethernet hardware  | 
 | 244 | +    }  | 
 | 245 | +  }  | 
 | 246 | + | 
 | 247 | +  if (Ethernet.linkStatus() == LinkOFF)  | 
 | 248 | +  {  | 
 | 249 | +    Serial.println("Not connected Ethernet cable");  | 
 | 250 | +  }  | 
 | 251 | + | 
 | 252 | +  Serial.print(F("Using mac index = "));  | 
 | 253 | +  Serial.println(index);  | 
 | 254 | + | 
 | 255 | +  Serial.print(F("Connected! IP address: "));  | 
 | 256 | +  Serial.println(Ethernet.localIP());  | 
 | 257 | + | 
 | 258 | +  ///////////////////////////////////  | 
 | 259 | +   | 
 | 260 | +  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request)  | 
 | 261 | +  {  | 
 | 262 | +    handleRoot(request);  | 
 | 263 | +  });  | 
 | 264 | + | 
 | 265 | +  server.on("/test.svg", HTTP_GET, [](AsyncWebServerRequest * request)  | 
 | 266 | +  {  | 
 | 267 | +    drawGraph(request);  | 
 | 268 | +  });  | 
 | 269 | + | 
 | 270 | +  server.on("/inline", [](AsyncWebServerRequest * request)  | 
 | 271 | +  {  | 
 | 272 | +    request->send(200, "text/plain", "This works as well");  | 
 | 273 | +  });  | 
 | 274 | + | 
 | 275 | +  server.onNotFound(handleNotFound);  | 
 | 276 | + | 
 | 277 | +  server.begin();  | 
 | 278 | + | 
 | 279 | +  Serial.print(F("HTTP EthernetWebServer is @ IP : "));  | 
 | 280 | +  Serial.println(Ethernet.localIP());  | 
 | 281 | + | 
 | 282 | +      | 
 | 283 | +  PrintHeapData("Pre Create Arduino String");  | 
 | 284 | + | 
 | 285 | +}  | 
 | 286 | + | 
 | 287 | +void heartBeatPrint()  | 
 | 288 | +{  | 
 | 289 | +  static int num = 1;  | 
 | 290 | + | 
 | 291 | +  Serial.print(F("."));  | 
 | 292 | + | 
 | 293 | +  if (num == 80)  | 
 | 294 | +  {  | 
 | 295 | +    Serial.println();  | 
 | 296 | +    num = 1;  | 
 | 297 | +  }  | 
 | 298 | +  else if (num++ % 10 == 0)  | 
 | 299 | +  {  | 
 | 300 | +    Serial.print(F(" "));  | 
 | 301 | +  }  | 
 | 302 | +}  | 
 | 303 | + | 
 | 304 | +void check_status()  | 
 | 305 | +{  | 
 | 306 | +  static unsigned long checkstatus_timeout = 0;  | 
 | 307 | + | 
 | 308 | +#define STATUS_CHECK_INTERVAL     10000L  | 
 | 309 | + | 
 | 310 | +  // Send status report every STATUS_REPORT_INTERVAL (60) seconds: we don't need to send updates frequently if there is no status change.  | 
 | 311 | +  if ((millis() > checkstatus_timeout) || (checkstatus_timeout == 0))  | 
 | 312 | +  {  | 
 | 313 | +    heartBeatPrint();  | 
 | 314 | +    checkstatus_timeout = millis() + STATUS_CHECK_INTERVAL;  | 
 | 315 | +  }  | 
 | 316 | +}  | 
 | 317 | + | 
 | 318 | +void loop()  | 
 | 319 | +{  | 
 | 320 | +  check_status();  | 
 | 321 | +}  | 
0 commit comments