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_data_point.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 00013 typedef struct 00014 { 00015 #if (defined CONNECTOR_TRANSPORT_TCP) 00016 #define DP_FILE_PATH_SIZE 64 00017 #else 00018 #define DP_FILE_PATH_SIZE 32 00019 #endif 00020 connector_request_data_service_send_t header; 00021 char file_path[DP_FILE_PATH_SIZE]; 00022 00023 enum 00024 { 00025 dp_content_type_binary, 00026 dp_content_type_csv 00027 } type; 00028 00029 union 00030 { 00031 struct 00032 { 00033 connector_request_data_point_single_t const * dp_request; 00034 connector_data_point_t const * current_dp; 00035 size_t bytes_sent; 00036 size_t bytes_to_send; 00037 00038 /************************************************************************* 00039 ** WARNING: Please don't change the order of the state unless default ** 00040 ** CSV format described in the Cloud documentation changes. ** 00041 *************************************************************************/ 00042 enum 00043 { 00044 dp_state_data, 00045 dp_state_time, 00046 dp_state_quality, 00047 dp_state_description, 00048 dp_state_location, 00049 dp_state_type, 00050 dp_state_unit, 00051 dp_state_forward_to 00052 } state; 00053 00054 } csv; 00055 00056 struct 00057 { 00058 connector_request_data_point_binary_t const * bp_request; 00059 uint8_t * current_bp; 00060 size_t bytes_to_send; 00061 } binary; 00062 00063 } data; 00064 00065 } data_point_info_t; 00066 00067 static connector_request_data_point_single_t const * data_point_single_pending = NULL; 00068 static connector_request_data_point_binary_t const * data_point_binary_pending = NULL; 00069 00070 static connector_status_t dp_initiate_data_point_single(connector_request_data_point_single_t const * const dp_ptr) 00071 { 00072 connector_status_t result = connector_invalid_data; 00073 00074 ASSERT_GOTO(dp_ptr != NULL, error); 00075 00076 if (data_point_single_pending != NULL) 00077 { 00078 result = connector_service_busy; 00079 goto error; 00080 } 00081 00082 if (dp_ptr->path == NULL) 00083 { 00084 connector_debug_printf("dp_initiate_data_point_single: NULL data point path\n"); 00085 goto error; 00086 } 00087 00088 if ((dp_ptr->point == NULL)) 00089 { 00090 connector_debug_printf("dp_initiate_data_point_single: NULL data point\n"); 00091 goto error; 00092 } 00093 00094 data_point_single_pending = dp_ptr; 00095 result = connector_success; 00096 00097 error: 00098 return result; 00099 } 00100 00101 static connector_status_t dp_initiate_data_point_binary(connector_request_data_point_binary_t const * const bp_ptr) 00102 { 00103 connector_status_t result = connector_invalid_data; 00104 00105 ASSERT_GOTO(bp_ptr != NULL, error); 00106 00107 if (data_point_binary_pending != NULL) 00108 { 00109 result = connector_service_busy; 00110 goto error; 00111 } 00112 00113 if (bp_ptr->path == NULL) 00114 { 00115 connector_debug_printf("dp_initiate_data_point_binary: NULL data point path\n"); 00116 goto error; 00117 } 00118 00119 if ((bp_ptr->point == NULL)) 00120 { 00121 connector_debug_printf("dp_initiate_data_point_binary: NULL data point\n"); 00122 goto error; 00123 } 00124 00125 data_point_binary_pending = bp_ptr; 00126 result = connector_success; 00127 00128 error: 00129 return result; 00130 } 00131 00132 static connector_status_t dp_callback_status_to_status(connector_callback_status_t const callback_status) 00133 { 00134 connector_status_t status; 00135 00136 switch (callback_status) 00137 { 00138 case connector_callback_continue: 00139 status = connector_working; 00140 break; 00141 00142 case connector_callback_busy: 00143 status = connector_pending; 00144 break; 00145 00146 default: 00147 status = connector_abort; 00148 break; 00149 } 00150 00151 return status; 00152 } 00153 00154 static connector_status_t dp_inform_status(connector_data_t * const connector_ptr, connector_request_id_data_point_t request, 00155 connector_transport_t const transport, void * context, connector_session_error_t const error) 00156 { 00157 connector_status_t result; 00158 connector_data_point_status_t dp_status; 00159 00160 dp_status.transport = transport; 00161 dp_status.user_context = context; 00162 dp_status.session_error = connector_session_error_none; 00163 00164 switch (error) 00165 { 00166 case connector_session_error_none: 00167 dp_status.status = connector_data_point_status_complete; 00168 break; 00169 00170 case connector_session_error_cancel: 00171 dp_status.status = connector_data_point_status_cancel; 00172 break; 00173 00174 case connector_session_error_timeout: 00175 dp_status.status = connector_data_point_status_timeout; 00176 break; 00177 00178 case connector_session_error_format: 00179 dp_status.status = connector_data_point_status_invalid_data; 00180 break; 00181 00182 default: 00183 dp_status.status = connector_data_point_status_session_error; 00184 dp_status.session_error = error; 00185 break; 00186 } 00187 00188 { 00189 connector_callback_status_t callback_status; 00190 connector_request_id_t request_id; 00191 00192 request_id.data_point_request = request; 00193 callback_status = connector_callback(connector_ptr->callback, connector_class_id_data_point, request_id, &dp_status); 00194 result = dp_callback_status_to_status(callback_status); 00195 } 00196 00197 return result; 00198 } 00199 00200 #if (CONNECTOR_VERSION >= 0x02010000) 00201 static connector_status_t dp_cancel_session(connector_data_t * const connector_ptr, void const * const session, uint32_t const * const request_id) 00202 { 00203 connector_status_t status = connector_working; 00204 connector_bool_t cancel_all = connector_bool(request_id == NULL); 00205 00206 if (data_point_binary_pending != NULL) 00207 { 00208 connector_bool_t const has_request_id = connector_bool(data_point_binary_pending->request_id != NULL); 00209 connector_bool_t const matching_request = connector_bool(has_request_id && *data_point_binary_pending->request_id == *request_id); 00210 00211 if (cancel_all || matching_request) 00212 { 00213 if (session == NULL) 00214 { 00215 status = dp_inform_status(connector_ptr, connector_request_id_data_point_binary_status, data_point_binary_pending->transport, data_point_binary_pending->user_context, connector_session_error_cancel); 00216 if (status != connector_working) 00217 goto done; 00218 } 00219 data_point_binary_pending = NULL; 00220 } 00221 } 00222 00223 if (data_point_single_pending != NULL) 00224 { 00225 connector_bool_t const pending_dp_has_request_id = connector_bool(data_point_single_pending->request_id != NULL); 00226 connector_bool_t const matching_request = connector_bool(pending_dp_has_request_id && *data_point_single_pending->request_id == *request_id); 00227 00228 if (cancel_all || matching_request) 00229 { 00230 if (session == NULL) 00231 { 00232 status = dp_inform_status(connector_ptr, connector_request_id_data_point_single_status, data_point_single_pending->transport, data_point_single_pending->user_context, connector_session_error_cancel); 00233 if (status != connector_working) 00234 goto done; 00235 } 00236 data_point_single_pending = NULL; 00237 } 00238 } 00239 done: 00240 return status; 00241 } 00242 #endif 00243 00244 static connector_status_t dp_fill_file_path(data_point_info_t * const dp_info, char const * const path, char const * const extension) 00245 { 00246 connector_status_t result; 00247 size_t const available_path_bytes = sizeof dp_info->file_path - 1; 00248 char const path_prefix[] = "DataPoint/"; 00249 size_t const path_prefix_bytes = sizeof path_prefix - 1; 00250 size_t const path_bytes = strlen(path); 00251 size_t const extension_bytes = strlen(extension); 00252 size_t const full_path_bytes = path_prefix_bytes + path_bytes + extension_bytes; 00253 00254 if (full_path_bytes < available_path_bytes) 00255 { 00256 strncpy(dp_info->file_path, path_prefix, path_prefix_bytes); 00257 strncpy(&dp_info->file_path[path_prefix_bytes], path, path_bytes); 00258 strncpy(&dp_info->file_path[path_prefix_bytes + path_bytes], extension, extension_bytes); 00259 dp_info->file_path[full_path_bytes] = '\0'; 00260 result = connector_working; 00261 } 00262 else 00263 { 00264 connector_debug_printf("dp_fill_file_path [DataPoint/%s.%s]: file path bytes [%" PRIsize "] exceeds the limit [%" PRIsize "]\n", path, extension, full_path_bytes, available_path_bytes); 00265 result = connector_invalid_data; 00266 } 00267 00268 return result; 00269 } 00270 00271 #if (CONNECTOR_VERSION >= 0x02010000) 00272 static connector_status_t dp_send_message(connector_data_t * const connector_ptr, data_point_info_t * const dp_info, 00273 connector_transport_t const transport, connector_bool_t const response_needed, uint32_t * request_id) 00274 #else 00275 static connector_status_t dp_send_message(connector_data_t * const connector_ptr, data_point_info_t * const dp_info, 00276 connector_transport_t const transport, connector_bool_t const response_needed) 00277 #endif 00278 { 00279 connector_status_t result; 00280 00281 dp_info->header.transport = transport; 00282 dp_info->header.user_context = dp_info; 00283 dp_info->header.path = dp_info->file_path; 00284 dp_info->header.response_required = response_needed; 00285 dp_info->header.content_type = NULL; 00286 dp_info->header.option = connector_data_service_send_option_overwrite; 00287 #if (CONNECTOR_VERSION >= 0x02010000) 00288 dp_info->header.request_id = request_id; 00289 #endif 00290 00291 result = connector_initiate_action(connector_ptr, connector_initiate_send_data, &dp_info->header); 00292 switch (result) 00293 { 00294 case connector_init_error: 00295 case connector_unavailable: 00296 case connector_service_busy: 00297 result = connector_pending; 00298 break; 00299 00300 case connector_success: 00301 result = connector_working; 00302 goto done; 00303 00304 default: 00305 connector_debug_printf("dp_send_message: connector_initiate_action failed [%d]!\n", result); 00306 break; 00307 } 00308 00309 done: 00310 return result; 00311 } 00312 00313 static void * dp_create_dp_info(connector_data_t * const connector_ptr, connector_status_t * result) 00314 { 00315 void * ptr; 00316 00317 *result = malloc_data_buffer(connector_ptr, sizeof(data_point_info_t), named_buffer_id(data_point_block), &ptr); 00318 if (*result != connector_working) 00319 { 00320 connector_debug_printf("dp_create_dp_info: failed to malloc [%d]!\n", *result); 00321 ptr = NULL; 00322 } 00323 00324 return ptr; 00325 } 00326 00327 static connector_status_t dp_process_csv(connector_data_t * const connector_ptr, connector_request_data_point_single_t const * const dp_ptr) 00328 { 00329 connector_status_t result = connector_idle; 00330 data_point_info_t * const dp_info = dp_create_dp_info(connector_ptr, &result); 00331 00332 if (dp_info == NULL) goto done; 00333 00334 dp_info->type = dp_content_type_csv; 00335 dp_info->data.csv.dp_request = dp_ptr; 00336 dp_info->data.csv.current_dp = dp_ptr->point; 00337 dp_info->data.csv.bytes_sent = 0; 00338 dp_info->data.csv.bytes_to_send = 0; 00339 dp_info->data.csv.state = dp_state_data; 00340 00341 result = dp_fill_file_path(dp_info, dp_ptr->path, ".csv"); 00342 if (result != connector_working) goto error; 00343 #if (CONNECTOR_VERSION >= 0x02010000) 00344 result = dp_send_message(connector_ptr, dp_info, dp_ptr->transport, dp_ptr->response_required, dp_ptr->request_id); 00345 #else 00346 result = dp_send_message(connector_ptr, dp_info, dp_ptr->transport, dp_ptr->response_required); 00347 #endif 00348 if (result == connector_working) goto done; 00349 00350 error: 00351 if (result != connector_pending) 00352 result = dp_inform_status(connector_ptr, connector_request_id_data_point_single_status, dp_ptr->transport, 00353 dp_ptr->user_context, connector_session_error_format); 00354 00355 if (free_data_buffer(connector_ptr, named_buffer_id(data_point_block), dp_info) != connector_working) 00356 result = connector_abort; 00357 00358 done: 00359 return result; 00360 } 00361 00362 static connector_status_t dp_process_binary(connector_data_t * const connector_ptr, connector_request_data_point_binary_t const * const bp_ptr) 00363 { 00364 connector_status_t result = connector_idle; 00365 data_point_info_t * const dp_info = dp_create_dp_info(connector_ptr, &result); 00366 00367 if (dp_info == NULL) goto done; 00368 00369 dp_info->type = dp_content_type_binary; 00370 dp_info->data.binary.bp_request = bp_ptr; 00371 dp_info->data.binary.current_bp = bp_ptr->point; 00372 dp_info->data.binary.bytes_to_send = bp_ptr->bytes_used; 00373 00374 result = dp_fill_file_path(dp_info, bp_ptr->path, ".bin"); 00375 if (result != connector_working) goto error; 00376 #if (CONNECTOR_VERSION >= 0x02010000) 00377 result = dp_send_message(connector_ptr, dp_info, bp_ptr->transport, bp_ptr->response_required, bp_ptr->request_id); 00378 #else 00379 result = dp_send_message(connector_ptr, dp_info, bp_ptr->transport, bp_ptr->response_required); 00380 #endif 00381 if (result == connector_working) goto done; 00382 00383 error: 00384 if (result != connector_pending) 00385 result = dp_inform_status(connector_ptr, connector_request_id_data_point_binary_status, bp_ptr->transport, 00386 bp_ptr->user_context, connector_session_error_format); 00387 00388 if (free_data_buffer(connector_ptr, named_buffer_id(data_point_block), dp_info) != connector_working) 00389 result = connector_abort; 00390 00391 done: 00392 return result; 00393 } 00394 00395 static connector_status_t dp_process_request(connector_data_t * const connector_ptr, connector_transport_t const transport) 00396 { 00397 connector_status_t result = connector_idle; 00398 static connector_bool_t process_csv = connector_true; 00399 00400 if (process_csv) 00401 { 00402 if ((data_point_single_pending != NULL) && (data_point_single_pending->transport == transport)) 00403 { 00404 result = dp_process_csv(connector_ptr, data_point_single_pending); 00405 if (result != connector_pending) 00406 { 00407 process_csv = connector_false; 00408 data_point_single_pending = NULL; 00409 goto done; 00410 } 00411 } 00412 } 00413 else 00414 process_csv = connector_true; 00415 00416 if ((data_point_binary_pending != NULL) && (data_point_binary_pending->transport == transport)) 00417 { 00418 result = dp_process_binary(connector_ptr, data_point_binary_pending); 00419 if (result != connector_pending) 00420 data_point_binary_pending = NULL; 00421 } 00422 00423 done: 00424 return result; 00425 } 00426 00427 static size_t dp_process_string(char * const string, char * const buffer, size_t const bytes_available, size_t * bytes_used_ptr) 00428 { 00429 size_t bytes_processed = 0; 00430 char const delimiters[] = {',', '\n', '\r', ' ', '\t'}; 00431 connector_bool_t need_quotes = connector_false; 00432 size_t const delimiters_size = sizeof delimiters; 00433 size_t index; 00434 00435 if ((string == NULL) || (string[0] == '\0')) goto done; 00436 00437 for (index = 0; index < delimiters_size; index++) 00438 { 00439 if (strchr(string, delimiters[index]) != NULL) 00440 { 00441 need_quotes = connector_true; 00442 break; 00443 } 00444 } 00445 00446 { 00447 char * const format = need_quotes ? "\"%s\"" : "%s"; 00448 00449 bytes_processed = connector_snprintf(buffer, bytes_available, format, string); 00450 00451 if (bytes_used_ptr != NULL) 00452 *bytes_used_ptr = need_quotes ? bytes_processed - 2 : bytes_processed; 00453 } 00454 00455 done: 00456 return bytes_processed; 00457 } 00458 00459 static size_t dp_process_data(data_point_info_t * const dp_info, char * const buffer, size_t const bytes_available) 00460 { 00461 connector_data_point_t const * dp_ptr = dp_info->data.csv.current_dp; 00462 connector_request_data_point_single_t const * const dp_request = dp_info->data.csv.dp_request; 00463 size_t bytes_processed = 0; 00464 00465 if (dp_ptr->data.type == connector_data_type_text) 00466 { 00467 bytes_processed = connector_snprintf(buffer, bytes_available, "%s", dp_ptr->data.element.text); 00468 goto done; 00469 } 00470 00471 switch (dp_request->type) 00472 { 00473 case connector_data_point_type_integer: 00474 bytes_processed = connector_snprintf(buffer, bytes_available, "%" PRId32, dp_ptr->data.element.native.int_value); 00475 break; 00476 00477 #if (defined CONNECTOR_HAS_64_BIT_INTEGERS) 00478 case connector_data_point_type_long: 00479 bytes_processed = connector_snprintf(buffer, bytes_available, "%" PRId64, dp_ptr->data.element.native.long_value); 00480 break; 00481 #endif 00482 00483 00484 case connector_data_point_type_string: 00485 { 00486 size_t bytes_copied = 0; 00487 00488 if (dp_info->data.csv.bytes_sent == 0) 00489 dp_info->data.csv.bytes_to_send = strlen(dp_ptr->data.element.native.string_value); 00490 00491 bytes_processed = dp_process_string(&dp_ptr->data.element.native.string_value[dp_info->data.csv.bytes_sent], buffer, bytes_available, &bytes_copied); 00492 00493 dp_info->data.csv.bytes_to_send -= bytes_copied; 00494 dp_info->data.csv.bytes_sent = (dp_info->data.csv.bytes_to_send > 0) ? dp_info->data.csv.bytes_sent + bytes_copied : 0; 00495 break; 00496 } 00497 00498 #if (defined FLOATING_POINT_SUPPORTED) 00499 case connector_data_point_type_float: 00500 bytes_processed = connector_snprintf(buffer, bytes_available, "%f", dp_ptr->data.element.native.float_value); 00501 break; 00502 00503 case connector_data_point_type_double: 00504 bytes_processed = connector_snprintf(buffer, bytes_available, "%lf", dp_ptr->data.element.native.double_value); 00505 break; 00506 #endif 00507 00508 default: 00509 ASSERT_GOTO(connector_false, done); 00510 break; 00511 } 00512 00513 done: 00514 return bytes_processed; 00515 } 00516 00517 static size_t dp_process_time(data_point_info_t * const dp_info, char * const buffer, size_t const bytes_available) 00518 { 00519 connector_data_point_t const * dp_ptr = dp_info->data.csv.current_dp; 00520 size_t bytes_processed = 0; 00521 00522 switch (dp_ptr->time.source) 00523 { 00524 case connector_time_cloud: 00525 break; 00526 00527 case connector_time_local_epoch_fractional: 00528 bytes_processed = connector_snprintf(buffer, bytes_available, "%u%03u", 00529 dp_ptr->time.value.since_epoch_fractional.seconds, 00530 dp_ptr->time.value.since_epoch_fractional.milliseconds); 00531 break; 00532 00533 #if (defined CONNECTOR_HAS_64_BIT_INTEGERS) 00534 case connector_time_local_epoch_whole: 00535 bytes_processed = connector_snprintf(buffer, bytes_available, "%lld", dp_ptr->time.value.since_epoch_whole.milliseconds); 00536 break; 00537 #endif 00538 00539 case connector_time_local_iso8601: 00540 bytes_processed = connector_snprintf(buffer, bytes_available, "%s", dp_ptr->time.value.iso8601_string); 00541 break; 00542 } 00543 00544 return bytes_processed; 00545 } 00546 00547 static size_t dp_process_quality(data_point_info_t * const dp_info, char * const buffer, size_t const bytes_available) 00548 { 00549 connector_data_point_t const * dp_ptr = dp_info->data.csv.current_dp; 00550 size_t bytes_processed = 0; 00551 00552 if (dp_ptr->quality.type != connector_quality_type_ignore) 00553 bytes_processed = connector_snprintf(buffer, bytes_available, "%d", dp_ptr->quality.value); 00554 00555 return bytes_processed; 00556 } 00557 00558 static size_t dp_process_description(data_point_info_t * const dp_info, char * const buffer, size_t const bytes_available) 00559 { 00560 connector_data_point_t const * dp_ptr = dp_info->data.csv.current_dp; 00561 size_t bytes_processed = 0; 00562 00563 if (dp_ptr->description != 0) 00564 bytes_processed = dp_process_string(dp_ptr->description, buffer, bytes_available, NULL); 00565 00566 return bytes_processed; 00567 } 00568 00569 static size_t dp_process_location(data_point_info_t * const dp_info, char * const buffer, size_t const bytes_available) 00570 { 00571 connector_data_point_t const * dp_ptr = dp_info->data.csv.current_dp; 00572 size_t bytes_processed = 0; 00573 00574 switch (dp_ptr->location.type) 00575 { 00576 case connector_location_type_ignore: 00577 break; 00578 00579 case connector_location_type_text: 00580 bytes_processed = connector_snprintf(buffer, bytes_available, "\"%s,%s,%s\"", 00581 dp_ptr->location.value.text.latitude, 00582 dp_ptr->location.value.text.longitude, 00583 dp_ptr->location.value.text.elevation); 00584 break; 00585 00586 #if (defined FLOATING_POINT_SUPPORTED) 00587 case connector_location_type_native: 00588 bytes_processed = connector_snprintf(buffer, bytes_available, "\"%f,%f,%f\"", 00589 dp_ptr->location.value.native.latitude, 00590 dp_ptr->location.value.native.longitude, 00591 dp_ptr->location.value.native.elevation); 00592 break; 00593 #endif 00594 } 00595 00596 return bytes_processed; 00597 } 00598 00599 static size_t dp_process_type(data_point_info_t * const dp_info, char * const buffer, size_t const bytes_available) 00600 { 00601 char const * const type_list[] = {"INTEGER", "LONG", "FLOAT", "DOUBLE", "STRING", "BINARY"}; 00602 connector_request_data_point_single_t const * request = dp_info->data.csv.dp_request; 00603 size_t bytes_processed = 0; 00604 00605 ASSERT_GOTO(asizeof(type_list) > request->type, error); 00606 bytes_processed = connector_snprintf(buffer, bytes_available, "%s", type_list[request->type]); 00607 00608 error: 00609 return bytes_processed; 00610 } 00611 00612 static size_t dp_process_unit(data_point_info_t * const dp_info, char * const buffer, size_t const bytes_available) 00613 { 00614 connector_request_data_point_single_t const * request = dp_info->data.csv.dp_request; 00615 size_t bytes_processed = 0; 00616 00617 if (request->unit != NULL) 00618 bytes_processed = dp_process_string(request->unit, buffer, bytes_available, NULL); 00619 00620 return bytes_processed; 00621 } 00622 00623 static size_t dp_process_forward_to(data_point_info_t * const dp_info, char * const buffer, size_t const bytes_available) 00624 { 00625 connector_request_data_point_single_t const * request = dp_info->data.csv.dp_request; 00626 size_t bytes_processed = 0; 00627 00628 if (request->forward_to != NULL) 00629 bytes_processed = dp_process_string(request->forward_to, buffer, bytes_available, NULL); 00630 00631 return bytes_processed; 00632 } 00633 00634 static size_t dp_update_state(data_point_info_t * const dp_info, char * const buffer) 00635 { 00636 if (dp_info->data.csv.state == dp_state_forward_to) 00637 { 00638 *buffer = '\n'; 00639 dp_info->data.csv.current_dp = dp_info->data.csv.current_dp->next; 00640 dp_info->data.csv.state = dp_state_data; 00641 } 00642 else 00643 { 00644 *buffer = ','; 00645 dp_info->data.csv.state++; 00646 } 00647 00648 return 1; 00649 } 00650 00651 00652 static size_t dp_fill_csv_payload(data_point_info_t * const dp_info, void * const payload, size_t const total_bytes, connector_transport_t transport) 00653 { 00654 size_t bytes_copied = 0; 00655 char * data_ptr = payload; 00656 size_t bytes_remaining = total_bytes; 00657 size_t (* process_fn) (data_point_info_t * const dp_info, char * const buffer, size_t const bytes_available) = NULL; 00658 00659 do 00660 { 00661 switch (dp_info->data.csv.state) 00662 { 00663 case dp_state_data: 00664 process_fn = dp_process_data; 00665 break; 00666 00667 case dp_state_time: 00668 process_fn = dp_process_time; 00669 break; 00670 00671 case dp_state_quality: 00672 process_fn = dp_process_quality; 00673 break; 00674 00675 case dp_state_description: 00676 process_fn = dp_process_description; 00677 break; 00678 00679 case dp_state_location: 00680 process_fn = dp_process_location; 00681 break; 00682 00683 case dp_state_type: 00684 process_fn = dp_process_type; 00685 break; 00686 00687 case dp_state_unit: 00688 process_fn = dp_process_unit; 00689 break; 00690 00691 case dp_state_forward_to: 00692 process_fn = dp_process_forward_to; 00693 break; 00694 } 00695 00696 bytes_copied = process_fn(dp_info, data_ptr, bytes_remaining); 00697 if (bytes_copied > 0) 00698 { 00699 if (bytes_copied >= bytes_remaining) 00700 { 00701 #if (defined CONNECTOR_SHORT_MESSAGE) 00702 /* For SM transports this is a problem because the buffer where the CSV is 00703 * written is preallocated. If the CSV grows to fill the buffer, then it 00704 * is too late. 00705 */ 00706 switch (transport) 00707 { 00708 #if (defined CONNECTOR_TRANSPORT_UDP) 00709 case connector_transport_udp: 00710 #endif 00711 #if (defined CONNECTOR_TRANSPORT_SMS) 00712 case connector_transport_sms: 00713 #endif 00714 connector_debug_printf("WARNING: Not enough space for processing the CSV DataPoint, increase the value of CONNECTOR_SM_MAX_DATA_POINTS_SEGMENTS\n"); 00715 ASSERT(connector_false); 00716 break; 00717 #if (defined CONNECTOR_TRANSPORT_TCP) 00718 case connector_transport_tcp: 00719 #endif 00720 case connector_transport_all: 00721 /* For connector_transport_tcp this is not a problem: once the packet is sent, 00722 * this function will be called again to finish the CSV. */ 00723 break; 00724 } 00725 #else 00726 UNUSED_PARAMETER(transport); 00727 #endif 00728 break; 00729 } 00730 00731 data_ptr += bytes_copied; 00732 bytes_remaining -= bytes_copied; 00733 } 00734 00735 if (dp_info->data.csv.bytes_to_send == 0) 00736 { 00737 size_t const bytes_offset = dp_update_state(dp_info, data_ptr); 00738 00739 bytes_remaining -= bytes_offset; 00740 data_ptr += bytes_offset; 00741 00742 if (dp_info->data.csv.current_dp == NULL) 00743 { 00744 break; 00745 } 00746 } 00747 else 00748 { 00749 break; 00750 } 00751 00752 } while (bytes_remaining > 0); 00753 00754 bytes_copied = total_bytes - bytes_remaining; 00755 00756 return bytes_copied; 00757 } 00758 00759 static connector_callback_status_t dp_handle_data_callback(connector_data_service_send_data_t * const data_ptr) 00760 { 00761 connector_callback_status_t status = connector_callback_abort; 00762 data_point_info_t * const dp_info = data_ptr->user_context; 00763 00764 ASSERT_GOTO(dp_info != NULL, error); 00765 switch (dp_info->type) 00766 { 00767 case dp_content_type_binary: 00768 if (dp_info->data.binary.bytes_to_send > data_ptr->bytes_available) 00769 { 00770 data_ptr->bytes_used = data_ptr->bytes_available; 00771 data_ptr->more_data = connector_true; 00772 } 00773 else 00774 { 00775 data_ptr->bytes_used = dp_info->data.binary.bytes_to_send; 00776 data_ptr->more_data = connector_false; 00777 } 00778 00779 memcpy(data_ptr->buffer, dp_info->data.binary.current_bp, data_ptr->bytes_used); 00780 dp_info->data.binary.current_bp += data_ptr->bytes_used; 00781 dp_info->data.binary.bytes_to_send -= data_ptr->bytes_used; 00782 break; 00783 00784 case dp_content_type_csv: 00785 data_ptr->bytes_used = dp_fill_csv_payload(dp_info, data_ptr->buffer, data_ptr->bytes_available, data_ptr->transport); 00786 data_ptr->more_data = (dp_info->data.csv.current_dp == NULL) ? connector_false : connector_true; 00787 break; 00788 } 00789 00790 status = connector_callback_continue; 00791 00792 error: 00793 return status; 00794 } 00795 00796 static connector_callback_status_t dp_handle_response_callback(connector_data_t * const connector_ptr, connector_data_service_send_response_t * const data_ptr) 00797 { 00798 connector_callback_status_t callback_status = connector_callback_abort; 00799 data_point_info_t * const dp_info = data_ptr->user_context; 00800 connector_request_id_t request_id; 00801 connector_data_point_response_t user_data; 00802 00803 ASSERT_GOTO(dp_info != NULL, error); 00804 switch (dp_info->type) 00805 { 00806 case dp_content_type_binary: 00807 user_data.user_context = dp_info->data.binary.bp_request->user_context; 00808 request_id.data_point_request = connector_request_id_data_point_binary_response; 00809 break; 00810 00811 case dp_content_type_csv: 00812 user_data.user_context = dp_info->data.csv.dp_request->user_context; 00813 request_id.data_point_request = connector_request_id_data_point_single_response; 00814 break; 00815 } 00816 00817 user_data.transport = data_ptr->transport; 00818 user_data.hint = data_ptr->hint; 00819 switch (data_ptr->response) 00820 { 00821 case connector_data_service_send_response_success: 00822 user_data.response = connector_data_point_response_success; 00823 break; 00824 00825 case connector_data_service_send_response_bad_request: 00826 user_data.response = connector_data_point_response_bad_request; 00827 break; 00828 00829 case connector_data_service_send_response_unavailable: 00830 user_data.response = connector_data_point_response_unavailable; 00831 break; 00832 00833 case connector_data_service_send_response_cloud_error: 00834 user_data.response = connector_data_point_response_cloud_error; 00835 break; 00836 default: 00837 ASSERT(connector_false); 00838 } 00839 00840 callback_status = connector_callback(connector_ptr->callback, connector_class_id_data_point, request_id, &user_data); 00841 if (callback_status == connector_callback_busy) goto error; 00842 00843 #if (CONNECTOR_VERSION < 0x02010000) 00844 if (free_data_buffer(connector_ptr, named_buffer_id(data_point_block), dp_info) != connector_working) 00845 callback_status = connector_callback_abort; 00846 #endif 00847 00848 error: 00849 return callback_status; 00850 } 00851 00852 static connector_callback_status_t dp_handle_status_callback(connector_data_t * const connector_ptr, connector_data_service_status_t * const data_ptr) 00853 { 00854 connector_callback_status_t callback_status = connector_callback_abort; 00855 data_point_info_t * const dp_info = data_ptr->user_context; 00856 connector_request_id_t request_id; 00857 connector_data_point_status_t user_data; 00858 00859 ASSERT_GOTO(dp_info != NULL, error); 00860 switch (dp_info->type) 00861 { 00862 case dp_content_type_binary: 00863 user_data.user_context = dp_info->data.binary.bp_request->user_context; 00864 request_id.data_point_request = connector_request_id_data_point_binary_status; 00865 break; 00866 00867 case dp_content_type_csv: 00868 user_data.user_context = dp_info->data.csv.dp_request->user_context; 00869 request_id.data_point_request = connector_request_id_data_point_single_status; 00870 break; 00871 } 00872 00873 user_data.transport = data_ptr->transport; 00874 user_data.session_error = data_ptr->session_error; 00875 switch (data_ptr->status) 00876 { 00877 case connector_data_service_status_complete: 00878 user_data.status = connector_data_point_status_complete; 00879 break; 00880 00881 case connector_data_service_status_cancel: 00882 user_data.status = connector_data_point_status_cancel; 00883 break; 00884 00885 case connector_data_service_status_timeout: 00886 user_data.status = connector_data_point_status_timeout; 00887 break; 00888 00889 case connector_data_service_status_session_error: 00890 user_data.status = connector_data_point_status_session_error; 00891 break; 00892 00893 default: 00894 user_data.status = connector_data_point_status_session_error; 00895 break; 00896 } 00897 00898 callback_status = connector_callback(connector_ptr->callback, connector_class_id_data_point, request_id, &user_data); 00899 if (callback_status == connector_callback_busy) goto error; 00900 00901 if (free_data_buffer(connector_ptr, named_buffer_id(data_point_block), dp_info) != connector_working) 00902 callback_status = connector_callback_abort; 00903 00904 error: 00905 return callback_status; 00906 } 00907 00908 #if (defined CONNECTOR_SHORT_MESSAGE) 00909 static connector_callback_status_t dp_handle_length_callback(connector_data_service_length_t * const data_ptr) 00910 { 00911 connector_callback_status_t status = connector_callback_abort; 00912 data_point_info_t * const dp_info = data_ptr->user_context; 00913 00914 ASSERT_GOTO(dp_info != NULL, error); 00915 switch (dp_info->type) 00916 { 00917 case dp_content_type_binary: 00918 data_ptr->total_bytes = dp_info->data.binary.bytes_to_send; 00919 break; 00920 00921 case dp_content_type_csv: 00922 { 00923 size_t const sm_header_bytes = 6; 00924 #if (defined CONNECTOR_TRANSPORT_UDP) 00925 size_t const transport_layer_bytes = (data_ptr->transport == connector_transport_udp) ? 18 : 10; 00926 size_t const max_packet_size = (data_ptr->transport == connector_transport_udp) ? SM_PACKET_SIZE_UDP : SM_PACKET_SIZE_SMS; 00927 #else 00928 size_t const transport_layer_bytes = 10; 00929 size_t const max_packet_size = SM_PACKET_SIZE_SMS; 00930 #endif 00931 size_t const max_payload_bytes = max_packet_size - (sm_header_bytes + transport_layer_bytes); 00932 #if !(defined CONNECTOR_SM_MAX_DATA_POINTS_SEGMENTS) 00933 #define CONNECTOR_SM_MAX_DATA_POINTS_SEGMENTS 1 00934 #endif 00935 00936 data_ptr->total_bytes = max_payload_bytes * CONNECTOR_SM_MAX_DATA_POINTS_SEGMENTS; 00937 break; 00938 } 00939 } 00940 00941 status = connector_callback_continue; 00942 00943 error: 00944 return status; 00945 } 00946 #endif 00947 00948 static connector_callback_status_t dp_handle_callback(connector_data_t * const connector_ptr, connector_request_id_data_service_t const ds_request_id, void * const data) 00949 { 00950 connector_callback_status_t status; 00951 00952 switch (ds_request_id) 00953 { 00954 case connector_request_id_data_service_send_data: 00955 status = dp_handle_data_callback(data); 00956 break; 00957 00958 case connector_request_id_data_service_send_response: 00959 status = dp_handle_response_callback(connector_ptr, data); 00960 break; 00961 00962 case connector_request_id_data_service_send_status: 00963 status = dp_handle_status_callback(connector_ptr, data); 00964 break; 00965 00966 #if (defined CONNECTOR_SHORT_MESSAGE) 00967 case connector_request_id_data_service_send_length: 00968 status = dp_handle_length_callback(data); 00969 break; 00970 #endif 00971 00972 default: 00973 status = connector_callback_unrecognized; 00974 break; 00975 } 00976 00977 return status; 00978 } 00979
Generated on Tue Jul 12 2022 19:18:38 by
1.7.2