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_send.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_get_user_data_length(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr, connector_sm_session_t * const session) 00013 { 00014 connector_status_t result; 00015 connector_callback_status_t status = connector_callback_continue; 00016 00017 #if !(defined CONNECTOR_DATA_SERVICE) && !(defined CONNECTOR_SM_CLI) 00018 (void)(connector_ptr); /* Unused argument */ 00019 #endif 00020 00021 switch (session->command) 00022 { 00023 case connector_sm_cmd_data: 00024 case connector_sm_cmd_no_path_data: 00025 { 00026 #if (defined CONNECTOR_DATA_SERVICE) 00027 connector_data_service_length_t cb_data; 00028 00029 cb_data.transport = session->transport; 00030 cb_data.user_context = session->user.context; 00031 cb_data.total_bytes = 0; 00032 00033 #if (defined CONNECTOR_DATA_POINTS) 00034 if (SmIsDatapoint(session->flags)) 00035 { 00036 status = dp_handle_callback(connector_ptr, connector_request_id_data_service_send_length, &cb_data); 00037 } 00038 else 00039 #endif 00040 { 00041 connector_request_id_t request_id; 00042 00043 request_id.data_service_request = SmIsClientOwned(session->flags) ? connector_request_id_data_service_send_length : connector_request_id_data_service_receive_reply_length; 00044 status = connector_callback(connector_ptr->callback, connector_class_id_data_service, request_id, &cb_data); 00045 if (status == connector_callback_unrecognized) 00046 status = connector_callback_continue; 00047 } 00048 00049 session->in.bytes = cb_data.total_bytes; 00050 #endif 00051 break; 00052 } 00053 00054 #if (defined CONNECTOR_SM_CLI) 00055 case connector_sm_cmd_cli: 00056 { 00057 connector_sm_cli_response_length_t cb_data; 00058 connector_request_id_t request_id; 00059 00060 cb_data.transport = session->transport; 00061 cb_data.user_context = session->user.context; 00062 cb_data.total_bytes = 0; 00063 00064 request_id.sm_request = connector_request_id_sm_cli_response_length; 00065 status = connector_callback(connector_ptr->callback, connector_class_id_short_message, request_id, &cb_data); 00066 if (status == connector_callback_unrecognized) 00067 status = connector_callback_continue; 00068 session->in.bytes = cb_data.total_bytes; 00069 break; 00070 } 00071 #endif 00072 00073 default: 00074 result = connector_abort; 00075 ASSERT_GOTO(connector_false, error); 00076 break; 00077 } 00078 00079 result = sm_map_callback_status_to_connector_status(status); 00080 if (status == connector_callback_continue) 00081 { 00082 ASSERT_GOTO(session->in.bytes < (sm_ptr->transport.sm_mtu_tx * UCHAR_MAX), error); 00083 session->sm_state = connector_sm_state_prepare_payload; 00084 } 00085 00086 error: 00087 return result; 00088 } 00089 00090 #if (defined CONNECTOR_DATA_SERVICE) 00091 static connector_status_t sm_get_more_request_data(connector_data_t * const connector_ptr, connector_sm_session_t * const session) 00092 { 00093 connector_status_t result = connector_abort; 00094 uint8_t * dptr = session->in.data; 00095 connector_data_service_send_data_t cb_data; 00096 00097 ASSERT_GOTO(session->in.bytes > session->bytes_processed, error); 00098 00099 cb_data.transport = session->transport; 00100 cb_data.user_context = session->user.context; 00101 cb_data.buffer = &dptr[session->bytes_processed]; 00102 cb_data.bytes_available = session->in.bytes - session->bytes_processed; 00103 cb_data.bytes_used = 0; 00104 cb_data.more_data = connector_false; 00105 00106 { 00107 connector_callback_status_t status; 00108 00109 #if (defined CONNECTOR_DATA_POINTS) 00110 if (SmIsDatapoint(session->flags)) 00111 { 00112 status = dp_handle_callback(connector_ptr, connector_request_id_data_service_send_data, &cb_data); 00113 } 00114 else 00115 #endif 00116 { 00117 connector_request_id_t request_id; 00118 00119 request_id.data_service_request = connector_request_id_data_service_send_data; 00120 status = connector_callback(connector_ptr->callback, connector_class_id_data_service, request_id, &cb_data); 00121 } 00122 00123 result = sm_map_callback_status_to_connector_status(status); 00124 } 00125 00126 session->user.context = cb_data.user_context; 00127 if (result == connector_working) 00128 { 00129 session->bytes_processed += cb_data.bytes_used; 00130 ASSERT(session->bytes_processed <= session->in.bytes); 00131 if (!cb_data.more_data) 00132 sm_set_payload_complete(session); 00133 } 00134 00135 error: 00136 return result; 00137 } 00138 00139 static connector_status_t sm_get_more_response_data(connector_data_t * const connector_ptr, connector_sm_session_t * const session) 00140 { 00141 connector_status_t result = connector_abort; 00142 uint8_t * dptr = session->in.data; 00143 connector_data_service_receive_reply_data_t cb_data; 00144 00145 ASSERT_GOTO(session->in.bytes > session->bytes_processed, error); 00146 00147 cb_data.transport = session->transport; 00148 cb_data.user_context = session->user.context; 00149 cb_data.buffer = &dptr[session->bytes_processed]; 00150 cb_data.bytes_available = session->in.bytes - session->bytes_processed; 00151 cb_data.bytes_used = 0; 00152 cb_data.more_data = connector_false; 00153 00154 { 00155 connector_callback_status_t status; 00156 connector_request_id_t request_id; 00157 00158 request_id.data_service_request = connector_request_id_data_service_receive_reply_data; 00159 status = connector_callback(connector_ptr->callback, connector_class_id_data_service, request_id, &cb_data); 00160 result = sm_map_callback_status_to_connector_status(status); 00161 } 00162 00163 session->user.context = cb_data.user_context; 00164 if (result == connector_working) 00165 { 00166 session->bytes_processed += cb_data.bytes_used; 00167 ASSERT(session->bytes_processed <= session->in.bytes); 00168 if (!cb_data.more_data) 00169 { 00170 sm_set_payload_complete(session); 00171 } 00172 else 00173 { 00174 ASSERT(cb_data.bytes_used < cb_data.bytes_available); 00175 } 00176 } 00177 00178 error: 00179 return result; 00180 } 00181 #endif 00182 00183 #if (defined CONNECTOR_COMPRESSION) 00184 static connector_status_t sm_compress_data(connector_data_t * const connector_ptr, connector_sm_session_t * const session) 00185 { 00186 connector_status_t status; 00187 size_t const excluded_header_adler32_footer_bytes = 6; 00188 00189 session->compress.out.data = NULL; 00190 session->compress.out.bytes = session->bytes_processed + excluded_header_adler32_footer_bytes; 00191 status = sm_allocate_user_buffer(connector_ptr, &session->compress.out); 00192 ASSERT_GOTO(status == connector_working, error); 00193 00194 { 00195 z_streamp const zlib_ptr = &session->compress.zlib; 00196 int zret; 00197 00198 memset(zlib_ptr, 0, sizeof *zlib_ptr); 00199 zret = deflateInit(zlib_ptr, Z_DEFAULT_COMPRESSION); 00200 ASSERT_GOTO(zret == Z_OK, error); 00201 00202 zlib_ptr->next_in = session->in.data; 00203 zlib_ptr->avail_in = session->bytes_processed; 00204 zlib_ptr->next_out = session->compress.out.data; 00205 zlib_ptr->avail_out = session->compress.out.bytes; 00206 zret = deflate(zlib_ptr, Z_FINISH); 00207 switch(zret) 00208 { 00209 case Z_STREAM_END: 00210 { 00211 size_t const compressed_bytes = session->compress.out.bytes - (zlib_ptr->avail_out + excluded_header_adler32_footer_bytes); 00212 00213 if (compressed_bytes < session->bytes_processed) 00214 { 00215 uint8_t * data_ptr = session->compress.out.data; 00216 00217 SmSetCompressed(session->flags); 00218 status = free_data_buffer(connector_ptr, named_buffer_id(sm_data_block), session->in.data); 00219 if (status != connector_working) goto error; 00220 session->in.data = data_ptr; 00221 session->bytes_processed = compressed_bytes; 00222 sm_set_payload_process(session); 00223 break; 00224 } 00225 } 00226 /* no break */ 00227 00228 case Z_OK: 00229 status = free_data_buffer(connector_ptr, named_buffer_id(sm_data_block), session->compress.out.data); 00230 if (status != connector_working) goto error; 00231 sm_set_payload_process(session); 00232 break; 00233 00234 default: 00235 status = connector_abort; 00236 ASSERT_GOTO(connector_false, error); 00237 break; 00238 } 00239 00240 zret = deflateEnd(zlib_ptr); 00241 ASSERT_GOTO(zret == Z_OK, error); 00242 } 00243 00244 error: 00245 return status; 00246 } 00247 #endif 00248 00249 static connector_status_t sm_prepare_segment(connector_sm_data_t * const sm_ptr, connector_sm_session_t * const session) 00250 { 00251 connector_status_t result = connector_abort; 00252 size_t const max_payload = sm_ptr->transport.sm_mtu_tx - record_end(segment); 00253 00254 session->segments.processed = 0; 00255 session->segments.size_array = NULL; 00256 if (session->in.bytes <= max_payload) 00257 session->segments.count = 1; 00258 #if (defined CONNECTOR_SM_MULTIPART) 00259 else 00260 { 00261 size_t const segment0_overhead_bytes = record_end(segment0) - record_end(segmentn); 00262 size_t const segment_count = (session->in.bytes + ((max_payload + segment0_overhead_bytes) - 1))/max_payload; 00263 00264 ASSERT_GOTO(segment_count < 256, error); 00265 session->segments.count = segment_count; 00266 SmSetMultiPart(session->flags); 00267 } 00268 #else 00269 else 00270 { 00271 connector_debug_printf("sm_prepare_segment: Multipart is disabled. Please define CONNECTOR_SM_MULTIPART in connector_config.h.\n"); 00272 ASSERT(connector_false); 00273 result = connector_invalid_data_size; 00274 goto error; 00275 } 00276 #endif 00277 00278 session->sm_state = connector_sm_state_send_data; 00279 result = connector_working; 00280 00281 error: 00282 return result; 00283 } 00284 00285 static connector_status_t sm_send_segment(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr) 00286 { 00287 connector_status_t result = connector_no_resource; 00288 connector_sm_packet_t * const send_packet = &sm_ptr->network.send_packet; 00289 connector_callback_status_t status; 00290 connector_network_send_t send_data; 00291 connector_request_id_t request_id; 00292 00293 send_data.buffer = &send_packet->data[send_packet->processed_bytes]; 00294 send_data.bytes_available = send_packet->total_bytes - send_packet->processed_bytes; 00295 send_data.handle = sm_ptr->network.handle; 00296 send_data.bytes_used = 0; 00297 00298 request_id.network_request = connector_request_id_network_send; 00299 status = connector_callback(connector_ptr->callback, sm_ptr->network.class_id, request_id, &send_data); 00300 ASSERT(status != connector_callback_unrecognized); 00301 result = sm_map_callback_status_to_connector_status(status); 00302 if (status != connector_callback_continue) goto error; 00303 00304 send_packet->processed_bytes += send_data.bytes_used; 00305 if (send_packet->processed_bytes >= send_packet->total_bytes) 00306 { 00307 connector_sm_session_t * const session = send_packet->pending_session; 00308 00309 ASSERT_GOTO(session != NULL, error); 00310 session->segments.processed++; 00311 if (session->segments.count == session->segments.processed) 00312 { 00313 if (session->in.bytes != 0) 00314 { 00315 connector_debug_printf("ERROR: sm_send_segment: All segments processed but still remaining bytes\n"); 00316 } 00317 result = sm_switch_path(connector_ptr, session, SmIsResponse(session->flags) ? connector_sm_state_complete : connector_sm_state_receive_data); 00318 if (result != connector_working) goto error; 00319 } 00320 00321 send_packet->total_bytes = 0; 00322 send_packet->processed_bytes = 0; 00323 send_packet->pending_session = NULL; 00324 } 00325 00326 error: 00327 return result; 00328 } 00329 00330 #if (defined CONNECTOR_TRANSPORT_SMS) 00331 static connector_status_t sm_encode_segment(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr, connector_sm_session_t * const session) 00332 { 00333 size_t const data_size = 1+(sm_ptr->network.send_packet.total_bytes * 5)/4; 00334 void * data_ptr = NULL; 00335 connector_status_t result = malloc_data_buffer(connector_ptr, data_size, named_buffer_id(sm_data_block), &data_ptr); 00336 00337 if (result == connector_working) 00338 { 00339 connector_sm_packet_t * const send_ptr = &sm_ptr->network.send_packet; 00340 00341 send_ptr->total_bytes = sm_encode85(data_ptr, data_size, send_ptr->data, send_ptr->total_bytes); 00342 memcpy(send_ptr->data, data_ptr, send_ptr->total_bytes); 00343 result = free_data_buffer(connector_ptr, named_buffer_id(sm_data_block), data_ptr); 00344 if (result != connector_working) goto error; 00345 session->sm_state = connector_sm_state_send_data; 00346 } 00347 00348 error: 00349 return result; 00350 } 00351 #endif 00352 00353 static connector_status_t sm_send_data(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr, connector_sm_session_t * const session) 00354 { 00355 connector_status_t result = connector_working; 00356 connector_sm_packet_t * const send_ptr = &sm_ptr->network.send_packet; 00357 uint8_t * data_ptr = send_ptr->data; 00358 uint8_t * sm_header; 00359 00360 if (send_ptr->total_bytes > 0) 00361 { 00362 goto send; 00363 } 00364 00365 switch (sm_ptr->network.transport) 00366 { 00367 #if (defined CONNECTOR_TRANSPORT_UDP) 00368 case connector_transport_udp: 00369 { 00370 uint8_t const sm_udp_version_num = SM_UDP_VERSION << 4; 00371 uint8_t const version_byte = sm_udp_version_num | sm_ptr->transport.id_type; 00372 00373 *data_ptr++ = version_byte; 00374 ASSERT(connector_ptr->connector_got_device_id); 00375 memcpy(data_ptr, sm_ptr->transport.id, sm_ptr->transport.id_length); 00376 data_ptr += sm_ptr->transport.id_length; 00377 break; 00378 } 00379 #endif 00380 00381 #if (defined CONNECTOR_TRANSPORT_SMS) 00382 case connector_transport_sms: 00383 { 00384 /* service ID available? */ 00385 if (sm_ptr->transport.id_length > 0) 00386 { 00387 ASSERT(sm_ptr->transport.id != NULL); 00388 memcpy(data_ptr, sm_ptr->transport.id, sm_ptr->transport.id_length); 00389 data_ptr += sm_ptr->transport.id_length; 00390 *data_ptr++ = ' '; 00391 } 00392 00393 break; 00394 } 00395 #endif 00396 00397 default: 00398 ASSERT(connector_false); 00399 break; 00400 } 00401 00402 sm_header = data_ptr; 00403 00404 { 00405 uint8_t const sm_version_num = 0x01 << 5; 00406 uint8_t const request_id_hi = (session->request_id & SM_REQUEST_ID_MASK) >> 8; 00407 uint8_t const request_id_low = session->request_id & 0xFF; 00408 uint8_t info_field = sm_version_num | request_id_hi; 00409 00410 if (SmIsResponse(session->flags)) 00411 SmSetResponse(info_field); 00412 else if (SmIsResponseNeeded(session->flags)) 00413 SmSetResponseNeeded(info_field); 00414 00415 if (session->segments.processed == 0) 00416 { 00417 uint8_t cmd_field = SmIsRequest(session->flags) ? session->command : 0; 00418 00419 if (SmIsError(session->flags)) 00420 SmSetError(cmd_field); 00421 if (SmIsCompressed(session->flags)) 00422 SmSetCompressed(cmd_field); 00423 00424 #if (defined CONNECTOR_SM_MULTIPART) 00425 if (SmIsMultiPart(session->flags)) 00426 { 00427 uint8_t * const segment0 = sm_header; 00428 00429 SmSetMultiPart(info_field); 00430 message_store_u8(segment0, info, info_field); 00431 message_store_u8(segment0, request, request_id_low); 00432 message_store_u8(segment0, segment, session->segments.processed); 00433 message_store_u8(segment0, count, session->segments.count); 00434 message_store_u8(segment0, cmd_status, cmd_field); 00435 message_store_be16(segment0, crc, 0); 00436 data_ptr += record_end(segment0); 00437 } 00438 else 00439 #endif 00440 { 00441 uint8_t * const segment = sm_header; 00442 00443 ASSERT_GOTO(SmIsNotMultiPart(session->flags), done); 00444 message_store_u8(segment, info, info_field); 00445 message_store_u8(segment, request, request_id_low); 00446 message_store_u8(segment, cmd_status, cmd_field); 00447 message_store_be16(segment, crc, 0); 00448 data_ptr += record_end(segment); 00449 } 00450 } 00451 else 00452 { 00453 uint8_t * const segmentn = sm_header; 00454 00455 ASSERT_GOTO(SmIsMultiPart(session->flags), done); 00456 SmSetMultiPart(info_field); 00457 message_store_u8(segmentn, info, info_field); 00458 message_store_u8(segmentn, request, request_id_low); 00459 message_store_u8(segmentn, segment, session->segments.processed); 00460 message_store_be16(segmentn, crc, 0); 00461 data_ptr += record_end(segmentn); 00462 } 00463 } 00464 00465 { 00466 size_t const filled_bytes = data_ptr - send_ptr->data; 00467 size_t const bytes_available = sm_ptr->transport.sm_mtu_tx - (data_ptr - sm_header); 00468 size_t payload_bytes; 00469 00470 if (SmIsError(session->flags)) 00471 { 00472 uint16_t const error_code = (uint16_t)session->error; 00473 char * const error_text = (session->error == connector_sm_error_in_request) ? "Request error" : "Unexpected request"; 00474 size_t const error_text_length = strlen(error_text) + 1; 00475 size_t const error_code_length = sizeof error_code; 00476 00477 StoreBE16(data_ptr, error_code); 00478 memcpy(data_ptr + error_code_length, error_text, error_text_length); 00479 payload_bytes = error_code_length + error_text_length; 00480 } 00481 else 00482 { 00483 payload_bytes = (session->in.bytes < bytes_available) ? session->in.bytes : bytes_available; 00484 00485 if (payload_bytes > 0) 00486 { 00487 memcpy(data_ptr, &session->in.data[session->bytes_processed], payload_bytes); 00488 session->bytes_processed += payload_bytes; 00489 session->in.bytes -= payload_bytes; 00490 } 00491 } 00492 00493 send_ptr->total_bytes = filled_bytes + payload_bytes; 00494 00495 { 00496 uint8_t * const crc_field = data_ptr - 2; 00497 size_t const header_bytes = data_ptr - sm_header; 00498 size_t const crc_bytes = header_bytes + payload_bytes; 00499 uint16_t crc_value = 0; 00500 00501 crc_value = sm_calculate_crc16(crc_value, sm_header, crc_bytes); 00502 StoreBE16(crc_field, crc_value); 00503 } 00504 } 00505 00506 send_ptr->pending_session = session; 00507 #if (defined CONNECTOR_TRANSPORT_SMS) 00508 if (SmIsEncoded(session->flags)) 00509 { 00510 session->sm_state = connector_sm_state_encoding; 00511 /* Increase pointer to skip preamble encoding */ 00512 if (sm_ptr->transport.id_length) 00513 { 00514 send_ptr->data += (sm_ptr->transport.id_length + SMS_SERVICEID_WRAPPER_TX_SIZE); 00515 send_ptr->total_bytes -= (sm_ptr->transport.id_length + SMS_SERVICEID_WRAPPER_TX_SIZE); 00516 } 00517 00518 result = sm_encode_segment(connector_ptr, sm_ptr, session); 00519 00520 /* Restore pointer if it has preamble */ 00521 if (sm_ptr->transport.id_length) 00522 { 00523 send_ptr->data -= (sm_ptr->transport.id_length + SMS_SERVICEID_WRAPPER_TX_SIZE); 00524 send_ptr->total_bytes += (sm_ptr->transport.id_length + SMS_SERVICEID_WRAPPER_TX_SIZE); 00525 } 00526 } 00527 #endif 00528 send: 00529 if (result == connector_working) 00530 { 00531 result = sm_send_segment(connector_ptr, sm_ptr); 00532 } 00533 00534 done: 00535 return result; 00536 } 00537 00538 static connector_status_t sm_process_send_path(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr, connector_sm_session_t * const session) 00539 { 00540 connector_status_t result = connector_abort; 00541 00542 ASSERT_GOTO(session != NULL, error); 00543 switch (session->sm_state) 00544 { 00545 case connector_sm_state_get_total_length: 00546 result = sm_get_user_data_length(connector_ptr, sm_ptr, session); 00547 break; 00548 00549 case connector_sm_state_prepare_payload: 00550 result = sm_prepare_payload(connector_ptr, session); 00551 break; 00552 00553 case connector_sm_state_more_data: 00554 #if (defined CONNECTOR_DATA_SERVICE) 00555 result = SmIsClientOwned(session->flags) ? sm_get_more_request_data(connector_ptr, session) : sm_get_more_response_data(connector_ptr, session); 00556 #endif 00557 break; 00558 00559 #if (defined CONNECTOR_COMPRESSION) 00560 case connector_sm_state_compress: 00561 result = sm_compress_data(connector_ptr, session); 00562 break; 00563 #endif 00564 00565 case connector_sm_state_prepare_segment: 00566 result = sm_prepare_segment(sm_ptr, session); 00567 break; 00568 00569 #if (defined CONNECTOR_TRANSPORT_SMS) 00570 case connector_sm_state_encoding: 00571 result = sm_encode_segment(connector_ptr, sm_ptr, session); 00572 if (result == connector_working) 00573 { 00574 result = sm_send_segment(connector_ptr, sm_ptr); 00575 } 00576 break; 00577 #endif 00578 00579 case connector_sm_state_send_data: 00580 result = sm_send_data(connector_ptr, sm_ptr, session); 00581 break; 00582 00583 default: 00584 ASSERT(connector_false); 00585 break; 00586 } 00587 00588 sm_verify_result(sm_ptr, &result); 00589 00590 error: 00591 return result; 00592 } 00593 00594
Generated on Tue Jul 12 2022 19:18:38 by
1.7.2