Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm_uc_source_http.c Source File

arm_uc_source_http.c

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 
00019 #include "update-client-common/arm_uc_config.h"
00020 
00021 #if defined(ARM_UC_FEATURE_FW_SOURCE_HTTP) && (ARM_UC_FEATURE_FW_SOURCE_HTTP == 1)
00022 
00023 // HTTP streaming of downloads.
00024 // ----------------------------
00025 // Implements an update source for update client use.
00026 // Keeps the fragment-get interface for all types, but replaces it under the
00027 //   hood with pre-fetch and caching of the requested data.
00028 // The pre-fetch entails requesting the server for the remainder of the resource,
00029 //   rather than just the fragment mentioned, and allowing the HTTP/TCP stack
00030 //   to do the work of buffering it. The caching entails keeping track of the
00031 //   current state of the buffered fetch, and returning the fragment as read
00032 //   from the buffered stream if appropriate, or re-requesting the data if there
00033 //   is no match between the request and the cached state, or the socket has
00034 //   been broken and the buffer is unavailable.
00035 // Note that streaming is not necessarily always the correct approach, there
00036 //   might on occasion be cause to force the fragment approach, related to
00037 //   available transports, or link properties.
00038 
00039 #include "update-client-source-http/arm_uc_source_http.h"
00040 
00041 #include "update-client-source-http-socket/arm_uc_http_socket.h"
00042 
00043 #include <time.h>
00044 #include <stdio.h>
00045 #include <stdbool.h>
00046 #include "update-client-source-http/arm_uc_source_http_extra.h"
00047 
00048 // TRACE.
00049 // ------
00050 
00051 // to disable extra trace, uncomment UC_SRCE_TRACE_ENTRY/VERBOSE/EXIT(...)
00052 // or to enable extra trace, uncomment UC_SRCE_TRACE_ENTRY/VERBOSE/EXIT UC_SRCE_TRACE
00053 #define UC_SRCE_TRACE_ENTRY(...)
00054 #define UC_SRCE_TRACE_VERBOSE(...)
00055 #define UC_SRCE_TRACE_EXIT(...)
00056 //#define UC_SRCE_TRACE_ENTRY UC_SRCE_TRACE
00057 //#define UC_SRCE_TRACE_VERBOSE UC_SRCE_TRACE
00058 //#define UC_SRCE_TRACE_EXIT UC_SRCE_TRACE
00059 
00060 // DATA & CONFIG.
00061 // --------------
00062 
00063 // current version of this driver.
00064 #define DRIVER_VER 0x00010000
00065 
00066 // default cost is lowered compared to fragment sources.
00067 #define ARM_UCS_HTTP_DEFAULT_COST (700)
00068 #define ARM_UCS_HTTP_HASH_LENGTH  (40)
00069 
00070 typedef struct _ARM_UCS_Http_Configuration {
00071     arm_uc_uri_t manifest;
00072     uint32_t interval;
00073     uint32_t currentCost;
00074     time_t lastPoll;
00075     int8_t hash[ARM_UCS_HTTP_HASH_LENGTH];
00076     void (*eventHandler)(uintptr_t event);
00077 } ARM_UCS_Http_Configuration_t;
00078 
00079 static ARM_UCS_Http_Configuration_t default_config = {
00080     .manifest = {
00081         .size_max = 0,
00082         .size = 0,
00083         .ptr = NULL,
00084         .scheme = URI_SCHEME_NONE,
00085         .port = 0,
00086         .host = NULL,
00087         .path = NULL
00088     },
00089     .interval = 0,
00090     .currentCost = 0xFFFFFFFF,
00091     .lastPoll = 0,
00092     .hash = { 0 },
00093     .eventHandler = 0
00094 };
00095 
00096 typedef enum {
00097     STATE_UCS_HTTP_IDLE,
00098     STATE_UCS_HTTP_MANIFEST,
00099     STATE_UCS_HTTP_FIRMWARE,
00100     STATE_UCS_HTTP_FIRMWARE_RELOAD,
00101     STATE_UCS_HTTP_KEYTABLE,
00102     STATE_UCS_HTTP_HASH
00103 } arm_ucs_http_state_t;
00104 
00105 #define MAX_RETRY 3
00106 
00107 typedef struct {
00108     arm_ucs_http_state_t stateHttp;
00109     arm_uc_uri_t *uri;
00110     arm_uc_buffer_t *buffer;
00111     uint32_t offset;
00112     uint8_t retryCount;
00113 } arm_ucs_state_t;
00114 
00115 static arm_ucs_state_t arm_ucs_state;
00116 
00117 static arm_uc_http_socket_context_t arm_uc_http_socket_context = { 0 };
00118 
00119 // HELPERS.
00120 // --------
00121 
00122 /* Helper function for resetting internal state */
00123 static inline void uc_state_reset()
00124 {
00125     arm_ucs_state.stateHttp  = STATE_UCS_HTTP_IDLE;
00126     arm_ucs_state.uri        = NULL;
00127     arm_ucs_state.buffer     = NULL;
00128     arm_ucs_state.offset     = 0;
00129     arm_ucs_state.retryCount = 0;
00130 }
00131 
00132 /* Helper function for checking if the stored hash is all zeros */
00133 static inline bool hash_is_zero()
00134 {
00135     bool result = true;
00136     for (uint32_t index = 0; index < ARM_UCS_HTTP_HASH_LENGTH; index++) {
00137         if (default_config.hash[index] != 0) {
00138             result = false;
00139             break;
00140         }
00141     }
00142     return result;
00143 }
00144 
00145 static arm_uc_error_t arm_ucs_http_error = {ERR_NONE};
00146 arm_uc_error_t ARM_UCS_Http_GetError(void) { return arm_ucs_http_error; }
00147 arm_uc_error_t ARM_UCS_Http_SetError(arm_uc_error_t an_error) { return (arm_ucs_http_error = an_error); }
00148 
00149 
00150 // FORWARD DECLARATIONS.
00151 // ---------------------
00152 
00153 arm_uc_error_t ARM_UCS_Http_Get(arm_uc_uri_t *uri,
00154                                 arm_uc_buffer_t *buffer,
00155                                 uint32_t offset,
00156                                 arm_ucs_http_state_t newHttpState);
00157 
00158 /******************************************************************************/
00159 /* ARM Update Client Source Extra                                             */
00160 /******************************************************************************/
00161 
00162 /**
00163  * @brief Set URI location for the default manifest.
00164  * @details The default manifest is polled regularly and generates a
00165  *          notification upon change. The URI struct and the content pointer to
00166  *          must be valid throughout the lifetime of the application.
00167  *
00168  * @param uri URI struct with manifest location.
00169  * @return Error code.
00170  */
00171 arm_uc_error_t ARM_UCS_Http_SetDefaultManifestURL(arm_uc_uri_t *uri)
00172 {
00173     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00174 
00175     /* check scheme is http */
00176     if ((uri == NULL) || (uri->scheme != URI_SCHEME_HTTP)) {
00177         ARM_UCS_Http_SetError((arm_uc_error_t) {SRCE_ERR_INVALID_PARAMETER});
00178         return ARM_UC_ERROR(SRCE_ERR_INVALID_PARAMETER);
00179     } else {
00180         /* copy pointers to local struct */
00181         default_config.manifest = *uri;
00182         return ARM_UC_ERROR(ERR_NONE);
00183     }
00184 }
00185 
00186 /**
00187  * @brief Set polling interval for notification generation.
00188  * @details The default manifest location is polled with this interval.
00189  *
00190  * @param seconds Seconds between each poll.
00191  * @return Error code.
00192  */
00193 arm_uc_error_t ARM_UCS_Http_SetPollingInterval(uint32_t seconds)
00194 {
00195     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00196 
00197     default_config.interval = seconds;
00198 
00199     return ARM_UC_ERROR(ERR_NONE);
00200 }
00201 
00202 /**
00203  * @brief Main function for the Source.
00204  * @details This function will query the default manifest location and generate
00205  *          a notification if it has changed since the last time it was checked.
00206  *          The number of queries generated is bound by the polling interval.
00207  *
00208  *          This function should be used on systems with timed callbacks.
00209  *
00210  * @return Seconds until the next polling interval.
00211  */
00212 uint32_t ARM_UCS_Http_CallMultipleTimes(arm_uc_buffer_t *hash_buffer)
00213 {
00214     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00215 
00216     uint32_t result = default_config.interval;
00217     time_t unixtime = time(NULL);
00218     uint32_t elapsed = unixtime - default_config.lastPoll;
00219 
00220     if ((default_config.eventHandler == NULL) ||
00221             (arm_ucs_state.stateHttp != STATE_UCS_HTTP_IDLE) ||
00222             (hash_buffer == NULL)) {
00223         return default_config.interval;
00224     }
00225 
00226     if (elapsed >= default_config.interval) {
00227         UC_SRCE_TRACE_VERBOSE("%s interval elapsed", __func__);
00228 
00229         // poll default URI
00230         default_config.lastPoll = unixtime;
00231 
00232         // get resource hash
00233         arm_ucs_state.stateHttp = STATE_UCS_HTTP_HASH;
00234         arm_ucs_state.buffer = hash_buffer;
00235 
00236         arm_uc_error_t retval = ARM_UCS_HttpSocket_GetHash(&default_config.manifest,
00237                                                            arm_ucs_state.buffer);
00238         if (ARM_UC_IS_ERROR(retval)) {
00239             uc_state_reset();
00240             return default_config.interval;
00241         }
00242     } else {
00243         result = (elapsed > 0) ? default_config.interval - elapsed : default_config.interval;
00244     }
00245 
00246     return result;
00247 }
00248 
00249 // EXTRA INTERFACE.
00250 // ----------------
00251 
00252 ARM_UCS_HTTPSourceExtra_t ARM_UCS_HTTPSourceExtra = {
00253     .SetDefaultManifestURL = ARM_UCS_Http_SetDefaultManifestURL,
00254     .SetPollingInterval    = ARM_UCS_Http_SetPollingInterval,
00255     .CallMultipleTimes     = ARM_UCS_Http_CallMultipleTimes
00256 };
00257 
00258 /******************************************************************************/
00259 /* ARM Update Client Source                                                   */
00260 /******************************************************************************/
00261 
00262 void ARM_UCS_Http_ProcessHash()
00263 {
00264     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00265 
00266 #if ARM_UC_SOURCE_MANAGER_TRACE_ENABLE
00267     printf("hash: ");
00268     for (uint32_t index = 0; index < arm_ucs_state.buffer->size; index++) {
00269         printf("%c", arm_ucs_state.buffer->ptr[index]);
00270     }
00271     printf("\r\n");
00272 #endif
00273 
00274     bool hashIsNew = false;
00275     bool firstBoot = hash_is_zero();
00276 
00277     /* compare hash with previous check */
00278     for (uint32_t index = 0; index < arm_ucs_state.buffer->size; index++) {
00279         /* compare hash */
00280         if (default_config.hash[index] != arm_ucs_state.buffer->ptr[index]) {
00281             /* store new hash */
00282             default_config.hash[index] = arm_ucs_state.buffer->ptr[index];
00283             hashIsNew = true;
00284         }
00285     }
00286 
00287     /* Request complete, reset state */
00288     uc_state_reset();
00289     arm_uc_http_socket_end_resume();
00290 
00291     /* Signal that a new manifest is available if the hash is non-zero
00292        and different from the last check.
00293     */
00294     if (hashIsNew && !firstBoot) {
00295         if (default_config.eventHandler) {
00296             default_config.eventHandler(EVENT_NOTIFICATION);
00297         }
00298     }
00299 }
00300 
00301 static void ARM_UCS_Http_HTTPEvent(uintptr_t event)
00302 {
00303     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00304 
00305     switch (event) {
00306         /* Hash received, process it */
00307         case UCS_HTTP_EVENT_HASH:
00308             UC_SRCE_TRACE("UCS_HTTP_EVENT_HASH");
00309 
00310             ARM_UCS_Http_ProcessHash();
00311             break;
00312 
00313         /* Download complete */
00314         case UCS_HTTP_EVENT_DOWNLOAD: {
00315             UC_SRCE_TRACE("UCS_HTTP_EVENT_DOWNLOAD");
00316 
00317             /* cache state before resetting it */
00318             arm_ucs_http_state_t previous_state = arm_ucs_state.stateHttp;
00319 
00320             /* reset internal state */
00321             uc_state_reset();
00322 
00323             /* signal successful download based on request */
00324             if (default_config.eventHandler) {
00325                 if (previous_state == STATE_UCS_HTTP_MANIFEST) {
00326                     default_config.eventHandler(EVENT_MANIFEST);
00327                 } else if (previous_state == STATE_UCS_HTTP_FIRMWARE) {
00328                     default_config.eventHandler(EVENT_FIRMWARE);
00329                 } else if (previous_state == STATE_UCS_HTTP_KEYTABLE) {
00330                     default_config.eventHandler(EVENT_KEYTABLE);
00331                 } else {
00332                     default_config.eventHandler(EVENT_ERROR);
00333                 }
00334             }
00335         }
00336         break;
00337 
00338         /* Socket error */
00339         case UCS_HTTP_EVENT_ERROR: {
00340             UC_SRCE_TRACE("UCS_HTTP_EVENT_ERROR");
00341 
00342             /* Treat polling as retry when reading hash */
00343             if (arm_ucs_state.stateHttp == STATE_UCS_HTTP_HASH) {
00344                 /* If the stored hash is zero, this error is most likely
00345                    generated due to the default manifest not being uploaded
00346                    yet. Mark the stored hash as non-zero, so the first time
00347                    the device successfully retrieves a hash we download the
00348                    manifest.
00349                 */
00350                 if (hash_is_zero()) {
00351                     default_config.hash[0] = 0xFF;
00352                 }
00353                 /* reset state but don't take any further action */
00354                 uc_state_reset();
00355             } else {
00356                 /* reset internal state */
00357                 uc_state_reset();
00358 
00359                 /* generate error event */
00360                 if (default_config.eventHandler) {
00361                     default_config.eventHandler(EVENT_ERROR_SOURCE);
00362                 }
00363             }
00364         }
00365         break;
00366 
00367         /* supplied buffer not large enough */
00368         case UCS_HTTP_EVENT_ERROR_BUFFER_SIZE: {
00369             /* reset internal state */
00370             uc_state_reset();
00371 
00372             /* generate error event */
00373             if (default_config.eventHandler) {
00374                 default_config.eventHandler(EVENT_ERROR_BUFFER_SIZE);
00375             }
00376         }
00377         break;
00378 
00379         default:
00380             UC_SRCE_ERR_MSG("%s Unknown event", __func__);
00381             break;
00382     }
00383 }
00384 
00385 /**
00386  * @brief Get driver version.
00387  * @return Driver version.
00388  */
00389 uint32_t ARM_UCS_Http_GetVersion(void)
00390 {
00391     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00392     return DRIVER_VER;
00393 }
00394 
00395 /**
00396  * @brief Get Source capabilities.
00397  * @return Struct containing capabilites. See definition above.
00398  */
00399 ARM_SOURCE_CAPABILITIES ARM_UCS_Http_GetCapabilities(void)
00400 {
00401     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00402 
00403     ARM_SOURCE_CAPABILITIES result = {
00404         .notify = 0,
00405         .manifest_default = 0,
00406         .manifest_url = 0,
00407         .firmware = 0,
00408         .keytable = 0
00409     };
00410 
00411     /* the event handler must be set before module can be used */
00412     if (default_config.eventHandler != 0) {
00413         result.manifest_url = 1;
00414         result.firmware = 1;
00415         result.keytable = 1;
00416 
00417         /* notification requires that the default manifest is set */
00418         if ((default_config.manifest.port != 0) || (default_config.interval != 0)) {
00419             result.notify = 1;
00420             result.manifest_default = 1;
00421         }
00422     }
00423 
00424     return result;
00425 }
00426 
00427 /**
00428  * @brief Initialize Source.
00429  * @details Function pointer to event handler is passed as argument.
00430  *
00431  * @param cb_event Function pointer to event handler. See events above.
00432  * @return Error code.
00433  */
00434 arm_uc_error_t ARM_UCS_Http_Initialize(ARM_SOURCE_SignalEvent_t cb_event)
00435 {
00436     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00437     ARM_UC_INIT_ERROR(status, SRCE_ERR_INVALID_PARAMETER);
00438 
00439     if (cb_event != NULL) {
00440         default_config.currentCost = ARM_UCS_HTTP_DEFAULT_COST;
00441         default_config.eventHandler = cb_event;
00442 
00443         /* register http callback handler */
00444         ARM_UCS_HttpSocket_Initialize(
00445             &arm_uc_http_socket_context,
00446             ARM_UCS_Http_HTTPEvent);
00447 
00448         ARM_UC_SET_ERROR(status, ERR_NONE);
00449     }
00450     uc_state_reset();
00451     if (ARM_UC_IS_ERROR(status)) {
00452         ARM_UCS_Http_SetError(status);
00453     }
00454     return status;
00455 }
00456 
00457 /**
00458  * @brief Uninitialized Source.
00459  * @return Error code.
00460  */
00461 arm_uc_error_t ARM_UCS_Http_Uninitialize(void)
00462 {
00463     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00464     ARM_UCS_Http_SetError((arm_uc_error_t) {SRCE_ERR_INVALID_PARAMETER});
00465     return ARM_UC_ERROR(SRCE_ERR_INVALID_PARAMETER);
00466 }
00467 
00468 // COSTS.
00469 // ------
00470 
00471 /**
00472  * @brief Cost estimation for retrieving manifest from the default location.
00473  * @details The estimation can vary over time and should not be cached too long.
00474  *          0x00000000 - The manifest is already downloaded.
00475  *          0xFFFFFFFF - Cannot retrieve manifest from this Source.
00476  *
00477  * @param cost Pointer to variable for the return value.
00478  * @return Error code.
00479  */
00480 arm_uc_error_t ARM_UCS_Http_GetManifestDefaultCost(
00481     uint32_t *a_cost_p)
00482 {
00483     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00484     ARM_UC_INIT_ERROR(status, SRCE_ERR_INVALID_PARAMETER);
00485 
00486     if (a_cost_p != 0) {
00487         *a_cost_p = default_config.currentCost;
00488         ARM_UC_SET_ERROR(status, ERR_NONE);
00489     }
00490     if (ARM_UC_IS_ERROR(status)) {
00491         ARM_UCS_Http_SetError(status);
00492     }
00493     return status;
00494 }
00495 
00496 /**
00497  * @brief Cost estimation for retrieving unspecified resource from URL.
00498  * @details The estimation can vary over time and should not be cached too long.
00499  *          0x00000000 - The manifest is already downloaded.
00500  *          0xFFFFFFFF - Cannot retrieve manifest from this Source.
00501  * @param uri URI struct with manifest location.
00502  * @param cost Pointer to variable for the return value.
00503  * @return Error code.
00504  */
00505 arm_uc_error_t ARM_UCS_Http_GetCost(
00506     arm_uc_uri_t *a_uri_p,
00507     uint32_t *a_cost_p)
00508 {
00509     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00510     ARM_UC_INIT_ERROR(status, SRCE_ERR_INVALID_PARAMETER);
00511 
00512     /* return default cost regardless of actual uri location */
00513     if ((a_uri_p != NULL) && (a_cost_p != NULL)) {
00514         *a_cost_p = default_config.currentCost;
00515         ARM_UC_SET_ERROR(status, ERR_NONE);
00516     }
00517     /* return no-path cost if URL is invalid */
00518     else if (a_cost_p != NULL) {
00519         *a_cost_p = 0xFFFFFFFF;
00520     }
00521     if (ARM_UC_IS_ERROR(status)) {
00522         ARM_UCS_Http_SetError(status);
00523     }
00524     return status;
00525 }
00526 
00527 /* @brief Cost estimation for retrieving manifest from URL.
00528  * @details The estimation can vary over time and should not be cached too long.
00529  *          0x00000000 - The manifest is already downloaded.
00530  *          0xFFFFFFFF - Cannot retrieve manifest from this Source.
00531  *
00532  * @param uri URI struct with manifest location.
00533  * @param cost Pointer to variable for the return value.
00534  * @return Error code.
00535  */
00536 arm_uc_error_t ARM_UCS_Http_GetManifestURLCost(arm_uc_uri_t *uri, uint32_t *cost)
00537 {
00538     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00539     return ARM_UCS_Http_GetCost(uri, cost);
00540 }
00541 
00542 /**
00543  * @brief Cost estimation for retrieving firmware from URL.
00544  * @details The estimation can vary over time and should not be cached too long.
00545  *          0x00000000 - The firmware is already downloaded.
00546  *          0xFFFFFFFF - Cannot retrieve firmware from this Source.
00547  *
00548  * @param uri URI struct with firmware location.
00549  * @param cost Pointer to variable for the return value.
00550  * @return Error code.
00551  */
00552 arm_uc_error_t ARM_UCS_Http_GetFirmwareURLCost(arm_uc_uri_t *uri, uint32_t *cost)
00553 {
00554     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00555     return ARM_UCS_Http_GetCost(uri, cost);
00556 }
00557 
00558 /**
00559  * @brief Cost estimation for retrieving key table from URL.
00560  * @details The estimation can vary over time and should not be cached too long.
00561  *          0x00000000 - The firmware is already downloaded.
00562  *          0xFFFFFFFF - Cannot retrieve firmware from this Source.
00563  *
00564  * @param uri URI struct with keytable location.
00565  * @param cost Pointer to variable for the return value.
00566  * @return Error code.
00567  */
00568 arm_uc_error_t ARM_UCS_Http_GetKeytableURLCost(arm_uc_uri_t *uri, uint32_t *cost)
00569 {
00570     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00571     return ARM_UCS_Http_GetCost(uri, cost);
00572 }
00573 
00574 // GETTING RESOURCES.
00575 // ------------------
00576 
00577 /**
00578  * @brief (Internal) Retrieve resource according to the given parameters
00579  *        in arm_ucs_state and store the returned data in the buffer in arm_ucs_state.
00580  * @param uri URI struct with resource location.
00581  * @param buffer Struct containing byte array, maximum size, and actual size.
00582  * @param offset Offset to retrieve fragment from.
00583  * @param newHttpState The intended new http state to be assigned to arm_ucs_state.stateHttp
00584  */
00585 
00586 arm_uc_error_t ARM_UCS_Http_Get(arm_uc_uri_t *uri,
00587                                 arm_uc_buffer_t *buffer,
00588                                 uint32_t offset,
00589                                 arm_ucs_http_state_t newHttpState)
00590 {
00591     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00592     ARM_UC_INIT_ERROR(status, SRCE_ERR_INVALID_PARAMETER);
00593 
00594     // Call the socket layer to get the requested data
00595 
00596     // check current state
00597     if (default_config.eventHandler == 0) {
00598         UC_SRCE_ERR_MSG("Uninitialized");
00599         return ARM_UC_ERROR(SRCE_ERR_UNINITIALIZED);
00600     }
00601     if (arm_ucs_state.stateHttp != STATE_UCS_HTTP_IDLE) {
00602         UC_SRCE_ERR_MSG("Busy");
00603         return ARM_UC_ERROR(SRCE_ERR_BUSY);
00604     }
00605 
00606     // assign new state
00607     arm_ucs_state.stateHttp      = newHttpState;
00608     arm_ucs_state.uri            = uri;
00609     arm_ucs_state.buffer         = buffer;
00610     arm_ucs_state.offset         = offset;
00611 
00612     // never returns an error because all Get does is installs the thread.
00613     while (ARM_UC_IS_ERROR(status) && (arm_ucs_state.retryCount++ < MAX_RETRY)) {
00614         // restore buffer size on retry
00615         arm_ucs_state.buffer->size = arm_ucs_state.buffer->size_max;
00616 
00617         switch (arm_ucs_state.stateHttp) {
00618             case STATE_UCS_HTTP_MANIFEST:
00619             case STATE_UCS_HTTP_FIRMWARE:
00620                 if (arm_ucs_state.buffer != 0 && arm_ucs_state.uri != 0) {
00621                     status = ARM_UCS_HttpSocket_GetFragment(arm_ucs_state.uri,
00622                                                             arm_ucs_state.buffer,
00623                                                             arm_ucs_state.offset);
00624                 }
00625                 break;
00626             case STATE_UCS_HTTP_KEYTABLE:
00627                 if (arm_ucs_state.buffer != 0 && arm_ucs_state.uri != 0) {
00628                     status = ARM_UCS_HttpSocket_GetFile(arm_ucs_state.uri,
00629                                                         arm_ucs_state.buffer);
00630                 }
00631                 break;
00632             default:
00633                 UC_SRCE_ERR_MSG("Invalid request parameter");
00634                 ARM_UC_SET_ERROR(status, SRCE_ERR_INVALID_PARAMETER);
00635                 break;
00636         }
00637     }
00638 
00639     if (ARM_UC_IS_ERROR(status)) {
00640         uc_state_reset();
00641     }
00642     if (ARM_UC_IS_ERROR(status)) {
00643         ARM_UCS_Http_SetError(status);
00644     }
00645     return status;
00646 }
00647 
00648 /**
00649  * @brief Retrieve manifest from the default location.
00650  * @details Manifest is stored in supplied buffer.
00651  *          Event is generated once manifest is in buffer.
00652  *
00653  * @param buffer Struct containing byte array, maximum size, and actual size.
00654  * @return Error code.
00655  */
00656 arm_uc_error_t ARM_UCS_Http_GetManifestDefault(arm_uc_buffer_t *buffer, uint32_t offset)
00657 {
00658     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00659     return ARM_UCS_Http_Get(&default_config.manifest, buffer, offset, STATE_UCS_HTTP_MANIFEST);
00660 }
00661 
00662 /**
00663  * @brief Retrieve manifest from URL.
00664  * @details Manifest is stored in supplied buffer.
00665  *          Event is generated once manifest is in buffer.
00666  *
00667  * @param uri URI struct with manifest location.
00668  * @param buffer Struct containing byte array, maximum size, and actual size.
00669  *
00670  * @return Error code.
00671  */
00672 arm_uc_error_t ARM_UCS_Http_GetManifestURL(arm_uc_uri_t *uri, arm_uc_buffer_t *buffer, uint32_t offset)
00673 {
00674     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00675     return ARM_UCS_Http_Get(uri, buffer, offset, STATE_UCS_HTTP_MANIFEST);
00676 }
00677 
00678 /**
00679  * @brief Retrieve firmware fragment.
00680  * @details Firmware fragment is stored in supplied buffer.
00681  *          Event is generated once fragment is in buffer.
00682  *
00683  * @param uri URI struct with firmware location.
00684  * @param buffer Struct containing byte array, maximum size, and actual size.
00685  * @param offset Firmware offset to retrieve fragment from.
00686  * @return Error code.
00687  */
00688 arm_uc_error_t ARM_UCS_Http_GetFirmwareFragment(arm_uc_uri_t *uri, arm_uc_buffer_t *buffer, uint32_t offset)
00689 {
00690     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00691     return ARM_UCS_Http_Get(uri, buffer, offset, STATE_UCS_HTTP_FIRMWARE);
00692 }
00693 
00694 /**
00695  * @brief Retrieve a key table from a URL.
00696  * @details Key table is stored in supplied buffer.
00697  *          Event is generated once fragment is in buffer.
00698  *
00699  * @param uri URI struct with keytable location.
00700  * @param buffer Struct containing byte array, maximum size, and actual size.
00701  * @return Error code.
00702  */
00703 arm_uc_error_t ARM_UCS_Http_GetKeytableURL(arm_uc_uri_t *uri, arm_uc_buffer_t *buffer)
00704 {
00705     UC_SRCE_TRACE_ENTRY(">> %s", __func__);
00706     return ARM_UCS_Http_Get(uri, buffer, UINT32_MAX, STATE_UCS_HTTP_KEYTABLE);
00707 }
00708 
00709 // SOURCE INTERFACE.
00710 // -----------------
00711 
00712 ARM_UPDATE_SOURCE ARM_UCS_HTTPSource = {
00713     .GetVersion             = ARM_UCS_Http_GetVersion,
00714     .GetCapabilities        = ARM_UCS_Http_GetCapabilities,
00715     .Initialize             = ARM_UCS_Http_Initialize,
00716     .Uninitialize           = ARM_UCS_Http_Uninitialize,
00717     .GetManifestDefaultCost = ARM_UCS_Http_GetManifestDefaultCost,
00718     .GetManifestURLCost     = ARM_UCS_Http_GetManifestURLCost,
00719     .GetFirmwareURLCost     = ARM_UCS_Http_GetFirmwareURLCost,
00720     .GetKeytableURLCost     = ARM_UCS_Http_GetKeytableURLCost,
00721     .GetManifestDefault     = ARM_UCS_Http_GetManifestDefault,
00722     .GetManifestURL         = ARM_UCS_Http_GetManifestURL,
00723     .GetFirmwareFragment    = ARM_UCS_Http_GetFirmwareFragment,
00724     .GetKeytableURL         = ARM_UCS_Http_GetKeytableURL
00725 };
00726 
00727 #endif // ARM_UC_FEATURE_FW_SOURCE_HTTP
00728