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.
rci_binary_output.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 void rci_set_output_error(rci_t * const rci, unsigned int const id, char const * const hint, rci_output_state_t state) 00013 { 00014 rci_global_error(rci, id, hint); 00015 set_rci_output_state(rci, state); 00016 state_call(rci, rci_parser_state_output); 00017 } 00018 00019 static connector_bool_t rci_output_data(rci_t * const rci, rci_buffer_t * const output, uint8_t const * const data, size_t const bytes) 00020 { 00021 connector_bool_t const overflow = connector_bool(rci_buffer_remaining(output) < bytes); 00022 00023 if (overflow) 00024 { 00025 rci->status = rci_status_flush_output; 00026 } 00027 else 00028 { 00029 memcpy(rci_buffer_position(output), data, bytes); 00030 rci_buffer_advance(output, bytes); 00031 } 00032 00033 return overflow; 00034 } 00035 00036 static size_t get_bytes_followed(uint32_t value) 00037 { 00038 /* Bytes needed for the value: 00039 * 1 byte is 0 to 0x7F 00040 * 2 bytes is 0 to 0x1FFF 00041 * 3 bytes is 0 to 0xFFFF 00042 * 5 bytes is 0 to 0xFFFFFFFF 00043 * 00044 * Get additional bytes needed according to the value. 00045 */ 00046 size_t bytes = 0; 00047 if (value <= UINT32_C(0x7F)) 00048 { 00049 bytes = 0; 00050 } 00051 else if (value < UINT32_C(0x2000)) 00052 { 00053 bytes = 1; 00054 } 00055 else if (value < UINT32_C(0x10000)) 00056 { 00057 bytes = 2; 00058 } 00059 else 00060 { 00061 bytes = 4; 00062 } 00063 00064 return bytes; 00065 } 00066 00067 static connector_bool_t rci_output_uint32(rci_t * const rci, uint32_t const value) 00068 { 00069 connector_bool_t overflow; 00070 size_t const bytes_follow = get_bytes_followed(value); 00071 00072 rci_buffer_t * const output = &rci->buffer.output; 00073 size_t const total_bytes = bytes_follow + 1; 00074 00075 overflow = connector_bool(rci_buffer_remaining(output) < total_bytes); 00076 if (overflow) 00077 { 00078 rci->status = rci_status_flush_output; 00079 } 00080 else 00081 { 00082 uint8_t * const rci_ber = rci_buffer_position(output); 00083 00084 /* 00085 * opcode 00086 * 7 6 5 4 3 2 1 0 bit 00087 * --------------- 00088 * 0 X X X X X X X (0 : 0x7F) 00089 * 1 0 0 X X X X X + 1 byte followed (0: 0x1FFF) 00090 * 1 0 1 - - - 0 0 + 2 bytes followed (0: 0xFFFF) 00091 * 1 0 1 - - - 0 1 + 4 bytes followed (0: 0xFFFFFFFF) 00092 * 1 0 1 - - - 1 0 + 8 bytes followed (0: 0xFFFFFFFFFFFFFFFF) 00093 * 1 1 0 - - - - - Reserved 00094 * 1 1 1 0 0 0 0 0 NONUM (No Value) 00095 * 1 1 1 0 0 0 0 1 TRM (Terminator) 00096 */ 00097 switch (total_bytes) 00098 { 00099 case record_bytes(rci_ber): 00100 { 00101 /* one byte with range [0, 0x7F] */ 00102 uint8_t const data = (uint8_t)value; 00103 message_store_u8(rci_ber, value, data); 00104 break; 00105 } 00106 case record_bytes(rci_ber_u8): 00107 { 00108 #define MAX_ONE_BYTE_FOLLOW_VALUE UINT32_C(0x1FFF) 00109 00110 /* two bytes with range [0, 0x1FFF] */ 00111 uint8_t * const rci_ber_u8 = rci_ber; 00112 uint8_t data; 00113 uint16_t data_value = (uint16_t)value; 00114 00115 ASSERT(value <= MAX_ONE_BYTE_FOLLOW_VALUE); 00116 00117 data = BINARY_RCI_SIZE_ALTERNATE_FLAG; 00118 data |= HIGH8(data_value); 00119 message_store_u8(rci_ber_u8, opcode, data); 00120 00121 data = LOW8(data_value); 00122 message_store_u8(rci_ber_u8, value, data); 00123 00124 #undef MAX_ONE_BYTE_FOLLOW_VALUE 00125 break; 00126 } 00127 case record_bytes(rci_ber_u16): 00128 { 00129 /* 3 bytes with range [0, 0xFFFF] */ 00130 uint8_t * const rci_ber_u16 = rci_ber; 00131 uint8_t const opcode = BINARY_RCI_SET_MULTI_FOLLOW_BYTES(binary_rci_two_follow_byte); 00132 uint16_t const data = (uint16_t)value; 00133 00134 message_store_u8(rci_ber_u16, opcode, opcode); 00135 message_store_be16(rci_ber_u16, value, data); 00136 break; 00137 } 00138 case record_bytes(rci_ber_u32): 00139 { 00140 /* 5 bytes with range [0, 0xFFFFFFFF */ 00141 uint8_t * const rci_ber_u32 = rci_ber; 00142 uint8_t const opcode = BINARY_RCI_SET_MULTI_FOLLOW_BYTES(binary_rci_four_follow_byte); 00143 00144 message_store_u8(rci_ber_u32, opcode, opcode); 00145 message_store_be32(rci_ber_u32, value, value); 00146 00147 break; 00148 00149 } 00150 } 00151 rci_buffer_advance(output, total_bytes); 00152 } 00153 return overflow; 00154 } 00155 00156 static connector_bool_t rci_output_string(rci_t * const rci, char const * const string, size_t const length) 00157 { 00158 00159 rci_buffer_t * const output = &rci->buffer.output; 00160 connector_bool_t overflow = connector_true; 00161 00162 /* output: | length | string | */ 00163 if (!rcistr_valid(&rci->output.content)) 00164 { 00165 /* set up the data and its length */ 00166 overflow = rci_output_uint32(rci, length); 00167 if (overflow) goto done; 00168 rci->output.content.data = (uint8_t *)string; 00169 rci->output.content.length = length; 00170 } 00171 00172 if (rci->output.content.length > 0) 00173 { 00174 size_t const avail_bytes = rci_buffer_remaining(output); 00175 size_t const write_bytes = (rci->output.content.length < avail_bytes) ? rci->output.content.length : avail_bytes; 00176 00177 overflow = rci_output_data(rci, output, (uint8_t *)rci->output.content.data, write_bytes); 00178 if (overflow) goto done; 00179 00180 rci->output.content.data += write_bytes; 00181 rci->output.content.length -= write_bytes; 00182 00183 } 00184 00185 if (rci->output.content.length > 0) 00186 { 00187 overflow = connector_true; 00188 rci->status = rci_status_flush_output; 00189 } 00190 else 00191 { 00192 clear_rcistr(&rci->output.content); 00193 } 00194 00195 done: 00196 return overflow; 00197 } 00198 00199 #if defined RCI_PARSER_USES_IPV4 00200 static connector_bool_t rci_output_ipv4(rci_t * const rci, char const * const string) 00201 { 00202 rci_buffer_t * const output = &rci->buffer.output; 00203 connector_bool_t overflow = connector_true; 00204 size_t const avail_bytes = rci_buffer_remaining(output); 00205 00206 if (avail_bytes < sizeof(uint32_t)) 00207 { 00208 goto done; 00209 } 00210 else 00211 { 00212 uint32_t ipv4 = 0; 00213 uint8_t * const rci_ber_u32 = rci_buffer_position(output); 00214 int dot_count = 0; 00215 size_t i; 00216 size_t length = strlen(string); 00217 char aux_string[4] = {'\0', '\0', '\0', '\0'}; /* Three chars plus terminator. */ 00218 00219 size_t index = 0; 00220 00221 for (i = 0; i < length; i++) 00222 { 00223 if (index > sizeof(aux_string) - 1) 00224 break; 00225 00226 if (string[i] != '.') 00227 { 00228 aux_string[index++] = string[i]; 00229 } 00230 00231 if (string[i] == '.' || i == (length -1)) 00232 { 00233 long int val; 00234 char * endptr; 00235 00236 val = strtol(aux_string, &endptr, 10); 00237 if (endptr == NULL || *endptr != '\0' || val < 0 || val > 255) 00238 { 00239 break; 00240 } 00241 00242 ipv4 = (ipv4 << 8) | val; 00243 dot_count++; 00244 index = 0; 00245 memset(aux_string, '\0', sizeof aux_string); 00246 } 00247 } 00248 if (dot_count != 4) 00249 { 00250 connector_request_id_t request_id; 00251 request_id.remote_config_request = connector_request_id_remote_config_group_process; 00252 notify_error_status(rci->service_data->connector_ptr->callback, connector_class_id_remote_config, request_id, connector_invalid_data_range); 00253 rci->status = rci_status_error; 00254 overflow = connector_false; 00255 connector_debug_printf("Invalid IPv4 \"%s\"\n", string); 00256 goto done; 00257 } 00258 00259 message_store_u8(rci_ber_u32, opcode, sizeof ipv4); 00260 message_store_be32(rci_ber_u32, value, ipv4); 00261 00262 rci_buffer_advance(output, record_bytes(rci_ber_u32)); 00263 00264 overflow = connector_false; 00265 } 00266 00267 done: 00268 return overflow; 00269 } 00270 #endif 00271 00272 static connector_bool_t rci_output_uint8(rci_t * const rci, uint8_t const value) 00273 { 00274 uint8_t const data = value; 00275 rci_buffer_t * const output = &rci->buffer.output; 00276 00277 return rci_output_data(rci, output, &data, sizeof data); 00278 } 00279 00280 #if defined RCI_PARSER_USES_FLOAT 00281 static connector_bool_t rci_output_float(rci_t * const rci, float const value) 00282 { 00283 float const float_value = value; 00284 uint32_t float_integer; 00285 00286 ASSERT(sizeof value == sizeof float_integer); 00287 00288 memcpy(&float_integer, &float_value, sizeof float_integer); 00289 00290 return rci_output_uint32(rci, float_integer); 00291 } 00292 #endif 00293 00294 #define rci_output_no_value(rci) rci_output_uint8((rci), BINARY_RCI_NO_VALUE) 00295 #define rci_output_terminator(rci) rci_output_uint8((rci), BINARY_RCI_TERMINATOR) 00296 00297 static void rci_output_command_id(rci_t * const rci) 00298 { 00299 connector_remote_config_t const * const remote_config = &rci->shared.callback_data; 00300 uint32_t command_id = 0; 00301 00302 switch (rci->shared.callback_data.group.type) 00303 { 00304 case connector_remote_group_setting: 00305 switch (rci->shared.callback_data.action) 00306 { 00307 case connector_remote_action_set: 00308 command_id = rci_command_set_setting; 00309 break; 00310 case connector_remote_action_query: 00311 command_id = rci_command_query_setting; 00312 break; 00313 } 00314 break; 00315 case connector_remote_group_state: 00316 switch (rci->shared.callback_data.action) 00317 { 00318 case connector_remote_action_set: 00319 command_id = rci_command_set_state; 00320 break; 00321 case connector_remote_action_query: 00322 command_id = rci_command_query_state; 00323 break; 00324 } 00325 break; 00326 } 00327 00328 { 00329 connector_bool_t const overflow = rci_output_uint32(rci, command_id); 00330 00331 if (!overflow) 00332 { 00333 if (remote_config->error_id != connector_success) 00334 state_call(rci, rci_parser_state_error); 00335 else 00336 state_call(rci, rci_parser_state_traverse); 00337 } 00338 } 00339 00340 return; 00341 } 00342 00343 static void rci_output_group_id(rci_t * const rci) 00344 { 00345 connector_remote_config_t const * const remote_config = &rci->shared.callback_data; 00346 uint32_t encoding_data; 00347 00348 if (!have_group_id(rci)) 00349 { 00350 state_call(rci, rci_parser_state_error); 00351 goto done; 00352 } 00353 00354 encoding_data = encode_group_id(get_group_id(rci)); 00355 00356 if (get_group_index(rci) > 1) 00357 encoding_data |= BINARY_RCI_ATTRIBUTE_BIT; 00358 00359 { 00360 connector_bool_t const overflow = rci_output_uint32(rci, encoding_data); 00361 00362 if (!overflow) 00363 { 00364 if (remote_config->error_id != connector_success) 00365 state_call(rci, rci_parser_state_error); 00366 else 00367 set_rci_output_state(rci, rci_output_state_group_attribute); 00368 } 00369 } 00370 00371 done: 00372 return; 00373 } 00374 00375 static connector_bool_t encode_attribute(rci_t * const rci, unsigned int const index) 00376 { 00377 uint32_t encoding_data; 00378 connector_bool_t overflow = connector_false; 00379 00380 if (index > 1) 00381 { 00382 /* attribute output 00383 * bit |7 | 6 5 | 4 3 2 1 0| 00384 * |x | 0 1 | - index -| 00385 */ 00386 #define BINARY_RCI_ATTRIBUTE_INDEX_MAX 31 00387 #define BINARY_RCI_ATTRIBUTE_TYPE_INDEX 0x20 00388 00389 ASSERT(index <= BINARY_RCI_ATTRIBUTE_INDEX_MAX); 00390 encoding_data = index | BINARY_RCI_ATTRIBUTE_TYPE_INDEX; 00391 00392 overflow = rci_output_uint32(rci, encoding_data); 00393 } 00394 00395 return overflow; 00396 } 00397 00398 static void rci_output_group_attribute(rci_t * const rci) 00399 { 00400 unsigned int const index = get_group_index(rci); 00401 connector_bool_t overflow = encode_attribute(rci, index); 00402 00403 if (!overflow) 00404 state_call(rci, rci_parser_state_traverse); 00405 } 00406 00407 00408 static void rci_output_field_id(rci_t * const rci) 00409 { 00410 connector_remote_config_t const * const remote_config = &rci->shared.callback_data; 00411 00412 if (!have_element_id(rci)) 00413 { 00414 state_call(rci, rci_parser_state_error); 00415 goto done; 00416 } 00417 00418 { 00419 /* output field id */ 00420 uint32_t id = encode_element_id(get_element_id(rci)); 00421 00422 if (remote_config->error_id != connector_success) id |= BINARY_RCI_FIELD_TYPE_INDICATOR_BIT; 00423 00424 { 00425 connector_bool_t const overflow = rci_output_uint32(rci, id); 00426 00427 if (overflow) goto done; 00428 00429 if (remote_config->error_id != connector_success) 00430 state_call(rci, rci_parser_state_error); 00431 else 00432 set_rci_output_state(rci, rci_output_state_field_value); 00433 } 00434 00435 } 00436 00437 done: 00438 return; 00439 } 00440 00441 00442 static void rci_output_field_value(rci_t * const rci) 00443 { 00444 connector_group_element_t const * const element = get_current_element(rci); 00445 connector_element_value_type_t const type = element->type; 00446 00447 connector_bool_t overflow = connector_false; 00448 00449 00450 switch (rci->shared.callback_data.action) 00451 { 00452 case connector_remote_action_set: 00453 overflow = rci_output_no_value(rci); 00454 goto done; 00455 00456 case connector_remote_action_query: 00457 break; 00458 } 00459 00460 switch (type) 00461 { 00462 #if defined RCI_PARSER_USES_STRINGS 00463 00464 #if defined RCI_PARSER_USES_STRING 00465 case connector_element_type_string: 00466 #endif 00467 00468 #if defined RCI_PARSER_USES_MULTILINE_STRING 00469 case connector_element_type_multiline_string: 00470 #endif 00471 00472 #if defined RCI_PARSER_USES_PASSWORD 00473 case connector_element_type_password: 00474 #endif 00475 00476 #if defined RCI_PARSER_USES_FQDNV4 00477 case connector_element_type_fqdnv4: 00478 #endif 00479 00480 #if defined RCI_PARSER_USES_FQDNV6 00481 case connector_element_type_fqdnv6: 00482 #endif 00483 00484 #if defined RCI_PARSER_USES_DATETIME 00485 case connector_element_type_datetime: 00486 #endif 00487 ASSERT(rci->shared.value.string_value != NULL); 00488 overflow = rci_output_string(rci, rci->shared.value.string_value, strlen(rci->shared.value.string_value)); 00489 break; 00490 #endif 00491 00492 #if defined RCI_PARSER_USES_IPV4 00493 case connector_element_type_ipv4: 00494 ASSERT(rci->shared.value.string_value != NULL); 00495 overflow = rci_output_ipv4(rci, rci->shared.value.string_value); 00496 break; 00497 #endif 00498 00499 #if defined RCI_PARSER_USES_INT32 00500 case connector_element_type_int32: 00501 overflow = rci_output_uint32(rci, rci->shared.value.signed_integer_value); 00502 break; 00503 #endif 00504 00505 #if (defined RCI_PARSER_USES_UNSIGNED_INTEGER) 00506 #if defined RCI_PARSER_USES_UINT32 00507 case connector_element_type_uint32: 00508 #endif 00509 00510 #if defined RCI_PARSER_USES_HEX32 00511 case connector_element_type_hex32: 00512 #endif 00513 00514 #if defined RCI_PARSER_USES_0X_HEX32 00515 case connector_element_type_0x_hex32: 00516 #endif 00517 00518 overflow = rci_output_uint32(rci, rci->shared.value.unsigned_integer_value); 00519 break; 00520 #endif 00521 00522 #if defined RCI_PARSER_USES_FLOAT 00523 case connector_element_type_float: 00524 overflow = rci_output_float(rci, rci->shared.value.float_value); 00525 break; 00526 #endif 00527 00528 #if defined RCI_PARSER_USES_ENUM 00529 case connector_element_type_enum: 00530 overflow = rci_output_uint32(rci, rci->shared.value.enum_value); 00531 break; 00532 #endif 00533 00534 #if defined RCI_PARSER_USES_ON_OFF 00535 case connector_element_type_on_off: 00536 overflow = rci_output_uint32(rci, rci->shared.value.on_off_value); 00537 break; 00538 #endif 00539 00540 #if defined RCI_PARSER_USES_BOOLEAN 00541 case connector_element_type_boolean: 00542 overflow = rci_output_uint32(rci, rci->shared.value.boolean_value); 00543 break; 00544 #endif 00545 } 00546 00547 done: 00548 if (!overflow) 00549 state_call(rci, rci_parser_state_traverse); 00550 00551 } 00552 00553 static void rci_output_field_terminator(rci_t * const rci) 00554 { 00555 connector_remote_config_t const * const remote_config = &rci->shared.callback_data; 00556 00557 connector_bool_t const overflow = rci_output_terminator(rci); 00558 if (!overflow) 00559 { 00560 invalidate_element_id(rci); 00561 00562 if (remote_config->error_id != connector_success) 00563 state_call(rci, rci_parser_state_error); 00564 else 00565 state_call(rci, rci_parser_state_traverse); 00566 } 00567 return; 00568 } 00569 00570 static void rci_output_group_terminator(rci_t * const rci) 00571 { 00572 connector_remote_config_t const * const remote_config = &rci->shared.callback_data; 00573 00574 if (remote_config->error_id != connector_success) 00575 { 00576 state_call(rci, rci_parser_state_error); 00577 } 00578 else 00579 { 00580 connector_bool_t const overflow = rci_output_terminator(rci); 00581 if (overflow) goto done; 00582 00583 set_rci_output_state(rci, rci_output_state_response_done); 00584 } 00585 00586 invalidate_group_id(rci); 00587 00588 done: 00589 return; 00590 } 00591 00592 static void rci_generate_output(rci_t * const rci) 00593 { 00594 rci_buffer_t * const output = &rci->buffer.output; 00595 00596 if ((rci_buffer_remaining(output) != 0)) 00597 { 00598 rci_debug_printf("output: %s\n", rci_output_state_t_as_string(rci->output.state)); 00599 00600 switch (rci->output.state) 00601 { 00602 case rci_output_state_command_id: 00603 rci_output_command_id(rci); 00604 break; 00605 00606 case rci_output_state_group_id: 00607 rci_output_group_id(rci); 00608 break; 00609 00610 case rci_output_state_group_attribute: 00611 rci_output_group_attribute(rci); 00612 break; 00613 00614 case rci_output_state_field_id: 00615 rci_output_field_id(rci); 00616 break; 00617 00618 case rci_output_state_field_value: 00619 rci_output_field_value(rci); 00620 break; 00621 00622 case rci_output_state_field_terminator: 00623 rci_output_field_terminator(rci); 00624 break; 00625 00626 case rci_output_state_group_terminator: 00627 rci_output_group_terminator(rci); 00628 break; 00629 00630 case rci_output_state_response_done: 00631 00632 if (get_rci_input_state(rci) == rci_input_state_done) 00633 { 00634 trigger_rci_callback(rci, connector_request_id_remote_config_session_end); 00635 set_rci_output_state(rci, rci_output_state_done); 00636 } 00637 else 00638 { 00639 state_call(rci, rci_parser_state_input); 00640 set_rci_input_state(rci, rci_input_state_command_id); 00641 } 00642 break; 00643 00644 case rci_output_state_done: 00645 { 00646 connector_remote_config_t const * const remote_config = &rci->shared.callback_data; 00647 if (remote_config->error_id != connector_success) 00648 state_call(rci, rci_parser_state_error); 00649 else 00650 rci->status = rci_status_complete; 00651 break; 00652 } 00653 } 00654 } 00655 else if ((rci_buffer_used(&rci->buffer.output) > 0) && (rci->status == rci_status_busy)) 00656 { 00657 /* We are here since we have no space left for more output data and we have output data waiting to be sent. 00658 So set up the state to send out the output data and come back to rci */ 00659 00660 rci->status = rci_status_flush_output; 00661 } 00662 00663 00664 #if defined RCI_DEBUG 00665 { 00666 size_t const bytes = rci_buffer_used(&rci->buffer.output); 00667 if (bytes > 0) 00668 { 00669 connector_debug_hexvalue("Response", rci->buffer.output.start, bytes); 00670 } 00671 } 00672 #endif 00673 00674 return; 00675 } 00676 00677
Generated on Tue Jul 12 2022 19:18:38 by
1.7.2