Skip to content

Instantly share code, notes, and snippets.

@fernandoc1
Created July 20, 2016 21:20
Show Gist options
  • Save fernandoc1/25eee61378b0c190d9a4e3b6d2028818 to your computer and use it in GitHub Desktop.
Save fernandoc1/25eee61378b0c190d9a4e3b6d2028818 to your computer and use it in GitHub Desktop.
modbus server with bit pooling.
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <modbus/modbus.h>
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
#include <vector>
#include <cstdio>
#include <cstdlib>
class ModbusAgent
{
modbus_t* context;
std::mutex poolRegisterMutex;
std::thread* poolThread;
bool pooling;
template <typename T> int checkVectorSize(int initialPosition, int finalPosition, std::vector<T>& values)
{
int expectedSize = finalPosition - initialPosition;
if(values.size() != expectedSize)
{
values.resize(expectedSize);
}
return expectedSize;
}
void poolingBitThread(int position)
{
uint8_t lastReadValue = 0;
while(pooling)
{
uint8_t regValue = 0;
if(modbus_flush(this->context) != 0)
{
throw std::runtime_error("Flush pooling register failed");
}
int numOfRegistersRead = modbus_read_bits(this->context, position, 1, &regValue);
if(numOfRegistersRead == 1)
{
if(lastReadValue != regValue)
{
std::cout << "Value changed to " << (int)regValue << std::endl;
lastReadValue = regValue;
}
}
else
{
throw std::runtime_error("Pooling register failed");
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
}
void poolingRegisterThread(int position)
{
uint16_t lastReadValue = 0;
while(pooling)
{
uint16_t regValue = 0;
if(modbus_flush(this->context) != 0)
{
throw std::runtime_error("Flush pooling register failed");
}
int numOfRegistersRead = modbus_read_registers(this->context, position, 1, &regValue);
if(numOfRegistersRead == 1)
{
if(lastReadValue != regValue)
{
std::cout << "Value changed to " << regValue << std::endl;
lastReadValue = regValue;
}
}
else
{
throw std::runtime_error("Pooling register failed");
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
public:
ModbusAgent(std::string ip, uint16_t port)
: context(modbus_new_tcp(ip.c_str(), port))
, pooling(true)
, poolThread(NULL)
{
if(modbus_connect(this->context) == -1)
{
throw std::runtime_error("Error while connecting to Modbus module");
}
}
~ModbusAgent()
{
modbus_close(this->context);
modbus_free(this->context);
}
int readRegisters(int initialPosition, int finalPosition, std::vector<uint16_t>& values)
{
checkVectorSize(initialPosition, finalPosition, values);
return modbus_read_registers(this->context, initialPosition, finalPosition, values.data());
}
int readBits(int initialPosition, int finalPosition, std::vector<uint8_t>& values)
{
checkVectorSize(initialPosition, finalPosition, values);
return modbus_read_bits(this->context, initialPosition, finalPosition, values.data());
}
int readInputBits(int initialPosition, int finalPosition, std::vector<uint8_t>& values)
{
checkVectorSize(initialPosition, finalPosition, values);
return modbus_read_input_bits(this->context, initialPosition, finalPosition, values.data());
}
virtual void poolRegister(int position)
{
if(this->poolThread == NULL)
{
//std::thread t(poolingRegisterThread);//&ModbusAgent::poolingRegisterThread, this);
this->poolThread = new std::thread(&ModbusAgent::poolingRegisterThread, this, position);
}
}
virtual void poolBit(int position)
{
if(this->poolThread == NULL)
{
this->poolThread = new std::thread(&ModbusAgent::poolingBitThread, this, position);
}
}
void waitPooling()
{
if(this->poolThread != NULL)
{
this->poolThread->join();
}
}
void stopPooling()
{
pooling = false;
}
};
int main()
{
ModbusAgent mbus("127.0.0.1", 1502);
int numberOfRegs = 1;
//std::vector<uint16_t> regs(numberOfRegs);
std::vector<uint8_t> regs(numberOfRegs);
//mbus.readRegisters(0, numberOfRegs, regs);
mbus.readBits(0, numberOfRegs, regs);
for(int i = 0; i < regs.size(); i++)
{
std::cout << "[" << i << "] " << (int)regs[i] << std::endl;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment