Modbus Simulator

A Modbus slave on your own machine: TCP, RTU or ASCII, with the register map, data types, byte order and value behaviour of the device you are developing against. This is the simulator's user guide.

Product page →

What the simulator does

The simulator makes your PC behave like one or more Modbus slave devices, so a Modbus master — a SCADA system, gateway, PLC, data logger or your own firmware — can be developed and tested without the real equipment.

The simulator with one slave selected, showing the register table
A TCP slave with its register map. Values change live; the request log at the bottom shows what the master asked for.
  • Three protocols. Modbus TCP on any port, and Modbus RTU or Modbus ASCII over a serial line such as a USB-to-RS-485 adapter.
  • Any number of slaves. Each slave has its own name, slave id, protocol and register map. Slaves can share a TCP port or a serial bus.
  • All four address spaces. Holding registers, input registers, coils and discrete inputs.
  • Function codes 1, 2, 3, 4, 5, 6, 7, 8, 15, 16, 17, 22, 23 and 43/14 (device identification), with correct exception responses for everything else.
  • Realistic data. Integers and floats in any byte order, values that change by themselves, counters that increment, coils that toggle or pulse.
  • Register maps from files. Upload a CSV or Excel register list; a template is included.
  • Full visibility. Every request and response is logged as hex with its result.
The About dialog
The ⓘ button in the header shows this summary at any time.

Getting started

  1. Run the program. On Windows double-click tamidas-modbus-simulator.exe; on macOS or Linux unpack the .tar.gz and start the binary from a terminal (see Command line for the first-run notes). A console window opens and shows the web address, and your default browser opens the simulator. Keep the console window open; closing it stops the simulator.
  2. Add a slave. On first start there are no slaves yet and the page shows an overview. Click + Add slave in the header (or the button in the overview) and follow Adding a slave.
  3. Load a register map. Upload the device's register list (see Importing a register map) or add registers by hand.
  4. Connect your master to the address shown in the slave tab and start polling. Watch the request log.
The overview shown when no slave exists
The start page before the first slave is added.
Where things are saved. Settings and register maps are stored in a data folder created next to the executable, so everything is back after a restart. Copy the executable to another folder to keep a separate setup.
Web port. The interface uses port 8080. If that port is busy the next free port is used and printed in the console window. See Command line to change it.

How data flows between master and simulator

A Modbus master sends a request; the simulator answers on behalf of the slave whose id is in the request. The pictures below show that exchange for Modbus TCP and for Modbus RTU, and what happens inside the simulator in between.

Modbus TCP

The master opens a TCP connection to the simulator PC's address and port and sends requests over it. One listener serves every slave on that port; the unit id byte in each request selects the slave.

Modbus master SCADA · PLC · gateway · your app TCP client → 192.168.0.81 : 502 unit id 2 Simulator PC TCP listener 0.0.0.0 : 502 one socket shared by every slave on this port routes by unit id Slave 1 Energy meter Slave 2 Pump controller Slave 3 Inverter each slave has its own registers, coils and simulation settings any other unit id → ignored (no reply), shown in the log Ethernet / Wi-Fi (LAN) Request Response Request frame (MBAP header + PDU) transaction00 07 protocol00 00 length00 06 unit id02 FC03 start 190004A 38 quantity00 02 Response frame MBAP header · length 00 07 02 03 04 bytes 43 66 80 00 = float32 230.5 (ABCD)
Modbus TCP: the master connects to the simulator's address and port. The listener hands each request to the slave whose id is in the unit-id byte, and the response travels back on the same connection.
  • The master needs three things: the simulator PC's IP address (shown in the slave tab), the port, and the unit id equal to the slave id.
  • Several masters can be connected at the same time; each connection is served independently.
  • Slaves on different ports get their own listener; slaves on the same host and port share one.

Modbus RTU

With RTU there is no network: the master and the simulator PC are joined by a two-wire RS-485 bus through a USB adapter. Frames are raw bytes with a CRC, separated by silence, and the first byte is the slave address.

