blob: bcf581d73ba6cd42e7ed01783006c6f8c1503369 [file] [log] [blame]
#include <cstring>
#include <gpioplus/handle.hpp>
#include <linux/gpio.h>
#include <stdexcept>
#include <system_error>
#include <type_traits>
namespace gpioplus
{
HandleFlags::HandleFlags(LineFlags line_flags) :
output(line_flags.output), active_low(line_flags.active_low),
open_drain(line_flags.open_drain), open_source(line_flags.open_source)
{
}
uint32_t HandleFlags::toInt() const
{
uint32_t ret = 0;
if (output)
{
ret |= GPIOHANDLE_REQUEST_OUTPUT;
}
else
{
ret |= GPIOHANDLE_REQUEST_INPUT;
}
if (active_low)
{
ret |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
}
if (open_drain)
{
ret |= GPIOHANDLE_REQUEST_OPEN_DRAIN;
}
if (open_source)
{
ret |= GPIOHANDLE_REQUEST_OPEN_SOURCE;
}
return ret;
}
static int build(const Chip& chip, const std::vector<Handle::Line>& lines,
HandleFlags flags, const char* consumer_label)
{
if (lines.size() > GPIOHANDLES_MAX)
{
throw std::runtime_error("Too many requested gpio handles");
}
struct gpiohandle_request req;
memset(&req, 0, sizeof(req));
for (size_t i = 0; i < lines.size(); ++i)
{
req.lineoffsets[i] = lines[i].offset;
req.default_values[i] = lines[i].default_value;
}
req.flags = flags.toInt();
strncpy(req.consumer_label, consumer_label, sizeof(req.consumer_label) - 1);
req.lines = lines.size();
int r = chip.getFd().getSys()->gpio_get_linehandle(*chip.getFd(), &req);
if (r < 0)
{
throw std::system_error(-r, std::generic_category(),
"gpio_get_linehandle");
}
return req.fd;
}
Handle::Handle(const Chip& chip, const std::vector<Line>& lines,
HandleFlags flags, const char* consumer_label) :
fd(build(chip, lines, flags, consumer_label), std::false_type(),
chip.getFd().getSys()),
nlines(lines.size())
{
}
const internal::Fd& Handle::getFd() const
{
return fd;
}
std::vector<uint8_t> Handle::getValues() const
{
std::vector<uint8_t> values(nlines);
getValues(values);
return values;
}
void Handle::getValues(std::vector<uint8_t>& values) const
{
struct gpiohandle_data data;
memset(&data, 0, sizeof(data));
int r = fd.getSys()->gpiohandle_get_line_values(*fd, &data);
if (r < 0)
{
throw std::system_error(-r, std::generic_category(),
"gpiohandle_get_line_values");
}
values.resize(nlines);
for (size_t i = 0; i < nlines; ++i)
{
values[i] = data.values[i];
}
}
void Handle::setValues(const std::vector<uint8_t>& values) const
{
if (values.size() != nlines)
{
throw std::runtime_error("Handle.setValues: Invalid input size");
}
struct gpiohandle_data data;
memset(&data, 0, sizeof(data));
for (size_t i = 0; i < nlines; ++i)
{
data.values[i] = values[i];
}
int r = fd.getSys()->gpiohandle_set_line_values(*fd, &data);
if (r < 0)
{
throw std::system_error(-r, std::generic_category(),
"gpiohandle_get_line_values");
}
}
} // namespace gpioplus