diff --git a/include/Modbus/BusList.h b/include/Modbus/BusList.h index a012266..17152b5 100644 --- a/include/Modbus/BusList.h +++ b/include/Modbus/BusList.h @@ -74,11 +74,20 @@ class WrongResponse : public std::runtime_error { exp_func, exp_address, called, address)) {} }; +/** + * Thrown when function error response (in Modbus, that's the function code | + * 0x80). Not thrown when the error handling function was provided + */ +class ErrorResponse : public std::runtime_error { +public: + ErrorResponse(uint8_t address, uint8_t func); +}; + /** * Error thrown when response action for the function received in response is * undefined. * - * @see BusList::addResponse + * @see BusList::add_response */ class UnexpectedResponse : public std::runtime_error { public: @@ -119,18 +128,13 @@ class ResponseRecord { /** * Construct callback entry. * - * @param _func Function code * @param _action Action to execute when function code is encountered - * @param _error_reply Error reply. That's usually 0x80 | _func * @param _error_action Error action */ - ResponseRecord(uint8_t _func, std::function _action, uint8_t _error_reply, - std::function _error_action) - : func(_func), action(_action), error_reply(_error_reply), error_action(_error_action) {} + ResponseRecord(std::function _action, std::function _error_action) + : action(_action), error_action(_error_action) {} - const uint8_t func; ///< sucessfull response function code std::function action; ///< action to call on sucessfull response - const uint8_t error_reply; ///< error response code std::function error_action; ///< action to call on the error response. Arguments ///< are address and error /< code received from ILC }; @@ -273,7 +277,7 @@ class BusList : public std::vector { * safe) disable the failing @glos{ILC}. * * @throw UnexpectedResponse Throwed when the bus list action for the - * address/function (set with the addResponse call) wasn't set. + * address/function (set with the add_response call) wasn't set. */ void parse(Parser parser); @@ -302,8 +306,10 @@ class BusList : public std::vector { * * @see checkCached */ - void addResponse(uint8_t func, std::function action, uint8_t error_reply, - std::function error_action = nullptr); + void add_response(uint8_t func, std::function action, + std::function error_action = nullptr); + + void set_error_response(uint8_t func, std::function error_action); ErrorRecord get_error_record(uint8_t address) { return _errors[address]; } @@ -314,7 +320,7 @@ class BusList : public std::vector { static constexpr uint8_t MODBUS_ERROR_MASK = 0x80; private: - std::list _functions; + std::map _functions; std::map _errors; diff --git a/include/cRIO/Application.h b/include/cRIO/Application.h index b7500df..610aeea 100644 --- a/include/cRIO/Application.h +++ b/include/cRIO/Application.h @@ -237,7 +237,7 @@ class Application { * Prints preamble for commands help. Can include tips which commands to * use,.. */ - virtual void printGenericHelp(){}; + virtual void printGenericHelp() {}; /** * Process option from command line parsing. diff --git a/include/cRIO/ModbusBuffer.h b/include/cRIO/ModbusBuffer.h index b467509..53c435f 100644 --- a/include/cRIO/ModbusBuffer.h +++ b/include/cRIO/ModbusBuffer.h @@ -411,13 +411,13 @@ class ModbusBuffer { * Called before responses are processed (before processXX methods are * called). */ - virtual void preProcess(){}; + virtual void preProcess() {}; /** * Called after responses are processed (after processXX methods are * called). */ - virtual void postProcess(){}; + virtual void postProcess() {}; /** * Thrown when an unknown response function is received. As unknown function diff --git a/include/cRIO/Task.h b/include/cRIO/Task.h index 6a81511..6b7b8c5 100644 --- a/include/cRIO/Task.h +++ b/include/cRIO/Task.h @@ -54,7 +54,7 @@ class Task { * * @param ex exception raised during processing */ - virtual void reportException(const std::exception &ex){}; + virtual void reportException(const std::exception &ex) {}; static constexpr task_return_t DONT_RESCHEDULE = 0xFFFFFFFF; diff --git a/src/ILC/ILCBusList.cpp b/src/ILC/ILCBusList.cpp index 767dda6..6fc0968 100644 --- a/src/ILC/ILCBusList.cpp +++ b/src/ILC/ILCBusList.cpp @@ -27,43 +27,37 @@ using namespace ILC; ILCBusList::ILCBusList(uint8_t bus) : _bus(bus) { - addResponse( - ILC_CMD::SERVER_ID, - [this](Modbus::Parser parser) { - uint8_t fnLen = parser.read(); - if (fnLen < 12) { - throw std::runtime_error(fmt::format( - "invalid ILC function 17 response length - expect at least 12, got {}", fnLen)); - } - fnLen -= 12; - - uint64_t uniqueID = parser.readU48(); - uint8_t ilcAppType = parser.read(); - uint8_t networkNodeType = parser.read(); - uint8_t ilcSelectedOptions = parser.read(); - uint8_t networkNodeOptions = parser.read(); - uint8_t majorRev = parser.read(); - uint8_t minorRev = parser.read(); - std::string fwName = parser.readString(fnLen); - parser.checkCRC(); - processServerID(parser.address(), uniqueID, ilcAppType, networkNodeType, ilcSelectedOptions, - networkNodeOptions, majorRev, minorRev, fwName); - }, - BusList::MODBUS_ERROR_MASK | ILC_CMD::SERVER_ID); - - addResponse( - ILC_CMD::SERVER_STATUS, - [this](Modbus::Parser parser) { - uint8_t mode = parser.read(); - uint16_t status = parser.read(); - uint16_t faults = parser.read(); - parser.checkCRC(); - _lastMode[parser.address()] = mode; - processServerStatus(parser.address(), mode, status, faults); - }, - BusList::MODBUS_ERROR_MASK | ILC_CMD::SERVER_STATUS); - - addResponse( + add_response(ILC_CMD::SERVER_ID, [this](Modbus::Parser parser) { + uint8_t fnLen = parser.read(); + if (fnLen < 12) { + throw std::runtime_error(fmt::format( + "invalid ILC function 17 response length - expect at least 12, got {}", fnLen)); + } + fnLen -= 12; + + uint64_t uniqueID = parser.readU48(); + uint8_t ilcAppType = parser.read(); + uint8_t networkNodeType = parser.read(); + uint8_t ilcSelectedOptions = parser.read(); + uint8_t networkNodeOptions = parser.read(); + uint8_t majorRev = parser.read(); + uint8_t minorRev = parser.read(); + std::string fwName = parser.readString(fnLen); + parser.checkCRC(); + processServerID(parser.address(), uniqueID, ilcAppType, networkNodeType, ilcSelectedOptions, + networkNodeOptions, majorRev, minorRev, fwName); + }); + + add_response(ILC_CMD::SERVER_STATUS, [this](Modbus::Parser parser) { + uint8_t mode = parser.read(); + uint16_t status = parser.read(); + uint16_t faults = parser.read(); + parser.checkCRC(); + _lastMode[parser.address()] = mode; + processServerStatus(parser.address(), mode, status, faults); + }); + + add_response( ILC_CMD::CHANGE_MODE, [this](Modbus::Parser parser) { uint16_t mode = parser.read(); @@ -71,28 +65,21 @@ ILCBusList::ILCBusList(uint8_t bus) : _bus(bus) { _lastMode[parser.address()] = mode; processChangeILCMode(parser.address(), mode); }, - BusList::MODBUS_ERROR_MASK | ILC_CMD::CHANGE_MODE, [this](uint8_t address, uint8_t error) { SPDLOG_WARN("Cannot change mode of ILC with address {0} - response {1} ({1:02x})", address, error); }); - addResponse( - ILC_CMD::SET_TEMP_ADDRESS, - [this](Modbus::Parser parser) { - uint8_t newAddress = parser.read(); - parser.checkCRC(); - processSetTempILCAddress(parser.address(), newAddress); - }, - BusList::MODBUS_ERROR_MASK | ILC_CMD::SET_TEMP_ADDRESS); + add_response(ILC_CMD::SET_TEMP_ADDRESS, [this](Modbus::Parser parser) { + uint8_t newAddress = parser.read(); + parser.checkCRC(); + processSetTempILCAddress(parser.address(), newAddress); + }); - addResponse( - ILC_CMD::RESET_SERVER, - [this](Modbus::Parser parser) { - parser.checkCRC(); - processResetServer(parser.address()); - }, - BusList::MODBUS_ERROR_MASK | ILC_CMD::RESET_SERVER); + add_response(ILC_CMD::RESET_SERVER, [this](Modbus::Parser parser) { + parser.checkCRC(); + processResetServer(parser.address()); + }); } ILCBusList::~ILCBusList() {} diff --git a/src/ILC/SensorMonitor.cpp b/src/ILC/SensorMonitor.cpp index baaf6f5..21143d5 100644 --- a/src/ILC/SensorMonitor.cpp +++ b/src/ILC/SensorMonitor.cpp @@ -29,22 +29,19 @@ using namespace ILC; SensorMonitor::SensorMonitor(uint8_t bus) : ILCBusList(bus) { - addResponse( - SENSOR_VALUES, - [this](Modbus::Parser parser) { - std::vector values; - // there should be 2 bytes (address, function), 4 bytes floats and 2 bytes CRC - so the size() - // shall be multiple of 4 - if (parser.size() % 4 != 0) { - throw std::runtime_error( - fmt::format("Invalid reponse length - expected 4*x, received {}", parser.size())); - } + add_response(SENSOR_VALUES, [this](Modbus::Parser parser) { + std::vector values; + // there should be 2 bytes (address, function), 4 bytes floats and 2 bytes CRC - so the size() + // shall be multiple of 4 + if (parser.size() % 4 != 0) { + throw std::runtime_error( + fmt::format("Invalid reponse length - expected 4*x, received {}", parser.size())); + } - for (int i = 1; i < static_cast(parser.size()) / 4; i++) { - values.push_back(parser.read()); - } + for (int i = 1; i < static_cast(parser.size()) / 4; i++) { + values.push_back(parser.read()); + } - processSensorValues(parser.address(), values); - }, - SENSOR_VALUES | MODBUS_ERROR_MASK); + processSensorValues(parser.address(), values); + }); } diff --git a/src/LSST/cRIO/ElectromechanicalPneumaticILC.cpp b/src/LSST/cRIO/ElectromechanicalPneumaticILC.cpp index e2a7502..dd4adb7 100644 --- a/src/LSST/cRIO/ElectromechanicalPneumaticILC.cpp +++ b/src/LSST/cRIO/ElectromechanicalPneumaticILC.cpp @@ -99,26 +99,24 @@ ElectromechanicalPneumaticILC::ElectromechanicalPneumaticILC(uint8_t bus) : ILC: processMezzaninePressure(parser.address(), primaryPush, primaryPull, secondaryPush, secondaryPull); }; - addResponse(ILC_EM_CMD::SET_STEPPER_STEPS, stepperForceStatus, 194); + add_response(ILC_EM_CMD::SET_STEPPER_STEPS, stepperForceStatus); - addResponse(ILC_EM_CMD::STEPPER_FORCE_STATUS, stepperForceStatus, 195); + add_response(ILC_EM_CMD::STEPPER_FORCE_STATUS, stepperForceStatus); - addResponse( - ILC_EM_CMD::SET_DCA_GAIN, [this](Modbus::Parser parser) { parser.checkCRC(); }, 201); + add_response(ILC_EM_CMD::SET_DCA_GAIN, [this](Modbus::Parser parser) { parser.checkCRC(); }); - addResponse(ILC_EM_CMD::REPORT_DCA_GAIN, dcaGain, 202); + add_response(ILC_EM_CMD::REPORT_DCA_GAIN, dcaGain); - addResponse(ILC_EM_CMD::SET_FORCE_OFFSET, forceActuatorForceStatus, 210); + add_response(ILC_EM_CMD::SET_FORCE_OFFSET, forceActuatorForceStatus); - addResponse(ILC_EM_CMD::REPORT_FA_FORCE_STATUS, forceActuatorForceStatus, 220); + add_response(ILC_EM_CMD::REPORT_FA_FORCE_STATUS, forceActuatorForceStatus); - addResponse( - ILC_EM_CMD::SET_OFFSET_AND_SENSITIVITY, [this](Modbus::Parser parser) { parser.checkCRC(); }, - 235); + add_response(ILC_EM_CMD::SET_OFFSET_AND_SENSITIVITY, + [this](Modbus::Parser parser) { parser.checkCRC(); }); - addResponse(ILC_EM_CMD::REPORT_CALIBRATION_DATA, calibrationData, 238); + add_response(ILC_EM_CMD::REPORT_CALIBRATION_DATA, calibrationData); - addResponse(ILC_EM_CMD::REPORT_MEZZANINE_PRESSURE, pressureData, 247); + add_response(ILC_EM_CMD::REPORT_MEZZANINE_PRESSURE, pressureData); - addResponse(ILC_EM_CMD::REPORT_HARDPOINT_LVDT, hardpointLVDT, 250); + add_response(ILC_EM_CMD::REPORT_HARDPOINT_LVDT, hardpointLVDT); } diff --git a/src/LSST/cRIO/FPGACliApp.cpp b/src/LSST/cRIO/FPGACliApp.cpp index 7a768a2..108bbd4 100644 --- a/src/LSST/cRIO/FPGACliApp.cpp +++ b/src/LSST/cRIO/FPGACliApp.cpp @@ -44,10 +44,8 @@ FPGACliApp::FPGACliApp(const char* name, const char* description) "Temporary disable given ILC in * commands"); addILCCommand("@enable", std::bind(&FPGACliApp::enableILC, this, std::placeholders::_1), "Re-enable given ILC in * commands"); - addILCCommand( - "info", [](ILCUnit u) { u.first->reportServerID(u.second); }, "Print ILC info"); - addILCCommand( - "status", [](ILCUnit u) { u.first->reportServerStatus(u.second); }, "Print ILC status"); + addILCCommand("info", [](ILCUnit u) { u.first->reportServerID(u.second); }, "Print ILC info"); + addILCCommand("status", [](ILCUnit u) { u.first->reportServerStatus(u.second); }, "Print ILC status"); addILCCommand( "standby", [](ILCUnit u) { u.first->changeILCMode(u.second, ILC::Mode::Standby); }, "Change ILC mode to standby"); @@ -63,8 +61,7 @@ FPGACliApp::FPGACliApp(const char* name, const char* description) addILCCommand( "clear-faults", [](ILCUnit u) { u.first->changeILCMode(u.second, ILC::Mode::ClearFaults); }, "Clear ILC faults"); - addILCCommand( - "reset", [](ILCUnit u) { u.first->resetServer(u.second); }, "Reset server"); + addILCCommand("reset", [](ILCUnit u) { u.first->resetServer(u.second); }, "Reset server"); addCommand("program-ilc", std::bind(&FPGACliApp::programILC, this, std::placeholders::_1), "FS?", NEED_FPGA, " ", "Program ILC with new firmware."); diff --git a/src/LSST/cRIO/MPU.cpp b/src/LSST/cRIO/MPU.cpp index 3df44fb..64b61f6 100644 --- a/src/LSST/cRIO/MPU.cpp +++ b/src/LSST/cRIO/MPU.cpp @@ -30,107 +30,93 @@ using namespace LSST::cRIO; MPU::MPU(uint8_t node_address) : _bus(0), _node_address(node_address) { - addResponse( - READ_INPUT_STATUS, - [this](Modbus::Parser parser) { - auto commanded = _commanded_info.front(); - _commanded_info.pop_front(); - - if (commanded.address == 0 || commanded.length == 0) { - throw std::runtime_error("Empty read input status"); - } - if (parser.address() != _node_address) { - throw std::runtime_error(fmt::format("Invalid ModBus address {}, expected {}", - parser.address(), _node_address)); - } - uint8_t len = parser.read(); - uint8_t data = 0x00; - if (commanded.length / 8 + (commanded.length % 8 == 0 ? 0 : 1) != len) { - throw std::runtime_error( - fmt::format("Invalid reply length - received {}, ceiling from {} / 8", len, - commanded.length)); - } - for (uint16_t i = 0; i < commanded.length; i++) { - if (i % 8 == 0) { - data = parser.read(); - } - _inputStatus[commanded.address + i] = data & 0x01; - data >>= 1; - } - parser.checkCRC(); - }, - 0x82); - - addResponse( - READ_HOLDING_REGISTERS, - [this](Modbus::Parser parser) { - auto commanded = _commanded_info.front(); - _commanded_info.pop_front(); - - if (parser.address() != _node_address) { - throw std::runtime_error(fmt::format("Invalid ModBus address {}, expected {}", - parser.address(), _node_address)); - } - uint8_t len = parser.read() / 2; - { - std::lock_guard lg(_registerMutex); - for (size_t i = 0; i < len; i++) { - uint16_t val = parser.read(); - _registers[commanded.address + i] = val; - } - } - parser.checkCRC(); - }, - 0x83); - - addResponse( - PRESET_HOLDING_REGISTER, - [this](Modbus::Parser parser) { - auto commanded = _commanded_info.front(); - _commanded_info.pop_front(); - - if (parser.address() != _node_address) { - throw std::runtime_error(fmt::format("Invalid ModBus address {}, expected {}", - parser.address(), _node_address)); - } - uint16_t reg = parser.read(); - uint16_t value = parser.read(); - if (reg != commanded.address) { - throw std::runtime_error( - fmt::format("Invalid register {:04x}, expected {:04x}", reg, commanded.address)); - } - { - std::lock_guard lg(_registerMutex); - _registers[commanded.address] = value; - } - parser.checkCRC(); - }, - 0x86); - - addResponse( - PRESET_HOLDING_REGISTERS, - [this](Modbus::Parser parser) { - auto commanded = _commanded_info.front(); - _commanded_info.pop_front(); - - if (parser.address() != _node_address) { - throw std::runtime_error(fmt::format("Invalid ModBus address {}, expected {}", - parser.address(), _node_address)); - } - uint16_t reg = parser.read(); - uint16_t len = parser.read(); - if (reg != commanded.address) { - throw std::runtime_error( - fmt::format("Invalid register {:04x}, expected {:04x}", reg, commanded.address)); - } - if (len != commanded.length) { - throw std::runtime_error( - fmt::format("Invalid length - register {:04x}, length {}, expected {}", reg, len, - commanded.length)); - } - parser.checkCRC(); - }, - 0x90); + add_response(READ_INPUT_STATUS, [this](Modbus::Parser parser) { + auto commanded = _commanded_info.front(); + _commanded_info.pop_front(); + + if (commanded.address == 0 || commanded.length == 0) { + throw std::runtime_error("Empty read input status"); + } + if (parser.address() != _node_address) { + throw std::runtime_error( + fmt::format("Invalid ModBus address {}, expected {}", parser.address(), _node_address)); + } + uint8_t len = parser.read(); + uint8_t data = 0x00; + if (commanded.length / 8 + (commanded.length % 8 == 0 ? 0 : 1) != len) { + throw std::runtime_error(fmt::format("Invalid reply length - received {}, ceiling from {} / 8", + len, commanded.length)); + } + for (uint16_t i = 0; i < commanded.length; i++) { + if (i % 8 == 0) { + data = parser.read(); + } + _inputStatus[commanded.address + i] = data & 0x01; + data >>= 1; + } + parser.checkCRC(); + }); + + add_response(READ_HOLDING_REGISTERS, [this](Modbus::Parser parser) { + auto commanded = _commanded_info.front(); + _commanded_info.pop_front(); + + if (parser.address() != _node_address) { + throw std::runtime_error( + fmt::format("Invalid ModBus address {}, expected {}", parser.address(), _node_address)); + } + uint8_t len = parser.read() / 2; + { + std::lock_guard lg(_registerMutex); + for (size_t i = 0; i < len; i++) { + uint16_t val = parser.read(); + _registers[commanded.address + i] = val; + } + } + parser.checkCRC(); + }); + + add_response(PRESET_HOLDING_REGISTER, [this](Modbus::Parser parser) { + auto commanded = _commanded_info.front(); + _commanded_info.pop_front(); + + if (parser.address() != _node_address) { + throw std::runtime_error( + fmt::format("Invalid ModBus address {}, expected {}", parser.address(), _node_address)); + } + uint16_t reg = parser.read(); + uint16_t value = parser.read(); + if (reg != commanded.address) { + throw std::runtime_error( + fmt::format("Invalid register {:04x}, expected {:04x}", reg, commanded.address)); + } + { + std::lock_guard lg(_registerMutex); + _registers[commanded.address] = value; + } + parser.checkCRC(); + }); + + add_response(PRESET_HOLDING_REGISTERS, [this](Modbus::Parser parser) { + auto commanded = _commanded_info.front(); + _commanded_info.pop_front(); + + if (parser.address() != _node_address) { + throw std::runtime_error( + fmt::format("Invalid ModBus address {}, expected {}", parser.address(), _node_address)); + } + uint16_t reg = parser.read(); + uint16_t len = parser.read(); + if (reg != commanded.address) { + throw std::runtime_error( + fmt::format("Invalid register {:04x}, expected {:04x}", reg, commanded.address)); + } + if (len != commanded.length) { + throw std::runtime_error(fmt::format("Invalid length - register {:04x}, length {}, expected {}", + reg, len, commanded.length)); + } + parser.checkCRC(); + }); } int MPU::responseLength(const std::vector &response) { diff --git a/src/LSST/cRIO/PrintILC.cpp b/src/LSST/cRIO/PrintILC.cpp index 8d445cf..f17e81a 100644 --- a/src/LSST/cRIO/PrintILC.cpp +++ b/src/LSST/cRIO/PrintILC.cpp @@ -32,25 +32,19 @@ using namespace LSST::cRIO; PrintILC::PrintILC(uint8_t bus) : ILCBusList(bus), _printout(0), _lastAddress(0) { - addResponse( - ILC_CLI_CMD::WRITE_APPLICATION_STATS, - [this](Modbus::Parser parser) { processWriteApplicationStats(parser.address()); }, 228); - - addResponse( - ILC_CLI_CMD::ERASE_APPLICATION, - [this](Modbus::Parser parser) { processEraseILCApplication(parser.address()); }, 229); - - addResponse( - ILC_CLI_CMD::WRITE_APPLICATION_PAGE, - [this](Modbus::Parser parser) { processWriteApplicationPage(parser.address()); }, 238); - - addResponse( - ILC_CLI_CMD::WRITE_VERIFY_APPLICATION, - [this](Modbus::Parser parser) { - uint16_t status = parser.read(); - processVerifyUserApplication(parser.address(), status); - }, - 231); + add_response(ILC_CLI_CMD::WRITE_APPLICATION_STATS, + [this](Modbus::Parser parser) { processWriteApplicationStats(parser.address()); }); + + add_response(ILC_CLI_CMD::ERASE_APPLICATION, + [this](Modbus::Parser parser) { processEraseILCApplication(parser.address()); }); + + add_response(ILC_CLI_CMD::WRITE_APPLICATION_PAGE, + [this](Modbus::Parser parser) { processWriteApplicationPage(parser.address()); }); + + add_response(ILC_CLI_CMD::WRITE_VERIFY_APPLICATION, [this](Modbus::Parser parser) { + uint16_t status = parser.read(); + processVerifyUserApplication(parser.address(), status); + }); } void PrintILC::writeApplicationStats(uint8_t address, uint16_t dataCRC, uint16_t startAddress, diff --git a/src/LSST/cRIO/ThermalILC.cpp b/src/LSST/cRIO/ThermalILC.cpp index 5ceaad2..ea7080e 100644 --- a/src/LSST/cRIO/ThermalILC.cpp +++ b/src/LSST/cRIO/ThermalILC.cpp @@ -41,14 +41,13 @@ ThermalILC::ThermalILC(uint8_t bus) : ILC::ILCBusList(bus) { processReHeaterGains(parser.address(), proportionalGain, integralGain); }; - addResponse(ILC_THERMAL_CMD::SET_THERMAL_DEMAND, thermalStatus, 216); + add_response(ILC_THERMAL_CMD::SET_THERMAL_DEMAND, thermalStatus); - addResponse(ILC_THERMAL_CMD::REPORT_THERMAL_STATUS, thermalStatus, 217); + add_response(ILC_THERMAL_CMD::REPORT_THERMAL_STATUS, thermalStatus); - addResponse( - ILC_THERMAL_CMD::SET_REHEATER_GAINS, [this](Modbus::Parser parser) { parser.checkCRC(); }, 220); + add_response(ILC_THERMAL_CMD::SET_REHEATER_GAINS, [this](Modbus::Parser parser) { parser.checkCRC(); }); - addResponse(ILC_THERMAL_CMD::REPORT_REHEATER_GAINS, reheaterGains, 221); + add_response(ILC_THERMAL_CMD::REPORT_REHEATER_GAINS, reheaterGains); } std::vector ThermalILC::getStatusString(uint16_t status) { diff --git a/src/Modbus/BusList.cpp b/src/Modbus/BusList.cpp index 5ea2967..2471482 100644 --- a/src/Modbus/BusList.cpp +++ b/src/Modbus/BusList.cpp @@ -51,6 +51,11 @@ void ErrorRecord::reset() { error_count = 0; } +ErrorResponse::ErrorResponse(uint8_t address, uint8_t func) + : std::runtime_error( + fmt::format("Error response - address {0}. response {1} ({1:02x}), function {2} ({2:02x})", + address, func, func & ~BusList::MODBUS_ERROR_MASK)) {} + BusList::BusList() {} int BusList::responseLength(const std::vector &response) { return -1; } @@ -73,34 +78,28 @@ void BusList::parse(Parser parser) { throw wr; } - for (auto func_record : _functions) { - if (func_record.func == called) { - func_record.action(parser); + if (called & MODBUS_ERROR_MASK) { + auto func = _functions.at(called & ~MODBUS_ERROR_MASK); + if (func.error_action != nullptr) { + func.error_action(address, called); _parsed_index++; - return; - } - - if (func_record.error_reply == called) { - uint8_t error = parser.read(); - parser.checkCRC(); - bool new_error = _errors[address].record(called, error); - - if (func_record.error_action != nullptr) { - func_record.error_action(address, error); - } else { - if (new_error) { - SPDLOG_WARN("Error reply from - function {} ({}), address {}", called, func_record.func, - address); - } - } + } else { _parsed_index++; - return; + throw ErrorResponse(address, called); } + } else { + _functions.at(called).action(parser); + _parsed_index++; } - throw UnexpectedResponse(address, called); + + // throw UnexpectedResponse(address, called); +} + +void BusList::add_response(uint8_t func, std::function action, + std::function error_action) { + _functions.emplace(func, ResponseRecord(action, error_action)); } -void BusList::addResponse(uint8_t func, std::function action, uint8_t error_reply, - std::function error_action) { - _functions.emplace(_functions.end(), ResponseRecord(func, action, error_reply, error_action)); +void BusList::set_error_response(uint8_t func, std::function error_action) { + _functions.at(func).error_action = error_action; } diff --git a/tests/test_ILCBusList.cpp b/tests/test_ILCBusList.cpp index bfc6543..50adb79 100644 --- a/tests/test_ILCBusList.cpp +++ b/tests/test_ILCBusList.cpp @@ -383,7 +383,7 @@ TEST_CASE("Error response", "[ILC]") { Modbus::Buffer mbuf(std::vector({103, 145, 3})); mbuf.writeCRC(); - CHECK_THROWS_AS(ilc.parse(mbuf), Modbus::WrongResponse); + CHECK_THROWS_AS(ilc.parse(mbuf), Modbus::ErrorResponse); CHECK(ilc.responseUniqueID == 0); Modbus::Buffer mbuf_ok; diff --git a/tests/test_Modbus_BusList.cpp b/tests/test_Modbus_BusList.cpp index bc646ba..9e8cc1c 100644 --- a/tests/test_Modbus_BusList.cpp +++ b/tests/test_Modbus_BusList.cpp @@ -36,18 +36,15 @@ class TestList : public BusList { }; TestList::TestList(uint8_t _expectedAddress) : expectedAddress(_expectedAddress) { - addResponse( - 3, - [this](Modbus::Parser parser) { - CHECK(parser.func() == 3); - CHECK(parser.read() == 6); - uint16_t reg1 = parser.read(); - uint16_t reg2 = parser.read(); - uint16_t reg3 = parser.read(); - CHECK_NOTHROW(parser.checkCRC()); - processReadRegister(parser.address(), reg1, reg2, reg3); - }, - 131); + add_response(3, [this](Modbus::Parser parser) { + CHECK(parser.func() == 3); + CHECK(parser.read() == 6); + uint16_t reg1 = parser.read(); + uint16_t reg2 = parser.read(); + uint16_t reg3 = parser.read(); + CHECK_NOTHROW(parser.checkCRC()); + processReadRegister(parser.address(), reg1, reg2, reg3); + }); } void TestList::processReadRegister(uint8_t address, uint16_t reg1, uint16_t reg2, uint16_t reg3) { @@ -115,7 +112,7 @@ TEST_CASE("Call function, parser return", "[Parsing]") { TEST_CASE("Call 10 functions, parser return", "[Parsing]") { TestList buslist(1); - auto generateReply = [](uint8_t address) -> std::vector { + auto generate_reply = [](uint8_t address) -> std::vector { Buffer mbuf(std::vector({address, 0x03, 0x06, 0xAE, 0x41, 0x56, 0x52, 0x43, 0x40})); mbuf.writeCRC(); return mbuf; @@ -127,14 +124,14 @@ TEST_CASE("Call 10 functions, parser return", "[Parsing]") { for (int address = 1; address < 10; address++) { buslist.expectedAddress = address; - CHECK_NOTHROW(buslist.parse(generateReply(address))); + CHECK_NOTHROW(buslist.parse(generate_reply(address))); } } TEST_CASE("Missing response", "[BusListErrors]") { TestList buslist(1); - auto generateReply = [](uint8_t address) -> std::vector { + auto generate_reply = [](uint8_t address) -> std::vector { Buffer mbuf(std::vector({address, 0x03, 0x06, 0xAE, 0x41, 0x56, 0x52, 0x43, 0x40})); mbuf.writeCRC(); return mbuf; @@ -146,14 +143,14 @@ TEST_CASE("Missing response", "[BusListErrors]") { for (uint8_t address = 1; address < 10; address++) { buslist.expectedAddress = address; - CHECK_NOTHROW(buslist.parse(generateReply(address))); + CHECK_NOTHROW(buslist.parse(generate_reply(address))); } buslist.reset(); for (uint8_t address = 1; address < 10; address++) { buslist.expectedAddress = address; - CHECK_THROWS_AS(buslist.parse(generateReply(address + 1)), WrongResponse); + CHECK_THROWS_AS(buslist.parse(generate_reply(address + 1)), WrongResponse); } buslist.reset(); @@ -161,25 +158,76 @@ TEST_CASE("Missing response", "[BusListErrors]") { // test MissingResponse is thrown properly in expected processing sequences buslist.expectedAddress = 1; - CHECK_THROWS_AS(buslist.parse(generateReply(2)), WrongResponse); + CHECK_THROWS_AS(buslist.parse(generate_reply(2)), WrongResponse); buslist.expectedAddress = 2; - CHECK_NOTHROW(buslist.parse(generateReply(2))); + CHECK_NOTHROW(buslist.parse(generate_reply(2))); buslist.expectedAddress = 3; - CHECK_NOTHROW(buslist.parse(generateReply(3))); + CHECK_NOTHROW(buslist.parse(generate_reply(3))); buslist.expectedAddress = 4; - CHECK_NOTHROW(buslist.parse(generateReply(4))); + CHECK_NOTHROW(buslist.parse(generate_reply(4))); buslist.expectedAddress = 5; - CHECK_THROWS_AS(buslist.parse(generateReply(7)), WrongResponse); + CHECK_THROWS_AS(buslist.parse(generate_reply(7)), WrongResponse); buslist.expectedAddress = 6; - CHECK_THROWS_AS(buslist.parse(generateReply(7)), WrongResponse); + CHECK_THROWS_AS(buslist.parse(generate_reply(7)), WrongResponse); buslist.expectedAddress = 7; - CHECK_NOTHROW(buslist.parse(generateReply(7))); + CHECK_NOTHROW(buslist.parse(generate_reply(7))); buslist.expectedAddress = 8; - CHECK_NOTHROW(buslist.parse(generateReply(8))); + CHECK_NOTHROW(buslist.parse(generate_reply(8))); buslist.expectedAddress = 9; - CHECK_NOTHROW(buslist.parse(generateReply(9))); + CHECK_NOTHROW(buslist.parse(generate_reply(9))); buslist.expectedAddress = 9; - CHECK_THROWS_AS(buslist.parse(generateReply(10)), std::out_of_range); + CHECK_THROWS_AS(buslist.parse(generate_reply(10)), std::out_of_range); +} + +TEST_CASE("Modbus error response", "[ModbusError]") { + TestList buslist(1); + + auto generate_reply = [](uint8_t address) -> std::vector { + Buffer mbuf(std::vector({address, 0x03, 0x06, 0xAE, 0x41, 0x56, 0x52, 0x43, 0x40})); + mbuf.writeCRC(); + return mbuf; + }; + + auto generate_error_reply = [](uint8_t address) -> std::vector { + Buffer mbuf(std::vector({address, 0x83, 0x01})); + mbuf.writeCRC(); + return mbuf; + }; + + for (uint8_t address = 1; address < 10; address++) { + buslist.callFunction(address, 3, 200, static_cast(0x1234), static_cast(0x0003)); + } + + for (uint8_t address = 1; address < 10; address++) { + buslist.expectedAddress = address; + CHECK_THROWS_AS(buslist.parse(generate_error_reply(address)), ErrorResponse); + } + + buslist.reset(); + + for (uint8_t address = 1; address < 10; address++) { + buslist.expectedAddress = address; + if (address & 0x01) { + CHECK_THROWS_AS(buslist.parse(generate_error_reply(address)), ErrorResponse); + } else { + CHECK_NOTHROW(buslist.parse(generate_reply(address))); + } + } + + uint8_t expected_address = 0; + + buslist.set_error_response(0x03, [&expected_address](uint8_t address, uint8_t called) -> void { + CHECK(address == expected_address); + CHECK(called == 0x83); + }); + + buslist.reset(); + + for (uint8_t address = 1; address < 10; address++) { + buslist.expectedAddress = address; + expected_address = address; + CHECK_NOTHROW(buslist.parse(generate_error_reply(address))); + } } TEST_CASE("Response length calculations", "[ResponseLength]") {