get rid of argp dependency
This commit is contained in:
@@ -74,18 +74,6 @@ check_function_exists(ppoll HAVE_PPOLL)
|
|||||||
check_include_file(linux/serial.h HAVE_LINUX_SERIAL -DHAVE_LINUX_SERIAL=1)
|
check_include_file(linux/serial.h HAVE_LINUX_SERIAL -DHAVE_LINUX_SERIAL=1)
|
||||||
check_include_file(dev/usb/uftdiio.h HAVE_FREEBSD_UFTDI -DHAVE_FREEBSD_UFTDI=1)
|
check_include_file(dev/usb/uftdiio.h HAVE_FREEBSD_UFTDI -DHAVE_FREEBSD_UFTDI=1)
|
||||||
|
|
||||||
check_function_exists(argp_parse HAVE_ARGP_H)
|
|
||||||
if(NOT HAVE_ARGP_H)
|
|
||||||
if(NOT ARGP_HINTS)
|
|
||||||
set(ARGP_HINTS ~/argp-standalone/src)
|
|
||||||
endif(NOT ARGP_HINTS)
|
|
||||||
find_library(LIB_ARGP NAMES argp argp-standalone HINTS ARGP_HINTS)
|
|
||||||
if (NOT LIB_ARGP)
|
|
||||||
message(FATAL_ERROR "argp library not available")
|
|
||||||
endif(NOT LIB_ARGP)
|
|
||||||
set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES} ${LIB_ARGP}")
|
|
||||||
endif(NOT HAVE_ARGP_H)
|
|
||||||
|
|
||||||
option(coverage "enable code coverage tracking." OFF)
|
option(coverage "enable code coverage tracking." OFF)
|
||||||
if(NOT coverage STREQUAL OFF)
|
if(NOT coverage STREQUAL OFF)
|
||||||
add_definitions(-g -O0 --coverage -Wall)
|
add_definitions(-g -O0 --coverage -Wall)
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ Building ebusd from the source requires the following packages and/or features:
|
|||||||
* g++ with C++11 support (>=4.8.1)
|
* g++ with C++11 support (>=4.8.1)
|
||||||
* make
|
* make
|
||||||
* kernel with pselect or ppoll support
|
* kernel with pselect or ppoll support
|
||||||
* glibc with argp support or argp-standalone
|
* glibc with getopt_long support
|
||||||
* libmosquitto-dev for MQTT support
|
* libmosquitto-dev for MQTT support
|
||||||
* libssl-dev for SSL support
|
* libssl-dev for SSL support
|
||||||
|
|
||||||
|
|||||||
@@ -40,9 +40,6 @@
|
|||||||
/* Defined if syslog.h is available. */
|
/* Defined if syslog.h is available. */
|
||||||
#cmakedefine HAVE_SYSLOG_H
|
#cmakedefine HAVE_SYSLOG_H
|
||||||
|
|
||||||
/* Defined if argp.h is available. */
|
|
||||||
#cmakedefine HAVE_ARGP_H
|
|
||||||
|
|
||||||
/* The name of package. */
|
/* The name of package. */
|
||||||
#cmakedefine PACKAGE "${PACKAGE_NAME}"
|
#cmakedefine PACKAGE "${PACKAGE_NAME}"
|
||||||
|
|
||||||
|
|||||||
@@ -48,14 +48,6 @@ if test "x$with_contrib" != "xno"; then
|
|||||||
fi
|
fi
|
||||||
AC_ARG_WITH(ebusfeed, AS_HELP_STRING([--with-ebusfeed], [enable inclusion of ebusfeed tool]), [with_ebusfeed=yes], [])
|
AC_ARG_WITH(ebusfeed, AS_HELP_STRING([--with-ebusfeed], [enable inclusion of ebusfeed tool]), [with_ebusfeed=yes], [])
|
||||||
AM_CONDITIONAL([WITH_EBUSFEED], [test "x$with_ebusfeed" == "xyes"])
|
AM_CONDITIONAL([WITH_EBUSFEED], [test "x$with_ebusfeed" == "xyes"])
|
||||||
AC_ARG_WITH(argp-lib, AS_HELP_STRING([--with-argp-lib=PATH], [path to argp libraries]), [LDFLAGS+="-L$with_argp_lib"])
|
|
||||||
AC_ARG_WITH(argp-include, AS_HELP_STRING([--with-argp-include=PATH], [path to argp includes]), [CXXFLAGS+="-I$with_argp_include"])
|
|
||||||
AC_CHECK_FUNC([argp_parse], [have_argp=yes], AC_CHECK_LIB([argp], [argp_parse], [have_argp=yes; LIBS="-largp $LIBS"], [have_argp=no]))
|
|
||||||
if test "x$have_argp" = "xyes"; then
|
|
||||||
AC_CHECK_HEADER([argp.h], AC_DEFINE([HAVE_ARGP_H], [1], [Defined if argp.h is available.]), AC_MSG_ERROR([argp.h not found]))
|
|
||||||
else
|
|
||||||
AC_MSG_ERROR([argp library not found, specify argp-standalone location in --with-argp-lib= and --with-argp-include= options.])
|
|
||||||
fi
|
|
||||||
AC_ARG_WITH(mqtt, AS_HELP_STRING([--without-mqtt], [disable support for MQTT handling]), [], [with_mqtt=yes])
|
AC_ARG_WITH(mqtt, AS_HELP_STRING([--without-mqtt], [disable support for MQTT handling]), [], [with_mqtt=yes])
|
||||||
if test "x$with_mqtt" != "xno"; then
|
if test "x$with_mqtt" != "xno"; then
|
||||||
AC_CHECK_LIB([mosquitto], [mosquitto_lib_init],
|
AC_CHECK_LIB([mosquitto], [mosquitto_lib_init],
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ url="https://github.com/john30/ebusd"
|
|||||||
# Upstream only supports these archs.
|
# Upstream only supports these archs.
|
||||||
arch="x86 x86_64 aarch64 armhf armv7"
|
arch="x86 x86_64 aarch64 armhf armv7"
|
||||||
license="GPL-3.0-only"
|
license="GPL-3.0-only"
|
||||||
makedepends="argp-standalone cmake mosquitto-dev openssl-dev"
|
makedepends="cmake mosquitto-dev openssl-dev"
|
||||||
source="$pkgname-$pkgver.tar.gz::https://github.com/john30/${pkgname}/archive/refs/tags/${pkgver}.tar.gz"
|
source="$pkgname-$pkgver.tar.gz::https://github.com/john30/${pkgname}/archive/refs/tags/${pkgver}.tar.gz"
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ include_directories(../lib/ebus)
|
|||||||
include_directories(../lib/utils)
|
include_directories(../lib/utils)
|
||||||
|
|
||||||
add_executable(ebusd ${ebusd_SOURCES})
|
add_executable(ebusd ${ebusd_SOURCES})
|
||||||
target_link_libraries(ebusd utils ebus pthread rt ${LIB_ARGP} ${ebusd_LIBS})
|
target_link_libraries(ebusd utils ebus pthread rt ${ebusd_LIBS})
|
||||||
|
|
||||||
install(TARGETS ebusd EXPORT ebusd DESTINATION usr/bin)
|
install(TARGETS ebusd EXPORT ebusd DESTINATION usr/bin)
|
||||||
|
|
||||||
|
|||||||
@@ -30,11 +30,11 @@
|
|||||||
|
|
||||||
namespace ebusd {
|
namespace ebusd {
|
||||||
|
|
||||||
/** the final @a argp_child structure. */
|
/** the final @a argParseChildOpt structure. */
|
||||||
static const struct argp_child g_last_argp_child = {nullptr, 0, nullptr, 0};
|
static const argParseChildOpt g_last_arg_child = {nullptr, nullptr};
|
||||||
|
|
||||||
/** the list of @a argp_child structures. */
|
/** the list of @a argParseChildOpt structures. */
|
||||||
static struct argp_child g_argp_children[
|
static argParseChildOpt g_arg_children[
|
||||||
1
|
1
|
||||||
#ifdef HAVE_MQTT
|
#ifdef HAVE_MQTT
|
||||||
+1
|
+1
|
||||||
@@ -44,17 +44,17 @@ static struct argp_child g_argp_children[
|
|||||||
#endif
|
#endif
|
||||||
];
|
];
|
||||||
|
|
||||||
const struct argp_child* datahandler_getargs() {
|
const argParseChildOpt* datahandler_getargs() {
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
#ifdef HAVE_MQTT
|
#ifdef HAVE_MQTT
|
||||||
g_argp_children[count++] = *mqtthandler_getargs();
|
g_arg_children[count++] = *mqtthandler_getargs();
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_KNX
|
#ifdef HAVE_KNX
|
||||||
g_argp_children[count++] = *knxhandler_getargs();
|
g_arg_children[count++] = *knxhandler_getargs();
|
||||||
#endif
|
#endif
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
g_argp_children[count] = g_last_argp_child;
|
g_arg_children[count] = g_last_arg_child;
|
||||||
return g_argp_children;
|
return g_arg_children;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,12 +19,12 @@
|
|||||||
#ifndef EBUSD_DATAHANDLER_H_
|
#ifndef EBUSD_DATAHANDLER_H_
|
||||||
#define EBUSD_DATAHANDLER_H_
|
#define EBUSD_DATAHANDLER_H_
|
||||||
|
|
||||||
#include <argp.h>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "ebusd/bushandler.h"
|
#include "ebusd/bushandler.h"
|
||||||
#include "lib/ebus/message.h"
|
#include "lib/ebus/message.h"
|
||||||
|
#include "lib/utils/arg.h"
|
||||||
|
|
||||||
namespace ebusd {
|
namespace ebusd {
|
||||||
|
|
||||||
@@ -49,10 +49,10 @@ enum scanStatus_t {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function for getting the argp definition for all known @a DataHandler instances.
|
* Helper function for getting the arg definition for all known @a DataHandler instances.
|
||||||
* @return a pointer to the argp_child structure, or nullptr.
|
* @return a pointer to the child argument options, or nullptr.
|
||||||
*/
|
*/
|
||||||
const struct argp_child* datahandler_getargs();
|
const argParseChildOpt* datahandler_getargs();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registration function that is called once during initialization.
|
* Registration function that is called once during initialization.
|
||||||
|
|||||||
+14
-17
@@ -52,9 +52,9 @@ using std::dec;
|
|||||||
#define O_VAR (O_INT-1)
|
#define O_VAR (O_INT-1)
|
||||||
|
|
||||||
/** the definition of the KNX arguments. */
|
/** the definition of the KNX arguments. */
|
||||||
static const struct argp_option g_knx_argp_options[] = {
|
static const argDef g_knx_argDefs[] = {
|
||||||
{nullptr, 0, nullptr, 0, "KNX options:", 1 },
|
{nullptr, 0, nullptr, 0, "KNX options:", 1 },
|
||||||
{"knxurl", O_URL, "URL", OPTION_ARG_OPTIONAL, "URL to open (i.e. \"[multicast][@interface]\" for KNXnet/IP"
|
{"knxurl", O_URL, "URL", af_optional, "URL to open (i.e. \"[multicast][@interface]\" for KNXnet/IP"
|
||||||
#ifdef HAVE_KNXD
|
#ifdef HAVE_KNXD
|
||||||
" or \"ip:host[:port]\" / \"local:/socketpath\" for knxd"
|
" or \"ip:host[:port]\" / \"local:/socketpath\" for knxd"
|
||||||
#endif
|
#endif
|
||||||
@@ -79,11 +79,11 @@ static vector<string>* g_integrationVars = nullptr; //!< the integration settin
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The KNX argument parsing function.
|
* The KNX argument parsing function.
|
||||||
* @param key the key from @a g_knx_argp_options.
|
* @param key the key from @a g_knx_arg_options.
|
||||||
* @param arg the option argument, or nullptr.
|
* @param arg the option argument, or nullptr.
|
||||||
* @param state the parsing state.
|
* @param state the parsing state.
|
||||||
*/
|
*/
|
||||||
static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
|
static int knx_parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
|
||||||
result_t result;
|
result_t result;
|
||||||
unsigned int value;
|
unsigned int value;
|
||||||
switch (key) {
|
switch (key) {
|
||||||
@@ -94,12 +94,12 @@ static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
|
|
||||||
case O_AGR: // --knxrage=5
|
case O_AGR: // --knxrage=5
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid knxrage value");
|
argParseError(parseOpt, "invalid knxrage value");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
value = parseInt(arg, 10, 0, 99999999, &result);
|
value = parseInt(arg, 10, 0, 99999999, &result);
|
||||||
if (result != RESULT_OK) {
|
if (result != RESULT_OK) {
|
||||||
argp_error(state, "invalid knxrage");
|
argParseError(parseOpt, "invalid knxrage");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_maxReadAge = value;
|
g_maxReadAge = value;
|
||||||
@@ -107,12 +107,12 @@ static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
|
|
||||||
case O_AGW: // --knxwage=5
|
case O_AGW: // --knxwage=5
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid knxwage value");
|
argParseError(parseOpt, "invalid knxwage value");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
value = parseInt(arg, 10, 0, 99999999, &result);
|
value = parseInt(arg, 10, 0, 99999999, &result);
|
||||||
if (result != RESULT_OK) {
|
if (result != RESULT_OK) {
|
||||||
argp_error(state, "invalid knxwage");
|
argParseError(parseOpt, "invalid knxwage");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_maxWriteAge = value;
|
g_maxWriteAge = value;
|
||||||
@@ -120,7 +120,7 @@ static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
|
|
||||||
case O_INT: // --knxint=/etc/ebusd/knx.cfg
|
case O_INT: // --knxint=/etc/ebusd/knx.cfg
|
||||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||||
argp_error(state, "invalid knxint file");
|
argParseError(parseOpt, "invalid knxint file");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_integrationFile = arg;
|
g_integrationFile = arg;
|
||||||
@@ -129,7 +129,7 @@ static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_VAR: // --knxvar=NAME=VALUE[,NAME=VALUE]*
|
case O_VAR: // --knxvar=NAME=VALUE[,NAME=VALUE]*
|
||||||
{
|
{
|
||||||
if (arg == nullptr || arg[0] == 0 || !strchr(arg, '=')) {
|
if (arg == nullptr || arg[0] == 0 || !strchr(arg, '=')) {
|
||||||
argp_error(state, "invalid knxvar");
|
argParseError(parseOpt, "invalid knxvar");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (!g_integrationVars) {
|
if (!g_integrationVars) {
|
||||||
@@ -143,18 +143,15 @@ static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return ARGP_ERR_UNKNOWN;
|
return ESRCH;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct argp g_knx_argp = { g_knx_argp_options, knx_parse_opt, nullptr, nullptr, nullptr, nullptr,
|
static const argParseChildOpt g_knx_arg_child = { g_knx_argDefs, knx_parse_opt };
|
||||||
nullptr };
|
|
||||||
static const struct argp_child g_knx_argp_child = {&g_knx_argp, 0, "", 1};
|
|
||||||
|
|
||||||
|
const argParseChildOpt* knxhandler_getargs() {
|
||||||
const struct argp_child* knxhandler_getargs() {
|
return &g_knx_arg_child;
|
||||||
return &g_knx_argp_child;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool knxhandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages,
|
bool knxhandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages,
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "lib/ebus/message.h"
|
#include "lib/ebus/message.h"
|
||||||
#include "lib/ebus/stringhelper.h"
|
#include "lib/ebus/stringhelper.h"
|
||||||
#include "lib/knx/knx.h"
|
#include "lib/knx/knx.h"
|
||||||
|
#include "lib/utils/arg.h"
|
||||||
|
|
||||||
namespace ebusd {
|
namespace ebusd {
|
||||||
|
|
||||||
@@ -41,10 +42,10 @@ using std::string;
|
|||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function for getting the argp definition for KNX.
|
* Helper function for getting the arg definition for KNX.
|
||||||
* @return a pointer to the argp_child structure.
|
* @return a pointer to the child argument options, or nullptr.
|
||||||
*/
|
*/
|
||||||
const struct argp_child* knxhandler_getargs();
|
const argParseChildOpt* knxhandler_getargs();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registration function that is called once during initialization.
|
* Registration function that is called once during initialization.
|
||||||
|
|||||||
+81
-76
@@ -23,7 +23,6 @@
|
|||||||
#include "ebusd/main.h"
|
#include "ebusd/main.h"
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <argp.h>
|
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -32,17 +31,11 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include "ebusd/mainloop.h"
|
#include "ebusd/mainloop.h"
|
||||||
#include "ebusd/network.h"
|
#include "ebusd/network.h"
|
||||||
|
#include "lib/utils/arg.h"
|
||||||
#include "lib/utils/log.h"
|
#include "lib/utils/log.h"
|
||||||
#include "lib/utils/httpclient.h"
|
#include "lib/utils/httpclient.h"
|
||||||
#include "ebusd/scan.h"
|
#include "ebusd/scan.h"
|
||||||
|
|
||||||
|
|
||||||
/** the version string of the program. */
|
|
||||||
const char *argp_program_version = "" PACKAGE_STRING "." REVISION "";
|
|
||||||
|
|
||||||
/** the report bugs to address of the program. */
|
|
||||||
const char *argp_program_bug_address = "" PACKAGE_BUGREPORT "";
|
|
||||||
|
|
||||||
namespace ebusd {
|
namespace ebusd {
|
||||||
|
|
||||||
using std::dec;
|
using std::dec;
|
||||||
@@ -146,10 +139,6 @@ static string s_configPath = CONFIG_PATH;
|
|||||||
/** whether scanConfig or configPath were set by arguments. */
|
/** whether scanConfig or configPath were set by arguments. */
|
||||||
static bool s_scanConfigOrPathSet = false;
|
static bool s_scanConfigOrPathSet = false;
|
||||||
|
|
||||||
/** the documentation of the program. */
|
|
||||||
static const char argpdoc[] =
|
|
||||||
"A daemon for communication with eBUS heating systems.";
|
|
||||||
|
|
||||||
#define O_INISND -2
|
#define O_INISND -2
|
||||||
#define O_DEVLAT (O_INISND-1)
|
#define O_DEVLAT (O_INISND-1)
|
||||||
#define O_SCNRET (O_DEVLAT-1)
|
#define O_SCNRET (O_DEVLAT-1)
|
||||||
@@ -187,7 +176,7 @@ static const char argpdoc[] =
|
|||||||
#define O_DMPFLU (O_DMPSIZ-1)
|
#define O_DMPFLU (O_DMPSIZ-1)
|
||||||
|
|
||||||
/** the definition of the known program arguments. */
|
/** the definition of the known program arguments. */
|
||||||
static const struct argp_option argpoptions[] = {
|
static const argDef argDefs[] = {
|
||||||
{nullptr, 0, nullptr, 0, "Device options:", 1 },
|
{nullptr, 0, nullptr, 0, "Device options:", 1 },
|
||||||
{"device", 'd', "DEV", 0, "Use DEV as eBUS device ("
|
{"device", 'd', "DEV", 0, "Use DEV as eBUS device ("
|
||||||
"prefix \"ens:\" for enhanced high speed device or "
|
"prefix \"ens:\" for enhanced high speed device or "
|
||||||
@@ -203,7 +192,7 @@ static const struct argp_option argpoptions[] = {
|
|||||||
{nullptr, 0, nullptr, 0, "Message configuration options:", 2 },
|
{nullptr, 0, nullptr, 0, "Message configuration options:", 2 },
|
||||||
{"configpath", 'c', "PATH", 0, "Read CSV config files from PATH (local folder or HTTPS URL) ["
|
{"configpath", 'c', "PATH", 0, "Read CSV config files from PATH (local folder or HTTPS URL) ["
|
||||||
CONFIG_PATH "]", 0 },
|
CONFIG_PATH "]", 0 },
|
||||||
{"scanconfig", 's', "ADDR", OPTION_ARG_OPTIONAL, "Pick CSV config files matching initial scan ADDR: "
|
{"scanconfig", 's', "ADDR", af_optional, "Pick CSV config files matching initial scan ADDR: "
|
||||||
"empty for broadcast ident message (default when configpath is not given), "
|
"empty for broadcast ident message (default when configpath is not given), "
|
||||||
"\"none\" for no initial scan message, "
|
"\"none\" for no initial scan message, "
|
||||||
"\"full\" for full scan, "
|
"\"full\" for full scan, "
|
||||||
@@ -215,11 +204,11 @@ static const struct argp_option argpoptions[] = {
|
|||||||
{"configlang", O_CFGLNG, "LANG", 0,
|
{"configlang", O_CFGLNG, "LANG", 0,
|
||||||
"Prefer LANG in multilingual configuration files [system default language]", 0 },
|
"Prefer LANG in multilingual configuration files [system default language]", 0 },
|
||||||
{"checkconfig", O_CHKCFG, nullptr, 0, "Check config files, then stop", 0 },
|
{"checkconfig", O_CHKCFG, nullptr, 0, "Check config files, then stop", 0 },
|
||||||
{"dumpconfig", O_DMPCFG, "FORMAT", OPTION_ARG_OPTIONAL,
|
{"dumpconfig", O_DMPCFG, "FORMAT", af_optional,
|
||||||
"Check and dump config files in FORMAT (\"json\" or \"csv\"), then stop", 0 },
|
"Check and dump config files in FORMAT (\"json\" or \"csv\"), then stop", 0 },
|
||||||
{"dumpconfigto", O_DMPCTO, "FILE", 0, "Dump config files to FILE", 0 },
|
{"dumpconfigto", O_DMPCTO, "FILE", 0, "Dump config files to FILE", 0 },
|
||||||
{"pollinterval", O_POLINT, "SEC", 0, "Poll for data every SEC seconds (0=disable) [5]", 0 },
|
{"pollinterval", O_POLINT, "SEC", 0, "Poll for data every SEC seconds (0=disable) [5]", 0 },
|
||||||
{"inject", 'i', "stop", OPTION_ARG_OPTIONAL, "Inject remaining arguments as already seen messages (e.g. "
|
{"inject", 'i', "stop", af_optional, "Inject remaining arguments as already seen messages (e.g. "
|
||||||
"\"FF08070400/0AB5454850303003277201\"), optionally stop afterwards", 0 },
|
"\"FF08070400/0AB5454850303003277201\"), optionally stop afterwards", 0 },
|
||||||
#ifdef HAVE_SSL
|
#ifdef HAVE_SSL
|
||||||
{"cafile", O_CAFILE, "FILE", 0, "Use CA FILE for checking certificates (uses defaults,"
|
{"cafile", O_CAFILE, "FILE", 0, "Use CA FILE for checking certificates (uses defaults,"
|
||||||
@@ -261,7 +250,7 @@ static const struct argp_option argpoptions[] = {
|
|||||||
" [notice]", 0 },
|
" [notice]", 0 },
|
||||||
|
|
||||||
{nullptr, 0, nullptr, 0, "Raw logging options:", 6 },
|
{nullptr, 0, nullptr, 0, "Raw logging options:", 6 },
|
||||||
{"lograwdata", O_RAW, "bytes", OPTION_ARG_OPTIONAL,
|
{"lograwdata", O_RAW, "bytes", af_optional,
|
||||||
"Log messages or all received/sent bytes on the bus", 0 },
|
"Log messages or all received/sent bytes on the bus", 0 },
|
||||||
{"lograwdatafile", O_RAWFIL, "FILE", 0, "Write raw log to FILE [" PACKAGE_LOGFILE "]", 0 },
|
{"lograwdatafile", O_RAWFIL, "FILE", 0, "Write raw log to FILE [" PACKAGE_LOGFILE "]", 0 },
|
||||||
{"lograwdatasize", O_RAWSIZ, "SIZE", 0, "Make raw log file no larger than SIZE kB [100]", 0 },
|
{"lograwdatasize", O_RAWSIZ, "SIZE", 0, "Make raw log file no larger than SIZE kB [100]", 0 },
|
||||||
@@ -277,12 +266,12 @@ static const struct argp_option argpoptions[] = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The program argument parsing function.
|
* The program argument parsing function.
|
||||||
* @param key the key from @a argpoptions.
|
* @param key the key from @a argDefs.
|
||||||
* @param arg the option argument, or nullptr.
|
* @param arg the option argument, or nullptr.
|
||||||
* @param state the parsing state.
|
* @param parseOpt the parse options.
|
||||||
*/
|
*/
|
||||||
error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
static int parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
|
||||||
struct options *opt = (struct options*)state->input;
|
struct options *opt = (struct options*)parseOpt->userArg;
|
||||||
result_t result = RESULT_OK;
|
result_t result = RESULT_OK;
|
||||||
unsigned int value;
|
unsigned int value;
|
||||||
|
|
||||||
@@ -290,7 +279,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
// Device options:
|
// Device options:
|
||||||
case 'd': // --device=/dev/ttyUSB0
|
case 'd': // --device=/dev/ttyUSB0
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid device");
|
argParseError(parseOpt, "invalid device");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->device = arg;
|
opt->device = arg;
|
||||||
@@ -307,7 +296,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_DEVLAT: // --latency=10
|
case O_DEVLAT: // --latency=10
|
||||||
value = parseInt(arg, 10, 0, 200000, &result); // backwards compatible (micros)
|
value = parseInt(arg, 10, 0, 200000, &result); // backwards compatible (micros)
|
||||||
if (result != RESULT_OK || (value <= 1000 && value > 200)) { // backwards compatible (micros)
|
if (result != RESULT_OK || (value <= 1000 && value > 200)) { // backwards compatible (micros)
|
||||||
argp_error(state, "invalid latency");
|
argParseError(parseOpt, "invalid latency");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->extraLatency = value > 1000 ? value/1000 : value; // backwards compatible (micros)
|
opt->extraLatency = value > 1000 ? value/1000 : value; // backwards compatible (micros)
|
||||||
@@ -316,7 +305,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
// Message configuration options:
|
// Message configuration options:
|
||||||
case 'c': // --configpath=https://cfg.ebusd.eu/
|
case 'c': // --configpath=https://cfg.ebusd.eu/
|
||||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||||
argp_error(state, "invalid configpath");
|
argParseError(parseOpt, "invalid configpath");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
s_configPath = arg;
|
s_configPath = arg;
|
||||||
@@ -336,7 +325,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
} else {
|
} else {
|
||||||
auto address = (symbol_t)parseInt(arg, 16, 0x00, 0xff, &result);
|
auto address = (symbol_t)parseInt(arg, 16, 0x00, 0xff, &result);
|
||||||
if (result != RESULT_OK || !isValidAddress(address)) {
|
if (result != RESULT_OK || !isValidAddress(address)) {
|
||||||
argp_error(state, "invalid initial scan address");
|
argParseError(parseOpt, "invalid initial scan address");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (isMaster(address)) {
|
if (isMaster(address)) {
|
||||||
@@ -353,7 +342,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_SCNRET: // --scanretries=10
|
case O_SCNRET: // --scanretries=10
|
||||||
value = parseInt(arg, 10, 0, 100, &result);
|
value = parseInt(arg, 10, 0, 100, &result);
|
||||||
if (result != RESULT_OK) {
|
if (result != RESULT_OK) {
|
||||||
argp_error(state, "invalid scanretries");
|
argParseError(parseOpt, "invalid scanretries");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->scanRetries = value;
|
opt->scanRetries = value;
|
||||||
@@ -371,14 +360,14 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
} else if (strcmp("json", arg) == 0) {
|
} else if (strcmp("json", arg) == 0) {
|
||||||
opt->dumpConfig = OF_DEFINITION | OF_NAMES | OF_UNITS | OF_COMMENTS | OF_VALUENAME | OF_ALL_ATTRS | OF_JSON;
|
opt->dumpConfig = OF_DEFINITION | OF_NAMES | OF_UNITS | OF_COMMENTS | OF_VALUENAME | OF_ALL_ATTRS | OF_JSON;
|
||||||
} else {
|
} else {
|
||||||
argp_error(state, "invalid dumpconfig");
|
argParseError(parseOpt, "invalid dumpconfig");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->checkConfig = true;
|
opt->checkConfig = true;
|
||||||
break;
|
break;
|
||||||
case O_DMPCTO: // --dumpconfigto=FILE
|
case O_DMPCTO: // --dumpconfigto=FILE
|
||||||
if (!arg || arg[0] == 0) {
|
if (!arg || arg[0] == 0) {
|
||||||
argp_error(state, "invalid dumpconfigto");
|
argParseError(parseOpt, "invalid dumpconfigto");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->dumpConfigTo = arg;
|
opt->dumpConfigTo = arg;
|
||||||
@@ -386,7 +375,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_POLINT: // --pollinterval=5
|
case O_POLINT: // --pollinterval=5
|
||||||
value = parseInt(arg, 10, 0, 3600, &result);
|
value = parseInt(arg, 10, 0, 3600, &result);
|
||||||
if (result != RESULT_OK) {
|
if (result != RESULT_OK) {
|
||||||
argp_error(state, "invalid pollinterval");
|
argParseError(parseOpt, "invalid pollinterval");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->pollInterval = value;
|
opt->pollInterval = value;
|
||||||
@@ -407,7 +396,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
{
|
{
|
||||||
auto address = (symbol_t)parseInt(arg, 16, 0, 0xff, &result);
|
auto address = (symbol_t)parseInt(arg, 16, 0, 0xff, &result);
|
||||||
if (result != RESULT_OK || !isMaster(address)) {
|
if (result != RESULT_OK || !isMaster(address)) {
|
||||||
argp_error(state, "invalid address");
|
argParseError(parseOpt, "invalid address");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->address = address;
|
opt->address = address;
|
||||||
@@ -419,7 +408,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_ACQTIM: // --acquiretimeout=10
|
case O_ACQTIM: // --acquiretimeout=10
|
||||||
value = parseInt(arg, 10, 1, 100000, &result); // backwards compatible (micros)
|
value = parseInt(arg, 10, 1, 100000, &result); // backwards compatible (micros)
|
||||||
if (result != RESULT_OK || (value <= 1000 && value > 100)) { // backwards compatible (micros)
|
if (result != RESULT_OK || (value <= 1000 && value > 100)) { // backwards compatible (micros)
|
||||||
argp_error(state, "invalid acquiretimeout");
|
argParseError(parseOpt, "invalid acquiretimeout");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->acquireTimeout = value > 1000 ? value/1000 : value; // backwards compatible (micros)
|
opt->acquireTimeout = value > 1000 ? value/1000 : value; // backwards compatible (micros)
|
||||||
@@ -427,7 +416,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_ACQRET: // --acquireretries=3
|
case O_ACQRET: // --acquireretries=3
|
||||||
value = parseInt(arg, 10, 0, 10, &result);
|
value = parseInt(arg, 10, 0, 10, &result);
|
||||||
if (result != RESULT_OK) {
|
if (result != RESULT_OK) {
|
||||||
argp_error(state, "invalid acquireretries");
|
argParseError(parseOpt, "invalid acquireretries");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->acquireRetries = value;
|
opt->acquireRetries = value;
|
||||||
@@ -435,7 +424,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_SNDRET: // --sendretries=2
|
case O_SNDRET: // --sendretries=2
|
||||||
value = parseInt(arg, 10, 0, 10, &result);
|
value = parseInt(arg, 10, 0, 10, &result);
|
||||||
if (result != RESULT_OK) {
|
if (result != RESULT_OK) {
|
||||||
argp_error(state, "invalid sendretries");
|
argParseError(parseOpt, "invalid sendretries");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->sendRetries = value;
|
opt->sendRetries = value;
|
||||||
@@ -443,7 +432,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_RCVTIM: // --receivetimeout=25
|
case O_RCVTIM: // --receivetimeout=25
|
||||||
value = parseInt(arg, 10, 1, 100000, &result); // backwards compatible (micros)
|
value = parseInt(arg, 10, 1, 100000, &result); // backwards compatible (micros)
|
||||||
if (result != RESULT_OK || (value <= 1000 && value > 100)) { // backwards compatible (micros)
|
if (result != RESULT_OK || (value <= 1000 && value > 100)) { // backwards compatible (micros)
|
||||||
argp_error(state, "invalid receivetimeout");
|
argParseError(parseOpt, "invalid receivetimeout");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->receiveTimeout = value > 1000 ? value/1000 : value; // backwards compatible (micros)
|
opt->receiveTimeout = value > 1000 ? value/1000 : value; // backwards compatible (micros)
|
||||||
@@ -451,7 +440,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_MASCNT: // --numbermasters=0
|
case O_MASCNT: // --numbermasters=0
|
||||||
value = parseInt(arg, 10, 0, 25, &result);
|
value = parseInt(arg, 10, 0, 25, &result);
|
||||||
if (result != RESULT_OK) {
|
if (result != RESULT_OK) {
|
||||||
argp_error(state, "invalid numbermasters");
|
argParseError(parseOpt, "invalid numbermasters");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->masterCount = value;
|
opt->masterCount = value;
|
||||||
@@ -463,14 +452,14 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
// Daemon options:
|
// Daemon options:
|
||||||
case O_ACLDEF: // --accesslevel=*
|
case O_ACLDEF: // --accesslevel=*
|
||||||
if (arg == nullptr) {
|
if (arg == nullptr) {
|
||||||
argp_error(state, "invalid accesslevel");
|
argParseError(parseOpt, "invalid accesslevel");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->accessLevel = arg;
|
opt->accessLevel = arg;
|
||||||
break;
|
break;
|
||||||
case O_ACLFIL: // --aclfile=/etc/ebusd/acl
|
case O_ACLFIL: // --aclfile=/etc/ebusd/acl
|
||||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||||
argp_error(state, "invalid aclfile");
|
argParseError(parseOpt, "invalid aclfile");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->aclFile = arg;
|
opt->aclFile = arg;
|
||||||
@@ -486,7 +475,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
break;
|
break;
|
||||||
case O_PIDFIL: // --pidfile=/var/run/ebusd.pid
|
case O_PIDFIL: // --pidfile=/var/run/ebusd.pid
|
||||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||||
argp_error(state, "invalid pidfile");
|
argParseError(parseOpt, "invalid pidfile");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->pidFile = arg;
|
opt->pidFile = arg;
|
||||||
@@ -494,7 +483,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case 'p': // --port=8888
|
case 'p': // --port=8888
|
||||||
value = parseInt(arg, 10, 1, 65535, &result);
|
value = parseInt(arg, 10, 1, 65535, &result);
|
||||||
if (result != RESULT_OK) {
|
if (result != RESULT_OK) {
|
||||||
argp_error(state, "invalid port");
|
argParseError(parseOpt, "invalid port");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->port = (uint16_t)value;
|
opt->port = (uint16_t)value;
|
||||||
@@ -505,21 +494,21 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_HTTPPT: // --httpport=0
|
case O_HTTPPT: // --httpport=0
|
||||||
value = parseInt(arg, 10, 1, 65535, &result);
|
value = parseInt(arg, 10, 1, 65535, &result);
|
||||||
if (result != RESULT_OK) {
|
if (result != RESULT_OK) {
|
||||||
argp_error(state, "invalid httpport");
|
argParseError(parseOpt, "invalid httpport");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->httpPort = (uint16_t)value;
|
opt->httpPort = (uint16_t)value;
|
||||||
break;
|
break;
|
||||||
case O_HTMLPA: // --htmlpath=/var/ebusd/html
|
case O_HTMLPA: // --htmlpath=/var/ebusd/html
|
||||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||||
argp_error(state, "invalid htmlpath");
|
argParseError(parseOpt, "invalid htmlpath");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->htmlPath = arg;
|
opt->htmlPath = arg;
|
||||||
break;
|
break;
|
||||||
case O_UPDCHK: // --updatecheck=on
|
case O_UPDCHK: // --updatecheck=on
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid updatecheck");
|
argParseError(parseOpt, "invalid updatecheck");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (strcmp("on", arg) == 0) {
|
if (strcmp("on", arg) == 0) {
|
||||||
@@ -527,7 +516,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
} else if (strcmp("off", arg) == 0) {
|
} else if (strcmp("off", arg) == 0) {
|
||||||
opt->updateCheck = false;
|
opt->updateCheck = false;
|
||||||
} else {
|
} else {
|
||||||
argp_error(state, "invalid updatecheck");
|
argParseError(parseOpt, "invalid updatecheck");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -535,7 +524,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
// Log options:
|
// Log options:
|
||||||
case 'l': // --logfile=/var/log/ebusd.log
|
case 'l': // --logfile=/var/log/ebusd.log
|
||||||
if (arg == nullptr || strcmp("/", arg) == 0) {
|
if (arg == nullptr || strcmp("/", arg) == 0) {
|
||||||
argp_error(state, "invalid logfile");
|
argParseError(parseOpt, "invalid logfile");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->logFile = arg;
|
opt->logFile = arg;
|
||||||
@@ -546,23 +535,23 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
if (pos == nullptr) {
|
if (pos == nullptr) {
|
||||||
pos = strchr(arg, ' ');
|
pos = strchr(arg, ' ');
|
||||||
if (pos == nullptr) {
|
if (pos == nullptr) {
|
||||||
argp_error(state, "invalid log");
|
argParseError(parseOpt, "invalid log");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*pos = 0;
|
*pos = 0;
|
||||||
int facilities = parseLogFacilities(arg);
|
int facilities = parseLogFacilities(arg);
|
||||||
if (facilities == -1) {
|
if (facilities == -1) {
|
||||||
argp_error(state, "invalid log: areas");
|
argParseError(parseOpt, "invalid log: areas");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
LogLevel level = parseLogLevel(pos + 1);
|
LogLevel level = parseLogLevel(pos + 1);
|
||||||
if (level == ll_COUNT) {
|
if (level == ll_COUNT) {
|
||||||
argp_error(state, "invalid log: level");
|
argParseError(parseOpt, "invalid log: level");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (opt->logAreas != -1 || opt->logLevel != ll_COUNT) {
|
if (opt->logAreas != -1 || opt->logLevel != ll_COUNT) {
|
||||||
argp_error(state, "invalid log (combined with logareas or loglevel)");
|
argParseError(parseOpt, "invalid log (combined with logareas or loglevel)");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
setFacilitiesLogLevel(facilities, level);
|
setFacilitiesLogLevel(facilities, level);
|
||||||
@@ -573,11 +562,11 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
{
|
{
|
||||||
int facilities = parseLogFacilities(arg);
|
int facilities = parseLogFacilities(arg);
|
||||||
if (facilities == -1) {
|
if (facilities == -1) {
|
||||||
argp_error(state, "invalid logareas");
|
argParseError(parseOpt, "invalid logareas");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (opt->multiLog) {
|
if (opt->multiLog) {
|
||||||
argp_error(state, "invalid logareas (combined with log)");
|
argParseError(parseOpt, "invalid logareas (combined with log)");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->logAreas = facilities;
|
opt->logAreas = facilities;
|
||||||
@@ -587,11 +576,11 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
{
|
{
|
||||||
LogLevel logLevel = parseLogLevel(arg);
|
LogLevel logLevel = parseLogLevel(arg);
|
||||||
if (logLevel == ll_COUNT) {
|
if (logLevel == ll_COUNT) {
|
||||||
argp_error(state, "invalid loglevel");
|
argParseError(parseOpt, "invalid loglevel");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (opt->multiLog) {
|
if (opt->multiLog) {
|
||||||
argp_error(state, "invalid loglevel (combined with log)");
|
argParseError(parseOpt, "invalid loglevel (combined with log)");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->logLevel = logLevel;
|
opt->logLevel = logLevel;
|
||||||
@@ -604,7 +593,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
break;
|
break;
|
||||||
case O_RAWFIL: // --lograwdatafile=/var/log/ebusd.log
|
case O_RAWFIL: // --lograwdatafile=/var/log/ebusd.log
|
||||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||||
argp_error(state, "invalid lograwdatafile");
|
argParseError(parseOpt, "invalid lograwdatafile");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->logRawFile = arg;
|
opt->logRawFile = arg;
|
||||||
@@ -612,7 +601,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_RAWSIZ: // --lograwdatasize=100
|
case O_RAWSIZ: // --lograwdatasize=100
|
||||||
value = parseInt(arg, 10, 1, 1000000, &result);
|
value = parseInt(arg, 10, 1, 1000000, &result);
|
||||||
if (result != RESULT_OK) {
|
if (result != RESULT_OK) {
|
||||||
argp_error(state, "invalid lograwdatasize");
|
argParseError(parseOpt, "invalid lograwdatasize");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->logRawSize = value;
|
opt->logRawSize = value;
|
||||||
@@ -625,7 +614,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
break;
|
break;
|
||||||
case O_DMPFIL: // --dumpfile=/tmp/ebusd_dump.bin
|
case O_DMPFIL: // --dumpfile=/tmp/ebusd_dump.bin
|
||||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||||
argp_error(state, "invalid dumpfile");
|
argParseError(parseOpt, "invalid dumpfile");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->dumpFile = arg;
|
opt->dumpFile = arg;
|
||||||
@@ -633,7 +622,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_DMPSIZ: // --dumpsize=100
|
case O_DMPSIZ: // --dumpsize=100
|
||||||
value = parseInt(arg, 10, 1, 1000000, &result);
|
value = parseInt(arg, 10, 1, 1000000, &result);
|
||||||
if (result != RESULT_OK) {
|
if (result != RESULT_OK) {
|
||||||
argp_error(state, "invalid dumpsize");
|
argParseError(parseOpt, "invalid dumpsize");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->dumpSize = value;
|
opt->dumpSize = value;
|
||||||
@@ -642,33 +631,27 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
opt->dumpFlush = true;
|
opt->dumpFlush = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ARGP_KEY_ARG:
|
|
||||||
if (opt->injectMessages || (opt->checkConfig && opt->scanConfig)) {
|
|
||||||
return ARGP_ERR_UNKNOWN;
|
|
||||||
}
|
|
||||||
argp_error(state, "invalid arguments starting with \"%s\"", arg);
|
|
||||||
return EINVAL;
|
|
||||||
default:
|
default:
|
||||||
return ARGP_ERR_UNKNOWN;
|
return ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// check for invalid arg combinations
|
// check for invalid arg combinations
|
||||||
if (opt->readOnly && (opt->answer || opt->generateSyn || opt->initialSend
|
if (opt->readOnly && (opt->answer || opt->generateSyn || opt->initialSend
|
||||||
|| (opt->scanConfig && opt->initialScan != ESC))) {
|
|| (opt->scanConfig && opt->initialScan != ESC))) {
|
||||||
argp_error(state, "cannot combine readonly with answer/generatesyn/initsend/scanconfig");
|
argParseError(parseOpt, "cannot combine readonly with answer/generatesyn/initsend/scanconfig");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (opt->scanConfig && opt->pollInterval == 0) {
|
if (opt->scanConfig && opt->pollInterval == 0) {
|
||||||
argp_error(state, "scanconfig without polling may lead to invalid files included for certain products!");
|
argParseError(parseOpt, "scanconfig without polling may lead to invalid files included for certain products!");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (opt->injectMessages && (opt->checkConfig || opt->dumpConfig)) {
|
if (opt->injectMessages && (opt->checkConfig || opt->dumpConfig)) {
|
||||||
argp_error(state, "cannot combine inject with checkconfig/dumpconfig");
|
argParseError(parseOpt, "cannot combine inject with checkconfig/dumpconfig");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void shutdown(bool error = false);
|
void shutdown(bool error = false);
|
||||||
|
|
||||||
void daemonize() {
|
void daemonize() {
|
||||||
@@ -823,8 +806,17 @@ void signalHandler(int sig) {
|
|||||||
* @return the exit code.
|
* @return the exit code.
|
||||||
*/
|
*/
|
||||||
int main(int argc, char* argv[], char* envp[]) {
|
int main(int argc, char* argv[], char* envp[]) {
|
||||||
struct argp aargp = { argpoptions, parse_opt, nullptr, argpdoc, datahandler_getargs(), nullptr, nullptr };
|
const argParseOpt parseOpt = {
|
||||||
setenv("ARGP_HELP_FMT", "no-dup-args-note", 0);
|
argDefs,
|
||||||
|
parse_opt,
|
||||||
|
0,
|
||||||
|
"" PACKAGE_NAME,
|
||||||
|
"[INJECT...]",
|
||||||
|
"A daemon for communication with eBUS heating systems.",
|
||||||
|
"Report bugs to " PACKAGE_BUGREPORT " .",
|
||||||
|
datahandler_getargs(),
|
||||||
|
&s_opt
|
||||||
|
};
|
||||||
|
|
||||||
char envname[32] = "--"; // needs to cover at least max length of any option name plus "--"
|
char envname[32] = "--"; // needs to cover at least max length of any option name plus "--"
|
||||||
char* envopt = envname+2;
|
char* envopt = envname+2;
|
||||||
@@ -849,7 +841,7 @@ int main(int argc, char* argv[], char* envp[]) {
|
|||||||
// ignore those defined in Dockerfile, EBUSD_OPTS, those with final args, and interactive ones
|
// ignore those defined in Dockerfile, EBUSD_OPTS, those with final args, and interactive ones
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
char* envargv[] = {envname, pos+1};
|
char* envargv[] = {argv[0], envname, pos+1};
|
||||||
int cnt = pos[1] ? 2 : 1;
|
int cnt = pos[1] ? 2 : 1;
|
||||||
if (pos[1] && strlen(*env) < sizeof(envname)-3
|
if (pos[1] && strlen(*env) < sizeof(envname)-3
|
||||||
&& (strcmp(envopt, "scanconfig") == 0 || strcmp(envopt, "lograwdata") == 0)) {
|
&& (strcmp(envopt, "scanconfig") == 0 || strcmp(envopt, "lograwdata") == 0)) {
|
||||||
@@ -858,8 +850,7 @@ int main(int argc, char* argv[], char* envp[]) {
|
|||||||
strcat(envopt, pos);
|
strcat(envopt, pos);
|
||||||
}
|
}
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
s_opt.injectMessages = true; // for skipping unknown values via ARGP_ERR_UNKNOWN
|
int err = argParse(&parseOpt, 1+cnt, envargv, &idx);
|
||||||
error_t err = argp_parse(&aargp, cnt, envargv, ARGP_PARSE_ARGV0|ARGP_SILENT|ARGP_IN_ORDER, &idx, &s_opt);
|
|
||||||
if (err != 0 && idx == -1) { // ignore args for non-arg boolean options
|
if (err != 0 && idx == -1) { // ignore args for non-arg boolean options
|
||||||
if (err == ESRCH) { // special value to abort immediately
|
if (err == ESRCH) { // special value to abort immediately
|
||||||
logWrite(lf_main, ll_error, "invalid argument in env: %s", *env); // force logging on exit
|
logWrite(lf_main, ll_error, "invalid argument in env: %s", *env); // force logging on exit
|
||||||
@@ -867,13 +858,27 @@ int main(int argc, char* argv[], char* envp[]) {
|
|||||||
}
|
}
|
||||||
logWrite(lf_main, ll_error, "invalid/unknown argument in env (ignored): %s", *env); // force logging
|
logWrite(lf_main, ll_error, "invalid/unknown argument in env (ignored): %s", *env); // force logging
|
||||||
}
|
}
|
||||||
s_opt.injectMessages = false; // restore (was not parsed from cmdline args yet)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int arg_index = -1;
|
int arg_index = -1;
|
||||||
if (argp_parse(&aargp, argc, argv, ARGP_IN_ORDER, &arg_index, &s_opt) != 0) {
|
switch (argParse(&parseOpt, argc, argv, &arg_index)) {
|
||||||
logWrite(lf_main, ll_error, "invalid arguments"); // force logging on exit
|
case 0: // OK
|
||||||
return EINVAL;
|
break;
|
||||||
|
case '?': // help printed
|
||||||
|
return 0;
|
||||||
|
case 'V':
|
||||||
|
printf("" PACKAGE_STRING "." REVISION "\n");
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
logWrite(lf_main, ll_error, "invalid arguments"); // force logging on exit
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg_index >= 0) {
|
||||||
|
if (!s_opt.injectMessages && !(s_opt.checkConfig && s_opt.scanConfig)) {
|
||||||
|
fprintf(stderr, "invalid arguments starting with \"%s\"", argv[arg_index]);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_opt.logAreas != -1 || s_opt.logLevel != ll_COUNT) {
|
if (s_opt.logAreas != -1 || s_opt.logLevel != ll_COUNT) {
|
||||||
|
|||||||
+28
-28
@@ -56,7 +56,7 @@ using std::dec;
|
|||||||
#define O_VERB (O_INSE+1)
|
#define O_VERB (O_INSE+1)
|
||||||
|
|
||||||
/** the definition of the MQTT arguments. */
|
/** the definition of the MQTT arguments. */
|
||||||
static const struct argp_option g_mqtt_argp_options[] = {
|
static const argDef g_mqtt_argDefs[] = {
|
||||||
{nullptr, 0, nullptr, 0, "MQTT options:", 1 },
|
{nullptr, 0, nullptr, 0, "MQTT options:", 1 },
|
||||||
{"mqtthost", O_HOST, "HOST", 0, "Connect to MQTT broker on HOST [localhost]", 0 },
|
{"mqtthost", O_HOST, "HOST", 0, "Connect to MQTT broker on HOST [localhost]", 0 },
|
||||||
{"mqttport", O_PORT, "PORT", 0, "Connect to MQTT broker on PORT (usually 1883), 0 to disable [0]", 0 },
|
{"mqttport", O_PORT, "PORT", 0, "Connect to MQTT broker on PORT (usually 1883), 0 to disable [0]", 0 },
|
||||||
@@ -72,7 +72,7 @@ static const struct argp_option g_mqtt_argp_options[] = {
|
|||||||
{"mqttqos", O_PQOS, "QOS", 0, "Set the QoS value for all topics (0-2) [0]", 0 },
|
{"mqttqos", O_PQOS, "QOS", 0, "Set the QoS value for all topics (0-2) [0]", 0 },
|
||||||
{"mqttint", O_INTF, "FILE", 0, "Read MQTT integration settings from FILE (no default)", 0 },
|
{"mqttint", O_INTF, "FILE", 0, "Read MQTT integration settings from FILE (no default)", 0 },
|
||||||
{"mqttvar", O_IVAR, "NAME=VALUE[,...]", 0, "Add variable(s) to the read MQTT integration settings", 0 },
|
{"mqttvar", O_IVAR, "NAME=VALUE[,...]", 0, "Add variable(s) to the read MQTT integration settings", 0 },
|
||||||
{"mqttjson", O_JSON, "short", OPTION_ARG_OPTIONAL,
|
{"mqttjson", O_JSON, "short", af_optional,
|
||||||
"Publish in JSON format instead of strings, optionally in short (value directly below field key)", 0 },
|
"Publish in JSON format instead of strings, optionally in short (value directly below field key)", 0 },
|
||||||
{"mqttverbose", O_VERB, nullptr, 0, "Publish all available attributes", 0 },
|
{"mqttverbose", O_VERB, nullptr, 0, "Publish all available attributes", 0 },
|
||||||
#if (LIBMOSQUITTO_VERSION_NUMBER >= 1003001)
|
#if (LIBMOSQUITTO_VERSION_NUMBER >= 1003001)
|
||||||
@@ -144,17 +144,17 @@ void splitFields(const string& str, vector<string>* row);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The MQTT argument parsing function.
|
* The MQTT argument parsing function.
|
||||||
* @param key the key from @a g_mqtt_argp_options.
|
* @param key the key from @a g_mqtt_argDefs.
|
||||||
* @param arg the option argument, or nullptr.
|
* @param arg the option argument, or nullptr.
|
||||||
* @param state the parsing state.
|
* @param state the parsing state.
|
||||||
*/
|
*/
|
||||||
static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
static int mqtt_parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
|
||||||
result_t result = RESULT_OK;
|
result_t result = RESULT_OK;
|
||||||
unsigned int value;
|
unsigned int value;
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case O_HOST: // --mqtthost=localhost
|
case O_HOST: // --mqtthost=localhost
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid mqtthost");
|
argParseError(parseOpt, "invalid mqtthost");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_host = arg;
|
g_host = arg;
|
||||||
@@ -163,7 +163,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_PORT: // --mqttport=1883
|
case O_PORT: // --mqttport=1883
|
||||||
value = parseInt(arg, 10, 1, 65535, &result);
|
value = parseInt(arg, 10, 1, 65535, &result);
|
||||||
if (result != RESULT_OK) {
|
if (result != RESULT_OK) {
|
||||||
argp_error(state, "invalid mqttport");
|
argParseError(parseOpt, "invalid mqttport");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_port = (uint16_t)value;
|
g_port = (uint16_t)value;
|
||||||
@@ -171,7 +171,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
|
|
||||||
case O_CLID: // --mqttclientid=clientid
|
case O_CLID: // --mqttclientid=clientid
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid mqttclientid");
|
argParseError(parseOpt, "invalid mqttclientid");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_clientId = arg;
|
g_clientId = arg;
|
||||||
@@ -179,7 +179,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
|
|
||||||
case O_USER: // --mqttuser=username
|
case O_USER: // --mqttuser=username
|
||||||
if (arg == nullptr) {
|
if (arg == nullptr) {
|
||||||
argp_error(state, "invalid mqttuser");
|
argParseError(parseOpt, "invalid mqttuser");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_username = arg;
|
g_username = arg;
|
||||||
@@ -187,7 +187,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
|
|
||||||
case O_PASS: // --mqttpass=password
|
case O_PASS: // --mqttpass=password
|
||||||
if (arg == nullptr) {
|
if (arg == nullptr) {
|
||||||
argp_error(state, "invalid mqttpass");
|
argParseError(parseOpt, "invalid mqttpass");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_password = replaceSecret(arg);
|
g_password = replaceSecret(arg);
|
||||||
@@ -196,21 +196,21 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_TOPI: // --mqtttopic=ebusd
|
case O_TOPI: // --mqtttopic=ebusd
|
||||||
{
|
{
|
||||||
if (arg == nullptr || arg[0] == 0 || arg[0] == '/' || strchr(arg, '+') || arg[strlen(arg)-1] == '/') {
|
if (arg == nullptr || arg[0] == 0 || arg[0] == '/' || strchr(arg, '+') || arg[strlen(arg)-1] == '/') {
|
||||||
argp_error(state, "invalid mqtttopic");
|
argParseError(parseOpt, "invalid mqtttopic");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
char *pos = strchr(arg, '#');
|
char *pos = strchr(arg, '#');
|
||||||
if (pos && (pos == arg || pos[1])) { // allow # only at very last position (to indicate not using any default)
|
if (pos && (pos == arg || pos[1])) { // allow # only at very last position (to indicate not using any default)
|
||||||
argp_error(state, "invalid mqtttopic");
|
argParseError(parseOpt, "invalid mqtttopic");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (g_topic) {
|
if (g_topic) {
|
||||||
argp_error(state, "duplicate mqtttopic");
|
argParseError(parseOpt, "duplicate mqtttopic");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
StringReplacer replacer;
|
StringReplacer replacer;
|
||||||
if (!replacer.parse(arg, true)) {
|
if (!replacer.parse(arg, true)) {
|
||||||
argp_error(state, "malformed mqtttopic");
|
argParseError(parseOpt, "malformed mqtttopic");
|
||||||
return ESRCH; // abort in any case due to the above potentially being destructive
|
return ESRCH; // abort in any case due to the above potentially being destructive
|
||||||
}
|
}
|
||||||
g_topic = arg;
|
g_topic = arg;
|
||||||
@@ -219,7 +219,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
|
|
||||||
case O_GTOP: // --mqttglobal=global/
|
case O_GTOP: // --mqttglobal=global/
|
||||||
if (arg == nullptr || strchr(arg, '+') || strchr(arg, '#')) {
|
if (arg == nullptr || strchr(arg, '+') || strchr(arg, '#')) {
|
||||||
argp_error(state, "invalid mqttglobal");
|
argParseError(parseOpt, "invalid mqttglobal");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_globalTopic = arg;
|
g_globalTopic = arg;
|
||||||
@@ -232,7 +232,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case O_PQOS: // --mqttqos=0
|
case O_PQOS: // --mqttqos=0
|
||||||
value = parseInt(arg, 10, 0, 2, &result);
|
value = parseInt(arg, 10, 0, 2, &result);
|
||||||
if (result != RESULT_OK) {
|
if (result != RESULT_OK) {
|
||||||
argp_error(state, "invalid mqttqos value");
|
argParseError(parseOpt, "invalid mqttqos value");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_qos = static_cast<signed>(value);
|
g_qos = static_cast<signed>(value);
|
||||||
@@ -240,7 +240,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
|
|
||||||
case O_INTF: // --mqttint=/etc/ebusd/mqttint.cfg
|
case O_INTF: // --mqttint=/etc/ebusd/mqttint.cfg
|
||||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||||
argp_error(state, "invalid mqttint file");
|
argParseError(parseOpt, "invalid mqttint file");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_integrationFile = arg;
|
g_integrationFile = arg;
|
||||||
@@ -248,7 +248,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
|
|
||||||
case O_IVAR: // --mqttvar=NAME=VALUE[,NAME=VALUE]*
|
case O_IVAR: // --mqttvar=NAME=VALUE[,NAME=VALUE]*
|
||||||
if (arg == nullptr || arg[0] == 0 || !strchr(arg, '=')) {
|
if (arg == nullptr || arg[0] == 0 || !strchr(arg, '=')) {
|
||||||
argp_error(state, "invalid mqttvar");
|
argParseError(parseOpt, "invalid mqttvar");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (!g_integrationVars) {
|
if (!g_integrationVars) {
|
||||||
@@ -277,7 +277,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
#if (LIBMOSQUITTO_VERSION_NUMBER >= 1004001)
|
#if (LIBMOSQUITTO_VERSION_NUMBER >= 1004001)
|
||||||
case O_VERS: // --mqttversion=3.1.1
|
case O_VERS: // --mqttversion=3.1.1
|
||||||
if (arg == nullptr || arg[0] == 0 || (strcmp(arg, "3.1") != 0 && strcmp(arg, "3.1.1") != 0)) {
|
if (arg == nullptr || arg[0] == 0 || (strcmp(arg, "3.1") != 0 && strcmp(arg, "3.1.1") != 0)) {
|
||||||
argp_error(state, "invalid mqttversion");
|
argParseError(parseOpt, "invalid mqttversion");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_version = strcmp(arg, "3.1.1") == 0 ? MQTT_PROTOCOL_V311 : MQTT_PROTOCOL_V31;
|
g_version = strcmp(arg, "3.1.1") == 0 ? MQTT_PROTOCOL_V311 : MQTT_PROTOCOL_V31;
|
||||||
@@ -295,7 +295,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
#if (LIBMOSQUITTO_MAJOR >= 1)
|
#if (LIBMOSQUITTO_MAJOR >= 1)
|
||||||
case O_CAFI: // --mqttca=file or --mqttca=dir/
|
case O_CAFI: // --mqttca=file or --mqttca=dir/
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid mqttca");
|
argParseError(parseOpt, "invalid mqttca");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (arg[strlen(arg)-1] == '/') {
|
if (arg[strlen(arg)-1] == '/') {
|
||||||
@@ -309,7 +309,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
|
|
||||||
case O_CERT: // --mqttcert=CERTFILE
|
case O_CERT: // --mqttcert=CERTFILE
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid mqttcert");
|
argParseError(parseOpt, "invalid mqttcert");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_certfile = arg;
|
g_certfile = arg;
|
||||||
@@ -317,7 +317,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
|
|
||||||
case O_KEYF: // --mqttkey=KEYFILE
|
case O_KEYF: // --mqttkey=KEYFILE
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid mqttkey");
|
argParseError(parseOpt, "invalid mqttkey");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_keyfile = arg;
|
g_keyfile = arg;
|
||||||
@@ -325,7 +325,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
|
|
||||||
case O_KEPA: // --mqttkeypass=PASSWORD
|
case O_KEPA: // --mqttkeypass=PASSWORD
|
||||||
if (arg == nullptr) {
|
if (arg == nullptr) {
|
||||||
argp_error(state, "invalid mqttkeypass");
|
argParseError(parseOpt, "invalid mqttkeypass");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
g_keypass = replaceSecret(arg);
|
g_keypass = replaceSecret(arg);
|
||||||
@@ -336,18 +336,18 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return ARGP_ERR_UNKNOWN;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct argp g_mqtt_argp = { g_mqtt_argp_options, mqtt_parse_opt, nullptr, nullptr, nullptr, nullptr,
|
static const argParseChildOpt g_mqtt_arg_child = {
|
||||||
nullptr };
|
g_mqtt_argDefs, mqtt_parse_opt
|
||||||
static const struct argp_child g_mqtt_argp_child = {&g_mqtt_argp, 0, "", 1};
|
};
|
||||||
|
|
||||||
|
|
||||||
const struct argp_child* mqtthandler_getargs() {
|
const argParseChildOpt* mqtthandler_getargs() {
|
||||||
return &g_mqtt_argp_child;
|
return &g_mqtt_arg_child;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check(int code, const char* method) {
|
bool check(int code, const char* method) {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "ebusd/bushandler.h"
|
#include "ebusd/bushandler.h"
|
||||||
#include "lib/ebus/message.h"
|
#include "lib/ebus/message.h"
|
||||||
#include "lib/ebus/stringhelper.h"
|
#include "lib/ebus/stringhelper.h"
|
||||||
|
#include "lib/utils/arg.h"
|
||||||
|
|
||||||
namespace ebusd {
|
namespace ebusd {
|
||||||
|
|
||||||
@@ -42,10 +43,10 @@ using std::string;
|
|||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function for getting the argp definition for MQTT.
|
* Helper function for getting the arg definition for MQTT.
|
||||||
* @return a pointer to the argp_child structure.
|
* @return a pointer to the child argument options, or nullptr.
|
||||||
*/
|
*/
|
||||||
const struct argp_child* mqtthandler_getargs();
|
const argParseChildOpt* mqtthandler_getargs();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registration function that is called once during initialization.
|
* Registration function that is called once during initialization.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
add_definitions(-Wconversion)
|
add_definitions(-Wconversion)
|
||||||
|
|
||||||
set(libutils_a_SOURCES
|
set(libutils_a_SOURCES
|
||||||
|
arg.h arg.cpp
|
||||||
log.h log.cpp
|
log.h log.cpp
|
||||||
tcpsocket.h tcpsocket.cpp
|
tcpsocket.h tcpsocket.cpp
|
||||||
thread.h thread.cpp
|
thread.h thread.cpp
|
||||||
|
|||||||
Executable
+346
@@ -0,0 +1,346 @@
|
|||||||
|
/*
|
||||||
|
* ebusd - daemon for communication with eBUS heating systems.
|
||||||
|
* Copyright (C) 2023 John Baier <ebusd@ebusd.eu>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* (at your option) 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib/utils/arg.h"
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
namespace ebusd {
|
||||||
|
|
||||||
|
#define isAlpha(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
|
||||||
|
|
||||||
|
void calcCounts(const argDef *argDefs, int &count, int &shortCharsCount, int &shortOptsCount) {
|
||||||
|
for (const argDef *arg = argDefs; arg && arg->help; arg++) {
|
||||||
|
if (!arg->name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
if (!isAlpha(arg->key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
shortCharsCount++;
|
||||||
|
shortOptsCount++;
|
||||||
|
if (arg->valueName) {
|
||||||
|
shortOptsCount++;
|
||||||
|
if (arg->flags & af_optional) {
|
||||||
|
shortOptsCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildOpts(const argDef *argDefs, int &count, int &shortCharsCount, int &shortOptsCount, struct option *longOpts, char *shortChars, int *shortIndexes, char *shortOpts, int argDefIdx) {
|
||||||
|
struct option *opt = longOpts+count;
|
||||||
|
for (const argDef *arg = argDefs; arg && arg->help; arg++, argDefIdx++) {
|
||||||
|
if (!arg->name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
opt->name = arg->name;
|
||||||
|
opt->has_arg = arg->valueName ? ((arg->flags & af_optional) ? optional_argument : required_argument) : no_argument;
|
||||||
|
opt->flag = nullptr;
|
||||||
|
opt->val = argDefIdx;
|
||||||
|
if (isAlpha(arg->key)) {
|
||||||
|
shortChars[shortCharsCount] = (char)arg->key;
|
||||||
|
shortIndexes[shortCharsCount++] = count;
|
||||||
|
shortOpts[shortOptsCount++] = (char)arg->key;
|
||||||
|
if (arg->valueName) {
|
||||||
|
shortOpts[shortOptsCount++] = ':';
|
||||||
|
if (arg->flags & af_optional) {
|
||||||
|
shortOpts[shortOptsCount++] = ':';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opt++;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const argDef endArgDef = {nullptr, 0, nullptr, 0, nullptr, 0 };
|
||||||
|
static const argDef helpArgDef = {"help", '?', nullptr, 0, "Give this help list", 0 };
|
||||||
|
static const argDef helpArgDefs[] = {
|
||||||
|
helpArgDef,
|
||||||
|
endArgDef
|
||||||
|
};
|
||||||
|
static const argDef versionArgDef = {"version", 'V', nullptr, 0, "Print program version", 0 };
|
||||||
|
static const argDef versionArgDefs[] = {
|
||||||
|
versionArgDef,
|
||||||
|
endArgDef
|
||||||
|
};
|
||||||
|
|
||||||
|
int argParse(const argParseOpt *parseOpt, int argc, char **argv, int *argIndex) {
|
||||||
|
int count = 0, shortCharsCount = 0, shortOptsCount = 0;
|
||||||
|
if (!(parseOpt->flags & af_noHelp)) {
|
||||||
|
calcCounts(helpArgDefs, count, shortCharsCount, shortOptsCount);
|
||||||
|
}
|
||||||
|
if (!(parseOpt->flags & af_noVersion)) {
|
||||||
|
calcCounts(versionArgDefs, count, shortCharsCount, shortOptsCount);
|
||||||
|
}
|
||||||
|
calcCounts(parseOpt->argDefs, count, shortCharsCount, shortOptsCount);
|
||||||
|
for (const argParseChildOpt *child = parseOpt->childOpts; child && child->argDefs; child++) {
|
||||||
|
calcCounts(child->argDefs, count, shortCharsCount, shortOptsCount);
|
||||||
|
}
|
||||||
|
struct option *longOpts = (struct option*)calloc(count+1, sizeof(struct option)); // room for EOF
|
||||||
|
char *shortChars = (char*)calloc(shortCharsCount+1, sizeof(char)); // room for \0
|
||||||
|
int *shortIndexes = (int*)calloc(shortCharsCount, sizeof(int));
|
||||||
|
char *shortOpts = (char*)calloc(2+shortOptsCount+1, sizeof(char)); // room for +, :, and \0
|
||||||
|
count = 0;
|
||||||
|
shortCharsCount = 0;
|
||||||
|
shortOptsCount = 0;
|
||||||
|
shortOpts[shortOptsCount++] = '+'; // posix mode to stop at first non-option
|
||||||
|
shortOpts[shortOptsCount++] = ':'; // return ':' for missing option
|
||||||
|
if (!(parseOpt->flags & af_noHelp)) {
|
||||||
|
buildOpts(helpArgDefs, count, shortCharsCount, shortOptsCount, longOpts, shortChars, shortIndexes, shortOpts, 0xff00);
|
||||||
|
}
|
||||||
|
if (!(parseOpt->flags & af_noVersion)) {
|
||||||
|
buildOpts(versionArgDefs, count, shortCharsCount, shortOptsCount, longOpts, shortChars, shortIndexes, shortOpts, 0xff01);
|
||||||
|
}
|
||||||
|
buildOpts(parseOpt->argDefs, count, shortCharsCount, shortOptsCount, longOpts, shortChars, shortIndexes, shortOpts, 0);
|
||||||
|
int children = 0;
|
||||||
|
for (const argParseChildOpt *child = parseOpt->childOpts; child && child->argDefs; child++) {
|
||||||
|
buildOpts(child->argDefs, count, shortCharsCount, shortOptsCount, longOpts, shortChars, shortIndexes, shortOpts, 0x100*(++children));
|
||||||
|
}
|
||||||
|
optind = 1; // setting to 0 does not work
|
||||||
|
int c = 0, longIdx = -1, ret = 0;
|
||||||
|
while ((c = getopt_long(argc, argv, shortOpts, longOpts, &longIdx)) != -1) {
|
||||||
|
if (c == '?') {
|
||||||
|
// unknown option or help
|
||||||
|
if (optopt != '?') {
|
||||||
|
ret = '!';
|
||||||
|
fprintf(stderr, "invalid argument %s\n", argv[optind - 1]);
|
||||||
|
} else {
|
||||||
|
ret = c;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == ':') {
|
||||||
|
// missing option
|
||||||
|
fprintf(stderr, "missing argument to %s\n", argv[optind - 1]);
|
||||||
|
ret = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isAlpha(c)) {
|
||||||
|
// short name
|
||||||
|
int idx = (int)(strchr(shortChars, c) - shortChars);
|
||||||
|
if (idx >= 0 && idx < shortCharsCount) {
|
||||||
|
longIdx = shortIndexes[idx];
|
||||||
|
} else {
|
||||||
|
longIdx = -1;
|
||||||
|
}
|
||||||
|
} else if (c >= 0 && longIdx < 0) {
|
||||||
|
longIdx = c;
|
||||||
|
}
|
||||||
|
if (longIdx < 0 || longIdx >= count) {
|
||||||
|
ret = '!'; // error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int val = longOpts[longIdx].val;
|
||||||
|
if (val == 0xff00) { // help
|
||||||
|
ret = '?';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (val == 0xff01) { // version
|
||||||
|
ret = 'V';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const argDef *argDefs;
|
||||||
|
parse_function_t parser;
|
||||||
|
if (val & 0xff00) {
|
||||||
|
const argParseChildOpt *child = parseOpt->childOpts + ((val>>8)-1);
|
||||||
|
argDefs = child->argDefs;
|
||||||
|
parser = child->parser;
|
||||||
|
} else {
|
||||||
|
argDefs = parseOpt->argDefs;
|
||||||
|
parser = parseOpt->parser;
|
||||||
|
}
|
||||||
|
const argDef *arg = argDefs + (val & 0xff);
|
||||||
|
c = parser(arg->key, optarg, parseOpt);
|
||||||
|
if (c != 0) {
|
||||||
|
ret = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret == '?') {
|
||||||
|
argHelp(parseOpt);
|
||||||
|
} else if (argIndex && optind < argc) {
|
||||||
|
*argIndex = optind;
|
||||||
|
}
|
||||||
|
free(longOpts);
|
||||||
|
free(shortChars);
|
||||||
|
free(shortOpts);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MIN_INDENT 18
|
||||||
|
#define MAX_INDENT 29
|
||||||
|
#define MAX_BREAK 79
|
||||||
|
|
||||||
|
void wrap(const char* str, size_t pos, size_t indent) {
|
||||||
|
const char* end = strchr(str, 0);
|
||||||
|
const char* eol = strchr(str, '\n');
|
||||||
|
char buf[MAX_BREAK + 1];
|
||||||
|
bool first = true;
|
||||||
|
while (*str && str < end) {
|
||||||
|
if (!first) {
|
||||||
|
if (indent) {
|
||||||
|
printf("%*c", (int)indent, ' ');
|
||||||
|
}
|
||||||
|
pos = indent;
|
||||||
|
}
|
||||||
|
// start from max position backwards to find a break char
|
||||||
|
size_t cnt = MAX_BREAK - pos;
|
||||||
|
if (eol && eol < str) {
|
||||||
|
eol = strchr(str, '\n');
|
||||||
|
}
|
||||||
|
if (eol && eol < str + cnt) {
|
||||||
|
// EOL is before latest possible break
|
||||||
|
cnt = eol - str;
|
||||||
|
} else if (end < str + cnt) {
|
||||||
|
cnt = end - str;
|
||||||
|
}
|
||||||
|
for (; cnt > 0; cnt--) {
|
||||||
|
char ch = str[cnt];
|
||||||
|
if (ch == ' ' || ch == '\n' || ch == 0) {
|
||||||
|
// break found
|
||||||
|
buf[0] = 0;
|
||||||
|
strncat(buf, str, cnt);
|
||||||
|
printf("%s\n", buf);
|
||||||
|
str += cnt;
|
||||||
|
if (*str) {
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
break; // restart
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cnt == 0 && *str) {
|
||||||
|
// final
|
||||||
|
printf("%s\n", str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t calcIndent(const argDef *argDefs) {
|
||||||
|
size_t indent = 0;
|
||||||
|
for (const argDef *arg = argDefs; arg && arg->help; arg++) {
|
||||||
|
if (!arg->name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// e.g. " -d, --device=DEV Use DEV..."
|
||||||
|
size_t length = 2 + 3 + 3 + strlen(arg->name) + 2;
|
||||||
|
if (arg->valueName) {
|
||||||
|
length += 1 + strlen(arg->valueName);
|
||||||
|
if (arg->flags & af_optional) {
|
||||||
|
length += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (length > indent) {
|
||||||
|
indent = length;
|
||||||
|
if (indent > MAX_INDENT) {
|
||||||
|
return indent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return indent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printArgs(const argDef *argDefs, size_t indent) {
|
||||||
|
for (const argDef *arg = argDefs; arg && arg->help; arg++) {
|
||||||
|
if (!arg->name) {
|
||||||
|
if (*arg->help) {
|
||||||
|
printf("\n %s\n", arg->help);
|
||||||
|
} else {
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
printf(" ");
|
||||||
|
if (isAlpha(arg->key) || arg->key == '?') {
|
||||||
|
printf("-%c,", arg->key);
|
||||||
|
} else {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
printf(" --%s", arg->name);
|
||||||
|
size_t taken = 2 + 3 + 3 + strlen(arg->name);
|
||||||
|
if (arg->valueName) {
|
||||||
|
taken += 1 + strlen(arg->valueName);
|
||||||
|
if (arg->flags & af_optional) {
|
||||||
|
printf("[=%s]", arg->valueName);
|
||||||
|
taken += 2;
|
||||||
|
} else {
|
||||||
|
printf("=%s", arg->valueName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (taken > indent) {
|
||||||
|
printf(" ");
|
||||||
|
wrap(arg->help, taken+1, indent);
|
||||||
|
} else {
|
||||||
|
printf("%*c", (int)(indent - taken), ' ');
|
||||||
|
wrap(arg->help, indent, indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void argHelp(const argParseOpt *parseOpt) {
|
||||||
|
size_t indent = calcIndent(parseOpt->argDefs);
|
||||||
|
if (indent < MAX_INDENT) {
|
||||||
|
for (const argParseChildOpt *child = parseOpt->childOpts; child && child->argDefs; child++) {
|
||||||
|
size_t childIndent = calcIndent(child->argDefs);
|
||||||
|
if (childIndent > indent) {
|
||||||
|
indent = childIndent;
|
||||||
|
if (indent > MAX_INDENT) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (indent > MAX_INDENT) {
|
||||||
|
indent = MAX_INDENT;
|
||||||
|
} else if (indent < MIN_INDENT) {
|
||||||
|
indent = MIN_INDENT;
|
||||||
|
}
|
||||||
|
printf("Usage: %s [OPTION...] %s\n",
|
||||||
|
parseOpt->name,
|
||||||
|
parseOpt->positional ? parseOpt->positional : ""
|
||||||
|
);
|
||||||
|
wrap(parseOpt->help, 0, 0);
|
||||||
|
printArgs(parseOpt->argDefs, indent);
|
||||||
|
for (const argParseChildOpt *child = parseOpt->childOpts; child && child->argDefs; child++) {
|
||||||
|
printArgs(child->argDefs, indent);
|
||||||
|
}
|
||||||
|
if (!(parseOpt->flags & (af_noHelp|af_noVersion))) {
|
||||||
|
printf("\n");
|
||||||
|
if (!(parseOpt->flags & af_noHelp)) {
|
||||||
|
printArgs(helpArgDefs, indent);
|
||||||
|
}
|
||||||
|
if (!(parseOpt->flags & af_noVersion)) {
|
||||||
|
printArgs(versionArgDefs, indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parseOpt->suffix) {
|
||||||
|
printf("\n");
|
||||||
|
wrap(parseOpt->suffix, 0, 0);
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ebusd
|
||||||
Executable
+97
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* ebusd - daemon for communication with eBUS heating systems.
|
||||||
|
* Copyright (C) 2023 John Baier <ebusd@ebusd.eu>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* (at your option) 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIB_UTILS_ARGS_H_
|
||||||
|
#define LIB_UTILS_ARGS_H_
|
||||||
|
|
||||||
|
namespace ebusd {
|
||||||
|
|
||||||
|
/** \file lib/utils/args.h */
|
||||||
|
|
||||||
|
/** the available arg flags. */
|
||||||
|
enum ArgFlag {
|
||||||
|
af_optional = 1<<0, //!< optional argument value
|
||||||
|
af_noHelp = 1<<1, //!< do not include -?/--help option
|
||||||
|
af_noVersion = 1<<2, //!< do not include -V/--version option
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Definition of a single argument. */
|
||||||
|
typedef struct argDef {
|
||||||
|
const char* name; //!< the (long) name of the argument, or nullptr for a group header
|
||||||
|
int key; //!< the argument key, also used as short name if alphabetic or the question mark
|
||||||
|
const char* valueName; //!< the optional argument value name
|
||||||
|
int flags; //!< flags for the argument, bit combination of @a ArgFlag
|
||||||
|
const char* help; //!< help text (mandatory)
|
||||||
|
int unused; //!< currently unused (kept for compatibility to argp)
|
||||||
|
} argDef;
|
||||||
|
|
||||||
|
struct argParseOpt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to be called for each argument.
|
||||||
|
* @param key the argument key as defined.
|
||||||
|
* @param arg the argument value, or nullptr.
|
||||||
|
* @param parseOpt ppointer to the @a argParseOpt structure.
|
||||||
|
* @return 0 on success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
typedef int (*parse_function_t)(int key, char *arg, const struct argParseOpt *parseOpt);
|
||||||
|
|
||||||
|
/** Options for child definitions. */
|
||||||
|
typedef struct argParseChildOpt {
|
||||||
|
const argDef *argDefs; //!< pointer to the argument defintions (last one needs to have nullptr help as end sign)
|
||||||
|
parse_function_t parser; //!< parse function to use
|
||||||
|
} argParseChildOpt;
|
||||||
|
|
||||||
|
/** Options to pass to @a argParse(). */
|
||||||
|
typedef struct argParseOpt {
|
||||||
|
const argDef *argDefs; //!< pointer to the argument defintions (last one needs to have nullptr help as end sign)
|
||||||
|
parse_function_t parser; //!< parse function to use
|
||||||
|
int flags; //!< flags for the parser, bit combination of @a ArgFlag
|
||||||
|
const char* name; //!< name of the program parsed
|
||||||
|
const char* positional; //!< help text for optional positional argument
|
||||||
|
const char* help; //!< help text for the program (second line of help output)
|
||||||
|
const char* suffix; //!< optional help suffix text
|
||||||
|
const argParseChildOpt *childOpts; //!< optional child definitions
|
||||||
|
void* userArg; //!< optional user argument
|
||||||
|
} argParseOpt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the arguments given in @a argv.
|
||||||
|
* @param parseOpt pointer to the @a argParseOpt structure.
|
||||||
|
* @param argc the argument count (including the full program name in index 0).
|
||||||
|
* @param argv the argument values (including the full program name in index 0).
|
||||||
|
* @param argIndex optional pointer for storing the index to the first non-argument found in argv.
|
||||||
|
* @return 0 on success, '!' for an invalid argument value, ':' for a missing argument value,
|
||||||
|
* '?' when "-?" was given, or the result of the parse function if non-zero.
|
||||||
|
*/
|
||||||
|
int argParse(const argParseOpt *parseOpt, int argc, char **argv, int *argIndex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the help text.
|
||||||
|
* @param parseOpt ppointer to the @a argParseOpt structure.
|
||||||
|
*/
|
||||||
|
void argHelp(const argParseOpt *parseOpt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience macro to print an error message to stderr.
|
||||||
|
*/
|
||||||
|
#define argParseError(argParseOpt, message) fprintf(stderr, "%s\n", message);
|
||||||
|
|
||||||
|
} // namespace ebusd
|
||||||
|
|
||||||
|
#endif // LIB_UTILS_ARGS_H_
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
add_definitions(-Wno-unused-parameter)
|
||||||
|
|
||||||
set(ebusctl_SOURCES ebusctl.cpp)
|
set(ebusctl_SOURCES ebusctl.cpp)
|
||||||
set(ebuspicloader_SOURCES ebuspicloader.cpp intelhex/intelhexclass.cpp)
|
set(ebuspicloader_SOURCES ebuspicloader.cpp intelhex/intelhexclass.cpp)
|
||||||
|
|
||||||
@@ -7,13 +9,13 @@ include_directories(intelhex)
|
|||||||
|
|
||||||
add_executable(ebusctl ${ebusctl_SOURCES})
|
add_executable(ebusctl ${ebusctl_SOURCES})
|
||||||
add_executable(ebuspicloader ${ebuspicloader_SOURCES})
|
add_executable(ebuspicloader ${ebuspicloader_SOURCES})
|
||||||
target_link_libraries(ebusctl utils ebus ${LIB_ARGP} ${ebusctl_LIBS})
|
target_link_libraries(ebusctl utils ebus ${ebusctl_LIBS})
|
||||||
target_link_libraries(ebuspicloader utils ${LIB_ARGP} ${ebuspicloader_LIBS})
|
target_link_libraries(ebuspicloader utils ${ebuspicloader_LIBS})
|
||||||
|
|
||||||
if(WITH_EBUSFEED)
|
if(WITH_EBUSFEED)
|
||||||
set(ebusfeed_SOURCES ebusfeed.cpp)
|
set(ebusfeed_SOURCES ebusfeed.cpp)
|
||||||
add_executable(ebusfeed ${ebusfeed_SOURCES})
|
add_executable(ebusfeed ${ebusfeed_SOURCES})
|
||||||
target_link_libraries(ebusfeed ebus ${LIB_ARGP} ${ebusfeed_LIBS})
|
target_link_libraries(ebusfeed utils ebus ${ebusfeed_LIBS})
|
||||||
endif(WITH_EBUSFEED)
|
endif(WITH_EBUSFEED)
|
||||||
|
|
||||||
install(TARGETS ebusctl ebuspicloader EXPORT ebusd DESTINATION usr/bin)
|
install(TARGETS ebusctl ebuspicloader EXPORT ebusd DESTINATION usr/bin)
|
||||||
|
|||||||
+35
-34
@@ -20,7 +20,6 @@
|
|||||||
# include <config.h>
|
# include <config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <argp.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#ifdef HAVE_PPOLL
|
#ifdef HAVE_PPOLL
|
||||||
# include <poll.h>
|
# include <poll.h>
|
||||||
@@ -30,6 +29,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "lib/utils/arg.h"
|
||||||
#include "lib/utils/tcpsocket.h"
|
#include "lib/utils/tcpsocket.h"
|
||||||
|
|
||||||
namespace ebusd {
|
namespace ebusd {
|
||||||
@@ -62,24 +62,8 @@ static struct options opt = {
|
|||||||
0 // argCount
|
0 // argCount
|
||||||
};
|
};
|
||||||
|
|
||||||
/** the version string of the program. */
|
|
||||||
const char *argp_program_version = "ebusctl of """ PACKAGE_STRING "";
|
|
||||||
|
|
||||||
/** the report bugs to address of the program. */
|
|
||||||
const char *argp_program_bug_address = "" PACKAGE_BUGREPORT "";
|
|
||||||
|
|
||||||
/** the documentation of the program. */
|
|
||||||
static const char argpdoc[] =
|
|
||||||
"Client for acessing " PACKAGE " via TCP.\n"
|
|
||||||
"\v"
|
|
||||||
"If given, send COMMAND together with CMDOPT options to " PACKAGE ".\n"
|
|
||||||
"Use 'help' as COMMAND for help on available " PACKAGE " commands.";
|
|
||||||
|
|
||||||
/** the description of the accepted arguments. */
|
|
||||||
static char argpargsdoc[] = "\nCOMMAND [CMDOPT...]";
|
|
||||||
|
|
||||||
/** the definition of the known program arguments. */
|
/** the definition of the known program arguments. */
|
||||||
static const struct argp_option argpoptions[] = {
|
static const argDef argDefs[] = {
|
||||||
{nullptr, 0, nullptr, 0, "Options:", 1 },
|
{nullptr, 0, nullptr, 0, "Options:", 1 },
|
||||||
{"server", 's', "HOST", 0, "Connect to " PACKAGE " on HOST (name or IP) [localhost]", 0 },
|
{"server", 's', "HOST", 0, "Connect to " PACKAGE " on HOST (name or IP) [localhost]", 0 },
|
||||||
{"port", 'p', "PORT", 0, "Connect to " PACKAGE " on PORT [8888]", 0 },
|
{"port", 'p', "PORT", 0, "Connect to " PACKAGE " on PORT [8888]", 0 },
|
||||||
@@ -92,19 +76,19 @@ static const struct argp_option argpoptions[] = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The program argument parsing function.
|
* The program argument parsing function.
|
||||||
* @param key the key from @a argpoptions.
|
* @param key the key from @a argDefs.
|
||||||
* @param arg the option argument, or nullptr.
|
* @param arg the option argument, or nullptr.
|
||||||
* @param state the parsing state.
|
* @param parseOpt the parse options.
|
||||||
*/
|
*/
|
||||||
error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
static int parse_opt(int key, char *arg, const argParseOpt *parseOpt) {
|
||||||
struct options *opt = (struct options*)state->input;
|
struct options *opt = (struct options*)parseOpt->userArg;
|
||||||
char* strEnd = nullptr;
|
char* strEnd = nullptr;
|
||||||
unsigned int value;
|
unsigned int value;
|
||||||
switch (key) {
|
switch (key) {
|
||||||
// Device settings:
|
// Device settings:
|
||||||
case 's': // --server=localhost
|
case 's': // --server=localhost
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid server");
|
argParseError(parseOpt, "invalid server");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->server = arg;
|
opt->server = arg;
|
||||||
@@ -112,7 +96,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case 'p': // --port=8888
|
case 'p': // --port=8888
|
||||||
value = strtoul(arg, &strEnd, 10);
|
value = strtoul(arg, &strEnd, 10);
|
||||||
if (strEnd == nullptr || strEnd == arg || *strEnd != 0 || value < 1 || value > 65535) {
|
if (strEnd == nullptr || strEnd == arg || *strEnd != 0 || value < 1 || value > 65535) {
|
||||||
argp_error(state, "invalid port");
|
argParseError(parseOpt, "invalid port");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->port = (uint16_t)value;
|
opt->port = (uint16_t)value;
|
||||||
@@ -120,7 +104,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case 't': // --timeout=10
|
case 't': // --timeout=10
|
||||||
value = strtoul(arg, &strEnd, 10);
|
value = strtoul(arg, &strEnd, 10);
|
||||||
if (strEnd == nullptr || strEnd == arg || *strEnd != 0 || value > 3600) {
|
if (strEnd == nullptr || strEnd == arg || *strEnd != 0 || value > 3600) {
|
||||||
argp_error(state, "invalid timeout");
|
argParseError(parseOpt, "invalid timeout");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->timeout = (uint16_t)value;
|
opt->timeout = (uint16_t)value;
|
||||||
@@ -128,12 +112,8 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case 'e': // --error
|
case 'e': // --error
|
||||||
opt->errorResponse = true;
|
opt->errorResponse = true;
|
||||||
break;
|
break;
|
||||||
case ARGP_KEY_ARGS:
|
|
||||||
opt->args = state->argv + state->next;
|
|
||||||
opt->argCount = state->argc - state->next;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
return ARGP_ERR_UNKNOWN;
|
return ESRCH;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -362,11 +342,32 @@ bool connect(const char* host, uint16_t port, uint16_t timeout, char* const *arg
|
|||||||
* @return the exit code.
|
* @return the exit code.
|
||||||
*/
|
*/
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
struct argp argp = { argpoptions, parse_opt, argpargsdoc, argpdoc, nullptr, nullptr, nullptr };
|
argParseOpt parseOpt = {
|
||||||
setenv("ARGP_HELP_FMT", "no-dup-args-note", 0);
|
argDefs,
|
||||||
if (argp_parse(&argp, argc, argv, ARGP_IN_ORDER, nullptr, &opt) != 0) {
|
parse_opt,
|
||||||
return EINVAL;
|
af_noVersion,
|
||||||
|
"ebusctl",
|
||||||
|
"[COMMAND [CMDOPT...]]",
|
||||||
|
"Client for accessing " PACKAGE " via TCP.",
|
||||||
|
"If given, send COMMAND together with CMDOPT options to " PACKAGE ".\n"
|
||||||
|
"Use 'help' as COMMAND for help on available " PACKAGE " commands.",
|
||||||
|
nullptr,
|
||||||
|
&opt
|
||||||
|
};
|
||||||
|
int arg_index = -1;
|
||||||
|
switch (argParse(&parseOpt, argc, argv, &arg_index)) {
|
||||||
|
case 0: // OK
|
||||||
|
break;
|
||||||
|
case '?': // help printed
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
if (arg_index >= 0) {
|
||||||
|
opt.args = argv + arg_index;
|
||||||
|
opt.argCount = argc - arg_index;
|
||||||
|
}
|
||||||
|
|
||||||
bool success = connect(opt.server, opt.port, opt.timeout, opt.args, opt.argCount);
|
bool success = connect(opt.server, opt.port, opt.timeout, opt.args, opt.argCount);
|
||||||
|
|
||||||
exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
|
exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||||
|
|||||||
+47
-47
@@ -20,7 +20,6 @@
|
|||||||
# include <config.h>
|
# include <config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <argp.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -29,6 +28,7 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include "lib/ebus/device.h"
|
#include "lib/ebus/device.h"
|
||||||
#include "lib/ebus/result.h"
|
#include "lib/ebus/result.h"
|
||||||
|
#include "lib/utils/arg.h"
|
||||||
|
|
||||||
namespace ebusd {
|
namespace ebusd {
|
||||||
|
|
||||||
@@ -58,31 +58,8 @@ static struct options opt = {
|
|||||||
"/tmp/ebus_dump.bin", // dumpFile
|
"/tmp/ebus_dump.bin", // dumpFile
|
||||||
};
|
};
|
||||||
|
|
||||||
/** the version string of the program. */
|
|
||||||
const char *argp_program_version = "ebusfeed of """ PACKAGE_STRING "";
|
|
||||||
|
|
||||||
/** the report bugs to address of the program. */
|
|
||||||
const char *argp_program_bug_address = "" PACKAGE_BUGREPORT "";
|
|
||||||
|
|
||||||
/** the documentation of the program. */
|
|
||||||
static const char argpdoc[] =
|
|
||||||
"Feed data from an " PACKAGE " DUMPFILE to a serial device.\n"
|
|
||||||
"\v"
|
|
||||||
"With no DUMPFILE, /tmp/ebus_dump.bin is used.\n"
|
|
||||||
"\n"
|
|
||||||
"Example for setting up two pseudo terminals with 'socat':\n"
|
|
||||||
" 1. 'socat -d -d pty,raw,echo=0 pty,raw,echo=0'\n"
|
|
||||||
" 2. create symbol links to appropriate devices, e.g.\n"
|
|
||||||
" 'ln -s /dev/pts/2 /dev/ttyUSB60'\n"
|
|
||||||
" 'ln -s /dev/pts/3 /dev/ttyUSB20'\n"
|
|
||||||
" 3. start " PACKAGE ": '" PACKAGE " -f -d /dev/ttyUSB20 --nodevicecheck'\n"
|
|
||||||
" 4. start ebusfeed: 'ebusfeed /path/to/ebus_dump.bin'\n";
|
|
||||||
|
|
||||||
/** the description of the accepted arguments. */
|
|
||||||
static char argpargsdoc[] = "[DUMPFILE]";
|
|
||||||
|
|
||||||
/** the definition of the known program arguments. */
|
/** the definition of the known program arguments. */
|
||||||
static const struct argp_option argpoptions[] = {
|
static const ebusd::argDef argDefs[] = {
|
||||||
{"device", 'd', "DEV", 0, "Write to DEV (serial device) [/dev/ttyUSB60]", 0 },
|
{"device", 'd', "DEV", 0, "Write to DEV (serial device) [/dev/ttyUSB60]", 0 },
|
||||||
{"time", 't', "USEC", 0, "Delay each byte by USEC us [10000]", 0 },
|
{"time", 't', "USEC", 0, "Delay each byte by USEC us [10000]", 0 },
|
||||||
|
|
||||||
@@ -91,18 +68,18 @@ static const struct argp_option argpoptions[] = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The program argument parsing function.
|
* The program argument parsing function.
|
||||||
* @param key the key from @a argpoptions.
|
* @param key the key from @a argDefs.
|
||||||
* @param arg the option argument, or nullptr.
|
* @param arg the option argument, or nullptr.
|
||||||
* @param state the parsing state.
|
* @param parseOpt the parse options.
|
||||||
*/
|
*/
|
||||||
error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
static int parse_opt(int key, char *arg, const ebusd::argParseOpt *parseOpt) {
|
||||||
struct options *opt = (struct options*)state->input;
|
struct options *opt = (struct options*)parseOpt->userArg;
|
||||||
char* strEnd = nullptr;
|
char* strEnd = nullptr;
|
||||||
switch (key) {
|
switch (key) {
|
||||||
// Device settings:
|
// Device settings:
|
||||||
case 'd': // --device=/dev/ttyUSB60
|
case 'd': // --device=/dev/ttyUSB60
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid device");
|
argParseError(parseOpt, "invalid device");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->device = arg;
|
opt->device = arg;
|
||||||
@@ -110,23 +87,12 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
case 't': // --time=10000
|
case 't': // --time=10000
|
||||||
opt->time = (unsigned int)strtoul(arg, &strEnd, 10);
|
opt->time = (unsigned int)strtoul(arg, &strEnd, 10);
|
||||||
if (strEnd == nullptr || strEnd == arg || *strEnd != 0 || opt->time < 1000 || opt->time > 100000000) {
|
if (strEnd == nullptr || strEnd == arg || *strEnd != 0 || opt->time < 1000 || opt->time > 100000000) {
|
||||||
argp_error(state, "invalid time");
|
argParseError(parseOpt, "invalid time");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARGP_KEY_ARG:
|
|
||||||
if (state->arg_num == 0) {
|
|
||||||
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
|
|
||||||
argp_error(state, "invalid dumpfile");
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
opt->dumpFile = arg;
|
|
||||||
} else {
|
|
||||||
return ARGP_ERR_UNKNOWN;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
return ARGP_ERR_UNKNOWN;
|
return ESRCH;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -139,11 +105,45 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
* @return the exit code.
|
* @return the exit code.
|
||||||
*/
|
*/
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
struct argp argp = { argpoptions, parse_opt, argpargsdoc, argpdoc, nullptr, nullptr, nullptr };
|
ebusd::argParseOpt parseOpt = {
|
||||||
setenv("ARGP_HELP_FMT", "no-dup-args-note", 0);
|
argDefs,
|
||||||
if (argp_parse(&argp, argc, argv, ARGP_IN_ORDER, nullptr, &opt) != 0) {
|
parse_opt,
|
||||||
return EINVAL;
|
"ebusfeed",
|
||||||
|
"[DUMPFILE]",
|
||||||
|
"Feed data from an " PACKAGE " DUMPFILE to a serial device.",
|
||||||
|
"With no DUMPFILE, /tmp/ebus_dump.bin is used.\n"
|
||||||
|
"\n"
|
||||||
|
"Example for setting up two pseudo terminals with 'socat':\n"
|
||||||
|
" 1. 'socat -d -d pty,raw,echo=0 pty,raw,echo=0'\n"
|
||||||
|
" 2. create symbol links to appropriate devices, e.g.\n"
|
||||||
|
" 'ln -s /dev/pts/2 /dev/ttyUSB60'\n"
|
||||||
|
" 'ln -s /dev/pts/3 /dev/ttyUSB20'\n"
|
||||||
|
" 3. start " PACKAGE ": '" PACKAGE " -f -d /dev/ttyUSB20 --nodevicecheck'\n"
|
||||||
|
" 4. start ebusfeed: 'ebusfeed /path/to/ebus_dump.bin'",
|
||||||
|
&opt
|
||||||
|
};
|
||||||
|
int arg_index = -1;
|
||||||
|
switch (ebusd::argParse(&parseOpt, argc, argv, &arg_index)) {
|
||||||
|
case 0: // OK
|
||||||
|
break;
|
||||||
|
case '?': // help printed
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
if (arg_index >= 0) {
|
||||||
|
if (argv[arg_index][0] == 0 || strcmp("/", argv[arg_index]) == 0) {
|
||||||
|
argParseError(parseOpt, "invalid dumpfile");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
if (arg_index != argc -1) {
|
||||||
|
// more than one arg
|
||||||
|
argParseError(parseOpt, "multiple dumpfile");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
opt.dumpFile = argv[arg_index];
|
||||||
|
}
|
||||||
|
|
||||||
Device* device = Device::create(opt.device, false, false, false);
|
Device* device = Device::create(opt.device, false, false, false);
|
||||||
if (device == nullptr) {
|
if (device == nullptr) {
|
||||||
cout << "unable to create device " << opt.device << endl;
|
cout << "unable to create device " << opt.device << endl;
|
||||||
|
|||||||
+62
-54
@@ -29,7 +29,6 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <argp.h>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@@ -37,29 +36,13 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "intelhex/intelhexclass.h"
|
#include "intelhex/intelhexclass.h"
|
||||||
|
#include "lib/utils/arg.h"
|
||||||
#include "lib/utils/tcpsocket.h"
|
#include "lib/utils/tcpsocket.h"
|
||||||
|
|
||||||
using ebusd::socketConnect;
|
using ebusd::socketConnect;
|
||||||
|
|
||||||
/** the version string of the program. */
|
|
||||||
const char *argp_program_version = "eBUS adapter PIC firmware loader";
|
|
||||||
|
|
||||||
/** the documentation of the program. */
|
|
||||||
static const char argpdoc[] =
|
|
||||||
"A tool for loading firmware to the eBUS adapter PIC and configure adjustable settings."
|
|
||||||
"\vPORT is either the serial port to use (e.g. "
|
|
||||||
#ifdef __CYGWIN__
|
|
||||||
"/dev/ttyS0 for COM1 on Windows"
|
|
||||||
#else
|
|
||||||
"/dev/ttyUSB0"
|
|
||||||
#endif
|
|
||||||
") that also supports a trailing wildcard '*' for testing"
|
|
||||||
" multiple ports, or a network port as \"ip:port\" for use with e.g. socat or ebusd-esp in PIC pass-through mode.";
|
|
||||||
|
|
||||||
static const char argpargsdoc[] = "PORT";
|
|
||||||
|
|
||||||
/** the definition of the known program arguments. */
|
/** the definition of the known program arguments. */
|
||||||
static const struct argp_option argpoptions[] = {
|
static const ebusd::argDef argDefs[] = {
|
||||||
{nullptr, 0, nullptr, 0, "IP options:", 1 },
|
{nullptr, 0, nullptr, 0, "IP options:", 1 },
|
||||||
{"dhcp", 'd', nullptr, 0, "set dynamic IP address via DHCP (default)", 0 },
|
{"dhcp", 'd', nullptr, 0, "set dynamic IP address via DHCP (default)", 0 },
|
||||||
{"ip", 'i', "IP", 0, "set fix IP address (e.g. 192.168.0.10)", 0 },
|
{"ip", 'i', "IP", 0, "set fix IP address (e.g. 192.168.0.10)", 0 },
|
||||||
@@ -82,7 +65,7 @@ static const struct argp_option argpoptions[] = {
|
|||||||
{nullptr, 0, nullptr, 0, "Tool options:", 9 },
|
{nullptr, 0, nullptr, 0, "Tool options:", 9 },
|
||||||
{"verbose", 'v', nullptr, 0, "enable verbose output", 0 },
|
{"verbose", 'v', nullptr, 0, "enable verbose output", 0 },
|
||||||
{"slow", 's', nullptr, 0, "low speed mode for transfer (115kBd instead of 921kBd)", 0 },
|
{"slow", 's', nullptr, 0, "low speed mode for transfer (115kBd instead of 921kBd)", 0 },
|
||||||
{nullptr, 0, nullptr, 0, nullptr, 0 },
|
{nullptr, 0, nullptr, 0, nullptr, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool verbose = false;
|
static bool verbose = false;
|
||||||
@@ -136,7 +119,13 @@ bool parseShort(const char *arg, uint16_t minValue, uint16_t maxValue, uint16_t
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
/**
|
||||||
|
* The program argument parsing function.
|
||||||
|
* @param key the key from @a argDefs.
|
||||||
|
* @param arg the option argument, or nullptr.
|
||||||
|
* @param parseOpt the parse options.
|
||||||
|
*/
|
||||||
|
static int parse_opt(int key, char *arg, const ebusd::argParseOpt *parseOpt) {
|
||||||
char *ip = nullptr, *part = nullptr;
|
char *ip = nullptr, *part = nullptr;
|
||||||
int pos = 0, sum = 0;
|
int pos = 0, sum = 0;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@@ -147,22 +136,22 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
break;
|
break;
|
||||||
case 'd': // --dhcp
|
case 'd': // --dhcp
|
||||||
if (setIp || setMask || setGateway) {
|
if (setIp || setMask || setGateway) {
|
||||||
argp_error(state, "either DHCP or IP address is needed");
|
argParseError(parseOpt, "either DHCP or IP address is needed");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
setDhcp = true;
|
setDhcp = true;
|
||||||
break;
|
break;
|
||||||
case 'i': // --ip=192.168.0.10
|
case 'i': // --ip=192.168.0.10
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid IP address");
|
argParseError(parseOpt, "invalid IP address");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (setDhcp) {
|
if (setDhcp) {
|
||||||
argp_error(state, "either DHCP or IP address is needed");
|
argParseError(parseOpt, "either DHCP or IP address is needed");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (setIp) {
|
if (setIp) {
|
||||||
argp_error(state, "IP address was specified twice");
|
argParseError(parseOpt, "IP address was specified twice");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
ip = strdup(arg);
|
ip = strdup(arg);
|
||||||
@@ -177,41 +166,41 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
}
|
}
|
||||||
free(ip);
|
free(ip);
|
||||||
if (pos != 4 || part || sum == 0) {
|
if (pos != 4 || part || sum == 0) {
|
||||||
argp_error(state, "invalid IP address");
|
argParseError(parseOpt, "invalid IP address");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
setIp = true;
|
setIp = true;
|
||||||
break;
|
break;
|
||||||
case 'm': // --mask=24
|
case 'm': // --mask=24
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid IP mask");
|
argParseError(parseOpt, "invalid IP mask");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (setDhcp) {
|
if (setDhcp) {
|
||||||
argp_error(state, "either DHCP or IP address is needed");
|
argParseError(parseOpt, "either DHCP or IP address is needed");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (setMask) {
|
if (setMask) {
|
||||||
argp_error(state, "mask was specified twice");
|
argParseError(parseOpt, "mask was specified twice");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (!parseByte(arg, 1, 0x1e, &setMaskLen)) {
|
if (!parseByte(arg, 1, 0x1e, &setMaskLen)) {
|
||||||
argp_error(state, "invalid IP mask");
|
argParseError(parseOpt, "invalid IP mask");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
setMask = true;
|
setMask = true;
|
||||||
break;
|
break;
|
||||||
case 'g': // --gateway=192.168.0.11
|
case 'g': // --gateway=192.168.0.11
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid gateway");
|
argParseError(parseOpt, "invalid gateway");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (setDhcp) {
|
if (setDhcp) {
|
||||||
argp_error(state, "either DHCP or IP address is needed");
|
argParseError(parseOpt, "either DHCP or IP address is needed");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (!setIp || !setMask) {
|
if (!setIp || !setMask) {
|
||||||
argp_error(state, "IP and mask need to be specified before gateway");
|
argParseError(parseOpt, "IP and mask need to be specified before gateway");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
ip = strdup(arg);
|
ip = strdup(arg);
|
||||||
@@ -228,7 +217,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
uint8_t maskRemain = setMaskLen-pos*8;
|
uint8_t maskRemain = setMaskLen-pos*8;
|
||||||
uint8_t mask = maskRemain >= 8 ? 255 : maskRemain == 0 ? 0 : (255^((1 << (8 - maskRemain)) - 1));
|
uint8_t mask = maskRemain >= 8 ? 255 : maskRemain == 0 ? 0 : (255^((1 << (8 - maskRemain)) - 1));
|
||||||
if ((address & mask) != (setIpAddress[pos] & mask)) {
|
if ((address & mask) != (setIpAddress[pos] & mask)) {
|
||||||
argp_error(state, "invalid gateway (different network)");
|
argParseError(parseOpt, "invalid gateway (different network)");
|
||||||
free(ip);
|
free(ip);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
@@ -237,15 +226,15 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
}
|
}
|
||||||
free(ip);
|
free(ip);
|
||||||
if (pos != 4 || part || sum == 0 || setGatewayBits == 0) {
|
if (pos != 4 || part || sum == 0 || setGatewayBits == 0) {
|
||||||
argp_error(state, "invalid gateway");
|
argParseError(parseOpt, "invalid gateway");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (setGatewayBits == hostBits) {
|
if (setGatewayBits == hostBits) {
|
||||||
argp_error(state, "invalid gateway (same as address)");
|
argParseError(parseOpt, "invalid gateway (same as address)");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (!setGatewayBits || setGatewayBits == ((1 << (32 - setMaskLen)) - 1)) {
|
if (!setGatewayBits || setGatewayBits == ((1 << (32 - setMaskLen)) - 1)) {
|
||||||
argp_error(state, "invalid gateway (net or broadcast address)");
|
argParseError(parseOpt, "invalid gateway (net or broadcast address)");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (setGatewayBits == 1) { // default
|
if (setGatewayBits == 1) { // default
|
||||||
@@ -260,7 +249,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
}
|
}
|
||||||
if (!(setGatewayBits >> 5)) {
|
if (!(setGatewayBits >> 5)) {
|
||||||
if (!(setGatewayBits & 0x1f)) {
|
if (!(setGatewayBits & 0x1f)) {
|
||||||
argp_error(state, "invalid gateway (net address)");
|
argParseError(parseOpt, "invalid gateway (net address)");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
// fine: host part above max gateway adjustable bits is the same and remainder non-zero
|
// fine: host part above max gateway adjustable bits is the same and remainder non-zero
|
||||||
@@ -274,7 +263,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
setGateway = true;
|
setGateway = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
argp_error(state, "invalid gateway (out of possible range of first/last 31 hosts in subnet)");
|
argParseError(parseOpt, "invalid gateway (out of possible range of first/last 31 hosts in subnet)");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
case 'M': // --macip
|
case 'M': // --macip
|
||||||
setMacFromIp = true;
|
setMacFromIp = true;
|
||||||
@@ -286,11 +275,11 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
break;
|
break;
|
||||||
case 'a': // --arbdel=1000
|
case 'a': // --arbdel=1000
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid arbitration delay");
|
argParseError(parseOpt, "invalid arbitration delay");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (!parseShort(arg, 0, 620, &setArbitrationDelayMicros)) {
|
if (!parseShort(arg, 0, 620, &setArbitrationDelayMicros)) {
|
||||||
argp_error(state, "invalid arbitration delay");
|
argParseError(parseOpt, "invalid arbitration delay");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
setArbitrationDelay = true;
|
setArbitrationDelay = true;
|
||||||
@@ -305,7 +294,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
break;
|
break;
|
||||||
case -3: // --variant=U|W|E|F|N|u|w|e|f|n
|
case -3: // --variant=U|W|E|F|N|u|w|e|f|n
|
||||||
if (arg == nullptr || arg[0] == 0) {
|
if (arg == nullptr || arg[0] == 0) {
|
||||||
argp_error(state, "invalid variant");
|
argParseError(parseOpt, "invalid variant");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (arg[0] == 'u' || arg[0] == 'U') {
|
if (arg[0] == 'u' || arg[0] == 'U') {
|
||||||
@@ -319,7 +308,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
} else if (arg[0] == 'n' || arg[0] == 'N') {
|
} else if (arg[0] == 'n' || arg[0] == 'N') {
|
||||||
setVariantValue = 0;
|
setVariantValue = 0;
|
||||||
} else {
|
} else {
|
||||||
argp_error(state, "invalid variant");
|
argParseError(parseOpt, "invalid variant");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
setVariantForced = arg[0]<'a';
|
setVariantForced = arg[0]<'a';
|
||||||
@@ -327,7 +316,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
break;
|
break;
|
||||||
case 'f': // --flash=firmware.hex
|
case 'f': // --flash=firmware.hex
|
||||||
if (arg == nullptr || arg[0] == 0 || stat(arg, &st) != 0 || !S_ISREG(st.st_mode)) {
|
if (arg == nullptr || arg[0] == 0 || stat(arg, &st) != 0 || !S_ISREG(st.st_mode)) {
|
||||||
argp_error(state, "invalid flash file");
|
argParseError(parseOpt, "invalid flash file");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
flashFile = arg;
|
flashFile = arg;
|
||||||
@@ -339,7 +328,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
lowSpeed = true;
|
lowSpeed = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return ARGP_ERR_UNKNOWN;
|
return ESRCH;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1094,7 +1083,7 @@ int readSettings(int fd, uint8_t* currentData = nullptr) {
|
|||||||
} else {
|
} else {
|
||||||
std::cout << "off" << std::endl;
|
std::cout << "off" << std::endl;
|
||||||
}
|
}
|
||||||
std::cout << "Variant: "; // since firmware 20221206
|
std::cout << "Variant: "; // since firmware 20221206
|
||||||
switch (configData[5]&0x03) {
|
switch (configData[5]&0x03) {
|
||||||
case 3:
|
case 3:
|
||||||
std::cout << "USB/RPI (high-speed)";
|
std::cout << "USB/RPI (high-speed)";
|
||||||
@@ -1156,7 +1145,7 @@ bool writeSettings(int fd, uint8_t* currentData = nullptr) {
|
|||||||
if (setVariant) {
|
if (setVariant) {
|
||||||
configData[5] = (configData[5]&0x38) | (setVariantForced?0:0x04) | (setVariantValue&0x03);
|
configData[5] = (configData[5]&0x38) | (setVariantForced?0:0x04) | (setVariantValue&0x03);
|
||||||
if (setVariantValue==0) {
|
if (setVariantValue==0) {
|
||||||
configData[1] = (configData[1]&~0x1f); // set mask=0 to disable Ethernet
|
configData[1] = (configData[1]&~0x1f); // set mask=0 to disable Ethernet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (writeConfig(fd, 0x0000, 8, configData) != 0) {
|
if (writeConfig(fd, 0x0000, 8, configData) != 0) {
|
||||||
@@ -1170,13 +1159,32 @@ bool writeSettings(int fd, uint8_t* currentData = nullptr) {
|
|||||||
int run(int fd);
|
int run(int fd);
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
struct argp aargp = { argpoptions, parse_opt, argpargsdoc, argpdoc, nullptr, nullptr, nullptr };
|
ebusd::argParseOpt parseOpt = {
|
||||||
|
argDefs,
|
||||||
|
parse_opt,
|
||||||
|
ebusd::af_noVersion,
|
||||||
|
"ebuspicloader",
|
||||||
|
"[PORT]",
|
||||||
|
"A tool for loading firmware to the eBUS adapter PIC and configure adjustable settings.",
|
||||||
|
"PORT is either the serial port to use (e.g. "
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
"/dev/ttyS0 for COM1 on Windows"
|
||||||
|
#else
|
||||||
|
"/dev/ttyUSB0"
|
||||||
|
#endif
|
||||||
|
") that also supports a trailing wildcard '*' for testing"
|
||||||
|
" multiple ports, or a network port as \"ip:port\" for use with e.g. socat or ebusd-esp in PIC pass-through mode.",
|
||||||
|
nullptr,
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
int arg_index = -1;
|
int arg_index = -1;
|
||||||
setenv("ARGP_HELP_FMT", "no-dup-args-note", 0);
|
switch (ebusd::argParse(&parseOpt, argc, argv, &arg_index)) {
|
||||||
|
case 0: // OK
|
||||||
if (argp_parse(&aargp, argc, argv, ARGP_IN_ORDER, &arg_index, nullptr) != 0) {
|
break;
|
||||||
std::cerr << "invalid arguments" << std::endl;
|
case '?': // help printed
|
||||||
exit(EXIT_FAILURE);
|
return 0;
|
||||||
|
default:
|
||||||
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setIp != setMask || (setMacFromIp && !setIp)) {
|
if (setIp != setMask || (setMacFromIp && !setIp)) {
|
||||||
@@ -1188,7 +1196,7 @@ int main(int argc, char* argv[]) {
|
|||||||
printFileChecksum();
|
printFileChecksum();
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
} else {
|
} else {
|
||||||
argp_help(&aargp, stderr, ARGP_HELP_STD_ERR, const_cast<char*>("ebuspicloader"));
|
ebusd::argHelp(&parseOpt);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user