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