Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/develop' into pts-settings
Browse files Browse the repository at this point in the history
  • Loading branch information
kieranc committed Nov 7, 2021
2 parents 85d494a + 4a5b5f9 commit 18e3cc7
Show file tree
Hide file tree
Showing 26 changed files with 516 additions and 63 deletions.
2 changes: 2 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Checks: '*,
-altera-unroll-loops,
-llvmlibc-callee-namespace,
-llvmlibc-restrict-system-libc-headers,
-llvm-header-guard,
-llvm-namespace-comment,
-google-build-using-namespace,
Expand All @@ -9,6 +10,7 @@ Checks: '*,
-fuchsia-statically-constructed-objects,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
-cppcoreguidelines-pro-bounds-constant-array-index,
-cppcoreguidelines-pro-type-static-cast-downcast,
-cppcoreguidelines-pro-type-union-access,
-cppcoreguidelines-pro-type-cstyle-cast,
-cppcoreguidelines-pro-type-vararg,
Expand Down
17 changes: 17 additions & 0 deletions doc/MotionService.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Motion Service
## Introduction
The motion service exposes step count and raw X/Y/Z motion value as READ and NOTIFY characteristics.

## Service
The service UUID is **00020000-78fc-48fe-8e23-433b3a1942d0**

## Characteristics
### Step count (UUID 00020001-78fc-48fe-8e23-433b3a1942d0)
The current number of steps represented as a single `uint32_t` (4 bytes) value.

### Raw motion values (UUID 00020002-78fc-48fe-8e23-433b3a1942d0)
The current raw motion values. This is a 3 `int16_t` array:

- [0] : X
- [1] : Y
- [2] : Z
19 changes: 12 additions & 7 deletions doc/ble.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,19 @@ When the service does not exist in the BLE specification, InfiniTime implements
The following custom services are implemented in InfiniTime:

- Since InfiniTime 0.8:
```
* Music Service : 00000000-78fc-48fe-8e23-433b3a1942d0
```

* Music Service : 00000000-78fc-48fe-8e23-433b3a1942d0


- Since InfiniTime 0.11:
```
* Navigation Service : 00010000-78fc-48fe-8e23-433b3a1942d0
```
* [Navigation Service](NavigationService.md) : 00010000-78fc-48fe-8e23-433b3a1942d0


- Since InfiniTime 0.13
* Call characteristic (extension to the Alert Notification Service): 00020001-78fc-48fe-8e23-433b3a1942d0


- Since InfiniTime 1.7:
* [Motion Service](MotionService.md) : 00030000-78fc-48fe-8e23-433b3a1942d0

---

