Compare commits
No commits in common. "beb7a86af1e834df9866e22290fd8d41b0c0b17d" and "8a9b805b95fced271b31b48d3d2c7a470bd9d16e" have entirely different histories.
beb7a86af1
...
8a9b805b95
@ -34,7 +34,6 @@ COMPONENTS_$(TARGET) = \
|
||||
$(TOP_DIR)/app/app_drivers/libappdrivers$(LIB_EXT) \
|
||||
$(TOP_DIR)/app/persistency/libpersistency$(LIB_EXT) \
|
||||
$(TOP_DIR)/app/translation/libtranslation$(LIB_EXT) \
|
||||
$(TOP_DIR)/app/translation/libble$(LIB_EXT) \
|
||||
$(TOP_DIR)/lvgl/liblvgl$(LIB_EXT)
|
||||
|
||||
ifeq ($(USE_LIB), 0)
|
||||
|
@ -6,107 +6,19 @@
|
||||
#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 */
|
||||
@ -119,34 +31,8 @@ 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_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";
|
||||
}
|
||||
tls_gpio_cfg(BATTERY_CONTROLLER_CHARGED_STATUS, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_FLOATING);
|
||||
}
|
||||
|
||||
void watch_peripherals_init(int8_t adcOffset)
|
||||
@ -157,7 +43,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 we'll use to stop the vibration motor */
|
||||
/* Let's initialize the timer w'll use to stop the vibration motor */
|
||||
struct tls_timer_cfg vibration_motor_timer_cfg =
|
||||
{
|
||||
.arg = NULL,
|
||||
@ -169,32 +55,8 @@ 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 vibration motor timer");
|
||||
APP_LOG_ERROR("Failed to create 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)
|
||||
@ -238,11 +100,22 @@ uint8_t battery_voltage_to_percentage(uint16_t voltage_in_mV)
|
||||
|
||||
battery_controller_status_e watch_peripherals_get_battery_controller_status(void)
|
||||
{
|
||||
return _battery_fsm;
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
@ -15,22 +15,12 @@ typedef enum battery_unit
|
||||
|
||||
typedef enum battery_controller_status
|
||||
{
|
||||
BATTERY_CONTROLLER_STATUS_DISCHARGING = 0,
|
||||
BATTERY_CONTROLLER_STATUS_CHARGING,
|
||||
BATTERY_CONTROLLER_STATUS_CHARGED,
|
||||
BATTERY_CONTROLLER_STATUS_ERROR
|
||||
BATTERY_CHARGING = 0,
|
||||
BATTERY_CHARGED,
|
||||
BATTERY_DISCHARGING,
|
||||
BATTERY_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.
|
||||
@ -39,14 +29,6 @@ const char *battery_controller_status_2_str(battery_controller_status_e 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
|
||||
@ -68,9 +50,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 BATTERY_CHARGING, BATTERY_CHARGED, BATTERY_DISCHARGING and BATTERY_ERROR.
|
||||
* @return battery_controller_status_e
|
||||
*/
|
||||
battery_controller_status_e watch_peripherals_get_battery_controller_status(void);
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
TOP_DIR = ../..
|
||||
sinclude $(TOP_DIR)/tools/w800/conf.mk
|
||||
|
||||
ifndef PDIR
|
||||
GEN_LIBS = libble$(LIB_EXT)
|
||||
endif
|
||||
|
||||
#DEFINES +=
|
||||
|
||||
sinclude $(TOP_DIR)/tools/w800/rules.mk
|
||||
|
||||
INCLUDES := $(INCLUDES) -I $(PDIR)include
|
||||
|
||||
PDIR := ../$(PDIR)
|
||||
sinclude $(PDIR)Makefile
|
@ -1,91 +0,0 @@
|
||||
#include "ble_modem.h"
|
||||
#include "app_common.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "wm_bt_def.h"
|
||||
#include "wm_bt_app.h"
|
||||
#include "wm_bt_util.h"
|
||||
#include "ble_service.h"
|
||||
|
||||
//Is needed for the BT off workaround
|
||||
#include "wm_wifi.h"
|
||||
|
||||
bool ble_modem_on(bool startService)
|
||||
{
|
||||
int status = BLE_HS_ENOERR;
|
||||
bool serviceStartSuccess = true;
|
||||
uint8_t uart_no = 0xFF;
|
||||
tls_appl_trace_level = TLS_BT_LOG_VERBOSE; //Should be set with a config define
|
||||
|
||||
if(bt_adapter_state == WM_BT_STATE_ON) {
|
||||
TLS_BT_APPL_TRACE_VERBOSE("ble modem already on"NEW_LINE);
|
||||
return true;
|
||||
}
|
||||
|
||||
TLS_BT_APPL_TRACE_DEBUG("ble modem running, uart_no=%d, log_level=%d"NEW_LINE, uart_no,
|
||||
tls_appl_trace_level);
|
||||
status = tls_bt_init(uart_no);
|
||||
|
||||
if((status != BLE_HS_ENOERR) && (status != BLE_HS_EALREADY)) {
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, tls_bt_init ret:%s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
}
|
||||
|
||||
// Start the ble service if it was asked and if it is not yet started
|
||||
if(startService && !ble_service_is_started())
|
||||
serviceStartSuccess = ble_service_start();
|
||||
|
||||
return ((status == BLE_HS_ENOERR || status == BLE_HS_EALREADY) && serviceStartSuccess) ? true : false;
|
||||
}
|
||||
|
||||
bool ble_modem_off(void)
|
||||
{
|
||||
int status = BLE_HS_ENOERR;
|
||||
bool serviceStopSuccess = true;
|
||||
TLS_BT_APPL_TRACE_DEBUG("ble modem off"NEW_LINE);
|
||||
|
||||
if(bt_adapter_state == WM_BT_STATE_OFF)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_VERBOSE("ble modem already off"NEW_LINE);
|
||||
return TLS_BT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if(ble_service_is_started())
|
||||
{
|
||||
serviceStopSuccess = ble_service_stop();
|
||||
}
|
||||
|
||||
// Let's make a busy wait on the status of the ble service:
|
||||
uint8_t timeout = 0;
|
||||
while(ble_service_is_started())
|
||||
{
|
||||
tls_os_time_delay(pdMS_TO_TICKS(5));
|
||||
|
||||
// Service is stuck ? waiting up to 300 ms for it to stop
|
||||
if(++timeout > 60)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_service_stop timeout "NEW_LINE, __FUNCTION__);
|
||||
return serviceStopSuccess;
|
||||
}
|
||||
};
|
||||
|
||||
status = tls_bt_deinit();
|
||||
|
||||
if((status != BLE_HS_ENOERR) && (status != BLE_HS_EALREADY)) {
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, tls_bt_deinit ret:%s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
}
|
||||
|
||||
if(status != BLE_HS_EALREADY)
|
||||
{
|
||||
//Starting a wifi scan really stops the BT modem ?? Why ? I don't know
|
||||
tls_wifi_scan();
|
||||
}
|
||||
|
||||
return ((status == BLE_HS_ENOERR || status == BLE_HS_EALREADY) && serviceStopSuccess) ? true : false;
|
||||
}
|
||||
|
||||
bool is_ble_modem_on(void)
|
||||
{
|
||||
if(bt_adapter_state == WM_BT_STATE_OFF || bt_system_action != WM_BT_SYSTEM_ACTION_IDLE)
|
||||
return false;
|
||||
return true;
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
#ifndef BLE_MODEM_H
|
||||
#define BLE_MODEM_H
|
||||
|
||||
#include "wm_type_def.h"
|
||||
|
||||
/**
|
||||
* @brief Turns the BLE modem on
|
||||
*
|
||||
* @param startService to start the ble service when turning the modem on
|
||||
* @return true on success
|
||||
* @return false on failure
|
||||
*/
|
||||
bool ble_modem_on(bool startService);
|
||||
|
||||
/**
|
||||
* @brief Turns the BLE modem off
|
||||
* @note If the ble service was started, then it will automatically be turned off with the modem
|
||||
*
|
||||
* @return true on success
|
||||
* @return false on failure
|
||||
*/
|
||||
bool ble_modem_off(void);
|
||||
|
||||
/**
|
||||
* @brief Find out if the modem is turned on or not
|
||||
*
|
||||
* @return true if turned on
|
||||
* @return false if turned off
|
||||
*/
|
||||
bool is_ble_modem_on(void);
|
||||
|
||||
#endif //BLE_MODEM_H
|
@ -1,789 +0,0 @@
|
||||
#include "ble_service.h"
|
||||
#include "app_common.h"
|
||||
#include "ble_modem.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "wm_bt_util.h"
|
||||
#include "bluetooth_sig_values.h"
|
||||
|
||||
#define USABLE_DEFAULT_MTU (20) //23 - 3 of header bytes
|
||||
|
||||
/* ble service internal workings attributes */
|
||||
static volatile ble_service_state_e _ble_service_state = BLE_SERVICE_MODE_STOPPED;
|
||||
static nus_data_rx_fn_t _ble_service_nus_data_rx_cb = NULL;
|
||||
static ble_service_state_change_fn_t _ble_service_state_change_cb = NULL;
|
||||
|
||||
/* Connection handle to the connected device : only one simultaneous connection */
|
||||
static uint16_t ble_device_conn_handle = BLE_HS_CONN_HANDLE_NONE;
|
||||
static uint16_t usable_mtu = USABLE_DEFAULT_MTU;
|
||||
|
||||
/**
|
||||
* @brief Structure used to store the various data to carry out a chunked notification or indication data transfer
|
||||
*
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint16_t length; // The length of the data being sent
|
||||
uint16_t offset; // The offset used to be ableto send the next chunk of data in the array
|
||||
uint16_t sent_chunk_size; // The size of the chunk sent
|
||||
const uint8_t *data; // The address of the data to send
|
||||
bool transfer_in_progress; // Is a transfer already in progress ?
|
||||
} data_being_sent_t;
|
||||
|
||||
// Only one transfer of a type () can occur at any given time
|
||||
static data_being_sent_t notification_data = {.data = NULL, .length = 0, .offset = 0, .transfer_in_progress = false};
|
||||
static data_being_sent_t indication_data = {.data = NULL, .length = 0, .offset = 0, .transfer_in_progress = false};
|
||||
|
||||
static struct ble_gap_event_listener ble_gap_event_listener;
|
||||
|
||||
static int battery_level_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
static uint16_t battery_level_char_handle = 0;
|
||||
static uint8_t battery_level_value = 42;
|
||||
|
||||
|
||||
static int gatt_nus_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
static const ble_uuid128_t gatt_nus_service_uuid = BLE_UUID128_INIT(0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E);
|
||||
|
||||
static uint16_t gatt_nus_char_rx_handle = 0;
|
||||
static const ble_uuid128_t gatt_nus_char_rx_uuid = BLE_UUID128_INIT(0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E);
|
||||
|
||||
static uint16_t gatt_nus_char_tx_handle = 0;
|
||||
static const ble_uuid128_t gatt_nus_char_tx_uuid = BLE_UUID128_INIT(0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x03, 0x00, 0x40, 0x6E);
|
||||
|
||||
static struct ble_gatt_svc_def gatt_svc[] =
|
||||
{
|
||||
{
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_DEVICE_ADV_SERVICE),
|
||||
.characteristics = (struct ble_gatt_chr_def[])
|
||||
{
|
||||
{
|
||||
.uuid = BLE_UUID16_DECLARE(0x2A19),
|
||||
.val_handle = &battery_level_char_handle,
|
||||
.access_cb = &(battery_level_char_access_cb),
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY
|
||||
},
|
||||
{
|
||||
.uuid = NULL
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = &gatt_nus_service_uuid.u,
|
||||
.characteristics = (struct ble_gatt_chr_def[])
|
||||
{
|
||||
{
|
||||
.uuid = &gatt_nus_char_rx_uuid.u,
|
||||
.val_handle = &gatt_nus_char_rx_handle,
|
||||
.access_cb = &(gatt_nus_char_access_cb),
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP
|
||||
}
|
||||
,
|
||||
{
|
||||
.uuid = &gatt_nus_char_tx_uuid.u,
|
||||
.val_handle = &gatt_nus_char_tx_handle,
|
||||
.access_cb = &(gatt_nus_char_access_cb),
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY
|
||||
}
|
||||
,
|
||||
{
|
||||
.uuid = NULL
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
.type = BLE_GATT_SVC_TYPE_END
|
||||
}
|
||||
};
|
||||
|
||||
static bool ble_service_define_gatt(const struct ble_gatt_svc_def *gatt_svc);
|
||||
static bool ble_service_advertise(bool enable);
|
||||
static int ble_gap_event_cb(struct ble_gap_event *event, void *arg);
|
||||
static int ble_advertise_gap_event_cb(struct ble_gap_event *event, void *arg);
|
||||
static void print_conn_desc(const struct ble_gap_conn_desc *desc);
|
||||
// Raw because it doesn't handle payload fragmentation if mtu size is smaller than the payload size
|
||||
static bool ble_service_send_raw_custom_notification(uint16_t characteristic_handle, const uint8_t *data, uint16_t length);
|
||||
static bool ble_service_send_custom_notification(uint16_t characteristic_handle, data_being_sent_t * const data);
|
||||
static void reset_data_being_sent(data_being_sent_t * const data);
|
||||
|
||||
// Needed to get the reponse after a mtu exchange request
|
||||
static int ble_gatt_mtu_cb(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t mtu, void *arg);
|
||||
|
||||
const char *ble_service_state_2_str(ble_service_state_e state)
|
||||
{
|
||||
switch(state) {
|
||||
CASE_RETURN_STR(BLE_SERVICE_MODE_STOPPED)
|
||||
CASE_RETURN_STR(BLE_SERVICE_MODE_IDLE)
|
||||
CASE_RETURN_STR(BLE_SERVICE_MODE_ADVERTISING)
|
||||
CASE_RETURN_STR(BLE_SERVICE_MODE_CONNECTED)
|
||||
CASE_RETURN_STR(BLE_SERVICE_MODE_INDICATING)
|
||||
CASE_RETURN_STR(BLE_SERVICE_MODE_EXITING)
|
||||
default:
|
||||
return "unkown ble service state";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PUBLIC FUNCTION DEFINITION
|
||||
*/
|
||||
|
||||
bool ble_service_start(void)
|
||||
{
|
||||
int status = BLE_HS_ENOERR;
|
||||
|
||||
// 1 We first check if the BLE service is stopped
|
||||
if(_ble_service_state != BLE_SERVICE_MODE_STOPPED)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("%s, ble service already running (%s)"NEW_LINE, __FUNCTION__, ble_service_state_2_str(_ble_service_state));
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2 We check if the BLE MODEM is turned on
|
||||
if(!is_ble_modem_on())
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble modem is not turned on"NEW_LINE, __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3 We set our device name and appearance
|
||||
if((status = ble_svc_gap_device_name_set(BLE_DEVICE_NAME)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("%s, ble_svc_gap_device_name_set "NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
}
|
||||
|
||||
if((status = ble_svc_gap_device_appearance_set(BLE_DEVICE_APPEARANCE)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("%s, ble_svc_gap_device_appearance_set "NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
}
|
||||
|
||||
// 4 We register our gatt (service structure)
|
||||
if(!ble_service_define_gatt(gatt_svc))
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, failed to define gatt"NEW_LINE, __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5 We register a gap event handler callback
|
||||
if((status = ble_gap_event_listener_register(&ble_gap_event_listener, &(ble_gap_event_cb), NULL)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_gap_event_listener_register %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 6 We are now ready to make all registered services available to peers
|
||||
if((status = ble_gatts_start()) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_gatts_start failed : %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 7 Finally we can start advertising
|
||||
if(!ble_service_advertise(true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_ble_service_state = BLE_SERVICE_MODE_ADVERTISING;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ble_service_stop(void)
|
||||
{
|
||||
int status = BLE_HS_ENOERR;
|
||||
|
||||
// 1 We first check if the BLE service is not stopped
|
||||
if(_ble_service_state == BLE_SERVICE_MODE_STOPPED)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("%s, ble service already stopped"NEW_LINE, __FUNCTION__);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2 We check if the BLE MODEM is turned on
|
||||
if(!is_ble_modem_on())
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble modem is not turned on"NEW_LINE, __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(_ble_service_state)
|
||||
{
|
||||
case BLE_SERVICE_MODE_CONNECTED:
|
||||
case BLE_SERVICE_MODE_INDICATING:
|
||||
status = ble_gap_terminate(ble_device_conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
if(status == BLE_HS_ENOERR)
|
||||
{
|
||||
_ble_service_state = BLE_SERVICE_MODE_EXITING;
|
||||
}
|
||||
else //BLE_HS_EDISABLED || BLE_HS_ENOTCONN or any other error
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("%s, ble_gap_terminate %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
_ble_service_state = BLE_SERVICE_MODE_STOPPED;
|
||||
//Unregister gap event listener
|
||||
if((status = ble_gap_event_listener_unregister(&ble_gap_event_listener)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("%s, ble_gap_event_listener_unregister %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BLE_SERVICE_MODE_ADVERTISING:
|
||||
if(!ble_service_advertise(false))
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("%s, ble_service_advertise failed to stop"NEW_LINE, __FUNCTION__);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ble_service_state = BLE_SERVICE_MODE_STOPPED;
|
||||
//Unregister gap event listener
|
||||
if((status = ble_gap_event_listener_unregister(&ble_gap_event_listener)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("%s, ble_gap_event_listener_unregister %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: //Just to keep compiler happy since BLE_SERVICE_MODE_STOPPED is rulled out earlier
|
||||
break;
|
||||
}
|
||||
|
||||
if(_ble_service_state == BLE_SERVICE_MODE_STOPPED)
|
||||
{
|
||||
// We finally clean the gatt registered services
|
||||
if((status = ble_gatts_reset()) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_gatts_reset %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ble_service_is_started(void)
|
||||
{
|
||||
return _ble_service_state != BLE_SERVICE_MODE_STOPPED;
|
||||
}
|
||||
|
||||
bool ble_service_is_device_connected(void)
|
||||
{
|
||||
return _ble_service_state == BLE_SERVICE_MODE_CONNECTED;
|
||||
}
|
||||
|
||||
void ble_service_register_state_change_cb(ble_service_state_change_fn_t ble_service_state_change_cb)
|
||||
{
|
||||
_ble_service_state_change_cb = ble_service_state_change_cb;
|
||||
}
|
||||
|
||||
ble_service_state_e ble_service_get_state(void)
|
||||
{
|
||||
return _ble_service_state;
|
||||
}
|
||||
|
||||
bool ble_service_update_connection_parameters(
|
||||
uint16_t itvl_min,
|
||||
uint16_t itvl_max,
|
||||
uint16_t latency,
|
||||
uint16_t supervision_timeout,
|
||||
uint16_t min_ce_len,
|
||||
uint16_t max_ce_len)
|
||||
{
|
||||
if(BLE_HS_CONN_HANDLE_NONE == ble_device_conn_handle)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, no active connection" NEW_LINE, __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
int status = BLE_HS_ENOERR;
|
||||
|
||||
struct ble_gap_upd_params gap_params_to_apply = {0};
|
||||
gap_params_to_apply.itvl_min = itvl_min;
|
||||
gap_params_to_apply.itvl_max = itvl_max;
|
||||
gap_params_to_apply.latency = latency;
|
||||
gap_params_to_apply.supervision_timeout = supervision_timeout;
|
||||
gap_params_to_apply.min_ce_len = min_ce_len;
|
||||
gap_params_to_apply.max_ce_len = max_ce_len;
|
||||
|
||||
if ((status = ble_gap_update_params(ble_device_conn_handle, &gap_params_to_apply)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_gap_update_params failed %s" NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ble_service_request_mtu_exchange(void)
|
||||
{
|
||||
if(BLE_HS_CONN_HANDLE_NONE == ble_device_conn_handle)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, no active connection" NEW_LINE, __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
int status = BLE_HS_ENOERR;
|
||||
|
||||
if((status = ble_gattc_exchange_mtu(ble_device_conn_handle, &(ble_gatt_mtu_cb), NULL)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_gattc_exchange_mtu %s" NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ble_service_send_nus_data(const uint8_t *data, uint16_t length)
|
||||
{
|
||||
// The NUS is TX is using notifications
|
||||
if(notification_data.transfer_in_progress)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("%s, a transfer is already in progress"NEW_LINE, __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
notification_data.transfer_in_progress = true;
|
||||
notification_data.data = data;
|
||||
notification_data.length = length;
|
||||
|
||||
return ble_service_send_custom_notification(gatt_nus_char_tx_handle, ¬ification_data);
|
||||
}
|
||||
|
||||
void ble_service_register_nus_data_rx_cb(nus_data_rx_fn_t nus_data_rx_cb)
|
||||
{
|
||||
_ble_service_nus_data_rx_cb = nus_data_rx_cb;
|
||||
}
|
||||
/**
|
||||
* PRIVATE FUNCTION DEFINITION
|
||||
* Used for the internal workings of the service
|
||||
*/
|
||||
|
||||
static bool ble_service_send_raw_custom_notification(uint16_t characteristic_handle, const uint8_t *data, uint16_t length)
|
||||
{
|
||||
if(BLE_HS_CONN_HANDLE_NONE == ble_device_conn_handle)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, no active connection" NEW_LINE, __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!data || !length)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, no data" NEW_LINE, __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
int status = BLE_HS_ENOERR;
|
||||
struct os_mbuf *om_buf = ble_hs_mbuf_from_flat(data, length);
|
||||
|
||||
if(!om_buf)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_hs_mbuf_from_flat" NEW_LINE, __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if((status = ble_gattc_notify_custom(ble_device_conn_handle, characteristic_handle, om_buf)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_hs_mbuf_from_flat %s" NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ble_service_send_custom_notification(uint16_t characteristic_handle, data_being_sent_t * const notif_data)
|
||||
{
|
||||
if(!notif_data)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("%s, notif_data is NULL"NEW_LINE, __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We compute the maximum size of the data we can send:
|
||||
uint16_t remaining_data_to_send = notif_data->length - notif_data->offset;
|
||||
notif_data->sent_chunk_size = remaining_data_to_send <= usable_mtu ? remaining_data_to_send : usable_mtu;
|
||||
|
||||
if(!ble_service_send_raw_custom_notification(characteristic_handle, ¬if_data->data[notif_data->offset], notif_data->sent_chunk_size))
|
||||
{
|
||||
//Transfer failed :
|
||||
reset_data_being_sent(notif_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int ble_gatt_mtu_cb(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t mtu, void *arg)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_DEBUG("ble_gatt_mtu_cb"NEW_LINE);
|
||||
|
||||
switch(error->status)
|
||||
{
|
||||
case 0:
|
||||
TLS_BT_APPL_TRACE_DEBUG("mtu exchange complete: conn_handle=%d mtu=%d"NEW_LINE,
|
||||
conn_handle, mtu);
|
||||
usable_mtu = mtu - 3;
|
||||
break;
|
||||
default:
|
||||
TLS_BT_APPL_TRACE_ERROR("Update MTU failed...error->status=%d"NEW_LINE, error->status);
|
||||
break;
|
||||
}
|
||||
|
||||
return BLE_HS_ENOERR;
|
||||
}
|
||||
|
||||
static bool ble_service_define_gatt(const struct ble_gatt_svc_def *gatt_svc)
|
||||
{
|
||||
int status = BLE_HS_ENOERR;
|
||||
|
||||
if((status = ble_gatts_count_cfg(gatt_svc)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_gatts_count_cfg failed : %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
if((status = ble_gatts_add_svcs(gatt_svc)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_gatts_add_svcs failed : %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
return status == BLE_HS_ENOERR ? true : false;
|
||||
}
|
||||
|
||||
static bool ble_service_advertise(bool enable)
|
||||
{
|
||||
int status = BLE_HS_ENOERR;
|
||||
|
||||
if(enable)
|
||||
{
|
||||
struct ble_hs_adv_fields advertisement_fields = {0};
|
||||
uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM;
|
||||
|
||||
advertisement_fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
|
||||
advertisement_fields.appearance = ble_svc_gap_device_appearance();
|
||||
advertisement_fields.appearance_is_present = 1;
|
||||
|
||||
// Set the name of a watch supported by GB
|
||||
#ifdef GADGETBRIDGE_SUPPORT
|
||||
static const char dev_name[12] = "Bangle.js 2";
|
||||
advertisement_fields.name = (uint8_t *)dev_name;//ble_svc_gap_device_name();
|
||||
advertisement_fields.name_len = 11;//strlen(ble_svc_gap_device_name());
|
||||
#else
|
||||
advertisement_fields.name = (uint8_t *)ble_svc_gap_device_name();
|
||||
advertisement_fields.name_len = strlen(ble_svc_gap_device_name());
|
||||
#endif
|
||||
|
||||
advertisement_fields.name_is_complete = 1;
|
||||
|
||||
advertisement_fields.uuids16 = (ble_uuid16_t[])
|
||||
{
|
||||
BLE_UUID16_INIT(BLE_DEVICE_ADV_SERVICE)
|
||||
};
|
||||
advertisement_fields.num_uuids16 = 1;
|
||||
advertisement_fields.uuids16_is_complete = 1;
|
||||
|
||||
// Lets apply the advertisement data
|
||||
if((status = ble_gap_adv_set_fields(&advertisement_fields)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_gap_adv_set_fields failed : %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
// We the device address
|
||||
uint8_t device_addr[6] = {0};
|
||||
extern int tls_get_bt_mac_addr(u8 *mac);
|
||||
tls_get_bt_mac_addr(device_addr);
|
||||
|
||||
// Make sure the the device address is compliant with the random address specification :
|
||||
device_addr[5] |= 0xC0;
|
||||
|
||||
if((status = ble_hs_id_set_rnd(device_addr)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_hs_id_set_rnd failed : %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
TLS_BT_APPL_TRACE_VERBOSE("addr type : %s"NEW_LINE"device addr : %02X:%02X:%02X:%02X:%02X:%02X"NEW_LINE,
|
||||
tls_bt_addr_type_2_str(own_addr_type),
|
||||
device_addr[5],
|
||||
device_addr[4],
|
||||
device_addr[3],
|
||||
device_addr[2],
|
||||
device_addr[1],
|
||||
device_addr[0]);
|
||||
}
|
||||
|
||||
// We are now ready to configure the advertisement parameters
|
||||
struct ble_gap_adv_params advertisement_params = {0};
|
||||
|
||||
advertisement_params.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||
advertisement_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
|
||||
advertisement_params.itvl_min = 160;
|
||||
advertisement_params.itvl_max = 160; //160 / 0.625 = 100 ms
|
||||
advertisement_params.filter_policy = 0;
|
||||
advertisement_params.channel_map = 0; // Use sane default
|
||||
advertisement_params.high_duty_cycle = 0;
|
||||
|
||||
if((status = ble_gap_adv_start(BLE_OWN_ADDR_RANDOM, NULL, BLE_HS_FOREVER, &advertisement_params, &(ble_advertise_gap_event_cb), NULL)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_gap_adv_start failed : %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if((status = ble_gap_adv_stop()) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_gap_adv_stop failed : %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// This is the brain of the ble service, here we handle all the possible GAP events
|
||||
static int ble_gap_event_cb(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
int status = BLE_HS_ENOERR;
|
||||
struct ble_gap_conn_desc desc;
|
||||
bool error = false;
|
||||
|
||||
TLS_BT_APPL_TRACE_EVENT("ble_gap_event_cb : %s"NEW_LINE, tls_bt_gap_evt_2_str(event->type));
|
||||
|
||||
switch(event->type)
|
||||
{
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
if(event->connect.status == BLE_HS_ENOERR)
|
||||
{
|
||||
if((status = ble_gap_conn_find(event->connect.conn_handle, &desc)) == BLE_HS_ENOERR)
|
||||
{
|
||||
print_conn_desc(&desc);
|
||||
if(desc.role == BLE_GAP_ROLE_SLAVE)
|
||||
{
|
||||
_ble_service_state = BLE_SERVICE_MODE_CONNECTED;
|
||||
usable_mtu = USABLE_DEFAULT_MTU;
|
||||
ble_device_conn_handle = event->connect.conn_handle;
|
||||
|
||||
//We call the state change callback if registered
|
||||
if(_ble_service_state_change_cb)_ble_service_state_change_cb(_ble_service_state);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = true;
|
||||
if((status = ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("%s, ble_gap_terminate %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
|
||||
//Resume advertising :
|
||||
if(error)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_VERBOSE("Remote device failed to connect, advertise again"NEW_LINE);
|
||||
if(!ble_service_advertise(true))
|
||||
{
|
||||
_ble_service_state = BLE_SERVICE_MODE_IDLE;
|
||||
return BLE_HS_EUNKNOWN;
|
||||
}
|
||||
_ble_service_state = BLE_SERVICE_MODE_ADVERTISING;
|
||||
}
|
||||
break;
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
if(event->disconnect.conn.role != BLE_GAP_ROLE_SLAVE) return 0;
|
||||
|
||||
TLS_BT_APPL_TRACE_DEBUG("Server disconnect reason=%d[0x%02x],state=%s"NEW_LINE, event->disconnect.reason,event->disconnect.reason-0x200,
|
||||
ble_service_state_2_str(_ble_service_state));
|
||||
|
||||
// Don't forget to invalidate the connection handle :
|
||||
ble_device_conn_handle = BLE_HS_CONN_HANDLE_NONE;
|
||||
|
||||
if(_ble_service_state == BLE_SERVICE_MODE_EXITING)
|
||||
{
|
||||
_ble_service_state = BLE_SERVICE_MODE_STOPPED;
|
||||
|
||||
if((status = ble_gap_event_listener_unregister(&ble_gap_event_listener)) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("%s, ble_gap_event_listener_unregister %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
}
|
||||
|
||||
// We finally clean the gatt registered services
|
||||
if((status = ble_gatts_reset()) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, ble_gatts_reset %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let's advertise again
|
||||
TLS_BT_APPL_TRACE_VERBOSE("Service disconnect event, advertise again"NEW_LINE);
|
||||
if(!ble_service_advertise(true))
|
||||
{
|
||||
_ble_service_state = BLE_SERVICE_MODE_IDLE;
|
||||
return BLE_HS_EUNKNOWN;
|
||||
}
|
||||
_ble_service_state = BLE_SERVICE_MODE_ADVERTISING;
|
||||
}
|
||||
|
||||
//We call the state change callback if registered
|
||||
if(_ble_service_state_change_cb)_ble_service_state_change_cb(_ble_service_state);
|
||||
break;
|
||||
case BLE_GAP_EVENT_CONN_UPDATE:
|
||||
TLS_BT_APPL_TRACE_DEBUG("Conn update status : %d"NEW_LINE, event->conn_update.status);
|
||||
if((status = ble_gap_conn_find(event->connect.conn_handle, &desc)) == BLE_HS_ENOERR)
|
||||
{
|
||||
print_conn_desc(&desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("%s, ble_gap_conn_find %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
}
|
||||
break;
|
||||
case BLE_GAP_EVENT_SUBSCRIBE:
|
||||
TLS_BT_APPL_TRACE_VERBOSE("Attr handle : %u"NEW_LINE
|
||||
"cur_indicate : %u"NEW_LINE
|
||||
"prev_indicate : %u"NEW_LINE
|
||||
"cur_notify : %u"NEW_LINE
|
||||
"prev_notify : %u"NEW_LINE,
|
||||
event->subscribe.attr_handle,
|
||||
event->subscribe.cur_indicate,
|
||||
event->subscribe.prev_indicate,
|
||||
event->subscribe.cur_notify,
|
||||
event->subscribe.prev_notify
|
||||
);
|
||||
break;
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
TLS_BT_APPL_TRACE_VERBOSE("MTU update : %u"NEW_LINE, event->mtu.value);
|
||||
usable_mtu = event->mtu.value - 3;
|
||||
break;
|
||||
case BLE_GAP_EVENT_NOTIFY_TX:
|
||||
if(event->notify_tx.indication == 0) // Notification
|
||||
{
|
||||
TLS_BT_APPL_TRACE_VERBOSE("Type : notification"NEW_LINE);
|
||||
if(event->notify_tx.status != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("%s, notify_tx notification error %d, transfer in progress : %u"NEW_LINE, __FUNCTION__, event->notify_tx.status, notification_data.transfer_in_progress);
|
||||
reset_data_being_sent(¬ification_data);
|
||||
return BLE_HS_EUNKNOWN;
|
||||
}
|
||||
|
||||
TLS_BT_APPL_TRACE_DEBUG("transfer : %u"NEW_LINE"length : %u"NEW_LINE"offset : %u"NEW_LINE,
|
||||
notification_data.transfer_in_progress,
|
||||
notification_data.length,
|
||||
notification_data.offset);
|
||||
|
||||
// We update the offset :
|
||||
notification_data.offset += notification_data.sent_chunk_size;
|
||||
|
||||
if(notification_data.offset < notification_data.length) // Still data to send ?
|
||||
{
|
||||
if(!ble_service_send_custom_notification(event->notify_tx.attr_handle, ¬ification_data))
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("Failed to send next notification chunk, aborting"NEW_LINE);
|
||||
reset_data_being_sent(¬ification_data);
|
||||
return BLE_HS_EUNKNOWN;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TLS_BT_APPL_TRACE_VERBOSE("last data chunk sent, end of the transfer"NEW_LINE);
|
||||
// All data has been sent, end of the transfer
|
||||
reset_data_being_sent(¬ification_data);
|
||||
}
|
||||
}
|
||||
else // Indication
|
||||
{
|
||||
TLS_BT_APPL_TRACE_WARNING("Indication not yet handled"NEW_LINE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TLS_BT_APPL_TRACE_WARNING("unhandled event !"NEW_LINE);
|
||||
}
|
||||
|
||||
return BLE_HS_ENOERR;
|
||||
}
|
||||
|
||||
static int ble_advertise_gap_event_cb(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
return BLE_HS_ENOERR;
|
||||
}
|
||||
|
||||
static int battery_level_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
int status = BLE_HS_ENOERR;
|
||||
TLS_BT_APPL_TRACE_EVENT("battery_level_char_access_cb op : %s"NEW_LINE, tls_bt_access_opt_2_str(ctxt->op));
|
||||
switch(ctxt->op)
|
||||
{
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR:
|
||||
if(attr_handle == battery_level_char_handle)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_VERBOSE("battery level reading"NEW_LINE);
|
||||
if((status = os_mbuf_append(ctxt->om, &battery_level_value, sizeof(battery_level_value))) != BLE_HS_ENOERR)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_ERROR("%s, battery level os_mbuf : %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TLS_BT_APPL_TRACE_WARNING("unhandled operation !"NEW_LINE);
|
||||
}
|
||||
|
||||
return BLE_HS_ENOERR;
|
||||
}
|
||||
|
||||
static int gatt_nus_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_EVENT("gatt_nus_char_access_cb op : %s"NEW_LINE, tls_bt_access_opt_2_str(ctxt->op));
|
||||
|
||||
switch(ctxt->op)
|
||||
{
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
{
|
||||
struct os_mbuf *om_buf = ctxt->om;
|
||||
while(om_buf)
|
||||
{
|
||||
// Call the nus rx cb function if one is registered
|
||||
if(_ble_service_nus_data_rx_cb)
|
||||
_ble_service_nus_data_rx_cb(om_buf->om_data, om_buf->om_len);
|
||||
|
||||
om_buf = SLIST_NEXT(om_buf, om_next);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TLS_BT_APPL_TRACE_WARNING("unhandled operation !"NEW_LINE);
|
||||
}
|
||||
|
||||
return BLE_HS_ENOERR;
|
||||
}
|
||||
|
||||
static void print_conn_desc(const struct ble_gap_conn_desc *desc)
|
||||
{
|
||||
TLS_BT_APPL_TRACE_VERBOSE("conn_handle : %u"NEW_LINE"conn_itvl : %u"NEW_LINE"conn_latency : %u"NEW_LINE"master_clock_accuracy : %u"NEW_LINE"role : %s"NEW_LINE"supervision_timeout : %u"NEW_LINE
|
||||
"encrypted : %u"NEW_LINE"authenticated : %u"NEW_LINE"bonded : %u"NEW_LINE,
|
||||
desc->conn_handle,
|
||||
desc->conn_itvl,
|
||||
desc->conn_latency,
|
||||
desc->master_clock_accuracy,
|
||||
desc->role == BLE_GAP_ROLE_MASTER ? "MASTER" : "SLAVE",
|
||||
desc->supervision_timeout,
|
||||
desc->sec_state.encrypted,
|
||||
desc->sec_state.authenticated,
|
||||
desc->sec_state.bonded);
|
||||
}
|
||||
|
||||
static void reset_data_being_sent(data_being_sent_t * const data)
|
||||
{
|
||||
if(data)
|
||||
{
|
||||
memset(data, 0, sizeof(data_being_sent_t));
|
||||
}
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
#ifndef BLE_SERVICE_H
|
||||
#define BLE_SERVICE_H
|
||||
|
||||
#include "wm_type_def.h"
|
||||
|
||||
#ifndef CASE_RETURN_STR
|
||||
#define CASE_RETURN_STR(const) case const: return #const;
|
||||
#endif
|
||||
|
||||
typedef void (*nus_data_rx_fn_t)(const uint8_t *data, uint16_t length);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BLE_SERVICE_MODE_STOPPED = 0x00,
|
||||
BLE_SERVICE_MODE_IDLE,
|
||||
BLE_SERVICE_MODE_ADVERTISING,
|
||||
BLE_SERVICE_MODE_CONNECTED,
|
||||
BLE_SERVICE_MODE_INDICATING,
|
||||
BLE_SERVICE_MODE_EXITING
|
||||
} ble_service_state_e;
|
||||
|
||||
typedef void (*ble_service_state_change_fn_t)(ble_service_state_e service_state);
|
||||
|
||||
/**
|
||||
* @brief Resturns the corresponding enum name as a string
|
||||
*
|
||||
* @param state the enum value
|
||||
* @return const char* the enum name as a string
|
||||
*/
|
||||
const char *ble_service_state_2_str(ble_service_state_e state);
|
||||
|
||||
/**
|
||||
* @brief Configures and starts the BLE service
|
||||
*
|
||||
* @return true on success
|
||||
* @return false on failure
|
||||
*/
|
||||
bool ble_service_start(void);
|
||||
|
||||
/**
|
||||
* @brief Deinits and stops the BLE service
|
||||
*
|
||||
* @return true on success
|
||||
* @return false on failure
|
||||
*/
|
||||
bool ble_service_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Check whether the ble service is running or not
|
||||
*
|
||||
* @return true if it is running
|
||||
* @return false if it is stopped
|
||||
*/
|
||||
bool ble_service_is_started(void);
|
||||
|
||||
/**
|
||||
* @brief Check whether a device is connected to the ble service or not
|
||||
*
|
||||
* @return true if a device is connected
|
||||
* @return false if no device is connected
|
||||
*/
|
||||
bool ble_service_is_device_connected(void);
|
||||
|
||||
/**
|
||||
* @brief Registers a callback function called every time the state of the BLE service changes.
|
||||
* For example, you can register a callback to know if a device connected to the service, or disconnected
|
||||
*
|
||||
* @param ble_service_state_change_cb the function to register as the callback. The ble_service_state parameter is set to the new state.
|
||||
*/
|
||||
void ble_service_register_state_change_cb(ble_service_state_change_fn_t ble_service_state_change_cb);
|
||||
|
||||
/**
|
||||
* @brief Returns the current state of the ble service
|
||||
*
|
||||
* @return ble_service_state_e
|
||||
*/
|
||||
ble_service_state_e ble_service_get_state(void);
|
||||
|
||||
/**
|
||||
* @brief Asks to update the current connection parameters
|
||||
* /!\ A connection should be already active before calling this function.
|
||||
*
|
||||
* @param itvl_min Minimum value for connection interval in 1.25ms units
|
||||
* @param itvl_max Maximum value for connection interval in 1.25ms units
|
||||
* @param latency Connection latency
|
||||
* @param supervision_timeout Supervision timeout in 10ms units
|
||||
* @param min_ce_len Minimum length of connection event in 0.625ms units
|
||||
* @param max_ce_len Maximum length of connection event in 0.625ms units
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool ble_service_update_connection_parameters(
|
||||
uint16_t itvl_min,
|
||||
uint16_t itvl_max,
|
||||
uint16_t latency,
|
||||
uint16_t supervision_timeout,
|
||||
uint16_t min_ce_len,
|
||||
uint16_t max_ce_len);
|
||||
|
||||
/**
|
||||
* @brief Requests a MTU (Maximum Transmission Unit) update in order to hopefully, get something bigger than 20 bytes ...
|
||||
*
|
||||
* @return true on success
|
||||
* @return false on failure
|
||||
*/
|
||||
bool ble_service_request_mtu_exchange(void);
|
||||
|
||||
/**
|
||||
* @brief Sends the provided payload of size length using the NUS (Nordic UART Service) TX characteristic
|
||||
*
|
||||
* @param data the data to send through the NUS
|
||||
* @param length the lenght in byte of the data to send
|
||||
* @return true on success
|
||||
* @return false on failure
|
||||
*/
|
||||
bool ble_service_send_nus_data(const uint8_t *data, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Registers a function which will be called every time data is received by the nus rx
|
||||
* @note To unregister a callback, simply pass NULL to the function
|
||||
*
|
||||
* @param nus_data_rx_cb a pointer to the function to call of type nus_data_rx_fn_t
|
||||
*/
|
||||
void ble_service_register_nus_data_rx_cb(nus_data_rx_fn_t nus_data_rx_cb);
|
||||
|
||||
#endif //BLE_APP_H
|
@ -1,9 +0,0 @@
|
||||
#ifndef BLUETOOTH_SIG_VALUES_H
|
||||
#define BLUETOOTH_SIG_VALUES_H
|
||||
|
||||
#define BLE_DEVICE_APPEARANCE (0x00C2) //Smart Watch
|
||||
#define BLE_DEVICE_NAME "MDBT42Q_W800SW"
|
||||
|
||||
#define BLE_DEVICE_ADV_SERVICE (0x180F) //Battery Service
|
||||
|
||||
#endif //BLUETOOTH_SIG_VALUES_H
|
File diff suppressed because one or more lines are too long
@ -17,9 +17,6 @@
|
||||
#include "watch_peripherals.h"
|
||||
#include "watch_settings.h"
|
||||
|
||||
#include "ble_modem.h"
|
||||
#include "ble_service.h"
|
||||
|
||||
static void date_time_cb(struct tm * const dateTime)
|
||||
{
|
||||
if(!dateTime)return;
|
||||
@ -27,7 +24,11 @@ static void date_time_cb(struct tm * const dateTime)
|
||||
//APP_LOG_DEBUG("RTC time : %d:%d:%d", dateTime->tm_hour, dateTime->tm_min, dateTime->tm_sec);
|
||||
}
|
||||
|
||||
static uint8_t _battery_percentage = 100;
|
||||
static uint8_t battery_percentage = 100;
|
||||
static uint8_t battery_indicator_cb(void)
|
||||
{
|
||||
return battery_percentage;
|
||||
}
|
||||
|
||||
WatchFace_t watchFace;
|
||||
MenuScreen_t menuScreen;
|
||||
@ -38,25 +39,7 @@ struct bma4_dev bma;
|
||||
struct bma4_accel_config accel_conf;
|
||||
struct bma456w_wrist_wear_wakeup_params setting;
|
||||
struct bma4_int_pin_config pin_config;
|
||||
|
||||
struct
|
||||
{
|
||||
uint16_t int_status;
|
||||
bool battery_controller_status;
|
||||
} _interrupts_statuses = {.int_status = 0, .battery_controller_status = false};
|
||||
|
||||
|
||||
/* This call back is automatically called by the watch face when it wants to refresh the battery */
|
||||
static void battery_indicator_cb(uint8_t *levelInPercent, BatteryState_e *batteryState)
|
||||
{
|
||||
*levelInPercent = _battery_percentage;
|
||||
*batteryState = watch_peripherals_get_battery_controller_status();
|
||||
}
|
||||
|
||||
static void battery_controller_status_on_change_cb(battery_controller_status_e old, battery_controller_status_e new)
|
||||
{
|
||||
_interrupts_statuses.battery_controller_status = true;
|
||||
}
|
||||
uint16_t int_status;
|
||||
|
||||
static void setGetBrightnessCb(uint8_t *brightness, SettingMode_e mode)
|
||||
{
|
||||
@ -66,10 +49,7 @@ static void setGetBrightnessCb(uint8_t *brightness, SettingMode_e mode)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Updates the settings in the watch settings structure
|
||||
watch_settings_display_set_brightness(*brightness);
|
||||
|
||||
// Physically apply the setting to the hardware
|
||||
persistency_get_settings()->display.display_brightness = *brightness;
|
||||
watch_peripherals_set_brightness(*brightness);
|
||||
}
|
||||
}
|
||||
@ -122,7 +102,7 @@ static void setDisplayVibrationDuration(uint8_t *duration, SettingMode_e mode)
|
||||
}
|
||||
else
|
||||
{
|
||||
watch_settings_display_set_vibrate_on_touch_duration(*duration);
|
||||
persistency_get_settings()->display.display_vibrate_on_touch_duration = *duration;
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,7 +114,7 @@ static void setDisplayVibrationStrength(uint8_t *strength, SettingMode_e mode)
|
||||
}
|
||||
else
|
||||
{
|
||||
watch_settings_display_set_vibrate_on_touch_strength(*strength);
|
||||
persistency_get_settings()->display.display_vibrate_on_touch_strength = *strength;
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,7 +126,7 @@ static void setTimeoutCb(uint8_t *timeout, SettingMode_e mode)
|
||||
}
|
||||
else
|
||||
{
|
||||
watch_settings_display_set_delay_before_sleep(*timeout);
|
||||
persistency_get_settings()->display.display_delay_before_sleep = *timeout;
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,7 +138,7 @@ static void setOrientationCb(uint8_t *orientation, SettingMode_e mode)
|
||||
}
|
||||
else
|
||||
{
|
||||
watch_settings_display_set_orientation(*orientation);
|
||||
persistency_get_settings()->display.display_orientation = *orientation;
|
||||
watch_peripherals_set_orientation(*orientation);
|
||||
// Forces to redraw the full screen to avoid strange artifacts
|
||||
lv_obj_invalidate(lv_scr_act());
|
||||
@ -173,26 +153,10 @@ static void setBLEEnabledCb(bool *enabled, SettingMode_e mode)
|
||||
}
|
||||
else
|
||||
{
|
||||
watch_settings_connectivity_set_ble_enabled(*enabled);
|
||||
//Let's turn the BLE on or OFF here
|
||||
if(*enabled)
|
||||
{
|
||||
if(!ble_modem_on(true))
|
||||
APP_LOG_ERROR("Failed to start BLE modem with service");
|
||||
else
|
||||
watch_face_set_bluetooth_indicator(&watchFace, BLUETOOTH_STATE_ON);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!ble_modem_off())
|
||||
APP_LOG_ERROR("Failed to stop BLE modem with service");
|
||||
else
|
||||
watch_face_set_bluetooth_indicator(&watchFace, BLUETOOTH_STATE_OFF);
|
||||
}
|
||||
persistency_get_settings()->connectivity.connectivity_ble_enabled = *enabled;
|
||||
}
|
||||
}
|
||||
|
||||
/* This may never get implemented due to power consumption */
|
||||
static void setWiFiEnabledCb(bool *enabled, SettingMode_e mode)
|
||||
{
|
||||
if(SETTING_MODE_GET == mode)
|
||||
@ -201,7 +165,7 @@ static void setWiFiEnabledCb(bool *enabled, SettingMode_e mode)
|
||||
}
|
||||
else
|
||||
{
|
||||
watch_settings_connectivity_set_wifi_enabled(*enabled);
|
||||
persistency_get_settings()->connectivity.connectivity_wifi_enabled = *enabled;
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,46 +177,21 @@ static void setLanguageCb(uint8_t *language, SettingMode_e mode)
|
||||
}
|
||||
else
|
||||
{
|
||||
watch_settings_language_and_UI_set_language(*language);
|
||||
persistency_get_settings()->languageAndUI.language = *language;
|
||||
}
|
||||
}
|
||||
|
||||
static void saveSettingsToFlash(void)
|
||||
{
|
||||
/*if(!persistency_save_settings_to_flash())
|
||||
{
|
||||
APP_LOG_ERROR("Failed to save watch settings to flash");
|
||||
}*/
|
||||
}
|
||||
|
||||
static void performFactoryReset()
|
||||
{
|
||||
// Reload factory settings
|
||||
persistency_factory_reset();
|
||||
|
||||
if(!persistency_save_settings_to_flash())
|
||||
{
|
||||
APP_LOG_ERROR("Failed to save factory reset settings to flash");
|
||||
return;
|
||||
}
|
||||
|
||||
// We do a hardware reset of the watch
|
||||
tls_sys_reset();
|
||||
}
|
||||
|
||||
SettingsScreenAPIInterface_t settingsScreenAPIInterface =
|
||||
{
|
||||
.setTimeSettingsCb = &(setTimeCb),
|
||||
.setBrightnessSettingsCb = &(setGetBrightnessCb),
|
||||
.setTimeoutSettingsCb = &(setTimeoutCb),
|
||||
.setDisplayVibrationDurationSettingsCb = &(setDisplayVibrationDuration),
|
||||
.setDisplayVibrationStrengthSettingsCb = &(setDisplayVibrationStrength),
|
||||
.setOrientationSettingsCb = &(setOrientationCb),
|
||||
.setBLEEnabledSettingsCb = &(setBLEEnabledCb),
|
||||
.setWiFiEnabledSettingsCb = &(setWiFiEnabledCb),
|
||||
.setLanguageSettingsCb = &(setLanguageCb),
|
||||
.saveSettingsCb = &(saveSettingsToFlash),
|
||||
.factoryResetCb = &(performFactoryReset),
|
||||
.setTimeSettingsCb = setTimeCb,
|
||||
.setBrightnessSettingsCb = setGetBrightnessCb,
|
||||
.setTimeoutSettingsCb = setTimeoutCb,
|
||||
.setDisplayVibrationDurationSettingsCb = setDisplayVibrationDuration,
|
||||
.setDisplayVibrationStrengthSettingsCb = setDisplayVibrationStrength,
|
||||
.setOrientationSettingsCb = setOrientationCb,
|
||||
.setBLEEnabledSettingsCb = setBLEEnabledCb,
|
||||
.setWiFiEnabledSettingsCb = setWiFiEnabledCb,
|
||||
.setLanguageSettingsCb = setLanguageCb,
|
||||
};
|
||||
|
||||
static uint16_t angle_with_offset(uint16_t angle, uint16_t offset)
|
||||
@ -284,21 +223,6 @@ static void delay_us(uint32_t period, void *intf_ptr)
|
||||
tls_os_time_delay(pdMS_TO_TICKS(period / 1000));
|
||||
}
|
||||
|
||||
static void ble_service_state_change_cb(ble_service_state_e ble_service_state)
|
||||
{
|
||||
switch(ble_service_state)
|
||||
{
|
||||
case BLE_SERVICE_MODE_CONNECTED:
|
||||
watch_face_set_bluetooth_indicator(&watchFace, BLUETOOTH_STATE_CONNECTED);
|
||||
break;
|
||||
case BLE_SERVICE_MODE_ADVERTISING:
|
||||
watch_face_set_bluetooth_indicator(&watchFace, BLUETOOTH_STATE_ON);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void scan_result_cb(void)
|
||||
{
|
||||
size_t buffer_size = sizeof(struct tls_scan_bss_format2_t) + sizeof(struct tls_bss_info_format2_t) * 10;
|
||||
@ -338,26 +262,11 @@ static void scan_result_cb(void)
|
||||
|
||||
void gfx_task(void *param)
|
||||
{
|
||||
APP_LOG_TRACE("GFX task starting");
|
||||
APP_LOG_TRACE("starting");
|
||||
|
||||
/* Init and load watch settings using the persistency layer */
|
||||
persistency_init();
|
||||
|
||||
if(!persistency_load_settings_from_flash())
|
||||
{
|
||||
APP_LOG_ERROR("Failed to retrieve watch settings from flash");
|
||||
}
|
||||
|
||||
//persistency_debug();
|
||||
|
||||
/* Let's init the watch peripherals driver (vibration motor + battery voltage sense) */
|
||||
watch_peripherals_init(27);
|
||||
watch_peripherals_register_battery_controller_status_change_cb(&(battery_controller_status_on_change_cb));
|
||||
|
||||
/* Make the first battery voltage reading here */
|
||||
uint16_t battery_voltage = watch_peripherals_get_battery_voltage(battery_unit_mv);
|
||||
_battery_percentage = battery_voltage_to_percentage(battery_voltage);
|
||||
|
||||
/* Check whether the RTC is running or not, if not, then the board was reset
|
||||
So we start the RTC */
|
||||
if(!tls_is_rtc_running())
|
||||
@ -390,7 +299,7 @@ void gfx_task(void *param)
|
||||
lv_scr_load(watchFace.display);
|
||||
|
||||
/* Let's init the I2C interface */
|
||||
i2c_init(I2C_SDA, I2C_SCL, I2C_CLOCK_SPEED);
|
||||
i2c_init(I2C_SDA, I2C_SCL, 100000);
|
||||
|
||||
uint8_t aliveCounter = 0;
|
||||
|
||||
@ -465,7 +374,7 @@ void gfx_task(void *param)
|
||||
else
|
||||
APP_LOG_INFO("BMA456 accel en failed");
|
||||
|
||||
bma456w_feature_enable(BMA456W_WRIST_WEAR_WAKEUP, BMA4_ENABLE, &bma);
|
||||
bma456w_feature_enable(BMA456W_WRIST_WEAR_WAKEUP, 1, &bma);
|
||||
|
||||
bma456w_get_wrist_wear_wakeup_param_config(&setting, &bma);
|
||||
|
||||
@ -492,21 +401,19 @@ void gfx_task(void *param)
|
||||
else
|
||||
APP_LOG_INFO("BMA456 set pin conf failed");
|
||||
|
||||
/* Configure BMA's step counter */
|
||||
if(bma456w_feature_enable(BMA456W_STEP_CNTR, BMA4_ENABLE, &bma) == BMA4_OK)
|
||||
APP_LOG_INFO("BMA456 step cnter feature enable ok");
|
||||
else
|
||||
APP_LOG_INFO("BMA456 step cnter feature enable failed");
|
||||
|
||||
/* Configure and register BLE stack and services callbacks */
|
||||
ble_service_register_state_change_cb(&(ble_service_state_change_cb));
|
||||
/* Let's init the watch peripherals driver (vibration motor + battery voltage sense) */
|
||||
watch_peripherals_init(27);
|
||||
/* Make the first battery voltage reading here */
|
||||
uint16_t battery_voltage = watch_peripherals_get_battery_voltage(battery_unit_mv);
|
||||
battery_percentage = battery_voltage_to_percentage(battery_voltage);
|
||||
watch_face_set_battery_indicator(&watchFace, battery_percentage);
|
||||
|
||||
/* Once we are done with the initializing steps we
|
||||
don't forget to turn the backlight on ! */
|
||||
watch_peripherals_set_brightness(persistency_get_settings()->display.display_brightness);
|
||||
|
||||
/* Enable WiFi hotspot scanning for antenna performance test purposes */
|
||||
//tls_wifi_scan_result_cb_register(&(scan_result_cb));
|
||||
tls_wifi_scan_result_cb_register(&(scan_result_cb));
|
||||
|
||||
extern LCDConfig_t LCDConfig;
|
||||
float temperature = 0;
|
||||
@ -534,33 +441,27 @@ void gfx_task(void *param)
|
||||
}
|
||||
|
||||
|
||||
uint8_t rslt = bma456w_read_int_status(&_interrupts_statuses.int_status, &bma);
|
||||
uint8_t rslt = bma456w_read_int_status(&int_status, &bma);
|
||||
if(rslt != BMA4_OK)
|
||||
APP_LOG_DEBUG("Failed to read int status");
|
||||
|
||||
if((BMA4_OK == rslt) && (_interrupts_statuses.int_status & BMA456W_WRIST_WEAR_WAKEUP_INT))
|
||||
if((BMA4_OK == rslt) && (int_status & BMA456W_WRIST_WEAR_WAKEUP_INT))
|
||||
{
|
||||
APP_LOG_DEBUG("Wrist tilt");
|
||||
}
|
||||
|
||||
if(++aliveCounter % 200 == 0)
|
||||
{
|
||||
uint32_t steps = 0;
|
||||
if(bma456w_step_counter_output(&steps, &bma) != BMA4_OK)
|
||||
APP_LOG_DEBUG("Failed to read step counts");
|
||||
|
||||
watch_face_set_step_count(&watchFace, steps);
|
||||
|
||||
pressure = BMP280_get_pressure(&temperature);
|
||||
BMP280_trigger_measurement();
|
||||
battery_voltage = watch_peripherals_get_battery_voltage(battery_unit_mv);
|
||||
_battery_percentage = battery_voltage_to_percentage(battery_voltage);
|
||||
APP_LOG_DEBUG("GFX thread, temp : %0.2f °C, press : %0.2f hPa, battery(%s) : %u mV <-> %u %%",
|
||||
battery_percentage = battery_voltage_to_percentage(battery_voltage);
|
||||
APP_LOG_DEBUG("GFX thread, temp : %0.2f °C, press : %0.2f hPa, bat(%d) : %u mV <-> %u %%",
|
||||
temperature,
|
||||
pressure/100,
|
||||
battery_controller_status_2_str(watch_peripherals_get_battery_controller_status()),
|
||||
watch_peripherals_get_battery_controller_status(),
|
||||
battery_voltage,
|
||||
_battery_percentage);
|
||||
battery_percentage);
|
||||
|
||||
//APP_LOG_DEBUG("Scanning WiFi : %d", tls_wifi_scan());
|
||||
|
||||
@ -611,15 +512,5 @@ void gfx_task(void *param)
|
||||
APP_LOG_DEBUG("CPU 160Mhz");
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle any interrupts status */
|
||||
if(_interrupts_statuses.battery_controller_status)
|
||||
{
|
||||
_interrupts_statuses.battery_controller_status = false;
|
||||
//Let's refresh the battery percentage as well:
|
||||
battery_voltage = watch_peripherals_get_battery_voltage(battery_unit_mv);
|
||||
_battery_percentage = battery_voltage_to_percentage(battery_voltage);
|
||||
watch_face_set_battery_indicator(&watchFace, _battery_percentage, watch_peripherals_get_battery_controller_status());
|
||||
}
|
||||
}
|
||||
}
|
@ -4,27 +4,6 @@
|
||||
#include <stdio.h>
|
||||
#include "app_log.h"
|
||||
|
||||
LV_IMG_DECLARE(battery_low_icon)
|
||||
LV_IMG_DECLARE(battery_charging_icon)
|
||||
LV_IMG_DECLARE(battery_charged_icon)
|
||||
|
||||
static void _set_bluetooth_indicator(WatchFace_t * const watchFace)
|
||||
{
|
||||
switch(watchFace->bluetoothIndicator.bluetoothState)
|
||||
{
|
||||
case BLUETOOTH_STATE_ON:
|
||||
lv_obj_set_style_img_recolor_opa(watchFace->bluetoothIndicator.bluetoothIcon, 185, LV_PART_MAIN);
|
||||
lv_obj_clear_flag(watchFace->bluetoothIndicator.bluetoothIcon, LV_OBJ_FLAG_HIDDEN);
|
||||
break;
|
||||
case BLUETOOTH_STATE_CONNECTED:
|
||||
lv_obj_set_style_img_recolor_opa(watchFace->bluetoothIndicator.bluetoothIcon, 0, LV_PART_MAIN);
|
||||
lv_obj_clear_flag(watchFace->bluetoothIndicator.bluetoothIcon, LV_OBJ_FLAG_HIDDEN);
|
||||
break;
|
||||
default:
|
||||
lv_obj_add_flag(watchFace->bluetoothIndicator.bluetoothIcon, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
static void gesture_event_cb(lv_event_t * e)
|
||||
{
|
||||
WatchFace_t *watchFace = e->user_data;
|
||||
@ -38,7 +17,6 @@ static void gesture_event_cb(lv_event_t * e)
|
||||
case LV_DIR_RIGHT:
|
||||
LV_LOG_USER("GESTURE : RIGHT");
|
||||
// We delete the timer
|
||||
lv_timer_del(watchFace->batteryIndicator.lowBatteryAnimationTimer);
|
||||
lv_timer_del(watchFace->handAnimationTimer);
|
||||
// We create the menu screen and switch to it
|
||||
extern MenuScreen_t menuScreen;
|
||||
@ -82,17 +60,11 @@ static void update_watch_hands_angles(WatchFace_t * const watchFace, uint8_t inc
|
||||
|
||||
//Don't forget to update the day date window
|
||||
sprintf(watchFace->dateWindow.dateWindowText, "%s%d", watchFace->dateTime.tm_mday < 10 ? " " : "", watchFace->dateTime.tm_mday);
|
||||
lv_label_set_text_static(watchFace->dateWindow.dateWindowWidget, watchFace->dateWindow.dateWindowText);
|
||||
|
||||
lv_obj_invalidate(watchFace->dateWindow.dateWindowWidget);
|
||||
APP_LOG_DEBUG("Syncing time");
|
||||
|
||||
if(watchFace->batteryIndicatorCb)
|
||||
{
|
||||
uint8_t levelInPercent = 0;
|
||||
BatteryState_e batteryState = BATTERY_STATE_DISCHARGING;
|
||||
watchFace->batteryIndicatorCb(&levelInPercent, &batteryState);
|
||||
watch_face_set_battery_indicator(watchFace, levelInPercent, batteryState);
|
||||
}
|
||||
watch_face_set_battery_indicator(watchFace, watchFace->batteryIndicatorCb());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -121,57 +93,6 @@ static void hand_timer_anim_cb(lv_timer_t *timer)
|
||||
update_watch_hands_angles(watchFace, 12);
|
||||
}
|
||||
|
||||
static void battery_timer_anim_cb(lv_timer_t *timer)
|
||||
{
|
||||
WatchFace_t *watchFace = timer->user_data;
|
||||
|
||||
if(lv_obj_has_flag(watchFace->batteryIndicator.batteryIcon, LV_OBJ_FLAG_HIDDEN))
|
||||
{
|
||||
lv_obj_clear_flag(watchFace->batteryIndicator.batteryIcon, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_obj_add_flag(watchFace->batteryIndicator.batteryIcon, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_battery_state_icon(WatchFace_t * const watchFace)
|
||||
{
|
||||
switch(watchFace->batteryIndicator.batteryState)
|
||||
{
|
||||
case BATTERY_STATE_CHARGING:
|
||||
lv_timer_pause(watchFace->batteryIndicator.lowBatteryAnimationTimer);
|
||||
lv_obj_clear_flag(watchFace->batteryIndicator.batteryIcon, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_img_set_src(watchFace->batteryIndicator.batteryIcon, &battery_charging_icon);
|
||||
break;
|
||||
case BATTERY_STATE_CHARGED:
|
||||
lv_timer_pause(watchFace->batteryIndicator.lowBatteryAnimationTimer);
|
||||
lv_obj_clear_flag(watchFace->batteryIndicator.batteryIcon, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_img_set_src(watchFace->batteryIndicator.batteryIcon, &battery_charged_icon);
|
||||
break;
|
||||
default:
|
||||
lv_obj_add_flag(watchFace->batteryIndicator.batteryIcon, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_img_set_src(watchFace->batteryIndicator.batteryIcon, &battery_low_icon);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hide_hour_and_minutes_hand_cb(lv_event_t *e)
|
||||
{
|
||||
WatchFace_t *watchFace = e->user_data;
|
||||
|
||||
if(lv_obj_has_flag(watchFace->hourHand.handImg, LV_OBJ_FLAG_HIDDEN))
|
||||
{
|
||||
lv_obj_clear_flag(watchFace->hourHand.handImg, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(watchFace->minuteHand.handImg, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_obj_add_flag(watchFace->hourHand.handImg, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(watchFace->minuteHand.handImg, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
void watch_face_init(WatchFace_t * const watchFace)
|
||||
{
|
||||
if(!watchFace)
|
||||
@ -180,7 +101,6 @@ void watch_face_init(WatchFace_t * const watchFace)
|
||||
return;
|
||||
}
|
||||
memset(watchFace, 0, sizeof(WatchFace_t));
|
||||
strcpy(watchFace->stepCounter.text, "0");
|
||||
}
|
||||
|
||||
void watch_face_register_date_time_cb(WatchFace_t * const watchFace, DateTimeCb_t dateTimeCb)
|
||||
@ -219,8 +139,7 @@ void watch_face_create(WatchFace_t * const watchFace)
|
||||
LV_IMG_DECLARE(watch_casio_minute_hand_asset)
|
||||
LV_IMG_DECLARE(watch_casio_second_hand_asset)
|
||||
LV_IMG_DECLARE(watch_casio_medium_hand_asset)
|
||||
//LV_IMG_DECLARE(watch_casio_small_hand_asset)
|
||||
LV_IMG_DECLARE(bluetooth_icon)
|
||||
LV_IMG_DECLARE(watch_casio_small_hand_asset)
|
||||
|
||||
//We create our parent screen :
|
||||
if(watchFace->display)
|
||||
@ -233,31 +152,30 @@ void watch_face_create(WatchFace_t * const watchFace)
|
||||
watchFace->display = lv_img_create(NULL);
|
||||
lv_img_set_src(watchFace->display, &watch_casio_face_asset);
|
||||
lv_obj_set_style_bg_color(watchFace->display, lv_color_black(), LV_PART_MAIN);
|
||||
lv_obj_add_event_cb(watchFace->display, &(hide_hour_and_minutes_hand_cb), LV_EVENT_LONG_PRESSED, watchFace);
|
||||
|
||||
//We load our other assets :
|
||||
/*lv_obj_t *smallHandImg = lv_img_create(watchFace->display);
|
||||
lv_obj_t *smallHandImg = lv_img_create(watchFace->display);
|
||||
lv_img_set_src(smallHandImg, &watch_casio_small_hand_asset);
|
||||
lv_obj_set_pos(smallHandImg, 69, 98);
|
||||
lv_img_set_pivot(smallHandImg, 4, 20);*/
|
||||
lv_img_set_pivot(smallHandImg, 4, 20);
|
||||
|
||||
//Battery arc is created here
|
||||
if(watchFace->batteryIndicator.batteryArc)
|
||||
if(watchFace->batteryIndicator.battery_arc)
|
||||
{
|
||||
LV_LOG_ERROR("batteryArc should be NULL here !");
|
||||
lv_obj_del(watchFace->batteryIndicator.batteryArc);
|
||||
watchFace->batteryIndicator.batteryArc = NULL;
|
||||
LV_LOG_ERROR("battery_arc should be NULL here !");
|
||||
lv_obj_del(watchFace->batteryIndicator.battery_arc);
|
||||
watchFace->batteryIndicator.battery_arc = NULL;
|
||||
}
|
||||
|
||||
watchFace->batteryIndicator.batteryArc = lv_arc_create(watchFace->display);
|
||||
lv_obj_remove_style(watchFace->batteryIndicator.batteryArc, NULL, LV_PART_KNOB);
|
||||
lv_obj_clear_flag(watchFace->batteryIndicator.batteryArc, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_set_size(watchFace->batteryIndicator.batteryArc, 60, 60);
|
||||
lv_obj_align(watchFace->batteryIndicator.batteryArc, LV_ALIGN_CENTER, -1, 45);
|
||||
lv_obj_set_style_arc_width(watchFace->batteryIndicator.batteryArc, 5, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_arc_width(watchFace->batteryIndicator.batteryArc, 0, LV_PART_MAIN);
|
||||
lv_obj_set_style_arc_color(watchFace->batteryIndicator.batteryArc, lv_color_make(228, 233, 236), LV_PART_INDICATOR);
|
||||
lv_arc_set_value(watchFace->batteryIndicator.batteryArc, 100);
|
||||
watchFace->batteryIndicator.battery_arc = lv_arc_create(watchFace->display);
|
||||
lv_obj_remove_style(watchFace->batteryIndicator.battery_arc, NULL, LV_PART_KNOB);
|
||||
lv_obj_clear_flag(watchFace->batteryIndicator.battery_arc, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_set_size(watchFace->batteryIndicator.battery_arc, 60, 60);
|
||||
lv_obj_align(watchFace->batteryIndicator.battery_arc, LV_ALIGN_CENTER, -1, 45);
|
||||
lv_obj_set_style_arc_width(watchFace->batteryIndicator.battery_arc, 5, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_arc_width(watchFace->batteryIndicator.battery_arc, 0, LV_PART_MAIN);
|
||||
lv_obj_set_style_arc_color(watchFace->batteryIndicator.battery_arc, lv_color_make(228, 233, 236), LV_PART_INDICATOR);
|
||||
lv_arc_set_value(watchFace->batteryIndicator.battery_arc, 100);
|
||||
|
||||
if(watchFace->batteryIndicator.label)
|
||||
{
|
||||
@ -270,57 +188,9 @@ void watch_face_create(WatchFace_t * const watchFace)
|
||||
strcpy(watchFace->batteryIndicator.text, "100 %");
|
||||
lv_label_set_text_static(watchFace->batteryIndicator.label, watchFace->batteryIndicator.text);
|
||||
lv_obj_set_style_text_color(watchFace->batteryIndicator.label, lv_color_white(), LV_PART_MAIN);
|
||||
lv_obj_align_to(watchFace->batteryIndicator.label, watchFace->batteryIndicator.batteryArc, LV_ALIGN_CENTER, 0, -5);
|
||||
lv_obj_align_to(watchFace->batteryIndicator.label, watchFace->batteryIndicator.battery_arc, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
// Battery icon is created here
|
||||
if(watchFace->batteryIndicator.batteryIcon)
|
||||
{
|
||||
LV_LOG_ERROR("batteryIcon should be NULL here !");
|
||||
lv_obj_del(watchFace->batteryIndicator.batteryIcon);
|
||||
watchFace->batteryIndicator.batteryIcon = NULL;
|
||||
}
|
||||
|
||||
watchFace->batteryIndicator.batteryIcon = lv_img_create(watchFace->display);
|
||||
set_battery_state_icon(watchFace);
|
||||
lv_img_set_zoom(watchFace->batteryIndicator.batteryIcon, 141);
|
||||
lv_obj_align_to(watchFace->batteryIndicator.batteryIcon, watchFace->batteryIndicator.label, LV_ALIGN_OUT_BOTTOM_MID, 0, -9);
|
||||
|
||||
if(watchFace->batteryIndicator.lowBatteryAnimationTimer)
|
||||
{
|
||||
LV_LOG_ERROR("battery animation timer should be NULL here !");
|
||||
lv_timer_del(watchFace->batteryIndicator.lowBatteryAnimationTimer);
|
||||
watchFace->batteryIndicator.lowBatteryAnimationTimer = NULL;
|
||||
}
|
||||
watchFace->batteryIndicator.lowBatteryAnimationTimer = lv_timer_create(&(battery_timer_anim_cb), 500, watchFace);
|
||||
lv_timer_pause(watchFace->batteryIndicator.lowBatteryAnimationTimer);
|
||||
|
||||
// Bluetooth status icon is created here
|
||||
if(watchFace->bluetoothIndicator.bluetoothIcon)
|
||||
{
|
||||
LV_LOG_ERROR("bluetoothIcon be NULL here !");
|
||||
lv_obj_del(watchFace->bluetoothIndicator.bluetoothIcon);
|
||||
watchFace->bluetoothIndicator.bluetoothIcon = NULL;
|
||||
}
|
||||
watchFace->bluetoothIndicator.bluetoothIcon = lv_img_create(watchFace->display);
|
||||
lv_img_set_src(watchFace->bluetoothIndicator.bluetoothIcon, &bluetooth_icon);
|
||||
lv_img_set_zoom(watchFace->bluetoothIndicator.bluetoothIcon, 128);
|
||||
lv_obj_add_flag(watchFace->bluetoothIndicator.bluetoothIcon, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_set_style_img_recolor(watchFace->bluetoothIndicator.bluetoothIcon, lv_palette_main(LV_PALETTE_GREY), LV_PART_MAIN);
|
||||
lv_obj_align_to(watchFace->bluetoothIndicator.bluetoothIcon, watchFace->batteryIndicator.batteryArc, LV_ALIGN_OUT_LEFT_BOTTOM, -9, 0);
|
||||
_set_bluetooth_indicator(watchFace);
|
||||
|
||||
// StepCounter label is created here
|
||||
if(watchFace->stepCounter.label)
|
||||
{
|
||||
LV_LOG_ERROR("stepCounter should be NULL here !");
|
||||
lv_obj_del(watchFace->stepCounter.label);
|
||||
watchFace->stepCounter.label = NULL;
|
||||
}
|
||||
|
||||
watchFace->stepCounter.label = lv_label_create(watchFace->display);
|
||||
lv_label_set_text_static(watchFace->stepCounter.label, watchFace->stepCounter.text);
|
||||
lv_obj_set_style_text_color(watchFace->stepCounter.label, lv_color_white(), LV_PART_MAIN);
|
||||
lv_obj_set_pos(watchFace->stepCounter.label, 63, 111);
|
||||
|
||||
if(watchFace->mediumHand24h.handImg)
|
||||
{
|
||||
@ -408,7 +278,7 @@ void watch_face_create(WatchFace_t * const watchFace)
|
||||
watchFace->handAnimationTimer = lv_timer_create(&(hand_timer_anim_cb), 199, watchFace);
|
||||
}
|
||||
|
||||
void watch_face_set_battery_indicator(WatchFace_t * const watchFace, uint8_t levelInPercent, BatteryState_e batteryState)
|
||||
void watch_face_set_battery_indicator(WatchFace_t * const watchFace, uint8_t percentage)
|
||||
{
|
||||
if(!watchFace)
|
||||
{
|
||||
@ -420,73 +290,18 @@ void watch_face_set_battery_indicator(WatchFace_t * const watchFace, uint8_t lev
|
||||
|
||||
lv_color_t arc_color = lv_color_make(228, 233, 236);
|
||||
|
||||
if(levelInPercent <= 10)
|
||||
if(percentage <= 10)
|
||||
arc_color = lv_color_make(228, 33, 81);
|
||||
else if(levelInPercent <= 30)
|
||||
else if(percentage <= 30)
|
||||
arc_color = lv_color_make(247, 148, 29);
|
||||
else if(levelInPercent <= 50)
|
||||
else if(percentage <= 50)
|
||||
arc_color = lv_color_make(226, 175, 58);
|
||||
|
||||
lv_arc_set_value(watchFace->batteryIndicator.batteryArc, levelInPercent);
|
||||
lv_obj_set_style_arc_color(watchFace->batteryIndicator.batteryArc, arc_color, LV_PART_INDICATOR);
|
||||
sprintf(watchFace->batteryIndicator.text, "%u %%", levelInPercent);
|
||||
lv_arc_set_value(watchFace->batteryIndicator.battery_arc, percentage);
|
||||
lv_obj_set_style_arc_color(watchFace->batteryIndicator.battery_arc, arc_color, LV_PART_INDICATOR);
|
||||
sprintf(watchFace->batteryIndicator.text, "%u %%", percentage);
|
||||
lv_label_set_text_static(watchFace->batteryIndicator.label, watchFace->batteryIndicator.text);
|
||||
lv_obj_align_to(watchFace->batteryIndicator.label, watchFace->batteryIndicator.batteryArc, LV_ALIGN_CENTER, 0, -5);
|
||||
|
||||
//We save the new battery state only if it's different, this allows to have a trigger when it changes :
|
||||
if(watchFace->batteryIndicator.batteryState != batteryState)
|
||||
{
|
||||
watchFace->batteryIndicator.batteryState = batteryState;
|
||||
set_battery_state_icon(watchFace);
|
||||
}
|
||||
|
||||
//Finally we check if it's time to show the battery low indicator by enabling it's timer
|
||||
if(levelInPercent <= 10 && watchFace->batteryIndicator.batteryState == BATTERY_STATE_DISCHARGING)
|
||||
{
|
||||
lv_timer_resume(watchFace->batteryIndicator.lowBatteryAnimationTimer);
|
||||
}
|
||||
else if(watchFace->batteryIndicator.batteryState == BATTERY_STATE_DISCHARGING)
|
||||
{
|
||||
lv_timer_pause(watchFace->batteryIndicator.lowBatteryAnimationTimer);
|
||||
lv_obj_add_flag(watchFace->batteryIndicator.batteryIcon, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
void watch_face_set_bluetooth_indicator(WatchFace_t * const watchFace, BluetoothState_e bluetoothState)
|
||||
{
|
||||
if(!watchFace)
|
||||
{
|
||||
LV_LOG_ERROR("NULL pointer given !");
|
||||
return;
|
||||
}
|
||||
|
||||
if(watchFace->bluetoothIndicator.bluetoothState == bluetoothState) return;
|
||||
|
||||
watchFace->bluetoothIndicator.bluetoothState = bluetoothState;
|
||||
|
||||
if(!watchFace->display) return;
|
||||
|
||||
_set_bluetooth_indicator(watchFace);
|
||||
}
|
||||
|
||||
void watch_face_set_step_count(WatchFace_t * const watchFace, uint32_t step_count)
|
||||
{
|
||||
if(!watchFace)
|
||||
{
|
||||
LV_LOG_ERROR("NULL pointer given !");
|
||||
return;
|
||||
}
|
||||
|
||||
if(step_count < 1000)
|
||||
sprintf(watchFace->stepCounter.text, "%u", step_count);
|
||||
else if(step_count < 9996)
|
||||
sprintf(watchFace->stepCounter.text, "%.2fk", step_count/1000.0);
|
||||
else
|
||||
sprintf(watchFace->stepCounter.text, "%.1fk", step_count/1000.0);
|
||||
|
||||
if(!watchFace->display) return;
|
||||
|
||||
lv_label_set_text_static(watchFace->stepCounter.label, watchFace->stepCounter.text);
|
||||
lv_obj_align_to(watchFace->batteryIndicator.label, watchFace->batteryIndicator.battery_arc, LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
|
||||
void watch_face_destroy(WatchFace_t * const watchFace)
|
||||
@ -504,12 +319,8 @@ void watch_face_destroy(WatchFace_t * const watchFace)
|
||||
watchFace->minuteHand.handImg = NULL;
|
||||
watchFace->secondHand.handImg = NULL;
|
||||
watchFace->mediumHand24h.handImg = NULL;
|
||||
watchFace->batteryIndicator.batteryArc = NULL;
|
||||
watchFace->batteryIndicator.battery_arc = NULL;
|
||||
watchFace->batteryIndicator.label = NULL;
|
||||
watchFace->batteryIndicator.batteryIcon = NULL;
|
||||
watchFace->batteryIndicator.lowBatteryAnimationTimer = NULL;
|
||||
watchFace->stepCounter.label = NULL;
|
||||
watchFace->bluetoothIndicator.bluetoothIcon = NULL;
|
||||
}
|
||||
|
||||
void watch_face_force_sync(WatchFace_t *const watchFace)
|
||||
|
@ -4,23 +4,8 @@
|
||||
#include "lvgl.h"
|
||||
#include <time.h>
|
||||
|
||||
typedef enum BatteryState
|
||||
{
|
||||
BATTERY_STATE_DISCHARGING = 0,
|
||||
BATTERY_STATE_CHARGING,
|
||||
BATTERY_STATE_CHARGED,
|
||||
} BatteryState_e;
|
||||
|
||||
typedef enum BluetoothState
|
||||
{
|
||||
BLUETOOTH_STATE_OFF = 0,
|
||||
BLUETOOTH_STATE_ON,
|
||||
BLUETOOTH_STATE_CONNECTED
|
||||
} BluetoothState_e;
|
||||
|
||||
typedef void (*DateTimeCb_t)(struct tm * const dateTime);
|
||||
|
||||
typedef void (*BatteryIndicatorCb_t)(uint8_t *levelInPercent, BatteryState_e *batteryState);
|
||||
typedef uint8_t (*BatteryIndicatorCb_t)(void);
|
||||
|
||||
typedef struct DateWindow
|
||||
{
|
||||
@ -37,25 +22,10 @@ typedef struct WatchHand
|
||||
typedef struct BatteryIndicator
|
||||
{
|
||||
lv_obj_t *label;
|
||||
lv_obj_t *batteryArc;
|
||||
lv_obj_t *batteryIcon;
|
||||
lv_timer_t *lowBatteryAnimationTimer;
|
||||
lv_obj_t *battery_arc;
|
||||
char text[7];
|
||||
BatteryState_e batteryState:2;
|
||||
} BatteryIndicator_t;
|
||||
|
||||
typedef struct BluetoothIndicator
|
||||
{
|
||||
lv_obj_t *bluetoothIcon;
|
||||
BluetoothState_e bluetoothState;
|
||||
} BluetoothIndicator_t;
|
||||
|
||||
typedef struct StepCounter
|
||||
{
|
||||
lv_obj_t *label;
|
||||
char text[7];
|
||||
} StepCounter_t;
|
||||
|
||||
/* Watch face context object */
|
||||
typedef struct WatchFace
|
||||
{
|
||||
@ -69,8 +39,7 @@ typedef struct WatchFace
|
||||
lv_obj_t *display;
|
||||
DateWindow_t dateWindow;
|
||||
BatteryIndicator_t batteryIndicator;
|
||||
StepCounter_t stepCounter;
|
||||
BluetoothIndicator_t bluetoothIndicator;
|
||||
|
||||
struct tm dateTime;
|
||||
} WatchFace_t;
|
||||
|
||||
@ -107,25 +76,7 @@ void watch_face_create(WatchFace_t * const watchFace);
|
||||
* @param watchFace a pointer to the watch face context structure.
|
||||
* @param percentage the value to set the indicator to in percent.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Sets the battery level in percent as well as it's current state to draw on the watch face.
|
||||
*
|
||||
* @param watchFace a pointer to the watch face context structure.
|
||||
* @param levelInPercent the level to set the indicator to in percent.
|
||||
* @param batteryState the current state of the battery : BATTERY_STATE_DISCHARGING, BATTERY_STATE_CHARGING or BATTERY_STATE_CHARGED
|
||||
*/
|
||||
void watch_face_set_battery_indicator(WatchFace_t * const watchFace, uint8_t levelInPercent, BatteryState_e batteryState);
|
||||
|
||||
/**
|
||||
* @brief Sets the current bluetooth state to display on the watch face
|
||||
*
|
||||
* @param watchFace a pointer to the watch face context structure.
|
||||
* @param bluetoothState the state of the bluetooth modem to show, can be : BLUETOOTH_STATE_OFF, BLUETOOTH_STATE_ON or BLUETOOTH_STATE_CONNECTED
|
||||
*/
|
||||
void watch_face_set_bluetooth_indicator(WatchFace_t * const watchFace, BluetoothState_e bluetoothState);
|
||||
|
||||
void watch_face_set_step_count(WatchFace_t * const watchFace, uint32_t step_count);
|
||||
void watch_face_set_battery_indicator(WatchFace_t * const watchFace, uint8_t percentage);
|
||||
|
||||
/**
|
||||
* @brief Forces the watch face to sync up with the RTC by calling the provided date_time_cb
|
||||
|
@ -55,10 +55,8 @@ static void touch_panel_feedback_cb(struct _lv_indev_drv_t *lv_indev_drv, uint8_
|
||||
{
|
||||
(void)lv_indev_drv;
|
||||
|
||||
uint32_t vibration_duration_ms = persistency_get_settings()->display.display_vibrate_on_touch_duration*50;
|
||||
uint16_t vibration_strength = persistency_get_settings()->display.display_vibrate_on_touch_strength*32;
|
||||
uint32_t vibration_duration_ms = 0;
|
||||
if(persistency_get_settings()->display.display_vibrate_on_touch_duration)
|
||||
vibration_duration_ms = persistency_get_settings()->display.display_vibrate_on_touch_duration*50 + 50;
|
||||
|
||||
switch(lv_event_code)
|
||||
{
|
||||
|
@ -167,14 +167,14 @@ tls_bt_init(uint8_t uart_idx)
|
||||
ble_hs_cfg.gatts_register_cb = on_svr_register_cb;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
/* Initialize all packages. */
|
||||
nimble_port_init(); // 7 k ram gone --> 112691
|
||||
nimble_port_init();
|
||||
/*Application levels code entry*/
|
||||
tls_ble_gap_init(); // 0k ram gone
|
||||
tls_bt_util_init(); // 0k ram gone
|
||||
tls_ble_gap_init();
|
||||
tls_bt_util_init();
|
||||
/*Initialize the vuart interface and enable controller*/
|
||||
ble_hci_vuart_init(uart_idx); // 47k gone --> 65423
|
||||
ble_hci_vuart_init(uart_idx);
|
||||
/* As the last thing, process events from default event queue. */
|
||||
tls_nimble_start(); // 3k gone --> 62175
|
||||
tls_nimble_start();
|
||||
|
||||
while(bt_adapter_state == WM_BT_STATE_OFF) {
|
||||
tls_os_time_delay(10);
|
||||
|
@ -15,11 +15,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** NOT PART OF THE OFFICIAL SDK **/
|
||||
int tls_bt_init(uint8_t uart_idx);
|
||||
int tls_bt_deinit(void);
|
||||
/**********************************/
|
||||
|
||||
|
||||
typedef enum {
|
||||
WM_BT_SYSTEM_ACTION_IDLE,
|
||||
|
@ -109,6 +109,9 @@ const char *tls_bt_gap_evt_2_str(uint32_t event)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define BLE_HS_ENOERR 0
|
||||
|
||||
const char *tls_bt_rc_2_str(uint32_t event)
|
||||
{
|
||||
switch(event) {
|
||||
@ -150,33 +153,7 @@ const char *tls_bt_rc_2_str(uint32_t event)
|
||||
}
|
||||
}
|
||||
|
||||
const char *tls_bt_addr_type_2_str(uint8_t addr_type)
|
||||
{
|
||||
switch(addr_type)
|
||||
{
|
||||
CASE_RETURN_STR(BLE_OWN_ADDR_PUBLIC)
|
||||
CASE_RETURN_STR(BLE_OWN_ADDR_RANDOM)
|
||||
CASE_RETURN_STR(BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT)
|
||||
CASE_RETURN_STR(BLE_OWN_ADDR_RPA_RANDOM_DEFAULT)
|
||||
|
||||
default:
|
||||
return "unknown addr_type";
|
||||
}
|
||||
}
|
||||
|
||||
const char *tls_bt_access_opt_2_str(uint8_t op)
|
||||
{
|
||||
switch(op)
|
||||
{
|
||||
CASE_RETURN_STR(BLE_GATT_ACCESS_OP_READ_CHR)
|
||||
CASE_RETURN_STR(BLE_GATT_ACCESS_OP_WRITE_CHR)
|
||||
CASE_RETURN_STR(BLE_GATT_ACCESS_OP_READ_DSC)
|
||||
CASE_RETURN_STR(BLE_GATT_ACCESS_OP_WRITE_DSC)
|
||||
|
||||
default:
|
||||
return "unknown operation type";
|
||||
}
|
||||
}
|
||||
|
||||
static void async_evt_func(struct ble_npl_event *ev)
|
||||
{
|
||||
|
@ -47,15 +47,12 @@ extern tls_bt_log_level_t tls_appl_trace_level;
|
||||
#define TLS_BT_APPL_TRACE_EVENT(...)
|
||||
#define TLS_BT_APPL_TRACE_DEBUG(...)
|
||||
#define TLS_BT_APPL_TRACE_VERBOSE(...)
|
||||
#endif
|
||||
|
||||
#define BLE_HS_ENOERR 0
|
||||
#endif
|
||||
|
||||
void tls_bt_log(uint32_t trace_set_mask, const char *fmt_str, ...);
|
||||
const char *tls_bt_gap_evt_2_str(uint32_t event);
|
||||
const char *tls_bt_rc_2_str(uint32_t event);
|
||||
const char *tls_bt_addr_type_2_str(uint8_t addr_type);
|
||||
const char *tls_bt_access_opt_2_str(uint8_t op);
|
||||
|
||||
extern int tls_bt_util_init(void);
|
||||
extern int tls_bt_util_deinit(void);
|
||||
|
@ -61,11 +61,11 @@
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_MSYS_1_BLOCK_COUNT
|
||||
#define MYNEWT_VAL_MSYS_1_BLOCK_COUNT (10)
|
||||
#define MYNEWT_VAL_MSYS_1_BLOCK_COUNT (24)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_MSYS_1_BLOCK_SIZE
|
||||
#define MYNEWT_VAL_MSYS_1_BLOCK_SIZE (100) // Default 292
|
||||
#define MYNEWT_VAL_MSYS_1_BLOCK_SIZE (292)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_MSYS_1_SANITY_MIN_COUNT
|
||||
@ -925,7 +925,7 @@
|
||||
|
||||
/*** @apache-mynewt-nimble/nimble/transport/socket */
|
||||
#ifndef MYNEWT_VAL_BLE_ACL_BUF_COUNT
|
||||
#define MYNEWT_VAL_BLE_ACL_BUF_COUNT (8) // Default 36
|
||||
#define MYNEWT_VAL_BLE_ACL_BUF_COUNT (36)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_ACL_BUF_SIZE
|
||||
@ -947,11 +947,11 @@
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT
|
||||
#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT (5) // Default 16
|
||||
#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT (16)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT
|
||||
#define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT (5) // Default 96
|
||||
#define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT (96)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_SOCK_CLI_SYSINIT_STAGE
|
||||
|
@ -17,7 +17,7 @@ void tls_nimble_start(void)
|
||||
{
|
||||
tls_host_task_stack_ptr = (void *)tls_mem_alloc(MYNEWT_VAL(OS_HS_STACK_SIZE) * sizeof(uint32_t));
|
||||
assert(tls_host_task_stack_ptr != NULL);
|
||||
tls_os_task_create(&tls_host_task_hdl, "ble_svc",
|
||||
tls_os_task_create(&tls_host_task_hdl, "bth",
|
||||
nimble_host_task,
|
||||
(void *)0,
|
||||
(void *)tls_host_task_stack_ptr,
|
||||
|
@ -43,22 +43,21 @@ INCLUDES += -I $(TOP_DIR)/src/os/rtos/include
|
||||
|
||||
INCLUDES += -I $(TOP_DIR)/src/app/factorycmd
|
||||
INCLUDES += -I $(TOP_DIR)/src/app/bleapp
|
||||
|
||||
INCLUDES += -I $(TOP_DIR)/app
|
||||
INCLUDES += -I $(TOP_DIR)/app/app_include
|
||||
INCLUDES += -I $(TOP_DIR)/app/app_drivers/lcd
|
||||
INCLUDES += -I $(TOP_DIR)/app/app_drivers/mmc_sdio
|
||||
INCLUDES += -I $(TOP_DIR)/app/app_drivers/i2c
|
||||
INCLUDES += -I $(TOP_DIR)/app/app_drivers/watch_peripherals
|
||||
INCLUDES += -I $(TOP_DIR)/app/app_include
|
||||
INCLUDES += -I $(TOP_DIR)/app/ble
|
||||
INCLUDES += -I $(TOP_DIR)/app/gfx
|
||||
INCLUDES += -I $(TOP_DIR)/app/persistency
|
||||
INCLUDES += -I $(TOP_DIR)/app/translation
|
||||
INCLUDES += -I $(TOP_DIR)/app/gfx
|
||||
INCLUDES += -I $(TOP_DIR)/app
|
||||
|
||||
#lvgl include
|
||||
INCLUDES += -I $(TOP_DIR)/lvgl/lvgl_v8.3
|
||||
INCLUDES += -I $(TOP_DIR)/lvgl/lvgl_port
|
||||
|
||||
|
||||
#nimble host
|
||||
INCLUDES += -I $(TOP_DIR)/src/bt/blehost/ext/tinycrypt/include
|
||||
INCLUDES += -I $(TOP_DIR)/src/bt/blehost/nimble/host/include
|
||||
|
Loading…
Reference in New Issue
Block a user