<?xml version="1.0" encoding="utf-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#">
<link rel="alternate" type="text/html" href="https://emergent.unpythonic.net/"/>

<title>Jeff Epler's blog</title>
<modified>2026-07-30T14:39:05Z</modified>
<tagline>Photos, electronics, cnc, and more</tagline>
<author><name>Jeff Epler</name><email>jepler@unpythonic.net</email></author>
<entry>
<title>More junkdrawer features</title>
<issued>2026-07-30T14:39:05Z</issued>
<modified>2026-07-30T14:39:05Z</modified>
<id>https://emergent.unpythonic.net/01785422345</id>
<link rel="alternate" type="text/html" href="https://emergent.unpythonic.net/01785422345"/>
<content type="text/html" mode="escaped">

&lt;p&gt;I've continued enhancing the static site generator for my &lt;a href=&quot;https://jepler.grebedoc.dev/junkdrawer/&quot;&gt;junkdrawer&lt;/a&gt; (github gist / pastebin replacement). The source code for the static site generator lives right in the same repo.&lt;/p&gt;
&lt;p&gt;One thing I missed was some kind of ability to preview PDFs that I have uploaded to the junkdrawer,
such as &lt;a href=&quot;https://jepler.grebedoc.dev/junkdrawer/u1hnis1w/&quot;&gt;this m6800 reference card&lt;/a&gt; that disappeared earlier this year from its original site.&lt;/p&gt;
&lt;p&gt;Initially, I tried to directly show the PDF as an &lt;code&gt;embed&lt;/code&gt; or &lt;code&gt;object&lt;/code&gt; tag.
However, getting the embedded viewer properly sized was beyond what I wanted to tangle with.&lt;/p&gt;
&lt;p&gt;Instead, I took the same approach github does: Convert the first pages of the pdf to images and display them with the &lt;code&gt;img&lt;/code&gt; tag. This then gets the lightbox treatment from my mkdocs setup, so you can comfortably zoom the page image to its full 150dpi majesty.&lt;/p&gt;
&lt;p&gt;I have made the decision to not worry too much about specially-crafted PDF files that might exploit bugs in poppler's &lt;code&gt;pdftoppm&lt;/code&gt;: I'll have already locally viewed any PDF I'm putting in the junk drawer, so the Bad Thing will already have occurred. Anyway, the site generation process installs the latest packaged &lt;code&gt;pdftoppm&lt;/code&gt; so I'm also likely to have patches for known poppler flaws.&lt;/p&gt;
&lt;p&gt;The main downside I've identified is that the image is just an image and is therefore not searchable with the browser's search feature. Alas.&lt;/p&gt;

</content>
</entry>
<entry>
<title>junkdrawer gets a grebedoc page</title>
<issued>2026-07-23T00:09:29Z</issued>
<modified>2026-07-23T00:09:29Z</modified>
<id>https://emergent.unpythonic.net/01784765369</id>
<link rel="alternate" type="text/html" href="https://emergent.unpythonic.net/01784765369"/>
<content type="text/html" mode="escaped">

&lt;p&gt;I added machinery to my &lt;a href=&quot;https://codeberg.org/jepler/junkdrawer&quot;&gt;junkdrawer&lt;/a&gt; repo so that it also builds a &lt;a href=&quot;https://jepler.grebedoc.dev/junkdrawer/&quot;&gt;static website&lt;/a&gt; that's served by &lt;a href=&quot;https://grebedoc.dev/&quot;&gt;grebedoc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The code to do it is in the junkdrawer's &amp;quot;site&amp;quot; directory and it functions just great using the free codeberg-tiny runner for CI.&lt;/p&gt;

</content>
</entry>
<entry>
<title>Calling a Python function with a timeout</title>
<issued>2026-07-20T14:52:16Z</issued>
<modified>2026-07-20T14:52:16Z</modified>
<id>https://emergent.unpythonic.net/01784559136</id>
<link rel="alternate" type="text/html" href="https://emergent.unpythonic.net/01784559136"/>
<content type="text/html" mode="escaped">

&lt;p&gt;In Python 3.13+ with pyrepl, my &lt;a href=&quot;https://codeberg.org/jepler/pydc&quot;&gt;rpn
calculator&lt;/a&gt; can show the result of evaluating
some code while the user is entering it at the prompt.&lt;/p&gt;
&lt;p&gt;Most code is trivial (e.g., &lt;code&gt;3 4 5 * *&lt;/code&gt; to multiply some numbers together) but
complex code including recursion is possible. This can give code that runs for
quite a long time! It's one thing if this happens when you hit enter, but
another when there's the possibility that the repl freezes in the middle of
entering some code.&lt;/p&gt;
&lt;p&gt;There are various recipes for running Python code with timeout, but I wrote my
own. Then, just for extra fun, I made it properly type check with &lt;code&gt;ty&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I didn't integrate it into pydc yet but that part shouldn't be hard.&lt;/p&gt;
&lt;p&gt;See the docstring of the function for some additional caveats.&lt;/p&gt;

