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::DATA_8); // 8 data bits
56 rs232Connector.setStopBits(SerialDataInterface::STOP_1); // 1 stop bit
57 rs232Connector.setParityBit(false, SerialDataInterface::EVEN); // no parity
58
59 setConnector(&connector_); // base class will do this in a moment,
60 // but thread already needs it
61 thread = std::thread([this]() { run(); });
62}
63
64void RS232Tester::unplugHelper(EmuTime::param /*time*/)
65{
66 // output
67 outFile.close();
68
69 // input
70 poller.abort();
71 thread.join();
72 inFile.reset();
73}
74
75std::string_view RS232Tester::getName() const
76{
77 return "rs232-tester";
78}
79
80std::string_view RS232Tester::getDescription() const
81{
82 return "RS232 tester pluggable. Reads all data from file specified "
83 "with the 'rs-232-inputfilename' setting. Writes all data "
84 "to the file specified with the 'rs232-outputfilename' "
85 "setting.";
86}
87
88void RS232Tester::run()
89{
90 if (!inFile) return;
91 while (!feof(inFile.get())) {
92#ifndef _WIN32
93 if (poller.poll(fileno(inFile.get()))) {
94 break;
95 }
96#endif
97 std::array<uint8_t, 1> buf;
98 size_t num = fread(buf.data(), sizeof(uint8_t), buf.size(), inFile.get());
99 if (poller.aborted()) {
100 break;
101 }
102 if (num != 1) {
103 continue;
104 }
105 assert(isPluggedIn());
106 std::lock_guard<std::mutex> lock(mutex);
107 queue.push_back(buf[0]);
108 eventDistributor.distributeEvent(Rs232TesterEvent());
109 }
110}
111
112// input
113void RS232Tester::signal(EmuTime::param time)
114{
115 auto* conn = checked_cast<RS232Connector*>(getConnector());
116 if (!conn->acceptsData()) {
117 std::lock_guard<std::mutex> lock(mutex);
118 queue.clear();
119 return;
120 }
121 if (!conn->ready()) return;
122
123 std::lock_guard<std::mutex> lock(mutex);
124 if (queue.empty()) return;
125 conn->recvByte(queue.pop_front(), time);
126}
127
128// EventListener
129int RS232Tester::signalEvent(const Event& /*event*/)
130{
131 if (isPluggedIn()) {
132 signal(scheduler.getCurrentTime());
133 } else {
134 std::lock_guard<std::mutex> lock(mutex);
135 queue.clear();
136 }
137 return 0;
138}
139
140
141// output
142void RS232Tester::recvByte(uint8_t value, EmuTime::param /*time*/)
143{
144 if (outFile.is_open()) {
145 outFile.put(narrow_cast<char>(value));
146 outFile.flush();
147 }
148}
149
150
151template<typename Archive>
152void RS232Tester::serialize(Archive& /*ar*/, unsigned /*version*/)
153{
154 // don't try to resume a previous logfile (see PrinterPortLogger)
155}
158
159} // 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
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:43
bool aborted()
Returns true iff abort() was called.
Definition Poller.hh:29
void abort()
Aborts a poll in progress and any future poll attempts.
Definition Poller.cc:31
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.
void signal(EmuTime::param time) override
~RS232Tester() override
void serialize(Archive &ar, unsigned version)
void unplugHelper(EmuTime::param time) 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:84
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
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:454
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
#define REGISTER_POLYMORPHIC_INITIALIZER(BASE, CLASS, NAME)