Changes

Created page with "we can use the '''FMX125/FMX640''' device‘s '''TCP - Binary''' feature to integrate the '''Modbus- RTU''' slave devices. If we can do some minor development on the server si..."
we can use the '''FMX125/FMX640''' device‘s '''TCP - Binary''' feature to integrate the '''Modbus- RTU''' slave devices. If we can do some minor development on the server side, we can easily integrate all the Modbus-supported equipment like '''Generators''', '''Energy Meters''', '''Fuel level sensors''', and ''' Temperature & Humidity sensors''', etc. without the additional cost of a Modbus controller and Router.

===System Architecture===

[[File:New System_Architecture.png|center]]

To implement this feature, we must properly implement the Teltonika '''[[Codec#Codec 12|codec 12]]''' protocol in the server. In the device, we need to use '''TCP Binary''' mode. We need to primarily convert the Modbus commands to the '''Codec 12 GPRS commands''' and send them to the Teltonika device. The FM device (Teltonika device) will route these commands to the Modbus field device through '''RS232/RS485 serial interface'''. The response for the Modbus command from the field device will collect by the FM device, packed as a '''GPRS response''', and will send to the server by using Codec 12 protocol. In the server, we need to decode this data according to the Modbus protocol.

===The Modbus Protocol===
<br />
'''What is Modbus?'''

Modbus is a serial communication protocol developed by Modicon and published by Modicon® in 1979 for use with its programmable logic controllers (PLCs). In simple terms, it is a method used for transmitting information over serial lines between electronic devices. The device requesting the information is called the Modbus Master and the devices supplying information are Modbus Slaves. In a standard Modbus network, there is one Master and up to 247 Slaves, each with a unique Slave Address from 1 to 247. The Master can also write information to the Slaves.
<br />
<br />

'''How does it work?'''
<br />

Modbus is transmitted over serial lines between devices. The simplest setup would be a single serial cable connecting the serial ports on two devices, a Master and a Slave. [[Image:Modbus signal.png|491x491px]]

The data is sent as a series of ones and zeroes called bits. Each bit is sent as a voltage. Zeroes are sent as positive voltages and ones as negative. The bits are sent very quickly. A typical transmission speed is 9600 baud (bits per second).
<br />
<br />

'''How is data stored in Standard Modbus?'''

Information is stored in the Slave device at four different tables. Two tables store on/off discrete values (coils) and two store numerical values (registers). The coils and registers each have a read-only table and a read-write table. Each table has 9999 values. Each coil or contact is 1 bit and assigned a data address between 0000 and 270E. Each register is 1 word = 16 bits = 2 bytes and also has a data address between 0000 and 270E.
<br />

<br />
{| class="wikitable"
|+
! style="width:20%; border: 1px solid white; border-bottom: 2px solid #0054A6; background: white; color: #0054A6; text-align: left;" |Coil/Register Numbers
! style="width:20%; border: 1px solid white; border-bottom: 2px solid #0054A6; background: white; color: #0054A6; text-align: left;" |Data Addresses
! style="width:40%; border: 1px solid white; border-bottom: 2px solid #0054A6; background: white; color: #0054A6; text-align: left;" |Type
! style="width:40%; border: 1px solid white; border-bottom: 2px solid #0054A6; background: white; color: #0054A6; text-align: left;" |Table Name
|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |1-9999
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |<span style="color:blue"><b>0000</b></span> to <span style="color:blue"><b>270E</b></span>
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" | READ-WRITE
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" | Discrete Output Coils
|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |10001-19999
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |<span style="color:blue"><b>0000</b></span> to <span style="color:blue"><b>270E</b></span>
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" | READ-ONLY
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" | Discrete Input Contacts
|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |30001-39999
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |<span style="color:blue"><b>0000</b></span> to <span style="color:blue"><b>270E</b></span>
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" | READ-ONLY
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" | Analog Input Registers
|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |40001-49999
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |<span style="color:blue"><b>0000</b></span> to <span style="color:blue"><b>270E</b></span>
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" | READ-WRITE
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" | Analog Output Holding Registers
|-
|}
Coil/Register Numbers can be thought of as location names since they do not appear in the actual messages. The Data Addresses are used in the messages. For example, the first Holding Register, number 40001, has the Data Address 0000. The difference between these two values is the offset. Each table has a different offset, which are 1, 10001, 30001, and 40001.
<br />
<br />

'''What is the Slave ID?'''

