Skip to content

Commit 4a5b5f9

Browse files
authored
Merge pull request #782 from Riksu9000/newer_buttonhandler
Newer ButtonHandler
2 parents cfc11ea + 60a717b commit 4a5b5f9

10 files changed

Lines changed: 211 additions & 33 deletions

File tree

src/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ list(APPEND SOURCE_FILES
507507
components/heartrate/Ptagc.cpp
508508
components/heartrate/HeartRateController.cpp
509509

510+
buttonhandler/ButtonHandler.cpp
510511
touchhandler/TouchHandler.cpp
511512
)
512513

@@ -567,6 +568,7 @@ list(APPEND RECOVERY_SOURCE_FILES
567568
components/heartrate/Ptagc.cpp
568569
components/motor/MotorController.cpp
569570
components/fs/FS.cpp
571+
buttonhandler/ButtonHandler.cpp
570572
touchhandler/TouchHandler.cpp
571573
)
572574

@@ -681,6 +683,7 @@ set(INCLUDE_FILES
681683
components/heartrate/Ptagc.h
682684
components/heartrate/HeartRateController.h
683685
components/motor/MotorController.h
686+
buttonhandler/ButtonHandler.h
684687
touchhandler/TouchHandler.h
685688
)
686689

src/buttonhandler/ButtonActions.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
3+
namespace Pinetime {
4+
namespace Controllers {
5+
enum class ButtonActions { None, Click, DoubleClick, LongPress, LongerPress };
6+
}
7+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include "ButtonHandler.h"
2+
3+
using namespace Pinetime::Controllers;
4+
5+
void ButtonTimerCallback(TimerHandle_t xTimer) {
6+
auto* sysTask = static_cast<Pinetime::System::SystemTask*>(pvTimerGetTimerID(xTimer));
7+
sysTask->PushMessage(Pinetime::System::Messages::HandleButtonTimerEvent);
8+
}
9+
10+
void ButtonHandler::Init(Pinetime::System::SystemTask* systemTask) {
11+
buttonTimer = xTimerCreate("buttonTimer", 0, pdFALSE, systemTask, ButtonTimerCallback);
12+
}
13+
14+
ButtonActions ButtonHandler::HandleEvent(Events event) {
15+
static constexpr TickType_t doubleClickTime = pdMS_TO_TICKS(200);
16+
static constexpr TickType_t longPressTime = pdMS_TO_TICKS(400);
17+
static constexpr TickType_t longerPressTime = pdMS_TO_TICKS(2000);
18+
19+
if (event == Events::Press) {
20+
buttonPressed = true;
21+
} else if (event == Events::Release) {
22+
releaseTime = xTaskGetTickCount();
23+
buttonPressed = false;
24+
}
25+
26+
switch (state) {
27+
case States::Idle:
28+
if (event == Events::Press) {
29+
xTimerChangePeriod(buttonTimer, doubleClickTime, 0);
30+
xTimerStart(buttonTimer, 0);
31+
state = States::Pressed;
32+
}
33+
break;
34+
case States::Pressed:
35+
if (event == Events::Press) {
36+
if (xTaskGetTickCount() - releaseTime < doubleClickTime) {
37+
xTimerStop(buttonTimer, 0);
38+
state = States::Idle;
39+
return ButtonActions::DoubleClick;
40+
}
41+
} else if (event == Events::Release) {
42+
xTimerChangePeriod(buttonTimer, doubleClickTime, 0);
43+
xTimerStart(buttonTimer, 0);
44+
} else if (event == Events::Timer) {
45+
if (buttonPressed) {
46+
xTimerChangePeriod(buttonTimer, longPressTime - doubleClickTime, 0);
47+
xTimerStart(buttonTimer, 0);
48+
state = States::Holding;
49+
} else {
50+
state = States::Idle;
51+
return ButtonActions::Click;
52+
}
53+
}
54+
break;
55+
case States::Holding:
56+
if (event == Events::Release) {
57+
xTimerStop(buttonTimer, 0);
58+
state = States::Idle;
59+
return ButtonActions::Click;
60+
} else if (event == Events::Timer) {
61+
xTimerChangePeriod(buttonTimer, longerPressTime - longPressTime - doubleClickTime, 0);
62+
xTimerStart(buttonTimer, 0);
63+
state = States::LongHeld;
64+
return ButtonActions::LongPress;
65+
}
66+
break;
67+
case States::LongHeld:
68+
if (event == Events::Release) {
69+
xTimerStop(buttonTimer, 0);
70+
state = States::Idle;
71+
} else if (event == Events::Timer) {
72+
state = States::Idle;
73+
return ButtonActions::LongerPress;
74+
}
75+
break;
76+
}
77+
return ButtonActions::None;
78+
}

src/buttonhandler/ButtonHandler.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
3+
#include "ButtonActions.h"
4+
#include "systemtask/SystemTask.h"
5+
#include <FreeRTOS.h>
6+
#include <timers.h>
7+
8+
namespace Pinetime {
9+
namespace Controllers {
10+
class ButtonHandler {
11+
public:
12+
enum class Events : uint8_t { Press, Release, Timer };
13+
void Init(Pinetime::System::SystemTask* systemTask);
14+
ButtonActions HandleEvent(Events event);
15+
16+
private:
17+
enum class States : uint8_t { Idle, Pressed, Holding, LongHeld };
18+
TickType_t releaseTime = 0;
19+
TimerHandle_t buttonTimer;
20+
bool buttonPressed = false;
21+
States state = States::Idle;
22+
};
23+
}
24+
}

src/displayapp/DisplayApp.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,20 @@ void DisplayApp::Refresh() {
260260
}
261261
}
262262
break;
263+
case Messages::ButtonLongPressed:
264+
if (currentApp != Apps::Clock) {
265+
LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::Down);
266+
}
267+
break;
268+
case Messages::ButtonLongerPressed:
269+
// Create reboot app and open it instead
270+
LoadApp(Apps::SysInfo, DisplayApp::FullRefreshDirections::Up);
271+
break;
272+
case Messages::ButtonDoubleClicked:
273+
if (currentApp != Apps::Notifications && currentApp != Apps::NotificationsPreview) {
274+
LoadApp(Apps::Notifications, DisplayApp::FullRefreshDirections::Down);
275+
}
276+
break;
263277

