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

« Back to documentation index

Show/hide line numbers connector_sm_cmd.h Source File

connector_sm_cmd.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 static connector_status_t sm_copy_user_request(connector_sm_data_t * const sm_ptr, connector_sm_session_t * const session)
00013 {
00014     connector_status_t result = connector_abort;
00015     connector_bool_t response_needed;
00016 
00017     ASSERT_GOTO(sm_ptr->pending.data != NULL, error);
00018     session->bytes_processed = 0;
00019 
00020     switch (sm_ptr->pending.request)
00021     {
00022         case connector_initiate_ping_request:
00023         {
00024             connector_sm_send_ping_request_t const * const request = sm_ptr->pending.data;
00025 
00026             session->user.context = request->user_context;
00027             session->user.header = NULL;
00028             session->command = connector_sm_cmd_ping;
00029             response_needed = request->response_required;
00030             session->sm_state = connector_sm_state_prepare_segment;
00031             break;
00032         }
00033 #if (defined CONNECTOR_DATA_SERVICE)
00034         case connector_initiate_send_data:
00035         {
00036             connector_request_data_service_send_t const * const request = sm_ptr->pending.data;
00037 
00038             session->user.context = request->user_context;
00039             session->user.header = request->path;
00040             session->command = (request->path != NULL) ? connector_sm_cmd_data : connector_sm_cmd_no_path_data;
00041             response_needed = request->response_required;
00042             session->sm_state = connector_sm_state_get_total_length;
00043             #if (defined CONNECTOR_DATA_POINTS)
00044             if (request->path != NULL)
00045             {
00046                 char const dp_prefix[] = "DataPoint/";
00047                 size_t const dp_prefix_bytes = sizeof dp_prefix - 1;
00048 
00049                 if (!strncmp(request->path, dp_prefix, dp_prefix_bytes))
00050                     SmSetDatapoint(session->flags);
00051             }
00052             #endif
00053             break;
00054         }
00055 #endif
00056         default:
00057             ASSERT_GOTO(connector_false, error);
00058             break;
00059     }
00060 
00061     if (response_needed) SmSetResponseNeeded(session->flags);
00062 
00063     result = connector_working;
00064 
00065 error:
00066     return result;
00067 }
00068 
00069 static void sm_verify_result(connector_sm_data_t * const sm_ptr, connector_status_t * const result)
00070 {
00071     switch (*result)
00072     {
00073         case connector_pending:
00074         case connector_working:
00075         case connector_idle:
00076             goto done;
00077 
00078         case connector_invalid_data_size:
00079             connector_debug_printf("WARNING: received a 'connector_invalid_data_size'\n");
00080             break;
00081         case connector_abort:
00082         case connector_invalid_response:
00083             sm_ptr->close.status = connector_close_status_abort;
00084             break;
00085 
00086         default:
00087             sm_ptr->close.status = connector_close_status_device_error;
00088             break;
00089     }
00090 
00091     *result = connector_working;
00092     switch(sm_ptr->transport.state)
00093     {
00094         case connector_transport_idle:
00095         case connector_transport_close:
00096         case connector_transport_terminate:
00097             break;
00098 
00099         default:
00100             sm_ptr->transport.state = connector_transport_close;
00101             break;
00102     }
00103 
00104 done:
00105     return;
00106 }
00107 
00108 #if (defined CONNECTOR_COMPRESSION) || (defined CONNECTOR_SM_MULTIPART)
00109 static size_t sm_get_max_payload_bytes(connector_sm_data_t * const sm_ptr)
00110 {
00111     size_t const sm_header_size = 5;
00112     
00113     /* This is used for Rx path... */
00114     size_t const max_payload_bytes = sm_ptr->transport.sm_mtu_rx - sm_header_size;
00115 
00116     return max_payload_bytes;
00117 }
00118 #endif
00119 
00120 static connector_status_t sm_allocate_user_buffer(connector_data_t * const connector_ptr, sm_data_block_t * const dblock)
00121 {
00122     void * ptr = NULL;
00123     connector_status_t result = connector_working;
00124 
00125     if (dblock->bytes > 0)
00126     {
00127         ASSERT(dblock->data == NULL);
00128         result = malloc_data_buffer(connector_ptr, dblock->bytes, named_buffer_id(sm_data_block), &ptr);
00129     }
00130 
00131     dblock->data = ptr;
00132 
00133     return result;
00134 }
00135 
00136 static connector_status_t sm_map_callback_status_to_connector_status(connector_callback_status_t const callback_status)
00137 {
00138     connector_status_t result;
00139 
00140     switch (callback_status)
00141     {
00142         case connector_callback_continue:
00143             result = connector_working;
00144             break;
00145 
00146         case connector_callback_busy:
00147             result = connector_pending;
00148             break;
00149 
00150         case connector_callback_error:
00151             result = connector_device_error;
00152             break;
00153 
00154         default:
00155             result = connector_abort;
00156             break;
00157     }
00158 
00159     return result;
00160 }
00161 
00162 #if (defined CONNECTOR_DATA_SERVICE)
00163 static connector_callback_status_t sm_inform_data_complete(connector_data_t * const connector_ptr, connector_sm_session_t * const session)
00164 {
00165     connector_request_id_t request_id;
00166     connector_callback_status_t callback_status;
00167     connector_data_service_status_t status_info;
00168 
00169     status_info.transport = session->transport;
00170     status_info.user_context = session->user.context;
00171     status_info.session_error = connector_session_error_none;
00172     switch (session->error)
00173     {
00174         case connector_sm_error_cancel:
00175             status_info.status = connector_data_service_status_cancel;
00176             break;
00177 
00178         case connector_sm_error_timeout:
00179             status_info.status = connector_data_service_status_timeout;
00180             break;
00181 
00182         case connector_sm_error_complete:
00183             status_info.status = connector_data_service_status_complete;
00184             break;
00185 
00186         case connector_sm_error_no_resource:
00187             status_info.session_error = connector_session_error_memory;
00188             /* no break */
00189         default:
00190             status_info.status = connector_data_service_status_session_error;
00191             break;
00192     }
00193 
00194     #if (defined CONNECTOR_DATA_POINTS)
00195     if (SmIsDatapoint(session->flags))
00196     {
00197         callback_status = dp_handle_callback(connector_ptr, connector_request_id_data_service_send_status, &status_info);
00198     }
00199     else
00200     #endif
00201     {
00202         request_id.data_service_request = SmIsClientOwned(session->flags) ? connector_request_id_data_service_send_status : connector_request_id_data_service_receive_status;
00203         callback_status = connector_callback(connector_ptr->callback, connector_class_id_data_service, request_id, &status_info);
00204     }
00205 
00206     return callback_status;
00207 }
00208 #endif
00209 
00210 #if (defined CONNECTOR_SM_CLI)
00211 static connector_callback_status_t sm_inform_cli_complete(connector_data_t * const connector_ptr, connector_sm_session_t * const session)
00212 {
00213     connector_request_id_t request_id;
00214     connector_callback_status_t callback_status;
00215     connector_sm_cli_status_t cb_data;
00216 
00217     cb_data.transport = session->transport;
00218     cb_data.user_context = session->user.context;
00219     cb_data.status = (session->error == connector_sm_error_cancel) ? connector_sm_cli_status_cancel : connector_sm_cli_status_error;
00220     request_id.sm_request = connector_request_id_sm_cli_status;
00221     callback_status = connector_callback(connector_ptr->callback, connector_class_id_short_message, request_id, &cb_data);
00222     if (callback_status == connector_callback_unrecognized)
00223         callback_status = connector_callback_error;
00224 
00225     return callback_status;
00226 }
00227 #endif
00228 
00229 static connector_callback_status_t sm_inform_ping_complete(connector_data_t * const connector_ptr, connector_sm_session_t * const session)
00230 {
00231     connector_callback_status_t callback_status = connector_callback_continue;
00232 
00233     if (SmIsClientOwned(session->flags))
00234     {
00235         connector_request_id_t request_id;
00236         connector_sm_ping_response_t cb_data;
00237 
00238         cb_data.transport = session->transport;
00239         cb_data.user_context = session->user.context;
00240         switch (session->error)
00241         {
00242             case connector_sm_error_none:
00243                 cb_data.status = connector_sm_ping_status_success;
00244                 break;
00245 
00246             case connector_sm_error_cancel:
00247                 cb_data.status = connector_sm_ping_status_cancel;
00248                 break;
00249 
00250             case connector_sm_error_timeout:
00251                 cb_data.status = connector_sm_ping_status_timeout;
00252                 break;
00253 
00254             case connector_sm_error_complete:
00255                 cb_data.status = connector_sm_ping_status_complete;
00256                 break;
00257 
00258             default:
00259                 cb_data.status = connector_sm_ping_status_error;
00260                 break;
00261         }
00262 
00263         request_id.sm_request = connector_request_id_sm_ping_response;
00264         callback_status = connector_callback(connector_ptr->callback, connector_class_id_short_message, request_id, &cb_data);
00265         if (callback_status == connector_callback_unrecognized)
00266             callback_status = connector_callback_continue;
00267     }
00268 
00269     return callback_status;
00270 }
00271 
00272 static connector_status_t sm_inform_session_complete(connector_data_t * const connector_ptr, connector_sm_session_t * const session)
00273 {
00274     connector_status_t result;
00275     connector_callback_status_t callback_status = connector_callback_continue;
00276 
00277     if (session->sm_state == connector_sm_state_complete) goto done;
00278 
00279     switch (session->command)
00280     {
00281         case connector_sm_cmd_data:
00282         case connector_sm_cmd_no_path_data:
00283 #if (defined CONNECTOR_DATA_SERVICE)
00284             callback_status = sm_inform_data_complete(connector_ptr, session);
00285 #endif
00286             break;
00287 
00288         #if (defined CONNECTOR_SM_CLI)
00289         case connector_sm_cmd_cli:
00290             callback_status = sm_inform_cli_complete(connector_ptr, session);
00291             break;
00292         #endif
00293 
00294         case connector_sm_cmd_ping:
00295             callback_status = sm_inform_ping_complete(connector_ptr, session);
00296             break;
00297 
00298         default:
00299             connector_debug_printf("sm_inform_session_complete: cancelling the session cmd [%d]\n", session->command);
00300             callback_status = connector_callback_continue;
00301             break;
00302     }
00303 
00304 done:
00305     result = sm_map_callback_status_to_connector_status(callback_status);
00306 
00307     if (session->in.data != NULL)
00308     {
00309         if (free_data_buffer(connector_ptr, named_buffer_id(sm_data_block), session->in.data) != connector_working)
00310             result = connector_abort;
00311 
00312         session->in.bytes = 0;
00313         session->in.data = NULL;
00314     }
00315 
00316     return result;
00317 }
00318 
00319 static connector_status_t sm_switch_path(connector_data_t * const connector_ptr, connector_sm_session_t * const session, connector_sm_state_t const next_state)
00320 {
00321     connector_status_t result = connector_working;
00322 
00323     if (session->in.data != NULL)
00324     {
00325         result = free_data_buffer(connector_ptr, named_buffer_id(sm_data_block), session->in.data);
00326         if (result != connector_working) goto error;
00327 
00328         session->in.bytes = 0;
00329         session->in.data = NULL;
00330     }
00331 
00332     if (SmIsResponseNeeded(session->flags))
00333     {
00334         session->sm_state = next_state;
00335         SmClearCompressed(session->flags);
00336         SmClearMultiPart(session->flags);
00337         SmSetResponse(session->flags);
00338         session->segments.processed = 0;
00339         if (session->command == connector_sm_cmd_data || session->command == connector_sm_cmd_no_path_data)
00340             SmClearResponseNeeded(session->flags); /* After the response is sent, inform the user that the session is completed */
00341     }
00342     else
00343     {
00344         if (SmIsClientOwned(session->flags) && !SmIsError(session->flags)) /* If it is an error, it has already been called by sm_handle_error() */
00345         {
00346             session->error = connector_sm_error_complete;
00347             result = sm_inform_session_complete(connector_ptr, session);
00348         }
00349 
00350         session->sm_state = connector_sm_state_complete;
00351     }
00352 
00353 error:
00354     return result;
00355 }
00356 
00357 static void sm_set_payload_process(connector_sm_session_t * const session)
00358 {
00359     size_t const zlib_header_bytes = 2;
00360 
00361     session->in.bytes = session->bytes_processed;
00362     session->sm_state = connector_sm_state_prepare_segment;
00363     session->bytes_processed = SmIsCompressed(session->flags) ? zlib_header_bytes : 0;
00364 }
00365 
00366 static void sm_set_payload_complete(connector_sm_session_t * const session)
00367 {
00368     ASSERT(session->bytes_processed <= session->in.bytes);
00369 
00370     #if (defined CONNECTOR_COMPRESSION)
00371     session->sm_state = connector_sm_state_compress;
00372     #else
00373     sm_set_payload_process(session);
00374     #endif
00375 }
00376 
00377 static void sm_set_header_complete(connector_sm_session_t * const session)
00378 {
00379     if (session->bytes_processed < session->in.bytes)
00380         session->sm_state = connector_sm_state_more_data;
00381     else
00382         sm_set_payload_complete(session);
00383 }
00384 
00385 static connector_status_t sm_prepare_data_request(connector_data_t * const connector_ptr, connector_sm_session_t * const session)
00386 {
00387     connector_status_t result = connector_abort;
00388     size_t const path_length_field_bytes = 1;
00389     char const * path = NULL;
00390     size_t path_len = 0;
00391 
00392     if (session->command == connector_sm_cmd_data)
00393     {
00394         size_t const five_bits_max_len = (1 << 5);
00395 
00396         path = session->user.header;
00397         ASSERT_GOTO(path != NULL, error);
00398         path_len = strlen(path);
00399         ASSERT_GOTO(path_len < five_bits_max_len, error);
00400         session->in.bytes += (path_length_field_bytes + path_len);
00401     }
00402 
00403     session->bytes_processed = 0;
00404     result = sm_allocate_user_buffer(connector_ptr, &session->in);
00405     if (result != connector_working)
00406     {
00407         session->error = connector_sm_error_no_resource;
00408         goto error;
00409     }
00410 
00411     if (path != NULL)
00412     {
00413         uint8_t * header = session->in.data;
00414 
00415         *header++ = path_len;
00416         memcpy(header, path, path_len);
00417         session->bytes_processed = path_length_field_bytes + path_len;
00418     }
00419 
00420     sm_set_header_complete(session);
00421 
00422 error:
00423     return result;
00424 }
00425 
00426 static connector_status_t sm_prepare_data_response(connector_data_t * const connector_ptr, connector_sm_session_t * const session)
00427 {
00428     connector_status_t const result = sm_allocate_user_buffer(connector_ptr, &session->in);
00429 
00430     if (result == connector_working)
00431     {
00432         session->bytes_processed = 0;
00433         sm_set_header_complete(session);
00434     }
00435     else
00436         session->error = connector_sm_error_no_resource;
00437 
00438     return result;
00439 }
00440 
00441 #if (defined CONNECTOR_SM_CLI)
00442 static connector_status_t sm_process_cli_request(connector_data_t * const connector_ptr, connector_sm_session_t * const session, void * const payload, size_t const bytes)
00443 {
00444     connector_status_t result = connector_abort;
00445     char * const cli_command = payload;
00446     size_t cli_bytes;
00447     connector_sm_data_t * sm_ptr = NULL;
00448 
00449     if (SmIsLastData(session->flags))
00450     {
00451         cli_bytes = strlen(cli_command) + 1; /* +1 for nul-terminate */
00452     }
00453     else
00454     {
00455         cli_bytes = bytes;
00456     }
00457 
00458     switch (session->transport)
00459     {
00460         #if (defined CONNECTOR_TRANSPORT_UDP)
00461         case connector_transport_udp:
00462             sm_ptr = &connector_ptr->sm_udp;
00463             break;
00464         #endif
00465 
00466         #if (defined CONNECTOR_TRANSPORT_SMS)
00467         case connector_transport_sms:
00468             sm_ptr = &connector_ptr->sm_sms;
00469             break;
00470         #endif
00471 
00472         default:
00473             ASSERT(connector_false);
00474             break;
00475     }
00476 
00477     if (bytes > cli_bytes)
00478     {
00479         size_t const max_response_packets = LoadBE16(cli_command + cli_bytes);
00480         size_t max_response_bytes = 0;
00481 
00482         size_t const max_payload = sm_ptr->transport.sm_mtu_tx - record_end(segment);
00483 
00484         if (max_response_packets == 0)
00485             max_response_bytes = 0;
00486         else if (max_response_packets == 1)
00487             max_response_bytes = max_payload;
00488         else
00489         {
00490             size_t const segment0_overhead_bytes = record_end(segment0) - record_end(segmentn);
00491             max_response_bytes = max_response_packets * max_payload - segment0_overhead_bytes;
00492         }
00493 
00494         session->user.header = (void *)max_response_bytes;
00495     }
00496     else
00497     {
00498         session->user.header = (void *)SIZE_MAX;
00499     }
00500 
00501     {
00502         connector_request_id_t request_id;
00503         connector_sm_cli_request_t cli_request;
00504         connector_callback_status_t callback_status;
00505 
00506         cli_request.transport = session->transport;
00507         cli_request.user_context = session->user.context;
00508         cli_request.buffer = cli_command;
00509         cli_request.bytes_used = cli_bytes;
00510         cli_request.response_required = SmIsResponseNeeded(session->flags);
00511 #if (CONNECTOR_VERSION >= 0x02010000)
00512         cli_request.more_data = SmIsNotLastData(session->flags);
00513 #endif
00514 
00515         request_id.sm_request = connector_request_id_sm_cli_request;
00516         callback_status = connector_callback(connector_ptr->callback, connector_class_id_short_message, request_id, &cli_request);
00517         if (callback_status == connector_callback_unrecognized)
00518             callback_status = connector_callback_error;
00519         result = sm_map_callback_status_to_connector_status(callback_status);
00520         if (callback_status == connector_callback_continue)
00521             session->user.context = cli_request.user_context;
00522     }
00523 
00524     return result;
00525 }
00526 
00527 static connector_status_t sm_prepare_cli_response(connector_data_t * const connector_ptr, connector_sm_session_t * const session)
00528 {
00529     connector_status_t result;
00530     connector_sm_cli_response_t cli_response;
00531     size_t const allowed_bytes = (size_t)session->user.header;
00532 
00533     if (session->in.data == NULL)
00534     {
00535         if (session->in.bytes > allowed_bytes)
00536             session->in.bytes = allowed_bytes;
00537 
00538         session->bytes_processed = 0;
00539         result = sm_allocate_user_buffer(connector_ptr, &session->in);
00540         if (result != connector_working)
00541             goto error;
00542     }
00543 
00544     cli_response.transport = session->transport;
00545     cli_response.user_context = session->user.context;
00546     ASSERT(session->in.bytes >= session->bytes_processed);
00547     cli_response.bytes_available = (session->in.bytes - session->bytes_processed);
00548     cli_response.buffer = ((char *)session->in.data) + session->bytes_processed;
00549     cli_response.bytes_used = 0;
00550     cli_response.more_data = connector_false;
00551 
00552     {
00553         connector_callback_status_t status;
00554         connector_request_id_t request_id;
00555 
00556         request_id.sm_request = connector_request_id_sm_cli_response;
00557         status = connector_callback(connector_ptr->callback, connector_class_id_short_message, request_id, &cli_response);
00558         if (status == connector_callback_unrecognized)
00559             status = connector_callback_error;
00560         ASSERT(cli_response.bytes_available >= cli_response.bytes_used);
00561         result = sm_map_callback_status_to_connector_status(status);
00562     }
00563 
00564     switch (result)
00565     {
00566         case connector_working:
00567             session->bytes_processed += cli_response.bytes_used;
00568             if ((!cli_response.more_data) || (session->bytes_processed >= session->in.bytes))
00569                 sm_set_payload_complete(session);
00570             break;
00571 
00572         case connector_device_error:
00573             session->error = connector_sm_error_cancel;
00574             result = connector_working;
00575             break;
00576 
00577         default:
00578             break;
00579     }
00580 
00581 error:
00582     return result;
00583 }
00584 #endif
00585 
00586 #if (defined CONNECTOR_TRANSPORT_SMS)
00587 static connector_status_t sm_process_config_request(connector_data_t * const connector_ptr, connector_sm_session_t * const session, void * const payload, size_t const bytes)
00588 {
00589     connector_status_t result = connector_success;
00590     connector_sm_receive_config_request_t config_request;
00591     
00592     ASSERT(SmIsLastData(session->flags));
00593     config_request.phone_number = payload;
00594 
00595     {
00596         size_t const phone_bytes = strlen(config_request.phone_number) + 1;
00597         config_request.service_id = (phone_bytes < bytes) ? config_request.phone_number + phone_bytes : NULL;
00598     }
00599 
00600     /* Callback sms transport close/open so new phone makes effect */
00601     {
00602         connector_sm_data_t * const sm_ptr = &connector_ptr->sm_sms;    /* Assume it's SMS transport */
00603         ASSERT(sm_ptr->network.class_id == connector_class_id_network_sms);
00604 
00605         if (sm_ptr->network.handle != NULL)
00606         {
00607             connector_callback_status_t callback_status;
00608             connector_request_id_t request_id;
00609             connector_network_close_t close_data;
00610 
00611             /* Close */
00612             close_data.handle = sm_ptr->network.handle;
00613             close_data.status = connector_close_status_device_stopped;
00614 
00615             request_id.network_request = connector_request_id_network_close;
00616             callback_status = connector_callback(connector_ptr->callback, sm_ptr->network.class_id, request_id, &close_data);
00617                 ASSERT(callback_status != connector_callback_unrecognized);
00618             switch (callback_status)
00619             {
00620                 case connector_callback_busy:
00621                     result = connector_pending;
00622                     sm_ptr->transport.state = connector_transport_receive; /* Keep on receive state to complete reconfiguration operation */
00623                     goto error;
00624 
00625                 case connector_callback_continue:
00626                     sm_ptr->network.handle = NULL;
00627                     result = connector_working;
00628                     break;
00629 
00630                 default:
00631                     sm_ptr->close.status = connector_close_status_abort;
00632                     break;
00633             }
00634         }
00635         
00636         if (sm_ptr->network.handle == NULL)
00637         {
00638             connector_callback_status_t callback_status;
00639             connector_request_id_t request_id;
00640             connector_network_open_t open_data;
00641 
00642             /* Open */
00643             open_data.device_cloud_url = config_request.phone_number;
00644             open_data.handle = NULL;
00645 
00646             request_id.network_request = connector_request_id_network_open;
00647             callback_status = connector_callback(connector_ptr->callback, sm_ptr->network.class_id, request_id, &open_data);
00648             ASSERT(callback_status != connector_callback_unrecognized);
00649             switch (callback_status)
00650             {
00651                 case connector_callback_continue:
00652                     result = connector_working;
00653                     sm_ptr->network.handle = open_data.handle;
00654                     break;
00655 
00656                 case  connector_callback_abort:
00657                     result = connector_abort;
00658                     goto error;
00659 
00660                 case connector_callback_unrecognized:
00661                     result = connector_unavailable;
00662                     goto error;
00663 
00664                 case connector_callback_error:
00665                     result = connector_open_error;
00666                     goto error;
00667 
00668                 case connector_callback_busy:
00669                     result = connector_pending;
00670                     sm_ptr->transport.state = connector_transport_receive; /* Keep on receive state to complete reconfiguration operation */
00671                     goto error;
00672             }
00673         }
00674     }
00675 
00676     /* Callback to config.c so user can save the new phone to persistent storage */
00677 #if !(defined CONNECTOR_CLOUD_PHONE)
00678     result = set_config_device_cloud_phone(connector_ptr, config_request.phone_number);
00679 #endif
00680 
00681     /* Callback to user */
00682     {
00683         connector_request_id_t request_id;
00684         connector_callback_status_t callback_status;
00685         config_request.transport = session->transport;
00686         config_request.response_required = SmIsResponseNeeded(session->flags);
00687 
00688         request_id.sm_request = connector_request_id_sm_config_request;
00689         callback_status = connector_callback(connector_ptr->callback, connector_class_id_short_message, request_id, &config_request);
00690         result = sm_map_callback_status_to_connector_status(callback_status);
00691     }
00692 error:
00693     return result;
00694 }
00695 #endif
00696 
00697 #if (defined CONNECTOR_DATA_SERVICE)
00698 static connector_status_t sm_pass_target_info(connector_data_t * const connector_ptr, connector_sm_session_t * const session, uint8_t * const target_ptr, size_t target_bytes)
00699 {
00700     #define SM_TARGET_MAX_LENGTH    32
00701     connector_status_t result = connector_working;
00702     connector_callback_status_t callback_status;
00703     connector_request_id_t request_id;
00704     connector_data_service_receive_target_t cb_data;
00705     char target_name[SM_TARGET_MAX_LENGTH];
00706 
00707     cb_data.transport = session->transport;
00708     cb_data.user_context = session->user.context;
00709     if (target_bytes > 0)
00710         memcpy(target_name, target_ptr, target_bytes);
00711     target_name[target_bytes] = '\0';
00712     cb_data.target = target_name;
00713     cb_data.response_required = SmIsResponseNeeded(session->flags);
00714 
00715     request_id.data_service_request = connector_request_id_data_service_receive_target;
00716     callback_status = connector_callback(connector_ptr->callback, connector_class_id_data_service, request_id, &cb_data);
00717     if (callback_status == connector_callback_unrecognized)
00718         callback_status = connector_callback_error; 
00719     result = sm_map_callback_status_to_connector_status(callback_status);
00720     session->user.context = cb_data.user_context;
00721 
00722     return result;
00723 }
00724 
00725 static connector_status_t sm_process_data_request(connector_data_t * const connector_ptr, connector_sm_session_t * const session, void * const payload, size_t const bytes)
00726 {
00727     uint8_t * data_ptr = payload;
00728     connector_status_t status = connector_working;
00729 
00730     if (session->error == connector_sm_error_complete)
00731         goto done;
00732 
00733     if (session->bytes_processed == 0)
00734     {
00735         size_t target_length =  0;
00736 
00737         if (session->command == connector_sm_cmd_data)
00738             target_length = 0x1F & *data_ptr;
00739 
00740         status = sm_pass_target_info(connector_ptr, session, data_ptr + 1, target_length);
00741         if (status != connector_working)
00742             goto error;
00743 
00744         /* Increase target_length: 
00745          * It's required for connector_sm_cmd_data to point correctly to actual data,
00746          * and will be used for connector_sm_cmd_no_path_data to signal that sm_pass_target_info 
00747          * has already been called */
00748         target_length++;
00749 
00750         /* Set pre-processed bytes for segment 0 */
00751         session->bytes_processed = target_length;
00752         
00753         /* Return pending so bytes_processed and session->segments.processed are not incremented */
00754         status = connector_pending;
00755         SmSetTargetInPayload(session->flags);
00756         goto done;
00757     }
00758     
00759     {
00760         connector_callback_status_t callback_status;
00761         connector_request_id_t request_id;
00762         connector_data_service_receive_data_t cb_data;
00763         size_t bytes_pre_processed =  0;
00764         
00765         /* Compute pre-processed bytes for segment 0 */
00766         if (SmIsTargetInPayload(session->flags) && (session->command == connector_sm_cmd_data))
00767             bytes_pre_processed = session->bytes_processed;
00768 
00769         data_ptr += bytes_pre_processed;
00770         
00771         cb_data.transport = session->transport;
00772         cb_data.user_context = session->user.context;
00773         cb_data.buffer = data_ptr;
00774         cb_data.bytes_used = bytes - bytes_pre_processed;
00775         cb_data.more_data = SmIsNotLastData(session->flags);
00776         request_id.data_service_request = connector_request_id_data_service_receive_data;
00777         callback_status = connector_callback(connector_ptr->callback, connector_class_id_data_service, request_id, &cb_data);
00778         if (callback_status == connector_callback_unrecognized)
00779             callback_status = connector_callback_error;
00780         if (callback_status != connector_callback_busy)
00781             SmClearTargetInPayload(session->flags);  
00782         status = sm_map_callback_status_to_connector_status(callback_status);
00783         session->user.context = cb_data.user_context;
00784     }
00785 
00786 error:
00787     switch (status)
00788     {
00789         case connector_device_error:
00790             session->error = connector_sm_error_complete;
00791             session->bytes_processed = bytes;
00792             status = connector_working;
00793             break;
00794 
00795         case connector_working:
00796             /* Restore pre-processed bytes for segment 0 */
00797             if (session->segments.processed == 0)
00798                 session->bytes_processed = 0;
00799             break;
00800 
00801         default:
00802             break;
00803     }
00804 
00805 done:
00806     return status;
00807 }
00808 
00809 static connector_status_t sm_process_data_response(connector_data_t * const connector_ptr, connector_sm_session_t * const session, void * const payload, size_t const bytes)
00810 {
00811     connector_status_t status = connector_working;
00812     connector_callback_status_t callback_status;
00813     connector_data_service_send_response_t cb_data;
00814     char * const text = payload;
00815 
00816     cb_data.transport = session->transport;
00817     cb_data.user_context = session->user.context;
00818     if (SmIsError(session->flags))
00819     {
00820         switch (session->error)
00821         {
00822             case connector_sm_error_in_request:
00823                 cb_data.response = connector_data_service_send_response_bad_request;
00824                 break;
00825 
00826             case connector_sm_error_unavailable:
00827                 cb_data.response = connector_data_service_send_response_unavailable;
00828                 break;
00829 
00830             default:
00831                 cb_data.response = connector_data_service_send_response_cloud_error;
00832                 break;
00833         }
00834     }
00835     else
00836         cb_data.response = connector_data_service_send_response_success;
00837 
00838     cb_data.hint = (bytes > 0) ? text : NULL;
00839 
00840     #if (defined CONNECTOR_DATA_POINTS)
00841     if (SmIsDatapoint(session->flags))
00842     {
00843         callback_status = dp_handle_callback(connector_ptr, connector_request_id_data_service_send_response, &cb_data);
00844     }
00845     else
00846     #endif
00847     {
00848         connector_request_id_t request_id;
00849 
00850         request_id.data_service_request = connector_request_id_data_service_send_response;
00851         callback_status = connector_callback(connector_ptr->callback, connector_class_id_data_service, request_id, &cb_data);
00852     }
00853  
00854     status = sm_map_callback_status_to_connector_status(callback_status);
00855     if (SmIsError(session->flags) && (status != connector_pending))
00856     {
00857         session->error = connector_sm_error_none;
00858         SmClearError(session->flags);
00859     }
00860 
00861     return status;
00862 }
00863 #endif
00864 
00865 static connector_status_t sm_process_reboot(connector_data_t * const connector_ptr)
00866 {
00867     connector_status_t result = connector_abort;
00868     connector_request_id_t request_id;
00869     connector_callback_status_t callback_status;
00870 
00871     request_id.os_request = connector_request_id_os_reboot;
00872     callback_status = connector_callback(connector_ptr->callback, connector_class_id_operating_system, request_id, NULL);
00873     /* JIRA IC4C-119 */
00874     /* ASSERT(callback_status != connector_callback_unrecognized); */
00875     
00876     result = sm_map_callback_status_to_connector_status(callback_status);
00877 
00878     return result;
00879 }
00880 
00881 static connector_status_t sm_process_ping_response(connector_data_t * const connector_ptr, connector_sm_session_t * const session)
00882 {
00883     connector_status_t status;
00884     connector_callback_status_t const callback_status = sm_inform_ping_complete(connector_ptr, session);
00885 
00886     status = sm_map_callback_status_to_connector_status(callback_status);
00887     if (SmIsError(session->flags) && (status != connector_pending))
00888     {
00889         session->error = connector_sm_error_none;
00890         SmClearError(session->flags);
00891     }
00892     return status;
00893 }
00894 
00895 static connector_status_t sm_process_ping_request(connector_data_t * const connector_ptr, connector_sm_session_t * const session)
00896 {
00897     connector_status_t status;
00898     connector_request_id_t request_id;
00899     connector_sm_receive_ping_request_t cb_data;
00900     connector_callback_status_t callback_status;
00901 
00902     cb_data.transport = session->transport;
00903     cb_data.response_required = SmIsResponseNeeded(session->flags);
00904 
00905     request_id.sm_request = connector_request_id_sm_ping_request;
00906     callback_status = connector_callback(connector_ptr->callback, connector_class_id_short_message, request_id, &cb_data);
00907     if (callback_status == connector_callback_unrecognized)
00908         callback_status = connector_callback_continue;
00909     status = sm_map_callback_status_to_connector_status(callback_status);
00910 
00911     return status;
00912 }
00913 
00914 static connector_status_t sm_process_opaque_response(connector_data_t * const connector_ptr, connector_sm_session_t * const session, void * payload, size_t const bytes)
00915 {
00916     connector_status_t status;
00917     connector_request_id_t request_id;
00918     connector_sm_opaque_response_t cb_data;
00919     connector_callback_status_t callback_status;
00920 
00921     cb_data.transport = session->transport;
00922     cb_data.id = session->request_id;
00923     cb_data.data = payload;
00924     cb_data.bytes_used = bytes;
00925     cb_data.error = SmIsError(session->flags);
00926 
00927     request_id.sm_request = connector_request_id_sm_opaque_response;
00928     callback_status = connector_callback(connector_ptr->callback, connector_class_id_short_message, request_id, &cb_data);
00929     status = sm_map_callback_status_to_connector_status(callback_status);
00930 
00931     return status;
00932 }
00933 
00934 static connector_status_t sm_prepare_payload(connector_data_t * const connector_ptr, connector_sm_session_t * const session)
00935 {
00936     connector_status_t result = connector_abort;
00937     connector_status_t (* prepare_fn) (connector_data_t * const connector_ptr, connector_sm_session_t * const session) = NULL;
00938 
00939     ASSERT_GOTO(session != NULL, error);
00940     switch (session->command)
00941     {
00942         case connector_sm_cmd_data:
00943         case connector_sm_cmd_no_path_data:
00944             prepare_fn = SmIsClientOwned(session->flags) ? sm_prepare_data_request : sm_prepare_data_response;
00945             break;
00946 
00947         #if (defined CONNECTOR_SM_CLI)
00948         case connector_sm_cmd_cli:
00949             ASSERT_GOTO(SmIsCloudOwned(session->flags), error);
00950             prepare_fn = sm_prepare_cli_response;
00951             break;
00952         #endif
00953 
00954         default:
00955             result = connector_unavailable;
00956             goto unexpected;
00957     }
00958 
00959     result = prepare_fn(connector_ptr, session);
00960 
00961 unexpected:
00962     if ((result == connector_working) && (session->error != connector_sm_error_none) && (session->error != connector_sm_error_complete))
00963     {
00964         session->sm_state = connector_sm_state_error;
00965         SmSetError(session->flags);
00966     }
00967 
00968 error:
00969     return result;
00970 }
00971 
00972 static connector_status_t sm_pass_user_data(connector_data_t * const connector_ptr, connector_sm_session_t * const session, uint8_t * payload, size_t const bytes)
00973 {
00974     connector_status_t result = connector_abort;
00975     connector_sm_state_t next_state = connector_sm_state_send_data;
00976 
00977     switch (session->command)
00978     {
00979         case connector_sm_cmd_data:
00980         case connector_sm_cmd_no_path_data:
00981             if (SmIsCloudOwned(session->flags))
00982             {
00983 #if (defined CONNECTOR_DATA_SERVICE)
00984                 result = sm_process_data_request(connector_ptr, session, payload, bytes);
00985 #endif
00986                 next_state = connector_sm_state_get_total_length;
00987             }
00988             else
00989             {
00990 #if (defined CONNECTOR_DATA_SERVICE)
00991                 result = sm_process_data_response(connector_ptr, session, payload, bytes);
00992 #endif
00993                 next_state = connector_sm_state_complete;
00994             }
00995             break;
00996 
00997         #if (defined CONNECTOR_SM_CLI)
00998         case connector_sm_cmd_cli:
00999             result = sm_process_cli_request(connector_ptr, session, payload, bytes);
01000             next_state = connector_sm_state_get_total_length;
01001             break;
01002         #endif
01003 
01004         #if (defined CONNECTOR_TRANSPORT_SMS)
01005         case connector_sm_cmd_config:
01006             if (SmIsCloudOwned(session->flags))
01007             {
01008                 result = sm_process_config_request(connector_ptr, session, payload, bytes);
01009             }
01010             break;
01011         #endif
01012 
01013         case connector_sm_cmd_connect:
01014             #if (defined CONNECTOR_TRANSPORT_TCP)
01015             if (edp_get_active_state(connector_ptr) == connector_transport_idle)
01016                 edp_set_active_state(connector_ptr, connector_transport_open);
01017             result = connector_working;
01018             #else
01019             connector_debug_printf("WARNING: received a 'request connect' but TCP transport is not available\n");
01020             result = connector_device_error;
01021             #endif
01022             break;
01023 
01024         case connector_sm_cmd_ping:
01025             if (SmIsCloudOwned(session->flags))
01026             {
01027                 result = sm_process_ping_request(connector_ptr, session);
01028             }
01029             else
01030             {
01031                 result = sm_process_ping_response(connector_ptr, session);
01032                 next_state = connector_sm_state_complete;
01033             }
01034             break;
01035 
01036         case connector_sm_cmd_reboot:
01037             SmSetReboot(session->flags);
01038             result = connector_working;
01039             break;
01040 
01041         case connector_sm_cmd_opaque_response:
01042             result = sm_process_opaque_response(connector_ptr, session, payload, bytes);
01043             break;
01044 
01045         default:
01046             result = connector_unavailable;
01047             break;
01048     }
01049 
01050     switch (result)
01051     {
01052         case connector_working:
01053             session->bytes_processed += bytes;
01054             switch (session->error)
01055             {
01056                 case connector_sm_error_none:
01057                 case connector_sm_error_complete:
01058                     if (SmIsLastData(session->flags))
01059                         sm_switch_path(connector_ptr, session, next_state);
01060                     break;
01061 
01062                 default:
01063                     session->sm_state = connector_sm_state_error;
01064                     SmSetError(session->flags);
01065                     break;
01066             }
01067             break;
01068 
01069         case connector_pending:
01070             break;
01071 
01072         case connector_device_error:
01073             session->error = connector_sm_error_cancel;
01074             session->sm_state = connector_sm_state_error;
01075             SmSetError(session->flags);
01076             result = connector_working;
01077             break;
01078 
01079         default:
01080             session->sm_state = connector_sm_state_error;
01081             SmSetError(session->flags);
01082             break;
01083     }
01084 
01085     return result;
01086 }
01087 
01088 static connector_status_t sm_process_payload(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr, connector_sm_session_t * const session)
01089 {
01090     connector_status_t result = connector_abort;
01091     uint8_t * data_ptr;
01092     size_t bytes;
01093 
01094 #if (defined CONNECTOR_SM_MULTIPART)
01095     if (SmIsMultiPart(session->flags))
01096     {
01097         size_t const max_payload_bytes = sm_get_max_payload_bytes(sm_ptr);
01098         size_t const data_index = session->segments.processed * max_payload_bytes;
01099 
01100         ASSERT_GOTO(session->in.data != NULL, error);
01101         ASSERT_GOTO(session->segments.processed < session->segments.count, error);
01102         if (session->segments.processed == (session->segments.count - 1))
01103             SmSetLastData(session->flags);
01104 
01105         data_ptr = &session->in.data[data_index];
01106         bytes = session->segments.size_array[session->segments.processed];
01107     }
01108     else
01109 #endif
01110     {
01111         UNUSED_PARAMETER(sm_ptr);
01112         ASSERT_GOTO(SmIsNotMultiPart(session->flags), error);
01113         SmSetLastData(session->flags);
01114         data_ptr = session->in.data;
01115         bytes = session->in.bytes;
01116     }
01117 
01118     result = sm_pass_user_data(connector_ptr, session, data_ptr, bytes);
01119     if ((result == connector_working) && (SmIsNotLastData(session->flags)))
01120         session->segments.processed++;
01121 
01122 error:
01123     return result;
01124 }
01125