openMSX
LedStatus.cc
Go to the documentation of this file.
1#include "LedStatus.hh"
2#include "MSXCliComm.hh"
4#include "Timer.hh"
5#include "ranges.hh"
6#include "stl.hh"
7#include "strCat.hh"
8#include "xrange.hh"
9#include <array>
10#include <string_view>
11
12namespace openmsx {
13
14[[nodiscard]] static std::string_view getLedName(LedStatus::Led led)
15{
16 static constexpr std::array<std::string_view, LedStatus::NUM_LEDS> names = {
17 "power", "caps", "kana", "pause", "turbo", "FDD"
18 };
19 return names[led];
20}
21
23 RTScheduler& rtScheduler,
24 CommandController& commandController,
25 MSXCliComm& msxCliComm_)
26 : RTSchedulable(rtScheduler)
27 , msxCliComm(msxCliComm_)
28 , interp(commandController.getInterpreter())
29 , ledStatus(generate_array<NUM_LEDS>([&](auto i) {
30 return ReadOnlySetting(
31 commandController,
32 tmpStrCat("led_", getLedName(static_cast<Led>(i))),
33 "Current status for LED",
34 TclObject("off"));
35 }))
36 , lastTime(Timer::getTime())
37{
38 ranges::fill(ledValue, false);
39}
40
41void LedStatus::setLed(Led led, bool status)
42{
43 if (ledValue[led] == status) return;
44 ledValue[led] = status;
45
46 // Some MSX programs generate tons of LED events (e.g. New Era uses
47 // the LEDs as a VU meter while playing samples). Without throttling
48 // all these events overload the host CPU. That's why we limit it to
49 // 100 events per second.
50 auto now = Timer::getTime();
51 auto diff = now - lastTime;
52 if (diff > 10000) { // 1/100 s
53 // handle now
54 lastTime = now;
55 handleEvent(led);
56 } else {
57 // schedule to handle it later, if we didn't plan to do so already
58 if (!isPendingRT()) {
59 scheduleRT(10000 - diff);
60 }
61 }
62}
63
64void LedStatus::handleEvent(Led led) noexcept
65{
66 std::string_view str = ledValue[led] ? "on": "off";
67 ledStatus[led].setReadOnlyValue(TclObject(str));
68 msxCliComm.updateFiltered(CliComm::LED, getLedName(led), str);
69}
70
71void LedStatus::executeRT()
72{
73 for (auto i : xrange(int(NUM_LEDS))) {
74 if (ledValue[i] != ledStatus[i].getValue().getBoolean(interp)) {
75 handleEvent(static_cast<Led>(i));
76 }
77 }
78 lastTime = Timer::getTime();
79}
80
81} // namespace openmsx
LedStatus(RTScheduler &rtScheduler, CommandController &commandController, MSXCliComm &msxCliComm)
Definition: LedStatus.cc:22
void setLed(Led led, bool status)
Definition: LedStatus.cc:41
void scheduleRT(uint64_t delta)
bool isPendingRT() const
uint64_t getTime()
Get current (real) time in us.
Definition: Timer.cc:7
This file implemented 3 utility functions:
Definition: Autofire.cc:9
constexpr void fill(ForwardRange &&range, const T &value)
Definition: ranges.hh:287
TemporaryString tmpStrCat(Ts &&... ts)
Definition: strCat.hh:610
constexpr auto xrange(T e)
Definition: xrange.hh:133