From f4ffc96d5a60b3051fbf7a8b21d0d19faae1f89c Mon Sep 17 00:00:00 2001 From: Th3maz1ng Date: Mon, 10 Apr 2023 10:07:57 +0200 Subject: [PATCH] Added the CodeBlocks project used to develop the Gadget Bridge parser code --- src/gadget_bridge_parser/gadget_bridge.c | 1417 +++++++++++++++++ src/gadget_bridge_parser/gadget_bridge.h | 220 +++ .../gadget_bridge_parser.cbp | 43 + .../gadget_bridge_parser.depend | 18 + .../gadget_bridge_parser.layout | 20 + src/gadget_bridge_parser/main.c | 308 ++++ 6 files changed, 2026 insertions(+) create mode 100644 src/gadget_bridge_parser/gadget_bridge.c create mode 100644 src/gadget_bridge_parser/gadget_bridge.h create mode 100644 src/gadget_bridge_parser/gadget_bridge_parser.cbp create mode 100644 src/gadget_bridge_parser/gadget_bridge_parser.depend create mode 100644 src/gadget_bridge_parser/gadget_bridge_parser.layout create mode 100644 src/gadget_bridge_parser/main.c diff --git a/src/gadget_bridge_parser/gadget_bridge.c b/src/gadget_bridge_parser/gadget_bridge.c new file mode 100644 index 0000000..ec1186e --- /dev/null +++ b/src/gadget_bridge_parser/gadget_bridge.c @@ -0,0 +1,1417 @@ +/** + * @file gadget_bridge.c + * @author Anatole SCHRAMM-HENRY + * @brief Source file implementing the API used to communicate/interact with the GadgetBridge Android application + * over BLE. + * @version 0.1 + * @date 2023-04-05 + * + * @copyright MIT + * + */ + +#include "gadget_bridge.h" +#include +#include +#include +//#include "ble_service.h" + +bool ble_service_send_nus_data(const uint8_t *data, uint16_t length) +{ + return true; +} + +/* Internal enum definition */ +typedef enum gadget_bridge_parser_fsm +{ + GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE = 0, + GADGET_BRIDGE_PARSER_FSM_FOUND_GB, + + GADGET_BRIDGE_PARSER_FSM_FOUND_NOTIFY, + GADGET_BRIDGE_PARSER_FSM_FOUND_ID_BODY, + GADGET_BRIDGE_PARSER_FSM_FOUND_SENDER, + GADGET_BRIDGE_PARSER_FSM_FOUND_TEL, + GADGET_BRIDGE_PARSER_FSM_FOUND_TITLE, + GADGET_BRIDGE_PARSER_FSM_PARSING_TITLE_CONTENT, + + GADGET_BRIDGE_PARSER_FSM_FOUND_ID_SRC, + GADGET_BRIDGE_PARSER_FSM_FOUND_SRC_BODY, + GADGET_BRIDGE_PARSER_FSM_PARSING_BODY_CONTENT, + + GADGET_BRIDGE_PARSER_FSM_FOUND_CALL, + GADGET_BRIDGE_PARSER_FSM_FOUND_NAME, + GADGET_BRIDGE_PARSER_FSM_FOUND_NUMBER, + + GADGET_BRIDGE_PARSER_FSM_FOUND_WEATHER, + GADGET_BRIDGE_PARSER_FSM_FOUND_TEMP, + GADGET_BRIDGE_PARSER_FSM_FOUND_HUM, + GADGET_BRIDGE_PARSER_FSM_FOUND_TXT, + GADGET_BRIDGE_PARSER_FSM_FOUND_WIND, + GADGET_BRIDGE_PARSER_FSM_FOUND_WINDDIR, + GADGET_BRIDGE_PARSER_FSM_FOUND_LOC, + + GADGET_BRIDGE_PARSER_FSM_FOUND_FIND, + + GADGET_BRIDGE_PARSER_FSM_FOUND_ACT, + GADGET_BRIDGE_PARSER_FSM_FOUND_STP, + GADGET_BRIDGE_PARSER_FSM_FOUND_HRM_INT, + + GADGET_BRIDGE_PARSER_FSM_FOUND_MUSICSTATE, + GADGET_BRIDGE_PARSER_FSM_FOUND_POSITION, + GADGET_BRIDGE_PARSER_FSM_FOUND_SHUFFLE, + GADGET_BRIDGE_PARSER_FSM_FOUND_REPEAT, + + GADGET_BRIDGE_PARSER_FSM_FOUND_MUSICINFO, + GADGET_BRIDGE_PARSER_FSM_FOUND_TRACK, + GADGET_BRIDGE_PARSER_FSM_FOUND_DURATION, + + GADGET_BRIDGE_PARSER_FSM_ERROR, +} gadget_bridge_parser_fsm_e; + +/* Internal variable definition */ +struct +{ + char buffer[GADGET_BRIDGE_PARSER_BUFFER_SIZE + 1]; // The +1 is for the string termination character. + uint16_t buffer_content_size; // Without counting the string termination character. + gadget_bridge_parser_fsm_e gadget_bridge_parser_fsm; + bool new_data; + parser_event_callback_t parser_event_callback; + gadget_bridge_event_data_t event_data; +} _gadget_bridge_internals = +{ + .buffer_content_size = 0, + .gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE, + .new_data = false, + .parser_event_callback = NULL, + .event_data = { .event_type = GADGET_BRIDGE_EVENT_TYPE_NONE}, +}; + +time_t _unix_timestamp = 0; + +/* Internal function definition */ +static const char *_gadget_bridge_toast_type_2_str(gadget_bridge_toast_type_e toast_type); +static const char *_gadget_bridge_music_control_2_str(gadget_bridge_music_control_e music_control); +static const char *_gadget_bridge_http_request_method_2_str(gadget_bridge_http_request_method_e http_request_method); +static void _parser_free_buffer(uint16_t length); +static void _free_event_data(void); + +bool gadget_bridge_send_toast(gadget_bridge_toast_type_e toast_type, const char *message) +{ + if(!message || !strlen(message)) + return true; + + bool to_return = true; + to_return &= ble_service_send_nus_data((const uint8_t *)"{\"t\":\"", 6); + to_return &= ble_service_send_nus_data((const uint8_t *)_gadget_bridge_toast_type_2_str(toast_type), strlen(_gadget_bridge_toast_type_2_str(toast_type))); + to_return &= ble_service_send_nus_data((const uint8_t *)"\",\"msg\":\"", 9); + to_return &= ble_service_send_nus_data((const uint8_t *)message, strlen(message)); + to_return &= ble_service_send_nus_data((const uint8_t *)"\"} \n", 4); + + return to_return; +} + +bool gadget_bridge_send_firmware_version(const char *fw1, const char *fw2) +{ + if(!fw1 && !fw2) + return true; + + bool to_return = true; + to_return &= ble_service_send_nus_data((const uint8_t *)"{\"t\":\"ver\",\"fw1\":\"", 18); + if(fw1) + { + to_return &= ble_service_send_nus_data((const uint8_t *)fw1, strlen(fw1)); + } + to_return &= ble_service_send_nus_data((const uint8_t *)"\",\"fw2\":\"", 9); + if(fw2) + { + to_return &= ble_service_send_nus_data((const uint8_t *)fw2, strlen(fw2)); + } + to_return &= ble_service_send_nus_data((const uint8_t *)"\"} \n", 4); + + return to_return; +} + +bool gadget_bridge_send_battery_status(uint8_t battery_level_in_percent, float battery_level_in_V, bool is_charging) +{ + bool to_return = true; + char num_2_str[30] = ""; + to_return &= ble_service_send_nus_data((const uint8_t *)"{\"t\":\"status\",\"bat\":", 20); + sprintf(num_2_str, "%u,\"chg\":%u,\"volt\":%.3f} \n", battery_level_in_percent, is_charging, battery_level_in_V); + to_return &= ble_service_send_nus_data((const uint8_t *)num_2_str, strlen(num_2_str)); + + return to_return; +} + +bool gadget_bridge_send_find_phone(bool find_phone) +{ + bool to_return = true; + to_return &= ble_service_send_nus_data((const uint8_t *)"{\"t\":\"findPhone\",\"n\":", 21); + if(find_phone) + to_return &= ble_service_send_nus_data((const uint8_t *)"true} \n", 7); + else + to_return &= ble_service_send_nus_data((const uint8_t *)"false} \n", 8); + + return to_return; +} + +bool gadget_bridge_send_music_control(gadget_bridge_music_control_e music_control) +{ + bool to_return = true; + to_return &= ble_service_send_nus_data((const uint8_t *)"{\"t\":\"music\",\"n\":\"", 18); + to_return &= ble_service_send_nus_data((const uint8_t *)_gadget_bridge_music_control_2_str(music_control), strlen(_gadget_bridge_music_control_2_str(music_control))); + to_return &= ble_service_send_nus_data((const uint8_t *)"\"} \n", 4); + + return to_return; +} + +bool gadget_bridge_send_activity_data(uint16_t heart_rate_in_bpm, uint32_t step_count) +{ + bool to_return = true; + char num_2_str[11] = ""; + //{\"t\":\"act\",\"hrm\":%s,\"stp\":%s} \n + to_return &= ble_service_send_nus_data((const uint8_t *)"{\"t\":\"act\",\"hrm\":", 17); + + sprintf(num_2_str, "%u", heart_rate_in_bpm); + to_return &= ble_service_send_nus_data((const uint8_t *)num_2_str, strlen(num_2_str)); + + to_return &= ble_service_send_nus_data((const uint8_t *)",\"stp\":", 7); + + sprintf(num_2_str, "%u", step_count); + to_return &= ble_service_send_nus_data((const uint8_t *)num_2_str, strlen(num_2_str)); + + to_return &= ble_service_send_nus_data((const uint8_t *)"} \n", 3); + + return to_return; +} + +bool gadget_bridge_send_http_request(uint32_t id, const char *url, gadget_bridge_http_request_method_e http_request_method, const char *http_body, const http_header_t *http_headers) +{ + bool to_return = true; + char num_2_str[11] = ""; + sprintf(num_2_str, "%u", id); + + to_return &= ble_service_send_nus_data((const uint8_t *)"{\"t\":\"http\",\"id\":\"", 18); + to_return &= ble_service_send_nus_data((const uint8_t *)num_2_str, strlen(num_2_str)); + to_return &= ble_service_send_nus_data((const uint8_t *)"\",\"url\":\"", 9); + to_return &= ble_service_send_nus_data((const uint8_t *)url, strlen(url)); + to_return &= ble_service_send_nus_data((const uint8_t *)"\",\"method\":\"", 12); + to_return &= ble_service_send_nus_data((const uint8_t *)_gadget_bridge_http_request_method_2_str(http_request_method), strlen(_gadget_bridge_http_request_method_2_str(http_request_method))); + to_return &= ble_service_send_nus_data((const uint8_t *)"\"} \n", 4); + return to_return; +} + +void gadget_bridge_parser_register_event_callback(parser_event_callback_t parser_event_callback) +{ + _gadget_bridge_internals.parser_event_callback = parser_event_callback; +} + +gadget_bridge_parser_code_e gadget_bridge_parser_feed(const char *data, uint16_t length) +{ + // First we check if there is still space left in the parser buffer + if(_gadget_bridge_internals.buffer_content_size >= GADGET_BRIDGE_PARSER_BUFFER_SIZE) + return GADGET_BRIDGE_PARSER_CODE_BUFFER_FULL; + + // We check if the incoming data is not too long for the buffer + if(_gadget_bridge_internals.buffer_content_size + length > GADGET_BRIDGE_PARSER_BUFFER_SIZE) + return GADGET_BRIDGE_PARSER_CODE_DATA_TOO_LONG; + + strncat(_gadget_bridge_internals.buffer, data, length); + _gadget_bridge_internals.buffer_content_size += length; + _gadget_bridge_internals.new_data = true; + + return GADGET_BRIDGE_PARSER_CODE_OK; +} + +static bool _parser_extract_time(char *start, char *end); +static bool _parser_extract_handle(char *start, char *end); +//static void _parser_extract_body(char *start, char *end); +//static void _parser_extract_sender(char *start, char *end); +//static void _parser_extract_tel(char *start, char *end); +static void _parser_extract_src(char *start, char *end); +static void _parser_extract_char_str(char *start, char *end, char **data); +static void _parser_extract_cmd(char *start, char *end); +static void _parser_extract_state(char *start, char *end); +static bool _parser_extract_uint8_t(char *start, char *end, uint8_t *data); +static bool _parser_extract_float(char *start, char *end, float *data); +static bool _parser_extract_uint16_t(char *start, char *end, uint16_t *data); +static bool _parser_extract_bool(char *start, char *end, bool *data); + +gadget_bridge_parser_code_e gadget_bridge_parser_run(void) +{ + if(!_gadget_bridge_internals.new_data) return GADGET_BRIDGE_PARSER_CODE_OK; + char *start = NULL, *end = NULL; + bool free_some_space = false; + gadget_bridge_parser_code_e to_return = GADGET_BRIDGE_PARSER_CODE_PARSING; + + switch(_gadget_bridge_internals.gadget_bridge_parser_fsm) + { + case GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE: + if((start = strstr(_gadget_bridge_internals.buffer, "setTime(")) + && (end = strstr(_gadget_bridge_internals.buffer, ");"))) + { + printf("###Found setTime\n"); + _parser_extract_time(start + 8, end); + + // We remove the parsed part from the buffer + end += 2; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + } + else if((start = strstr(_gadget_bridge_internals.buffer, "setTimeZone(")) + && (end = strstr(_gadget_bridge_internals.buffer, ");"))) + { + printf("###Found setTimeZone\n"); + float time_zone = 0.0; + if(_parser_extract_float(start + 12, end, &time_zone)) + { + _gadget_bridge_internals.event_data.event_type = GADGET_BRIDGE_EVENT_TYPE_SET_TIME; + _gadget_bridge_internals.event_data.time.time_zone = time_zone; + // Set the local time by taking into account the gmtime + //_unix_timestamp += _gadget_bridge_internals.event_data.time.time_zone*3600; + _gadget_bridge_internals.event_data.time.local_time = *localtime(&_unix_timestamp); + + // If a callback was registered, we call it and pass the data to it + if(_gadget_bridge_internals.parser_event_callback) + { + _gadget_bridge_internals.parser_event_callback(&_gadget_bridge_internals.event_data); + } + } + + // We remove the parsed part from the buffer + end += 2; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + { + printf("###Found GB\n"); + start += 3; + _parser_free_buffer( + start -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_GB; + } + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else + _gadget_bridge_internals.new_data = false; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_GB: + if((start = strstr(_gadget_bridge_internals.buffer, "t:\"notify\","))) + { + printf("###Found notify\n"); + _gadget_bridge_internals.event_data.event_type = GADGET_BRIDGE_EVENT_TYPE_NOTIFY; + // We remove the parsed part from the buffer + start += 11; + _parser_free_buffer( + start -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_NOTIFY; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "t:\"call\","))) + { + printf("###Found call\n"); + _gadget_bridge_internals.event_data.event_type = GADGET_BRIDGE_EVENT_TYPE_CALL; + // We remove the parsed part from the buffer + start += 9; + _parser_free_buffer( + start -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_CALL; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "t:\"weather\","))) + { + printf("###Found weather\n"); + _gadget_bridge_internals.event_data.event_type = GADGET_BRIDGE_EVENT_TYPE_WEATHER; + // We remove the parsed part from the buffer + start += 12; + _parser_free_buffer( + start -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_WEATHER; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "t:\"find\","))) + { + printf("###Found find\n"); + _gadget_bridge_internals.event_data.event_type = GADGET_BRIDGE_EVENT_TYPE_FIND; + // We remove the parsed part from the buffer + start += 9; + _parser_free_buffer( + start -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_FIND; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "t:\"act\","))) + { + printf("###Found act\n"); + _gadget_bridge_internals.event_data.event_type = GADGET_BRIDGE_EVENT_TYPE_ACT; + // We remove the parsed part from the buffer + start += 8; + _parser_free_buffer( + start -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_ACT; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "t:\"musicstate\","))) + { + printf("###Found musicstate\n"); + _gadget_bridge_internals.event_data.event_type = GADGET_BRIDGE_EVENT_TYPE_MUSIC_STATE; + // We remove the parsed part from the buffer + start += 15; + _parser_free_buffer( + start -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_MUSICSTATE; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "t:\"musicinfo\","))) + { + printf("###Found musicinfo\n"); + _gadget_bridge_internals.event_data.event_type = GADGET_BRIDGE_EVENT_TYPE_MUSIC_INFO; + // We remove the parsed part from the buffer + start += 14; + _parser_free_buffer( + start -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_MUSICINFO; + } + // If we did not find the rest but found GB again, then some payload was lost... + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + // Here we parse the notify type of payloads + case GADGET_BRIDGE_PARSER_FSM_FOUND_NOTIFY: + if((start = strstr(_gadget_bridge_internals.buffer, "id:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",src"))) + { + printf("###Found ID SRC\n"); + + _parser_extract_handle(start + 3, end); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_ID_SRC; + } + /*else if((start = strstr(_gadget_bridge_internals.buffer, "id:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",body"))) + { + printf("###Found ID BODY\n"); + _parser_extract_handle(start + 3, end); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_ID_BODY; + }*/ + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_ID_SRC: + if((start = strstr(_gadget_bridge_internals.buffer, "src:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",title"))) + { + printf("###Found TITLE\n"); + + _parser_extract_src(start + 5, end - 1); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_TITLE; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_TITLE: + if((start = strstr(_gadget_bridge_internals.buffer, "title:"))) + { + printf("###Parsing TITLE content\n"); + + // We remove the parsed part from the buffer + start += 7; + _parser_free_buffer( + start -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_PARSING_TITLE_CONTENT; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_PARSING_TITLE_CONTENT: + { + end = strstr(_gadget_bridge_internals.buffer, ",body"); + if(end) + { + printf("###Found BODY\n"); + + _parser_extract_char_str(_gadget_bridge_internals.buffer, end - 1, &_gadget_bridge_internals.event_data.notification.title); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_SRC_BODY; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + // Then we have a very long title, in this case we juste keep the max set up + else if(!end && _gadget_bridge_internals.buffer_content_size >= GADGET_BRIDGE_PARSER_MAX_TITLE_SIZE) + { + printf("###NOTIFICATION (MAX TITLE SIZE)\n"); + + _parser_extract_char_str(_gadget_bridge_internals.buffer, _gadget_bridge_internals.buffer + GADGET_BRIDGE_PARSER_MAX_TITLE_SIZE, &_gadget_bridge_internals.event_data.notification.title); + + // We remove the parsed part from the buffer + _parser_free_buffer( + GADGET_BRIDGE_PARSER_MAX_TITLE_SIZE+1 + ); + + // The end of the road for this object + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_SRC_BODY; + } + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + } + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_SRC_BODY: + if((start = strstr(_gadget_bridge_internals.buffer, "body:"))) + { + printf("###Parsing BODY content\n"); + + // We remove the : "body":" part + start += 6; + _parser_free_buffer( + start -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_PARSING_BODY_CONTENT; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_PARSING_BODY_CONTENT: + { + end = strstr(_gadget_bridge_internals.buffer, "})"); + if(end) + { + printf("###NOTIFICATION Type done\n"); + + _parser_extract_char_str(_gadget_bridge_internals.buffer, end - 1, &_gadget_bridge_internals.event_data.notification.body); + + // We remove the parsed part from the buffer + end += 2; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + + // If a callback was registered, we call it and pass the data to it + if(_gadget_bridge_internals.parser_event_callback) + { + _gadget_bridge_internals.parser_event_callback(&_gadget_bridge_internals.event_data); + } + + // Free the allocated data + _free_event_data(); + + // The end of the road for this object + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + // Then we have a very long body, in this case we juste keep the max set up + else if(!end && _gadget_bridge_internals.buffer_content_size >= GADGET_BRIDGE_PARSER_MAX_BODY_SIZE) + { + printf("###NOTIFICATION (MAX BODY SIZE) Type done\n"); + + _parser_extract_char_str(_gadget_bridge_internals.buffer, _gadget_bridge_internals.buffer + GADGET_BRIDGE_PARSER_MAX_BODY_SIZE, &_gadget_bridge_internals.event_data.notification.body); + + // We remove the parsed part from the buffer + _parser_free_buffer( + GADGET_BRIDGE_PARSER_MAX_BODY_SIZE + 1 + ); + + // If a callback was registered, we call it and pass the data to it + if(_gadget_bridge_internals.parser_event_callback) + { + _gadget_bridge_internals.parser_event_callback(&_gadget_bridge_internals.event_data); + } + + // Free the allocated data + _free_event_data(); + + // The end of the road for this object + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + } + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + } + break; + /*case GADGET_BRIDGE_PARSER_FSM_FOUND_ID_BODY: + if((start = strstr(_gadget_bridge_internals.buffer, "body:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",sender"))) + { + printf("###Found SENDER\n"); + _parser_extract_body(start + 6, end - 1); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_SENDER; + } + else + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_SENDER: + if((start = strstr(_gadget_bridge_internals.buffer, "sender:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",tel"))) + { + printf("###Found TEL\n"); + _parser_extract_sender(start + 8, end - 1); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_TEL; + } + else + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_TEL: + if((start = strstr(_gadget_bridge_internals.buffer, "tel:")) + && (end = strstr(_gadget_bridge_internals.buffer, "})"))) + { + printf("###SMS Type one done\n"); + _parser_extract_tel(start + 5, end - 1); + + // We remove the parsed part from the buffer + end += 2; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + + // If a callback was registered, we call it and pass the data to it + if(_gadget_bridge_internals.parser_event_callback) + _gadget_bridge_internals.parser_event_callback(&_gadget_bridge_internals.event_data); + // The end of the road for this object + } + + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + break;*/ + case GADGET_BRIDGE_PARSER_FSM_FOUND_CALL: + if((start = strstr(_gadget_bridge_internals.buffer, "cmd:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",name"))) + { + printf("###Found NAME\n"); + _parser_extract_cmd(start + 5, end - 1); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_NAME; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_NAME: + if((start = strstr(_gadget_bridge_internals.buffer, "name:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",number"))) + { + printf("###Found NUMBER\n"); + _parser_extract_char_str(start + 6, end - 1, &_gadget_bridge_internals.event_data.call.contact); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_NUMBER; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_NUMBER: + if((start = strstr(_gadget_bridge_internals.buffer, "number:")) + && (end = strstr(_gadget_bridge_internals.buffer, "})"))) + { + printf("###CALL Type done\n"); + _parser_extract_char_str(start + 8, end - 1, &_gadget_bridge_internals.event_data.call.phone_number); + + // We remove the parsed part from the buffer + end += 2; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + + // If a callback was registered, we call it and pass the data to it + if(_gadget_bridge_internals.parser_event_callback) + { + _gadget_bridge_internals.parser_event_callback(&_gadget_bridge_internals.event_data); + } + + // Free the allocated data + _free_event_data(); + + // The end of the road for this object + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_WEATHER: + if((start = strstr(_gadget_bridge_internals.buffer, "temp:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",hum"))) + { + printf("###Found HUM\n"); + _parser_extract_float(start + 5, end, &_gadget_bridge_internals.event_data.weather.temperature_celsius); + // Do get °C instead of kelvins + _gadget_bridge_internals.event_data.weather.temperature_celsius += -273.15; + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_HUM; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_HUM: + if((start = strstr(_gadget_bridge_internals.buffer, "hum:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",code"))) + { + // We don't care about code... + printf("###Found TXT\n"); + _parser_extract_uint8_t(start + 4, end, &_gadget_bridge_internals.event_data.weather.humidity); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_TXT; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_TXT: + if((start = strstr(_gadget_bridge_internals.buffer, "txt:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",wind"))) + { + // We don't care about code... + printf("###Found WIND\n"); + _parser_extract_char_str(start + 5, end - 1, &_gadget_bridge_internals.event_data.weather.weather_desc); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_WIND; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_WIND: + if((start = strstr(_gadget_bridge_internals.buffer, "wind:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",wdir"))) + { + // We don't care about code... + printf("###Found WIND DIR\n"); + _parser_extract_float(start + 5, end, &_gadget_bridge_internals.event_data.weather.wind_speed_kmh); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_WINDDIR; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_WINDDIR: + if((start = strstr(_gadget_bridge_internals.buffer, "wdir:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",loc"))) + { + // We don't care about code... + printf("###Found LOC\n"); + _parser_extract_uint16_t(start + 5, end, &_gadget_bridge_internals.event_data.weather.wind_dir); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_LOC; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_LOC: + if((start = strstr(_gadget_bridge_internals.buffer, "loc:")) + && (end = strstr(_gadget_bridge_internals.buffer, "})"))) + { + printf("###WEATHER Type done\n"); + _parser_extract_char_str(start + 5, end - 1, &_gadget_bridge_internals.event_data.weather.location); + + // We remove the parsed part from the buffer + end += 2; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + + // If a callback was registered, we call it and pass the data to it + if(_gadget_bridge_internals.parser_event_callback) + { + _gadget_bridge_internals.parser_event_callback(&_gadget_bridge_internals.event_data); + } + + // Free the allocated data + _free_event_data(); + + // The end of the road for this object + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_FIND: + if((start = strstr(_gadget_bridge_internals.buffer, "n:")) + && (end = strstr(_gadget_bridge_internals.buffer, "})"))) + { + printf("###FIND Type done\n"); + _parser_extract_bool(start + 2, end, &_gadget_bridge_internals.event_data.find.find); + + // We remove the parsed part from the buffer + end += 2; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + + // If a callback was registered, we call it and pass the data to it + if(_gadget_bridge_internals.parser_event_callback) + { + _gadget_bridge_internals.parser_event_callback(&_gadget_bridge_internals.event_data); + } + // The end of the road for this object + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_ACT: + if((start = strstr(_gadget_bridge_internals.buffer, "hrm:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",stp"))) + { + printf("###Found STP\n"); + _parser_extract_bool(start + 4, end, &_gadget_bridge_internals.event_data.act.heart_rate_monitor); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_STP; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_STP: + if((start = strstr(_gadget_bridge_internals.buffer, "stp:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",int"))) + { + printf("###Found INT\n"); + _parser_extract_bool(start + 4, end, &_gadget_bridge_internals.event_data.act.steps); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_HRM_INT; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_HRM_INT: + if((start = strstr(_gadget_bridge_internals.buffer, "int:")) + && (end = strstr(_gadget_bridge_internals.buffer, "})"))) + { + printf("###ACT Type done\n"); + _parser_extract_uint8_t(start + 4, end, &_gadget_bridge_internals.event_data.act.heart_rate_interval); + + // We remove the parsed part from the buffer + end += 2; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + + // If a callback was registered, we call it and pass the data to it + if(_gadget_bridge_internals.parser_event_callback) + { + _gadget_bridge_internals.parser_event_callback(&_gadget_bridge_internals.event_data); + } + + // The end of the road for this object + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_MUSICSTATE: + if((start = strstr(_gadget_bridge_internals.buffer, "state:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",position"))) + { + printf("###Found POSITION\n"); + _parser_extract_state(start + 7, end - 1); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_POSITION; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_POSITION: + if((start = strstr(_gadget_bridge_internals.buffer, "position:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",shuffle"))) + { + printf("###Found SHUFFLE\n"); + _parser_extract_uint16_t(start + 9, end, &_gadget_bridge_internals.event_data.music_state.position_in_seconds); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_SHUFFLE; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_SHUFFLE: + if((start = strstr(_gadget_bridge_internals.buffer, "shuffle:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",repeat"))) + { + printf("###Found REPEAT\n"); + _parser_extract_uint8_t(start + 8, end, &_gadget_bridge_internals.event_data.music_state.shuffle); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_REPEAT; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_REPEAT: + if((start = strstr(_gadget_bridge_internals.buffer, "repeat:")) + && (end = strstr(_gadget_bridge_internals.buffer, "})"))) + { + printf("###MUSICSTATE Type done\n"); + _parser_extract_uint8_t(start + 7, end, &_gadget_bridge_internals.event_data.music_state.repeat); + + // We remove the parsed part from the buffer + end += 2; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + + // If a callback was registered, we call it and pass the data to it + if(_gadget_bridge_internals.parser_event_callback) + { + _gadget_bridge_internals.parser_event_callback(&_gadget_bridge_internals.event_data); + } + + // The end of the road for this object + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_MUSICINFO: + if((start = strstr(_gadget_bridge_internals.buffer, "artist:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",track"))) + { + printf("###Found TRACK\n"); + _parser_extract_char_str(start + 8, end - 1, &_gadget_bridge_internals.event_data.music_info.artist); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_TRACK; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_TRACK: + if((start = strstr(_gadget_bridge_internals.buffer, "track:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",dur"))) + { + printf("###Found DURATION\n"); + _parser_extract_char_str(start + 7, end - 1, &_gadget_bridge_internals.event_data.music_info.track); + + // We remove the parsed part from the buffer + end += 1; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_FOUND_DURATION; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_FOUND_DURATION: + if((start = strstr(_gadget_bridge_internals.buffer, "dur:")) + && (end = strstr(_gadget_bridge_internals.buffer, ",c"))) + { + printf("###MUSICINFO Type done\n"); + _parser_extract_uint16_t(start + 4, end, &_gadget_bridge_internals.event_data.music_info.duration_in_seconds); + + // We remove the parsed part from the buffer + end += 2; + _parser_free_buffer( + end -_gadget_bridge_internals.buffer + ); + + // If a callback was registered, we call it and pass the data to it + if(_gadget_bridge_internals.parser_event_callback) + { + _gadget_bridge_internals.parser_event_callback(&_gadget_bridge_internals.event_data); + } + + // Free the allocated data + _free_event_data(); + + // The end of the road for this object + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + } + else if((start = strstr(_gadget_bridge_internals.buffer, "GB("))) + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + else if(_gadget_bridge_internals.buffer_content_size > GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD) + free_some_space = true; + else to_return = GADGET_BRIDGE_PARSER_CODE_OK; + break; + case GADGET_BRIDGE_PARSER_FSM_ERROR: + printf("###Parser error\n"); + default: + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + } + + if(free_some_space) + { + printf("###Freeing some space\n"); + uint16_t free_buffer_from_size = _gadget_bridge_internals.buffer_content_size - GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD; + _parser_free_buffer(free_buffer_from_size); + _gadget_bridge_internals.gadget_bridge_parser_fsm = GADGET_BRIDGE_PARSER_FSM_NEW_MESSAGE; + } + + return to_return; +} + +#ifndef CASE_RETURN_STR +#define CASE_RETURN_STR(const) case const: return #const; +#endif + +const char *gadget_bridge_parser_code_2_str(gadget_bridge_parser_code_e parser_code) +{ + switch(parser_code) + { + CASE_RETURN_STR(GADGET_BRIDGE_PARSER_CODE_OK) + CASE_RETURN_STR(GADGET_BRIDGE_PARSER_CODE_PARSING) + CASE_RETURN_STR(GADGET_BRIDGE_PARSER_CODE_BUFFER_FULL) + CASE_RETURN_STR(GADGET_BRIDGE_PARSER_CODE_DATA_TOO_LONG) + default: + return "Unknown parser code"; + } +} + +const char *gadget_bridge_event_type_2_str(gadget_bridge_event_type_e event_type) +{ + switch(event_type) + { + CASE_RETURN_STR(GADGET_BRIDGE_EVENT_TYPE_NONE) + CASE_RETURN_STR(GADGET_BRIDGE_EVENT_TYPE_SET_TIME) + CASE_RETURN_STR(GADGET_BRIDGE_EVENT_TYPE_NOTIFY) + CASE_RETURN_STR(GADGET_BRIDGE_EVENT_TYPE_CALL) + CASE_RETURN_STR(GADGET_BRIDGE_EVENT_TYPE_WEATHER) + CASE_RETURN_STR(GADGET_BRIDGE_EVENT_TYPE_FIND) + CASE_RETURN_STR(GADGET_BRIDGE_EVENT_TYPE_ACT) + CASE_RETURN_STR(GADGET_BRIDGE_EVENT_TYPE_MUSIC_INFO) + CASE_RETURN_STR(GADGET_BRIDGE_EVENT_TYPE_MUSIC_STATE) + default: + return "Unknown event type"; + } +} + +const char *gadget_bridge_notification_type_2_str(gadget_bridge_notification_type_e notification_type) +{ + switch(notification_type) + { + CASE_RETURN_STR(GADGET_BRIDGE_NOTIFICATION_TYPE_SMS) + CASE_RETURN_STR(GADGET_BRIDGE_NOTIFICATION_TYPE_EMAIL) + CASE_RETURN_STR(GADGET_BRIDGE_NOTIFICATION_TYPE_UNKNOWN) + default: + return "Unknown notification type"; + } +} + +const char *gadget_bridge_music_state_2_str(gadget_bridge_music_state_e music_state) +{ + switch(music_state) + { + CASE_RETURN_STR(GADGET_BRIDGE_MUSIC_STATE_PAUSE) + CASE_RETURN_STR(GADGET_BRIDGE_MUSIC_STATE_PLAY) + CASE_RETURN_STR(GADGET_BRIDGE_MUSIC_STATE_UNKNOWN) + default: + return "Unknown music state"; + } +} + +void gadget_bridge_parser_debug(void) +{ + printf("Buffer size : %u\nBuffer content : #%s#\n", _gadget_bridge_internals.buffer_content_size, _gadget_bridge_internals.buffer); +} + +/* Internal function declaration */ +static const char *_gadget_bridge_toast_type_2_str(gadget_bridge_toast_type_e toast_type) +{ + switch(toast_type) + { + case GADGET_BRIDGE_TOAST_TYPE_ERROR: + return "error"; + case GADGET_BRIDGE_TOAST_TYPE_WARN: + return "warn"; + case GADGET_BRIDGE_TOAST_TYPE_INFO: + default: + return "info"; + } +} + +static const char *_gadget_bridge_music_control_2_str(gadget_bridge_music_control_e music_control) +{ + switch(music_control) + { + case GADGET_BRIDGE_MUSIC_CONTROL_PLAY: + return "play"; + case GADGET_BRIDGE_MUSIC_CONTROL_PLAYPAUSE: + return "playpause"; + case GADGET_BRIDGE_MUSIC_CONTROL_NEXT: + return "next"; + case GADGET_BRIDGE_MUSIC_CONTROL_PREVIOUS: + return "previous"; + case GADGET_BRIDGE_MUSIC_CONTROL_VOLUMEUP: + return "volumeup"; + case GADGET_BRIDGE_MUSIC_CONTROL_VOLUMEDOWN: + return "volumedown"; + case GADGET_BRIDGE_MUSIC_CONTROL_FORWARD: + return "forward"; + case GADGET_BRIDGE_MUSIC_CONTROL_REWIND: + return "rewind"; + case GADGET_BRIDGE_MUSIC_CONTROL_PAUSE: + default : + return "pause"; + } +} + +static const char *_gadget_bridge_http_request_method_2_str(gadget_bridge_http_request_method_e http_request_method) +{ + switch(http_request_method) + { + case GADGET_BRIDGE_HTTP_REQUEST_POST: + return "post"; + case GADGET_BRIDGE_HTTP_REQUEST_HEAD: + return "head"; + case GADGET_BRIDGE_HTTP_REQUEST_PUT: + return "put"; + case GADGET_BRIDGE_HTTP_REQUEST_PATCH: + return "patch"; + case GADGET_BRIDGE_HTTP_REQUEST_DELETE: + return "delete"; + case GADGET_BRIDGE_HTTP_REQUEST_GET: + default: + return "get"; + } +} + +static bool _parser_extract_time(char *start, char *end) +{ + *end = '\0'; + char *is_valid = NULL; + _unix_timestamp = strtoul(start, &is_valid, 10); + + // We set the type of the data and its content + _gadget_bridge_internals.event_data.event_type = GADGET_BRIDGE_EVENT_TYPE_SET_TIME; + // Turn the timestamp into a date and time + _gadget_bridge_internals.event_data.time.gm_time = *gmtime(&_unix_timestamp); + return *is_valid == '\0'; +} + +static bool _parser_extract_handle(char *start, char *end) +{ + *end = '\0'; + char *is_valid = NULL; + uint32_t handle = strtoul(start, &is_valid, 10); + + // We set the type of the data and its content + _gadget_bridge_internals.event_data.notification.handle = handle; + printf("###Extracted handle : %u\n", handle); + + return *is_valid == '\0'; +} + +static bool _parser_extract_uint8_t(char *start, char *end, uint8_t *data) +{ + *end = '\0'; + char *is_valid = NULL; + *data = strtoul(start, &is_valid, 10); + + printf("###Extracted uint8_t : %u\n", *data); + + return *is_valid == '\0'; +} + +static bool _parser_extract_float(char *start, char *end, float *data) +{ + *end = '\0'; + char *is_valid = NULL; + *data = strtof(start, &is_valid); + + printf("###Extracted float : %.2f\n", *data); + + return *is_valid == '\0'; +} + +static bool _parser_extract_uint16_t(char *start, char *end, uint16_t *data) +{ + *end = '\0'; + char *is_valid = NULL; + *data = strtoul(start, &is_valid, 10); + + printf("###Extracted uint16_t : %u\n", *data); + + return *is_valid == '\0'; +} + +/*static void _parser_extract_body(char *start, char *end) +{ + *end = '\0'; + _gadget_bridge_internals.event_data.sms.body = strdup(start); + _gadget_bridge_internals.event_data.event_type = GADGET_BRIDGE_EVENT_TYPE_SMS; + + printf("###Extracted body : %s\n", _gadget_bridge_internals.event_data.sms.body); +} + +static void _parser_extract_sender(char *start, char *end) +{ + *end = '\0'; + _gadget_bridge_internals.event_data.sms.contact = strdup(start); + + printf("###Extracted sender : %s\n", _gadget_bridge_internals.event_data.sms.contact); +} + +static void _parser_extract_tel(char *start, char *end) +{ + *end = '\0'; + _gadget_bridge_internals.event_data.sms.phone_number = strdup(start); + + printf("###Extracted tel : %s\n", _gadget_bridge_internals.event_data.sms.phone_number); +}*/ + +static void _parser_extract_src(char *start, char *end) +{ + *end = '\0'; + if(strcmp(start, "Messages") == 0) + _gadget_bridge_internals.event_data.notification.notification_type = GADGET_BRIDGE_NOTIFICATION_TYPE_SMS; + else if(strcmp(start, "E-mail") == 0) + _gadget_bridge_internals.event_data.notification.notification_type = GADGET_BRIDGE_NOTIFICATION_TYPE_EMAIL; + else + _gadget_bridge_internals.event_data.notification.notification_type = GADGET_BRIDGE_NOTIFICATION_TYPE_UNKNOWN; + + printf("###Source is : %s\n", start); +} + +static void _parser_extract_char_str(char *start, char *end, char **data) +{ + *end = '\0'; + *data = strdup(start); + + printf("###Extracted char str : #%s#\n", *data); +} + +static void _parser_extract_cmd(char *start, char *end) +{ + *end = '\0'; + + if(strcmp(start, "incoming") == 0) + _gadget_bridge_internals.event_data.call.call_action = GADGET_BRIDGE_CALL_ACTION_INCOMING; + else if(strcmp(start, "end") == 0) + _gadget_bridge_internals.event_data.call.call_action = GADGET_BRIDGE_CALL_ACTION_END; + else + _gadget_bridge_internals.event_data.call.call_action = GADGET_BRIDGE_CALL_ACTION_UNKNOWN; + + printf("###Commande is : %s\n", start); +} + +static void _parser_extract_state(char *start, char *end) +{ + *end = '\0'; + + if(strcmp(start, "play") == 0) + _gadget_bridge_internals.event_data.music_state.music_state = GADGET_BRIDGE_MUSIC_STATE_PLAY; + else if(strcmp(start, "pause") == 0) + _gadget_bridge_internals.event_data.music_state.music_state = GADGET_BRIDGE_MUSIC_STATE_PAUSE; + else + _gadget_bridge_internals.event_data.music_state.music_state = GADGET_BRIDGE_MUSIC_STATE_UNKNOWN; + + printf("###State is : %s\n", start); +} + +static bool _parser_extract_bool(char *start, char *end, bool *data) +{ + *end = '\0'; + if(strcmp(start, "true") == 0) + *data = true; + else if(strcmp(start, "false") == 0) + *data = false; + else + return false; + + printf("###Extracted bool : %s\n", *data ? "true" : "false"); + return true; +} + +static void _parser_free_buffer(uint16_t length) +{ + length = length > _gadget_bridge_internals.buffer_content_size ? _gadget_bridge_internals.buffer_content_size : length; + + memmove(_gadget_bridge_internals.buffer, _gadget_bridge_internals.buffer + length, _gadget_bridge_internals.buffer_content_size - length + 1); // +1 to include \0 + _gadget_bridge_internals.buffer_content_size -= length; +} + +static void _free_event_data(void) +{ + switch(_gadget_bridge_internals.event_data.event_type) + { + case GADGET_BRIDGE_EVENT_TYPE_NOTIFY: + free(_gadget_bridge_internals.event_data.notification.title); + _gadget_bridge_internals.event_data.notification.title = NULL; + free(_gadget_bridge_internals.event_data.notification.body); + _gadget_bridge_internals.event_data.notification.body = NULL; + break; + case GADGET_BRIDGE_EVENT_TYPE_CALL: + free(_gadget_bridge_internals.event_data.call.phone_number); + _gadget_bridge_internals.event_data.call.phone_number = NULL; + free(_gadget_bridge_internals.event_data.call.contact); + _gadget_bridge_internals.event_data.call.contact = NULL; + break; + case GADGET_BRIDGE_EVENT_TYPE_WEATHER: + free(_gadget_bridge_internals.event_data.weather.location); + _gadget_bridge_internals.event_data.weather.location = NULL; + free(_gadget_bridge_internals.event_data.weather.weather_desc); + _gadget_bridge_internals.event_data.weather.weather_desc = NULL; + break; + case GADGET_BRIDGE_EVENT_TYPE_MUSIC_INFO: + free(_gadget_bridge_internals.event_data.music_info.artist); + _gadget_bridge_internals.event_data.music_info.artist = NULL; + free(_gadget_bridge_internals.event_data.music_info.track); + _gadget_bridge_internals.event_data.music_info.track = NULL; + break; + default: + break; + } +} diff --git a/src/gadget_bridge_parser/gadget_bridge.h b/src/gadget_bridge_parser/gadget_bridge.h new file mode 100644 index 0000000..3f9e755 --- /dev/null +++ b/src/gadget_bridge_parser/gadget_bridge.h @@ -0,0 +1,220 @@ +/** + * @file gadget_bridge.h + * @author Anatole SCHRAMM-HENRY + * @brief Header file exposing the API used to communicate/interact with the GadgetBridge Android application + * over BLE. + * @version 0.1 + * @date 2023-04-04 + * + * @copyright MIT + * + */ + +#ifndef GADGET_BRIDGE_H +#define GADGET_BRIDGE_H + +#include +#include +#include + +/** + * @brief Size of the internal buffer used to store incoming data + * which needs to be parsed. + * + */ +#define GADGET_BRIDGE_PARSER_BUFFER_SIZE (300) +#define GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD (100) + +#define GADGET_BRIDGE_PARSER_MAX_BODY_SIZE (200) +#define GADGET_BRIDGE_PARSER_MAX_TITLE_SIZE (100) + +typedef enum gadget_bridge_toast_type +{ + GADGET_BRIDGE_TOAST_TYPE_INFO = 0, + GADGET_BRIDGE_TOAST_TYPE_WARN, + GADGET_BRIDGE_TOAST_TYPE_ERROR, +} gadget_bridge_toast_type_e; + +typedef enum gadget_bridge_music_control +{ + GADGET_BRIDGE_MUSIC_CONTROL_PLAY = 0, + GADGET_BRIDGE_MUSIC_CONTROL_PAUSE, + GADGET_BRIDGE_MUSIC_CONTROL_PLAYPAUSE, + GADGET_BRIDGE_MUSIC_CONTROL_NEXT, + GADGET_BRIDGE_MUSIC_CONTROL_PREVIOUS, + GADGET_BRIDGE_MUSIC_CONTROL_VOLUMEUP, + GADGET_BRIDGE_MUSIC_CONTROL_VOLUMEDOWN, + GADGET_BRIDGE_MUSIC_CONTROL_FORWARD, + GADGET_BRIDGE_MUSIC_CONTROL_REWIND, +} gadget_bridge_music_control_e; + +typedef enum gadget_bridge_call_action +{ + GADGET_BRIDGE_CALL_ACTION_ACCEPT = 0, + GADGET_BRIDGE_CALL_ACTION_END, + GADGET_BRIDGE_CALL_ACTION_INCOMING, + GADGET_BRIDGE_CALL_ACTION_OUTGOING, + GADGET_BRIDGE_CALL_ACTION_REJECT, + GADGET_BRIDGE_CALL_ACTION_START, + GADGET_BRIDGE_CALL_ACTION_IGNORE, + GADGET_BRIDGE_CALL_ACTION_UNKNOWN, +} gadget_bridge_call_action_e; + +typedef enum gadget_bridge_notification_action +{ + GADGET_BRIDGE_NOTIFICATION_ACTION_DISMISS = 0, + GADGET_BRIDGE_NOTIFICATION_ACTION_DISMISS_ALL, + GADGET_BRIDGE_NOTIFICATION_ACTION_OPEN, + GADGET_BRIDGE_NOTIFICATION_ACTION_MUTE, + GADGET_BRIDGE_NOTIFICATION_ACTION_REPLY, +} gadget_bridge_notification_action_e; + +typedef enum gadget_bridge_http_request_method +{ + GADGET_BRIDGE_HTTP_REQUEST_GET = 0, + GADGET_BRIDGE_HTTP_REQUEST_POST, + GADGET_BRIDGE_HTTP_REQUEST_HEAD, + GADGET_BRIDGE_HTTP_REQUEST_PUT, + GADGET_BRIDGE_HTTP_REQUEST_PATCH, + GADGET_BRIDGE_HTTP_REQUEST_DELETE, + +} gadget_bridge_http_request_method_e; + +typedef enum gadget_bridge_parser_code +{ + GADGET_BRIDGE_PARSER_CODE_OK = 0, + GADGET_BRIDGE_PARSER_CODE_PARSING, + GADGET_BRIDGE_PARSER_CODE_BUFFER_FULL, + GADGET_BRIDGE_PARSER_CODE_DATA_TOO_LONG, +} gadget_bridge_parser_code_e; + +typedef struct http_header +{ + const char *key; + const char *value; +} http_header_t; + +typedef enum gadget_bridge_event_type +{ + GADGET_BRIDGE_EVENT_TYPE_NONE = 0, + GADGET_BRIDGE_EVENT_TYPE_SET_TIME, + GADGET_BRIDGE_EVENT_TYPE_NOTIFY, + GADGET_BRIDGE_EVENT_TYPE_CALL, + GADGET_BRIDGE_EVENT_TYPE_WEATHER, + GADGET_BRIDGE_EVENT_TYPE_FIND, + GADGET_BRIDGE_EVENT_TYPE_ACT, + GADGET_BRIDGE_EVENT_TYPE_MUSIC_INFO, + GADGET_BRIDGE_EVENT_TYPE_MUSIC_STATE, + GADGET_BRIDGE_EVENT_TYPE_UNKNOWN, +} gadget_bridge_event_type_e; + +typedef enum gadget_bridge_notification_type +{ + GADGET_BRIDGE_NOTIFICATION_TYPE_SMS = 0, + GADGET_BRIDGE_NOTIFICATION_TYPE_EMAIL, + GADGET_BRIDGE_NOTIFICATION_TYPE_UNKNOWN, +} gadget_bridge_notification_type_e; + +typedef enum +{ + GADGET_BRIDGE_MUSIC_STATE_PAUSE = 0, + GADGET_BRIDGE_MUSIC_STATE_PLAY, + GADGET_BRIDGE_MUSIC_STATE_UNKNOWN, +} gadget_bridge_music_state_e; + +typedef struct gadget_bridge_event_data +{ + gadget_bridge_event_type_e event_type; + union + { + struct + { + struct tm gm_time; + struct tm local_time; + int8_t time_zone; + } time; + struct + { + uint32_t handle; + gadget_bridge_notification_type_e notification_type; + char *title; + char *body; + } notification; + struct + { + char *phone_number; + char *contact; + gadget_bridge_call_action_e call_action; + } call; + struct + { + float temperature_celsius; + uint8_t humidity; + char *weather_desc; + float wind_speed_kmh; + uint16_t wind_dir; + char *location; + } weather; + struct + { + bool find; + } find; + struct + { + bool heart_rate_monitor; + bool steps; + uint8_t heart_rate_interval; + } act; + struct + { + gadget_bridge_music_state_e music_state; + uint16_t position_in_seconds; + uint8_t shuffle; + uint8_t repeat; + } music_state; + struct + { + char *artist; + char *track; + uint16_t duration_in_seconds; + } music_info; + }; +} gadget_bridge_event_data_t; + +typedef void (*parser_event_callback_t)(const gadget_bridge_event_data_t *gadget_bridge_event_data); + +bool gadget_bridge_send_toast(gadget_bridge_toast_type_e toast_type, const char *message); + +bool gadget_bridge_send_firmware_version(const char *fw1, const char *fw2); + +bool gadget_bridge_send_battery_status(uint8_t battery_level_in_percent, float battery_level_in_V, bool is_charging); + +bool gadget_bridge_send_find_phone(bool find_phone); + +bool gadget_bridge_send_music_control(gadget_bridge_music_control_e music_control); + +bool gadget_bridge_handle_call(gadget_bridge_call_action_e call_action); + +bool gadget_bridge_handle_notification(gadget_bridge_call_action_e notification_action, uint32_t handle, const char *phone_number, const char *message); + +bool gadget_bridge_send_activity_data(uint16_t heart_rate_in_bpm, uint32_t step_count); + +bool gadget_bridge_send_http_request(uint32_t id, const char *url, gadget_bridge_http_request_method_e http_request_method, const char *http_body, const http_header_t *http_headers); + +void gadget_bridge_parser_register_event_callback(parser_event_callback_t parser_event_callback); + +gadget_bridge_parser_code_e gadget_bridge_parser_feed(const char *data, uint16_t length); + +gadget_bridge_parser_code_e gadget_bridge_parser_run(void); + +const char *gadget_bridge_parser_code_2_str(gadget_bridge_parser_code_e parser_code); + +const char *gadget_bridge_event_type_2_str(gadget_bridge_event_type_e event_type); + +const char *gadget_bridge_notification_type_2_str(gadget_bridge_notification_type_e notification_type); + +const char *gadget_bridge_music_state_2_str(gadget_bridge_music_state_e music_state); + +void gadget_bridge_parser_debug(void); + +#endif //GADGET_BRIDGE_H diff --git a/src/gadget_bridge_parser/gadget_bridge_parser.cbp b/src/gadget_bridge_parser/gadget_bridge_parser.cbp new file mode 100644 index 0000000..15936dc --- /dev/null +++ b/src/gadget_bridge_parser/gadget_bridge_parser.cbp @@ -0,0 +1,43 @@ + + + + + + diff --git a/src/gadget_bridge_parser/gadget_bridge_parser.depend b/src/gadget_bridge_parser/gadget_bridge_parser.depend new file mode 100644 index 0000000..109b3e3 --- /dev/null +++ b/src/gadget_bridge_parser/gadget_bridge_parser.depend @@ -0,0 +1,18 @@ +# depslib dependency file v1.0 +1681050439 source:/home/think/Desktop/Mes_documents/Programming/C_C++/gadget_bridge_parser/main.c + + + + "gadget_bridge.h" + +1681050803 source:/home/think/Desktop/Mes_documents/Programming/C_C++/gadget_bridge_parser/gadget_bridge.c + "gadget_bridge.h" + + + + +1681049124 /home/think/Desktop/Mes_documents/Programming/C_C++/gadget_bridge_parser/gadget_bridge.h + + + + diff --git a/src/gadget_bridge_parser/gadget_bridge_parser.layout b/src/gadget_bridge_parser/gadget_bridge_parser.layout new file mode 100644 index 0000000..7a3a027 --- /dev/null +++ b/src/gadget_bridge_parser/gadget_bridge_parser.layout @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/gadget_bridge_parser/main.c b/src/gadget_bridge_parser/main.c new file mode 100644 index 0000000..8e90359 --- /dev/null +++ b/src/gadget_bridge_parser/main.c @@ -0,0 +1,308 @@ +/** + * @file main.c + * @author Anatole SCHRAMM-HENRY + * @brief Source file containing the test programm used to verify the parser + * + * @version 0.1 + * @date 2023-04-10 + * + * @copyright MIT + * + */ + +#include +#include +#include + +#include "gadget_bridge.h" + +/** +[3][16]setTime(1680860758);E.setTimeZone(2.0);(s=>{s&&(s.timezone=2.0)&&require('Storage').write('setting.json',s);})(require('Storage').readJSON('setting.json',1)) +[10][16]GB({t:"calendar",id:63751,type:0,timestamp:1680991200,durationInSeconds:86400,title:"Easter Sunday",description:"Observance\nTo hide observances, go to Google Calendar Settings > Holidays in France",location:"",calName:"anatole.schramm-henry@master-stic.fr/Holidays in France",color:-15292571,allDay:true}) +[10][16]GB({t:"calendar",id:63749,type:0,timestamp:1681077600,durationInSeconds:86400,title:"Easter Monday",description:"Public holiday",location:"",calName:"anatole.schramm-henry@master-stic.fr/Holidays in France",color:-15292571,allDay:true}) +[10][16]GB({t:"weather",temp:0,hum:0,code:3200,wind:0.0,wdir:0,loc:""})[10] + +[16]GB({t:"notify",id:1680859061,body:"test hehe test",sender:"+33652623698",tel:"+33652623698"}) +[10][16]GB({t:"notify",id:1680859062,src:"Messages",title:"06 52 62 36 98",body:"test hehe test"})[10] +[16]GB({t:"notify",id:1680859063,src:"E-mail",title:"Th3maz1ng Wot Channel",body:"Test subject"})[10] +[16]GB({t:"call",cmd:"incoming",name:"+33950208629",number:"+33950208629"}) +[10][16]GB({t:"call",cmd:"end",name:"+33950208629",number:"+33950208629"})[10] + +[16]GB({t:"weather",temp:284,hum:89,code:803,txt:"nuages mod⸮r⸮s",wind:11.0,wdir:347,loc:"ST. ETIENNE"})[10] +[16]GB({t:"weather",temp:284,hum:89,code:803,txt:"nuages mod⸮r⸮s",wind:11.0,wdir:347,loc:"ST. ETIENNE"})[10] +GB({t:"find",n:true})[10] +[16]GB({t:"find",n:false})[10] +GB({t:"act",hrm:false,stp:true,int:10})[10] +[16]GB({t:"act",hrm:true,stp:true,int:10})[10] +[16]GB({t:"act",hrm:true,stp:false,int:10})[10] +[16]GB({t:"act",hrm:false,stp:false,int:10})[10] + +Add time zone +**/ + +void parser_event(const gadget_bridge_event_data_t *gadget_bridge_event_data) +{ + printf("----------->Event of type : %s\n", gadget_bridge_event_type_2_str(gadget_bridge_event_data->event_type)); + + switch(gadget_bridge_event_data->event_type) + { + case GADGET_BRIDGE_EVENT_TYPE_SET_TIME: + printf("%d:%d:%d %d/%d/%d\n%d\n", + gadget_bridge_event_data->time.local_time.tm_hour, + gadget_bridge_event_data->time.local_time.tm_min, + gadget_bridge_event_data->time.local_time.tm_sec, + gadget_bridge_event_data->time.local_time.tm_mday, + gadget_bridge_event_data->time.local_time.tm_mon, + gadget_bridge_event_data->time.local_time.tm_year + 1900, + gadget_bridge_event_data->time.time_zone); + break; + case GADGET_BRIDGE_EVENT_TYPE_NOTIFY: + printf("%u\n%s\n%s\n%s\n", + gadget_bridge_event_data->notification.handle, + gadget_bridge_notification_type_2_str(gadget_bridge_event_data->notification.notification_type), + gadget_bridge_event_data->notification.title, + gadget_bridge_event_data->notification.body); + break; + break; + case GADGET_BRIDGE_EVENT_TYPE_CALL: + printf("%u\n%s\n%s\n", + gadget_bridge_event_data->call.call_action, + gadget_bridge_event_data->call.contact, + gadget_bridge_event_data->call.phone_number); + break; + case GADGET_BRIDGE_EVENT_TYPE_WEATHER: + printf("%.2f\n%u\n%s\n%.2f\n%u\n%s\n", + gadget_bridge_event_data->weather.temperature_celsius, + gadget_bridge_event_data->weather.humidity, + gadget_bridge_event_data->weather.weather_desc, + gadget_bridge_event_data->weather.wind_speed_kmh, + gadget_bridge_event_data->weather.wind_dir, + gadget_bridge_event_data->weather.location); + break; + case GADGET_BRIDGE_EVENT_TYPE_FIND: + printf("%d\n",gadget_bridge_event_data->find.find); + break; + case GADGET_BRIDGE_EVENT_TYPE_ACT: + printf("%d\n%d\n%u\n", + gadget_bridge_event_data->act.heart_rate_monitor, + gadget_bridge_event_data->act.steps, + gadget_bridge_event_data->act.heart_rate_interval); + break; + case GADGET_BRIDGE_EVENT_TYPE_MUSIC_STATE: + printf("%s\n%u\n%u\n%u\n", + gadget_bridge_music_state_2_str(gadget_bridge_event_data->music_state.music_state), + gadget_bridge_event_data->music_state.position_in_seconds, + gadget_bridge_event_data->music_state.shuffle, + gadget_bridge_event_data->music_state.repeat); + break; + case GADGET_BRIDGE_EVENT_TYPE_MUSIC_INFO: + printf("%s\n%s\n%u\n", + gadget_bridge_event_data->music_info.artist, + gadget_bridge_event_data->music_info.track, + gadget_bridge_event_data->music_info.duration_in_seconds); + break; + default: + printf("Unhandled\n"); + } +} + +const char *sample[] = +{ +"[3]", +"[16]setTime(1680979884)", +";E.setTimeZone(2.0);", +"(s=>{s&&(s.timezone=", +"2.0)&&require('Stora", +"ge').write('setting.", +"json',s);})(require(", +"'Storage').readJSON(", +"'setting.json',1))[10]", +"[16]GB({t:\"calendar\",id", +":63992,type:0,timest", +"amp:1680991200,durat", +"ionInSeconds:86400,t", +"itle:\"Easter Sunday\"", +",description:\"Observ", +"ance\nTo hide observ", +"ances, go to Google ", +"Calendar Settings > ", +"Holidays in France\",", +"location:\"\",calName:", +"\"anatole.schramm-hen", +"ry@master-stic.fr/Ho", +"lidays in France\",co", +"lor:-15292571,allDay", +":true})[10]", +"[16]GB({t:\"calendar\",id", +":63990,type:0,timest", +"amp:1681077600,durat", +"ionInSeconds:86400,t", +"itle:\"Easter Monday\"", +",description:\"Public", +" holiday\",location:\"", +"\",calName:\"anatole.s", +"chramm-henry@master-", +"stic.fr/Holidays in ", +"France\",color:-15292", +"571,allDay:true})[10]", +"[16]GB({t:\"act\",hrm:fal", +"se,stp:true,int:10})", +"[10]", +"[16]GB({t:\"act\",hrm:tru", +"e,stp:true,int:10})[10]", +"[16]GB({t:\"act\",hrm:tru", +"e,stp:false,int:10})", +"[10]", +"[16]GB({t:\"act\",hrm:fal", +"se,stp:false,int:10}", +")[10]", +"[16]GB({t:\"find\",n:true", +"})[10]", +"[16]GB({t:\"find\",n:fals", +"e})[10]", +"[16]GB({t:\"find\",n:fals", +"e})[10]", + +"[16]GB({t:\"weather\",tem", +"p:277,hum:96,code:80", +"4,txt:\"tr⸮s nuageux\"", +",wind:4.0,wdir:130,l", +"oc:\"ST. ETIENNE\"})[10]", + +"[16]GB({t:\"notify\",id:1", +"680945578,body:\"test", +" 1 2 1 2\",sender:\"+3", +"3652623698\",tel:\"+33", +"652623698\"})[10]", + +"[16]GB({t:\"notify\",id:1", +"680945579,src:\"Messa", +"ges\",title:\"06 52 62", +" 36 98\",body:\"test 1", +" 2 1 2\"})[10]", + +"[16]GB({t:\"notify\",id:1", +"6809533,src:\"Messa", +"ges\",title:\"06 52 62", +" 36 98\",body:\"test 2", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +" lol xptdr\"})[10]", + +"[16]GB({t:\"call\",cm", +"d:\"incoming\",nam", +"e:\"+3395020862", +"9\",number:\"+33950208", +"629\"})", + +"[16]GB({t:\"call\",cm", +"d:\"end\",nam", +"e:\"+3395020862", +"9\",number:\"+33950208", +"629\"})", + +"[16]GB({t:\"notify\",id", +":1680859063,src:\"E-mail", +"\",title:\"Th3maz1ng Wo", +"qsfsqfqsfagueule", +"et ce txcbxcbcxbxccxbcxcbcbeule", +"et ce txvvxcvcxvbnbv,jkmlgueule", +"et ce titre estcvbcnvcnghjhjhgjghueule", +"et ce titre ewcwxcxwcxwc magueule", +"t Channel\",body:\"Test", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +"Lorem ipsum dolor sit ", +" subject\"})[10]", + +"[16]GB({t:\"notify\",id", +":1680859063,src:\"E-mail", +"\",title:\"Th3maz1ng Wo", +"t Channel\",body:\"Test", +" subject\"})[10]", + +"[16]GB({t:\"musicinfo\",a", +"rtist:\"The Good Life", +" Radio x Sensual Mus", +"ique\",track:\"The Goo", +"d Life Radio⸮?⸮24/7 ", +"Live Radio | Best Re", +"lax House, Chillout,", +" Study, Running, Gym", +", Happy Music\",dur:0", +",c:-1,n:-1})[10]", + +"[16]GB({t:\"musicstate\",", +"state:\"pause\",positi", +"on:3587,shuffle:1,re", +"peat:1})[10]", + +"[16]GB({t:\"musicinfo\",a", +"rtist:\"The Good Life", +" Radio x Sensual Mus", +"ique\",track:\"The Goo", +"d Life Radio⸮?⸮24/7 ", +"Live Radio | Best Re", +"lax House, Chillout,", +" Study, Running, Gym", +", Happy Music\",dur:0", +",c:-1,n:-1})[10]", + +"[16]GB({t:\"musicstate\",", +"state:\"play\",positio", +"n:3582,shuffle:1,rep", +"eat:1})[10]", + +"[16]GB({t:\"musicinfo\",a", +"rtist:\"Bliss Corpora", +"tion\",track:\"Eiffel ", +"65 - Blue (Da Ba Dee", +") [Gabry Ponte Ice P", +"op Mix] (Original Vi", +"deo with subtitles)\"", +",dur:219,c:-1,n:-1})", + + + +}; + +int main() +{ + gadget_bridge_parser_code_e code; + + printf("Testing the gadget bridge parser :\n"); + + gadget_bridge_parser_register_event_callback(&(parser_event)); + + uint8_t sample_count = sizeof sample / sizeof *sample; + printf("Number of samples : %u\n", sample_count); + + for(uint8_t i = 0; i < sample_count; i++) + { + gadget_bridge_parser_feed(sample[i], strlen(sample[i])); + + gadget_bridge_parser_debug(); + while((code = gadget_bridge_parser_run()) == GADGET_BRIDGE_PARSER_CODE_PARSING); + printf("Parser code : %s\n", gadget_bridge_parser_code_2_str(code)); + gadget_bridge_parser_debug(); + } + + return 0; +}