20#include <netinet/tcp.h>
26static constexpr char IP232_MAGIC =
'\xff';
29static constexpr char IP232_DTR_LO =
'\x00';
30static constexpr char IP232_DTR_HI =
'\x01';
33static constexpr char IP232_DCD_LO =
'\x00';
34static constexpr char IP232_DCD_HI =
'\x01';
35static constexpr char IP232_DCD_MASK =
'\x01';
37static constexpr char IP232_RI_LO =
'\x00';
38static constexpr char IP232_RI_HI =
'\x02';
39static constexpr char IP232_RI_MASK =
'\x02';
44 : eventDistributor(eventDistributor_), scheduler(scheduler_)
45 , rs232NetAddressSetting(
46 commandController,
"rs232-net-address",
47 "IP/address:port for RS232 net pluggable",
50 commandController,
"rs232-net-ip232",
51 "Enable IP232 protocol",
78static std::optional<RS232Net::NetworkSocketAddress> parseNetworkAddress(std::string_view address)
80 if (address.empty()) {
86 RS232Net::NetworkSocketAddress result;
87 memset(&result.address, 0,
sizeof(result.address));
89 struct addrinfo hints;
90 memset(&hints, 0,
sizeof(hints));
91 hints.ai_socktype = SOCK_STREAM;
92 hints.ai_protocol = IPPROTO_TCP;
95 hints.ai_family = AF_INET;
96 result.domain = PF_INET;
97 result.len =
sizeof(result.address.ipv4);
98 result.address.ipv4.sin_family = AF_INET;
99 result.address.ipv4.sin_port = 0;
100 result.address.ipv4.sin_addr.s_addr = INADDR_ANY;
103 hints.ai_family = AF_INET6;
104 result.domain = PF_INET6;
105 result.len =
sizeof(result.address.ipv6);
106 result.address.ipv6.sin6_family = AF_INET6;
107 result.address.ipv6.sin6_port = 0;
108 result.address.ipv6.sin6_addr = in6addr_any;
112 std::string addressPart;
113 std::string portPart;
115 if (!ipv6_port_part.empty()) {
117 if (!ipv6_address_part.starts_with(
'[') || !ipv6_port_part.starts_with(
':')) {
121 addressPart = std::string(ipv6_address_part.substr(1));
122 portPart = std::string(ipv6_port_part .
substr(1));
126 if (numColons == 0) {
128 addressPart = std::string(address);
129 }
else if (numColons == 1) {
132 addressPart = std::string(ipv4_address_part);
133 portPart = std::string(ipv4_port_part);
137 addressPart = std::string(address);
143 struct addrinfo* res;
144 if (getaddrinfo(addressPart.c_str(), portPart.c_str(), &hints, &res) != 0) {
148 memcpy(&result.address, res->ai_addr, res->ai_addrlen);
156 auto address = rs232NetAddressSetting.
getString();
157 auto socketAddress = parseNetworkAddress(address);
158 if (!socketAddress) {
159 throw PlugException(
"Incorrect address / could not resolve: ", address);
161 open_socket(*socketAddress);
172 auto& rs232Connector = checked_cast<RS232Connector&>(connector_);
180 thread = std::thread([
this]() { run(); });
188 static constexpr std::array<char, 2> dtr_lo = {IP232_MAGIC, IP232_DTR_LO};
196 if (thread.joinable()) thread.join();
206 return "RS232 Network pluggable. Connects the RS232 port to IP:PORT, "
207 "selected with the 'rs232-net-address' setting.";
212 bool ipMagic =
false;
216 if (poller.
poll(sockfd)) {
221 auto n =
sock_recv(sockfd, &b,
sizeof(b));
234 if (b != IP232_MAGIC) {
235 DCD = (b & IP232_DCD_MASK) == IP232_DCD_HI;
239 RI = (b & IP232_RI_MASK) == IP232_RI_HI;
244 if (b == IP232_MAGIC) {
254 std::scoped_lock lock(mutex);
264 auto* conn = checked_cast<RS232Connector*>(
getConnector());
266 if (!conn->acceptsData()) {
267 std::scoped_lock lock(mutex);
272 if (!conn->ready() || !RTS)
return;
274 std::scoped_lock lock(mutex);
275 if (queue.
empty())
return;
277 conn->recvByte(b, time);
281bool RS232Net::signalEvent(
const Event& )
286 std::scoped_lock lock(mutex);
297 auto value =
static_cast<char>(value_);
298 if ((value == IP232_MAGIC) && IP232) {
299 static constexpr std::array<char, 2> ff = {IP232_MAGIC, IP232_MAGIC};
302 net_put(std::span{&value, 1});
330 if (DTR == status)
return;
335 std::array<char, 2> dtr = {IP232_MAGIC, DTR ? IP232_DTR_HI : IP232_DTR_LO};
342 if (RTS == status)
return;
345 std::scoped_lock lock(mutex);
346 if (!queue.
empty()) {
353bool RS232Net::net_put(std::span<const char> buf)
357 if (
auto n =
sock_send(sockfd, buf.data(), buf.size()); n < 0) {
366void RS232Net::open_socket(
const NetworkSocketAddress& socket_address)
368 sockfd = socket(socket_address.domain, SOCK_STREAM, IPPROTO_TCP);
372 setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, std::bit_cast<char*>(&one),
sizeof(one));
374 if (connect(sockfd, &socket_address.address.generic, socket_address.len) < 0) {
380template<
typename Archive>
bool getBoolean() const noexcept
Represents something you can plug devices into.
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.
Thrown when a plug action fails.
bool isPluggedIn() const
Returns true if this pluggable is currently plugged into a connector.
void setConnector(Connector *conn)
Connector * getConnector() const
Get the connector this Pluggable is plugged into.
bool poll(int fd)
Waits for an event to occur on the given file descriptor.
void reset()
Reset aborted() to false.
void abort()
Aborts a poll in progress and any future poll attempts.
void serialize(Archive &ar, unsigned version)
RS232Net(EventDistributor &eventDistributor, Scheduler &scheduler, CommandController &commandController)
void recvByte(uint8_t value, EmuTime::param time) override
void plugHelper(Connector &connector, EmuTime::param time) override
void unplugHelper(EmuTime::param time) override
std::string_view getDescription() const override
Description for this pluggable.
void setRTS(bool status, EmuTime::param time) override
std::optional< bool > getRI(EmuTime::param time) const override
void signal(EmuTime::param time) override
std::optional< bool > getCTS(EmuTime::param time) const override
std::optional< bool > getDCD(EmuTime::param time) const override
void setDTR(bool status, EmuTime::param time) override
std::optional< bool > getDSR(EmuTime::param time) const override
std::string_view getName() const override
Name used to identify this pluggable.
EmuTime::param getCurrentTime() const
Get the current scheduler time.
zstring_view getString() const noexcept
std::pair< string_view, string_view > splitOnFirst(string_view str, string_view chars)
This file implemented 3 utility functions:
constexpr int OPENMSX_INVALID_SOCKET
ptrdiff_t sock_send(SOCKET sd, const char *buf, size_t count)
void sock_close(SOCKET sd)
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
ptrdiff_t sock_recv(SOCKET sd, char *buf, size_t count)
auto count(InputRange &&range, const T &value)
std::string_view substr(std::string_view utf8, std::string_view::size_type first=0, std::string_view::size_type len=std::string_view::npos)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)