Commit 67691e43 authored by Pavel Vainerman's avatar Pavel Vainerman

(ModbusSlave): добавил поддержку "контроля mbfunc".

Теперь для MBSlave разрешены одинаковые регистры для разных mbfunc. Но это нужно включать аргументом --prefix-check-mbfunc 1
parent 566c96f1
......@@ -472,24 +472,6 @@ bool MBExchange::checkPoll( bool wrFunc )
return true;
}
// -----------------------------------------------------------------------------
MBExchange::RegID MBExchange::genRegID( const ModbusRTU::ModbusData mbreg, const int fn )
{
// формула для вычисления ID
// требования:
// 1. ID > диапазона возможных регистров
// 2. одинаковые регистры, но разные функции должны давать разный ID
// 3. регистры идущие подряд, должна давать ID идущие тоже подряд
// Вообще диапазоны:
// mbreg: 0..65535
// fn: 0...255
int max = numeric_limits<ModbusRTU::ModbusData>::max(); // по идее 65535
int fn_max = numeric_limits<ModbusRTU::ModbusByte>::max(); // по идее 255
// fn необходимо привести к диапазону 0..max
return max + mbreg + max + UniSetTypes::lcalibrate(fn, 0, fn_max, 0, max, false);
}
// ------------------------------------------------------------------------------------------
void MBExchange::printMap( MBExchange::RTUDeviceMap& m )
{
cout << "devices: " << endl;
......@@ -566,7 +548,7 @@ void MBExchange::rtuQueryOptimization( RTUDeviceMap& m )
for( auto it = d->regmap.begin(); it != d->regmap.end(); ++it )
{
auto beg = it;
RegID id = it->second->id; // или собственно it->first
ModbusRTU::RegID id = it->second->id; // или собственно it->first
beg->second->q_num = 1;
beg->second->q_count = 1;
++it;
......@@ -2000,7 +1982,7 @@ MBExchange::RTUDevice* MBExchange::addDev( RTUDeviceMap& mp, ModbusRTU::ModbusAd
return d;
}
// ------------------------------------------------------------------------------------------
MBExchange::RegInfo* MBExchange::addReg( RegMap& mp, RegID id, ModbusRTU::ModbusData r,
MBExchange::RegInfo* MBExchange::addReg( RegMap& mp, ModbusRTU::RegID id, ModbusRTU::ModbusData r,
UniXML::iterator& xmlit, MBExchange::RTUDevice* dev )
{
auto it = mp.find(id);
......@@ -2332,7 +2314,7 @@ bool MBExchange::initItem( UniXML::iterator& it )
// требования:
// - ID > диапазона возможных регитров
// - разные функции должны давать разный ID
RegID rID = genRegID(mbreg, fn);
ModbusRTU::RegID rID = ModbusRTU::genRegID(mbreg, fn);
RegInfo* ri = addReg(dev->regmap, rID, mbreg, it, dev);
......@@ -2424,7 +2406,7 @@ bool MBExchange::initItem( UniXML::iterator& it )
for( auto i = 1; i < p1->rnum; i++ )
{
RegID id1 = genRegID(mbreg + i, ri->mbfunc);
ModbusRTU::RegID id1 = ModbusRTU::genRegID(mbreg + i, ri->mbfunc);
RegInfo* r = addReg(dev->regmap, id1, mbreg + i, it, dev);
r->q_num = i + 1;
r->q_count = 1;
......
......@@ -93,9 +93,7 @@ class MBExchange:
typedef std::list<RSProperty> PList;
static std::ostream& print_plist( std::ostream& os, const PList& p );
typedef unsigned long RegID;
typedef std::map<RegID, RegInfo*> RegMap;
typedef std::map<ModbusRTU::RegID, RegInfo*> RegMap;
struct RegInfo
{
// т.к. RSProperty содержит rwmutex с запрещённым конструктором копирования
......@@ -117,7 +115,7 @@ class MBExchange:
ModbusRTU::ModbusData mbreg; /*!< регистр */
ModbusRTU::SlaveFunctionCode mbfunc; /*!< функция для чтения/записи */
PList slst;
RegID id;
ModbusRTU::RegID id;
RTUDevice* dev;
......@@ -204,8 +202,6 @@ class MBExchange:
void printMap(RTUDeviceMap& d);
// ----------------------------------
static RegID genRegID( const ModbusRTU::ModbusData r, const int fn );
enum Timer
{
tmExchange
......@@ -276,7 +272,7 @@ class MBExchange:
void initOffsetList();
RTUDevice* addDev( RTUDeviceMap& dmap, ModbusRTU::ModbusAddr a, UniXML::iterator& it );
RegInfo* addReg( RegMap& rmap, RegID id, ModbusRTU::ModbusData r, UniXML::iterator& it, RTUDevice* dev );
RegInfo* addReg( RegMap& rmap, ModbusRTU::RegID id, ModbusRTU::ModbusData r, UniXML::iterator& it, RTUDevice* dev );
RSProperty* addProp( PList& plist, RSProperty&& p );
bool initMTRitem( UniXML::iterator& it, RegInfo* p );
......
......@@ -304,6 +304,7 @@ class MBSlave:
int nbyte; /*!< номер байта, который надо "сохранить" из "пришедщего в запросе" слова. [1-2] */
bool rawdata; /*!< флаг, что в SM просто сохраняются 4-байта (актуально для типа F4)*/
std::shared_ptr<BitRegProperty> bitreg; /*!< указатель, как признак является ли данный регистр "сборным" из битовых */
ModbusRTU::RegID regID;
IOProperty():
mbreg(0),
......@@ -311,7 +312,8 @@ class MBSlave:
vtype(VTypes::vtUnknown),
wnum(0),
nbyte(0),
rawdata(false)
rawdata(false),
regID(0)
{}
friend std::ostream& operator<<( std::ostream& os, IOProperty& p );
......@@ -404,7 +406,7 @@ class MBSlave:
// т.к. в функциях (much_real_read,nuch_real_write) рассчёт на отсортированность IOMap
// то использовать unordered_map нельзя
typedef std::map<ModbusRTU::ModbusData, IOProperty> IOMap;
typedef std::map<ModbusRTU::RegID, IOProperty> IOMap;
IOMap iomap; /*!< список входов/выходов */
std::shared_ptr<ModbusServerSlot> mbslot;
......@@ -413,6 +415,7 @@ class MBSlave:
xmlNode* cnode;
std::string s_field;
std::string s_fvalue;
int default_mbfunc={0}; // функция по умолчанию, для вычисления RegID
std::shared_ptr<SMInterface> shm;
......@@ -437,17 +440,16 @@ class MBSlave:
void readConfiguration();
bool check_item( UniXML::iterator& it );
ModbusRTU::mbErrCode real_write( ModbusRTU::ModbusData reg, ModbusRTU::ModbusData val );
ModbusRTU::mbErrCode real_write( ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int& i, int count );
ModbusRTU::mbErrCode real_read( ModbusRTU::ModbusData reg, ModbusRTU::ModbusData& val );
ModbusRTU::mbErrCode much_real_read( ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int count );
ModbusRTU::mbErrCode much_real_write( ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int count );
ModbusRTU::mbErrCode real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData val, const int fn=0 );
ModbusRTU::mbErrCode real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int& i, int count, const int fn=0 );
ModbusRTU::mbErrCode real_read( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData& val, const int fn=0 );
ModbusRTU::mbErrCode much_real_read( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int count, const int fn=0 );
ModbusRTU::mbErrCode much_real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int count, const int fn=0 );
ModbusRTU::mbErrCode real_read_it( IOMap::iterator& it, ModbusRTU::ModbusData& val );
ModbusRTU::mbErrCode real_bitreg_read_it( std::shared_ptr<BitRegProperty>& bp, ModbusRTU::ModbusData& val );
ModbusRTU::mbErrCode real_read_prop( IOProperty* p, ModbusRTU::ModbusData& val );
ModbusRTU::mbErrCode real_write_it( IOMap::iterator& it, ModbusRTU::ModbusData* dat, int& i, int count );
ModbusRTU::mbErrCode real_bitreg_write_it( std::shared_ptr<BitRegProperty>& bp, const ModbusRTU::ModbusData val );
ModbusRTU::mbErrCode real_write_prop( IOProperty* p, ModbusRTU::ModbusData* dat, int& i, int count );
......@@ -482,7 +484,8 @@ class MBSlave:
timeout_t wait_msec;
bool force; /*!< флаг означающий, что надо сохранять в SM, даже если значение не менялось */
bool mbregFromID;
bool mbregFromID={0};
bool checkMBFunc={0};
typedef std::unordered_map<int, std::string> FileList;
FileList flist;
......
......@@ -454,7 +454,7 @@ TEST_CASE("(0x10): write register outputs or memories", "[modbus][mbslave][mbtcp
}
}
TEST_CASE("Read(0x03,0x04): vtypes..", "[modbus][mbslave][mbtcpslave]")
TEST_CASE("Read(0x03,0x04): vtypes..", "[modbus][mbslave][mbread][mbtcpslave]")
{
using namespace VTypes;
InitTest();
......@@ -475,6 +475,7 @@ TEST_CASE("Read(0x03,0x04): vtypes..", "[modbus][mbslave][mbtcpslave]")
REQUIRE( (int)i2 == -100000 );
}
}
#if 0
SECTION("Test: read vtype 'I2r'")
{
ModbusRTU::ModbusData tREG = 102;
......@@ -603,6 +604,7 @@ TEST_CASE("Read(0x03,0x04): vtypes..", "[modbus][mbslave][mbtcpslave]")
REQUIRE( (unsigned short)b == 200 );
}
}
#endif
}
// -------------------------------------------------------------
......
......@@ -74,6 +74,17 @@ namespace ModbusRTU
// 21 ...65535 RESERVED
};
typedef unsigned long RegID;
/*! Получение уникального ID (hash?) на основе номера функции и регистра
* Требования к данной функции:
* 1. ID > диапазона возможных регистров (>65535)
* 2. одинаковые регистры, но разные функции должны давать разный ID
* 3. регистры идущие подряд, должны давать ID идущие тоже подряд
*/
RegID genRegID( const ModbusRTU::ModbusData r, const int fn );
// определение размера данных в зависимости от типа сообщения
// возвращает -1 - если динамический размер сообщения или размер неизвестен
int szRequestDiagnosticData( DiagnosticsSubFunction f );
......
#include <assert.h>
#include <string>
#include <iostream>
#include <limits>
#include <sstream>
#include <iomanip>
#include "modbus/ModbusTypes.h"
......@@ -3558,3 +3559,15 @@ std::string ModbusRTU::rdi2str( int id )
return s.str();
}
// -----------------------------------------------------------------------
ModbusRTU::RegID ModbusRTU::genRegID( const ModbusRTU::ModbusData mbreg, const int fn )
{
// диапазоны:
// mbreg: 0..65535
// fn: 0...255
int max = numeric_limits<ModbusRTU::ModbusData>::max(); // по идее 65535
int fn_max = numeric_limits<ModbusRTU::ModbusByte>::max(); // по идее 255
// fn необходимо привести к диапазону 0..max
return max + mbreg + max + UniSetTypes::lcalibrate(fn, 0, fn_max, 0, max, false);
}
// -----------------------------------------------------------------------
#include <catch.hpp>
#include <limits>
#include "modbus/ModbusTypes.h"
using namespace std;
// ---------------------------------------------------------------
TEST_CASE("WriteOutputMessage", "[modbus][WriteOutputMessage]" )
{
SECTION("WriteOutputMessage: limit the amount of data verification")
......@@ -19,7 +20,7 @@ TEST_CASE("WriteOutputMessage", "[modbus][WriteOutputMessage]" )
WARN("Tests for 'Modbus types' incomplete..");
}
// ---------------------------------------------------------------
TEST_CASE("Modbus helpers", "[modbus][helpers]" )
{
using namespace ModbusRTU;
......@@ -70,7 +71,7 @@ TEST_CASE("Modbus helpers", "[modbus][helpers]" )
REQUIRE( b2str(-1) == "ff" );
}
}
// ---------------------------------------------------------------
#if 0
/*! \TODO Надо ещё подумать как тут протестировать */
TEST_CASE("dat2f", "[modbus]" )
......@@ -81,7 +82,7 @@ TEST_CASE("dat2f", "[modbus]" )
// REQUIRE( dat2f(0xff,0xff) == 0.0f );
}
#endif
// ---------------------------------------------------------------
TEST_CASE("isWriteFunction", "[modbus][isWriteFunction]" )
{
using namespace ModbusRTU;
......@@ -104,8 +105,28 @@ TEST_CASE("isWriteFunction", "[modbus][isWriteFunction]" )
CHECK_FALSE( isWriteFunction(fnJournalCommand) );
CHECK_FALSE( isWriteFunction(fnFileTransfer) );
}
// ---------------------------------------------------------------
TEST_CASE("checkCRC", "[modbus][checkCRC]" )
{
// ModbusCRC checkCRC( ModbusByte* start, int len );
}
// ---------------------------------------------------------------
#if 0
#warning VERY LONG TIME TEST
TEST_CASE("genRegID", "[modbus][genRegID]" )
{
int max_reg = numeric_limits<ModbusRTU::ModbusData>::max();
int max_fn = numeric_limits<ModbusRTU::ModbusByte>::max();
ModbusRTU::RegID prevID = ModbusRTU::genRegID(0,0);
for( int f=1; f<max_fn; f++ )
{
ModbusRTU::RegID minID = ModbusRTU::genRegID(0,f);
REQUIRE( minID > prevID );
for( int r=1; r<max_reg; r++ )
REQUIRE( ModbusRTU::genRegID(r,f) == minID+r );
}
}
#endif
// ---------------------------------------------------------------
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment