Sebastián Pastor / EtheriosCloudConnector
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers layer.h Source File

layer.h

00001 /*
00002  * Copyright (c) 2013 Digi International Inc.,
00003  * All rights not expressly granted are reserved.
00004  *
00005  * This Source Code Form is subject to the terms of the Mozilla Public
00006  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
00007  * You can obtain one at http://mozilla.org/MPL/2.0/.
00008  *
00009  * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
00010  * =======================================================================
00011  */
00012 
00013 
00014 #define MANDATORY_FACILITY          (connector_request_id_config_t)-1
00015 
00016 #define SET_FACILITY_SUPPORT(i) (UINT32_C(0x01) << (i))
00017 #define IS_FACILITY_SUPPORTED(connector_ptr, table_index)    (connector_ptr->edp_data.facilities.supported_mask & SET_FACILITY_SUPPORT(table_index))
00018 
00019 typedef connector_status_t (* connector_facility_service_init_cb_t)(struct connector_data * const connector_ptr, unsigned int const facility_index);
00020 typedef connector_status_t (* connector_facility_service_delete_cb_t)(struct connector_data * const connector_ptr);
00021 typedef connector_status_t (* connector_facility_service_process_cb_t )(struct connector_data * const connector_ptr,
00022                                                                  void * const facility_data,
00023                                                                  uint8_t * const packet,
00024                                                                  unsigned int * const receive_timeout);
00025 
00026 typedef struct {
00027     connector_request_id_t request_id;
00028     connector_facility_service_init_cb_t init_cb;
00029     connector_facility_service_delete_cb_t delete_cb;
00030     connector_facility_service_delete_cb_t cleanup_cb;
00031     connector_facility_service_process_cb_t discovery_cb;
00032     connector_facility_service_process_cb_t process_cb;
00033 } connector_facility_service_t;
00034 
00035 /* Table of all supported facilities.
00036  *
00037  * The connector will call the callback to see whether it supports each optional facility.
00038  * It will call init_cb to initialize the facility and delete_cb to remove the facility.
00039  * The init_cb must call add_facility_data() to add the facility into the facility list.
00040  * The delete_cb is called to delete the facility from the facility list when user terminates the connector.
00041  */
00042 static connector_facility_service_t const connector_supported_service_table[] = {
00043         /* mandatory facilities */
00044         {{MANDATORY_FACILITY}, connector_facility_cc_init, connector_facility_cc_delete, connector_facility_cc_cleanup, cc_discovery, cc_process},
00045 
00046         /* list of optional facilities */
00047 #if (defined CONNECTOR_FIRMWARE_SERVICE) || (defined CONNECTOR_RCI_SERVICE)
00048     #if (defined CONNECTOR_FIRMWARE_SUPPORT) || (defined CONNECTOR_RCI_SERVICE)
00049         {{MANDATORY_FACILITY}, connector_facility_firmware_init, connector_facility_firmware_delete, NULL, fw_discovery, fw_process},
00050     #else
00051         {{connector_request_id_config_firmware_facility}, connector_facility_firmware_init, connector_facility_firmware_delete, NULL, fw_discovery, fw_process},
00052     #endif
00053 #endif
00054 #if (defined CONNECTOR_DATA_SERVICE)
00055     #if (defined CONNECTOR_DATA_SERVICE_SUPPORT)
00056         {{MANDATORY_FACILITY}, connector_facility_data_service_init, connector_facility_data_service_delete, connector_facility_data_service_cleanup, msg_discovery, msg_process},
00057     #else
00058         {{connector_request_id_config_data_service}, connector_facility_data_service_init, connector_facility_data_service_delete, connector_facility_data_service_cleanup, msg_discovery, msg_process},
00059     #endif
00060 #endif
00061 #if (defined CONNECTOR_FILE_SYSTEM)
00062     #if (defined CONNECTOR_FILE_SYSTEM_SUPPORT)
00063         {{MANDATORY_FACILITY}, connector_facility_file_system_init, connector_facility_file_system_delete, connector_facility_file_system_cleanup, msg_discovery, msg_process},
00064     #else
00065         {{connector_request_id_config_file_system}, connector_facility_file_system_init, connector_facility_file_system_delete, connector_facility_file_system_cleanup, msg_discovery, msg_process},
00066     #endif
00067 #endif
00068 
00069 #if (defined CONNECTOR_RCI_SERVICE)
00070     #if (defined CONNECTOR_REMOTE_CONFIGURATION_SUPPORT)
00071         {{MANDATORY_FACILITY}, connector_facility_rci_service_init, connector_facility_rci_service_delete, connector_facility_rci_service_cleanup, msg_discovery, msg_process}
00072     #else
00073         {{connector_request_id_config_remote_configuration}, connector_facility_rci_service_init, connector_facility_rci_service_delete, connector_facility_rci_service_cleanup, msg_discovery, msg_process}
00074     #endif
00075 #endif
00076 };
00077 
00078 static size_t const connector_facility_count = asizeof(connector_supported_service_table);
00079 
00080 
00081 static connector_status_t layer_remove_facilities(connector_data_t * const connector_ptr, connector_supported_facility_cb_index_t cb_index)
00082 {
00083     connector_status_t result = connector_idle;
00084     size_t i;
00085 
00086     for (i=0; (i < connector_facility_count) && ((result == connector_idle) || (result == connector_working)); i++)
00087     {
00088         if (IS_FACILITY_SUPPORTED(connector_ptr,i))
00089         {
00090             switch (cb_index)
00091             {
00092             case facility_callback_delete:
00093                 if (connector_supported_service_table[i].delete_cb != NULL)
00094                 {
00095                     result = connector_supported_service_table[i].delete_cb(connector_ptr);
00096                 }
00097                 break;
00098             case facility_callback_cleanup:
00099                 if (connector_supported_service_table[i].cleanup_cb != NULL)
00100                 {
00101                     result = connector_supported_service_table[i].cleanup_cb(connector_ptr);
00102                 }
00103                 break;
00104             }
00105             ASSERT(result != connector_pending);
00106         }
00107     }
00108     return result;
00109 }
00110 
00111 
00112 
00113 static connector_status_t layer_discovery_facility(connector_data_t * const connector_ptr)
00114 {
00115     connector_status_t result = connector_idle;
00116     connector_facility_t * fac_ptr;
00117 
00118     /* invoke any facility that needs to send any message to Device Cloud
00119      * during initialization phase at discovery layer.
00120      */
00121     fac_ptr = (connector_ptr->edp_data.facilities.current == NULL)? connector_ptr->edp_data.facilities.list: connector_ptr->edp_data.facilities.current;
00122 
00123     for (;fac_ptr != NULL && result == connector_idle; fac_ptr = fac_ptr->next)
00124     {
00125         unsigned int const i = fac_ptr->service_index;
00126 
00127         if (connector_supported_service_table[i].discovery_cb != NULL)
00128         {   /* function to send facility discovery */
00129             result = connector_supported_service_table[i].discovery_cb(connector_ptr, fac_ptr->facility_data,
00130                                                                    NULL, &connector_ptr->edp_data.receive_packet.timeout);
00131             connector_ptr->edp_data.facilities.current = (result == connector_pending) ? fac_ptr : fac_ptr->next;
00132         }
00133     }
00134 
00135     if (result == connector_working || result == connector_idle)
00136     {
00137         if (connector_ptr->edp_data.facilities.current == NULL)
00138         {
00139             /* done all facilities */
00140             result = connector_working;
00141         }
00142         else if (result == connector_working)
00143         {
00144             /* continue next facility */
00145             result = connector_idle;
00146         }
00147     }
00148     return result;
00149 }
00150 
00151 
00152 static connector_status_t edp_layer_get_supported_facilities(connector_data_t * const connector_ptr)
00153 {
00154 #define NUMBER_FACILITY_PER_BYTE CHAR_BIT
00155     connector_status_t result = connector_working;
00156     unsigned int i;
00157 
00158     connector_ptr->edp_data.facilities.supported_mask = 0;
00159 
00160     ASSERT(CHAR_BIT == 8);
00161     ASSERT(connector_facility_count <= (sizeof connector_ptr->edp_data.facilities.supported_mask * NUMBER_FACILITY_PER_BYTE));
00162 
00163     /* connector_supported_service_table[] table includes a list of supported facilities.
00164      * Call callback to see which facility is supported.
00165      */
00166 
00167     for (i=0; i < connector_facility_count; i++)
00168     {
00169         connector_request_id_t const request_id = connector_supported_service_table[i].request_id;
00170         connector_config_supported_t config_status;
00171 
00172         config_status.supported = connector_bool(request_id.config_request == MANDATORY_FACILITY);
00173 
00174         if (request_id.config_request != MANDATORY_FACILITY)
00175         {   /* this is optional facility so ask application whether it supports this facility */
00176             connector_callback_status_t status;
00177 
00178             status = connector_callback(connector_ptr->callback, connector_class_id_config, request_id, &config_status);
00179             switch (status)
00180             {
00181             case connector_callback_busy:
00182                 /* not allowed to returned busy */
00183                 connector_debug_printf("edp_layer_get_supported_facilities: callback returns connector_callback_busy which is not allowed\n");
00184                 result = connector_abort;
00185                 goto error;
00186             case connector_callback_abort:
00187             case connector_callback_error:
00188                 result = connector_abort;
00189                 goto done;
00190             case connector_callback_unrecognized:
00191                 config_status.supported = connector_false;
00192                 break;
00193             case connector_callback_continue:
00194                 break;
00195             }
00196         }
00197 
00198         switch (config_status.supported)
00199         {
00200         case connector_true:
00201             connector_ptr->edp_data.facilities.supported_mask |= (uint16_t)SET_FACILITY_SUPPORT(i);
00202             break;
00203         case connector_false:
00204             break;
00205         default:
00206             result = connector_invalid_data_range;
00207             goto error;
00208         }
00209 
00210     }
00211 
00212 error:
00213     if (result != connector_working)
00214     {
00215         connector_request_id_t const request_id = connector_supported_service_table[i].request_id;
00216         if (notify_error_status(connector_ptr->callback, connector_class_id_config, request_id, result) != connector_working)
00217             result = connector_abort;
00218     }
00219 
00220 done:
00221     return result;
00222 }
00223 
00224 static connector_status_t edp_layer_initialize_facilities(connector_data_t * const connector_ptr)
00225 {
00226     connector_status_t result = connector_working;
00227     size_t  i;
00228 
00229     for (i=0; i < connector_facility_count; i++)
00230     {
00231         if (IS_FACILITY_SUPPORTED(connector_ptr,i) &&
00232            connector_supported_service_table[i].init_cb != NULL)
00233         {
00234             result = connector_supported_service_table[i].init_cb(connector_ptr, i);
00235             if ( result != connector_working) goto done;
00236         }
00237     }
00238 
00239     {
00240         connector_facility_t * fac_ptr;
00241         /* initialize packet pointer for each facility */
00242         for (fac_ptr = connector_ptr->edp_data.facilities.list; fac_ptr != NULL; fac_ptr = fac_ptr->next)
00243         {
00244             fac_ptr->packet_buffer = NULL;
00245         }
00246     }
00247 
00248 done:
00249     return result;
00250 }
00251 
00252 static connector_status_t layer_facility_process(connector_data_t * const connector_ptr)
00253 {
00254     connector_status_t result = connector_idle;
00255     connector_facility_t * fac_ptr;
00256 
00257 
00258     /* Invoke facility process.
00259      *
00260      * Run all facilities. But each starting facility
00261      * will be alternated.
00262      */
00263     fac_ptr = (connector_ptr->edp_data.facilities.current != NULL) ? connector_ptr->edp_data.facilities.current : connector_ptr->edp_data.facilities.list;
00264     connector_ptr->edp_data.facilities.current = fac_ptr;
00265     do
00266     {
00267         /* We want to run all facilities processes */
00268         unsigned int const i = fac_ptr->service_index;
00269 
00270         if (connector_supported_service_table[i].process_cb)
00271         {
00272             uint8_t * const packet = (fac_ptr->packet_buffer != NULL) ? fac_ptr->packet_buffer->buffer: NULL;
00273 
00274             result = connector_supported_service_table[i].process_cb(connector_ptr, fac_ptr->facility_data,
00275                                                                  packet, &connector_ptr->edp_data.receive_packet.timeout);
00276 
00277             if (result != connector_pending && result != connector_active && fac_ptr->packet_buffer != NULL)
00278             {   /* release the packet when it's done */
00279                 tcp_release_receive_packet(connector_ptr, fac_ptr->packet_buffer);
00280                 fac_ptr->packet_buffer = NULL;
00281             }
00282             fac_ptr = (fac_ptr->next != NULL) ? fac_ptr->next : connector_ptr->edp_data.facilities.list;
00283         }
00284 
00285     } while (result == connector_idle && fac_ptr != connector_ptr->edp_data.facilities.current);
00286 
00287     /* setup next starting facility process */
00288     connector_ptr->edp_data.facilities.current = (connector_ptr->edp_data.facilities.current != NULL) ? connector_ptr->edp_data.facilities.current->next : connector_ptr->edp_data.facilities.list;
00289 
00290     if (result == connector_abort) edp_set_close_status(connector_ptr, connector_close_status_abort);
00291 
00292     return result;
00293 }
00294