diff options
Diffstat (limited to 'src/inverterctl.cc')
-rw-r--r-- | src/inverterctl.cc | 343 |
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"); } |