Skip to content

Commit

Permalink
add write multiple
Browse files Browse the repository at this point in the history
  • Loading branch information
markaren committed Sep 26, 2024
1 parent 6a3f2de commit 62e12a8
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 11 deletions.
2 changes: 2 additions & 0 deletions include/simple_socket/ModbusClient.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ namespace simple_socket {

bool write_single_register(uint16_t address, uint16_t value, uint8_t unit_id = 1);

bool ModbusClient::write_multiple_registers(uint16_t address, const std::vector<uint16_t>& values, uint8_t unitID = 1);

~ModbusClient();

private:
Expand Down
54 changes: 43 additions & 11 deletions src/simple_socket/ModusClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ namespace {
}

// The first 9 bytes are part of the MBAP header and function code
uint8_t byte_count = response[8];// The number of data bytes
const uint8_t byte_count = response[8];// The number of data bytes

// Check if the byte count matches the expected number of bytes
if (byte_count != count * 2) {
Expand All @@ -48,8 +48,8 @@ namespace {
// Extract the registers from the response
std::vector<uint16_t> registers;
for (size_t i = 0; i < count; ++i) {
uint16_t reg_value = (response[9 + i * 2] << 8) | response[9 + i * 2 + 1];// Combine high and low bytes
registers.push_back(reg_value);
const uint16_t reg_value = (response[9 + i * 2] << 8) | response[9 + i * 2 + 1];// Combine high and low bytes
registers.emplace_back(reg_value);
}

return registers;
Expand All @@ -60,8 +60,8 @@ namespace {
if (response.size() < 12) {
return false;
}
uint16_t resp_address = (response[8] << 8) | response[9];
uint16_t resp_value = (response[10] << 8) | response[11];
const uint16_t resp_address = (response[8] << 8) | response[9];
const uint16_t resp_value = (response[10] << 8) | response[11];
return resp_address == address && resp_value == value;
}

Expand Down Expand Up @@ -90,12 +90,12 @@ struct ModbusClient::Impl {
throw std::runtime_error("Failed to send Modbus request");
}

std::vector<uint8_t> response = receive_response();
std::vector<uint8_t> response = receive_response(count);
// Handle the response and extract register values
return parse_registers_response(response, count);
}

std::vector<uint8_t> receive_response() {
std::vector<uint8_t> receive_response(uint16_t count) {
std::vector<uint8_t> buffer(256);// Adjust buffer size based on expected response
const auto bytes_received = conn->read(buffer);
if (bytes_received < 0) {
Expand All @@ -107,26 +107,54 @@ struct ModbusClient::Impl {

bool write_single_register(uint16_t address, uint16_t value, uint8_t unitID) {
// Construct the data part (address + value) for the Modbus PDU
std::vector data {
std::vector data{
static_cast<unsigned char>((address >> 8) & 0xFF),// High byte of the address
static_cast<unsigned char>(address & 0xFF), // Low byte of the address
static_cast<unsigned char>((value >> 8) & 0xFF), // High byte of the value
static_cast<unsigned char>(value & 0xFF) // Low byte of the value
};

// Create the Modbus request
std::vector<uint8_t> request = makeRequest(next_transaction_id_++, unitID, 0x06, data);// 0x06 for Write Single Register
const auto request = makeRequest(next_transaction_id_++, unitID, 0x06, data);// 0x06 for Write Single Register

// Send request and handle the response
if (!conn->write(request)) {
return false;
}

std::vector<uint8_t> response = receive_response();
std::vector<uint8_t> response = receive_response(1);
// Validate the response (should echo the request)
validate_write_response(response, address, value);
return validate_write_response(response, address, value);
}

bool write_multiple_registers(uint16_t address, const std::vector<uint16_t>& values, uint8_t unitID) {
// Construct the data part for the Modbus PDU: address, number of registers, and values
std::vector data = {
static_cast<unsigned char>((address >> 8) & 0xFF), // High byte of the address
static_cast<unsigned char>(address & 0xFF), // Low byte of the address
static_cast<unsigned char>((values.size() >> 8) & 0xFF),// High byte of number of registers
static_cast<unsigned char>(values.size() & 0xFF), // Low byte of number of registers
static_cast<unsigned char>(values.size() * 2) // Byte count (2 bytes per register)
};

// Append register values (each register is 2 bytes)
for (const auto& value : values) {
data.emplace_back(static_cast<unsigned char>((value >> 8) & 0xFF));// High byte of value
data.emplace_back(static_cast<unsigned char>(value & 0xFF)); // Low byte of value
}

// Create the Modbus request
const auto request = makeRequest(next_transaction_id_++, unitID, 0x10, data);// 0x10 for Write Multiple Registers

// Send request and handle the response
if (!conn->write(request)) {
return false;
}

const auto response = receive_response(values.size());
// Validate the response (should echo the address and number of registers written)
return validate_write_response(response, address, values.size());
}

TCPClientContext ctx;
std::unique_ptr<SimpleConnection> conn;
Expand All @@ -146,4 +174,8 @@ bool ModbusClient::write_single_register(uint16_t address, uint16_t value, uint8
return pimpl_->write_single_register(address, value, unit_id);
}

bool ModbusClient::write_multiple_registers(uint16_t address, const std::vector<uint16_t>& values, uint8_t unitID) {
return pimpl_->write_multiple_registers(address, values, unitID);
}

ModbusClient::~ModbusClient() = default;

0 comments on commit 62e12a8

Please sign in to comment.