mirror of
https://github.com/InfiniTimeOrg/InfiniTime.git
synced 2024-10-22 15:11:51 +02:00
Compare commits
10 commits
f9dd8f1f07
...
c79fb7d693
Author | SHA1 | Date | |
---|---|---|---|
c79fb7d693 | |||
8598142c27 | |||
299edca193 | |||
8e29d82985 | |||
0e76bf1766 | |||
15daf4cb84 | |||
4aef5a9f4d | |||
145b45c501 | |||
96b171524f | |||
0e1a074720 |
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -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
3
.gitmodules
vendored
|
@ -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
|
||||||
|
|
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)
|
- [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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
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},
|
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({¤tTimeClient, &alertNotificationClient}) {
|
serviceDiscovery({¤tTimeClient, &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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -42,6 +42,7 @@ namespace Pinetime {
|
||||||
SettingChimes,
|
SettingChimes,
|
||||||
SettingShakeThreshold,
|
SettingShakeThreshold,
|
||||||
SettingBluetooth,
|
SettingBluetooth,
|
||||||
|
FindMyPhone,
|
||||||
Error
|
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::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")
|
||||||
|
|
|
@ -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,
|
||||||
|
|
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* 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
|
|
Loading…
Reference in a new issue