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  std::string_view outName = rs232OutputFilenameSetting.getString();
37  FileOperations::openofstream(outFile, std::string(outName));
38  if (outFile.fail()) {
39  outFile.clear();
40  throw PlugException("Error opening output file: ", outName);
41  }
42 
43  // input
44  std::string_view inName = rs232InputFilenameSetting.getString();
45  inFile = FileOperations::openFile(std::string(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 const std::string& RS232Tester::getName() const
73 {
74  static const std::string name("rs232-tester");
75  return name;
76 }
77 
78 std::string_view RS232Tester::getDescription() const
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
openmsx::RS232Tester::serialize
void serialize(Archive &ar, unsigned version)
Definition: RS232Tester.cc:151
openmsx::Scheduler
Definition: Scheduler.hh:34
openmsx::CommandController
Definition: CommandController.hh:18
serialize.hh
RS232Tester.hh
openmsx::Poller::aborted
bool aborted()
Returns true iff abort() was called.
Definition: Poller.hh:28
openmsx::RS232Tester::signal
void signal(EmuTime::param time) override
Definition: RS232Tester.cc:112
openmsx::Poller::poll
bool poll(int fd)
Waits for an event to occur on the given file descriptor.
Definition: Poller.cc:43
cb_queue::empty
bool empty() const
Definition: circular_buffer.hh:385
cb_queue::push_back
void push_back(U &&u)
Definition: circular_buffer.hh:358
cb_queue::clear
void clear()
Definition: circular_buffer.hh:386
openmsx::PlugException
Thrown when a plug action fails.
Definition: PlugException.hh:11
PlugException.hh
openmsx::RS232Tester::getDescription
std::string_view getDescription() const override
Description for this pluggable.
Definition: RS232Tester.cc:78
openmsx::FileOperations::openofstream
void openofstream(std::ofstream &stream, const std::string &filename)
Open an ofstream in a platform-independent manner.
Definition: FileOperations.cc:367
openmsx::Pluggable
Definition: Pluggable.hh:12
openmsx::EventDistributor
Definition: EventDistributor.hh:17
openmsx::RS232Tester::plugHelper
void plugHelper(Connector &connector, EmuTime::param time) override
Definition: RS232Tester.cc:33
openmsx::Pluggable::getConnector
Connector * getConnector() const
Get the connector this Pluggable is plugged into.
Definition: Pluggable.hh:43
openmsx::FilenameSetting::getString
std::string_view getString() const noexcept
Definition: FilenameSetting.hh:18
openmsx::RS232Tester::unplugHelper
void unplugHelper(EmuTime::param time) override
Definition: RS232Tester.cc:61
openmsx::RS232Connector::setDataBits
void setDataBits(DataBits bits) override=0
openmsx::SerialDataInterface::DATA_8
@ DATA_8
Definition: SerialDataInterface.hh:13
openmsx::RS232Tester::recvByte
void recvByte(byte value, EmuTime::param time) override
Definition: RS232Tester.cc:141
EventDistributor.hh
cb_queue::pop_front
T pop_front()
Definition: circular_buffer.hh:365
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
openmsx::SerialDataInterface::STOP_1
@ STOP_1
Definition: SerialDataInterface.hh:16
openmsx::Pluggable::setConnector
void setConnector(Connector *conn)
Definition: Pluggable.hh:58
RS232Connector.hh
Scheduler.hh
openmsx::FileOperations::openFile
FILE_t openFile(const std::string &filename, const std::string &mode)
Call fopen() in a platform-independent manner.
Definition: FileOperations.cc:353
FileOperations.hh
openmsx::RS232Tester
Definition: RS232Tester.hh:23
openmsx::RS232Connector
Definition: RS232Connector.hh:13
openmsx::RS232Tester::RS232Tester
RS232Tester(EventDistributor &eventDistributor, Scheduler &scheduler, CommandController &commandController)
Definition: RS232Tester.cc:11
openmsx::Connector
Represents something you can plug devices into.
Definition: Connector.hh:21
openmsx::RS232Tester::getName
const std::string & getName() const override
Name used to identify this pluggable.
Definition: RS232Tester.cc:72
openmsx::OPENMSX_RS232_TESTER_EVENT
@ OPENMSX_RS232_TESTER_EVENT
Definition: Event.hh:78
openmsx::EventDistributor::registerEventListener
void registerEventListener(EventType type, EventListener &listener, Priority priority=OTHER)
Registers a given object to receive certain events.
Definition: EventDistributor.cc:23
openmsx::Pluggable::isPluggedIn
bool isPluggedIn() const
Returns true if this pluggable is currently plugged into a connector.
Definition: Pluggable.hh:49
openmsx::EventDistributor::unregisterEventListener
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
Definition: EventDistributor.cc:35
openmsx::Poller::abort
void abort()
Aborts a poll in progress and any future poll attempts.
Definition: Poller.cc:31
openmsx::Scheduler::getCurrentTime
EmuTime::param getCurrentTime() const
Get the current scheduler time.
Definition: Scheduler.cc:84
openmsx::RS232Tester::~RS232Tester
~RS232Tester() override
Definition: RS232Tester.cc:27
openmsx
This file implemented 3 utility functions:
Definition: Autofire.cc:5
openmsx::SerialDataInterface::EVEN
@ EVEN
Definition: SerialDataInterface.hh:20
openmsx::REGISTER_POLYMORPHIC_INITIALIZER
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
openmsx::EventDistributor::distributeEvent
void distributeEvent(const EventPtr &event)
Schedule the given event for delivery.
Definition: EventDistributor.cc:44