1 #pragma once 2 3 #include <format> 4 #include <stdexcept> 5 #include <string> 6 7 namespace phosphor::modbus::rtu 8 { 9 10 enum class ModbusExceptionCode 11 { 12 // The Modbus function code in the request is not supported or is an invalid 13 // action for the server. 14 illegalFunctionCode = 1, 15 16 // The requested data address is not valid or authorized for the server. 17 illegalDataAddress = 2, 18 19 // The value provided in the request is not an allowable value for the 20 // server, or the data field is structured incorrectly. 21 illegalDataValue = 3, 22 23 // The server encountered an internal error and cannot perform the requested 24 // operation. 25 slaveDeviceFailure = 4, 26 27 // The server has accepted the request but needs more time to process it. 28 acknowledge = 5, 29 30 // The server is currently busy and cannot respond to the request. 31 slaveDeviceBusy = 6, 32 33 // The server cannot perform the program function received in the query. 34 // This code is returned for an unsuccessful programming request using 35 // function code 13 or 14 decimal. The client should request diagnostic or 36 // error information from the server. 37 negativeAcknowledge = 7, 38 39 // The server attempted to read extended memory, but detected a parity error 40 // in the memory. The client can retry the request, but service may be 41 // required on the server device. 42 memoryParityError = 8, 43 unknownError = 255, 44 }; 45 46 class ModbusException : public std::runtime_error 47 { 48 public: 49 const ModbusExceptionCode code; 50 ModbusException(uint8_t code,const std::string & message="")51 explicit ModbusException(uint8_t code, const std::string& message = "") : 52 std::runtime_error(std::format( 53 "{} ({})", toString(static_cast<ModbusExceptionCode>(code)), 54 message)), 55 code(static_cast<ModbusExceptionCode>(code)) 56 {} 57 toString(ModbusExceptionCode code)58 static auto toString(ModbusExceptionCode code) -> std::string 59 { 60 switch (code) 61 { 62 case ModbusExceptionCode::illegalFunctionCode: 63 return "Illegal Function Code"; 64 case ModbusExceptionCode::illegalDataAddress: 65 return "Illegal Data Address"; 66 case ModbusExceptionCode::illegalDataValue: 67 return "Illegal Data Value"; 68 case ModbusExceptionCode::slaveDeviceFailure: 69 return "Slave Device Failure"; 70 case ModbusExceptionCode::acknowledge: 71 return "Acknowledge"; 72 case ModbusExceptionCode::slaveDeviceBusy: 73 return "Slave Device Busy"; 74 case ModbusExceptionCode::negativeAcknowledge: 75 return "Negative Acknowledge"; 76 case ModbusExceptionCode::memoryParityError: 77 return "Memory Parity Error"; 78 default: 79 return "Unknown Modbus Error"; 80 } 81 } 82 }; 83 84 class ModbusCRCException : public std::runtime_error 85 { 86 public: ModbusCRCException(uint16_t expectedCRC,uint16_t crc)87 explicit ModbusCRCException(uint16_t expectedCRC, uint16_t crc) : 88 std::runtime_error( 89 "CRC mismatch, expected: " + std::to_string(expectedCRC) + 90 " received: " + std::to_string(crc)) 91 {} 92 }; 93 94 class ModbusBadResponseException : public std::runtime_error 95 { 96 public: ModbusBadResponseException(const std::string & fieldName,uint32_t expectedValue,uint32_t currentValue)97 explicit ModbusBadResponseException(const std::string& fieldName, 98 uint32_t expectedValue, 99 uint32_t currentValue) : 100 std::runtime_error( 101 "Value mismatch for " + fieldName + 102 ", expected value: " + std::to_string(expectedValue) + 103 ", current value: " + std::to_string(currentValue)) 104 {} 105 }; 106 107 } // namespace phosphor::modbus::rtu 108