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(OPENMSX_RS232_TESTER_EVENT, *this);
25 }
26 
28 {
29  eventDistributor.unregisterEventListener(OPENMSX_RS232_TESTER_EVENT, *this);
30 }
31 
32 // Pluggable
33 void RS232Tester::plugHelper(Connector& connector_, EmuTime::param /*time*/)
34 {
35  // output
36  string_view outName = rs232OutputFilenameSetting.getString();
37  FileOperations::openofstream(outFile, outName.str());
38  if (outFile.fail()) {
39  outFile.clear();
40  throw PlugException("Error opening output file: ", outName);
41  }
42 
43  // input
44  string_view inName = rs232InputFilenameSetting.getString();
45  inFile = FileOperations::openFile(inName.str(), "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 const std::string& RS232Tester::getName() const
73 {
74  static const std::string name("rs232-tester");
75  return name;
76 }
77 
79 {
80  return "RS232 tester pluggable. Reads all data from file specified "
81  "with the 'rs-232-inputfilename' setting. Writes all data "
82  "to the file specified with the 'rs232-outputfilename' "
83  "setting.";
84 }
85 
86 void RS232Tester::run()
87 {
88  byte buf;
89  if (!inFile) return;
90  while (!feof(inFile.get())) {
91 #ifndef _WIN32
92  if (poller.poll(fileno(inFile.get()))) {
93  break;
94  }
95 #endif
96  size_t num = fread(&buf, 1, 1, inFile.get());
97  if (poller.aborted()) {
98  break;
99  }
100  if (num != 1) {
101  continue;
102  }
103  assert(isPluggedIn());
104  std::lock_guard<std::mutex> lock(mutex);
105  queue.push_back(buf);
106  eventDistributor.distributeEvent(
107  std::make_shared<SimpleEvent>(OPENMSX_RS232_TESTER_EVENT));
108  }
109 }
110 
111 // input
112 void RS232Tester::signal(EmuTime::param time)
113 {
114  auto* conn = static_cast<RS232Connector*>(getConnector());
115  if (!conn->acceptsData()) {
116  std::lock_guard<std::mutex> lock(mutex);
117  queue.clear();
118  return;
119  }
120  if (!conn->ready()) return;
121 
122  std::lock_guard<std::mutex> lock(mutex);
123  if (queue.empty()) return;
124  conn->recvByte(queue.pop_front(), time);
125 }
126 
127 // EventListener
128 int RS232Tester::signalEvent(const std::shared_ptr<const Event>& /*event*/)
129 {
130  if (isPluggedIn()) {
131  signal(scheduler.getCurrentTime());
132  } else {
133  std::lock_guard<std::mutex> lock(mutex);
134  queue.clear();
135  }
136  return 0;
137 }
138 
139 
140 // output
141 void RS232Tester::recvByte(byte value, EmuTime::param /*time*/)
142 {
143  if (outFile.is_open()) {
144  outFile.put(value);
145  outFile.flush();
146  }
147 }
148 
149 
150 template<typename Archive>
151 void RS232Tester::serialize(Archive& /*ar*/, unsigned /*version*/)
152 {
153  // don't try to resume a previous logfile (see PrinterPortLogger)
154 }
157 
158 } // namespace openmsx
void abort()
Aborts a poll in progress and any future poll attempts.
Definition: Poller.cc:31
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
Represents something you can plug devices into.
Definition: Connector.hh:20
Connector * getConnector() const
Get the connector this Pluggable is plugged into.
Definition: Pluggable.hh:43
void registerEventListener(EventType type, EventListener &listener, Priority priority=OTHER)
Registers a given object to receive certain events.
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
RS232Tester(EventDistributor &eventDistributor, Scheduler &scheduler, CommandController &commandController)
Definition: RS232Tester.cc:11
void setConnector(Connector *conn)
Definition: Pluggable.hh:58
bool isPluggedIn() const
Returns true if this pluggable is currently plugged into a connector.
Definition: Pluggable.hh:49
void openofstream(std::ofstream &stream, const std::string &filename)
Open an ofstream in a platform-independent manner.
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
void distributeEvent(const EventPtr &event)
Schedule the given event for delivery.
bool empty() const
EmuTime::param getCurrentTime() const
Get the current scheduler time.
Definition: Scheduler.cc:85
bool poll(int fd)
Waits for an event to occur on the given file descriptor.
Definition: Poller.cc:43
const std::string & getName() const override
Name used to identify this pluggable.
Definition: RS232Tester.cc:72
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
bool aborted()
Returns true iff abort() was called.
Definition: Poller.hh:28
~RS232Tester() override
Definition: RS232Tester.cc:27
void plugHelper(Connector &connector, EmuTime::param time) override
Definition: RS232Tester.cc:33
string_view getDescription() const override
Description for this pluggable.
Definition: RS232Tester.cc:78
string_view getString() const noexcept
This class implements a (close approximation) of the std::string_view class.
Definition: string_view.hh:16
void serialize(Archive &ar, unsigned version)
Definition: RS232Tester.cc:151
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1006
std::string str() const
Definition: string_view.cc:12
void recvByte(byte value, EmuTime::param time) override
Definition: RS232Tester.cc:141
void setDataBits(DataBits bits) override=0
FILE_t openFile(const std::string &filename, const std::string &mode)
Call fopen() in a platform-independent manner.
void unplugHelper(EmuTime::param time) override
Definition: RS232Tester.cc:61
void push_back(U &&u)
void signal(EmuTime::param time) override
Definition: RS232Tester.cc:112
Thrown when a plug action fails.