diff options
author | Evgeny Zinoviev <me@ch1p.io> | 2021-06-07 01:40:32 +0300 |
---|---|---|
committer | Evgeny Zinoviev <me@ch1p.io> | 2021-12-02 04:05:15 +0300 |
commit | 3aed59276c2b7275603f6da18377b77718948667 (patch) | |
tree | 86816d82ab02b6e4761175d599f5749490706792 /src/protocol_18/client.cc | |
parent | d86ca1e596b094cba101e0e3e6c8cdb71f8116e9 (diff) |
wipp17
Diffstat (limited to 'src/protocol_18/client.cc')
-rw-r--r-- | src/protocol_18/client.cc | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/src/protocol_18/client.cc b/src/protocol_18/client.cc new file mode 100644 index 0000000..d42c24a --- /dev/null +++ b/src/protocol_18/client.cc @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#include <memory> +#include <utility> +#include <sstream> +#include <iomanip> +#include <cmath> +#include <stdexcept> + +#include "client.h" +#include "types.h" +#include "defines.h" +#include "../protocol/exceptions.h" +#include "response.h" +#include "../voltronic/crc.h" + +#define MKRESPONSE(type) std::shared_ptr<response_type::BaseResponse>(new response_type::type(raw, rawSize)) + +#define RESPONSE_CASE(type) \ + case CommandType::Get ## type: \ + response = MKRESPONSE(type); \ + break; \ + + +namespace p18 { + +std::shared_ptr<response_type::BaseResponse> Client::execute(int commandType, std::vector<std::string>& arguments) { + auto type = static_cast<CommandType>(commandType); + + std::ostringstream buf; + buf << std::setfill('0'); + + bool isSetCommand = commandType >= 100; + + auto pos = raw_commands.find(type); + if (pos == raw_commands.end()) + throw std::runtime_error("packedCommand " + std::to_string(commandType) + " not found"); + + std::string packedCommand = pos->second; + std::string packedArguments = packArguments(type, arguments); + + size_t len = sizeof(voltronic::CRC) + 1 + packedCommand.size() + packedArguments.size(); + + buf << "^"; + buf << (isSetCommand ? "S" : "P"); + buf << std::setw(3) << len; + buf << packedCommand; + buf << packedArguments; + + std::string packed = buf.str(); + + auto result = runOnDevice(packed); + std::shared_ptr<response_type::BaseResponse> response; + + const auto raw = result.first; + const auto rawSize = result.second; + + switch (type) { + RESPONSE_CASE(ProtocolID) + RESPONSE_CASE(CurrentTime) + RESPONSE_CASE(TotalGenerated) + RESPONSE_CASE(YearGenerated) + RESPONSE_CASE(MonthGenerated) + RESPONSE_CASE(DayGenerated) + RESPONSE_CASE(SeriesNumber) + RESPONSE_CASE(CPUVersion) + RESPONSE_CASE(RatedInformation) + RESPONSE_CASE(GeneralStatus) + RESPONSE_CASE(WorkingMode) + RESPONSE_CASE(FaultsAndWarnings) + RESPONSE_CASE(FlagsAndStatuses) + RESPONSE_CASE(Defaults) + RESPONSE_CASE(AllowedChargingCurrents) + RESPONSE_CASE(AllowedACChargingCurrents) + RESPONSE_CASE(ParallelRatedInformation) + RESPONSE_CASE(ParallelGeneralStatus) + RESPONSE_CASE(ACChargingTimeBucket) + RESPONSE_CASE(ACLoadsSupplyTimeBucket) + + case CommandType::SetLoads: + case CommandType::SetFlag: + case CommandType::SetDefaults: + case CommandType::SetBatteryMaxChargingCurrent: + case CommandType::SetBatteryMaxACChargingCurrent: + case CommandType::SetACOutputFreq: + case CommandType::SetBatteryMaxChargingVoltage: + case CommandType::SetACOutputRatedVoltage: + case CommandType::SetOutputSourcePriority: + case CommandType::SetBatteryChargingThresholds: + case CommandType::SetChargingSourcePriority: + case CommandType::SetSolarPowerPriority: + case CommandType::SetACInputVoltageRange: + case CommandType::SetBatteryType: + case CommandType::SetOutputModel: + case CommandType::SetBatteryCutOffVoltage: + case CommandType::SetSolarConfig: + case CommandType::ClearGenerated: + case CommandType::SetDateTime: + case CommandType::SetACChargingTimeBucket: + case CommandType::SetACLoadsSupplyTimeBucket: + response = MKRESPONSE(SetResponse); + break; + } + + if (!response->validate()) + throw protocol::InvalidResponseError("validate() failed"); + + response->unpack(); + return std::move(response); +} + +std::string Client::packArguments(p18::CommandType commandType, std::vector<std::string>& arguments) { + std::ostringstream buf; + buf << std::setfill('0'); + + switch (commandType) { + case CommandType::GetYearGenerated: + case CommandType::SetOutputSourcePriority: + case CommandType::SetSolarPowerPriority: + case CommandType::SetACInputVoltageRange: + case CommandType::SetBatteryType: + case CommandType::SetLoads: + buf << arguments[0]; + break; + + case CommandType::GetMonthGenerated: + case CommandType::GetDayGenerated: + buf << arguments[0]; + for (int i = 1; i <= (commandType == CommandType::GetMonthGenerated ? 1 : 2); i++) + buf << std::setw(2) << std::stoi(arguments[i]); + break; + + case CommandType::GetParallelGeneralStatus: + case CommandType::GetParallelRatedInformation: + buf << std::stoi(arguments[0]); + break; + + case CommandType::SetFlag: + buf << (arguments[1] == "1" ? "E" : "D"); + buf << arguments[0]; + break; + + case CommandType::SetBatteryMaxChargingCurrent: + case CommandType::SetBatteryMaxACChargingCurrent: + buf << arguments[0] << ","; + buf << std::setw(3) << std::stoi(arguments[1]); + break; + + case CommandType::SetACOutputFreq: + buf << std::setw(2) << std::stoi(arguments[0]); + break; + + case CommandType::SetBatteryMaxChargingVoltage: + case CommandType::SetBatteryChargingThresholds: { + for (int i = 0; i < 2; i++) { + double val = std::stod(arguments[i]); + buf << std::setw(3) << (int)round(val*10); + if (i == 0) + buf << ","; + } + break; + } + + case CommandType::SetACOutputRatedVoltage: { + buf << std::setw(4) << (std::stoi(arguments[0])*10); + break; + } + + case CommandType::SetChargingSourcePriority: + case CommandType::SetOutputModel: + buf << arguments[0] << "," << arguments[1]; + break; + + case CommandType::SetBatteryCutOffVoltage: { + double v = std::stod(arguments[0]); + buf << std::setw(3) << ((int)round(v*10)); + break; + } + + case CommandType::SetSolarConfig: { + size_t len = arguments[0].size(); + buf << std::setw(2) << len << arguments[0]; + if (len < 20) { + for (int i = 0; i < 20-len; i++) + buf << "0"; + } + break; + } + + case CommandType::SetDateTime: { + for (int i = 0; i < 6; i++) { + int val = std::stoi(arguments[i]); + if (i == 0) + val -= 2000; + buf << std::setw(2) << val; + } + break; + } + + case CommandType::SetACChargingTimeBucket: + case CommandType::SetACLoadsSupplyTimeBucket: + for (int i = 0; i < 4; i++) { + buf << std::setw(2) << std::stoi(arguments[i]); + if (i == 1) + buf << ","; + } + break; + + default: + break; + } + + return buf.str(); +} + +}
\ No newline at end of file |