ipmifan/ipmi.cpp

141 lines
4.1 KiB
C++

#include "ipmi.h"
#include <algorithm>
#include <iostream>
static constexpr size_t IPMI_RAW_MAX_ARGS = 65536*2;
static double ipmi_convert_sensor_reading(void *sensor_reading, int sensor_reading_type)
{
if(sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL)
return (double)(*((uint8_t *)sensor_reading));
else if (sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32)
return (double)(*((uint32_t *)sensor_reading));
else if (sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE)
return *((double *)sensor_reading);
return 0;
}
Sensor ipmi_read_sensor_from_ctx(ipmi_monitoring_ctx_t ctx)
{
Sensor sensor;
sensor.chip = "IPMI";
int record_id = ipmi_monitoring_sensor_read_record_id(ctx);
int reading_type = ipmi_monitoring_sensor_read_sensor_reading_type(ctx);
char *name = ipmi_monitoring_sensor_read_sensor_name(ctx);
void *reading = ipmi_monitoring_sensor_read_sensor_reading(ctx);
if(record_id < 0 || reading_type < 0 || !name || !reading)
return sensor;
if(reading_type != IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32 &&
reading_type != IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE)
return sensor;
sensor.name.assign(name);
sensor.reading = ipmi_convert_sensor_reading(reading, reading_type);
sensor.id = record_id;
return sensor;
}
bool ipmi_fill_sensor_ids(std::vector<Sensor>& sensors, ipmi_monitoring_ctx_t ctx, struct ipmi_monitoring_ipmi_config* config)
{
unsigned int types[] = {IPMI_MONITORING_SENSOR_TYPE_TEMPERATURE};
unsigned int types_len = sizeof(types)/sizeof(types[0]);
int sensor_count = ipmi_monitoring_sensor_readings_by_sensor_type(ctx, NULL, config, 0, types, types_len, NULL, NULL);
for(int i = 0; i < sensor_count; ++i, ipmi_monitoring_sensor_iterator_next(ctx))
{
Sensor sensor = ipmi_read_sensor_from_ctx(ctx);
auto search = std::find(sensors.begin(), sensors.end(), sensor);
if(search != sensors.end())
*search = sensor;
}
for(Sensor& sensor : sensors)
{
if(sensor.id == 0 && sensor.chip == "IPMI")
return false;
}
return true;
}
bool ipmi_update_sensors(std::vector<Sensor>& sensors, ipmi_monitoring_ctx_t ctx, struct ipmi_monitoring_ipmi_config* config)
{
unsigned int *ids = new unsigned int[sensors.size()];
for(size_t i = 0; i < sensors.size(); ++i)
ids[i] = sensors[i].id;
int sensor_count = ipmi_monitoring_sensor_readings_by_record_id(ctx, NULL, config, 0, ids, sensors.size(), NULL, NULL);
delete[] ids;
if(sensor_count < static_cast<int>(sensors.size()))
return false;
for(int i = 0; i < sensor_count; ++i, ipmi_monitoring_sensor_iterator_next(ctx))
{
Sensor readsensor = ipmi_read_sensor_from_ctx(ctx);
for(Sensor& sensor : sensors)
{
if(sensor.id == readsensor.id)
sensor = readsensor;
}
}
return true;
}
ipmi_monitoring_ctx_t init_ipmi_monitoring()
{
int errnum;
int ret = ipmi_monitoring_init(/*IPMI_MONITORING_FLAGS_DEBUG*/ 0, &errnum);
if(ret < 0)
{
std::cerr<<"Could not init ipmi "<<ipmi_monitoring_ctx_strerror(errnum)<<'\n';
return NULL;
}
ipmi_monitoring_ctx_t ctx = ipmi_monitoring_ctx_create();
if(!ctx)
{
std::cerr<<"failed to create montioring context\n";
return NULL;
}
return ctx;
}
ipmi_ctx_t ipmi_open_context()
{
ipmi_ctx_t ctx = ipmi_ctx_create();
if(!ctx)
{
std::cerr<<"Could not allocae raw context\n";
return nullptr;
}
ipmi_driver_type_t driver = IPMI_DEVICE_OPENIPMI;
int ret = ipmi_ctx_find_inband(ctx, &driver, false, 0, 0, nullptr, 0, 0);
if(ret < 0)
{
std::cerr<<"Could not create raw context "<<ipmi_ctx_errormsg(ctx)<<'\n';
ipmi_ctx_destroy(ctx);
return nullptr;
}
return ctx;
}
bool ipmi_set_fan_group(ipmi_ctx_t raw_ctx, uint8_t group, double speed)
{
char converted_speed = std::max(std::min(static_cast<char>(100), static_cast<char>(speed*100)), static_cast<char>(0));
char command[] = {0x70, 0x66, 0x01, static_cast<char>(group), converted_speed};
char bytesrx[IPMI_RAW_MAX_ARGS] = {0};
int rxlen = ipmi_cmd_raw(raw_ctx, 0, 0x30, command, sizeof(command), bytesrx, IPMI_RAW_MAX_ARGS);
if(rxlen < 0)
{
std::cerr<<"Raw write to ipmi failed with: "<<ipmi_ctx_errormsg(raw_ctx);
return false;
}
return true;
}