Expand Down
30 changes: 30 additions & 0 deletions doc/buildAndProgram.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,33 @@ Loading section .sec7, size 0xdf08 lma 0x40000
Start address 0x0, load size 314200
Transfer rate: 45 KB/sec, 969 bytes/write.
```
### How to generate files needed by the factory
These files are needed by the Pine64 factory to flash InfiniTime as the default firmware on the PineTimes.
Two files are needed: an **HEX (.hex)** file that contains the content of the internal flash memory (bootloader + InfiniTime) and a **binary (.bin)** file that contains the content of the external flash memory (recovery firmware).
#### merged-internal.hex
First, convert the bootloader to hex:
```
<ARM TOOLCHAIN>/bin/arm-none-eabi-objcopy -I binary -O ihex ./bootloader.bin ./bootloader.hex
```
where `bootloader.bin` is the [last stable version](https://github.com/JF002/pinetime-mcuboot-bootloader/releases) of the [bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader).
Then, convert the MCUBoot image of InfiniTime:
```
<ARM TOOLCHAIN>/bin/arm-none-eabi-objcopy -I binary -O ihex --change-addresses 0x8000 ./pinetime-mcuboot-app-image-1.6.0.bin ./pinetime-mcuboot-app-image-1.6.0.hex
```
where `pinetime-mcuboot-app-image-1.6.0.bin` is [the bin of the last MCUBoot image](https://github.com/InfiniTimeOrg/InfiniTime/releases) of [InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime).
Pay attention to the parameter `--change-addresses 0x8000`. It's needed to ensure the image will be flashed at the offset expected by the bootloader (0x8000).
Finally, merge them together with **mergehex**:
```
/opt/mergehex/mergehex -m ./bootloader.hex ./pinetime-mcuboot-app-image-1.6.0.hex -o merged-internal.hex
```
This file must be flashed at offset **0x00** of the internal memory of the NRF52832.
#### spinor.bin
This file is the MCUBoot image of the last stable version of the recovery firmware. It must be flashed at offset **0x00** of the external SPINOR flash memory.
2 changes: 1 addition & 1 deletion doc/gettingStarted/gettingStarted-1.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Basically, a **firmware** is just a software running on the embedded hardware of
- **[The bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader)** is responsible for safely applying **updates** of the *application firmware*, reverting them in case of issues and load the recovery firmware when requested.
- **The recovery firmware** is a specific *application firmware* than can be loaded by the bootloader on user request. This firmware can be useful in case of serious issue, when the main application firmware cannot perform an OTA update correctly. Currently, this recovery firmware is based on [InfiniTime 0.14.1](https://github.com/InfiniTimeOrg/InfiniTime/releases/tag/0.14.1).

**OTA** and **DFU** refer to the update of the firmware over BLE (**B**luetooth **L**ow **E**nergy). **OTA** means **O**ver **T**he **A**ir, this is a functionality that allows the user to update the firmware how their device using a wireless communication like BLE. When we talk about **DFU** (**D**igital **F**irmware **U**pdate), we refer to the file format and protocol used to send the update of the firmware to the watch over-the-air. InfiniTime implement the (legacy) DFU protocol from Nordic Semiconductor (NRF).
**OTA** and **DFU** refer to the update of the firmware over BLE (**B**luetooth **L**ow **E**nergy). **OTA** means **O**ver **T**he **A**ir, this is a functionality that allows the user to update the firmware how their device using a wireless communication like BLE. When we talk about **DFU** (**D**evice **F**irmware **U**pdate), we refer to the file format and protocol used to send the update of the firmware to the watch over-the-air. InfiniTime implement the (legacy) DFU protocol from Nordic Semiconductor (NRF).

## How to check the version of InfiniTime and the bootloader?

Expand Down
6 changes: 6 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ list(APPEND SOURCE_FILES
components/ble/ImmediateAlertService.cpp
components/ble/ServiceDiscovery.cpp
components/ble/HeartRateService.cpp
components/ble/MotionService.cpp
components/firmwarevalidator/FirmwareValidator.cpp
components/motor/MotorController.cpp
components/settings/Settings.cpp
Expand Down Expand Up @@ -505,6 +506,7 @@ list(APPEND SOURCE_FILES
components/heartrate/Ptagc.cpp
components/heartrate/HeartRateController.cpp

buttonhandler/ButtonHandler.cpp
touchhandler/TouchHandler.cpp
)

Expand Down Expand Up @@ -544,6 +546,7 @@ list(APPEND RECOVERY_SOURCE_FILES
components/ble/ServiceDiscovery.cpp
components/ble/NavigationService.cpp
components/ble/HeartRateService.cpp
components/ble/MotionService.cpp
components/firmwarevalidator/FirmwareValidator.cpp
components/settings/Settings.cpp
components/timer/TimerController.cpp
Expand All @@ -564,6 +567,7 @@ list(APPEND RECOVERY_SOURCE_FILES
components/heartrate/Ptagc.cpp
components/motor/MotorController.cpp
components/fs/FS.cpp
buttonhandler/ButtonHandler.cpp
touchhandler/TouchHandler.cpp
)

Expand Down Expand Up @@ -651,6 +655,7 @@ set(INCLUDE_FILES
components/ble/ServiceDiscovery.h
components/ble/BleClient.h
components/ble/HeartRateService.h
components/ble/MotionService.h
components/settings/Settings.h
components/timer/TimerController.h
components/alarm/AlarmController.h
Expand All @@ -677,6 +682,7 @@ set(INCLUDE_FILES
components/heartrate/Ptagc.h
components/heartrate/HeartRateController.h
components/motor/MotorController.h
buttonhandler/ButtonHandler.h
touchhandler/TouchHandler.h
)

Expand Down
7 changes: 7 additions & 0 deletions src/buttonhandler/ButtonActions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

namespace Pinetime {
namespace Controllers {
enum class ButtonActions { None, Click, DoubleClick, LongPress, LongerPress };
}
}
78 changes: 78 additions & 0 deletions src/buttonhandler/ButtonHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include "ButtonHandler.h"

using namespace Pinetime::Controllers;

void ButtonTimerCallback(TimerHandle_t xTimer) {
auto* sysTask = static_cast<Pinetime::System::SystemTask*>(pvTimerGetTimerID(xTimer));
sysTask->PushMessage(Pinetime::System::Messages::HandleButtonTimerEvent);
}

void ButtonHandler::Init(Pinetime::System::SystemTask* systemTask) {
buttonTimer = xTimerCreate("buttonTimer", 0, pdFALSE, systemTask, ButtonTimerCallback);
}

ButtonActions ButtonHandler::HandleEvent(Events event) {
static constexpr TickType_t doubleClickTime = pdMS_TO_TICKS(200);
static constexpr TickType_t longPressTime = pdMS_TO_TICKS(400);
static constexpr TickType_t longerPressTime = pdMS_TO_TICKS(2000);

if (event == Events::Press) {
buttonPressed = true;
} else if (event == Events::Release) {
releaseTime = xTaskGetTickCount();
buttonPressed = false;
}

switch (state) {
case States::Idle:
if (event == Events::Press) {
xTimerChangePeriod(buttonTimer, doubleClickTime, 0);
xTimerStart(buttonTimer, 0);
state = States::Pressed;
}
break;
case States::Pressed:
if (event == Events::Press) {
if (xTaskGetTickCount() - releaseTime < doubleClickTime) {
xTimerStop(buttonTimer, 0);
state = States::Idle;
return ButtonActions::DoubleClick;
}
} else if (event == Events::Release) {
xTimerChangePeriod(buttonTimer, doubleClickTime, 0);
xTimerStart(buttonTimer, 0);
} else if (event == Events::Timer) {
if (buttonPressed) {
xTimerChangePeriod(buttonTimer, longPressTime - doubleClickTime, 0);
xTimerStart(buttonTimer, 0);
state = States::Holding;
} else {
state = States::Idle;
return ButtonActions::Click;
}
}
break;
case States::Holding:
if (event == Events::Release) {
xTimerStop(buttonTimer, 0);
state = States::Idle;
return ButtonActions::Click;
} else if (event == Events::Timer) {
xTimerChangePeriod(buttonTimer, longerPressTime - longPressTime - doubleClickTime, 0);
xTimerStart(buttonTimer, 0);
state = States::LongHeld;
return ButtonActions::LongPress;
}
break;
case States::LongHeld:
if (event == Events::Release) {
xTimerStop(buttonTimer, 0);
state = States::Idle;
} else if (event == Events::Timer) {
state = States::Idle;
return ButtonActions::LongerPress;
}
break;
}
return ButtonActions::None;
}
24 changes: 24 additions & 0 deletions src/buttonhandler/ButtonHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include "ButtonActions.h"
#include "systemtask/SystemTask.h"
#include <FreeRTOS.h>
#include <timers.h>

namespace Pinetime {
namespace Controllers {
class ButtonHandler {
public:
enum class Events : uint8_t { Press, Release, Timer };
void Init(Pinetime::System::SystemTask* systemTask);
ButtonActions HandleEvent(Events event);

private:
enum class States : uint8_t { Idle, Pressed, Holding, LongHeld };
TickType_t releaseTime = 0;
TimerHandle_t buttonTimer;
bool buttonPressed = false;
States state = States::Idle;
};
}
}
16 changes: 14 additions & 2 deletions src/components/ble/HeartRateService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ constexpr ble_uuid16_t HeartRateService::heartRateServiceUuid;
constexpr ble_uuid16_t HeartRateService::heartRateMeasurementUuid;

namespace {
int HeartRateServiceServiceCallback(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);
}
Expand All @@ -19,7 +19,7 @@ HeartRateService::HeartRateService(Pinetime::System::SystemTask& system, Control
: system {system},
heartRateController {heartRateController},
characteristicDefinition {{.uuid = &heartRateMeasurementUuid.u,
.access_cb = HeartRateServiceServiceCallback,
.access_cb = HeartRateServiceCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
.val_handle = &heartRateMeasurementHandle},
Expand Down Expand Up @@ -56,6 +56,8 @@ int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t a
}

void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) {
if(!heartRateMeasurementNotificationEnable) return;

uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
auto* om = ble_hs_mbuf_from_flat(buffer, 2);

Expand All @@ -67,3 +69,13 @@ void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) {

ble_gattc_notify_custom(connectionHandle, heartRateMeasurementHandle, om);
}

void HeartRateService::SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) {
if(attributeHandle == heartRateMeasurementHandle)
heartRateMeasurementNotificationEnable = true;
}

void HeartRateService::UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) {
if(attributeHandle == heartRateMeasurementHandle)
heartRateMeasurementNotificationEnable = false;
}
7 changes: 6 additions & 1 deletion src/components/ble/HeartRateService.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define min // workaround: nimble's min/max macros conflict with libstdc++
#define max
#include <host/ble_gap.h>
#include <atomic>
#undef max
#undef min

Expand All @@ -18,6 +19,9 @@ namespace Pinetime {
int OnHeartRateRequested(uint16_t connectionHandle, 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);

private:
Pinetime::System::SystemTask& system;
Controllers::HeartRateController& heartRateController;
Expand All @@ -28,10 +32,11 @@ namespace Pinetime {

static constexpr ble_uuid16_t heartRateMeasurementUuid {.u {.type = BLE_UUID_TYPE_16}, .value = heartRateMeasurementId};

struct ble_gatt_chr_def characteristicDefinition[3];
struct ble_gatt_chr_def characteristicDefinition[2];
struct ble_gatt_svc_def serviceDefinition[2];

uint16_t heartRateMeasurementHandle;
std::atomic_bool heartRateMeasurementNotificationEnable {false};
};
}
}
Loading

0 comments on commit 18e3cc7

Please sign in to comment.