Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
Generated on Tue Jul 12 2022 19:18:38 by
1.7.2