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
31{
32 eventDistributor.unregisterEventListener(EventType::RS232_TESTER, *this);
33}
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(
109 Event::create<Rs232TesterEvent>());
110 }
111}
112
113// input
114void RS232Tester::signal(EmuTime::param time)
115{
116 auto* conn = checked_cast<RS232Connector*>(getConnector());
117 if (!conn->acceptsData()) {
118 std::lock_guard<std::mutex> lock(mutex);
119 queue.clear();
120 return;
121 }
122 if (!conn->ready()) return;
123
124 std::lock_guard<std::mutex> lock(mutex);
125 if (queue.empty()) return;
126 conn->recvByte(queue.pop_front(), time);
127}
128
129// EventListener
130int RS232Tester::signalEvent(const Event& /*event*/)
131{
132 if (isPluggedIn()) {
133 signal(scheduler.getCurrentTime());
134 } else {
135 std::lock_guard<std::mutex> lock(mutex);
136 queue.clear();
137 }
138 return 0;
139}
140
141
142// output
143void RS232Tester::recvByte(uint8_t value, EmuTime::param /*time*/)
144{
145 if (outFile.is_open()) {
146 outFile.put(narrow_cast<char>(value));
147 outFile.flush();
148 }
149}
150
151
152template<typename Archive>
153void RS232Tester::serialize(Archive& /*ar*/, unsigned /*version*/)
154{
155 // don't try to resume a previous logfile (see PrinterPortLogger)
156}
159
160} // 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)
Definition: RS232Tester.cc:14
void plugHelper(Connector &connector, EmuTime::param time) override
Definition: RS232Tester.cc:36
std::string_view getName() const override
Name used to identify this pluggable.
Definition: RS232Tester.cc:75
void signal(EmuTime::param time) override
Definition: RS232Tester.cc:114
~RS232Tester() override
Definition: RS232Tester.cc:30
void serialize(Archive &ar, unsigned version)
Definition: RS232Tester.cc:153
void unplugHelper(EmuTime::param time) override
Definition: RS232Tester.cc:64
void recvByte(uint8_t value, EmuTime::param time) override
Definition: RS232Tester.cc:143
std::string_view getDescription() const override
Description for this pluggable.
Definition: RS232Tester.cc:80
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
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1021