Skip to content

Commit 970877b

Browse files
committed
added httpota example
1 parent f4e8cab commit 970877b

File tree

3 files changed

+250
-26
lines changed

3 files changed

+250
-26
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
+19-26
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,49 @@
11
/*
22
Usage
3-
This example demonstrates how to use the SAMD SFU library to update a
4-
sketch on any Arduino MKR board connected to a MKRMEM Shield. This sketch
5-
prints out the date and time the sketch was compiled.
6-
7-
Steps to update sketch via MKRMEM shield:
8-
9-
1) Upload this sketch or another sketch that includes the SFU library
10-
via #include <SFU.h>
11-
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>
129
2) Update the sketch as desired. For this example the sketch prints out
1310
the compiled date and time so no updates are needed.
14-
1511
3) In the IDE select: Sketch -> Export compiled Binary
16-
1712
4) Open the location of the sketch and convert the .bin file to a C byte array.
1813
cat SKETCH.bin | xxd --include > Binary.h
19-
20-
5) Copy Binary.h file from the sketch's folder to the SFU_LoadBinary sketch
21-
and load it to the MKRMEM via SFU_LoadBinary sketch.
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.
2216
*/
2317

2418
/*
25-
Include the SFU library
19+
Include the SSU library
2620
2721
This will add some code to the sketch before setup() is called
28-
to check if UPDATE.bin is present on the flash chip of the MKRMEM
29-
shield. If this theck is positive the file is used to update the sketch
30-
running on the board. After this UPDATE.BIN is deleted from the flash.
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.
3126
*/
3227

3328

3429
#include <SSU.h>
3530

36-
37-
void setup() {
31+
void setup()
32+
{
3833
Serial.begin(9600);
39-
while(!Serial) { }
40-
34+
while (!Serial) { }
4135
// wait a bit
4236
delay(1000);
43-
4437
String message;
4538
message += "Sketch compile date and time: ";
4639
message += __DATE__;
4740
message += " ";
4841
message += __TIME__;
49-
5042
// print out the sketch compile date and time on the serial port
5143
Serial.println(message);
5244
}
5345

54-
void loop() {
46+
void loop()
47+
{
5548
// add you own code here
56-
}
49+
}

0 commit comments

Comments
 (0)