Skip to content

Commit 44d354b

Browse files
authored
Merge pull request #534 from Rocketct/GSMOTA
SSU support for OTA on SaraU210 module
2 parents 6e049f7 + 970877b commit 44d354b

File tree

12 files changed

+3161
-0
lines changed

12 files changed

+3161
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
/*
2+
Small example sketch demonstrating how to perform OTA via HTTP/S
3+
utilizing a MKRGSM 1400 and the storage on the integrated
4+
SARA U-201 GSM module.
5+
6+
Please, be careful because no verification is done on the
7+
received OTA file, apart size verification of the transmitted
8+
bytes using the HTTP Content-Length header.
9+
10+
For production-grade OTA procedure you might want to implement
11+
a content verification procedure using a CRC calculation
12+
or an hash (eg. MD5 or SHA256) comparison.
13+
14+
Circuit:
15+
* MKR GSM 1400 board
16+
* Antenna
17+
* SIM card with a data plan
18+
19+
Steps to update a sketch:
20+
21+
1) Create a new sketch or update an existing one to be updated over-the-air.
22+
The sketch needs to contain also the code below for future OTAs.
23+
The sketch must include the SSU library via
24+
#include <SSU.h>
25+
26+
2) In the IDE select: Sketch -> Export compiled Binary.
27+
28+
3) Open the location of the sketch (Sketch -> Show Sketch Folder) and upload
29+
the .bin file to your HTTP/S server.
30+
31+
4) Upload this sketch after configuring the server, port and filename variables.
32+
33+
The sketch will download the OTA file, store it into the U-201 storage, and
34+
will reset the board to trigger the SSU update procedure.
35+
36+
37+
created 25 June 2020
38+
by Giampaolo Mancini
39+
*/
40+
41+
#include <MKRGSM.h>
42+
43+
// This includes triggers the firmware update procedure
44+
// in the bootloader after reset.
45+
#include <SSU.h>
46+
47+
// Do not change! SSU will look for these files!
48+
constexpr char UPDATE_FILE_NAME[] = "UPDATE.BIN";
49+
static constexpr char CHECK_FILE_NAME[] = "UPDATE.OK";
50+
51+
#include "arduino_secrets.h"
52+
const char PINNUMBER[] = SECRET_PINNUMBER;
53+
// APN data
54+
const char GPRS_APN[] = SECRET_GPRS_APN;
55+
const char GPRS_LOGIN[] = SECRET_GPRS_LOGIN;
56+
const char GPRS_PASSWORD[] = SECRET_GPRS_PASSWORD;
57+
58+
// Change to GSMClient for non-SSL/TLS connection.
59+
// Not recommended.
60+
GSMSSLClient client;
61+
GPRS gprs;
62+
GSM gsmAccess;
63+
64+
GSMFileUtils fileUtils;
65+
66+
bool isHeaderComplete = false;
67+
String httpHeader;
68+
69+
bool isDownloadComplete = false;
70+
unsigned int fileSize = 0;
71+
unsigned int totalWritten = 0;
72+
73+
constexpr char server[] = "example.org";
74+
constexpr int port = 443;
75+
76+
// Name of the new firmware file to be updated.
77+
constexpr char filename[] = "update.bin";
78+
79+
80+
void setup()
81+
{
82+
unsigned long timeout = millis();
83+
84+
Serial.begin(9600);
85+
while (!Serial && millis() - timeout < 5000)
86+
;
87+
88+
Serial.println("Starting OTA Update via HTTP and Arduino SSU.");
89+
Serial.println();
90+
91+
bool connected = false;
92+
93+
Serial.print("Connecting to cellular network... ");
94+
while (!connected) {
95+
if ((gsmAccess.begin(PINNUMBER) == GSM_READY) && (gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY)) {
96+
connected = true;
97+
} else {
98+
Serial.println("Not connected");
99+
delay(1000);
100+
}
101+
}
102+
103+
Serial.println("Connected.");
104+
Serial.println();
105+
106+
// Modem has already been initialized in the sketch:
107+
// begin FileUtils without MODEM initialization.
108+
fileUtils.begin(false);
109+
110+
Serial.print("Connecting to ");
111+
Serial.print(server);
112+
Serial.print(":");
113+
Serial.print(port);
114+
Serial.print("... ");
115+
if (client.connect(server, port)) {
116+
Serial.println("Connected.");
117+
Serial.print("Downloading ");
118+
Serial.println(filename);
119+
Serial.print("... ");
120+
// Make the HTTP request:
121+
client.print("GET /");
122+
client.print(filename);
123+
client.println(" HTTP/1.1");
124+
client.print("Host: ");
125+
client.println(server);
126+
client.println("Connection: close");
127+
client.println();
128+
} else {
129+
Serial.println("Connection failed");
130+
}
131+
}
132+
133+
void loop()
134+
{
135+
while (client.available()) {
136+
// Skip the HTTP header
137+
if (!isHeaderComplete) {
138+
const char c = client.read();
139+
httpHeader += c;
140+
if (httpHeader.endsWith("\r\n\r\n")) {
141+
isHeaderComplete = true;
142+
143+
// Get the size of the OTA file from the
144+
// HTTP Content-Length header.
145+
fileSize = getContentLength();
146+
147+
Serial.println();
148+
Serial.print("HTTP header complete. ");
149+
Serial.print("OTA file size is ");
150+
Serial.print(fileSize);
151+
Serial.println(" bytes.");
152+
if (fileSize == 0) {
153+
Serial.println("Unable to get OTA file size.");
154+
while (true)
155+
;
156+
}
157+
}
158+
} else {
159+
// Read the OTA file in len-bytes blocks to preserve RAM.
160+
constexpr size_t len { 512 };
161+
char buf[len] { 0 };
162+
163+
// Read len bytes from HTTP client...
164+
uint32_t read = client.readBytes(buf, len);
165+
// and append them to the update file.
166+
uint32_t written = fileUtils.appendFile(UPDATE_FILE_NAME, buf, read);
167+
168+
if (written != read) {
169+
Serial.println("Error while saving data.");
170+
while (true)
171+
;
172+
}
173+
174+
// Update the received byte counter
175+
totalWritten += written;
176+
177+
// Check for full file received and stored
178+
isDownloadComplete = totalWritten == fileSize;
179+
180+
Serial.print("Received: ");
181+
Serial.print(totalWritten);
182+
Serial.print("/");
183+
Serial.println(fileSize);
184+
}
185+
}
186+
if (isDownloadComplete) {
187+
Serial.println();
188+
Serial.println("Download complete.");
189+
Serial.println("Enabling checkpoint.");
190+
Serial.println();
191+
192+
// Create the checkpoint file: will be removed by SSU
193+
// after successful update.
194+
auto status = fileUtils.downloadFile(CHECK_FILE_NAME, { 0 }, 1);
195+
if (status != 1) {
196+
Serial.println("Unable to create checkpoint file.");
197+
while (true)
198+
;
199+
}
200+
201+
Serial.println("Resetting MCU in order to trigger SSU...");
202+
Serial.println();
203+
delay(500);
204+
NVIC_SystemReset();
205+
}
206+
}
207+
208+
int getContentLength()
209+
{
210+
const String contentLengthHeader = "Content-Length:";
211+
const auto contentLengthHeaderLen = contentLengthHeader.length();
212+
213+
auto indexContentLengthStart = httpHeader.indexOf(contentLengthHeader);
214+
if (indexContentLengthStart < 0) {
215+
Serial.println("Unable to find Content-Length header (Start)");
216+
return 0;
217+
}
218+
auto indexContentLengthStop = httpHeader.indexOf("\r\n", indexContentLengthStart);
219+
if (indexContentLengthStart < 0) {
220+
Serial.println("Unable to find Content-Length header (Stop)");
221+
return 0;
222+
}
223+
auto contentLength = httpHeader.substring(indexContentLengthStart + contentLengthHeaderLen + 1, indexContentLengthStop);
224+
225+
contentLength.trim();
226+
return contentLength.toInt();
227+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#define SECRET_PINNUMBER ""
2+
#define SECRET_GPRS_APN "GPRS_APN" // replace your GPRS APN
3+
#define SECRET_GPRS_LOGIN "login" // replace with your GPRS login
4+
#define SECRET_GPRS_PASSWORD "password" // replace with your GPRS password

libraries/SSU/examples/SSU_LoadBinary/Binary.h

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**************************************************************************************
2+
* INCLUDE
3+
**************************************************************************************/
4+
5+
6+
#include <MKRGSM.h>
7+
8+
9+
/**************************************************************************************
10+
* CONSTANTS
11+
**************************************************************************************/
12+
13+
static char const BINARY[] =
14+
15+
{
16+
#include "Binary.h"
17+
};
18+
19+
20+
GSMFileUtils fileUtils;
21+
22+
23+
/**************************************************************************************
24+
* SETUP/LOOP
25+
**************************************************************************************/
26+
27+
void setup() {
28+
Serial.begin(9600);
29+
30+
unsigned long const start = millis();
31+
for(unsigned long now = millis(); !Serial && ((now - start) < 5000); now = millis()) { };
32+
33+
Serial.print("Accessing SARA U-201 Filesystem... ");
34+
if(!fileUtils.begin()) {
35+
Serial.println("failed.");
36+
return;
37+
38+
}
39+
Serial.println("OK");
40+
Serial.print("Writing \"UPDATE.BIN\" ... ");
41+
42+
uint32_t bytes_to_write = sizeof(BINARY);
43+
auto bytes_written = fileUtils.downloadFile("UPDATE.BIN", BINARY, bytes_to_write);
44+
45+
if(bytes_written != bytes_to_write) {
46+
Serial.println("downloadFile failed.");return;
47+
48+
} else {
49+
Serial.print("OK (");
50+
Serial.print(bytes_written);
51+
Serial.println(" bytes written)");
52+
}
53+
}
54+
55+
void loop() {
56+
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
Usage
3+
This example demonstrates how to use the SAMD SSU library to update a
4+
sketch on any Arduino MKR board via the storage on the SARA U-201 GSM module.
5+
This sketch prints out the date and time the sketch was compiled.
6+
Steps to update sketch:
7+
1) Upload this sketch or another sketch that includes the SSU library
8+
via #include <SSU.h>
9+
2) Update the sketch as desired. For this example the sketch prints out
10+
the compiled date and time so no updates are needed.
11+
3) In the IDE select: Sketch -> Export compiled Binary
12+
4) Open the location of the sketch and convert the .bin file to a C byte array.
13+
cat SKETCH.bin | xxd --include > Binary.h
14+
5) Copy Binary.h file from the sketch's folder to the SSU_LoadBinary sketch
15+
and load it to the U-201 via SSU_LoadBinary sketch.
16+
*/
17+
18+
/*
19+
Include the SSU library
20+
21+
This will add some code to the sketch before setup() is called
22+
to check if UPDATE.BIN and UPDATE.OK are present on the storage of
23+
the U-201 module. If this theck is positive UPDATE.BIN is used to update
24+
the sketch running on the board.
25+
After this UPDATE.BIN and UPDATE.OK are deleted from the flash.
26+
*/
27+
28+
29+
#include <SSU.h>
30+
31+
void setup()
32+
{
33+
Serial.begin(9600);
34+
while (!Serial) { }
35+
// wait a bit
36+
delay(1000);
37+
String message;
38+
message += "Sketch compile date and time: ";
39+
message += __DATE__;
40+
message += " ";
41+
message += __TIME__;
42+
// print out the sketch compile date and time on the serial port
43+
Serial.println(message);
44+
}
45+
46+
void loop()
47+
{
48+
// add you own code here
49+
}

0 commit comments

Comments
 (0)