Modbus master PLC · RTU · data logger RS-485 port 9600 8N1 polls slave 2 RS-485 bus (twisted pair) A (+) B (−) A↔A · B↔B · swap if silent USB-to-RS-485 adapter CH340 · FTDI · CP210x USB Simulator PC Serial port COM3 · 9600 8N1 one adapter shared by every slave with these settings Frame parser waits for silence (t3.5) · checks CRC-16 · reads address byte Slave 1 answers id 1 Slave 2 answers id 2 other ids ignored, logged address 0 = broadcast: processed by every slave, never answered reply sent after the optional response delay Request · 8 bytes Response · 9 bytes Request frame (RTU) slave addr02 FC03 start 190004A 38 quantity00 02 CRC-16lo hi ← silence ≥ 3.5 characters marks the end of a frame Response frame 02 03 04 bytes 43 66 80 00 CRC lo hi = float32 230.5 (ABCD)
Modbus RTU: request and response share the same two wires, so only one device talks at a time. The simulator answers only the slave ids it hosts on that serial port.
  • Line settings (baud rate, data bits, parity, stop bits) must be identical on both ends, otherwise frames arrive corrupted and show as bad-crc in the log.
  • Because the bus is shared, the master must wait for each response before sending the next request; the simulator replies immediately unless a response delay is configured.
  • Several simulated slaves on one adapter behave like several physical devices on the bus.

Modbus ASCII

Modbus ASCII is the second transmission mode of the Modbus serial line. The wiring, the bus rules and the slave addressing are those of Modbus RTU; what changes is how a frame is written on the wire. Every byte is sent as two readable hexadecimal characters, a frame starts with a colon and ends with carriage return + line feed, and the checksum is an 8-bit LRC instead of the CRC-16. Older PLCs, some drives and devices behind modems or radio links use it because it tolerates long pauses between characters.

The same request — read 2 holding registers at 19000 from slave 2 Modbus RTU · 8 bytes, binary, ends with silence slave addr02FC03start 190004A 38quantity00 02CRC-16lo hi ← silence ≥ 3.5 characters marks the end Modbus ASCII · 17 characters, text, framed by ':' and CR LF start:slave addr0 2FC0 3start 190004 A 3 8quantity0 0 0 2LRC7 7endCR LF each byte is sent as two hex characters (0–9, A–F) Response frame (ASCII) · 21 characters start:slave addr0 2FC0 3byte count0 4data = float32 230.54 3 6 6 8 0 0 0LRCC EendCR LF LRC = two's complement of the 8-bit sum of the bytes before it: 02+03+4A+38+00+02 = 89h → 100h − 89h = 77h. In the request log: :02034A38000277 → :02030443668000CE
Modbus ASCII carries exactly the same address, function code and data as RTU; only the framing and the checksum differ.
  • A frame begins at : and ends at CR LF. A new colon always restarts reception, so a master that aborts a frame and starts again is understood.
  • Characters may arrive up to 1 second apart. A longer gap discards the partial frame, which is logged as bad-lrc.
  • The standard line setting is 7 data bits, even parity, 1 stop bit (7E1), because only ASCII characters travel on the line; many devices also allow 7O1, 7N2 or 8N1. It must match the master.
  • Frames with a wrong LRC, an odd number of hex characters or non-hex characters are not answered and show as bad-lrc in the log. Lowercase hex is accepted; responses use uppercase.
  • A frame is about twice as long as in RTU, so polling is slower at the same baud rate.
  • RTU and ASCII cannot be mixed on one bus: every device on a serial port uses the same mode. Slave address 0 is a broadcast — processed, never answered — exactly as in RTU.

Inside the simulator

Whichever transport delivered the frame, the same steps produce the answer:

1 · ReceiveTCP socket orserial port 2 · ParseMBAP header, orCRC / LRC check 3 · Routeunit id →slave 4 · Executefunction code:read or write 5 · Encodedata type,byte order 6 · Replyresponse orexception 01/02/03 Register store of the slave holding · input · coils · discrete inputs values move by simulation (random, increment, toggle, pulse) master writes are stored and freeze the value Request log & live UI every frame, result and exception table values update as they change new registers created by writes appear Your browser edits registers, flips coils, starts and stops slaves changes take effect for the next request
One pipeline for every protocol. Step 4 reads from or writes to the slave's register store, which the simulation and the web page also change.
StepWhat can go wrongSeen as
2 · ParseWrong baud rate or parity, noise on the busbad-crc in the log, no reply
3 · RouteMaster uses a slave id that is not hosted on that port or busignored in the log, no reply — the master times out
4 · ExecuteUnsupported function, undefined address, bad quantityexception 01 / 02 / 03
5 · EncodeByte order or type differs from what the master expectsreply is ok but the master shows a wrong value — compare with the Raw words column

