JAndrassy / ArduinoOTA

Arduino library to upload sketch over network to Arduino board with WiFi or Ethernet libraries
GNU Lesser General Public License v2.1
435 stars 89 forks source link

InternalStorage - Flash MKR NB 1500 #232

Closed loppylu closed 8 months ago

loppylu commented 8 months ago

Hello, And thanks for your library :)

I am facing an issue when trying to flash my device. I am currently getting a bin file from a HTTP server (will be HTTPS in the future) and trying to add this the device. The content/bin is of 18317 bytes. Below you can see my code (sorry about the formatting, dunno why it didn't grab the whole thing as code). Everything works fine until I am erasing the flash on the device. It seems that is indeed erasing it (since the old program can not be run anymore after this when rebooting the device), but it won't continue to add the new content. Below is my "modified" Serial print of the copyFlashAndReset function.

I get to the 'eraseFlash(dest, length, pageSize);' function, but it won't continue after that. Do you have any thoughts on why?

Thanks again! Richard

static void copyFlashAndReset(int dest, int src, int length, int pageSize)
  {

    volatile uint32_t* d = (volatile uint32_t*)dest;
    uint32_t* s = (uint32_t*)src;

    Serial.println("Erasing flash");
    eraseFlash(dest, length, pageSize);
    Serial.println("Copying over to flash");
    for (int i = 0; i < length; i += 4) {
      *d++ = *s++;

      waitForReady();
    }

    Serial.println("Restarting device");
    delay(1000);

    NVIC_SystemReset();
  }
void handleSketchDownload() {
  static unsigned long previousMillis = 0;
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis < CHECK_INTERVAL)
    return;
  previousMillis = currentMillis;

  String response;

  if (client.connect(SERVER, SERVER_PORT)) {
    Serial.println("Connected to server");

    client.print("GET ");
    client.print(PATH);
    client.println(" HTTP/1.1");
    client.print("Host: ");
    client.println(SERVER);
    client.println("User-Agent: Arduino/1.0");
    client.println("Connection: close");
    client.println();

    // Read and parse the response headers
    int statusCode = 0;
    int contentLength = 0;

    while (client.connected()) {
      if (client.available()) {
        // Read the response line by line
        String line = client.readStringUntil('\n');
        Serial.println(line);

        // Parse headers
        if (line == "\r") {
          Serial.println("End of headers");
          break;
        } else {
          int colonIndex = line.indexOf(':');
          if (colonIndex != -1) {
            String headerName = line.substring(0, colonIndex);
            String headerValue = line.substring(colonIndex + 1);
            headerValue.trim();  // Remove leading/trailing spaces

            if (headerName.equals("HTTP/1.1")) {
              // Extract status code
              statusResponse = headerValue.substring(0, 3).toInt();
              Serial.print("Status Code: ");
              Serial.println(statusCode);
            } else if (headerName.equals("Content-Length")) {
              // Extract content length
              responseContentLength = headerValue.toInt();
              Serial.print("Content Length: ");
              Serial.println(responseContentLength);
            }
          }
        }
      }
    }

    Serial.println("---- END OF RESPONSE ----");

    // Check if the received content length matches the expected length
    Serial.println("The correct amount of bytes read, continuing to install update");
    if (!InternalStorage.open(responseContentLength)) 
    {
      client.stop();
      Serial.println("There is not enough space to store the update. Can't continue with update.");
      return;
    }

    Serial.write("Will read through the data in the device with length", responseContentLength);

    while (client.connected() && responseContentLength > 0) {
      if (client.available()) {
        InternalStorage.write(client.read());
        responseContentLength--;
      }
    }

    InternalStorage.close();
    client.stop();
    if (responseContentLength > 0) {
      Serial.print("Timeout downloading update file at ");
      Serial.print(responseContentLength);
      Serial.println(" bytes. Can't continue with update.");
      return;
    }

    Serial.println("Sketch update apply and reset.");
    Serial.flush();
    blink(3,500);
    InternalStorage.apply(); // this doesn't return

  } else {
    Serial.println("Failed to open socket. Extended error report:");
  }
}
JAndrassy commented 8 months ago

copyFlashAndReset runs in RAM and is not allowed to use and other part of the code since that is overwritten. so Serial print just crashes

loppylu commented 8 months ago

Hi again, And thanks for your quick reply.

Ok, I added those prints just for debugging, but before I added the Serial.print (not modified your code) I didn't hear that it reached the NVIC command to reset it either (normal USB sound when a new USB is connected). I believe the interrupts are removed as well, so blinking the LED is probably out of the question also for some sort of debugging.

I assume there is not difference between MKR boards on this specific matter since you've tested this on other MKR boards, so it should behave the same. I have run the same bin file with bossac, and that works fine.

Then I am guessing that there is something with the bin-file I am receiving, but I don't see any flaws to that either to be honest. That is more of a forum question I guess (so I can mark this is as closed), but do you see any reason why this would not work? I am happy to share my entire code if you want to have it as an example for NB 1500 later on.

Richard

loppylu commented 8 months ago

Hi again, I will close this issue, since the issue was not related to your library. I finally got it working, the code I provided earlier was correct on both sides, the issue was the content of the HTTP request returned it as text and not octet-stream.

Thanks again for your help!