diff options
Diffstat (limited to 'src/components')
49 files changed, 425 insertions, 177 deletions
diff --git a/src/components/alarm/AlarmController.cpp b/src/components/alarm/AlarmController.cpp index d97e1cff..88f65d9a 100644 --- a/src/components/alarm/AlarmController.cpp +++ b/src/components/alarm/AlarmController.cpp @@ -28,7 +28,7 @@ AlarmController::AlarmController(Controllers::DateTime& dateTimeController) : da namespace { void SetOffAlarm(TimerHandle_t xTimer) { - auto controller = static_cast<Pinetime::Controllers::AlarmController*>(pvTimerGetTimerID(xTimer)); + auto* controller = static_cast<Pinetime::Controllers::AlarmController*>(pvTimerGetTimerID(xTimer)); controller->SetOffAlarmNow(); } } diff --git a/src/components/alarm/AlarmController.h b/src/components/alarm/AlarmController.h index 91f60f5a..8ac0de9a 100644 --- a/src/components/alarm/AlarmController.h +++ b/src/components/alarm/AlarmController.h @@ -26,6 +26,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class AlarmController { public: @@ -40,18 +41,23 @@ namespace Pinetime { void StopAlerting(); enum class AlarmState { Not_Set, Set, Alerting }; enum class RecurType { None, Daily, Weekdays }; + uint8_t Hours() const { return hours; } + uint8_t Minutes() const { return minutes; } + AlarmState State() const { return state; } + RecurType Recurrence() const { return recurrence; } + void SetRecurrence(RecurType recurType) { recurrence = recurType; } diff --git a/src/components/battery/BatteryController.cpp b/src/components/battery/BatteryController.cpp index 300d0978..4d860490 100644 --- a/src/components/battery/BatteryController.cpp +++ b/src/components/battery/BatteryController.cpp @@ -1,4 +1,5 @@ #include "components/battery/BatteryController.h" +#include "components/utility/LinearApproximation.h" #include "drivers/PinMap.h" #include <hal/nrf_gpio.h> #include <nrfx_saadc.h> @@ -15,8 +16,8 @@ Battery::Battery() { } void Battery::ReadPowerState() { - isCharging = !nrf_gpio_pin_read(PinMap::Charging); - isPowerPresent = !nrf_gpio_pin_read(PinMap::PowerPresent); + isCharging = (nrf_gpio_pin_read(PinMap::Charging) == 0); + isPowerPresent = (nrf_gpio_pin_read(PinMap::PowerPresent) == 0); if (isPowerPresent && !isCharging) { isFull = true; @@ -60,8 +61,8 @@ void Battery::SaadcInit() { } void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) { - const uint16_t battery_max = 4180; // maximum voltage of battery ( max charging voltage is 4.21 ) - const uint16_t battery_min = 3200; // minimum voltage of battery before shutdown ( depends on the battery ) + static const Utility::LinearApproximation<uint16_t, uint8_t, 6> approx { + {{{3500, 0}, {3616, 3}, {3723, 22}, {3776, 48}, {3979, 79}, {4180, 100}}}}; if (p_event->type == NRFX_SAADC_EVT_DONE) { @@ -74,19 +75,26 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) { // p_event->data.done.p_buffer[0] = (adc_voltage / reference_voltage) * 1024 voltage = p_event->data.done.p_buffer[0] * (8 * 600) / 1024; - uint8_t newPercent; - if (isFull) { - newPercent = 100; - } else if (voltage < battery_min) { - newPercent = 0; - } else { - newPercent = std::min((voltage - battery_min) * 100 / (battery_max - battery_min), isCharging ? 99 : 100); + uint8_t newPercent = 100; + if (!isFull) { + // max. voltage while charging is higher than when discharging + newPercent = std::min(approx.GetValue(voltage), isCharging ? uint8_t {99} : uint8_t {100}); + } + + if (isPowerPresent) { + batteryLowNotified = false; } if ((isPowerPresent && newPercent > percentRemaining) || (!isPowerPresent && newPercent < percentRemaining) || firstMeasurement) { firstMeasurement = false; percentRemaining = newPercent; systemTask->PushMessage(System::Messages::BatteryPercentageUpdated); + + // warn about low battery when not charging and below threshold + if (BatteryIsLow() && !isPowerPresent && !batteryLowNotified) { + systemTask->PushMessage(System::Messages::LowBattery); + batteryLowNotified = true; + } } nrfx_saadc_uninit(); diff --git a/src/components/battery/BatteryController.h b/src/components/battery/BatteryController.h index 5a7394c4..b47b77cc 100644 --- a/src/components/battery/BatteryController.h +++ b/src/components/battery/BatteryController.h @@ -18,6 +18,10 @@ namespace Pinetime { return percentRemaining; } + bool BatteryIsLow() const { + return percentRemaining <= lowBatteryThreshold; + } + uint16_t Voltage() const { return voltage; } @@ -39,6 +43,7 @@ namespace Pinetime { static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7; uint16_t voltage = 0; uint8_t percentRemaining = 0; + bool batteryLowNotified = false; bool isFull = false; bool isCharging = false; @@ -50,6 +55,8 @@ namespace Pinetime { void SaadcEventHandler(nrfx_saadc_evt_t const* p_event); static void AdcCallbackStatic(nrfx_saadc_evt_t const* event); + static constexpr uint8_t lowBatteryThreshold {15}; + bool isReading = false; Pinetime::System::SystemTask* systemTask = nullptr; diff --git a/src/components/ble/AlertNotificationClient.cpp b/src/components/ble/AlertNotificationClient.cpp index 095fdef6..e3bc9242 100644 --- a/src/components/ble/AlertNotificationClient.cpp +++ b/src/components/ble/AlertNotificationClient.cpp @@ -35,9 +35,9 @@ namespace { return client->OnDescriptorDiscoveryEventCallback(conn_handle, error, chr_val_handle, dsc); } - int NewAlertSubcribeCallback(uint16_t conn_handle, const struct ble_gatt_error* error, struct ble_gatt_attr* attr, void* arg) { + int NewAlertSubcribeCallback(uint16_t conn_handle, const struct ble_gatt_error* error, struct ble_gatt_attr* /*attr*/, void* arg) { auto client = static_cast<AlertNotificationClient*>(arg); - return client->OnNewAlertSubcribe(conn_handle, error, attr); + return client->OnNewAlertSubcribe(conn_handle, error); } } @@ -107,7 +107,7 @@ int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connection return 0; } -int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute) { +int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error) { if (error->status == 0) { NRF_LOG_INFO("ANS New alert subscribe OK"); } else { diff --git a/src/components/ble/AlertNotificationClient.h b/src/components/ble/AlertNotificationClient.h index 2d6a3873..b038f0d8 100644 --- a/src/components/ble/AlertNotificationClient.h +++ b/src/components/ble/AlertNotificationClient.h @@ -25,7 +25,7 @@ namespace Pinetime { bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service); int OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic); - int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute); + int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error); int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error* error, uint16_t characteristicValueHandle, diff --git a/src/components/ble/AlertNotificationService.cpp b/src/components/ble/AlertNotificationService.cpp index 04819122..d9f28698 100644 --- a/src/components/ble/AlertNotificationService.cpp +++ b/src/components/ble/AlertNotificationService.cpp @@ -11,9 +11,9 @@ constexpr ble_uuid16_t AlertNotificationService::ansUuid; constexpr ble_uuid16_t AlertNotificationService::ansCharUuid; constexpr ble_uuid128_t AlertNotificationService::notificationEventUuid; -int AlertNotificationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { +int AlertNotificationCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto anService = static_cast<AlertNotificationService*>(arg); - return anService->OnAlert(conn_handle, attr_handle, ctxt); + return anService->OnAlert(ctxt); } void AlertNotificationService::Init() { @@ -44,7 +44,7 @@ AlertNotificationService::AlertNotificationService(System::SystemTask& systemTas notificationManager {notificationManager} { } -int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int AlertNotificationService::OnAlert(struct ble_gatt_access_ctxt* ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { constexpr size_t stringTerminatorSize = 1; // end of string '\0' constexpr size_t headerSize = 3; diff --git a/src/components/ble/AlertNotificationService.h b/src/components/ble/AlertNotificationService.h index 5c7d428c..4b3c6385 100644 --- a/src/components/ble/AlertNotificationService.h +++ b/src/components/ble/AlertNotificationService.h @@ -16,6 +16,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class NotificationManager; @@ -24,7 +25,7 @@ namespace Pinetime { AlertNotificationService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager); void Init(); - int OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnAlert(struct ble_gatt_access_ctxt* ctxt); void AcceptIncomingCall(); void RejectIncomingCall(); diff --git a/src/components/ble/BatteryInformationService.cpp b/src/components/ble/BatteryInformationService.cpp index 9a3f86f5..db7c8566 100644 --- a/src/components/ble/BatteryInformationService.cpp +++ b/src/components/ble/BatteryInformationService.cpp @@ -7,9 +7,9 @@ using namespace Pinetime::Controllers; constexpr ble_uuid16_t BatteryInformationService::batteryInformationServiceUuid; constexpr ble_uuid16_t BatteryInformationService::batteryLevelUuid; -int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { +int BatteryInformationServiceCallback(uint16_t /*conn_handle*/, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto* batteryInformationService = static_cast<BatteryInformationService*>(arg); - return batteryInformationService->OnBatteryServiceRequested(conn_handle, attr_handle, ctxt); + return batteryInformationService->OnBatteryServiceRequested(attr_handle, ctxt); } BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController) @@ -38,9 +38,7 @@ void BatteryInformationService::Init() { ASSERT(res == 0); } -int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHandle, - uint16_t attributeHandle, - ble_gatt_access_ctxt* context) { +int BatteryInformationService::OnBatteryServiceRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context) { if (attributeHandle == batteryLevelHandle) { NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle); uint8_t batteryValue = batteryController.PercentRemaining(); @@ -49,6 +47,7 @@ int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHand } return 0; } + void BatteryInformationService::NotifyBatteryLevel(uint16_t connectionHandle, uint8_t level) { auto* om = ble_hs_mbuf_from_flat(&level, 1); ble_gattc_notify_custom(connectionHandle, batteryLevelHandle, om); diff --git a/src/components/ble/BatteryInformationService.h b/src/components/ble/BatteryInformationService.h index c6fc52e4..7f0a89ad 100644 --- a/src/components/ble/BatteryInformationService.h +++ b/src/components/ble/BatteryInformationService.h @@ -9,14 +9,16 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class Battery; + class BatteryInformationService { public: BatteryInformationService(Controllers::Battery& batteryController); void Init(); - int OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); + int OnBatteryServiceRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context); void NotifyBatteryLevel(uint16_t connectionHandle, uint8_t level); private: diff --git a/src/components/ble/BleController.h b/src/components/ble/BleController.h index 675ede2d..de0a1bc2 100644 --- a/src/components/ble/BleController.h +++ b/src/components/ble/BleController.h @@ -24,6 +24,7 @@ namespace Pinetime { void StopFirmwareUpdate(); void FirmwareUpdateTotalBytes(uint32_t totalBytes); void FirmwareUpdateCurrentBytes(uint32_t currentBytes); + void State(FirmwareUpdateStates state) { firmwareUpdateState = state; } @@ -31,12 +32,15 @@ namespace Pinetime { bool IsFirmwareUpdating() const { return isFirmwareUpdating; } + uint32_t FirmwareUpdateTotalBytes() const { return firmwareUpdateTotalBytes; } + uint32_t FirmwareUpdateCurrentBytes() const { return firmwareUpdateCurrentBytes; } + FirmwareUpdateStates State() const { return firmwareUpdateState; } @@ -44,15 +48,19 @@ namespace Pinetime { void Address(BleAddress&& addr) { address = addr; } + const BleAddress& Address() const { return address; } + void AddressType(AddressTypes t) { addressType = t; } + void SetPairingKey(uint32_t k) { pairingKey = k; } + uint32_t GetPairingKey() const { return pairingKey; } diff --git a/src/components/ble/CurrentTimeClient.cpp b/src/components/ble/CurrentTimeClient.cpp index 53e98cb6..e535ae83 100644 --- a/src/components/ble/CurrentTimeClient.cpp +++ b/src/components/ble/CurrentTimeClient.cpp @@ -85,21 +85,11 @@ int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_g // TODO check that attribute->handle equals the handle discovered in OnCharacteristicDiscoveryEvent CtsData result; os_mbuf_copydata(attribute->om, 0, sizeof(CtsData), &result); - NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", - result.year, - result.month, - result.dayofmonth, - result.hour, - result.minute, - result.second); - dateTimeController.SetTime(result.year, - result.month, - result.dayofmonth, - 0, - result.hour, - result.minute, - result.second, - nrf_rtc_counter_get(portNRF_RTC_REG)); + uint16_t year = ((uint16_t) result.year_MSO << 8) + result.year_LSO; + + NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", year, result.month, result.dayofmonth, result.hour, result.minute, result.second); + dateTimeController + .SetTime(year, result.month, result.dayofmonth, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG)); } else { NRF_LOG_INFO("Error retrieving current time: %d", error->status); } diff --git a/src/components/ble/CurrentTimeClient.h b/src/components/ble/CurrentTimeClient.h index 9e48be79..0a3a8735 100644 --- a/src/components/ble/CurrentTimeClient.h +++ b/src/components/ble/CurrentTimeClient.h @@ -19,24 +19,29 @@ namespace Pinetime { 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); int OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_attr* attribute); + static constexpr const ble_uuid16_t* Uuid() { return &CurrentTimeClient::ctsServiceUuid; } + static constexpr const ble_uuid16_t* CurrentTimeCharacteristicUuid() { return &CurrentTimeClient::currentTimeCharacteristicUuid; } + void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override; private: typedef struct __attribute__((packed)) { - uint16_t year; + uint8_t year_LSO; // explicit byte ordering to be independent of machine order + uint8_t year_MSO; // BLE GATT is little endian uint8_t month; uint8_t dayofmonth; uint8_t hour; uint8_t minute; uint8_t second; - uint8_t millis; - uint8_t reason; + uint8_t dayofweek; + uint8_t fractions256; // currently ignored + uint8_t reason; // currently ignored, not that any host would set it anyway } CtsData; static constexpr uint16_t ctsServiceId {0x1805}; @@ -55,4 +60,4 @@ namespace Pinetime { std::function<void(uint16_t)> onServiceDiscovered; }; } -}
\ No newline at end of file +} diff --git a/src/components/ble/CurrentTimeService.cpp b/src/components/ble/CurrentTimeService.cpp index 8430d1bc..856bc63a 100644 --- a/src/components/ble/CurrentTimeService.cpp +++ b/src/components/ble/CurrentTimeService.cpp @@ -5,11 +5,23 @@ using namespace Pinetime::Controllers; constexpr ble_uuid16_t CurrentTimeService::ctsUuid; -constexpr ble_uuid16_t CurrentTimeService::ctChrUuid; +constexpr ble_uuid16_t CurrentTimeService::ctsCtChrUuid; +constexpr ble_uuid16_t CurrentTimeService::ctsLtChrUuid; -int CTSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { +int CTSCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto cts = static_cast<CurrentTimeService*>(arg); - return cts->OnTimeAccessed(conn_handle, attr_handle, ctxt); + + return cts->OnCurrentTimeServiceAccessed(ctxt); +} + +int CurrentTimeService::OnCurrentTimeServiceAccessed(struct ble_gatt_access_ctxt* ctxt) { + switch (ble_uuid_u16(ctxt->chr->uuid)) { + case ctsCurrentTimeCharId: + return OnCurrentTimeAccessed(ctxt); + case ctsLocalTimeCharId: + return OnLocalTimeAccessed(ctxt); + } + return -1; // Unknown characteristic } void CurrentTimeService::Init() { @@ -18,45 +30,69 @@ void CurrentTimeService::Init() { ASSERT(res == 0); res = ble_gatts_add_svcs(serviceDefinition); + ASSERT(res == 0); } -int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int CurrentTimeService::OnCurrentTimeAccessed(struct ble_gatt_access_ctxt* ctxt) { NRF_LOG_INFO("Setting time..."); if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { - CtsData result; - os_mbuf_copydata(ctxt->om, 0, sizeof(CtsData), &result); + CtsCurrentTimeData result; + int res = os_mbuf_copydata(ctxt->om, 0, sizeof(CtsCurrentTimeData), &result); + if (res < 0) { + NRF_LOG_ERROR("Error reading BLE Data writing to CTS Current Time (too little data)") + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + + uint16_t year = ((uint16_t) result.year_MSO << 8) + result.year_LSO; - NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", - result.year, - result.month, - result.dayofmonth, - result.hour, - result.minute, - result.second); + NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", year, result.month, result.dayofmonth, result.hour, result.minute, result.second); - m_dateTimeController.SetTime(result.year, - result.month, - result.dayofmonth, - 0, - result.hour, - result.minute, - result.second, - nrf_rtc_counter_get(portNRF_RTC_REG)); + m_dateTimeController + .SetTime(year, result.month, result.dayofmonth, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG)); } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { - CtsData currentDateTime; - currentDateTime.year = m_dateTimeController.Year(); + CtsCurrentTimeData currentDateTime; + currentDateTime.year_LSO = m_dateTimeController.Year() & 0xff; + currentDateTime.year_MSO = (m_dateTimeController.Year() >> 8) & 0xff; currentDateTime.month = static_cast<u_int8_t>(m_dateTimeController.Month()); currentDateTime.dayofmonth = m_dateTimeController.Day(); currentDateTime.hour = m_dateTimeController.Hours(); currentDateTime.minute = m_dateTimeController.Minutes(); currentDateTime.second = m_dateTimeController.Seconds(); - currentDateTime.millis = 0; + currentDateTime.fractions256 = 0; - int res = os_mbuf_append(ctxt->om, ¤tDateTime, sizeof(CtsData)); + int res = os_mbuf_append(ctxt->om, ¤tDateTime, sizeof(CtsCurrentTimeData)); + return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + + return 0; +} + +int CurrentTimeService::OnLocalTimeAccessed(struct ble_gatt_access_ctxt* ctxt) { + NRF_LOG_INFO("Setting timezone..."); + + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + CtsLocalTimeData result; + int res = os_mbuf_copydata(ctxt->om, 0, sizeof(CtsLocalTimeData), &result); + + if (res < 0) { + NRF_LOG_ERROR("Error reading BLE Data writing to CTS Local Time (too little data)") + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + + NRF_LOG_INFO("Received data: %d %d", result.timezone, result.dst); + + m_dateTimeController.SetTimeZone(result.timezone, result.dst); + + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + CtsLocalTimeData currentTimezone; + currentTimezone.timezone = m_dateTimeController.TzOffset(); + currentTimezone.dst = m_dateTimeController.DstOffset(); + + int res = os_mbuf_append(ctxt->om, ¤tTimezone, sizeof(currentTimezone)); return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } @@ -64,12 +100,19 @@ int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handl } CurrentTimeService::CurrentTimeService(DateTime& dateTimeController) - : characteristicDefinition {{.uuid = &ctChrUuid.u, + : characteristicDefinition { + + {.uuid = &ctsLtChrUuid.u, .access_cb = CTSCallback, + .arg = this, + .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}, + {.uuid = &ctsCtChrUuid.u, + .access_cb = CTSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}, - {0}}, + + {0}}, serviceDefinition { {/* Device Information Service */ .type = BLE_GATT_SVC_TYPE_PRIMARY, diff --git a/src/components/ble/CurrentTimeService.h b/src/components/ble/CurrentTimeService.h index ca87d970..bec75a2b 100644 --- a/src/components/ble/CurrentTimeService.h +++ b/src/components/ble/CurrentTimeService.h @@ -16,29 +16,40 @@ namespace Pinetime { CurrentTimeService(DateTime& dateTimeController); void Init(); - int OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnCurrentTimeServiceAccessed(struct ble_gatt_access_ctxt* ctxt); + int OnCurrentTimeAccessed(struct ble_gatt_access_ctxt* ctxt); + int OnLocalTimeAccessed(struct ble_gatt_access_ctxt* ctxt); private: static constexpr uint16_t ctsId {0x1805}; - static constexpr uint16_t ctsCharId {0x2a2b}; + static constexpr uint16_t ctsCurrentTimeCharId {0x2a2b}; + static constexpr uint16_t ctsLocalTimeCharId {0x2a0f}; static constexpr ble_uuid16_t ctsUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsId}; - static constexpr ble_uuid16_t ctChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsCharId}; + static constexpr ble_uuid16_t ctsCtChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsCurrentTimeCharId}; + static constexpr ble_uuid16_t ctsLtChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsLocalTimeCharId}; - struct ble_gatt_chr_def characteristicDefinition[2]; + struct ble_gatt_chr_def characteristicDefinition[3]; struct ble_gatt_svc_def serviceDefinition[2]; typedef struct __attribute__((packed)) { - uint16_t year; + uint8_t year_LSO; // BLE GATT is little endian + uint8_t year_MSO; uint8_t month; uint8_t dayofmonth; uint8_t hour; uint8_t minute; uint8_t second; - uint8_t millis; - uint8_t reason; - } CtsData; + uint8_t dayofweek; + uint8_t fractions256; // currently ignored + uint8_t reason; // currently ignored, not that any host would set it anyway + } CtsCurrentTimeData; + + typedef struct __attribute__((packed)) { + int8_t timezone; + int8_t dst; + } CtsLocalTimeData; DateTime& m_dateTimeController; }; diff --git a/src/components/ble/DeviceInformationService.cpp b/src/components/ble/DeviceInformationService.cpp index 0f47c90f..f0d1b5a7 100644 --- a/src/components/ble/DeviceInformationService.cpp +++ b/src/components/ble/DeviceInformationService.cpp @@ -10,9 +10,9 @@ constexpr ble_uuid16_t DeviceInformationService::deviceInfoUuid; constexpr ble_uuid16_t DeviceInformationService::hwRevisionUuid; constexpr ble_uuid16_t DeviceInformationService::swRevisionUuid; -int DeviceInformationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { +int DeviceInformationCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto deviceInformationService = static_cast<DeviceInformationService*>(arg); - return deviceInformationService->OnDeviceInfoRequested(conn_handle, attr_handle, ctxt); + return deviceInformationService->OnDeviceInfoRequested(ctxt); } void DeviceInformationService::Init() { @@ -24,7 +24,7 @@ void DeviceInformationService::Init() { ASSERT(res == 0); } -int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int DeviceInformationService::OnDeviceInfoRequested(struct ble_gatt_access_ctxt* ctxt) { const char* str; switch (ble_uuid_u16(ctxt->chr->uuid)) { diff --git a/src/components/ble/DeviceInformationService.h b/src/components/ble/DeviceInformationService.h index a269afb4..c4babd1b 100644 --- a/src/components/ble/DeviceInformationService.h +++ b/src/components/ble/DeviceInformationService.h @@ -14,7 +14,7 @@ namespace Pinetime { DeviceInformationService(); void Init(); - int OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnDeviceInfoRequested(struct ble_gatt_access_ctxt* ctxt); private: static constexpr uint16_t deviceInfoId {0x180a}; @@ -50,4 +50,4 @@ namespace Pinetime { struct ble_gatt_svc_def serviceDefinition[2]; }; } -}
\ No newline at end of file +} diff --git a/src/components/ble/DfuService.h b/src/components/ble/DfuService.h index 4708a4a6..b56911b9 100644 --- a/src/components/ble/DfuService.h +++ b/src/components/ble/DfuService.h @@ -13,9 +13,11 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Drivers { class SpiNorFlash; } + namespace Controllers { class Ble; @@ -46,10 +48,12 @@ namespace Pinetime { void OnNotificationTimer(); void Reset(); }; + class DfuImage { public: DfuImage(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash {spiNorFlash} { } + void Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc); void Erase(); void Append(uint8_t* data, size_t size); diff --git a/src/components/ble/FSService.h b/src/components/ble/FSService.h index 828925a8..b2299623 100644 --- a/src/components/ble/FSService.h +++ b/src/components/ble/FSService.h @@ -11,8 +11,10 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class Ble; + class FSService { public: FSService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::FS& fs); @@ -71,6 +73,7 @@ namespace Pinetime { FSState state; char filepath[maxpathlen]; // TODO ..ugh fixed filepath len int fileSize; + using ReadHeader = struct __attribute__((packed)) { commands command; uint8_t padding; @@ -89,6 +92,7 @@ namespace Pinetime { uint32_t chunklen; uint8_t chunk[]; }; + using ReadPacing = struct __attribute__((packed)) { commands command; uint8_t status; @@ -124,6 +128,7 @@ namespace Pinetime { uint32_t dataSize; uint8_t data[]; }; + using ListDirHeader = struct __attribute__((packed)) { commands command; uint8_t padding; @@ -171,6 +176,7 @@ namespace Pinetime { commands command; uint8_t status; }; + using MoveHeader = struct __attribute__((packed)) { commands command; uint8_t padding; diff --git a/src/components/ble/HeartRateService.cpp b/src/components/ble/HeartRateService.cpp index d49a02c8..c522e67e 100644 --- a/src/components/ble/HeartRateService.cpp +++ b/src/components/ble/HeartRateService.cpp @@ -9,9 +9,9 @@ constexpr ble_uuid16_t HeartRateService::heartRateServiceUuid; constexpr ble_uuid16_t HeartRateService::heartRateMeasurementUuid; namespace { - int HeartRateServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { + int HeartRateServiceCallback(uint16_t /*conn_handle*/, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto* heartRateService = static_cast<HeartRateService*>(arg); - return heartRateService->OnHeartRateRequested(conn_handle, attr_handle, ctxt); + return heartRateService->OnHeartRateRequested(attr_handle, ctxt); } } @@ -45,7 +45,7 @@ void HeartRateService::Init() { ASSERT(res == 0); } -int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) { +int HeartRateService::OnHeartRateRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context) { if (attributeHandle == heartRateMeasurementHandle) { NRF_LOG_INFO("HEARTRATE : handle = %d", heartRateMeasurementHandle); uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value @@ -60,7 +60,7 @@ void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) { if (!heartRateMeasurementNotificationEnable) return; - uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value + uint8_t buffer[2] = {0, heartRateValue}; // [0] = flags, [1] = hr value auto* om = ble_hs_mbuf_from_flat(buffer, 2); uint16_t connectionHandle = system.nimble().connHandle(); @@ -72,12 +72,12 @@ void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) { ble_gattc_notify_custom(connectionHandle, heartRateMeasurementHandle, om); } -void HeartRateService::SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) { +void HeartRateService::SubscribeNotification(uint16_t attributeHandle) { if (attributeHandle == heartRateMeasurementHandle) heartRateMeasurementNotificationEnable = true; } -void HeartRateService::UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) { +void HeartRateService::UnsubscribeNotification(uint16_t attributeHandle) { if (attributeHandle == heartRateMeasurementHandle) heartRateMeasurementNotificationEnable = false; -}
\ No newline at end of file +} diff --git a/src/components/ble/HeartRateService.h b/src/components/ble/HeartRateService.h index 4e4a5a42..003bdbd1 100644 --- a/src/components/ble/HeartRateService.h +++ b/src/components/ble/HeartRateService.h @@ -10,17 +10,19 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class HeartRateController; + class HeartRateService { public: HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController); void Init(); - int OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); + int OnHeartRateRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context); void OnNewHeartRateValue(uint8_t hearRateValue); - void SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle); - void UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle); + void SubscribeNotification(uint16_t attributeHandle); + void UnsubscribeNotification(uint16_t attributeHandle); private: Pinetime::System::SystemTask& system; diff --git a/src/components/ble/ImmediateAlertService.cpp b/src/components/ble/ImmediateAlertService.cpp index c80b3783..b9de615a 100644 --- a/src/components/ble/ImmediateAlertService.cpp +++ b/src/components/ble/ImmediateAlertService.cpp @@ -9,9 +9,9 @@ constexpr ble_uuid16_t ImmediateAlertService::immediateAlertServiceUuid; constexpr ble_uuid16_t ImmediateAlertService::alertLevelUuid; namespace { - int AlertLevelCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { + int AlertLevelCallback(uint16_t /*conn_handle*/, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto* immediateAlertService = static_cast<ImmediateAlertService*>(arg); - return immediateAlertService->OnAlertLevelChanged(conn_handle, attr_handle, ctxt); + return immediateAlertService->OnAlertLevelChanged(attr_handle, ctxt); } const char* ToString(ImmediateAlertService::Levels level) { @@ -56,7 +56,7 @@ void ImmediateAlertService::Init() { ASSERT(res == 0); } -int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) { +int ImmediateAlertService::OnAlertLevelChanged(uint16_t attributeHandle, ble_gatt_access_ctxt* context) { if (attributeHandle == alertLevelHandle) { if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { auto alertLevel = static_cast<Levels>(context->om->om_data[0]); diff --git a/src/components/ble/ImmediateAlertService.h b/src/components/ble/ImmediateAlertService.h index 1f778acd..47a05439 100644 --- a/src/components/ble/ImmediateAlertService.h +++ b/src/components/ble/ImmediateAlertService.h @@ -9,15 +9,17 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class NotificationManager; + class ImmediateAlertService { public: enum class Levels : uint8_t { NoAlert = 0, MildAlert = 1, HighAlert = 2 }; ImmediateAlertService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager); void Init(); - int OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); + int OnAlertLevelChanged(uint16_t attributeHandle, ble_gatt_access_ctxt* context); private: Pinetime::System::SystemTask& systemTask; diff --git a/src/components/ble/MotionService.cpp b/src/components/ble/MotionService.cpp index 121ad3b0..604f22d5 100644 --- a/src/components/ble/MotionService.cpp +++ b/src/components/ble/MotionService.cpp @@ -21,9 +21,9 @@ namespace { constexpr ble_uuid128_t stepCountCharUuid {CharUuid(0x01, 0x00)}; constexpr ble_uuid128_t motionValuesCharUuid {CharUuid(0x02, 0x00)}; - int MotionServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { + int MotionServiceCallback(uint16_t /*conn_handle*/, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto* motionService = static_cast<MotionService*>(arg); - return motionService->OnStepCountRequested(conn_handle, attr_handle, ctxt); + return motionService->OnStepCountRequested(attr_handle, ctxt); } } @@ -59,7 +59,7 @@ void MotionService::Init() { ASSERT(res == 0); } -int MotionService::OnStepCountRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) { +int MotionService::OnStepCountRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context) { if (attributeHandle == stepCountHandle) { NRF_LOG_INFO("Motion-stepcount : handle = %d", stepCountHandle); uint32_t buffer = motionController.NbSteps(); @@ -90,11 +90,12 @@ void MotionService::OnNewStepCountValue(uint32_t stepCount) { ble_gattc_notify_custom(connectionHandle, stepCountHandle, om); } + void MotionService::OnNewMotionValues(int16_t x, int16_t y, int16_t z) { if (!motionValuesNoficationEnabled) return; - int16_t buffer[3] = {motionController.X(), motionController.Y(), motionController.Z()}; + int16_t buffer[3] = {x, y, z}; auto* om = ble_hs_mbuf_from_flat(buffer, 3 * sizeof(int16_t)); uint16_t connectionHandle = system.nimble().connHandle(); @@ -106,14 +107,14 @@ void MotionService::OnNewMotionValues(int16_t x, int16_t y, int16_t z) { ble_gattc_notify_custom(connectionHandle, motionValuesHandle, om); } -void MotionService::SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) { +void MotionService::SubscribeNotification(uint16_t attributeHandle) { if (attributeHandle == stepCountHandle) stepCountNoficationEnabled = true; else if (attributeHandle == motionValuesHandle) motionValuesNoficationEnabled = true; } -void MotionService::UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) { +void MotionService::UnsubscribeNotification(uint16_t attributeHandle) { if (attributeHandle == stepCountHandle) stepCountNoficationEnabled = false; else if (attributeHandle == motionValuesHandle) diff --git a/src/components/ble/MotionService.h b/src/components/ble/MotionService.h index 1b4ac0a3..1b172528 100644 --- a/src/components/ble/MotionService.h +++ b/src/components/ble/MotionService.h @@ -10,18 +10,20 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class MotionController; + class MotionService { public: MotionService(Pinetime::System::SystemTask& system, Controllers::MotionController& motionController); void Init(); - int OnStepCountRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); + int OnStepCountRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context); void OnNewStepCountValue(uint32_t stepCount); void OnNewMotionValues(int16_t x, int16_t y, int16_t z); - void SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle); - void UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle); + void SubscribeNotification(uint16_t attributeHandle); + void UnsubscribeNotification(uint16_t attributeHandle); private: Pinetime::System::SystemTask& system; diff --git a/src/components/ble/MusicService.cpp b/src/components/ble/MusicService.cpp index fc7cef01..403c957b 100644 --- a/src/components/ble/MusicService.cpp +++ b/src/components/ble/MusicService.cpp @@ -48,8 +48,8 @@ namespace { constexpr uint8_t MaxStringSize {40}; - int MusicCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { - return static_cast<Pinetime::Controllers::MusicService*>(arg)->OnCommand(conn_handle, attr_handle, ctxt); + int MusicCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { + return static_cast<Pinetime::Controllers::MusicService*>(arg)->OnCommand(ctxt); } } @@ -122,7 +122,7 @@ void Pinetime::Controllers::MusicService::Init() { ASSERT(res == 0); } -int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int Pinetime::Controllers::MusicService::OnCommand(struct ble_gatt_access_ctxt* ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { size_t notifSize = OS_MBUF_PKTLEN(ctxt->om); size_t bufferSize = notifSize; diff --git a/src/components/ble/MusicService.h b/src/components/ble/MusicService.h index 047d0d26..6aebc3c5 100644 --- a/src/components/ble/MusicService.h +++ b/src/components/ble/MusicService.h @@ -30,6 +30,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class MusicService { public: @@ -37,7 +38,7 @@ namespace Pinetime { void Init(); - int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnCommand(struct ble_gatt_access_ctxt* ctxt); void event(char event); diff --git a/src/components/ble/NavigationService.cpp b/src/components/ble/NavigationService.cpp index 76143686..5508d08c 100644 --- a/src/components/ble/NavigationService.cpp +++ b/src/components/ble/NavigationService.cpp @@ -39,9 +39,9 @@ namespace { constexpr ble_uuid128_t navManDistCharUuid {CharUuid(0x03, 0x00)}; constexpr ble_uuid128_t navProgressCharUuid {CharUuid(0x04, 0x00)}; - int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { - auto navService = static_cast<Pinetime::Controllers::NavigationService*>(arg); - return navService->OnCommand(conn_handle, attr_handle, ctxt); + int NAVCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { + auto* navService = static_cast<Pinetime::Controllers::NavigationService*>(arg); + return navService->OnCommand(ctxt); } } // namespace @@ -81,7 +81,7 @@ void Pinetime::Controllers::NavigationService::Init() { ASSERT(res == 0); } -int Pinetime::Controllers::NavigationService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int Pinetime::Controllers::NavigationService::OnCommand(struct ble_gatt_access_ctxt* ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { size_t notifSize = OS_MBUF_PKTLEN(ctxt->om); diff --git a/src/components/ble/NavigationService.h b/src/components/ble/NavigationService.h index c0c77f35..1c1739ba 100644 --- a/src/components/ble/NavigationService.h +++ b/src/components/ble/NavigationService.h @@ -30,6 +30,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class NavigationService { @@ -38,7 +39,7 @@ namespace Pinetime { void Init(); - int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnCommand(struct ble_gatt_access_ctxt* ctxt); std::string getFlag(); diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp index 52f4e4ce..912f5927 100644 --- a/src/components/ble/NimbleController.cpp +++ b/src/components/ble/NimbleController.cpp @@ -322,14 +322,14 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { event->subscribe.prev_indicate); if (event->subscribe.reason == BLE_GAP_SUBSCRIBE_REASON_TERM) { - heartRateService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); - motionService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); + heartRateService.UnsubscribeNotification(event->subscribe.attr_handle); + motionService.UnsubscribeNotification(event->subscribe.attr_handle); } else if (event->subscribe.prev_notify == 0 && event->subscribe.cur_notify == 1) { - heartRateService.SubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); - motionService.SubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); + heartRateService.SubscribeNotification(event->subscribe.attr_handle); + motionService.SubscribeNotification(event->subscribe.attr_handle); } else if (event->subscribe.prev_notify == 1 && event->subscribe.cur_notify == 0) { - heartRateService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); - motionService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); + heartRateService.UnsubscribeNotification(event->subscribe.attr_handle); + motionService.UnsubscribeNotification(event->subscribe.attr_handle); } break; diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h index 000231fe..8f1dfed7 100644 --- a/src/components/ble/NimbleController.h +++ b/src/components/ble/NimbleController.h @@ -58,12 +58,15 @@ namespace Pinetime { Pinetime::Controllers::MusicService& music() { return musicService; }; + Pinetime::Controllers::NavigationService& navigation() { return navService; }; + Pinetime::Controllers::AlertNotificationService& alertService() { return anService; }; + Pinetime::Controllers::WeatherService& weather() { return weatherService; }; diff --git a/src/components/ble/NotificationManager.h b/src/components/ble/NotificationManager.h index 4c199dbf..09b5a561 100644 --- a/src/components/ble/NotificationManager.h +++ b/src/components/ble/NotificationManager.h @@ -51,9 +51,11 @@ namespace Pinetime { static constexpr size_t MaximumMessageSize() { return MessageSize; }; + bool IsEmpty() const { return size == 0; } + size_t NbNotifications() const; private: diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index 23f53b74..e606d9bf 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -20,8 +20,8 @@ #include "libs/QCBOR/inc/qcbor/qcbor.h" #include "systemtask/SystemTask.h" -int WeatherCallback(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt, void* arg) { - return static_cast<Pinetime::Controllers::WeatherService*>(arg)->OnCommand(connHandle, attrHandle, ctxt); +int WeatherCallback(uint16_t /*connHandle*/, uint16_t /*attrHandle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { + return static_cast<Pinetime::Controllers::WeatherService*>(arg)->OnCommand(ctxt); } namespace Pinetime { @@ -41,7 +41,7 @@ namespace Pinetime { ASSERT(res == 0); } - int WeatherService::OnCommand(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt) { + int WeatherService::OnCommand(struct ble_gatt_access_ctxt* ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { const uint8_t packetLen = OS_MBUF_PKTLEN(ctxt->om); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) if (packetLen <= 0) { @@ -552,11 +552,12 @@ namespace Pinetime { int16_t WeatherService::GetTodayMinTemp() const { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - uint64_t currentDayEnd = currentTimestamp - ((24 - dateTimeController.Hours()) * 60 * 60) - - ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds()); + uint64_t currentDayEnd = currentTimestamp + ((24 - dateTimeController.Hours()) * 60 * 60) + + ((60 - dateTimeController.Minutes()) * 60) + (60 - dateTimeController.Seconds()); + uint64_t currentDayStart = currentDayEnd - 86400; int16_t result = -32768; for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Temperature && IsEventStillValid(header, currentTimestamp) && + if (header->eventType == WeatherData::eventtype::Temperature && header->timestamp >= currentDayStart && header->timestamp < currentDayEnd && reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature != -32768) { int16_t temperature = reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature; @@ -575,11 +576,12 @@ namespace Pinetime { int16_t WeatherService::GetTodayMaxTemp() const { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - uint64_t currentDayEnd = currentTimestamp - ((24 - dateTimeController.Hours()) * 60 * 60) - - ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds()); + uint64_t currentDayEnd = currentTimestamp + ((24 - dateTimeController.Hours()) * 60 * 60) + + ((60 - dateTimeController.Minutes()) * 60) + (60 - dateTimeController.Seconds()); + uint64_t currentDayStart = currentDayEnd - 86400; int16_t result = -32768; for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Temperature && IsEventStillValid(header, currentTimestamp) && + if (header->eventType == WeatherData::eventtype::Temperature && header->timestamp >= currentDayStart && header->timestamp < currentDayEnd && reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature != -32768) { int16_t temperature = reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature; diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h index e37417da..00650e90 100644 --- a/src/components/ble/weather/WeatherService.h +++ b/src/components/ble/weather/WeatherService.h @@ -39,6 +39,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class WeatherService { @@ -47,7 +48,7 @@ namespace Pinetime { void Init(); - int OnCommand(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt); + int OnCommand(struct ble_gatt_access_ctxt* ctxt); /* * Helper functions for quick access to currently valid data diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp index 4dc16329..b744fbb2 100644 --- a/src/components/datetime/DateTimeController.cpp +++ b/src/components/datetime/DateTimeController.cpp @@ -20,14 +20,7 @@ void DateTime::SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, UpdateTime(previousSystickCounter); // Update internal state without updating the time } -void DateTime::SetTime(uint16_t year, - uint8_t month, - uint8_t day, - uint8_t dayOfWeek, - uint8_t hour, - uint8_t minute, - uint8_t second, - uint32_t systickCounter) { +void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter) { std::tm tm = { /* .tm_sec = */ second, /* .tm_min = */ minute, @@ -36,6 +29,7 @@ void DateTime::SetTime(uint16_t year, /* .tm_mon = */ month - 1, /* .tm_year = */ year - 1900, }; + tm.tm_isdst = -1; // Use DST value from local time zone currentDateTime = std::chrono::system_clock::from_time_t(std::mktime(&tm)); @@ -50,6 +44,11 @@ void DateTime::SetTime(uint16_t year, systemTask->PushMessage(System::Messages::OnNewTime); } +void DateTime::SetTimeZone(int8_t timezone, int8_t dst) { + tzOffset = timezone; + dstOffset = dst; +} + void DateTime::UpdateTime(uint32_t systickCounter) { // Handle systick counter overflow uint32_t systickDelta = 0; @@ -136,6 +135,7 @@ void DateTime::Register(Pinetime::System::SystemTask* systemTask) { } using ClockType = Pinetime::Controllers::Settings::ClockType; + std::string DateTime::FormattedTime() { // Return time as a string in 12- or 24-hour format char buff[9]; diff --git a/src/components/datetime/DateTimeController.h b/src/components/datetime/DateTimeController.h index 81319d15..74ccf4da 100644 --- a/src/components/datetime/DateTimeController.h +++ b/src/components/datetime/DateTimeController.h @@ -9,6 +9,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class DateTime { public: @@ -30,37 +31,85 @@ namespace Pinetime { December }; - void SetTime(uint16_t year, - uint8_t month, - uint8_t day, - uint8_t dayOfWeek, - uint8_t hour, - uint8_t minute, - uint8_t second, - uint32_t systickCounter); + void SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter); + + /* + * setter corresponding to the BLE Set Local Time characteristic. + * + * used to update difference between utc and local time (see UtcOffset()) + * + * parameters are in quarters of an our. Following the BLE CTS specification, + * timezone is expected to be constant over DST which will be reported in + * dst field. + */ + void SetTimeZone(int8_t timezone, int8_t dst); + void UpdateTime(uint32_t systickCounter); + uint16_t Year() const { return year; } + Months Month() const { return month; } + uint8_t Day() const { return day; } + Days DayOfWeek() const { return dayOfWeek; } + uint8_t Hours() const { return hour; } + uint8_t Minutes() const { return minute; } + uint8_t Seconds() const { return second; } + /* + * returns the offset between local time and UTC in quarters of an hour + * + * Availability of this field depends on wether the companion app + * supports the BLE CTS Local Time Characteristic. Expect it to be 0 + * if not. + */ + int8_t UtcOffset() const { + return tzOffset + dstOffset; + } + + /* + * returns the offset between the (dst independent) local time zone and UTC + * in quarters of an hour + * + * Availability of this field depends on wether the companion app + * supports the BLE CTS Local Time Characteristic. Expect it to be 0 + * if not. + */ + int8_t TzOffset() const { + return tzOffset; + } + + /* + * returns the offset between the local time zone and local time + * in quarters of an hour + * if != 0, DST is in effect, if == 0 not. + * + * Availability of this field depends on wether the companion app + * supports the BLE CTS Local Time Characteristic. Expect it to be 0 + * if not. + */ + int8_t DstOffset() const { + return dstOffset; + } + const char* MonthShortToString() const; const char* DayOfWeekShortToString() const; static const char* MonthShortToStringLow(Months month); @@ -69,6 +118,11 @@ namespace Pinetime { std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const { return currentDateTime; } + + std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> UTCDateTime() const { + return currentDateTime - std::chrono::seconds((tzOffset + dstOffset) * 15 * 60); + } + std::chrono::seconds Uptime() const { return uptime; } @@ -85,6 +139,8 @@ namespace Pinetime { uint8_t hour = 0; uint8_t minute = 0; uint8_t second = 0; + int8_t tzOffset = 0; + int8_t dstOffset = 0; uint32_t previousSystickCounter = 0; std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> currentDateTime; diff --git a/src/components/fs/FS.cpp b/src/components/fs/FS.cpp index 14b05525..0bb59afa 100644 --- a/src/components/fs/FS.cpp +++ b/src/components/fs/FS.cpp @@ -89,18 +89,23 @@ int FS::DirClose(lfs_dir_t* lfs_dir) { int FS::DirRead(lfs_dir_t* dir, lfs_info* info) { return lfs_dir_read(&lfs, dir, info); } + int FS::DirRewind(lfs_dir_t* dir) { return lfs_dir_rewind(&lfs, dir); } + int FS::DirCreate(const char* path) { return lfs_mkdir(&lfs, path); } + int FS::Rename(const char* oldPath, const char* newPath) { return lfs_rename(&lfs, oldPath, newPath); } + int FS::Stat(const char* path, lfs_info* info) { return lfs_stat(&lfs, path, info); } + lfs_ssize_t FS::GetFSSize() { return lfs_fs_size(&lfs); } @@ -110,7 +115,7 @@ lfs_ssize_t FS::GetFSSize() { ----------- Interface between littlefs and SpiNorFlash ----------- */ -int FS::SectorSync(const struct lfs_config* c) { +int FS::SectorSync(const struct lfs_config* /*c*/) { return 0; } @@ -142,7 +147,7 @@ int FS::SectorRead(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, */ namespace { - lv_fs_res_t lvglOpen(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode) { + lv_fs_res_t lvglOpen(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t /*mode*/) { lfs_file_t* file = static_cast<lfs_file_t*>(file_p); FS* filesys = static_cast<FS*>(drv->user_data); int res = filesys->FileOpen(file, path, LFS_O_RDONLY); @@ -195,4 +200,4 @@ void FS::LVGLFileSystemInit() { fs_drv.user_data = this; lv_fs_drv_register(&fs_drv); -}
\ No newline at end of file +} diff --git a/src/components/fs/FS.h b/src/components/fs/FS.h index 87fcdc23..9730e474 100644 --- a/src/components/fs/FS.h +++ b/src/components/fs/FS.h @@ -35,6 +35,7 @@ namespace Pinetime { static size_t getSize() { return size; } + static size_t getBlockSize() { return blockSize; } diff --git a/src/components/gfx/Gfx.h b/src/components/gfx/Gfx.h index 54c4a8b7..17c248f7 100644 --- a/src/components/gfx/Gfx.h +++ b/src/components/gfx/Gfx.h @@ -10,6 +10,7 @@ namespace Pinetime { namespace Drivers { class St7789; } + namespace Components { class Gfx : public Pinetime::Drivers::BufferProvider { public: @@ -33,9 +34,11 @@ namespace Pinetime { static constexpr uint8_t height = 240; enum class Action { None, FillRectangle, DrawChar }; + struct State { State() : busy {false}, action {Action::None}, remainingIterations {0}, currentIteration {0} { } + volatile bool busy; volatile Action action; volatile uint16_t remainingIterations; diff --git a/src/components/heartrate/HeartRateController.h b/src/components/heartrate/HeartRateController.h index a63f1a70..f66c79f8 100644 --- a/src/components/heartrate/HeartRateController.h +++ b/src/components/heartrate/HeartRateController.h @@ -7,9 +7,11 @@ namespace Pinetime { namespace Applications { class HeartRateTask; } + namespace System { class SystemTask; } + namespace Controllers { class HeartRateController { public: @@ -21,9 +23,11 @@ namespace Pinetime { void Update(States newState, uint8_t heartRate); void SetHeartRateTask(Applications::HeartRateTask* task); + States State() const { return state; } + uint8_t HeartRate() const { return heartRate; } diff --git a/src/components/heartrate/Ppg.cpp b/src/components/heartrate/Ppg.cpp index a5d83696..900b1c22 100644 --- a/src/components/heartrate/Ppg.cpp +++ b/src/components/heartrate/Ppg.cpp @@ -29,8 +29,9 @@ namespace { auto z1 = CompareShift(d, mn - 1, size); for (int i = mn; i < mx + 1; i++) { auto z = CompareShift(d, i, size); - if (z2 > z1 && z1 < z) + if (z2 > z1 && z1 < z) { return i; + } z2 = z1; z1 = z; } @@ -52,41 +53,48 @@ int8_t Ppg::Preprocess(float spl) { auto spl_int = static_cast<int8_t>(spl); - if (dataIndex < 200) + if (dataIndex < 200) { data[dataIndex++] = spl_int; + } return spl_int; } -float Ppg::HeartRate() { - if (dataIndex < 200) +int Ppg::HeartRate() { + if (dataIndex < 200) { return 0; + } NRF_LOG_INFO("PREPROCESS, offset = %d", offset); auto hr = ProcessHeartRate(); dataIndex = 0; return hr; } -float Ppg::ProcessHeartRate() { - auto t0 = Trough(data.data(), dataIndex, 7, 48); - if (t0 < 0) + +int Ppg::ProcessHeartRate() { + int t0 = Trough(data.data(), dataIndex, 7, 48); + if (t0 < 0) { return 0; + } - float t1 = t0 * 2; + int t1 = t0 * 2; t1 = Trough(data.data(), dataIndex, t1 - 5, t1 + 5); - if (t1 < 0) + if (t1 < 0) { return 0; + } - float t2 = static_cast<int>(t1 * 3) / 2; + int t2 = (t1 * 3) / 2; t2 = Trough(data.data(), dataIndex, t2 - 5, t2 + 5); - if (t2 < 0) + if (t2 < 0) { return 0; + } - float t3 = static_cast<int>(t2 * 4) / 3; + int t3 = (t2 * 4) / 3; t3 = Trough(data.data(), dataIndex, t3 - 4, t3 + 4); - if (t3 < 0) - return static_cast<int>(60 * 24 * 3) / static_cast<int>(t2); + if (t3 < 0) { + return (60 * 24 * 3) / t2; + } - return static_cast<int>(60 * 24 * 4) / static_cast<int>(t3); + return (60 * 24 * 4) / t3; } void Ppg::SetOffset(uint16_t offset) { diff --git a/src/components/heartrate/Ppg.h b/src/components/heartrate/Ppg.h index 7000c871..1f709bab 100644 --- a/src/components/heartrate/Ppg.h +++ b/src/components/heartrate/Ppg.h @@ -12,9 +12,9 @@ namespace Pinetime { public: Ppg(); int8_t Preprocess(float spl); - float HeartRate(); + int HeartRate(); - void SetOffset(uint16_t i); + void SetOffset(uint16_t offset); void Reset(); private: @@ -25,7 +25,7 @@ namespace Pinetime { Ptagc agc; Biquad lpf; - float ProcessHeartRate(); + int ProcessHeartRate(); }; } } diff --git a/src/components/heartrate/Ptagc.cpp b/src/components/heartrate/Ptagc.cpp index 1c60bc23..221be460 100644 --- a/src/components/heartrate/Ptagc.cpp +++ b/src/components/heartrate/Ptagc.cpp @@ -14,13 +14,15 @@ Ptagc::Ptagc(float start, float decay, float threshold) : peak {start}, decay {d } float Ptagc::Step(float spl) { - if (std::abs(spl) > peak) + if (std::abs(spl) > peak) { peak *= boost; - else + } else { peak *= decay; + } - if ((spl > (peak * threshold)) || (spl < (peak * -threshold))) + if ((spl > (peak * threshold)) || (spl < (peak * -threshold))) { return 0.0f; + } spl = 100.0f * spl / (2.0f * peak); return spl; diff --git a/src/components/motion/MotionController.cpp b/src/components/motion/MotionController.cpp index 7dd32127..8ba46814 100644 --- a/src/components/motion/MotionController.cpp +++ b/src/components/motion/MotionController.cpp @@ -26,10 +26,9 @@ bool MotionController::Should_RaiseWake(bool isSleeping) { if (not isSleeping) { if (y <= 0) { return false; - } else { - lastYForWakeUp = 0; - return false; } + lastYForWakeUp = 0; + return false; } if (y >= 0) { @@ -62,6 +61,7 @@ bool MotionController::Should_ShakeWake(uint16_t thresh) { lastZForShake = z; return wake; } + int32_t MotionController::currentShakeSpeed() { return accumulatedspeed; } @@ -69,6 +69,7 @@ int32_t MotionController::currentShakeSpeed() { void MotionController::IsSensorOk(bool isOk) { isSensorOk = isOk; } + void MotionController::Init(Pinetime::Drivers::Bma421::DeviceTypes types) { switch (types) { case Drivers::Bma421::DeviceTypes::BMA421: @@ -82,6 +83,7 @@ void MotionController::Init(Pinetime::Drivers::Bma421::DeviceTypes types) { break; } } + void MotionController::SetService(Pinetime::Controllers::MotionService* service) { this->service = service; } diff --git a/src/components/motion/MotionController.h b/src/components/motion/MotionController.h index f80b11b9..857bd45a 100644 --- a/src/components/motion/MotionController.h +++ b/src/components/motion/MotionController.h @@ -19,12 +19,15 @@ namespace Pinetime { int16_t X() const { return x; } + int16_t Y() const { return y; } + int16_t Z() const { return z; } + uint32_t NbSteps() const { return nbSteps; } @@ -32,6 +35,7 @@ namespace Pinetime { void ResetTrip() { currentTripSteps = 0; } + uint32_t GetTripSteps() const { return currentTripSteps; } @@ -40,6 +44,7 @@ namespace Pinetime { bool Should_RaiseWake(bool isSleeping); int32_t currentShakeSpeed(); void IsSensorOk(bool isOk); + bool IsSensorOk() const { return isSensorOk; } diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index db6103f4..4e392416 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -34,6 +34,6 @@ void MotorController::StopRinging() { nrf_gpio_pin_set(PinMap::Motor); } -void MotorController::StopMotor(TimerHandle_t xTimer) { +void MotorController::StopMotor(TimerHandle_t /*xTimer*/) { nrf_gpio_pin_set(PinMap::Motor); } diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 93f861f3..d1e71656 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -45,6 +45,7 @@ namespace Pinetime { Colors ColorBG = Colors::Black; PTSGaugeStyle gaugeStyle = PTSGaugeStyle::Full; }; + struct WatchFaceInfineat { bool showSideCover = true; int colorIndex = 0; @@ -66,6 +67,7 @@ namespace Pinetime { } settings.clockFace = face; }; + uint8_t GetClockFace() const { return settings.clockFace; }; @@ -76,6 +78,7 @@ namespace Pinetime { } settings.chimesOption = chimeOption; }; + ChimesOption GetChimeOption() const { return settings.chimesOption; }; @@ -85,6 +88,7 @@ namespace Pinetime { settingsChanged = true; settings.PTS.ColorTime = colorTime; }; + Colors GetPTSColorTime() const { return settings.PTS.ColorTime; }; @@ -94,6 +98,7 @@ namespace Pinetime { settingsChanged = true; settings.PTS.ColorBar = colorBar; }; + Colors GetPTSColorBar() const { return settings.PTS.ColorBar; }; @@ -103,6 +108,7 @@ namespace Pinetime { settingsChanged = true; settings.PTS.ColorBG = colorBG; }; + Colors GetPTSColorBG() const { return settings.PTS.ColorBG; }; @@ -113,6 +119,7 @@ namespace Pinetime { settingsChanged = true; } }; + bool GetInfineatShowSideCover() const { return settings.watchFaceInfineat.showSideCover; }; @@ -123,6 +130,7 @@ namespace Pinetime { settingsChanged = true; } }; + int GetInfineatColorIndex() const { return settings.watchFaceInfineat.colorIndex; }; @@ -132,6 +140,7 @@ namespace Pinetime { settingsChanged = true; settings.PTS.gaugeStyle = gaugeStyle; }; + PTSGaugeStyle GetPTSGaugeStyle() const { return settings.PTS.gaugeStyle; }; @@ -147,6 +156,7 @@ namespace Pinetime { void SetSettingsMenu(uint8_t menu) { settingsMenu = menu; }; + uint8_t GetSettingsMenu() const { return settingsMenu; }; @@ -157,6 +167,7 @@ namespace Pinetime { } settings.clockType = clocktype; }; + ClockType GetClockType() const { return settings.clockType; }; @@ -167,6 +178,7 @@ namespace Pinetime { } settings.notificationStatus = status; }; + Notification GetNotificationStatus() const { return settings.notificationStatus; }; @@ -255,6 +267,7 @@ namespace Pinetime { Pinetime::Controllers::FS& fs; static constexpr uint32_t settingsVersion = 0x0004; + struct SettingsData { uint32_t version = settingsVersion; uint32_t stepsGoal = 10000; diff --git a/src/components/timer/TimerController.h b/src/components/timer/TimerController.h index 93d8afc6..20f07e82 100644 --- a/src/components/timer/TimerController.h +++ b/src/components/timer/TimerController.h @@ -7,6 +7,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class TimerController { diff --git a/src/components/utility/LinearApproximation.h b/src/components/utility/LinearApproximation.h new file mode 100644 index 00000000..f7104ced --- /dev/null +++ b/src/components/utility/LinearApproximation.h @@ -0,0 +1,41 @@ +#pragma once + +#include <cstddef> +#include <array> + +namespace Pinetime { + namespace Utility { + + // based on: https://github.com/SHristov92/LinearApproximation/blob/main/Linear.h + template <typename Key, typename Value, std::size_t Size> class LinearApproximation { + using Point = struct { + Key key; + Value value; + }; + + public: + LinearApproximation(const std::array<Point, Size>&& sorted_points) : points {sorted_points} { + } + + Value GetValue(Key key) const { + if (key <= points[0].key) { + return points[0].value; + } + + for (std::size_t i = 1; i < Size; i++) { + const auto& p = points[i]; + const auto& p_prev = points[i - 1]; + + if (key < p.key) { + return p_prev.value + (key - p_prev.key) * (p.value - p_prev.value) / (p.key - p_prev.key); + } + } + + return points[Size - 1].value; + } + + private: + std::array<Point, Size> points; + }; + } +} |