Slaves

A slave is one simulated device. Every slave appears as a tab named after it.

Adding a slave

Click + Add slave. A panel slides in from the right.

The Add slave panel for a Modbus TCP slave
Adding a Modbus TCP slave. The bind host is prefilled with this PC's network address.
FieldMeaning
NameShown on the tab. Anything you like, for example the device model.
Slave idThe Modbus unit identifier the master will address, 1–247. The next free id is suggested. It cannot be changed later; remove and re-add the slave instead.
ProtocolModbus TCP, Modbus RTU or Modbus ASCII. The settings below change with the choice.

Press Save. The slave is created, its transport is started, and its tab opens. If the transport could not start — for example the port is in use — the slave is still created and the reason is shown in the tab.

Modbus TCP settings

FieldMeaning
Bind hostThe address the slave listens on. The simulator detects the PC's network addresses and prefills the LAN address; this is also the address to enter in the master. Choose 0.0.0.0 to listen on every address of the PC, or 127.0.0.1 to accept connections from this PC only. Click the field to pick from the list.
PortTCP port, normally 502. No administrator rights are needed. Use another port if 502 is taken by other software.
Tip. Binding to a specific address stops working if the PC gets a new address from DHCP. 0.0.0.0 avoids that; the tab then shows the reachable address next to it.

Modbus RTU settings

The Add slave panel for a Modbus RTU slave
RTU settings. The serial port list is read from the PC; press ↻ after plugging in an adapter.
FieldMeaning
Serial portThe COM port of the USB-to-RS-485 adapter (Windows COMx, macOS /dev/tty.usbserial-…, Linux /dev/ttyUSB0). Auto-detect USB adapter picks the first USB serial adapter found at start time.
Baud rate, Data bits, Parity, Stop bitsMust match the master exactly. Common meter settings are 9600 or 19200 baud, 8 data bits, no parity, 1 stop bit — written 9600 8N1.
Response delay (ms)Extra pause before each response. Leave at 0 unless you are testing a master's timeout handling or a slow device.
Wiring. Connect adapter A(+) to master A(+) and B(−) to B(−), plus GND if available. Labels differ between manufacturers, so if nothing arrives, swap A and B. Frames that arrive with a bad checksum show as bad-crc in the request log, which usually means wrong baud rate or parity.

Modbus ASCII settings

A Modbus ASCII slave uses the same serial settings as an RTU slave — serial port, baud rate, data bits, parity, stop bits and response delay — with these differences:

FieldMeaning
Data bits, ParityChoosing Modbus ASCII switches the fields to the standard 7E1 (7 data bits, even parity, 1 stop bit) if they still hold the RTU default 8N1, and back again when you return to RTU. Change them if your master uses something else, for example 8N1 or 7O1.
Response delay (ms)As for RTU. There is no silence requirement between ASCII frames, so 0 is fine for every master.
One mode per serial port. Slaves that share an adapter must all be RTU or all be ASCII, with identical line settings. A slave whose mode differs from the one already running on that port is not started and shows a conflict message. To test both modes, use two adapters or switch the slaves' protocol.

Simulation settings

These settings are per slave and sit at the bottom of the Add / Edit panel.

SettingMeaning
Update interval (ms)How often registers in random and increment mode get a new value. Bits have their own period (see Bit modes).
Read unmappedWhat a master gets when it reads an address you have not defined. Return 0 makes block reads over gaps succeed, like most meters. Exception 02 rejects the whole read with illegal data address, like a strict device.
Write unmappedWhat happens when a master writes to an undefined address. Create register adds a new holding register or coil at that address with the written value. Exception 02 rejects the write.
Device identificationWhat a master gets when it asks who the slave is with function code 43 / 14: vendor name, product code and revision, plus the vendor URL, product name, model name and application name. Each field has a default; the application name defaults to the slave's name. Clients such as the Modbus Logic Client show these next to the connection.

The slave tab

