Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: FXAS21002 FXOS8700Q
arm_uc_source_manager.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-source-manager/arm_uc_source_manager.h" 00020 00021 #include "update-client-common/arm_uc_common.h" 00022 #include "update-client-common/arm_uc_config.h" 00023 #include "update-client-source/arm_uc_source.h" 00024 00025 #if defined(ARM_UC_PROFILE_MBED_CLOUD_CLIENT) && (ARM_UC_PROFILE_MBED_CLOUD_CLIENT == 1) 00026 #include "pal.h" 00027 #endif 00028 00029 #include <stdint.h> 00030 #include <stdlib.h> 00031 00032 // TRACE. 00033 // ------ 00034 00035 // to disable extra trace, uncomment UC_SRCE_TRACE_ENTRY/VERBOSE/EXIT(...) 00036 // or to enable extra trace, uncomment UC_SRCE_TRACE_ENTRY/VERBOSE/EXIT UC_SRCE_TRACE 00037 #define UC_SRCE_TRACE_ENTRY(...) 00038 #define UC_SRCE_TRACE_VERBOSE(...) 00039 #define UC_SRCE_TRACE_EXIT(...) 00040 //#define UC_SRCE_TRACE_ENTRY UC_SRCE_TRACE 00041 //#define UC_SRCE_TRACE_VERBOSE UC_SRCE_TRACE 00042 //#define UC_SRCE_TRACE_EXIT UC_SRCE_TRACE 00043 00044 // DATA & CONFIG. 00045 // -------------- 00046 00047 static const ARM_UPDATE_SOURCE *source_registry[MAX_SOURCES]; 00048 static ARM_SOURCE_SignalEvent_t event_cb; 00049 00050 // storage set aside for adding event_cb to the event queue 00051 static arm_uc_callback_t event_cb_storage = {0}; 00052 00053 static arm_uc_error_t ucsm_last_error = {ERR_NONE}; 00054 00055 typedef enum { 00056 QUERY_TYPE_UNKNOWN, 00057 QUERY_TYPE_MANIFEST_DEFAULT, 00058 QUERY_TYPE_MANIFEST_URL, 00059 QUERY_TYPE_FIRMWARE, 00060 QUERY_TYPE_KEYTABLE 00061 } query_type_t; 00062 00063 typedef struct { 00064 arm_uc_uri_t *uri; // the uri from which the resourced should be fetched 00065 arm_uc_buffer_t *buffer; // buffer given by caller to contain the results of the fetch 00066 uint32_t offset; // offset parameter passed to the source 00067 query_type_t type; // type of request, whether is manifest, firmware or keytable 00068 uint8_t excludes[MAX_SOURCES]; // records the tried and failed sources during a get request 00069 uint8_t current_source; // records the index of source use in the get request in progress 00070 } request_t; 00071 00072 // Hold information about the request in flight, there will always only be one request in flight 00073 static request_t request_in_flight; 00074 00075 // FORWARD DECLARATIONS. 00076 // --------------------- 00077 00078 /** 00079 * @brief Initialise a request_t struct, called when a new request 00080 * have been initiated from the hub 00081 */ 00082 static arm_uc_error_t ARM_UCSM_RequestStructInit(request_t *request); 00083 00084 /** 00085 * @brief The SourceRegistry is an array of ARM_UPDATE_SOURCE 00086 */ 00087 static arm_uc_error_t ARM_UCSM_SourceRegistryInit(void); 00088 static arm_uc_error_t ARM_UCSM_SourceRegistryAdd(const ARM_UPDATE_SOURCE *source); 00089 static arm_uc_error_t ARM_UCSM_SourceRegistryRemove(const ARM_UPDATE_SOURCE *source); 00090 00091 /** 00092 * @brief return the index of the source with the smallest cost 00093 * @param url Struct containing URL. NULL for default Manifest. 00094 * @param type The type of current request. 00095 * @param excludes Pointer to an array of size MAX_SOURCES to indicate 00096 * sources we want to exclude in the search. Set excludes[i]=1 to 00097 * exclude source_registry[i] 00098 * @param index Used to return the index of the source with the smallest cost 00099 */ 00100 static arm_uc_error_t ARM_UCSM_SourceRegistryGetLowestCost(arm_uc_uri_t *uri, 00101 query_type_t type, 00102 uint8_t *excludes, 00103 uint32_t *index); 00104 00105 /** 00106 * @brief Find the source of lowest cost and call the corresponding method 00107 * depending on the type of the request. Retry with source of the next 00108 * smallest cost if previous sources failed until the source registry 00109 * is exhausted. 00110 */ 00111 static arm_uc_error_t ARM_UCSM_Get(request_t *req); 00112 00113 /** 00114 * @brief Catch callbacks from sources to enable error handling 00115 */ 00116 static void ARM_UCSM_CallbackWrapper(uintptr_t event); 00117 00118 #if defined(ARM_UC_PROFILE_MBED_CLOUD_CLIENT) && (ARM_UC_PROFILE_MBED_CLOUD_CLIENT == 1) 00119 00120 static void ARM_UCSM_ScheduleAsyncBusyRetryGet(void); 00121 00122 // BUSY RETRY. 00123 // ----------- 00124 00125 // structs to enable timer callback. 00126 static palTimerID_t async_retry_timer_id; 00127 static arm_uc_callback_t async_retry_timer_callback_struct; 00128 00129 // default settings for retries. 00130 #define BUSY_RETRY_DELAY_MS 500 00131 #define MAX_BUSY_RETRIES 2 00132 00133 // number of retries that have taken place. 00134 static uint32_t num_busy_retries = 0; 00135 00136 /** 00137 * @brief Retry Get if source was busy at previous attempt. 00138 * @details If source is busy ARM_UCSM_AsyncRetryGet is registered with event queue, 00139 * so it is called again to retry same source. RetryGet is delayed a bit 00140 * to allow the link to clear (if possible), and is retried multiple times, 00141 * with a gap between tries. 00142 */ 00143 static void ARM_UCSM_DoAsyncBusyRetryGet(uintptr_t unused) 00144 { 00145 UC_SRCE_TRACE_ENTRY(">> %s", __func__); 00146 (void) unused; 00147 00148 // if already retried as many times as allowed, bail out with error, 00149 // otherwise try the Get, and schedule follow-up if fails. 00150 if (++num_busy_retries > MAX_BUSY_RETRIES) { 00151 num_busy_retries = 0; 00152 ARM_UCSM_RequestStructInit(&request_in_flight); 00153 // TODO this potentially aborts the whole download if on an intermediate fragment, 00154 // so figure out if that is the desired behaviour or not. 00155 // the resume engine is *really* only designed to protect a single fragment, 00156 // but this seems way too fragile to have around. 00157 ARM_UCSM_SetError(ARM_UC_ERROR(SOMA_ERR_UNSPECIFIED)); 00158 ARM_UC_PostCallback(&event_cb_storage, event_cb, ARM_UC_SM_EVENT_ERROR); 00159 } else if (ARM_UCSM_Get(&request_in_flight).error != ERR_NONE) { 00160 ARM_UCSM_ScheduleAsyncBusyRetryGet(); 00161 } 00162 UC_SRCE_TRACE_EXIT(".. %s", __func__); 00163 } 00164 00165 /** 00166 * @brief post scheduled action to event queue to avoid running in timer context. 00167 */ 00168 static void ARM_UCSM_PostAsyncBusyRetryGet( 00169 void const *unused) 00170 { 00171 UC_SRCE_TRACE_ENTRY(">> %s", __func__); 00172 (void)unused; 00173 00174 pal_osTimerStop(async_retry_timer_id); 00175 ARM_UC_PostCallback(&async_retry_timer_callback_struct, ARM_UCSM_DoAsyncBusyRetryGet, 0); 00176 } 00177 00178 /** 00179 * @brief request timer-scheduled invocation, invokes post directly if timer fails. 00180 */ 00181 static void ARM_UCSM_ScheduleAsyncBusyRetryGet(void) 00182 { 00183 UC_SRCE_TRACE_ENTRY(">> %s", __func__); 00184 palStatus_t pal_status = PAL_SUCCESS; 00185 // if delay timer has not already been initialized then do so. 00186 if (async_retry_timer_id == 0) { 00187 pal_status = pal_osTimerCreate( 00188 ARM_UCSM_PostAsyncBusyRetryGet, NULL, palOsTimerOnce , &async_retry_timer_id); 00189 } 00190 // if timer has been successfully initialized then install delayed action. 00191 if (pal_status == PAL_SUCCESS) { 00192 pal_status = pal_osTimerStart(async_retry_timer_id, BUSY_RETRY_DELAY_MS); 00193 } 00194 // if not successfully installed delayed action then post action directly. 00195 if (pal_status != PAL_SUCCESS) { 00196 async_retry_timer_id = 0; 00197 ARM_UC_PostCallback(&async_retry_timer_callback_struct, ARM_UCSM_DoAsyncBusyRetryGet, 0); 00198 } 00199 } 00200 00201 #else // ARM_UC_PROFILE_MBED_CLOUD_CLIENT 00202 00203 /** 00204 * @brief Retry get due to source being busy 00205 */ 00206 static void ARM_UCSM_AsyncRetryGet(uintptr_t); 00207 00208 #endif // ARM_UC_PROFILE_MBED_CLOUD_CLIENT 00209 00210 // UTILITY. 00211 // -------- 00212 00213 /** 00214 * @brief Initialise the `Request` struct 00215 */ 00216 static arm_uc_error_t ARM_UCSM_RequestStructInit(request_t *request) 00217 { 00218 memset(request, 0, sizeof(request_t)); 00219 request->current_source = MAX_SOURCES; 00220 request->type = QUERY_TYPE_UNKNOWN; 00221 00222 return (arm_uc_error_t) { ERR_NONE }; 00223 } 00224 00225 00226 // REGISTRY. 00227 // --------- 00228 00229 /** 00230 * @brief Initialise the source_registry array to NULL 00231 */ 00232 static arm_uc_error_t ARM_UCSM_SourceRegistryInit(void) 00233 { 00234 memset(source_registry, 0, sizeof(source_registry)); 00235 return (arm_uc_error_t) { ERR_NONE }; 00236 } 00237 /** 00238 * @brief Returns the index of the given address (possibly NULL) in the source array, 00239 * or MAX_SOURCES if the address is not found. 00240 */ 00241 static uint32_t ARM_UCSM_GetIndexOf(const ARM_UPDATE_SOURCE *source) 00242 { 00243 uint32_t index = MAX_SOURCES; 00244 for (uint32_t i = 0; i < MAX_SOURCES; i++) { 00245 if (source_registry[i] == source) { 00246 index = i; 00247 break; 00248 } 00249 } 00250 return index; 00251 } 00252 /** 00253 * @brief Returns the index of the given source address in the source array, 00254 * or MAX_SOURCES if the source is not found. 00255 */ 00256 static uint32_t ARM_UCSM_GetIndexOfSource(const ARM_UPDATE_SOURCE *source) 00257 { 00258 return ARM_UCSM_GetIndexOf(source); 00259 } 00260 00261 /** 00262 * @brief Add pointer to source to the source_registry array 00263 */ 00264 static arm_uc_error_t ARM_UCSM_SourceRegistryAdd(const ARM_UPDATE_SOURCE *source) 00265 { 00266 uint32_t index = ARM_UCSM_GetIndexOf(NULL); 00267 if (index == MAX_SOURCES) { 00268 return ARM_UCSM_SetError((arm_uc_error_t) { SOMA_ERR_SOURCE_REGISTRY_FULL }); 00269 } else { 00270 source_registry[index] = source; 00271 return (arm_uc_error_t) { ERR_NONE }; 00272 } 00273 00274 } 00275 00276 /** 00277 * @brief Remove pointer to source from the source_registry array 00278 */ 00279 static arm_uc_error_t ARM_UCSM_SourceRegistryRemove(const ARM_UPDATE_SOURCE *source) 00280 { 00281 uint32_t index = ARM_UCSM_GetIndexOfSource(source); 00282 00283 if (index == MAX_SOURCES) { // source not found 00284 return ARM_UCSM_SetError((arm_uc_error_t) { SOMA_ERR_SOURCE_NOT_FOUND }); 00285 } 00286 00287 source_registry[index] = NULL; 00288 return (arm_uc_error_t) { ERR_NONE }; 00289 } 00290 00291 // SOURCE MANAGEMENT. 00292 // ------------------ 00293 00294 /** 00295 * @brief find the index of the source with the smallest cost 00296 * @param url Struct containing URL. NULL for default Manifest. 00297 * @param type The type of current request. 00298 * @param excludes Pointer to an array of size MAX_SOURCES to indicate 00299 * sources we want to exclude in the search. Set excludes[i]=1 to 00300 * exclude source_registry[i] 00301 * @param index Used to return the index of the source with the smalllest cost 00302 * @return error status. 00303 */ 00304 static arm_uc_error_t ARM_UCSM_SourceRegistryGetLowestCost(arm_uc_uri_t *uri, 00305 query_type_t type, 00306 uint8_t *excludes, 00307 uint32_t *index) 00308 { 00309 uint32_t min_cost = UINT32_MAX; 00310 uint32_t min_cost_index = 0; 00311 00312 // start with no route found, could be no sources are registered, skips loop. 00313 arm_uc_error_t retval = (arm_uc_error_t) { SOMA_ERR_NO_ROUTE_TO_SOURCE }; 00314 00315 UC_SRCE_TRACE_ENTRY(">> %s, type %" PRIu32, __func__, (uint32_t)type); 00316 00317 // loop through all sources 00318 for (uint32_t i = 0; i < MAX_SOURCES; i++) { 00319 // assume no route to begin each loop, need to actually find one to change this. 00320 retval = (arm_uc_error_t) { SOMA_ERR_NO_ROUTE_TO_SOURCE }; 00321 00322 // if source is NULL or it has been explicitly excluded because of failure before 00323 if (source_registry[i] == NULL) { 00324 continue; 00325 } else if ((excludes != NULL) && (excludes[i] == 1)) { 00326 UC_SRCE_TRACE_VERBOSE("skipping excluded index %" PRIu32, i); 00327 continue; 00328 } else { 00329 UC_SRCE_TRACE_VERBOSE("testing index %" PRIu32, i); 00330 } 00331 00332 ARM_SOURCE_CAPABILITIES cap = source_registry[i]->GetCapabilities(); 00333 uint32_t cost = UINT32_MAX; 00334 00335 switch (type) { 00336 case QUERY_TYPE_UNKNOWN: 00337 break; 00338 case QUERY_TYPE_MANIFEST_DEFAULT: 00339 if ((uri == NULL) && (cap.manifest_default == 1)) { 00340 UC_SRCE_TRACE_VERBOSE("getting manifest default cost, index %" PRIu32, i); 00341 retval = source_registry[i]->GetManifestDefaultCost(&cost); 00342 } 00343 break; 00344 case QUERY_TYPE_MANIFEST_URL: 00345 if ((uri != NULL) && (cap.manifest_url == 1)) { 00346 UC_SRCE_TRACE_VERBOSE("getting manifest url cost, index %" PRIu32, i); 00347 retval = source_registry[i]->GetManifestURLCost(uri, &cost); 00348 } 00349 break; 00350 case QUERY_TYPE_FIRMWARE: 00351 if ((uri != NULL) && (cap.firmware == 1)) { 00352 UC_SRCE_TRACE_VERBOSE("getting firmware url cost, index %" PRIu32, i); 00353 retval = source_registry[i]->GetFirmwareURLCost(uri, &cost); 00354 } 00355 break; 00356 case QUERY_TYPE_KEYTABLE: 00357 if ((uri != NULL) && (cap.keytable == 1)) { 00358 UC_SRCE_TRACE_VERBOSE("getting keytable url cost, index %" PRIu32, i); 00359 retval = source_registry[i]->GetKeytableURLCost(uri, &cost); 00360 } 00361 break; 00362 default: 00363 break; 00364 } 00365 if (retval.error != ERR_NONE) { 00366 // get cost from source i failed, either no match or during assessment. 00367 // cost is invalid at this point, so skip to next iteration 00368 ARM_UCSM_SetError(retval); 00369 UC_SRCE_TRACE("invalid cost for index %" PRIu32 " type %" PRIu32, i, (uint32_t)type); 00370 continue; 00371 } 00372 // record the cost and i if cost is lower than stored minimum cost. 00373 if (cost < min_cost) { 00374 min_cost = cost; 00375 min_cost_index = i; 00376 } 00377 } 00378 // if no minimum cost was found, then no route was found. 00379 // otherwise return the best route available. 00380 if (min_cost == UINT32_MAX) { 00381 UC_SRCE_ERR_MSG(".. %s: Error - No route", __func__); 00382 return ARM_UCSM_SetError((arm_uc_error_t) { SOMA_ERR_NO_ROUTE_TO_SOURCE }); 00383 } else { 00384 *index = min_cost_index; 00385 UC_SRCE_TRACE_VERBOSE("%s index = %" PRIu32, __func__, min_cost_index); 00386 return (arm_uc_error_t) { ERR_NONE }; 00387 } 00388 } 00389 00390 #if defined(ARM_UC_PROFILE_MBED_CLOUD_CLIENT) && (ARM_UC_PROFILE_MBED_CLOUD_CLIENT == 1) 00391 00392 /** 00393 * @brief find source of lowest cost and call consecutive sources until retrieved. 00394 * @details Find the source of lowest cost and call the corresponding method 00395 * depending on the type of the request. Retry with source of the next 00396 * smallest cost if previous sources failed until the source registry 00397 * is exhausted. 00398 * @param pointer to struct containing details of requested info. 00399 * @return error status 00400 */ 00401 static arm_uc_error_t ARM_UCSM_Get(request_t *req) 00402 { 00403 UC_SRCE_TRACE_ENTRY(">> %s", __func__); 00404 arm_uc_error_t retval = (arm_uc_error_t) { ERR_NONE }; 00405 00406 if (req->uri != NULL) { 00407 UC_SRCE_TRACE_VERBOSE(" with %" PRIxPTR ", host [%s], path [%s], type %" PRIu32, 00408 (uintptr_t)req->uri, req->uri->host, req->uri->path, (uint32_t)req->type); 00409 } else { 00410 UC_SRCE_TRACE_VERBOSE(" with NULL, type %" PRIu32, (uint32_t)req->type); 00411 } 00412 00413 uint32_t index = 0; 00414 if (retval.error == ERR_NONE) { 00415 // get the source of lowest cost, checking that call is valid. 00416 retval = ARM_UCSM_SourceRegistryGetLowestCost( 00417 req->uri, 00418 req->type, 00419 req->excludes, 00420 &index); 00421 } 00422 if (retval.error == ERR_NONE) { 00423 // call is known to be valid, no need to check URI again. 00424 switch (req->type) { 00425 case QUERY_TYPE_MANIFEST_DEFAULT: 00426 UC_SRCE_TRACE_VERBOSE("calling source %" PRIu32 " GetManifestDefault", index); 00427 retval = source_registry[index]->GetManifestDefault(req->buffer, req->offset); 00428 break; 00429 case QUERY_TYPE_MANIFEST_URL: 00430 UC_SRCE_TRACE_VERBOSE("calling source %" PRIu32 " GetManifestURL with %" PRIxPTR, index, (uintptr_t)req->uri); 00431 retval = source_registry[index]->GetManifestURL(req->uri, req->buffer, req->offset); 00432 break; 00433 case QUERY_TYPE_FIRMWARE: 00434 UC_SRCE_TRACE_VERBOSE("calling source %" PRIu32 " GetFirmwareFragment with %" PRIxPTR, index, (uintptr_t)req->uri); 00435 retval = source_registry[index]->GetFirmwareFragment(req->uri, req->buffer, req->offset); 00436 break; 00437 case QUERY_TYPE_KEYTABLE: 00438 UC_SRCE_TRACE_VERBOSE("calling source %" PRIu32 " GetKeytableURL with %" PRIxPTR, index, (uintptr_t)req->uri); 00439 retval = source_registry[index]->GetKeytableURL(req->uri, req->buffer); 00440 break; 00441 default: 00442 if (req->uri == NULL) { 00443 UC_SRCE_ERR_MSG("-ARM_UCSM_Get: Error - Invalid parameter (URI == NULL)"); 00444 ARM_UCSM_SetError(retval = (arm_uc_error_t) { SOMA_ERR_INVALID_URI }); 00445 } else { 00446 UC_SRCE_ERR_MSG("-ARM_UCSM_Get: Error - Invalid parameter (unknown request type)"); 00447 ARM_UCSM_SetError(retval = (arm_uc_error_t) { SOMA_ERR_INVALID_REQUEST }); 00448 } 00449 break; 00450 } 00451 } else { 00452 UC_SRCE_ERR_MSG("%s error retval.code %" PRIu32, __func__, retval.code); 00453 } 00454 00455 // decide what to do based on the results of preceding efforts. 00456 if (retval.code == SRCE_ERR_BUSY) { 00457 UC_SRCE_TRACE_VERBOSE("%s Busy -> ScheduleAsyncBusyRetryGet", __func__); 00458 ARM_UCSM_ScheduleAsyncBusyRetryGet(); 00459 retval = (arm_uc_error_t) { ERR_NONE }; 00460 } else if (retval.code == SOMA_ERR_NO_ROUTE_TO_SOURCE) { 00461 UC_SRCE_ERR_MSG(".. %s: Error - no route available", __func__); 00462 return retval; 00463 } else if (retval.error != ERR_NONE) { 00464 // failure, try source with the next smallest cost. 00465 ARM_UCSM_SetError(retval); 00466 req->excludes[index] = 1; 00467 UC_SRCE_TRACE_VERBOSE(".. %s: Error - failure (try source with the next smallest cost)", __func__); 00468 retval = ARM_UCSM_Get(req); 00469 } else { 00470 // record the index of source handling the get request currently. 00471 req->current_source = index; 00472 UC_SRCE_TRACE_VERBOSE(".. %s: Using source %" PRIu32, __func__, index); 00473 retval = (arm_uc_error_t) { ERR_NONE }; 00474 } 00475 if (ARM_UC_IS_ERROR(retval)) { 00476 ARM_UCSM_SetError(retval); 00477 } 00478 return retval; 00479 } 00480 00481 #else // ARM_UC_PROFILE_MBED_CLOUD_CLIENT 00482 00483 /** 00484 * @brief Find the source of lowest cost and call the corresponding method 00485 * depending on the type of the request. Retry with source of the next 00486 * smallest cost if previous sources failed until the source registry 00487 * is exhausted. 00488 */ 00489 static arm_uc_error_t ARM_UCSM_Get(request_t *req) 00490 { 00491 UC_SRCE_TRACE_ENTRY(">> %s", __func__); 00492 if (req->uri != NULL) { 00493 UC_SRCE_TRACE_VERBOSE(" with %s" PRIx32 ", host [%s], path [%s], type %" PRId16, 00494 req->uri->ptr, req->uri->host, req->uri->path, req->type); 00495 } else { 00496 UC_SRCE_TRACE_VERBOSE(" with NULL, type %" PRId16, req->type); 00497 } 00498 uint32_t index = 0; 00499 00500 ARM_UC_INIT_ERROR(retval, ERR_NONE); 00501 00502 // get the source of lowest cost 00503 retval = ARM_UCSM_SourceRegistryGetLowestCost(req->uri, req->type, req->excludes, &index); 00504 if (ARM_UC_IS_ERROR(retval)) { 00505 UC_SRCE_ERR_MSG(".. %s: error retval.code %" PRIx32, __func__, retval.code); 00506 return ARM_UCSM_SetError(retval); 00507 } 00508 00509 if ((req->uri == NULL) && (req->type == QUERY_TYPE_MANIFEST_DEFAULT)) { 00510 UC_SRCE_TRACE_VERBOSE("calling source %" PRIu32 " GetManifestDefault", index); 00511 retval = source_registry[index]->GetManifestDefault(req->buffer, req->offset); 00512 } else if ((req->uri != NULL) && (req->type == QUERY_TYPE_MANIFEST_URL)) { 00513 UC_SRCE_TRACE_VERBOSE("calling source %" PRIu32 " GetManifestURL with %s", index, req->uri->ptr); 00514 retval = source_registry[index]->GetManifestURL(req->uri, req->buffer, req->offset); 00515 } else if ((req->uri != NULL) && (req->type == QUERY_TYPE_FIRMWARE)) { 00516 UC_SRCE_TRACE_VERBOSE("calling source %" PRIu32 " GetFirmwareFragment with %s", index, req->uri->ptr); 00517 retval = source_registry[index]->GetFirmwareFragment(req->uri, req->buffer, req->offset); 00518 } else if ((req->uri != NULL) && (req->type == QUERY_TYPE_KEYTABLE)) { 00519 UC_SRCE_TRACE_VERBOSE("calling source %" PRIu32 " GetKeytableURL with %s", index, req->uri->ptr); 00520 retval = source_registry[index]->GetKeytableURL(req->uri, req->buffer); 00521 } else { 00522 if (req->uri == NULL) { 00523 UC_SRCE_TRACE(".. %s: Error - Invalid parameter (URI == NULL)", __func__); 00524 return ARM_UCSM_SetError(ARM_UC_ERROR(SOMA_ERR_INVALID_URI)); 00525 } else { 00526 UC_SRCE_TRACE("..%s: Error - Invalid parameter (unknown request type)", __func__); 00527 return ARM_UCSM_SetError(ARM_UC_ERROR(SOMA_ERR_INVALID_REQUEST)); 00528 } 00529 } 00530 if (ARM_UC_ERROR_MATCHES(retval, SRCE_ERR_BUSY)) { 00531 UC_SRCE_TRACE(".. %s: Error - Busy -> PostCallback AsyncRetryGet", __func__); 00532 ARM_UC_PostCallback(&event_cb_storage, ARM_UCSM_AsyncRetryGet, 0); 00533 return ARM_UC_ERROR(ERR_NONE); 00534 } else if (ARM_UC_IS_ERROR(retval)) { 00535 // failure, try source with the next smallest cost 00536 ARM_UCSM_SetError(retval); 00537 req->excludes[index] = 1; 00538 UC_SRCE_TRACE(".. %s: Error - failure (try source with the next smallest cost)", __func__); 00539 return ARM_UCSM_Get(req); 00540 } 00541 // record the index of source handling the get request currently 00542 req->current_source = index; 00543 UC_SRCE_TRACE_EXIT(".. %s, using source %" PRIu32, __func__, index); 00544 00545 return ARM_UC_ERROR(ERR_NONE); 00546 } 00547 00548 /** 00549 * @brief If source is busy ARM_UCSM_AsyncRetryGet is registered with 00550 the event queue so it is called again to retry the same source 00551 */ 00552 static void ARM_UCSM_AsyncRetryGet(uintptr_t unused) 00553 { 00554 (void) unused; 00555 00556 UC_SRCE_TRACE_ENTRY(">> %s", __func__); 00557 arm_uc_error_t retval = ARM_UCSM_Get(&request_in_flight); 00558 if (retval.error != ERR_NONE) { 00559 ARM_UCSM_RequestStructInit(&request_in_flight); 00560 ARM_UCSM_SetError(retval); 00561 ARM_UC_PostCallback(&event_cb_storage, event_cb, ARM_UC_SM_EVENT_ERROR); 00562 } 00563 UC_SRCE_TRACE_EXIT(".. %s", __func__); 00564 } 00565 00566 #endif // ARM_UC_PROFILE_MBED_CLOUD_CLIENT 00567 00568 /** 00569 * @brief Translate source event into source manager event 00570 */ 00571 static ARM_UC_SM_Event_t ARM_UCSM_TranslateEvent(uintptr_t source_event) 00572 { 00573 ARM_UC_SM_Event_t event = ARM_UC_SM_EVENT_ERROR; 00574 00575 switch (source_event) { 00576 case EVENT_NOTIFICATION: 00577 event = ARM_UC_SM_EVENT_NOTIFICATION; 00578 break; 00579 case EVENT_MANIFEST: 00580 event = ARM_UC_SM_EVENT_MANIFEST; 00581 break; 00582 case EVENT_FIRMWARE: 00583 event = ARM_UC_SM_EVENT_FIRMWARE; 00584 break; 00585 case EVENT_KEYTABLE: 00586 event = ARM_UC_SM_EVENT_KEYTABLE; 00587 break; 00588 case EVENT_ERROR: 00589 event = ARM_UC_SM_EVENT_ERROR; 00590 break; 00591 case EVENT_ERROR_SOURCE: 00592 event = ARM_UC_SM_EVENT_ERROR_SOURCE; 00593 break; 00594 case EVENT_ERROR_BUFFER_SIZE: 00595 event = ARM_UC_SM_EVENT_ERROR_BUFFER_SIZE; 00596 break; 00597 } 00598 00599 return event; 00600 } 00601 00602 /** 00603 * @brief Catch callbacks from sources to enable error handling 00604 */ 00605 static void ARM_UCSM_CallbackWrapper(uintptr_t source_event) 00606 { 00607 UC_SRCE_TRACE_ENTRY(">> %s", __func__); 00608 UC_SRCE_TRACE_VERBOSE("source_event == %" PRIu32, source_event); 00609 ARM_UC_SM_Event_t event = ARM_UCSM_TranslateEvent(source_event); 00610 00611 if ((event == ARM_UC_SM_EVENT_ERROR) 00612 && (request_in_flight.type != QUERY_TYPE_UNKNOWN)) { 00613 UC_SRCE_TRACE("ARM_UCSM_TranslateEvent event error == %" PRId16, event); 00614 request_in_flight.excludes[request_in_flight.current_source] = 1; 00615 arm_uc_error_t retval = ARM_UCSM_Get(&request_in_flight); 00616 if (retval.code != ERR_NONE) { 00617 UC_SRCE_TRACE("ARM_UCSM_Get() retval.code == %" PRIx32, retval.code); 00618 ARM_UCSM_RequestStructInit(&request_in_flight); 00619 ARM_UCSM_SetError(retval); 00620 ARM_UC_PostCallback(&event_cb_storage, event_cb, event); 00621 } 00622 } else { 00623 ARM_UCSM_RequestStructInit(&request_in_flight); 00624 ARM_UC_PostCallback(&event_cb_storage, event_cb, event); 00625 } 00626 UC_SRCE_TRACE_EXIT(".. %s", __func__); 00627 } 00628 00629 // PUBLIC API. 00630 // ----------- 00631 00632 /* further documentation of the API can be found in source_manager.h */ 00633 00634 arm_uc_error_t ARM_UCSM_Initialize(ARM_SOURCE_SignalEvent_t callback) 00635 { 00636 // remember the callback 00637 event_cb = callback; 00638 00639 // init source_registry to NULL 00640 return ARM_UCSM_SourceRegistryInit(); 00641 } 00642 00643 arm_uc_error_t ARM_UCSM_Uninitialize() 00644 { 00645 for (size_t i = 0; i < MAX_SOURCES; i++) { 00646 if (source_registry[i] != NULL) { 00647 source_registry[i]->Uninitialize(); 00648 source_registry[i] = NULL; 00649 } 00650 } 00651 return (arm_uc_error_t) {ERR_NONE}; 00652 } 00653 00654 arm_uc_error_t ARM_UCSM_AddSource(const ARM_UPDATE_SOURCE *source) 00655 { 00656 if (ARM_UCSM_GetIndexOfSource(source) != MAX_SOURCES) { 00657 // Source already added, don't add again 00658 // TODO should this return ERR_NONE or a new error 00659 // SOMA_ERR_ALREADY_PRESENT? 00660 return (arm_uc_error_t) { ERR_NONE }; 00661 } 00662 source->Initialize(ARM_UCSM_CallbackWrapper); 00663 return ARM_UCSM_SourceRegistryAdd(source); 00664 } 00665 00666 arm_uc_error_t ARM_UCSM_RemoveSource(const ARM_UPDATE_SOURCE *source) 00667 { 00668 arm_uc_error_t err = ARM_UCSM_SourceRegistryRemove(source); 00669 if (err.code == ERR_NONE) { 00670 // Call 'uninitialize' only if the source was found (and removed) 00671 source->Uninitialize(); 00672 } 00673 return err; 00674 } 00675 00676 /* All the `Get` APIs map into `ARM_UCSM_Get` via ARM_UCSM_GetCommon() */ 00677 00678 /** 00679 * @brief invoke Get after setting up params in in-flight store. 00680 */ 00681 arm_uc_error_t ARM_UCSM_GetCommon( 00682 arm_uc_uri_t *uri, 00683 arm_uc_buffer_t *buffer, 00684 uint32_t offset, 00685 query_type_t type) 00686 { 00687 ARM_UCSM_RequestStructInit(&request_in_flight); 00688 request_in_flight.uri = uri; 00689 request_in_flight.buffer = buffer; 00690 request_in_flight.offset = offset; 00691 request_in_flight.type = type; 00692 00693 arm_uc_error_t retval = ARM_UCSM_Get(&request_in_flight); 00694 if (retval.code != ERR_NONE) { 00695 ARM_UCSM_SetError(retval); 00696 ARM_UCSM_RequestStructInit(&request_in_flight); 00697 } 00698 return retval; 00699 } 00700 00701 arm_uc_error_t ARM_UCSM_GetManifest(arm_uc_buffer_t *buffer, uint32_t offset) 00702 { 00703 arm_uc_error_t retval = ARM_UCSM_GetCommon( 00704 NULL, buffer, offset, QUERY_TYPE_MANIFEST_DEFAULT); 00705 return retval; 00706 } 00707 00708 arm_uc_error_t ARM_UCSM_GetManifestFrom(arm_uc_uri_t *uri, 00709 arm_uc_buffer_t *buffer, 00710 uint32_t offset) 00711 { 00712 arm_uc_error_t retval = ARM_UCSM_GetCommon( 00713 uri, buffer, offset, QUERY_TYPE_MANIFEST_URL); 00714 return retval; 00715 } 00716 00717 arm_uc_error_t ARM_UCSM_GetFirmwareFragment(arm_uc_uri_t *uri, 00718 arm_uc_buffer_t *buffer, 00719 uint32_t offset) 00720 { 00721 arm_uc_error_t retval = ARM_UCSM_GetCommon( 00722 uri, buffer, offset, QUERY_TYPE_FIRMWARE); 00723 return retval; 00724 } 00725 00726 arm_uc_error_t ARM_UCSM_GetKeytable(arm_uc_uri_t *uri, arm_uc_buffer_t *buffer) 00727 { 00728 arm_uc_error_t retval = ARM_UCSM_GetCommon( 00729 uri, buffer, 0, QUERY_TYPE_KEYTABLE); 00730 return retval; 00731 } 00732 00733 arm_uc_error_t ARM_UCSM_GetError(void) 00734 { 00735 return ucsm_last_error; 00736 } 00737 00738 arm_uc_error_t ARM_UCSM_SetError(arm_uc_error_t an_error) 00739 { 00740 return (ucsm_last_error = an_error); 00741 } 00742 00743 00744 00745 // INTERFACE. 00746 // ---------- 00747 00748 ARM_UC_SOURCE_MANAGER_t ARM_UC_SourceManager = { 00749 .Initialize = ARM_UCSM_Initialize, 00750 .Uninitialize = ARM_UCSM_Uninitialize, 00751 .AddSource = ARM_UCSM_AddSource, 00752 .RemoveSource = ARM_UCSM_RemoveSource, 00753 .GetManifest = ARM_UCSM_GetManifest, 00754 .GetManifestFrom = ARM_UCSM_GetManifestFrom, 00755 .GetFirmwareFragment = ARM_UCSM_GetFirmwareFragment, 00756 .GetKeytable = ARM_UCSM_GetKeytable 00757 };
Generated on Tue Jul 12 2022 20:20:57 by
