diff --git a/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.c b/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.c index 8f1d2e0..5c91098 100644 --- a/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.c +++ b/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.c @@ -6,19 +6,107 @@ #include "wm_timer.h" #include "wm_pwm.h" +#define INTERRUPT_POLICY (0) +#define POLL_POLICY (1) +#define BATTERY_CONTROLLER_STATUS_DETECTION_POLICY INTERRUPT_POLICY + +/* Battery voltage and ADC */ static int8_t _adc_offset = 0; + +/* Vibration motor timer */ static uint8_t _vibration_motor_timer_id = WM_TIMER_ID_INVALID; +/* Battery charge controller status */ +static battery_controller_status_e _battery_fsm = BATTERY_CONTROLLER_STATUS_DISCHARGING; +static BatteryControllerStatusChangeCb_t _BatteryControllerStatusChangeCb = NULL; + static void vibration_motor_timer_irq_cb(void *p) { (void)p; tls_pwm_stop(VIBRATION_MOTOR_PWM_CHANNEL); tls_gpio_cfg(VIBRATION_MOTOR_ENABLE, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_FLOATING); tls_gpio_write(VIBRATION_MOTOR_ENABLE, 0); - APP_LOG_DEBUG("Vibration stopped"); } +#if BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == POLL_POLICY +static uint8_t _battery_status_timer_id = WM_TIMER_ID_INVALID; + +static void battery_status_timer_irq_cb(void *p) +{ + bool charging = tls_gpio_read(BATTERY_CONTROLLER_CHARGING_STATUS) == 0; + bool charged = tls_gpio_read(BATTERY_CONTROLLER_CHARGED_STATUS) == 0; + + battery_controller_status_e old_battery_status = _battery_fsm; + + if(charging && !charged) + _battery_fsm = BATTERY_CONTROLLER_STATUS_CHARGING; + else if(!charging && charged) + _battery_fsm = BATTERY_CONTROLLER_STATUS_CHARGED; + else if (!charging && !charged) + _battery_fsm = BATTERY_CONTROLLER_STATUS_DISCHARGING; + else + _battery_fsm = BATTERY_CONTROLLER_STATUS_ERROR; + + if(old_battery_status != _battery_fsm) + { + // Let's call a user registered callback here + APP_LOG_INFO("Battery status changed from %s to %s", + battery_controller_status_2_str(old_battery_status), + battery_controller_status_2_str(_battery_fsm)); + + if(_BatteryControllerStatusChangeCb) _BatteryControllerStatusChangeCb(old_battery_status, _battery_fsm); + } +} +#elif BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == INTERRUPT_POLICY +static void battery_controller_irq_cb(void *p) +{ + enum tls_io_name gpio_pin = (enum tls_io_name)p; + + if(BATTERY_CONTROLLER_CHARGING_STATUS == gpio_pin) + { + tls_clr_gpio_irq_status(BATTERY_CONTROLLER_CHARGING_STATUS); + } + if(BATTERY_CONTROLLER_CHARGED_STATUS == gpio_pin) + { + tls_clr_gpio_irq_status(BATTERY_CONTROLLER_CHARGED_STATUS); + } + + bool charging = tls_gpio_read(BATTERY_CONTROLLER_CHARGING_STATUS) == 0; + bool charged = tls_gpio_read(BATTERY_CONTROLLER_CHARGED_STATUS) == 0; + + battery_controller_status_e old_battery_status = _battery_fsm; + + switch(old_battery_status) + { + case BATTERY_CONTROLLER_STATUS_CHARGING: + if(charged) _battery_fsm = BATTERY_CONTROLLER_STATUS_CHARGED; + else if(!charged && !charging) _battery_fsm = BATTERY_CONTROLLER_STATUS_DISCHARGING; + break; + case BATTERY_CONTROLLER_STATUS_CHARGED: + if(!charged && !charging) _battery_fsm = BATTERY_CONTROLLER_STATUS_DISCHARGING; + break; + case BATTERY_CONTROLLER_STATUS_DISCHARGING: + if(charging) _battery_fsm = BATTERY_CONTROLLER_STATUS_CHARGING; + break; + default: + _battery_fsm = BATTERY_CONTROLLER_STATUS_DISCHARGING; + break; + } + + if(old_battery_status != _battery_fsm) + { + // Let's call a user registered callback here + APP_LOG_INFO("Battery status changed from %s to : %s, IRQ : %u", + battery_controller_status_2_str(old_battery_status), + battery_controller_status_2_str(_battery_fsm), + gpio_pin); + + if(_BatteryControllerStatusChangeCb) _BatteryControllerStatusChangeCb(old_battery_status, _battery_fsm); + } +} +#endif + static void watch_peripherals_io_init(void) { /* We initialize the ADC input as well as the gpio used to enabled the voltage divider bridge */ @@ -31,8 +119,34 @@ static void watch_peripherals_io_init(void) tls_gpio_write(VIBRATION_MOTOR_ENABLE, 0); /* We initialize the pins used to read the battery controller IC charging and charged statuses */ - tls_gpio_cfg(BATTERY_CONTROLLER_CHARGING_STATUS, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_FLOATING); tls_gpio_cfg(BATTERY_CONTROLLER_CHARGED_STATUS, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_FLOATING); + tls_gpio_cfg(BATTERY_CONTROLLER_CHARGING_STATUS, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_FLOATING); + +#if BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == INTERRUPT_POLICY + tls_gpio_isr_register(BATTERY_CONTROLLER_CHARGED_STATUS, &(battery_controller_irq_cb), (int*) BATTERY_CONTROLLER_CHARGED_STATUS); + tls_gpio_irq_enable(BATTERY_CONTROLLER_CHARGED_STATUS, WM_GPIO_IRQ_TRIG_DOUBLE_EDGE); // Enabled when level is changing edge + + tls_gpio_isr_register(BATTERY_CONTROLLER_CHARGING_STATUS, &(battery_controller_irq_cb), (int*) BATTERY_CONTROLLER_CHARGING_STATUS); + tls_gpio_irq_enable(BATTERY_CONTROLLER_CHARGING_STATUS, WM_GPIO_IRQ_TRIG_DOUBLE_EDGE); // Enabled when level is changing edge +#endif +} + +#ifndef CASE_RETURN_STR +#define CASE_RETURN_STR(const) case const: return #const; +#endif + +const char *battery_controller_status_2_str(battery_controller_status_e status) +{ + switch(status) + { + CASE_RETURN_STR(BATTERY_CONTROLLER_STATUS_CHARGING) + CASE_RETURN_STR(BATTERY_CONTROLLER_STATUS_DISCHARGING) + CASE_RETURN_STR(BATTERY_CONTROLLER_STATUS_CHARGED) + CASE_RETURN_STR(BATTERY_CONTROLLER_STATUS_ERROR) + + default: + return "Unknown Battery Status"; + } } void watch_peripherals_init(int8_t adcOffset) @@ -43,7 +157,7 @@ void watch_peripherals_init(int8_t adcOffset) /* Prevent multiple init call !*/ if(WM_TIMER_ID_INVALID == _vibration_motor_timer_id) { - /* Let's initialize the timer w'll use to stop the vibration motor */ + /* Let's initialize the timer we'll use to stop the vibration motor */ struct tls_timer_cfg vibration_motor_timer_cfg = { .arg = NULL, @@ -55,8 +169,32 @@ void watch_peripherals_init(int8_t adcOffset) _vibration_motor_timer_id = tls_timer_create(&vibration_motor_timer_cfg); if(WM_TIMER_ID_INVALID == _vibration_motor_timer_id) - APP_LOG_ERROR("Failed to create timer"); + APP_LOG_ERROR("Failed to create vibration motor timer"); } +#if BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == POLL_POLICY + if(WM_TIMER_ID_INVALID == _battery_status_timer_id) + { + struct tls_timer_cfg battery_status_timer_cfg = + { + .arg = NULL, + .callback = &(battery_status_timer_irq_cb), + .unit = TLS_TIMER_UNIT_MS, + .is_repeat = true, + .timeout = 200 + }; + _battery_status_timer_id = tls_timer_create(&battery_status_timer_cfg); + + if(WM_TIMER_ID_INVALID == _battery_status_timer_id) + APP_LOG_ERROR("Failed to create battery status timer"); + else + tls_timer_start(_battery_status_timer_id); + } +#endif +} + +void watch_peripherals_register_battery_controller_status_change_cb(BatteryControllerStatusChangeCb_t BatteryControllerStatusChangeCb) +{ + _BatteryControllerStatusChangeCb = BatteryControllerStatusChangeCb; } uint16_t watch_peripherals_get_battery_voltage(battery_unit_e unit) @@ -100,22 +238,11 @@ uint8_t battery_voltage_to_percentage(uint16_t voltage_in_mV) battery_controller_status_e watch_peripherals_get_battery_controller_status(void) { - bool charging = tls_gpio_read(BATTERY_CONTROLLER_CHARGING_STATUS) == 0; - bool charged = tls_gpio_read(BATTERY_CONTROLLER_CHARGED_STATUS) == 0; - - if(charging && !charged) - return BATTERY_CHARGING; - else if(!charging && charged) - return BATTERY_CHARGED; - else if (!charging && !charged) - return BATTERY_DISCHARGING; - else - return BATTERY_ERROR; + return _battery_fsm; } void watch_peripherals_vibrate(uint8_t strength, uint32_t durationMs) { - APP_LOG_DEBUG("Vibration started"); /* No need to do anything if the duration is 0 or if the strength is 0 */ if(!strength || !durationMs) return; /* We start the timer which will stop the vibration after durationMs time */ diff --git a/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.h b/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.h index e81226c..8dd9f03 100644 --- a/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.h +++ b/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.h @@ -15,12 +15,22 @@ typedef enum battery_unit typedef enum battery_controller_status { - BATTERY_CHARGING = 0, - BATTERY_CHARGED, - BATTERY_DISCHARGING, - BATTERY_ERROR + BATTERY_CONTROLLER_STATUS_DISCHARGING = 0, + BATTERY_CONTROLLER_STATUS_CHARGING, + BATTERY_CONTROLLER_STATUS_CHARGED, + BATTERY_CONTROLLER_STATUS_ERROR } battery_controller_status_e; +typedef void (*BatteryControllerStatusChangeCb_t)(battery_controller_status_e old, battery_controller_status_e new); + +/** + * @brief Helper function to easily print the battery status enumeration name + * + * @param status the enumeration value for which to get the name + * @return const char* a string representing the enumeration value + */ +const char *battery_controller_status_2_str(battery_controller_status_e status); + /** * @brief Inits the watch peripherals driver. * This must be called before using the API. @@ -29,6 +39,14 @@ typedef enum battery_controller_status */ void watch_peripherals_init(int8_t adcOffset); +/** + * @brief Registers the user provided callback function to notify the battery controller status change event + * @note This function should be as short as possible, do not call LVGL functions in it. + * + * @param BatteryStatusChangeCb a pointer to the function having the right definition. + */ +void watch_peripherals_register_battery_controller_status_change_cb(BatteryControllerStatusChangeCb_t BatteryStatusChangeCb); + /** * @brief Reads and returns the current battery voltage in mV or it's corresponding capacity in percentage. * This function takes into account the adcOffset parameter provided in the @ref watch_peripherals_init @@ -50,9 +68,9 @@ uint8_t battery_voltage_to_percentage(uint16_t voltage_in_mV); /** * @brief Returns the current battery controller IC status. - * It can be one of the following + * It can be one of the following : * - * @return battery_controller_status_e + * @return battery_controller_status_e BATTERY_CHARGING, BATTERY_CHARGED, BATTERY_DISCHARGING and BATTERY_ERROR. */ battery_controller_status_e watch_peripherals_get_battery_controller_status(void);