From 83b1571067db46450d59f4b5c977f055f85a5f6f Mon Sep 17 00:00:00 2001 From: anschrammh Date: Mon, 18 Dec 2023 21:16:48 +0100 Subject: [PATCH] Updated the GadgetBridge parser api to be able to interact with received notifications (DISMISS, OPEN, REPLY etc) --- src/W800_SDK_v1.00.10/app/ble/gadget_bridge.c | 74 ++++++++++++++++--- src/W800_SDK_v1.00.10/app/ble/gadget_bridge.h | 53 +++++++------ 2 files changed, 96 insertions(+), 31 deletions(-) diff --git a/src/W800_SDK_v1.00.10/app/ble/gadget_bridge.c b/src/W800_SDK_v1.00.10/app/ble/gadget_bridge.c index 9d563ea..92bf567 100644 --- a/src/W800_SDK_v1.00.10/app/ble/gadget_bridge.c +++ b/src/W800_SDK_v1.00.10/app/ble/gadget_bridge.c @@ -7,9 +7,9 @@ * @date 2023-04-05 * Updated : 2023-10-15, fixed potential memory leak. * Updated : 2023-10-17, fixed potential issue where a double quote is added at the start of a parsed string. - * + * * @copyright MIT - * + * */ #include "gadget_bridge.h" @@ -93,6 +93,7 @@ static 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_notification_action_2_str(gadget_bridge_notification_action_e notification_action); 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); @@ -138,8 +139,8 @@ bool gadget_bridge_send_battery_status(uint8_t battery_level_in_percent, float b 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)); + int length = 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, length); return to_return; } @@ -166,6 +167,41 @@ bool gadget_bridge_send_music_control(gadget_bridge_music_control_e music_contro return to_return; } +bool gadget_bridge_send_notification_action(gadget_bridge_notification_action_e notification_action, uint32_t handle, const char *phone_number, const char *message) +{ + bool to_return = true; + char num_2_str[11] = ""; + + // There is no point sending a reply without an actual message + if(notification_action == GADGET_BRIDGE_NOTIFICATION_ACTION_REPLY && !message) + return false; + + to_return &= ble_service_send_nus_data((const uint8_t *)"{\"t\":\"notify\",\"n\":\"", 19); + to_return &= ble_service_send_nus_data((const uint8_t *)_gadget_bridge_notification_action_2_str(notification_action), strlen(_gadget_bridge_notification_action_2_str(notification_action))); + to_return &= ble_service_send_nus_data((const uint8_t *)"\",\"id\":", 7); + + int length = sprintf(num_2_str, "%u", handle); + to_return &= ble_service_send_nus_data((const uint8_t *)num_2_str, length); + + if(notification_action == GADGET_BRIDGE_NOTIFICATION_ACTION_REPLY) + { + if(phone_number) + { + to_return &= ble_service_send_nus_data((const uint8_t *)",\"tel\":\"", 8); + to_return &= ble_service_send_nus_data((const uint8_t *)phone_number, strlen(phone_number)); + to_return &= ble_service_send_nus_data((const uint8_t *)"\"", 1); + } + + to_return &= ble_service_send_nus_data((const uint8_t *)",\"msg\":\"", 8); + to_return &= ble_service_send_nus_data((const uint8_t *)message, strlen(message)); + to_return &= ble_service_send_nus_data((const uint8_t *)"\"", 1); + } + + to_return &= ble_service_send_nus_data((const uint8_t *)"} \n", 3); + + return to_return; +} + bool gadget_bridge_send_activity_data(uint16_t heart_rate_in_bpm, uint32_t step_count) { bool to_return = true; @@ -173,13 +209,13 @@ bool gadget_bridge_send_activity_data(uint16_t heart_rate_in_bpm, uint32_t step_ //{\"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)); + int length = sprintf(num_2_str, "%u", heart_rate_in_bpm); + to_return &= ble_service_send_nus_data((const uint8_t *)num_2_str, length); 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)); + length = sprintf(num_2_str, "%u", step_count); + to_return &= ble_service_send_nus_data((const uint8_t *)num_2_str, length); to_return &= ble_service_send_nus_data((const uint8_t *)"} \n", 3); @@ -190,10 +226,10 @@ bool gadget_bridge_send_http_request(uint32_t id, const char *url, gadget_bridge { bool to_return = true; char num_2_str[11] = ""; - sprintf(num_2_str, "%u", id); + int length = 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 *)num_2_str, length); 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); @@ -1318,6 +1354,24 @@ static const char *_gadget_bridge_music_control_2_str(gadget_bridge_music_contro } } +static const char *_gadget_bridge_notification_action_2_str(gadget_bridge_notification_action_e notification_action) +{ + switch(notification_action) + { + case GADGET_BRIDGE_NOTIFICATION_ACTION_DISMISS_ALL: + return "dismiss_all"; + case GADGET_BRIDGE_NOTIFICATION_ACTION_OPEN: + return "open"; + case GADGET_BRIDGE_NOTIFICATION_ACTION_MUTE: + return "mute"; + case GADGET_BRIDGE_NOTIFICATION_ACTION_REPLY: + return "reply"; + case GADGET_BRIDGE_NOTIFICATION_ACTION_DISMISS: + default : + return "dismiss"; + } +} + static const char *_gadget_bridge_http_request_method_2_str(gadget_bridge_http_request_method_e http_request_method) { switch(http_request_method) diff --git a/src/W800_SDK_v1.00.10/app/ble/gadget_bridge.h b/src/W800_SDK_v1.00.10/app/ble/gadget_bridge.h index 2f01af3..cfae539 100644 --- a/src/W800_SDK_v1.00.10/app/ble/gadget_bridge.h +++ b/src/W800_SDK_v1.00.10/app/ble/gadget_bridge.h @@ -5,9 +5,9 @@ * over BLE. * @version 0.1 * @date 2023-04-04 - * + * * @copyright MIT - * + * */ #ifndef GADGET_BRIDGE_H @@ -19,7 +19,7 @@ /** * @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) @@ -27,21 +27,21 @@ * @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) @@ -205,7 +205,7 @@ typedef void (*parser_event_callback_t)(gadget_bridge_event_data_t *gadget_bridg /** * @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. @@ -216,7 +216,7 @@ bool gadget_bridge_send_toast(gadget_bridge_toast_type_e toast_type, const char /** * @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. @@ -226,7 +226,7 @@ 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. @@ -238,7 +238,7 @@ bool gadget_bridge_send_battery_status(uint8_t battery_level_in_percent, float b /** * @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. @@ -247,22 +247,33 @@ 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: + * + * @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); +/** + * @brief Sends a command to perform an action to the specified received notification. + * + * @param notification_action an enumeration value indicating the action to perform on the notification : + * DISMISS, DISMISS_ALL, OPEN, MUTE and REPLY. + * @param handle the notification's handle. + * @param phone_number a string containing a phone number to send the REPLY to or NULL to use the same number as the notification. + * @param message a string containing the message to send to a REPLY action, can be NULL if the action is different. + * @return true if the command was successfully sent. + * @return false otherwise. + */ +bool gadget_bridge_send_notification_action(gadget_bridge_notification_action_e notification_action, uint32_t handle, const char *phone_number, const char *message); + 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 + * @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. @@ -273,7 +284,7 @@ bool gadget_bridge_send_activity_data(uint16_t heart_rate_in_bpm, uint32_t step_ /** * @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.. @@ -288,14 +299,14 @@ bool gadget_bridge_send_http_request(uint32_t id, const char *url, gadget_bridge /** * @brief Registers a callback function used to listen for GadgetBridge events. - * - * @param parser_event_callback + * + * @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. @@ -306,7 +317,7 @@ gadget_bridge_parser_code_e gadget_bridge_parser_feed(const char *data, uint16_t /** * @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);