openMSX
RS232Tester.cc
Go to the documentation of this file.
1 #include "RS232Tester.hh"
2 #include "RS232Connector.hh"
3 #include "PlugException.hh"
4 #include "EventDistributor.hh"
5 #include "Scheduler.hh"
6 #include "FileOperations.hh"
7 #include "serialize.hh"
8 
9 namespace openmsx {
10 
12  Scheduler& scheduler_,
13  CommandController& commandController)
14  : eventDistributor(eventDistributor_), scheduler(scheduler_)
15  , rs232InputFilenameSetting(
16  commandController, "rs232-inputfilename",
17  "filename of the file where the RS232 input is read from",
18  "rs232-input")
19  , rs232OutputFilenameSetting(
20  commandController, "rs232-outputfilename",
21  "filename of the file where the RS232 output is written to",
22  "rs232-output")
23 {
24  eventDistributor.registerEventListener(EventType::RS232_TESTER, *this);
25 }
26 
28 {
29  eventDistributor.unregisterEventListener(EventType::RS232_TESTER, *this);
30 }
31 
32 // Pluggable
33 void RS232Tester::plugHelper(Connector& connector_, EmuTime::param /*time*/)
34 {
35  // output
36  auto outName = rs232OutputFilenameSetting.getString();
37  FileOperations::openofstream(outFile, outName);
38  if (outFile.fail()) {
39  outFile.clear();
40  throw PlugException("Error opening output file: ", outName);
41  }
42 
43  // input
44  auto inName = rs232InputFilenameSetting.getString();
45  inFile = FileOperations::openFile(inName, "rb");
46  if (!inFile) {
47  outFile.close();
48  throw PlugException("Error opening input file: ", inName);
49  }
50 
51  auto& rs232Connector = static_cast<RS232Connector&>(connector_);
52  rs232Connector.setDataBits(SerialDataInterface::DATA_8); // 8 data bits
53  rs232Connector.setStopBits(SerialDataInterface::STOP_1); // 1 stop bit
54  rs232Connector.setParityBit(false, SerialDataInterface::EVEN); // no parity
55 
56  setConnector(&connector_); // base class will do this in a moment,
57  // but thread already needs it
58  thread = std::thread([this]() { run(); });
59 }
60 
61 void RS232Tester::unplugHelper(EmuTime::param /*time*/)
62 {
63  // output
64  outFile.close();
65 
66  // input
67  poller.abort();
68  thread.join();
69  inFile.reset();
70 }
71 
72 std::string_view RS232Tester::getName() const
73 {
74  return "rs232-tester";
75 }
76 
77 std::string_view RS232Tester::getDescription() const
78 {
79  return "RS232 tester pluggable. Reads all data from file specified "
80  "with the 'rs-232-inputfilename' setting. Writes all data "
81  "to the file specified with the 'rs232-outputfilename' "
82  "setting.";
83 }
84 
85 void RS232Tester::run()
86 {
87  if (!inFile) return;
88  while (!feof(inFile.get())) {
89 #ifndef _WIN32
90  if (poller.poll(fileno(inFile.get()))) {
91  break;
92  }
93 #endif
94  byte buf;
95  size_t num = fread(&buf, 1, 1, inFile.get());
96  if (poller.aborted()) {
97  break;
98  }
99  if (num != 1) {
100  continue;
101  }
102  assert(isPluggedIn());
103  std::lock_guard<std::mutex> lock(mutex);
104  queue.push_back(buf);
105  eventDistributor.distributeEvent(
106  Event::create<Rs232TesterEvent>());
107  }
108 }
109 
110 // input
111 void RS232Tester::signal(EmuTime::param time)
112 {
113  auto* conn = static_cast<RS232Connector*>(getConnector());
114  if (!conn->acceptsData()) {
115  std::lock_guard<std::mutex> lock(mutex);
116  queue.clear();
117  return;
118  }
119  if (!conn->ready()) return;
120 
121  std::lock_guard<std::mutex> lock(mutex);
122  if (queue.empty()) return;
123  conn->recvByte(queue.pop_front(), time);
124 }
125 
126 // EventListener
127 int RS232Tester::signalEvent(const Event& /*event*/) noexcept
128 {
129  if (isPluggedIn()) {
130  signal(scheduler.getCurrentTime());
131  } else {
132  std::lock_guard<std::mutex> lock(mutex);
133  queue.clear();
134  }
135  return 0;
136 }
137 
138 
139 // output
140 void RS232Tester::recvByte(byte value, EmuTime::param /*time*/)
141 {
142  if (outFile.is_open()) {
143  outFile.put(value);
144  outFile.flush();
145  }
146 }
147 
148 
149 template<typename Archive>
150 void RS232Tester::serialize(Archive& /*ar*/, unsigned /*version*/)
151 {
152  // don't try to resume a previous logfile (see PrinterPortLogger)
153 }
156 
157 } // namespace openmsx
bool empty() const
void push_back(U &&u)
Represents something you can plug devices into.
Definition: Connector.hh:21
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
void distributeEvent(Event &&event)
Schedule the given event for delivery.
void registerEventListener(EventType type, EventListener &listener, Priority priority=OTHER)
Registers a given object to receive certain events.
zstring_view getString() const noexcept
Thrown when a plug action fails.
bool isPluggedIn() const
Returns true if this pluggable is currently plugged into a connector.
Definition: Pluggable.hh:49
Connector * getConnector() const
Get the connector this Pluggable is plugged into.
Definition: Pluggable.hh:43
void setConnector(Connector *conn)
Definition: Pluggable.hh:58
bool poll(int fd)
Waits for an event to occur on the given file descriptor.
Definition: Poller.cc:43
bool aborted()
Returns true iff abort() was called.
Definition: Poller.hh:28
void abort()
Aborts a poll in progress and any future poll attempts.
Definition: Poller.cc:31
void setDataBits(DataBits bits) override=0
RS232Tester(EventDistributor &eventDistributor, Scheduler &scheduler, CommandController &commandController)
Definition: RS232Tester.cc:11
void plugHelper(Connector &connector, EmuTime::param time) override
Definition: RS232Tester.cc:33
std::string_view getName() const override
Name used to identify this pluggable.
Definition: RS232Tester.cc:72
void recvByte(byte value, EmuTime::param time) override
Definition: RS232Tester.cc:140
void signal(EmuTime::param time) override
Definition: RS232Tester.cc:111
~RS232Tester() override
Definition: RS232Tester.cc:27
void serialize(Archive &ar, unsigned version)
Definition: RS232Tester.cc:150
void unplugHelper(EmuTime::param time) override
Definition: RS232Tester.cc:61
std::string_view getDescription() const override
Description for this pluggable.
Definition: RS232Tester.cc:77
void openofstream(std::ofstream &stream, zstring_view filename)
Open an ofstream in a platform-independent manner.
FILE_t openFile(zstring_view filename, zstring_view mode)
Call fopen() in a platform-independent manner.
This file implemented 3 utility functions:
Definition: Autofire.cc:9
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:998