diff --git a/README.md b/README.md index 704f3b7..9f40cd5 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # modbus-cpp -A TCP / RTU modbus library written in c++ as a header-only. +The goal was to write a TCP / RTU modbus library written in c++ as a header-only, but reality quickly followed suit. +To avoid large implementations in the header file and create a mess, I quickly decided to write it more conventional. + + diff --git a/src/modbusbase.cpp b/src/modbusbase.cpp index 210798c..e3bd4bc 100644 --- a/src/modbusbase.cpp +++ b/src/modbusbase.cpp @@ -7,4 +7,154 @@ #include "modbusbase.h" +int ModbusBase::readCoils(uint16_t address, uint16_t amount, bool *buffer) +{ + +} + +int ModbusBase::readInputBits(uint16_t address, uint16_t amount, bool *buffer) +{ + +} + +int ModbusBase::readHoldingRegisters(uint16_t address, uitn16_t amount, uint16_t *buffer) +{ + +} + +int ModbusBase::readInputRegisters(uint16_t address, uint16_t amount, uint16_t *buffer) +{ + +} + +int ModbusBase::writeCoil(uint16_t address, const bool &to_write) +{ + +} + +int ModbusBase::writeRegister(uint16_t address, const uint16_t &value) +{ + +} + +int ModbusBase::writeCoils(uint16_t address, uint16_t amount, const bool *value) +{ + +} + +int ModbusBase::writeRegisters(uint16_t address, uint16_t amount, const uint16_t *value) +{ + +} + +void ModbusBase::buildRequest(uint8_t *to_send, uint16_t address, int function_code) const +{ + to_send[0] = (uint8_t)(m_msg_id >> 8u); + to_send[1] = (uint8_t)(m_msg_id & 0x00FFu); + to_send[2] = 0; + to_send[3] = 0; + to_send[4] = 0; + to_send[6] = (uint8_t)m_slaveId; + to_send[7] = (uint8_t)function_code; + to_send[8] = (uint8_t)(address >> 8u); + to_send[9] = (uint8_t)(address & 0x00FFu); +} + +int ModbusBase::modbusRead(uint16_t address, uint16_t amount, int function_code) +{ + // TODO: Building the frames should be dependant on the chosen transport layer.. ( 256 for RTU, 260 for TCP ) + // Declare as pure virtual and implement in the transport-specific class? + // For now we focus on TCP as it is easier to implement. + uint8_t to_send[12]; + buildRequest(to_send, address, function_code); + to_send[5] = 6; + to_send[10] = (uint8_t) + } +} + +int ModbusBase::modbusWrite(uint16_t address, uint16_t amount, int function_code, const uint16_t *value) +{ + // TODO: Building the frames should be dependant on the chosen transport layer.. ( 256 for RTU, 260 for TCP ) + // Declare as pure virtual and implement in the transport-specific class? + // For now we focus on TCP as it is easier to implement. + int status = 0; + uint8_t *to_send; + + switch (function_code) + { + // Intentionally fall-through + case WRITE_COIL: + case WRITE_REG: + { + to_send = new uint8_t[12]; + buildRequest(to_send, address, function_code); + to_send[5] = 6; + to_send[10] = (uint8_t)(value[0] >> 8u); + to_send[11] = (uint8_t)(value[0] & 0x00FFu); + status = modbusSend(to_send, 12); + break; + } + case WRITE_REGS: + { + to_send = new uint8_t[13 + 2 * amount]; + buildRequest(to_send, address, function_code); + to_send[5] = (uint8_t)(7 + 2 * amount); + to_send[10] = (uint8_t)(amount >> 8u); + to_send[11] = (uint8_t)(amount & 0x00FFu); + to_send[12] = (uint8_t)(2 * amount); + for (int i = 0; i < amount; i++) + { + to_send[13 + 2 * i] = (uint8_t)(value[i] >> 8u); + to_send[14 + 2 * i] = (uint8_t)(value[i] & 0x00FFu); + } + status = modbusSend(to_send, 13 + 2 * amount); + break; + } + case WRITE_COILS: + { + to_send = new uint8_t[14 + ( amount - 1 ) / 8]; + buildRequest(to_send, address, function_code); + to_send[5] = (uint8_t)(7 + ( amount + 7 ) / 8); + to_send[10] = (uint8_t)(amount >> 8u); + to_send[11] = (uint8_t)(amount & 0x00FFu); + to_send[12] = (uint8_t)((amount + 7) / 8); + for (int i = 0; i < (amount + 7) / 8; i++) + { + to_send[13 + i] = 0 // Init needed before summing. + } + for (int i = 0; i < amount; i++) + { + to_send[13 + i / 8] += (uint8_t)(value[i] << (i % 8u)); + } + status = modbusSend(to_send, 13 + (amount - 1) / 8); + } + } + delete[] to_send; + return status; +} + +ssize_t ModbusBase::modbusSend(uint8_t *to_send, size_t length) +{ + +} + +ssize_t ModbusBase::modbusReceive(uint8_t *buffer) const +{ + +} + +void ModbusBase::modbusErrorHandle(const uint8_t *msg, int function_code) +{ + +} + +void ModbusBase::setBadConnection() +{ + +} + +void ModbusBase::setBadInput() +{ + +} diff --git a/src/modbusbase.h b/src/modbusbase.h index 583ead5..6b7af77 100644 --- a/src/modbusbase.h +++ b/src/modbusbase.h @@ -55,7 +55,11 @@ public: ModbusBase(); virtual ~ModbusBase(); - void setSlaveId(int slave_id); + /*! + * Set slave id for this context + * \param slave_id - The slave id this system is known under. + */ + void setSlaveId(int slave_id) { m_slaveId = slave_id; } // Pure virtuals. Override when inherited. virtual bool Connect() const = 0; @@ -74,11 +78,26 @@ public: int writeRegisters(uint16_t address, uint16_t amount, const uint16_t *value); private: // Methods + /*! + * Modbus Request Builder + * \param to_send - Message buffer to be send + * \param address - Reference Address + * \param function_code - Modbus Functional Code + */ void buildRequest(uint8_t *to_send, uint16_t address, int function_code) const; int modbusRead(uint16_t address, uint16_t amount, int function_code); + /*! + * Write Request Builder and Sender + * \param address - Reference address + * \param amount - Amount of data to be written + * \param function_code - Modbus Functional Code + * \param value - Data to be written + * + * \return int + */ int modbusWrite(uint16_t address, uint16_t amount, int function_code, const uint16_t *value); - ssize_t modbusSend(uint8_t *to_send, size_t length); - ssize_t modbusReceive(uint8_t *buffer) const; + virtual ssize_t modbusSend(uint8_t *to_send, size_t length) = 0; + virtual ssize_t modbusReceive(uint8_t *buffer) const = 0; void modbusErrorHandle(const uint8_t *msg, int function_code); void setBadConnection();