Commit 326960c7 authored by Pavel Vainerman's avatar Pavel Vainerman Committed by Pavel Vainerman

[modbus master][reload config]: reload by HTTP API

parent cc15c224
......@@ -1185,54 +1185,56 @@ int oinfo(const string& args, UInterface& ui, const string& userparam )
// --------------------------------------------------------------------------------------
int apiRequest( const string& args, UInterface& ui, const string& query )
{
auto conf = uniset_conf();
auto sl = uniset::getObjectsList( args, conf );
// if( verb )
// cout << "apiRequest: query: " << query << endl;
if( query.size() < 1 )
{
if( !quiet )
cerr << "query is too small '" << query << "'" << endl;
return 1;
}
string q = query;
if( q.rfind("/api/", 0) != 0 )
{
q = "/api/" + uniset::UHttp::UHTTP_API_VERSION;
if( query[0] != '/' )
q += "/";
q += query;
}
for( auto && it : sl )
{
if( it.node == DefaultObjectId )
it.node = conf->getLocalNode();
try
{
cout << ui.apiRequest(it.id, q, it.node) << endl;
}
catch( const std::exception& ex )
{
if( !quiet )
cerr << "std::exception: " << ex.what() << endl;
}
catch(...)
{
if( !quiet )
cerr << "Unknown exception.." << endl;
}
cout << endl << endl;
}
return 0;
auto conf = uniset_conf();
auto sl = uniset::getObjectsList( args, conf );
// if( verb )
// cout << "apiRequest: query: " << query << endl;
if( query.size() < 1 )
{
if( !quiet )
cerr << "query is too small '" << query << "'" << endl;
return 1;
}
string q = query;
if( q.rfind("/api/", 0) != 0 )
{
q = "/api/" + uniset::UHttp::UHTTP_API_VERSION;
if( query[0] != '/' )
q += "/";
q += query;
}
for( auto&& it : sl )
{
if( it.node == DefaultObjectId )
it.node = conf->getLocalNode();
try
{
cout << ui.apiRequest(it.id, q, it.node) << endl;
}
catch( const std::exception& ex )
{
if( !quiet )
cerr << "std::exception: " << ex.what() << endl;
}
catch(...)
{
if( !quiet )
cerr << "Unknown exception.." << endl;
}
cout << endl << endl;
}
return 0;
}
// --------------------------------------------------------------------------------------
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -37,9 +37,9 @@ MBTCPMaster::MBTCPMaster(uniset::ObjectId objId, uniset::ObjectId shmId,
auto conf = uniset_conf();
// префикс для "свойств" - по умолчанию "tcp_";
mbconf->prop_prefix = initPropPrefix(mbconf->s_field, "tcp_");
mbinfo << myname << "(init): prop_prefix=" << mbconf->prop_prefix << endl;
// префикс для "свойств" - по умолчанию "tcp_";
mbconf->prop_prefix = initPropPrefix(mbconf->s_field, "tcp_");
mbinfo << myname << "(init): prop_prefix=" << mbconf->prop_prefix << endl;
UniXML::iterator it(cnode);
......@@ -61,16 +61,16 @@ MBTCPMaster::MBTCPMaster(uniset::ObjectId objId, uniset::ObjectId shmId,
force_disconnect = conf->getArgInt("--" + prefix + "-persistent-connection", it.getProp("persistent_connection")) ? false : true;
mbinfo << myname << "(init): persisten-connection=" << (!force_disconnect) << endl;
if( shm->isLocalwork() )
mbconf->loadConfig(conf->getConfXML(), conf->getXMLSensorsSection());
else
ic->addReadItem( sigc::mem_fun(this, &MBTCPMaster::readItem) );
if( shm->isLocalwork() )
mbconf->loadConfig(conf->getConfXML(), conf->getXMLSensorsSection());
else
ic->addReadItem( sigc::mem_fun(this, &MBTCPMaster::readItem) );
pollThread = unisetstd::make_unique<ThreadCreator<MBTCPMaster>>(this, &MBTCPMaster::poll_thread);
pollThread->setFinalAction(this, &MBTCPMaster::final_thread);
if( mblog->is_info() )
MBConfig::printMap(mbconf->devices);
if( mblog->is_info() )
MBConfig::printMap(mbconf->devices);
}
// -----------------------------------------------------------------------------
MBTCPMaster::~MBTCPMaster()
......@@ -105,11 +105,11 @@ std::shared_ptr<ModbusClient> MBTCPMaster::initMB( bool reopen )
mbtcp->connect(iaddr, port);
mbtcp->setForceDisconnect(force_disconnect);
if( mbconf->recv_timeout > 0 )
mbtcp->setTimeout(mbconf->recv_timeout);
if( mbconf->recv_timeout > 0 )
mbtcp->setTimeout(mbconf->recv_timeout);
mbtcp->setSleepPause(mbconf->sleepPause_msec);
mbtcp->setAfterSendPause(mbconf->aftersend_pause);
mbtcp->setSleepPause(mbconf->sleepPause_msec);
mbtcp->setAfterSendPause(mbconf->aftersend_pause);
mbinfo << myname << "(init): ipaddr=" << iaddr << " port=" << port
<< " connection=" << (mbtcp->isConnection() ? "OK" : "FAIL" ) << endl;
......@@ -140,45 +140,45 @@ void MBTCPMaster::final_thread()
// -----------------------------------------------------------------------------
void MBTCPMaster::poll_thread()
{
// ждём начала работы..(см. MBExchange::activateObject)
while( !isProcActive() && !canceled )
{
uniset::uniset_rwmutex_rlock l(mutex_start);
}
// if( canceled )
// return;
// работаем
while( isProcActive() )
{
try
{
if( sidExchangeMode != DefaultObjectId && force )
exchangeMode = shm->localGetValue(itExchangeMode, sidExchangeMode);
}
catch(...)
{
throw;
}
try
{
poll();
}
catch(...)
{
// if( !checkProcActive() )
throw;
}
if( !isProcActive() )
break;
msleep(mbconf->polltime);
}
dinfo << myname << "(poll_thread): thread finished.." << endl;
// ждём начала работы..(см. MBExchange::activateObject)
while( !isProcActive() && !canceled )
{
uniset::uniset_rwmutex_rlock l(mutex_start);
}
// if( canceled )
// return;
// работаем
while( isProcActive() )
{
try
{
if( sidExchangeMode != DefaultObjectId && force )
exchangeMode = shm->localGetValue(itExchangeMode, sidExchangeMode);
}
catch(...)
{
throw;
}
try
{
poll();
}
catch(...)
{
// if( !checkProcActive() )
throw;
}
if( !isProcActive() )
break;
msleep(mbconf->polltime);
}
dinfo << myname << "(poll_thread): thread finished.." << endl;
}
// -----------------------------------------------------------------------------
bool MBTCPMaster::deactivateObject()
......
......@@ -35,6 +35,8 @@ namespace uniset
- \ref sec_MBTCP_Conf
- \ref sec_MBTCP_ConfList
- \ref sec_MBTCP_ExchangeMode
- \ref sec_MBTCP_ReloadConfig
- \ref sec_MBTCP_REST_API
\section sec_MBTCP_Comm Общее описание ModbusTCP master
Класс реализует процесс обмена (опрос/запись) с RTU-устройствами,
......@@ -207,6 +209,34 @@ namespace uniset
Если указан и параметр \a safemodeSensor=".." и \a safemodeResetIfNotRespond="1", то будет использован
режим \b safeExternalControl (как более приоритетный).
\section sec_MBTCP_ReloadConfig Переконфигурирование "на ходу"
В процессе реализована возможность перечитать конфигурацию "на ходу". Для этого достаточно процессу
послать команду SystemMessage::Reconfigure или воспользоваться HTTP API, где можно указать файл из
которого произвести загрузку (см. \ref sec_MBTCP_REST_API).
При этом процесс приостанавливает обмен и перезагружает конфигурационный файл с которым был запущен.
Переконфигурировать можно регистры, список устройств, адреса и любые свойства. В том числе возможно
добавление новых регистров в список или уменьшение списка существующих.
\warning Если во время загрузки новой конфигурации будет найдена какая-то ошибка, то конфигурация не будет применена.
Ошибку можно будет увидеть в логах процесса.
\warning Важно понимать, что это перезагрузка только настроек касающихся ModbusMaster, поэтому список датчиков
и другие базовые настройки должны совпадать с исходным файлом. Т.е. возможно только переопределение параметров
касающихся обмена, а не всего конфига в целом.
\section sec_MBTCP_REST_API ModbusMaster HTTP API
\code
/help - Получение списка доступных команд
/ - получение стандартной информации
/reconfigure?confile=/path/to/confile - Перезагрузить конфигурацию
confile - абсолютный путь до файла с конфигурацией. Не обязательный параметр.
\endcode
\warning Важно иметь ввиду, что если указывается confile, то он должен совпадать с базовым configure.xml
в идентификаторах датчиков. И как минимум должен содержать соответствующую секцию настроек для процесса
и те датчики, которые участвуют в обмене. Т.к. реальный config (глобальный) не подменяется, из указанного
файла только загружаются необходимые для инициализации обмена параметры.
*/
// -----------------------------------------------------------------------------
/*!
......
......@@ -53,7 +53,7 @@ namespace uniset
virtual void step() override;
virtual bool poll() override;
virtual std::shared_ptr<ModbusClient> initMB( bool reopen = false ) override;
virtual std::shared_ptr<ModbusClient> initMB( bool reopen = false ) override;
private:
RTUExchange();
......
......@@ -16,7 +16,7 @@
--mbtcp-persistent-connection 1 \
--ulog-add-levels system \
--mbtcp-run-logserver \
--mbtcp-log-add-levels any \
--mbtcp-log-add-levels info,warn,crit \
$*
#--mbtcp-log-add-levels level4,level3 \
......
......@@ -10,127 +10,127 @@
/*! Реализация MBTCPTestServer для тестирования */
class MBTCPTestServer
{
public:
MBTCPTestServer( const std::unordered_set<uniset::ModbusRTU::ModbusAddr>& vaddr, const std::string& inetaddr, int port = 502, bool verbose = false );
~MBTCPTestServer();
inline void setVerbose( bool state )
{
verbose = state;
}
inline void setReply( uint32_t val )
{
replyVal = val;
}
void execute(); /*!< основной цикл работы */
void setLog( std::shared_ptr<DebugStream> dlog );
inline bool isRunning()
{
return ( sslot && sslot->isActive() );
}
inline void disableExchange( bool set = true )
{
disabled = set;
}
inline bool getForceSingleCoilCmd()
{
return forceSingleCoilCmd;
}
inline int16_t getLastWriteOutputSingleRegister()
{
return lastWriteOutputSingleRegister;
}
inline uniset::ModbusRTU::ForceCoilsMessage getLastForceCoilsQ()
{
return lastForceCoilsQ;
}
inline uniset::ModbusRTU::WriteOutputMessage getLastWriteOutput()
{
return lastWriteOutputQ;
}
friend std::ostream& operator<<(std::ostream& os, const MBTCPTestServer* m );
inline float getF2TestValue()
{
return f2_test_value;
}
protected:
// действия при завершении работы
void sigterm( int signo );
/*! обработка 0x01 */
uniset::ModbusRTU::mbErrCode readCoilStatus( uniset::ModbusRTU::ReadCoilMessage& query,
uniset::ModbusRTU::ReadCoilRetMessage& reply );
/*! обработка 0x02 */
uniset::ModbusRTU::mbErrCode readInputStatus( uniset::ModbusRTU::ReadInputStatusMessage& query,
uniset::ModbusRTU::ReadInputStatusRetMessage& reply );
/*! обработка 0x03 */
uniset::ModbusRTU::mbErrCode readOutputRegisters( uniset::ModbusRTU::ReadOutputMessage& query,
uniset::ModbusRTU::ReadOutputRetMessage& reply );
/*! обработка 0x04 */
uniset::ModbusRTU::mbErrCode readInputRegisters( uniset::ModbusRTU::ReadInputMessage& query,
uniset::ModbusRTU::ReadInputRetMessage& reply );
/*! обработка 0x05 */
uniset::ModbusRTU::mbErrCode forceSingleCoil( uniset::ModbusRTU::ForceSingleCoilMessage& query,
uniset::ModbusRTU::ForceSingleCoilRetMessage& reply );
/*! обработка 0x0F */
uniset::ModbusRTU::mbErrCode forceMultipleCoils( uniset::ModbusRTU::ForceCoilsMessage& query,
uniset::ModbusRTU::ForceCoilsRetMessage& reply );
/*! обработка 0x10 */
uniset::ModbusRTU::mbErrCode writeOutputRegisters( uniset::ModbusRTU::WriteOutputMessage& query,
uniset::ModbusRTU::WriteOutputRetMessage& reply );
/*! обработка 0x06 */
uniset::ModbusRTU::mbErrCode writeOutputSingleRegister( uniset::ModbusRTU::WriteSingleOutputMessage& query,
uniset::ModbusRTU::WriteSingleOutputRetMessage& reply );
uniset::ModbusRTU::mbErrCode diagnostics( uniset::ModbusRTU::DiagnosticMessage& query,
uniset::ModbusRTU::DiagnosticRetMessage& reply );
uniset::ModbusRTU::mbErrCode read4314( uniset::ModbusRTU::MEIMessageRDI& query,
uniset::ModbusRTU::MEIMessageRetRDI& reply );
/*! обработка запросов на чтение ошибок */
uniset::ModbusRTU::mbErrCode journalCommand( uniset::ModbusRTU::JournalCommandMessage& query,
uniset::ModbusRTU::JournalCommandRetMessage& reply );
/*! обработка запроса на установку времени */
uniset::ModbusRTU::mbErrCode setDateTime( uniset::ModbusRTU::SetDateTimeMessage& query,
uniset::ModbusRTU::SetDateTimeRetMessage& reply );
/*! обработка запроса удалённого сервиса */
uniset::ModbusRTU::mbErrCode remoteService( uniset::ModbusRTU::RemoteServiceMessage& query,
uniset::ModbusRTU::RemoteServiceRetMessage& reply );
uniset::ModbusRTU::mbErrCode fileTransfer( uniset::ModbusRTU::FileTransferMessage& query,
uniset::ModbusRTU::FileTransferRetMessage& reply );
/*! интерфейс ModbusSlave для обмена по RS */
uniset::ModbusTCPServerSlot* sslot;
std::unordered_set<uniset::ModbusRTU::ModbusAddr> vaddr; /*!< адреса данного узла */
bool verbose;
uint32_t replyVal;
bool forceSingleCoilCmd;
int16_t lastWriteOutputSingleRegister;
uniset::ModbusRTU::ForceCoilsMessage lastForceCoilsQ;
uniset::ModbusRTU::WriteOutputMessage lastWriteOutputQ;
float f2_test_value = {0.0};
public:
MBTCPTestServer( const std::unordered_set<uniset::ModbusRTU::ModbusAddr>& vaddr, const std::string& inetaddr, int port = 502, bool verbose = false );
~MBTCPTestServer();
inline void setVerbose( bool state )
{
verbose = state;
}
inline void setReply( uint32_t val )
{
replyVal = val;
}
void execute(); /*!< основной цикл работы */
void setLog( std::shared_ptr<DebugStream> dlog );
inline bool isRunning()
{
return ( sslot && sslot->isActive() );
}
inline void disableExchange( bool set = true )
{
disabled = set;
}
inline bool getForceSingleCoilCmd()
{
return forceSingleCoilCmd;
}
inline int16_t getLastWriteOutputSingleRegister()
{
return lastWriteOutputSingleRegister;
}
inline uniset::ModbusRTU::ForceCoilsMessage getLastForceCoilsQ()
{
return lastForceCoilsQ;
}
inline uniset::ModbusRTU::WriteOutputMessage getLastWriteOutput()
{
return lastWriteOutputQ;
}
friend std::ostream& operator<<(std::ostream& os, const MBTCPTestServer* m );
inline float getF2TestValue()
{
return f2_test_value;
}
protected:
// действия при завершении работы
void sigterm( int signo );
/*! обработка 0x01 */
uniset::ModbusRTU::mbErrCode readCoilStatus( uniset::ModbusRTU::ReadCoilMessage& query,
uniset::ModbusRTU::ReadCoilRetMessage& reply );
/*! обработка 0x02 */
uniset::ModbusRTU::mbErrCode readInputStatus( uniset::ModbusRTU::ReadInputStatusMessage& query,
uniset::ModbusRTU::ReadInputStatusRetMessage& reply );
/*! обработка 0x03 */
uniset::ModbusRTU::mbErrCode readOutputRegisters( uniset::ModbusRTU::ReadOutputMessage& query,
uniset::ModbusRTU::ReadOutputRetMessage& reply );
/*! обработка 0x04 */
uniset::ModbusRTU::mbErrCode readInputRegisters( uniset::ModbusRTU::ReadInputMessage& query,
uniset::ModbusRTU::ReadInputRetMessage& reply );
/*! обработка 0x05 */
uniset::ModbusRTU::mbErrCode forceSingleCoil( uniset::ModbusRTU::ForceSingleCoilMessage& query,
uniset::ModbusRTU::ForceSingleCoilRetMessage& reply );
/*! обработка 0x0F */
uniset::ModbusRTU::mbErrCode forceMultipleCoils( uniset::ModbusRTU::ForceCoilsMessage& query,
uniset::ModbusRTU::ForceCoilsRetMessage& reply );
/*! обработка 0x10 */
uniset::ModbusRTU::mbErrCode writeOutputRegisters( uniset::ModbusRTU::WriteOutputMessage& query,
uniset::ModbusRTU::WriteOutputRetMessage& reply );
/*! обработка 0x06 */
uniset::ModbusRTU::mbErrCode writeOutputSingleRegister( uniset::ModbusRTU::WriteSingleOutputMessage& query,
uniset::ModbusRTU::WriteSingleOutputRetMessage& reply );
uniset::ModbusRTU::mbErrCode diagnostics( uniset::ModbusRTU::DiagnosticMessage& query,
uniset::ModbusRTU::DiagnosticRetMessage& reply );
uniset::ModbusRTU::mbErrCode read4314( uniset::ModbusRTU::MEIMessageRDI& query,
uniset::ModbusRTU::MEIMessageRetRDI& reply );
/*! обработка запросов на чтение ошибок */
uniset::ModbusRTU::mbErrCode journalCommand( uniset::ModbusRTU::JournalCommandMessage& query,
uniset::ModbusRTU::JournalCommandRetMessage& reply );
/*! обработка запроса на установку времени */
uniset::ModbusRTU::mbErrCode setDateTime( uniset::ModbusRTU::SetDateTimeMessage& query,
uniset::ModbusRTU::SetDateTimeRetMessage& reply );
/*! обработка запроса удалённого сервиса */
uniset::ModbusRTU::mbErrCode remoteService( uniset::ModbusRTU::RemoteServiceMessage& query,
uniset::ModbusRTU::RemoteServiceRetMessage& reply );
uniset::ModbusRTU::mbErrCode fileTransfer( uniset::ModbusRTU::FileTransferMessage& query,
uniset::ModbusRTU::FileTransferRetMessage& reply );
/*! интерфейс ModbusSlave для обмена по RS */
uniset::ModbusTCPServerSlot* sslot;
std::unordered_set<uniset::ModbusRTU::ModbusAddr> vaddr; /*!< адреса данного узла */
bool verbose;
uint32_t replyVal;
bool forceSingleCoilCmd;
int16_t lastWriteOutputSingleRegister;
uniset::ModbusRTU::ForceCoilsMessage lastForceCoilsQ;
uniset::ModbusRTU::WriteOutputMessage lastWriteOutputQ;
float f2_test_value = {0.0};
#if 0
typedef std::map<uniset::ModbusRTU::mbErrCode, unsigned int> ExchangeErrorMap;
......
......@@ -47,14 +47,14 @@ int main( int argc, const char* argv[] )
if( !shm )
return 1;
mbm = MBTCPMaster::init_mbmaster(argc, argv, shm->getId(), (apart ? nullptr : shm ));
mbm = MBTCPMaster::init_mbmaster(argc, argv, shm->getId(), (apart ? nullptr : shm ));
if( !mbm )
return 1;
if( !mbm )
return 1;
auto act = UniSetActivator::Instance();
act->add(shm);
act->add(mbm);
act->add(shm);
act->add(mbm);
SystemMessage sm(SystemMessage::StartUp);
act->broadcast( sm.transport_msg() );
......
......@@ -706,43 +706,49 @@ Poco::JSON::Object::Ptr UObject_SK::request_conf_set( const std::string& req, co
{
Poco::JSON::Object::Ptr jret = new Poco::JSON::Object();
Poco::JSON::Array::Ptr jupdated = uniset::json::make_child_array(jret, "updated");
for( const auto& p: params )
for( const auto& p : params )
{
if( p.first == "sleep_msec" )
{
int val = uni_atoi(p.second);
if( val > 0 )
{
sleep_msec = uni_atoi(p.second);
jupdated->add(p.first);
}
continue;
}
if( p.first == "resetMsgTime" )
{
int val = uni_atoi(p.second);
if( val > 0 )
{
resetMsgTime = uni_atoi(p.second);
jupdated->add(p.first);
}
continue;
}
if( p.first == "forceOut" )
{
int val = uni_atoi(p.second);
if( val > 0 )
{
forceOut = uni_atoi(p.second);
jupdated->add(p.first);
}
continue;
}
}
jret->set("Result", (jupdated->size() > 0 ? "OK" : "FAIL") );
......
......@@ -204,12 +204,12 @@ namespace uniset
void setActive( bool set );
#ifndef DISABLE_REST_API
// вспомогательные функции
virtual Poco::JSON::Object::Ptr httpGetMyInfo( Poco::JSON::Object::Ptr root );
Poco::JSON::Object::Ptr request_conf( const std::string& req, const Poco::URI::QueryParameters& p );
virtual Poco::JSON::Object::Ptr request_conf_get( const std::string& req, const Poco::URI::QueryParameters& p );
virtual Poco::JSON::Object::Ptr request_conf_set( const std::string& req, const Poco::URI::QueryParameters& p );
Poco::JSON::Object::Ptr request_conf_name( const std::string& name, const std::string& props );
// вспомогательные функции
virtual Poco::JSON::Object::Ptr httpGetMyInfo( Poco::JSON::Object::Ptr root );
Poco::JSON::Object::Ptr request_conf( const std::string& req, const Poco::URI::QueryParameters& p );
virtual Poco::JSON::Object::Ptr request_conf_get( const std::string& req, const Poco::URI::QueryParameters& p );
virtual Poco::JSON::Object::Ptr request_conf_set( const std::string& req, const Poco::URI::QueryParameters& p );
Poco::JSON::Object::Ptr request_conf_name( const std::string& name, const std::string& props );
#endif
private:
......
......@@ -60,12 +60,12 @@ namespace uniset
/*! текущее количество подключений */
size_t getCountSessions() const noexcept;
// Сбор статистики по соединениям...
struct SessionInfo
{
SessionInfo( const std::string& a, size_t ask ): iaddr(a), askCount(ask) {}
// Сбор статистики по соединениям...
struct SessionInfo
{
SessionInfo( const std::string& a, size_t ask ): iaddr(a), askCount(ask) {}
std::string iaddr;
std::string iaddr;
size_t askCount;
};
......
......@@ -988,6 +988,7 @@ namespace uniset
return getInfo(request);
#else
SimpleInfo* ret = new SimpleInfo();
ret->id = getId();
ostringstream err;
try
......
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