OXYGENHUB
◆ main openmsx / src / utils / SerialPort.hh
2.9 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef SERIALPORT_HH
2
#define SERIALPORT_HH
3
4
#include "zstring_view.hh"
5
6
#include <cstddef>
7
#include <cstdint>
8
#include <expected>
9
#include <span>
10
#include <string>
11
#include <string_view>
12
#include <vector>
13
14
namespace openmsx::serial {
15
16
#ifdef _WIN32
17
using serial_handle_t = void*;
18
#else
19
using serial_handle_t = int;
20
#endif
21
22
// Platform-specific error value, captured at the moment of failure (a copy
23
// of errno on POSIX, GetLastError() on Windows). It is safe to store the
24
// value and format it later with to_string(): no other call can overwrite
25
// the error state in between.
26
struct ErrorCode {
27
#ifdef _WIN32
28
	unsigned long value = 0;
29
#else
30
	int value = 0;
31
#endif
32
};
33
34
[[nodiscard]] std::string to_string(ErrorCode ec);
35
36
struct SerialParams {
37
	unsigned baudRate = 115200;
38
	int dataBits = 8;
39
	int stopBits = 1; // 1, 2 (1.5 is not supported on most platforms)
40
	int parity = 0;   // 0=none, 1=odd, 2=even, 3=mark, 4=space
41
};
42
43
// Result of a read()/write(): success carries the number of bytes
44
// transferred (read() may return 0 = no data available within the port's
45
// timeouts), failure carries the ErrorCode.
46
using IoResult = std::expected<size_t, ErrorCode>;
47
48
// An open serial port. Move-only RAII: the destructor closes the port, so
49
// a Handle cannot outlive its open port (there is no explicit close()).
50
// Not thread-safe by itself: callers must synchronize concurrent access
51
// (RS232Raw joins its worker thread before closing the port).
52
struct Handle {
53
	Handle(const Handle&) = delete;
54
	Handle& operator=(const Handle&) = delete;
55
	Handle(Handle&& other) noexcept;
56
	Handle& operator=(Handle&& other) noexcept;
57
	~Handle();
58
59
	// Blocking reads/writes.
60
	[[nodiscard]] IoResult read(std::span<uint8_t> buf) const;
61
	[[nodiscard]] IoResult write(std::span<const uint8_t> buf) const;
62
63
	// The underlying OS handle/fd, e.g. for integration with openMSX's
64
	// Poller on POSIX.
65
	[[nodiscard]] serial_handle_t native_handle() const { return handle; }
66
67
	[[nodiscard]] std::expected<void, ErrorCode> set_params(const SerialParams& params) const;
68
	[[nodiscard]] std::expected<void, ErrorCode> set_dtr(bool on) const;
69
	[[nodiscard]] std::expected<void, ErrorCode> set_rts(bool on) const;
70
71
	struct ModemStatus {
72
		bool cts;
73
		bool dsr;
74
		bool dcd;
75
		bool ri;
76
	};
77
	// Currently unused by openMSX (RS232Raw keeps fixed modem-status
78
	// values instead of polling the hardware); kept for future use.
79
	[[nodiscard]] std::expected<ModemStatus, ErrorCode> get_modem_status() const;
80
81
private:
82
	friend std::expected<Handle, ErrorCode> open(zstring_view portName, const SerialParams& params);
83
	explicit Handle(serial_handle_t handle_);
84
	void release() noexcept;
85
	serial_handle_t handle;
86
};
87
88
// Opens the port with the given parameters. On failure the returned
89
// ErrorCode is valid and no Handle is produced.
90
[[nodiscard]] std::expected<Handle, ErrorCode> open(zstring_view portName, const SerialParams& params);
91
92
[[nodiscard]] std::vector<std::string> list_ports();
93
94
} // namespace openmsx::serial
95
96
#endif