mirror of
https://github.com/InfiniTimeOrg/InfiniTime.git
synced 2024-10-22 15:11:51 +02:00
Merge 299edca193
into 8598142c27
This commit is contained in:
commit
c79fb7d693
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,6 +7,7 @@ cmake-build-*
|
|||
cmake-*/
|
||||
CMakeFiles
|
||||
**/CMakeCache.txt
|
||||
CMakeLists.txt.user*
|
||||
cmake_install.cmake
|
||||
Makefile
|
||||
build
|
||||
|
|
12
doc/ble.md
12
doc/ble.md
|
@ -14,6 +14,8 @@ This page describes the BLE implementation and API built in this firmware.
|
|||
- [BLE Services](#ble-services)
|
||||
- [CTS](#cts)
|
||||
- [ANS](#ans)
|
||||
- [BLE Clients](#ble-clients)
|
||||
- [IAC](#iac)
|
||||
- [Getting Information](#getting-information)
|
||||
- [Firmware Version](#firmware-version)
|
||||
- [Battery Level](#battery-level)
|
||||
|
@ -113,6 +115,16 @@ The following custom services are implemented in InfiniTime:
|
|||
|
||||
![ANS sequence diagram](./ble/ans_sequence.png "ANS sequence diagram")
|
||||
|
||||
## BLE clients
|
||||
|
||||
### IAC
|
||||
|
||||
InfiniTime implements Immediade Alert Service client, that can be used to send notifications to companion app.
|
||||
This is useful for "Find my Phone" functionality.
|
||||
|
||||
More documentation about this service can be found here.
|
||||
|
||||
[Immediade Alert Service](https://www.bluetooth.com/specifications/specs/immediate-alert-service-1-0/)
|
||||
---
|
||||
|
||||
### Getting Information
|
||||
|
|
|
@ -385,6 +385,7 @@ list(APPEND SOURCE_FILES
|
|||
displayapp/screens/Notifications.cpp
|
||||
displayapp/screens/Twos.cpp
|
||||
displayapp/screens/HeartRate.cpp
|
||||
displayapp/screens/FindMyPhone.cpp
|
||||
displayapp/screens/FlashLight.cpp
|
||||
displayapp/screens/List.cpp
|
||||
displayapp/screens/CheckboxList.cpp
|
||||
|
@ -459,6 +460,7 @@ list(APPEND SOURCE_FILES
|
|||
components/ble/BatteryInformationService.cpp
|
||||
components/ble/FSService.cpp
|
||||
components/ble/ImmediateAlertService.cpp
|
||||
components/ble/ImmediateAlertClient.cpp
|
||||
components/ble/ServiceDiscovery.cpp
|
||||
components/ble/HeartRateService.cpp
|
||||
components/ble/MotionService.cpp
|
||||
|
@ -528,6 +530,7 @@ list(APPEND RECOVERY_SOURCE_FILES
|
|||
components/ble/BatteryInformationService.cpp
|
||||
components/ble/FSService.cpp
|
||||
components/ble/ImmediateAlertService.cpp
|
||||
components/ble/ImmediateAlertClient.cpp
|
||||
components/ble/ServiceDiscovery.cpp
|
||||
components/ble/NavigationService.cpp
|
||||
components/ble/HeartRateService.cpp
|
||||
|
@ -608,6 +611,7 @@ set(INCLUDE_FILES
|
|||
displayapp/Apps.h
|
||||
displayapp/screens/Notifications.h
|
||||
displayapp/screens/HeartRate.h
|
||||
displayapp/screens/FindMyPhone.h
|
||||
displayapp/screens/Metronome.h
|
||||
displayapp/screens/Motion.h
|
||||
displayapp/screens/Timer.h
|
||||
|
@ -647,6 +651,7 @@ set(INCLUDE_FILES
|
|||
components/ble/BatteryInformationService.h
|
||||
components/ble/FSService.h
|
||||
components/ble/ImmediateAlertService.h
|
||||
components/ble/ImmediateAlertClient.h
|
||||
components/ble/ServiceDiscovery.h
|
||||
components/ble/BleClient.h
|
||||
components/ble/HeartRateService.h
|
||||
|
@ -835,7 +840,7 @@ if (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
|
|||
# add_definitions(-DCLOCK_CONFIG_LOG_LEVEL=4)
|
||||
# add_definitions(-DRTC_CONFIG_LOG_ENABLED=1)
|
||||
# add_definitions(-DRTC_CONFIG_LOG_LEVEL=4)
|
||||
|
||||
|
||||
# Nimble Logging
|
||||
add_definitions(-DMYNEWT_VAL_NEWT_FEATURE_LOGCFG=1)
|
||||
# add_definitions(-DMYNEWT_VAL_LOG_LEVEL=0)
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
#define configTICK_RATE_HZ 1024
|
||||
#define configMAX_PRIORITIES (3)
|
||||
#define configMINIMAL_STACK_SIZE (120)
|
||||
#define configTOTAL_HEAP_SIZE (1024 * 40)
|
||||
#define configTOTAL_HEAP_SIZE (1024 * 39)
|
||||
#define configMAX_TASK_NAME_LEN (4)
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
#define configIDLE_SHOULD_YIELD 1
|
||||
|
|
113
src/components/ble/ImmediateAlertClient.cpp
Normal file
113
src/components/ble/ImmediateAlertClient.cpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
#include "components/ble/ImmediateAlertClient.h"
|
||||
#include <cstring>
|
||||
#include <nrf_log.h>
|
||||
#include "systemtask/SystemTask.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
constexpr ble_uuid16_t ImmediateAlertClient::immediateAlertClientUuid;
|
||||
constexpr ble_uuid16_t ImmediateAlertClient::alertLevelCharacteristicUuid;
|
||||
|
||||
namespace {
|
||||
int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error* error, const struct ble_gatt_svc* service, void* arg) {
|
||||
auto client = static_cast<ImmediateAlertClient*>(arg);
|
||||
return client->OnDiscoveryEvent(conn_handle, error, service);
|
||||
}
|
||||
|
||||
int OnImmediateAlertCharacteristicDiscoveredCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error* error,
|
||||
const struct ble_gatt_chr* chr,
|
||||
void* arg) {
|
||||
auto client = static_cast<ImmediateAlertClient*>(arg);
|
||||
return client->OnCharacteristicDiscoveryEvent(conn_handle, error, chr);
|
||||
}
|
||||
}
|
||||
|
||||
ImmediateAlertClient::ImmediateAlertClient(Pinetime::System::SystemTask& systemTask)
|
||||
: systemTask {systemTask},
|
||||
characteristicDefinition {{
|
||||
.uuid = &alertLevelCharacteristicUuid.u,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
},
|
||||
{0}},
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = &immediateAlertClientUuid.u,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
} {
|
||||
}
|
||||
|
||||
void ImmediateAlertClient::Init() {
|
||||
}
|
||||
|
||||
bool ImmediateAlertClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service) {
|
||||
if (service == nullptr && error->status == BLE_HS_EDONE) {
|
||||
if (isDiscovered) {
|
||||
NRF_LOG_INFO("IAS found, starting characteristics discovery");
|
||||
|
||||
ble_gattc_disc_all_chrs(connectionHandle, iasStartHandle, iasEndHandle, OnImmediateAlertCharacteristicDiscoveredCallback, this);
|
||||
} else {
|
||||
NRF_LOG_INFO("IAS not found");
|
||||
onServiceDiscovered(connectionHandle);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (service != nullptr && ble_uuid_cmp(&immediateAlertClientUuid.u, &service->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("IAS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
|
||||
isDiscovered = true;
|
||||
iasStartHandle = service->start_handle;
|
||||
iasEndHandle = service->end_handle;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int ImmediateAlertClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle,
|
||||
const ble_gatt_error* error,
|
||||
const ble_gatt_chr* characteristic) {
|
||||
|
||||
if (error->status != 0 && error->status != BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("IAS Characteristic discovery ERROR");
|
||||
onServiceDiscovered(conn_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
||||
if (!isCharacteristicDiscovered) {
|
||||
NRF_LOG_INFO("IAS Characteristic discovery unsuccessful");
|
||||
onServiceDiscovered(conn_handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (characteristic != nullptr && ble_uuid_cmp(&alertLevelCharacteristicUuid.u, &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("AIS Characteristic discovered : 0x%x", characteristic->val_handle);
|
||||
isCharacteristicDiscovered = true;
|
||||
alertLevelHandle = characteristic->val_handle;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ImmediateAlertClient::Discover(uint16_t connectionHandle, std::function<void(uint16_t)> onServiceDiscovered) {
|
||||
NRF_LOG_INFO("[IAS] Starting discovery");
|
||||
this->onServiceDiscovered = onServiceDiscovered;
|
||||
ble_gattc_disc_svc_by_uuid(connectionHandle, &immediateAlertClientUuid.u, OnDiscoveryEventCallback, this);
|
||||
}
|
||||
|
||||
bool ImmediateAlertClient::sendImmediateAlert(ImmediateAlertClient::Levels level) {
|
||||
|
||||
auto* om = ble_hs_mbuf_from_flat(&level, 1);
|
||||
|
||||
uint16_t connectionHandle = systemTask.nimble().connHandle();
|
||||
|
||||
if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ble_gattc_write_no_rsp(connectionHandle, alertLevelHandle, om);
|
||||
return true;
|
||||
}
|
61
src/components/ble/ImmediateAlertClient.h
Normal file
61
src/components/ble/ImmediateAlertClient.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
#define min // workaround: nimble's min/max macros conflict with libstdc++
|
||||
#define max
|
||||
#include <host/ble_gap.h>
|
||||
#undef max
|
||||
#undef min
|
||||
#include <cstdint>
|
||||
#include "components/ble/BleClient.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
class SystemTask;
|
||||
}
|
||||
|
||||
namespace Controllers {
|
||||
class NotificationManager;
|
||||
|
||||
class ImmediateAlertClient : public BleClient {
|
||||
public:
|
||||
enum class Levels : uint8_t { NoAlert = 0, MildAlert = 1, HighAlert = 2 };
|
||||
|
||||
ImmediateAlertClient(Pinetime::System::SystemTask& systemTask);
|
||||
void Init();
|
||||
|
||||
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service);
|
||||
int OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
|
||||
|
||||
bool sendImmediateAlert(Levels level);
|
||||
|
||||
static constexpr const ble_uuid16_t* Uuid() {
|
||||
return &ImmediateAlertClient::immediateAlertClientUuid;
|
||||
}
|
||||
|
||||
static constexpr const ble_uuid16_t* AlertLevelCharacteristicUuid() {
|
||||
return &ImmediateAlertClient::alertLevelCharacteristicUuid;
|
||||
}
|
||||
|
||||
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
|
||||
|
||||
private:
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
|
||||
static constexpr uint16_t immediateAlertClientId {0x1802};
|
||||
static constexpr uint16_t alertLevelId {0x2A06};
|
||||
|
||||
static constexpr ble_uuid16_t immediateAlertClientUuid {.u {.type = BLE_UUID_TYPE_16}, .value = immediateAlertClientId};
|
||||
static constexpr ble_uuid16_t alertLevelCharacteristicUuid {.u {.type = BLE_UUID_TYPE_16}, .value = alertLevelId};
|
||||
|
||||
bool isDiscovered = false;
|
||||
uint16_t iasStartHandle;
|
||||
uint16_t iasEndHandle;
|
||||
bool isCharacteristicDiscovered = false;
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
uint16_t alertLevelHandle;
|
||||
std::function<void(uint16_t)> onServiceDiscovered;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -46,10 +46,11 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
|
|||
weatherService {dateTimeController},
|
||||
batteryInformationService {batteryController},
|
||||
immediateAlertService {systemTask, notificationManager},
|
||||
iaClient {systemTask},
|
||||
heartRateService {*this, heartRateController},
|
||||
motionService {*this, motionController},
|
||||
fsService {systemTask, fs},
|
||||
serviceDiscovery({¤tTimeClient, &alertNotificationClient}) {
|
||||
serviceDiscovery({¤tTimeClient, &alertNotificationClient, &iaClient}) {
|
||||
}
|
||||
|
||||
void nimble_on_reset(int reason) {
|
||||
|
@ -95,6 +96,7 @@ void NimbleController::Init() {
|
|||
dfuService.Init();
|
||||
batteryInformationService.Init();
|
||||
immediateAlertService.Init();
|
||||
iaClient.Init();
|
||||
heartRateService.Init();
|
||||
motionService.Init();
|
||||
fsService.Init();
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "components/ble/FSService.h"
|
||||
#include "components/ble/HeartRateService.h"
|
||||
#include "components/ble/ImmediateAlertService.h"
|
||||
#include "components/ble/ImmediateAlertClient.h"
|
||||
#include "components/ble/MusicService.h"
|
||||
#include "components/ble/NavigationService.h"
|
||||
#include "components/ble/ServiceDiscovery.h"
|
||||
|
@ -71,6 +72,10 @@ namespace Pinetime {
|
|||
return weatherService;
|
||||
};
|
||||
|
||||
Pinetime::Controllers::ImmediateAlertClient& immediateAlertClient() {
|
||||
return iaClient;
|
||||
}
|
||||
|
||||
uint16_t connHandle();
|
||||
void NotifyBatteryLevel(uint8_t level);
|
||||
|
||||
|
@ -103,6 +108,7 @@ namespace Pinetime {
|
|||
NavigationService navService;
|
||||
BatteryInformationService batteryInformationService;
|
||||
ImmediateAlertService immediateAlertService;
|
||||
ImmediateAlertClient iaClient;
|
||||
HeartRateService heartRateService;
|
||||
MotionService motionService;
|
||||
FSService fsService;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
ServiceDiscovery::ServiceDiscovery(std::array<BleClient*, 2>&& clients) : clients {clients} {
|
||||
ServiceDiscovery::ServiceDiscovery(std::array<BleClient*, 3>&& clients) : clients {clients} {
|
||||
}
|
||||
|
||||
void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) {
|
||||
|
@ -29,4 +29,4 @@ void ServiceDiscovery::DiscoverNextService(uint16_t connectionHandle) {
|
|||
this->OnServiceDiscovered(connectionHandle);
|
||||
};
|
||||
(*clientIterator)->Discover(connectionHandle, discoverNextService);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,13 +9,13 @@ namespace Pinetime {
|
|||
|
||||
class ServiceDiscovery {
|
||||
public:
|
||||
ServiceDiscovery(std::array<BleClient*, 2>&& bleClients);
|
||||
ServiceDiscovery(std::array<BleClient*, 3>&& bleClients);
|
||||
|
||||
void StartDiscovery(uint16_t connectionHandle);
|
||||
|
||||
private:
|
||||
BleClient** clientIterator;
|
||||
std::array<BleClient*, 2> clients;
|
||||
std::array<BleClient*, 3> clients;
|
||||
void OnServiceDiscovered(uint16_t connectionHandle);
|
||||
void DiscoverNextService(uint16_t connectionHandle);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "displayapp/DisplayApp.h"
|
||||
#include <libraries/log/nrf_log.h>
|
||||
#include "displayapp/screens/HeartRate.h"
|
||||
#include "displayapp/screens/FindMyPhone.h"
|
||||
#include "displayapp/screens/Motion.h"
|
||||
#include "displayapp/screens/Timer.h"
|
||||
#include "displayapp/screens/Alarm.h"
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace Pinetime {
|
|||
SettingChimes,
|
||||
SettingShakeThreshold,
|
||||
SettingBluetooth,
|
||||
FindMyPhone,
|
||||
Error
|
||||
};
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ else ()
|
|||
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Dice")
|
||||
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome")
|
||||
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation")
|
||||
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::FindMyPhone")
|
||||
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather")
|
||||
#set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion")
|
||||
set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware")
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
},
|
||||
{
|
||||
"file": "FontAwesome5-Solid+Brands+Regular.woff",
|
||||
"range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743"
|
||||
"range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743, 0xf002"
|
||||
}
|
||||
],
|
||||
"bpp": 1,
|
||||
|
|
126
src/displayapp/screens/FindMyPhone.cpp
Normal file
126
src/displayapp/screens/FindMyPhone.cpp
Normal file
|
@ -0,0 +1,126 @@
|
|||
#include "displayapp/screens/FindMyPhone.h"
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#include "displayapp/DisplayApp.h"
|
||||
#include "displayapp/InfiniTimeTheme.h"
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
static constexpr char defaultLabelText[] = "Find my phone";
|
||||
static constexpr char alertSentLabelText[] = "Alert sent";
|
||||
static constexpr char noConnectionLabelText[] = "No connection";
|
||||
static constexpr auto restoreLabelTimeoutTicks = pdMS_TO_TICKS(2 * 1000);
|
||||
|
||||
void btnImmediateAlertEventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||
auto* screen = static_cast<FindMyPhone*>(obj->user_data);
|
||||
screen->OnImmediateAlertEvent(obj, event);
|
||||
}
|
||||
|
||||
void RestoreLabelTaskCallback(lv_task_t* task) {
|
||||
auto* screen = static_cast<FindMyPhone*>(task->user_data);
|
||||
screen->RestoreLabelText();
|
||||
screen->StopRestoreLabelTask();
|
||||
}
|
||||
}
|
||||
|
||||
FindMyPhone::FindMyPhone(Pinetime::Controllers::ImmediateAlertClient& immediateAlertClient) : immediateAlertClient {immediateAlertClient} {
|
||||
last_level = Pinetime::Controllers::ImmediateAlertClient::Levels::NoAlert;
|
||||
|
||||
container = lv_cont_create(lv_scr_act(), nullptr);
|
||||
|
||||
lv_obj_set_size(container, LV_HOR_RES, LV_VER_RES);
|
||||
lv_obj_set_style_local_bg_color(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||
lv_obj_set_style_local_pad_all(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||
lv_obj_set_style_local_pad_inner(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||
lv_obj_set_style_local_border_width(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||
|
||||
label_title = lv_label_create(lv_scr_act(), nullptr);
|
||||
|
||||
lv_label_set_text_static(label_title, defaultLabelText);
|
||||
lv_obj_set_style_local_text_color(label_title, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
|
||||
lv_obj_align(label_title, nullptr, LV_ALIGN_CENTER, 0, -40);
|
||||
|
||||
bt_none = lv_btn_create(container, nullptr);
|
||||
bt_none->user_data = this;
|
||||
lv_obj_set_event_cb(bt_none, btnImmediateAlertEventHandler);
|
||||
lv_obj_set_size(bt_none, 76, 76);
|
||||
lv_obj_align(bt_none, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||
label_none = lv_label_create(bt_none, nullptr);
|
||||
lv_label_set_text_static(label_none, "None");
|
||||
lv_obj_set_style_local_bg_color(bt_none, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
|
||||
|
||||
bt_mild = lv_btn_create(container, nullptr);
|
||||
bt_mild->user_data = this;
|
||||
lv_obj_set_event_cb(bt_mild, btnImmediateAlertEventHandler);
|
||||
lv_obj_set_size(bt_mild, 76, 76);
|
||||
lv_obj_align(bt_mild, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
|
||||
label_mild = lv_label_create(bt_mild, nullptr);
|
||||
lv_label_set_text_static(label_mild, "Mild");
|
||||
lv_obj_set_style_local_bg_color(bt_mild, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight);
|
||||
|
||||
bt_high = lv_btn_create(container, nullptr);
|
||||
bt_high->user_data = this;
|
||||
lv_obj_set_event_cb(bt_high, btnImmediateAlertEventHandler);
|
||||
lv_obj_set_size(bt_high, 76, 76);
|
||||
lv_obj_align(bt_high, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||
label_high = lv_label_create(bt_high, nullptr);
|
||||
lv_label_set_text_static(label_high, "High");
|
||||
lv_obj_set_style_local_bg_color(bt_high, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
}
|
||||
|
||||
FindMyPhone::~FindMyPhone() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
void FindMyPhone::OnImmediateAlertEvent(lv_obj_t* obj, lv_event_t event) {
|
||||
if (event == LV_EVENT_CLICKED) {
|
||||
if (obj == bt_none) {
|
||||
last_level = Pinetime::Controllers::ImmediateAlertClient::Levels::NoAlert;
|
||||
} else if (obj == bt_mild) {
|
||||
last_level = Pinetime::Controllers::ImmediateAlertClient::Levels::MildAlert;
|
||||
} else if (obj == bt_high) {
|
||||
last_level = Pinetime::Controllers::ImmediateAlertClient::Levels::HighAlert;
|
||||
}
|
||||
UpdateImmediateAlerts();
|
||||
}
|
||||
}
|
||||
|
||||
void FindMyPhone::UpdateImmediateAlerts() {
|
||||
switch (last_level) {
|
||||
case Pinetime::Controllers::ImmediateAlertClient::Levels::NoAlert:
|
||||
lv_obj_set_style_local_text_color(label_title, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
|
||||
break;
|
||||
case Pinetime::Controllers::ImmediateAlertClient::Levels::MildAlert:
|
||||
lv_obj_set_style_local_text_color(label_title, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight);
|
||||
break;
|
||||
case Pinetime::Controllers::ImmediateAlertClient::Levels::HighAlert:
|
||||
lv_obj_set_style_local_text_color(label_title, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
break;
|
||||
}
|
||||
if (immediateAlertClient.sendImmediateAlert(last_level)) {
|
||||
lv_label_set_text_static(label_title, alertSentLabelText);
|
||||
} else {
|
||||
lv_label_set_text_static(label_title, noConnectionLabelText);
|
||||
}
|
||||
ScheduleRestoreLabelTask();
|
||||
}
|
||||
|
||||
void FindMyPhone::ScheduleRestoreLabelTask() {
|
||||
if (taskRestoreLabelText) {
|
||||
return;
|
||||
}
|
||||
taskRestoreLabelText = lv_task_create(RestoreLabelTaskCallback, restoreLabelTimeoutTicks, LV_TASK_PRIO_MID, this);
|
||||
}
|
||||
|
||||
void FindMyPhone::StopRestoreLabelTask() {
|
||||
if (taskRestoreLabelText) {
|
||||
lv_task_del(taskRestoreLabelText);
|
||||
taskRestoreLabelText = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void FindMyPhone::RestoreLabelText() {
|
||||
lv_label_set_text_static(label_title, defaultLabelText);
|
||||
lv_obj_set_style_local_text_color(label_title, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
|
||||
}
|
62
src/displayapp/screens/FindMyPhone.h
Normal file
62
src/displayapp/screens/FindMyPhone.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <chrono>
|
||||
#include "displayapp/screens/Screen.h"
|
||||
#include "Symbols.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "components/ble/ImmediateAlertClient.h"
|
||||
|
||||
#include <lvgl/src/lv_core/lv_style.h>
|
||||
#include <lvgl/src/lv_core/lv_obj.h>
|
||||
|
||||
namespace Pinetime {
|
||||
|
||||
namespace Controllers {
|
||||
class ImmediateAlertClient;
|
||||
}
|
||||
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
|
||||
class FindMyPhone : public Screen {
|
||||
public:
|
||||
explicit FindMyPhone(Pinetime::Controllers::ImmediateAlertClient& immediateAlertClient);
|
||||
~FindMyPhone() override;
|
||||
|
||||
void OnImmediateAlertEvent(lv_obj_t* obj, lv_event_t event);
|
||||
|
||||
void ScheduleRestoreLabelTask();
|
||||
void StopRestoreLabelTask();
|
||||
void RestoreLabelText();
|
||||
|
||||
private:
|
||||
Pinetime::Controllers::ImmediateAlertClient& immediateAlertClient;
|
||||
|
||||
void UpdateImmediateAlerts();
|
||||
|
||||
lv_obj_t* container;
|
||||
lv_obj_t* label_title;
|
||||
lv_obj_t* bt_none;
|
||||
lv_obj_t* bt_high;
|
||||
lv_obj_t* bt_mild;
|
||||
lv_obj_t* label_none;
|
||||
lv_obj_t* label_high;
|
||||
lv_obj_t* label_mild;
|
||||
lv_task_t* taskRestoreLabelText = nullptr;
|
||||
|
||||
Pinetime::Controllers::ImmediateAlertClient::Levels last_level;
|
||||
};
|
||||
}
|
||||
|
||||
template <>
|
||||
struct AppTraits<Apps::FindMyPhone> {
|
||||
static constexpr Apps app = Apps::FindMyPhone;
|
||||
static constexpr const char* icon = Screens::Symbols::magnifyingGlass;
|
||||
|
||||
static Screens::Screen* Create(AppControllers& controllers) {
|
||||
return new Screens::FindMyPhone(controllers.systemTask->nimble().immediateAlertClient());
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
|
@ -39,6 +39,7 @@ namespace Pinetime {
|
|||
static constexpr const char* eye = "\xEF\x81\xAE";
|
||||
static constexpr const char* home = "\xEF\x80\x95";
|
||||
static constexpr const char* sleep = "\xEE\xBD\x84";
|
||||
static constexpr const char* magnifyingGlass = "\xEF\x80\x82"; // f002
|
||||
|
||||
// fontawesome_weathericons.c
|
||||
// static constexpr const char* sun = "\xEF\x86\x85";
|
||||
|
|
Loading…
Reference in a new issue