blob: 4ff67c53f4ffd4fa02ca1ea7fd8f9697e1ba9160 [file] [log] [blame]
/**
* Copyright 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "config.h"
#include "build/buildjson.hpp"
#include "conf.hpp"
#include "interfaces.hpp"
#include "pid/builder.hpp"
#include "pid/buildjson.hpp"
#include "pid/pidthread.hpp"
#include "pid/zone.hpp"
#include "sensors/builder.hpp"
#include "sensors/buildjson.hpp"
#include "sensors/manager.hpp"
#include "threads/busthread.hpp"
#include "util.hpp"
#include <getopt.h>
#include <chrono>
#include <iostream>
#include <map>
#include <memory>
#include <sdbusplus/bus.hpp>
#include <thread>
#include <unordered_map>
#include <utility>
#include <vector>
#if CONFIGURE_DBUS
#include "dbus/dbusconfiguration.hpp"
#endif
/* The YAML converted sensor list. */
extern std::map<std::string, struct SensorConfig> sensorConfig;
/* The YAML converted PID list. */
extern std::map<int64_t, PIDConf> zoneConfig;
/* The YAML converted Zone configuration. */
extern std::map<int64_t, struct ZoneConfig> zoneDetailsConfig;
int main(int argc, char* argv[])
{
int rc = 0;
std::string configPath = "";
while (1)
{
// clang-format off
static struct option long_options[] = {
{"conf", required_argument, 0, 'c'},
{0, 0, 0, 0}
};
// clang-format on
int option_index = 0;
int c = getopt_long(argc, argv, "c:", long_options, &option_index);
if (c == -1)
{
break;
}
switch (c)
{
case 'c':
configPath = std::string{optarg};
break;
default:
/* skip garbage. */
continue;
}
}
auto modeControlBus = sdbusplus::bus::new_system();
#if CONFIGURE_DBUS
{
dbus_configuration::init(modeControlBus);
}
#endif
SensorManager mgmr;
std::unordered_map<int64_t, std::unique_ptr<PIDZone>> zones;
// Create a manager for the ModeBus because we own it.
static constexpr auto modeRoot = "/xyz/openbmc_project/settings/fanctrl";
sdbusplus::server::manager::manager(modeControlBus, modeRoot);
/*
* When building the sensors, if any of the dbus passive ones aren't on the
* bus, it'll fail immediately.
*/
if (configPath.length() > 0)
{
try
{
auto jsonData = parseValidateJson(configPath);
mgmr = buildSensors(buildSensorsFromJson(jsonData));
std::map<int64_t, PIDConf> pidConfig;
std::map<int64_t, struct ZoneConfig> zoneConfig;
std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(jsonData);
zones = buildZones(pidConfig, zoneConfig, mgmr, modeControlBus);
}
catch (const std::exception& e)
{
std::cerr << "Failed during building: " << e.what() << "\n";
exit(EXIT_FAILURE); /* fatal error. */
}
}
else
{
mgmr = buildSensors(sensorConfig);
zones = buildZones(zoneConfig, zoneDetailsConfig, mgmr, modeControlBus);
}
if (0 == zones.size())
{
std::cerr << "No zones defined, exiting.\n";
return rc;
}
/*
* All sensors are managed by one manager, but each zone has a pointer to
* it.
*/
auto& hostSensorBus = mgmr.getHostBus();
auto& passiveListeningBus = mgmr.getPassiveBus();
std::cerr << "Starting threads\n";
/* TODO(venture): Ask SensorManager if we have any passive sensors. */
struct ThreadParams p = {std::ref(passiveListeningBus), ""};
std::thread l(busThread, std::ref(p));
/* TODO(venture): Ask SensorManager if we have any host sensors. */
static constexpr auto hostBus = "xyz.openbmc_project.Hwmon.external";
struct ThreadParams e = {std::ref(hostSensorBus), hostBus};
std::thread te(busThread, std::ref(e));
static constexpr auto modeBus = "xyz.openbmc_project.State.FanCtrl";
struct ThreadParams m = {std::ref(modeControlBus), modeBus};
std::thread tm(busThread, std::ref(m));
std::vector<std::thread> zoneThreads;
/* TODO(venture): This was designed to have one thread per zone, but really
* it could have one thread for all the zones and iterate through each
* sequentially as it goes -- and it'd probably be fast enough to do that,
* however, a system isn't likely going to have more than a couple zones.
* If it only has a couple zones, then this is fine.
*/
for (const auto& i : zones)
{
std::cerr << "pushing zone" << std::endl;
zoneThreads.push_back(std::thread(pidControlThread, i.second.get()));
}
l.join();
te.join();
tm.join();
for (auto& t : zoneThreads)
{
t.join();
}
return rc;
}