Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers FirmwareUpdateResource.cpp Source File

FirmwareUpdateResource.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 
00019 #include "update-client-lwm2m/FirmwareUpdateResource.h"
00020 
00021 #include "update-client-common/arm_uc_common.h"
00022 #include "source/update_client_hub_state_machine.h"
00023 #include "source/update_client_hub_error_handler.h"
00024 
00025 #include <stdio.h>
00026 
00027 #define ARM_UCS_LWM2M_INTERNAL_ERROR (-1)
00028 #define ARM_UCS_LWM2M_INTERNAL_SUCCESS (0)
00029 
00030 namespace FirmwareUpdateResource {
00031 
00032     /* send delayed response */
00033     enum {
00034         ResourcePackage,
00035         ResourcePackageURI,
00036         ResourceUpdate
00037     };
00038 
00039     static void packageCallback(void* _parameters);
00040     static void packageURICallback(void* _parameters);
00041     static void updateCallback(void*);
00042     static void notificationCallback(const M2MBase& object, NotificationDeliveryStatus delivery_status, void* client_args);
00043     static void sendDelayedResponseTask(uint32_t parameter);
00044 
00045     /* LWM2M Firmware Update Object */
00046     static M2MObject* updateObject;
00047 
00048     /* LWM2M Firmware Update Object resources */
00049     static M2MResource* resourcePackage = NULL;
00050     static M2MResource* resourcePackageURI = NULL;
00051     static M2MResource* resourceUpdate = NULL;
00052     static M2MResource* resourceState = NULL;
00053     static M2MResource* resourceResult = NULL;
00054     static M2MResource* resourceName = NULL;
00055     static M2MResource* resourceVersion = NULL;
00056 
00057     /* function pointers to callback functions */
00058     static void (*externalPackageCallback)(const uint8_t* buffer, uint16_t length) = NULL;
00059     static void (*externalPackageURICallback)(const uint8_t* buffer, uint16_t length) = NULL;
00060     static void (*externalUpdateCallback)(void) = NULL;
00061     static void (*externalNotificationCallback)(void) = NULL;
00062 
00063     /* Callback structs for delayed response.
00064      *
00065      * There needs to be one per callback type to avoid collisions between different operations.
00066      */
00067     static arm_uc_callback_t callbackNodePackage = { NULL, 0, NULL, 0 };
00068     static arm_uc_callback_t callbackNodePackageURI = { NULL, 0, NULL, 0 };
00069     static arm_uc_callback_t callbackNodeResourceUpdate = { NULL, 0, NULL, 0 };
00070 }
00071 
00072 /**
00073  * @brief Initialize LWM2M Firmware Update Object
00074  * @details Sets up LWM2M object with accompanying resources.
00075  */
00076 void FirmwareUpdateResource::Initialize(void)
00077 {
00078     static bool initialized = false;
00079 
00080     if (!initialized)
00081     {
00082         initialized = true;
00083 
00084         /* The LWM2M Firmware Update Object is at /5 */
00085         updateObject = M2MInterfaceFactory::create_object("5");
00086 
00087         if (updateObject)
00088         {
00089             /* Create first (and only) instance /5/0 */
00090             M2MObjectInstance* updateInstance = updateObject->create_object_instance();
00091 
00092             if (updateInstance)
00093             {
00094                 /* Set observable so the Portal can read it */
00095                 updateInstance->set_observable(true);
00096 
00097                 /* Default values are non-standard, but the standard has no
00098                    values for indicating that the device is initializing.
00099                    To address this, Service ignores -1 and/or 255 values coming through,
00100                    so for our purposes this is the correct form of initialization.
00101                 */
00102                 uint8_t defaultValue[] = {"-1"};
00103                 uint8_t defaultVersion[] = {"-1"};
00104 
00105                 /* Create Package resource /5/0/0 */
00106                 resourcePackage = updateInstance->create_dynamic_resource(
00107                                     "0", "Package", M2MResourceInstance::OPAQUE, false);
00108                 if (resourcePackage)
00109                 {
00110                     /* This should be PUT according to the standard but
00111                        Connector client doesn't support callbacks for PUT.
00112                     */
00113                     resourcePackage->set_operation(M2MBase::POST_ALLOWED);
00114                     resourcePackage->set_execute_function(packageCallback);
00115 
00116                     /* The delayed response if for processing heavier loads */
00117                     resourcePackage->set_delayed_response(true);
00118                 }
00119 
00120                 /* Create Package URI resource /5/0/1 */
00121                 resourcePackageURI = updateInstance->create_dynamic_resource(
00122                                     "1", "PackageURI", M2MResourceInstance::STRING, false);
00123                 if (resourcePackageURI)
00124                 {
00125                     resourcePackageURI->set_operation(M2MBase::POST_ALLOWED);
00126                     resourcePackageURI->set_execute_function(packageURICallback);
00127                     resourcePackageURI->set_delayed_response(true);
00128                 }
00129 
00130                 /* Create Update resource /5/0/2 */
00131                 resourceUpdate = updateInstance->create_dynamic_resource(
00132                                     "2", "Update", M2MResourceInstance::BOOLEAN, false);
00133                 if (resourceUpdate)
00134                 {
00135                     resourceUpdate->set_operation(M2MBase::POST_ALLOWED);
00136                     resourceUpdate->set_execute_function(updateCallback);
00137                     resourceUpdate->set_delayed_response(true);
00138                 }
00139 
00140                 /* Create State resource /5/0/3 */
00141                 resourceState = updateInstance->create_dynamic_resource(
00142                                     "3", "State", M2MResourceInstance::INTEGER, true);
00143                 if (resourceState)
00144                 {
00145                     resourceState->set_operation(M2MBase::GET_ALLOWED);
00146                     resourceState->set_notification_delivery_status_cb(notificationCallback, NULL);
00147                     resourceState->set_value(defaultValue, sizeof(defaultValue) - 1);
00148                 }
00149 
00150                 /* Create Update Result resource /5/0/5 */
00151                 resourceResult = updateInstance->create_dynamic_resource(
00152                                     "5", "UpdateResult", M2MResourceInstance::INTEGER, true);
00153                 if (resourceResult)
00154                 {
00155                     resourceResult->set_operation(M2MBase::GET_ALLOWED);
00156                     resourceResult->set_notification_delivery_status_cb(notificationCallback, NULL);
00157                     resourceResult->set_value(defaultValue, sizeof(defaultValue) - 1);
00158                 }
00159 
00160                 /* Create PkgName resource /5/0/6 */
00161                 resourceName = updateInstance->create_dynamic_resource(
00162                                     "6", "PkgName", M2MResourceInstance::STRING, true);
00163                 if (resourceName)
00164                 {
00165                     resourceName->set_operation(M2MBase::GET_ALLOWED);
00166                     resourceName->set_value(defaultVersion, sizeof(defaultVersion) - 1);
00167                 }
00168 
00169                 /* Create PkgVersion resource /5/0/7 */
00170                 resourceVersion = updateInstance->create_dynamic_resource(
00171                                     "7", "PkgVersion", M2MResourceInstance::STRING, true);
00172                 if (resourceVersion)
00173                 {
00174                     resourceVersion->set_operation(M2MBase::GET_ALLOWED);
00175                     resourceVersion->set_value(defaultVersion, sizeof(defaultVersion) - 1);
00176                 }
00177             }
00178         }
00179     }
00180 }
00181 
00182 M2MObject* FirmwareUpdateResource::getObject()
00183 {
00184     Initialize();
00185 
00186     return updateObject;
00187 }
00188 
00189 void FirmwareUpdateResource::packageCallback(void* _parameters)
00190 {
00191     UC_SRCE_TRACE("FirmwareUpdateResource::packageCallback");
00192 
00193     if (_parameters && externalPackageCallback)
00194     {
00195         /* recast parameter */
00196         M2MResource::M2MExecuteParameter* parameters =
00197             static_cast<M2MResource::M2MExecuteParameter*>(_parameters);
00198 
00199         /* read payload */
00200         const uint8_t* buffer = parameters->get_argument_value();
00201         uint16_t length = parameters->get_argument_value_length();
00202 
00203         /* invoke external callback function */
00204         externalPackageCallback(buffer, length);
00205 
00206         /* schedule delayed response */
00207         ARM_UC_PostCallback(&callbackNodePackage,
00208                             FirmwareUpdateResource::sendDelayedResponseTask,
00209                             FirmwareUpdateResource::ResourcePackage);
00210     }
00211 }
00212 
00213 void FirmwareUpdateResource::packageURICallback(void* _parameters)
00214 {
00215     UC_SRCE_TRACE("FirmwareUpdateResource::packageURICallback");
00216 
00217     if (_parameters && externalPackageURICallback)
00218     {
00219         /* recast parameter */
00220         M2MResource::M2MExecuteParameter* parameters =
00221             static_cast<M2MResource::M2MExecuteParameter*>(_parameters);
00222 
00223         /* read payload */
00224         const uint8_t* buffer = parameters->get_argument_value();
00225         uint16_t length = parameters->get_argument_value_length();
00226 
00227         /* invoke external callback function */
00228         externalPackageURICallback(buffer, length);
00229 
00230         /* schedule delayed response */
00231         ARM_UC_PostCallback(&callbackNodePackageURI,
00232                             FirmwareUpdateResource::sendDelayedResponseTask,
00233                             FirmwareUpdateResource::ResourcePackageURI);
00234     }
00235 }
00236 
00237 void FirmwareUpdateResource::updateCallback(void* _parameters)
00238 {
00239     UC_SRCE_TRACE("FirmwareUpdateResource::updateCallback");
00240 
00241     (void) _parameters;
00242 
00243     if (externalUpdateCallback)
00244     {
00245         /* invoke external callback function */
00246         externalUpdateCallback();
00247 
00248         /* schedule delayed response */
00249         ARM_UC_PostCallback(&callbackNodeResourceUpdate,
00250                             FirmwareUpdateResource::sendDelayedResponseTask,
00251                             FirmwareUpdateResource::ResourceUpdate);
00252     }
00253 }
00254 
00255 void FirmwareUpdateResource::notificationCallback(const M2MBase& base,
00256                                                   const NotificationDeliveryStatus delivery_status,
00257                                                   void *client_args)
00258 {
00259     UC_SRCE_TRACE("FirmwareUpdateResource::notificationCallback status: %d", delivery_status);
00260 
00261     if (delivery_status == NOTIFICATION_STATUS_DELIVERED) {
00262         // Notification has been ACKed by server, complete to callback
00263         UC_SRCE_TRACE("FirmwareUpdateResource::notificationCallback DELIVERED");
00264 
00265         if (externalNotificationCallback) {
00266             externalNotificationCallback();
00267         }
00268 
00269     }
00270     else if (delivery_status == NOTIFICATION_STATUS_BUILD_ERROR ||
00271              delivery_status == NOTIFICATION_STATUS_RESEND_QUEUE_FULL ||
00272              delivery_status == NOTIFICATION_STATUS_SEND_FAILED ||
00273              delivery_status == NOTIFICATION_STATUS_UNSUBSCRIBED) {
00274         // Error case, notification not reaching service
00275         // We are sending out error because we cannot rely connection is
00276         // anymore up and the service and client are not in sync anymore.
00277         // Also sending new notifications after this might lock event
00278         // machine because comms cannot service us anymore.
00279         UC_SRCE_ERR_MSG("Received Notification delivery status: %d - ERROR!", delivery_status);
00280         ARM_UC_HUB_ErrorHandler(HUB_ERR_CONNECTION, ARM_UC_HUB_getState());
00281 
00282     }
00283     else {
00284         // NOTIFICATION_STATUS_INIT
00285         // NOTIFICATION_STATUS_SENT
00286         // NOTIFICATION_STATUS_SUBSCRIBED
00287         UC_SRCE_TRACE("FirmwareUpdateResource::notificationCallback Status ignored, waiting delivery...");
00288     }
00289 }
00290 
00291 void FirmwareUpdateResource::sendDelayedResponseTask(uint32_t parameter)
00292 {
00293     UC_SRCE_TRACE("FirmwareUpdateResource::sendDelayedResponseTask");
00294 
00295     switch (parameter)
00296     {
00297         case FirmwareUpdateResource::ResourcePackage:
00298             UC_SRCE_TRACE("resourcePackage->send_delayed_post_response");
00299             resourcePackage->send_delayed_post_response();
00300             break;
00301         case FirmwareUpdateResource::ResourcePackageURI:
00302             UC_SRCE_TRACE("resourcePackageURI->send_delayed_post_response");
00303             resourcePackageURI->send_delayed_post_response();
00304             break;
00305         case FirmwareUpdateResource::ResourceUpdate:
00306             UC_SRCE_TRACE("resourceUpdate->send_delayed_post_response");
00307             resourceUpdate->send_delayed_post_response();
00308             break;
00309         default:
00310             UC_SRCE_ERR_MSG("unsupported resource");
00311             break;
00312     }
00313 }
00314 
00315 /*****************************************************************************/
00316 /* Update Client Source                                                      */
00317 /*****************************************************************************/
00318 
00319 /* Add callback for resource /5/0/0, Package */
00320 int32_t FirmwareUpdateResource::addPackageCallback(void (*cb)(const uint8_t* buffer, uint16_t length))
00321 {
00322     UC_SRCE_TRACE("FirmwareUpdateResource::addPackageCallback: %p", cb);
00323 
00324     externalPackageCallback = cb;
00325 
00326     return ARM_UCS_LWM2M_INTERNAL_SUCCESS;
00327 }
00328 
00329 /* Add callback for resource /5/0/1, Package URI */
00330 int32_t FirmwareUpdateResource::addPackageURICallback(void (*cb)(const uint8_t* buffer, uint16_t length))
00331 {
00332     UC_SRCE_TRACE("FirmwareUpdateResource::addPackageURICallback: %p", cb);
00333 
00334     externalPackageURICallback = cb;
00335 
00336     return ARM_UCS_LWM2M_INTERNAL_SUCCESS;
00337 }
00338 
00339 /* Add callback for resource /5/0/2, Update */
00340 int32_t FirmwareUpdateResource::addUpdateCallback(void (*cb)(void))
00341 {
00342     UC_SRCE_TRACE("FirmwareUpdateResource::addUpdateCallback: %p", cb);
00343 
00344     externalUpdateCallback = cb;
00345 
00346     return ARM_UCS_LWM2M_INTERNAL_SUCCESS;
00347 }
00348 
00349 /* Add callback for when send{State, UpdateResult} is done */
00350 int32_t FirmwareUpdateResource::addNotificationCallback(void (*cb)(void))
00351 {
00352     UC_SRCE_TRACE("FirmwareUpdateResource::addNotificationCallback: %p", cb);
00353 
00354     externalNotificationCallback = cb;
00355 
00356     return ARM_UCS_LWM2M_INTERNAL_SUCCESS;
00357 }
00358 
00359 /*****************************************************************************/
00360 /* Update Client Status                                                      */
00361 /*****************************************************************************/
00362 
00363 /* Send state for resource /5/0/3, State */
00364 int32_t FirmwareUpdateResource::sendState(arm_ucs_lwm2m_state_t state)
00365 {
00366     UC_SRCE_TRACE("FirmwareUpdateResource::sendState");
00367 
00368     int32_t result = ARM_UCS_LWM2M_INTERNAL_ERROR;
00369 
00370     if (state <= ARM_UCS_LWM2M_STATE_LAST)
00371     {
00372         /* valid states: 0-3 */
00373         uint8_t value[2];
00374         snprintf((char*)value, 2, "%d", state);
00375         resourceState->set_value(value, 1);
00376 
00377         result = ARM_UCS_LWM2M_INTERNAL_SUCCESS;
00378     }
00379 
00380     return result;
00381 }
00382 
00383 /* Send result for resource /5/0/5, Update Result */
00384 int32_t FirmwareUpdateResource::sendUpdateResult(arm_ucs_lwm2m_result_t updateResult)
00385 {
00386     UC_SRCE_TRACE("FirmwareUpdateResource::sendUpdateResult");
00387 
00388     int32_t result = ARM_UCS_LWM2M_INTERNAL_ERROR;
00389 
00390     if (updateResult <= ARM_UCS_LWM2M_RESULT_LAST)
00391     {
00392         /* valid results: 0-8 */
00393         uint8_t value[2];
00394         snprintf((char*)value, 2, "%d", updateResult);
00395         resourceResult->set_value(value, 1);
00396 
00397         result = ARM_UCS_LWM2M_INTERNAL_SUCCESS;
00398     }
00399 
00400     return result;
00401 }
00402 
00403 /* Send name for resource /5/0/6 PkgName */
00404 int32_t FirmwareUpdateResource::sendPkgName(const uint8_t* name, uint16_t length)
00405 {
00406     UC_SRCE_TRACE("FirmwareUpdateResource::sendPkgName");
00407 
00408     int32_t result = ARM_UCS_LWM2M_INTERNAL_ERROR;
00409 
00410     /* the maximum length is defined in the OMA LWM2M standard. */
00411     if ((name != NULL) && (length <= 255))
00412     {
00413         uint8_t value[64] = { 0 };
00414         uint8_t index = 0;
00415 
00416         /* convert to printable characters using lookup table */
00417         for ( ; (index < 32) && (index < length); index++)
00418         {
00419             value[2 * index    ] = arm_uc_hex_table[name[index] >> 4];
00420             value[2 * index + 1] = arm_uc_hex_table[name[index] & 0x0F];
00421         }
00422 
00423         resourceName->set_value(value, 2 * index);
00424 
00425         result = ARM_UCS_LWM2M_INTERNAL_SUCCESS;
00426     }
00427 
00428     return result;
00429 }
00430 
00431 /* Send version for resource /5/0/7, PkgVersion */
00432 int32_t FirmwareUpdateResource::sendPkgVersion(uint64_t version)
00433 {
00434     UC_SRCE_TRACE("FirmwareUpdateResource::sendPkgVersion");
00435 
00436     uint8_t value[21] = { 0 };
00437     uint8_t length = snprintf((char*) value, 21, "%llu" , version);
00438     resourceVersion->set_value(value, length);
00439 
00440     return ARM_UCS_LWM2M_INTERNAL_SUCCESS;
00441 }
00442 
00443 void FirmwareUpdateResource::Uninitialize(void)
00444 {
00445     UC_SRCE_TRACE("FirmwareUpdateResource::Uninitialize"); 
00446     delete updateObject;
00447     updateObject = NULL;
00448 }