summaryrefslogtreecommitdiff
path: root/src/protocol_18/input.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/protocol_18/input.cc')
-rw-r--r--src/protocol_18/input.cc341
1 files changed, 341 insertions, 0 deletions
diff --git a/src/protocol_18/input.cc b/src/protocol_18/input.cc
new file mode 100644
index 0000000..5647ee6
--- /dev/null
+++ b/src/protocol_18/input.cc
@@ -0,0 +1,341 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include "input.h"
+#include "defines.h"
+#include "functions.h"
+#include "../util.h"
+
+namespace p18 {
+
+using namespace protocol;
+
+const std::map<std::string, CommandType> client_commands = {
+ {"get-protocol-id", CommandType::GetProtocolID},
+ {"get-date-time", CommandType::GetCurrentTime},
+ {"get-total-generated", CommandType::GetTotalGenerated},
+ {"get-year-generated", CommandType::GetYearGenerated},
+ {"get-month-generated", CommandType::GetMonthGenerated},
+ {"get-day-generated", CommandType::GetDayGenerated},
+ {"get-series-number", CommandType::GetSeriesNumber},
+ {"get-cpu-version", CommandType::GetCPUVersion},
+ {"get-rated", CommandType::GetRatedInformation},
+ {"get-status", CommandType::GetGeneralStatus},
+ {"get-mode", CommandType::GetWorkingMode},
+ {"get-errors", CommandType::GetFaultsAndWarnings},
+ {"get-flags", CommandType::GetFlagsAndStatuses},
+ {"get-rated-defaults", CommandType::GetDefaults},
+ {"get-allowed-charging-currents", CommandType::GetAllowedChargingCurrents},
+ {"get-allowed-ac-charging-currents", CommandType::GetAllowedACChargingCurrents},
+ {"get-p-rated", CommandType::GetParallelRatedInformation},
+ {"get-p-status", CommandType::GetParallelGeneralStatus},
+ {"get-ac-charging-time", CommandType::GetACChargingTimeBucket},
+ {"get-ac-loads-supply-time", CommandType::GetACLoadsSupplyTimeBucket},
+ {"set-loads-supply", CommandType::SetLoads},
+ {"set-flag", CommandType::SetFlag},
+ {"set-rated-defaults", CommandType::SetDefaults},
+ {"set-max-charging-current", CommandType::SetBatteryMaxChargingCurrent},
+ {"set-max-ac-charging-current", CommandType::SetBatteryMaxACChargingCurrent},
+ {"set-ac-output-freq", CommandType::SetACOutputFreq},
+ {"set-max-charging-voltage", CommandType::SetBatteryMaxChargingVoltage},
+ {"set-ac-output-voltage", CommandType::SetACOutputRatedVoltage},
+ {"set-output-source-priority", CommandType::SetOutputSourcePriority},
+ {"set-charging-thresholds", CommandType::SetBatteryChargingThresholds}, /* Battery re-charging and re-discharging voltage when utility is available */
+ {"set-charging-source-priority", CommandType::SetChargingSourcePriority},
+ {"set-solar-power-priority", CommandType::SetSolarPowerPriority},
+ {"set-ac-input-voltage-range", CommandType::SetACInputVoltageRange},
+ {"set-battery-type", CommandType::SetBatteryType},
+ {"set-output-model", CommandType::SetOutputModel},
+ {"set-battery-cut-off-voltage", CommandType::SetBatteryCutOffVoltage},
+ {"set-solar-configuration", CommandType::SetSolarConfig},
+ {"clear-generated-data", CommandType::ClearGenerated},
+ {"set-date-time", CommandType::SetDateTime},
+ {"set-ac-charging-time", CommandType::SetACChargingTimeBucket},
+ {"set-ac-loads-supply-time", CommandType::SetACLoadsSupplyTimeBucket},
+};
+
+CommandType validate_input(std::string& command,
+ std::vector<std::string>& arguments,
+ void* input) {
+ auto it = client_commands.find(command);
+ if (it == client_commands.end())
+ throw std::invalid_argument("invalid command");
+
+ auto commandType = it->second;
+ switch (commandType) {
+ case CommandType::GetYearGenerated:
+ GET_ARGS(1);
+ validate_date_args(&arguments[0], nullptr, nullptr);
+ break;
+
+ case CommandType::GetMonthGenerated:
+ GET_ARGS(2);
+ validate_date_args(&arguments[0], &arguments[1], nullptr);
+ break;
+
+ case CommandType::GetDayGenerated:
+ GET_ARGS(3);
+ validate_date_args(&arguments[0], &arguments[1], &arguments[2]);
+ break;
+
+ case CommandType::GetParallelRatedInformation:
+ case CommandType::GetParallelGeneralStatus:
+ GET_ARGS(1);
+ if (!is_numeric(arguments[0]) || arguments[0].size() > 1)
+ throw std::invalid_argument("invalid argument");
+ break;
+
+ case 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 CommandType::SetFlag: {
+ GET_ARGS(2);
+
+ bool match_found = false;
+ for (auto const& item: 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 CommandType::SetBatteryMaxChargingCurrent:
+ case CommandType::SetBatteryMaxACChargingCurrent: {
+ GET_ARGS(2);
+
+ auto id = static_cast<unsigned>(std::stoul(arguments[0]));
+ auto amps = static_cast<unsigned>(std::stoul(arguments[1]));
+
+ if (!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 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 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 CommandType::SetACOutputRatedVoltage: {
+ GET_ARGS(1);
+
+ auto v = static_cast<unsigned>(std::stoul(arguments[0]));
+
+ bool matchFound = false;
+ for (const auto &item: ac_output_rated_voltages) {
+ if (v == item) {
+ matchFound = true;
+ break;
+ }
+ }
+
+ if (!matchFound)
+ throw std::invalid_argument("invalid voltage");
+
+ break;
+ }
+
+ case 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 CommandType::SetBatteryChargingThresholds: {
+ GET_ARGS(2);
+
+ float cv = std::stof(arguments[0]);
+ float dv = std::stof(arguments[1]);
+
+ if (index_of(bat_ac_recharging_voltages_12v, cv) == -1 &&
+ index_of(bat_ac_recharging_voltages_24v, cv) == -1 &&
+ index_of(bat_ac_recharging_voltages_48v, cv) == -1)
+ throw std::invalid_argument("invalid CV");
+
+ if (index_of(bat_ac_redischarging_voltages_12v, dv) == -1 &&
+ index_of(bat_ac_redischarging_voltages_24v, dv) == -1 &&
+ index_of(bat_ac_redischarging_voltages_48v, dv) == -1)
+ throw std::invalid_argument("invalid DV");
+
+ break;
+ }
+
+ case CommandType::SetChargingSourcePriority: {
+ GET_ARGS(2);
+
+ auto id = static_cast<unsigned>(std::stoul(arguments[0]));
+ if (!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 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 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 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 CommandType::SetOutputModel: {
+ GET_ARGS(2);
+
+ auto id = static_cast<unsigned>(std::stoul(arguments[0]));
+ if (!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 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 CommandType::SetSolarConfig: {
+ GET_ARGS(1);
+
+ if (!is_numeric(arguments[0]) || arguments[0].size() > 20)
+ throw std::invalid_argument("invalid argument");
+
+ break;
+ }
+
+ case 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 CommandType::SetACChargingTimeBucket:
+ case 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