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

« Back to documentation index

Show/hide line numbers connector_data_point.h Source File

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