diff --git a/dependencies/build/getoptPlusPlus/getoptpp.cc b/dependencies/build/getoptPlusPlus/getoptpp.cc index aae499a9..eca180a7 100644 --- a/dependencies/build/getoptPlusPlus/getoptpp.cc +++ b/dependencies/build/getoptPlusPlus/getoptpp.cc @@ -1,18 +1,18 @@ - /* (C) 2011 Viktor Lofgren - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +/* (C) 2011 Viktor Lofgren + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #include "getoptpp.h" #include @@ -23,175 +23,207 @@ using namespace std; namespace vlofgren { /* - * - * Class OptionsParser - * - * - */ +* +* Class OptionsParser +* +* +*/ OptionsParser::OptionsParser(const char* programDesc) : fprogramDesc(programDesc) {} OptionsParser::~OptionsParser() {} ParameterSet& OptionsParser::getParameters() { - return parameters; + return parameters; } void OptionsParser::parse(int argc, const char* argv[]) throw(runtime_error) { - argv0 = argv[0]; + argv0 = argv[0]; - if(argc == 1) return; + if(argc == 1) return; - vector v(&argv[1], &argv[argc]); + vector v(&argv[1], &argv[argc]); - ParserState state(*this, v); + ParserState state(*this, v); - for(; !state.end(); state.advance()) { + for(; !state.end(); state.advance()) { - std::list::iterator i; + std::list::iterator i; - for(i = parameters.parameters.begin(); - i != parameters.parameters.end(); i++) - { - if((*i)->receive(state)) break; - } + for(i = parameters.parameters.begin(); + i != parameters.parameters.end(); i++) + { + int n = 0; + try + { + n = (*i)->receive(state); + } + catch(Parameter::ExpectedArgument &) + { + throw Parameter::ExpectedArgument(state.get() + ": expected an argument"); + } + catch(Parameter::UnexpectedArgument &) + { + throw Parameter::UnexpectedArgument(state.get() + ": did not expect an argument"); + } + catch(Switchable::SwitchingError &) + { + throw Parameter::ParameterRejected(state.get() + ": parameter already set"); + } + catch(Parameter::ParameterRejected & pr) { + std::string what = pr.what(); + if(what.length()) + { + throw Parameter::ParameterRejected(state.get() + ": " + what); + } + throw Parameter::ParameterRejected(state.get() + " (unspecified error)"); + } - if(i == parameters.parameters.end()) { - std::string file = state.get(); - if(file == "--") { - state.advance(); - break; - } - else if(file.at(0) == '-') - throw Parameter::ParameterRejected(string("Bad parameter: ") + file); - else files.push_back(state.get()); - } - } + for (int j = 1; j < n; ++j) + { + state.advance(); + } - if(!state.end()) for(; !state.end(); state.advance()) { - files.push_back(state.get()); - } + if(n != 0) + { + break; + } + } + + if(i == parameters.parameters.end()) { + std::string file = state.get(); + if(file == "--") { + state.advance(); + break; + } + else if(file.at(0) == '-') + throw Parameter::ParameterRejected(string("Bad parameter: ") + file); + else files.push_back(state.get()); + } + } + + if(!state.end()) for(; !state.end(); state.advance()) { + files.push_back(state.get()); + } } void OptionsParser::usage() const { - cerr << "Usage: " << programName() << " arguments" << endl; + cerr << fprogramDesc << endl; + cerr << "Usage: " << programName() << " [OPTIONS]" << endl << endl; - cerr << fprogramDesc << endl << endl; + cerr << "Parameters: " << endl; - cerr << "Parameters: " << endl; + std::list::const_iterator i; + for(i = parameters.parameters.begin(); + i != parameters.parameters.end(); i++) + { + cerr.width(30); + cerr << std::left << " " + (*i)->usageLine(); - std::list::const_iterator i; - for(i = parameters.parameters.begin(); - i != parameters.parameters.end(); i++) - { - cerr.width(30); - cerr << std::left << " " + (*i)->usageLine(); - - cerr.width(40); - cerr << std::left << (*i)->description() << endl; - - } + cerr.width(40); + cerr << std::left << (*i)->description() << endl; + } } const vector& OptionsParser::getFiles() const { - return files; + return files; } const string& OptionsParser::programName() const { - return argv0; + return argv0; } /* - * Parameter set - * - * - */ +* Parameter set +* +* +*/ ParameterSet::ParameterSet(const ParameterSet& ps) { - throw new runtime_error("ParameterSet not copyable"); + throw new runtime_error("ParameterSet not copyable"); } ParameterSet::~ParameterSet() { - for(std::list::iterator i = parameters.begin(); - i != parameters.end(); i++) - { - delete *i; - } + for(std::list::iterator i = parameters.begin(); + i != parameters.end(); i++) + { + delete *i; + } } /* The typical use case for command line arguments makes linear searching completely - * acceptable here. - */ +* acceptable here. +*/ Parameter& ParameterSet::operator[](char c) const { - for(std::list::const_iterator i = parameters.begin(); i!= parameters.end(); i++) { - if((*i)->shortOption() == c) return *(*i); - } - throw out_of_range("ParameterSet["+c+string("]")); + for(std::list::const_iterator i = parameters.begin(); i!= parameters.end(); i++) { + if((*i)->shortOption() == c) return *(*i); + } + throw out_of_range("ParameterSet["+c+string("]")); } Parameter& ParameterSet::operator[](const string& param) const { - for(std::list::const_iterator i = parameters.begin(); i!= parameters.end(); i++) { - if((*i)->longOption() == param) return *(*i); - } - throw out_of_range("ParameterSet["+param+"]"); + for(std::list::const_iterator i = parameters.begin(); i!= parameters.end(); i++) { + if((*i)->longOption() == param) return *(*i); + } + throw out_of_range("ParameterSet["+param+"]"); } /* - * - * Class ParserState - * - * - */ +* +* Class ParserState +* +* +*/ ParserState::ParserState(OptionsParser &opts, vector& args) : - opts(opts), arguments(args), iterator(args.begin()) + opts(opts), arguments(args), iterator(args.begin()) { - + } const string ParserState::peek() const { - vector::const_iterator next = iterator+1; - if(next != arguments.end()) return *next; - else return ""; - + vector::const_iterator next = iterator+1; + if(next != arguments.end()) return *next; + else return ""; + } const string ParserState::get() const { - if(!end()) return *iterator; - else return ""; + if(!end()) return *iterator; + else return ""; } void ParserState::advance() { - iterator++; + iterator++; } bool ParserState::end() const { - return iterator == arguments.end(); + return iterator == arguments.end(); } /* - * - * Class Parameter - * - * - */ +* +* Class Parameter +* +* +*/ Parameter::Parameter(char shortOption, const std::string & longOption, const std::string & description) : - fshortOption(shortOption), flongOption(longOption), fdescription(description) + fshortOption(shortOption), flongOption(longOption), fdescription(description) { - + } Parameter::~Parameter() {} @@ -202,11 +234,11 @@ bool Parameter::hasShortOption() const { return fshortOption != 0x0; } char Parameter::shortOption() const { assert(hasShortOption()); return fshortOption; } /* - * - * Class Switchable - * - * - */ +* +* Class Switchable +* +* +*/ bool Switchable::isSet() const { return fset; } Switchable::~Switchable() {}; @@ -217,108 +249,88 @@ MultiSwitchable::~MultiSwitchable() {} void UniquelySwitchable::set() throw (Switchable::SwitchingError) { - if(UniquelySwitchable::isSet()) throw Switchable::SwitchingError(); - fset = true; + if(UniquelySwitchable::isSet()) throw Switchable::SwitchingError(); + fset = true; } UniquelySwitchable::~UniquelySwitchable() {} PresettableUniquelySwitchable::~PresettableUniquelySwitchable() {} bool PresettableUniquelySwitchable::isSet() const { - return UniquelySwitchable::isSet() || fpreset.isSet(); + return UniquelySwitchable::isSet() || fpreset.isSet(); } void PresettableUniquelySwitchable::set() throw (Switchable::SwitchingError) { - UniquelySwitchable::set(); + UniquelySwitchable::set(); } void PresettableUniquelySwitchable::preset() { - fpreset.set(); + fpreset.set(); } /* - * - * Class SwitchParameter - * - * - */ - - -SwitchParameter::SwitchParameter(char shortOption, const char *longOption, - const char* description) : CommonParameter(shortOption, longOption, description) {} -SwitchParameter::~SwitchParameter() {} - -void SwitchParameter::receiveSwitch() throw(Parameter::ParameterRejected) { - set(); -} - -void SwitchParameter::receiveArgument(const string &arg) throw(Parameter::ParameterRejected) { - throw UnexpectedArgument(); -} - -/* - * - * PODParameter specializations - * - * - * - */ +* +* PODParameter specializations +* +* +* +*/ template<> PODParameter::PODParameter(char shortOption, const char *longOption, - const char* description) : CommonParameter(shortOption, longOption, description) { - preset(); + const char* description) : CommonParameter(shortOption, longOption, description) { + preset(); } template<> int PODParameter::validate(const string &s) throw(Parameter::ParameterRejected) { - // This is sadly necessary for strto*-functions to operate on - // const char*. The function doesn't write to the memory, though, - // so it's quite safe. + // This is sadly necessary for strto*-functions to operate on + // const char*. The function doesn't write to the memory, though, + // so it's quite safe. - char* cstr = const_cast(s.c_str()); - if(*cstr == '\0') throw ParameterRejected("No argument given"); + char* cstr = const_cast(s.c_str()); + if(*cstr == '\0') throw ParameterRejected("No argument given"); - long l = strtol(cstr, &cstr, 10); - if(*cstr != '\0') throw ParameterRejected("Expected int"); + long l = strtol(cstr, &cstr, 10); + if(*cstr != '\0') throw ParameterRejected("Expected int"); - if(l > INT_MAX || l < INT_MIN) { - throw ParameterRejected("Expected int"); - } + if(l > INT_MAX || l < INT_MIN) { + throw ParameterRejected("Expected int"); + } - return l; + return l; } template<> long PODParameter::validate(const string &s) throw(Parameter::ParameterRejected) { - char* cstr = const_cast(s.c_str()); - if(*cstr == '\0') throw ParameterRejected("No argument given"); + char* cstr = const_cast(s.c_str()); + if(*cstr == '\0') throw ParameterRejected("No argument given"); - long l = strtol(cstr, &cstr, 10); - if(*cstr != '\0') throw ParameterRejected("Expected long"); + long l = strtol(cstr, &cstr, 10); + if(*cstr != '\0') throw ParameterRejected("Expected long"); - return l; + return l; } template<> double PODParameter::validate(const string &s) throw(Parameter::ParameterRejected) { - char* cstr = const_cast(s.c_str()); - if(*cstr == '\0') throw ParameterRejected("No argument given"); + char* cstr = const_cast(s.c_str()); + if(*cstr == '\0') throw ParameterRejected("No argument given"); - double d = strtod(cstr, &cstr); - if(*cstr != '\0') throw ParameterRejected("Expected double"); + double d = strtod(cstr, &cstr); + if(*cstr != '\0') throw ParameterRejected("Expected double"); - return d; + return d; } template<> string PODParameter::validate(const string &s) throw(Parameter::ParameterRejected) { - return s; + return s; } diff --git a/dependencies/include/getoptPlusPlus/getoptpp.h b/dependencies/include/getoptPlusPlus/getoptpp.h index 23d0aeba..b0f825cf 100644 --- a/dependencies/include/getoptPlusPlus/getoptpp.h +++ b/dependencies/include/getoptPlusPlus/getoptpp.h @@ -203,7 +203,7 @@ protected: * iterator that technically allows for more complex grammar than what is * presently used. */ - virtual bool receive(ParserState& state) throw(ParameterRejected) = 0; + virtual int receive(ParserState& state) throw(ParameterRejected) = 0; friend class OptionsParser; @@ -250,20 +250,9 @@ protected: * receiveSwitch() or receiveArgument() accordingly. * * @param state The current argument being parsed. + * @return The number of parameters taken from the input */ - virtual bool receive(ParserState& state) throw(ParameterRejected); - - /** - * Called when a parameter does not have an argument, e.g. - * either -f or --foo - */ - virtual void receiveSwitch() throw (ParameterRejected) = 0; - - /** - * Called when a parameter does have an argument, .e.g - * -fbar or --foo=bar - */ - virtual void receiveArgument(const std::string& argument) throw (ParameterRejected) = 0; + virtual int receive(ParserState& state) throw(ParameterRejected) = 0; }; /** This class (used as a mixin) defines how a parameter @@ -344,15 +333,15 @@ private: /* Parameter that does not take an argument, and throws an exception * if an argument is given */ -class SwitchParameter : public CommonParameter { +template +class SwitchParameter : public CommonParameter { public: SwitchParameter(char shortOption, const char *longOption, const char* description); virtual ~SwitchParameter(); protected: - virtual void receiveSwitch() throw (Parameter::ParameterRejected); - virtual void receiveArgument(const std::string& argument) throw (Parameter::ParameterRejected); + virtual int receive(ParserState& state) throw(Parameter::ParameterRejected); }; /** Plain-Old-Data parameter. Performs input validation. @@ -363,8 +352,8 @@ protected: * Specifically, you need to specialize validate(). */ -template -class PODParameter : public CommonParameter { +template +class PODParameter : public CommonParameter { public: PODParameter(char shortOption, const char *longOption, const char* description); @@ -383,14 +372,14 @@ public: std::string usageLine() const; protected: + virtual int receive(ParserState& state) throw(Parameter::ParameterRejected); + /** Validation function for the data type. * * @throw ParameterRejected if the argument does not conform to this data type. * @return the value corresponding to the argument. */ - virtual T validate(const std::string& s) throw (ParameterRejected); - virtual void receiveArgument(const std::string &argument) throw(ParameterRejected); - virtual void receiveSwitch() throw (Parameter::ParameterRejected); + virtual T validate(const std::string& s) throw (Parameter::ParameterRejected); T value; }; diff --git a/dependencies/include/getoptPlusPlus/parameter.include.cc b/dependencies/include/getoptPlusPlus/parameter.include.cc index 4564d5ec..a1daf516 100644 --- a/dependencies/include/getoptPlusPlus/parameter.include.cc +++ b/dependencies/include/getoptPlusPlus/parameter.include.cc @@ -53,155 +53,125 @@ template std::string CommonParameter::usageLine() const { std::stringstream strstr; - strstr.width(10); if (hasShortOption()) { - strstr << std::left<< std::string("-") + shortOption(); + strstr << "-" << shortOption() << ", "; } else { - strstr << " "; + strstr << " "; } - strstr.width(20); - strstr << std::left << "--" + longOption(); + strstr.width(20); + strstr << std::left << "--" + longOption(); - return strstr.str(); + return strstr.str(); } - +/* + * + * Class SwitchParameter + * + * + */ template -bool CommonParameter::receive(ParserState& state) throw(Parameter::ParameterRejected) { +SwitchParameter::SwitchParameter(char shortOption, const char *longOption, + const char* description) : CommonParameter(shortOption, longOption, description) {} +template +SwitchParameter::~SwitchParameter() {} + +template +int SwitchParameter::receive(ParserState& state) throw(Parameter::ParameterRejected) { const std::string arg = state.get(); - try { - if(arg.at(0) != '-') return false; + if(arg.at(0) != '-') return false; - if(arg.at(1) == '-') { /* Long form parameter */ - try { - unsigned int eq = arg.find_first_of("="); + if ((arg.at(1) == '-' && arg.substr(2) == this->longOption()) || + (this->hasShortOption() && arg.at(1) == this->shortOption() && arg.length() == 2)) + { + this->set(); + return 1; + } - if(eq == std::string::npos) { - if(arg.substr(2) != longOption()) - return false; - - this->receiveSwitch(); - } else { - if(arg.substr(2, eq-2) != longOption()) - return false; - - this->receiveArgument(arg.substr(eq+1)); - } - return true; - } catch(Parameter::ExpectedArgument &ea) { - throw ExpectedArgument("--" + longOption() + ": expected an argument"); - } catch(Parameter::UnexpectedArgument &ua) { - throw UnexpectedArgument("--" + longOption() + ": did not expect an argument"); - } catch(Switchable::SwitchingError &e) { - throw ParameterRejected("--" + longOption() + ": parameter already set"); - } catch(Parameter::ParameterRejected &pr) { - - std::string what = pr.what(); - if(what.length()) - throw Parameter::ParameterRejected("--" + longOption() + ": " + what); - throw Parameter::ParameterRejected("--" + longOption() + " (unspecified error)"); - } - } - else if (hasShortOption()) - { - try { - if(arg.at(1) == shortOption()) { - /* Matched argument on the form -f or -fsomething */ - if(arg.length() == 2) { /* -f */ - this->receiveSwitch(); - - return true; - } else { /* -fsomething */ - this->receiveArgument(arg.substr(2)); - - return true; - } - } - } catch(Parameter::ExpectedArgument &ea) { - throw ExpectedArgument(std::string("-") + shortOption() + ": expected an argument"); - } catch(Parameter::UnexpectedArgument &ua) { - throw UnexpectedArgument(std::string("-") + shortOption() + ": did not expect an argument"); - } catch(Switchable::SwitchingError &e) { - throw ParameterRejected(std::string("-") + shortOption() + ": parameter already set"); - } - } - } catch(std::out_of_range& o) { - return false; - } - - return false; + return 0; } - - /* * PODParameter stuff * */ -template -PODParameter::PODParameter(char shortOption, const char *longOption, +template +PODParameter::PODParameter(char shortOption, const char *longOption, const char* description) : CommonParameter(shortOption, longOption, description) {} -template -PODParameter::~PODParameter() {} +template +PODParameter::~PODParameter() {} -template -PODParameter::operator T() const { return getValue(); } +template +PODParameter::operator T() const { return getValue(); } -template -void PODParameter::setDefault(T value) { +template +void PODParameter::setDefault(T value) { PresettableUniquelySwitchable::preset(); this->value = value; } -template -T PODParameter::getValue() const { - if(!isSet()) { - throw runtime_error( - std::string("Attempting to retreive the argument of parameter") + longOption() + " but it hasn't been set!"); +template +T PODParameter::getValue() const { + if(!this->isSet()) { + throw std::runtime_error( + std::string("Attempting to retreive the argument of parameter") + this->longOption() + " but it hasn't been set!"); } return value; } - -template -std::string PODParameter::usageLine() const { +template +std::string PODParameter::usageLine() const { std::stringstream strstr; - strstr.width(10); - if (hasShortOption()) + if (this->hasShortOption()) { - strstr << std::left << std::string("-") + shortOption() +"arg"; + strstr << "-" << this->shortOption() << ", "; } else { - strstr << ""; + strstr << " "; } strstr.width(20); - strstr << std::left << "--" + longOption() + "=arg"; + strstr << std::left << "--" + this->longOption() + " "; return strstr.str(); } -template -void PODParameter::receiveSwitch() throw (Parameter::ParameterRejected) { - throw Parameter::ExpectedArgument(); -} +template +int PODParameter::receive(ParserState& state) throw(Parameter::ParameterRejected) { -template -void PODParameter::receiveArgument(const std::string &argument) throw(Parameter::ParameterRejected) { - set(); - value = this->validate(argument); -} + const std::string arg = state.get(); + if(arg.at(0) != '-') return false; + + if((arg.at(1) == '-' && arg.substr(2) == this->longOption()) || + (this->hasShortOption() && arg.at(1) == this->shortOption() && arg.length() == 2)) + { + // retrieve the argument + std::string arg1 = state.peek(); + if (arg1.length() == 0) + { + throw Parameter::ExpectedArgument(arg + ": expected an argument"); + return 1; + } + + this->set(); + value = this->validate(arg1); + + return 2; + } + + return 0; +} #endif diff --git a/src/hyperion-remote/CMakeLists.txt b/src/hyperion-remote/CMakeLists.txt index a6eee382..8ed36533 100644 --- a/src/hyperion-remote/CMakeLists.txt +++ b/src/hyperion-remote/CMakeLists.txt @@ -1,19 +1,22 @@ cmake_minimum_required(VERSION 2.8) project(hyperion-remote) -find_package(Qt4 REQUIRED QtCore QtNetwork) +find_package(Qt4 REQUIRED QtCore QtGui QtNetwork) # The following I do not undrstand completely... # libQtCore.so uses some hardcoded library path inside which are incorrect after copying the file RPi file system # Therefor, an extra path is needed on which to find the required libraries LINK_DIRECTORIES(${LINK_DIRECTORIES} ${CMAKE_FIND_ROOT_PATH}/lib/arm-linux-gnueabihf) -include_directories(${QT_INCLUDE_DIR}) +include_directories(${QT_INCLUDES}) -set(hyperion-remote_HEADERS) +set(hyperion-remote_HEADERS + specialoptions.h + connection.h) set(hyperion-remote_SOURCES - hyperion-remote.cpp) + hyperion-remote.cpp + connection.cpp) qt4_wrap_cpp(HYPERION_REMOTE_MOC_SOURCES ${hyperion-remote_HEADERS}) @@ -25,6 +28,7 @@ add_executable(hyperion-remote qt4_use_modules(hyperion-remote Core + Gui Network) target_link_libraries(hyperion-remote diff --git a/src/hyperion-remote/connection.cpp b/src/hyperion-remote/connection.cpp new file mode 100644 index 00000000..0b2d6970 --- /dev/null +++ b/src/hyperion-remote/connection.cpp @@ -0,0 +1,71 @@ +#include "connection.h" + +Connection::Connection(const std::string &address, bool printJson) +{ +} + +Connection::~Connection() +{ +} + +bool Connection::setColor(QColor color, int priority, int duration) +{ + std::cout << "Set color to " << color.red() << " " << color.green() << " " << color.blue() << std::endl; + return false; +} + +bool Connection::setImage(QImage image, int priority, int duration) +{ + std::cout << "Set image has size: " << image.width() << "x" << image.height() << std::endl; + return false; +} + +bool Connection::listPriorities() +{ + std::cout << "List priority channels" << std::endl; + return false; +} + +bool Connection::clear(int priority) +{ + std::cout << "Clear priority channel " << priority << std::endl; + return false; +} + +bool Connection::clearAll() +{ + std::cout << "Clear all priority channels" << std::endl; + return false; +} + +bool Connection::setThreshold(double red, double green, double blue) +{ + return false; +} + +bool Connection::setGamma(double red, double green, double blue) +{ + return false; +} + +bool Connection::setBlacklevel(double red, double green, double blue) +{ + return false; +} + +bool Connection::setWhitelevel(double red, double green, double blue) +{ + return false; +} + +bool Connection::sendMessage(const Json::Value &message) +{ + if (_printJson) + { + std::cout << "Command:" << std::endl; + std::cout << message << std::endl; + } + + return true; +} + diff --git a/src/hyperion-remote/connection.h b/src/hyperion-remote/connection.h new file mode 100644 index 00000000..5035e630 --- /dev/null +++ b/src/hyperion-remote/connection.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include +#include + +#include + +class Connection +{ +public: + Connection(const std::string & address, bool printJson); + ~Connection(); + + bool setColor(QColor color, int priority, int duration); + bool setImage(QImage image, int priority, int duration); + bool listPriorities(); + bool clear(int priority); + bool clearAll(); + bool setThreshold(double red, double green, double blue); + bool setGamma(double red, double green, double blue); + bool setBlacklevel(double red, double green, double blue); + bool setWhitelevel(double red, double green, double blue); + +private: + bool sendMessage(const Json::Value & message); + +private: + bool _printJson; +}; diff --git a/src/hyperion-remote/hyperion-remote.cpp b/src/hyperion-remote/hyperion-remote.cpp index 2311ffef..df6e57ba 100644 --- a/src/hyperion-remote/hyperion-remote.cpp +++ b/src/hyperion-remote/hyperion-remote.cpp @@ -1,10 +1,25 @@ -#include +#include + #include #include +#include "specialoptions.h" +#include "connection.h" + + using namespace vlofgren; +int count(std::initializer_list values) +{ + int count = 0; + for (auto& value : values) { + if (value) + count++; + } + return count; +} + int main(int argc, const char * argv[]) { // some settings @@ -13,37 +28,96 @@ int main(int argc, const char * argv[]) OptionsParser optionParser("Simple application to send a command to hyperion using the Json interface"); ParameterSet & parameters = optionParser.getParameters(); - StringParameter & argAddress = parameters.add('a', "address" , QString("Set the address of the hyperion server [default: %1]").arg(defaultServerAddress).toAscii().constData()); - IntParameter & argPriority = parameters.add ('p', "priority" , QString("Use to the provided priority channel (the lower the number, the higher the priority) [default: %1]").arg(defaultPriority).toAscii().constData()); - IntParameter & argDuration = parameters.add ('d', "duration" , "Specify how long the leds should be switched on in millseconds. Without this parameter, the leds will be switched on without end time."); - StringParameter & argColor = parameters.add('c', "color" , "Set all leds to a constant color (either RRGGBB hex value or a color name)"); - StringParameter & argImage = parameters.add('i', "image" , "Set the leds to the colors according to the given image file"); - SwitchParameter & argList = parameters.add('l', "list" , "List all priority channels which are in use"); - SwitchParameter & argClear = parameters.add('x', "clear" , "Clear data for the priority channel provided by the -p option"); - SwitchParameter & argClearAll = parameters.add(0x0, "clear-all" , "Clear data for all priority channels"); - DoubleParameter & argGamma = parameters.add('g', "gamma" , "Set the gamma of the leds (requires 3 values)"); - DoubleParameter & argThreshold = parameters.add('t', "threshold" , "Set the threshold of the leds (requires 3 values between 0.0 and 1.0)"); - DoubleParameter & argBlacklevel = parameters.add('b', "blacklevel", "Set the blacklevel of the leds (requires 3 values which are normally between 0.0 and 1.0)"); - DoubleParameter & argWhitelevel = parameters.add('w', "whitelevel", "Set the whitelevel of the leds (requires 3 values which are normally between 0.0 and 1.0)"); - SwitchParameter & argPrint = parameters.add(0x0, "print" , "Print the json input and output messages on stdout"); - SwitchParameter & argHelp = parameters.add('h', "help" , "Show this help message and exit"); + StringParameter & argAddress = parameters.add ('a', "address" , QString("Set the address of the hyperion server [default: %1]").arg(defaultServerAddress).toAscii().constData()); + IntParameter & argPriority = parameters.add ('p', "priority" , QString("Use to the provided priority channel (the lower the number, the higher the priority) [default: %1]").arg(defaultPriority).toAscii().constData()); + IntParameter & argDuration = parameters.add ('d', "duration" , "Specify how long the leds should be switched on in millseconds [default: infinity]"); + ColorParameter & argColor = parameters.add ('c', "color" , "Set all leds to a constant color (either RRGGBB hex value or a color name)"); + ImageParameter & argImage = parameters.add ('i', "image" , "Set the leds to the colors according to the given image file"); + SwitchParameter<> & argList = parameters.add >('l', "list" , "List all priority channels which are in use"); + SwitchParameter<> & argClear = parameters.add >('x', "clear" , "Clear data for the priority channel provided by the -p option"); + SwitchParameter<> & argClearAll = parameters.add >(0x0, "clear-all" , "Clear data for all priority channels"); + TransformParameter & argGamma = parameters.add('g', "gamma" , "Set the gamma of the leds (requires 3 values)"); + TransformParameter & argThreshold = parameters.add('t', "threshold" , "Set the threshold of the leds (requires 3 space seperated values between 0.0 and 1.0)"); + TransformParameter & argBlacklevel = parameters.add('b', "blacklevel", "Set the blacklevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)"); + TransformParameter & argWhitelevel = parameters.add('w', "whitelevel", "Set the whitelevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)"); + SwitchParameter<> & argPrint = parameters.add >(0x0, "print" , "Print the json input and output messages on stdout"); + SwitchParameter<> & argHelp = parameters.add >('h', "help" , "Show this help message and exit"); + + argAddress.setDefault(defaultServerAddress.toStdString()); + argPriority.setDefault(defaultPriority); + argDuration.setDefault(-1); + try { optionParser.parse(argc, argv); } catch (const std::runtime_error & e) { - qWarning() << e.what(); - optionParser.usage(); + std::cerr << e.what() << std::endl; return 1; } + // check if we need to display the usage if (argHelp.isSet()) { optionParser.usage(); return 0; } + // check if a color transform is set + bool colorTransform = argThreshold.isSet() || argGamma.isSet() || argBlacklevel.isSet() || argWhitelevel.isSet(); + + // check if exactly one command was given + int commandCount = count({argColor.isSet(), argImage.isSet(), argList.isSet(), argClear.isSet(), argClearAll.isSet(), colorTransform}); + if (commandCount != 1) + { + if (commandCount == 0) + { + std::cerr << "No command found. Provide one of the following options:" << std::endl; + } + else + { + std::cerr << "Multiple commands found. Provide one of the following options:" << std::endl; + } + std::cerr << " " << argColor.usageLine() << std::endl; + std::cerr << " " << argImage.usageLine() << std::endl; + std::cerr << " " << argList.usageLine() << std::endl; + std::cerr << " " << argClear.usageLine() << std::endl; + std::cerr << " " << argClearAll.usageLine() << std::endl; + std::cerr << "or one or more of the color transformations:" << std::endl; + std::cerr << " " << argThreshold.usageLine() << std::endl; + std::cerr << " " << argGamma.usageLine() << std::endl; + std::cerr << " " << argBlacklevel.usageLine() << std::endl; + std::cerr << " " << argWhitelevel.usageLine() << std::endl; + return 1; + } + + Connection connection(argAddress.getValue(), argPrint.isSet()); + + // now execute the given command + if (argColor.isSet()) + { + connection.setColor(argColor.getValue(), argPriority.getValue(), argDuration.getValue()); + } + else if (argImage.isSet()) + { + connection.setImage(argImage.getValue(), argPriority.getValue(), argDuration.getValue()); + } + else if (argList.isSet()) + { + connection.listPriorities(); + } + else if (argClear.isSet()) + { + connection.clear(argPriority.getValue()); + } + else if (argClearAll.isSet()) + { + connection.clearAll(); + } + else if (colorTransform) + { + } return 0; } diff --git a/src/hyperion-remote/specialoptions.h b/src/hyperion-remote/specialoptions.h new file mode 100644 index 00000000..96f4b304 --- /dev/null +++ b/src/hyperion-remote/specialoptions.h @@ -0,0 +1,102 @@ +#pragma once + +#include +#include + +#include + +struct ColorTransform +{ + double valueRed; + double valueGreen; + double valueBlue; +}; + +typedef vlofgren::PODParameter ColorParameter; +typedef vlofgren::PODParameter ImageParameter; +typedef vlofgren::PODParameter TransformParameter; + +namespace vlofgren { + template<> + QColor ColorParameter::validate(const std::string& s) throw (Parameter::ParameterRejected) + { + // Check if we can create the color by name + QColor color(s.c_str()); + if (color.isValid()) + { + return color; + } + + // check if we can create the color by hex RRGGBB value + if (s.length() == 6 && isxdigit(s[0]) && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]) && isxdigit(s[5])) + { + bool ok = true; + int rgb[3]; + for (int i = 0; i < 3 && ok; ++i) + { + QString colorComponent(s.substr(2*i, 2).c_str()); + rgb[i] = colorComponent.toInt(&ok, 16); + } + + // check if all components parsed succesfully + if (ok) + { + color.setRgb(rgb[0], rgb[1], rgb[2]); + return color; + } + } + + std::stringstream errorMessage; + errorMessage << "Invalid color. A color is specified by a six lettered RRGGBB hex value or one of the following names:"; + foreach (const QString & colorname, QColor::colorNames()) { + errorMessage << "\n " << colorname.toStdString(); + } + throw Parameter::ParameterRejected(errorMessage.str()); + + return color; + } + + template<> + QImage ImageParameter::validate(const std::string& s) throw (Parameter::ParameterRejected) + { + QImage image(s.c_str()); + + if (image.isNull()) + { + std::stringstream errorMessage; + errorMessage << "File " << s << " could not be opened as an image"; + throw Parameter::ParameterRejected(errorMessage.str()); + } + + return image; + } + + template<> + ColorTransform TransformParameter::validate(const std::string& s) throw (Parameter::ParameterRejected) + { + ColorTransform transform; + + // s should be split in 3 parts + // seperators are either a ',' or a space + QStringList components = QString(s.c_str()).split(" ", QString::SkipEmptyParts); + + if (components.size() == 3) + { + bool ok1, ok2, ok3; + transform.valueRed = components[0].toDouble(&ok1); + transform.valueGreen = components[1].toDouble(&ok2); + transform.valueBlue = components[2].toDouble(&ok3); + + if (ok1 && ok2 && ok3) + { + return transform; + } + } + + std::stringstream errorMessage; + errorMessage << "Argument " << s << " can not be parsed to 3 double values"; + throw Parameter::ParameterRejected(errorMessage.str()); + + return transform; + } +}