Skip to content

Commit 4c280bc

Browse files
committed
Basic implementation of OTA business logic
1 parent 0596769 commit 4c280bc

File tree

10 files changed

+280
-48
lines changed

10 files changed

+280
-48
lines changed

.github/workflows/compile-examples.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ jobs:
88

99
env:
1010
# libraries to install
11-
UNIVERSAL_LIBRARIES: '"ArduinoCloudThing" "Arduino_ConnectionHandler" "Arduino_DebugUtils" "ArduinoMqttClient" "Arduino_MKRMEM"'
11+
UNIVERSAL_LIBRARIES: '"ArduinoCloudThing" "Arduino_ConnectionHandler" "Arduino_DebugUtils" "ArduinoMqttClient" "Arduino_CRC32"'
1212
# board-specific libraries
13-
WIFI_LIBRARIES: '"ArduinoBearSSL" "ArduinoECCX08" "RTCZero" "WiFi101" "WiFiNINA"'
13+
WIFI_LIBRARIES: '"ArduinoBearSSL" "ArduinoECCX08" "RTCZero" "WiFi101" "WiFiNINA" "Arduino_MKRMEM"'
1414
WAN_LIBRARIES: '"ArduinoBearSSL" "ArduinoECCX08" "RTCZero" "MKRWAN"'
15-
GSM_LIBRARIES: '"ArduinoBearSSL" "ArduinoECCX08" "RTCZero" "MKRGSM"'
16-
NB_LIBRARIES: '"ArduinoBearSSL" "ArduinoECCX08" "RTCZero" "MKRNB"'
15+
GSM_LIBRARIES: '"ArduinoBearSSL" "ArduinoECCX08" "RTCZero" "MKRGSM" "Arduino_MKRMEM"'
16+
NB_LIBRARIES: '"ArduinoBearSSL" "ArduinoECCX08" "RTCZero" "MKRNB" "Arduino_MKRMEM"'
1717
ESP8266_LIBRARIES: ''
1818
# sketch paths to compile (recursive)
1919
UNIVERSAL_SKETCH_PATHS: '"examples/ArduinoIoTCloud-Advanced" "examples/ArduinoIoTCloud-Basic" "examples/utility/ArduinoIoTCloud_Travis_CI"'

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
*~
44
.vscode
55
*.orig
6-
.vs
6+
.vs
7+
build

extras/test/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ project(testArduinoIoTCloud)
1010

1111
include_directories(include)
1212
include_directories(../../src/utility/ota)
13+
include_directories(../../../Arduino_CRC32/src)
1314
include_directories(external/catch/v2.12.1/include)
1415

1516
##########################################################################
@@ -26,11 +27,13 @@ set(TEST_SRCS
2627
src/test_main.cpp
2728
src/test_OTALogic.cpp
2829
src/OTAStorage_Mock.cpp
30+
src/OTATestData.cpp
2931
../../src/utility/ota/OTALogic.cpp
3032
)
3133

3234
##########################################################################
3335

36+
add_compile_definitions(HOST)
3437
add_compile_options(-Wall -Wextra -Wpedantic -Werror)
3538

3639
##########################################################################

extras/test/include/OTAStorage_Mock.h

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
#include <OTAStorage.h>
1313

14+
#include <vector>
15+
1416
/**************************************************************************************
1517
CLASS DECLARATION
1618
**************************************************************************************/
@@ -31,6 +33,7 @@ class OTAStorage_Mock : public OTAStorage
3133

3234
bool _init_return_val;
3335
bool _open_return_val;
36+
std::vector <uint8_t> _binary;
3437

3538
};
3639

extras/test/include/OTATestData.h

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2020 Arduino. All rights reserved.
3+
*/
4+
5+
#ifndef OTA_TEST_DATA_H_
6+
#define OTA_TEST_DATA_H_
7+
8+
/**************************************************************************************
9+
INCLUDE
10+
**************************************************************************************/
11+
12+
#include <stdint.h>
13+
14+
/**************************************************************************************
15+
TYPEDEF
16+
**************************************************************************************/
17+
18+
union OTAData
19+
{
20+
struct __attribute__((packed))
21+
{
22+
uint32_t len;
23+
uint32_t crc32;
24+
uint8_t bin[256*1024]; /* Maximum flash size of ATSAMD21G18 is 256 KB */
25+
} data;
26+
uint8_t buf[sizeof(data)];
27+
};
28+
29+
/**************************************************************************************
30+
FUNCTION DECLARATION
31+
**************************************************************************************/
32+
33+
void generate_valid_ota_data(OTAData & ota_data);
34+
35+
#endif /* OTA_TEST_DATA_H_ */

extras/test/src/OTAStorage_Mock.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ bool OTAStorage_Mock::init()
3030

3131
bool OTAStorage_Mock::open()
3232
{
33+
_binary.clear();
3334
return _open_return_val;
3435
}
3536

36-
size_t OTAStorage_Mock::write(uint8_t const * const /* buf */, size_t const num_bytes)
37+
size_t OTAStorage_Mock::write(uint8_t const * const buf, size_t const num_bytes)
3738
{
39+
std::copy(buf, buf + num_bytes, std::back_inserter(_binary));
3840
return num_bytes;
3941
}
4042