Slave tabs and the tab header
The tab header: name, summary line, addressing switch, Start/Stop, Edit and Remove, and the transport status.
  • Tab strip. One tab per slave with a status dot: green when its transport is running, red when it failed, grey when stopped. The register count is shown next to the name.
  • Summary line. Slave id, protocol and endpoint, number of registers, update interval and whether the transport is live.
  • Addressing. Shows addresses 0-based or 1-based everywhere. See Addressing.
  • ▶ Start / ■ Stop — one button that starts or stops this slave's transport. The label shows the action it will perform.
  • ✎ Edit slave — opens the same panel as Add slave with the current values. Name, protocol, transport and simulation settings can all be changed; saving applies them and restarts the transport if it was running.
  • 🗑 Remove slave — deletes the slave and all its registers after confirmation.
The Edit slave panel
Edit slave opens the same panel prefilled; only the slave id is locked.
  • Status line. Green while listening (with request counters for TCP), red with the reason when the transport could not start, hidden when stopped.
A stopped RTU slave
An RTU slave that is stopped. Press Start after plugging in the adapter.

Several slaves at once

Add as many slaves as you need. How they share the hardware follows the Modbus rules:

  • Same TCP port. Slaves with the same bind host and port share one listener. The unit id in each request selects the slave. A request whose unit id matches none of them — including 0 and 255 — is not answered and appears as ignored in the log, so set the master's unit id to the slave id.
  • Different TCP ports. Each gets its own listener.
  • Same serial port. Slaves with the same port, the same mode (RTU or ASCII) and identical line settings share the adapter, exactly like several devices on one RS-485 bus. Frames for other slave ids are ignored. If the line settings differ, the second slave is not started and shows a conflict message.
  • TCP and RTU together are independent and can run side by side.
A slave speaks one protocol. To expose the same register map over both TCP and RTU, create two slaves and import the same file into each.

Address spaces

Each slave has the four Modbus address spaces. The cards at the top of the tab select which one the table shows and display the register count in each.

The four address space cards
Click a card to show that space. The card also tells you which function codes read and write it.
SpaceReadWriteContent
Holding registersFC3FC6 (one), FC16 (many), FC22, FC2316-bit words; multi-word values span consecutive addresses
Input registersFC4read-only16-bit words
CoilsFC1FC5 (one), FC15 (many)single bits
Discrete inputsFC2read-onlysingle bits

Addresses are independent per space and per slave: holding register 0 and coil 0 are different things, and slave 1's register 100 has nothing to do with slave 2's.

Holding and input registers

The holding register table
The register table. Every cell is editable; values and raw words update live.

Table columns

ColumnMeaning
AddressStart address of the value. A 32-bit value occupies this address and the next one, a 64-bit value four addresses. Shown 0- or 1-based according to the addressing switch.
NameFree text to identify the register.
TypeData type, see below.
Byte orderHow multi-word values are arranged, see below.
ModeHow the value changes over time, see Value modes.
Min / MaxRange for random mode and wrap-around limits for increment mode.
StepAmount added on each update in increment mode.
DecDecimal places kept when generating values.
UnitEngineering unit, for your reference only.
ValueThe current value. Type a value to set it; the register switches to fixed so it stays.
Raw words (hex)The 16-bit words exactly as they are sent to the master, after type conversion and byte ordering.
WriteWhich function codes can write this space, or read-only.

Data types and byte order

TypeWordsRange
int16 / uint161−32 768…32 767 / 0…65 535
int32 / uint322±2.1 × 10⁹ / 0…4.29 × 10⁹
int64 / uint64464-bit integers
float322IEEE 754 single precision
float644IEEE 754 double precision

Modbus itself only knows 16-bit words, so devices differ in how they split larger values. The byte order column reproduces the device you are simulating. With the bytes of a 32-bit value called A B C D (A most significant):

Byte orderAlso calledWords on the wire
ABCDbig-endian, "Modbus standard"AB CD
CDABword-swapped, little-endian wordsCD AB
BADCbyte-swappedBA DC
DCBAlittle-endianDC BA
Finding the right byte order. If the master shows nonsense for a float, look at the Raw words column and try another byte order until the master shows the value you typed. For 230.5 as float32 the words are 4366 8000 in ABCD and 8000 4366 in CDAB.

Value modes

