Skip to content

Commit

Permalink
Add SSU LZSS HTTP OTA example
Browse files Browse the repository at this point in the history
  • Loading branch information
manchoz committed Jul 15, 2020
1 parent 807f450 commit 7c5a8d4
Show file tree
Hide file tree
Showing 2 changed files with 231 additions and 0 deletions.
227 changes: 227 additions & 0 deletions libraries/SSU/examples/SSU_LZSS_HttpOta/SSU_LZSS_HttpOta.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
/*
Small example sketch demonstrating how to perform OTA via HTTP/S
utilizing a MKRGSM 1400 and the storage on the integrated
SARA U-201 GSM module.
Please, be careful because no verification is done on the
received OTA file, apart size verification of the transmitted
bytes using the HTTP Content-Length header.
For production-grade OTA procedure you might want to implement
a content verification procedure using a CRC calculation
or an hash (eg. MD5 or SHA256) comparison.
Circuit:
* MKR GSM 1400 board
* Antenna
* SIM card with a data plan
Steps to update a sketch:
1) Create a new sketch or update an existing one to be updated over-the-air.
The sketch needs to contain also the code below for future OTAs.
The sketch must include the SSU library via
#include <SSU.h>
2) In the IDE select: Sketch -> Export compiled Binary.
3) Open the location of the sketch (Sketch -> Show Sketch Folder) and upload
the .bin file to your HTTP/S server.
4) Upload this sketch after configuring the server, port and filename variables.
The sketch will download the OTA file, store it into the U-201 storage, and
will reset the board to trigger the SSU update procedure.
created 25 June 2020
by Giampaolo Mancini
*/

#include <MKRGSM.h>

// This includes triggers the firmware update procedure
// in the bootloader after reset.
#include <SSU.h>

// Do not change! SSU will look for these files!
constexpr char UPDATE_FILE_NAME[] = "UPDATE.BIN.LZSS";
static constexpr char CHECK_FILE_NAME[] = "UPDATE.OK";

#include "arduino_secrets.h"
const char PINNUMBER[] = SECRET_PINNUMBER;
// APN data
const char GPRS_APN[] = SECRET_GPRS_APN;
const char GPRS_LOGIN[] = SECRET_GPRS_LOGIN;
const char GPRS_PASSWORD[] = SECRET_GPRS_PASSWORD;

// Change to GSMClient for non-SSL/TLS connection.
// Not recommended.
GSMSSLClient client;
GPRS gprs;
GSM gsmAccess;

GSMFileUtils fileUtils;

bool isHeaderComplete = false;
String httpHeader;

bool isDownloadComplete = false;
unsigned int fileSize = 0;
unsigned int totalWritten = 0;

constexpr char server[] = "example.org";
constexpr int port = 443;

// Name of the new firmware file to be updated.
constexpr char filename[] = "update.lzss";


void setup()
{
unsigned long timeout = millis();

Serial.begin(9600);
while (!Serial && millis() - timeout < 5000)
;

Serial.println("Starting OTA Update via HTTP and Arduino SSU.");
Serial.println();

bool connected = false;

Serial.print("Connecting to cellular network... ");
while (!connected) {
if ((gsmAccess.begin(PINNUMBER) == GSM_READY) && (gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY)) {
connected = true;
} else {
Serial.println("Not connected");
delay(1000);
}
}

Serial.println("Connected.");
Serial.println();

// Modem has already been initialized in the sketch:
// begin FileUtils without MODEM initialization.
fileUtils.begin(false);

Serial.print("Connecting to ");
Serial.print(server);
Serial.print(":");
Serial.print(port);
Serial.print("... ");
if (client.connect(server, port)) {
Serial.println("Connected.");
Serial.print("Downloading ");
Serial.println(filename);
Serial.print("... ");
// Make the HTTP request:
client.print("GET /");
client.print(filename);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(server);
client.println("Connection: close");
client.println();
} else {
Serial.println("Connection failed");
}
}

void loop()
{
while (client.available()) {
// Skip the HTTP header
if (!isHeaderComplete) {
const char c = client.read();
httpHeader += c;
if (httpHeader.endsWith("\r\n\r\n")) {
isHeaderComplete = true;

// Get the size of the OTA file from the
// HTTP Content-Length header.
fileSize = getContentLength();

Serial.println();
Serial.print("HTTP header complete. ");
Serial.print("OTA file size is ");
Serial.print(fileSize);
Serial.println(" bytes.");
if (fileSize == 0) {
Serial.println("Unable to get OTA file size.");
while (true)
;
}
}
} else {
// Read the OTA file in len-bytes blocks to preserve RAM.
constexpr size_t len { 512 };
char buf[len] { 0 };

// Read len bytes from HTTP client...
uint32_t read = client.readBytes(buf, len);
// and append them to the update file.
uint32_t written = fileUtils.appendFile(UPDATE_FILE_NAME, buf, read);

if (written != read) {
Serial.println("Error while saving data.");
while (true)
;
}

// Update the received byte counter
totalWritten += written;

// Check for full file received and stored
isDownloadComplete = totalWritten == fileSize;

Serial.print("Received: ");
Serial.print(totalWritten);
Serial.print("/");
Serial.println(fileSize);
}
}
if (isDownloadComplete) {
Serial.println();
Serial.println("Download complete.");
Serial.println("Enabling checkpoint.");
Serial.println();

// Create the checkpoint file: will be removed by SSU
// after successful update.
auto status = fileUtils.downloadFile(CHECK_FILE_NAME, { 0 }, 1);
if (status != 1) {
Serial.println("Unable to create checkpoint file.");
while (true)
;
}

Serial.println("Resetting MCU in order to trigger SSU...");
Serial.println();
delay(500);
NVIC_SystemReset();
}
}

int getContentLength()
{
const String contentLengthHeader = "Content-Length:";
const auto contentLengthHeaderLen = contentLengthHeader.length();

auto indexContentLengthStart = httpHeader.indexOf(contentLengthHeader);
if (indexContentLengthStart < 0) {
Serial.println("Unable to find Content-Length header (Start)");
return 0;
}
auto indexContentLengthStop = httpHeader.indexOf("\r\n", indexContentLengthStart);
if (indexContentLengthStart < 0) {
Serial.println("Unable to find Content-Length header (Stop)");
return 0;
}
auto contentLength = httpHeader.substring(indexContentLengthStart + contentLengthHeaderLen + 1, indexContentLengthStop);

contentLength.trim();
return contentLength.toInt();
}
4 changes: 4 additions & 0 deletions libraries/SSU/examples/SSU_LZSS_HttpOta/arduino_secrets.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#define SECRET_PINNUMBER ""
#define SECRET_GPRS_APN "GPRS_APN" // replace your GPRS APN
#define SECRET_GPRS_LOGIN "login" // replace with your GPRS login
#define SECRET_GPRS_PASSWORD "password" // replace with your GPRS password

0 comments on commit 7c5a8d4

Please sign in to comment.