Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwm2m-source.cpp Source File

lwm2m-source.cpp

00001 // ----------------------------------------------------------------------------
00002 // Copyright 2016-2017 ARM Ltd.
00003 //
00004 // SPDX-License-Identifier: Apache-2.0
00005 //
00006 // Licensed under the Apache License, Version 2.0 (the "License");
00007 // you may not use this file except in compliance with the License.
00008 // You may obtain a copy of the License at
00009 //
00010 //     http://www.apache.org/licenses/LICENSE-2.0
00011 //
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 // ----------------------------------------------------------------------------
00018 // Note: this macro is needed on armcc to get the the PRI*32 macros
00019 // from inttypes.h in a C++ code.
00020 #ifndef __STDC_FORMAT_MACROS
00021 #define __STDC_FORMAT_MACROS
00022 #endif
00023 
00024 #include <inttypes.h>
00025 
00026 #include "update-lwm2m-mbed-apis.h"
00027 #include "update-client-common/arm_uc_common.h"
00028 #include "update-client-lwm2m/lwm2m-source.h"
00029 #include "update-client-lwm2m/FirmwareUpdateResource.h"
00030 #include "update-client-lwm2m/DeviceMetadataResource.h"
00031 #include "update-client-common/arm_uc_config.h"
00032 
00033 /* error management */
00034 static arm_uc_error_t arm_ucs_lwm2m_error = {ERR_NONE};
00035 arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetError(void) { return arm_ucs_lwm2m_error; }
00036 arm_uc_error_t ARM_UCS_LWM2M_SOURCE_SetError(arm_uc_error_t an_error) { return (arm_ucs_lwm2m_error = an_error); }
00037 
00038 /* forward declaration */
00039 static void ARM_UCS_PackageCallback(const uint8_t *buffer, uint16_t length);
00040 
00041 /* local copy of the received manifest */
00042 static uint8_t *arm_ucs_manifest_buffer = NULL;
00043 static uint16_t arm_ucs_manifest_length = 0;
00044 
00045 /* callback function pointer and struct */
00046 static void (*ARM_UCS_EventHandler)(uintptr_t event) = 0;
00047 static arm_uc_callback_t callbackNodeManifest = { NULL, 0, NULL, 0 };
00048 static arm_uc_callback_t callbackNodeNotification = { NULL, 0, NULL, 0 };
00049 
00050 #if defined(ARM_UC_FEATURE_FW_SOURCE_COAP) && (ARM_UC_FEATURE_FW_SOURCE_COAP == 1)
00051 static bool arm_uc_get_data_request_transaction_ongoing = false;
00052 static size_t arm_uc_received_file_size = 0;
00053 static size_t arm_uc_total_file_size = 0;
00054 static void arm_uc_get_data_req_callback(const uint8_t *buffer, size_t buffer_size, size_t total_size, bool last_block,
00055                                          void *context);
00056 static void arm_uc_get_data_req_error_callback(get_data_req_error_t error_code, void *context);
00057 
00058 #define ARM_UCS_DEFAULT_COST (900)
00059 #define ARM_UCS_HASH_LENGTH  (40)
00060 
00061 // The hub uses a double buffer system to speed up firmware download and storage
00062 #define BUFFER_SIZE_MAX (ARM_UC_BUFFER_SIZE / 2) //  define size of the double buffers
00063 
00064 #if BUFFER_SIZE_MAX < SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE
00065 #error MBED_CLOUD_CLIENT_UPDATE_BUFFER must be at least double the size of SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE
00066 #endif
00067 
00068 // Set proper Storage buffer size with requirements:
00069 // 1. Storage buffer size >= Block size (SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE)
00070 // 1. & 2 AND is >= page size (BUFFER_SIZE_MAX)
00071 // 2. & 3. AND is multiple of Block size (X * SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE)
00072 #define STORAGE_BUFFER_SIZE max_storage(SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE, BUFFER_SIZE_MAX)
00073 //                                  1.               2.                 3.
00074 #define max_storage(X,Y)    ((X) > (Y) ? (X) : ( (Y%X==0) ? (Y) :(BLOCK_MULTIPLIER(X,Y)*X)))
00075 
00076 #define BLOCK_MULTIPLIER(X,Y)   ((Y/X)+1)
00077 
00078 static uint8_t storage_message[STORAGE_BUFFER_SIZE];
00079 static arm_uc_buffer_t storage_buffer = {
00080     .size_max = STORAGE_BUFFER_SIZE,
00081     .size = 0,
00082     .ptr = storage_message
00083 };
00084 
00085 static arm_uc_buffer_t *output_buffer_ptr = NULL;
00086 static char *copy_full_url = NULL;
00087 static DownloadType download_type = FIRMWARE_DOWNLOAD; //default FIRMWARE = COAP download using filepath of server;
00088 
00089 #endif // ARM_UC_FEATURE_FW_SOURCE_COAP
00090 
00091 /**
00092  * @brief Get driver version.
00093  * @return Driver version.
00094  */
00095 uint32_t ARM_UCS_LWM2M_SOURCE_GetVersion(void)
00096 {
00097     return 0;
00098 }
00099 
00100 /**
00101  * @brief Get Source capabilities.
00102  * @return Struct containing capabilites. See definition above.
00103  */
00104 ARM_SOURCE_CAPABILITIES ARM_UCS_LWM2M_SOURCE_GetCapabilities(void)
00105 {
00106     ARM_SOURCE_CAPABILITIES result;
00107     UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetCapabilities:");
00108 
00109     result.notify = 0;
00110     result.manifest_default = 0;
00111     result.manifest_url = 0;
00112     result.firmware = 0;
00113     result.keytable = 0;
00114 
00115     /* the event handler must be set before module can be used */
00116     if (ARM_UCS_EventHandler != 0) {
00117         result.notify = 1;
00118         result.manifest_default = 1;
00119         result.manifest_url = 1;
00120 #if defined(ARM_UC_FEATURE_FW_SOURCE_COAP) && (ARM_UC_FEATURE_FW_SOURCE_COAP == 1)
00121         result.firmware = 1;
00122 #endif
00123         result.keytable = 1;
00124     }
00125 
00126     return result;
00127 }
00128 
00129 /**
00130  * @brief Initialize Source.
00131  * @details Function pointer to event handler is passed as argument.
00132  *
00133  * @param cb_event Function pointer to event handler. See events above.
00134  * @return Error code.
00135  */
00136 arm_uc_error_t ARM_UCS_LWM2M_SOURCE_Initialize(ARM_SOURCE_SignalEvent_t cb_event)
00137 {
00138     UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_Initialize: %p", cb_event);
00139     ARM_UC_INIT_ERROR(result, SRCE_ERR_INVALID_PARAMETER);
00140 
00141 #if defined(ARM_UC_FEATURE_FW_SOURCE_COAP) && (ARM_UC_FEATURE_FW_SOURCE_COAP == 1)
00142     arm_uc_get_data_request_transaction_ongoing = false;
00143     arm_uc_received_file_size = 0;
00144     arm_uc_total_file_size = 0;
00145 #endif
00146 
00147     if (cb_event != 0) {
00148         /* store callback handler */
00149         ARM_UCS_EventHandler = cb_event;
00150 
00151         /* Initialize LWM2M Firmware Update Object */
00152         FirmwareUpdateResource::Initialize();
00153 
00154         /* Register callback handler */
00155         FirmwareUpdateResource::addPackageCallback(ARM_UCS_PackageCallback);
00156 
00157         DeviceMetadataResource::Initialize();
00158 
00159         ARM_UC_SET_ERROR(result, ERR_NONE);
00160     }
00161 
00162     if (ARM_UC_IS_ERROR(result)) {
00163         ARM_UCS_LWM2M_SOURCE_SetError(result);
00164     }
00165     return result;
00166 }
00167 
00168 /**
00169  * @brief Uninitialized Source.
00170  * @return Error code.
00171  */
00172 arm_uc_error_t ARM_UCS_LWM2M_SOURCE_Uninitialize(void)
00173 {
00174     ARM_UC_INIT_ERROR(retval, ERR_NONE);
00175     DeviceMetadataResource::Uninitialize();
00176     FirmwareUpdateResource::Uninitialize();
00177 
00178     return retval;
00179 }
00180 
00181 /**
00182  * @brief Cost estimation for retrieving manifest from the default location.
00183  * @details The estimation can vary over time and should not be cached too long.
00184  *          0x00000000 - The manifest is already downloaded.
00185  *          0xFFFFFFFF - Cannot retrieve manifest from this Source.
00186  *
00187  * @param cost Pointer to variable for the return value.
00188  * @return Error code.
00189  */
00190 arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetManifestDefaultCost(uint32_t *cost)
00191 {
00192     ARM_UC_INIT_ERROR(result, SRCE_ERR_INVALID_PARAMETER);
00193 
00194     if (cost != 0) {
00195         /* set cost to 0 when manifest is cached */
00196         if (arm_ucs_manifest_buffer && arm_ucs_manifest_length) {
00197             *cost = 0;
00198         }
00199         /* set cost to 0xFFFFFFFF when manifest has been read */
00200         else {
00201             *cost = 0xFFFFFFFF;
00202         }
00203 
00204         ARM_UC_SET_ERROR(result, ERR_NONE);
00205     }
00206 
00207     if (ARM_UC_IS_ERROR(result)) {
00208         ARM_UCS_LWM2M_SOURCE_SetError(result);
00209     }
00210     return result;
00211 }
00212 
00213 /**
00214  * @brief Retrieve manifest from the default location.
00215  * @details Manifest is stored in supplied buffer.
00216  *          Event is generated once manifest is in buffer.
00217  *
00218  * @param buffer Struct containing byte array, maximum size, and actual size.
00219  * @return Error code.
00220  */
00221 arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetManifestDefault(arm_uc_buffer_t *buffer,
00222                                                        uint32_t offset)
00223 {
00224     ARM_UC_INIT_ERROR(result, SRCE_ERR_INVALID_PARAMETER);
00225 
00226     /* copy manifest from cache into buffer */
00227     if ((buffer != NULL) &&
00228             (buffer->ptr != NULL) &&
00229             (arm_ucs_manifest_buffer != NULL) &&
00230             (arm_ucs_manifest_length != 0) &&
00231             (offset < arm_ucs_manifest_length)) {
00232         /* remaining length based on offset request */
00233         uint16_t length = arm_ucs_manifest_length - offset;
00234 
00235         /* set actual length based on buffer size */
00236         if (length > buffer->size_max) {
00237             length = buffer->size_max;
00238         }
00239 
00240         /* size check */
00241         if (length > 0) {
00242             /* copy manifest from local buffer to external buffer */
00243             memcpy(buffer->ptr, &arm_ucs_manifest_buffer[offset], length);
00244             buffer->size = length;
00245 
00246             /* delete local buffer once the entire manifest has been read */
00247             if (offset + length >= arm_ucs_manifest_length) {
00248                 delete[] arm_ucs_manifest_buffer;
00249                 arm_ucs_manifest_buffer = NULL;
00250                 arm_ucs_manifest_length = 0;
00251             }
00252 
00253             ARM_UC_SET_ERROR(result, ERR_NONE);
00254 
00255             /* signal event handler that manifest has been copied to buffer */
00256             if (ARM_UCS_EventHandler) {
00257                 ARM_UC_PostCallback(&callbackNodeManifest,
00258                                     ARM_UCS_EventHandler,
00259                                     EVENT_MANIFEST);
00260             }
00261         }
00262     }
00263 
00264     if (ARM_UC_IS_ERROR(result)) {
00265         ARM_UCS_LWM2M_SOURCE_SetError(result);
00266     }
00267     return result;
00268 }
00269 
00270 static void ARM_UCS_PackageCallback(const uint8_t *buffer, uint16_t length)
00271 {
00272     uint32_t event_code = EVENT_ERROR;
00273 
00274     if (arm_ucs_manifest_buffer) {
00275         UC_SRCE_ERR_MSG("received new manifest before reading the old one");
00276 
00277         /* delete old buffer to make space for the new one */
00278         delete[] arm_ucs_manifest_buffer;
00279         arm_ucs_manifest_length = 0;
00280     }
00281 
00282     /* allocate a local buffer of the same size as the manifest */
00283     arm_ucs_manifest_buffer = new uint8_t[length];
00284 
00285     if (arm_ucs_manifest_buffer) {
00286         /* copy manifest from payload to local buffer */
00287         memcpy(arm_ucs_manifest_buffer, buffer, length);
00288         arm_ucs_manifest_length = length;
00289 
00290         event_code = EVENT_NOTIFICATION;
00291     }
00292 
00293     /* signal event handler with result */
00294     if (ARM_UCS_EventHandler) {
00295         ARM_UC_PostCallback(&callbackNodeNotification,
00296                             ARM_UCS_EventHandler,
00297                             event_code);
00298     }
00299 }
00300 
00301 
00302 /**
00303  * @brief Cost estimation for retrieving firmware from URL.
00304  * @details The estimation can vary over time and should not be cached too long.
00305  *          0x00000000 - The firmware is already downloaded.
00306  *          0xFFFFFFFF - Cannot retrieve firmware from this Source.
00307  *
00308  * @param uri URI struct with firmware location.
00309  * @param cost Pointer to variable for the return value.
00310  * @return Error code.
00311  */
00312 arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetFirmwareURLCost(arm_uc_uri_t *uri,
00313                                                        uint32_t *cost)
00314 {
00315     UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareURLCost");
00316 
00317     ARM_UC_INIT_ERROR(result, SRCE_ERR_INVALID_PARAMETER);
00318 
00319 #if defined(ARM_UC_FEATURE_FW_SOURCE_COAP) && (ARM_UC_FEATURE_FW_SOURCE_COAP == 1)
00320     /* not supported - return default cost regardless of actual uri location */
00321     if ((uri != 0) && (cost != 0)) {
00322         UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareURLCost uri and cost");
00323         *cost = ARM_UCS_DEFAULT_COST;
00324         result.code = ERR_NONE ;
00325     }
00326 #else
00327     /* not supported */
00328     if (cost != 0) {
00329         UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareURLCost cost 0xFFFFFFFF");
00330         *cost = 0xFFFFFFFF;
00331         result.code = ERR_NONE ;
00332     }
00333 #endif
00334     if (ARM_UC_IS_ERROR(result)) {
00335         ARM_UCS_LWM2M_SOURCE_SetError(result);
00336     }
00337     return result;
00338 }
00339 
00340 
00341 /**
00342  * @brief Retrieve firmware fragment.
00343  * @details Firmware fragment is stored in supplied buffer.
00344  *          Event is generated once fragment is in buffer.
00345  *
00346  * @param uri URI struct with firmware location.
00347  * @param buffer Struct containing byte array, maximum size, and actual size.
00348  * @param offset Firmware offset to retrieve fragment from.
00349  * @return Error code.
00350  */
00351 arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment(arm_uc_uri_t *uri,
00352                                                         arm_uc_buffer_t *buffer,
00353                                                         uint32_t offset)
00354 {
00355 
00356     arm_uc_error_t retval = { .code = SRCE_ERR_INVALID_PARAMETER };
00357 #if defined(ARM_UC_FEATURE_FW_SOURCE_COAP) && (ARM_UC_FEATURE_FW_SOURCE_COAP == 1)
00358     if (uri == NULL || buffer == NULL || FirmwareUpdateResource::getM2MInterface() == NULL) {
00359         return retval;
00360     }
00361 
00362     UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment: %s %s, buffer size: %" PRIu32 ", buffer max: %" PRIu32
00363                   " offset: %" PRIu32, (const char *)uri->ptr, uri->path, buffer->size, buffer->size_max, offset);
00364     UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment: total file size %" PRIu32 ", received file size %" PRIu32,
00365                   (uint32_t)arm_uc_total_file_size, (uint32_t)arm_uc_received_file_size);
00366 
00367     /*
00368      * NOTE: we are using M2MInterface API "get_data_request()" asynchronously, so first call to GetFirmwareFragment()
00369      * will not return anything in the buffer. Instead we will get COAP blocks into callback arm_uc_get_data_req_callback()
00370      * where we will copy those to our internal storage_buffer. When storage_buffer has enough data
00371      * (more or eq than buffer->size_max == Storage Page size) we will copy data from it to output buffer
00372      * and indicate to Hub state machine using event EVENT_FIRMWARE
00373      */
00374     if (offset == 0) {
00375         // First fragment
00376         storage_buffer.size = 0;
00377         arm_uc_received_file_size = 0;
00378         arm_uc_total_file_size = 0;
00379     } else if (arm_uc_received_file_size == 0) {
00380         // The received file size was reset to zero indicating that we have received the full payload
00381         // as indicated by the server but we are asked to carry on downloading from the given offset.
00382         // This indicates a mismatch between the actual payload size in the server and that given in the manifest.
00383         UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment: payload size indicated in manifest is bigger than that reported by server!");
00384         if (ARM_UCS_EventHandler) {
00385             ARM_UC_PostCallback(&callbackNodeManifest,
00386                                 ARM_UCS_EventHandler,
00387                                 EVENT_ERROR);
00388         }
00389         return retval;
00390     }
00391 
00392     output_buffer_ptr = buffer;
00393     free(copy_full_url);
00394     copy_full_url = (char *)malloc(arm_uc_calculate_full_uri_length(uri));
00395     if (copy_full_url == NULL) {
00396         //TODO to return SRCE_ERR_OUT_OF_MEMORY
00397         UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment: ERROR OUT OF MEMORY for uri copy!");
00398         return retval;
00399     }
00400     if (uri->scheme == URI_SCHEME_COAPS) {
00401         strcpy(copy_full_url, UC_COAPS_STRING);
00402     } else if (uri->scheme == URI_SCHEME_HTTP) {
00403         strcpy(copy_full_url, UC_HTTP_STRING);
00404     } else {
00405         UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment: Not Supported SCHEME! length of copy url: %u",
00406                       sizeof(copy_full_url));
00407         return retval;
00408     }
00409     strcat(copy_full_url, (const char *)uri->ptr);
00410     strcat(copy_full_url, uri->path);
00411 
00412     if ((arm_uc_received_file_size == arm_uc_total_file_size &&
00413             arm_uc_received_file_size != 0)) {
00414 
00415         // If last block - write to buffer and complete
00416         if (storage_buffer.ptr &&
00417                 (arm_uc_received_file_size == arm_uc_total_file_size)) {
00418             memcpy(buffer->ptr, storage_buffer.ptr, storage_buffer.size);
00419             buffer->size = storage_buffer.size;
00420             memmove(storage_buffer.ptr, storage_buffer.ptr + storage_buffer.size, (storage_buffer.size_max - storage_buffer.size));
00421             storage_buffer.size -= buffer->size;
00422         }
00423 
00424         // We were waiting for one more state machine cycle for previous write to complete
00425         // Now we can return with EVENT_FIRMWARE so that main state machine changes properly
00426         if (ARM_UCS_EventHandler) {
00427             ARM_UC_PostCallback(&callbackNodeManifest,
00428                                 ARM_UCS_EventHandler,
00429                                 EVENT_FIRMWARE);
00430         }
00431         retval.code = ERR_NONE;
00432         arm_uc_received_file_size = 0;
00433         arm_uc_total_file_size = 0;
00434     } else if (!arm_uc_get_data_request_transaction_ongoing) {
00435         // We need to get request for next block of data
00436         UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment: Issue new get request for uri: %s, offset: %" PRIu32,
00437                       copy_full_url, (uint32_t)arm_uc_received_file_size);
00438         if (FirmwareUpdateResource::getM2MInterface()) {
00439 
00440             FirmwareUpdateResource::getM2MInterface()->get_data_request(download_type,
00441                                                                         copy_full_url,
00442                                                                         arm_uc_received_file_size,
00443                                                                         true,
00444                                                                         arm_uc_get_data_req_callback,
00445                                                                         arm_uc_get_data_req_error_callback,
00446                                                                         FirmwareUpdateResource::getM2MInterface());
00447 
00448             arm_uc_get_data_request_transaction_ongoing = true;
00449 
00450             retval.code = ERR_NONE;
00451         }
00452     } else {
00453         // There is not enough data in Storage buffer yet
00454         // AND We have Async get_data_request already ongoing
00455         // -> Do nothing we should not get here?
00456         // This can happen if GetFirmwareFragment is called again before
00457         // the previous get completed with buffer and EVENT_FIRMWARE
00458         UC_SRCE_ERR_MSG("Internal error: BLOCK - data request already ongoing");
00459     }
00460     if (ARM_UC_IS_ERROR(retval)) {
00461         ARM_UCS_LWM2M_SOURCE_SetError(retval);
00462     }
00463     return retval;
00464 #else
00465     (void) uri;
00466     (void) buffer;
00467     (void) offset;
00468     return retval;
00469 #endif //ARM_UC_FEATURE_FW_SOURCE_COAP
00470 }
00471 
00472 #if defined(ARM_UC_FEATURE_FW_SOURCE_COAP) && (ARM_UC_FEATURE_FW_SOURCE_COAP == 1)
00473 void arm_uc_get_data_req_callback(const uint8_t *buffer, size_t buffer_size, size_t total_size, bool last_block,
00474                                   void *context)
00475 {
00476     (void)last_block;
00477 
00478     UC_SRCE_TRACE("get_data_req_callback: %" PRIu32 ", %" PRIu32, (uint32_t)buffer_size, (uint32_t)total_size);
00479     M2MInterface *interface = (M2MInterface *)context;
00480 
00481     if (arm_uc_received_file_size == 0) {
00482         arm_uc_total_file_size = total_size;
00483     }
00484 
00485     arm_uc_received_file_size += buffer_size;
00486     UC_SRCE_TRACE("get_data_req_callback:  received %" PRIu32 "/%" PRIu32, (uint32_t)arm_uc_received_file_size,
00487                   (uint32_t)arm_uc_total_file_size);
00488 
00489     if (arm_uc_received_file_size == arm_uc_total_file_size) {
00490         UC_SRCE_TRACE("get_data_req_callback:  transfer completed\n");
00491     }
00492 
00493     /*
00494      * FLOW:
00495      * 1. If there is space in Storage buffer for the incoming buffer -> copy buffer to storage buffer
00496      * 2. Else signal error event EVENT_ERROR_BUFFER_SIZE
00497      */
00498     // Check there is space available in the storage buffer
00499     if (storage_buffer.size_max - storage_buffer.size >= buffer_size) {
00500         memcpy(storage_buffer.ptr + storage_buffer.size, buffer, buffer_size);
00501         storage_buffer.size += buffer_size;
00502     } else {
00503         // Error - no space available, signal it to source manager
00504         UC_SRCE_TRACE("arm_uc_get_data_req_callback:  Storage Buffer OVERFLOW ERROR!! \n");
00505         if (ARM_UCS_EventHandler) {
00506             ARM_UC_PostCallback(&callbackNodeManifest,
00507                                 ARM_UCS_EventHandler,
00508                                 EVENT_ERROR_BUFFER_SIZE);
00509         }
00510         return;
00511     }
00512 
00513     /*
00514      * FLOW:
00515      * 1. If there is enough data in storage-buffer now to complete to output buffer, copy now and indicate with EVENT_FIRMWARE
00516      *    to continue to write -cycle
00517      * 2. Else if this is the last block of data, copy the remaining (<size_max) to output buffer and indicate with
00518      *    EVENT_FIRMWARE to continue to write-cycle
00519      * 3. Else Request new block of data using API get_data_request
00520      */
00521     if (storage_buffer.size >= output_buffer_ptr->size_max) {
00522         // 1. We have received into Storage buffer at least one page size of data
00523         // -> Let's return it to UC Hub so that it can be written
00524         UC_SRCE_TRACE("arm_uc_get_data_req_callback: return with Storage buffer size: %" PRIu32 ", buffer size: %" PRIu32,
00525                       storage_buffer.size, output_buffer_ptr->size_max);
00526         if (storage_buffer.ptr) {
00527             memcpy(output_buffer_ptr->ptr, storage_buffer.ptr, output_buffer_ptr->size_max);
00528             //storage_buffer.ptr += buffer->size_max;
00529             memmove(storage_buffer.ptr, storage_buffer.ptr + output_buffer_ptr->size_max,
00530                     (storage_buffer.size_max - output_buffer_ptr->size_max));
00531             storage_buffer.size -= output_buffer_ptr->size_max;
00532             output_buffer_ptr->size = output_buffer_ptr->size_max;
00533         }
00534 
00535         if (ARM_UCS_EventHandler) {
00536             ARM_UC_PostCallback(&callbackNodeManifest,
00537                                 ARM_UCS_EventHandler,
00538                                 EVENT_FIRMWARE);
00539         }
00540         arm_uc_get_data_request_transaction_ongoing = false;
00541     } else if (arm_uc_received_file_size == arm_uc_total_file_size &&
00542                arm_uc_received_file_size != 0) {
00543 
00544         // 2. this is the last block of data - copy to output buffer and complete with EVENT_FIRMWARE
00545         if (storage_buffer.ptr &&
00546                 (arm_uc_received_file_size == arm_uc_total_file_size)) {
00547             memcpy(output_buffer_ptr->ptr, storage_buffer.ptr, storage_buffer.size);
00548             output_buffer_ptr->size = storage_buffer.size;
00549 
00550             memmove(storage_buffer.ptr, storage_buffer.ptr + storage_buffer.size, (storage_buffer.size_max - storage_buffer.size));
00551             storage_buffer.size = 0;
00552         }
00553 
00554         // We were waiting for one more state machine cycle for previous write to complete
00555         // Now we can return with EVENT_FIRMWARE so that main state machine changes properly
00556         if (ARM_UCS_EventHandler) {
00557             ARM_UC_PostCallback(&callbackNodeManifest,
00558                                 ARM_UCS_EventHandler,
00559                                 EVENT_FIRMWARE);
00560         }
00561         arm_uc_get_data_request_transaction_ongoing = false;
00562         free(copy_full_url);
00563         copy_full_url = NULL;
00564         arm_uc_received_file_size = 0;
00565         arm_uc_total_file_size = 0;
00566     } else  {
00567         // 3. We want to issue new get data
00568         UC_SRCE_TRACE("arm_uc_get_data_req_callback: Issue new get request for uri: %s, offset: %" PRIu32, copy_full_url,
00569                       (uint32_t)arm_uc_received_file_size);
00570         interface->get_data_request(download_type,
00571                                         copy_full_url,
00572                                         arm_uc_received_file_size,
00573                                         true,
00574                                         arm_uc_get_data_req_callback,
00575                                         arm_uc_get_data_req_error_callback,
00576                                         interface);
00577         arm_uc_get_data_request_transaction_ongoing = true;
00578     }
00579 #ifdef ARM_UC_COAP_DATA_PRINTOUT
00580     if (buffer) {
00581         uint32_t i = 0;
00582         int row_len = 40;
00583         uint32_t max_length = 2048;
00584 
00585         while (i < buffer_size && i < max_length) {
00586             if (i + row_len > buffer_size) {
00587                 row_len = buffer_size - i;
00588             }
00589             UC_SRCE_TRACE("Payload:\t\t%s", tr_array(buffer + i, row_len)); // in HEX
00590 
00591             i += row_len;
00592         }
00593 
00594     }
00595 #endif
00596 }
00597 
00598 void arm_uc_get_data_req_error_callback(get_data_req_error_t error_code, void *context)
00599 {
00600     UC_SRCE_TRACE("get_data_req_error_callback:  ERROR: %u\n", error_code);
00601     arm_uc_received_file_size = 0;
00602     arm_uc_total_file_size = 0;
00603     arm_uc_get_data_request_transaction_ongoing = false;
00604     free(copy_full_url);
00605     copy_full_url = NULL;
00606     download_type = FIRMWARE_DOWNLOAD;
00607     if (ARM_UCS_EventHandler) {
00608         ARM_UC_PostCallback(&callbackNodeManifest,
00609                             ARM_UCS_EventHandler,
00610                             EVENT_ERROR);
00611     }
00612 }
00613 #endif //ARM_UC_FEATURE_FW_SOURCE_COAP
00614 
00615 /*****************************************************************************/
00616 /* Capabilities not supported by this source                                 */
00617 /*****************************************************************************/
00618 
00619 /**
00620  * @brief Cost estimation for retrieving manifest from URL.
00621  * @details The estimation can vary over time and should not be cached too long.
00622  *          0x00000000 - The manifest is already downloaded.
00623  *          0xFFFFFFFF - Cannot retrieve manifest from this Source.
00624  *
00625  * @param uri URI struct with manifest location.
00626  * @param cost Pointer to variable for the return value.
00627  * @return Error code.
00628  */
00629 arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetManifestURLCost(arm_uc_uri_t *uri,
00630                                                        uint32_t *cost)
00631 {
00632     (void) uri;
00633     (void) cost;
00634 
00635     ARM_UC_INIT_ERROR(result, SRCE_ERR_INVALID_PARAMETER);
00636 
00637     /* not supported - return default cost regardless of actual uri location */
00638     if (cost) {
00639         *cost = 0xFFFFFFFF;
00640         ARM_UC_SET_ERROR(result, ERR_NONE);
00641     }
00642 
00643     if (ARM_UC_IS_ERROR(result)) {
00644         ARM_UCS_LWM2M_SOURCE_SetError(result);
00645     }
00646     return result;
00647 }
00648 
00649 /**
00650  * @brief Cost estimation for retrieving key table from URL.
00651  * @details The estimation can vary over time and should not be cached too long.
00652  *          0x00000000 - The firmware is already downloaded.
00653  *          0xFFFFFFFF - Cannot retrieve firmware from this Source.
00654  *
00655  * @param uri URI struct with keytable location.
00656  * @param cost Pointer to variable for the return value.
00657  * @return Error code.
00658  */
00659 arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetKeytableURLCost(arm_uc_uri_t *uri,
00660                                                        uint32_t *cost)
00661 {
00662     (void) uri;
00663     (void) cost;
00664 
00665     ARM_UC_INIT_ERROR(result, SRCE_ERR_INVALID_PARAMETER);
00666 
00667     /* not supported - return default cost regardless of actual uri location */
00668     if ((uri != 0) && (cost != 0)) {
00669         *cost = 0xFFFFFFFF;
00670         ARM_UC_SET_ERROR(result, ERR_NONE);
00671     }
00672 
00673     if (ARM_UC_IS_ERROR(result)) {
00674         ARM_UCS_LWM2M_SOURCE_SetError(result);
00675     }
00676     return result;
00677 }
00678 
00679 /**
00680  * @brief Retrieve manifest from URL.
00681  * @details Manifest is stored in supplied buffer.
00682  *          Event is generated once manifest is in buffer.
00683  *
00684  * @param uri URI struct with manifest location.
00685  * @param buffer Struct containing byte array, maximum size, and actual size.
00686  *
00687  * @return Error code.
00688  */
00689 arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetManifestURL(arm_uc_uri_t *uri,
00690                                                    arm_uc_buffer_t *buffer,
00691                                                    uint32_t offset)
00692 {
00693     (void) uri;
00694     (void) buffer;
00695     (void) offset;
00696 
00697     ARM_UC_INIT_ERROR(retval, SRCE_ERR_INVALID_PARAMETER);
00698 
00699     if (ARM_UC_IS_ERROR(retval)) {
00700         ARM_UCS_LWM2M_SOURCE_SetError(retval);
00701     }
00702     return retval;
00703 }
00704 
00705 /**
00706  * @brief Retrieve a key table from a URL.
00707  * @details Key table is stored in supplied buffer.
00708  *          Event is generated once fragment is in buffer.
00709  *
00710  * @param uri URI struct with keytable location.
00711  * @param buffer Struct containing byte array, maximum size, and actual size.
00712  * @return Error code.
00713  */
00714 arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetKeytableURL(arm_uc_uri_t *uri,
00715                                                    arm_uc_buffer_t *buffer)
00716 {
00717     (void) uri;
00718     (void) buffer;
00719 
00720     ARM_UC_INIT_ERROR(retval, SRCE_ERR_INVALID_PARAMETER);
00721 
00722     if (ARM_UC_IS_ERROR(retval)) {
00723         ARM_UCS_LWM2M_SOURCE_SetError(retval);
00724     }
00725     return retval;
00726 }