OXYGENHUB
◆ main openmsx / src / LedStatus.cc
2.1 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "LedStatus.hh"
2
3
#include "CommandController.hh"
4
#include "MSXCliComm.hh"
5
#include "Timer.hh"
6
7
#include "stl.hh"
8
#include "strCat.hh"
9
#include "xrange.hh"
10
11
#include <algorithm>
12
#include <array>
13
#include <string_view>
14
15
namespace openmsx {
16
17
using namespace std::literals;
18
19
[[nodiscard]] static std::string_view getLedName(LedStatus::Led led)
20
{
21
	static constexpr std::array<std::string_view, LedStatus::NUM_LEDS> names = {
22
		"power", "caps", "kana", "pause", "turbo", "FDD"
23
	};
24
	return names[led];
25
}
26
27
LedStatus::LedStatus(
28
		RTScheduler& rtScheduler,
29
		CommandController& commandController,
30
		MSXCliComm& msxCliComm_)
31
	: RTSchedulable(rtScheduler)
32
	, msxCliComm(msxCliComm_)
33
	, interp(commandController.getInterpreter())
34
	, ledStatus(generate_array<NUM_LEDS>([&](auto i) {
35
		return ReadOnlySetting(
36
			commandController,
37
			tmpStrCat("led_", getLedName(static_cast<Led>(i))),
38
			"Current status for LED",
39
			TclObject("off"));
40
	}))
41
	, lastTime(Timer::getTime())
42
{
43
	std::ranges::fill(ledValue, false);
44
}
45
46
void LedStatus::setLed(Led led, bool status)
47
{
48
	if (ledValue[led] == status) return;
49
	ledValue[led] = status;
50
51
	// Some MSX programs generate tons of LED events (e.g. New Era uses
52
	// the LEDs as a VU meter while playing samples). Without throttling
53
	// all these events overload the host CPU. That's why we limit it to
54
	// 100 events per second.
55
	auto now = Timer::getTime();
56
	auto diff = now - lastTime;
57
	if (diff > 10000) { // 1/100 s
58
		// handle now
59
		lastTime = now;
60
		handleEvent(led);
61
	} else {
62
		// schedule to handle it later, if we didn't plan to do so already
63
		if (!isPendingRT()) {
64
			scheduleRT(10000 - diff);
65
		}
66
	}
67
}
68
69
void LedStatus::handleEvent(Led led) noexcept
70
{
71
	std::string_view str = ledValue[led] ? "on"sv : "off"sv;
72
	ledStatus[led].setReadOnlyValue(TclObject(str));
73
	msxCliComm.updateFiltered(CliComm::UpdateType::LED, getLedName(led), str);
74
}
75
76
void LedStatus::executeRT()
77
{
78
	for (auto i : xrange(int(NUM_LEDS))) {
79
		if (ledValue[i] != ledStatus[i].getValue().getBoolean(interp)) {
80
			handleEvent(static_cast<Led>(i));
81
		}
82
	}
83
	lastTime = Timer::getTime();
84
}
85
86
} // namespace openmsx