[PATCH phosphor-hwmon] Initial read-daemon for hwmon entries
Brad Bishop
bradleyb at fuzziesquirrel.com
Thu Oct 22 11:40:14 AEDT 2015
> On Oct 20, 2015, at 11:42 PM, OpenBMC Patches <patches at stwcx.xyz> wrote:
>
> From: Patrick Williams <patrick at stwcx.xyz>
>
> Discoveres hwmon entries for fans, input voltage, and temperature
Discovers
> sensors. Polls entries on a 1s interval and displays a message to
> stdout if one of the entries have changed.
> ---
> Makefile | 60 +++++++++++++++++++++++++++++++++++++++++++++
> README.md | 3 +++
> argument.C | 57 ++++++++++++++++++++++++++++++++++++++++++
> argument.H | 28 +++++++++++++++++++++
> directory.C | 38 ++++++++++++++++++++++++++++
> directory.H | 20 +++++++++++++++
> hwmon.H | 23 +++++++++++++++++
> readd.C | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> sensorcache.H | 27 ++++++++++++++++++++
> sensorset.C | 26 ++++++++++++++++++++
> sensorset.H | 31 +++++++++++++++++++++++
> sysfs.H | 31 +++++++++++++++++++++++
> 12 files changed, 423 insertions(+)
> create mode 100644 Makefile
> create mode 100644 README.md
> create mode 100644 argument.C
> create mode 100644 argument.H
> create mode 100644 directory.C
> create mode 100644 directory.H
> create mode 100644 hwmon.H
> create mode 100644 readd.C
> create mode 100644 sensorcache.H
> create mode 100644 sensorset.C
> create mode 100644 sensorset.H
> create mode 100644 sysfs.H
>
> diff --git a/Makefile b/Makefile
> new file mode 100644
> index 0000000..49a7e4d
> --- /dev/null
> +++ b/Makefile
> @@ -0,0 +1,60 @@
> +LIBS += libphosphor-hwmon.so
> +libphosphor-hwmon.so_OBJS += argument.o
> +libphosphor-hwmon.so_OBJS += directory.o
So if I want to use this directory utility can I just link my application to libphosphor-hwmon?
> +libphosphor-hwmon.so_OBJS += sensorset.o
> +
> +EXES += phosphor-hwmon-readd
> +phosphor-hwmon-readd_OBJS += readd.o
> +phosphor-hwmon-readd_LIBS += phosphor-hwmon
> +
> +#TODO: Issue#1 - Add the write-daemon for fan, pwm control.
> +#EXES += phosphor-hwmon-writed
> +#phosphor-hwmon-writed_OBJS += writed.o
> +#phosphor-hwmon-writed_LIBS += phosphor-hwmon
> +
> +#### -----------------------------------------------------------------------####
> +# #
> +## Compilare Regulas Sequi ##
> +# #
> +#### -----------------------------------------------------------------------####
> +
> +CXXFLAGS ?= -O3 -g -pipe
> +CXXFLAGS += --std=gnu++14 -Wall -flto -fPIC
> +
> +define __BUILD_EXE
> +$1 : $$($1_OBJS) $$(LIBS)
> + $$(LINK.cpp) -o $$@ $$^
> +
> +#include $$($1_OBJS:.o=.d)
> +endef
> +
> +$(foreach exe,$(EXES),$(eval $(call __BUILD_EXE,$(exe))))
> +
> +define __BUILD_LIB
> +$1 : $$($1_OBJS)
> + $$(LINK.cpp) -shared -o $$@ $$^
> +
> +#include $$($1_OBJS:.o=.d)
> +endef
> +
> +$(foreach lib,$(LIBS),$(eval $(call __BUILD_LIB,$(lib))))
> +
> +.PHONY: clean
> +clean:
> + $(RM) $(foreach exe,$(EXES),$(exe) $($(exe)_OBJS)) \
> + $(foreach lib,$(LIBS),$(lib) $($(lib)_OBJS))
> +
> +DESTDIR ?= /
> +BINDIR ?= /usr/bin
> +LIBDIR ?= /usr/lib
> +
> +.PHONY: install
> +install:
> + install -m 0755 -d $(DESTDIR)$(BINDIR)
> + install -m 0755 $(EXES) $(DESTDIR)$(BINDIR)
> + install -m 0755 -d $(DESTDIR)$(LIBDIR)
> + install -m 0755 $(LIBS) $(DESTDIR)$(LIBDIR)
> +
> +.DEFAULT_GOAL: all
> +.PHONY: all
> +all: $(EXES) $(LIBS)
> diff --git a/README.md b/README.md
> new file mode 100644
> index 0000000..88122e6
> --- /dev/null
> +++ b/README.md
> @@ -0,0 +1,3 @@
> += phosphor-hwmon =
> +
> +Exposes generic hwmon entries as DBus objects.
> diff --git a/argument.C b/argument.C
> new file mode 100644
> index 0000000..15c258e
> --- /dev/null
> +++ b/argument.C
> @@ -0,0 +1,57 @@
> +#include <iostream>
> +#include <iterator>
> +#include <algorithm>
> +#include <cassert>
> +#include "argument.H"
> +
> +ArgumentParser::ArgumentParser(int argc, char** argv)
> +{
> + int option = 0;
> + while(-1 != (option = getopt_long(argc, argv, optionstr, options, NULL)))
> + {
> + if ((option == '?') || (option == 'h'))
> + {
> + usage(argv);
> + exit(-1);
> + }
> +
> + auto i = &options[0];
> + while ((i->val != option) && (i->val != 0)) ++i;
> +
> + if (i->val)
> + arguments[i->name] = (i->has_arg ? optarg : true_string);
> + }
> +}
> +
> +const std::string& ArgumentParser::operator[](const std::string& opt)
> +{
> + auto i = arguments.find(opt);
> + if (i == arguments.end())
> + {
> + return empty_string;
> + }
> + else
> + {
> + return i->second;
> + }
> +}
> +
> +void ArgumentParser::usage(char** argv)
> +{
> + std::cerr << "Usage: " << argv[0] << " [options]" << std::endl;
> + std::cerr << "Options:" << std::endl;
> + std::cerr << " --path=<path> sysfs location to monitor"
> + << std::endl;
> +}
> +
> +const option ArgumentParser::options[] =
> +{
> + { "path", required_argument, NULL, 'p' },
> + { "help", no_argument, NULL, 'h' },
> + { 0, 0, 0, 0},
> +};
> +
> +const char* ArgumentParser::optionstr = "p:?h";
> +
> +const std::string ArgumentParser::true_string = "true";
> +const std::string ArgumentParser::empty_string = "";
> diff --git a/argument.H b/argument.H
> new file mode 100644
> index 0000000..252fc36
> --- /dev/null
> +++ b/argument.H
> @@ -0,0 +1,28 @@
> +#ifndef __ARGUMENT_H
> +#define __ARGUMENT_H
> +#include <getopt.h>
> +#include <map>
> +#include <string>
> +
> +class ArgumentParser
> +{
> + public:
> + ArgumentParser(int argc, char** argv);
> + const std::string& operator[](const std::string& opt);
> +
> + static void usage(char** argv);
> +
> + static const std::string true_string;
> + static const std::string empty_string;
> +
> + private:
> + std::map<const std::string, std::string> arguments;
> +
> + static const option options[];
> + static const char* optionstr;
> +
> + private:
> + ArgumentParser() {};
> +};
> +
> +#endif
> diff --git a/directory.C b/directory.C
> new file mode 100644
> index 0000000..5be9ff1
> --- /dev/null
> +++ b/directory.C
> @@ -0,0 +1,38 @@
> +#include <cerrno>
> +#include <cstring>
> +#include <iostream>
> +#include "directory.H"
> +
> +Directory::Directory(const std::string& path) : entry(nullptr)
> +{
> + dirp = opendir(path.c_str());
> + if (NULL == dirp)
> + {
> + auto e = errno;
> + std::cerr << "Error opening directory " << path.c_str()
> + << " : " << strerror(e) << std::endl;
> + }
> +}
> +
> +Directory::~Directory()
> +{
> + if (dirp)
> + {
> + closedir(dirp);
> + }
> +}
> +
> +bool Directory::next(std::string& name)
> +{
> + if (!dirp) return false;
> +
> + dirent entry;
> + dirent* result;
> +
> + auto rc = readdir_r(dirp, &entry, &result);
> +
> + if ((rc) || (NULL == result)) return false;
> +
> + name = entry.d_name;
> + return true;
> +}
> diff --git a/directory.H b/directory.H
> new file mode 100644
> index 0000000..1b085c5
> --- /dev/null
> +++ b/directory.H
> @@ -0,0 +1,20 @@
> +#ifndef __DIRECTORY_H
> +#define __DIRECTORY_H
> +
> +#include <string>
> +#include <dirent.h>
> +
> +class Directory
> +{
> + public:
> + explicit Directory(const std::string& path);
> + ~Directory();
> +
> + bool next(std::string& name);
> +
> + private:
> + dirent* entry;
> + DIR* dirp;
> +};
> +
> +#endif
> diff --git a/hwmon.H b/hwmon.H
> new file mode 100644
> index 0000000..494d38e
> --- /dev/null
> +++ b/hwmon.H
> @@ -0,0 +1,23 @@
> +#ifndef __HWMON_H
> +#define __HWMON_H
> +
> +#include <string>
> +
> +namespace hwmon
> +{
> + using namespace std::literals;
> +
> + namespace entry
> + {
> + static const std::string input = "input"s;
> + }
> +
> + namespace type
> + {
> + static const std::string fan = "fan"s;
> + static const std::string temp = "temp"s;
> + static const std::string volt = "in"s;
> + }
> +}
> +
> +#endif
> diff --git a/readd.C b/readd.C
> new file mode 100644
> index 0000000..467ecbf
> --- /dev/null
> +++ b/readd.C
> @@ -0,0 +1,79 @@
> +#include <iostream>
> +#include <memory>
> +#include <thread>
> +#include "argument.H"
> +#include "sensorset.H"
> +#include "sensorcache.H"
> +#include "hwmon.H"
> +#include "sysfs.H"
> +
> +static void exit_with_error(const char* err, char** argv)
> +{
> + ArgumentParser::usage(argv);
> + std::cerr << std::endl;
> + std::cerr << "ERROR: " << err << std::endl;
> + exit(-1);
> +}
> +
> +int main(int argc, char** argv)
> +{
> + // Read arguments.
> + auto options = std::make_unique<ArgumentParser>(argc, argv);
> +
> + // Parse out path argument.
> + auto path = (*options)["path"];
> + if (path == ArgumentParser::empty_string)
> + {
> + exit_with_error("Path not specified.", argv);
> + }
> +
> + // Finished getting options out, so release the parser.
> + options.release();
> +
> + // Check sysfs for available sensors.
> + auto sensors = std::make_unique<SensorSet>(path);
> + auto sensor_cache = std::make_unique<SensorCache>();
> +
> + // TODO: Issue#3 - Need to make calls to the dbus sensor cache here to
> + // ensure the objects all exist?
> +
> + // Polling loop.
> + while(true)
> + {
> + // Iterate through all the sensors.
> + for(auto& i : *sensors)
> + {
> + if (i.second.find(hwmon::entry::input) != i.second.end())
> + {
> + // Read value from sensor.
> + int value = 0;
> + read_sysfs(make_sysfs_path(path,
> + i.first.first, i.first.second,
> + hwmon::entry::input),
> + value);
> +
> + // Update sensor cache.
> + if (sensor_cache->update(i.first, value))
> + {
> + // TODO: Issue#4 - dbus event here.
> + std::cout << i.first.first << i.first.second << " = "
> + << value << std::endl;
> + }
> + }
> + }
> +
> + // Sleep until next interval.
> + // TODO: Issue#5 - Make this configurable.
> + // TODO: Issue#6 - Optionally look at polling interval sysfs entry.
> + {
> + using namespace std::literals::chrono_literals;
> + std::this_thread::sleep_for(1s);
> + }
> +
> + // TODO: Issue#7 - Should probably periodically check the SensorSet
> + // for new entries.
> + }
> +
> + return 0;
> +}
> +
> diff --git a/sensorcache.H b/sensorcache.H
> new file mode 100644
> index 0000000..64333d8
> --- /dev/null
> +++ b/sensorcache.H
> @@ -0,0 +1,27 @@
> +#ifndef __SENSORCACHE_H
> +#define __SENSORCACHE_H
> +
> +#include <map>
> +
> +class SensorCache
> +{
> + public:
> + typedef std::map<std::pair<std::string, std::string>,
> + int> container_t;
> +
> + bool update(const container_t::key_type& k,
> + const container_t::mapped_type& v)
> + {
> + auto& i = container[k];
> + if (v == i) return false;
> + else
> + {
> + i = v;
> + return true;
> + }
> + }
> + private:
> + container_t container;
> +};
> +
> +#endif
> diff --git a/sensorset.C b/sensorset.C
> new file mode 100644
> index 0000000..8b59ac1
> --- /dev/null
> +++ b/sensorset.C
> @@ -0,0 +1,26 @@
> +#include <regex>
> +#include <iostream>
> +#include "sensorset.H"
> +#include "directory.H"
> +
> +// TODO: Issue#2 - STL regex generates really bloated code. Use POSIX regex
> +// interfaces instead.
> +static const std::regex sensors_regex =
> + std::regex("^(fan|in|temp)([0-9]+)_([a-z]*)", std::regex::extended);
> +static const auto sensor_regex_match_count = 4;
> +
> +SensorSet::SensorSet(const std::string& path)
> +{
> + Directory d(path);
> + std::string file;
> +
> + while(d.next(file))
> + {
> + std::smatch match;
> + std::regex_search(file, match, sensors_regex);
> +
> + if (match.size() != sensor_regex_match_count) continue;
> +
> + container[make_pair(match[1],match[2])].emplace(match[3]);
> + }
> +}
> diff --git a/sensorset.H b/sensorset.H
> new file mode 100644
> index 0000000..beb8446
> --- /dev/null
> +++ b/sensorset.H
> @@ -0,0 +1,31 @@
> +#ifndef __SENSORSET_H
> +#define __SENSORSET_H
> +
> +#include <map>
> +#include <set>
> +#include <string>
> +
> +class SensorSet
> +{
> + public:
> + typedef std::map<std::pair<std::string, std::string>,
> + std::set<std::string>> container_t;
> +
> + SensorSet(const std::string& path);
> +
> + container_t::const_iterator begin()
> + {
> + return const_cast<const container_t&>(container).begin();
> + }
> +
> + container_t::const_iterator end()
> + {
> + return const_cast<const container_t&>(container).end();
> + }
> +
> + private:
> + container_t container;
> +
> +};
> +
> +#endif
> diff --git a/sysfs.H b/sysfs.H
> new file mode 100644
> index 0000000..d073d77
> --- /dev/null
> +++ b/sysfs.H
> @@ -0,0 +1,31 @@
> +#ifndef __SYSFS_H
> +#define __SYSFS_H
> +
> +#include <fstream>
> +#include <string>
> +
> +template <typename T>
> +void read_sysfs(const std::string& path, T& val)
> +{
> + std::ifstream s(path);
> + s >> val;
> +}
> +
> +template <typename T>
> +void write_sysfs(const std::string& path, const T& val)
> +{
> + std::ofstream s(path);
> + s << val;
> +}
> +
> +const std::string make_sysfs_path(const std::string& path,
> + const std::string& type,
> + const std::string& id,
> + const std::string& entry)
> +{
> + using namespace std::literals;
> +
> + return path + "/"s + type + id + "_"s + entry;
> +}
> +
> +#endif
> --
> 2.6.0
>
>
> _______________________________________________
> openbmc mailing list
> openbmc at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/openbmc
More information about the openbmc
mailing list