Etherios Cloud Connector very first porting for mbed. Tested in an LPC1768
Etherios Cloud Connector for Embedded v2.1.0.3 library for mbed. Early porting.
This port is centered mainly in the platform code. So it should work properly with the provided examples of send_data, device_request, data_points, RCI and firmware_update (stub implementation, not a real one... yet ;-)). Filesystem is not implemented yet, and some examples might need changes.
To run, it needs the following libraries: - mbed - mbed-rtos - EthernetInterface
Find more information (and the source code!) about Etherios Cloud Connector for Embedded here: http://www.etherios.com/products/devicecloud/support/connector and in: http://www.etherios.com
Diff: private/rci_binary_output.h
- Revision:
- 0:1c358ea10753
diff -r 000000000000 -r 1c358ea10753 private/rci_binary_output.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/private/rci_binary_output.h Tue Dec 03 13:34:02 2013 +0000 @@ -0,0 +1,677 @@ +/* + * Copyright (c) 2013 Digi International Inc., + * All rights not expressly granted are reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 + * ======================================================================= + */ +static void rci_set_output_error(rci_t * const rci, unsigned int const id, char const * const hint, rci_output_state_t state) +{ + rci_global_error(rci, id, hint); + set_rci_output_state(rci, state); + state_call(rci, rci_parser_state_output); +} + +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) +{ + connector_bool_t const overflow = connector_bool(rci_buffer_remaining(output) < bytes); + + if (overflow) + { + rci->status = rci_status_flush_output; + } + else + { + memcpy(rci_buffer_position(output), data, bytes); + rci_buffer_advance(output, bytes); + } + + return overflow; +} + +static size_t get_bytes_followed(uint32_t value) +{ + /* Bytes needed for the value: + * 1 byte is 0 to 0x7F + * 2 bytes is 0 to 0x1FFF + * 3 bytes is 0 to 0xFFFF + * 5 bytes is 0 to 0xFFFFFFFF + * + * Get additional bytes needed according to the value. + */ + size_t bytes = 0; + if (value <= UINT32_C(0x7F)) + { + bytes = 0; + } + else if (value < UINT32_C(0x2000)) + { + bytes = 1; + } + else if (value < UINT32_C(0x10000)) + { + bytes = 2; + } + else + { + bytes = 4; + } + + return bytes; +} + +static connector_bool_t rci_output_uint32(rci_t * const rci, uint32_t const value) +{ + connector_bool_t overflow; + size_t const bytes_follow = get_bytes_followed(value); + + rci_buffer_t * const output = &rci->buffer.output; + size_t const total_bytes = bytes_follow + 1; + + overflow = connector_bool(rci_buffer_remaining(output) < total_bytes); + if (overflow) + { + rci->status = rci_status_flush_output; + } + else + { + uint8_t * const rci_ber = rci_buffer_position(output); + + /* + * opcode + * 7 6 5 4 3 2 1 0 bit + * --------------- + * 0 X X X X X X X (0 : 0x7F) + * 1 0 0 X X X X X + 1 byte followed (0: 0x1FFF) + * 1 0 1 - - - 0 0 + 2 bytes followed (0: 0xFFFF) + * 1 0 1 - - - 0 1 + 4 bytes followed (0: 0xFFFFFFFF) + * 1 0 1 - - - 1 0 + 8 bytes followed (0: 0xFFFFFFFFFFFFFFFF) + * 1 1 0 - - - - - Reserved + * 1 1 1 0 0 0 0 0 NONUM (No Value) + * 1 1 1 0 0 0 0 1 TRM (Terminator) + */ + switch (total_bytes) + { + case record_bytes(rci_ber): + { + /* one byte with range [0, 0x7F] */ + uint8_t const data = (uint8_t)value; + message_store_u8(rci_ber, value, data); + break; + } + case record_bytes(rci_ber_u8): + { + #define MAX_ONE_BYTE_FOLLOW_VALUE UINT32_C(0x1FFF) + + /* two bytes with range [0, 0x1FFF] */ + uint8_t * const rci_ber_u8 = rci_ber; + uint8_t data; + uint16_t data_value = (uint16_t)value; + + ASSERT(value <= MAX_ONE_BYTE_FOLLOW_VALUE); + + data = BINARY_RCI_SIZE_ALTERNATE_FLAG; + data |= HIGH8(data_value); + message_store_u8(rci_ber_u8, opcode, data); + + data = LOW8(data_value); + message_store_u8(rci_ber_u8, value, data); + + #undef MAX_ONE_BYTE_FOLLOW_VALUE + break; + } + case record_bytes(rci_ber_u16): + { + /* 3 bytes with range [0, 0xFFFF] */ + uint8_t * const rci_ber_u16 = rci_ber; + uint8_t const opcode = BINARY_RCI_SET_MULTI_FOLLOW_BYTES(binary_rci_two_follow_byte); + uint16_t const data = (uint16_t)value; + + message_store_u8(rci_ber_u16, opcode, opcode); + message_store_be16(rci_ber_u16, value, data); + break; + } + case record_bytes(rci_ber_u32): + { + /* 5 bytes with range [0, 0xFFFFFFFF */ + uint8_t * const rci_ber_u32 = rci_ber; + uint8_t const opcode = BINARY_RCI_SET_MULTI_FOLLOW_BYTES(binary_rci_four_follow_byte); + + message_store_u8(rci_ber_u32, opcode, opcode); + message_store_be32(rci_ber_u32, value, value); + + break; + + } + } + rci_buffer_advance(output, total_bytes); + } + return overflow; +} + +static connector_bool_t rci_output_string(rci_t * const rci, char const * const string, size_t const length) +{ + + rci_buffer_t * const output = &rci->buffer.output; + connector_bool_t overflow = connector_true; + + /* output: | length | string | */ + if (!rcistr_valid(&rci->output.content)) + { + /* set up the data and its length */ + overflow = rci_output_uint32(rci, length); + if (overflow) goto done; + rci->output.content.data = (uint8_t *)string; + rci->output.content.length = length; + } + + if (rci->output.content.length > 0) + { + size_t const avail_bytes = rci_buffer_remaining(output); + size_t const write_bytes = (rci->output.content.length < avail_bytes) ? rci->output.content.length : avail_bytes; + + overflow = rci_output_data(rci, output, (uint8_t *)rci->output.content.data, write_bytes); + if (overflow) goto done; + + rci->output.content.data += write_bytes; + rci->output.content.length -= write_bytes; + + } + + if (rci->output.content.length > 0) + { + overflow = connector_true; + rci->status = rci_status_flush_output; + } + else + { + clear_rcistr(&rci->output.content); + } + +done: + return overflow; +} + +#if defined RCI_PARSER_USES_IPV4 +static connector_bool_t rci_output_ipv4(rci_t * const rci, char const * const string) +{ + rci_buffer_t * const output = &rci->buffer.output; + connector_bool_t overflow = connector_true; + size_t const avail_bytes = rci_buffer_remaining(output); + + if (avail_bytes < sizeof(uint32_t)) + { + goto done; + } + else + { + uint32_t ipv4 = 0; + uint8_t * const rci_ber_u32 = rci_buffer_position(output); + int dot_count = 0; + size_t i; + size_t length = strlen(string); + char aux_string[4] = {'\0', '\0', '\0', '\0'}; /* Three chars plus terminator. */ + + size_t index = 0; + + for (i = 0; i < length; i++) + { + if (index > sizeof(aux_string) - 1) + break; + + if (string[i] != '.') + { + aux_string[index++] = string[i]; + } + + if (string[i] == '.' || i == (length -1)) + { + long int val; + char * endptr; + + val = strtol(aux_string, &endptr, 10); + if (endptr == NULL || *endptr != '\0' || val < 0 || val > 255) + { + break; + } + + ipv4 = (ipv4 << 8) | val; + dot_count++; + index = 0; + memset(aux_string, '\0', sizeof aux_string); + } + } + if (dot_count != 4) + { + connector_request_id_t request_id; + request_id.remote_config_request = connector_request_id_remote_config_group_process; + notify_error_status(rci->service_data->connector_ptr->callback, connector_class_id_remote_config, request_id, connector_invalid_data_range); + rci->status = rci_status_error; + overflow = connector_false; + connector_debug_printf("Invalid IPv4 \"%s\"\n", string); + goto done; + } + + message_store_u8(rci_ber_u32, opcode, sizeof ipv4); + message_store_be32(rci_ber_u32, value, ipv4); + + rci_buffer_advance(output, record_bytes(rci_ber_u32)); + + overflow = connector_false; + } + +done: + return overflow; +} +#endif + +static connector_bool_t rci_output_uint8(rci_t * const rci, uint8_t const value) +{ + uint8_t const data = value; + rci_buffer_t * const output = &rci->buffer.output; + + return rci_output_data(rci, output, &data, sizeof data); +} + +#if defined RCI_PARSER_USES_FLOAT +static connector_bool_t rci_output_float(rci_t * const rci, float const value) +{ + float const float_value = value; + uint32_t float_integer; + + ASSERT(sizeof value == sizeof float_integer); + + memcpy(&float_integer, &float_value, sizeof float_integer); + + return rci_output_uint32(rci, float_integer); +} +#endif + +#define rci_output_no_value(rci) rci_output_uint8((rci), BINARY_RCI_NO_VALUE) +#define rci_output_terminator(rci) rci_output_uint8((rci), BINARY_RCI_TERMINATOR) + +static void rci_output_command_id(rci_t * const rci) +{ + connector_remote_config_t const * const remote_config = &rci->shared.callback_data; + uint32_t command_id = 0; + + switch (rci->shared.callback_data.group.type) + { + case connector_remote_group_setting: + switch (rci->shared.callback_data.action) + { + case connector_remote_action_set: + command_id = rci_command_set_setting; + break; + case connector_remote_action_query: + command_id = rci_command_query_setting; + break; + } + break; + case connector_remote_group_state: + switch (rci->shared.callback_data.action) + { + case connector_remote_action_set: + command_id = rci_command_set_state; + break; + case connector_remote_action_query: + command_id = rci_command_query_state; + break; + } + break; + } + + { + connector_bool_t const overflow = rci_output_uint32(rci, command_id); + + if (!overflow) + { + if (remote_config->error_id != connector_success) + state_call(rci, rci_parser_state_error); + else + state_call(rci, rci_parser_state_traverse); + } + } + + return; +} + +static void rci_output_group_id(rci_t * const rci) +{ + connector_remote_config_t const * const remote_config = &rci->shared.callback_data; + uint32_t encoding_data; + + if (!have_group_id(rci)) + { + state_call(rci, rci_parser_state_error); + goto done; + } + + encoding_data = encode_group_id(get_group_id(rci)); + + if (get_group_index(rci) > 1) + encoding_data |= BINARY_RCI_ATTRIBUTE_BIT; + + { + connector_bool_t const overflow = rci_output_uint32(rci, encoding_data); + + if (!overflow) + { + if (remote_config->error_id != connector_success) + state_call(rci, rci_parser_state_error); + else + set_rci_output_state(rci, rci_output_state_group_attribute); + } + } + +done: + return; +} + +static connector_bool_t encode_attribute(rci_t * const rci, unsigned int const index) +{ + uint32_t encoding_data; + connector_bool_t overflow = connector_false; + + if (index > 1) + { + /* attribute output + * bit |7 | 6 5 | 4 3 2 1 0| + * |x | 0 1 | - index -| + */ + #define BINARY_RCI_ATTRIBUTE_INDEX_MAX 31 + #define BINARY_RCI_ATTRIBUTE_TYPE_INDEX 0x20 + + ASSERT(index <= BINARY_RCI_ATTRIBUTE_INDEX_MAX); + encoding_data = index | BINARY_RCI_ATTRIBUTE_TYPE_INDEX; + + overflow = rci_output_uint32(rci, encoding_data); + } + + return overflow; +} + +static void rci_output_group_attribute(rci_t * const rci) +{ + unsigned int const index = get_group_index(rci); + connector_bool_t overflow = encode_attribute(rci, index); + + if (!overflow) + state_call(rci, rci_parser_state_traverse); +} + + +static void rci_output_field_id(rci_t * const rci) +{ + connector_remote_config_t const * const remote_config = &rci->shared.callback_data; + + if (!have_element_id(rci)) + { + state_call(rci, rci_parser_state_error); + goto done; + } + + { + /* output field id */ + uint32_t id = encode_element_id(get_element_id(rci)); + + if (remote_config->error_id != connector_success) id |= BINARY_RCI_FIELD_TYPE_INDICATOR_BIT; + + { + connector_bool_t const overflow = rci_output_uint32(rci, id); + + if (overflow) goto done; + + if (remote_config->error_id != connector_success) + state_call(rci, rci_parser_state_error); + else + set_rci_output_state(rci, rci_output_state_field_value); + } + + } + +done: + return; +} + + +static void rci_output_field_value(rci_t * const rci) +{ + connector_group_element_t const * const element = get_current_element(rci); + connector_element_value_type_t const type = element->type; + + connector_bool_t overflow = connector_false; + + + switch (rci->shared.callback_data.action) + { + case connector_remote_action_set: + overflow = rci_output_no_value(rci); + goto done; + + case connector_remote_action_query: + break; + } + + switch (type) + { +#if defined RCI_PARSER_USES_STRINGS + +#if defined RCI_PARSER_USES_STRING + case connector_element_type_string: +#endif + +#if defined RCI_PARSER_USES_MULTILINE_STRING + case connector_element_type_multiline_string: +#endif + +#if defined RCI_PARSER_USES_PASSWORD + case connector_element_type_password: +#endif + +#if defined RCI_PARSER_USES_FQDNV4 + case connector_element_type_fqdnv4: +#endif + +#if defined RCI_PARSER_USES_FQDNV6 + case connector_element_type_fqdnv6: +#endif + +#if defined RCI_PARSER_USES_DATETIME + case connector_element_type_datetime: +#endif + ASSERT(rci->shared.value.string_value != NULL); + overflow = rci_output_string(rci, rci->shared.value.string_value, strlen(rci->shared.value.string_value)); + break; +#endif + +#if defined RCI_PARSER_USES_IPV4 + case connector_element_type_ipv4: + ASSERT(rci->shared.value.string_value != NULL); + overflow = rci_output_ipv4(rci, rci->shared.value.string_value); + break; +#endif + +#if defined RCI_PARSER_USES_INT32 + case connector_element_type_int32: + overflow = rci_output_uint32(rci, rci->shared.value.signed_integer_value); + break; +#endif + +#if (defined RCI_PARSER_USES_UNSIGNED_INTEGER) +#if defined RCI_PARSER_USES_UINT32 + case connector_element_type_uint32: +#endif + +#if defined RCI_PARSER_USES_HEX32 + case connector_element_type_hex32: +#endif + +#if defined RCI_PARSER_USES_0X_HEX32 + case connector_element_type_0x_hex32: +#endif + + overflow = rci_output_uint32(rci, rci->shared.value.unsigned_integer_value); + break; +#endif + +#if defined RCI_PARSER_USES_FLOAT + case connector_element_type_float: + overflow = rci_output_float(rci, rci->shared.value.float_value); + break; +#endif + +#if defined RCI_PARSER_USES_ENUM + case connector_element_type_enum: + overflow = rci_output_uint32(rci, rci->shared.value.enum_value); + break; +#endif + +#if defined RCI_PARSER_USES_ON_OFF + case connector_element_type_on_off: + overflow = rci_output_uint32(rci, rci->shared.value.on_off_value); + break; +#endif + +#if defined RCI_PARSER_USES_BOOLEAN + case connector_element_type_boolean: + overflow = rci_output_uint32(rci, rci->shared.value.boolean_value); + break; +#endif + } + +done: + if (!overflow) + state_call(rci, rci_parser_state_traverse); + +} + +static void rci_output_field_terminator(rci_t * const rci) +{ + connector_remote_config_t const * const remote_config = &rci->shared.callback_data; + + connector_bool_t const overflow = rci_output_terminator(rci); + if (!overflow) + { + invalidate_element_id(rci); + + if (remote_config->error_id != connector_success) + state_call(rci, rci_parser_state_error); + else + state_call(rci, rci_parser_state_traverse); + } + return; +} + +static void rci_output_group_terminator(rci_t * const rci) +{ + connector_remote_config_t const * const remote_config = &rci->shared.callback_data; + + if (remote_config->error_id != connector_success) + { + state_call(rci, rci_parser_state_error); + } + else + { + connector_bool_t const overflow = rci_output_terminator(rci); + if (overflow) goto done; + + set_rci_output_state(rci, rci_output_state_response_done); + } + + invalidate_group_id(rci); + +done: + return; +} + +static void rci_generate_output(rci_t * const rci) +{ + rci_buffer_t * const output = &rci->buffer.output; + + if ((rci_buffer_remaining(output) != 0)) + { + rci_debug_printf("output: %s\n", rci_output_state_t_as_string(rci->output.state)); + + switch (rci->output.state) + { + case rci_output_state_command_id: + rci_output_command_id(rci); + break; + + case rci_output_state_group_id: + rci_output_group_id(rci); + break; + + case rci_output_state_group_attribute: + rci_output_group_attribute(rci); + break; + + case rci_output_state_field_id: + rci_output_field_id(rci); + break; + + case rci_output_state_field_value: + rci_output_field_value(rci); + break; + + case rci_output_state_field_terminator: + rci_output_field_terminator(rci); + break; + + case rci_output_state_group_terminator: + rci_output_group_terminator(rci); + break; + + case rci_output_state_response_done: + + if (get_rci_input_state(rci) == rci_input_state_done) + { + trigger_rci_callback(rci, connector_request_id_remote_config_session_end); + set_rci_output_state(rci, rci_output_state_done); + } + else + { + state_call(rci, rci_parser_state_input); + set_rci_input_state(rci, rci_input_state_command_id); + } + break; + + case rci_output_state_done: + { + connector_remote_config_t const * const remote_config = &rci->shared.callback_data; + if (remote_config->error_id != connector_success) + state_call(rci, rci_parser_state_error); + else + rci->status = rci_status_complete; + break; + } + } + } + else if ((rci_buffer_used(&rci->buffer.output) > 0) && (rci->status == rci_status_busy)) + { + /* We are here since we have no space left for more output data and we have output data waiting to be sent. + So set up the state to send out the output data and come back to rci */ + + rci->status = rci_status_flush_output; + } + + +#if defined RCI_DEBUG + { + size_t const bytes = rci_buffer_used(&rci->buffer.output); + if (bytes > 0) + { + connector_debug_hexvalue("Response", rci->buffer.output.start, bytes); + } + } +#endif + + return; +} + +