Merge branch 'develop' into detect_full_charge
This commit is contained in:
commit
b210090837
47 changed files with 942 additions and 243 deletions
8
.github/workflows/main.yml
vendored
8
.github/workflows/main.yml
vendored
|
@ -9,13 +9,13 @@ name: Build PineTime Firmware
|
|||
# When to run this Workflow...
|
||||
on:
|
||||
|
||||
# Run this Workflow when files are updated (Pushed) in the "master" Branch
|
||||
# Run this Workflow when files are updated (Pushed) in the "master" and "develop" Branch
|
||||
push:
|
||||
branches: [ master ]
|
||||
branches: [ master, develop ]
|
||||
|
||||
# Also run this Workflow when a Pull Request is created or updated in the "master" Branch
|
||||
# Also run this Workflow when a Pull Request is created or updated in the "master" and "develop" Branch
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
branches: [ master, develop ]
|
||||
|
||||
# Steps to run for the Workflow
|
||||
jobs:
|
||||
|
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -38,4 +38,8 @@ Testing/Temporary/
|
|||
**/.DS_Store
|
||||
|
||||
# Windows
|
||||
**/thumbs.db
|
||||
**/thumbs.db
|
||||
|
||||
#VSCODE
|
||||
.vscode/.cortex-debug.registers.state.json
|
||||
.vscode/.cortex-debug.peripherals.state.json
|
||||
|
|
52
.vscode/settings.json
vendored
52
.vscode/settings.json
vendored
|
@ -5,5 +5,55 @@
|
|||
"-DNRF5_SDK_PATH=${env:NRF5_SDK_PATH}",
|
||||
],
|
||||
"cmake.generator": "Unix Makefiles",
|
||||
"clang-tidy.buildPath": "build/compile_commands.json"
|
||||
"clang-tidy.buildPath": "build/compile_commands.json",
|
||||
"files.associations": {
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"chrono": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"string": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"fstream": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"new": "cpp",
|
||||
"ostream": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,14 @@ if(BUILD_DFU)
|
|||
set(BUILD_DFU true)
|
||||
endif()
|
||||
|
||||
option(WATCH_COLMI_P8 "Build for the Colmi P8" OFF)
|
||||
set(TARGET_DEVICE "PineTime")
|
||||
|
||||
if(WATCH_COLMI_P8)
|
||||
set(TARGET_DEVICE "Colmi P8")
|
||||
add_definitions(-DWATCH_P8)
|
||||
endif()
|
||||
|
||||
set(PROJECT_GIT_COMMIT_HASH "")
|
||||
|
||||
execute_process(COMMAND git rev-parse --short HEAD
|
||||
|
@ -68,6 +76,7 @@ message(" * Version : " ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${P
|
|||
message(" * Toolchain : " ${ARM_NONE_EABI_TOOLCHAIN_PATH})
|
||||
message(" * GitRef(S) : " ${PROJECT_GIT_COMMIT_HASH})
|
||||
message(" * NRF52 SDK : " ${NRF5_SDK_PATH})
|
||||
message(" * Target device : " ${TARGET_DEVICE})
|
||||
set(PROGRAMMER "???")
|
||||
if(USE_JLINK)
|
||||
message(" * Programmer/debugger : JLINK")
|
||||
|
|
25
README.md
25
README.md
|
@ -1,20 +1,10 @@
|
|||
# PineTime
|
||||
# InfiniTime
|
||||
|
||||
[![Build PineTime Firmware](https://github.com/JF002/InfiniTime/workflows/Build%20PineTime%20Firmware/badge.svg?branch=master)](https://github.com/JF002/InfiniTime/actions)
|
||||
|
||||
> The PineTime is a free and open source smartwatch capable of running custom-built open operating systems. Some of the notable features include a heart rate monitor, a week-long battery as well as a capacitive touch IPS display that is legible in direct sunlight. It is a fully community driven side-project, which means that it will ultimately be up to the developers and end-users to determine when they deem the PineTime ready to ship.
|
||||
|
||||
> We envision the PineTime as a companion for not only your PinePhone but also for your favorite devices — any phone, tablet, or even PC.
|
||||
|
||||
*https://www.pine64.org/pinetime/*
|
||||
|
||||
The **Pinetime** smartwatch is built around the NRF52832 MCU (512KB Flash, 64KB RAM), a 240*240 LCD display driven by the ST7789 controller, an accelerometer, a heart rate sensor, and a vibration motor.
|
||||
|
||||
# InfiniTime
|
||||
|
||||
![InfiniTime logo](images/infinitime-logo.jpg "InfiniTime Logo")
|
||||
|
||||
The goal of this project is to design an open-source firmware for the Pinetime smartwatch :
|
||||
The goal of this project is to design an open-source firmware for the [Pinetime smartwatch](https://www.pine64.org/pinetime/) :
|
||||
|
||||
- Code written in **modern C++**;
|
||||
- Build system based on **CMake**;
|
||||
|
@ -22,6 +12,11 @@ The goal of this project is to design an open-source firmware for the Pinetime s
|
|||
- Using **[LittleVGL/LVGL 7](https://lvgl.io/)** as UI library...
|
||||
- ... and **[NimBLE 1.3.0](https://github.com/apache/mynewt-nimble)** as BLE stack.
|
||||
|
||||
## New to InfiniTime?
|
||||
|
||||
- [Getting started with InfiniTime 1.0 (quick user guide, update bootloader and InfiniTime,...)](doc/gettingStarted/gettingStarted-1.0.md)
|
||||
- [Flash, upgrade (OTA), time synchronization,...](doc/gettingStarted/ota-gadgetbridge-nrfconnect.md)
|
||||
|
||||
## Overview
|
||||
|
||||
![Pinetime screens](images/1.0.0/collage.png "PinetimeScreens")
|
||||
|
@ -70,16 +65,12 @@ As of now, here is the list of achievements of this project:
|
|||
* [Amazfish](https://openrepos.net/content/piggz/amazfish) (on SailfishOS and Linux)
|
||||
* [Siglo](https://github.com/alexr4535/siglo) (on Linux)
|
||||
* **[Experimental]** [WebBLEWatch](https://hubmartin.github.io/WebBLEWatch/) Synchronize time directly from your web browser. [video](https://youtu.be/IakiuhVDdrY)
|
||||
* **[Experimental]** [Infini-iOS](https://github.com/xan-m/Infini-iOS) (on iOS)
|
||||
- OTA (Over-the-air) update via BLE
|
||||
- [Bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader) based on [MCUBoot](https://juullabs-oss.github.io/mcuboot/)
|
||||
|
||||
## Documentation
|
||||
|
||||
### Getting started
|
||||
|
||||
- [Getting started with InfiniTime 1.0 (quick user guide, update bootloader and InfiniTime,...)](doc/gettingStarted/gettingStarted-1.0.md)
|
||||
- [Flash, upgrade (OTA), time synchronization,...](doc/gettingStarted/ota-gadgetbridge-nrfconnect.md)
|
||||
|
||||
### Develop
|
||||
|
||||
- [Generate the fonts and symbols](src/displayapp/fonts/README.md)
|
||||
|
|
|
@ -98,7 +98,7 @@ The script makes use of the following tools:
|
|||
|
||||
After setup you can use cmake as usual:
|
||||
|
||||
1. Generate the actual build files (out-of-source builds are strongly recomended):
|
||||
1. Generate the actual build files (out-of-source builds are strongly recommended):
|
||||
|
||||
```commandline
|
||||
cmake -H. -B"cmake-build" -G "Unix Makefiles"
|
||||
|
|
|
@ -28,6 +28,7 @@ CMake configures the project according to variables you specify the command line
|
|||
**GDB_CLIENT_BIN_PATH**|Path to arm-none-eabi-gdb executable. Used only if `USE_GDB_CLIENT` is 1.|`-DGDB_CLIENT_BIN_PATH=/home/jf/nrf52/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-gdb`
|
||||
**GDB_CLIENT_TARGET_REMOTE**|Target remote connection string. Used only if `USE_GDB_CLIENT` is 1.|`-DGDB_CLIENT_TARGET_REMOTE=/dev/ttyACM0`
|
||||
**BUILD_DFU (\*\*)**|Build DFU files while building (needs [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil)).|`-DBUILD_DFU=1`
|
||||
**WATCH_COLMI_P8**|Use pin configuration for Colmi P8 watch|`-DWATCH_COLMI_P8=1`
|
||||
|
||||
####(**) Note about **CMAKE_BUILD_TYPE**:
|
||||
By default, this variable is set to *Release*. It compiles the code with size and speed optimizations. We use this value for all the binaries we publish when we [release](https://github.com/JF002/InfiniTime/releases) new versions of InfiniTime.
|
||||
|
|
|
@ -47,6 +47,8 @@ Read carefully the warning and tap **Install**:
|
|||
|
||||
Wait for the transfer to finish. Your PineTime should reset and reboot with the new version of InfiniTime!
|
||||
|
||||
Don't forget to **validate** your firmware. In the InfiniTime go to the settings (swipe right, select gear icon) and Firmware option and click **validate**. Otherwise after reboot the previous firmware will be used.
|
||||
|
||||
![Gadgetbridge 5](gadgetbridge5.jpg)
|
||||
|
||||
### Using NRFConnect
|
||||
|
@ -64,6 +66,8 @@ Select **Distribution packet (ZIP)**:
|
|||
|
||||
Browse to the DFU file you downloaded previously, the DFU transfer will start automatically. When the transfer is finished, your PineTime will reset and restart on the new version of InfiniTime!
|
||||
|
||||
Don't forget to **validate** your firmware. In the InfiniTime go to the settings (swipe right, select gear icon) and Firmware option and click **validate**. Otherwise after reboot the previous firmware will be used.
|
||||
|
||||
![NRFConnect 3](nrfconnect3.jpg)
|
||||
|
||||
## How to flash InfiniTime using the SWD interface
|
||||
|
@ -88,6 +92,10 @@ If you are using OpenOCD with a STLinkV2, you can find more info [on this page](
|
|||
### Using Gadgetbridge
|
||||
Good news! Gadgetbridge **automatically** synchronizes the time when connecting to your PineTime!
|
||||
|
||||
### Using any Chromium-based web browser
|
||||
You can use it from your PC, Mac, Android. Browsers now have BLE support.
|
||||
https://hubmartin.github.io/WebBLEWatch/
|
||||
|
||||
### Using NRFConnect
|
||||
You must enable the **CTS** *GATT server* into NRFConnect so that InfiniTime can synchronize the time with your smartphone.
|
||||
|
||||
|
|
|
@ -3,4 +3,4 @@ The versioning of this project is based on [Semantic versionning](https://semver
|
|||
|
||||
- The **patch** is incremented when we fix a bug on a **released** version (most of the time using a **hotfix** branch).
|
||||
- The **minor** is incremented when we release a new version with new features. It corresponds to a merge of **develop** into **master**.
|
||||
- The **major** should be incremented when a breaking change is made to the application. We still have to define what is a breaking change in the context of this project. For now, I suggest that it stays **0** until we have a fully functionning firmware suited for the final user.
|
||||
- The **major** should be incremented when a breaking change is made to the application. We still have to define what is a breaking change in the context of this project. For now, I suggest that it stays **0** until we have a fully functioning firmware suited for the final user.
|
|
@ -6,12 +6,18 @@ GROUP(-lgcc -lc -lnosys)
|
|||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x08020, LENGTH = 0x78000
|
||||
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000
|
||||
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
}
|
||||
.noinit(NOLOAD):
|
||||
{
|
||||
PROVIDE(__start_noinit_data = .);
|
||||
*(.noinit)
|
||||
PROVIDE(__stop_noinit_data = .);
|
||||
} > RAM
|
||||
} INSERT AFTER .bss
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
|
11
gcc_nrf52.ld
11
gcc_nrf52.ld
|
@ -6,12 +6,18 @@ GROUP(-lgcc -lc -lnosys)
|
|||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x00000, LENGTH = 0x78000
|
||||
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000
|
||||
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
}
|
||||
.noinit(NOLOAD):
|
||||
{
|
||||
PROVIDE(__start_noinit_data = .);
|
||||
*(.noinit)
|
||||
PROVIDE(__stop_noinit_data = .);
|
||||
} > RAM
|
||||
} INSERT AFTER .bss
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
@ -44,6 +50,7 @@ SECTIONS
|
|||
PROVIDE(__stop_log_filter_data = .);
|
||||
} > RAM
|
||||
|
||||
|
||||
} INSERT AFTER .data;
|
||||
|
||||
SECTIONS
|
||||
|
|
|
@ -92,6 +92,9 @@ set(SDK_SOURCE_FILES
|
|||
set(TINYCRYPT_SRC
|
||||
libs/mynewt-nimble/ext/tinycrypt/src/aes_encrypt.c
|
||||
libs/mynewt-nimble/ext/tinycrypt/src/utils.c
|
||||
libs/mynewt-nimble/ext/tinycrypt/src/cmac_mode.c
|
||||
libs/mynewt-nimble/ext/tinycrypt/src/ecc.c
|
||||
libs/mynewt-nimble/ext/tinycrypt/src/ecc_dh.c
|
||||
)
|
||||
|
||||
set(NIMBLE_SRC
|
||||
|
@ -104,6 +107,10 @@ set(NIMBLE_SRC
|
|||
libs/mynewt-nimble/nimble/host/src/ble_l2cap.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_hs_mbuf.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_sm.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_sm_cmd.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_sm_lgcy.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_sm_alg.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_sm_sc.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_gap.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_gatts.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_gattc.c
|
||||
|
@ -127,10 +134,6 @@ set(NIMBLE_SRC
|
|||
libs/mynewt-nimble/nimble/host/src/ble_hs_atomic.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_hs_adv.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_hs_flow.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_sm.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_sm_cmd.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_sm_lgcy.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_sm_alg.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_hs_mqueue.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_hs_stop.c
|
||||
libs/mynewt-nimble/nimble/host/src/ble_hs_startup.c
|
||||
|
@ -418,6 +421,7 @@ list(APPEND SOURCE_FILES
|
|||
displayapp/screens/BatteryInfo.cpp
|
||||
displayapp/screens/Steps.cpp
|
||||
displayapp/screens/Timer.cpp
|
||||
displayapp/screens/Alarm.cpp
|
||||
displayapp/Colors.cpp
|
||||
|
||||
## Settings
|
||||
|
@ -474,6 +478,7 @@ list(APPEND SOURCE_FILES
|
|||
components/motor/MotorController.cpp
|
||||
components/settings/Settings.cpp
|
||||
components/timer/TimerController.cpp
|
||||
components/alarm/AlarmController.cpp
|
||||
components/fs/FS.cpp
|
||||
drivers/Cst816s.cpp
|
||||
FreeRTOS/port.c
|
||||
|
@ -540,6 +545,7 @@ list(APPEND RECOVERY_SOURCE_FILES
|
|||
components/firmwarevalidator/FirmwareValidator.cpp
|
||||
components/settings/Settings.cpp
|
||||
components/timer/TimerController.cpp
|
||||
components/alarm/AlarmController.cpp
|
||||
drivers/Cst816s.cpp
|
||||
FreeRTOS/port.c
|
||||
FreeRTOS/port_cmsis_systick.c
|
||||
|
@ -612,6 +618,7 @@ set(INCLUDE_FILES
|
|||
displayapp/screens/Metronome.h
|
||||
displayapp/screens/Motion.h
|
||||
displayapp/screens/Timer.h
|
||||
displayapp/screens/Alarm.h
|
||||
displayapp/Colors.h
|
||||
drivers/St7789.h
|
||||
drivers/SpiNorFlash.h
|
||||
|
@ -621,6 +628,7 @@ set(INCLUDE_FILES
|
|||
drivers/DebugPins.h
|
||||
drivers/InternalFlash.h
|
||||
drivers/Hrs3300.h
|
||||
drivers/PinMap.h
|
||||
drivers/Bma421.h
|
||||
drivers/Bma421_C/bma4.c
|
||||
drivers/Bma421_C/bma423.c
|
||||
|
@ -643,6 +651,7 @@ set(INCLUDE_FILES
|
|||
components/ble/HeartRateService.h
|
||||
components/settings/Settings.h
|
||||
components/timer/TimerController.h
|
||||
components/alarm/AlarmController.h
|
||||
drivers/Cst816s.h
|
||||
FreeRTOS/portmacro.h
|
||||
FreeRTOS/portmacro_cmsis.h
|
||||
|
|
114
src/components/alarm/AlarmController.cpp
Normal file
114
src/components/alarm/AlarmController.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
/* Copyright (C) 2021 mruss77, Florian
|
||||
|
||||
This file is part of InfiniTime.
|
||||
|
||||
InfiniTime is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
InfiniTime is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "AlarmController.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "app_timer.h"
|
||||
#include "task.h"
|
||||
#include <chrono>
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
AlarmController::AlarmController(Controllers::DateTime& dateTimeController) : dateTimeController {dateTimeController} {
|
||||
}
|
||||
|
||||
APP_TIMER_DEF(alarmAppTimer);
|
||||
|
||||
namespace {
|
||||
void SetOffAlarm(void* p_context) {
|
||||
auto* controller = static_cast<Pinetime::Controllers::AlarmController*>(p_context);
|
||||
if (controller != nullptr) {
|
||||
controller->SetOffAlarmNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AlarmController::Init(System::SystemTask* systemTask) {
|
||||
app_timer_create(&alarmAppTimer, APP_TIMER_MODE_SINGLE_SHOT, SetOffAlarm);
|
||||
this->systemTask = systemTask;
|
||||
}
|
||||
|
||||
void AlarmController::SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin) {
|
||||
hours = alarmHr;
|
||||
minutes = alarmMin;
|
||||
}
|
||||
|
||||
void AlarmController::ScheduleAlarm() {
|
||||
// Determine the next time the alarm needs to go off and set the app_timer
|
||||
app_timer_stop(alarmAppTimer);
|
||||
|
||||
auto now = dateTimeController.CurrentDateTime();
|
||||
alarmTime = now;
|
||||
time_t ttAlarmTime = std::chrono::system_clock::to_time_t(alarmTime);
|
||||
tm* tmAlarmTime = std::localtime(&ttAlarmTime);
|
||||
|
||||
// If the time being set has already passed today,the alarm should be set for tomorrow
|
||||
if (hours < dateTimeController.Hours() || (hours == dateTimeController.Hours() && minutes <= dateTimeController.Minutes())) {
|
||||
tmAlarmTime->tm_mday += 1;
|
||||
// tm_wday doesn't update automatically
|
||||
tmAlarmTime->tm_wday = (tmAlarmTime->tm_wday + 1) % 7;
|
||||
}
|
||||
|
||||
tmAlarmTime->tm_hour = hours;
|
||||
tmAlarmTime->tm_min = minutes;
|
||||
tmAlarmTime->tm_sec = 0;
|
||||
|
||||
// if alarm is in weekday-only mode, make sure it shifts to the next weekday
|
||||
if (recurrence == RecurType::Weekdays) {
|
||||
if (tmAlarmTime->tm_wday == 0) { // Sunday, shift 1 day
|
||||
tmAlarmTime->tm_mday += 1;
|
||||
} else if (tmAlarmTime->tm_wday == 6) { // Saturday, shift 2 days
|
||||
tmAlarmTime->tm_mday += 2;
|
||||
}
|
||||
}
|
||||
tmAlarmTime->tm_isdst = -1; // use system timezone setting to determine DST
|
||||
|
||||
// now can convert back to a time_point
|
||||
alarmTime = std::chrono::system_clock::from_time_t(std::mktime(tmAlarmTime));
|
||||
auto mSecToAlarm = std::chrono::duration_cast<std::chrono::milliseconds>(alarmTime - now).count();
|
||||
app_timer_start(alarmAppTimer, APP_TIMER_TICKS(mSecToAlarm), this);
|
||||
|
||||
state = AlarmState::Set;
|
||||
}
|
||||
|
||||
uint32_t AlarmController::SecondsToAlarm() {
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(alarmTime - dateTimeController.CurrentDateTime()).count();
|
||||
}
|
||||
|
||||
void AlarmController::DisableAlarm() {
|
||||
app_timer_stop(alarmAppTimer);
|
||||
state = AlarmState::Not_Set;
|
||||
}
|
||||
|
||||
void AlarmController::SetOffAlarmNow() {
|
||||
state = AlarmState::Alerting;
|
||||
systemTask->PushMessage(System::Messages::SetOffAlarm);
|
||||
}
|
||||
|
||||
void AlarmController::StopAlerting() {
|
||||
systemTask->PushMessage(System::Messages::StopRinging);
|
||||
|
||||
// Alarm state is off unless this is a recurring alarm
|
||||
if (recurrence == RecurType::None) {
|
||||
state = AlarmState::Not_Set;
|
||||
} else {
|
||||
state = AlarmState::Set;
|
||||
// set next instance
|
||||
ScheduleAlarm();
|
||||
}
|
||||
}
|
68
src/components/alarm/AlarmController.h
Normal file
68
src/components/alarm/AlarmController.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* Copyright (C) 2021 mruss77, Florian
|
||||
|
||||
This file is part of InfiniTime.
|
||||
|
||||
InfiniTime is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
InfiniTime is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "app_timer.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
class SystemTask;
|
||||
}
|
||||
namespace Controllers {
|
||||
class AlarmController {
|
||||
public:
|
||||
AlarmController(Controllers::DateTime& dateTimeController);
|
||||
|
||||
void Init(System::SystemTask* systemTask);
|
||||
void SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin);
|
||||
void ScheduleAlarm();
|
||||
void DisableAlarm();
|
||||
void SetOffAlarmNow();
|
||||
uint32_t SecondsToAlarm();
|
||||
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;
|
||||
}
|
||||
|
||||
private:
|
||||
Controllers::DateTime& dateTimeController;
|
||||
System::SystemTask* systemTask = nullptr;
|
||||
uint8_t hours = 7;
|
||||
uint8_t minutes = 0;
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> alarmTime;
|
||||
AlarmState state = AlarmState::Not_Set;
|
||||
RecurType recurrence = RecurType::None;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#include "BatteryController.h"
|
||||
#include "drivers/PinMap.h"
|
||||
#include <hal/nrf_gpio.h>
|
||||
#include <nrfx_saadc.h>
|
||||
#include <algorithm>
|
||||
|
@ -9,15 +10,12 @@ Battery* Battery::instance = nullptr;
|
|||
|
||||
Battery::Battery() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
void Battery::Init() {
|
||||
nrf_gpio_cfg_input(chargingPin, static_cast<nrf_gpio_pin_pull_t> GPIO_PIN_CNF_PULL_Pullup);
|
||||
nrf_gpio_cfg_input(PinMap::Charging, static_cast<nrf_gpio_pin_pull_t> GPIO_PIN_CNF_PULL_Disabled);
|
||||
}
|
||||
|
||||
void Battery::Update() {
|
||||
isCharging = !nrf_gpio_pin_read(chargingPin);
|
||||
isPowerPresent = !nrf_gpio_pin_read(powerPresentPin);
|
||||
isCharging = !nrf_gpio_pin_read(PinMap::Charging);
|
||||
isPowerPresent = !nrf_gpio_pin_read(PinMap::PowerPresent);
|
||||
|
||||
if (isPowerPresent && !isCharging) {
|
||||
isFull = true;
|
||||
|
@ -81,5 +79,11 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) {
|
|||
|
||||
nrfx_saadc_uninit();
|
||||
isReading = false;
|
||||
|
||||
systemTask->PushMessage(System::Messages::BatteryMeasurementDone);
|
||||
}
|
||||
}
|
||||
|
||||
void Battery::Register(Pinetime::System::SystemTask* systemTask) {
|
||||
this->systemTask = systemTask;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <drivers/include/nrfx_saadc.h>
|
||||
#include <array>
|
||||
#include <numeric>
|
||||
#include <systemtask/SystemTask.h>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
|
@ -11,8 +10,8 @@ namespace Pinetime {
|
|||
public:
|
||||
Battery();
|
||||
|
||||
void Init();
|
||||
void Update();
|
||||
void Register(System::SystemTask* systemTask);
|
||||
|
||||
uint8_t PercentRemaining() const {
|
||||
return percentRemaining;
|
||||
|
@ -36,8 +35,6 @@ namespace Pinetime {
|
|||
static Battery* instance;
|
||||
nrf_saadc_value_t saadc_value;
|
||||
|
||||
static constexpr uint32_t chargingPin = 12;
|
||||
static constexpr uint32_t powerPresentPin = 19;
|
||||
static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7;
|
||||
uint16_t voltage = 0;
|
||||
uint8_t percentRemaining = 0;
|
||||
|
@ -52,6 +49,8 @@ namespace Pinetime {
|
|||
static void AdcCallbackStatic(nrfx_saadc_evt_t const* event);
|
||||
|
||||
bool isReading = false;
|
||||
|
||||
Pinetime::System::SystemTask* systemTask = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,19 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
|
|||
serviceDiscovery({¤tTimeClient, &alertNotificationClient}) {
|
||||
}
|
||||
|
||||
void nimble_on_reset(int reason) {
|
||||
NRF_LOG_INFO("Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
void nimble_on_sync(void) {
|
||||
int rc;
|
||||
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
ASSERT(rc == 0);
|
||||
|
||||
nptr->StartAdvertising();
|
||||
}
|
||||
|
||||
int GAPEventCallback(struct ble_gap_event* event, void* arg) {
|
||||
auto nimbleController = static_cast<NimbleController*>(arg);
|
||||
return nimbleController->OnGAPEvent(event);
|
||||
|
@ -51,6 +64,10 @@ void NimbleController::Init() {
|
|||
while (!ble_hs_synced()) {
|
||||
}
|
||||
|
||||
nptr = this;
|
||||
ble_hs_cfg.reset_cb = nimble_on_reset;
|
||||
ble_hs_cfg.sync_cb = nimble_on_sync;
|
||||
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
|
||||
|
@ -64,28 +81,31 @@ void NimbleController::Init() {
|
|||
batteryInformationService.Init();
|
||||
immediateAlertService.Init();
|
||||
heartRateService.Init();
|
||||
int res;
|
||||
res = ble_hs_util_ensure_addr(0);
|
||||
ASSERT(res == 0);
|
||||
res = ble_hs_id_infer_auto(0, &addrType);
|
||||
ASSERT(res == 0);
|
||||
res = ble_svc_gap_device_name_set(deviceName);
|
||||
ASSERT(res == 0);
|
||||
|
||||
int rc;
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
ASSERT(rc == 0);
|
||||
rc = ble_hs_id_infer_auto(0, &addrType);
|
||||
ASSERT(rc == 0);
|
||||
rc = ble_svc_gap_device_name_set(deviceName);
|
||||
ASSERT(rc == 0);
|
||||
rc = ble_svc_gap_device_appearance_set(0xC2);
|
||||
ASSERT(rc == 0);
|
||||
Pinetime::Controllers::Ble::BleAddress address;
|
||||
res = ble_hs_id_copy_addr(addrType, address.data(), nullptr);
|
||||
ASSERT(res == 0);
|
||||
rc = ble_hs_id_copy_addr(addrType, address.data(), nullptr);
|
||||
ASSERT(rc == 0);
|
||||
bleController.AddressType((addrType == 0) ? Ble::AddressTypes::Public : Ble::AddressTypes::Random);
|
||||
bleController.Address(std::move(address));
|
||||
|
||||
res = ble_gatts_start();
|
||||
ASSERT(res == 0);
|
||||
rc = ble_gatts_start();
|
||||
ASSERT(rc == 0);
|
||||
|
||||
if (!ble_gap_adv_active() && !bleController.IsConnected())
|
||||
StartAdvertising();
|
||||
}
|
||||
|
||||
void NimbleController::StartAdvertising() {
|
||||
if (bleController.IsConnected() || ble_gap_conn_active() || ble_gap_adv_active())
|
||||
return;
|
||||
|
||||
ble_svc_gap_device_name_set(deviceName);
|
||||
int rc;
|
||||
|
||||
/* set adv parameters */
|
||||
struct ble_gap_adv_params adv_params;
|
||||
|
@ -102,11 +122,17 @@ void NimbleController::StartAdvertising() {
|
|||
|
||||
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
/* fast advertise for 30 sec */
|
||||
if (fastAdvCount < 15) {
|
||||
adv_params.itvl_min = 32;
|
||||
adv_params.itvl_max = 47;
|
||||
fastAdvCount++;
|
||||
} else {
|
||||
adv_params.itvl_min = 1636;
|
||||
adv_params.itvl_max = 1651;
|
||||
}
|
||||
|
||||
fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
// fields.uuids128 = BLE_UUID128(BLE_UUID128_DECLARE(
|
||||
// 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
// 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff));
|
||||
fields.uuids128 = &dfuServiceUuid;
|
||||
fields.num_uuids128 = 1;
|
||||
fields.uuids128_is_complete = 1;
|
||||
|
@ -116,28 +142,25 @@ void NimbleController::StartAdvertising() {
|
|||
rsp_fields.name_len = strlen(deviceName);
|
||||
rsp_fields.name_is_complete = 1;
|
||||
|
||||
ble_gap_adv_set_fields(&fields);
|
||||
// ASSERT(res == 0); // TODO this one sometimes fails with error 22 (notsync)
|
||||
rc = ble_gap_adv_set_fields(&fields);
|
||||
ASSERT(rc == 0);
|
||||
|
||||
ble_gap_adv_rsp_set_fields(&rsp_fields);
|
||||
// ASSERT(res == 0);
|
||||
rc = ble_gap_adv_rsp_set_fields(&rsp_fields);
|
||||
ASSERT(rc == 0);
|
||||
|
||||
ble_gap_adv_start(addrType, NULL, 180000, &adv_params, GAPEventCallback, this);
|
||||
// ASSERT(res == 0);// TODO I've disabled these ASSERT as they sometime asserts and reset the mcu.
|
||||
// For now, the advertising is restarted as soon as it ends. There may be a race condition
|
||||
// that prevent the advertising from restarting reliably.
|
||||
// I remove the assert to prevent this uncesseray crash, but in the long term, the management of
|
||||
// the advertising should be improve (better error handling, and advertise for 3 minutes after
|
||||
// the application has been woken up, for example.
|
||||
rc = ble_gap_adv_start(addrType, NULL, 2000, &adv_params, GAPEventCallback, this);
|
||||
ASSERT(rc == 0);
|
||||
}
|
||||
|
||||
int NimbleController::OnGAPEvent(ble_gap_event* event) {
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_ADV_COMPLETE");
|
||||
NRF_LOG_INFO("advertise complete; reason=%dn status=%d", event->adv_complete.reason, event->connect.status);
|
||||
NRF_LOG_INFO("reason=%d; status=%d", event->adv_complete.reason, event->connect.status);
|
||||
StartAdvertising();
|
||||
break;
|
||||
case BLE_GAP_EVENT_CONNECT: {
|
||||
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_CONNECT");
|
||||
|
||||
/* A new connection was established or a connection attempt failed. */
|
||||
|
@ -145,35 +168,44 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {
|
|||
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising. */
|
||||
StartAdvertising();
|
||||
currentTimeClient.Reset();
|
||||
alertNotificationClient.Reset();
|
||||
connectionHandle = BLE_HS_CONN_HANDLE_NONE;
|
||||
bleController.Disconnect();
|
||||
fastAdvCount = 0;
|
||||
StartAdvertising();
|
||||
} else {
|
||||
connectionHandle = event->connect.conn_handle;
|
||||
bleController.Connect();
|
||||
systemTask.PushMessage(Pinetime::System::Messages::BleConnected);
|
||||
connectionHandle = event->connect.conn_handle;
|
||||
// Service discovery is deffered via systemtask
|
||||
// Service discovery is deferred via systemtask
|
||||
}
|
||||
} break;
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_DISCONNECT");
|
||||
NRF_LOG_INFO("disconnect; reason=%d", event->disconnect.reason);
|
||||
NRF_LOG_INFO("disconnect reason=%d", event->disconnect.reason);
|
||||
|
||||
/* Connection terminated; resume advertising. */
|
||||
currentTimeClient.Reset();
|
||||
alertNotificationClient.Reset();
|
||||
connectionHandle = BLE_HS_CONN_HANDLE_NONE;
|
||||
bleController.Disconnect();
|
||||
fastAdvCount = 0;
|
||||
StartAdvertising();
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_CONN_UPDATE:
|
||||
NRF_LOG_INFO("Advertising event : BLE_GAP_EVENT_CONN_UPDATE");
|
||||
/* The central has updated the connection parameters. */
|
||||
NRF_LOG_INFO("connection updated; status=%d ", event->conn_update.status);
|
||||
NRF_LOG_INFO("update status=%d ", event->conn_update.status);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_ENC_CHANGE:
|
||||
/* Encryption has been enabled or disabled for this connection. */
|
||||
NRF_LOG_INFO("encryption change event; status=%d ", event->enc_change.status);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_SUBSCRIBE:
|
||||
NRF_LOG_INFO("subscribe event; conn_handle=%d attr_handle=%d "
|
||||
"reason=%d prevn=%d curn=%d previ=%d curi=???\n",
|
||||
|
@ -183,10 +215,12 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {
|
|||
event->subscribe.prev_notify,
|
||||
event->subscribe.cur_notify,
|
||||
event->subscribe.prev_indicate);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value);
|
||||
return 0;
|
||||
NRF_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n",
|
||||
event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_REPEAT_PAIRING: {
|
||||
/* We already have a bond with the peer, but it is attempting to
|
||||
|
@ -217,8 +251,7 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {
|
|||
notifSize);
|
||||
|
||||
alertNotificationClient.OnNotification(event);
|
||||
return 0;
|
||||
}
|
||||
} break;
|
||||
/* Attribute data is contained in event->notify_rx.attr_data. */
|
||||
|
||||
default:
|
||||
|
@ -229,7 +262,9 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {
|
|||
}
|
||||
|
||||
void NimbleController::StartDiscovery() {
|
||||
serviceDiscovery.StartDiscovery(connectionHandle);
|
||||
if (connectionHandle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
serviceDiscovery.StartDiscovery(connectionHandle);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t NimbleController::connHandle() {
|
||||
|
@ -237,7 +272,7 @@ uint16_t NimbleController::connHandle() {
|
|||
}
|
||||
|
||||
void NimbleController::NotifyBatteryLevel(uint8_t level) {
|
||||
if(connectionHandle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
if (connectionHandle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
batteryInformationService.NotifyBatteryLevel(connectionHandle, level);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,10 @@ namespace Pinetime {
|
|||
uint16_t connHandle();
|
||||
void NotifyBatteryLevel(uint8_t level);
|
||||
|
||||
void RestartFastAdv() {
|
||||
fastAdvCount = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr const char* deviceName = "InfiniTime";
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
|
@ -94,6 +98,7 @@ namespace Pinetime {
|
|||
|
||||
uint8_t addrType; // 1 = Random, 0 = PUBLIC
|
||||
uint16_t connectionHandle = BLE_HS_CONN_HANDLE_NONE;
|
||||
uint8_t fastAdvCount = 0;
|
||||
|
||||
ble_uuid128_t dfuServiceUuid {
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
|
@ -101,5 +106,7 @@ namespace Pinetime {
|
|||
|
||||
ServiceDiscovery serviceDiscovery;
|
||||
};
|
||||
|
||||
static NimbleController* nptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#include "BrightnessController.h"
|
||||
#include <hal/nrf_gpio.h>
|
||||
#include "displayapp/screens/Symbols.h"
|
||||
|
||||
#include "drivers/PinMap.h"
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
void BrightnessController::Init() {
|
||||
nrf_gpio_cfg_output(pinLcdBacklight1);
|
||||
nrf_gpio_cfg_output(pinLcdBacklight2);
|
||||
nrf_gpio_cfg_output(pinLcdBacklight3);
|
||||
nrf_gpio_cfg_output(PinMap::LcdBacklightLow);
|
||||
nrf_gpio_cfg_output(PinMap::LcdBacklightMedium);
|
||||
nrf_gpio_cfg_output(PinMap::LcdBacklightHigh);
|
||||
Set(level);
|
||||
}
|
||||
|
||||
|
@ -16,24 +16,24 @@ void BrightnessController::Set(BrightnessController::Levels level) {
|
|||
switch (level) {
|
||||
default:
|
||||
case Levels::High:
|
||||
nrf_gpio_pin_clear(pinLcdBacklight1);
|
||||
nrf_gpio_pin_clear(pinLcdBacklight2);
|
||||
nrf_gpio_pin_clear(pinLcdBacklight3);
|
||||
nrf_gpio_pin_clear(PinMap::LcdBacklightLow);
|
||||
nrf_gpio_pin_clear(PinMap::LcdBacklightMedium);
|
||||
nrf_gpio_pin_clear(PinMap::LcdBacklightHigh);
|
||||
break;
|
||||
case Levels::Medium:
|
||||
nrf_gpio_pin_clear(pinLcdBacklight1);
|
||||
nrf_gpio_pin_clear(pinLcdBacklight2);
|
||||
nrf_gpio_pin_set(pinLcdBacklight3);
|
||||
nrf_gpio_pin_clear(PinMap::LcdBacklightLow);
|
||||
nrf_gpio_pin_clear(PinMap::LcdBacklightMedium);
|
||||
nrf_gpio_pin_set(PinMap::LcdBacklightHigh);
|
||||
break;
|
||||
case Levels::Low:
|
||||
nrf_gpio_pin_clear(pinLcdBacklight1);
|
||||
nrf_gpio_pin_set(pinLcdBacklight2);
|
||||
nrf_gpio_pin_set(pinLcdBacklight3);
|
||||
nrf_gpio_pin_clear(PinMap::LcdBacklightLow);
|
||||
nrf_gpio_pin_set(PinMap::LcdBacklightMedium);
|
||||
nrf_gpio_pin_set(PinMap::LcdBacklightHigh);
|
||||
break;
|
||||
case Levels::Off:
|
||||
nrf_gpio_pin_set(pinLcdBacklight1);
|
||||
nrf_gpio_pin_set(pinLcdBacklight2);
|
||||
nrf_gpio_pin_set(pinLcdBacklight3);
|
||||
nrf_gpio_pin_set(PinMap::LcdBacklightLow);
|
||||
nrf_gpio_pin_set(PinMap::LcdBacklightMedium);
|
||||
nrf_gpio_pin_set(PinMap::LcdBacklightHigh);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,6 @@ namespace Pinetime {
|
|||
const char* ToString();
|
||||
|
||||
private:
|
||||
static constexpr uint8_t pinLcdBacklight1 = 14;
|
||||
static constexpr uint8_t pinLcdBacklight2 = 22;
|
||||
static constexpr uint8_t pinLcdBacklight3 = 23;
|
||||
Levels level = Levels::High;
|
||||
Levels backupLevel = Levels::High;
|
||||
};
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
void DateTime::SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> t) {
|
||||
this->currentDateTime = t;
|
||||
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) {
|
||||
std::tm tm = {
|
||||
|
@ -67,7 +72,7 @@ void DateTime::UpdateTime(uint32_t systickCounter) {
|
|||
// Notify new day to SystemTask
|
||||
if (hour == 0 and not isMidnightAlreadyNotified) {
|
||||
isMidnightAlreadyNotified = true;
|
||||
if(systemTask != nullptr)
|
||||
if (systemTask != nullptr)
|
||||
systemTask->PushMessage(System::Messages::OnNewDay);
|
||||
} else if (hour != 0) {
|
||||
isMidnightAlreadyNotified = false;
|
||||
|
|
|
@ -74,6 +74,7 @@ namespace Pinetime {
|
|||
}
|
||||
|
||||
void Register(System::SystemTask* systemTask);
|
||||
void SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> t);
|
||||
|
||||
private:
|
||||
uint16_t year = 0;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <hal/nrf_gpio.h>
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "app_timer.h"
|
||||
#include "drivers/PinMap.h"
|
||||
|
||||
APP_TIMER_DEF(shortVibTimer);
|
||||
APP_TIMER_DEF(longVibTimer);
|
||||
|
@ -12,8 +13,8 @@ MotorController::MotorController(Controllers::Settings& settingsController) : se
|
|||
}
|
||||
|
||||
void MotorController::Init() {
|
||||
nrf_gpio_cfg_output(pinMotor);
|
||||
nrf_gpio_pin_set(pinMotor);
|
||||
nrf_gpio_cfg_output(PinMap::Motor);
|
||||
nrf_gpio_pin_set(PinMap::Motor);
|
||||
app_timer_init();
|
||||
|
||||
app_timer_create(&shortVibTimer, APP_TIMER_MODE_SINGLE_SHOT, StopMotor);
|
||||
|
@ -30,7 +31,7 @@ void MotorController::RunForDuration(uint8_t motorDuration) {
|
|||
return;
|
||||
}
|
||||
|
||||
nrf_gpio_pin_clear(pinMotor);
|
||||
nrf_gpio_pin_clear(PinMap::Motor);
|
||||
app_timer_start(shortVibTimer, APP_TIMER_TICKS(motorDuration), nullptr);
|
||||
}
|
||||
|
||||
|
@ -44,9 +45,9 @@ void MotorController::StartRinging() {
|
|||
|
||||
void MotorController::StopRinging() {
|
||||
app_timer_stop(longVibTimer);
|
||||
nrf_gpio_pin_set(pinMotor);
|
||||
nrf_gpio_pin_set(PinMap::Motor);
|
||||
}
|
||||
|
||||
void MotorController::StopMotor(void* p_context) {
|
||||
nrf_gpio_pin_set(pinMotor);
|
||||
nrf_gpio_pin_set(PinMap::Motor);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "app_timer.h"
|
||||
#include "components/settings/Settings.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
static constexpr uint8_t pinMotor = 16;
|
||||
|
||||
class MotorController {
|
||||
public:
|
||||
|
|
|
@ -114,7 +114,7 @@ namespace Pinetime {
|
|||
};
|
||||
|
||||
void setWakeUpMode(WakeUpMode wakeUp, bool enabled) {
|
||||
if (!isWakeUpModeOn(wakeUp)) {
|
||||
if (enabled != isWakeUpModeOn(wakeUp)) {
|
||||
settingsChanged = true;
|
||||
}
|
||||
settings.wakeUpMode.set(static_cast<size_t>(wakeUp), enabled);
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace Pinetime {
|
|||
NotificationsPreview,
|
||||
Notifications,
|
||||
Timer,
|
||||
Alarm,
|
||||
FlashLight,
|
||||
BatteryInfo,
|
||||
Music,
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <displayapp/screens/HeartRate.h>
|
||||
#include <displayapp/screens/Motion.h>
|
||||
#include <displayapp/screens/Timer.h>
|
||||
#include <displayapp/screens/Alarm.h>
|
||||
#include "components/battery/BatteryController.h"
|
||||
#include "components/ble/BleController.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
|
@ -90,6 +91,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
|||
Pinetime::Controllers::MotorController& motorController,
|
||||
Pinetime::Controllers::MotionController& motionController,
|
||||
Pinetime::Controllers::TimerController& timerController,
|
||||
Pinetime::Controllers::AlarmController& alarmController,
|
||||
Pinetime::Controllers::TouchHandler& touchHandler)
|
||||
: lcd {lcd},
|
||||
lvgl {lvgl},
|
||||
|
@ -104,6 +106,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
|||
motorController {motorController},
|
||||
motionController {motionController},
|
||||
timerController {timerController},
|
||||
alarmController {alarmController},
|
||||
touchHandler {touchHandler} {
|
||||
}
|
||||
|
||||
|
@ -136,9 +139,6 @@ void DisplayApp::InitHw() {
|
|||
brightnessController.Set(settingsController.GetBrightness());
|
||||
}
|
||||
|
||||
uint32_t acc = 0;
|
||||
uint32_t count = 0;
|
||||
bool toggle = true;
|
||||
void DisplayApp::Refresh() {
|
||||
TickType_t queueTimeout;
|
||||
TickType_t delta;
|
||||
|
@ -194,9 +194,6 @@ void DisplayApp::Refresh() {
|
|||
// clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected :
|
||||
// Screens::Clock::BleConnectionStates::NotConnected);
|
||||
break;
|
||||
case Messages::UpdateBatteryLevel:
|
||||
batteryController.Update();
|
||||
break;
|
||||
case Messages::NewNotification:
|
||||
LoadApp(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down);
|
||||
break;
|
||||
|
@ -208,6 +205,13 @@ void DisplayApp::Refresh() {
|
|||
LoadApp(Apps::Timer, DisplayApp::FullRefreshDirections::Down);
|
||||
}
|
||||
break;
|
||||
case Messages::AlarmTriggered:
|
||||
if (currentApp == Apps::Alarm) {
|
||||
auto* alarm = static_cast<Screens::Alarm*>(currentScreen.get());
|
||||
alarm->SetAlerting();
|
||||
} else {
|
||||
LoadApp(Apps::Alarm, DisplayApp::FullRefreshDirections::None);
|
||||
}
|
||||
case Messages::TouchEvent: {
|
||||
if (state != States::Running) {
|
||||
break;
|
||||
|
@ -340,6 +344,9 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
|||
case Apps::Timer:
|
||||
currentScreen = std::make_unique<Screens::Timer>(this, timerController);
|
||||
break;
|
||||
case Apps::Alarm:
|
||||
currentScreen = std::make_unique<Screens::Alarm>(this, alarmController);
|
||||
break;
|
||||
|
||||
// Settings
|
||||
case Apps::QuickSettings:
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
#include "components/settings/Settings.h"
|
||||
#include "displayapp/screens/Screen.h"
|
||||
#include "components/timer/TimerController.h"
|
||||
#include "components/alarm/AlarmController.h"
|
||||
#include "touchhandler/TouchHandler.h"
|
||||
|
||||
#include "Messages.h"
|
||||
|
||||
namespace Pinetime {
|
||||
|
@ -57,6 +59,7 @@ namespace Pinetime {
|
|||
Pinetime::Controllers::MotorController& motorController,
|
||||
Pinetime::Controllers::MotionController& motionController,
|
||||
Pinetime::Controllers::TimerController& timerController,
|
||||
Pinetime::Controllers::AlarmController& alarmController,
|
||||
Pinetime::Controllers::TouchHandler& touchHandler);
|
||||
void Start();
|
||||
void PushMessage(Display::Messages msg);
|
||||
|
@ -82,6 +85,7 @@ namespace Pinetime {
|
|||
Pinetime::Controllers::MotorController& motorController;
|
||||
Pinetime::Controllers::MotionController& motionController;
|
||||
Pinetime::Controllers::TimerController& timerController;
|
||||
Pinetime::Controllers::AlarmController& alarmController;
|
||||
Pinetime::Controllers::TouchHandler& touchHandler;
|
||||
|
||||
Pinetime::Controllers::FirmwareValidator validator;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <components/rle/RleDecoder.h>
|
||||
#include <touchhandler/TouchHandler.h>
|
||||
#include "displayapp/icons/infinitime/infinitime-nb.c"
|
||||
#include "components/ble/BleController.h"
|
||||
|
||||
using namespace Pinetime::Applications;
|
||||
|
||||
|
@ -21,6 +22,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd,
|
|||
Pinetime::Controllers::MotorController& motorController,
|
||||
Pinetime::Controllers::MotionController& motionController,
|
||||
Pinetime::Controllers::TimerController& timerController,
|
||||
Pinetime::Controllers::AlarmController& alarmController,
|
||||
Pinetime::Controllers::TouchHandler& touchHandler)
|
||||
: lcd {lcd}, bleController {bleController} {
|
||||
|
||||
|
|
|
@ -6,32 +6,39 @@
|
|||
#include <bits/unique_ptr.h>
|
||||
#include <queue.h>
|
||||
#include "components/gfx/Gfx.h"
|
||||
#include "components/battery/BatteryController.h"
|
||||
#include "components/brightness/BrightnessController.h"
|
||||
#include "components/ble/BleController.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
#include "components/ble/NotificationManager.h"
|
||||
#include "components/firmwarevalidator/FirmwareValidator.h"
|
||||
#include "drivers/Cst816s.h"
|
||||
#include <date/date.h>
|
||||
#include <drivers/Watchdog.h>
|
||||
#include <components/heartrate/HeartRateController.h>
|
||||
#include <components/motion/MotionController.h>
|
||||
#include <components/motor/MotorController.h>
|
||||
#include <components/settings/Settings.h>
|
||||
#include "TouchEvents.h"
|
||||
#include "Apps.h"
|
||||
#include "Messages.h"
|
||||
#include "DummyLittleVgl.h"
|
||||
#include "components/timer/TimerController.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Drivers {
|
||||
class St7789;
|
||||
class Cst816S;
|
||||
class WatchdogView;
|
||||
}
|
||||
namespace Controllers {
|
||||
class Settings;
|
||||
class Battery;
|
||||
class Ble;
|
||||
class DateTime;
|
||||
class NotificationManager;
|
||||
class HeartRateController;
|
||||
class MotionController;
|
||||
class TouchHandler;
|
||||
class MotorController;
|
||||
class TimerController;
|
||||
class AlarmController;
|
||||
}
|
||||
|
||||
namespace System {
|
||||
class SystemTask;
|
||||
};
|
||||
namespace Controllers {
|
||||
class TouchHandler;
|
||||
}
|
||||
|
||||
namespace Applications {
|
||||
class DisplayApp {
|
||||
public:
|
||||
|
@ -48,6 +55,7 @@ namespace Pinetime {
|
|||
Pinetime::Controllers::MotorController& motorController,
|
||||
Pinetime::Controllers::MotionController& motionController,
|
||||
Pinetime::Controllers::TimerController& timerController,
|
||||
Pinetime::Controllers::AlarmController& alarmController,
|
||||
Pinetime::Controllers::TouchHandler& touchHandler);
|
||||
void Start();
|
||||
void PushMessage(Pinetime::Applications::Display::Messages msg);
|
||||
|
|
|
@ -7,7 +7,6 @@ namespace Pinetime {
|
|||
GoToRunning,
|
||||
UpdateDateTime,
|
||||
UpdateBleConnection,
|
||||
UpdateBatteryLevel,
|
||||
TouchEvent,
|
||||
ButtonPushed,
|
||||
NewNotification,
|
||||
|
@ -15,7 +14,8 @@ namespace Pinetime {
|
|||
BleFirmwareUpdateStarted,
|
||||
UpdateTimeOut,
|
||||
DimScreen,
|
||||
RestoreBrightness
|
||||
RestoreBrightness,
|
||||
AlarmTriggered
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
254
src/displayapp/screens/Alarm.cpp
Normal file
254
src/displayapp/screens/Alarm.cpp
Normal file
|
@ -0,0 +1,254 @@
|
|||
/* Copyright (C) 2021 mruss77, Florian
|
||||
|
||||
This file is part of InfiniTime.
|
||||
|
||||
InfiniTime is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
InfiniTime is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Alarm.h"
|
||||
#include "Screen.h"
|
||||
#include "Symbols.h"
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
using Pinetime::Controllers::AlarmController;
|
||||
|
||||
static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
|
||||
Alarm* screen = static_cast<Alarm*>(obj->user_data);
|
||||
screen->OnButtonEvent(obj, event);
|
||||
}
|
||||
|
||||
Alarm::Alarm(DisplayApp* app, Controllers::AlarmController& alarmController)
|
||||
: Screen(app), running {true}, alarmController {alarmController} {
|
||||
|
||||
time = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
|
||||
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||
|
||||
alarmHours = alarmController.Hours();
|
||||
alarmMinutes = alarmController.Minutes();
|
||||
lv_label_set_text_fmt(time, "%02lu:%02lu", alarmHours, alarmMinutes);
|
||||
|
||||
lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -25);
|
||||
|
||||
btnHoursUp = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnHoursUp->user_data = this;
|
||||
lv_obj_set_event_cb(btnHoursUp, btnEventHandler);
|
||||
lv_obj_set_size(btnHoursUp, 60, 40);
|
||||
lv_obj_align(btnHoursUp, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, -85);
|
||||
txtHrUp = lv_label_create(btnHoursUp, nullptr);
|
||||
lv_label_set_text_static(txtHrUp, "+");
|
||||
|
||||
btnHoursDown = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnHoursDown->user_data = this;
|
||||
lv_obj_set_event_cb(btnHoursDown, btnEventHandler);
|
||||
lv_obj_set_size(btnHoursDown, 60, 40);
|
||||
lv_obj_align(btnHoursDown, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, 35);
|
||||
txtHrDown = lv_label_create(btnHoursDown, nullptr);
|
||||
lv_label_set_text_static(txtHrDown, "-");
|
||||
|
||||
btnMinutesUp = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnMinutesUp->user_data = this;
|
||||
lv_obj_set_event_cb(btnMinutesUp, btnEventHandler);
|
||||
lv_obj_set_size(btnMinutesUp, 60, 40);
|
||||
lv_obj_align(btnMinutesUp, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -20, -85);
|
||||
txtMinUp = lv_label_create(btnMinutesUp, nullptr);
|
||||
lv_label_set_text_static(txtMinUp, "+");
|
||||
|
||||
btnMinutesDown = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnMinutesDown->user_data = this;
|
||||
lv_obj_set_event_cb(btnMinutesDown, btnEventHandler);
|
||||
lv_obj_set_size(btnMinutesDown, 60, 40);
|
||||
lv_obj_align(btnMinutesDown, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -20, 35);
|
||||
txtMinDown = lv_label_create(btnMinutesDown, nullptr);
|
||||
lv_label_set_text_static(txtMinDown, "-");
|
||||
|
||||
btnEnable = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnEnable->user_data = this;
|
||||
lv_obj_set_event_cb(btnEnable, btnEventHandler);
|
||||
lv_obj_set_size(btnEnable, 115, 50);
|
||||
lv_obj_align(btnEnable, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
|
||||
txtEnable = lv_label_create(btnEnable, nullptr);
|
||||
SetEnableButtonState();
|
||||
|
||||
btnRecur = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnRecur->user_data = this;
|
||||
lv_obj_set_event_cb(btnRecur, btnEventHandler);
|
||||
lv_obj_set_size(btnRecur, 115, 50);
|
||||
lv_obj_align(btnRecur, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
|
||||
txtRecur = lv_label_create(btnRecur, nullptr);
|
||||
SetRecurButtonState();
|
||||
|
||||
btnInfo = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnInfo->user_data = this;
|
||||
lv_obj_set_event_cb(btnInfo, btnEventHandler);
|
||||
lv_obj_set_size(btnInfo, 50, 40);
|
||||
lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_CENTER, 0, -85);
|
||||
txtInfo = lv_label_create(btnInfo, nullptr);
|
||||
lv_label_set_text_static(txtInfo, "i");
|
||||
}
|
||||
|
||||
Alarm::~Alarm() {
|
||||
lv_obj_clean(lv_scr_act());
|
||||
}
|
||||
|
||||
void Alarm::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
|
||||
using Pinetime::Controllers::AlarmController;
|
||||
if (event == LV_EVENT_CLICKED) {
|
||||
if (obj == btnEnable) {
|
||||
if (alarmController.State() == AlarmController::AlarmState::Alerting) {
|
||||
alarmController.StopAlerting();
|
||||
} else if (alarmController.State() == AlarmController::AlarmState::Set) {
|
||||
alarmController.DisableAlarm();
|
||||
} else {
|
||||
alarmController.ScheduleAlarm();
|
||||
}
|
||||
SetEnableButtonState();
|
||||
return;
|
||||
}
|
||||
if (obj == btnInfo) {
|
||||
ShowInfo();
|
||||
return;
|
||||
}
|
||||
if (obj == btnMessage) {
|
||||
lv_obj_del(txtMessage);
|
||||
lv_obj_del(btnMessage);
|
||||
txtMessage = nullptr;
|
||||
btnMessage = nullptr;
|
||||
return;
|
||||
}
|
||||
// If any other button was pressed, disable the alarm
|
||||
// this is to make it clear that the alarm won't be set until it is turned back on
|
||||
if (alarmController.State() == AlarmController::AlarmState::Set) {
|
||||
alarmController.DisableAlarm();
|
||||
SetEnableButtonState();
|
||||
}
|
||||
if (obj == btnMinutesUp) {
|
||||
if (alarmMinutes >= 59) {
|
||||
alarmMinutes = 0;
|
||||
} else {
|
||||
alarmMinutes++;
|
||||
}
|
||||
UpdateAlarmTime();
|
||||
return;
|
||||
}
|
||||
if (obj == btnMinutesDown) {
|
||||
if (alarmMinutes == 0) {
|
||||
alarmMinutes = 59;
|
||||
} else {
|
||||
alarmMinutes--;
|
||||
}
|
||||
UpdateAlarmTime();
|
||||
return;
|
||||
}
|
||||
if (obj == btnHoursUp) {
|
||||
if (alarmHours >= 23) {
|
||||
alarmHours = 0;
|
||||
} else {
|
||||
alarmHours++;
|
||||
}
|
||||
UpdateAlarmTime();
|
||||
return;
|
||||
}
|
||||
if (obj == btnHoursDown) {
|
||||
if (alarmHours == 0) {
|
||||
alarmHours = 23;
|
||||
} else {
|
||||
alarmHours--;
|
||||
}
|
||||
UpdateAlarmTime();
|
||||
return;
|
||||
}
|
||||
if (obj == btnRecur) {
|
||||
ToggleRecurrence();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Alarm::UpdateAlarmTime() {
|
||||
lv_label_set_text_fmt(time, "%02d:%02d", alarmHours, alarmMinutes);
|
||||
alarmController.SetAlarmTime(alarmHours, alarmMinutes);
|
||||
}
|
||||
|
||||
void Alarm::SetAlerting() {
|
||||
SetEnableButtonState();
|
||||
}
|
||||
|
||||
void Alarm::SetEnableButtonState() {
|
||||
switch (alarmController.State()) {
|
||||
case AlarmController::AlarmState::Set:
|
||||
lv_label_set_text(txtEnable, "ON");
|
||||
lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN);
|
||||
break;
|
||||
case AlarmController::AlarmState::Not_Set:
|
||||
lv_label_set_text(txtEnable, "OFF");
|
||||
lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
|
||||
break;
|
||||
case AlarmController::AlarmState::Alerting:
|
||||
lv_label_set_text(txtEnable, Symbols::stop);
|
||||
lv_obj_set_style_local_bg_color(btnEnable, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
}
|
||||
}
|
||||
|
||||
void Alarm::ShowInfo() {
|
||||
btnMessage = lv_btn_create(lv_scr_act(), nullptr);
|
||||
btnMessage->user_data = this;
|
||||
lv_obj_set_event_cb(btnMessage, btnEventHandler);
|
||||
lv_obj_set_height(btnMessage, 200);
|
||||
lv_obj_set_width(btnMessage, 150);
|
||||
lv_obj_align(btnMessage, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
||||
txtMessage = lv_label_create(btnMessage, nullptr);
|
||||
lv_obj_set_style_local_bg_color(btnMessage, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_NAVY);
|
||||
|
||||
if (alarmController.State() == AlarmController::AlarmState::Set) {
|
||||
auto timeToAlarm = alarmController.SecondsToAlarm();
|
||||
|
||||
auto daysToAlarm = timeToAlarm / 86400;
|
||||
auto hrsToAlarm = (timeToAlarm % 86400) / 3600;
|
||||
auto minToAlarm = (timeToAlarm % 3600) / 60;
|
||||
auto secToAlarm = timeToAlarm % 60;
|
||||
|
||||
lv_label_set_text_fmt(
|
||||
txtMessage, "Time to\nalarm:\n%2d Days\n%2d Hours\n%2d Minutes\n%2d Seconds", daysToAlarm, hrsToAlarm, minToAlarm, secToAlarm);
|
||||
} else {
|
||||
lv_label_set_text(txtMessage, "Alarm\nis not\nset.");
|
||||
}
|
||||
}
|
||||
|
||||
void Alarm::SetRecurButtonState() {
|
||||
using Pinetime::Controllers::AlarmController;
|
||||
switch (alarmController.Recurrence()) {
|
||||
case AlarmController::RecurType::None:
|
||||
lv_label_set_text(txtRecur, "ONCE");
|
||||
break;
|
||||
case AlarmController::RecurType::Daily:
|
||||
lv_label_set_text(txtRecur, "DAILY");
|
||||
break;
|
||||
case AlarmController::RecurType::Weekdays:
|
||||
lv_label_set_text(txtRecur, "MON-FRI");
|
||||
}
|
||||
}
|
||||
|
||||
void Alarm::ToggleRecurrence() {
|
||||
using Pinetime::Controllers::AlarmController;
|
||||
switch (alarmController.Recurrence()) {
|
||||
case AlarmController::RecurType::None:
|
||||
alarmController.SetRecurrence(AlarmController::RecurType::Daily);
|
||||
break;
|
||||
case AlarmController::RecurType::Daily:
|
||||
alarmController.SetRecurrence(AlarmController::RecurType::Weekdays);
|
||||
break;
|
||||
case AlarmController::RecurType::Weekdays:
|
||||
alarmController.SetRecurrence(AlarmController::RecurType::None);
|
||||
}
|
||||
SetRecurButtonState();
|
||||
}
|
54
src/displayapp/screens/Alarm.h
Normal file
54
src/displayapp/screens/Alarm.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* Copyright (C) 2021 mruss77, Florian
|
||||
|
||||
This file is part of InfiniTime.
|
||||
|
||||
InfiniTime is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
InfiniTime is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "Screen.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "../LittleVgl.h"
|
||||
#include "components/alarm/AlarmController.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
class Alarm : public Screen {
|
||||
public:
|
||||
Alarm(DisplayApp* app, Controllers::AlarmController& alarmController);
|
||||
~Alarm() override;
|
||||
void SetAlerting();
|
||||
void OnButtonEvent(lv_obj_t* obj, lv_event_t event);
|
||||
|
||||
private:
|
||||
bool running;
|
||||
uint8_t alarmHours;
|
||||
uint8_t alarmMinutes;
|
||||
Controllers::AlarmController& alarmController;
|
||||
|
||||
lv_obj_t *time, *btnEnable, *txtEnable, *btnMinutesUp, *btnMinutesDown, *btnHoursUp, *btnHoursDown, *txtMinUp, *txtMinDown,
|
||||
*txtHrUp, *txtHrDown, *btnRecur, *txtRecur, *btnMessage, *txtMessage, *btnInfo, *txtInfo;
|
||||
|
||||
enum class EnableButtonState { On, Off, Alerting };
|
||||
void SetEnableButtonState();
|
||||
void SetRecurButtonState();
|
||||
void SetAlarm();
|
||||
void ShowInfo();
|
||||
void ToggleRecurrence();
|
||||
void UpdateAlarmTime();
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -58,7 +58,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
|||
{"2", Apps::Twos},
|
||||
{Symbols::chartLine, Apps::Motion},
|
||||
{Symbols::drum, Apps::Metronome},
|
||||
{"", Apps::None},
|
||||
{Symbols::clock, Apps::Alarm},
|
||||
}};
|
||||
|
||||
return std::make_unique<Screens::Tile>(1, 2, app, settingsController, batteryController, dateTimeController, applications);
|
||||
|
|
|
@ -55,8 +55,6 @@ BatteryInfo::~BatteryInfo() {
|
|||
|
||||
void BatteryInfo::Refresh() {
|
||||
|
||||
batteryController.Update();
|
||||
|
||||
batteryPercent = batteryController.PercentRemaining();
|
||||
batteryVoltage = batteryController.Voltage();
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ Metronome::~Metronome() {
|
|||
|
||||
void Metronome::Refresh() {
|
||||
if (metronomeStarted) {
|
||||
if (xTaskGetTickCount() - startTime > 60 * configTICK_RATE_HZ / bpm) {
|
||||
if (xTaskGetTickCount() - startTime > 60u * configTICK_RATE_HZ / static_cast<uint16_t>(bpm)) {
|
||||
startTime += 60 * configTICK_RATE_HZ / bpm;
|
||||
counter--;
|
||||
if (counter == 0) {
|
||||
|
|
|
@ -152,7 +152,7 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
|||
uint8_t notifNb,
|
||||
Modes mode,
|
||||
Pinetime::Controllers::AlertNotificationService& alertNotificationService)
|
||||
: notifNr {notifNr}, notifNb {notifNb}, mode {mode}, alertNotificationService {alertNotificationService} {
|
||||
: mode {mode}, alertNotificationService {alertNotificationService} {
|
||||
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), NULL);
|
||||
|
||||
lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x222222));
|
||||
|
|
|
@ -43,21 +43,13 @@ namespace Pinetime {
|
|||
void OnCallButtonEvent(lv_obj_t*, lv_event_t event);
|
||||
|
||||
private:
|
||||
uint8_t notifNr = 0;
|
||||
uint8_t notifNb = 0;
|
||||
char pageText[4];
|
||||
|
||||
lv_obj_t* container1;
|
||||
lv_obj_t* t1;
|
||||
lv_obj_t* l1;
|
||||
lv_obj_t* l2;
|
||||
lv_obj_t* bt_accept;
|
||||
lv_obj_t* bt_mute;
|
||||
lv_obj_t* bt_reject;
|
||||
lv_obj_t* label_accept;
|
||||
lv_obj_t* label_mute;
|
||||
lv_obj_t* label_reject;
|
||||
lv_obj_t* bottomPlaceholder;
|
||||
Modes mode;
|
||||
Pinetime::Controllers::AlertNotificationService& alertNotificationService;
|
||||
bool running = true;
|
||||
|
|
|
@ -50,8 +50,8 @@ std::unique_ptr<Screen> Settings::CreateScreen2() {
|
|||
std::array<Screens::List::Applications, 4> applications {{
|
||||
{Symbols::shoe, "Steps", Apps::SettingSteps},
|
||||
{Symbols::batteryHalf, "Battery", Apps::BatteryInfo},
|
||||
{Symbols::paintbrush, "PTS Colors", Apps::SettingPineTimeStyle},
|
||||
{Symbols::check, "Firmware", Apps::FirmwareValidation},
|
||||
{Symbols::list, "About", Apps::SysInfo},
|
||||
}};
|
||||
|
||||
return std::make_unique<Screens::List>(1, 3, app, settingsController, applications);
|
||||
|
@ -60,7 +60,7 @@ std::unique_ptr<Screen> Settings::CreateScreen2() {
|
|||
std::unique_ptr<Screen> Settings::CreateScreen3() {
|
||||
|
||||
std::array<Screens::List::Applications, 4> applications {{
|
||||
{Symbols::paintbrush, "PTS Colors", Apps::SettingPineTimeStyle},
|
||||
{Symbols::list, "About", Apps::SysInfo},
|
||||
{Symbols::none, "None", Apps::None},
|
||||
{Symbols::none, "None", Apps::None},
|
||||
{Symbols::none, "None", Apps::None},
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <legacy/nrf_drv_gpiote.h>
|
||||
#include <nrfx_log.h>
|
||||
#include <task.h>
|
||||
#include "drivers/PinMap.h"
|
||||
|
||||
using namespace Pinetime::Drivers;
|
||||
|
||||
|
@ -18,12 +19,12 @@ Cst816S::Cst816S(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster {twiMaste
|
|||
}
|
||||
|
||||
void Cst816S::Init() {
|
||||
nrf_gpio_cfg_output(pinReset);
|
||||
nrf_gpio_pin_set(pinReset);
|
||||
nrf_gpio_cfg_output(PinMap::Cst816sReset);
|
||||
nrf_gpio_pin_set(PinMap::Cst816sReset);
|
||||
vTaskDelay(50);
|
||||
nrf_gpio_pin_clear(pinReset);
|
||||
nrf_gpio_pin_clear(PinMap::Cst816sReset);
|
||||
vTaskDelay(5);
|
||||
nrf_gpio_pin_set(pinReset);
|
||||
nrf_gpio_pin_set(PinMap::Cst816sReset);
|
||||
vTaskDelay(50);
|
||||
|
||||
// Wake the touchpanel up
|
||||
|
@ -80,9 +81,9 @@ Cst816S::TouchInfos Cst816S::GetTouchInfo() {
|
|||
}
|
||||
|
||||
void Cst816S::Sleep() {
|
||||
nrf_gpio_pin_clear(pinReset);
|
||||
nrf_gpio_pin_clear(PinMap::Cst816sReset);
|
||||
vTaskDelay(5);
|
||||
nrf_gpio_pin_set(pinReset);
|
||||
nrf_gpio_pin_set(PinMap::Cst816sReset);
|
||||
vTaskDelay(50);
|
||||
static constexpr uint8_t sleepValue = 0x03;
|
||||
twiMaster.Write(twiAddress, 0xA5, &sleepValue, 1);
|
||||
|
|
|
@ -36,9 +36,6 @@ namespace Pinetime {
|
|||
void Wakeup();
|
||||
|
||||
private:
|
||||
static constexpr uint8_t pinIrq = 28;
|
||||
static constexpr uint8_t pinReset = 10;
|
||||
|
||||
// Unused/Unavailable commented out
|
||||
static constexpr uint8_t gestureIndex = 1;
|
||||
static constexpr uint8_t touchPointNumIndex = 2;
|
||||
|
|
38
src/drivers/PinMap.h
Normal file
38
src/drivers/PinMap.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
namespace Pinetime {
|
||||
namespace PinMap {
|
||||
|
||||
#ifdef WATCH_P8
|
||||
// COLMI P8
|
||||
static constexpr uint8_t Charging = 19;
|
||||
static constexpr uint8_t Cst816sReset = 13;
|
||||
static constexpr uint8_t Button = 17;
|
||||
#else
|
||||
// Pinetime
|
||||
static constexpr uint8_t Charging = 12;
|
||||
static constexpr uint8_t Cst816sReset = 10;
|
||||
static constexpr uint8_t Button = 13;
|
||||
#endif
|
||||
|
||||
static constexpr uint8_t Cst816sIrq = 28;
|
||||
static constexpr uint8_t PowerPresent = 19;
|
||||
|
||||
static constexpr uint8_t Motor = 16;
|
||||
|
||||
static constexpr uint8_t LcdBacklightLow = 14;
|
||||
static constexpr uint8_t LcdBacklightMedium = 22;
|
||||
static constexpr uint8_t LcdBacklightHigh = 23;
|
||||
|
||||
static constexpr uint8_t SpiSck = 2;
|
||||
static constexpr uint8_t SpiMosi = 3;
|
||||
static constexpr uint8_t SpiMiso = 4;
|
||||
|
||||
static constexpr uint8_t SpiFlashCsn = 5;
|
||||
static constexpr uint8_t SpiLcdCsn = 25;
|
||||
static constexpr uint8_t LcdDataCommand = 18;
|
||||
|
||||
static constexpr uint8_t TwiScl = 7;
|
||||
static constexpr uint8_t TwiSda = 6;
|
||||
}
|
||||
}
|
70
src/main.cpp
70
src/main.cpp
|
@ -43,7 +43,9 @@
|
|||
#include "drivers/St7789.h"
|
||||
#include "drivers/TwiMaster.h"
|
||||
#include "drivers/Cst816s.h"
|
||||
#include "drivers/PinMap.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "drivers/PinMap.h"
|
||||
#include "touchhandler/TouchHandler.h"
|
||||
|
||||
#if NRF_LOG_ENABLED
|
||||
|
@ -54,14 +56,6 @@ Pinetime::Logging::NrfLogger logger;
|
|||
Pinetime::Logging::DummyLogger logger;
|
||||
#endif
|
||||
|
||||
static constexpr uint8_t pinSpiSck = 2;
|
||||
static constexpr uint8_t pinSpiMosi = 3;
|
||||
static constexpr uint8_t pinSpiMiso = 4;
|
||||
static constexpr uint8_t pinSpiFlashCsn = 5;
|
||||
static constexpr uint8_t pinLcdCsn = 25;
|
||||
static constexpr uint8_t pinLcdDataCommand = 18;
|
||||
static constexpr uint8_t pinTwiScl = 7;
|
||||
static constexpr uint8_t pinTwiSda = 6;
|
||||
static constexpr uint8_t touchPanelTwiAddress = 0x15;
|
||||
static constexpr uint8_t motionSensorTwiAddress = 0x18;
|
||||
static constexpr uint8_t heartRateSensorTwiAddress = 0x44;
|
||||
|
@ -70,33 +64,30 @@ Pinetime::Drivers::SpiMaster spi {Pinetime::Drivers::SpiMaster::SpiModule::SPI0,
|
|||
{Pinetime::Drivers::SpiMaster::BitOrder::Msb_Lsb,
|
||||
Pinetime::Drivers::SpiMaster::Modes::Mode3,
|
||||
Pinetime::Drivers::SpiMaster::Frequencies::Freq8Mhz,
|
||||
pinSpiSck,
|
||||
pinSpiMosi,
|
||||
pinSpiMiso}};
|
||||
Pinetime::PinMap::SpiSck,
|
||||
Pinetime::PinMap::SpiMosi,
|
||||
Pinetime::PinMap::SpiMiso}};
|
||||
|
||||
Pinetime::Drivers::Spi lcdSpi {spi, pinLcdCsn};
|
||||
Pinetime::Drivers::St7789 lcd {lcdSpi, pinLcdDataCommand};
|
||||
Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn};
|
||||
Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand};
|
||||
|
||||
Pinetime::Drivers::Spi flashSpi {spi, pinSpiFlashCsn};
|
||||
Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn};
|
||||
Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi};
|
||||
|
||||
// The TWI device should work @ up to 400Khz but there is a HW bug which prevent it from
|
||||
// respecting correct timings. According to erratas heet, this magic value makes it run
|
||||
// at ~390Khz with correct timings.
|
||||
static constexpr uint32_t MaxTwiFrequencyWithoutHardwareBug {0x06200000};
|
||||
Pinetime::Drivers::TwiMaster twiMaster {NRF_TWIM1, MaxTwiFrequencyWithoutHardwareBug, pinTwiSda, pinTwiScl};
|
||||
Pinetime::Drivers::TwiMaster twiMaster {NRF_TWIM1, MaxTwiFrequencyWithoutHardwareBug, Pinetime::PinMap::TwiSda, Pinetime::PinMap::TwiScl};
|
||||
Pinetime::Drivers::Cst816S touchPanel {twiMaster, touchPanelTwiAddress};
|
||||
#ifdef PINETIME_IS_RECOVERY
|
||||
static constexpr bool isFactory = true;
|
||||
#include "displayapp/DummyLittleVgl.h"
|
||||
#include "displayapp/DisplayAppRecovery.h"
|
||||
Pinetime::Components::LittleVgl lvgl {lcd, touchPanel};
|
||||
#else
|
||||
static constexpr bool isFactory = false;
|
||||
#include "displayapp/LittleVgl.h"
|
||||
#include "displayapp/DisplayApp.h"
|
||||
Pinetime::Components::LittleVgl lvgl {lcd, touchPanel};
|
||||
#endif
|
||||
Pinetime::Components::LittleVgl lvgl {lcd, touchPanel};
|
||||
|
||||
Pinetime::Drivers::Bma421 motionSensor {twiMaster, motionSensorTwiAddress};
|
||||
Pinetime::Drivers::Hrs3300 heartRateSensor {twiMaster, heartRateSensorTwiAddress};
|
||||
|
@ -105,10 +96,8 @@ TimerHandle_t debounceTimer;
|
|||
TimerHandle_t debounceChargeTimer;
|
||||
Pinetime::Controllers::Battery batteryController;
|
||||
Pinetime::Controllers::Ble bleController;
|
||||
void ble_manager_set_ble_connection_callback(void (*connection)());
|
||||
void ble_manager_set_ble_disconnection_callback(void (*disconnection)());
|
||||
static constexpr uint8_t pinTouchIrq = 28;
|
||||
static constexpr uint8_t pinPowerPresentIrq = 19;
|
||||
static constexpr uint8_t pinTouchIrq = Pinetime::PinMap::Cst816sIrq;
|
||||
static constexpr uint8_t pinPowerPresentIrq = Pinetime::PinMap::PowerPresent;
|
||||
|
||||
Pinetime::Controllers::HeartRateController heartRateController;
|
||||
Pinetime::Applications::HeartRateTask heartRateApp(heartRateSensor, heartRateController);
|
||||
|
@ -119,13 +108,13 @@ Pinetime::Drivers::WatchdogView watchdogView(watchdog);
|
|||
Pinetime::Controllers::NotificationManager notificationManager;
|
||||
Pinetime::Controllers::MotionController motionController;
|
||||
Pinetime::Controllers::TimerController timerController;
|
||||
Pinetime::Controllers::AlarmController alarmController {dateTimeController};
|
||||
Pinetime::Controllers::TouchHandler touchHandler(touchPanel, lvgl);
|
||||
|
||||
Pinetime::Controllers::FS fs {spiNorFlash};
|
||||
Pinetime::Controllers::Settings settingsController {fs};
|
||||
Pinetime::Controllers::MotorController motorController {settingsController};
|
||||
|
||||
|
||||
Pinetime::Applications::DisplayApp displayApp(lcd,
|
||||
lvgl,
|
||||
touchPanel,
|
||||
|
@ -139,6 +128,7 @@ Pinetime::Applications::DisplayApp displayApp(lcd,
|
|||
motorController,
|
||||
motionController,
|
||||
timerController,
|
||||
alarmController,
|
||||
touchHandler);
|
||||
|
||||
Pinetime::System::SystemTask systemTask(spi,
|
||||
|
@ -151,6 +141,7 @@ Pinetime::System::SystemTask systemTask(spi,
|
|||
bleController,
|
||||
dateTimeController,
|
||||
timerController,
|
||||
alarmController,
|
||||
watchdog,
|
||||
notificationManager,
|
||||
motorController,
|
||||
|
@ -164,15 +155,25 @@ Pinetime::System::SystemTask systemTask(spi,
|
|||
fs,
|
||||
touchHandler);
|
||||
|
||||
/* Variable Declarations for variables in noinit SRAM
|
||||
Increment NoInit_MagicValue upon adding variables to this area
|
||||
*/
|
||||
extern uint32_t __start_noinit_data;
|
||||
extern uint32_t __stop_noinit_data;
|
||||
static constexpr uint32_t NoInit_MagicValue = 0xDEAD0000;
|
||||
uint32_t NoInit_MagicWord __attribute__((section(".noinit")));
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> NoInit_BackUpTime __attribute__((section(".noinit")));
|
||||
|
||||
|
||||
void nrfx_gpiote_evt_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
|
||||
if (pin == pinTouchIrq) {
|
||||
if (pin == Pinetime::PinMap::Cst816sIrq) {
|
||||
systemTask.OnTouchEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
if (pin == pinPowerPresentIrq and action == NRF_GPIOTE_POLARITY_TOGGLE) {
|
||||
if (pin == Pinetime::PinMap::PowerPresent and action == NRF_GPIOTE_POLARITY_TOGGLE) {
|
||||
xTimerStartFromISR(debounceChargeTimer, &xHigherPriorityTaskWoken);
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
return;
|
||||
|
@ -305,18 +306,18 @@ int main(void) {
|
|||
nrf_drv_clock_init();
|
||||
|
||||
// Unblock i2c?
|
||||
nrf_gpio_cfg(pinTwiScl,
|
||||
nrf_gpio_cfg(Pinetime::PinMap::TwiScl,
|
||||
NRF_GPIO_PIN_DIR_OUTPUT,
|
||||
NRF_GPIO_PIN_INPUT_DISCONNECT,
|
||||
NRF_GPIO_PIN_NOPULL,
|
||||
NRF_GPIO_PIN_S0D1,
|
||||
NRF_GPIO_PIN_NOSENSE);
|
||||
nrf_gpio_pin_set(pinTwiScl);
|
||||
nrf_gpio_pin_set(Pinetime::PinMap::TwiScl);
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
nrf_gpio_pin_toggle(pinTwiScl);
|
||||
nrf_gpio_pin_toggle(Pinetime::PinMap::TwiScl);
|
||||
nrf_delay_us(5);
|
||||
}
|
||||
nrf_gpio_cfg_default(pinTwiScl);
|
||||
nrf_gpio_cfg_default(Pinetime::PinMap::TwiScl);
|
||||
|
||||
debounceTimer = xTimerCreate("debounceTimer", 200, pdFALSE, (void*) 0, DebounceTimerCallback);
|
||||
debounceChargeTimer = xTimerCreate("debounceTimerCharge", 200, pdFALSE, (void*) 0, DebounceTimerChargeCallback);
|
||||
|
@ -324,6 +325,15 @@ int main(void) {
|
|||
// retrieve version stored by bootloader
|
||||
Pinetime::BootloaderVersion::SetVersion(NRF_TIMER2->CC[0]);
|
||||
|
||||
|
||||
if (NoInit_MagicWord == NoInit_MagicValue) {
|
||||
dateTimeController.SetCurrentTime(NoInit_BackUpTime);
|
||||
} else {
|
||||
//Clear Memory to known state
|
||||
memset(&__start_noinit_data,0,(uintptr_t)&__stop_noinit_data-(uintptr_t)&__start_noinit_data);
|
||||
NoInit_MagicWord = NoInit_MagicValue;
|
||||
}
|
||||
|
||||
lvgl.Init();
|
||||
|
||||
systemTask.Start();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <components/brightness/BrightnessController.h>
|
||||
#include <algorithm>
|
||||
#include "recoveryImage.h"
|
||||
#include "drivers/PinMap.h"
|
||||
|
||||
#include "displayapp/icons/infinitime/infinitime-nb.c"
|
||||
#include "components/rle/RleDecoder.h"
|
||||
|
@ -27,12 +28,6 @@ Pinetime::Logging::NrfLogger logger;
|
|||
Pinetime::Logging::DummyLogger logger;
|
||||
#endif
|
||||
|
||||
static constexpr uint8_t pinSpiSck = 2;
|
||||
static constexpr uint8_t pinSpiMosi = 3;
|
||||
static constexpr uint8_t pinSpiMiso = 4;
|
||||
static constexpr uint8_t pinSpiFlashCsn = 5;
|
||||
static constexpr uint8_t pinLcdCsn = 25;
|
||||
static constexpr uint8_t pinLcdDataCommand = 18;
|
||||
|
||||
static constexpr uint8_t displayWidth = 240;
|
||||
static constexpr uint8_t displayHeight = 240;
|
||||
|
@ -45,14 +40,14 @@ Pinetime::Drivers::SpiMaster spi {Pinetime::Drivers::SpiMaster::SpiModule::SPI0,
|
|||
{Pinetime::Drivers::SpiMaster::BitOrder::Msb_Lsb,
|
||||
Pinetime::Drivers::SpiMaster::Modes::Mode3,
|
||||
Pinetime::Drivers::SpiMaster::Frequencies::Freq8Mhz,
|
||||
pinSpiSck,
|
||||
pinSpiMosi,
|
||||
pinSpiMiso}};
|
||||
Pinetime::Drivers::Spi flashSpi {spi, pinSpiFlashCsn};
|
||||
Pinetime::PinMap::SpiSck,
|
||||
Pinetime::PinMap::SpiMosi,
|
||||
Pinetime::PinMap::SpiMiso}};
|
||||
Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn};
|
||||
Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi};
|
||||
|
||||
Pinetime::Drivers::Spi lcdSpi {spi, pinLcdCsn};
|
||||
Pinetime::Drivers::St7789 lcd {lcdSpi, pinLcdDataCommand};
|
||||
Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn};
|
||||
Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand};
|
||||
|
||||
Pinetime::Components::Gfx gfx {lcd};
|
||||
Pinetime::Controllers::BrightnessController brightnessController;
|
||||
|
|
|
@ -20,7 +20,11 @@ namespace Pinetime {
|
|||
EnableSleeping,
|
||||
DisableSleeping,
|
||||
OnNewDay,
|
||||
OnChargingEvent
|
||||
OnChargingEvent,
|
||||
SetOffAlarm,
|
||||
StopRinging,
|
||||
MeasureBatteryTimerExpired,
|
||||
BatteryMeasurementDone,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,8 +21,10 @@
|
|||
#include "drivers/SpiNorFlash.h"
|
||||
#include "drivers/TwiMaster.h"
|
||||
#include "drivers/Hrs3300.h"
|
||||
#include "drivers/PinMap.h"
|
||||
#include "main.h"
|
||||
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace Pinetime::System;
|
||||
|
@ -47,6 +49,11 @@ void IdleTimerCallback(TimerHandle_t xTimer) {
|
|||
sysTask->OnIdle();
|
||||
}
|
||||
|
||||
void MeasureBatteryTimerCallback(TimerHandle_t xTimer) {
|
||||
auto* sysTask = static_cast<SystemTask*>(pvTimerGetTimerID(xTimer));
|
||||
sysTask->PushMessage(Pinetime::System::Messages::MeasureBatteryTimerExpired);
|
||||
}
|
||||
|
||||
SystemTask::SystemTask(Drivers::SpiMaster& spi,
|
||||
Drivers::St7789& lcd,
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
|
||||
|
@ -57,6 +64,7 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi,
|
|||
Controllers::Ble& bleController,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::TimerController& timerController,
|
||||
Controllers::AlarmController& alarmController,
|
||||
Drivers::Watchdog& watchdog,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::MotorController& motorController,
|
||||
|
@ -79,6 +87,7 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi,
|
|||
bleController {bleController},
|
||||
dateTimeController {dateTimeController},
|
||||
timerController {timerController},
|
||||
alarmController {alarmController},
|
||||
watchdog {watchdog},
|
||||
notificationManager {notificationManager},
|
||||
motorController {motorController},
|
||||
|
@ -121,17 +130,18 @@ void SystemTask::Work() {
|
|||
fs.Init();
|
||||
|
||||
nimbleController.Init();
|
||||
nimbleController.StartAdvertising();
|
||||
lcd.Init();
|
||||
|
||||
twiMaster.Init();
|
||||
touchPanel.Init();
|
||||
dateTimeController.Register(this);
|
||||
batteryController.Init();
|
||||
batteryController.Register(this);
|
||||
batteryController.Update();
|
||||
motorController.Init();
|
||||
motionSensor.SoftReset();
|
||||
timerController.Register(this);
|
||||
timerController.Init();
|
||||
alarmController.Init(this);
|
||||
|
||||
// Reset the TWI device because the motion sensor chip most probably crashed it...
|
||||
twiMaster.Sleep();
|
||||
|
@ -144,13 +154,11 @@ void SystemTask::Work() {
|
|||
displayApp.Register(this);
|
||||
displayApp.Start();
|
||||
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::UpdateBatteryLevel);
|
||||
|
||||
heartRateSensor.Init();
|
||||
heartRateSensor.Disable();
|
||||
heartRateApp.Start();
|
||||
|
||||
nrf_gpio_cfg_sense_input(pinButton, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pulldown, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_High);
|
||||
nrf_gpio_cfg_sense_input(PinMap::Button, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pulldown, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_High);
|
||||
nrf_gpio_cfg_output(15);
|
||||
nrf_gpio_pin_set(15);
|
||||
|
||||
|
@ -161,9 +169,9 @@ void SystemTask::Work() {
|
|||
pinConfig.sense = (nrf_gpiote_polarity_t) NRF_GPIOTE_POLARITY_HITOLO;
|
||||
pinConfig.pull = (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pulldown;
|
||||
|
||||
nrfx_gpiote_in_init(pinButton, &pinConfig, nrfx_gpiote_evt_handler);
|
||||
nrfx_gpiote_in_init(PinMap::Button, &pinConfig, nrfx_gpiote_evt_handler);
|
||||
|
||||
nrf_gpio_cfg_sense_input(pinTouchIrq, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_Low);
|
||||
nrf_gpio_cfg_sense_input(PinMap::Cst816sIrq, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_Low);
|
||||
|
||||
pinConfig.skip_gpio_setup = true;
|
||||
pinConfig.hi_accuracy = false;
|
||||
|
@ -171,24 +179,26 @@ void SystemTask::Work() {
|
|||
pinConfig.sense = (nrf_gpiote_polarity_t) NRF_GPIOTE_POLARITY_HITOLO;
|
||||
pinConfig.pull = (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup;
|
||||
|
||||
nrfx_gpiote_in_init(pinTouchIrq, &pinConfig, nrfx_gpiote_evt_handler);
|
||||
nrfx_gpiote_in_init(PinMap::Cst816sIrq, &pinConfig, nrfx_gpiote_evt_handler);
|
||||
|
||||
pinConfig.sense = NRF_GPIOTE_POLARITY_TOGGLE;
|
||||
pinConfig.pull = NRF_GPIO_PIN_NOPULL;
|
||||
pinConfig.is_watcher = false;
|
||||
pinConfig.hi_accuracy = false;
|
||||
pinConfig.skip_gpio_setup = true;
|
||||
nrfx_gpiote_in_init(pinPowerPresentIrq, &pinConfig, nrfx_gpiote_evt_handler);
|
||||
nrfx_gpiote_in_init(PinMap::PowerPresent, &pinConfig, nrfx_gpiote_evt_handler);
|
||||
|
||||
if (nrf_gpio_pin_read(pinPowerPresentIrq)) {
|
||||
nrf_gpio_cfg_sense_input(pinPowerPresentIrq, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_LOW);
|
||||
if (nrf_gpio_pin_read(PinMap::PowerPresent)) {
|
||||
nrf_gpio_cfg_sense_input(PinMap::PowerPresent, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_LOW);
|
||||
} else {
|
||||
nrf_gpio_cfg_sense_input(pinPowerPresentIrq, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH);
|
||||
nrf_gpio_cfg_sense_input(PinMap::PowerPresent, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH);
|
||||
}
|
||||
|
||||
idleTimer = xTimerCreate("idleTimer", pdMS_TO_TICKS(2000), pdFALSE, this, IdleTimerCallback);
|
||||
dimTimer = xTimerCreate("dimTimer", pdMS_TO_TICKS(settingsController.GetScreenTimeOut() - 2000), pdFALSE, this, DimTimerCallback);
|
||||
measureBatteryTimer = xTimerCreate("measureBattery", batteryMeasurementPeriod, pdTRUE, this, MeasureBatteryTimerCallback);
|
||||
xTimerStart(dimTimer, 0);
|
||||
xTimerStart(measureBatteryTimer, portMAX_DELAY);
|
||||
|
||||
// Suppress endless loop diagnostic
|
||||
#pragma clang diagnostic push
|
||||
|
@ -198,11 +208,6 @@ void SystemTask::Work() {
|
|||
|
||||
uint8_t msg;
|
||||
if (xQueueReceive(systemTasksMsgQueue, &msg, 100)) {
|
||||
|
||||
batteryController.Update();
|
||||
// the battery does not emit events when changing charge levels, so we piggyback
|
||||
// on any system event to read and update the current values
|
||||
|
||||
Messages message = static_cast<Messages>(msg);
|
||||
switch (message) {
|
||||
case Messages::EnableSleeping:
|
||||
|
@ -226,15 +231,16 @@ void SystemTask::Work() {
|
|||
touchPanel.Wakeup();
|
||||
}
|
||||
|
||||
nimbleController.StartAdvertising();
|
||||
xTimerStart(dimTimer, 0);
|
||||
spiNorFlash.Wakeup();
|
||||
lcd.Wakeup();
|
||||
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToRunning);
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::UpdateBatteryLevel);
|
||||
heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::WakeUp);
|
||||
|
||||
if (!bleController.IsConnected())
|
||||
nimbleController.RestartFastAdv();
|
||||
|
||||
isSleeping = false;
|
||||
isWakingUp = false;
|
||||
isDimmed = false;
|
||||
|
@ -275,6 +281,16 @@ void SystemTask::Work() {
|
|||
motorController.RunForDuration(35);
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::TimerDone);
|
||||
break;
|
||||
case Messages::SetOffAlarm:
|
||||
if (isSleeping && !isWakingUp) {
|
||||
GoToRunning();
|
||||
}
|
||||
motorController.StartRinging();
|
||||
displayApp.PushMessage(Pinetime::Applications::Display::Messages::AlarmTriggered);
|
||||
break;
|
||||
case Messages::StopRinging:
|
||||
motorController.StopRinging();
|
||||
break;
|
||||
case Messages::BleConnected:
|
||||
ReloadIdleTimer();
|
||||
isBleDiscoveryTimerRunning = true;
|
||||
|
@ -327,8 +343,18 @@ void SystemTask::Work() {
|
|||
stepCounterMustBeReset = true;
|
||||
break;
|
||||
case Messages::OnChargingEvent:
|
||||
batteryController.Update();
|
||||
motorController.RunForDuration(15);
|
||||
// Battery level is updated on every message - there's no need to do anything
|
||||
break;
|
||||
case Messages::MeasureBatteryTimerExpired:
|
||||
sendBatteryNotification = true;
|
||||
batteryController.Update();
|
||||
break;
|
||||
case Messages::BatteryMeasurementDone:
|
||||
if (sendBatteryNotification) {
|
||||
sendBatteryNotification = false;
|
||||
nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -340,22 +366,18 @@ void SystemTask::Work() {
|
|||
if (bleDiscoveryTimer == 0) {
|
||||
isBleDiscoveryTimerRunning = false;
|
||||
// Services discovery is deffered from 3 seconds to avoid the conflicts between the host communicating with the
|
||||
// tharget and vice-versa. I'm not sure if this is the right way to handle this...
|
||||
// target and vice-versa. I'm not sure if this is the right way to handle this...
|
||||
nimbleController.StartDiscovery();
|
||||
} else {
|
||||
bleDiscoveryTimer--;
|
||||
}
|
||||
}
|
||||
|
||||
if (xTaskGetTickCount() - batteryNotificationTick > batteryNotificationPeriod) {
|
||||
nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining());
|
||||
batteryNotificationTick = xTaskGetTickCount();
|
||||
}
|
||||
|
||||
monitor.Process();
|
||||
uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG);
|
||||
dateTimeController.UpdateTime(systick_counter);
|
||||
if (!nrf_gpio_pin_read(pinButton))
|
||||
NoInit_BackUpTime = dateTimeController.CurrentDateTime();
|
||||
if (!nrf_gpio_pin_read(PinMap::Button))
|
||||
watchdog.Kick();
|
||||
}
|
||||
// Clear diagnostic suppression
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <heartratetask/HeartRateTask.h>
|
||||
#include <components/settings/Settings.h>
|
||||
#include <drivers/Bma421.h>
|
||||
#include <drivers/PinMap.h>
|
||||
#include <components/motion/MotionController.h>
|
||||
|
||||
#include "SystemMonitor.h"
|
||||
|
@ -16,6 +17,7 @@
|
|||
#include "components/ble/NotificationManager.h"
|
||||
#include "components/motor/MotorController.h"
|
||||
#include "components/timer/TimerController.h"
|
||||
#include "components/alarm/AlarmController.h"
|
||||
#include "components/fs/FS.h"
|
||||
#include "touchhandler/TouchHandler.h"
|
||||
|
||||
|
@ -31,6 +33,7 @@
|
|||
#include "drivers/Watchdog.h"
|
||||
#include "Messages.h"
|
||||
|
||||
extern std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> NoInit_BackUpTime;
|
||||
namespace Pinetime {
|
||||
namespace Drivers {
|
||||
class Cst816S;
|
||||
|
@ -56,6 +59,7 @@ namespace Pinetime {
|
|||
Controllers::Ble& bleController,
|
||||
Controllers::DateTime& dateTimeController,
|
||||
Controllers::TimerController& timerController,
|
||||
Controllers::AlarmController& alarmController,
|
||||
Drivers::Watchdog& watchdog,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Controllers::MotorController& motorController,
|
||||
|
@ -100,6 +104,7 @@ namespace Pinetime {
|
|||
Pinetime::Controllers::Ble& bleController;
|
||||
Pinetime::Controllers::DateTime& dateTimeController;
|
||||
Pinetime::Controllers::TimerController& timerController;
|
||||
Pinetime::Controllers::AlarmController& alarmController;
|
||||
QueueHandle_t systemTasksMsgQueue;
|
||||
std::atomic<bool> isSleeping {false};
|
||||
std::atomic<bool> isGoingToSleep {false};
|
||||
|
@ -120,15 +125,6 @@ namespace Pinetime {
|
|||
Pinetime::Controllers::TouchHandler& touchHandler;
|
||||
Pinetime::Controllers::NimbleController nimbleController;
|
||||
|
||||
static constexpr uint8_t pinSpiSck = 2;
|
||||
static constexpr uint8_t pinSpiMosi = 3;
|
||||
static constexpr uint8_t pinSpiMiso = 4;
|
||||
static constexpr uint8_t pinSpiCsn = 25;
|
||||
static constexpr uint8_t pinLcdDataCommand = 18;
|
||||
static constexpr uint8_t pinButton = 13;
|
||||
static constexpr uint8_t pinTouchIrq = 28;
|
||||
static constexpr uint8_t pinPowerPresentIrq = 19;
|
||||
|
||||
static void Process(void* instance);
|
||||
void Work();
|
||||
void ReloadIdleTimer();
|
||||
|
@ -136,13 +132,15 @@ namespace Pinetime {
|
|||
uint8_t bleDiscoveryTimer = 0;
|
||||
TimerHandle_t dimTimer;
|
||||
TimerHandle_t idleTimer;
|
||||
TimerHandle_t measureBatteryTimer;
|
||||
bool sendBatteryNotification = false;
|
||||
bool doNotGoToSleep = false;
|
||||
|
||||
void GoToRunning();
|
||||
void UpdateMotion();
|
||||
bool stepCounterMustBeReset = false;
|
||||
static constexpr TickType_t batteryNotificationPeriod = 1000 * 60 * 10; // 1 tick ~= 1ms. 1ms * 60 * 10 = 10 minutes
|
||||
TickType_t batteryNotificationTick = 0;
|
||||
static constexpr TickType_t batteryMeasurementPeriod = pdMS_TO_TICKS(10 * 60 * 1000);
|
||||
TickType_t lastBatteryNotificationTime = 0;
|
||||
|
||||
#if configUSE_TRACE_FACILITY == 1
|
||||
SystemMonitor<FreeRtosMonitor> monitor;
|
||||
|
|
Loading…
Reference in a new issue