ModeBehaviour
fixedThe value never changes by itself. Typing a value sets this mode automatically.
randomEvery update interval a new value between Min and Max is generated, rounded to Dec decimals. Good for voltages, currents and temperatures.
incrementEvery update interval Step is added. When the value passes Max it wraps to Min. Good for energy and run-hour counters.

The update interval is a per-slave setting (see Simulation settings).

Editing, adding and deleting

The register toolbar
The toolbar above each table.
  • Editing. Change any cell directly in the table. Edited rows are highlighted and the Save changes button shows how many rows are pending. Press it, or Ctrl+S (⌘+S on a Mac), to apply them. Live values keep updating rows you are not editing.
  • + Add register adds a row after the last one, at the next free address, copying the type and byte order of the previous row. Edit it and save.
  • ✕ at the end of a row deletes it after confirmation. Deletion is immediate and does not need Save.
  • Upload CSV / XLS imports a whole map, see Importing a register map.
Overlaps. If two registers cover the same address, a warning is shown above the table and the later definition wins on the wire. Fix the addresses or types so they do not overlap.
The input register table
Input registers use the same table; they are read-only for the master.

Coils and discrete inputs

Coils (FC1) and discrete inputs (FC2) are single bits. Their table is simpler: an address, a name, a switch showing the current value, a mode with its parameters, and the write access.

The coil table in Rows view
Coils. Click a switch to flip a bit immediately — no Save needed.
  • Switch. Green with 1 means set, grey with 0 means clear. Clicking it changes the value at once; in a driven mode the new value is the starting point for the next cycle.
  • + Add bit adds a bit at the next free address.
  • Coils can be written by the master with FC5 and FC15; discrete inputs are read-only and reject those with exception 01.
The discrete input table
Discrete inputs: same table, read-only for the master, driven from here.

Bit modes

Choosing a mode shows only the fields that mode uses.

ModeParametersBehaviour
static—Never changes by itself. Only a click or a master write changes it. Use it for inputs you want to control by hand.
togglePeriodFlips every Period ms: a square wave with 50 % duty. Period 5000 gives a 10 s cycle. Simulates a running/stopped contact.
randomPeriod, ProbEvery Period ms the bit is re-rolled: it becomes 1 with probability Prob (0–1), otherwise 0. Prob 0.3 means set about 30 % of the time.
pulsePeriod, WidthRests at its current value, then flips to the opposite value for Width ms, every Period ms. Width 0 means one simulation tick. Simulates an alarm blip or a button press.
Periods and widths are handled on a 100 ms clock, so 50 ms is the smallest useful step.

Packed view

The Rows / Packed switch, available for coils and discrete inputs, shows the bits the way FC1 and FC2 return them: one 16-bit word per row with bit 0 on the right, and the word value in hex.

The packed view of coils
Packed view. Green cells are set, white are clear, grey dashed cells are addresses without a bit.
  • Click a green or white cell to flip that bit.
  • Click a grey cell to add a bit at that address.
  • The Word (hex) column is what a master reading those 16 bits receives, which makes it easy to compare with a master's raw view.

0-based and 1-based addressing

Modbus frames carry 0-based addresses, but many manuals and masters number registers from 1, or use the 40001 / 30001 convention. The switch in the tab header changes how addresses are displayed everywhere for that slave: the tables, the packed view and the request log.

Tables shown with 1-based addresses
With 1-based addressing the column header changes and every address is shown one higher.
  • The setting only affects what you see. Nothing changes on the wire.
  • Values typed into the Address column are interpreted in the selected base.
  • Import and export files always use 0-based protocol addresses.
  • For the 40001 convention enter 40001 in the master as register 1 (1-based) or 0 (0-based) here — the leading 4 only identifies the holding register space.

Writes from the master

Masters can write holding registers (FC6, FC16, FC22, FC23) and coils (FC5, FC15). The simulator applies the write and keeps what was written.

  • A written register switches to fixed mode and a written coil to static, so the simulation does not overwrite the master's value on the next update. The row in the table updates immediately.
  • Writing one word of a multi-word value — for example only the high word of a float32 — re-decodes the value from the combined words, exactly as a real device would.
  • FC22 (mask write) applies the AND and OR masks to the current word.
  • FC23 performs the write first and then the read.
  • Writes to addresses that are not defined either create a new register or coil (named hr_<address> or coil_<address>) or return exception 02, depending on the slave's Write unmapped setting. Newly created rows appear in the table with a notice.
  • Input registers and discrete inputs have no write function code; the request is answered with exception 01.