&lt;p&gt;(Embedded not available - View &lt;a href=&quot;https://codeberg.org/jepler/junkdrawer/src/commit/main/kvghgghs/timeout.py&quot;&gt;kvghgghs/timeout.py&lt;/a&gt; on codeberg.org or &lt;a href=&quot;https://codeberg.org/jepler/junkdrawer/raw/commit/main/kvghgghs/timeout.py&quot;&gt;download raw&lt;/a&gt;)&lt;/p&gt;
</content>
</entry>
<entry>
<title>The oldest bug I ever fixed? (no)</title>
<issued>2026-05-19T03:41:43Z</issued>
<modified>2026-05-19T03:41:43Z</modified>
<id>https://emergent.unpythonic.net/01779162103</id>
<link rel="alternate" type="text/html" href="https://emergent.unpythonic.net/01779162103"/>
<content type="text/html" mode="escaped">


&lt;p&gt;&lt;h2&gt;Correction&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Update, 2026-05-24&lt;/strong&gt;: It was an emulator bug. My friend tested on his hardware and the original comparison code works correctly.&lt;/p&gt;
&lt;h2&gt;Original post&lt;/h2&gt;
&lt;p&gt;I've been playing with Tom Pittman's Tiny BASIC for 6800 computers. It's a very simple, small, and early BASIC implementation. It is also almost as old as me, being &lt;a href=&quot;https://archive.org/details/dr_dobbs_journal_vol_01/page/n25/mode/2up&quot;&gt;announced by February 1976&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this BASIC, all numbers are 16-bit signed integers with a range of -32768 to 32767 inclusive.&lt;/p&gt;
&lt;p&gt;Anyway, while working in Tiny BASIC, I got some weird results and boiled it down to the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IF 32513 &amp;lt; 0 THEN PRINT &amp;quot;WAT&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This prints &amp;quot;WAT&amp;quot;, even though we usually consider 32513 to be greater than 0.&lt;/p&gt;
&lt;p&gt;After spending an evening and a morning with it, and comparing the implementation to Tom Pittman's Tiny BASIC for 6502 computers, I believe that this bug is in the original implementation, and not the emulator I'm using.&lt;/p&gt;
&lt;p&gt;The original version performs a 16-bit subtraction from two separate 8-bit subtractions; then, from the final flags value tries to determine whether the full result of the subtraction is greater to, less than, or equal to zero.&lt;/p&gt;
&lt;p&gt;This works for many inputs. However, for some particular input values, the CPU flags—which are only aware of the results of the &lt;em&gt;most significant byte of the subtraction&lt;/em&gt;—don't match up with the usual notions of comparison.&lt;/p&gt;
&lt;p&gt;The fix, which I've implemented in my version of Tiny BASIC, is to instead compare the MSBs first as signed numbers, then if they are equal, to compare the LSBs as unsigned numbers.&lt;/p&gt;
&lt;p&gt;I also wrote a test harness which performs about 60,000 comparisons, checking them against Python's idea of integer ordering. Now, all those comparisons (as well as my original test case) pass.&lt;/p&gt;
&lt;p&gt;From what I can determine, the listing I have is derived from &amp;quot;&lt;a href=&quot;https://github.com/douggilliland/Retro-Computers/blob/master/6800/TinyBASIC/Pittman-TinyBASIC/TB68R.txt&quot;&gt;TINY BASIC 6800 V.3R (C)1976 BY TOM PITTMAN (TB683R)&lt;/a&gt;&amp;quot;. The &amp;quot;3&amp;quot; indicates it's the 4th release (0-based version numbering); TB682R was mentioned in ddj in October, 1976.&lt;/p&gt;
&lt;p&gt;I'm a bit tickled to think I have fixed a bug that someone wrote when I was less than 1 year old &lt;em&gt;cough&lt;/em&gt; 50 years ago &lt;em&gt;cough&lt;/em&gt;. It's a bit much to claim I might be the first person who ever noticed or fixed the bug, but I looked through a range of old dr dobb's journal issues and never found anyone who remarked on the bug.&lt;/p&gt;
&lt;p&gt;This is quite possibly the earliest-written bug I will ever fix.&lt;/p&gt;

</content>
</entry>
<entry>
<title>Talking directly to in-process tcl/tk</title>
<issued>2024-10-06T14:15:01Z</issued>
<modified>2024-10-06T14:15:01Z</modified>
<id>https://emergent.unpythonic.net/01728224101</id>
<link rel="alternate" type="text/html" href="https://emergent.unpythonic.net/01728224101"/>
<content type="text/html" mode="escaped">

I recently saw &lt;a href=&quot;https://beauty-of-imagination.blogspot.com/2024/10/simpler-than-pysimplegui-and-python.html&quot;&gt;a post on a blog&lt;/a&gt; about using wish as a subprocess of Python, as a way to access tk without the complexity of tkinter.

&lt;p&gt;To be clear the original post also calls out the situation where the tkinter part of python is not installed by default, and my technique would not be applicable there.

&lt;p&gt;So what do you do if you like Tk but don't care for the high level abstraction provided by Tkinter? Well, you can &lt;tt&gt;import _tkinter&lt;/tt&gt; and create a tkapp object with &lt;tt&gt;_tkinter.create()&lt;/tt&gt;.

&lt;p&gt;The _tkinter module and the tkapp object is largely undocumented, but in Python
3.11 here are some useful methods:
&lt;ul&gt;
&lt;li&gt; tkapp.createcommand: Create a callback into Python code. Takes a string and a callable. Creates a Tcl command with that name, that calls back into Python code: &lt;tt&gt;app.createcomand(&quot;cb&quot;, lambda *args: print(&quot;cb&quot;, args))&lt;/tt&gt;
&lt;li&gt; tkapp.eval: Takes a command and evaluates it. Call it with a single string: &lt;tt&gt;app.eval(&quot;button .b -text HI -command {cb arg1 arg2}&quot;)&lt;/tt&gt;
&lt;li&gt; tkapp.call: Takes a series of arguments, does proper Tcl quoting, and evaluates it: &lt;tt&gt;app.call(&quot;pack&quot;, &quot;.b&quot;)&lt;/tt&gt;
&lt;/ul&gt;
Now, go forth and program your graphical app without all that Python object
nonsense!

&lt;p&gt;&lt;pre&gt;
Python 3.11.2 (main, Aug 26 2024, 07:20:54) [GCC 12.2.0] on linux
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&gt;&gt;&gt; import _tkinter
&gt;&gt;&gt; app = _tkinter.create()
&gt;&gt;&gt; app.createcommand(&quot;cb&quot;, lambda *args: print(&quot;cb&quot;, args))
&gt;&gt;&gt; app.eval(&quot;button .b -text HI -command {cb arg1 arg2}&quot;)
'.b'
&gt;&gt;&gt; app.call(&quot;pack&quot;, &quot;.b&quot;)
''
&gt;&gt;&gt; # Now I click the button several times ...
&gt;&gt;&gt; cb ('arg1', 'arg2')
cb ('arg1', 'arg2')
cb ('arg1', 'arg2')
&lt;/pre&gt;
</content>
</entry>
<entry>
<title>DragonBoard™ 410c with rt-preempt failure</title>
<issued>2015-09-01T14:39:18Z</issued>
<modified>2015-09-01T14:39:18Z</modified>
<id>https://emergent.unpythonic.net/01441118358</id>
<link rel="alternate" type="text/html" href="https://emergent.unpythonic.net/01441118358"/>
<content type="text/html" mode="escaped">

&lt;div style=&quot;float:right;clear:right&quot;&gt;&lt;!-- linaro-01Sep2015-49.png--&gt;&lt;div class=albumouter style=width:306px id=&gt;&lt;div class=albumimage style=&quot;width:292px;margin-left:7.0px;&quot;&gt;&lt;a href=&quot;https://media.unpythonic.net/emergent-files/01441118358/linaro-01Sep2015-49.png&quot; class=&quot;thickbox&quot; rel=&quot;album&quot; title=&quot;LinuxCNC latency test results on
DragonBoard&quot;&gt;&lt;img src=&quot;https://media.unpythonic.net/emergent-files/01441118358/linaro-01Sep2015-49-small.jpg&quot; width=286 height=300&gt;&lt;/a&gt;&lt;div &gt;&lt;div style=&quot;float: right&quot; &gt;&lt;a href=&quot;https://media.unpythonic.net/emergent-files/01441118358/linaro-01Sep2015-49.png&quot;&gt;&lt;img class=zoom src=&quot;https://media.unpythonic.net/emergent-files/default/zoom.png&quot;&gt;&lt;/a&gt;&lt;/div&gt;&lt;a href=&quot;https://media.unpythonic.net/emergent-files/01441118358/linaro-01Sep2015-49.png&quot;&gt;LinuxCNC latency test results on
DragonBoard&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
I was excited to obtain a &lt;a href=&quot;https://www.96boards.org/products/ce/dragonboard410c/&quot;&gt;DragonBoard&lt;/a&gt;, an
affordable 64-bit ARM single-board computer, but unfortunately it hasn't lived
up to my hopes.

&lt;p&gt;First of all, it shipped with one terrible problem, making it useless for
headless development: &lt;a href=&quot;https://bugs.96boards.org/show_bug.cgi?id=66&quot;&gt;The onboard wireless doesn't receive multicast traffic, including ARP
requests&lt;/a&gt;!  And their kernel doesn't provide many modular drivers, so adding
any old USB wireless dongle doesn't work until you rebuild the kernel.  As
of this writing, there is no useful workaround.

&lt;p&gt;And that's when I hit the second show-stopper problem.  I planned to build
kernels for this thing anyway, because the goal is to run LinuxCNC on it
with rt-preempt realtime.  So I stuck in a large capacity micro-sd card,
obtained the kernel source, built it, and rebooted with my new kernel.

&lt;p&gt;(incidentally, testing kernels is a PITA.  You have two choices: one,
flash the one and only boot area with your new and untested kernel and
hope for the best; two, tether to a PC (losing USB keyboard and mouse on the
dragonboard!) and use fastboot every time you boot.  ugh)

&lt;p&gt;.. but the new kernel just didn't work.  It scrolled kernel messages,
but got stuck partway through booting.  dmesg implicated the wireless card.
This one at least has a workaround: &lt;a href=&quot;https://bugs.96boards.org/show_bug.cgi?id=80&quot;&gt;cherry-pick a certain commit from
their kernel git&lt;/a&gt;.  As I understand it, this bug is triggered by using the
compiler on the dragonboard, and not encountered with the linaro cross-compiler
running on a traditional x86 desktop.

&lt;p&gt;Anyway, having found out about this I was briefly celebratory.  I booted with
my own kernel and had a working USB dongle.  Unfortunately, that celebration
was short-lived.  The USB dongle hasn't been terribly reliable either,
particularly under high CPU load.

&lt;p&gt;I soldiered on and patched the linaro 4.0 kernel with the 4.0-rt5 patchset.
There were a few minor conflicts which I believe I resolved correctly.
Unfortunately, the LinuxCNC latency-test readily encounters latencies above
15ms (15000us).  LinuxCNC really would like sub-100us max latencies.

&lt;p&gt;I briefly enabled tracers, and have traces that seem to implicate a variety
of subsystems: networking, usb, and video *all* figure.  More experienced
developers than I will have to be the ones to sort out RT on 64-bit ARM.

&lt;p&gt;</content>
</entry>
<entry>
<title>Proven Delights (and what are proofs anyway)</title>
<issued>2015-08-05T13:13:49Z</issued>
<modified>2015-08-05T13:13:49Z</modified>
<id>https://emergent.unpythonic.net/01438780429</id>
<link rel="alternate" type="text/html" href="https://emergent.unpythonic.net/01438780429"/>
<content type="text/html" mode="escaped">
I won a copy of the book &lt;a href=&quot;http://hackersdelight.org/&quot;&gt;Hacker's
Delight&lt;/a&gt; from &lt;a href=&quot;http://blog.regehr.org/&quot;&gt;John Regehr&lt;/a&gt; for my entry in
his &lt;a href=&quot;http://blog.regehr.org/archives/1213&quot;&gt;nibble sort contest&lt;/a&gt;
earlier this year.

&lt;p&gt;In that thread I had heard about the &lt;a href=&quot;http://www.cprover.org/cbmc/&quot;&gt;CBMC Bounded Model Checking software&lt;/a&gt;, and it gave me the idea to combine
the two: a project to take implementations of the algorithms from Hacker's
Delight and prove the algorithms' properties with CBMC.

&lt;p&gt;I have a modest start on github, which I am calling &amp;quot;Proven Delights&amp;quot;:</content>
</entry>
<entry>
<title>Better pasting for irssi in X</title>
<issued>2014-06-24T12:35:40Z</issued>
<modified>2014-06-24T12:35:40Z</modified>
<id>https://emergent.unpythonic.net/01403613340</id>
<link rel="alternate" type="text/html" href="https://emergent.unpythonic.net/01403613340"/>
<content type="text/html" mode="escaped">
While it's otherwise an excellent irc client, I've been frustrated by pasting
in &lt;a href=&quot;http://www.irssi.org&quot;&gt;irssi&lt;/a&gt;.  There are two main problems:</content>
</entry>
</feed>