extras/test/src/OTATestData.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2020 Arduino. All rights reserved.
3+
*/
4+
5+
/**************************************************************************************
6+
INCLUDE
7+
**************************************************************************************/
8+
9+
#include <OTATestData.h>
10+
11+
#include <algorithm>
12+
13+
/**************************************************************************************
14+
FUNCTION DEFINITION
15+
**************************************************************************************/
16+
17+
void generate_valid_ota_data(OTAData & ota_data)
18+
{
19+
/* Set length. Attention: header length (8 bytes for len and crc32 are not included - this is only the payload length. */
20+
ota_data.data.len = 64 * 1024;
21+
22+
/* Fill array */
23+
std::generate(ota_data.data.bin,
24+
ota_data.data.bin + ota_data.data.len,
25+
[](void) -> uint8_t
26+
{
27+
static uint8_t val = 0;
28+
return val++;
29+
});
30+
31+
/* Generate CRC */
32+
33+
}

extras/test/src/test_OTALogic.cpp

+39-24
Original file line numberDiff line numberDiff line change
@@ -6,49 +6,64 @@
66
INCLUDE
77
**************************************************************************************/
88

9+
#include <algorithm>
10+
911
#include <catch.hpp>
1012

13+
#include <OTATestData.h>
1114
#include <OTAStorage_Mock.h>
1215

1316
#include <OTALogic.h>
1417

1518
/**************************************************************************************
16-
TEST CODE
19+
TEST HELPER
1720
**************************************************************************************/
1821

19-
TEST_CASE("A OTALogic object is instantiated", "[OTALogic::OTALogic]")
22+
void simulateOTABinaryReception(OTALogic & ota_logic, OTAStorage_Mock & ota_storage, OTAData const & ota_test_data)
2023
{
21-
OTALogic ota_logic;
22-
23-
REQUIRE(ota_logic.state() == OTAState::Init);
24+
uint32_t bytes_written = 0;
25+
uint32_t const bytes_to_write = sizeof(uint32_t) + sizeof(uint32_t) + ota_test_data.data.len;
26+
for(; bytes_written < (bytes_to_write - MQTT_OTA_BUF_SIZE); bytes_written += MQTT_OTA_BUF_SIZE)
27+
{
28+
ota_logic.onOTADataReceived(ota_test_data.buf + bytes_written, MQTT_OTA_BUF_SIZE);
29+
ota_logic.update(&ota_storage);
30+
}
2431

25-
WHEN("update(nullptr) is run")
32+
if(bytes_written < bytes_to_write)
2633
{
27-
ota_logic.update(nullptr);
28-
THEN("the logic shall transitition to the Error state") {
29-
REQUIRE(ota_logic.state() == OTAState::Error);
30-
}
34+
uint32_t const remaining_bytes = (bytes_to_write - bytes_written);
35+
ota_logic.onOTADataReceived(ota_test_data.buf + bytes_written, remaining_bytes);
36+
ota_logic.update(&ota_storage);
3137
}
3238
}
3339

34-
TEST_CASE("A OTALogic object checks is valid OTAStorage is available", "[OTALogic::update-1]")
40+
/**************************************************************************************
41+
TEST CODE
42+
**************************************************************************************/
43+
44+
TEST_CASE("A valid OTA binary is received ", "[OTALogic - valid data]")
3545
{
3646
OTALogic ota_logic;
47+
OTAData valid_ota_test_data;
3748
OTAStorage_Mock ota_storage;
3849

39-
WHEN("update(&ota_storage) is run")
50+
ota_storage._init_return_val = true;
51+
ota_storage._open_return_val = true;
52+
53+
generate_valid_ota_data(valid_ota_test_data);
54+
55+
simulateOTABinaryReception(ota_logic, ota_storage, valid_ota_test_data);
56+
57+
THEN("the complete binary file should have been written to the OTA storage")
58+
{
59+
REQUIRE(ota_storage._binary.size() == valid_ota_test_data.data.len);
60+
REQUIRE(std::equal(ota_storage._binary.begin(),
61+
ota_storage._binary.end(),
62+
valid_ota_test_data.data.bin));
63+
}
64+
65+
THEN("The OTA logic should be in the 'Reset' state")
4066
{
41-
WHEN("OTAStorage::init() succeeds")
42-
{
43-
ota_storage._init_return_val = true;
44-
ota_logic.update(&ota_storage);
45-
THEN("the logic shall transitition to the Idle state") REQUIRE(ota_logic.state() == OTAState::Idle);
46-
}
47-
WHEN("OTAStorage::init() fails")
48-
{
49-
ota_storage._init_return_val = false;
50-
ota_logic.update(&ota_storage);
51-
THEN("the logic shall transitition to the Error state") REQUIRE(ota_logic.state() == OTAState::Error);
52-
}
67+
REQUIRE(ota_logic.state() == OTAState::Reset);
5368
}
5469
}

0 commit comments

Comments
 (0)