264278
case Messages::BleFirmwareUpdateStarted:
265279
LoadApp(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down);

src/displayapp/Messages.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ namespace Pinetime {
99
UpdateBleConnection,
1010
TouchEvent,
1111
ButtonPushed,
12+
ButtonLongPressed,
13+
ButtonLongerPressed,
14+
ButtonDoubleClicked,
1215
NewNotification,
1316
TimerDone,
1417
BleFirmwareUpdateStarted,

src/main.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include "systemtask/SystemTask.h"
4848
#include "drivers/PinMap.h"
4949
#include "touchhandler/TouchHandler.h"
50+
#include "buttonhandler/ButtonHandler.h"
5051

5152
#if NRF_LOG_ENABLED
5253
#include "logging/NrfLogger.h"
@@ -96,8 +97,6 @@ TimerHandle_t debounceTimer;
9697
TimerHandle_t debounceChargeTimer;
9798
Pinetime::Controllers::Battery batteryController;
9899
Pinetime::Controllers::Ble bleController;
99-
static constexpr uint8_t pinTouchIrq = Pinetime::PinMap::Cst816sIrq;
100-
static constexpr uint8_t pinPowerPresentIrq = Pinetime::PinMap::PowerPresent;
101100

102101
Pinetime::Controllers::HeartRateController heartRateController;
103102
Pinetime::Applications::HeartRateTask heartRateApp(heartRateSensor, heartRateController);
@@ -110,6 +109,7 @@ Pinetime::Controllers::MotionController motionController;
110109
Pinetime::Controllers::TimerController timerController;
111110
Pinetime::Controllers::AlarmController alarmController {dateTimeController};
112111
Pinetime::Controllers::TouchHandler touchHandler(touchPanel, lvgl);
112+
Pinetime::Controllers::ButtonHandler buttonHandler;
113113

114114
Pinetime::Controllers::FS fs {spiNorFlash};
115115
Pinetime::Controllers::Settings settingsController {fs};
@@ -153,7 +153,8 @@ Pinetime::System::SystemTask systemTask(spi,
153153
displayApp,
154154
heartRateApp,
155155
fs,
156-
touchHandler);
156+
touchHandler,
157+
buttonHandler);
157158