Importing a register map

Instead of typing registers, upload the device's register list. The importer reads .csv, .xls and .xlsx files and fills all four spaces of the slave whose tab is open in one go.

The import dialog
Drag a file onto the dotted box or click to browse. A sample file is one click away.

Steps

  1. Open the tab of the slave the file belongs to and click Upload CSV / XLS above any table. The dialog title names that slave.
  2. Choose Replace current map to discard that slave's registers and load the file, or Append to current map to add the file's rows to them. Other slaves are never touched.
  3. Drop the file on the dotted box, or click it to browse. The import runs at once and the dialog closes; a message summarises how many rows were imported and lists any that were skipped with the reason.

File format

The first row holds column names. Names are matched loosely — case, spaces and punctuation are ignored — and the header may be preceded by a few title rows.

ColumnRequiredMeaning
Modbus FunctionyesThe read function code: 1 coil, 2 discrete input, 3 holding register, 4 input register.
Modbus RegAddryes0-based start address.
Data Formatyesfloat, double, int, uint, bool, or a simulator type name such as float32 or uint16.
Data LennoSize in bytes: 2, 4 or 8. Decides between int16 / int32 / int64 and float32 / float64. Defaults: float → float32, int / uint → 16-bit.
4 Bytes OrdernoByte order: 0 or ABCD, 1 or DCBA, 2 or BADC, 3 or CDAB.
JSON KeyWord or NamenoRegister name.
Unit, Min, Max, Mode, Step, Decimals, ValuenoSimulation settings for registers, as in the table.
Period, Prob, WidthnoBit mode parameters in ms / 0–1 / ms.
Data SourcenoIf present, rows whose source does not contain "Modbus" are skipped. Useful for device export files that mix Modbus rows with others.
Modbus Slave AddrignoredMany device files carry a slave-address column. It is ignored: every row goes into the slave you are uploading to.

When Min, Max, Mode and Unit are missing, the importer guesses sensible values from the name: names containing volt get 228–232 V, curr 4–16 A, freq 49.95–50.05 Hz, power 1000–3000 W, energy an incrementing counter, THD 0.5–4 %.

Template. The Download the sample .csv link in the dialog gives a file with one row per data format across all four spaces. Open it in Excel, replace the rows with your device's list and upload it into the slave's tab.
Skipped rows. A row is skipped when a mandatory cell is empty, the function code is not 1–4, the address is not a number, or its Data Source is not Modbus. The message after import lists each skipped row with its reason. If no row can be imported, the dialog stays open and shows the problem, for example a missing mandatory column.

Request log

The request log at the bottom of the page shows every frame the simulator receives, on every transport and for every slave, newest first.

The request log
Request and response as hex, with the result. Exceptions and ignored frames are highlighted.
ColumnMeaning
TimeArrival time with milliseconds.
ViaTCP with the client address and port, RTU or ASCII.
SlaveUnit id in the request.
FCFunction code; hover for its name.
Address, Qty / valueStart address (in the selected base) and quantity, or the written value for single writes, masks for FC22.
Resultok · exception N with its name · ignored when the unit id is not served on that transport · broadcast for unit id 0 (processed, never answered) · bad-crc for corrupted RTU frames · bad-lrc for ASCII frames with a wrong checksum, invalid characters or an inter-character timeout.
Request, ResponseThe complete frames in hex, including the TCP header or the RTU CRC. Modbus ASCII frames are shown as the text that travelled on the line, for example :02034A38000277 (the trailing CR LF is not shown).

Pause stops the list from scrolling while you read; Clear empties it. The last 300 requests are kept.

Function codes and exceptions

