26char constexpr OTA_CB_IS_NULL[] =
"OTA update callback is NULL, has it been deleted";
30char constexpr ERROR_UPDATE_BEGIN[] =
"Failed to initalize flash updater, ensure that the partition scheme has two app sections";
31char constexpr ERROR_UPDATE_WRITE[] =
"Only wrote (%u) bytes of binary data instead of expected (%u)";
35char constexpr CHUNK_REQUEST_TIMED_OUT[] =
"Failed to receive requested chunk (%u) in (%llu) us. Internet connection might have been lost";
36#if THINGSBOARD_ENABLE_DEBUG
37char constexpr FW_CHUNK[] =
"Receive chunk (%u), with size (%u) bytes";
38char constexpr HASH_EXPECTED[] =
"Expected checksum: (%s)";
39char constexpr CHECKSUM_VERIFICATION_SUCCESS[] =
"Checksum is the same as expected";
40char constexpr FW_UPDATE_SUCCESS[] =
"Update success";
49template <
typename Logger>
57 : m_fw_callback(nullptr)
58 , m_publish_callback(publish_callback)
59 , m_send_fw_state_callback(send_fw_state_callback)
60 , m_finish_callback(finish_callback)
63 , m_fw_checksum_algorithm()
66 , m_requested_chunks(0U)
69#if !THINGSBOARD_ENABLE_STL
70 m_subscribedInstance =
nullptr;
81 m_fw_callback = &fw_callback;
83 m_total_chunks = (m_fw_size / m_fw_callback->
Get_Chunk_Size()) + 1U;
84 (void)strncpy(m_fw_checksum, fw_checksum,
sizeof(m_fw_checksum));
85 m_fw_checksum_algorithm = fw_checksum_algorithm;
87#if THINGSBOARD_ENABLE_STL
90 request_timeout.Set_Timeout_Callback(OTA_Handler::Static_Handle_Request_Timeout);
92 Request_First_Firmware_Packet();
106 m_fw_callback =
nullptr;
117 if (current_chunk != m_requested_chunks) {
121 size_t expected_chunk_size = 0U;
122 if (!Received_Valid_Chunk_Size(total_bytes, expected_chunk_size)) {
129 #if THINGSBOARD_ENABLE_DEBUG
130 Logger::printfln(FW_CHUNK, current_chunk, total_bytes);
134 if (current_chunk == 0U && !fw_updater->begin(m_fw_size)) {
139 auto const written_bytes = fw_updater->write(payload, total_bytes);
140 if (written_bytes != total_bytes) {
142 (void)snprintf(message,
sizeof(message),
ERROR_UPDATE_WRITE, written_bytes, total_bytes);
143 Logger::printfln(message);
144 return Handle_Failure(OTA_Failure_Response::RETRY_UPDATE, message);
149 (void)m_hash.
update(payload, total_bytes);
151 m_requested_chunks = current_chunk + 1;
156 if (m_fw_callback ==
nullptr) {
158 return Handle_Failure(OTA_Failure_Response::RETRY_NOTHING,
OTA_CB_IS_NULL);
162 Request_Next_Firmware_Packet();
165#if !THINGSBOARD_USE_ESP_TIMER
176 void Reset_Retries() {
186 bool Received_Valid_Chunk_Size(
size_t const & received_chunk_size,
size_t & expected_chunk_size) {
187 bool const is_last_chunk = m_requested_chunks + 1 >= m_total_chunks;
189 auto const last_chunk_expected_size = m_fw_size % m_fw_callback->
Get_Chunk_Size();
190 expected_chunk_size = last_chunk_expected_size;
191 return received_chunk_size == last_chunk_expected_size;
198 void Request_First_Firmware_Packet() {
199 m_requested_chunks = 0U;
202 (void)m_hash.
start(m_fw_checksum_algorithm);
207 Request_Next_Firmware_Packet();
212 void Request_Next_Firmware_Packet() {
214 if (m_requested_chunks >= m_total_chunks) {
215 Finish_Firmware_Update();
235 void Finish_Firmware_Update() {
237 auto const calculated_checksum = m_hash.
finish();
239 if (strncmp(m_fw_checksum, calculated_checksum.hash, strlen(m_fw_checksum)) != 0) {
242 Logger::printfln(message);
243 return Handle_Failure(OTA_Failure_Response::RETRY_UPDATE, message);
246 #if THINGSBOARD_ENABLE_DEBUG
247 Logger::printfln(CHECKSUM_VERIFICATION_SUCCESS);
251 if (!fw_updater->end()) {
253 return Handle_Failure(OTA_Failure_Response::RETRY_UPDATE,
ERROR_UPDATE_END);
256 #if THINGSBOARD_ENABLE_DEBUG
257 Logger::printfln(FW_UPDATE_SUCCESS);
271 if (m_retries <= 0) {
272 Abort_Firmware_Update(error_message);
280 switch (failure_response) {
281 case OTA_Failure_Response::RETRY_CHUNK:
282 Request_Next_Firmware_Packet();
284 case OTA_Failure_Response::RETRY_UPDATE:
285 Request_First_Firmware_Packet();
287 case OTA_Failure_Response::RETRY_NOTHING:
288 Abort_Firmware_Update(error_message);
297 void Abort_Firmware_Update(
char const * error_message) {
298 (void)m_send_fw_state_callback.Call_Callback(
FW_STATE_FAILED, error_message);
299 if (m_fw_callback !=
nullptr) {
306 void Handle_Request_Timeout() {
308 uint64_t
const & timeout = request_timeout.
Get_Timeout();
311 Logger::printfln(message);
312 Handle_Failure(OTA_Failure_Response::RETRY_CHUNK, message);
315#if !THINGSBOARD_ENABLE_STL
316 static bool Static_Handle_Request_Timeout() {
317 if (m_subscribedInstance ==
nullptr) {
320 return m_subscribedInstance->Handle_Request_Timeout();
330 size_t m_fw_size = {};
334 size_t m_total_chunks = {};
335 size_t m_requested_chunks = {};
339#if !THINGSBOARD_ENABLE_STL
340OTA_Handler *OTA_Handler::m_subscribedInstance =
nullptr;
size_t constexpr MAX_STRING_HASH_SIZE
Definition: HashGenerator.h:17
OTA_Failure_Response
Possible responses to error states the OTA update might fall into.
Definition: OTA_Failure_Response.h:11
char constexpr FW_STATE_DOWNLOADED[]
Definition: OTA_Handler.h:20
char constexpr ERROR_UPDATE_END[]
Definition: OTA_Handler.h:32
char constexpr FW_STATE_DOWNLOADING[]
Definition: OTA_Handler.h:19
char constexpr FW_STATE_UPDATING[]
Definition: OTA_Handler.h:21
char constexpr CHUNK_REQUEST_TIMED_OUT[]
Definition: OTA_Handler.h:35
char constexpr RECEIVED_UNEXPECTED_CHUNK_SIZE[]
Definition: OTA_Handler.h:29
char constexpr FW_STATE_FAILED[]
Definition: OTA_Handler.h:22
char constexpr UNABLE_TO_REQUEST_CHUNCKS[]
Definition: OTA_Handler.h:27
char constexpr FW_UPDATE_ABORTED[]
Definition: OTA_Handler.h:34
char constexpr RECEIVED_UNEXPECTED_CHUNK[]
Definition: OTA_Handler.h:28
char constexpr FW_STATE_UPDATED[]
Definition: OTA_Handler.h:23
char constexpr CHECKSUM_VERIFICATION_FAILED[]
Definition: OTA_Handler.h:33
char constexpr ERROR_UPDATE_BEGIN[]
Definition: OTA_Handler.h:30
char constexpr OTA_CB_IS_NULL[]
Definition: OTA_Handler.h:26
char constexpr ERROR_UPDATE_WRITE[]
Definition: OTA_Handler.h:31
General purpose safe callback wrapper. Expects either c-style or c++ style function pointer,...
Definition: Callback.h:30
std::function< return_type(argument_types... arguments)> function
Callback signature.
Definition: Callback.h:34
return_type Call_Callback(argument_types const &... arguments) const
Calls the callback that was subscribed, when this class instance was initally created.
Definition: Callback.h:62
Wrapper class which allows generating a hash of a given type from any arbitrary byte payload,...
Definition: HashGenerator.h:28
bool start(mbedtls_md_type_t const &type)
Starts the hashing process.
Definition: HashGenerator.cpp:11
bool update(uint8_t const *data, size_t const &length)
Update the current hash value with new data.
Definition: HashGenerator.cpp:24
HashString finish()
Calculates the final hash string representation and stops the hash calculation no further calls to up...
Definition: HashGenerator.cpp:28
static size_t Calculate_Print_Size(char const *format, Args const &... args)
Returns the total amount of bytes needed to store the formatted string with null termination,...
Definition: Helper.h:32
virtual void reset()=0
Resets the writing of the given data so it can be restarted with begin.
Handles the complete processing of received binary firmware data including writing the data into some...
Definition: OTA_Handler.h:50
void Stop_Firmware_Update()
Stops the firmware update completly and informs that user that the update has failed because it has b...
Definition: OTA_Handler.h:99
void Process_Firmware_Packet(size_t const ¤t_chunk, uint8_t *payload, size_t const &total_bytes)
Called when the chunk response is received from the server and if successfull sends the request for t...
Definition: OTA_Handler.h:116
void Start_Firmware_Update(OTA_Update_Callback &fw_callback, size_t const &fw_size, char const *fw_checksum, mbedtls_md_type_t const &fw_checksum_algorithm)
Starts the firmware update with requesting the first firmware packet and initalizes the underlying ne...
Definition: OTA_Handler.h:80
OTA_Handler(Callback< bool, size_t const &, size_t const & >::function publish_callback, Callback< bool, char const *const, char const *const >::function send_fw_state_callback, Callback< bool >::function finish_callback)
Constructor.
Definition: OTA_Handler.h:56
void update()
Used to update the watchdog timer which uses a simple software time in the background....
Definition: OTA_Handler.h:168
Over the air firmware update callback wrapper.
Definition: OTA_Update_Callback.h:19
Timeoutable_Request & Get_Request_Timeout()
Gets the request timeout callback.
Definition: OTA_Update_Callback.cpp:83
void Call_Progress_Callback(size_t const ¤t, size_t const &total) const
Calls the progress callback that was subscribed, when this class instance was initally created.
Definition: OTA_Update_Callback.cpp:51
uint8_t Get_Chunk_Retries() const
Gets the amount of times we attempt to download each chunk of the OTA firmware binary file.
Definition: OTA_Update_Callback.cpp:67
uint16_t Get_Chunk_Size() const
Gets the size of the chunks that the firmware binary data will be split into.
Definition: OTA_Update_Callback.cpp:75
IUpdater * Get_Updater() const
Gets the updater implementation, used to write the actual firmware data into the needed memory locati...
Definition: OTA_Update_Callback.cpp:35
size_t const & Get_Request_ID() const
Gets the unique request identifier that is connected to the original request.
Definition: OTA_Update_Callback.cpp:43
void Set_Timeout_Callback(Callback_Watchdog::function timeout_callback)
Sets the callback method that will be called upon request timeout (did not receive a response from th...
Definition: Timeoutable_Request.cpp:36
uint64_t const & Get_Timeout() const
Gets the amount of microseconds until we expect to have received a response.
Definition: Timeoutable_Request.cpp:11
void Update_Timeout_Timer()
Updates the internal timeout timer.
Definition: Timeoutable_Request.cpp:20
void Start_Timeout_Timer()
Starts the internal timeout timer if we actually received a configured valid timeout time and a valid...
Definition: Timeoutable_Request.cpp:25
void Stop_Timeout_Timer()
Stops the internal timeout timer, is called as soon as an answer is received from the cloud....
Definition: Timeoutable_Request.cpp:32