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