xref: /openbmc/phosphor-modbus/rtu/firmware/device_firmware.cpp (revision cf77ef540b925e10e3078bbdfbd795a0c1d9ff1f)
1 #include "device_firmware.hpp"
2 
3 #include "device/base_device.hpp"
4 
5 #include <phosphor-logging/lg2.hpp>
6 
7 namespace phosphor::modbus::rtu::device
8 {
9 
10 PHOSPHOR_LOG2_USING;
11 
getRandomId()12 static auto getRandomId() -> long int
13 {
14     struct timespec ts;
15     clock_gettime(CLOCK_REALTIME, &ts);
16     unsigned int seed = ts.tv_nsec ^ getpid();
17     srandom(seed);
18     return random() % 10000;
19 }
20 
getObjectPath(const config_intf::Config & config)21 static auto getObjectPath(const config_intf::Config& config)
22     -> sdbusplus::message::object_path
23 {
24     for (const auto& firmwareRegister : config.firmwareRegisters)
25     {
26         if (firmwareRegister.type == config_intf::FirmwareRegisterType::version)
27         {
28             if (firmwareRegister.name.empty())
29             {
30                 return sdbusplus::message::object_path(
31                            FirmwareIntf::namespace_path) /
32                        std::format("{}_{}", config.name, getRandomId());
33             }
34             else
35             {
36                 return sdbusplus::message::object_path(
37                            FirmwareIntf::namespace_path) /
38                        std::format("{}_{}_{}", config.name,
39                                    firmwareRegister.name, getRandomId());
40             }
41         }
42     }
43 
44     throw std::runtime_error(
45         "No firmware version register found for " + config.name);
46 }
47 
48 constexpr FirmwareIntf::Version::properties_t initVersion{
49     "Unknown", FirmwareIntf::VersionPurpose::Other};
50 constexpr FirmwareIntf::Activation::properties_t initActivation{
51     FirmwareIntf::Activations::NotReady,
52     FirmwareIntf::RequestedActivations::None};
53 constexpr FirmwareIntf::Definitions::properties_t initAssociations{};
54 
DeviceFirmware(sdbusplus::async::context & ctx,const config_intf::Config & config,PortIntf & serialPort)55 DeviceFirmware::DeviceFirmware(sdbusplus::async::context& ctx,
56                                const config_intf::Config& config,
57                                PortIntf& serialPort) :
58     objectPath(getObjectPath(config)),
59     currentFirmware(
60         std::make_unique<FirmwareIntf>(ctx, objectPath.str.c_str(), initVersion,
61                                        initActivation, initAssociations)),
62     config(config), serialPort(serialPort)
63 {
64     currentFirmware->Version::emit_added();
65     currentFirmware->Activation::emit_added();
66     currentFirmware->Definitions::emit_added();
67 
68     info("Device firmware {NAME} created successfully", "NAME", config.name);
69 }
70 
readVersionRegister()71 auto DeviceFirmware::readVersionRegister() -> sdbusplus::async::task<void>
72 {
73     const auto it = std::find_if(
74         config.firmwareRegisters.begin(), config.firmwareRegisters.end(),
75         [](const config_intf::FirmwareRegister& firmwareRegister) {
76             return firmwareRegister.type ==
77                    config_intf::FirmwareRegisterType::version;
78         });
79 
80     if (it == config.firmwareRegisters.end())
81     {
82         error("No firmware version register found for {NAME}", "NAME",
83               config.name);
84         co_return;
85     }
86 
87     const config_intf::FirmwareRegister& versionRegister = *it;
88 
89     auto registers = std::vector<uint16_t>(versionRegister.size);
90     auto ret = co_await serialPort.readHoldingRegisters(
91         config.address, versionRegister.offset, config.baudRate, config.parity,
92         registers);
93     if (!ret)
94     {
95         error("Failed to read holding registers {NAME} for {DEVICE_ADDRESS}",
96               "NAME", versionRegister.name, "DEVICE_ADDRESS", config.address);
97         co_return;
98     }
99 
100     std::string strValue = "";
101 
102     for (const auto& value : registers)
103     {
104         strValue += static_cast<char>((value >> 8) & 0xFF);
105         strValue += static_cast<char>(value & 0xFF);
106     }
107 
108     currentFirmware->version(strValue);
109     currentFirmware->activation(FirmwareIntf::Activation::Activations::Active);
110     auto associationList =
111         std::vector<std::tuple<std::string, std::string, std::string>>{
112             {"running", "ran_on", config.inventoryPath}};
113     currentFirmware->associations(associationList);
114 
115     info("Firmware version {VERSION} for {NAME} at {DEVICE_ADDRESS}", "VERSION",
116          strValue, "NAME", config.name, "DEVICE_ADDRESS", config.address);
117 }
118 
119 } // namespace phosphor::modbus::rtu::device
120