From baafb96f3089d7fc890b4b5ef65bb2934fce3f55 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 7 Jun 2020 20:03:10 +0200 Subject: [PATCH 01/11] Set version to 0.7.0 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 003be764..51ac2d18 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(pinetime VERSION 0.6.0 LANGUAGES C CXX ASM) +project(pinetime VERSION 0.7.0 LANGUAGES C CXX ASM) set(NRF_TARGET "nrf52") From e22c0609b542b133fe2effe8f91501d50b763d45 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 7 Jun 2020 20:04:43 +0200 Subject: [PATCH 02/11] Add uptime counter in DateTimeController and display it in SystemInfo screen. --- src/Components/DateTime/DateTimeController.cpp | 3 ++- src/Components/DateTime/DateTimeController.h | 3 ++- src/DisplayApp/Screens/ScreenList.cpp | 15 ++++++++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Components/DateTime/DateTimeController.cpp b/src/Components/DateTime/DateTimeController.cpp index 5cfa08eb..30d9c13f 100644 --- a/src/Components/DateTime/DateTimeController.cpp +++ b/src/Components/DateTime/DateTimeController.cpp @@ -47,7 +47,8 @@ void DateTime::UpdateTime(uint32_t systickCounter) { previousSystickCounter = 0xffffff - (rest - systickCounter); } - currentDateTime += std::chrono::seconds (correctedDelta); + currentDateTime += std::chrono::seconds(correctedDelta); + uptime += std::chrono::seconds(correctedDelta); auto dp = date::floor(currentDateTime); auto time = date::make_time(currentDateTime-dp); diff --git a/src/Components/DateTime/DateTimeController.h b/src/Components/DateTime/DateTimeController.h index 1e65bd11..d6020745 100644 --- a/src/Components/DateTime/DateTimeController.h +++ b/src/Components/DateTime/DateTimeController.h @@ -21,6 +21,7 @@ namespace Pinetime { uint8_t Seconds() const { return second; } std::chrono::time_point CurrentDateTime() const { return currentDateTime; } + std::chrono::seconds Uptime() const { return uptime; } private: uint16_t year = 0; Months month = Months::Unknown; @@ -32,7 +33,7 @@ namespace Pinetime { uint32_t previousSystickCounter = 0; std::chrono::time_point currentDateTime; - + std::chrono::seconds uptime {0}; }; } } \ No newline at end of file diff --git a/src/DisplayApp/Screens/ScreenList.cpp b/src/DisplayApp/Screens/ScreenList.cpp index 93a91212..a1701688 100644 --- a/src/DisplayApp/Screens/ScreenList.cpp +++ b/src/DisplayApp/Screens/ScreenList.cpp @@ -43,19 +43,32 @@ ScreenList::ScreenList(Pinetime::Applications::DisplayApp *app, Pinetime::Contro } }(); + // uptime + static constexpr uint32_t secondsInADay = 60*60*24; + static constexpr uint32_t secondsInAnHour = 60*60; + static constexpr uint32_t secondsInAMinute = 60; + uint32_t uptimeSeconds = dateTimeController.Uptime().count(); + uint32_t uptimeDays = (uptimeSeconds / secondsInADay); + uptimeSeconds = uptimeSeconds % secondsInADay; + uint32_t uptimeHours = uptimeSeconds / secondsInAnHour; + uptimeSeconds = uptimeSeconds % secondsInAnHour; + uint32_t uptimeMinutes = uptimeSeconds / secondsInAMinute; + uptimeSeconds = uptimeSeconds % secondsInAMinute; + // TODO handle more than 100 days of uptime sprintf(t1, "Pinetime\n" "Version:%d.%d.%d\n" "Build: xx/xx/xxxx\n" "Time: %02d:%02d:%02d\n" "date: %02d/%02d/%04d\n" - "Uptime: xd xxhxx:xx\n" + "Uptime: %02lud %02lu:%02lu:%02lu\n" "Battery: %d%%\n" "Backlight: %d/3\n" "Last reset: %s\n" "BLE MAC: \n AA:BB:CC:DD:EE:FF", Version::Major(), Version::Minor(), Version::Patch(), dateTimeController.Hours(), dateTimeController.Minutes(), dateTimeController.Seconds(), dateTimeController.Day(), dateTimeController.Month(), dateTimeController.Year(), + uptimeDays, uptimeHours, uptimeMinutes, uptimeSeconds, batteryPercent, brightness, resetReason); screens.emplace_back(t1); From 81a0ad73d9f3613b78805c0fe6c23252c01ed451 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 7 Jun 2020 20:05:04 +0200 Subject: [PATCH 03/11] Set idle timeout to 15s before going to sleep. --- src/SystemTask/SystemTask.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SystemTask/SystemTask.h b/src/SystemTask/SystemTask.h index b6ecf7c9..ab5f7010 100644 --- a/src/SystemTask/SystemTask.h +++ b/src/SystemTask/SystemTask.h @@ -67,7 +67,7 @@ namespace Pinetime { void Work(); bool isBleDiscoveryTimerRunning = false; uint8_t bleDiscoveryTimer = 0; - static constexpr uint32_t idleTime = 5000; + static constexpr uint32_t idleTime = 15000; TimerHandle_t idleTimer; bool doNotGoToSleep = false; From 421af9625b56039e14084aacf6b987c34cf35ebd Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 7 Jun 2020 20:16:39 +0200 Subject: [PATCH 04/11] Add build date and time in sysinfo screen. --- src/DisplayApp/Screens/ScreenList.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/DisplayApp/Screens/ScreenList.cpp b/src/DisplayApp/Screens/ScreenList.cpp index a1701688..4599a384 100644 --- a/src/DisplayApp/Screens/ScreenList.cpp +++ b/src/DisplayApp/Screens/ScreenList.cpp @@ -58,16 +58,18 @@ ScreenList::ScreenList(Pinetime::Applications::DisplayApp *app, Pinetime::Contro sprintf(t1, "Pinetime\n" "Version:%d.%d.%d\n" - "Build: xx/xx/xxxx\n" + "Build: %s\n" + " %s\n" + "Date: %02d/%02d/%04d\n" "Time: %02d:%02d:%02d\n" - "date: %02d/%02d/%04d\n" "Uptime: %02lud %02lu:%02lu:%02lu\n" "Battery: %d%%\n" "Backlight: %d/3\n" - "Last reset: %s\n" - "BLE MAC: \n AA:BB:CC:DD:EE:FF", Version::Major(), Version::Minor(), Version::Patch(), - dateTimeController.Hours(), dateTimeController.Minutes(), dateTimeController.Seconds(), + "Last reset: %s\n", + Version::Major(), Version::Minor(), Version::Patch(), + __DATE__, __TIME__, dateTimeController.Day(), dateTimeController.Month(), dateTimeController.Year(), + dateTimeController.Hours(), dateTimeController.Minutes(), dateTimeController.Seconds(), uptimeDays, uptimeHours, uptimeMinutes, uptimeSeconds, batteryPercent, brightness, resetReason); From 9115c49bba366698c79b3fc07a991bee1c0cd4ca Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 7 Jun 2020 20:31:13 +0200 Subject: [PATCH 05/11] Fix reset reason (it returns the actual reset reason instead of hard coded 'hard reset' value). --- src/drivers/Watchdog.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/drivers/Watchdog.cpp b/src/drivers/Watchdog.cpp index 850fd2f1..11da1211 100644 --- a/src/drivers/Watchdog.cpp +++ b/src/drivers/Watchdog.cpp @@ -32,17 +32,17 @@ void Watchdog::Kick() { } Watchdog::ResetReasons Watchdog::ActualResetReason() const { - uint32_t resetReason; -// sd_power_reset_reason_get(&resetReason); -// sd_power_reset_reason_clr(0xFFFFFFFF); -// if(resetReason & 0x01u) return ResetReasons::ResetPin; -// if((resetReason >> 1u) & 0x01u) return ResetReasons::Watchdog; -// if((resetReason >> 2u) & 0x01u) return ResetReasons::SoftReset; -// if((resetReason >> 3u) & 0x01u) return ResetReasons::CpuLockup; -// if((resetReason >> 16u) & 0x01u) return ResetReasons::SystemOff; -// if((resetReason >> 17u) & 0x01u) return ResetReasons::LpComp; -// if((resetReason >> 18u) & 0x01u) return ResetReasons::DebugInterface; -// if((resetReason >> 19u) & 0x01u) return ResetReasons::NFC; + uint32_t reason = NRF_POWER->RESETREAS; + NRF_POWER->RESETREAS = 0xffffffff; + + if(reason & 0x01u) return ResetReasons::ResetPin; + if((reason >> 1u) & 0x01u) return ResetReasons::Watchdog; + if((reason >> 2u) & 0x01u) return ResetReasons::SoftReset; + if((reason >> 3u) & 0x01u) return ResetReasons::CpuLockup; + if((reason >> 16u) & 0x01u) return ResetReasons::SystemOff; + if((reason >> 17u) & 0x01u) return ResetReasons::LpComp; + if((reason) & 0x01u) return ResetReasons::DebugInterface; + if((reason >> 19u) & 0x01u) return ResetReasons::NFC; return ResetReasons::HardReset; } From 47851fb3b476268d967738f09f9da812e0fc575f Mon Sep 17 00:00:00 2001 From: JF Date: Mon, 8 Jun 2020 21:51:34 +0200 Subject: [PATCH 06/11] Display BLE MAC address in sysinfo Screen. --- src/Components/Ble/BleController.h | 9 +++++++++ src/Components/Ble/NimbleController.cpp | 7 ++++++- src/Components/Ble/NimbleController.h | 2 +- src/DisplayApp/DisplayApp.cpp | 2 +- src/DisplayApp/Screens/ScreenList.cpp | 18 +++++++++++++----- src/DisplayApp/Screens/ScreenList.h | 8 ++++++-- 6 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/Components/Ble/BleController.h b/src/Components/Ble/BleController.h index c47e65b6..3f52ea25 100644 --- a/src/Components/Ble/BleController.h +++ b/src/Components/Ble/BleController.h @@ -2,12 +2,15 @@ #include #include +#include namespace Pinetime { namespace Controllers { class Ble { public: + using BleAddress = std::array; enum class FirmwareUpdateStates {Idle, Running, Validated, Error}; + enum class AddressTypes { Public, Random }; Ble() = default; bool IsConnected() const {return isConnected;} @@ -24,12 +27,18 @@ namespace Pinetime { uint32_t FirmwareUpdateTotalBytes() const { return firmwareUpdateTotalBytes; } uint32_t FirmwareUpdateCurrentBytes() const { return firmwareUpdateCurrentBytes; } FirmwareUpdateStates State() const { return firmwareUpdateState; } + + void Address(BleAddress&& addr) { address = addr; } + const BleAddress& Address() const { return address; } + void AddressType(AddressTypes t) { addressType = t;} private: bool isConnected = false; bool isFirmwareUpdating = false; uint32_t firmwareUpdateTotalBytes = 0; uint32_t firmwareUpdateCurrentBytes = 0; FirmwareUpdateStates firmwareUpdateState = FirmwareUpdateStates::Idle; + BleAddress address; + AddressTypes addressType; }; } diff --git a/src/Components/Ble/NimbleController.cpp b/src/Components/Ble/NimbleController.cpp index 4c8035b7..561dbce4 100644 --- a/src/Components/Ble/NimbleController.cpp +++ b/src/Components/Ble/NimbleController.cpp @@ -90,8 +90,13 @@ void NimbleController::Init() { res = ble_hs_id_infer_auto(0, &addrType); ASSERT(res == 0); res = ble_svc_gap_device_name_set(deviceName); - ASSERT(res == 0); + Pinetime::Controllers::Ble::BleAddress address; + res = ble_hs_id_copy_addr(addrType, address.data(), nullptr); + ASSERT(res == 0); + bleController.AddressType((addrType == 0) ? Ble::AddressTypes::Public : Ble::AddressTypes::Random); + bleController.Address(std::move(address)); + res = ble_gatts_start(); ASSERT(res == 0); } diff --git a/src/Components/Ble/NimbleController.h b/src/Components/Ble/NimbleController.h index 7e680607..cf50d78d 100644 --- a/src/Components/Ble/NimbleController.h +++ b/src/Components/Ble/NimbleController.h @@ -50,7 +50,7 @@ namespace Pinetime { AlertNotificationClient alertNotificationClient; CurrentTimeService currentTimeService; - uint8_t addrType; + uint8_t addrType; // 1 = Random, 0 = PUBLIC uint16_t connectionHandle; ble_uuid128_t dfuServiceUuid { diff --git a/src/DisplayApp/DisplayApp.cpp b/src/DisplayApp/DisplayApp.cpp index 01c3aa96..8e35ef55 100644 --- a/src/DisplayApp/DisplayApp.cpp +++ b/src/DisplayApp/DisplayApp.cpp @@ -185,7 +185,7 @@ void DisplayApp::RunningState() { onClockApp = true; break; // case Apps::Test: currentScreen.reset(new Screens::Message(this)); break; - case Apps::SysInfo: currentScreen.reset(new Screens::ScreenList(this, dateTimeController, batteryController, brightnessController, watchdog)); break; + case Apps::SysInfo: currentScreen.reset(new Screens::ScreenList(this, dateTimeController, batteryController, brightnessController, bleController, watchdog)); break; case Apps::Meter: currentScreen.reset(new Screens::Meter(this)); break; case Apps::Gauge: currentScreen.reset(new Screens::Gauge(this)); break; case Apps::Brightness : currentScreen.reset(new Screens::Brightness(this, brightnessController)); break; diff --git a/src/DisplayApp/Screens/ScreenList.cpp b/src/DisplayApp/Screens/ScreenList.cpp index 4599a384..48f71649 100644 --- a/src/DisplayApp/Screens/ScreenList.cpp +++ b/src/DisplayApp/Screens/ScreenList.cpp @@ -8,10 +8,15 @@ using namespace Pinetime::Applications::Screens; // move operation. // It should accept many type of "sub screen" (it only supports Label for now). // The number of sub screen it supports must be dynamic. -ScreenList::ScreenList(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::DateTime &dateTimeController, - Pinetime::Controllers::Battery& batteryController, Pinetime::Controllers::BrightnessController& brightnessController, Pinetime::Drivers::WatchdogView& watchdog) : +ScreenList::ScreenList(Pinetime::Applications::DisplayApp *app, + Pinetime::Controllers::DateTime &dateTimeController, + Pinetime::Controllers::Battery& batteryController, + Pinetime::Controllers::BrightnessController& brightnessController, + Pinetime::Controllers::Ble& bleController, + Pinetime::Drivers::WatchdogView& watchdog) : Screen(app), - dateTimeController{dateTimeController}, batteryController{batteryController}, brightnessController{brightnessController}, watchdog{watchdog} { + dateTimeController{dateTimeController}, batteryController{batteryController}, + brightnessController{brightnessController}, bleController{bleController}, watchdog{watchdog} { screens.reserve(3); // TODO all of this is far too heavy (string processing). This should be improved. @@ -75,10 +80,13 @@ ScreenList::ScreenList(Pinetime::Applications::DisplayApp *app, Pinetime::Contro screens.emplace_back(t1); - strncpy(t2, "Hello from\nthe developper!", 27); + auto& bleAddr = bleController.Address(); + sprintf(t2, "BLE MAC: \n %2x:%2x:%2x:%2x:%2x:%2x", + bleAddr[5], bleAddr[4], bleAddr[3], bleAddr[2], bleAddr[1], bleAddr[0]); screens.emplace_back(t2); - strncpy(t3, "Place holder\nin case we need\nmore room!", 40); + strncpy(t3, "Hello from\nthe developper!", 27); + screens.emplace_back(t3); auto &screen = screens[screenIndex]; diff --git a/src/DisplayApp/Screens/ScreenList.h b/src/DisplayApp/Screens/ScreenList.h index ad093d35..b0ee016b 100644 --- a/src/DisplayApp/Screens/ScreenList.h +++ b/src/DisplayApp/Screens/ScreenList.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "Screen.h" #include "Label.h" @@ -13,6 +14,7 @@ namespace Pinetime { Pinetime::Controllers::DateTime& dateTimeController, Pinetime::Controllers::Battery& batteryController, Pinetime::Controllers::BrightnessController& brightnessController, + Pinetime::Controllers::Ble& bleController, Pinetime::Drivers::WatchdogView& watchdog); ~ScreenList() override; bool Refresh() override; @@ -27,11 +29,13 @@ namespace Pinetime { Pinetime::Controllers::DateTime& dateTimeController; Pinetime::Controllers::Battery& batteryController; Pinetime::Controllers::BrightnessController& brightnessController; + Pinetime::Controllers::Ble& bleController; Pinetime::Drivers::WatchdogView& watchdog; + char t1[200]; - char t2[30]; - char t3[42]; + char t2[200]; + char t3[30]; }; } } From fab220d0b9c6868b4fa96ce5f3e3f41b5454a0c7 Mon Sep 17 00:00:00 2001 From: JF Date: Sat, 13 Jun 2020 17:33:49 +0200 Subject: [PATCH 07/11] Fix idle timer bug that would prevent the screen from waking up. --- src/SystemTask/SystemTask.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/SystemTask/SystemTask.cpp b/src/SystemTask/SystemTask.cpp index b0f58d17..61b3c638 100644 --- a/src/SystemTask/SystemTask.cpp +++ b/src/SystemTask/SystemTask.cpp @@ -16,6 +16,8 @@ using namespace Pinetime::System; void IdleTimerCallback(TimerHandle_t xTimer) { + + NRF_LOG_INFO("IdleTimerCallback"); auto sysTask = static_cast(pvTimerGetTimerID(xTimer)); sysTask->OnIdle(); } @@ -113,6 +115,7 @@ void SystemTask::Work() { break; case Messages::GoToSleep: NRF_LOG_INFO("[SystemTask] Going to sleep"); + xTimerStop(idleTimer, 0); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::GoToSleep); isSleeping = true; break; From f133d1e9ea9e5d679f41545fac8d09a6760db0d8 Mon Sep 17 00:00:00 2001 From: JF Date: Tue, 16 Jun 2020 20:44:11 +0200 Subject: [PATCH 08/11] Fix #include that were pointing to my own FS instead of relative paths to the SDK. --- src/drivers/InternalFlash.cpp | 2 +- src/graphics.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/drivers/InternalFlash.cpp b/src/drivers/InternalFlash.cpp index bc89ff1a..db705d78 100644 --- a/src/drivers/InternalFlash.cpp +++ b/src/drivers/InternalFlash.cpp @@ -1,4 +1,4 @@ -#include +#include #include "InternalFlash.h" using namespace Pinetime::Drivers; diff --git a/src/graphics.cpp b/src/graphics.cpp index d95ba3fa..8c39c89a 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include "bootloader/boot_graphics.h" #include #include From 5faa68ba1ab88c1fe8bf919c2cee24c9adbeae4d Mon Sep 17 00:00:00 2001 From: JF Date: Tue, 16 Jun 2020 20:44:55 +0200 Subject: [PATCH 09/11] Remove reference to MERGEHEX as it's not needed anymore. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 30a92dc8..e728969d 100644 --- a/README.md +++ b/README.md @@ -92,14 +92,14 @@ GDB (Back Magic Probe) ``` $ mkdir build $ cd build -$ cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_GDB_CLIENT=1 -DGDB_CLIENT_BIN_PATH=... -DGDB_CLIENT_TARGET_REMOTE=... -DMERGEHEX=... ../ +$ cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_GDB_CLIENT=1 -DGDB_CLIENT_BIN_PATH=... -DGDB_CLIENT_TARGET_REMOTE=... ../ ``` OpenOCD (STlink v2 clones) ``` $ mkdir build $ cd build -$ cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_OPENOCD=1 -DGDB_CLIENT_BIN_PATH=[optional] -DMERGEHEX=... ../ +$ cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_OPENOCD=1 -DGDB_CLIENT_BIN_PATH=[optional] ../ ``` * Make From 73e6cbde79d632a5446aca4372424456927597b9 Mon Sep 17 00:00:00 2001 From: JF Date: Tue, 16 Jun 2020 21:02:03 +0200 Subject: [PATCH 10/11] Fix builds that do not specify CMAKE_BUILD_TYPE during CMake generation. Apply Release by default. --- README.md | 8 ++++++++ src/CMakeLists.txt | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/README.md b/README.md index e728969d..42efda20 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,14 @@ $ cd build $ cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=... -DNRF5_SDK_PATH=... -DUSE_OPENOCD=1 -DGDB_CLIENT_BIN_PATH=[optional] ../ ``` + +**Note** : By default, the build configuration *Release* is applied. It means that the code is built with optimisations enabled (-O3). If you wanto to compile in *Debug* mode to ease debugging and step-by-step debugging, specify the CMake variable `CMAKE_BUILD_TYPE` in the CMake command line: + +``` +-DCMAKE_BUILD_TYPE=Debug +``` + + * Make ``` $ make -j pinetime-app diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 286a792a..1609196a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -546,6 +546,10 @@ add_definitions(-DNRF52 -DNRF52832 -DNRF52832_XXAA -DNRF52_PAN_74 -DNRF52_PAN_64 add_definitions(-DFREERTOS) add_definitions(-DDEBUG_NRF_USER) +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") +endif() + # Build autonomous binary (without support for bootloader) set(EXECUTABLE_NAME "pinetime-app") set(NRF5_LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/gcc_nrf52.ld") From 9a89ff7f7764df085a59c8a24fe578228a22fc6c Mon Sep 17 00:00:00 2001 From: JF Date: Tue, 16 Jun 2020 21:07:53 +0200 Subject: [PATCH 11/11] Set version to 0.6.1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 51ac2d18..c5cf78aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(pinetime VERSION 0.7.0 LANGUAGES C CXX ASM) +project(pinetime VERSION 0.6.1 LANGUAGES C CXX ASM) set(NRF_TARGET "nrf52")