> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oryx.mechatronstudio.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Modbus

> RTU, ASCII and TCP, with the function codes and exceptions translated.

Modbus builds on the UART reading: **every byte is one character on the serial
line**. That is why it has serial settings of its own, independent from UART: it
is not unusual to read a loose line at 8N1 and a Modbus bus at 8E1 at the same
time.

## Settings

| Setting         | Options                           | Default |
| --------------- | --------------------------------- | ------- |
| **Mode**        | RTU, ASCII, TCP                   | RTU     |
| **Direction**   | Auto, Request, Response           | Auto    |
| **Serial line** | The same character format as UART | 8E1     |

### The three modes

> In **RTU** frames are split by a 3.5-character silence; in **ASCII** by `:`
> and CR LF; in **TCP** by the length the MBAP header declares.

<Note>
  For **Modbus TCP** what is read is the framing: the MBAP header and the PDU. The
  layers below —TCP, IP, Ethernet— are not drawn: the bytes are written as serial
  characters.
</Note>

### The direction

The data layout depends on the side of the conversation. In **Auto** it is
inferred from the frame length and the previous request; it is worth forcing it
to draw a single frame on its own.

## Fields

| Field                | What it is                                                                                         |
| -------------------- | -------------------------------------------------------------------------------------------------- |
| **Slave address**    | Which device the master is talking to. Address 0 is broadcast: everyone listens and nobody answers |
| **Function**         | What is being asked. With bit `0x80` set, it is an exception response                              |
| **Starting address** | The first register or coil of the request                                                          |
| **Quantity**         | How many registers or coils it covers                                                              |
| **Value**            | What gets written                                                                                  |
| **AND / OR mask**    | In the masked write                                                                                |
| **CRC / LRC**        | The check, depending on the mode                                                                   |

In TCP the MBAP header fields are added:

| Field                      | What it is                                                            |
| -------------------------- | --------------------------------------------------------------------- |
| **Transaction identifier** | Pairs the response with its request                                   |
| **Protocol identifier**    | Always 0 for Modbus                                                   |
| **Length**                 | How many bytes follow, the unit byte included                         |
| **Unit identifier**        | Which device behind the gateway; 255 is the one on the network itself |

## Function codes it recognizes

| Code | Function                         |
| ---- | -------------------------------- |
| `01` | Read coils                       |
| `02` | Read discrete inputs             |
| `03` | Read holding registers           |
| `04` | Read input registers             |
| `05` | Write single coil                |
| `06` | Write single register            |
| `07` | Read exception status            |
| `08` | Diagnostics                      |
| `0B` | Get comm event counter           |
| `0C` | Get comm event log               |
| `0F` | Write multiple coils             |
| `10` | Write multiple registers         |
| `11` | Report server ID                 |
| `14` | Read file record                 |
| `15` | Write file record                |
| `16` | Mask write register              |
| `17` | Read/write multiple registers    |
| `18` | Read FIFO queue                  |
| `2B` | Encapsulated interface transport |

A code outside the list is still shown, as *Function N*.

## Exceptions

| Code | Exception                          |
| ---- | ---------------------------------- |
| `01` | Illegal function                   |
| `02` | Illegal data address               |
| `03` | Illegal data value                 |
| `04` | Server device failure              |
| `05` | Acknowledged, it will take a while |
| `06` | Server device busy                 |
| `08` | Memory parity error                |
| `0A` | Gateway path unavailable           |
| `0B` | Gateway target failed to respond   |

## Errors it detects

| Label                        | What happened                                            |
| ---------------------------- | -------------------------------------------------------- |
| **Short frame**              | Not enough to make a frame                               |
| **Wrong length**             | The frame is not the size it should be for that function |
| **CRC error**                | The RTU check does not match                             |
| **LRC error**                | The ASCII check does not match                           |
| **Unknown function**         | The function code is not in the list                     |
| **Exception**                | It is an exception response                              |
| **Silence inside the frame** | There is a gap in the line within a single frame         |
| **Line error**               | The serial character reading failed (framing or parity)  |
| **Quantity out of range**    | The requested quantity is not valid for that function    |
| **Wrong byte count**         | The count byte does not match the data that follows      |
| **Coil value**               | The value written to a coil is not valid                 |
| **Reserved address**         | The slave address is outside the allowed range           |
| **No CR LF**                 | The ASCII frame does not close with CR LF                |
| **Not a hex digit**          | In ASCII, a character that is not a hex digit            |
| **Protocol not 0**           | The MBAP protocol identifier is not 0                    |
| **MBAP length**              | The declared length does not match the frame             |
| **Outside a frame**          | Bytes that belong to no frame                            |

## The summary

Each frame is summed up with the device and the function, and an arrow giving
the direction:

* `0x01 → Read holding registers` for a request
* `0x01 ← Read holding registers` for the response
* `0x01 ✗ Read holding registers` for an exception
* `Broadcast → Write multiple coils` for address 0
* `Incomplete frame` or `Outside a frame` when it does not add up

At the end, a `✓` or a `✗` depending on the check.

## How to start

With nothing drawn, the status box explains:

> *No frame yet. Every byte is one character on the serial line: in RTU and
> ASCII a frame starts with the slave address, and in TCP with the MBAP header.*
