xref: /openbmc/phosphor-modbus/rtu/port/base_port.hpp (revision 7f9d41ddfad8c74d51fa1cf4a591b7f085254396)
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 
37 template <typename T>
38 concept HasPropertiesMembers = requires(T properties) {
39                                    {
40                                        properties.name
41                                    } -> std::same_as<std::string&>;
42                                    {
43                                        properties.mode
44                                    } -> std::same_as<std::string&>;
45                                    {
46                                        properties.baud_rate
47                                    } -> std::same_as<uint64_t&>;
48                                    {
49                                        properties.rts_delay
50                                    } -> std::same_as<uint64_t&>;
51                                };
52 
53 template <typename T>
54 concept HasConfigMembers = requires(T config) {
55                                { config.name } -> std::same_as<std::string&>;
56                                { config.portMode } -> std::same_as<PortMode&>;
57                                { config.baudRate } -> std::same_as<uint32_t&>;
58                                { config.rtsDelay } -> std::same_as<uint16_t&>;
59                            };
60 
61 template <HasConfigMembers BaseConfig, HasPropertiesMembers BaseProperties>
62 auto updateBaseConfig(BaseConfig& config, const BaseProperties& properties)
63     -> bool
64 {
65     PHOSPHOR_LOG2_USING;
66 
67     config.name = properties.name;
68     config.baudRate = static_cast<uint32_t>(properties.baud_rate);
69     config.rtsDelay = static_cast<uint16_t>(properties.rts_delay);
70 
71     for (const auto& [modeStr, portMode] : config::validPortModes)
72     {
73         if (modeStr == properties.mode)
74         {
75             config.portMode = portMode;
76             break;
77         }
78     }
79     if (config.portMode == PortMode::unknown)
80     {
81         error("Invalid port mode {PORT_MODE} for {NAME}", "PORT_MODE",
82               properties.mode, "NAME", properties.name);
83         return false;
84     }
85 
86     debug("Base Port config: {NAME} {PORT_MODE} {BAUD_RATE} {RTS_DELAY}",
87           "NAME", config.name, "PORT_MODE", config.portMode, "BAUD_RATE",
88           config.baudRate, "RTS_DELAY", config.rtsDelay);
89 
90     return true;
91 }
92 
93 } // namespace config
94 
95 class BasePort
96 {
97   public:
98     explicit BasePort(sdbusplus::async::context& ctx,
99                       const config::Config& config,
100                       const std::string& devicePath);
101 
102     auto readHoldingRegisters(uint8_t deviceAddress, uint16_t registerOffset,
103                               uint32_t baudRate, Parity parity,
104                               std::vector<uint16_t>& registers)
105         -> sdbusplus::async::task<bool>;
106 
107   private:
108     std::string name;
109     int fd = -1;
110     std::unique_ptr<ModbusIntf> modbus;
111     sdbusplus::async::mutex mutex;
112 };
113 
114 } // namespace phosphor::modbus::rtu::port
115