Each slave in a network is assigned a unique unit address from 1 to 247. When the master requests data, the first byte it sends is the Slave address. This way each slave knows after the first byte whether or not to ignore the message.
<br />
<br />

'''What is a function code?'''

The second byte sent by the Master is the Function code. This number tells the slave which table to access and whether to read from or write to the table.
<br />

{| class="wikitable"
|+
! style="width:20%; border: 1px solid white; border-bottom: 2px solid #0054A6; background: white; color: #0054A6; text-align: left;" |Function Code
! style="width:20%; border: 1px solid white; border-bottom: 2px solid #0054A6; background: white; color: #0054A6; text-align: left;" |Action
! style="width:40%; border: 1px solid white; border-bottom: 2px solid #0054A6; background: white; color: #0054A6; text-align: left;" |Table Name
|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |01 (<span style="color:blue"><b>01</b></span> HEX)
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Read
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Discrete Output Coils
|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |05 (<span style="color:blue"><b>05</b></span> HEX)
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Write Single
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Discrete Output Coil
|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |15 (<span style="color:blue"><b>0F</b></span> HEX)
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Write Multiple
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Discrete Output Coils
|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |02 (<span style="color:blue"><b>02</b></span> HEX)
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Read
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Discrete Input Contacts
|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |04 (<span style="color:blue"><b>04</b></span> HEX)
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Read
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Analog Input Registers
|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |03 (<span style="color:blue"><b>03</b></span> HEX)
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Read
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Analog Output Holding Registers
|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |06 (<span style="color:blue"><b>06</b></span> HEX)
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Write Single
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Analog Output Holding Register
|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |16 (<span style="color:blue"><b>10</b></span> HEX)
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Write Multiple
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Analog Output Holding Registers
|-
|}

Since most of the sensors and equipment are using holding registers, we will check the read holding registers function in detail.

'''Read Holding Registers (FC=03)'''

'''Request'''

This command is requesting the content of analog output holding registers # 40108 to 40110 from the slave device with address 17.

'''<span style="background-color:#ff00ff;">11</span> <span style="background-color:#00ff00;">03</span> <span style="background-color:#FBD1EC;">006B</span> <span style="background-color:#B2B2B2;">0003</span> <span style="background-color:#ffff00;">7687</span> '''

