xref: /openbmc/phosphor-modbus/rtu/port/base_port.hpp (revision b62e3dfe5505fdb8c2ab96156b62e3bfb878b7a6)
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