Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
U
uniset2
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
UniSet project repositories
uniset2
Commits
a6f9d9cb
Commit
a6f9d9cb
authored
Oct 10, 2011
by
Pavel Vainerman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
(modbus): "Наброски" реализации функции 0x08
parent
5e610cf4
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
390 additions
and
0 deletions
+390
-0
ModbusTypes.h
include/modbus/ModbusTypes.h
+115
-0
ModbusTypes.cc
src/Communications/Modbus/ModbusTypes.cc
+275
-0
No files found.
include/modbus/ModbusTypes.h
View file @
a6f9d9cb
...
...
@@ -37,6 +37,7 @@ namespace ModbusRTU
fnReadInputRegisters
=
0x04
,
/*!< read input registers or memories or read word outputs or memories */
fnForceSingleCoil
=
0x05
,
/*!< forces a single coil to either ON or OFF */
fnWriteOutputSingleRegister
=
0x06
,
/*!< write register outputs or memories */
fnDiagnostics
=
0x08
,
/*!< Diagnostics (Serial Line only) */
fnForceMultipleCoils
=
0x0F
,
/*!< force multiple coils */
fnWriteOutputRegisters
=
0x10
,
/*!< write register outputs or memories */
fnReadFileRecord
=
0x14
,
/*!< read file record */
...
...
@@ -47,6 +48,33 @@ namespace ModbusRTU
fnFileTransfer
=
0x66
/*!< file transfer */
};
/*! Коды диагностически подфункций (для запроса 0x08) */
enum
DiagnosticsSubFunction
{
subEcho
=
0x00
,
/*!< (0) Return Query Data (echo) */
dgRestartComm
=
0x01
,
/*!< (1) Restart Communications Option */
dgDiagReg
=
0x02
,
/*!< (2) Return Diagnostic Register */
dgChangeASCII
=
0x03
,
/*!< (3) Change ASCII Input Delimiter */
dgForceListen
=
0x04
,
/*!< (4) Force Listen Only Mode */
// 05.. 09 RESERVED
dgClearCounters
=
0x0A
,
/*!< (10)Clear Counters and Diagnostic Register */
dgBusMsgCount
=
0x0B
,
/*!< (11) Return Bus Message Count */
dgBusErrCount
=
0x0C
,
/*!< (12) Return Bus Communication Error Count */
dgBusExceptCount
=
0x0D
,
/*!< (13) Return Bus Exception Error Count */
dgMsgslavecount
=
0x0E
,
/*!< (14) Return Slave Message Count */
dgNoNoResponseCount
=
0x0F
,
/*!< (15) Return Slave No Response Count */
dgSlaveNAKCount
=
0x10
,
/*!< (16) Return Slave NAK Count */
dgSlaveBusyCount
=
0x11
,
/*!< (17) Return Slave Busy Count */
dgBusCharOverrunCount
=
0x12
,
/*!< (18) Return Bus Character Overrun Count */
// = 0x13, /*!< RESERVED */
dgClearOverrunCounter
=
0x14
/*!< (20) Clear Overrun Counter and FlagN.A. */
// 21 ...65535 RESERVED
};
// определение размера данных в зависимости от типа сообщения
// возвращает -1 - если динамический размер сообщения или размер неизвестен
int
szRequestDiagnosticData
(
DiagnosticsSubFunction
f
);
/*! различные базовые константы */
enum
{
...
...
@@ -914,6 +942,93 @@ namespace ModbusRTU
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
WriteSingleOutputRetMessage
&
m
);
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
WriteSingleOutputRetMessage
*
m
);
// -----------------------------------------------------------------------
/*! Запрос 0x08 */
struct
DiagnosticMessage
:
public
ModbusHeader
{
ModbusData
subf
;
ModbusData
data
[
MAXLENPACKET
/
sizeof
(
ModbusData
)];
/*!< данные */
ModbusCRC
crc
;
// ------- to slave -------
DiagnosticMessage
(
ModbusAddr
addr
,
ModbusData
dat
);
/*! преобразование для посылки в сеть */
ModbusMessage
transport_msg
();
// ------- from master -------
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
);
}
/*! узнать длину данных следующий за предварительным заголовком ( в байтах ) */
static
int
getDataLen
(
ModbusMessage
&
m
);
ModbusCRC
crc
;
// ------- to master -------
DiagnosticRetMessage
(
ModbusAddr
_from
);
/*! добавление данных.
* \return TRUE - если удалось
* \return FALSE - если НЕ удалось
*/
bool
addData
(
ModbusData
d
);
/*! очистка данных */
void
clear
();
/*! проверка на переполнение */
inline
bool
isFull
()
{
return
(
dcount
*
sizeof
(
ModbusData
)
>=
MAXLENPACKET
);
}
/*! размер данных(после заголовка) у данного типа сообщения */
int
szData
();
/*! преобразование для посылки в сеть */
ModbusMessage
transport_msg
();
// Это поле не входит в стандарт modbus
// оно вспомогательное и игнорируется при
// преобразовании в ModbusMessage.
// Делать что-типа memcpy(buf,this,sizeof(*this)); будет не верно.
// Используйте специальную функцию transport_msg()
int
dcount
;
/*!< фактическое количество данных в сообщении */
};
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
DiagnosticRetMessage
&
m
);
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
DiagnosticRetMessage
*
m
);
// -----------------------------------------------------------------------
/*! Чтение информации об ошибке */
struct
JournalCommandMessage
:
...
...
src/Communications/Modbus/ModbusTypes.cc
View file @
a6f9d9cb
...
...
@@ -2094,6 +2094,281 @@ std::ostream& ModbusRTU::operator<<(std::ostream& os, WriteSingleOutputRetMessag
}
// -------------------------------------------------------------------------
int
ModbusRTU
::
szRequestDiagnosticData
(
DiagnosticsSubFunction
f
)
{
if
(
f
==
subEcho
)
return
1
;
// тут странно, вроде в стандарте количество динамическое
// но везде вроде в примерах.. "одно слово"..
if
(
f
==
dgRestartComm
)
return
1
;
if
(
f
==
dgDiagReg
)
return
1
;
if
(
f
==
dgChangeASCII
)
return
1
;
if
(
f
==
dgForceListen
)
return
1
;
if
(
f
==
dgClearCounters
)
return
1
;
if
(
f
==
dgBusMsgCount
)
return
1
;
if
(
f
==
dgBusErrCount
)
return
1
;
if
(
f
==
dgBusExceptCount
)
return
1
;
if
(
f
==
dgMsgslavecount
)
return
1
;
if
(
f
==
dgNoNoResponseCount
)
return
1
;
if
(
f
==
dgSlaveNAKCount
)
return
1
;
if
(
f
==
dgSlaveBusyCount
)
return
1
;
if
(
f
==
dgBusCharOverrunCount
)
return
1
;
if
(
f
==
dgClearOverrunCounter
)
return
1
;
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
)
{
init
(
m
);
return
*
this
;
}
// -------------------------------------------------------------------------
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
;
int
count
=
szRequestDiagnosticData
((
DiagnosticsSubFunction
)
subf
);
if
(
count
>
MAXDATALEN
)
throw
mbException
(
erPacketTooLong
);
if
(
count
<
0
)
throw
mbException
(
erBadDataValue
);
memcpy
(
&
data
,
&
(
m
.
data
[
1
]),
sizeof
(
ModbusData
)
*
count
);
// переворачиваем данные
for
(
unsigned
int
i
=
0
;
i
<
count
;
i
++
)
data
[
i
]
=
SWAPSHORT
(
data
[
i
]);
memcpy
(
&
crc
,
&
(
m
.
data
[
sizeof
(
ModbusData
)
*
count
+
1
]),
szCRC
);
}
// -------------------------------------------------------------------------
int
DiagnosticRetMessage
::
getDataLen
(
ModbusMessage
&
m
)
{
if
(
m
.
len
<
0
)
return
0
;
return
m
.
data
[
0
];
/*
DiagnosticMessage rm(m);
return (int)(rm.bcnt);
*/
}
// -------------------------------------------------------------------------
DiagnosticRetMessage
::
DiagnosticRetMessage
(
ModbusAddr
_addr
)
:
dcount
(
0
)
{
addr
=
_addr
;
func
=
fnDiagnostics
;
memset
(
data
,
0
,
sizeof
(
data
));
}
// -------------------------------------------------------------------------
bool
DiagnosticRetMessage
::
addData
(
ModbusData
d
)
{
if
(
isFull
()
)
return
false
;
data
[
dcount
++
]
=
d
;
return
true
;
}
// -------------------------------------------------------------------------
void
DiagnosticRetMessage
::
clear
()
{
memset
(
data
,
0
,
sizeof
(
data
));
dcount
=
0
;
}
// -------------------------------------------------------------------------
ModbusMessage
DiagnosticRetMessage
::
transport_msg
()
{
ModbusMessage
mm
;
// assert(sizeof(ModbusMessage)>=sizeof(DiagnosticRetMessage));
assert
(
sizeof
(
ModbusMessage
)
>=
(
unsigned
int
)
szModbusHeader
+
szData
()
);
// копируем заголовок и данные
memcpy
(
&
mm
,
this
,
szModbusHeader
);
int
ind
=
0
;
// copy bcnt
memcpy
(
&
mm
.
data
,
&
subf
,
sizeof
(
subf
));
ind
+=
sizeof
(
subf
);
// Создаём временно массив, переворачиваем байты
ModbusData
*
dtmp
=
new
ModbusData
[
dcount
];
for
(
int
i
=
0
;
i
<
dcount
;
i
++
)
dtmp
[
i
]
=
SWAPSHORT
(
data
[
i
]);
// копируем
memcpy
(
&
(
mm
.
data
[
ind
]),
dtmp
,
sizeof
(
ModbusData
)
*
dcount
);
delete
dtmp
;
ind
+=
sizeof
(
ModbusData
)
*
dcount
;
// пересчитываем CRC по перевёрнутым данным
ModbusData
crc
=
checkCRC
(
(
ModbusByte
*
)(
&
mm
),
szModbusHeader
+
sizeof
(
subf
)
+
sizeof
(
ModbusData
)
*
dcount
);
// копируем CRC (последний элемент). Без переворачивания...
memcpy
(
&
(
mm
.
data
[
ind
]),
&
crc
,
szCRC
);
ind
+=
szCRC
;
// длина сообщения...
mm
.
len
=
ind
;
return
mm
;
}
// -------------------------------------------------------------------------
int
DiagnosticRetMessage
::
szData
()
{
// фактическое число данных + контрольная сумма
return
dcount
*
sizeof
(
ModbusData
)
+
szCRC
;
}
// -------------------------------------------------------------------------
std
::
ostream
&
ModbusRTU
::
operator
<<
(
std
::
ostream
&
os
,
DiagnosticRetMessage
&
m
)
{
return
mbPrintMessage
(
os
,(
ModbusByte
*
)(
&
m
),
szModbusHeader
+
m
.
szData
()
);
}
std
::
ostream
&
ModbusRTU
::
operator
<<
(
std
::
ostream
&
os
,
DiagnosticRetMessage
*
m
)
{
return
os
<<
(
*
m
);
}
// -------------------------------------------------------------------------
JournalCommandMessage
::
JournalCommandMessage
(
ModbusMessage
&
m
)
{
assert
(
m
.
func
==
fnJournalCommand
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment