Compare commits

...

10 commits

Author SHA1 Message Date
Vyacheslav Chigrin c79fb7d693
Merge 299edca193 into 8598142c27 2024-10-10 00:24:47 +01:00
NeroBurner 8598142c27
Remove unused submodule QCBOR (#2138)
Some checks failed
CI / build-firmware (push) Successful in 5m57s
CI / build-simulator (push) Failing after 3s
CI / get-base-ref-size (push) Has been skipped
CI / Compare build size (push) Has been skipped
The submodule isn't used anymore. Remove the submodule reference
completely.
2024-10-09 20:26:08 +02:00
Vyacheslav Chigrin 299edca193 Update documentation. 2024-07-02 23:09:03 +03:00
Vyacheslav Chigrin 8e29d82985 Decrease heap size to fix build. 2024-07-02 23:09:03 +03:00
Vyacheslav Chigrin 0e76bf1766 Restore FindMyPhone UI after task sent. 2024-07-02 23:09:03 +03:00
Vyacheslav Chigrin 15daf4cb84 Fix delivering notification level change in ImmediateAlertClient. 2024-07-02 23:09:03 +03:00
Jozef Mlich 4aef5a9f4d enable discovery 2024-07-02 23:09:03 +03:00
Jozef Mlich 145b45c501 Make it separate as Immediate Alert Client 2024-07-02 23:09:03 +03:00
Jozef Mlich 96b171524f update screen layout 2024-07-02 23:09:03 +03:00
Jozef Mlich 0e1a074720 Try to implement find my phone feature #343
Co-authored-by: Vyacheslav Chigrin <vyacheslav.chigrin@izba.dev>
2024-07-02 23:09:03 +03:00
19 changed files with 400 additions and 12 deletions

1
.gitignore vendored
View file

@ -7,6 +7,7 @@ cmake-build-*
cmake-*/ cmake-*/
CMakeFiles CMakeFiles
**/CMakeCache.txt **/CMakeCache.txt
CMakeLists.txt.user*
cmake_install.cmake cmake_install.cmake
Makefile Makefile
build build

3
.gitmodules vendored
View file

@ -4,9 +4,6 @@
[submodule "src/libs/littlefs"] [submodule "src/libs/littlefs"]
path = src/libs/littlefs path = src/libs/littlefs
url = https://github.com/littlefs-project/littlefs.git url = https://github.com/littlefs-project/littlefs.git
[submodule "src/libs/QCBOR"]
path = src/libs/QCBOR
url = https://github.com/laurencelundblade/QCBOR.git
[submodule "src/libs/arduinoFFT"] [submodule "src/libs/arduinoFFT"]
path = src/libs/arduinoFFT path = src/libs/arduinoFFT
url = https://github.com/kosme/arduinoFFT.git url = https://github.com/kosme/arduinoFFT.git

View file

@ -14,6 +14,8 @@ This page describes the BLE implementation and API built in this firmware.
- [BLE Services](#ble-services) - [BLE Services](#ble-services)
- [CTS](#cts) - [CTS](#cts)
- [ANS](#ans) - [ANS](#ans)
- [BLE Clients](#ble-clients)
- [IAC](#iac)
- [Getting Information](#getting-information) - [Getting Information](#getting-information)
- [Firmware Version](#firmware-version) - [Firmware Version](#firmware-version)
- [Battery Level](#battery-level) - [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") ![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 ### Getting Information

View file

@ -385,6 +385,7 @@ list(APPEND SOURCE_FILES
displayapp/screens/Notifications.cpp displayapp/screens/Notifications.cpp
displayapp/screens/Twos.cpp displayapp/screens/Twos.cpp
displayapp/screens/HeartRate.cpp displayapp/screens/HeartRate.cpp
displayapp/screens/FindMyPhone.cpp
displayapp/screens/FlashLight.cpp displayapp/screens/FlashLight.cpp
displayapp/screens/List.cpp displayapp/screens/List.cpp
displayapp/screens/CheckboxList.cpp displayapp/screens/CheckboxList.cpp
@ -459,6 +460,7 @@ list(APPEND SOURCE_FILES
components/ble/BatteryInformationService.cpp components/ble/BatteryInformationService.cpp
components/ble/FSService.cpp components/ble/FSService.cpp
components/ble/ImmediateAlertService.cpp components/ble/ImmediateAlertService.cpp
components/ble/ImmediateAlertClient.cpp
components/ble/ServiceDiscovery.cpp components/ble/ServiceDiscovery.cpp
components/ble/HeartRateService.cpp components/ble/HeartRateService.cpp
components/ble/MotionService.cpp components/ble/MotionService.cpp
@ -528,6 +530,7 @@ list(APPEND RECOVERY_SOURCE_FILES
components/ble/BatteryInformationService.cpp components/ble/BatteryInformationService.cpp
components/ble/FSService.cpp components/ble/FSService.cpp
components/ble/ImmediateAlertService.cpp components/ble/ImmediateAlertService.cpp
components/ble/ImmediateAlertClient.cpp
components/ble/ServiceDiscovery.cpp components/ble/ServiceDiscovery.cpp
components/ble/NavigationService.cpp components/ble/NavigationService.cpp
components/ble/HeartRateService.cpp components/ble/HeartRateService.cpp
@ -608,6 +611,7 @@ set(INCLUDE_FILES
displayapp/Apps.h displayapp/Apps.h
displayapp/screens/Notifications.h displayapp/screens/Notifications.h
displayapp/screens/HeartRate.h displayapp/screens/HeartRate.h
displayapp/screens/FindMyPhone.h
displayapp/screens/Metronome.h displayapp/screens/Metronome.h
displayapp/screens/Motion.h displayapp/screens/Motion.h
displayapp/screens/Timer.h displayapp/screens/Timer.h
@ -647,6 +651,7 @@ set(INCLUDE_FILES
components/ble/BatteryInformationService.h components/ble/BatteryInformationService.h
components/ble/FSService.h components/ble/FSService.h
components/ble/ImmediateAlertService.h components/ble/ImmediateAlertService.h
components/ble/ImmediateAlertClient.h
components/ble/ServiceDiscovery.h components/ble/ServiceDiscovery.h
components/ble/BleClient.h components/ble/BleClient.h
components/ble/HeartRateService.h components/ble/HeartRateService.h
@ -835,7 +840,7 @@ if (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
# add_definitions(-DCLOCK_CONFIG_LOG_LEVEL=4) # add_definitions(-DCLOCK_CONFIG_LOG_LEVEL=4)
# add_definitions(-DRTC_CONFIG_LOG_ENABLED=1) # add_definitions(-DRTC_CONFIG_LOG_ENABLED=1)
# add_definitions(-DRTC_CONFIG_LOG_LEVEL=4) # add_definitions(-DRTC_CONFIG_LOG_LEVEL=4)
# Nimble Logging # Nimble Logging
add_definitions(-DMYNEWT_VAL_NEWT_FEATURE_LOGCFG=1) add_definitions(-DMYNEWT_VAL_NEWT_FEATURE_LOGCFG=1)
# add_definitions(-DMYNEWT_VAL_LOG_LEVEL=0) # add_definitions(-DMYNEWT_VAL_LOG_LEVEL=0)

View file

@ -62,7 +62,7 @@
#define configTICK_RATE_HZ 1024 #define configTICK_RATE_HZ 1024
#define configMAX_PRIORITIES (3) #define configMAX_PRIORITIES (3)
#define configMINIMAL_STACK_SIZE (120) #define configMINIMAL_STACK_SIZE (120)
#define configTOTAL_HEAP_SIZE (1024 * 40) #define configTOTAL_HEAP_SIZE (1024 * 39)
#define configMAX_TASK_NAME_LEN (4) #define configMAX_TASK_NAME_LEN (4)
#define configUSE_16_BIT_TICKS 0 #define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1 #define configIDLE_SHOULD_YIELD 1

View 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;
}

View 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;
};
}
}

View file

@ -46,10 +46,11 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
weatherService {dateTimeController}, weatherService {dateTimeController},
batteryInformationService {batteryController}, batteryInformationService {batteryController},
immediateAlertService {systemTask, notificationManager}, immediateAlertService {systemTask, notificationManager},
iaClient {systemTask},
heartRateService {*this, heartRateController}, heartRateService {*this, heartRateController},
motionService {*this, motionController}, motionService {*this, motionController},
fsService {systemTask, fs}, fsService {systemTask, fs},
serviceDiscovery({&currentTimeClient, &alertNotificationClient}) { serviceDiscovery({&currentTimeClient, &alertNotificationClient, &iaClient}) {
} }
void nimble_on_reset(int reason) { void nimble_on_reset(int reason) {
@ -95,6 +96,7 @@ void NimbleController::Init() {
dfuService.Init(); dfuService.Init();
batteryInformationService.Init(); batteryInformationService.Init();
immediateAlertService.Init(); immediateAlertService.Init();
iaClient.Init();
heartRateService.Init(); heartRateService.Init();
motionService.Init(); motionService.Init();
fsService.Init(); fsService.Init();

View file

@ -17,6 +17,7 @@
#include "components/ble/FSService.h" #include "components/ble/FSService.h"
#include "components/ble/HeartRateService.h" #include "components/ble/HeartRateService.h"
#include "components/ble/ImmediateAlertService.h" #include "components/ble/ImmediateAlertService.h"
#include "components/ble/ImmediateAlertClient.h"
#include "components/ble/MusicService.h" #include "components/ble/MusicService.h"
#include "components/ble/NavigationService.h" #include "components/ble/NavigationService.h"
#include "components/ble/ServiceDiscovery.h" #include "components/ble/ServiceDiscovery.h"
@ -71,6 +72,10 @@ namespace Pinetime {
return weatherService; return weatherService;
}; };
Pinetime::Controllers::ImmediateAlertClient& immediateAlertClient() {
return iaClient;
}
uint16_t connHandle(); uint16_t connHandle();
void NotifyBatteryLevel(uint8_t level); void NotifyBatteryLevel(uint8_t level);
@ -103,6 +108,7 @@ namespace Pinetime {
NavigationService navService; NavigationService navService;
BatteryInformationService batteryInformationService; BatteryInformationService batteryInformationService;
ImmediateAlertService immediateAlertService; ImmediateAlertService immediateAlertService;
ImmediateAlertClient iaClient;
HeartRateService heartRateService; HeartRateService heartRateService;
MotionService motionService; MotionService motionService;
FSService fsService; FSService fsService;

View file

@ -4,7 +4,7 @@
using namespace Pinetime::Controllers; 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) { void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) {
@ -29,4 +29,4 @@ void ServiceDiscovery::DiscoverNextService(uint16_t connectionHandle) {
this->OnServiceDiscovered(connectionHandle); this->OnServiceDiscovered(connectionHandle);
}; };
(*clientIterator)->Discover(connectionHandle, discoverNextService); (*clientIterator)->Discover(connectionHandle, discoverNextService);
} }

View file

@ -9,13 +9,13 @@ namespace Pinetime {
class ServiceDiscovery { class ServiceDiscovery {
public: public:
ServiceDiscovery(std::array<BleClient*, 2>&& bleClients); ServiceDiscovery(std::array<BleClient*, 3>&& bleClients);
void StartDiscovery(uint16_t connectionHandle); void StartDiscovery(uint16_t connectionHandle);
private: private:
BleClient** clientIterator; BleClient** clientIterator;
std::array<BleClient*, 2> clients; std::array<BleClient*, 3> clients;
void OnServiceDiscovered(uint16_t connectionHandle); void OnServiceDiscovered(uint16_t connectionHandle);
void DiscoverNextService(uint16_t connectionHandle); void DiscoverNextService(uint16_t connectionHandle);
}; };

View file

@ -1,6 +1,7 @@
#include "displayapp/DisplayApp.h" #include "displayapp/DisplayApp.h"
#include <libraries/log/nrf_log.h> #include <libraries/log/nrf_log.h>
#include "displayapp/screens/HeartRate.h" #include "displayapp/screens/HeartRate.h"
#include "displayapp/screens/FindMyPhone.h"
#include "displayapp/screens/Motion.h" #include "displayapp/screens/Motion.h"
#include "displayapp/screens/Timer.h" #include "displayapp/screens/Timer.h"
#include "displayapp/screens/Alarm.h" #include "displayapp/screens/Alarm.h"

View file

@ -42,6 +42,7 @@ namespace Pinetime {
SettingChimes, SettingChimes,
SettingShakeThreshold, SettingShakeThreshold,
SettingBluetooth, SettingBluetooth,
FindMyPhone,
Error Error
}; };

View file

@ -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::Dice")
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome") 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::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::Weather")
#set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion") #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") set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware")

View file

@ -7,7 +7,7 @@
}, },
{ {
"file": "FontAwesome5-Solid+Brands+Regular.woff", "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, "bpp": 1,

View 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);
}

View 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());
};
};
}
}

View file

@ -39,6 +39,7 @@ namespace Pinetime {
static constexpr const char* eye = "\xEF\x81\xAE"; static constexpr const char* eye = "\xEF\x81\xAE";
static constexpr const char* home = "\xEF\x80\x95"; static constexpr const char* home = "\xEF\x80\x95";
static constexpr const char* sleep = "\xEE\xBD\x84"; static constexpr const char* sleep = "\xEE\xBD\x84";
static constexpr const char* magnifyingGlass = "\xEF\x80\x82"; // f002
// fontawesome_weathericons.c // fontawesome_weathericons.c
// static constexpr const char* sun = "\xEF\x86\x85"; // static constexpr const char* sun = "\xEF\x86\x85";

@ -1 +0,0 @@
Subproject commit 56b17bf9f74096774944bcac0829adcd887d391e