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

« Back to documentation index

Show/hide line numbers connector_sm.h Source File

connector_sm.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 #include "connector_sm_utils.h"
00013 #include "connector_sm_cmd.h"
00014 #include "connector_sm_session.h"
00015 #include "connector_sm_send.h"
00016 #include "connector_sm_recv.h"
00017 
00018 static connector_sm_data_t * get_sm_data(connector_data_t * const connector_ptr, connector_transport_t const transport)
00019 {
00020     connector_sm_data_t * sm_ptr = NULL;
00021 
00022     switch (transport)
00023     {
00024         #if (defined CONNECTOR_TRANSPORT_UDP)
00025         case connector_transport_udp:
00026             sm_ptr = &connector_ptr->sm_udp;
00027             break;
00028         #endif
00029 
00030         #if (defined CONNECTOR_TRANSPORT_SMS)
00031         case connector_transport_sms:
00032             sm_ptr = &connector_ptr->sm_sms;
00033             break;
00034         #endif
00035 
00036         default:
00037             ASSERT(connector_false);
00038             break;
00039     }
00040 
00041     return sm_ptr;
00042 }
00043 
00044 static connector_status_t sm_initialize(connector_data_t * const connector_ptr, connector_transport_t const transport)
00045 {
00046     connector_status_t result = connector_init_error;
00047     connector_sm_data_t * const sm_ptr = get_sm_data(connector_ptr, transport);
00048 
00049     ASSERT_GOTO(sm_ptr != NULL, error);
00050     switch (transport)
00051     {
00052         #if (defined CONNECTOR_TRANSPORT_UDP)
00053         case connector_transport_udp:
00054         {
00055             size_t const sm_udp_version_length = 1;
00056 
00057             sm_ptr->transport.id_type = connector_sm_id_type_device_id;
00058             sm_ptr->transport.id = connector_ptr->device_id;
00059             sm_ptr->transport.id_length = DEVICE_ID_LENGTH;
00060 
00061             sm_ptr->network.class_id = connector_class_id_network_udp;
00062             sm_ptr->network.transport = connector_transport_udp;
00063             sm_ptr->transport.mtu = SM_PACKET_SIZE_UDP;
00064             sm_ptr->transport.sm_mtu_tx = sm_ptr->transport.mtu - (sm_ptr->transport.id_length + sm_udp_version_length);
00065             sm_ptr->transport.sm_mtu_rx = sm_ptr->transport.sm_mtu_tx;
00066             break;
00067         }
00068         #endif
00069 
00070         #if (defined CONNECTOR_TRANSPORT_SMS)
00071         case connector_transport_sms:
00072         {
00073             #if (defined CONNECTOR_CLOUD_SERVICE_ID)
00074             static uint8_t service_id[] = CONNECTOR_CLOUD_SERVICE_ID;
00075             size_t const service_id_length = sizeof service_id -1;
00076             #else
00077             size_t service_id_length = connector_ptr->device_cloud_service_id_length;
00078             char * service_id = connector_ptr->device_cloud_service_id;
00079             #endif
00080 
00081             if (service_id_length)
00082             {
00083                 sm_ptr->transport.id_type = connector_sm_id_type_service_id;
00084                 sm_ptr->transport.id = (uint8_t *)service_id;
00085                 sm_ptr->transport.id_length = service_id_length;
00086             }
00087             else
00088             {
00089                 /* No shared codes used */
00090                 sm_ptr->transport.id_type = connector_sm_id_type_none;
00091                 sm_ptr->transport.id_length = 0;
00092             }
00093 
00094             sm_ptr->network.class_id = connector_class_id_network_sms;
00095             sm_ptr->network.transport = connector_transport_sms;
00096             sm_ptr->transport.mtu = SM_PACKET_SIZE_SMS_ENCODED;
00097             {
00098                 if ((sm_ptr->transport.id != NULL) && (sm_ptr->transport.id_length > 0))
00099                 {
00100                     /* Preamble is NOT encoded85, so for a service-id like 'idgp': */
00101                     /*
00102                        For Tx: 'idgp '
00103                                There is room for 160-5=155 not encoded85 characters. After encoding, that will lead to a max payload of 155*4/5=124 bytes.
00104                      */
00105                     sm_ptr->transport.sm_mtu_tx = (((sm_ptr->transport.mtu - (sm_ptr->transport.id_length + SMS_SERVICEID_WRAPPER_TX_SIZE))*4) / 5);
00106                     /*
00107                        For Rx: '(idgp):'
00108                                There is room for 160-7=153 not encoded85 characters. After encoding, that will lead to a max payload of 153*4/5=122 bytes.
00109                      */
00110 
00111                     sm_ptr->transport.sm_mtu_rx = (((sm_ptr->transport.mtu - (sm_ptr->transport.id_length + SMS_SERVICEID_WRAPPER_RX_SIZE))*4) / 5);
00112                 }
00113                 else
00114                 {
00115                     sm_ptr->transport.sm_mtu_tx = ((sm_ptr->transport.mtu *4) / 5);
00116                     sm_ptr->transport.sm_mtu_rx = sm_ptr->transport.sm_mtu_tx;
00117                 }
00118             }
00119             break;
00120         }
00121         #endif
00122 
00123         default:
00124             ASSERT_GOTO(connector_false, error);
00125             break;
00126     }
00127 
00128     sm_ptr->transport.state = connector_transport_idle;
00129     sm_ptr->pending.data = NULL;
00130     sm_ptr->session.head = NULL;
00131     sm_ptr->session.tail = NULL;
00132     sm_ptr->session.current = NULL;
00133     #if (defined CONNECTOR_SM_MAX_SESSIONS)
00134     sm_ptr->session.max_sessions = CONNECTOR_SM_MAX_SESSIONS;
00135     #else
00136     sm_ptr->session.max_sessions = 2;
00137     #endif
00138     sm_ptr->session.active_client_sessions = 0;
00139     sm_ptr->session.active_cloud_sessions = 0;
00140 
00141     #if (defined CONNECTOR_SM_MAX_RX_SEGMENTS) && (CONNECTOR_SM_MAX_RX_SEGMENTS > 1) && (!defined CONNECTOR_SM_MULTIPART)
00142     #error "You must define CONNECTOR_SM_MULTIPART in order to set CONNECTOR_SM_MAX_RX_SEGMENTS bigger than 1"
00143     #endif
00144 
00145     #if (defined CONNECTOR_SM_MAX_DATA_POINTS_SEGMENTS) && (CONNECTOR_SM_MAX_DATA_POINTS_SEGMENTS > 1) && (!defined CONNECTOR_SM_MULTIPART)
00146     #error "You must define CONNECTOR_SM_MULTIPART in order to set CONNECTOR_SM_MAX_DATA_POINTS_SEGMENTS bigger than 1"
00147     #endif
00148 
00149     #if (defined CONNECTOR_SM_MAX_RX_SEGMENTS)
00150     sm_ptr->session.max_segments = CONNECTOR_SM_MAX_RX_SEGMENTS;
00151     #else
00152     sm_ptr->session.max_segments = 1;
00153     #endif
00154     #if (defined CONNECTOR_SM_TIMEOUT)
00155     sm_ptr->timeout_in_seconds = CONNECTOR_SM_TIMEOUT;
00156     #else
00157     sm_ptr->timeout_in_seconds = SM_WAIT_FOREVER;
00158     #endif
00159     sm_ptr->network.handle = NULL;
00160     sm_ptr->close.status = connector_close_status_device_error;
00161     sm_ptr->close.callback_needed = connector_true;
00162     sm_ptr->close.stop_condition = connector_stop_immediately;
00163 
00164     switch (transport)
00165     {
00166         #if (defined CONNECTOR_TRANSPORT_UDP)
00167         case connector_transport_udp:
00168         {
00169 #if !(defined CONNECTOR_NETWORK_UDP_START)
00170             {
00171                 connector_config_connect_type_t config_connect;
00172 
00173                 result = get_config_connect_status(connector_ptr, connector_request_id_config_network_udp, &config_connect);
00174                 ASSERT_GOTO(result == connector_working, error);
00175 
00176                 sm_ptr->transport.connect_type = config_connect.type;
00177             }
00178 #else
00179             ASSERT((CONNECTOR_NETWORK_UDP_START == connector_connect_auto) || (CONNECTOR_NETWORK_UDP_START == connector_connect_manual));
00180             sm_ptr->transport.connect_type = CONNECTOR_NETWORK_UDP_START;
00181             result = connector_working;
00182 #endif
00183             break;
00184         }
00185         #endif
00186 
00187         #if (defined CONNECTOR_TRANSPORT_SMS)
00188         case connector_transport_sms:
00189         {
00190 #if !(defined CONNECTOR_NETWORK_SMS_START)
00191             {
00192                 connector_config_connect_type_t config_connect;
00193 
00194                 result = get_config_connect_status(connector_ptr, connector_request_id_config_network_sms, &config_connect);
00195                 ASSERT_GOTO(result == connector_working, error);
00196 
00197                 sm_ptr->transport.connect_type = config_connect.type;
00198             }
00199 #else
00200             ASSERT((CONNECTOR_NETWORK_SMS_START == connector_connect_auto) || (CONNECTOR_NETWORK_SMS_START == connector_connect_manual));
00201             sm_ptr->transport.connect_type = CONNECTOR_NETWORK_SMS_START;
00202             result = connector_working;
00203 #endif
00204             break;
00205         }
00206         #endif
00207 
00208         default:
00209             ASSERT_GOTO(connector_false, error);
00210             break;
00211     }
00212 
00213 error:
00214     return result;
00215 }
00216 
00217 static connector_status_t connector_sm_init(connector_data_t * const connector_ptr)
00218 {
00219     connector_status_t status;
00220 
00221     connector_ptr->last_request_id = SM_DEFAULT_REQUEST_ID;
00222 
00223     #if (defined CONNECTOR_TRANSPORT_UDP)
00224     status = sm_initialize(connector_ptr, connector_transport_udp);
00225     ASSERT_GOTO(status == connector_working, error);
00226     #endif
00227 
00228     #if (defined CONNECTOR_TRANSPORT_SMS)
00229     status = sm_initialize(connector_ptr, connector_transport_sms);
00230     ASSERT_GOTO(status == connector_working, error);
00231     #endif
00232 
00233 error:
00234     return status;
00235 }
00236 
00237 #if (CONNECTOR_VERSION >= 0x02010000)
00238 /* Return request_data's request_id field. This varies depending on the request. If this can't be done, set request_id to NULL */
00239 static uint32_t * get_request_id_ptr(connector_initiate_request_t const request, void const * const request_data)
00240 {
00241     uint32_t * request_id;
00242     switch (request)
00243     {
00244 #if (defined CONNECTOR_DATA_POINTS)
00245         case connector_initiate_data_point_single:
00246         {
00247             connector_request_data_point_single_t const * const data = request_data;
00248 
00249             request_id = data->request_id;
00250             break;
00251         }
00252         case connector_initiate_data_point_binary:
00253         {
00254             connector_request_data_point_binary_t const * const data = request_data;
00255 
00256             request_id = data->request_id;
00257             break;
00258         }
00259 #endif
00260 #if (defined CONNECTOR_DATA_SERVICE)
00261         case connector_initiate_send_data:
00262         {
00263             connector_request_data_service_send_t const * const data = request_data;
00264 
00265             request_id = data->request_id;
00266             break;
00267          }
00268 #endif
00269         case connector_initiate_ping_request:
00270         {
00271             connector_sm_send_ping_request_t const * const data = request_data;
00272 
00273             request_id = data->request_id;
00274             break;
00275         }
00276         default:
00277             request_id = NULL;
00278             break;
00279     }
00280 
00281     return request_id;
00282 }
00283 #endif
00284 
00285 static connector_status_t sm_initiate_action(connector_handle_t const handle, connector_initiate_request_t const request, void const * const request_data)
00286 {
00287     connector_status_t result = connector_service_busy;
00288     connector_data_t * const connector_ptr = (connector_data_t *)handle;
00289     connector_transport_t const * const transport_ptr = request_data;
00290 
00291     ASSERT_GOTO(handle != NULL, error);
00292     ASSERT_GOTO((request_data != NULL) || (request == connector_initiate_terminate), error);
00293 
00294     switch (request)
00295     {
00296         case connector_initiate_transport_start:
00297         {
00298             connector_sm_data_t * const sm_ptr = get_sm_data(connector_ptr, *transport_ptr);
00299 
00300             ASSERT_GOTO(sm_ptr != NULL, error);
00301             switch (sm_ptr->transport.state)
00302             {
00303                 case connector_transport_idle:
00304                 case connector_transport_close:
00305                     break;
00306 
00307                 case connector_transport_terminate:
00308                     result = connector_device_terminated;
00309                     goto error;
00310 
00311                 default:
00312                     goto done;
00313             }
00314 
00315             if (sm_ptr->pending.data != NULL) goto error;
00316             sm_ptr->pending.data = &sm_ptr->close.stop_condition; /* dummy */
00317             sm_ptr->pending.request = request;
00318             break;
00319         }
00320 
00321         case connector_initiate_terminate:
00322             if (transport_ptr == NULL)
00323             {
00324                 connector_transport_t transport;
00325 
00326                 #if (defined CONNECTOR_TRANSPORT_UDP)
00327                 transport = connector_transport_udp;
00328                 result = sm_initiate_action(handle, request, &transport); /* intended recursive */
00329                 if (result != connector_success) goto error;
00330                 #endif
00331 
00332                 #if (defined CONNECTOR_TRANSPORT_SMS)
00333                 transport = connector_transport_sms;
00334                 result = sm_initiate_action(handle, request, &transport); /* intended recursive */
00335                 if (result != connector_success) goto error;
00336                 #endif
00337             }
00338             else
00339             {
00340                 connector_sm_data_t * const sm_ptr = get_sm_data(connector_ptr, *transport_ptr);
00341 
00342                 ASSERT_GOTO(sm_ptr != NULL, error);
00343                 if (sm_ptr->transport.state != connector_transport_terminate)
00344                 {
00345                     sm_ptr->transport.state = connector_transport_close;
00346                     sm_ptr->close.callback_needed = connector_false;
00347                     sm_ptr->close.status = connector_close_status_device_terminated;
00348                 }
00349             }
00350             break;
00351 
00352         case connector_initiate_transport_stop:
00353             if (*transport_ptr == connector_transport_all)
00354             {
00355                 connector_initiate_stop_request_t stop_request;
00356 
00357                 memcpy(&stop_request, request_data, sizeof stop_request);
00358                 #if (defined CONNECTOR_TRANSPORT_UDP)
00359                 stop_request.transport = connector_transport_udp;
00360                 result = sm_initiate_action(handle, request, &stop_request); /* intended recursive */
00361                 if (result == connector_success)
00362                 {
00363                     connector_sm_data_t * const sm_ptr = get_sm_data(connector_ptr, connector_transport_udp);
00364 
00365                     sm_ptr->close.callback_needed = connector_false;
00366                 }
00367                 else
00368                     goto error;
00369                 #endif
00370 
00371                 #if (defined CONNECTOR_TRANSPORT_SMS)
00372                 stop_request.transport = connector_transport_sms;
00373                 result = sm_initiate_action(handle, request, &stop_request); /* intended recursive */
00374                 if (result == connector_success)
00375                 {
00376                     connector_sm_data_t * const sm_ptr = get_sm_data(connector_ptr, connector_transport_sms);
00377 
00378                     sm_ptr->close.callback_needed = connector_false;
00379                 }
00380                 else
00381                     goto error;
00382                 #endif
00383             }
00384             else
00385             {
00386                 connector_initiate_stop_request_t const * const stop_ptr = request_data;
00387                 connector_sm_data_t * const sm_ptr = get_sm_data(connector_ptr, stop_ptr->transport);
00388 
00389                 ASSERT_GOTO(sm_ptr != NULL, error);
00390                 switch (sm_ptr->transport.state)
00391                 {
00392                     case connector_transport_terminate:
00393                         result = connector_device_terminated;
00394                         goto error;
00395 
00396                     case connector_transport_close:
00397                         result = connector_service_busy;
00398                         goto error;
00399 
00400                     default:
00401                     {
00402                         connector_initiate_stop_request_t const * const stop_request = request_data;
00403 
00404                         sm_ptr->close.status = connector_close_status_device_stopped;
00405                         sm_ptr->close.user_context = stop_ptr->user_context;
00406                         sm_ptr->close.stop_condition = stop_request->condition;
00407                         if ((stop_request->condition == connector_stop_immediately) || (sm_ptr->session.head == NULL))
00408                             sm_ptr->transport.state = connector_transport_close;
00409                         break;
00410                     }
00411                 }
00412             }
00413 
00414             break;
00415 
00416         case connector_initiate_session_cancel:
00417 #if (CONNECTOR_VERSION >= 0x02010000)
00418         case connector_initiate_session_cancel_all:
00419 #endif
00420         {
00421             connector_sm_data_t * const sm_ptr = get_sm_data(connector_ptr, *transport_ptr);
00422             
00423             ASSERT_GOTO(sm_ptr != NULL, error);
00424 
00425             if (sm_ptr->close.stop_condition == connector_wait_sessions_complete)
00426             {
00427                 result = connector_unavailable;
00428                 goto error;
00429             }
00430 
00431             if (sm_ptr->pending.data != NULL)
00432                 goto error;
00433 
00434             sm_ptr->pending.data = request_data;
00435             sm_ptr->pending.request = request;
00436             sm_ptr->pending.pending_internal = connector_false;
00437             break;
00438         }
00439 
00440         case connector_initiate_ping_request:
00441 #if (defined CONNECTOR_DATA_SERVICE)
00442         case connector_initiate_send_data:
00443 #endif
00444 #if (defined CONNECTOR_DATA_POINTS)
00445         case connector_initiate_data_point_binary:
00446         case connector_initiate_data_point_single:
00447 #endif
00448         {
00449             connector_sm_data_t * const sm_ptr = get_sm_data(connector_ptr, *transport_ptr);
00450 
00451             ASSERT_GOTO(sm_ptr != NULL, error);
00452 
00453             if (sm_ptr->close.stop_condition == connector_wait_sessions_complete)
00454             {
00455                 result = connector_unavailable;
00456                 goto error;
00457             }
00458 
00459             switch (sm_ptr->transport.state)
00460             {
00461                 case connector_transport_idle:
00462                 case connector_transport_open:
00463                 case connector_transport_close:
00464                 case connector_transport_terminate:
00465                 case connector_transport_wait_for_reconnect:
00466                     result = connector_unavailable;
00467                     goto error;
00468                 case connector_transport_send:
00469                 case connector_transport_receive:
00470                 case connector_transport_redirect:
00471                 {
00472 #if (CONNECTOR_VERSION >= 0x02010000)
00473                     uint32_t * request_id = NULL;
00474 #endif
00475                     if (sm_ptr->close.stop_condition == connector_wait_sessions_complete)
00476                     {
00477                         result = connector_unavailable;
00478                         goto error;
00479                     }
00480 #if (CONNECTOR_VERSION >= 0x02010000)
00481                     request_id = get_request_id_ptr(request, request_data);
00482                     /* dp_initiate_data_point_single/binary() convert a connector_initiate_data_point_single/binary
00483                      * to a connector_initiate_send_data, but we want that that "hidden" connector_initiate_send_data
00484                      * use the same request_id, which has been already set by dp_send_message().
00485                      * */
00486                     if (sm_ptr->pending.pending_internal)
00487                     {
00488                         sm_ptr->pending.pending_internal = connector_false;
00489                         if (request_id != NULL)
00490                         {
00491                             /* Use the same request_id */
00492                             sm_ptr->pending.request_id = *request_id;
00493                         }
00494                         else
00495                         {
00496                             /* Update request_id */
00497                             result = sm_get_request_id(connector_ptr, sm_ptr);
00498                             ASSERT_GOTO(result == connector_working, error);
00499                             sm_ptr->pending.request_id = connector_ptr->last_request_id;
00500                         }
00501                     }
00502                     else
00503                     {
00504                         /* Update request_id */
00505                         result = sm_get_request_id(connector_ptr, sm_ptr);
00506                         ASSERT_GOTO(result == connector_working, error);
00507                         sm_ptr->pending.request_id = connector_ptr->last_request_id;
00508                         if (request_id != NULL)
00509                             *request_id = sm_ptr->pending.request_id;
00510                     }
00511 #endif
00512 
00513 #if (defined CONNECTOR_DATA_POINTS)
00514                     switch (request)
00515                     {
00516                         case connector_initiate_data_point_single:
00517                         {
00518                             sm_ptr->pending.pending_internal = connector_true;
00519                             result = dp_initiate_data_point_single(request_data);
00520                             goto done_datapoints;
00521                         }
00522                         case connector_initiate_data_point_binary:
00523                         {
00524                             sm_ptr->pending.pending_internal = connector_true;
00525                             result = dp_initiate_data_point_binary(request_data);
00526                             goto done_datapoints;
00527                         }
00528 
00529                         default:
00530                             break;
00531                     }
00532 #endif
00533                     if (sm_ptr->pending.data != NULL)
00534                     {
00535                         result = connector_service_busy;
00536                         goto error;
00537                     }
00538                     sm_ptr->pending.data = request_data;
00539                     sm_ptr->pending.request = request;
00540                     break;
00541                 }
00542                 default:
00543                     ASSERT(connector_false);
00544                     break;
00545             }
00546             break;
00547         }
00548         default:
00549             ASSERT(connector_false);
00550             break;
00551     }
00552 
00553 done:
00554     result = connector_success;
00555 
00556 #if (defined CONNECTOR_DATA_POINTS)
00557 done_datapoints:
00558 #endif
00559 error:
00560     return result;
00561 }
00562 
00563 static void sm_init_network_packet(connector_sm_packet_t * const packet, void * const ptr)
00564 {
00565     packet->data = ptr;
00566     packet->total_bytes = 0;
00567     packet->processed_bytes = 0;
00568     packet->pending_session = NULL;
00569 }
00570 
00571 static connector_status_t sm_open_transport(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr)
00572 {
00573     connector_status_t result;
00574 
00575     {
00576         connector_callback_status_t status;
00577         connector_network_open_t open_data;
00578         connector_request_id_t request_id;
00579 
00580         switch(sm_ptr->network.class_id)
00581         {
00582             case connector_class_id_network_sms:
00583                 open_data.device_cloud_url = connector_ptr->device_cloud_phone;
00584                 break;
00585 
00586             default:
00587                 open_data.device_cloud_url = connector_ptr->device_cloud_url;
00588                 break;
00589         }
00590         open_data.handle = NULL;
00591 
00592         request_id.network_request = connector_request_id_network_open;
00593         status = connector_callback(connector_ptr->callback, sm_ptr->network.class_id, request_id, &open_data);
00594         ASSERT(status != connector_callback_unrecognized);
00595         switch (status)
00596         {
00597             case connector_callback_continue:
00598                 result = connector_working;
00599                 sm_ptr->network.handle = open_data.handle;
00600                 break;
00601 
00602             case  connector_callback_abort:
00603                 result = connector_abort;
00604                 goto error;
00605 
00606             case connector_callback_unrecognized:
00607                 result = connector_unavailable;
00608                 goto error;
00609 
00610             case connector_callback_error:
00611                 result = connector_open_error;
00612                 goto error;
00613 
00614             case connector_callback_busy:
00615                 result = connector_pending;
00616                 goto error;
00617         }
00618     }
00619 
00620     {
00621         void * data_ptr;
00622         size_t const data_size = 2 * sm_ptr->transport.mtu;
00623 
00624         result = malloc_data_buffer(connector_ptr, data_size, named_buffer_id(sm_packet), &data_ptr);
00625         ASSERT_GOTO(result == connector_working, error);
00626 
00627         {
00628             uint8_t * const send_data_ptr = data_ptr;
00629             uint8_t * const recv_data_ptr = send_data_ptr + sm_ptr->transport.mtu;
00630 
00631             sm_init_network_packet(&sm_ptr->network.send_packet, send_data_ptr);
00632             sm_init_network_packet(&sm_ptr->network.recv_packet, recv_data_ptr);
00633         }
00634     }
00635 
00636 error:
00637     return result;
00638 }
00639 
00640 static connector_status_t sm_close_transport(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr)
00641 {
00642     connector_status_t result = sm_cancel_session(connector_ptr, sm_ptr, NULL);
00643 
00644     if (result == connector_abort)
00645         sm_ptr->close.status = connector_close_status_abort;
00646 
00647     if (sm_ptr->network.handle != NULL)
00648     {
00649         connector_callback_status_t callback_status;
00650         connector_request_id_t request_id;
00651         connector_network_close_t close_data;
00652 
00653         close_data.handle = sm_ptr->network.handle;
00654         close_data.status = sm_ptr->close.status;
00655 
00656         connector_debug_printf("sm_close_transport: status %d\n", sm_ptr->close.status);
00657         request_id.network_request = connector_request_id_network_close;
00658         callback_status = connector_callback(connector_ptr->callback, sm_ptr->network.class_id, request_id, &close_data);
00659         ASSERT(callback_status != connector_callback_unrecognized);
00660         switch (callback_status)
00661         {
00662             case connector_callback_busy:
00663                 result = connector_pending;
00664                 goto done;
00665 
00666             case connector_callback_continue:
00667                 result = connector_working;
00668                 break;
00669 
00670             default:
00671                 sm_ptr->close.status = connector_close_status_abort;
00672                 break;
00673         }
00674 
00675         sm_ptr->network.handle = NULL;
00676     }
00677 
00678     if (sm_ptr->network.send_packet.data != NULL)
00679     {
00680         if (free_data_buffer(connector_ptr, named_buffer_id(sm_packet), sm_ptr->network.send_packet.data) == connector_abort)
00681             sm_ptr->close.status = connector_close_status_abort;
00682         sm_ptr->network.send_packet.data = NULL;
00683     }
00684 
00685     if (sm_ptr->close.callback_needed)
00686     {
00687         connector_transport_t const transport = sm_ptr->network.transport;
00688         connector_status_t const stop_status = connector_stop_callback(connector_ptr, transport, sm_ptr->close.user_context);
00689 
00690         switch (stop_status)
00691         {
00692             case connector_abort:
00693                 sm_ptr->close.status = connector_close_status_abort;
00694                 break;
00695 
00696             case connector_pending:
00697                 result = connector_pending;
00698                 goto done;
00699 
00700             default:
00701                 break;
00702         }
00703     }
00704 
00705     switch (sm_ptr->close.status)
00706     {
00707         case connector_close_status_abort:
00708         case connector_close_status_device_terminated:
00709             sm_ptr->transport.state = connector_transport_terminate;
00710             result = (sm_ptr->close.status == connector_close_status_device_terminated) ? connector_device_terminated : connector_abort;
00711             break;
00712 
00713         default:
00714             sm_ptr->transport.state = connector_transport_idle;
00715             sm_ptr->close.stop_condition = connector_stop_immediately;
00716             sm_ptr->close.callback_needed = connector_true;
00717             break;
00718     }
00719 
00720 done:
00721     return result;
00722 }
00723 
00724 static connector_status_t sm_state_machine(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr)
00725 {
00726     connector_status_t result = connector_idle;
00727     size_t iterations = 2;
00728 
00729     ASSERT_GOTO(sm_ptr != NULL, error);
00730 
00731     if (sm_ptr->transport.state == connector_transport_terminate)
00732     {
00733         result = connector_device_terminated;
00734         goto done;
00735     }
00736     result = sm_process_pending_data(connector_ptr, sm_ptr);
00737     if (result != connector_idle && result != connector_pending)
00738         goto done;
00739 
00740 #if (defined CONNECTOR_DATA_POINTS)
00741     result = dp_process_request(connector_ptr, sm_ptr->network.transport);
00742     if ((result != connector_idle) && (result != connector_working))
00743         goto error;
00744 #endif
00745 
00746     while (iterations > 0)
00747     {
00748         switch (sm_ptr->transport.state)
00749         {
00750             case connector_transport_idle:
00751                 if ((sm_ptr->transport.connect_type == connector_connect_auto) && (sm_ptr->close.status == connector_close_status_device_error))
00752                     sm_ptr->transport.state = connector_transport_open;
00753                 goto done;
00754 
00755             case connector_transport_open:
00756                 result = sm_open_transport(connector_ptr, sm_ptr);
00757                 switch(result)
00758                 {
00759                     case connector_working:
00760                         sm_ptr->transport.state = connector_transport_receive;
00761                         break;
00762                     case connector_pending:
00763                         sm_ptr->transport.state = connector_transport_open;
00764                         break;
00765                     case connector_open_error:
00766                     {
00767                         sm_ptr->transport.connect_at = 0;
00768                         sm_ptr->transport.state = connector_transport_wait_for_reconnect;
00769                         break;
00770                     }
00771                     default:
00772                         sm_ptr->transport.state = connector_transport_idle;
00773                         break;
00774                 }
00775                 goto done;
00776 
00777             case connector_transport_receive:
00778                 sm_ptr->transport.state = connector_transport_send;
00779                 if (sm_ptr->network.handle != NULL)    /* Give a chance to dynamic reconfiguration of the network when provisioning message arrives */
00780                     result = sm_receive_data(connector_ptr, sm_ptr); /* NOTE: sm_receive_data has precedence over sm_process_recv_path just to keep the receive buffer ready */
00781                 if ((result != connector_idle) && (result != connector_pending))
00782                     goto done;
00783                 else
00784                 {
00785                     connector_sm_session_t * session = (sm_ptr->session.current == NULL) ? sm_ptr->session.head : sm_ptr->session.current;
00786 
00787                     if (session == NULL) goto done;
00788 
00789                     do
00790                     {
00791                         if (session->sm_state >= connector_sm_state_receive_data)
00792                         {
00793                             result = sm_process_recv_path(connector_ptr, sm_ptr, session);
00794                             switch (result)
00795                             {
00796                                 case connector_working:
00797                                 case connector_pending:
00798                                     sm_ptr->session.current = session->next;
00799                                     goto done;
00800 
00801                                 case connector_idle:
00802                                     break;
00803 
00804                                 default:
00805                                     ASSERT_GOTO(connector_false, error);
00806                                     break;
00807                             }
00808                         }
00809 
00810                         session = session->next;
00811                         sm_ptr->session.current = session;
00812 
00813                     } while (session != NULL);
00814                 }
00815 
00816                 iterations--;
00817                 break;
00818 
00819             case connector_transport_send:
00820             {
00821                 connector_sm_session_t * session = (sm_ptr->session.current == NULL) ? sm_ptr->session.head : sm_ptr->session.current;
00822 
00823                 sm_ptr->transport.state = connector_transport_receive;
00824                 if (session == NULL) goto done;
00825 
00826                 do
00827                 {
00828                     if (session->sm_state <= connector_sm_state_send_data)
00829                     {
00830                         result = sm_process_send_path(connector_ptr, sm_ptr, session);
00831                         switch (result)
00832                         {
00833                             case connector_working:
00834                             case connector_pending:
00835                                 sm_ptr->session.current = session->next;
00836                                 goto done;
00837 
00838                             case connector_idle:
00839                                 break;
00840 
00841                             default:
00842                                 ASSERT_GOTO(connector_false, error);
00843                                 break;
00844                         }
00845                     }
00846 
00847                     session = session->next;
00848                     sm_ptr->session.current = session;
00849 
00850                 } while (session != NULL);
00851 
00852                 iterations--;
00853                 break;
00854             }
00855 
00856             case connector_transport_close:
00857                 result = sm_close_transport(connector_ptr, sm_ptr);
00858                 goto done;
00859 
00860             case connector_transport_terminate:
00861                 break;
00862 
00863             case connector_transport_wait_for_reconnect:
00864             {
00865                 if (sm_ptr->transport.connect_at == 0)
00866                 {
00867 #if (defined CONNECTOR_TRANSPORT_UDP) && defined CONNECTOR_TRANSPORT_SMS
00868                     connector_debug_printf("Waiting %d second before reconnecting SM transport %s\n",
00869                                  CONNECTOR_TRANSPORT_RECONNECT_AFTER, sm_ptr->network.transport == connector_transport_udp ? "UDP" : "SMS");
00870 #elif defined CONNECTOR_TRANSPORT_UDP
00871                     connector_debug_printf("Waiting %d second before reconnecting SM transport UDP\n", CONNECTOR_TRANSPORT_RECONNECT_AFTER);
00872 #else
00873                     connector_debug_printf("Waiting %d second before reconnecting SM transport SMS\n", CONNECTOR_TRANSPORT_RECONNECT_AFTER);
00874 #endif
00875                     result = get_system_time(connector_ptr, &sm_ptr->transport.connect_at);
00876                     if (result != connector_working)
00877                         goto done;
00878                     sm_ptr->transport.connect_at += CONNECTOR_TRANSPORT_RECONNECT_AFTER;
00879                 } else {
00880                     unsigned long int uptime;
00881 
00882                     result = get_system_time(connector_ptr, &uptime);
00883                     if (result != connector_working)
00884                         goto done;
00885                     if (uptime >= sm_ptr->transport.connect_at)
00886                         sm_ptr->transport.state = connector_transport_open;
00887                 }
00888                 break;
00889             }
00890             default:
00891                 ASSERT_GOTO(connector_false, error);
00892                 break;
00893         }
00894     }
00895 
00896 error:
00897 done:
00898     return result;
00899 }
00900 
00901 #if (defined CONNECTOR_TRANSPORT_UDP)
00902 static connector_status_t connector_udp_step(connector_data_t * const connector_ptr)
00903 {
00904     return sm_state_machine(connector_ptr, &connector_ptr->sm_udp);
00905 }
00906 #endif
00907 
00908 #if (defined CONNECTOR_TRANSPORT_SMS)
00909 static connector_status_t connector_sms_step(connector_data_t * const connector_ptr)
00910 {
00911     return sm_state_machine(connector_ptr, &connector_ptr->sm_sms);
00912 }
00913 #endif
00914