'''<span style="background-color:#ff00ff;">11</span>''': The Slave Address (11 hex = address17)
<br />
'''<span style="background-color:#00ff00;">03</span>''': The Function Code 3 (read Analog Output Holding Registers)
<br />
'''<span style="background-color:#FBD1EC;">006B</span>''': The Data Address of the first register requested.(006B hex = 107, + 40001 offset = input #40108)
<br />
'''<span style="background-color:#B2B2B2;">0003</span>''': The total number of registers requested. (Read 3 registers 40108 to 40110)
<br />
'''<span style="background-color:#ffff00;">7687</span>''': The CRC (cyclic redundancy check) for error checking.
<br />
<br />
'''Response'''
<br />
<br />

'''<span style="background-color:#ff00ff;">11</span> <span style="background-color:#00ff00;">03</span> <span style="background-color:#D1F7FB;">06</span> <span style="background-color:#F6FAD2;">AE41</span> <span style="background-color:#FDDDCF;">5652</span> <span style="background-color:#D1CEFE;">4340</span> <span style="background-color:#ffff00;">49AD</span>'''

<br />

'''<span style="background-color:#ff00ff;">11</span>''': The Slave Address (11 hex = address17)<br />
'''<span style="background-color:#00ff00;">03</span>''': The Function Code 3 (read Analog Output Holding Registers)<br />
'''<span style="background-color:#D1F7FB;">06</span>''': The number of data bytes to follow (3 registers x 2 bytes each = 6 bytes)<br />
'''<span style="background-color:#F6FAD2;">AE41</span>''': The contents of register 40108<br />
'''<span style="background-color:#FDDDCF;">5652</span>''': The contents of register 40109<br />
'''<span style="background-color:#D1CEFE;">4340</span>''': The contents of register 40110<br />
'''<span style="background-color:#ffff00;">49AD</span>''': The CRC (cyclic redundancy check).<br />
<br />

'''What is a CRC?'''
<br />

CRC stands for Cyclic Redundancy check. It is two bytes added to the end of every Modbus message for error detection. Every byte in the message is used to calculate the CRC. The receiving device also calculates the CRC and compares it to the CRC from the sending device. If even one bit in the message is received incorrectly, the CRCs will be different, and an error will result.<br />

<br />
<br />

===TZONE TZ-THT02 RS485 Modbus RTU Temperature and Humidity sensor integration===

<br />

We can integrate any Modbus slave device into our device including Generators, Energy Meters, Fuel level sensors, Flow meters, etc. In order to test the Modbus integration TZONE TZ-THT02 sensor shall be used. <br />
<br />
<br />
[[File:TZ-THT02.png|655x655px]]
<br />
<br />

The THT-02 temperature and humidity sensor is designed based on the RS-485 communication interface, compatible with the standard Modbus-RTU protocol, and can be connected to the Modbus network to achieve temperature and humidity measurement and monitoring.

<br />
<br />

'''Sensor Technical Data'''

Supply voltage DC 5~24V<br />
Current 5mA<br />
RS-485 interface Transmission rate Optional 4800bps / 9600bps / 19200bps<br />

Lead description<br />

Yellow Green RS485 interface A+ <br />
Green RS485 interface B-<br />
Black Ground (connect to the negative end of the power)<br />
Red Power supply positive (connect to the positive end of the power supply)<br />

'''DIP switch and address code'''

<br />
[[File:DIP switch setting.png|498x498px]]

<br />

The above picture is a schematic diagram of the DIP switch. The DIP switch has 8 DIP positions. The corresponding numbers from 1 to 8 are 128, 64, 32, 16, 8, 4, 2, and 1, and these values are added together as the address code. As shown in the figure above, bits 1, 3, and 4 are in the ON position, so the address code is 128+32+16=176, that is, the address code is 176. We have set the sensor address as 1 by setting DIP switch 1 as ON.

===Wiring scheme===

<br />
Since the sensor supports the RS485, we need to use the RS485 interface of the FM device for the integration. Connect FM device '''RS485 – A''' to the '''sensor RS485 A''' and '''RS485 B''' to '''RS485 B''' of the sensor. <br />
If we are using an RS232 Modbus device, we need to connect FM device '''Tx''' to Modbus device '''Rx''' and FM device '''Rx''' to Modbus device '''Tx'''.<br />

If you are using FMX640, you need to use an RJ45 cable for connecting the RS232/RS485 devices.<br />

===FM device configuration===

<br />
For the Modbus integration, we need to select '''RS485''' as UART mode and '''TCP Binary''' as RS485 mode. Set the baud rate and parity as per the sensor configuration. In our case, the sensor baud rate is 9600 and parity is None. Leave the CMD ID field and Prefix settings as it is. We used FMX125 for testing but in FMX640 also you can use the same settings
<br />
<br />

[[File:RS485 Configuration.png]]


===Creating the Modbus command===
<br />

This sensor is using eight holding registers to store the data. We need to use '''Read Holding Registers (FC=03)''' Modbus function to read the values from these registers. Please find the sensor register address details below.

<br />
{| class="wikitable"
|+
! style="width:20%; border: 1px solid white; border-bottom: 2px solid #0054A6; background: white; color: #0054A6; text-align: left;" |Register Address
! style="width:30%; border: 1px solid white; border-bottom: 2px solid #0054A6; background: white; color: #0054A6; text-align: left;" |Meaning
! style="width:40%; border: 1px solid white; border-bottom: 2px solid #0054A6; background: white; color: #0054A6; text-align: left;" |Description
! style="width:40%; border: 1px solid white; border-bottom: 2px solid #0054A6; background: white; color: #0054A6; text-align: left;" |Read and Write
|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |0
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Temperature
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |The unit is 0.1 degree
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Read only

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |1
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Relative Humidity
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |The unit is 0.1%
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Read only

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |2
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Reserved 1
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Read only

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |3
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Reserved 2
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Read only

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |4
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Address code
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Set by DIP switch
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Read only

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |5
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Baudrate
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Support 4800, 9600, 19200
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Read and Write

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |6
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Hardware version
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Read only

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |7
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Software version
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Read only

|-
|}

<br />

We need to send the below Modbus command to the sensor to read the data from register addresses 0 to 7 (40001 to 40009).

'''<span style="background-color:#ff00ff;">01</span> <span style="background-color:#00ff00;">03</span> <span style="background-color:#FBD1EC;">0000</span> <span style="background-color:#B2B2B2;">0008</span> <span style="background-color:#ffff00;">440C</span>'''

'''<span style="background-color:#ff00ff;">01</span>''':The Slave Address (Sensor address)

'''</span><span style="background-color:#00ff00;">03</span>''':The Function Code

'''<span style="background-color:#FBD1EC;">0000</span>''':The Data Address of the first register requested

'''<span style="background-color:#B2B2B2;">0008</span>''':The total number of registers requested (Read 8 registers 40001 to 40009)

'''</span><span style="background-color:#ffff00;">440C</span>''':The CRC (cyclic redundancy check) for error checking

===Constructing the Codec 12 Command===

<br />

As discussed in the beginning, we need to pack this Modbus command as Codec 12 command then only we can send it from the server. Please find the below structure of a Codec 12 command.

<br />

'''Command message structure:'''
{| class="nd-othertables_2" style="width:100%;"
|+
! rowspan="1" style="width:10%; border-bottom: 2px solid #0054A6; vertical-align: middle; text-align: center;" |0x00000000 (Preamble)
! rowspan="1" style="width:10%; border-bottom: 2px solid #0054A6; vertical-align: middle; text-align: center;" |Data Size
! rowspan="1" style="width:10%; border-bottom: 2px solid #0054A6; vertical-align: middle; text-align: center;" |Codec ID
! rowspan="1" style="width:10%; border-bottom: 2px solid #0054A6; vertical-align: middle; text-align: center;" |Command Quantity 1
! colspan="1" style="width:10%; border-bottom: 2px solid #0054A6; vertical-align: middle; text-align: center;" |Type (0x05)
! rowspan="1" style="width:14%; border-bottom: 2px solid #0054A6; vertical-align: middle; text-align: center;" |Command Size
! rowspan="1" style="width:14%; border-bottom: 2px solid #0054A6; vertical-align: middle; text-align: center;" |Command
! rowspan="1" style="width:14%; border-bottom: 2px solid #0054A6; vertical-align: middle; text-align: center;" |Command Quantity 2
! rowspan="1" style="width:14%; border-bottom: 2px solid #0054A6; vertical-align: middle; text-align: center;" |CRC-16
|-
| style="vertical-align: middle; text-align: center;" |4 bytes
| style="vertical-align: middle; text-align: center;" |4 bytes
| style="vertical-align: middle; text-align: center;" |1 byte
| style="vertical-align: middle; text-align: center;" |1 byte
| style="vertical-align: middle; text-align: center;" |1 byte
| style="vertical-align: middle; text-align: center;" |4 bytes
| style="vertical-align: middle; text-align: center;" |X bytes
| style="vertical-align: middle; text-align: center;" |1 byte
| style="vertical-align: middle; text-align: center;" |4 bytes
|-
|}


'''Preamble''' - the packet starts with four zero bytes.<br />
'''Data Size''' - size is calculated from the Codec ID field to the second command or response quantity field.<br />
'''Codec ID''' - in Codec12 it is always 0x0C.<br />
'''Command/Response Quantity 1''' - it is ignored when parsing the message.<br />
'''Type''' - 0x0E – If you set the type as 0E the device will route this command to serial ports.<br />
'''Command/Response Size''' – command or response length.<br />
'''Command/Response''' – command or response in HEX.<br />
'''Command/Response Quantity 2''' - a byte that defines how many records (commands or responses) is in the packet. This byte will not be parsed but it’s recommended that it should contain the same value as Command/Response Quantity 1.<br />
'''CRC-16''' – calculated from Codec ID to the Command Quantity 2. CRC (Cyclic Redundancy Check) is an error-detecting code used to detect accidental changes to RAW data.<br />

Let‘s create our GPRS command as per the codec 12 protocol.

'''</span><span style="background-color:#00ff00;">010300000008440C</span>''' is the Modbus command; we have used this command as the payload of our GPRS command.

<br />

'''00000000 00000010 0C 01 0E 00000008 </span><span style="background-color:#00ff00;">010300000008440C</span> 01 00001181'''

<br />

'''Sensor response'''

<!-- This table kept for future use
{| class="wikitable"
|+
! style="width:20%; border: 1px solid white; border-bottom: 2px solid #0054A6; background: white; color: #0054A6; text-align: left;" |Field description
! style="width:30%; border: 1px solid white; border-bottom: 2px solid #0054A6; background: white; color: #0054A6; text-align: left;" |Example

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Slave address
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |01

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Function code
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |03

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Returm the number of bytes
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |10

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Temperature - High byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |00

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Temperature - Low byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |FA

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Humidity - High byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |02

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Humidity - Low byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |58

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Reserved byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |00

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Reserved byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |00

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Reserved byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |00

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Reserved byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |00

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Sensor address High Byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |00

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Sensor address Low Byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |01

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Baud rate High Byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |25

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |Baud rate Low Byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |80

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |HW version High Byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |06

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |HW version Low Byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |00

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |SW version High Byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |00

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |SW version Low Byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |0A

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |CRC Low Byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |D4

|-
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |CRC High Byte
| style="border: 1px solid white; border-bottom: 2px solid #E8E8E8; text-align: left; vertical-align: center; background: white;" |64

|-
|}

-->
<br />
Please find the below sensor response for the Modbus command to read eight holding registers. The device will pack this response in a Codec 12 packet and send it to the server. So, in the server, we will get the codec 12 response from the device, and we need to parse this as per the codec 12 protocol to get the sensor response. This is the response from the device for the Modbus command.

<br />

'''00000000 0000001D 0C 01 06 00000015 </span><span style="background-color:#00ff00;">010310010901B500000000000125800600000C489C</span> 01 0000EFAA'''

<br />

If we parse this message as per the codec 12 protocol, we will get the original Modbus response from the sensor i.e., '''</span><span style="background-color:#ff00ff;">01</span> </span><span style="background-color:#00ff00;">03</span> </span><span style="background-color:#FBD1EC;">10</span> </span><span style="background-color:#99FF99;">0109</span> <span style="background-color:#FF9900;">01B5</span> <span style="background-color:#B2B2B2;"> 00000000</span> <span style="background-color:#ff00ff;">0001</span> <span style="background-color:#00ffff;">2580</span> <span style="background-color:#D1F7FB;">0600</span> <span style="background-color:#F6FAD2;">000C</span> <span style="background-color:#ffff00;"> 489C </span>'''. We need to decode this data as per the Modbus protocol.

<br />

'''</span><span style="background-color:#ff00ff;">01</span>''':The Slave Address (Sensor address)<br />

'''</span><span style="background-color:#00ff00;">03</span>''':The Function Code<br />

'''</span><span style="background-color:#FBD1EC;">10</span>''':The number of bytes<br />

'''</span><span style="background-color:#99FF99;">0109</span>''':Temperature<br />

'''<span style="background-color:#FF9900;">01B5</span>''':Humidity<br />

'''<span style="background-color:#B2B2B2;"> 00000000</span>''':Reserved Bytes<br />

'''<span style="background-color:#ff00ff;">0001</span>''':Sensor address<br />

'''<span style="background-color:#00ffff;">2580</span>''':Baud rate<br />

'''<span style="background-color:#D1F7FB;">0600</span>''':Hardware version<br />

'''<span style="background-color:#F6FAD2;">000C</span>''':Software version<br />

'''<span style="background-color:#ffff00;"> 489C </span>''':CRC<br />
<br />

'''Data analysis'''<br />


We need to analyze this data in the server as per the sensor user manual to get the correct values.<br />


'''Temperature''' = '''</span><span style="background-color:#99FF99;">0109</span>H'''<br />
we need to do the hex-to-decimal conversion.<br />
'''Hex2Dec (</span><span style="background-color:#99FF99;">0109</span>)''' = '''265'''<br />
Then we need to divide by 10 to get the temperature value in degree Celsius, '''265/10''' = '''26.5 ℃'''<br />

<br />

The same calculation we need to perform for the Humidity also.<br />

'''Humidity''' = '''<span style="background-color:#FF9900;">01B5</span>H''' <br />

'''Hex2Dec (<span style="background-color:#FF9900;">01B5</span>)''' = '''437 / 10 = 43.7%RH'''.<br />

<br />

'''Baud rate''' = '''<span style="background-color:#00ffff;">2580</span>''', we need to do the hex-to-decimal conversion to get the baud rate.<br />

'''Hex2Dec (<span style="background-color:#00ffff;">2580</span>) = 9600'''<br />

===Sample Codec 12 message frames===
<br />
We have used Hercules as our test server. We have sent the command as HEX and received the response from the device.

<br />

[[File:Hercules.png]]

<br />

===Conclusion===
<br />

Teltonika FMX125 & FMX640 devices are capable to integrate equipment and sensors that use Modbus RTU protocol. We have successfully integrated TZONE TZ-THT02 RS485 Modbus RTU Temperature and Humidity sensor with FMC125.

[[Category: Frequently Asked Questions - FAQ]]

Navigation menu