blob: 82cbed47693a547b5f39aedc86c71689f15dfc18 [file] [log] [blame]
/**
* Copyright © 2017 IBM Corporation
*
* 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.
*/
/**
* This program is a utility for accessing GPIOs.
* Actions:
* low: Set a GPIO low
* high: Set a GPIO high
* low_high: Set a GPIO low, delay if requested, set it high
* high_low: Set a GPIO high, delay if requested, set it low
*/
#include "argument.hpp"
#include "gpio.hpp"
#include <algorithm>
#include <chrono>
#include <iostream>
#include <map>
#include <phosphor-logging/log.hpp>
#include <thread>
using namespace phosphor::gpio;
using namespace phosphor::logging;
typedef void (*gpioFunction)(GPIO&, unsigned int);
using gpioFunctionMap = std::map<std::string, gpioFunction>;
/**
* Sets a GPIO low
*
* @param[in] gpio - the GPIO object
* @param[in] delayInMS - Unused in this function
*/
void low(GPIO& gpio, unsigned int)
{
gpio.set(GPIO::Value::low);
}
/**
* Sets a GPIO high
*
* @param[in] gpio - the GPIO object
* @param[in] delayInMS - Unused in this function
*/
void high(GPIO& gpio, unsigned int)
{
gpio.set(GPIO::Value::high);
}
/**
* Sets a GPIO high, then delays, then sets it low
*
* @param[in] gpio - the GPIO object
* @param[in] delayInMS - The delay in between the sets
*/
void highLow(GPIO& gpio, unsigned int delayInMS)
{
gpio.set(GPIO::Value::high);
std::chrono::milliseconds delay{delayInMS};
std::this_thread::sleep_for(delay);
gpio.set(GPIO::Value::low);
}
/**
* Sets a GPIO low, then delays, then sets it high
*
* @param[in] gpio - the GPIO to write
* @param[in] delayInMS - The delay in between the sets
*/
void lowHigh(GPIO& gpio, unsigned int delayInMS)
{
gpio.set(GPIO::Value::low);
std::chrono::milliseconds delay{delayInMS};
std::this_thread::sleep_for(delay);
gpio.set(GPIO::Value::high);
}
/**
* The actions supported by this program
*/
static const gpioFunctionMap functions{
{"low", low}, {"high", high}, {"low_high", lowHigh}, {"high_low", highLow}};
/**
* Prints usage and exits the program
*
* @param[in] err - the error message to print
* @param[in] argv - argv from main()
*/
void exitWithError(const char* err, char** argv)
{
std::cerr << "ERROR: " << err << "\n";
ArgumentParser::usage(argv);
exit(EXIT_FAILURE);
}
/**
* Returns the number value of the argument passed in.
*
* @param[in] name - the argument name
* @param[in] parser - the argument parser
* @param[in] argv - arv from main()
*/
template <typename T>
T getValueFromArg(const char* name, ArgumentParser& parser, char** argv)
{
char* p = NULL;
auto val = strtol(parser[name].c_str(), &p, 10);
// strol sets p on error, also we don't allow negative values
if (*p || (val < 0))
{
using namespace std::string_literals;
std::string msg = "Invalid "s + name + " value passed in";
exitWithError(msg.c_str(), argv);
}
return static_cast<T>(val);
}
int main(int argc, char** argv)
{
ArgumentParser args(argc, argv);
auto path = args["path"];
if (path == ArgumentParser::emptyString)
{
exitWithError("GPIO device path not specified", argv);
}
auto action = args["action"];
if (action == ArgumentParser::emptyString)
{
exitWithError("Action not specified", argv);
}
if (args["gpio"] == ArgumentParser::emptyString)
{
exitWithError("GPIO not specified", argv);
}
auto gpioNum = getValueFromArg<gpioNum_t>("gpio", args, argv);
// Not all actions require a delay, so not required
unsigned int delay = 0;
if (args["delay"] != ArgumentParser::emptyString)
{
delay = getValueFromArg<decltype(delay)>("delay", args, argv);
}
auto function = functions.find(action);
if (function == functions.end())
{
exitWithError("Invalid action value passed in", argv);
}
GPIO gpio{path, gpioNum, GPIO::Direction::output};
try
{
function->second(gpio, delay);
}
catch (const std::runtime_error& e)
{
std::cerr << e.what();
return -1;
}
return 0;
}