EM·LINK
Universal Device Terminal - a single HTML file that talks to devices over USB serial or WiFi (WebSocket or MQTT over WebSocket), decodes industrial protocols, plots telemetry, and carries a suite of engineering calculators.
No install. No account. No server. Nothing you connect to, capture or calculate leaves your machine.
Quick start
- Open EM·LINK in a modern browser. For USB serial use desktop Chrome or Edge, which provide
the Web Serial API; WebSocket, MQTT, the simulator and the tools work in any modern browser.
- Pick a transport in the sidebar.
- Press CONNECT.
No hardware to hand? Choose SIMULATOR and connect. It streams synthetic telemetry, ANSI-coloured log lines, GNSS sentences, Modbus RTU frames and J1939 CAN frames, so every feature can be explored with nothing plugged in.
If you see a red banner
USB serial uses the Web Serial API, which needs a secure context and a desktop Chromium-based browser (Chrome or Edge). Opening the file directly with file:// works in some browser builds and not others. If the banner appears in Chrome or Edge, serve the file over local HTTP instead:
python3 -m http.server 8000
localhost counts as secure, so everything works from there. On phones, Safari and Firefox the banner says USB serial is not available there and the USB SERIAL option is greyed out; WebSocket, MQTT, the simulator and every tool still work.
Browser support
| Feature | Desktop Chrome / Edge | Safari, Firefox, phones |
|---|---|---|
| USB Serial | yes | not available |
| WebSocket · MQTT | yes | yes |
| Tools · plotter · decoders | yes | yes |
USB serial needs the Web Serial API, which not every browser family implements. Everything else - the tool suite, the decoders, the plotter, the docs - works in any modern browser.
Themes
Three: OCEAN (navy + blue), SIGNAL (near-black + orange), and FIELD (light, for projectors and well-lit rooms). The choice persists across visits.
Transports
Three links and a simulator, one interface. Everything downstream - terminal, plotter, decoders, logging, file transfer - behaves identically no matter which you pick.
USB Serial
Uses the Web Serial API. Click CONNECT and the browser shows its own port picker; the page never sees ports you have not explicitly granted.
- Baud 300 to 1 500 000, or AUTO DETECT
- Frame 7/8 data bits, 1/2 stop bits, none/even/odd parity
- Flow control none or RTS/CTS
Granted ports appear in PREVIOUSLY GRANTED on later visits, so you can reconnect without the picker. ⟳ REFRESH PORTS re-reads that list.
Auto-baud detection
Select ◈ AUTO DETECT. The scan opens each rate from fastest to slowest, listens for about 1.1 s, and prints what it found:
AUTO-DETECT: scanning 17 rates for "BOOTING"…
1500000 → 0 B, printable 0%
921600 → 43 B, printable 12%
115200 → 512 B, printable 99%
AUTO-DETECT: matched "BOOTING" at 115200.
Give it a search word of six characters or more taken from your boot banner and it stops on the first exact match. Leave the word blank and it falls back to picking the rate with the highest proportion of printable bytes. The full scan table is printed either way, so you can judge the result rather than trust it.
WiFi - WebSocket
Point it at a device running a WebSocket server. A few lines of firmware get you a bidirectional link with no relay and no cloud.
Binary and text frames are both accepted and handed to the terminal as bytes.
Mixed content: a page served overhttps://may only openwss://. If you serve EM·LINK over HTTPS and your device speaks plainws://, the browser blocks it. Open EM·LINK overhttp://localhostinstead, or terminate TLS at the device.
WiFi - MQTT over WebSocket
Subscribes to a topic and prints each message as a line; transmitting publishes to a second topic.
The broker must expose a WebSocket listener - the plain 1883 TCP port will not work from a browser. A typical broker configuration:
listener 9001
protocol websockets
PREFIX LINES WITH TOPIC puts [embedos/plant1/telemetry] in front of each message, which matters when a wildcard subscription is pulling from many devices at once.
The MQTT client library is fetched from a CDN on first use, so this transport needs internet access even when the broker is local.
Simulator
Generates a synthetic device: boot messages with ANSI colour, four telemetry channels, periodic WARN and ERROR lines, checksum-valid GNSS sentences, CRC-valid Modbus RTU frames and J1939 CAN frames. Transmitted commands are echoed back with ACK.
Terminal
Display formats
- ASCII - text with ANSI colour and cursor handling
- HEX - offset, 16 bytes per row, ASCII gutter
- BIN - the same layout in binary
Switching format changes only the display. Line counting, plotting and every decoder keep running on the byte stream underneath, so nothing is lost by looking at hex for a while.
ANSI / VT100
With ANSI / VT100 COLOUR on, the terminal handles:
- SGR colour - the 16 base colours, 256-colour (
38;5;n) and truecolor (38;2;r;g;b) - Bold, dim, italic, underline, inverse
\rcarriage return as an overwrite, so progress bars and spinners render as intended rather
than scrolling off the screen
\bbackspace, tab stops every 8 columnsESC[Kerase line,ESC[2Jclear screen,ESC[GandESC[Hcolumn addressing^Gbell - flashes the terminal when BELL ON ^G is enabled
Turn ANSI off to see the raw escape sequences, which is the faster way to debug firmware that is emitting them incorrectly.
UTF-8
UTF-8 DECODE uses a streaming decoder that keeps multi-byte sequences intact across chunk boundaries - without it, a → arriving split across two reads renders as â. Turn it off for strictly binary or latin-1 protocols.
Raw keyboard mode
RAW KEYBOARD (INTERACTIVE) sends keystrokes straight down the link instead of using the transmit box. This is what makes interactive serial consoles (a bootloader prompt, a Linux login shell, an AT command shell) usable:
| Key | Sends |
|---|---|
Ctrl+A … Ctrl+Z | 0x01 … 0x1A, so ^C, ^D, ^Z all work |
| Arrows | ESC[A ESC[B ESC[C ESC[D |
| Home / End | ESC[H / ESC[F |
| Delete / PgUp / PgDn | ESC[3~ / ESC[5~ / ESC[6~ |
| Tab / Escape | 0x09 / 0x1B |
| Backspace | ^? (127) or ^H (8) - configurable |
Pasting sends the clipboard contents down the link. Click into the terminal first so the transmit box does not have focus.
BACKSPACE SENDS exists because the two conventions are genuinely split: most Unix-like systems expect ^?, while many embedded monitors and older systems expect ^H. If backspace prints ^H or deletes the wrong character, switch it.
Other terminal options
- LOCAL ECHO - echo typed characters locally, for links that do not echo back
- ECHO TX IN TERMINAL - show transmitted lines prefixed with
» - TIMESTAMPS - millisecond timestamps on every line
- SCROLLBACK LINES - how much history to retain
Transmit
Type into the transmit box and press Enter. ↑ / ↓ walk command history.
TX LINE ENDING appends LF, CR, CRLF or nothing. AT-command modems generally want CR; Unix shells want LF; many industrial devices want CRLF.
MACROS are four editable command buttons, saved in the browser.
Plotter
Any line containing KEY: value or KEY = value becomes a plot channel automatically:
TEMP0: 24.5
PRESSURE = 3.412
RPM: 1670
GRAPH opens the plot area; + VIEWPORT adds another. Each viewport has:
- Channel chips - click to show or hide each channel
- Time range - 10 s to 15 min
- NORM - normalise each channel to its own 0–100% band
- CSV - export just that viewport's channels
- ✕ - remove the viewport
When to use NORM
A shared Y axis is useless the moment magnitudes differ. Plot TEMP: 24 next to heap=27811 and the temperature is a flat line at the bottom. NORM maps each channel onto its own range so you can compare shape - when things move together, which leads which - rather than absolute value. Turn it off to read real numbers.
Decoders
GNSS / NMEA
Parses RMC, GGA, GSA, GSV, GLL, VTG and TXT with checksum validation. Invalid sentences are dropped silently rather than corrupting the fix.
GPS POPUP opens a draggable panel with a live map and track trail, position, altitude, speed, fix type, satellite count, HDOP, UTC, a course-over-ground compass and per-satellite SNR bars. ⧉ copies the coordinates.
The map uses OpenStreetMap tiles. With no internet it falls back to a self-drawn track plot with a scale grid, so the trail is still visible offline.
Modbus RTU
RTU has no start delimiter. Frames are separated only by an idle gap of at least 3.5 character times, which is why naive decoders produce garbage on a busy or mixed line.
This decoder does what a protocol analyser does:
- For each position in the buffer, work out which ADU lengths the function code permits - a
read-holding-registers request is 8 bytes, its response is 3 + byte_count + 2, an exception is 5.
- Test CRC-16 on each candidate length.
- On a match, emit the frame and jump past it. On no match, slide one byte and try again.
The result resyncs on a noisy bus and pulls valid frames out of a stream that also carries ASCII logging. Frames whose CRC fails are only reported if they at least look like an ADU - a valid slave address and a known function code - so random text does not fill the table.
Decoded function codes: 1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 15, 16, 17, 20, 21, 22, 23, 43, plus all exception responses by name.
MODBUS FRAME GAP sets the idle timeout used to flush the tail of the buffer. Six milliseconds suits 9600–115200 baud; raise it on slow links.
CAN / J1939
Accepts two text formats, auto-detected:
t1238001122334455667788 SLCAN, 11-bit
T0CF004008F07D7D1027000000 SLCAN, 29-bit
can0 18FEE500 [8] 10 27 00 00 50 C3 00 00
(1707.123) can0 0CF00400#F07D7D1027000000
29-bit identifiers are decoded to priority, data page, PDU format, PDU specific, PGN, source address and destination address per J1939.
GROUP BY ID collapses the table to one row per identifier with a message counter, which is how you read a live bus. Turn it off for a chronological trace.
Files
A local file store backed by IndexedDB. Files live in your browser and are never uploaded.
- ▲ ADD FILES or drag and drop
- DOWNLOAD · VIEW · DELETE
- SEND - stream the file down the link in 512-byte chunks
- XMODEM - transfer with acknowledgement and error checking
Captured session logs and converted firmware images land here too.
XMODEM
Implements XMODEM with 128-byte blocks and either CRC-16 or the simple checksum, chosen by whatever the other end asks for. Both directions are supported.
Sending: start the receiver on the target first (rx filename or your bootloader's equivalent), then pick the file. EM·LINK waits for the receiver's C or NAK handshake, then streams blocks, retrying any the receiver rejects. Progress shows in the bar at the bottom.
Receiving: click ◈ XMODEM RECEIVE, name the file, then start the sender on the target. EM·LINK sends C every three seconds until the transfer begins, and saves the result to the file store when it sees EOT.
Logging and export
Log modes
| Mode | Captures |
|---|---|
| All session output | every line, as displayed |
| Printable output only | strips control characters |
| Raw hex dump | offset, hex bytes, ASCII gutter |
| None | nothing |
AUTO-CAPTURE TO FILE STORE saves the log automatically when the link closes.
Exports
EXPORT or Ctrl+S:
| Format | Contents |
|---|---|
.txt | session log with a header of link details and counters |
plot .csv | wide table, one column per channel, forward-filled to a shared time axis |
Modbus .csv | every decoded frame with CRC status and raw bytes |
CAN .csv | every frame with ID, PGN, source address, DLC and data bytes |
The plot CSV is deliberately a wide table - one row per timestamp, one column per channel, values forward-filled. That form drops straight into a spreadsheet or data-frame library without reshaping.
Sessions
A named session profile stores every transport setting, decoder toggle, terminal option, theme and macro. SAVE AS creates one, LOAD restores it, ⚙ MANAGE SESSIONS lists, overwrites, deletes, exports and imports them.
Export produces a JSON file you can commit to a repo or hand to a colleague, so a whole team can share the exact settings for a given rig.
Passwords are not stored in session profiles.
Keyboard shortcuts
| Shortcut | Action |
|---|---|
Ctrl+S | export session log |
Ctrl+L | clear terminal |
Ctrl+ + / Ctrl+ - | font size |
↑ / ↓ | command history in the transmit box |
In raw keyboard mode Ctrl combinations go to the device instead, as they should.
Limits in this version
| Item | Limit |
|---|---|
| Saved sessions | 3 |
| File store | 10 files, 10 MB in total |
| Plot viewports | 2 |
| Plot channels | 8 at once |
| Plot history | 15 minutes |
| Scrollback | 20 000 lines |
When you reach a limit, EM·LINK says which one, for example Limit reached in this version (3 saved sessions).
Tool methods and derivations
The tool suite is the piece that separates EM·LINK from generic calculator sites - every number is traceable to a published standard, and this section shows the derivation for each. The formula inside the tool is the one-liner; this is where the piecewise ranges, ancillary equations, and verified reference points live.
Number & Bit Inspector
Bit-level view of any 8/16/32/64-bit value. Bases, IEEE-754 field breakdown, click-to-toggle bits, endian swap.
IEEE-754 float decomposition. A float bit pattern splits into sign, exponent and mantissa:
value = (-1)^s · (1 + m / 2^n_m) · 2^(e - bias)
For 32-bit floats: sign = bit 31, exponent = bits 30…23 (bias 127), mantissa = bits 22…0. For 64-bit: sign = bit 63, exponent = bits 62…52 (bias 1023), mantissa = bits 51…0.
Two's-complement signed interpretation flips the top bit's weight from positive to negative, so an N-bit value is:
signed = unsigned - 2^N if the MSB is set, else unsigned
CRC & Checksum Suite
13 preset polynomials plus a custom-poly mode. All match the published check values of the CRC catalogue for the standard test string 123456789.
General polynomial CRC. For a width-w CRC with polynomial p, initial value init, input reflection rin, output reflection rout, and final XOR xor:
crc = init
for each byte b:
if rin: b = reflect(b, 8)
crc = crc XOR (b << (w - 8))
repeat 8 times:
if MSB of crc set: crc = (crc << 1) XOR p
else: crc = (crc << 1)
crc = crc AND ((1 << w) - 1)
if rout: crc = reflect(crc, w)
crc = crc XOR xorVerified reference points - CRC of ASCII 123456789:
| Preset | Expected |
|---|---|
| CRC-16/MODBUS | 0x4B37 |
| CRC-16/CCITT-FALSE | 0x29B1 |
| CRC-16/XMODEM | 0x31C3 |
| CRC-32 (zlib) | 0xCBF43926 |
Also computes the simpler checksums used in the same protocols: XOR-8 (as in the GNSS-sentence checksum), SUM-8, LRC (as in the Modbus-ASCII trailer), Fletcher-16.
Modbus Register Interpreter
The word-order problem, solved. Modbus transports 16-bit registers, but 32-bit floats and integers have four possible byte arrangements depending on how the device firmware packed them. The tool shows all four side by side, so the correct one is immediately obvious.
The four orderings. Given two consecutive 16-bit registers R0 (bytes A B) and R1 (bytes C D):
| Order | Byte layout in memory | Common name |
|---|---|---|
| ABCD | A B C D | big-endian, standard IEEE-754 network order |
| CDAB | C D A B | word-swapped |
| BADC | B A D C | byte-swapped |
| DCBA | D C B A | fully reversed, little-endian |
The float is then decoded per IEEE-754 from those four bytes. If the reading is 1e-40 or 1e38, the word order is wrong - try CDAB, which is the most common mismatch.
Also decodes as int16, int32 both orderings, uint32 both orderings, and treats each register byte as ASCII.
Fixed-Point Q Converter
Convert real values to and from Qm.n fixed-point integers.
Conversion. A Qm.n value has m integer bits and n fraction bits (plus a sign bit if signed):
raw = round(x · 2^n) back = raw · 2^-n resolution = 2^-n range signed: -2^m … 2^m - 2^-n range unsigned: 0 … 2^(m+1) - 2^-n
If raw exceeds the range, the value saturates and quantisation error grows unboundedly - the tool flags this as SATURATED.
Example. Q15 (0 int, 15 fraction, signed, 16 bits total) is the most common DSP format for audio and control loops. 0.75 in Q15 is round(0.75 · 32768) = 24576 = 0x6000. Multiplying two Qm.n values gives Q2m.2n; shift right by n to get back to Qm.n.
C Struct Layout & Padding
Paste a struct definition, get real byte offsets and inserted padding. Also reports the byte savings from reordering members widest-first.
Alignment rules. Each member aligns to its own natural size:
offset(m_i) = smallest offset ≥ sum(size(m_j) + pad_j) for j < i
such that offset(m_i) mod align(m_i) = 0The struct itself aligns to its widest member, so trailing padding may be added at the end to make the struct size a multiple of that alignment. This is why an array of the struct works correctly - each element's members land on their natural alignment.
Target ABI. 32-bit ARM: long and pointers are 4 bytes, aligned to 4. 64-bit x86-64 or AArch64: long and pointers are 8 bytes, aligned to 8.
Common example. A struct of uint8, uint32, uint8, float, uint16 on 32-bit ARM ends up 20 bytes with 8 bytes of padding. Reordering widest-first (uint32, float, uint16, uint8, uint8) gives 12 bytes with 0 padding. On a 1000-record log buffer that's 8 kB of RAM saved.
Intel HEX / SREC Inspector
Parses Intel HEX and Motorola S-record firmware files. Validates every record's checksum, maps the contiguous segments, computes the image CRC-32, and converts to raw .bin with 0xFF gap fill (matching erased flash).
Intel HEX record structure. Each line is :LLAAAATTDD…DDCC where LL is data length, AAAA is the 16-bit address, TT is the record type (00 data, 01 EOF, 02 extended segment, 04 extended linear, 05 start linear), and CC is the two's-complement of the sum of every preceding byte. The checksum passes when the sum of all bytes on the line (including CC) mod 256 equals zero.
S-record checksum is the one's complement of the sum of the length, address and data bytes. Passes when the sum of all bytes mod 256 equals 0xFF.
Extended addressing. Record type 02 shifts the base address by 16; type 04 sets the upper 16 bits of a 32-bit address. Both are tracked so a firmware image that crosses a 64 KB boundary decodes to the correct absolute addresses.
MQTT Topic Matcher
Test wildcard subscription filters against a list of topics before deploying to a fleet.
Match rules. Split filter and topic on /. Compare level-by-level:
- Literal segment matches only the identical segment.
+matches exactly one level, any content.#matches everything from that position on, and is only valid as the last segment.- Filter and topic must have the same number of levels unless the filter ends in
#.
The $ prefix on system topics is treated specially by most brokers - wildcards do not cross it. # alone subscribes to everything, which should never be used in production.
4–20 mA / 0–10 V Loop Scaling
Full analogue-front-end arithmetic: sense-resistor voltage, ADC counts, engineering units, resolution per count, and wire-break detection.
Current-to-voltage. For a current loop with sense resistor R:
V = I · R counts = (V / V_ref) · (2^N - 1) EU = EU_min + ((I - I_min) / (I_max - I_min)) · (EU_max - EU_min)
Wire-break detection per NAMUR NE 43. For a 4-20 mA loop:
- I < 3.6 mA → wire break or under-range fault
- 3.6 ≤ I < 3.8 → under-range
- 3.8 ≤ I ≤ 20.5 → normal
- I > 20.5 → over-range
- I > 21 → over-range fault
Sizing the sense resistor. For a 3.3 V ADC reference, a 165 Ω sense resistor makes 20 mA land exactly at V_ref (using the full ADC span cleanly). The traditional 250 Ω is intended for a 5 V system, where 20 mA gives 5 V; on a 3.3 V ADC that clips.
NTC Thermistor
Resistance-to-temperature both directions, with divider counts and self-heating.
Beta model - two-point fit, reasonable across a narrow range around the reference point:
1/T = 1/T_0 + (1/B) · ln(R / R_0) where T, T_0 are in kelvin
Steinhart-Hart - three-term fit, accurate over much wider ranges:
1/T = A + B · ln(R) + C · (ln(R))^3
To solve for R at a given T, iterate the cubic numerically (the tool uses a bisection over ln(R)). Beta drifts several degrees at the ends of a wide temperature range; use Steinhart-Hart beyond about −20…+80 °C.
Divider output. With the NTC on the low side, series resistor R_s to V_ref, ADC on the NTC:
V_out = V_ref · R / (R + R_s) counts = (V_out / V_ref) · (2^N - 1)
Self-heating. Current through the NTC dissipates power that raises its own temperature and biases the reading. Typical dissipation coefficient is ~1 mW/°C in still air, so a 3.3 V divider across 10 kΩ dissipating ~0.3 mW adds ~0.3 °C to the reading. Keep it under 1 mW for laboratory work.
RTD PT100 / PT1000
Callendar-Van Dusen both directions, including the sub-zero cubic term that linear approximations get wrong.
Callendar-Van Dusen equation per the International Electrotechnical Commission's temperature-sensor standard (IEC 60751):
T ≥ 0 °C: R = R_0 · (1 + A·T + B·T^2)
T < 0 °C: R = R_0 · (1 + A·T + B·T^2 + C·T^3·(T - 100))
where R_0 = 100 Ω for PT100, 1000 Ω for PT1000
A = 3.9083 × 10^-3
B = -5.775 × 10^-7
C = -4.183 × 10^-12Inverse. Above 0 °C, the quadratic has a closed-form solution:
T = (-R_0·A + sqrt(R_0^2·A^2 - 4·R_0·B·(R_0 - R))) / (2·R_0·B)
Below 0 °C, the cubic term prevents a closed form; the tool uses the quadratic as a seed and refines with Newton's method to convergence.
Verified reference points per IEC 60751:
| Temperature | PT100 resistance |
|---|---|
| −200 °C | 18.5201 Ω |
| 0 °C | 100.0000 Ω |
| 100 °C | 138.5055 Ω |
| 850 °C | 390.481 Ω |
Lead-wire error. A 2-wire configuration adds twice the one-way lead resistance directly to the reading. At 0.5 Ω/leg that's 1 Ω, which shifts a PT100 reading by ~2.5 °C. 3-wire cancels this provided all three legs match; 4-wire is immune.
Excitation self-heating. At 1 mA through a 100 Ω sensor, dissipation is 0.1 mW, which raises the sensor about 0.005 °C in still air. Above 1 mA the effect starts to matter for precision work.
Thermocouple K / J
Full NIST ITS-90 polynomials both directions, with cold-junction compensation.
Direct (temperature to millivolts). The National Institute of Standards and Technology publishes piecewise polynomial coefficients for each thermocouple type:
emf(T) = sum(c_i · T^i) for i = 0…n
Type K above 0 °C adds an exponential correction:
emf(T) += a_0 · exp(a_1 · (T - a_2)^2)Type K is piecewise across −270…0 °C and 0…1372 °C. Type J across −210…760 °C and 760…1200 °C. Coefficients are the ITS-90 reference table values.
Inverse (millivolts to temperature). A separate set of piecewise polynomial coefficients maps EMF back to temperature, split at 0 mV and, for K, at 20.644 mV.
Cold-junction compensation. A thermocouple only measures the difference between its two junctions. If the measurement circuit sits at 25 °C, the reading is low by the EMF that a K junction would produce at 25 °C - about 1 mV, or ~25 °C worth.
emf_absolute = emf_measured + emf(T_cold_junction) T_hot = inverse(emf_absolute)
Skipping this step is the classic ~25 °C error people find in hand-rolled thermocouple code.
Verified reference points per NIST ITS-90:
| Type | Temperature | EMF |
|---|---|---|
| K | 100 °C | 4.096 mV |
| K | 500 °C | 20.644 mV |
| K | 1000 °C | 41.276 mV |
| J | 100 °C | 5.269 mV |
| J | 500 °C | 27.393 mV |
ADC Resolution & Noise
LSB size, effective bits (ENOB), noise-free bits, and how much oversampling actually buys.
Ideal SNR of an N-bit converter:
SNR_ideal = 6.02 · N + 1.76 dB
Effective bits from measured noise. Given noise as RMS microvolts:
noise_LSB = noise / LSB_size ENOB = N - log2(noise_LSB · sqrt(12))
The sqrt(12) factor converts RMS noise to the equivalent peak-to-peak range for a Gaussian process, which matches the quantisation error convention.
Noise-free bits is the more conservative figure - the resolution you can quote in a datasheet without qualification:
NFB = floor(log2(2^N / (noise_LSB · 6.6)))
The 6.6 factor is the standard peak-to-peak-to-RMS ratio for a 99.9 % confidence bound.
Oversampling gain. Each 4× in sample rate adds 1 bit of resolution:
gain_bits = log2(oversample_ratio) / 2
This only works if the noise is at least 1 LSB - noise itself acts as the dither. A perfectly quiet input gains nothing from oversampling.
UART Baud Rate Error
Divisor register, actual baud, and error percentage for common register formats. Reproduces the well-known bad combinations that explain why certain "odd" crystal frequencies exist.
Standard divisor. For a peripheral clock f_clk and target baud b:
divisor = round(f_clk / b) actual = f_clk / divisor error = (actual - b) / b
With 16× or 8× oversampling (the two major register formats):
16×: divisor = round(f_clk / (16·b)) - 1 (register value)
actual = f_clk / (16 · (divisor + 1))
8×: divisor = round(f_clk / (8·b)) - 1
actual = f_clk / (8 · (divisor + 1))Error budget. A UART resynchronises only on the start bit, then samples in the middle of each bit for the rest of the frame. By the stop bit, error has accumulated across ~10 bit times. Each end has its own error; the combined figure must stay under ~50 % of a bit period.
Verified reference point. At a 16 MHz clock with 115200 baud and 16× oversampling:
- Standard mode: −3.55 % error, will drop frames
- Double-speed mode (8×): +2.12 % error, marginal but usable
- With an 11.0592 MHz crystal instead: 0.00 %, which is why this "odd" frequency exists
I²C Pull-Up Calculator
Minimum and maximum pull-up resistor per the I²C specification, plus the E24 value closest to the geometric mean.
Minimum - set by sink current the low driver can pull:
R_p(min) = (V_DD - V_OL) / I_OL
Typical I²C receivers guarantee 3 mA sink at V_OL = 0.4 V, giving R_p(min) ≈ (3.3 - 0.4)/0.003 ≈ 970 Ω at 3.3 V.
Maximum - set by bus capacitance and required rise time:
R_p(max) = t_r / (0.8473 · C_b)
t_r limits:
Standard mode (100 kHz): 1000 ns
Fast mode (400 kHz): 300 ns
Fast mode plus (1 MHz): 120 nsThe 0.8473 factor is ln(0.7/0.3) - the number of RC time constants between the 30 % and 70 % of V_DD points that UM10204 uses to define I²C rise time.
When no pull-up works. If R_p(max) < R_p(min), the bus is over-capacitance for that speed - you must shorten the bus, split it with a repeater, or drop to a slower mode. Bus capacitance is roughly 10 pF per device plus 1 pF per cm of trace; the specification caps it at 400 pF for Standard and Fast mode and 550 pF for Fast-mode Plus.
RS-485 Termination & Bias
Fail-safe bias resistor, cable-length limit, stub-length limit, unit-load budget.
Bias resistors. A pair of resistors from the differential pair to V_CC and ground respectively, providing enough current through the termination network to hold ≥ 200 mV differential when the bus is idle.
V_diff = V_CC · R_load / (2·R_bias + R_load)
R_load = parallel(R_term_effective, sum of receiver input impedances)
= 1 / (1/(Z_0/n_terminators) + 1/(12 kΩ / UL / n_nodes))
Rearrange for R_bias:
R_bias = (V_CC · R_load / V_diff_min - R_load) / 2Length-rate product - an empirical rule for the maximum reliable cable length at a given data rate:
length · rate ≤ 10^8 m · bps
Stub length - 20 % of the round-trip time at the data rate, conservatively:
stub_max = 0.2 · (2 · 10^8 / rate) metres
Unit load budget. A standard transceiver presents 1 UL (12 kΩ) to the bus. The specification allows up to 32 UL. Reduced-load transceivers present ½, ¼ or ⅛ UL, allowing 64, 128 or 256 nodes.
Timer & PWM Register Calculator
Ranked prescaler / period pairs for a target output frequency, with the PWM resolution each pair leaves you.
Frequency equation. A typical hardware timer has a prescaler PSC and an auto-reload period ARR:
f_out = f_timer / ((PSC + 1) · (ARR + 1)) resolution = log2(ARR + 1) bits duty_register = (ARR + 1) · duty%
Prefer the pair with the largest ARR - resolution is what you lose when the prescaler is too aggressive. At ARR = 4200 (~12 bits), duty steps in ~0.024 %. At ARR = 42, they step in 2.4 %.
Wire Gauge & Voltage Drop
Loop voltage drop for field wiring and 4–20 mA compliance-voltage budgets.
Wire diameter. American Wire Gauge is defined logarithmically:
d_mm = 0.127 · 92^((36 - AWG) / 39) area_mm² = π/4 · d²
Copper resistance with temperature correction (α = 0.00393 per °C):
ρ = 1.724 × 10^-8 · (1 + α · (T - 20)) Ω · m R_per_metre = ρ / (area · 10^-6) R_loop = R_per_metre · length · 2 (out and back) V_drop = I · R_loop P_loss = I² · R_loop
4-20 mA compliance-voltage budget. For a supply V_S driving a loop with cable drop V_drop and a sense resistor R_sense:
V_transmitter = V_S - V_drop - I · R_sense At 20 mA with V_S = 24 V, 100 m of AWG 22 (copper at 25 °C), and R_sense = 250 Ω: R_loop ≈ 10.8 Ω V_drop ≈ 0.22 V V_available at transmitter ≈ 24 - 0.22 - 5 = 18.8 V
Most industrial transmitters need at least 12 V compliance, so 6.8 V of margin is comfortable.
Privacy
Everything runs in the page. There is no backend, no telemetry and no account.
| Data | Where it lives |
|---|---|
| Session logs, plot data, decoded frames | memory, until you clear or close the tab |
| Files, captured logs | IndexedDB, in your browser |
| Sessions, macros, theme | localStorage, in your browser |
Some features load files from the internet, only when you use them, so they need a connection: the MQTT and GPS map libraries come from unpkg.com, map tiles come from OpenStreetMap, and the fonts come from Google Fonts. Everything else runs without a network connection.
Troubleshooting
Red banner about USB serial. USB serial needs desktop Chrome or Edge. Serve over http://localhost instead of opening the file directly. WebSocket, MQTT, the simulator and the tools work without it.
Port picker is empty. The device is not enumerating. Check the cable - many are charge-only - and confirm the USB-serial driver is present. On Linux, add yourself to dialout and log back in.
Connected but nothing arrives. Wrong baud rate is the usual cause; try AUTO DETECT. Then check TX and RX are not swapped, and that both ends share a ground.
Text is mojibake. Baud rate is close but wrong - the framing survives, the bits do not. AUTO DETECT resolves it.
Progress bars scroll instead of updating. ANSI is switched off, so \r is being ignored.
Modbus table is empty. Confirm the traffic really is RTU and not ASCII - RTU is binary, and ASCII frames start with a colon. Raise the frame gap on slow links.
CAN table is empty. The adapter is probably emitting a binary protocol rather than SLCAN or candump text. Put the terminal in HEX and look at what actually arrives.
Verification summary
Every calculator is tested against published reference values, not eyeballed. The main ones:
| Check | Expected | Source |
|---|---|---|
Modbus CRC of 01 04 02 FF FF | B8 80 | canonical test vector |
CRC-16/MODBUS of 123456789 | 0x4B37 | CRC catalogue |
CRC-32 of 123456789 | 0xCBF43926 | CRC catalogue |
XMODEM CRC-16 of ABC | 0x3994 | XMODEM specification |
J1939 ID 0x0CF00400 | PGN 61444 (EEC1) | SAE J1939-71 |
| PT100 at 0 / 100 / −200 °C | 100.0000 / 138.5055 / 18.5201 Ω | IEC 60751 |
| Type K at 100 / 500 / 1000 °C | 4.096 / 20.644 / 41.276 mV | NIST ITS-90 |
| UART baud at 16 MHz / 115200 (16× / 8×) | −3.55 % / +2.12 % | standard divisor equation |
If any calculator ever produces a number that disagrees with its cited standard, that is a bug in the tool - please report it.