Documented almost every function of the API, implemented the http request command which is useless since GadgetBridge does not have internet permissions :(

This commit is contained in:
Th3maz1ng 2023-04-09 12:41:38 +02:00
parent bfba12e43b
commit b3bf6ce896
2 changed files with 243 additions and 13 deletions

View File

@ -6,7 +6,7 @@
* @version 0.1
* @date 2023-04-05
*
* @copyright Copyright (c) 2023
* @copyright MIT
*
*/
@ -28,9 +28,11 @@ typedef enum gadget_bridge_parser_fsm
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,
@ -77,6 +79,7 @@ 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);
@ -169,6 +172,30 @@ bool gadget_bridge_send_activity_data(uint16_t heart_rate_in_bpm, uint32_t step_
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;
}
/*bool gadget_bridge_send_force_calendar_sync(void)
{
bool to_return = true;
to_return &= ble_service_send_nus_data((const uint8_t *)"{\"t\":\"force_calendar_sync\"} \n", 29);
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;
@ -389,12 +416,31 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
else to_return = GADGET_BRIDGE_PARSER_CODE_OK;
break;
case GADGET_BRIDGE_PARSER_FSM_FOUND_TITLE:
if((start = strstr(_gadget_bridge_internals.buffer, "title:"))
&& (end = strstr(_gadget_bridge_internals.buffer, ",body")))
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(start + 7, end - 1, &_gadget_bridge_internals.event_data.notification.title);
_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;
@ -403,19 +449,52 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
);
_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_FOUND_SRC_BODY:
if((start = strstr(_gadget_bridge_internals.buffer, "body:"))
&& (end = strstr(_gadget_bridge_internals.buffer, "})")))
case GADGET_BRIDGE_PARSER_FSM_PARSING_BODY_CONTENT:
{
end = strstr(_gadget_bridge_internals.buffer, "})");
if(end)
{
//printf("###NOTIFICATION Type one done\n");
//printf("###NOTIFICATION Type done\n");
_parser_extract_char_str(start + 6, end - 1, &_gadget_bridge_internals.event_data.notification.body);
_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;
@ -431,12 +510,34 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
_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;
// 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:"))
@ -556,6 +657,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
_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;
@ -690,6 +792,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
_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;
@ -716,6 +819,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
_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;
@ -783,6 +887,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_run(void)
}
// 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;
@ -898,6 +1003,26 @@ static const char *_gadget_bridge_music_control_2_str(gadget_bridge_music_contro
}
}
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';

View File

@ -17,13 +17,34 @@
#include <time.h>
/**
* @brief Size of the internal buffer used to store incoming data
* which needs to be parsed.
* @brief GADGET_BRIDGE_PARSER_BUFFER_SIZE allows to set the size of the buffer
* which is internally used by the parser to do it's job.
*
*/
#define GADGET_BRIDGE_PARSER_BUFFER_SIZE (300)
/**
* @brief GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD permits to set a size threshold used to free up
* some space in the parser's internal buffer when the threshold is reached.
* This ensures that we can keep on feeding new data and not get stuck.
*
*/
#define GADGET_BRIDGE_PARSER_BUFFER_THRESHOLD (100)
/**
* @brief GADGET_BRIDGE_PARSER_MAX_BODY_SIZE defines the max body size that will be saved in the event_data
* structure when parsing the body of a notification.
*
*/
#define GADGET_BRIDGE_PARSER_MAX_BODY_SIZE (200)
/**
* @brief GADGET_BRIDGE_PARSER_MAX_TITLE_SIZE defines the max title size that will be saved in the event_data
* structure when parsing the title of a notification.
*
*/
#define GADGET_BRIDGE_PARSER_MAX_TITLE_SIZE (100)
typedef enum gadget_bridge_toast_type
{
GADGET_BRIDGE_TOAST_TYPE_INFO = 0,
@ -157,28 +178,112 @@ typedef struct gadget_bridge_event_data
typedef void (*parser_event_callback_t)(const gadget_bridge_event_data_t *gadget_bridge_event_data);
/**
* @brief Sends an Android toast to GadgetBridge to be displayed on the phone.
*
* @param toast_type the type of the toast (INFO, WARN or ERROR).
* @param message a string representing the message to display.
* @return true if the command was successfully sent.
* @return false otherwise.
*/
bool gadget_bridge_send_toast(gadget_bridge_toast_type_e toast_type, const char *message);
/**
* @brief Sends up to two firmwares version to GadgetBridge.
* These are displayed in the display details section of the watch in GadgetBridge.
*
* @param fw1 a string representing the first firmware version.
* @param fw2 a string representing the second firmware version.
* @return true if the command was successfully sent.
* @return false otherwise.
*/
bool gadget_bridge_send_firmware_version(const char *fw1, const char *fw2);
/**
* @brief Sends the current battery status to GadgetBridge.
*
* @param battery_level_in_percent the current battery level from 0 to 100%.
* @param battery_level_in_V the current battery voltage in volts (3.942 for example).
* @param is_charging a boolean which indicates if the battery is currently charging or not.
* @return true if the command was successfully sent.
* @return false otherwise.
*/
bool gadget_bridge_send_battery_status(uint8_t battery_level_in_percent, float battery_level_in_V, bool is_charging);
/**
* @brief Sends the find phone command to GagdetBridge, this will make the phone ring and vibrate
* so that you can locate it.
*
* @param find_phone a boolean which indicates to make the phone rind and vibrate or not.
* @return true if the command was successfully sent.
* @return false otherwise.
*/
bool gadget_bridge_send_find_phone(bool find_phone);
/**
* @brief Sends a command to control the music playback of the phone through GadgetBridge.
*
* @param music_control an enumeration value indicating the action to perform:
* PLAY, PAUSE, NEXT, PREVIOUS, VOLUMEUP etc..
* @return true if the command was successfully sent.
* @return false otherwise.
*/
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);
/**
* @brief Sends the provided activity data to GadgetBridge. This will then be displayed
* on the app in the activity section.
*
* @param heart_rate_in_bpm the current heart rate in beat per minute
* @param step_count the number of new steps since the last time the count was sent.
* @return true if the command was successfully sent.
* @return false otherwise.
*/
bool gadget_bridge_send_activity_data(uint16_t heart_rate_in_bpm, uint32_t step_count);
/**
* @brief Tells GadgetBridge to perform an HTTP request for us.
* @note THIS DOES NOT WORK as GadgetBridge don't and will never have network permission... what a pitty !
*
* @param id an unsigned integer representing the ID of the http request
* @param url a string representing the URL to fetch
* @param http_request_method a enumeration value specifying the http verb to use : GET, POST, PATCH etc..
* @param http_body the body to include in the request (not implemented yet)
* @param http_headers various headers to include in the request (not implemented yet)
* @return true if the request has been successfully sent to GadgetBridge
* @return false otherwise
*/
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 gadget_bridge_send_force_calendar_sync(void);
/**
* @brief Registers a callback function used to listen for GadgetBridge events.
*
* @param parser_event_callback
*/
void gadget_bridge_parser_register_event_callback(parser_event_callback_t parser_event_callback);
/**
* @brief Feeds new data to the GadgetBridge parser.
*
* @param data the new chunk of data to parse, it will be copied to the parser's internal buffer,
* so you can free the memory containing the string after calling the function.
* @param length the length in bytes of the new chunk.
* @return gadget_bridge_parser_code_e GADGET_BRIDGE_PARSER_CODE_OK if no error occured.
*/
gadget_bridge_parser_code_e gadget_bridge_parser_feed(const char *data, uint16_t length);
/**
* @brief Call this function to run the parser.
* It should be safe to call if in a loop like : while((code = gadget_bridge_parser_run()) == GADGET_BRIDGE_PARSER_CODE_PARSING);
*
* @return gadget_bridge_parser_code_e the parser's execution status code.
*/
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);