FCNameNotes
1Read Coils1–2000 bits per request
2Read Discrete Inputs1–2000 bits
3Read Holding Registers1–125 registers
4Read Input Registers1–125 registers
5Write Single Coilvalue FF00 = on, 0000 = off
6Write Single Register
7Read Exception Statusreturns 0 (serial line)
8Diagnosticssub-function 0 (return query data) only
15Write Multiple Coils1–1968 bits
16Write Multiple Registers1–123 registers
17Report Server IDreturns the slave id and a run indicator
22Mask Write Register(current AND and_mask) OR (or_mask AND NOT and_mask)
23Read/Write Multiple Registerswrite first, then read
43 / 14Read Device Identificationvendor name, product code, revision (basic) plus vendor URL, product name, model name and application name (regular); stream and individual access, conformity level 0x82. The values are set per slave under Device identification.
ExceptionMeaningWhen the simulator sends it
01Illegal functionUnsupported function code, write to a read-only space, diagnostics sub-function other than 0
02Illegal data addressRead or write touching an undefined address while the slave is set to reject it; address beyond 65535
03Illegal data valueQuantity out of range, byte count mismatch, coil value other than FF00/0000

Testing with a master

Modbus TCP

  1. Add a TCP slave. Note the address in the summary line, for example 192.168.0.81:502.
  2. In the master, create a TCP connection to that IP and port, with unit id equal to the slave id.
  3. Poll, for example FC3 from address 19000 for 26 registers (13 floats). The request log shows each poll and the values are those in the table.

If the master is on another PC, allow the port through the Windows firewall when asked, or add a rule for the executable. The unit id in the master must equal the slave id; other ids are ignored.

Modbus RTU

  1. Plug in the USB-to-RS-485 adapter and install its driver if Windows does not recognise it. Note its COM port in Device Manager.
  2. Add an RTU slave with that port and the master's line settings, then Start it. The tab shows RTU listening on COMx.
  3. Wire A to A and B to B, and poll from the master with the slave id.
  4. No reply: swap A and B. bad-crc in the log: baud rate or parity mismatch. ignored: the master uses a different slave id.

Modbus ASCII

  1. Connect the adapter as for RTU. In the master, select the ASCII transmission mode and note its line settings — usually 9600 7E1.
  2. Add a slave with protocol Modbus ASCII, the same port and line settings, then Start it. The tab shows ASCII listening on COMx.
  3. Poll from the master. The request log shows the frames as text, which makes them easy to compare with the master's own trace or with a serial terminal.
  4. bad-lrc in the log: line settings differ (7 versus 8 data bits is the usual cause) or the master is actually sending RTU. Nothing in the log at all: wiring, or the master is set to RTU and its binary frames contain no colon.

Command line and data folder

tamidas-modbus-simulator.exe                 start and open the browser
tamidas-modbus-simulator.exe --no-open       start without opening the browser
tamidas-modbus-simulator.exe --help          show the options

set PORT=9000 & tamidas-modbus-simulator.exe            web interface on another port
set MODBUS_SIM_DATA=D:\sim\data & tamidas-modbus-simulator.exe   use another data folder

macOS / Linux — the same options, from a terminal:
./tamidas-modbus-simulator-macos-arm64 --no-open
PORT=9000 ./tamidas-modbus-simulator-linux-x64
MODBUS_SIM_DATA=/opt/sim/data ./tamidas-modbus-simulator-linux-x64
BuildFor
tamidas-modbus-simulator.exeWindows 10/11, 64-bit
tamidas-modbus-simulator-macos-arm64Macs with Apple silicon (M1 and later) — portable binary
tamidas-modbus-simulator-macos-x64Intel Macs — portable binary
tamidas-modbus-simulator-<version>-macos-arm64.pkgApple silicon — installer package
tamidas-modbus-simulator-<version>-macos-x64.pkgIntel Macs — installer package
tamidas-modbus-simulator-linux-x6464-bit Linux on Intel/AMD (Ubuntu, Debian, Fedora, …)
tamidas-modbus-simulator-linux-arm6464-bit Linux on ARM (Raspberry Pi 4/5 with a 64-bit OS, ARM servers)
macOS installer package (.pkg). Double-click the .pkg, click through the installer (it asks for your Mac password, as every installer does), then open Terminal and type tamidas-modbus-simulator. The package is signed and notarised by Apple and carries its notarisation ticket, so it installs without any security prompt, even offline. The command is placed in /usr/local/bin; settings and register maps go to ~/Library/Application Support/tamidas-modbus-simulator. To remove it: sudo rm /usr/local/bin/tamidas-modbus-simulator.
First run on macOS (portable binary). The easiest way is the one-line installer, which needs no confirmation: open Terminal and run curl -fsSL https://raw.githubusercontent.com/TamidaSRepo/modbus-simulator/main/install.sh | sh, then start tamidas-modbus-simulator. If you unpacked the archive yourself, start the binary from Terminal (./tamidas-modbus-simulator-macos-arm64) or double-click it in Finder. The macOS builds are signed with the TamidaS Developer ID and notarised by Apple, so Gatekeeper lets them run; if macOS asks once whether to open a file downloaded from the internet, click Open. The first start needs an internet connection for that check. Use the arm64 build on Apple silicon and the x64 build on an Intel Mac.
First run on Linux. The same installer works on Linux: curl -fsSL https://raw.githubusercontent.com/TamidaSRepo/modbus-simulator/main/install.sh | sh. If you unpacked the archive yourself and the file is not executable, run chmod +x on it. To use a serial adapter without root, add yourself to the dialout group and log in again. TCP ports below 1024 (such as 502) need sudo setcap 'cap_net_bind_service=+ep' <binary> or a port such as 1502.
FileContent
data/config.jsonSlaves with their transport and simulation settings.
data/registers.jsonAll registers and their current values. Saved on every change and every 30 s.

