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