openMSX
LedStatus.cc
Go to the documentation of this file.
1 #include "LedStatus.hh"
2 #include "MSXCliComm.hh"
3 #include "CommandController.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 
11 namespace 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 {
36  lastTime = Timer::getTime();
37  ranges::fill(ledValue, false);
38 }
39 
40 void 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 
63 void LedStatus::handleEvent(Led led) noexcept
64 {
65  std::string_view str = ledValue[led] ? "on": "off";
66  ledStatus[led].setReadOnlyValue(TclObject(str));
67  msxCliComm.update(CliComm::LED, getLedName(led), str);
68 }
69 
70 void 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
void fill(ForwardRange &&range, const T &value)
Definition: ranges.hh:226
TemporaryString tmpStrCat(Ts &&... ts)
Definition: strCat.hh:659
constexpr auto xrange(T e)
Definition: xrange.hh:155