1 #pragma once
2
3 #include "modbus/modbus.hpp"
4
5 #include <phosphor-logging/lg2.hpp>
6 #include <sdbusplus/async.hpp>
7 #include <xyz/openbmc_project/Configuration/USBPort/client.hpp>
8
9 #include <concepts>
10
11 namespace phosphor::modbus::rtu::port
12 {
13
14 using ModbusIntf = phosphor::modbus::rtu::Modbus;
15
16 namespace config
17 {
18
19 enum class PortMode
20 {
21 rs232,
22 rs485,
23 unknown
24 };
25
26 static constexpr std::array<std::pair<std::string_view, PortMode>, 2>
27 validPortModes = {{{"RS232", PortMode::rs232}, {"RS485", PortMode::rs485}}};
28
29 struct Config
30 {
31 std::string name = "unknown";
32 PortMode portMode = PortMode::unknown;
33 uint32_t baudRate = 0;
34 uint16_t rtsDelay = 0;
35
36 virtual ~Config() = default;
37 };
38
39 template <typename T>
40 concept HasPropertiesMembers = requires(T properties) {
41 {
42 properties.name
43 } -> std::same_as<std::string&>;
44 {
45 properties.mode
46 } -> std::same_as<std::string&>;
47 {
48 properties.baud_rate
49 } -> std::same_as<uint64_t&>;
50 {
51 properties.rts_delay
52 } -> std::same_as<uint64_t&>;
53 };
54
55 template <typename T>
56 concept HasConfigMembers = requires(T config) {
57 { config.name } -> std::same_as<std::string&>;
58 { config.portMode } -> std::same_as<PortMode&>;
59 { config.baudRate } -> std::same_as<uint32_t&>;
60 { config.rtsDelay } -> std::same_as<uint16_t&>;
61 };
62
63 template <HasConfigMembers BaseConfig, HasPropertiesMembers BaseProperties>
updateBaseConfig(BaseConfig & config,const BaseProperties & properties)64 auto updateBaseConfig(BaseConfig& config, const BaseProperties& properties)
65 -> bool
66 {
67 PHOSPHOR_LOG2_USING;
68
69 config.name = properties.name;
70 config.baudRate = static_cast<uint32_t>(properties.baud_rate);
71 config.rtsDelay = static_cast<uint16_t>(properties.rts_delay);
72
73 for (const auto& [modeStr, portMode] : config::validPortModes)
74 {
75 if (modeStr == properties.mode)
76 {
77 config.portMode = portMode;
78 break;
79 }
80 }
81 if (config.portMode == PortMode::unknown)
82 {
83 error("Invalid port mode {PORT_MODE} for {NAME}", "PORT_MODE",
84 properties.mode, "NAME", properties.name);
85 return false;
86 }
87
88 debug("Base Port config: {NAME} {PORT_MODE} {BAUD_RATE} {RTS_DELAY}",
89 "NAME", config.name, "PORT_MODE", config.portMode, "BAUD_RATE",
90 config.baudRate, "RTS_DELAY", config.rtsDelay);
91
92 return true;
93 }
94
95 } // namespace config
96
97 class BasePort
98 {
99 public:
100 explicit BasePort(sdbusplus::async::context& ctx,
101 const config::Config& config,
102 const std::string& devicePath);
103
104 auto readHoldingRegisters(uint8_t deviceAddress, uint16_t registerOffset,
105 uint32_t baudRate, Parity parity,
106 std::vector<uint16_t>& registers)
107 -> sdbusplus::async::task<bool>;
108
109 private:
110 std::string name;
111 int fd = -1;
112 std::unique_ptr<ModbusIntf> modbus;
113 sdbusplus::async::mutex mutex;
114 };
115
116 } // namespace phosphor::modbus::rtu::port
117