/** * @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 "wm_type_def.h" #include /** * @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, 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_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 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; }; } gadget_bridge_event_data_t; 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); 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); void gadget_bridge_parser_debug(void); #endif //GADGET_BRIDGE_H