158159
/* Variable Declarations for variables in noinit SRAM
159160
Increment NoInit_MagicValue upon adding variables to this area
@@ -176,21 +177,19 @@ void nrfx_gpiote_evt_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action
176177
if (pin == Pinetime::PinMap::PowerPresent and action == NRF_GPIOTE_POLARITY_TOGGLE) {
177178
xTimerStartFromISR(debounceChargeTimer, &xHigherPriorityTaskWoken);
178179
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
179-
return;
180+
} else if (pin == Pinetime::PinMap::Button) {
181+
xTimerStartFromISR(debounceTimer, &xHigherPriorityTaskWoken);
182+
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
180183
}
181-
182-
xTimerStartFromISR(debounceTimer, &xHigherPriorityTaskWoken);
183-
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
184184
}
185185

186186
void DebounceTimerChargeCallback(TimerHandle_t xTimer) {
187187
xTimerStop(xTimer, 0);
188188
systemTask.PushMessage(Pinetime::System::Messages::OnChargingEvent);
189189
}
190190

191-
void DebounceTimerCallback(TimerHandle_t xTimer) {
192-
xTimerStop(xTimer, 0);
193-
systemTask.OnButtonPushed();
191+
void DebounceTimerCallback(TimerHandle_t /*unused*/) {
192+
systemTask.PushMessage(Pinetime::System::Messages::HandleButtonEvent);
194193
}
195194

