diff options
Diffstat (limited to 'src/p18/commands.cc')
-rw-r--r-- | src/p18/commands.cc | 457 |
1 files changed, 0 insertions, 457 deletions
diff --git a/src/p18/commands.cc b/src/p18/commands.cc deleted file mode 100644 index 5060d49..0000000 --- a/src/p18/commands.cc +++ /dev/null @@ -1,457 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause - -#include <stdexcept> -#include <sstream> -#include <vector> -#include <string> - -#ifdef INVERTERCTL -#include <getopt.h> -#endif - -#include "commands.h" -#include "defines.h" -#include "functions.h" -#include "../util.h" -#include "../logging.h" - -namespace p18 { - -const std::map<std::string, p18::CommandType> client_commands = { - {"get-protocol-id", p18::CommandType::GetProtocolID}, - {"get-date-time", p18::CommandType::GetCurrentTime}, - {"get-total-generated", p18::CommandType::GetTotalGenerated}, - {"get-year-generated", p18::CommandType::GetYearGenerated}, - {"get-month-generated", p18::CommandType::GetMonthGenerated}, - {"get-day-generated", p18::CommandType::GetDayGenerated}, - {"get-series-number", p18::CommandType::GetSeriesNumber}, - {"get-cpu-version", p18::CommandType::GetCPUVersion}, - {"get-rated", p18::CommandType::GetRatedInformation}, - {"get-status", p18::CommandType::GetGeneralStatus}, - {"get-mode", p18::CommandType::GetWorkingMode}, - {"get-errors", p18::CommandType::GetFaultsAndWarnings}, - {"get-flags", p18::CommandType::GetFlagsAndStatuses}, - {"get-rated-defaults", p18::CommandType::GetDefaults}, - {"get-allowed-charging-currents", p18::CommandType::GetAllowedChargingCurrents}, - {"get-allowed-ac-charging-currents", p18::CommandType::GetAllowedACChargingCurrents}, - {"get-p-rated", p18::CommandType::GetParallelRatedInformation}, - {"get-p-status", p18::CommandType::GetParallelGeneralStatus}, - {"get-ac-charging-time", p18::CommandType::GetACChargingTimeBucket}, - {"get-ac-loads-supply-time", p18::CommandType::GetACLoadsSupplyTimeBucket}, - {"set-loads-supply", p18::CommandType::SetLoads}, - {"set-flag", p18::CommandType::SetFlag}, - {"set-rated-defaults", p18::CommandType::SetDefaults}, - {"set-max-charging-current", p18::CommandType::SetBatteryMaxChargingCurrent}, - {"set-max-ac-charging-current", p18::CommandType::SetBatteryMaxACChargingCurrent}, - {"set-ac-output-freq", p18::CommandType::SetACOutputFreq}, - {"set-max-charging-voltage", p18::CommandType::SetBatteryMaxChargingVoltage}, - {"set-ac-output-voltage", p18::CommandType::SetACOutputRatedVoltage}, - {"set-output-source-priority", p18::CommandType::SetOutputSourcePriority}, - {"set-charging-thresholds", p18::CommandType::SetBatteryChargingThresholds}, /* Battery re-charging and re-discharging voltage when utility is available */ - {"set-charging-source-priority", p18::CommandType::SetChargingSourcePriority}, - {"set-solar-power-priority", p18::CommandType::SetSolarPowerPriority}, - {"set-ac-input-voltage-range", p18::CommandType::SetACInputVoltageRange}, - {"set-battery-type", p18::CommandType::SetBatteryType}, - {"set-output-model", p18::CommandType::SetOutputModel}, - {"set-battery-cut-off-voltage", p18::CommandType::SetBatteryCutOffVoltage}, - {"set-solar-configuration", p18::CommandType::SetSolarConfig}, - {"clear-generated-data", p18::CommandType::ClearGenerated}, - {"set-date-time", p18::CommandType::SetDateTime}, - {"set-ac-charging-time", p18::CommandType::SetACChargingTimeBucket}, - {"set-ac-loads-supply-time", p18::CommandType::SetACLoadsSupplyTimeBucket}, -}; - -static void validate_date_args(const std::string* ys, const std::string* ms, const std::string* ds) { - static const std::string err_year = "invalid year"; - static const std::string err_month = "invalid month"; - static const std::string err_day = "invalid day"; - - int y, m = 0, d = 0; - - // validate year - if (!is_numeric(*ys) || ys->size() != 4) - throw std::invalid_argument(err_year); - - y = std::stoi(*ys); - if (y < 2000 || y > 2099) - throw std::invalid_argument(err_year); - - // validate month - if (ms != nullptr) { - if (!is_numeric(*ms) || ms->size() > 2) - throw std::invalid_argument(err_month); - - m = std::stoi(*ms); - if (m < 1 || m > 12) - throw std::invalid_argument(err_month); - } - - // validate day - if (ds != nullptr) { - if (!is_numeric(*ds) || ds->size() > 2) - throw std::invalid_argument(err_day); - - d = std::stoi(*ds); - if (d < 1 || d > 31) - throw std::invalid_argument(err_day); - } - - if (y != 0 && m != 0 && d != 0) { - if (!is_date_valid(y, m, d)) - throw std::invalid_argument("invalid date"); - } -} - -static void validate_time_args(const std::string* hs, const std::string* ms, const std::string* ss) { - static const std::string err_hour = "invalid hour"; - static const std::string err_minute = "invalid minute"; - static const std::string err_second = "invalid second"; - - unsigned h, m, s; - - if (!is_numeric(*hs) || hs->size() > 2) - throw std::invalid_argument(err_hour); - - h = static_cast<unsigned>(std::stoul(*hs)); - if (h > 23) - throw std::invalid_argument(err_hour); - - if (!is_numeric(*ms) || ms->size() > 2) - throw std::invalid_argument(err_minute); - - m = static_cast<unsigned>(std::stoul(*ms)); - if (m > 59) - throw std::invalid_argument(err_minute); - - if (!is_numeric(*ss) || ss->size() > 2) - throw std::invalid_argument(err_second); - - s = static_cast<unsigned>(std::stoul(*ss)); - if (s > 59) - throw std::invalid_argument(err_second); -} - - -#define GET_ARGS(__len__) get_args((CommandInput*)input, arguments, (__len__)) - -#ifdef INVERTERCTL -static void get_args(CommandInput* input, - std::vector<std::string>& arguments, - size_t count) { - for (size_t i = 0; i < count; i++) { - if (optind < input->argc && *input->argv[optind] != '-') - arguments.emplace_back(input->argv[optind++]); - else { - std::ostringstream error; - error << "this command requires " << count << " argument"; - if (count > 1) - error << "s"; - throw std::invalid_argument(error.str()); - } - } -} -#endif - -#ifdef INVERTERD -static void get_args(CommandInput* input, - std::vector<std::string>& arguments, - size_t count) { - if (input->argv->size() < count) { - std::ostringstream error; - error << "this command requires " << count << " argument"; - if (count > 1) - error << "s"; - throw std::invalid_argument(error.str()); - } - - for (size_t i = 0; i < count; i++) - arguments.emplace_back((*input->argv)[i]); -} -#endif - -p18::CommandType validate_input(std::string& command, - std::vector<std::string>& arguments, - void* input) { - auto it = p18::client_commands.find(command); - if (it == p18::client_commands.end()) - throw std::invalid_argument("invalid command"); - - auto commandType = it->second; - switch (commandType) { - case p18::CommandType::GetYearGenerated: - GET_ARGS(1); - validate_date_args(&arguments[0], nullptr, nullptr); - break; - - case p18::CommandType::GetMonthGenerated: - GET_ARGS(2); - validate_date_args(&arguments[0], &arguments[1], nullptr); - break; - - case p18::CommandType::GetDayGenerated: - GET_ARGS(3); - validate_date_args(&arguments[0], &arguments[1], &arguments[2]); - break; - - case p18::CommandType::GetParallelRatedInformation: - case p18::CommandType::GetParallelGeneralStatus: - GET_ARGS(1); - if (!is_numeric(arguments[0]) || arguments[0].size() > 1) - throw std::invalid_argument("invalid argument"); - break; - - case p18::CommandType::SetLoads: { - GET_ARGS(1); - std::string &arg = arguments[0]; - if (arg != "0" && arg != "1") - throw std::invalid_argument("invalid argument, only 0 or 1 allowed"); - break; - } - - case p18::CommandType::SetFlag: { - GET_ARGS(2); - - bool match_found = false; - for (auto const& item: p18::flags) { - if (arguments[0] == item.flag) { - arguments[0] = item.letter; - match_found = true; - break; - } - } - - if (!match_found) - throw std::invalid_argument("invalid flag"); - - if (arguments[1] != "0" && arguments[1] != "1") - throw std::invalid_argument("invalid flag state, only 0 or 1 allowed"); - - break; - } - - case p18::CommandType::SetBatteryMaxChargingCurrent: - case p18::CommandType::SetBatteryMaxACChargingCurrent: { - GET_ARGS(2); - - auto id = static_cast<unsigned>(std::stoul(arguments[0])); - auto amps = static_cast<unsigned>(std::stoul(arguments[1])); - - if (!p18::is_valid_parallel_id(id)) - throw std::invalid_argument("invalid id"); - - // 3 characters max - if (amps > 999) - throw std::invalid_argument("invalid amps"); - - break; - } - - case p18::CommandType::SetACOutputFreq: { - GET_ARGS(1); - std::string &freq = arguments[0]; - if (freq != "50" && freq != "60") - throw std::invalid_argument("invalid frequency, only 50 or 60 allowed"); - break; - } - - case p18::CommandType::SetBatteryMaxChargingVoltage: { - GET_ARGS(2); - - float cv = std::stof(arguments[0]); - float fv = std::stof(arguments[1]); - - if (cv < 48.0 || cv > 58.4) - throw std::invalid_argument("invalid CV"); - - if (fv < 48.0 || fv > 58.4) - throw std::invalid_argument("invalid FV"); - - break; - } - - case p18::CommandType::SetACOutputRatedVoltage: { - GET_ARGS(1); - - auto v = static_cast<unsigned>(std::stoul(arguments[0])); - - bool matchFound = false; - for (const auto &item: p18::ac_output_rated_voltages) { - if (v == item) { - matchFound = true; - break; - } - } - - if (!matchFound) - throw std::invalid_argument("invalid voltage"); - - break; - } - - case p18::CommandType::SetOutputSourcePriority: { - GET_ARGS(1); - - std::array<std::string, 2> priorities({"SUB", "SBU"}); - - long index = index_of(priorities, arguments[0]); - if (index == -1) - throw std::invalid_argument("invalid argument"); - - arguments[0] = std::to_string(index); - break; - } - - case p18::CommandType::SetBatteryChargingThresholds: { - GET_ARGS(2); - - float cv = std::stof(arguments[0]); - float dv = std::stof(arguments[1]); - - if (index_of(p18::bat_ac_recharging_voltages_12v, cv) == -1 && - index_of(p18::bat_ac_recharging_voltages_24v, cv) == -1 && - index_of(p18::bat_ac_recharging_voltages_48v, cv) == -1) - throw std::invalid_argument("invalid CV"); - - if (index_of(p18::bat_ac_redischarging_voltages_12v, dv) == -1 && - index_of(p18::bat_ac_redischarging_voltages_24v, dv) == -1 && - index_of(p18::bat_ac_redischarging_voltages_48v, dv) == -1) - throw std::invalid_argument("invalid DV"); - - break; - } - - case p18::CommandType::SetChargingSourcePriority: { - GET_ARGS(2); - - auto id = static_cast<unsigned>(std::stoul(arguments[0])); - if (!p18::is_valid_parallel_id(id)) - throw std::invalid_argument("invalid id"); - - std::array<std::string, 3> priorities({"SF", "SU", "S"}); - long index = index_of(priorities, arguments[1]); - if (index == -1) - throw std::invalid_argument("invalid argument"); - - arguments[1] = std::to_string(index); - break; - } - - case p18::CommandType::SetSolarPowerPriority: { - GET_ARGS(1); - - std::array<std::string, 2> allowed({"BLU", "LBU"}); - long index = index_of(allowed, arguments[0]); - if (index == -1) - throw std::invalid_argument("invalid priority"); - - arguments[0] = std::to_string(index); - break; - } - - case p18::CommandType::SetACInputVoltageRange: { - GET_ARGS(1); - std::array<std::string, 2> allowed({"APPLIANCE", "UPS"}); - long index = index_of(allowed, arguments[0]); - if (index == -1) - throw std::invalid_argument("invalid argument"); - arguments[0] = std::to_string(index); - break; - } - - case p18::CommandType::SetBatteryType: { - GET_ARGS(1); - - std::array<std::string, 3> allowed({"AGM", "FLOODED", "USER"}); - long index = index_of(allowed, arguments[0]); - if (index == -1) - throw std::invalid_argument("invalid type"); - arguments[0] = std::to_string(index); - - break; - } - - case p18::CommandType::SetOutputModel: { - GET_ARGS(2); - - auto id = static_cast<unsigned>(std::stoul(arguments[0])); - if (!p18::is_valid_parallel_id(id)) - throw std::invalid_argument("invalid id"); - - std::array<std::string, 5> allowed({"SM", "P", "P1", "P2", "P3"}); - long index = index_of(allowed, arguments[1]); - if (index == -1) - throw std::invalid_argument("invalid model"); - arguments[1] = std::to_string(index); - - break; - } - - case p18::CommandType::SetBatteryCutOffVoltage: { - GET_ARGS(1); - - float v = std::stof(arguments[0]); - if (v < 40.0 || v > 48.0) - throw std::invalid_argument("invalid voltage"); - - break; - } - - case p18::CommandType::SetSolarConfig: { - GET_ARGS(1); - - if (!is_numeric(arguments[0]) || arguments[0].size() > 20) - throw std::invalid_argument("invalid argument"); - - break; - } - - case p18::CommandType::SetDateTime: { - GET_ARGS(6); - - validate_date_args(&arguments[0], &arguments[1], &arguments[2]); - validate_time_args(&arguments[3], &arguments[4], &arguments[5]); - - break; - } - - case p18::CommandType::SetACChargingTimeBucket: - case p18::CommandType::SetACLoadsSupplyTimeBucket: { - GET_ARGS(2); - - std::vector<std::string> start = split(arguments[0], ':'); - if (start.size() != 2) - throw std::invalid_argument("invalid start time"); - - std::vector<std::string> end = split(arguments[1], ':'); - if (end.size() != 2) - throw std::invalid_argument("invalid end time"); - - auto startHour = static_cast<unsigned short>(std::stoul(start[0])); - auto startMinute = static_cast<unsigned short>(std::stoul(start[1])); - if (startHour > 23 || startMinute > 59) - throw std::invalid_argument("invalid start time"); - - auto endHour = static_cast<unsigned short>(std::stoul(end[0])); - auto endMinute = static_cast<unsigned short>(std::stoul(end[1])); - if (endHour > 23 || endMinute > 59) - throw std::invalid_argument("invalid end time"); - - arguments.clear(); - - arguments.emplace_back(std::to_string(startHour)); - arguments.emplace_back(std::to_string(startMinute)); - - arguments.emplace_back(std::to_string(endHour)); - arguments.emplace_back(std::to_string(endMinute)); - - break; - } - - default: - break; - } - - return commandType; -} - -}
\ No newline at end of file |