leo hendrickson
/
S
Diff: simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/source/lwm2m-source.cpp
- Revision:
- 0:25fa8795676b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/source/lwm2m-source.cpp Sun Apr 18 15:20:23 2021 +0000 @@ -0,0 +1,726 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- +// Note: this macro is needed on armcc to get the the PRI*32 macros +// from inttypes.h in a C++ code. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include <inttypes.h> + +#include "update-lwm2m-mbed-apis.h" +#include "update-client-common/arm_uc_common.h" +#include "update-client-lwm2m/lwm2m-source.h" +#include "update-client-lwm2m/FirmwareUpdateResource.h" +#include "update-client-lwm2m/DeviceMetadataResource.h" +#include "update-client-common/arm_uc_config.h" + +/* error management */ +static arm_uc_error_t arm_ucs_lwm2m_error = {ERR_NONE}; +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetError(void) { return arm_ucs_lwm2m_error; } +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_SetError(arm_uc_error_t an_error) { return (arm_ucs_lwm2m_error = an_error); } + +/* forward declaration */ +static void ARM_UCS_PackageCallback(const uint8_t *buffer, uint16_t length); + +/* local copy of the received manifest */ +static uint8_t *arm_ucs_manifest_buffer = NULL; +static uint16_t arm_ucs_manifest_length = 0; + +/* callback function pointer and struct */ +static void (*ARM_UCS_EventHandler)(uintptr_t event) = 0; +static arm_uc_callback_t callbackNodeManifest = { NULL, 0, NULL, 0 }; +static arm_uc_callback_t callbackNodeNotification = { NULL, 0, NULL, 0 }; + +#if defined(ARM_UC_FEATURE_FW_SOURCE_COAP) && (ARM_UC_FEATURE_FW_SOURCE_COAP == 1) +static bool arm_uc_get_data_request_transaction_ongoing = false; +static size_t arm_uc_received_file_size = 0; +static size_t arm_uc_total_file_size = 0; +static void arm_uc_get_data_req_callback(const uint8_t *buffer, size_t buffer_size, size_t total_size, bool last_block, + void *context); +static void arm_uc_get_data_req_error_callback(get_data_req_error_t error_code, void *context); + +#define ARM_UCS_DEFAULT_COST (900) +#define ARM_UCS_HASH_LENGTH (40) + +// The hub uses a double buffer system to speed up firmware download and storage +#define BUFFER_SIZE_MAX (ARM_UC_BUFFER_SIZE / 2) // define size of the double buffers + +#if BUFFER_SIZE_MAX < SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE +#error MBED_CLOUD_CLIENT_UPDATE_BUFFER must be at least double the size of SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE +#endif + +// Set proper Storage buffer size with requirements: +// 1. Storage buffer size >= Block size (SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE) +// 1. & 2 AND is >= page size (BUFFER_SIZE_MAX) +// 2. & 3. AND is multiple of Block size (X * SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE) +#define STORAGE_BUFFER_SIZE max_storage(SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE, BUFFER_SIZE_MAX) +// 1. 2. 3. +#define max_storage(X,Y) ((X) > (Y) ? (X) : ( (Y%X==0) ? (Y) :(BLOCK_MULTIPLIER(X,Y)*X))) + +#define BLOCK_MULTIPLIER(X,Y) ((Y/X)+1) + +static uint8_t storage_message[STORAGE_BUFFER_SIZE]; +static arm_uc_buffer_t storage_buffer = { + .size_max = STORAGE_BUFFER_SIZE, + .size = 0, + .ptr = storage_message +}; + +static arm_uc_buffer_t *output_buffer_ptr = NULL; +static char *copy_full_url = NULL; +static DownloadType download_type = FIRMWARE_DOWNLOAD; //default FIRMWARE = COAP download using filepath of server; + +#endif // ARM_UC_FEATURE_FW_SOURCE_COAP + +/** + * @brief Get driver version. + * @return Driver version. + */ +uint32_t ARM_UCS_LWM2M_SOURCE_GetVersion(void) +{ + return 0; +} + +/** + * @brief Get Source capabilities. + * @return Struct containing capabilites. See definition above. + */ +ARM_SOURCE_CAPABILITIES ARM_UCS_LWM2M_SOURCE_GetCapabilities(void) +{ + ARM_SOURCE_CAPABILITIES result; + UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetCapabilities:"); + + result.notify = 0; + result.manifest_default = 0; + result.manifest_url = 0; + result.firmware = 0; + result.keytable = 0; + + /* the event handler must be set before module can be used */ + if (ARM_UCS_EventHandler != 0) { + result.notify = 1; + result.manifest_default = 1; + result.manifest_url = 1; +#if defined(ARM_UC_FEATURE_FW_SOURCE_COAP) && (ARM_UC_FEATURE_FW_SOURCE_COAP == 1) + result.firmware = 1; +#endif + result.keytable = 1; + } + + return result; +} + +/** + * @brief Initialize Source. + * @details Function pointer to event handler is passed as argument. + * + * @param cb_event Function pointer to event handler. See events above. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_Initialize(ARM_SOURCE_SignalEvent_t cb_event) +{ + UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_Initialize: %p", cb_event); + ARM_UC_INIT_ERROR(result, SRCE_ERR_INVALID_PARAMETER); + +#if defined(ARM_UC_FEATURE_FW_SOURCE_COAP) && (ARM_UC_FEATURE_FW_SOURCE_COAP == 1) + arm_uc_get_data_request_transaction_ongoing = false; + arm_uc_received_file_size = 0; + arm_uc_total_file_size = 0; +#endif + + if (cb_event != 0) { + /* store callback handler */ + ARM_UCS_EventHandler = cb_event; + + /* Initialize LWM2M Firmware Update Object */ + FirmwareUpdateResource::Initialize(); + + /* Register callback handler */ + FirmwareUpdateResource::addPackageCallback(ARM_UCS_PackageCallback); + + DeviceMetadataResource::Initialize(); + + ARM_UC_SET_ERROR(result, ERR_NONE); + } + + if (ARM_UC_IS_ERROR(result)) { + ARM_UCS_LWM2M_SOURCE_SetError(result); + } + return result; +} + +/** + * @brief Uninitialized Source. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_Uninitialize(void) +{ + ARM_UC_INIT_ERROR(retval, ERR_NONE); + DeviceMetadataResource::Uninitialize(); + FirmwareUpdateResource::Uninitialize(); + + return retval; +} + +/** + * @brief Cost estimation for retrieving manifest from the default location. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The manifest is already downloaded. + * 0xFFFFFFFF - Cannot retrieve manifest from this Source. + * + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetManifestDefaultCost(uint32_t *cost) +{ + ARM_UC_INIT_ERROR(result, SRCE_ERR_INVALID_PARAMETER); + + if (cost != 0) { + /* set cost to 0 when manifest is cached */ + if (arm_ucs_manifest_buffer && arm_ucs_manifest_length) { + *cost = 0; + } + /* set cost to 0xFFFFFFFF when manifest has been read */ + else { + *cost = 0xFFFFFFFF; + } + + ARM_UC_SET_ERROR(result, ERR_NONE); + } + + if (ARM_UC_IS_ERROR(result)) { + ARM_UCS_LWM2M_SOURCE_SetError(result); + } + return result; +} + +/** + * @brief Retrieve manifest from the default location. + * @details Manifest is stored in supplied buffer. + * Event is generated once manifest is in buffer. + * + * @param buffer Struct containing byte array, maximum size, and actual size. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetManifestDefault(arm_uc_buffer_t *buffer, + uint32_t offset) +{ + ARM_UC_INIT_ERROR(result, SRCE_ERR_INVALID_PARAMETER); + + /* copy manifest from cache into buffer */ + if ((buffer != NULL) && + (buffer->ptr != NULL) && + (arm_ucs_manifest_buffer != NULL) && + (arm_ucs_manifest_length != 0) && + (offset < arm_ucs_manifest_length)) { + /* remaining length based on offset request */ + uint16_t length = arm_ucs_manifest_length - offset; + + /* set actual length based on buffer size */ + if (length > buffer->size_max) { + length = buffer->size_max; + } + + /* size check */ + if (length > 0) { + /* copy manifest from local buffer to external buffer */ + memcpy(buffer->ptr, &arm_ucs_manifest_buffer[offset], length); + buffer->size = length; + + /* delete local buffer once the entire manifest has been read */ + if (offset + length >= arm_ucs_manifest_length) { + delete[] arm_ucs_manifest_buffer; + arm_ucs_manifest_buffer = NULL; + arm_ucs_manifest_length = 0; + } + + ARM_UC_SET_ERROR(result, ERR_NONE); + + /* signal event handler that manifest has been copied to buffer */ + if (ARM_UCS_EventHandler) { + ARM_UC_PostCallback(&callbackNodeManifest, + ARM_UCS_EventHandler, + EVENT_MANIFEST); + } + } + } + + if (ARM_UC_IS_ERROR(result)) { + ARM_UCS_LWM2M_SOURCE_SetError(result); + } + return result; +} + +static void ARM_UCS_PackageCallback(const uint8_t *buffer, uint16_t length) +{ + uint32_t event_code = EVENT_ERROR; + + if (arm_ucs_manifest_buffer) { + UC_SRCE_ERR_MSG("received new manifest before reading the old one"); + + /* delete old buffer to make space for the new one */ + delete[] arm_ucs_manifest_buffer; + arm_ucs_manifest_length = 0; + } + + /* allocate a local buffer of the same size as the manifest */ + arm_ucs_manifest_buffer = new uint8_t[length]; + + if (arm_ucs_manifest_buffer) { + /* copy manifest from payload to local buffer */ + memcpy(arm_ucs_manifest_buffer, buffer, length); + arm_ucs_manifest_length = length; + + event_code = EVENT_NOTIFICATION; + } + + /* signal event handler with result */ + if (ARM_UCS_EventHandler) { + ARM_UC_PostCallback(&callbackNodeNotification, + ARM_UCS_EventHandler, + event_code); + } +} + + +/** + * @brief Cost estimation for retrieving firmware from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The firmware is already downloaded. + * 0xFFFFFFFF - Cannot retrieve firmware from this Source. + * + * @param uri URI struct with firmware location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetFirmwareURLCost(arm_uc_uri_t *uri, + uint32_t *cost) +{ + UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareURLCost"); + + ARM_UC_INIT_ERROR(result, SRCE_ERR_INVALID_PARAMETER); + +#if defined(ARM_UC_FEATURE_FW_SOURCE_COAP) && (ARM_UC_FEATURE_FW_SOURCE_COAP == 1) + /* not supported - return default cost regardless of actual uri location */ + if ((uri != 0) && (cost != 0)) { + UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareURLCost uri and cost"); + *cost = ARM_UCS_DEFAULT_COST; + result.code = ERR_NONE ; + } +#else + /* not supported */ + if (cost != 0) { + UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareURLCost cost 0xFFFFFFFF"); + *cost = 0xFFFFFFFF; + result.code = ERR_NONE ; + } +#endif + if (ARM_UC_IS_ERROR(result)) { + ARM_UCS_LWM2M_SOURCE_SetError(result); + } + return result; +} + + +/** + * @brief Retrieve firmware fragment. + * @details Firmware fragment is stored in supplied buffer. + * Event is generated once fragment is in buffer. + * + * @param uri URI struct with firmware location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * @param offset Firmware offset to retrieve fragment from. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment(arm_uc_uri_t *uri, + arm_uc_buffer_t *buffer, + uint32_t offset) +{ + + arm_uc_error_t retval = { .code = SRCE_ERR_INVALID_PARAMETER }; +#if defined(ARM_UC_FEATURE_FW_SOURCE_COAP) && (ARM_UC_FEATURE_FW_SOURCE_COAP == 1) + if (uri == NULL || buffer == NULL || FirmwareUpdateResource::getM2MInterface() == NULL) { + return retval; + } + + UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment: %s %s, buffer size: %" PRIu32 ", buffer max: %" PRIu32 + " offset: %" PRIu32, (const char *)uri->ptr, uri->path, buffer->size, buffer->size_max, offset); + UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment: total file size %" PRIu32 ", received file size %" PRIu32, + (uint32_t)arm_uc_total_file_size, (uint32_t)arm_uc_received_file_size); + + /* + * NOTE: we are using M2MInterface API "get_data_request()" asynchronously, so first call to GetFirmwareFragment() + * will not return anything in the buffer. Instead we will get COAP blocks into callback arm_uc_get_data_req_callback() + * where we will copy those to our internal storage_buffer. When storage_buffer has enough data + * (more or eq than buffer->size_max == Storage Page size) we will copy data from it to output buffer + * and indicate to Hub state machine using event EVENT_FIRMWARE + */ + if (offset == 0) { + // First fragment + storage_buffer.size = 0; + arm_uc_received_file_size = 0; + arm_uc_total_file_size = 0; + } else if (arm_uc_received_file_size == 0) { + // The received file size was reset to zero indicating that we have received the full payload + // as indicated by the server but we are asked to carry on downloading from the given offset. + // This indicates a mismatch between the actual payload size in the server and that given in the manifest. + UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment: payload size indicated in manifest is bigger than that reported by server!"); + if (ARM_UCS_EventHandler) { + ARM_UC_PostCallback(&callbackNodeManifest, + ARM_UCS_EventHandler, + EVENT_ERROR); + } + return retval; + } + + output_buffer_ptr = buffer; + free(copy_full_url); + copy_full_url = (char *)malloc(arm_uc_calculate_full_uri_length(uri)); + if (copy_full_url == NULL) { + //TODO to return SRCE_ERR_OUT_OF_MEMORY + UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment: ERROR OUT OF MEMORY for uri copy!"); + return retval; + } + if (uri->scheme == URI_SCHEME_COAPS) { + strcpy(copy_full_url, UC_COAPS_STRING); + } else if (uri->scheme == URI_SCHEME_HTTP) { + strcpy(copy_full_url, UC_HTTP_STRING); + } else { + UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment: Not Supported SCHEME! length of copy url: %u", + sizeof(copy_full_url)); + return retval; + } + strcat(copy_full_url, (const char *)uri->ptr); + strcat(copy_full_url, uri->path); + + if ((arm_uc_received_file_size == arm_uc_total_file_size && + arm_uc_received_file_size != 0)) { + + // If last block - write to buffer and complete + if (storage_buffer.ptr && + (arm_uc_received_file_size == arm_uc_total_file_size)) { + memcpy(buffer->ptr, storage_buffer.ptr, storage_buffer.size); + buffer->size = storage_buffer.size; + memmove(storage_buffer.ptr, storage_buffer.ptr + storage_buffer.size, (storage_buffer.size_max - storage_buffer.size)); + storage_buffer.size -= buffer->size; + } + + // We were waiting for one more state machine cycle for previous write to complete + // Now we can return with EVENT_FIRMWARE so that main state machine changes properly + if (ARM_UCS_EventHandler) { + ARM_UC_PostCallback(&callbackNodeManifest, + ARM_UCS_EventHandler, + EVENT_FIRMWARE); + } + retval.code = ERR_NONE; + arm_uc_received_file_size = 0; + arm_uc_total_file_size = 0; + } else if (!arm_uc_get_data_request_transaction_ongoing) { + // We need to get request for next block of data + UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment: Issue new get request for uri: %s, offset: %" PRIu32, + copy_full_url, (uint32_t)arm_uc_received_file_size); + if (FirmwareUpdateResource::getM2MInterface()) { + + FirmwareUpdateResource::getM2MInterface()->get_data_request(download_type, + copy_full_url, + arm_uc_received_file_size, + true, + arm_uc_get_data_req_callback, + arm_uc_get_data_req_error_callback, + FirmwareUpdateResource::getM2MInterface()); + + arm_uc_get_data_request_transaction_ongoing = true; + + retval.code = ERR_NONE; + } + } else { + // There is not enough data in Storage buffer yet + // AND We have Async get_data_request already ongoing + // -> Do nothing we should not get here? + // This can happen if GetFirmwareFragment is called again before + // the previous get completed with buffer and EVENT_FIRMWARE + UC_SRCE_ERR_MSG("Internal error: BLOCK - data request already ongoing"); + } + if (ARM_UC_IS_ERROR(retval)) { + ARM_UCS_LWM2M_SOURCE_SetError(retval); + } + return retval; +#else + (void) uri; + (void) buffer; + (void) offset; + return retval; +#endif //ARM_UC_FEATURE_FW_SOURCE_COAP +} + +#if defined(ARM_UC_FEATURE_FW_SOURCE_COAP) && (ARM_UC_FEATURE_FW_SOURCE_COAP == 1) +void arm_uc_get_data_req_callback(const uint8_t *buffer, size_t buffer_size, size_t total_size, bool last_block, + void *context) +{ + (void)last_block; + + UC_SRCE_TRACE("get_data_req_callback: %" PRIu32 ", %" PRIu32, (uint32_t)buffer_size, (uint32_t)total_size); + M2MInterface *interface = (M2MInterface *)context; + + if (arm_uc_received_file_size == 0) { + arm_uc_total_file_size = total_size; + } + + arm_uc_received_file_size += buffer_size; + UC_SRCE_TRACE("get_data_req_callback: received %" PRIu32 "/%" PRIu32, (uint32_t)arm_uc_received_file_size, + (uint32_t)arm_uc_total_file_size); + + if (arm_uc_received_file_size == arm_uc_total_file_size) { + UC_SRCE_TRACE("get_data_req_callback: transfer completed\n"); + } + + /* + * FLOW: + * 1. If there is space in Storage buffer for the incoming buffer -> copy buffer to storage buffer + * 2. Else signal error event EVENT_ERROR_BUFFER_SIZE + */ + // Check there is space available in the storage buffer + if (storage_buffer.size_max - storage_buffer.size >= buffer_size) { + memcpy(storage_buffer.ptr + storage_buffer.size, buffer, buffer_size); + storage_buffer.size += buffer_size; + } else { + // Error - no space available, signal it to source manager + UC_SRCE_TRACE("arm_uc_get_data_req_callback: Storage Buffer OVERFLOW ERROR!! \n"); + if (ARM_UCS_EventHandler) { + ARM_UC_PostCallback(&callbackNodeManifest, + ARM_UCS_EventHandler, + EVENT_ERROR_BUFFER_SIZE); + } + return; + } + + /* + * FLOW: + * 1. If there is enough data in storage-buffer now to complete to output buffer, copy now and indicate with EVENT_FIRMWARE + * to continue to write -cycle + * 2. Else if this is the last block of data, copy the remaining (<size_max) to output buffer and indicate with + * EVENT_FIRMWARE to continue to write-cycle + * 3. Else Request new block of data using API get_data_request + */ + if (storage_buffer.size >= output_buffer_ptr->size_max) { + // 1. We have received into Storage buffer at least one page size of data + // -> Let's return it to UC Hub so that it can be written + UC_SRCE_TRACE("arm_uc_get_data_req_callback: return with Storage buffer size: %" PRIu32 ", buffer size: %" PRIu32, + storage_buffer.size, output_buffer_ptr->size_max); + if (storage_buffer.ptr) { + memcpy(output_buffer_ptr->ptr, storage_buffer.ptr, output_buffer_ptr->size_max); + //storage_buffer.ptr += buffer->size_max; + memmove(storage_buffer.ptr, storage_buffer.ptr + output_buffer_ptr->size_max, + (storage_buffer.size_max - output_buffer_ptr->size_max)); + storage_buffer.size -= output_buffer_ptr->size_max; + output_buffer_ptr->size = output_buffer_ptr->size_max; + } + + if (ARM_UCS_EventHandler) { + ARM_UC_PostCallback(&callbackNodeManifest, + ARM_UCS_EventHandler, + EVENT_FIRMWARE); + } + arm_uc_get_data_request_transaction_ongoing = false; + } else if (arm_uc_received_file_size == arm_uc_total_file_size && + arm_uc_received_file_size != 0) { + + // 2. this is the last block of data - copy to output buffer and complete with EVENT_FIRMWARE + if (storage_buffer.ptr && + (arm_uc_received_file_size == arm_uc_total_file_size)) { + memcpy(output_buffer_ptr->ptr, storage_buffer.ptr, storage_buffer.size); + output_buffer_ptr->size = storage_buffer.size; + + memmove(storage_buffer.ptr, storage_buffer.ptr + storage_buffer.size, (storage_buffer.size_max - storage_buffer.size)); + storage_buffer.size = 0; + } + + // We were waiting for one more state machine cycle for previous write to complete + // Now we can return with EVENT_FIRMWARE so that main state machine changes properly + if (ARM_UCS_EventHandler) { + ARM_UC_PostCallback(&callbackNodeManifest, + ARM_UCS_EventHandler, + EVENT_FIRMWARE); + } + arm_uc_get_data_request_transaction_ongoing = false; + free(copy_full_url); + copy_full_url = NULL; + arm_uc_received_file_size = 0; + arm_uc_total_file_size = 0; + } else { + // 3. We want to issue new get data + UC_SRCE_TRACE("arm_uc_get_data_req_callback: Issue new get request for uri: %s, offset: %" PRIu32, copy_full_url, + (uint32_t)arm_uc_received_file_size); + interface->get_data_request(download_type, + copy_full_url, + arm_uc_received_file_size, + true, + arm_uc_get_data_req_callback, + arm_uc_get_data_req_error_callback, + interface); + arm_uc_get_data_request_transaction_ongoing = true; + } +#ifdef ARM_UC_COAP_DATA_PRINTOUT + if (buffer) { + uint32_t i = 0; + int row_len = 40; + uint32_t max_length = 2048; + + while (i < buffer_size && i < max_length) { + if (i + row_len > buffer_size) { + row_len = buffer_size - i; + } + UC_SRCE_TRACE("Payload:\t\t%s", tr_array(buffer + i, row_len)); // in HEX + + i += row_len; + } + + } +#endif +} + +void arm_uc_get_data_req_error_callback(get_data_req_error_t error_code, void *context) +{ + UC_SRCE_TRACE("get_data_req_error_callback: ERROR: %u\n", error_code); + arm_uc_received_file_size = 0; + arm_uc_total_file_size = 0; + arm_uc_get_data_request_transaction_ongoing = false; + free(copy_full_url); + copy_full_url = NULL; + download_type = FIRMWARE_DOWNLOAD; + if (ARM_UCS_EventHandler) { + ARM_UC_PostCallback(&callbackNodeManifest, + ARM_UCS_EventHandler, + EVENT_ERROR); + } +} +#endif //ARM_UC_FEATURE_FW_SOURCE_COAP + +/*****************************************************************************/ +/* Capabilities not supported by this source */ +/*****************************************************************************/ + +/** + * @brief Cost estimation for retrieving manifest from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The manifest is already downloaded. + * 0xFFFFFFFF - Cannot retrieve manifest from this Source. + * + * @param uri URI struct with manifest location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetManifestURLCost(arm_uc_uri_t *uri, + uint32_t *cost) +{ + (void) uri; + (void) cost; + + ARM_UC_INIT_ERROR(result, SRCE_ERR_INVALID_PARAMETER); + + /* not supported - return default cost regardless of actual uri location */ + if (cost) { + *cost = 0xFFFFFFFF; + ARM_UC_SET_ERROR(result, ERR_NONE); + } + + if (ARM_UC_IS_ERROR(result)) { + ARM_UCS_LWM2M_SOURCE_SetError(result); + } + return result; +} + +/** + * @brief Cost estimation for retrieving key table from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The firmware is already downloaded. + * 0xFFFFFFFF - Cannot retrieve firmware from this Source. + * + * @param uri URI struct with keytable location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetKeytableURLCost(arm_uc_uri_t *uri, + uint32_t *cost) +{ + (void) uri; + (void) cost; + + ARM_UC_INIT_ERROR(result, SRCE_ERR_INVALID_PARAMETER); + + /* not supported - return default cost regardless of actual uri location */ + if ((uri != 0) && (cost != 0)) { + *cost = 0xFFFFFFFF; + ARM_UC_SET_ERROR(result, ERR_NONE); + } + + if (ARM_UC_IS_ERROR(result)) { + ARM_UCS_LWM2M_SOURCE_SetError(result); + } + return result; +} + +/** + * @brief Retrieve manifest from URL. + * @details Manifest is stored in supplied buffer. + * Event is generated once manifest is in buffer. + * + * @param uri URI struct with manifest location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetManifestURL(arm_uc_uri_t *uri, + arm_uc_buffer_t *buffer, + uint32_t offset) +{ + (void) uri; + (void) buffer; + (void) offset; + + ARM_UC_INIT_ERROR(retval, SRCE_ERR_INVALID_PARAMETER); + + if (ARM_UC_IS_ERROR(retval)) { + ARM_UCS_LWM2M_SOURCE_SetError(retval); + } + return retval; +} + +/** + * @brief Retrieve a key table from a URL. + * @details Key table is stored in supplied buffer. + * Event is generated once fragment is in buffer. + * + * @param uri URI struct with keytable location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetKeytableURL(arm_uc_uri_t *uri, + arm_uc_buffer_t *buffer) +{ + (void) uri; + (void) buffer; + + ARM_UC_INIT_ERROR(retval, SRCE_ERR_INVALID_PARAMETER); + + if (ARM_UC_IS_ERROR(retval)) { + ARM_UCS_LWM2M_SOURCE_SetError(retval); + } + return retval; +}