openMSX
LedStatus.cc
Go to the documentation of this file.
1 #include "LedStatus.hh"
2 #include "MSXCliComm.hh"
3 #include "ReadOnlySetting.hh"
4 #include "CommandController.hh"
5 #include "Timer.hh"
6 #include "xrange.hh"
7 #include <memory>
8 
9 namespace openmsx {
10 
11 [[nodiscard]] static std::string getLedName(LedStatus::Led led)
12 {
13  static constexpr const char* const names[LedStatus::NUM_LEDS] = {
14  "power", "caps", "kana", "pause", "turbo", "FDD"
15  };
16  return names[led];
17 }
18 
20  RTScheduler& rtScheduler,
21  CommandController& commandController,
22  MSXCliComm& msxCliComm_)
23  : RTSchedulable(rtScheduler)
24  , msxCliComm(msxCliComm_)
25  , interp(commandController.getInterpreter())
26 {
27  lastTime = Timer::getTime();
28  for (auto i : xrange(int(NUM_LEDS))) {
29  ledValue[i] = false;
30  std::string name = getLedName(static_cast<Led>(i));
31  ledStatus[i] = std::make_unique<ReadOnlySetting>(
32  commandController, tmpStrCat("led_", name),
33  "Current status for LED",
34  TclObject("off"));
35  }
36 }
37 
38 LedStatus::~LedStatus() = default;
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:19
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:5
TemporaryString tmpStrCat(Ts &&... ts)
Definition: strCat.hh:659
constexpr auto xrange(T e)
Definition: xrange.hh:155