Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers simple-mbed-cloud-client.cpp Source File

simple-mbed-cloud-client.cpp

00001 // ----------------------------------------------------------------------------
00002 // Copyright 2016-2018 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 <stdio.h>
00020 #include "simple-mbed-cloud-client.h"
00021 #include "mbed-trace-helper.h"
00022 #include "resource-helper.h"
00023 
00024 #ifdef MBED_CLOUD_DEV_UPDATE_ID
00025 #include "update_client_hub.h"
00026 #endif
00027 
00028 #define TRACE_GROUP "SMCC"
00029 
00030 #ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE
00031 #include MBED_CLOUD_CLIENT_USER_CONFIG_FILE
00032 #endif
00033 
00034 #ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE
00035 #include "update-helper/update-helper.h"
00036 #endif
00037 
00038 #ifdef MBED_HEAP_STATS_ENABLED
00039 #include "memory_tests.h"
00040 #endif
00041 
00042 #ifndef DEFAULT_FIRMWARE_PATH
00043 #define DEFAULT_FIRMWARE_PATH       "/fs/firmware"
00044 #endif
00045 
00046 SimpleMbedCloudClient::SimpleMbedCloudClient(NetworkInterface *net, BlockDevice *bd, FileSystem *fs) :
00047     _registered(false),
00048     _register_called(false),
00049     _register_and_connect_called(false),
00050     _registered_cb(NULL),
00051     _unregistered_cb(NULL),
00052     _error_cb(NULL),
00053     _net(net),
00054     _bd(bd),
00055     _fs(fs),
00056     _storage(bd, fs)
00057 {
00058 }
00059 
00060 SimpleMbedCloudClient::~SimpleMbedCloudClient() {
00061     for (unsigned int i = 0; _resources.size(); i++) {
00062         delete _resources[i];
00063     }
00064 }
00065 
00066 int SimpleMbedCloudClient::init(bool format) {
00067     // Requires DAPLink 245+ (https://github.com/ARMmbed/DAPLink/pull/364)
00068     // Older versions: workaround to prevent possible deletion of credentials:
00069     wait(1);
00070 
00071 #ifdef MBED_CLOUD_DEV_UPDATE_ID
00072 
00073     extern const uint8_t arm_uc_vendor_id[];
00074     extern const uint16_t arm_uc_vendor_id_size;
00075     extern const uint8_t arm_uc_class_id[];
00076     extern const uint16_t arm_uc_class_id_size;
00077 
00078     ARM_UC_SetVendorId(arm_uc_vendor_id, arm_uc_vendor_id_size);
00079     ARM_UC_SetClassId(arm_uc_class_id, arm_uc_class_id_size);
00080 
00081 #endif
00082 
00083     // Initialize Mbed Trace for debugging
00084     // Create mutex for tracing to avoid broken lines in logs
00085     if(!mbed_trace_helper_create_mutex()) {
00086         printf("[SMCC] ERROR - Mutex creation for mbed_trace failed!\n");
00087         return 1;
00088     }
00089 
00090     // Initialize mbed trace
00091     mbed_trace_init();
00092     mbed_trace_helper_create_mutex();
00093     mbed_trace_mutex_wait_function_set(mbed_trace_helper_mutex_wait);
00094     mbed_trace_mutex_release_function_set(mbed_trace_helper_mutex_release);
00095 
00096     // Initialize the FCC
00097     int status = fcc_init();
00098     if (status != FCC_STATUS_SUCCESS && status != FCC_STATUS_ENTROPY_ERROR && status != FCC_STATUS_ROT_ERROR) {
00099         tr_error("Factory Client Configuration failed with status %d", status);
00100         return 1;
00101     }
00102 
00103     status = _storage.init();
00104     if (status != FCC_STATUS_SUCCESS) {
00105         tr_error("Failed to initialize storage layer (%d)", status);
00106         return 1;
00107     }
00108 
00109     status = _storage.sotp_init();
00110     if (status != FCC_STATUS_SUCCESS) {
00111         tr_error("Could not initialize SOTP (%d)", status);
00112         fcc_finalize();
00113         return 1;
00114     }
00115 
00116 #if RESET_STORAGE
00117     status = reset_storage();
00118     if (status != FCC_STATUS_SUCCESS) {
00119         tr_error("reset_storage (triggered by RESET_STORAGE macro) failed (%d)", status);
00120         return 1;
00121     }
00122     // Reinitialize SOTP
00123     status = _storage.sotp_init();
00124     if (status != FCC_STATUS_SUCCESS) {
00125         tr_error("Could not initialize SOTP (%d)", status);
00126         return 1;
00127     }
00128 #endif
00129 
00130     status = verify_cloud_configuration(format);
00131 
00132     if (status != 0) {
00133     // This is designed to simplify user-experience by auto-formatting the
00134     // primary storage if no valid certificates exist.
00135     // This should never be used for any kind of production devices.
00136 #if MBED_CONF_APP_FORMAT_STORAGE_LAYER_ON_ERROR == 1
00137         tr_info("Could not load certificate (e.g. no certificates or RoT might have changed), resetting storage...");
00138         status = reset_storage();
00139         if (status != FCC_STATUS_SUCCESS) {
00140             return status;
00141         }
00142         status = _storage.sotp_init();
00143         if (status != FCC_STATUS_SUCCESS) {
00144             return status;
00145         }
00146         status = verify_cloud_configuration(format);
00147         if (status != 0) {
00148             return status;
00149         }
00150 #else
00151         return 1;
00152 #endif
00153     }
00154 
00155     // Deletes existing firmware images from storage.
00156     // This deletes any existing firmware images during application startup.
00157     // This compilation flag is currently implemented only for mbed OS.
00158 #ifdef RESET_FIRMWARE
00159     palStatus_t status = PAL_SUCCESS;
00160     status = pal_fsRmFiles(DEFAULT_FIRMWARE_PATH);
00161     if(status == PAL_SUCCESS) {
00162         printf("[SMCC] Firmware storage erased\n");
00163     } else if (status == PAL_ERR_FS_NO_PATH) {
00164         tr_info("Firmware path not found/does not exist");
00165     } else {
00166         tr_error("Firmware storage erasing failed with %" PRId32, status);
00167         return 1;
00168     }
00169 #endif
00170 
00171     return 0;
00172 }
00173 
00174 bool SimpleMbedCloudClient::call_register() {
00175     // need to unregister first before calling this function again
00176     if (_register_called) return false;
00177 
00178     _cloud_client.on_registered(this, &SimpleMbedCloudClient::client_registered);
00179     _cloud_client.on_unregistered(this, &SimpleMbedCloudClient::client_unregistered);
00180     _cloud_client.on_error(this, &SimpleMbedCloudClient::error);
00181 
00182     bool setup = _cloud_client.setup(_net);
00183     _register_called = true;
00184     if (!setup) {
00185         tr_error("Client setup failed");
00186         return false;
00187     }
00188 
00189 #ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE
00190     /* Set callback functions for authorizing updates and monitoring progress.
00191        Code is implemented in update_ui_example.cpp
00192        Both callbacks are completely optional. If no authorization callback
00193        is set, the update process will procede immediately in each step.
00194     */
00195     update_helper_set_cloud_client(&_cloud_client);
00196     _cloud_client.set_update_authorize_handler(update_authorize);
00197     _cloud_client.set_update_progress_handler(update_progress);
00198 #endif
00199     return true;
00200 }
00201 
00202 void SimpleMbedCloudClient::close() {
00203     _cloud_client.close();
00204 }
00205 
00206 void SimpleMbedCloudClient::register_update() {
00207     _cloud_client.register_update();
00208 }
00209 
00210 void SimpleMbedCloudClient::client_registered() {
00211     _registered = true;
00212     static const ConnectorClientEndpointInfo* endpoint = NULL;
00213     if (endpoint == NULL) {
00214         endpoint = _cloud_client.endpoint_info();
00215         if (endpoint && _registered_cb) {
00216             _registered_cb(endpoint);
00217         }
00218     }
00219 #ifdef MBED_HEAP_STATS_ENABLED
00220     heap_stats();
00221 #endif
00222 }
00223 
00224 void SimpleMbedCloudClient::client_unregistered() {
00225     _registered = false;
00226     _register_called = false;
00227 
00228     if (_unregistered_cb) {
00229         _unregistered_cb();
00230     }
00231 
00232 #ifdef MBED_HEAP_STATS_ENABLED
00233     heap_stats();
00234 #endif
00235 }
00236 
00237 void SimpleMbedCloudClient::error(int error_code) {
00238     const char *error;
00239     switch(error_code) {
00240         case MbedCloudClient::ConnectErrorNone:
00241             error = "MbedCloudClient::ConnectErrorNone";
00242             break;
00243         case MbedCloudClient::ConnectAlreadyExists:
00244             error = "MbedCloudClient::ConnectAlreadyExists";
00245             break;
00246         case MbedCloudClient::ConnectBootstrapFailed:
00247             error = "MbedCloudClient::ConnectBootstrapFailed";
00248             break;
00249         case MbedCloudClient::ConnectInvalidParameters:
00250             error = "MbedCloudClient::ConnectInvalidParameters";
00251             break;
00252         case MbedCloudClient::ConnectNotRegistered:
00253             error = "MbedCloudClient::ConnectNotRegistered";
00254             break;
00255         case MbedCloudClient::ConnectTimeout:
00256             error = "MbedCloudClient::ConnectTimeout";
00257             break;
00258         case MbedCloudClient::ConnectNetworkError:
00259             error = "MbedCloudClient::ConnectNetworkError";
00260             break;
00261         case MbedCloudClient::ConnectResponseParseFailed:
00262             error = "MbedCloudClient::ConnectResponseParseFailed";
00263             break;
00264         case MbedCloudClient::ConnectUnknownError:
00265             error = "MbedCloudClient::ConnectUnknownError";
00266             break;
00267         case MbedCloudClient::ConnectMemoryConnectFail:
00268             error = "MbedCloudClient::ConnectMemoryConnectFail";
00269             break;
00270         case MbedCloudClient::ConnectNotAllowed:
00271             error = "MbedCloudClient::ConnectNotAllowed";
00272             break;
00273         case MbedCloudClient::ConnectSecureConnectionFailed:
00274             error = "MbedCloudClient::ConnectSecureConnectionFailed";
00275             break;
00276         case MbedCloudClient::ConnectDnsResolvingFailed:
00277             error = "MbedCloudClient::ConnectDnsResolvingFailed";
00278             break;
00279 #ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE
00280         case MbedCloudClient::UpdateWarningCertificateNotFound:
00281             error = "MbedCloudClient::UpdateWarningCertificateNotFound";
00282             break;
00283         case MbedCloudClient::UpdateWarningIdentityNotFound:
00284             error = "MbedCloudClient::UpdateWarningIdentityNotFound";
00285             break;
00286         case MbedCloudClient::UpdateWarningCertificateInvalid:
00287             error = "MbedCloudClient::UpdateWarningCertificateInvalid";
00288             break;
00289         case MbedCloudClient::UpdateWarningSignatureInvalid:
00290             error = "MbedCloudClient::UpdateWarningSignatureInvalid";
00291             break;
00292         case MbedCloudClient::UpdateWarningVendorMismatch:
00293             error = "MbedCloudClient::UpdateWarningVendorMismatch";
00294             break;
00295         case MbedCloudClient::UpdateWarningClassMismatch:
00296             error = "MbedCloudClient::UpdateWarningClassMismatch";
00297             break;
00298         case MbedCloudClient::UpdateWarningDeviceMismatch:
00299             error = "MbedCloudClient::UpdateWarningDeviceMismatch";
00300             break;
00301         case MbedCloudClient::UpdateWarningURINotFound:
00302             error = "MbedCloudClient::UpdateWarningURINotFound";
00303             break;
00304         case MbedCloudClient::UpdateWarningRollbackProtection:
00305             error = "MbedCloudClient::UpdateWarningRollbackProtection";
00306             break;
00307         case MbedCloudClient::UpdateWarningUnknown:
00308             error = "MbedCloudClient::UpdateWarningUnknown";
00309             break;
00310         case MbedCloudClient::UpdateErrorWriteToStorage:
00311             error = "MbedCloudClient::UpdateErrorWriteToStorage";
00312             break;
00313         case MbedCloudClient::UpdateErrorInvalidHash:
00314             error = "MbedCloudClient::UpdateErrorInvalidHash";
00315             break;
00316 #endif
00317         default:
00318             error = "UNKNOWN";
00319     }
00320 
00321     if (_error_cb) {
00322         _error_cb(error_code, error);
00323         return;
00324     }
00325 
00326     printf("\n[SMCC] Error occurred : %s\n", error);
00327     printf("[SMCC] Error code : %d\n", error_code);
00328     printf("[SMCC] Error details : %s\n",_cloud_client.error_description());
00329 }
00330 
00331 bool SimpleMbedCloudClient::is_client_registered() {
00332     return _registered;
00333 }
00334 
00335 bool SimpleMbedCloudClient::is_register_called() {
00336     return _register_called;
00337 }
00338 
00339 bool SimpleMbedCloudClient::register_and_connect() {
00340     if (_register_and_connect_called) return false;
00341 
00342     mcc_resource_def resourceDef;
00343 
00344     for (int i = 0; i < _resources.size(); i++) {
00345         _resources[i]->get_data(&resourceDef);
00346         M2MResource *res = add_resource(&_obj_list, resourceDef.object_id, resourceDef.instance_id,
00347                     resourceDef.resource_id, resourceDef.name.c_str(), M2MResourceInstance::STRING,
00348                     (M2MBase::Operation)resourceDef.method_mask, resourceDef.value.c_str(), resourceDef.observable,
00349                     resourceDef.put_callback, resourceDef.post_callback, resourceDef.notification_callback);
00350         _resources[i]->set_m2m_resource(res);
00351     }
00352     _cloud_client.add_objects(_obj_list);
00353 
00354     _register_and_connect_called = true;
00355 
00356     // Start registering to the cloud.
00357     bool retval = call_register();
00358 
00359 // Print memory statistics if the MBED_HEAP_STATS_ENABLED is defined.
00360 #ifdef MBED_HEAP_STATS_ENABLED
00361         tr_info("Register being called");
00362         heap_stats();
00363 #endif
00364 
00365     return retval;
00366 }
00367 
00368 void SimpleMbedCloudClient::on_registered(Callback<void(const ConnectorClientEndpointInfo*)> cb) {
00369     _registered_cb = cb;
00370 }
00371 
00372 void SimpleMbedCloudClient::on_unregistered(Callback<void()> cb) {
00373     _unregistered_cb = cb;
00374 }
00375 
00376 void SimpleMbedCloudClient::on_update_authorized(void (*cb)(int32_t request)) {
00377     _cloud_client.set_update_authorize_handler(cb);
00378 }
00379 
00380 void SimpleMbedCloudClient::on_update_progress(void (*cb)(uint32_t progress, uint32_t total)) {
00381     _cloud_client.set_update_progress_handler(cb);
00382 }
00383 
00384 void SimpleMbedCloudClient::on_error_cb(Callback<void(int, const char*)> cb) {
00385     _error_cb = cb;
00386 }
00387 
00388 int SimpleMbedCloudClient::reformat_storage() {
00389     return _storage.reformat_storage();
00390 }
00391 
00392 MbedCloudClient *SimpleMbedCloudClient::get_cloud_client() {
00393     return &_cloud_client;
00394 }
00395 
00396 MbedCloudClientResource* SimpleMbedCloudClient::create_resource(const char *path, const char *name) {
00397     MbedCloudClientResource *resource = new MbedCloudClientResource(this, path, name);
00398     _resources.push_back(resource);
00399     return resource;
00400 }
00401 
00402 int SimpleMbedCloudClient::reset_storage() {
00403     tr_info("Resetting storage to an empty state...");
00404     int status = fcc_storage_delete();
00405     if (status != FCC_STATUS_SUCCESS) {
00406         tr_debug("Failed to delete FCC storage (%d), formatting...", status);
00407 
00408         status = _storage.reformat_storage();
00409         if (status == 0) {
00410             tr_debug("Storage reformatted, resetting storage again...");
00411             // Try to reset storage again after format.
00412             // It is required to run fcc_storage_delete() after format.
00413             status = fcc_storage_delete();
00414             if (status != FCC_STATUS_SUCCESS) {
00415                 tr_warn("Failed to delete FCC storage (again) (%d)", status);
00416             }
00417             else {
00418                 tr_debug("Deleted FCC storage");
00419             }
00420         }
00421     }
00422 
00423     if (status == FCC_STATUS_SUCCESS) {
00424         tr_info("OK - Reset storage to an empty state...");
00425     }
00426 
00427     return status;
00428 }
00429 
00430 int SimpleMbedCloudClient::verify_cloud_configuration(bool format) {
00431     int status;
00432 
00433 #if MBED_CONF_DEVICE_MANAGEMENT_DEVELOPER_MODE == 1
00434     tr_debug("Starting developer flow");
00435     if( format ) {
00436         status = reset_storage();
00437         if (status != FCC_STATUS_SUCCESS) {
00438             tr_debug("Failed to reset storage");
00439             return status;
00440         }
00441     }
00442     status = fcc_developer_flow();
00443     if (status == FCC_STATUS_KCM_FILE_EXIST_ERROR) {
00444         tr_debug("Developer credentials already exist on storage layer, verifying credentials...");
00445     } else if (status != FCC_STATUS_SUCCESS) {
00446         tr_debug("No developer credentials on storage layer yet");
00447         return status;
00448     }
00449 #endif
00450     status = fcc_verify_device_configured_4mbed_cloud();
00451     return status;
00452 }