Newer
Older
Tardis / src / ButtonThread.cpp
/*
SPDX-License-Identifier: MIT
Copyright (c) 2024 John Watts and the LuminaSensum contributors
*/

#include "ButtonThread.h"
#include "mbed.h"

EventFlags buttonFlags;

#define PUSH_FLAG 0b01

void button_onrise(void) { buttonFlags.set(PUSH_FLAG); }

int readButtonPresses(void) {
	int pressed_count = 0;

	// Wait and track an initial press without timing out
	buttonFlags.wait_any(PUSH_FLAG);
	pressed_count++;

	while (true) {
		uint32_t flags = buttonFlags.wait_any(PUSH_FLAG, 1000);
		bool timed_out = flags == osFlagsErrorTimeout;
		bool had_any_error = flags & osFlagsError;
		if (timed_out) {
			break;
		} else if (had_any_error) {
			error("Unable to wait for push button flag?\n");
		} else {
			pressed_count++;
		}
	}

	return pressed_count;
}

int buttonPressCount;
Mutex buttonPressMutex;
ConditionVariable cv(buttonPressMutex);

void buttonTask(void) {
	InterruptIn buttonIRQ(BUTTON1);
	buttonIRQ.rise(button_onrise);

	while (true) {
		int presses = readButtonPresses();
		buttonPressMutex.lock();
		buttonPressCount = presses;
		cv.notify_one();
		buttonPressMutex.unlock();
	}
}

bool waitPressCondition(Kernel::Clock::time_point timeout) {
	// buttonPressCount is 0 if we have already read the current value
	while (buttonPressCount == 0) {
		if (cv.wait_until(timeout) == cv_status::timeout) {
			return false;
		}
	}
	return true;
}

// returns presses or -1 on timeout
int waitForPresses(std::chrono::milliseconds wait_time) {
	Kernel::Clock::time_point timeout = Kernel::Clock::now() + wait_time;
	int presses = -1;
	buttonPressMutex.lock();
	if (waitPressCondition(timeout)) {
		presses = buttonPressCount;
		buttonPressCount = 0;
	}
	buttonPressMutex.unlock();
	return presses;
}