196195
void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) {
@@ -319,8 +318,8 @@ int main(void) {
319318
}
320319
nrf_gpio_cfg_default(Pinetime::PinMap::TwiScl);
321320

322-
debounceTimer = xTimerCreate("debounceTimer", 200, pdFALSE, (void*) 0, DebounceTimerCallback);
323-
debounceChargeTimer = xTimerCreate("debounceTimerCharge", 200, pdFALSE, (void*) 0, DebounceTimerChargeCallback);
321+
debounceTimer = xTimerCreate("debounceTimer", 10, pdFALSE, nullptr, DebounceTimerCallback);
322+
debounceChargeTimer = xTimerCreate("debounceTimerCharge", 200, pdFALSE, nullptr, DebounceTimerChargeCallback);
324323

325324
// retrieve version stored by bootloader
326325
Pinetime::BootloaderVersion::SetVersion(NRF_TIMER2->CC[0]);

src/systemtask/Messages.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ namespace Pinetime {
1515
BleFirmwareUpdateStarted,
1616
BleFirmwareUpdateFinished,
1717
OnTouchEvent,
18-
OnButtonEvent,
18+
HandleButtonEvent,
19+
HandleButtonTimerEvent,
1920
OnDisplayTaskSleeping,
2021
EnableSleeping,
2122
DisableSleeping,

src/systemtask/SystemTask.cpp

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include "main.h"
2626
#include "BootErrors.h"
2727

28-
2928
#include <memory>
3029

3130
using namespace Pinetime::System;
@@ -77,7 +76,8 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi,
7776
Pinetime::Applications::DisplayApp& displayApp,
7877
Pinetime::Applications::HeartRateTask& heartRateApp,
7978
Pinetime::Controllers::FS& fs,
80-
Pinetime::Controllers::TouchHandler& touchHandler)
79+
Pinetime::Controllers::TouchHandler& touchHandler,
80+
Pinetime::Controllers::ButtonHandler& buttonHandler)
8181
: spi {spi},
8282
lcd {lcd},
8383
spiNorFlash {spiNorFlash},
@@ -101,8 +101,15 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi,
101101
heartRateApp(heartRateApp),
102102
fs {fs},
103103
touchHandler {touchHandler},
104-
nimbleController(*this, bleController, dateTimeController, notificationManager,
105-
batteryController, spiNorFlash, heartRateController, motionController) {
104+
buttonHandler {buttonHandler},
105+
nimbleController(*this,
106+
bleController,
107+
dateTimeController,
108+
notificationManager,
109+
batteryController,
110+
spiNorFlash,
111+
heartRateController,
112+
motionController) {
106113
}
107114

108115
void SystemTask::Start() {
@@ -163,6 +170,8 @@ void SystemTask::Work() {
163170
heartRateSensor.Disable();
164171
heartRateApp.Start();
165172

173+
buttonHandler.Init(this);
174+
166175
// Button
167176
nrf_gpio_cfg_output(15);
168177
nrf_gpio_pin_set(15);
@@ -326,10 +335,25 @@ void SystemTask::Work() {
326335
ReloadIdleTimer();
327336
displayApp.PushMessage(Pinetime::Applications::Display::Messages::TouchEvent);
328337
break;
329-
case Messages::OnButtonEvent:
330-
ReloadIdleTimer();
331-
displayApp.PushMessage(Pinetime::Applications::Display::Messages::ButtonPushed);
332-
break;
338+
case Messages::HandleButtonEvent: {
339+
Controllers::ButtonActions action;
340+
if (nrf_gpio_pin_read(Pinetime::PinMap::Button) == 0) {
341+
action = buttonHandler.HandleEvent(Controllers::ButtonHandler::Events::Release);
342+
} else {
343+
action = buttonHandler.HandleEvent(Controllers::ButtonHandler::Events::Press);
344+
// This is for faster wakeup, sacrificing special longpress and doubleclick handling while sleeping
345+
if (IsSleeping()) {
346+
fastWakeUpDone = true;
347+
GoToRunning();
348+
break;
349+
}
350+
}
351+
HandleButtonAction(action);
352+
} break;
353+
case Messages::HandleButtonTimerEvent: {
354+
auto action = buttonHandler.HandleEvent(Controllers::ButtonHandler::Events::Timer);
355+
HandleButtonAction(action);
356+
} break;
333357
case Messages::OnDisplayTaskSleeping:
334358
if (BootloaderVersion::IsValid()) {
335359
// First versions of the bootloader do not expose their version and cannot initialize the SPI NOR FLASH
@@ -414,18 +438,36 @@ void SystemTask::UpdateMotion() {
414438
}
415439
}
416440

417-
void SystemTask::OnButtonPushed() {
418-
if (isGoingToSleep)
441+
void SystemTask::HandleButtonAction(Controllers::ButtonActions action) {
442+
if (IsSleeping()) {
419443
return;
420-
if (!isSleeping) {
421-
NRF_LOG_INFO("[systemtask] Button pushed");
422-
PushMessage(Messages::OnButtonEvent);
423-
} else {
424-
if (!isWakingUp) {
425-
NRF_LOG_INFO("[systemtask] Button pushed, waking up");
426-
GoToRunning();
427-
}
428444
}
445+
446+
ReloadIdleTimer();
447+
448+
using Actions = Controllers::ButtonActions;
449+
450+
switch (action) {
451+
case Actions::Click:
452+
// If the first action after fast wakeup is a click, it should be ignored.
453+
if (!fastWakeUpDone && !isGoingToSleep) {
454+
displayApp.PushMessage(Applications::Display::Messages::ButtonPushed);
455+
}
456+
break;
457+
case Actions::DoubleClick:
458+
displayApp.PushMessage(Applications::Display::Messages::ButtonDoubleClicked);
459+
break;
460+
case Actions::LongPress:
461+
displayApp.PushMessage(Applications::Display::Messages::ButtonLongPressed);
462+
break;
463+
case Actions::LongerPress:
464+
displayApp.PushMessage(Applications::Display::Messages::ButtonLongerPressed);
465+
break;
466+
default:
467+
return;
468+
}
469+
470+
fastWakeUpDone = false;
429471
}
430472

431473
void SystemTask::GoToRunning() {

0 commit comments

Comments
 (0)