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