Example: DF1 MSpec
The DF1 protocol has three basic messages: a command message, acknowledge and not acknowledge.
A 0x10
is used as delimiter to differentiate between the messages and parts of the command message.
ACK | NAK |
---|---|
10 06 |
10 15 |
This is what a read command message looks like in full-duplex mode using CRC as checksum:
Name | DLE | STX | DST | SRC | CMD | STS | TNS | ADDR | SIZE | DLE | ETX | CRC |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Value |
10 |
02 |
XX |
XX |
01 |
00 |
XX XX |
XX XX |
02 |
10 |
03 |
XX XX |
The according response with the requested byte data:
Name | DLE | STX | DST | SRC | CMD | STS | TNS | DATA | SIZE | DLE | ETX | CRC |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Value |
10 |
02 |
XX |
XX |
41 |
00 |
XX XX |
XX XX |
02 |
10 |
03 |
XX XX |
Every message starts with a DLE = 0x10
. The second byte is used to differentiate what type of message will follow.
In the case of a command message it is 0x02
. DST and SRC specify the target and source of the message.
CMD = 0x01
means an unprotected read is requested, the command response code is always attained with the addition of 0x40
. STS is a status byte,
TNS is the transaction counter that is incremented by the master and used to recognize the specific message response.
ADDR is the memory address being requested, size specifies how many bytes are to be read.
DLE + ETX mark the end of the message, the last two bytes are the CRC that is calculated using the previously sent bytes.
Here is the MSpec to model the behaviour:
[discriminatedType DF1Symbol [const uint 8 messageStart 0x10] [discriminator uint 8 symbolType] [typeSwitch 'symbolType' ['0x02' DF1SymbolMessageFrame [simple uint 8 destinationAddress] [simple uint 8 sourceAddress] [simple DF1Command command] [const uint 8 messageEnd 0x10] [const uint 8 endTransaction 0x03] [checksum uint 16 'crc' 'STATIC_CALL("org.apache.plc4x.java.df1.readwrite.utils.StaticHelper.crcCheck", destinationAddress, sourceAddress, command)'] ] ['0x06' DF1SymbolMessageFrameACK ] ['0x15' DF1SymbolMessageFrameNAK ] ] ] [discriminatedType DF1Command [discriminator uint 8 commandCode] [simple uint 8 status] [simple uint 16 transactionCounter] [typeSwitch 'commandCode' ['0x01' DF1UnprotectedReadRequest [simple uint 16 address] [simple uint 8 size] ] ['0x41' DF1UnprotectedReadResponse [manualArray uint 8 'data' terminated 'STATIC_CALL("org.apache.plc4x.java.df1.readwrite.utils.StaticHelper.dataTerminate", io)' 'STATIC_CALL("org.apache.plc4x.java.df1.readwrite.utils.StaticHelper.readData", io)' 'STATIC_CALL("org.apache.plc4x.java.df1.readwrite.utils.StaticHelper.writeData", io, element)' 'STATIC_CALL("org.apache.plc4x.java.df1.readwrite.utils.StaticHelper.dataLength", data)'] ] ] ]
The basic object is the DF1Symbol, where the second byte is used to distinguish between the different message types using a typeSwitch. In the case of a command message, the message frame contains the DF1Command to further differentiate between the command types. Currently only the unprotected read and its response are implemented.