quick-and-dirty waveform viewer in JS

Aug 29, 2026 Last reply: 4 days ago 6 Replies

I was thinking about bit-banging NRZI signaling on a microcontroller with HDLC-style bit stuffing, the idea being that I could maybe tolerate larger clock speed discrepancies than with conventional asynchronous serial, and I realized I didn’t really have a good way to visualize the waveforms.



So I hacked together the following goofy encoder and waveform viewer, which is online at

formatting link
.Dedicated to the public domain, CC0, from Argentina.



Feedback is welcome. I don’t know much about electronics, but I’m eager to learn.



Kragen



<!-- /* --><!DOCTYPE html>
<html lang="en"> <!-- for hyphenation -->
<title>NRZI waveform display with HDLC-like bit stuffing</title>



<h1>NRZI waveform display with HDLC-like bit stuffing</h1>


<div class="textbox">


</div>



<canvas id="theCanvas"></canvas>

I was thinking about using HDLC-like bit stuffing with NRZI for a project, and I wanted to see what the resulting waveforms looked like and have an easy way to try encoding different Unicode text strings. (My theory is that this encoding not only guarantees transitions more often than conventional asynchronous serial data with start bits and stop bits, it’s also more forgiving of timing error.) So I whipped up this DHTML SPA, inspired by Sigrok Pulseview, which is better-looking and more full-featured. It uses little-endian bit order.



To see the bit-stuffing in action, you need to have five consecutive 1 bits in your unstuffed bitstream. ASCII characters with five consecutive 1 bits inside the same byte include ^_ (control underscore, US), DEL, and “>?_|}~”. Non-ASCII characters include “¿”, because in UTF-8 that’s c2 bf, and the two high bits of c2 are both set, and they come right before the six low bits of bf, which are also all set. With non-ASCII characters, you can also get runs of five 1 bits that cross characters, as in “áo”, where the low 4 bits of “o” 6f follow the high bit of the second byte of “á”, c3 a1.



<h2>Notes on trying to use AI</h2>

Last night on my cellphone in bed, I tried to get Claude Haiku to write the program for me. After an hour of prompting and code review, it had 250 lines of code that almost worked — displaying waveforms, but not correctly. This was pretty impressive for not having tested it, but still not really what I wanted.



So, in an hour and a half more, I got this waveform viewer working better than what it had produced, in... about the same amount of code, actually. And in a total of about two hours I had something more or less serviceable for my immediate purpose. So, maybe I could have gotten the AI to do it just as fast? I don’t know.



I did learn about the TextEncoder class and the “input” event on &lt;input> elements from the bot.



Brain fart; this makes no sense and should have said something like, “My theory is that this encoding not only wastes less bandwidth than conventional asynchronous serial data with start bits and stop bits, it also guarantees transitions more often, making it more forgiving of timing error.”

Those responsible for the error have been sacked.

Kragen

And how does visualization provide any benefit beyond the written description? It's not exactly very complicated. As for bit stuffing, you can't use it with a protocol that doesn't explicitly recognize it. That's not much of a limitation because quite a few of them do. In generic protocols without bit stuffing, the conflict is fixed with "byte stuffing", allowing the mess to be cleaned up in software, and it requires reprogramming.

Thank you, Don Y! WaveDrom, and WaveJSON, look wonderful, and I should have used them, but I didn’t know about them. They support everything I needed, and much more as well.

For context, from

formatting link
:

For CLI use:

npx wavedrom --input source.json5 > output.svg

For simple web page use, apparently you `` and then `<body onload="WaveDrom.ProcessAll()">` to convert all your `` elements into timing diagrams.

The tutorial introduction you linked explains:

And gives this example:

{ signal: [{ name: "Alfa", wave: "01.zx=ud.23.456789" }] }

And the interactive editor link for it

formatting link
which looks great.

Kragen

It fits your "quick-and-dirty" description. It isn't infinitely versatile -- but, it is super easy to use to hack together "clean" and *consistent* illustrations without dragging out a straightedge.

Here's an idea. Given some time T

two transitions separated by T is a zero two separated by 4T is a 1 two separated by 15T is an idle, a filler.

That's pretty timing tolerant and is DC-balanced.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required