Both files are plain JSON. Copy the data folder to move a setup to another PC, or keep several folders and point MODBUS_SIM_DATA at the one you need.

Troubleshooting

Windows shows a SmartScreen warning when starting the exe

The file is not code-signed. Choose More info → Run anyway. The program only runs locally and does not connect to the internet.

macOS says the app cannot be opened or the developer cannot be verified

The published builds are signed and notarised, so this should not happen with a file downloaded from this site. It appears when the download was damaged, when the Mac is offline during the first start (Gatekeeper fetches the notarisation ticket once), or when the file is not the original. Download the archive again and check its SHA-256 against SHA256SUMS, or use the installer script, which verifies the checksum for you. On an Intel Mac use the x64 build; on Apple silicon the arm64 build.

The settings are not next to the executable

When the folder holding the executable cannot be written (Homebrew, /usr/local/bin, Program Files, a .pkg install) the data folder moves to the user's application-data folder: ~/Library/Application Support/tamidas-modbus-simulator on macOS, ~/.local/share/tamidas-modbus-simulator on Linux, %APPDATA%\TamidaS\modbus-simulator on Windows. The console prints the folder in use at start; MODBUS_SIM_DATA overrides it.

On Linux the serial port cannot be opened ("permission denied")

Your user is not allowed to use the adapter. Add it to the dialout group (sudo usermod -aG dialout $USER), log out and in again, and Start the slave. The same applies to /dev/ttyACM0 devices.

The tab says "Port 502 is already in use"

Another program (or another slave with a different bind host) is listening on that port. Edit the slave and pick another port, or stop the other program.

The master times out on TCP

Check that the slave is live (green dot), that the master uses the address shown in the summary line, and that the Windows firewall allows the port. Requests that reach the simulator always appear in the log, so an empty log means the connection never arrived.

Values read by the master are wrong

Compare the master's raw registers with the Raw words column. If the words match but the value does not, change the byte order or data type. If the words differ, the master is reading a different address — remember 0- vs 1-based.

The master reads a block and gets exception 02

The block covers an address you have not defined and the slave's Read unmapped is set to Exception 02. Add the missing registers or switch the setting to Return 0.

A value I set keeps changing

The register is in random or increment mode. Set the mode to fixed, or type the value — typing sets fixed automatically.

A Modbus ASCII master gets no answer, or the log shows bad-lrc

Both ends must use the same mode and the same line settings. bad-lrc with readable text in the Request column usually means a data-bits or parity mismatch (the standard for ASCII is 7E1); unreadable text means the master is sending RTU frames to an ASCII slave. An RTU slave that receives ASCII frames logs bad-crc instead. Switch the slave's protocol in ✎ Edit slave — the serial port and register map are kept.

Auto-detect does not find my USB adapter

Auto-detect looks for common USB serial names at start time. Press ↻ in the port list, select the COM port explicitly and Start the slave again.

Where are the log and the settings after I closed the program?

Settings and registers are in the data folder next to the executable; the request log is not saved.

Modbus Simulator documentation | Modbus Logic