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 "checked_cast.hh"
8#include "narrow.hh"
9#include "serialize.hh"
10#include <array>
11
12namespace openmsx {
13
15 Scheduler& scheduler_,
16 CommandController& commandController)
17 : eventDistributor(eventDistributor_), scheduler(scheduler_)
18 , rs232InputFilenameSetting(
19 commandController, "rs232-inputfilename",
20 "filename of the file where the RS232 input is read from",
21 "rs232-input")
22 , rs232OutputFilenameSetting(
23 commandController, "rs232-outputfilename",
24 "filename of the file where the RS232 output is written to",
25 "rs232-output")
26{
27 eventDistributor.registerEventListener(EventType::RS232_TESTER, *this);
28}
29
34
35// Pluggable
36void RS232Tester::plugHelper(Connector& connector_, EmuTime::param /*time*/)
37{
38 // output
39 auto outName = rs232OutputFilenameSetting.getString();
40 FileOperations::openOfStream(outFile, outName);
41 if (outFile.fail()) {
42 outFile.clear();
43 throw PlugException("Error opening output file: ", outName);
44 }
45
46 // input
47 auto inName = rs232InputFilenameSetting.getString();
48 inFile = FileOperations::openFile(inName, "rb");
49 if (!inFile) {
50 outFile.close();
51 throw PlugException("Error opening input file: ", inName);
52 }
53
54 auto& rs232Connector = checked_cast<RS232Connector&>(connector_);
55 rs232Connector.setDataBits(SerialDataInterface::DataBits::D8); // 8 data bits
56 rs232Connector.setStopBits(SerialDataInterface::StopBits::S1); // 1 stop bit
57 rs232Connector.setParityBit(false, SerialDataInterface::Parity::EVEN); // no parity
58
59 setConnector(&connector_); // base class will do this in a moment,
60 // but thread already needs it
61 poller.reset();
62 thread = std::thread([this]() { run(); });
63}
64
65void RS232Tester::unplugHelper(EmuTime::param /*time*/)
66{
67 // output
68 outFile.close();
69
70 // input
71 poller.abort();
72 thread.join();
73 inFile.reset();
74}
75
76std::string_view RS232Tester::getName() const
77{
78 return "rs232-tester";
79}
80
81std::string_view RS232Tester::getDescription() const
82{
83 return "RS232 tester pluggable. Reads all data from file specified "
84 "with the 'rs-232-inputfilename' setting. Writes all data "
85 "to the file specified with the 'rs232-outputfilename' "
86 "setting.";
87}
88
89void RS232Tester::run()
90{
91 if (!inFile) return;
92 while (!feof(inFile.get())) {
93#ifndef _WIN32
94 if (poller.poll(fileno(inFile.get()))) {
95 break;
96 }
97#endif
98 std::array<uint8_t, 1> buf;
99 size_t num = fread(buf.data(), sizeof(uint8_t), buf.size(), inFile.get());
100 if (poller.aborted()) {
101 break;
102 }
103 if (num != 1) {
104 continue;
105 }
106 assert(isPluggedIn());
107 std::scoped_lock lock(mutex);
108 queue.push_back(buf[0]);
109 eventDistributor.distributeEvent(Rs232TesterEvent());
110 }
111}
112
113// Control lines
114// Needed to set these lines in the correct state for a plugged device
115
116std::optional<bool> RS232Tester::getDSR(EmuTime::param /*time*/) const
117{
118 return true;
119}
120
121std::optional<bool> RS232Tester::getCTS(EmuTime::param /*time*/) const
122{
123 return true;
124}
125
126// input
127void RS232Tester::signal(EmuTime::param time)
128{
129 auto* conn = checked_cast<RS232Connector*>(getConnector());
130 if (!conn->acceptsData()) {
131 std::scoped_lock lock(mutex);
132 queue.clear();
133 return;
134 }
135 if (!conn->ready()) return;
136
137 std::scoped_lock lock(mutex);
138 if (queue.empty()) return;
139 conn->recvByte(queue.pop_front(), time);
140}
141
142// EventListener
143bool RS232Tester::signalEvent(const Event& /*event*/)
144{
145 if (isPluggedIn()) {
146 signal(scheduler.getCurrentTime());
147 } else {
148 std::scoped_lock lock(mutex);
149 queue.clear();
150 }
151 return false;
152}
153
154
155// output
156void RS232Tester::recvByte(uint8_t value, EmuTime::param /*time*/)
157{
158 if (outFile.is_open()) {
159 outFile.put(narrow_cast<char>(value));
160 outFile.flush();
161 }
162}
163
164
165template<typename Archive>
166void RS232Tester::serialize(Archive& /*ar*/, unsigned /*version*/)
167{
168 // don't try to resume a previous logfile (see PrinterPortLogger)
169}
172
173} // 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=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
void setConnector(Connector *conn)
Definition Pluggable.hh:58
Connector * getConnector() const
Get the connector this Pluggable is plugged into.
Definition Pluggable.hh:43
bool poll(int fd)
Waits for an event to occur on the given file descriptor.
Definition Poller.cc:42
void reset()
Reset aborted() to false.
Definition Poller.hh:43
bool aborted() const
Returns true iff abort() was called.
Definition Poller.hh:33
void abort()
Aborts a poll in progress and any future poll attempts.
Definition Poller.cc:30
RS232Tester(EventDistributor &eventDistributor, Scheduler &scheduler, CommandController &commandController)
void plugHelper(Connector &connector, EmuTime::param time) override
std::string_view getName() const override
Name used to identify this pluggable.
std::optional< bool > getCTS(EmuTime::param time) const override
void signal(EmuTime::param time) override
~RS232Tester() override
void serialize(Archive &ar, unsigned version)
void unplugHelper(EmuTime::param time) override
std::optional< bool > getDSR(EmuTime::param time) const override
void recvByte(uint8_t value, EmuTime::param time) override
std::string_view getDescription() const override
Description for this pluggable.
EmuTime::param getCurrentTime() const
Get the current scheduler time.
Definition Scheduler.cc:82
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:11
std::variant< KeyUpEvent, KeyDownEvent, MouseMotionEvent, MouseButtonUpEvent, MouseButtonDownEvent, MouseWheelEvent, JoystickAxisMotionEvent, JoystickHatEvent, JoystickButtonUpEvent, JoystickButtonDownEvent, OsdControlReleaseEvent, OsdControlPressEvent, WindowEvent, TextEvent, FileDropEvent, QuitEvent, FinishFrameEvent, CliCommandEvent, GroupEvent, BootEvent, FrameDrawnEvent, BreakEvent, SwitchRendererEvent, TakeReverseSnapshotEvent, AfterTimedEvent, MachineLoadedEvent, MachineActivatedEvent, MachineDeactivatedEvent, MidiInReaderEvent, MidiInWindowsEvent, MidiInCoreMidiEvent, MidiInCoreMidiVirtualEvent, MidiInALSAEvent, Rs232TesterEvent, Rs232NetEvent, ImGuiDelayedActionEvent, ImGuiActiveEvent > Event
Definition Event.hh:445
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
#define REGISTER_POLYMORPHIC_INITIALIZER(BASE, CLASS, NAME)