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.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
Generated on Tue Jul 12 2022 19:18:38 by
1.7.2