Commit 73db415f authored by Pavel Vainerman's avatar Pavel Vainerman

(modbus): Добился компиляции. Приступил к реализации обработки функции 0x08.

parent f475a091
......@@ -19,6 +19,7 @@ static struct option longopts[] = {
{ "write06", required_argument, 0, 'z' },
{ "write0F", required_argument, 0, 'm' },
{ "write10", required_argument, 0, 'w' },
{"diag08", required_argument, 0, 'o' },
// { "readfile14", required_argument, 0, 'g' },
// { "writefile15", required_argument, 0, 'p' },
{ "filetransfer66", required_argument, 0, 'u' },
......@@ -45,6 +46,7 @@ static void print_help()
printf("[--read02] slaveaddr reg count - read from reg (from slaveaddr). Default: count=1\n");
printf("[--read03] slaveaddr reg count - read from reg (from slaveaddr). Default: count=1\n");
printf("[--read04] slaveaddr reg count - read from reg (from slaveaddr). Default: count=1\n");
printf("[--diag08] slaveaddr subfunc - diagnostics request\n");
// printf("[--readfile14] slaveaddr fileID - read file from slaveaddr).\n");
// printf("[--writefile15] slaveaddr id filename - write file to slaveaddr).\n");
printf("[--filetransfer66] slaveaddr fileID [filename] - get file from slaveaddr. Default save to 'fileID.transfer'\n");
......@@ -81,7 +83,8 @@ enum Command
cmdDetectSlave,
cmdReadFile,
cmdWriteFile,
cmdFileTransfer
cmdFileTransfer,
cmdDiag
};
// --------------------------------------------------------------------------
static char* checkArg( int ind, int argc, char* argv[] );
......@@ -103,6 +106,7 @@ int main( int argc, char **argv )
ModbusRTU::SlaveFunctionCode fn = ModbusRTU::fnReadInputRegisters;
ModbusRTU::ModbusAddr beg = 0;
ModbusRTU::ModbusAddr end = 255;
ModbusRTU::DiagnosticsSubFunction subfunc = ModbusRTU::subEcho;
int tout = 2000;
DebugStream dlog;
string tofile("");
......@@ -111,7 +115,7 @@ int main( int argc, char **argv )
try
{
while( (opt = getopt_long(argc, argv, "hva:w:z:m:r:x:c:b:d:s:t:qn:u:yl:t:",longopts,&optindex)) != -1 )
while( (opt = getopt_long(argc, argv, "hva:w:z:m:r:x:c:b:d:s:t:qn:u:yl:t:o:",longopts,&optindex)) != -1 )
{
switch (opt)
{
......@@ -146,6 +150,20 @@ int main( int argc, char **argv )
count = uni_atoi(argv[optind+1]);
break;
case 'o':
cmd = cmdDiag;
slaveaddr = ModbusRTU::str2mbAddr( optarg );
if( !checkArg(optind,argc,argv) )
{
cerr << "diagnostic command error: bad or no arguments..." << endl;
return 1;
}
else
subfunc = (ModbusRTU::DiagnosticsSubFunction)uni_atoi(argv[optind]);
break;
case 'f':
cmd = cmdWrite05;
case 'z':
......@@ -508,7 +526,31 @@ int main( int argc, char **argv )
cout << "(reply): " << ret << endl;
}
break;
case cmdDiag:
{
if( verb )
{
cout << "diag08: slaveaddr=" << ModbusRTU::addr2str(slaveaddr)
<< " subfunc=" << ModbusRTU::dat2str(subfunc) << "(" << (int)subfunc << ")"
<< endl;
}
ModbusRTU::DiagnosticRetMessage ret = mb.diag08(slaveaddr,subfunc);
if( verb )
cout << "(reply): " << ret << endl;
cout << "(reply): count=" << ModbusRTU::dat2str(ret.count) << endl;
for( int i=0; i<ret.count; i++ )
{
cout << i <<": (" << ModbusRTU::dat2str( reg + i ) << ") = " << (int)(ret.data[i])
<< " ("
<< ModbusRTU::dat2str(ret.data[i])
<< ")"
<< endl;
}
}
break;
case cmdDetectSlave:
{
if( verb )
......
......@@ -82,6 +82,10 @@ class ModbusClient
ModbusRTU::WriteOutputRetMessage write10( ModbusRTU::WriteOutputMessage& msg )
throw(ModbusRTU::mbException);
/*! Диагностика (0x08) */
ModbusRTU::DiagnosticRetMessage diag08( ModbusRTU::ModbusAddr addr,
ModbusRTU::DiagnosticsSubFunction subfunc )
throw(ModbusRTU::mbException);
/*! Установить системное время (0x50)
hour - часы [0..23]
......
......@@ -50,6 +50,9 @@ class ModbusRTUSlaveSlot:
virtual ModbusRTU::mbErrCode writeOutputRegisters( ModbusRTU::WriteOutputMessage& query,
ModbusRTU::WriteOutputRetMessage& reply );
virtual ModbusRTU::mbErrCode diagnostics( ModbusRTU::DiagnosticMessage& query,
ModbusRTU::DiagnosticRetMessage& reply );
virtual ModbusRTU::mbErrCode journalCommand( ModbusRTU::JournalCommandMessage& query,
ModbusRTU::JournalCommandRetMessage& reply );
......
......@@ -141,7 +141,16 @@ class ModbusServer
virtual ModbusRTU::mbErrCode writeOutputRegisters( ModbusRTU::WriteOutputMessage& query,
ModbusRTU::WriteOutputRetMessage& reply )=0;
/*! Обработка запроса на запись данных (0x08).
\param query - запрос
\param reply - ответ. Заполняется в обработчике.
\return Результат обработки
*/
virtual ModbusRTU::mbErrCode diagnostics( ModbusRTU::DiagnosticMessage& query,
ModbusRTU::DiagnosticRetMessage& reply )=0;
/*! Обработка запроса по журналу (0x65)
\param query - запрос
\param reply - ответ. Заполняется в обработчике.
......
......@@ -44,7 +44,11 @@ class ModbusServerSlot
typedef sigc::slot<ModbusRTU::mbErrCode,
ModbusRTU::WriteOutputMessage&,
ModbusRTU::WriteOutputRetMessage&> WriteOutputSlot;
typedef sigc::slot<ModbusRTU::mbErrCode,
ModbusRTU::DiagnosticMessage&,
ModbusRTU::DiagnosticRetMessage&> DiagnosticsSlot;
typedef sigc::slot<ModbusRTU::mbErrCode,
ModbusRTU::JournalCommandMessage&,
ModbusRTU::JournalCommandRetMessage&> JournalCommandSlot;
......@@ -79,6 +83,9 @@ class ModbusServerSlot
/*! подключение обработчика 'записи данных' 0x06 */
void connectWriteSingleOutput( WriteSingleOutputSlot sl );
/*! подключение обработчика 'записи данных' 0x08 */
void connectDiagnostics( DiagnosticsSlot sl );
/*! подключение обработчика 'записи данных' 0x0F */
void connectForceCoils( ForceCoilsSlot sl );
......@@ -108,6 +115,7 @@ class ModbusServerSlot
WriteOutputSlot slWriteOutputs;
ForceSingleCoilSlot slForceSingleCoil;
WriteSingleOutputSlot slWriteSingleOutputs;
DiagnosticsSlot slDiagnostics;
JournalCommandSlot slJournalCommand;
SetDateTimeSlot slSetDateTime;
RemoteServiceSlot slRemoteService;
......
......@@ -44,6 +44,9 @@ class ModbusTCPServerSlot:
virtual ModbusRTU::mbErrCode writeOutputRegisters( ModbusRTU::WriteOutputMessage& query,
ModbusRTU::WriteOutputRetMessage& reply );
virtual ModbusRTU::mbErrCode diagnostics( ModbusRTU::DiagnosticMessage& query,
ModbusRTU::DiagnosticRetMessage& reply );
virtual ModbusRTU::mbErrCode journalCommand( ModbusRTU::JournalCommandMessage& query,
ModbusRTU::JournalCommandRetMessage& reply );
......
......@@ -948,46 +948,17 @@ namespace ModbusRTU
{
ModbusData subf;
ModbusData data[MAXLENPACKET/sizeof(ModbusData)]; /*!< данные */
ModbusCRC crc;
// ------- to slave -------
DiagnosticMessage( ModbusAddr addr, ModbusData dat );
/*! преобразование для посылки в сеть */
ModbusMessage transport_msg();
// ------- from master -------
// ------- from slave -------
DiagnosticMessage( ModbusMessage& m );
DiagnosticMessage& operator=( ModbusMessage& m );
void init( ModbusMessage& m );
/*! размер данных(после заголовка) у данного типа сообщения */
int szData();
// вспомогательное поле определяющее количество байт данных в данном сообщении
int dcount;
}__attribute__((packed));
std::ostream& operator<<(std::ostream& os, DiagnosticMessage& m );
std::ostream& operator<<(std::ostream& os, DiagnosticMessage* m );
// -----------------------------------------------------------------------
/*! Ответ для 0x08 */
struct DiagnosticRetMessage:
public ModbusHeader
{
ModbusData subf;
ModbusData data[MAXLENPACKET/sizeof(ModbusData)]; /*!< данные */
// ------- from slave -------
DiagnosticRetMessage( ModbusMessage& m );
DiagnosticRetMessage& operator=( ModbusMessage& m );
void init( ModbusMessage& m );
/*! размер предварительного заголовка
* (после основного до фактических данных)
*/
static inline int szHead()
{
// bcnt
return sizeof(ModbusByte);
return sizeof(subf);
}
/*! узнать длину данных следующий за предварительным заголовком ( в байтах ) */
......@@ -995,7 +966,7 @@ namespace ModbusRTU
ModbusCRC crc;
// ------- to master -------
DiagnosticRetMessage( ModbusAddr _from );
DiagnosticMessage( ModbusAddr _from, DiagnosticsSubFunction subf );
/*! добавление данных.
* \return TRUE - если удалось
......@@ -1009,7 +980,7 @@ namespace ModbusRTU
/*! проверка на переполнение */
inline bool isFull()
{
return ( dcount*sizeof(ModbusData) >= MAXLENPACKET );
return ( sizeof(subf)+count*sizeof(ModbusData) >= MAXLENPACKET );
}
/*! размер данных(после заголовка) у данного типа сообщения */
......@@ -1023,7 +994,17 @@ namespace ModbusRTU
// преобразовании в ModbusMessage.
// Делать что-типа memcpy(buf,this,sizeof(*this)); будет не верно.
// Используйте специальную функцию transport_msg()
int dcount; /*!< фактическое количество данных в сообщении */
int count; /*!< фактическое количество данных в сообщении */
};
std::ostream& operator<<(std::ostream& os, DiagnosticMessage& m );
std::ostream& operator<<(std::ostream& os, DiagnosticMessage* m );
// -----------------------------------------------------------------------
/*! Ответ для 0x08 */
struct DiagnosticRetMessage:
public DiagnosticMessage
{
DiagnosticRetMessage( ModbusMessage& m );
DiagnosticRetMessage( DiagnosticMessage& m );
};
std::ostream& operator<<(std::ostream& os, DiagnosticRetMessage& m );
......
......@@ -148,6 +148,20 @@ WriteOutputRetMessage ModbusClient::write10( WriteOutputMessage& msg )
throw mbException(res);
}
// --------------------------------------------------------------------------------
DiagnosticRetMessage ModbusClient::diag08( ModbusAddr addr,
DiagnosticsSubFunction subfunc )
throw(ModbusRTU::mbException)
{
DiagnosticMessage msg(addr,subfunc);
qbuf = msg.transport_msg();
mbErrCode res = query(msg.addr,qbuf,reply,replyTimeOut_ms);
if( res==erNoError )
return DiagnosticRetMessage(reply);
throw mbException(res);
}
// --------------------------------------------------------------------------------
SetDateTimeRetMessage ModbusClient::setDateTime( ModbusAddr addr, ModbusByte hour, ModbusByte min, ModbusByte sec,
ModbusByte day, ModbusByte mon, ModbusByte year,
ModbusByte century )
......
......@@ -81,6 +81,15 @@ mbErrCode ModbusRTUSlaveSlot::writeOutputRegisters( WriteOutputMessage& query,
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::diagnostics( DiagnosticMessage& query,
DiagnosticRetMessage& reply )
{
if( !slDiagnostics )
return erOperationFailed;
return slDiagnostics(query,reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlaveSlot::forceSingleCoil( ForceSingleCoilMessage& query,
ForceSingleCoilRetMessage& reply )
{
......
......@@ -50,6 +50,11 @@ void ModbusServerSlot::connectWriteSingleOutput( WriteSingleOutputSlot sl )
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectDiagnostics( DiagnosticsSlot sl )
{
slDiagnostics = sl;
}
// -------------------------------------------------------------------------
void ModbusServerSlot::connectForceSingleCoil( ForceSingleCoilSlot sl )
{
slForceSingleCoil = sl;
......
......@@ -75,6 +75,15 @@ mbErrCode ModbusTCPServerSlot::writeOutputRegisters( WriteOutputMessage& query,
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::diagnostics( DiagnosticMessage& query,
DiagnosticRetMessage& reply )
{
if( !slDiagnostics )
return erOperationFailed;
return slDiagnostics(query,reply);
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServerSlot::forceSingleCoil( ForceSingleCoilMessage& query,
ForceSingleCoilRetMessage& reply )
{
......
......@@ -2145,67 +2145,10 @@ int ModbusRTU::szRequestDiagnosticData( DiagnosticsSubFunction f )
return -1;
}
// -------------------------------------------------------------------------
DiagnosticMessage::DiagnosticMessage( ModbusAddr a, ModbusData sf ):
subf(sf),
dcount(0)
{
addr = a;
func = fnDiagnostics;
}
// -------------------------------------------------------------------------
int DiagnosticMessage::szData()
{
int sz = szRequestDiagnosticData( (DiagnosticsSubFunction)subf );
if( sz >= 0 ) // return subf + szData + CRC
return (sizeof(ModbusData) + sizeof(ModbusData)*sz + szCRC);
return 0;
}
// -------------------------------------------------------------------------
ModbusMessage DiagnosticMessage::transport_msg()
{
assert(sizeof(ModbusMessage)>=sizeof(DiagnosticMessage));
ModbusMessage mm;
// копируем заголовок
memcpy(&mm,this,szModbusHeader);
// копируем данные (переворачиваем байты)
ModbusData d = SWAPSHORT(subf);
int last = sizeof(d); // индекс в массиве данных ( байтовый массив!!! )
memcpy(mm.data,&d,last);
int count = szRequestDiagnosticData((DiagnosticsSubFunction)subf );
// Создаём временно массив, переворачиваем байты
ModbusData* dtmp = new ModbusData[count];
for( int i=0; i<count; i++ )
dtmp[i] = SWAPSHORT(data[i]);
// копируем
memcpy(&(mm.data[last]),dtmp, sizeof(ModbusData)*count );
delete dtmp;
last += sizeof(ModbusData)*count;
// пересчитываем CRC по перевёрнутым данным
ModbusData crc = checkCRC( (ModbusByte*)(&mm), szModbusHeader+last );
// копируем CRC (последний элемент). Без переворачивания...
memcpy(&(mm.data[last]),&crc,szCRC);
// длина сообщения...
mm.len = szData();
return mm;
}
// -------------------------------------------------------------------------
DiagnosticMessage::DiagnosticMessage( ModbusMessage& m )
{
init(m);
}
// -------------------------------------------------------------------------
DiagnosticMessage& DiagnosticMessage::operator=( ModbusMessage& m )
{
......@@ -2216,53 +2159,15 @@ DiagnosticMessage& DiagnosticMessage::operator=( ModbusMessage& m )
void DiagnosticMessage::init( ModbusMessage& m )
{
assert( m.func == fnDiagnostics );
memset(this,0,sizeof(*this));
memcpy(this,&m,sizeof(*this)); // m.len
// переворачиваем слова
subf = SWAPSHORT(subf);
int count = szRequestDiagnosticData( (DiagnosticsSubFunction)subf );
if( count > MAXDATALEN )
throw mbException(erPacketTooLong);
if( count < 0 )
throw mbException(erBadDataValue);
for( int i=0;i<count; i++ )
data[i] = SWAPSHORT(data[i]);
}
// -------------------------------------------------------------------------
std::ostream& ModbusRTU::operator<<(std::ostream& os, DiagnosticMessage& m )
{
return os << "addr=" << addr2str(m.addr)
<< " subf=" << dat2str(m.subf);
}
std::ostream& ModbusRTU::operator<<(std::ostream& os, DiagnosticMessage* m )
{
return os << (*m);
}
// -------------------------------------------------------------------------
DiagnosticRetMessage::DiagnosticRetMessage( ModbusMessage& m )
{
init(m);
}
// -------------------------------------------------------------------------
DiagnosticRetMessage& DiagnosticRetMessage::operator=( ModbusMessage& m )
{
init(m);
return *this;
}
// -------------------------------------------------------------------------
void DiagnosticRetMessage::init( ModbusMessage& m )
{
assert( m.func == fnDiagnostics );
memset(this,0,sizeof(*this));
addr = m.addr;
func = m.func;
memcpy( &subf,m.data,sizeof(subf) );
int last = sizeof(subf);
subf = SWAPSHORT(subf);
int count = szRequestDiagnosticData((DiagnosticsSubFunction)subf );
if( count > MAXDATALEN )
throw mbException(erPacketTooLong);
......@@ -2271,53 +2176,60 @@ void DiagnosticRetMessage::init( ModbusMessage& m )
throw mbException(erBadDataValue);
memcpy(&data,&(m.data[1]),sizeof(ModbusData)*count);
last +=sizeof(ModbusData)*count;
// переворачиваем данные
for( unsigned int i=0; i<count; i++ )
for( int i=0; i<count; i++ )
data[i] = SWAPSHORT(data[i]);
memcpy(&crc,&(m.data[sizeof(ModbusData)*count+1]),szCRC);
memcpy(&crc,&(m.data[last]),szCRC);
}
// -------------------------------------------------------------------------
int DiagnosticRetMessage::getDataLen( ModbusMessage& m )
int DiagnosticMessage::getDataLen( ModbusMessage& m )
{
if( m.len < 0 )
return 0;
return m.data[0];
/*
DiagnosticMessage rm(m);
return (int)(rm.bcnt);
*/
ModbusData d;
memcpy( &d,m.data,sizeof(d) );
d = SWAPSHORT(d);
int sz = szRequestDiagnosticData((DiagnosticsSubFunction)d );
if( sz >= 0 )
return sz + sizeof(d); // subf + sz
return 0;
}
// -------------------------------------------------------------------------
DiagnosticRetMessage::DiagnosticRetMessage( ModbusAddr _addr ):
dcount(0)
DiagnosticMessage::DiagnosticMessage( ModbusAddr _addr, DiagnosticsSubFunction sf ):
count(0)
{
addr = _addr;
func = fnDiagnostics;
subf = sf;
memset(data,0,sizeof(data));
}
// -------------------------------------------------------------------------
bool DiagnosticRetMessage::addData( ModbusData d )
bool DiagnosticMessage::addData( ModbusData d )
{
if( isFull() )
return false;
data[dcount++] = d;
data[count++] = d;
return true;
}
// -------------------------------------------------------------------------
void DiagnosticRetMessage::clear()
void DiagnosticMessage::clear()
{
memset(data,0,sizeof(data));
dcount = 0;
count = 0;
}
// -------------------------------------------------------------------------
ModbusMessage DiagnosticRetMessage::transport_msg()
ModbusMessage DiagnosticMessage::transport_msg()
{
ModbusMessage mm;
// assert(sizeof(ModbusMessage)>=sizeof(DiagnosticRetMessage));
// assert(sizeof(ModbusMessage)>=sizeof(DiagnosticMessage));
assert( sizeof(ModbusMessage) >= (unsigned int)szModbusHeader+szData() );
// копируем заголовок и данные
......@@ -2329,19 +2241,19 @@ ModbusMessage DiagnosticRetMessage::transport_msg()
ind+=sizeof(subf);
// Создаём временно массив, переворачиваем байты
ModbusData* dtmp = new ModbusData[dcount];
for( int i=0; i<dcount; i++ )
ModbusData* dtmp = new ModbusData[count];
for( int i=0; i<count; i++ )
dtmp[i] = SWAPSHORT(data[i]);
// копируем
memcpy(&(mm.data[ind]),dtmp,sizeof(ModbusData)*dcount);
memcpy(&(mm.data[ind]),dtmp,sizeof(ModbusData)*count);
delete dtmp;
ind+=sizeof(ModbusData)*dcount;
ind+=sizeof(ModbusData)*count;
// пересчитываем CRC по перевёрнутым данным
ModbusData crc = checkCRC( (ModbusByte*)(&mm), szModbusHeader+sizeof(subf)+sizeof(ModbusData)*dcount );
ModbusData crc = checkCRC( (ModbusByte*)(&mm), szModbusHeader+sizeof(subf)+sizeof(ModbusData)*count );
// копируем CRC (последний элемент). Без переворачивания...
memcpy(&(mm.data[ind]),&crc,szCRC);
......@@ -2353,15 +2265,38 @@ ModbusMessage DiagnosticRetMessage::transport_msg()
return mm;
}
// -------------------------------------------------------------------------
int DiagnosticRetMessage::szData()
int DiagnosticMessage::szData()
{
// фактическое число данных + контрольная сумма
return dcount*sizeof(ModbusData)+szCRC;
return sizeof(subf)+count*sizeof(ModbusData)+szCRC;
}
// -------------------------------------------------------------------------
DiagnosticRetMessage::DiagnosticRetMessage( ModbusMessage& m ):
DiagnosticMessage(m)
{
}
// -------------------------------------------------------------------------
DiagnosticRetMessage::DiagnosticRetMessage( DiagnosticMessage& m ):
DiagnosticMessage(m)
{
}
// -------------------------------------------------------------------------
std::ostream& ModbusRTU::operator<<(std::ostream& os, DiagnosticMessage& m )
{
// return mbPrintMessage(os,(ModbusByte*)(&m), szModbusHeader + m.szData() );
return os << "addr=" << addr2str(m.addr)
<< " subf=" << dat2str(m.subf);
}
std::ostream& ModbusRTU::operator<<(std::ostream& os, DiagnosticMessage* m )
{
return os << (*m);
}
// -------------------------------------------------------------------------
std::ostream& ModbusRTU::operator<<(std::ostream& os, DiagnosticRetMessage& m )
{
return mbPrintMessage(os,(ModbusByte*)(&m), szModbusHeader + m.szData() );
return mbPrintMessage(os,(ModbusByte*)(&m),sizeof(m));
}
std::ostream& ModbusRTU::operator<<(std::ostream& os, DiagnosticRetMessage* m )
......
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