summaryrefslogtreecommitdiff
path: root/src/inverterctl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/inverterctl.cc')
-rw-r--r--src/inverterctl.cc343
1 files changed, 211 insertions, 132 deletions
diff --git a/src/inverterctl.cc b/src/inverterctl.cc
index f071f2e..d22f53a 100644
--- a/src/inverterctl.cc
+++ b/src/inverterctl.cc
@@ -10,19 +10,33 @@
#include <stdexcept>
#include <getopt.h>
+// common stuff
#include "logging.h"
#include "util.h"
#include "common.h"
-#include "p18/client.h"
-#include "p18/types.h"
-#include "p18/defines.h"
-#include "p18/exceptions.h"
-#include "p18/commands.h"
#include "formatter/formatter.h"
#include "voltronic/device.h"
#include "voltronic/exceptions.h"
#include "hexdump/hexdump.h"
+#include "protocol/input.h"
+#include "protocol/exceptions.h"
+#include "protocol/response.h"
+
+// p18
+#include "protocol_18/client.h"
+#include "protocol_18/types.h"
+#include "protocol_18/defines.h"
+#include "protocol_18/input.h"
+
+// p17
+//#include "protocol_17/client.h"
+#include "protocol_17/types.h"
+#include "protocol_17/defines.h"
+#include "protocol_17/input.h"
+
+
+
const size_t MAX_RAW_COMMAND_LENGTH = 128;
template <typename T, std::size_t N>
@@ -42,6 +56,7 @@ static void short_usage(const char* progname) {
" -h: Show this help\n"
" --help: Show full help (with all commands)\n"
" --raw <DATA>: Execute arbitrary command and print response\n"
+ " -p, --protocol <ID> 17 or 18 (default)\n"
" --device <DEVICE>: 'usb' (default), 'serial' or 'pseudo'\n"
" --timeout <TIMEOUT>: Timeout in ms (default: " << voltronic::Device::TIMEOUT << ")\n"
" --verbose: Be verbose\n"
@@ -52,7 +67,142 @@ static void short_usage(const char* progname) {
exit(1);
}
-static void usage(const char* progname) {
+static void usage_p17() {
+ std::cout <<
+ "P17 commands:\n"
+ " get-protocol-id\n"
+ " get-date-time\n"
+ " get-total-generated\n"
+ " get-year-generated <yyyy>\n"
+ " get-month-generated <yyyy> <mm>\n"
+ " get-day-generated <yyyy> <mm> <dd> <HH>\n"
+ " get-series-number\n"
+ " get-cpu-version\n"
+ " get-secondary-cpu-version\n"
+
+ ;
+}
+
+static void usage_p18() {
+ std::cout <<
+ "P18 commands:\n"
+ " get-protocol-id\n"
+ " get-date-time\n"
+ " get-total-generated\n"
+ " get-year-generated <yyyy>\n"
+ " get-month-generated <yyyy> <mm>\n"
+ " get-day-generated <yyyy> <mm> <dd>\n"
+ " get-series-number\n"
+ " get-cpu-version\n"
+ " get-rated\n"
+ " get-status\n"
+ " get-p-rated <id>\n"
+ " id: Parallel machine ID\n"
+ "\n"
+ " get-p-status <id>\n"
+ " id: Parallel machine ID\n"
+ "\n"
+ " get-mode\n"
+ " get-errors\n"
+ " get-flags\n"
+ " get-rated-defaults\n"
+ " get-allowed-charging-currents\n"
+ " get-allowed-ac-charging-currents\n"
+ " get-ac-charging-time\n"
+ " get-ac-loads-supply-time\n"
+ " set-loads-supply 0|1\n"
+ " set-flag <flag> 0|1\n"
+ " set-rated-defaults\n"
+ " set-max-charging-current <id> <amps>\n"
+ " id: Parallel machine ID (use 0 for single model)\n"
+ " amps: Use get-allowed-charging-currents\n"
+ " to see a list of allowed values.\n"
+ "\n"
+ " set-max-ac-charging-current <id> <amps>\n"
+ " id: Parallel machine ID (use 0 for single model)\n"
+ " amps: Use get-allowed-ac-charging-currents\n"
+ " to see a list of allowed values.\n"
+ "\n"
+ " set-ac-output-freq 50|60\n"
+ " set-max-charging-voltage <cv> <fv>\n"
+ " cv: Constant voltage (48.0 ~ 58.4).\n"
+ " fv: Float voltage (48.0 ~ 58.4).\n"
+ "\n"
+ " set-ac-output-voltage <v>\n"
+ " v: " << p18::ac_output_rated_voltages << "\n"
+ "\n"
+ " set-output-source-priority SUB|SBU\n"
+ " 'SUB' means " << p18::OutputSourcePriority::SolarUtilityBattery << "\n"
+ " 'SBU' means " << p18::OutputSourcePriority::SolarBatteryUtility << "\n"
+ "\n"
+ " set-charging-thresholds <cv> <dv>\n"
+ " Set battery re-charging and re-discharging voltages when\n"
+ " utility is available.\n"
+ "\n"
+ " cv: re-charging voltage\n"
+ " For 12 V unit: " << p18::bat_ac_recharging_voltages_12v << "\n"
+ " For 24 V unit: " << p18::bat_ac_recharging_voltages_24v << "\n"
+ " For 48 V unit: " << p18::bat_ac_recharging_voltages_48v << "\n"
+ "\n"
+ " dv: re-discharging voltage\n"
+ " For 12 V unit: " << p18::bat_ac_redischarging_voltages_12v << "\n"
+ " For 24 V unit: " << p18::bat_ac_redischarging_voltages_24v << "\n"
+ " For 48 V unit: " << p18::bat_ac_redischarging_voltages_48v << "\n"
+ "\n"
+ " set-charging-source-priority <id> <priority>\n"
+ " id: Parallel machine ID (use 0 for a single model)\n"
+ " priority: SF|SU|S\n"
+ " 'SF' means " << p18::ChargerSourcePriority::SolarFirst << ",\n"
+ " 'SU' means " << p18::ChargerSourcePriority::SolarAndUtility << "\n"
+ " 'S' means " << p18::ChargerSourcePriority::SolarOnly << "\n"
+ "\n"
+ " set-solar-power-priority BLU|LBU\n"
+ " 'BLU' means " << p18::SolarPowerPriority::BatteryLoadUtility << "\n"
+ " 'LBU' means " << p18::SolarPowerPriority::LoadBatteryUtility << "\n"
+ "\n"
+ " set-ac-input-voltage-range APPLIANCE|UPS\n"
+ " set-battery-type AGM|FLOODED|USER\n"
+ " set-output-model <id> <model>\n"
+ " id: Parallel machine ID (use 0 for a single model)\n"
+ " model: SM|P|P1|P2|P3\n"
+ " SM: " << p18::OutputModelSetting::SingleModule << "\n"
+ " P: " << p18::OutputModelSetting::ParallelOutput << "\n"
+ " P1: " << p18::OutputModelSetting::Phase1OfThreePhaseOutput << "\n"
+ " P2: " << p18::OutputModelSetting::Phase2OfThreePhaseOutput << "\n"
+ " P3: " << p18::OutputModelSetting::Phase3OfThreePhaseOutput << "\n"
+ "\n"
+ " set-battery-cut-off-voltage <v>\n"
+ " v: Cut-off voltage (40.0~48.0)\n"
+ "\n"
+ " set-solar-configuration <id>\n"
+ " id: Serial number\n"
+ "\n"
+ " clear-generated-data\n"
+ " Clear all recorded stats about generated energy.\n"
+ "\n"
+ " set-date-time <YYYY> <MM> <DD> <hh> <mm> <ss>\n"
+ " YYYY: Year\n"
+ " MM: Month\n"
+ " DD: Day\n"
+ " hh: Hours\n"
+ " mm: Minutes\n"
+ " ss: Seconds\n"
+ "\n"
+ " set-ac-charging-time <start> <end>\n"
+ " start: Starting time, hh:mm format\n"
+ " end: Ending time, hh:mm format\n"
+ "\n"
+ " set-ac-loads-supply-time <start> <end>\n"
+ " start: Starting time, hh:mm format\n"
+ " end: Ending time, hh:mm format\n"
+ "\n"
+ "Flags:\n";
+
+ for (const p18::Flag& flag: p18::flags)
+ std::cout << " " << flag.flag << ": " << flag.description << "\n";
+}
+
+static void usage(const char* progname, Protocol p) {
std::ios_base::fmtflags f(std::cout.flags());
std::cout << "Usage: " << progname << " OPTIONS [COMMAND]\n" <<
"\n"
@@ -61,6 +211,7 @@ static void usage(const char* progname) {
" --help: Show this help\n"
" --raw <DATA>: Execute arbitrary command and print response\n"
" (example: ^P005PI)\n"
+ " -p, --protocol <ID> Protocol ID (default: 18)\n"
" --device <DEVICE>: Device type to use. See below for list of supported\n"
" devices\n"
" --timeout <TIMEOUT>: Device read/write timeout, in milliseconds\n"
@@ -69,6 +220,10 @@ static void usage(const char* progname) {
" device traffic)\n"
" --format <FORMAT>: Output format for command responses\n"
"\n"
+ "Protocols:\n"
+ " 17\n"
+ " 18\n"
+ "\n"
"Device types:\n"
" usb USB device\n"
" serial Serial device\n"
@@ -87,121 +242,13 @@ static void usage(const char* progname) {
" --serial-data-bits 5|6|7|8\n"
" --serial-stop-bits 1|1.5|2\n"
" --serial-parity none|odd|even|mark|space\n"
- "\n"
- "Commands:\n"
- " get-protocol-id\n"
- " get-date-time\n"
- " get-total-generated\n"
- " get-year-generated <yyyy>\n"
- " get-month-generated <yyyy> <mm>\n"
- " get-day-generated <yyyy> <mm> <dd>\n"
- " get-series-number\n"
- " get-cpu-version\n"
- " get-rated\n"
- " get-status\n"
- " get-p-rated <id>\n"
- " id: Parallel machine ID\n"
- "\n"
- " get-p-status <id>\n"
- " id: Parallel machine ID\n"
- "\n"
- " get-mode\n"
- " get-errors\n"
- " get-flags\n"
- " get-rated-defaults\n"
- " get-allowed-charging-currents\n"
- " get-allowed-ac-charging-currents\n"
- " get-ac-charging-time\n"
- " get-ac-loads-supply-time\n"
- " set-loads-supply 0|1\n"
- " set-flag <flag> 0|1\n"
- " set-rated-defaults\n"
- " set-max-charging-current <id> <amps>\n"
- " id: Parallel machine ID (use 0 for single model)\n"
- " amps: Use get-allowed-charging-currents\n"
- " to see a list of allowed values.\n"
- "\n"
- " set-max-ac-charging-current <id> <amps>\n"
- " id: Parallel machine ID (use 0 for single model)\n"
- " amps: Use get-allowed-ac-charging-currents\n"
- " to see a list of allowed values.\n"
- "\n"
- " set-ac-output-freq 50|60\n"
- " set-max-charging-voltage <cv> <fv>\n"
- " cv: Constant voltage (48.0 ~ 58.4).\n"
- " fv: Float voltage (48.0 ~ 58.4).\n"
- "\n"
- " set-ac-output-voltage <v>\n"
- " v: " << p18::ac_output_rated_voltages << "\n"
- "\n"
- " set-output-source-priority SUB|SBU\n"
- " 'SUB' means " << p18::OutputSourcePriority::SolarUtilityBattery << "\n"
- " 'SBU' means " << p18::OutputSourcePriority::SolarBatteryUtility << "\n"
- "\n"
- " set-charging-thresholds <cv> <dv>\n"
- " Set battery re-charging and re-discharging voltages when\n"
- " utility is available.\n"
- "\n"
- " cv: re-charging voltage\n"
- " For 12 V unit: " << p18::bat_ac_recharging_voltages_12v << "\n"
- " For 24 V unit: " << p18::bat_ac_recharging_voltages_24v << "\n"
- " For 48 V unit: " << p18::bat_ac_recharging_voltages_48v << "\n"
- "\n"
- " dv: re-discharging voltage\n"
- " For 12 V unit: " << p18::bat_ac_redischarging_voltages_12v << "\n"
- " For 24 V unit: " << p18::bat_ac_redischarging_voltages_24v << "\n"
- " For 48 V unit: " << p18::bat_ac_redischarging_voltages_48v << "\n"
- "\n"
- " set-charging-source-priority <id> <priority>\n"
- " id: Parallel machine ID (use 0 for a single model)\n"
- " priority: SF|SU|S\n"
- " 'SF' means " << p18::ChargerSourcePriority::SolarFirst << ",\n"
- " 'SU' means " << p18::ChargerSourcePriority::SolarAndUtility << "\n"
- " 'S' means " << p18::ChargerSourcePriority::SolarOnly << "\n"
- "\n"
- " set-solar-power-priority BLU|LBU\n"
- " 'BLU' means " << p18::SolarPowerPriority::BatteryLoadUtility << "\n"
- " 'LBU' means " << p18::SolarPowerPriority::LoadBatteryUtility << "\n"
- "\n"
- " set-ac-input-voltage-range APPLIANCE|UPS\n"
- " set-battery-type AGM|FLOODED|USER\n"
- " set-output-model <id> <model>\n"
- " id: Parallel machine ID (use 0 for a single model)\n"
- " model: SM|P|P1|P2|P3\n"
- " SM: " << p18::OutputModelSetting::SingleModule << "\n"
- " P: " << p18::OutputModelSetting::ParallelOutput << "\n"
- " P1: " << p18::OutputModelSetting::Phase1OfThreePhaseOutput << "\n"
- " P2: " << p18::OutputModelSetting::Phase2OfThreePhaseOutput << "\n"
- " P3: " << p18::OutputModelSetting::Phase3OfThreePhaseOutput << "\n"
- "\n"
- " set-battery-cut-off-voltage <v>\n"
- " v: Cut-off voltage (40.0~48.0)\n"
- "\n"
- " set-solar-configuration <id>\n"
- " id: Serial number\n"
- "\n"
- " clear-generated-data\n"
- " Clear all recorded stats about generated energy.\n"
- "\n"
- " set-date-time <YYYY> <MM> <DD> <hh> <mm> <ss>\n"
- " YYYY: Year\n"
- " MM: Month\n"
- " DD: Day\n"
- " hh: Hours\n"
- " mm: Minutes\n"
- " ss: Seconds\n"
- "\n"
- " set-ac-charging-time <start> <end>\n"
- " start: Starting time, hh:mm format\n"
- " end: Ending time, hh:mm format\n"
- "\n"
- " set-ac-loads-supply-time <start> <end>\n"
- " start: Starting time, hh:mm format\n"
- " end: Ending time, hh:mm format\n"
- "\n"
- "Flags:\n";
- for (const p18::Flag& flag: p18::flags)
- std::cout << " " << flag.flag << ": " << flag.description << "\n";
+ "\n";
+
+ switch (p) {
+ case Protocol::P17: usage_p17(); break;
+ case Protocol::P18: usage_p18(); break;
+ }
+
std::cout <<
"\n"
"Formats:\n"
@@ -219,7 +266,7 @@ static void output_formatted_error(formatter::Format format, std::exception& e,
buf << s << ": ";
buf << e.what();
- auto err = p18::response_type::ErrorResponse(buf.str());
+ auto err = protocol::ErrorResponse(buf.str());
auto output = err.format(format);
if (format == formatter::Format::JSON) {
@@ -245,8 +292,9 @@ int main(int argc, char *argv[]) {
Action action = Action::Command;
u64 timeout = voltronic::Device::TIMEOUT;
bool verbose = false;
- p18::CommandType commandType;
+ int commandType;
std::vector<std::string> arguments;
+ Protocol protocol = Protocol::P18;
// format params
bool formatChanged = false;
@@ -273,6 +321,7 @@ int main(int argc, char *argv[]) {
{"help", no_argument, nullptr, LO_HELP},
{"verbose", no_argument, nullptr, LO_VERBOSE},
{"raw", required_argument, nullptr, LO_RAW},
+ {"protocol", required_argument, nullptr, LO_PROTOCOL},
{"timeout", required_argument, nullptr, LO_TIMEOUT},
{"format", required_argument, nullptr, LO_FORMAT},
{"device", required_argument, nullptr, LO_DEVICE},
@@ -287,7 +336,7 @@ int main(int argc, char *argv[]) {
};
bool getoptError = false; // FIXME
- while ((opt = getopt_long(argc, argv, "h", long_options, nullptr)) != EOF) {
+ while ((opt = getopt_long(argc, argv, "hp:", long_options, nullptr)) != EOF) {
if (opt == '?') {
getoptError = true;
break;
@@ -295,10 +344,26 @@ int main(int argc, char *argv[]) {
// simple options (flags), no arguments
switch (opt) {
- case 'h': action = Action::ShortHelp; continue;
- case LO_HELP: action = Action::FullHelp; continue;
- case LO_VERBOSE: verbose = true; continue;
- default: break;
+ case 'h':
+ action = Action::ShortHelp;
+ continue;
+
+ case 'p': {
+ std::string s(optarg);
+ protocol = protocol_from_string(s);
+ break;
+ }
+
+ case LO_HELP:
+ action = Action::FullHelp;
+ continue;
+
+ case LO_VERBOSE:
+ verbose = true;
+ continue;
+
+ default:
+ break;
}
// options with arguments
@@ -331,6 +396,10 @@ int main(int argc, char *argv[]) {
action = Action::Raw;
break;
+ case LO_PROTOCOL:
+ protocol = protocol_from_string(arg);
+ break;
+
case LO_TIMEOUT:
timeout = std::stoull(arg);
break;
@@ -408,7 +477,7 @@ int main(int argc, char *argv[]) {
break;
case Action::FullHelp:
- usage(argv[0]);
+ usage(argv[0], protocol);
break;
case Action::Command: {
@@ -417,8 +486,16 @@ int main(int argc, char *argv[]) {
std::string command = argv[optind++];
- p18::CommandInput input{argc, argv};
- commandType = p18::validate_input(command, arguments, (void*)&input);
+ protocol::CommandInput input{argc, argv};
+ switch (protocol) {
+ case Protocol::P17:
+ commandType = static_cast<int>(p17::validate_input(command, arguments, (void*)&input));
+ break;
+
+ case Protocol::P18:
+ commandType = static_cast<int>(p18::validate_input(command, arguments, (void*)&input));
+ break;
+ }
break;
}
@@ -457,6 +534,8 @@ int main(int argc, char *argv[]) {
break;
}
+ dev->setFlags(voltronic::FLAG_READ_CRC | voltronic::FLAG_VERIFY_CRC);
+
dev->setVerbose(verbose);
dev->setTimeout(timeout);
@@ -484,7 +563,7 @@ int main(int argc, char *argv[]) {
catch (voltronic::InvalidDataError& e) {
output_formatted_error(format, e, "data is invalid");
}
- catch (p18::InvalidResponseError& e) {
+ catch (protocol::InvalidResponseError& e) {
output_formatted_error(format, e, "response is invalid");
}